From 6effd7d864ae741095ddb7d7c18cd409744f4728 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Mon, 29 Apr 2013 20:31:18 +0430 Subject: [PATCH] Visualization of datum lines and planes --- src/Mod/PartDesign/App/DatumFeature.cpp | 457 ++++++++++++++++++ src/Mod/PartDesign/App/DatumFeature.h | 6 + src/Mod/PartDesign/Gui/ViewProviderDatum.cpp | 241 +++++++-- .../Gui/ViewProviderTransformed.cpp | 1 + 4 files changed, 669 insertions(+), 36 deletions(-) create mode 100644 src/Mod/PartDesign/App/DatumFeature.cpp diff --git a/src/Mod/PartDesign/App/DatumFeature.cpp b/src/Mod/PartDesign/App/DatumFeature.cpp new file mode 100644 index 0000000000..bb6861f11a --- /dev/null +++ b/src/Mod/PartDesign/App/DatumFeature.cpp @@ -0,0 +1,457 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinländer * + * * + * 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 +#endif + +#include +#include +#include "DatumFeature.h" +#include +#include +#include +#include "Mod/Part/App/PrimitiveFeature.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +using namespace PartDesign; + +PROPERTY_SOURCE_ABSTRACT(PartDesign::Datum, App::DocumentObject) + +Datum::Datum(void) +{ + ADD_PROPERTY_TYPE(References,(0,0),"References",(App::PropertyType)(App::Prop_None),"References defining the datum feature"); + ADD_PROPERTY(Values,(0.0)); + touch(); +} + +Datum::~Datum() +{ +} + + +App::DocumentObjectExecReturn *Datum::execute(void) +{ + References.touch(); + return StdReturn; +} + +void Datum::onChanged(const App::Property* prop) +{ + + if (prop == &References) { + 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])); + } + + App::DocumentObject::onChanged(prop); +} + +void Datum::onDocumentRestored() +{ + // This seems to be the only way to make the ViewProvider display the datum feature + References.touch(); + App::DocumentObject::onDocumentRestored(); +} + +// Note: We don't distinguish between e.g. datum lines and edges here +#define PLANE QObject::tr("DPLANE") +#define LINE QObject::tr("DLINE") +#define POINT QObject::tr("DPOINT") + +const QString Datum::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 == PartDesign::Line::getClassTypeId()) + return LINE; + else if (type == PartDesign::Point::getClassTypeId()) + return POINT; + else if (type.isDerivedFrom(Part::Feature::getClassTypeId())) { + // Note: For now, only planar references are possible + if (subname.size() > 4 && subname.substr(0,4) == "Face") + return PLANE; + else if (subname.size() > 4 && subname.substr(0,4) == "Edge") + return LINE; + else if (subname.size() > 6 && subname.substr(0,6) == "Vertex") + return POINT; + } + + throw Base::Exception("PartDesign::Datum::getRefType(): Illegal object type"); +} + +// ================================ Initialize the hints ===================== + +std::map, std::set > Point::hints = std::map, std::set >(); + +void Point::initHints() +{ + std::set DONE; + DONE.insert(QObject::tr("Point")); + + 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(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; +} + +std::map, std::set > Line::hints = std::map, std::set >(); + +void Line::initHints() +{ + std::set DONE; + DONE.insert(QObject::tr("Line")); + + 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(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); + hints[key] = value; // PLANE -> 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(); + value.insert(POINT); value.insert(LINE); value.insert(PLANE); + hints[key] = value; +} + +std::map, std::set > Plane::hints = std::map, std::set >(); + +void Plane::initHints() +{ + std::set DONE; + DONE.insert(QObject::tr("Plane")); + + 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); + hints[key] = value; // LINE -> POINT + + key.clear(); value.clear(); + value.insert(POINT); value.insert(LINE); value.insert(PLANE); + hints[key] = value; +} + +// ============================================================================ + +PROPERTY_SOURCE(PartDesign::Point, PartDesign::Datum) + +Point::Point() +{ + ADD_PROPERTY_TYPE(_Point,(Base::Vector3d(0,0,1)),"DatumPoint", + App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), + "Coordinates of the datum point"); +} + +Point::~Point() +{ +} + +void Point::onChanged(const App::Property* prop) +{ + Datum::onChanged(prop); + + if (prop == &References) { + std::set hint = getHint(); + if (!((hint.size() == 1) && (hint.find(QObject::tr("Point")) != hint.end()))) + return; // incomplete references + + // Extract the geometry of the references + std::vector refs = References.getValues(); + std::vector refnames = References.getSubValues(); + Base::Vector3f* 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; + + 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->_Point.getValue()); + } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) { + PartDesign::Line* l = static_cast(refs[i]); + //point = new Base::Vector3f (p->_Point.getValue()); + } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { + PartDesign::Plane* p = static_cast(refs[i]); + //point = new Base::Vector3f (p->_Point.getValue()); + } else if (refs[i]->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { + App::Plane* p = static_cast(refs[i]); + //point = new Base::Vector3f (p->_Point.getValue()); + } 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::Vector3f(p.X(), p.Y(), p.Z()); + } else if (subshape.ShapeType() == TopAbs_EDGE) { + TopoDS_Edge e = TopoDS::Edge(subshape); + 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); + if (s1.IsNull()) + s1 = BRep_Tool::Surface(f); + else if (s2.IsNull()) + s2 = BRep_Tool::Surface(f); + else + 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 (!c1.IsNull()) { + if (!c2.IsNull()) { + // Point from intersection of two curves + GeomAPI_ExtremaCurveCurve intersector(c1, c2); + if ((intersector.LowerDistance() > Precision::Confusion()) || (intersector.NbExtrema() == 0)) + return; // No intersection + // Note: We don't check for multiple intersection points + gp_Pnt p, p2; + intersector.Points(1, p, p2); + point = new Base::Vector3f(p.X(), p.Y(), p.Z()); + } else if (!s1.IsNull()) { + GeomAPI_IntCS intersector(c1, s1); + if (!intersector.IsDone() || (intersector.NbPoints() == 0)) + return; + if (intersector.NbPoints() > 1) + Base::Console().Warning("More than one intersection point for datum point from curve and surface"); + + gp_Pnt p = intersector.Point(1); + point = new Base::Vector3f(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"); + 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"); + + gp_Pnt p = intersector.Point(1); + point = new Base::Vector3f(p.X(), p.Y(), p.Z()); + } else { + return; + } + + _Point.setValue(*point); + _Point.touch(); // This triggers ViewProvider::updateData() + delete point; + } +} + + +const std::set Point::getHint() +{ + if (hints.find(refTypes) != hints.end()) + return hints[refTypes]; + else + return std::set(); +} + + +PROPERTY_SOURCE(PartDesign::Line, PartDesign::Datum) + +Line::Line() +{ +} + +Line::~Line() +{ +} + +void Line::onChanged(const App::Property *prop) +{ + gp_Pnt point1(0,0,0); + + gp_Pnt point2(10,10,10); + + return; +} + + +const std::set Line::getHint() +{ + if (hints.find(refTypes) != hints.end()) + return hints[refTypes]; + else + return std::set(); +} + + +PROPERTY_SOURCE(PartDesign::Plane, PartDesign::Datum) + +Plane::Plane() +{ +} + +void Plane::onChanged(const App::Property *prop) +{ + double O = 10.0; //this->Offset.getValue(); + double A = 45.0; //this->Angle.getValue(); + + if (fabs(A) > 360.0) + return; // "Angle too large (please use -360.0 .. +360.0)" + + gp_Pnt pnt(0.0,0.0,0.0); + gp_Dir dir(0.0,0.0,1.0); + + return; +} + + +const std::set Plane::getHint() +{ + if (hints.find(refTypes) != hints.end()) + return hints[refTypes]; + else + return std::set(); +} diff --git a/src/Mod/PartDesign/App/DatumFeature.h b/src/Mod/PartDesign/App/DatumFeature.h index 99a4bbf75d..6bee013108 100644 --- a/src/Mod/PartDesign/App/DatumFeature.h +++ b/src/Mod/PartDesign/App/DatumFeature.h @@ -95,6 +95,9 @@ class PartDesignExport Line : public PartDesign::Datum PROPERTY_HEADER(PartDesign::Line); public: + App::PropertyVector _Base; + App::PropertyVector _Direction; + Line(); virtual ~Line(); @@ -118,6 +121,9 @@ class PartDesignExport Plane : public PartDesign::Datum PROPERTY_HEADER(PartDesign::Plane); public: + App::PropertyVector _Base; + App::PropertyVector _Normal; + Plane(); const char* getViewProviderName(void) const { diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp index 2bbfd9c634..5a66b17f72 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp @@ -28,14 +28,22 @@ # include # include # include +# include # include +# include # include # include # include +# include +# include # include # include # include # include +# include +# include +# include +# include #endif #include "ViewProviderDatum.h" @@ -44,6 +52,7 @@ #include #include #include +#include using namespace PartDesignGui; @@ -73,13 +82,19 @@ void ViewProviderDatum::attach(App::DocumentObject *obj) datumType = QObject::tr("Point"); SoSeparator* sep = new SoSeparator(); + SoPickStyle* ps = new SoPickStyle(); + ps->style = SoPickStyle::SHAPE; SoShapeHints* hints = new SoShapeHints(); hints->shapeType.setValue(SoShapeHints::UNKNOWN_SHAPE_TYPE); hints->vertexOrdering.setValue(SoShapeHints::COUNTERCLOCKWISE); SoBaseColor* color = new SoBaseColor(); - color->rgb.setValue(0.9, 0.9, 0.2); + color->rgb.setValue(0.9, 0.9, 0.1); + SoMaterial* material = new SoMaterial(); + material->diffuseColor.setValue(0.9f, 0.9f, 0.1f); + material->transparency.setValue(0.2); sep->addChild(hints); sep->addChild(color); + sep->addChild(material); sep->addChild(pShapeSep); addDisplayMaskMode(sep, "Base"); } @@ -182,7 +197,7 @@ ViewProviderDatumPoint::ViewProviderDatumPoint() { SoMarkerSet* points = new SoMarkerSet(); points->markerIndex = SoMarkerSet::DIAMOND_FILLED_9_9; - points->numPoints = 1; + points->numPoints = 0; pShapeSep->addChild(points); } @@ -197,13 +212,23 @@ void ViewProviderDatumPoint::updateData(const App::Property* prop) PartDesign::Point* pcDatum = static_cast(this->getObject()); if (strcmp(prop->getName(),"_Point") == 0) { - Base::Vector3f p = pcDatum->_Point.getValue(); + Base::Vector3d p = pcDatum->_Point.getValue(); SoMFVec3f v; + v.setNum(1); v.set1Value(0, p.x, p.y, p.z); - SoVertexProperty* vprop = new SoVertexProperty(); - vprop->vertex = v; SoMarkerSet* points = static_cast(pShapeSep->getChild(0)); - points->vertexProperty = vprop; + + SoVertexProperty* vprop; + if (points->vertexProperty.getValue() == NULL) { + vprop = new SoVertexProperty(); + vprop->vertex = v; + points->vertexProperty = vprop; + } else { + vprop = static_cast(points->vertexProperty.getValue()); + vprop->vertex = v; + } + + points->numPoints = 1; } ViewProviderDatum::updateData(prop); @@ -213,12 +238,8 @@ PROPERTY_SOURCE(PartDesignGui::ViewProviderDatumLine,PartDesignGui::ViewProvider ViewProviderDatumLine::ViewProviderDatumLine() { - /* - SoMarkerSet* points = new SoMarkerSet(); - points->markerIndex = SoMarkerSet::DIAMOND_FILLED_9_9; - points->numPoints = 1; - pShapeSep->addChild(points); - */ + SoLineSet* lineSet = new SoLineSet(); + pShapeSep->addChild(lineSet); } ViewProviderDatumLine::~ViewProviderDatumLine() @@ -231,16 +252,51 @@ void ViewProviderDatumLine::updateData(const App::Property* prop) // Gets called whenever a property of the attached object changes PartDesign::Line* pcDatum = static_cast(this->getObject()); - /* - if (strcmp(prop->getName(),"_Point") == 0) { - Base::Vector3f p = pcDatum->_Point.getValue(); + if (strcmp(prop->getName(),"_Base") == 0) { + Base::Vector3d base = pcDatum->_Base.getValue(); + Base::Vector3d dir = pcDatum->_Direction.getValue(); + + // Get limits of the line from bounding box of the body + PartDesign::Body* body = PartDesign::Body::findBodyOf(this->getObject()); + if (body == NULL) + return; + Part::Feature* tipSolid = static_cast(body->getPrevSolidFeature()); + if (tipSolid == NULL) + return; + Base::BoundBox3d bbox = tipSolid->Shape.getShape().getBoundBox(); + bbox.Enlarge(0.1 * bbox.CalcDiagonalLength()); + Base::Vector3d p1, p2; + if (bbox.IsInBox(base)) { + bbox.IntersectionPoint(base, dir, p1, Precision::Confusion()); + bbox.IntersectionPoint(base, -dir, p2, Precision::Confusion()); + } else { + bbox.IntersectWithLine(base, dir, p1, p2); + if ((p1 == Base::Vector3d(0,0,0)) && (p2 == Base::Vector3d(0,0,0))) + bbox.IntersectWithLine(base, -dir, p1, p2); + } + + // Display the line SoMFVec3f v; - v.set1Value(0, p.x, p.y, p.z); - SoVertexProperty* vprop = new SoVertexProperty(); - vprop->vertex = v; - SoMarkerSet* points = static_cast(pShapeSep->getChild(0)); - points->vertexProperty = vprop; - }*/ + v.setNum(2); + v.set1Value(0, p1.x, p1.y, p1.z); + v.set1Value(1, p2.x, p2.y, p2.z); + SoLineSet* lineSet = static_cast(pShapeSep->getChild(0)); + + SoVertexProperty* vprop; + if (lineSet->vertexProperty.getValue() == NULL) { + vprop = new SoVertexProperty(); + vprop->vertex = v; + lineSet->vertexProperty = vprop; + } else { + vprop = static_cast(lineSet->vertexProperty.getValue()); + vprop->vertex = v; + } + + SoMFInt32 idx; + idx.setNum(1); + idx.set1Value(0, 2); + lineSet->numVertices = idx; + } ViewProviderDatum::updateData(prop); } @@ -249,12 +305,8 @@ PROPERTY_SOURCE(PartDesignGui::ViewProviderDatumPlane,PartDesignGui::ViewProvide ViewProviderDatumPlane::ViewProviderDatumPlane() { - /* - SoMarkerSet* points = new SoMarkerSet(); - points->markerIndex = SoMarkerSet::DIAMOND_FILLED_9_9; - points->numPoints = 1; - pShapeSep->addChild(points); - */ + SoFaceSet* faceSet = new SoFaceSet(); + pShapeSep->addChild(faceSet); } ViewProviderDatumPlane::~ViewProviderDatumPlane() @@ -266,16 +318,133 @@ void ViewProviderDatumPlane::updateData(const App::Property* prop) { // Gets called whenever a property of the attached object changes PartDesign::Plane* pcDatum = static_cast(this->getObject()); -/* - if (strcmp(prop->getName(),"_Point") == 0) { - Base::Vector3f p = pcDatum->_Point.getValue(); + + if (strcmp(prop->getName(),"_Base") == 0) { + Base::Vector3d base = pcDatum->_Base.getValue(); + Base::Vector3d normal = pcDatum->_Normal.getValue(); + + // Get limits of the plane from bounding box of the body + PartDesign::Body* body = PartDesign::Body::findBodyOf(this->getObject()); + if (body == NULL) + return; + Part::Feature* tipSolid = static_cast(body->getPrevSolidFeature()); + if (tipSolid == NULL) + return; + Base::BoundBox3d bbox = tipSolid->Shape.getShape().getBoundBox(); + bbox.Enlarge(0.1 * bbox.CalcDiagonalLength()); + + // Calculate intersection of plane with bounding box edges + // TODO: This can be a lot more efficient if we do the maths ourselves, e.g. + // http://cococubed.asu.edu/code_pages/raybox.shtml + // http://www.fho-emden.de/~hoffmann/cubeplane12112006.pdf + Handle_Geom_Plane plane = new Geom_Plane(gp_Pnt(base.x, base.y, base.z), gp_Dir(normal.x, normal.y, normal.z)); + std::vector points; + + for (int i = 0; i < 12; i++) { + // Get the edge of the bounding box + Base::Vector3d p1, p2; + bbox.CalcDistance(i, p1, p2); + Base::Vector3d ldir = p2 - p1; + Handle_Geom_Line line = new Geom_Line(gp_Pnt(p1.x, p1.y, p1.z), gp_Dir(ldir.x, ldir.y, ldir.z)); + GeomAPI_IntCS intersector(line, plane); + if (!intersector.IsDone() || (intersector.NbPoints() == 0)) + continue; + gp_Pnt pnt = intersector.Point(1); + Base::Vector3d point(pnt.X(), pnt.Y(), pnt.Z()); + + // Check whether intersection is on the bbox edge (bbox.IsInside() always tests false) + double edgeLength = (p1 - p2).Length(); + double l1 = (p1 - point).Length(); + double l2 = (p2 - point).Length(); + if (fabs(edgeLength - l1 - l2) > 0.001) + continue; + + // Check for duplicates + bool duplicate = false; + for (std::vector::const_iterator p = points.begin(); p != points.end(); p++) { + if ((point - *p).Sqr() < Precision::Confusion()) { + duplicate = true; + break; + } + } + if (!duplicate) + points.push_back(point); + } + + if (points.size() < 3) + return; + + // Sort the points to get a proper polygon, see http://www.fho-emden.de/~hoffmann/cubeplane12112006.pdf p.5 + if (points.size() > 3) { + // Longest component of normal vector + int longest; + if (normal.x > normal.y) + if (normal.x > normal.z) + longest = 0; // x is longest + else + longest = 2; // z is longest + else + if (normal.y > normal.z) + longest = 1; // y is longest + else + longest = 2; // z is longest + + // mean value for intersection points + Base::Vector3d m; + for (std::vector::iterator p = points.begin(); p != points.end(); p++) + m += *p; + m /= points.size(); + + // Sort by angles + double a[points.size()]; + for (int i = 0; i < points.size() - 1; i++) { + if (longest == 0) + a[i] = atan2(points[i].z - m.z, points[i].y - m.y); + else if (longest == 1) + a[i] = atan2(points[i].z - m.z, points[i].x - m.x); + else + a[i] = atan2(points[i].y - m.y, points[i].x - m.x); + + for (int k = i+1; k < points.size(); k++) { + if (longest == 0) + a[k] = atan2(points[k].z - m.z, points[k].y - m.y); + else if (longest == 1) + a[k] = atan2(points[k].z - m.z, points[k].x - m.x); + else + a[k] = atan2(points[k].y - m.y, points[k].x - m.x); + + if (a[k] < a[i]) { + Base::Vector3d temp = points[i]; + points[i] = points[k]; + points[k] = temp; + a[i] = a[k]; + } + } + } + } + + // Display the plane SoMFVec3f v; - v.set1Value(0, p.x, p.y, p.z); - SoVertexProperty* vprop = new SoVertexProperty(); - vprop->vertex = v; - SoMarkerSet* points = static_cast(pShapeSep->getChild(0)); - points->vertexProperty = vprop; - }*/ + v.setNum(points.size()); + for (int p = 0; p < points.size(); p++) + v.set1Value(p, points[p].x, points[p].y, points[p].z); + SoFaceSet* faceSet = static_cast(pShapeSep->getChild(0)); + + SoVertexProperty* vprop; + if (faceSet->vertexProperty.getValue() == NULL) { + vprop = new SoVertexProperty(); + vprop->vertex = v; + faceSet->vertexProperty = vprop; + } else { + vprop = static_cast(faceSet->vertexProperty.getValue()); + vprop->vertex = v; + } + + SoMFInt32 idx; + idx.setNum(1); + idx.set1Value(0, points.size()); + faceSet->numVertices = idx; + } ViewProviderDatum::updateData(prop); } diff --git a/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp b/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp index 7be6c4c47e..60f2cfd6a2 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include