Beispiel #1
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ContourVertex"/> struct as a copy.
 /// </summary>
 /// <param name="vert">The original vertex.</param>
 /// <param name="region">The region that the vertex belongs to.</param>
 public ContourVertex(ContourVertex vert, RegionId region)
 {
     this.X        = vert.X;
     this.Y        = vert.Y;
     this.Z        = vert.Z;
     this.RegionId = region;
 }
Beispiel #2
0
        /// <summary>
        /// Gets the leftness of a triangle formed from 3 contour vertices.
        /// </summary>
        /// <param name="a">The first vertex.</param>
        /// <param name="b">The second vertex.</param>
        /// <param name="c">The third vertex.</param>
        /// <returns>A value indicating the leftness of the triangle.</returns>
        public static bool IsLeft(ref ContourVertex a, ref ContourVertex b, ref ContourVertex c)
        {
            int area;

            Area2D(ref a, ref b, ref c, out area);
            return(area < 0);
        }
Beispiel #3
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ContourVertex"/> struct as a copy.
 /// </summary>
 /// <param name="vert">The original vertex.</param>
 /// <param name="index">The index of the original vertex, which is temporarily stored in the <see cref="RegionId"/> field.</param>
 public ContourVertex(ContourVertex vert, int index)
 {
     this.X        = vert.X;
     this.Y        = vert.Y;
     this.Z        = vert.Z;
     this.RegionId = new RegionId(index);
 }
Beispiel #4
0
		/// <summary>
		/// Initializes a new instance of the <see cref="ContourVertex"/> struct as a copy.
		/// </summary>
		/// <param name="vert">The original vertex.</param>
		/// <param name="index">The index of the original vertex, which is temporarily stored in the <see cref="RegionId"/> field.</param>
		public ContourVertex(ContourVertex vert, int index)
		{
			this.X = vert.X;
			this.Y = vert.Y;
			this.Z = vert.Z;
			this.RegionId = new RegionId(index);
		}
Beispiel #5
0
        /// <summary>
        /// Finds the closest indices between two contours. Useful for merging contours.
        /// </summary>
        /// <param name="a">A contour.</param>
        /// <param name="b">Another contour.</param>
        /// <param name="indexA">The nearest index on contour A.</param>
        /// <param name="indexB">The nearest index on contour B.</param>
        private static void GetClosestIndices(Contour a, Contour b, out int indexA, out int indexB)
        {
            int closestDistance = int.MaxValue;
            int lengthA         = a.vertices.Length;
            int lengthB         = b.vertices.Length;

            indexA = -1;
            indexB = -1;

            for (int i = 0; i < lengthA; i++)
            {
                int vertA     = i;
                int vertANext = (i + 1) % lengthA;
                int vertAPrev = (i + lengthA - 1) % lengthA;

                for (int j = 0; j < lengthB; j++)
                {
                    int vertB = j;

                    //vertB must be infront of vertA
                    if (ContourVertex.IsLeft(ref a.vertices[vertAPrev], ref a.vertices[vertA], ref b.vertices[vertB]) &&
                        ContourVertex.IsLeft(ref a.vertices[vertA], ref a.vertices[vertANext], ref b.vertices[vertB]))
                    {
                        int dx       = b.vertices[vertB].X - a.vertices[vertA].X;
                        int dz       = b.vertices[vertB].Z - a.vertices[vertA].Z;
                        int tempDist = dx * dx + dz * dz;
                        if (tempDist < closestDistance)
                        {
                            indexA          = i;
                            indexB          = j;
                            closestDistance = tempDist;
                        }
                    }
                }
            }
        }
Beispiel #6
0
        /// <summary>
        /// Simplify the contours by reducing the number of edges
        /// </summary>
        /// <param name="rawVerts">Initial vertices</param>
        /// <param name="simplified">New and simplified vertices</param>
        /// <param name="maxError">Maximum error allowed</param>
        /// <param name="maxEdgeLen">The maximum edge length allowed</param>
        /// <param name="buildFlags">Flags determines how to split the long edges</param>
        public static void Simplify(List <ContourVertex> rawVerts, List <ContourVertex> simplified, float maxError, int maxEdgeLen, ContourBuildFlags buildFlags)
        {
            bool tesselateWallEdges = (buildFlags & ContourBuildFlags.TessellateWallEdges) == ContourBuildFlags.TessellateWallEdges;
            bool tesselateAreaEdges = (buildFlags & ContourBuildFlags.TessellateAreaEdges) == ContourBuildFlags.TessellateAreaEdges;

            //add initial points
            bool hasConnections = false;

            for (int i = 0; i < rawVerts.Count; i++)
            {
                if (rawVerts[i].RegionId.Id != 0)
                {
                    hasConnections = true;
                    break;
                }
            }

            if (hasConnections)
            {
                //contour has some portals to other regions
                //add new point to every location where region changes
                for (int i = 0, end = rawVerts.Count; i < end; i++)
                {
                    int  ii = (i + 1) % end;
                    bool differentRegions = rawVerts[i].RegionId.Id != rawVerts[ii].RegionId.Id;
                    bool areaBorders      = RegionId.HasFlags(rawVerts[i].RegionId, RegionFlags.AreaBorder) != RegionId.HasFlags(rawVerts[ii].RegionId, RegionFlags.AreaBorder);

                    if (differentRegions || areaBorders)
                    {
                        simplified.Add(new ContourVertex(rawVerts[i], i));
                    }
                }
            }

            //add some points if thhere are no connections
            if (simplified.Count == 0)
            {
                //find lower-left and upper-right vertices of contour
                int      lowerLeftX = rawVerts[0].X;
                int      lowerLeftY = rawVerts[0].Y;
                int      lowerLeftZ = rawVerts[0].Z;
                RegionId lowerLeftI = RegionId.Null;

                int      upperRightX = rawVerts[0].X;
                int      upperRightY = rawVerts[0].Y;
                int      upperRightZ = rawVerts[0].Z;
                RegionId upperRightI = RegionId.Null;

                //iterate through points
                for (int i = 0; i < rawVerts.Count; i++)
                {
                    int x = rawVerts[i].X;
                    int y = rawVerts[i].Y;
                    int z = rawVerts[i].Z;

                    if (x < lowerLeftX || (x == lowerLeftX && z < lowerLeftZ))
                    {
                        lowerLeftX = x;
                        lowerLeftY = y;
                        lowerLeftZ = z;
                        lowerLeftI = new RegionId(i);
                    }

                    if (x > upperRightX || (x == upperRightX && z > upperRightZ))
                    {
                        upperRightX = x;
                        upperRightY = y;
                        upperRightZ = z;
                        upperRightI = new RegionId(i);
                    }
                }

                //save the points
                simplified.Add(new ContourVertex(lowerLeftX, lowerLeftY, lowerLeftZ, lowerLeftI));
                simplified.Add(new ContourVertex(upperRightX, upperRightY, upperRightZ, upperRightI));
            }

            //add points until all points are within error tolerance of simplified slope
            int numPoints = rawVerts.Count;

            for (int i = 0; i < simplified.Count;)
            {
                int ii = (i + 1) % simplified.Count;

                //obtain (x, z) coordinates, along with region id
                int ax = simplified[i].X;
                int az = simplified[i].Z;
                int ai = (int)simplified[i].RegionId;

                int bx = simplified[ii].X;
                int bz = simplified[ii].Z;
                int bi = (int)simplified[ii].RegionId;

                float maxDeviation = 0;
                int   maxi = -1;
                int   ci, countIncrement, endi;

                //traverse segment in lexilogical order (try to go from smallest to largest coordinates?)
                if (bx > ax || (bx == ax && bz > az))
                {
                    countIncrement = 1;
                    ci             = (int)(ai + countIncrement) % numPoints;
                    endi           = (int)bi;
                }
                else
                {
                    countIncrement = numPoints - 1;
                    ci             = (int)(bi + countIncrement) % numPoints;
                    endi           = (int)ai;
                }

                //tessellate only outer edges or edges between areas
                if (rawVerts[ci].RegionId.Id == 0 || RegionId.HasFlags(rawVerts[ci].RegionId, RegionFlags.AreaBorder))
                {
                    //find the maximum deviation
                    while (ci != endi)
                    {
                        float deviation = Distance.PointToSegment2DSquared(rawVerts[ci].X, rawVerts[ci].Z, ax, az, bx, bz);

                        if (deviation > maxDeviation)
                        {
                            maxDeviation = deviation;
                            maxi         = ci;
                        }

                        ci = (ci + countIncrement) % numPoints;
                    }
                }

                //If max deviation is larger than accepted error, add new point
                if (maxi != -1 && maxDeviation > (maxError * maxError))
                {
                    simplified.Insert(i + 1, new ContourVertex(rawVerts[maxi], maxi));
                }
                else
                {
                    i++;
                }
            }

            //split too long edges
            if (maxEdgeLen > 0 && (tesselateAreaEdges || tesselateWallEdges))
            {
                for (int i = 0; i < simplified.Count;)
                {
                    int ii = (i + 1) % simplified.Count;

                    //get (x, z) coordinates along with region id
                    int ax = simplified[i].X;
                    int az = simplified[i].Z;
                    int ai = (int)simplified[i].RegionId;

                    int bx = simplified[ii].X;
                    int bz = simplified[ii].Z;
                    int bi = (int)simplified[ii].RegionId;

                    //find maximum deviation from segment
                    int maxi = -1;
                    int ci   = (int)(ai + 1) % numPoints;

                    //tessellate only outer edges or edges between areas
                    bool tess = false;

                    //wall edges
                    if (tesselateWallEdges && rawVerts[ci].RegionId.Id == 0)
                    {
                        tess = true;
                    }

                    //edges between areas
                    if (tesselateAreaEdges && RegionId.HasFlags(rawVerts[ci].RegionId, RegionFlags.AreaBorder))
                    {
                        tess = true;
                    }

                    if (tess)
                    {
                        int dx = bx - ax;
                        int dz = bz - az;
                        if (dx * dx + dz * dz > maxEdgeLen * maxEdgeLen)
                        {
                            //round based on lexilogical direction (smallest to largest cooridinates, first by x.
                            //if x coordinates are equal, then compare z coordinates)
                            int n = bi < ai ? (bi + numPoints - ai) : (bi - ai);

                            if (n > 1)
                            {
                                if (bx > ax || (bx == ax && bz > az))
                                {
                                    maxi = (int)(ai + n / 2) % numPoints;
                                }
                                else
                                {
                                    maxi = (int)(ai + (n + 1) / 2) % numPoints;
                                }
                            }
                        }
                    }

                    //add new point
                    if (maxi != -1)
                    {
                        simplified.Insert(i + 1, new ContourVertex(rawVerts[maxi], maxi));
                    }
                    else
                    {
                        i++;
                    }
                }
            }

            for (int i = 0; i < simplified.Count; i++)
            {
                ContourVertex sv = simplified[i];

                //take edge vertex flag from current raw point and neighbor region from next raw point
                int      ai = ((int)sv.RegionId + 1) % numPoints;
                RegionId bi = sv.RegionId;

                //save new region id
                sv.RegionId = RegionId.FromRawBits(((int)rawVerts[ai].RegionId & (RegionId.MaskId | (int)RegionFlags.AreaBorder)) | ((int)rawVerts[(int)bi].RegionId & (int)RegionFlags.VertexBorder));

                simplified[i] = sv;
            }
        }
Beispiel #7
0
 /// <summary>
 /// Gets the 2D area of the triangle ABC.
 /// </summary>
 /// <param name="a">Point A of triangle ABC.</param>
 /// <param name="b">Point B of triangle ABC.</param>
 /// <param name="c">Point C of triangle ABC.</param>
 /// <param name="area">The 2D area of the triangle.</param>
 public static void Area2D(ref ContourVertex a, ref ContourVertex b, ref ContourVertex c, out int area)
 {
     area = (b.X - a.X) * (c.Z - a.Z) - (c.X - a.X) * (b.Z - a.Z);
 }
Beispiel #8
0
		/// <summary>
		/// Initializes a new instance of the <see cref="ContourVertex"/> struct as a copy.
		/// </summary>
		/// <param name="vert">The original vertex.</param>
		/// <param name="region">The region that the vertex belongs to.</param>
		public ContourVertex(ContourVertex vert, RegionId region)
		{
			this.X = vert.X;
			this.Y = vert.Y;
			this.Z = vert.Z;
			this.RegionId = region;
		}
Beispiel #9
0
		/// <summary>
		/// Gets the 2D area of the triangle ABC.
		/// </summary>
		/// <param name="a">Point A of triangle ABC.</param>
		/// <param name="b">Point B of triangle ABC.</param>
		/// <param name="c">Point C of triangle ABC.</param>
		/// <param name="area">The 2D area of the triangle.</param>
		public static void Area2D(ref ContourVertex a, ref ContourVertex b, ref ContourVertex c, out int area)
		{
			area = (b.X - a.X) * (c.Z - a.Z) - (c.X - a.X) * (b.Z - a.Z);
		}
Beispiel #10
0
		/// <summary>
		/// Gets the leftness of a triangle formed from 3 contour vertices.
		/// </summary>
		/// <param name="a">The first vertex.</param>
		/// <param name="b">The second vertex.</param>
		/// <param name="c">The third vertex.</param>
		/// <returns>A value indicating the leftness of the triangle.</returns>
		public static bool IsLeft(ref ContourVertex a, ref ContourVertex b, ref ContourVertex c)
		{
			int area;
			Area2D(ref a, ref b, ref c, out area);
			return area < 0;
		}