Start a new topic

Forcing scene / xform refresh after editing the values using Python

Original Post by: chrisell Thu Jul 24 22:06:27 2014


I've written a quick script to find groups with transforms in them and multiply all the delta values by 2. It works, but the scene doesn't refresh afterwards. I have to either touch all the transforms manually, or close and re-open the file to see them.


How can I force the currently-open scene to refresh to show all the modified transforms?


#!/usr/local/bin/python

import os

import sys

import math


def scaleTransforms (db, parent, rec, i):

item = mgGetCode(rec)

if (item == fltGroup):

itemName=mgGetName(rec)

if mgHasXform(rec):

transform = mgGetXform(rec)

transformType = mgGetXformType(transform)

if transformType == MXLL_TRANSLATE:

dummy,fromx,fromy,fromz = mgGetCoord3d(rec,fltXmTranslateFrom)

dummy,tox,toy,toz = mgGetCoord3d(rec,fltXmTranslateDelta)

print "Transform found in group ",itemName," from ",fromx,",",fromy,",",fromz," to ",tox,",",toy,",",toz

ok = mgSetCoord3d (rec, fltXmTranslateFrom, 0.0, 0.0, 0.0)

ok = mgSetCoord3d (rec, fltXmTranslateDelta, tox*2.0, toy*2.0, toz*2.0)

return MG_TRUE


editorContext = mgNewEditorContext ("Toolname")

db = mgEditorGetDbRec(editorContext)

mgWalk (db, scaleTransforms, None, 0, MWALK_MASTER)

mgRefreshScene(editorContext)


Original Post by: SteveThompson Mon Jul 28 20:30:02 2014


Ok, that explains it. Thanks for the update Chris.

Original Post by: chrisell Mon Jul 28 19:08:56 2014


Ok I can see where my confusion lies. In all my other scripts, I use this where I make my OWN list of entities - so I grab a bunch of stuff and populate my own Python list structures, then use that method to get stuff back out of those. I don't directly use that method to suck things out of the selectlist in the model itself.

So for example if I'm building a couple of lists of polys, one with specific colours and one with specific textures, I traverse the database using mgwalk and when I find matching items, dump them into my own python lists for later use.

Original Post by: SteveThompson Mon Jul 28 17:45:04 2014


Interesting. Is this something that’s unique to construction points ? I use the selectList method on all sorts of other things (polys, groups etc) in other scripts, which is what was confusing me here.

There is nothing special about construction vertices, they are simple mgrec records like any other node in the scene.


I am very surprised to hear that you can access mgreclist items using the index operator. As I alluded to in my last post, mgreclist is an opaque type in both C and Python variants of the OpenFlight API so there should not be any way that the Python interpreter can know how to slice it into individual items. Furthermore, looking at the mgreclist type, there is all sorts of "header" information at the front of the structure so, again, no way Python should be able to "slice" it up into items.


If you can dig up a script showing the index operator working on a mgreclist, I'd be interested in seeing it to understand what might be going on behind the scenes.


I tried using "selectList [ i ]" in several different script scenarios and have not found one to return the proper mgrec.

Original Post by: chrisell Mon Jul 28 16:54:05 2014


Interesting. Is this something that's unique to construction points ? I use the selectList method on all sorts of other things (polys, groups etc) in other scripts, which is what was confusing me here.


In the end, I went about it a slightly different way - I went through the construction entity functions and did an "is it selected" check. Brute force and not so efficient but it worked:


constructions=mgGetConstructList(db)

rec,matrix=mgGetNextRecInList(constructions)

while (rec):

if mgIsSelected(rec):

ok,coords=mgGetConstructVertexCoords(rec)

xCoord=coords.x

yCoord=coords.y

zCoord=coords.z

Original Post by: SteveThompson Mon Jul 28 16:01:22 2014


The problem with this script is that you are trying to reference selectList like an array. It is not an array type so you cannot access elements in it using the index operator ([]). i.e. you can't use:


selectList


When you pass this "bad" value to mgGetConstructVertexCoords, the value it returns is erroneous (the Python None value is returned). Since coords is None, you cannot access the ".x" value (None has no x field)


Instead you need to use the API mgreclist accessor functions to access elements in the selectList.


Here is a version of your script that shows how you might do that:


db = mgGetCurrentDb()

selectList = mgGetSelectList (db)

numSelectedPoints = mgGetRecListCount (selectList)

for i in range (0,numSelectedPoints):

print "CONSTRUCTION POINT"

constructVtx, mat = mgGetNthRecInList(selectList, i+1)

ok,coords = mgGetConstructVertexCoords(constructVtx)

Xposition = coords.x

Original Post by: chrisell Fri Jul 25 17:54:17 2014


Ok apparently I'm having a bad week for scripts. I can't even get a 5-liner together to print out the X position of all the selected construction verts.


selectList = mgGetSelectList (db)

numSelectedPoints = mgGetRecListCount (selectList)

for i in range (0,numSelectedPoints):

print "CONSTRUCTION POINT"

ok,coords = mgGetConstructVertexCoords(selectList)

Xposition = coords.x


It doesn't like "coords.x" and for the life of me I can't see it. I've been staring at the script for too long.

Original Post by: chrisell Fri Jul 25 14:48:12 2014


Makes good sense thanks !

Original Post by: SteveThompson Fri Jul 25 13:53:14 2014


Fair question... The OpenFlight API searches recursively for attributes on nodes. So in theory you could get or set vertex attributes through a polygon record. In this way you were able to get/set attributes of the transform through the group since the transform is attached to the group. This is useful (and necessary) for true nested records but can be a bit misleading (and dangerous) for attached records. In the vertex / polygon record example you can only access the first vertex. The API would not know how to look past the first attached record. In the group / translate case (yours) it finds the first translate. If you had two translate records attached you could not access the second.


So while the API has this "quirk" Creator does not. In your script, Creator sees that the group node got a new attribute value and refreshes the group attribute page but does not know that what really happened is that the transform of the group got updated. As a result the correct GUI elements in Creator don't know they need to update. When you talk directly to the transform record Creator knows to update things related to the transform.


Hope that makes sense.

Original Post by: chrisell Fri Jul 25 13:08:27 2014


Aha. That would explain it.

I suppose that begs the question: why did my original script work at all?

Original Post by: SteveThompson Fri Jul 25 00:34:56 2014


I believe there is a problem with your script. You are calling mgGetCoord3d and mgSetCoord3d on the group record instead of the transform record. I changed your script as shown below and Creator draws the nodes in their new positions just fine.


#!/usr/local/bin/python

import os

import sys

import math


def scaleTransforms (db, parent, rec, i):

item = mgGetCode(rec)

if (item == fltGroup):

itemName=mgGetName(rec)

if mgHasXform(rec):

transform = mgGetXform(rec)

transformType = mgGetXformType(transform)

if transformType == MXLL_TRANSLATE:

dummy,fromx,fromy,fromz = mgGetCoord3d(transform,fltXmTranslateFrom)

dummy,tox,toy,toz = mgGetCoord3d(transform,fltXmTranslateDelta)

print "Transform found in group ",itemName," from ",fromx,",",fromy,",",fromz," to ",tox,",",toy,",",toz

ok = mgSetCoord3d (transform, fltXmTranslateFrom, 0.0, 0.0, 0.0)

ok = mgSetCoord3d (transform, fltXmTranslateDelta, tox*2.0, toy*2.0, toz*2.0)

return MG_TRUE


editorContext = mgNewEditorContext ("Toolname")

db = mgEditorGetDbRec(editorContext)

mgWalk (db, scaleTransforms, None, 0, MWALK_MASTER)

mgRefreshScene(editorContext)

Login to post a comment