| 444 | } |
| 445 | |
| 446 | void BooleanTool::executeForLine(const PathObject* area, const PathObject* line, BooleanTool::PathObjects& out_objects) const |
| 447 | { |
| 448 | if (op != BooleanTool::Intersection && op != BooleanTool::Difference) |
| 449 | { |
| 450 | Q_ASSERT_X(false, "BooleanTool::executeForLine", "Only intersection and difference are supported."); |
| 451 | return; // no-op in release build |
| 452 | } |
| 453 | if (line->parts().size() != 1) |
| 454 | { |
| 455 | Q_ASSERT_X(false, "BooleanTool::executeForLine", "Only single-part lines are supported."); |
| 456 | return; // no-op in release build |
| 457 | } |
| 458 | |
| 459 | // Calculate all intersection points of line with the area path |
| 460 | PathObject::Intersections intersections; |
| 461 | line->calcAllIntersectionsWith(area, intersections); |
| 462 | intersections.normalize(); |
| 463 | |
| 464 | PathObject* first_segment = nullptr; |
| 465 | PathObject* last_segment = nullptr; |
| 466 | |
| 467 | const auto& part = line->parts().front(); |
| 468 | const auto& path_coords = part.path_coords; |
| 469 | |
| 470 | // Only one segment? |
| 471 | if (intersections.empty()) |
| 472 | { |
| 473 | auto middle_length = part.length(); |
| 474 | auto middle = SplitPathCoord::at(path_coords, middle_length); |
| 475 | if (area->isPointInsideArea(middle.pos) == (op == BooleanTool::Intersection)) |
| 476 | out_objects.push_back(line->duplicate()); |
| 477 | return; |
| 478 | } |
| 479 | |
| 480 | // First segment |
| 481 | auto middle_length = intersections[0].length / 2; |
| 482 | auto middle = SplitPathCoord::at(path_coords, middle_length); |
| 483 | if (area->isPointInsideArea(middle.pos) == (op == BooleanTool::Intersection)) |
| 484 | { |
| 485 | PathObject* segment = line->duplicate(); |
| 486 | segment->changePathBounds(0, 0.0, intersections[0].length); |
| 487 | first_segment = segment; |
| 488 | } |
| 489 | |
| 490 | // Middle segments |
| 491 | for (std::size_t i = 0; i < intersections.size() - 1; ++i) |
| 492 | { |
| 493 | middle_length = (intersections[i].length + intersections[i+1].length) / 2; |
| 494 | auto middle = SplitPathCoord::at(path_coords, middle_length); |
| 495 | if (area->isPointInsideArea(middle.pos) == (op == BooleanTool::Intersection)) |
| 496 | { |
| 497 | PathObject* segment = line->duplicate(); |
| 498 | segment->changePathBounds(0, intersections[i].length, intersections[i+1].length); |
| 499 | out_objects.push_back(segment); |
| 500 | } |
| 501 | } |
| 502 | |
| 503 | // Last segment |
no test coverage detected