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());