Mesh: implement PropertyMaterial
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user