Part name and model unit issue

Hi, I’m trying to retrieve the part name or subpart name and unit of the model but haven’t found the right API for it. Could you please help me with this?

I have developed a converter that transforms SketchUp model data into a 3D PDF. One of its features, called the model tree, provides a hierarchical representation of the model. To implement this feature, I need to retrieve the Assembly name, Subassembly name, and Part name. I have written the SketchUp model reading code in C++. Could you provide a sample code or the relevant API for this?

I moved topic to SketchUp SDK category. (I have no experience with it.)

SketchUp DOM does not use these exact terms. We would need a picture or more information as to what the PDF specification describes these terms as.

But, in the meantime, note the following:

  • The model itself can have optional name and description properties.

  • When a model file serves as a component definition (and is imported into a model) then the name and description are accessed via the component’s definition object. (The name property for a definition is required, as it is the key into the model’s definitions collection, and a sequential unique name will be generated if the definition does not have one.)

  • Component instances can also optionally can have a name property, as well as group instances optionally having a name property, that are distinct from their definition’s name property.

  • The entities collection of a definition can contain nested instances of other definitions.

So, the SketchUp hierarchy is free form. You might treat the root model level as the Assembly, the direct child instances & groups as Subassembly objects, and the grandchildren all as Part objects.

But beware that not all modelers will organize their models like this. SketchUp is mostly aimed at architectural modeling and will follow the IFC standard for hierarchy.

1 Like

Thanks, DanRathbun.

Please refer to the image of the Outliner. In my case, the name “Truck Delivery” represents the main assembly or root, while all other entries are sub-assemblies or parts of this root. The “BackTires” instance is considered a part of “Truck Delivery,” and “TruckTireBack” is a subpart of it.

I reviewed the documentation you shared and attempted to retrieve the name using SUComponentInstanceGetName and SUGroupGetName. However, these methods consistently return a null pointer. Is this the correct approach to obtain the names, or am I missing something?

In SketchUp’s Outliner, the definition names are in <> delimiters.

So, in the tree you have shown, none of the instances have a name assigned.

2 Likes

I have assigned the names to the instances, please refer to the image. The method “SUComponentInstanceGetName(instances[i], &instance_Name);” returns the null ptr.

You’ll need to create the string ref first.

SUStringRef su_str
SUStringCreate(&su_str);

SUComponentInstanceGetName(instance_ref, &su_str);

size_t length;
SUStringGetUTF16Length(su_str, &length);

std::wstring result;
result.resize(length);
SUStringGetUTF16(su_str, length, &result[0], &length);

SUStringRelease(&su_str);

return result;
1 Like

Looks like a good job for a function passing in a instance reference.

1 Like

@RaPIT Thanks for the solution. I have implemented it on my end and can now retrieve the names of all instances and groups. I wrote a traversal function to process the model data before converting it to a 3D PDF. However, the traversal was not performed hierarchically, resulting in an incorrect output. Could you please review my code and suggest the correct approach for hierarchical model traversal?

SUModelRef model = SU_INVALID;
SUModelLoadStatus status;
SUResult res = SUModelCreateFromFileWithStatus(&model, path, &status);
SUEntitiesRef entities = SU_INVALID;
SUModelGetEntities(model, &entities);
assembly = TraverseRoot(entities, commandData, previousTransform);
exportdata(assembly);

Assembly TraverseRoot(SUEntitiesRef entities, CLRPrecisionCommand commandData, SUTransformation previousTransform)
{
    Assembly assemb;
    size_t nastedfaceCount = 0;
    size_t NumInstancescount = 0;
    size_t groupCount = 0;
    size_t faceCount = 0;
    SUTransformation currentTransform;
    SUComponentDefinitionRef component;

    //Need to check the assembly have subcomponent, subinstance or raw faces(Preset in the root assembly direcrtly)
    SUEntitiesGetNumInstances(entities, &NumInstancescount);
    SUEntitiesGetNumGroups(entities, &groupCount);
    SUEntitiesGetNumFaces(entities, &faceCount);
    //Traverse the component instace of the root assembly
    if (NumInstancescount > 0)
    {
        assemb = TraverseComponentInstaceData(entities, NumInstancescount, previousTransform, commandData);
    }
    if(groupCount > 0)
    {
        assemb = TraverseGroupPartData(entities, groupCount, previousTransform, commandData);
    }
}

Assembly TraverseComponentInstaceData(SUEntitiesRef entities, size_t NumInstancescount, SUTransformation previoustransform, CLRPrecisionCommand commandData)
{
	Assembly componentAssembly;
	size_t nastedfaceCount = 0;
	size_t edgeCount = 0;
	size_t nestedNumInstancescount = 0;
	SUEntitiesRef nastedentities;
	SUTransformation currentTransform;
	SUComponentDefinitionRef component;
	std::vector<SUComponentInstanceRef> instances(NumInstancescount);
	std::vector<SUFaceRef> faces(nastedfaceCount);
	SUEntitiesGetInstances(entities, NumInstancescount, &instances[0], &NumInstancescount);
    for (size_t i = 0; i < NumInstancescount; i++)
    {
        SUComponentInstanceGetDefinition(instances[i], &component);
		SUComponentDefinitionGetEntities(component, &nastedentities);
        SUEntitiesGetNumFaces(nastedentities, &nastedfaceCount);
        size_t instaceCount = 0;
        size_t groupCount = 0;
        SUEntitiesGetNumInstances(nastedentities, &instaceCount);
        SUEntitiesGetNumGroups(nastedentities, &groupCount);
        if (instaceCount > 0)
        {
            Assembly tempassembly;
            previousTransform = currentTransform;
            previousTransform.values[15] = 9898;
            tempassembly = TraverseComponentInstaceData(nastedentities, instaceCount, previousTransform, commandData);
            previousTransform.values[15] = 1;
            componentAssembly.subAssemblies.push_back(tempassembly);
        }
        if (groupCount > 0)
        {
            Assembly tempassembly;
            previousTransform = currentTransform;
            previousTransform.values[15] = 9898;
            tempassembly = TraverseGroupPartData(nastedentities, groupCount, previousTransform, commandData);
            previousTransform.values[15] = 1;
            componentAssembly.subAssemblies.push_back(tempassembly);
        }
    }
    return componentAssembly;
}

Assembly TraverseGroupPartData(SUEntitiesRef entities, size_t groupCount, SUTransformation previoustransform, CLRPrecisionCommand commandData)
{
//Same as instance
}

Where is a return from TraverseRoot ?

I have created a class called Assembly to store geometric data collected during traversal, which is later passed to the export method for further processing.

class Assembly
{
public:
	std::vector<Part> parts;
	std::vector<Assembly> subAssemblies;
	std::vector<double> transMat;
	std::string assemblyName;
	FusionCam fusioncamObject;
	SkechUpCam sketchupcamObject;
	bool m_isVisible;
	bool m_Unit_in_file;
	double unit;
};

The TraverseRoot doesn’t have return, and it assign to the same assembly results of two different calls, is it intentional or just the code has been simplified during copy paste?

What is the output, (some simple example) why is not hierarchically?

code has been simplified during copy paste.

Hmm I don’t see any issues here, try to Log/Dump OutputDebugString or something inside the TraverseComponentInstaceData to check why the hierarchy is flat.