From 2e6c54eedfed8788f3a4009a2951e53d7ca968d1 Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 28 Jul 2014 16:39:34 +0200 Subject: [PATCH] + improve the plane fit from REEN module --- src/Mod/Mesh/App/Core/Approximation.cpp | 19 +++++++++++ src/Mod/Mesh/App/Core/Approximation.h | 4 +++ src/Mod/Part/App/AppPartPy.cpp | 34 ++++++++++++++----- src/Mod/ReverseEngineering/Gui/Command.cpp | 38 ++++++++++++++++++---- 4 files changed, 80 insertions(+), 15 deletions(-) diff --git a/src/Mod/Mesh/App/Core/Approximation.cpp b/src/Mod/Mesh/App/Core/Approximation.cpp index 2c1731e26c..e81df79f16 100644 --- a/src/Mod/Mesh/App/Core/Approximation.cpp +++ b/src/Mod/Mesh/App/Core/Approximation.cpp @@ -29,6 +29,7 @@ #include "Approximation.h" +#include #include #include #include @@ -360,6 +361,24 @@ void PlaneFit::ProjectToPlane () } } +void PlaneFit::Dimension(float& length, float& width) const +{ + const Base::Vector3f& bs = _vBase; + const Base::Vector3f& ex = _vDirU; + const Base::Vector3f& ey = _vDirV; + + Base::BoundBox3f bbox; + std::list::const_iterator cIt; + for (cIt = _vPoints.begin(); cIt != _vPoints.end(); ++cIt) { + Base::Vector3f pnt = *cIt; + pnt.TransformToCoordinateSystem(bs, ex, ey); + bbox.Add(pnt); + } + + length = bbox.MaxX - bbox.MinX; + width = bbox.MaxY - bbox.MinY; +} + // ------------------------------------------------------------------------------- bool QuadraticFit::GetCurvatureInfo(double x, double y, double z, diff --git a/src/Mod/Mesh/App/Core/Approximation.h b/src/Mod/Mesh/App/Core/Approximation.h index 958209a036..fd9455bc22 100644 --- a/src/Mod/Mesh/App/Core/Approximation.h +++ b/src/Mod/Mesh/App/Core/Approximation.h @@ -225,6 +225,10 @@ public: * Projects the points onto the fitted plane. */ void ProjectToPlane(); + /** + * Get the dimension of the fitted plane. + */ + void Dimension(float& length, float& width) const; protected: Base::Vector3f _vBase; /**< Base vector of the plane. */ diff --git a/src/Mod/Part/App/AppPartPy.cpp b/src/Mod/Part/App/AppPartPy.cpp index bd5d787e9c..7b114c8e45 100644 --- a/src/Mod/Part/App/AppPartPy.cpp +++ b/src/Mod/Part/App/AppPartPy.cpp @@ -44,6 +44,7 @@ # include # include # include +# include # include # include # include @@ -576,10 +577,11 @@ static PyObject * makeSolid(PyObject *self, PyObject *args) static PyObject * makePlane(PyObject *self, PyObject *args) { double length, width; - PyObject *pPnt=0, *pDir=0; - if (!PyArg_ParseTuple(args, "dd|O!O!", &length, &width, - &(Base::VectorPy::Type), &pPnt, - &(Base::VectorPy::Type), &pDir)) + PyObject *pPnt=0, *pDirZ=0, *pDirX=0; + if (!PyArg_ParseTuple(args, "dd|O!O!O!", &length, &width, + &(Base::VectorPy::Type), &pPnt, + &(Base::VectorPy::Type), &pDirZ, + &(Base::VectorPy::Type), &pDirX)) return NULL; if (length < Precision::Confusion()) { @@ -598,11 +600,21 @@ static PyObject * makePlane(PyObject *self, PyObject *args) Base::Vector3d pnt = static_cast(pPnt)->value(); p.SetCoord(pnt.x, pnt.y, pnt.z); } - if (pDir) { - Base::Vector3d vec = static_cast(pDir)->value(); + if (pDirZ) { + Base::Vector3d vec = static_cast(pDirZ)->value(); d.SetCoord(vec.x, vec.y, vec.z); } - Handle_Geom_Plane aPlane = new Geom_Plane(p, d); + Handle_Geom_Plane aPlane; + if (pDirX) { + Base::Vector3d vec = static_cast(pDirX)->value(); + gp_Dir dx; + dx.SetCoord(vec.x, vec.y, vec.z); + aPlane = new Geom_Plane(gp_Ax3(p, d, dx)); + } + else { + aPlane = new Geom_Plane(p, d); + } + BRepBuilderAPI_MakeFace Face(aPlane, 0.0, length, 0.0, width #if OCC_VERSION_HEX >= 0x060502 , Precision::Confusion() @@ -614,6 +626,10 @@ static PyObject * makePlane(PyObject *self, PyObject *args) PyErr_SetString(PyExc_Exception, "creation of plane failed"); return NULL; } + catch (Standard_Failure) { + PyErr_SetString(PyExc_Exception, "creation of plane failed"); + return NULL; + } } static PyObject * makeBox(PyObject *self, PyObject *args) @@ -1688,8 +1704,8 @@ struct PyMethodDef Part_methods[] = { "makeSolid(shape) -- Create a solid out of the shells inside a shape."}, {"makePlane" ,makePlane ,METH_VARARGS, - "makePlane(length,width,[pnt,dir]) -- Make a plane\n" - "By default pnt=Vector(0,0,0) and dir=Vector(0,0,1)"}, + "makePlane(length,width,[pnt,dirZ,dirX]) -- Make a plane\n" + "By default pnt=Vector(0,0,0) and dirZ=Vector(0,0,1), dirX is ignored in this case"}, {"makeBox" ,makeBox ,METH_VARARGS, "makeBox(length,width,height,[pnt,dir]) -- Make a box located\n" diff --git a/src/Mod/ReverseEngineering/Gui/Command.cpp b/src/Mod/ReverseEngineering/Gui/Command.cpp index 623be39e47..30991d1500 100644 --- a/src/Mod/ReverseEngineering/Gui/Command.cpp +++ b/src/Mod/ReverseEngineering/Gui/Command.cpp @@ -127,6 +127,15 @@ void CmdApproxPlane::activated(int iMsg) std::vector aTopo; static_cast(jt->second)->getFaces(aPoints, aTopo,0.01f); + // get a reference normal for the plane fit + Base::Vector3f refNormal(0,0,0); + if (!aTopo.empty()) { + Data::ComplexGeoData::Facet f = aTopo.front(); + Base::Vector3d v1 = aPoints[f.I2] - aPoints[f.I1]; + Base::Vector3d v2 = aPoints[f.I3] - aPoints[f.I1]; + refNormal = Base::convertTo(v1 % v2); + } + std::vector aData; aData.reserve(aPoints.size()); for (std::vector::iterator jt = aPoints.begin(); jt != aPoints.end(); ++jt) @@ -135,21 +144,38 @@ void CmdApproxPlane::activated(int iMsg) fit.AddPoints(aData); float sigma = fit.Fit(); Base::Vector3f base = fit.GetBase(); + Base::Vector3f dirU = fit.GetDirU(); + Base::Vector3f dirV = fit.GetDirV(); Base::Vector3f norm = fit.GetNormal(); - Base::Console().Message("RMS value for plane fit with %ld points: %.4f\n", aData.size(), sigma); - Base::Console().Message(" Plane base(%.4f, %.4f, %.4f)\n", base.x, base.y, base.z); - Base::Console().Message(" Plane normal(%.4f, %.4f, %.4f)\n", norm.x, norm.y, norm.z); + // if the dot product of the refernce with the plane normal is negative + // a flip must be done + if (refNormal * norm < 0) { + norm = -norm; + dirU = -dirU; + } + + float width, length; + fit.Dimension(width, length); + // move to the corner point + base = base - (0.5f * length * dirU + 0.5f * width * dirV); + + Base::Console().Log("RMS value for plane fit with %ld points: %.4f\n", aData.size(), sigma); + Base::Console().Log(" Plane base(%.4f, %.4f, %.4f)\n", base.x, base.y, base.z); + Base::Console().Log(" Plane normal(%.4f, %.4f, %.4f)\n", norm.x, norm.y, norm.z); std::stringstream str; str << "import Part" << std::endl; str << "from FreeCAD import Base" << std::endl; - str << "Part.show(Part.makePlane(" - << 10 << ", " << 10 << ", " + str << "App.ActiveDocument.addObject('Part::Feature','Plane_fit').Shape=" + << "Part.makePlane(" + << width << ", " << length << ", " << "Base.Vector(" << base.x << ", " << base.y << ", " << base.z << "), " << "Base.Vector(" - << norm.x << ", " << norm.y << ", " << norm.z << ")))" << std::endl; + << norm.x << ", " << norm.y << ", " << norm.z << "), " + << "Base.Vector(" + << dirU.x << ", " << dirU.y << ", " << dirU.z << "))" << std::endl; openCommand("Fit plane"); doCommand(Gui::Command::Doc, str.str().c_str());