@@ -477,10 +477,59 @@ public ManifoldBindings(File cacheDirectory) throws Exception {
477477 ValueLayout .JAVA_LONG // arg6: size_t n_tris
478478 );
479479
480+ load ("manifold_hull_pts" , ValueLayout .ADDRESS , ValueLayout .ADDRESS , ValueLayout .ADDRESS , ValueLayout .JAVA_LONG );
481+
480482 System .out .println ("Available Manifold functions: " + functions .keySet ());
481483
482484 }
483485
486+ /**
487+ * Computes the convex hull of a set of points.
488+ *
489+ * Each point is supplied as a {@code double[3]} of {x, y, z}. If fewer than
490+ * 4 points are provided, or all points are coplanar, an empty manifold is
491+ * returned (matching the C++ API's documented behaviour).
492+ *
493+ * The caller owns the returned MemorySegment and must eventually pass it
494+ * to {@link #delete(MemorySegment)} or {@link #safeDelete(MemorySegment)}.
495+ *
496+ * @param points list of points, each a double[3] of {x, y, z}
497+ * @return the convex hull as a ManifoldManifold* MemorySegment
498+ * @throws IllegalArgumentException if any point array has length != 3
499+ * @throws Throwable on native call failure
500+ */
501+ public MemorySegment hullPoints (ArrayList <double []> points ) throws Throwable {
502+ if (points == null || points .isEmpty ()) {
503+ return empty ();
504+ }
505+
506+ // Validate all points up front before allocating any native memory.
507+ for (int i = 0 ; i < points .size (); i ++) {
508+ if (points .get (i ) == null || points .get (i ).length != 3 ) {
509+ throw new IllegalArgumentException ("Point at index " + i + " must be a double[3] of {x, y, z}" );
510+ }
511+ }
512+
513+ // ManifoldVec3 is three packed doubles: {double x, double y, double z} = 24 bytes each.
514+ final long VEC3_BYTES = 3 * Double .BYTES ;
515+ long count = points .size ();
516+
517+ try (Arena arena = Arena .ofConfined ()) {
518+ // Allocate a flat array of ManifoldVec3 structs in a temporary arena.
519+ MemorySegment ptsBuffer = arena .allocate (VEC3_BYTES * count );
520+ for (int i = 0 ; i < count ; i ++) {
521+ double [] pt = points .get (i );
522+ long base = i * VEC3_BYTES ;
523+ ptsBuffer .set (ValueLayout .JAVA_DOUBLE , base , pt [0 ]); // x
524+ ptsBuffer .set (ValueLayout .JAVA_DOUBLE , base + Double .BYTES , pt [1 ]); // y
525+ ptsBuffer .set (ValueLayout .JAVA_DOUBLE , base + 2 * Double .BYTES , pt [2 ]); // z
526+ }
527+
528+ MemorySegment mem = (MemorySegment ) functions .get ("manifold_alloc_manifold" ).invoke ();
529+ return (MemorySegment ) functions .get ("manifold_hull_pts" ).invoke (mem , ptsBuffer , count );
530+ }
531+ }
532+
484533 /**
485534 * Slices the manifold at the given Z height, returning the cross-section as a
486535 * list of polygon contours. Each contour is a list of (x, y) vertex pairs
0 commit comments