/*************************************************************************** * Copyright (c) 2007 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 # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include #endif #include "PrimitiveFeature.h" #include #include #include #include #ifndef M_PI #define M_PI 3.14159265358979323846 #endif namespace Part { const App::PropertyQuantityConstraint::Constraints apexRange = {0.0,90.0,0.1}; 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}; const App::PropertyQuantityConstraint::Constraints quantityRange = {0.0,FLT_MAX,0.1}; } using namespace Part; PROPERTY_SOURCE_ABSTRACT(Part::Primitive, Part::Feature) Primitive::Primitive(void) { touch(); } Primitive::~Primitive() { } short Primitive::mustExecute(void) const { return Feature::mustExecute(); } void Primitive::Restore(Base::XMLReader &reader) { reader.readElement("Properties"); int Cnt = reader.getAttributeAsInteger("Count"); for (int i=0 ;igetTypeId().getName(), TypeName) == 0) { prop->Restore(reader); } else if (prop) { Base::Type inputType = Base::Type::fromName(TypeName); if (prop->getTypeId().isDerivedFrom(App::PropertyFloat::getClassTypeId()) && inputType.isDerivedFrom(App::PropertyFloat::getClassTypeId())) { // Do not directly call the property's Restore method in case the implmentation // has changed. So, create a temporary PropertyFloat object and assign the value. App::PropertyFloat floatProp; floatProp.Restore(reader); static_cast(prop)->setValue(floatProp.getValue()); } } } catch (const Base::XMLParseException&) { throw; // re-throw } catch (const Base::Exception &e) { Base::Console().Error("%s\n", e.what()); } catch (const std::exception &e) { Base::Console().Error("%s\n", e.what()); } catch (const char* e) { Base::Console().Error("%s\n", e); } #ifndef FC_DEBUG catch (...) { Base::Console().Error("Primitive::Restore: Unknown C++ exception thrown"); } #endif reader.readEndElement("Property"); } reader.readEndElement("Properties"); } void Primitive::onChanged(const App::Property* prop) { if (!isRestoring()) { // Do not support sphere, ellipsoid and torus because the creation // takes too long and thus is not feasible std::string grp = (prop->getGroup() ? prop->getGroup() : ""); if (grp == "Plane" || grp == "Cylinder" || grp == "Cone") { try { App::DocumentObjectExecReturn *ret = recompute(); delete ret; } catch (...) { } } } Part::Feature::onChanged(prop); } PROPERTY_SOURCE(Part::Vertex, Part::Primitive) Vertex::Vertex() { ADD_PROPERTY(X,(0.0f)); ADD_PROPERTY(Y,(0.0f)); ADD_PROPERTY(Z,(0.0f)); } Vertex::~Vertex() { } short Vertex::mustExecute() const { if (X.isTouched() || Y.isTouched() || Z.isTouched()) return 1; return Part::Feature::mustExecute(); } App::DocumentObjectExecReturn *Vertex::execute(void) { gp_Pnt point; point.SetX(this->X.getValue()); point.SetY(this->Y.getValue()); point.SetZ(this->Z.getValue()); BRepBuilderAPI_MakeVertex MakeVertex(point); const TopoDS_Vertex& vertex = MakeVertex.Vertex(); this->Shape.setValue(vertex); return App::DocumentObject::StdReturn; } void Vertex::onChanged(const App::Property* prop) { if (!isRestoring()) { if (prop == &X || prop == &Y || prop == &Z){ try { App::DocumentObjectExecReturn *ret = recompute(); delete ret; } catch (...) { } } } Part::Feature::onChanged(prop); } PROPERTY_SOURCE(Part::Line, Part::Primitive) Line::Line() { ADD_PROPERTY_TYPE(X1,(0.0),"Vertex 1 - Start",App::Prop_None,"X value of the start vertex"); ADD_PROPERTY_TYPE(Y1,(0.0),"Vertex 1 - Start",App::Prop_None,"Y value of the Start vertex"); ADD_PROPERTY_TYPE(Z1,(0.0),"Vertex 1 - Start",App::Prop_None,"Z value of the Start vertex"); ADD_PROPERTY_TYPE(X2,(0.0),"Vertex 2 - Finish",App::Prop_None,"X value of the finish vertex"); ADD_PROPERTY_TYPE(Y2,(0.0),"Vertex 2 - Finish",App::Prop_None,"Y value of the finish vertex"); ADD_PROPERTY_TYPE(Z2,(1.0),"Vertex 2 - Finish",App::Prop_None,"Z value of the finish vertex"); } Line::~Line() { } short Line::mustExecute() const { if (X1.isTouched() || Y1.isTouched() || Z1.isTouched() || X2.isTouched() || Y2.isTouched() || Z2.isTouched()) return 1; return Part::Feature::mustExecute(); } App::DocumentObjectExecReturn *Line::execute(void) { gp_Pnt point1; point1.SetX(this->X1.getValue()); point1.SetY(this->Y1.getValue()); point1.SetZ(this->Z1.getValue()); gp_Pnt point2; point2.SetX(this->X2.getValue()); point2.SetY(this->Y2.getValue()); point2.SetZ(this->Z2.getValue()); BRepBuilderAPI_MakeEdge mkEdge(point1, point2); if (!mkEdge.IsDone()) return new App::DocumentObjectExecReturn("Failed to create edge"); const TopoDS_Edge& edge = mkEdge.Edge(); this->Shape.setValue(edge); return App::DocumentObject::StdReturn; } void Line::onChanged(const App::Property* prop) { if (!isRestoring()) { if (prop == &X1 || prop == &Y1 || prop == &Z1 || prop == &X2 || prop == &Y2 || prop == &Z2){ try { App::DocumentObjectExecReturn *ret = recompute(); delete ret; } catch (...) { } } } Part::Feature::onChanged(prop); } PROPERTY_SOURCE(Part::Plane, Part::Primitive) Plane::Plane() { ADD_PROPERTY_TYPE(Length,(100.0f),"Plane",App::Prop_None,"The length of the plane"); ADD_PROPERTY_TYPE(Width ,(100.0f),"Plane",App::Prop_None,"The width of the plane"); } short Plane::mustExecute() const { if (Length.isTouched() || Width.isTouched() ) return 1; return Primitive::mustExecute(); } App::DocumentObjectExecReturn *Plane::execute(void) { double L = this->Length.getValue(); double W = this->Width.getValue(); if (L < Precision::Confusion()) return new App::DocumentObjectExecReturn("Length of plane too small"); if (W < Precision::Confusion()) return new App::DocumentObjectExecReturn("Width of plane too small"); gp_Pnt pnt(0.0,0.0,0.0); gp_Dir dir(0.0,0.0,1.0); Handle_Geom_Plane aPlane = new Geom_Plane(pnt, dir); BRepBuilderAPI_MakeFace mkFace(aPlane, 0.0, L, 0.0, W #if OCC_VERSION_HEX >= 0x060502 , Precision::Confusion() #endif ); const char *error=0; switch (mkFace.Error()) { case BRepBuilderAPI_FaceDone: break; // ok case BRepBuilderAPI_NoFace: error = "no face"; break; case BRepBuilderAPI_NotPlanar: error = "not planar"; break; case BRepBuilderAPI_CurveProjectionFailed: break; case BRepBuilderAPI_ParametersOutOfRange: error = "parameters out of range"; break; #if OCC_VERSION_HEX < 0x060500 case BRepBuilderAPI_SurfaceNotC2: error = "surface not C2"; break; #endif default: error = "unknown error"; break; } // Error ? if (error) { return new App::DocumentObjectExecReturn(error); } TopoDS_Shape ResultShape = mkFace.Shape(); this->Shape.setValue(ResultShape); return App::DocumentObject::StdReturn; } PROPERTY_SOURCE(Part::Sphere, Part::Primitive) Sphere::Sphere(void) { 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); } short Sphere::mustExecute() const { if (Radius.isTouched()) return 1; if (Angle1.isTouched()) return 1; if (Angle2.isTouched()) return 1; if (Angle3.isTouched()) return 1; return Primitive::mustExecute(); } App::DocumentObjectExecReturn *Sphere::execute(void) { // Build a sphere if (Radius.getValue() < Precision::Confusion()) return new App::DocumentObjectExecReturn("Radius of sphere too small"); try { BRepPrimAPI_MakeSphere mkSphere(Radius.getValue(), Angle1.getValue()/180.0f*M_PI, Angle2.getValue()/180.0f*M_PI, Angle3.getValue()/180.0f*M_PI); TopoDS_Shape ResultShape = mkSphere.Shape(); this->Shape.setValue(ResultShape); } catch (Standard_Failure) { Handle_Standard_Failure e = Standard_Failure::Caught(); return new App::DocumentObjectExecReturn(e->GetMessageString()); } return App::DocumentObject::StdReturn; } PROPERTY_SOURCE(Part::Ellipsoid, Part::Primitive) Ellipsoid::Ellipsoid(void) { ADD_PROPERTY_TYPE(Radius1,(2.0),"Ellipsoid",App::Prop_None,"The radius of the ellipsoid"); Radius1.setConstraints(&quantityRange); ADD_PROPERTY_TYPE(Radius2,(4.0),"Ellipsoid",App::Prop_None,"The radius of the ellipsoid"); Radius2.setConstraints(&quantityRange); ADD_PROPERTY_TYPE(Radius3,(0.0),"Ellipsoid",App::Prop_None,"The radius of the ellipsoid"); Radius3.setConstraints(&quantityRange); 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); } short 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 Primitive::mustExecute(); } App::DocumentObjectExecReturn *Ellipsoid::execute(void) { // Build a sphere if (Radius1.getValue() < Precision::Confusion()) return new App::DocumentObjectExecReturn("Radius of ellipsoid too small"); if (Radius2.getValue() < Precision::Confusion()) return new App::DocumentObjectExecReturn("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(), Angle1.getValue()/180.0f*M_PI, Angle2.getValue()/180.0f*M_PI, Angle3.getValue()/180.0f*M_PI); 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); TopoDS_Shape ResultShape = mkTrsf.Shape(); this->Shape.setValue(ResultShape); } catch (Standard_Failure) { Handle_Standard_Failure e = Standard_Failure::Caught(); return new App::DocumentObjectExecReturn(e->GetMessageString()); } return App::DocumentObject::StdReturn; } PROPERTY_SOURCE(Part::Cylinder, Part::Primitive) Cylinder::Cylinder(void) { ADD_PROPERTY_TYPE(Radius,(2.0),"Cylinder",App::Prop_None,"The radius of the cylinder"); ADD_PROPERTY_TYPE(Height,(10.0f),"Cylinder",App::Prop_None,"The height of the cylinder"); ADD_PROPERTY_TYPE(Angle,(360.0f),"Cylinder",App::Prop_None,"The angle of the cylinder"); Angle.setConstraints(&angleRangeU); } short Cylinder::mustExecute() const { if (Radius.isTouched()) return 1; if (Height.isTouched()) return 1; if (Angle.isTouched()) return 1; return Primitive::mustExecute(); } App::DocumentObjectExecReturn *Cylinder::execute(void) { // Build a cylinder if (Radius.getValue() < Precision::Confusion()) return new App::DocumentObjectExecReturn("Radius of cylinder too small"); if (Height.getValue() < Precision::Confusion()) return new App::DocumentObjectExecReturn("Height of cylinder too small"); try { BRepPrimAPI_MakeCylinder mkCylr(Radius.getValue(), Height.getValue(), Angle.getValue()/180.0f*M_PI); TopoDS_Shape ResultShape = mkCylr.Shape(); this->Shape.setValue(ResultShape); } catch (Standard_Failure) { Handle_Standard_Failure e = Standard_Failure::Caught(); return new App::DocumentObjectExecReturn(e->GetMessageString()); } return App::DocumentObject::StdReturn; } App::PropertyIntegerConstraint::Constraints Prism::polygonRange = {3,INT_MAX,1}; PROPERTY_SOURCE(Part::Prism, Part::Primitive) Prism::Prism(void) { 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"); Polygon.setConstraints(&polygonRange); } short Prism::mustExecute() const { if (Polygon.isTouched()) return 1; if (Circumradius.isTouched()) return 1; if (Height.isTouched()) return 1; return Primitive::mustExecute(); } App::DocumentObjectExecReturn *Prism::execute(void) { // Build a prism if (Polygon.getValue() < 3) return new App::DocumentObjectExecReturn("Polygon of prism is invalid, must have 3 or more sides"); if (Circumradius.getValue() < Precision::Confusion()) return new App::DocumentObjectExecReturn("Circumradius of the polygon, of the prism, is too small"); if (Height.getValue() < Precision::Confusion()) return new App::DocumentObjectExecReturn("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; iShape.setValue(mkPrism.Shape()); } catch (Standard_Failure) { Handle_Standard_Failure e = Standard_Failure::Caught(); return new App::DocumentObjectExecReturn(e->GetMessageString()); } return App::DocumentObject::StdReturn; } App::PropertyIntegerConstraint::Constraints RegularPolygon::polygon = {3,INT_MAX,1}; PROPERTY_SOURCE(Part::RegularPolygon, Part::Primitive) RegularPolygon::RegularPolygon(void) { ADD_PROPERTY_TYPE(Polygon,(6.0),"RegularPolygon",App::Prop_None,"Number of sides in the regular polygon"); ADD_PROPERTY_TYPE(Circumradius,(2.0),"RegularPolygon",App::Prop_None,"Circumradius (centre to vertex) of the polygon"); Polygon.setConstraints(&polygon); } short RegularPolygon::mustExecute() const { if (Polygon.isTouched()) return 1; if (Circumradius.isTouched()) return 1; return Primitive::mustExecute(); } App::DocumentObjectExecReturn *RegularPolygon::execute(void) { // Build a regular polygon if (Polygon.getValue() < 3) return new App::DocumentObjectExecReturn("the polygon is invalid, must have 3 or more sides"); if (Circumradius.getValue() < Precision::Confusion()) return new App::DocumentObjectExecReturn("Circumradius of the polygon 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; iShape.setValue(mkPoly.Shape()); } catch (Standard_Failure) { Handle_Standard_Failure e = Standard_Failure::Caught(); return new App::DocumentObjectExecReturn(e->GetMessageString()); } return App::DocumentObject::StdReturn; } PROPERTY_SOURCE(Part::Cone, Part::Primitive) Cone::Cone(void) { 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); } short Cone::mustExecute() const { if (Radius1.isTouched()) return 1; if (Radius2.isTouched()) return 1; if (Height.isTouched()) return 1; if (Angle.isTouched()) return 1; return Primitive::mustExecute(); } App::DocumentObjectExecReturn *Cone::execute(void) { if (Radius1.getValue() < 0) return new App::DocumentObjectExecReturn("Radius of cone too small"); if (Radius2.getValue() < 0) return new App::DocumentObjectExecReturn("Radius of cone too small"); if (Height.getValue() < Precision::Confusion()) return new App::DocumentObjectExecReturn("Height of cone too small"); try { // Build a cone BRepPrimAPI_MakeCone mkCone(Radius1.getValue(), Radius2.getValue(), Height.getValue(), Angle.getValue()/180.0f*M_PI); TopoDS_Shape ResultShape = mkCone.Shape(); this->Shape.setValue(ResultShape); } catch (Standard_Failure) { Handle_Standard_Failure e = Standard_Failure::Caught(); return new App::DocumentObjectExecReturn(e->GetMessageString()); } return App::DocumentObject::StdReturn; } PROPERTY_SOURCE(Part::Torus, Part::Primitive) Torus::Torus(void) { ADD_PROPERTY_TYPE(Radius1,(10.0),"Torus",App::Prop_None,"The radius of the torus"); Radius1.setConstraints(&quantityRange); ADD_PROPERTY_TYPE(Radius2,(2.0),"Torus",App::Prop_None,"The radius of the torus"); 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); } short 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 Primitive::mustExecute(); } App::DocumentObjectExecReturn *Torus::execute(void) { if (Radius1.getValue() < Precision::Confusion()) return new App::DocumentObjectExecReturn("Radius of torus too small"); if (Radius2.getValue() < Precision::Confusion()) return new App::DocumentObjectExecReturn("Radius of torus too small"); try { #if 1 // Build a torus gp_Circ circle; circle.SetRadius(Radius2.getValue()); gp_Pnt pos(Radius1.getValue(),0,0); gp_Dir dir(0,1,0); circle.SetAxis(gp_Ax1(pos, dir)); BRepBuilderAPI_MakeEdge mkEdge(circle, Base::toRadians(Angle1.getValue()+180.0f), Base::toRadians(Angle2.getValue()+180.0f)); BRepBuilderAPI_MakeWire mkWire; mkWire.Add(mkEdge.Edge()); BRepBuilderAPI_MakeFace mkFace(mkWire.Wire()); BRepPrimAPI_MakeRevol mkRevol(mkFace.Face(), gp_Ax1(gp_Pnt(0,0,0), gp_Dir(0,0,1)), Base::toRadians(Angle3.getValue()), Standard_True); TopoDS_Shape ResultShape = mkRevol.Shape(); #else BRepPrimAPI_MakeTorus mkTorus(Radius1.getValue(), Radius2.getValue(), Angle1.getValue()/180.0f*Standard_PI, Angle2.getValue()/180.0f*Standard_PI, Angle3.getValue()/180.0f*Standard_PI); const TopoDS_Solid& ResultShape = mkTorus.Solid(); #endif this->Shape.setValue(ResultShape); } catch (Standard_Failure) { Handle_Standard_Failure e = Standard_Failure::Caught(); return new App::DocumentObjectExecReturn(e->GetMessageString()); } return App::DocumentObject::StdReturn; } PROPERTY_SOURCE(Part::Helix, Part::Primitive) const char* Part::Helix::LocalCSEnums[]= {"Right-handed","Left-handed",NULL}; const char* Part::Helix::StyleEnums []= {"Old style","New style",NULL}; Helix::Helix(void) { ADD_PROPERTY_TYPE(Pitch, (1.0),"Helix",App::Prop_None,"The pitch of the helix"); Pitch.setConstraints(&quantityRange); ADD_PROPERTY_TYPE(Height,(2.0),"Helix",App::Prop_None,"The height of the helix"); Height.setConstraints(&quantityRange); ADD_PROPERTY_TYPE(Radius,(1.0),"Helix",App::Prop_None,"The radius of the helix"); Radius.setConstraints(&quantityRange); ADD_PROPERTY_TYPE(Angle,(0.0),"Helix",App::Prop_None,"If angle is > 0 a conical otherwise a cylindircal surface is used"); Angle.setConstraints(&apexRange); ADD_PROPERTY_TYPE(LocalCoord,(long(0)),"Coordinate System",App::Prop_None,"Orientation of the local coordinate system of the helix"); LocalCoord.setEnums(LocalCSEnums); ADD_PROPERTY_TYPE(Style,(long(0)),"Helix style",App::Prop_Hidden,"Old style creates incorrect and new style create correct helices"); Style.setEnums(StyleEnums); } void Helix::onChanged(const App::Property* prop) { if (!isRestoring()) { if (prop == &Pitch || prop == &Height || prop == &Radius || prop == &Angle || prop == &LocalCoord || prop == &Style) { try { App::DocumentObjectExecReturn *ret = recompute(); delete ret; } catch (...) { } } } Part::Feature::onChanged(prop); } short Helix::mustExecute() const { if (Pitch.isTouched()) return 1; if (Height.isTouched()) return 1; if (Radius.isTouched()) return 1; if (Angle.isTouched()) return 1; if (LocalCoord.isTouched()) return 1; if (Style.isTouched()) return 1; return Primitive::mustExecute(); } App::DocumentObjectExecReturn *Helix::execute(void) { try { Standard_Real myPitch = Pitch.getValue(); Standard_Real myHeight = Height.getValue(); Standard_Real myRadius = Radius.getValue(); Standard_Real myAngle = Angle.getValue(); Standard_Boolean myLocalCS = LocalCoord.getValue() ? Standard_True : Standard_False; //Standard_Boolean myStyle = Style.getValue() ? Standard_True : Standard_False; TopoShape helix; // work around for OCC bug #23314 (FC #0954) // the exact conditions for failure are unknown. building the helix 1 turn at a time // seems to always work. this->Shape.setValue(helix.makeLongHelix(myPitch, myHeight, myRadius, myAngle, myLocalCS)); // if (myHeight / myPitch > 50.0) // this->Shape.setValue(helix.makeLongHelix(myPitch, myHeight, myRadius, myAngle, myLocalCS)); // else // this->Shape.setValue(helix.makeHelix(myPitch, myHeight, myRadius, myAngle, myLocalCS, myStyle)); } catch (Standard_Failure) { Handle_Standard_Failure e = Standard_Failure::Caught(); return new App::DocumentObjectExecReturn(e->GetMessageString()); } return App::DocumentObject::StdReturn; } PROPERTY_SOURCE(Part::Spiral, Part::Primitive) Spiral::Spiral(void) { ADD_PROPERTY_TYPE(Growth, (1.0),"Spiral",App::Prop_None,"The growth of the spiral per rotation"); Growth.setConstraints(&quantityRange); ADD_PROPERTY_TYPE(Radius,(1.0),"Spiral",App::Prop_None,"The radius of the spiral"); Radius.setConstraints(&quantityRange); ADD_PROPERTY_TYPE(Rotations,(2.0),"Spiral",App::Prop_None,"The number of rotations"); Rotations.setConstraints(&quantityRange); } void Spiral::onChanged(const App::Property* prop) { if (!isRestoring()) { if (prop == &Growth || prop == &Rotations || prop == &Radius) { try { App::DocumentObjectExecReturn *ret = recompute(); delete ret; } catch (...) { } } } Part::Feature::onChanged(prop); } short Spiral::mustExecute() const { if (Growth.isTouched()) return 1; if (Rotations.isTouched()) return 1; if (Radius.isTouched()) return 1; return Primitive::mustExecute(); } App::DocumentObjectExecReturn *Spiral::execute(void) { try { Standard_Real myNumRot = Rotations.getValue(); Standard_Real myRadius = Radius.getValue(); Standard_Real myGrowth = Growth.getValue(); Standard_Real myPitch = 1.0; Standard_Real myHeight = myNumRot * myPitch; Standard_Real myAngle = atan(myGrowth / myPitch); TopoShape helix; if (myGrowth < Precision::Confusion()) Standard_Failure::Raise("Growth too small"); if (myNumRot < Precision::Confusion()) Standard_Failure::Raise("Number of rotations too small"); gp_Ax2 cylAx2(gp_Pnt(0.0,0.0,0.0) , gp::DZ()); Handle_Geom_Surface surf = new Geom_ConicalSurface(gp_Ax3(cylAx2), myAngle, myRadius); gp_Pnt2d aPnt(0, 0); gp_Dir2d aDir(2. * M_PI, myPitch); gp_Ax2d aAx2d(aPnt, aDir); Handle(Geom2d_Line) line = new Geom2d_Line(aAx2d); gp_Pnt2d beg = line->Value(0); gp_Pnt2d end = line->Value(sqrt(4.0*M_PI*M_PI+myPitch*myPitch)*(myHeight/myPitch)); // calculate end point for conical helix Standard_Real v = myHeight / cos(myAngle); Standard_Real u = (myHeight/myPitch) * 2.0 * M_PI; gp_Pnt2d cend(u, v); end = cend; Handle(Geom2d_TrimmedCurve) segm = GCE2d_MakeSegment(beg , end); TopoDS_Edge edgeOnSurf = BRepBuilderAPI_MakeEdge(segm , surf); TopoDS_Wire wire = BRepBuilderAPI_MakeWire(edgeOnSurf); BRepLib::BuildCurves3d(wire); Handle_Geom_Plane aPlane = new Geom_Plane(gp_Pnt(0.0,0.0,0.0), gp::DZ()); Standard_Real range = (myNumRot+1) * myGrowth + 1 + myRadius; BRepBuilderAPI_MakeFace mkFace(aPlane, -range, range, -range, range #if OCC_VERSION_HEX >= 0x060502 , Precision::Confusion() #endif ); BRepProj_Projection proj(wire, mkFace.Face(), gp::DZ()); this->Shape.setValue(proj.Shape()); } catch (Standard_Failure) { Handle_Standard_Failure e = Standard_Failure::Caught(); return new App::DocumentObjectExecReturn(e->GetMessageString()); } return App::DocumentObject::StdReturn; } PROPERTY_SOURCE(Part::Wedge, Part::Primitive) 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"); } short 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 Primitive::mustExecute(); } App::DocumentObjectExecReturn *Wedge::execute(void) { 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("delta x of wedge too small"); if (dy < Precision::Confusion()) return new App::DocumentObjectExecReturn("delta y of wedge too small"); if (dz < Precision::Confusion()) return new App::DocumentObjectExecReturn("delta z of wedge too small"); if (dz2 < 0) return new App::DocumentObjectExecReturn("delta z2 of wedge is negative"); if (dx2 < 0) return new App::DocumentObjectExecReturn("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()); this->Shape.setValue(mkSolid.Solid()); } catch (Standard_Failure) { Handle_Standard_Failure e = Standard_Failure::Caught(); return new App::DocumentObjectExecReturn(e->GetMessageString()); } return App::DocumentObject::StdReturn; } void Wedge::onChanged(const App::Property* prop) { if (prop == &Xmin || prop == &Ymin || prop == &Zmin || prop == &X2min || prop == &Z2min || prop == &Xmax || prop == &Ymax || prop == &Zmax || prop == &X2max || prop == &Z2max) { if (!isRestoring()) { App::DocumentObjectExecReturn *ret = recompute(); delete ret; } } Part::Primitive::onChanged(prop); } App::PropertyQuantityConstraint::Constraints Ellipse::angleRange = {0.0,360.0,1.0}; PROPERTY_SOURCE(Part::Ellipse, Part::Primitive) Ellipse::Ellipse() { ADD_PROPERTY(MajorRadius,(4.0f)); ADD_PROPERTY(MinorRadius,(4.0f)); ADD_PROPERTY(Angle0,(0.0f)); Angle0.setConstraints(&angleRange); ADD_PROPERTY(Angle1,(360.0f)); Angle1.setConstraints(&angleRange); } Ellipse::~Ellipse() { } short Ellipse::mustExecute() const { if (Angle0.isTouched() || Angle1.isTouched() || MajorRadius.isTouched() || MinorRadius.isTouched()) return 1; return Part::Feature::mustExecute(); } App::DocumentObjectExecReturn *Ellipse::execute(void) { gp_Elips ellipse; ellipse.SetMajorRadius(this->MajorRadius.getValue()); ellipse.SetMinorRadius(this->MinorRadius.getValue()); BRepBuilderAPI_MakeEdge clMakeEdge(ellipse, Base::toRadians(this->Angle0.getValue()), Base::toRadians(this->Angle1.getValue())); const TopoDS_Edge& edge = clMakeEdge.Edge(); this->Shape.setValue(edge); return App::DocumentObject::StdReturn; } void Ellipse::onChanged(const App::Property* prop) { if (!isRestoring()) { if (prop == &MajorRadius || prop == &MinorRadius || prop == &Angle0 || prop == &Angle1){ try { App::DocumentObjectExecReturn *ret = recompute(); delete ret; } catch (...) { } } } Part::Feature::onChanged(prop); }