public bool RemovePerimeterOverlaps(List <Point3> perimeter, long overlapMergeAmount_um, out List <PathAndWidth> separatedPolygons, bool pathIsClosed = true) { bool pathWasOptomized = false; perimeter = MakeCloseSegmentsMergable(perimeter, overlapMergeAmount_um); // make a copy that has every point duplicated (so that we have them as segments). List <Segment> polySegments = Segment.ConvertPathToSegments(perimeter, pathIsClosed); Altered[] markedAltered = new Altered[polySegments.Count]; int segmentCount = polySegments.Count; // now walk every segment and check if there is another segment that is similar enough to merge them together for (int firstSegmentIndex = 0; firstSegmentIndex < segmentCount; firstSegmentIndex++) { for (int checkSegmentIndex = firstSegmentIndex + 1; checkSegmentIndex < segmentCount; checkSegmentIndex++) { // The first point of start and the last point of check (the path will be coming back on itself). long startDelta = (polySegments[firstSegmentIndex].Start - polySegments[checkSegmentIndex].End).Length(); // if the segments are similar enough if (startDelta < overlapMergeAmount_um) { // The last point of start and the first point of check (the path will be coming back on itself). long endDelta = (polySegments[firstSegmentIndex].End - polySegments[checkSegmentIndex].Start).Length(); if (endDelta < overlapMergeAmount_um) { pathWasOptomized = true; // move the first segments points to the average of the merge positions long startEndWidth = Math.Abs((polySegments[firstSegmentIndex].Start - polySegments[checkSegmentIndex].End).Length()); long endStartWidth = Math.Abs((polySegments[firstSegmentIndex].End - polySegments[checkSegmentIndex].Start).Length()); polySegments[firstSegmentIndex].Width = Math.Min(startEndWidth, endStartWidth); polySegments[firstSegmentIndex].Start = (polySegments[firstSegmentIndex].Start + polySegments[checkSegmentIndex].End) / 2; // the start polySegments[firstSegmentIndex].End = (polySegments[firstSegmentIndex].End + polySegments[checkSegmentIndex].Start) / 2; // the end markedAltered[firstSegmentIndex] = Altered.merged; // mark this segment for removal markedAltered[checkSegmentIndex] = Altered.remove; // We only expect to find one match for each segment, so move on to the next segment break; } } } } // remove the marked segments for (int segmentIndex = segmentCount - 1; segmentIndex >= 0; segmentIndex--) { if (markedAltered[segmentIndex] == Altered.remove) { polySegments.RemoveAt(segmentIndex); } } // go through the polySegments and create a new polygon for every connected set of segments separatedPolygons = new List <PathAndWidth>(); PathAndWidth currentPolygon = new PathAndWidth(); separatedPolygons.Add(currentPolygon); // put in the first point for (int segmentIndex = 0; segmentIndex < polySegments.Count; segmentIndex++) { // add the start point currentPolygon.Path.Add(polySegments[segmentIndex].Start); currentPolygon.ExtrusionWidthUm = polySegments[segmentIndex].Width + overlapMergeAmount_um; // if the next segment is not connected to this one if (segmentIndex < polySegments.Count - 1 && (polySegments[segmentIndex].End != polySegments[segmentIndex + 1].Start || polySegments[segmentIndex].Width != polySegments[segmentIndex + 1].Width)) { // add the end point currentPolygon.Path.Add(polySegments[segmentIndex].End); // create a new polygon currentPolygon = new PathAndWidth(); separatedPolygons.Add(currentPolygon); } } // add the end point currentPolygon.Path.Add(polySegments[polySegments.Count - 1].End); return(pathWasOptomized); }
public void WriteQueuedGCode(int layerThickness, int fanSpeedPercent = -1, int bridgeFanSpeedPercent = -1) { GCodePathConfig lastConfig = null; int extruderIndex = gcodeExport.GetExtruderIndex(); for (int pathIndex = 0; pathIndex < paths.Count; pathIndex++) { GCodePath path = paths[pathIndex]; if (extruderIndex != path.extruderIndex) { extruderIndex = path.extruderIndex; gcodeExport.SwitchExtruder(extruderIndex); } else if (path.Retract) { gcodeExport.WriteRetraction(); } if (path.config != travelConfig && lastConfig != path.config) { if (path.config.gcodeComment == "BRIDGE" && bridgeFanSpeedPercent != -1) { gcodeExport.WriteFanCommand(bridgeFanSpeedPercent); } else if (lastConfig?.gcodeComment == "BRIDGE" && bridgeFanSpeedPercent != -1) { gcodeExport.WriteFanCommand(fanSpeedPercent); } gcodeExport.WriteComment("TYPE:{0}".FormatWith(path.config.gcodeComment)); lastConfig = path.config; } double speed = path.config.speed; if (path.config.lineWidth_um != 0) { // Prevent cooling overrides from affecting bridge moves if (path.config.gcodeComment != "BRIDGE") { speed = speed * extrudeSpeedFactor / 100; } } else { speed = speed * travelSpeedFactor / 100; } if (path.points.Count == 1 && path.config != travelConfig && (gcodeExport.GetPositionXY() - path.points[0].XYPoint).ShorterThen(path.config.lineWidth_um * 2)) { //Check for lots of small moves and combine them into one large line Point3 nextPosition = path.points[0]; int i = pathIndex + 1; while (i < paths.Count && paths[i].points.Count == 1 && (nextPosition - paths[i].points[0]).ShorterThen(path.config.lineWidth_um * 2)) { nextPosition = paths[i].points[0]; i++; } if (paths[i - 1].config == travelConfig) { i--; } if (i > pathIndex + 2) { nextPosition = gcodeExport.GetPosition(); for (int x = pathIndex; x < i - 1; x += 2) { long oldLen = (nextPosition - paths[x].points[0]).Length(); Point3 newPoint = (paths[x].points[0] + paths[x + 1].points[0]) / 2; long newLen = (gcodeExport.GetPosition() - newPoint).Length(); if (newLen > 0) { gcodeExport.WriteMove(newPoint, speed, (int)(path.config.lineWidth_um * oldLen / newLen)); } nextPosition = paths[x + 1].points[0]; } gcodeExport.WriteMove(paths[i - 1].points[0], speed, path.config.lineWidth_um); pathIndex = i - 1; continue; } } bool spiralize = path.config.spiralize; if (spiralize) { //Check if we are the last spiralize path in the list, if not, do not spiralize. for (int m = pathIndex + 1; m < paths.Count; m++) { if (paths[m].config.spiralize) { spiralize = false; } } } if (spiralize) // if we are still in spiralize mode { //If we need to spiralize then raise the head slowly by 1 layer as this path progresses. double totalLength = 0; long z = gcodeExport.GetPositionZ(); IntPoint currentPosition = gcodeExport.GetPositionXY(); for (int pointIndex = 0; pointIndex < path.points.Count; pointIndex++) { IntPoint nextPosition = path.points[pointIndex].XYPoint; totalLength += (currentPosition - nextPosition).LengthMm(); currentPosition = nextPosition; } double length = 0.0; currentPosition = gcodeExport.GetPositionXY(); for (int i = 0; i < path.points.Count; i++) { IntPoint nextPosition = path.points[i].XYPoint; length += (currentPosition - nextPosition).LengthMm(); currentPosition = nextPosition; Point3 nextExtrusion = path.points[i]; nextExtrusion.z = (int)(z + layerThickness * length / totalLength + .5); gcodeExport.WriteMove(nextExtrusion, speed, path.config.lineWidth_um); } } else { bool pathIsClosed = true; if (perimeterStartEndOverlapRatio < 1) { pathIsClosed = !TrimPerimeterIfNeeded(path, perimeterStartEndOverlapRatio); } // This is test code to remove double drawn small perimeter lines. List <PathAndWidth> pathsWithOverlapsRemoved; if (RemovePerimetersThatOverlap(path, speed, out pathsWithOverlapsRemoved, pathIsClosed)) { for (int polygonIndex = 0; polygonIndex < pathsWithOverlapsRemoved.Count; polygonIndex++) { PathAndWidth polygon = pathsWithOverlapsRemoved[polygonIndex]; if (polygon.Path.Count == 2) { // make sure the path is ordered with the first point the closest to where we are now Point3 currentPosition = gcodeExport.GetPosition(); // if the second point is closer swap them if ((polygon.Path[1] - currentPosition).LengthSquared() < (polygon.Path[0] - currentPosition).LengthSquared()) { // swap them Point3 temp = polygon.Path[0]; polygon.Path[0] = polygon.Path[1]; polygon.Path[1] = temp; } } // move to the start of this polygon gcodeExport.WriteMove(polygon.Path[0], travelConfig.speed, 0); // write all the data for the polygon for (int pointIndex = 1; pointIndex < polygon.Path.Count; pointIndex++) { gcodeExport.WriteMove(polygon.Path[pointIndex], speed, polygon.ExtrusionWidthUm); } } } else { for (int i = 0; i < path.points.Count; i++) { gcodeExport.WriteMove(path.points[i], speed, path.config.lineWidth_um); } } } } gcodeExport.UpdateTotalPrintTime(); }
public bool RemovePerimeterOverlaps(List<Point3> perimeter, long overlapMergeAmount_um, out List<PathAndWidth> separatedPolygons, bool pathIsClosed = true) { bool pathWasOptomized = false; perimeter = MakeCloseSegmentsMergable(perimeter, overlapMergeAmount_um); // make a copy that has every point duplicated (so that we have them as segments). List <Segment> polySegments = Segment.ConvertPathToSegments(perimeter, pathIsClosed); Altered[] markedAltered = new Altered[polySegments.Count]; int segmentCount = polySegments.Count; // now walk every segment and check if there is another segment that is similar enough to merge them together for (int firstSegmentIndex = 0; firstSegmentIndex < segmentCount; firstSegmentIndex++) { for (int checkSegmentIndex = firstSegmentIndex + 1; checkSegmentIndex < segmentCount; checkSegmentIndex++) { // The first point of start and the last point of check (the path will be coming back on itself). long startDelta = (polySegments[firstSegmentIndex].Start - polySegments[checkSegmentIndex].End).Length(); // if the segments are similar enough if (startDelta < overlapMergeAmount_um) { // The last point of start and the first point of check (the path will be coming back on itself). long endDelta = (polySegments[firstSegmentIndex].End - polySegments[checkSegmentIndex].Start).Length(); if (endDelta < overlapMergeAmount_um) { pathWasOptomized = true; // move the first segments points to the average of the merge positions long startEndWidth = Math.Abs((polySegments[firstSegmentIndex].Start - polySegments[checkSegmentIndex].End).Length()); long endStartWidth = Math.Abs((polySegments[firstSegmentIndex].End - polySegments[checkSegmentIndex].Start).Length()); polySegments[firstSegmentIndex].Width = Math.Min(startEndWidth, endStartWidth); polySegments[firstSegmentIndex].Start = (polySegments[firstSegmentIndex].Start + polySegments[checkSegmentIndex].End) / 2; // the start polySegments[firstSegmentIndex].End = (polySegments[firstSegmentIndex].End + polySegments[checkSegmentIndex].Start) / 2; // the end markedAltered[firstSegmentIndex] = Altered.merged; // mark this segment for removal markedAltered[checkSegmentIndex] = Altered.remove; // We only expect to find one match for each segment, so move on to the next segment break; } } } } // remove the marked segments for (int segmentIndex = segmentCount - 1; segmentIndex >= 0; segmentIndex--) { if (markedAltered[segmentIndex] == Altered.remove) { polySegments.RemoveAt(segmentIndex); } } // go through the polySegments and create a new polygon for every connected set of segments separatedPolygons = new List<PathAndWidth>(); PathAndWidth currentPolygon = new PathAndWidth(); separatedPolygons.Add(currentPolygon); // put in the first point for (int segmentIndex = 0; segmentIndex < polySegments.Count; segmentIndex++) { // add the start point currentPolygon.Path.Add(polySegments[segmentIndex].Start); currentPolygon.ExtrusionWidthUm = polySegments[segmentIndex].Width + overlapMergeAmount_um; // if the next segment is not connected to this one if (segmentIndex < polySegments.Count - 1 && (polySegments[segmentIndex].End != polySegments[segmentIndex + 1].Start || polySegments[segmentIndex].Width != polySegments[segmentIndex + 1].Width)) { // add the end point currentPolygon.Path.Add(polySegments[segmentIndex].End); // create a new polygon currentPolygon = new PathAndWidth(); separatedPolygons.Add(currentPolygon); } } // add the end point currentPolygon.Path.Add(polySegments[polySegments.Count - 1].End); return pathWasOptomized; }