diff options
| author | Ruben Beltran del Rio <ruben@unlimited.pizza> | 2021-02-03 23:53:12 +0100 |
|---|---|---|
| committer | Ruben Beltran del Rio <ruben@unlimited.pizza> | 2021-02-03 23:53:12 +0100 |
| commit | 5e8ff4850c4827125fe12788dd5b153c4f636f48 (patch) | |
| tree | f37c90338f33e7ddc84cc855a20dca1ca503476e /Map/Extensions | |
| parent | 1b85f723b48d38cf345bb9a4f3fd01aa6039b50b (diff) | |
Add code for first release
Diffstat (limited to 'Map/Extensions')
| -rw-r--r-- | Map/Extensions/Binding+unwrap.swift | 12 | ||||
| -rw-r--r-- | Map/Extensions/Date+format.swift | 12 | ||||
| -rw-r--r-- | Map/Extensions/Map+parse.swift | 255 | ||||
| -rw-r--r-- | Map/Extensions/NSImage+writePNG.swift | 25 |
4 files changed, 213 insertions, 91 deletions
diff --git a/Map/Extensions/Binding+unwrap.swift b/Map/Extensions/Binding+unwrap.swift deleted file mode 100644 index 3498cc3..0000000 --- a/Map/Extensions/Binding+unwrap.swift +++ /dev/null @@ -1,12 +0,0 @@ -import SwiftUI - -extension Binding { - init(_ source: Binding<Value?>, _ defaultValue: Value) { - // Ensure a non-nil value in `source`. - if source.wrappedValue == nil { - source.wrappedValue = defaultValue - } - // Unsafe unwrap because *we* know it's non-nil now. - self.init(source)! - } -} diff --git a/Map/Extensions/Date+format.swift b/Map/Extensions/Date+format.swift index c12e67d..d29ed0f 100644 --- a/Map/Extensions/Date+format.swift +++ b/Map/Extensions/Date+format.swift @@ -8,10 +8,10 @@ import Foundation extension Date { - func format() -> String { - let formatter = DateFormatter() - formatter.dateStyle = .short - formatter.timeStyle = .medium - return formatter.string(from: self) - } + func format() -> String { + let formatter = DateFormatter() + formatter.dateStyle = .short + formatter.timeStyle = .medium + return formatter.string(from: self) + } } diff --git a/Map/Extensions/Map+parse.swift b/Map/Extensions/Map+parse.swift index 03e7993..d82ba99 100644 --- a/Map/Extensions/Map+parse.swift +++ b/Map/Extensions/Map+parse.swift @@ -1,106 +1,215 @@ import CoreGraphics import Foundation -let VERTEX_PATTERN = "([^\\(]+?)[\\s]*\\([\\s]*([0-9]+.?[0-9]*)[\\s]*,[\\s]*([0-9]+.?[0-9]*)[\\s]*\\)" -let EDGE_PATTERN = "(.+?)[\\s]*->[\\s]*(.+)" +let vertexPattern = + "([^\\(]+?)[\\s]*\\([\\s]*([0-9]+.?[0-9]*)[\\s]*,[\\s]*([0-9]+.?[0-9]*)[\\s]*\\)" +let edgePattern = "(.+?)[\\s]*-([->])[\\s]*(.+)" +let blockerPattern = "\\[Blocker\\][\\s]*(.+)" +let opportunityPattern = "\\[Opportunity\\][\\s]*(.+)[\\s]+([-+])[\\s]*([0-9]+.?[0-9]*)" +let stagePattern = "\\[(I{1,3})\\][\\s]*([0-9]+.?[0-9]*)" struct ParsedMap { - let vertices: [Vertex] - let edges: [MapEdge] + let vertices: [Vertex] + let edges: [MapEdge] + let blockers: [Blocker] + let opportunities: [Opportunity] + let stages: [CGFloat] } struct Vertex { - let id: Int - let label: String - let position: CGPoint + let id: Int + let label: String + let position: CGPoint } struct MapEdge { - let id: Int - let origin: CGPoint - let destination: CGPoint + let id: Int + let origin: CGPoint + let destination: CGPoint + let arrowhead: Bool } +struct Blocker { + let id: Int + let position: CGPoint +} + +struct Opportunity { + let id: Int + let origin: CGPoint + let destination: CGPoint +} + +let defaultDimensions: [CGFloat] = [ + 25.0, + 50.0, + 75.0, +] + // Extracts the vertices from the text func parseVertices(_ text: String) -> [String: CGPoint] { - - var result: [String: CGPoint] = [:] - let regex = try! NSRegularExpression(pattern: VERTEX_PATTERN, options: .caseInsensitive) - - let lines = text.split(whereSeparator: \.isNewline) - - for line in lines { - let range = NSRange(location: 0, length: line.utf16.count) - let matches = regex.matches(in: String(line), options: [], range: range) - - if matches.count > 0 && matches[0].numberOfRanges == 4{ - let match = matches[0]; - let key = String(line[Range(match.range(at: 1), in: line)!]) - let xString = String(line[Range(match.range(at: 2), in: line)!]) - let yString = String(line[Range(match.range(at: 3), in: line)!]) - let x = CGFloat(truncating: NumberFormatter().number(from:xString) ?? 0.0) - let y = CGFloat(truncating: NumberFormatter().number(from:yString) ?? 0.0) - let point = CGPoint(x: x, y: y) - - result[key] = point - } + var result: [String: CGPoint] = [:] + let regex = try! NSRegularExpression(pattern: vertexPattern, options: .caseInsensitive) + + let lines = text.split(whereSeparator: \.isNewline) + + for line in lines { + let range = NSRange(location: 0, length: line.utf16.count) + let matches = regex.matches(in: String(line), options: [], range: range) + + if matches.count > 0 && matches[0].numberOfRanges == 4 { + + let match = matches[0] + let key = String(line[Range(match.range(at: 1), in: line)!]) + let xString = String(line[Range(match.range(at: 2), in: line)!]) + let yString = String(line[Range(match.range(at: 3), in: line)!]) + let x = CGFloat(truncating: NumberFormatter().number(from: xString) ?? 0.0) + let y = CGFloat(truncating: NumberFormatter().number(from: yString) ?? 0.0) + let point = CGPoint(x: x, y: y) + + result[key] = point } - - return result -} + } -// Extracts the edges from the text + return result +} func parseEdges(_ text: String, vertices: [String: CGPoint]) -> [MapEdge] { - - var result: [MapEdge] = [] - let regex = try! NSRegularExpression(pattern: EDGE_PATTERN, options: .caseInsensitive) - - let lines = text.split(whereSeparator: \.isNewline) - - for (index, line) in lines.enumerated() { - let range = NSRange(location: 0, length: line.utf16.count) - let matches = regex.matches(in: String(line), options: [], range: range) - - if matches.count > 0 && matches[0].numberOfRanges == 3 { - let match = matches[0]; - let vertexA = String(line[Range(match.range(at: 1), in: line)!]) - let vertexB = String(line[Range(match.range(at: 2), in: line)!]) - - if let origin = vertices[vertexA] { - if let destination = vertices[vertexB] { - result.append(MapEdge(id: index, origin: origin, destination: destination)) - } - } + var result: [MapEdge] = [] + let regex = try! NSRegularExpression(pattern: edgePattern, options: .caseInsensitive) + + let lines = text.split(whereSeparator: \.isNewline) + + for (index, line) in lines.enumerated() { + let range = NSRange(location: 0, length: line.utf16.count) + let matches = regex.matches(in: String(line), options: [], range: range) + + if matches.count > 0 && matches[0].numberOfRanges == 4 { + + let match = matches[0] + let arrowhead = String(line[Range(match.range(at: 2), in: line)!]) == ">" + let vertexA = String(line[Range(match.range(at: 1), in: line)!]) + let vertexB = String(line[Range(match.range(at: 3), in: line)!]) + + if let origin = vertices[vertexA] { + if let destination = vertices[vertexB] { + result.append( + MapEdge(id: index, origin: origin, destination: destination, arrowhead: arrowhead)) } + } } - - return result + } + + return result +} + +func parseOpportunities(_ text: String, vertices: [String: CGPoint]) -> [Opportunity] { + + var result: [Opportunity] = [] + let regex = try! NSRegularExpression(pattern: opportunityPattern, options: .caseInsensitive) + + let lines = text.split(whereSeparator: \.isNewline) + + for (index, line) in lines.enumerated() { + let range = NSRange(location: 0, length: line.utf16.count) + let matches = regex.matches(in: String(line), options: [], range: range) + + if matches.count > 0 && matches[0].numberOfRanges == 4 { + + let match = matches[0] + let multiplier = CGFloat( + String(line[Range(match.range(at: 2), in: line)!]) == "-" ? -1.0 : 1.0) + let vertex = String(line[Range(match.range(at: 1), in: line)!]) + let opportunityString = String(line[Range(match.range(at: 3), in: line)!]) + let opportunity = CGFloat( + truncating: NumberFormatter().number(from: opportunityString) ?? 0.0) + + if let origin = vertices[vertex] { + let destination = CGPoint(x: origin.x + opportunity * multiplier, y: origin.y) + result.append(Opportunity(id: index, origin: origin, destination: destination)) + } + } + } + + return result +} + +func parseBlockers(_ text: String, vertices: [String: CGPoint]) -> [Blocker] { + + var result: [Blocker] = [] + let regex = try! NSRegularExpression(pattern: blockerPattern, options: .caseInsensitive) + + let lines = text.split(whereSeparator: \.isNewline) + + for (index, line) in lines.enumerated() { + let range = NSRange(location: 0, length: line.utf16.count) + let matches = regex.matches(in: String(line), options: [], range: range) + + if matches.count > 0 && matches[0].numberOfRanges == 2 { + + let match = matches[0] + let vertexA = String(line[Range(match.range(at: 1), in: line)!]) + + if let position = vertices[vertexA] { + result.append(Blocker(id: index, position: position)) + } + } + } + + return result +} + +func parseStages(_ text: String) -> [CGFloat] { + + var result = defaultDimensions + let regex = try! NSRegularExpression(pattern: stagePattern, options: .caseInsensitive) + + let lines = text.split(whereSeparator: \.isNewline) + + for line in lines { + let range = NSRange(location: 0, length: line.utf16.count) + let matches = regex.matches(in: String(line), options: [], range: range) + + if matches.count > 0 && matches[0].numberOfRanges == 3 { + + let match = matches[0] + let stage = String(line[Range(match.range(at: 1), in: line)!]) + let dimensionsString = String(line[Range(match.range(at: 2), in: line)!]) + let dimensions = CGFloat(truncating: NumberFormatter().number(from: dimensionsString) ?? 0.0) + + result[stage.count - 1] = dimensions + } + } + + return result } // Converts vetex dictionary to array func mapVertices(_ vertices: [String: CGPoint]) -> [Vertex] { - var i = 0 - return vertices.map { label, position in - i += 1; - return Vertex(id: i, label: label, position: position) - } + var i = 0 + return vertices.map { label, position in + i += 1 + return Vertex(id: i, label: label, position: position) + } } extension Map { - func parse() -> ParsedMap { - - let text = self.content ?? "" - let vertices = parseVertices(text) - let mappedVertices = mapVertices(vertices) - let edges = parseEdges(text, vertices: vertices) - print(mappedVertices) - print(edges) - - return ParsedMap(vertices: mappedVertices, edges: edges) - } + func parse() -> ParsedMap { + + let text = self.content ?? "" + let vertices = parseVertices(text) + let mappedVertices = mapVertices(vertices) + let edges = parseEdges(text, vertices: vertices) + let blockers = parseBlockers(text, vertices: vertices) + let opportunities = parseOpportunities(text, vertices: vertices) + let stages = parseStages(text) + + return ParsedMap( + vertices: mappedVertices, edges: edges, blockers: blockers, opportunities: opportunities, + stages: stages) + } } diff --git a/Map/Extensions/NSImage+writePNG.swift b/Map/Extensions/NSImage+writePNG.swift new file mode 100644 index 0000000..c24c0cf --- /dev/null +++ b/Map/Extensions/NSImage+writePNG.swift @@ -0,0 +1,25 @@ +import Cocoa + +extension NSImage { + public func writePNG(toURL url: URL) { + + guard let data = tiffRepresentation, + let rep = NSBitmapImageRep(data: data), + let imgData = rep.representation( + using: .png, properties: [.compressionFactor: NSNumber(floatLiteral: 1.0)]) + else { + + print( + "\(self.self) Error Function '\(#function)' Line: \(#line) No tiff rep found for image writing to \(url)" + ) + return + } + + do { + try imgData.write(to: url) + } catch let error { + print( + "\(self.self) Error Function '\(#function)' Line: \(#line) \(error.localizedDescription)") + } + } +} |