Skip to content

Commit 1a48702

Browse files
committed
Add default implementation for importGeometry()
1 parent 73542ed commit 1a48702

File tree

8 files changed

+75
-72
lines changed

8 files changed

+75
-72
lines changed

ShapeScript.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@
8585
0183AAED28EC3ACB00AD1984 /* Settings+Editor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0183AAE128EC3ACB00AD1984 /* Settings+Editor.swift */; };
8686
01977FCB215D0BD400D65D5E /* Scene.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01977FCA215D0BD400D65D5E /* Scene.swift */; };
8787
019853A228360F7500047DF2 /* TypesystemTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 019853A128360F7500047DF2 /* TypesystemTests.swift */; };
88+
01994BF82B3EB7EE004DE69C /* EvaluationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01994BF72B3EB7EE004DE69C /* EvaluationDelegate.swift */; };
8889
01A6FE7D2AEF5BCB006AE113 /* Members.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01A6FE7C2AEF5BCB006AE113 /* Members.swift */; };
8990
01A6FE832AEF5D2A006AE113 /* MemberTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01A6FE822AEF5D2A006AE113 /* MemberTests.swift */; };
9091
01A6FECD2AF9ADB1006AE113 /* Material+SceneKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01A6FECC2AF9ADB1006AE113 /* Material+SceneKit.swift */; };
@@ -391,6 +392,7 @@
391392
0183AAE128EC3ACB00AD1984 /* Settings+Editor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Settings+Editor.swift"; sourceTree = "<group>"; };
392393
01977FCA215D0BD400D65D5E /* Scene.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Scene.swift; sourceTree = "<group>"; };
393394
019853A128360F7500047DF2 /* TypesystemTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TypesystemTests.swift; sourceTree = "<group>"; };
395+
01994BF72B3EB7EE004DE69C /* EvaluationDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EvaluationDelegate.swift; sourceTree = "<group>"; };
394396
01A6FE7C2AEF5BCB006AE113 /* Members.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Members.swift; sourceTree = "<group>"; };
395397
01A6FE822AEF5D2A006AE113 /* MemberTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemberTests.swift; sourceTree = "<group>"; };
396398
01A6FECC2AF9ADB1006AE113 /* Material+SceneKit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Material+SceneKit.swift"; sourceTree = "<group>"; };
@@ -640,6 +642,7 @@
640642
014F85D8215B890100461FB7 /* Interpreter.swift */,
641643
01DE96702A082A6A0080DB79 /* ProgramError.swift */,
642644
013312D221C9BBCC00626F1B /* EvaluationContext.swift */,
645+
01994BF72B3EB7EE004DE69C /* EvaluationDelegate.swift */,
643646
013DB0BD21C8731C00DFB0D2 /* StandardLibrary.swift */,
644647
01BD943821936B90005FFAEC /* RandomSequence.swift */,
645648
01FDE3D426BD766C00A46F66 /* GeometryCache.swift */,
@@ -1140,6 +1143,7 @@
11401143
isa = PBXSourcesBuildPhase;
11411144
buildActionMask = 2147483647;
11421145
files = (
1146+
01994BF82B3EB7EE004DE69C /* EvaluationDelegate.swift in Sources */,
11431147
01CF787226EA36AD0097907A /* String+Ordinals.swift in Sources */,
11441148
014F85D9215B890100461FB7 /* Interpreter.swift in Sources */,
11451149
01E3AA0526CB8E8200E0B287 /* Value+Logging.swift in Sources */,

ShapeScript/EvaluationContext.swift

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ import CoreGraphics
1717
import CoreText
1818
#endif
1919

20+
#if canImport(SceneKit)
21+
import SceneKit
22+
#endif
23+
2024
// MARK: Implementation
2125

2226
public struct SourceLocation: Hashable {
@@ -328,6 +332,52 @@ extension EvaluationContext {
328332
#endif
329333
}
330334

335+
func importGeometry(at url: URL) throws -> Geometry? {
336+
if let geometry = try delegate?.importGeometry(for: url) {
337+
// Allow delegate to implement alternative loading mechanism, e.g. hard-coded geometry for testing
338+
return geometry
339+
}
340+
switch url.pathExtension.lowercased() {
341+
case "stl", "stla":
342+
let data = try Data(contentsOf: url)
343+
if let mesh = Mesh(stlData: data, materialLookup: {
344+
Material(color: $0)
345+
}) {
346+
return Geometry(
347+
type: .mesh(mesh),
348+
name: nil,
349+
transform: .identity,
350+
material: .default,
351+
smoothing: nil,
352+
children: [],
353+
sourceLocation: nil
354+
)
355+
}
356+
default:
357+
break
358+
}
359+
var isDirectory: ObjCBool = false
360+
_ = FileManager.default.fileExists(atPath: url.path, isDirectory: &isDirectory)
361+
var url = url
362+
if isDirectory.boolValue {
363+
let newURL = url.appendingPathComponent(url.lastPathComponent)
364+
if FileManager.default.fileExists(atPath: newURL.path) {
365+
url = newURL
366+
}
367+
}
368+
#if canImport(SceneKit)
369+
let scene = try SCNScene(url: url, options: [
370+
.flattenScene: false,
371+
.createNormalsIfAbsent: true,
372+
.convertToYUp: true,
373+
.preserveOriginalTopology: true,
374+
])
375+
return try Geometry(scene.rootNode)
376+
#else
377+
return nil
378+
#endif
379+
}
380+
331381
func importFile(at path: String) throws -> Value {
332382
let url = try resolveURL(for: path)
333383
if importStack.contains(url) {
@@ -407,7 +457,7 @@ extension EvaluationContext {
407457
}
408458
default:
409459
do {
410-
if let geometry = try delegate?.importGeometry(for: url)?.with(
460+
if let geometry = try importGeometry(at: url)?.with(
411461
transform: childTransform,
412462
material: material,
413463
sourceLocation: sourceLocation
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//
2+
// EvaluationDelegate.swift
3+
// ShapeScript Lib
4+
//
5+
// Created by Nick Lockwood on 29/12/2023.
6+
// Copyright © 2023 Nick Lockwood. All rights reserved.
7+
//
8+
9+
import Euclid
10+
import Foundation
11+
12+
public protocol EvaluationDelegate: AnyObject {
13+
func resolveURL(for path: String) -> URL
14+
func importGeometry(for url: URL) throws -> Geometry?
15+
func debugLog(_ values: [AnyHashable])
16+
}
17+
18+
public extension EvaluationDelegate {
19+
func importGeometry(for _: URL) throws -> Geometry? { nil }
20+
}

ShapeScript/Interpreter.swift

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,6 @@ import Foundation
1313

1414
public let version = "1.8.0"
1515

16-
public protocol EvaluationDelegate: AnyObject {
17-
func resolveURL(for path: String) -> URL
18-
func importGeometry(for url: URL) throws -> Geometry?
19-
func debugLog(_ values: [AnyHashable])
20-
}
21-
2216
public func evaluate(
2317
_ program: Program,
2418
delegate: EvaluationDelegate?,

ShapeScriptTests/MetadataTests.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,6 @@ class MetadataTests: XCTestCase {
608608
609609
func testExamplesAllRunWithoutError() {
610610
class TestDelegate: EvaluationDelegate {
611-
func importGeometry(for _: URL) throws -> Geometry? { nil }
612611
func debugLog(_: [AnyHashable]) {}
613612
614613
func resolveURL(for name: String) -> URL {

ShapeScriptTests/TestDelegate.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,6 @@ class TestDelegate: EvaluationDelegate {
1717
self.directory = directory
1818
}
1919

20-
func importGeometry(for _: URL) throws -> Geometry? {
21-
preconditionFailure()
22-
}
23-
2420
var imports = [String]()
2521
func resolveURL(for name: String) -> URL {
2622
imports.append(name)

Viewer/CLI/CLI.swift

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -120,28 +120,6 @@ extension CLI: EvaluationDelegate {
120120
URL(fileURLWithPath: path, relativeTo: inputURL)
121121
}
122122

123-
func importGeometry(for url: URL) throws -> Geometry? {
124-
var isDirectory: ObjCBool = false
125-
_ = FileManager.default.fileExists(atPath: url.path, isDirectory: &isDirectory)
126-
var url = url
127-
if isDirectory.boolValue {
128-
let newURL = url.appendingPathComponent(url.lastPathComponent)
129-
if FileManager.default.fileExists(atPath: newURL.path) {
130-
url = newURL
131-
}
132-
}
133-
#if canImport(SceneKit)
134-
let scene = try SCNScene(url: url, options: [
135-
.flattenScene: false,
136-
.createNormalsIfAbsent: true,
137-
.convertToYUp: true,
138-
])
139-
return try Geometry(scene.rootNode)
140-
#else
141-
return nil
142-
#endif
143-
}
144-
145123
func debugLog(_ values: [AnyHashable]) {
146124
var spaceNeeded = false
147125
print(values.compactMap {

Viewer/Shared/Document+EvaluationDelegate.swift

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -28,44 +28,6 @@ extension Document: EvaluationDelegate {
2828
return url
2929
}
3030

31-
func importGeometry(for url: URL) throws -> Geometry? {
32-
var isDirectory: ObjCBool = false
33-
_ = FileManager.default.fileExists(atPath: url.path, isDirectory: &isDirectory)
34-
var url = url
35-
if isDirectory.boolValue {
36-
let newURL = url.appendingPathComponent(url.lastPathComponent)
37-
if FileManager.default.fileExists(atPath: newURL.path) {
38-
url = newURL
39-
}
40-
}
41-
let data = try Data(contentsOf: url)
42-
switch url.pathExtension.lowercased() {
43-
case "stl":
44-
if let mesh = Mesh(stlData: data, materialLookup: {
45-
Material(color: $0)
46-
}) {
47-
return Geometry(
48-
type: .mesh(mesh),
49-
name: nil,
50-
transform: .identity,
51-
material: .default,
52-
smoothing: nil,
53-
children: [],
54-
sourceLocation: nil
55-
)
56-
}
57-
default:
58-
break
59-
}
60-
let scene = try SCNScene(url: url, options: [
61-
.flattenScene: false,
62-
.createNormalsIfAbsent: true,
63-
.convertToYUp: true,
64-
.preserveOriginalTopology: true,
65-
])
66-
return try Geometry(scene.rootNode)
67-
}
68-
6931
func debugLog(_ values: [AnyHashable]) {
7032
let line: String
7133
if values.count == 1 {

0 commit comments

Comments
 (0)