code wiki / (root) / nx_meshseg3d.nx

nx_meshseg3d.nx source

↩ module page · 81 lines · 3283 B

1// nx_meshseg3d.nx -- 3D PART SEGMENTATION of a triangle mesh (cadtwin P2): decompose a scanned mesh into its 2// component PARTS so each can be analyzed (per-part wall-thickness R5 + underbuilt R6). Classical region-growing: 3// (a) CONNECTIVITY -- disconnected mesh pieces = separate parts; (b) CREASE -- within a connected piece, split 4// at sharp dihedral edges (adjacent face normals differ by more than a DATA-DRIVEN threshold). ONE function 5// with a cos-threshold param does both (threshold = -Q -> pure connectivity; higher -> crease-split). The 6// neural SOTA (SAMPart3D/PartField, PartObjaverse-Tiny mIoU ~84) is trained-model-bound; this is the sovereign 7// classical first rung. Composes nx_mesh3 + nx_meshthick (face normals). Deterministic. license_tier: ORIGINAL 8import "nx_meshthick.nx" 9 10// two triangles adjacent iff they share exactly 2 vertex indices (a common edge) 11func ms_adjacent(base: i64, i: i64, j: i64) -> i64 { 12 let ti: *i64 = m3_tri(base, i) 13 let tj: *i64 = m3_tri(base, j) 14 var common: i64 = 0 15 var a: i64 = 0 16 while a < 3 { 17 var b: i64 = 0 18 while b < 3 { 19 if ti[a] == tj[b] { common = common + 1 } 20 b = b + 1 21 } 22 a = a + 1 23 } 24 if common >= 2 { return 1 } 25 return 0 26} 27 28// segment faces by region-growing across edges whose adjacent-normal dot >= cos_thresh (Q14). labels[F] filled 29// with segment ids 0..k-1. Returns k = number of segments. scratch: queue[F], n1[3], n2[3] via mmap once. 30func ms_segment(base: i64, cos_thresh: i64, labels: *i64) -> i64 { 31 let h: *i64 = m3_hdr(base) 32 let nf: i64 = h[1] 33 var i: i64 = 0 34 while i < nf { labels[i] = 0 - 1; i = i + 1 } 35 let queue: *i64 = sys_mmap((nf + 8) * 8) as *i64 36 let n1: *i64 = sys_mmap(32) as *i64 37 let n2: *i64 = sys_mmap(32) as *i64 38 var seg: i64 = 0 39 var f: i64 = 0 40 while f < nf { 41 if labels[f] < 0 { 42 // new segment via BFS 43 labels[f] = seg 44 queue[0] = f 45 var qh: i64 = 0 46 var qt: i64 = 1 47 while qh < qt { 48 let cur: i64 = queue[qh] 49 qh = qh + 1 50 mtk_face_normal(base, cur, n1) 51 var g: i64 = 0 52 while g < nf { 53 if labels[g] < 0 { 54 if ms_adjacent(base, cur, g) == 1 { 55 mtk_face_normal(base, g, n2) 56 let d: i64 = (n1[0] * n2[0] + n1[1] * n2[1] + n1[2] * n2[2]) / 256 // fx256 unit normals -> cos*256... see note 57 if d >= cos_thresh { 58 labels[g] = seg 59 queue[qt] = g 60 qt = qt + 1 61 } 62 } 63 } 64 g = g + 1 65 } 66 } 67 seg = seg + 1 68 } 69 f = f + 1 70 } 71 return seg 72} 73 74// count faces in each segment into counts[k]; returns nothing meaningful 75func ms_seg_sizes(labels: *i64, nf: i64, counts: *i64, k: i64) -> i64 { 76 var i: i64 = 0 77 while i < k { counts[i] = 0; i = i + 1 } 78 i = 0 79 while i < nf { let s: i64 = labels[i]; if s >= 0 { counts[s] = counts[s] + 1 } i = i + 1 } 80 return 0 81}