Sherif Sherif - 5 months ago 10
Java Question

How to draw a line that points correctly at images at the corners of the screen

I have some fixed position images at every screen edge and I want to find a way to be able to point at them correctly, I get both my old and new mouse points from MouseMoved and with those 2 points and the angle I can draw a line that reaches the end of the screen but unfortunately I can't make that line point correctly at the images


What your program is trying to do is:

  1. Find the angle that the line is supposed to have.
  2. Start by assuming the line is going to be very long so that it crosses the edge of the rectangle.
  3. Then cut it off at the point of crossing.

For example, assume the rectangle is 180 by 120, and that your angle is 45ยบ. The larger of the dimensions is 180, so you draw a line of length 180 at that angle:

Illustration of that situation

So you want to cut the line where the arrow is. Both your newX and your newY are outside of the frame. According to the logic of your program, you see that newX is greater than 1750, and so you cut it to 180 (the frame max y in my example). And the value of newY is greater than 850, and so you cut it to 120 (the rectangle's max Y in my example).

This means that almost always, you'll end up with the line end being at (180,120) instead of where the arrow is. This is because you just adjusted one coordinate, but you failed to find the corresponding Y on the line before continuing.

Basically, when you cut down newX to getWidth() - 100, you also need to find Y that will go with it and is on the same line. So you need to calculate Y again. Instead of:

    if (newX  > 1720)
        newX  = getWidth() - 100;

You need to have

    if (newX  > 1720)
        newX  = getWidth() - 100;
        newY = Math.round(oldY + (newX - oldX)*Math.tan(angle));

The new value of newY may still be outside of the rectangle. In fact, the new point is this:

New point that was calculated

So now you will adjust the value of Y - but again, you have to be careful, and match the value of X to that Y according to the same angle.

But beware: the method is not very good to begin with. Taking Math.max(getWidth(), getHeight()) as the initial length of the line is only going to work for certain points. But what if your point is near one corner and the other point is near the opposite corner? The diagonal of the rectangle is longer than either its width and height. So you'll get a line that is too short and won't reach the edge.

You could calculate the diagonal instead of max, but perhaps you should adopt a different method:

  1. Calculate the linear formula of the line (any line is y=ax+b).
  2. Calculate the Y for x=100 and x=width-100
  3. Calculate the X for y=100 and y=height-100
  4. Now you have four pairs of X and Y, find out which one of them is the correct one. Only two are going to be inside the frame, and only one of these is in the right direction.

    In fact, you don't need to calculate four points. If the original newX from the mouse event was to the right of the oldX, only calculate the formula at the right edge. The left edge doesn't interest you. If it was on the left, only calculate at the left edge. If the original newY from the mouse event was below the oldY, only calculate the formula at the lower edge, and if it was higher, only at the top edge. You'll end up with two points. Only one of them is "legal" (both x and y are in the rectangle), and you use that.

Calculating from the edges