Mesh: implement PropertyMaterial

This commit is contained in:
wmayer
2022-10-23 19:49:46 +02:00
parent 094ec8cb59
commit 86bf176b1f
6 changed files with 444 additions and 2 deletions

View File

@@ -74,6 +74,7 @@ PyMOD_INIT_FUNC(Mesh)
// init Type system
Mesh::PropertyNormalList ::init();
Mesh::PropertyCurvatureList ::init();
Mesh::PropertyMaterial ::init();
Mesh::PropertyMeshKernel ::init();
Mesh::MeshObject ::init();

View File

@@ -99,6 +99,32 @@ struct QUAD {int iV[4];};
// --------------------------------------------------------------
bool Material::operator == (const Material& mat) const
{
if (binding != mat.binding)
return false;
if (ambientColor != mat.ambientColor)
return false;
if (diffuseColor != mat.diffuseColor)
return false;
if (specularColor != mat.specularColor)
return false;
if (emissiveColor != mat.emissiveColor)
return false;
if (shininess != mat.shininess)
return false;
if (transparency != mat.transparency)
return false;
return true;
}
bool Material::operator != (const Material& mat) const
{
return !operator==(mat);
}
// --------------------------------------------------------------
std::vector<std::string> MeshInput::supportedMeshFormats()
{
std::vector<std::string> fmt;

View File

@@ -83,6 +83,9 @@ struct MeshExport Material
std::vector<App::Color> emissiveColor; /**< Defines the emissive color. */
std::vector<float> shininess;
std::vector<float> transparency;
bool operator == (const Material& mat) const;
bool operator != (const Material& mat) const;
};
struct MeshExport Group

View File

@@ -46,6 +46,7 @@ using namespace Mesh;
TYPESYSTEM_SOURCE(Mesh::PropertyNormalList, App::PropertyLists)
TYPESYSTEM_SOURCE(Mesh::PropertyCurvatureList , App::PropertyLists)
TYPESYSTEM_SOURCE(Mesh::PropertyMaterial , App::Property)
TYPESYSTEM_SOURCE(Mesh::PropertyMeshKernel , App::PropertyComplexGeoData)
PropertyNormalList::PropertyNormalList()
@@ -426,6 +427,323 @@ void PropertyCurvatureList::Paste(const App::Property &from)
// ----------------------------------------------------------------------------
const MeshCore::Material& PropertyMaterial::getValue() const
{
return _material;
}
MeshCore::MeshIO::Binding PropertyMaterial::getBinding() const
{
return _material.binding;
}
const std::vector<App::Color>& PropertyMaterial::getAmbientColor() const
{
return _material.ambientColor;
}
const std::vector<App::Color>& PropertyMaterial::getDiffuseColor() const
{
return _material.diffuseColor;
}
const std::vector<App::Color>& PropertyMaterial::getSpecularColor() const
{
return _material.specularColor;
}
const std::vector<App::Color>& PropertyMaterial::getEmissiveColor() const
{
return _material.emissiveColor;
}
const std::vector<float>& PropertyMaterial::getShininess() const
{
return _material.shininess;
}
const std::vector<float>& PropertyMaterial::getTransparency() const
{
return _material.transparency;
}
void PropertyMaterial::setValue(const MeshCore::Material& value)
{
aboutToSetValue();
_material = value;
hasSetValue();
}
void PropertyMaterial::setAmbientColor(const std::vector<App::Color>& value)
{
aboutToSetValue();
_material.ambientColor = value;
hasSetValue();
}
void PropertyMaterial::setDiffuseColor(const std::vector<App::Color>& value)
{
aboutToSetValue();
_material.diffuseColor = value;
hasSetValue();
}
void PropertyMaterial::setSpecularColor(const std::vector<App::Color>& value)
{
aboutToSetValue();
_material.specularColor = value;
hasSetValue();
}
void PropertyMaterial::setEmissiveColor(const std::vector<App::Color>& value)
{
aboutToSetValue();
_material.emissiveColor = value;
hasSetValue();
}
void PropertyMaterial::setShininess(const std::vector<float>& value)
{
aboutToSetValue();
_material.shininess = value;
hasSetValue();
}
void PropertyMaterial::setTransparency(const std::vector<float>& value)
{
aboutToSetValue();
_material.transparency = value;
hasSetValue();
}
void PropertyMaterial::setBinding(MeshCore::MeshIO::Binding bind)
{
aboutToSetValue();
_material.binding = bind;
hasSetValue();
}
PyObject* PropertyMaterial::getPyObject()
{
auto getColorList = [](const std::vector<App::Color>& color) {
Py::List list;
for (const auto& it : color) {
list.append(Py::TupleN(Py::Float(it.r),
Py::Float(it.g),
Py::Float(it.b)));
}
return list;
};
auto getFloatList = [](const std::vector<float>& value) {
Py::List list;
for (auto it : value) {
list.append(Py::Float(it));
}
return list;
};
Py::Dict dict;
dict.setItem("binding", Py::Long(static_cast<int>(_material.binding)));
dict.setItem("ambientColor", getColorList(_material.ambientColor));
dict.setItem("diffuseColor", getColorList(_material.diffuseColor));
dict.setItem("specularColor", getColorList(_material.specularColor));
dict.setItem("emissiveColor", getColorList(_material.emissiveColor));
dict.setItem("shininess", getFloatList(_material.shininess));
dict.setItem("transparency", getFloatList(_material.transparency));
return Py::new_reference_to(dict);
}
void PropertyMaterial::setPyObject(PyObject* obj)
{
auto getColorList = [](const Py::Dict& dict, const std::string& key) {
std::vector<App::Color> color;
if (dict.hasKey(key)) {
Py::Sequence list(dict.getItem(key));
color.reserve(list.size());
for (const auto& it : list) {
Py::Sequence tuple(it);
float r = static_cast<float>(Py::Float(tuple[0]));
float g = static_cast<float>(Py::Float(tuple[1]));
float b = static_cast<float>(Py::Float(tuple[2]));
color.emplace_back(r, g, b);
}
}
return color;
};
auto getFloatList = [](const Py::Dict& dict, const std::string& key) {
std::vector<float> value;
if (dict.hasKey(key)) {
Py::Sequence list(dict.getItem(key));
value.reserve(list.size());
for (const auto& it : list) {
value.push_back(static_cast<float>(Py::Float(it)));
}
}
return value;
};
try {
MeshCore::Material material;
Py::Dict dict(obj);
if (dict.hasKey("binding")) {
Py::Long binding(dict.getItem("binding"));
int bind = static_cast<int>(binding);
material.binding = static_cast<MeshCore::MeshIO::Binding>(bind);
}
material.ambientColor = getColorList(dict, "ambientColor");
material.diffuseColor = getColorList(dict, "diffuseColor");
material.specularColor = getColorList(dict, "specularColor");
material.emissiveColor = getColorList(dict, "emissiveColor");
material.shininess = getFloatList(dict, "shininess");
material.transparency = getFloatList(dict, "transparency");
setValue(material);
}
catch (Py::Exception& e) {
e.clear();
throw Base::TypeError("Not a dict with expected keys");
}
}
void PropertyMaterial::Save(Base::Writer& writer) const
{
if (!writer.isForceXML()) {
writer.Stream() << writer.ind() << "<Material file=\""
<< writer.addFile(getName(), this) << "\"/>" << std::endl;
}
}
void PropertyMaterial::Restore(Base::XMLReader& reader)
{
reader.readElement("Material");
if (reader.hasAttribute("file")) {
std::string file(reader.getAttribute("file"));
if (!file.empty()) {
// initiate a file read
reader.addFile(file.c_str(), this);
}
}
}
void PropertyMaterial::SaveDocFile(Base::Writer &writer) const
{
Base::OutputStream str(writer.Stream());
auto saveColor = [&str](const std::vector<App::Color>& color) {
uint32_t count = static_cast<uint32_t>(color.size());
str << count;
for (const auto& it : color) {
str << it.getPackedValue();
}
};
auto saveFloat = [&str](const std::vector<float>& value) {
uint32_t count = static_cast<uint32_t>(value.size());
str << count;
for (const auto& it : value) {
str << it;
}
};
uint32_t bind = static_cast<uint32_t>(_material.binding);
str << bind;
saveColor(_material.ambientColor);
saveColor(_material.diffuseColor);
saveColor(_material.specularColor);
saveColor(_material.emissiveColor);
saveFloat(_material.shininess);
saveFloat(_material.transparency);
}
void PropertyMaterial::RestoreDocFile(Base::Reader &reader)
{
Base::InputStream str(reader);
auto restoreColor = [&str](std::vector<App::Color>& color) {
uint32_t count = 0;
str >> count;
color.resize(count);
for (auto& it : color) {
uint32_t value; // must be 32 bit long
str >> value;
it.setPackedValue(value);
}
};
auto restoreFloat = [&str](std::vector<float>& value) {
uint32_t count = 0;
str >> count;
value.resize(count);
for (auto& it : value) {
float valueF;
str >> valueF;
it = valueF;
}
};
MeshCore::Material material;
uint32_t bind = 0;
str >> bind;
material.binding = static_cast<MeshCore::MeshIO::Binding>(bind);
restoreColor(material.ambientColor);
restoreColor(material.diffuseColor);
restoreColor(material.specularColor);
restoreColor(material.emissiveColor);
restoreFloat(material.shininess);
restoreFloat(material.transparency);
setValue(material);
}
const char* PropertyMaterial::getEditorName() const
{
return "";
}
App::Property* PropertyMaterial::Copy() const
{
PropertyMaterial *prop = new PropertyMaterial();
prop->_material = _material;
return prop;
}
void PropertyMaterial::Paste(const Property& from)
{
aboutToSetValue();
using ObjectType = std::remove_pointer<decltype(this)>::type;
_material = dynamic_cast<const ObjectType&>(from)._material;
hasSetValue();
}
unsigned int PropertyMaterial::getMemSize() const
{
auto size = _material.ambientColor.size() +
_material.diffuseColor.size() +
_material.emissiveColor.size() +
_material.shininess.size() +
_material.specularColor.size() +
_material.transparency.size() +
_material.library.size() + sizeof(_material);
return static_cast<unsigned int>(size);
}
bool PropertyMaterial::isSame(const App::Property& other) const
{
if (&other == this)
return true;
return getTypeId() == other.getTypeId()
&& getValue() == static_cast<decltype(this)>(&other)->getValue();
}
// ----------------------------------------------------------------------------
PropertyMeshKernel::PropertyMeshKernel()
: _meshObject(new MeshObject()), meshPyObject(nullptr)
{

View File

@@ -37,8 +37,9 @@
#include <App/PropertyStandard.h>
#include <App/PropertyGeo.h>
#include "Core/MeshKernel.h"
#include "Mesh.h"
#include <Mod/Mesh/App/Core/MeshKernel.h>
#include <Mod/Mesh/App/Core/MeshIO.h>
#include <Mod/Mesh/App/Mesh.h>
namespace Mesh
@@ -164,6 +165,57 @@ private:
std::vector<CurvatureInfo> _lValueList;
};
/** Mesh material properties
*/
class MeshExport PropertyMaterial : public App::Property
{
TYPESYSTEM_HEADER_WITH_OVERRIDE();
public:
PropertyMaterial() = default;
~PropertyMaterial() override = default;
/** Sets the property
*/
void setValue(const MeshCore::Material &mat);
void setAmbientColor(const std::vector<App::Color>& col);
void setDiffuseColor(const std::vector<App::Color>& col);
void setSpecularColor(const std::vector<App::Color>& col);
void setEmissiveColor(const std::vector<App::Color>& col);
void setShininess(const std::vector<float>&);
void setTransparency(const std::vector<float>&);
void setBinding(MeshCore::MeshIO::Binding);
const MeshCore::Material& getValue() const;
const std::vector<App::Color>& getAmbientColor() const;
const std::vector<App::Color>& getDiffuseColor() const;
const std::vector<App::Color>& getSpecularColor() const;
const std::vector<App::Color>& getEmissiveColor() const;
const std::vector<float>& getShininess() const;
const std::vector<float>& getTransparency() const;
MeshCore::MeshIO::Binding getBinding() const;
PyObject* getPyObject() override;
void setPyObject(PyObject*) override;
void Save (Base::Writer& writer) const override;
void Restore(Base::XMLReader& reader) override;
void SaveDocFile(Base::Writer& writer) const override;
void RestoreDocFile(Base::Reader& reader) override;
const char* getEditorName() const override;
Property* Copy() const override;
void Paste(const Property& from) override;
unsigned int getMemSize() const override;
bool isSame(const Property& other) const override;
private:
MeshCore::Material _material;
};
/** The mesh kernel property class.
* @author Werner Mayer
*/

View File

@@ -8,6 +8,7 @@ import os
import sys
import io
import FreeCAD, unittest, Mesh
import MeshEnums
from FreeCAD import Base
import time, tempfile, math
# http://python-kurs.eu/threads.php
@@ -681,3 +682,44 @@ class MeshSubElement(unittest.TestCase):
def tearDown(self):
pass
class MeshProperty(unittest.TestCase):
def setUp(self):
self.doc = FreeCAD.newDocument("MeshTest")
def tearDown(self):
FreeCAD.closeDocument(self.doc.Name)
def testMaterial(self):
mesh = self.doc.addObject("Mesh::Feature", "Sphere")
mesh.Mesh = Mesh.createBox(1.0, 1.0, 1.0)
len1 = int(mesh.Mesh.CountFacets / 2)
len2 = int(mesh.Mesh.CountFacets - len1)
material = {"transparency" : [0.2] * len1 + [0.8] * len2}
material["binding"] = MeshEnums.Binding.PER_FACE
material["ambientColor"] = [(1,0,0)] * (len1 + len2)
material["diffuseColor"] = [(0,1,0)] * (len1 + len2)
material["specularColor"] = [(0,0,1)] * (len1 + len2)
material["emissiveColor"] = [(1,1,1)] * (len1 + len2)
material["shininess"] = [0.3] * (len1 + len2)
mesh.addProperty("Mesh::PropertyMaterial", "Material")
mesh.Material = material
TempPath = tempfile.gettempdir()
SaveName = TempPath + os.sep + "mesh_with_material.FCStd"
self.doc.saveAs(SaveName)
FreeCAD.closeDocument(self.doc.Name)
self.doc = FreeCAD.openDocument(SaveName)
mesh2 = self.doc.Sphere
material2 = mesh2.Material
self.assertEqual(int(material2["binding"]), int(MeshEnums.Binding.PER_FACE))
self.assertEqual(len(material2["ambientColor"]), len1 + len2)
self.assertEqual(len(material2["diffuseColor"]), len1 + len2)
self.assertEqual(len(material2["specularColor"]), len1 + len2)
self.assertEqual(len(material2["emissiveColor"]), len1 + len2)
self.assertEqual(len(material2["shininess"]), len1 + len2)
self.assertEqual(len(material2["transparency"]), len1 + len2)