diff --git a/src/Mod/Part/App/DatumFeature.cpp b/src/Mod/Part/App/DatumFeature.cpp index f4b66afaa..1e730b613 100644 --- a/src/Mod/Part/App/DatumFeature.cpp +++ b/src/Mod/Part/App/DatumFeature.cpp @@ -67,16 +67,12 @@ #endif using namespace Part; +using namespace Attacher; -PROPERTY_SOURCE_ABSTRACT(Part::Datum, Part::Feature) +PROPERTY_SOURCE_ABSTRACT(Part::Datum, Part::AttachableObject) Datum::Datum(void) { - ADD_PROPERTY_TYPE(References,(0,0),"References",(App::PropertyType)(App::Prop_None),"References defining the datum feature"); - ADD_PROPERTY(Offset,(0.0)); - ADD_PROPERTY(Offset2,(0.0)); - ADD_PROPERTY(Offset3,(0.0)); - ADD_PROPERTY(Angle,(0.0)); touch(); } @@ -86,20 +82,19 @@ Datum::~Datum() void Datum::onChanged (const App::Property* prop) { - Part::Feature::onChanged(prop); + AttachableObject::onChanged(prop); } App::DocumentObjectExecReturn *Datum::execute(void) { - References.touch(); - return StdReturn; + return AttachableObject::execute(); } void Datum::onDocumentRestored() { // This seems to be the only way to make the ViewProvider display the datum feature - References.touch(); - Part::Feature::onDocumentRestored(); + Support.touch(); + AttachableObject::onDocumentRestored(); } TopoDS_Shape Datum::getShape() const diff --git a/src/Mod/Part/App/DatumFeature.h b/src/Mod/Part/App/DatumFeature.h index 76ec9289a..0e744d58d 100644 --- a/src/Mod/Part/App/DatumFeature.h +++ b/src/Mod/Part/App/DatumFeature.h @@ -28,6 +28,7 @@ #include #include "PartFeature.h" +#include "AttachableObject.h" namespace Part { @@ -35,7 +36,7 @@ namespace Part // This generic class is defined here so that the Sketcher module can access datum features // without creating a dependency on PartDesign -class PartExport Datum : public Part::Feature +class PartExport Datum : public Part::AttachableObject { PROPERTY_HEADER(Part::Datum); @@ -44,35 +45,18 @@ public: virtual ~Datum(); //short mustExecute(); - /// The references defining the datum object, e.g. three planes for a point, two planes for a line - App::PropertyLinkSubList References; - /// Offsets and angle for defining planes - App::PropertyFloat Offset; - App::PropertyFloat Offset2; - App::PropertyFloat Offset3; - App::PropertyFloat Angle; - /// recalculate the feature App::DocumentObjectExecReturn *execute(void); /// returns the type name of the view provider virtual const char* getViewProviderName(void) const = 0; - virtual const std::set getHint() const = 0; - - /// Return the number of offset values that make sense for the current reference combination - virtual const int offsetsAllowed() const = 0; - /// Return a shape including Placement representing the datum feature TopoDS_Shape getShape() const; protected: void onChanged (const App::Property* prop); void onDocumentRestored(); - -protected: - std::multiset refTypes; - }; } //namespace Part diff --git a/src/Mod/PartDesign/App/AppPartDesign.cpp b/src/Mod/PartDesign/App/AppPartDesign.cpp index 12ca55f38..ec897df14 100644 --- a/src/Mod/PartDesign/App/AppPartDesign.cpp +++ b/src/Mod/PartDesign/App/AppPartDesign.cpp @@ -140,8 +140,4 @@ PyMODINIT_FUNC init_PartDesign() PartDesign::AdditiveWedge ::init(); PartDesign::SubtractiveWedge ::init(); - PartDesign::Point ::initHints(); - PartDesign::Line ::initHints(); - PartDesign::Plane ::initHints(); - PartDesign::CoordinateSystem ::initHints(); } diff --git a/src/Mod/PartDesign/App/DatumCS.cpp b/src/Mod/PartDesign/App/DatumCS.cpp index 591e32fc6..76db5e534 100644 --- a/src/Mod/PartDesign/App/DatumCS.cpp +++ b/src/Mod/PartDesign/App/DatumCS.cpp @@ -53,233 +53,21 @@ using namespace PartDesign; -// Note: We don't distinguish between e.g. datum lines and edges here -#define PLANE QObject::tr("DPLANE") -#define CYLINDER QObject::tr("DCYLINDER") -#define LINE QObject::tr("DLINE") -#define POINT QObject::tr("DPOINT") -#define ANGLE QObject::tr("Angle") -#define CS QObject::tr("DCOORDINATESYSTEM") -#define DONE QObject::tr("Done") - -std::map, std::set > CoordinateSystem::hints = std::map, std::set >(); - -void CoordinateSystem::initHints() -{ - std::set Done; - Done.insert(QObject::tr("Done")); - - std::multiset key; - std::set value; - - //Point first ---------------------- - key.insert(POINT); - value.insert(PLANE); - value.insert(LINE); - value.insert(POINT); - value.insert(DONE); - hints[key] = value; - - key.clear(); value.clear(); - key.insert(POINT); - key.insert(PLANE); - value.insert(LINE); - value.insert(POINT); - value.insert(DONE); - hints[key] = value; - - key.clear(); value.clear(); - key.insert(POINT); - key.insert(PLANE); - key.insert(LINE); - hints[key] = Done; - - key.clear(); value.clear(); - key.insert(POINT); - key.insert(PLANE); - key.insert(POINT); - hints[key] = Done; - - key.clear(); value.clear(); - key.insert(POINT); - key.insert(LINE); - value.insert(PLANE); - value.insert(LINE); - value.insert(POINT); - value.insert(DONE); - hints[key] = value; - - key.clear(); value.clear(); - key.insert(POINT); - key.insert(LINE); - key.insert(PLANE); - hints[key] = Done; - - key.clear(); value.clear(); - key.insert(POINT); - key.insert(LINE); - key.insert(LINE); - hints[key] = Done; - - key.clear(); value.clear(); - key.insert(POINT); - key.insert(LINE); - key.insert(POINT); - hints[key] = Done; - - key.clear(); value.clear(); - key.insert(POINT); - key.insert(POINT); - value.insert(PLANE); - value.insert(LINE); - value.insert(POINT); - value.insert(DONE); - hints[key] = value; - - key.clear(); value.clear(); - key.insert(POINT); - key.insert(POINT); - key.insert(PLANE); - hints[key] = Done; - - key.clear(); value.clear(); - key.insert(POINT); - key.insert(POINT); - key.insert(LINE); - hints[key] = Done; - - key.clear(); value.clear(); - key.insert(POINT); - key.insert(POINT); - key.insert(POINT); - hints[key] = Done; - - //Plane First ------------------------- - key.clear(); value.clear(); - key.insert(PLANE); - value.insert(LINE); - value.insert(POINT); - value.insert(DONE); - hints[key] = value; - - key.clear(); value.clear(); - key.insert(PLANE); - key.insert(LINE); - value.insert(POINT); - value.insert(DONE); - hints[key] = value; - - key.clear(); value.clear(); - key.insert(PLANE); - key.insert(LINE); - key.insert(POINT); - hints[key] = Done; - - key.clear(); value.clear(); - key.insert(PLANE); - key.insert(POINT); - value.insert(LINE); - value.insert(POINT); - value.insert(DONE); - hints[key] = value; - - key.clear(); value.clear(); - key.insert(PLANE); - key.insert(POINT); - key.insert(LINE); - hints[key] = Done; - - key.clear(); value.clear(); - key.insert(PLANE); - key.insert(POINT); - key.insert(POINT); - hints[key] = Done; - - - //Line First ------------------------- - key.clear(); value.clear(); - key.insert(LINE); - value.insert(PLANE); - value.insert(LINE); - value.insert(POINT); - value.insert(DONE); - hints[key] = value; - - key.clear(); value.clear(); - key.insert(LINE); - key.insert(PLANE); - value.insert(POINT); - value.insert(DONE); - hints[key] = value; - - key.clear(); value.clear(); - key.insert(LINE); - key.insert(PLANE); - key.insert(POINT); - hints[key] = Done; - - key.clear(); value.clear(); - key.insert(LINE); - key.insert(LINE); - value.insert(POINT); - value.insert(DONE); - hints[key] = value; - - key.clear(); value.clear(); - key.insert(LINE); - key.insert(LINE); - key.insert(POINT); - hints[key] = Done; - - key.clear(); value.clear(); - key.insert(LINE); - key.insert(POINT); - value.insert(PLANE); - value.insert(LINE); - value.insert(POINT); - value.insert(DONE); - hints[key] = value; - - key.clear(); value.clear(); - key.insert(LINE); - key.insert(POINT); - key.insert(PLANE); - hints[key] = Done; - - key.clear(); value.clear(); - key.insert(LINE); - key.insert(POINT); - key.insert(POINT); - hints[key] = Done; - - key.clear(); value.clear(); - key.insert(LINE); - key.insert(PLANE); - key.insert(POINT); - hints[key] = Done; -} // ============================================================================ -#define GP_POINT(p) \ - gp_Pnt(p[0], p[1], p[2]) - -#define GP_DIR(p) \ - gp_Dir(p[0], p[1], p[2]) - PROPERTY_SOURCE(PartDesign::CoordinateSystem, Part::Datum) CoordinateSystem::CoordinateSystem() { + this->setAttacher(new AttachEngine3D); // Create a shape, which will be used by the Sketcher. Them main function is to avoid a dependency of // Sketcher on the PartDesign module BRepBuilderAPI_MakeFace builder(gp_Pln(gp_Pnt(0,0,0), gp_Dir(0,0,1))); if (!builder.IsDone()) return; Shape.setValue(builder.Shape()); - - References.touch(); } CoordinateSystem::~CoordinateSystem() @@ -288,304 +76,9 @@ CoordinateSystem::~CoordinateSystem() void CoordinateSystem::onChanged(const App::Property *prop) { - if ((prop == &References) || (prop == &Offset) || (prop == &Offset2) || (prop == &Offset3)) { - - Base::Placement plm; - const std::vector& refs = References.getValues(); - const std::vector& subrefs = References.getSubValues(); - - if (refs.size() != subrefs.size()) - throw Base::Exception("Size of references and subreferences do not match"); - - refTypes.clear(); - for (int r = 0; r < refs.size(); r++) - refTypes.insert(getRefType(refs[r], subrefs[r])); - - std::set hint = getHint(); - if (refs.size() != 0 && !(hint.find(QObject::tr("Done")) != hint.end())) - throw Base::Exception("Can not build coordinate system from given references"); // incomplete references - - //build the placement from the references - bool plane = false, line1 = false, line2 = false, point1 = false, point2=false, point3=false; - gp_Pln pln; - gp_Lin lin1, lin2; - gp_Pnt p1, p2, p3; - - int count = 0; - for(int i = 0; i < refs.size(); i++) { - - if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Point::getClassTypeId())) { - PartDesign::Point* p = static_cast(refs[i]); - if(!point1) { - p1 = GP_POINT(p->getPoint()); - point1=true; - } else if(!point2) { - p2 = GP_POINT(p->getPoint()); - point2=true; - } else if(!point3) { - p3 = GP_POINT(p->getPoint()); - point3=true; - } - else - throw Base::Exception("Too many points in coordinate system references"); //too much points selected - } - else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { - PartDesign::Plane* p = static_cast(refs[i]); - if(!plane) { - pln = gp_Pln(GP_POINT(p->getBasePoint()), GP_DIR(p->getNormal())); - plane=true; - } - else - throw Base::Exception("Too many planes in coordinate syste references"); - } else if (refs[i]->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { - App::Plane* p = static_cast(refs[i]); - if(!plane) { - gp_Pnt base(0,0,0); - gp_Dir dir(0,0,1); - if (strcmp(p->PlaneType.getValue(), App::Part::BaseplaneTypes[0]) == 0) - dir = gp_Dir(0,0,1); - else if (strcmp(p->PlaneType.getValue(), App::Part::BaseplaneTypes[1]) == 0) - dir = gp_Dir(0,1,0); - else if (strcmp(p->PlaneType.getValue(), App::Part::BaseplaneTypes[2]) == 0) - dir = gp_Dir(1,0,0); - - pln = gp_Pln(base, dir); - plane=true; - } - else - throw Base::Exception("Too many planes in coordinate syste references"); //too much planes selected - } - else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) { - PartDesign::Line* p = static_cast(refs[i]); - if(!line1) { - lin1 = gp_Lin(GP_POINT(p->getBasePoint()), GP_DIR(p->getDirection())); - line1 = true; - } - else if(!line2) { - lin2 = gp_Lin(GP_POINT(p->getBasePoint()), GP_DIR(p->getDirection())); - line2 = true; - } - else - throw Base::Exception("Too many lines in coordinate syste references");; //too much lines selected - - } else if (refs[i]->getTypeId().isDerivedFrom(App::Line::getClassTypeId())) { - App::Line* p = static_cast(refs[i]); - gp_Pnt base(0,0,0); - gp_Dir dir(0,0,1); - if (strcmp(p->LineType.getValue(), App::Part::BaselineTypes[0]) == 0) - dir = gp_Dir(1,0,0); - else if (strcmp(p->LineType.getValue(), App::Part::BaselineTypes[1]) == 0) - dir = gp_Dir(0,1,0); - else if (strcmp(p->LineType.getValue(), App::Part::BaselineTypes[2]) == 0) - dir = gp_Dir(0,0,1); - - if(!line1) { - lin1 = gp_Lin(base, dir); - line1=true; - } - else if(!line2) { - lin2 = gp_Lin(base, dir); - line2=true; - } - else - throw Base::Exception("Too many lines in coordinate syste references"); - } - else if (refs[i]->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { - Part::Feature* feature = static_cast(refs[i]); - const TopoDS_Shape& sh = feature->Shape.getValue(); - if (sh.IsNull()) - throw Base::Exception("Invalid shape in reference"); - // Get subshape - TopoDS_Shape subshape = feature->Shape.getShape().getSubShape(subrefs[i].c_str()); - if (subshape.IsNull()) - throw Base::Exception("Reference has Null shape"); - - if (subshape.ShapeType() == TopAbs_VERTEX) { - TopoDS_Vertex v = TopoDS::Vertex(subshape); - - if(!point1) { - p1 = BRep_Tool::Pnt(v); - point1=true; - } else if(!point2) { - p2 = BRep_Tool::Pnt(v); - point2=true; - } else if(!point3) { - p3 = BRep_Tool::Pnt(v); - point3=true; - } - else - throw Base::Exception("Too many points in coordinate system references"); - } - else if (subshape.ShapeType() == TopAbs_EDGE) { - TopoDS_Edge e = TopoDS::Edge(subshape); - BRepAdaptor_Curve adapt(e); - if (adapt.GetType() != GeomAbs_Line) - throw Base::Exception("Only straight edges are supported"); - - if(!line1) { - lin1 = adapt.Line(); - line1=true; - } - else if(!line2) { - lin2 = adapt.Line(); - line2=true; - } - else - throw Base::Exception("Too many lines in coordinate system references"); - - } else if (subshape.ShapeType() == TopAbs_FACE) { - TopoDS_Face f = TopoDS::Face(subshape); - BRepAdaptor_Surface adapt(f); - if (adapt.GetType() == GeomAbs_Plane) { - // Ensure that the front and back of the plane corresponds with the face's idea of front and back - bool reverse = (f.Orientation() == TopAbs_REVERSED); - gp_Pln pl = adapt.Plane(); - gp_Dir d = pl.Axis().Direction(); - const gp_Pnt& p = pl.Location(); - if (reverse) d.Reverse(); - - if(!plane) { - pln = gp_Pln(p, d); - plane = true; - } - else - throw Base::Exception("Too many planes in coordinate system references"); - - } else { - throw Base::Exception("Only planar faces allowed"); - } - } - } - - count++; - }; - - gp_Ax3 ax; - if(point1) { - - if(plane) { - if(!pln.Contains(p1, Precision::Confusion())) - throw Base::Exception("Point must lie on plane"); - - if(point2) { - if(!pln.Contains(p2, Precision::Confusion())) - throw Base::Exception("Point must lie on plane"); - - if(p1.Distance(p2) < Precision::Confusion()) - throw Base::Exception("Point must not be coincident"); - - ax = gp_Ax3(p1, pln.Axis().Direction(), gp_Dir((p2.XYZ()-p1.XYZ()))); - } - else if(line1) { - if(!pln.Contains(lin1, Precision::Confusion(), Precision::Confusion())) - throw Base::Exception("Line must lie on plane"); - - if(line2) - throw Base::Exception("Two lines and a plain are not supportet"); - - ax = gp_Ax3(p1, pln.Axis().Direction(), lin1.Direction()); - } - else { - ax = gp_Ax3(p1, pln.Axis().Direction(), pln.XAxis().Direction()); - } - } - else if(line1) { - - if(point2) { - if(!gp_Lin(p1, lin1.Direction()).Contains(p2, Precision::Confusion())) - throw Base::Exception("Second Point must not lie on z-axis"); - - if(p1.Distance(p2) < Precision::Confusion()) - throw Base::Exception("Points must not be coincident"); - - ax = gp_Ax3(p1, lin1.Direction(), gp_Dir((p2.XYZ()-p1.XYZ()))); - } - else if(line2) { - if(lin2.Angle(lin1) CoordinateSystem::getHint() const -{ - if (hints.find(refTypes) != hints.end()) - return hints[refTypes]; - else - return std::set(); -} - -const int CoordinateSystem::offsetsAllowed() const -{ - return 3; -} - Base::Vector3d CoordinateSystem::getXAxis() { Base::Rotation rot = Placement.getValue().getRotation(); diff --git a/src/Mod/PartDesign/App/DatumCS.h b/src/Mod/PartDesign/App/DatumCS.h index 1150efaac..ab7385fe9 100644 --- a/src/Mod/PartDesign/App/DatumCS.h +++ b/src/Mod/PartDesign/App/DatumCS.h @@ -43,10 +43,6 @@ public: return "PartDesignGui::ViewProviderDatumCoordinateSystem"; } - static void initHints(); - const std::set getHint() const; - const int offsetsAllowed() const; - Base::Vector3d getXAxis(); Base::Vector3d getYAxis(); Base::Vector3d getZAxis(); @@ -54,9 +50,6 @@ public: protected: virtual void onChanged(const App::Property* prop); -private: - // Hints on what further references are required/possible on this feature for a given set of references - static std::map, std::set > hints; }; } //namespace PartDesign diff --git a/src/Mod/PartDesign/App/DatumLine.cpp b/src/Mod/PartDesign/App/DatumLine.cpp index eddcee4c7..1c5b420b2 100644 --- a/src/Mod/PartDesign/App/DatumLine.cpp +++ b/src/Mod/PartDesign/App/DatumLine.cpp @@ -70,74 +70,19 @@ #include #include #include -#include "Mod/Part/App/PrimitiveFeature.h" #ifndef M_PI #define M_PI 3.14159265358979323846 #endif using namespace PartDesign; - -// Note: We don't distinguish between e.g. datum lines and edges here -#define PLANE QObject::tr("DPLANE") -#define LINE QObject::tr("DLINE") -#define CIRCLE QObject::tr("DCIRCLE") -#define POINT QObject::tr("DPOINT") -#define ANGLE QObject::tr("Angle") - -std::map, std::set > Line::hints = std::map, std::set >(); - -void Line::initHints() -{ - std::set DONE; - DONE.insert(QObject::tr("Done")); - - std::multiset key; - std::set value; - key.insert(LINE); - hints[key] = DONE; // LINE -> DONE. Line from another line or edge - - key.clear(); value.clear(); - key.insert(CIRCLE); - hints[key] = DONE; // CIRCLE -> DONE. Line from center of circle or arc or axis of cylinder or cylinder segment - - key.clear(); value.clear(); - key.insert(POINT); - value.insert(POINT); - hints[key] = value; // POINT -> POINT - - key.clear(); value.clear(); - key.insert(POINT); key.insert(POINT); - hints[key] = DONE; // {POINT, POINT} -> DONE. Line from two points or vertices - - key.clear(); value.clear(); - key.insert(PLANE); - value.insert(PLANE); - value.insert(LINE); - hints[key] = value; // PLANE -> LINE or PLANE - - key.clear(); value.clear(); - key.insert(PLANE); key.insert(PLANE); - hints[key] = DONE; // {PLANE, PLANE} -> DONE. Line from two planes or faces - - key.clear(); value.clear(); - key.insert(PLANE); key.insert(LINE); - value.insert(LINE); - hints[key] = value; // {PLANE, LINE} -> LINE - - key.clear(); value.clear(); - key.insert(PLANE); key.insert(LINE); key.insert(LINE); - hints[key] = DONE; // {PLANE, LINE, LINE} -> DONE. Line from plane with distance (default zero) to two lines - - key.clear(); value.clear(); - value.insert(POINT); value.insert(LINE); value.insert(PLANE); - hints[key] = value; -} +using namespace Attacher; PROPERTY_SOURCE(PartDesign::Line, Part::Datum) Line::Line() { + this->setAttacher(new AttachEngineLine); // Create a shape, which will be used by the Sketcher. Them main function is to avoid a dependency of // Sketcher on the PartDesign module BRepBuilderAPI_MakeEdge builder(gp_Lin(gp_Pnt(0,0,0), gp_Dir(0,0,1))); @@ -145,7 +90,7 @@ Line::Line() return; Shape.setValue(builder.Shape()); - References.touch(); + Support.touch(); } Line::~Line() @@ -154,274 +99,9 @@ Line::~Line() void Line::onChanged(const App::Property *prop) { - if ((prop == &References) || (prop == &Offset) || (prop == &Offset2)) { - refTypes.clear(); - std::vector refs = References.getValues(); - std::vector refnames = References.getSubValues(); - if (refs.size() != refnames.size()) - throw Base::Exception("Reference Missmatch"); - - for (int r = 0; r < refs.size(); r++) - refTypes.insert(getRefType(refs[r], refnames[r])); - - std::set hint = getHint(); - if (!((hint.size() == 1) && (hint.find(QObject::tr("Done")) != hint.end()))) - return; // incomplete references - - // Extract the geometry of the references - Base::Vector3d* base = NULL; - Base::Vector3d* direction = NULL; - Base::Vector3d* p1 = NULL; - Base::Vector3d* p2 = NULL; - gp_Lin* line = NULL; - gp_Circ* circle = NULL; - Handle_Geom_Surface s1 = NULL; - Handle_Geom_Surface s2 = NULL; - Handle_Geom_Surface s3 = NULL; - - for (int i = 0; i < refs.size(); i++) { - if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Point::getClassTypeId())) { - PartDesign::Point* p = static_cast(refs[i]); - if (p1 == NULL) - p1 = new Base::Vector3d (p->getPoint()); - else - p2 = new Base::Vector3d (p->getPoint()); - } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) { - PartDesign::Line* l = static_cast(refs[i]); - if (s1.IsNull()) { - base = new Base::Vector3d (l->getBasePoint()); - direction = new Base::Vector3d (l->getDirection()); - } else { - // Create plane through line normal to s1 - Handle_Geom_Plane pl = Handle_Geom_Plane::DownCast(s1); - if (pl.IsNull()) - return; // Non-planar first surface - gp_Dir ldir = gp_Dir(l->getDirection().x, l->getDirection().y, l->getDirection().z); - gp_Dir normal = ldir.Crossed(pl->Axis().Direction()); - double offset1 = Offset.getValue(); - double offset2 = Offset2.getValue(); - gp_Pnt base = gp_Pnt(l->getBasePoint().x, l->getBasePoint().y, l->getBasePoint().z); - if (s2.IsNull()) { - base.Translate(offset1 * normal); - s2 = new Geom_Plane(base, normal); - } else { - base.Translate(offset2 * normal); - s3 = new Geom_Plane(base, normal); - } - } - } else if (refs[i]->getTypeId().isDerivedFrom(App::Line::getClassTypeId())) { - App::Line* l = static_cast(refs[i]); - gp_Dir ldir; - if (strcmp(l->LineType.getValue(), App::Part::BaselineTypes[0]) == 0) - ldir = gp_Dir(1,0,0); - else if (strcmp(l->LineType.getValue(), App::Part::BaselineTypes[1]) == 0) - ldir = gp_Dir(0,1,0); - else if (strcmp(l->LineType.getValue(), App::Part::BaselineTypes[2]) == 0) - ldir = gp_Dir(0,0,1); - - if (s1.IsNull()) { - base = new Base::Vector3d (0,0,0); - direction = new Base::Vector3d (ldir.X(), ldir.Y(), ldir.Z()); - } else { - // Create plane through line normal to s1 - Handle_Geom_Plane pl = Handle_Geom_Plane::DownCast(s1); - if (pl.IsNull()) - throw Base::Exception("Non-planar first surface"); // Non-planar first surface - gp_Dir normal = ldir.Crossed(pl->Axis().Direction()); - double offset1 = Offset.getValue(); - double offset2 = Offset2.getValue(); - gp_Pnt base = gp_Pnt(0,0,0); - if (s2.IsNull()) { - base.Translate(offset1 * normal); - s2 = new Geom_Plane(base, normal); - } else { - base.Translate(offset2 * normal); - s3 = new Geom_Plane(base, normal); - } - } - - }else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { - PartDesign::Plane* p = static_cast(refs[i]); - Base::Vector3d base = p->getBasePoint(); - Base::Vector3d normal = p->getNormal(); - double offset1 = Offset.getValue(); - double offset2 = Offset2.getValue(); - - if (s1.IsNull()) { - base += normal * offset1; - s1 = new Geom_Plane(gp_Pnt(base.x, base.y, base.z), gp_Dir(normal.x, normal.y, normal.z)); - } else { - base += normal * offset2; - s2 = new Geom_Plane(gp_Pnt(base.x, base.y, base.z), gp_Dir(normal.x, normal.y, normal.z)); - } - } else if (refs[i]->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { - App::Plane* p = static_cast(refs[i]); - // Note: We only handle the three base planes here - gp_Pnt base(0,0,0); - gp_Dir normal; - if (strcmp(p->PlaneType.getValue(), App::Part::BaseplaneTypes[0]) == 0) - normal = gp_Dir(0,0,1); - else if (strcmp(p->PlaneType.getValue(), App::Part::BaseplaneTypes[2]) == 0) - normal = gp_Dir(1,0,0); - else if (strcmp(p->PlaneType.getValue(), App::Part::BaseplaneTypes[1]) == 0) - normal = gp_Dir(0,1,0); - - double offset1 = Offset.getValue(); - double offset2 = Offset2.getValue(); - - if (s1.IsNull()) { - base = gp_Pnt(normal.X() * offset1, normal.Y() * offset1, normal.Z() * offset1); - s1 = new Geom_Plane(base, normal); - } else { - base = gp_Pnt(normal.X() * offset2, normal.Y() * offset2, normal.Z() * offset2); - s2 = new Geom_Plane(base, normal); - } - } else if (refs[i]->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { - Part::Feature* feature = static_cast(refs[i]); - const TopoDS_Shape& sh = feature->Shape.getValue(); - if (sh.IsNull()) - return; // "PartDesign::Line: Reference has NULL shape" - // Get subshape - TopoDS_Shape subshape = feature->Shape.getShape().getSubShape(refnames[i].c_str()); - if (subshape.IsNull()) - return; // "PartDesign::Line: Reference has NULL subshape"; - - if (subshape.ShapeType() == TopAbs_VERTEX) { - TopoDS_Vertex v = TopoDS::Vertex(subshape); - gp_Pnt p = BRep_Tool::Pnt(v); - if (p1 == NULL) - p1 = new Base::Vector3d(p.X(), p.Y(), p.Z()); - else - p2 = new Base::Vector3d(p.X(), p.Y(), p.Z()); - } else if (subshape.ShapeType() == TopAbs_EDGE) { - TopoDS_Edge e = TopoDS::Edge(subshape); - BRepAdaptor_Curve adapt(e); - if (adapt.GetType() == GeomAbs_Circle) { - circle = new gp_Circ(adapt.Circle()); - } else if (adapt.GetType() == GeomAbs_Line) { - if (s1.IsNull()) { - line = new gp_Lin(adapt.Line()); - } else { - // Create plane through line normal to s1 - Handle_Geom_Plane pl = Handle_Geom_Plane::DownCast(s1); - if (pl.IsNull()) - return; // Non-planar first surface - gp_Dir normal = adapt.Line().Direction().Crossed(pl->Axis().Direction()); - double offset1 = Offset.getValue(); - double offset2 = Offset2.getValue(); - gp_Pnt base = adapt.Line().Location(); - if (s2.IsNull()) { - base.Translate(offset1 * normal); - s2 = new Geom_Plane(base, normal); - } else { - base.Translate(offset2 * normal); - s3 = new Geom_Plane(base, normal); - } - } - } else { - return; // Non-linear edge - } - } else if (subshape.ShapeType() == TopAbs_FACE) { - TopoDS_Face f = TopoDS::Face(subshape); - double offset1 = Offset.getValue(); - double offset2 = Offset2.getValue(); - BRepAdaptor_Surface adapt(f); - - if (s1.IsNull()) { - if (adapt.GetType() == GeomAbs_Cylinder) { - circle = new gp_Circ(gp_Ax2(adapt.Cylinder().Location(), adapt.Cylinder().Axis().Direction()), - adapt.Cylinder().Radius()); - } else if (adapt.GetType() == GeomAbs_Plane) { - gp_Trsf mov; - mov.SetTranslation(offset1 * gp_Vec(adapt.Plane().Axis().Direction())); - TopLoc_Location loc(mov); - f.Move(loc); - } - s1 = BRep_Tool::Surface(f); - } else { - if (adapt.GetType() == GeomAbs_Plane) { - gp_Trsf mov; - mov.SetTranslation(offset2 * gp_Vec(adapt.Plane().Axis().Direction())); - TopLoc_Location loc(mov); - f.Move(loc); - } - s2 = BRep_Tool::Surface(f); - } - } - } else { - return; //"PartDesign::Point: Invalid reference type" - } - } - - if ((base != NULL) && (direction != NULL)) { - // Line from other datum line. Nothing to be done - } else if ((p1 != NULL) && (p2 != NULL)) { - // Line from two points - base = new Base::Vector3d(*p1); - direction = new Base::Vector3d(*p2 - *p1); - } else if (line != NULL) { - // Line from gp_lin - base = new Base::Vector3d(line->Location().X(), line->Location().Y(), line->Location().Z()); - direction = new Base::Vector3d(line->Direction().X(), line->Direction().Y(), line->Direction().Z()); - } else if (circle != NULL) { - // Line from center of circle or cylinder - gp_Pnt centre = circle->Axis().Location(); - base = new Base::Vector3d(centre.X(), centre.Y(), centre.Z()); - gp_Dir dir = circle->Axis().Direction(); - direction = new Base::Vector3d(dir.X(), dir.Y(), dir.Z()); - } else if (!s1.IsNull() && !s2.IsNull()) { - if (!s3.IsNull()) - s1 = s3; // Line from a plane and two lines/edges - // Line from two surfaces - GeomAPI_IntSS intersectorSS(s1, s2, Precision::Confusion()); - if (!intersectorSS.IsDone() || (intersectorSS.NbLines() == 0)) - throw Base::Exception("Intersection of surfaces failed"); - if (intersectorSS.NbLines() > 1) - Base::Console().Warning("More than one intersection curve for datum line from surfaces\n"); - Handle_Geom_Line l = Handle_Geom_Line::DownCast(intersectorSS.Line(1)); - if (l.IsNull()) - return; // non-linear intersection curve - gp_Lin lin = l->Lin(); - base = new Base::Vector3d(lin.Location().X(), lin.Location().Y(), lin.Location().Z()); - direction = new Base::Vector3d(lin.Direction().X(), lin.Direction().Y(), lin.Direction().Z()); - } else { - return; - } - - Placement.setValue(Base::Placement(*base, Base::Rotation(Base::Vector3d(0,0,1), *direction))); - - delete base; - delete direction; - if (p1 != NULL) delete p1; - if (p2 != NULL) delete p2; - if (line != NULL) delete line; - if (circle != NULL) delete circle; - } - Part::Datum::onChanged(prop); } -const std::set Line::getHint() const -{ - if (hints.find(refTypes) != hints.end()) - return hints[refTypes]; - else - return std::set(); -} - -const int Line::offsetsAllowed() const -{ - int planes = 0; - int lines = 0; - for (std::multiset::const_iterator r = refTypes.begin(); r != refTypes.end(); r++) { - if (*r == PLANE) planes++; - if (*r == LINE) lines++; - } - if (lines == 0) return planes; - if ((planes == 1) && (lines == 2)) return 2; - return 0; -} - Base::Vector3d Line::getBasePoint() const { return Placement.getValue().getPosition(); diff --git a/src/Mod/PartDesign/App/DatumLine.h b/src/Mod/PartDesign/App/DatumLine.h index b67853649..fec043fa7 100644 --- a/src/Mod/PartDesign/App/DatumLine.h +++ b/src/Mod/PartDesign/App/DatumLine.h @@ -28,6 +28,7 @@ #include #include #include +#include namespace PartDesign { @@ -44,19 +45,12 @@ public: return "PartDesignGui::ViewProviderDatumLine"; } - static void initHints(); - const std::set getHint() const; - const int offsetsAllowed() const; - Base::Vector3d getBasePoint() const; Base::Vector3d getDirection() const; protected: virtual void onChanged(const App::Property* prop); -private: - // Hints on what further references are required/possible on this feature for a given set of references - static std::map, std::set > hints; }; } //namespace PartDesign diff --git a/src/Mod/PartDesign/App/DatumPlane.cpp b/src/Mod/PartDesign/App/DatumPlane.cpp index 7b8b1fe19..28d35c641 100644 --- a/src/Mod/PartDesign/App/DatumPlane.cpp +++ b/src/Mod/PartDesign/App/DatumPlane.cpp @@ -68,88 +68,13 @@ #include #include #include -#include "Mod/Part/App/PrimitiveFeature.h" #ifndef M_PI #define M_PI 3.14159265358979323846 #endif using namespace PartDesign; - -// Note: We don't distinguish between e.g. datum lines and edges here -#define PLANE QObject::tr("DPLANE") -#define CYLINDER QObject::tr("DCYLINDER") -#define LINE QObject::tr("DLINE") -#define POINT QObject::tr("DPOINT") -#define ANGLE QObject::tr("Angle") - -std::map, std::set > Plane::hints = std::map, std::set >(); - -void Plane::initHints() -{ - std::set DONE; - DONE.insert(QObject::tr("Done")); - - std::multiset key; - std::set value; - key.insert(PLANE); - hints[key] = DONE; // PLANE -> DONE. Plane from another plane or face - - key.clear(); value.clear(); - key.insert(POINT); - value.insert(POINT); value.insert(LINE); - hints[key] = value; // POINT -> POINT or LINE - - key.clear(); value.clear(); - key.insert(POINT); key.insert(LINE); - hints[key] = DONE; // {POINT, LINE} -> DONE. Plane from point/vertex and line/edge - - key.clear(); value.clear(); - key.insert(POINT); key.insert(POINT); - value.insert(POINT); - hints[key] = value; // {POINT, POINT} -> POINT - - key.clear(); value.clear(); - key.insert(POINT); key.insert(POINT); key.insert(POINT); - hints[key] = DONE; // {POINT, POINT, POINT} -> DONE. Plane from 3 points or vertices - - key.clear(); value.clear(); - key.insert(LINE); - value.insert(POINT); value.insert(PLANE); value.insert(ANGLE); - hints[key] = value; // LINE -> POINT or PLANE or ANGLE - - key.clear(); value.clear(); - key.insert(PLANE); key.insert(LINE); - value.insert(ANGLE); - hints[key] = value; // {PLANE, LINE} -> ANGLE - - key.clear(); value.clear(); - key.insert(PLANE); key.insert(ANGLE); - value.insert(LINE); - hints[key] = value; // {PLANE, ANGLE} -> LINE - - key.clear(); value.clear(); - key.insert(ANGLE); key.insert(LINE); - value.insert(PLANE); - hints[key] = value; // {ANGLE, LINE} -> PLANE - - key.clear(); value.clear(); - key.insert(LINE); key.insert(PLANE); key.insert(ANGLE); - hints[key] = DONE; // {LINE, PLANE, ANGLE} -> DONE. Plane through line with angle to other plane - - key.clear(); value.clear(); - key.insert(CYLINDER); - value.insert(PLANE); - hints[key] = value; // CYLINDER -> PLANE - - key.clear(); value.clear(); - key.insert(CYLINDER); key.insert(PLANE); - hints[key] = DONE; // {CYLINDER, PLANE} -> DONE. Plane tangential to cylinder and normal to other plane - - key.clear(); value.clear(); - value.insert(POINT); value.insert(LINE); value.insert(PLANE); value.insert(ANGLE); - hints[key] = value; -} +using namespace Attacher; // ============================================================================ @@ -157,6 +82,7 @@ PROPERTY_SOURCE(PartDesign::Plane, Part::Datum) Plane::Plane() { + this->setAttacher(new AttachEngine3D); // Create a shape, which will be used by the Sketcher. Them main function is to avoid a dependency of // Sketcher on the PartDesign module BRepBuilderAPI_MakeFace builder(gp_Pln(gp_Pnt(0,0,0), gp_Dir(0,0,1))); @@ -164,7 +90,6 @@ Plane::Plane() return; Shape.setValue(builder.Shape()); - References.touch(); } Plane::~Plane() @@ -173,217 +98,9 @@ Plane::~Plane() void Plane::onChanged(const App::Property *prop) { - if (prop == &Angle) { - // Zero value counts as angle not defined - if (fabs(Angle.getValue()) > Precision::Confusion()) - refTypes.insert(ANGLE); - else - refTypes.erase(ANGLE); - } - - if ((prop == &References) || (prop == &Offset)) { - refTypes.clear(); - std::vector refs = References.getValues(); - std::vector refnames = References.getSubValues(); - - for (int r = 0; r < refs.size(); r++) { - const Part::Feature* ref = static_cast(refs[r]); - if ((ref != NULL) && ref->Shape.getValue().IsNull()) - continue; // This can happen while a document is being restored from a file - refTypes.insert(getRefType(refs[r], refnames[r])); - } - - if (fabs(Angle.getValue()) > Precision::Confusion()) - refTypes.insert(ANGLE); - - std::set hint = getHint(); - if (!((hint.size() == 1) && (hint.find(QObject::tr("Done")) != hint.end()))) - return; // incomplete references - - // Extract the geometry of the references - Base::Vector3d* p1 = NULL; - Base::Vector3d* p2 = NULL; - Base::Vector3d* p3 = NULL; - Base::Vector3d* normal = NULL; - gp_Lin* line = NULL; - gp_Cylinder* cyl = NULL; - - for (int i = 0; i < refs.size(); i++) { - if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Point::getClassTypeId())) { - PartDesign::Point* p = static_cast(refs[i]); - if (p1 == NULL) - p1 = new Base::Vector3d (p->getPoint()); - else if (p2 == NULL) - p2 = new Base::Vector3d (p->getPoint()); - else - p3 = new Base::Vector3d (p->getPoint()); - } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) { - PartDesign::Line* l = static_cast(refs[i]); - Base::Vector3d base = l->getBasePoint(); - Base::Vector3d dir = l->getDirection(); - line = new gp_Lin(gp_Pnt(base.x, base.y, base.z), gp_Dir(dir.x, dir.y, dir.z)); - } else if (refs[i]->getTypeId().isDerivedFrom(App::Line::getClassTypeId())) { - App::Line* l = static_cast(refs[i]); - Base::Vector3d base = Base::Vector3d(0,0,0); - gp_Dir dir; - if (strcmp(l->LineType.getValue(), App::Part::BaselineTypes[0]) == 0) - dir = gp_Dir(1,0,0); - else if (strcmp(l->LineType.getValue(), App::Part::BaselineTypes[1]) == 0) - dir = gp_Dir(0,1,0); - else if (strcmp(l->LineType.getValue(), App::Part::BaselineTypes[2]) == 0) - dir = gp_Dir(0,0,1); - line = new gp_Lin(gp_Pnt(base.x, base.y, base.z), gp_Dir(dir.X(), dir.Y(), dir.Z())); - } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { - PartDesign::Plane* p = static_cast(refs[i]); - p1 = new Base::Vector3d(p->getBasePoint()); - normal = new Base::Vector3d(p->getNormal()); - } else if (refs[i]->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { - App::Plane* p = static_cast(refs[i]); - // Note: We only handle the three base planes here - p1 = new Base::Vector3d(0,0,0); - normal = new Base::Vector3d; - if (strcmp(p->PlaneType.getValue(), App::Part::BaseplaneTypes[0]) == 0) - *normal = Base::Vector3d(0,0,1); - else if (strcmp(p->PlaneType.getValue(), App::Part::BaseplaneTypes[1]) == 0) - *normal = Base::Vector3d(0,1,0); - else if (strcmp(p->PlaneType.getValue(), App::Part::BaseplaneTypes[2]) == 0) - *normal = Base::Vector3d(1,0,0); - } else if (refs[i]->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { - Part::Feature* feature = static_cast(refs[i]); - const TopoDS_Shape& sh = feature->Shape.getValue(); - if (sh.IsNull()) - return; // "PartDesign::Plane: Reference has NULL shape" - // Get subshape - TopoDS_Shape subshape = feature->Shape.getShape().getSubShape(refnames[i].c_str()); - if (subshape.IsNull()) - return; // "PartDesign::Plane: Reference has NULL subshape"; - - if (subshape.ShapeType() == TopAbs_VERTEX) { - TopoDS_Vertex v = TopoDS::Vertex(subshape); - gp_Pnt p = BRep_Tool::Pnt(v); - if (p1 == NULL) - p1 = new Base::Vector3d(p.X(), p.Y(), p.Z()); - else if (p2 == NULL) - p2 = new Base::Vector3d(p.X(), p.Y(), p.Z()); - else - p3 = new Base::Vector3d(p.X(), p.Y(), p.Z()); - } else if (subshape.ShapeType() == TopAbs_EDGE) { - TopoDS_Edge e = TopoDS::Edge(subshape); - BRepAdaptor_Curve adapt(e); - if (adapt.GetType() != GeomAbs_Line) - return; // Non-linear edge - line = new gp_Lin(adapt.Line()); - } else if (subshape.ShapeType() == TopAbs_FACE) { - TopoDS_Face f = TopoDS::Face(subshape); - BRepAdaptor_Surface adapt(f); - if (adapt.GetType() == GeomAbs_Plane) { - // Ensure that the front and back of the plane corresponds with the face's idea of front and back - bool reverse = (f.Orientation() == TopAbs_REVERSED); - gp_Pln plane = adapt.Plane(); - if (!plane.Direct()) { - // toggle if plane has a left-handed coordinate system - plane.UReverse(); - reverse = !reverse; - } - gp_Dir d = adapt.Plane().Axis().Direction(); - if (reverse) d.Reverse(); - - // Ensure that the position of the placement corresponds to what the face would yield in - // Part2DObject::positionBySupport() - Base::Vector3d pos = feature->Placement.getValue().getPosition(); - gp_Pnt gp_pos(pos.x,pos.y,pos.z); - Handle (Geom_Plane) gPlane = new Geom_Plane(plane); - GeomAPI_ProjectPointOnSurf projector(gp_pos,gPlane); - gp_Pnt b = projector.NearestPoint(); - - p1 = new Base::Vector3d(b.X(), b.Y(), b.Z()); - normal = new Base::Vector3d(d.X(), d.Y(), d.Z()); - } else if (adapt.GetType() == GeomAbs_Cylinder) { - cyl = new gp_Cylinder(adapt.Cylinder()); - } else { - return; // invalid surface type - } - } - } else { - return; //"PartDesign::Plane: Invalid reference type" - } - } - - if ((line != NULL) && (normal != NULL) && (p1 != NULL) && (fabs(Angle.getValue()) > Precision::Confusion())) { - // plane from line, plane, and angle to plane - *normal = normal->Normalize(); - gp_Pnt p = line->Location(); - *p1 = Base::Vector3d(p.X(), p.Y(), p.Z()); - gp_Dir dir = line->Direction(); - Base::Rotation rot(Base::Vector3d(dir.X(), dir.Y(), dir.Z()), Angle.getValue() / 180.0 * M_PI); - rot.multVec(*normal, *normal); - } else if ((cyl != NULL) && (normal != NULL)) { - // Plane tangential to cylinder and parallel to other plane - gp_Dir dir(normal->x, normal->y, normal->z); - Handle_Geom_Curve normalLine = new Geom_Line(cyl->Location(), dir); - Handle_Geom_Surface cylinder = new Geom_CylindricalSurface(*cyl); - - // Intersect a line through the base point of the cylinder and normal to the plane with the cylinder itself - GeomAPI_IntCS intersector(normalLine, cylinder); - if (!intersector.IsDone() || (intersector.NbPoints() == 0)) - throw Base::Exception("Curve - Surface intersection failed"); - if (intersector.NbPoints() > 1) - Base::Console().Warning("More than one intersection point for datum plane from cylinder and plane\n"); - - gp_Pnt inter = intersector.Point(1); - p1 = new Base::Vector3d(inter.X(), inter.Y(), inter.Z()); - // TODO: Allow to control which side of the cylinder the plane is created on - there are always two possibilities - } else if ((p1 != NULL) && (normal != NULL)) { - // plane from other plane. Nothing to be done - } else if ((p1 != NULL) && (p2 != NULL) && (p3 != NULL)) { - // Plane from three points - Base::Vector3d vec1 = *p2 - *p1; - Base::Vector3d vec2 = *p3 - *p1; - normal = new Base::Vector3d(vec1 % vec2); - } else if ((line != NULL) && (p1 != NULL)) { - // Plane from point and line - p2 = new Base::Vector3d(line->Location().X(), line->Location().Y(), line->Location().Z()); - gp_Pnt p(line->Location().X() + line->Direction().X(), line->Location().Y() + line->Direction().Y(), line->Location().Z() + line->Direction().Z()); - p3 = new Base::Vector3d(p.X(), p.Y(), p.Z()); - Base::Vector3d vec1 = *p2 - *p1; - Base::Vector3d vec2 = *p3 - *p1; - normal = new Base::Vector3d(vec1 % vec2); - } else { - throw Base::Exception("Unvalid references"); - } - - *normal = normal->Normalize(); - - if (fabs(Offset.getValue()) > Precision::Confusion()) - *p1 += Offset.getValue() * *normal; - - Placement.setValue(Base::Placement(*p1,Base::Rotation(Base::Vector3d(0,0,1), *normal))); - - delete p1; - delete normal; - if (p2 != NULL) delete p2; - if (p3 != NULL) delete p3; - if (line != NULL) delete line; - if (cyl != NULL) delete cyl; - } - Part::Datum::onChanged(prop); } - -const std::set Plane::getHint() const -{ - if (hints.find(refTypes) != hints.end()) - return hints[refTypes]; - else - return std::set(); -} - -const int Plane::offsetsAllowed() const -{ - return 1; -} - Base::Vector3d Plane::getBasePoint() { return Placement.getValue().getPosition(); diff --git a/src/Mod/PartDesign/App/DatumPlane.h b/src/Mod/PartDesign/App/DatumPlane.h index 3d78165b6..545e30fec 100644 --- a/src/Mod/PartDesign/App/DatumPlane.h +++ b/src/Mod/PartDesign/App/DatumPlane.h @@ -43,19 +43,11 @@ public: return "PartDesignGui::ViewProviderDatumPlane"; } - static void initHints(); - const std::set getHint() const; - const int offsetsAllowed() const; - Base::Vector3d getBasePoint(); Base::Vector3d getNormal(); protected: virtual void onChanged(const App::Property* prop); - -private: - // Hints on what further references are required/possible on this feature for a given set of references - static std::map, std::set > hints; }; } //namespace PartDesign diff --git a/src/Mod/PartDesign/App/DatumPoint.cpp b/src/Mod/PartDesign/App/DatumPoint.cpp index 340c143d6..cbcad427d 100644 --- a/src/Mod/PartDesign/App/DatumPoint.cpp +++ b/src/Mod/PartDesign/App/DatumPoint.cpp @@ -76,78 +76,19 @@ using namespace PartDesign; -// Note: We don't distinguish between e.g. datum lines and edges here -#define PLANE QObject::tr("DPLANE") -#define CYLINDER QObject::tr("DCYLINDER") -#define LINE QObject::tr("DLINE") -#define POINT QObject::tr("DPOINT") -#define CIRCLE QObject::tr("DCIRCLE") -#define ANGLE QObject::tr("Angle") - -// ================================ Initialize the hints ===================== - -std::map, std::set > Point::hints = std::map, std::set >(); - -void Point::initHints() -{ - std::set DONE; - DONE.insert(QObject::tr("Done")); - - std::multiset key; - std::set value; - key.insert(POINT); - hints[key] = DONE; // POINT -> DONE. Point from another point or vertex - - key.clear(); value.clear(); - key.insert(CIRCLE); - hints[key] = DONE; // CIRCLE -> DONE. Point from center of circle or arc - - key.clear(); value.clear(); - key.insert(LINE); - value.insert(LINE); value.insert(PLANE); - hints[key] = value; // LINE -> LINE or PLANE - - key.clear(); value.clear(); - key.insert(LINE); key.insert(LINE); - hints[key] = DONE; // {LINE, LINE} -> DONE. Point from two lines or edges - - key.clear(); value.clear(); - key.insert(LINE); key.insert(PLANE); - hints[key] = DONE; // {LINE, PLANE} -> DONE. Point from line and plane - - key.clear(); value.clear(); - key.insert(PLANE); - value.insert(PLANE); value.insert(LINE); - hints[key] = value; // PLANE -> PLANE or LINE - - key.clear(); value.clear(); - key.insert(PLANE); key.insert(PLANE); - value.insert(PLANE); - hints[key] = value; // {PLANE, PLANE} -> PLANE - - key.clear(); value.clear(); - key.insert(PLANE); key.insert(PLANE); key.insert(PLANE); - hints[key] = DONE; // {PLANE, PLANE, PLANE} -> DONE. Point from three planes - - key.clear(); value.clear(); - value.insert(POINT); value.insert(LINE); value.insert(PLANE); - hints[key] = value; -} - // ============================================================================ PROPERTY_SOURCE(PartDesign::Point, Part::Datum) Point::Point() { + this->setAttacher(new AttachEnginePoint); // Create a shape, which will be used by the Sketcher. Them main function is to avoid a dependency of // Sketcher on the PartDesign module BRepBuilderAPI_MakeVertex builder(gp_Pnt(0,0,0)); if (!builder.IsDone()) return; Shape.setValue(builder.Shape()); - - References.touch(); } Point::~Point() @@ -156,223 +97,6 @@ Point::~Point() void Point::onChanged(const App::Property* prop) { - if ((prop == &References) || (prop == &Offset) || (prop == &Offset2) || (prop == &Offset3)) { - refTypes.clear(); - std::vector refs = References.getValues(); - std::vector refnames = References.getSubValues(); - - for (int r = 0; r < refs.size(); r++) - refTypes.insert(getRefType(refs[r], refnames[r])); - - std::set hint = getHint(); - if (!((hint.size() == 1) && (hint.find(QObject::tr("Done")) != hint.end()))) - return; // incomplete references - - // Extract the geometry of the references - Base::Vector3d* point = NULL; - Handle_Geom_Curve c1 = NULL; - Handle_Geom_Curve c2 = NULL; - Handle_Geom_Surface s1 = NULL; - Handle_Geom_Surface s2 = NULL; - Handle_Geom_Surface s3 = NULL; - gp_Circ* circle = NULL; - - for (int i = 0; i < refs.size(); i++) { - if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Point::getClassTypeId())) { - PartDesign::Point* p = static_cast(refs[i]); - point = new Base::Vector3d (p->getPoint()); - } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) { - PartDesign::Line* l = static_cast(refs[i]); - Base::Vector3d base = l->getBasePoint(); - Base::Vector3d dir = l->getDirection(); - if (c1.IsNull()) - c1 = new Geom_Line(gp_Pnt(base.x, base.y, base.z), gp_Dir(dir.x, dir.y, dir.z)); - else - c2 = new Geom_Line(gp_Pnt(base.x, base.y, base.z), gp_Dir(dir.x, dir.y, dir.z)); - } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { - PartDesign::Plane* p = static_cast(refs[i]); - Base::Vector3d base = p->getBasePoint(); - Base::Vector3d normal = p->getNormal(); - if (s1.IsNull()) - s1 = new Geom_Plane(gp_Pnt(base.x, base.y, base.z), gp_Dir(normal.x, normal.y, normal.z)); - else if (s2.IsNull()) - s2 = new Geom_Plane(gp_Pnt(base.x, base.y, base.z), gp_Dir(normal.x, normal.y, normal.z)); - else - s3 = new Geom_Plane(gp_Pnt(base.x, base.y, base.z), gp_Dir(normal.x, normal.y, normal.z)); - - } else if (refs[i]->getTypeId().isDerivedFrom(App::Line::getClassTypeId())) { - App::Line* l = static_cast(refs[i]); - // Note: We only handle the three base planes here - gp_Pnt base(0,0,0); - gp_Dir normal; - if (strcmp(l->LineType.getValue(), App::Part::BaselineTypes[0]) == 0) - normal = gp_Dir(1,0,0); - else if (strcmp(l->LineType.getValue(), App::Part::BaselineTypes[1]) == 0) - normal = gp_Dir(0,1,0); - else if (strcmp(l->LineType.getValue(), App::Part::BaselineTypes[2]) == 0) - normal = gp_Dir(0,0,1); - - if (s1.IsNull()) - c1 = new Geom_Line(base, normal); - else if (s2.IsNull()) - c2 = new Geom_Line(base, normal); - - } else if (refs[i]->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { - App::Plane* p = static_cast(refs[i]); - // Note: We only handle the three base planes here - gp_Pnt base(0,0,0); - gp_Dir normal; - if (strcmp(p->PlaneType.getValue(), App::Part::BaseplaneTypes[0]) == 0) - normal = gp_Dir(0,0,1); - else if (strcmp(p->PlaneType.getValue(), App::Part::BaseplaneTypes[2]) == 0) - normal = gp_Dir(1,0,0); - else if (strcmp(p->PlaneType.getValue(), App::Part::BaseplaneTypes[1]) == 0) - normal = gp_Dir(0,1,0); - - if (s1.IsNull()) - s1 = new Geom_Plane(base, normal); - else if (s2.IsNull()) - s2 = new Geom_Plane(base, normal); - else - s3 = new Geom_Plane(base, normal); - } else if (refs[i]->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { - Part::Feature* feature = static_cast(refs[i]); - const TopoDS_Shape& sh = feature->Shape.getValue(); - if (sh.IsNull()) - return; // "PartDesign::Point: Reference has NULL shape" - // Get subshape - TopoDS_Shape subshape = feature->Shape.getShape().getSubShape(refnames[i].c_str()); - if (subshape.IsNull()) - return; // "PartDesign::Point: Reference has NULL subshape"; - - if (subshape.ShapeType() == TopAbs_VERTEX) { - TopoDS_Vertex v = TopoDS::Vertex(subshape); - gp_Pnt p = BRep_Tool::Pnt(v); - point = new Base::Vector3d(p.X(), p.Y(), p.Z()); - } else if (subshape.ShapeType() == TopAbs_EDGE) { - TopoDS_Edge e = TopoDS::Edge(subshape); - BRepAdaptor_Curve adapt(e); - if (adapt.GetType() == GeomAbs_Circle) { - circle = new gp_Circ(adapt.Circle()); - } else { - Standard_Real first, last; - if (c1.IsNull()) - c1 = BRep_Tool::Curve(e, first, last); - else - c2 = BRep_Tool::Curve(e, first, last); - } - } else if (subshape.ShapeType() == TopAbs_FACE) { - TopoDS_Face f = TopoDS::Face(subshape); - double offset1 = Offset.getValue(); - double offset2 = Offset2.getValue(); - double offset3 = Offset3.getValue(); - BRepAdaptor_Surface adapt(f); - - if (s1.IsNull()) { - if (adapt.GetType() == GeomAbs_Plane) { - gp_Trsf mov; - mov.SetTranslation(offset1 * gp_Vec(adapt.Plane().Axis().Direction())); - TopLoc_Location loc(mov); - f.Move(loc); - } - s1 = BRep_Tool::Surface(f); - } else if (s2.IsNull()) { - if (adapt.GetType() == GeomAbs_Plane) { - gp_Trsf mov; - mov.SetTranslation(offset2 * gp_Vec(adapt.Plane().Axis().Direction())); - TopLoc_Location loc(mov); - f.Move(loc); - } - s2 = BRep_Tool::Surface(f); - } else { - if (adapt.GetType() == GeomAbs_Plane) { - gp_Trsf mov; - mov.SetTranslation(offset3 * gp_Vec(adapt.Plane().Axis().Direction())); - TopLoc_Location loc(mov); - f.Move(loc); - } - s3 = BRep_Tool::Surface(f); - } - } - } else { - return; //"PartDesign::Point: Invalid reference type" - } - } - - if (point != NULL) { - // Point from vertex or other point. Nothing to be done - } else if (circle != NULL) { - // Point from center of circle (or arc) - gp_Pnt centre = circle->Axis().Location(); - point = new Base::Vector3d(centre.X(), centre.Y(), centre.Z()); - } else if (!c1.IsNull()) { - if (!c2.IsNull()) { - // Point from intersection of two curves - GeomAPI_ExtremaCurveCurve intersector(c1, c2); - if ((intersector.LowerDistance() > Precision::Confusion()) || (intersector.NbExtrema() == 0)) - throw Base::Exception("Curve-Curve intersection failed"); // No intersection - // Note: We don't check for multiple intersection points - gp_Pnt p, p2; - intersector.Points(1, p, p2); - - // Apply offset if the curves are linear (meaning they define a plane that contains them both) - if ((c1->DynamicType() == STANDARD_TYPE(Geom_Line)) && (c2->DynamicType() == STANDARD_TYPE(Geom_Line))) { - // Get translation vectors - Handle_Geom_Line lin1 = Handle_Geom_Line::DownCast(c1); - Handle_Geom_Line lin2 = Handle_Geom_Line::DownCast(c2); - gp_Dir normal = lin1->Lin().Direction().Crossed(lin2->Lin().Direction()); // normal of the plane - gp_Dir trans1 = normal.Crossed(lin1->Lin().Direction()); - gp_Dir trans2 = normal.Crossed(lin2->Lin().Direction()); - double offset1 = Offset.getValue(); - double offset2 = Offset2.getValue(); - c1->Translate(offset1 * gp_Vec(trans1)); - c2->Translate(offset2 * gp_Vec(trans2)); - // Intersect again - intersector = GeomAPI_ExtremaCurveCurve(c1, c2); - if ((intersector.LowerDistance() > Precision::Confusion()) || (intersector.NbExtrema() == 0)) - throw Base::Exception("Curve-Curve intersection failed"); // No intersection - // Note: We don't check for multiple intersection points - intersector.Points(1, p, p2); - } - - point = new Base::Vector3d(p.X(), p.Y(), p.Z()); - } else if (!s1.IsNull()) { - GeomAPI_IntCS intersector(c1, s1); - if (!intersector.IsDone() || (intersector.NbPoints() == 0)) - throw Base::Exception("Curve-Surface intersection failed"); - if (intersector.NbPoints() > 1) - Base::Console().Warning("More than one intersection point for datum point from curve and surface\n"); - - gp_Pnt p = intersector.Point(1); - point = new Base::Vector3d(p.X(), p.Y(), p.Z()); - } else - return; - } else if (!s1.IsNull() && !s2.IsNull() && !s3.IsNull()) { - GeomAPI_IntSS intersectorSS(s1, s2, Precision::Confusion()); - if (!intersectorSS.IsDone() || (intersectorSS.NbLines() == 0)) - return; - if (intersectorSS.NbLines() > 1) - Base::Console().Warning("More than one intersection line for datum point from surfaces\n"); - Handle_Geom_Curve line = intersectorSS.Line(1); - - GeomAPI_IntCS intersector(line, s3); - if (!intersector.IsDone() || (intersector.NbPoints() == 0)) - return; - if (intersector.NbPoints() > 1) - Base::Console().Warning("More than one intersection point for datum point from surfaces\n"); - - gp_Pnt p = intersector.Point(1); - point = new Base::Vector3d(p.X(), p.Y(), p.Z()); - } else { - return; - } - - Placement.setValue(Base::Placement(*point, Base::Rotation())); - - delete point; - if (circle != NULL) delete circle; - } - Part::Datum::onChanged(prop); } @@ -380,73 +104,3 @@ Base::Vector3d Point::getPoint() { return Placement.getValue().getPosition(); } - - -const std::set Point::getHint() const -{ - if (hints.find(refTypes) != hints.end()) - return hints[refTypes]; - else - return std::set(); -} - -const int Point::offsetsAllowed() const -{ - int numlines = 0, numplanes = 0; - for (std::multiset::const_iterator r = refTypes.begin(); r != refTypes.end(); r++) { - if (*r == LINE) numlines++; - else if (*r == PLANE) numplanes++; - } - - if (numlines == 2) return 2; // Special case: Two intersecting lines. TODO: Check for co-planarity - return numplanes; -} - - -namespace PartDesign { - -const QString getRefType(const App::DocumentObject* obj, const std::string& subname) -{ - Base::Type type = obj->getTypeId(); - - if ((type == App::Plane::getClassTypeId()) || (type == PartDesign::Plane::getClassTypeId())) - return PLANE; - else if ((type == App::Line::getClassTypeId()) || (type == PartDesign::Line::getClassTypeId())) - return LINE; - else if (type == PartDesign::Point::getClassTypeId()) - return POINT; - else if (type.isDerivedFrom(Part::Feature::getClassTypeId())) { - const Part::Feature* feature = static_cast(obj); - const Part::TopoShape& topShape = feature->Shape.getShape(); - if (topShape.isNull()) - return QString::fromAscii("EMPTYSHAPE"); // Can happen on file loading - - if (subname.size() > 4 && subname.substr(0,4) == "Face") { - TopoDS_Shape face = topShape.getSubShape(subname.c_str()); - if (face.IsNull() || (face.ShapeType() != TopAbs_FACE)) - throw Base::Exception("Part::Datum::getRefType(): No valid subshape could be extracted"); - BRepAdaptor_Surface adapt(TopoDS::Face(face)); - if (adapt.GetType() == GeomAbs_Plane) - return PLANE; - else if (adapt.GetType() == GeomAbs_Cylinder) - return CYLINDER; - else - throw Base::Exception("Part::Datum::getRefType(): Only planar and cylindrical faces are allowed"); - } else if (subname.size() > 4 && subname.substr(0,4) == "Edge") { - TopoDS_Shape edge = topShape.getSubShape(subname.c_str()); - if (edge.IsNull() || (edge.ShapeType() != TopAbs_EDGE)) - throw Base::Exception("Part::Datum::getRefType(): No valid subshape could be extracted"); - BRepAdaptor_Curve adapt(TopoDS::Edge(edge)); - if (adapt.GetType() == GeomAbs_Circle) - return CIRCLE; - else // We don't check for other types yet - return LINE; - } else if (subname.size() > 6 && subname.substr(0,6) == "Vertex") { - return POINT; - } - } - - throw Base::Exception("Part::Datum::getRefType(): Illegal object type"); -} - -} diff --git a/src/Mod/PartDesign/App/DatumPoint.h b/src/Mod/PartDesign/App/DatumPoint.h index 0a23e064d..9227bbe43 100644 --- a/src/Mod/PartDesign/App/DatumPoint.h +++ b/src/Mod/PartDesign/App/DatumPoint.h @@ -44,24 +44,12 @@ public: return "PartDesignGui::ViewProviderDatumPoint"; } - static void initHints(); - const std::set getHint() const; - const int offsetsAllowed() const; - Base::Vector3d getPoint(); protected: virtual void onChanged(const App::Property* prop); - -private: - // Hints on what further references are required/possible on this feature for a given set of references - static std::map, std::set > hints; }; -// This has to be declared somewhere... a good place would be Part::Datum but since the code requires -// access to PartDesign::Point etc. that's not possible -const QString getRefType(const App::DocumentObject* obj, const std::string& subname); - } //namespace PartDesign diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index aaebd46d0..1ada6bbaa 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -599,9 +599,10 @@ void CmdPartDesignPlane::activated(int iMsg) openCommand("Create a datum plane"); doCommand(Doc,"App.activeDocument().addObject('PartDesign::Plane','%s')",FeatName.c_str()); if (refStr.length() > 0) - doCommand(Doc,"App.activeDocument().%s.References = %s",FeatName.c_str(),refStr.toStdString().c_str()); - doCommand(Doc,"App.activeDocument().%s.Offset = 0.0",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Angle = 0.0",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Support = %s",FeatName.c_str(),refStr.toStdString().c_str()); + Datum* pcDatum = static_cast(getDocument()->getObject(FeatName.c_str())); + eSuggestResult msg; + pcDatum->MapMode.setValue(pcDatum->attacher().listMapModes(msg)); doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", pcActiveBody->getNameInDocument(), FeatName.c_str()); doCommand(Gui,"App.activeDocument().recompute()"); // recompute the feature based on its references @@ -643,7 +644,10 @@ void CmdPartDesignLine::activated(int iMsg) openCommand("Create a datum line"); doCommand(Doc,"App.activeDocument().addObject('PartDesign::Line','%s')",FeatName.c_str()); if (refStr.length() > 0) - doCommand(Doc,"App.activeDocument().%s.References = %s",FeatName.c_str(),refStr.toStdString().c_str()); + doCommand(Doc,"App.activeDocument().%s.Support = %s",FeatName.c_str(),refStr.toStdString().c_str()); + Datum* pcDatum = static_cast(getDocument()->getObject(FeatName.c_str())); + eSuggestResult msg; + pcDatum->MapMode.setValue(pcDatum->attacher().listMapModes(msg)); doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", pcActiveBody->getNameInDocument(), FeatName.c_str()); doCommand(Gui,"App.activeDocument().recompute()"); // recompute the feature based on its references @@ -685,12 +689,14 @@ void CmdPartDesignPoint::activated(int iMsg) openCommand("Create a datum point"); doCommand(Doc,"App.activeDocument().addObject('PartDesign::Point','%s')",FeatName.c_str()); if (refStr.length() > 0) - doCommand(Doc,"App.activeDocument().%s.References = %s",FeatName.c_str(),refStr.toStdString().c_str()); + doCommand(Doc,"App.activeDocument().%s.Support = %s",FeatName.c_str(),refStr.toStdString().c_str()); + Datum* pcDatum = static_cast(getDocument()->getObject(FeatName.c_str())); + eSuggestResult msg; + pcDatum->MapMode.setValue(pcDatum->attacher().listMapModes(msg)); doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", pcActiveBody->getNameInDocument(), FeatName.c_str()); doCommand(Gui,"App.activeDocument().recompute()"); // recompute the feature based on its references doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - } bool CmdPartDesignPoint::isActive(void) @@ -886,7 +892,7 @@ void CmdPartDesignNewSketch::activated(int iMsg) App::Plane* plane = static_cast(features.front()); std::string FeatName = getUniqueObjectName("Sketch"); std::string supportString = std::string("(App.activeDocument().") + plane->getNameInDocument() + - ", ['" + (false ? "back" : "front") + "'])"; + ", [''])"; Gui::Command::openCommand("Create a new Sketch"); Gui::Command::doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str());