/* KLayout Layout Viewer Copyright (C) 2006-2016 Matthias Koefferlein This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef HDR_dbEdgeProcessor #define HDR_dbEdgeProcessor #include "dbCommon.h" #include "dbTypes.h" #include "dbEdge.h" #include "dbPolygon.h" #include #include namespace db { struct WorkEdge; struct CutPoints; class EdgeSink; /** * @brief A destination for a (sorted) set of edges * * This receiver can be used as destination for the edge processor. * It will receive edge events in the scanline order, this is bottom to * top and left to right. Edges will be non-intersecting. * * This is the base class for such edge receivers. */ class DB_PUBLIC EdgeSink { public: /** * @brief Constructor */ EdgeSink () { } /** * @brief Destructor */ virtual ~EdgeSink () { }; /** * @brief Start event * * This method is called shortly before the first edge is delivered. * Specifically, all edges are already cached before this method is called. * Thus, inside an implementation of this method, the original source can be * discarded. */ virtual void start () { } /** * @brief End event * * This method is called after the last edge has been delivered. */ virtual void flush () { } /** * @brief Deliver an edge * * This method delivers an edge that ends or starts at the current scanline. */ virtual void put (const db::Edge &) { } /** * @brief Deliver an edge that crosses the scanline * * This method is called to deliver an edge that is not starting or ending at the * current scanline. * Another delivery of a set of crossing edges may happen through the skip_n * method which delivers a set of (unspecified) edges which are guaranteed to form * a closed sequence, that is one which is starting and ending at a wrap count of 0. */ virtual void crossing_edge (const db::Edge &) { } /** * @brief Deliver an edge set forming a closed sequence * * See description of "crossing_egde" for details. */ virtual void skip_n (size_t /*n*/) { } /** * @brief Signal the start of a scanline at the given y coordinate */ virtual void begin_scanline (db::Coord /*y*/) { } /** * @brief Signal the end of a scanline at the given y coordinate */ virtual void end_scanline (db::Coord /*y*/) { } }; /** * @brief A edge container that can be used as a receiver for edges * * This class reimplements the EdgeSink interface. * This receiver simply collects the edges in a container (a vector of edges) * which is either kept internally or supplied from the outside. */ class DB_PUBLIC EdgeContainer : public EdgeSink { public: /** * @brief Constructor connecting this receiver to an external edge vector */ EdgeContainer (std::vector &edges, bool clear = false) : EdgeSink (), mp_edges (&edges), m_clear (clear) { } /** * @brief Constructor using an internal edge vector */ EdgeContainer () : EdgeSink (), mp_edges (&m_edges), m_clear (false) { } /** * @brief Get the edges collected so far (const version) */ const std::vector &edges () const { return *mp_edges; } /** * @brief Get the edges collected so far (non-const version) */ std::vector &edges () { return *mp_edges; } /** * @brief Implementation of the EdgeSink interface */ virtual void start () { if (m_clear) { mp_edges->clear (); // The single-shot scheme is a easy way to overcome problems with multiple start/flush brackets (i.e. on size filter) m_clear = false; } } /** * @brief Implementation of the EdgeSink interface */ virtual void put (const db::Edge &e) { mp_edges->push_back (e); } private: std::vector m_edges; std::vector *mp_edges; bool m_clear; }; /** * @brief The edge set operator base class * * This class is an internal class that specifies how the output is formed from * a set of intersecting-free input edges. * Basically, this object receives events for the edges along the scan line. * At the beginning of the scan line, the "reset" method is called to bring the * evaluator into a defined state. Each edge has an integer property that can be * used to distinguish edges from different polygons or layers. */ class DB_PUBLIC EdgeEvaluatorBase { public: typedef size_t property_type; EdgeEvaluatorBase () { } virtual ~EdgeEvaluatorBase () { } virtual void reset () { } virtual void reserve (size_t /*n*/) { } virtual int edge (bool /*north*/, bool /*enter*/, property_type /*p*/) { return 0; } virtual bool select_edge (bool /*horizontal*/, property_type /*p*/) { return false; } virtual int compare_ns () const { return 0; } virtual bool is_reset () const { return false; } virtual bool prefer_touch () const { return false; } virtual bool selects_edges () const { return false; } }; /** * @brief An intersection detector * * This edge evaluator will not produce output edges but rather record the * property pairs of polygons intersecting. Only intersections (overlaps) * are recorded. Touching contacts are not recorded. * * It will build a set of property pairs, where the lower property value * is the first one of the pairs. */ class DB_PUBLIC InteractionDetector : public EdgeEvaluatorBase { public: typedef std::set > interactions_type; typedef interactions_type::const_iterator iterator; /** * @brief Constructor * * The mode parameter selects the interaction check mode. * 0 is "overlapping". * -1 will select all polygons inside polygons from the other layer. * +1 will select all polygons outside polygons from the other layer. * * In mode -1 and +1, finish () needs to be called before the interactions * can be used. In mode -1 and +1, the interactions delivered will contain * interactions of the reference property vs. the property of the respective * input polygons (property != reference property). In mode +1 these are * pseudo-interactions, because "outside" by definition means non-interacting. * * Mode -1 (inside) and +1 (outside) requires a single property value for the containing region. * This property value must be specified in the container_id parameter. * For correct operation, the container_id must be the lowest property ID and * the interacting edges must have higher property id's. * The reported interactions will be (container_id,polygon_id) even for outside mode. */ InteractionDetector (int mode = 0, property_type container_id = 0); /** * @brief Sets the "touching" flag * * If this flag is set, the interaction will include "touching" interactions in mode 0, i.e. * touching shapes will be counted as interacting. */ void set_include_touching (bool f) { m_include_touching = f; } /** * @brief Gets the "touching" flag */ bool include_touching () const { return m_include_touching; } /** * @brief Finish the collection * * This method must be called in mode -1 and +1 in order to finish the collection. */ void finish (); /** * @brief Iterator delivering the interactions (begin iterator) * * The iterator delivers pairs of property values. The lower value will be the first one of the pair. */ iterator begin () const { return m_interactions.begin (); } /** * @brief Iterator delivering the interactions (end iterator) */ iterator end () const { return m_interactions.end (); } virtual void reset (); virtual void reserve (size_t n); virtual int edge (bool north, bool enter, property_type p); virtual int compare_ns () const; virtual bool is_reset () const { return m_inside.empty (); } virtual bool prefer_touch () const { return m_mode == 0 && m_include_touching; } private: int m_mode; bool m_include_touching; property_type m_container_id; std::vector m_wcv_n, m_wcv_s; std::set m_inside; std::set > m_interactions; std::set m_non_interactions; }; /** * @brief A generic inside operator * * This incarnation of the evaluator class implements an "inside" function * based on a generic operator. */ template class DB_PUBLIC GenericMerge : public EdgeEvaluatorBase { public: /** * @brief Constructor */ GenericMerge (const F &function) : m_wc_n (0), m_wc_s (0), m_function (function) { } virtual void reset () { m_wc_n = m_wc_s = 0; } virtual void reserve (size_t /*n*/) { // .. nothing yet .. } virtual int edge (bool north, bool enter, property_type /*p*/) { int *wc = north ? &m_wc_n : &m_wc_s; bool t0 = m_function (*wc); if (enter) { ++*wc; } else { --*wc; } bool t1 = m_function (*wc); if (t1 && ! t0) { return 1; } else if (! t1 && t0) { return -1; } else { return 0; } } virtual int compare_ns () const { if (m_function (m_wc_s) && ! m_function (m_wc_n)) { return -1; } else if (! m_function (m_wc_s) && m_function (m_wc_n)) { return 1; } else { return 0; } } virtual bool is_reset () const { return (m_wc_n == 0 && m_wc_s == 0); } private: int m_wc_n, m_wc_s; F m_function; }; /** * @brief A helper class to implement the SimpleMerge operator */ struct ParametrizedInsideFunc { ParametrizedInsideFunc (int mode) : m_mode (mode) { // .. nothing yet .. } inline bool operator() (int wc) const { if (m_mode > 0) { return wc >= m_mode; } else if (m_mode < 0) { return wc <= m_mode || -wc <= m_mode; } else { return (wc < 0 ? ((-wc) % 2) : (wc % 2)) != 0; } } public: int m_mode; }; /** * @brief Simple merge operator * * This incarnation of the evaluator class implements a simple * merge criterion for a set of edges. A result is generated if the wrap count (wc) * of the edge set satisfies a condition given by "mode". Specifically: * mode == 0: even-odd rule (wc = ... -3, -1, 1, 3, ...) * mode == 1: wc >= 1 * mode == -1: wc >= 1 || wc <= -1 * mode == n: wc >= n * mode == -n: wc >= n || wc <= -n */ class DB_PUBLIC SimpleMerge : public GenericMerge { public: /** * @brief Constructor */ SimpleMerge (int mode = -1) : GenericMerge (ParametrizedInsideFunc (mode)) { } }; /** * @brief Boolean operations * * This incarnation of the evaluator class implements a boolean operation * (AND, A NOT B, B NOT A, XOR, OR). The mode can be specified in the constructor. * It relies on the properties being set in a certain way: bit 0 codes the layer (0 for A, 1 for B) * while the other bits are used to distinguish the polygons. For each polygon, a non-zero * wrap count rule is applied before the boolean operation's output is formed. */ class DB_PUBLIC BooleanOp : public EdgeEvaluatorBase { public: enum BoolOp { And = 1, ANotB = 2, BNotA = 3, Xor = 4, Or = 5 }; /** * @brief Constructor * * @param mode The boolean operation that this object represents */ BooleanOp (BoolOp mode); virtual void reset (); virtual void reserve (size_t n); virtual int edge (bool north, bool enter, property_type p); virtual int compare_ns () const; virtual bool is_reset () const { return m_zeroes == m_wcv_n.size () + m_wcv_s.size (); } protected: template bool result (int wca, int wcb, const InsideFunc &inside_a, const InsideFunc &inside_b) const; template int edge_impl (bool north, bool enter, property_type p, const InsideFunc &inside_a, const InsideFunc &inside_b); template int compare_ns_impl (const InsideFunc &inside_a, const InsideFunc &inside_b) const; private: int m_wc_na, m_wc_nb, m_wc_sa, m_wc_sb; std::vector m_wcv_n, m_wcv_s; BoolOp m_mode; size_t m_zeroes; }; /** * @brief Edge vs. Polygon intersection * * This operator detects edges inside or outside polygons. * The polygon edges must be given with property 0, the other edges * with properties 1 and higher. * * The operator will deliver edges inside polygons or outside polygons. * It can be configured to include edges on the border of the polygons * as being considered "inside the polygon". */ class DB_PUBLIC EdgePolygonOp : public db::EdgeEvaluatorBase { public: /** * @brief Constructor * * @param outside If true, the operator will deliver edges outside the polygon * @param include_touching If true, edges on the polygon's border will be considered "inside" of polygons * @param polygon_mode Determines how the polygon edges on property 0 are interpreted (see merge operators) */ EdgePolygonOp (bool outside = false, bool include_touching = true, int polygon_mode = -1); virtual void reset (); virtual bool select_edge (bool horizontal, property_type p); virtual int edge (bool north, bool enter, property_type p); virtual bool is_reset () const; virtual bool prefer_touch () const; virtual bool selects_edges () const; private: bool m_outside, m_include_touching; db::ParametrizedInsideFunc m_function; int m_wcp_n, m_wcp_s; }; /** * @brief Boolean operations * * This class implements a boolean operation similar to BooleanOp, but * in addition it allows to specify the merge mode for the two inputs. * See "SimpleMergeOp" for the definition of the merge modes. * This operator is especially useful to implement boolean operations * with sized polygons which required a >0 interpretation. */ class DB_PUBLIC BooleanOp2 : public BooleanOp { public: /** * @brief Constructor * * @param mode The boolean operation that this object represents */ BooleanOp2 (BoolOp mode, int wc_mode_a, int wc_mode_b); virtual int edge (bool north, bool enter, property_type p); virtual int compare_ns () const; private: int m_wc_mode_a, m_wc_mode_b; }; /** * @brief Merge operation * * This incarnation of the evaluator class implements a merge operation * which allows to distinguish polygons (through edge properties) and * allows to specify a overlap value. Default is 0 which means that the * merge is equivalent to producing all polygins. A overlap value of 1 means * that at least two polygons must overlap to produce a result. */ class DB_PUBLIC MergeOp : public EdgeEvaluatorBase { public: /** * @brief Constructor * * @param min_overlap See class description */ MergeOp (unsigned int min_overlap = 0); virtual void reset (); virtual void reserve (size_t n); virtual int edge (bool north, bool enter, property_type p); virtual int compare_ns () const; virtual bool is_reset () const { return m_zeroes == m_wcv_n.size () + m_wcv_s.size (); } private: int m_wc_n, m_wc_s; std::vector m_wcv_n, m_wcv_s; unsigned int m_min_wc; size_t m_zeroes; }; /** * @brief The basic edge processor * * An edge processor takes a set of edges, processes them by removing intersections and * applying a custom operator for computing the output edge sets which then are delivered * to an EdgeSink receiver object. */ class DB_PUBLIC EdgeProcessor { public: typedef size_t property_type; /** * @brief Default constructor * * @param report_progress If true, a tl::Progress object will be created to report any progress (warning: this will impose a performance penalty) * @param progress_text The description text of the progress object */ EdgeProcessor (bool report_progress = false, const std::string &progress_desc = std::string ()); /** * @brief Destructor */ ~EdgeProcessor (); /** * @brief Enable progress reporting * * @param progress_text The description text of the progress object */ void enable_progress (const std::string &progress_desc = std::string ()); /** * @brief Disable progress reporting */ void disable_progress (); /** * @brief Reserve space for at least n edges */ void reserve (size_t n); /** * @brief Insert an edge */ void insert (const db::Edge &e, property_type p = 0); /** * @brief Insert an polygon */ void insert (const db::Polygon &q, property_type p = 0); /** * @brief Insert a sequence of edges * * This method does not reserve for the number of elements required. This must * be done explicitly for performance benefits. */ template void insert_sequence (Iter from, Iter to, property_type p = 0) { for (Iter i = from; i != to; ++i) { insert (*i, p); } } /** * @brief Insert a sequence of edges (iterator with at_end semantics) * * This method does not reserve for the number of elements required. This must * be done explicitly for performance benefits. */ template void insert_sequence (Iter i, property_type p = 0) { for ( ; !i.at_end (); ++i) { insert (*i, p); } } /** * @brief Clear all edges stored currently in this processor */ void clear (); /** * @brief Process the edges stored currently */ void process (db::EdgeSink &es, EdgeEvaluatorBase &op); /** * @brief Merge the given polygons in a simple "non-zero wrapcount" fashion * * The wrapcount is computed over all polygons, i.e. overlapping polygons may "cancel" if they * have different orientation (since a polygon is oriented by construction that is not easy to achieve). * The other merge operation provided for this purpose is "merge" which normalizes each polygon individually before * merging them. "simple_merge" is somewhat faster and consumes less memory. * * The result is presented as a set of edges forming closed contours. Hulls are oriented clockwise while * holes are oriented counter-clockwise. * * This is a convenience method that bundles filling of the edges, processing with * a SimpleMerge operator and puts the result into an output vector. * * @param in The input polygons * @param out The output edges * @param mode The merge mode (see SimpleMerge constructor) */ void simple_merge (const std::vector &in, std::vector &out, int mode = -1); /** * @brief Merge the given polygons in a simple "non-zero wrapcount" fashion into polygons * * The wrapcount is computed over all polygons, i.e. overlapping polygons may "cancel" if they * have different orientation (since a polygon is oriented by construction that is not easy to achieve). * The other merge operation provided for this purpose is "merge" which normalizes each polygon individually before * merging them. "simple_merge" is somewhat faster and consumes less memory. * * This method produces polygons and allows to fine-tune the parameters for that purpose. * * This is a convenience method that bundles filling of the edges, processing with * a SimpleMerge operator and puts the result into an output vector. * * @param in The input polygons * @param out The output polygons * @param resolve_holes true, if holes should be resolved into the hull * @param min_coherence true, if touching corners should be resolved into less connected contours * @param mode The merge mode (see SimpleMerge constructor) */ void simple_merge (const std::vector &in, std::vector &out, bool resolve_holes = true, bool min_coherence = true, int mode = -1); /** * @brief Merge the given edges in a simple "non-zero wrapcount" fashion * * The egdes provided must form valid closed contours. Contours oriented differently "cancel" each other. * Overlapping contours are merged when the orientation is the same. * * The result is presented as a set of edges forming closed contours. Hulls are oriented clockwise while * holes are oriented counter-clockwise. * * This is a convenience method that bundles filling of the edges, processing with * a SimpleMerge operator and puts the result into an output vector. * * @param in The input edges * @param out The output edges * @param mode The merge mode (see SimpleMerge constructor) */ void simple_merge (const std::vector &in, std::vector &out, int mode = -1); /** * @brief Merge the given edges in a simple "non-zero wrapcount" fashion into polygons * * The egdes provided must form valid closed contours. Contours oriented differently "cancel" each other. * Overlapping contours are merged when the orientation is the same. * * This method produces polygons and allows to fine-tune the parameters for that purpose. * * This is a convenience method that bundles filling of the edges, processing with * a SimpleMerge operator and puts the result into an output vector. * * @param in The input edges * @param out The output polygons * @param resolve_holes true, if holes should be resolved into the hull * @param min_coherence true, if touching corners should be resolved into less connected contours * @param mode The merge mode (see SimpleMerge constructor) */ void simple_merge (const std::vector &in, std::vector &out, bool resolve_holes = true, bool min_coherence = true, int mode = -1); /** * @brief Merge the given polygons * * In contrast to "simple_merge", this merge implementation considers each polygon individually before merging them. * Thus self-overlaps are effectively removed before the output is computed and holes are correctly merged with the * hull. In addition, this method allows to select areas with a higher wrap count which allows to compute overlaps * of polygons on the same layer. Because this method merges the polygons before the overlap is computed, self-overlapping * polygons do not contribute to higher wrap count areas. * * The result is presented as a set of edges forming closed contours. Hulls are oriented clockwise while * holes are oriented counter-clockwise. * * This is a convenience method that bundles filling of the edges, processing with * a Merge operator and puts the result into an output vector. * * @param in The input polygons * @param out The output edges * @param min_wc The minimum wrap count for output (0: all polygons, 1: at least two overlapping) */ void merge (const std::vector &in, std::vector &out, unsigned int min_wc = 0); /** * @brief Merge the given polygons * * In contrast to "simple_merge", this merge implementation considers each polygon individually before merging them. * Thus self-overlaps are effectively removed before the output is computed and holes are correctly merged with the * hull. In addition, this method allows to select areas with a higher wrap count which allows to compute overlaps * of polygons on the same layer. Because this method merges the polygons before the overlap is computed, self-overlapping * polygons do not contribute to higher wrap count areas. * * This method produces polygons and allows to fine-tune the parameters for that purpose. * * This is a convenience method that bundles filling of the edges, processing with * a Merge operator and puts the result into an output vector. * * @param in The input polygons * @param out The output polygons * @param min_wc The minimum wrap count for output (0: all polygons, 1: at least two overlapping) * @param resolve_holes true, if holes should be resolved into the hull * @param min_coherence true, if touching corners should be resolved into less connected contours */ void merge (const std::vector &in, std::vector &out, unsigned int min_wc = 0, bool resolve_holes = true, bool min_coherence = true); /** * @brief Size the given polygons * * This method sizes a set of polygons. Before the sizing is applied, the polygons are merged. After that, sizing is applied * on the individual result polygons of the merge step. The result may contain overlapping contours, but no self-overlaps. * * dx and dy describe the sizing. A positive value indicates oversize (outwards) while a negative one describes undersize (inwards). * The sizing applied can be choosen differently in x and y direction. In this case, the sign must be identical for both * dx and dy. * * The result is presented as a set of edges forming closed contours. Hulls are oriented clockwise while * holes are oriented counter-clockwise. * * This is a convenience method that bundles filling of the edges and processing them * and which puts the result into an output vector. * * @param in The input polygons * @param dx The sizing value in x direction * @param dy The sizing value in y direction * @param out The output edges * @param mode The sizing mode (see db::Polygon for a description) */ void size (const std::vector &in, db::Coord dx, db::Coord dy, std::vector &out, unsigned int mode = 2); /** * @brief Size the given polygons into polygons * * This method sizes a set of polygons. Before the sizing is applied, the polygons are merged. After that, sizing is applied * on the individual result polygons of the merge step. The result may contain overlapping polygons, but no self-overlapping ones. * Polygon overlap occures if the polygons are close enough, so a positive sizing makes polygons overlap. * * dx and dy describe the sizing. A positive value indicates oversize (outwards) while a negative one describes undersize (inwards). * The sizing applied can be choosen differently in x and y direction. In this case, the sign must be identical for both * dx and dy. * * This method produces polygons and allows to fine-tune the parameters for that purpose. * * This is a convenience method that bundles filling of the edges, processing with * a SimpleMerge operator and puts the result into an output vector. * * @param in The input polygons * @param dx The sizing value in x direction * @param dy The sizing value in y direction * @param out The output polygons * @param mode The sizing mode (see db::Polygon for a description) * @param resolve_holes true, if holes should be resolved into the hull * @param min_coherence true, if touching corners should be resolved into less connected contours */ void size (const std::vector &in, db::Coord dx, db::Coord dy, std::vector &out, unsigned int mode = 2, bool resolve_holes = true, bool min_coherence = true); /** * @brief Size the given polygons (isotropic) * * This method is equivalent to calling the anisotropic version with identical dx and dy. * * @param in The input polygons * @param d The sizing value in x direction * @param out The output edges * @param mode The sizing mode (see db::Polygon for a description) */ void size (const std::vector &in, db::Coord d, std::vector &out, unsigned int mode = 2) { size (in, d, d, out, mode); } /** * @brief Size the given polygons into polygons (isotropic) * * This method is equivalent to calling the anisotropic version with identical dx and dy. * * @param in The input polygons * @param d The sizing value in x direction * @param out The output polygons * @param mode The sizing mode (see db::Polygon for a description) * @param resolve_holes true, if holes should be resolved into the hull * @param min_coherence true, if touching corners should be resolved into less connected contours */ void size (const std::vector &in, db::Coord d, std::vector &out, unsigned int mode = 2, bool resolve_holes = true, bool min_coherence = true) { size (in, d, d, out, mode, resolve_holes, min_coherence); } /** * @brief Boolean operation for a set of given polygons, creating edges * * This method computes the result for the given boolean operation on two sets of polygons. * The result is presented as a set of edges forming closed contours. Hulls are oriented clockwise while * holes are oriented counter-clockwise. * * This is a convenience method that bundles filling of the edges, processing with * a Boolean operator and puts the result into an output vector. * * @param a The input polygons (first operand) * @param b The input polygons (second operand) * @param out The output edges * @param mode The boolean mode */ void boolean (const std::vector &a, const std::vector &b, std::vector &out, int mode); /** * @brief Boolean operation for a set of given polygons, creating polygons * * This method computes the result for the given boolean operation on two sets of polygons. * This method produces polygons on output and allows to fine-tune the parameters for that purpose. * * This is a convenience method that bundles filling of the edges, processing with * a Boolean operator and puts the result into an output vector. * * @param a The input polygons (first operand) * @param b The input polygons (second operand) * @param out The output polygons * @param mode The boolean mode * @param resolve_holes true, if holes should be resolved into the hull * @param min_coherence true, if touching corners should be resolved into less connected contours */ void boolean (const std::vector &a, const std::vector &b, std::vector &out, int mode, bool resolve_holes = true, bool min_coherence = true); /** * @brief Boolean operation for a set of given edges, creating edges * * This method computes the result for the given boolean operation on two sets of edges. * The input edges must form closed contours where holes and hulls must be oriented differently. * The input edges are processed with a simple non-zero wrap count rule as a whole. * * The result is presented as a set of edges forming closed contours. Hulls are oriented clockwise while * holes are oriented counter-clockwise. * * This is a convenience method that bundles filling of the edges, processing with * a Boolean operator and puts the result into an output vector. * * @param a The input edges (first operand) * @param b The input edges (second operand) * @param out The output edges * @param mode The boolean mode */ void boolean (const std::vector &a, const std::vector &b, std::vector &out, int mode); /** * @brief Boolean operation for a set of given edges, creating polygons * * This method computes the result for the given boolean operation on two sets of edges. * The input edges must form closed contours where holes and hulls must be oriented differently. * The input edges are processed with a simple non-zero wrap count rule as a whole. * * This method produces polygons on output and allows to fine-tune the parameters for that purpose. * * This is a convenience method that bundles filling of the edges, processing with * a Boolean operator and puts the result into an output vector. * * @param a The input polygons (first operand) * @param b The input polygons (second operand) * @param out The output polygons * @param mode The boolean mode * @param resolve_holes true, if holes should be resolved into the hull * @param min_coherence true, if touching corners should be resolved into less connected contours */ void boolean (const std::vector &a, const std::vector &b, std::vector &out, int mode, bool resolve_holes = true, bool min_coherence = true); private: std::vector *mp_work_edges; std::vector *mp_cpvector; bool m_report_progress; std::string m_progress_desc; static size_t count_edges (const db::Polygon &q) { size_t n = q.hull ().size (); for (unsigned int h = 0; h < q.holes (); ++h) { n += q.hole (h).size (); } return n; } static size_t count_edges (const std::vector &v) { size_t n = 0; for (std::vector::const_iterator p = v.begin (); p != v.end (); ++p) { n += count_edges (*p); } return n; } }; } #endif