Maxxx
Maxxx

Reputation: 3595

How to move the end points of a line to keep its length but make it parallel to another line (C# preferably!)

I have a line segment whose end points I know

Line1 (X1,Y1) (X2,Y2)

I have a second line

Line2 (X3,Y3) (X4,Y4)

I want to calculate new end points for line 1 such that the resulting line is parallel to Line2, and Line1's centre point remains at the same coordinates.

i.e. such that Line1 simply rotates so it is parallel to Line2

I know I can calculate each line's angle

var line1Angle = (Mathf.Atan2(x2 - x1, y2 - y1));
var line2Angle = (Mathf.Atan2(x4 - x3, y4 - y3));

I can also calculate the lengths

var len1 = Math.Sqrt((x2-x1)*(x2-x1)+ (y2-y1) * (y2-y1));
var len2 = Math.Sqrt((x4-x3)*(x4-x3)+ (y4-y3) * (y4-y3));

but everything I have tried seems to fail - either not rotating correctly, or rotating but with the incorrect length.

The closest code I have (below) rotates correctly, but the length of Line1 is not retained.

The code uses an 'offset' which was used by the code this version is based on as it simply drew a parallel line 'offset' pixels from the destination line - I have set it to an arbitrary value but I believe should be the distance of Line1's centre point from the closest point on Line2.

I'd love it if someone could supply a code version, rather than an explanation (or as well as!) as I've read and tried so many non-code solutions, and evidently my understanding / translation to code is flawed!


float len1 = (float)Math.Sqrt((x2-x1)*(x2-x1)+ (y2-y1) * (y2-y1));
float len2 = (float)Math.Sqrt((x4-x3)*(x4-x3)+ (y4-y3) * (y4-y3));

float offset = 3.0f; // This should be the dist from our center to the closest wall but I"m compromising for now!
float newX1 = x3 + offset * (y4 - y3) * (len1 / len2);
float newX2 = x4 + offset * (y4 - y3) * (len1 / len2);
float newY1 = y3 + offset * (x3 - x4) * (len1 / len2);
float newY2 = y4 + offset * (x3 - x4) * (len1 / len2); 

Upvotes: 0

Views: 470

Answers (2)

JonasH
JonasH

Reputation: 36629

I would highly recommend that you define actual types for your line segment and points. You can use Math.Net or System.Numerics.Vectors if you want something to start with.

Assuming your line segment have a StartPoint and EndPoint we can define a MidPoint and Direction extension methods. I'm going to use the Math.Net types for the example, but it is not difficult to make your own types.

static Vector2D Midpoint(this Line2D l) => (l.StartPoint + l.EndPoint) / 2;
static Vector2D Direction(this Line2D l) => (l.EndPoint - l.StartPoint ).Normalize() ;

We can also define a static method to create a new line from these methods/Properties:

static Line2D FromMidpointDirection(Vector2D midpoint, Vector2D direction, float length){
    var halfDir = direction  * length/ 2;
    return new Line2D(midpoint - halfDir , midpint + halfDir );

Note that you might want to add comments or pick another name for Direction, since it is not obvious if this is normalized or not.

Then you can recreate your line:

var mid = sourceLine.Midpoint();
var dir = targetLine.Direction();
var newLine = FromMidpointDirection(mid, dir,sourceLine.Length);

Using higher level types like this tend to make your code more reusable and easier to read and understand.

Upvotes: 0

MBo
MBo

Reputation: 80287

Approach without angles: you know segment lengths, and can just form new segment ends with the same direction as line2 defines

dx1 = x2 - x1
dy1 = y2 - y1
dx2 = x4 - x3
dy2 = y4 - y3
len1 = hypot(dx1, dy1)
len2 = hypot(dx2, dy2)
midx = (x1 + x2) / 2
midy = (y1 + y2) / 2
coeff = 0.5 * len1 / len2

//now we make a vector with direction of line2
//and length of half of line1

newx1 = midx - dx2 * coeff  
newy1 = midy - dy2 * coeff
newx2 = midx + dx2 * coeff
newy2 = midy + dy2 * coeff

Upvotes: 1

Related Questions