/****************************************************************************** * Copyright (c) 2012 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 #endif #include #include #include #include #include #include "ViewProviderTransformed.h" #include "TaskTransformedParameters.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("Edit %1").arg(QString::fromStdString(featureName)), receiver, member); act->setData(QVariant((int)ViewProvider::Default)); PartDesignGui::ViewProvider::setupContextMenu(menu, receiver, member); } Gui::ViewProvider *ViewProviderTransformed::startEditing(int ModNum) { PartDesign::Transformed* pcTransformed = static_cast(getObject()); if(!pcTransformed->Originals.getSize()) { for(auto obj : pcTransformed->getInList()) { if(obj->isDerivedFrom(PartDesign::MultiTransform::getClassTypeId())) { auto vp = Gui::Application::Instance->getViewProvider(obj); if(vp) return vp->startEditing(ModNum); return nullptr; } } } return ViewProvider::startEditing(ModNum); } bool ViewProviderTransformed::setEdit(int ModNum) { pcRejectedRoot = new SoSeparator(); pcRejectedRoot->ref(); SoPickStyle* rejectedPickStyle = new SoPickStyle(); rejectedPickStyle->style = SoPickStyle::UNPICKABLE; SoShapeHints* rejectedHints = new SoShapeHints(); rejectedHints->vertexOrdering = SoShapeHints::UNKNOWN_ORDERING; 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(rejectedNormb); // NOTE: The code relies on the last child added here being index 6 pcRoot->addChild(pcRejectedRoot); recomputeFeature(false); return ViewProvider::setEdit(ModNum); } void ViewProviderTransformed::unsetEdit(int ModNum) { ViewProvider::unsetEdit(ModNum); while (pcRejectedRoot->getNumChildren() > 7) { SoSeparator* sep = static_cast(pcRejectedRoot->getChild(7)); SoMultipleCopy* rejectedTrfms = static_cast(sep->getChild(2)); Gui::coinRemoveAllChildren(rejectedTrfms); sep->removeChild(1); sep->removeChild(0); pcRejectedRoot ->removeChild(7); } Gui::coinRemoveAllChildren(pcRejectedRoot); pcRoot->removeChild(pcRejectedRoot); pcRejectedRoot->unref(); } bool ViewProviderTransformed::onDelete(const std::vector &s) { return ViewProvider::onDelete(s); } void ViewProviderTransformed::recomputeFeature(bool recompute) { PartDesign::Transformed* pcTransformed = static_cast(getObject()); if(recompute || (pcTransformed->isError() || pcTransformed->mustExecute())) pcTransformed->recomputeFeature(true); unsigned rejected = 0; TopoDS_Shape cShape = pcTransformed->rejected; TopExp_Explorer xp; xp.Init(cShape, TopAbs_SOLID); for (; xp.More(); xp.Next()) { rejected++; } QString msg = QString::fromLatin1("%1"); if (rejected > 0) { msg = QString::fromLatin1("%1
\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); } } auto error = pcTransformed->getDocument()->getErrorDescription(pcTransformed); if (error) { msg = msg.arg(QString::fromLatin1("%1
")); msg = msg.arg(QString::fromUtf8(error)); } else { msg = msg.arg(QString::fromLatin1("%1
")); msg = msg.arg(QObject::tr("Transformation succeeded")); } diagMessage = msg; signalDiagnosis(msg); // Clear all the rejected stuff while (pcRejectedRoot->getNumChildren() > 7) { SoSeparator* sep = static_cast(pcRejectedRoot->getChild(7)); SoMultipleCopy* rejectedTrfms = static_cast(sep->getChild(2)); Gui::coinRemoveAllChildren(rejectedTrfms); sep->removeChild(1); sep->removeChild(0); pcRejectedRoot ->removeChild(7); } // Display the rejected transformations in red if (rejected > 0) { showRejectedShape(cShape); } } void ViewProviderTransformed::showRejectedShape(TopoDS_Shape shape) { try { // calculating the deflection value Standard_Real xMin, yMin, zMin, xMax, yMax, zMax; { Bnd_Box bounds; BRepBndLib::Add(shape, 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 // Note: This DOES have an effect on shape Standard_Real AngDeflectionRads = AngularDeflection.getValue() / 180.0 * M_PI; BRepMesh_IncrementalMesh(shape, deflection, Standard_False, AngDeflectionRads, Standard_True); // We must reset the location here because the transformation data // are set in the placement property TopLoc_Location aLoc; shape.Location(aLoc); // count triangles and nodes in the mesh int nbrTriangles=0, nbrNodes=0; TopExp_Explorer Ex; for (Ex.Init(shape, 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 SoCoordinate3* rejectedCoords = new SoCoordinate3(); rejectedCoords ->point .setNum(nbrNodes); SoNormal* rejectedNorms = new SoNormal(); rejectedNorms ->vector .setNum(nbrNodes); SoIndexedFaceSet* rejectedFaceSet = new SoIndexedFaceSet(); 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 FaceNodeOffset=0,FaceTriaOffset=0; for (Ex.Init(shape, TopAbs_FACE); Ex.More(); Ex.Next()) { const TopoDS_Face &actFace = TopoDS::Face(Ex.Current()); // get triangulation std::vector points; std::vector facets; if (!Part::Tools::getTriangulation(actFace, points, facets)) continue; // get normal per vertex std::vector vertexnormals; Part::Tools::getPointNormals(points, facets, vertexnormals); // getting size of node and triangle array of this face std::size_t nbNodesInFace = points.size(); std::size_t nbTriInFace = facets.size(); for (std::size_t i = 0; i < points.size(); i++) { verts[FaceNodeOffset+i] = SbVec3f(points[i].X(), points[i].Y(), points[i].Z()); } for (std::size_t i = 0; i < vertexnormals.size(); i++) { norms[FaceNodeOffset+i] = SbVec3f(vertexnormals[i].X(), vertexnormals[i].Y(), vertexnormals[i].Z()); } // cycling through the poly mesh for (std::size_t g=0; g < nbTriInFace; g++) { // Get the triangle Standard_Integer N1,N2,N3; facets[g].Get(N1,N2,N3); // set the index vector with the 3 point indexes and the end delimiter index[FaceTriaOffset*4+4*g] = FaceNodeOffset+N1; index[FaceTriaOffset*4+4*g+1] = FaceNodeOffset+N2; index[FaceTriaOffset*4+4*g+2] = FaceNodeOffset+N3; index[FaceTriaOffset*4+4*g+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 SoMultipleCopy* rejectedTrfms = new SoMultipleCopy(); rejectedTrfms->matrix.finishEditing(); rejectedTrfms->addChild(rejectedFaceSet); SoSeparator* sep = new SoSeparator(); sep->addChild(rejectedCoords); sep->addChild(rejectedNorms); sep->addChild(rejectedTrfms); pcRejectedRoot->addChild(sep); } } catch (...) { Base::Console().Error("Cannot compute Inventor representation for the rejected transformations of shape of %s.\n", getObject()->getNameInDocument()); } }