InspectionFeature.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (c) 2011 Werner Mayer <wmayer[at]users.sourceforge.net>     *
00003  *                                                                         *
00004  *   This file is part of the FreeCAD CAx development system.              *
00005  *                                                                         *
00006  *   This library is free software; you can redistribute it and/or         *
00007  *   modify it under the terms of the GNU Library General Public           *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2 of the License, or (at your option) any later version.      *
00010  *                                                                         *
00011  *   This library  is distributed in the hope that it will be useful,      *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00014  *   GNU Library General Public License for more details.                  *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Library General Public     *
00017  *   License along with this library; see the file COPYING.LIB. If not,    *
00018  *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
00019  *   Suite 330, Boston, MA  02111-1307, USA                                *
00020  *                                                                         *
00021  ***************************************************************************/
00022 
00023 
00024 #include "PreCompiled.h"
00025 #include <gp_Pnt.hxx>
00026 #include <BRepExtrema_DistShapeShape.hxx>
00027 #include <BRepBuilderAPI_MakeVertex.hxx>
00028 #include <TopoDS_Vertex.hxx>
00029 
00030 #include <QEventLoop>
00031 #include <QFuture>
00032 #include <QFutureWatcher>
00033 #include <QtConcurrentMap>
00034 
00035 #include <boost/signals.hpp>
00036 #include <boost/bind.hpp>
00037 
00038 #include <Base/Console.h>
00039 #include <Base/Exception.h>
00040 #include <Base/FutureWatcherProgress.h>
00041 #include <Base/Parameter.h>
00042 #include <Base/Sequencer.h>
00043 #include <Base/Tools.h>
00044 #include <App/Application.h>
00045 #include <Mod/Mesh/App/Mesh.h>
00046 #include <Mod/Mesh/App/MeshFeature.h>
00047 #include <Mod/Mesh/App/Core/Algorithm.h>
00048 #include <Mod/Mesh/App/Core/Grid.h>
00049 #include <Mod/Mesh/App/Core/Iterator.h>
00050 #include <Mod/Mesh/App/Core/MeshKernel.h>
00051 #include <Mod/Points/App/PointsFeature.h>
00052 #include <Mod/Points/App/PointsGrid.h>
00053 #include <Mod/Part/App/PartFeature.h>
00054 
00055 #include "InspectionFeature.h"
00056 
00057 
00058 using namespace Inspection;
00059 
00060 InspectActualMesh::InspectActualMesh(const Mesh::MeshObject& rMesh) : _iter(rMesh.getKernel())
00061 {
00062     this->_count = rMesh.countPoints();
00063     this->_iter.Transform(rMesh.getTransform());
00064 }
00065 
00066 InspectActualMesh::~InspectActualMesh()
00067 {
00068 }
00069 
00070 unsigned long InspectActualMesh::countPoints() const
00071 {
00072     return this->_count;
00073 }
00074 
00075 Base::Vector3f InspectActualMesh::getPoint(unsigned long index)
00076 {
00077     _iter.Set(index);
00078     return *_iter;
00079 }
00080 
00081 // ----------------------------------------------------------------
00082 
00083 InspectActualPoints::InspectActualPoints(const Points::PointKernel& rPoints) : _rKernel(rPoints)
00084 {
00085 }
00086 
00087 unsigned long InspectActualPoints::countPoints() const
00088 {
00089     return _rKernel.size();
00090 }
00091 
00092 Base::Vector3f InspectActualPoints::getPoint(unsigned long index)
00093 {
00094     Base::Vector3d p = _rKernel.getPoint(index);
00095     return Base::Vector3f((float)p.x,(float)p.y,(float)p.z);
00096 }
00097 
00098 // ----------------------------------------------------------------
00099 
00100 InspectActualShape::InspectActualShape(const Part::TopoShape& shape) : _rShape(shape)
00101 {
00102     ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath
00103         ("User parameter:BaseApp/Preferences/Mod/Part");
00104     float deviation = hGrp->GetFloat("MeshDeviation",0.2);
00105 
00106     Base::BoundBox3d bbox = _rShape.getBoundBox();
00107     Standard_Real deflection = (bbox.LengthX() + bbox.LengthY() + bbox.LengthZ())/300.0 * deviation;
00108 
00109     std::vector<Data::ComplexGeoData::Facet> f;
00110     _rShape.getFaces(points, f, (float)deflection);
00111 }
00112 
00113 unsigned long InspectActualShape::countPoints() const
00114 {
00115     return points.size();
00116 }
00117 
00118 Base::Vector3f InspectActualShape::getPoint(unsigned long index)
00119 {
00120     return Base::toVector<float>(points[index]);
00121 }
00122 
00123 // ----------------------------------------------------------------
00124 
00125 namespace Inspection {
00126     class MeshInspectGrid : public MeshCore::MeshGrid
00127     {
00128     public:
00129         MeshInspectGrid (const MeshCore::MeshKernel &mesh, float fGridLen, const Base::Matrix4D& m)
00130             : MeshCore::MeshGrid(mesh), _transform(m)
00131         {
00132             Base::BoundBox3f clBBMesh = _pclMesh->GetBoundBox().Transformed(m);
00133             Rebuild(std::max<unsigned long>((unsigned long)(clBBMesh.LengthX() / fGridLen), 1),
00134                     std::max<unsigned long>((unsigned long)(clBBMesh.LengthY() / fGridLen), 1),
00135                     std::max<unsigned long>((unsigned long)(clBBMesh.LengthZ() / fGridLen), 1));
00136         }
00137 
00138         void Validate (const MeshCore::MeshKernel&)
00139         {
00140             // do nothing
00141         }
00142 
00143         void Validate (void)
00144         {
00145             // do nothing
00146         }
00147 
00148         bool Verify() const
00149         {
00150             // do nothing
00151             return true;
00152         }
00153 
00154     protected:
00155         void CalculateGridLength (unsigned long ulCtGrid, unsigned long ulMaxGrids)
00156         {
00157             // do nothing
00158         }
00159 
00160         void CalculateGridLength (int iCtGridPerAxis)
00161         {
00162             // do nothing
00163         }
00164 
00165         unsigned long HasElements (void) const
00166         {
00167             return _pclMesh->CountFacets();
00168         }
00169 
00170         void Pos (const Base::Vector3f &rclPoint, unsigned long &rulX, unsigned long &rulY, unsigned long &rulZ) const
00171         {
00172             rulX = (unsigned long)((rclPoint.x - _fMinX) / _fGridLenX);
00173             rulY = (unsigned long)((rclPoint.y - _fMinY) / _fGridLenY);
00174             rulZ = (unsigned long)((rclPoint.z - _fMinZ) / _fGridLenZ);
00175 
00176             assert((rulX < _ulCtGridsX) && (rulY < _ulCtGridsY) && (rulZ < _ulCtGridsZ));
00177         }
00178 
00179         void AddFacet (const MeshCore::MeshGeomFacet &rclFacet, unsigned long ulFacetIndex)
00180         {
00181             unsigned long ulX, ulY, ulZ;
00182             unsigned long ulX1, ulY1, ulZ1, ulX2, ulY2, ulZ2;
00183 
00184             Base::BoundBox3f clBB;
00185             clBB &= rclFacet._aclPoints[0];
00186             clBB &= rclFacet._aclPoints[1];
00187             clBB &= rclFacet._aclPoints[2];
00188 
00189             Pos(Base::Vector3f(clBB.MinX,clBB.MinY,clBB.MinZ), ulX1, ulY1, ulZ1);
00190             Pos(Base::Vector3f(clBB.MaxX,clBB.MaxY,clBB.MaxZ), ulX2, ulY2, ulZ2);
00191   
00192 
00193             if ((ulX1 < ulX2) || (ulY1 < ulY2) || (ulZ1 < ulZ2)) {
00194                 for (ulX = ulX1; ulX <= ulX2; ulX++) {
00195                     for (ulY = ulY1; ulY <= ulY2; ulY++) {
00196                         for (ulZ = ulZ1; ulZ <= ulZ2; ulZ++) {
00197                             if (rclFacet.IntersectBoundingBox(GetBoundBox(ulX, ulY, ulZ)))
00198                                 _aulGrid[ulX][ulY][ulZ].insert(ulFacetIndex);
00199                         }
00200                     }
00201                 }
00202             }
00203             else
00204                 _aulGrid[ulX1][ulY1][ulZ1].insert(ulFacetIndex);
00205         }
00206 
00207         void InitGrid (void)
00208         {
00209             unsigned long i, j;
00210 
00211             Base::BoundBox3f clBBMesh = _pclMesh->GetBoundBox().Transformed(_transform);
00212 
00213             float fLengthX = clBBMesh.LengthX(); 
00214             float fLengthY = clBBMesh.LengthY();
00215             float fLengthZ = clBBMesh.LengthZ();
00216 
00217             _fGridLenX = (1.0f + fLengthX) / float(_ulCtGridsX);
00218             _fMinX = clBBMesh.MinX - 0.5f;
00219 
00220             _fGridLenY = (1.0f + fLengthY) / float(_ulCtGridsY);
00221             _fMinY = clBBMesh.MinY - 0.5f;
00222 
00223             _fGridLenZ = (1.0f + fLengthZ) / float(_ulCtGridsZ);
00224             _fMinZ = clBBMesh.MinZ - 0.5f;
00225 
00226             _aulGrid.clear();
00227             _aulGrid.resize(_ulCtGridsX);
00228             for (i = 0; i < _ulCtGridsX; i++) {
00229                 _aulGrid[i].resize(_ulCtGridsY);
00230                 for (j = 0; j < _ulCtGridsY; j++)
00231                     _aulGrid[i][j].resize(_ulCtGridsZ);
00232             }
00233         }
00234 
00235         void RebuildGrid (void)
00236         {
00237             _ulCtElements = _pclMesh->CountFacets();
00238             InitGrid();
00239  
00240             unsigned long i = 0;
00241             MeshCore::MeshFacetIterator clFIter(*_pclMesh);
00242             clFIter.Transform(_transform);
00243             for (clFIter.Init(); clFIter.More(); clFIter.Next()) {
00244                 AddFacet(*clFIter, i++);
00245             }
00246         }
00247 
00248     private:
00249         Base::Matrix4D _transform;
00250     };
00251 }
00252 
00253 InspectNominalMesh::InspectNominalMesh(const Mesh::MeshObject& rMesh, float offset) : _iter(rMesh.getKernel())
00254 {
00255     const MeshCore::MeshKernel& kernel = rMesh.getKernel();
00256     _iter.Transform(rMesh.getTransform());
00257 
00258     // Max. limit of grid elements
00259     float fMaxGridElements=8000000.0f;
00260     Base::BoundBox3f box = kernel.GetBoundBox().Transformed(rMesh.getTransform());
00261 
00262     // estimate the minimum allowed grid length
00263     float fMinGridLen = (float)pow((box.LengthX()*box.LengthY()*box.LengthZ()/fMaxGridElements), 0.3333f);
00264     float fGridLen = 5.0f * MeshCore::MeshAlgorithm(kernel).GetAverageEdgeLength();
00265 
00266     // We want to avoid to get too small grid elements otherwise building up the grid structure would take
00267     // too much time and memory. 
00268     // Having quite a dense grid speeds up more the following algorithms extremely. Due to the issue above it's
00269     // always a compromise between speed and memory usage.
00270     fGridLen = std::max<float>(fMinGridLen, fGridLen);
00271 
00272     // build up grid structure to speed up algorithms
00273     _pGrid = new MeshInspectGrid(kernel, fGridLen, rMesh.getTransform());
00274     _box = box;
00275     _box.Enlarge(offset);
00276 }
00277 
00278 InspectNominalMesh::~InspectNominalMesh()
00279 {
00280     delete this->_pGrid;
00281 }
00282 
00283 float InspectNominalMesh::getDistance(const Base::Vector3f& point)
00284 {
00285     if (!_box.IsInBox(point))
00286         return FLT_MAX; // must be inside bbox
00287 
00288     std::vector<unsigned long> indices;
00289     //_pGrid->GetElements(point, indices);
00290     if (indices.empty()) {
00291         std::set<unsigned long> inds;
00292         _pGrid->MeshGrid::SearchNearestFromPoint(point, inds);
00293         indices.insert(indices.begin(), inds.begin(), inds.end());
00294     }
00295 
00296     float fMinDist=FLT_MAX;
00297     bool positive = true;
00298     for (std::vector<unsigned long>::iterator it = indices.begin(); it != indices.end(); ++it) {
00299         _iter.Set(*it);
00300         float fDist = _iter->DistanceToPoint(point);
00301         if (fabs(fDist) < fabs(fMinDist)) {
00302             fMinDist = fDist;
00303             positive = point.DistanceToPlane(_iter->_aclPoints[0], _iter->GetNormal()) > 0;
00304         }
00305     }
00306 
00307     if (!positive)
00308         fMinDist = -fMinDist;
00309     return fMinDist;
00310 }
00311 
00312 // ----------------------------------------------------------------
00313 
00314 InspectNominalFastMesh::InspectNominalFastMesh(const Mesh::MeshObject& rMesh, float offset) : _iter(rMesh.getKernel())
00315 {
00316     const MeshCore::MeshKernel& kernel = rMesh.getKernel();
00317     _iter.Transform(rMesh.getTransform());
00318 
00319     // Max. limit of grid elements
00320     float fMaxGridElements=8000000.0f;
00321     Base::BoundBox3f box = kernel.GetBoundBox().Transformed(rMesh.getTransform());
00322 
00323     // estimate the minimum allowed grid length
00324     float fMinGridLen = (float)pow((box.LengthX()*box.LengthY()*box.LengthZ()/fMaxGridElements), 0.3333f);
00325     float fGridLen = 5.0f * MeshCore::MeshAlgorithm(kernel).GetAverageEdgeLength();
00326 
00327     // We want to avoid to get too small grid elements otherwise building up the grid structure would take
00328     // too much time and memory. 
00329     // Having quite a dense grid speeds up more the following algorithms extremely. Due to the issue above it's
00330     // always a compromise between speed and memory usage.
00331     fGridLen = std::max<float>(fMinGridLen, fGridLen);
00332 
00333     // build up grid structure to speed up algorithms
00334     _pGrid = new MeshInspectGrid(kernel, fGridLen, rMesh.getTransform());
00335     _box = box;
00336     _box.Enlarge(offset);
00337     max_level = (unsigned long)(offset/fGridLen);
00338 }
00339 
00340 InspectNominalFastMesh::~InspectNominalFastMesh()
00341 {
00342     delete this->_pGrid;
00343 }
00344 
00349 float InspectNominalFastMesh::getDistance(const Base::Vector3f& point)
00350 {
00351     if (!_box.IsInBox(point))
00352         return FLT_MAX; // must be inside bbox
00353 
00354     std::set<unsigned long> indices;
00355 #if 0 // a point in a neighbour grid can be nearer
00356     std::vector<unsigned long> elements;
00357     _pGrid->GetElements(point, elements);
00358     indices.insert(elements.begin(), elements.end());
00359 #else
00360     unsigned long ulX, ulY, ulZ;
00361     _pGrid->Position(point, ulX, ulY, ulZ);
00362     unsigned long ulLevel = 0;
00363     while (indices.size() == 0 && ulLevel <= max_level)
00364         _pGrid->GetHull(ulX, ulY, ulZ, ulLevel++, indices);
00365     if (indices.size() == 0 || ulLevel==1)
00366         _pGrid->GetHull(ulX, ulY, ulZ, ulLevel, indices);
00367 #endif
00368 
00369     float fMinDist=FLT_MAX;
00370     bool positive = true;
00371     for (std::set<unsigned long>::iterator it = indices.begin(); it != indices.end(); ++it) {
00372         _iter.Set(*it);
00373         float fDist = _iter->DistanceToPoint(point);
00374         if (fabs(fDist) < fabs(fMinDist)) {
00375             fMinDist = fDist;
00376             positive = point.DistanceToPlane(_iter->_aclPoints[0], _iter->GetNormal()) > 0;
00377         }
00378     }
00379 
00380     if (!positive)
00381         fMinDist = -fMinDist;
00382     return fMinDist;
00383 }
00384 
00385 // ----------------------------------------------------------------
00386 
00387 InspectNominalPoints::InspectNominalPoints(const Points::PointKernel& Kernel, float offset) : _rKernel(Kernel)
00388 {
00389     int uGridPerAxis = 50; // totally 125.000 grid elements 
00390     this->_pGrid = new Points::PointsGrid (Kernel, uGridPerAxis);
00391 }
00392 
00393 InspectNominalPoints::~InspectNominalPoints()
00394 {
00395     delete this->_pGrid;
00396 }
00397 
00398 float InspectNominalPoints::getDistance(const Base::Vector3f& point)
00399 {
00400     //TODO: Make faster
00401     std::set<unsigned long> indices;
00402     unsigned long x,y,z;
00403     Base::Vector3d pointd(point.x,point.y,point.z);
00404     _pGrid->Position(pointd, x, y, z);
00405     _pGrid->GetElements(x,y,z,indices);
00406 
00407     double fMinDist=DBL_MAX;
00408     for (std::set<unsigned long>::iterator it = indices.begin(); it != indices.end(); ++it) {
00409         Base::Vector3d pt = _rKernel.getPoint(*it);
00410         double fDist = Base::Distance(pointd, pt);
00411         if (fDist < fMinDist) {
00412             fMinDist = fDist;
00413         }
00414     }
00415 
00416     return (float)fMinDist;
00417 }
00418 
00419 // ----------------------------------------------------------------
00420 
00421 InspectNominalShape::InspectNominalShape(const TopoDS_Shape& shape, float radius) : _rShape(shape)
00422 {
00423     distss = new BRepExtrema_DistShapeShape();
00424     distss->LoadS1(_rShape);
00425     //distss->SetDeflection(radius);
00426 }
00427 
00428 InspectNominalShape::~InspectNominalShape()
00429 {
00430     delete distss;
00431 }
00432 
00433 float InspectNominalShape::getDistance(const Base::Vector3f& point)
00434 {
00435     BRepBuilderAPI_MakeVertex mkVert(gp_Pnt(point.x,point.y,point.z));
00436     distss->LoadS2(mkVert.Vertex());
00437     float fMinDist=FLT_MAX;
00438     if (distss->Perform() && distss->NbSolution() > 0)
00439         fMinDist = (float)distss->Value();
00440     return fMinDist;
00441 }
00442 
00443 // ----------------------------------------------------------------
00444 
00445 // helper class to use Qt's concurrent framework
00446 struct DistanceInspection
00447 {
00448 
00449     DistanceInspection(float radius, InspectActualGeometry*  a,
00450                        std::vector<InspectNominalGeometry*> n)
00451                     : radius(radius), actual(a), nominal(n)
00452     {
00453     }
00454     float mapped(unsigned long index)
00455     {
00456         Base::Vector3f pnt = actual->getPoint(index);
00457 
00458         float fMinDist=FLT_MAX;
00459         for (std::vector<InspectNominalGeometry*>::iterator it = nominal.begin(); it != nominal.end(); ++it) {
00460             float fDist = (*it)->getDistance(pnt);
00461             if (fabs(fDist) < fabs(fMinDist))
00462                 fMinDist = fDist;
00463         }
00464 
00465         if (fMinDist > this->radius)
00466             fMinDist = FLT_MAX;
00467         else if (-fMinDist > this->radius)
00468             fMinDist = -FLT_MAX;
00469 
00470         return fMinDist;
00471     }
00472 
00473     float radius;
00474     InspectActualGeometry*  actual;
00475     std::vector<InspectNominalGeometry*> nominal;
00476 };
00477 
00478 PROPERTY_SOURCE(Inspection::Feature, App::DocumentObject)
00479 
00480 Feature::Feature()
00481 {
00482     ADD_PROPERTY(SearchRadius,(0.05f));
00483     ADD_PROPERTY(Thickness,(0.0f));
00484     ADD_PROPERTY(Actual,(0));
00485     ADD_PROPERTY(Nominals,(0));
00486     ADD_PROPERTY(Distances,(0.0f));
00487 }
00488 
00489 Feature::~Feature()
00490 {
00491 }
00492 
00493 short Feature::mustExecute() const
00494 {
00495     if (SearchRadius.isTouched())
00496         return 1;
00497     if (Thickness.isTouched())
00498         return 1;
00499     if (Actual.isTouched())
00500         return 1;
00501     if (Nominals.isTouched())
00502         return 1;
00503     return 0;
00504 }
00505 
00506 App::DocumentObjectExecReturn* Feature::execute(void)
00507 {
00508     App::DocumentObject* pcActual = Actual.getValue();
00509     if (!pcActual)
00510         throw Base::Exception("No actual geometry to inspect specified");
00511 
00512     InspectActualGeometry* actual = 0;
00513     if (pcActual->getTypeId().isDerivedFrom(Mesh::Feature::getClassTypeId())) {
00514         Mesh::Feature* mesh = static_cast<Mesh::Feature*>(pcActual);
00515         actual = new InspectActualMesh(mesh->Mesh.getValue());
00516     }
00517     else if (pcActual->getTypeId().isDerivedFrom(Points::Feature::getClassTypeId())) {
00518         Points::Feature* pts = static_cast<Points::Feature*>(pcActual);
00519         actual = new InspectActualPoints(pts->Points.getValue());
00520     }
00521     else if (pcActual->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) {
00522         Part::Feature* part = static_cast<Part::Feature*>(pcActual);
00523         actual = new InspectActualShape(part->Shape.getShape());
00524     }
00525     else {
00526         throw Base::Exception("Unknown geometric type");
00527     }
00528 
00529     // get a list of nominals
00530     std::vector<InspectNominalGeometry*> inspectNominal;
00531     const std::vector<App::DocumentObject*>& nominals = Nominals.getValues();
00532     for (std::vector<App::DocumentObject*>::const_iterator it = nominals.begin(); it != nominals.end(); ++it) {
00533         InspectNominalGeometry* nominal = 0;
00534         if ((*it)->getTypeId().isDerivedFrom(Mesh::Feature::getClassTypeId())) {
00535             Mesh::Feature* mesh = static_cast<Mesh::Feature*>(*it);
00536             nominal = new InspectNominalMesh(mesh->Mesh.getValue(), this->SearchRadius.getValue());
00537         }
00538         else if ((*it)->getTypeId().isDerivedFrom(Points::Feature::getClassTypeId())) {
00539             Points::Feature* pts = static_cast<Points::Feature*>(*it);
00540             nominal = new InspectNominalPoints(pts->Points.getValue(), this->SearchRadius.getValue());
00541         }
00542         else if ((*it)->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) {
00543             Part::Feature* part = static_cast<Part::Feature*>(*it);
00544             nominal = new InspectNominalShape(part->Shape.getValue(), this->SearchRadius.getValue());
00545         }
00546 
00547         if (nominal)
00548             inspectNominal.push_back(nominal);
00549     }
00550 
00551 #if 0 // test with some huge data sets
00552     Standard::SetReentrant(Standard_True);
00553     std::vector<unsigned long> index(actual->countPoints());
00554     std::generate(index.begin(), index.end(), Base::iotaGen<unsigned long>(0));
00555     DistanceInspection check(this->SearchRadius.getValue(), actual, inspectNominal);
00556     QFuture<float> future = QtConcurrent::mapped
00557         (index, boost::bind(&DistanceInspection::mapped, &check, _1));
00558     //future.waitForFinished(); // blocks the GUI
00559     Base::FutureWatcherProgress progress("Inspecting...", actual->countPoints());
00560     QFutureWatcher<float> watcher;
00561     QObject::connect(&watcher, SIGNAL(progressValueChanged(int)),
00562                      &progress, SLOT(progressValueChanged(int)));
00563     watcher.setFuture(future);
00564 
00565     // keep it responsive during computation
00566     QEventLoop loop;
00567     QObject::connect(&watcher, SIGNAL(finished()), &loop, SLOT(quit()));
00568     loop.exec();
00569 
00570     std::vector<float> vals;
00571     vals.insert(vals.end(), future.begin(), future.end());
00572 #else
00573     unsigned long count = actual->countPoints();
00574     std::stringstream str;
00575     str << "Inspecting " << this->Label.getValue() << "...";
00576     Base::SequencerLauncher seq(str.str().c_str(), count);
00577 
00578     std::vector<float> vals(count);
00579     for (unsigned long index = 0; index < count; index++) {
00580         Base::Vector3f pnt = actual->getPoint(index);
00581 
00582         float fMinDist=FLT_MAX;
00583         for (std::vector<InspectNominalGeometry*>::iterator it = inspectNominal.begin(); it != inspectNominal.end(); ++it) {
00584             float fDist = (*it)->getDistance(pnt);
00585             if (fabs(fDist) < fabs(fMinDist))
00586                 fMinDist = fDist;
00587         }
00588 
00589         if (fMinDist > this->SearchRadius.getValue())
00590             fMinDist = FLT_MAX;
00591         else if (-fMinDist > this->SearchRadius.getValue())
00592             fMinDist = -FLT_MAX;
00593         vals[index] = fMinDist;
00594         seq.next();
00595     }
00596 #endif
00597 
00598     Distances.setValues(vals);
00599 
00600     float fRMS = 0;
00601     int countRMS = 0;
00602     for (std::vector<float>::iterator it = vals.begin(); it != vals.end(); ++it) {
00603         if (fabs(*it) < FLT_MAX) {
00604             fRMS += (*it) * (*it);
00605             countRMS++;
00606         }
00607     }
00608 
00609     fRMS = fRMS / countRMS;
00610     fRMS = sqrt(fRMS);
00611     Base::Console().Message("RMS value for '%s' with search radius=%.4f is: %.4f\n",
00612         this->Label.getValue(), this->SearchRadius.getValue(), fRMS);
00613 
00614     delete actual;
00615     for (std::vector<InspectNominalGeometry*>::iterator it = inspectNominal.begin(); it != inspectNominal.end(); ++it)
00616         delete *it;
00617 
00618     return 0;
00619 }
00620 
00621 // ----------------------------------------------------------------
00622 
00623 PROPERTY_SOURCE(Inspection::Group, App::DocumentObjectGroup)
00624 
00625 
00626 Group::Group()
00627 {
00628 }
00629 
00630 Group::~Group()
00631 {
00632 }

Generated on Wed Nov 23 19:00:19 2011 for FreeCAD by  doxygen 1.6.1