Ejemplo n.º 1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="Segment" /> class.
        /// </summary>
        public Segment(Vertex v0, Vertex v1, int label)
        {
            this.v0 = v0;
            this.v1 = v1;

            this.label = label;
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Read vertex information of the given line.
        /// </summary>
        /// <param name="data">The input geometry.</param>
        /// <param name="index">The current vertex index.</param>
        /// <param name="line">The current line.</param>
        /// <param name="attributes">Number of point attributes</param>
        /// <param name="marks">Number of point markers (0 or 1)</param>
        static void ReadVertex(List<Vertex> data, int index, string[] line, int attributes, int marks)
        {
            double x = double.Parse(line[1], nfi);
            double y = double.Parse(line[2], nfi);

            var v = new Vertex(x, y);

            // Read a vertex marker.
            if (marks > 0 && line.Length > 3 + attributes)
            {
                v.Label = int.Parse(line[3 + attributes]);
            }

            if (attributes > 0)
            {
#if USE_ATTRIBS
                var attribs = new double[attributes];

                // Read the vertex attributes.
                for (int j = 0; j < attributes; j++)
                {
                    if (line.Length > 3 + j)
                    {
                        attribs[j] = double.Parse(line[3 + j], nfi);
                    }
                }

                v.attributes = attribs;
#endif
            }

            data.Add(v);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Enumerate all vertices adjacent to given vertex.
        /// </summary>
        /// <param name="vertex">The center vertex.</param>
        /// <returns></returns>
        public IEnumerable<Vertex> EnumerateVertices(Vertex vertex)
        {
            BuildCache(vertex, true);

            foreach (var item in cache)
            {
                yield return item.Dest();
            }
        }
Ejemplo n.º 4
0
        public VoronoiRegion(Vertex generator)
        {
            this.id = generator.id;
            this.generator = generator;
            this.vertices = new List<Point>();
            this.bounded = true;

            this.neighbors = new Dictionary<int, VoronoiRegion>();
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Enumerate all triangles adjacent to given vertex.
        /// </summary>
        /// <param name="vertex">The center vertex.</param>
        /// <returns></returns>
        public IEnumerable<ITriangle> EnumerateTriangles(Vertex vertex)
        {
            BuildCache(vertex, false);

            foreach (var item in cache)
            {
                yield return item.tri;
            }
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Case 2: edge origin lies outside the domain.
        /// </summary>
        private void HandleCase2(HalfEdge edge, TVertex v1, TVertex v2)
        {
            // The vertices of the infinite edge.
            var p1 = (Point)edge.origin;
            var p2 = (Point)edge.twin.origin;

            // The two edges leaving p1, pointing into the mesh.
            var e1 = edge.twin.next;
            var e2 = e1.twin.next;

            // Check if the neighboring cell was closed before.
            if (edge.twin.id != edge.twin.face.edge.id)
            {
                edge.twin.face.edge.next = e1;
            }
            else
            {
                // If the cell isn't closed yet, make sure to update the faces edge pointer.
                e1.face.edge = e1;
            }

            // Find the two intersections with boundary edge.
            IntersectionHelper.IntersectSegments(v1, v2, e1.origin, e1.twin.origin, ref p2);
            IntersectionHelper.IntersectSegments(v1, v2, e2.origin, e2.twin.origin, ref p1);

            // The infinite edge will now lie on the boundary. Update pointers:
            e1.twin.next   = edge.twin;
            edge.twin.next = e2;
            edge.twin.face = e2.face;

            e1.origin = edge.twin.origin;

            // Dissolve edge from other edges (origin and face stay the same).
            edge.twin.twin = null;
            edge.twin      = null;

            // Close the cell.
            var gen = factory.CreateVertex(v1.x, v1.y);
            var he  = factory.CreateHalfEdge(gen, edge.face);

            gen.leaving = he;

            edge.next    = he;
            he.next      = edge.face.edge;
            e2.twin.next = edge;

            // Let the face edge point to the edge leaving at generator.
            edge.face.edge = he;

            base.edges.Add(he);

            he.id = base.edges.Count;

            gen.id = offset++;
            base.vertices.Add(gen);
        }
Ejemplo n.º 7
0
        void KruskalsMinimumSpanningTree()
        {
            //triangles = new List<Triangle>();
            tmpConnections = new List <KruskalsEdge>();
            connections    = new List <KruskalsEdge>();
            //triangles = DelaunayTriangulation.TriangulateByFlippingEdges(points);
            List <int> vertices = new List <int>();
            int        index    = 0;
            int        index2   = 0;

            foreach (var edge in mesh.Edges)
            {
                TriangleNet.Geometry.Vertex v0 = mesh.vertices[edge.P0];
                TriangleNet.Geometry.Vertex v1 = mesh.vertices[edge.P1];
                Vector3 p0  = new Vector3((float)v0.x, 0.0f, (float)v0.y);
                Vector3 p1  = new Vector3((float)v1.x, 0.0f, (float)v1.y);
                int     tmp = 0;
                foreach (var point in Rooms)
                {
                    if (p0 == point.Position)
                    {
                        index = tmp;
                        break;
                    }

                    tmp++;
                }
                tmp = 0;
                foreach (var point in Rooms)
                {
                    if (p1 == point.Position)
                    {
                        index2 = tmp;
                        break;
                    }

                    tmp++;
                }
                tmpConnections.Add(new KruskalsEdge()
                {
                    Vertex1 = edge.P0, Room1 = Rooms[index], Vertex2 = edge.P1, Room2 = Rooms[index2], Weight = (Vector3.Distance(p0, p1)) * (Rooms[index].weight / 20)
                });
                if (!vertices.Contains(edge.P0))
                {
                    vertices.Add(edge.P0);
                }
                if (!vertices.Contains(edge.P1))
                {
                    vertices.Add(edge.P1);
                }
            }

            connections = KruskalsAlgorithm.Kruskals_MST(tmpConnections, vertices, false, connectivityPercentage);
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Find a new location for a Steiner point.
        /// </summary>
        /// <param name="org"></param>
        /// <param name="dest"></param>
        /// <param name="apex"></param>
        /// <param name="xi"></param>
        /// <param name="eta"></param>
        /// <param name="offcenter"></param>
        /// <param name="badotri"></param>
        /// <returns></returns>
        public Point FindLocation(Vertex org, Vertex dest, Vertex apex,
            ref double xi, ref double eta, bool offcenter, Otri badotri)
        {
            // Based on using -U switch, call the corresponding function
            if (behavior.MaxAngle == 0.0)
            {
                return FindNewLocationWithoutMaxAngle(org, dest, apex, ref xi, ref eta, true, badotri);
            }

            // With max angle
            return FindNewLocation(org, dest, apex, ref xi, ref eta, true, badotri);
        }
Ejemplo n.º 9
0
        private void BuildCache(Vertex vertex, bool vertices)
        {
            cache.Clear();

            Otri init = vertex.tri;
            Otri next = default(Otri);
            Otri prev = default(Otri);

            init.Copy(ref next);

            // Move counter-clockwise around the vertex.
            while (next.tri.id != Mesh.DUMMY)
            {
                cache.Add(next);

                next.Copy(ref prev);
                next.Onext();

                if (next.Equals(init))
                {
                    break;
                }
            }

            if (next.tri.id == Mesh.DUMMY)
            {
                // We reached the boundary. To get all adjacent triangles, start
                // again at init triangle and now move clockwise.
                init.Copy(ref next);

                if (vertices)
                {
                    // Don't forget to add the vertex lying on the boundary.
                    prev.Lnext();
                    cache.Add(prev);
                }

                next.Oprev();

                while (next.tri.id != Mesh.DUMMY)
                {
                    cache.Insert(0, next);

                    next.Oprev();

                    if (next.Equals(init))
                    {
                        break;
                    }
                }
            }
        }
Ejemplo n.º 10
0
    public static void GenerateOffSet(IslandNetMesh islandNetMesh, float skylandDeclinePrecent, float skylandRadius)
    {
        IEnumerator <TriangleNet.Geometry.Vertex> vertexEnum = islandNetMesh.netMesh.Vertices.GetEnumerator();

        for (int i = 0; i < islandNetMesh.netMesh.vertices.Count; i++)
        {
            if (!vertexEnum.MoveNext())
            {
                break;
            }
            TriangleNet.Geometry.Vertex current = vertexEnum.Current;
            float precentDistanceFromTheEdge    = 1 - Mathf.Sqrt(Mathf.Pow((float)current.x, 2) + Mathf.Pow((float)current.y, 2)) / (float)skylandRadius;
            current.x += (perlinNoise.GetNoise((float)current.x * 10, (float)current.y * 10)) * 5;
            current.y += (perlinNoise.GetNoise((float)current.x * 10, (float)current.y * 10)) * 5;
        }
    }
Ejemplo n.º 11
0
        /// <summary>
        /// Impose alternating cuts on given vertex array.
        /// </summary>
        /// <param name="array">The vertex array.</param>
        /// <param name="length">The number of vertices to sort.</param>
        /// <param name="seed">Random seed used for pivoting.</param>
        public static void Alternate(Vertex[] array, int length, int seed = RANDOM_SEED)
        {
            var qs = new VertexSorter(array, seed);

            int divider = length >> 1;

            // Re-sort the array of vertices to accommodate alternating cuts.
            if (length - divider >= 2)
            {
                if (divider >= 2)
                {
                    qs.AlternateAxes(0, divider - 1, 1);
                }

                qs.AlternateAxes(divider, length - 1, 1);
            }
        }
Ejemplo n.º 12
0
    void CreateMap(TriangleNet.Mesh m, float maxz, float yOffset)
    {
        Dictionary <int, TriangleNet.Geometry.Vertex> id2vert  = new Dictionary <int, TriangleNet.Geometry.Vertex>();
        List <TriangleNet.Geometry.Vertex>            vertices = new List <TriangleNet.Geometry.Vertex>();
        List <ISegment> segments = new List <ISegment>();

        foreach (TriangleNet.Geometry.Vertex v in m.Vertices)
        {
            id2vert[v.id] = v;
            vertices.Add(v);
        }

        foreach (Edge e in m.Edges)
        {
            TriangleNet.Geometry.Vertex v1 = id2vert[e.P0];
            TriangleNet.Geometry.Vertex v2 = id2vert[e.P1];
            segments.Add(new Segment(v1, v2));
        }
        CreateMap(vertices, segments, maxz, yOffset);
    }
Ejemplo n.º 13
0
        /// <summary>
        /// Case 2: edge origin lies outside the domain.
        /// </summary>
        private void HandleCase2(HalfEdge edge, TVertex v1, TVertex v2)
        {
            // The vertices of the infinite edge.
            var p1 = (Point)edge.origin;
            var p2 = (Point)edge.twin.origin;

            // The two edges leaving p1, pointing into the mesh.
            var e1 = edge.twin.next;
            var e2 = e1.twin.next;

            // Find the two intersections with boundary edge.
            IntersectionHelper.IntersectSegments(v1, v2, e1.origin, e1.twin.origin, ref p2);
            IntersectionHelper.IntersectSegments(v1, v2, e2.origin, e2.twin.origin, ref p1);

            // The infinite edge will now lie on the boundary. Update pointers:
            e1.twin.next   = edge.twin;
            edge.twin.next = e2;
            edge.twin.face = e2.face;

            e1.origin = edge.twin.origin;

            edge.twin.twin = null;
            edge.twin      = null;

            // Close the cell.
            var gen = factory.CreateVertex(v1.x, v1.y);
            var he  = factory.CreateHalfEdge(gen, edge.face);

            edge.next = he;
            he.next   = edge.face.edge;

            // Let the face edge point to the edge leaving at generator.
            edge.face.edge = he;

            base.edges.Add(he);

            he.id = base.edges.Count;

            gen.id = offset++;
            base.vertices.Add(gen);
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Linear interpolation of vertex attributes.
        /// </summary>
        /// <param name="vertex">The interpolation vertex.</param>
        /// <param name="triangle">The triangle containing the vertex.</param>
        /// <param name="n">The number of vertex attributes.</param>
        /// <remarks>
        /// The vertex is expected to lie inside the triangle.
        /// </remarks>
        public static void InterpolateAttributes(Vertex vertex, ITriangle triangle, int n)
        {
            Vertex org = triangle.GetVertex(0);
            Vertex dest = triangle.GetVertex(1);
            Vertex apex = triangle.GetVertex(2);

            double xdo, ydo, xao, yao;
            double denominator;
            double dx, dy;
            double xi, eta;

            // Compute the circumcenter of the triangle.
            xdo = dest.x - org.x;
            ydo = dest.y - org.y;
            xao = apex.x - org.x;
            yao = apex.y - org.y;

            denominator = 0.5 / (xdo * yao - xao * ydo);

            //dx = (yao * dodist - ydo * aodist) * denominator;
            //dy = (xdo * aodist - xao * dodist) * denominator;

            dx = vertex.x - org.x;
            dy = vertex.y - org.y;

            // To interpolate vertex attributes for the new vertex inserted at
            // the circumcenter, define a coordinate system with a xi-axis,
            // directed from the triangle's origin to its destination, and
            // an eta-axis, directed from its origin to its apex.
            // Calculate the xi and eta coordinates of the circumcenter.
            xi = (yao * dx - xao * dy) * (2.0 * denominator);
            eta = (xdo * dy - ydo * dx) * (2.0 * denominator);
        
            for (int i = 0; i < n; i++)
            {
                // Interpolate the vertex attributes.
                vertex.attributes[i] = org.attributes[i]
                    + xi * (dest.attributes[i] - org.attributes[i])
                    + eta * (apex.attributes[i] - org.attributes[i]);
            }
        }
Ejemplo n.º 15
0
    void CreateMap(VoronoiBase sv, float maxz, float yOffset)
    {
        Dictionary <int, TriangleNet.Geometry.Vertex> id2vert  = new Dictionary <int, TriangleNet.Geometry.Vertex>();
        List <TriangleNet.Geometry.Vertex>            vertices = new List <TriangleNet.Geometry.Vertex>();
        List <ISegment> segments = new List <ISegment>();

        foreach (TriangleNet.Topology.DCEL.Vertex v in sv.Vertices)
        {
            TriangleNet.Geometry.Vertex new_v = new TriangleNet.Geometry.Vertex(v.x, v.y);
            id2vert[v.id] = new_v;
            vertices.Add(new_v);
        }

        foreach (Edge e in sv.Edges)
        {
            TriangleNet.Geometry.Vertex v1 = id2vert[e.P0];
            TriangleNet.Geometry.Vertex v2 = id2vert[e.P1];
            segments.Add(new Segment(v1, v2));
        }
        CreateMap(vertices, segments, maxz, yOffset);
    }
Ejemplo n.º 16
0
        /// <summary>
        /// Case 1: edge origin lies inside the domain.
        /// </summary>
        private void HandleCase1(HalfEdge edge, TVertex v1, TVertex v2)
        {
            //int mark = GetBoundaryMark(v1);

            // The infinite vertex.
            var v = (Point)edge.twin.origin;

            // The half-edge is the bisector of v1 and v2, so the projection onto the
            // boundary segment is actually its midpoint.
            v.x = (v1.x + v2.x) / 2.0;
            v.y = (v1.y + v2.y) / 2.0;

            // Close the cell connected to edge.
            var gen = factory.CreateVertex(v1.x, v1.y);

            var h1 = factory.CreateHalfEdge(edge.twin.origin, edge.face);
            var h2 = factory.CreateHalfEdge(gen, edge.face);

            edge.next = h1;
            h1.next   = h2;
            h2.next   = edge.face.edge;

            gen.leaving = h2;

            // Let the face edge point to the edge leaving at generator.
            edge.face.edge = h2;

            base.edges.Add(h1);
            base.edges.Add(h2);

            int count = base.edges.Count;

            h1.id = count;
            h2.id = count + 1;

            gen.id = offset++;
            base.vertices.Add(gen);
        }
Ejemplo n.º 17
0
        /// <summary>
        /// Case 1: edge origin lies inside the domain.
        /// </summary>
        private void HandleCase1(HalfEdge edge, TVertex v1, TVertex v2)
        {
            //int mark = GetBoundaryMark(v1);

            // The infinite vertex.
            var v = (Point)edge.twin.origin;

            // The half-edge is the bisector of v1 and v2, so the projection onto the
            // boundary segment is actually its midpoint.
            v.x = (v1.x + v2.x) / 2.0;
            v.y = (v1.y + v2.y) / 2.0;

            // Close the cell connected to edge.
            var gen = factory.CreateVertex(v1.x, v1.y);

            var h1 = factory.CreateHalfEdge(edge.twin.origin, edge.face);
            var h2 = factory.CreateHalfEdge(gen, edge.face);

            edge.next = h1;
            h1.next = h2;
            h2.next = edge.face.edge;

            gen.leaving = h2;

            // Let the face edge point to the edge leaving at generator.
            edge.face.edge = h2;

            base.edges.Add(h1);
            base.edges.Add(h2);

            int count = base.edges.Count;

            h1.id = count;
            h2.id = count + 1;

            gen.id = offset++;
            base.vertices.Add(gen);
        }
Ejemplo n.º 18
0
 /// <summary>
 /// Set the origin of the segment that includes the subsegment.
 /// </summary>
 internal void SetSegOrg(Vertex vertex)
 {
     seg.vertices[2 + orient] = vertex;
 }
Ejemplo n.º 19
0
 /// <summary>
 /// Set destination of a subsegment.
 /// </summary>
 internal void SetDest(Vertex vertex)
 {
     seg.vertices[1 - orient] = vertex;
 }
Ejemplo n.º 20
0
 /// <summary>
 /// Set the origin or destination of a subsegment.
 /// </summary>
 internal void SetOrg(Vertex vertex)
 {
     seg.vertices[orient] = vertex;
 }
Ejemplo n.º 21
0
        /// <summary>
        /// Case 2: edge origin lies outside the domain.
        /// </summary>
        private void HandleCase2(HalfEdge edge, TVertex v1, TVertex v2)
        {
            // The vertices of the infinite edge.
            var p1 = (Point)edge.origin;
            var p2 = (Point)edge.twin.origin;

            // The two edges leaving p1, pointing into the mesh.
            var e1 = edge.twin.next;
            var e2 = e1.twin.next;

            // Find the two intersections with boundary edge.
            IntersectionHelper.IntersectSegments(v1, v2, e1.origin, e1.twin.origin, ref p2);
            IntersectionHelper.IntersectSegments(v1, v2, e2.origin, e2.twin.origin, ref p1);

            // The infinite edge will now lie on the boundary. Update pointers:
            e1.twin.next = edge.twin;
            edge.twin.next = e2;
            edge.twin.face = e2.face;

            e1.origin = edge.twin.origin;

            edge.twin.twin = null;
            edge.twin = null;

            // Close the cell.
            var gen = factory.CreateVertex(v1.x, v1.y);
            var he = factory.CreateHalfEdge(gen, edge.face);

            edge.next = he;
            he.next = edge.face.edge;

            // Let the face edge point to the edge leaving at generator.
            edge.face.edge = he;

            base.edges.Add(he);

            he.id = base.edges.Count;

            gen.id = offset++;
            base.vertices.Add(gen);
        }
Ejemplo n.º 22
0
 /// <summary>
 /// Set Destination
 /// </summary>
 internal void SetDest(Vertex v)
 {
     tri.vertices[minus1Mod3[orient]] = v;
 }
Ejemplo n.º 23
0
        /// <summary>
        /// Finds the star of a given point.
        /// </summary>
        /// <param name="badotri"></param>
        /// <param name="p"></param>
        /// <param name="q"></param>
        /// <param name="r"></param>
        /// <param name="whichPoint"></param>
        /// <param name="points">List of points on the star of the given point.</param>
        /// <returns>Number of points on the star of the given point.</returns>
        private int GetStarPoints(Otri badotri, Vertex p, Vertex q, Vertex r,
                    int whichPoint, ref double[] points)
        {

            Otri neighotri = default(Otri);  // for return value of the function
            Otri tempotri;   // for temporary usage
            double first_x = 0, first_y = 0;	  // keeps the first point to be considered
            double second_x = 0, second_y = 0;  // for determining the edge we will begin
            double third_x = 0, third_y = 0;	  // termination
            double[] returnPoint = new double[2];	  // for keeping the returned point	
            int numvertices = 0;	  // for keeping number of surrounding vertices

            // first determine which point to be used to find its neighbor triangles
            switch (whichPoint)
            {
                case 1:
                    first_x = p.x;	// point at the center
                    first_y = p.y;
                    second_x = r.x; // second vertex of first edge to consider
                    second_y = r.y;
                    third_x = q.x;  // for terminating the search
                    third_y = q.y;
                    break;
                case 2:
                    first_x = q.x;  // point at the center
                    first_y = q.y;
                    second_x = p.x; // second vertex of first edge to consider
                    second_y = p.y;
                    third_x = r.x;	// for terminating the search
                    third_y = r.y;
                    break;
                case 3:
                    first_x = r.x;	// point at the center
                    first_y = r.y;
                    second_x = q.x; // second vertex of first edge to consider
                    second_y = q.y;
                    third_x = p.x;	// for terminating the search
                    third_y = p.y;
                    break;
            }
            tempotri = badotri;
            // add first point as the end of first edge
            points[numvertices] = second_x;
            numvertices++;
            points[numvertices] = second_y;
            numvertices++;
            // assign as dummy value
            returnPoint[0] = second_x; returnPoint[1] = second_y;
            // until we reach the third point of the beginning triangle	
            do
            {
                // find the neighbor's third point where it is incident to given edge
                if (!GetNeighborsVertex(tempotri, first_x, first_y, second_x, second_y, ref returnPoint, ref neighotri))
                {
                    // go to next triangle
                    tempotri = neighotri;
                    // now the second point is the neighbor's third vertex			
                    second_x = returnPoint[0];
                    second_y = returnPoint[1];
                    // add a new point to the list of surrounding points
                    points[numvertices] = returnPoint[0];
                    numvertices++;
                    points[numvertices] = returnPoint[1];
                    numvertices++;
                }
                else
                {
                    numvertices = 0;
                    break;
                }

            } while (!((Math.Abs(returnPoint[0] - third_x) <= EPS) &&
                     (Math.Abs(returnPoint[1] - third_y) <= EPS)));
            return numvertices / 2;

        }
Ejemplo n.º 24
0
 /// <summary>
 /// Add a vertex to the polygon.
 /// </summary>
 /// <param name="vertex">The vertex to insert.</param>
 public void Add(Vertex vertex)
 {
     this.points.Add(vertex);
 }
Ejemplo n.º 25
0
        private void OnDrawGizmos()
        {
            if (Rooms == null)
            {
                return;
            }

            if (ShowBestPointsOnly)
            {
                foreach (var point in bestRooms)
                {
                    Gizmos.color = Color.black;
                    Gizmos.DrawWireCube(point.Position, point.Size);
                }
            }
            else
            {
                foreach (var point in Rooms)
                {
                    Gizmos.color = Color.black;
                    Gizmos.color = new Color(point.weight / 20, Gizmos.color.g, Gizmos.color.b, Gizmos.color.a);
                    Gizmos.DrawWireCube(point.Position, point.Size);
                    //Handles.Label(point.Position, point.Position.ToString());
                }
            }

            if (mesh == null)
            {
                return;
            }

            if (!showConections)
            {
                Gizmos.color = Color.green;
                foreach (var edge in mesh.Edges)
                {
                    TriangleNet.Geometry.Vertex v0 = mesh.vertices[edge.P0];
                    TriangleNet.Geometry.Vertex v1 = mesh.vertices[edge.P1];
                    Vector3 p0 = new Vector3((float)v0.x, 0.0f, (float)v0.y);
                    Vector3 p1 = new Vector3((float)v1.x, 0.0f, (float)v1.y);
                    Gizmos.DrawLine(p0, p1);
                }
            }

            if (connections == null)
            {
                return;
            }

            if (showConections)
            {
                foreach (var connection in connections)
                {
                    Gizmos.color = Color.magenta;
                    Gizmos.DrawLine(connection.Room1.Position, connection.Room2.Position);
                }
            }

            if (showRoomConections)
            {
                foreach (var room in bestRooms)
                {
                    Gizmos.color = Color.cyan;
                    foreach (var connection in room.connections)
                    {
                        Gizmos.DrawLine(room.Position, connection.Position);
                    }
                }
            }
        }
Ejemplo n.º 26
0
    public override List <SubdividableEdgeLoop <CityEdge> > GetChildren(SubdividableEdgeLoop <CityEdge> parent)
    {
        Vector2[] parentPoints = parent.GetPoints();
        Polygon   parentPoly   = parent.GetPolygon();
        //generate points of interest
        List <RoadDestination> pointsOfInterest = new List <RoadDestination>();
        Vector2 centroid = parent.GetCenter();
        //parent.EnumerateEdges((EdgeLoopEdge edge) =>
        //{
        //    pointsOfInterest.Add(new RoadDestination(Vector2.Lerp(edge.a.pt, edge.b.pt, Random.Range(0.2f, 0.8f)), 1, false, true));
        //});
        Rect bounds = parent.GetBounds();

        bounds.width  = bounds.width * 2;
        bounds.height = bounds.height * 2;
        int potentialRoadPointsRt = Mathf.CeilToInt(Mathf.Sqrt(potentialRoadPoints));

        float approxDiameter           = Mathf.Sqrt(parentPoly.area);
        float minimumPerimeterDistance = approxDiameter / 4f;

        for (int x = 0; x < potentialRoadPointsRt; x++)
        {
            for (int y = 0; y < potentialRoadPointsRt; y++)
            {
                Vector2 point = new Vector2((x / (float)potentialRoadPointsRt) * bounds.width + bounds.xMin,
                                            (y / (float)potentialRoadPointsRt) * bounds.height + bounds.yMin);
                float distBtwnPts = (bounds.width + bounds.height) / (potentialRoadPoints * 2);
                point = point + new Vector2(Random.Range(-1f, 1f), Random.Range(-1, 1f)) * distBtwnPts * 3f;

                if (parentPoly.ContainsPoint(point)) // && parent.DistToPerimeter(point) > minimumPerimeterDistance)
                {
                    pointsOfInterest.Add(new RoadDestination(point, 0, false, false));
                }
            }
        }
        pointsOfInterest.Add(new RoadDestination(bounds.center + new Vector2(bounds.width * 100, bounds.height * 100), 0, false, false));
        pointsOfInterest.Add(new RoadDestination(bounds.center + new Vector2(bounds.width * 100, -bounds.height * 100), 0, false, false));
        pointsOfInterest.Add(new RoadDestination(bounds.center + new Vector2(-bounds.width * 100, -bounds.height * 100), 0, false, false));
        pointsOfInterest.Add(new RoadDestination(bounds.center + new Vector2(-bounds.width * 100, bounds.height * 100), 0, false, false));

        //triangulate points of interest to get potential road segments
        TriangleNet.Geometry.Polygon polygon = new TriangleNet.Geometry.Polygon();
        Dictionary <TriangleNet.Geometry.Vertex, RoadDestination> vertexDestMap = new Dictionary <TriangleNet.Geometry.Vertex, RoadDestination>();

        foreach (RoadDestination dest in pointsOfInterest)
        {
            TriangleNet.Geometry.Vertex vert = new TriangleNet.Geometry.Vertex(dest.point.x, dest.point.y);
            vertexDestMap.Add(vert, dest);
            polygon.Add(vert);
        }
        TriangleNet.Meshing.ConstraintOptions options =
            new TriangleNet.Meshing.ConstraintOptions()
        {
            ConformingDelaunay = true
        };
        TriangleNet.Meshing.GenericMesher mesher = new TriangleNet.Meshing.GenericMesher();
        TriangleNet.Meshing.IMesh         mesh   = mesher.Triangulate(polygon);

        TriangleNet.Voronoi.StandardVoronoi      voronoi      = new TriangleNet.Voronoi.StandardVoronoi((TriangleNet.Mesh)mesh);
        IEnumerable <TriangleNet.Geometry.IEdge> voronoiEdges = voronoi.Edges;
        List <TriangleNet.Topology.DCEL.Vertex>  voronoiVerts = voronoi.Vertices;

        List <DividingEdge> dividingEdges          = new List <DividingEdge>();
        ILinkedGraphEdgeFactory <CityEdge> factory = new CityEdgeFactory();

        foreach (TriangleNet.Geometry.IEdge edge in voronoiEdges)
        {
            Vector2 a = new Vector2((float)voronoiVerts[edge.P0].X, (float)voronoiVerts[edge.P0].Y);
            Vector2 b = new Vector2((float)voronoiVerts[edge.P1].X, (float)voronoiVerts[edge.P1].Y);

            dividingEdges.Add(new DividingEdge(a, b, factory, factoryParams));
        }



        //get vertices as list
        //ICollection<TriangleNet.Geometry.Vertex> vertices = mesh.Vertices;
        //TriangleNet.Geometry.Vertex[] vertexList = new TriangleNet.Geometry.Vertex[vertices.Count];
        //vertices.CopyTo(vertexList, 0);
        //IEnumerable<TriangleNet.Geometry.Edge> meshEdges = mesh.Edges;


        //build a list of dividing edges and pass it to the child collector


        //foreach (TriangleNet.Geometry.Edge edge in meshEdges) {
        //    //if (vertConnections[edge.P0] > 4)
        //    //{
        //    //    vertConnections[edge.P0]--;
        //    //    continue;
        //    //}
        //    //if (vertConnections[edge.P1] > 4)
        //    //{
        //    //    vertConnections[edge.P1]--;
        //    //    continue;
        //    //}
        //    Vector2 a = new Vector2((float)vertexList[edge.P0].X, (float)vertexList[edge.P0].Y);
        //    Vector2 b = new Vector2((float)vertexList[edge.P1].X, (float)vertexList[edge.P1].Y);

        //    dividingEdges.Add(new DividingEdge(a, b, factory, CityEdgeType.LandPath));
        //}

        return(CollectChildren(parent, dividingEdges));
    }
Ejemplo n.º 27
0
        /// <summary>
        /// Split all the encroached subsegments.
        /// </summary>
        /// <param name="triflaws">A flag that specifies whether one should take 
        /// note of new bad triangles that result from inserting vertices to repair 
        /// encroached subsegments.</param>
        /// <remarks>
        /// Each encroached subsegment is repaired by splitting it - inserting a
        /// vertex at or near its midpoint.  Newly inserted vertices may encroach
        /// upon other subsegments; these are also repaired.
        /// </remarks>
        private void SplitEncSegs(bool triflaws)
        {
            Otri enctri = default(Otri);
            Otri testtri = default(Otri);
            Osub testsh = default(Osub);
            Osub currentenc = default(Osub);
            BadSubseg seg;
            Vertex eorg, edest, eapex;
            Vertex newvertex;
            InsertVertexResult success;
            double segmentlength, nearestpoweroftwo;
            double split;
            double multiplier, divisor;
            bool acuteorg, acuteorg2, acutedest, acutedest2;

            // Note that steinerleft == -1 if an unlimited number
            // of Steiner points is allowed.
            while (badsubsegs.Count > 0)
            {
                if (mesh.steinerleft == 0)
                {
                    break;
                }

                seg = badsubsegs.Dequeue();

                currentenc = seg.subseg;
                eorg = currentenc.Org();
                edest = currentenc.Dest();
                // Make sure that this segment is still the same segment it was
                // when it was determined to be encroached.  If the segment was
                // enqueued multiple times (because several newly inserted
                // vertices encroached it), it may have already been split.
                if (!Osub.IsDead(currentenc.seg) && (eorg == seg.org) && (edest == seg.dest))
                {
                    // To decide where to split a segment, we need to know if the
                    // segment shares an endpoint with an adjacent segment.
                    // The concern is that, if we simply split every encroached
                    // segment in its center, two adjacent segments with a small
                    // angle between them might lead to an infinite loop; each
                    // vertex added to split one segment will encroach upon the
                    // other segment, which must then be split with a vertex that
                    // will encroach upon the first segment, and so on forever.
                    // To avoid this, imagine a set of concentric circles, whose
                    // radii are powers of two, about each segment endpoint.
                    // These concentric circles determine where the segment is
                    // split. (If both endpoints are shared with adjacent
                    // segments, split the segment in the middle, and apply the
                    // concentric circles for later splittings.)

                    // Is the origin shared with another segment?
                    currentenc.Pivot(ref enctri);
                    enctri.Lnext(ref testtri);
                    testtri.Pivot(ref testsh);
                    acuteorg = testsh.seg.hash != Mesh.DUMMY;
                    // Is the destination shared with another segment?
                    testtri.Lnext();
                    testtri.Pivot(ref testsh);
                    acutedest = testsh.seg.hash != Mesh.DUMMY;

                    // If we're using Chew's algorithm (rather than Ruppert's)
                    // to define encroachment, delete free vertices from the
                    // subsegment's diametral circle.
                    if (!behavior.ConformingDelaunay && !acuteorg && !acutedest)
                    {
                        eapex = enctri.Apex();
                        while ((eapex.type == VertexType.FreeVertex) &&
                               ((eorg.x - eapex.x) * (edest.x - eapex.x) +
                                (eorg.y - eapex.y) * (edest.y - eapex.y) < 0.0))
                        {
                            mesh.DeleteVertex(ref testtri);
                            currentenc.Pivot(ref enctri);
                            eapex = enctri.Apex();
                            enctri.Lprev(ref testtri);
                        }
                    }

                    // Now, check the other side of the segment, if there's a triangle there.
                    enctri.Sym(ref testtri);
                    if (testtri.tri.id != Mesh.DUMMY)
                    {
                        // Is the destination shared with another segment?
                        testtri.Lnext();
                        testtri.Pivot(ref testsh);
                        acutedest2 = testsh.seg.hash != Mesh.DUMMY;
                        acutedest = acutedest || acutedest2;
                        // Is the origin shared with another segment?
                        testtri.Lnext();
                        testtri.Pivot(ref testsh);
                        acuteorg2 = testsh.seg.hash != Mesh.DUMMY;
                        acuteorg = acuteorg || acuteorg2;

                        // Delete free vertices from the subsegment's diametral circle.
                        if (!behavior.ConformingDelaunay && !acuteorg2 && !acutedest2)
                        {
                            eapex = testtri.Org();
                            while ((eapex.type == VertexType.FreeVertex) &&
                                   ((eorg.x - eapex.x) * (edest.x - eapex.x) +
                                    (eorg.y - eapex.y) * (edest.y - eapex.y) < 0.0))
                            {
                                mesh.DeleteVertex(ref testtri);
                                enctri.Sym(ref testtri);
                                eapex = testtri.Apex();
                                testtri.Lprev();
                            }
                        }
                    }

                    // Use the concentric circles if exactly one endpoint is shared
                    // with another adjacent segment.
                    if (acuteorg || acutedest)
                    {
                        segmentlength = Math.Sqrt((edest.x - eorg.x) * (edest.x - eorg.x) +
                                             (edest.y - eorg.y) * (edest.y - eorg.y));
                        // Find the power of two that most evenly splits the segment.
                        // The worst case is a 2:1 ratio between subsegment lengths.
                        nearestpoweroftwo = 1.0;
                        while (segmentlength > 3.0 * nearestpoweroftwo)
                        {
                            nearestpoweroftwo *= 2.0;
                        }
                        while (segmentlength < 1.5 * nearestpoweroftwo)
                        {
                            nearestpoweroftwo *= 0.5;
                        }
                        // Where do we split the segment?
                        split = nearestpoweroftwo / segmentlength;
                        if (acutedest)
                        {
                            split = 1.0 - split;
                        }
                    }
                    else
                    {
                        // If we're not worried about adjacent segments, split
                        // this segment in the middle.
                        split = 0.5;
                    }

                    // Create the new vertex (interpolate coordinates).
                    newvertex = new Vertex(
                        eorg.x + split * (edest.x - eorg.x),
                        eorg.y + split * (edest.y - eorg.y),
                        currentenc.seg.boundary
#if USE_ATTRIBS
                        , mesh.nextras
#endif
                    );

                    newvertex.type = VertexType.SegmentVertex;

                    newvertex.hash = mesh.hash_vtx++;
                    newvertex.id = newvertex.hash;

                    mesh.vertices.Add(newvertex.hash, newvertex);
#if USE_ATTRIBS
                    // Interpolate attributes.
                    for (int i = 0; i < mesh.nextras; i++)
                    {
                        newvertex.attributes[i] = eorg.attributes[i]
                            + split * (edest.attributes[i] - eorg.attributes[i]);
                    }
#endif
                    if (!Behavior.NoExact)
                    {
                        // Roundoff in the above calculation may yield a 'newvertex'
                        // that is not precisely collinear with 'eorg' and 'edest'.
                        // Improve collinearity by one step of iterative refinement.
                        multiplier = predicates.CounterClockwise(eorg, edest, newvertex);
                        divisor = ((eorg.x - edest.x) * (eorg.x - edest.x) +
                                   (eorg.y - edest.y) * (eorg.y - edest.y));
                        if ((multiplier != 0.0) && (divisor != 0.0))
                        {
                            multiplier = multiplier / divisor;
                            // Watch out for NANs.
                            if (!double.IsNaN(multiplier))
                            {
                                newvertex.x += multiplier * (edest.y - eorg.y);
                                newvertex.y += multiplier * (eorg.x - edest.x);
                            }
                        }
                    }

                    // Check whether the new vertex lies on an endpoint.
                    if (((newvertex.x == eorg.x) && (newvertex.y == eorg.y)) ||
                        ((newvertex.x == edest.x) && (newvertex.y == edest.y)))
                    {

                        logger.Error("Ran out of precision: I attempted to split a"
                            + " segment to a smaller size than can be accommodated by"
                            + " the finite precision of floating point arithmetic.",
                            "Quality.SplitEncSegs()");

                        throw new Exception("Ran out of precision");
                    }
                    // Insert the splitting vertex.  This should always succeed.
                    success = mesh.InsertVertex(newvertex, ref enctri, ref currentenc, true, triflaws);
                    if ((success != InsertVertexResult.Successful) && (success != InsertVertexResult.Encroaching))
                    {
                        logger.Error("Failure to split a segment.", "Quality.SplitEncSegs()");
                        throw new Exception("Failure to split a segment.");
                    }
                    if (mesh.steinerleft > 0)
                    {
                        mesh.steinerleft--;
                    }
                    // Check the two new subsegments to see if they're encroached.
                    CheckSeg4Encroach(ref currentenc);
                    currentenc.Next();
                    CheckSeg4Encroach(ref currentenc);
                }

                // Set subsegment's origin to NULL. This makes it possible to detect dead 
                // badsubsegs when traversing the list of all badsubsegs.
                seg.org = null;
            }
        }
Ejemplo n.º 28
0
        /// <summary>
        /// Find a new location for a Steiner point.
        /// </summary>
        /// <param name="torg"></param>
        /// <param name="tdest"></param>
        /// <param name="tapex"></param>
        /// <param name="circumcenter"></param>
        /// <param name="xi"></param>
        /// <param name="eta"></param>
        /// <param name="offcenter"></param>
        /// <param name="badotri"></param>
        private Point FindNewLocationWithoutMaxAngle(Vertex torg, Vertex tdest, Vertex tapex,
            ref double xi, ref double eta, bool offcenter, Otri badotri)
        {
            double offconstant = behavior.offconstant;

            // for calculating the distances of the edges
            double xdo, ydo, xao, yao, xda, yda;
            double dodist, aodist, dadist;
            // for exact calculation
            double denominator;
            double dx, dy, dxoff, dyoff;

            ////////////////////////////// HALE'S VARIABLES //////////////////////////////
            // keeps the difference of coordinates edge 
            double xShortestEdge = 0, yShortestEdge = 0, xMiddleEdge, yMiddleEdge, xLongestEdge, yLongestEdge;

            // keeps the square of edge lengths
            double shortestEdgeDist = 0, middleEdgeDist = 0, longestEdgeDist = 0;

            // keeps the vertices according to the angle incident to that vertex in a triangle
            Point smallestAngleCorner, middleAngleCorner, largestAngleCorner;

            // keeps the type of orientation if the triangle
            int orientation = 0;
            // keeps the coordinates of circumcenter of itself and neighbor triangle circumcenter	
            Point myCircumcenter, neighborCircumcenter;

            // keeps if bad triangle is almost good or not
            int almostGood = 0;
            // keeps the cosine of the largest angle
            double cosMaxAngle;
            bool isObtuse; // 1: obtuse 0: nonobtuse
            // keeps the radius of petal
            double petalRadius;
            // for calculating petal center
            double xPetalCtr_1, yPetalCtr_1, xPetalCtr_2, yPetalCtr_2, xPetalCtr, yPetalCtr, xMidOfShortestEdge, yMidOfShortestEdge;
            double dxcenter1, dycenter1, dxcenter2, dycenter2;
            // for finding neighbor
            Otri neighborotri = default(Otri);
            double[] thirdPoint = new double[2];
            //int neighborNotFound = -1;
            bool neighborNotFound;
            // for keeping the vertices of the neighbor triangle
            Vertex neighborvertex_1;
            Vertex neighborvertex_2;
            Vertex neighborvertex_3;
            // dummy variables 
            double xi_tmp = 0, eta_tmp = 0;
            //vertex thirdVertex;
            // for petal intersection
            double vector_x, vector_y, xMidOfLongestEdge, yMidOfLongestEdge, inter_x, inter_y;
            double[] p = new double[5], voronoiOrInter = new double[4];
            bool isCorrect;

            // for vector calculations in perturbation
            double ax, ay, d;
            double pertConst = 0.06; // perturbation constant

            double lengthConst = 1; // used at comparing circumcenter's distance to proposed point's distance
            double justAcute = 1; // used for making the program working for one direction only
            // for smoothing
            int relocated = 0;// used to differentiate between calling the deletevertex and just proposing a steiner point
            double[] newloc = new double[2];   // new location suggested by smoothing
            double origin_x = 0, origin_y = 0; // for keeping torg safe
            Otri delotri; // keeping the original orientation for relocation process
            // keeps the first and second direction suggested points
            double dxFirstSuggestion, dyFirstSuggestion, dxSecondSuggestion, dySecondSuggestion;
            // second direction variables
            double xMidOfMiddleEdge, yMidOfMiddleEdge;
            ////////////////////////////// END OF HALE'S VARIABLES //////////////////////////////

            Statistic.CircumcenterCount++;

            // Compute the circumcenter of the triangle.
            xdo = tdest.x - torg.x;
            ydo = tdest.y - torg.y;
            xao = tapex.x - torg.x;
            yao = tapex.y - torg.y;
            xda = tapex.x - tdest.x;
            yda = tapex.y - tdest.y;
            // keeps the square of the distances
            dodist = xdo * xdo + ydo * ydo;
            aodist = xao * xao + yao * yao;
            dadist = (tdest.x - tapex.x) * (tdest.x - tapex.x) +
                (tdest.y - tapex.y) * (tdest.y - tapex.y);
            // checking if the user wanted exact arithmetic or not
            if (Behavior.NoExact)
            {
                denominator = 0.5 / (xdo * yao - xao * ydo);
            }
            else
            {
                // Use the counterclockwise() routine to ensure a positive (and
                //   reasonably accurate) result, avoiding any possibility of
                //   division by zero.
                denominator = 0.5 / predicates.CounterClockwise(tdest, tapex, torg);
                // Don't count the above as an orientation test.
                Statistic.CounterClockwiseCount--;
            }
            // calculate the circumcenter in terms of distance to origin point 
            dx = (yao * dodist - ydo * aodist) * denominator;
            dy = (xdo * aodist - xao * dodist) * denominator;
            // for debugging and for keeping circumcenter to use later
            // coordinate value of the circumcenter
            myCircumcenter = new Point(torg.x + dx, torg.y + dy);

            delotri = badotri; // save for later
            ///////////////// FINDING THE ORIENTATION OF TRIANGLE //////////////////
            // Find the (squared) length of the triangle's shortest edge.  This
            //   serves as a conservative estimate of the insertion radius of the
            //   circumcenter's parent.  The estimate is used to ensure that
            //   the algorithm terminates even if very small angles appear in
            //   the input PSLG. 						
            // find the orientation of the triangle, basically shortest and longest edges
            orientation = LongestShortestEdge(aodist, dadist, dodist);
            //printf("org: (%f,%f), dest: (%f,%f), apex: (%f,%f)\n",torg[0],torg[1],tdest[0],tdest[1],tapex[0],tapex[1]);
            /////////////////////////////////////////////////////////////////////////////////////////////
            // 123: shortest: aodist	// 213: shortest: dadist	// 312: shortest: dodist   //	
            //	middle: dadist 		//	middle: aodist 		//	middle: aodist     //
            //	longest: dodist		//	longest: dodist		//	longest: dadist    //
            // 132: shortest: aodist 	// 231: shortest: dadist 	// 321: shortest: dodist   //
            //	middle: dodist 		//	middle: dodist 		//	middle: dadist     //
            //	longest: dadist		//	longest: aodist		//	longest: aodist    //
            /////////////////////////////////////////////////////////////////////////////////////////////

            switch (orientation)
            {
                case 123: 	// assign necessary information
                    /// smallest angle corner: dest
                    /// largest angle corner: apex
                    xShortestEdge = xao; yShortestEdge = yao;
                    xMiddleEdge = xda; yMiddleEdge = yda;
                    xLongestEdge = xdo; yLongestEdge = ydo;

                    shortestEdgeDist = aodist;
                    middleEdgeDist = dadist;
                    longestEdgeDist = dodist;

                    smallestAngleCorner = tdest;
                    middleAngleCorner = torg;
                    largestAngleCorner = tapex;
                    break;

                case 132: 	// assign necessary information
                    /// smallest angle corner: dest
                    /// largest angle corner: org
                    xShortestEdge = xao; yShortestEdge = yao;
                    xMiddleEdge = xdo; yMiddleEdge = ydo;
                    xLongestEdge = xda; yLongestEdge = yda;

                    shortestEdgeDist = aodist;
                    middleEdgeDist = dodist;
                    longestEdgeDist = dadist;

                    smallestAngleCorner = tdest;
                    middleAngleCorner = tapex;
                    largestAngleCorner = torg;

                    break;
                case 213: 	// assign necessary information
                    /// smallest angle corner: org
                    /// largest angle corner: apex
                    xShortestEdge = xda; yShortestEdge = yda;
                    xMiddleEdge = xao; yMiddleEdge = yao;
                    xLongestEdge = xdo; yLongestEdge = ydo;

                    shortestEdgeDist = dadist;
                    middleEdgeDist = aodist;
                    longestEdgeDist = dodist;

                    smallestAngleCorner = torg;
                    middleAngleCorner = tdest;
                    largestAngleCorner = tapex;
                    break;
                case 231: 	// assign necessary information
                    /// smallest angle corner: org
                    /// largest angle corner: dest
                    xShortestEdge = xda; yShortestEdge = yda;
                    xMiddleEdge = xdo; yMiddleEdge = ydo;
                    xLongestEdge = xao; yLongestEdge = yao;

                    shortestEdgeDist = dadist;
                    middleEdgeDist = dodist;
                    longestEdgeDist = aodist;

                    smallestAngleCorner = torg;
                    middleAngleCorner = tapex;
                    largestAngleCorner = tdest;
                    break;
                case 312: 	// assign necessary information
                    /// smallest angle corner: apex
                    /// largest angle corner: org
                    xShortestEdge = xdo; yShortestEdge = ydo;
                    xMiddleEdge = xao; yMiddleEdge = yao;
                    xLongestEdge = xda; yLongestEdge = yda;

                    shortestEdgeDist = dodist;
                    middleEdgeDist = aodist;
                    longestEdgeDist = dadist;

                    smallestAngleCorner = tapex;
                    middleAngleCorner = tdest;
                    largestAngleCorner = torg;
                    break;
                case 321: 	// assign necessary information
                default: // TODO: is this safe?
                    /// smallest angle corner: apex
                    /// largest angle corner: dest
                    xShortestEdge = xdo; yShortestEdge = ydo;
                    xMiddleEdge = xda; yMiddleEdge = yda;
                    xLongestEdge = xao; yLongestEdge = yao;

                    shortestEdgeDist = dodist;
                    middleEdgeDist = dadist;
                    longestEdgeDist = aodist;

                    smallestAngleCorner = tapex;
                    middleAngleCorner = torg;
                    largestAngleCorner = tdest;
                    break;

            }// end of switch	
            // check for offcenter condition
            if (offcenter && (offconstant > 0.0))
            {
                // origin has the smallest angle
                if (orientation == 213 || orientation == 231)
                {
                    // Find the position of the off-center, as described by Alper Ungor.
                    dxoff = 0.5 * xShortestEdge - offconstant * yShortestEdge;
                    dyoff = 0.5 * yShortestEdge + offconstant * xShortestEdge;
                    // If the off-center is closer to destination than the
                    //   circumcenter, use the off-center instead.
                    /// doubleLY BAD CASE ///			
                    if (dxoff * dxoff + dyoff * dyoff <
                        (dx - xdo) * (dx - xdo) + (dy - ydo) * (dy - ydo))
                    {
                        dx = xdo + dxoff;
                        dy = ydo + dyoff;
                    }
                    /// ALMOST GOOD CASE ///
                    else
                    {
                        almostGood = 1;
                    }
                    // destination has the smallest angle	
                }
                else if (orientation == 123 || orientation == 132)
                {
                    // Find the position of the off-center, as described by Alper Ungor.
                    dxoff = 0.5 * xShortestEdge + offconstant * yShortestEdge;
                    dyoff = 0.5 * yShortestEdge - offconstant * xShortestEdge;
                    // If the off-center is closer to the origin than the
                    //   circumcenter, use the off-center instead.
                    /// doubleLY BAD CASE ///
                    if (dxoff * dxoff + dyoff * dyoff < dx * dx + dy * dy)
                    {
                        dx = dxoff;
                        dy = dyoff;
                    }
                    /// ALMOST GOOD CASE ///		
                    else
                    {
                        almostGood = 1;
                    }
                    // apex has the smallest angle	
                }
                else
                {//orientation == 312 || orientation == 321 
                    // Find the position of the off-center, as described by Alper Ungor.
                    dxoff = 0.5 * xShortestEdge - offconstant * yShortestEdge;
                    dyoff = 0.5 * yShortestEdge + offconstant * xShortestEdge;
                    // If the off-center is closer to the origin than the
                    //   circumcenter, use the off-center instead.
                    /// doubleLY BAD CASE ///
                    if (dxoff * dxoff + dyoff * dyoff < dx * dx + dy * dy)
                    {
                        dx = dxoff;
                        dy = dyoff;
                    }
                    /// ALMOST GOOD CASE ///		
                    else
                    {
                        almostGood = 1;
                    }
                }
            }
            // if the bad triangle is almost good, apply our approach
            if (almostGood == 1)
            {

                /// calculate cosine of largest angle	///	
                cosMaxAngle = (middleEdgeDist + shortestEdgeDist - longestEdgeDist) / (2 * Math.Sqrt(middleEdgeDist) * Math.Sqrt(shortestEdgeDist));
                if (cosMaxAngle < 0.0)
                {
                    // obtuse
                    isObtuse = true;
                }
                else if (Math.Abs(cosMaxAngle - 0.0) <= EPS)
                {
                    // right triangle (largest angle is 90 degrees)
                    isObtuse = true;
                }
                else
                {
                    // nonobtuse
                    isObtuse = false;
                }
                /// RELOCATION	(LOCAL SMOOTHING) ///
                /// check for possible relocation of one of triangle's points ///				
                relocated = DoSmoothing(delotri, torg, tdest, tapex, ref newloc);
                /// if relocation is possible, delete that vertex and insert a vertex at the new location ///		
                if (relocated > 0)
                {
                    Statistic.RelocationCount++;

                    dx = newloc[0] - torg.x;
                    dy = newloc[1] - torg.y;
                    origin_x = torg.x;	// keep for later use
                    origin_y = torg.y;
                    switch (relocated)
                    {
                        case 1:
                            //printf("Relocate: (%f,%f)\n", torg[0],torg[1]);			
                            mesh.DeleteVertex(ref delotri);
                            break;
                        case 2:
                            //printf("Relocate: (%f,%f)\n", tdest[0],tdest[1]);			
                            delotri.Lnext();
                            mesh.DeleteVertex(ref delotri);
                            break;
                        case 3:
                            //printf("Relocate: (%f,%f)\n", tapex[0],tapex[1]);						
                            delotri.Lprev();
                            mesh.DeleteVertex(ref delotri);
                            break;

                    }
                }
                else
                {
                    // calculate radius of the petal according to angle constraint
                    // first find the visible region, PETAL
                    // find the center of the circle and radius
                    petalRadius = Math.Sqrt(shortestEdgeDist) / (2 * Math.Sin(behavior.MinAngle * Math.PI / 180.0));
                    /// compute two possible centers of the petal ///
                    // finding the center
                    // first find the middle point of smallest edge
                    xMidOfShortestEdge = (middleAngleCorner.x + largestAngleCorner.x) / 2.0;
                    yMidOfShortestEdge = (middleAngleCorner.y + largestAngleCorner.y) / 2.0;
                    // two possible centers
                    xPetalCtr_1 = xMidOfShortestEdge + Math.Sqrt(petalRadius * petalRadius - (shortestEdgeDist / 4)) * (middleAngleCorner.y -
                        largestAngleCorner.y) / Math.Sqrt(shortestEdgeDist);
                    yPetalCtr_1 = yMidOfShortestEdge + Math.Sqrt(petalRadius * petalRadius - (shortestEdgeDist / 4)) * (largestAngleCorner.x -
                        middleAngleCorner.x) / Math.Sqrt(shortestEdgeDist);

                    xPetalCtr_2 = xMidOfShortestEdge - Math.Sqrt(petalRadius * petalRadius - (shortestEdgeDist / 4)) * (middleAngleCorner.y -
                        largestAngleCorner.y) / Math.Sqrt(shortestEdgeDist);
                    yPetalCtr_2 = yMidOfShortestEdge - Math.Sqrt(petalRadius * petalRadius - (shortestEdgeDist / 4)) * (largestAngleCorner.x -
                        middleAngleCorner.x) / Math.Sqrt(shortestEdgeDist);
                    // find the correct circle since there will be two possible circles
                    // calculate the distance to smallest angle corner
                    dxcenter1 = (xPetalCtr_1 - smallestAngleCorner.x) * (xPetalCtr_1 - smallestAngleCorner.x);
                    dycenter1 = (yPetalCtr_1 - smallestAngleCorner.y) * (yPetalCtr_1 - smallestAngleCorner.y);
                    dxcenter2 = (xPetalCtr_2 - smallestAngleCorner.x) * (xPetalCtr_2 - smallestAngleCorner.x);
                    dycenter2 = (yPetalCtr_2 - smallestAngleCorner.y) * (yPetalCtr_2 - smallestAngleCorner.y);

                    // whichever is closer to smallest angle corner, it must be the center
                    if (dxcenter1 + dycenter1 <= dxcenter2 + dycenter2)
                    {
                        xPetalCtr = xPetalCtr_1; yPetalCtr = yPetalCtr_1;
                    }
                    else
                    {
                        xPetalCtr = xPetalCtr_2; yPetalCtr = yPetalCtr_2;
                    }

                    /// find the third point of the neighbor triangle  ///
                    neighborNotFound = GetNeighborsVertex(badotri, middleAngleCorner.x, middleAngleCorner.y,
                                smallestAngleCorner.x, smallestAngleCorner.y, ref thirdPoint, ref neighborotri);
                    /// find the circumcenter of the neighbor triangle ///
                    dxFirstSuggestion = dx;	// if we cannot find any appropriate suggestion, we use circumcenter
                    dyFirstSuggestion = dy;
                    // if there is a neighbor triangle
                    if (!neighborNotFound)
                    {
                        neighborvertex_1 = neighborotri.Org();
                        neighborvertex_2 = neighborotri.Dest();
                        neighborvertex_3 = neighborotri.Apex();
                        // now calculate neighbor's circumcenter which is the voronoi site
                        neighborCircumcenter = predicates.FindCircumcenter(neighborvertex_1, neighborvertex_2, neighborvertex_3,
                            ref xi_tmp, ref eta_tmp);

                        /// compute petal and Voronoi edge intersection ///
                        // in order to avoid degenerate cases, we need to do a vector based calculation for line		
                        vector_x = (middleAngleCorner.y - smallestAngleCorner.y);//(-y, x)
                        vector_y = smallestAngleCorner.x - middleAngleCorner.x;
                        vector_x = myCircumcenter.x + vector_x;
                        vector_y = myCircumcenter.y + vector_y;


                        // by intersecting bisectors you will end up with the one you want to walk on
                        // then this line and circle should be intersected
                        CircleLineIntersection(myCircumcenter.x, myCircumcenter.y, vector_x, vector_y,
                                xPetalCtr, yPetalCtr, petalRadius, ref p);
                        /// choose the correct intersection point ///
                        // calculate middle point of the longest edge(bisector)
                        xMidOfLongestEdge = (middleAngleCorner.x + smallestAngleCorner.x) / 2.0;
                        yMidOfLongestEdge = (middleAngleCorner.y + smallestAngleCorner.y) / 2.0;
                        // we need to find correct intersection point, since line intersects circle twice
                        isCorrect = ChooseCorrectPoint(xMidOfLongestEdge, yMidOfLongestEdge, p[3], p[4],
                                    myCircumcenter.x, myCircumcenter.y, isObtuse);
                        // make sure which point is the correct one to be considered
                        if (isCorrect)
                        {
                            inter_x = p[3];
                            inter_y = p[4];
                        }
                        else
                        {
                            inter_x = p[1];
                            inter_y = p[2];
                        }
                        /// check if there is a Voronoi vertex between before intersection ///
                        // check if the voronoi vertex is between the intersection and circumcenter
                        PointBetweenPoints(inter_x, inter_y, myCircumcenter.x, myCircumcenter.y,
                                neighborCircumcenter.x, neighborCircumcenter.y, ref voronoiOrInter);

                        /// determine the point to be suggested ///
                        if (p[0] > 0.0)
                        { // there is at least one intersection point
                            // if it is between circumcenter and intersection	
                            // if it returns 1.0 this means we have a voronoi vertex within feasible region
                            if (Math.Abs(voronoiOrInter[0] - 1.0) <= EPS)
                            {
                                if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, neighborCircumcenter.x, neighborCircumcenter.y))
                                {
                                    // go back to circumcenter
                                    dxFirstSuggestion = dx;
                                    dyFirstSuggestion = dy;

                                }
                                else
                                { // we are not creating a bad triangle
                                    // neighbor's circumcenter is suggested
                                    dxFirstSuggestion = voronoiOrInter[2] - torg.x;
                                    dyFirstSuggestion = voronoiOrInter[3] - torg.y;
                                }

                            }
                            else
                            { // there is no voronoi vertex between intersection point and circumcenter
                                if (IsBadTriangleAngle(largestAngleCorner.x, largestAngleCorner.y, middleAngleCorner.x, middleAngleCorner.y, inter_x, inter_y))
                                {
                                    // if it is inside feasible region, then insert v2				
                                    // apply perturbation
                                    // find the distance between circumcenter and intersection point
                                    d = Math.Sqrt((inter_x - myCircumcenter.x) * (inter_x - myCircumcenter.x) +
                                        (inter_y - myCircumcenter.y) * (inter_y - myCircumcenter.y));
                                    // then find the vector going from intersection point to circumcenter
                                    ax = myCircumcenter.x - inter_x;
                                    ay = myCircumcenter.y - inter_y;

                                    ax = ax / d;
                                    ay = ay / d;
                                    // now calculate the new intersection point which is perturbated towards the circumcenter
                                    inter_x = inter_x + ax * pertConst * Math.Sqrt(shortestEdgeDist);
                                    inter_y = inter_y + ay * pertConst * Math.Sqrt(shortestEdgeDist);
                                    if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, inter_x, inter_y))
                                    {
                                        // go back to circumcenter
                                        dxFirstSuggestion = dx;
                                        dyFirstSuggestion = dy;

                                    }
                                    else
                                    {
                                        // intersection point is suggested
                                        dxFirstSuggestion = inter_x - torg.x;
                                        dyFirstSuggestion = inter_y - torg.y;

                                    }
                                }
                                else
                                {
                                    // intersection point is suggested
                                    dxFirstSuggestion = inter_x - torg.x;
                                    dyFirstSuggestion = inter_y - torg.y;
                                }
                            }
                            /// if it is an acute triangle, check if it is a good enough location ///
                            // for acute triangle case, we need to check if it is ok to use either of them
                            if ((smallestAngleCorner.x - myCircumcenter.x) * (smallestAngleCorner.x - myCircumcenter.x) +
                                (smallestAngleCorner.y - myCircumcenter.y) * (smallestAngleCorner.y - myCircumcenter.y) >
                                lengthConst * ((smallestAngleCorner.x - (dxFirstSuggestion + torg.x)) *
                                        (smallestAngleCorner.x - (dxFirstSuggestion + torg.x)) +
                                        (smallestAngleCorner.y - (dyFirstSuggestion + torg.y)) *
                                        (smallestAngleCorner.y - (dyFirstSuggestion + torg.y))))
                            {
                                // use circumcenter
                                dxFirstSuggestion = dx;
                                dyFirstSuggestion = dy;
                            }// else we stick to what we have found	
                        }// intersection point

                    }// if it is on the boundary, meaning no neighbor triangle in this direction, try other direction	

                    /// DO THE SAME THING FOR THE OTHER DIRECTION ///
                    /// find the third point of the neighbor triangle  ///
                    neighborNotFound = GetNeighborsVertex(badotri, largestAngleCorner.x, largestAngleCorner.y,
                                smallestAngleCorner.x, smallestAngleCorner.y, ref thirdPoint, ref neighborotri);
                    /// find the circumcenter of the neighbor triangle ///
                    dxSecondSuggestion = dx;	// if we cannot find any appropriate suggestion, we use circumcenter
                    dySecondSuggestion = dy;
                    // if there is a neighbor triangle
                    if (!neighborNotFound)
                    {
                        neighborvertex_1 = neighborotri.Org();
                        neighborvertex_2 = neighborotri.Dest();
                        neighborvertex_3 = neighborotri.Apex();
                        // now calculate neighbor's circumcenter which is the voronoi site
                        neighborCircumcenter = predicates.FindCircumcenter(neighborvertex_1, neighborvertex_2, neighborvertex_3,
                            ref xi_tmp, ref eta_tmp);

                        /// compute petal and Voronoi edge intersection ///
                        // in order to avoid degenerate cases, we need to do a vector based calculation for line		
                        vector_x = (largestAngleCorner.y - smallestAngleCorner.y);//(-y, x)
                        vector_y = smallestAngleCorner.x - largestAngleCorner.x;
                        vector_x = myCircumcenter.x + vector_x;
                        vector_y = myCircumcenter.y + vector_y;


                        // by intersecting bisectors you will end up with the one you want to walk on
                        // then this line and circle should be intersected
                        CircleLineIntersection(myCircumcenter.x, myCircumcenter.y, vector_x, vector_y,
                                xPetalCtr, yPetalCtr, petalRadius, ref p);

                        /// choose the correct intersection point ///
                        // calcuwedgeslate middle point of the longest edge(bisector)
                        xMidOfMiddleEdge = (largestAngleCorner.x + smallestAngleCorner.x) / 2.0;
                        yMidOfMiddleEdge = (largestAngleCorner.y + smallestAngleCorner.y) / 2.0;
                        // we need to find correct intersection point, since line intersects circle twice
                        // this direction is always ACUTE
                        isCorrect = ChooseCorrectPoint(xMidOfMiddleEdge, yMidOfMiddleEdge, p[3], p[4],
                                    myCircumcenter.x, myCircumcenter.y, false/*(isObtuse+1)%2*/);
                        // make sure which point is the correct one to be considered
                        if (isCorrect)
                        {
                            inter_x = p[3];
                            inter_y = p[4];
                        }
                        else
                        {
                            inter_x = p[1];
                            inter_y = p[2];
                        }

                        /// check if there is a Voronoi vertex between before intersection ///
                        // check if the voronoi vertex is between the intersection and circumcenter
                        PointBetweenPoints(inter_x, inter_y, myCircumcenter.x, myCircumcenter.y,
                                neighborCircumcenter.x, neighborCircumcenter.y, ref voronoiOrInter);

                        /// determine the point to be suggested ///
                        if (p[0] > 0.0)
                        { // there is at least one intersection point
                            // if it is between circumcenter and intersection	
                            // if it returns 1.0 this means we have a voronoi vertex within feasible region
                            if (Math.Abs(voronoiOrInter[0] - 1.0) <= EPS)
                            {
                                if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, neighborCircumcenter.x, neighborCircumcenter.y))
                                {
                                    // go back to circumcenter
                                    dxSecondSuggestion = dx;
                                    dySecondSuggestion = dy;

                                }
                                else
                                { // we are not creating a bad triangle
                                    // neighbor's circumcenter is suggested
                                    dxSecondSuggestion = voronoiOrInter[2] - torg.x;
                                    dySecondSuggestion = voronoiOrInter[3] - torg.y;

                                }

                            }
                            else
                            { // there is no voronoi vertex between intersection point and circumcenter
                                if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, inter_x, inter_y))
                                {
                                    // if it is inside feasible region, then insert v2				
                                    // apply perturbation
                                    // find the distance between circumcenter and intersection point
                                    d = Math.Sqrt((inter_x - myCircumcenter.x) * (inter_x - myCircumcenter.x) +
                                        (inter_y - myCircumcenter.y) * (inter_y - myCircumcenter.y));
                                    // then find the vector going from intersection point to circumcenter
                                    ax = myCircumcenter.x - inter_x;
                                    ay = myCircumcenter.y - inter_y;

                                    ax = ax / d;
                                    ay = ay / d;
                                    // now calculate the new intersection point which is perturbated towards the circumcenter
                                    inter_x = inter_x + ax * pertConst * Math.Sqrt(shortestEdgeDist);
                                    inter_y = inter_y + ay * pertConst * Math.Sqrt(shortestEdgeDist);
                                    if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, inter_x, inter_y))
                                    {
                                        // go back to circumcenter
                                        dxSecondSuggestion = dx;
                                        dySecondSuggestion = dy;

                                    }
                                    else
                                    {
                                        // intersection point is suggested
                                        dxSecondSuggestion = inter_x - torg.x;
                                        dySecondSuggestion = inter_y - torg.y;
                                    }
                                }
                                else
                                {

                                    // intersection point is suggested
                                    dxSecondSuggestion = inter_x - torg.x;
                                    dySecondSuggestion = inter_y - torg.y;
                                }
                            }
                            /// if it is an acute triangle, check if it is a good enough location ///
                            // for acute triangle case, we need to check if it is ok to use either of them
                            if ((smallestAngleCorner.x - myCircumcenter.x) * (smallestAngleCorner.x - myCircumcenter.x) +
                                (smallestAngleCorner.y - myCircumcenter.y) * (smallestAngleCorner.y - myCircumcenter.y) >
                                lengthConst * ((smallestAngleCorner.x - (dxSecondSuggestion + torg.x)) *
                                        (smallestAngleCorner.x - (dxSecondSuggestion + torg.x)) +
                                        (smallestAngleCorner.y - (dySecondSuggestion + torg.y)) *
                                        (smallestAngleCorner.y - (dySecondSuggestion + torg.y))))
                            {
                                // use circumcenter
                                dxSecondSuggestion = dx;
                                dySecondSuggestion = dy;
                            }// else we stick on what we have found	
                        }
                    }// if it is on the boundary, meaning no neighbor triangle in this direction, the other direction might be ok		
                    if (isObtuse)
                    {
                        //obtuse: do nothing					
                        dx = dxFirstSuggestion;
                        dy = dyFirstSuggestion;
                    }
                    else
                    { // acute : consider other direction				
                        if (justAcute * ((smallestAngleCorner.x - (dxSecondSuggestion + torg.x)) *
                                (smallestAngleCorner.x - (dxSecondSuggestion + torg.x)) +
                                (smallestAngleCorner.y - (dySecondSuggestion + torg.y)) *
                                (smallestAngleCorner.y - (dySecondSuggestion + torg.y))) >
                                (smallestAngleCorner.x - (dxFirstSuggestion + torg.x)) *
                                (smallestAngleCorner.x - (dxFirstSuggestion + torg.x)) +
                                (smallestAngleCorner.y - (dyFirstSuggestion + torg.y)) *
                                (smallestAngleCorner.y - (dyFirstSuggestion + torg.y)))
                        {
                            dx = dxSecondSuggestion;
                            dy = dySecondSuggestion;
                        }
                        else
                        {
                            dx = dxFirstSuggestion;
                            dy = dyFirstSuggestion;
                        }

                    }// end if obtuse
                }// end of relocation				 
            }// end of almostGood	

            Point circumcenter = new Point();

            if (relocated <= 0)
            {
                circumcenter.x = torg.x + dx;
                circumcenter.y = torg.y + dy;
            }
            else
            {
                circumcenter.x = origin_x + dx;
                circumcenter.y = origin_y + dy;
            }

            xi = (yao * dx - xao * dy) * (2.0 * denominator);
            eta = (xdo * dy - ydo * dx) * (2.0 * denominator);

            return circumcenter;
        }
Ejemplo n.º 29
0
 /// <summary>
 /// Set Apex
 /// </summary>
 internal void SetApex(Vertex v)
 {
     tri.vertices[orient] = v;
 }
Ejemplo n.º 30
0
 /// <summary>
 /// Set the destination of the segment that includes the subsegment.
 /// </summary>
 internal void SetSegDest(Vertex vertex)
 {
     seg.vertices[3 - orient] = vertex;
 }
Ejemplo n.º 31
0
    void GenMap()
    {
        /*
         *  <settings>
         */
        int starsAm = 10000;

        // What percentage of space is taken up by stars.
        int starDensity = 20;

        // Minimal corridor length relative to maximal star size.
        float minCorridorLengthCoeff = 3.0f;

        // What percentage of space is taken up by corridors.
        int corridorDensity = 60;

        float maxz = 3.0f;

        /*
         *  </settings>
         */

        float max_star_size = Mathf.Max(pos_star_sizes);

        Debug.Log("Max star size: " + max_star_size);
        float min_corridor_length         = max_star_size * minCorridorLengthCoeff;
        float min_corridor_length_squared = Mathf.Pow(min_corridor_length, 2);

        int starsx = Mathf.RoundToInt(Mathf.Sqrt(starsAm));
        int starsy = starsx;

        float width  = (starsx * max_star_size) + ((starsx - 1) * min_corridor_length);
        float height = (starsy * max_star_size) + ((starsy - 1) * min_corridor_length);

        background.transform.localScale = new Vector3(width * 0.11f, 1.0f, height * 0.11f);
        background.GetComponent <MeshRenderer>().material.SetTextureScale("_MainTex", new Vector2(width / 70.0f, height / 70.0f));

        Debug.Log("Dimensions: " + width + ", " + height);

        float minx = width * -0.5f;
        float miny = height * -0.5f;

        float maxx = width * 0.5f;
        float maxy = height * 0.5f;

        float max_offset_x = (width / starsx) - ((min_corridor_length - max_star_size) * 0.5f);
        float max_offset_y = (height / starsy) - ((min_corridor_length - max_star_size) * 0.5f);

        Debug.Log("Offsets: " + max_offset_x + ", " + max_offset_y);

        Rectangle bounds = new Rectangle(minx, miny, width, height);

        TriangleNet.Mesh mesh = (TriangleNet.Mesh)GenericMesher.StructuredMesh(bounds, starsx - 1, starsy - 1);

        List <TriangleNet.Geometry.Vertex> stars = new List <TriangleNet.Geometry.Vertex>();

        List <TriangleNet.Geometry.Vertex> shuffled_verts = new List <TriangleNet.Geometry.Vertex>(mesh.Vertices);

        shuffled_verts.Shuffle();

        int stars_amount = 0;

        foreach (TriangleNet.Geometry.Vertex v in shuffled_verts)
        {
            if (stars_amount > 3 && Random.Range(0, 101) > starDensity)
            {
                continue;
            }
            stars.Add(v);
            stars_amount++;
        }
        GenericMesher gm = new GenericMesher(new SweepLine());

        mesh = (TriangleNet.Mesh)gm.Triangulate(stars);

        StandardVoronoi sv = new StandardVoronoi(mesh);

        Polygon final = new Polygon(sv.Vertices.Count);

        Dictionary <int, TriangleNet.Geometry.Vertex> good_stars = new Dictionary <int, TriangleNet.Geometry.Vertex>();
        Dictionary <int, int> bad2goodstar  = new Dictionary <int, int>();
        List <int>            outBoundStars = new List <int>();

        foreach (TriangleNet.Topology.DCEL.Vertex v in sv.Vertices)
        {
            if (v.x < minx || v.x > maxx || v.y < miny || v.y > maxy)
            {
                outBoundStars.Add(v.id);
                continue;
            }

            bool invalid = false;
            foreach (TriangleNet.Geometry.Vertex other in good_stars.Values)
            {
                Vector2 v1 = new Vector2((float)v.x, (float)v.y);
                Vector2 v2 = new Vector2((float)other.x, (float)other.y);

                if ((v2 - v1).sqrMagnitude < min_corridor_length_squared)
                {
                    invalid = true;

                    bad2goodstar[v.id] = other.id;
                }
            }

            if (invalid)
            {
                continue;
            }

            TriangleNet.Geometry.Vertex new_v = new TriangleNet.Geometry.Vertex(v.x, v.y);
            new_v.id         = v.id;
            good_stars[v.id] = new_v;
            final.Add(new_v);
        }

        List <Segment> good_segments = new List <Segment>();

        foreach (Edge e in sv.Edges)
        {
            if (outBoundStars.Contains(e.P0) || outBoundStars.Contains(e.P1))
            {
                continue;
            }

            int P0_id;
            int P1_id;

            if (bad2goodstar.ContainsKey(e.P0))
            {
                P0_id = bad2goodstar[e.P0];
            }
            else
            {
                P0_id = e.P0;
            }

            if (bad2goodstar.ContainsKey(e.P1))
            {
                P1_id = bad2goodstar[e.P1];
            }
            else
            {
                P1_id = e.P1;
            }

            if (P0_id == P1_id)
            {
                continue;
            }

            good_segments.Add(new Segment(good_stars[P0_id], good_stars[P1_id]));
        }

        Dictionary <int, List <int> > connected_stars = new Dictionary <int, List <int> >();

        foreach (Segment s in good_segments)
        {
            if (!connected_stars.ContainsKey(s.P0))
            {
                connected_stars[s.P0] = new List <int>();
            }
            connected_stars[s.P0].Add(s.P1);

            if (!connected_stars.ContainsKey(s.P1))
            {
                connected_stars[s.P1] = new List <int>();
            }
            connected_stars[s.P1].Add(s.P0);
        }

        Debug.Log("Currently edges: " + good_segments.Count);

        List <Segment> temp_segments = new List <Segment>(good_segments);

        temp_segments.Shuffle();

        foreach (Segment s in temp_segments)
        {
            if (Random.Range(0, 101) > corridorDensity && RemovalConnectionsCheck(connected_stars, s.P0, s.P1))
            {
                connected_stars[s.P0].Remove(s.P1);
                connected_stars[s.P1].Remove(s.P0);
                good_segments.Remove(s);
            }
        }

        foreach (Segment s in good_segments)
        {
            final.Add(s);
        }

        Debug.Log("Stars after everything: " + final.Points.Count);
        Debug.Log("Corridors after everything: " + good_segments.Count);
        CreateMap(final, maxz, 0.0f);
    }
Ejemplo n.º 32
0
    public static Mesh GetTriangulationMesh(Vector3[] verts, HashSet <int> borderVerts, Polygon boundary)
    {
        TriangleNet.Geometry.Polygon polygon = new TriangleNet.Geometry.Polygon();
        //Dictionary<TriangleNet.Geometry.Vertex, float> vertexElevMap = new Dictionary<TriangleNet.Geometry.Vertex, float>();
        foreach (Vector3 vert in verts)
        {
            TriangleNet.Geometry.Vertex triangulationVert = new TriangleNet.Geometry.Vertex(vert.x, vert.z);
            //vertexElevMap.Add(triangulationVert, vert.y);
            polygon.Add(triangulationVert);
        }

        TriangleNet.Meshing.ConstraintOptions options =
            new TriangleNet.Meshing.ConstraintOptions()
        {
            ConformingDelaunay = true
        };
        TriangleNet.Meshing.GenericMesher mesher = new TriangleNet.Meshing.GenericMesher();
        TriangleNet.Meshing.IMesh         mesh   = mesher.Triangulate(polygon);

        Vector3[]  meshVerts     = new Vector3[mesh.Vertices.Count];
        List <int> meshTriangles = new List <int>();

        Dictionary <TriangleNet.Geometry.Vertex, int> vertexIndexMap = new Dictionary <TriangleNet.Geometry.Vertex, int>();

        int v = 0;

        foreach (TriangleNet.Geometry.Vertex triangulatorVert in mesh.Vertices)
        {
            meshVerts[v] = new Vector3((float)triangulatorVert.X, verts[v].y, (float)triangulatorVert.Y);
            vertexIndexMap[triangulatorVert] = v;
            v++;
        }
        //for (int i = 0; i < vertexList.Length; i ++)
        //{
        //    TriangleNet.Geometry.Vertex triangulatorVert = vertexList[i];
        //    meshVerts[i] = new Vector3((float)triangulatorVert.X, vertexElevMap[triangulatorVert], (float)triangulatorVert.Y);
        //    vertexIndexMap[triangulatorVert] = i;
        //}

        foreach (TriangleNet.Topology.Triangle tri in mesh.Triangles)
        {
            int     ind1   = vertexIndexMap[tri.GetVertex(0)];
            int     ind2   = vertexIndexMap[tri.GetVertex(2)];
            int     ind3   = vertexIndexMap[tri.GetVertex(1)];
            Vector2 center = new Vector2((float)(tri.GetVertex(0).X + tri.GetVertex(1).X + tri.GetVertex(2).X) / 3f, (float)(tri.GetVertex(0).Y + tri.GetVertex(1).Y + tri.GetVertex(2).Y) / 3f);

            if (!(borderVerts.Contains(ind1) && borderVerts.Contains(ind2) && borderVerts.Contains(ind3)) || (boundary.ContainsPoint(center) && !boundary.PermiterContainsPoint(center)))
            {
                meshTriangles.Add(ind1);
                meshTriangles.Add(ind2);
                meshTriangles.Add(ind3);
            }
        }

        Mesh unityMesh = new Mesh();

        unityMesh.vertices  = meshVerts;
        unityMesh.triangles = meshTriangles.ToArray();
        unityMesh.RecalculateBounds();
        unityMesh.RecalculateNormals();
        return(unityMesh);
    }
Ejemplo n.º 33
0
 /// <summary>
 /// Deallocate space for a vertex, marking it dead.
 /// </summary>
 /// <param name="dyingvertex"></param>
 internal void VertexDealloc(Vertex dyingvertex)
 {
     // Mark the vertex as dead. This makes it possible to detect dead 
     // vertices when traversing the list of all vertices.
     dyingvertex.type = VertexType.DeadVertex;
     vertices.Remove(dyingvertex.hash);
 }
Ejemplo n.º 34
0
        /// <summary>
        /// Checks if smothing is possible for a given bad triangle.
        /// </summary>
        /// <param name="badotri"></param>
        /// <param name="torg"></param>
        /// <param name="tdest"></param>
        /// <param name="tapex"></param>
        /// <param name="newloc">The new location for the point, if somothing is possible.</param>
        /// <returns>Returns 1, 2 or 3 if smoothing will work, 0 otherwise.</returns>
        private int DoSmoothing(Otri badotri, Vertex torg, Vertex tdest, Vertex tapex,
            ref double[] newloc)
        {

            int numpoints_p = 0;// keeps the number of points in a star of point p, q, r
            int numpoints_q = 0;
            int numpoints_r = 0;
            //int i;	
            double[] possibilities = new double[6];//there can be more than one possibilities
            int num_pos = 0; // number of possibilities
            int flag1 = 0, flag2 = 0, flag3 = 0;
            bool newLocFound = false;

            //vertex v1, v2, v3;	// for ccw test
            //double p1[2], p2[2], p3[2];
            //double temp[2];

            //********************* TRY TO RELOCATE POINT "p" ***************

            // get the surrounding points of p, so this gives us the triangles
            numpoints_p = GetStarPoints(badotri, torg, tdest, tapex, 1, ref points_p);
            // check if the points in counterclockwise order
            // 	p1[0] = points_p[0];  p1[1] = points_p[1];
            // 	p2[0] = points_p[2];  p2[1] = points_p[3];
            // 	p3[0] = points_p[4];  p3[1] = points_p[5];
            // 	v1 = (vertex)p1; v2 = (vertex)p2; v3 = (vertex)p3; 
            // 	if(counterclockwise(m,b,v1,v2,v3) < 0){
            // 		// reverse the order to ccw
            // 		for(i = 0; i < numpoints_p/2; i++){
            // 			temp[0] = points_p[2*i];	
            // 			temp[1] = points_p[2*i+1];
            // 			points_p[2*i] = points_p[2*(numpoints_p-1)-2*i];
            // 			points_p[2*i+1] = points_p[2*(numpoints_p-1)+1-2*i];
            // 			points_p[2*(numpoints_p-1)-2*i] = temp[0];
            // 			points_p[2*(numpoints_p-1)+1-2*i] = temp[1];
            // 		}
            // 	}
            // 	m.counterclockcount--;
            // INTERSECTION OF PETALS
            // first check whether the star angles are appropriate for relocation
            if (torg.type == VertexType.FreeVertex && numpoints_p != 0 && ValidPolygonAngles(numpoints_p, points_p))
            {
                //newLocFound = getPetalIntersection(m, b, numpoints_p, points_p, newloc);
                //newLocFound = getPetalIntersectionBruteForce(m, b,numpoints_p, points_p, newloc,torg[0],torg[1]);
                if (behavior.MaxAngle == 0.0)
                {
                    newLocFound = GetWedgeIntersectionWithoutMaxAngle(numpoints_p, points_p, ref newloc);
                }
                else
                {
                    newLocFound = GetWedgeIntersection(numpoints_p, points_p, ref newloc);
                }
                //printf("call petal intersection for p\n");
                // make sure the relocated point is a free vertex	
                if (newLocFound)
                {
                    possibilities[0] = newloc[0];// something found
                    possibilities[1] = newloc[1];
                    num_pos++;// increase the number of possibilities
                    flag1 = 1;
                }
            }

            //********************* TRY TO RELOCATE POINT "q" ***************		

            // get the surrounding points of q, so this gives us the triangles
            numpoints_q = GetStarPoints(badotri, torg, tdest, tapex, 2, ref points_q);
            // 	// check if the points in counterclockwise order
            // 	v1[0] = points_q[0];  v1[1] = points_q[1];
            // 	v2[0] = points_q[2];  v2[1] = points_q[3];
            // 	v3[0] = points_q[4];  v3[1] = points_q[5];
            // 	if(counterclockwise(m,b,v1,v2,v3) < 0){
            // 		// reverse the order to ccw
            // 		for(i = 0; i < numpoints_q/2; i++){
            // 			temp[0] = points_q[2*i];	
            // 			temp[1] = points_q[2*i+1];
            // 			points_q[2*i] = points_q[2*(numpoints_q-1)-2*i];
            // 			points_q[2*i+1] = points_q[2*(numpoints_q-1)+1-2*i];
            // 			points_q[2*(numpoints_q-1)-2*i] = temp[0];
            // 			points_q[2*(numpoints_q-1)+1-2*i] = temp[1];
            // 		}
            // 	}
            // 	m.counterclockcount--;
            // INTERSECTION OF PETALS
            // first check whether the star angles are appropriate for relocation
            if (tdest.type == VertexType.FreeVertex && numpoints_q != 0 && ValidPolygonAngles(numpoints_q, points_q))
            {
                //newLocFound = getPetalIntersection(m, b,numpoints_q, points_q, newloc);
                //newLocFound = getPetalIntersectionBruteForce(m, b,numpoints_q, points_q, newloc,tapex[0],tapex[1]);
                if (behavior.MaxAngle == 0.0)
                {
                    newLocFound = GetWedgeIntersectionWithoutMaxAngle(numpoints_q, points_q, ref newloc);
                }
                else
                {
                    newLocFound = GetWedgeIntersection(numpoints_q, points_q, ref newloc);
                }
                //printf("call petal intersection for q\n");	

                // make sure the relocated point is a free vertex	
                if (newLocFound)
                {
                    possibilities[2] = newloc[0];// something found
                    possibilities[3] = newloc[1];
                    num_pos++;// increase the number of possibilities
                    flag2 = 2;
                }
            }


            //********************* TRY TO RELOCATE POINT "q" ***************		
            // get the surrounding points of r, so this gives us the triangles
            numpoints_r = GetStarPoints(badotri, torg, tdest, tapex, 3, ref points_r);
            // check if the points in counterclockwise order
            // 	v1[0] = points_r[0];  v1[1] = points_r[1];
            // 	v2[0] = points_r[2];  v2[1] = points_r[3];
            // 	v3[0] = points_r[4];  v3[1] = points_r[5];
            // 	if(counterclockwise(m,b,v1,v2,v3) < 0){
            // 		// reverse the order to ccw
            // 		for(i = 0; i < numpoints_r/2; i++){
            // 			temp[0] = points_r[2*i];	
            // 			temp[1] = points_r[2*i+1];
            // 			points_r[2*i] = points_r[2*(numpoints_r-1)-2*i];
            // 			points_r[2*i+1] = points_r[2*(numpoints_r-1)+1-2*i];
            // 			points_r[2*(numpoints_r-1)-2*i] = temp[0];
            // 			points_r[2*(numpoints_r-1)+1-2*i] = temp[1];
            // 		}
            // 	}
            // 	m.counterclockcount--;
            // INTERSECTION OF PETALS
            // first check whether the star angles are appropriate for relocation
            if (tapex.type == VertexType.FreeVertex && numpoints_r != 0 && ValidPolygonAngles(numpoints_r, points_r))
            {
                //newLocFound = getPetalIntersection(m, b,numpoints_r, points_r, newloc);
                //newLocFound = getPetalIntersectionBruteForce(m, b,numpoints_r, points_r, newloc,tdest[0],tdest[1]);
                if (behavior.MaxAngle == 0.0)
                {
                    newLocFound = GetWedgeIntersectionWithoutMaxAngle(numpoints_r, points_r, ref newloc);
                }
                else
                {
                    newLocFound = GetWedgeIntersection(numpoints_r, points_r, ref newloc);
                }

                //printf("call petal intersection for r\n");


                // make sure the relocated point is a free vertex	
                if (newLocFound)
                {
                    possibilities[4] = newloc[0];// something found
                    possibilities[5] = newloc[1];
                    num_pos++;// increase the number of possibilities
                    flag3 = 3;
                }
            }
            //printf("numpossibilities %d\n",num_pos);
            //////////// AFTER FINISH CHECKING EVERY POSSIBILITY, CHOOSE ANY OF THE AVAILABLE ONE //////////////////////	
            if (num_pos > 0)
            {
                if (flag1 > 0)
                { // suggest to relocate origin
                    newloc[0] = possibilities[0];
                    newloc[1] = possibilities[1];
                    return flag1;

                }
                else
                {
                    if (flag2 > 0)
                    { // suggest to relocate apex
                        newloc[0] = possibilities[2];
                        newloc[1] = possibilities[3];
                        return flag2;

                    }
                    else
                    {// suggest to relocate destination
                        if (flag3 > 0)
                        {
                            newloc[0] = possibilities[4];
                            newloc[1] = possibilities[5];
                            return flag3;

                        }
                    }
                }
            }

            return 0;// could not find any good relocation
        }
Ejemplo n.º 35
0
        /// <summary>
        /// Insert a vertex into a Delaunay triangulation, performing flips as necessary 
        /// to maintain the Delaunay property.
        /// </summary>
        /// <param name="newvertex">The point to be inserted.</param>
        /// <param name="searchtri">The triangle to start the search.</param>
        /// <param name="splitseg">Segment to split.</param>
        /// <param name="segmentflaws">Check for creation of encroached subsegments.</param>
        /// <param name="triflaws">Check for creation of bad quality triangles.</param>
        /// <returns>If a duplicate vertex or violated segment does not prevent the 
        /// vertex from being inserted, the return value will be ENCROACHINGVERTEX if 
        /// the vertex encroaches upon a subsegment (and checking is enabled), or
        /// SUCCESSFULVERTEX otherwise. In either case, 'searchtri' is set to a handle
        /// whose origin is the newly inserted vertex.</returns>
        /// <remarks>
        /// The point 'newvertex' is located. If 'searchtri.triangle' is not NULL,
        /// the search for the containing triangle begins from 'searchtri'.  If
        /// 'searchtri.triangle' is NULL, a full point location procedure is called.
        /// If 'insertvertex' is found inside a triangle, the triangle is split into
        /// three; if 'insertvertex' lies on an edge, the edge is split in two,
        /// thereby splitting the two adjacent triangles into four. Edge flips are
        /// used to restore the Delaunay property. If 'insertvertex' lies on an
        /// existing vertex, no action is taken, and the value DUPLICATEVERTEX is
        /// returned. On return, 'searchtri' is set to a handle whose origin is the
        /// existing vertex.
        ///
        /// InsertVertex() does not use flip() for reasons of speed; some
        /// information can be reused from edge flip to edge flip, like the
        /// locations of subsegments.
        /// 
        /// Param 'splitseg': Normally, the parameter 'splitseg' is set to NULL, 
        /// implying that no subsegment should be split. In this case, if 'insertvertex' 
        /// is found to lie on a segment, no action is taken, and the value VIOLATINGVERTEX 
        /// is returned. On return, 'searchtri' is set to a handle whose primary edge is the 
        /// violated subsegment.
        /// If the calling routine wishes to split a subsegment by inserting a vertex in it, 
        /// the parameter 'splitseg' should be that subsegment. In this case, 'searchtri' 
        /// MUST be the triangle handle reached by pivoting from that subsegment; no point 
        /// location is done.
        /// 
        /// Param 'segmentflaws': Flags that indicate whether or not there should
        /// be checks for the creation of encroached subsegments. If a newly inserted 
        /// vertex encroaches upon subsegments, these subsegments are added to the list 
        /// of subsegments to be split if 'segmentflaws' is set.
        /// 
        /// Param 'triflaws': Flags that indicate whether or not there should be
        /// checks for the creation of bad quality triangles. If bad triangles are 
        /// created, these are added to the queue if 'triflaws' is set.
        /// </remarks>
        internal InsertVertexResult InsertVertex(Vertex newvertex, ref Otri searchtri,
            ref Osub splitseg, bool segmentflaws, bool triflaws)
        {
            Otri horiz = default(Otri);
            Otri top = default(Otri);
            Otri botleft = default(Otri), botright = default(Otri);
            Otri topleft = default(Otri), topright = default(Otri);
            Otri newbotleft = default(Otri), newbotright = default(Otri);
            Otri newtopright = default(Otri);
            Otri botlcasing = default(Otri), botrcasing = default(Otri);
            Otri toplcasing = default(Otri), toprcasing = default(Otri);
            Otri testtri = default(Otri);
            Osub botlsubseg = default(Osub), botrsubseg = default(Osub);
            Osub toplsubseg = default(Osub), toprsubseg = default(Osub);
            Osub brokensubseg = default(Osub);
            Osub checksubseg = default(Osub);
            Osub rightsubseg = default(Osub);
            Osub newsubseg = default(Osub);
            BadSubseg encroached;
            //FlipStacker newflip;
            Vertex first;
            Vertex leftvertex, rightvertex, botvertex, topvertex, farvertex;
            Vertex segmentorg, segmentdest;
            int region;
            double area;
            InsertVertexResult success;
            LocateResult intersect;
            bool doflip;
            bool mirrorflag;
            bool enq;

            if (splitseg.seg == null)
            {
                // Find the location of the vertex to be inserted.  Check if a good
                // starting triangle has already been provided by the caller.
                if (searchtri.tri.id == DUMMY)
                {
                    // Find a boundary triangle.
                    horiz.tri = dummytri;
                    horiz.orient = 0;
                    horiz.Sym();

                    // Search for a triangle containing 'newvertex'.
                    intersect = locator.Locate(newvertex, ref horiz);
                }
                else
                {
                    // Start searching from the triangle provided by the caller.
                    searchtri.Copy(ref horiz);
                    intersect = locator.PreciseLocate(newvertex, ref horiz, true);
                }
            }
            else
            {
                // The calling routine provides the subsegment in which
                // the vertex is inserted.
                searchtri.Copy(ref horiz);
                intersect = LocateResult.OnEdge;
            }

            if (intersect == LocateResult.OnVertex)
            {
                // There's already a vertex there.  Return in 'searchtri' a triangle
                // whose origin is the existing vertex.
                horiz.Copy(ref searchtri);
                locator.Update(ref horiz);
                return InsertVertexResult.Duplicate;
            }
            if ((intersect == LocateResult.OnEdge) || (intersect == LocateResult.Outside))
            {
                // The vertex falls on an edge or boundary.
                if (checksegments && (splitseg.seg == null))
                {
                    // Check whether the vertex falls on a subsegment.
                    horiz.Pivot(ref brokensubseg);
                    if (brokensubseg.seg.hash != DUMMY)
                    {
                        // The vertex falls on a subsegment, and hence will not be inserted.
                        if (segmentflaws)
                        {
                            enq = behavior.NoBisect != 2;
                            if (enq && (behavior.NoBisect == 1))
                            {
                                // This subsegment may be split only if it is an
                                // internal boundary.
                                horiz.Sym(ref testtri);
                                enq = testtri.tri.id != DUMMY;
                            }
                            if (enq)
                            {
                                // Add the subsegment to the list of encroached subsegments.
                                encroached = new BadSubseg();
                                encroached.subseg = brokensubseg;
                                encroached.org = brokensubseg.Org();
                                encroached.dest = brokensubseg.Dest();

                                qualityMesher.AddBadSubseg(encroached);
                            }
                        }
                        // Return a handle whose primary edge contains the vertex,
                        //   which has not been inserted.
                        horiz.Copy(ref searchtri);
                        locator.Update(ref horiz);
                        return InsertVertexResult.Violating;
                    }
                }

                // Insert the vertex on an edge, dividing one triangle into two (if
                // the edge lies on a boundary) or two triangles into four.
                horiz.Lprev(ref botright);
                botright.Sym(ref botrcasing);
                horiz.Sym(ref topright);
                // Is there a second triangle?  (Or does this edge lie on a boundary?)
                mirrorflag = topright.tri.id != DUMMY;
                if (mirrorflag)
                {
                    topright.Lnext();
                    topright.Sym(ref toprcasing);
                    MakeTriangle(ref newtopright);
                }
                else
                {
                    // Splitting a boundary edge increases the number of boundary edges.
                    hullsize++;
                }
                MakeTriangle(ref newbotright);

                // Set the vertices of changed and new triangles.
                rightvertex = horiz.Org();
                leftvertex = horiz.Dest();
                botvertex = horiz.Apex();
                newbotright.SetOrg(botvertex);
                newbotright.SetDest(rightvertex);
                newbotright.SetApex(newvertex);
                horiz.SetOrg(newvertex);

                // Set the region of a new triangle.
                newbotright.tri.label = botright.tri.label;

                if (behavior.VarArea)
                {
                    // Set the area constraint of a new triangle.
                    newbotright.tri.area = botright.tri.area;
                }

                if (mirrorflag)
                {
                    topvertex = topright.Dest();
                    newtopright.SetOrg(rightvertex);
                    newtopright.SetDest(topvertex);
                    newtopright.SetApex(newvertex);
                    topright.SetOrg(newvertex);

                    // Set the region of another new triangle.
                    newtopright.tri.label = topright.tri.label;

                    if (behavior.VarArea)
                    {
                        // Set the area constraint of another new triangle.
                        newtopright.tri.area = topright.tri.area;
                    }
                }

                // There may be subsegments that need to be bonded
                // to the new triangle(s).
                if (checksegments)
                {
                    botright.Pivot(ref botrsubseg);

                    if (botrsubseg.seg.hash != DUMMY)
                    {
                        botright.SegDissolve(dummysub);
                        newbotright.SegBond(ref botrsubseg);
                    }

                    if (mirrorflag)
                    {
                        topright.Pivot(ref toprsubseg);
                        if (toprsubseg.seg.hash != DUMMY)
                        {
                            topright.SegDissolve(dummysub);
                            newtopright.SegBond(ref toprsubseg);
                        }
                    }
                }

                // Bond the new triangle(s) to the surrounding triangles.
                newbotright.Bond(ref botrcasing);
                newbotright.Lprev();
                newbotright.Bond(ref botright);
                newbotright.Lprev();

                if (mirrorflag)
                {
                    newtopright.Bond(ref toprcasing);
                    newtopright.Lnext();
                    newtopright.Bond(ref topright);
                    newtopright.Lnext();
                    newtopright.Bond(ref newbotright);
                }

                if (splitseg.seg != null)
                {
                    // Split the subsegment into two.
                    splitseg.SetDest(newvertex);
                    segmentorg = splitseg.SegOrg();
                    segmentdest = splitseg.SegDest();
                    splitseg.Sym();
                    splitseg.Pivot(ref rightsubseg);
                    InsertSubseg(ref newbotright, splitseg.seg.boundary);
                    newbotright.Pivot(ref newsubseg);
                    newsubseg.SetSegOrg(segmentorg);
                    newsubseg.SetSegDest(segmentdest);
                    splitseg.Bond(ref newsubseg);
                    newsubseg.Sym();
                    newsubseg.Bond(ref rightsubseg);
                    splitseg.Sym();

                    // Transfer the subsegment's boundary marker to the vertex if required.
                    if (newvertex.label == 0)
                    {
                        newvertex.label = splitseg.seg.boundary;
                    }
                }

                if (checkquality)
                {
                    flipstack.Clear();

                    flipstack.Push(default(Otri)); // Dummy flip (see UndoVertex)
                    flipstack.Push(horiz);
                }

                // Position 'horiz' on the first edge to check for
                // the Delaunay property.
                horiz.Lnext();
            }
            else
            {
                // Insert the vertex in a triangle, splitting it into three.
                horiz.Lnext(ref botleft);
                horiz.Lprev(ref botright);
                botleft.Sym(ref botlcasing);
                botright.Sym(ref botrcasing);
                MakeTriangle(ref newbotleft);
                MakeTriangle(ref newbotright);

                // Set the vertices of changed and new triangles.
                rightvertex = horiz.Org();
                leftvertex = horiz.Dest();
                botvertex = horiz.Apex();
                newbotleft.SetOrg(leftvertex);
                newbotleft.SetDest(botvertex);
                newbotleft.SetApex(newvertex);
                newbotright.SetOrg(botvertex);
                newbotright.SetDest(rightvertex);
                newbotright.SetApex(newvertex);
                horiz.SetApex(newvertex);

                // Set the region of the new triangles.
                newbotleft.tri.label = horiz.tri.label;
                newbotright.tri.label = horiz.tri.label;

                if (behavior.VarArea)
                {
                    // Set the area constraint of the new triangles.
                    area = horiz.tri.area;
                    newbotleft.tri.area = area;
                    newbotright.tri.area = area;
                }

                // There may be subsegments that need to be bonded
                // to the new triangles.
                if (checksegments)
                {
                    botleft.Pivot(ref botlsubseg);
                    if (botlsubseg.seg.hash != DUMMY)
                    {
                        botleft.SegDissolve(dummysub);
                        newbotleft.SegBond(ref botlsubseg);
                    }
                    botright.Pivot(ref botrsubseg);
                    if (botrsubseg.seg.hash != DUMMY)
                    {
                        botright.SegDissolve(dummysub);
                        newbotright.SegBond(ref botrsubseg);
                    }
                }

                // Bond the new triangles to the surrounding triangles.
                newbotleft.Bond(ref botlcasing);
                newbotright.Bond(ref botrcasing);
                newbotleft.Lnext();
                newbotright.Lprev();
                newbotleft.Bond(ref newbotright);
                newbotleft.Lnext();
                botleft.Bond(ref newbotleft);
                newbotright.Lprev();
                botright.Bond(ref newbotright);

                if (checkquality)
                {
                    flipstack.Clear();
                    flipstack.Push(horiz);
                }
            }

            // The insertion is successful by default, unless an encroached
            // subsegment is found.
            success = InsertVertexResult.Successful;

            if (newvertex.tri.tri != null)
            {
                // Store the coordinates of the triangle that contains newvertex.
                newvertex.tri.SetOrg(rightvertex);
                newvertex.tri.SetDest(leftvertex);
                newvertex.tri.SetApex(botvertex);
            }

            // Circle around the newly inserted vertex, checking each edge opposite it 
            // for the Delaunay property. Non-Delaunay edges are flipped. 'horiz' is 
            // always the edge being checked. 'first' marks where to stop circling.
            first = horiz.Org();
            rightvertex = first;
            leftvertex = horiz.Dest();
            // Circle until finished.
            while (true)
            {
                // By default, the edge will be flipped.
                doflip = true;

                if (checksegments)
                {
                    // Check for a subsegment, which cannot be flipped.
                    horiz.Pivot(ref checksubseg);
                    if (checksubseg.seg.hash != DUMMY)
                    {
                        // The edge is a subsegment and cannot be flipped.
                        doflip = false;

                        if (segmentflaws)
                        {
                            // Does the new vertex encroach upon this subsegment?
                            if (qualityMesher.CheckSeg4Encroach(ref checksubseg) > 0)
                            {
                                success = InsertVertexResult.Encroaching;
                            }
                        }
                    }
                }

                if (doflip)
                {
                    // Check if the edge is a boundary edge.
                    horiz.Sym(ref top);
                    if (top.tri.id == DUMMY)
                    {
                        // The edge is a boundary edge and cannot be flipped.
                        doflip = false;
                    }
                    else
                    {
                        // Find the vertex on the other side of the edge.
                        farvertex = top.Apex();
                        // In the incremental Delaunay triangulation algorithm, any of
                        // 'leftvertex', 'rightvertex', and 'farvertex' could be vertices
                        // of the triangular bounding box. These vertices must be
                        // treated as if they are infinitely distant, even though their
                        // "coordinates" are not.
                        if ((leftvertex == infvertex1) || (leftvertex == infvertex2) ||
                            (leftvertex == infvertex3))
                        {
                            // 'leftvertex' is infinitely distant. Check the convexity of
                            // the boundary of the triangulation. 'farvertex' might be
                            // infinite as well, but trust me, this same condition should
                            // be applied.
                            doflip = predicates.CounterClockwise(newvertex, rightvertex, farvertex) > 0.0;
                        }
                        else if ((rightvertex == infvertex1) ||
                                 (rightvertex == infvertex2) ||
                                 (rightvertex == infvertex3))
                        {
                            // 'rightvertex' is infinitely distant. Check the convexity of
                            // the boundary of the triangulation. 'farvertex' might be
                            // infinite as well, but trust me, this same condition should
                            // be applied.
                            doflip = predicates.CounterClockwise(farvertex, leftvertex, newvertex) > 0.0;
                        }
                        else if ((farvertex == infvertex1) ||
                                 (farvertex == infvertex2) ||
                                 (farvertex == infvertex3))
                        {
                            // 'farvertex' is infinitely distant and cannot be inside
                            // the circumcircle of the triangle 'horiz'.
                            doflip = false;
                        }
                        else
                        {
                            // Test whether the edge is locally Delaunay.
                            doflip = predicates.InCircle(leftvertex, newvertex, rightvertex, farvertex) > 0.0;
                        }
                        if (doflip)
                        {
                            // We made it! Flip the edge 'horiz' by rotating its containing
                            // quadrilateral (the two triangles adjacent to 'horiz').
                            // Identify the casing of the quadrilateral.
                            top.Lprev(ref topleft);
                            topleft.Sym(ref toplcasing);
                            top.Lnext(ref topright);
                            topright.Sym(ref toprcasing);
                            horiz.Lnext(ref botleft);
                            botleft.Sym(ref botlcasing);
                            horiz.Lprev(ref botright);
                            botright.Sym(ref botrcasing);
                            // Rotate the quadrilateral one-quarter turn counterclockwise.
                            topleft.Bond(ref botlcasing);
                            botleft.Bond(ref botrcasing);
                            botright.Bond(ref toprcasing);
                            topright.Bond(ref toplcasing);
                            if (checksegments)
                            {
                                // Check for subsegments and rebond them to the quadrilateral.
                                topleft.Pivot(ref toplsubseg);
                                botleft.Pivot(ref botlsubseg);
                                botright.Pivot(ref botrsubseg);
                                topright.Pivot(ref toprsubseg);
                                if (toplsubseg.seg.hash == DUMMY)
                                {
                                    topright.SegDissolve(dummysub);
                                }
                                else
                                {
                                    topright.SegBond(ref toplsubseg);
                                }
                                if (botlsubseg.seg.hash == DUMMY)
                                {
                                    topleft.SegDissolve(dummysub);
                                }
                                else
                                {
                                    topleft.SegBond(ref botlsubseg);
                                }
                                if (botrsubseg.seg.hash == DUMMY)
                                {
                                    botleft.SegDissolve(dummysub);
                                }
                                else
                                {
                                    botleft.SegBond(ref botrsubseg);
                                }
                                if (toprsubseg.seg.hash == DUMMY)
                                {
                                    botright.SegDissolve(dummysub);
                                }
                                else
                                {
                                    botright.SegBond(ref toprsubseg);
                                }
                            }
                            // New vertex assignments for the rotated quadrilateral.
                            horiz.SetOrg(farvertex);
                            horiz.SetDest(newvertex);
                            horiz.SetApex(rightvertex);
                            top.SetOrg(newvertex);
                            top.SetDest(farvertex);
                            top.SetApex(leftvertex);

                            // Assign region.
                            // TODO: check region ok (no Math.Min necessary)
                            region = Math.Min(top.tri.label, horiz.tri.label);
                            top.tri.label = region;
                            horiz.tri.label = region;

                            if (behavior.VarArea)
                            {
                                if ((top.tri.area <= 0.0) || (horiz.tri.area <= 0.0))
                                {
                                    area = -1.0;
                                }
                                else
                                {
                                    // Take the average of the two triangles' area constraints.
                                    // This prevents small area constraints from migrating a
                                    // long, long way from their original location due to flips.
                                    area = 0.5 * (top.tri.area + horiz.tri.area);
                                }

                                top.tri.area = area;
                                horiz.tri.area = area;
                            }

                            if (checkquality)
                            {
                                flipstack.Push(horiz);
                            }

                            // On the next iterations, consider the two edges that were exposed (this
                            // is, are now visible to the newly inserted vertex) by the edge flip.
                            horiz.Lprev();
                            leftvertex = farvertex;
                        }
                    }
                }
                if (!doflip)
                {
                    // The handle 'horiz' is accepted as locally Delaunay.
                    if (triflaws)
                    {
                        // Check the triangle 'horiz' for quality.
                        qualityMesher.TestTriangle(ref horiz);
                    }

                    // Look for the next edge around the newly inserted vertex.
                    horiz.Lnext();
                    horiz.Sym(ref testtri);
                    // Check for finishing a complete revolution about the new vertex, or
                    // falling outside of the triangulation. The latter will happen when
                    // a vertex is inserted at a boundary.
                    if ((leftvertex == first) || (testtri.tri.id == DUMMY))
                    {
                        // We're done. Return a triangle whose origin is the new vertex.
                        horiz.Lnext(ref searchtri);

                        Otri recenttri = default(Otri);
                        horiz.Lnext(ref recenttri);
                        locator.Update(ref recenttri);

                        return success;
                    }
                    // Finish finding the next edge around the newly inserted vertex.
                    testtri.Lnext(ref horiz);
                    rightvertex = leftvertex;
                    leftvertex = horiz.Dest();
                }
            }
        }
Ejemplo n.º 36
0
        SplayNode FrontLocate(SplayNode splayroot, Otri bottommost, Vertex searchvertex,
                              ref Otri searchtri, ref bool farright)
        {
            bool farrightflag;

            bottommost.Copy(ref searchtri);
            splayroot = Splay(splayroot, searchvertex, ref searchtri);

            farrightflag = false;
            while (!farrightflag && RightOfHyperbola(ref searchtri, searchvertex))
            {
                searchtri.Onext();
                farrightflag = searchtri.Equals(bottommost);
            }
            farright = farrightflag;
            return splayroot;
        }
Ejemplo n.º 37
0
 /// <summary>
 /// Set Origin
 /// </summary>
 internal void SetOrg(Vertex v)
 {
     tri.vertices[plus1Mod3[orient]] = v;
 }
Ejemplo n.º 38
0
        /// <summary>
        /// Generates a structured mesh.
        /// </summary>
        /// <param name="bounds">Bounds of the mesh.</param>
        /// <param name="nx">Number of segments in x direction.</param>
        /// <param name="ny">Number of segments in y direction.</param>
        /// <returns>Mesh</returns>
        public static IMesh StructuredMesh(Rectangle bounds, int nx, int ny)
        {
            var polygon = new Polygon((nx + 1) * (ny + 1));

            double x, y, dx, dy, left, bottom;

            dx = bounds.Width / nx;
            dy = bounds.Height / ny;

            left = bounds.Left;
            bottom = bounds.Bottom;

            int i, j, k, l, n = 0;

            // Add vertices.
            var points = new Vertex[(nx + 1) * (ny + 1)];

            for (i = 0; i <= nx; i++)
            {
                x = left + i * dx;

                for (j = 0; j <= ny; j++)
                {
                    y = bottom + j * dy;

                    points[n++] = new Vertex(x, y);
                }
            }

            polygon.Points.AddRange(points);

            n = 0;

            // Set vertex hash and id.
            foreach (var v in points)
            {
                v.hash = v.id = n++;
            }

            // Add boundary segments.
            var segments = polygon.Segments;

            segments.Capacity = 2 * (nx + ny);

            Vertex a, b;

            for (j = 0; j < ny; j++)
            {
                // Left
                a = points[j];
                b = points[j + 1];

                segments.Add(new Segment(a, b, 1));

                a.Label = b.Label = 1;

                // Right
                a = points[nx * (ny + 1) + j];
                b = points[nx * (ny + 1) + (j + 1)];

                segments.Add(new Segment(a, b, 1));

                a.Label = b.Label = 1;
            }

            for (i = 0; i < nx; i++)
            {
                // Bottom
                a = points[(ny + 1) * i];
                b = points[(ny + 1) * (i + 1)];

                segments.Add(new Segment(a, b, 1));

                a.Label = b.Label = 1;

                // Top
                a = points[ny + (ny + 1) * i];
                b = points[ny + (ny + 1) * (i + 1)];

                segments.Add(new Segment(a, b, 1));

                a.Label = b.Label = 1;
            }

            // Add triangles.
            var triangles = new InputTriangle[2 * nx * ny];

            n = 0;

            for (i = 0; i < nx; i++)
            {
                for (j = 0; j < ny; j++)
                {
                    k = j + (ny + 1) * i;
                    l = j + (ny + 1) * (i + 1);

                    // Create 2 triangles in rectangle [k, l, l + 1, k + 1].

                    if ((i + j) % 2 == 0)
                    {
                        // Diagonal from bottom left to top right.
                        triangles[n++] = new InputTriangle(k, l, l + 1);
                        triangles[n++] = new InputTriangle(k, l + 1, k + 1);
                    }
                    else
                    {
                        // Diagonal from top left to bottom right.
                        triangles[n++] = new InputTriangle(k, l, k + 1);
                        triangles[n++] = new InputTriangle(l, l + 1, k + 1);
                    }
                }
            }

            return Converter.ToMesh(polygon, triangles);
        }
Ejemplo n.º 39
0
        SplayNode CircleTopInsert(SplayNode splayroot, Otri newkey,
                                  Vertex pa, Vertex pb, Vertex pc, double topy)
        {
            double ccwabc;
            double xac, yac, xbc, ybc;
            double aclen2, bclen2;
            Point searchpoint = new Point(); // TODO: mesh.nextras
            Otri dummytri = default(Otri);

            ccwabc = predicates.CounterClockwise(pa, pb, pc);
            xac = pa.x - pc.x;
            yac = pa.y - pc.y;
            xbc = pb.x - pc.x;
            ybc = pb.y - pc.y;
            aclen2 = xac * xac + yac * yac;
            bclen2 = xbc * xbc + ybc * ybc;
            searchpoint.x = pc.x - (yac * bclen2 - ybc * aclen2) / (2.0 * ccwabc);
            searchpoint.y = topy;
            return SplayInsert(Splay(splayroot, searchpoint, ref dummytri), newkey, searchpoint);
        }
Ejemplo n.º 40
0
        /// <summary>
        /// Inserts a vertex at the circumcenter of a triangle. Deletes 
        /// the newly inserted vertex if it encroaches upon a segment.
        /// </summary>
        /// <param name="badtri"></param>
        private void SplitTriangle(BadTriangle badtri)
        {
            Otri badotri = default(Otri);
            Vertex borg, bdest, bapex;
            Point newloc; // Location of the new vertex
            double xi = 0, eta = 0;
            InsertVertexResult success;
            bool errorflag;

            badotri = badtri.poortri;
            borg = badotri.Org();
            bdest = badotri.Dest();
            bapex = badotri.Apex();

            // Make sure that this triangle is still the same triangle it was
            // when it was tested and determined to be of bad quality.
            // Subsequent transformations may have made it a different triangle.
            if (!Otri.IsDead(badotri.tri) && (borg == badtri.org) &&
                (bdest == badtri.dest) && (bapex == badtri.apex))
            {
                errorflag = false;
                // Create a new vertex at the triangle's circumcenter.

                // Using the original (simpler) Steiner point location method
                // for mesh refinement.
                // TODO: NewLocation doesn't work for refinement. Why? Maybe 
                // reset VertexType?
                if (behavior.fixedArea || behavior.VarArea)
                {
                    newloc = predicates.FindCircumcenter(borg, bdest, bapex, ref xi, ref eta, behavior.offconstant);
                }
                else
                {
                    newloc = newLocation.FindLocation(borg, bdest, bapex, ref xi, ref eta, true, badotri);
                }

                // Check whether the new vertex lies on a triangle vertex.
                if (((newloc.x == borg.x) && (newloc.y == borg.y)) ||
                    ((newloc.x == bdest.x) && (newloc.y == bdest.y)) ||
                    ((newloc.x == bapex.x) && (newloc.y == bapex.y)))
                {
                    if (Log.Verbose)
                    {
                        logger.Warning("New vertex falls on existing vertex.", "Quality.SplitTriangle()");
                        errorflag = true;
                    }
                }
                else
                {
                    // The new vertex must be in the interior, and therefore is a
                    // free vertex with a marker of zero.
                    Vertex newvertex = new Vertex(newloc.x, newloc.y, 0
#if USE_ATTRIBS
                        , mesh.nextras
#endif
                        );

                    newvertex.type = VertexType.FreeVertex;

                    // Ensure that the handle 'badotri' does not represent the longest
                    // edge of the triangle.  This ensures that the circumcenter must
                    // fall to the left of this edge, so point location will work.
                    // (If the angle org-apex-dest exceeds 90 degrees, then the
                    // circumcenter lies outside the org-dest edge, and eta is
                    // negative.  Roundoff error might prevent eta from being
                    // negative when it should be, so I test eta against xi.)
                    if (eta < xi)
                    {
                        badotri.Lprev();
                    }

                    // Assign triangle for attributes interpolation.
                    newvertex.tri.tri = newvertex_tri;

                    // Insert the circumcenter, searching from the edge of the triangle,
                    // and maintain the Delaunay property of the triangulation.
                    Osub tmp = default(Osub);
                    success = mesh.InsertVertex(newvertex, ref badotri, ref tmp, true, true);

                    if (success == InsertVertexResult.Successful)
                    {
                        newvertex.hash = mesh.hash_vtx++;
                        newvertex.id = newvertex.hash;
#if USE_ATTRIBS
                        if (mesh.nextras > 0)
                        {
                            Interpolation.InterpolateAttributes(newvertex, newvertex.tri.tri, mesh.nextras);
                        }
#endif
                        mesh.vertices.Add(newvertex.hash, newvertex);

                        if (mesh.steinerleft > 0)
                        {
                            mesh.steinerleft--;
                        }
                    }
                    else if (success == InsertVertexResult.Encroaching)
                    {
                        // If the newly inserted vertex encroaches upon a subsegment,
                        // delete the new vertex.
                        mesh.UndoVertex();
                    }
                    else if (success == InsertVertexResult.Violating)
                    {
                        // Failed to insert the new vertex, but some subsegment was
                        // marked as being encroached.
                    }
                    else
                    {   // success == DUPLICATEVERTEX
                        // Couldn't insert the new vertex because a vertex is already there.
                        if (Log.Verbose)
                        {
                            logger.Warning("New vertex falls on existing vertex.", "Quality.SplitTriangle()");
                            errorflag = true;
                        }
                    }
                }
                if (errorflag)
                {
                    logger.Error("The new vertex is at the circumcenter of triangle: This probably "
                        + "means that I am trying to refine triangles to a smaller size than can be "
                        + "accommodated by the finite precision of floating point arithmetic.",
                        "Quality.SplitTriangle()");

                    throw new Exception("The new vertex is at the circumcenter of triangle.");
                }
            }
        }
Ejemplo n.º 41
0
        double CircleTop(Vertex pa, Vertex pb, Vertex pc, double ccwabc)
        {
            double xac, yac, xbc, ybc, xab, yab;
            double aclen2, bclen2, ablen2;

            Statistic.CircleTopCount++;

            xac = pa.x - pc.x;
            yac = pa.y - pc.y;
            xbc = pb.x - pc.x;
            ybc = pb.y - pc.y;
            xab = pa.x - pb.x;
            yab = pa.y - pb.y;
            aclen2 = xac * xac + yac * yac;
            bclen2 = xbc * xbc + ybc * ybc;
            ablen2 = xab * xab + yab * yab;
            return pc.y + (xac * bclen2 - xbc * aclen2 + Math.Sqrt(aclen2 * bclen2 * ablen2)) / (2.0 * ccwabc);
        }