How to get the material of component?


#1

Hi,

I’m working on an skp import with c++ SDK (2016 version).
This import works very well but I have one difficulty.

I cann’t get the right material of component instance. It returns a material with empty name. That’s why?

SUEntitiesRef CSktLoader::LoadComponentInstance(SUComponentInstanceRef instance, CSktEdoInfo& edoinfo)
{
// Convert to entities
SUComponentDefinitionRef component_definition;
SUComponentInstanceGetDefinition(instance, &component_definition);
SUEntitiesRef entities;
SUComponentDefinitionGetEntities(component_definition, &entities);

size_t faceCount = 0;
SUResult res = SUEntitiesGetNumFaces(entities, &faceCount);
if (faceCount > 0)
{
    SUFaceRef face;
    SUEntitiesGetFaces(entities, 1, &face, &faceCount);

    SUMaterialRef material = SU_INVALID;
    SUFaceGetFrontMaterial(face, &material);
 }

}


#2

The instance can have a material override that all it’s faces with no material (called “default material”,) will render onto. But an individual face’s material will not be overridden (ie, a primitive entity’s material assignments take precedence over the instance or group material assignments.)

So use
SUDrawingElementGetMaterial

You may need to first upcast using:
SUComponentInstanceToDrawingElement


#3

@DanRathbun related question:

How does one set the default material? At the moment, if we want to assign a material to a component, we are forced to loop over all the faces and assign both front & back materials. Which is slow, both in the SDK and Ruby. The default material sounds like a solution to that.


#4

In Ruby we assign nil (which is the singleton instance of the NilClass,) as the front and/or back face material (to clear any material assignments.) Any newly created faces should have “default” material (ie, no material) assigned.

On the Ruby API side, if you query a face’s material, and it has none (which is “the default”,) then Ruby returns a reference to nil.

I am not sure what is returned for the C APIs. Perhaps compare against SU_INVALID ?
(That is what it is when you first create a material object, yes ?)

@tt_su, @bugra ?


The word “default” is a confusing word to use to describe the feature, because people think that they can assign some color or material choice to be “the default” that is applied to all new faces that are created.

But this is not the case (yet.) Perhaps at one time it was a planned feature, but has not yet been implemented ? (I know it has been a requested feature, in the past.)


#5

@tickle Just noticed when re-reading your question. When you loop over a component’s entities and make material assignments to anything (nested groups, components, and primitives,) you change all instances of that definition. Instances do not have an entities collection,… only definitions.

So if you wish the end users to be able to paint separate instances, with different materials, then the material assignment needs to be left to the user, so they are applied to the instances (as a whole,)… and not the definition’s entities. (Or in your code you assign material to instances, not to it’s definition’s entities.)


#6

That’s it . Thanks!:smiley:


#7

Thanks, Dan. My default material question was maybe a tad misleading. Let me rephrase my question based on some tantalizing parts in your answer:

Instead of having to loop through hundreds of faces and assign materials to them (which is slow), I would prefer assigning materials once, say, per component (definition is fine).

However, as far as I can tell, materials can only be assigned to DrawingElements, and components nor groups, nor any entity collection is a DrawingElement.

https://www.sketchup.com/intl/en/developer/docs/ourdoc/drawingelement

Essentially: I’m looking for a fast way to assign a material to a component. Either via Ruby or the API.

EDIT: Just found out a ComponentDefinition is a DrawingElement. The Documentation on DrawingElement did not mention this, sorry. So I think I’m out of the woods.

EDIT 2: assigning the material to the ComponentDefinition didn’t work. I had to add it to the instance:

    instance.material= material
    instance.definition.material= material   # doesn't seem to work

#8

The SketchUp engine is C++ which is object-oriented. So goes the SketchUp DOM (Document Object Model) and the Ruby API.

Everything saved into DOM is a subclass of Entity. (ie, Layer, ShadowInfo, Material, etc.) The DrawingElement class is a subclass of Entity, and like it’s siblings inherits functions (aka methods,) constants, etc., from it’s superclass(es), all the way back to Object.) Anything that you can see or draw into the model, is an instance of a class, that is a subclass of DrawingElement. (The Face class for example, is a subclass of DrawingElement.)

But the new reading & writing API is C. You don’t clearly see in it, the object-orient inheritance of the SKP document’s DOM. So they mimic it with functions named similarly to how they’d be named in the OO languages. In Ruby you’d have Sketchup::Face.material(), but in C, they concatenate the whole object qualification together in one long name like: SketchUpFaceGetMaterial(). (Just an example, not an exact function name, per se.)

No it’s not. Assign persisting materials to the component instance(s), not their definition.

… and leave all the primitives in the definition’s entities collection with no material assignment, and they’ll render with each instance’s material assignment.

The assignment of a material to a component definition, will only render whilst a new component instance is being placed (ie, when it is attached to the cursor.)

It is sort of a highlighting effect. (“Here I am, insert me someplace good!”)


#9

Right. Thank you, Dan.

I was aware that ComponentInstance/Definition were of the Entity class, but not of DrawingElement. The documentation suggest that the lower level entities (faces, edges etc) are DrawingElements, with zero mention of ComponentInstance/Definition. I’d suggest to the SU team:

  • amending the Ruby docs to reflect that
  • include an proper object hierarchy in the Ruby docs

The “anything that can be drawn” rule for DrawingElement is a bit finger-in-the-wind. According to the docs, Curve, for example, is not a DrawingElement. Sure there is a good reason, but you can see how things can get a bit confusing.


#10

:warning:

This conversation was written before the Ruby API documentation was redeployed using YARD, so some of the issues discussed are no longer present in the new interface.

[quote=“tickle, post:9, topic:25592”]
I was aware that ComponentInstance/Definition were of the Entity class, but not of DrawingElement.
The documentation suggest that the lower level entities (faces, edges etc) are DrawingElements, with zero mention of ComponentInstance/Definition.[/quote]

Actually, they are themselves defined as a class (having their own unique functionality) first.
More precisely, they are subclasses of Drawingelement.
Their Ruby API docpages clearly state their “parent” class as Drawingelement.
Go to the docpage for Drawingelement, and it’s “parent” is given as Entity, and it’s “parent” is given as Object.

Then within the Ruby Console, execute: Sketchup::Face.ancestors

The term “parent” is not a Ruby term, and we have asked in the past to have it changed to “superclass”. But the engine to generate those old pages is not so flexible it seems. But, it’s not so wrong as the first superclass in the inheritance chain, (called it’s “ancestors”) could logically be referred to as “the direct parent class”.

While there is an ancestors() method to return the array of all a class’ ancestor superclasses, there is no dedicated core Ruby parent() method.

The API however, uses a parent() method to denote ownership of a drawingelement within the entities collection of another DOM object. (ie, the model itself, or some group or component.)

This tends to cause confusion between “model DOM ownership” and the programming language class inheritance chain. They are two separate things.
Let me stress this. The Document database object tree (ie, the DOM, the exact layout of which is proprietary,) is not the same as the Ruby API class hierarchy (which mimics the underlying C++ classes.) Many newbs confound the two.
The latter is organized for namespace encapsulation to avoid code clashing, and functionality inheritance.
The former (the DOM) is organized to store and transport the model data as a file.

I am not sure what you mean by “zero mention of ComponentInstance/Definition” ?

… and then: “include an proper object hierarchy in the Ruby docs

Just FYI, the API documentation’s left-column navigation tree is not ordered in any object hierarchy (be it Ruby or DOM.) It is just loosely categorical. And there are misplaced links. Ie, some collection type classes are not beneath the “Collections” category, etc.

:warning:

This above is no longer valid. In the new YARD interface, the left column navigation pane lists classes by their encapsulating namespace.(There are no longer categorical lists.)

The object hierarchy diagram link was removed because it is old, and some new classes and modules are not on it.
Saving a copy locally might be a good idea. (It was drawn by one of the developers, Roger [RLC] and first posted in the old Google Groups forum.)

:warning:

[details=(The online diagram link is broken.)]

[/details]

http://www.sketchup.com/intl/en/developer/docs/diagram :arrow_left: broken!

Hey! That is simply MY way of trying to explain a concept. It is not a “rule”.
Yes, curve/arcurve information is saved with the model.

Because it and it’s subclass ArcCurve are “virtual” geometry helper classes. They are actually made up of Edge segments. (In a way they are sort of like Groups, special kinds of components “under the hood.”) And I am not saying I like that either. Importers and Exporters often have to read their geometric information and recreate real arcs and circles in the target format.

The simplest explanation why Curve was not made a subclass of Drawingelement, is because they did not want the Curve (and ArcCurve) classes to inherit the methods of Drawingelement.

Sure. I can. The docs got hardly no “love” at all during the Google years. They are slowly getting better.
Also the documentation generators produce a vastly different style of documentation between the C APIs and the Ruby API. (I find the doxygen C docs to be a lot more cumbersome to navigate.)


#11

Woah. Even if dated/incomplete, the diagram is excellent!

Just that all examples on the DrawingElement page refer to faces. Not once is there a hint at ComponentInstance/Definition being a DrawingElement.

I think you answered that. I was looking for the diagram, basically :slight_smile:


#12

The diagram is not really a strict class hierarchy (or even a DOM hierarchy.)
It’s more an object interaction diagram.

Re: examples. They have always been poor. But, the examples and the API reference are not teaching resources. There are other tutorials out there. See my Ruby Learning Resources pinned post in the Ruby category.


#13

For reference (untested), these are SDK methods that could help with material assignment:
SUDrawingElementSetMaterial

After upcasting, say, a component instance to a DrawingElement (as Dan pointed out earlier):
SUComponentInstanceToDrawingElement


#15

The online Ruby docs are now generated using YARD.

A proper ancestor chain can now be shown at the top of each Ruby API class page.
In the inheritance table at the top, click on the “show all” link, and the Inherits: box …

… will expand to:

Also keep in mind that Includes: shows library modules that are mixed into the class, and also serve as superclasses. ie:

my_component_defn.is_a?(Comparable)

… will return true, if my_component_defn is an instance of the Sketchup::ComponentDefinition class.


Also, there are other Ruby Core library modules and classes in the ancestry chain that are not shown (yet) in the API documentation. As mentioned above, you can always interogate any class as to it’s ancestry, at the console:

Sketchup::ComponentDefinition.ancestors

or

my_component_defn.class.ancestors

… will return an array similar to the following, in SketchUp 2014 (and higher):

[ Sketchup::ComponentDefinition, Comparable, Sketchup::Drawingelement,
  Sketchup::Entity, Object, PP::ObjectMixin,
  JSON::Ext::Generator::GeneratorMethods::Object, Kernel, BasicObject ]