Esempio n. 1
0
        /// <summary>
        /// Determines if line1 intersects line2, when line1 is offset by pos1 and line2
        /// is offset by pos2.
        /// </summary>
        /// <param name="line1">Line 1</param>
        /// <param name="line2">Line 2</param>
        /// <param name="pos1">Origin of line 1</param>
        /// <param name="pos2">Origin of line 2</param>
        /// <param name="strict">If overlap is required for intersection</param>
        /// <returns>If line1 intersects line2</returns>
        public static bool Intersects(Line2 line1, Line2 line2, Vector2 pos1, Vector2 pos2, bool strict)
        {
            if (line1.Horizontal && line2.Horizontal)
            {
                return(AxisAlignedLine2.Intersects(line1.MinX + pos1.X, line1.MaxX + pos1.X, line2.MinX + pos2.X, line2.MaxX + pos2.X, strict, false));
            }
            else if (line1.Vertical && line2.Vertical)
            {
                return(AxisAlignedLine2.Intersects(line1.MinY + pos1.Y, line1.MaxY + pos1.Y, line2.MinY + pos2.Y, line2.MaxY + pos2.Y, strict, false));
            }
            else if (line1.Horizontal || line2.Horizontal)
            {
                if (line2.Horizontal)
                {
                    // swap line 1 and 2 to prevent duplicating everything
                    var tmp  = line1;
                    var tmpp = pos1;
                    line1 = line2;
                    pos1  = pos2;
                    line2 = tmp;
                    pos2  = tmpp;
                }

                if (line2.Vertical)
                {
                    return(AxisAlignedLine2.Contains(line1.MinX + pos1.X, line1.MaxX + pos1.X, line2.Start.X + pos2.X, strict, false) &&
                           AxisAlignedLine2.Contains(line2.MinY + pos2.Y, line2.MaxY + pos2.Y, line1.Start.Y + pos1.Y, strict, false));
                }
                else
                {
                    // recalculate line2 y intercept
                    // y = mx + b
                    // b = y - mx
                    var line2YIntInner = line2.Start.Y + pos2.Y - line2.Slope * (line2.Start.X + pos2.X);
                    // check line2.x at line1.y
                    // line2.y = line2.slope * line2.x + line2.yintercept
                    // line1.y = line2.slope * line2.x + line2.yintercept
                    // line1.y - line2.yintercept = line2.slope * line2.x
                    // (line1.y - line2.yintercept) / line2.slope = line2.x
                    var line2XAtLine1Y = (line1.Start.Y + pos1.Y - line2YIntInner) / line2.Slope;
                    return(AxisAlignedLine2.Contains(line1.MinX + pos1.X, line1.MaxX + pos1.X, line2XAtLine1Y, strict, false) &&
                           AxisAlignedLine2.Contains(line2.MinX + pos2.X, line2.MaxX + pos2.X, line2XAtLine1Y, strict, false));
                }
            }
            else if (line1.Vertical)
            {
                // vertical line with regular line
                var line2YIntInner = line2.Start.Y + pos2.Y - line2.Slope * (line2.Start.X + pos2.X);
                var line2YAtLine1X = line2.Slope * (line1.Start.X + pos1.X) + line2YIntInner;
                return(AxisAlignedLine2.Contains(line1.MinY + pos1.Y, line1.MaxY + pos1.Y, line2YAtLine1X, strict, false) &&
                       AxisAlignedLine2.Contains(line2.MinY + pos2.Y, line2.MaxY + pos2.Y, line2YAtLine1X, strict, false));
            }

            // two non-vertical, non-horizontal lines
            var line1YInt = line1.Start.Y + pos1.Y - line1.Slope * (line1.Start.X + pos1.X);
            var line2YInt = line2.Start.Y + pos2.Y - line2.Slope * (line2.Start.X + pos2.X);

            if (Math.Abs(line1.Slope - line2.Slope) <= Math2.DEFAULT_EPSILON)
            {
                // parallel lines
                if (line1YInt != line2YInt)
                {
                    return(false); // infinite lines don't intersect
                }
                // parallel lines with equal y intercept. Intersect if ever at same X coordinate.
                return(AxisAlignedLine2.Intersects(line1.MinX + pos1.X, line1.MaxX + pos1.X, line2.MinX + pos2.X, line2.MaxX + pos2.X, strict, false));
            }
            else
            {
                // two non-parallel lines. Only one possible intersection point

                // y1 = y2
                // line1.Slope * x + line1.YIntercept = line2.Slope * x + line2.YIntercept
                // line1.Slope * x - line2.Slope * x = line2.YIntercept - line1.YIntercept
                // x (line1.Slope - line2.Slope) = line2.YIntercept - line1.YIntercept
                // x = (line2.YIntercept - line1.YIntercept) / (line1.Slope - line2.Slope)
                var x = (line2YInt - line1YInt) / (line1.Slope - line2.Slope);

                return(AxisAlignedLine2.Contains(line1.MinX + pos1.X, line1.MaxX + pos1.X, x, strict, false) &&
                       AxisAlignedLine2.Contains(line2.MinX + pos1.X, line2.MaxX + pos2.X, x, strict, false));
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Finds the line of overlap between the the two lines if there is
        /// one. If the two lines are not coincident (i.e., if the infinite
        /// lines are not the same) then they don't share a line of points.
        /// If they are coincident, they may still share no points (two
        /// seperate but coincident line segments), one point (they share
        /// an edge), or infinitely many points (the share a coincident
        /// line segment). In all but the last case, this returns false
        /// and overlap is set to null. In the last case this returns true
        /// and overlap is set to the line of overlap.
        /// </summary>
        /// <param name="a">The first line</param>
        /// <param name="b">The second line</param>
        /// <param name="pos1">The position of the first line</param>
        /// <param name="pos2">the position of the second line</param>
        /// <param name="overlap">Set to null or the line of overlap</param>
        /// <returns>True if a and b overlap at infinitely many points,
        /// false otherwise</returns>
        public static unsafe bool LineOverlap(Line2 a, Line2 b, Vector2 pos1, Vector2 pos2, out Line2 overlap)
        {
            if (!Parallel(a, b))
            {
                overlap = null;
                return(false);
            }
            if (!AlongInfiniteLine(a, pos1, b.Start + pos2))
            {
                overlap = null;
                return(false);
            }

            Vector2 relOrigin = a.Start + pos1;

            float *projs = stackalloc float[4] {
                0,
                a.Magnitude,
                Math2.Dot((b.Start + pos2) - relOrigin, a.Axis),
                Math2.Dot((b.End + pos2) - relOrigin, a.Axis)
            };

            bool *isFromLine1 = stackalloc bool[4] {
                true,
                true,
                false,
                false
            };

            FindSortedOverlap(projs, isFromLine1);

            if (isFromLine1[0] == isFromLine1[1])
            {
                // at best we overlap at one point, most likely no overlap
                overlap = null;
                return(false);
            }

            if (Math2.Approximately(projs[1], projs[2]))
            {
                // Overlap at one point
                overlap = null;
                return(false);
            }

            overlap = new Line2(
                relOrigin + projs[1] * a.Axis,
                relOrigin + projs[2] * a.Axis
                );
            return(true);
        }
Esempio n. 3
0
        /// <summary>
        /// Determines if the given point is along the infinite line described
        /// by the given line shifted the given amount.
        /// </summary>
        /// <param name="line">The line</param>
        /// <param name="pos">The shift for the line</param>
        /// <param name="pt">The point</param>
        /// <returns>True if pt is on the infinite line extension of the segment</returns>
        public static bool AlongInfiniteLine(Line2 line, Vector2 pos, Vector2 pt)
        {
            float normalPart = Vector2.Dot(pt - pos - line.Start, line.Normal);

            return(Math2.Approximately(normalPart, 0));
        }
Esempio n. 4
0
        /// <summary>
        /// Initializes a polygon with the specified vertices
        /// </summary>
        /// <param name="vertices">Vertices</param>
        /// <exception cref="ArgumentNullException">If vertices is null</exception>
        public Polygon2(Vector2[] vertices)
        {
            if (vertices == null)
            {
                throw new ArgumentNullException(nameof(vertices));
            }

            Vertices = vertices;

            Normals = new List <Vector2>();
            Vector2 tmp;

            for (int i = 1; i < vertices.Length; i++)
            {
                tmp = Math2.MakeStandardNormal(Vector2.Normalize(Math2.Perpendicular(vertices[i] - vertices[i - 1])));
                if (!Normals.Contains(tmp))
                {
                    Normals.Add(tmp);
                }
            }

            tmp = Math2.MakeStandardNormal(Vector2.Normalize(Math2.Perpendicular(vertices[0] - vertices[vertices.Length - 1])));
            if (!Normals.Contains(tmp))
            {
                Normals.Add(tmp);
            }

            var min = new Vector2(vertices[0].X, vertices[0].Y);
            var max = new Vector2(min.X, min.Y);

            for (int i = 1; i < vertices.Length; i++)
            {
                min.X = Math.Min(min.X, vertices[i].X);
                min.Y = Math.Min(min.Y, vertices[i].Y);
                max.X = Math.Max(max.X, vertices[i].X);
                max.Y = Math.Max(max.Y, vertices[i].Y);
            }
            AABB = new Rect2(min, max);

            _LongestAxisLength = -1;

            // Center, area, and lines
            TrianglePartition = new Triangle2[Vertices.Length - 2];
            float[] triangleSortKeys = new float[TrianglePartition.Length];
            float   area             = 0;

            Lines    = new Line2[Vertices.Length];
            Lines[0] = new Line2(Vertices[Vertices.Length - 1], Vertices[0]);
            var last = Vertices[0];

            Center = new Vector2(0, 0);
            for (int i = 1; i < Vertices.Length - 1; i++)
            {
                var next  = Vertices[i];
                var next2 = Vertices[i + 1];
                Lines[i] = new Line2(last, next);
                var tri = new Triangle2(new Vector2[] { Vertices[0], next, next2 });
                TrianglePartition[i - 1] = tri;
                triangleSortKeys[i - 1]  = -tri.Area;
                area   += tri.Area;
                Center += tri.Center * tri.Area;
                last    = next;
            }
            Lines[Vertices.Length - 1] = new Line2(Vertices[Vertices.Length - 2], Vertices[Vertices.Length - 1]);

            Array.Sort(triangleSortKeys, TrianglePartition);

            Area    = area;
            Center /= area;

            last = Vertices[Vertices.Length - 1];
            var centToLast            = (last - Center);
            var angLast               = Rotation2.Standardize((float)Math.Atan2(centToLast.Y, centToLast.X));
            var cwCounter             = 0;
            var ccwCounter            = 0;
            var foundDefinitiveResult = false;

            for (int i = 0; i < Vertices.Length; i++)
            {
                var curr       = Vertices[i];
                var centToCurr = (curr - Center);
                var angCurr    = Rotation2.Standardize((float)Math.Atan2(centToCurr.Y, centToCurr.X));


                var clockwise = (angCurr < angLast && (angCurr - angLast) < Math.PI) || (angCurr - angLast) > Math.PI;
                if (clockwise)
                {
                    cwCounter++;
                }
                else
                {
                    ccwCounter++;
                }

                Clockwise = clockwise;
                if (Math.Abs(angLast - angCurr) > Math2.DEFAULT_EPSILON)
                {
                    foundDefinitiveResult = true;
                    break;
                }

                last       = curr;
                centToLast = centToCurr;
                angLast    = angCurr;
            }
            if (!foundDefinitiveResult)
            {
                Clockwise = cwCounter > ccwCounter;
            }
        }