private int AddEdgeToMesh(MEdge edge) { int i, j; if ((i = edgeList.IndexOf(edge)) == -1) { edgeList.Add(edge); switch (edge.edgeType) { case MEdge.MEdgeType.LINEAR: MLinearEdge le = edge as MLinearEdge; j = AddPointToMesh(le.start); if (j != -1) { le.start = pointList[j]; } le.start.edges.Add(edge); j = AddPointToMesh(le.end); if (j != -1) { le.end = pointList[j]; } le.end.edges.Add(edge); break; case MEdge.MEdgeType.CURVE: MCurveEdge ce = edge as MCurveEdge; foreach (Vector3 v in ce.mesh.vertices) { boundingBox.AdjustToContain(v); } j = AddPointToMesh(ce.center); if (j != -1) { ce.center = pointList[j]; } ce.center.edges.Add(edge); break; case MEdge.MEdgeType.GENERAL: MGeneralEdge ge = edge as MGeneralEdge; foreach (Vector3 v in ge.points) { boundingBox.AdjustToContain(v); } break; default: Debug.Log("MMesh: AddEdgeToList: unhandled edge type " + edge.edgeType); break; } } return(i); }
public MGeneralEdge CreateGeneralEdge(List <Vector3> points) { MGeneralEdge edge = new MGeneralEdge(points); if (!edge.IsValid()) { return(null); } int i; if ((i = AddEdgeToMesh(edge)) != -1) { return(edgeList[i] as MGeneralEdge); } else { return(edge); } }
public List<MObject> PlaneSplit(Vector3 normal, Vector3 planePoint) { normal = worldToLocalMatrix.MultiplyVector(normal).normalized; planePoint = worldToLocalMatrix.MultiplyPoint(planePoint); MMesh mesh1 = new MMesh(); MMesh mesh2 = new MMesh(); foreach(MPoint p in mesh.pointList) { int r = MHelperFunctions.FloatZero(Vector3.Dot(p.position - planePoint, normal)); if(r == 0) { mesh1.CreatePoint(p.position); mesh2.CreatePoint(p.position); } else if(r > 0) { mesh1.CreatePoint(p.position); } else { mesh2.CreatePoint(p.position); } } Dictionary<MEdge, List<MEdge>> edgeMap = new Dictionary<MEdge, List<MEdge>>(); List<MFace> facesNeedSplit = new List<MFace>(); foreach(MEdge edge in mesh.edgeList) { switch (edge.edgeType) { case MEdge.MEdgeType.LINEAR: { MLinearEdge le = edge as MLinearEdge; Vector3 v1 = le.start.position - MHelperFunctions.PointProjectionInFace(le.start.position, normal, planePoint); Vector3 v2 = le.end.position - MHelperFunctions.PointProjectionInFace(le.end.position, normal, planePoint); int r1 = MHelperFunctions.FloatZero(Vector3.Dot(v1, normal)); int r2 = MHelperFunctions.FloatZero(Vector3.Dot(v2, normal)); if (r1 == 0 && r2 == 0) { mesh1.CreateLinearEdge(new MPoint(le.start.position), new MPoint(le.end.position)); mesh2.CreateLinearEdge(new MPoint(le.start.position), new MPoint(le.end.position)); } else if (r1 >= 0 && r2 >= 0) { mesh1.CreateLinearEdge(new MPoint(le.start.position), new MPoint(le.end.position)); } else if (r1 <= 0 && r2 <= 0) { mesh2.CreateLinearEdge(new MPoint(le.start.position), new MPoint(le.end.position)); } else { foreach (MFace face in le.faces) { if(!facesNeedSplit.Contains(face))facesNeedSplit.Add(face); } List<MEdge> edgeList = new List<MEdge>(); Vector3 v = (le.end.position - le.start.position).normalized * v1.magnitude / (v1.magnitude + v2.magnitude) + le.start.position; if (r1 > 0) { edgeList.Add(mesh1.CreateLinearEdge(new MPoint(le.start.position), new MPoint(v))); edgeList.Add(mesh2.CreateLinearEdge(new MPoint(v), new MPoint(le.end.position))); } else { edgeList.Add(mesh1.CreateLinearEdge(new MPoint(le.end.position), new MPoint(v))); edgeList.Add(mesh2.CreateLinearEdge(new MPoint(v), new MPoint(le.start.position))); } if(edgeList.Count == 2)edgeMap.Add(le, edgeList); } break; } case MEdge.MEdgeType.CURVE: { MCurveEdge ce = edge as MCurveEdge; int r = MHelperFunctions.FloatZero(Vector3.Dot(ce.center.position - planePoint, normal)); if (MHelperFunctions.Parallel(normal, ce.normal)) { if (r == 0) { mesh1.CreateCurveEdge(ce.center, ce.radius, ce.normal); mesh2.CreateCurveEdge(ce.center, ce.radius, ce.normal); } else if (r > 0) { mesh1.CreateCurveEdge(ce.center, ce.radius, ce.normal); } else { mesh2.CreateCurveEdge(ce.center, ce.radius, ce.normal); } } else { float sin = Vector3.Cross(normal.normalized, ce.normal.normalized).magnitude; float h = MHelperFunctions.DistanceP2F(ce.center.position, normal, planePoint); float thresh = h / ce.radius; if (sin <= thresh) //不相交 { if (r > 0) { mesh1.CreateCurveEdge(ce.center, ce.radius, ce.normal); } else { mesh2.CreateCurveEdge(ce.center, ce.radius, ce.normal); } } else //相交 { foreach (MFace face in ce.faces) { facesNeedSplit.Add(face); } Vector3 p; Vector3 centerProjection = MHelperFunctions.PointProjectionInFace(ce.center.position, normal, planePoint); if (!MHelperFunctions.Perpendicular(ce.normal, normal)) { Vector3 intersection = MHelperFunctions.IntersectionLineWithFace(ce.normal, ce.center.position, normal, planePoint); p = (centerProjection - intersection).normalized * (h * h / Vector3.Distance(centerProjection, intersection)) + centerProjection; } else { p = centerProjection; } Vector3 n = Vector3.Cross(normal, ce.normal).normalized; float l = Vector3.Distance(p, ce.center.position); float d = Mathf.Sqrt(ce.radius * ce.radius - l * l); Vector3 secp1 = p + n * d; Vector3 secp2 = p - n * d; List<MEdge> edgeList = new List<MEdge>(); List<Vector3> points1 = MHelperFunctions.GenerateArcPoint(secp1, secp2, ce.normal, ce.center.position); List<Vector3> points2 = MHelperFunctions.GenerateArcPoint(secp2, secp1, ce.normal, ce.center.position); int count1 = points1.Count; int count2 = points2.Count; Vector3 sample = count1 >= count2 ? points1[count1/2] : points2[count2/2]; r = MHelperFunctions.FloatZero(Vector3.Dot(sample, normal)); if((r > 0 && points1.Count >= points2.Count) || (r < 0 && points1.Count < points2.Count)) { edgeList.Add(mesh1.CreateGeneralEdge(points1)); edgeList.Add(mesh2.CreateGeneralEdge(points2)); } else { edgeList.Add(mesh1.CreateGeneralEdge(points2)); edgeList.Add(mesh2.CreateGeneralEdge(points1)); } edgeMap.Add(ce, edgeList); } } break; } case MEdge.MEdgeType.GENERAL: { MGeneralEdge ge = edge as MGeneralEdge; Vector3 p; int r; int topHalf = 0; int count = ge.points.Count; List<Vector3> points = new List<Vector3>(); for(int i = 0; i < count; i++) { p = ge.points[i]; r = MHelperFunctions.FloatZero(Vector3.Dot(p - planePoint, normal)); if(topHalf != 0) { if(r > 0 && topHalf < 0) { Vector3 intersection = MHelperFunctions.IntersectionLineWithFace(p - ge.points[i - 1], p, normal, planePoint); points.Add(intersection); mesh2.CreateGeneralEdge(points); points = new List<Vector3>(); points.Add(intersection); topHalf = 1; } else if(r < 0 && topHalf > 0) { Vector3 intersection = MHelperFunctions.IntersectionLineWithFace(p - ge.points[i - 1], p, normal, planePoint); points.Add(intersection); mesh1.CreateGeneralEdge(points); points = new List<Vector3>(); points.Add(intersection); topHalf = -1; } } else { topHalf = r; } points.Add(p); } if(points.Count > 1) { if(topHalf > 0) { mesh1.CreateGeneralEdge(points); } else { mesh2.CreateGeneralEdge(points); } } break; } } } List<List<Vector3>> splitPoints = new List<List<Vector3>>(); Dictionary<Vector3, List<KeyValuePair<Vector3, int>>> splitGraph = new Dictionary<Vector3, List<KeyValuePair<Vector3, int>>>(); foreach(MFace face in mesh.faceList) { switch (face.faceType) { case MFace.MFaceType.CIRCLE: { MCircleFace cirf = face as MCircleFace; if (facesNeedSplit.Contains(cirf)) { List<MEdge> edges; if (!edgeMap.TryGetValue(cirf.circle, out edges)) break; List<Vector3> points1 = new List<Vector3>(((MGeneralEdge)edges[0]).points); List<Vector3> points2 = new List<Vector3>(((MGeneralEdge)edges[1]).points); List<Vector3> split = new List<Vector3>(); split.Add(points1[0]); split.Add(points2[0]); int count = splitPoints.Count; splitPoints.Add(split); MHelperFunctions.AddValToDictionary(splitGraph, points1[0], points2[0], count); MHelperFunctions.AddValToDictionary(splitGraph, points2[0], points1[0], count); mesh1.CreateLinearEdge(new MPoint(points1[0]), new MPoint(points2[0])); mesh2.CreateLinearEdge(new MPoint(points1[0]), new MPoint(points2[0])); points1.Add(points1[0]); points2.Add(points2[0]); mesh1.CreateGeneralFlatFace(points1); mesh2.CreateGeneralFlatFace(points2); } else { int r = MHelperFunctions.FloatZero(Vector3.Dot(cirf.circle.center.position - planePoint, normal)); if(r == 0) { mesh1.CreateCircleFace(new MCurveEdge(new MPoint(cirf.circle.center.position), cirf.circle.normal, cirf.circle.radius)); mesh2.CreateCircleFace(new MCurveEdge(new MPoint(cirf.circle.center.position), cirf.circle.normal, cirf.circle.radius)); } else if(r > 0) { mesh1.CreateCircleFace(new MCurveEdge(new MPoint(cirf.circle.center.position), cirf.circle.normal, cirf.circle.radius)); } else { mesh2.CreateCircleFace(new MCurveEdge(new MPoint(cirf.circle.center.position), cirf.circle.normal, cirf.circle.radius)); } } break; } case MFace.MFaceType.CONE: case MFace.MFaceType.CYLINDER: case MFace.MFaceType.GENERAL_CURVE: { List<List<Vector3>> split; List<Mesh> meshs = MHelperFunctions.MeshSplit(face.mesh, normal, planePoint, out split); mesh1.CreateGeneralCurveFace(meshs[0]); mesh2.CreateGeneralCurveFace(meshs[1]); foreach(List<Vector3> l in split) { if(l.Count < 2) { Debug.Log("unexpected list count"); continue; } if(MHelperFunctions.BlurEqual(l[0], l[l.Count - 1])) { mesh1.CreateGeneralFlatFace(l); mesh2.CreateGeneralFlatFace(l); } else { int count = splitPoints.Count; splitPoints.Add(l); MHelperFunctions.AddValToDictionary(splitGraph, l[0], l[l.Count - 1], count); MHelperFunctions.AddValToDictionary(splitGraph, l[l.Count - 1],l[0], count); } if (MHelperFunctions.PointsInLine(l)) { mesh1.CreateLinearEdge(new MPoint(l[0]), new MPoint(l[l.Count - 1])); mesh2.CreateLinearEdge(new MPoint(l[0]), new MPoint(l[l.Count - 1])); } else { mesh1.CreateGeneralEdge(new List<Vector3>(l)); mesh2.CreateGeneralEdge(new List<Vector3>(l)); } } break; } case MFace.MFaceType.SPHERE: { MSphereFace sf = face as MSphereFace; List<List<Vector3>> split; List<Mesh> meshs = MHelperFunctions.MeshSplit(face.mesh, normal, planePoint, out split); mesh1.CreateGeneralCurveFace(meshs[0]); mesh2.CreateGeneralCurveFace(meshs[1]); Vector3 projCenter = MHelperFunctions.PointProjectionInFace(sf.center.position, normal, planePoint); float dis = Vector3.Distance(sf.center.position, projCenter); if(dis < sf.radius) { float r = Mathf.Sqrt(sf.radius * sf.radius - dis * dis); MCurveEdge ce = mesh1.CreateCurveEdge(new MPoint(projCenter), r, normal); mesh1.CreateCircleFace(ce); ce = mesh2.CreateCurveEdge(new MPoint(projCenter), r, normal); mesh2.CreateCircleFace(ce); } break; } case MFace.MFaceType.POLYGON: { MPolygonFace polyf = face as MPolygonFace; if (facesNeedSplit.Contains(polyf)) { List<MEdge> edges; List<MLinearEdge> edges1 = new List<MLinearEdge>(); List<MLinearEdge> edges2 = new List<MLinearEdge>(); List<Vector3> split = new List<Vector3>(); foreach(MLinearEdge edge in polyf.edgeList) { if(edgeMap.TryGetValue(edge, out edges)) { MLinearEdge le = edges[0] as MLinearEdge; edges1.Add(new MLinearEdge(new MPoint(le.start.position), new MPoint(le.end.position))); split.Add(le.end.position); le = edges[1] as MLinearEdge; edges2.Add(new MLinearEdge(new MPoint(le.start.position), new MPoint(le.end.position))); } else { int r1 = MHelperFunctions.FloatZero(Vector3.Dot(edge.start.position - planePoint, normal)); int r2 = MHelperFunctions.FloatZero(Vector3.Dot(edge.end.position - planePoint, normal)); if (r1 == 0 && r2 == 0) { edges1.Add(new MLinearEdge(new MPoint(edge.start.position), new MPoint(edge.end.position))); edges2.Add(new MLinearEdge(new MPoint(edge.start.position), new MPoint(edge.end.position))); } else if(r1 >= 0 && r2 >= 0) { edges1.Add(new MLinearEdge(new MPoint(edge.start.position), new MPoint(edge.end.position))); } else if(r1 <= 0 && r2 <= 0) { edges2.Add(new MLinearEdge(new MPoint(edge.start.position), new MPoint(edge.end.position))); } else { Debug.Log("r1: " + r1 + ", r2: " + r2); } } } if(split.Count != 2) { // TODO: 非凸多边形 被分割成了大于2个面 Debug.Log("unexpected split count"); continue; } else { edges1.Add(new MLinearEdge(new MPoint(split[0]), new MPoint(split[1]))); edges2.Add(new MLinearEdge(new MPoint(split[0]), new MPoint(split[1]))); } int count = splitPoints.Count; splitPoints.Add(split); MHelperFunctions.AddValToDictionary(splitGraph, split[0], split[1], count); MHelperFunctions.AddValToDictionary(splitGraph, split[1], split[0], count); mesh1.CreatePolygonFace(edges1); mesh2.CreatePolygonFace(edges2); } else { int r = MHelperFunctions.FloatZero(Vector3.Dot(polyf.edgeList[0].start.position - planePoint, normal)); if (r == 0) { List<MLinearEdge> edges1 = new List<MLinearEdge>(); List<MLinearEdge> edges2 = new List<MLinearEdge>(); foreach(MLinearEdge e in polyf.edgeList) { edges1.Add(new MLinearEdge(new MPoint(e.start.position), new MPoint(e.end.position))); edges2.Add(new MLinearEdge(new MPoint(e.start.position), new MPoint(e.end.position))); } mesh1.CreatePolygonFace(edges1); mesh2.CreatePolygonFace(edges2); } else { List<MLinearEdge> edges = new List<MLinearEdge>(); foreach (MLinearEdge e in polyf.edgeList) { edges.Add(new MLinearEdge(new MPoint(e.start.position), new MPoint(e.end.position))); } if(r > 0) { mesh1.CreatePolygonFace(edges); } else { mesh2.CreatePolygonFace(edges); } } } break; } case MFace.MFaceType.GENERAL_FLAT: { MGeneralFlatFace gff = face as MGeneralFlatFace; List<Vector3> points1 = new List<Vector3>(); List<Vector3> points2 = new List<Vector3>(); List<Vector3> split = new List<Vector3>(); Vector3 p; int lastr = 0; int r; int count = gff.points.Count; for (int i = 0; i < count; i++) { p = gff.points[i]; r = MHelperFunctions.FloatZero(Vector3.Dot(p - planePoint, normal)); if(lastr >= 0 && r >= 0) { points1.Add(p); } else if(lastr <= 0 && r <= 0) { points2.Add(p); } else { Vector3 intersect = MHelperFunctions.IntersectionLineWithFace(p - gff.points[i - 1], p, normal, planePoint); split.Add(intersect); points1.Add(intersect); points2.Add(intersect); if(r > 0) { points1.Add(p); } else { points2.Add(p); } } lastr = r; } if (split.Count != 2) { // TODO: 非凸多边形 被分割成了大于2个面 Debug.Log("unexpected split count"); continue; } else { mesh1.CreateLinearEdge(new MPoint(split[0]), new MPoint(split[1])); mesh2.CreateLinearEdge(new MPoint(split[0]), new MPoint(split[1])); } int cnt = splitPoints.Count; splitPoints.Add(split); MHelperFunctions.AddValToDictionary(splitGraph, split[0], split[1], cnt); MHelperFunctions.AddValToDictionary(splitGraph, split[1], split[0], cnt); mesh1.CreateGeneralFlatFace(points1); mesh2.CreateGeneralFlatFace(points2); break; } } } List<List<Vector3>> loops = MHelperFunctions.GroupLoop(splitGraph, splitPoints); foreach(List<Vector3> list in loops) { mesh1.CreateGeneralFlatFace(list); mesh2.CreateGeneralFlatFace(list); } List<MObject> objects = new List<MObject>(); if (!mesh1.IsEmpty()) { MObject obj = new MObject(template, mesh1); obj.transform.position = transform.position; obj.transform.rotation = transform.rotation; obj.transform.localScale = transform.localScale; objects.Add(obj); } if (!mesh2.IsEmpty()) { MObject obj = new MObject(template, mesh2); obj.transform.position = transform.position; obj.transform.rotation = transform.rotation; obj.transform.localScale = transform.localScale; objects.Add(obj); } return objects; }
public bool ExportObject(string filename) { StringBuilder sb = new StringBuilder(); List<MPoint> pointList = mesh.pointList; List<MEdge> edgeList = mesh.edgeList; List<MFace> faceList = mesh.faceList; foreach(MPoint point in pointList) { sb.Append(string.Format("p {0} {1} {2}\n", point.position.x, point.position.y, point.position.z)); } foreach(MEdge edge in edgeList) { switch (edge.edgeType) { case MEdge.MEdgeType.LINEAR: int start = pointList.IndexOf(((MLinearEdge)edge).start); int end = pointList.IndexOf(((MLinearEdge)edge).end); sb.Append(string.Format("le {0} {1}\n", start, end)); break; case MEdge.MEdgeType.CURVE: MCurveEdge ce = edge as MCurveEdge; int center = pointList.IndexOf(ce.center); sb.Append(string.Format("ce {0} {1} {2} {3} {4}\n", center, ce.radius, ce.normal.x, ce.normal.y, ce.normal.z)); break; case MEdge.MEdgeType.GENERAL: MGeneralEdge ge = edge as MGeneralEdge; sb.Append("ge\n"); foreach(Vector3 v in ge.points) { sb.Append(string.Format("v {0} {1} {2}\n", v.x, v.y, v.z)); } break; } } foreach(MFace face in faceList) { switch (face.faceType) { case MFace.MFaceType.POLYGON: sb.Append("polyf\n"); foreach(MLinearEdge edge in ((MPolygonFace)face).edgeList) { int index = edgeList.IndexOf(edge); sb.Append(string.Format("e {0}\n", index)); } break; case MFace.MFaceType.CIRCLE: MCircleFace circf = face as MCircleFace; int circle = edgeList.IndexOf(circf.circle); sb.Append(string.Format("circf {0}\n", circle)); break; case MFace.MFaceType.CONE: MConeFace conf = face as MConeFace; int top = pointList.IndexOf(conf.top); int bottom = edgeList.IndexOf(conf.bottom); sb.Append(string.Format("conf {0} {1}\n", top, bottom)); break; case MFace.MFaceType.CYLINDER: MCylinderFace cylindf = face as MCylinderFace; top = edgeList.IndexOf(cylindf.top); bottom = edgeList.IndexOf(cylindf.bottom); sb.Append(string.Format("cylf {0} {1}\n", top, bottom)); break; case MFace.MFaceType.SPHERE: MSphereFace sf = face as MSphereFace; int center = pointList.IndexOf(sf.center); sb.Append(string.Format("sf {0} {1}\n", center, sf.radius)); break; case MFace.MFaceType.GENERAL_FLAT: MGeneralFlatFace gff = face as MGeneralFlatFace; sb.Append("gff\n"); foreach (Vector3 v in gff.points) { sb.Append(string.Format("v {0} {1} {2}\n", v.x, v.y, v.z)); } break; case MFace.MFaceType.GENERAL_CURVE: MGeneralCurveFace gcf = face as MGeneralCurveFace; sb.Append("gcf\n"); foreach(Vector3 v in gcf.mesh.vertices) { sb.Append(string.Format("v {0} {1} {2}\n", v.x, v.y, v.z)); } int count = gcf.mesh.triangles.Length / 3; for(int i = 0; i < count; i++) { sb.Append(string.Format("f {0} {1} {2}\n", gcf.mesh.triangles[3 * i], gcf.mesh.triangles[3 * i + 1], gcf.mesh.triangles[3 * i + 2])); } break; } } if (!Directory.Exists(MDefinitions.SAVE_PATH)) { Directory.CreateDirectory(MDefinitions.SAVE_PATH); } using (StreamWriter sw = new StreamWriter(MDefinitions.SAVE_PATH+"/" + filename)) { sw.Write(sb.ToString()); sw.Flush(); sw.Close(); } return true; }