Skip to content

Commit

Permalink
Add new tool path option for surfacing (#2699)
Browse files Browse the repository at this point in the history
  • Loading branch information
breiler authored Feb 15, 2025
1 parent 57a1233 commit 20a87e3
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ public void render(Graphics2D graphics, Drawing drawing) {
Shape shape = getShape();
if (getCutType() == CutType.NONE) {
drawShape(graphics, dashedStroke, Colors.SHAPE_HINT, shape);
} else if (getCutType() == CutType.POCKET) {
} else if (getCutType() == CutType.POCKET || getCutType() == CutType.SURFACE) {
graphics.setStroke(new BasicStroke(strokeWidth));
graphics.setColor(getCutColor());
graphics.fill(shape);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ This file is part of Universal Gcode Sender (UGS).
*/
public enum CutType {
NONE("None", List.of(EntitySetting.CUT_TYPE)),
POCKET("Mill Pocket", DEFAULT_ENDMILL_SETTINGS),
POCKET("Mill - Pocket", DEFAULT_ENDMILL_SETTINGS),
SURFACE("Mill - Surface", DEFAULT_ENDMILL_SETTINGS),
ON_PATH("Mill - On path", DEFAULT_ENDMILL_SETTINGS),
INSIDE_PATH("Mill - Inside path", DEFAULT_ENDMILL_SETTINGS),
OUTSIDE_PATH("Mill - Outside path", DEFAULT_ENDMILL_SETTINGS),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,7 @@
import java.awt.*;

public class CutTypeIcon extends ImageIcon {
private ImageIcon icon;

public CutTypeIcon(CutType cutType) {
this(cutType, Size.MEDIUM);
}
private final ImageIcon icon;

public enum Size {
SMALL(""),
Expand Down Expand Up @@ -53,6 +49,7 @@ public CutTypeIcon(CutType cutType, Size size) {
icon = ImageUtilities.loadImageIcon("img/centerdrill" + size.value + ".svg", false);
setDescription(cutType.getName());
break;
case SURFACE:
case LASER_FILL:
icon = ImageUtilities.loadImageIcon("img/cutfill" + size.value + ".svg", false);
setDescription(cutType.getName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import com.willwinder.ugs.nbp.designer.io.gcode.toolpaths.LaserOutlineToolPath;
import com.willwinder.ugs.nbp.designer.io.gcode.toolpaths.OutlineToolPath;
import com.willwinder.ugs.nbp.designer.io.gcode.toolpaths.PocketToolPath;
import com.willwinder.ugs.nbp.designer.io.gcode.toolpaths.SurfaceToolPath;
import com.willwinder.ugs.nbp.designer.io.gcode.toolpaths.ToolPathStats;
import com.willwinder.ugs.nbp.designer.io.gcode.toolpaths.ToolPathUtils;
import com.willwinder.ugs.nbp.designer.model.Settings;
Expand Down Expand Up @@ -78,7 +79,7 @@ public String toGcode(List<Cuttable> entities) {
throw new RuntimeException("An error occured while trying to generate gcode", e);
}

result.append("\n" + "; Turning off spindle\n" )
result.append("\n; Turning off spindle\n" )
.append(Code.M5.name()).append("\n" );
return result.toString();
}
Expand All @@ -96,6 +97,12 @@ private GcodePath getGcodePathFromCuttables(List<Cuttable> cuttables) {
simplePocket.setTargetDepth(cuttable.getTargetDepth());
simplePocket.appendGcodePath(gcodePath, settings);
break;
case SURFACE:
SurfaceToolPath surfaceToolPath = new SurfaceToolPath(settings, cuttable);
surfaceToolPath.setStartDepth(cuttable.getStartDepth());
surfaceToolPath.setTargetDepth(cuttable.getTargetDepth());
surfaceToolPath.appendGcodePath(gcodePath, settings);
break;
case OUTSIDE_PATH:
OutlineToolPath simpleOutsidePath = new OutlineToolPath(settings, cuttable);
simpleOutsidePath.setOffset(settings.getToolDiameter() / 2d);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package com.willwinder.ugs.nbp.designer.io.gcode.toolpaths;

import com.willwinder.ugs.nbp.designer.entities.cuttable.Cuttable;
import com.willwinder.ugs.nbp.designer.io.gcode.path.GcodePath;
import com.willwinder.ugs.nbp.designer.io.gcode.path.Segment;
import com.willwinder.ugs.nbp.designer.io.gcode.path.SegmentType;
import com.willwinder.ugs.nbp.designer.model.Settings;
import com.willwinder.universalgcodesender.model.PartialPosition;
import com.willwinder.universalgcodesender.model.UnitUtils;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.CoordinateXY;
import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.LineString;
import org.locationtech.jts.geom.MultiPoint;

import java.awt.geom.Area;
import java.util.List;

public class SurfaceToolPath extends AbstractToolPath {
private final Cuttable source;

public SurfaceToolPath(Settings settings, Cuttable source) {
super(settings);
this.source = source;
}

private List<Geometry> getGeometries() {
Geometry geometry = ToolPathUtils.convertAreaToGeometry(new Area(source.getShape()), getGeometryFactory());
Geometry shell = geometry.buffer(-settings.getToolDiameter() / 2d);
return List.of(shell);
}

public void appendGcodePath(GcodePath gcodePath, Settings settings) {
gcodePath.addSegment(new Segment(SegmentType.SEAM, null, null, (int) Math.round(settings.getMaxSpindleSpeed() * (source.getSpindleSpeed() / 100d)), source.getFeedRate()));

double stepOver = settings.getToolDiameter() * Math.min(Math.max(0.01, Math.abs(settings.getToolStepOver())), 1.0);


List<Geometry> geometries = getGeometries();
geometries.forEach(g -> {
Envelope envelope = g.getEnvelopeInternal();

double currentDepth = getStartDepth();
addGeometriesToGcodePath(gcodePath, settings, g, envelope, currentDepth, stepOver);

while (currentDepth < getTargetDepth()) {
currentDepth += settings.getDepthPerPass();
if (currentDepth > getTargetDepth()) {
currentDepth = getTargetDepth();
}

addGeometriesToGcodePath(gcodePath, settings, g, envelope, currentDepth, stepOver);
}
});
}

private void addGeometriesToGcodePath(GcodePath gcodePath, Settings settings, Geometry g, Envelope envelope, double currentDepth, double stepOver) {
double currentY = envelope.getMinY();
while (currentY <= envelope.getMaxY()) {
LineString lineString = getGeometryFactory().createLineString(new Coordinate[]{
new CoordinateXY(envelope.getMinX(), currentY),
new CoordinateXY(envelope.getMaxX(), currentY),
});

addLineIntersectionSegments(gcodePath, g, lineString, currentDepth, settings.getSafeHeight());
currentY += stepOver;
}
}

private void addLineIntersectionSegments(GcodePath gcodePath, Geometry geometry, LineString lineString, double currentDepth, double safeHeight) {
Geometry intersection = geometry.intersection(lineString);

// If the intersection is a multipoint we should not connect the points with a line
if (intersection instanceof MultiPoint) {
return;
}

List<PartialPosition> geometryCoordinates = ToolPathUtils.geometryToCoordinates(intersection);
List<PartialPosition> partialPosition = geometryCoordinates.stream()
.map(numericCoordinate -> PartialPosition.builder(numericCoordinate).build()).toList();

if (partialPosition.size() > 1) {
for (int i = 0; i + 1 < partialPosition.size(); i += 2) {
PartialPosition startPosition = partialPosition.get(i);
PartialPosition endPosition = partialPosition.get(i + 1);

// Make sure we are working from left to right
if (startPosition.getX() > endPosition.getX()) {
startPosition = partialPosition.get(i + 1);
endPosition = partialPosition.get(i);
}

gcodePath.addSegment(SegmentType.MOVE, PartialPosition.builder(UnitUtils.Units.MM).setZ(safeHeight).build());
gcodePath.addSegment(SegmentType.MOVE, startPosition);
gcodePath.addSegment(SegmentType.MOVE, PartialPosition.builder(UnitUtils.Units.MM).setZ(0d).build());
gcodePath.addSegment(SegmentType.POINT, PartialPosition.builder(UnitUtils.Units.MM).setZ(-currentDepth).build());
gcodePath.addSegment(SegmentType.LINE, endPosition, source.getFeedRate());
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ This file is part of Universal Gcode Sender (UGS).
public enum CutTypeV1 {
NONE,
POCKET,
SURFACE,
ON_PATH,
INSIDE_PATH,
OUTSIDE_PATH,
Expand All @@ -36,6 +37,8 @@ public enum CutTypeV1 {
public static CutTypeV1 fromCutType(CutType cutType) {
if (cutType == CutType.POCKET) {
return POCKET;
} else if (cutType == CutType.SURFACE) {
return SURFACE;
} else if (cutType == CutType.ON_PATH) {
return ON_PATH;
} else if (cutType == CutType.INSIDE_PATH) {
Expand All @@ -56,6 +59,8 @@ public static CutTypeV1 fromCutType(CutType cutType) {
public static CutType toCutType(CutTypeV1 cutType) {
if (cutType == POCKET) {
return CutType.POCKET;
} else if (cutType == SURFACE) {
return CutType.SURFACE;
} else if (cutType == ON_PATH) {
return CutType.ON_PATH;
} else if (cutType == INSIDE_PATH) {
Expand Down

0 comments on commit 20a87e3

Please sign in to comment.