| 495 | } |
| 496 | |
| 497 | Expected<ToolPathResult> lacingToolPath( const MeshPart& mp, const ToolPathParams& params, Axis cutDirection ) |
| 498 | { |
| 499 | if ( cutDirection != Axis::X && cutDirection != Axis::Y ) |
| 500 | return unexpected( "Lacing can be done along the X or Y axis" ); |
| 501 | |
| 502 | const bool cutDirectionIsX = cutDirection == Axis::X; |
| 503 | const auto cutDirectionIdx = int( cutDirection ); |
| 504 | const auto sideDirection = cutDirectionIsX ? Axis::Y : Axis::X; |
| 505 | const auto sideDirectionIdx = int( sideDirection ); |
| 506 | |
| 507 | ToolPathResult res; |
| 508 | |
| 509 | if ( !params.offsetMesh ) |
| 510 | { |
| 511 | auto preprocessedMesh = preprocessMesh( mp.mesh, params, false ); |
| 512 | if ( !preprocessedMesh ) |
| 513 | return unexpected( preprocessedMesh.error() ); |
| 514 | |
| 515 | res.modifiedMesh = std::move( *preprocessedMesh ); |
| 516 | } |
| 517 | |
| 518 | const auto& mesh = params.offsetMesh ? params.offsetMesh->mesh : res.modifiedMesh; |
| 519 | |
| 520 | const auto box = mesh.computeBoundingBox(); |
| 521 | const float safeZ = std::max( box.max.z + 10.0f * params.millRadius, params.safeZ ); |
| 522 | |
| 523 | const Vector3f normal = cutDirectionIsX ? Vector3f::plusX() : Vector3f::plusY(); |
| 524 | const auto plane = MR::Plane3f::fromDirAndPt( normal, box.max ); |
| 525 | const int steps = int( std::floor( ( plane.d - box.min[cutDirectionIdx] ) / params.sectionStep ) ); |
| 526 | |
| 527 | MeshEdgePoint lastEdgePoint = {}; |
| 528 | // bypass direction is not meaningful for this toolpath, so leave it as default |
| 529 | auto allSections = extractAllSections( mesh, box, cutDirection, params.sectionStep, steps, BypassDirection::Clockwise, subprogress( params.cb, 0.25f, 0.5f ) ); |
| 530 | if ( allSections.empty() ) |
| 531 | return unexpectedOperationCanceled(); |
| 532 | const auto sbp = subprogress( params.cb, 0.5f, 1.0f ); |
| 533 | |
| 534 | float lastFeed = 0; |
| 535 | const bool expandToolpath = params.toolpathExpansion > 0.f; |
| 536 | |
| 537 | Vector3f lastPoint; |
| 538 | // if the last point is equal to parameter, do nothing |
| 539 | // otherwise add new move |
| 540 | const auto addPoint = [&] ( const Vector3f& point ) |
| 541 | { |
| 542 | if ( lastPoint == point ) |
| 543 | return; |
| 544 | |
| 545 | if ( lastFeed == params.baseFeed ) |
| 546 | { |
| 547 | cutDirectionIsX ? |
| 548 | res.commands.push_back( { .y = point.y, .z = point.z } ) : |
| 549 | res.commands.push_back( { .x = point.x, .z = point.z } ); |
| 550 | } |
| 551 | else |
| 552 | { |
| 553 | cutDirectionIsX ? |
| 554 | res.commands.push_back( { .feed = params.baseFeed, .y = point.y, .z = point.z } ) : |
nothing calls this directly
no test coverage detected