Files
create/src/Mod/Mesh/Gui/ViewProviderMeshNode.cpp
2011-10-10 13:44:52 +00:00

404 lines
13 KiB
C++

/***************************************************************************
* Copyright (c) 2006 Werner Mayer <werner.wm.mayer@gmx.de> *
* *
* 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/SoBaseColor.h>
# include <Inventor/nodes/SoDrawStyle.h>
# include <Inventor/nodes/SoMaterial.h>
# include <Inventor/nodes/SoShapeHints.h>
# include <Inventor/nodes/SoOrthographicCamera.h>
# include <qmessagebox.h>
#endif
/// Here the FreeCAD includes sorted by Base,App,Gui......
#include <Base/Console.h>
#include <Base/Exception.h>
#include <Base/Sequencer.h>
#include <Base/Tools2D.h>
#include <Base/ViewProj.h>
#include <App/Document.h>
#include <App/PropertyLinks.h>
#include <Gui/Application.h>
#include <Gui/Command.h>
#include <Gui/Document.h>
#include <Gui/SoFCSelection.h>
#include <Gui/MainWindow.h>
#include <Gui/MouseModel.h>
#include <Gui/Selection.h>
#include <Gui/Window.h>
#include <Gui/View3DInventor.h>
#include <Gui/View3DInventorViewer.h>
#include <Mod/Mesh/App/Core/Algorithm.h>
#include <Mod/Mesh/App/Core/Evaluation.h>
#include <Mod/Mesh/App/Core/Grid.h>
#include <Mod/Mesh/App/Core/Iterator.h>
#include <Mod/Mesh/App/Core/MeshIO.h>
#include <Mod/Mesh/App/Core/Visitor.h>
#include <Mod/Mesh/App/Mesh.h>
#include <Mod/Mesh/App/MeshFeature.h>
#include <Mod/Mesh/Gui/SoFCMeshNode.h>
#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<ParameterGrp> 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<Mesh::Feature*>(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<ParameterGrp> 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<std::string> ViewProviderMeshNode::getDisplayModes(void) const
{
std::vector<std::string> 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<SbVec2f> 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<MeshCore::MeshGeomFacet> 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<unsigned long> 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<Mesh::Feature*>(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<Mesh::Feature*>(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
}