/*************************************************************************** * Copyright (c) 2006 Werner Mayer * * * * 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 #endif /// Here the FreeCAD includes sorted by Base,App,Gui...... #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 "ViewProvider.h" #include "ViewProviderMeshNode.h" using namespace MeshGui; App::PropertyFloatConstraint::Constraints ViewProviderMeshNode::floatRange = {1.0f,64.0f,1.0f}; PROPERTY_SOURCE(MeshGui::ViewProviderMeshNode, Gui::ViewProviderGeometryObject) ViewProviderMeshNode::ViewProviderMeshNode() : pcOpenEdge(0), m_bEdit(false) { ADD_PROPERTY(LineWidth,(2.0f)); LineWidth.setConstraints(&floatRange); ADD_PROPERTY(PointSize,(2.0f)); PointSize.setConstraints(&floatRange); ADD_PROPERTY(OpenEdges,(false)); pOpenColor = new SoBaseColor(); setOpenEdgeColorFrom(ShapeColor.getValue()); pOpenColor->ref(); pcLineStyle = new SoDrawStyle(); pcLineStyle->ref(); pcLineStyle->style = SoDrawStyle::LINES; pcLineStyle->lineWidth = LineWidth.getValue(); pcPointStyle = new SoDrawStyle(); pcPointStyle->ref(); pcPointStyle->style = SoDrawStyle::POINTS; pcPointStyle->pointSize = PointSize.getValue(); // read the correct shape color from the preferences Base::Reference hGrp = Gui::WindowParameter::getDefaultParameter()->GetGroup("Mod/Mesh"); App::Color color = ShapeColor.getValue(); unsigned long current = color.getPackedValue(); unsigned long setting = hGrp->GetUnsigned("MeshColor", current); if ( current != setting ) { color.setPackedValue((uint32_t)setting); ShapeColor.setValue(color); } } ViewProviderMeshNode::~ViewProviderMeshNode() { pOpenColor->unref(); pcLineStyle->unref(); pcPointStyle->unref(); } void ViewProviderMeshNode::onChanged(const App::Property* prop) { if ( prop == &LineWidth ) { pcLineStyle->lineWidth = LineWidth.getValue(); } else if ( prop == &PointSize ) { pcPointStyle->pointSize = PointSize.getValue(); } else if ( prop == &OpenEdges ) { showOpenEdges( OpenEdges.getValue() ); } else { // Set the inverse color for open edges if ( prop == &ShapeColor ) { setOpenEdgeColorFrom(ShapeColor.getValue()); } else if ( prop == &ShapeMaterial ) { setOpenEdgeColorFrom(ShapeMaterial.getValue().diffuseColor); } ViewProviderGeometryObject::onChanged(prop); } } void ViewProviderMeshNode::setOpenEdgeColorFrom( const App::Color& c ) { float r=1.0f-c.r; r = r < 0.5f ? 0.0f : 1.0f; float g=1.0f-c.g; g = g < 0.5f ? 0.0f : 1.0f; float b=1.0f-c.b; b = b < 0.5f ? 0.0f : 1.0f; pOpenColor->rgb.setValue(r, g, b); } void ViewProviderMeshNode::attach(App::DocumentObject *pcFeat) { ViewProviderGeometryObject::attach(pcFeat); // only one selection node for the mesh const Mesh::Feature* meshFeature = dynamic_cast(pcFeat); MeshGui::SoFCMeshNode* mesh = new MeshGui::SoFCMeshNode(); mesh->setMesh(meshFeature->Mesh.getValuePtr()); pcHighlight->addChild(mesh); // faces SoGroup* pcFlatRoot = new SoGroup(); // read the correct shape color from the preferences Base::Reference hGrp = Gui::WindowParameter::getDefaultParameter()->GetGroup("Mod/Mesh"); bool twoSide = hGrp->GetBool("TwoSideRendering", true); if ( twoSide ) { // enable two-side rendering SoShapeHints * flathints = new SoShapeHints; flathints->vertexOrdering = SoShapeHints::COUNTERCLOCKWISE; flathints->shapeType = SoShapeHints::UNKNOWN_SHAPE_TYPE; pcFlatRoot->addChild(flathints); } pcFlatRoot->addChild(pcShapeMaterial); pcFlatRoot->addChild(pcHighlight); addDisplayMaskMode(pcFlatRoot, "Flat"); // points SoGroup* pcPointRoot = new SoGroup(); pcPointRoot->addChild(pcPointStyle); pcPointRoot->addChild(pcFlatRoot); addDisplayMaskMode(pcPointRoot, "Point"); // wires SoLightModel* pcLightModel = new SoLightModel(); pcLightModel->model = SoLightModel::BASE_COLOR; SoGroup* pcWireRoot = new SoGroup(); pcWireRoot->addChild(pcLineStyle); pcWireRoot->addChild(pcLightModel); pcWireRoot->addChild(pcShapeMaterial); pcWireRoot->addChild(pcHighlight); addDisplayMaskMode(pcWireRoot, "Wireframe"); // faces+wires SoGroup* pcFlatWireRoot = new SoGroup(); pcFlatWireRoot->addChild(pcFlatRoot); pcFlatWireRoot->addChild(pcWireRoot); addDisplayMaskMode(pcFlatWireRoot, "FlatWireframe"); } void ViewProviderMeshNode::updateData(const App::Property*) { // Needs to update internal bounding box caches pcHighlight->touch(); } QIcon ViewProviderMeshNode::getIcon() const { const char * Mesh_Feature_xpm[] = { "16 16 4 1", ". c None", "# c #000000", "s c #BEC2FC", "g c #00FF00", ".......##.......", "....#######.....", "..##ggg#ggg#....", "##ggggg#gggg##..", "#g#ggg#gggggg##.", "#gg#gg#gggg###s.", "#gg#gg#gg##gg#s.", "#ggg#####ggg#ss.", "#gggg##gggg#ss..", ".#g##g#gggg#s...", ".##ggg#ggg#ss...", ".##gggg#g#ss....", "..s#####g#s.....", "....sss##ss.....", "........ss......", "................"}; QPixmap px(Mesh_Feature_xpm); return px; } void ViewProviderMeshNode::setDisplayMode(const char* ModeName) { if ( strcmp("Shaded",ModeName)==0 ) setDisplayMaskMode("Flat"); else if ( strcmp("Points",ModeName)==0 ) setDisplayMaskMode("Point"); else if ( strcmp("Shaded+Wireframe",ModeName)==0 ) setDisplayMaskMode("FlatWireframe"); else if ( strcmp("Wireframe",ModeName)==0 ) setDisplayMaskMode("Wireframe"); ViewProviderGeometryObject::setDisplayMode( ModeName ); } std::vector ViewProviderMeshNode::getDisplayModes(void) const { std::vector StrList; // add your own modes StrList.push_back("Shaded"); StrList.push_back("Wireframe"); StrList.push_back("Shaded+Wireframe"); StrList.push_back("Points"); return StrList; } bool ViewProviderMeshNode::setEdit(int ModNum) { if ( m_bEdit ) return true; m_bEdit = true; return true; } void ViewProviderMeshNode::unsetEdit(void) { m_bEdit = false; } const char* ViewProviderMeshNode::getEditModeName(void) { return "Polygon picking"; } bool ViewProviderMeshNode::handleEvent(const SoEvent * const ev,Gui::View3DInventorViewer &Viewer) { if ( m_bEdit ) { unsetEdit(); std::vector clPoly = Viewer.getPickedPolygon(); if ( clPoly.size() < 3 ) return true; if ( clPoly.front() != clPoly.back() ) clPoly.push_back(clPoly.front()); // get the normal of the front clipping plane SbVec3f b,n; Viewer.getNearPlane(b, n); Base::Vector3f cPoint(b[0],b[1],b[2]), cNormal(n[0],n[1],n[2]); SoCamera* pCam = Viewer.getCamera(); SbViewVolume vol = pCam->getViewVolume (); // create a tool shape from these points std::vector aFaces; bool ok = ViewProviderMesh::createToolMesh( clPoly, vol, cNormal, aFaces ); // Get the attached mesh property Mesh::PropertyMeshKernel& meshProp = ((Mesh::Feature*)pcObject)->Mesh; // Get the facet indices inside the tool mesh std::vector indices; MeshCore::MeshKernel cToolMesh; cToolMesh = aFaces; MeshCore::MeshFacetGrid cGrid(meshProp.getValue().getKernel()); MeshCore::MeshAlgorithm cAlg(meshProp.getValue().getKernel()); cAlg.GetFacetsFromToolMesh(cToolMesh, cNormal, cGrid, indices); meshProp.deleteFacetIndices( indices ); // update open edge display if needed // if ( pcOpenEdge ) // { // showOpenEdges(false); // showOpenEdges(true); // } Viewer.render(); if ( !ok ) // note: the mouse grabbing needs to be released //QMessageBox::warning(Viewer.getWidget(),"Invalid polygon","The picked polygon seems to have self-overlappings.\n\nThis could lead to strange rersults."); Base::Console().Message("The picked polygon seems to have self-overlappings. This could lead to strange results."); } return false; } void ViewProviderMeshNode::showOpenEdges(bool show) { #if 1 if ( show ) { pcOpenEdge = new SoSeparator(); pcOpenEdge->addChild(pcLineStyle); pcOpenEdge->addChild(pOpenColor); const Mesh::Feature* meshFeature = dynamic_cast(pcObject); MeshGui::SoFCMeshOpenEdge* mesh = new MeshGui::SoFCMeshOpenEdge(); mesh->setMesh(meshFeature->Mesh.getValuePtr()); pcOpenEdge->addChild(mesh); // add to the highlight node pcHighlight->addChild(pcOpenEdge); } else if (pcOpenEdge) { // remove the node and destroy the data pcHighlight->removeChild(pcOpenEdge); pcOpenEdge = 0; } #else if ( show ) { pcOpenEdge = new SoSeparator(); pcOpenEdge->addChild(pcLineStyle); pcOpenEdge->addChild(pOpenColor); SoCoordinate3* points = new SoCoordinate3(); pcOpenEdge->addChild(points); SoLineSet* lines = new SoLineSet(); pcOpenEdge->addChild(lines); // add to the highlight node pcHighlight->addChild(pcOpenEdge); // Build up the array of border points int index=0; const MeshCore::MeshKernel& rMesh = dynamic_cast(pcObject)->getMesh(); const MeshCore::MeshFacetArray& rFaces = rMesh.GetFacets(); const MeshCore::MeshPointArray& rPoint = rMesh.GetPoints(); // Count number of open edges first int ctEdges=0; for ( MeshCore::MeshFacetArray::_TConstIterator jt = rFaces.begin(); jt != rFaces.end(); ++jt ) { for ( int i=0; i<3; i++ ) { if ( jt->_aulNeighbours[i] == ULONG_MAX ) { ctEdges++; } } } // disable internal notification for speedup points->enableNotify(false); lines->enableNotify(false); points->point.setNum(2*ctEdges); lines->numVertices.setNum(ctEdges); for ( MeshCore::MeshFacetArray::_TConstIterator it = rFaces.begin(); it != rFaces.end(); ++it ) { for ( int i=0; i<3; i++ ) { if ( it->_aulNeighbours[i] == ULONG_MAX ) { const MeshCore::MeshPoint& cP0 = rPoint[it->_aulPoints[i]]; const MeshCore::MeshPoint& cP1 = rPoint[it->_aulPoints[(i+1)%3]]; points->point.set1Value(index++, cP0.x, cP0.y, cP0.z); points->point.set1Value(index++, cP1.x, cP1.y, cP1.z); lines->numVertices.set1Value(index/2-1,2); } } } // enable notification points->enableNotify(true); lines->enableNotify(true); points->touch(); lines->touch(); } else { // remove the node and destroy the data pcHighlight->removeChild(pcOpenEdge); pcOpenEdge = 0; } #endif }