mirror of https://github.com/KLayout/klayout.git
WIP: more tests, bug fixes, new feature: deep_reject_odd_polygons, odd_polygons check disabled in deep mode
This commit is contained in:
parent
e21f14b79d
commit
158ea196ec
|
|
@ -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<db::Polygon, db::Polygon> &interactions, std::vector<std::unordered_set<db::Polygon> > &results, size_t max_vertex_count, double area_ratio) const;
|
||||
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::PolygonRef, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::PolygonRef> > &results, size_t max_vertex_count, double area_ratio) const;
|
||||
|
|
|
|||
|
|
@ -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<db::RecursiveShapeIterator, db::ICplxTrans> 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
|
||||
|
|
|
|||
|
|
@ -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<db::cell_index_type> *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<db::cell_index_type> &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<std::set<db::cell_index_type> > 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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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 <db::Polygon> split_polygons;
|
||||
db::split_polygon (poly, split_polygons);
|
||||
|
||||
for (std::vector <db::Polygon>::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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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 <class F>
|
||||
bool
|
||||
check_wrapcount (const db::Polygon &poly, std::vector<db::Polygon> *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<F> 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<db::Polygon> *strange_parts)
|
||||
{
|
||||
return check_wrapcount<StrangePolygonInsideFunc> (poly, strange_parts);
|
||||
}
|
||||
|
||||
bool
|
||||
is_non_orientable_polygon (const db::Polygon &poly, std::vector<db::Polygon> *strange_parts)
|
||||
{
|
||||
return check_wrapcount<NonOrientablePolygonFunc> (poly, strange_parts);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Rounding tools
|
||||
|
||||
|
|
|
|||
|
|
@ -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<db::Polygon> *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<db::Polygon> *error_parts = 0);
|
||||
|
||||
/**
|
||||
* @brief A area collector
|
||||
*
|
||||
|
|
|
|||
|
|
@ -111,6 +111,19 @@ Class<db::DeepShapeStore> 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"
|
||||
|
|
|
|||
|
|
@ -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<db::Polygon> 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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue