When attaching user data to brep components, attach the data to the underlying geometry, not the topology. For example, instead of attaching user data to an ON_BrepFace, attach it to the face's underlying ON_Surface object instead.
The following source code example demonstrates how to attach object user data to the underlying surface of a brep face.
CRhinoCommand::result CCommandTest::RunCommand(
const CRhinoCommandContext& context)
{
// Allow for picking of either a surface or a brep face.
CRhinoGetObject go;
go.SetCommandPrompt( L"Select surface to attach data" );
go.SetGeometryFilter( CRhinoGetObject::surface_object );
go.EnableSubObjectSelect( TRUE );
go.GetObjects( 1, 1 );
if( go.CommandResult() != CRhinoCommand::success )
return go.CommandResult();
// Get first object reference. Note, this reference
// reprsents the picked surface or face, not the
// top level brep.
const CRhinoObjRef& objref = go.Object(0);
// Get face on brep that was picked
const ON_BrepFace* face = objref.Face();
if( !face )
return failure;
// Get the faces underlying surface
const ON_Surface* srf = face->SurfaceOf();
if( !srf )
return failure;
// Query surface for user data
CTestUserData* ud = CTestUserData::Cast( srf->GetUserData(ud->m_uuid) );
if( ud )
{
RhinoApp().Print( L"Data already attached.\n" );
return nothing;
}
// Get the top level object
const CRhinoBrepObject* obj = CRhinoBrepObject::Cast( objref.Object() );
if( !obj )
return failure;
// Duplicate the top level object.
CRhinoBrepObject* dupe_obj = CRhinoBrepObject::Cast( obj->DuplicateObject() );
if( !dupe_obj )
return failure;
// Get the brep
ON_Brep* dupe_brep = dupe_obj->Brep();
if( !dupe_brep )
return failure;
// Get the surface
ON_Surface* dupe_srf = dupe_brep->m_S[face->SurfaceIndexOf()];
if( !dupe_srf )
return failure;
// New up the user data
ud = new CTestUserData();
if( !ud )
{
delete dupe_obj;
return failure;
}
// TODO: Initialize user data object here
// Attach user data to surface, not face. Note, ud
// is now owned by dupe_srf, not by us. So, we are
// not responsible for deleting it;
if( !dupe_srf->AttachUserData(ud) )
{
delete ud;
delete dupe_obj;
return failure;
}
// Replace object. Note, we cannot reuse objref for it references
// the picked face, not the top level brep.
// Note, dupe_obj is now owned by Rhino, so we are not
// responsible for deleting it.
if( !context.m_doc.ReplaceObject(CRhinoObjRef(obj), dupe_obj) )
{
delete dupe_obj;
return failure;
}
// Done deal
RhinoApp().Print( L"Data attached successfully.\n" );
context.m_doc.Redraw();
return CRhinoCommand::success;
}
Public Overrides Function RunCommand(ByVal context As IRhinoCommandContext) _
As IRhinoCommand.result
' Allow for picking of either a surface or a brep face.
Dim go As New MRhinoGetObject()
go.SetCommandPrompt("Select surface to attach data")
go.SetGeometryFilter(IRhinoGetObject.GEOMETRY_TYPE_FILTER.surface_object)
go.EnableSubObjectSelect(True)
go.GetObjects(1, 1)
If (go.CommandResult() <> IRhinoCommand.result.success) Then
Return go.CommandResult()
End If
' Get first object reference. Note, this reference
' reprsents the picked surface or face, not the
' top level brep.
Dim objref As MRhinoObjRef = go.Object(0)
' Get face on brep that was picked
Dim face As IOnBrepFace = objref.Face()
If (face Is Nothing) Then Return IRhinoCommand.result.failure
' Get the faces underlying surface
Dim srf As IOnSurface = face.SurfaceOf()
If (srf Is Nothing) Then Return IRhinoCommand.result.failure
' Query surface for user data
Dim key As String = "MyVBUserData"
Dim userdata As String = ""
If (srf.GetUserString(key, userdata)) Then
RhUtil.RhinoApp().Print("Data already attached." + vbCrLf)
RhUtil.RhinoApp().Print("USERDATA = " + userdata + vbCrLf)
Return IRhinoCommand.result.nothing
End If
' Get the top level object
Dim obj As IRhinoBrepObject = MRhinoBrepObject.ConstCast(objref.Object())
If (obj Is Nothing) Then Return IRhinoCommand.result.failure
Dim orig_brep As IOnBrep = obj.Brep()
Dim dupe_brep As New OnBrep(orig_brep)
' Get the surface
Dim dupe_srf As OnSurface = dupe_brep.m_S(face.SurfaceIndexOf())
If (dupe_srf Is Nothing) Then Return IRhinoCommand.result.failure
' Attach user data to surface, not face.
' Set our user data string. This can be any type of string. In this example, we
' just set up some text, but this could be a serialized .NET class
dupe_srf.SetUserString(key, "my custom user data")
' Replace object. Note, we cannot reuse objref for it references
' the picked face, not the top level brep.
If (context.m_doc.ReplaceObject(New MRhinoObjRef(obj), dupe_brep) IsNot Nothing) Then
RhUtil.RhinoApp().Print("Data attached successfully" + vbCrLf)
context.m_doc.Redraw()
Return IRhinoCommand.result.success
End If
Return IRhinoCommand.result.nothing
End Function
public override IRhinoCommand.result RunCommand(IRhinoCommandContext context)
{
// Allow for picking of either a surface or a brep face.
MRhinoGetObject go = new MRhinoGetObject();
go.SetCommandPrompt("Select surface to attach data");
go.SetGeometryFilter(IRhinoGetObject.GEOMETRY_TYPE_FILTER.surface_object);
go.EnableSubObjectSelect(true);
go.GetObjects(1, 1);
if(go.CommandResult() != IRhinoCommand.result.success)
return go.CommandResult();
// Get first object reference. Note, this reference
// reprsents the picked surface or face, not the
// top level brep.
MRhinoObjRef objref = go.Object(0);
// Get face on brep that was picked
IOnBrepFace face = objref.Face();
if( face == null )
return IRhinoCommand.result.failure;
// Get the faces underlying surface
IOnSurface srf = face.SurfaceOf();
if( srf == null )
return IRhinoCommand.result.failure;
// Query surface for user data
string key = "MyCSUserData";
string userdata = "";
if( srf.GetUserString(key, ref userdata) )
{
RhUtil.RhinoApp().Print("Data already attached.\n");
RhUtil.RhinoApp().Print("USERDATA = " + userdata + "\n");
return IRhinoCommand.result.nothing;
}
// Get the top level object
IRhinoBrepObject obj = MRhinoBrepObject.ConstCast(objref.Object());
if( obj == null )
return IRhinoCommand.result.failure;
IOnBrep orig_brep = obj.Brep();
OnBrep dupe_brep = new OnBrep(orig_brep);
// Get the surface
OnSurface dupe_srf = dupe_brep.m_S[face.SurfaceIndexOf()];
if( dupe_srf == null )
return IRhinoCommand.result.failure;
// Attach user data to surface, not face.
// Set our user data string. This can be any type of string. In this example, we
// just set up some text, but this could be a serialized .NET class
dupe_srf.SetUserString(key, "my custom user data");
// Replace object. Note, we cannot reuse objref for it references
// the picked face, not the top level brep.
if(context.m_doc.ReplaceObject(new MRhinoObjRef(obj), dupe_brep) != null)
{
RhUtil.RhinoApp().Print("Data attached successfully\n");
context.m_doc.Redraw();
return IRhinoCommand.result.success;
}
return IRhinoCommand.result.nothing;
}