Esempio n. 1
0
 /// <summary>
 /// Uses the intersection count to detect if there is an intersection
 /// </summary>
 /// <param name="other"></param>
 /// <returns></returns>
 public bool Intersects(Segment other)
 {
     return (IntersectionCount(other) > 0);
 }
Esempio n. 2
0
 /// <summary>
 /// Determines the shortest distance between two segments
 /// </summary>
 /// <param name="lineSegment">Segment, The line segment to test against this segment</param>
 /// <returns>Double, the shortest distance between two segments</returns>
 public double DistanceTo(Segment lineSegment)
 {
     //http://www.geometryalgorithms.com/Archive/algorithm_0106/algorithm_0106.htm
     const double smallNum = 0.00000001;
     Vector u = ToVector(); // Segment 1
     Vector v = lineSegment.ToVector(); // Segment 2
     Vector w = ToVector();
     double a = u.Dot(u);  // length of segment 1
     double b = u.Dot(v);  // length of segment 2 projected onto line 1
     double c = v.Dot(v);  // length of segment 2
     double d = u.Dot(w);  //
     double e = v.Dot(w);
     double dist = a * c - b * b;
     double sc, sN, sD = dist;
     double tc, tN, tD = dist;
     // compute the line parameters of the two closest points
     if (dist < smallNum)
     {
         // the lines are almost parallel force using point P0 on segment 1
         // to prevent possible division by 0 later
         sN = 0.0;
         sD = 1.0;
         tN = e;
         tD = c;
     }
     else
     {
         // get the closest points on the infinite lines
         sN = (b * e - c * d);
         tN = (a * e - b * d);
         if (sN < 0.0)
         {
             // sc < 0 => the s=0 edge is visible
             sN = 0.0;
             tN = e;
             tD = c;
         }
         else if (sN > sD)
         {
             // sc > 1 => the s=1 edge is visible
             sN = sD;
             tN = e + b;
             tD = c;
         }
     }
     if (tN < 0.0)
     {
         // tc < 0 => the t=0 edge is visible
         tN = 0.0;
         // recompute sc for this edge
         if (-d < 0.0)
         {
             sN = 0.0;
         }
         else if (-d > a)
         {
             sN = sD;
         }
         else
         {
             sN = -d;
             sD = a;
         }
     }
     else if (tN > tD)
     {
         // tc > 1 => the t = 1 edge is visible
         // recompute sc for this edge
         if ((-d + b) < 0.0)
         {
             sN = 0;
         }
         else if ((-d + b) > a)
         {
             sN = sD;
         }
         else
         {
             sN = (-d + b);
             sD = a;
         }
     }
     // finally do the division to get sc and tc
     if (Math.Abs(sN) < smallNum)
     {
         sc = 0.0;
     }
     else
     {
         sc = sN / sD;
     }
     if (Math.Abs(tN) < smallNum)
     {
         tc = 0.0;
     }
     else
     {
         tc = tN / tD;
     }
     // get the difference of the two closest points
     Vector dU = u.Multiply(sc);
     Vector dV = v.Multiply(tc);
     Vector dP = (w.Add(dU)).Subtract(dV);
     // S1(sc) - S2(tc)
     return dP.Length2D;
 }
Esempio n. 3
0
        /// <summary>
        /// Returns 0 if no intersections occur, 1 if an intersection point is found,
        /// and 2 if the segments are colinear and overlap.
        /// </summary>
        /// <param name="other"></param>
        /// <returns></returns>
        public int IntersectionCount(Segment other)
        {
            double x1 = P1.X;
            double y1 = P1.Y;
            double x2 = P2.X;
            double y2 = P2.Y;
            double x3 = other.P1.X;
            double y3 = other.P1.Y;
            double x4 = other.P2.X;
            double y4 = other.P2.Y;
            double denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);

            //The case of two degenerate segements
            if ((x1 == x2) && (y1 == y2) && (x3 == x4) && (y3 == y4))
            {
                if ((x1 != x3) || (y1 != y3))
                    return 0;
            }

            // if denom is 0, then the two lines are parallel
            double na = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3);
            double nb = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3);
            // if denom is 0 AND na and nb are 0, then the lines are coincident and DO intersect
            if (Math.Abs(denom) < Epsilon && Math.Abs(na) < Epsilon && Math.Abs(nb) < Epsilon) return 2;
            // If denom is 0, but na or nb are not 0, then the lines are parallel and not coincident
            if (denom == 0) return 0;
            double ua = na / denom;
            double ub = nb / denom;
            if (ua < 0 || ua > 1) return 0; // not intersecting with segment a
            if (ub < 0 || ub > 1) return 0; // not intersecting with segment b
            // If we get here, then one intersection exists and it is found on both line segments
            return 1;
        }
Esempio n. 4
0
        /// <summary>
        /// For each coordinate in the other part, if it falls in the extent of this polygon, a
        /// ray crossing test is used for point in polygon testing.  If it is not in the extent,
        /// it is skipped.
        /// </summary>
        /// <param name="polygonShape">The part of the polygon to analyze polygon</param>
        /// <param name="otherPart">The other part</param>
        /// <returns>Boolean, true if any coordinate falls inside the polygon</returns>
        private static bool ContainsVertex(ShapeRange polygonShape, PartRange otherPart)
        {
            // Create an extent for faster checking in most cases
            Extent ext = polygonShape.Extent;

            foreach (Vertex point in otherPart)
            {
                // This extent check shortcut should help speed things up for large polygon parts
                if (!ext.Intersects(point)) continue;

                // Imagine a ray on the horizontal starting from point.X -> infinity.  (In practice this can be ext.XMax)
                // Count the intersections of segments with that line.  If the resulting count is odd, the point is inside.
                Segment ray = new Segment(point.X, point.Y, ext.MaxX, point.Y);
                int[] numCrosses = new int[polygonShape.NumParts]; // A cross is a complete cross.  Coincident doesn't count because it is either 0 or 2 crosses.
                int totalCrosses = 0;
                int iPart = 0;
                foreach (PartRange ring in polygonShape.Parts)
                {
                    foreach (Segment segment in ring.Segments)
                    {
                        if (segment.IntersectionCount(ray) != 1) continue;
                        numCrosses[iPart]++;
                        totalCrosses++;
                    }
                    iPart++;
                }

                // If we didn't actually have any polygons we cant intersect with anything
                if (polygonShape.NumParts < 1) return false;

                // For shapes with only one part, we don't need to test part-containment.
                if (polygonShape.NumParts == 1 && totalCrosses % 2 == 1) return true;

                // This used to check to see if totalCrosses == 1, but now checks to see if totalCrosses is an odd number.
                // This change was made to solve the issue described in HD Issue 8593 (http://hydrodesktop.codeplex.com/workitem/8593).
                if (totalCrosses % 2 == 1) return true;

                totalCrosses = 0;
                for (iPart = 0; iPart < numCrosses.Length; iPart++)
                {
                    int count = numCrosses[iPart];
                    // If this part does not contain the point, don't bother trying to figure out if the part is a hole or not.
                    if (count % 2 == 0) continue;

                    // If this particular part is a hole, subtract the total crosses by 1,  otherwise add one.
                    // This takes time, so we want to do this as few times as possible.
                    if (polygonShape.Parts[iPart].IsHole())
                    {
                        totalCrosses--;
                    }
                    else
                    {
                        totalCrosses++;
                    }
                }
                return totalCrosses > 0;
            }
            return false;
        }