/*************************************************************************** * Copyright (c) 2015 Stefan Tröger * * * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "FeaturePrimitive.h" #include "FeaturePy.h" #include "Mod/Part/App/TopoShapeOpCode.h" using namespace PartDesign; namespace PartDesign { const App::PropertyQuantityConstraint::Constraints torusRangeV = {-180.0, 180.0, 1.0}; const App::PropertyQuantityConstraint::Constraints angleRangeU = {0.0, 360.0, 1.0}; const App::PropertyQuantityConstraint::Constraints angleRangeV = {-90.0, 90.0, 1.0}; // it turned out that OCC cannot e.g. create a box with a width of Precision::Confusion() // with two times Precision::Confusion() all geometric primitives can be created const App::PropertyQuantityConstraint::Constraints quantityRange = {2 * Precision::Confusion(), std::numeric_limits::max(), 0.1}; const App::PropertyQuantityConstraint::Constraints quantityRangeZero = {0.0, std::numeric_limits::max(), 0.1}; PROPERTY_SOURCE_WITH_EXTENSIONS(PartDesign::FeaturePrimitive, PartDesign::FeatureAddSub) FeaturePrimitive::FeaturePrimitive() { Part::AttachExtension::initExtension(this); } App::DocumentObjectExecReturn* FeaturePrimitive::execute(const TopoDS_Shape& primitive) { if (onlyHaveRefined()) { return App::DocumentObject::StdReturn; } try { // transform the primitive in the correct coordinance FeatureAddSub::execute(); // if we have no base we just add the standard primitive shape TopoShape primitiveShape; primitiveShape.setShape(primitive); TopoShape base; try { // if we have a base shape we need to make sure that it does not get our transformation // to base = getBaseTopoShape().moved(getLocation().Inverted()); primitiveShape.Tag = -this->getID(); } catch (const Base::Exception&) { // as we use this for preview we can add it even if useless for subtractive AddSubShape.setValue(primitiveShape); if (getAddSubType() == FeatureAddSub::Additive) { Shape.setValue(getSolid(primitiveShape)); } else { return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP( "Exception", "Cannot subtract primitive feature without base feature" )); } return App::DocumentObject::StdReturn; } AddSubShape.setValue(primitiveShape); TopoShape boolOp(0); const char* maker; switch (getAddSubType()) { case Additive: maker = Part::OpCodes::Fuse; break; case Subtractive: maker = Part::OpCodes::Cut; break; default: return new App::DocumentObjectExecReturn( QT_TRANSLATE_NOOP("Exception", "Unknown operation type") ); } try { boolOp.makeElementBoolean(maker, {base, primitiveShape}); } catch (Standard_Failure&) { return new App::DocumentObjectExecReturn( QT_TRANSLATE_NOOP("Exception", "Failed to perform boolean operation") ); } TopoShape solidBoolOp = getSolid(boolOp); // lets check if the result is a solid if (solidBoolOp.isNull()) { return new App::DocumentObjectExecReturn( QT_TRANSLATE_NOOP("Exception", "Resulting shape is not a solid") ); } // store shape before refinement this->rawShape = boolOp; if (solidBoolOp == base) { // solidBoolOp is misplaced but boolOp is ok Shape.setValue(boolOp); return App::DocumentObject::StdReturn; } solidBoolOp = refineShapeIfActive(solidBoolOp); Shape.setValue(getSolid(solidBoolOp)); } catch (Standard_Failure& e) { return new App::DocumentObjectExecReturn(e.GetMessageString()); } return App::DocumentObject::StdReturn; } void FeaturePrimitive::onChanged(const App::Property* prop) { if (prop == &AttachmentOffset) { this->recompute(); return; } FeatureAddSub::onChanged(prop); } // suppress warning about tp_print for Py3.8 #if defined(__clang__) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wmissing-field-initializers" #endif PYTHON_TYPE_DEF(PrimitivePy, PartDesign::FeaturePy) // explicit bombs PYTHON_TYPE_IMP(PrimitivePy, PartDesign::FeaturePy) #if defined(__clang__) # pragma clang diagnostic pop #endif PyObject* FeaturePrimitive::getPyObject() { if (PythonObject.is(Py::_None())) { // ref counter is set to 1 PythonObject = Py::Object(new PrimitivePy(this), true); } return Py::new_reference_to(PythonObject); } PROPERTY_SOURCE(PartDesign::Box, PartDesign::FeaturePrimitive) Box::Box() { ADD_PROPERTY_TYPE(Length, (10.0f), "Box", App::Prop_None, "The length of the box"); ADD_PROPERTY_TYPE(Width, (10.0f), "Box", App::Prop_None, "The width of the box"); ADD_PROPERTY_TYPE(Height, (10.0f), "Box", App::Prop_None, "The height of the box"); Length.setConstraints(&quantityRange); Width.setConstraints(&quantityRange); Height.setConstraints(&quantityRange); primitiveType = FeaturePrimitive::Box; } App::DocumentObjectExecReturn* Box::execute() { double L = Length.getValue(); double W = Width.getValue(); double H = Height.getValue(); if (L < Precision::Confusion()) { return new App::DocumentObjectExecReturn( QT_TRANSLATE_NOOP("Exception", "Length of box too small") ); } if (W < Precision::Confusion()) { return new App::DocumentObjectExecReturn( QT_TRANSLATE_NOOP("Exception", "Width of box too small") ); } if (H < Precision::Confusion()) { return new App::DocumentObjectExecReturn( QT_TRANSLATE_NOOP("Exception", "Height of box too small") ); } try { // Build a box using the dimension attributes BRepPrimAPI_MakeBox mkBox(L, W, H); return FeaturePrimitive::execute(mkBox.Shape()); } catch (Standard_Failure& e) { return new App::DocumentObjectExecReturn(e.GetMessageString()); } } short int Box::mustExecute() const { if (Length.isTouched() || Height.isTouched() || Width.isTouched()) { return 1; } return FeaturePrimitive::mustExecute(); } PROPERTY_SOURCE(PartDesign::AdditiveBox, PartDesign::Box) PROPERTY_SOURCE(PartDesign::SubtractiveBox, PartDesign::Box) PROPERTY_SOURCE(PartDesign::Cylinder, PartDesign::FeaturePrimitive) Cylinder::Cylinder() { ADD_PROPERTY_TYPE(Radius, (10.0f), "Cylinder", App::Prop_None, "The radius of the cylinder"); ADD_PROPERTY_TYPE(Angle, (360.0f), "Cylinder", App::Prop_None, "The closing angle of the cylinder "); ADD_PROPERTY_TYPE(Height, (10.0f), "Cylinder", App::Prop_None, "The height of the cylinder"); Angle.setConstraints(&angleRangeU); Radius.setConstraints(&quantityRange); Height.setConstraints(&quantityRange); Part::PrismExtension::initExtension(this); primitiveType = FeaturePrimitive::Cylinder; } App::DocumentObjectExecReturn* Cylinder::execute() { // Build a cylinder if (Radius.getValue() < Precision::Confusion()) { return new App::DocumentObjectExecReturn( QT_TRANSLATE_NOOP("Exception", "Radius of cylinder too small") ); } if (Height.getValue() < Precision::Confusion()) { return new App::DocumentObjectExecReturn( QT_TRANSLATE_NOOP("Exception", "Height of cylinder too small") ); } if (Angle.getValue() < Precision::Confusion()) { return new App::DocumentObjectExecReturn( QT_TRANSLATE_NOOP("Exception", "Rotation angle of cylinder too small") ); } try { BRepPrimAPI_MakeCylinder mkCylr( Radius.getValue(), Height.getValue(), Base::toRadians(Angle.getValue()) ); // the direction vector for the prism is the height for z and the given angle BRepPrim_Cylinder prim = mkCylr.Cylinder(); TopoDS_Shape result = makePrism(Height.getValue(), prim.BottomFace()); return FeaturePrimitive::execute(result); } catch (Standard_Failure& e) { return new App::DocumentObjectExecReturn(e.GetMessageString()); } return App::DocumentObject::StdReturn; } short int Cylinder::mustExecute() const { if (Radius.isTouched() || Height.isTouched() || Angle.isTouched()) { return 1; } return FeaturePrimitive::mustExecute(); } PROPERTY_SOURCE(PartDesign::AdditiveCylinder, PartDesign::Cylinder) PROPERTY_SOURCE(PartDesign::SubtractiveCylinder, PartDesign::Cylinder) PROPERTY_SOURCE(PartDesign::Sphere, PartDesign::FeaturePrimitive) Sphere::Sphere() { ADD_PROPERTY_TYPE(Radius, (5.0), "Sphere", App::Prop_None, "The radius of the sphere"); Radius.setConstraints(&quantityRange); ADD_PROPERTY_TYPE(Angle1, (-90.0f), "Sphere", App::Prop_None, "The angle of the sphere"); Angle1.setConstraints(&angleRangeV); ADD_PROPERTY_TYPE(Angle2, (90.0f), "Sphere", App::Prop_None, "The angle of the sphere"); Angle2.setConstraints(&angleRangeV); ADD_PROPERTY_TYPE(Angle3, (360.0f), "Sphere", App::Prop_None, "The angle of the sphere"); Angle3.setConstraints(&angleRangeU); primitiveType = FeaturePrimitive::Sphere; } App::DocumentObjectExecReturn* Sphere::execute() { // Build a sphere if (Radius.getValue() < Precision::Confusion()) { return new App::DocumentObjectExecReturn( QT_TRANSLATE_NOOP("Exception", "Radius of sphere too small") ); } try { BRepPrimAPI_MakeSphere mkSphere( Radius.getValue(), Base::toRadians(Angle1.getValue()), Base::toRadians(Angle2.getValue()), Base::toRadians(Angle3.getValue()) ); return FeaturePrimitive::execute(mkSphere.Shape()); } catch (Standard_Failure& e) { return new App::DocumentObjectExecReturn(e.GetMessageString()); } return App::DocumentObject::StdReturn; } short int Sphere::mustExecute() const { if (Radius.isTouched() || Angle1.isTouched() || Angle2.isTouched() || Angle3.isTouched()) { return 1; } return FeaturePrimitive::mustExecute(); } PROPERTY_SOURCE(PartDesign::AdditiveSphere, PartDesign::Sphere) PROPERTY_SOURCE(PartDesign::SubtractiveSphere, PartDesign::Sphere) PROPERTY_SOURCE(PartDesign::Cone, PartDesign::FeaturePrimitive) Cone::Cone() { ADD_PROPERTY_TYPE(Radius1, (2.0), "Cone", App::Prop_None, "The radius of the cone"); ADD_PROPERTY_TYPE(Radius2, (4.0), "Cone", App::Prop_None, "The radius of the cone"); ADD_PROPERTY_TYPE(Height, (10.0), "Cone", App::Prop_None, "The height of the cone"); ADD_PROPERTY_TYPE(Angle, (360.0), "Cone", App::Prop_None, "The angle of the cone"); Angle.setConstraints(&angleRangeU); Radius1.setConstraints(&quantityRangeZero); Radius2.setConstraints(&quantityRangeZero); Height.setConstraints(&quantityRange); primitiveType = FeaturePrimitive::Cone; } App::DocumentObjectExecReturn* Cone::execute() { if (Radius1.getValue() < 0.0) { return new App::DocumentObjectExecReturn( QT_TRANSLATE_NOOP("Exception", "Radius of cone cannot be negative") ); } if (Radius2.getValue() < 0.0) { return new App::DocumentObjectExecReturn( QT_TRANSLATE_NOOP("Exception", "Radius of cone cannot be negative") ); } if (Height.getValue() < Precision::Confusion()) { return new App::DocumentObjectExecReturn( QT_TRANSLATE_NOOP("Exception", "Height of cone too small") ); } try { if (std::abs(Radius1.getValue() - Radius2.getValue()) < Precision::Confusion()) { // Build a cylinder BRepPrimAPI_MakeCylinder mkCylr( Radius1.getValue(), Height.getValue(), Base::toRadians(Angle.getValue()) ); return FeaturePrimitive::execute(mkCylr.Shape()); } // Build a cone BRepPrimAPI_MakeCone mkCone( Radius1.getValue(), Radius2.getValue(), Height.getValue(), Base::toRadians(Angle.getValue()) ); return FeaturePrimitive::execute(mkCone.Shape()); } catch (Standard_Failure& e) { return new App::DocumentObjectExecReturn(e.GetMessageString()); } return App::DocumentObject::StdReturn; } short int Cone::mustExecute() const { if (Radius1.isTouched()) { return 1; } if (Radius2.isTouched()) { return 1; } if (Height.isTouched()) { return 1; } if (Angle.isTouched()) { return 1; } return FeaturePrimitive::mustExecute(); } PROPERTY_SOURCE(PartDesign::AdditiveCone, PartDesign::Cone) PROPERTY_SOURCE(PartDesign::SubtractiveCone, PartDesign::Cone) PROPERTY_SOURCE(PartDesign::Ellipsoid, PartDesign::FeaturePrimitive) Ellipsoid::Ellipsoid() { ADD_PROPERTY_TYPE(Radius1, (2.0), "Ellipsoid", App::Prop_None, "Radius in local Z-direction"); Radius1.setConstraints(&quantityRange); ADD_PROPERTY_TYPE(Radius2, (4.0), "Ellipsoid", App::Prop_None, "Radius in local X-direction"); Radius2.setConstraints(&quantityRange); ADD_PROPERTY_TYPE( Radius3, (0.0), "Ellipsoid", App::Prop_None, "Radius in local Y-direction\nIf zero, it is equal to Radius2" ); Radius3.setConstraints(&quantityRangeZero); ADD_PROPERTY_TYPE(Angle1, (-90.0f), "Ellipsoid", App::Prop_None, "The angle of the ellipsoid"); Angle1.setConstraints(&angleRangeV); ADD_PROPERTY_TYPE(Angle2, (90.0f), "Ellipsoid", App::Prop_None, "The angle of the ellipsoid"); Angle2.setConstraints(&angleRangeV); ADD_PROPERTY_TYPE(Angle3, (360.0f), "Ellipsoid", App::Prop_None, "The angle of the ellipsoid"); Angle3.setConstraints(&angleRangeU); primitiveType = FeaturePrimitive::Ellipsoid; } App::DocumentObjectExecReturn* Ellipsoid::execute() { // Build a sphere if (Radius1.getValue() < Precision::Confusion()) { return new App::DocumentObjectExecReturn( QT_TRANSLATE_NOOP("Exception", "Radius of ellipsoid too small") ); } if (Radius2.getValue() < Precision::Confusion()) { return new App::DocumentObjectExecReturn( QT_TRANSLATE_NOOP("Exception", "Radius of ellipsoid too small") ); } try { gp_Pnt pnt(0.0, 0.0, 0.0); gp_Dir dir(0.0, 0.0, 1.0); gp_Ax2 ax2(pnt, dir); BRepPrimAPI_MakeSphere mkSphere( ax2, Radius2.getValue(), Base::toRadians(Angle1.getValue()), Base::toRadians(Angle2.getValue()), Base::toRadians(Angle3.getValue()) ); Standard_Real scaleX = 1.0; Standard_Real scaleZ = Radius1.getValue() / Radius2.getValue(); // issue #1798: A third radius has been introduced. To be backward // compatible if Radius3 is 0.0 (default) it's handled to be the same // as Radius2 Standard_Real scaleY = 1.0; if (Radius3.getValue() >= Precision::Confusion()) { scaleY = Radius3.getValue() / Radius2.getValue(); } gp_GTrsf mat; mat.SetValue(1, 1, scaleX); mat.SetValue(2, 1, 0.0); mat.SetValue(3, 1, 0.0); mat.SetValue(1, 2, 0.0); mat.SetValue(2, 2, scaleY); mat.SetValue(3, 2, 0.0); mat.SetValue(1, 3, 0.0); mat.SetValue(2, 3, 0.0); mat.SetValue(3, 3, scaleZ); BRepBuilderAPI_GTransform mkTrsf(mkSphere.Shape(), mat); return FeaturePrimitive::execute(mkTrsf.Shape()); } catch (Standard_Failure& e) { return new App::DocumentObjectExecReturn(e.GetMessageString()); } return App::DocumentObject::StdReturn; } short int Ellipsoid::mustExecute() const { if (Radius1.isTouched()) { return 1; } if (Radius2.isTouched()) { return 1; } if (Radius3.isTouched()) { return 1; } if (Angle1.isTouched()) { return 1; } if (Angle2.isTouched()) { return 1; } if (Angle3.isTouched()) { return 1; } return FeaturePrimitive::mustExecute(); } PROPERTY_SOURCE(PartDesign::AdditiveEllipsoid, PartDesign::Ellipsoid) PROPERTY_SOURCE(PartDesign::SubtractiveEllipsoid, PartDesign::Ellipsoid) PROPERTY_SOURCE(PartDesign::Torus, PartDesign::FeaturePrimitive) Torus::Torus() { ADD_PROPERTY_TYPE(Radius1, (10.0), "Torus", App::Prop_None, "Radius in local XY-plane"); Radius1.setConstraints(&quantityRange); ADD_PROPERTY_TYPE(Radius2, (2.0), "Torus", App::Prop_None, "Radius in local XZ-plane"); Radius2.setConstraints(&quantityRange); ADD_PROPERTY_TYPE(Angle1, (-180.0), "Torus", App::Prop_None, "The angle of the torus"); Angle1.setConstraints(&torusRangeV); ADD_PROPERTY_TYPE(Angle2, (180.0), "Torus", App::Prop_None, "The angle of the torus"); Angle2.setConstraints(&torusRangeV); ADD_PROPERTY_TYPE(Angle3, (360.0), "Torus", App::Prop_None, "The angle of the torus"); Angle3.setConstraints(&angleRangeU); primitiveType = FeaturePrimitive::Torus; } App::DocumentObjectExecReturn* Torus::execute() { if (Radius1.getValue() < Precision::Confusion()) { return new App::DocumentObjectExecReturn( QT_TRANSLATE_NOOP("Exception", "Radius of torus too small") ); } if (Radius2.getValue() < Precision::Confusion()) { return new App::DocumentObjectExecReturn( QT_TRANSLATE_NOOP("Exception", "Radius of torus too small") ); } try { // https://forum.freecad.org/viewtopic.php?f=3&t=52719 #if 0 BRepPrimAPI_MakeTorus mkTorus(Radius1.getValue(), Radius2.getValue(), Base::toRadians(Angle1.getValue()), Base::toRadians(Angle2.getValue()), Base::toRadians(Angle3.getValue())); return FeaturePrimitive::execute(mkTorus.Solid()); #else Part::TopoShape shape; return FeaturePrimitive::execute(shape.makeTorus( Radius1.getValue(), Radius2.getValue(), Angle1.getValue(), Angle2.getValue(), Angle3.getValue() )); #endif } catch (Standard_Failure& e) { return new App::DocumentObjectExecReturn(e.GetMessageString()); } return App::DocumentObject::StdReturn; } short int Torus::mustExecute() const { if (Radius1.isTouched()) { return 1; } if (Radius2.isTouched()) { return 1; } if (Angle1.isTouched()) { return 1; } if (Angle2.isTouched()) { return 1; } if (Angle3.isTouched()) { return 1; } return FeaturePrimitive::mustExecute(); } PROPERTY_SOURCE(PartDesign::AdditiveTorus, PartDesign::Torus) PROPERTY_SOURCE(PartDesign::SubtractiveTorus, PartDesign::Torus) PROPERTY_SOURCE(PartDesign::Prism, PartDesign::FeaturePrimitive) Prism::Prism() { ADD_PROPERTY_TYPE( Polygon, (6.0), "Prism", App::Prop_None, "Number of sides in the polygon, of the prism" ); ADD_PROPERTY_TYPE( Circumradius, (2.0), "Prism", App::Prop_None, "Circumradius (centre to vertex) of the polygon, of the prism" ); ADD_PROPERTY_TYPE(Height, (10.0f), "Prism", App::Prop_None, "The height of the prism"); Part::PrismExtension::initExtension(this); primitiveType = FeaturePrimitive::Prism; } App::DocumentObjectExecReturn* Prism::execute() { // Build a prism if (Polygon.getValue() < 3) { return new App::DocumentObjectExecReturn( QT_TRANSLATE_NOOP("Exception", "Polygon of prism is invalid, must have 3 or more sides") ); } if (Circumradius.getValue() < Precision::Confusion()) { return new App::DocumentObjectExecReturn( QT_TRANSLATE_NOOP("Exception", "Circumradius of the polygon, of the prism, is too small") ); } if (Height.getValue() < Precision::Confusion()) { return new App::DocumentObjectExecReturn( QT_TRANSLATE_NOOP("Exception", "Height of prism is too small") ); } try { long nodes = Polygon.getValue(); Base::Matrix4D mat; mat.rotZ(Base::toRadians(360.0 / nodes)); // create polygon BRepBuilderAPI_MakePolygon mkPoly; Base::Vector3d v(Circumradius.getValue(), 0, 0); for (long i = 0; i < nodes; i++) { mkPoly.Add(gp_Pnt(v.x, v.y, v.z)); v = mat * v; } mkPoly.Add(gp_Pnt(v.x, v.y, v.z)); BRepBuilderAPI_MakeFace mkFace(mkPoly.Wire()); // the direction vector for the prism is the height for z and the given angle TopoDS_Shape prism = makePrism(Height.getValue(), mkFace.Face()); return FeaturePrimitive::execute(prism); } catch (Standard_Failure& e) { return new App::DocumentObjectExecReturn(e.GetMessageString()); } return App::DocumentObject::StdReturn; } short int Prism::mustExecute() const { if (Polygon.isTouched()) { return 1; } if (Circumradius.isTouched()) { return 1; } if (Height.isTouched()) { return 1; } return FeaturePrimitive::mustExecute(); } PROPERTY_SOURCE(PartDesign::AdditivePrism, PartDesign::Prism) PROPERTY_SOURCE(PartDesign::SubtractivePrism, PartDesign::Prism) PROPERTY_SOURCE(PartDesign::Wedge, PartDesign::FeaturePrimitive) Wedge::Wedge() { ADD_PROPERTY_TYPE(Xmin, (0.0f), "Wedge", App::Prop_None, "Xmin of the wedge"); ADD_PROPERTY_TYPE(Ymin, (0.0f), "Wedge", App::Prop_None, "Ymin of the wedge"); ADD_PROPERTY_TYPE(Zmin, (0.0f), "Wedge", App::Prop_None, "Zmin of the wedge"); ADD_PROPERTY_TYPE(X2min, (2.0f), "Wedge", App::Prop_None, "X2min of the wedge"); ADD_PROPERTY_TYPE(Z2min, (2.0f), "Wedge", App::Prop_None, "Z2min of the wedge"); ADD_PROPERTY_TYPE(Xmax, (10.0f), "Wedge", App::Prop_None, "Xmax of the wedge"); ADD_PROPERTY_TYPE(Ymax, (10.0f), "Wedge", App::Prop_None, "Ymax of the wedge"); ADD_PROPERTY_TYPE(Zmax, (10.0f), "Wedge", App::Prop_None, "Zmax of the wedge"); ADD_PROPERTY_TYPE(X2max, (8.0f), "Wedge", App::Prop_None, "X2max of the wedge"); ADD_PROPERTY_TYPE(Z2max, (8.0f), "Wedge", App::Prop_None, "Z2max of the wedge"); primitiveType = FeaturePrimitive::Wedge; } App::DocumentObjectExecReturn* Wedge::execute() { double xmin = Xmin.getValue(); double ymin = Ymin.getValue(); double zmin = Zmin.getValue(); double z2min = Z2min.getValue(); double x2min = X2min.getValue(); double xmax = Xmax.getValue(); double ymax = Ymax.getValue(); double zmax = Zmax.getValue(); double z2max = Z2max.getValue(); double x2max = X2max.getValue(); double dx = xmax - xmin; double dy = ymax - ymin; double dz = zmax - zmin; double dz2 = z2max - z2min; double dx2 = x2max - x2min; if (dx < Precision::Confusion()) { return new App::DocumentObjectExecReturn( QT_TRANSLATE_NOOP("Exception", "delta x of wedge too small") ); } if (dy < Precision::Confusion()) { return new App::DocumentObjectExecReturn( QT_TRANSLATE_NOOP("Exception", "delta y of wedge too small") ); } if (dz < Precision::Confusion()) { return new App::DocumentObjectExecReturn( QT_TRANSLATE_NOOP("Exception", "delta z of wedge too small") ); } if (dz2 < 0) { return new App::DocumentObjectExecReturn( QT_TRANSLATE_NOOP("Exception", "delta z2 of wedge is negative") ); } if (dx2 < 0) { return new App::DocumentObjectExecReturn( QT_TRANSLATE_NOOP("Exception", "delta x2 of wedge is negative") ); } try { gp_Pnt pnt(0.0, 0.0, 0.0); gp_Dir dir(0.0, 0.0, 1.0); BRepPrim_Wedge mkWedge(gp_Ax2(pnt, dir), xmin, ymin, zmin, z2min, x2min, xmax, ymax, zmax, z2max, x2max); BRepBuilderAPI_MakeSolid mkSolid; mkSolid.Add(mkWedge.Shell()); return FeaturePrimitive::execute(mkSolid.Solid()); } catch (Standard_Failure& e) { return new App::DocumentObjectExecReturn(e.GetMessageString()); } return App::DocumentObject::StdReturn; } short int Wedge::mustExecute() const { if (Xmin.isTouched() || Ymin.isTouched() || Zmin.isTouched() || X2min.isTouched() || Z2min.isTouched() || Xmax.isTouched() || Ymax.isTouched() || Zmax.isTouched() || X2max.isTouched() || Z2max.isTouched()) { return 1; } return FeaturePrimitive::mustExecute(); } PROPERTY_SOURCE(PartDesign::AdditiveWedge, PartDesign::Wedge) PROPERTY_SOURCE(PartDesign::SubtractiveWedge, PartDesign::Wedge) } // namespace PartDesign