Files
Gas-Tank-AR-App/GasTankAR/Views/TankAR/PipeRouteEntityFactory.swift
Dennis Nemec b8536d4182 Add tank catalog with USDZ models and tank selection
Introduce TankDefinition/TankCatalog loaded from Tanks.json, bundle the
Drachengas USDZ tank models, add tank selection and preview views, and
update the AR experience, editor and project views to use the catalog.
Includes tests for catalog loading and model selection.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 19:12:39 +02:00

64 lines
2.3 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// PipeRouteEntityFactory.swift
// GasTankAR
//
// Created by Dennis Nemec on 28.08.26.
//
import RealityKit
import UIKit
/// Baut die AR-Visualisierung einer Rohrführung: Wegpunkt-Kugeln und die verbindenden
/// Segmente. Bewusst in einer markanten, naturfremden Farbe (Pink/Magenta) gehalten.
@MainActor
enum PipeRouteEntityFactory {
/// Markante, in der Natur kaum vorkommende Linien-/Punktfarbe.
private static let color = UIColor.systemPink
private static let waypointRadius: Float = 0.02
private static let segmentThickness: Float = 0.012
/// Kugel für einen Wegpunkt.
static func makeWaypoint(at position: SIMD3<Float>) -> ModelEntity {
let sphere = ModelEntity(
mesh: .generateSphere(radius: waypointRadius),
materials: [UnlitMaterial(color: color)]
)
sphere.position = position
return sphere
}
/// Verbindungssegment zwischen zwei Wegpunkten.
static func makeSegment(from start: SIMD3<Float>, to end: SIMD3<Float>) -> ModelEntity {
let segment = makeSegmentBase()
configureSegment(segment, from: start, to: end)
segment.collision = CollisionComponent(shapes: [
ShapeResource.generateBox(size: SIMD3(0.08, 0.08, 1))
])
segment.components.set(InputTargetComponent())
return segment
}
static func setSegmentColor(_ segment: Entity, color: UIColor) {
guard let model = segment as? ModelEntity else { return }
model.model?.materials = [UnlitMaterial(color: color)]
}
/// Basis-Segment der Länge 1 m (entlang +Z) – für die Live-Vorschau wiederverwendbar.
static func makeSegmentBase() -> ModelEntity {
ModelEntity(
mesh: .generateBox(size: SIMD3(segmentThickness, segmentThickness, 1)),
materials: [UnlitMaterial(color: color)]
)
}
/// Richtet ein Segment zwischen zwei Punkten aus (Länge über Z-Skalierung).
static func configureSegment(_ segment: Entity, from start: SIMD3<Float>, to end: SIMD3<Float>) {
let length = max(simd_distance(start, end), 0.0001)
segment.transform = Transform(
scale: SIMD3(1, 1, length),
rotation: simd_quatf(from: SIMD3(0, 0, 1), to: normalize(end - start)),
translation: (start + end) / 2
)
}
}