Created
May 18, 2020 07:06
-
-
Save izakpavel/e202cfa90189cf1aa2f9e0787783f9f6 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// AnimatableVector2D.swift | |
// | |
// this is derivation of generic AnimatableVector presented at: https://nerdyak.tech/development/2020/01/12/animating-complex-shapes-in-swiftui.html | |
// | |
// Created by Pavel Zak on 18/05/2020. | |
// | |
import SwiftUI | |
struct AnimatableVector2D: VectorArithmetic { | |
var values: [CGPoint] | |
init(count: Int = 1) { | |
self.values = [CGPoint](repeating: CGPoint(), count: count) | |
self.magnitudeSquared = 0.0 | |
} | |
init(with values: [CGPoint]) { | |
self.values = values | |
self.magnitudeSquared = 0 | |
self.recomputeMagnitude() | |
} | |
func computeMagnitude()->Double { | |
// compute square magnitued of the vector | |
// = sum of all squared values | |
var sum: Double = 0.0 | |
for index in 0..<self.values.count { | |
sum += Double(self.values[index].x*self.values[index].x) | |
sum += Double(self.values[index].y*self.values[index].y) | |
} | |
return Double(sum) | |
} | |
mutating func recomputeMagnitude(){ | |
self.magnitudeSquared = self.computeMagnitude() | |
} | |
// MARK: VectorArithmetic | |
var magnitudeSquared: Double // squared magnitude of the vector | |
mutating func scale(by rhs: Double) { | |
// scale vector with a scalar | |
// = each value is multiplied by rhs | |
for index in 0..<values.count { | |
values[index].x *= CGFloat(rhs) | |
values[index].y *= CGFloat(rhs) | |
} | |
self.magnitudeSquared = self.computeMagnitude() | |
} | |
// MARK: AdditiveArithmetic | |
// zero is identity element for aditions | |
// = all values are zero | |
static var zero: AnimatableVector2D = AnimatableVector2D() | |
static func + (lhs: AnimatableVector2D, rhs: AnimatableVector2D) -> AnimatableVector2D { | |
var retValues = [CGPoint]() | |
for index in 0..<min(lhs.values.count, rhs.values.count) { | |
retValues.append(CGPoint(x: lhs.values[index].x + rhs.values[index].x, y: lhs.values[index].y + rhs.values[index].y)) | |
} | |
return AnimatableVector2D(with: retValues) | |
} | |
static func += (lhs: inout AnimatableVector2D, rhs: AnimatableVector2D) { | |
for index in 0..<min(lhs.values.count,rhs.values.count) { | |
lhs.values[index].x += rhs.values[index].x | |
lhs.values[index].y += rhs.values[index].y | |
} | |
lhs.recomputeMagnitude() | |
} | |
static func - (lhs: AnimatableVector2D, rhs: AnimatableVector2D) -> AnimatableVector2D { | |
var retValues = [CGPoint]() | |
for index in 0..<min(lhs.values.count, rhs.values.count) { | |
retValues.append(CGPoint(x: lhs.values[index].x - rhs.values[index].x, y: lhs.values[index].y - rhs.values[index].y)) | |
} | |
return AnimatableVector2D(with: retValues) | |
} | |
static func -= (lhs: inout AnimatableVector2D, rhs: AnimatableVector2D) { | |
for index in 0..<min(lhs.values.count,rhs.values.count) { | |
lhs.values[index].x -= rhs.values[index].x | |
lhs.values[index].y -= rhs.values[index].y | |
} | |
lhs.recomputeMagnitude() | |
} | |
} | |
// example of usage | |
struct ExampleShape: Shape { | |
var controlPoints: AnimatableVector2D | |
var animatableData: AnimatableVector2D { | |
set { self.controlPoints = newValue } | |
get { return self.controlPoints } | |
} | |
func path(in rect: CGRect) -> Path { | |
return Path { path in | |
path.move(to: self.controlPoints.values[0]) | |
var i = 1; | |
while i < self.controlPoints.values.count { | |
path.addLine(to: self.controlPoints.values[i]) | |
i += 1; | |
} | |
path.addLine(to: self.controlPoints.values[0]) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment