| 16 | { |
| 17 | |
| 18 | Expected<Mesh> pointsToMeshFusion( const PointCloud & cloud, const PointsToMeshParameters& params ) |
| 19 | { |
| 20 | MR_TIMER; |
| 21 | |
| 22 | auto cb = params.progress; |
| 23 | |
| 24 | PointsToDistanceVolumeParams p2vParams; |
| 25 | |
| 26 | VertNormals normals; |
| 27 | if ( !cloud.hasNormals() ) |
| 28 | { |
| 29 | auto optTriang = TriangulationHelpers::buildUnitedLocalTriangulations( cloud, |
| 30 | { .radius = params.sigma }, subprogress( cb, 0.0f, 0.2f ) ); |
| 31 | |
| 32 | if ( !optTriang ) |
| 33 | return unexpectedOperationCanceled(); |
| 34 | |
| 35 | auto norms = makeOrientedNormals( cloud, *optTriang, subprogress( cb, 0.2f, 0.4f ) ); |
| 36 | if ( !norms ) |
| 37 | return unexpectedOperationCanceled(); |
| 38 | normals = std::move( *norms ); |
| 39 | p2vParams.ptNormals = &normals; |
| 40 | |
| 41 | cb = subprogress( cb, 0.40f, 1.00f ); |
| 42 | } |
| 43 | |
| 44 | const auto triCb = ( params.ptColors && params.vColors ) ? subprogress( cb, 0.00f, 0.90f ) : cb; |
| 45 | |
| 46 | p2vParams.cb = subprogress( triCb, 0.00f, 0.50f ); |
| 47 | // fused surface can deviate from original points proportionally to params.sigma value |
| 48 | const auto box = cloud.getBoundingBox().expanded( Vector3f::diagonal( 2 * params.sigma ) ); |
| 49 | const auto [origin, dimensions] = calcOriginAndDimensions( box, params.voxelSize ); |
| 50 | p2vParams.origin = origin; |
| 51 | p2vParams.voxelSize = Vector3f::diagonal( params.voxelSize ); |
| 52 | p2vParams.dimensions = dimensions; |
| 53 | p2vParams.sigma = params.sigma; |
| 54 | p2vParams.minWeight = params.minWeight; |
| 55 | p2vParams.invSigmaModifier = params.invSigmaModifier; |
| 56 | p2vParams.sqrtAngleWeight = params.sqrtAngleWeight; |
| 57 | |
| 58 | MarchingCubesParams vmParams; |
| 59 | vmParams.origin = p2vParams.origin; |
| 60 | vmParams.iso = 0; |
| 61 | vmParams.cb = subprogress( triCb, 0.50f, 1.00f ); |
| 62 | vmParams.lessInside = true; |
| 63 | |
| 64 | Expected<Mesh> res; |
| 65 | if ( params.createVolumeCallbackByParts && ( !params.canCreateVolume || params.canCreateVolume( cloud, p2vParams ) ) ) |
| 66 | { |
| 67 | p2vParams.cb = {}; |
| 68 | vmParams.cb = subprogress( triCb, 0.00f, 0.90f ); |
| 69 | |
| 70 | MarchingCubesByParts mesher( p2vParams.dimensions, vmParams ); |
| 71 | res = |
| 72 | params.createVolumeCallbackByParts( cloud, p2vParams, [&mesher] ( const SimpleVolumeMinMax& volume, [[maybe_unused]] int zOffset ) |
| 73 | { |
| 74 | assert( zOffset == mesher.nextZ() ); |
| 75 | return mesher.addPart( volume ); |
no test coverage detected