Archive for June, 2010

Graphics using Python’s standard library (Tkinter)

I really dig Python. It just (seemingly) has no built-in graphics capabilities, which makes me sad. Or DOES it? It ships with the Tkinter module, right? Which can display built-in graphics via its canvas widget.  Based on that, presumably you can start to do some simple interactive graphical applications a-la Pygame \ Processing.  Right?

Well, I thought I’d give it a shot.  Considering I’ve not ever used Tkinter, this was my first real foray into that arena.  But you can display graphics and bind callbacks to events, so it has the foundation for doing what I want.

My first attempt is listed below.  Some things I learned:

  • How to query the mouse position in the Tkinter window.
  • How to create a rectangle, that will follow the mouse around.
  • How to… make a Tkinter window with callbacks that make all the magic happen.

Not very impressive on it’s own:  All you get is a small window with a blue rectangle that follows the mouse.  But baby steps here.  I’m interested to see how far this can go.

from Tkinter import *

class Rect(object):
    def __init__(self, canvas, width, height):
        self.canvas = canvas
        self.width = width
        self.height = height
        self.x = 0
        self.y = 0
        coord = self.getCoordinates()
        self.rect = self.canvas.create_rectangle(coord[0], coord[1],
                                                 coord[2], coord[2],
                                                 fill="blue")

    def getCoordinates(self):
        # Used to define the sides of the rect based on a starting x,y position.
        left = -self.width/2 + self.x
        top = -self.height/2 + self.y
        right = self.width/2 + self.x
        bottom = self.height/2 + self.y
        return left, top, bottom, right

    def move(self, x, y):
        # Move the Rect object to a new location.  What is called to by the
        # UI callback moveRect()
        deltaX = x - self.x
        deltaY = y - self.y
        self.canvas.move(self.rect, deltaX, deltaY)
        self.x = x
        self.y = y

class App(object):

    def __init__(self, width=256, height=256):
        self.width = width
        self.height = height

        self.root = Tk()
        self.root.title("tkinter_test01")
        self.root.geometry("%sx%s"%(self.width, self.height))

        self.canvas = Canvas(self.root, width=self.width, height=self.height)
        # Bind the event to move our Rect:
        self.canvas.bind("<Motion>", self.moveRect)
        self.canvas.pack()

        # Create our Rect object:
        self.rect = Rect(self.canvas, 32, 32)

        self.root.mainloop()

    def moveRect(self, event):
        # Callback that will move our Rect object
        self.rect.move(event.x, event.y)

if __name__ == "__main__":
    App()

New PyGame app: simpleParticle01

Been a while, but I finally got around to doing another simple PyGame app, which I’ve called ‘simpleParticle01’ (descriptive, yes…).

Find executable download, Python source, and description over on its page.

Find executable download, Python source, and description over on its page.

Uninstance all instances in a Maya scene

From over on my mel wiki:

Maya makes it easy to create an instance of a node, but I’ve found no built-in way to query what nodes in the scene are instanced.  Poking around a bit in the API however, it only takes a few lines of code:

# Python code
import maya.cmds as mc
import maya.OpenMaya as om

def getInstances():
    instances = []
    iterDag = om.MItDag(om.MItDag.kBreadthFirst)
    while not iterDag.isDone():
        instanced = om.MItDag.isInstanced(iterDag)
        if instanced:
            instances.append(iterDag.fullPathName())
        iterDag.next()
    return instances

This function will return a list of all the instances in the scene, nice! I have yet to find any other function that can do this via mel.

But how would you actually uninstance them? I worked on this problem quite a bit: If you simply have a bunch of leaf nodes that are instanced, it’s not hard to do. But if you have a say ten spheres all instanced, then you make two groups of five, then instance those groups, and parent all the groups, then instance that parent… very quickly things get hairy:  You try and uninstance a leaf by duplicating it, and now the duplicate appears in every other parental instance!
Like I just mentioned, most solutions I’ve found explain you can just ‘duplicate the instance’ to solve this problem, and this works on an individual instance that has no parent node that is an instance.  But when you have the situation I list above, the solution I found is this:  You can actually duplicate the instances parent, then delete the original parent, which will (via a loop) cleanly uninstance everything in the scene.  And since the getInstances() function returns a list parent-first, this works out great:

def uninstance():
    instances = getInstances()
    while len(instances):
        parent = mc.listRelatives(instances[0], parent=True, fullPath=True)[0]
        mc.duplicate(parent, renameChildren=True)
        mc.delete(parent)
        instances = getInstances()

lambda and map in Maya

Starting using a couple shorthand techniques today via map and lambda to save on screen real estate when authoring Python modules in Maya.  I often times will troll the scene for info and want to print stuff:

Here, I find the transform name for all mesh in the scene, then print them all with tabs in front:

import sys
import maya.cmds as mc
# Get transform for each mesh:
shapes = mc.ls(type='mesh')
transforms = map(lambda x: mc.listRelatives(x, parent=True)[0], shapes)
# print with tab in front:
map(lambda x: sys.stdout.write('\t%s\n'%x), transforms)

By using our map / lambda combo, I’m able to side-step the need to write any loops. Here’s how it would look otherwise:

import maya.cmds as mc
# Get transform for each mesh:
shapes = mc.ls(type='mesh')
transforms = []
for s in shapes:
    transforms.append(mc.listRelatives(s, parent=True)[0])
# print with tab in front:
for tran in transforms:
    print '\t', tran

Not counting imports and comments, I halved the number of lines of code. One could argue the bottom example is possibly more readable however.

openFrameworks + Code::Blocks Install

A while back I picked up the book Programming Interactivity, since it deals with Processing, Arduino, and openFrameworks.  I know a bit of Processing and Arduino, I mainly got it as a primer to help me wrap my head around c++ through openFrameworks.  As I quickly learned though, as a c++ \ openFrameworks noob, there were some serious holes in getting the install working.  I’m sure people that are more versed in the languages take this stuff for granted, but it took me a bit of searching.  I was also surprised that I could find no all-inclusive install tutorial for using openFrameworks with Code::Blocks, the IDE the book (and apparently openFrameworks) recommend using.  Took me a while to get it working, so I will log my steps here for future generations to follow.  I should point out this is being done on a WinXP system.

Install Code::Blocks

openFrameworks does have a install process for Code::Blocks here.  I followed that exactly after downloading the Code::Blocks binary release.

Download openFrameworks

I downloaded the ‘code blocks FAT’ file and unzipped it.  One of the key pieces that was missing was where to pit this data.  I had tried a variety of subdirs on my computer, but couldn’t ever get any of the openFrameworks projects to compile.  Finally after a lot of web searching, I learned I needed to put it in:

c:\openframeworks

So that’s exactly what I did, and things started working better.

Run Some Examples

In Code::Blocks, I opened the ‘workspace’:
C:\openframeworks\apps\examples\textureExample\textureExample.workspace
(or any example workspace for that matter) and promptly bonked the ‘Build and Run’ button.  But an error occurred:

error: 'exit' is not a member of 'std'|

After doing a bit of web searching, I ran across this post, which gives directions on how to modify the ‘ofConstants.h’ file (located C:\openframeworks\libs\openFrameworks\utils) to correct the issue.

After that, ‘Build and Run’ was appeased, and my openFrameworks career has officially started.