// // PipeRoute.swift // GasTankAR // // Created by Dennis Nemec on 28.08.26. // import Foundation import simd /// Eine Rohrführung als geordnete Folge von Wegpunkten (Welt-Koordinaten), die zu einem /// zusammenhängenden Pfad verbunden werden – visualisiert die geplante Rohrverlegung. struct PipeRoute: Codable { private(set) var waypoints: [SIMD3] = [] private(set) var removedSegmentIndices: Set = [] var count: Int { waypoints.count } /// Gesamtlänge des Pfads über alle aktiven Segmente in Metern. var totalLength: Float { guard waypoints.count > 1 else { return 0 } return zip(waypoints, waypoints.dropFirst()) .enumerated() .filter { !removedSegmentIndices.contains($0.offset) } .reduce(0) { $0 + simd_distance($1.element.0, $1.element.1) } } func isSegmentRemoved(at index: Int) -> Bool { removedSegmentIndices.contains(index) } mutating func removeSegmentAndOrphanedWaypoints(at index: Int) { guard index >= 0, index < waypoints.count - 1 else { return } removedSegmentIndices.insert(index) var connected = Array(repeating: false, count: waypoints.count) for segmentIndex in 0..<(waypoints.count - 1) where !removedSegmentIndices.contains(segmentIndex) { connected[segmentIndex] = true connected[segmentIndex + 1] = true } let oldToNew = connected.enumerated().reduce(into: [Int: Int]()) { result, item in if item.element { result[item.offset] = result.count } } let oldRemovedSegments = removedSegmentIndices waypoints = waypoints.enumerated() .filter { connected[$0.offset] } .map(\.element) removedSegmentIndices = Set( oldRemovedSegments.compactMap { oldIndex in guard let newIndex = oldToNew[oldIndex], oldToNew[oldIndex + 1] != nil else { return nil } return newIndex } ) } var formattedLength: String { String(format: "%.2f m", totalLength) } mutating func add(_ waypoint: SIMD3) { waypoints.append(waypoint) } @discardableResult mutating func removeLast() -> SIMD3? { guard !waypoints.isEmpty else { return nil } let removedIndex = waypoints.count - 2 removedSegmentIndices.remove(removedIndex) removedSegmentIndices = Set( removedSegmentIndices.map { index in index > removedIndex ? index - 1 : index } ) return waypoints.removeLast() } mutating func clear() { waypoints.removeAll() removedSegmentIndices.removeAll() } } /// Ablaufphasen beim Erstellen einer Rohrführung. enum PipeRoutingPhase: Equatable { /// Kein Rohr-Routing aktiv. case idle /// Wegpunkte werden gesetzt. case placing }