code wiki / (root) / nx_mesh_decimate.nx

nx_mesh_decimate.nx source

↩ module page · 103 lines · 4902 B

1// nx_mesh_decimate.nx -- mesh DECIMATION by dense-grid vertex clustering (Rossignac-Borrel 1993), 2// pure integer. Marching-tetrahedra meshes are dense (many tiny triangles on flat faces); this 3// snaps every vertex to a regular cell grid (cell-CENTROID representative) and drops triangles 4// that collapse (>=2 verts land in the same cell) -> far fewer triangles for the SAME shape, with 5// bounded error <= ~cell. The transfer/size EXCEED: a sovereign STL shrinks Nx with one tolerance 6// knob, deterministically (integer). No hash needed (a dense bbox grid has no key collisions). 7// Reuses nx_mesh + nx_mesh_print_check (bbox). HONEST: this is a SIZE/transfer decimation, lossy 8// by <=~cell and not guaranteed watertight; closure-preserving decimation is a later rung. 9// license_tier: ORIGINAL 10import "nx_syscalls.nx" 11import "nx_mesh.nx" 12import "nx_mesh_print_check.nx" 13 14const NX_DECIM_MAX_CELLS: i64 = 6000000 15 16// linear cell index of (x,y,z) within the grid anchored at (minx,miny,minz), cell size `cell`. 17func decim_cell(x: i64, y: i64, z: i64, minx: i64, miny: i64, minz: i64, 18 cell: i64, nx_: i64, ny_: i64) -> i64 { 19 let cx: i64 = (x - minx) / cell 20 let cy: i64 = (y - miny) / cell 21 let cz: i64 = (z - minz) / cell 22 return cx + cy * nx_ + cz * nx_ * ny_ 23} 24 25func nx_mesh_decimate(m: *NxMesh, cell: i64) -> *NxMesh { 26 if (m as i64) == 0 { return 0 as *NxMesh } 27 if cell <= 0 { return 0 as *NxMesh } 28 let bb: *NxMeshBBox = nx_mesh_bbox_compute(m) 29 if bb.valid != 1 { return 0 as *NxMesh } 30 let minx: i64 = bb.min_x; let miny: i64 = bb.min_y; let minz: i64 = bb.min_z 31 let nx_: i64 = (bb.max_x - minx) / cell + 1 32 let ny_: i64 = (bb.max_y - miny) / cell + 1 33 let nz_: i64 = (bb.max_z - minz) / cell + 1 34 let nc: i64 = nx_ * ny_ * nz_ 35 if nc <= 0 { return 0 as *NxMesh } 36 if nc > NX_DECIM_MAX_CELLS { return 0 as *NxMesh } // cell too fine for this bbox 37 38 let cidx: *i64 = (sys_mmap(nc * 8)) as *i64 39 let sx: *i64 = (sys_mmap(nc * 8)) as *i64 40 let sy: *i64 = (sys_mmap(nc * 8)) as *i64 41 let sz: *i64 = (sys_mmap(nc * 8)) as *i64 42 let cnt: *i64 = (sys_mmap(nc * 8)) as *i64 43 var i: i64 = 0 44 while i < nc { cidx[i] = 0 - 1; sx[i] = 0; sy[i] = 0; sz[i] = 0; cnt[i] = 0; i = i + 1 } 45 46 // pass 1: accumulate centroid sums per occupied cell 47 var v: i64 = 0 48 while v < m.n_verts { 49 let x: i64 = nx_mesh_get_vertex_x(m, v) 50 let y: i64 = nx_mesh_get_vertex_y(m, v) 51 let z: i64 = nx_mesh_get_vertex_z(m, v) 52 let ci: i64 = decim_cell(x, y, z, minx, miny, minz, cell, nx_, ny_) 53 if ci >= 0 { if ci < nc { 54 sx[ci] = sx[ci] + x; sy[ci] = sy[ci] + y; sz[ci] = sz[ci] + z; cnt[ci] = cnt[ci] + 1 55 } } 56 v = v + 1 57 } 58 59 // assign new vertex indices to occupied cells 60 var nv: i64 = 0 61 i = 0 62 while i < nc { if cnt[i] > 0 { cidx[i] = nv; nv = nv + 1 } i = i + 1 } 63 if nv <= 0 { return 0 as *NxMesh } 64 65 // count surviving (non-degenerate) triangles 66 var nt2: i64 = 0 67 var t: i64 = 0 68 while t < m.n_tris { 69 let a: i64 = m.indices[t*3+0]; let b: i64 = m.indices[t*3+1]; let c: i64 = m.indices[t*3+2] 70 let ca: i64 = decim_cell(nx_mesh_get_vertex_x(m,a), nx_mesh_get_vertex_y(m,a), nx_mesh_get_vertex_z(m,a), minx,miny,minz,cell,nx_,ny_) 71 let cb: i64 = decim_cell(nx_mesh_get_vertex_x(m,b), nx_mesh_get_vertex_y(m,b), nx_mesh_get_vertex_z(m,b), minx,miny,minz,cell,nx_,ny_) 72 let cc: i64 = decim_cell(nx_mesh_get_vertex_x(m,c), nx_mesh_get_vertex_y(m,c), nx_mesh_get_vertex_z(m,c), minx,miny,minz,cell,nx_,ny_) 73 if ca != cb { if cb != cc { if ca != cc { nt2 = nt2 + 1 } } } 74 t = t + 1 75 } 76 if nt2 <= 0 { return 0 as *NxMesh } 77 78 let out: *NxMesh = nx_mesh_alloc(nv, nt2, 0) 79 if (out as i64) == 0 { return out } 80 81 // emit centroid vertices (integer average of the cell's members) 82 i = 0 83 while i < nc { 84 if cnt[i] > 0 { 85 nx_mesh_set_vertex(out, cidx[i], sx[i]/cnt[i], sy[i]/cnt[i], sz[i]/cnt[i], 0) 86 } 87 i = i + 1 88 } 89 // emit remapped, non-degenerate triangles 90 var tt: i64 = 0 91 t = 0 92 while t < m.n_tris { 93 let a: i64 = m.indices[t*3+0]; let b: i64 = m.indices[t*3+1]; let c: i64 = m.indices[t*3+2] 94 let ca: i64 = cidx[decim_cell(nx_mesh_get_vertex_x(m,a), nx_mesh_get_vertex_y(m,a), nx_mesh_get_vertex_z(m,a), minx,miny,minz,cell,nx_,ny_)] 95 let cb: i64 = cidx[decim_cell(nx_mesh_get_vertex_x(m,b), nx_mesh_get_vertex_y(m,b), nx_mesh_get_vertex_z(m,b), minx,miny,minz,cell,nx_,ny_)] 96 let cc: i64 = cidx[decim_cell(nx_mesh_get_vertex_x(m,c), nx_mesh_get_vertex_y(m,c), nx_mesh_get_vertex_z(m,c), minx,miny,minz,cell,nx_,ny_)] 97 if ca != cb { if cb != cc { if ca != cc { 98 nx_mesh_set_triangle(out, tt, ca, cb, cc); tt = tt + 1 99 } } } 100 t = t + 1 101 } 102 return out 103}