398 lines
17 KiB
C++
398 lines
17 KiB
C++
/******************************************************************************
|
|
* Copyright (c)2012 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 <Bnd_Box.hxx>
|
|
# include <BRep_Tool.hxx>
|
|
# include <BRepBndLib.hxx>
|
|
# include <BRepMesh_IncrementalMesh.hxx>
|
|
# include <Standard_Version.hxx>
|
|
# include <TopExp_Explorer.hxx>
|
|
# include <TopoDS.hxx>
|
|
# include <Poly_Triangulation.hxx>
|
|
# include <Inventor/nodes/SoCoordinate3.h>
|
|
# include <Inventor/nodes/SoDrawStyle.h>
|
|
# include <Inventor/nodes/SoIndexedFaceSet.h>
|
|
# include <Inventor/nodes/SoMaterial.h>
|
|
# include <Inventor/nodes/SoMultipleCopy.h>
|
|
# include <Inventor/nodes/SoNormal.h>
|
|
# include <Inventor/nodes/SoPickStyle.h>
|
|
# include <Inventor/nodes/SoSeparator.h>
|
|
# include <Inventor/nodes/SoShapeHints.h>
|
|
# include <Inventor/nodes/SoTransparencyType.h>
|
|
# include <QAction>
|
|
# include <QMenu>
|
|
# include <QMessageBox>
|
|
#endif
|
|
|
|
#include "ViewProviderTransformed.h"
|
|
#include "TaskTransformedParameters.h"
|
|
#include <Base/Console.h>
|
|
#include <Gui/Control.h>
|
|
#include <Gui/Application.h>
|
|
#include <Mod/Part/App/TopoShape.h>
|
|
#include <Mod/PartDesign/App/FeatureAdditive.h>
|
|
#include <Mod/PartDesign/App/FeatureSubtractive.h>
|
|
#include <Mod/PartDesign/App/FeatureTransformed.h>
|
|
|
|
using namespace PartDesignGui;
|
|
|
|
PROPERTY_SOURCE(PartDesignGui::ViewProviderTransformed,PartDesignGui::ViewProvider)
|
|
|
|
void ViewProviderTransformed::setupContextMenu(QMenu* menu, QObject* receiver, const char* member)
|
|
{
|
|
QAction* act;
|
|
act = menu->addAction(QObject::tr((std::string("Edit ") + featureName + " feature").c_str()), receiver, member);
|
|
act->setData(QVariant((int)ViewProvider::Default));
|
|
PartGui::ViewProviderPart::setupContextMenu(menu, receiver, member);
|
|
}
|
|
|
|
bool ViewProviderTransformed::setEdit(int ModNum)
|
|
{
|
|
pcRejectedRoot = new SoSeparator();
|
|
pcRejectedRoot->ref();
|
|
|
|
rejectedTrfms = new SoMultipleCopy();
|
|
rejectedTrfms->ref();
|
|
|
|
rejectedCoords = new SoCoordinate3();
|
|
rejectedCoords->ref();
|
|
|
|
rejectedNorms = new SoNormal();
|
|
rejectedNorms->ref();
|
|
|
|
rejectedFaceSet = new SoIndexedFaceSet();
|
|
rejectedFaceSet->ref();
|
|
|
|
SoPickStyle* rejectedPickStyle = new SoPickStyle();
|
|
rejectedPickStyle->style = SoPickStyle::UNPICKABLE;
|
|
|
|
SoShapeHints* rejectedHints = new SoShapeHints();
|
|
rejectedHints->vertexOrdering = SoShapeHints::COUNTERCLOCKWISE;
|
|
rejectedHints->shapeType = SoShapeHints::UNKNOWN_SHAPE_TYPE;
|
|
|
|
SoMaterialBinding* rejectedBind = new SoMaterialBinding();
|
|
|
|
SoTransparencyType* rejectedTransparencyType = new SoTransparencyType();
|
|
rejectedTransparencyType->value.setValue(SoGLRenderAction::BLEND);
|
|
|
|
SoMaterial* rejectedMaterial = new SoMaterial();
|
|
rejectedMaterial->diffuseColor.set1Value(0,SbColor(1.f,0.f,0.f));
|
|
rejectedMaterial->transparency.setValue(0.6f);
|
|
|
|
SoDrawStyle* rejectedFaceStyle = new SoDrawStyle();
|
|
rejectedFaceStyle->style = SoDrawStyle::FILLED;
|
|
|
|
SoNormalBinding* rejectedNormb = new SoNormalBinding();
|
|
rejectedNormb->value = SoNormalBinding::PER_VERTEX_INDEXED;
|
|
|
|
// just faces with no edges or points
|
|
pcRejectedRoot->addChild(rejectedPickStyle);
|
|
pcRejectedRoot->addChild(rejectedTransparencyType);
|
|
pcRejectedRoot->addChild(rejectedBind);
|
|
pcRejectedRoot->addChild(rejectedMaterial);
|
|
pcRejectedRoot->addChild(rejectedHints);
|
|
pcRejectedRoot->addChild(rejectedFaceStyle);
|
|
pcRejectedRoot->addChild(rejectedCoords);
|
|
pcRejectedRoot->addChild(rejectedNorms);
|
|
pcRejectedRoot->addChild(rejectedNormb);
|
|
pcRejectedRoot->addChild(rejectedTrfms);
|
|
rejectedTrfms->addChild(rejectedFaceSet);
|
|
|
|
pcRoot->addChild(pcRejectedRoot);
|
|
|
|
recomputeFeature();
|
|
return true;
|
|
}
|
|
|
|
void ViewProviderTransformed::unsetEdit(int ModNum)
|
|
{
|
|
if (ModNum == ViewProvider::Default) {
|
|
// when pressing ESC make sure to close the dialog
|
|
Gui::Control().closeDialog();
|
|
}
|
|
else {
|
|
PartGui::ViewProviderPart::unsetEdit(ModNum);
|
|
}
|
|
|
|
rejectedTrfms->removeAllChildren();
|
|
pcRejectedRoot->removeAllChildren();
|
|
|
|
pcRoot->removeChild(pcRejectedRoot);
|
|
|
|
pcRejectedRoot->unref();
|
|
rejectedTrfms->unref();
|
|
rejectedCoords->unref();
|
|
rejectedNorms->unref();
|
|
rejectedFaceSet->unref();
|
|
}
|
|
|
|
bool ViewProviderTransformed::onDelete(const std::vector<std::string> &)
|
|
{
|
|
PartDesign::Transformed* pcTransformed = static_cast<PartDesign::Transformed*>(getObject());
|
|
std::vector<App::DocumentObject*> originals = pcTransformed->Originals.getValues();
|
|
|
|
// if abort command deleted the object the originals are visible again
|
|
for (std::vector<App::DocumentObject*>::const_iterator it = originals.begin(); it != originals.end(); ++it)
|
|
{
|
|
if (((*it) != NULL) && Gui::Application::Instance->getViewProvider(*it))
|
|
Gui::Application::Instance->getViewProvider(*it)->show();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
const bool ViewProviderTransformed::checkDlgOpen(TaskDlgTransformedParameters* transformedDlg) {
|
|
// When double-clicking on the item for this feature the
|
|
// object unsets and sets its edit mode without closing
|
|
// the task panel
|
|
Gui::TaskView::TaskDialog *dlg = Gui::Control().activeDialog();
|
|
transformedDlg = qobject_cast<TaskDlgTransformedParameters *>(dlg);
|
|
|
|
if ((transformedDlg != NULL) && (transformedDlg->getTransformedView() != this))
|
|
transformedDlg = NULL; // another transformed feature left open its task panel
|
|
|
|
if ((dlg != NULL) && (transformedDlg == NULL)) {
|
|
QMessageBox msgBox;
|
|
msgBox.setText(QObject::tr("A dialog is already open in the task panel"));
|
|
msgBox.setInformativeText(QObject::tr("Do you want to close this dialog?"));
|
|
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
|
msgBox.setDefaultButton(QMessageBox::Yes);
|
|
int ret = msgBox.exec();
|
|
if (ret == QMessageBox::Yes)
|
|
Gui::Control().reject();
|
|
else
|
|
return false;
|
|
}
|
|
|
|
// clear the selection (convenience)
|
|
Gui::Selection().clearSelection();
|
|
|
|
// Continue (usually in virtual method setEdit())
|
|
return true;
|
|
}
|
|
|
|
void ViewProviderTransformed::recomputeFeature(void)
|
|
{
|
|
PartDesign::Transformed* pcTransformed = static_cast<PartDesign::Transformed*>(getObject());
|
|
pcTransformed->getDocument()->recomputeFeature(pcTransformed);
|
|
const std::vector<App::DocumentObjectExecReturn*> log = pcTransformed->getDocument()->getRecomputeLog();
|
|
unsigned rejected = pcTransformed->getRejectedTransformations().size();
|
|
QString msg = QString::fromLatin1("%1");
|
|
if (rejected > 0) {
|
|
msg = QString::fromLatin1("<font color='orange'>%1<br/></font>\r\n%2");
|
|
if (rejected == 1)
|
|
msg = msg.arg(QObject::tr("One transformed shape does not intersect support"));
|
|
else {
|
|
msg = msg.arg(QObject::tr("%1 transformed shapes do not intersect support"));
|
|
msg = msg.arg(rejected);
|
|
}
|
|
}
|
|
if (log.size() > 0) {
|
|
msg = msg.arg(QString::fromLatin1("<font color='red'>%1<br/></font>"));
|
|
msg = msg.arg(QString::fromStdString(log.back()->Why));
|
|
} else {
|
|
msg = msg.arg(QString::fromLatin1("<font color='green'>%1<br/></font>"));
|
|
msg = msg.arg(QObject::tr("Transformation succeeded"));
|
|
}
|
|
signalDiagnosis(msg);
|
|
|
|
TopoDS_Shape shape;
|
|
if (rejected != 0) {
|
|
// FIXME: create a compound if there are more than one originals
|
|
App::DocumentObject* original = pcTransformed->Originals.getValues().front();
|
|
if (original->getTypeId().isDerivedFrom(PartDesign::Additive::getClassTypeId())) {
|
|
PartDesign::Additive* addFeature = static_cast<PartDesign::Additive*>(original);
|
|
shape = addFeature->AddShape.getShape()._Shape;
|
|
} else if (original->getTypeId().isDerivedFrom(PartDesign::Subtractive::getClassTypeId())) {
|
|
PartDesign::Subtractive* subFeature = static_cast<PartDesign::Subtractive*>(original);
|
|
shape = subFeature->SubShape.getShape()._Shape;
|
|
}
|
|
}
|
|
|
|
if (rejected == 0 || shape.IsNull()) {
|
|
rejectedCoords ->point .setNum(0);
|
|
rejectedNorms ->vector .setNum(0);
|
|
rejectedFaceSet ->coordIndex .setNum(0);
|
|
rejectedTrfms ->matrix .setNum(0);
|
|
} else {
|
|
// Display the rejected transformations in red
|
|
TopoDS_Shape cShape(shape);
|
|
|
|
try {
|
|
// calculating the deflection value
|
|
Standard_Real xMin, yMin, zMin, xMax, yMax, zMax;
|
|
{
|
|
Bnd_Box bounds;
|
|
BRepBndLib::Add(cShape, bounds);
|
|
bounds.SetGap(0.0);
|
|
bounds.Get(xMin, yMin, zMin, xMax, yMax, zMax);
|
|
}
|
|
Standard_Real deflection = ((xMax-xMin)+(yMax-yMin)+(zMax-zMin))/300.0 * Deviation.getValue();
|
|
|
|
// create or use the mesh on the data structure
|
|
#if OCC_VERSION_HEX >= 0x060600
|
|
Standard_Real AngDeflectionRads = AngularDeflection.getValue() / 180.0 * M_PI;
|
|
BRepMesh_IncrementalMesh(cShape,deflection,Standard_False,
|
|
AngDeflectionRads,Standard_True);
|
|
#else
|
|
BRepMesh_IncrementalMesh(cShape,deflection);
|
|
#endif
|
|
// We must reset the location here because the transformation data
|
|
// are set in the placement property
|
|
TopLoc_Location aLoc;
|
|
cShape.Location(aLoc);
|
|
|
|
// count triangles and nodes in the mesh
|
|
int nbrTriangles=0, nbrNodes=0;
|
|
TopExp_Explorer Ex;
|
|
for (Ex.Init(cShape,TopAbs_FACE);Ex.More();Ex.Next()) {
|
|
Handle (Poly_Triangulation) mesh = BRep_Tool::Triangulation(TopoDS::Face(Ex.Current()), aLoc);
|
|
// Note: we must also count empty faces
|
|
if (!mesh.IsNull()) {
|
|
nbrTriangles += mesh->NbTriangles();
|
|
nbrNodes += mesh->NbNodes();
|
|
}
|
|
}
|
|
|
|
// create memory for the nodes and indexes
|
|
rejectedCoords ->point .setNum(nbrNodes);
|
|
rejectedNorms ->vector .setNum(nbrNodes);
|
|
rejectedFaceSet ->coordIndex .setNum(nbrTriangles*4);
|
|
|
|
// get the raw memory for fast fill up
|
|
SbVec3f* verts = rejectedCoords ->point .startEditing();
|
|
SbVec3f* norms = rejectedNorms ->vector .startEditing();
|
|
int32_t* index = rejectedFaceSet ->coordIndex .startEditing();
|
|
|
|
// preset the normal vector with null vector
|
|
for (int i=0; i < nbrNodes; i++)
|
|
norms[i]= SbVec3f(0.0,0.0,0.0);
|
|
|
|
int ii = 0,FaceNodeOffset=0,FaceTriaOffset=0;
|
|
for (Ex.Init(cShape, TopAbs_FACE); Ex.More(); Ex.Next(),ii++) {
|
|
TopLoc_Location aLoc;
|
|
const TopoDS_Face &actFace = TopoDS::Face(Ex.Current());
|
|
// get the mesh of the shape
|
|
Handle (Poly_Triangulation) mesh = BRep_Tool::Triangulation(actFace,aLoc);
|
|
if (mesh.IsNull()) continue;
|
|
|
|
// getting the transformation of the shape/face
|
|
gp_Trsf myTransf;
|
|
Standard_Boolean identity = true;
|
|
if (!aLoc.IsIdentity()) {
|
|
identity = false;
|
|
myTransf = aLoc.Transformation();
|
|
}
|
|
|
|
// getting size of node and triangle array of this face
|
|
int nbNodesInFace = mesh->NbNodes();
|
|
int nbTriInFace = mesh->NbTriangles();
|
|
// check orientation
|
|
TopAbs_Orientation orient = actFace.Orientation();
|
|
|
|
// cycling through the poly mesh
|
|
const Poly_Array1OfTriangle& Triangles = mesh->Triangles();
|
|
const TColgp_Array1OfPnt& Nodes = mesh->Nodes();
|
|
for (int g=1; g <= nbTriInFace; g++) {
|
|
// Get the triangle
|
|
Standard_Integer N1,N2,N3;
|
|
Triangles(g).Get(N1,N2,N3);
|
|
|
|
// change orientation of the triangle if the face is reversed
|
|
if ( orient != TopAbs_FORWARD ) {
|
|
Standard_Integer tmp = N1;
|
|
N1 = N2;
|
|
N2 = tmp;
|
|
}
|
|
|
|
// get the 3 points of this triangle
|
|
gp_Pnt V1(Nodes(N1)), V2(Nodes(N2)), V3(Nodes(N3));
|
|
|
|
// transform the vertices to the place of the face
|
|
if (!identity) {
|
|
V1.Transform(myTransf);
|
|
V2.Transform(myTransf);
|
|
V3.Transform(myTransf);
|
|
}
|
|
|
|
// calculating per vertex normals
|
|
// Calculate triangle normal
|
|
gp_Vec v1(V1.X(),V1.Y(),V1.Z()),v2(V2.X(),V2.Y(),V2.Z()),v3(V3.X(),V3.Y(),V3.Z());
|
|
gp_Vec Normal = (v2-v1)^(v3-v1);
|
|
|
|
// add the triangle normal to the vertex normal for all points of this triangle
|
|
norms[FaceNodeOffset+N1-1] += SbVec3f(Normal.X(),Normal.Y(),Normal.Z());
|
|
norms[FaceNodeOffset+N2-1] += SbVec3f(Normal.X(),Normal.Y(),Normal.Z());
|
|
norms[FaceNodeOffset+N3-1] += SbVec3f(Normal.X(),Normal.Y(),Normal.Z());
|
|
|
|
// set the vertices
|
|
verts[FaceNodeOffset+N1-1].setValue((float)(V1.X()),(float)(V1.Y()),(float)(V1.Z()));
|
|
verts[FaceNodeOffset+N2-1].setValue((float)(V2.X()),(float)(V2.Y()),(float)(V2.Z()));
|
|
verts[FaceNodeOffset+N3-1].setValue((float)(V3.X()),(float)(V3.Y()),(float)(V3.Z()));
|
|
|
|
// set the index vector with the 3 point indexes and the end delimiter
|
|
index[FaceTriaOffset*4+4*(g-1)] = FaceNodeOffset+N1-1;
|
|
index[FaceTriaOffset*4+4*(g-1)+1] = FaceNodeOffset+N2-1;
|
|
index[FaceTriaOffset*4+4*(g-1)+2] = FaceNodeOffset+N3-1;
|
|
index[FaceTriaOffset*4+4*(g-1)+3] = SO_END_FACE_INDEX;
|
|
}
|
|
|
|
// counting up the per Face offsets
|
|
FaceNodeOffset += nbNodesInFace;
|
|
FaceTriaOffset += nbTriInFace;
|
|
}
|
|
|
|
// normalize all normals
|
|
for (int i=0; i < nbrNodes; i++)
|
|
norms[i].normalize();
|
|
|
|
// end the editing of the nodes
|
|
rejectedCoords ->point .finishEditing();
|
|
rejectedNorms ->vector .finishEditing();
|
|
rejectedFaceSet ->coordIndex .finishEditing();
|
|
|
|
// fill in the transformation matrices
|
|
rejectedTrfms->matrix.setNum(rejected);
|
|
SbMatrix* mats = rejectedTrfms->matrix.startEditing();
|
|
|
|
std::list<gp_Trsf> rejected_trsf = pcTransformed->getRejectedTransformations();
|
|
std::list<gp_Trsf>::const_iterator trsf = rejected_trsf.begin();
|
|
for (unsigned int i=0; i < rejected; i++,trsf++) {
|
|
Base::Matrix4D mat;
|
|
Part::TopoShape::convertToMatrix(*trsf,mat);
|
|
mats[i] = convert(mat);
|
|
}
|
|
rejectedTrfms->matrix.finishEditing();
|
|
}
|
|
catch (...) {
|
|
Base::Console().Error("Cannot compute Inventor representation for the rejected transformations of shape of %s.\n",
|
|
pcTransformed->getNameInDocument());
|
|
}
|
|
}
|
|
|
|
}
|
|
|