Пример #1
0
        } //end doClip

        //TODO: test this
        private void IntegrateIntersections(ref List <DeepPoint> list)
        {
            for (int i = 0; i < list.Count; i++)
            {
                DeepPoint normal = list[i];
                for (int j = 0; j < normal.intersections.Count; j++)
                {
                    DeepPoint intersection = normal.intersections[j];

                    list.Insert(i + 1, intersection);
                    i++;
                }
            }
        }
Пример #2
0
        //TODO: test
        private void BuildIntersectionMap(ref Dictionary <PointF, int> fromMap, List <DeepPoint> from, ref Dictionary <PointF, int> toMap, List <DeepPoint> to)
        {
            for (int i = 0; i < from.Count; i++)
            {
                DeepPoint point = from[i];

                if (point.type == DeepPoint.PointType.Intersection)
                {
                    //we can do both at once since we should have the same number of intersections

                    for (int j = 0; j < to.Count; j++)
                    {
                        if (to[j].p == point.p)
                        {
                            fromMap.Add(point.p, j);
                        }
                    }
                    toMap.Add(point.p, i);
                }
            }
        }
Пример #3
0
        private void doClip(PointF[] clip, PointF[] shape)
        {
            List <DeepPoint> deepShape = new List <DeepPoint>(Array.ConvertAll(shape, p => new DeepPoint(p, DeepPoint.PointType.Normal, p.InOrOut(clip))));
            List <DeepPoint> deepClip  = new List <DeepPoint>(Array.ConvertAll(clip, p => new DeepPoint(p, DeepPoint.PointType.Normal, p.InOrOut(shape))));

            for (int i = 0; i < deepShape.Count; i++)
            {
                DeepPoint p1 = deepShape[i];
                DeepPoint p2 = deepShape.NextAfter(i);

                //check for intersections
                for (int j = 0; j < deepClip.Count; j++)
                {
                    DeepPoint c1 = deepClip[j];
                    DeepPoint c2 = deepClip.NextAfter(j);

                    List <PointF> interOutput;
                    if (Line.Intersection(p1, p2, c1, c2, out interOutput))
                    {
                        foreach (PointF inter in interOutput)
                        {
                            //This ensures that we have the same intersection added to both (avoid precision errors)
                            DeepPoint intersection = new DeepPoint(inter, DeepPoint.PointType.Intersection, DeepPoint.PointStatus.Undetermined);

                            if (inter == p1.p || inter == p2.p || inter == c1.p || inter == c2.p)
                            {
                                if (inter == p1.p && inter == c1.p)
                                {
                                    p1.overlap = true;
                                    c1.overlap = true;
                                    p1.type    = DeepPoint.PointType.Intersection;
                                    c1.type    = DeepPoint.PointType.Intersection;
                                    continue;
                                }
                                else if (inter != p2.p && inter != c1.p && inter != c2.p)
                                {
                                    if (inter == p1.p)
                                    {
                                        p1.overlap = true;
                                        p1.type    = DeepPoint.PointType.Intersection;
                                    }
                                    else
                                    {
                                        p1.intersections.Add(intersection);
                                    }

                                    c1.intersections.Add(intersection);
                                }
                            }
                            else
                            {
                                //TODO: if intersection is same as p1,p2,c1,c2 -> make a note of it?
                                p1.intersections.Add(intersection);
                                c1.intersections.Add(intersection);
                            }
                        }
                    }
                }

                //sort intersections by distance to p1
                p1.SortIntersections();


                //loop through intersections between p1 and p2
                for (int j = 0; j < p1.intersections.Count; j++)
                {
                    DeepPoint intersection = p1.intersections[j];

                    //if there's a previous intersection
                    if (j > 0)
                    {
                        DeepPoint prev = p1.intersections[j - 1];
                        if (prev.status == DeepPoint.PointStatus.In)
                        {
                            intersection.status = DeepPoint.PointStatus.Out;                                          //set inter pStatus to Out
                        }
                        else
                        {
                            intersection.status = DeepPoint.PointStatus.In;  //set inter as In
                        }
                    }
                    else if (p1.status == DeepPoint.PointStatus.In)
                    {
                        intersection.status = DeepPoint.PointStatus.Out;                                             //set inter as Out
                    }
                    else
                    {
                        intersection.status = DeepPoint.PointStatus.In;  //set inter as In
                    }
                }
            }

            //sort all intersections in clip
            for (int i = 0; i < deepClip.Count; i++)
            {
                deepClip[i].SortIntersections();
            }

            IntegrateIntersections(ref deepShape);
            IntegrateIntersections(ref deepClip);

            //Use these to jump from list to list
            Dictionary <PointF, int> shapeIntersectionToClipIndex = new Dictionary <PointF, int>();
            Dictionary <PointF, int> clipIntersectionToShapeIndex = new Dictionary <PointF, int>();

            BuildIntersectionMap(ref shapeIntersectionToClipIndex, deepShape, ref clipIntersectionToShapeIndex, deepClip);

            //start from entering points
            List <int> iEntering = new List <int>();

            //Get entering intersections
            for (int i = 0; i < deepShape.Count; i++)
            {
                DeepPoint point = deepShape[i];
                if (point.overlap || (point.type == DeepPoint.PointType.Intersection && point.status == DeepPoint.PointStatus.In))
                {
                    iEntering.Add(i);
                }
            }

            List <List <DeepPoint> > output       = new List <List <DeepPoint> >();
            List <DeepPoint>         currentShape = new List <DeepPoint>();

            bool allEnteringAreOverlap = true;

            foreach (int i in iEntering)
            {
                if (!deepShape[i].overlap)
                {
                    allEnteringAreOverlap = false;
                    break;
                }
            }

            bool hasNonOverlapIntersections = false;

            foreach (DeepPoint p in deepShape)
            {
                if (!p.overlap && p.type == DeepPoint.PointType.Intersection)
                {
                    hasNonOverlapIntersections = true;
                    break;
                }
            }

            //handle special cases
            if ((iEntering.Count == 0 || allEnteringAreOverlap) && !hasNonOverlapIntersections)
            {
                bool allInside = true;
                foreach (DeepPoint p in deepShape)
                {
                    if (p.status != DeepPoint.PointStatus.In && !p.overlap)
                    {
                        allInside = false;
                        break;
                    }
                }

                if (allInside)
                {
                    foreach (DeepPoint p in deepShape)
                    {
                        currentShape.Add(p);
                    }
                }
                else
                {
                    //check that deepClip are all inside
                    allInside = true;
                    foreach (DeepPoint p in deepClip)
                    {
                        if (p.status != DeepPoint.PointStatus.In && !p.overlap)
                        {
                            allInside = false;
                            break;
                        }
                    }

                    if (allInside)
                    {
                        foreach (DeepPoint p in deepClip)
                        {
                            currentShape.Add(p);
                        }
                    }
                    else
                    {
                        return;
                    }
                }

                output.Add(currentShape);
                pen.Width = 5;
                DrawLines(Array.ConvertAll(output[0].ToArray(), p => p.p), Color.Green);
                pen.Width = 2;
                return;
            }

            //TODO: add method to ignore entering points that were included in an output shape already

            //go through all of our entering points
            for (int mainCount = 0; mainCount < iEntering.Count; mainCount++)
            {
                int goToIndex = iEntering[mainCount];

                bool complete = false;

                while (!complete)
                {
                    //loop through all shape points starting at goToIndex
                    for (int iCount = goToIndex; iCount < deepShape.Count + goToIndex; iCount++)
                    {
                        int       i  = iCount % deepShape.Count;
                        DeepPoint p1 = deepShape[i];
                        DeepPoint p2 = deepShape.NextAfter(i);

                        if (p1.overlap)
                        {
                            DeepPoint prev = deepShape.PrevBefore(i);
                            if (prev.overlap || prev.status == DeepPoint.PointStatus.Out)
                            {
                                p1.tempStatus = DeepPoint.PointStatus.In;
                            }
                            else
                            {
                                p1.tempStatus = DeepPoint.PointStatus.Out;
                            }
                        }
                        else
                        {
                            p1.tempStatus = p1.status;
                        }

                        if (p2.overlap)
                        {
                            if (p1.overlap || p1.status == DeepPoint.PointStatus.Out)
                            {
                                p2.tempStatus = DeepPoint.PointStatus.In;
                            }
                            else
                            {
                                p2.tempStatus = DeepPoint.PointStatus.Out;
                            }
                        }
                        else
                        {
                            p2.tempStatus = p2.status;
                        }

                        if (p1.type == DeepPoint.PointType.Normal)
                        {
                            if (p1.tempStatus == DeepPoint.PointStatus.In)
                            {
                                //break when we get back to start
                                if (currentShape.Count > 0 && currentShape[0].p == p1.p)
                                {
                                    complete = true;
                                    break;
                                }

                                currentShape.Add(p1);

                                //point2 must be heading outwards
                                if (p2.type == DeepPoint.PointType.Intersection)
                                {
                                    //go to clipPoints loop and start from intersection
                                    //goToIndex = shapeIntersectionToClipIndex[p2.p] + 1;
                                    //break;
                                }
                            }
                            //we don't care about point2 here
                            //if point1 is an outside normal point,
                            //	then point2 must either be an outside normal point OR an intersection going inwards.
                            //		The former doesn't not need to be handled, the latter will be handled upon looping
                        }
                        else //p1 is an intersection
                        {
                            //break when we get back to start
                            if (currentShape.Count > 0 && currentShape[0].p == p1.p)
                            {
                                complete = true;
                                break;
                            }

                            //we must add point 1 since it's on the border
                            currentShape.Add(p1);

                            //exiting
                            if (p1.tempStatus == DeepPoint.PointStatus.Out)
                            {
                                //go to clipPoints loop and start from after intersection;
                                goToIndex = (shapeIntersectionToClipIndex[p1.p] + 1) % deepClip.Count;
                                break;
                            }
                        }
                    } //end deepShape for

                    //break while loop if complete
                    if (complete)
                    {
                        break;
                    }

                    //loop through all clip points starting at goToIndex
                    //we should only get here from a go to from shapePoints
                    for (int iCount = goToIndex; iCount < deepClip.Count + goToIndex; iCount++)
                    {
                        int       i  = iCount % deepClip.Count;
                        DeepPoint p1 = deepClip[i];
                        DeepPoint p2 = deepClip.NextAfter(i);

                        if (p1.overlap)
                        {
                            DeepPoint prev = deepClip.PrevBefore(i);
                            if (prev.overlap || prev.status == DeepPoint.PointStatus.Out)
                            {
                                p1.tempStatus = DeepPoint.PointStatus.In;
                            }
                            else
                            {
                                p1.tempStatus = DeepPoint.PointStatus.Out;
                            }
                        }
                        else
                        {
                            p1.tempStatus = p1.status;
                        }

                        if (p2.overlap)
                        {
                            if (p1.overlap || p1.status == DeepPoint.PointStatus.Out)
                            {
                                p2.tempStatus = DeepPoint.PointStatus.In;
                            }
                            else
                            {
                                p2.tempStatus = DeepPoint.PointStatus.Out;
                            }
                        }
                        else
                        {
                            p2.tempStatus = p2.status;
                        }

                        if (p1.type == DeepPoint.PointType.Intersection)
                        {
                            //break when we get back to start
                            if (currentShape.Count > 0 && currentShape[0].p == p1.p)
                            {
                                complete = true;
                                break;
                            }

                            //we must add point 1 since it's on the border
                            currentShape.Add(p1);

                            //if it was going inwards
                            if (p1.tempStatus == DeepPoint.PointStatus.In)
                            {
                                //go to shapePoints loop and start from after point1
                                goToIndex = (clipIntersectionToShapeIndex[p1.p] + 1) % deepShape.Count;
                                break;
                            }
                        }
                        else //p1 is normal
                        {
                            if (p1.tempStatus == DeepPoint.PointStatus.In)
                            {
                                //break when we get back to start
                                if (currentShape.Count > 0 && currentShape[0].p == p1.p)
                                {
                                    complete = true;
                                    break;
                                }

                                //we must add point 1 since it's on the border
                                currentShape.Add(p1);
                            }
                        }
                    } //end deepClip for
                }     //end while loop

                output.Add(currentShape);
                currentShape = new List <DeepPoint>();
            }//end main for loop

            //remove duplicate points
            for (int iOutput = 0; iOutput < output.Count; iOutput++)
            {
                List <DeepPoint> points = output[iOutput];
                for (int i = 0; i < points.Count; i++)
                {
                    //remove duplicates
                    if (points[i].p == points.NextAfter(i).p)
                    {
                        //remove current
                        points.RemoveAt(i);
                        i--;
                    }
                }

                if (points.Count < 3)
                {
                    output.Remove(points);
                    iOutput--;
                }
            }

            pen.Width = 5;
            DrawLines(Array.ConvertAll(output[0].ToArray(), p => p.p), Color.Green);
            pen.Width = 2;
        } //end doClip
Пример #4
0
        public static bool Intersection(DeepPoint start1, DeepPoint end1, DeepPoint start2, DeepPoint end2, out List <PointF> output)
        {
            output = new List <PointF>();
            float det;
            float A1, B1, C1;
            float A2, B2, C2;

            //https://www.topcoder.com/community/data-science/data-science-tutorials/geometry-concepts-line-intersection-and-its-applications/#line_line_intersection
            A1 = end1.p.Y - start1.p.Y;
            B1 = start1.p.X - end1.p.X;
            C1 = A1 * start1.p.X + B1 * start1.p.Y;

            A2 = end2.p.Y - start2.p.Y;
            B2 = start2.p.X - end2.p.X;
            C2 = A2 * start2.p.X + B2 * start2.p.Y;

            det = A1 * B2 - A2 * B1;

            if (det == 0)
            {
                float mTop = end1.p.Y - start1.p.Y;
                float mBot = end1.p.X - start1.p.X;

                float b1 = end1.p.Y - (mTop * end1.p.X) / mBot;
                float b2 = end2.p.Y - (mTop * end2.p.X) / mBot;

                if (b1 != b2)
                {
                    return(false);
                }

                bool overlap = false;

                //there will possibly be two points
                float cxMin = Math.Min(start2.p.X, end2.p.X);
                float cxMax = Math.Max(start2.p.X, end2.p.X);

                float cyMin = Math.Min(start2.p.Y, end2.p.Y);
                float cyMax = Math.Max(start2.p.Y, end2.p.Y);

                if (cxMin <= start1.p.X && start1.p.X <= cxMax &&
                    cyMin <= start1.p.Y && start1.p.Y <= cyMax)
                {
                    //use start1
                    output.Add(start1.p);
                    overlap = true;
                }
                else
                {
                    //use start2
                    output.Add(start2.p);
                }

                if (cxMin <= end1.p.X && end1.p.X <= cxMax &&
                    cyMin <= end1.p.Y && end1.p.Y <= cyMax)
                {
                    //use end1
                    output.Add(end1.p);
                    overlap = true;
                }
                else
                {
                    //use end2
                    output.Add(end2.p);
                }

                //lines are parallel and possibly overlap
                Console.WriteLine("Parallel Lines");
                return(overlap);
            }

            PointF intersect = new PointF(B2 * C1 - B1 * C2, A1 * C2 - A2 * C1); //would normally be /det

            intersect.X /= det;
            intersect.Y /= det;
            //using multiplication instead since it's less likely to have precision errors
            float xMin = Math.Min(start2.p.X, end2.p.X);
            float xMax = Math.Max(start2.p.X, end2.p.X);

            float yMin = Math.Min(start2.p.Y, end2.p.Y);
            float yMax = Math.Max(start2.p.Y, end2.p.Y);

            float xMin2 = Math.Min(start1.p.X, end1.p.X);
            float xMax2 = Math.Max(start1.p.X, end1.p.X);

            float yMin2 = Math.Min(start1.p.Y, end1.p.Y);
            float yMax2 = Math.Max(start1.p.Y, end1.p.Y);

            if (xMin <= intersect.X && intersect.X <= xMax &&
                yMin <= intersect.Y && intersect.Y <= yMax &&
                xMin2 <= intersect.X && intersect.X <= xMax2 &&
                yMin2 <= intersect.Y && intersect.Y <= yMax2)
            {
                output.Add(intersect);
                return(true);
            }
            else
            {
                return(false);
            }
        }
Пример #5
0
 //Distance Squared
 public static float DistanceSquared(DeepPoint p1, DeepPoint p2)
 {
     return((p2.p.X - p1.p.X) * (p2.p.X - p1.p.X) + (p2.p.Y - p1.p.Y) * (p2.p.Y - p1.p.Y));
 }
Пример #6
0
        public static DeepPoint.PointStatus InOrOut(this PointF point, PointF[] shape)
        {
            //a point that we can guarantee is outside of our shape
            PointF outside = new PointF(float.MaxValue, float.MaxValue);

            //find the leftmost and topmost bounds
            for (int i = 0; i < shape.Length; i++)
            {
                PointF p = shape[i];

                if (p.X < outside.X)
                {
                    outside.X = p.X;
                }
                if (p.Y < outside.Y)
                {
                    outside.Y = p.Y;
                }
            }

            outside.X -= 7;
            outside.Y -= 13;

            HashSet <PointF> intersections = new HashSet <PointF>();

            int intersectionCount = 0;

            for (int i = 0; i < shape.Length; i++)
            {
                PointF c1 = shape[i];
                PointF c2 = shape[(i + 1) % shape.Length];

                //if our point is the same as one of the shape points, we consider it inside the shape
                //if(point == c1 || point == c2) return DeepPoint.PointStatus.In;

                Console.WriteLine("{0} == {1}", DeepPoint.Distance(point, c1) + DeepPoint.Distance(point, c2), DeepPoint.Distance(c1, c2));
                if (DeepPoint.Distance(point, c1) + DeepPoint.Distance(point, c2) == DeepPoint.Distance(c1, c2))
                {
                    return(DeepPoint.PointStatus.In);                                                                                             //TODO: mark it as border
                }
                float det;
                float A1, B1, C1;
                float A2, B2, C2;

                //https://www.topcoder.com/community/data-science/data-science-tutorials/geometry-concepts-line-intersection-and-its-applications/#line_line_intersection
                A1 = c2.Y - c1.Y;
                B1 = c1.X - c2.X;
                C1 = A1 * c1.X + B1 * c1.Y;

                A2 = outside.Y - point.Y;
                B2 = point.X - outside.X;
                C2 = A2 * point.X + B2 * point.Y;

                det = A1 * B2 - A2 * B1;
                if (det == 0)
                {
                    throw new Exception("PARALLEL");
                }

                PointF intersect = new PointF(B2 * C1 - B1 * C2, A1 * C2 - A2 * C1); //would normally be /det
                intersect.X /= det;
                intersect.Y /= det;

                //using multiplication instead since it's less likely to have precision errors
                float xMin = Math.Min(c1.X, c2.X);
                float xMax = Math.Max(c1.X, c2.X);

                float yMin = Math.Min(c1.Y, c2.Y);
                float yMax = Math.Max(c1.Y, c2.Y);

                float xMin2 = Math.Min(point.X, outside.X);
                float xMax2 = Math.Max(point.X, outside.X);

                float yMin2 = Math.Min(point.Y, outside.Y);
                float yMax2 = Math.Max(point.Y, outside.Y);

                if (xMin <= intersect.X && intersect.X <= xMax &&
                    yMin <= intersect.Y && intersect.Y <= yMax &&
                    xMin2 <= intersect.X && intersect.X <= xMax2 &&
                    yMin2 <= intersect.Y && intersect.Y <= yMax2 &&
                    !intersections.Contains(intersect))
                {
                    intersectionCount++;
                    intersections.Add(intersect);
                }
            }

            //covers 0 + evens
            if (intersectionCount % 2 == 0)
            {
                return(DeepPoint.PointStatus.Out);
            }
            else
            {
                return(DeepPoint.PointStatus.In); //odds > 0
            }
        }