| 396 | } |
| 397 | |
| 398 | BooleanResult booleanImpl( Mesh&& meshA, Mesh&& meshB, BooleanOperation operation, const BooleanParameters& params, BooleanInternalParameters intParams ) |
| 399 | { |
| 400 | MR_TIMER; |
| 401 | BooleanResult result; |
| 402 | CoordinateConverters converters; |
| 403 | PreciseCollisionResult intersections; |
| 404 | ContinuousContours contours; |
| 405 | |
| 406 | bool needCutMeshA = operation != BooleanOperation::InsideB && operation != BooleanOperation::OutsideB; |
| 407 | bool needCutMeshB = operation != BooleanOperation::InsideA && operation != BooleanOperation::OutsideA; |
| 408 | |
| 409 | converters = getVectorConverters( meshA, meshB, params.rigidB2A ); |
| 410 | |
| 411 | auto loneCb = subprogress( params.cb, 0.0f, 0.8f ); |
| 412 | |
| 413 | FaceHashMap new2orgSubdivideMapA; |
| 414 | FaceHashMap new2orgSubdivideMapB; |
| 415 | std::vector<int> prevLoneContoursIds; |
| 416 | int iters = 0; |
| 417 | const int cMaxFixLoneIterations = 100; |
| 418 | bool aSubdivided = false; |
| 419 | bool bSubdivided = false; |
| 420 | for ( ;; iters++ ) |
| 421 | { |
| 422 | // find intersections |
| 423 | intersections = findCollidingEdgeTrisPrecise( meshA, meshB, converters.toInt, params.rigidB2A ); |
| 424 | // order intersections |
| 425 | contours = orderIntersectionContours( meshA.topology, meshB.topology, intersections ); |
| 426 | // find lone |
| 427 | auto loneContoursIds = detectLoneContours( contours ); |
| 428 | |
| 429 | if ( loneCb && !loneCb( ( std::log10( float( iters + 1 ) * 0.1f ) + 2.0f ) / 3.0f ) ) |
| 430 | return { .errorString = stringOperationCanceled() }; |
| 431 | |
| 432 | if ( !loneContoursIds.empty() && ( loneContoursIds == prevLoneContoursIds || iters == cMaxFixLoneIterations ) ) |
| 433 | { |
| 434 | // in some rare cases there are lone contours with zero area that cannot be resolved |
| 435 | // they lead to infinite loop, so just try to remove them |
| 436 | removeLoneContours( contours ); |
| 437 | break; |
| 438 | } |
| 439 | |
| 440 | prevLoneContoursIds = loneContoursIds; |
| 441 | |
| 442 | // separate A lone from B lone |
| 443 | ContinuousContours loneA; |
| 444 | ContinuousContours loneB; |
| 445 | for ( int i = 0; i < loneContoursIds.size(); ++i ) |
| 446 | { |
| 447 | const auto& contour = contours[loneContoursIds[i]]; |
| 448 | if ( contour[0].isEdgeATriB() ) |
| 449 | loneB.push_back( contour ); |
| 450 | else |
| 451 | loneA.push_back( contour ); |
| 452 | } |
| 453 | if ( loneContoursIds.empty() || |
| 454 | ( loneA.empty() && !needCutMeshB ) || |
| 455 | ( loneB.empty() && !needCutMeshA ) ) |
no test coverage detected