bool GeometricalAnalysisTools::computeSphereFrom4( const CCVector3& A, const CCVector3& B, const CCVector3& C, const CCVector3& D, CCVector3& center, PointCoordinateType& radius ) { //inspired from 'tetrahedron_circumsphere_3d' by Adrian Bowyer and John Woodwark //Set up the linear system. double a[12]; { CCVector3 AB = B-A; a[0] = AB.x; a[3] = AB.y; a[6] = AB.z; a[9] = AB.norm2d(); } { CCVector3 AC = C-A; a[1] = AC.x; a[4] = AC.y; a[7] = AC.z; a[10] = AC.norm2d(); } { CCVector3 AD = D-A; a[2] = AD.x; a[5] = AD.y; a[8] = AD.z; a[11] = AD.norm2d(); } // Solve the linear system (with Gauss-Jordan elimination) if ( dmat_solve ( 3, 1, a ) != 0 ) { //system is singular? return false; } // Compute the radius and center. CCVector3 u = CCVector3(static_cast<PointCoordinateType>(a[0+3*3]), static_cast<PointCoordinateType>(a[1+3*3]), static_cast<PointCoordinateType>(a[2+3*3])) / 2; radius = u.norm(); center = A + u; return true; }
bool ScalarFieldTools::computeMeanGradientOnPatch( const DgmOctree::octreeCell& cell, void** additionalParameters, NormalizedProgress* nProgress/*=0*/) { //additional parameters bool euclideanDistances = *reinterpret_cast<bool*>(additionalParameters[0]); PointCoordinateType radius = *reinterpret_cast<PointCoordinateType*>(additionalParameters[1]); ScalarField* theGradientNorms = reinterpret_cast<ScalarField*>(additionalParameters[2]); //number of points inside the current cell unsigned n = cell.points->size(); //spherical neighborhood extraction structure DgmOctree::NearestNeighboursSphericalSearchStruct nNSS; nNSS.level = cell.level; nNSS.prepare(radius,cell.parentOctree->getCellSize(nNSS.level)); cell.parentOctree->getCellPos(cell.truncatedCode,cell.level,nNSS.cellPos,true); cell.parentOctree->computeCellCenter(nNSS.cellPos,cell.level,nNSS.cellCenter); //we already know the points inside the current cell { try { nNSS.pointsInNeighbourhood.resize(n); } catch (.../*const std::bad_alloc&*/) //out of memory { return false; } DgmOctree::NeighboursSet::iterator it = nNSS.pointsInNeighbourhood.begin(); for (unsigned j=0; j<n; ++j,++it) { it->point = cell.points->getPointPersistentPtr(j); it->pointIndex = cell.points->getPointGlobalIndex(j); } nNSS.alreadyVisitedNeighbourhoodSize = 1; } const GenericIndexedCloudPersist* cloud = cell.points->getAssociatedCloud(); for (unsigned i=0; i<n; ++i) { ScalarType gN = NAN_VALUE; ScalarType d1 = cell.points->getPointScalarValue(i); if (ScalarField::ValidValue(d1)) { cell.points->getPoint(i,nNSS.queryPoint); //we extract the point's neighbors //warning: there may be more points at the end of nNSS.pointsInNeighbourhood than the actual nearest neighbors (k)! unsigned k = cell.parentOctree->findNeighborsInASphereStartingFromCell(nNSS,radius,true); //if more than one neighbour (the query point itself) if (k > 1) { CCVector3d sum(0,0,0); unsigned counter = 0; //j = 1 because the first point is the query point itself --> contribution = 0 for (unsigned j=1; j<k; ++j) { ScalarType d2 = cloud->getPointScalarValue(nNSS.pointsInNeighbourhood[j].pointIndex); if (ScalarField::ValidValue(d2)) { CCVector3 u = *nNSS.pointsInNeighbourhood[j].point - nNSS.queryPoint; double norm2 = u.norm2d(); if (norm2 > ZERO_TOLERANCE) { double dd = d2 - d1; if (!euclideanDistances || dd*dd < 1.01 * norm2) { dd /= norm2; sum.x += u.x * dd; //warning: and here 'dd'=dd/norm2 ;) sum.y += u.y * dd; sum.z += u.z * dd; ++counter; } } } } if (counter != 0) gN = static_cast<ScalarType>(sum.norm()/counter); } } if (theGradientNorms) //if "IN" and "OUT" SFs are the same theGradientNorms->setValue(cell.points->getPointGlobalIndex(i),gN); else //if "IN" and "OUT" SFs are different cell.points->setPointScalarValue(i,gN); if (nProgress && !nProgress->oneStep()) return false; } return true; }