Exemplo n.º 1
0
        // Check if this polygon contains a point
        public override bool Contains(Vector2 point)
        {
            // Suppose we have a polygon with n vertices.  Let p be a point, and
            // consider the ray emanating from p and extending toward the left.
            // Lastly, let n be the number of times this ray intersects the polygon's
            // perimeter.  Then the following properties hold.
            //
            //  1.)  If n is even, then p lies outside the polygon.
            //  2.)  If n is odd, then p is inside the polygon.
            //
            // Note:  This expresion assumes that the (x_0, y_0) and (x_n, y_n) are
            // identical, i.e. the polygon is closed.

            // Entry logging
      #if IS_LOGGING_METHODS
            Log.Write(String.Format("Entering method for {0}", this.Name));
      #endif

            // Declare result
            bool result;

            #region [1]  Broad phase:  Bounding box test

            // First, check if point is outside MinBoundingBox
            if (!this.MinBoundingBox.Contains(point))
            {
                result = false;  goto exit;
            }

            #endregion

            #region [2]  Narrow phase:  Ray casting test

            // Note:  We have to be very careful here.  Suppose our ray intersects
            // with a vertex of our polygon.  In this case, the ray will technically
            // intersect with two different edges!  This is really just one point of
            // intersection, and so we have to be careful that it is not counted
            // twice!

            // Initialize intersection counter
            int count = 0;

            // Create a horizontal ray stemming from the point and extending to the left
            LineSegment ray = new LineSegment(point, new Vector2(this.MinBoundingBox.X - 1, point.Y));
            // if (Globals.TestBool) { Trace.WriteLine("ray = " + ray); }

            // Get edges
            List <LineSegment> edges = this.Edges;

            // Loop through each edge
            for (int i = 0; i < this.Vertices.Count; i++)
            {
                // Point to current edge
                LineSegment edge = edges[i];
                // if (Globals.TestBool) { Trace.WriteLine("edge[" + i + "] = " + edge + ", count = " + count); }

                // Check if ray intersects with edge
                if (ray.IntersectsWith(edge))
                {
                    // If ray is coincident with ray, count once
                    if (edge.Point1.Y == ray.Point2.Y && edge.Point2.Y == ray.Point2.Y)
                    {
                        count++;
                    }
                    // If ray intersects with vertex, don't double count it
                    else if (edge.Point2.Y != ray.Point2.Y)
                    {
                        count++;
                    }
                }
            }

            // Check if count is even
            if (count % 2 == 0)
            {
                result = false; goto exit;
            }
            else
            {
                result = true; goto exit;
            }

            #endregion


            // [*]  Exit trap
exit:

            // Exit logging
            // if (Globals.TestBool) { Trace.WriteLine("final count = " + count); }
      #if IS_LOGGING_METHODS
            Log.Write(String.Format("Exiting method for {0}", this.Name));
      #endif


            // Return result
            return(result);
        }
Exemplo n.º 2
0
        // Get point of intersection between this line and another
        public Vector2 IntersectionWith(LineSegment line)
        {
            // Suppose A = (x1, y1), B = (x2, y2), C = (x3, y3), D = (x4, y4).  We
            // may define vector (ua, ub) as follows.
            //
            //   ua = na / d
            //   ub = nb / d
            //   na = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)
            //   nb = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)
            //    d = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1)
            //
            // The following results hold true.
            //
            //   1.)  If d = 0, then the line segments are parallel
            //   2.)  If d, na, and nb all equal zero, then the line segments are
            //        coincident (overlap).
            //   3.)  If ua and ub lie between 0 and 1, then the intersection point
            //        lies within the line segment' end points.  In this case, the
            //        point of intersection (x, y) may be written as follows.
            //
            //          x = x1 + ua * (x2 - x1)
            //          y = y1 + ua * (y2 - y1)

            // Note:  If the line segments do not intersect, this function will
            // return positive infinity.  If they overlap, it will simply return
            // (x1, y1).

            // Entry logging
      #if IS_LOGGING_METHODS
            Log.Write("Entering method");
      #endif

            // Declare result
            Vector2 result;

            // Declare each coordinate
            float x1 = this.Point1.X;
            float x2 = this.Point2.X;
            float x3 = line.Point1.X;
            float x4 = line.Point2.X;
            float y1 = this.Point1.Y;
            float y2 = this.Point2.Y;
            float y3 = line.Point1.Y;
            float y4 = line.Point2.Y;

            // Calculate the denominator and each numerator
            float d  = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
            float na = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3);
            float nb = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3);

            // Check if lines are parallel
            if (d == 0)
            {
                // If so, check if they are coincident
                if (na == 0 && nb == 0)
                {
                    float minA = x1; float maxA = x2; if (x2 < x1)
                    {
                        minA = x2; maxA = x1;
                    }
                    float minB = x3; float maxB = x4; if (x4 < x3)
                    {
                        minB = x4; maxB = x3;
                    }
                    Interval intervalA = new Interval(minA, maxA);
                    Interval intervalB = new Interval(minB, maxB);
                    Interval overlap   = intervalA.IntersectionWith(intervalB);
                    if (!overlap.IsEmpty)
                    {
                        result = new Vector2(overlap.Min, y1);
                    }
                    else
                    {
                        result = Vector2.PositiveInfinity;
                    }
                }
                else
                {
                    result = Vector2.PositiveInfinity; goto exit;
                }
            }
            // Otherwise
            else
            {
                // Divide each numerator by the denominator
                float ua = na / d;
                float ub = nb / d;

                // Stop if ua is outside the interval (0, 1)
                if (ua < 0 || ua > 1)
                {
                    result = Vector2.PositiveInfinity; goto exit;
                }

                // Stop if ub is outside the interval (0, 1)
                if (ub < 0 || ub > 1)
                {
                    result = Vector2.PositiveInfinity; goto exit;
                }

                // If we haven't stopped yet, then the line segments intersect
                float x = x1 + ua * (x2 - x1);
                float y = y1 + ua * (y2 - y1);
                result = new Vector2(x, y); goto exit;
            }

            // Exit trap
exit:

            // Exit logging
      #if IS_LOGGING_METHODS
            Log.Write("Exiting method");
      #endif

            // Return result
            return(result);
        }
Exemplo n.º 3
0
        // Find the point on this polygon closest to a point
        public override Vector2 ClosestPointTo(Vector2 point)
        {
            // Let e be an arbitrary edge with direction d.  Furthermore, let [a, b] and p
            // be the projections of e and our point onto the d-axis, respectively.  Then
            // there are two possible cases.

            //   1.)  p is in [a, b]
            //        Then there is a perpendicular line connecting our point to e.  This
            //        edge might contain the closest point.
            //   2.)  p is not in [a, b]
            //        This edge definitely does not contain the closest point.  We may
            //        disregard it.
            //
            // We check this criterion for each edge, compute the closest point to each
            // edge, and that which yields the smallest distance.  However, if no edges
            // satisfy the above criterion, then the closest point must be a vertex.

            // Note:  If there are two equidistant, closest points, this method will only
            // return one of them!

            // Entry logging
      #if IS_LOGGING_METHODS
            Log.Write(String.Format("Entering method for {0}", this.Name));
      #endif

            // Declare result
            Vector2 result = Vector2.Zero;
            // Initialize minDistance as positive infinity
            float minDistance = float.PositiveInfinity;

            // First, we loop through the polygon's vertices
            for (int i = 0; i < this.Vertices.Count; i++)
            {
                // Get current vertex
                Vector2 vertex = this.Vertices[i];
                // Get distance between vertex and point
                float distance = Vector2.Distance(vertex, point);
                // Update minimum distance and result
                if (distance < minDistance)
                {
                    minDistance = distance;
                    result      = vertex;
                }
            }

            // Get edges
            List <LineSegment> edges = this.Edges;

            // Loop through edges
            for (int i = 0; i < this.Vertices.Count; i++)
            {
                // Get current edge
                LineSegment edge = edges[i];
                // Get edge's direction vector
                Vector2 axis = edge.Direction;
                // Project edge onto axis
                Interval edgeProjection = edge.ProjectOnto(axis);
                // Project point onto axis
                float pointProjection = Vector2.Project(point, axis);
                // Check if p is in [a, b]
                if (edgeProjection.Contains(pointProjection))
                {
                    // If so, check minimum distance between point and edge
                    Vector2 closestEdgePoint = edge.ClosestPointTo(point);
                    float   distance         = Vector2.Distance(closestEdgePoint, point);
                    // Update minimum distance and result
                    if (distance < minDistance)
                    {
                        minDistance = distance;
                        result      = closestEdgePoint;
                    }
                }
            }

            // Exit logging
      #if IS_LOGGING_METHODS
            Log.Write(String.Format("Exiting method for {0}", this.Name));
      #endif

            // Return result
            return(result);
        }