FreeCAD/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp

225 lines
9.1 KiB
C++

/***************************************************************************
* Copyright (c) 2013 Jan Rheinlaender <jrheinlaender@users.sourceforge.net> *
* *
* 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 <Inventor/nodes/SoSeparator.h>
# include <Inventor/nodes/SoPickStyle.h>
# include <Inventor/nodes/SoShapeHints.h>
# include <Inventor/nodes/SoMaterial.h>
# include <Inventor/nodes/SoBaseColor.h>
# include <Inventor/nodes/SoMarkerSet.h>
# include <Inventor/nodes/SoVertexProperty.h>
# include <Inventor/nodes/SoLineSet.h>
# include <Inventor/nodes/SoFaceSet.h>
# include <Inventor/details/SoLineDetail.h>
# include <Inventor/details/SoFaceDetail.h>
# include <Inventor/details/SoPointDetail.h>
# include <TopoDS_Vertex.hxx>
# include <TopoDS.hxx>
# include <BRep_Tool.hxx>
# include <gp_Pnt.hxx>
# include <Precision.hxx>
# include <Geom_Plane.hxx>
# include <Geom_Line.hxx>
# include <GeomAPI_IntCS.hxx>
#endif
#include "ViewProviderDatumPlane.h"
#include "TaskDatumParameters.h"
#include "Workbench.h"
#include <Mod/PartDesign/App/DatumPlane.h>
#include <Gui/Control.h>
#include <Gui/Command.h>
#include <Gui/Application.h>
#include <Mod/PartDesign/App/Body.h>
using namespace PartDesignGui;
PROPERTY_SOURCE(PartDesignGui::ViewProviderDatumPlane,PartDesignGui::ViewProviderDatum)
ViewProviderDatumPlane::ViewProviderDatumPlane()
{
SoMaterial* material = new SoMaterial();
material->diffuseColor.setValue(0.9f, 0.9f, 0.13);
material->transparency.setValue(0.2);
pShapeSep->addChild(material);
}
ViewProviderDatumPlane::~ViewProviderDatumPlane()
{
}
void ViewProviderDatumPlane::updateData(const App::Property* prop)
{
// Gets called whenever a property of the attached object changes
PartDesign::Plane* pcDatum = static_cast<PartDesign::Plane*>(this->getObject());
if (strcmp(prop->getName(),"Placement") == 0) {
Base::Placement plm = pcDatum->Placement.getValue();
plm.invert();
Base::Vector3d base(0,0,0);
Base::Vector3d normal(0,0,1);
// Get limits of the plane from bounding box of the body
PartDesign::Body* body = static_cast<PartDesign::Body*>(Part::BodyBase::findBodyOf(this->getObject()));
if (body == NULL)
return;
Base::BoundBox3d bbox = body->getBoundBox();
bbox = bbox.Transformed(plm.toMatrix());
double dlength = bbox.CalcDiagonalLength();
bbox.Enlarge(0.1 * dlength);
// 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<Base::Vector3d> points;
for (int i = 0; i < 12; i++) {
// Get the edge of the bounding box
Base::Vector3d p1, p2;
bbox.CalcEdge(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<Base::Vector3d>::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<Base::Vector3d>::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.setNum(points.size());
for (int p = 0; p < points.size(); p++)
v.set1Value(p, points[p].x, points[p].y, points[p].z);
SoMFInt32 idx;
idx.setNum(1);
idx.set1Value(0, points.size());
SoFaceSet* faceSet;
SoLineSet* lineSet;
SoVertexProperty* vprop;
if (pShapeSep->getNumChildren() == 1) {
faceSet = new SoFaceSet();
vprop = new SoVertexProperty();
vprop->vertex = v;
faceSet->vertexProperty = vprop;
faceSet->numVertices = idx;
pShapeSep->addChild(faceSet);
lineSet = new SoLineSet();
lineSet->vertexProperty = vprop;
lineSet->numVertices = idx;
pShapeSep->addChild(lineSet);
} else {
faceSet = static_cast<SoFaceSet*>(pShapeSep->getChild(1));
vprop = static_cast<SoVertexProperty*>(faceSet->vertexProperty.getValue());
vprop->vertex = v;
faceSet->numVertices = idx;
lineSet = static_cast<SoLineSet*>(pShapeSep->getChild(2));
vprop = static_cast<SoVertexProperty*>(lineSet->vertexProperty.getValue());
vprop->vertex = v;
lineSet->numVertices = idx;
}
}
ViewProviderDatum::updateData(prop);
}