Example #1
0
 // Helper: leftOf(segment, point) returns true if point is "left"
 // of segment treated as a vector. Note that this assumes a 2D
 // coordinate system in which the Y axis grows downwards, which
 // matches common 2D graphics libraries, but is the opposite of
 // the usual convention from mathematics and in 3D graphics
 // libraries.
 public static bool GetIsLeft(Segment s, Vector2 p)
 {
     // This is based on a 3d cross product, but we don't need to
     // use z coordinate inputs (they're 0), and we only need the
     // sign. If you're annoyed that cross product is only defined
     // in 3d, see "outer product" in Geometric Algebra.
     // <http://en.wikipedia.org/wiki/Geometric_algebra>
     var cross =
         (s.End.Point.x - s.Start.Point.x) * (p.y - s.Start.Point.y)
         - (s.End.Point.y - s.Start.Point.y) * (p.x - s.Start.Point.x);
     return cross < 0;
     // Also note that this is the naive version of the test and
     // isn't numerically robust. See
     // <https://github.com/mikolalysenko/robust-arithmetic> for a
     // demo of how this fails when a point is very close to the
     // line.
 }
Example #2
0
        // Helper: do we know that segment a is in front of b?
        // Implementation not anti-symmetric (that is to say,
        // _segment_in_front_of(a, b) != (!_segment_in_front_of(b, a)).
        // Also note that it only has to work in a restricted set of cases
        // in the visibility algorithm; I don't think it handles all
        // cases. See http://www.redblobgames.com/articles/visibility/segment-sorting.html
        public static IntersectionResult IsInFrontOf(Segment a, Segment b, Vector2 relativeTo)
        {
            // NOTE: we slightly shorten the segments so that
            // intersections of the endpoints (common) don't count as
            // intersections in this algorithm
            const float epsilon = 0.01f;
            bool A1 = ShadowMathUtils.GetIsLeft(a, ShadowMathUtils.Interpolate(b.Start.Point, b.End.Point, epsilon));
            bool A2 = ShadowMathUtils.GetIsLeft(a, ShadowMathUtils.Interpolate(b.End.Point, b.Start.Point, epsilon));
            bool A3 = ShadowMathUtils.GetIsLeft(a, relativeTo);
            bool B1 = ShadowMathUtils.GetIsLeft(b, ShadowMathUtils.Interpolate(a.Start.Point, a.End.Point, epsilon));
            bool B2 = ShadowMathUtils.GetIsLeft(b, ShadowMathUtils.Interpolate(a.End.Point, a.Start.Point, epsilon));
            bool B3 = ShadowMathUtils.GetIsLeft(b, relativeTo);

            // NOTE: this algorithm is probably worthy of a short article
            // but for now, draw it on paper to see how it works. Consider
            // the line A1-A2. If both B1 and B2 are on one side and
            // relativeTo is on the other side, then A is in between the
            // viewer and B. We can do the same with B1-B2: if A1 and A2
            // are on one side, and relativeTo is on the other side, then
            // B is in between the viewer and A.
            if (B1 == B2 && B2 != B3) return IntersectionResult.InFront;
            if (A1 == A2 && A2 == A3) return IntersectionResult.InFront;
            if (A1 == A2 && A2 != A3) return IntersectionResult.Behind;
            if (B1 == B2 && B2 == B3) return IntersectionResult.Behind;

            // If A1 != A2 and B1 != B2 then we have an intersection.
            // Expose it for the GUI to show a message. A more robust
            // implementation would split segments at intersections so
            // that part of the segment is in front and part is behind.
            //demo_intersectionsDetected.push([a.p1, a.p2, b.p1, b.p2]);
            return IntersectionResult.Intersects;

            // NOTE: previous implementation was a.d < b.d. That's simpler
            // but trouble when the segments are of dissimilar sizes. If
            // you're on a grid and the segments are similarly sized, then
            // using distance will be a simpler and faster implementation.
        }
Example #3
0
        private void Split(Segment segment, Vector2 middle, Queue<Segment> open)
        {
            Vector2 start = segment.Start.Point;
            Vector2 end = segment.End.Point;
            //Debug.LogFormat("Splitting {0}-{1} at {2}", start, end, middle);

            open.Enqueue(new Segment(start, middle));
            open.Enqueue(new Segment(middle, end));

            //Segment endSegment = new Segment(position, segment.End.Point);
            //segment.End.Point = position;
            //open.Enqueue(segment);
            //open.Enqueue(endSegment);
        }
Example #4
0
        private void AddTriangle(float angle1, float angle2, Segment segment, Segment previous)
        {
            Vector2 delta1 = new Vector2(Mathf.Cos(angle1), Mathf.Sin(angle1));
            Vector2 delta2 = new Vector2(Mathf.Cos(angle2), Mathf.Sin(angle2));

            Vector2 p1 = Center;
            Vector2 p2 = p1 + delta1;
            Vector2 p3 = new Vector2(0.0f, 0.0f);
            Vector2 p4 = new Vector2(0.0f, 0.0f);

            Gizmos.color = Color.blue;
            if (segment != null)
            {
                // Stop the triangle at the intersecting segment
                p3 = segment.Start.Point;
                p4 = segment.End.Point;
            }
            else
            {
                // Stop the triangle at a fixed distance; this probably is
                // not what we want, but it never gets used in the demo
                p3 = p1 + delta1 * 500;
                p4 = p1 + delta2 * 500;
            }

            Vector2 pBegin = ShadowMathUtils.LineIntersection(p3, p4, p1, p2);
            p2 = p1 + delta2;
            Vector2 pEnd = ShadowMathUtils.LineIntersection(p3, p4, p1, p2);

            if (_drawGizmos)
            {
                Gizmos.color = Color.green;
                Gizmos.DrawLine(p1, pBegin);
                Gizmos.DrawLine(p2, pEnd);

                //Gizmos.DrawLine(pBegin, pEnd);
                Gizmos.color = Color.yellow;
                Gizmos.DrawSphere(pBegin, 0.1f);
                Gizmos.color = Color.blue;
                Gizmos.DrawSphere(pEnd, 0.1f);
            }

            if (previous != null
                && ShadowMathUtils.Approximately(segment.Slope, previous.Slope)
                && ShadowMathUtils.Approximately(Output.Last(),pBegin))
            {
                // It's a continuation of the previous segment!
                Output.RemoveAt(Output.Count-1);
                Output.Add(pEnd);
            }
            else
            {
                Output.Add(pBegin);
                Output.Add(pEnd);
            }
        }
Example #5
0
 public EndPoint(Vector2 point, Segment segment)
 {
     Point = point;
     Segment = segment;
 }
Example #6
0
        public static SideTestResult SideTest(Segment s, Vector2 p)
        {
            float cross =
                (s.End.Point.x - s.Start.Point.x) * (p.y - s.Start.Point.y)
                - (s.End.Point.y - s.Start.Point.y) * (p.x - s.Start.Point.x);

            if (Math.Abs(cross) < 0.00001f)
            {
                return SideTestResult.On;
            }
            if (cross < 0)
            {
                return SideTestResult.Left;
            }
            return SideTestResult.Right;
        }