Reading instanced geometry

opennurbs
c
instance
(Nathaniel) #1

Hello,

I have just started using OpenNURBS to read 3dm models into my (C++) application. Naturally, getting started with a new library takes some time, but I am currently trying to figure out how to properly read the instanced geometry.
I am able to read non-instanced geometry, but the instances do not receive the correct transform; they remain at the origin. I started from this example: https://developer.rhino3d.com/guides/opennurbs/traverse-instance-definitions/ and used the m_xform in the ON_InstanceRef, but I must be doing something wrong. Does the transform need to be applied recursively, or is it already in world space?
And the geometry is not a problem, I am getting the geometry (although it is hard to tell whether I get the X instances, or only get the shape once, since they are not transformed.).

This is (a part of) my code for dealing with the instances:

void ProcessInstances(...)
{
    ONX_ModelComponentIterator it(model, ON_ModelComponent::Type::InstanceDefinition);
    for(ON_ModelComponentReference mcr = it.FirstComponentReference(); false == mcr.IsEmpty(); mcr = it.NextComponentReference())
    {
        const ON_ModelComponent* modelComponent = mcr.ModelComponent();
        if(CheckComponent(modelComponent, ...))
        {
            const ON_InstanceDefinition* idef = ON_InstanceDefinition::Cast(modelComponent);
            if(nullptr != idef)
            {
                ProcessInstanceDefinition(idef->Id(), ON_Xform::IdentityTransformation);
            }
        }
    }
}

void ProcessInstanceDefinition(const ON_UUID& idef_id, ON_Xform transform)
{
    const ON_ModelComponentReference& idef_component_ref = model.ComponentFromId(ON_ModelComponent::Type::InstanceDefinition, idef_id);
    const ON_InstanceDefinition* idef = ON_InstanceDefinition::Cast(idef_component_ref.ModelComponent());
    if(idef)
    {
        const ON_SimpleArray<ON_UUID>& geometry_id_list = idef->InstanceGeometryIdList();
        const int geometry_id_count = geometry_id_list.Count();
        for(int i = 0; i < geometry_id_count; i++)
        {
            const ON_ModelComponentReference& model_component_ref = model.ComponentFromId(ON_ModelComponent::Type::ModelGeometry, geometry_id_list[i]);
            const ON_ModelGeometryComponent* model_geometry = ON_ModelGeometryComponent::Cast(model_component_ref.ModelComponent());
            if(nullptr != model_geometry)
            {
                const ON_Geometry* geometry = model_geometry->Geometry(nullptr);
                if(nullptr != geometry)
                {
                    const ON_InstanceRef* iref = ON_InstanceRef::Cast(geometry);
                    if(iref)
                    {
                        ProcessInstanceDefinition(iref->m_instance_definition_uuid, iref->m_xform);
                    }
                    else
                    {
                        ProcessGeometryComponent(geometry, transform);
                    }
                }
            }
        }
    }
}

void ProcessGeometryComponent(const ON_Geometry* geom, ON_Xform transform)
{
    // Only handle BREPs for now... Other types later
    ON_Brep* brep = geom->BrepForm();
    if(brep)
    {
        brep->Transform(transform);
        brep->ShrinkSurfaces();
        int numFaces = brep->m_F.Count();
        for(int f = 0; f < numFaces; ++f)
        {
            // Process faces...
        }
    }
}

What I would like, is to just get all the geometry for now and instanced at the correct transform, I don’t need to use instancing in my application yet, and right now it is really about understanding the transforms OpenNURBS uses as well as the instancing mechanic.

EDIT: It seems that some transforms are being applied, but not all. I think it has to do with nesting (not sure what this is called in Rhino). So, for example, I have some instanced objects that are transformed into place w.r.t. their parent, but then this group (which is also instanced) is not transformed.

Thank you!

Nathaniël

0 Likes

(Dale Fugier) #2

Hi @nathaniel,

If you are using openNURBS to read a 3dm file into another application that does not support blocks or instances, then you can use this sample code as model of how to read ON_InstanceRef objects, find their instance definition geometries, and transform them to their world Cartesian location.

cmdSampleReadInstancesFromFile.cpp

Note, the sample just reads the stuff back into Rhino. But you should be able to adapt this to your application.

– Dale

0 Likes

(Nathaniel) #3

Dale,

Thank you so much, this works like a charm, and straight out of the box!
This helps me out a lot!

Nathaniël

0 Likes