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);
}