Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
maustinstar committed Aug 17, 2020
1 parent bd22ba4 commit 654a885
Show file tree
Hide file tree
Showing 11 changed files with 340 additions and 5 deletions.
11 changes: 7 additions & 4 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import PackageDescription

let package = Package(
name: "Liquid",
platforms: [
.iOS(.v13)
],
products: [
// Products define the executables and libraries produced by a package, and make them visible to other packages.
.library(
name: "Liquid",
targets: ["Liquid"]),
Expand All @@ -16,11 +18,12 @@ let package = Package(
// .package(url: /* package url */, from: "1.0.0"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
.target(
name: "Liquid",
name: "CLiquid",
dependencies: []),
.target(
name: "Liquid",
dependencies: ["CLiquid"]),
.testTarget(
name: "LiquidTests",
dependencies: ["Liquid"]),
Expand Down
40 changes: 40 additions & 0 deletions Sources/CLiquid/Bezier.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//
// Bezier.c
//
//
// Created by Michael Verges on 8/17/20.
//

#include "Bezier.h"

/**
* @brief a
*/
void bezier_ctrl(const int size, const double *src_x, const double *src_y,
double *ctrl1_x, double *ctrl1_y,
double *ctrl2_x, double *ctrl2_y) {
int prev = size - 1;
int next = 1;
for(int i = 0; i < size; i++) {
double dx = src_x[prev] - src_x[next];
double dy = src_y[prev] - src_y[next];
double m = sqrt(dx * dx + dy * dy);
dx /= m;
dy /= m;

double next_dx = src_x[i] - src_x[next];
double next_dy = src_y[i] - src_y[next];
double next_dist = sqrt(next_dx * next_dx + next_dy * next_dy);
ctrl1_x[next] = src_x[i] - dx * next_dist / 3.0;
ctrl1_y[next] = src_y[i] - dy * next_dist / 3.0;

double prev_dx = src_x[i] - src_x[prev];
double prev_dy = src_y[i] - src_y[prev];
double prev_dist = sqrt(prev_dx * prev_dx + prev_dy * prev_dy);
ctrl2_x[i] = src_x[i] + dx * prev_dist / 3.0;
ctrl2_y[i] = src_y[i] + dy * prev_dist / 3.0;

prev = (prev + 1) % size;
next = (next + 1) % size;
}
}
16 changes: 16 additions & 0 deletions Sources/CLiquid/include/Bezier.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// Bezier.h
//
//
// Created by Michael Verges on 8/17/20.
//

#ifndef Bezier_h
#define Bezier_h

#include <math.h>
void bezier_ctrl(const int size, const double *src_x, const double *src_y,
double *ctrl1_x, double *ctrl1_y,
double *ctrl2_x, double *ctrl2_y);

#endif /* Bezier_h */
48 changes: 48 additions & 0 deletions Sources/Liquid/AnimatableArray.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//
// AnimatableArray.swift
//
//
// Created by Michael Verges on 8/14/20.
//

import SwiftUI
import enum Accelerate.vDSP

struct AnimatableArray: VectorArithmetic {

var values: [Double]

init(_ values: [Double]) {
self.values = values
}

static var zero = AnimatableArray([0.0])

static func + (lhs: AnimatableArray, rhs: AnimatableArray) -> AnimatableArray {
let count = min(lhs.values.count, rhs.values.count)
return AnimatableArray(vDSP.add(lhs.values[0..<count], rhs.values[0..<count]))
}

static func += (lhs: inout AnimatableArray, rhs: AnimatableArray) {
let count = min(lhs.values.count, rhs.values.count)
vDSP.add(lhs.values[0..<count], rhs.values[0..<count], result: &lhs.values[0..<count])
}

static func - (lhs: AnimatableArray, rhs: AnimatableArray) -> AnimatableArray {
let count = min(lhs.values.count, rhs.values.count)
return AnimatableArray(vDSP.subtract(lhs.values[0..<count], rhs.values[0..<count]))
}

static func -= (lhs: inout AnimatableArray, rhs: AnimatableArray) {
let count = min(lhs.values.count, rhs.values.count)
vDSP.subtract(lhs.values[0..<count], rhs.values[0..<count], result: &lhs.values[0..<count])
}

mutating func scale(by rhs: Double) {
vDSP.multiply(rhs, values, result: &values)
}

var magnitudeSquared: Double {
vDSP.sum(vDSP.multiply(values, values))
}
}
49 changes: 49 additions & 0 deletions Sources/Liquid/ControlPoints.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//
// File.swift
//
//
// Created by Michael Verges on 8/17/20.
//

import CoreGraphics
import CLiquid

struct ControlPoints {

var x1: [Double]
var y1: [Double]
var x2: [Double]
var y2: [Double]

init(x: [Double], y: [Double]) {
assert(
x.count == y.count,
"Expected matching pairs for x and y, but found "
+ "\(x.count) x points and \(y.count) y points")
let count = x.count
var x1: [Double] = [Double](repeating: 0, count: count)
var y1: [Double] = [Double](repeating: 0, count: count)
var x2: [Double] = [Double](repeating: 0, count: count)
var y2: [Double] = [Double](repeating: 0, count: count)
bezier_ctrl(Int32(count), x, y, &x1, &y1, &x2, &y2)
self.x1 = x1
self.y1 = y1
self.x2 = x1
self.y2 = y1
}

init(_ points: [CGPoint]) {
let count = points.count
let x = points.map { Double($0.x) }
let y = points.map { Double($0.y) }
var x1: [Double] = [Double](repeating: 0, count: count)
var y1: [Double] = [Double](repeating: 0, count: count)
var x2: [Double] = [Double](repeating: 0, count: count)
var y2: [Double] = [Double](repeating: 0, count: count)
bezier_ctrl(Int32(count), x, y, &x1, &y1, &x2, &y2)
self.x1 = x1
self.y1 = y1
self.x2 = x1
self.y2 = y1
}
}
26 changes: 26 additions & 0 deletions Sources/Liquid/Extensions/Array.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// Array.swift
//
//
// Created by Michael Verges on 8/17/20.
//

import Foundation

extension Array {
func randomElements(_ n: Int) -> [Element] {
var copy = self
var selection: [Element] = []
let range = count / n
for _ in 0..<n {
let max: Int = Swift.min(range, copy.count)
let index = Int.random(in: 0...(max - 1))
selection.append(copy[index])
copy.removeFirst(range)
if copy.isEmpty {
return selection
}
}
return selection
}
}
18 changes: 18 additions & 0 deletions Sources/Liquid/Extensions/CGPath.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// CGPath.swift
//
//
// Created by Michael Verges on 8/17/20.
//

import CoreGraphics

extension CGPath {
func getPoints() -> [CGPoint] {
var points: [CGPoint] = []
self.applyWithBlock { (element) in
points.append(element.pointee.points.pointee)
}
return points
}
}
34 changes: 34 additions & 0 deletions Sources/Liquid/Extensions/Interpolate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// Interpolate.swift
//
//
// Created by Michael Verges on 8/17/20.
//

import Accelerate

extension Array where Element == Double {
func interpolate(_ n: Int) -> [Double] {

let stride = vDSP_Stride(1)

var base: Double = 0
var end = Double(n - 1)
var control = [Double](repeating: 0, count: count)
vDSP_vgenD(&base, &end, &control, stride, vDSP_Length(count))

var result = [Double](repeating: 0, count: n)
vDSP_vgenpD(self, stride, control, stride, &result, stride, vDSP_Length(n), vDSP_Length(self.count))

return result
}
}

extension Array where Element == CGPoint {

func interpolate(_ n: Int) -> (x: [Double], y: [Double]) {
let x = self.map { Double($0.x) }
let y = self.map { Double($0.y) }
return (x.interpolate(n), y.interpolate(n))
}
}
37 changes: 37 additions & 0 deletions Sources/Liquid/Extensions/Path.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//
// Path.swift
//
//
// Created by Michael Verges on 8/17/20.
//

import SwiftUI

extension Path {

@discardableResult
mutating func smooth(_ points: [CGPoint]) -> Path {
let controls = ControlPoints(points)
self.move(to: points.last!)
for i in 0..<points.count {
self.addCurve(
to: points[i],
control1: CGPoint(x: controls.x1[i], y: controls.y1[i]),
control2: CGPoint(x: controls.x2[i], y: controls.y2[i]))
}
return self
}

@discardableResult
mutating func smooth(x: [Double], y: [Double]) -> Path {
let controls = ControlPoints(x: x, y: y)
move(to: CGPoint(x: x.last!, y: y.last!))
for i in 0..<x.count {
addCurve(
to: CGPoint(x: x[i], y: y[i]),
control1: CGPoint(x: controls.x1[i], y: controls.y1[i]),
control2: CGPoint(x: controls.x2[i], y: controls.y2[i]))
}
return self
}
}
64 changes: 64 additions & 0 deletions Sources/Liquid/LiquidCircle.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//
// LiquidCircle.swift
//
//
// Created by Michael Verges on 8/17/20.
//

import SwiftUI

struct LiquidCircle: LiquidShape {

struct Model: LiquidModel {
var radians: AnimatableArray
}
static func generate(from model: Model) -> Model {
let radians = generateRadians(model.radians.values.count)
return Model(radians: AnimatableArray(radians))
}
init(_ model: Model) {
self.radians = model.radians
}

var radians: AnimatableArray

var animatableData: AnimatableArray {
get { radians }
set { radians = newValue }
}

func path(in rect: CGRect) -> Path {

Path { path in
let points = self.points(in: rect)
path.smooth(x: points.x, y: points.y)
}
}

static func generateRadians(_ count: Int) -> [Double] {
var results: [Double] = []
for i in 0..<count {
let min = Double(i) / Double(count) * 2 * .pi
let max = Double(i + 1) / Double(count) * 2 * .pi
results.append(Double.random(in: min...max))
}

let offset = Double.random(in: 0...(.pi))
return results.map { $0 + offset }
}

func points(in rect: CGRect) -> (x: [Double], y: [Double]) {
var x: [Double] = []
var y: [Double] = []
x.reserveCapacity(radians.values.count)
y.reserveCapacity(radians.values.count)
let width = Double(rect.width)
let height = Double(rect.height)
let offset = (x: Double(rect.midX), y: Double(rect.midY))
for i in 0..<radians.values.count {
x.append(offset.x + cos(radians.values[i]) * width / 2)
y.append(offset.y + sin(radians.values[i]) * height / 2)
}
return (x, y)
}
}
2 changes: 1 addition & 1 deletion Tests/LiquidTests/LiquidTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ final class LiquidTests: XCTestCase {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct
// results.
XCTAssertEqual(Liquid().text, "Hello, World!")
// XCTAssertEqual(Liquid().text, "Hello, World!")
}

static var allTests = [
Expand Down

0 comments on commit 654a885

Please sign in to comment.