Skip to content

Instantly share code, notes, and snippets.

@izakpavel
Created May 18, 2020 07:06
Show Gist options
  • Save izakpavel/e202cfa90189cf1aa2f9e0787783f9f6 to your computer and use it in GitHub Desktop.
Save izakpavel/e202cfa90189cf1aa2f9e0787783f9f6 to your computer and use it in GitHub Desktop.
//
// 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