summaryrefslogtreecommitdiff
path: root/include/geometry/shape_line_chain.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/geometry/shape_line_chain.h')
-rw-r--r--include/geometry/shape_line_chain.h598
1 files changed, 598 insertions, 0 deletions
diff --git a/include/geometry/shape_line_chain.h b/include/geometry/shape_line_chain.h
new file mode 100644
index 0000000..ae2bf5e
--- /dev/null
+++ b/include/geometry/shape_line_chain.h
@@ -0,0 +1,598 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2013 CERN
+ * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
+ *
+ * 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 <vector>
+#include <sstream>
+
+#include <boost/optional.hpp>
+
+#include <math/vector2d.h>
+#include <geometry/shape.h>
+#include <geometry/seg.h>
+
+/**
+ * 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<VECTOR2I>::iterator point_iter;
+ typedef std::vector<VECTOR2I>::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<INTERSECTION> 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& aA, const VECTOR2I& aB ) :
+ SHAPE( SH_LINE_CHAIN ), m_closed( false )
+ {
+ m_points.resize( 2 );
+ m_points[0] = aA;
+ m_points[1] = aB;
+ }
+
+ SHAPE_LINE_CHAIN( const VECTOR2I& aA, const VECTOR2I& aB, const VECTOR2I& aC ) :
+ SHAPE( SH_LINE_CHAIN ), m_closed( false )
+ {
+ m_points.resize( 3 );
+ m_points[0] = aA;
+ m_points[1] = aB;
+ m_points[2] = aC;
+ }
+
+ SHAPE_LINE_CHAIN( const VECTOR2I& aA, const VECTOR2I& aB, const VECTOR2I& aC, const VECTOR2I& aD ) :
+ SHAPE( SH_LINE_CHAIN ), m_closed( false )
+ {
+ m_points.resize( 4 );
+ m_points[0] = aA;
+ m_points[1] = aB;
+ m_points[2] = aC;
+ m_points[3] = aD;
+ }
+
+
+ SHAPE_LINE_CHAIN( const VECTOR2I* aV, int aCount ) :
+ SHAPE( SH_LINE_CHAIN ),
+ m_closed( false )
+ {
+ m_points.resize( aCount );
+
+ for( int i = 0; i < aCount; i++ )
+ m_points[i] = *aV++;
+ }
+
+ ~SHAPE_LINE_CHAIN()
+ {}
+
+ SHAPE* Clone() const;
+
+ /**
+ * 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 aIndex: 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 aIndex )
+ {
+ if( aIndex < 0 )
+ aIndex += SegmentCount();
+
+ if( aIndex == (int)( m_points.size() - 1 ) && m_closed )
+ return SEG( m_points[aIndex], m_points[0], aIndex );
+ else
+ return SEG( m_points[aIndex], m_points[aIndex + 1], aIndex );
+ }
+
+ /**
+ * Function CSegment()
+ *
+ * Returns a read-only segment referencing to the segment (index) in the line chain.
+ * @param aIndex: 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 aIndex ) const
+ {
+ if( aIndex < 0 )
+ aIndex += SegmentCount();
+
+ if( aIndex == (int)( m_points.size() - 1 ) && m_closed )
+ return SEG( const_cast<VECTOR2I&>( m_points[aIndex] ),
+ const_cast<VECTOR2I&>( m_points[0] ), aIndex );
+ else
+ return SEG( const_cast<VECTOR2I&>( m_points[aIndex] ),
+ const_cast<VECTOR2I&>( m_points[aIndex + 1] ), aIndex );
+ }
+
+ /**
+ * Function Point()
+ *
+ * Returns a reference to a given point in the line chain.
+ * @param aIndex index of the point
+ * @return reference to the point
+ */
+ VECTOR2I& Point( int aIndex )
+ {
+ if( aIndex < 0 )
+ aIndex += PointCount();
+
+ return m_points[aIndex];
+ }
+
+ /**
+ * Function CPoint()
+ *
+ * Returns a const reference to a given point in the line chain.
+ * @param aIndex index of the point
+ * @return const reference to the point
+ */
+ const VECTOR2I& CPoint( int aIndex ) const
+ {
+ if( aIndex < 0 )
+ aIndex += PointCount();
+ else if( aIndex >= PointCount() )
+ aIndex -= PointCount();
+
+ return m_points[aIndex];
+ }
+
+ /// @copydoc SHAPE::BBox()
+ const BOX2I BBox( int aClearance = 0 ) const
+ {
+ BOX2I bbox;
+ bbox.Compute( m_points );
+
+ if( aClearance != 0 )
+ bbox.Inflate( aClearance );
+
+ 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 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 aX is X coordinate of the new point
+ * @param aY is Y coordinate of the new point
+ */
+ void Append( int aX, int aY, bool aAllowDuplication = false )
+ {
+ VECTOR2I v( aX, aY );
+ Append( v, aAllowDuplication );
+ }
+
+ /**
+ * Function Append()
+ *
+ * Appends a new point at the end of the line chain.
+ * @param aP the new point
+ */
+ void Append( const VECTOR2I& aP, bool aAllowDuplication = false )
+ {
+ if( m_points.size() == 0 )
+ m_bbox = BOX2I( aP, VECTOR2I( 0, 0 ) );
+
+ if( m_points.size() == 0 || aAllowDuplication || 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 < aOtherLine.PointCount(); i++ )
+ {
+ const VECTOR2I p = aOtherLine.CPoint( i );
+ m_points.push_back( p );
+ m_bbox.Merge( p );
+ }
+ }
+
+ void Insert( int aVertex, const VECTOR2I& aP )
+ {
+ m_points.insert( m_points.begin() + aVertex, aP );
+ }
+
+ /**
+ * Function Replace()
+ *
+ * Replaces points with indices in range [start_index, end_index] with a single
+ * point aP.
+ * @param aStartIndex start of the point range to be replaced (inclusive)
+ * @param aEndIndex end of the point range to be replaced (inclusive)
+ * @param aP replacement point
+ */
+ void Replace( int aStartIndex, int aEndIndex, const VECTOR2I& aP );
+
+ /**
+ * Function Replace()
+ *
+ * Replaces points with indices in range [start_index, end_index] with the points from
+ * line chain aLine.
+ * @param aStartIndex start of the point range to be replaced (inclusive)
+ * @param aEndIndex end of the point range to be replaced (inclusive)
+ * @param aLine replacement line chain.
+ */
+ void Replace( int aStartIndex, int aEndIndex, const SHAPE_LINE_CHAIN& aLine );
+
+ /**
+ * Function Remove()
+ *
+ * Removes the range of points [start_index, end_index] from the line chain.
+ * @param aStartIndex start of the point range to be replaced (inclusive)
+ * @param aEndIndex end of the point range to be replaced (inclusive)
+ */
+ void Remove( int aStartIndex, int aEndIndex );
+
+ /**
+ * Function Split()
+ *
+ * Inserts the point aP belonging to one of the our segments, splitting the adjacent
+ * segment in two.
+ * @param aP the point to be inserted
+ * @return index of the newly inserted point (or a negative value if aP does not lie on
+ * our line)
+ */
+ int Split( const VECTOR2I& aP );
+
+ /**
+ * Function Find()
+ *
+ * Searches for point aP.
+ * @param aP the point to be looked for
+ * @return index of the correspoinding point in the line chain or negative when not found.
+ */
+ int Find( const VECTOR2I& aP ) const;
+
+ /**
+ * Function FindSegment()
+ *
+ * Searches for segment containing point aP.
+ * @param aP the point to be looked for
+ * @return index of the correspoinding segment in the line chain or negative when not found.
+ */
+ int FindSegment( const VECTOR2I& aP ) const;
+
+ /**
+ * Function Slice()
+ *
+ * Returns a subset of this line chain containing the [start_index, end_index] range of points.
+ * @param aStartIndex start of the point range to be returned (inclusive)
+ * @param aEndIndex end of the point range to be returned (inclusive)
+ * @return cut line chain.
+ */
+ const SHAPE_LINE_CHAIN Slice( int aStartIndex, int aEndIndex = -1 ) const;
+
+ struct compareOriginDistance
+ {
+ compareOriginDistance( const VECTOR2I& aOrigin ):
+ m_origin( aOrigin )
+ {}
+
+ bool operator()( const INTERSECTION& aA, const INTERSECTION& aB )
+ {
+ return ( m_origin - aA.p ).EuclideanNorm() < ( m_origin - aB.p ).EuclideanNorm();
+ }
+
+ VECTOR2I m_origin;
+ };
+
+ bool Intersects( const SHAPE_LINE_CHAIN& aChain ) const;
+
+ /**
+ * Function Intersect()
+ *
+ * Finds all intersection points between our line chain and the segment aSeg.
+ * @param aSeg the segment chain to find intersections with
+ * @param aIp reference to a vector to store found intersections. Intersection points
+ * are sorted with increasing distances from point aSeg.a.
+ * @return number of intersections found
+ */
+ int Intersect( const SEG& aSeg, INTERSECTIONS& aIp ) const;
+
+ /**
+ * Function Intersect()
+ *
+ * Finds all intersection points between our line chain and the line chain aChain.
+ * @param aChain the line chain to find intersections with
+ * @param aIp reference to a vector to store found intersections. Intersection points
+ * are sorted with increasing path lengths from the starting point of aChain.
+ * @return number of intersections found
+ */
+ int Intersect( const SHAPE_LINE_CHAIN& aChain, INTERSECTIONS& aIp ) const;
+
+ /**
+ * Function PathLength()
+ *
+ * Computes the walk path length from the beginning of the line chain and
+ * the point aP belonging to our line.
+ * @return: path length in Euclidean metric or negative if aP does not belong to
+ * the line chain.
+ */
+ int PathLength( const VECTOR2I& aP ) const;
+
+ /**
+ * Function PointInside()
+ *
+ * Checks if point aP lies inside a convex polygon defined by the line chain. For closed
+ * shapes only.
+ * @param aP point to check
+ * @return true if the point is inside the shape (edge is not treated as being inside).
+ */
+ bool PointInside( const VECTOR2I& aP ) const;
+
+ /**
+ * Function PointOnEdge()
+ *
+ * Checks if point aP lies on an edge or vertex of the line chain.
+ * @param aP point to check
+ * @return true if the point lies on the edge.
+ */
+ bool PointOnEdge( const VECTOR2I& aP ) const;
+
+ /**
+ * Function SelfIntersecting()
+ *
+ * Checks if the line chain is self-intersecting.
+ * @return (optional) first found self-intersection point.
+ */
+ const boost::optional<INTERSECTION> 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;
+
+ /**
+ * Function NearestPoint()
+ *
+ * Finds a point on the line chain that is closest to the line defined
+ * by the points of segment aSeg, also returns the distance.
+ * @param aSeg Segment defining the line.
+ * @param dist reference receiving the distance to the nearest point.
+ * @return the nearest point.
+ */
+ const VECTOR2I NearestPoint( const SEG& aSeg, int& dist ) const;
+
+ /// @copydoc SHAPE::Format()
+ const std::string Format() const;
+
+ /// @copydoc SHAPE::Parse()
+ bool Parse( std::stringstream& aStream );
+
+ bool operator!=( const SHAPE_LINE_CHAIN& aRhs ) const
+ {
+ if( PointCount() != aRhs.PointCount() )
+ return true;
+
+ for( int i = 0; i < PointCount(); i++ )
+ {
+ if( CPoint( i ) != aRhs.CPoint( i ) )
+ return true;
+ }
+
+ return false;
+ }
+
+ bool CompareGeometry( const SHAPE_LINE_CHAIN & aOther ) const;
+
+ void Move( const VECTOR2I& aVector )
+ {
+ for( std::vector<VECTOR2I>::iterator i = m_points.begin(); i != m_points.end(); ++i )
+ (*i) += aVector;
+ }
+
+ bool IsSolid() const
+ {
+ return false;
+ }
+
+private:
+ /// array of vertices
+ std::vector<VECTOR2I> m_points;
+
+ /// is the line chain closed?
+ bool m_closed;
+
+ /// cached bounding box
+ BOX2I m_bbox;
+};
+
+#endif // __SHAPE_LINE_CHAIN