Organic Maps sources as of 02.04.2025 (fad26bbf22ac3da75e01e62aa01e5c8e11861005)

To expand with full Organic Maps and Maps.ME commits history run:
  git remote add om-historic [om-historic.git repo url]
  git fetch --tags om-historic
  git replace squashed-history historic-commits
This commit is contained in:
Konstantin Pastbin
2025-04-13 16:37:30 +07:00
commit e3e4a1985a
12931 changed files with 13195100 additions and 0 deletions

View File

@@ -0,0 +1,50 @@
import UIKit
public enum ChartType {
case regular
case percentage
}
public enum ChartLineType: String {
case line
case lineArea
}
public protocol ChartFormatter {
func xAxisString(from value: Double) -> String
func yAxisString(from value: Double) -> String
func yAxisLowerBound(from value: CGFloat) -> CGFloat
func yAxisUpperBound(from value: CGFloat) -> CGFloat
func yAxisSteps(lowerBound: CGFloat, upperBound: CGFloat) -> [CGFloat]
}
public protocol ChartData {
var xAxisValues: [Double] { get }
var lines: [ChartLine] { get }
var type: ChartType { get }
}
public protocol ChartLine {
var values: [ChartValue] { get }
var color: UIColor { get }
var type: ChartLineType { get }
}
public struct ChartValue {
let x: CGFloat
let y: CGFloat
public init(xValues: CGFloat, y: CGFloat) {
self.x = xValues
self.y = y
}
}
extension Array where Element == ChartValue {
var maxDistance: CGFloat { return map { $0.x }.max() ?? 0 }
func altitude(at relativeDistance: CGFloat) -> CGFloat {
guard let distance = last?.x else { return 0 }
return first { $0.x >= distance * relativeDistance }?.y ?? 0
}
}

View File

@@ -0,0 +1,131 @@
import UIKit
protocol ChartPathBuilder {
func build(_ lines: [ChartPresentationLine])
func makeLinePath(line: ChartPresentationLine) -> UIBezierPath
func makePercentLinePath(line: ChartPresentationLine, bottomLine: ChartPresentationLine?) -> UIBezierPath
}
extension ChartPathBuilder {
func makeLinePreviewPath(line: ChartPresentationLine) -> UIBezierPath {
let path = UIBezierPath()
let values = line.values
let xScale = CGFloat(values.count) / values.maxDistance
for i in 0..<values.count {
let x = values[i].x * xScale
let y = values[i].y - line.minY
if i == 0 {
path.move(to: CGPoint(x: x, y: y))
} else {
path.addLine(to: CGPoint(x: x, y: y))
}
}
return path
}
func makeLinePath(line: ChartPresentationLine) -> UIBezierPath {
let path = UIBezierPath()
let values = line.values
let xScale = CGFloat(values.count) / values.maxDistance
for i in 0..<values.count {
let x = values[i].x * xScale
let y = values[i].y - line.minY
if i == 0 {
path.move(to: CGPoint(x: x, y: y))
} else {
path.addLine(to: CGPoint(x: x, y: y))
}
}
return path
}
func makePercentLinePreviewPath(line: ChartPresentationLine, bottomLine: ChartPresentationLine?) -> UIBezierPath {
let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: 0))
let aggregatedValues = line.aggregatedValues
let xScale = CGFloat(aggregatedValues.count) / aggregatedValues.maxDistance
for i in 0..<aggregatedValues.count {
let x = aggregatedValues[i].x * xScale
let y = aggregatedValues[i].y - CGFloat(line.minY)
path.addLine(to: CGPoint(x: x, y: y))
}
path.addLine(to: CGPoint(x: aggregatedValues.maxDistance, y: 0))
path.close()
return path
}
func makePercentLinePath(line: ChartPresentationLine, bottomLine: ChartPresentationLine?) -> UIBezierPath {
let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: 0))
let aggregatedValues = line.aggregatedValues
let xScale = CGFloat(aggregatedValues.count) / aggregatedValues.maxDistance
for i in 0..<aggregatedValues.count {
let x = aggregatedValues[i].x * xScale
let y = aggregatedValues[i].y - CGFloat(line.minY)
path.addLine(to: CGPoint(x: x, y: y))
}
path.addLine(to: CGPoint(x: aggregatedValues.maxDistance, y: 0))
path.close()
return path
}
}
final class DefaultChartPathBuilder {
private let builders: [ChartType: ChartPathBuilder] = [
.regular : LinePathBuilder(),
.percentage : PercentagePathBuilder()
]
func build(_ lines: [ChartPresentationLine], type: ChartType) {
builders[type]?.build(lines)
}
}
final class LinePathBuilder: ChartPathBuilder {
func build(_ lines: [ChartPresentationLine]) {
lines.forEach {
$0.aggregatedValues = $0.values
if $0.type == .lineArea {
$0.minY = 0
for val in $0.values {
$0.maxY = max(val.y, $0.maxY)
}
$0.path = makePercentLinePath(line: $0, bottomLine: nil)
$0.previewPath = makePercentLinePreviewPath(line: $0, bottomLine: nil)
} else {
for val in $0.values {
$0.minY = min(val.y, $0.minY)
$0.maxY = max(val.y, $0.maxY)
}
$0.path = makeLinePath(line: $0)
$0.previewPath = makeLinePreviewPath(line: $0)
}
}
}
}
final class PercentagePathBuilder: ChartPathBuilder {
func build(_ lines: [ChartPresentationLine]) {
lines.forEach {
$0.minY = 0
$0.maxY = CGFloat(Int.min)
}
for i in 0..<lines[0].values.count {
let sum = CGFloat(lines.reduce(0) { (r, l) in r + l.values[i].y })
var aggrPercentage: CGFloat = 0
lines.forEach {
aggrPercentage += CGFloat($0.values[i].y) / sum * 100
$0.aggregatedValues.append(ChartValue(xValues: lines[0].values[i].x, y: aggrPercentage))
$0.maxY = max(round(aggrPercentage), CGFloat($0.maxY))
}
}
var prevLine: ChartPresentationLine? = nil
lines.forEach {
$0.path = makePercentLinePath(line: $0, bottomLine: prevLine)
$0.previewPath = makePercentLinePreviewPath(line: $0, bottomLine: prevLine)
prevLine = $0
}
}
}

View File

@@ -0,0 +1,56 @@
import UIKit
public class ChartPresentationData {
private let chartData: ChartData
private var presentationLines: [ChartPresentationLine]
private let pathBuilder = DefaultChartPathBuilder()
let formatter: ChartFormatter
var linesCount: Int { chartData.lines.count }
var pointsCount: Int { chartData.xAxisValues.count }
var xAxisValues: [Double] { chartData.xAxisValues }
var type: ChartType { chartData.type }
var labels: [String]
var lower = CGFloat(Int.max)
var upper = CGFloat(Int.min)
public init(_ chartData: ChartData, formatter: ChartFormatter) {
self.chartData = chartData
self.formatter = formatter
self.presentationLines = chartData.lines.map { ChartPresentationLine($0) }
self.labels = chartData.xAxisValues.map { formatter.xAxisString(from: $0) }
recalculateBounds()
}
func labelAt(_ point: CGFloat) -> String {
formatter.xAxisString(from: xAxisValueAt(point))
}
func xAxisValueAt(_ point: CGFloat) -> Double {
let distance = chartData.xAxisValues.last!
let p1 = floor(point)
let p2 = ceil(point)
let v1 = p1 / CGFloat(pointsCount) * distance
let v2 = p2 / CGFloat(pointsCount) * distance
return v1 + (v2 - v1) * Double(point.truncatingRemainder(dividingBy: 1))
}
func lineAt(_ index: Int) -> ChartPresentationLine {
presentationLines[index]
}
private func recalculateBounds() {
presentationLines.forEach { $0.aggregatedValues = [] }
pathBuilder.build(presentationLines, type: type)
var l = CGFloat(Int.max)
var u = CGFloat(Int.min)
presentationLines.forEach {
l = min($0.minY, l)
u = max($0.maxY, u)
}
lower = l
upper = u
}
}

View File

@@ -0,0 +1,19 @@
import UIKit
final class ChartPresentationLine {
private let chartLine: ChartLine
var aggregatedValues: [ChartValue] = []
var minY: CGFloat = CGFloat(Int.max)
var maxY: CGFloat = CGFloat(Int.min)
var path = UIBezierPath()
var previewPath = UIBezierPath()
var values: [ChartValue] { chartLine.values }
var color: UIColor { chartLine.color }
var type: ChartLineType { chartLine.type }
init(_ chartLine: ChartLine) {
self.chartLine = chartLine
}
}