Skip to content

Commit f96ef4d

Browse files
committed
Fix floating point error in the clip line to envelope logic
1 parent 06c4356 commit f96ef4d

2 files changed

Lines changed: 47 additions & 2 deletions

File tree

ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/utils/GeometryUtils.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,21 @@ public static LineString clipLineToEnvelope(LineString line, Envelope envelope)
2525
Coordinate p0 = line.getCoordinateN(0);
2626
Coordinate p1 = line.getCoordinateN(1);
2727

28-
Point2D[] clipped = liangBarskyClipLine(new Point2D.Double(p0.x, p0.y), new Point2D.Double(p1.x, p1.y), new Rectangle2D.Double(envelope.getMinX(), envelope.getMinY(), envelope.getWidth(), envelope.getHeight()));
28+
// Allow for tiny floating-point overshoots like 251.00000000000003
29+
final double epsilon = 1e-9;
30+
Rectangle2D expandedEnvelope = new Rectangle2D.Double(
31+
envelope.getMinX() - epsilon,
32+
envelope.getMinY() - epsilon,
33+
envelope.getWidth() + (2 * epsilon),
34+
envelope.getHeight() + (2 * epsilon)
35+
);
36+
37+
Point2D[] clipped = liangBarskyClipLine(
38+
new Point2D.Double(p0.x, p0.y),
39+
new Point2D.Double(p1.x, p1.y),
40+
expandedEnvelope
41+
);
42+
2943
if (clipped == null) {
3044
return null;
3145
}
@@ -37,7 +51,6 @@ public static LineString clipLineToEnvelope(LineString line, Envelope envelope)
3751
return gf.createLineString(new Coordinate[]{start, end});
3852
}
3953

40-
4154
public static LineString generateLineString(Envelope envelope, double offsetAlongNormal, double angleInDegrees) {
4255
// Convert angle to radians
4356
double radians = Math.toRadians(-angleInDegrees);

ugs-platform/ugs-platform-plugin-designer/src/test/java/com/willwinder/ugs/nbp/designer/io/gcode/toolpaths/SurfaceToolPathTest.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -604,4 +604,36 @@ public void toGcodePathShouldAddSpindleSpeed() {
604604
assertEquals(9000, segment.getSpindleSpeed(), 0.01);
605605
assertEquals(200, segment.getFeedSpeed(), 0.01);
606606
}
607+
608+
@Test
609+
public void toGcodePathShouldStartFromTheTopWithConventionalMilling() {
610+
Rectangle rectangle = new Rectangle(0, 0);
611+
rectangle.setSize(new Size(250, 270));
612+
rectangle.setLeadInPercent(0);
613+
rectangle.setDirection(Direction.CONVENTIONAL);
614+
rectangle.setToolPathDirection(ToolPathDirection.HORIZONTAL);
615+
616+
Settings settings = new Settings();
617+
settings.setToolDiameter(38);
618+
settings.setToolStepOver(100);
619+
settings.setSafeHeight(10);
620+
621+
SurfaceToolPath toolPath = new SurfaceToolPath(settings, rectangle);
622+
toolPath.setStartDepth(1);
623+
toolPath.setTargetDepth(1);
624+
625+
GcodePath gcodePath = toolPath.toGcodePath();
626+
List<Segment> segments = gcodePath.getSegments();
627+
628+
// 8 passes -> 4 segments each, plus SEAM and final safe-height move
629+
assertEquals(34, segments.size());
630+
631+
// Conventional milling should start at the top-most usable pass.
632+
// Segment layout for the first pass:
633+
// 0 SEAM, 1 safe Z, 2 XY start, 3 Z plunge, 4 line end
634+
Segment firstPassStart = segments.get(2);
635+
assertEquals(SegmentType.MOVE, firstPassStart.type);
636+
assertXYPoint(firstPassStart.point, 19, 251);
637+
assertFalse(firstPassStart.point.hasZ());
638+
}
607639
}

0 commit comments

Comments
 (0)