2

As part of a larger algorithm, I am traversing a set of interconnected line segments. On arriving at any vertex via a line segment, I need to find the leftmost line segment leaving from that point.

As an example, suppose I start at vertex A and follow line segment AB to arrive at vertex B, I now need to choose the leftmost of line segments BC, BD, BE... to arrive at the next vertex.

I can do this by taking the signed areas of each pair of exiting segments. If signed area of triangle BDC is positive, then BDC is counter-clockwise oriented so BC falls to the left of BD. I could then compare BC with BE and proceed likewise with other segments to find the leftmost exit. But this only works when angle CBD is acute. I will have to add a special case to handle obtuse CBD.

enter image description here

There must be a simpler way to do this. Any ideas?

Agnel Kurian
  • 53,593
  • 39
  • 135
  • 210
  • Could you consider the lines vectors in euclidian R^n, all starting from the vertex of interest (in your example B; that vertex would change after each step), and calculate the angles between them using the euclidian norm (see [wikipedia](http://en.wikipedia.org/wiki/Vector_space#Normed_vector_spaces_and_inner_product_spaces) for details)? – G. Bach May 14 '13 at 11:51
  • Is there a reason you aren't using a [quad-edge](http://en.wikipedia.org/wiki/Quad-edge_data_structure) representation or something like it? Then you could just follow one pointer. – David Eisenstat May 14 '13 at 12:34
  • If you need to build the circularly linked list in the first place, divide the outgoing half-edges from B into those with dy >= 0 and those with dy < 0 and then use determinant tests to sort each group. – David Eisenstat May 14 '13 at 12:38
  • I am not familiar with your terminology. I will need to research this. Thank you for your inputs. – Agnel Kurian May 14 '13 at 13:24
  • 1
    Why not get the `Atan2` angle of each line and test wich is nearest `180 degrees` or `Pi`. – Daniel Möller May 14 '13 at 13:45
  • If you don't have `Atan2` do `(EndY - StartY)/(EndX - StartX)`, taking care that those having negative `(EndX - StartX)` are to the left, the positives are to the right. – Daniel Möller May 14 '13 at 13:48
  • Instead of `atan2`, you might want to use [pseudoangles](http://stackoverflow.com/q/16542042/1468366). – MvG May 14 '13 at 13:58
  • @MvG The pseudoangle calculation is equivalent to the determinant test with a multiplication replaced by a slower divide. – David Eisenstat May 14 '13 at 14:04
  • "Leftmost" is ambiguous, so edit question and define it. In the examples, is BC "leftmost", or is it BD? – James Waldby - jwpat7 May 14 '13 at 14:11
  • @jwpat7 BC is leftmost in the above examples. – Agnel Kurian May 14 '13 at 15:08
  • @David Eisenstat, could you elaborate on how a determinant test avoids dividing by the vector length? – agentp May 17 '13 at 15:36
  • @george By clearing denominators. – David Eisenstat May 17 '13 at 16:02
  • David, I see. thats good for the problem posed with only two branches but it doesnt give you a value to sort on if you have a bunch you need to order. (im sure you knew that just thinking out loud..) – agentp May 17 '13 at 21:16

1 Answers1

2

Consider the line segments to be vectors. You want to choose the leftmost of BC, BD, BE, ... To do this, calculate the counter-clockwise angle between BA (which is AB in the reverse direction) and the other directed segments BC, BD, BE, ..

The segment you want is the one with the largest CCW angle.

To calculate the CCW angle for vector BX, use atan2() to calculate the orientation angles a and x for BA and BX. Then your CCW angle is (2π+x-a) mod 2π. (i.e. normalized to be in the interval [0,2π]).

brainjam
  • 18,180
  • 7
  • 49
  • 78
  • Thanks. This will work but is there a way I can avoid calling trigonometric functions and square roots? – Agnel Kurian May 16 '13 at 06:26
  • Probably, but that's a separate question. You might want to read up on pseudoangles (http://stackoverflow.com/questions/16542042/fastest-way-to-sort-vectors-by-angle-without-actually-computing-that-angle) or rational trigonometry (http://en.wikipedia.org/wiki/Rational_trigonometry), where you could perhaps combine the idea of spread with the way you were computing signed areas. – brainjam May 16 '13 at 12:55