/*************************************************************************** * 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 #endif #include "ViewProviderFemPostObject.h" #include "TaskPostBoxes.h" #include #include #include #include #include #include #include #include #include #include #include #include using namespace FemGui; PROPERTY_SOURCE(FemGui::ViewProviderFemPostObject, Gui::ViewProviderDocumentObject) ViewProviderFemPostObject::ViewProviderFemPostObject() : m_blockPropertyChanges(false) { //initialize the properties ADD_PROPERTY_TYPE(Field,((long)0), "Coloring", App::Prop_None, "Select the field used for calculating the color"); ADD_PROPERTY_TYPE(VectorMode,((long)0), "Coloring", App::Prop_None, "Select what to show for a vector field"); ADD_PROPERTY(Transperency, (0)); sPixmap = "fem-fem-mesh-from-shape"; //create the subnodes which do the visualization work m_shapeHints = new SoShapeHints(); m_shapeHints->ref(); m_shapeHints->shapeType = SoShapeHints::UNKNOWN_SHAPE_TYPE; m_coordinates = new SoCoordinate3(); m_coordinates->ref(); m_materialBinding = new SoMaterialBinding(); m_materialBinding->ref(); m_material = new SoMaterial(); m_material->ref(); m_normalBinding = new SoNormalBinding(); m_normalBinding->ref(); m_normals = new SoNormal(); m_normals->ref(); m_faces = new SoIndexedFaceSet(); m_faces->ref(); m_triangleStrips = new SoIndexedTriangleStripSet(); m_triangleStrips->ref(); m_markers = new SoIndexedPointSet(); m_markers->ref(); m_lines = new SoIndexedLineSet(); m_lines->ref(); m_drawStyle = new SoDrawStyle(); m_drawStyle->ref(); m_drawStyle->lineWidth.setValue(2); m_drawStyle->pointSize.setValue(3); m_seperator = new SoSeparator(); m_seperator->ref(); // simple color bar m_colorRoot = new SoSeparator(); m_colorRoot->ref(); m_colorStyle = new SoDrawStyle(); m_colorStyle->ref(); m_colorRoot->addChild(m_colorStyle); m_colorBar = new Gui::SoFCColorBar; m_colorBar->Attach(this); m_colorBar->ref(); //create the vtk algorithms we use for visualisation m_outline = vtkSmartPointer::New(); m_points = vtkSmartPointer::New(); m_pointsSurface = vtkSmartPointer::New(); m_surface = vtkSmartPointer::New(); m_wireframe = vtkSmartPointer::New(); m_wireframeSurface = vtkSmartPointer::New(); m_surfaceEdges = vtkSmartPointer::New(); m_pointsSurface->AddInputConnection(m_surface->GetOutputPort()); m_wireframeSurface->AddInputConnection(m_surface->GetOutputPort()); m_surfaceEdges->AddInputConnection(m_surface->GetOutputPort()); m_surfaceEdges->AddInputConnection(m_wireframeSurface->GetOutputPort()); m_currentAlgorithm = m_outline; } ViewProviderFemPostObject::~ViewProviderFemPostObject() { m_shapeHints->unref(); m_coordinates->unref(); m_materialBinding->unref(); m_drawStyle->unref(); m_normalBinding->unref(); m_normals->unref(); m_faces->unref(); m_triangleStrips->unref(); m_markers->unref(); m_lines->unref(); m_seperator->unref(); m_material->unref(); m_colorBar->Detach(this); m_colorBar->unref(); m_colorStyle->unref(); m_colorRoot->unref(); } void ViewProviderFemPostObject::attach(App::DocumentObject *pcObj) { ViewProviderDocumentObject::attach(pcObj); // face nodes m_seperator->addChild(m_shapeHints); m_seperator->addChild(m_drawStyle); m_seperator->addChild(m_materialBinding); m_seperator->addChild(m_material); m_seperator->addChild(m_coordinates); m_seperator->addChild(m_markers); m_seperator->addChild(m_lines); m_seperator->addChild(m_faces); // Check for an already existing color bar Gui::SoFCColorBar* pcBar = ((Gui::SoFCColorBar*)findFrontRootOfType( Gui::SoFCColorBar::getClassTypeId() )); if ( pcBar ) { float fMin = m_colorBar->getMinValue(); float fMax = m_colorBar->getMaxValue(); // Attach to the foreign color bar and delete our own bar pcBar->Attach(this); pcBar->ref(); pcBar->setRange(fMin, fMax, 3); pcBar->Notify(0); m_colorBar->Detach(this); m_colorBar->unref(); m_colorBar = pcBar; } m_colorRoot->addChild(m_colorBar); //all addDisplayMaskMode(m_seperator, "Default"); setDisplayMaskMode("Default"); setupPipeline(); } SoSeparator* ViewProviderFemPostObject::getFrontRoot(void) const { return m_colorRoot; } void ViewProviderFemPostObject::setDisplayMode(const char* ModeName) { if (strcmp("Outline",ModeName)==0) m_currentAlgorithm = m_outline; else if (strcmp("Surface with Edges",ModeName)==0) m_currentAlgorithm = m_surfaceEdges; else if (strcmp("Surface",ModeName)==0) m_currentAlgorithm = m_surface; else if (strcmp("Wireframe",ModeName)==0) m_currentAlgorithm = m_wireframe; else if (strcmp("Wireframe (surface only)",ModeName)==0) m_currentAlgorithm = m_wireframeSurface; else if (strcmp("Nodes",ModeName)==0) m_currentAlgorithm = m_points; else if (strcmp("Nodes (surface only)",ModeName)==0) m_currentAlgorithm = m_pointsSurface; update(); ViewProviderDocumentObject::setDisplayMode( ModeName ); } std::vector ViewProviderFemPostObject::getDisplayModes(void) const { std::vector StrList; StrList.push_back("Outline"); StrList.push_back("Nodes"); //StrList.push_back("Nodes (surface only)"); somehow this filter does not work StrList.push_back("Surface"); StrList.push_back("Surface with Edges"); StrList.push_back("Wireframe"); StrList.push_back("Wireframe (surface only)"); return StrList; } void ViewProviderFemPostObject::update() { if(!setupPipeline()) return; m_currentAlgorithm->Update(); updateProperties(); update3D(); } void ViewProviderFemPostObject::updateProperties() { m_blockPropertyChanges = true; vtkPolyData* poly = m_currentAlgorithm->GetOutput(); //coloring std::string val; if(Field.getEnums() && Field.getValue() >= 0) val = Field.getValueAsString(); std::vector colorArrays; colorArrays.push_back("None"); vtkPointData* point = poly->GetPointData(); for(int i=0; iGetNumberOfArrays(); ++i) colorArrays.push_back(point->GetArrayName(i)); vtkCellData* cell = poly->GetCellData(); for(int i=0; iGetNumberOfArrays(); ++i) colorArrays.push_back(cell->GetArrayName(i)); App::Enumeration empty; Field.setValue(empty); m_coloringEnum.setEnums(colorArrays); Field.setValue(m_coloringEnum); std::vector::iterator it = std::find(colorArrays.begin(), colorArrays.end(), val); if(!val.empty() && it != colorArrays.end()) Field.setValue(val.c_str()); Field.purgeTouched(); //Vector mode if(VectorMode.getEnums() && VectorMode.getValue() >= 0) val = VectorMode.getValueAsString(); colorArrays.clear(); if(Field.getValue() == 0) colorArrays.push_back("Not a vector"); else { int array = Field.getValue() - 1; //0 is none vtkPolyData* pd = m_currentAlgorithm->GetOutput(); vtkDataArray* data = pd->GetPointData()->GetArray(array); if(data->GetNumberOfComponents() == 1) colorArrays.push_back("Not a vector"); else { colorArrays.push_back("Magnitude"); if(data->GetNumberOfComponents() >= 2) { colorArrays.push_back("X"); colorArrays.push_back("Y"); } if(data->GetNumberOfComponents() >= 3) colorArrays.push_back("Z"); } } VectorMode.setValue(empty); m_vectorEnum.setEnums(colorArrays); VectorMode.setValue(m_vectorEnum); it = std::find(colorArrays.begin(), colorArrays.end(), val); if(!val.empty() && it != colorArrays.end()) VectorMode.setValue(val.c_str()); m_blockPropertyChanges = false; } void ViewProviderFemPostObject::update3D() { vtkPolyData* pd = m_currentAlgorithm->GetOutput(); vtkPointData *pntData; vtkPoints *points; vtkDataArray *normals = NULL; vtkDataArray *tcoords = NULL; vtkCellArray *cells; vtkIdType npts = 0; vtkIdType *indx = 0; points = pd->GetPoints(); pntData = pd->GetPointData(); normals = pntData->GetNormals(); tcoords = pntData->GetTCoords(); // write out point data if any WritePointData(points, normals, tcoords); bool ResetColorBarRange = true; WriteColorData(ResetColorBarRange); WriteTransperency(); // write out polys if any if (pd->GetNumberOfPolys() > 0) { m_faces->coordIndex.startEditing(); int soidx = 0; cells = pd->GetPolys(); for (cells->InitTraversal(); cells->GetNextCell(npts,indx); ) { for (int i = 0; i < npts; i++) { m_faces->coordIndex.set1Value(soidx, static_cast(indx[i])); ++soidx; } m_faces->coordIndex.set1Value(soidx, -1); ++soidx; } m_faces->coordIndex.setNum(soidx); m_faces->coordIndex.finishEditing(); } else m_faces->coordIndex.setNum(0); // write out tstrips if any if (pd->GetNumberOfStrips() > 0) { int soidx = 0; cells = pd->GetStrips(); m_triangleStrips->coordIndex.startEditing(); for (cells->InitTraversal(); cells->GetNextCell(npts,indx); ) { for (int i = 0; i < npts; i++) { m_triangleStrips->coordIndex.set1Value(soidx, static_cast(indx[i])); ++soidx; } m_triangleStrips->coordIndex.set1Value(soidx, -1); ++soidx; } m_triangleStrips->coordIndex.setNum(soidx); m_triangleStrips->coordIndex.finishEditing(); } else m_triangleStrips->coordIndex.setNum(0); // write out lines if any if (pd->GetNumberOfLines() > 0) { int soidx = 0; cells = pd->GetLines(); m_lines->coordIndex.startEditing(); for (cells->InitTraversal(); cells->GetNextCell(npts,indx); ) { for (int i = 0; i < npts; i++) { m_lines->coordIndex.set1Value(soidx, static_cast(indx[i])); ++soidx; } m_lines->coordIndex.set1Value(soidx, -1); ++soidx; } m_lines->coordIndex.setNum(soidx); m_lines->coordIndex.finishEditing(); } else m_lines->coordIndex.setNum(0); // write out verts if any if (pd->GetNumberOfVerts() > 0){ int soidx = 0; cells = pd->GetVerts(); m_markers->coordIndex.startEditing(); m_markers->coordIndex.setNum(pd->GetNumberOfVerts()); for (cells->InitTraversal(); cells->GetNextCell(npts,indx); ) { m_markers->coordIndex.set1Value(soidx, static_cast(indx[0])); ++soidx; } m_markers->coordIndex.finishEditing(); } else m_markers->coordIndex.setNum(0); } void ViewProviderFemPostObject::WritePointData(vtkPoints* points, vtkDataArray* normals, vtkDataArray* tcoords) { double *p; int i; if(!points) return; m_coordinates->point.startEditing(); m_coordinates->point.setNum(points->GetNumberOfPoints()); for (i = 0; i < points->GetNumberOfPoints(); i++) { p = points->GetPoint(i); m_coordinates->point.set1Value(i, p[0], p[1], p[2]); } m_coordinates->point.finishEditing(); // write out the point normal data if (normals) { m_normals->vector.startEditing(); m_normals->vector.setNum(normals->GetNumberOfTuples()); for (i = 0; i < normals->GetNumberOfTuples(); i++) { p = normals->GetTuple(i); m_normals->vector.set1Value(i, SbVec3f(p[0], p[1], p[2])); } m_normals->vector.finishEditing(); m_normalBinding->value = SoNormalBinding::PER_VERTEX_INDEXED; m_normalBinding->value.touch(); } } void ViewProviderFemPostObject::WriteColorData(bool ResetColorBarRange) { if(!setupPipeline()) return; if(Field.getEnumVector().empty() || Field.getValue() == 0) { m_material->diffuseColor.setValue(SbColor(0.8,0.8,0.8)); m_material->transparency.setValue(0.); m_materialBinding->value = SoMaterialBinding::OVERALL; m_materialBinding->touch(); return; }; int array = Field.getValue() - 1; //0 is none vtkPolyData* pd = m_currentAlgorithm->GetOutput(); vtkDataArray* data = pd->GetPointData()->GetArray(array); int component = VectorMode.getValue() - 1; //0 is either "Not a vector" or magnitude, for -1 is correct for magnitude. x y and z are one number too high if(strcmp(VectorMode.getValueAsString(), "Not a vector")==0) component = 0; //build the lookuptable if (ResetColorBarRange == true) { double range[2]; data->GetRange(range, component); m_colorBar->setRange(range[0], range[1]); } m_material->diffuseColor.startEditing(); for (int i = 0; i < pd->GetNumberOfPoints(); i++) { double value = 0; if(component >= 0) value = data->GetComponent(i, component); else { for(int j=0; jGetNumberOfComponents(); ++j) value += std::pow(data->GetComponent(i, j),2); value = std::sqrt(value); } App::Color c = m_colorBar->getColor(value); m_material->diffuseColor.set1Value(i, c.r, c.g, c.b); } m_material->diffuseColor.finishEditing(); m_materialBinding->value = SoMaterialBinding::PER_VERTEX_INDEXED; m_materialBinding->touch(); } void ViewProviderFemPostObject::WriteTransperency() { float trans = float(Transperency.getValue()) / 100.; m_material->transparency.setValue(trans); } void ViewProviderFemPostObject::updateData(const App::Property* p) { if( strcmp(p->getName(), "Data") == 0 ) { update(); } } bool ViewProviderFemPostObject::setupPipeline() { vtkDataObject* data = static_cast(getObject())->Data.getValue(); if(!data) return false; m_outline->SetInputData(data); m_surface->SetInputData(data); m_wireframe->SetInputData(data); m_points->SetInputData(data); return true; } void ViewProviderFemPostObject::onChanged(const App::Property* prop) { if(m_blockPropertyChanges) return; bool ResetColorBarRange = true; if(prop == &Field && setupPipeline()) { updateProperties(); WriteColorData(ResetColorBarRange); WriteTransperency(); } else if(prop == &VectorMode && setupPipeline()) { WriteColorData(ResetColorBarRange); WriteTransperency(); } else if(prop == &Transperency) { WriteTransperency(); } ViewProviderDocumentObject::onChanged(prop); } bool ViewProviderFemPostObject::doubleClicked(void) { Gui::Application::Instance->activeDocument()->setEdit(this, (int)ViewProvider::Default); return true; } bool ViewProviderFemPostObject::setEdit(int ModNum) { if (ModNum == ViewProvider::Default || ModNum == 1 ) { Gui::TaskView::TaskDialog *dlg = Gui::Control().activeDialog(); TaskDlgPost *postDlg = qobject_cast(dlg); if (postDlg && postDlg->getView() != this) postDlg = 0; // another pad left open its task panel if (dlg && !postDlg) { 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; } // start the edit dialog if (postDlg) Gui::Control().showDialog(postDlg); else { postDlg = new TaskDlgPost(this); setupTaskDialog(postDlg); Gui::Control().showDialog(postDlg); } return true; } else { return ViewProviderDocumentObject::setEdit(ModNum); } } void ViewProviderFemPostObject::setupTaskDialog(TaskDlgPost* dlg) { dlg->appendBox(new TaskPostDisplay(this)); } void ViewProviderFemPostObject::unsetEdit(int ModNum) { if (ModNum == ViewProvider::Default) { // and update the pad //getSketchObject()->getDocument()->recompute(); // when pressing ESC make sure to close the dialog Gui::Control().closeDialog(); } else { ViewProviderDocumentObject::unsetEdit(ModNum); } } void ViewProviderFemPostObject::hide(void) { Gui::ViewProviderDocumentObject::hide(); m_colorStyle->style = SoDrawStyle::INVISIBLE; } void ViewProviderFemPostObject::show(void) { Gui::ViewProviderDocumentObject::show(); m_colorStyle->style = SoDrawStyle::FILLED; } void ViewProviderFemPostObject::OnChange(Base::Subject< int >& rCaller, int rcReason) { bool ResetColorBarRange = false; WriteColorData(ResetColorBarRange); }