Find objects associated with Texture Mapping

Hi there,

does anybody know how to find out which object/objects are altered when listening to RhinoDoc.TextureMappingEvent - its args doesn’t indicate anything like that RhinoDoc.TextureMappingEventArgs Class

Traversing all objects and finding if they have any mapping and getting those mappings to compare if old/new one is there is at least inefficient if not weird.

Any wise shortcut?

Hmm… It turns out that even finding objects and getting their mappings ids and comparing isn’t a way to go:


@dale would you be so kind and guide me on this?

private void RhinoDoc_TextureMappingEvent(object sender, Rhino.RhinoDoc.TextureMappingEventArgs e)
        {
            bool changed = false;
            var rhObjs = e.Document.Objects.Where(i => ids.Contains(i.Id));

            foreach (var rhObj in rhObjs)
            {
                var channels = rhObj.GetTextureChannels();

                foreach (var channel in channels)
                {
                    var mapping = rhObj.GetTextureMapping(channel);

                    if (mapping == e.OldMapping)
                    {
                        changed = true;
                        break;
                    }
                }

                if (changed) break;
            }

            if (changed)
                OnPropertyChanged("TextureMappingChanged");
        }

Above listener + few mapping changes crashes Rhino without warning or pops above window - dump can’t be saved also for some reason.

Huh… Weird - it never popped up i found it in output window → Exception thrown: ‘System.AccessViolationException’ in RhinoCommon.dll so → that ObjectTable is not traversable during texture mapping change event since i already locked RhinoObject inside a loop…

So far it seems that this event is meant to be used is some exotic scenarios.

That is curious…

This seems to work in python (3 maps, ~2k objects in doc):

def handle_tex_map_e(sender, e):
    try:
        for obj in sc.doc.Objects:
            if obj.HasTextureMapping():
                 channels = obj.GetTextureChannels()
                 maps = set()
                 for channel in channels:
                     maps.add(obj.GetTextureMapping(channel).Id)
                 if e.NewMapping.Id in maps:
                     # print sender, e, e.Document, e.EventType, e.NewMapping, e.OldMapping
                     # print maps
                     print('Object {} has the modified mapping'.format(obj.Id))
    except Exception as exp:
        print exp

Hopefully a guid list can be added to the event args.

@nathancoatney thanks for input! Hmm i see you put this in try block. Did you tried randomly change some mappings? I’m curious how many times it thowed exp in your case.

The try…except is for safety. This was extracted out of an eto non-modal form template that already had it present, as I’ve found eto can crash Rhino completely, so better to wrap in a try…except to avoid restarts.

I didn’t get any exceptions related to the texture map event. I modified the texture map via the gizmo and changed mapping types. The event seemed to track those changes…I didn’t do more extensive testing though.

Given they didn’t provide any object data in the event args, certainly there is some way to go from texture map to object(s)…we just haven’t found it yet…

Don’t know … It came to my mind that it can collide thread-safety somewhere later after calling own event so i just left this without any additional stuff only traversing objects and trying to check equality but it still just crashes rhino after few mapping changes - funny is that i put it in try-catch also but never thrown exp but immediately crashes rhino without any warning or i get rarely window from above screen.

Main suspect here would be ‘rhObj.GetTextureMapping(channel)’ since it could be swapped internally and it can fail here during traversing.

Only difference I see is I test for mapping before getting the Ids.

I don’t know what your OnPropertyChanged(“TextureMappingChanged”) does…are you emitting another event?

As i said i deleted this to be sure thats not my fault later. Nothing changed.

Just to update i ended with:

private void RhinoDoc_TextureMappingEvent(object sender, Rhino.RhinoDoc.TextureMappingEventArgs e)
        {
            bool changed = false;
            var docObjs = Rhino.RhinoDoc.ActiveDoc.Objects.ToList();
            var idsCopy = ids.ToList();

            var rhObjs = docObjs.Where(i => idsCopy.Contains(i.Id));

            try
            {
                foreach (var rhObj in rhObjs)
                {
                    lock (rhObj)
                    {
                        var channels = rhObj.GetTextureChannels();

                        foreach (var channel in channels)
                        {
                            var mappingId = rhObj.GetTextureMapping(channel).Id;

                            if (mappingId == e.NewMapping.Id)
                            {
                                changed = true;
                                break;
                            }
                        }

                        if (changed) break;
                    }
                }
            }
            catch (Exception ex)
            {
                Rhino.RhinoApp.WriteLine(ex.Message);
            }

            if (changed)
                Rhino.RhinoApp.WriteLine("changed");
        }

Nothing was catched and still crashing.

Ah, I didn’t catch that…I see now.

I guess this clarifies the situation - https://support.microsoft.com/en-us/help/125749/description-of-the-r6025-run-time-error-in-visual-c - I guess i try to get mapping before it’s ready on the native side this would actually mean that traversing and comparing in the event will never be stable.

@dale would you mind confirm/deny?

Since we’re in the topic of tracking objects - i also made next attempt to track displacement/rounded edges etc changes but without luck i ended with hooking to private fields of userdata trying to find any trace of those modifiers but also without luck. As i understand without it’s original userdata type definiton those are out of my range and cannot find out if those were changed.

Sorry, I don’t now anything about this.

@andy, @nathanletwory - is this something you can help with?

It’d be easier to help if we could have a complete, but as simple as possible, code that compiles out of the box and shows the problem - a self-contained test plug-in.

I had to revisit this and without luck … @dale or @nathanletwory can you check the implementation of TextureMappingEventArgs isn’t there sth off or some silly bug - id of old mapping is always the same as new no matter what. Or if Id stays the same what I should compare in this case? This one is valid for v5,v6 and v7.

It must be something wrong there as e.OldMapping returns nonsense … Below results during debugging.

Besides ideally would be just to attach to e arg RhinoObject which was changed as if some object gains first mapping it’s impossible to find which object it will be assigned.

1 Like

Hi @D-W , did you find a solution to that issue in the end?
We’ve come across the same problem regarding the limitation of the TextureMappingEvent .

@benoit.deschenes1 just checked that for you. I’ve ended with comparing ids in the e.Document against reference id kept in my object and if those matches I update. When I look at it I think it is far from being perfect. I remember I wasted a lot of time on that and that was probably the only one which made any sense back then.

Thanks for looking back into this!
It’s true that all that hastle could simply be fixed by providing a reference to the modified RhinoObject in the Rhino.RhinoDoc.TextureMappingEventArgs … Looks like an oversight because the current interface is really unpractical.