0
$\begingroup$

I have a label which is linked to an anchor. The problem is to find on which one of the four side of the label (which is a Rectangle) should be linked to the anchor.

|label|<----[anchor]

So I created a vector from the label center to the top right of the label (v1), a vector from the center to the bottom right (v2), to the top left (v3) and bottom left (v4). I also create a vector from the center of the label to my anchor (v).

My problem is to find if v is between (v1,v2) , (v1,v3) , (v1, v4) or(v4, v2) so I can know from which side I should link my anchor.

to calculate if a vector v is between v1 and v2 I use the following formula :

 (crossProduct v1, v >= 0 and crossProduct v, v2 >= 0) or 
 (crossProduct v1, v <= 0 and crossProduct v, v2 <= 0)

where crossProduct is calculated with the following formula:

v1.y * v2.y - v1.x * v2.x

However I'm not able to find the correct side of the rectangle.

$\endgroup$

marked as duplicate by Rahul, Antonios-Alexandros Robotis, John B, Shailesh, JonMark Perry Mar 17 '16 at 1:50

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • $\begingroup$ Are you trying to find the nearest side of the rectangle to the anchor, then? $\endgroup$ – amd Mar 15 '16 at 19:50
  • $\begingroup$ Exactly, I ended up using atan2 and and calculate the angles of each of the vectors. $\endgroup$ – Ben D Mar 16 '16 at 9:11
  • $\begingroup$ There’s no need to involve inverse trig functions. See my answer, below. $\endgroup$ – amd Mar 16 '16 at 19:01
0
$\begingroup$

If you extend the diagonals of the rectangle, they divide the plane into four regions. We want to find the region in which the anchor lies.

For a square centered on the origin, this is easy: If $|x|>|y|$, then it’s the right or left side depending on the sign of $x$; if $|x|<|y|$, then it’s the top or bottom depending on the sign of $y$; if they’re equal, pick one of the two possibilities. To handle the general case, transform it into the simple one, i.e., translate so that the center of the rectangle is at the origin and scale to make it a square. This leads to the transformation: $$\begin{align} x_a' &= (x_a-x_c)/w \\ y_a' &= (y_a-y_c)/h, \end{align}$$ where $(x_a,y_a)$ are the anchor coordinates, $(x_c,y_c)$ are the coordinates of the rectangle’s center, and $(w,h)$ are its dimensions.

If you also rotate through an angle of $\frac\pi4$, you just need to compare the signs of $x$ and $y$, but that introduces division by $\sqrt2$ and more multiplications, which is pretty likely to be slower.

The above assumes that the sides of the rectangle are aligned with the coordinate axes. If they’re not, it’s still possible to use this technique, but working out the appropriate transformation gets more complicated.

$\endgroup$
0
$\begingroup$

If you define between-ness as for its argument $t, \theta$ as $ t_1< t < t_2 $ where $t$ are all positive ( decided by $atan2$ function ) , Suppose have $ t=1,3, 6 $ or $t= 1,3,-.28 $, $ t=3$ is always the in-between, middle sandwiched angle. We need to consider ordered angles in ascending or descending order.

$\endgroup$
-1
$\begingroup$

I thought of a method that uses dot product (Edit: For code involving cross product, see the end of the answer). Refer this diagram:

vector diagram

Find the cosine of the angle between $\vec {v\,}$ and $\vec {v_1}$ using dot product, as: $$ \cos \theta = \dfrac{\vec {v\,}\cdot\vec {v_1}}{|\vec{v\,}||\vec{v_1}|}$$ Then find the cosine of the angle between $\vec {v_2}$ and $\vec {v_1}$ and compare the two cosines. The angle with larger cosine will be the smaller angle. (If the cosine comes negative for the pair including $\vec {v\,}$, then it surely can't be near that vector with which it was paired). Repeat this for other 3 vectors.

Note that you wouldn't need to find the angle between any two vectors.

Important Edit: Change the code block:

(crossProduct v1, v >= 0 and crossProduct v, v2 >= 0) or 
(crossProduct v1, v <= 0 and crossProduct v, v2 <= 0)

to

(crossProduct v1, v >= 0 and crossProduct v, v2 <= 0) or 
(crossProduct v1, v <= 0 and crossProduct v, v2 >= 0)

or simply

((crossProduct v1, v) * (crossProduct v2, v) >= 0 )

To essentially check if the cross product in both cases is of same or opposite sign. Hope this helps!

$\endgroup$
  • $\begingroup$ Thanks for your reply. Your solution seems ok, but in the mean time I found another solution which I think is close to yours. I calculate the atan2 of each of the 5 vectors and then I check between which of those angles v is placed. $\endgroup$ – Ben D Mar 16 '16 at 9:14
  • $\begingroup$ You're welcome! A small suggestion: the method involving atan could be less efficient. You could use your crossProduct which would be simpler and more efficient too! Cheers! $\endgroup$ – FreezingFire Mar 16 '16 at 10:01

Not the answer you're looking for? Browse other questions tagged or ask your own question.