@@ -119,50 +119,60 @@ void relaxApprox( PointCloud& pointCloud, const PointCloudApproxRelaxParams& par
119119 float radius = params.neighborhoodRadius > 0 .0f ? params.neighborhoodRadius :
120120 pointCloud.getBoundingBox ().diagonal () * 0 .1f ;
121121
122+ bool hasNormals = pointCloud.normals .size () > size_t ( pointCloud.validPoints .find_last () );
123+
122124 for ( int i = 0 ; i < params.iterations ; ++i )
123125 {
124126 newPoints = pointCloud.points ;
125127 BitSetParallelFor ( zone, [&] ( VertId v )
126128 {
127129 PointAccumulator accum;
128- std::vector<VertId> neighbors ;
129- Vector3d centroid;
130+ std::vector<std::pair< VertId, double >> weightedNeighbors ;
131+
130132 findPointsInBall ( pointCloud, pointCloud.points [v], radius,
131133 [&] ( VertId newV, const Vector3f& position )
132134 {
133- Vector3d ptD = Vector3d ( position );
134- centroid += ptD;
135- accum.addPoint ( ptD );
136- neighbors.push_back ( newV );
135+ double w = 1.0 ;
136+ if ( hasNormals )
137+ w = dot ( pointCloud.normals [v], pointCloud.normals [newV] );
138+ if ( w > 0.0 )
139+ {
140+ weightedNeighbors.push_back ( { newV,w } );
141+ accum.addPoint ( Vector3d ( position ), w );
142+ }
137143 } );
138- if ( neighbors .size () < 6 )
144+ if ( weightedNeighbors .size () < 6 )
139145 return ;
140146
141- centroid /= double ( neighbors.size () );
142147 auto & np = newPoints[v];
143148 Vector3f target;
144- auto plane = accum.getBestPlane ();
145149 if ( params.type == RelaxApproxType::Planar )
146- {
147- target = Plane3f ( plane ).project ( np );
148- }
150+ target = accum.getBestPlanef ().project ( np );
149151 else if ( params.type == RelaxApproxType::Quadric )
150152 {
151- AffineXf3d basis;
152- basis.A .z = plane.n .normalized ();
153- auto [x, y] = basis.A .z .perpendicular ();
154- basis.A .x = x;
155- basis.A .y = y;
153+ AffineXf3d basis = accum.getBasicXf ();
154+ basis.A = basis.A .transposed ();
155+ std::swap ( basis.A .x , basis.A .y );
156+ std::swap ( basis.A .y , basis.A .z );
156157 basis.A = basis.A .transposed ();
157- basis.b = Vector3d ( np );
158158 auto basisInv = basis.inverse ();
159+
159160 QuadricApprox approxAccum;
160- for ( auto newV : neighbors )
161- approxAccum.addPoint ( basisInv ( Vector3d ( pointCloud.points [newV] ) ) );
162- auto res = QuadricApprox::findZeroProjection ( approxAccum.calcBestCoefficients () );
163- target = Vector3f ( basis ( res ) );
161+ for ( auto [newV, w] : weightedNeighbors )
162+ approxAccum.addPoint ( basisInv ( Vector3d ( pointCloud.points [newV] ) ), w );
163+
164+ auto centerPoint = basisInv ( Vector3d ( pointCloud.points [v] ) );
165+ const auto coefs = approxAccum.calcBestCoefficients ();
166+ centerPoint.z =
167+ coefs[0 ] * centerPoint.x * centerPoint.x +
168+ coefs[1 ] * centerPoint.x * centerPoint.y +
169+ coefs[2 ] * centerPoint.y * centerPoint.y +
170+ coefs[3 ] * centerPoint.x +
171+ coefs[4 ] * centerPoint.y +
172+ coefs[5 ];
173+ target = Vector3f ( basis ( centerPoint ) );
164174 }
165- np += ( params.force * ( 0 . 5f * target + Vector3f ( 0.5 * centroid ) - np ) );
175+ np += ( params.force * ( target - np ) );
166176 } );
167177 pointCloud.points .swap ( newPoints );
168178 pointCloud.invalidateCaches ();
0 commit comments