Fem: Save and restore custom colors of elements in mesh - fixes #6131

This commit is contained in:
marioalexis
2024-04-28 02:50:07 -03:00
committed by Yorik van Havre
parent 2e7a1cf358
commit 1b6fa97472
3 changed files with 272 additions and 111 deletions

View File

@@ -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<long>(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<long, App::Color>& NodeColorMap)
{
long endId = (--NodeColorMap.end())->first;
std::vector<App::Color> 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<long>& NodeIds,
const std::vector<App::Color>& NodeColors)
{
long endId = *(std::max_element(NodeIds.begin(), NodeIds.end()));
std::vector<App::Color> colorVec(endId + 1, App::Color(0, 1, 0));
long i = 0;
for (std::vector<long>::const_iterator it = NodeIds.begin(); it != NodeIds.end(); ++it, i++) {
colorVec[*it] = NodeColors[i];
}
setColorByNodeIdHelper(colorVec);
}
void ViewProviderFemMesh::setColorByNodeIdHelper(const std::vector<App::Color>& 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<unsigned long>::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<long, Base::Vector3d>& NodeDispMap)
{
long startId = NodeDispMap.begin()->first;
@@ -681,37 +683,192 @@ void ViewProviderFemMesh::applyDisplacementToNodes(double factor)
DisplacementFactor = factor;
}
void ViewProviderFemMesh::setColorByElementId(const std::map<long, App::Color>& ElementColorMap)
void ViewProviderFemMesh::setColorByNodeId(const std::vector<long>& NodeIds,
const std::vector<App::Color>& NodeColors)
{
pcMatBinding->value = SoMaterialBinding::PER_FACE;
long endId = *(std::max_element(NodeIds.begin(), NodeIds.end()));
std::vector<App::Color> colorVec(endId + 1, App::Color(0, 1, 0));
long i = 0;
for (std::vector<long>::const_iterator it = NodeIds.begin(); it != NodeIds.end(); ++it, i++) {
colorVec[*it] = NodeColors[i];
}
setColorByNodeIdHelper(colorVec);
}
void ViewProviderFemMesh::setColorByNodeIdHelper(const std::vector<App::Color>& 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<unsigned long>::const_iterator it = vFaceElementIdx.begin();
it != vFaceElementIdx.end();
long i = 0;
for (std::vector<unsigned long>::const_iterator it = vNodeElementIdx.begin();
it != vNodeElementIdx.end();
++it, i++) {
unsigned long ElemIdx = ((*it) >> 3);
const std::map<long, App::Color>::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<std::vector<long>, App::Color>& elemColorMap)
{
setColorByIdHelper(elemColorMap, vNodeElementIdx, 0, NodeColorArray);
}
void ViewProviderFemMesh::setColorByElementId(
const std::map<std::vector<long>, App::Color>& elemColorMap)
{
setColorByIdHelper(elemColorMap, vFaceElementIdx, 3, ElementColorArray);
}
void ViewProviderFemMesh::setColorByIdHelper(
const std::map<std::vector<long>, App::Color>& elemColorMap,
const std::vector<unsigned long>& vElementIdx,
int rShift,
App::PropertyColorList& prop)
{
std::vector<App::Color> vecColor(vElementIdx.size());
std::map<long, const App::Color*> 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<unsigned long>::const_iterator it = vElementIdx.begin();
it != vElementIdx.end();
++it, i++) {
unsigned long ElemIdx = ((*it) >> rShift);
const std::map<long, const App::Color*>::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<unsigned long>& 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<App::Color> 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);
}
// ----------------------------------------------------------------------------

View File

@@ -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<long, App::Color>& NodeColorMap);
void setColorByNodeId(const std::map<std::vector<long>, App::Color>& NodeColorMap);
void setColorByNodeId(const std::vector<long>& NodeIds,
const std::vector<App::Color>& 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<long, App::Color>& ElementColorMap);
void setColorByElementId(const std::map<std::vector<long>, App::Color>& ElementColorMap);
/// reset the view of the element colors
void resetColorByElementId();
void setMaterialByElement();
//@}
const std::vector<unsigned long>& 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<App::Color>&);
void setDisplacementByNodeIdHelper(const std::vector<Base::Vector3d>& DispVector, long startId);
void setColorByIdHelper(const std::map<std::vector<long>, App::Color>& elemColorMap,
const std::vector<unsigned long>& vElementIdx,
int rShift,
App::PropertyColorList& prop);
void setMaterialByColorArray(const App::PropertyColorList* prop,
const std::vector<unsigned long>& vElementIdx) const;
void setMaterialOverall() const;
/// index of elements to their triangles
std::vector<unsigned long> vFaceElementIdx;
std::vector<unsigned long> vNodeElementIdx;
std::vector<unsigned long> vHighlightedIdx;
std::vector<Base::Vector3d> DisplacementVector;
double DisplacementFactor;

View File

@@ -8,6 +8,7 @@
#include <Base/GeometryPyCXX.h>
#include <Base/VectorPy.h>
#include <App/MaterialPy.h>
#include <Mod/Fem/App/FemMeshObject.h>
#include "ViewProviderFemMesh.h"
@@ -178,43 +179,42 @@ Py::Dict ViewProviderFemMeshPy::getNodeColor() const
throw Py::AttributeError("Not yet implemented");
}
namespace
{
std::map<std::vector<long>, App::Color> colorMapFromDict(Py::Dict& arg)
{
std::map<std::vector<long>, App::Color> colorMap;
for (Py::Dict::iterator it = arg.begin(); it != arg.end(); ++it) {
std::vector<long> 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<long>(Py::Long(i)));
}
}
else {
vecId.emplace_back(static_cast<long>(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<long,App::Color> 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<long> NodeIds(size);
std::vector<App::Color> 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<long, App::Color> 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));
}
}