diff --git a/src/Mod/Fem/Gui/ViewProviderFemMesh.cpp b/src/Mod/Fem/Gui/ViewProviderFemMesh.cpp index e2b3dc998c..2e1e80edb0 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemMesh.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemMesh.cpp @@ -186,6 +186,8 @@ PROPERTY_SOURCE(FemGui::ViewProviderFemMesh, Gui::ViewProviderGeometryObject) App::PropertyFloatConstraint::Constraints ViewProviderFemMesh::floatRange = {1.0, 64.0, 1.0}; +const char* ViewProviderFemMesh::colorModeEnum[] = {"Overall", "ByElement", "ByNode", nullptr}; + ViewProviderFemMesh::ViewProviderFemMesh() { sPixmap = "fem-femmesh-from-shape"; @@ -202,6 +204,23 @@ ViewProviderFemMesh::ViewProviderFemMesh() ADD_PROPERTY(ShowInner, (false)); ADD_PROPERTY(MaxFacesShowInner, (50000)); + ADD_PROPERTY_TYPE(ColorMode, + ("Overall"), + "Display Options", + App::Prop_None, + "Set the color mode"); + ADD_PROPERTY_TYPE(NodeColorArray, + (PointColor.getValue()), + "Object Style", + App::Prop_Hidden, + "Node diffuse color array"); + ADD_PROPERTY_TYPE(ElementColorArray, + (ShapeAppearance.getDiffuseColor()), + "Object Style", + App::Prop_Hidden, + "Node diffuse color array"); + + ColorMode.setEnums(colorModeEnum); onlyEdges = false; pcDrawStyle = new SoDrawStyle(); @@ -380,6 +399,16 @@ void ViewProviderFemMesh::updateData(const App::Property* prop) void ViewProviderFemMesh::onChanged(const App::Property* prop) { + auto matchTransparency = [&]() { + if (getObject() && getObject()->testStatus(App::ObjectStatus::TouchOnColorChange)) { + getObject()->touch(true); + } + long value = static_cast(100 * ShapeAppearance.getTransparency() + 0.5); + if (value != Transparency.getValue()) { + Transparency.setValue(value); + } + }; + if (prop == &PointSize) { pcPointStyle->pointSize = PointSize.getValue(); } @@ -413,6 +442,31 @@ void ViewProviderFemMesh::onChanged(const App::Property* prop) else if (prop == &LineWidth) { pcDrawStyle->lineWidth = LineWidth.getValue(); } + else if (prop == &ColorMode) { + switch (ColorMode.getValue()) { + case 1: // ByElement + setMaterialByColorArray(&ElementColorArray, vFaceElementIdx); + break; + case 2: // ByNode + setMaterialByColorArray(&NodeColorArray, vNodeElementIdx); + break; + default: // Overall + setMaterialOverall(); + } + } + else if (prop == &ShapeAppearance && ColorMode.getValue() == 0) { + matchTransparency(); + setMaterialOverall(); + } + else if ((prop == &ElementColorArray || prop == &ShapeAppearance) + && ColorMode.getValue() == 1) { + matchTransparency(); + setMaterialByColorArray(&ElementColorArray, vFaceElementIdx); + } + else if ((prop == &NodeColorArray || prop == &ShapeAppearance) && ColorMode.getValue() == 2) { + matchTransparency(); + setMaterialByColorArray(&NodeColorArray, vNodeElementIdx); + } else { ViewProviderGeometryObject::onChanged(prop); } @@ -549,58 +603,6 @@ PyObject* ViewProviderFemMesh::getPyObject() return Py::new_reference_to(PythonObject); } -void ViewProviderFemMesh::setColorByNodeId(const std::map& NodeColorMap) -{ - long endId = (--NodeColorMap.end())->first; - - std::vector colorVec(endId + 1, App::Color(0, 1, 0)); - for (const auto& it : NodeColorMap) { - colorVec[it.first] = it.second; - } - - setColorByNodeIdHelper(colorVec); -} -void ViewProviderFemMesh::setColorByNodeId(const std::vector& NodeIds, - const std::vector& NodeColors) -{ - - long endId = *(std::max_element(NodeIds.begin(), NodeIds.end())); - - std::vector colorVec(endId + 1, App::Color(0, 1, 0)); - long i = 0; - for (std::vector::const_iterator it = NodeIds.begin(); it != NodeIds.end(); ++it, i++) { - colorVec[*it] = NodeColors[i]; - } - - setColorByNodeIdHelper(colorVec); -} - -void ViewProviderFemMesh::setColorByNodeIdHelper(const std::vector& colorVec) -{ - pcMatBinding->value = SoMaterialBinding::PER_VERTEX_INDEXED; - - // resizing and writing the color vector: - pcShapeMaterial->diffuseColor.setNum(vNodeElementIdx.size()); - SbColor* colors = pcShapeMaterial->diffuseColor.startEditing(); - - long i = 0; - for (std::vector::const_iterator it = vNodeElementIdx.begin(); - it != vNodeElementIdx.end(); - ++it, i++) { - colors[i] = SbColor(colorVec[*it].r, colorVec[*it].g, colorVec[*it].b); - } - - pcShapeMaterial->diffuseColor.finishEditing(); -} - -void ViewProviderFemMesh::resetColorByNodeId() -{ - pcMatBinding->value = SoMaterialBinding::OVERALL; - pcShapeMaterial->diffuseColor.setNum(0); - const App::Color& c = ShapeAppearance.getDiffuseColor(); - pcShapeMaterial->diffuseColor.setValue(c.r, c.g, c.b); -} - void ViewProviderFemMesh::setDisplacementByNodeId(const std::map& NodeDispMap) { long startId = NodeDispMap.begin()->first; @@ -681,37 +683,192 @@ void ViewProviderFemMesh::applyDisplacementToNodes(double factor) DisplacementFactor = factor; } -void ViewProviderFemMesh::setColorByElementId(const std::map& ElementColorMap) +void ViewProviderFemMesh::setColorByNodeId(const std::vector& NodeIds, + const std::vector& NodeColors) { - pcMatBinding->value = SoMaterialBinding::PER_FACE; + long endId = *(std::max_element(NodeIds.begin(), NodeIds.end())); + + std::vector colorVec(endId + 1, App::Color(0, 1, 0)); + long i = 0; + for (std::vector::const_iterator it = NodeIds.begin(); it != NodeIds.end(); ++it, i++) { + colorVec[*it] = NodeColors[i]; + } + + setColorByNodeIdHelper(colorVec); +} + +void ViewProviderFemMesh::setColorByNodeIdHelper(const std::vector& colorVec) +{ + pcMatBinding->value = SoMaterialBinding::PER_VERTEX_INDEXED; // resizing and writing the color vector: - pcShapeMaterial->diffuseColor.setNum(vFaceElementIdx.size()); + pcShapeMaterial->diffuseColor.setNum(vNodeElementIdx.size()); SbColor* colors = pcShapeMaterial->diffuseColor.startEditing(); - int i = 0; - for (std::vector::const_iterator it = vFaceElementIdx.begin(); - it != vFaceElementIdx.end(); + long i = 0; + for (std::vector::const_iterator it = vNodeElementIdx.begin(); + it != vNodeElementIdx.end(); ++it, i++) { - unsigned long ElemIdx = ((*it) >> 3); - const std::map::const_iterator pos = ElementColorMap.find(ElemIdx); - if (pos == ElementColorMap.end()) { - colors[i] = SbColor(0, 1, 0); - } - else { - colors[i] = SbColor(pos->second.r, pos->second.g, pos->second.b); - } + colors[i] = SbColor(colorVec[*it].r, colorVec[*it].g, colorVec[*it].b); } pcShapeMaterial->diffuseColor.finishEditing(); } -void ViewProviderFemMesh::resetColorByElementId() +void ViewProviderFemMesh::resetColorByNodeId() { + const App::Color& c = ShapeAppearance.getDiffuseColor(); + NodeColorArray.setValue(c); +} + +void ViewProviderFemMesh::setColorByNodeId( + const std::map, App::Color>& elemColorMap) +{ + setColorByIdHelper(elemColorMap, vNodeElementIdx, 0, NodeColorArray); +} + +void ViewProviderFemMesh::setColorByElementId( + const std::map, App::Color>& elemColorMap) +{ + setColorByIdHelper(elemColorMap, vFaceElementIdx, 3, ElementColorArray); +} + +void ViewProviderFemMesh::setColorByIdHelper( + const std::map, App::Color>& elemColorMap, + const std::vector& vElementIdx, + int rShift, + App::PropertyColorList& prop) +{ + std::vector vecColor(vElementIdx.size()); + std::map colorMap; + for (const auto& m : elemColorMap) { + for (long i : m.first) { + colorMap[i] = &m.second; + } + } + + App::Color baseDif = ShapeAppearance.getDiffuseColor(); + int i = 0; + for (std::vector::const_iterator it = vElementIdx.begin(); + it != vElementIdx.end(); + ++it, i++) { + unsigned long ElemIdx = ((*it) >> rShift); + const std::map::const_iterator pos = colorMap.find(ElemIdx); + vecColor[i] = pos == colorMap.end() ? baseDif : *pos->second; + } + + prop.setValue(vecColor); +} + +void ViewProviderFemMesh::setMaterialOverall() const +{ + const App::Material& mat = ShapeAppearance[0]; + App::Color baseDif = mat.diffuseColor; + App::Color baseAmb = mat.ambientColor; + App::Color baseSpe = mat.specularColor; + App::Color baseEmi = mat.emissiveColor; + float baseShi = mat.shininess; + float baseTra = mat.transparency; + pcMatBinding->value = SoMaterialBinding::OVERALL; pcShapeMaterial->diffuseColor.setNum(0); + pcShapeMaterial->ambientColor.setNum(0); + pcShapeMaterial->specularColor.setNum(0); + pcShapeMaterial->emissiveColor.setNum(0); + pcShapeMaterial->shininess.setNum(0); + pcShapeMaterial->transparency.setNum(0); + pcShapeMaterial->diffuseColor.setValue(baseDif.r, baseDif.g, baseDif.b); + pcShapeMaterial->ambientColor.setValue(baseAmb.r, baseAmb.g, baseAmb.b); + pcShapeMaterial->specularColor.setValue(baseSpe.r, baseSpe.g, baseSpe.b); + pcShapeMaterial->emissiveColor.setValue(baseEmi.r, baseEmi.g, baseEmi.b); + pcShapeMaterial->shininess.setValue(baseShi); + pcShapeMaterial->transparency.setValue(baseTra); + + pcFaces->touch(); + + return; +} + +void ViewProviderFemMesh::setMaterialByColorArray( + const App::PropertyColorList* prop, + const std::vector& vElementIdx) const +{ + const App::Material& baseMat = ShapeAppearance[0]; + App::Color baseDif = baseMat.diffuseColor; + App::Color baseAmb = baseMat.ambientColor; + App::Color baseSpe = baseMat.specularColor; + App::Color baseEmi = baseMat.emissiveColor; + float baseShi = baseMat.shininess; + float baseTra = baseMat.transparency; + + // resizing and writing the color vector: + std::vector vecColor = prop->getValue(); + size_t elemSize = vElementIdx.size(); + if (vecColor.size() == 1) { + pcMatBinding->value = SoMaterialBinding::OVERALL; + pcShapeMaterial->diffuseColor.setNum(0); + pcShapeMaterial->ambientColor.setNum(0); + pcShapeMaterial->specularColor.setNum(0); + pcShapeMaterial->emissiveColor.setNum(0); + pcShapeMaterial->shininess.setNum(0); + pcShapeMaterial->transparency.setNum(0); + pcShapeMaterial->diffuseColor.setValue(vecColor[0].r, vecColor[0].g, vecColor[0].b); + pcShapeMaterial->ambientColor.setValue(baseAmb.r, baseAmb.g, baseAmb.b); + pcShapeMaterial->specularColor.setValue(baseSpe.r, baseSpe.g, baseSpe.b); + pcShapeMaterial->emissiveColor.setValue(baseEmi.r, baseEmi.g, baseEmi.b); + pcShapeMaterial->shininess.setValue(baseShi); + pcShapeMaterial->transparency.setValue(baseTra); + + return; + } + + if (prop == &ElementColorArray) { + pcMatBinding->value = SoMaterialBinding::PER_FACE; + } + else if (prop == &NodeColorArray) { + pcMatBinding->value = SoMaterialBinding::PER_VERTEX_INDEXED; + } + + pcShapeMaterial->diffuseColor.setNum(elemSize); + SbColor* diffuse = pcShapeMaterial->diffuseColor.startEditing(); + pcShapeMaterial->ambientColor.setNum(elemSize); + SbColor* ambient = pcShapeMaterial->ambientColor.startEditing(); + pcShapeMaterial->specularColor.setNum(elemSize); + SbColor* specular = pcShapeMaterial->specularColor.startEditing(); + pcShapeMaterial->emissiveColor.setNum(elemSize); + SbColor* emissive = pcShapeMaterial->emissiveColor.startEditing(); + pcShapeMaterial->shininess.setNum(elemSize); + float* shininess = pcShapeMaterial->shininess.startEditing(); + pcShapeMaterial->transparency.setNum(elemSize); + float* transparency = pcShapeMaterial->transparency.startEditing(); + + vecColor.resize(elemSize, baseDif); + + int i = 0; + for (const App::Color& c : vecColor) { + diffuse[i] = SbColor(c.r, c.g, c.b); + ambient[i] = SbColor(baseAmb.r, baseAmb.g, baseAmb.b); + specular[i] = SbColor(baseSpe.r, baseSpe.g, baseSpe.b); + emissive[i] = SbColor(baseEmi.r, baseEmi.g, baseEmi.b); + shininess[i] = baseShi; + transparency[i] = baseTra; + ++i; + } + + pcShapeMaterial->diffuseColor.finishEditing(); + pcShapeMaterial->ambientColor.finishEditing(); + pcShapeMaterial->specularColor.finishEditing(); + pcShapeMaterial->emissiveColor.finishEditing(); + pcShapeMaterial->shininess.finishEditing(); + pcShapeMaterial->transparency.finishEditing(); + + pcFaces->touch(); +} + +void ViewProviderFemMesh::resetColorByElementId() +{ const App::Color& c = ShapeAppearance.getDiffuseColor(); - pcShapeMaterial->diffuseColor.setValue(c.r, c.g, c.b); + ElementColorArray.setValue(c); } // ---------------------------------------------------------------------------- diff --git a/src/Mod/Fem/Gui/ViewProviderFemMesh.h b/src/Mod/Fem/Gui/ViewProviderFemMesh.h index cca87ee6c4..92eaa76f22 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemMesh.h +++ b/src/Mod/Fem/Gui/ViewProviderFemMesh.h @@ -73,6 +73,9 @@ public: App::PropertyBool BackfaceCulling; App::PropertyBool ShowInner; App::PropertyInteger MaxFacesShowInner; + App::PropertyEnumeration ColorMode; + App::PropertyColorList NodeColorArray; + App::PropertyColorList ElementColorArray; void attach(App::DocumentObject* pcObject) override; void setDisplayMode(const char* ModeName) override; @@ -110,7 +113,7 @@ public: //@{ /// set the color for each node - void setColorByNodeId(const std::map& NodeColorMap); + void setColorByNodeId(const std::map, App::Color>& NodeColorMap); void setColorByNodeId(const std::vector& NodeIds, const std::vector& NodeColors); @@ -125,9 +128,10 @@ public: /// reaply the node displacement with a certain factor and do a redraw void applyDisplacementToNodes(double factor); /// set the color for each element - void setColorByElementId(const std::map& ElementColorMap); + void setColorByElementId(const std::map, App::Color>& ElementColorMap); /// reset the view of the element colors void resetColorByElementId(); + void setMaterialByElement(); //@} const std::vector& getVisibleElementFaces() const @@ -139,6 +143,7 @@ public: private: static App::PropertyFloatConstraint::Constraints floatRange; + static const char* colorModeEnum[]; Py::Object PythonObject; @@ -148,11 +153,18 @@ protected: void setColorByNodeIdHelper(const std::vector&); void setDisplacementByNodeIdHelper(const std::vector& DispVector, long startId); + void setColorByIdHelper(const std::map, App::Color>& elemColorMap, + const std::vector& vElementIdx, + int rShift, + App::PropertyColorList& prop); + void setMaterialByColorArray(const App::PropertyColorList* prop, + const std::vector& vElementIdx) const; + void setMaterialOverall() const; + /// index of elements to their triangles std::vector vFaceElementIdx; std::vector vNodeElementIdx; std::vector vHighlightedIdx; - std::vector DisplacementVector; double DisplacementFactor; diff --git a/src/Mod/Fem/Gui/ViewProviderFemMeshPyImp.cpp b/src/Mod/Fem/Gui/ViewProviderFemMeshPyImp.cpp index 0c1a73660c..26c5b8ea1d 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemMeshPyImp.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemMeshPyImp.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include "ViewProviderFemMesh.h" @@ -178,43 +179,42 @@ Py::Dict ViewProviderFemMeshPy::getNodeColor() const throw Py::AttributeError("Not yet implemented"); } +namespace +{ + +std::map, App::Color> colorMapFromDict(Py::Dict& arg) +{ + std::map, App::Color> colorMap; + for (Py::Dict::iterator it = arg.begin(); it != arg.end(); ++it) { + std::vector vecId; + const Py::Object& id = (*it).first; + if (id.isTuple()) { + Py::Tuple idSeq(id); + for (const Py::Object& i: idSeq) { + vecId.emplace_back(static_cast(Py::Long(i))); + } + } + else { + vecId.emplace_back(static_cast(Py::Long(id))); + } + const Py::Object& value = (*it).second; + Py::Tuple color(value); + colorMap[vecId] = App::Color(Py::Float(color[0]), Py::Float(color[1]), Py::Float(color[2])); + } + + return colorMap; +} + +} // namespace void ViewProviderFemMeshPy::setNodeColor(Py::Dict arg) { long size = arg.size(); if (size == 0) { - this->getViewProviderFemMeshPtr()->resetColorByNodeId(); + getViewProviderFemMeshPtr()->resetColorByNodeId(); } else { - Base::TimeElapsed Start; - Base::Console().Log( - "Start: ViewProviderFemMeshPy::setNodeColor() =================================\n"); - // std::map NodeColorMap; - - // for( Py::Dict::iterator it = arg.begin(); it!= arg.end();++it){ - // Py::Long id((*it).first); - // Py::Tuple color((*it).second); - // NodeColorMap[id] = - // App::Color(Py::Float(color[0]),Py::Float(color[1]),Py::Float(color[2]),0); - // } - std::vector NodeIds(size); - std::vector NodeColors(size); - - long i = 0; - for (Py::Dict::iterator it = arg.begin(); it != arg.end(); ++it, i++) { - Py::Long id((*it).first); - Py::Tuple color((*it).second); - NodeIds[i] = id; - NodeColors[i] = - App::Color(Py::Float(color[0]), Py::Float(color[1]), Py::Float(color[2]), 0); - } - Base::Console().Log(" %f: Start ViewProviderFemMeshPy::setNodeColor() call \n", - Base::TimeElapsed::diffTimeF(Start, Base::TimeElapsed())); - - // this->getViewProviderFemMeshPtr()->setColorByNodeId(NodeColorMap); - this->getViewProviderFemMeshPtr()->setColorByNodeId(NodeIds, NodeColors); - Base::Console().Log(" %f: Finish ViewProviderFemMeshPy::setNodeColor() call \n", - Base::TimeElapsed::diffTimeF(Start, Base::TimeElapsed())); + getViewProviderFemMeshPtr()->setColorByNodeId(colorMapFromDict(arg)); } } @@ -229,18 +229,10 @@ Py::Dict ViewProviderFemMeshPy::getElementColor() const void ViewProviderFemMeshPy::setElementColor(Py::Dict arg) { if (arg.size() == 0) { - this->getViewProviderFemMeshPtr()->resetColorByNodeId(); + getViewProviderFemMeshPtr()->resetColorByElementId(); } else { - std::map NodeColorMap; - - for (Py::Dict::iterator it = arg.begin(); it != arg.end(); ++it) { - Py::Long id((*it).first); - Py::Tuple color((*it).second); - NodeColorMap[id] = - App::Color(Py::Float(color[0]), Py::Float(color[1]), Py::Float(color[2]), 0); - } - this->getViewProviderFemMeshPtr()->setColorByElementId(NodeColorMap); + getViewProviderFemMeshPtr()->setColorByElementId(colorMapFromDict(arg)); } }