/// <summary> /// 该方法可将geomodel中的mesh集合合并为一个mesh对象 /// </summary> /// <param name="geoModel"></param> /// <param name="Tolerance">容差,小数点后位数。设置后所有点坐标的小数点后只保留该长度</param> public static void MergeMeshs(this GeoModel geoModel, int Tolerance=2) { if (geoModel.Meshes.Count > 0) { Mesh mesh = new Mesh(); Dictionary<int, Vertice> vPDic; List<Index> vPIndex; geoModel.structureData(Tolerance,out vPDic,out vPIndex); //归一化法线 foreach (KeyValuePair<int, Vertice> vP in vPDic) { double distence = Math.Sqrt(Math.Pow(vP.Value.Normal.X, 2) + Math.Pow(vP.Value.Normal.Y, 2) + Math.Pow(vP.Value.Normal.Z, 2)); if (distence>0) { vP.Value.Normal.X /= distence; vP.Value.Normal.Y /= distence; vP.Value.Normal.Z /= distence; } } geoModel.MakeMesh(vPDic, vPIndex); geoModel.CalculateNormals(ref vPDic, vPIndex); } }
/// <summary> /// 按平面切割模型 /// </summary> /// <param name="geoModel"></param> /// <param name="surface">切割平面</param> public static void ClipModel(this GeoModel geoModel, Surface surface) { if (geoModel.Meshes == null) return; #region 提取顶点 Dictionary<int, Vertice> vPDic; List<Index> vPIndex; geoModel.structureData(2, out vPDic, out vPIndex); #endregion List<Index> wellBeRm = new List<Index>(); List<Index> wellBeAdd = new List<Index>(); foreach (Index index in vPIndex) { #region 找到至少具有一点高于切割平面的三角面 if (!surface.isBelowMe(vPDic[index.P1]) || !surface.isBelowMe(vPDic[index.P2]) || !surface.isBelowMe(vPDic[index.P3])) { wellBeRm.Add(index); //第一步去掉都三个顶点都在切割面上方的三角面 if (!surface.isBelowMe(vPDic[index.P1]) && !surface.isBelowMe(vPDic[index.P2]) && !surface.isBelowMe(vPDic[index.P3])) { //vPDic.Remove(index.P1); vPDic.Remove(index.P2); vPDic.Remove(index.P3); //只需要删掉索引!不要删掉点,这个点还可能被其它三角面索引到,而其它三角面可能与切割平面相交 //这里不能直接在循环体内删除。应该记录列表,待循环完毕后再统一删,否则会打乱集合。 //vPIndex.Remove(index); //这里逻辑应该是都会删掉的,移到判断外去执行了 //wellBeRm.Add(index); } else { //剩下的就是和切割平面相交的三角面。这里开始计算三角形边与平面的交点 #region 计算交点的函数 //P1在下 if (surface.isBelowMe(vPDic[index.P1])) { #region //P1,P2在下,P3在上 if (surface.isBelowMe(vPDic[index.P2])) { #region Vertice vP1 = surface.Intersect(vPDic[index.P1], vPDic[index.P3]);//第一个交点 Vertice vP2 = surface.Intersect(vPDic[index.P2], vPDic[index.P3]);//第二个交点 //插入新生成的两个点,并添加这两点和剩下两点构成三角面的索引。 if (!vPDic.ContainsKey(vP1.HashCode)) vPDic.Add(vP1.HashCode, vP1); if (!vPDic.ContainsKey(vP2.HashCode)) vPDic.Add(vP2.HashCode, vP2); //连接P1和vP2,构成两个三角形 Index vIn1 = new Index() { P1 = vP1.HashCode, P2 = vP2.HashCode, P3 = vPDic[index.P1].HashCode }; Index vIn2 = new Index() { P1 = vPDic[index.P1].HashCode, P2 = vP2.HashCode, P3 = vPDic[index.P2].HashCode }; //同理这里不能直接编辑当前循环的list //vPIndex.Add(vIn1); //vPIndex.Add(vIn2); wellBeAdd.Add(vIn1); wellBeAdd.Add(vIn2); #endregion } //P1,P3在下,P2在上 else if (surface.isBelowMe(vPDic[index.P3])) { #region Vertice vP1 = surface.Intersect(vPDic[index.P1], vPDic[index.P2]);//第一个交点 Vertice vP2 = surface.Intersect(vPDic[index.P3], vPDic[index.P2]);//第二个交点 //插入新生成的两个点,并添加这两点和剩下两点构成三角面的索引。 if (!vPDic.ContainsKey(vP1.HashCode)) vPDic.Add(vP1.HashCode, vP1); if (!vPDic.ContainsKey(vP2.HashCode)) vPDic.Add(vP2.HashCode, vP2); //连接P1和vP2,构成两个三角形 Index vIn1 = new Index() { P1 = vP1.HashCode, P2 = vP2.HashCode, P3 = vPDic[index.P1].HashCode }; Index vIn2 = new Index() { P1 = vPDic[index.P1].HashCode, P2 = vP2.HashCode, P3 = vPDic[index.P3].HashCode }; //vPIndex.Add(vIn1); //vPIndex.Add(vIn2); wellBeAdd.Add(vIn1); wellBeAdd.Add(vIn2); #endregion } //P1在下,P2,P3在上 else { #region Vertice vP1 = surface.Intersect(vPDic[index.P1], vPDic[index.P2]);//第一个交点 Vertice vP2 = surface.Intersect(vPDic[index.P1], vPDic[index.P3]);//第二个交点 //插入新生成的两个点,并添加这两点和剩下一点构成三角面的索引 if (!vPDic.ContainsKey(vP1.HashCode)) vPDic.Add(vP1.HashCode, vP1); if (!vPDic.ContainsKey(vP2.HashCode)) vPDic.Add(vP2.HashCode, vP2); Index vIn = new Index() { P1 = vP1.HashCode, P2 = vP2.HashCode, P3 = vPDic[index.P1].HashCode }; //vPIndex.Add(vIn); wellBeAdd.Add(vIn); #endregion } #endregion } else //P1在上 { #region //P1,P2在上,P3在下 if (!surface.isBelowMe(vPDic[index.P2])) { #region Vertice vP1 = surface.Intersect(vPDic[index.P3], vPDic[index.P2]);//第一个交点 Vertice vP2 = surface.Intersect(vPDic[index.P3], vPDic[index.P1]);//第二个交点 //插入新生成的两个点,并添加这两点和剩下一点构成三角面的索引 if (!vPDic.ContainsKey(vP1.HashCode)) vPDic.Add(vP1.HashCode, vP1); if (!vPDic.ContainsKey(vP2.HashCode)) vPDic.Add(vP2.HashCode, vP2); Index vIn = new Index() { P1 = vP1.HashCode, P2 = vP2.HashCode, P3 = vPDic[index.P3].HashCode }; //vPIndex.Add(vIn); wellBeAdd.Add(vIn); #endregion } //P1,P3在上,P2在下 else if (!surface.isBelowMe(vPDic[index.P3])) { #region Vertice vP1 = surface.Intersect(vPDic[index.P2], vPDic[index.P3]);//第一个交点 Vertice vP2 = surface.Intersect(vPDic[index.P2], vPDic[index.P1]);//第二个交点 //插入新生成的两个点,并添加这两点和剩下一点构成三角面的索引 if (!vPDic.ContainsKey(vP1.HashCode)) vPDic.Add(vP1.HashCode, vP1); if (!vPDic.ContainsKey(vP2.HashCode)) vPDic.Add(vP2.HashCode, vP2); Index vIn = new Index() { P1 = vP1.HashCode, P2 = vP2.HashCode, P3 = vPDic[index.P2].HashCode }; //vPIndex.Add(vIn); wellBeAdd.Add(vIn); #endregion } //P1在上,P2,P3在下 else { #region Vertice vP1 = surface.Intersect(vPDic[index.P2], vPDic[index.P1]);//第一个交点 Vertice vP2 = surface.Intersect(vPDic[index.P3], vPDic[index.P1]);//第二个交点 //插入新生成的两个点,并添加这两点和剩下两点构成三角面的索引。 if (!vPDic.ContainsKey(vP1.HashCode)) vPDic.Add(vP1.HashCode, vP1); if (!vPDic.ContainsKey(vP2.HashCode)) vPDic.Add(vP2.HashCode, vP2); //连接P1和vP2,构成两个三角形 Index vIn1 = new Index() { P1 = vP1.HashCode, P2 = vP2.HashCode, P3 = vPDic[index.P2].HashCode }; Index vIn2 = new Index() { P1 = vPDic[index.P2].HashCode, P2 = vP2.HashCode, P3 = vPDic[index.P3].HashCode }; //vPIndex.Add(vIn1); //vPIndex.Add(vIn2); wellBeAdd.Add(vIn1); wellBeAdd.Add(vIn2); #endregion } #endregion } //surface.Intersect() #endregion } } #endregion } //统一删除刚刚记录的三角面 foreach (Index index in wellBeRm) { vPIndex.Remove(index);} //统一添加 foreach (Index index in wellBeAdd) { Console.WriteLine("=添加点="); Console.WriteLine(string.Format("{0},{1},{2}", vPDic[index.P1].X, vPDic[index.P1].Y, vPDic[index.P1].Z)); Console.WriteLine(string.Format("{0},{1},{2}", vPDic[index.P2].X, vPDic[index.P1].Y, vPDic[index.P2].Z)); Console.WriteLine(string.Format("{0},{1},{2}", vPDic[index.P3].X, vPDic[index.P1].Y, vPDic[index.P3].Z)); Console.WriteLine("========"); vPIndex.Add(index); } Point3Ds ps = new Point3Ds(); ps.ImportVPList(vPDic, wellBeAdd); Mesh m = geoModel.CreateMesh(ps); //geoModel.Meshes.Clear(); geoModel.Meshes.Add(m); geoModel.MergeMeshs(); geoModel.MakeMesh(vPDic, vPIndex); geoModel.CalculateNormals(ref vPDic, vPIndex); }
/// <summary> /// 根据结构化的数据制作mesh,三角网构造算法还没写好。此函数构造的面连线不正确 /// </summary> /// <param name="geoModel"></param> /// <param name="vPDic">顶点集合</param> /// <param name="vPIndex">索引列表</param> public static void MakeMesh(this GeoModel geoModel, Dictionary<int, Vertice> vPDic, List<Index> vPIndex) { #region 输出结构化数据到顺序数组 double[] Vertices = new double[vPIndex.Count * 3 * 3];//由于顶点被按照索引展开,这里需要额外的空间。 Int32[] Indexes = new Int32[vPIndex.Count * 3]; double[] Normals = new double[Vertices.Length]; int j = 0; for (int i = 0; i < Indexes.Length; i++) { Indexes[i] = i;//顺序写入索引,之后的点序列按照这个索引展开 } foreach (Index index in vPIndex) { //这里又产生了重复数据,我不知道要怎么再不产生重复的基础上写入数组 #region 依赖索引list写入顶点数组,此过程多次索引的顶点被展开了 Vertices[j] = vPDic[index.P1].X; Vertices[j + 1] = vPDic[index.P1].Y; Vertices[j + 2] = vPDic[index.P1].Z; Vertices[j + 3] = vPDic[index.P2].X; Vertices[j + 4] = vPDic[index.P2].Y; Vertices[j + 5] = vPDic[index.P2].Z; Vertices[j + 6] = vPDic[index.P3].X; Vertices[j + 7] = vPDic[index.P3].Y; Vertices[j + 8] = vPDic[index.P3].Z; #endregion #region 计算法向量 geoModel.CalculateNormals(ref vPDic, vPIndex); #endregion #region 写入法向量 Normals[j / 9] = vPDic[index.P1].Normal.X; Normals[(j / 9) + 1] = vPDic[index.P1].Normal.Y; Normals[(j / 9) + 2] = vPDic[index.P1].Normal.Z; Normals[(j / 9) + 3] = vPDic[index.P2].Normal.X; Normals[(j / 9) + 4] = vPDic[index.P2].Normal.Y; Normals[(j / 9) + 5] = vPDic[index.P2].Normal.Z; Normals[(j / 9) + 6] = vPDic[index.P3].Normal.X; Normals[(j / 9) + 7] = vPDic[index.P3].Normal.Y; Normals[(j / 9) + 8] = vPDic[index.P3].Normal.Z; #endregion j += 9; } #endregion Mesh mesh = new Mesh(); mesh.Vertices = Vertices; mesh.Indexes = Indexes; mesh.Normals = Normals; geoModel.Meshes.Clear(); geoModel.Meshes.Add(mesh); }