From d876e188082c314299f338799512965f3e25c03b Mon Sep 17 00:00:00 2001 From: David Carter Date: Tue, 1 Oct 2024 01:15:16 -0400 Subject: [PATCH] Materials: Correct DiffuseColor custom attribute Custom attributes were modified to maintain the behaviour of setting transparencies using the DiffuseColor alpha channels --- src/App/PropertyStandard.cpp | 10 +++ src/App/PropertyStandard.h | 1 + src/Mod/Material/CMakeLists.txt | 2 + src/Mod/Material/InitGui.py | 2 + src/Mod/Material/TestMaterialsGui.py | 23 +++++++ .../materialtests/TestMaterialDocument.py | 69 +++++++++++++++++++ src/Mod/Part/Gui/ViewProviderExt.cpp | 1 - src/Mod/Part/Gui/ViewProviderPartExtPyImp.cpp | 22 +++++- 8 files changed, 127 insertions(+), 3 deletions(-) create mode 100644 src/Mod/Material/TestMaterialsGui.py create mode 100644 src/Mod/Material/materialtests/TestMaterialDocument.py diff --git a/src/App/PropertyStandard.cpp b/src/App/PropertyStandard.cpp index 2de7de1fb9..2618506f2d 100644 --- a/src/App/PropertyStandard.cpp +++ b/src/App/PropertyStandard.cpp @@ -3099,6 +3099,16 @@ float PropertyMaterialList::getTransparency(int index) const return _lValueList[index].transparency; } +std::vector PropertyMaterialList::getTransparencies() const +{ + std::vector list; + for (auto& material : _lValueList) { + list.push_back(material.transparency); + } + + return list; +} + Material PropertyMaterialList::getPyValue(PyObject* value) const { if (PyObject_TypeCheck(value, &(MaterialPy::Type))) { diff --git a/src/App/PropertyStandard.h b/src/App/PropertyStandard.h index 41bd8257ee..3a8068f486 100644 --- a/src/App/PropertyStandard.h +++ b/src/App/PropertyStandard.h @@ -1176,6 +1176,7 @@ public: float getTransparency() const; float getTransparency(int index) const; + std::vector getTransparencies() const; PyObject* getPyObject() override; diff --git a/src/Mod/Material/CMakeLists.txt b/src/Mod/Material/CMakeLists.txt index 43eb11f17e..be887820a1 100644 --- a/src/Mod/Material/CMakeLists.txt +++ b/src/Mod/Material/CMakeLists.txt @@ -10,6 +10,7 @@ SET(MaterialScripts_Files importFCMat.py MaterialEditor.py TestMaterialsApp.py + TestMaterialsGui.py Templatematerial.yml ) @@ -292,6 +293,7 @@ set(MaterialTest_Files materialtests/TestModels.py materialtests/TestMaterials.py materialtests/TestMaterialCreation.py + materialtests/TestMaterialDocument.py materialtests/TestMaterialFilter.py ) diff --git a/src/Mod/Material/InitGui.py b/src/Mod/Material/InitGui.py index 898d045b01..04c2102064 100644 --- a/src/Mod/Material/InitGui.py +++ b/src/Mod/Material/InitGui.py @@ -45,3 +45,5 @@ class MaterialWorkbench(Gui.Workbench): Gui.addWorkbench(MaterialWorkbench()) + +FreeCAD.__unit_test__ += [ "TestMaterialsGui" ] diff --git a/src/Mod/Material/TestMaterialsGui.py b/src/Mod/Material/TestMaterialsGui.py new file mode 100644 index 0000000000..6798b3b7ab --- /dev/null +++ b/src/Mod/Material/TestMaterialsGui.py @@ -0,0 +1,23 @@ +#************************************************************************** +# Copyright (c) 2023 David Carter * +# * +# This file is part of the FreeCAD CAx development system. * +# * +# This program is free software; you can redistribute it and/or modify * +# it under the terms of the GNU Lesser General Public License (LGPL) * +# as published by the Free Software Foundation; either version 2 of * +# the License, or (at your option) any later version. * +# for detail see the LICENCE text file. * +# * +# FreeCAD 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 FreeCAD; if not, write to the Free Software * +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# USA * +#************************************************************************** + +from materialtests.TestMaterialDocument import DocumentTestCases diff --git a/src/Mod/Material/materialtests/TestMaterialDocument.py b/src/Mod/Material/materialtests/TestMaterialDocument.py new file mode 100644 index 0000000000..821cec09e7 --- /dev/null +++ b/src/Mod/Material/materialtests/TestMaterialDocument.py @@ -0,0 +1,69 @@ +# *************************************************************************** +# * * +# * Copyright (c) 2024 FreeCAD Project Association * +# * * +# * This file is part of FreeCAD. * +# * * +# * FreeCAD is free software: you can redistribute it and/or modify it * +# * under the terms of the GNU Lesser General Public License as * +# * published by the Free Software Foundation, either version 2.1 of the * +# * License, or (at your option) any later version. * +# * * +# * FreeCAD 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 * +# * Lesser General Public License for more details. * +# * * +# * You should have received a copy of the GNU Lesser General Public * +# * License along with FreeCAD. If not, see * +# * . * +# * * +# *************************************************************************** + +import unittest +import FreeCAD + +class DocumentTestCases(unittest.TestCase): + """ + Test class for FreeCAD material tests that need a document + """ + + def setUp(self): + self.doc = FreeCAD.newDocument() + + def tearDown(self): + FreeCAD.closeDocument(self.doc.Name) + + def testApplyDiffuseColorCheckShapeAppearance(self): + """ Test that applying a DiffuseColor with transparency results in a correct ShapeAppearance """ + dif_col_1 = (1.0, 1.0, 0.0, 0.0) # yellow 0% transparent + dif_col_2 = (1.0, 0.0, 0.0, 0.5) # red 50% transparent + dif_col = [dif_col_1] + [dif_col_2] + 4 * [dif_col_1] + + obj = self.doc.addObject("Part::Box") + vobj = obj.ViewObject + vobj.DiffuseColor = dif_col + + self.assertEqual( + [m.DiffuseColor[:3] + (m.Transparency, ) for m in vobj.ShapeAppearance], + vobj.DiffuseColor + ) + + def testApplyShapeAppearanceCheckDiffuseColor(self): + """ Test that applying a ShapeAppearance with transparency results in a correct DiffuseColor """ + sapp_1 = FreeCAD.Material() + sapp_1.DiffuseColor = (0.0, 1.0, 1.0, 1.0) # cyan + sapp_1.Transparency = 0.0 # 0% transparent + sapp_2 = FreeCAD.Material() + sapp_2.DiffuseColor = (0.0, 1.0, 0.0, 1.0) # green + sapp_2.Transparency = 0.3 # 30% transparent + sapp = [sapp_1] + [sapp_2] + 4 * [sapp_1] + + obj = self.doc.addObject("Part::Box") + vobj = obj.ViewObject + vobj.ShapeAppearance = sapp + + self.assertEqual( + [m.DiffuseColor[:3] + (m.Transparency, ) for m in vobj.ShapeAppearance], + vobj.DiffuseColor + ) diff --git a/src/Mod/Part/Gui/ViewProviderExt.cpp b/src/Mod/Part/Gui/ViewProviderExt.cpp index 1233ca4ea1..81b1b5e59a 100644 --- a/src/Mod/Part/Gui/ViewProviderExt.cpp +++ b/src/Mod/Part/Gui/ViewProviderExt.cpp @@ -346,7 +346,6 @@ void ViewProviderPartExt::onChanged(const App::Property* prop) std::vector transparencies; transparencies.resize(static_cast(colors.size())); for (int i = 0; i < static_cast(colors.size()); i++) { - Base::Console().Log("%d: %f\n", i, colors[i].a); transparencies[i] = colors[i].a; colors[i].a = 1.0; } diff --git a/src/Mod/Part/Gui/ViewProviderPartExtPyImp.cpp b/src/Mod/Part/Gui/ViewProviderPartExtPyImp.cpp index 48885e5776..adc59b9b98 100644 --- a/src/Mod/Part/Gui/ViewProviderPartExtPyImp.cpp +++ b/src/Mod/Part/Gui/ViewProviderPartExtPyImp.cpp @@ -51,7 +51,15 @@ PyObject* ViewProviderPartExtPy::getCustomAttributes(const char* attr) const if (strcmp(attr, "DiffuseColor") == 0) { // Get the color properties App::PropertyColorList prop; - prop.setValues(vp->ShapeAppearance.getDiffuseColors()); + + // v0.21 used the alpha channel to store transparency values + std::vector colors = vp->ShapeAppearance.getDiffuseColors(); + std::vector transparencies = vp->ShapeAppearance.getTransparencies(); + for (int i = 0; i < static_cast(colors.size()); i++) { + colors[i].a = transparencies[i]; + } + + prop.setValues(colors); return prop.getPyObject(); } return nullptr; @@ -64,7 +72,17 @@ int ViewProviderPartExtPy::setCustomAttributes(const char* attr, PyObject* obj) // Set the color properties App::PropertyColorList prop; prop.setPyObject(obj); - vp->ShapeAppearance.setDiffuseColors(prop.getValues()); + + // v0.21 used the alpha channel to store transparency values + std::vector colors = prop.getValues(); + std::vector transparencies; + transparencies.resize(static_cast(colors.size())); + for (int i = 0; i < static_cast(colors.size()); i++) { + transparencies[i] = colors[i].a; + colors[i].a = 1.0; + } + vp->ShapeAppearance.setDiffuseColors(colors); + vp->ShapeAppearance.setTransparencies(transparencies); return 1; } return 0;