/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2013 CERN * @author Tomasz Wlostowski * * 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, you may find one here: * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * or you may search the http://www.gnu.org website for the version 2 license, * or you may write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __SHAPE_LINE_CHAIN #define __SHAPE_LINE_CHAIN #include #include #include #include #include #include /** * Class SHAPE_LINE_CHAIN * * Represents a polyline (an zero-thickness chain of connected line segments). * I purposedly didn't name it "polyline" to avoid confusion with the existing CPolyLine class in pcbnew. * * SHAPE_LINE_CHAIN class shall not be used for polygons! */ class SHAPE_LINE_CHAIN : public SHAPE { private: typedef std::vector::iterator point_iter; typedef std::vector::const_iterator point_citer; public: /** * Struct Intersection * * Represents an intersection between two line segments */ struct Intersection { /// segment belonging from the (this) argument of Intersect() SEG our; /// segment belonging from the aOther argument of Intersect() SEG their; /// point of intersection between our and their. VECTOR2I p; }; typedef std::vector Intersections; /** * Constructor * Initializes an empty line chain. */ SHAPE_LINE_CHAIN(): SHAPE (SH_LINE_CHAIN), m_closed(false) {}; /** * Copy Constructor */ SHAPE_LINE_CHAIN(const SHAPE_LINE_CHAIN& aShape): SHAPE (SH_LINE_CHAIN), m_points(aShape.m_points), m_closed(aShape.m_closed) {}; /** * Constructor * Initializes a 2-point line chain (a single segment) */ SHAPE_LINE_CHAIN(const VECTOR2I& a, const VECTOR2I& b): SHAPE (SH_LINE_CHAIN), m_closed(false) { m_points.resize(2); m_points[0] = a; m_points[1] = b; } SHAPE_LINE_CHAIN(const VECTOR2I& a, const VECTOR2I& b, const VECTOR2I& c): SHAPE (SH_LINE_CHAIN), m_closed(false) { m_points.resize(3); m_points[0] = a; m_points[1] = b; m_points[2] = c; } SHAPE_LINE_CHAIN(const VECTOR2I *v, int count): SHAPE (SH_LINE_CHAIN), m_closed(false) { m_points.resize(count); for(int i = 0; i < count ; i++) m_points[i] = *v++; } ~SHAPE_LINE_CHAIN() {}; /** * Function Clear() * Removes all points from the line chain. */ void Clear() { m_points.clear(); m_closed = false; } /** * Function SetClosed() * * Marks the line chain as closed (i.e. with a segment connecting the last point with the first point). * @param aClosed: whether the line chain is to be closed or not. */ void SetClosed(bool aClosed) { m_closed = aClosed; } /** * Function IsClosed() * * @return aClosed: true, when our line is closed. */ bool IsClosed() const { return m_closed; } /** * Function SegmentCount() * * Returns number of segments in this line chain. * @return number of segments */ int SegmentCount() const { int c = m_points.size() - 1; if(m_closed) c++; return std::max(0, c); } /** * Function PointCount() * * Returns the number of points (vertices) in this line chain * @return number of points */ int PointCount() const { return m_points.size(); }; /** * Function Segment() * * Returns a segment referencing to the segment (index) in the line chain. * Modifying ends of the returned segment will modify corresponding points in the line chain. * @param index: index of the segment in the line chain. Negative values are counted from the end (i.e. -1 means * the last segment in the line chain) * @return SEG referenced to given segment in the line chain */ SEG Segment ( int index ) { if(index < 0) index += SegmentCount(); if(index == (m_points.size() - 1) && m_closed ) return SEG ( m_points[index], m_points[0], index ); else return SEG ( m_points[index], m_points[index + 1], index ); } /** * Function CSegment() * * Returns a read-only segment referencing to the segment (index) in the line chain. * @param index: index of the segment in the line chain. Negative values are counted from the end (i.e. -1 means * the last segment in the line chain) * @return SEG referenced to given segment in the line chain */ const SEG CSegment ( int index ) const { if(index < 0) index += SegmentCount(); if(index == (m_points.size() - 1) && m_closed ) return SEG ( const_cast(m_points[index]), const_cast(m_points[0]), index ); else return SEG ( const_cast(m_points[index]), const_cast(m_points[index + 1]), index ); } /** * Function Point() * * Returns a reference to a given point in the line chain. * @param index index of the point * @return reference to the point */ VECTOR2I& Point ( int index ) { if(index < 0) index += PointCount(); return m_points[index]; } /** * Function CPoint() * * Returns a const reference to a given point in the line chain. * @param index index of the point * @return const reference to the point */ const VECTOR2I& CPoint ( int index ) const { if(index < 0) index += PointCount(); return m_points[index]; } /// @copydoc SHAPE::BBox() const BOX2I BBox ( int aClearance = 0 ) const { BOX2I bbox; bbox.Compute(m_points); return bbox; } /** * Function Collide() * * Checks if point aP lies closer to us than aClearance. * @param aP the point to check for collisions with * @param aClearance minimum distance that does not qualify as a collision. * @return true, when a collision has been found */ bool Collide ( const VECTOR2I& aP, int aClearance = 0 ) const; /** * Function Collide() * * Checks if box aBox lies closer to us than aClearance. * @param aP the box to check for collisions with * @param aClearance minimum distance that does not qualify as a collision. * @return true, when a collision has been found */ bool Collide ( const BOX2I& aBox, int aClearance = 0 ) const; /** * Function Collide() * * Checks if segment aSeg lies closer to us than aClearance. * @param aSeg the segment to check for collisions with * @param aClearance minimum distance that does not qualify as a collision. * @return true, when a collision has been found */ bool Collide ( const SEG& aSeg, int aClearance = 0 ) const; /** * Function Distance() * * Computes the minimum distance between the line chain and a point aP. * @param aP the point * @return minimum distance. */ int Distance( const VECTOR2I & aP ) const; /** * Function Reverse() * * Reverses point order in the line chain. * @return line chain with reversed point order (original A-B-C-D: returned D-C-B-A) */ const SHAPE_LINE_CHAIN Reverse() const; /** * Function Length() * * Returns length of the line chain in Euclidean metric. * @return length of the line chain */ int Length() const; /** * Function Append() * * Appends a new point at the end of the line chain. * @param x X coordinate of the new point * @param y Y coordinate of the new point */ void Append(int x, int y) { VECTOR2I v(x, y); Append(v); } /** * Function Append() * * Appends a new point at the end of the line chain. * @param aP the new point */ void Append(const VECTOR2I& aP) { if(m_points.size() == 0) m_bbox = BOX2I(aP, VECTOR2I(0, 0)); if (m_points.size() == 0 || CPoint(-1) != aP) { m_points.push_back(aP); m_bbox.Merge(aP); } } /** * Function Append() * * Appends another line chain at the end. * @param aOtherLine the line chain to be appended. */ void Append(const SHAPE_LINE_CHAIN& aOtherLine) { if(aOtherLine.PointCount() == 0) return; else if(PointCount() == 0 || aOtherLine.CPoint(0) != CPoint(-1)) { const VECTOR2I p = aOtherLine.CPoint(0); m_points.push_back(p); m_bbox.Merge(p); } for(int i = 1; i SelfIntersecting() const; /** * Function Simplify() * * Simplifies the line chain by removing colinear adjacent segments and duplicate vertices. * @return reference to self. */ SHAPE_LINE_CHAIN& Simplify(); /** * Function NearestPoint() * * Finds a point on the line chain that is closest to point aP. * @return the nearest point. */ const VECTOR2I NearestPoint(const VECTOR2I& aP) const; /// @copydoc SHAPE::Format() const std::string Format() const; bool operator!=(const SHAPE_LINE_CHAIN& rhs) const { if(PointCount() != rhs.PointCount()) return true; for(int i = 0; i < PointCount(); i++) if( CPoint(i) != rhs.CPoint(i) ) return true; return false; } private: /// array of vertices std::vector m_points; /// is the line chain closed? bool m_closed; /// cached bounding box BOX2I m_bbox; }; #endif // __SHAPE_LINE_CHAIN