예제 #1
0
 public void AddPoint(Vertex p)
 {
     min.x = Math.Min(min.x, p.x);
     max.x = Math.Max(max.x, p.x);
     min.y = Math.Min(min.y, p.y);
     max.y = Math.Max(max.y, p.y);
 }
예제 #2
0
 public static float Orient(Vertex a,
             Vertex b,
             Vertex c)
 {
     Matrix3 m = new Matrix3(a.x, a.y, 1,
                             b.x, b.y, 1,
                             c.x, c.y, 1);
     return m.Determinant();
 }
예제 #3
0
 // returns > 0 if p is inside the circle described by A,B,C < 0 outside, = 0 on the circle
 public static float InCircle(Vertex a,
                         Vertex b,
                         Vertex c,
                         Vertex p)
 {
     Matrix4 m = new Matrix4(a.x, a.y, a.x * a.x + a.y * a.y, 1,
                             b.x, b.y, b.x * b.x + b.y * b.y, 1,
                             c.x, c.y, c.x * c.x + c.y * c.y, 1,
                             p.x, p.y, p.x * p.x + p.y * p.y, 1);
     float det = m.Determinant();
     if (Orient(a, b, c) > 0.0f)
     {
         return det;
     }
     else
     {
         return -det;
     }
 }
예제 #4
0
 public void BoundingCircunference(out Vertex center, out float radius)
 {
     center = (max + min) * 0.5f;
     radius = Vertex.Distance(center, min);
 }
예제 #5
0
        public void SplitTriangle(int triIdx, Vertex p, out int[] result)
        {
            int newVertex = vertices.Count;
            vertices.Add(p);

            Triangle oldTri = triangles[triIdx];
            Debug.Assert(oldTri.valid);

            int A = oldTri.vertices[0];
            int B = oldTri.vertices[1];
            int C = oldTri.vertices[2];
            Debug.Assert(A != B && A != C && A != newVertex && B != C && B != newVertex && C != newVertex);

            RemoveTriangle(triIdx);

            result = new int[3];
            result[0] = CreateTriangle(A, B, newVertex);
            result[1] = CreateTriangle(B, C, newVertex);
            result[2] = CreateTriangle(C, A, newVertex);
            #if DEBUG
            Debug.Assert(CheckConsistency());
            #endif
        }
예제 #6
0
        public void SplitEdge(int edgeIndex, Vertex p, out int[] result)
        {
            Edge edge = edges[edgeIndex];
            float distance;
            Debug.Assert(PointOnSegment(vertices[edge.vertices[0]],
                                          vertices[edge.vertices[1]],
                                          p,
                                          POINT_ON_SEGMENT_DISTANCE_EPSILON,
                                          POINT_ON_SEGMENT_PARAMETRIC_EPSILON,
                                          out distance));

            /*
                       B = edge.v[0]
                      /|\
                     / | \         T1 = A,B,C   T2 = D,C,B
                    /  |  \
                   /   |   \       T1' = A,B,P  T2' = D,C,P  T3' = A,P,C  T4' = B,D,P
                  /    |    \
                A ---- P ---- D
                  \    |    /
                   \   |   /
                    \  |  /
                     \ | /
                      \|/
                       C = edge.v[1]

            */

            result = new int[4];
            for (int idx = 0; idx < 4; idx++)
            {
                result[idx] = -1;
            }

            int triIdx1 = edge.triangles[0];
            int triIdx2 = edge.triangles[1];

            int tri1edge = triIdx1 >= 0 ? triangles[triIdx1].LocalEdgeIndex(edgeIndex) : -1;
            Debug.Assert(triIdx1 < 0 || tri1edge >= 0);
            int tri2edge = triIdx2 >= 0 ? triangles[triIdx2].LocalEdgeIndex(edgeIndex) : -1;
            Debug.Assert(triIdx2 < 0 || tri2edge >= 0);
            int A = triIdx1 >= 0 ? VertexOutOfTriEdge(triIdx1, tri1edge) : -1;
            Debug.Assert(triIdx1 < 0 || A >= 0);
            int D = triIdx2 >= 0 ? VertexOutOfTriEdge(triIdx2, tri2edge) : -1;
            Debug.Assert(triIdx2 < 0 || D >= 0);

            if (A < 0 || D < 0) return;

            int B = edge.vertices[0];
            int C = edge.vertices[1];

            Debug.Assert(B >= 0 && C >= 0);
            if (B < 0 || C < 0) return;

            Debug.Assert(triangles[triIdx1].Contains(A, B, C));
            Debug.Assert(triangles[triIdx2].Contains(C, B, D));
            if (triIdx1 >= 0) RemoveTriangle(triIdx1);
            if (triIdx2 >= 0) RemoveTriangle(triIdx2);
            Debug.Assert(edge.triangles[0] < 0 && edge.triangles[1] < 0);

            vertices.Add(p);
            int newVertex = vertices.Count - 1;

            int index = 0;
            if (A >= 0 && B >= 0)
            {
                result[index++] = CreateTriangle(A, B, newVertex);
            }
            if (D >= 0 && C >= 0)
            {
                result[index++] = CreateTriangle(D, C, newVertex);
            }
            if (A >= 0 && C >= 0)
            {
                result[index++] = CreateTriangle(A, newVertex, C);
            }
            if (B >= 0 && D >= 0)
            {
                result[index++] = CreateTriangle(B, D, newVertex);
            }
            #if DEBUG
            Debug.Assert(CheckConsistency());
            #endif
        }
예제 #7
0
 public static bool SegmentIntersect(Vertex A, Vertex B, Vertex C, Vertex D)
 {
     Vertex p;
     return SegmentIntersect(A, B, C, D, out p);
 }
예제 #8
0
            public bool CircumCircle(List<Vertex> verts, out Vertex center, out float radius)
            {
                // Calculate the circle that passes through 3 coplanar points
                // http://mathworld.wolfram.com/Circle.html

                Vertex p0 = verts[vertices[0]];
                Vertex p1 = verts[vertices[1]];
                Vertex p2 = verts[vertices[2]];

                Matrix3 ma = new Matrix3(p0.x, p0.y, 1,
                                            p1.x, p1.y, 1,
                                            p2.x, p2.y, 1);
                float a = ma.Determinant();
                if (Math.Abs(a) < 1e-5f)
                {
                    center = new Vertex(0, 0);
                    radius = 0;
                    return false;
                }

                Matrix3 md = new Matrix3(p0.x * p0.x + p0.y * p0.y, p0.y, 1,
                                          p1.x * p1.x + p1.y * p1.y, p1.y, 1,
                                          p2.x * p2.x + p2.y * p2.y, p2.y, 1);
                float d = -md.Determinant();

                Matrix3 me = new Matrix3(p0.x * p0.x + p0.y * p0.y, p0.x, 1,
                                          p1.x * p1.x + p1.y * p1.y, p1.x, 1,
                                          p2.x * p2.x + p2.y * p2.y, p2.x, 1);
                float e = me.Determinant();

                Matrix3 mf = new Matrix3(p0.x * p0.x + p0.y * p0.y, p0.x, p0.y,
                                          p1.x * p1.x + p1.y * p1.y, p1.x, p1.y,
                                          p2.x * p2.x + p2.y * p2.y, p2.x, p2.y);
                float f = -mf.Determinant();

                center = new Vertex(-d / (2 * a), -e / (2 * a));
                radius = (float)Math.Sqrt((d * d + e * e) / (4 * a * a) - f / a);

                return true;
            }
예제 #9
0
        public void ToImage(Image img, Adjacency adjacency)
        {
            SolidBrush vertexColor = new SolidBrush(Color.Green);
            Pen boundaryColor = new Pen(Color.Blue);
            Pen cellColor = new Pen(Color.Gray);

            Graphics g = Graphics.FromImage(img);
            g.Clear(Color.White);
            for (int e = 0; e < edges.Count; e++)
            {
                Vertex v0 = vertices[ edges[e].v[0] ];
                Vertex v1 = vertices[ edges[e].v[1] ];
                g.DrawLine(boundaryColor, v0.x * img.Width, v0.y * img.Height, v1.x * img.Width, v1.y * img.Height);

                Vertex cellA = adjacency.vertices[edges[e].cell[0]];
                Vertex cellB = adjacency.vertices[edges[e].cell[1]];
                Vertex centerV = new Vertex((v0.x + v1.x) * 0.5f, (v0.y + v1.y) * 0.5f);
                g.DrawLine(cellColor, centerV.x * img.Width, centerV.y * img.Height, cellA.x * img.Width, cellA.y * img.Height);
                g.DrawLine(cellColor, centerV.x * img.Width, centerV.y * img.Height, cellB.x * img.Width, cellB.y * img.Height);
            }
            for (int v = 0; v < vertices.Count; v++)
            {
                const float r = 3;
                g.FillEllipse(vertexColor, new RectangleF(vertices[v].x * img.Width - r, vertices[v].y * img.Height - r, 2 * r, 2 * r));
            }
        }
예제 #10
0
        public static bool PointInPolygon(Vertex p, List<Vertex> polygon)
        {
            if ( polygon.Count < 4 ) return false; // idx 0 and n are the same, so we need 2 extra points minimum

            // polygon is considered a closed shape made of edges linking vi and vi+1
            Debug.Assert(polygon[0] == polygon[polygon.Count - 1]);

            // trace an "infinite" line from the source point and count the number
            // of intersections with the polygon edges. Even number = the point
            // is outside, odd number if it's inside.

            // We will use a horizontal line, but to avoid intersections with the
            // VERTICES on any segment, we'll sort the Y coordinates of every vertex
            // and find a gap

            Vertex rectEndPoint = null;

            List<float> y = new List<float>();
            for (int i = 0; i < polygon.Count - 1; i++)
            {
                y.Add(polygon[i].y);
            }
            y.Sort();
            if (p.y <= y[0] || p.y >= y[y.Count - 1]) return false;

            int index = y.BinarySearch(p.y);
            if ( index < 0 ) index = ~index; // if not found, index will be <0 with the closest greater number in bitwise complement

            // we've already ruled out the cases where p.y < all values and p.y > all values, so index must be within 1..n-1
            float approxY = (y[index-1] + y[index]) * 0.5f;
            rectEndPoint = new Vertex( p.x + 10000.0f, //make it a big number, but not as much as float.MaxValue to avoid numerical issues
                                       approxY);

            // count intersections
            int intersections = 0;
            for (int i = 0; i < polygon.Count-1; i++)
            {
                if (SegmentIntersect(polygon[i], polygon[i + 1], p, rectEndPoint)) intersections++;
            }

            return intersections > 0 && intersections % 2 !=  0;
        }
예제 #11
0
 public static Vertex Normalize(Vertex v)
 {
     float f = v.Length();
     return new Vertex(v.x / f, v.y / f);
 }
예제 #12
0
 public static float Dot(Vertex a, Vertex b)
 {
     return a.x * b.x + a.y * b.y;
 }
예제 #13
0
 public static float Distance(Vertex a, Vertex b)
 {
     return (float)Math.Sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
 }
예제 #14
0
 static float Signed2DTriangleArea(Vertex A, Vertex B, Vertex C)
 {
     return (A.x - C.x) * (B.y - C.y) - (A.y - C.y) * (B.x - C.x);
 }
예제 #15
0
        // returns the triangle index of the triangle containing p
        public int PointInTriangle(Vertex p)
        {
            for (int i = 0; i < triangles.Count; i++)
            {

                Triangle t = triangles[i];
                if (!t.valid)
                {
                    continue;
                }

                bool hit = false;

                // use barycentric coordinates to determine whether the point is inside the triangle

                // http://steve.hollasch.net/cgindex/math/barycentric.html

                Vertex v0 = vertices[t.vertices[0]];
                Vertex v1 = vertices[t.vertices[1]];
                Vertex v2 = vertices[t.vertices[2]];

                float b0 = (v1.x - v0.x) * (v2.y - v0.y) - (v2.x - v0.x) * (v1.y - v0.y);
                if (b0 != 0)
                {
                    float b1 = ((v1.x - p.x) * (v2.y - p.y) - (v2.x - p.x) * (v1.y - p.y)) / b0;
                    float b2 = ((v2.x - p.x) * (v0.y - p.y) - (v0.x - p.x) * (v2.y - p.y)) / b0;
                    float b3 = ((v0.x - p.x) * (v1.y - p.y) - (v1.x - p.x) * (v0.y - p.y)) / b0;

                    hit = b1 >= 0 && b2 >= 0 && b3 >= 0;
                }

                if (hit)
                {
                    return i;
                }
            }
            return -1;
        }
예제 #16
0
        bool PointOnSegment(Vertex A, Vertex B,
                             Vertex P,
                             float distanceEpsilon,
                             float parametricEpsilon,
                             out float pointSegmentDistance)
        {
            // Determines whether P lies within the segment A-B

            float segmentLength = Vertex.Distance(A, B);
            float tangentABdist = Vertex.Dot(Vertex.Normalize(B - A), Vertex.Normalize(P - A)) * (P - A).Length();
            float u = tangentABdist / segmentLength;
            if (u < parametricEpsilon || u > 1.0 - parametricEpsilon)
            {
                pointSegmentDistance = float.MaxValue;
                return false;
            }

            Vertex isect = A + (B - A) * u;
            float dist = (P - isect).Length();

            pointSegmentDistance = dist;

            if (dist > distanceEpsilon * segmentLength)
            {
                return false;
            }
            return true;
        }
예제 #17
0
        public int PointInTriangleEdge(Vertex p, int t)
        {
            Triangle triangle = triangles[t];
            Debug.Assert(triangle.valid);

            int closestEdge = -1;
            float closestDistance = float.MaxValue;
            for (int i = 0; i < 3; i++)
            {
                Debug.Assert(triangle.edges[i] != Int32.MaxValue);
                int edgeIdx = Math.Abs(triangle.edges[i]) - 1;
                Edge edge = edges[edgeIdx];
                float distance;
                if (PointOnSegment(vertices[edge.vertices[0]],
                                     vertices[edge.vertices[1]],
                                     p,
                                     POINT_ON_SEGMENT_DISTANCE_EPSILON,
                                     POINT_ON_SEGMENT_PARAMETRIC_EPSILON,
                                     out distance))
                {
                    if (distance < closestDistance)
                    {
                        closestDistance = distance;
                        closestEdge = edgeIdx;
                    }
                }
            }

            return closestEdge;
        }
예제 #18
0
 public float InsideCircumcircle(Vertex p, List<Vertex> verts)
 {
     Vertex A = verts[vertices[0]];
     Vertex B = verts[vertices[1]];
     Vertex C = verts[vertices[2]];
     float det = Predicates.InCircle(A, B, C, p);
     return det;
 }
예제 #19
0
 public Bounds2D()
 {
     min = new Vertex(float.MaxValue, float.MaxValue);
     max = new Vertex(float.MinValue, float.MinValue);
 }
예제 #20
0
        private static void Delaunay2DCreateSuperTriangle(List<Vertex> vertices, Adjacency adjacency,
                                            out int stIdx1, out int stIdx2, out int stIdx3)
        {
            // Calculate super triangle

            Bounds2D bounds = new Bounds2D();
            for (int i = 0; i < vertices.Count; i++)
            {
                bounds.AddPoint(vertices[i]);
            }

            Vertex center;
            float radius;
            bounds.BoundingCircunference(out center, out radius);

            Vertex st1 = new Vertex();
            Vertex st2 = new Vertex();
            Vertex st3 = new Vertex();

            const float DEG2RAD = (float)Math.PI / 180.0f;

            st1.x = center.x + 2.0f * radius * (float)Math.Cos(0.0f * DEG2RAD);
            st1.y = center.y + 2.0f * radius * (float)Math.Sin(0.0f * DEG2RAD);
            st2.x = center.x + 2.0f * radius * (float)Math.Cos(120.0f * DEG2RAD);
            st2.y = center.y + 2.0f * radius * (float)Math.Sin(120.0f * DEG2RAD);
            st3.x = center.x + 2.0f * radius * (float)Math.Cos(240.0f * DEG2RAD);
            st3.y = center.y + 2.0f * radius * (float)Math.Sin(240.0f * DEG2RAD);

            adjacency.vertices.Add(st1);
            adjacency.vertices.Add(st2);
            adjacency.vertices.Add(st3);

            stIdx1 = adjacency.vertices.Count - 3;
            stIdx2 = adjacency.vertices.Count - 2;
            stIdx3 = adjacency.vertices.Count - 1;

            adjacency.CreateTriangle(stIdx1, stIdx2, stIdx3);
        }
예제 #21
0
        public static bool SegmentIntersect(Vertex A, Vertex B, Vertex C, Vertex D, out Vertex p )
        {
            // using triangle areas (Real Time Collision Detection book)

            float a1 = Signed2DTriangleArea(A, B, D); // compute winding of ABD [ + or - ]
            float a2 = Signed2DTriangleArea(A, B, C); // to intersect, must have sign opposite of a1

            // if c and d are on different sides of AB, areas have different signs
            if (Math.Abs(a1) > 1e-3f && Math.Abs(a2) > 1e-3f && a1 * a2 < 0.0f)
            {
                // Compute signs of a and b with respect to segment cd
                float a3 = Signed2DTriangleArea(C, D, A); // Compute winding of cda [ + or - ]
                // since area is ant a1 - a2 = a3 - a4, or a4 = a3 + a2 - a1
                //float a4 = Signed2DTriangleArea( C, D, B );
                float a4 = a3 + a2 - a1;
                // Points a and b on different sides of cd if areas have different signs
                if (a3 * a4 < 0.0f)
                {
                    // Segments intersect. Find intersection poitn along L(t) = a + t * ( b - a )
                    float t = a3 / ( a3 - a4 );
                    p = A + ( B - A ) * t;
                    return true;
                }
            }
            // segments not intersecting (or collinear)
            p = new Vertex(-1, -1);
            return false;
        }