コード例 #1
0
        /// <summary>
        /// Flips the given triangle edge in the triangulation.
        /// Flipping for Delaunay means changing the edge for the adjacent two triangles to the other possibility.
        /// </summary>
        /// <param name="T"></param>
        /// <param name="a_Edge"></param>
        private static void Flip(Triangulation T, TriangleEdge a_Edge)
        {
            var a_Triangle = a_Edge.T;
            var a_Twin     = a_Edge.Twin.T;

            if (a_Triangle == null || a_Twin == null)
            {
                throw new GeomException("Cannot flip edge if neighbouring triangles don't exist");
            }

            // retrieve other adjacent edges to edge vertices
            // e3  .  e1
            //   / | \
            //  .  |  .
            //   \ | /
            // e2  .  e0
            var e0 = a_Triangle.OtherEdge(a_Edge, a_Edge.Point1);
            var e1 = a_Triangle.OtherEdge(a_Edge, a_Edge.Point2);
            var e2 = a_Twin.OtherEdge(a_Edge.Twin, a_Edge.Point1);
            var e3 = a_Twin.OtherEdge(a_Edge.Twin, a_Edge.Point2);

            // create new triangle edges
            var euv = new TriangleEdge(e0.Point1, e2.Point2, null, null);
            var evu = new TriangleEdge(e2.Point2, e0.Point1, euv, null);

            euv.Twin = evu;

            // Remove old triangles
            T.RemoveTriangle(a_Triangle);
            T.RemoveTriangle(a_Twin);

            // add new triangles
            T.AddTriangle(new Triangle(e0, e2, evu));
            T.AddTriangle(new Triangle(e3, e1, euv));
        }
コード例 #2
0
        internal static Vector3 GetUncommonPoint(ITriangle triangle, TriangleEdge edge0, TriangleEdge edge1)
        {
            Vector3[] points0 = new Vector3[] { triangle.GetPoint(edge0, true), triangle.GetPoint(edge0, false) };
            Vector3[] points1 = new Vector3[] { triangle.GetPoint(edge1, true), triangle.GetPoint(edge1, false) };

            // Find exact
            for (int cntr0 = 0; cntr0 < points0.Length; cntr0++)
            {
                for (int cntr1 = 0; cntr1 < points1.Length; cntr1++)
                {
                    if (points0[cntr0] == points1[cntr1])
                    {
                        return(points0[cntr0 == 0 ? 1 : 0]);     // return the one that isn't common
                    }
                }
            }

            // Find close - execution should never get here, just being safe
            for (int cntr0 = 0; cntr0 < points0.Length; cntr0++)
            {
                for (int cntr1 = 0; cntr1 < points1.Length; cntr1++)
                {
                    if (points0[cntr0].IsNearValue(points1[cntr1]))
                    {
                        return(points0[cntr0 == 0 ? 1 : 0]);     // return the one that isn't common
                    }
                }
            }

            throw new ApplicationException("Didn't find a common point");
        }
コード例 #3
0
 public Edge AddEdge(Surface surface, TriangleEdge edge)
 {
     if (edges.ContainsKey(edge))
     {
         var e = edges[edge];
         e.Surfaces.ForEach(s => {
             s.AdjacentSurfaces.Add(surface);
             surface.AdjacentSurfaces.Add(s);
         });
         e.Surfaces.Add(surface);
         return(e);
     }
     else
     {
         var e = new Edge()
         {
             edge = edge
         };
         e.Surfaces.Add(surface);
         edges[edge] = e;
         e.v1        = AddVertex(e, edge.a);
         e.v2        = AddVertex(e, edge.b);
         e.v1.Edges.Add(e);
         e.v1.AdjacentVerts.Add(e.v2);
         e.v2.Edges.Add(e);
         e.v2.AdjacentVerts.Add(e.v1);
         return(e);
     }
 }
コード例 #4
0
        internal static float GetEdgeLength(ITriangle triangle, TriangleEdge edge)
        {
            Vector3 point0 = triangle.GetPoint(edge, true);
            Vector3 point1 = triangle.GetPoint(edge, false);

            return((point1 - point0).magnitude);
        }
コード例 #5
0
        internal static Vector3 GetEdgeMidpoint(ITriangle triangle, TriangleEdge edge)
        {
            Vector3 point0 = triangle.GetPoint(edge, true);
            Vector3 point1 = triangle.GetPoint(edge, false);

            Vector3 halfLength = (point1 - point0) * .5f;

            return(point0 + halfLength);
        }
コード例 #6
0
        private static LinkedList <int> OrderVertices(Triangle[] triangles)
        {
            var result        = new LinkedList <int>();
            var usedTriangles = new bool[triangles.Length];
            var queue         = new Queue <LinkedListNode <int> >();

            var edgesDict = new TrianglesEdgesDictionary(triangles.Length);

            foreach (var triangle in triangles)
            {
                edgesDict.AddTriangle(triangle);
            }

            var firstVertex   = triangles.SelectMany(it => it.Vertices).First(it => it.Triangles.Count == 1);
            var firstTriangle = firstVertex.Triangles.Single();

            usedTriangles[firstTriangle.Id] = true;
            result.AddLast(firstVertex.Id);
            result.AddLast(firstTriangle.Vertices.First(it => it.Id != firstVertex.Id).Id);
            result.AddLast(firstTriangle.Vertices.Last(it => it.Id != firstVertex.Id).Id);

            queue.Enqueue(result.Last);

            while (result.Count < triangles.Length + 2)
            {
                var edgeEndNode = queue.Dequeue();
                var edge        = new TriangleEdge()
                {
                    A = edgeEndNode.Value, B = edgeEndNode.Previous.Value
                };

                foreach (var ownerTriangle in edgesDict[edge])
                {
                    if (usedTriangles[ownerTriangle.TriangleId])
                    {
                        continue;
                    }
                    usedTriangles[ownerTriangle.TriangleId] = true;

                    var newNode = result.AddBefore(edgeEndNode, ownerTriangle.ThirdVertex);
                    queue.Enqueue(newNode);
                    queue.Enqueue(edgeEndNode);
                }
            }

            return(result);
        }
コード例 #7
0
        internal static Vector3 GetOppositePoint(ITriangle triangle, TriangleEdge edge)
        {
            switch (edge)
            {
            case TriangleEdge.Edge_01:
                return(triangle.Point2);

            case TriangleEdge.Edge_12:
                return(triangle.Point0);

            case TriangleEdge.Edge_20:
                return(triangle.Point1);

            default:
                throw new ApplicationException("Unknown TriangleEdge: " + edge.ToString());
            }
        }
コード例 #8
0
            private void AddEdgeWitOwnerByVertexIndexes(Triangle triangle, int a, int b, int c)
            {
                var key = new TriangleEdge()
                {
                    A = triangle.Vertices[a].Id, B = triangle.Vertices[b].Id
                };
                var value = new EdgeOwnerTriangle()
                {
                    TriangleId = triangle.Id, ThirdVertex = triangle.Vertices[c].Id
                };

                if (!base.TryGetValue(key, out var list))
                {
                    base[key] = list = new List <EdgeOwnerTriangle>(2);
                }
                list.Add(value);
            }
コード例 #9
0
        public TriangleTest()
        {
            v1 = new Vector2(0, 0);
            v2 = new Vector2(1, 1);
            v3 = new Vector2(2, 0);
            v4 = new Vector2(-1, -1);

            e1 = new TriangleEdge(v1, v2);
            e2 = new TriangleEdge(v2, v3);
            e3 = new TriangleEdge(v3, v1);
            t1 = new Triangle(e1, e2, e3);

            e4 = new TriangleEdge(v1, v3);
            e5 = new TriangleEdge(v3, v4);
            e6 = new TriangleEdge(v4, v1);
            t2 = new Triangle(e4, e5, e6);

            e3.Twin = e4;
            e4.Twin = e3;
        }
コード例 #10
0
    void DrawEdge(TriangleEdge e, bool gray, bool first)
    {
        var c = gray ? Color.gray : Color.white;

        if (ShowEdgeVertices)
        {
            Gizmos.color = Color.white * c;

            DrawCube(e.a);
            DrawCube(e.b);
        }

        if (ShowEdges)
        {
            Gizmos.color = Color.white * c;
            if (first)
            {
                Gizmos.color = Color.red;
            }
            Gizmos.DrawLine(new Vector3(e.a.x, e.a.y), new Vector3(e.b.x, e.b.y));
        }

        if (ShowCircumcenter)
        {
            Gizmos.color = Color.blue * c;
            DrawCube(e.circumcenter, 0.05f);
        }

        if (ShowCircle)
        {
            Gizmos.color = Color.white * c;
            DrawCircle(e.circumcenter, e.innerCircleR);
        }

        if (ShowRoots)
        {
            Gizmos.color = Color.green * c;
            DrawCube(e.root, 0.05f);
            DrawCircle(e.root, 3);
        }
    }
コード例 #11
0
        public TriangulationTest()
        {
            v1 = new Vector2(0, 0);
            v2 = new Vector2(1, 1);
            v3 = new Vector2(2, 0);
            v4 = new Vector2(1, -1);

            e1 = new TriangleEdge(v1, v2);
            e2 = new TriangleEdge(v2, v3);
            e3 = new TriangleEdge(v3, v1);
            t1 = new Triangle(e1, e2, e3);

            e4 = new TriangleEdge(v1, v3);
            e5 = new TriangleEdge(v3, v4);
            e6 = new TriangleEdge(v4, v1);
            t2 = new Triangle(e4, e5, e6);

            T = new Triangulation();
            T.AddTriangle(t1);
            T.AddTriangle(t2);
        }
コード例 #12
0
        /// <summary>
        /// Checks if the Delaunay property holds for the edge.
        /// </summary>
        /// <param name="T"></param>
        /// <returns>Whether the triangle edge is valid for a Delaunay triangulation.</returns>
        public static bool IsValid(TriangleEdge a_Edge)
        {
            // outer edge always valid
            if (a_Edge != null && a_Edge.IsOuter)
            {
                return(true);
            }

            if (a_Edge == null || a_Edge.T == null || a_Edge.Twin == null || a_Edge.Twin.T == null)
            {
                throw new GeomException("Invalid triangle edge - null pointers");
            }

            var a_triangle = a_Edge.T;
            var a_Twin     = a_Edge.Twin.T;

            // Points to test
            var u = a_Edge.T.OtherVertex(a_Edge).Value;
            var v = a_Edge.Twin.T.OtherVertex(a_Edge.Twin).Value;

            return(!a_triangle.InsideCircumcircle(v) && !a_Twin.InsideCircumcircle(u));
        }
コード例 #13
0
        internal static Vector3 GetPoint(ITriangle triangle, TriangleEdge edge, bool isFrom)
        {
            switch (edge)
            {
            case TriangleEdge.Edge_01:
                if (isFrom)
                {
                    return(triangle.Point0);
                }
                else
                {
                    return(triangle.Point1);
                }

            case TriangleEdge.Edge_12:
                if (isFrom)
                {
                    return(triangle.Point1);
                }
                else
                {
                    return(triangle.Point2);
                }

            case TriangleEdge.Edge_20:
                if (isFrom)
                {
                    return(triangle.Point2);
                }
                else
                {
                    return(triangle.Point0);
                }

            default:
                throw new ApplicationException("Unknown TriangleEdge: " + edge.ToString());
            }
        }
コード例 #14
0
        /// <summary>
        /// Makes an edge legal accorinding to the Delaunay condition.
        /// Recurses whenever flipping an edge since adjacent edges can be made illegal.
        /// </summary>
        /// <param name="T"></param>
        /// <param name="a_Vertex"></param>
        /// <param name="a_Edge"></param>
        private static void LegalizeEdge(Triangulation T, Vector2 a_Vertex, TriangleEdge a_Edge)
        {
            // do not legalize outer edge
            if (a_Edge != null && a_Edge.IsOuter)
            {
                return;
            }

            if (a_Edge == null || a_Edge.T == null || a_Edge.Twin == null || a_Edge.Twin.T == null)
            {
                throw new GeomException("Invalid triangle edge - Cannot legalize edge");
            }

            var a_triangle = a_Edge.T;
            var a_Twin     = a_Edge.Twin.T;

            if (!IsValid(a_Edge))
            {
                Flip(T, a_Edge);

                LegalizeEdge(T, a_Vertex, a_Twin.OtherEdge(a_Edge.Twin, a_Edge.Point1));
                LegalizeEdge(T, a_Vertex, a_Twin.OtherEdge(a_Edge.Twin, a_Edge.Point2));
            }
        }
コード例 #15
0
ファイル: TriangleStripper.cs プロジェクト: RicoPlays/sm64dse
        private TriangleLinked DetermineBestNextNeighbour(TriangleLinked triangle, List<TriangleLinked> neighbours, TriangleEdge edge, 
            bool tieBreak = false)
        {
            if (neighbours.Count == 0) return null;

            if (neighbours.Count == 1) return neighbours[0];

            neighbours.Sort((a, b) => GetNumLinked(a).CompareTo(GetNumLinked(b)));

            TriangleLinked[] twoTop = new TriangleLinked[2];
            twoTop[0] = neighbours[0]; twoTop[1] = neighbours[1];

            int[] numLinkedOfNeighbours = new int[] { GetNumLinked(twoTop[0]), GetNumLinked(twoTop[1]) };

            if (numLinkedOfNeighbours[0] < numLinkedOfNeighbours[1])
            {
                return twoTop[0];
            }
            else if (numLinkedOfNeighbours[1] < numLinkedOfNeighbours[0])
            {
                return twoTop[1];
            }
            else if (!tieBreak)
            {
                List<TriangleLinked> firstLinked = GetLinked(twoTop[0])[(int)edge];
                List<TriangleLinked> secondLinked = GetLinked(twoTop[1])[(int)edge];

                TriangleLinked firstBest = DetermineBestNextNeighbour(twoTop[0], firstLinked, edge, true);
                TriangleLinked secondBest = DetermineBestNextNeighbour(twoTop[1], secondLinked, edge, true);

                if (GetNumLinked(firstBest) < GetNumLinked(secondBest))
                    return twoTop[0];
                else
                    return twoTop[1];
            }
            else if (tieBreak)
            {
                return twoTop[0];
            }
            else
            {
                return null;
            }
        }
コード例 #16
0
 public Vector3 GetPoint(TriangleEdge edge, bool isFrom)
 {
     return(Triangle.GetPoint(this, edge, isFrom));
 }
コード例 #17
0
        private static bool need_rasterize(TriangleEdge edge1, TriangleEdge edge2, TriangleEdge edge3, float2 pixelpositon, float area, out float A, out float B, out float C)
        {
            A = TriangleDoubleArea(edge2.rtpos1, edge2.rtpos2, pixelpositon);
            B = TriangleDoubleArea(edge3.rtpos1, edge3.rtpos2, pixelpositon);
            C = TriangleDoubleArea(edge1.rtpos1, edge1.rtpos2, pixelpositon);

            return(need_rasterize(edge1.rtpos1, edge1.rtpos2, edge1.anotherrtpos, pixelpositon));

            //按照定义判断,会由于浮点数出现错误的点和缝隙

            if (area * A < 0 || area * B < 0 || area * C < 0)
            {
                //不在三角形内
                return(false);
            }
            //应用TOP-LEFT规则

            if (A == 0)
            {
                if (B == 0)
                {
                    if (!((edge2.istopedge && edge3.isleftedge) || (edge2.isleftedge && edge3.istopedge)))
                    {
                        return(false);
                    }
                }
                else if (C == 0)
                {
                    if (!((edge2.istopedge && edge1.isleftedge) || (edge2.isleftedge && edge1.istopedge)))
                    {
                        return(false);
                    }
                }
                else
                {
                    if (!(edge2.istopedge || edge2.isleftedge))
                    {
                        return(false);
                    }
                }
            }
            if (B == 0)
            {
                if (A == 0)
                {
                    if (!((edge2.istopedge && edge3.isleftedge) || (edge2.isleftedge && edge3.istopedge)))
                    {
                        return(false);
                    }
                }
                else if (C == 0)
                {
                    if (!((edge1.istopedge && edge3.isleftedge) || (edge1.isleftedge && edge3.istopedge)))
                    {
                        return(false);
                    }
                }
                else
                {
                    if (!(edge3.istopedge || edge3.isleftedge))
                    {
                        return(false);
                    }
                }
            }
            if (C == 0)
            {
                if (A == 0)
                {
                    if (!((edge2.istopedge && edge1.isleftedge) || (edge2.isleftedge && edge1.istopedge)))
                    {
                        return(false);
                    }
                }
                else if (B == 0)
                {
                    if (!((edge1.istopedge && edge2.isleftedge) || (edge1.isleftedge && edge2.istopedge)))
                    {
                        return(false);
                    }
                }
                else
                {
                    if (!(edge1.istopedge || edge1.isleftedge))
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
コード例 #18
0
        public static void Triangle(IRenderTarget renderBuffer, v2f p1, v2f p2, v2f p3, Raster[] rasters, out int totalrasters)
        {
            /*
             * D3D将点按z字形分成两个三角形做光栅化,而三角形的光栅化遵守TOP-LEFT规则:
             * 在屏幕上,若某条边位于三角形的左侧,则这条边称为LEFT边;若某条边是平行边,且位于三角形的上侧,则这条边称为TOP边。简单地讲,LEFT边是“左侧的边”,TOP边是“上面的平行边”。
             * D3D规定:
             * (1)如果一个像素中心刚好落在三角形的一条边上,则仅当这条边为TOP或LEFT边时才画该像素;
             * (2)如果一个像素中心刚好落在三角形两条边的交点,则仅当两条边分别为TOP和LEFT边时才画该像素。
             * TOP-LEFT规则保证了当两个三角形有重合边时,像素不会被重复渲染。对于拆分成两个三角形的点,则保证了一个顶点只覆盖一个像素。
             */
            totalrasters = 0;

            float2 pos1 = toRenderTargetPos(renderBuffer, p1.SV_POSITION.xy / p1.SV_POSITION.w);
            float2 pos2 = toRenderTargetPos(renderBuffer, p2.SV_POSITION.xy / p2.SV_POSITION.w);
            float2 pos3 = toRenderTargetPos(renderBuffer, p3.SV_POSITION.xy / p3.SV_POSITION.w);

            float area = TriangleDoubleArea(pos1, pos2, pos3);

            if (area == 0)
            {
                return;
            }


            //****确定矩形区域****
            int top    = (int)Math.Floor(Mathf.min(Mathf.min(pos1.y, pos2.y), pos3.y));
            int bottom = (int)Math.Ceiling(Mathf.max(Mathf.max(pos1.y, pos2.y), pos3.y));
            int left   = (int)Math.Floor(Mathf.min(Mathf.min(pos1.x, pos2.x), pos3.x));
            int right  = (int)Math.Ceiling(Mathf.max(Mathf.max(pos1.x, pos2.x), pos3.x));

            TriangleEdge edge1 = new TriangleEdge()
            {
                rtpos1 = pos1, rtpos2 = pos2, anotherrtpos = pos3
            };
            TriangleEdge edge2 = new TriangleEdge()
            {
                rtpos1 = pos2, rtpos2 = pos3, anotherrtpos = pos1
            };
            TriangleEdge edge3 = new TriangleEdge()
            {
                rtpos1 = pos3, rtpos2 = pos1, anotherrtpos = pos2
            };

            //如果用定义判断,需要处理顶边和左边,这里不用定义判断,所以不需要执行了
            //edge1.checkedgeattribue();
            //edge2.checkedgeattribue();
            //edge3.checkedgeattribue();


            if (left < 0)
            {
                left = 0;
            }
            if (top < 0)
            {
                top = 0;
            }

            //***将矩形区域扩展成2的倍数
            if (left % 2 == 1)
            {
                left--;
            }
            if (right % 2 == 1)
            {
                right++;
            }
            if (top % 2 == 1)
            {
                top--;
            }
            if (bottom % 2 == 1)
            {
                bottom++;
            }



            for (int i = left; i < right; i += 2)
            {
                if (i < 0 || i >= renderBuffer.rt_width)
                {
                    continue;
                }

                for (int j = top; j < bottom; j += 2)
                {
                    if (j < 0 || j >= renderBuffer.rt_height)
                    {
                        continue;
                    }

                    float2 pixelpositon = new float2(i + 0.5f, j + 0.5f);

                    //***检测相邻的四个像素。片段着色器阶段四个相邻像素Z形执行

                    float[] A      = new float[4];
                    float[] B      = new float[4];
                    float[] C      = new float[4];
                    bool[]  r_pass = new bool[4];

                    r_pass[0] = need_rasterize(edge1, edge2, edge3, new float2(pixelpositon.x, pixelpositon.y), area, out A[0], out B[0], out C[0]);
                    r_pass[1] = need_rasterize(edge1, edge2, edge3, new float2(pixelpositon.x + 1, pixelpositon.y), area, out A[1], out B[1], out C[1]);
                    r_pass[2] = need_rasterize(edge1, edge2, edge3, new float2(pixelpositon.x, pixelpositon.y + 1), area, out A[2], out B[2], out C[2]);
                    r_pass[3] = need_rasterize(edge1, edge2, edge3, new float2(pixelpositon.x + 1, pixelpositon.y + 1), area, out A[3], out B[3], out C[3]);

                    if (!(r_pass[0] || r_pass[1] || r_pass[2] || r_pass[3]))
                    {
                        continue;
                    }

                    for (int jj = 0; jj < 2; jj++)
                    {
                        for (int ii = 0; ii < 2; ii++)
                        {
                            int idx = jj * 2 + ii;

                            //重心坐标系
                            float a = A[idx] / area;
                            float b = B[idx] / area;
                            float c = C[idx] / area;

                            //返回光栅化结果

                            var r = rasters[totalrasters];
                            r.isclippass = false;
                            r.rasterize  = r_pass[idx];
                            r.x          = i + ii;
                            r.y          = j + jj;

                            v2f v2f = new v2f();
                            interpolation(ref v2f, ref p1, ref p2, ref p3, a, b, c);

                            r.vsout = v2f;

                            totalrasters++;
                        }
                    }
                }
            }
        }
コード例 #19
0
        private TriangleLinked DetermineBestNextNeighbour(TriangleLinked triangle, List <TriangleLinked> neighbours, TriangleEdge edge,
                                                          bool tieBreak = false)
        {
            if (neighbours.Count == 0)
            {
                return(null);
            }

            if (neighbours.Count == 1)
            {
                return(neighbours[0]);
            }

            neighbours.Sort((a, b) => GetNumLinked(a).CompareTo(GetNumLinked(b)));

            TriangleLinked[] twoTop = new TriangleLinked[2];
            twoTop[0] = neighbours[0]; twoTop[1] = neighbours[1];

            int[] numLinkedOfNeighbours = new int[] { GetNumLinked(twoTop[0]), GetNumLinked(twoTop[1]) };

            if (numLinkedOfNeighbours[0] < numLinkedOfNeighbours[1])
            {
                return(twoTop[0]);
            }
            else if (numLinkedOfNeighbours[1] < numLinkedOfNeighbours[0])
            {
                return(twoTop[1]);
            }
            else if (!tieBreak)
            {
                List <TriangleLinked> firstLinked  = GetLinked(twoTop[0])[(int)edge];
                List <TriangleLinked> secondLinked = GetLinked(twoTop[1])[(int)edge];

                TriangleLinked firstBest  = DetermineBestNextNeighbour(twoTop[0], firstLinked, edge, true);
                TriangleLinked secondBest = DetermineBestNextNeighbour(twoTop[1], secondLinked, edge, true);

                if (firstBest == null)
                {
                    return(twoTop[1]);
                }
                else if (secondBest == null)
                {
                    return(twoTop[0]);
                }
                else if (GetNumLinked(firstBest) < GetNumLinked(secondBest))
                {
                    return(twoTop[0]);
                }
                else
                {
                    return(twoTop[1]);
                }
            }
            else if (tieBreak)
            {
                return(twoTop[0]);
            }
            else
            {
                return(null);
            }
        }
コード例 #20
0
        Tuple <ModelBase.FaceListDef, List <int> > GetStripAndIndicesForStartingEvenEdge(
            TriangleLinked start, TriangleEdge startForwardEdge)
        {
            List <int> stripIndices = new List <int>();
            List <TriangleRotation> stripRotations = new List <TriangleRotation>();

            List <TriangleLinked> linked        = GetLinked(start)[(int)startForwardEdge];
            TriangleLinked        bestNeighbour = DetermineBestNextNeighbour(start, linked, startForwardEdge);

            if (bestNeighbour == null)
            {
                return(new Tuple <ModelBase.FaceListDef, List <int> >(new ModelBase.FaceListDef(), new List <int>()));
            }

            TriangleRotation startRotation = (TriangleRotation)((int)(startForwardEdge - TriangleEdge.Edge_BC + 3) % 3);

            TriangleLinked   t               = start;
            TriangleEdge     currentEdge     = startForwardEdge;
            TriangleRotation currentRotation = startRotation;
            bool             even            = true;
            int index_t = -1;

            while (t != null && !stripIndices.Contains((index_t = m_Triangles.IndexOf(t))))
            {
                stripIndices.Add(index_t);
                stripRotations.Add(currentRotation);

                linked        = GetLinked(t)[(int)currentEdge];
                bestNeighbour = DetermineBestNextNeighbour(t, linked, currentEdge);

                t = bestNeighbour;

                even = !even;

                if (t != null)
                {
                    // Determine rotation and the edge to be used to get the next face

                    ModelBase.FaceDef triangleC_CW = new ModelBase.FaceDef(3);
                    if (even)
                    {
                        triangleC_CW.m_Vertices[0] = t.m_Triangle.m_Vertices[0];
                        triangleC_CW.m_Vertices[1] = t.m_Triangle.m_Vertices[1];
                        triangleC_CW.m_Vertices[2] = t.m_Triangle.m_Vertices[2];
                    }
                    else
                    {
                        triangleC_CW.m_Vertices[0] = t.m_Triangle.m_Vertices[2];
                        triangleC_CW.m_Vertices[1] = t.m_Triangle.m_Vertices[1];
                        triangleC_CW.m_Vertices[2] = t.m_Triangle.m_Vertices[0];
                    }

                    // The edge of the vertices which match the preceding triangle's
                    TriangleEdge linkBackEdge = TriangleEdge.Edge_AB;
                    // The vertices which match the preceding triangle's
                    ModelBase.VertexDef[] currentMatchedEdge = new ModelBase.VertexDef[2];
                    TriangleLinked        previous           = m_Triangles[stripIndices[stripIndices.Count - 1]];
                    currentMatchedEdge[0] = previous.m_Triangle.m_Vertices[(int)(currentEdge + 0) % 3];
                    currentMatchedEdge[1] = previous.m_Triangle.m_Vertices[(int)(currentEdge + 1) % 3];
                    // Find the edge in the current triangle which if odd has been made CW which matches
                    // that from the preceding triangle. This will be set as the current triangle's first,
                    // or 'AB' edge and the next edge (next two vertices) will be used to match the next
                    // triangle.
                    for (int i = 0; i < 3; i++)
                    {
                        ModelBase.VertexDef[] edge = new ModelBase.VertexDef[2];
                        edge[0] = triangleC_CW.m_Vertices[(i + 0) % 3];
                        edge[1] = triangleC_CW.m_Vertices[(i + 1) % 3];
                        if (edge.Except(currentMatchedEdge).Count() == 0)
                        {
                            linkBackEdge = (TriangleEdge)i;
                            break;
                        }
                    }

                    TriangleEdge nextEdgeNoC_CW = (TriangleEdge)((int)(linkBackEdge + 1) % 3);

                    TriangleEdge nextEdge = nextEdgeNoC_CW;
                    if (!even)
                    {
                        // If odd, nextEdgeNoC_CW points to the edge to be used if written CW, however
                        // all triangles have been read in as CCW so need to get the corresponding edge
                        // in CCW version.
                        ModelBase.VertexDef[] nextEdgeNoC_CW_Vertices = new ModelBase.VertexDef[2];
                        nextEdgeNoC_CW_Vertices[0] = triangleC_CW.m_Vertices[(int)(nextEdgeNoC_CW + 0) % 3];
                        nextEdgeNoC_CW_Vertices[1] = triangleC_CW.m_Vertices[(int)(nextEdgeNoC_CW + 1) % 3];
                        for (int i = 0; i < 3; i++)
                        {
                            ModelBase.VertexDef[] ccwEdge = new ModelBase.VertexDef[2];
                            ccwEdge[0] = t.m_Triangle.m_Vertices[(i + 0) % 3];
                            ccwEdge[1] = t.m_Triangle.m_Vertices[(i + 1) % 3];
                            if (nextEdgeNoC_CW_Vertices.Except(ccwEdge).Count() == 0)
                            {
                                nextEdge = (TriangleEdge)i;
                                break;
                            }
                        }
                    }

                    // Now we need to determine the required rotation of the current triangle so that for
                    // even triangles the new vertex in at index 0 and for odd triangles it occurs at
                    // index 2.
                    ModelBase.VertexDef uniqueVertex  = t.m_Triangle.m_Vertices.Except(previous.m_Triangle.m_Vertices).ElementAt(0);
                    int uniqueVertexIndex             = Array.IndexOf(t.m_Triangle.m_Vertices, uniqueVertex);
                    TriangleRotation requiredRotation =
                        (even) ? (TriangleRotation)((uniqueVertexIndex - 2 + 3) % 3) :
                        (TriangleRotation)(uniqueVertexIndex);

                    currentRotation = requiredRotation;
                    currentEdge     = nextEdge;

                    // To best understand how this works, debug and step-through how the following model is handled:
                    //
                    // An example:
                    // Faces as defined in model (all Counter-Clockwise (CCW)):
                    // f 1 2 3
                    // f 4 1 3
                    // f 4 5 1
                    // Build strip from edge CA.
                    // # 2 3 1 (LS)      <- Need to Left Shift vertices so that CA is the second edge (in a tri. strip it's
                    //                      always the second edge that's shared - see diagram at top).
                    // #   3 1 4 (4 1 3) <- For odd faces the new vertex must be at index [0]
                    //                      No Rot required, link-back CW: AB, CW forward: AB + 1 = BC,
                    //                      CCW forward: edge in CCW that contains vertices in (CW forward) = AB
                    //                      The next triangle is the one that shares the CCW edge AB (vertices 1 and 4)
                    // #     1 4 5 (RS)  <- Even face the new vertex needs to be in index [2] so need to Right Shift vertices
                    //                      Repeat steps as for above face but don't need to worry about converting between CCW and CW order
                }
            }

            ModelBase.FaceListDef tStrip = new ModelBase.FaceListDef(ModelBase.PolyListType.TriangleStrip);

            for (int i = 0; i < stripIndices.Count; i++)
            {
                TriangleRotation requiredRotation = (TriangleRotation)stripRotations[i];

                ModelBase.FaceDef rotated = new ModelBase.FaceDef(3);
                rotated.m_Vertices[0] = m_Triangles[stripIndices[i]].m_Triangle.m_Vertices[((int)(0 + requiredRotation) % 3)];
                rotated.m_Vertices[1] = m_Triangles[stripIndices[i]].m_Triangle.m_Vertices[((int)(1 + requiredRotation) % 3)];
                rotated.m_Vertices[2] = m_Triangles[stripIndices[i]].m_Triangle.m_Vertices[((int)(2 + requiredRotation) % 3)];

                tStrip.m_Faces.Add(rotated);
            }

            return(new Tuple <ModelBase.FaceListDef, List <int> >(tStrip, stripIndices));
        }
コード例 #21
0
 public Vector3 GetUncommonPoint(TriangleEdge edge0, TriangleEdge edge1)
 {
     return(Triangle.GetUncommonPoint(this, edge0, edge1));
 }
コード例 #22
0
 public Vector3 GetOppositePoint(TriangleEdge edge)
 {
     return(Triangle.GetOppositePoint(this, edge));
 }
コード例 #23
0
 private static double GetLength(ITriangleIndexed triangle, TriangleEdge edge, SortedList<Tuple<int, int>, double> lengths)
 {
     return GetLength(triangle.GetIndex(edge, true), triangle.GetIndex(edge, false), lengths);
 }
コード例 #24
0
            private static void PruneBrainLinks_Remove(TriangleIndexed triangle, TriangleEdge edge, List<Tuple<int[], int[]>> links)
            {
                int index1 = triangle.GetIndex(edge, true);
                int index2 = triangle.GetIndex(edge, false);

                Tuple<int[], int[]> existing = null;
                bool? is1in1 = null;

                // Find and remove the link that contains this edge
                for (int cntr = 0; cntr < links.Count; cntr++)
                {
                    if (links[cntr].Item1.Contains(index1) && links[cntr].Item2.Contains(index2))
                    {
                        is1in1 = true;
                    }
                    else if (links[cntr].Item1.Contains(index2) && links[cntr].Item2.Contains(index1))
                    {
                        is1in1 = false;
                    }
                    else
                    {
                        continue;
                    }

                    existing = links[cntr];
                    links.RemoveAt(cntr);
                    break;
                }

                if (existing == null)
                {
                    //throw new ArgumentException("Didn't find the link");

                    // A neighbor triangle probably removed it
                    return;
                }

                // Add back if there were more than 2 involved
                if (existing.Item1.Length == 1 && existing.Item2.Length == 1)
                {
                    // This link only holds one item on each side.  It's already removed from the list, so there is nothing left to do
                    return;
                }

                int[] newItem1 = PruneBrainLinks_Remove_Reduce(existing.Item1, index1, index2, is1in1.Value);
                int[] newItem2 = PruneBrainLinks_Remove_Reduce(existing.Item2, index2, index1, is1in1.Value);

                links.Add(Tuple.Create(newItem1, newItem2));
            }
コード例 #25
0
            private static void PruneBrainLinks_Merge(TriangleIndexed triangle, TriangleEdge edge, List<Tuple<int[], int[]>> links)
            {
                // Figure out which indexes to look for
                int[] pair = new[] { triangle.GetIndex(edge, true), triangle.GetIndex(edge, false) };
                int other = triangle.IndexArray.First(o => !pair.Contains(o));

                // Extract the affected links out of the list
                List<Tuple<int[], int[]>> affected = new List<Tuple<int[], int[]>>();

                int index = 0;
                while (index < links.Count)
                {
                    var current = links[index];

                    if (current.Item1.Contains(other) && current.Item2.Any(o => pair.Contains(o)))
                    {
                        affected.Add(current);
                        links.RemoveAt(index);
                    }
                    else if (current.Item2.Contains(other) && current.Item1.Any(o => pair.Contains(o)))
                    {
                        affected.Add(Tuple.Create(current.Item2, current.Item1));       // reversing them so that Item1 is always other
                        links.RemoveAt(index);
                    }
                    else
                    {
                        index++;
                    }
                }

                // Combine the affected links (there shouldn't be more than two)
                var merged = Tuple.Create(
                    affected.SelectMany(o => o.Item1).Distinct().ToArray(),
                    affected.SelectMany(o => o.Item2).Distinct().ToArray());

                links.Add(merged);
            }
コード例 #26
0
ファイル: TriangleStripper.cs プロジェクト: RicoPlays/sm64dse
        Tuple<ModelBase.FaceListDef, List<int>> GetStripAndIndicesForStartingEvenEdge(
            TriangleLinked start, TriangleEdge startForwardEdge)
        {
            List<int> stripIndices = new List<int>();
            List<TriangleRotation> stripRotations = new List<TriangleRotation>();

            List<TriangleLinked> linked = GetLinked(start)[(int)startForwardEdge];
            TriangleLinked bestNeighbour = DetermineBestNextNeighbour(start, linked, startForwardEdge);

            if (bestNeighbour == null)
                return new Tuple<ModelBase.FaceListDef, List<int>>(new ModelBase.FaceListDef(), new List<int>());

            TriangleRotation startRotation = (TriangleRotation)((int)(startForwardEdge - TriangleEdge.Edge_BC + 3) % 3);

            TriangleLinked t = start;
            TriangleEdge currentEdge = startForwardEdge;
            TriangleRotation currentRotation = startRotation;
            bool even = true;
            int index_t = -1;
            while (t != null && !stripIndices.Contains((index_t = m_Triangles.IndexOf(t))))
            {
                stripIndices.Add(index_t);
                stripRotations.Add(currentRotation);

                linked = GetLinked(t)[(int)currentEdge];
                bestNeighbour = DetermineBestNextNeighbour(t, linked, currentEdge);

                t = bestNeighbour;

                even = !even;

                if (t != null)
                {
                    // Determine rotation and the edge to be used to get the next face

                    ModelBase.FaceDef triangleC_CW = new ModelBase.FaceDef(3);
                    if (even)
                    {
                        triangleC_CW.m_Vertices[0] = t.m_Triangle.m_Vertices[0];
                        triangleC_CW.m_Vertices[1] = t.m_Triangle.m_Vertices[1];
                        triangleC_CW.m_Vertices[2] = t.m_Triangle.m_Vertices[2];
                    }
                    else
                    {
                        triangleC_CW.m_Vertices[0] = t.m_Triangle.m_Vertices[2];
                        triangleC_CW.m_Vertices[1] = t.m_Triangle.m_Vertices[1];
                        triangleC_CW.m_Vertices[2] = t.m_Triangle.m_Vertices[0];
                    }

                    // The edge of the vertices which match the preceding triangle's
                    TriangleEdge linkBackEdge = TriangleEdge.Edge_AB;
                    // The vertices which match the preceding triangle's
                    ModelBase.VertexDef[] currentMatchedEdge = new ModelBase.VertexDef[2];
                    TriangleLinked previous = m_Triangles[stripIndices[stripIndices.Count - 1]];
                    currentMatchedEdge[0] = previous.m_Triangle.m_Vertices[(int)(currentEdge + 0) % 3];
                    currentMatchedEdge[1] = previous.m_Triangle.m_Vertices[(int)(currentEdge + 1) % 3];
                    // Find the edge in the current triangle which if odd has been made CW which matches
                    // that from the preceding triangle. This will be set as the current triangle's first,
                    // or 'AB' edge and the next edge (next two vertices) will be used to match the next
                    // triangle.
                    for (int i = 0; i < 3; i++)
                    {
                        ModelBase.VertexDef[] edge = new ModelBase.VertexDef[2];
                        edge[0] = triangleC_CW.m_Vertices[(i + 0) % 3];
                        edge[1] = triangleC_CW.m_Vertices[(i + 1) % 3];
                        if (edge.Except(currentMatchedEdge).Count() == 0)
                        {
                            linkBackEdge = (TriangleEdge)i;
                            break;
                        }
                    }

                    TriangleEdge nextEdgeNoC_CW = (TriangleEdge)((int)(linkBackEdge + 1) % 3);

                    TriangleEdge nextEdge = nextEdgeNoC_CW;
                    if (!even)
                    {
                        // If odd, nextEdgeNoC_CW points to the edge to be used if written CW, however
                        // all triangles have been read in as CCW so need to get the corresponding edge
                        // in CCW version.
                        ModelBase.VertexDef[] nextEdgeNoC_CW_Vertices = new ModelBase.VertexDef[2];
                        nextEdgeNoC_CW_Vertices[0] = triangleC_CW.m_Vertices[(int)(nextEdgeNoC_CW + 0) % 3];
                        nextEdgeNoC_CW_Vertices[1] = triangleC_CW.m_Vertices[(int)(nextEdgeNoC_CW + 1) % 3];
                        for (int i = 0; i < 3; i++)
                        {
                            ModelBase.VertexDef[] ccwEdge = new ModelBase.VertexDef[2];
                            ccwEdge[0] = t.m_Triangle.m_Vertices[(i + 0) % 3];
                            ccwEdge[1] = t.m_Triangle.m_Vertices[(i + 1) % 3];
                            if (nextEdgeNoC_CW_Vertices.Except(ccwEdge).Count() == 0)
                            {
                                nextEdge = (TriangleEdge)i;
                                break;
                            }
                        }
                    }

                    // Now we need to determine the required rotation of the current triangle so that for
                    // even triangles the new vertex in at index 0 and for odd triangles it occurs at
                    // index 2.
                    ModelBase.VertexDef uniqueVertex = t.m_Triangle.m_Vertices.Except(previous.m_Triangle.m_Vertices).ElementAt(0);
                    int uniqueVertexIndex = Array.IndexOf(t.m_Triangle.m_Vertices, uniqueVertex);
                    TriangleRotation requiredRotation =
                        (even) ? (TriangleRotation)((uniqueVertexIndex - 2 + 3) % 3) :
                        (TriangleRotation)(uniqueVertexIndex);

                    currentRotation = requiredRotation;
                    currentEdge = nextEdge;

                    // To best understand how this works, debug and step-through how the following model is handled:
                    //
                    // An example:
                    // Faces as defined in model (all Counter-Clockwise (CCW)):
                    // f 1 2 3
                    // f 4 1 3
                    // f 4 5 1
                    // Build strip from edge CA.
                    // # 2 3 1 (LS)      <- Need to Left Shift vertices so that CA is the second edge.
                    // #   3 1 4 (4 1 3) <- For odd faces the new vertex must be at index [0]
                    //                      No Rot required, link-back CW: AB, CW forward: AB + 1 = BC,
                    //                      CCW forward: edge in CCW that contains vertices in (CW forward) = AB
                    //                      The next triangle is the one that shares the CCW edge AB (vertices 1 and 4)
                    // #     1 4 5 (RS)  <- Even face the new vertex needs to be in index [2] so need to Right Shift vertices
                    //                      Repeat steps as for above face but don't need to worry about converting between CCW and CW order
                }

            }

            ModelBase.FaceListDef tStrip = new ModelBase.FaceListDef(ModelBase.PolyListType.TriangleStrip);

            even = true;
            for (int i = 0; i < stripIndices.Count; i++)
            {
                TriangleRotation requiredRotation = (TriangleRotation)stripRotations[i];

                ModelBase.FaceDef rotated = new ModelBase.FaceDef(3);
                rotated.m_Vertices[0] = m_Triangles[stripIndices[i]].m_Triangle.m_Vertices[((int)(0 + requiredRotation) % 3)];
                rotated.m_Vertices[1] = m_Triangles[stripIndices[i]].m_Triangle.m_Vertices[((int)(1 + requiredRotation) % 3)];
                rotated.m_Vertices[2] = m_Triangles[stripIndices[i]].m_Triangle.m_Vertices[((int)(2 + requiredRotation) % 3)];

                tStrip.m_Faces.Add(rotated);

                even = !even;
            }

            return new Tuple<ModelBase.FaceListDef, List<int>>(tStrip, stripIndices);
        }
コード例 #27
0
 public Vector3 GetEdgeMidpoint(TriangleEdge edge)
 {
     return(Triangle.GetEdgeMidpoint(this, edge));
 }
コード例 #28
0
 public float GetEdgeLength(TriangleEdge edge)
 {
     return(Triangle.GetEdgeLength(this, edge));
 }