Issue: rs.MatchObjectAttributes() makes objects dissapear

Hi there,

I use rs.MatchObjectAttributes() to clone the attributes (e.g. objectlayer, usertexts, etc) from objects, nested inside a block to their copies. (I use this mechanism as a workaround for this related issue)

When I run the script below with runPythonScript "C:/path/scriptname.py", I expect the copies to be in the document, but when I call rs.MatchObjectAttributes(), the objects seem to have become invalid (or at least unselectable). If rs.MatchObjectAttributes() is not called, the copies are valid and selected

I hope somebody can help me out.

Thanks,
Tim

test_issue_content_dissappear.3dm (395.0 KB)

#! python 2
import traceback as tb
import rhinoscriptsyntax as rs

class BlockDefinition(object):

    def __init__(self, name):
        self.name = name

    def traverse(self, func, result=None, block_name=None, parent_xform=rs.XformIdentity()):

        # initialize variables if not set
        if result == None:
            result = []

        if block_name == None:
            block_name = self.name

        # traverse block tree
        content = rs.BlockObjects(block_name)
        for obj in content:
            if rs.IsBlockInstance(obj):
                instance_xform = rs.BlockInstanceXform(obj)
                if parent_xform:
                    instance_xform = rs.XformMultiply(parent_xform, instance_xform )

                self.traverse( func, result, rs.BlockInstanceName(obj), instance_xform )

            func(obj, result, parent_xform)

        return result


def main():
    try:
        objs = rs.GetObjects(preselect=True, filter=rs.filter.instance)
        for obj in objs:
            if rs.IsBlockInstance(obj):
                block_name = rs.BlockInstanceName(obj)

                # traverse all child blocks, and add breps to the result
                definition = BlockDefinition(block_name)
                def _get_breps(obj, result, xform):
                    # when obj is a brep, add it to the result
                    if rs.IsBrep(obj):
                        copy = rs.TransformObject(obj, xform, copy=True)

                        """ ############# ISSUE OCCURS HERE ########### """
                        """ when I comment out the line below, the described issue does not occur """
                        rs.MatchObjectAttributes(copy, obj)
                        result.append(copy)

                content_copies = definition.traverse(_get_breps)
                print('content_copies', content_copies)

                # empty current selection and select copies
                rs.UnselectAllObjects()
                rs.SelectObjects(content_copies)
                print('selection', rs.SelectedObjects())

                rs.ZoomSelected()

    except Exception as exc:
        print(tb.format_exc())

if __name__ == '__main__':
    main()

Hi @pascal @dale,

since you’ve picked up the seemingly related issue I’ve reported here,

I’d like to bring this topic under your attention.

Could you please have another look?

Thanks!
Tim

Hi @timcastelijn,

Maybe something like this is better:

#! python 2

import Rhino
import scriptcontext as sc

def TestTim():
    filter = Rhino.DocObjects.ObjectType.InstanceReference
    rc, objref = Rhino.Input.RhinoGet.GetOneObject("Select block instance", False, filter)
    if not objref or rc != Rhino.Commands.Result.Success: 
        return

    iref = objref.Object()
    if not isinstance(iref, Rhino.DocObjects.InstanceObject):
        return

    out_objects, out_attributes, out_xforms = iref.Explode(True)
    for i in range(len(out_objects)):
        obj = out_objects[i]
        geom = obj.Geometry
        geom.Transform(out_xforms[i])
        sc.doc.Objects.Add(geom, iref.Attributes)
    sc.doc.Views.Redraw()

if __name__ == "__main__":
    TestTim()

– Dale

Hi @dale,

First of all, thanks for your response. I much appreciate your help. However, I don’t think my question did come across correctly.

The issue reported here is that when I call rs.MatchObjectAttributes(obj, copy) the selection is empty when I run rs.SelectObjects(content) later in the script. I don’t think that is intended behavior. If I comment out rs.MatchObjectAttributes, the copies are selected as expected.

Thanks,
Tim

P.S. using rs.MatchObjectAttributes() was a workaround for this issue, that @pascal reported in youtrack, but was never solved

Hi @timcastelijn,

MatchProperties will replace the object with a copy that contains new attributes. Because the object is replaced, you’ll (probably) need to reselect the new reference (if you want or need it to be selected).

– Dale

OK, thank you Dale. That makes sense. I’ll figure out a solution from here.

(btw, I meant rs.MatchObjectAttributes() instead of rs.MatchProperties(). I will update it in the posts above for future readers)

Hi @dale,

I am running into the same issue in other parts of my code.

I interpret this line:

        if scriptcontext.doc.Objects.ModifyAttributes(id, source_attr, True):

in the definition of rs.MatchObjectAttributes() in object.py as if the objects’ Attributes should be modified, rather than returning a new reference. Also the documentation doesn’t mention that another reference is created.

I have a workaround now, but I still think rs.MatchObjectAttributes() shows unintended behavior. Could you have another look at it? I have another isolated example that demonstrates the unintended behavior if that helps.

Thanks,
Tim

Hi @Dale,

based on your answer on my other topic, I’ve made a modified version of my script. It still puzzles me that copies seem to disappear from the doc when I match the attributes with the orginal.

If I run the script below, I expect the content from all blocks to be in the document. However, the breps from linked blocks have disappeared.

I hope you can help me out.

Best regards,
Tim

test_issue_content_dissappear.3dm (395.0 KB)
E_side (linked block).3dm (384.8 KB)

#! python3

import rhinoscriptsyntax as rs
import scriptcontext as sc

def traverse(block_name, my_func, result=None, parent_xform = rs.XformIdentity()):
    
    if result is None:
        result=[]
    
    block_objects = rs.BlockObjects(block_name)
    for obj in block_objects:
        if rs.IsBlockInstance(obj):
            child_block_name = rs.BlockInstanceName(obj)
            xform = rs.BlockInstanceXform(obj)
            traverse(child_block_name, my_func, result, xform * parent_xform)
        
        my_func(obj, result, parent_xform)
    
    return result

def main():
    
    # let user select the input
    obj = rs.GetObject("select block with nested linked instances", filter=rs.filter.instance, preselect=True)
    if not obj:
        return
    
    block_name = rs.BlockInstanceName(obj)
    
    def create_transformed_copy(obj, result, parent_xform):
        """
            function to create a copy of objects that are not instances 
            @param obj: GUID object ref
            @param result: list of function result
            @param parent_xform: parent transformation matrix
            return None 
        """
        if not rs.IsBlockInstance(obj):
            copy = rs.TransformObject(obj, parent_xform, True)
            # -----------------------
            # match attributes of original to copy
            if rs.IsObjectReference(obj):
                source = rs.coercerhinoobject(obj)
                source_attr = source.Attributes.Duplicate()
                target = rs.coerceguid(copy, True)
                sc.doc.Objects.ModifyAttributes(target, source_attr, True)

            result.append(copy)
    
    # recursively run this function on all objects in tree
    result = traverse( block_name, create_transformed_copy)

    # "result" contains all breps nested inside the block
    print('result', result)

    # "selection" unexpectedly does not contain breps from linked blocks  
    rs.UnselectAllObjects()
    rs.SelectObjects(result)
    print('selection', rs.SelectedObjects())

    rs.ZoomSelected()
if __name__ == '__main__':
    main()