From 0af6fc089447d02ec4dd1751a11a263446ada163 Mon Sep 17 00:00:00 2001 From: balazs-bamer Date: Sat, 7 Feb 2015 18:58:25 +0100 Subject: [PATCH] allow wires as surface input Now an arbitrary mixture of edges and wires can be used as input. However, the total count of edges together with the wire members can only be 2, 3 or 4. For some reason, wires do not work in Python script: test1.BoundaryList = [(Draft.upgrade([bs1a, bs2a]), 'Wire1')] yields an empty BoundaryList --- src/Mod/Surface/App/FeatureBSplineSurf.cpp | 7 +- src/Mod/Surface/App/FeatureBSurf.cpp | 59 +++++++----- src/Mod/Surface/App/FeatureBSurf.h | 3 + src/Mod/Surface/App/FeatureBezSurf.cpp | 7 +- src/Mod/Surface/Gui/Command.cpp | 106 +++++++++++++-------- 5 files changed, 114 insertions(+), 68 deletions(-) diff --git a/src/Mod/Surface/App/FeatureBSplineSurf.cpp b/src/Mod/Surface/App/FeatureBSplineSurf.cpp index 8d67c97e62..fe6270ae0c 100644 --- a/src/Mod/Surface/App/FeatureBSplineSurf.cpp +++ b/src/Mod/Surface/App/FeatureBSplineSurf.cpp @@ -107,10 +107,9 @@ App::DocumentObjectExecReturn *BSplineSurf::execute(void) GeomFill_FillingStyle fstyle = getFillingStyle(); GeomFill_BSplineCurves aSurfBuilder; //Create Surface Builder - int ncrv = BoundaryList.getSize(); - if(ncrv==2) {aSurfBuilder.Init(crvs[0], crvs[1], fstyle);} - else if(ncrv==3) {aSurfBuilder.Init(crvs[0], crvs[1], crvs[2], fstyle);} - else if(ncrv==4) {aSurfBuilder.Init(crvs[0], crvs[1], crvs[2], crvs[3], fstyle);} + if(edgeCount==2) {aSurfBuilder.Init(crvs[0], crvs[1], fstyle);} + else if(edgeCount==3) {aSurfBuilder.Init(crvs[0], crvs[1], crvs[2], fstyle);} + else if(edgeCount==4) {aSurfBuilder.Init(crvs[0], crvs[1], crvs[2], crvs[3], fstyle);} createFace(aSurfBuilder.Surface()); diff --git a/src/Mod/Surface/App/FeatureBSurf.cpp b/src/Mod/Surface/App/FeatureBSurf.cpp index bc85b1afbe..4b0adfdaba 100644 --- a/src/Mod/Surface/App/FeatureBSurf.cpp +++ b/src/Mod/Surface/App/FeatureBSurf.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #endif #include @@ -82,43 +83,57 @@ void BSurf::getWire(TopoDS_Wire& aWire) Handle(ShapeExtend_WireData) aWD = new ShapeExtend_WireData; int boundaryListSize = BoundaryList.getSize(); - if(boundaryListSize > 4 || boundaryListSize < 2) + if(boundaryListSize > 4) // if too many not even try { Standard_Failure::Raise("Only 2-4 curves are allowed"); return; } + BRepBuilderAPI_Copy copier; + edgeCount = 0; for(int i = 0; i < boundaryListSize; i++) { - Part::TopoShape ts; //Curve TopoShape - TopoDS_Shape sub; //Curve TopoDS_Shape - TopoDS_Edge etmp; //Curve TopoDS_Edge - - //Get Edge App::PropertyLinkSubList::SubSet set = BoundaryList[i]; if(set.obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { - ts = static_cast(set.obj)->Shape.getShape(); - - //we want only the subshape which is linked - sub = ts.getSubShape(set.sub); - // make a copy of the shape and the underlying geometry to avoid to affect the input shapes - BRepBuilderAPI_Copy copy(sub); - sub = copy.Shape(); - - if(sub.ShapeType() == TopAbs_EDGE) { //Check Shape type and assign edge - etmp = TopoDS::Edge(sub); + const Part::TopoShape &ts = static_cast(set.obj)->Shape.getShape(); + if(ts._Shape.ShapeType() == TopAbs_WIRE) + { + const TopoDS_Wire &wire = TopoDS::Wire(ts._Shape); + // resolve the wire, we need edges from now on + for (TopExp_Explorer wireExplorer (wire, TopAbs_EDGE); wireExplorer.More(); wireExplorer.Next()) + { + // make a copy of the shape and the underlying geometry to avoid to affect the input shapes + copier.Perform(wireExplorer.Current()); + aWD->Add(TopoDS::Edge(copier.Shape())); + edgeCount++; + } } - else { - Standard_Failure::Raise("Curves must be type TopoDS_Edge"); - return; //Raise exception - } - aWD->Add(etmp); + else + { + //we want only the subshape which is linked + const TopoDS_Shape &sub = ts.getSubShape(set.sub); + // make a copy of the shape and the underlying geometry to avoid to affect the input shapes + copier.Perform(sub); + const TopoDS_Shape © = copier.Shape(); + if(copy.ShapeType() == TopAbs_EDGE) { //Check Shape type and assign edge + aWD->Add(TopoDS::Edge(copy)); + edgeCount++; + } + else { + Standard_Failure::Raise("Curves must be of type TopoDS_Edge or TopoDS_Wire"); + return; //Raise exception + } + } } else{Standard_Failure::Raise("Curve not from Part::Feature");return;} - + } + if(edgeCount < 2 || edgeCount > 4) + { + Standard_Failure::Raise("Only 2-4 curves are allowed"); + return; } //Reorder the curves and fix the wire if required diff --git a/src/Mod/Surface/App/FeatureBSurf.h b/src/Mod/Surface/App/FeatureBSurf.h index 287ae206de..af9d81f185 100644 --- a/src/Mod/Surface/App/FeatureBSurf.h +++ b/src/Mod/Surface/App/FeatureBSurf.h @@ -61,6 +61,9 @@ protected: // corrects the initially invalid fill type void correcteInvalidFillType(); + // number of edges is a result of calculating single and wire edges + int edgeCount; + private: static const char* FillTypeEnums[]; }; diff --git a/src/Mod/Surface/App/FeatureBezSurf.cpp b/src/Mod/Surface/App/FeatureBezSurf.cpp index de4dad2ff4..ad90184b82 100644 --- a/src/Mod/Surface/App/FeatureBezSurf.cpp +++ b/src/Mod/Surface/App/FeatureBezSurf.cpp @@ -89,10 +89,9 @@ App::DocumentObjectExecReturn *BezSurf::execute(void) GeomFill_FillingStyle fstyle = getFillingStyle(); GeomFill_BezierCurves aSurfBuilder; //Create Surface Builder - int ncrv = BoundaryList.getSize(); - if(ncrv==2) {aSurfBuilder.Init(crvs[0], crvs[1], fstyle);} - else if(ncrv==3) {aSurfBuilder.Init(crvs[0], crvs[1], crvs[2], fstyle);} - else if(ncrv==4) {aSurfBuilder.Init(crvs[0], crvs[1], crvs[2], crvs[3], fstyle);} + if(edgeCount==2) {aSurfBuilder.Init(crvs[0], crvs[1], fstyle);} + else if(edgeCount==3) {aSurfBuilder.Init(crvs[0], crvs[1], crvs[2], fstyle);} + else if(edgeCount==4) {aSurfBuilder.Init(crvs[0], crvs[1], crvs[2], crvs[3], fstyle);} createFace(aSurfBuilder.Surface()); diff --git a/src/Mod/Surface/Gui/Command.cpp b/src/Mod/Surface/Gui/Command.cpp index 6794f3a33d..819d0c4630 100644 --- a/src/Mod/Surface/Gui/Command.cpp +++ b/src/Mod/Surface/Gui/Command.cpp @@ -160,6 +160,8 @@ public: protected: bool willBezier; bool willBSpline; + int edgeCount; + bool isEdge(const TopoDS_Shape& shape); virtual bool isActive(void); void createSurface(const char *surfaceNamePrefix, const char *commandName, const char *pythonAddCommand); virtual void activated(int iMsg); @@ -176,13 +178,51 @@ CmdSurfaceBSurf::CmdSurfaceBSurf() : Command("Surface_BSurf") sPixmap = "BSplineSurf"; } +bool CmdSurfaceBSurf::isEdge(const TopoDS_Shape& shape) +{ + if (shape.IsNull() || shape.ShapeType() != TopAbs_EDGE) + { + return false; + } + TopoDS_Edge etmp = TopoDS::Edge(shape); //Curve TopoDS_Edge + TopLoc_Location heloc; // this will be output + Standard_Real u0;// contains output + Standard_Real u1;// contains output + Handle_Geom_Curve c_geom = BRep_Tool::Curve(etmp,heloc,u0,u1); //The geometric curve + Handle_Geom_BezierCurve bez_geom = Handle_Geom_BezierCurve::DownCast(c_geom); //Try to get Bezier curve + if (bez_geom.IsNull()) + { + // this one is not Bezier, we hope it can be converted into b-spline + if(willBezier) { + // already found the other type, fail + return false; + } + // we will create b-spline surface + willBSpline = true; + } + else + { + // this one is Bezier + if(willBSpline) { + // already found the other type, fail + return false; + } + // we will create Bezier surface + willBezier = true; + } + edgeCount++; + return true; +} + bool CmdSurfaceBSurf::isActive(void) { willBezier = willBSpline = false; std::vector Sel = getSelection().getSelection(); - if (Sel.size() < 2 || Sel.size() > 4) { + if (Sel.size() > 4) { return false; } + // we need to count them inside wires, too + edgeCount = 0; for (std::vector::iterator it = Sel.begin(); it != Sel.end(); ++it) { if(!((*it).pObject->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))) { @@ -191,67 +231,57 @@ bool CmdSurfaceBSurf::isActive(void) Part::TopoShape ts = static_cast((*it).pObject)->Shape.getShape(); try { // make sure the main shape type is edge or wire - TopAbs_ShapeEnum shapeType = ts._Shape.ShapeType(); - if(shapeType != TopAbs_WIRE && shapeType != TopAbs_EDGE) + if(ts._Shape.ShapeType() == TopAbs_WIRE) { - return false; - } - TopoDS_Shape shape = ts.getSubShape("Edge1"); - if (shape.IsNull()) - { - return false; - } - if(shape.ShapeType() != TopAbs_EDGE) { //Check Shape type and assign edge - return false; - } - TopoDS_Edge etmp = TopoDS::Edge(shape); //Curve TopoDS_Edge - TopLoc_Location heloc; // this will be output - Standard_Real u0;// contains output - Standard_Real u1;// contains output - Handle_Geom_Curve c_geom = BRep_Tool::Curve(etmp,heloc,u0,u1); //The geometric curve - Handle_Geom_BezierCurve bez_geom = Handle_Geom_BezierCurve::DownCast(c_geom); //Try to get Bezier curve - if (bez_geom.IsNull()) - { - // this one is not Bezier, we hope it can be converted into b-spline - if(willBezier) { - // already found the other type, fail - return false; + TopoDS_Wire wire = TopoDS::Wire(ts._Shape); + for (TopExp_Explorer wireExplorer (wire, TopAbs_EDGE); wireExplorer.More(); wireExplorer.Next()) + { + if(!isEdge(wireExplorer.Current())) + { + return false; + } } - // we will create b-spline surface - willBSpline = true; } else { - // this one is Bezier - if(willBSpline) { - // already found the other type, fail + TopoDS_Shape shape = ts.getSubShape("Edge1"); + if(!isEdge(shape)) + { return false; } - // we will create Bezier surface - willBezier = true; } } catch(Standard_Failure) { // any OCC exception means an unappropriate shape in the selection return false; } } - return true; + return edgeCount >= 2 && edgeCount <= 4; } void CmdSurfaceBSurf::createSurface(const char *surfaceNamePrefix, const char *commandName, const char *pythonAddCommand) { - // we take the whole selection and require that all of its members are of the required curve - std::vector sel = getSelection().getSelectionEx(0); - if (sel.size() == 2) { + if (edgeCount == 2) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Warning"), QObject::tr("Surfaces with two edges may fail for some fill types.")); } std::string FeatName = getUniqueObjectName(surfaceNamePrefix); std::stringstream bspListCmd; + std::vector Sel = getSelection().getSelection(); bspListCmd << "FreeCAD.ActiveDocument.ActiveObject.BoundaryList = ["; - for (std::vector::iterator it = sel.begin(); it != sel.end(); ++it) { - bspListCmd << "(App.activeDocument()." << it->getFeatName() << ", \'Edge1\'),"; + for (std::vector::iterator it = Sel.begin(); it != Sel.end(); ++it) + { + Part::TopoShape ts = static_cast((*it).pObject)->Shape.getShape(); + bspListCmd << "(App.activeDocument()." << it->FeatName; + // if it is wire, add as wire + if(ts._Shape.ShapeType() == TopAbs_WIRE) + { + bspListCmd << ", \'Wire1\'),"; + } + else + { + bspListCmd << ", \'Edge1\'),"; + } } bspListCmd << "]";