We closed this forum 18 June 2010. It has served us well since 2005 as the ALPHA forum did before it from 2002 to 2005. New discussions are ongoing at the new URL http://forum.processing.org. You'll need to sign up and get a new user account. We're sorry about that inconvenience, but we think it's better in the long run. The content on this forum will remain online.
IndexProgramming Questions & HelpPrograms › Give object instances their own canvas
Page Index Toggle Pages: 1
Give object instances their own canvas (Read 2067 times)
Give object instances their own canvas
Aug 9th, 2007, 8:35am
 
My first Processing project: I'm porting an ActionScript experiment ( http://www.gskinner.com/blog/archives/2005/01/varicoseg_exper.html ) to Processing. The AS code ( http://www.gskinner.com/blog/archives/2005/01/source_code_var.html ) recursively spawns MovieClips (a Vein class that inherits from MovieClip) to draw the veins. In Flash each MovieClip functions like an encapsulated canvas. This makes it quite easy to task each instance of the vein class with drawing itself within its canvas.

Here's my immediate dilemma: If you take a gander at the AS experiment, you'll see that the entire canvas rotates and translates. This is achieved by creating a parent MovieClip within which all of the vein MovieClips are nested.

Does Processing have a similar ability (independent sub-canvases)? Based on my limited knowledge of Processing, I understand that if I were to translate a bunch of lines without clear()ing the sketch, they would just smear the canvas. But if I clear() the sketch on each frame, then I have to redraw the entire vein structure, which would greatly complicate the code.

Am I just trying to cram an AS square into a Processing circle?

Given the visual created by the AS experiment, how would you approach it in Processing?
Re: Give object instances their own canvas
Reply #1 - Aug 9th, 2007, 8:40am
 
Here are some heavily commented pasties of the two classes used in the AS experiment:

Vein: http://pastie.caboo.se/86208

VeinManager: http://pastie.caboo.se/86209
Re: Give object instances their own canvas
Reply #2 - Aug 9th, 2007, 2:18pm
 
Quote:
In Flash each MovieClip functions like an encapsulated canvas.


i think this is just your assumption. they draw to stage as far as i know, otherwise it would be pretty inefficent ...

to do something similar in processing, set up a class for the vein object, add a draw() function to it, create a loop inside PApplet.draw() that calles each vein instance. i think that's the best way to do it. see a similar question here:

http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Syntax;action=display;num=1186358380

F
Re: Give object instances their own canvas
Reply #3 - Aug 9th, 2007, 5:07pm
 
fjen wrote on Aug 9th, 2007, 2:18pm:
i think this is just your assumption. they draw to stage as far as i know...


I undertand that, under the covers, every MovieClip probably just draws to stage. What I meant by each MC using its own canvas is:

* Each MC has its own coordinate system. I.E. when drawing inside of an MC, [0,0] is the top left corner of the MC, not the top left corner of the stage.
* The DrawingAPI keeps an independent 'pencil' (if you will) for each MC. The lineTo() method draws starting at the last line drawn in the MC from which it was called, not the last line that was drawn to stage by any MC
* Calling the method to clear the lines produced by the DrawingAPI only clears the lines within the MC from which it was called. It seems to me that the clear() method in Processing clears the entire canvas (no way to scope it to the lines drawn by a single instance of a class)

fjen wrote on Aug 9th, 2007, 2:18pm:
...it would be pretty inefficent ...


You're absolutely right. ActionScript is notoriously inneficient (though Flash Player 9 and ActionScript 3 are much improved). Performance is one of the reasons (among a host of others) that I'm making the jump to Processing. It's exciting to be met with such a helpful community of Processing enthusiasts!
Re: Give object instances their own canvas
Reply #4 - Aug 9th, 2007, 6:57pm
 
Quote:
* Each MC has its own coordinate system. I.E. when drawing inside of an MC, [0,0] is the top left corner of the MC, not the top left corner of the stage.


that's what pushMatrix() and popMatrix() are for.

Quote:
* The DrawingAPI keeps an independent 'pencil' (if you will) for each MC. The lineTo() method draws starting at the last line drawn in the MC from which it was called, not the last line that was drawn to stage by any MC


that's a pretty special behavior. you can store these settings in a couple of variables.

Quote:
* Calling the method to clear the lines produced by the DrawingAPI only clears the lines within the MC from which it was called. It seems to me that the clear() method in Processing clears the entire canvas (no way to scope it to the lines drawn by a single instance of a class)


jep.

a way to do that is to let every object have it's own PGraphics. these are extending PImage, so you can use 'em with image() (see example).
be aware that PGraphics might be a little memory hungry, so creating thousands of objects is not recommended.
... and you have to give the PGraphics a fixed size.

F
Re: Give object instances their own canvas
Reply #5 - Aug 10th, 2007, 12:03am
 
OK, I have the main artery working. But I've run into a major snag. Since I have to instantiate the PGraphic object with a static width, the canvas space very quickly runs out. Not to mention, it's crazy slow.

Are there any other ways to accomplish this? What about drawing the vein system on a sphere and simply rotating the sphere to keep the head of the vein in view? Is it possible draw a line() directly onto a sphere()?

Here is the code I have so far. It works, but the artery hits the edge of the PGraphic pretty quickly:

Code:

PApplet app = this;

Vein artery;

void setup() {
size(800, 500);
background(0);
frameRate(50);
artery = new Vein(Vein.MAX_THICKNESS, width/2, height/2, random(2));
}

void draw() {
background(0);
}

public class Vein {
// contants
final static int MAX_THICKNESS = 5;

public float _y;
public float _x;

// private properties;
private PGraphics pg;
private int angle = 0;
private int thickness;
private int originalThickness;
private int count = 10;
private float yLast = 0;
private float xLast;

Vein (int thickness, float x, float y, float angle) {
// instantiate an instance of PGraphics
pg = createGraphics(1600, 1000, JAVA2D);
// set line width
thickness = originalThickness = thickness;
pg.strokeWeight(thickness);
// set x coordinate
_x = xLast = x;
// set y coordinate
_y = yLast = y;
// set initial angle
angle = angle;
// set color (not implemented)
// register to be drawn every frame
app.registerDraw(this);
}

void draw () {
// Generate a random seed (higher for thinner lines)

// This has the effect of causing smaller lines to move

// More eratically while the larger lines make less pronounced turns
float seed = MAX_THICKNESS-thickness+1;
// Add a random angle to the existing angle


angle += PI/180*(random(seed*20)-seed*10);


// Length to grow on this frame


float length = random(7)+seed+2;


// Add the length plus the cosine of the random angle


_x += length*cos(angle);


// Add the length plus the sine of the random angle


_y += length*sin(angle);
translate((-_x+width/2), (-_y+height/2));


// Draw the new addition
pg.beginDraw();
pg.stroke(255);
pg.strokeWeight(count);
pg.line(xLast, yLast, _x, _y);
pg.endDraw();
// store the current x and y for the next loop
xLast = _x;
yLast = _y;
// add the PGraphic to the sketch
image(pg, 50, 50);
}
}
Re: Give object instances their own canvas
Reply #6 - Aug 24th, 2007, 7:51pm
 
Code:

// fjenett 20070824

// using a different approach here:
// i have one master vein class that generates vein-pieces.
// these inherit from vein and generate the sub-vein-pieces.

Vein vein;

void setup ()
{
size(500, 500);
vein = new Vein( this );
frameRate( 20 );
smooth();
xx = width / 2.0;
yy = height / 2.0;
}

float xx, yy;
float antifraction = 0.08;

void draw ()
{
background( 0xEE220000 );

// move camera to the main veins position
xx += ((-vein.position.x+width /2)-xx)*antifraction;
yy += ((-vein.position.y+height/2)-yy)*antifraction;
translate(xx, yy);

// instead of registerDraw(), to be able to see stackOverFlow errors ..
vein.draw();
}

public class Vein
{
Point2D position;
float angle;
Vector pieces;
float strokeWeight = 8;
int strokeColor = 0xFFFF0000;

float birthRate;
float growRate;

Vein () {}

Vein ( PApplet _p )
{
//_p. registerDraw( this );
init( new Point2D( width/2, height/2 ), random(2) );
growRate = 3.0;
birthRate = 1.005;
}

void init ( Point2D _sp, float _a )
{
position = _sp;
angle = _a;
pieces = new Vector();
}

float DEG_2_RAD = PI/180.0;

public void add ()
{
Point2D nextPosition = position;
int cnt = (int)random( 0, birthRate );
if ( is_master ) cnt++;
for ( int i=0; i<cnt; i++ )
{
float thickness = is_master ? strokeWeight : strokeWeight*0.9;
float seed = thickness;
float length = random(growRate)+seed+2;
angle += DEG_2_RAD * ( random(seed*10) - seed*5 );
float _x = length * cos(angle);
float _y = length * sin(angle);
Point2D endPoint = new Point2D( position.x+_x, position.y+_y );
if ( i==0 )
nextPosition = new Point2D( endPoint.x, endPoint.y );
pieces.add( new VeinPiece( position, endPoint, thickness, is_master ? strokeColor : dim(strokeColor), angle, this ) );
}
position = nextPosition;
}

int dim ( int col )
{
int a = (col >> 24) & 0xFF;
int r = (col >> 16) & 0xFF;
int g = (col >> 8) & 0xFF;
int b = col & 0xFF;
r-=20; if ( r < 100 ) r = 100;
b+=8; if ( b > 180 ) b = 180;
return (a << 24) + (r << 16) + (g << 8) + b;
}

boolean is_master = true;
public void draw ()
{
if ( is_master ) add();
for ( int i=0; i<pieces.size(); i++ ) ((VeinPiece)pieces.get(i)).draw();
}
}

class VeinPiece
extends Vein
{
Point2D start, end;
int canGrow;

Vein parent;

VeinPiece () {}
VeinPiece ( PApplet _p ) {}

VeinPiece ( Point2D _s, Point2D _e, float _st, int _sc, float _a, Vein _p )
{
start = _s;
end = _e;
strokeWeight = _st;
strokeColor = _sc;

parent = _p;

birthRate = 1.1;
growRate = 5;

is_master = false;
canGrow = (int)random(20);

init(_e,_a);
}

void draw ()
{
if ( canGrow > 0 ) { super.add(); canGrow--; }
super.draw();

stroke( strokeColor );
strokeWeight( strokeWeight );
line( start.x, start.y, end.x, end.y );

if ( strokeWeight < 0.05 ) { parent.pieces.remove(this); return; }
strokeWeight -= 0.03;
}
}

class Point2D
{
float x, y;
Point2D ( float _x, float _y ) {
x = _x;
y = _y;
}
}

Page Index Toggle Pages: 1