|
4 | 4 | import java.lang.foreign.*; |
5 | 5 | import java.lang.invoke.MethodHandle; |
6 | 6 | import java.nio.file.Files; |
| 7 | +import java.util.ArrayList; |
7 | 8 | import java.util.HashMap; |
8 | 9 | import java.util.Map; |
9 | 10 |
|
@@ -281,7 +282,16 @@ public ManifoldBindings(File cacheDirectory) throws Exception { |
281 | 282 | // ManifoldPolygons* manifold_slice(void* mem, ManifoldManifold* m, double |
282 | 283 | // height); |
283 | 284 | load("manifold_slice", ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.JAVA_DOUBLE); |
| 285 | + // size_t manifold_polygons_num_contour(ManifoldPolygons* p); |
| 286 | + load("manifold_polygons_num_contour", ValueLayout.JAVA_LONG, ValueLayout.ADDRESS); |
284 | 287 |
|
| 288 | + // size_t manifold_polygons_contour_length(ManifoldPolygons* p, int idx); |
| 289 | + load("manifold_polygons_contour_length", ValueLayout.JAVA_LONG, ValueLayout.ADDRESS, ValueLayout.JAVA_INT); |
| 290 | + |
| 291 | + // ManifoldVec2 manifold_polygons_get_point(ManifoldPolygons* p, int contour, int idx); |
| 292 | + // ManifoldVec2 is {double x, double y} = 16 bytes |
| 293 | + load("manifold_polygons_get_point", MemoryLayout.structLayout(ValueLayout.JAVA_DOUBLE, ValueLayout.JAVA_DOUBLE), |
| 294 | + ValueLayout.ADDRESS, ValueLayout.JAVA_INT, ValueLayout.JAVA_INT); |
285 | 295 | // ===== Analysis ===== |
286 | 296 |
|
287 | 297 | // double manifold_volume(ManifoldManifold* m); |
@@ -468,6 +478,49 @@ public ManifoldBindings(File cacheDirectory) throws Exception { |
468 | 478 |
|
469 | 479 | } |
470 | 480 |
|
| 481 | + /** |
| 482 | + * Slices the manifold at the given Z height, returning the cross-section as a |
| 483 | + * list of polygon contours. Each contour is a list of (x, y) vertex pairs |
| 484 | + * representing one closed loop of the cross-section. Outer contours are |
| 485 | + * wound counter-clockwise; holes are wound clockwise. |
| 486 | + * |
| 487 | + * @param m the manifold to slice |
| 488 | + * @param height Z height at which to slice |
| 489 | + * @return list of contours, each contour is a double[][] of [x, y] pairs |
| 490 | + * @throws Throwable on native call failure |
| 491 | + */ |
| 492 | + public ArrayList<double[][]> slice(MemorySegment m, double height) throws Throwable { |
| 493 | + MemorySegment polygons = null; |
| 494 | + try (Arena arena = Arena.ofConfined()) { |
| 495 | + MemorySegment mem = arena.allocate(256); // ManifoldPolygons opaque mem |
| 496 | + polygons = (MemorySegment) functions.get("manifold_slice").invoke(mem, m, height); |
| 497 | + |
| 498 | + long numContours = (long) functions.get("manifold_polygons_num_contour").invoke(polygons); |
| 499 | + ArrayList<double[][]> result = new ArrayList<double[][]>((int) numContours); |
| 500 | + |
| 501 | + for (int c = 0; c < numContours; c++) { |
| 502 | + long len = (long) functions.get("manifold_polygons_contour_length").invoke(polygons, c); |
| 503 | + double[][] contour = new double[(int) len][2]; |
| 504 | + for (int i = 0; i < len; i++) { |
| 505 | + MemorySegment pt = (MemorySegment) functions.get("manifold_polygons_get_point").invoke(arena, |
| 506 | + polygons, c, i); |
| 507 | + contour[i][0] = pt.get(ValueLayout.JAVA_DOUBLE, 0); // x |
| 508 | + contour[i][1] = pt.get(ValueLayout.JAVA_DOUBLE, 8); // y |
| 509 | + } |
| 510 | + result.add(contour); |
| 511 | + } |
| 512 | + |
| 513 | + return result; |
| 514 | + } finally { |
| 515 | + if (polygons != null) { |
| 516 | + try { |
| 517 | + functions.get("manifold_delete_polygons").invoke(polygons); |
| 518 | + } catch (Throwable ignored) { |
| 519 | + } |
| 520 | + } |
| 521 | + } |
| 522 | + } |
| 523 | + |
471 | 524 | public void deleteMeshGL64(MemorySegment seg) { |
472 | 525 | if (seg == null) |
473 | 526 | return; |
|
0 commit comments