mirror of https://github.com/KLayout/klayout.git
DRC: corners function
Plus: a new RBA binding for decompose_convex/trapezoids that delivers a region.
This commit is contained in:
parent
cf6aef46e5
commit
43359195ea
|
|
@ -610,3 +610,23 @@ run_demo gen, "input.extent_refs(:top_right).sized(0.1)", "drc_extent_refs27.png
|
||||||
run_demo gen, "input.extent_refs(0.25, 0.75).sized(0.1)", "drc_extent_refs30.png"
|
run_demo gen, "input.extent_refs(0.25, 0.75).sized(0.1)", "drc_extent_refs30.png"
|
||||||
run_demo gen, "input.extent_refs(0.25, 0.75, 0.5, 1.0)", "drc_extent_refs31.png"
|
run_demo gen, "input.extent_refs(0.25, 0.75, 0.5, 1.0)", "drc_extent_refs31.png"
|
||||||
|
|
||||||
|
class Gen
|
||||||
|
def produce(s1, s2)
|
||||||
|
pts = [
|
||||||
|
RBA::Point::new(0, 0),
|
||||||
|
RBA::Point::new(0, 8000),
|
||||||
|
RBA::Point::new(4000, 4000),
|
||||||
|
RBA::Point::new(4000, 2000),
|
||||||
|
RBA::Point::new(6000, 2000),
|
||||||
|
RBA::Point::new(6000, 0),
|
||||||
|
];
|
||||||
|
s1.insert(RBA::Polygon::new(pts))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
gen = Gen::new
|
||||||
|
|
||||||
|
run_demo gen, "input.corners.sized(0.1)", "drc_corners1.png"
|
||||||
|
run_demo gen, "input.corners(90.0).sized(0.1)", "drc_corners2.png"
|
||||||
|
run_demo gen, "input.corners(-90.0 .. -45.0).sized(0.1)", "drc_corners3.png"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,43 @@ static db::Region *new_shapes (const db::Shapes &s)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static db::Region *new_texts (const db::RecursiveShapeIterator &si_in, const std::string &pat, bool pattern)
|
struct DotDelivery
|
||||||
|
{
|
||||||
|
typedef db::Edges container_type;
|
||||||
|
|
||||||
|
DotDelivery () : container ()
|
||||||
|
{
|
||||||
|
container.reset (new container_type ());
|
||||||
|
container->set_merged_semantics (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert (const db::Point &pt)
|
||||||
|
{
|
||||||
|
container->insert (db::Edge (pt, pt));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::auto_ptr<container_type> container;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BoxDelivery
|
||||||
|
{
|
||||||
|
typedef db::Region container_type;
|
||||||
|
|
||||||
|
BoxDelivery () : container ()
|
||||||
|
{
|
||||||
|
container.reset (new container_type ());
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert (const db::Point &pt)
|
||||||
|
{
|
||||||
|
container->insert (db::Box (pt - db::Vector (1, 1), pt + db::Vector (1, 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::auto_ptr<container_type> container;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Delivery>
|
||||||
|
static typename Delivery::container_type *new_texts (const db::RecursiveShapeIterator &si_in, const std::string &pat, bool pattern)
|
||||||
{
|
{
|
||||||
db::RecursiveShapeIterator si (si_in);
|
db::RecursiveShapeIterator si (si_in);
|
||||||
si.shape_flags (db::ShapeIterator::Texts);
|
si.shape_flags (db::ShapeIterator::Texts);
|
||||||
|
|
@ -87,7 +123,7 @@ static db::Region *new_texts (const db::RecursiveShapeIterator &si_in, const std
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::auto_ptr<db::Region> r (new db::Region ());
|
Delivery delivery;
|
||||||
|
|
||||||
while (! si.at_end ()) {
|
while (! si.at_end ()) {
|
||||||
if (si.shape ().is_text () &&
|
if (si.shape ().is_text () &&
|
||||||
|
|
@ -95,58 +131,81 @@ static db::Region *new_texts (const db::RecursiveShapeIterator &si_in, const std
|
||||||
db::Text t;
|
db::Text t;
|
||||||
si.shape ().text (t);
|
si.shape ().text (t);
|
||||||
t.transform (si.trans ());
|
t.transform (si.trans ());
|
||||||
r->insert (db::Box (t.box ().enlarged (db::Vector (1, 1))));
|
delivery.insert (t.box ().center ());
|
||||||
}
|
}
|
||||||
si.next ();
|
si.next ();
|
||||||
}
|
}
|
||||||
|
|
||||||
return r.release ();
|
return delivery.container.release ();
|
||||||
}
|
}
|
||||||
|
|
||||||
static db::Edges *new_texts_dots (const db::RecursiveShapeIterator &si_in, const std::string &pat, bool pattern)
|
template <class Delivery>
|
||||||
|
static typename Delivery::container_type *texts (const db::Region *r, const std::string &pat, bool pattern)
|
||||||
{
|
{
|
||||||
db::RecursiveShapeIterator si (si_in);
|
return new_texts<Delivery> (r->iter (), pat, pattern);
|
||||||
si.shape_flags (db::ShapeIterator::Texts);
|
}
|
||||||
|
|
||||||
|
template <class Delivery>
|
||||||
|
static typename Delivery::container_type *corners (const db::Region *r, double angle_start, double angle_end)
|
||||||
|
{
|
||||||
|
db::CplxTrans t_start (1.0, angle_start, false, db::DVector ());
|
||||||
|
db::CplxTrans t_end (1.0, angle_end, false, db::DVector ());
|
||||||
|
|
||||||
|
bool big_angle = (angle_end - angle_start + db::epsilon) > 180.0;
|
||||||
|
bool all = (angle_end - angle_start - db::epsilon) > 360.0;
|
||||||
|
|
||||||
|
Delivery delivery;
|
||||||
|
|
||||||
|
for (db::Region::const_iterator p = r->begin_merged (); ! p.at_end (); ++p) {
|
||||||
|
|
||||||
|
size_t n = p->holes () + 1;
|
||||||
|
for (size_t i = 0; i < n; ++i) {
|
||||||
|
|
||||||
|
const db::Polygon::contour_type &ctr = p->contour (i);
|
||||||
|
size_t nn = ctr.size ();
|
||||||
|
if (nn > 2) {
|
||||||
|
|
||||||
|
db::Point pp = ctr [nn - 2];
|
||||||
|
db::Point pt = ctr [nn - 1];
|
||||||
|
for (size_t j = 0; j < nn; ++j) {
|
||||||
|
|
||||||
|
db::Point pn = ctr [j];
|
||||||
|
|
||||||
|
if (all) {
|
||||||
|
delivery.insert (pt);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
db::Vector vin (pt - pp);
|
||||||
|
db::DVector vout (pn - pt);
|
||||||
|
|
||||||
|
db::DVector v1 = t_start * vin;
|
||||||
|
db::DVector v2 = t_end * vin;
|
||||||
|
|
||||||
|
bool vp1 = db::vprod_sign (v1, vout) >= 0;
|
||||||
|
bool vp2 = db::vprod_sign (v2, vout) <= 0;
|
||||||
|
|
||||||
|
if (big_angle && (vp1 || vp2)) {
|
||||||
|
delivery.insert (pt);
|
||||||
|
} else if (! big_angle && vp1 && vp2) {
|
||||||
|
if (db::sprod_sign (v1, vout) > 0 && db::sprod_sign (v2, vout) > 0) {
|
||||||
|
delivery.insert (pt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pp = pt;
|
||||||
|
pt = pn;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
tl::GlobPattern glob_pat;
|
|
||||||
bool all = false;
|
|
||||||
if (pattern) {
|
|
||||||
if (pat == "*") {
|
|
||||||
all = true;
|
|
||||||
} else {
|
|
||||||
glob_pat = tl::GlobPattern (pat);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::auto_ptr<db::Edges> r (new db::Edges ());
|
return delivery.container.release ();
|
||||||
// Dots will vanish when we try to merge them ... hence disable merged semantics
|
|
||||||
r->set_merged_semantics (false);
|
|
||||||
|
|
||||||
while (! si.at_end ()) {
|
|
||||||
if (si.shape ().is_text () &&
|
|
||||||
(all || (pattern && glob_pat.match (si.shape ().text_string ())) || (!pattern && si.shape ().text_string () == pat))) {
|
|
||||||
db::Text t;
|
|
||||||
si.shape ().text (t);
|
|
||||||
t.transform (si.trans ());
|
|
||||||
db::Point c = t.box ().center ();
|
|
||||||
r->insert (db::Edge (c, c));
|
|
||||||
}
|
|
||||||
si.next ();
|
|
||||||
}
|
|
||||||
|
|
||||||
return r.release ();
|
|
||||||
}
|
|
||||||
|
|
||||||
static db::Region texts (const db::Region *r, const std::string &pat, bool pattern)
|
|
||||||
{
|
|
||||||
std::auto_ptr<db::Region> o (new_texts (r->iter (), pat, pattern));
|
|
||||||
return *o;
|
|
||||||
}
|
|
||||||
|
|
||||||
static db::Edges texts_dots (const db::Region *r, const std::string &pat, bool pattern)
|
|
||||||
{
|
|
||||||
std::auto_ptr<db::Edges> o (new_texts_dots (r->iter (), pat, pattern));
|
|
||||||
return *o;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static db::Region *new_si (const db::RecursiveShapeIterator &si)
|
static db::Region *new_si (const db::RecursiveShapeIterator &si)
|
||||||
|
|
@ -597,32 +656,34 @@ static int projection_metrics ()
|
||||||
return db::Projection;
|
return db::Projection;
|
||||||
}
|
}
|
||||||
|
|
||||||
static db::Shapes decompose_convex (const db::Region *r, int mode)
|
template <class Container>
|
||||||
|
static Container *decompose_convex (const db::Region *r, int mode)
|
||||||
{
|
{
|
||||||
db::Shapes shapes;
|
std::auto_ptr<Container> shapes (new Container ());
|
||||||
db::SimplePolygonContainer sp;
|
db::SimplePolygonContainer sp;
|
||||||
for (db::Region::const_iterator p = r->begin_merged (); ! p.at_end(); ++p) {
|
for (db::Region::const_iterator p = r->begin_merged (); ! p.at_end(); ++p) {
|
||||||
sp.polygons ().clear ();
|
sp.polygons ().clear ();
|
||||||
db::decompose_convex (*p, db::PreferredOrientation (mode), sp);
|
db::decompose_convex (*p, db::PreferredOrientation (mode), sp);
|
||||||
for (std::vector <db::SimplePolygon>::const_iterator i = sp.polygons ().begin (); i != sp.polygons ().end (); ++i) {
|
for (std::vector <db::SimplePolygon>::const_iterator i = sp.polygons ().begin (); i != sp.polygons ().end (); ++i) {
|
||||||
shapes.insert (*i);
|
shapes->insert (*i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return shapes;
|
return shapes.release ();
|
||||||
}
|
}
|
||||||
|
|
||||||
static db::Shapes decompose_trapezoids (const db::Region *r, int mode)
|
template <class Container>
|
||||||
|
static Container *decompose_trapezoids (const db::Region *r, int mode)
|
||||||
{
|
{
|
||||||
db::Shapes shapes;
|
std::auto_ptr<Container> shapes (new Container ());
|
||||||
db::SimplePolygonContainer sp;
|
db::SimplePolygonContainer sp;
|
||||||
for (db::Region::const_iterator p = r->begin_merged (); ! p.at_end(); ++p) {
|
for (db::Region::const_iterator p = r->begin_merged (); ! p.at_end(); ++p) {
|
||||||
sp.polygons ().clear ();
|
sp.polygons ().clear ();
|
||||||
db::decompose_trapezoids (*p, db::TrapezoidDecompositionMode (mode), sp);
|
db::decompose_trapezoids (*p, db::TrapezoidDecompositionMode (mode), sp);
|
||||||
for (std::vector <db::SimplePolygon>::const_iterator i = sp.polygons ().begin (); i != sp.polygons ().end (); ++i) {
|
for (std::vector <db::SimplePolygon>::const_iterator i = sp.polygons ().begin (); i != sp.polygons ().end (); ++i) {
|
||||||
shapes.insert (*i);
|
shapes->insert (*i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return shapes;
|
return shapes.release ();
|
||||||
}
|
}
|
||||||
|
|
||||||
// provided by gsiDeclDbPolygon.cc:
|
// provided by gsiDeclDbPolygon.cc:
|
||||||
|
|
@ -706,7 +767,7 @@ Class<db::Region> decl_Region ("Region",
|
||||||
"r = RBA::Region::new(layout.begin_shapes(cell, layer), RBA::ICplxTrans::new(layout.dbu / dbu))\n"
|
"r = RBA::Region::new(layout.begin_shapes(cell, layer), RBA::ICplxTrans::new(layout.dbu / dbu))\n"
|
||||||
"@/code\n"
|
"@/code\n"
|
||||||
) +
|
) +
|
||||||
constructor ("new", &new_texts, gsi::arg("shape_iterator"), gsi::arg ("expr"), gsi::arg ("as_pattern", true),
|
constructor ("new", &new_texts<BoxDelivery>, gsi::arg("shape_iterator"), gsi::arg ("expr"), gsi::arg ("as_pattern", true),
|
||||||
"@brief Constructor from a text set\n"
|
"@brief Constructor from a text set\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@param shape_iterator The iterator from which to derive the texts\n"
|
"@param shape_iterator The iterator from which to derive the texts\n"
|
||||||
|
|
@ -726,11 +787,11 @@ Class<db::Region> decl_Region ("Region",
|
||||||
"\n"
|
"\n"
|
||||||
"This method has been introduced in version 0.25."
|
"This method has been introduced in version 0.25."
|
||||||
) +
|
) +
|
||||||
method_ext ("texts", &texts, gsi::arg ("expr", std::string ("*")), gsi::arg ("as_pattern", true),
|
factory_ext ("texts", &texts<BoxDelivery>, gsi::arg ("expr", std::string ("*")), gsi::arg ("as_pattern", true),
|
||||||
"@hide\n"
|
"@hide\n"
|
||||||
"This method is provided for DRC implementation only."
|
"This method is provided for DRC implementation only."
|
||||||
) +
|
) +
|
||||||
method_ext ("texts_dots", &texts_dots, gsi::arg ("expr", std::string ("*")), gsi::arg ("as_pattern", true),
|
factory_ext ("texts_dots", &texts<DotDelivery>, gsi::arg ("expr", std::string ("*")), gsi::arg ("as_pattern", true),
|
||||||
"@hide\n"
|
"@hide\n"
|
||||||
"This method is provided for DRC implementation only."
|
"This method is provided for DRC implementation only."
|
||||||
) +
|
) +
|
||||||
|
|
@ -1042,6 +1103,26 @@ Class<db::Region> decl_Region ("Region",
|
||||||
"@hide\n"
|
"@hide\n"
|
||||||
"This method is provided for DRC implementation.\n"
|
"This method is provided for DRC implementation.\n"
|
||||||
) +
|
) +
|
||||||
|
factory_ext ("corners", &corners<BoxDelivery>, gsi::arg ("angle_start", -180.0), gsi::arg ("angle_end", 180.0),
|
||||||
|
"@brief This method will select all corners whose attached edges satisfy the angle condition.\n"
|
||||||
|
"\n"
|
||||||
|
"The angle values specify a range of angles: all corners whose attached edges form an angle "
|
||||||
|
"between angle_start and angle_end will be reported as small (2x2 DBU) boxes. The angle is measured "
|
||||||
|
"between the incoming and the outcoming edge in mathematical sense: a positive value is a turn left "
|
||||||
|
"while a negative value is a turn right. Since polygon contours are oriented clockwise, positive "
|
||||||
|
"angles will report concave corners while negative ones report convex ones.\n"
|
||||||
|
"\n"
|
||||||
|
"A similar function that reports corners as point-like edges is \\corners_dots.\n"
|
||||||
|
"\n"
|
||||||
|
"This function has been introduced in version 0.25.\n"
|
||||||
|
) +
|
||||||
|
method_ext ("corners_dots", &corners<DotDelivery>, gsi::arg ("angle_start", -180.0), gsi::arg ("angle_end", 180.0),
|
||||||
|
"@brief This method will select all corners whose attached edges satisfy the angle condition.\n"
|
||||||
|
"\n"
|
||||||
|
"This method is similar to \\corners, but delivers an \\Edges collection with dot-like edges for each corner.\n"
|
||||||
|
"\n"
|
||||||
|
"This function has been introduced in version 0.25.\n"
|
||||||
|
) +
|
||||||
method ("merge", (db::Region &(db::Region::*) ()) &db::Region::merge,
|
method ("merge", (db::Region &(db::Region::*) ()) &db::Region::merge,
|
||||||
"@brief Merge the region\n"
|
"@brief Merge the region\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
|
@ -1518,19 +1599,33 @@ Class<db::Region> decl_Region ("Region",
|
||||||
"\n"
|
"\n"
|
||||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||||
) +
|
) +
|
||||||
method_ext ("decompose_convex", &decompose_convex, gsi::arg ("preferred_orientation", po_any (), "\\Polygon#PO_any"),
|
factory_ext ("decompose_convex", &decompose_convex<db::Shapes>, gsi::arg ("preferred_orientation", po_any (), "\\Polygon#PO_any"),
|
||||||
"@brief Decomposes the region into convex pieces.\n"
|
"@brief Decomposes the region into convex pieces.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This method will return a \\Shapes container that holds a decomposition of the region into convex, simple polygons.\n"
|
"This method will return a \\Shapes container that holds a decomposition of the region into convex, simple polygons.\n"
|
||||||
"See \\Polygon#decompose_convex for details.\n"
|
"See \\Polygon#decompose_convex for details. If you want \\Region output, you should use \\decompose_convex_to_region.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This method has been introduced in version 0.25."
|
"This method has been introduced in version 0.25."
|
||||||
) +
|
) +
|
||||||
method_ext ("decompose_trapezoids", &decompose_trapezoids, gsi::arg ("mode", td_simple (), "\\Polygon#TD_simple"),
|
factory_ext ("decompose_convex_to_region", &decompose_convex<db::Region>, gsi::arg ("preferred_orientation", po_any (), "\\Polygon#PO_any"),
|
||||||
|
"@brief Decomposes the region into convex pieces into a region.\n"
|
||||||
|
"\n"
|
||||||
|
"This method is identical to \\decompose_convex, but delivers a \\Region object.\n"
|
||||||
|
"\n"
|
||||||
|
"This method has been introduced in version 0.25."
|
||||||
|
) +
|
||||||
|
factory_ext ("decompose_trapezoids", &decompose_trapezoids<db::Shapes>, gsi::arg ("mode", td_simple (), "\\Polygon#TD_simple"),
|
||||||
"@brief Decomposes the region into trapezoids.\n"
|
"@brief Decomposes the region into trapezoids.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This method will return a \\Shapes container that holds a decomposition of the region into trapezoids.\n"
|
"This method will return a \\Shapes container that holds a decomposition of the region into trapezoids.\n"
|
||||||
"See \\Polygon#decompose_trapezoids for details.\n"
|
"See \\Polygon#decompose_trapezoids for details. If you want \\Region output, you should use \\decompose_trapezoids_to_region.\n"
|
||||||
|
"\n"
|
||||||
|
"This method has been introduced in version 0.25."
|
||||||
|
) +
|
||||||
|
factory_ext ("decompose_trapezoids_to_region", &decompose_trapezoids<db::Region>, gsi::arg ("mode", td_simple (), "\\Polygon#TD_simple"),
|
||||||
|
"@brief Decomposes the region into trapezoids.\n"
|
||||||
|
"\n"
|
||||||
|
"This method is identical to \\decompose_trapezoids, but delivers a \\Region object.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This method has been introduced in version 0.25."
|
"This method has been introduced in version 0.25."
|
||||||
) +
|
) +
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
#define _HDR_gsiMethods
|
#define _HDR_gsiMethods
|
||||||
|
|
||||||
#include "tlString.h"
|
#include "tlString.h"
|
||||||
|
#include "tlUtils.h"
|
||||||
#include "tlAssert.h"
|
#include "tlAssert.h"
|
||||||
#include "gsiSerialisation.h"
|
#include "gsiSerialisation.h"
|
||||||
|
|
||||||
|
|
@ -810,6 +811,16 @@ constant (const std::string &name, R (*m) (), const std::string &doc = std::stri
|
||||||
return Methods (new ConstantGetter <R> (name, m, doc));
|
return Methods (new ConstantGetter <R> (name, m, doc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct return_by_value
|
||||||
|
{
|
||||||
|
typedef tl::False is_factory;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct return_new_object
|
||||||
|
{
|
||||||
|
typedef tl::True is_factory;
|
||||||
|
};
|
||||||
|
|
||||||
// 0 argument
|
// 0 argument
|
||||||
|
|
||||||
#define _COUNT 0
|
#define _COUNT 0
|
||||||
|
|
|
||||||
|
|
@ -220,7 +220,7 @@ private:
|
||||||
_ARGSPECMEM
|
_ARGSPECMEM
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class X, class R _COMMA _TMPLARG>
|
template <class X, class R _COMMA _TMPLARG, class F = gsi::return_by_value>
|
||||||
class _NAME(Method)
|
class _NAME(Method)
|
||||||
: public MethodSpecificBase <X>
|
: public MethodSpecificBase <X>
|
||||||
{
|
{
|
||||||
|
|
@ -240,7 +240,11 @@ public:
|
||||||
{
|
{
|
||||||
this->clear ();
|
this->clear ();
|
||||||
_ADDARGS
|
_ADDARGS
|
||||||
this->template set_return<R> ();
|
if (tl::value_from_type (typename F::is_factory ())) {
|
||||||
|
this->template set_return_new<R> ();
|
||||||
|
} else {
|
||||||
|
this->template set_return<R> ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual MethodBase *clone () const
|
virtual MethodBase *clone () const
|
||||||
|
|
@ -264,7 +268,7 @@ private:
|
||||||
_ARGSPECMEM
|
_ARGSPECMEM
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class X, class R _COMMA _TMPLARG>
|
template <class X, class R _COMMA _TMPLARG, class F = gsi::return_by_value>
|
||||||
class _NAME(ConstMethod)
|
class _NAME(ConstMethod)
|
||||||
: public MethodSpecificBase <X>
|
: public MethodSpecificBase <X>
|
||||||
{
|
{
|
||||||
|
|
@ -284,7 +288,11 @@ public:
|
||||||
{
|
{
|
||||||
this->clear ();
|
this->clear ();
|
||||||
_ADDARGS
|
_ADDARGS
|
||||||
this->template set_return<R> ();
|
if (tl::value_from_type (typename F::is_factory ())) {
|
||||||
|
this->template set_return_new<R> ();
|
||||||
|
} else {
|
||||||
|
this->template set_return<R> ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual MethodBase *clone () const
|
virtual MethodBase *clone () const
|
||||||
|
|
@ -308,7 +316,7 @@ private:
|
||||||
_ARGSPECMEM
|
_ARGSPECMEM
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class X, class R _COMMA _TMPLARG>
|
template <class X, class R _COMMA _TMPLARG, class F = gsi::return_by_value>
|
||||||
class _NAME(ExtMethod)
|
class _NAME(ExtMethod)
|
||||||
: public MethodBase
|
: public MethodBase
|
||||||
{
|
{
|
||||||
|
|
@ -328,7 +336,11 @@ public:
|
||||||
{
|
{
|
||||||
this->clear ();
|
this->clear ();
|
||||||
_ADDARGS
|
_ADDARGS
|
||||||
this->template set_return<R> ();
|
if (tl::value_from_type (typename F::is_factory ())) {
|
||||||
|
this->template set_return_new<R> ();
|
||||||
|
} else {
|
||||||
|
this->template set_return<R> ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual MethodBase *clone () const
|
virtual MethodBase *clone () const
|
||||||
|
|
@ -440,50 +452,6 @@ private:
|
||||||
_ARGSPECMEM
|
_ARGSPECMEM
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class X _COMMA _TMPLARG>
|
|
||||||
class _NAME(Factory)
|
|
||||||
: public MethodBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
_NAME(Factory) (const std::string &name, X *(*m) (_FUNCARGLIST), const std::string &doc)
|
|
||||||
: MethodBase (name, doc), m_m (m)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
_NAME(Factory) *add_args (_ARGSPEC)
|
|
||||||
{
|
|
||||||
_ARGSPECINIT;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void initialize ()
|
|
||||||
{
|
|
||||||
this->clear ();
|
|
||||||
_ADDARGS
|
|
||||||
this->template set_return_new<X *> ();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual MethodBase *clone () const
|
|
||||||
{
|
|
||||||
return new _NAME(Factory) (*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if _COUNT != 0
|
|
||||||
virtual void call (void *, SerialArgs &args, SerialArgs &ret) const
|
|
||||||
#else
|
|
||||||
virtual void call (void *, SerialArgs &, SerialArgs &ret) const
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
this->mark_called ();
|
|
||||||
_GETARGVARS;
|
|
||||||
ret.write<X *> ((*m_m) (_ARGVARLIST));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
X *(*m_m) (_FUNCARGLIST);
|
|
||||||
_ARGSPECMEM
|
|
||||||
};
|
|
||||||
|
|
||||||
// pointer iterator method descriptors
|
// pointer iterator method descriptors
|
||||||
|
|
||||||
template <class X, class R _COMMA _TMPLARG>
|
template <class X, class R _COMMA _TMPLARG>
|
||||||
|
|
@ -1400,6 +1368,22 @@ method_ext (const std::string &name, R (*xm) (X * _COMMA _FUNCARGLIST) _COMMA _A
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
template <class X, class R _COMMA _TMPLARG>
|
||||||
|
Methods
|
||||||
|
factory_ext (const std::string &name, R *(*xm) (X * _COMMA _FUNCARGLIST), const std::string &doc = std::string ())
|
||||||
|
{
|
||||||
|
return Methods (new _NAME(ExtMethod) <X, R * _COMMA _FUNCARGLIST, gsi::return_new_object> (name, xm, doc));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if _COUNT != 0
|
||||||
|
template <class X, class R _COMMA _TMPLARG _COMMA _TMPLARGSPECS>
|
||||||
|
Methods
|
||||||
|
factory_ext (const std::string &name, R *(*xm) (X * _COMMA _FUNCARGLIST) _COMMA _ARGSPECS, const std::string &doc = std::string ())
|
||||||
|
{
|
||||||
|
return Methods ((new _NAME(ExtMethod) <X, R * _COMMA _FUNCARGLIST, gsi::return_new_object> (name, xm, doc))->add_args (_ARGSPECARGS));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
template <class X _COMMA _TMPLARG>
|
template <class X _COMMA _TMPLARG>
|
||||||
Methods
|
Methods
|
||||||
constructor (const std::string &name, X *(*m) (_FUNCARGLIST), const std::string &doc = std::string ())
|
constructor (const std::string &name, X *(*m) (_FUNCARGLIST), const std::string &doc = std::string ())
|
||||||
|
|
@ -1416,22 +1400,6 @@ constructor (const std::string &name, X *(*m) (_FUNCARGLIST) _COMMA _ARGSPECS, c
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <class X _COMMA _TMPLARG>
|
|
||||||
Methods
|
|
||||||
factory (const std::string &name, X *(*m) (_FUNCARGLIST), const std::string &doc = std::string ())
|
|
||||||
{
|
|
||||||
return Methods (new _NAME(Factory) <X _COMMA _FUNCARGLIST> (name, m, doc));
|
|
||||||
}
|
|
||||||
|
|
||||||
#if _COUNT != 0
|
|
||||||
template <class X _COMMA _TMPLARG _COMMA _TMPLARGSPECS>
|
|
||||||
Methods
|
|
||||||
factory (const std::string &name, X *(*m) (_FUNCARGLIST) _COMMA _ARGSPECS, const std::string &doc = std::string ())
|
|
||||||
{
|
|
||||||
return Methods ((new _NAME(Factory) <X _COMMA _FUNCARGLIST> (name, m, doc))->add_args (_ARGSPECARGS));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template <class R _COMMA _TMPLARG>
|
template <class R _COMMA _TMPLARG>
|
||||||
Methods
|
Methods
|
||||||
method (const std::string &name, R (*m) (_FUNCARGLIST), const std::string &doc = std::string ())
|
method (const std::string &name, R (*m) (_FUNCARGLIST), const std::string &doc = std::string ())
|
||||||
|
|
@ -1480,6 +1448,22 @@ method (const std::string &name, R (X::*m) (_FUNCARGLIST) const _COMMA _ARGSPECS
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
template <class X, class R _COMMA _TMPLARG>
|
||||||
|
Methods
|
||||||
|
factory (const std::string &name, R *(X::*m) (_FUNCARGLIST) const, const std::string &doc = std::string ())
|
||||||
|
{
|
||||||
|
return Methods (new _NAME(ConstMethod) <X, R * _COMMA _FUNCARGLIST, gsi::return_new_object> (name, m, doc));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if _COUNT != 0
|
||||||
|
template <class X, class R _COMMA _TMPLARG _COMMA _TMPLARGSPECS>
|
||||||
|
Methods
|
||||||
|
factory (const std::string &name, R *(X::*m) (_FUNCARGLIST) const _COMMA _ARGSPECS, const std::string &doc = std::string ())
|
||||||
|
{
|
||||||
|
return Methods ((new _NAME(ConstMethod) <X, R * _COMMA _FUNCARGLIST, gsi::return_new_object> (name, m, doc))->add_args (_ARGSPECARGS));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
template <class X, class R _COMMA _TMPLARG>
|
template <class X, class R _COMMA _TMPLARG>
|
||||||
Methods
|
Methods
|
||||||
callback (const std::string &name, R (X::*m) (_FUNCARGLIST) const, Callback X::*cb, const std::string &doc = std::string ())
|
callback (const std::string &name, R (X::*m) (_FUNCARGLIST) const, Callback X::*cb, const std::string &doc = std::string ())
|
||||||
|
|
|
||||||
|
|
@ -887,6 +887,66 @@ CODE
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# %DRC%
|
||||||
|
# @name corners
|
||||||
|
# @brief Selects corners of polygons
|
||||||
|
# @synopsis layer.corners([ options ])
|
||||||
|
# @synopsis layer.corners(angle, [ options ])
|
||||||
|
# @synopsis layer.corners(amin .. amax, [ options ])
|
||||||
|
#
|
||||||
|
# This method produces markers on the corners of the polygons. An angle criterion can be given which
|
||||||
|
# selects corners based on the angle of the connecting edges. Positive angles indicate a left turn
|
||||||
|
# while negative angles indicate a right turn. Since polygons are oriented clockwise, postive angles
|
||||||
|
# indicate concave corners while negative ones indicate convex corners.
|
||||||
|
#
|
||||||
|
# The markers generated can be point-like edges or small 2x2 DBU boxes. The latter is the default.
|
||||||
|
#
|
||||||
|
# The options available are:
|
||||||
|
#
|
||||||
|
# @ul
|
||||||
|
# @li @b as_boxes @/b: with this option, small boxes will be produced as markers @/li
|
||||||
|
# @li @b as_dots @/b: with this option, point-like edges will be produced instead of small boxes @/li
|
||||||
|
# @/ul
|
||||||
|
#
|
||||||
|
# The following image shows the effect of this method
|
||||||
|
#
|
||||||
|
# @table
|
||||||
|
# @tr
|
||||||
|
# @td @img(/images/drc_corners1.png) @/td
|
||||||
|
# @td @img(/images/drc_corners2.png) @/td
|
||||||
|
# @td @img(/images/drc_corners3.png) @/td
|
||||||
|
# @/tr
|
||||||
|
# @/table
|
||||||
|
|
||||||
|
def corners(*args)
|
||||||
|
|
||||||
|
requires_region("corners")
|
||||||
|
|
||||||
|
as_dots = false
|
||||||
|
amin = -180.0
|
||||||
|
amax = 180.0
|
||||||
|
|
||||||
|
args.each do |a|
|
||||||
|
if a.is_a?(Range)
|
||||||
|
if (!a.min.is_a?(1.0.class) && !a.min.is_a?(1.class)) || (!a.max.is_a?(1.0.class) && !a.max.is_a?(1.class))
|
||||||
|
raise("An angle limit requires an interval of two angles")
|
||||||
|
end
|
||||||
|
amin = a.min.to_f
|
||||||
|
amax = a.max.to_f
|
||||||
|
elsif a.is_a?(1.0.class) || a.is_a?(1.class)
|
||||||
|
amin = a.to_f
|
||||||
|
amax = a.to_f
|
||||||
|
elsif a.is_a?(DRCAsDots)
|
||||||
|
as_dots = a.value
|
||||||
|
else
|
||||||
|
raise("Invalid argument for 'corners' method")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
DRCLayer::new(@engine, @engine._tcmd(@data, 0, RBA::Region, as_dots ? :corners_dots : :corners, amin, amax))
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
# %DRC%
|
# %DRC%
|
||||||
# @name middle
|
# @name middle
|
||||||
# @brief Returns the center points of the bounding boxes of the polygons
|
# @brief Returns the center points of the bounding boxes of the polygons
|
||||||
|
|
|
||||||
|
|
@ -148,6 +148,38 @@ Clean state is the default.
|
||||||
See <a href="#raw">raw</a> for some remarks about how this state is
|
See <a href="#raw">raw</a> for some remarks about how this state is
|
||||||
propagated.
|
propagated.
|
||||||
</p>
|
</p>
|
||||||
|
<h2>"corners" - Selects corners of polygons</h2>
|
||||||
|
<keyword name="corners"/>
|
||||||
|
<a name="corners"/><p>Usage:</p>
|
||||||
|
<ul>
|
||||||
|
<li><tt>layer.corners([ options ])</tt></li>
|
||||||
|
<li><tt>layer.corners(angle, [ options ])</tt></li>
|
||||||
|
<li><tt>layer.corners(amin .. amax, [ options ])</tt></li>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
This method produces markers on the corners of the polygons. An angle criterion can be given which
|
||||||
|
selects corners based on the angle of the connecting edges. Positive angles indicate a left turn
|
||||||
|
while negative angles indicate a right turn. Since polygons are oriented clockwise, postive angles
|
||||||
|
indicate concave corners while negative ones indicate convex corners.
|
||||||
|
</p><p>
|
||||||
|
The markers generated can be point-like edges or small 2x2 DBU boxes. The latter is the default.
|
||||||
|
</p><p>
|
||||||
|
The options available are:
|
||||||
|
</p><p>
|
||||||
|
<ul>
|
||||||
|
<li><b>as_boxes </b>: with this option, small boxes will be produced as markers </li>
|
||||||
|
<li><b>as_dots </b>: with this option, point-like edges will be produced instead of small boxes </li>
|
||||||
|
</ul>
|
||||||
|
</p><p>
|
||||||
|
The following image shows the effect of this method
|
||||||
|
</p><p>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td><img src="/images/drc_corners1.png"/></td>
|
||||||
|
<td><img src="/images/drc_corners2.png"/></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</p>
|
||||||
<h2>"data" - Gets the low-level data object</h2>
|
<h2>"data" - Gets the low-level data object</h2>
|
||||||
<keyword name="data"/>
|
<keyword name="data"/>
|
||||||
<a name="data"/><p>Usage:</p>
|
<a name="data"/><p>Usage:</p>
|
||||||
|
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 5.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.9 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 5.1 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.5 KiB |
|
|
@ -92,6 +92,9 @@
|
||||||
<file alias="drc_extent_refs27.png">doc/images/drc_extent_refs27.png</file>
|
<file alias="drc_extent_refs27.png">doc/images/drc_extent_refs27.png</file>
|
||||||
<file alias="drc_extent_refs30.png">doc/images/drc_extent_refs30.png</file>
|
<file alias="drc_extent_refs30.png">doc/images/drc_extent_refs30.png</file>
|
||||||
<file alias="drc_extent_refs31.png">doc/images/drc_extent_refs31.png</file>
|
<file alias="drc_extent_refs31.png">doc/images/drc_extent_refs31.png</file>
|
||||||
|
<file alias="drc_corners1.png">doc/images/drc_corners1.png</file>
|
||||||
|
<file alias="drc_corners2.png">doc/images/drc_corners2.png</file>
|
||||||
|
<file alias="drc_corners3.png">doc/images/drc_corners3.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
<qresource prefix="/help/about">
|
<qresource prefix="/help/about">
|
||||||
<file alias="rba_notation.xml">doc/about/rba_notation.xml</file>
|
<file alias="rba_notation.xml">doc/about/rba_notation.xml</file>
|
||||||
|
|
|
||||||
|
|
@ -542,6 +542,10 @@ a1.extent_refs(:right_center).sized(0.05).output(1052, 0)
|
||||||
a1.extent_refs(:rc).sized(0.05).output(1052, 1)
|
a1.extent_refs(:rc).sized(0.05).output(1052, 1)
|
||||||
a1.extent_refs(0.25, 0.5, 0.5, 0.75).output(1053, 0)
|
a1.extent_refs(0.25, 0.5, 0.5, 0.75).output(1053, 0)
|
||||||
|
|
||||||
|
a1.corners.sized(0.05).output(1060, 0)
|
||||||
|
a1.corners(-90.0, as_boxes).sized(0.05).output(1061, 0)
|
||||||
|
a1.corners(-90.0, as_dots).extended(0.05, 0.05, 0.05, 0.05).output(1062, 0)
|
||||||
|
|
||||||
puts "=== Single-cell testsuite ==="
|
puts "=== Single-cell testsuite ==="
|
||||||
|
|
||||||
run_testsuite(0, 1)
|
run_testsuite(0, 1)
|
||||||
|
|
|
||||||
|
|
@ -683,12 +683,30 @@ class DBRegion_TestClass < TestBase
|
||||||
r.insert(p)
|
r.insert(p)
|
||||||
|
|
||||||
assert_equal(RBA::Region::new(r.decompose_convex).to_s, "(0,10;0,30;10,30;10,10);(10,30;10,40;40,40;40,30);(0,30;0,50;10,50;10,30);(30,0;30,30;40,30;40,0);(0,0;0,10;30,10;30,0)")
|
assert_equal(RBA::Region::new(r.decompose_convex).to_s, "(0,10;0,30;10,30;10,10);(10,30;10,40;40,40;40,30);(0,30;0,50;10,50;10,30);(30,0;30,30;40,30;40,0);(0,0;0,10;30,10;30,0)")
|
||||||
|
assert_equal(r.decompose_convex_to_region.to_s, "(0,10;0,30;10,30;10,10);(10,30;10,40;40,40;40,30);(0,30;0,50;10,50;10,30);(30,0;30,30;40,30;40,0);(0,0;0,10;30,10;30,0)")
|
||||||
assert_equal(RBA::Region::new(r.decompose_convex(RBA::Polygon::PO_horizontal)).to_s, "(0,10;0,30;10,30;10,10);(0,30;0,40;40,40;40,30);(0,40;0,50;10,50;10,40);(30,10;30,30;40,30;40,10);(0,0;0,10;40,10;40,0)")
|
assert_equal(RBA::Region::new(r.decompose_convex(RBA::Polygon::PO_horizontal)).to_s, "(0,10;0,30;10,30;10,10);(0,30;0,40;40,40;40,30);(0,40;0,50;10,50;10,40);(30,10;30,30;40,30;40,10);(0,0;0,10;40,10;40,0)")
|
||||||
assert_equal(RBA::Region::new(r.decompose_trapezoids).to_s, "(0,0;0,10;40,10;40,0);(0,10;0,30;10,30;10,10);(30,10;30,30;40,30;40,10);(0,30;0,40;40,40;40,30);(0,40;0,50;10,50;10,40)")
|
assert_equal(RBA::Region::new(r.decompose_trapezoids).to_s, "(0,0;0,10;40,10;40,0);(0,10;0,30;10,30;10,10);(30,10;30,30;40,30;40,10);(0,30;0,40;40,40;40,30);(0,40;0,50;10,50;10,40)")
|
||||||
|
assert_equal(r.decompose_trapezoids_to_region.to_s, "(0,0;0,10;40,10;40,0);(0,10;0,30;10,30;10,10);(30,10;30,30;40,30;40,10);(0,30;0,40;40,40;40,30);(0,40;0,50;10,50;10,40)")
|
||||||
assert_equal(RBA::Region::new(r.decompose_trapezoids(RBA::Polygon::TD_htrapezoids)).to_s, "(0,10;0,30;10,30;10,10);(10,30;10,40;40,40;40,30);(0,30;0,50;10,50;10,30);(30,0;30,30;40,30;40,0);(0,0;0,10;30,10;30,0)")
|
assert_equal(RBA::Region::new(r.decompose_trapezoids(RBA::Polygon::TD_htrapezoids)).to_s, "(0,10;0,30;10,30;10,10);(10,30;10,40;40,40;40,30);(0,30;0,50;10,50;10,30);(30,0;30,30;40,30;40,0);(0,0;0,10;30,10;30,0)")
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# corners functions
|
||||||
|
def test_14
|
||||||
|
|
||||||
|
r = RBA::Region::new
|
||||||
|
p = RBA::Polygon::from_s("(0,0;0,80;40,40;40,0/10,10;30,10;30,30;10,30)")
|
||||||
|
r.insert(p)
|
||||||
|
|
||||||
|
assert_equal(r.corners.to_s, "(39,-1;39,1;41,1;41,-1);(-1,-1;-1,1;1,1;1,-1);(-1,79;-1,81;1,81;1,79);(39,39;39,41;41,41;41,39);(9,29;9,31;11,31;11,29);(9,9;9,11;11,11;11,9);(29,9;29,11;31,11;31,9);(29,29;29,31;31,31;31,29)")
|
||||||
|
assert_equal(r.corners(-90.0, 90.0).to_s, "(39,-1;39,1;41,1;41,-1);(-1,-1;-1,1;1,1;1,-1);(39,39;39,41;41,41;41,39);(9,29;9,31;11,31;11,29);(9,9;9,11;11,11;11,9);(29,9;29,11;31,11;31,9);(29,29;29,31;31,31;31,29)")
|
||||||
|
assert_equal(r.corners(-90.0, -90.0).to_s, "(39,-1;39,1;41,1;41,-1);(-1,-1;-1,1;1,1;1,-1)")
|
||||||
|
assert_equal(r.corners(-45.0, -45.0).to_s, "(39,39;39,41;41,41;41,39)")
|
||||||
|
assert_equal(r.corners(-90.0, -45.0).to_s, "(39,-1;39,1;41,1;41,-1);(-1,-1;-1,1;1,1;1,-1);(39,39;39,41;41,41;41,39)")
|
||||||
|
assert_equal(r.corners(90.0, 90.0).to_s, "(9,29;9,31;11,31;11,29);(9,9;9,11;11,11;11,9);(29,9;29,11;31,11;31,9);(29,29;29,31;31,31;31,29)")
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
load("test_epilogue.rb")
|
load("test_epilogue.rb")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue