From 408b8391860ac53566dfa76df0fa064cf481212c Mon Sep 17 00:00:00 2001 From: gsdali <51393997+gsdali@users.noreply.github.com> Date: Thu, 2 Jul 2026 05:52:55 +0900 Subject: [PATCH 1/2] =?UTF-8?q?fix(heatmap):=20ViewportBody.directMesh=20n?= =?UTF-8?q?o=20longer=20exists=20=E2=80=94=20build=20vertexData=20directly?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ViewportBody dropped the directMesh(positions:normals:indices:color:) factory; its real init takes a single interleaved vertexData ([px,py,pz,nx,ny,nz,...], stride 6), not separate positions/normals arrays. Zips the two flat per-vertex arrays HeatmapTools already builds into that layout — the same idiom OCCTSwiftViewport's own primitive factories (e.g. .box) use internally. Verified: swift build succeeds (was failing on this exact API-drift error); swift test --no-parallel passes 48/48, including signed_deviation_heatmap and the other heatmap-adjacent tests that exercise this path. Co-Authored-By: Claude Opus 4.8 (1M context) --- Sources/OCCTMCPCore/Tools/HeatmapTools.swift | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Sources/OCCTMCPCore/Tools/HeatmapTools.swift b/Sources/OCCTMCPCore/Tools/HeatmapTools.swift index 9fcaa81..ae3024c 100644 --- a/Sources/OCCTMCPCore/Tools/HeatmapTools.swift +++ b/Sources/OCCTMCPCore/Tools/HeatmapTools.swift @@ -135,9 +135,19 @@ public enum HeatmapTools { let base = UInt32(indices.count) indices.append(base); indices.append(base + 1); indices.append(base + 2) } - bodies.append(ViewportBody.directMesh( + // ViewportBody.directMesh (positions/normals as separate arrays) no longer exists — + // ViewportBody's init takes a single interleaved vertexData ([px,py,pz,nx,ny,nz,...], + // stride 6), so zip the two flat per-vertex arrays together here (same idiom the + // OCCTSwiftViewport primitive factories, e.g. .box, use internally). + var vertexData: [Float] = [] + vertexData.reserveCapacity(positions.count * 2) + for i in stride(from: 0, to: positions.count, by: 3) { + vertexData.append(positions[i]); vertexData.append(positions[i + 1]); vertexData.append(positions[i + 2]) + vertexData.append(bnormals[i]); vertexData.append(bnormals[i + 1]); vertexData.append(bnormals[i + 2]) + } + bodies.append(ViewportBody( id: "\(fromBodyId)#band\(b)", - positions: positions, normals: bnormals, indices: indices, color: color + vertexData: vertexData, indices: indices, edges: [], color: color )) } guard !bodies.isEmpty else { return .init("No coloured surface produced.", isError: true) } From 1fd9ee0a4eb657f68044104e7972005caca42b69 Mon Sep 17 00:00:00 2001 From: gsdali <51393997+gsdali@users.noreply.github.com> Date: Thu, 2 Jul 2026 05:54:50 +0900 Subject: [PATCH 2/2] fix(deps): guard sibling-path detection against SwiftPM's own checkout layout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Same fleet-wide fix as OCCTSwiftScripts#69/#70 and OCCTSwiftIO's 2026-06-23 fix: occtDep's sibling probe (..//Package.swift) is filesystem-based and fires whenever a same-named directory happens to exist next to this manifest — including when THIS manifest is itself a transitively-resolved SwiftPM checkout under a consumer's .build/checkouts/, where SwiftPM lays every dependency out as a flat sibling. Doesn't affect OCCTMCP's own build (it's the root package here, so its manifestDir is never inside .build/) but matters once OCCTMCP itself is consumed as a dependency by something else — added for fleet-wide consistency with the sweep. Guards both occtDep and occtDepUpToNextMinor. Co-Authored-By: Claude Opus 4.8 (1M context) --- Package.swift | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Package.swift b/Package.swift index dae3352..e0a3ef9 100644 --- a/Package.swift +++ b/Package.swift @@ -15,10 +15,13 @@ import Foundation // Prefer a local sibling checkout (../) when present, else the published URL — so the whole // OCCT ecosystem SHARES the single OCCTSwift/Libraries/OCCT.xcframework instead of each repo // extracting its own 1.3 GB copy. CI / fresh clones (no sibling) use the URL pin. `#filePath`-relative -// so it's independent of build CWD. +// so it's independent of build CWD. Guarded against SwiftPM's own checkout layout: a transitively- +// resolved checkout under a consumer's .build/ must never be treated as a local dev sibling +// (ecosystem issue OCCTSwiftScripts#69 / #70). func occtDep(_ name: String, from version: String) -> Package.Dependency { let manifestDir = URL(fileURLWithPath: #filePath).deletingLastPathComponent().path - if FileManager.default.fileExists(atPath: manifestDir + "/../\(name)/Package.swift") { + if !manifestDir.contains("/.build/"), + FileManager.default.fileExists(atPath: manifestDir + "/../\(name)/Package.swift") { return .package(path: "../\(name)") } return .package(url: "https://github.com/SecondMouseAU/\(name).git", from: Version(version)!) @@ -27,9 +30,11 @@ func occtDep(_ name: String, from version: String) -> Package.Dependency { // As occtDep, but pins to the package's minor line (`.upToNextMinor`) instead of // the major. Used to cap a transitive dependency whose newer minors pull deps we // don't want in the graph — see the OCCTSwiftIO note in `dependencies` below. +// Same checkout-layout guard as occtDep (ecosystem issue OCCTSwiftScripts#69 / #70). func occtDepUpToNextMinor(_ name: String, from version: String) -> Package.Dependency { let manifestDir = URL(fileURLWithPath: #filePath).deletingLastPathComponent().path - if FileManager.default.fileExists(atPath: manifestDir + "/../\(name)/Package.swift") { + if !manifestDir.contains("/.build/"), + FileManager.default.fileExists(atPath: manifestDir + "/../\(name)/Package.swift") { return .package(path: "../\(name)") } return .package(url: "https://github.com/SecondMouseAU/\(name).git", .upToNextMinor(from: Version(version)!))