public void DoProcessing() { if (!gcode.IsOpened()) { return; } timeKeeper.Restart(); LogOutput.Log("Analyzing and optimizing model...\n"); optomizedModel = new OptimizedModel(simpleModel); if (MatterSlice.Canceled) { return; } optomizedModel.SetPositionAndSize(simpleModel, config.positionToPlaceObjectCenter_um.X, config.positionToPlaceObjectCenter_um.Y, -config.bottomClipAmount_um, config.centerObjectInXy); for (int volumeIndex = 0; volumeIndex < simpleModel.volumes.Count; volumeIndex++) { LogOutput.Log(" Face counts: {0} . {1} {2:0.0}%\n".FormatWith((int)simpleModel.volumes[volumeIndex].faceTriangles.Count, (int)optomizedModel.volumes[volumeIndex].facesTriangle.Count, (double)(optomizedModel.volumes[volumeIndex].facesTriangle.Count) / (double)(simpleModel.volumes[volumeIndex].faceTriangles.Count) * 100)); LogOutput.Log(" Vertex counts: {0} . {1} {2:0.0}%\n".FormatWith((int)simpleModel.volumes[volumeIndex].faceTriangles.Count * 3, (int)optomizedModel.volumes[volumeIndex].vertices.Count, (double)(optomizedModel.volumes[volumeIndex].vertices.Count) / (double)(simpleModel.volumes[volumeIndex].faceTriangles.Count * 3) * 100)); } LogOutput.Log("Optimize model {0:0.0}s \n".FormatWith(timeKeeper.Elapsed.Seconds)); timeKeeper.Reset(); Stopwatch timeKeeperTotal = new Stopwatch(); timeKeeperTotal.Start(); preSetup(config.extrusionWidth_um); sliceModels(storage); processSliceData(storage); if (MatterSlice.Canceled) { return; } writeGCode(storage); if (MatterSlice.Canceled) { return; } LogOutput.logProgress("process", 1, 1); //Report to the GUI that a file has been fully processed. LogOutput.Log("Total time elapsed {0:0.00}s.\n".FormatWith(timeKeeperTotal.Elapsed.Seconds)); }
public void GenerateSupportGrid(OptimizedModel model, ConfigSettings config) { this.generated = false; if (config.supportEndAngle < 0) { return; } this.generated = true; this.gridOffset.X = model.minXYZ_um.x; this.gridOffset.Y = model.minXYZ_um.y; this.gridScale = 200; this.gridWidth = (model.size_um.x / this.gridScale) + 1; this.gridHeight = (model.size_um.y / this.gridScale) + 1; int gridSize = this.gridWidth * this.gridHeight; this.xYGridOfSupportPoints = new List <List <SupportPoint> >(gridSize); for (int i = 0; i < gridSize; i++) { this.xYGridOfSupportPoints.Add(new List <SupportPoint>()); } this.endAngleDegrees = config.supportEndAngle; this.generateInternalSupport = config.generateInternalSupport; this.supportXYDistance_um = config.supportXYDistance_um; this.supportLayerHeight_um = config.layerThickness_um; this.supportZGapLayers = config.supportNumberOfLayersToSkipInZ; this.supportInterfaceLayers = config.supportInterfaceLayers; // This should really be a ray intersection as later code is going to count on it being an even odd list of bottoms and tops. // As it is we are finding the hit on the plane but not checking for good intersection with the triangle. for (int volumeIndex = 0; volumeIndex < model.volumes.Count; volumeIndex++) { OptimizedVolume vol = model.volumes[volumeIndex]; for (int faceIndex = 0; faceIndex < vol.facesTriangle.Count; faceIndex++) { OptimizedFace faceTriangle = vol.facesTriangle[faceIndex]; Point3 v0 = vol.vertices[faceTriangle.vertexIndex[0]].position; Point3 v1 = vol.vertices[faceTriangle.vertexIndex[1]].position; Point3 v2 = vol.vertices[faceTriangle.vertexIndex[2]].position; // get the angle of this polygon double angleFromHorizon; { FPoint3 v0f = new FPoint3(v0); FPoint3 v1f = new FPoint3(v1); FPoint3 v2f = new FPoint3(v2); FPoint3 normal = (v1f - v0f).Cross(v2f - v0f); normal.z = Math.Abs(normal.z); angleFromHorizon = (Math.PI / 2) - FPoint3.CalculateAngle(normal, FPoint3.Up); } v0.x = (int)((v0.x - this.gridOffset.X) / (double)this.gridScale + .5); v0.y = (int)((v0.y - this.gridOffset.Y) / (double)this.gridScale + .5); v1.x = (int)((v1.x - this.gridOffset.X) / (double)this.gridScale + .5); v1.y = (int)((v1.y - this.gridOffset.Y) / (double)this.gridScale + .5); v2.x = (int)((v2.x - this.gridOffset.X) / (double)this.gridScale + .5); v2.y = (int)((v2.y - this.gridOffset.Y) / (double)this.gridScale + .5); if (v0.x > v1.x) { swap(ref v0, ref v1); } if (v1.x > v2.x) { swap(ref v1, ref v2); } if (v0.x > v1.x) { swap(ref v0, ref v1); } for (long x = v0.x; x < v1.x; x++) { long y0 = (long)(v0.y + (v1.y - v0.y) * (x - v0.x) / (double)(v1.x - v0.x) + .5); long y1 = (long)(v0.y + (v2.y - v0.y) * (x - v0.x) / (double)(v2.x - v0.x) + .5); long z0 = (long)(v0.z + (v1.z - v0.z) * (x - v0.x) / (double)(v1.x - v0.x) + .5); long z1 = (long)(v0.z + (v2.z - v0.z) * (x - v0.x) / (double)(v2.x - v0.x) + .5); if (y0 > y1) { swap(ref y0, ref y1); swap(ref z0, ref z1); } for (long y = y0; y < y1; y++) { SupportPoint newSupportPoint = new SupportPoint((int)(z0 + (z1 - z0) * (y - y0) / (double)(y1 - y0) + .5), angleFromHorizon); this.xYGridOfSupportPoints[(int)(x + y * this.gridWidth)].Add(newSupportPoint); } } for (int x = v1.x; x < v2.x; x++) { long y0 = (long)(v1.y + (v2.y - v1.y) * (x - v1.x) / (double)(v2.x - v1.x) + .5); long y1 = (long)(v0.y + (v2.y - v0.y) * (x - v0.x) / (double)(v2.x - v0.x) + .5); long z0 = (long)(v1.z + (v2.z - v1.z) * (x - v1.x) / (double)(v2.x - v1.x) + .5); long z1 = (long)(v0.z + (v2.z - v0.z) * (x - v0.x) / (double)(v2.x - v0.x) + .5); if (y0 > y1) { swap(ref y0, ref y1); swap(ref z0, ref z1); } for (int y = (int)y0; y < y1; y++) { this.xYGridOfSupportPoints[x + y * this.gridWidth].Add(new SupportPoint((int)(z0 + (z1 - z0) * (double)(y - y0) / (double)(y1 - y0) + .5), angleFromHorizon)); } } } } for (int x = 0; x < this.gridWidth; x++) { for (int y = 0; y < this.gridHeight; y++) { int gridIndex = x + y * this.gridWidth; List <SupportPoint> currentList = this.xYGridOfSupportPoints[gridIndex]; currentList.Sort(SortSupportsOnZ); if (currentList.Count > 1) { // now remove duplicates (try to make it a better bottom and top list) for (int i = currentList.Count - 1; i >= 1; i--) { if (currentList[i].z == currentList[i - 1].z) { currentList.RemoveAt(i); } } } } } this.gridOffset.X += this.gridScale / 2; this.gridOffset.Y += this.gridScale / 2; }
public OptimizedVolume(SimpleVolume volume, OptimizedModel model) { this.model = model; vertices.Capacity = volume.faceTriangles.Count * 3; facesTriangle.Capacity = volume.faceTriangles.Count; Dictionary <int, List <int> > indexMap = new Dictionary <int, List <int> >(); Stopwatch t = new Stopwatch(); t.Start(); for (int i = 0; i < volume.faceTriangles.Count; i++) { OptimizedFace f = new OptimizedFace(); if ((i % 1000 == 0) && t.Elapsed.Seconds > 2) { LogOutput.logProgress("optimized", i + 1, volume.faceTriangles.Count); } for (int j = 0; j < 3; j++) { Point3 p = volume.faceTriangles[i].v[j]; int hash = (int)(((p.x + MELD_DIST / 2) / MELD_DIST) ^ (((p.y + MELD_DIST / 2) / MELD_DIST) << 10) ^ (((p.z + MELD_DIST / 2) / MELD_DIST) << 20)); int idx = 0; bool add = true; if (indexMap.ContainsKey(hash)) { for (int n = 0; n < indexMap[hash].Count; n++) { if ((vertices[indexMap[hash][n]].position - p).testLength(MELD_DIST)) { idx = indexMap[hash][n]; add = false; break; } } } if (add) { if (!indexMap.ContainsKey(hash)) { indexMap.Add(hash, new List <int>()); } indexMap[hash].Add(vertices.Count); idx = vertices.Count; vertices.Add(new OptimizedPoint3(p)); } f.vertexIndex[j] = idx; } if (f.vertexIndex[0] != f.vertexIndex[1] && f.vertexIndex[0] != f.vertexIndex[2] && f.vertexIndex[1] != f.vertexIndex[2]) { //Check if there is a face with the same points bool duplicate = false; for (int _idx0 = 0; _idx0 < vertices[f.vertexIndex[0]].usedByFacesList.Count; _idx0++) { for (int _idx1 = 0; _idx1 < vertices[f.vertexIndex[1]].usedByFacesList.Count; _idx1++) { for (int _idx2 = 0; _idx2 < vertices[f.vertexIndex[2]].usedByFacesList.Count; _idx2++) { if (vertices[f.vertexIndex[0]].usedByFacesList[_idx0] == vertices[f.vertexIndex[1]].usedByFacesList[_idx1] && vertices[f.vertexIndex[0]].usedByFacesList[_idx0] == vertices[f.vertexIndex[2]].usedByFacesList[_idx2]) { duplicate = true; } } } } if (!duplicate) { vertices[f.vertexIndex[0]].usedByFacesList.Add(facesTriangle.Count); vertices[f.vertexIndex[1]].usedByFacesList.Add(facesTriangle.Count); vertices[f.vertexIndex[2]].usedByFacesList.Add(facesTriangle.Count); facesTriangle.Add(f); } } } //fprintf(stdout, "\rAll faces are optimized in %5.1fs.\n",timeElapsed(t)); int openFacesCount = 0; for (int i = 0; i < facesTriangle.Count; i++) { OptimizedFace f = facesTriangle[i]; f.touchingFaces[0] = getFaceIdxWithPoints(f.vertexIndex[0], f.vertexIndex[1], i); f.touchingFaces[1] = getFaceIdxWithPoints(f.vertexIndex[1], f.vertexIndex[2], i); f.touchingFaces[2] = getFaceIdxWithPoints(f.vertexIndex[2], f.vertexIndex[0], i); if (f.touchingFaces[0] == -1) { openFacesCount++; } if (f.touchingFaces[1] == -1) { openFacesCount++; } if (f.touchingFaces[2] == -1) { openFacesCount++; } } //fprintf(stdout, " Number of open faces: %i\n", openFacesCount); }
public OptimizedVolume(SimpleVolume volume, OptimizedModel model) { this.parentModel = model; vertices.Capacity = volume.faceTriangles.Count * 3; facesTriangle.Capacity = volume.faceTriangles.Count; Dictionary <int, List <int> > indexMap = new Dictionary <int, List <int> >(); Stopwatch t = new Stopwatch(); t.Start(); for (int faceIndex = 0; faceIndex < volume.faceTriangles.Count; faceIndex++) { if (MatterSlice.Canceled) { return; } OptimizedFace optimizedFace = new OptimizedFace(); if ((faceIndex % 1000 == 0) && t.Elapsed.Seconds > 2) { LogOutput.logProgress("optimized", faceIndex + 1, volume.faceTriangles.Count); } for (int vertexIndex = 0; vertexIndex < 3; vertexIndex++) { Point3 p = volume.faceTriangles[faceIndex].vertices[vertexIndex]; int hash = (int)(((p.x + MELD_DIST / 2) / MELD_DIST) ^ (((p.y + MELD_DIST / 2) / MELD_DIST) << 10) ^ (((p.z + MELD_DIST / 2) / MELD_DIST) << 20)); int idx = 0; bool add = true; if (indexMap.ContainsKey(hash)) { for (int n = 0; n < indexMap[hash].Count; n++) { if ((vertices[indexMap[hash][n]].position - p).AbsLengthLEQ(MELD_DIST)) { idx = indexMap[hash][n]; add = false; break; } } } if (add) { if (!indexMap.ContainsKey(hash)) { indexMap.Add(hash, new List <int>()); } indexMap[hash].Add(vertices.Count); idx = vertices.Count; vertices.Add(new OptimizedPoint3(p)); } optimizedFace.vertexIndex[vertexIndex] = idx; } if (optimizedFace.vertexIndex[0] != optimizedFace.vertexIndex[1] && optimizedFace.vertexIndex[0] != optimizedFace.vertexIndex[2] && optimizedFace.vertexIndex[1] != optimizedFace.vertexIndex[2]) { //Check if there is a face with the same points bool duplicate = false; for (int _idx0 = 0; _idx0 < vertices[optimizedFace.vertexIndex[0]].usedByFacesList.Count; _idx0++) { for (int _idx1 = 0; _idx1 < vertices[optimizedFace.vertexIndex[1]].usedByFacesList.Count; _idx1++) { for (int _idx2 = 0; _idx2 < vertices[optimizedFace.vertexIndex[2]].usedByFacesList.Count; _idx2++) { if (vertices[optimizedFace.vertexIndex[0]].usedByFacesList[_idx0] == vertices[optimizedFace.vertexIndex[1]].usedByFacesList[_idx1] && vertices[optimizedFace.vertexIndex[0]].usedByFacesList[_idx0] == vertices[optimizedFace.vertexIndex[2]].usedByFacesList[_idx2]) { duplicate = true; } } } } if (!duplicate) { vertices[optimizedFace.vertexIndex[0]].usedByFacesList.Add(facesTriangle.Count); vertices[optimizedFace.vertexIndex[1]].usedByFacesList.Add(facesTriangle.Count); vertices[optimizedFace.vertexIndex[2]].usedByFacesList.Add(facesTriangle.Count); facesTriangle.Add(optimizedFace); } } } //fprintf(stdout, "\rAll faces are optimized in %5.1fs.\n",timeElapsed(t)); int openFacesCount = 0; for (int faceIndex = 0; faceIndex < facesTriangle.Count; faceIndex++) { OptimizedFace optimizedFace = facesTriangle[faceIndex]; optimizedFace.touchingFaces[0] = getOtherFaceIndexContainingVertices(optimizedFace.vertexIndex[0], optimizedFace.vertexIndex[1], faceIndex); optimizedFace.touchingFaces[1] = getOtherFaceIndexContainingVertices(optimizedFace.vertexIndex[1], optimizedFace.vertexIndex[2], faceIndex); optimizedFace.touchingFaces[2] = getOtherFaceIndexContainingVertices(optimizedFace.vertexIndex[2], optimizedFace.vertexIndex[0], faceIndex); if (optimizedFace.touchingFaces[0] == -1) { openFacesCount++; } if (optimizedFace.touchingFaces[1] == -1) { openFacesCount++; } if (optimizedFace.touchingFaces[2] == -1) { openFacesCount++; } } //fprintf(stdout, " Number of open faces: %i\n", openFacesCount); }
public void GenerateSupportGrid(OptimizedModel model, ConfigSettings config) { this.generated = false; if (config.supportEndAngle < 0) { return; } this.generated = true; this.gridOffset.X = model.minXYZ_um.x; this.gridOffset.Y = model.minXYZ_um.y; this.gridScale = 200; this.gridWidth = (model.size_um.x / this.gridScale) + 1; this.gridHeight = (model.size_um.y / this.gridScale) + 1; int gridSize = this.gridWidth * this.gridHeight; this.xYGridOfSupportPoints = new List<List<SupportPoint>>(gridSize); for (int i = 0; i < gridSize; i++) { this.xYGridOfSupportPoints.Add(new List<SupportPoint>()); } this.endAngleDegrees = config.supportEndAngle; this.generateInternalSupport = config.generateInternalSupport; this.supportXYDistance_um = config.supportXYDistance_um; this.supportLayerHeight_um = config.layerThickness_um; this.supportZGapLayers = config.supportNumberOfLayersToSkipInZ; this.supportInterfaceLayers = config.supportInterfaceLayers; // This should really be a ray intersection as later code is going to count on it being an even odd list of bottoms and tops. // As it is we are finding the hit on the plane but not checking for good intersection with the triangle. for (int volumeIndex = 0; volumeIndex < model.volumes.Count; volumeIndex++) { OptimizedVolume vol = model.volumes[volumeIndex]; for (int faceIndex = 0; faceIndex < vol.facesTriangle.Count; faceIndex++) { OptimizedFace faceTriangle = vol.facesTriangle[faceIndex]; Point3 v0 = vol.vertices[faceTriangle.vertexIndex[0]].position; Point3 v1 = vol.vertices[faceTriangle.vertexIndex[1]].position; Point3 v2 = vol.vertices[faceTriangle.vertexIndex[2]].position; // get the angle of this polygon double angleFromHorizon; { FPoint3 v0f = new FPoint3(v0); FPoint3 v1f = new FPoint3(v1); FPoint3 v2f = new FPoint3(v2); FPoint3 normal = (v1f - v0f).Cross(v2f - v0f); normal.z = Math.Abs(normal.z); angleFromHorizon = (Math.PI / 2) - FPoint3.CalculateAngle(normal, FPoint3.Up); } v0.x = (int)((v0.x - this.gridOffset.X) / (double)this.gridScale + .5); v0.y = (int)((v0.y - this.gridOffset.Y) / (double)this.gridScale + .5); v1.x = (int)((v1.x - this.gridOffset.X) / (double)this.gridScale + .5); v1.y = (int)((v1.y - this.gridOffset.Y) / (double)this.gridScale + .5); v2.x = (int)((v2.x - this.gridOffset.X) / (double)this.gridScale + .5); v2.y = (int)((v2.y - this.gridOffset.Y) / (double)this.gridScale + .5); if (v0.x > v1.x) swap(ref v0, ref v1); if (v1.x > v2.x) swap(ref v1, ref v2); if (v0.x > v1.x) swap(ref v0, ref v1); for (long x = v0.x; x < v1.x; x++) { long y0 = (long)(v0.y + (v1.y - v0.y) * (x - v0.x) / (double)(v1.x - v0.x) + .5); long y1 = (long)(v0.y + (v2.y - v0.y) * (x - v0.x) / (double)(v2.x - v0.x) + .5); long z0 = (long)(v0.z + (v1.z - v0.z) * (x - v0.x) / (double)(v1.x - v0.x) + .5); long z1 = (long)(v0.z + (v2.z - v0.z) * (x - v0.x) / (double)(v2.x - v0.x) + .5); if (y0 > y1) { swap(ref y0, ref y1); swap(ref z0, ref z1); } for (long y = y0; y < y1; y++) { SupportPoint newSupportPoint = new SupportPoint((int)(z0 + (z1 - z0) * (y - y0) / (double)(y1 - y0) + .5), angleFromHorizon); this.xYGridOfSupportPoints[(int)(x + y * this.gridWidth)].Add(newSupportPoint); } } for (int x = v1.x; x < v2.x; x++) { long y0 = (long)(v1.y + (v2.y - v1.y) * (x - v1.x) / (double)(v2.x - v1.x) + .5); long y1 = (long)(v0.y + (v2.y - v0.y) * (x - v0.x) / (double)(v2.x - v0.x) + .5); long z0 = (long)(v1.z + (v2.z - v1.z) * (x - v1.x) / (double)(v2.x - v1.x) + .5); long z1 = (long)(v0.z + (v2.z - v0.z) * (x - v0.x) / (double)(v2.x - v0.x) + .5); if (y0 > y1) { swap(ref y0, ref y1); swap(ref z0, ref z1); } for (int y = (int)y0; y < y1; y++) { this.xYGridOfSupportPoints[x + y * this.gridWidth].Add(new SupportPoint((int)(z0 + (z1 - z0) * (double)(y - y0) / (double)(y1 - y0) + .5), angleFromHorizon)); } } } } for (int x = 0; x < this.gridWidth; x++) { for (int y = 0; y < this.gridHeight; y++) { int gridIndex = x + y * this.gridWidth; List<SupportPoint> currentList = this.xYGridOfSupportPoints[gridIndex]; currentList.Sort(SortSupportsOnZ); if (currentList.Count > 1) { // now remove duplicates (try to make it a better bottom and top list) for (int i = currentList.Count - 1; i >= 1; i--) { if (currentList[i].z == currentList[i - 1].z) { currentList.RemoveAt(i); } } } } } this.gridOffset.X += this.gridScale / 2; this.gridOffset.Y += this.gridScale / 2; }