33#include <clipper2/clipper.h>
50 for(
size_t i = 0; i < aV.size(); i+= 2 )
58 const std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
59 const std::vector<SHAPE_ARC>& aArcBuffer ) :
61 m_closed( true ), m_width( 0 )
63 std::map<ssize_t, ssize_t> loadedArcs;
68 [&]( ssize_t aArcIndex ) -> ssize_t
74 else if( loadedArcs.count( aArcIndex ) == 0 )
76 loadedArcs.insert( { aArcIndex,
m_arcs.size() } );
77 m_arcs.push_back( aArcBuffer.at( aArcIndex ) );
80 return loadedArcs.at( aArcIndex );
83 for(
size_t ii = 0; ii < aPath.size(); ++ii )
85 Append( aPath[ii].
X, aPath[ii].Y );
87 m_shapes[ii].first = loadArc( aZValueBuffer[aPath[ii].Z].m_FirstArcIdx );
88 m_shapes[ii].second = loadArc( aZValueBuffer[aPath[ii].Z].m_SecondArcIdx );
102 const std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
103 const std::vector<SHAPE_ARC>& aArcBuffer ) :
105 m_closed( true ), m_width( 0 )
107 std::map<ssize_t, ssize_t> loadedArcs;
112 [&]( ssize_t aArcIndex ) -> ssize_t
118 else if( loadedArcs.count( aArcIndex ) == 0 )
120 loadedArcs.insert( { aArcIndex,
m_arcs.size() } );
121 m_arcs.push_back( aArcBuffer.at( aArcIndex ) );
124 return loadedArcs.at( aArcIndex );
127 for(
size_t ii = 0; ii < aPath.size(); ++ii )
129 Append( aPath[ii].x, aPath[ii].y );
131 m_shapes[ii].first = loadArc( aZValueBuffer[aPath[ii].z].m_FirstArcIdx );
132 m_shapes[ii].second = loadArc( aZValueBuffer[aPath[ii].z].m_SecondArcIdx );
146 std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
147 std::vector<SHAPE_ARC>& aArcBuffer )
const
149 ClipperLib::Path c_path;
151 bool orientation =
Area(
false ) >= 0;
152 ssize_t shape_offset = aArcBuffer.size();
154 if( orientation != aRequiredOrientation )
160 c_path.reserve( pointCount );
162 for(
int i = 0; i < pointCount; i++ )
167 size_t z_value_ptr = aZValueBuffer.size();
168 aZValueBuffer.push_back( z_value );
170 c_path.emplace_back( vertex.
x, vertex.
y, z_value_ptr );
173 aArcBuffer.insert( aArcBuffer.end(), input.
m_arcs.begin(), input.
m_arcs.end() );
180 std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
181 std::vector<SHAPE_ARC>& aArcBuffer )
const
183 Clipper2Lib::Path64 c_path;
185 bool orientation =
Area(
false ) >= 0;
186 ssize_t shape_offset = aArcBuffer.size();
188 if( orientation != aRequiredOrientation )
194 c_path.reserve( pointCount );
196 for(
int i = 0; i < pointCount; i++ )
201 size_t z_value_ptr = aZValueBuffer.size();
202 aZValueBuffer.push_back( z_value );
204 c_path.emplace_back( vertex.
x, vertex.
y, z_value_ptr );
207 aArcBuffer.insert( aArcBuffer.end(), input.
m_arcs.begin(), input.
m_arcs.end() );
220 size_t rotations = 0;
261 aArcIndex +=
m_arcs.size();
263 if( aArcIndex >=
static_cast<ssize_t
>(
m_arcs.size() ) )
270 [&]( ssize_t& aShapeIndex )
272 if( aShapeIndex == aArcIndex )
275 if( aShapeIndex > aArcIndex )
280 std::swap( sh.first, sh.second );
290 wxCHECK_MSG( aArcIndex <
m_arcs.size(), ,
291 wxT(
"Invalid arc index requested." ) );
300 m_arcs[aArcIndex] = newArc;
315 wxCHECK_MSG( aPtIndex <
static_cast<ssize_t
>(
m_shapes.size() ), ,
316 wxT(
"Invalid point index requested." ) );
320 if( aCoincident || aPtIndex == 0 )
323 ssize_t firstArcIndex =
m_shapes[aPtIndex].first;
327 amendArc( firstArcIndex, newStart, newEnd );
342 ssize_t currArcIdx =
ArcIndex( aPtIndex );
357 if( !aCoincident &&
ArcIndex( aPtIndex - 1 ) != currArcIdx )
360 m_arcs[currArcIdx] = newArc2;
364 m_arcs[currArcIdx] = newArc1;
365 m_arcs.insert(
m_arcs.begin() + currArcIdx + 1, newArc2 );
369 m_shapes[aPtIndex].second = currArcIdx + 1;
374 for(
int i = aPtIndex; i <
PointCount(); i++ )
407 SEG::ecoord dist_sq = ( pn - aP ).SquaredEuclideanNorm();
409 if( dist_sq < closest_dist_sq )
412 closest_dist_sq = dist_sq;
414 if( closest_dist_sq == 0 )
418 if( closest_dist_sq < clearance_sq && !aActual )
423 if( closest_dist_sq == 0 || closest_dist_sq < clearance_sq )
426 *aLocation = nearest;
429 *aActual = sqrt( closest_dist_sq );
464 SEG::ecoord dist_sq = ( pn - aP ).SquaredEuclideanNorm();
466 if( dist_sq < closest_dist_sq )
469 closest_dist_sq = dist_sq;
471 if( closest_dist_sq == 0 )
475 if( closest_dist_sq < clearance_sq && !aActual )
480 if( closest_dist_sq == 0 || closest_dist_sq < clearance_sq )
483 *aLocation = nearest;
486 *aActual = sqrt( closest_dist_sq );
492 for(
size_t i = 0; i <
ArcCount(); i++ )
497 wxASSERT_MSG( arc.
GetWidth() == 0, wxT(
"Invalid arc width - should be zero" ) );
499 if( arc.
Collide( aP, aClearance, aActual, aLocation ) )
513 arc.Rotate( aAngle, aCenter );
540 if( dist_sq < closest_dist_sq )
545 closest_dist_sq = dist_sq;
547 if( closest_dist_sq == 0)
551 if( closest_dist_sq < clearance_sq && !aActual )
556 if( closest_dist_sq == 0 || closest_dist_sq < clearance_sq )
559 *aLocation = nearest;
562 *aActual = sqrt( closest_dist_sq );
598 if( dist_sq < closest_dist_sq )
603 closest_dist_sq = dist_sq;
605 if( closest_dist_sq == 0 )
609 if( closest_dist_sq < clearance_sq && !aActual )
614 if( closest_dist_sq == 0 || closest_dist_sq < clearance_sq )
617 *aLocation = nearest;
620 *aActual = sqrt( closest_dist_sq );
626 for(
size_t i = 0; i <
ArcCount(); i++ )
631 wxASSERT_MSG( arc.
GetWidth() == 0, wxT(
"Invalid arc width - should be zero" ) );
633 if( arc.
Collide( aSeg, aClearance, aActual, aLocation ) )
654 [&]( ssize_t& aShapeIndex )
657 aShapeIndex = a.
m_arcs.size() - aShapeIndex - 1;
666 std::swap( sh.first, sh.second );
682 for( ssize_t arcIndex =
m_arcs.size() - 1; arcIndex >= 0; --arcIndex )
698 for(
size_t i = 0; i <
ArcCount(); i++ )
699 l +=
CArcs()[i].GetLength();
710 pt.x = -pt.x + 2 * aRef.
x;
713 pt.y = -pt.y + 2 * aRef.
y;
717 arc.Mirror( aX, aY, aRef );
733 Remove( aStartIndex, aEndIndex );
734 Insert( aStartIndex, aP );
744 if( aStartIndex < 0 )
748 wxASSERT( aStartIndex <= aEndIndex );
749 wxASSERT( aEndIndex <
static_cast<int>(
m_points.size() ) );
756 Remove( aStartIndex, aEndIndex );
769 Remove( aStartIndex, aEndIndex );
780 Remove( aStartIndex, aEndIndex );
787 size_t prev_arc_count =
m_arcs.size();
788 std::vector<std::pair<ssize_t, ssize_t>> new_shapes = newLine.
m_shapes;
790 for( std::pair<ssize_t, ssize_t>& shape_pair : new_shapes )
793 [&]( ssize_t& aShape )
796 aShape += prev_arc_count;
800 m_shapes.insert(
m_shapes.begin() + aStartIndex, new_shapes.begin(), new_shapes.end() );
816 if( aStartIndex < 0 )
822 aEndIndex = std::min( aEndIndex,
PointCount() - 1 );
828 size_t nextIndex =
static_cast<size_t>( aEndIndex ) + 1;
833 std::set<size_t> extra_arcs;
834 auto logArcIdxRemoval = [&]( ssize_t& aShapeIndex )
837 extra_arcs.insert( aShapeIndex );
841 for(
int i = aStartIndex; i <= aEndIndex; i++ )
845 if( i == aStartIndex )
847 logArcIdxRemoval(
m_shapes[i].second );
854 else if( i == aEndIndex )
856 logArcIdxRemoval(
m_shapes[i].first );
859 assert( i > aStartIndex ||
IsSharedPt( i - 1 )
869 for(
auto arc : extra_arcs )
903 int found_index =
Find( aP );
912 if( dist < min_dist && seg.
A != aP && seg.
B != aP )
915 if( found_index < 0 )
917 else if( s < found_index )
931 size_t newIndex =
static_cast<size_t>( ii ) + 1;
955 if( aThreshold == 0 )
962 if( (
CPoint( s ) - aP).EuclideanNorm() <= aThreshold )
988 int numPoints =
static_cast<int>(
m_shapes.size() );
992 for(
int i = 0; i < static_cast<int>(
m_points.size() ) - 1; i++ )
1016 while( i < numPoints &&
m_shapes[i].first == arcIdx )
1035 if( aPointIndex < 0 )
1041 if( ( aForwards && aPointIndex == lastIndex ) ||
1042 ( !aForwards && aPointIndex == 0 ) )
1047 int delta = aForwards ? 1 : -1;
1050 return aPointIndex +
delta;
1052 int arcStart = aPointIndex;
1059 auto arcIndex = [&](
int aIndex ) -> ssize_t
1067 ssize_t currentArcIdx = arcIndex( aPointIndex );
1070 while( aPointIndex < lastIndex && aPointIndex >= 0 && arcIndex( aPointIndex ) == currentArcIdx )
1071 aPointIndex +=
delta;
1073 if( aPointIndex == lastIndex )
1075 if( !
m_closed && arcIndex( aPointIndex ) == currentArcIdx )
1085 if( aPointIndex - arcStart > 1 && !indexStillOnArc )
1086 aPointIndex -=
delta;
1102 [&]( ssize_t& aIdx )
1112 if( aPointIndex < 0 )
1122 int start = aPointIndex;
1123 int end = aPointIndex;
1124 int arcIdx =
ArcIndex( aPointIndex );
1129 while( start >= 0 &&
m_shapes[start].first == arcIdx )
1133 if( start >= 1 &&
m_shapes[
static_cast<ssize_t
>( start ) - 1].second == arcIdx )
1139 while( end <
static_cast<int>(
m_shapes.size() ) - 1 &&
m_shapes[end].first == arcIdx )
1153 if( aStartIndex < 0 )
1156 int numPoints =
static_cast<int>(
m_points.size() );
1162 ssize_t arcToSplitIndex =
ArcIndex( aStartIndex );
1166 for(
size_t i = aStartIndex; arcToSplitIndex ==
ArcIndex( i ); i++ )
1183 rv.
m_arcs.push_back( newArc );
1188 for(
int i = aStartIndex; i <= aEndIndex && i < numPoints; i =
NextShape( i ) )
1196 bool isLastShape = nextShape < 0;
1198 if( ( isLastShape && aEndIndex != ( numPoints - 1 ) )
1199 || ( nextShape > aEndIndex ) )
1201 if( i == aEndIndex )
1213 for( ; i <= aEndIndex && i < numPoints; i++ )
1233 rv.
m_arcs.push_back( newArc );
1250 wxT(
"Still on an arc segment, we missed something..." ) );
1269 size_t num_arcs =
m_arcs.size();
1272 auto fixShapeIndices =
1273 [&](
const std::pair<ssize_t, ssize_t>& aShapeIndices ) -> std::pair<ssize_t, ssize_t>
1275 std::pair<ssize_t, ssize_t> retval = aShapeIndices;
1280 aIndex = aIndex + num_arcs;
1303 for(
int i = 1; i < aOtherLine.
PointCount(); i++ )
1308 ssize_t arcIndex = aOtherLine.
ArcIndex( i );
1347 chain.
m_arcs.push_back( aArc );
1348 chain.
m_arcs.back().SetWidth( 0 );
1368 wxCHECK( aVertex <
m_points.size(), );
1370 if( aVertex > 0 &&
IsPtOnArc( aVertex ) )
1383 wxCHECK( aVertex <
m_points.size(), );
1385 if( aVertex > 0 &&
IsPtOnArc( aVertex ) )
1389 ssize_t arc_pos =
m_arcs.size();
1391 for(
auto arc_it =
m_shapes.rbegin() ;
1392 arc_it !=
m_shapes.rend() + aVertex;
1397 arc_pos = std::max( ( *arc_it ).first, ( *arc_it ).second );
1406 [&]( ssize_t& aIndex )
1408 if( aIndex >= arc_pos )
1420 m_points.insert(
m_points.begin() + aVertex, chain.CPoints().begin(), chain.CPoints().end() );
1424 std::vector<std::pair<ssize_t, ssize_t>> new_points( chain.PointCount(),
1425 { arc_pos, SHAPE_IS_PT } );
1427 m_shapes.insert(
m_shapes.begin() + aVertex, new_points.begin(), new_points.end() );
1461 aIp.push_back( is );
1466 sort( aIp.begin(), aIp.end(), comp );
1475 if( aIps.size() == 0 )
1477 aIps.push_back( aP );
1481 aIps.push_back( aP );
1486 bool aExcludeColinearAndTouching,
BOX2I* aChainBBox )
const
1488 BOX2I bb_other = aChainBBox ? *aChainBBox : aChain.
BBox();
1493 const BOX2I bb_cur( a.
A, a.
B - a.
A );
1513 if( coll && ! aExcludeColinearAndTouching )
1589 bool indexMatch =
true;
1599 indexMatch = ( i == aIndex );
1617 bool aUseBBoxCache )
const
1629 bool inside =
false;
1644 for(
int i = 0; i < pointCount; )
1647 const auto p2 =
GetPoint( i == pointCount ? 0 : i );
1648 const auto diff = p2 - p1;
1652 const int d =
rescale( diff.x, ( aPt.
y - p1.y ), diff.y );
1654 if( ( ( p1.y > aPt.
y ) != ( p2.y > aPt.
y ) ) && ( aPt.
x - p1.x < d ) )
1661 if( aAccuracy <= 1 )
1683 return ( hypot( dist.
x, dist.
y ) <= aAccuracy + 1 ) ? 0 : -1;
1690 if( s.
A == aPt || s.
B == aPt )
1693 if( s.
Distance( aPt ) <= aAccuracy + 1 )
1712 if( s.
A == aP || s.
B == aP )
1731 if( s1 + 1 != s2 &&
CSegment( s1 ).Contains( s2a ) )
1739 else if(
CSegment( s1 ).Contains( s2b ) &&
1767 return std::optional<SHAPE_LINE_CHAIN::INTERSECTION>();
1773 std::vector<VECTOR2I> pts_unique;
1774 std::vector<std::pair<ssize_t, ssize_t>> shapes_unique;
1807 std::pair<ssize_t,ssize_t> shapeToKeep =
m_shapes[i];
1812 assert( shapeToKeep.first <
static_cast<int>(
m_arcs.size() ) );
1813 assert( shapeToKeep.second <
static_cast<int>(
m_arcs.size() ) );
1815 pts_unique.push_back(
CPoint( i ) );
1816 shapes_unique.push_back( shapeToKeep );
1823 np = pts_unique.size();
1837 && (
SEG( p0, pts_unique[n + 2] ).LineDistance( pts_unique[n + 1] ) <= 1
1838 ||
SEG( p0, pts_unique[n + 2] ).Collinear(
SEG( p0, pts_unique[n + 1] ) ) ) )
1843 m_shapes.push_back( shapes_unique[i] );
1850 m_points.push_back( pts_unique[np - 1] );
1851 m_shapes.push_back( shapes_unique[np - 1] );
1860 m_points.push_back( pts_unique[np - 2] );
1861 m_shapes.push_back( shapes_unique[np - 2] );
1864 m_points.push_back( pts_unique[np - 1] );
1865 m_shapes.push_back( shapes_unique[np - 1] );
1874 bool aAllowInternalShapePoints )
const
1882 int min_d = std::numeric_limits<int>::max();
1896 if( !aAllowInternalShapePoints )
1919 return nearestArc.
GetP1();
1921 return nearestArc.
GetP0();
1941 dist = std::numeric_limits<int>::max();
1954 return CPoint( nearest );
1960 int min_d = std::numeric_limits<int>::max();
1980 std::stringstream ss;
1982 ss <<
"SHAPE_LINE_CHAIN( { ";
1992 ss <<
"}, " << (
m_closed ?
"true" :
"false" );
2013 if( a.m_points.size() != b.
m_points.size() )
2016 for(
int i = 0; i < a.PointCount(); i++ )
2018 if( a.CPoint( i ) != b.
CPoint( i ) )
2048 if( n_pts > aStream.str().size() )
2054 if( n_arcs > aStream.str().size() )
2057 for(
size_t i = 0; i < n_pts; i++ )
2069 for(
size_t i = 0; i < n_arcs; i++ )
2091 if( aPathLength == 0 )
2099 if( total + l >= aPathLength )
2102 return s.
A + d.
Resize( aPathLength - total );
2122 for(
int i = 0, j = size - 1; i < size; ++i )
2130 return std::fabs( area * 0.5 );
2138 m_finished( false ),
2148 if( ipNext.
y == m_point.y )
2150 if( ( ipNext.
x == m_point.x )
2151 || ( ip.
y == m_point.y && ( ( ipNext.
x > m_point.x ) == ( ip.
x < m_point.x ) ) ) )
2159 if( ( ip.
y < m_point.y ) != ( ipNext.
y < m_point.y ) )
2161 if( ip.
x >= m_point.x )
2163 if( ipNext.
x > m_point.x )
2165 m_state = 1 - m_state;
2169 double d = (double) ( ip.
x - m_point.x ) * ( ipNext.
y - m_point.y )
2170 - (
double) ( ipNext.
x - m_point.x ) * ( ip.
y - m_point.y );
2179 if( ( d > 0 ) == ( ipNext.
y > ip.
y ) )
2180 m_state = 1 - m_state;
2185 if( ipNext.
x > m_point.x )
2187 double d = (double) ( ip.
x - m_point.x ) * ( ipNext.
y - m_point.y )
2188 - (
double) ( ipNext.
x - m_point.x ) * ( ip.
y - m_point.y );
2197 if( ( d > 0 ) == ( ipNext.
y > ip.
y ) )
2198 m_state = 1 - m_state;
2211 m_lastPoint = aPolyline.
CPoint( 0 );
2212 m_firstPoint = aPolyline.
CPoint( 0 );
2217 for(
int i = 1; i < aPolyline.
PointCount(); i++ )
2219 auto p = aPolyline.
CPoint( i );
2221 if( !processVertex( m_lastPoint, p ) )
2232 processVertex( m_lastPoint, m_firstPoint );
bool Intersects(const BOX2< Vec > &aRect) const
BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
const VECTOR2I ReflectPoint(const VECTOR2I &aP) const
Reflect a point using this segment as axis.
int LineDistance(const VECTOR2I &aP, bool aDetermineSide=false) const
Return the closest Euclidean distance between point aP and the line defined by the ends of segment (t...
ecoord SquaredDistance(const SEG &aSeg) const
VECTOR2I::extended_type ecoord
const VECTOR2I NearestPoint(const VECTOR2I &aP) const
Compute a point on the segment (this) that is closest to point aP.
int Length() const
Return the length (this).
OPT_VECTOR2I Intersect(const SEG &aSeg, bool aIgnoreEndpoints=false, bool aLines=false) const
Compute intersection point of segment (this) with segment aSeg.
static SEG::ecoord Square(int a)
bool Collinear(const SEG &aSeg) const
Check if segment aSeg lies on the same line as (this).
int Distance(const SEG &aSeg) const
Compute minimum Euclidean distance to segment aSeg.
bool Contains(const SEG &aSeg) const
const VECTOR2I & GetArcMid() const
void SetWidth(int aWidth)
SHAPE_ARC & ConstructFromStartEndCenter(const VECTOR2I &aStart, const VECTOR2I &aEnd, const VECTOR2I &aCenter, bool aClockwise=false, double aWidth=0)
Constructs this arc from the given start, end and center.
const VECTOR2I & GetP1() const
bool Collide(const SEG &aSeg, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if the boundary of shape (this) lies closer to the segment aSeg than aClearance,...
const SHAPE_LINE_CHAIN ConvertToPolyline(double aAccuracy=DefaultAccuracyForPCB(), double *aEffectiveAccuracy=nullptr) const
Construct a SHAPE_LINE_CHAIN of segments from a given arc.
static double DefaultAccuracyForPCB()
VECTOR2I GetCenter() const
const VECTOR2I & GetP0() const
POINT_INSIDE_TRACKER(const VECTOR2I &aPoint)
bool processVertex(const VECTOR2I &ip, const VECTOR2I &ipNext)
void AddPolyline(const SHAPE_LINE_CHAIN &aPolyline)
bool PointInside(const VECTOR2I &aPt, int aAccuracy=0, bool aUseBBoxCache=false) const
Check if point aP lies inside a polygon (any type) defined by the line chain.
virtual bool Collide(const VECTOR2I &aP, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if point aP lies closer to us than aClearance.
SEG::ecoord SquaredDistance(const VECTOR2I &aP, bool aOutlineOnly=false) const
bool PointOnEdge(const VECTOR2I &aP, int aAccuracy=0) const
Check if point aP lies on an edge or vertex of the line chain.
int EdgeContainingPoint(const VECTOR2I &aP, int aAccuracy=0) const
Check if point aP lies on an edge or vertex of the line chain.
virtual size_t GetPointCount() const =0
virtual size_t GetSegmentCount() const =0
virtual const VECTOR2I GetPoint(int aIndex) const =0
virtual BOX2I * GetCachedBBox() const
virtual bool IsClosed() const =0
virtual const SEG GetSegment(int aIndex) const =0
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
std::vector< std::pair< ssize_t, ssize_t > > m_shapes
Array of indices that refer to the index of the shape if the point is part of a larger shape,...
const SHAPE_LINE_CHAIN Reverse() const
Reverse point order in the line chain.
bool IsPtOnArc(size_t aPtIndex) const
const SHAPE_ARC & Arc(size_t aArc) const
void splitArc(ssize_t aPtIndex, bool aCoincident=false)
Splits an arc into two arcs at aPtIndex.
const std::optional< INTERSECTION > SelfIntersecting() const
Check if the line chain is self-intersecting.
bool Parse(std::stringstream &aStream) override
bool CheckClearance(const VECTOR2I &aP, const int aDist) const
Check if point aP is closer to (or on) an edge or vertex of the line chain.
std::vector< SHAPE_ARC > m_arcs
SHAPE_LINE_CHAIN & Simplify(bool aRemoveColinear=true)
Simplify the line chain by removing colinear adjacent segments and duplicate vertices.
bool IsClosed() const override
virtual const VECTOR2I GetPoint(int aIndex) const override
ClipperLib::Path convertToClipper(bool aRequiredOrientation, std::vector< CLIPPER_Z_VALUE > &aZValueBuffer, std::vector< SHAPE_ARC > &aArcBuffer) const
Create a new Clipper path from the SHAPE_LINE_CHAIN in a given orientation.
void SetPoint(int aIndex, const VECTOR2I &aPos)
Move a point to a specific location.
const VECTOR2I PointAlong(int aPathLength) const
int Split(const VECTOR2I &aP)
Insert the point aP belonging to one of the our segments, splitting the adjacent segment in two.
int NextShape(int aPointIndex, bool aForwards=true) const
Return the vertex index of the next shape in the chain, or -1 if aPointIndex is the last shape.
void fixIndicesRotation()
Fix indices of this chain to ensure arcs are not split between the end and start indices.
std::vector< VECTOR2I > m_points
array of vertices
int FindSegment(const VECTOR2I &aP, int aThreshold=1) const
Search for segment containing point aP.
int ShapeCount() const
Return the number of shapes (line segments or arcs) in this line chain.
ssize_t reversedArcIndex(size_t aSegment) const
Return the arc index for the given segment index, looking backwards.
int Intersect(const SEG &aSeg, INTERSECTIONS &aIp) const
Find all intersection points between our line chain and the segment aSeg.
bool Intersects(const SHAPE_LINE_CHAIN &aChain) const
SHAPE_LINE_CHAIN()
Initialize an empty line chain.
int PointCount() const
Return the number of points (vertices) in this line chain.
bool IsArcEnd(size_t aIndex) const
void Replace(int aStartIndex, int aEndIndex, const VECTOR2I &aP)
Replace points with indices in range [start_index, end_index] with a single point aP.
virtual bool Collide(const VECTOR2I &aP, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if point aP lies closer to us than aClearance.
void ClearArcs()
Remove all arc references in the line chain, resulting in a chain formed only of straight segments.
void mergeFirstLastPointIfNeeded()
Merge the first and last point if they are the same and this chain is closed.
bool CompareGeometry(const SHAPE_LINE_CHAIN &aOther) const
ssize_t ArcIndex(size_t aSegment) const
Return the arc index for the given segment index.
BOX2I m_bbox
cached bounding box
const SHAPE_LINE_CHAIN Slice(int aStartIndex, int aEndIndex=-1) const
Return a subset of this line chain containing the [start_index, end_index] range of points.
bool m_closed
is the line chain closed?
const std::vector< SHAPE_ARC > & CArcs() const
int NearestSegment(const VECTOR2I &aP) const
Find the segment nearest the given point.
double Area(bool aAbsolute=true) const
Return the area of this chain.
void Mirror(bool aX=true, bool aY=false, const VECTOR2I &aRef={ 0, 0 })
Mirror the line points about y or x (or both).
void amendArc(size_t aArcIndex, const VECTOR2I &aNewStart, const VECTOR2I &aNewEnd)
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
virtual const SEG GetSegment(int aIndex) const override
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
const std::vector< std::pair< ssize_t, ssize_t > > & CShapes() const
const VECTOR2I NearestPoint(const VECTOR2I &aP, bool aAllowInternalShapePoints=true) const
Find a point on the line chain that is closest to point aP.
int SegmentCount() const
Return the number of segments in this line chain.
int PathLength(const VECTOR2I &aP, int aIndex=-1) const
Compute the walk path length from the beginning of the line chain and the point aP belonging to our l...
int Distance(const VECTOR2I &aP, bool aOutlineOnly=false) const
Compute the minimum distance between the line chain and a point aP.
const std::string Format(bool aCplusPlus=true) const override
Clipper2Lib::Path64 convertToClipper2(bool aRequiredOrientation, std::vector< CLIPPER_Z_VALUE > &aZValueBuffer, std::vector< SHAPE_ARC > &aArcBuffer) const
Create a new Clipper2 path from the SHAPE_LINE_CHAIN in a given orientation.
static const std::pair< ssize_t, ssize_t > SHAPES_ARE_PT
void convertArc(ssize_t aArcIndex)
Convert an arc to only a point chain by removing the arc and references.
virtual size_t GetSegmentCount() const override
void Remove(int aStartIndex, int aEndIndex)
Remove the range of points [start_index, end_index] from the line chain.
const SEG CSegment(int aIndex) const
Return a constant copy of the aIndex segment in the line chain.
bool IsArcSegment(size_t aSegment) const
void RemoveShape(int aPointIndex)
Remove the shape at the given index from the line chain.
void Insert(size_t aVertex, const VECTOR2I &aP)
bool IsArcStart(size_t aIndex) const
bool IsSharedPt(size_t aIndex) const
Test if a point is shared between multiple shapes.
std::vector< INTERSECTION > INTERSECTIONS
long long int Length() const
Return length of the line chain in Euclidean metric.
int Find(const VECTOR2I &aP, int aThreshold=0) const
Search for point aP.
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
SHAPE * Clone() const override
Return a dynamically allocated copy of the shape.
static const ssize_t SHAPE_IS_PT
An abstract shape on 2D plane.
VECTOR2I::extended_type ecoord
static constexpr extended_type ECOORD_MAX
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
bool pair_contains(const std::pair< _Type, _Type > __pair, _Value __value)
Returns true if either of the elements in an std::pair contains the given value.
void run_on_pair(std::pair< _Type, _Type > &__pair, _Function __f)
Apply a function to the first and second element of a std::pair.
std::optional< VECTOR2I > OPT_VECTOR2I
@ SH_LINE_CHAIN
line chain (polyline)
static void addIntersection(SHAPE_LINE_CHAIN::INTERSECTIONS &aIps, int aPc, const SHAPE_LINE_CHAIN::INTERSECTION &aP)
std::vector< FAB_LAYER_COLOR > dummy
Holds information on each point of a SHAPE_LINE_CHAIN that is retrievable after an operation with Cli...
Represent an intersection between two line segments.
bool is_corner_their
When true, the corner [index_their] of the 'their' line lies exactly on 'our' line.
bool is_corner_our
When true, the corner [index_our] of the 'our' line lies exactly on 'their' line.
int index_our
Index of the intersecting corner/segment in the 'our' (== this) line.
VECTOR2I p
Point of intersection between our and their.
bool valid
Auxiliary flag to avoid copying intersection info to intersection refining code, used by the refining...
int index_their
index of the intersecting corner/segment in the 'their' (Intersect() method parameter) line.
bool operator()(const SHAPE_LINE_CHAIN::INTERSECTION &aA, const SHAPE_LINE_CHAIN::INTERSECTION &aB) const
compareOriginDistance(const VECTOR2I &aOrigin)
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
double EuclideanNorm(const VECTOR2I &vector)
T rescale(T aNumerator, T aValue, T aDenominator)
Scale a number (value) by rational (numerator/denominator).