2

I want to test if a vector (a polygon vertex normal actually) is facing outward or inward. The polygon winds CW, edges goes from A (filled circle) to B (stroked circle). I have these normals a a result of preliminary calculations, now I want to test their facing.

enter image description here

Like this. Gray normals should be invalid while green normals should be validated. Probably I could do it by calculating angles, then simply compare them, but I really want to spare trigonometric calls here.

Is there any cheap method that compare only the "slopes" somehow? Something like this Bryce Boe CCW algorithm in this http://bryceboe.com/2006/10/23/line-segment-intersection-algorithm/

Geri Borbás
  • 15,810
  • 18
  • 109
  • 172

3 Answers3

1

The sign of the cross product of an edge vector with a normal vector will tell you on what side of the edge the normal vector points.

Compute (Xb - Xa).Ny - (Yb - Ya).Nx.

This will work for convex polygons.

For general polygons, you will have to intersect the supporting line of the normal with the polygon outline; you will find an even number of intersections (some possibly double); by linking them even-to-odd, you will know what portions of the line are inside or outside.

enter image description here

1

If you take the normal vector together with the vector formed by the two points of the segment (tail to head is clockwise), then to get from the segment vector to the normal you have to move counter clockwise. Call the normal N and the segment vector S, the counter-clockwise check becomes:

if(cross(S, N) > 0)
   // Bad
else
   // Good

The cross product is computed this way:

int cross(Vector p, Vector q)
{   return (p.x*q.y - p.y*q.x);
}

So if the normal is N = (0, 1) and S = (1, 0), the cross product gives 1*1 - 0*0 = 1 > 0 and this tells you that the normal is pointing out.

mrk
  • 3,061
  • 1
  • 29
  • 34
1

Cross product sign test suggested by the others is the solution.

public static bool PointIsLeftOfSegment(Vector2 point, Vector2 a, Vector2 b)
{
    float crossProduct = (b.x - a.x) * (point.y - a.y) - (b.y - a.y) * (point.x - a.x);
    return (crossProduct > 0.0f);
}

For the original question, I composed tests for both segments (considering acute angles as well).

bool acute = segmentA.IsPointLeft(segmentB.b);
bool leftA = segmentA.IsPointLeft(point);
bool leftB = segmentB.IsPointLeft(point);
bool outward = (acute) ? leftA && leftB : leftA || leftB;
bool inward = !outward;

Testbed just fine: https://vine.co/u/1137617915458592768

Geri Borbás
  • 15,810
  • 18
  • 109
  • 172