Tuesday 27 May 2014

Metasequoia Script – integer vertex coordinates

The registered version of Metasequoia allows scripting in the Python language.

This article will demonstrate a script to move all vertices (also known as points) in an object to integer coordinates.

An integer is a whole number like 1, 2, 3, 40, 75 etc.

A trial license for Metasequoia 4 is easy to obtain and unlocks all features for a limited time including the Script Editor. [link]

Start Metasequoia and click Primitive in the Command panel and create a box using the default values.

Create a Box in Meta

This creates a box with the vertices at integer coordinates so I will move them slightly. Make sure Snap to Grid is off.

Move the vertices

Click Panel>Script Editor in the menu to open the Script Editor.

Open the Script Editor

Click File>Open and navigate to the Script folder inside Metasequoia’s installation folder and open the file “outobj.py”.

Open the outobj.py

This is a script to export all objects to a simple Wavefront *.obj format and display it in the output window of the editor.

We will use this script just for reference and see what information is available to us from Metasequoia.

For a more thorough reference click Help>Index to display the API for Metasequoia scripting.
The API (Application Programming Interface) is a document that tells what information you can get from an application and what names you use to get it.

Modify the outobj.py script as shown below and save the script with a different name. Make sure the extension is ".py".

# assumes scale 1:1 

doc = MQSystem.getDocument()

num = doc.numObject
for n in range(0,num):
 obj = doc.object[n]
 if obj is None: continue
 numVert = obj.numVertex
 for v in range(0,numVert):
  x = obj.vertex[v].pos.x
  y = obj.vertex[v].pos.y
  z = obj.vertex[v].pos.z
  MQSystem.println("old: x:%f y:%f z:%f"%(x,y,z))
  x = round(x)
  y = round(y)
  z = round(z)
  MQSystem.println("new: x:%f y:%f z:%f"%(x,y,z))
  obj.vertex[v].pos.x = int(x)
  obj.vertex[v].pos.y = int(y)
  obj.vertex[v].pos.z = int(z)
MQSystem.println("Done")

The thing with Python is that indentation matters so make sure you indent the same as above. You can use spaces or tabs to indent but never use both in the same script.

Python is case sensitive so make sure the capitalisation is the same too.

Click Script>Run or press F5 to run the script. You will see the old and new coordinate values printed in the output window.

Run the script

Close the Script editor and return to Metasequoia.

You can check the coordinates are integer values by clicking Move, clicking Abs in the sub panel and then clicking on each vertex.

Check coordinate values in Meta

UPDATE:
I modified the script to apply to only visible objects and also for use if the object is not large enough.

Change the scale value in the script to suit. To change for 1:1 change the scale value to 1.

scale = 1

HeinzFritz at TombRaiderForums reported errors running the script in Metasequoia 3 and had to delete the last six lines of code for it to run.

As far as I can tell the code should be OK with Python 2 and Metasequoia 3.

In Metasequoia 3 you have to make sure the [EOF] is on the last line of the script, by itself and not indented.

# Metasequoia Python script 

MQSystem.clearLog()

# change scale to suit
scale = 1024

scale *= 1.0
objCount = 0
vertCount = 0

doc = MQSystem.getDocument()
num = doc.numObject
for n in range(0,num):
 obj = doc.object[n]
 if obj is None:
  continue
 if not obj.visible:
  continue
 objCount += 1 
 numVert = obj.numVertex
 vertCount += numVert
 for v in range(0,numVert):
  x = obj.vertex[v].pos.x
  y = obj.vertex[v].pos.y
  z = obj.vertex[v].pos.z
  MQSystem.println("\tx:%f y:%f z:%f"%(x,y,z))
  x = round(x*scale)/scale
  y = round(y*scale)/scale
  z = round(z*scale)/scale
  obj.vertex[v].pos.x = x
  obj.vertex[v].pos.y = y
  obj.vertex[v].pos.z = z
  MQSystem.println("\tx:%f y:%f z:%f\n"%(x,y,z))

if objCount == 0:
 MQSystem.println("No visible objects!")
elif vertCount == 0:
 MQSystem.println("No points found!")
else:
 MQSystem.println("Done. Scale was %d"%scale)



No comments:

Post a Comment