diff --git a/src/Mod/Surface/App/FeatureBSurf.cpp b/src/Mod/Surface/App/FeatureBSurf.cpp index d0dc734b2b..35f7d35fa1 100644 --- a/src/Mod/Surface/App/FeatureBSurf.cpp +++ b/src/Mod/Surface/App/FeatureBSurf.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #endif #include @@ -43,6 +44,99 @@ using namespace Surface; +void ShapeValidator::initValidator(void) +{ + willBezier = willBSpline = false; + edgeCount = 0; +} + +// shows error message if the shape is not an edge +bool ShapeValidator::checkEdge(const TopoDS_Shape& shape) +{ + if (shape.IsNull() || shape.ShapeType() != TopAbs_EDGE) + { + Standard_Failure::Raise("Shape is not an 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 + Standard_Failure::Raise("Mixing Bezier and non-Bezier curves is not allowed."); + return false; + } + // we will create b-spline surface + willBSpline = true; + } + else + { + // this one is Bezier + if(willBSpline) { + // already found the other type, fail + Standard_Failure::Raise("Mixing Bezier and non-Bezier curves is not allowed."); + return false; + } + // we will create Bezier surface + willBezier = true; + } + edgeCount++; + return true; +} + +void ShapeValidator::checkAndAdd(const TopoDS_Shape &shape, Handle(ShapeExtend_WireData) *aWD) +{ + if(!checkEdge(shape)) + { + return; + } + if(aWD != NULL) + { + BRepBuilderAPI_Copy copier(shape); + // make a copy of the shape and the underlying geometry to avoid to affect the input shapes + (*aWD)->Add(TopoDS::Edge(copier.Shape())); + } +} + +void ShapeValidator::checkAndAdd(const Part::TopoShape &ts, const char *subName, Handle(ShapeExtend_WireData) *aWD) +{ + + try { + // unwrap the wire + if((!ts._Shape.IsNull()) && ts._Shape.ShapeType() == TopAbs_WIRE) + { + TopoDS_Wire wire = TopoDS::Wire(ts._Shape); + for (TopExp_Explorer wireExplorer (wire, TopAbs_EDGE); wireExplorer.More(); wireExplorer.Next()) + { + checkAndAdd(wireExplorer.Current(), aWD); + } + } + else + { + if(subName != NULL && *subName != 0) + { + //we want only the subshape which is linked + checkAndAdd(ts.getSubShape(subName), aWD); + } + else + { + checkAndAdd(ts._Shape, aWD); + } + } + } + catch(Standard_Failure) { // any OCC exception means an unappropriate shape in the selection + Standard_Failure::Raise("Wrong shape type."); + return; + } +} + + PROPERTY_SOURCE(Surface::BSurf, Part::Feature) const char* BSurf::FillTypeEnums[] = {"Invalid", "Sretched", "Coons", "Curved", NULL}; @@ -90,8 +184,7 @@ void BSurf::getWire(TopoDS_Wire& aWire) return; } - BRepBuilderAPI_Copy copier; - edgeCount = 0; + initValidator(); for(int i = 0; i < boundaryListSize; i++) { App::PropertyLinkSubList::SubSet set = BoundaryList[i]; @@ -99,35 +192,7 @@ void BSurf::getWire(TopoDS_Wire& aWire) if(set.obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { const Part::TopoShape &ts = static_cast(set.obj)->Shape.getShape(); - if((!ts._Shape.IsNull()) && 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 - { - //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.IsNull()) && 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 - } - } + checkAndAdd(ts, set.sub, &aWD); } else{Standard_Failure::Raise("Curve not from Part::Feature");return;} } diff --git a/src/Mod/Surface/App/FeatureBSurf.h b/src/Mod/Surface/App/FeatureBSurf.h index af9d81f185..2f5f0844fb 100644 --- a/src/Mod/Surface/App/FeatureBSurf.h +++ b/src/Mod/Surface/App/FeatureBSurf.h @@ -25,6 +25,7 @@ #define FEATUREBSURF_H #include +#include #include #include @@ -36,8 +37,21 @@ class Handle_Geom_BoundedSurface; namespace Surface { + +class ShapeValidator +{ +protected: + bool willBezier; + bool willBSpline; + int edgeCount; + + void initValidator(void); + bool checkEdge(const TopoDS_Shape& shape); + void checkAndAdd(const TopoDS_Shape &shape, Handle(ShapeExtend_WireData) *aWD = NULL); + void checkAndAdd(const Part::TopoShape &ts, const char *subName, Handle(ShapeExtend_WireData) *aWire = NULL); +}; -class BSurf : public Part::Feature +class BSurf : public Part::Feature, public ShapeValidator { PROPERTY_HEADER(Surface::BSurf); @@ -61,9 +75,6 @@ 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/Gui/Command.cpp b/src/Mod/Surface/Gui/Command.cpp index 4ff3146f61..e3e9ab4373 100644 --- a/src/Mod/Surface/Gui/Command.cpp +++ b/src/Mod/Surface/Gui/Command.cpp @@ -37,7 +37,6 @@ #include #include #include -#include #include #endif @@ -150,7 +149,7 @@ void CmdSurfaceCut::activated(int iMsg) // Bezier and BSpline surfaces //=========================================================================== //DEF_STD_CMD_A(CmdSurfaceBSurf); -class CmdSurfaceBSurf : public Gui::Command +class CmdSurfaceBSurf : public Gui::Command, public Surface::ShapeValidator { public: CmdSurfaceBSurf(); @@ -158,12 +157,9 @@ public: virtual const char* className() const { return "CmdSurfaceBSurf"; } 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); + void showError(const char *msg); virtual void activated(int iMsg); }; @@ -178,93 +174,24 @@ 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() > 4) { + long size = Sel.size(); + if(size < 1 || 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()))) { return false; } - Part::TopoShape ts = static_cast((*it).pObject)->Shape.getShape(); - try { - // make sure the main shape type is edge or wire - if((!ts._Shape.IsNull()) && ts._Shape.ShapeType() == TopAbs_WIRE) - { - TopoDS_Wire wire = TopoDS::Wire(ts._Shape); - for (TopExp_Explorer wireExplorer (wire, TopAbs_EDGE); wireExplorer.More(); wireExplorer.Next()) - { - if(!isEdge(wireExplorer.Current())) - { - return false; - } - } - } - else - { - TopoDS_Shape shape = ts.getSubShape("Edge1"); - if(!isEdge(shape)) - { - return false; - } - } - } - catch(Standard_Failure) { // any OCC exception means an unappropriate shape in the selection - return false; - } } - return edgeCount >= 2 && edgeCount <= 4; + return true; } void CmdSurfaceBSurf::createSurface(const char *surfaceNamePrefix, const char *commandName, const char *pythonAddCommand) { - 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(); @@ -294,9 +221,51 @@ void CmdSurfaceBSurf::createSurface(const char *surfaceNamePrefix, const char *c updateActive(); } +void CmdSurfaceBSurf::showError(const char *msg) +{ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Error"), + QObject::tr(msg)); +} + void CmdSurfaceBSurf::activated(int iMsg) { - // check wich was activated and perfom it clearing the flag + initValidator(); + std::vector Sel = getSelection().getSelection(); + if (Sel.size() > 4) { + showError("Too many selected objects."); + return; + } + for (std::vector::iterator it = Sel.begin(); it != Sel.end(); ++it) + { + Gui::SelectionSingleton::SelObj selObj = *it; + if(!(selObj.pObject->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))) { + showError("Selected object is not a feature."); + return; + } + + Part::TopoShape ts = static_cast(selObj.pObject)->Shape.getShape(); + try { + checkAndAdd(ts, selObj.SubName); + } + catch(Standard_Failure sf) { + showError(sf.GetMessageString()); + return; + } + } + switch(edgeCount) { + case 2: + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Warning"), + QObject::tr("Surfaces with two edges may fail for some fill types.")); + break; + case 3: // no message + case 4: + break; + default: + showError("This tool requires 2, 3 or 4 curves."); + return; + } + + // check wich was activated and perfom and clearing the flag if(willBezier) { createSurface("BezierSurface", "Create Bezier surface", "FreeCAD.ActiveDocument.addObject(\"Surface::BezSurf\",\"%s\")");