/* KLayout Layout Viewer Copyright (C) 2006-2017 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_dbBox #define HDR_dbBox #include "dbCommon.h" #include "dbPoint.h" #include "dbTrans.h" #include "dbObjectTag.h" #include "tlTypeTraits.h" #include #include #include namespace db { template class generic_repository; class ArrayRepository; /** * @brief A box class * * This object represents a box (a rectangular shape). * Notation is: p1 is the lower left point, p2 the * upper right one. * A box can be empty. An empty box represents no area * (not even a point). A box can be a point or a single * line. In this case, the area is zero but the box still * can overlap other boxes. * The template parameter C is the type to use for coordinate * values. "R" is the type actually used for representing the * coordinates internally (i.e. R=short, C=int for a 16bit * coordinates box). */ template struct box { typedef C coord_type; typedef box box_type; typedef point point_type; typedef vector vector_type; typedef typename coord_traits::area_type area_type; typedef typename coord_traits::distance_type distance_type; typedef typename coord_traits::perimeter_type perimeter_type; typedef object_tag< box > tag; /** * @brief Empty box constructor */ box () : m_p1 (1, 1), m_p2 (-1, -1) { // .. nothing else .. } /** * @brief Standard constructor with four coordinates * * Creates a box from four coordinates (left, bottom, * right, top). The coordinates are sorted, so left and * right can be swapped as well as top and bottom. * * @param x1 The first x coordinate * @param y1 The first y coordinate * @param x2 The second x coordinate * @param y2 The second y coordinate */ box (C x1, C y1, C x2, C y2) : m_p1 (x1 < x2 ? x1 : x2, y1 < y2 ? y1 : y2), m_p2 (x2 > x1 ? x2 : x1, y2 > y1 ? y2 : y1) { // .. nothing else .. } /** * @brief The standard constructor taking two point objects * * As the four coordinate constructor but accepting two * point objects. The coordinates are sorted so the points * do not neccessarily need to be lower/left or upper/right. * * @param p1 The first point * @param p2 The second point */ box (const point &p1, const point &p2) : m_p1 (p1.x () < p2.x () ? p1.x () : p2.x (), p1.y () < p2.y () ? p1.y () : p2.y ()), m_p2 (p2.x () > p1.x () ? p2.x () : p1.x (), p2.y () > p1.y () ? p2.y () : p1.y ()) { // .. nothing else .. } /** * @brief The copy constructor that also does type conversions * * The implementation relies on the ability of the point constructor * to convert between types. It assumes that the conversion is * maintaining the order of the coordinates and the emptyness condition. */ template explicit box (const box &b) : m_p1 (b.p1 ()), m_p2 (b.p2 ()) { // .. nothing else .. } /** * @brief The world box (maximum dimensions) * * Hint: this box is likely to be somewhat misfunctional. It cannot be transformed well for example. */ static box world () { return box (std::numeric_limits::min (), std::numeric_limits::min (), std::numeric_limits::max (), std::numeric_limits::max ()); } /** * @brief The (dummy) translation operator */ void translate (const box &d, db::generic_repository &, db::ArrayRepository &); /** * @brief The (dummy) translation operator */ template void translate (const box &d, const T &t, db::generic_repository &, db::ArrayRepository &); /** * @brief The "less" operator to establish a sorting order. */ bool operator< (const box &b) const; /** * @brief Equality test */ bool operator== (const box &b) const; /** * @brief Inequality test */ bool operator!= (const box &b) const; /** * @brief Fuzzy comparison of boxes */ bool equal (const box_type &b) const; /** * @brief Fuzzy comparison of boxes */ bool not_equal (const box_type &b) const { return !equal (b); } /** * @brief Fuzzy "less" comparison of points */ bool less (const box_type &p) const; /** * @brief A method version for scaling operator* (mainly for automation purposes) */ box scaled (double s) const; /** * @brief Convolve boxes. * * The *= operator convolves the box with the one given as * the argument. The box resulting from "convolution" is the * outer boundary of the union set formed by placing * the second box at every point of the first. In other words, * the returned box of (p1,p2)*(q1,q2) is (p1+q1,p2+q2). * * @param b The box to convolve with *this. * * @return The convolved box. */ box &operator*= (const box &b); /** * @brief A method version for operator* (mainly for automation purposes) */ box convolved (const box &b) const; /** * @brief Joining of boxes. * * The += operator joins the box with the one given as * the argument. Joining constructs a box that encloses * both boxes given. Empty boxes are neutral: they do not * change another box when joining. Overwrites *this * with the result. * * @param b The box to join with *this. * * @return The joined box. */ box &operator+= (const box &b); /** * @brief A method version for operator+ (mainly for automation purposes) */ box joined (const box &b) const; /** * @brief Joining of a box with a point. * * The += operator joins the box with a point such that * the new box encloses the point and the old box. * Overwrites *this with the result. * * @param p The point to join with *this. * * @return The joined box. */ box &operator+= (const point &p); /** * @brief Intersection of boxes. * * The intersection of two boxes is the largest * box common to both boxes. The intersection may be * empty if both boxes to not touch. If the boxes do * not overlap but touch the result may be a single * line or point with an area of zero. Overwrites *this * with the result. * * @param c The box to take the intersection with * * @return The intersection box. */ box &operator&= (const box &b); /** * @brief A method version for operator& (mainly for automation purposes) */ box intersection (const box &b) const; /** * @brief Returns the box moved by a certain distance * * Moves the box by a given offset and returns the moved * box. Does not modify *this. Does not check for coordinate * overflows. * * @param p The offset to move the box. * * @return The moved box. */ box moved (const vector &p) const; /** * @brief Enlarges the box by a certain amount. * * Enlarges the box by x and y value specified in the vector * passed. Positive values with grow the box, negative ones * will shrink the box. The result may be an empty box if the * box disappears. The amount specifies the grow or shrink * per edge. The width and height will change by twice the * amount. * Does not modify *this. Does not check for coordinate * overflows. * * @param p The grow or shrink amount in x and y direction * * @return The enlarged box. */ box enlarged (const vector &p) const; /** * @brief Transformation of the box * * Transforms the box with a given transformation and * writes the result to *this. If the transformation is non-orthogonal, * the result will still be a box (which is not correct strictly spoken) * which will be the enclosing box of the rotated box. * * @param t The transformation to apply. * * @return The transformed box. */ template box &transform (const Tr &t); /** * @brief Returns the transformed box. * * Transforms the box and returns the result without changing * the box. If the transformation is non-orthogonal, * the result will still be a box (which is not correct strictly spoken) * which will be the enclosing box of the rotated box. * * @param t The transformation to apply. * * @return The transformed box. */ template box transformed (const Tr &t) const; /** * @brief Moves the box * * Like %moved but modifies the box so it becomes the moved * box. * * @param p The distance to move * * @return The moved box. */ box &move (const vector &p); /** * @brief Reduce the box * * This method is mainly provided for template argument substituition * of path and polygon objects by boxes. It basically moves the box. * * @param tr Receives the transformation that must be applied to render the original box */ void reduce (simple_trans &tr) { vector_type d (p1 () - point_type ()); move (-d); tr = simple_trans (simple_trans::r0, d); } /** * @brief Reduce the box * * This method is mainly provided for template argument substituition * of path and polygon objects by boxes. It basically moves the box. * * @param tr Receives the transformation that must be applied to render the original box */ void reduce (disp_trans &tr) { vector_type d (p1 () - point_type ()); move (-d); tr = disp_trans (d); } /** * @brief Reduce the box * * This method is mainly provided for template argument substituition * of path and polygon objects by boxes. It basically does nothing (like the same methods in path etc.) */ void reduce (unit_trans &) { // .. nothing .. } /** * @brief Enlarges the box * * Like %enlarged but modifies the box so it becomes the enlarged * box. * * @param p The grow/shrink to apply. * * @return The enlarged box. */ box &enlarge (const vector &p); /** * @brief Accessor to the lower left point. * * @return The lower left point */ const point &p1 () const; /** * @brief Accessor to the upper right point. * * @return The upper right point */ const point &p2 () const; /** * @brief Accessor to the lower left point. This is synonym for p1. * * @return The lower left point */ const point &lower_left () const; /** * @brief Accessor to the upper right point. This a synonym for p2. * * @return The upper right point */ const point &upper_right () const; /** * @brief Accessor to the upper left point. * * @return The upper left point */ point upper_left () const; /** * @brief Accessor to the lower right point. * * @return The lower right point */ point lower_right () const; /** * @brief is_point predicate * * A box has this predicate if it consists of exactly one point */ bool is_point () const; /** * @brief Write accessor to the lower left point. * * The box will still remain a valid box even if the new lower left point * is not the actual lower left point. In this case, the points will be * ordered properly. */ void set_p1 (const point &_p1); /** * @brief Accessor to the upper right point. * * The box will still remain a valid box even if the new upper right point * is not the actual upper right point. In this case, the points will be * ordered properly. */ void set_p2 (const point &_p2); /** * @brief Accessor to the center point * * Due to rounding in integer space, the center coordinate may not * be the exact center unless double coordinates as used. * For very large boxes, width and height might overflow and the * result may not be correct. * * @return The center */ point center () const; /** * @brief The width of the box. * * @return The width of the box. */ distance_type width () const; /** * @brief The height of the box. * * @return The height of the box. */ distance_type height () const; /** * @brief The left boundary of the box. */ C left () const; /** * @brief The right boundary of the box. */ C right () const; /** * @brief The top boundary of the box. */ C top () const; /** * @brief The bottom boundary of the box. */ C bottom () const; /** * @brief Set the left margin * * If the left margin gets larger that the right one, the value given will become the * right margin */ void set_left (C l); /** * @brief Set the right margin * * If the right margin gets less that the left one, the value given will become the * left margin */ void set_right (C r); /** * @brief Set the bottom margin * * If the bottom margin gets larger that the top one, the value given will become the * top margin */ void set_bottom (C b); /** * @brief Set the top margin * * If the top margin gets less that the bottom one, the value given will become the * bottom margin */ void set_top (C t); /** * @brief Empty test of the box. * * @return True if the box is empty (not if the area is zero) */ bool empty () const; /** * @brief Contains test. * * Tests whether a point is inside the box. * This includes if the point is on the box contour. * * @param p The point to test against. * * @return true if the point is inside p. */ bool contains (const point &p) const; /** * @brief Inside test. * * Tests whether the box is inside the given one. Returns false * if either the box of the test box is empty. * "Inside" also includes the case when the edges of the box coincide. * * @param b The box to test against. * * @return true if the box is inside b. */ bool inside (const box &b) const; /** * @brief Touching test. * * Tests whether the box is touching the given one. Returns false * if either the box of the test box is empty. * Touching also includes the case of overlap. * * @param b The box to test against. * * @return true if the box is touching b (has as least one common * point with b) */ bool touches (const box &b) const; /** * @brief Overlap test. * * Tests whether the box is overlapping the given one. Returns false * if either the box of the test box is empty. * * @param b The box to test against. * * @return true if the box is overlapping b (the area of the * intersection box is non-empty) */ bool overlaps (const box &b) const; /** * @brief Computation of the perimeter of a box * * @return The perimeter of the box. 0 if empty. */ perimeter_type perimeter () const; /** * @brief Computation of the area of a box * * @return The area of the box. 0 if empty. */ area_type area () const; /** * @brief Computation of the area of a box in double * * @return The area of the box. 0 if empty. */ double double_area () const; /** * @brief Default conversion to string */ std::string to_string () const { return to_string (0.0); } /** * @brief Conversion to string * * If dbu is set, it determines the factor by which the coordinates are multiplied to render * micron units. In addition, a micron format is choosen for output of these coordinates. */ std::string to_string (double dbu) const { if (empty ()) { return "()"; } else { return "(" + m_p1.to_string (dbu) + ";" + m_p2.to_string (dbu) + ")"; } } private: point m_p1, m_p2; }; template inline void box::translate (const box &d, db::generic_repository &, db::ArrayRepository &) { *this = d; } template template inline void box::translate (const box &d, const T &t, db::generic_repository &, db::ArrayRepository &) { *this = d; transform (t); } template inline bool box::operator< (const box &b) const { return m_p1 < b.m_p1 || (m_p1 == b.m_p1 && m_p2 < b.m_p2); } template inline bool box::less (const box &b) const { if (! m_p1.equal (b.p1 ())) { return m_p1.less (b.p1 ()); } if (! m_p2.equal (b.p2 ())) { return m_p2.less (b.p2 ()); } return false; } template inline bool box::operator== (const box &b) const { if (empty () && b.empty ()) { return true; } else if (! empty () && ! b.empty ()) { return m_p1 == b.m_p1 && m_p2 == b.m_p2; } else { return false; } } template inline bool box::operator!= (const box &b) const { return !operator== (b); } template inline bool box::equal (const box &b) const { return m_p1.equal (b.p1 ()) && m_p2.equal (b.p2 ()); } template inline box & box::operator*= (const box &b) { if (! b.empty () && ! empty ()) { m_p1 += vector (b.m_p1); m_p2 += vector (b.m_p2); } else { *this = box (); } return *this; } template inline box box::scaled (double s) const { return box (*this * s); } template inline box box::convolved (const box &b) const { box r (*this); r *= b; return r; } template inline box & box::operator+= (const box &b) { if (! b.empty ()) { if (empty ()) { *this = b; } else { db::point p1 (m_p1.x () < b.m_p1.x () ? m_p1.x () : b.m_p1.x (), m_p1.y () < b.m_p1.y () ? m_p1.y () : b.m_p1.y ()); db::point p2 (m_p2.x () > b.m_p2.x () ? m_p2.x () : b.m_p2.x (), m_p2.y () > b.m_p2.y () ? m_p2.y () : b.m_p2.y ()); m_p1 = p1; m_p2 = p2; } } return *this; } template inline box box::joined (const box &b) const { box r (*this); r += b; return r; } template inline box & box::operator+= (const point &p) { if (empty ()) { m_p1 = point (p); m_p2 = point (p); } else { db::point p1 (m_p1.x () < p.x () ? m_p1.x () : p.x (), m_p1.y () < p.y () ? m_p1.y () : p.y ()); db::point p2 (m_p2.x () > p.x () ? m_p2.x () : p.x (), m_p2.y () > p.y () ? m_p2.y () : p.y ()); m_p1 = p1; m_p2 = p2; } return *this; } template inline box & box::operator&= (const box &b) { if (b.empty ()) { *this = box (); } else if (! empty ()) { point p1 (m_p1.x () > b.m_p1.x () ? m_p1.x () : b.m_p1.x (), m_p1.y () > b.m_p1.y () ? m_p1.y () : b.m_p1.y ()); point p2 (m_p2.x () < b.m_p2.x () ? m_p2.x () : b.m_p2.x (), m_p2.y () < b.m_p2.y () ? m_p2.y () : b.m_p2.y ()); m_p1 = p1; m_p2 = p2; } return *this; } template inline box box::intersection (const box &b) const { box r (*this); r &= b; return r; } template inline box box::moved (const vector &p) const { box b (*this); b.move (p); return b; } template inline box box::enlarged (const vector &p) const { box b (*this); b.enlarge (p); return b; } template template inline box & box::transform (const Tr &t) { if (! empty ()) { if (t.is_ortho ()) { *this = box (point (t * m_p1), point (t * m_p2)); } else { box b (point (t * m_p1), point (t * m_p2)); b += point (t * upper_left ()); b += point (t * lower_right ()); *this = b; } } return *this; } template template inline box box::transformed (const Tr &t) const { if (! empty ()) { if (t.is_ortho ()) { return box (t * m_p1, t * m_p2); } else { box b (t * m_p1, t * m_p2); b += t * upper_left (); b += t * lower_right (); return b; } } else { return box (); } } template inline box & box::move (const vector &p) { m_p1 += p; m_p2 += p; return *this; } template inline box & box::enlarge (const vector &p) { m_p1 -= p; m_p2 += p; return *this; } template inline const point & box::p1 () const { return m_p1; } template inline const point & box::p2 () const { return m_p2; } template inline const point & box::lower_left () const { return m_p1; } template inline const point & box::upper_right () const { return m_p2; } template inline point box::upper_left () const { return point (m_p1.x (), m_p2.y ()); } template inline point box::lower_right () const { return point (m_p2.x (), m_p1.y ()); } template inline bool box::is_point () const { return m_p1 == m_p2; } template inline void box::set_p1 (const point &_p1) { *this = box_type (_p1, p2 ()); } template inline void box::set_p2 (const point &_p2) { *this = box_type (p1 (), _p2); } template inline point box::center () const { return point (m_p1.x () + width () / 2, m_p1.y () + height () / 2); } template inline typename box::distance_type box::width () const { return m_p2.x () - m_p1.x (); } template inline typename box::distance_type box::height () const { return m_p2.y () - m_p1.y (); } template inline C box::left () const { return m_p1.x (); } template inline C box::right () const { return m_p2.x (); } template inline C box::top () const { return m_p2.y (); } template inline C box::bottom () const { return m_p1.y (); } template inline void box::set_left (C l) { if (empty ()) { *this = box (l, 0, l, 0); } else { *this = box (l, bottom (), std::max (right (), l), top ()); } } template inline void box::set_right (C r) { if (empty ()) { *this = box (r, 0, r, 0); } else { *this = box (std::min (left (), r), bottom (), r, top ()); } } template inline void box::set_bottom (C b) { if (empty ()) { *this = box (0, b, 0, b); } else { *this = box (left (), b, right (), std::max (top (), b)); } } template inline void box::set_top (C t) { if (empty ()) { *this = box (0, t, 0, t); } else { *this = box (left (), std::min (bottom (), t), right (), t); } } template inline bool box::empty () const { return m_p1.x () > m_p2.x () || m_p1.y () > m_p2.y (); } template inline bool box::contains (const point &p) const { if (empty ()) { return false; } else { return (m_p2.x () >= p.x () && m_p1.x () <= p.x ()) && (m_p2.y () >= p.y () && m_p1.y () <= p.y ()); } } template inline bool box::inside (const box &b) const { if (b.empty () || empty ()) { return false; } else { return (m_p1.x () >= b.m_p1.x () && m_p2.x () <= b.m_p2.x ()) && (m_p1.y () >= b.m_p1.y () && m_p2.y () <= b.m_p2.y ()); } } template inline bool box::touches (const box &b) const { if (b.empty () || empty ()) { return false; } else { return (m_p1.x () <= b.m_p2.x () && b.m_p1.x () <= m_p2.x ()) && (m_p1.y () <= b.m_p2.y () && b.m_p1.y () <= m_p2.y ()); } } template inline bool box::overlaps (const box &b) const { if (b.empty () || empty ()) { return false; } else { return (m_p1.x () < b.m_p2.x () && b.m_p1.x () < m_p2.x ()) && (m_p1.y () < b.m_p2.y () && b.m_p1.y () < m_p2.y ()); } } template inline typename box::area_type box::area () const { if (empty ()) { return area_type (0); } else { return area_type (height ()) * area_type (width ()); } } template inline typename box::perimeter_type box::perimeter () const { if (empty ()) { return perimeter_type (0); } else { return 2 * (perimeter_type (height ()) + perimeter_type (width ())); } } template inline double box::double_area () const { if (empty ()) { return 0.0; } else { return double (height ()) * double (width ()); } } /** * @brief The left side as a unary function */ template struct box_left : public std::unary_function { typename Box::coord_type operator() (const Box &b) const { return b.left (); } }; /** * @brief The right side as a unary function */ template struct box_right : public std::unary_function { typename Box::coord_type operator() (const Box &b) const { return b.right (); } }; /** * @brief The bottom side as a unary function */ template struct box_bottom : public std::unary_function { typename Box::coord_type operator() (const Box &b) const { return b.bottom (); } }; /** * @brief The top side as a unary function */ template struct box_top : public std::unary_function { typename Box::coord_type operator() (const Box &b) const { return b.top (); } }; /** * @brief "overlap" binary predicate */ template struct boxes_overlap : public std::binary_function { bool operator() (const Box &b1, const Box &b2) const { return b1.overlaps (b2); } }; /** * @brief "touch" binary predicate */ template struct boxes_touch : public std::binary_function { bool operator() (const Box &b1, const Box &b2) const { return b1.touches (b2); } }; /** * @brief Transformation with the * operator * * @param t Transformation to apply (first parameter) * @param b The box to transform (second parameter) * * @return The box b transformed by t. */ template inline box operator* (const Tr &t, const box &b) { return b.transformed (t); } /** * @brief Intersection mapped on the & operator. * * @param b1 The first box. * @param b2 The second box. * * @return The intersection of b1 and b2. */ template inline box operator& (const box &b1, const box &b2) { box bb (b1); bb &= b2; return bb; } /** * @brief Scaling of a box * * @param b The box to scale. * @param s The scaling factor * * @return The scaled box */ template inline box operator* (const box &b, double s) { if (b.empty ()) { return box (); } else { return box (b.p1 () * s, b.p2 () * s); } } /** * @brief Scaling of a box with some integer factor * * @param b The box to scale. * @param s The scaling factor * * @return The scaled box */ template inline box operator* (const box &b, long s) { if (b.empty ()) { return box (); } else { return box (b.p1 () * s, b.p2 () * s); } } /** * @brief Scaling of a box with some integer factor * * @param b The box to scale. * @param s The scaling factor * * @return The scaled box */ template inline box operator* (const box &b, int s) { if (b.empty ()) { return box (); } else { return box (b.p1 () * s, b.p2 () * s); } } /** * @brief Scaling of a box with some integer factor * * @param b The box to scale. * @param s The scaling factor * * @return The scaled box */ template inline box operator* (const box &b, unsigned int s) { if (b.empty ()) { return box (); } else { return box (b.p1 () * s, b.p2 () * s); } } /** * @brief Scaling of a box with some integer factor * * @param b The box to scale. * @param s The scaling factor * * @return The scaled box */ template inline box operator* (const box &b, unsigned long s) { if (b.empty ()) { return box (); } else { return box (b.p1 () * s, b.p2 () * s); } } /** * @brief Box joining mapped on the + operator. * * @param b1 The first box. * @param b2 The second box. * * @return b1 joined with b2. */ template inline box operator+ (const box &b1, const box &b2) { box bb (b1); bb += b2; return bb; } /** * @brief "Folding" of two boxes * * @param b1 The first box. * @param b2 The second box. * * @return b1 folded with b2 (see db::box::operator*= ()). */ template inline box operator* (const box &b1, const box &b2) { box bb (b1); bb *= b2; return bb; } /** * @brief Stream output operator */ template inline std::ostream & operator<< (std::ostream &os, const box &b) { return (os << b.to_string ()); } /** * @brief A helper inserter that adds a point to a box */ template class box_inserter { public: box_inserter (Box &box) : mp_box (&box) { // .. nothing yet .. } box_inserter &operator* () { return *this; } box_inserter &operator++ () { return *this; } box_inserter &operator++ (int) { return *this; } template box_inserter &operator= (const Point &p) { *mp_box += p; return *this; } private: Box *mp_box; }; /** * @brief The standard short integer coordinate box */ typedef box::short_coord_type> ShortBox; /** * @brief The standard integer coordinate box */ typedef box Box; /** * @brief The double coordinate box */ typedef box DBox; } // namespace db /** * @brief Special extractors for the boxes */ namespace tl { /** * @brief The type traits for the box type */ template struct type_traits > : public type_traits { typedef trivial_relocate_required relocate_requirements; typedef true_tag supports_extractor; typedef true_tag supports_to_string; typedef true_tag has_less_operator; typedef true_tag has_equal_operator; }; template<> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::Box &b); template<> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::DBox &b); template<> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::Box &b); template<> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::DBox &b); } // namespace tl #endif