public void Optimize(IntPoint startPosition, PathFinder pathFinder, int layerIndex, bool addMovePolys, GCodePathConfig pathConfig = null) { // pathFinder = null; this.OptimizedPaths.Clear(); bool doSeamHiding = pathConfig != null && pathConfig.DoSeamHiding && !pathConfig.Spiralize; bool canTravelForwardOrBackward = pathConfig != null && !pathConfig.ClosedLoop; // Find the point that is closest to our current position (start position) var completedPolygons = new HashSet <int>(); var polygonAccelerator = Polygons.GetQuadTree(); IntPoint currentPosition = startPosition; while (completedPolygons.Count < Polygons.Count) { var closestPolyPoint = FindClosestPolyAndPoint(currentPosition, polygonAccelerator, completedPolygons, doSeamHiding, layerIndex, pathConfig != null ? pathConfig.LineWidth_um : 0, canTravelForwardOrBackward, out IntPoint endPosition); // if we have a path finder check if we have actually found the shortest path if (pathFinder != null && closestPolyPoint.SourcePolyIndex != -1 && closestPolyPoint.PointIndex != -1 && closestPolyPoint.FoundPath) { // the position that we are going to move to to begin the next polygon (the other side of the endPosition) var nextStartPosition = Polygons[closestPolyPoint.SourcePolyIndex][closestPolyPoint.PointIndex]; var pathPolygon = new Polygon(); // path find the start and end that we found to find out how far it is if (pathFinder.CreatePathInsideBoundary(currentPosition, nextStartPosition, pathPolygon, true, layerIndex)) { var pathLength = pathPolygon.PolygonLength(); var directLength = (nextStartPosition - currentPosition).Length(); var center = pathPolygon.GetPositionAllongPath(.5, pathConfig != null ? pathConfig.ClosedLoop : false); var tryAgain = false; do { tryAgain = false; if (pathLength > config.MinimumTravelToCauseRetraction_um / 10 && pathLength > directLength * 2) { // try to find a closer place to go to by looking at the center of the returned path var midPolyPoint = FindClosestPolyAndPoint(center, polygonAccelerator, completedPolygons, doSeamHiding, layerIndex, pathConfig != null ? pathConfig.LineWidth_um : 0, canTravelForwardOrBackward, out IntPoint midEndPosition); if (midPolyPoint.SourcePolyIndex != -1 && midPolyPoint.PointIndex != -1 && closestPolyPoint.FoundPath) { var midStartPosition = Polygons[midPolyPoint.SourcePolyIndex][midPolyPoint.PointIndex]; if (pathFinder.CreatePathInsideBoundary(currentPosition, midStartPosition, pathPolygon, true, layerIndex)) { var midPathLength = pathPolygon.PolygonLength(); if (midPathLength < pathLength) { closestPolyPoint = midPolyPoint; endPosition = midEndPosition; pathLength = midPathLength; center = pathPolygon.GetPositionAllongPath(.5, pathConfig != null ? pathConfig.ClosedLoop : false); tryAgain = true; } } } } } while (tryAgain); } } if (closestPolyPoint.SourcePolyIndex == -1) { // could not find any next point break; } OptimizedPaths.Add(closestPolyPoint); completedPolygons.Add(closestPolyPoint.SourcePolyIndex); currentPosition = endPosition; } }
public void Optimize(IntPoint startPosition, PathFinder pathFinder, int layerIndex, bool addMovePolys, GCodePathConfig pathConfig = null) { // pathFinder = null; this.OptimizedPaths.Clear(); bool doSeamHiding = pathConfig != null && pathConfig.DoSeamHiding && !pathConfig.Spiralize; bool canTravelForwardOrBackward = pathConfig != null && !pathConfig.ClosedLoop; // Find the point that is closest to our current position (start position) var completedPolygons = new HashSet <int>(); var polygonAccelerator = Polygons.GetQuadTree(); IntPoint currentPosition = startPosition; while (completedPolygons.Count < Polygons.Count) { var closestPolyPoint = FindClosestPolyAndPoint(currentPosition, polygonAccelerator, completedPolygons, doSeamHiding, config.SeamPlacement, layerIndex, pathConfig != null ? pathConfig.LineWidth_um : 0, canTravelForwardOrBackward, out IntPoint endPosition); // if we have a path finder check if we have actually found the shortest path if (pathFinder != null && closestPolyPoint.SourcePolyIndex != -1 && closestPolyPoint.PointIndex != -1 && closestPolyPoint.FoundPath) { // the position that we are going to move to to begin the next polygon (the other side of the endPosition) var nextStartPosition = Polygons[closestPolyPoint.SourcePolyIndex][closestPolyPoint.PointIndex]; var pathPolygon = new Polygon(); // path find the start and end that we found to find out how far it is if (pathFinder.CreatePathInsideBoundary(currentPosition, nextStartPosition, pathPolygon, true, layerIndex)) { var pathLength = pathPolygon.PolygonLength(); var directLength = (nextStartPosition - currentPosition).Length(); var center = pathPolygon.GetPositionAllongPath(.5, pathConfig != null ? pathConfig.ClosedLoop : false); var tryAgain = false; do { tryAgain = false; if (pathLength > config.MinimumTravelToCauseRetraction_um / 10 && pathLength > directLength * 2) { // try to find a closer place to go to by looking at the center of the returned path var midPolyPoint = FindClosestPolyAndPoint(center, polygonAccelerator, completedPolygons, doSeamHiding, config.SeamPlacement, layerIndex, pathConfig != null ? pathConfig.LineWidth_um : 0, canTravelForwardOrBackward, out IntPoint midEndPosition); if (midPolyPoint.SourcePolyIndex != -1 && midPolyPoint.PointIndex != -1 && closestPolyPoint.FoundPath) { var midStartPosition = Polygons[midPolyPoint.SourcePolyIndex][midPolyPoint.PointIndex]; if (pathFinder.CreatePathInsideBoundary(currentPosition, midStartPosition, pathPolygon, true, layerIndex)) { var midPathLength = pathPolygon.PolygonLength(); if (midPathLength < pathLength) { closestPolyPoint = midPolyPoint; endPosition = midEndPosition; pathLength = midPathLength; center = pathPolygon.GetPositionAllongPath(.5, pathConfig != null ? pathConfig.ClosedLoop : false); tryAgain = true; } } } } }while (tryAgain); } } if (closestPolyPoint.SourcePolyIndex == -1) { // could not find any next point break; } OptimizedPaths.Add(closestPolyPoint); completedPolygons.Add(closestPolyPoint.SourcePolyIndex); currentPosition = endPosition; } if (pathConfig?.Name.Contains("inset") == true && Polygons.Count > 1) { // we have a subdivided perimeter make sure it is wound in the right direction // create a polygon that is all the points in the output order var polygon = new Polygon(); foreach (var optimizedPath in OptimizedPaths) { var sourcePoly = Polygons[optimizedPath.SourcePolyIndex]; polygon.Add(sourcePoly[optimizedPath.PointIndex]); var endIndex = (optimizedPath.PointIndex - 1 + sourcePoly.Count) % sourcePoly.Count; polygon.Add(sourcePoly[endIndex]); } // find the winding of all ponits if (polygon.GetWindingDirection() == -1) { var newPaths = new List <OptimizedPath>(); // if -1 reverse the order so they will be ccw foreach (var optimizedPath in ((IEnumerable <OptimizedPath>)OptimizedPaths).Reverse()) { var sourcePoly = Polygons[optimizedPath.SourcePolyIndex]; var endIndex = optimizedPath.PointIndex == 0 ? sourcePoly.Count - 1 : 0; newPaths.Add(new OptimizedPath(optimizedPath.SourcePolyIndex, endIndex, optimizedPath.IsExtrude, optimizedPath.FoundPath)); } OptimizedPaths = newPaths; } } }