unioil-loyalty-rn-app/ios/Pods/lottie-ios/Sources/Private/Utility/Primitives/CompoundBezierPath.swift

168 lines
4.2 KiB
Swift

//
// CompoundBezierPath.swift
// lottie-swift
//
// Created by Brandon Withrow on 1/14/19.
//
import CoreGraphics
import Foundation
/// A collection of BezierPath objects that can be trimmed and added.
///
struct CompoundBezierPath {
// MARK: Lifecycle
init() {
paths = []
length = 0
}
init(path: BezierPath) {
paths = [path]
length = path.length
}
init(paths: [BezierPath], length: CGFloat) {
self.paths = paths
self.length = length
}
init(paths: [BezierPath]) {
self.paths = paths
var l: CGFloat = 0
for path in paths {
l = l + path.length
}
length = l
}
// MARK: Internal
let paths: [BezierPath]
let length: CGFloat
func addPath(path: BezierPath) -> CompoundBezierPath {
var newPaths = paths
newPaths.append(path)
return CompoundBezierPath(paths: newPaths, length: length + path.length)
}
func combine(_ compoundBezier: CompoundBezierPath) -> CompoundBezierPath {
var newPaths = paths
newPaths.append(contentsOf: compoundBezier.paths)
return CompoundBezierPath(paths: newPaths, length: length + compoundBezier.length)
}
func trim(fromPosition: CGFloat, toPosition: CGFloat, offset: CGFloat, trimSimultaneously: Bool) -> CompoundBezierPath {
if fromPosition == toPosition {
return CompoundBezierPath()
}
if trimSimultaneously {
/// Trim each path individually.
var newPaths = [BezierPath]()
for path in paths {
newPaths.append(contentsOf: path.trim(
fromLength: fromPosition * path.length,
toLength: toPosition * path.length,
offsetLength: offset * path.length))
}
return CompoundBezierPath(paths: newPaths)
}
/// Normalize lengths to the curve length.
var startPosition = (fromPosition + offset).truncatingRemainder(dividingBy: 1)
var endPosition = (toPosition + offset).truncatingRemainder(dividingBy: 1)
if startPosition < 0 {
startPosition = 1 + startPosition
}
if endPosition < 0 {
endPosition = 1 + endPosition
}
if startPosition == 1 {
startPosition = 0
}
if endPosition == 0 {
endPosition = 1
}
if
startPosition == 0 && endPosition == 1 ||
startPosition == endPosition ||
startPosition == 1 && endPosition == 0
{
/// The trim encompasses the entire path. Return.
return self
}
var positions: [(start: CGFloat, end: CGFloat)]
if endPosition < startPosition {
positions = [
(start: 0, end: endPosition * length),
(start: startPosition * length, end: length),
]
} else {
positions = [(start: startPosition * length, end: endPosition * length)]
}
var compoundPath = CompoundBezierPath()
var trim = positions.remove(at: 0)
var pathStartPosition: CGFloat = 0
var finishedTrimming = false
var i = 0
while !finishedTrimming {
if paths.count <= i {
/// Rounding errors
finishedTrimming = true
continue
}
let path = paths[i]
let pathEndPosition = pathStartPosition + path.length
if pathEndPosition < trim.start {
/// Path is not included in the trim, continue.
pathStartPosition = pathEndPosition
i = i + 1
continue
} else if trim.start <= pathStartPosition, pathEndPosition <= trim.end {
/// Full Path is inside of trim. Add full path.
compoundPath = compoundPath.addPath(path: path)
} else {
if
let trimPath = path.trim(
fromLength: trim.start > pathStartPosition ? (trim.start - pathStartPosition) : 0,
toLength: trim.end < pathEndPosition ? (trim.end - pathStartPosition) : path.length,
offsetLength: 0).first
{
compoundPath = compoundPath.addPath(path: trimPath)
}
}
if trim.end <= pathEndPosition {
/// We are done with the current trim.
/// Advance trim but remain on the same path in case the next trim overlaps it.
if positions.count > 0 {
trim = positions.remove(at: 0)
} else {
finishedTrimming = true
}
} else {
pathStartPosition = pathEndPosition
i = i + 1
}
}
return compoundPath
}
}