Exemplo n.º 1
0
    public static bool IsEarTip(List <Vector3> vertices, List <PolyVertex> pvs, PolyVertex pv)
    {
        if (pv.wasRemoved || !pv.isConvex)
        {
            return(false);
        }

        var prev = pv.prevIndex;
        var curr = pv.currIndex;
        var next = pv.nextIndex;

        var prevVert = vertices[prev];
        var currVert = vertices[curr];
        var nextVert = vertices[next];

        var isEar = true;

        foreach (var p in pvs)
        {
            if (!p.wasRemoved && !p.isConvex && p.currIndex != prev && p.currIndex != curr && p.currIndex != next)
            {
                if (MeshUtilities.IsPointInTriangle(vertices[p.currIndex], prevVert, currVert, nextVert, true, true))
                {
                    isEar = false;
                    break;
                }
            }
        }

        return(isEar);
    }
Exemplo n.º 2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="BVTree"/> class.
        /// </summary>
        /// <param name="verts">A set of vertices.</param>
        /// <param name="polys">A set of polygons composed of the vertices in <c>verts</c>.</param>
        /// <param name="nvp">The maximum number of vertices per polygon.</param>
        /// <param name="cellSize">The size of a cell.</param>
        /// <param name="cellHeight">The height of a cell.</param>
        public BVTree(PolyVertex[] verts, PolyMesh.Polygon[] polys, int nvp, float cellSize, float cellHeight)
        {
            nodes = new Node[polys.Length * 2];
            var items = new List <Node>();

            for (int i = 0; i < polys.Length; i++)
            {
                PolyMesh.Polygon p = polys[i];

                Node temp;
                temp.Index      = i;
                temp.Bounds.Min = temp.Bounds.Max = verts[p.Vertices[0]];

                for (int j = 1; j < nvp; j++)
                {
                    int vi = p.Vertices[j];
                    if (vi == PolyMesh.NullId)
                    {
                        break;
                    }

                    var v = verts[vi];
                    PolyVertex.ComponentMin(ref temp.Bounds.Min, ref v, out temp.Bounds.Min);
                    PolyVertex.ComponentMax(ref temp.Bounds.Max, ref v, out temp.Bounds.Max);
                }

                temp.Bounds.Min.Y = (int)Math.Floor((float)temp.Bounds.Min.Y * cellHeight / cellSize);
                temp.Bounds.Max.Y = (int)Math.Ceiling((float)temp.Bounds.Max.Y * cellHeight / cellSize);

                items.Add(temp);
            }

            Subdivide(items, 0, items.Count, 0);
        }
Exemplo n.º 3
0
        /// <summary>
        /// Calculates the bounding box for a set of bounding boxes.
        /// </summary>
        /// <param name="items">The list of all the bounding boxes.</param>
        /// <param name="minIndex">The first bounding box in the list to get the extends of.</param>
        /// <param name="maxIndex">The last bounding box in the list to get the extends of.</param>
        /// <param name="bounds">The extends of all the bounding boxes.</param>
        private static void CalcExtends(List <Node> items, int minIndex, int maxIndex, out PolyBounds bounds)
        {
            bounds = items[minIndex].Bounds;

            for (int i = minIndex + 1; i < maxIndex; i++)
            {
                Node it = items[i];
                PolyVertex.ComponentMin(ref it.Bounds.Min, ref bounds.Min, out bounds.Min);
                PolyVertex.ComponentMax(ref it.Bounds.Max, ref bounds.Max, out bounds.Max);
            }
        }
Exemplo n.º 4
0
    public static void SetupPolyVerts(List <Vector3> vertices, List <PolyVertex> polyVerts, Vector3 polygonNormal)
    {
        for (int i = 0; i < vertices.Count; ++i)
        {
            var curr = new PolyVertex();

            curr.currIndex = i;
            curr.prevIndex = i == 0 ? vertices.Count - 1 : i - 1;
            curr.nextIndex = (i + 1) % vertices.Count;

            curr.isConvex = IsFacingSameAsPolyNormal(vertices[curr.prevIndex], vertices[curr.currIndex], vertices[curr.nextIndex], polygonNormal);

            polyVerts.Add(curr);
        }
    }
Exemplo n.º 5
0
 /// <summary>
 /// Determines whether the vertices follow a certain order
 /// </summary>
 /// <param name="a">Vertex A</param>
 /// <param name="b">Vertex B</param>
 /// <param name="c">Vertex C</param>
 /// <returns>True if conditions met, false if not</returns>
 private static bool ULeft(PolyVertex a, PolyVertex b, PolyVertex c)
 {
     return (b.X - a.X) * (c.Z - a.Z) -
         (c.X - a.X) * (b.Z - a.Z) < 0;
 }
Exemplo n.º 6
0
        /// <summary>
        /// Walk the edges of a contour to determine whether a triangle can be formed.
        /// Form as many triangles as possible.
        /// </summary>
        /// <param name="verts">Vertices array</param>
        /// <param name="indices">Indices array</param>
        /// <param name="tris">Triangles array</param>
        /// <returns>The number of triangles.</returns>
        private static int Triangulate(PolyVertex[] verts, int[] indices, Triangle[] tris)
        {
            int ntris = 0;
            int n = verts.Length;

            //last bit of index determines whether vertex can be removed
            for (int i = 0; i < n; i++)
            {
                int i1 = Next(i, n);
                int i2 = Next(i1, n);
                if (Diagonal(i, i2, verts, indices))
                {
                    SetDiagonalFlag(ref indices[i1]);
                }
            }

            //need 3 verts minimum for a polygon
            while (n > 3)
            {
                //find the minimum distance betwee two vertices.
                //also, save their index
                int minLen = -1;
                int minIndex = -1;
                for (int i = 0; i < n; i++)
                {
                    int i1 = Next(i, n);

                    if (HasDiagonalFlag(indices[i1]))
                    {
                        int p0 = RemoveDiagonalFlag(indices[i]);
                        int p2 = RemoveDiagonalFlag(indices[Next(i1, n)]);

                        int dx = verts[p2].X - verts[p0].X;
                        int dy = verts[p2].Z - verts[p0].Z;
                        int len = dx * dx + dy * dy;

                        if (minLen < 0 || len < minLen)
                        {
                            minLen = len;
                            minIndex = i;
                        }
                    }
                }

                if (minIndex == -1)
                {
                    return -ntris;
                }

                int mi = minIndex;
                int mi1 = Next(mi, n);
                int mi2 = Next(mi1, n);

                tris[ntris] = new Triangle();
                tris[ntris].Index0 = RemoveDiagonalFlag(indices[mi]);
                tris[ntris].Index1 = RemoveDiagonalFlag(indices[mi1]);
                tris[ntris].Index2 = RemoveDiagonalFlag(indices[mi2]);
                ntris++;

                //remove P[i1]
                n--;
                for (int k = mi1; k < n; k++)
                    indices[k] = indices[k + 1];

                if (mi1 >= n) mi1 = 0;
                mi = Prev(mi1, n);

                //update diagonal flags
                if (Diagonal(Prev(mi, n), mi1, verts, indices))
                {
                    SetDiagonalFlag(ref indices[mi]);
                }
                else
                {
                    RemoveDiagonalFlag(ref indices[mi]);
                }

                if (Diagonal(mi, Next(mi1, n), verts, indices))
                {
                    SetDiagonalFlag(ref indices[mi1]);
                }
                else
                {
                    RemoveDiagonalFlag(ref indices[mi1]);
                }
            }

            //append remaining triangle
            tris[ntris] = new Triangle();
            tris[ntris].Index0 = RemoveDiagonalFlag(indices[0]);
            tris[ntris].Index1 = RemoveDiagonalFlag(indices[1]);
            tris[ntris].Index2 = RemoveDiagonalFlag(indices[2]);
            ntris++;

            return ntris;
        }
Exemplo n.º 7
0
        /// <summary>
        /// Initializes a new instance of the <see cref="PolyMesh"/> class by creating polygons from contours.
        /// </summary>
        /// <param name="contSet">The <see cref="ContourSet"/> to generate polygons from.</param>
        /// <param name="cellSize">The size of one voxel/cell.</param>
        /// <param name="cellHeight">The height of one voxel/cell.</param>
        /// <param name="borderSize">The size of the border around the mesh.</param>
        /// <param name="numVertsPerPoly">The maximum number of vertices per polygon.</param>
        public PolyMesh(ContourSet contSet, float cellSize, float cellHeight, int borderSize, int numVertsPerPoly)
        {
            //copy contour data
            this.bounds = contSet.Bounds;
            this.cellSize = cellSize;
            this.cellHeight = cellHeight;
            this.borderSize = borderSize;

            //get maximum limits
            //TODO move to ContourSet?
            int maxVertices = 0;
            int maxTris = 0;
            int maxVertsPerCont = 0;
            foreach (var cont in contSet)
            {
                int vertCount = cont.Vertices.Length;

                //skip null contours
                if (vertCount < 3)
                    continue;

                maxVertices += vertCount;
                maxTris += vertCount - 2;
                maxVertsPerCont = Math.Max(maxVertsPerCont, vertCount);
            }

            //initialize the mesh members
            var verts = new List<PolyVertex>(maxVertices);
            var polys = new List<Polygon>(maxTris);

            Queue<int> vertRemoveQueue = new Queue<int>(maxVertices);

            this.numVertsPerPoly = numVertsPerPoly;

            var vertDict = new Dictionary<PolyVertex, int>(new PolyVertex.RoughYEqualityComparer(2));

            int[] indices = new int[maxVertsPerCont]; //keep track of vertex hash codes
            Triangle[] tris = new Triangle[maxVertsPerCont];
            List<Polygon> contPolys = new List<Polygon>(maxVertsPerCont + 1);

            //extract contour data
            foreach (Contour cont in contSet)
            {
                //skip null contours
                if (cont.IsNull)
                    continue;

                PolyVertex[] vertices = new PolyVertex[cont.Vertices.Length];

                //triangulate contours
                for (int i = 0; i < cont.Vertices.Length; i++)
                {
                    var cv = cont.Vertices[i];
                    vertices[i] = new PolyVertex(cv.X, cv.Y, cv.Z);
                    indices[i] = i;
                }

                //Form triangles inside the area bounded by the contours
                int ntris = Triangulate(vertices, indices, tris);
                if (ntris <= 0) //TODO notify user when this happens. Logging?
                    ntris = -ntris;

                //add and merge vertices
                for (int i = 0; i < cont.Vertices.Length; i++)
                {
                    var cv = cont.Vertices[i];
                    var pv = vertices[i];

                    //save the hash code for each vertex
                    indices[i] = AddVertex(vertDict, pv, verts);

                    if (RegionId.HasFlags(cv.RegionId, RegionFlags.VertexBorder))
                    {
                        //the vertex should be removed
                        vertRemoveQueue.Enqueue(indices[i]);
                    }
                }

                contPolys.Clear();

                //iterate through all the triangles
                for (int i = 0; i < ntris; i++)
                {
                    Triangle ti = tris[i];

                    //make sure there are three distinct vertices. anything less can't be a polygon.
                    if (ti.Index0 == ti.Index1
                        || ti.Index0 == ti.Index2
                        || ti.Index1 == ti.Index2)
                        continue;

                    //each polygon has numVertsPerPoly
                    //index 0, 1, 2 store triangle vertices
                    //other polygon indexes (3 to numVertsPerPoly - 1) should be used for storing extra vertices when two polygons merge together
                    Polygon p = new Polygon(numVertsPerPoly, Area.Null, RegionId.Null, 0);
                    p.Vertices[0] = RemoveDiagonalFlag(indices[ti.Index0]);
                    p.Vertices[1] = RemoveDiagonalFlag(indices[ti.Index1]);
                    p.Vertices[2] = RemoveDiagonalFlag(indices[ti.Index2]);
                    contPolys.Add(p);
                }

                //no polygons generated, so skip
                if (contPolys.Count == 0)
                    continue;

                //merge polygons
                if (numVertsPerPoly > 3)
                {
                    while (true)
                    {
                        //find best polygons
                        int bestMergeVal = 0;
                        int bestPolyA = 0, bestPolyB = 0, bestEdgeA = 0, bestEdgeB = 0;

                        for (int i = 0; i < contPolys.Count - 1; i++)
                        {
                            int pj = i;

                            for (int j = i + 1; j < contPolys.Count; j++)
                            {
                                int pk = j;
                                int ea = 0, eb = 0;
                                int v = GetPolyMergeValue(contPolys, pj, pk, verts, out ea, out eb);
                                if (v > bestMergeVal)
                                {
                                    bestMergeVal = v;
                                    bestPolyA = i;
                                    bestPolyB = j;
                                    bestEdgeA = ea;
                                    bestEdgeB = eb;
                                }
                            }
                        }

                        if (bestMergeVal > 0)
                        {
                            int pa = bestPolyA;
                            int pb = bestPolyB;
                            MergePolys(contPolys, pa, pb, bestEdgeA, bestEdgeB);
                            contPolys[pb] = contPolys[contPolys.Count - 1];
                            contPolys.RemoveAt(contPolys.Count - 1);
                        }
                        else
                        {
                            //no more merging
                            break;
                        }
                    }
                }

                //store polygons
                for (int i = 0; i < contPolys.Count; i++)
                {
                    Polygon p = contPolys[i];
                    Polygon p2 = new Polygon(numVertsPerPoly, cont.Area, cont.RegionId, 0);

                    Buffer.BlockCopy(p.Vertices, 0, p2.Vertices, 0, numVertsPerPoly * sizeof(int));

                    polys.Add(p2);
                }
            }

            //remove edge vertices
            while (vertRemoveQueue.Count > 0)
            {
                int i = vertRemoveQueue.Dequeue();

                if (CanRemoveVertex(polys, i))
                    RemoveVertex(verts, polys, i);
            }

            //calculate adjacency (edges)
            BuildMeshAdjacency(verts, polys, numVertsPerPoly);

            //find portal edges
            if (this.borderSize > 0)
            {
                //iterate through all the polygons
                for (int i = 0; i < polys.Count; i++)
                {
                    Polygon p = polys[i];

                    //iterate through all the vertices
                    for (int j = 0; j < numVertsPerPoly; j++)
                    {
                        if (p.Vertices[j] == NullId)
                            break;

                        //skip connected edges
                        if (p.NeighborEdges[j] != NullId)
                            continue;

                        int nj = j + 1;
                        if (nj >= numVertsPerPoly || p.Vertices[nj] == NullId)
                            nj = 0;

                        //grab two consecutive vertices
                        int va = p.Vertices[j];
                        int vb = p.Vertices[nj];

                        //set some flags
                        if (verts[va].X == 0 && verts[vb].X == 0)
                            p.NeighborEdges[j] = NeighborEdgeFlag | 0;
                        else if (verts[va].Z == contSet.Height && verts[vb].Z == contSet.Height)
                            p.NeighborEdges[j] = NeighborEdgeFlag | 1;
                        else if (verts[va].X == contSet.Width && verts[vb].X == contSet.Width)
                            p.NeighborEdges[j] = NeighborEdgeFlag | 2;
                        else if (verts[va].Z == 0 && verts[vb].Z == 0)
                            p.NeighborEdges[j] = NeighborEdgeFlag | 3;
                    }
                }
            }

            this.vertices = verts.ToArray();
            this.polygons = polys.ToArray();
        }
Exemplo n.º 8
0
        /// <summary>
        /// Generate a new vertices with (x, y, z) coordiates and return the hash code index 
        /// </summary>
        /// <param name="vertDict">Vertex dictionary that maps coordinates to index</param>
        /// <param name="v">A vertex.</param>
        /// <param name="verts">The list of vertices</param>
        /// <returns>The vertex index</returns>
        private static int AddVertex(Dictionary<PolyVertex, int> vertDict, PolyVertex v, List<PolyVertex> verts)
        {
            int index;
            if (vertDict.TryGetValue(v, out index))
            {
                return index;
            }

            index = verts.Count;
            verts.Add(v);
            vertDict.Add(v, index);
            return index;
        }
Exemplo n.º 9
0
        /// <summary>
        /// True if and only if diagonal (i, j) is strictly internal to polygon 
        /// in neighborhood of i endpoint.
        /// </summary>
        /// <param name="i">Vertex index i</param>
        /// <param name="j">Vertex index j</param>
        /// <param name="verts">Contour vertices</param>
        /// <param name="indices">PolyMesh indices</param>
        /// <returns>True, if internal. False, if otherwise.</returns>
        public static bool InCone(int i, int j, PolyVertex[] verts, int[] indices)
        {
            int pi = RemoveDiagonalFlag(indices[i]);
            int pj = RemoveDiagonalFlag(indices[j]);
            int pi1 = RemoveDiagonalFlag(indices[Next(i, verts.Length)]);
            int pin1 = RemoveDiagonalFlag(indices[Prev(i, verts.Length)]);

            //if P[i] is convex vertex (i + 1 left or on (i - 1, i))
            if (PolyVertex.IsLeftOn(ref verts[pin1], ref verts[pi], ref verts[pi1]))
                return PolyVertex.IsLeft(ref verts[pi], ref verts[pj], ref verts[pin1]) && PolyVertex.IsLeft(ref verts[pj], ref verts[pi], ref verts[pi1]);

            //assume (i - 1, i, i + 1) not collinear
            return !(PolyVertex.IsLeftOn(ref verts[pi], ref verts[pj], ref verts[pi1]) && PolyVertex.IsLeftOn(ref verts[pj], ref verts[pi], ref verts[pin1]));
        }
Exemplo n.º 10
0
        /// <summary>
        /// True if and only if (v[i], v[j]) is internal or external diagonal
        /// ignoring edges incident to v[i] or v[j].
        /// </summary>
        /// <param name="i">Vertex index i</param>
        /// <param name="j">Vertex index j</param>
        /// <param name="verts">Contour vertices</param>
        /// <param name="indices">PolyMesh indices</param>
        /// <returns>True, if internal or external diagonal. False, if otherwise.</returns>
        public static bool Diagonalie(int i, int j, PolyVertex[] verts, int[] indices)
        {
            int d0 = RemoveDiagonalFlag(indices[i]);
            int d1 = RemoveDiagonalFlag(indices[j]);

            //for each edge (k, k + 1)
            for (int k = 0; k < verts.Length; k++)
            {
                int k1 = Next(k, verts.Length);

                //skip edges incident to i or j
                if (!((k == i) || (k1 == i) || (k == j) || (k1 == j)))
                {
                    int p0 = RemoveDiagonalFlag(indices[k]);
                    int p1 = RemoveDiagonalFlag(indices[k1]);

                    if (PolyVertex.Equal2D(ref verts[d0], ref verts[p0]) ||
                        PolyVertex.Equal2D(ref verts[d1], ref verts[p0]) ||
                        PolyVertex.Equal2D(ref verts[d0], ref verts[p1]) ||
                        PolyVertex.Equal2D(ref verts[d1], ref verts[p1]))
                        continue;

                    if (PolyVertex.Intersect(ref verts[d0], ref verts[d1], ref verts[p0], ref verts[p1]))
                        return false;
                }
            }

            return true;
        }
Exemplo n.º 11
0
		/// <summary>
		/// Floodfill heightfield to get 2D height data, starting at vertex locations
		/// </summary>
		/// <param name="compactField">Original heightfield data</param>
		/// <param name="poly">Polygon in PolyMesh</param>
		/// <param name="polyCount">Number of vertices per polygon</param>
		/// <param name="verts">PolyMesh Vertices</param>
		/// <param name="borderSize">Heightfield border size</param>
		/// <param name="hp">HeightPatch which extracts heightfield data</param>
		/// <param name="stack">Temporary stack of CompactSpanReferences</param>
		private void GetHeightDataSeedsFromVertices(CompactHeightfield compactField, PolyMesh.Polygon poly, int polyCount, PolyVertex[] verts, int borderSize, HeightPatch hp, List<CompactSpanReference> stack)
		{
			hp.SetAll(0);

			//use poly vertices as seed points
			for (int j = 0; j < polyCount; j++)
			{
				var csr = new CompactSpanReference(0, 0, -1);
				int dmin = int.MaxValue;

				var v = verts[poly.Vertices[j]];

				for (int k = 0; k < 9; k++)
				{
					//get vertices and offset x and z coordinates depending on current drection
					int ax = v.X + VertexOffset[k * 2 + 0];
					int ay = v.Y;
					int az = v.Z + VertexOffset[k * 2 + 1];

					//skip if out of bounds
					if (ax < hp.X || ax >= hp.X + hp.Width || az < hp.Y || az >= hp.Y + hp.Length)
						continue;

					//get new cell
					CompactCell c = compactField.Cells[(az + borderSize) * compactField.Width + (ax + borderSize)];
					
					//loop through all the spans
					for (int i = c.StartIndex, end = c.StartIndex + c.Count; i < end; i++)
					{
						CompactSpan s = compactField.Spans[i];
						
						//find minimum y-distance
						int d = Math.Abs(ay - s.Minimum);
						if (d < dmin)
						{
							csr = new CompactSpanReference(ax, az, i);
							dmin = d;
						}
					}
				}

				//only add if something new found
				if (csr.Index != -1)
				{
					stack.Add(csr);
				}
			}

			//find center of polygon using flood fill
			int pcx = 0, pcz = 0;
			for (int j = 0; j < polyCount; j++)
			{
				var v = verts[poly.Vertices[j]];
				pcx += v.X;
				pcz += v.Z;
			}

			pcx /= polyCount;
			pcz /= polyCount;

			//stack groups 3 elements as one part
			foreach (var cell in stack)
			{
				int idx = (cell.Y - hp.Y) * hp.Width + (cell.X - hp.X);
				hp[idx] = 1;
			}

			//process the entire stack
			while (stack.Count > 0)
			{
				var cell = stack[stack.Count - 1];
				stack.RemoveAt(stack.Count - 1);

				//check if close to center of polygon
				if (Math.Abs(cell.X - pcx) <= 1 && Math.Abs(cell.Y - pcz) <= 1)
				{
					//clear the stack and add a new group
					stack.Clear();

					stack.Add(cell);
					break;
				}

				CompactSpan cs = compactField[cell];

				//check all four directions
				for (var dir = Direction.West; dir <= Direction.South; dir++)
				{
					//skip if disconnected
					if (!cs.IsConnected(dir))
						continue;

					//get neighbor
					int ax = cell.X + dir.GetHorizontalOffset();
					int ay = cell.Y + dir.GetVerticalOffset();

					//skip if out of bounds
					if (ax < hp.X || ax >= (hp.X + hp.Width) || ay < hp.Y || ay >= (hp.Y + hp.Length))
						continue;

					if (hp[(ay - hp.Y) * hp.Width + (ax - hp.X)] != 0)
						continue;

					//get the new index
					int ai = compactField.Cells[(ay + borderSize) * compactField.Width + (ax + borderSize)].StartIndex + CompactSpan.GetConnection(ref cs, dir);

					//save data
					int idx = (ay - hp.Y) * hp.Width + (ax - hp.X);
					hp[idx] = 1;

					//push to stack
					stack.Add(new CompactSpanReference(ax, ay, ai));
				}
			}

			//clear the heightpatch
			hp.Clear();

			//mark start locations
			for (int i = 0; i < stack.Count; i++)
			{
				var c = stack[i];

				//set new heightpatch data
				int idx = (c.Y - hp.Y) * hp.Width + (c.X - hp.X);
				CompactSpan cs = compactField.Spans[c.Index];
				hp[idx] = cs.Minimum;

				stack[i] = new CompactSpanReference(c.X + borderSize, c.Y + borderSize, c.Index);
			}
		}
Exemplo n.º 12
0
        /// <summary>
        /// Removing vertices will leave holes that have to be triangulated again.
        /// </summary>
        /// <param name="verts">A list of vertices</param>
        /// <param name="polys">A list of polygons</param>
        /// <param name="vertex">The vertex to remove</param>
        private void RemoveVertex(List<PolyVertex> verts, List<Polygon> polys, int vertex)
        {
            int numVertsPerPoly = this.numVertsPerPoly;

            //count number of polygons to remove
            int numRemovedVerts = 0;
            for (int i = 0; i < polys.Count; i++)
            {
                Polygon p = polys[i];

                for (int j = 0; j < p.VertexCount; j++)
                {
                    if (p.Vertices[j] == vertex)
                        numRemovedVerts++;
                }
            }

            List<Edge> edges = new List<Edge>(numRemovedVerts * numVertsPerPoly);
            List<int> hole = new List<int>(numRemovedVerts * numVertsPerPoly);
            List<RegionId> regions = new List<RegionId>(numRemovedVerts * numVertsPerPoly);
            List<Area> areas = new List<Area>(numRemovedVerts * numVertsPerPoly);

            //Iterate through all the polygons
            for (int i = 0; i < polys.Count; i++)
            {
                Polygon p = polys[i];

                if (p.ContainsVertex(vertex))
                {
                    int nv = p.VertexCount;

                    //collect edges which don't touch removed vertex
                    for (int j = 0, k = nv - 1; j < nv; k = j++)
                        if (p.Vertices[j] != vertex && p.Vertices[k] != vertex)
                            edges.Add(new Edge(p.Vertices[k], p.Vertices[j], p.RegionId, p.Area));

                    polys[i] = polys[polys.Count - 1];
                    polys.RemoveAt(polys.Count - 1);
                    i--;
                }
            }

            //remove vertex
            verts.RemoveAt(vertex);

            //adjust indices
            for (int i = 0; i < polys.Count; i++)
            {
                Polygon p = polys[i];

                for (int j = 0; j < p.VertexCount; j++)
                {
                    if (p.Vertices[j] > vertex)
                        p.Vertices[j]--;
                }
            }

            for (int i = 0; i < edges.Count; i++)
            {
                Edge edge = edges[i];
                if (edge.Vert0 > vertex)
                    edge.Vert0--;

                if (edge.Vert1 > vertex)
                    edge.Vert1--;

                edges[i] = edge;
            }

            if (edges.Count == 0)
                return;

            //Find edges surrounding the holes
            hole.Add(edges[0].Vert0);
            regions.Add(edges[0].Region);
            areas.Add(edges[0].Area);

            while (edges.Count > 0)
            {
                bool match = false;

                for (int i = 0; i < edges.Count; i++)
                {
                    Edge edge = edges[i];
                    bool add = false;

                    if (hole[0] == edge.Vert1)
                    {
                        //segment matches beginning of hole boundary
                        hole.Insert(0, edge.Vert0);
                        regions.Insert(0, edge.Region);
                        areas.Insert(0, edge.Area);
                        add = true;
                    }
                    else if (hole[hole.Count - 1] == edge.Vert0)
                    {
                        //segment matches end of hole boundary
                        hole.Add(edge.Vert1);
                        regions.Add(edge.Region);
                        areas.Add(edge.Area);
                        add = true;
                    }

                    if (add)
                    {
                        //edge segment was added so remove it
                        edges[i] = edges[edges.Count - 1];
                        edges.RemoveAt(edges.Count - 1);
                        match = true;
                        i--;
                    }
                }

                if (!match)
                    break;
            }

            var tris = new Triangle[hole.Count];
            var tverts = new PolyVertex[hole.Count];
            var thole = new int[hole.Count];

            //generate temp vertex array for triangulation
            for (int i = 0; i < hole.Count; i++)
            {
                int polyIndex = hole[i];
                tverts[i] = verts[polyIndex];
                thole[i] = i;
            }

            //triangulate the hole
            int ntris = Triangulate(tverts, thole, tris);
            if (ntris < 0)
                ntris = -ntris;

            //merge hole triangles back to polygons
            List<Polygon> mergePolys = new List<Polygon>(ntris + 1);

            for (int j = 0; j < ntris; j++)
            {
                Triangle t = tris[j];
                if (t.Index0 != t.Index1 && t.Index0 != t.Index2 && t.Index1 != t.Index2)
                {
                    Polygon p = new Polygon(numVertsPerPoly, areas[t.Index0], regions[t.Index0], 0);
                    p.Vertices[0] = hole[t.Index0];
                    p.Vertices[1] = hole[t.Index1];
                    p.Vertices[2] = hole[t.Index2];
                    mergePolys.Add(p);
                }
            }

            if (mergePolys.Count == 0)
                return;

            //merge polygons
            if (numVertsPerPoly > 3)
            {
                while (true)
                {
                    //find best polygons
                    int bestMergeVal = 0;
                    int bestPolyA = 0, bestPolyB = 0, bestEa = 0, bestEb = 0;

                    for (int j = 0; j < mergePolys.Count - 1; j++)
                    {
                        int pj = j;
                        for (int k = j + 1; k < mergePolys.Count; k++)
                        {
                            int pk = k;
                            int edgeA, edgeB;
                            int v = GetPolyMergeValue(mergePolys, pj, pk, verts, out edgeA, out edgeB);
                            if (v > bestMergeVal)
                            {
                                bestMergeVal = v;
                                bestPolyA = j;
                                bestPolyB = k;
                                bestEa = edgeA;
                                bestEb = edgeB;
                            }
                        }
                    }

                    if (bestMergeVal > 0)
                    {
                        int polyA = bestPolyA;
                        int polyB = bestPolyB;
                        MergePolys(mergePolys, polyA, polyB, bestEa, bestEb);
                        mergePolys[polyB] = mergePolys[mergePolys.Count - 1];
                        mergePolys.RemoveAt(mergePolys.Count - 1);
                    }
                    else
                    {
                        //no more merging
                        break;
                    }
                }
            }

            //add merged polys back to the list.
            polys.AddRange(mergePolys);
        }
Exemplo n.º 13
0
    public static void CheckAfterEarCutoff(List <Vector3> vertices, List <PolyVertex> pvs, PolyVertex pv, Vector3 polygonNormal,
                                           VertexList ears)
    {
        // 1.) if prev was convex, do nothing.
        // 2.) if prev was reflex, re-check, and modify convex / reflex lists.
        // 3.) if convex, update its ear status.

        if (!pv.isConvex)
        {
            var prev = vertices[pv.prevIndex];
            var tip  = vertices[pv.currIndex];
            var next = vertices[pv.nextIndex];

            pv.isConvex = IsFacingSameAsPolyNormal(prev, tip, next, polygonNormal);
        }

        if (pv.isConvex)
        {
            var isEar          = IsEarTip(vertices, pvs, pv);
            var weKnowItsAnEar = ears.Contains(pv.currIndex);

            if (isEar != weKnowItsAnEar)
            {
                if (isEar)
                {
                    ears.AddIndex(pv.currIndex);
                }
                else
                {
                    ears.RemoveIndex(pv.currIndex);
                }
            }
        }
    }
Exemplo n.º 14
0
		private static bool DiagonalieLoose(int i, int j, PolyVertex[] verts, int[] indices)
		{
			int d0 = RemoveDiagonalFlag(indices[i]);
			int d1 = RemoveDiagonalFlag(indices[j]);

			for (int k = 0; k < verts.Length; k++)
			{
				int k1 = Next(k, verts.Length);
				if (!((k == i) || (k1 == i) || (k == j) || (k1 == j)))
				{
					int p0 = RemoveDiagonalFlag(indices[k]);
					int p1 = RemoveDiagonalFlag(indices[k1]);

					if (PolyVertex.Equal2D(ref verts[d0], ref verts[p0]) ||
						PolyVertex.Equal2D(ref verts[d1], ref verts[p0]) ||
						PolyVertex.Equal2D(ref verts[d0], ref verts[p1]) ||
						PolyVertex.Equal2D(ref verts[d1], ref verts[p1]))
						continue;

					if (PolyVertex.IntersectProp(ref verts[d0], ref verts[d1], ref verts[p0], ref verts[p1]))
						return false;
				}
			}

			return true;
		}
Exemplo n.º 15
0
		private static bool InConeLoose(int i, int j, PolyVertex[] verts, int[] indices)
		{
			int pi = RemoveDiagonalFlag(indices[i]);
			int pj = RemoveDiagonalFlag(indices[j]);
			int pi1 = RemoveDiagonalFlag(indices[Next(i, verts.Length)]);
			int pin1 = RemoveDiagonalFlag(indices[Prev(i, verts.Length)]);

			if (PolyVertex.IsLeftOn(ref verts[pin1], ref verts[pi], ref verts[pi1]))
				return PolyVertex.IsLeftOn(ref verts[pi], ref verts[pj], ref verts[pin1])
					&& PolyVertex.IsLeftOn(ref verts[pj], ref verts[pi], ref verts[pi1]);

			return !(PolyVertex.IsLeftOn(ref verts[pi], ref verts[pj], ref verts[pi1])
				&& PolyVertex.IsLeftOn(ref verts[pj], ref verts[pi], ref verts[pin1]));
		}
Exemplo n.º 16
0
		private static bool DiagonalLoose(int i, int j, PolyVertex[] verts, int[] indices)
		{
			return InConeLoose(i, j, verts, indices) && DiagonalieLoose(i, j, verts, indices);
		}
Exemplo n.º 17
0
 /// <summary>
 /// True if and only if (v[i], v[j]) is a proper internal diagonal of polygon.
 /// </summary>
 /// <param name="i">Vertex index i</param>
 /// <param name="j">Vertex index j</param>
 /// <param name="verts">Contour vertices</param>
 /// <param name="indices">PolyMesh indices</param>
 /// <returns>True, if internal diagonal. False, if otherwise.</returns>
 public static bool Diagonal(int i, int j, PolyVertex[] verts, int[] indices)
 {
     return InCone(i, j, verts, indices) && Diagonalie(i, j, verts, indices);
 }
Exemplo n.º 18
0
		private void GetHeightData(CompactHeightfield compactField, PolyMesh.Polygon poly, int polyCount, PolyVertex[] verts, int borderSize, HeightPatch hp)
		{
			var stack = new List<CompactSpanReference>();
			bool empty = true;
			hp.Clear();

			for (int y = 0; y < hp.Length; y++)
			{
				int hy = hp.Y + y + borderSize;
				for (int x = 0; x < hp.Width; x++)
				{
					int hx = hp.X + x + borderSize;
					var cells = compactField.Cells[hy * compactField.Width + hx];
					for (int i = cells.StartIndex, end = cells.StartIndex + cells.Count; i < end; i++)
					{
						var span = compactField.Spans[i];

						if (span.Region == poly.RegionId)
						{
							hp[x, y] = span.Minimum;
							empty = false;

							bool border = false;
							for (var dir = Direction.West; dir <= Direction.South; dir++)
							{
								if (span.IsConnected(dir))
								{
									int ax = hx + dir.GetHorizontalOffset();
									int ay = hy + dir.GetVerticalOffset();
									int ai = compactField.Cells[ay * compactField.Width + ax].StartIndex + CompactSpan.GetConnection(ref span, dir);

									if (compactField.Spans[ai].Region != poly.RegionId)
									{
										border = true;
										break;
									}
								}
							}

							if (border)
								stack.Add(new CompactSpanReference(hx, hy, i));

							break;
						}
					}
				}
			}

			if (empty)
				GetHeightDataSeedsFromVertices(compactField, poly, polyCount, verts, borderSize, hp, stack);

			const int RetractSize = 256;
			int head = 0;

			while (head < stack.Count)
			{
				var cell = stack[head++];
				var cs = compactField[cell];

				if (head >= RetractSize)
				{
					head = 0;
					if (stack.Count > RetractSize)
					{
						for (int i = 0; i < stack.Count - RetractSize; i++)
							stack[i] = stack[i + RetractSize];
					}

					int targetSize = stack.Count % RetractSize;
					while (stack.Count > targetSize)
						stack.RemoveAt(stack.Count - 1);
				}

				//loop in all four directions
				for (var dir = Direction.West; dir <= Direction.South; dir++)
				{
					//skip
					if (!cs.IsConnected(dir))
						continue;

					int ax = cell.X + dir.GetHorizontalOffset();
					int ay = cell.Y + dir.GetVerticalOffset();
					int hx = ax - hp.X - borderSize;
					int hy = ay - hp.Y - borderSize;

					if (hx < 0 || hx >= hp.Width || hy < 0 || hy >= hp.Length)
						continue;

					//only continue if height is unset
					if (hp.IsSet(hy * hp.Width + hx))
						continue;

					//get new span
					int ai = compactField.Cells[ay * compactField.Width + ax].StartIndex + CompactSpan.GetConnection(ref cs, dir);
					CompactSpan ds = compactField.Spans[ai];

					hp[hx, hy] = ds.Minimum;

					stack.Add(new CompactSpanReference(ax, ay, ai));
				}
			}
		}