diff --git a/MANIFEST.in b/MANIFEST.in index 0bdaff373..e6b8ffd56 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -12,6 +12,7 @@ recursive-include src/pymod *.cc *.h recursive-include src/rbastub *.cc *.h recursive-include src/rdb/rdb *.cc *.h recursive-include src/tl/tl *.cc *.h +recursive-include src/pymod *.pyi include src/plugins/*/db_plugin/*.cc include src/plugins/*/*/db_plugin/*.cc include src/plugins/*/db_plugin/*.h diff --git a/README.md b/README.md index 8873c3dce..075eae92f 100644 --- a/README.md +++ b/README.md @@ -11,12 +11,12 @@ For more details see http://www.klayout.org. Building on Linux: -* Qt 4.7 or later (4.6 with some restrictions) or Qt 5 +* Qt 4.7 or later (4.6 with some restrictions), Qt 5 or Qt 6 * gcc 4.6 or later or clang 3.8 or later Building on Windows with MSYS2: -* MSYS2 with gcc, Qt4 or 5, zlib, ruby and python packages installed +* MSYS2 with gcc, Qt4, 5 or 6, zlib, ruby and python packages installed Building on Windows with MSVC 2017: @@ -34,14 +34,10 @@ For more build instructions see http://www.klayout.de/build.html. ## Building instructions (Linux) -### Plain building for Qt4 +### Plain building for Qt4, Qt5 and Qt6 (one Qt version installed) ./build.sh -### Plain building for Qt5 - - ./build.sh -qt5 - ### Building without Qt binding ./build.sh -without-qtbinding diff --git a/scripts/create_drc_samples.rb b/scripts/create_drc_samples.rb index 2f0da729b..fb35b1a5a 100644 --- a/scripts/create_drc_samples.rb +++ b/scripts/create_drc_samples.rb @@ -600,6 +600,32 @@ run_demo gen, "input1.edges.not(input2)", "drc_not3.png" run_demo gen, "input1.edges.inside_part(input2)", "drc_inside_part.png" run_demo gen, "input1.edges.outside_part(input2)", "drc_outside_part.png" +class Gen + def produce(s1, s2) + pts = [ + RBA::Point::new(0 , 0 ), + RBA::Point::new(0 , 3000), + RBA::Point::new(2000, 3000), + RBA::Point::new(2000, 5000), + RBA::Point::new(6000, 5000), + RBA::Point::new(6000, 0 ) + ]; + s1.insert(RBA::Polygon::new(pts)) + s2.insert(RBA::Box::new(0, 0, 4000, 6000)) + end +end + +gen = Gen::new + +run_demo gen, "input1.edges.inside(input2)", "drc_inside_ep.png" +run_demo gen, "input1.edges.inside(input2.edges)", "drc_inside_ee.png" +run_demo gen, "input1.edges.not_inside(input2)", "drc_not_inside_ep.png" +run_demo gen, "input1.edges.not_inside(input2.edges)", "drc_not_inside_ee.png" +run_demo gen, "input1.edges.outside(input2)", "drc_outside_ep.png" +run_demo gen, "input1.edges.outside(input2.edges)", "drc_outside_ee.png" +run_demo gen, "input1.edges.not_outside(input2)", "drc_not_outside_ep.png" +run_demo gen, "input1.edges.not_outside(input2.edges)", "drc_not_outside_ee.png" + class Gen def produce(s1, s2) s1.insert(RBA::Box::new(-1000, 0, 1000, 2000)) diff --git a/setup.py b/setup.py index 59461c867..1c4871bf6 100644 --- a/setup.py +++ b/setup.py @@ -759,4 +759,6 @@ if __name__ == '__main__': url='https://github.com/klayout/klayout', packages=find_packages('src/pymod/distutils_src'), package_dir={'': 'src/pymod/distutils_src'}, # https://github.com/pypa/setuptools/issues/230 + package_data={config.root: ["src/pymod/distutils_src/klayout/*.pyi"]}, + include_package_data=True, ext_modules=[_tl, _gsi, _pya, _rba, _db, _lib, _rdb, _lym, _laybasic, _layview, _ant, _edt, _img] + db_plugins + [tl, db, lib, rdb, lay]) diff --git a/src/ant/ant/antPlugin.cc b/src/ant/ant/antPlugin.cc index 488809029..aa942aeac 100644 --- a/src/ant/ant/antPlugin.cc +++ b/src/ant/ant/antPlugin.cc @@ -91,7 +91,7 @@ PluginDeclaration::get_options (std::vector < std::pair (cfg_ruler_snap_mode, ACConverter ().to_string (lay::AC_Any))); options.push_back (std::pair (cfg_ruler_obj_snap, tl::to_string (true))); options.push_back (std::pair (cfg_ruler_grid_snap, tl::to_string (false))); - options.push_back (std::pair (cfg_ruler_templates, ant::TemplatesConverter ().to_string (make_standard_templates ()))); + options.push_back (std::pair (cfg_ruler_templates, std::string ())); options.push_back (std::pair (cfg_current_ruler_template, "0")); // grid-micron is not configured here since some other entity is supposed to do this. } @@ -183,13 +183,10 @@ PluginDeclaration::config_finalize () if (m_templates_updated) { update_menu (); - m_templates_updated = false; - m_current_template_updated = false; } else if (m_current_template_updated) { update_current_template (); - m_current_template_updated = false; } } @@ -198,21 +195,16 @@ void PluginDeclaration::initialized (lay::Dispatcher *root) { // Check if we already have templates (initial setup) + // NOTE: this is not done by using a default value for the configuration item but dynamically. + // This provides a migration path from earlier versions (not having templates) to recent ones. bool any_templates = false; for (std::vector::iterator i = m_templates.begin (); ! any_templates && i != m_templates.end (); ++i) { any_templates = ! i->category ().empty (); } if (! any_templates) { - - // This is the migration path from <= 0.24 to 0.25: clear all templates unless we - // have categorized ones there. Those can't be deleted, so we know we have a 0.25 - // setup if there are some - m_templates = make_standard_templates (); - - root->config_set (cfg_ruler_templates, ant::TemplatesConverter ().to_string (m_templates)); + root->config_set (cfg_ruler_templates, ant::TemplatesConverter ().to_string (make_standard_templates ())); root->config_end (); - } } @@ -250,6 +242,8 @@ PluginDeclaration::update_current_template () } } + + m_current_template_updated = false; } void @@ -294,6 +288,9 @@ PluginDeclaration::update_menu () } } } + + m_templates_updated = false; + m_current_template_updated = false; } void diff --git a/src/db/db/dbAsIfFlatEdges.cc b/src/db/db/dbAsIfFlatEdges.cc index 8aa9d1fae..e42d5c29b 100644 --- a/src/db/db/dbAsIfFlatEdges.cc +++ b/src/db/db/dbAsIfFlatEdges.cc @@ -95,11 +95,11 @@ AsIfFlatEdges::to_string (size_t nmax) const } EdgesDelegate * -AsIfFlatEdges::selected_interacting_generic (const Region &other, bool inverse) const +AsIfFlatEdges::selected_interacting_generic (const Region &other, EdgeInteractionMode mode, bool inverse) const { // shortcuts if (other.empty () || empty ()) { - return new EmptyEdges (); + return ((mode == EdgesOutside) == inverse) ? new EmptyEdges () : clone (); } db::box_scanner2 scanner (report_progress (), progress_desc ()); @@ -110,7 +110,7 @@ AsIfFlatEdges::selected_interacting_generic (const Region &other, bool inverse) scanner.insert1 (e.operator-> (), 0); } - AddressablePolygonDelivery p = other.addressable_polygons (); + AddressablePolygonDelivery p = (mode == EdgesInside ? other.addressable_merged_polygons () : other.addressable_polygons ()); for ( ; ! p.at_end (); ++p) { scanner.insert2 (p.operator-> (), 1); @@ -120,17 +120,17 @@ AsIfFlatEdges::selected_interacting_generic (const Region &other, bool inverse) if (! inverse) { - edge_to_region_interaction_filter filter (*output); + edge_to_region_interaction_filter filter (output.get (), mode); scanner.process (filter, 1, db::box_convert (), db::box_convert ()); } else { - std::set interacting; - edge_to_region_interaction_filter > filter (interacting); + std::set result; + edge_to_region_interaction_filter > filter (&result, mode); scanner.process (filter, 1, db::box_convert (), db::box_convert ()); for (EdgesIterator o (begin_merged ()); ! o.at_end (); ++o) { - if (interacting.find (*o) == interacting.end ()) { + if (result.find (*o) == result.end ()) { output->insert (*o); } } @@ -141,8 +141,13 @@ AsIfFlatEdges::selected_interacting_generic (const Region &other, bool inverse) } EdgesDelegate * -AsIfFlatEdges::selected_interacting_generic (const Edges &edges, bool inverse) const +AsIfFlatEdges::selected_interacting_generic (const Edges &edges, EdgeInteractionMode mode, bool inverse) const { + // shortcuts + if (edges.empty () || empty ()) { + return ((mode == EdgesOutside) == inverse) ? new EmptyEdges () : clone (); + } + db::box_scanner scanner (report_progress (), progress_desc ()); AddressableEdgeDelivery e (begin_merged (), has_valid_merged_edges ()); @@ -151,7 +156,8 @@ AsIfFlatEdges::selected_interacting_generic (const Edges &edges, bool inverse) c scanner.insert (e.operator-> (), 0); } - AddressableEdgeDelivery ee = edges.addressable_edges (); + // NOTE: "inside" needs merged edges for the other edges as the algorithm works edge by edge + AddressableEdgeDelivery ee = (mode == EdgesInside ? edges.addressable_merged_edges () : edges.addressable_edges ()); for ( ; ! ee.at_end (); ++ee) { scanner.insert (ee.operator-> (), 1); @@ -161,17 +167,17 @@ AsIfFlatEdges::selected_interacting_generic (const Edges &edges, bool inverse) c if (! inverse) { - edge_interaction_filter filter (*output); + edge_interaction_filter filter (*output, mode); scanner.process (filter, 1, db::box_convert ()); } else { - std::set interacting; - edge_interaction_filter > filter (interacting); + std::set result; + edge_interaction_filter > filter (result, mode); scanner.process (filter, 1, db::box_convert ()); for (EdgesIterator o (begin_merged ()); ! o.at_end (); ++o) { - if (interacting.find (*o) == interacting.end ()) { + if (result.find (*o) == result.end ()) { output->insert (*o); } } @@ -181,6 +187,95 @@ AsIfFlatEdges::selected_interacting_generic (const Edges &edges, bool inverse) c return output.release (); } +std::pair +AsIfFlatEdges::selected_interacting_pair_generic (const Region ®ion, EdgeInteractionMode mode) const +{ + // shortcuts + if (region.empty () || empty ()) { + if (mode != EdgesOutside) { + return std::make_pair (new EmptyEdges (), clone ()); + } else { + return std::make_pair (clone (), new EmptyEdges ()); + } + } + + db::box_scanner2 scanner (report_progress (), progress_desc ()); + + AddressableEdgeDelivery e (begin_merged (), has_valid_merged_edges ()); + + for ( ; ! e.at_end (); ++e) { + scanner.insert1 (e.operator-> (), 0); + } + + AddressablePolygonDelivery p = region.addressable_merged_polygons (); + + for ( ; ! p.at_end (); ++p) { + scanner.insert2 (p.operator-> (), 1); + } + + std::unique_ptr output (new FlatEdges (true)); + std::unique_ptr output2 (new FlatEdges (true)); + + std::set result; + edge_to_region_interaction_filter > filter (&result, mode); + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + + for (EdgesIterator o (begin_merged ()); ! o.at_end (); ++o) { + if (result.find (*o) == result.end ()) { + output2->insert (*o); + } else { + output->insert (*o); + } + } + + return std::make_pair (output.release (), output2.release ()); +} + +std::pair +AsIfFlatEdges::selected_interacting_pair_generic (const Edges &other, EdgeInteractionMode mode) const +{ + // shortcuts + if (other.empty () || empty ()) { + if (mode != EdgesOutside) { + return std::make_pair (new EmptyEdges (), clone ()); + } else { + return std::make_pair (clone (), new EmptyEdges ()); + } + } + + db::box_scanner scanner (report_progress (), progress_desc ()); + + AddressableEdgeDelivery e (begin_merged (), has_valid_merged_edges ()); + + for ( ; ! e.at_end (); ++e) { + scanner.insert (e.operator-> (), 0); + } + + AddressableEdgeDelivery ee = other.addressable_merged_edges (); + + for ( ; ! ee.at_end (); ++ee) { + scanner.insert (ee.operator-> (), 1); + } + + std::unique_ptr output (new FlatEdges (true)); + std::unique_ptr output2 (new FlatEdges (true)); + + std::set results; + edge_interaction_filter > filter (results, mode); + scanner.process (filter, 1, db::box_convert ()); + + for (EdgesIterator o (begin_merged ()); ! o.at_end (); ++o) { + if (results.find (*o) == results.end ()) { + output2->insert (*o); + } else { + output->insert (*o); + } + } + + return std::make_pair (output.release (), output2.release ()); +} + + EdgesDelegate * AsIfFlatEdges::pull_generic (const Edges &edges) const { @@ -199,7 +294,7 @@ AsIfFlatEdges::pull_generic (const Edges &edges) const } std::unique_ptr output (new FlatEdges (true)); - edge_interaction_filter filter (*output); + edge_interaction_filter filter (*output, EdgesInteract); scanner.process (filter, 1, db::box_convert ()); return output.release (); @@ -229,7 +324,7 @@ AsIfFlatEdges::pull_generic (const Region &other) const std::unique_ptr output (new FlatRegion (true)); - edge_to_region_interaction_filter filter (*output); + edge_to_region_interaction_filter filter (output.get (), EdgesInteract); scanner.process (filter, 1, db::box_convert (), db::box_convert ()); return output.release (); @@ -250,27 +345,112 @@ AsIfFlatEdges::pull_interacting (const Region &other) const EdgesDelegate * AsIfFlatEdges::selected_interacting (const Edges &other) const { - return selected_interacting_generic (other, false); + return selected_interacting_generic (other, EdgesInteract, false); } EdgesDelegate * AsIfFlatEdges::selected_not_interacting (const Edges &other) const { - return selected_interacting_generic (other, true); + return selected_interacting_generic (other, EdgesInteract, true); } EdgesDelegate * AsIfFlatEdges::selected_interacting (const Region &other) const { - return selected_interacting_generic (other, false); + return selected_interacting_generic (other, EdgesInteract, false); } EdgesDelegate * AsIfFlatEdges::selected_not_interacting (const Region &other) const { - return selected_interacting_generic (other, true); + return selected_interacting_generic (other, EdgesInteract, true); } +std::pair +AsIfFlatEdges::selected_interacting_pair (const Region &other) const +{ + return selected_interacting_pair_generic (other, EdgesInteract); +} + +std::pair +AsIfFlatEdges::selected_interacting_pair (const Edges &other) const +{ + return selected_interacting_pair_generic (other, EdgesInteract); +} + +EdgesDelegate * +AsIfFlatEdges::selected_outside (const Region &other) const +{ + return selected_interacting_generic (other, EdgesOutside, false); +} + +EdgesDelegate * +AsIfFlatEdges::selected_not_outside (const Region &other) const +{ + return selected_interacting_generic (other, EdgesOutside, true); +} + +std::pair +AsIfFlatEdges::selected_outside_pair (const Region &other) const +{ + return selected_interacting_pair_generic (other, EdgesOutside); +} + +EdgesDelegate * +AsIfFlatEdges::selected_inside (const Region &other) const +{ + return selected_interacting_generic (other, EdgesInside, false); +} + +EdgesDelegate * +AsIfFlatEdges::selected_not_inside (const Region &other) const +{ + return selected_interacting_generic (other, EdgesInside, true); +} + +std::pair +AsIfFlatEdges::selected_inside_pair (const Region &other) const +{ + return selected_interacting_pair_generic (other, EdgesInside); +} + +EdgesDelegate * +AsIfFlatEdges::selected_outside (const Edges &other) const +{ + return selected_interacting_generic (other, EdgesOutside, false); +} + +EdgesDelegate * +AsIfFlatEdges::selected_not_outside (const Edges &other) const +{ + return selected_interacting_generic (other, EdgesOutside, true); +} + +std::pair +AsIfFlatEdges::selected_outside_pair (const Edges &other) const +{ + return selected_interacting_pair_generic (other, EdgesOutside); +} + +EdgesDelegate * +AsIfFlatEdges::selected_inside (const Edges &other) const +{ + return selected_interacting_generic (other, EdgesInside, false); +} + +EdgesDelegate * +AsIfFlatEdges::selected_not_inside (const Edges &other) const +{ + return selected_interacting_generic (other, EdgesInside, true); +} + +std::pair +AsIfFlatEdges::selected_inside_pair (const Edges &other) const +{ + return selected_interacting_pair_generic (other, EdgesInside); +} + + namespace { @@ -584,18 +764,52 @@ AsIfFlatEdges::boolean (const Edges *other, EdgeBoolOp op) const return output.release (); } -EdgesDelegate * -AsIfFlatEdges::edge_region_op (const Region &other, bool outside, bool include_borders) const +std::pair +AsIfFlatEdges::boolean_andnot (const Edges *other) const +{ + std::unique_ptr output (new FlatEdges (true)); + std::unique_ptr output2 (new FlatEdges (true)); + EdgeBooleanClusterCollectorToShapes cluster_collector (&output->raw_edges (), EdgeAndNot, &output2->raw_edges ()); + + db::box_scanner scanner (report_progress (), progress_desc ()); + scanner.reserve (count () + (other ? other->count () : 0)); + + AddressableEdgeDelivery e (begin (), has_valid_edges ()); + + for ( ; ! e.at_end (); ++e) { + if (! e->is_degenerate ()) { + scanner.insert (e.operator-> (), 0); + } + } + + AddressableEdgeDelivery ee; + + if (other) { + ee = other->addressable_edges (); + for ( ; ! ee.at_end (); ++ee) { + if (! ee->is_degenerate ()) { + scanner.insert (ee.operator-> (), 1); + } + } + } + + scanner.process (cluster_collector, 1, db::box_convert ()); + + return std::make_pair (output.release (), output2.release ()); +} + +std::pair +AsIfFlatEdges::edge_region_op (const Region &other, db::EdgePolygonOp::mode_t mode, bool include_borders) const { // shortcuts - if (other.empty ()) { - if (! outside) { - return new EmptyEdges (); + if (other.empty () || empty ()) { + if (mode == db::EdgePolygonOp::Both) { + return std::make_pair (new EmptyEdges (), clone ()); + } else if (mode == db::EdgePolygonOp::Inside) { + return std::make_pair (new EmptyEdges (), (EdgesDelegate *) 0); } else { - return clone (); + return std::make_pair (clone (), (EdgesDelegate *) 0); } - } else if (empty ()) { - return new EmptyEdges (); } db::EdgeProcessor ep (report_progress (), progress_desc ()); @@ -610,12 +824,19 @@ AsIfFlatEdges::edge_region_op (const Region &other, bool outside, bool include_b ep.insert (*e, 1); } + std::unique_ptr output_second; + std::unique_ptr cc_second; + if (mode == db::EdgePolygonOp::Both) { + output_second.reset (new FlatEdges (false)); + cc_second.reset (new db::EdgeShapeGenerator (output_second->raw_edges (), true /*clear*/, 2 /*second tag*/)); + } + std::unique_ptr output (new FlatEdges (false)); - db::EdgeShapeGenerator cc (output->raw_edges (), true /*clear*/); - db::EdgePolygonOp op (outside, include_borders); + db::EdgeShapeGenerator cc (output->raw_edges (), true /*clear*/, 1 /*tag*/, cc_second.get ()); + db::EdgePolygonOp op (mode, include_borders); ep.process (cc, op); - return output.release (); + return std::make_pair (output.release (), output_second.release ()); } EdgesDelegate * diff --git a/src/db/db/dbAsIfFlatEdges.h b/src/db/db/dbAsIfFlatEdges.h index 98e93d35d..785b0a677 100644 --- a/src/db/db/dbAsIfFlatEdges.h +++ b/src/db/db/dbAsIfFlatEdges.h @@ -28,6 +28,8 @@ #include "dbBoxScanner.h" #include "dbEdgesDelegate.h" #include "dbEdgeBoolean.h" +#include "dbEdgeProcessor.h" +#include "dbEdgesUtils.h" #include "dbBoxScanner.h" #include "dbPolygonTools.h" @@ -115,19 +117,29 @@ public: return boolean (&other, EdgeAnd); } - virtual EdgesDelegate *and_with (const Region &other) const - { - return edge_region_op (other, false /*inside*/, true /*include borders*/); - } - virtual EdgesDelegate *not_with (const Edges &other) const { return boolean (&other, EdgeNot); } + virtual std::pair andnot_with (const Edges &other) const + { + return boolean_andnot (&other); + } + + virtual EdgesDelegate *and_with (const Region &other) const + { + return edge_region_op (other, db::EdgePolygonOp::Inside, true /*include borders*/).first; + } + virtual EdgesDelegate *not_with (const Region &other) const { - return edge_region_op (other, true /*outside*/, true /*include borders*/); + return edge_region_op (other, db::EdgePolygonOp::Outside, true /*include borders*/).first; + } + + virtual std::pair andnot_with (const Region &other) const + { + return edge_region_op (other, db::EdgePolygonOp::Both, true /*include borders*/); } virtual EdgesDelegate *xor_with (const Edges &other) const @@ -154,12 +166,17 @@ public: virtual EdgesDelegate *inside_part (const Region &other) const { - return edge_region_op (other, false /*inside*/, false /*don't include borders*/); + return edge_region_op (other, db::EdgePolygonOp::Inside, false /*don't include borders*/).first; } virtual EdgesDelegate *outside_part (const Region &other) const { - return edge_region_op (other, true /*outside*/, false /*don't include borders*/); + return edge_region_op (other, db::EdgePolygonOp::Outside, false /*don't include borders*/).first; + } + + virtual std::pair inside_outside_part_pair (const Region &other) const + { + return edge_region_op (other, db::EdgePolygonOp::Both, false /*don't include borders*/); } virtual RegionDelegate *extended (coord_type ext_b, coord_type ext_e, coord_type ext_o, coord_type ext_i, bool join) const; @@ -170,6 +187,21 @@ public: virtual EdgesDelegate *selected_not_interacting (const Edges &) const; virtual EdgesDelegate *selected_interacting (const Region &) const; virtual EdgesDelegate *selected_not_interacting (const Region &) const; + virtual std::pair selected_interacting_pair (const Region &other) const; + virtual std::pair selected_interacting_pair (const Edges &other) const; + + virtual EdgesDelegate *selected_outside (const Edges &other) const; + virtual EdgesDelegate *selected_not_outside (const Edges &other) const; + virtual std::pair selected_outside_pair (const Edges &other) const; + virtual EdgesDelegate *selected_inside (const Edges &other) const; + virtual EdgesDelegate *selected_not_inside (const Edges &other) const; + virtual std::pair selected_inside_pair (const Edges &other) const; + virtual EdgesDelegate *selected_outside (const Region &other) const; + virtual EdgesDelegate *selected_not_outside (const Region &other) const; + virtual std::pair selected_outside_pair (const Region &other) const; + virtual EdgesDelegate *selected_inside (const Region &other) const; + virtual EdgesDelegate *selected_not_inside (const Region &other) const; + virtual std::pair selected_inside_pair (const Region &other) const; virtual EdgesDelegate *in (const Edges &, bool) const; @@ -184,8 +216,10 @@ protected: EdgePairsDelegate *run_check (db::edge_relation_type rel, const Edges *other, db::Coord d, const EdgesCheckOptions &options) const; virtual EdgesDelegate *pull_generic (const Edges &edges) const; virtual RegionDelegate *pull_generic (const Region ®ion) const; - virtual EdgesDelegate *selected_interacting_generic (const Edges &edges, bool inverse) const; - virtual EdgesDelegate *selected_interacting_generic (const Region ®ion, bool inverse) const; + virtual EdgesDelegate *selected_interacting_generic (const Edges &edges, EdgeInteractionMode mode, bool inverse) const; + virtual std::pair selected_interacting_pair_generic (const Edges &edges, EdgeInteractionMode mode) const; + virtual EdgesDelegate *selected_interacting_generic (const Region ®ion, EdgeInteractionMode mode, bool inverse) const; + virtual std::pair selected_interacting_pair_generic (const Region ®ion, EdgeInteractionMode mode) const; AsIfFlatEdges &operator= (const AsIfFlatEdges &other); AsIfFlatEdges (const AsIfFlatEdges &other); @@ -195,7 +229,8 @@ private: virtual db::Box compute_bbox () const; EdgesDelegate *boolean (const Edges *other, EdgeBoolOp op) const; - EdgesDelegate *edge_region_op (const Region &other, bool outside, bool include_borders) const; + std::pair boolean_andnot (const Edges *other) const; + std::pair edge_region_op(const Region &other, db::EdgePolygonOp::mode_t mode, bool include_borders) const; }; } diff --git a/src/db/db/dbCommonReader.cc b/src/db/db/dbCommonReader.cc index 315499971..0400621eb 100644 --- a/src/db/db/dbCommonReader.cc +++ b/src/db/db/dbCommonReader.cc @@ -556,6 +556,7 @@ CommonReader::read (db::Layout &layout) void CommonReader::init (const LoadLayoutOptions &options) { + ReaderBase::init (options); CommonReaderBase::init (); db::CommonReaderOptions common_options = options.get_options (); diff --git a/src/db/db/dbCommonReader.h b/src/db/db/dbCommonReader.h index 9610e1634..b5a5a9a19 100644 --- a/src/db/db/dbCommonReader.h +++ b/src/db/db/dbCommonReader.h @@ -237,7 +237,7 @@ protected: friend class CommonReaderLayerMapping; virtual void common_reader_error (const std::string &msg) = 0; - virtual void common_reader_warn (const std::string &msg) = 0; + virtual void common_reader_warn (const std::string &msg, int warn_level = 1) = 0; /** * @brief Merge (and delete) the src_cell into target_cell diff --git a/src/db/db/dbDeepEdges.cc b/src/db/db/dbDeepEdges.cc index b45c93f56..c1ca6f78b 100644 --- a/src/db/db/dbDeepEdges.cc +++ b/src/db/db/dbDeepEdges.cc @@ -387,7 +387,7 @@ DeepEdges::has_valid_edges () const bool DeepEdges::has_valid_merged_edges () const { - return merged_semantics (); + return false; } const db::RecursiveShapeIterator * @@ -797,12 +797,21 @@ DeepEdges::and_or_not_with (const DeepEdges *other, EdgeBoolOp op) const return dl_out; } -DeepLayer -DeepEdges::edge_region_op (const DeepRegion *other, bool outside, bool include_borders) const +std::pair +DeepEdges::edge_region_op (const DeepRegion *other, EdgePolygonOp::mode_t mode, bool include_borders) const { - DeepLayer dl_out (deep_layer ().derived ()); + std::vector output_layers; - db::EdgeToPolygonLocalOperation op (outside, include_borders); + DeepLayer dl_out (deep_layer ().derived ()); + output_layers.push_back (dl_out.layer ()); + + DeepLayer dl_out2; + if (mode == EdgePolygonOp::Both) { + dl_out2 = DeepLayer (deep_layer ().derived ()); + output_layers.push_back (dl_out2.layer ()); + } + + db::EdgeToPolygonLocalOperation op (mode, include_borders); db::local_processor proc (const_cast (&deep_layer ().layout ()), const_cast (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell ()); proc.set_base_verbosity (base_verbosity ()); @@ -810,9 +819,9 @@ DeepEdges::edge_region_op (const DeepRegion *other, bool outside, bool include_b proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ()); proc.set_max_vertex_count (deep_layer ().store ()->max_vertex_count ()); - proc.run (&op, deep_layer ().layer (), other->deep_layer ().layer (), dl_out.layer ()); + proc.run (&op, deep_layer ().layer (), other->deep_layer ().layer (), output_layers); - return dl_out; + return std::make_pair (dl_out, dl_out2); } EdgesDelegate *DeepEdges::intersections (const Edges &other) const @@ -821,8 +830,7 @@ EdgesDelegate *DeepEdges::intersections (const Edges &other) const if (empty () || other.empty ()) { - // Nothing to do - return new EmptyEdges (); + return clone (); } else if (! other_deep) { @@ -839,10 +847,14 @@ EdgesDelegate *DeepEdges::and_with (const Edges &other) const { const DeepEdges *other_deep = dynamic_cast (other.delegate ()); - if (empty () || other.empty ()) { + if (empty ()) { - // Nothing to do - return new EmptyEdges (); + return clone (); + + } else if (other.empty ()) { + + // NOTE: we do not use "EmptyEdges" as we want to maintain + return new DeepEdges (deep_layer ().derived ()); } else if (! other_deep) { @@ -855,43 +867,12 @@ EdgesDelegate *DeepEdges::and_with (const Edges &other) const } } -EdgesDelegate *DeepEdges::and_with (const Region &other) const -{ - const DeepRegion *other_deep = dynamic_cast (other.delegate ()); - - if (empty ()) { - - // Nothing to do - return new EmptyEdges (); - - } else if (other.empty ()) { - - // Nothing to do - return clone (); - - } else if (! other_deep) { - - return AsIfFlatEdges::not_with (other); - - } else { - - return new DeepEdges (edge_region_op (other_deep, false /*outside*/, true /*include borders*/)); - - } -} - EdgesDelegate *DeepEdges::not_with (const Edges &other) const { const DeepEdges *other_deep = dynamic_cast (other.delegate ()); - if (empty ()) { + if (empty () || other.empty ()) { - // Nothing to do - return new EmptyEdges (); - - } else if (other.empty ()) { - - // Nothing to do return clone (); } else if (! other_deep) { @@ -905,18 +886,61 @@ EdgesDelegate *DeepEdges::not_with (const Edges &other) const } } -EdgesDelegate *DeepEdges::not_with (const Region &other) const +EdgesDelegate *DeepEdges::and_with (const Region &other) const { const DeepRegion *other_deep = dynamic_cast (other.delegate ()); if (empty ()) { - // Nothing to do - return new EmptyEdges (); + return clone (); } else if (other.empty ()) { - // Nothing to do + // NOTE: we do not use "EmptyEdges" as we want to maintain + return new DeepEdges (deep_layer ().derived ()); + + } else if (! other_deep) { + + return AsIfFlatEdges::and_with (other); + + } else { + + return new DeepEdges (edge_region_op (other_deep, EdgePolygonOp::Inside, true /*include borders*/).first); + + } +} + +std::pair DeepEdges::andnot_with (const Region &other) const +{ + const DeepRegion *other_deep = dynamic_cast (other.delegate ()); + + if (empty ()) { + + return std::make_pair (clone (), clone ()); + + } else if (other.empty ()) { + + // NOTE: we do not use "EmptyEdges" as we want to maintain "deepness" + return std::make_pair (new DeepEdges (deep_layer ().derived ()), clone ()); + + } else if (! other_deep) { + + return AsIfFlatEdges::andnot_with (other); + + } else { + + auto res = edge_region_op (other_deep, EdgePolygonOp::Both, true /*include borders*/); + return std::make_pair (new DeepEdges (res.first), new DeepEdges (res.second)); + + } +} + +EdgesDelegate *DeepEdges::not_with (const Region &other) const +{ + const DeepRegion *other_deep = dynamic_cast (other.delegate ()); + + if (empty () || other.empty ()) { + return clone (); } else if (! other_deep) { @@ -925,7 +949,33 @@ EdgesDelegate *DeepEdges::not_with (const Region &other) const } else { - return new DeepEdges (edge_region_op (other_deep, true /*outside*/, true /*include borders*/)); + return new DeepEdges (edge_region_op (other_deep, EdgePolygonOp::Outside, true /*include borders*/).first); + + } +} + +std::pair +DeepEdges::andnot_with (const Edges &other) const +{ + const DeepRegion *other_deep = dynamic_cast (other.delegate ()); + + if (empty ()) { + + return std::make_pair (clone (), clone ()); + + } else if (other.empty ()) { + + // NOTE: we do not use "EmptyEdges" as we want to maintain + return std::make_pair (new DeepEdges (deep_layer ().derived ()), clone ()); + + } else if (! other_deep) { + + return AsIfFlatEdges::andnot_with (other); + + } else { + + auto res = edge_region_op (other_deep, EdgePolygonOp::Both, true /*include borders*/); + return std::make_pair (new DeepEdges (res.first), new DeepEdges (res.second)); } } @@ -936,12 +986,10 @@ EdgesDelegate *DeepEdges::xor_with (const Edges &other) const if (empty ()) { - // Nothing to do return other.delegate ()->clone (); } else if (other.empty ()) { - // Nothing to do return clone (); } else if (! other_deep) { @@ -1013,21 +1061,20 @@ EdgesDelegate *DeepEdges::inside_part (const Region &other) const if (empty ()) { - // Nothing to do - return new EmptyEdges (); + return clone (); } else if (other.empty ()) { - // Nothing to do - return clone (); + // NOTE: we do not use "EmptyEdges" as we want to maintain + return new DeepEdges (deep_layer ().derived ()); } else if (! other_deep) { - return AsIfFlatEdges::not_with (other); + return AsIfFlatEdges::inside_part (other); } else { - return new DeepEdges (edge_region_op (other_deep, false /*outside*/, false /*include borders*/)); + return new DeepEdges (edge_region_op (other_deep, db::EdgePolygonOp::Inside, false /*include borders*/).first); } } @@ -1036,23 +1083,42 @@ EdgesDelegate *DeepEdges::outside_part (const Region &other) const { const DeepRegion *other_deep = dynamic_cast (other.delegate ()); - if (empty ()) { + if (empty () || other.empty ()) { - // Nothing to do - return new EmptyEdges (); - - } else if (other.empty ()) { - - // Nothing to do return clone (); } else if (! other_deep) { - return AsIfFlatEdges::not_with (other); + return AsIfFlatEdges::outside_part (other); } else { - return new DeepEdges (edge_region_op (other_deep, true /*outside*/, false /*include borders*/)); + return new DeepEdges (edge_region_op (other_deep, db::EdgePolygonOp::Outside, false /*include borders*/).first); + + } +} + +std::pair DeepEdges::inside_outside_part_pair (const Region &other) const +{ + const DeepRegion *other_deep = dynamic_cast (other.delegate ()); + + if (empty ()) { + + return std::make_pair (clone (), clone ()); + + } else if (other.empty ()) { + + // NOTE: we do not use "EmptyEdges" as we want to maintain "deepness" + return std::make_pair (new DeepEdges (deep_layer ().derived ()), clone ()); + + } else if (! other_deep) { + + return AsIfFlatEdges::inside_outside_part_pair (other); + + } else { + + auto res = edge_region_op (other_deep, EdgePolygonOp::Both, false /*include borders*/); + return std::make_pair (new DeepEdges (res.first), new DeepEdges (res.second)); } } @@ -1157,8 +1223,10 @@ class Edge2EdgeInteractingLocalOperation : public local_operation { public: - Edge2EdgeInteractingLocalOperation (bool inverse) - : m_inverse (inverse) + enum output_mode_t { Normal, Inverse, Both }; + + Edge2EdgeInteractingLocalOperation (EdgeInteractionMode mode, output_mode_t output_mode) + : m_mode (mode), m_output_mode (output_mode) { // .. nothing yet .. } @@ -1171,9 +1239,15 @@ public: virtual void do_compute_local (db::Layout * /*layout*/, const shape_interactions &interactions, std::vector > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const { - tl_assert (results.size () == 1); + tl_assert (results.size () == (m_output_mode == Both ? 2 : 1)); + std::unordered_set &result = results.front (); + std::unordered_set *result2 = 0; + if (m_output_mode == Both) { + result2 = &results[1]; + } + db::box_scanner scanner; std::set others; @@ -1192,22 +1266,30 @@ public: scanner.insert (o.operator-> (), 1); } - if (m_inverse) { + if (m_output_mode == Inverse || m_output_mode == Both) { std::unordered_set interacting; - edge_interaction_filter > filter (interacting); + edge_interaction_filter > filter (interacting, m_mode); scanner.process (filter, 1, db::box_convert ()); for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + const db::Edge &subject = interactions.subject_shape (i->first); if (interacting.find (subject) == interacting.end ()) { + if (m_output_mode != Both) { + result.insert (subject); + } else { + result2->insert (subject); + } + } else if (m_output_mode == Both) { result.insert (subject); } + } } else { - edge_interaction_filter > filter (result); + edge_interaction_filter > filter (result, m_mode); scanner.process (filter, 1, db::box_convert ()); } @@ -1216,10 +1298,10 @@ public: virtual OnEmptyIntruderHint on_empty_intruder_hint () const { - if (m_inverse) { - return Copy; + if (m_mode == EdgesOutside) { + return m_output_mode == Both ? Copy : (m_output_mode == Inverse ? Drop : Copy); } else { - return Drop; + return m_output_mode == Both ? CopyToSecond : (m_output_mode == Inverse ? Copy : Drop); } } @@ -1229,7 +1311,8 @@ public: } private: - bool m_inverse; + EdgeInteractionMode m_mode; + output_mode_t m_output_mode; }; class Edge2EdgePullLocalOperation @@ -1270,7 +1353,7 @@ public: scanner.insert (o.operator-> (), 0); } - edge_interaction_filter > filter (result); + edge_interaction_filter > filter (result, EdgesInteract); scanner.process (filter, 1, db::box_convert ()); } @@ -1290,8 +1373,10 @@ class Edge2PolygonInteractingLocalOperation : public local_operation { public: - Edge2PolygonInteractingLocalOperation (bool inverse) - : m_inverse (inverse) + enum output_mode_t { Normal, Inverse, Both }; + + Edge2PolygonInteractingLocalOperation (EdgeInteractionMode mode, output_mode_t output_mode) + : m_mode (mode), m_output_mode (output_mode) { // .. nothing yet .. } @@ -1304,9 +1389,15 @@ public: virtual void do_compute_local (db::Layout * /*layout*/, const shape_interactions &interactions, std::vector > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const { - tl_assert (results.size () == 1); + tl_assert (results.size () == size_t (m_output_mode == Both ? 2 : 1)); + std::unordered_set &result = results.front (); + std::unordered_set *result2 = 0; + if (m_output_mode == Both) { + result2 = &results[1]; + } + db::box_scanner2 scanner; std::set others; @@ -1327,22 +1418,31 @@ public: scanner.insert2 (& heap.back (), 1); } - if (m_inverse) { + if (m_output_mode == Inverse || m_output_mode == Both) { std::unordered_set interacting; - edge_to_region_interaction_filter > filter (interacting); + edge_to_region_interaction_filter > filter (&interacting, m_mode); scanner.process (filter, 1, db::box_convert (), db::box_convert ()); for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + const db::Edge &subject = interactions.subject_shape (i->first); + if (interacting.find (subject) == interacting.end ()) { + if (m_output_mode != Both) { + result.insert (subject); + } else { + result2->insert (subject); + } + } else if (m_output_mode == Both) { result.insert (subject); } + } } else { - edge_to_region_interaction_filter > filter (result); + edge_to_region_interaction_filter > filter (&result, m_mode); scanner.process (filter, 1, db::box_convert (), db::box_convert ()); } @@ -1350,20 +1450,46 @@ public: virtual OnEmptyIntruderHint on_empty_intruder_hint () const { - if (m_inverse) { - return Copy; + if (m_mode == EdgesOutside) { + return m_output_mode == Both ? Copy : (m_output_mode == Inverse ? Drop : Copy); } else { - return Drop; + return m_output_mode == Both ? CopyToSecond : (m_output_mode == Inverse ? Copy : Drop); } } virtual std::string description () const { - return tl::to_string (tr ("Select interacting edges")); + if (m_mode == EdgesInteract) { + if (m_output_mode == Inverse) { + return tl::to_string (tr ("Select non-interacting edges")); + } else if (m_output_mode == Normal) { + return tl::to_string (tr ("Select interacting edges")); + } else { + return tl::to_string (tr ("Select interacting and non-interacting edges")); + } + } else if (m_mode == EdgesInside) { + if (m_output_mode == Inverse) { + return tl::to_string (tr ("Select non-inside edges")); + } else if (m_output_mode == Normal) { + return tl::to_string (tr ("Select inside edges")); + } else { + return tl::to_string (tr ("Select inside and non-inside edges")); + } + } else if (m_mode == EdgesOutside) { + if (m_output_mode == Inverse) { + return tl::to_string (tr ("Select non-outside edges")); + } else if (m_output_mode == Normal) { + return tl::to_string (tr ("Select outside edges")); + } else { + return tl::to_string (tr ("Select outside and non-outside edges")); + } + } + return std::string (); } private: - bool m_inverse; + EdgeInteractionMode m_mode; + output_mode_t m_output_mode; }; struct ResultInserter @@ -1427,7 +1553,7 @@ public: } ResultInserter inserter (layout, result); - edge_to_region_interaction_filter filter (inserter); + edge_to_region_interaction_filter filter (&inserter, EdgesInteract); scanner.process (filter, 1, db::box_convert (), db::box_convert ()); } @@ -1445,7 +1571,7 @@ public: } EdgesDelegate * -DeepEdges::selected_interacting_generic (const Region &other, bool inverse) const +DeepEdges::selected_interacting_generic (const Region &other, EdgeInteractionMode mode, bool inverse) const { std::unique_ptr dr_holder; const db::DeepRegion *other_deep = dynamic_cast (other.delegate ()); @@ -1459,19 +1585,51 @@ DeepEdges::selected_interacting_generic (const Region &other, bool inverse) cons DeepLayer dl_out (edges.derived ()); - db::Edge2PolygonInteractingLocalOperation op (inverse); + db::Edge2PolygonInteractingLocalOperation op (mode, inverse ? db::Edge2PolygonInteractingLocalOperation::Inverse : db::Edge2PolygonInteractingLocalOperation::Normal); db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ()); proc.set_base_verbosity (base_verbosity ()); proc.set_threads (edges.store ()->threads ()); - proc.run (&op, edges.layer (), other_deep->deep_layer ().layer (), dl_out.layer ()); + proc.run (&op, edges.layer (), (mode == EdgesInside ? other_deep->merged_deep_layer () : other_deep->deep_layer ()).layer (), dl_out.layer ()); return new db::DeepEdges (dl_out); } +std::pair +DeepEdges::selected_interacting_pair_generic (const Region &other, EdgeInteractionMode mode) const +{ + std::unique_ptr dr_holder; + const db::DeepRegion *other_deep = dynamic_cast (other.delegate ()); + if (! other_deep) { + // if the other region isn't deep, turn into a top-level only deep region to facilitate re-hierarchization + dr_holder.reset (new db::DeepRegion (other, const_cast (*deep_layer ().store ()))); + other_deep = dr_holder.get (); + } + + const db::DeepLayer &edges = merged_deep_layer (); + + DeepLayer dl_out (edges.derived ()); + DeepLayer dl_out2 (edges.derived ()); + + std::vector output_layers; + output_layers.reserve (2); + output_layers.push_back (dl_out.layer ()); + output_layers.push_back (dl_out2.layer ()); + + db::Edge2PolygonInteractingLocalOperation op (mode, db::Edge2PolygonInteractingLocalOperation::Both); + + db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ()); + proc.set_base_verbosity (base_verbosity ()); + proc.set_threads (edges.store ()->threads ()); + + proc.run (&op, edges.layer (), other_deep->merged_deep_layer ().layer (), output_layers); + + return std::make_pair (new db::DeepEdges (dl_out), new db::DeepEdges (dl_out2)); +} + EdgesDelegate * -DeepEdges::selected_interacting_generic (const Edges &other, bool inverse) const +DeepEdges::selected_interacting_generic (const Edges &other, EdgeInteractionMode mode, bool inverse) const { std::unique_ptr dr_holder; const db::DeepEdges *other_deep = dynamic_cast (other.delegate ()); @@ -1485,17 +1643,49 @@ DeepEdges::selected_interacting_generic (const Edges &other, bool inverse) const DeepLayer dl_out (edges.derived ()); - db::Edge2EdgeInteractingLocalOperation op (inverse); + db::Edge2EdgeInteractingLocalOperation op (mode, inverse ? db::Edge2EdgeInteractingLocalOperation::Inverse : db::Edge2EdgeInteractingLocalOperation::Normal); db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ()); proc.set_base_verbosity (base_verbosity ()); proc.set_threads (edges.store ()->threads ()); - proc.run (&op, edges.layer (), other_deep->deep_layer ().layer (), dl_out.layer ()); + proc.run (&op, edges.layer (), (mode == EdgesInside ? other_deep->merged_deep_layer () : other_deep->deep_layer ()).layer (), dl_out.layer ()); return new db::DeepEdges (dl_out); } +std::pair +DeepEdges::selected_interacting_pair_generic (const Edges &other, EdgeInteractionMode mode) const +{ + std::unique_ptr dr_holder; + const db::DeepEdges *other_deep = dynamic_cast (other.delegate ()); + if (! other_deep) { + // if the other edge collection isn't deep, turn into a top-level only deep edge collection to facilitate re-hierarchization + dr_holder.reset (new db::DeepEdges (other, const_cast (*deep_layer ().store ()))); + other_deep = dr_holder.get (); + } + + const db::DeepLayer &edges = merged_deep_layer (); + + DeepLayer dl_out (edges.derived ()); + DeepLayer dl_out2 (edges.derived ()); + + std::vector output_layers; + output_layers.reserve (2); + output_layers.push_back (dl_out.layer ()); + output_layers.push_back (dl_out2.layer ()); + + db::Edge2EdgeInteractingLocalOperation op (mode, db::Edge2EdgeInteractingLocalOperation::Both); + + db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ()); + proc.set_base_verbosity (base_verbosity ()); + proc.set_threads (edges.store ()->threads ()); + + proc.run (&op, edges.layer (), other_deep->merged_deep_layer ().layer (), output_layers); + + return std::make_pair (new db::DeepEdges (dl_out), new db::DeepEdges (dl_out2)); +} + RegionDelegate *DeepEdges::pull_generic (const Region &other) const { std::unique_ptr dr_holder; diff --git a/src/db/db/dbDeepEdges.h b/src/db/db/dbDeepEdges.h index f00913540..1bd84c16f 100644 --- a/src/db/db/dbDeepEdges.h +++ b/src/db/db/dbDeepEdges.h @@ -133,10 +133,12 @@ public: virtual EdgesDelegate *merged () const; virtual EdgesDelegate *and_with (const Edges &other) const; - virtual EdgesDelegate *and_with (const Region &other) const; - virtual EdgesDelegate *not_with (const Edges &other) const; + virtual std::pair andnot_with (const Edges &) const; + + virtual EdgesDelegate *and_with (const Region &other) const; virtual EdgesDelegate *not_with (const Region &other) const; + virtual std::pair andnot_with (const Region &) const; virtual EdgesDelegate *xor_with (const Edges &other) const; @@ -149,6 +151,7 @@ public: virtual EdgesDelegate *inside_part (const Region &other) const; virtual EdgesDelegate *outside_part (const Region &other) const; + virtual std::pair inside_outside_part_pair (const Region &) const; virtual RegionDelegate *extended (coord_type ext_b, coord_type ext_e, coord_type ext_o, coord_type ext_i, bool join) const; @@ -179,12 +182,14 @@ private: void ensure_merged_edges_valid () const; const DeepLayer &merged_deep_layer () const; DeepLayer and_or_not_with(const DeepEdges *other, EdgeBoolOp op) const; - DeepLayer edge_region_op (const DeepRegion *other, bool outside, bool include_borders) const; + std::pair edge_region_op (const DeepRegion *other, EdgePolygonOp::mode_t op, bool include_borders) const; EdgePairsDelegate *run_check (db::edge_relation_type rel, const Edges *other, db::Coord d, const db::EdgesCheckOptions &options) const; virtual EdgesDelegate *pull_generic (const Edges &edges) const; virtual RegionDelegate *pull_generic (const Region ®ion) const; - virtual EdgesDelegate *selected_interacting_generic (const Edges &edges, bool invert) const; - virtual EdgesDelegate *selected_interacting_generic (const Region ®ion, bool invert) const; + virtual EdgesDelegate *selected_interacting_generic (const Edges &edges, EdgeInteractionMode mode, bool inverse) const; + virtual std::pair selected_interacting_pair_generic (const Edges &edges, EdgeInteractionMode mode) const; + virtual EdgesDelegate *selected_interacting_generic (const Region ®ion, EdgeInteractionMode mode, bool inverse) const; + virtual std::pair selected_interacting_pair_generic (const Region ®ion, EdgeInteractionMode mode) const; DeepEdges *apply_filter (const EdgeFilterBase &filter) const; template OutputContainer *processed_impl (const edge_processor &filter) const; diff --git a/src/db/db/dbEdgeBoolean.h b/src/db/db/dbEdgeBoolean.h index 1e258104d..d09c20b29 100644 --- a/src/db/db/dbEdgeBoolean.h +++ b/src/db/db/dbEdgeBoolean.h @@ -36,7 +36,7 @@ namespace db /** * @brief A common definition for the boolean operations available on edges */ -enum EdgeBoolOp { EdgeOr, EdgeNot, EdgeXor, EdgeAnd, EdgeIntersections }; +enum EdgeBoolOp { EdgeOr, EdgeNot, EdgeXor, EdgeAnd, EdgeIntersections, EdgeAndNot /*not always supported*/ }; struct OrJoinOp { @@ -87,7 +87,13 @@ struct EdgeBooleanCluster typedef db::Edge::coord_type coord_type; EdgeBooleanCluster (OutputContainer *output, EdgeBoolOp op) - : mp_output (output), m_op (op) + : mp_output (output), mp_output2 (0), m_op (op) + { + // .. nothing yet .. + } + + EdgeBooleanCluster (OutputContainer *output, OutputContainer *output2, EdgeBoolOp op) + : mp_output (output), mp_output2 (output2), m_op (op) { // .. nothing yet .. } @@ -99,11 +105,13 @@ struct EdgeBooleanCluster // shortcut for single edge if (begin () + 1 == end ()) { if (begin ()->second == 0) { - if (m_op != EdgeAnd) { + if (m_op == EdgeAndNot) { + mp_output2->insert (*(begin ()->first)); + } else if (m_op != EdgeAnd) { mp_output->insert (*(begin ()->first)); } } else { - if (m_op != EdgeAnd && m_op != EdgeNot) { + if (m_op != EdgeAnd && m_op != EdgeNot && m_op != EdgeAndNot) { mp_output->insert (*(begin ()->first)); } } @@ -174,19 +182,34 @@ struct EdgeBooleanCluster if (b.begin () == b.end ()) { // optimize for empty b - if (m_op != EdgeAnd) { + OutputContainer *oc = 0; + if (m_op == EdgeAndNot) { + oc = mp_output; + } else if (m_op != EdgeAnd) { + oc = mp_output; + } + + if (oc) { for (tl::interval_map::const_iterator ib = b.begin (); ib != b.end (); ++ib) { if (ib->second > 0) { - mp_output->insert (db::Edge (p1 + db::Vector (d * (ib->first.first * n)), p1 + db::Vector (d * (ib->first.second * n)))); + oc->insert (db::Edge (p1 + db::Vector (d * (ib->first.first * n)), p1 + db::Vector (d * (ib->first.second * n)))); } else if (ib->second < 0) { - mp_output->insert (db::Edge (p1 + db::Vector (d * (ib->first.second * n)), p1 + db::Vector (d * (ib->first.first * n)))); + oc->insert (db::Edge (p1 + db::Vector (d * (ib->first.second * n)), p1 + db::Vector (d * (ib->first.first * n)))); } } } } else { - if (m_op == EdgeAnd) { + tl::interval_map q2; + + if (m_op == EdgeAnd || m_op == EdgeAndNot) { + if (m_op == EdgeAndNot) { + q2 = q; + for (tl::interval_map::const_iterator ib = b.begin (); ib != b.end (); ++ib) { + q2.add (ib->first.first, ib->first.second, ib->second, not_jop); + } + } for (tl::interval_map::const_iterator ib = b.begin (); ib != b.end (); ++ib) { q.add (ib->first.first, ib->first.second, ib->second, and_jop); } @@ -208,12 +231,20 @@ struct EdgeBooleanCluster } } + for (tl::interval_map::const_iterator iq = q2.begin (); iq != q2.end (); ++iq) { + if (iq->second > 0) { + mp_output2->insert (db::Edge (p1 + db::Vector (d * (iq->first.first * n)), p1 + db::Vector (d * (iq->first.second * n)))); + } else if (iq->second < 0) { + mp_output2->insert (db::Edge (p1 + db::Vector (d * (iq->first.second * n)), p1 + db::Vector (d * (iq->first.first * n)))); + } + } + } } private: - OutputContainer *mp_output; + OutputContainer *mp_output, *mp_output2; db::EdgeBoolOp m_op; }; @@ -221,8 +252,8 @@ template struct EdgeBooleanClusterCollector : public db::cluster_collector > { - EdgeBooleanClusterCollector (OutputContainer *output, EdgeBoolOp op) - : db::cluster_collector > (EdgeBooleanCluster (output, op == EdgeIntersections ? EdgeAnd : op), op != EdgeAnd && op != EdgeIntersections /*report single*/), + EdgeBooleanClusterCollector (OutputContainer *output, EdgeBoolOp op, OutputContainer *output2 = 0) + : db::cluster_collector > (EdgeBooleanCluster (output, output2, op == EdgeIntersections ? EdgeAnd : op), op != EdgeAnd && op != EdgeIntersections /*report single*/), mp_output (output), mp_intersections (op == EdgeIntersections ? output : 0) { // .. nothing yet .. @@ -377,6 +408,12 @@ public: typedef Iterator const_iterator; + ShapesToOutputContainerAdaptor () + : mp_shapes (0) + { + // .. nothing yet .. + } + ShapesToOutputContainerAdaptor (db::Shapes &shapes) : mp_shapes (&shapes) { @@ -413,8 +450,14 @@ struct DB_PUBLIC EdgeBooleanClusterCollectorToShapes { } + EdgeBooleanClusterCollectorToShapes (db::Shapes *output, EdgeBoolOp op, db::Shapes *output2) + : EdgeBooleanClusterCollector (&m_adaptor, op, &m_adaptor2), m_adaptor (*output), m_adaptor2 (*output2) + { + } + private: ShapesToOutputContainerAdaptor m_adaptor; + ShapesToOutputContainerAdaptor m_adaptor2; }; } diff --git a/src/db/db/dbEdgeProcessor.cc b/src/db/db/dbEdgeProcessor.cc index e5d75c16e..3b0261fe8 100644 --- a/src/db/db/dbEdgeProcessor.cc +++ b/src/db/db/dbEdgeProcessor.cc @@ -560,8 +560,8 @@ private: // ------------------------------------------------------------------------------- // EdgePolygonOp implementation -EdgePolygonOp::EdgePolygonOp (bool outside, bool include_touching, int polygon_mode) - : m_outside (outside), m_include_touching (include_touching), +EdgePolygonOp::EdgePolygonOp (EdgePolygonOp::mode_t mode, bool include_touching, int polygon_mode) + : m_mode (mode), m_include_touching (include_touching), m_function (polygon_mode), m_wcp_n (0), m_wcp_s (0) { @@ -572,27 +572,30 @@ void EdgePolygonOp::reset () m_wcp_n = m_wcp_s = 0; } -bool EdgePolygonOp::select_edge (bool horizontal, property_type p) +int EdgePolygonOp::select_edge (bool horizontal, property_type p) { if (p == 0) { + return 0; + } - return false; + bool inside; - } else if (horizontal) { - - bool res; + if (horizontal) { if (m_include_touching) { - res = (m_function (m_wcp_n) || m_function (m_wcp_s)); + inside = (m_function (m_wcp_n) || m_function (m_wcp_s)); } else { - res = (m_function (m_wcp_n) && m_function (m_wcp_s)); + inside = (m_function (m_wcp_n) && m_function (m_wcp_s)); } - - return m_outside ? !res : res; - } else { + inside = m_function (m_wcp_n); + } - return m_outside ? !m_function (m_wcp_n) : m_function (m_wcp_n); - + if (m_mode == Inside) { + return inside ? 1 : 0; + } else if (m_mode == Outside) { + return inside ? 0 : 1; + } else { + return inside ? 1 : 2; } } @@ -1626,6 +1629,7 @@ public: void reset () { + mp_es->reset_stop (); mp_op->reset (); } @@ -1634,6 +1638,11 @@ public: return mp_op->is_reset (); } + bool can_stop () + { + return mp_es->can_stop (); + } + void reserve (size_t n) { mp_op->reserve (n); @@ -1705,10 +1714,11 @@ public: void select_edge (const WorkEdge &e) { - if (mp_op->select_edge (e.dy () == 0, e.prop)) { - mp_es->put (e); + int tag = mp_op->select_edge (e.dy () == 0, e.prop); + if (tag > 0) { + mp_es->put (e, (unsigned int) tag); #ifdef DEBUG_EDGE_PROCESSOR - printf ("put(%s)\n", e.to_string().c_str()); + printf ("put(%s, %d)\n", e.to_string().c_str(), tag); #endif } } @@ -1937,6 +1947,19 @@ public: return true; } + /** + * @brief Gets a value indicating whether the generator wants to stop + */ + bool can_stop () + { + for (std::vector::iterator s = m_states.begin (); s != m_states.end (); ++s) { + if (s->can_stop ()) { + return true; + } + } + return false; + } + /** * @brief Reserve memory n edges */ @@ -2410,7 +2433,7 @@ EdgeProcessor::redo_or_process (const std::vectorbegin (); - for (std::vector ::iterator current = mp_work_edges->begin (); current != mp_work_edges->end (); ) { + for (std::vector ::iterator current = mp_work_edges->begin (); current != mp_work_edges->end () && ! gs.can_stop (); ) { if (m_report_progress) { double p = double (std::distance (mp_work_edges->begin (), current)) / double (mp_work_edges->size ()); diff --git a/src/db/db/dbEdgeProcessor.h b/src/db/db/dbEdgeProcessor.h index be7916479..b10f2e5c5 100644 --- a/src/db/db/dbEdgeProcessor.h +++ b/src/db/db/dbEdgeProcessor.h @@ -56,7 +56,7 @@ public: /** * @brief Constructor */ - EdgeSink () { } + EdgeSink () : m_can_stop (false) { } /** * @brief Destructor @@ -87,6 +87,15 @@ public: */ virtual void put (const db::Edge &) { } + /** + * @brief Deliver a tagged edge + * + * This method delivers an edge that ends or starts at the current scanline. + * This version includes a tag which is generated when using "select_edge". + * A tag is a value > 0 returned by "select_edge". + */ + virtual void put (const db::Edge &, int /*tag*/) { } + /** * @brief Deliver an edge that crosses the scanline * @@ -114,6 +123,38 @@ public: * @brief Signal the end of a scanline at the given y coordinate */ virtual void end_scanline (db::Coord /*y*/) { } + + /** + * @brief Gets a value indicating that the generator wants to stop + */ + bool can_stop () const + { + return m_can_stop; + } + + /** + * @brief Resets the stop request + */ + void reset_stop () + { + m_can_stop = false; + } + +protected: + /** + * @brief Sets the stop request + * + * The scanner can choose to stop once the request is set. + * This is useful for implementing receivers that can stop once a + * specific condition is found. + */ + void request_stop () + { + m_can_stop = true; + } + +private: + bool m_can_stop; }; /** @@ -130,15 +171,15 @@ public: /** * @brief Constructor connecting this receiver to an external edge vector */ - EdgeContainer (std::vector &edges, bool clear = false) - : EdgeSink (), mp_edges (&edges), m_clear (clear) + EdgeContainer (std::vector &edges, bool clear = false, int tag = 0, EdgeContainer *chained = 0) + : EdgeSink (), mp_edges (&edges), m_clear (clear), m_tag (tag), mp_chained (chained) { } /** * @brief Constructor using an internal edge vector */ - EdgeContainer () - : EdgeSink (), mp_edges (&m_edges), m_clear (false) + EdgeContainer (int tag = 0, EdgeContainer *chained = 0) + : EdgeSink (), mp_edges (&m_edges), m_clear (false), m_tag (tag), mp_chained (chained) { } /** @@ -167,6 +208,9 @@ public: // The single-shot scheme is a easy way to overcome problems with multiple start/flush brackets (i.e. on size filter) m_clear = false; } + if (mp_chained) { + mp_chained->start (); + } } /** @@ -175,12 +219,30 @@ public: virtual void put (const db::Edge &e) { mp_edges->push_back (e); + if (mp_chained) { + mp_chained->put (e); + } + } + + /** + * @brief Implementation of the EdgeSink interface + */ + virtual void put (const db::Edge &e, int tag) + { + if (m_tag == 0 || tag == m_tag) { + mp_edges->push_back (e); + } + if (mp_chained) { + mp_chained->put (e, tag); + } } private: std::vector m_edges; std::vector *mp_edges; bool m_clear; + int m_tag; + EdgeContainer *mp_chained; }; /** @@ -204,7 +266,7 @@ public: virtual void reset () { } virtual void reserve (size_t /*n*/) { } virtual int edge (bool /*north*/, bool /*enter*/, property_type /*p*/) { return 0; } - virtual bool select_edge (bool /*horizontal*/, property_type /*p*/) { return false; } + virtual int select_edge (bool /*horizontal*/, property_type /*p*/) { return 0; } virtual int compare_ns () const { return 0; } virtual bool is_reset () const { return false; } virtual bool prefer_touch () const { return false; } @@ -215,8 +277,8 @@ public: * @brief An intersection detector * * This edge evaluator will not produce output edges but rather record the - * property pairs of polygons intersecting. Only intersections (overlaps) - * are recorded. Touching contacts are not recorded. + * property pairs of polygons intersecting or interacting in the specified + * way. * * It will build a set of property pairs, where the lower property value * is the first one of the pairs. @@ -491,6 +553,15 @@ class DB_PUBLIC EdgePolygonOp : public db::EdgeEvaluatorBase { public: + /** + * @brief The operation mode + */ + enum mode_t { + Inside = 0, // Selects inside edges + Outside = 1, // Selects outside edges + Both = 2 // Selects both (inside -> tag #1, outside -> tag #2) + }; + /** * @brief Constructor * @@ -498,17 +569,18 @@ public: * @param include_touching If true, edges on the polygon's border will be considered "inside" of polygons * @param polygon_mode Determines how the polygon edges on property 0 are interpreted (see merge operators) */ - EdgePolygonOp (bool outside = false, bool include_touching = true, int polygon_mode = -1); + EdgePolygonOp (mode_t mode = Inside, bool include_touching = true, int polygon_mode = -1); virtual void reset (); - virtual bool select_edge (bool horizontal, property_type p); + virtual int select_edge (bool horizontal, property_type p); virtual int edge (bool north, bool enter, property_type p); virtual bool is_reset () const; virtual bool prefer_touch () const; virtual bool selects_edges () const; private: - bool m_outside, m_include_touching; + mode_t m_mode; + bool m_include_touching; db::ParametrizedInsideFunc m_function; int m_wcp_n, m_wcp_s; }; diff --git a/src/db/db/dbEdges.h b/src/db/db/dbEdges.h index 77bc25801..6f2114d41 100644 --- a/src/db/db/dbEdges.h +++ b/src/db/db/dbEdges.h @@ -274,6 +274,16 @@ public: return mp_delegate; } + /** + * @brief Takes the underlying delegate object + */ + EdgesDelegate *take_delegate () + { + EdgesDelegate *delegate = mp_delegate; + mp_delegate = 0; + return delegate; + } + /** * @brief Sets the base verbosity * @@ -794,6 +804,24 @@ public: return *this; } + /** + * @brief Boolean AND/NOT operator in the same operation + */ + std::pair andnot (const Edges &other) const + { + std::pair p = mp_delegate->andnot_with (other); + return std::pair (Edges (p.first), Edges (p.second)); + } + + /** + * @brief Boolean AND/NOT operator with a region in the same operation + */ + std::pair andnot (const Region &other) const + { + std::pair p = mp_delegate->andnot_with (other); + return std::pair (Edges (p.first), Edges (p.second)); + } + /** * @brief Boolean XOR operator */ @@ -974,6 +1002,17 @@ public: return Edges (mp_delegate->outside_part (other)); } + /** + * @brief Returns the eges inside the given region and the ones outside the region. + * + * This method combined both inside_part and outside_part. + */ + std::pair inside_outside_part (const Region &other) const + { + std::pair p = mp_delegate->inside_outside_part_pair (other); + return std::pair (Edges (p.first), Edges (p.second)); + } + /** * @brief Selects all polygons of the other region set which overlap or touch edges from this edge set * @@ -1037,6 +1076,251 @@ public: return Edges (mp_delegate->selected_not_interacting (other)); } + /** + * @brief Returns all edges of this edge set which do not overlap or touch with polygons from the region together with the ones that do not + */ + std::pair selected_interacting_differential (const Region &other) const + { + std::pair p = mp_delegate->selected_interacting_pair (other); + return std::pair (Edges (p.first), Edges (p.second)); + } + + /** + * @brief Selects all edges of this edge collection which are completely outside polygons from the region + * + * Merged semantics applies. + */ + Edges &select_outside (const Region &other) + { + set_delegate (mp_delegate->selected_outside (other)); + return *this; + } + + /** + * @brief Selects all edges of this edge collection which are not completely outside polygons from the region + * + * Merged semantics applies. + */ + Edges &select_not_outside (const Region &other) + { + set_delegate (mp_delegate->selected_not_outside (other)); + return *this; + } + + /** + * @brief Returns all edges of this edge collection which are completely outside polygons from the region + * + * This method is an out-of-place version of select_outside. + * + * Merged semantics applies. + */ + Edges selected_outside (const Region &other) const + { + return Edges (mp_delegate->selected_outside (other)); + } + + /** + * @brief Returns all edges of this edge collection which are not completely outside polygons from the region + * + * This method is an out-of-place version of select_not_outside. + * + * Merged semantics applies. + */ + Edges selected_not_outside (const Region &other) const + { + return Edges (mp_delegate->selected_not_outside (other)); + } + + /** + * @brief Returns all edges of this which are completely outside polygons from the region and the opposite ones at the same time + * + * This method is equivalent to calling selected_outside and selected_not_outside, but faster. + * + * Merged semantics applies. + */ + std::pair selected_outside_differential (const Region &other) const + { + std::pair p = mp_delegate->selected_outside_pair (other); + return std::pair (Edges (p.first), Edges (p.second)); + } + + /** + * @brief Selects all edges of this edge collection which are completely inside polygons from the region + * + * Merged semantics applies. + */ + Edges &select_inside (const Region &other) + { + set_delegate (mp_delegate->selected_inside (other)); + return *this; + } + + /** + * @brief Selects all edges of this edge collection which are not completely inside polygons from the region + * + * Merged semantics applies. + */ + Edges &select_not_inside (const Region &other) + { + set_delegate (mp_delegate->selected_not_inside (other)); + return *this; + } + + /** + * @brief Returns all edges of this which are completely inside polygons from the region + * + * This method is an out-of-place version of select_inside. + * + * Merged semantics applies. + */ + Edges selected_inside (const Region &other) const + { + return Edges (mp_delegate->selected_inside (other)); + } + + /** + * @brief Returns all edges of this which are not completely inside polygons from the region + * + * This method is an out-of-place version of select_not_inside. + * + * Merged semantics applies. + */ + Edges selected_not_inside (const Region &other) const + { + return Edges (mp_delegate->selected_not_inside (other)); + } + + /** + * @brief Returns all edges of this which are completely inside polygons from the region and the opposite ones at the same time + * + * This method is equivalent to calling selected_inside and selected_not_inside, but faster. + * + * Merged semantics applies. + */ + std::pair selected_inside_differential (const Region &other) const + { + std::pair p = mp_delegate->selected_inside_pair (other); + return std::pair (Edges (p.first), Edges (p.second)); + } + + /** + * @brief Selects all edges of this edge collection which are completely outside edges from the other edge collection + * + * Merged semantics applies. + */ + Edges &select_outside (const Edges &other) + { + set_delegate (mp_delegate->selected_outside (other)); + return *this; + } + + /** + * @brief Selects all edges of this edge collection which are not completely outside edges from the other edge collection + * + * Merged semantics applies. + */ + Edges &select_not_outside (const Edges &other) + { + set_delegate (mp_delegate->selected_not_outside (other)); + return *this; + } + + /** + * @brief Returns all edges of this edge collection which are completely outside edges from the other edge collection + * + * This method is an out-of-place version of select_outside. + * + * Merged semantics applies. + */ + Edges selected_outside (const Edges &other) const + { + return Edges (mp_delegate->selected_outside (other)); + } + + /** + * @brief Returns all edges of this edge collection which are not completely outside edges from the other edge collection + * + * This method is an out-of-place version of select_not_outside. + * + * Merged semantics applies. + */ + Edges selected_not_outside (const Edges &other) const + { + return Edges (mp_delegate->selected_not_outside (other)); + } + + /** + * @brief Returns all edges of this which are completely outside edges from the other edge collection and the opposite ones at the same time + * + * This method is equivalent to calling selected_outside and selected_not_outside, but faster. + * + * Merged semantics applies. + */ + std::pair selected_outside_differential (const Edges &other) const + { + std::pair p = mp_delegate->selected_outside_pair (other); + return std::pair (Edges (p.first), Edges (p.second)); + } + + /** + * @brief Selects all edges of this edge collection which are completely inside edges from the other edge collection + * + * Merged semantics applies. + */ + Edges &select_inside (const Edges &other) + { + set_delegate (mp_delegate->selected_inside (other)); + return *this; + } + + /** + * @brief Selects all edges of this edge collection which are not completely inside edges from the other edge collection + * + * Merged semantics applies. + */ + Edges &select_not_inside (const Edges &other) + { + set_delegate (mp_delegate->selected_not_inside (other)); + return *this; + } + + /** + * @brief Returns all edges of this which are completely inside edgess from the other edge collection + * + * This method is an out-of-place version of select_inside. + * + * Merged semantics applies. + */ + Edges selected_inside (const Edges &other) const + { + return Edges (mp_delegate->selected_inside (other)); + } + + /** + * @brief Returns all edges of this which are not completely inside edges from the other edge collection + * + * This method is an out-of-place version of select_not_inside. + * + * Merged semantics applies. + */ + Edges selected_not_inside (const Edges &other) const + { + return Edges (mp_delegate->selected_not_inside (other)); + } + + /** + * @brief Returns all edges of this which are completely inside edges from the other edge collection and the opposite ones at the same time + * + * This method is equivalent to calling selected_inside and selected_not_inside, but faster. + * + * Merged semantics applies. + */ + std::pair selected_inside_differential (const Edges &other) const + { + std::pair p = mp_delegate->selected_inside_pair (other); + return std::pair (Edges (p.first), Edges (p.second)); + } + /** * @brief Selects all edges of this edge set which overlap or touch with edges from the other edge set * @@ -1059,6 +1343,15 @@ public: return Edges (mp_delegate->selected_interacting (other)); } + /** + * @brief Returns all edges of this edge set which do not overlap or touch with edges from the other edge set together with the ones that do not + */ + std::pair selected_interacting_differential (const Edges &other) const + { + std::pair p = mp_delegate->selected_interacting_pair (other); + return std::pair (Edges (p.first), Edges (p.second)); + } + /** * @brief Selects all edges of this edge set which do not overlap or touch with edges from the other edge set * diff --git a/src/db/db/dbEdgesDelegate.h b/src/db/db/dbEdgesDelegate.h index d33084df5..59a595f4b 100644 --- a/src/db/db/dbEdgesDelegate.h +++ b/src/db/db/dbEdgesDelegate.h @@ -294,9 +294,11 @@ public: virtual EdgesDelegate *merged () const = 0; virtual EdgesDelegate *and_with (const Edges &other) const = 0; - virtual EdgesDelegate *and_with (const Region &other) const = 0; virtual EdgesDelegate *not_with (const Edges &other) const = 0; + virtual std::pair andnot_with (const Edges &) const = 0; + virtual EdgesDelegate *and_with (const Region &other) const = 0; virtual EdgesDelegate *not_with (const Region &other) const = 0; + virtual std::pair andnot_with (const Region &) const = 0; virtual EdgesDelegate *xor_with (const Edges &other) const = 0; virtual EdgesDelegate *or_with (const Edges &other) const = 0; virtual EdgesDelegate *add_in_place (const Edges &other) = 0; @@ -307,12 +309,28 @@ public: virtual EdgesDelegate *inside_part (const Region &other) const = 0; virtual EdgesDelegate *outside_part (const Region &other) const = 0; + virtual std::pair inside_outside_part_pair (const Region &other) const = 0; virtual RegionDelegate *pull_interacting (const Region &) const = 0; virtual EdgesDelegate *pull_interacting (const Edges &) const = 0; virtual EdgesDelegate *selected_interacting (const Region &other) const = 0; virtual EdgesDelegate *selected_not_interacting (const Region &other) const = 0; virtual EdgesDelegate *selected_interacting (const Edges &other) const = 0; virtual EdgesDelegate *selected_not_interacting (const Edges &other) const = 0; + virtual std::pair selected_interacting_pair (const Region &other) const = 0; + virtual std::pair selected_interacting_pair (const Edges &other) const = 0; + + virtual EdgesDelegate *selected_outside (const Region &other) const = 0; + virtual EdgesDelegate *selected_not_outside (const Region &other) const = 0; + virtual std::pair selected_outside_pair (const Region &other) const = 0; + virtual EdgesDelegate *selected_inside (const Region &other) const = 0; + virtual EdgesDelegate *selected_not_inside (const Region &other) const = 0; + virtual std::pair selected_inside_pair (const Region &other) const = 0; + virtual EdgesDelegate *selected_outside (const Edges &other) const = 0; + virtual EdgesDelegate *selected_not_outside (const Edges &other) const = 0; + virtual std::pair selected_outside_pair (const Edges &other) const = 0; + virtual EdgesDelegate *selected_inside (const Edges &other) const = 0; + virtual EdgesDelegate *selected_not_inside (const Edges &other) const = 0; + virtual std::pair selected_inside_pair (const Edges &other) const = 0; virtual EdgesDelegate *in (const Edges &other, bool invert) const = 0; diff --git a/src/db/db/dbEdgesUtils.cc b/src/db/db/dbEdgesUtils.cc index add511f2e..df0ca4dfd 100644 --- a/src/db/db/dbEdgesUtils.cc +++ b/src/db/db/dbEdgesUtils.cc @@ -177,7 +177,7 @@ extended_edge (const db::Edge &edge, db::Coord ext_b, db::Coord ext_e, db::Coord // ------------------------------------------------------------------------------------------------------------- // EdgeSegmentSelector processor -EdgeSegmentSelector::EdgeSegmentSelector (int mode, db::Edges::length_type length, double fraction) +EdgeSegmentSelector::EdgeSegmentSelector (int mode, Edge::distance_type length, double fraction) : m_mode (mode), m_length (length), m_fraction (fraction) { } @@ -274,4 +274,96 @@ EdgeOrientationFilter::selected (const db::Edge &edge) const } } +// ------------------------------------------------------------------------------------------------------------- +// Edge to Edge relation implementation + +bool edge_interacts (const db::Edge &a, const db::Edge &b) +{ + return a.intersect (b); +} + +bool edge_is_inside (const db::Edge &a, const db::Edge &b) +{ + return b.contains (a.p1 ()) && b.contains (a.p2 ()); +} + +bool edge_is_outside (const db::Edge &a, const db::Edge &b) +{ + if (a.parallel (b)) { + return ! a.coincident (b); + } else { + auto pt = a.intersect_point (b); + if (! pt.first) { + // no intersection -> outside + return true; + } + return ! b.contains_excl (pt.second) || ! a.contains_excl (pt.second); + } +} + +// ------------------------------------------------------------------------------------------------------------- +// Edge to Polygon relation implementation + +bool edge_interacts (const db::Edge &a, const db::Polygon &b) +{ + return db::interact (b, a); +} + +namespace { + +struct DetectTagEdgeSink + : public db::EdgeSink +{ + DetectTagEdgeSink (int tag) + : fail_tag (tag), result (true) { } + + virtual void put (const db::Edge &, int tag) + { + if (tag == fail_tag) { + result = false; + request_stop (); + } + } + + int fail_tag; + bool result; +}; + +} + +static bool +edge_is_inside_or_outside (bool outside, const db::Edge &a, const db::Polygon &b) +{ + db::EdgeProcessor ep; + ep.insert (b, 0); + + ep.insert (a, 1); + + DetectTagEdgeSink es (outside ? 1 : 2); // 2 is the "outside" tag in "Both" mode -> this makes inside fail + db::EdgePolygonOp op (db::EdgePolygonOp::Both, true /*include borders*/); + ep.process (es, op); + + return es.result; +} + +bool edge_is_inside (const db::Edge &a, const db::Polygon &b) +{ + // shortcuts + if (!a.bbox ().inside (b.box ())) { + return false; + } + + return edge_is_inside_or_outside (false, a, b); +} + +bool edge_is_outside (const db::Edge &a, const db::Polygon &b) +{ + // shortcuts + if (! a.bbox ().overlaps (b.box ())) { + return true; + } + + return edge_is_inside_or_outside (true, a, b); +} + } diff --git a/src/db/db/dbEdgesUtils.h b/src/db/db/dbEdgesUtils.h index 666581358..055d78eae 100644 --- a/src/db/db/dbEdgesUtils.h +++ b/src/db/db/dbEdgesUtils.h @@ -34,6 +34,11 @@ namespace db { +/** + * @brief The operation mode for the interaction filters + */ +enum EdgeInteractionMode { EdgesInteract, EdgesInside, EdgesOutside }; + class PolygonSink; /** @@ -241,6 +246,21 @@ private: EdgeAngleChecker m_checker; }; +/** + * @brief A predicate defining edge a interacts with b + */ +DB_PUBLIC bool edge_interacts (const db::Edge &a, const db::Edge &b); + +/** + * @brief A predicate defining edge a is "inside" b + */ +DB_PUBLIC bool edge_is_inside (const db::Edge &a, const db::Edge &b); + +/** + * @brief A predicate defining edge a is "outside" b + */ +DB_PUBLIC bool edge_is_outside (const db::Edge &a, const db::Edge &b); + /** * @brief A helper class for the edge interaction functionality which acts as an edge pair receiver */ @@ -249,31 +269,65 @@ class edge_interaction_filter : public db::box_scanner_receiver { public: - edge_interaction_filter (OutputContainer &output) - : mp_output (&output) + edge_interaction_filter (OutputContainer &output, EdgeInteractionMode mode) + : mp_output (&output), m_mode (mode) { // .. nothing yet .. } + void finish (const db::Edge *o, size_t p) + { + if (p == 0 && m_mode == EdgesOutside && m_seen.find (o) == m_seen.end ()) { + mp_output->insert (*o); + } + } + void add (const db::Edge *o1, size_t p1, const db::Edge *o2, size_t p2) { // Select the edges which intersect if (p1 != p2) { + const db::Edge *o = p1 > p2 ? o2 : o1; const db::Edge *oo = p1 > p2 ? o1 : o2; - if (o->intersect (*oo)) { + + if ((m_mode == EdgesInteract && db::edge_interacts (*o, *oo)) || + (m_mode == EdgesInside && db::edge_is_inside (*o, *oo))) { + if (m_seen.insert (o).second) { mp_output->insert (*o); } + + } else if (m_mode == EdgesOutside && ! db::edge_is_outside (*o, *oo)) { + + // In this case we need to collect edges which are outside always - we report those on "finished". + m_seen.insert (o); + } + } } private: OutputContainer *mp_output; std::set m_seen; + EdgeInteractionMode m_mode; }; +/** + * @brief A predicate defining edge a interacts with polygon b + */ +DB_PUBLIC bool edge_interacts (const db::Edge &a, const db::Polygon &b); + +/** + * @brief A predicate defining edge a is "inside" polygon b + */ +DB_PUBLIC bool edge_is_inside (const db::Edge &a, const db::Polygon &b); + +/** + * @brief A predicate defining edge a is "outside" polygon b + */ +DB_PUBLIC bool edge_is_outside (const db::Edge &a, const db::Polygon &b); + /** * @brief A helper class for the edge to region interaction functionality which acts as an edge pair receiver * @@ -288,28 +342,64 @@ class edge_to_region_interaction_filter : public db::box_scanner_receiver2 { public: - edge_to_region_interaction_filter (OutputContainer &output) - : mp_output (&output) + edge_to_region_interaction_filter (OutputContainer *output, EdgeInteractionMode mode) + : mp_output (output), m_mode (mode) { // .. nothing yet .. } + void finish (const OutputType *o) + { + if (m_mode == EdgesOutside && m_seen.find (o) == m_seen.end ()) { + mp_output->insert (*o); + } + } + + void finish1 (const db::Edge *o, size_t /*p*/) + { + const OutputType *ep = 0; + tl::select (ep, o, (const db::Polygon *) 0); + if (ep) { + finish (ep); + } + } + + void finish2 (const db::Polygon *o, size_t /*p*/) + { + const OutputType *ep = 0; + tl::select (ep, (const db::Edge *) 0, o); + if (ep) { + finish (ep); + } + } + void add (const db::Edge *e, size_t, const db::Polygon *p, size_t) { const OutputType *ep = 0; tl::select (ep, e, p); if (m_seen.find (ep) == m_seen.end ()) { - if (db::interact (*p, *e)) { + + if ((m_mode == EdgesInteract && db::edge_interacts (*e, *p)) || + (m_mode == EdgesInside && db::edge_is_inside (*e, *p))) { + m_seen.insert (ep); mp_output->insert (*ep); + + } else if (m_mode == EdgesOutside && ! db::edge_is_outside (*e, *p)) { + + // In this case we need to collect edges which are outside always - we report those on "finished". + m_seen.insert (ep); + } + } } private: OutputContainer *mp_output; std::set m_seen; + EdgeInteractionMode m_mode; }; /** @@ -407,7 +497,7 @@ class DB_PUBLIC EdgeSegmentSelector : public EdgeProcessorBase { public: - EdgeSegmentSelector (int mode, db::Edges::length_type length, double fraction); + EdgeSegmentSelector (int mode, Edge::distance_type length, double fraction); ~EdgeSegmentSelector (); virtual void process (const db::Edge &edge, std::vector &res) const; @@ -420,7 +510,7 @@ public: private: int m_mode; - db::Edges::length_type m_length; + db::Edge::distance_type m_length; double m_fraction; db::MagnificationReducer m_vars; }; diff --git a/src/db/db/dbEmptyEdges.h b/src/db/db/dbEmptyEdges.h index a58f5d374..569eada56 100644 --- a/src/db/db/dbEmptyEdges.h +++ b/src/db/db/dbEmptyEdges.h @@ -75,9 +75,11 @@ public: virtual EdgesDelegate *merged () const { return new EmptyEdges (); } virtual EdgesDelegate *and_with (const Edges &) const { return new EmptyEdges (); } - virtual EdgesDelegate *and_with (const Region &) const { return new EmptyEdges (); } virtual EdgesDelegate *not_with (const Edges &) const { return new EmptyEdges (); } + virtual std::pair andnot_with (const Edges &) const { return std::make_pair (new EmptyEdges (), new EmptyEdges ()); } + virtual EdgesDelegate *and_with (const Region &) const { return new EmptyEdges (); } virtual EdgesDelegate *not_with (const Region &) const { return new EmptyEdges (); } + virtual std::pair andnot_with (const Region &) const { return std::make_pair (new EmptyEdges (), new EmptyEdges ()); } virtual EdgesDelegate *xor_with (const Edges &other) const; virtual EdgesDelegate *or_with (const Edges &other) const; virtual EdgesDelegate *add_in_place (const Edges &other); @@ -88,12 +90,29 @@ public: virtual EdgesDelegate *inside_part (const Region &) const { return new EmptyEdges (); } virtual EdgesDelegate *outside_part (const Region &) const { return new EmptyEdges (); } + virtual std::pair inside_outside_part_pair (const Region &) const { return std::make_pair (new EmptyEdges (), new EmptyEdges ()); } + virtual RegionDelegate *pull_interacting (const Region &) const; virtual EdgesDelegate *pull_interacting (const Edges &) const { return new EmptyEdges (); } virtual EdgesDelegate *selected_interacting (const Edges &) const { return new EmptyEdges (); } virtual EdgesDelegate *selected_not_interacting (const Edges &) const { return new EmptyEdges (); } virtual EdgesDelegate *selected_interacting (const Region &) const { return new EmptyEdges (); } virtual EdgesDelegate *selected_not_interacting (const Region &) const { return new EmptyEdges (); } + virtual std::pair selected_interacting_pair (const Region &) const { return std::make_pair (new EmptyEdges (), new EmptyEdges ()); } + virtual std::pair selected_interacting_pair (const Edges &) const { return std::make_pair (new EmptyEdges (), new EmptyEdges ()); } + + virtual EdgesDelegate *selected_outside (const Region &) const { return new EmptyEdges (); } + virtual EdgesDelegate *selected_not_outside (const Region &) const { return new EmptyEdges (); } + virtual std::pair selected_outside_pair (const Region &) const { return std::make_pair (new EmptyEdges (), new EmptyEdges ()); } + virtual EdgesDelegate *selected_inside (const Region &) const { return new EmptyEdges (); } + virtual EdgesDelegate *selected_not_inside (const Region &) const { return new EmptyEdges (); } + virtual std::pair selected_inside_pair (const Region &) const { return std::make_pair (new EmptyEdges (), new EmptyEdges ()); } + virtual EdgesDelegate *selected_outside (const Edges &) const { return new EmptyEdges (); } + virtual EdgesDelegate *selected_not_outside (const Edges &) const { return new EmptyEdges (); } + virtual std::pair selected_outside_pair (const Edges &) const { return std::make_pair (new EmptyEdges (), new EmptyEdges ()); } + virtual EdgesDelegate *selected_inside (const Edges &) const { return new EmptyEdges (); } + virtual EdgesDelegate *selected_not_inside (const Edges &) const { return new EmptyEdges (); } + virtual std::pair selected_inside_pair (const Edges &) const { return std::make_pair (new EmptyEdges (), new EmptyEdges ()); } virtual EdgesDelegate *in (const Edges &, bool) const { return new EmptyEdges (); } diff --git a/src/db/db/dbFillTool.cc b/src/db/db/dbFillTool.cc index e4540a1e5..78aff9644 100644 --- a/src/db/db/dbFillTool.cc +++ b/src/db/db/dbFillTool.cc @@ -152,30 +152,6 @@ public: } } - size_t filled_pixels () const - { - size_t n = 0; - - for (std::vector::const_iterator a = m_area_maps.begin (); a != m_area_maps.end (); ++a) { - - db::Coord nx = db::Coord (a->nx ()); - db::Coord ny = db::Coord (a->ny ()); - db::AreaMap::area_type amax = a->pixel_area (); - - double n = 0; - for (size_t i = 0; i < size_t (nx); ++i) { - for (size_t j = 0; j < size_t (ny); ++j) { - if (a->get (i, j) >= amax) { - n += 1; - } - } - } - - } - - return n; - } - const db::Point &p0 () const { return m_origin; } unsigned int row_steps () const { return m_row_steps; } diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index 6b9bf63cc..d8c9114d5 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -1366,9 +1366,10 @@ compute_area_and_perimeter_of_net_shapes (const db::hier_clusters perimeter = ap_collector.perimeter (); } -static void +static db::Point get_merged_shapes_of_net (const db::hier_clusters &clusters, db::cell_index_type ci, size_t cid, unsigned int layer_id, db::Shapes &shapes) { + db::Point ref; db::EdgeProcessor ep; // count vertices and reserve space @@ -1380,16 +1381,76 @@ get_merged_shapes_of_net (const db::hier_clusters &clusters, db::c size_t p = 0; for (db::recursive_cluster_shape_iterator rci (clusters, layer_id, ci, cid); !rci.at_end (); ++rci) { - ep.insert (rci.trans () * rci->polygon_ref (), ++p); + if (p == 0) { + db::PolygonRef pr = (rci.trans () * rci->polygon_ref ()); + db::PolygonRef::polygon_edge_iterator e = pr.begin_edge (); + if (! e.at_end ()) { + // pick one reference point for the label + ref = (*e).p1 (); + ep.insert (pr, ++p); + } + } else { + ep.insert (rci.trans () * rci->polygon_ref (), ++p); + } } db::ShapeGenerator sg (shapes); db::PolygonGenerator pg (sg, false); db::SimpleMerge op; ep.process (pg, op); + + return ref; } -db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_area_factor, double gate_perimeter_factor, const db::Region &metal, double metal_area_factor, double metal_perimeter_factor, double ratio, const std::vector > &diodes) +static std::string +create_antenna_msg (double agate, db::Polygon::area_type agate_int, double gate_area_factor, db::Polygon::perimeter_type pgate_int, double gate_perimeter_factor, + double ametal, db::Polygon::area_type ametal_int, double metal_area_factor, db::Polygon::perimeter_type pmetal_int, double metal_perimeter_factor, + const std::vector > &diodes, + const std::vector &adiodes_int, + double r, double ratio, double dbu) +{ + std::string msg; + msg += tl::sprintf ("agate_eff: %.12g, ", agate); + if (fabs (gate_area_factor) > 1e-6) { + msg += tl::sprintf ("agate: %.12g, agate_factor: %.12g, ", agate_int * dbu * dbu, gate_area_factor); + } + if (fabs (gate_perimeter_factor) > 1e-6) { + msg += tl::sprintf ("pgate: %.12g, pgate_factor: %.12g, ", pgate_int * dbu * dbu, gate_perimeter_factor); + } + msg += tl::sprintf ("ametal_eff: %.12g, ", ametal); + if (fabs (metal_area_factor) > 1e-6) { + msg += tl::sprintf ("ametal: %.12g, ametal_factor: %.12g, ", ametal_int * dbu * dbu, metal_area_factor); + } + if (fabs (metal_perimeter_factor) > 1e-6) { + msg += tl::sprintf ("pmetal: %.12g, pmetal_factor: %.12g, ", pmetal_int * dbu * dbu, metal_perimeter_factor); + } + if (! adiodes_int.empty ()) { + msg += "adiodes: ["; + for (auto d = adiodes_int.begin (); d != adiodes_int.end (); ++d) { + if (d != adiodes_int.begin ()) { + msg += ", "; + } + msg += tl::sprintf ("%.12g", *d * dbu * dbu); + } + msg += "], "; + } + if (! diodes.empty ()) { + msg += "diode_factors: ["; + for (auto d = diodes.begin (); d != diodes.end (); ++d) { + if (d != diodes.begin ()) { + msg += ", "; + } + msg += tl::sprintf ("%.12g", d->second); + } + msg += "], "; + } + msg += tl::sprintf ("ratio: %.12g, ", ametal / agate); + msg += tl::sprintf ("max_ratio_eff: %.12g, ", r); + msg += tl::sprintf ("max_ratio: %.12g", ratio); + return msg; +} + +db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_area_factor, double gate_perimeter_factor, const db::Region &metal, double metal_area_factor, double metal_perimeter_factor, double ratio, const std::vector > &diodes, db::Texts *values) { // TODO: that's basically too much .. we only need the clusters if (! m_netlist_extracted) { @@ -1401,6 +1462,11 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_a db::DeepLayer dl (&dss (), m_layout_index, ly.insert_layer ()); + db::DeepLayer dlv; + if (values) { + dlv = db::DeepLayer (&dss (), m_layout_index, ly.insert_layer ()); + } + for (db::Layout::bottom_up_const_iterator cid = ly.begin_bottom_up (); cid != ly.end_bottom_up (); ++cid) { const connected_clusters &clusters = m_net_clusters.clusters_per_cell (*cid); @@ -1408,6 +1474,8 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_a continue; } + std::vector adiodes_int; + for (connected_clusters::all_iterator c = clusters.begin_all (); ! c.at_end (); ++c) { if (! clusters.is_root (*c)) { @@ -1417,13 +1485,18 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_a double r = ratio; bool skip = false; - for (std::vector >::const_iterator d = diodes.begin (); d != diodes.end () && ! skip; ++d) { + adiodes_int.clear (); + adiodes_int.reserve (diodes.size ()); + + for (auto d = diodes.begin (); d != diodes.end () && ! skip; ++d) { db::Polygon::area_type adiode_int = 0; db::Polygon::perimeter_type pdiode_int = 0; compute_area_and_perimeter_of_net_shapes (m_net_clusters, *cid, *c, layer_of (*d->first), adiode_int, pdiode_int); + adiodes_int.push_back (adiode_int); + if (fabs (d->second) < db::epsilon) { if (adiode_int > 0) { skip = true; @@ -1465,12 +1538,29 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_a } if (tl::verbosity () >= 50) { - tl::info << "cell [" << ly.cell_name (*cid) << "]: agate=" << tl::to_string (agate) << ", ametal=" << tl::to_string (ametal) << ", r=" << tl::sprintf ("%.12g", r); + tl::info << "cell [" << ly.cell_name (*cid) << "]: " << + create_antenna_msg (agate, agate_int, gate_area_factor, pgate_int, gate_perimeter_factor, + ametal, ametal_int, metal_area_factor, pmetal_int, metal_perimeter_factor, + diodes, adiodes_int, r, ratio, dbu); } if (ametal / agate > r + db::epsilon) { + db::Shapes &shapes = ly.cell (*cid).shapes (dl.layer ()); - get_merged_shapes_of_net (m_net_clusters, *cid, *c, layer_of (metal), shapes); + db::Point ref = get_merged_shapes_of_net (m_net_clusters, *cid, *c, layer_of (metal), shapes); + + if (values) { + + // generate a data string with the details of the antenna computation (intentionally like JSON) + std::string msg = create_antenna_msg (agate, agate_int, gate_area_factor, pgate_int, gate_perimeter_factor, + ametal, ametal_int, metal_area_factor, pmetal_int, metal_perimeter_factor, + diodes, adiodes_int, r, ratio, dbu); + + db::Shapes &shapesv = ly.cell (*cid).shapes (dlv.layer ()); + shapesv.insert (db::Text (msg, db::Trans (ref - db::Point ()))); + + } + } } @@ -1481,6 +1571,10 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_a } + if (values) { + *values = db::Texts (new db::DeepTexts (dlv)); + } + return db::Region (new db::DeepRegion (dl)); } diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index 6b04e5cce..f1b099076 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -856,18 +856,18 @@ public: * regardless of the diode's area. * In other words: any diode will make the net safe against antenna discharge. */ - db::Region antenna_check (const db::Region &gate, double gate_perimeter_factor, const db::Region &metal, double metal_perimeter_factor, double ratio, const std::vector > &diodes = std::vector > ()) + db::Region antenna_check (const db::Region &gate, double gate_perimeter_factor, const db::Region &metal, double metal_perimeter_factor, double ratio, const std::vector > &diodes = std::vector > (), db::Texts *values = 0) { - return antenna_check (gate, 1.0, gate_perimeter_factor, metal, 1.0, metal_perimeter_factor, ratio, diodes); + return antenna_check (gate, 1.0, gate_perimeter_factor, metal, 1.0, metal_perimeter_factor, ratio, diodes, values); } /** * @brief Variant of the antenna check not using the perimeter * This version uses 0 for the perimeter factor hence not taking into account the perimeter at all. */ - db::Region antenna_check (const db::Region &gate, const db::Region &metal, double ratio, const std::vector > &diodes = std::vector > ()) + db::Region antenna_check (const db::Region &gate, const db::Region &metal, double ratio, const std::vector > &diodes = std::vector > (), db::Texts *values = 0) { - return antenna_check (gate, 1.0, 0.0, metal, 1.0, 0.0, ratio, diodes); + return antenna_check (gate, 1.0, 0.0, metal, 1.0, 0.0, ratio, diodes, values); } /** @@ -879,8 +879,10 @@ public: * * where f is the area scale factor and t the perimeter scale factor. This version allows to ignore the * area contribution entirely and switch to a perimeter-based antenna check by setting f to zero. + * + * If values is non-null, texts explaining the violations are placed there. */ - db::Region antenna_check (const db::Region &gate, double gate_area_factor, double gate_perimeter_factor, const db::Region &metal, double metal_area_factor, double metal_perimeter_factor, double ratio, const std::vector > &diodes = std::vector > ()); + db::Region antenna_check (const db::Region &gate, double gate_area_factor, double gate_perimeter_factor, const db::Region &metal, double metal_area_factor, double metal_perimeter_factor, double ratio, const std::vector > &diodes = std::vector > (), Texts *values = 0); /** * @brief Saves the database to the given path diff --git a/src/db/db/dbLayoutToNetlistFormatDefs.h b/src/db/db/dbLayoutToNetlistFormatDefs.h index d77386a2d..428eaaeaa 100644 --- a/src/db/db/dbLayoutToNetlistFormatDefs.h +++ b/src/db/db/dbLayoutToNetlistFormatDefs.h @@ -46,55 +46,76 @@ namespace db * The file follows the declaration-before-use principle * (circuits before subcircuits, nets before use ...) * - * Global statements: + * Main body: + * [version|description|unit|top|layer|connect|global|circuit|class|device|any]* * + * [version]: * version() - file format version [short key: V] + * + * [description]: * description() - an arbitrary description text [short key: B] + * + * [unit]: * unit() - specifies the database unit [short key: U] + * + * [top]: * top() - specifies the name of the top circuit [short key: W] + * + * [layer]: * layer( ?) - define a layer [short key: L] + * + * [connect]: * connect( ...) - connects layer1 with the following layers [short key: C] + * + * [global]: * global( ...) * - connects the shapes of the layer with the given global * nets [short key: G] + * + * [circuit]: * circuit( [circuit-def]) - circuit (cell) [short key: X] + * + * [class]: * class(