//
        // Is a point intersecting with a circle?
        //
        //Is a point d inside, outside or on the same circle where a, b, c are all on the circle's edge
        public static IntersectionCases PointCircle(MyVector2 a, MyVector2 b, MyVector2 c, MyVector2 testPoint)
        {
            //Center of circle
            MyVector2 circleCenter = _Geometry.CalculateCircleCenter(a, b, c);

            //The radius sqr of the circle
            float radiusSqr = MyVector2.SqrDistance(a, circleCenter);

            //The distance sqr from the point to the circle center
            float distPointCenterSqr = MyVector2.SqrDistance(testPoint, circleCenter);

            //Add/remove a small value becuse we will never be exactly on the edge because of floating point precision issues
            //Mutiply epsilon by two because we are using sqr root???
            if (distPointCenterSqr < radiusSqr - MathUtility.EPSILON * 2f)
            {
                return(IntersectionCases.IsInside);
            }
            else if (distPointCenterSqr > radiusSqr + MathUtility.EPSILON * 2f)
            {
                return(IntersectionCases.NoIntersection);
            }
            else
            {
                return(IntersectionCases.IsOnEdge);
            }
        }
Esempio n. 2
0
        //The hull may still intersect with the edge between the point on the hole and the "visible" point on the hull,
        //so the point on the hull might not be visible, so we should try to find a better point
        private static void FindActualVisibleVertexOnHull(EarClippingPolygon hull, EarClippingPolygon hole, MyVector2 intersectionVertex, ref MyVector2 visibleVertex)
        {
            //Form a triangle
            Triangle2 t = new Triangle2(hole.maxX_Vert, intersectionVertex, visibleVertex);

            //According to litterature, we check if a reflect vertex is within this triangle
            //If so, one of them is a better visible vertex on the hull
            List <MyVector2> reflectVertices = FindReflectVertices(hull, hole);

            //Pick the reflect vertex with the smallest angle
            //The angle is measure from the point on the hole towards:
            //- intersection point on the hull
            //- reflect vertex
            float minAngle = Mathf.Infinity;

            //If more than one reflect vertex have the same angle then pick the one closest to the point on the hole
            float minDistSqr = Mathf.Infinity;

            foreach (MyVector2 v in reflectVertices)
            {
                if (_Intersections.PointTriangle(t, v, includeBorder: true))
                {
                    float angle = MathUtility.AngleBetween(intersectionVertex - hole.maxX_Vert, v - hole.maxX_Vert);

                    //Debug.DrawLine(v.ToVector3(1f), hole.maxX_Vert.ToVector3(1f), Color.blue, 2f);

                    //Debug.DrawLine(intersectionVertex.ToVector3(1f), hole.maxX_Vert.ToVector3(1f), Color.black, 2f);

                    //TestAlgorithmsHelpMethods.DebugDrawCircle(v.ToVector3(1f), 0.3f, Color.blue);

                    //Debug.Log(angle * Mathf.Rad2Deg);

                    if (angle < minAngle)
                    {
                        minAngle = angle;

                        visibleVertex = v;

                        //We also need to calculate this in case a future point has the same angle
                        minDistSqr = MyVector2.SqrDistance(v, hole.maxX_Vert);

                        //Debug.Log(minDistanceSqr);

                        //TestAlgorithmsHelpMethods.DebugDrawCircle(v.ToVector3(1f), 0.3f, Color.green);
                    }
                    //If the angle is the same, then pick the vertex which is the closest to the point on the hull
                    else if (Mathf.Abs(angle - minAngle) < MathUtility.EPSILON)
                    {
                        float distSqr = MyVector2.SqrDistance(v, hole.maxX_Vert);

                        //Debug.Log(minDistanceSqr);

                        if (distSqr < minDistSqr)
                        {
                            visibleVertex = v;

                            minDistSqr = distSqr;

                            //TestAlgorithmsHelpMethods.DebugDrawCircle(v.ToVector3(1f), 0.3f, Color.red);

                            //Debug.Log(distSqr);
                        }
                    }
                }
            }

            //Will show how the holes are connected with the hull
            //Debug.DrawLine(visibleVertex.ToVector3(1f), hole.maxX_Vert.ToVector3(1f), Color.red, 5f);

            //TestAlgorithmsHelpMethods.DebugDrawCircle(visibleVertex.ToVector3(1f), 0.3f, Color.red);
            //TestAlgorithmsHelpMethods.DebugDrawCircle(hole.maxX_Vert.ToVector3(1f), 0.3f, Color.red);
        }
        //Used for debugging so we can see what's going on
        //public static List<MyVector2> GenerateConvexHull(List<MyVector2> originalPoints, bool includeColinearPoints, AABB normalizingbox, float dMax)


        public static List <MyVector2> GenerateConvexHull(List <MyVector2> originalPoints, bool includeColinearPoints)
        {
            List <MyVector2> pointsOnConvexHull = new List <MyVector2>();


            //Step 1.
            //Find the extreme points along each axis
            //This is similar to AABB but we need both x and y coordinates at each extreme point
            MyVector2 maxX = originalPoints[0];
            MyVector2 minX = originalPoints[0];
            MyVector2 maxY = originalPoints[0];
            MyVector2 minY = originalPoints[0];

            for (int i = 1; i < originalPoints.Count; i++)
            {
                MyVector2 p = originalPoints[i];

                if (p.x > maxX.x)
                {
                    maxX = p;
                }
                if (p.x < minX.x)
                {
                    minX = p;
                }

                if (p.y > maxY.y)
                {
                    maxY = p;
                }
                if (p.y < minY.y)
                {
                    minY = p;
                }
            }


            //Step 2.
            //From the 4 extreme points, choose the pair that's furthest appart
            //These two are the first two points on the hull
            List <MyVector2> extremePoints = new List <MyVector2>()
            {
                maxX, minX, maxY, minY
            };

            //Just pick some points as start value
            MyVector2 p1 = maxX;
            MyVector2 p2 = minX;

            //Can use sqr because we are not interested in the exact distance
            float maxDistanceSqr = -Mathf.Infinity;

            //Loop through all points and compare them
            //TODO is comparing too many times: example maxX with maxY, and then maxY with maxX
            //https://stackoverflow.com/questions/12249051/unique-combinations-of-list
            for (int i = 0; i < extremePoints.Count; i++)
            {
                MyVector2 p1_test = extremePoints[i];

                for (int j = 0; j < extremePoints.Count; j++)
                {
                    //Dont compare the point with itself
                    if (i == j)
                    {
                        continue;
                    }

                    MyVector2 p2_test = extremePoints[j];

                    float distSqr = MyVector2.SqrDistance(p1_test, p2_test);

                    if (distSqr > maxDistanceSqr)
                    {
                        maxDistanceSqr = distSqr;

                        p1 = p1_test;
                        p2 = p2_test;
                    }
                }
            }

            //Convert the list to hashset to easier remove points which are on the hull or are inside of the hull
            HashSet <MyVector2> pointsToAdd = new HashSet <MyVector2>(originalPoints);

            //Remove the first 2 points on the hull
            pointsToAdd.Remove(p1);
            pointsToAdd.Remove(p2);


            //Step 3.
            //Find the third point on the hull, by finding the point which is the furthest
            //from the line between p1 and p2
            MyVector2 p3 = FindPointFurthestFromEdge(p1, p2, pointsToAdd);

            //Remove it from the points we want to add
            pointsToAdd.Remove(p3);


            //Step 4. Form the intitial triangle

            //Make sure the hull is oriented counter-clockwise
            Triangle2 tStart = new Triangle2(p1, p2, p3);

            if (_Geometry.IsTriangleOrientedClockwise(tStart.p1, tStart.p2, tStart.p3))
            {
                tStart.ChangeOrientation();
            }

            //New p1-p3
            p1 = tStart.p1;
            p2 = tStart.p2;
            p3 = tStart.p3;

            //pointsOnConvexHull.Add(p1);
            //pointsOnConvexHull.Add(p2);
            //pointsOnConvexHull.Add(p3);

            //Remove the points that we now know are within the hull triangle
            RemovePointsWithinTriangle(tStart, pointsToAdd);


            //Step 5.
            //Associate the rest of the points to their closest edge
            HashSet <MyVector2> edge_p1p2_points = new HashSet <MyVector2>();
            HashSet <MyVector2> edge_p2p3_points = new HashSet <MyVector2>();
            HashSet <MyVector2> edge_p3p1_points = new HashSet <MyVector2>();

            foreach (MyVector2 p in pointsToAdd)
            {
                //p1 p2
                LeftOnRight pointRelation1 = _Geometry.IsPoint_Left_On_Right_OfVector(p1, p2, p);

                if (pointRelation1 == LeftOnRight.On || pointRelation1 == LeftOnRight.Right)
                {
                    edge_p1p2_points.Add(p);

                    continue;
                }

                //p2 p3
                LeftOnRight pointRelation2 = _Geometry.IsPoint_Left_On_Right_OfVector(p2, p3, p);

                if (pointRelation2 == LeftOnRight.On || pointRelation2 == LeftOnRight.Right)
                {
                    edge_p2p3_points.Add(p);

                    continue;
                }

                //p3 p1
                //If the point hasnt been added yet, we know it belong to this edge
                edge_p3p1_points.Add(p);
            }


            //Step 6
            //For each edge, find the point furthest away and create a new triangle
            //and repeat the above steps by finding which points are inside of the hull
            //and which points are outside and belong to a new edge

            //Will automatically ignore the last point on this sub-hull to avoid doubles
            List <MyVector2> pointsOnHUll_p1p2 = CreateSubConvexHUll(p1, p2, edge_p1p2_points);

            List <MyVector2> pointsOnHUll_p2p3 = CreateSubConvexHUll(p2, p3, edge_p2p3_points);

            List <MyVector2> pointsOnHUll_p3p1 = CreateSubConvexHUll(p3, p1, edge_p3p1_points);


            //Create the final hull by combing the points
            pointsOnConvexHull.Clear();

            pointsOnConvexHull.AddRange(pointsOnHUll_p1p2);
            pointsOnConvexHull.AddRange(pointsOnHUll_p2p3);
            pointsOnConvexHull.AddRange(pointsOnHUll_p3p1);



            //Step 7. Add colinear points
            //I think the easiest way to add colinear points is to add them when the algorithm is finished
            if (includeColinearPoints)
            {
                pointsOnConvexHull = AddColinearPoints(pointsOnConvexHull, originalPoints);
            }


            //Debug.Log("Points on hull: " + pointsOnConvexHull.Count);


            return(pointsOnConvexHull);
        }
Esempio n. 4
0
        //Find a vertex on the hull that should be visible from the hole
        private static void FindVisibleVertexOnHUll(EarClippingPolygon hull, EarClippingPolygon hole, Edge2 line_hole_to_outside, out int closestEdge, out MyVector2 visibleVertex)
        {
            //The first and second point on the hull is defined as edge 0, and so on...
            closestEdge = -1;
            //The vertex that should be visible to the hole (which is the max of the line that's intersecting with the line)
            visibleVertex = new MyVector2(-1f, -1f);


            //Do line-line intersection to find intersectionVertex which is the point of intersection that's the closest to the hole
            MyVector2 intersectionVertex = new MyVector2(-1f, -1f);

            float minDistanceSqr = Mathf.Infinity;

            List <MyVector2> verticesHull = hull.Vertices;

            for (int i = 0; i < verticesHull.Count; i++)
            {
                MyVector2 p1_hull = verticesHull[i];
                MyVector2 p2_hull = verticesHull[MathUtility.ClampListIndex(i + 1, verticesHull.Count)];

                //We dont need to check this line if it's to the left of the point on the hole
                //If so they cant intersect
                if (p1_hull.x < hole.maxX_Vert.x && p2_hull.x < hole.maxX_Vert.x)
                {
                    continue;
                }

                Edge2 line_hull = new Edge2(p1_hull, p2_hull);

                bool isIntersecting = _Intersections.LineLine(line_hole_to_outside, line_hull, includeEndPoints: true);

                //Here we can maybe add a check if any of the vertices is on the line???

                if (isIntersecting)
                {
                    MyVector2 testIntersectionVertex = _Intersections.GetLineLineIntersectionPoint(line_hole_to_outside, line_hull);

                    //if (hole.id == 3) TestAlgorithmsHelpMethods.DebugDrawCircle(testIntersectionVertex.ToVector3(), 0.2f, Color.green);

                    float distanceSqr = MyVector2.SqrDistance(line_hole_to_outside.p1, testIntersectionVertex);

                    if (distanceSqr < minDistanceSqr)
                    {
                        closestEdge    = i;
                        minDistanceSqr = distanceSqr;

                        intersectionVertex = testIntersectionVertex;
                    }
                }
            }

            //This means we couldn't find a closest edge
            if (closestEdge == -1)
            {
                Debug.Log("Couldn't find a closest edge to hole");

                return;
            }


            //But we can't connect the hole with this intersection point, so we need to find a vertex which is visible from the hole
            //The closest edge has two vertices. Pick the one with the highest x-value, which is the vertex
            //that should be visible from the hole
            MyVector2 p1 = hull.Vertices[closestEdge];
            MyVector2 p2 = hull.Vertices[MathUtility.ClampListIndex(closestEdge + 1, hull.Vertices.Count)];

            visibleVertex = p1;

            //They are the same so pick the one that is the closest
            if (Mathf.Abs(p1.x - p2.x) < MathUtility.EPSILON)
            {
                float hole_p1 = MyVector2.SqrDistance(hole.maxX_Vert, p1);
                float hole_p2 = MyVector2.SqrDistance(hole.maxX_Vert, p2);

                visibleVertex = hole_p1 < hole_p2 ? p1 : p2;
            }
            else if (p2.x > visibleVertex.x)
            {
                visibleVertex = p2;
            }

            if (hole.id == 3)
            {
                //TestAlgorithmsHelpMethods.DebugDrawCircle(intersectionVertex.ToVector3(), 0.4f, Color.black);
                //TestAlgorithmsHelpMethods.DebugDrawCircle(visibleVertex.ToVector3(), 0.4f, Color.green);
            }

            //But the hull may still intersect with this edge between the point on the hole and the visible point on the hull,
            //so the visible point on the hull might not be visible after all
            //So we might have to find a new point which is visible
            FindActualVisibleVertexOnHull(hull, hole, intersectionVertex, ref visibleVertex);
        }