Id(), ModelObjectId(), and RuntimeSerialNumber()

Hi.
I want to store a bunch of user selected object. but those properties confused me.
What’s the difference between them?

CRhinoGetObject getObjs;
getCrvs.GetObjects(1, 0);
if (getCrvs.CommandResult() != CRhinoCommand::success)
	return;

for (int i = 0; i < getCrvs.ObjectCount(); i++) {
     const CRhinoObject* pObj = getCrvs.Object(0).Object();

     pObj->Id();
     pObj->ModelObjectId();
     pObj->RuntimeSerialNumber();

     // store selected object
     // ...
}

Hi @Liu2,

It is best to track Rhino objects by their unique GUID, which is persistent for the life of the object.

An object’s runtime serial number is used to identify instance of an object. For example, when you move an object, the old one is pushed onto the undo stack and a new one added to the document. In this case, the GUID is the same for both objects, but the runtime serial numbers will be different.

Note, there are several way to get an object’s GUID. Choose the one that best works for you.

To retrieve a Rhino object by it’s GUID, use CRhinoDoc::LookupObject.

CRhinoCommand::result CCommandTest::RunCommand(const CRhinoCommandContext& context)
{
  CRhinoGetObject go;
  go.SetCommandPrompt(L"Select object");
  go.EnableSubObjectSelect(false);
  go.GetObjects(1, 1);
  if (go.CommandResult() != CRhinoCommand::success)
    return go.CommandResult();

  const CRhinoObjRef& objref = go.Object(0);
  const CRhinoObject* pObj = objref.Object();
  if (nullptr == pObj)
    return CRhinoCommand::failure;

  ON_wString str;
  ON_UUID uuid;

  uuid = pObj->Id();
  ON_UuidToString(uuid, str);
  RhinoApp().Print(L"CRhinoObject::Id: %ls\n", static_cast<const wchar_t*>(str));

  uuid = pObj->ModelObjectId();
  ON_UuidToString(uuid, str);
  RhinoApp().Print(L"CRhinoObject::ModelObjectId: %ls\n", static_cast<const wchar_t*>(str));

  uuid = pObj->Attributes().m_uuid;
  ON_UuidToString(uuid, str);
  RhinoApp().Print(L"CRhinoObject::Attributes::m_uuid: %ls\n", static_cast<const wchar_t*>(str));

  unsigned int sn = pObj->RuntimeSerialNumber();
  RhinoApp().Print(L"CRhinoObject::RuntimeSerialNumber: %u\n", sn);

  const CRhinoObject* pLookup = context.m_doc.LookupObject(uuid);
  if (nullptr != pLookup)
  {
    // TODO...
  }

  return CRhinoCommand::success;
}

– Dale

Thanks Dale, It helps a lot

Hi Dale.
I use uuid to track objects now.
but It failed when I want to cast the objects to origin.


     const CRhinoObject* pLookup = CRhinoCurveObject::FromId(RhinoApp().ActiveDoc()->RuntimeSerialNumber(), uuid);

     if(nullptr != pLookup){
         // cast failed
         const ON_Curve* curve = ON_Curve::Cast(pLookup->Geometry());
     }

Hi @dale ,
After a testing,
I found that when I set curve_object filter, the surface boundary still could be selected, which leads to the ON_Curve casting failed.

    CRhinoGetObject go;
    go.SetGeometryFilter(CRhinoGetObject::curve_object);

    // selected ...
    // ...

    const CRhinoObject* pLookup = CRhinoCurveObject::FromId(RhinoApp().ActiveDoc()->RuntimeSerialNumber(), m_SelectedCurves[i].m_ID);
    if (nullptr != pLookup) {
        CRhinoObjRef objRef(pLookup);
        // casting failed
        const ON_Curve* curve = objRef.Curve();
    }

and those curves(top circle, bottom circle, vertical curve. see picture below) shared a common uuid.

    // result returns 0
    int result = ON_UuidCompare(topCircleID, bottomCircleID); 


Hi @Liu2,

Please review the attached and let me know if you have any questions.

cmdTestLiu.cpp (3.7 KB)

– Dale

Thank you @dale .
Through your code example, I can correctly store UUID of the curves.

    // select curves
	CRhinoGetObject go;
	go.SetCommandPrompt(L"Select curves");
	go.EnablePreSelect(FALSE);	
	go.SetGeometryFilter(CRhinoGetObject::curve_object);
	go.GetObjects(1, 0);	
	if (go.CommandResult() != CRhinoCommand::success)
		return;

	std::vector<UUID> uuidList;
	for (int i = 0; i < go.ObjectCount(); i++) {

		const CRhinoObject* pObj = go.Object(i).Object();
		// Dealing with non-curve situation
		const CRhinoCurveObject* pCurveObj = CRhinoCurveObject::Cast(pObj);
		if (nullptr == pCurveObj) 
		{
			RhinoApp().Print(L"Selected object %d is not a curve but a %ls\n", i, pObj->ShortDescription(false));

			continue;
		}
        uuidList.push_back(pObj->Id());
    }

But I still have a question:
Why can I select the boundary of the surface even after setting go.SetGeometryFilter(CRhinoGetObject::curve_object)?
Snipaste_2024-03-29_10-37-17

The code below shows the selected object of the picture above is a surface.

    RhinoApp().Print(L"CRhinoObject::ObjectType: %ls\n", pRhinoObj->ShortDescription(false));

Hi @Liu2,

If you do not want to select edge curves, then add this line of code to your getter:

go.EnableSubObjectSelect(false);

– Dale

2 posts were split to a new topic: Persistent GUID of ON_Brep objects