1. NodeBox 1
    1. Homepage
    2. NodeBox 3Node-based app for generative design and data visualization
    3. NodeBox OpenGLHardware-accelerated cross-platform graphics library
    4. NodeBox 1Generate 2D visuals using Python code (Mac OS X only)
  2. Gallery
  3. Documentation
  4. Forum
  5. Blog

graphics objects, layout, algorithm animation

Posted by Neal on Feb 27, 2007


Hi, I'm experimenting with nodebox for algorithm animation, and finding that an object-oriented approach seems natural.

E.g., to display text in a box, I define a "text_box" class that has a bunch of parameters and a draw method that draws a box with text in it.

I also imagine being able to use objects to do layout at a higher level. E.g., "put this object to the right of this object" instead of calculating detailed coords.

So, question 1: I'm wondering if anyone is working on building a utlity library of drawable objects, possibly with layout?

Also, question 2: The basic approach I'd like to take for animating an algorithm would be to first implement the algorithm without thinking about animating it (but with classes representing the objects of interest). Then, once the implementation is done, augment the classes in a systematic manner (preferably in a separate file) to add drawing methods. That is, I'd like to keep the algorithm logic separate from the graphic presentation. (Similar to how one tries to put only structured content in HTML, and then use separate CSS files to control the presentation.) I'm wondering if any nodebox users have figured out good ways of doing this.

thanks.



Posted by Tom De Smedt on Mar 5, 2007

Hi Neal,

OO is an excellent way to organise projects, especially if they go beyond the range of a short and simple layout script. In fact, most of the drawing primitives in NodeBox *are* objects (Rect, Oval, BezierPath, Image) but we added a simple command layer on top of that for people with no programming experience. Take a look at the Dendrite example in the gallery to see how you can manipulate a BezierPath object directly for example.

We are currently working on a node-based implementation, in which everything basically are nodes or objects.

As for your second question, inheritance of classes seems a logical approach (e.g. starting out with an Object class and then inheriting that into a TextBox class for example):

class Object:
    
    def __init__(self, x, y, w, h):
        self.x = x
        self.y = y
        self.w = w
        self.h = h
 
class Text(Object):
    
    def __init__(self, txt, x, y, w, h):
        Object.__init__(self, x, y, w, h)
        self.txt = txt
    
    def draw(self):
        _ctx.text(self.txt, self.x, self.y, width=self.w, height=self.h)
        
t = Text("hello there", 10, 100, 100, 100)
t.draw()


Another thing that you may want to look at is writing your own NodeBox libraries. Every time you write a script that you are planning to reuse in a lot of places / on a lot of occasions, making a library out of it is a good idea.

Notice how in the above example I prepend the text() command with _ctx. The _ctx represents the context in which you are currently drawing, i.e. the canvas of the current NodeBox script running. This way you could save the file, import it with ximport() in another script file, and ensure the output is drawn to the current canvas.

Take a look at the SVG library to get an idea of how _ctx works.

Hope that helps!
Tom



Posted by NEal on Mar 11, 2007


Thank you Tom.

I see that I can construct BezierPath objects without drawing them.

Next I am interested in laying out constructed objects.

For example, I'd like to construct two path objects, and then move one next to the other.

For that I would need to be able to (1) get the bounding boxes of the paths, and (2) perform a transform on the paths to move and/or scale them, and only after that, (3) draw them.

Are (1) and (2) possible?

Thanks!

Neal




Posted by Tom De Smedt on Mar 12, 2007

Hi Neal,

To get the bounds of a path you can use the bounds property:

path = textpath("hello", 100, 100)
(x,y), (width, height) = path.bounds
print x, y, width, height
 
rect(x, y, width, height)
 
fill(1)
drawpath(path)


If you want to transform paths, use the rotate(), scale() or translate() command prior to calling drawpath().