| 1357 | } |
| 1358 | |
| 1359 | std::vector<GCommand> replaceLineSegmentsWithCircularArcs( const std::span<GCommand>& path, float eps, float maxRadius, Axis axis ) |
| 1360 | { |
| 1361 | if ( path.size() < 5 ) |
| 1362 | return {}; |
| 1363 | |
| 1364 | std::vector<GCommand> res; |
| 1365 | |
| 1366 | int startIdx = 0, endIdx = 0; |
| 1367 | Vector2f bestArcCenter, bestArcStart, bestArcEnd; |
| 1368 | bool CCWrotation = false; |
| 1369 | double bestArcR = 0; |
| 1370 | for ( int i = startIdx + 2; i < path.size(); ++i ) |
| 1371 | { |
| 1372 | const GCommand& d2 = path[i]; |
| 1373 | const int middleI = ( i + startIdx ) / 2; |
| 1374 | const GCommand& d1 = path[middleI]; |
| 1375 | |
| 1376 | const Vector2f p0 = project( path[startIdx], axis ); |
| 1377 | const Vector2f p1 = project( d1, axis ); |
| 1378 | const Vector2f p2 = project( d2, axis ); |
| 1379 | |
| 1380 | const Vector2f dif1 = p1 - p0; |
| 1381 | const Vector2f dif2 = p2 - p1; |
| 1382 | |
| 1383 | Vector2f pCenter; |
| 1384 | if ( dot( dif1, dif2 ) > 0 |
| 1385 | && calcCircleCenter( p0, p1, p2, pCenter ) ) |
| 1386 | { |
| 1387 | const double rArc = ( pCenter - p0 ).length(); |
| 1388 | const double r2Max = sqr( rArc + eps ); |
| 1389 | const double r2Min = sqr( rArc - eps ); |
| 1390 | |
| 1391 | const bool ccwRotation = cross( dif1, dif2 ) > 0; |
| 1392 | |
| 1393 | Vector2f dirStart = rotate90( p0 - pCenter ); |
| 1394 | Vector2f dirEnd = rotateMinus90( p2 - pCenter ); |
| 1395 | if ( ccwRotation ) |
| 1396 | { |
| 1397 | dirStart = -dirStart; |
| 1398 | dirEnd = -dirEnd; |
| 1399 | } |
| 1400 | |
| 1401 | bool allInTolerance = true; |
| 1402 | Vector2f pPrev = p0; |
| 1403 | for ( int k = startIdx + 1; k <= i; ++k ) |
| 1404 | { |
| 1405 | const Vector2f pk = project( path[k], axis ); |
| 1406 | double r2k = ( pCenter - pk ).lengthSq(); |
| 1407 | const Vector2f pkMiddle = ( pk + pPrev ) * 0.5f; |
| 1408 | double r2kMiddle = ( pCenter - pkMiddle ).lengthSq(); |
| 1409 | if ( r2k < r2Min || r2k > r2Max |
| 1410 | || r2kMiddle < r2Min || r2kMiddle > r2Max ) |
| 1411 | { |
| 1412 | allInTolerance = false; |
| 1413 | break; |
| 1414 | } |
| 1415 | bool insideArc = dot( dirStart, pk - p0 ) >= 0 && dot( dirEnd, pk - p2 ) >= 0; |
| 1416 | if ( !insideArc ) |
no test coverage detected