FAQ
Cover
This is the archive Discourse for the Processing (ALPHA) software.
Please visit the new Processing forum for current information.

   Processing 1.0 _ALPHA_
   Programming Questions & Help
   Programs
(Moderators: fry, REAS)
   replicate, translate, or decapitate?
« Previous topic | Next topic »

Pages: 1 
   Author  Topic: replicate, translate, or decapitate?  (Read 2849 times)
Mark Hill

WWW Email
replicate, translate, or decapitate?
« on: Mar 23rd, 2005, 11:39am »


If there's anyone brave enough...  
 
I've got this continuous canvas that I've generated and am displaying using a number of replicate functions.
 
The wrap around works fine. The problem I'm having is when I draw to this image it's origin is the top-left. I want the drawing to appear in the center of the screen.
 
In the drawsn() method the current x and y pos can be offset against a central screen pos, but this throws the display and thus wrapping function out.
 
Can anyone see a solution as my head is battered from looking at replicates and offsets for too long.
 
 
Many thanks.
 
 
Code:
 
 
BGraphics buf;
color pen;
 
void setup() {
 
  size(200,200);
  buf = new BGraphics(800,800);
 
  for(int i=0; i<buf.pixels.length; i++)  {
    buf.pixels[i] = 0;
  }
 
  pen = color(255,255,255);
   
  bx = buf.width/2;
  by = buf.height/2;
 
  buf.ellipseMode(CENTER_DIAMETER);
  buf.strokeWeight(3);
 
  setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
}
 
void loop() {
 
  float oldbx=bx;
  float oldby=by;
 
  updatePos();
   
  smoothLine(buf,(int)oldbx,(int)oldby,(int)bx,(int)by,pen);
  drawscn();
}
 
 
 
// draw large Bimage to screen as a continuous surface.
int x1,y1,x2,y2,x3,y3;
 
void drawscn() {
 
  x3=(int)bx; // -width/2
  y3=(int)by; // -height/2 these will draw to center  
 
  x1=abs(buf.width-x3);
  x2=abs(width-x1);
  y1=abs(buf.height-y3);
  y2=abs(height-y1);
 
 
  if(x3>buf.width-width) {
    replicate(buf,0,y3,x2,y3+y1,x1,0,x1+x2,y1);
 
    if(y3>buf.height-height) {
 replicate(buf,0,0,x2,y2,x1,y1,x1+x2,y1+y2);
    }
  }
 
  if(y3>buf.height-height) {
    replicate(buf,x3,0,x3+x1,y2,0,y1,x1,y1+y2);
  }
 
  replicate(buf,x3,y3,x3+x1,y3+y1,0,0,x1,y1);
}
 
float bx,by;
float xmag, ymag = 0;
 
void updatePos() {
 
  float xlim = buf.width;
  float ylim = buf.height;
 
  xmag = (pmouseX-width/2)*0.030;
  ymag = (pmouseY-height/2)*0.030;
 
  if(xmag<= 0) {
    bx= (bx-xmag) % xlim;
  }
 
  else if(xmag>0)
  {
    // decrement
    bx = xlim - bx;
    bx = (bx+xmag) % xlim;
    bx = xlim-bx;
  }
 
  if(ymag<= 0) {
    by= (by-ymag) % ylim;
  }
 
  else if(ymag>0)
  {
    // decrement
    by = ylim - by;
    by = (by+ymag) % ylim;
    by = ylim - by;
  }
 
}
 
 
 
public void smoothLine(BGraphics g, int x1, int y1, int x2, int y2, color pen) {
  g.stroke(this.pen);      // Stroke on @ set weight
  g.line(x1,y1,x2,y2);     // draw the line  
  if(g.strokeWeight>1) {
    g.noStroke();  // strokeweight>1 causes strange behaviour so noStroke to be safe, probably quicker, too.
    g.ellipse(x1, y1, g.strokeWeight*2,g.strokeWeight*2);  // cap previous line with rounded end
  }
}  
 
Quasimondo

WWW Email
Re: replicate, translate, or decapitate?
« Reply #1 on: Mar 23rd, 2005, 6:09pm »

Replace your line  
 
Code:
smoothLine(buf,(int)oldbx,(int)oldby,(int)bx,(int)by,pen);

 
with this:
 
Code:
smoothLine(buf,((int)oldbx+width/2)%800,((int)oldby+height/2)%800,((int)bx+width/2)%800,((int)by+height/2)%800,pen);

 
 
Note: you will still need to do something at the edges - if oldbx is on the left and bx is on the right it will draw a straight line through the whole canvas. Same with oldby/by
« Last Edit: Mar 23rd, 2005, 6:12pm by Quasimondo »  

Mario Klingemann | Quasimondo | Incubator | côdeazur
Mark Hill

WWW Email
Re: replicate, translate, or decapitate?
« Reply #2 on: Mar 23rd, 2005, 8:52pm »

Thanks a lot Mario,
 
That saved me a headache. I'd tried the offset but not accounted for the additional %.
 
Yeah, I know about the line through the entire BImage as a result of the wrap around, I just wanted to iron out the other problem first.  
 
oldbx and bx can never be further apart than the scroll rate so I'll put a test in for that and account for the %800 - 0 wrap, too!
 
You're a good'un.
« Last Edit: Mar 23rd, 2005, 8:56pm by Mark Hill »  
Mark Hill

WWW Email
Re: replicate, translate, or decapitate?
« Reply #3 on: Mar 24th, 2005, 12:37am »

Nope! I've scratched my head and a few other places besides, and although I can deal with the wrap problem using the distance between the old and new positions. I'm still stuffed for continuing the line across the divides.
 
I've written a new loop (below) that isolates the areas around the overlaps in relation to the strokeWeight, but I'm buggered if I can work out what the additional draw function needs to be to maintain continuity...
 
Perhaps it's only possible with a line of a single width because of how the line draw and ellipse methods work.
 
Any help very much appreciated.
 
P.S How do I highlight code extracts as appears in other posts?
 
 
 
void loop() {
 
  background(255,0,0);
  
  oldbx=((int)bx+width/2)%buf.width;
  oldby=((int)by+height/2)%buf.height;
 
  updatePos();
  
  curbx =((int)bx+width/2)%buf.width;
  curby =((int)by+height/2)%buf.height;
  
  // Check that both coords are on the same side of the line
  if(abs( oldbx - curbx) < buf.width/2  
    && abs( oldby - curby) < buf.height/2) {  
    
    smoothLine(buf,oldbx, oldby, curbx, curby, pen);    
  }
  
   // are we in the cross over area?
   if(curbx>buf.width-buf.strokeWeight | curbx<0+buf.strokeWeight) {
    
     println(xlim-curbx); // gives the opposite of where you currently are.
    }
 
 
  // are we in the cross over area?
   if(curby>buf.height-buf.strokeWeight | curby<0+buf.strokeWeight) {
    
     println(ylim-curby); // gives the opposite of where you currently are.
    }
    
  drawscn();
}
« Last Edit: Mar 24th, 2005, 11:22am by Mark Hill »  
Quasimondo

WWW Email
Re: replicate, translate, or decapitate?
« Reply #4 on: Mar 24th, 2005, 1:38pm »

I guess what you will have to do if a line crosses an edge is to split that line in two parts - aka draw two lines: one from the old position to the edge and one from the opposite edge to the new position.
 
In the end I think that you could make it all easier for yourself by wrapping the whole canvas each time instead of wrapping the screen and then always draw your point at the middle of the canvas.
 
To highlight code, wrap it into  
 
(code)your code here(/code)
 
but use square brackets, not round ones (I don't know how to demostrate it properly)
 

Mario Klingemann | Quasimondo | Incubator | côdeazur
Mark Hill

WWW Email
Re: replicate, translate, or decapitate?
« Reply #5 on: Mar 24th, 2005, 3:05pm »


Thanks for the suggestion, Mario.
 
I'm not sure I follow. Wrapping the whole canvas is going to require a large blit. I know I can break this down over a number of frames, but I'm still not sure I follow you.
 
I've messed about with the existing drawing functions around the edges but I'm not sure I can maintain a thick line on a wrap.
 
Would you elaborate a little on what you mean by the whole canvas being wrapped.
 
Cheers
 
Quasimondo

WWW Email
Re: replicate, translate, or decapitate?
« Reply #6 on: Mar 24th, 2005, 7:45pm »

Yes - I thought about making a huge blit - I didn't try though, so it might be a too big performance hit.
 

Mario Klingemann | Quasimondo | Incubator | côdeazur
Quasimondo

WWW Email
Re: replicate, translate, or decapitate?
« Reply #7 on: Mar 24th, 2005, 8:19pm »

Okay, I tried something else: if a line gets drawn over the edge - let it draw over the edge - but do it twice. This makes it necessary to keep the information that we lost by using the %800 operator.
 
(I kicked some parts of your replication code out..)
 
Code:

 
BGraphics buf;  
color pen;  
 
void setup() {  
 
  size(200,200);  
  buf = new BGraphics(800,800);  
 
  for(int i=0; i<buf.pixels.length; i++)  {  
    buf.pixels[i] = 0;  
  }  
 
  pen = color(255,255,255);  
    
  bx = buf.width/2;  
  by = buf.height/2;  
 
  buf.ellipseMode(CENTER_DIAMETER);  
  buf.strokeWeight(3);  
  
  setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));  
}  
 
void loop() {  
 
  float oldbx=bx;  
  float oldby=by;  
  updatePos();  
  smoothLine(buf,((int)oldbx+width/2),((int)oldby+height/2),((int)bx+widt h/2),((int)by+height/2),pen);  
  bx=(bx+buf.width)%buf.width;
  by=(by+buf.height)%buf.height;
  drawscn();  
}  
 
 
 
// draw large Bimage to screen as a continuous surface.  
int x1,y1,x2,y2,x3,y3;  
 
void drawscn() {  
  
  x3=(((int)bx%buf.width)+buf.width)%buf.width;
  y3=(((int)by%buf.height)+buf.height)%buf.height;
 
  x1=abs(buf.width-x3);  
  x2=abs(width-x1);  
  y1=abs(buf.height-y3);  
  y2=abs(height-y1);  
 
 
  if(x3>buf.width-width) {  
    replicate(buf,0,y3,x2,y3+y1,x1,0,x1+x2,y1);  
 
    if(y3>buf.height-height) {  
 replicate(buf,0,0,x2,y2,x1,y1,x1+x2,y1+y2);  
    }  
  }  
 
  if(y3>buf.height-height) {  
    replicate(buf,x3,0,x3+x1,y2,0,y1,x1,y1+y2);  
  }  
 
  replicate(buf,x3,y3,x3+x1,y3+y1,0,0,x1,y1);  
}  
 
float bx,by;  
float xmag, ymag = 0;  
 
void updatePos() {  
  xmag = (pmouseX-width/2)*0.030;  
  ymag = (pmouseY-height/2)*0.030;  
  bx+=xmag;
  by+=ymag;
}  
 
 
 
public void smoothLine(BGraphics g, int x1, int y1, int x2, int y2, color pen) {  
  g.stroke(this.pen);      // Stroke on @ set weight  
  g.line(x1,y1,x2,y2);     // draw the line  
  
  if(g.strokeWeight>1) {  
    g.noStroke();  // strokeweight>1 causes strange behaviour so noStroke to be safe, probably quicker, too.  
    g.ellipse(x1, y1, g.strokeWeight*2,g.strokeWeight*2);  // cap previous line with rounded end  
  }  
  
  boolean drawagain=false;
  if (x1<0){
    x1+=buf.width;
    x2+=buf.width;
    drawagain=true;  
  } else if (x1>buf.width){
    x1-=buf.width;
    x2-=buf.width;
    drawagain=true;  
  } else if (x2<0){
    x1+=buf.width;
    x2+=buf.width;
    drawagain=true;  
  } else if (x2>buf.width){
    x1-=800;
    x2-=800;
    drawagain=true;  
  }
  
  if (y1<0){
    y1+=buf.height;
    y2+=buf.height;
    drawagain=true;  
  } else if (y1>buf.height){
    y1-=buf.height;
    y2-=buf.height;
    drawagain=true;  
  } else if (y2<0){
    y1+=buf.height;
    y2+=buf.height;
    drawagain=true;  
  } else if (y2>buf.height){
    y1-=buf.height;
    y2-=buf.height;
    drawagain=true;  
  }
  if (drawagain){
    g.line(x1,y1,x2,y2);    
    if(g.strokeWeight>1) {  
      g.noStroke();  // strokeweight>1 causes strange behaviour so noStroke to be safe, probably quicker, too.  
      g.ellipse(x1, y1, g.strokeWeight*2,g.strokeWeight*2);  // cap previous line with rounded end  
      g.ellipse(x2, y2, g.strokeWeight*2,g.strokeWeight*2);  // cap previous line with rounded end  
    }    
  }
 
  
}  
 
« Last Edit: Mar 24th, 2005, 8:21pm by Quasimondo »  

Mario Klingemann | Quasimondo | Incubator | côdeazur
Mark Hill

WWW Email
Re: replicate, translate, or decapitate?
« Reply #8 on: Mar 25th, 2005, 1:21am »

It's a very neat solution and does a terrific job, but... when you make the crossover between wraps at angles of incidence like   \|   that, it runs into problems like half-printing a line as you run down the seam of the wrap . I've messed about with a strokeWeight compensation but to no avail.
 
My next thought is: why not draw the line to the visible screen and backward blit to the buf as a sprite, so effectively we end up with:
 
replicate buffer to screen - draw line - replicate screen to buffer  
 
I know it's crude, but I'm gonna give it a go, as I can see the strokeWeight problem persisting, although I may be wrong...? This way the draw function is out of the way, and only confined to a small area requiring backwards duplication, making the wrapping problem as straightforward as the buffer to screen blit.
« Last Edit: Mar 25th, 2005, 12:31pm by Mark Hill »  
Mark Hill

WWW Email
Re: replicate, translate, or decapitate?
« Reply #9 on: Mar 25th, 2005, 8:03pm »

Here it is at last! I ended up doing as I suggested in my last post and performed blit from the buffer to the screen according to the current position, drew a line at the center of the screen and then blitted a rectangular portion of 20*20 (ish) screen pixels back to the buffer; essentially combining screen and buffer info.
 
This eliminates any need for tricky drawing functions across seams. It screws the smooth(); function, however and that poses another problem.
 
Thanks for all the help Mario. Much appreciated!
 
Code:

 
 
BGraphics buf;
color pen;
 
int backSize = 20;
 
void setup() {
 
  size(200,200);
  buf = new BGraphics(800,800);
  buf.background(26,26,0);
 
  pen = color(255,255,255);
 
  bx = buf.width/2-width;
  by = buf.height/2-height;
 
  ellipseMode(CENTER_DIAMETER);
  strokeWeight(4);
  blitX = width/2-backSize/2;
  blitY = height/2-backSize/2;
  
  noSmooth();
 
  setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
}
 
void loop() {
 
  updatePos();
 
  // Blit buffer to screen, draw line and blit back modified section to buffer
  drawscn();
  smoothLine(g,width/2,height/2,width/2+(int)xmag,height/2+(int)ymag,pen) ;
  backBlit();
  
 
}
 
int blitX,blitY;
 
void backBlit() {
 
  x3=(((int)bx%buf.width)+buf.width+blitX)%buf.width;
  y3=(((int)by%buf.height)+buf.height+blitX)%buf.height;
 
  x1 = abs(buf.width-x3);
  x2 = abs(x1-backSize);
  y1 = abs(buf.height-y3);
  y2 = abs(y1-backSize);
 
  // blit X wrap around
  if(x3>=buf.width-backSize) {
    buf.replicate(g,blitX+x1,blitY,blitX+x2+x1,blitY+backSize, 0,y3,x2,y3+backSize);
 
    // blit X and Y wrap
    if(y3>=buf.height-backSize) {
      buf.replicate(g,blitX+x1,blitY+y1,blitX+x2+x1,blitY+y2+y1, 0,0,x2,y2);
    }
  }
 
  if(y3>=buf.height-backSize) {
    buf.replicate(g,blitX,blitY+y1,blitX+backSize,blitY+y1+y2, x3,0,x3+backSize,y2);
  }
 
  buf.replicate(g,blitX,blitY,blitX+backSize,blitY+backSize, x3,y3,x3+backSize,y3+backSize);
}
 
// draw large Bimage to screen as a continuous surface.
int x1,y1,x2,y2,x3,y3;
 
void drawscn() {
 
  x3=(((int)bx%buf.width)+buf.width)%buf.width;
  y3=(((int)by%buf.height)+buf.height)%buf.height;
 
  x1=abs(buf.width-x3);
  x2=abs(width-x1);
  y1=abs(buf.height-y3);
  y2=abs(height-y1);
 
  // blit X wrap around
  if(x3>=buf.width-width) {
    replicate(buf,0,y3,x2,y3+y1, x1,0,x1+x2,y1);
 
    // blit X and Y wrap
    if(y3>=buf.height-height) {
      replicate(buf,0,0,x2,y2,x1, y1,x1+x2,y1+y2);
    }
  }
 
  if(y3>=buf.height-height) {
    replicate(buf,x3,0,x3+x1,y2, 0,y1,x1,y1+y2);
  }
 
  replicate(buf,x3,y3,x3+x1,y3+y1, 0,0,x1,y1);
}
 
float bx,by;
float xmag, ymag = 0;
 
void updatePos() {
  xmag = (pmouseX-width/2)*0.030;
  ymag = (pmouseY-height/2)*0.030;
  bx = (bx+xmag)%buf.width;
  by = (by+ymag)%buf.height;
}
 
public void smoothLine(BGraphics g, int x1, int y1, int x2, int y2, color penCol) {
  g.stroke(penCol);      // Stroke on @ set weight
  g.line(x1,y1,x2,y2);     // draw the line
 
  if(g.strokeWeight>1) {
    g.noStroke();  // strokeweight>1 causes strange behaviour, so noStroke to be safe, probably quicker, too.
    g.ellipse(x1, y1, g.strokeWeight*2,g.strokeWeight*2);  // cap previous line with rounded end
  }
}
 
« Last Edit: Mar 25th, 2005, 8:04pm by Mark Hill »  
Pages: 1 

« Previous topic | Next topic »