diff --git a/src/db/db/dbPolygonTools.cc b/src/db/db/dbPolygonTools.cc index 18d850929..515d6c47f 100644 --- a/src/db/db/dbPolygonTools.cc +++ b/src/db/db/dbPolygonTools.cc @@ -121,6 +121,11 @@ struct cut_polygon_edge : contour (c), index (n), projected (p), point (pt), last_point (lpt) { } + edge_type edge () const + { + return edge_type (last_point, point); + } + int contour; unsigned int index; projection_type projected; @@ -137,151 +142,55 @@ struct cut_polygon_segment CuttingEdgeType leave; CuttingEdgeType enter; int segment; - bool hole; cut_polygon_segment () - : leave (), enter (), segment (-1), hole (false) + : leave (), enter (), segment (-1) { // .. nothing yet .. } +}; - bool operator< (const cut_polygon_segment &b) const +template +struct loose_end_struct +{ +public: + typedef typename CuttingEdgeType::edge_type edge_type; + typedef typename CuttingEdgeType::projection_type projection_type; + + loose_end_struct (bool _enter, typename std::vector >::const_iterator _iter) + : enter (_enter), iter (_iter) { - projection_type amin = std::min (leave.projected, enter.projected); - projection_type bmin = std::min (b.leave.projected, b.enter.projected); - - projection_type amax = std::max (leave.projected, enter.projected); - projection_type bmax = std::max (b.leave.projected, b.enter.projected); - - if (amin != bmin) { - return amin < bmin; - } else { - int vs = db::vprod_sign (min_edge (), b.min_edge ()); - if (vs != 0) { - return vs > 0; - } else if (amax == amin) { - return bmax != bmin; - } else if (bmax == bmin) { - return false; - } else { - return amax > bmax; - } - } + // .. nothing yet .. } - bool after (const cut_polygon_segment &b) const - { - projection_type pb_max = std::max (b.leave.projected, b.enter.projected); - projection_type pa_min = std::min (leave.projected, enter.projected); + bool enter; + typename std::vector >::const_iterator iter; - if (pb_max < pa_min) { - return true; - } else if (pb_max > pa_min) { - return false; - } else { - return db::vprod_sign (min_edge (), b.max_edge ()) <= 0; - } + edge_type edge () const + { + return enter ? iter->enter.edge () : iter->leave.edge (); } - edge_type max_edge () const + projection_type proj () const { - if (leave.projected > enter.projected) { - return edge_type (leave.last_point, leave.point); - } else if (leave.projected < enter.projected) { - return edge_type (enter.last_point, enter.point); - } else { - int vs = db::vprod_sign (leave.point - leave.last_point, enter.point - enter.last_point); - if (vs < 0) { - return edge_type (leave.last_point, leave.point); - } else { - return edge_type (enter.last_point, enter.point); - } - } + return enter ? iter->enter.projected : iter->leave.projected; } - edge_type min_edge () const + bool operator< (const loose_end_struct &other) const { - if (leave.projected < enter.projected) { - return edge_type (leave.last_point, leave.point); - } else if (leave.projected > enter.projected) { - return edge_type (enter.last_point, enter.point); + if (proj () != other.proj ()) { + return proj () < other.proj (); } else { - int vs = db::vprod_sign (leave.point - leave.last_point, enter.point - enter.last_point); - if (vs > 0) { - return edge_type (leave.last_point, leave.point); - } else { - return edge_type (enter.last_point, enter.point); - } + return db::vprod_sign (edge (), other.edge ()) > 0; } } }; -template -static void cut_polygon_produce_cut_points (typename std::vector::const_iterator from, typename std::vector::const_iterator to, std::vector &output, bool holes) -{ - typename std::vector::const_iterator e = from; - while (e != to) { - - // collect "illegal" segments (i.e. holes not being bracketed by a contour - typename std::vector::const_iterator e1 = e; - for ( ; e != to && e->hole != holes; ++e) { - ; - } - - if (e == to) { - // In this case we have only wrong typed segments within the wrong bracketing segment (i.e. holes inside a hole bracket) or on the outside. - // Sort the leaving and entering edges correctly. - for (typename std::vector::const_iterator o = e1; o != e; ++o) { - if (! holes) { - output.push_back (o->leave); - output.push_back (o->enter); - } else { - output.push_back (o->enter); - output.push_back (o->leave); - } - } - return; - } - - typename std::vector::const_iterator ee = e + 1; - for ( ; ee != to; ++ee) { - if (e->hole == holes && ee->after (*e)) { - break; - } - } - - if (e->hole) { - output.push_back (e->enter); - } else { - output.push_back (e->leave); - } - - // include all illegal segments into the first "good" segment, so we have a correct hierarchy at least. - if (e1 != e) { - cut_polygon_produce_cut_points (e1, e, output, !holes); - } - - if (e + 1 != ee) { - cut_polygon_produce_cut_points (e + 1, ee, output, !holes); - } - - if (e->hole) { - output.push_back (e->leave); - } else { - output.push_back (e->enter); - } - - e = ee; - - } -} - template void cut_polygon_internal (const PolygonType &input, const Edge &line, CutPolygonReceiverBase *right_of_line) { typedef typename PolygonType::point_type point_type; typedef typename PolygonType::coord_type coord_type; - typedef typename PolygonType::area_type area_type; typedef typename PolygonType::contour_type contour_type; typedef db::edge edge_type; typedef cut_polygon_edge cut_polygon_edge_type; @@ -352,34 +261,6 @@ void cut_polygon_internal (const PolygonType &input, const Edge &line, CutPolygo cutting_segments.pop_back (); } - // assign hull/hole identities .. - for (typename std::vector::iterator c = cutting_segments.begin () + nfirst; c != cutting_segments.end (); ++c) { - - unsigned int n = (unsigned int) contour.size (); - unsigned int n1 = c->enter.index; - unsigned int n2 = c->leave.index; - - // compute area of the segment and derive the hull part/hole part nature of the segment from the sign - area_type a = 0; - point_type pl = c->enter.point; - for (unsigned int i = n1; ; ) { - a += db::vprod (pl - point_type (), contour[i] - point_type ()); - pl = contour[i]; - if (i == n2) { - break; - } - ++i; - if (i == n) { - i = 0; - } - } - a += db::vprod (pl - point_type (), c->leave.point - point_type ()); - a += db::vprod (c->leave.point - point_type (), c->enter.point - point_type ()); - - c->hole = (a > 0); - - } - } else if (line.side_of (contour[0]) < 0) { if (do_hole_assignment) { @@ -403,12 +284,47 @@ void cut_polygon_internal (const PolygonType &input, const Edge &line, CutPolygo } - std::sort (cutting_segments.begin (), cutting_segments.end ()); + // build a table of the loose ends + + std::vector > loose_ends; + loose_ends.reserve (cutting_segments.size () * 2); + + for (typename std::vector::const_iterator i = cutting_segments.begin (); i != cutting_segments.end (); ++i) { + loose_ends.push_back (loose_end_struct (true, i)); + loose_ends.push_back (loose_end_struct (false, i)); + } + + std::stable_sort (loose_ends.begin (), loose_ends.end ()); + + // bring the points in a strict enter/leave order if possible + + bool enter = false; + for (typename std::vector >::iterator i = loose_ends.begin (); i != loose_ends.end (); ++i) { + if (i->enter != enter) { + typename std::vector >::iterator j = i + 1; + typename std::vector >::iterator jj = loose_ends.end (); + for ( ; j != loose_ends.end () && !(*j < *i) && !(*i < *j); ++j) { + if (j->enter == enter) { + jj = j; + break; + } + } + if (jj == loose_ends.end ()) { + tl_assert (false); // @@@ cannot cut + } + std::swap (*jj, *i); + } + enter = !enter; + } + + // connect the segments a pair each std::vector cutting_edges; - cutting_edges.reserve (cutting_segments.size () * 2); + cutting_edges.reserve (loose_ends.size ()); - cut_polygon_produce_cut_points (typename std::vector::const_iterator (cutting_segments.begin ()), typename std::vector::const_iterator (cutting_segments.end ()), cutting_edges, false); + for (typename std::vector >::iterator i = loose_ends.begin (); i != loose_ends.end (); ++i) { + cutting_edges.push_back (i->enter ? i->iter->enter : i->iter->leave); + } std::vector contour_points; typedef std::map , std::pair::iterator, typename std::vector::iterator> > cut_point_map_type;