Material improvements

Hi,

As mention in the Help forum, I’ve started working on better material support in FreeCAD. These are the changes/additions I want to implement:

  1. Extend and modify the Material class to support arbitrary, but pre-defined, properties.

This is done by adding a vector of boost::any variables. This will provide a type-safe way of accessing various properties, minimizing conversion code throughout FreeCAD. The currently existing member variables are replaced by functions calls accessing this vector. These should be exposed in python as normal attributes.

  1. Add a material property to the class/classes that represent a solid.

This property needs to handle the material for the solid itself, but also the surface. This is done by having a single reference for the solid, and a map of faces → materials for the surface. This makes it possible to color different faces of a solid. Also, each face may have multiple materials (e.g paint + silk print).

  1. Add infrastructure for a material database.

This is done to unify access to the materials. Two main classes are defined: MaterialDatabase and MaterialSource. A database is basically a collection of sources. One of the sources will be the standard FCmat files already defined and used.

I don’t think these changes will be very intrusive to the already existing material support in FreeCAD; in fact my gut feeling is that this will simplify things, and code in other workbenches can be minimized.

For the moment I don’t have any code worth sharing; what I have barely compiles, doesn’t have all the functions, and most likely doesn’t work properly yet :slight_smile:

Eivind

Hello Eivind,

Do you mean that we could apply a bitmap image on a face, and have it stored into the model?

That is my goal, but I don’t know if that is possible or not with the current graphical framework FreeCAD uses.

Eivind

Excellent plan!!!

I agree with you, this could simplify a lot material handling throughout FreeCAD. At the moment we have many scripts (in Material, in Arch, in FEM,…) that all do a lot of the same things. From my point of view, the most important points are:

  • proper unit handling (values in material cards are often expressed in different units that are not always well handled ATM)
  • unified way to work with several materials per object (both FEM and Arch do it in different ways)
  • unified way to handle material objects in a FreeCAD document (currently objects that have a material in arch or fem use a propertylink to link to a material object that stores the material info itself, but both have differetn ways to edit/update the material object)

I think it is possible, but you might need to tweak the ViewProviders a lot (create many different coin materials, textures, etc). Supporting textures will also bring a lot of additional issues (texture size and orientation, also called mapping, etc). I would definitely separate the two subjects.

Thank you! :slight_smile:

In C++ this is handled in a type-safe way; boost::any does this. In Python, the C++ types are now mirrored, so a Quantity type in C++ will be a Quantity in Python as well. Same for all other types. To make this work, the property name and type must be registered in the database. Currently this is done compile-time. This is not ideal, but I need to have conversion functions from string to boost::any and from boost::any to PyObject (and vice versa). New types can in principle be defined by modules, but I haven’t exposed the interface for this yet.

In my design that is 1 material per solid + n surface materials. A surface material may span the complete surface, or just a face. Also, a face may contain multiple surface materials (stacked in order). Does that cover the needs for Arch and FEM?

I think the material(s) should be a property of the solid. Is Part::Feature the place to put this? This is where the shape is stored, and I think this is the most low-level solid in FreeCAD?

This is not first priority :slight_smile:

Another question regarding the Python material interface. Material today have both a constructor and a set method. This doesn’t fit very well into my current plan. How much will things break if we remove these two functions? They would basically be replaced by a database access to get the materials, something like:

mat = db.getMaterial(“GOLD”)

to get an existing one, or

mat = source.createMaterial(“PLATINUM”)

to create a new material in the given source.

Material properties are accessed like

mat.YoungsModulus

in Python, and something like

boost::any_cast(mat->getProperty(“YoungsModulus”)) in C++.

(In C++ properties can be indexed by a numeric ID as well, to speed things up).

There will be different sources. I have defined three already:

  • DefaultMaterialSource: All legacy materials for visualization. These only contain the color definitions.
  • FileMaterialSource: This contains materials in FCMat format.
  • DocumentMaterialSource: This may contain materials created for the document owning the source. In its most basic use, if you modify the color of an object, a copy will be stored here (not implemented yet!).

FileMaterialSource may be added multiple times, so it can be used for both system and user-defined materials.

Eivind

What about multi-solid objects? I think for example, to a window, which has metal (or wood) parts, and glass. Both Arch and FEM use a lot of these compounds (or compsolids soon!). One might hook the material to a toposhape, which might bring a lot of problems, not sure it’s a good idea to go that way.

Maybe the best way would be to work a bit like the DiffuseColor property (an array of materials). That might require more thinking, though. Not sure we want one item in the array for each face… Also what happens for objects with non-solid shapes, etc.

I think your changes to the python API would not be a big problem,ATM both Arch and FEM are still in a state where doing those changes would be easy, specially if it’s for the greater good ( mat.YoungsModulus for example :slight_smile: )

Your ideas sounds great to me eivind!

+1 to yoriks post.

Managing the materials in a building modell will be really a challange … Just some ideas in the regard of solid (volume) material …

I’m not really sure yet if we should only allow one material for an volume object (solid or whatever) In real world design off a building I can imagin dozens of attributes for materials. If only one attribute is different one has to use a different material. Resulting in dozens different materials. An simple example.

For most people involved in planing a building concrete is one material. This is fine for all people and for all building models of this building except one person, me. I use in my calculations (FEM) two or three differend concrete materials with a different youngs modulus. But as said before all others do not need to know these are different concrete types. It is even not visible on the drawings just in my calculation.

Normally this does not matters, because every person (architect, structural engineer, cost calculator, light engineer, electrical engineer, water engineer, what ever engineer is needed for a building ) has its own software, its own building modell and its own materials. FreeCAD is the only software (at the moment) which could combines different models and thus different materials from different persons in one building model.

Adding a material property is something, that is definitely needed.
How to achieve this also in case of compsolids is a good question. Do have compsolids more than one volume, like a shape has more than one face?

I found some time ago this post from ickby: http://forum.freecadweb.org/viewtopic.php?f=10&t=16021
where I started to think, if this can also be used to add all the missing properties in FreeCAD:

  • material with all its subproperties: densitiy, youngs modulus, color, etc. wood would also need a direction, as it is an anisotropic material.
  • face properties like threads or knurling (used for example in step-files)
  • organisational properies like part-numbers, material cost …
  • manufacturing properties like tolerances, surface finish etc.

Ulrich

Found the answer. A compsolid has more than one “Solid”. So the material property has to be a subproperty of the Solid.

Ulrich

Thank you for your feedback. This can be achieved by using inheritance; materials have a Father property to specify that. I already have support for this. In this way it is possible to override properties like youngs modulus. However, inheritance may not be the right answer, so for the solid specification, I think composition of several materials is the way to go. The composition should we stacked, so it is possible to override other properties. I think inheritance and stacked composition will solve most problems of material specialization.

For surface materials, I think we shall interpret the stack as several individual materials; the intention here is to say something about the actual manufacturing, e.g paint, silk-print, special coatings, etc. To override certain properties here will require inheritance, but I think that is ok.

Eivind

Wouldn’t a window in principle be an assembly of multiple parts? In that case each part would have their own material. However, as I understand we now have compsolids, which are actual multiple solids. To support this, the material property needs to be able to address multiple separate solids. If we also stack materials as suggested in my previous post, a solid material specification will be a vector of vectors; each solid has a vector of materials. For surfaces, I would create a map (solid, face) → vector of materials.

Eivind

The material framework can be used (or abused) for this! Currently it’s just a matter of registering new properties. This has to be done compile-time, but can be done by individual (C++) modules.

Eivind

To me the plan looks very good Eivind! Indeed there are many different cases, but it seems that what you are proposing will be pretty flexible. This topic is actually good to gather these cases…

Hi all,

I’ve had some progress with my material code, and have some code to share now. Please notice that this is in the very early stages. The code is at https://github.com/eivindkv/free-cad-code/tree/Material , almost rebased to most recent master.

Things more or less done:

  • Added a MaterialDatabase class. This is the collection of various sources described below. Material queries happens from this database.
  • Added a DefaultMaterialSource class. This source is read-only and contains the original pre-defined materials that could be selected in FreeCAD. It also contains a DEFAULT material, that all other materials can inherit from, to ensure that visual properties are defined.
  • Added a DocumentMaterialSource class. Per-document materials are stored here. If visualization materials are changed, a copy is stored here.
  • Added a FileMaterialSource class. FCMat materials cards are provided by this source. Multiple sources may be added (system/user).
  • Added a PropertyPartMaterial class. This class and its helper classes encapsulates materials for solids and surfaces.
  • Added a PropertyPartMaterial member Material to Part::Feature, along with its Shape.

I’ve been focusing on the data structure part now; almost nothing is done on the Gui part, except propagating material colors from the Material property to the view provider, so the colors of the parts change.

I have also added a Python interface (this is what I actually use for testing), and a typical use-case could be:

App.ActiveDocument.Box.Material.setSolidMaterial(0, “PLA”);

This will assign the PLA material to solid 0 of Box. Properties can then be queried, e.g

App.ActiveDocument.Box.Material.Solid[0].YoungsModulus

Surface materials are accessed as e.g

App.ActiveDocument.Box.Material.Solid[0].setSurfaceMaterial(0, “GOLD”)

(provided that Solid[0] has been set first).

The material databases are accessed either at App.getMaterialDatabase() or doc.MaterialDatabase (ideally they should have the same syntax; something for later). The material database in App is the application-wide database, so adding/removing/editing materials should be possible to do without an open document. The material database in the document links to the application-wide one, but also provides a private material source for materials specific for the document.

Please let me know what you think.

Eivind

I just browsed through your code Eivind, that’s fantastic! (now I need to test…)

Awesome that you managed to unify all the bits and pieces of different material implementations throughout FreeCAD under one structure… that’s really impressive! I like that the Material property is independent of the Shape property. So you can do App.ActiveDocument.Box.Material.setSolidMaterial(2, “PLA”); regardless of if there is a solid nr. 2 or not. That seems pretty solid to me. I also like the solids/surfaces materials, it seemed too much for me when you first talked about it, but I begin to see the picture, you have “generic” surface materials for all the non-solid situations (Mesh, Part shells, etc), and also solid materials that are very useful for cases that enforce solids (PartDesign, Arch). That makes a lot of sense.

A coupe of questions:

  1. When creating a new document, a new material database is attached to that document, that contains a) legacy materials (the old Coin materials, bronze, gold, etc), b) the contents of system and user .FCMat cards and c) a place for document-specific materials. When saving the file, only part c) is saved together with the document, so when reopening the file, parts a) and b) are re-attached, right? What happens is a file is using a material card, but is opened on another machine that doesn’t have that card? Are all materials used in a document always copied to c)? I couldn’t find that…

  2. You say the App Material Database is editable too? How would that work? Where would that be saved?

  3. In your implementation, the properties that a material can have are hard-coded. No way for a user to add custom properties. I wonder if we should allow that or not… There are arguments on both sides…

  4. Did you think about possible duplicates? Like, if you have a steel stored in the document materials, and another same steel in FCMats… Should that be left to the user to sort out? Some apps do that kind of “decision” for you, for ex. if you have a file with a material named concrete, on opening a file, Revit will discard “your” concrete and use “his” concrete, and I really don’t like that…

Good Morning @eivindkv:
Thank you for 4.000 lines and 49 files of code. Incredible! :laughing:
I don’t know to read C++ code (the developer corner is not my territory!). However the material issue is transcendental for me and I would like to do a requests. Excuse me if I understood incorrectly your code or if I go too faster (‘this is in the very early stages:laughing: ).

You said:

Also, each face may have multiple materials (e.g paint + silk print)

Also, a face may contain multiple surface materials (stacked in order)

for the solid specification, I think composition of several materials is the way to go. The composition should we stacked

Your idea of MaterialStack applied to surfaces (faces) is amazing. This is similar to Radiance’s system, where a surface can carry an unlimited number of materials, plus an unlimited numbers of textures and patterns. This is the Everest talking about specification of surfaces. Congratulations!

My concerns is that I don’t clearly see the MaterialComposition.

1º) will the MaterialComposition have layers?

2º) could a solid have a MaterialComposition? The question is with a single solid, no with a compsolids.

3º) how will the thickness of every layer be specified?

Thank you very much

Do we need to make any changes to the material files or scripts that are currently in the master to operate on the files and material spreadsheet?

I’m talking about this [1] and this [2]

[1] https://github.com/FreeCAD/FreeCAD/tree/master/src/Mod/Material/StandardMaterial
[2] https://github.com/FreeCAD/FreeCAD/tree/master/src/Mod/Material/StandardMaterial/Tools

No, one of the data sources reads (and will eventually write) the FCMat format, so there’s no need to change this.

Eivind

Yes, the legacy materials and the system/user sources are always attached. Materials are not currently copied to the document; I’d like to avoid copying, as it makes the database fragmented and harder to maintain. The document-specific source is mainly now to store the colors of the solids/faces applied by the user. These need to be stored somewhere; before it was in the material property itself, but now each material object belongs to a source, thus it must be stored there. In the document, references to materials are stored by name. This means that if you open the file on a another machine without the system-wide materials, the material-lookup will fail. This must of course be handled in a graceful way.

The Material database in App comprises the files-based sources, i.e the FCMat-based directories. Saving is not implemented yet for these file-based material sources. In general, each material object belongs to a source, and it will eventually be stored back to the source where it belongs if it is changed.

Yes, they currently are hard-coded. If we stick to a pre-defined set of types, it is possible to define new properties. Providing type-safety is what makes this a bit tricky, because each type needs conversion functions both to and from python, but also to and from boost::any. However, I think type-safety is important, as it must be handled somewhere anyway, so having it in the “core” is probably best.

The material databases and sources are stacked, so when searching for a material, it will pick the one a the top of the stack.

Eivind

Hello,

I have no clear picture about material support, but one note on the API: In the code examples you provided you access Materials like “Solid[0]”, which indicates the usual freecad python subshape accessing scheme by index. Accessing subshapes however does also work by strings, like “Face1” or “Edge2” in TopoShape class which should also be supportet in your API. This may sound like splitting a hair, and it definitely is for the current situation. However, ezzy is currently working hard on topological naming. Once done it is quite likely that the string based subshape identification can use tnaming, as this is what the link properties use, but not the indexed based identification. So maybe it is a good idee to have that in mind while designing the API and the underlying data structure. Your code will suffer from naming issue like everything else that uses subshapes. And on second note it would be nice to have both options for specifying subahpes anyway :slight_smile: