diff --git a/Package.resolved b/Package.resolved
index eee1671..c4b5a89 100644
--- a/Package.resolved
+++ b/Package.resolved
@@ -1,13 +1,13 @@
{
- "originHash" : "0e11f021a4d366bad494e92af92839bdf3a2394466e3876a9e1c2182012bd394",
+ "originHash" : "193f12a2c125ba349244b6ef2c622ab89425ebd63522973119c7c5869efbaa80",
"pins" : [
{
"identity" : "occtswift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/gsdali/OCCTSwift.git",
"state" : {
- "revision" : "6e3f99603ed14790816cb4857a6df20848bd11ca",
- "version" : "1.7.1"
+ "revision" : "94eea64c25c265f268ecd6da6fef36b05a60ce9b",
+ "version" : "1.8.0"
}
},
{
diff --git a/Package.swift b/Package.swift
index b0e25c7..8b7b7dd 100644
--- a/Package.swift
+++ b/Package.swift
@@ -42,7 +42,9 @@ let package = Package(
// setters no-op but getters return the live derived value. The cookbook
// ergonomics relied on since v1.3.1 (circularPatternCut #169, sweep
// orientation #170, concave/convex/edges(where:) #171) are unchanged.
- .package(url: "https://github.com/gsdali/OCCTSwift.git", from: "1.7.1"),
+ // 1.8.0 adds Exporter.writeBREP(allowInvalid:) for the load-brep /
+ // import `--allow-invalid` flags (OCCTMCP #41).
+ .package(url: "https://github.com/gsdali/OCCTSwift.git", from: "1.8.0"),
// RenderPreview rasterizes through Viewport's OffscreenRenderer.
// Floored at v1.0.4: v1.0.3 fixes an uncatchable quantize() crash on
// body load (Viewport #30) and v1.0.4 makes the published Viewport
diff --git a/Sources/ScriptHarness/GraphIO.swift b/Sources/ScriptHarness/GraphIO.swift
index ec1a387..ad85569 100644
--- a/Sources/ScriptHarness/GraphIO.swift
+++ b/Sources/ScriptHarness/GraphIO.swift
@@ -32,10 +32,13 @@ public enum GraphIO {
}
}
- public static func writeBREP(_ shape: Shape, to path: String) throws {
+ /// - Parameter allowInvalid: skip the `shape.isValid` write gate so an
+ /// in-progress / loose-face reconstruction can be persisted as-is
+ /// (OCCTSwift ≥ 1.8.0; loadBREP doesn't gate on read).
+ public static func writeBREP(_ shape: Shape, to path: String, allowInvalid: Bool = false) throws {
let url = URL(fileURLWithPath: path)
do {
- try Exporter.writeBREP(shape: shape, to: url)
+ try Exporter.writeBREP(shape: shape, to: url, allowInvalid: allowInvalid)
} catch {
throw ScriptError.message("Failed to write BREP at \(path): \(error.localizedDescription)")
}
diff --git a/Sources/occtkit/Commands/Import.swift b/Sources/occtkit/Commands/Import.swift
index 5309f58..0f41a39 100644
--- a/Sources/occtkit/Commands/Import.swift
+++ b/Sources/occtkit/Commands/Import.swift
@@ -43,7 +43,7 @@ enum ImportCommand: Subcommand {
Usage:
import --emit-manifest
[--format auto|step|iges|stl|obj]
- [--id-prefix ] [--preserve-assembly] [--heal-on-import]
+ [--id-prefix
] [--preserve-assembly] [--heal-on-import] [--allow-invalid]
import (JSON request from file)
import (JSON request from stdin)
"""
@@ -55,6 +55,7 @@ enum ImportCommand: Subcommand {
var idPrefix: String
var preserveAssembly: Bool
var healOnImport: Bool
+ var allowInvalid: Bool
}
private enum Format: String, Decodable {
@@ -68,6 +69,7 @@ enum ImportCommand: Subcommand {
let idPrefix: String?
let preserveAssembly: Bool?
let healOnImport: Bool?
+ let allowInvalid: Bool?
}
struct Response: Encodable {
@@ -107,7 +109,8 @@ enum ImportCommand: Subcommand {
let document = try loadDocumentSTEP(path: req.inputPath)
assembly = try walkAssembly(
document: document, emitDir: emitDir,
- idPrefix: req.idPrefix, bodies: &bodies, addedIds: &addedIds
+ idPrefix: req.idPrefix, allowInvalid: req.allowInvalid,
+ bodies: &bodies, addedIds: &addedIds
)
} else {
if req.preserveAssembly && format != .step {
@@ -116,7 +119,7 @@ enum ImportCommand: Subcommand {
let shape = try loadSingleShape(format: format, path: req.inputPath)
let id = "\(req.idPrefix)_0"
let bodyURL = emitDir.appendingPathComponent("\(id).brep")
- try GraphIO.writeBREP(shape, to: bodyURL.path)
+ try GraphIO.writeBREP(shape, to: bodyURL.path, allowInvalid: req.allowInvalid)
bodies.append(BodyDescriptor(id: id, file: "\(id).brep"))
addedIds.append(id)
}
@@ -185,6 +188,7 @@ enum ImportCommand: Subcommand {
document: Document,
emitDir: URL,
idPrefix: String,
+ allowInvalid: Bool,
bodies: inout [BodyDescriptor],
addedIds: inout [String]
) throws -> Response.Assembly {
@@ -195,7 +199,8 @@ enum ImportCommand: Subcommand {
for root in roots {
let component = try walkNode(
node: root, idPrefix: idPrefix, parentPathSegment: nil,
- emitDir: emitDir, bodies: &bodies, addedIds: &addedIds, counter: &counter
+ emitDir: emitDir, allowInvalid: allowInvalid,
+ bodies: &bodies, addedIds: &addedIds, counter: &counter
)
components.append(component)
}
@@ -209,6 +214,7 @@ enum ImportCommand: Subcommand {
idPrefix: String,
parentPathSegment: String?,
emitDir: URL,
+ allowInvalid: Bool,
bodies: inout [BodyDescriptor],
addedIds: inout [String],
counter: inout Int
@@ -219,7 +225,7 @@ enum ImportCommand: Subcommand {
// Write geometry if this node has any (pure-assembly nodes have no shape).
if let shape = node.shape {
let bodyURL = emitDir.appendingPathComponent("\(id).brep")
- try GraphIO.writeBREP(shape, to: bodyURL.path)
+ try GraphIO.writeBREP(shape, to: bodyURL.path, allowInvalid: allowInvalid)
bodies.append(BodyDescriptor(
id: id,
file: "\(id).brep",
@@ -238,7 +244,8 @@ enum ImportCommand: Subcommand {
for child in node.children {
children.append(try walkNode(
node: child, idPrefix: idPrefix, parentPathSegment: id,
- emitDir: emitDir, bodies: &bodies, addedIds: &addedIds, counter: &counter
+ emitDir: emitDir, allowInvalid: allowInvalid,
+ bodies: &bodies, addedIds: &addedIds, counter: &counter
))
}
@@ -272,6 +279,7 @@ enum ImportCommand: Subcommand {
var idPrefix: String = "imported"
var preserveAssembly = false
var healOnImport = false
+ var allowInvalid = false
var i = 1
while i < args.count {
switch args[i] {
@@ -290,6 +298,8 @@ enum ImportCommand: Subcommand {
preserveAssembly = true
case "--heal-on-import":
healOnImport = true
+ case "--allow-invalid":
+ allowInvalid = true
default:
throw ScriptError.message("Unknown flag: \(args[i])")
}
@@ -298,7 +308,7 @@ enum ImportCommand: Subcommand {
guard let emitManifest else { throw ScriptError.message("--emit-manifest is required") }
return Request(inputPath: inputPath, emitManifest: emitManifest, format: format,
idPrefix: idPrefix, preserveAssembly: preserveAssembly,
- healOnImport: healOnImport)
+ healOnImport: healOnImport, allowInvalid: allowInvalid)
}
private static func valueOrThrow(args: [String], i: Int, flag: String) throws -> String {
@@ -326,7 +336,8 @@ enum ImportCommand: Subcommand {
format: raw.format ?? .auto,
idPrefix: raw.idPrefix ?? "imported",
preserveAssembly: raw.preserveAssembly ?? false,
- healOnImport: raw.healOnImport ?? false
+ healOnImport: raw.healOnImport ?? false,
+ allowInvalid: raw.allowInvalid ?? false
)
}
}
diff --git a/Sources/occtkit/Commands/LoadBrep.swift b/Sources/occtkit/Commands/LoadBrep.swift
index 1d860e9..2193c47 100644
--- a/Sources/occtkit/Commands/LoadBrep.swift
+++ b/Sources/occtkit/Commands/LoadBrep.swift
@@ -29,7 +29,7 @@ enum LoadBrepCommand: Subcommand {
static let summary = "Load a BREP and emit a manifest entry for OCCTSwiftViewport"
static let usage = """
Usage:
- load-brep --emit-manifest [--id ] [--color ]
+ load-brep --emit-manifest [--id ] [--color ] [--allow-invalid]
load-brep (JSON request from file)
load-brep (JSON request from stdin)
"""
@@ -39,6 +39,7 @@ enum LoadBrepCommand: Subcommand {
var emitManifest: String
var id: String?
var color: String?
+ var allowInvalid: Bool
}
private struct JSONRequest: Decodable {
@@ -46,6 +47,7 @@ enum LoadBrepCommand: Subcommand {
let emitManifest: String
let id: String?
let color: String?
+ let allowInvalid: Bool?
}
struct Response: Encodable {
@@ -71,7 +73,7 @@ enum LoadBrepCommand: Subcommand {
let emitDir = URL(fileURLWithPath: req.emitManifest)
try? FileManager.default.createDirectory(at: emitDir, withIntermediateDirectories: true)
let bodyURL = emitDir.appendingPathComponent("\(bodyId).brep")
- try GraphIO.writeBREP(shape, to: bodyURL.path)
+ try GraphIO.writeBREP(shape, to: bodyURL.path, allowInvalid: req.allowInvalid)
let manifest = ScriptManifest(
description: "Imported via load-brep",
@@ -104,6 +106,7 @@ enum LoadBrepCommand: Subcommand {
var emitManifest: String?
var id: String?
var color: String?
+ var allowInvalid = false
var i = 1
while i < args.count {
switch args[i] {
@@ -119,13 +122,16 @@ enum LoadBrepCommand: Subcommand {
i += 1
guard i < args.count else { throw ScriptError.message("--color expects a value") }
color = args[i]
+ case "--allow-invalid":
+ allowInvalid = true
default:
throw ScriptError.message("Unknown flag: \(args[i])")
}
i += 1
}
guard let emitManifest else { throw ScriptError.message("--emit-manifest is required") }
- return Request(inputBrep: inputBrep, emitManifest: emitManifest, id: id, color: color)
+ return Request(inputBrep: inputBrep, emitManifest: emitManifest, id: id, color: color,
+ allowInvalid: allowInvalid)
}
private static func readFile(_ path: String) throws -> Data {
@@ -143,7 +149,7 @@ enum LoadBrepCommand: Subcommand {
throw ScriptError.message("Invalid JSON: \(error.localizedDescription)")
}
return Request(inputBrep: raw.inputBrep, emitManifest: raw.emitManifest,
- id: raw.id, color: raw.color)
+ id: raw.id, color: raw.color, allowInvalid: raw.allowInvalid ?? false)
}
// MARK: - Helpers (shared with Import)