/*************************************************************************** * Copyright (c) 2015 Stefan Tröger * * * * 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 #endif #include #include #include #include #include #include #include "ViewProviderAddSub.h" using namespace PartDesignGui; PROPERTY_SOURCE(PartDesignGui::ViewProviderAddSub,PartDesignGui::ViewProvider) ViewProviderAddSub::ViewProviderAddSub() { previewShape = new SoSeparator(); previewShape->ref(); previewFaceSet = new PartGui::SoBrepFaceSet(); previewFaceSet->ref(); previewCoords = new SoCoordinate3(); previewCoords->ref(); previewNorm = new SoNormal(); previewNorm->ref(); whichChild = -1; } ViewProviderAddSub::~ViewProviderAddSub() { previewFaceSet->unref(); previewCoords->unref(); previewNorm->unref(); previewShape->unref(); } void ViewProviderAddSub::attach(App::DocumentObject* obj) { ViewProvider::attach(obj); auto* bind = new SoMaterialBinding(); bind->value = SoMaterialBinding::OVERALL; auto* material = new SoMaterial(); if (static_cast(obj)->getAddSubType() == PartDesign::FeatureAddSub::Additive) material->diffuseColor = SbColor(1,1,0); else material->diffuseColor = SbColor(1,0,0); material->transparency = 0.7f; auto* pick = new SoPickStyle(); pick->style = SoPickStyle::UNPICKABLE; previewShape->addChild(pick); previewShape->addChild(bind); previewShape->addChild(material); previewShape->addChild(previewCoords); previewShape->addChild(previewNorm); previewShape->addChild(previewFaceSet); addDisplayMaskMode(previewShape, "Shape preview"); updateAddSubShapeIndicator(); } void ViewProviderAddSub::updateAddSubShapeIndicator() { TopoDS_Shape cShape(getObject()->AddSubShape.getValue()); if (cShape.IsNull()) { previewCoords ->point .setNum(0); previewNorm ->vector .setNum(0); previewFaceSet ->coordIndex .setNum(0); previewFaceSet ->partIndex .setNum(0); return; } try { // calculating the deflection value Bnd_Box bounds; BRepBndLib::Add(cShape, bounds); bounds.SetGap(0.0); Standard_Real xMin, yMin, zMin, xMax, yMax, zMax; 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 Standard_Real AngDeflectionRads = Base::toRadians(AngularDeflection.getValue()); BRepMesh_IncrementalMesh(cShape, 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; cShape.Location(aLoc); // count triangles and nodes in the mesh int numTriangles=0,numNodes=0,numNorms=0,numFaces=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()) { numTriangles += mesh->NbTriangles(); numNodes += mesh->NbNodes(); numNorms += mesh->NbNodes(); } numFaces++; } // create memory for the nodes and indexes previewCoords ->point .setNum(numNodes); previewNorm ->vector .setNum(numNorms); previewFaceSet ->coordIndex .setNum(numTriangles*4); previewFaceSet ->partIndex .setNum(numFaces); // get the raw memory for fast fill up SbVec3f* verts = previewCoords ->point .startEditing(); SbVec3f* previewNorms = previewNorm ->vector .startEditing(); int32_t* index = previewFaceSet ->coordIndex .startEditing(); int32_t* parts = previewFaceSet ->partIndex .startEditing(); // preset the previewNormal vector with null vector for (int i=0;i < numNorms;i++) previewNorms[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++) { const TopoDS_Face &actFace = TopoDS::Face(Ex.Current()); TopLoc_Location loc; Handle(Poly_Triangulation) mesh = BRep_Tool::Triangulation(actFace, loc); if (mesh.IsNull()) continue; // get triangulation std::vector points; std::vector facets; Part::Tools::getTriangulation(actFace, points, facets); // get normal per vertex std::vector vertexnormals; Part::Tools::getPointNormals(actFace, mesh, vertexnormals); Part::Tools::applyTransformationOnNormals(loc, 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++) { previewNorms[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; } parts[ii] = nbTriInFace; // new part // counting up the per Face offsets faceNodeOffset += nbNodesInFace; faceTriaOffset += nbTriInFace; } // previewNormalize all previewNormals for (int i = 0; i< numNorms ;i++) previewNorms[i].normalize(); // end the editing of the nodes previewCoords ->point .finishEditing(); previewNorm ->vector .finishEditing(); previewFaceSet ->coordIndex .finishEditing(); previewFaceSet ->partIndex .finishEditing(); } catch (...) { Base::Console().error("Cannot compute Inventor representation for the shape of %s.\n",pcObject->getNameInDocument()); } } void ViewProviderAddSub::updateData(const App::Property* p) { if(p->getName() && strcmp(p->getName(), "AddSubShape")==0) updateAddSubShapeIndicator(); PartDesignGui::ViewProvider::updateData(p); } void ViewProviderAddSub::setPreviewDisplayMode(bool onoff) { // A mask mode is always set, also for hidden objects. // Now when changing to another mask mode this automatically // displays an object and when restoring the previous state it's // not sufficient to only revert the mask mode. Also the child // number of the switch node must be reverted. if (onoff) { if(pcModeSwitch->getChild(getDefaultMode()) == previewShape) return; displayMode = getActiveDisplayMode(); whichChild = pcModeSwitch->whichChild.getValue(); setDisplayMaskMode("Shape preview"); } if (!onoff) { if(pcModeSwitch->getChild(getDefaultMode()) != previewShape) return; setDisplayMaskMode(displayMode.c_str()); pcModeSwitch->whichChild.setValue(whichChild); } App::DocumentObject* obj = getObject()->BaseFeature.getValue(); if (obj) static_cast(Gui::Application::Instance->getViewProvider(obj))->makeTemporaryVisible(onoff); }