From 4af7d95a6dff48c71946c63f039d0ff210faa4d9 Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 11 Nov 2015 18:27:26 +0100 Subject: [PATCH] + support of linear b-spline/bezier curves and planar b-spline/bezier surfaces to get direction --- src/Mod/Fem/App/CMakeLists.txt | 2 + src/Mod/Fem/App/FemConstraint.cpp | 22 +- src/Mod/Fem/App/FemTools.cpp | 280 +++++++++++++++++++ src/Mod/Fem/App/FemTools.h | 74 +++++ src/Mod/Fem/App/PreCompiled.h | 8 +- src/Mod/Fem/Gui/TaskFemConstraintBearing.cpp | 18 +- src/Mod/Fem/Gui/TaskFemConstraintForce.cpp | 21 +- src/Mod/Fem/Gui/TaskFemConstraintGear.cpp | 13 +- 8 files changed, 391 insertions(+), 47 deletions(-) create mode 100644 src/Mod/Fem/App/FemTools.cpp create mode 100644 src/Mod/Fem/App/FemTools.h diff --git a/src/Mod/Fem/App/CMakeLists.txt b/src/Mod/Fem/App/CMakeLists.txt index 8f14d2570..6305e5a27 100755 --- a/src/Mod/Fem/App/CMakeLists.txt +++ b/src/Mod/Fem/App/CMakeLists.txt @@ -62,6 +62,8 @@ SOURCE_GROUP("Python" FILES ${Python_SRCS}) SET(Mod_SRCS AppFem.cpp AppFemPy.cpp + FemTools.cpp + FemTools.h PreCompiled.cpp PreCompiled.h ) diff --git a/src/Mod/Fem/App/FemConstraint.cpp b/src/Mod/Fem/App/FemConstraint.cpp index 565167ee4..48ad96a6e 100644 --- a/src/Mod/Fem/App/FemConstraint.cpp +++ b/src/Mod/Fem/App/FemConstraint.cpp @@ -52,6 +52,7 @@ #endif #include "FemConstraint.h" +#include "FemTools.h" #include #include @@ -322,25 +323,6 @@ const Base::Vector3d Constraint::getDirection(const App::PropertyLinkSub &direct str << "No such sub-element '" << subName << "'"; throw Base::AttributeError(str.str()); } - gp_Dir dir; - if (sh.ShapeType() == TopAbs_FACE) { - BRepAdaptor_Surface surface(TopoDS::Face(sh)); - if (surface.GetType() == GeomAbs_Plane) { - dir = surface.Plane().Axis().Direction(); - } else { - return Base::Vector3d(0,0,0); // "Direction must be a planar face or linear edge" - } - } else if (sh.ShapeType() == TopAbs_EDGE) { - BRepAdaptor_Curve line(TopoDS::Edge(sh)); - if (line.GetType() == GeomAbs_Line) { - dir = line.Line().Direction(); - } else { - return Base::Vector3d(0,0,0); // "Direction must be a planar face or linear edge" - } - } - - Base::Vector3d the_direction(dir.X(), dir.Y(), dir.Z()); - the_direction.Normalize(); - return the_direction; + return Fem::Tools::getDirectionFromShape(sh); } diff --git a/src/Mod/Fem/App/FemTools.cpp b/src/Mod/Fem/App/FemTools.cpp new file mode 100644 index 000000000..234aaaef1 --- /dev/null +++ b/src/Mod/Fem/App/FemTools.cpp @@ -0,0 +1,280 @@ +/*************************************************************************** + * Copyright (c) 2015 Werner Mayer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#include "PreCompiled.h" +#ifndef _PreComp_ +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include "FemTools.h" + +Base::Vector3d Fem::Tools::getDirectionFromShape(const TopoDS_Shape& shape) +{ + gp_XYZ dir(0, 0, 0); + + // "Direction must be a planar face or linear edge" + // + if (shape.ShapeType() == TopAbs_FACE) { + if (isPlanar(TopoDS::Face(shape))) { + dir = getDirection(TopoDS::Face(shape)); + } + } + else if (shape.ShapeType() == TopAbs_EDGE) { + if (isLinear(TopoDS::Edge(shape))) { + dir = getDirection(TopoDS::Edge(shape)); + } + } + + Base::Vector3d the_direction(dir.X(), dir.Y(), dir.Z()); + return the_direction; +} + +bool Fem::Tools::isPlanar(const TopoDS_Face& face) +{ + BRepAdaptor_Surface surface(face); + if (surface.GetType() == GeomAbs_Plane) { + return true; + } + else if (surface.GetType() == GeomAbs_BSplineSurface) { + Handle_Geom_BSplineSurface spline = surface.BSpline(); + try { + TColgp_Array2OfPnt poles(1,spline->NbUPoles(),1,spline->NbVPoles()); + spline->Poles(poles); + + // get the plane from three control points + gp_Pnt p1 = poles(poles.LowerRow(),poles.LowerCol()); + gp_Pnt p2 = poles(poles.UpperRow(),poles.LowerCol()); + gp_Pnt p3 = poles(poles.LowerRow(),poles.UpperCol()); + gp_Vec vec1(p1, p2); + gp_Vec vec2(p1, p3); + gp_Vec vec3 = vec1.Crossed(vec2); + gp_Pln plane(p1, gp_Dir(vec3)); + + for (int i=poles.LowerRow(); i<=poles.UpperRow(); i++) { + for (int j=poles.LowerCol(); j Precision::Confusion()) { + return false; + } + } + } + + return true; + } + catch (Standard_Failure) { + return false; + } + } + else if (surface.GetType() == GeomAbs_BezierSurface) { + Handle_Geom_BezierSurface bezier = surface.Bezier(); + try { + TColgp_Array2OfPnt poles(1,bezier->NbUPoles(),1,bezier->NbVPoles()); + bezier->Poles(poles); + + // get the plane from three control points + gp_Pnt p1 = poles(poles.LowerRow(),poles.LowerCol()); + gp_Pnt p2 = poles(poles.UpperRow(),poles.LowerCol()); + gp_Pnt p3 = poles(poles.LowerRow(),poles.UpperCol()); + gp_Vec vec1(p1, p2); + gp_Vec vec2(p1, p3); + gp_Vec vec3 = vec1.Crossed(vec2); + gp_Pln plane(p1, gp_Dir(vec3)); + + for (int i=poles.LowerRow(); i<=poles.UpperRow(); i++) { + for (int j=poles.LowerCol(); j Precision::Confusion()) { + return false; + } + } + } + + return true; + } + catch (Standard_Failure) { + return false; + } + } + + return false; +} + +gp_XYZ Fem::Tools::getDirection(const TopoDS_Face& face) +{ + gp_XYZ dir(0, 0, 0); + + BRepAdaptor_Surface surface(face); + if (surface.GetType() == GeomAbs_Plane) { + dir = surface.Plane().Axis().Direction().XYZ(); + } + else if (surface.GetType() == GeomAbs_BSplineSurface) { + Handle_Geom_BSplineSurface spline = surface.BSpline(); + try { + TColgp_Array2OfPnt poles(1,spline->NbUPoles(),1,spline->NbVPoles()); + spline->Poles(poles); + + // get the plane from three control points + gp_Pnt p1 = poles(poles.LowerRow(),poles.LowerCol()); + gp_Pnt p2 = poles(poles.UpperRow(),poles.LowerCol()); + gp_Pnt p3 = poles(poles.LowerRow(),poles.UpperCol()); + gp_Vec vec1(p1, p2); + gp_Vec vec2(p1, p3); + gp_Vec vec3 = vec1.Crossed(vec2); + gp_Pln plane(p1, gp_Dir(vec3)); + dir = plane.Axis().Direction().XYZ(); + } + catch (Standard_Failure) { + } + } + else if (surface.GetType() == GeomAbs_BezierSurface) { + Handle_Geom_BezierSurface bezier = surface.Bezier(); + try { + TColgp_Array2OfPnt poles(1,bezier->NbUPoles(),1,bezier->NbVPoles()); + bezier->Poles(poles); + + // get the plane from three control points + gp_Pnt p1 = poles(poles.LowerRow(),poles.LowerCol()); + gp_Pnt p2 = poles(poles.UpperRow(),poles.LowerCol()); + gp_Pnt p3 = poles(poles.LowerRow(),poles.UpperCol()); + gp_Vec vec1(p1, p2); + gp_Vec vec2(p1, p3); + gp_Vec vec3 = vec1.Crossed(vec2); + gp_Pln plane(p1, gp_Dir(vec3)); + dir = plane.Axis().Direction().XYZ(); + } + catch (Standard_Failure) { + } + } + + return dir; +} + +bool Fem::Tools::isLinear(const TopoDS_Edge& edge) +{ + BRepAdaptor_Curve curve(edge); + if (curve.GetType() == GeomAbs_Line) { + return true; + } + else if (curve.GetType() == GeomAbs_BSplineCurve) { + Handle_Geom_BSplineCurve spline = curve.BSpline(); + try { + gp_Pnt s1 = spline->Pole(1); + gp_Pnt sn = spline->Pole(spline->NbPoles()); + gp_Vec vec(s1, sn); + gp_Lin line(s1, gp_Dir(vec)); + + for (int i=2; iNbPoles(); i++) { + // are control points collinear? + Standard_Real dist = line.Distance(spline->Pole(i)); + if (dist > Precision::Confusion()) { + return false; + } + } + + return true; + } + catch (Standard_Failure) { + return false; + } + } + else if (curve.GetType() == GeomAbs_BezierCurve) { + Handle_Geom_BezierCurve bezier = curve.Bezier(); + try { + gp_Pnt s1 = bezier->Pole(1); + gp_Pnt sn = bezier->Pole(bezier->NbPoles()); + gp_Vec vec(s1, sn); + gp_Lin line(s1, gp_Dir(vec)); + + for (int i=2; iNbPoles(); i++) { + // are control points collinear? + Standard_Real dist = line.Distance(bezier->Pole(i)); + if (dist > Precision::Confusion()) { + return false; + } + } + + return true; + } + catch (Standard_Failure) { + return false; + } + } + + return false; +} + +gp_XYZ Fem::Tools::getDirection(const TopoDS_Edge& edge) +{ + gp_XYZ dir(0, 0, 0); + + BRepAdaptor_Curve curve(edge); + if (curve.GetType() == GeomAbs_Line) { + dir = curve.Line().Direction().XYZ(); + } + else if (curve.GetType() == GeomAbs_BSplineCurve) { + Handle_Geom_BSplineCurve spline = curve.BSpline(); + try { + gp_Pnt s1 = spline->Pole(1); + gp_Pnt sn = spline->Pole(spline->NbPoles()); + gp_Vec vec(s1, sn); + gp_Lin line(s1, gp_Dir(vec)); + dir = line.Direction().XYZ(); + } + catch (Standard_Failure) { + } + } + else if (curve.GetType() == GeomAbs_BezierCurve) { + Handle_Geom_BezierCurve bezier = curve.Bezier(); + try { + gp_Pnt s1 = bezier->Pole(1); + gp_Pnt sn = bezier->Pole(bezier->NbPoles()); + gp_Vec vec(s1, sn); + gp_Lin line(s1, gp_Dir(vec)); + dir = line.Direction().XYZ(); + } + catch (Standard_Failure) { + } + } + + return dir; +} diff --git a/src/Mod/Fem/App/FemTools.h b/src/Mod/Fem/App/FemTools.h new file mode 100644 index 000000000..30813e179 --- /dev/null +++ b/src/Mod/Fem/App/FemTools.h @@ -0,0 +1,74 @@ +/*************************************************************************** + * Copyright (c) 2015 Werner Mayer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef FEM_TOOLS_H +#define FEM_TOOLS_H + +#include +#include + +class TopoDS_Shape; +class TopoDS_Edge; +class TopoDS_Face; + +namespace Fem +{ + +class AppFemExport Tools +{ +public: + /*! + Get the direction of the shape. If the shape is a planar face + then get its normal direction. If it's 'linear' then get its + direction vector. + @see isLinear + @see isPlanar + */ + static Base::Vector3d getDirectionFromShape(const TopoDS_Shape&); + /*! + Checks whether the curve of the edge is 'linear' which is the case + for a line or a spline or Bezier curve with collinear control points. + */ + static bool isLinear(const TopoDS_Edge&); + /*! + Checks whether the surface of the face is planar. + */ + static bool isPlanar(const TopoDS_Face&); + /*! + It is assumed that the edge is 'linear'. + The direction vector of the line is returned. + @see isLinear + */ + static gp_XYZ getDirection(const TopoDS_Edge&); + /*! + It is assumed that the face is 'planar'. + The normal vector of the plane is returned. + @see isPlanar + */ + static gp_XYZ getDirection(const TopoDS_Face&); +}; + +} //namespace Fem + + +#endif // FEM_TOOLS_H diff --git a/src/Mod/Fem/App/PreCompiled.h b/src/Mod/Fem/App/PreCompiled.h index 134ada07e..b9d2684a0 100644 --- a/src/Mod/Fem/App/PreCompiled.h +++ b/src/Mod/Fem/App/PreCompiled.h @@ -30,15 +30,15 @@ #ifdef FC_OS_WIN32 # define AppFemExport __declspec(dllexport) # define FemExport __declspec(dllexport) -# define PartExport __declspec(dllimport) +# define PartExport __declspec(dllimport) # define MeshExport __declspec(dllimport) # define BaseExport __declspec(dllimport) #else // for Linux # define AppFemExport # define FemExport -# define PartExport -# define MeshExport -# define BaseExport +# define PartExport +# define MeshExport +# define BaseExport #endif #ifdef _MSC_VER diff --git a/src/Mod/Fem/Gui/TaskFemConstraintBearing.cpp b/src/Mod/Fem/Gui/TaskFemConstraintBearing.cpp index a7d3d3a66..eb4fb2141 100644 --- a/src/Mod/Fem/Gui/TaskFemConstraintBearing.cpp +++ b/src/Mod/Fem/Gui/TaskFemConstraintBearing.cpp @@ -52,6 +52,7 @@ #include #include #include +#include #include #include @@ -172,7 +173,7 @@ void TaskFemConstraintBearing::onSelectionChanged(const Gui::SelectionChanges& m if (Objects.size() > 0) { QMessageBox::warning(this, tr("Selection error"), tr("Please use only a single reference for bearing constraint")); return; - } + } if (subName.substr(0,4) != "Face") { QMessageBox::warning(this, tr("Selection error"), tr("Only faces can be picked")); return; @@ -193,20 +194,21 @@ void TaskFemConstraintBearing::onSelectionChanged(const Gui::SelectionChanges& m // Turn off reference selection mode onButtonReference(false); - } else if (selectionMode == selloc) { + } + else if (selectionMode == selloc) { if (subName.substr(0,4) == "Face") { - BRepAdaptor_Surface surface(TopoDS::Face(ref)); - if (surface.GetType() != GeomAbs_Plane) { + if (!Fem::Tools::isPlanar(TopoDS::Face(ref))) { QMessageBox::warning(this, tr("Selection error"), tr("Only planar faces can be picked")); return; } - } else if (subName.substr(0,4) == "Edge") { - BRepAdaptor_Curve line(TopoDS::Edge(ref)); - if (line.GetType() != GeomAbs_Line) { + } + else if (subName.substr(0,4) == "Edge") { + if (!Fem::Tools::isLinear(TopoDS::Edge(ref))) { QMessageBox::warning(this, tr("Selection error"), tr("Only linear edges can be picked")); return; } - } else { + } + else { QMessageBox::warning(this, tr("Selection error"), tr("Only faces and edges can be picked")); return; } diff --git a/src/Mod/Fem/Gui/TaskFemConstraintForce.cpp b/src/Mod/Fem/Gui/TaskFemConstraintForce.cpp index 0679f2cc9..f492dfce9 100644 --- a/src/Mod/Fem/Gui/TaskFemConstraintForce.cpp +++ b/src/Mod/Fem/Gui/TaskFemConstraintForce.cpp @@ -52,6 +52,7 @@ #include #include #include +#include #include #include @@ -175,7 +176,8 @@ void TaskFemConstraintForce::onSelectionChanged(const Gui::SelectionChanges& msg QMessageBox::warning(this, tr("Selection error"), tr("Mixed shape types are not possible. Use a second constraint instead")); return; } - } else { + } + else { if ((subName.substr(0,4) != "Face") && (subName.substr(0,4) != "Edge") && (subName.substr(0,6) != "Vertex")) { QMessageBox::warning(this, tr("Selection error"), tr("Only faces, edges and vertices can be picked")); return; @@ -187,7 +189,7 @@ void TaskFemConstraintForce::onSelectionChanged(const Gui::SelectionChanges& msg for (; pos < Objects.size(); pos++) { if (obj == Objects[pos]) { break; - } + } } if (pos != Objects.size()) { @@ -204,20 +206,21 @@ void TaskFemConstraintForce::onSelectionChanged(const Gui::SelectionChanges& msg // Turn off reference selection mode onButtonReference(false); - } else if (selectionMode == seldir) { + } + else if (selectionMode == seldir) { if (subName.substr(0,4) == "Face") { - BRepAdaptor_Surface surface(TopoDS::Face(ref)); - if (surface.GetType() != GeomAbs_Plane) { + if (!Fem::Tools::isPlanar(TopoDS::Face(ref))) { QMessageBox::warning(this, tr("Selection error"), tr("Only planar faces can be picked")); return; } - } else if (subName.substr(0,4) == "Edge") { - BRepAdaptor_Curve line(TopoDS::Edge(ref)); - if (line.GetType() != GeomAbs_Line) { + } + else if (subName.substr(0,4) == "Edge") { + if (!Fem::Tools::isLinear(TopoDS::Edge(ref))) { QMessageBox::warning(this, tr("Selection error"), tr("Only linear edges can be picked")); return; } - } else { + } + else { QMessageBox::warning(this, tr("Selection error"), tr("Only faces and edges can be picked")); return; } diff --git a/src/Mod/Fem/Gui/TaskFemConstraintGear.cpp b/src/Mod/Fem/Gui/TaskFemConstraintGear.cpp index a4bd3ad0d..ed46bc8d6 100644 --- a/src/Mod/Fem/Gui/TaskFemConstraintGear.cpp +++ b/src/Mod/Fem/Gui/TaskFemConstraintGear.cpp @@ -54,6 +54,7 @@ #include #include #include +#include #include #include @@ -149,18 +150,18 @@ void TaskFemConstraintGear::onSelectionChanged(const Gui::SelectionChanges& msg) if (selectionMode == seldir) { if (subName.substr(0,4) == "Face") { - BRepAdaptor_Surface surface(TopoDS::Face(ref)); - if (surface.GetType() != GeomAbs_Plane) { + if (!Fem::Tools::isPlanar(TopoDS::Face(ref))) { QMessageBox::warning(this, tr("Selection error"), tr("Only planar faces can be picked")); return; } - } else if (subName.substr(0,4) == "Edge") { - BRepAdaptor_Curve line(TopoDS::Edge(ref)); - if (line.GetType() != GeomAbs_Line) { + } + else if (subName.substr(0,4) == "Edge") { + if (!Fem::Tools::isLinear(TopoDS::Edge(ref))) { QMessageBox::warning(this, tr("Selection error"), tr("Only linear edges can be picked")); return; } - } else { + } + else { QMessageBox::warning(this, tr("Selection error"), tr("Only faces and edges can be picked")); return; }