| 42 | } |
| 43 | |
| 44 | Expected<Mesh> alignContoursToMesh( const Mesh& mesh, const Contours2f& contours, const ContoursMeshAlignParams& params ) |
| 45 | { |
| 46 | MR_TIMER; |
| 47 | auto contoursMesh = PlanarTriangulation::triangulateContours( contours ); |
| 48 | auto bbox = contoursMesh.computeBoundingBox(); |
| 49 | if ( !bbox.valid() ) |
| 50 | return unexpected( "Contours mesh is empty" ); |
| 51 | |
| 52 | const float cStartDepth = bbox.diagonal() * 0.05f; // use relative depth to avoid floating errors |
| 53 | addBaseToPlanarMesh( contoursMesh, -cStartDepth ); |
| 54 | |
| 55 | auto diagonal = bbox.size(); diagonal.z = cStartDepth; |
| 56 | AffineXf3f transform; |
| 57 | |
| 58 | const auto& vecx = params.xDirection.normalized(); |
| 59 | const auto norm = params.zDirection != nullptr ? *params.zDirection : mesh.pseudonormal( params.meshPoint ); |
| 60 | const auto vecy = cross( vecx, -norm ).normalized(); |
| 61 | |
| 62 | const Vector3f pivotCoord{ bbox.min.x + diagonal.x * params.pivotPoint.x, |
| 63 | bbox.min.y + diagonal.y * params.pivotPoint.y, |
| 64 | 0.0f }; |
| 65 | |
| 66 | auto rotQ = Quaternionf( Vector3f::plusX(), vecx ); |
| 67 | // handle degenerated case |
| 68 | auto newY = rotQ( Vector3f::plusY() ); |
| 69 | auto dotY = dot( newY, vecy ); |
| 70 | if ( std::abs( std::abs( dotY ) - 1.0f ) < 10.0f * std::numeric_limits<float>::epsilon() ) |
| 71 | { |
| 72 | if ( dotY < 0.0f ) |
| 73 | rotQ = Quaternionf( vecx, PI_F ) * rotQ; |
| 74 | } |
| 75 | else |
| 76 | rotQ = Quaternionf( newY, vecy ) * rotQ; |
| 77 | AffineXf3f rot = AffineXf3f::linear( rotQ ); |
| 78 | |
| 79 | auto translation = mesh.triPoint( params.meshPoint ); |
| 80 | |
| 81 | transform = |
| 82 | AffineXf3f::translation( translation ) * |
| 83 | rot |
| 84 | * AffineXf3f::translation( -pivotCoord ); |
| 85 | |
| 86 | auto& contoursMeshPoints = contoursMesh.points; |
| 87 | for ( auto& p : contoursMeshPoints ) |
| 88 | p = transform( p ); |
| 89 | |
| 90 | auto plusOffsetDir = norm * std::abs( params.extrusion ); |
| 91 | auto minusOffsetDir = norm * ( cStartDepth - std::abs( params.extrusion ) ); |
| 92 | const auto maxMovement = std::max( 0.0f, params.maximumShift ); |
| 93 | for ( int i = 0; i < contoursMeshPoints.size() / 2; ++i ) |
| 94 | { |
| 95 | PointOnFace hit; |
| 96 | auto inter = rayMeshIntersect( mesh, Line3f{ contoursMeshPoints[VertId( i )] + norm * bbox.size().y, -norm } ); |
| 97 | if ( !inter ) |
| 98 | return unexpected( std::string( "Cannot align contours" ) ); |
| 99 | hit = inter.proj; |
| 100 | |
| 101 | auto coords = hit.point; |
no test coverage detected