532 lines
14 KiB
C++
532 lines
14 KiB
C++
/*
|
|
* 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& 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<VECTOR2I&>(m_points[index]),
|
|
const_cast<VECTOR2I&>(m_points[0]), index );
|
|
else
|
|
return SEG ( const_cast<VECTOR2I&>(m_points[index]),
|
|
const_cast<VECTOR2I&>(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<aOtherLine.PointCount(); i++)
|
|
{
|
|
const VECTOR2I p = aOtherLine.CPoint(i);
|
|
m_points.push_back(p);
|
|
m_bbox.Merge(p);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Function Replace()
|
|
*
|
|
* Replaces points with indices in range [start_index, end_index] with a single
|
|
* point aP.
|
|
* @param start_index start of the point range to be replaced (inclusive)
|
|
* @param end_index end of the point range to be replaced (inclusive)
|
|
* @param aP replacement point
|
|
*/
|
|
void Replace( int start_index, int end_index, const VECTOR2I& aP);
|
|
|
|
/**
|
|
* Function Replace()
|
|
*
|
|
* Replaces points with indices in range [start_index, end_index] with the points from line chain aLine.
|
|
* @param start_index start of the point range to be replaced (inclusive)
|
|
* @param end_index end of the point range to be replaced (inclusive)
|
|
* @param aLine replacement line chain.
|
|
*/
|
|
void Replace( int start_index, int end_index, const SHAPE_LINE_CHAIN& aLine);
|
|
|
|
/**
|
|
* Function Remove()
|
|
*
|
|
* Removes the range of points [start_index, end_index] from the line chain.
|
|
* @param start_index start of the point range to be replaced (inclusive)
|
|
* @param end_index end of the point range to be replaced (inclusive)
|
|
*/
|
|
void Remove( int start_index, int end_index);
|
|
|
|
/**
|
|
* 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 Slice()
|
|
*
|
|
* Returns a subset of this line chain containing the [start_index, end_index] range of points.
|
|
* @param start_index start of the point range to be returned (inclusive)
|
|
* @param end_index end of the point range to be returned (inclusive)
|
|
* @return cut line chain.
|
|
*/
|
|
const SHAPE_LINE_CHAIN Slice( int start_index, int end_index = -1) const;
|
|
|
|
|
|
struct compareOriginDistance {
|
|
compareOriginDistance( VECTOR2I& aOrigin ):
|
|
m_origin(aOrigin) {};
|
|
|
|
bool operator()(const Intersection &a, const Intersection& b)
|
|
{
|
|
return (m_origin - a.p).EuclideanNorm() < (m_origin - b.p).EuclideanNorm();
|
|
}
|
|
|
|
VECTOR2I m_origin;
|
|
};
|
|
|
|
|
|
/**
|
|
* 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;
|
|
|
|
/// @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<VECTOR2I> m_points;
|
|
/// is the line chain closed?
|
|
bool m_closed;
|
|
/// cached bounding box
|
|
BOX2I m_bbox;
|
|
};
|
|
|
|
#endif // __SHAPE_LINE_CHAIN
|