Implemented #2 ([Simple]Polygon#extract_rad feature for Ruby/Python)

This commit is contained in:
Matthias Koefferlein 2017-02-25 00:43:05 +01:00
parent 85f048dd6d
commit ae986d3234
4 changed files with 321 additions and 104 deletions

View File

@ -778,21 +778,22 @@ smooth (const db::Polygon &polygon, db::Coord d)
// -------------------------------------------------------------------------
// Rounding tools
bool
extract_rad_from_contour (db::Polygon::polygon_contour_iterator from, db::Polygon::polygon_contour_iterator to, double &rinner, double &router, unsigned int &n, std::vector <db::Point> *new_pts, bool fallback)
template <class C>
static bool
do_extract_rad_from_contour (typename db::polygon<C>::polygon_contour_iterator from, typename db::polygon<C>::polygon_contour_iterator to, double &rinner, double &router, unsigned int &n, std::vector <db::point<C> > *new_pts, bool fallback)
{
if (from == to) {
return false;
}
db::Polygon::polygon_contour_iterator p0 = from;
typename db::polygon<C>::polygon_contour_iterator p0 = from;
db::Polygon::polygon_contour_iterator p1 = p0;
typename db::polygon<C>::polygon_contour_iterator p1 = p0;
++p1;
if (p1 == to) {
p1 = from;
}
db::Polygon::polygon_contour_iterator p2 = p1;
typename db::polygon<C>::polygon_contour_iterator p2 = p1;
const double cos_thr = 0.8;
const double circle_segment_thr = 2.5;
@ -810,8 +811,8 @@ extract_rad_from_contour (db::Polygon::polygon_contour_iterator from, db::Polygo
p2 = from;
}
db::Edge ep (*p0, *p1);
db::Edge e (*p1, *p2);
db::edge<C> ep (*p0, *p1);
db::edge<C> e (*p1, *p2);
bool inner = (db::vprod_sign (ep, e) > 0);
double &ls = inner ? ls_inner : ls_outer;
@ -841,7 +842,7 @@ extract_rad_from_contour (db::Polygon::polygon_contour_iterator from, db::Polygo
// search for the first circle segment (where cos(a) > cos_thr)
// or a long segment is followed by a short one or the curvature changes.
db::Polygon::polygon_contour_iterator pm1 = from;
typename db::polygon<C>::polygon_contour_iterator pm1 = from;
p0 = pm1;
++p0;
@ -861,7 +862,7 @@ extract_rad_from_contour (db::Polygon::polygon_contour_iterator from, db::Polygo
p2 = from;
}
db::Polygon::polygon_contour_iterator p3 = p2;
typename db::polygon<C>::polygon_contour_iterator p3 = p2;
do {
@ -870,10 +871,10 @@ extract_rad_from_contour (db::Polygon::polygon_contour_iterator from, db::Polygo
p3 = from;
}
db::Edge em (*pm1, *p0);
db::Edge ep (*p0, *p1);
db::Edge e (*p1, *p2);
db::Edge en (*p2, *p3);
db::edge<C> em (*pm1, *p0);
db::edge<C> ep (*p0, *p1);
db::edge<C> e (*p1, *p2);
db::edge<C> en (*p2, *p3);
bool first_or_last = fallback || (e.double_length () > circle_segment_thr * ep.double_length () || ep.double_length () > circle_segment_thr * e.double_length ())
|| (db::vprod_sign (em, ep) * db::vprod_sign (ep, e) < 0 || db::vprod_sign (ep, e) * db::vprod_sign (e, en) < 0);
@ -907,11 +908,11 @@ extract_rad_from_contour (db::Polygon::polygon_contour_iterator from, db::Polygo
new_pts->clear ();
}
db::Polygon::polygon_contour_iterator pfirst = p0;
typename db::polygon<C>::polygon_contour_iterator pfirst = p0;
bool in_corner = false;
double ls_corner = 0.0;
db::Edge elast;
db::Polygon::polygon_contour_iterator plast;
db::edge<C> elast;
typename db::polygon<C>::polygon_contour_iterator plast;
double asum = 0.0;
unsigned int nseg = 0;
@ -931,10 +932,10 @@ extract_rad_from_contour (db::Polygon::polygon_contour_iterator from, db::Polygo
p3 = from;
}
db::Edge em (*pm1, *p0);
db::Edge ep (*p0, *p1);
db::Edge e (*p1, *p2);
db::Edge en (*p2, *p3);
db::edge<C> em (*pm1, *p0);
db::edge<C> ep (*p0, *p1);
db::edge<C> e (*p1, *p2);
db::edge<C> en (*p2, *p3);
// Heuristic detection of a new circle segment:
// In fallback mode vertical or horizontal edges separate circle segments.
@ -956,7 +957,7 @@ extract_rad_from_contour (db::Polygon::polygon_contour_iterator from, db::Polygo
if (! in_corner) {
elast = ep;
plast = p1;
asum = db::vprod (*p1 - db::Point (), *p2 - db::Point ());
asum = db::vprod (*p1 - db::point<C> (), *p2 - db::point<C> ());
nseg = 1;
ls_corner = ls;
}
@ -967,13 +968,13 @@ extract_rad_from_contour (db::Polygon::polygon_contour_iterator from, db::Polygo
if (in_corner) {
std::pair<bool, db::Point> cp = elast.cut_point (e);
std::pair<bool, db::point<C> > cp = elast.cut_point (e);
if (! cp.first) {
// We have a full 180 degree bend without a stop (actually two corners).
// Use the segment in between that is perpendicular to the start and end segment as stop edge.
db::Polygon::polygon_contour_iterator pp1 = plast;
db::Polygon::polygon_contour_iterator pp2 = pp1;
typename db::polygon<C>::polygon_contour_iterator pp1 = plast;
typename db::polygon<C>::polygon_contour_iterator pp2 = pp1;
double asum_part = 0.0;
unsigned int nseg_part = 0;
@ -984,12 +985,12 @@ extract_rad_from_contour (db::Polygon::polygon_contour_iterator from, db::Polygo
pp2 = from;
}
e = db::Edge (*pp1, *pp2);
e = db::edge<C> (*pp1, *pp2);
if (db::sprod_sign (elast, e) == 0) {
break;
}
asum_part += db::vprod (*pp1 - db::Point (), *pp2 - db::Point ());
asum_part += db::vprod (*pp1 - db::point<C> (), *pp2 - db::point<C> ());
++nseg_part;
pp1 = pp2;
@ -1008,11 +1009,11 @@ extract_rad_from_contour (db::Polygon::polygon_contour_iterator from, db::Polygo
++nseg_part;
asum -= asum_part;
asum -= db::vprod (e.p1 () - db::Point (), e.p2 () - db::Point ());
asum -= db::vprod (e.p1 () - db::point<C> (), e.p2 () - db::point<C> ());
nseg -= nseg_part;
asum_part += db::vprod (cp.second - db::Point (), elast.p2 () - db::Point ());
asum_part += db::vprod (*pp1 - db::Point (), cp.second - db::Point ());
asum_part += db::vprod (cp.second - db::point<C> (), elast.p2 () - db::point<C> ());
asum_part += db::vprod (*pp1 - db::point<C> (), cp.second - db::point<C> ());
double sin_atot = db::vprod (elast, e);
double cos_atot = db::sprod (elast, e);
@ -1034,7 +1035,7 @@ extract_rad_from_contour (db::Polygon::polygon_contour_iterator from, db::Polygo
elast = e;
e = db::Edge (*p1, *p2);
e = db::edge<C> (*p1, *p2);
cp = elast.cut_point (e);
if (! cp.first) {
return false;
@ -1046,8 +1047,8 @@ extract_rad_from_contour (db::Polygon::polygon_contour_iterator from, db::Polygo
new_pts->push_back (cp.second);
}
asum += db::vprod (cp.second - db::Point (), elast.p2 () - db::Point ());
asum += db::vprod (*p1 - db::Point (), cp.second - db::Point ());
asum += db::vprod (cp.second - db::point<C> (), elast.p2 () - db::point<C> ());
asum += db::vprod (*p1 - db::point<C> (), cp.second - db::point<C> ());
++nseg;
@ -1074,7 +1075,7 @@ extract_rad_from_contour (db::Polygon::polygon_contour_iterator from, db::Polygo
} else if (in_corner) {
asum += db::vprod (*p1 - db::Point (), *p2 - db::Point ());
asum += db::vprod (*p1 - db::point<C> (), *p2 - db::point<C> ());
++nseg;
} else {
@ -1112,45 +1113,58 @@ extract_rad_from_contour (db::Polygon::polygon_contour_iterator from, db::Polygo
}
}
bool
extract_rad (const db::Polygon &polygon, double &rinner, double &router, unsigned int &n, db::Polygon *new_polygon)
bool
extract_rad_from_contour (typename db::Polygon::polygon_contour_iterator from, typename db::Polygon::polygon_contour_iterator to, double &rinner, double &router, unsigned int &n, std::vector <db::Point> *new_pts, bool fallback)
{
return do_extract_rad_from_contour (from, to, rinner, router, n, new_pts, fallback);
}
bool
extract_rad_from_contour (typename db::DPolygon::polygon_contour_iterator from, typename db::DPolygon::polygon_contour_iterator to, double &rinner, double &router, unsigned int &n, std::vector <db::DPoint> *new_pts, bool fallback)
{
return do_extract_rad_from_contour (from, to, rinner, router, n, new_pts, fallback);
}
template <class C>
static bool
do_extract_rad (const db::polygon<C> &polygon, double &rinner, double &router, unsigned int &n, db::polygon<C> *new_polygon)
{
if (new_polygon) {
std::vector <db::Point> new_pts;
std::vector <db::point<C> > new_pts;
if (! extract_rad_from_contour (polygon.begin_hull (), polygon.end_hull (), rinner, router, n, &new_pts) &&
! extract_rad_from_contour (polygon.begin_hull (), polygon.end_hull (), rinner, router, n, &new_pts, true)) {
if (! do_extract_rad_from_contour (polygon.begin_hull (), polygon.end_hull (), rinner, router, n, &new_pts, false) &&
! do_extract_rad_from_contour (polygon.begin_hull (), polygon.end_hull (), rinner, router, n, &new_pts, true)) {
// no radius found
return false;
} else {
new_polygon->assign_hull (new_pts.begin (), new_pts.end (), true /*compress*/);
new_polygon->assign_hull (new_pts.begin (), new_pts.end ());
}
for (unsigned int h = 0; h < polygon.holes (); ++h) {
new_pts.clear ();
if (! extract_rad_from_contour (polygon.begin_hole (h), polygon.end_hole (h), rinner, router, n, &new_pts) &&
! extract_rad_from_contour (polygon.begin_hole (h), polygon.end_hole (h), rinner, router, n, &new_pts, true)) {
if (! do_extract_rad_from_contour (polygon.begin_hole (h), polygon.end_hole (h), rinner, router, n, &new_pts, false) &&
! do_extract_rad_from_contour (polygon.begin_hole (h), polygon.end_hole (h), rinner, router, n, &new_pts, true)) {
// no radius found
return false;
} else {
new_polygon->insert_hole (new_pts.begin (), new_pts.end (), true /*compress*/);
new_polygon->insert_hole (new_pts.begin (), new_pts.end ());
}
}
} else {
if (! extract_rad_from_contour (polygon.begin_hull (), polygon.end_hull (), rinner, router, n, 0)) {
if (! extract_rad_from_contour (polygon.begin_hull (), polygon.end_hull (), rinner, router, n, 0, true)) {
if (! do_extract_rad_from_contour (polygon.begin_hull (), polygon.end_hull (), rinner, router, n, (std::vector<db::point<C> > *) 0, false)) {
if (! do_extract_rad_from_contour (polygon.begin_hull (), polygon.end_hull (), rinner, router, n, (std::vector<db::point<C> > *) 0, true)) {
return false;
}
}
for (unsigned int h = 0; h < polygon.holes (); ++h) {
if (! extract_rad_from_contour (polygon.begin_hole (h), polygon.end_hole (h), rinner, router, n, 0)) {
if (! extract_rad_from_contour (polygon.begin_hole (h), polygon.end_hole (h), rinner, router, n, 0, true)) {
if (! do_extract_rad_from_contour (polygon.begin_hole (h), polygon.end_hole (h), rinner, router, n, (std::vector<db::point<C> > *) 0, false)) {
if (! do_extract_rad_from_contour (polygon.begin_hole (h), polygon.end_hole (h), rinner, router, n, (std::vector<db::point<C> > *) 0, true)) {
return false;
}
}
@ -1162,22 +1176,36 @@ extract_rad (const db::Polygon &polygon, double &rinner, double &router, unsigne
}
void
compute_rounded_contour (db::Polygon::polygon_contour_iterator from, db::Polygon::polygon_contour_iterator to, std::vector <db::Point> &new_pts, double rinner, double router, unsigned int n)
bool
extract_rad (const db::Polygon &polygon, double &rinner, double &router, unsigned int &n, db::Polygon *new_polygon)
{
std::vector<db::Point> points;
return do_extract_rad (polygon, rinner, router, n, new_polygon);
}
bool
extract_rad (const db::DPolygon &polygon, double &rinner, double &router, unsigned int &n, db::DPolygon *new_polygon)
{
return do_extract_rad (polygon, rinner, router, n, new_polygon);
}
template <class C>
static void
do_compute_rounded_contour (typename db::polygon<C>::polygon_contour_iterator from, typename db::polygon<C>::polygon_contour_iterator to, std::vector <db::point<C> > &new_pts, double rinner, double router, unsigned int n)
{
std::vector<db::point<C> > points;
// collect the points into a vector
if (from != to) {
db::Polygon::polygon_contour_iterator p0 = from;
db::Polygon::polygon_contour_iterator p1 = p0;
typename db::polygon<C>::polygon_contour_iterator p0 = from;
typename db::polygon<C>::polygon_contour_iterator p1 = p0;
++p1;
if (p1 == to) {
p1 = from;
}
db::Polygon::polygon_contour_iterator p2 = p1;
typename db::polygon<C>::polygon_contour_iterator p2 = p1;
do {
@ -1186,7 +1214,7 @@ compute_rounded_contour (db::Polygon::polygon_contour_iterator from, db::Polygon
p2 = from;
}
if (! db::Edge (*p0, *p1).parallel (db::Edge (*p1, *p2))) {
if (! db::edge<C> (*p0, *p1).parallel (db::edge<C> (*p1, *p2))) {
points.push_back (*p1);
}
@ -1204,9 +1232,9 @@ compute_rounded_contour (db::Polygon::polygon_contour_iterator from, db::Polygon
for (size_t i = 0; i < points.size (); ++i) {
db::Point p0 = points [(i + points.size () - 1) % points.size ()];
db::Point p1 = points [i];
db::Point p2 = points [(i + points.size () + 1) % points.size ()];
db::point<C> p0 = points [(i + points.size () - 1) % points.size ()];
db::point<C> p1 = points [i];
db::point<C> p2 = points [(i + points.size () + 1) % points.size ()];
db::DVector e1 = (db::DPoint (p1) - db::DPoint (p0)) * (1.0 / p0.double_distance (p1));
db::DVector e2 = (db::DPoint (p2) - db::DPoint (p1)) * (1.0 / p1.double_distance (p2));
@ -1227,9 +1255,9 @@ compute_rounded_contour (db::Polygon::polygon_contour_iterator from, db::Polygon
for (size_t i = 0; i < points.size (); ++i) {
db::Point p0 = points [(i + points.size () - 1) % points.size ()];
db::Point p1 = points [i];
db::Point p2 = points [(i + points.size () + 1) % points.size ()];
db::point<C> p0 = points [(i + points.size () - 1) % points.size ()];
db::point<C> p1 = points [i];
db::point<C> p2 = points [(i + points.size () + 1) % points.size ()];
db::DVector e1 = (db::DPoint (p1) - db::DPoint (p0)) * (1.0 / p0.double_distance (p1));
db::DVector e2 = (db::DPoint (p2) - db::DPoint (p1)) * (1.0 / p1.double_distance (p2));
@ -1274,7 +1302,7 @@ compute_rounded_contour (db::Polygon::polygon_contour_iterator from, db::Polygon
db::DPoint qm = q0 + (q1 - q0) * 0.5;
db::DPoint q = qm + (qm - pr) * (q0.sq_distance (qm) / pr.sq_distance (qm));
new_pts.push_back (db::Point (q));
new_pts.push_back (db::point<C> (q));
q0 = q1;
@ -1289,11 +1317,24 @@ compute_rounded_contour (db::Polygon::polygon_contour_iterator from, db::Polygon
}
}
db::Polygon
compute_rounded (const db::Polygon &polygon, double rinner, double router, unsigned int n)
void
compute_rounded_contour (db::Polygon::polygon_contour_iterator from, db::Polygon::polygon_contour_iterator to, std::vector <db::Point> &new_pts, double rinner, double router, unsigned int n)
{
db::Polygon new_poly;
std::vector <db::Point> new_pts;
do_compute_rounded_contour (from, to, new_pts, rinner, router, n);
}
void
compute_rounded_contour (db::DPolygon::polygon_contour_iterator from, db::DPolygon::polygon_contour_iterator to, std::vector <db::DPoint> &new_pts, double rinner, double router, unsigned int n)
{
do_compute_rounded_contour (from, to, new_pts, rinner, router, n);
}
template <class C>
static db::polygon<C>
do_compute_rounded (const db::polygon<C> &polygon, double rinner, double router, unsigned int n)
{
db::polygon<C> new_poly;
std::vector <db::point<C> > new_pts;
compute_rounded_contour (polygon.begin_hull (), polygon.end_hull (), new_pts, rinner, router, n);
new_poly.assign_hull (new_pts.begin (), new_pts.end (), false /*don't compress*/);
@ -1307,6 +1348,18 @@ compute_rounded (const db::Polygon &polygon, double rinner, double router, unsig
return new_poly;
}
db::Polygon
compute_rounded (const db::Polygon &polygon, double rinner, double router, unsigned int n)
{
return do_compute_rounded (polygon, rinner, router, n);
}
db::DPolygon
compute_rounded (const db::DPolygon &polygon, double rinner, double router, unsigned int n)
{
return do_compute_rounded (polygon, rinner, router, n);
}
// -------------------------------------------------------------------------
// Implementation of AreaMap

View File

@ -359,6 +359,11 @@ inline bool interact (const db::DSimplePolygon &poly1, const db::DSimplePolygon
*/
bool DB_PUBLIC extract_rad_from_contour (db::Polygon::polygon_contour_iterator from, db::Polygon::polygon_contour_iterator to, double &rinner, double &router, unsigned int &n, std::vector <db::Point> *new_pts = 0, bool fallback = false);
/**
* @brief Extract a corner radius from a contour (version for double coordinates)
*/
bool DB_PUBLIC extract_rad_from_contour (db::DPolygon::polygon_contour_iterator from, db::DPolygon::polygon_contour_iterator to, double &rinner, double &router, unsigned int &n, std::vector <db::DPoint> *new_pts = 0, bool fallback = false);
/**
* @brief Extract the radius (better: radii) from a polygon and if requested, compute the new polygon without the rounding
*
@ -366,6 +371,11 @@ bool DB_PUBLIC extract_rad_from_contour (db::Polygon::polygon_contour_iterator f
*/
bool DB_PUBLIC extract_rad (const db::Polygon &polygon, double &rinner, double &router, unsigned int &n, db::Polygon *new_polygon = 0);
/**
* @brief Extract a corner radius from a polygon (version for double coordinates)
*/
bool DB_PUBLIC extract_rad (const db::DPolygon &polygon, double &rinner, double &router, unsigned int &n, db::DPolygon *new_polygon = 0);
/**
* @brief Compute the rounded version of a polygon contour
*
@ -379,6 +389,11 @@ bool DB_PUBLIC extract_rad (const db::Polygon &polygon, double &rinner, double &
*/
void DB_PUBLIC compute_rounded_contour (db::Polygon::polygon_contour_iterator from, db::Polygon::polygon_contour_iterator to, std::vector <db::Point> &new_pts, double rinner, double router, unsigned int n);
/**
* @brief Compute the rounded version of a polygon contour (double coordinate version)
*/
void DB_PUBLIC compute_rounded_contour (db::DPolygon::polygon_contour_iterator from, db::DPolygon::polygon_contour_iterator to, std::vector <db::DPoint> &new_pts, double rinner, double router, unsigned int n);
/**
* @brief Compute the rounded version of the polygon
*
@ -386,6 +401,11 @@ void DB_PUBLIC compute_rounded_contour (db::Polygon::polygon_contour_iterator fr
*/
db::Polygon DB_PUBLIC compute_rounded (const db::Polygon &poly, double rinner, double router, unsigned int n);
/**
* @brief Compute the rounded version of the polygon (double coordinate version)
*/
db::DPolygon DB_PUBLIC compute_rounded (const db::DPolygon &poly, double rinner, double router, unsigned int n);
/**
* @brief Smooth a contour
*

View File

@ -173,6 +173,37 @@ struct simple_polygon_defs
return poly->area ();
}
static std::vector<tl::Variant> extract_rad (const C *sp)
{
db::polygon<coord_type> p, pnew;
p.assign_hull (sp->begin_hull (), sp->end_hull (), false);
double rinner = 0.0, router = 0.0;
unsigned int n = 1;
if (! db::extract_rad (p, rinner, router, n, &pnew) || pnew.holes () > 0) {
return std::vector<tl::Variant> ();
} else {
std::vector<tl::Variant> res;
C spnew;
spnew.assign_hull (pnew.begin_hull (), pnew.end_hull ());
res.push_back (tl::Variant (spnew));
res.push_back (rinner);
res.push_back (router);
res.push_back (n);
return res;
}
}
static C round_corners (const C *sp, double rinner, double router, unsigned int n)
{
db::polygon<coord_type> p;
p.assign_hull (sp->begin_hull (), sp->end_hull (), false);
p = db::compute_rounded (p, rinner, router, n);
tl_assert (p.holes () == 0);
C res;
res.assign_hull (p.begin_hull (), p.end_hull ());
return res;
}
static gsi::Methods methods ()
{
return
@ -382,6 +413,45 @@ struct simple_polygon_defs
method ("to_s", (std::string (C::*) () const) &C::to_string,
"@brief Convert to a string\n"
) +
method_ext ("round_corners", &round_corners,
"@brief Round the corners of the polygon\n"
"@args rinner, router, n\n"
"\n"
"Replaces the corners of the polygon with circle segments.\n"
"\n"
"@param rinner The circle radius of inner corners (in database units).\n"
"@param router The circle radius of outer corners (in database units).\n"
"@param n The number of points per full circle.\n"
"\n"
"@return The new polygon.\n"
"\n"
"This method was introduced in version 0.22 for integer coordinates and in 0.25 for all coordinate types.\n"
) +
method_ext ("extract_rad", &extract_rad,
"@brief Extracts the corner radii from a rounded polygon\n"
"\n"
"Attempts to extract the radii of rounded corner polygon. This is essentially the inverse of "
"the \\round_corners method. If this method succeeds, if will return an array of four elements: "
"@ul\n"
"@li The polygon with the rounded corners replaced by edgy ones @/li\n"
"@li The radius of the inner corners @/li\n"
"@li The radius of the outer corners @/li\n"
"@li The number of points per full circle @/li\n"
"@/ul\n"
"\n"
"This method is based on some assumptions and may fail. In this case, an empty array is returned.\n"
"\n"
"If successful, the following code will more or less render the original polygon and parameters\n"
"\n"
"@code\n"
"p = ... # some polygon\n"
"p.round_corners(ri, ro, n)\n"
"(p2, ri2, ro2, n2) = p.extract_rad\n"
"# -> p2 == p, ro2 == ro, ri2 == ri, n2 == n (within some limits)\n"
"@/code\n"
"\n"
"This method was introduced in version 0.25.\n"
) +
method_ext ("area", &area,
"@brief The area of the polygon\n"
"The area is correct only if the polygon is not self-overlapping and the polygon is oriented clockwise."
@ -396,13 +466,6 @@ struct simple_polygon_defs
}
};
static db::Polygon sp_round_corners (const db::SimplePolygon *sp, double rinner, double router, unsigned int n)
{
db::Polygon p;
p.assign_hull (sp->begin_hull (), sp->end_hull (), false);
return db::compute_rounded (p, rinner, router, n);
}
static db::Polygon sp_minkowsky_sum_pe (const db::SimplePolygon *sp, const db::Edge &e, bool rh)
{
db::Polygon p;
@ -474,20 +537,6 @@ Class<db::SimplePolygon> decl_SimplePolygon ("SimplePolygon",
"\n"
"This method has been introduced in version 0.25."
) +
method_ext ("round_corners", &sp_round_corners,
"@brief Round the corners of the polygon\n"
"@args rinner, router, n\n"
"\n"
"Replaces the corners of the polygon with circle segments.\n"
"\n"
"@param rinner The circle radius of inner corners (in database units).\n"
"@param router The circle radius of outer corners (in database units).\n"
"@param n The number of points per full circle.\n"
"\n"
"@return The new polygon.\n"
"\n"
"This method was introduced in version 0.22.\n"
) +
method_ext ("minkowsky_sum", &sp_minkowsky_sum_pe,
"@brief Compute the Minkowsky sum of a polygon and an edge\n"
"@args a, b, resolve_holes\n"
@ -879,6 +928,28 @@ struct polygon_defs
return poly->area ();
}
static std::vector<tl::Variant> extract_rad (const C *p)
{
C pnew;
double rinner = 0.0, router = 0.0;
unsigned int n = 1;
if (! db::extract_rad (*p, rinner, router, n, &pnew)) {
return std::vector<tl::Variant> ();
} else {
std::vector<tl::Variant> res;
res.push_back (tl::Variant (pnew));
res.push_back (rinner);
res.push_back (router);
res.push_back (n);
return res;
}
}
static C round_corners (const C *p, double rinner, double router, unsigned int n)
{
return db::compute_rounded (*p, rinner, router, n);
}
static gsi::Methods methods ()
{
return
@ -1259,6 +1330,45 @@ struct polygon_defs
method ("to_s", (std::string (C::*) () const) &C::to_string,
"@brief Convert to a string\n"
) +
method_ext ("round_corners", &round_corners,
"@brief Rounds the corners of the polygon\n"
"@args rinner, router, n\n"
"\n"
"Replaces the corners of the polygon with circle segments.\n"
"\n"
"@param rinner The circle radius of inner corners (in database units).\n"
"@param router The circle radius of outer corners (in database units).\n"
"@param n The number of points per full circle.\n"
"\n"
"@return The new polygon.\n"
"\n"
"This method was introduced in version 0.20 for integer coordinates and in 0.25 for all coordinate types.\n"
) +
method_ext ("extract_rad", &extract_rad,
"@brief Extracts the corner radii from a rounded polygon\n"
"\n"
"Attempts to extract the radii of rounded corner polygon. This is essentially the inverse of "
"the \\round_corners method. If this method succeeds, if will return an array of four elements: "
"@ul\n"
"@li The polygon with the rounded corners replaced by edgy ones @/li\n"
"@li The radius of the inner corners @/li\n"
"@li The radius of the outer corners @/li\n"
"@li The number of points per full circle @/li\n"
"@/ul\n"
"\n"
"This method is based on some assumptions and may fail. In this case, an empty array is returned.\n"
"\n"
"If successful, the following code will more or less render the original polygon and parameters\n"
"\n"
"@code\n"
"p = ... # some polygon\n"
"p.round_corners(ri, ro, n)\n"
"(p2, ri2, ro2, n2) = p.extract_rad\n"
"# -> p2 == p, ro2 == ro, ri2 == ri, n2 == n (within some limits)\n"
"@/code\n"
"\n"
"This method was introduced in version 0.25.\n"
) +
method_ext ("area", &area,
"@brief The area of the polygon\n"
"The area is correct only if the polygon is not self-overlapping and the polygon is oriented clockwise."
@ -1316,11 +1426,6 @@ static db::Polygon smooth (const db::Polygon *p, db::Coord d)
return db::smooth (*p, d);
}
static db::Polygon round_corners (const db::Polygon *p, double rinner, double router, unsigned int n)
{
return db::compute_rounded (*p, rinner, router, n);
}
static db::Polygon minkowsky_sum_pe (const db::Polygon *p, const db::Edge &e, bool rh)
{
return db::minkowsky_sum (*p, e, rh);
@ -1514,20 +1619,6 @@ Class<db::Polygon> decl_Polygon ("Polygon",
"\n"
"This method was introduced in version 0.23.\n"
) +
method_ext ("round_corners", &round_corners,
"@brief Rounds the corners of the polygon\n"
"@args rinner, router, n\n"
"\n"
"Replaces the corners of the polygon with circle segments.\n"
"\n"
"@param rinner The circle radius of inner corners (in database units).\n"
"@param router The circle radius of outer corners (in database units).\n"
"@param n The number of points per full circle.\n"
"\n"
"@return The new polygon.\n"
"\n"
"This method was introduced in version 0.20.\n"
) +
method_ext ("minkowsky_sum", &minkowsky_sum_pe,
"@brief Computes the Minkowsky sum of the polygon and an edge\n"
"@args e, resolve_holes\n"

View File

@ -472,6 +472,59 @@ class DBPolygon_TestClass < TestBase
end
# polygon decomposition
def test_extractRad
ex = RBA::SimplePolygon::new.extract_rad
assert_equal(ex.inspect, "[]")
sp = RBA::SimplePolygon::from_s("(0,0;0,200000;300000,200000;300000,100000;100000,100000;100000,0)")
sp = sp.round_corners(10000, 5000, 200)
ex = sp.extract_rad
assert_equal(ex.inspect, "[(0,0;0,200000;300000,200000;300000,100000;100000,100000;100000,0), 10000.0, 5000.0, 200]")
ex = RBA::Polygon::new.extract_rad
assert_equal(ex.inspect, "[]")
sp = RBA::Polygon::from_s("(0,0;0,300000;300000,300000;300000,0/100000,100000;200000,100000;200000,200000;100000,200000)")
sp = sp.round_corners(10000, 5000, 200)
ex = sp.extract_rad
assert_equal(ex.inspect, "[(0,0;0,300000;300000,300000;300000,0/100000,100000;200000,100000;200000,200000;100000,200000), 10000.0, 5000.0, 200]")
# double coords too ...
ex = RBA::DSimplePolygon::new.extract_rad
assert_equal(ex.inspect, "[]")
sp = RBA::DSimplePolygon::from_s("(0,0;0,200000;300000,200000;300000,100000;100000,100000;100000,0)")
sp = sp.round_corners(10000, 5000, 200)
ex = sp.extract_rad
# round to integers for better comparison
ex[0] = RBA::SimplePolygon::new(ex[0])
assert_equal(ex.inspect, "[(0,0;0,200000;300000,200000;300000,100000;100000,100000;100000,0), 10000.0, 5000.0, 200]")
ex = RBA::DPolygon::new.extract_rad
assert_equal(ex.inspect, "[]")
sp = RBA::DPolygon::from_s("(0,0;0,300000;300000,300000;300000,0/100000,100000;200000,100000;200000,200000;100000,200000)")
sp = sp.round_corners(10000, 5000, 200)
ex = sp.extract_rad
# round to integers for better comparison
ex[0] = RBA::Polygon::new(ex[0])
assert_equal(ex.inspect, "[(0,0;0,300000;300000,300000;300000,0/100000,100000;200000,100000;200000,200000;100000,200000), 10000.0, 5000.0, 200]")
end
end
load("test_epilogue.rb")