17

I'm trying to draw a line between two (2D) points when the user swipes their finger across a touch screen. To do this, I plan on drawing a rectangle on every touch update between the X and Y of the previous touch update and the X and Y of the latest touch update. This should create a continuous and solid line as the user swipes their finger across the screen. However, I would also like this line to have an arbitrary width. My question is, how should I go about calculating the coordinates I need for each rectangle (x1, y1, x2, y2)?

--

Also: if anyone has any information on how I could then go about applying anti-aliasing to this line it'd be a massive help.

Ashif
  • 1,652
  • 14
  • 30
AaronDS
  • 851
  • 2
  • 13
  • 31
  • 2
    I'm confused, so you have the top left (x1,y1) and the bottom right (x2,y2) and need to create a rectangle with those points? Wouldn't the coordinates just be [(x1,y1),(x2,y1),(x1,y2),(x2,y2)]? – Danny Oct 21 '11 at 19:06
  • All the information I have to work with is the previous location of where the users finger was on the screen and the latest location. I need to draw a line between the two, with an arbitrary width. Note the rectangle needs to be centred as well. It's not as simple as you believe. This appalling illustration might or might not help. [link](http://dl.dropbox.com/u/17610534/picutre.png) (note the second coordinate on the top rectangle should actually be 150,50 but hopefully you'll understand what I'm getting at) – AaronDS Oct 21 '11 at 19:14
  • Why do you intend to use rectangles? Why not thick line segments? – datenwolf Oct 21 '11 at 19:48
  • datenwolf: On the platform I'm developing for, OpenGL only allows for 1px wide anti-aliased lines. – AaronDS Oct 21 '11 at 20:07

3 Answers3

24

Calculate a vector between start and end points

V.X := Point2.X - Point1.X;
V.Y := Point2.Y - Point1.Y;

Then calculate a perpendicular to it (just swap X and Y coordinates)

P.X := V.Y; //Use separate variable otherwise you overwrite X coordinate here
P.Y := -V.X; //Flip the sign of either the X or Y (edit by adam.wulf)

Normalize that perpendicular

Length = sqrt(P.X * P.X + P.Y * P.Y); //Thats length of perpendicular
N.X = P.X / Length;
N.Y = P.Y / Length; //Now N is normalized perpendicular

Calculate 4 points that form a rectangle by adding normalized perpendicular and multiplying it by half of the desired width

R1.X := Point1.X + N.X * Width / 2;
R1.Y := Point1.Y + N.Y * Width / 2;
R2.X := Point1.X - N.X * Width / 2;
R2.Y := Point1.Y - N.Y * Width / 2;
R3.X := Point2.X + N.X * Width / 2;
R3.Y := Point2.Y + N.Y * Width / 2;
R4.X := Point2.X - N.X * Width / 2;
R4.Y := Point2.Y - N.Y * Width / 2;

Draw rectangle using these 4 points.

Here's the picture:

Drawing rectangle between two points

EDIT: To answer the comments: If X and Y are the same then the line is exactly diagonal and perpendicular to a diagonal is a diagonal. Normalization is a method of making a length to equal to 1, so that the width of your line in this example will not depend on perpendiculars length (which is equal to lines length here).

Kromster
  • 7,181
  • 7
  • 63
  • 111
  • 1
    @Krom Stern Please elaborate the `Draw rectangle using these 4 points.` Your answer is great, but i am confused in determining the rectangle size by these 4 points. Pleas help. thanks. – Salman Khakwani Aug 15 '13 at 06:19
  • @SalmanKhakwani: I'm not sure how can I explain it even more simpler. What is exactly confuses you? – Kromster Aug 15 '13 at 09:47
  • I am following http://stackoverflow.com/questions/18229683/resize-line-from-endpoints question, and your answer seems very suitable for this question. Can you please answer that question, it will be very helpful for me :) – Salman Khakwani Aug 15 '13 at 12:00
  • great answer. i'd ditch the P intermediate variable though. and probably worth incorporating the ` * Width / 2` into N. – drewish Feb 01 '15 at 21:22
  • Thanks, It was saved my time. For those who use Qt to plot:-> Draw 4 pointst( R1X, R1Y, R2X, R2Y, R3X, R3Y and R4X, R4Y) using QPolygon and it was perfectly plotted with variable type as "double/float" instead of "int" to avoid loss of points when 2 input points are inclined. – Ashif May 26 '15 at 08:03
  • Use QPolygon as "QPolygon polygon; polygon << QPoint(R1X, R1Y) << QPoint(R2X, R2Y) << QPoint(R4X, R4Y) << QPoint(R3X, R3Y)"; – Ashif May 26 '15 at 10:01
8

Easy way (I'll call the "width" the thickness of the line):

We need to calculate 2 values, the shift on the x axis and the shift on the y axis for each of the 4 corners. Which is easy enough.

The dimensions of the line are:

width = x2 - x1

height = y2 - y1

Now the x shift (let's call it xS):

xS = (thickness * height / length of line) / 2

yS = (thickness * width / length of line) / 2

To find the length of the line, use Pythagoras's theorem:

length = square_root(width * width + height * height)

Now you have the x shift and y shift.

First coordinate is: (x1 - xS, y1 + yS)

Second: (x1 + xS, y1 - yS)

Third: (x2 + xS, y2 - yS)

Fourth: (x2 - xS, y2 + yS)

And there you go! (Those coordinates are drawn counterclockwise, the default for OpenGL)

Fault
  • 1,239
  • 4
  • 14
  • 18
0

If I understand you correctly, you have two end points say A(x1,y1) and B(x2,y2) and an arbitrary width for the rectangle say w. I assume the end points will be just at the middle of the rectangle's shorter sides meaning the distance of the final rectangles corner coordinates would be w/2 to A and B.

You can compute the slope of the line by;

s1 = (y2 - y1) / (x2 - x1) // assuming x1 != x2

The slope of the shorter sides is nothing but s2 = -1/s1.

We have slope, we have distance and we have the reference points.

We than can derive two equations for each corner point:

For one corner closer to A

C(x3,y3):

(y3 - y1) / (x3 - x1) = s2 // by slope

(y3 - y1)^2 + (x3 - x1)^2 = (w/2)^2 // by distance

replacing (y3 - y1) by a and (x3 - x1) by b yields

a = b * s2 // slope equation

// replace a by b*s2

b^2 * s2^2 + b^2 = (w/2)^2 // distance equaiton

b^2 = (w/2)^2 / (s2^2+1)

b = sqrt((w/2)^2 / (s2^2+1))

we know w and s2 and hence compute b

If b is known, we can deduce x3

x3 = b + x1

and a, as well

a = b * s2

and so y3

y3 = b*s2 + y1

we have one corner point C(x3,y3).

To compute the other corner point closer to A, say D(x4,y4), the slope equation can be constructed as

(y1 - y4) / (x1 - x4) = s2 and the calculations listed above should be applied.

Other two corners can be calculated with the steps listed here replacing A(x1, y1) with B(x2,y2).

tafa
  • 7,146
  • 3
  • 36
  • 40