Loading...
Logo
Processing Forum
pardon my geometry ignorance.

i've been racking my brain trying to remember how to do this, i found some helpful links


but i just can't seem to implement them in the way i want.

what i'm doing is simply drawing a line on the screen and i want to maintain the same thickness i.e. the same distance (distX) of ptA and ptB from the line. currently when i draw the line from top to bottom it's the proper thickness, but when drawing left to right it's much thinner.

how can i maintain the proper relationship of ptA to ptB even when the orientation flips, i.e. horizontal to vertical? i know it has something to do with measuring the angle.



thanks
Ken

Replies(6)

Hey frederickk,

You're right about measuring the angle. A very useful function for this is atan2.

Here is an example...

Copy code
  1. float x,y,xold,yold;
  2. int distance = 40;

  3. void setup() {
  4.   size(600,600);
  5.   background(255);
  6.   smooth();
  7. }

  8. void draw() {
  9.   fill(255,9);
  10.   rect(0,0,width,height);

  11.   x = sin(0.02 * frameCount)*width/3;
  12.   y = cos(0.02 * frameCount)*height/3;

  13. //  x = mouseX;
  14. //  y = mouseY;

  15.   translate(width/2,height/2); // if using mouseX and mouseY comment this line out
  16.   translate(x,y);

  17.   float angle = atan2(y - yold, x - xold);
  18.   rotate(angle);

  19.   stroke(0);
  20.   line(0,-(distance-10),0,(distance-10));

  21.   noStroke();
  22.   fill(217,22,121);
  23.   ellipse(0,-distance,10,10);

  24.   fill(0,156,225);
  25.   ellipse(0,distance,10,10);

  26.   fill(0);
  27.   ellipse(0,0,5,5);

  28.   xold = x;
  29.   yold = y;
  30. }

  31. void keyPressed() {
  32.   if (key == 'z') { if (distance > 6) { distance--; } }
  33.   if (key == 'x') { distance++; }
  34. }

Hope this helps!

Amnon
That's a useful code example - is it in the wiki?
amnon.

thanks, this is almost exactly what i'm looking for. the only issure i'm having now, is how would i do this for points i've already collected? i.e. for use with beginShape() when cycling through an array?

Copy code
  1. /*
  2.  * drawnPts = an array of previously drawn x,y coords
  3.  * that are being reloaded and and adjusted
  4.  */

  5. float thickness = 10;

  6. PVector[] lineA;
  7. PVector[] lineB;

  8. //adjust points
  9. //-----------------------------------------
  10. for(int i=1; i<drawnPts.length; i++) {
  11.   float angle = atan2(drawnPoints[i].y - drawnPoints[i-1].y, drawnPoints[i].x - drawnPoints[i-1].x);
  12.   //this is where i get confused, i'm not sure
  13.   //of how to implement the "angle"

  14.   PVector ptsA;
  15.   ptsA.x = drawnPts[i].x;
  16.   ptsA.y = drawnPts[i].y + thickness;
  17.   lineA[i] = ptsA;

  18.   PVector ptsB;
  19.   ptsB.x = drawnPts[i].x;
  20.   ptsB.y = drawnPts[i].y - thickness;
  21.   lineB[i] = ptsB;
  22. }


  23. //draw points
  24. //-----------------------------------------
  25. beginShape(QUAD_STRIP);
  26. for(int i=1; i<lineA.length; i++) {
  27.   vertex(lineA[i].x, lineA[i].y);
  28.   vertex(lineB[i].x, lineB[i].y);
  29.   vertex(lineB[i-1].x, lineB[i-1].y);
  30.   vertex(lineA[i-1].x, lineA[i-1].y);
  31. }
  32. endShape();
  


@ hndrsn6

Nope, just made it up. But if someone with wiki-access finds it wiki-worthy, feel free to add it.

@ frederickk

Can't run your code, so some general comments. Like you already know, using arrays and for loops is an easy way to repeat the process for multiple points. You can use the same sketch within the for loop, only you need to combine it with pushMatrix & popMatrix. Just put these at the beginning and end of the for loop and it should work as normal.

However using beginShape is problematic in this case, because...
Transformations such as translate(), rotate(), and scale() do not work within beginShape().
So you would need some kind of solution/workaround to tackle this issue.
Frederickk, I think you are touching on what is actually a slightly more complicated problem. Amnon's solution will work for some lines, but not all. It is not possible to guarantee that two parallel lines will always maintain an equal distance of separation. For example, in your original figure the distance between points A and B is greater at the bottom right corner (the right-angled bend). To illustrate it with a more extreme example,



Acute turns in the line force the parallel line to move further away in order to maintain parallelism. You can also get the problem of self-intersecting lines if the distance between the parallel lines is large enough. There are solutions to this, and it is related to a more general problem of creating a  straight skeleton .

Anyway, here is a processing sketch which should do what you need, assuming you are happy to tolerate the possibility of self-intersection around sharp internal angles. Someone more familiar with computational geometry may be able to simplify the calculation, but it appears to work well enough.
// Simple paralell lines sketch.
// Jo Wood, 1st September, 2010.
                                // The vertices of the original line to draw.
PVector[] points=new PVector[] {new PVector(40,50),  new PVector(250,50),  new PVector(100,100),
                                new PVector(50,200), new PVector(150,300), new PVector(350,300),
                                new PVector(350,200),new PVector(370,200), new PVector(370,300)};  
                                   
PVector[] parallelPoints;       // The vertices of the parallel line to construct.
float     distance = 30;        // Distance between the two lines.

void setup() 
{
  size(500,350);
  noLoop();
  smooth();
  noFill();
  strokeWeight(6);
  calcParallelLine();
}

void draw()
{
  background(255);
  
  // Draw original line.
  stroke(0,158,227);
  beginShape();
  for (PVector p : points)
  {
    vertex(p.x,p.y);  
  }
  endShape();
  
  // Draw parallel line.
  stroke(248,0,123);
  beginShape();
  for (PVector p : parallelPoints)
  {
    vertex(p.x,p.y);  
  }
  endShape();  
}

/* Calculates the vertex positions of a line parallel to the original
 * line at an approximate fixed distance.
 */
void calcParallelLine()
{
  parallelPoints = new PVector[points.length]; 
  
  // First vertex on parallel line uses vector from first to second vertex
  parallelPoints[0] = findNormal(points[0],points[0],points[1]);
  
  // Most of the parallel line uses the 'before' and 'after' vertices.
  for (int i=1; i
              
               length-1; i++)
  {    
    parallelPoints[i] = findNormal(points[i],points[i-1],points[i+1]);
  }
  
  
               // Last vertex on parallel line uses vector from penultimate to last vertex.
  parallelPoints[points.
               length-1] = findNormal(points[points.
               length-1],
                                               points[points.
               length-2],
                                               points[points.
               length-1]);
}


               /* Finds the normal at p0 - the intersection of two vectors p1 and p2.

                * Joining adjacent normals maintains parallelism with points p1-p0-p2.

                */

               private 
               PVector findNormal(
               PVector p0, 
               PVector p1, 
               PVector p2)
{
  
               // Calculate the vectors from p0 to its neighbours and standardize their lengths.
  
               PVector v1 = 
               new 
               PVector(p1.x-p0.x,p1.y-p0.y);
  
               PVector v2 = 
               new 
               PVector(p2.x-p0.x,p2.y-p0.y);
  v1.
               normalize();
  v2.
               normalize();
  
  
               // Find vector between the two new vectors and the angle between them.
  
               PVector v = 
               new 
               PVector(v2.x-v1.x,v2.y-v1.y);
  v.
               normalize();
 
  
               float 
               angleBetween = 
               PVector.
               angleBetween(v1,v2);
  
               if (
               Float.isNaN(
               angleBetween))
  {
    
               angleBetween = 
               PI;
  }
  
  
               // Calculate normal and scale it depending on the interior angle at p0.
  
               float d = distance/
               sin(
               angleBetween*.5);
  
               return 
               new 
               PVector(p0.x+d*v.y, p0.y-d*v.x); 
}


              
This is rather a side-question: Can you (or anybody else) recommand a specific book on "basic to intermediate level" geometry? I'm currently collecting suggestions for my personal "wish-list" of books to have at home and find geometry very interesting. In particular, when trying to do some new Processing sketches
 
What I'm looking for would be a bit more than the average school-geometry book/equation collection, but "practical" enough to have those things in it as well.