public static Mesh[] SplitIntoMeshesOnOrthographicZ(Mesh meshToSplit, Vector3 buildVolume, ReportProgressRatio reportProgress) { // check if the part is bigger than the build plate (if it is we need to use that as our size) AxisAlignedBoundingBox partBounds = meshToSplit.GetAxisAlignedBoundingBox(); buildVolume.x = Math.Max(buildVolume.x, partBounds.XSize + 2); buildVolume.y = Math.Max(buildVolume.y, partBounds.YSize + 2); buildVolume.z = Math.Max(buildVolume.z, partBounds.ZSize + 2); // Find all the separate objects that are on the plate // Create a 2D image the size of the printer bed at some scale with the parts draw on it top down double scaleFactor = 5; ImageBuffer partPlate = new ImageBuffer((int)(buildVolume.x * scaleFactor), (int)(buildVolume.y * scaleFactor), 32, new BlenderBGRA()); Vector2 renderOffset = new Vector2(buildVolume.x / 2, buildVolume.y / 2) - new Vector2(partBounds.Center.x, partBounds.Center.y); PolygonMesh.Rendering.OrthographicZProjection.DrawTo(partPlate.NewGraphics2D(), meshToSplit, renderOffset, scaleFactor, RGBA_Bytes.White); bool continueProcessin = true; if (reportProgress != null) { reportProgress(.2, "", out continueProcessin); } //ImageIO.SaveImageData("test part plate 0.png", partPlate); // expand the bounds a bit so that we can collect all the vertices and polygons within each bound Dilate.DoDilate3x3Binary(partPlate, 1); //ImageIO.SaveImageData("test part plate 1.png", partPlate); // trace all the bounds of the objects on the plate PolyTree polyTreeForPlate = FindDistictObjectBounds(partPlate); if (polyTreeForPlate == null) { Mesh[] singleMesh = new Mesh[1]; singleMesh[0] = meshToSplit; return singleMesh; } // get all the discrete areas that are polygons so we can search them Polygons discreteAreas = new Polygons(); GetAreasRecursive(polyTreeForPlate, discreteAreas); if (discreteAreas.Count == 0) { return null; } else if (discreteAreas.Count == 1) { Mesh[] singleMesh = new Mesh[1]; singleMesh[0] = meshToSplit; return singleMesh; } Graphics2D graphics2D = partPlate.NewGraphics2D(); graphics2D.Clear(RGBA_Bytes.Black); Random rand = new Random(); foreach (Polygon polygon in discreteAreas) { graphics2D.Render(PlatingHelper.PolygonToPathStorage(polygon), new RGBA_Bytes(rand.Next(128, 255), rand.Next(128, 255), rand.Next(128, 255))); } if (reportProgress != null) { reportProgress(.5, "", out continueProcessin); } //ImageIO.SaveImageData("test part plate 2.png", partPlate); // add each of the separate bounds polygons to new meshes Mesh[] discreteMeshes = new Mesh[discreteAreas.Count]; for (int i = 0; i < discreteAreas.Count; i++) { discreteMeshes[i] = new Mesh(); } foreach (Face face in meshToSplit.Faces) { bool faceDone = false; // figure out which area one or more of the vertices are in add the face to the right new mesh foreach (FaceEdge faceEdge in face.FaceEdges()) { Vector2 position = new Vector2(faceEdge.firstVertex.Position.x, faceEdge.firstVertex.Position.y); position += renderOffset; position *= scaleFactor; for (int areaIndex = discreteAreas.Count - 1; areaIndex >= 0; areaIndex--) { if (PointInPolygon(discreteAreas[areaIndex], new IntPoint((int)position.x, (int)position.y))) { List<Vertex> faceVertices = new List<Vertex>(); foreach (FaceEdge faceEdgeToAdd in face.FaceEdges()) { Vertex newVertex = discreteMeshes[areaIndex].CreateVertex(faceEdgeToAdd.firstVertex.Position); faceVertices.Add(newVertex); } discreteMeshes[areaIndex].CreateFace(faceVertices.ToArray()); faceDone = true; break; } } if (faceDone) { break; } } } if (reportProgress != null) { reportProgress(.8, "", out continueProcessin); } for (int i = 0; i < discreteMeshes.Count(); i++) { Mesh mesh = discreteMeshes[i]; } return discreteMeshes; }