diff --git a/src/db/db/dbCompoundOperation.h b/src/db/db/dbCompoundOperation.h index 34b12c8a1..e052a6e67 100644 --- a/src/db/db/dbCompoundOperation.h +++ b/src/db/db/dbCompoundOperation.h @@ -1046,7 +1046,7 @@ public: virtual const TransformationReducer *vars () const { return mp_proc->vars (); } virtual bool wants_variants () const { return mp_proc->wants_variants (); } - virtual bool wants_merged () const { return true; } + virtual bool wants_merged () const { return ! mp_proc->requires_raw_input (); } virtual void do_compute_local (db::Layout *layout, const shape_interactions &interactions, std::vector > &results, size_t max_vertex_count, double area_ratio) const; virtual void do_compute_local (db::Layout *layout, const shape_interactions &interactions, std::vector > &results, size_t max_vertex_count, double area_ratio) const; diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc index 665833809..32b7988a6 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -288,11 +288,21 @@ struct DeepShapeStore::LayoutHolder // ---------------------------------------------------------------------------------- DeepShapeStoreState::DeepShapeStoreState () - : m_threads (1), m_max_area_ratio (3.0), m_max_vertex_count (16), m_text_property_name (), m_text_enlargement (-1) + : m_threads (1), m_max_area_ratio (3.0), m_max_vertex_count (16), m_reject_odd_polygons (false), m_text_property_name (), m_text_enlargement (-1) { // .. nothing yet .. } +void DeepShapeStoreState::set_reject_odd_polygons (bool f) +{ + m_reject_odd_polygons = f; +} + +bool DeepShapeStoreState::reject_odd_polygons () const +{ + return m_reject_odd_polygons; +} + void DeepShapeStoreState::set_text_enlargement (int enl) { m_text_enlargement = enl; @@ -437,7 +447,7 @@ DeepLayer DeepShapeStore::create_from_flat (const db::Region ®ion, bool for_n // The chain of operators for producing clipped and reduced polygon references db::PolygonReferenceHierarchyBuilderShapeReceiver refs (&layout (), text_enlargement (), text_property_name ()); - db::ReducingHierarchyBuilderShapeReceiver red (&refs, max_area_ratio, max_vertex_count); + db::ReducingHierarchyBuilderShapeReceiver red (&refs, max_area_ratio, max_vertex_count, m_state.reject_odd_polygons ()); // try to maintain the texts on top level - go through shape iterator std::pair ii = region.begin_iter (); @@ -631,6 +641,16 @@ double DeepShapeStore::max_area_ratio () const return m_state.max_area_ratio (); } +void DeepShapeStore::set_reject_odd_polygons (bool f) +{ + m_state.set_reject_odd_polygons (f); +} + +bool DeepShapeStore::reject_odd_polygons () const +{ + return m_state.reject_odd_polygons (); +} + void DeepShapeStore::set_max_vertex_count (size_t n) { m_state.set_max_vertex_count (n); @@ -791,7 +811,7 @@ DeepLayer DeepShapeStore::create_polygon_layer (const db::RecursiveShapeIterator // The chain of operators for producing clipped and reduced polygon references db::PolygonReferenceHierarchyBuilderShapeReceiver refs (& layout, text_enlargement (), text_property_name ()); - db::ReducingHierarchyBuilderShapeReceiver red (&refs, max_area_ratio, max_vertex_count); + db::ReducingHierarchyBuilderShapeReceiver red (&refs, max_area_ratio, max_vertex_count, m_state.reject_odd_polygons ()); db::ClippingHierarchyBuilderShapeReceiver clip (&red); // Build the working hierarchy from the recursive shape iterator diff --git a/src/db/db/dbDeepShapeStore.h b/src/db/db/dbDeepShapeStore.h index d5c559b1a..1b4f595b5 100644 --- a/src/db/db/dbDeepShapeStore.h +++ b/src/db/db/dbDeepShapeStore.h @@ -252,6 +252,9 @@ public: void set_text_enlargement (int enl); int text_enlargement () const; + void set_reject_odd_polygons (bool f); + bool reject_odd_polygons () const; + const std::set *breakout_cells (unsigned int layout_index) const; void clear_breakout_cells (unsigned int layout_index); void set_breakout_cells (unsigned int layout_index, const std::set &boc); @@ -261,6 +264,7 @@ public: private: int m_threads; double m_max_area_ratio; + bool m_reject_odd_polygons; size_t m_max_vertex_count; tl::Variant m_text_property_name; std::vector > m_breakout_cells; @@ -611,6 +615,20 @@ public: */ int threads () const; + /** + * @brief Sets a flag indicating whether to reject odd polygons + * + * Some kind of "odd" (e.g. non-orientable) polygons may spoil the functionality + * because they cannot be handled properly. By using this flag, the shape store + * we reject these kind of polygons. The default is "accept" (without warning). + */ + void set_reject_odd_polygons (bool f); + + /** + * @brief Gets a flag indicating whether to reject odd polygons + */ + bool reject_odd_polygons () const; + /** * @brief Sets the maximum vertex count default value * diff --git a/src/db/db/dbHierarchyBuilder.cc b/src/db/db/dbHierarchyBuilder.cc index 5e6801a5f..0ae678485 100644 --- a/src/db/db/dbHierarchyBuilder.cc +++ b/src/db/db/dbHierarchyBuilder.cc @@ -557,8 +557,8 @@ ClippingHierarchyBuilderShapeReceiver::insert_clipped (const db::Polygon &poly, // --------------------------------------------------------------------------------------------- -ReducingHierarchyBuilderShapeReceiver::ReducingHierarchyBuilderShapeReceiver (HierarchyBuilderShapeReceiver *pipe, double area_ratio, size_t max_vertex_count) - : mp_pipe (pipe ? pipe : &def_inserter), m_area_ratio (area_ratio), m_max_vertex_count (max_vertex_count) +ReducingHierarchyBuilderShapeReceiver::ReducingHierarchyBuilderShapeReceiver (HierarchyBuilderShapeReceiver *pipe, double area_ratio, size_t max_vertex_count, bool reject_odd_polygons) + : mp_pipe (pipe ? pipe : &def_inserter), m_area_ratio (area_ratio), m_max_vertex_count (max_vertex_count), m_reject_odd_polygons (reject_odd_polygons) { // .. nothing yet .. } @@ -590,14 +590,24 @@ ReducingHierarchyBuilderShapeReceiver::push (const db::Polygon &shape, const db: } void -ReducingHierarchyBuilderShapeReceiver::reduce (const db::Polygon &poly, const db::ICplxTrans &trans, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) +ReducingHierarchyBuilderShapeReceiver::reduce (const db::Polygon &poly, const db::ICplxTrans &trans, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target, bool check) { + if (check && m_reject_odd_polygons && is_non_orientable_polygon (poly)) { + // non-orientable polygons generate an error + if (target->cell () && target->cell ()->layout ()) { + throw tl::Exception (tl::to_string (tr ("Non-orientable polygon encountered: %s in cell %s")), poly.to_string (), target->cell ()->layout ()->cell_name (target->cell ()->cell_index ())); + } else { + throw tl::Exception (tl::to_string (tr ("Non-orientable polygon encountered: %s")), poly.to_string ()); + } + } + if ((m_max_vertex_count >= 4 && poly.vertices () > m_max_vertex_count) || (m_area_ratio > 2.0 && poly.area_ratio () > m_area_ratio)) { std::vector split_polygons; db::split_polygon (poly, split_polygons); + for (std::vector ::const_iterator sp = split_polygons.begin (); sp != split_polygons.end (); ++sp) { - reduce (*sp, trans, region, complex_region, target); + reduce (*sp, trans, region, complex_region, target, false); } } else { diff --git a/src/db/db/dbHierarchyBuilder.h b/src/db/db/dbHierarchyBuilder.h index 71a7baa14..2bb1eca0a 100644 --- a/src/db/db/dbHierarchyBuilder.h +++ b/src/db/db/dbHierarchyBuilder.h @@ -124,18 +124,19 @@ class DB_PUBLIC ReducingHierarchyBuilderShapeReceiver : public HierarchyBuilderShapeReceiver { public: - ReducingHierarchyBuilderShapeReceiver (HierarchyBuilderShapeReceiver *pipe = 0, double area_ratio = 3.0, size_t max_vertex_count = 16); + ReducingHierarchyBuilderShapeReceiver (HierarchyBuilderShapeReceiver *pipe = 0, double area_ratio = 3.0, size_t max_vertex_count = 16, bool reject_odd_polygons = false); virtual void push (const db::Shape &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); virtual void push (const db::Box &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); virtual void push (const db::Polygon &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); private: - void reduce (const db::Polygon &poly, const db::ICplxTrans &trans, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target); + void reduce (const db::Polygon &poly, const db::ICplxTrans &trans, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target, bool check = true); HierarchyBuilderShapeReceiver *mp_pipe; double m_area_ratio; size_t m_max_vertex_count; + bool m_reject_odd_polygons; }; /** diff --git a/src/db/db/dbPolygonTools.cc b/src/db/db/dbPolygonTools.cc index 14961102a..0c2312e22 100644 --- a/src/db/db/dbPolygonTools.cc +++ b/src/db/db/dbPolygonTools.cc @@ -837,6 +837,107 @@ smooth (const db::Polygon &polygon, db::Coord d) return new_poly; } +// ------------------------------------------------------------------------- +// Strange polygons + +namespace +{ + +/** + * @brief A helper class to implement the strange polygon detector + */ +struct StrangePolygonInsideFunc +{ + inline bool operator() (int wc) const + { + return wc < 0 || wc > 1; + } +}; + +/** + * @brief A helper class to implement the non-orientable polygon detector + */ +struct NonOrientablePolygonFunc +{ + inline bool operator() (int wc) const + { + // As polygon contours are normalized by default to positive wrap count a negative wrap count + // indicates non-orientability + return wc < 0; + } +}; + +/** + * @brief An exception type indicating a strange polygon + */ +struct OddPolygonException +{ + OddPolygonException () { } +}; + +/** + * @brief An edge processor catching the error + */ +class ErrorCatchingEdgeSink + : public db::EdgeSink +{ + // TODO: we should not use exceptions to indicate a condition, but right now, there is no good alternative + // and this is considered an error anyway. + virtual void put (const db::Edge &) { throw OddPolygonException (); } + virtual void crossing_edge (const db::Edge &) { throw OddPolygonException (); } +}; + +} + +template +bool +check_wrapcount (const db::Polygon &poly, std::vector *error_parts) +{ + size_t vn = poly.vertices (); + if (vn < 4 || (vn == 4 && poly.is_box ())) { + return false; + } + + EdgeProcessor ep; + ep.insert (poly); + + F inside; + db::GenericMerge op (inside); + + if (error_parts) { + + db::PolygonContainer pc (*error_parts, false); + db::PolygonGenerator pg (pc, false, false); + ep.process (pg, op); + + return ! error_parts->empty (); + + } else { + + try { + ErrorCatchingEdgeSink es; + ep.process (es, op); + } catch (OddPolygonException &) { + return true; + } + + return false; + + } +} + +bool +is_strange_polygon (const db::Polygon &poly, std::vector *strange_parts) +{ + return check_wrapcount (poly, strange_parts); +} + +bool +is_non_orientable_polygon (const db::Polygon &poly, std::vector *strange_parts) +{ + return check_wrapcount (poly, strange_parts); +} + // ------------------------------------------------------------------------- // Rounding tools diff --git a/src/db/db/dbPolygonTools.h b/src/db/db/dbPolygonTools.h index 1ae38b928..b3c439126 100644 --- a/src/db/db/dbPolygonTools.h +++ b/src/db/db/dbPolygonTools.h @@ -465,6 +465,23 @@ void DB_PUBLIC smooth_contour (db::Polygon::polygon_contour_iterator from, db::P */ db::Polygon DB_PUBLIC smooth (const db::Polygon &poly, db::Coord d); +/** + * @brief Returns a value indicating whether the polygon is an "strange polygon" + * "strange polygons" are ones which are non-orientable or have self-overlaps, e.g. their wrap + * count after orientation normalization is not 0 or 1. + * If "error_parts" is given it will receive markers indicating the parts which violate + * this wrap count condition. + */ +bool DB_PUBLIC is_strange_polygon (const db::Polygon &poly, std::vector *error_parts = 0); + +/** + * @brief Returns a value indicating whether the polygon is "non-orientable" + * Such polygons contain loops which cannot be oriented, e.g. "8"-type loops. + * If "error_parts" is given it will receive markers indicating the parts which are + * non-orientable. + */ +bool DB_PUBLIC is_non_orientable_polygon (const db::Polygon &poly, std::vector *error_parts = 0); + /** * @brief A area collector * diff --git a/src/db/db/gsiDeclDbDeepShapeStore.cc b/src/db/db/gsiDeclDbDeepShapeStore.cc index b9acf43b3..2b206be31 100644 --- a/src/db/db/gsiDeclDbDeepShapeStore.cc +++ b/src/db/db/gsiDeclDbDeepShapeStore.cc @@ -111,6 +111,19 @@ Class decl_dbDeepShapeStore ("db", "DeepShapeStore", gsi::method ("threads", &db::DeepShapeStore::threads, "@brief Gets the number of threads.\n" ) + + gsi::method ("reject_odd_polygons=", &db::DeepShapeStore::set_reject_odd_polygons, gsi::arg ("count"), + "@brief Sets a flag indicating whether to reject odd polygons\n" + "\n" + "Some kind of 'odd' (e.g. non-orientable) polygons may spoil the functionality " + "because they cannot be handled properly. By using this flag, the shape store " + "we reject these kind of polygons. The default is 'accept' (without warning).\n" + "\n" + "This attribute has been introduced in version 0.27." + ) + + gsi::method ("reject_odd_polygons", &db::DeepShapeStore::reject_odd_polygons, + "@brief Gets a flag indicating whether to reject odd polygons.\n" + "This attribute has been introduced in version 0.27." + ) + gsi::method ("max_vertex_count=", &db::DeepShapeStore::set_max_vertex_count, gsi::arg ("count"), "@brief Sets the maximum vertex count default value\n" "\n" diff --git a/src/db/unit_tests/dbPolygonToolsTests.cc b/src/db/unit_tests/dbPolygonToolsTests.cc index cbd6dad51..a0e92cc71 100644 --- a/src/db/unit_tests/dbPolygonToolsTests.cc +++ b/src/db/unit_tests/dbPolygonToolsTests.cc @@ -2372,3 +2372,94 @@ TEST(404) EXPECT_EQ (sp[1].to_string (), "(0,832;176,874;390,925)"); } } + +static db::Polygon str2poly (const std::string &s) +{ + db::Polygon poly; + tl::Extractor ex (s.c_str ()); + ex.read (poly); + return poly; +} + +// self-overlapping, non-orientable check +TEST(405) +{ + std::string ps; + std::vector parts; + + // null polygon + ps = "()"; + EXPECT_EQ (db::is_strange_polygon (str2poly (ps)), false); + EXPECT_EQ (db::is_non_orientable_polygon (str2poly (ps)), false); + + // triangle + ps = "(0,0;1000,0;1000,1000)"; + EXPECT_EQ (db::is_strange_polygon (str2poly (ps)), false); + EXPECT_EQ (db::is_non_orientable_polygon (str2poly (ps)), false); + + // rectangle counter-clockwise + ps = "(0,0;1000,0;1000,1000;0,1000)"; + EXPECT_EQ (db::is_strange_polygon (str2poly (ps)), false); + EXPECT_EQ (db::is_non_orientable_polygon (str2poly (ps)), false); + + // rectangle clockwise + ps = "(0,0;0,1000;1000,1000;1000,0)"; + EXPECT_EQ (db::is_strange_polygon (str2poly (ps)), false); + EXPECT_EQ (db::is_non_orientable_polygon (str2poly (ps)), false); + + // "8" shape + ps = "(0,0;1000,1000;0,1000;1000,0)"; + EXPECT_EQ (db::is_strange_polygon (str2poly (ps)), true); + EXPECT_EQ (db::is_non_orientable_polygon (str2poly (ps)), true); + + parts.clear (); + EXPECT_EQ (db::is_strange_polygon (str2poly (ps), &parts), true); + EXPECT_EQ (parts.size (), size_t (1)); + if (! parts.empty ()) { + EXPECT_EQ (parts[0].to_string (), "(0,0;500,500;1000,0)"); + } + + parts.clear (); + EXPECT_EQ (db::is_non_orientable_polygon (str2poly (ps), &parts), true); + EXPECT_EQ (parts.size (), size_t (1)); + if (! parts.empty ()) { + EXPECT_EQ (parts[0].to_string (), "(0,0;500,500;1000,0)"); + } + + // self-touching + ps = "(0,0;0,2000;1000,2000;1000,1000;3000,1000;3000,3000;1000,3000;1000,2000;0,2000;0,4000;4000,4000;4000,0)"; + EXPECT_EQ (db::is_strange_polygon (str2poly (ps)), false); + EXPECT_EQ (db::is_non_orientable_polygon (str2poly (ps)), false); + + // self-overlap + ps = "(0,0;0,2500;1000,2500;1000,1000;3000,1000;3000,3000;1000,3000;1000,2000;0,2000;0,4000;4000,4000;4000,0)"; + EXPECT_EQ (db::is_strange_polygon (str2poly (ps)), true); + EXPECT_EQ (db::is_non_orientable_polygon (str2poly (ps)), false); + + parts.clear (); + EXPECT_EQ (db::is_strange_polygon (str2poly (ps), &parts), true); + EXPECT_EQ (parts.size (), size_t (1)); + if (! parts.empty ()) { + EXPECT_EQ (parts[0].to_string (), "(0,2000;0,2500;1000,2500;1000,2000)"); + } + + // inner loop twisted + ps = "(0,0;0,2000;1000,2000;1000,3000;3000,3000;3000,1000;1000,1000;1000,2000;0,2000;0,4000;4000,4000;4000,0)"; + EXPECT_EQ (db::is_strange_polygon (str2poly (ps)), true); + // This is a double loop, so it's orientable + EXPECT_EQ (db::is_non_orientable_polygon (str2poly (ps)), false); + + // non-orientable hole + ps = "(0,0;0,4000;4000,4000;4000,0/1000,1000;3000,3000;1000,3000;3000,1000)"; + EXPECT_EQ (db::is_strange_polygon (str2poly (ps)), true); + + // NOTE: a non-orientable holes does not generate -1 wrapcount, but just 0. So the polygon is "orientable" + // as a whole. Which isn't good for detecting invalid input polygons, but as those are hull-only for GDS and + // OASIS and most other formats (except DXF), we don't care too much here: + EXPECT_EQ (db::is_non_orientable_polygon (str2poly (ps)), false); + + // hole outside hull + ps = "(0,0;0,4000;4000,4000;4000,0/1000,1000;5000,1000;5000,3000;1000,3000)"; + EXPECT_EQ (db::is_strange_polygon (str2poly (ps)), true); + EXPECT_EQ (db::is_non_orientable_polygon (str2poly (ps)), true); +} diff --git a/src/drc/drc/built-in-macros/_drc_engine.rb b/src/drc/drc/built-in-macros/_drc_engine.rb index 16f2ccadb..78146057d 100644 --- a/src/drc/drc/built-in-macros/_drc_engine.rb +++ b/src/drc/drc/built-in-macros/_drc_engine.rb @@ -53,10 +53,13 @@ module DRC dss = RBA::DeepShapeStore::new @max_area_ratio = dss.max_area_ratio @max_vertex_count = dss.max_vertex_count + @deep_reject_odd_polygons = dss.reject_odd_polygons dss._destroy @verbose = false + @in_context = false + end def joined @@ -680,6 +683,28 @@ module DRC self.threads(n) end + # %DRC% + # @name deep_reject_odd_polygons + # @brief Gets or sets a value indicating whether the reject odd polygons in deep mode + # @synopsis deep_reject_odd_polygons(flag) + # @synopsis deep_reject_odd_polygons + # + # In deep mode, non-orientable (e.g. "8"-shaped) polygons may not be resolved properly. + # By default the interpretation of such polygons is undefined - they may even vanish entirely. + # By setting this flag to true, the deep mode layout processor will reject such polygons with + # an error. + + def deep_reject_odd_polygons(*args) + if args.size > 0 + @deep_reject_odd_polygons = args[0] ? true : false + end + @deep_reject_odd_polygons + end + + def deep_reject_odd_polygons=(flag) + self.deep_reject_odd_polygons(flag) + end + # %DRC% # @name max_vertex_count # @brief Gets or sets the maximum vertex count for deep mode fragmentation @@ -1770,18 +1795,29 @@ CODE end def _wrapper_context(func, *args, &proc) + in_context_outer = @in_context begin + @in_context = true return yield(*args) rescue => ex raise("'" + func + "': " + ex.to_s) + ensure + @in_context = in_context_outer end end def _context(func, *args, &proc) - begin + if @in_context return yield(*args) - rescue => ex - raise("'" + func + "': " + ex.to_s) + else + begin + @in_context = true + return yield(*args) + rescue => ex + raise("'" + func + "': " + ex.to_s) + ensure + @in_context = false + end end end @@ -1879,7 +1915,7 @@ CODE end - # enable progress + # disable progress again if obj.is_a?(RBA::Region) obj.disable_progress end @@ -1934,7 +1970,7 @@ CODE end - # enable progress + # disable progress again if obj.is_a?(RBA::Region) obj.disable_progress end @@ -1977,7 +2013,7 @@ CODE end - # enable progress + # disable progress again if obj.is_a?(RBA::Region) obj.disable_progress end @@ -2322,6 +2358,7 @@ CODE # object which keeps the DSS. @dss.text_property_name = "LABEL" @dss.text_enlargement = 1 + @dss.reject_odd_polygons = @deep_reject_odd_polygons @dss.max_vertex_count = @max_vertex_count @dss.max_area_ratio = @max_area_ratio diff --git a/src/drc/drc/built-in-macros/_drc_layer.rb b/src/drc/drc/built-in-macros/_drc_layer.rb index 3ebb3f2e6..ea74b4abe 100644 --- a/src/drc/drc/built-in-macros/_drc_layer.rb +++ b/src/drc/drc/built-in-macros/_drc_layer.rb @@ -1233,11 +1233,19 @@ CODE # @synopsis layer.odd_polygons # Returns the parts of the polygons which are not orientable (i.e. "8" configuration) or self-overlapping. # Merged semantics does not apply for this method. Always the raw polygons are taken (see \raw). + # + # The odd_polygons check is not available in deep mode currently. See \deep_reject_odd_polygons for + # an alternative. def odd_polygons @engine._context("odd_polygons") do - requires_region - DRCLayer::new(@engine, @engine._tcmd(self.data, 0, RBA::Region, :strange_polygon_check)) + if is_deep? + @engine.error("'odd_polygons' is not performing any check in deep mode - use 'deep_reject_odd_polygons' instead") + return @engine.polygons + else + requires_region + return DRCLayer::new(@engine, @engine._vcmd(self.data, :strange_polygon_check)) + end end end diff --git a/src/drc/unit_tests/drcGenericTests.cc b/src/drc/unit_tests/drcGenericTests.cc index afdec0972..ceb96eb0d 100644 --- a/src/drc/unit_tests/drcGenericTests.cc +++ b/src/drc/unit_tests/drcGenericTests.cc @@ -168,3 +168,13 @@ TEST(10d) { run_test (_this, "10", true); } + +TEST(11) +{ + run_test (_this, "11", false); +} + +TEST(11d) +{ + run_test (_this, "11", true); +} diff --git a/testdata/drc/drcGenericTests_11.drc b/testdata/drc/drcGenericTests_11.drc new file mode 100644 index 000000000..89c21c24c --- /dev/null +++ b/testdata/drc/drcGenericTests_11.drc @@ -0,0 +1,40 @@ + +source $drc_test_source +target $drc_test_target + +if $drc_test_deep + deep + threads(0) # easier to debug +end + +if $drc_test_deep + + begin + deep_reject_odd_polygons(true) + l1 = input(1, 0) + raise("Test failed: input should throw and error because of odd polygons") + rescue => ex + if ex.to_s != "'input': Non-orientable polygon encountered: (1500,5000;6000,5000;1500,9500;6000,9500) in cell TOP in Region::initialize" + raise("Test failed: unexpected error message") + end + end + + # This one should work: + deep_reject_odd_polygons(false) + l1 = input(1, 0) + +else + l1 = input(1, 0) +end + +# special functions + +l1.output(1, 0) + +# classical "odd_polygons" check for reference +l1.odd_polygons.output(10, 0) + +l1.drc(smoothed(0.5)).output(100, 0) +l1.drc(odd_polygons).output(101, 0) +l1.drc(rounded_corners(1.0, 0.5, 8)).output(102, 0) + diff --git a/testdata/drc/drcGenericTests_11.gds b/testdata/drc/drcGenericTests_11.gds new file mode 100644 index 000000000..b4f292e1a Binary files /dev/null and b/testdata/drc/drcGenericTests_11.gds differ diff --git a/testdata/drc/drcGenericTests_au11.gds b/testdata/drc/drcGenericTests_au11.gds new file mode 100644 index 000000000..557e81b97 Binary files /dev/null and b/testdata/drc/drcGenericTests_au11.gds differ diff --git a/testdata/drc/drcGenericTests_au11d.gds b/testdata/drc/drcGenericTests_au11d.gds new file mode 100644 index 000000000..5907e39c1 Binary files /dev/null and b/testdata/drc/drcGenericTests_au11d.gds differ