66import java .nio .file .Files ;
77import java .util .ArrayList ;
88import java .util .HashMap ;
9+ import java .util .HashSet ;
910import java .util .Map ;
10-
11+ import java . util . Set ;
1112import java .io .*;
1213import java .lang .foreign .MemorySegment ;
1314import java .nio .*;
@@ -297,16 +298,19 @@ public ManifoldBindings(File cacheDirectory) throws Exception {
297298 // ManifoldPolygons* manifold_slice(void* mem, ManifoldManifold* m, double
298299 // height);
299300 load ("manifold_slice" , ValueLayout .ADDRESS , ValueLayout .ADDRESS , ValueLayout .ADDRESS , ValueLayout .JAVA_DOUBLE );
300- // size_t manifold_polygons_num_contour(ManifoldPolygons* p);
301- load ("manifold_polygons_num_contour" , ValueLayout .JAVA_LONG , ValueLayout .ADDRESS );
302301
303- // size_t manifold_polygons_contour_length(ManifoldPolygons* p, int idx);
304- load ("manifold_polygons_contour_length" , ValueLayout .JAVA_LONG , ValueLayout .ADDRESS , ValueLayout .JAVA_INT );
305302
306- // ManifoldVec2 manifold_polygons_get_point(ManifoldPolygons* p, int contour, int idx);
307- // ManifoldVec2 is {double x, double y} = 16 bytes
308- load ("manifold_polygons_get_point" , MemoryLayout .structLayout (ValueLayout .JAVA_DOUBLE , ValueLayout .JAVA_DOUBLE ),
309- ValueLayout .ADDRESS , ValueLayout .JAVA_INT , ValueLayout .JAVA_INT );
303+ load ("manifold_alloc_polygons" , ValueLayout .ADDRESS );
304+ // size_t manifold_polygons_length(ManifoldPolygons* ps);
305+ load ("manifold_polygons_length" , ValueLayout .JAVA_LONG , ValueLayout .ADDRESS );
306+
307+ // size_t manifold_polygons_simple_length(ManifoldPolygons* ps, size_t idx);
308+ load ("manifold_polygons_simple_length" , ValueLayout .JAVA_LONG , ValueLayout .ADDRESS , ValueLayout .JAVA_LONG );
309+ // ManifoldVec2 manifold_polygons_get_point(ManifoldPolygons* ps, size_t simple_idx, size_t pt_idx);
310+ // ManifoldVec2 = {double x, double y} = 16 bytes, returned by value
311+ load ("manifold_polygons_get_point" ,
312+ MemoryLayout .structLayout (ValueLayout .JAVA_DOUBLE , ValueLayout .JAVA_DOUBLE ),
313+ ValueLayout .ADDRESS , ValueLayout .JAVA_LONG , ValueLayout .JAVA_LONG );
310314 // ManifoldPolygons* manifold_alloc_polygons();
311315 load ("manifold_alloc_polygons" , ValueLayout .ADDRESS );
312316
@@ -388,8 +392,11 @@ public ManifoldBindings(File cacheDirectory) throws Exception {
388392 load ("manifold_is_empty" , ValueLayout .JAVA_INT , ValueLayout .ADDRESS );
389393
390394 // size_t manifold_manifold_vec_size(); Should return 8
391- load ("manifold_manifold_vec_size" , ValueLayout .JAVA_LONG , ValueLayout .ADDRESS );
392-
395+ //load("manifold_manifold_vec_size", ValueLayout.JAVA_LONG, ValueLayout.ADDRESS);
396+ // REPLACE WITH (no argument — it's a sizeof-style function):
397+ load ("manifold_manifold_vec_size" , ValueLayout .JAVA_LONG );
398+ // AND add the length function for actual runtime vec count:
399+ load ("manifold_manifold_vec_length" , ValueLayout .JAVA_LONG , ValueLayout .ADDRESS );
393400 // ManifoldManifold* manifold_manifold_vec_get(void* mem, ManifoldManifoldVec*
394401 // ms, size_t idx);
395402 load ("manifold_manifold_vec_get" , ValueLayout .ADDRESS , ValueLayout .ADDRESS , ValueLayout .JAVA_LONG );
@@ -545,42 +552,38 @@ public MemorySegment hullPoints(ArrayList<double[]> points) throws Throwable {
545552 }
546553 }
547554
548- /**
549- * Slices the manifold at the given Z height, returning the cross-section as a
550- * list of polygon contours. Each contour is a list of (x, y) vertex pairs
551- * representing one closed loop of the cross-section. Outer contours are
552- * wound counter-clockwise; holes are wound clockwise.
553- *
554- * @param m the manifold to slice
555- * @param height Z height at which to slice
556- * @return list of contours, each contour is a double[][] of [x, y] pairs
557- * @throws Throwable on native call failure
558- */
559555 public ArrayList <double [][]> slice (MemorySegment m , double height ) throws Throwable {
560556 MemorySegment polygons = null ;
561557 try (Arena arena = Arena .ofConfined ()) {
558+ // manifold_slice(void* mem, ManifoldManifold* m, double height) → ManifoldPolygons*
562559 MemorySegment mem = (MemorySegment ) functions .get ("manifold_alloc_polygons" ).invoke ();
563560 polygons = (MemorySegment ) functions .get ("manifold_slice" ).invoke (mem , m , height );
564561
565- long numContours = (long ) functions .get ("manifold_polygons_num_contour" ).invoke (polygons );
566- ArrayList <double [][]> result = new ArrayList <double [][]>((int ) numContours );
562+ // size_t manifold_polygons_length(ManifoldPolygons* ps) → number of contours
563+ long numContours = (long ) functions .get ("manifold_polygons_length" ).invoke (polygons );
564+ ArrayList <double [][]> result = new ArrayList <>((int ) numContours );
567565
568566 for (int c = 0 ; c < numContours ; c ++) {
569- long len = (long ) functions .get ("manifold_polygons_contour_length" ).invoke (polygons , c );
567+ // size_t manifold_polygons_simple_length(ManifoldPolygons* ps, size_t idx)
568+ long len = (long ) functions .get ("manifold_polygons_simple_length" ).invoke (polygons , (long ) c );
570569 double [][] contour = new double [(int ) len ][2 ];
570+
571571 for (int i = 0 ; i < len ; i ++) {
572+ // ManifoldVec2 manifold_polygons_get_point(ManifoldPolygons* ps, size_t simple_idx, size_t pt_idx)
572573 MemorySegment pt = (MemorySegment ) functions .get ("manifold_polygons_get_point" ).invoke (arena ,
573- polygons , c , i );
574+ polygons , ( long ) c , ( long ) i );
574575 contour [i ][0 ] = pt .get (ValueLayout .JAVA_DOUBLE , 0 ); // x
575576 contour [i ][1 ] = pt .get (ValueLayout .JAVA_DOUBLE , 8 ); // y
576577 }
577578 result .add (contour );
578579 }
579-
580580 return result ;
581581 } finally {
582582 if (polygons != null ) {
583- functions .get ("manifold_delete_polygons" ).invoke (polygons );
583+ try {
584+ functions .get ("manifold_delete_polygons" ).invoke (polygons );
585+ } catch (Throwable ignored ) {
586+ }
584587 }
585588 }
586589 }
@@ -1029,13 +1032,15 @@ public MemorySegment[] split(MemorySegment a, MemorySegment b) throws Throwable
10291032 } catch (Throwable e ) {
10301033 // Clean up allocated manifolds on failure
10311034 try {
1032- functions . get ( "manifold_delete_manifold" ). invoke (firstMem );
1035+ delete (firstMem );
10331036 } catch (Throwable ignored ) {
1037+ ignored .printStackTrace ();
10341038 }
10351039
10361040 try {
1037- functions . get ( "manifold_delete_manifold" ). invoke (secondMem );
1041+ delete (secondMem );
10381042 } catch (Throwable ignored ) {
1043+ ignored .printStackTrace ();
10391044 }
10401045
10411046 throw e ;
@@ -1070,12 +1075,9 @@ public MemorySegment boundingBox(MemorySegment m) throws Throwable {
10701075 }
10711076
10721077 public MemorySegment importMeshGL (float [] vertices , int [] triangles , long nVerts , long nTris ) throws Throwable {
1073- System .out .println ("Importing mesh: " + nVerts + " vertices, " + nTris + " triangles" );
10741078
1075- // Validate input arrays match declared sizes
10761079 if (vertices .length < nVerts * 3 || triangles .length < nTris * 3 ) {
1077- throw new IllegalArgumentException ("Array length mismatch: vertices=" + vertices .length + " (expected "
1078- + (nVerts * 3 ) + "), triangles=" + triangles .length + " (expected " + (nTris * 3 ) + ")" );
1080+ throw new IllegalArgumentException ("Array length mismatch" );
10791081 }
10801082
10811083 MethodHandle mh = functions .get ("manifold_meshgl" );
@@ -1084,79 +1086,53 @@ public MemorySegment importMeshGL(float[] vertices, int[] triangles, long nVerts
10841086
10851087 try (Arena tempArena = Arena .ofConfined ()) {
10861088
1087- // Copy vertices
10881089 MemorySegment vertPtr = tempArena .allocate (nVerts * 3 * Float .BYTES );
10891090 vertPtr .copyFrom (MemorySegment .ofArray (vertices ));
10901091
1091- // Copy triangles
10921092 MemorySegment triPtr = tempArena .allocate (nTris * 3 * Integer .BYTES );
10931093 triPtr .copyFrom (MemorySegment .ofArray (triangles ));
10941094
1095- // Allocate MeshGL (native heap - must track for cleanup)
1096- MemorySegment meshGLmem = (MemorySegment ) functions .get ("manifold_alloc_meshgl" ).invoke ();
1097- MemorySegment meshGL = null ;
1098-
1099- try { // Create MeshGL
1095+ // Allocate both up front so cleanup is uniform
1096+ MemorySegment meshGLMem = (MemorySegment ) functions .get ("manifold_alloc_meshgl" ).invoke ();
11001097
1101- meshGL = (MemorySegment ) mh .invoke (meshGLmem , vertPtr , nVerts , 3L , triPtr , nTris );
1102-
1103- // Merge (native heap - must track for cleanup)
1104- MemorySegment mergedMem = (MemorySegment ) functions .get ("manifold_alloc_meshgl" ).invoke ();
1105- MemorySegment merged = null ;
1106-
1107- try {
1108- merged = (MemorySegment ) functions .get ("manifold_meshgl_merge" ).invoke (mergedMem , meshGL );
1109-
1110- // Create Manifold
1111- MemorySegment manMem = (MemorySegment ) functions .get ("manifold_alloc_manifold" ).invoke ();
1112- MemorySegment manifold = (MemorySegment ) functions .get ("manifold_of_meshgl" ).invoke (manMem , merged );
1113-
1114- // Success path: cleanup intermediates, return result
1115- try {
1116- functions .get ("manifold_delete_meshgl" ).invoke (merged );
1117- } catch (Throwable ignored ) {
1118- }
1119-
1120- try {
1121- functions .get ("manifold_delete_meshgl" ).invoke (meshGL );
1122- } catch (Throwable ignored ) {
1123- }
1124-
1125- return manifold ;
1126-
1127- } catch (Throwable e ) { // Cleanup merged on failure
1128-
1129- if (merged != null ) {
1130- try {
1131- functions .get ("manifold_delete_meshgl" ).invoke (merged );
1132- } catch (Throwable ignored ) {
1133- }
1134- } else {
1135- try {
1136- functions .get ("manifold_delete_meshgl" ).invoke (mergedMem );
1137- } catch (Throwable ignored ) {
1138- }
1139- }
1140- throw e ;
1141- }
1142-
1143- } catch (Throwable e ) {// Cleanup meshGL on failure
1098+ MemorySegment mergedMem = (MemorySegment ) functions .get ("manifold_alloc_meshgl" ).invoke ();
1099+ MemorySegment merged = null ;
1100+ MemorySegment meshGL = null ;
1101+ MemorySegment manMem = null ;
1102+ MemorySegment manifold = null ;
1103+ try {
1104+ // Both of these likely return the same pointer they were given
1105+ meshGL = (MemorySegment ) mh .invoke (meshGLMem , vertPtr , nVerts , 3L , triPtr , nTris );
1106+ merged = (MemorySegment ) functions .get ("manifold_meshgl_merge" ).invoke (mergedMem , meshGL );
1107+
1108+ manMem = (MemorySegment ) functions .get ("manifold_alloc_manifold" ).invoke ();
1109+ manifold = (MemorySegment ) functions .get ("manifold_of_meshgl" ).invoke (manMem , merged );
1110+ // System.out.println("meshGLMem addr: " + meshGLMem.address());
1111+ // System.out.println("meshGL addr: " + meshGL.address());
1112+ // System.out.println("mergedMem addr: " + mergedMem.address());
1113+ // System.out.println("merged addr: " + merged.address());
1114+ // System.out.println("manMem addr: " + manMem.address());
1115+ // System.out.println("manifold addr: " + manifold.address());
1116+ return manifold ;
1117+
1118+ } finally {
1119+ // Collect unique addresses to delete
1120+ Set <Long > freed = new HashSet <>();
1121+ for (MemorySegment seg : new MemorySegment [] { merged , meshGL }) {
1122+ if (seg == null )
1123+ continue ;
1124+ if (seg .address () == manifold .address ())
1125+ continue ;
1126+ if (freed .add (seg .address ())) { // add() returns false if already present
1127+ //System.out.print("\nFreeing: " + seg.address());
1128+ functions .get ("manifold_delete_meshgl" ).invoke (seg );
1129+ //System.out.print(" done\n ");
11441130
1145- if (meshGL != null ) {
1146- try {
1147- functions .get ("manifold_delete_meshgl" ).invoke (meshGL );
1148- } catch (Throwable ignored ) {
1149- }
1150- } else {
1151- try {
1152- functions .get ("manifold_delete_meshgl" ).invoke (meshGLmem );
1153- } catch (Throwable ignored ) {
11541131 }
11551132 }
1156- throw e ;
1133+ freed . clear () ;
11571134 }
1158-
1159- } // tempArena closed here, vertPtr and triPtr freed automatically
1135+ }
11601136 }
11611137
11621138 public MeshData exportMeshGL (MemorySegment manifold ) throws Throwable {
@@ -1332,8 +1308,16 @@ public long estimateMemoryBytes(MemorySegment m) throws Throwable {
13321308 return manifoldHandle + internalTotal + exportTotal + bvhOverhead ;
13331309 }
13341310
1311+ //private HashMap<MemorySegment,Exception> deleted = new HashMap<>();
1312+
13351313 public void delete (MemorySegment manifold ) throws Throwable {
1314+ // if (deleted.containsKey(manifold)) {
1315+ // System.err.println("Memory was deleted at ");
1316+ // deleted.get(manifold).printStackTrace();
1317+ // throw new DoubleFreeException();
1318+ // }
13361319 functions .get ("manifold_delete_manifold" ).invoke (manifold );
1320+ //deleted.put(manifold, new Exception());
13371321 }
13381322
13391323 // Null-safe delete
@@ -1735,7 +1719,7 @@ private static List<RawMesh> parseModelXml(String xml) {
17351719 verts .add (attrFloat (tag , "x" ));
17361720 verts .add (attrFloat (tag , "y" ));
17371721 verts .add (attrFloat (tag , "z" ));
1738- } else if (tris != null && tag .startsWith ("triangle" )) {
1722+ } else if (tris != null && tag .startsWith ("triangle" ) && ! tag . startsWith ( "triangles" ) ) {
17391723 // <triangle v1=… v2=… v3=…/> — local indices, no offset needed
17401724 tris .add (attrInt (tag , "v1" ));
17411725 tris .add (attrInt (tag , "v2" ));
0 commit comments