33#include <clipper2/clipper.h>
52 for(
size_t i = 0; i < aV.size(); i+= 2 )
73 m_width( aArc.GetWidth() )
81 const std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
82 const std::vector<SHAPE_ARC>& aArcBuffer ) :
84 m_closed( true ), m_width( 0 )
86 std::map<ssize_t, ssize_t> loadedArcs;
91 [&]( ssize_t aArcIndex ) -> ssize_t
97 else if( loadedArcs.count( aArcIndex ) == 0 )
99 loadedArcs.insert( { aArcIndex,
m_arcs.size() } );
100 m_arcs.push_back( aArcBuffer.at( aArcIndex ) );
103 return loadedArcs.at( aArcIndex );
106 for(
size_t ii = 0; ii < aPath.size(); ++ii )
108 Append( aPath[ii].
X, aPath[ii].Y );
110 m_shapes[ii].first = loadArc( aZValueBuffer[aPath[ii].Z].m_FirstArcIdx );
111 m_shapes[ii].second = loadArc( aZValueBuffer[aPath[ii].Z].m_SecondArcIdx );
125 const std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
126 const std::vector<SHAPE_ARC>& aArcBuffer ) :
128 m_closed( true ), m_width( 0 )
130 std::map<ssize_t, ssize_t> loadedArcs;
135 [&]( ssize_t aArcIndex ) -> ssize_t
141 else if( loadedArcs.count( aArcIndex ) == 0 )
143 loadedArcs.insert( { aArcIndex,
m_arcs.size() } );
144 m_arcs.push_back( aArcBuffer.at( aArcIndex ) );
147 return loadedArcs.at( aArcIndex );
150 for(
size_t ii = 0; ii < aPath.size(); ++ii )
152 Append( aPath[ii].x, aPath[ii].y );
154 m_shapes[ii].first = loadArc( aZValueBuffer[aPath[ii].z].m_FirstArcIdx );
155 m_shapes[ii].second = loadArc( aZValueBuffer[aPath[ii].z].m_SecondArcIdx );
169 std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
170 std::vector<SHAPE_ARC>& aArcBuffer )
const
172 ClipperLib::Path c_path;
174 bool orientation =
Area(
false ) >= 0;
175 ssize_t shape_offset = aArcBuffer.size();
177 if( orientation != aRequiredOrientation )
183 c_path.reserve( pointCount );
185 for(
int i = 0; i < pointCount; i++ )
190 size_t z_value_ptr = aZValueBuffer.size();
191 aZValueBuffer.push_back( z_value );
193 c_path.emplace_back( vertex.
x, vertex.
y, z_value_ptr );
196 aArcBuffer.insert( aArcBuffer.end(), input.
m_arcs.begin(), input.
m_arcs.end() );
203 std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
204 std::vector<SHAPE_ARC>& aArcBuffer )
const
206 Clipper2Lib::Path64 c_path;
208 bool orientation =
Area(
false ) >= 0;
209 ssize_t shape_offset = aArcBuffer.size();
211 if( orientation != aRequiredOrientation )
217 c_path.reserve( pointCount );
219 for(
int i = 0; i < pointCount; i++ )
224 size_t z_value_ptr = aZValueBuffer.size();
225 aZValueBuffer.push_back( z_value );
227 c_path.emplace_back( vertex.
x, vertex.
y, z_value_ptr );
230 aArcBuffer.insert( aArcBuffer.end(), input.
m_arcs.begin(), input.
m_arcs.end() );
243 size_t rotations = 0;
294 aArcIndex +=
m_arcs.size();
296 if( aArcIndex >=
static_cast<ssize_t
>(
m_arcs.size() ) )
303 [&]( ssize_t& aShapeIndex )
305 if( aShapeIndex == aArcIndex )
308 if( aShapeIndex > aArcIndex )
313 std::swap( sh.first, sh.second );
323 wxCHECK_MSG( aArcIndex <
m_arcs.size(), ,
324 wxT(
"Invalid arc index requested." ) );
333 m_arcs[aArcIndex] = newArc;
348 wxCHECK_MSG( aPtIndex <
static_cast<ssize_t
>(
m_shapes.size() ), ,
349 wxT(
"Invalid point index requested." ) );
353 if( aCoincident || aPtIndex == 0 )
356 ssize_t firstArcIndex =
m_shapes[aPtIndex].first;
360 amendArc( firstArcIndex, newStart, newEnd );
375 ssize_t currArcIdx =
ArcIndex( aPtIndex );
390 if( !aCoincident &&
ArcIndex( aPtIndex - 1 ) != currArcIdx )
393 m_arcs[currArcIdx] = newArc2;
397 m_arcs[currArcIdx] = newArc1;
398 m_arcs.insert(
m_arcs.begin() + currArcIdx + 1, newArc2 );
402 m_shapes[aPtIndex].second = currArcIdx + 1;
407 for(
int i = aPtIndex; i <
PointCount(); i++ )
440 SEG::ecoord dist_sq = ( pn - aP ).SquaredEuclideanNorm();
442 if( dist_sq < closest_dist_sq )
445 closest_dist_sq = dist_sq;
447 if( closest_dist_sq == 0 )
451 if( closest_dist_sq < clearance_sq && !aActual )
456 if( closest_dist_sq == 0 || closest_dist_sq < clearance_sq )
459 *aLocation = nearest;
462 *aActual = sqrt( closest_dist_sq );
497 SEG::ecoord dist_sq = ( pn - aP ).SquaredEuclideanNorm();
499 if( dist_sq < closest_dist_sq )
502 closest_dist_sq = dist_sq;
504 if( closest_dist_sq == 0 )
508 if( closest_dist_sq < clearance_sq && !aActual )
513 if( closest_dist_sq == 0 || closest_dist_sq < clearance_sq )
516 *aLocation = nearest;
519 *aActual = sqrt( closest_dist_sq );
525 for(
size_t i = 0; i <
ArcCount(); i++ )
530 wxASSERT_MSG( arc.
GetWidth() == 0, wxT(
"Invalid arc width - should be zero" ) );
532 if( arc.
Collide( aP, aClearance, aActual, aLocation ) )
546 arc.Rotate( aAngle, aCenter );
573 if( dist_sq < closest_dist_sq )
578 closest_dist_sq = dist_sq;
580 if( closest_dist_sq == 0)
584 if( closest_dist_sq < clearance_sq && !aActual )
589 if( closest_dist_sq == 0 || closest_dist_sq < clearance_sq )
592 *aLocation = nearest;
595 *aActual = sqrt( closest_dist_sq );
631 if( dist_sq < closest_dist_sq )
636 closest_dist_sq = dist_sq;
638 if( closest_dist_sq == 0 )
642 if( closest_dist_sq < clearance_sq && !aActual )
647 if( closest_dist_sq == 0 || closest_dist_sq < clearance_sq )
650 *aLocation = nearest;
653 *aActual = sqrt( closest_dist_sq );
658 int closest_dist = std::numeric_limits<int>::max();
661 closest_dist = sqrt( closest_dist_sq );
664 for(
size_t i = 0; i <
ArcCount(); i++ )
670 wxASSERT_MSG( arc.
GetWidth() == 0, wxT(
"Invalid arc width - should be zero" ) );
672 if( arc.
Collide( aSeg, aClearance, aActual || aLocation ? &dist :
nullptr,
673 aLocation ? &nearest :
nullptr ) )
678 if( dist < closest_dist )
683 if( closest_dist == 0 || closest_dist < aClearance )
686 *aLocation = nearest;
689 *aActual = closest_dist;
711 [&]( ssize_t& aShapeIndex )
714 aShapeIndex = a.
m_arcs.size() - aShapeIndex - 1;
723 std::swap( sh.first, sh.second );
739 for( ssize_t arcIndex =
m_arcs.size() - 1; arcIndex >= 0; --arcIndex )
755 for(
size_t i = 0; i <
ArcCount(); i++ )
756 l +=
CArcs()[i].GetLength();
767 pt.x = -pt.x + 2 * aRef.
x;
770 pt.y = -pt.y + 2 * aRef.
y;
774 arc.Mirror( aX, aY, aRef );
790 Remove( aStartIndex, aEndIndex );
791 Insert( aStartIndex, aP );
801 if( aStartIndex < 0 )
805 wxASSERT( aStartIndex <= aEndIndex );
806 wxASSERT( aEndIndex <
static_cast<int>(
m_points.size() ) );
813 Remove( aStartIndex, aEndIndex );
826 Remove( aStartIndex, aEndIndex );
837 Remove( aStartIndex, aEndIndex );
844 size_t prev_arc_count =
m_arcs.size();
845 std::vector<std::pair<ssize_t, ssize_t>> new_shapes = newLine.
m_shapes;
847 for( std::pair<ssize_t, ssize_t>& shape_pair : new_shapes )
850 [&]( ssize_t& aShape )
853 aShape += prev_arc_count;
857 m_shapes.insert(
m_shapes.begin() + aStartIndex, new_shapes.begin(), new_shapes.end() );
878 if( aStartIndex < 0 )
901 if( aStartIndex > aEndIndex )
907 std::set<size_t> extra_arcs;
908 auto logArcIdxRemoval = [&]( ssize_t& aShapeIndex )
911 extra_arcs.insert( aShapeIndex );
915 for(
int i = aStartIndex; i <= aEndIndex; i++ )
919 if( i == aStartIndex )
921 logArcIdxRemoval(
m_shapes[i].second );
928 else if( i == aEndIndex )
930 logArcIdxRemoval(
m_shapes[i].first );
933 assert( i > aStartIndex || (
IsSharedPt( i - 1 )
945 for(
auto arc : extra_arcs )
975 int found_index =
Find( aP );
977 if( found_index >= 0 && aExact )
987 if( dist < min_dist && seg.
A != aP && seg.
B != aP )
990 if( found_index < 0 )
992 else if( s < found_index )
1006 size_t newIndex =
static_cast<size_t>( ii ) + 1;
1030 if( aThreshold == 0 )
1037 if( (
CPoint( s ) - aP).EuclideanNorm() <= aThreshold )
1060 wxCHECK2_MSG(
m_points.size() ==
m_shapes.size(),
return 0,
"Invalid chain!" );
1091 if( aPointIndex < 0 )
1094 if( aPointIndex < 0 )
1100 if( aPointIndex >= lastIndex )
1105 if( aPointIndex == lastIndex - 1 )
1114 return aPointIndex + 1;
1118 int arcStart = aPointIndex;
1122 wxCHECK2_MSG(
m_shapes[aPointIndex].first !=
SHAPE_IS_PT,
return -1,
"malformed chain!" );
1124 ssize_t currentArcIdx =
ArcIndex( aPointIndex );
1127 while( aPointIndex < lastIndex &&
ArcIndex( aPointIndex ) == currentArcIdx )
1134 if( aPointIndex - arcStart > 1 && !indexStillOnArc )
1137 if( aPointIndex == lastIndex )
1159 [&]( ssize_t& aIdx )
1169 if( aPointIndex < 0 )
1172 if( aPointIndex >=
PointCount() || aPointIndex < 0 )
1181 int start = aPointIndex;
1182 int end = aPointIndex;
1183 int arcIdx =
ArcIndex( aPointIndex );
1188 while( start > 0 &&
ArcIndex(
static_cast<ssize_t
>( start ) - 1 ) == arcIdx )
1192 if( !
IsArcEnd( end ) || start == end )
1206 if( aStartIndex < 0 )
1216 int numPoints =
static_cast<int>(
m_points.size() );
1221 ssize_t arcToSplitIndex =
ArcIndex( aStartIndex );
1225 for(
size_t i = aStartIndex; arcToSplitIndex ==
ArcIndex( i ); i++ )
1242 rv.
m_arcs.push_back( newArc );
1247 for(
int i = aStartIndex; i <= aEndIndex && i < numPoints; i =
NextShape( i ) )
1253 bool isLastShape = nextShape < 0;
1257 if( ( isLastShape && aEndIndex != ( numPoints - 1 ) )
1258 || ( nextShape > aEndIndex ) )
1260 if( i == aEndIndex )
1272 for( ; i <= aEndIndex && i < numPoints; i++ )
1292 rv.
m_arcs.push_back( newArc );
1309 wxT(
"Still on an arc segment, we missed something..." ) );
1311 if( i == aStartIndex )
1314 bool nextPointIsArc = isLastShape ? false :
IsArcSegment( nextShape );
1316 if( !nextPointIsArc && i <
SegmentCount() && i < aEndIndex )
1335 size_t num_arcs =
m_arcs.size();
1338 auto fixShapeIndices =
1339 [&](
const std::pair<ssize_t, ssize_t>& aShapeIndices ) -> std::pair<ssize_t, ssize_t>
1341 std::pair<ssize_t, ssize_t> retval = aShapeIndices;
1346 aIndex = aIndex + num_arcs;
1369 for(
int i = 1; i < aOtherLine.
PointCount(); i++ )
1374 ssize_t arcIndex = aOtherLine.
ArcIndex( i );
1404 chain.
m_arcs.push_back( aArc );
1405 chain.
m_arcs.back().SetWidth( 0 );
1425 wxCHECK( aVertex <
m_points.size(), );
1427 if( aVertex > 0 &&
IsPtOnArc( aVertex ) )
1440 wxCHECK( aVertex <
m_points.size(), );
1442 if( aVertex > 0 &&
IsPtOnArc( aVertex ) )
1446 ssize_t arc_pos =
m_arcs.size();
1448 for(
auto arc_it =
m_shapes.rbegin() ;
1449 arc_it !=
m_shapes.rend() + aVertex;
1454 arc_pos = std::max( ( *arc_it ).first, ( *arc_it ).second );
1463 [&]( ssize_t& aIndex )
1465 if( aIndex >= arc_pos )
1477 m_points.insert(
m_points.begin() + aVertex, chain.CPoints().begin(), chain.CPoints().end() );
1481 std::vector<std::pair<ssize_t, ssize_t>> new_points( chain.PointCount(),
1482 { arc_pos, SHAPE_IS_PT } );
1484 m_shapes.insert(
m_shapes.begin() + aVertex, new_points.begin(), new_points.end() );
1518 aIp.push_back( is );
1523 sort( aIp.begin(), aIp.end(), comp );
1532 if( aIps.size() == 0 )
1534 aIps.push_back( aP );
1538 aIps.push_back( aP );
1543 bool aExcludeColinearAndTouching,
BOX2I* aChainBBox )
const
1545 BOX2I bb_other = aChainBBox ? *aChainBBox : aChain.
BBox();
1550 const BOX2I bb_cur( a.
A, a.
B - a.
A );
1570 if( coll && ! aExcludeColinearAndTouching )
1646 bool indexMatch =
true;
1656 indexMatch = ( i == aIndex );
1674 bool aUseBBoxCache )
const
1686 bool inside =
false;
1701 for(
int i = 0; i < pointCount; )
1704 const auto p2 =
GetPoint( i == pointCount ? 0 : i );
1705 const auto diff = p2 - p1;
1709 const int d =
rescale( diff.x, ( aPt.
y - p1.y ), diff.y );
1711 if( ( ( p1.y > aPt.
y ) != ( p2.y > aPt.
y ) ) && ( aPt.
x - p1.x < d ) )
1718 if( aAccuracy <= 1 )
1740 return ( hypot( dist.
x, dist.
y ) <= aAccuracy + 1 ) ? 0 : -1;
1747 if( s.
A == aPt || s.
B == aPt )
1750 if( s.
Distance( aPt ) <= aAccuracy + 1 )
1769 if( s.
A == aP || s.
B == aP )
1788 if( s1 + 1 != s2 &&
CSegment( s1 ).Contains( s2a ) )
1796 else if(
CSegment( s1 ).Contains( s2b ) &&
1824 return std::optional<SHAPE_LINE_CHAIN::INTERSECTION>();
1829 bool aAllowInternalShapePoints )
const
1837 int min_d = std::numeric_limits<int>::max();
1851 if( !aAllowInternalShapePoints )
1874 return nearestArc.
GetP1();
1876 return nearestArc.
GetP0();
1896 dist = std::numeric_limits<int>::max();
1909 return CPoint( nearest );
1915 int min_d = std::numeric_limits<int>::max();
1935 std::stringstream ss;
1937 ss <<
"SHAPE_LINE_CHAIN( { ";
1947 ss <<
"}, " << (
m_closed ?
"true" :
"false" );
1968 if( a.m_points.size() != b.
m_points.size() )
1971 for(
int i = 0; i < a.PointCount(); i++ )
1973 if( a.CPoint( i ) != b.
CPoint( i ) )
2003 if( n_pts > aStream.str().size() )
2009 if( n_arcs > aStream.str().size() )
2012 for(
size_t i = 0; i < n_pts; i++ )
2024 for(
size_t i = 0; i < n_arcs; i++ )
2046 if( aPathLength == 0 )
2054 if( total + l >= aPathLength )
2057 return s.
A + d.
Resize( aPathLength - total );
2077 for(
int i = 0, j = size - 1; i < size; ++i )
2085 return std::fabs( area * 0.5 );
2093 std::vector<VECTOR2I> pts_unique;
2094 std::vector<std::pair<ssize_t, ssize_t>> shapes_unique;
2125 std::pair<ssize_t,ssize_t> shapeToKeep =
m_shapes[i];
2130 assert( shapeToKeep.first <
static_cast<int>(
m_arcs.size() ) );
2131 assert( shapeToKeep.second <
static_cast<int>(
m_arcs.size() ) );
2133 pts_unique.push_back(
CPoint( i ) );
2134 shapes_unique.push_back( shapeToKeep );
2142 for(
size_t ii = 0; ii < pts_unique.size(); ++ii )
2144 const VECTOR2I p0 = pts_unique[ii];
2147 m_shapes.push_back( shapes_unique[ii] );
2158 std::vector<VECTOR2I> new_points;
2159 std::vector<std::pair<ssize_t, ssize_t>> new_shapes;
2161 new_points.reserve(
m_points.size() );
2162 new_shapes.reserve(
m_shapes.size() );
2164 for(
size_t ii = 0; ii <
m_points.size(); )
2166 new_points.push_back(
m_points[ii] );
2167 new_shapes.push_back(
m_shapes[ii] );
2168 size_t jj = ( ii + 1 ) %
m_points.size();
2169 size_t kk = ( jj + 1 ) %
m_points.size();
2179 && ii != kk && jj > ii )
2185 if( ii == kk || jj <= ii )
2192 if( new_points.size() == 1 )
2194 new_points.push_back(
m_points.back() );
2195 new_shapes.push_back(
m_shapes.back() );
2217 int i_start = l.
Find( m );
2218 int i_end = l.
Find( n );
2220 if( i_start > i_end )
2223 i_start = l.
Find( m );
2224 i_end = l.
Find( n );
2227 aPre = l.
Slice( 0, i_start );
2228 aPost = l.
Slice( i_end, -1 );
2229 aMid = l.
Slice( i_start, i_end );
2235 bool aSimplify )
const
2241 poly.
OffsetLineChain( *
this, aAmount, aCornerStrategy, aMaxError, aSimplify );
2259 outline.
Split( start,
true );
2260 outline.
Split( end,
true );
2262 const int idA = outline.
Find( start );
2263 const int idB = outline.
Find( end );
2265 if( idA == -1 || idB == -1 )
2271 for(
int i = idA;; )
2290 for(
int i = idB;; )
2309 if( aLeft.
CPoint( 0 ) != start )
2312 wxASSERT( aLeft.
CPoint( 0 ) == start );
2315 if( aRight.
CPoint( 0 ) != start )
2318 wxASSERT( aRight.
CPoint( 0 ) == start );
2322 int sideLeft = base.
Side( aLeft.
CPoint( 1 ) );
2323 int sideRight = base.
Side( aRight.
CPoint( 1 ) );
2325 if( sideLeft == 0 || sideRight == 0 )
2328 if( sideLeft == sideRight )
2331 if( sideLeft > 0 && sideRight < 0 )
2332 std::swap( aLeft, aRight );
2359 m_finished( false ),
2369 if( ipNext.
y == m_point.y )
2371 if( ( ipNext.
x == m_point.x )
2372 || ( ip.
y == m_point.y && ( ( ipNext.
x > m_point.x ) == ( ip.
x < m_point.x ) ) ) )
2380 if( ( ip.
y < m_point.y ) != ( ipNext.
y < m_point.y ) )
2382 if( ip.
x >= m_point.x )
2384 if( ipNext.
x > m_point.x )
2386 m_state = 1 - m_state;
2390 double d = (double) ( ip.
x - m_point.x ) * ( ipNext.
y - m_point.y )
2391 - (
double) ( ipNext.
x - m_point.x ) * ( ip.
y - m_point.y );
2400 if( ( d > 0 ) == ( ipNext.
y > ip.
y ) )
2401 m_state = 1 - m_state;
2406 if( ipNext.
x > m_point.x )
2408 double d = (double) ( ip.
x - m_point.x ) * ( ipNext.
y - m_point.y )
2409 - (
double) ( ipNext.
x - m_point.x ) * ( ip.
y - m_point.y );
2418 if( ( d > 0 ) == ( ipNext.
y > ip.
y ) )
2419 m_state = 1 - m_state;
2432 m_lastPoint = aPolyline.
CPoint( 0 );
2433 m_firstPoint = aPolyline.
CPoint( 0 );
2438 for(
int i = 1; i < aPolyline.
PointCount(); i++ )
2440 auto p = aPolyline.
CPoint( i );
2442 if( !processVertex( m_lastPoint, p ) )
2453 processVertex( m_lastPoint, m_firstPoint );
2479 size_t nextIdx = aSegment + 1;
2481 if( nextIdx >
m_shapes.size() - 1 )
2510 size_t prevIndex = aIndex - 1;
2514 else if( aIndex >
m_points.size() -1 )
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
int Side(const VECTOR2I &aP) const
Determine on which side of directed line passing via segment ends point aP lies.
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)
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.
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
bool PointInside(const VECTOR2I &aPt, int aAccuracy=0, bool aUseBBoxCache=false) const override
Check if point aP lies inside a closed shape.
virtual bool IsClosed() const =0
virtual const SEG GetSegment(int aIndex) const =0
SEG::ecoord SquaredDistance(const VECTOR2I &aP, bool aOutlineOnly=false) const override
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
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, bool aExact=false)
Insert the point aP belonging to one of the our segments, splitting the adjacent segment in two.
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.
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
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
void Simplify(int aMaxError=0)
Simplify the line chain by removing colinear adjacent segments and duplicate vertices.
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.
void TransformToPolygon(SHAPE_POLY_SET &aBuffer, int aError, ERROR_LOC aErrorLoc) const override
Fills a SHAPE_POLY_SET with a polygon representation of this shape.
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.
void Clear()
Remove all points from the line chain.
SEG Segment(int aIndex) const
Return a copy of the aIndex-th segment in the line chain.
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.
int NextShape(int aPointIndex) const
Return the vertex index of the next shape in the chain, or -1 if aPointIndex is the last shape.
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...
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.
void RemoveDuplicatePoints()
Remove the duplicate points 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
bool OffsetLine(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, SHAPE_LINE_CHAIN &aLeft, SHAPE_LINE_CHAIN &aRight, bool aSimplify=false) const
Creates line chains aLeft and aRight offset to this line chain.
Represent a set of closed polygons.
bool HasHoles() const
Return true if the polygon set has any holes.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
void OffsetLineChain(const SHAPE_LINE_CHAIN &aLine, int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify)
Perform offsetting of a line chain.
int OutlineCount() const
Return the number of outlines in the set.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
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.
CORNER_STRATEGY
define how inflate transform build inflated polygon
ERROR_LOC
When approximating an arc or circle, should the error be placed on the outside or inside of the curve...
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)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
bool TestSegmentHitFast(const VECTOR2I &aRefPoint, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aDist)
Test if a point hits a line segment within a given distance.
double EuclideanNorm(const VECTOR2I &vector)
T rescale(T aNumerator, T aValue, T aDenominator)
Scale a number (value) by rational (numerator/denominator).