28#include <clipper2/clipper.h>
51 int minX, maxX, minY, maxY;
71 for(
size_t i = 0; i < aV.size(); i+= 2 )
96 if( aMaxError.has_value() )
97 Append( aArc, aMaxError.value() );
106 const std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
107 const std::vector<SHAPE_ARC>& aArcBuffer ) :
113 std::map<ssize_t, ssize_t> loadedArcs;
118 [&]( ssize_t aArcIndex ) -> ssize_t
120 if( aArcIndex == SHAPE_IS_PT )
124 else if( loadedArcs.count( aArcIndex ) == 0 )
126 loadedArcs.insert( { aArcIndex, m_arcs.size() } );
127 m_arcs.push_back( aArcBuffer.at( aArcIndex ) );
130 return loadedArcs.at( aArcIndex );
133 for(
size_t ii = 0; ii < aPath.size(); ++ii )
135 Append( aPath[ii].x, aPath[ii].y );
138 int idx_z = aPath[ii].z;
140 if( idx_z < 0 || idx_z >= (
int)aZValueBuffer.size() )
143 m_shapes[ii].first = loadArc( aZValueBuffer[idx_z].m_FirstArcIdx );
144 m_shapes[ii].second = loadArc( aZValueBuffer[idx_z].m_SecondArcIdx );
149 wxASSERT( m_shapes.size() == m_points.size() );
153 fixIndicesRotation();
158 std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
159 std::vector<SHAPE_ARC>& aArcBuffer )
const
161 Clipper2Lib::Path64 c_path;
163 bool orientation =
Area(
false ) >= 0;
164 ssize_t shape_offset = aArcBuffer.size();
166 if( orientation != aRequiredOrientation )
172 c_path.reserve( pointCount );
174 for(
int i = 0; i < pointCount; i++ )
179 size_t z_value_ptr = aZValueBuffer.size();
180 aZValueBuffer.push_back( z_value );
182 c_path.emplace_back( vertex.
x, vertex.
y, z_value_ptr );
185 aArcBuffer.insert( aArcBuffer.end(), input.
m_arcs.begin(), input.
m_arcs.end() );
198 size_t rotations = 0;
249 aArcIndex +=
m_arcs.size();
251 if( aArcIndex >=
static_cast<ssize_t
>(
m_arcs.size() ) )
258 [&]( ssize_t& aShapeIndex )
260 if( aShapeIndex == aArcIndex )
263 if( aShapeIndex > aArcIndex )
268 std::swap( sh.first, sh.second );
278 wxCHECK_MSG( aArcIndex <
m_arcs.size(), ,
279 wxT(
"Invalid arc index requested." ) );
288 m_arcs[aArcIndex] = newArc;
303 wxCHECK_MSG( aPtIndex <
static_cast<ssize_t
>(
m_shapes.size() ), ,
304 wxT(
"Invalid point index requested." ) );
308 if( aCoincident || aPtIndex == 0 )
311 ssize_t firstArcIndex =
m_shapes[aPtIndex].first;
315 amendArc( firstArcIndex, newStart, newEnd );
330 ssize_t currArcIdx =
ArcIndex( aPtIndex );
345 if( !aCoincident &&
ArcIndex( aPtIndex - 1 ) != currArcIdx )
348 m_arcs[currArcIdx] = newArc2;
352 m_arcs[currArcIdx] = newArc1;
353 m_arcs.insert(
m_arcs.begin() + currArcIdx + 1, newArc2 );
357 m_shapes[aPtIndex].second = currArcIdx + 1;
362 for(
int i = aPtIndex; i <
PointCount(); i++ )
395 SEG::ecoord dist_sq = ( pn - aP ).SquaredEuclideanNorm();
397 if( dist_sq < closest_dist_sq )
400 closest_dist_sq = dist_sq;
402 if( closest_dist_sq == 0 )
406 if( closest_dist_sq < clearance_sq && !aActual )
411 if( closest_dist_sq == 0 || closest_dist_sq < clearance_sq )
414 *aLocation = nearest;
417 *aActual = sqrt( closest_dist_sq );
452 SEG::ecoord dist_sq = ( pn - aP ).SquaredEuclideanNorm();
454 if( dist_sq < closest_dist_sq )
457 closest_dist_sq = dist_sq;
459 if( closest_dist_sq == 0 )
463 if( closest_dist_sq < clearance_sq && !aActual )
468 if( closest_dist_sq == 0 || closest_dist_sq < clearance_sq )
471 *aLocation = nearest;
474 *aActual = sqrt( closest_dist_sq );
480 for(
size_t i = 0; i <
ArcCount(); i++ )
485 wxASSERT_MSG( arc.
GetWidth() == 0, wxT(
"Invalid arc width - should be zero" ) );
487 if( arc.
Collide( aP, aClearance, aActual, aLocation ) )
501 arc.Rotate( aAngle, aCenter );
508 const std::vector<VECTOR2I>& myPts =
m_points;
509 const std::vector<VECTOR2I>& otherPts = aOther.
m_points;
511 const int c_maxBoxes = 100;
512 const int c_minPtsPerBox = 20;
514 int myPointsPerBox = std::max( c_minPtsPerBox,
int( myPts.size() / c_maxBoxes ) + 1 );
515 int otherPointsPerBox = std::max( c_minPtsPerBox,
int( otherPts.size() / c_maxBoxes ) + 1 );
517 int myNumBoxes = ( myPts.size() + myPointsPerBox - 1 ) / myPointsPerBox;
518 int otherNumBoxes = ( otherPts.size() + otherPointsPerBox - 1 ) / otherPointsPerBox;
528 std::vector<BOX> myBoxes( myNumBoxes );
529 std::vector<BOX> otherBoxes( otherNumBoxes );
532 for(
size_t i = 0; i < myPts.size(); i++ )
535 BOX& box = myBoxes[i / myPointsPerBox];
539 box.bbox.Merge( pt );
548 for(
size_t i = 0; i < otherPts.size(); i++ )
551 BOX& box = otherBoxes[i / otherPointsPerBox];
555 box.bbox.Merge( pt );
565 for( BOX& box : myBoxes )
567 box.center = box.bbox.GetCenter();
568 box.radius = int( box.bbox.GetDiameter() / 2 );
571 for( BOX& box : otherBoxes )
573 box.center = box.bbox.GetCenter();
574 box.radius = int( box.bbox.GetDiameter() / 2 );
580 DIST_PAIR( int64_t aDistSq,
size_t aIdA,
size_t aIdB ) :
581 dist( aDistSq ), idA( aIdA ), idB( aIdB )
590 std::vector<DIST_PAIR> pairsToTest;
592 for(
size_t ia = 0; ia < myBoxes.size(); ia++ )
594 for(
size_t ib = 0; ib < otherBoxes.size(); ib++ )
596 const BOX& ca = myBoxes[ia];
597 const BOX& cb = otherBoxes[ib];
599 if( !ca.valid || !cb.valid )
605 int64_t dist = ( pB - pA ).EuclideanNorm();
610 pairsToTest.emplace_back( dist, ia, ib );
614 std::sort( pairsToTest.begin(), pairsToTest.end(),
615 [](
const DIST_PAIR& a,
const DIST_PAIR& b )
617 return a.dist < b.dist;
620 const int c_polyPairsLimit = 5;
625 for(
size_t pairId = 0; pairId < pairsToTest.size() && pairId < c_polyPairsLimit; pairId++ )
627 const DIST_PAIR& pair = pairsToTest[pairId];
633 size_t myStartId = pair.idA * myPointsPerBox;
634 size_t myEndId = myStartId + myPointsPerBox;
636 if( myEndId > myPts.size() )
637 myEndId = myPts.size();
639 VECTOR2I myPrevPt = myPts[myStartId == 0 ? myPts.size() - 1 : myStartId - 1];
641 size_t otherStartId = pair.idB * otherPointsPerBox;
642 size_t otherEndId = otherStartId + otherPointsPerBox;
644 if( otherEndId > otherPts.size() )
645 otherEndId = otherPts.size();
647 VECTOR2I otherPrevPt = otherPts[otherStartId == 0 ? otherPts.size() - 1 : otherStartId - 1];
649 if(
ClosestSegments( myPrevPt, myPts.begin() + myStartId, myPts.begin() + myEndId,
650 otherPrevPt, otherPts.begin() + otherStartId,
651 otherPts.begin() + otherEndId, ptA, ptB, dist_sq ) )
653 if( dist_sq < total_closest_dist_sq )
655 total_closest_dist_sq = dist_sq;
672 if( aMyStart == aMyEnd )
675 if( aOtherStart == aOtherEnd )
681 for(
point_citer itA = aMyStart; itA != aMyEnd; itA++ )
686 for(
point_citer itB = aOtherStart; itB != aOtherEnd; itB++ )
690 SEG segA( lastPtA, ptA );
691 SEG segB( lastPtB, ptB );
697 if( segA.
NearestPoints( segB, nearestA, nearestB, dist_sq ) )
699 if( dist_sq < closest_dist_sq )
701 closest_dist_sq = dist_sq;
713 aDistSq = closest_dist_sq;
724 for(
point_citer itA = aMyStart; itA != aMyEnd; itA++ )
728 for(
point_citer itB = aOtherStart; itB != aOtherEnd; itB++ )
737 if( dist_sq < closest_dist_sq )
739 closest_dist_sq = dist_sq;
746 aDistSq = closest_dist_sq;
757 aOther.
m_points.cend(), aPt0, aPt1, dist_sq );
784 if( dist_sq < closest_dist_sq )
789 closest_dist_sq = dist_sq;
791 if( closest_dist_sq == 0)
795 if( closest_dist_sq < clearance_sq && !aActual )
800 if( closest_dist_sq == 0 || closest_dist_sq < clearance_sq )
803 *aLocation = nearest;
806 *aActual = sqrt( closest_dist_sq );
842 if( dist_sq < closest_dist_sq )
847 closest_dist_sq = dist_sq;
849 if( closest_dist_sq == 0 )
853 if( closest_dist_sq < clearance_sq && !aActual )
858 if( closest_dist_sq == 0 || closest_dist_sq < clearance_sq )
861 *aLocation = nearest;
864 *aActual = sqrt( closest_dist_sq );
869 int dist = std::numeric_limits<int>::max();
870 SEG::ecoord closest_dist = sqrt( closest_dist_sq );
873 for(
size_t i = 0; i <
ArcCount(); i++ )
879 wxASSERT_MSG( arc.
GetWidth() == 0, wxT(
"Invalid arc width - should be zero" ) );
881 if( arc.
Collide( aSeg, aClearance, aActual || aLocation ? &dist :
nullptr,
882 aLocation ? &pos :
nullptr ) )
887 if( dist < closest_dist )
895 if( closest_dist == 0 || closest_dist < aClearance )
898 *aLocation = nearest;
901 *aActual = closest_dist;
923 [&]( ssize_t& aShapeIndex )
926 aShapeIndex = a.
m_arcs.size() - aShapeIndex - 1;
935 std::swap( sh.first, sh.second );
951 for( ssize_t arcIndex =
m_arcs.size() - 1; arcIndex >= 0; --arcIndex )
967 for(
size_t i = 0; i <
ArcCount(); i++ )
968 l +=
CArcs()[i].GetLength();
979 pt.x = -pt.x + 2 * aRef.
x;
981 pt.y = -pt.y + 2 * aRef.
y;
985 arc.Mirror( aRef, aFlipDirection );
1001 Remove( aStartIndex, aEndIndex );
1002 Insert( aStartIndex, aP );
1012 if( aStartIndex < 0 )
1016 wxASSERT( aStartIndex <= aEndIndex );
1017 wxASSERT( aEndIndex <
static_cast<int>(
m_points.size() ) );
1024 Remove( aStartIndex, aEndIndex );
1037 Remove( aStartIndex, aEndIndex );
1048 Remove( aStartIndex, aEndIndex );
1055 size_t prev_arc_count =
m_arcs.size();
1056 std::vector<std::pair<ssize_t, ssize_t>> new_shapes = newLine.
m_shapes;
1058 for( std::pair<ssize_t, ssize_t>& shape_pair : new_shapes )
1061 [&]( ssize_t& aShape )
1064 aShape += prev_arc_count;
1068 m_shapes.insert(
m_shapes.begin() + aStartIndex, new_shapes.begin(), new_shapes.end() );
1089 if( aStartIndex < 0 )
1112 if( aStartIndex > aEndIndex )
1118 std::set<size_t> extra_arcs;
1119 auto logArcIdxRemoval = [&]( ssize_t& aShapeIndex )
1122 extra_arcs.insert( aShapeIndex );
1126 for(
int i = aStartIndex; i <= aEndIndex; i++ )
1130 if( i == aStartIndex )
1132 logArcIdxRemoval(
m_shapes[i].second );
1139 else if( i == aEndIndex )
1141 logArcIdxRemoval(
m_shapes[i].first );
1144 assert( i > aStartIndex || (
IsSharedPt( i - 1 )
1156 for(
auto arc : extra_arcs )
1186 int found_index =
Find( aP );
1188 if( found_index >= 0 && aExact )
1198 if( dist < min_dist && seg.
A != aP && seg.
B != aP )
1201 if( found_index < 0 )
1203 else if( s < found_index )
1217 size_t newIndex =
static_cast<size_t>( ii ) + 1;
1222 m_shapes.insert(
m_shapes.begin() + newIndex, { ArcIndex( ii ), SHAPE_IS_PT } );
1241 if( aThreshold == 0 )
1248 if( (
CPoint( s ) - aP).EuclideanNorm() <= aThreshold )
1271 wxCHECK2_MSG(
m_points.size() ==
m_shapes.size(),
return 0,
"Invalid chain!" );
1292 wxCHECK( aIndex < segCount && aIndex >= 0,
1304 if( aPointIndex < 0 )
1307 if( aPointIndex < 0 )
1313 if( aPointIndex >= lastIndex )
1318 if( aPointIndex == lastIndex - 1 )
1327 return aPointIndex + 1;
1331 int arcStart = aPointIndex;
1335 wxCHECK2_MSG(
m_shapes[aPointIndex].first !=
SHAPE_IS_PT,
return -1,
"malformed chain!" );
1337 ssize_t currentArcIdx =
ArcIndex( aPointIndex );
1340 while( aPointIndex < lastIndex &&
ArcIndex( aPointIndex ) == currentArcIdx )
1347 if( aPointIndex - arcStart > 1 && !indexStillOnArc )
1350 if( aPointIndex == lastIndex )
1372 [&]( ssize_t& aIdx )
1382 if( aPointIndex < 0 )
1385 if( aPointIndex >=
PointCount() || aPointIndex < 0 )
1394 int start = aPointIndex;
1395 int end = aPointIndex;
1396 int arcIdx =
ArcIndex( aPointIndex );
1401 while( start > 0 &&
ArcIndex(
static_cast<ssize_t
>( start ) - 1 ) == arcIdx )
1425 if( aStartIndex < 0 )
1435 int numPoints =
static_cast<int>(
m_points.size() );
1440 ssize_t arcToSplitIndex =
ArcIndex( aStartIndex );
1444 for(
size_t i = aStartIndex; i <
m_points.size() && arcToSplitIndex ==
ArcIndex( i ); i++ )
1461 rv.
m_arcs.push_back( newArc );
1466 for(
int i = aStartIndex; i <= aEndIndex && i < numPoints; i =
NextShape( i ) )
1472 bool isLastShape = nextShape < 0;
1476 if( ( isLastShape && aEndIndex != ( numPoints - 1 ) )
1477 || ( nextShape > aEndIndex ) )
1479 if( i == aEndIndex )
1491 for( ; i <= aEndIndex && i < numPoints; i++ )
1511 rv.
m_arcs.push_back( newArc );
1519 rv.
Append( currentArc, aMaxError );
1527 wxASSERT_MSG( !
IsArcSegment( i ), wxT(
"Still on an arc segment, we missed something..." ) );
1529 if( i == aStartIndex )
1532 bool nextPointIsArc = isLastShape ? false :
IsArcSegment( nextShape );
1534 if( !nextPointIsArc && i <
SegmentCount() && i < aEndIndex )
1555 size_t num_arcs =
m_arcs.size();
1558 auto fixShapeIndices =
1559 [&](
const std::pair<ssize_t, ssize_t>& aShapeIndices ) -> std::pair<ssize_t, ssize_t>
1561 std::pair<ssize_t, ssize_t> retval = aShapeIndices;
1566 aIndex = aIndex + num_arcs;
1589 for(
int i = 1; i < aOtherLine.
PointCount(); i++ )
1594 ssize_t arcIndex = aOtherLine.
ArcIndex( i );
1622 if(
chain.PointCount() > 2 )
1624 chain.m_arcs.push_back( aArc );
1625 chain.m_arcs.back().SetWidth( 0 );
1627 for(
auto& sh :
chain.m_shapes )
1645 wxCHECK( aVertex <
m_points.size(), );
1647 if( aVertex > 0 &&
IsPtOnArc( aVertex ) )
1666 wxCHECK( aVertex <
m_points.size(), );
1668 if( aVertex > 0 &&
IsPtOnArc( aVertex ) )
1672 ssize_t arc_pos =
m_arcs.size();
1674 for(
auto arc_it =
m_shapes.rbegin() ;
1675 arc_it !=
m_shapes.rend() + aVertex;
1680 arc_pos = std::max( ( *arc_it ).first, ( *arc_it ).second );
1689 [&]( ssize_t& aIndex )
1691 if( aIndex >= arc_pos )
1707 std::vector<std::pair<ssize_t, ssize_t>> new_points(
chain.PointCount(),
1708 { arc_pos, SHAPE_IS_PT } );
1710 m_shapes.insert(
m_shapes.begin() + aVertex, new_points.begin(), new_points.end() );
1734 const int ptCount =
static_cast<int>(
m_points.size() );
1736 const int segMinX = std::min( aSeg.
A.
x, aSeg.
B.
x );
1737 const int segMaxX = std::max( aSeg.
A.
x, aSeg.
B.
x );
1738 const int segMinY = std::min( aSeg.
A.
y, aSeg.
B.
y );
1739 const int segMaxY = std::max( aSeg.
A.
y, aSeg.
B.
y );
1741 for(
int s = 0; s < segCount; s++ )
1746 if( std::max( ptA.
x, ptB.
x ) < segMinX || std::min( ptA.
x, ptB.
x ) > segMaxX
1747 || std::max( ptA.
y, ptB.
y ) < segMinY || std::min( ptA.
y, ptB.
y ) > segMaxY )
1762 aIp.push_back( is );
1767 sort( aIp.begin(), aIp.end(),
comp );
1776 const int ptCount =
static_cast<int>(
m_points.size() );
1778 const int segMinX = std::min( aSeg.
A.
x, aSeg.
B.
x );
1779 const int segMaxX = std::max( aSeg.
A.
x, aSeg.
B.
x );
1780 const int segMinY = std::min( aSeg.
A.
y, aSeg.
B.
y );
1781 const int segMaxY = std::max( aSeg.
A.
y, aSeg.
B.
y );
1783 for(
int s = 0; s < segCount; s++ )
1788 if( std::max( ptA.
x, ptB.
x ) < segMinX || std::min( ptA.
x, ptB.
x ) > segMaxX
1789 || std::max( ptA.
y, ptB.
y ) < segMinY || std::min( ptA.
y, ptB.
y ) > segMaxY )
1803 bool aExcludeColinearAndTouching,
BOX2I* aChainBBox )
const
1808 if( ourSegCount == 0 || theirSegCount == 0 )
1812 const int ourPtCount =
static_cast<int>(
m_points.size() );
1813 const int theirPtCount =
static_cast<int>( aChain.
CPoints().size() );
1814 const std::vector<VECTOR2I>& theirPts = aChain.
CPoints();
1816 thread_local std::vector<SEG> theirSegs;
1817 thread_local std::vector<SEG_EXTENT> sorted;
1819 theirSegs.resize( theirSegCount );
1820 sorted.resize( theirSegCount );
1823 for(
int i = 0; i < theirSegCount; i++ )
1826 const VECTOR2I& pb = theirPts[i + 1 < theirPtCount ? i + 1 : 0];
1827 theirSegs[i] =
SEG( pa, pb, i );
1831 for(
int i = 0; i < theirSegCount; i++ )
1833 const SEG& s = theirSegs[i];
1834 sorted[i] = { std::min( s.
A.
x, s.
B.
x ), std::max( s.
A.
x, s.
B.
x ),
1835 std::min( s.
A.
y, s.
B.
y ), std::max( s.
A.
y, s.
B.
y ), i };
1838 std::sort( sorted.begin(), sorted.end(),
1839 [](
const SEG_EXTENT& a,
const SEG_EXTENT& b ) { return a.minX < b.minX; } );
1841 for(
int s1 = 0; s1 < ourSegCount; s1++ )
1846 const int ourMinX = std::min( a1.
x, b1.
x );
1847 const int ourMaxX = std::max( a1.
x, b1.
x );
1848 const int ourMinY = std::min( a1.
y, b1.
y );
1849 const int ourMaxY = std::max( a1.
y, b1.
y );
1851 if( ourMaxX < bbOther.m_Left || ourMinX > bbOther.
m_Right
1852 || ourMaxY < bbOther.m_Top || ourMinY > bbOther.
m_Bottom )
1857 const SEG a( a1, b1, s1 );
1861 auto rightEnd = std::upper_bound( sorted.begin(), sorted.end(), ourMaxX,
1862 [](
int val,
const SEG_EXTENT& e )
1864 return val < e.minX;
1867 for(
auto jt = sorted.begin(); jt != rightEnd; ++jt )
1869 if( jt->maxX < ourMinX || jt->maxY < ourMinY || jt->minY > ourMaxY )
1872 const SEG& b = theirSegs[jt->segIdx];
1883 if( !aExcludeColinearAndTouching && a.
Collinear( b ) )
1889 aIp.push_back( is );
1897 aIp.push_back( is );
1904 aIp.push_back( is );
1912 aIp.push_back( is );
1943 aIp.push_back( is );
1959 bool indexMatch =
true;
1969 indexMatch = ( i == aIndex );
1975 sum += ( aP - seg.
A ).EuclideanNorm();
1987 bool aUseBBoxCache )
const
1992 const int pointCount =
static_cast<int>(
m_points.size() );
1999 bool inside =
false;
2001 for(
int i = 0; i < pointCount; )
2004 const VECTOR2I& p2 = pts[i == pointCount ? 0 : i];
2010 const int d =
rescale( diff.
x, ( aPt.
y - p1.
y ), diff.
y );
2012 if( ( ( p1.
y >= aPt.
y ) != ( p2.
y >= aPt.
y ) ) && ( aPt.
x - p1.
x < d ) )
2016 if( aAccuracy <= 1 )
2024 bool aUseBBoxCache )
const
2048 bool inside =
false;
2050 for(
int i = 0; i < pointCount; )
2059 const int d =
rescale( diff.
x, ( aPt.
y - p1.
y ), diff.
y );
2061 if( ( ( p1.
y >= aPt.
y ) != ( p2.
y >= aPt.
y ) ) && ( aPt.
x - p1.
x < d ) )
2067 if( aAccuracy <= 1 )
2082 const int threshold = aAccuracy + 1;
2083 const int64_t thresholdSq = int64_t( threshold ) * threshold;
2090 else if( pointCount == 1 )
2093 return distSq <= thresholdSq ? 0 : -1;
2098 for(
size_t i = 0; i < segCount; i++ )
2102 if( s.
A == aPt || s.
B == aPt )
2124 if( s.
A == aP || s.
B == aP )
2138 const int ptCount =
static_cast<int>(
m_points.size() );
2142 return std::optional<INTERSECTION>();
2145 auto endIdx = [ptCount](
int i )
2151 for(
int s1 = 0; s1 < segCount; s1++ )
2157 const int s1MinX = std::min( a1.
x, b1.
x ) - 2;
2158 const int s1MaxX = std::max( a1.
x, b1.
x ) + 2;
2159 const int s1MinY = std::min( a1.
y, b1.
y ) - 2;
2160 const int s1MaxY = std::max( a1.
y, b1.
y ) + 2;
2162 for(
int s2 = s1 + 1; s2 < segCount; s2++ )
2167 const int s2MinX = std::min( a2.
x, b2.
x );
2168 const int s2MaxX = std::max( a2.
x, b2.
x );
2170 if( s1MaxX < s2MinX || s2MaxX < s1MinX )
2173 const int s2MinY = std::min( a2.
y, b2.
y );
2174 const int s2MaxY = std::max( a2.
y, b2.
y );
2176 if( s1MaxY < s2MinY || s2MaxY < s1MinY )
2179 const SEG seg1( a1, b1, s1 );
2181 if( s1 + 1 != s2 && seg1.
Contains( a2 ) )
2193 !( closed && s1 == 0 && s2 == segCount - 1 ) )
2217 return std::optional<INTERSECTION>();
2234const std::optional<SHAPE_LINE_CHAIN::INTERSECTION>
2237 auto pointsClose = [](
const VECTOR2I& aPt1,
const VECTOR2I& aPt2 ) ->
bool
2239 return (
VECTOR2D( aPt1 ) - aPt2 ).SquaredEuclideanNorm() <= 2.0;
2242 auto collideArcSeg = [&pointsClose](
const SHAPE_ARC& aArc,
const SEG& aSeg,
int aClearance = 0,
2248 std::vector<VECTOR2I> candidatePts =
circle.Intersect( aSeg );
2250 for(
const VECTOR2I& candidate : candidatePts )
2253 if( aArc.
GetP1() == aSeg.A && pointsClose( candidate, aSeg.A ) )
2256 if( aSeg.B == aArc.
GetP0() && pointsClose( candidate, aSeg.B ) )
2259 bool collides = aArc.
Collide( candidate, aClearance,
nullptr, aLocation );
2271 std::vector<VECTOR2I> candidatePts;
2273 aArc1.
Intersect( aArc2, &candidatePts );
2275 for(
const VECTOR2I& candidate : candidatePts )
2278 if( aArc1.
GetP1() == aArc2.GetP0() && pointsClose( candidate, aArc1.
GetP1() ) )
2281 if( aArc2.GetP1() == aArc1.
GetP0() && pointsClose( candidate, aArc2.GetP1() ) )
2285 *aLocation = candidate;
2293 auto collideSegSeg = [
this](
int s1,
int s2,
INTERSECTION& is )
2300 if( s1 + 1 != s2 && seg1.
Contains( s2a ) )
2303 is.index_their = s2;
2314 is.index_their = s2;
2325 is.index_their = s2;
2336 std::vector<SHAPE_KEY> shapeCache;
2337 for(
int si = 0; si != -1; si =
NextShape( si ) )
2341 shapeCache.emplace_back( si, arci,
2346 for(
size_t sk1 = 0; sk1 < shapeCache.size(); sk1++ )
2348 for(
size_t sk2 = sk1 + 1; sk2 < shapeCache.size(); sk2++ )
2397 return std::optional<SHAPE_LINE_CHAIN::INTERSECTION>();
2402 bool aAllowInternalShapePoints )
const
2410 int min_d = std::numeric_limits<int>::max();
2424 if( !aAllowInternalShapePoints )
2447 return nearestArc.
GetP1();
2449 return nearestArc.
GetP0();
2469 dist = std::numeric_limits<int>::max();
2482 return CPoint( nearest );
2488 int min_d = std::numeric_limits<int>::max();
2508 std::stringstream ss;
2510 ss <<
"SHAPE_LINE_CHAIN( { ";
2520 ss <<
"}, " << (
m_closed ?
"true" :
"false" );
2536 bool aCyclicalCompare,
2537 int aEpsilon )
const
2543 if( a.m_points.size() != b.
m_points.size() )
2546 if( aCyclicalCompare )
2548 std::vector<VECTOR2I> aVerts = a.m_points;
2549 std::vector<VECTOR2I> bVerts = b.
m_points;
2551 auto centroid = [](
const std::vector<VECTOR2I>& pts )
2553 double sx = 0.0, sy = 0.0;
2554 for(
const auto& p : pts )
2559 return std::pair<double, double>( sx / pts.size(), sy / pts.size() );
2562 auto aC = centroid( aVerts );
2563 auto bC = centroid( bVerts );
2566 [](
const std::pair<double, double>& c,
const VECTOR2I& p1,
const VECTOR2I& p2 )
2568 double a1 = atan2( p1.y - c.second, p1.x - c.first );
2569 double a2 = atan2( p2.y - c.second, p2.x - c.first );
2574 std::sort( aVerts.begin(), aVerts.end(),
2577 return angleCmp( aC, p1, p2 );
2580 std::sort( bVerts.begin(), bVerts.end(),
2583 return angleCmp( bC, p1, p2 );
2586 for(
size_t i = 0; i < aVerts.size(); i++ )
2588 if( abs( aVerts[i].x - bVerts[i].x ) > aEpsilon
2589 || abs( aVerts[i].y - bVerts[i].y ) > aEpsilon )
2596 for(
int i = 0; i < a.PointCount(); i++ )
2598 if( abs( a.CPoint( i ).x - b.
CPoint( i ).
x ) > aEpsilon
2599 || abs( a.CPoint( i ).y - b.
CPoint( i ).
y ) > aEpsilon )
2632 if( n_pts > aStream.str().size() )
2638 if( n_arcs > aStream.str().size() )
2641 for(
size_t i = 0; i < n_pts; i++ )
2653 for(
size_t i = 0; i < n_arcs; i++ )
2675 if( aPathLength == 0 )
2683 if( total + l >= aPathLength )
2686 return s.
A + d.
Resize( aPathLength - total );
2706 for(
int i = 0, j = size - 1; i < size; ++i )
2714 return std::fabs( area * 0.5 );
2722 std::vector<VECTOR2I> pts_unique;
2723 std::vector<std::pair<ssize_t, ssize_t>> shapes_unique;
2754 std::pair<ssize_t,ssize_t> shapeToKeep =
m_shapes[i];
2759 assert( shapeToKeep.first <
static_cast<int>(
m_arcs.size() ) );
2760 assert( shapeToKeep.second <
static_cast<int>(
m_arcs.size() ) );
2762 pts_unique.push_back(
CPoint( i ) );
2763 shapes_unique.push_back( shapeToKeep );
2771 for(
size_t ii = 0; ii < pts_unique.size(); ++ii )
2773 const VECTOR2I p0 = pts_unique[ii];
2776 m_shapes.push_back( shapes_unique[ii] );
2787 std::vector<VECTOR2I> new_points;
2788 std::vector<std::pair<ssize_t, ssize_t>> new_shapes;
2790 new_points.reserve(
m_points.size() );
2791 new_shapes.reserve(
m_shapes.size() );
2793 for(
size_t start_idx = 0; start_idx <
m_points.size(); )
2795 new_points.push_back(
m_points[start_idx] );
2796 new_shapes.push_back(
m_shapes[start_idx] );
2803 size_t end_idx = ( start_idx + 2 ) %
m_points.size();
2804 bool can_simplify =
true;
2806 while( can_simplify && end_idx != start_idx && ( end_idx > start_idx ||
m_closed ) )
2809 for(
size_t test_idx = ( start_idx + 1 ) %
m_points.size();
2810 test_idx != end_idx;
2811 test_idx = ( test_idx + 1 ) %
m_points.size() )
2818 can_simplify =
false;
2825 can_simplify =
false;
2833 end_idx = ( end_idx + 1 ) %
m_points.size();
2838 if( end_idx == ( start_idx + 2 ) %
m_points.size() )
2845 size_t new_start_idx = ( end_idx +
m_points.size() - 1 ) %
m_points.size();
2848 if( new_start_idx <= start_idx )
2851 start_idx = new_start_idx;
2856 if( new_points.size() == 1 )
2858 new_points.push_back(
m_points.back() );
2859 new_shapes.push_back(
m_shapes.back() );
2866 new_points.push_back(
m_points.back() );
2867 new_shapes.push_back(
m_shapes.back() );
2872 m_points = std::move( new_points );
2873 m_shapes = std::move( new_shapes );
2889 int i_start = l.
Find( m );
2890 int i_end = l.
Find( n );
2892 if( i_start > i_end )
2895 i_start = l.
Find( m );
2896 i_end = l.
Find( n );
2899 aPre = l.
Slice( 0, i_start );
2900 aPost = l.
Slice( i_end, -1 );
2901 aMid = l.
Slice( i_start, i_end );
2908 std::vector<VECTOR2I> pts_unique;
2909 std::vector<std::pair<ssize_t, ssize_t>> shapes_unique;
2942 std::pair<ssize_t,ssize_t> shapeToKeep =
m_shapes[i];
2947 assert( shapeToKeep.first <
static_cast<int>(
m_arcs.size() ) );
2948 assert( shapeToKeep.second <
static_cast<int>(
m_arcs.size() ) );
2950 pts_unique.push_back(
CPoint( i ) );
2951 shapes_unique.push_back( shapeToKeep );
2958 np = pts_unique.size();
2972 && (
SEG( p0, pts_unique[n + 2] ).LineDistance( pts_unique[n + 1] ) <= 1
2973 ||
SEG( p0, pts_unique[n + 2] ).Collinear(
SEG( p0, pts_unique[n + 1] ) ) ) )
2978 m_shapes.push_back( shapes_unique[i] );
2985 m_points.push_back( pts_unique[np - 1] );
2986 m_shapes.push_back( shapes_unique[np - 1] );
2995 m_points.push_back( pts_unique[np - 2] );
2996 m_shapes.push_back( shapes_unique[np - 2] );
2999 m_points.push_back( pts_unique[np - 1] );
3000 m_shapes.push_back( shapes_unique[np - 1] );
3009 bool aSimplify )
const
3015 poly.
OffsetLineChain( *
this, aAmount, aCornerStrategy, aMaxError, aSimplify );
3033 outline.
Split( start,
true );
3036 const int idA = outline.
Find( start );
3037 const int idB = outline.
Find(
end );
3039 if( idA == -1 || idB == -1 )
3045 for(
int i = idA;; )
3064 for(
int i = idB;; )
3083 if( aLeft.
CPoint( 0 ) != start )
3086 wxASSERT( aLeft.
CPoint( 0 ) == start );
3089 if( aRight.
CPoint( 0 ) != start )
3092 wxASSERT( aRight.
CPoint( 0 ) == start );
3096 int sideLeft = base.
Side( aLeft.
CPoint( 1 ) );
3097 int sideRight = base.
Side( aRight.
CPoint( 1 ) );
3099 if( sideLeft == 0 || sideRight == 0 )
3102 if( sideLeft == sideRight )
3105 if( sideLeft > 0 && sideRight < 0 )
3106 std::swap( aLeft, aRight );
3174 if( ( d > 0 ) == ( ipNext.
y > ip.
y ) )
3192 if( ( d > 0 ) == ( ipNext.
y > ip.
y ) )
3212 for(
int i = 1; i < aPolyline.
PointCount(); i++ )
3214 auto p = aPolyline.
CPoint( i );
3253 size_t nextIdx = aSegment + 1;
3255 if( nextIdx >
m_shapes.size() - 1 )
3284 size_t prevIndex = aIndex - 1;
3288 else if( aIndex >
m_points.size() -1 )
ERROR_LOC
When approximating an arc or circle, should the error be placed on the outside or inside of the curve...
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Represent basic circle geometry with utility geometry functions.
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).
bool NearestPoints(const SEG &aSeg, VECTOR2I &aPtA, VECTOR2I &aPtB, int64_t &aDistSq) const
Compute closest points between this segment and aSeg.
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.
int GetWidth() const override
const SHAPE_LINE_CHAIN ConvertToPolyline(int aMaxError=DefaultAccuracyForPCB(), int *aActualError=nullptr) const
Construct a SHAPE_LINE_CHAIN of segments from a given arc.
int Intersect(const CIRCLE &aArc, std::vector< VECTOR2I > *aIpsBuffer) const
Find intersection points between this arc and a CIRCLE.
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,...
static int DefaultAccuracyForPCB()
const VECTOR2I & GetP0() const
void SetWidth(int aWidth) override
const VECTOR2I & GetCenter() 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
SHAPE_LINE_CHAIN_BASE(SHAPE_TYPE aType)
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
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
int Distance(const VECTOR2I &aP, bool aOutlineOnly) const
bool IsClosed() const override
virtual const VECTOR2I GetPoint(int aIndex) const override
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.
SHAPE_LINE_CHAIN()
Initialize an empty line chain.
int m_width
Width of the segments (for BBox calculations in RTree) TODO Adjust usage of SHAPE_LINE_CHAIN to accou...
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.
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.
void Simplify(int aTolerance=0)
Simplify the line chain by removing colinear adjacent segments and duplicate vertices.
SEG Segment(int aIndex) const
Return a copy of the aIndex-th segment in the line chain.
BOX2I m_bbox
cached bounding box
BOX2I * GetCachedBBox() const override
bool m_closed
is the line chain closed?
friend class SHAPE_POLY_SET
const std::vector< SHAPE_ARC > & CArcs() const
const std::optional< INTERSECTION > SelfIntersectingWithArcs() const
Check if the line chain is self-intersecting.
bool Intersects(const SEG &aSeg) 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.
SHAPE_LINE_CHAIN & Simplify2(bool aRemoveColinear=true)
void amendArc(size_t aArcIndex, const VECTOR2I &aNewStart, const VECTOR2I &aNewEnd)
bool ClosestPoints(const SHAPE_LINE_CHAIN &aOther, VECTOR2I &aPt0, VECTOR2I &aPt1) const
Finds closest points between this and the other line chain.
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
bool CompareGeometry(const SHAPE_LINE_CHAIN &aOther, bool aCyclicalCompare=false, int aEpsilon=0) const
Compare this line chain with another one.
const VECTOR2I NearestPoint(const VECTOR2I &aP, bool aAllowInternalShapePoints=true) const
Find a point on the line chain that is closest to point aP.
const SHAPE_LINE_CHAIN Slice(int aStartIndex, int aEndIndex) const
Return a subset of this line chain containing the [start_index, end_index] range of points.
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 VECTOR2I & CLastPoint() const
Return the last point in the line chain.
void Mirror(const VECTOR2I &aRef, FLIP_DIRECTION aFlipDirection)
Mirror the line points about y or x (or both).
bool ClosestSegmentsFast(const SHAPE_LINE_CHAIN &aOther, VECTOR2I &aPt0, VECTOR2I &aPt1) const
Finds closest points between segments of this and the other line chain.
const std::string Format(bool aCplusPlus=true) const override
static bool ClosestSegments(const VECTOR2I &aMyPrevPt, const point_citer &aMyStart, const point_citer &aMyEnd, const VECTOR2I &aOtherPrevPt, const point_citer &aOtherStart, const point_citer &aOtherEnd, VECTOR2I &aPt0, VECTOR2I &aPt1, int64_t &aDistSq)
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.
bool PointInside(const VECTOR2I &aPt, int aAccuracy=0, bool aUseBBoxCache=false) const override
Check if point aP lies inside a closed shape.
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 std::vector< VECTOR2I > & CPoints() const
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
std::vector< VECTOR2I >::const_iterator point_citer
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.
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
SHAPE(SHAPE_TYPE aType)
Create an empty shape of type aType.
virtual int GetWidth() const
constexpr extended_type SquaredDistance(const VECTOR2< T > &aVector) const
Compute the squared distance between two vectors.
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
@ LEFT_RIGHT
Flip left to right (around the Y axis)
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)
int getArcPolygonizationMaxError()
std::vector< FAB_LAYER_COLOR > dummy
A min-max version of BOX2 for fast intersection checking.
bool Intersects(const BOX2I_MINMAX &aOther) const
Holds information on each point of a SHAPE_LINE_CHAIN that is retrievable after an operation with Cli...
SHAPE_KEY(int aFirstIdx, int aArcIdx, const BOX2I_MINMAX &aBBox)
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)
const SHAPE_LINE_CHAIN chain
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
bool TestSegmentHit(const VECTOR2I &aRefPoint, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aDist)
Test if aRefPoint is with aDistance on the line defined by aStart and aEnd.
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.
T rescale(T aNumerator, T aValue, T aDenominator)
Scale a number (value) by rational (numerator/denominator).
VECTOR2< int32_t > VECTOR2I
VECTOR2< double > VECTOR2D
VECTOR2< int64_t > VECTOR2L