Skip to content

Commit c783d31

Browse files
committed
Fem: Save and restore custom colors of elements in mesh - fixes FreeCAD#6131
1 parent ed77603 commit c783d31

File tree

3 files changed

+272
-111
lines changed

3 files changed

+272
-111
lines changed

src/Mod/Fem/Gui/ViewProviderFemMesh.cpp

+225-68
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,8 @@ PROPERTY_SOURCE(FemGui::ViewProviderFemMesh, Gui::ViewProviderGeometryObject)
186186

187187
App::PropertyFloatConstraint::Constraints ViewProviderFemMesh::floatRange = {1.0, 64.0, 1.0};
188188

189+
const char* ViewProviderFemMesh::colorModeEnum[] = {"Overall", "ByElement", "ByNode", nullptr};
190+
189191
ViewProviderFemMesh::ViewProviderFemMesh()
190192
{
191193
sPixmap = "fem-femmesh-from-shape";
@@ -202,6 +204,23 @@ ViewProviderFemMesh::ViewProviderFemMesh()
202204
ADD_PROPERTY(ShowInner, (false));
203205
ADD_PROPERTY(MaxFacesShowInner, (50000));
204206

207+
ADD_PROPERTY_TYPE(ColorMode,
208+
("Overall"),
209+
"Display Options",
210+
App::Prop_None,
211+
"Set the color mode");
212+
ADD_PROPERTY_TYPE(NodeColorArray,
213+
(PointColor.getValue()),
214+
"Object Style",
215+
App::Prop_Hidden,
216+
"Node diffuse color array");
217+
ADD_PROPERTY_TYPE(ElementColorArray,
218+
(ShapeAppearance.getDiffuseColor()),
219+
"Object Style",
220+
App::Prop_Hidden,
221+
"Node diffuse color array");
222+
223+
ColorMode.setEnums(colorModeEnum);
205224
onlyEdges = false;
206225

207226
pcDrawStyle = new SoDrawStyle();
@@ -380,6 +399,16 @@ void ViewProviderFemMesh::updateData(const App::Property* prop)
380399

381400
void ViewProviderFemMesh::onChanged(const App::Property* prop)
382401
{
402+
auto matchTransparency = [&]() {
403+
if (getObject() && getObject()->testStatus(App::ObjectStatus::TouchOnColorChange)) {
404+
getObject()->touch(true);
405+
}
406+
long value = static_cast<long>(100 * ShapeAppearance.getTransparency() + 0.5);
407+
if (value != Transparency.getValue()) {
408+
Transparency.setValue(value);
409+
}
410+
};
411+
383412
if (prop == &PointSize) {
384413
pcPointStyle->pointSize = PointSize.getValue();
385414
}
@@ -413,6 +442,31 @@ void ViewProviderFemMesh::onChanged(const App::Property* prop)
413442
else if (prop == &LineWidth) {
414443
pcDrawStyle->lineWidth = LineWidth.getValue();
415444
}
445+
else if (prop == &ColorMode) {
446+
switch (ColorMode.getValue()) {
447+
case 1: // ByElement
448+
setMaterialByColorArray(&ElementColorArray, vFaceElementIdx);
449+
break;
450+
case 2: // ByNode
451+
setMaterialByColorArray(&NodeColorArray, vNodeElementIdx);
452+
break;
453+
default: // Overall
454+
setMaterialOverall();
455+
}
456+
}
457+
else if (prop == &ShapeAppearance && ColorMode.getValue() == 0) {
458+
matchTransparency();
459+
setMaterialOverall();
460+
}
461+
else if ((prop == &ElementColorArray || prop == &ShapeAppearance)
462+
&& ColorMode.getValue() == 1) {
463+
matchTransparency();
464+
setMaterialByColorArray(&ElementColorArray, vFaceElementIdx);
465+
}
466+
else if ((prop == &NodeColorArray || prop == &ShapeAppearance) && ColorMode.getValue() == 2) {
467+
matchTransparency();
468+
setMaterialByColorArray(&NodeColorArray, vNodeElementIdx);
469+
}
416470
else {
417471
ViewProviderGeometryObject::onChanged(prop);
418472
}
@@ -549,58 +603,6 @@ PyObject* ViewProviderFemMesh::getPyObject()
549603
return Py::new_reference_to(PythonObject);
550604
}
551605

552-
void ViewProviderFemMesh::setColorByNodeId(const std::map<long, App::Color>& NodeColorMap)
553-
{
554-
long endId = (--NodeColorMap.end())->first;
555-
556-
std::vector<App::Color> colorVec(endId + 1, App::Color(0, 1, 0));
557-
for (const auto& it : NodeColorMap) {
558-
colorVec[it.first] = it.second;
559-
}
560-
561-
setColorByNodeIdHelper(colorVec);
562-
}
563-
void ViewProviderFemMesh::setColorByNodeId(const std::vector<long>& NodeIds,
564-
const std::vector<App::Color>& NodeColors)
565-
{
566-
567-
long endId = *(std::max_element(NodeIds.begin(), NodeIds.end()));
568-
569-
std::vector<App::Color> colorVec(endId + 1, App::Color(0, 1, 0));
570-
long i = 0;
571-
for (std::vector<long>::const_iterator it = NodeIds.begin(); it != NodeIds.end(); ++it, i++) {
572-
colorVec[*it] = NodeColors[i];
573-
}
574-
575-
setColorByNodeIdHelper(colorVec);
576-
}
577-
578-
void ViewProviderFemMesh::setColorByNodeIdHelper(const std::vector<App::Color>& colorVec)
579-
{
580-
pcMatBinding->value = SoMaterialBinding::PER_VERTEX_INDEXED;
581-
582-
// resizing and writing the color vector:
583-
pcShapeMaterial->diffuseColor.setNum(vNodeElementIdx.size());
584-
SbColor* colors = pcShapeMaterial->diffuseColor.startEditing();
585-
586-
long i = 0;
587-
for (std::vector<unsigned long>::const_iterator it = vNodeElementIdx.begin();
588-
it != vNodeElementIdx.end();
589-
++it, i++) {
590-
colors[i] = SbColor(colorVec[*it].r, colorVec[*it].g, colorVec[*it].b);
591-
}
592-
593-
pcShapeMaterial->diffuseColor.finishEditing();
594-
}
595-
596-
void ViewProviderFemMesh::resetColorByNodeId()
597-
{
598-
pcMatBinding->value = SoMaterialBinding::OVERALL;
599-
pcShapeMaterial->diffuseColor.setNum(0);
600-
const App::Color& c = ShapeAppearance.getDiffuseColor();
601-
pcShapeMaterial->diffuseColor.setValue(c.r, c.g, c.b);
602-
}
603-
604606
void ViewProviderFemMesh::setDisplacementByNodeId(const std::map<long, Base::Vector3d>& NodeDispMap)
605607
{
606608
long startId = NodeDispMap.begin()->first;
@@ -681,37 +683,192 @@ void ViewProviderFemMesh::applyDisplacementToNodes(double factor)
681683
DisplacementFactor = factor;
682684
}
683685

684-
void ViewProviderFemMesh::setColorByElementId(const std::map<long, App::Color>& ElementColorMap)
686+
void ViewProviderFemMesh::setColorByNodeId(const std::vector<long>& NodeIds,
687+
const std::vector<App::Color>& NodeColors)
688+
{
689+
long endId = *(std::max_element(NodeIds.begin(), NodeIds.end()));
690+
691+
std::vector<App::Color> colorVec(endId + 1, App::Color(0, 1, 0));
692+
long i = 0;
693+
for (std::vector<long>::const_iterator it = NodeIds.begin(); it != NodeIds.end(); ++it, i++) {
694+
colorVec[*it] = NodeColors[i];
695+
}
696+
697+
setColorByNodeIdHelper(colorVec);
698+
}
699+
700+
void ViewProviderFemMesh::setColorByNodeIdHelper(const std::vector<App::Color>& colorVec)
685701
{
686-
pcMatBinding->value = SoMaterialBinding::PER_FACE;
702+
pcMatBinding->value = SoMaterialBinding::PER_VERTEX_INDEXED;
687703

688704
// resizing and writing the color vector:
689-
pcShapeMaterial->diffuseColor.setNum(vFaceElementIdx.size());
705+
pcShapeMaterial->diffuseColor.setNum(vNodeElementIdx.size());
690706
SbColor* colors = pcShapeMaterial->diffuseColor.startEditing();
691707

692-
int i = 0;
693-
for (std::vector<unsigned long>::const_iterator it = vFaceElementIdx.begin();
694-
it != vFaceElementIdx.end();
708+
long i = 0;
709+
for (std::vector<unsigned long>::const_iterator it = vNodeElementIdx.begin();
710+
it != vNodeElementIdx.end();
695711
++it, i++) {
696-
unsigned long ElemIdx = ((*it) >> 3);
697-
const std::map<long, App::Color>::const_iterator pos = ElementColorMap.find(ElemIdx);
698-
if (pos == ElementColorMap.end()) {
699-
colors[i] = SbColor(0, 1, 0);
700-
}
701-
else {
702-
colors[i] = SbColor(pos->second.r, pos->second.g, pos->second.b);
703-
}
712+
colors[i] = SbColor(colorVec[*it].r, colorVec[*it].g, colorVec[*it].b);
704713
}
705714

706715
pcShapeMaterial->diffuseColor.finishEditing();
707716
}
708717

709-
void ViewProviderFemMesh::resetColorByElementId()
718+
void ViewProviderFemMesh::resetColorByNodeId()
719+
{
720+
const App::Color& c = ShapeAppearance.getDiffuseColor();
721+
NodeColorArray.setValue(c);
722+
}
723+
724+
void ViewProviderFemMesh::setColorByNodeId(
725+
const std::map<std::vector<long>, App::Color>& elemColorMap)
710726
{
727+
setColorByIdHelper(elemColorMap, vNodeElementIdx, 0, NodeColorArray);
728+
}
729+
730+
void ViewProviderFemMesh::setColorByElementId(
731+
const std::map<std::vector<long>, App::Color>& elemColorMap)
732+
{
733+
setColorByIdHelper(elemColorMap, vFaceElementIdx, 3, ElementColorArray);
734+
}
735+
736+
void ViewProviderFemMesh::setColorByIdHelper(
737+
const std::map<std::vector<long>, App::Color>& elemColorMap,
738+
const std::vector<unsigned long>& vElementIdx,
739+
int rShift,
740+
App::PropertyColorList& prop)
741+
{
742+
std::vector<App::Color> vecColor(vElementIdx.size());
743+
std::map<long, const App::Color*> colorMap;
744+
for (const auto& m : elemColorMap) {
745+
for (long i : m.first) {
746+
colorMap[i] = &m.second;
747+
}
748+
}
749+
750+
App::Color baseDif = ShapeAppearance.getDiffuseColor();
751+
int i = 0;
752+
for (std::vector<unsigned long>::const_iterator it = vElementIdx.begin();
753+
it != vElementIdx.end();
754+
++it, i++) {
755+
unsigned long ElemIdx = ((*it) >> rShift);
756+
const std::map<long, const App::Color*>::const_iterator pos = colorMap.find(ElemIdx);
757+
vecColor[i] = pos == colorMap.end() ? baseDif : *pos->second;
758+
}
759+
760+
prop.setValue(vecColor);
761+
}
762+
763+
void ViewProviderFemMesh::setMaterialOverall() const
764+
{
765+
const App::Material& mat = ShapeAppearance[0];
766+
App::Color baseDif = mat.diffuseColor;
767+
App::Color baseAmb = mat.ambientColor;
768+
App::Color baseSpe = mat.specularColor;
769+
App::Color baseEmi = mat.emissiveColor;
770+
float baseShi = mat.shininess;
771+
float baseTra = mat.transparency;
772+
711773
pcMatBinding->value = SoMaterialBinding::OVERALL;
712774
pcShapeMaterial->diffuseColor.setNum(0);
775+
pcShapeMaterial->ambientColor.setNum(0);
776+
pcShapeMaterial->specularColor.setNum(0);
777+
pcShapeMaterial->emissiveColor.setNum(0);
778+
pcShapeMaterial->shininess.setNum(0);
779+
pcShapeMaterial->transparency.setNum(0);
780+
pcShapeMaterial->diffuseColor.setValue(baseDif.r, baseDif.g, baseDif.b);
781+
pcShapeMaterial->ambientColor.setValue(baseAmb.r, baseAmb.g, baseAmb.b);
782+
pcShapeMaterial->specularColor.setValue(baseSpe.r, baseSpe.g, baseSpe.b);
783+
pcShapeMaterial->emissiveColor.setValue(baseEmi.r, baseEmi.g, baseEmi.b);
784+
pcShapeMaterial->shininess.setValue(baseShi);
785+
pcShapeMaterial->transparency.setValue(baseTra);
786+
787+
pcFaces->touch();
788+
789+
return;
790+
}
791+
792+
void ViewProviderFemMesh::setMaterialByColorArray(
793+
const App::PropertyColorList* prop,
794+
const std::vector<unsigned long>& vElementIdx) const
795+
{
796+
const App::Material& baseMat = ShapeAppearance[0];
797+
App::Color baseDif = baseMat.diffuseColor;
798+
App::Color baseAmb = baseMat.ambientColor;
799+
App::Color baseSpe = baseMat.specularColor;
800+
App::Color baseEmi = baseMat.emissiveColor;
801+
float baseShi = baseMat.shininess;
802+
float baseTra = baseMat.transparency;
803+
804+
// resizing and writing the color vector:
805+
std::vector<App::Color> vecColor = prop->getValue();
806+
size_t elemSize = vElementIdx.size();
807+
if (vecColor.size() == 1) {
808+
pcMatBinding->value = SoMaterialBinding::OVERALL;
809+
pcShapeMaterial->diffuseColor.setNum(0);
810+
pcShapeMaterial->ambientColor.setNum(0);
811+
pcShapeMaterial->specularColor.setNum(0);
812+
pcShapeMaterial->emissiveColor.setNum(0);
813+
pcShapeMaterial->shininess.setNum(0);
814+
pcShapeMaterial->transparency.setNum(0);
815+
pcShapeMaterial->diffuseColor.setValue(vecColor[0].r, vecColor[0].g, vecColor[0].b);
816+
pcShapeMaterial->ambientColor.setValue(baseAmb.r, baseAmb.g, baseAmb.b);
817+
pcShapeMaterial->specularColor.setValue(baseSpe.r, baseSpe.g, baseSpe.b);
818+
pcShapeMaterial->emissiveColor.setValue(baseEmi.r, baseEmi.g, baseEmi.b);
819+
pcShapeMaterial->shininess.setValue(baseShi);
820+
pcShapeMaterial->transparency.setValue(baseTra);
821+
822+
return;
823+
}
824+
825+
if (prop == &ElementColorArray) {
826+
pcMatBinding->value = SoMaterialBinding::PER_FACE;
827+
}
828+
else if (prop == &NodeColorArray) {
829+
pcMatBinding->value = SoMaterialBinding::PER_VERTEX_INDEXED;
830+
}
831+
832+
pcShapeMaterial->diffuseColor.setNum(elemSize);
833+
SbColor* diffuse = pcShapeMaterial->diffuseColor.startEditing();
834+
pcShapeMaterial->ambientColor.setNum(elemSize);
835+
SbColor* ambient = pcShapeMaterial->ambientColor.startEditing();
836+
pcShapeMaterial->specularColor.setNum(elemSize);
837+
SbColor* specular = pcShapeMaterial->specularColor.startEditing();
838+
pcShapeMaterial->emissiveColor.setNum(elemSize);
839+
SbColor* emissive = pcShapeMaterial->emissiveColor.startEditing();
840+
pcShapeMaterial->shininess.setNum(elemSize);
841+
float* shininess = pcShapeMaterial->shininess.startEditing();
842+
pcShapeMaterial->transparency.setNum(elemSize);
843+
float* transparency = pcShapeMaterial->transparency.startEditing();
844+
845+
vecColor.resize(elemSize, baseDif);
846+
847+
int i = 0;
848+
for (const App::Color& c : vecColor) {
849+
diffuse[i] = SbColor(c.r, c.g, c.b);
850+
ambient[i] = SbColor(baseAmb.r, baseAmb.g, baseAmb.b);
851+
specular[i] = SbColor(baseSpe.r, baseSpe.g, baseSpe.b);
852+
emissive[i] = SbColor(baseEmi.r, baseEmi.g, baseEmi.b);
853+
shininess[i] = baseShi;
854+
transparency[i] = baseTra;
855+
++i;
856+
}
857+
858+
pcShapeMaterial->diffuseColor.finishEditing();
859+
pcShapeMaterial->ambientColor.finishEditing();
860+
pcShapeMaterial->specularColor.finishEditing();
861+
pcShapeMaterial->emissiveColor.finishEditing();
862+
pcShapeMaterial->shininess.finishEditing();
863+
pcShapeMaterial->transparency.finishEditing();
864+
865+
pcFaces->touch();
866+
}
867+
868+
void ViewProviderFemMesh::resetColorByElementId()
869+
{
713870
const App::Color& c = ShapeAppearance.getDiffuseColor();
714-
pcShapeMaterial->diffuseColor.setValue(c.r, c.g, c.b);
871+
ElementColorArray.setValue(c);
715872
}
716873

717874
// ----------------------------------------------------------------------------

0 commit comments

Comments
 (0)