From 1e89ea22d551cebfd6c0c0451000c3283ddb2d2e Mon Sep 17 00:00:00 2001 From: Ruben Beltran del Rio Date: Wed, 9 Jul 2025 08:43:04 +0200 Subject: Get rid of old map parser --- Map/Business/RenderableMap.swift | 210 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 Map/Business/RenderableMap.swift (limited to 'Map/Business/RenderableMap.swift') diff --git a/Map/Business/RenderableMap.swift b/Map/Business/RenderableMap.swift new file mode 100644 index 0000000..c8ab776 --- /dev/null +++ b/Map/Business/RenderableMap.swift @@ -0,0 +1,210 @@ +// Copyright (C) 2024 Rubén Beltrán del Río + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see https://map.tranquil.systems. +import Foundation + +struct RenderableMap { + let vertices: [Vertex] + let edges: [MapEdge] + let inertias: [Inertia] + let opportunities: [Opportunity] + let notes: [Note] + let stages: [CGFloat] + let groups: [[Vertex]] + + static let empty: RenderableMap = RenderableMap( + vertices: [], edges: [], inertias: [], opportunities: [], notes: [], stages: defaultDimensions, + groups: []) + + static func from(_ entities: [Wmap.Entity]) -> RenderableMap { + var vertices: [Vertex] = [] + var edges: [MapEdge] = [] + var inertias: [Inertia] = [] + var opportunities: [Opportunity] = [] + var notes: [Note] = [] + var stages: [CGFloat] = [25.0, 50.0, 75.0] // default dimensions + var groups: [[Vertex]] = [] + + // Build a vertex lookup for edges, groups, etc. + var vertexMap: [String: Vertex] = [:] + var vertexIdCounter = 0 + + for entity in entities { + switch entity { + case .vertex(let vertex): + let newVertex = Vertex( + id: vertexIdCounter, + label: vertex.label, + position: CGPoint(x: vertex.coordinates.0, y: vertex.coordinates.1), + shape: convertShape(vertex.shape) + ) + vertices.append(newVertex) + vertexMap[vertex.label] = newVertex + vertexIdCounter += 1 + + case .note(let note): + notes.append( + Note( + id: notes.count, + position: CGPoint(x: note.coordinates.0, y: note.coordinates.1), + text: note.text + )) + + case .stage(let stage): + let stageIndex = convertStageNumber(stage.number) - 1 + if stageIndex >= 0 && stageIndex < 3 { + stages[stageIndex] = stage.value + } + + default: + continue + } + } + + // Second pass for entities that depend on vertices + for entity in entities { + switch entity { + case .edge(let edge): + if let fromVertex = vertexMap[edge.from], + let toVertex = vertexMap[edge.to] + { + edges.append( + MapEdge( + id: edges.count, + origin: fromVertex.position, + destination: toVertex.position, + arrowhead: edge.isDirected + )) + } + + case .inertia(let inertia): + if let vertex = vertexMap[inertia.vertex] { + inertias.append( + Inertia( + id: inertias.count, + position: vertex.position + )) + } + + case .evolution(let evolution): + if let vertex = vertexMap[evolution.vertex] { + let direction: CGFloat = evolution.isPositive ? 1.0 : -1.0 + let destination = CGPoint( + x: vertex.position.x + (direction * evolution.value), + y: vertex.position.y + ) + opportunities.append( + Opportunity( + id: opportunities.count, + origin: vertex.position, + destination: destination + )) + } + + case .group(let group): + var groupVertices: [Vertex] = [] + for vertexName in group.vertices { + if let vertex = vertexMap[vertexName] { + groupVertices.append(vertex) + } + } + if !groupVertices.isEmpty { + groups.append(groupVertices) + } + + default: + continue + } + } + + return RenderableMap( + vertices: vertices, + edges: edges, + inertias: inertias, + opportunities: opportunities, + notes: notes, + stages: stages, + groups: groups + ) + } + + private static func convertShape(_ shape: String?) -> VertexShape { + guard let shape = shape?.lowercased() else { return .circle } + switch shape { + case "square": return .square + case "triangle": return .triangle + case "x": return .x + default: return .circle + } + } + + private static func convertStageNumber(_ stageNumber: String) -> Int { + switch stageNumber.lowercased() { + case "i": return 1 + case "ii": return 2 + case "iii": return 3 + case "iv": return 4 + default: return 1 + } + } +} + +struct Vertex: Identifiable, Hashable { + let id: Int + let label: String + let position: CGPoint + var shape: VertexShape = .circle +} + +struct Note { + let id: Int + let position: CGPoint + let text: String +} + +enum VertexShape: String { + case circle + case square + case triangle + case x +} + +struct MapEdge { + let id: Int + let origin: CGPoint + let destination: CGPoint + let arrowhead: Bool +} + +struct Inertia { + let id: Int + let position: CGPoint +} + +struct Opportunity { + let id: Int + let origin: CGPoint + let destination: CGPoint +} + +struct StageDimensions { + let index: Int + let dimensions: CGFloat +} + +private let defaultDimensions: [CGFloat] = [ + 25.0, + 50.0, + 75.0, +] -- cgit