Skip to content

Commit

Permalink
Merge pull request #11 from li3zhen1/gh-pages
Browse files Browse the repository at this point in the history
Add Swift DocC
  • Loading branch information
li3zhen1 authored Oct 18, 2023
2 parents a51ee16 + 70381dc commit 2173f9f
Show file tree
Hide file tree
Showing 304 changed files with 965 additions and 22 deletions.
23 changes: 23 additions & 0 deletions Package.resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"pins" : [
{
"identity" : "swift-docc-plugin",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-docc-plugin",
"state" : {
"revision" : "26ac5758409154cc448d7ab82389c520fa8a8247",
"version" : "1.3.0"
}
},
{
"identity" : "swift-docc-symbolkit",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-docc-symbolkit",
"state" : {
"revision" : "b45d1f2ed151d057b54504d653e0da5552844e34",
"version" : "1.0.0"
}
}
],
"version" : 2
}
7 changes: 7 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ let package = Package(
.iOS(.v13),
.watchOS(.v10),
],

products: [
// Products define the executables and libraries a package produces, making them visible to other packages.

Expand All @@ -24,6 +25,12 @@ let package = Package(
),

],

dependencies: [
// other dependencies
.package(url: "https://github.com/apple/swift-docc-plugin", from: "1.1.0"),
],

targets: [

.target(
Expand Down
5 changes: 5 additions & 0 deletions Sources/ForceSimulation/ForceLike.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,13 @@

import NDTree

/// A protocol that represents a force.
/// A force takes a simulation state and modifies its node positions and velocities.
public protocol ForceLike {
associatedtype NodeID: Hashable

/// Takes a simulation state and modifies its node positions and velocities.
/// This is executed in each tick of the simulation.
func apply(alpha: Double)
}

Expand Down
25 changes: 14 additions & 11 deletions Sources/ForceSimulation/Simulation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,13 @@ enum SimulationError: Error {
case subscriptionToNonexistentNode
}

/// An N-Dimensional force simulation.
public final class Simulation<NodeID, V> where NodeID: Hashable, V: VectorLike, V.Scalar == Double {

/// The type of the vector used in the simulation.
/// Usually this is `Double` if you are on Apple platforms.
public typealias Scalar = V.Scalar

// public struct NodeStatus {
// public var position: V
// public var velocity: V
// public var fixation: V?
//
// static var zero: NodeStatus { .init(position: .zero, velocity: .zero) }
// }

public let initializedAlpha: Double

Expand All @@ -33,10 +29,6 @@ public final class Simulation<NodeID, V> where NodeID: Hashable, V: VectorLike,

public internal(set) var forces: [any ForceLike] = []

/// This is only used for initialization.
/// Position, velocities, fixations are moved to the arrays below
/// to utilize cache hit
// private var nodes: [NodeStatus]

public internal(set) var nodePositions: [V]
public internal(set) var nodeVelocities: [V]
Expand All @@ -46,6 +38,15 @@ public final class Simulation<NodeID, V> where NodeID: Hashable, V: VectorLike,

@usableFromInline internal private(set) var nodeIdToIndexLookup: [NodeID: Int] = [:]

/// Create a new simulation.
/// - Parameters:
/// - nodeIds: Hashable identifiers for the nodes. Force simulation calculate them by order once created.
/// - alpha:
/// - alphaMin:
/// - alphaDecay: The larger the value, the faster the simulation converges to the final result.
/// - alphaTarget:
/// - velocityDecay:
/// - getInitialPosition: The closure to set the initial position of the node. If not provided, the initial position is set to zero.
public init(
nodeIds: [NodeID],
alpha: Double = 1,
Expand Down Expand Up @@ -91,6 +92,8 @@ public final class Simulation<NodeID, V> where NodeID: Hashable, V: VectorLike,
return nodeIdToIndexLookup[nodeId]!
}

/// Run the simulation for a number of iterations.
/// - Parameter iterationCount: Default to 1.
public func tick(iterationCount: UInt = 1) {
for _ in 0..<iterationCount {
alpha += (alphaTarget - alpha) * alphaDecay
Expand Down
4 changes: 4 additions & 0 deletions Sources/ForceSimulation/Utils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
//
import NDTree


// TODO: https://forums.swift.org/t/deterministic-randomness-in-swift/20835/5

/// A random number generator that generates deterministic random numbers.
public struct LinearCongruentialGenerator {
@usableFromInline internal static let a: Double = 1_664_525
@usableFromInline internal static let c: Double = 1_013_904_223
Expand Down Expand Up @@ -51,6 +54,7 @@ extension Vector2d {
}
}

/// A Hashable identifier for an edge.
public struct EdgeID<NodeID>: Hashable where NodeID: Hashable {
public let source: NodeID
public let target: NodeID
Expand Down
2 changes: 2 additions & 0 deletions Sources/ForceSimulation/forces/CenterForce.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//
import NDTree

/// A force that represents links between nodes.
final public class CenterForce<NodeID, V>: ForceLike
where NodeID: Hashable, V: VectorLike, V.Scalar == Double {
public var center: V
Expand Down Expand Up @@ -35,6 +36,7 @@ where NodeID: Hashable, V: VectorLike, V.Scalar == Double {

extension Simulation {

/// Create a center force, See: https://d3js.org/d3-force/center
@discardableResult
public func createCenterForce(center: V, strength: Double = 0.1) -> CenterForce<NodeID, V> {
let f = CenterForce<NodeID, V>(center: center, strength: strength)
Expand Down
3 changes: 3 additions & 0 deletions Sources/ForceSimulation/forces/CollideForce.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ struct MaxRadiusTreeDelegate<NodeID, V>: NDTreeDelegate where NodeID: Hashable,

}


/// A force that prevents nodes from overlapping.
public final class CollideForce<NodeID, V>: ForceLike
where NodeID: Hashable, V: VectorLike, V.Scalar == Double {

Expand Down Expand Up @@ -178,6 +180,7 @@ extension CollideForce.CollideRadius: PrecalculatableNodeProperty {

extension Simulation {

/// Create a collide force, See: https://d3js.org/d3-force/collide
@discardableResult
public func createCollideForce(
radius: CollideForce<NodeID, V>.CollideRadius = .constant(3.0),
Expand Down
2 changes: 2 additions & 0 deletions Sources/ForceSimulation/forces/DirectionForce.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import NDTree

/// A force that moves nodes to a target position.
final public class DirectionForce<NodeID, V>: ForceLike
where NodeID: Hashable, V: VectorLike, V.Scalar == Double {

Expand Down Expand Up @@ -93,6 +94,7 @@ extension DirectionForce.Direction {

public extension Simulation {

/// Create a direction force, Similar to https://d3js.org/d3-force/position
@discardableResult
func createPositionForce(
direction: DirectionForce<NodeID, V>.Direction,
Expand Down
9 changes: 9 additions & 0 deletions Sources/ForceSimulation/forces/LinkForce.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ enum LinkForceError: Error {
case useBeforeSimulationInitialized
}

/// A force that represents links between nodes.
final public class LinkForce<NodeID, V>: ForceLike
where NodeID: Hashable, V: VectorLike, V.Scalar == Double {

Expand Down Expand Up @@ -157,6 +158,7 @@ protocol PrecalculatableEdgeProperty {
}



extension LinkForce.LinkLength: PrecalculatableEdgeProperty {
func calculated(
for links: [EdgeID<NodeID>], connectionLookupTable: LinkForce<NodeID, V>.LinkLookup<NodeID>
Expand All @@ -172,6 +174,8 @@ extension LinkForce.LinkLength: PrecalculatableEdgeProperty {
}
}



extension LinkForce.LinkStiffness: PrecalculatableEdgeProperty {
func calculated(
for links: [EdgeID<NodeID>],
Expand All @@ -197,7 +201,12 @@ extension LinkForce.LinkStiffness: PrecalculatableEdgeProperty {
}
}



extension Simulation {


/// Create a link force, Similar to https://d3js.org/d3-force/link
@discardableResult
public func createLinkForce(
_ links: [EdgeID<NodeID>],
Expand Down
4 changes: 3 additions & 1 deletion Sources/ForceSimulation/forces/ManyBodyForce.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ enum ManyBodyForceError: Error {
case buildQuadTreeBeforeSimulationInitialized
}


struct MassQuadtreeDelegate<NodeID, V>: NDTreeDelegate where NodeID: Hashable, V: VectorLike {

public var accumulatedMass: Double = .zero
Expand Down Expand Up @@ -74,6 +75,7 @@ struct MassQuadtreeDelegate<NodeID, V>: NDTreeDelegate where NodeID: Hashable, V
}
}

/// A force that simulate the many-body force. See: https://d3js.org/d3-force/many-body
final public class ManyBodyForce<NodeID, V>: ForceLike
where NodeID: Hashable, V: VectorLike, V.Scalar == Double {

Expand Down Expand Up @@ -305,7 +307,7 @@ extension ManyBodyForce.NodeMass: PrecalculatableNodeProperty {
}

extension Simulation {

/// Create a many-body force. See: https://d3js.org/d3-force/many-body
@discardableResult
public func createManyBodyForce(
strength: Double,
Expand Down
3 changes: 3 additions & 0 deletions Sources/ForceSimulation/forces/RadialForce.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

import NDTree

/// A force that applies a radial force to all nodes.
/// Similar to https://d3js.org/d3-force/position
final public class RadialForce<NodeID, V>: ForceLike
where NodeID: Hashable, V: VectorLike, V.Scalar == Double {
weak var simulation: Simulation<NodeID, V>? {
Expand Down Expand Up @@ -83,6 +85,7 @@ extension RadialForce.NodeRadius: PrecalculatableNodeProperty {

extension Simulation {

/// Create a radial force, Similar to https://d3js.org/d3-force/position
@discardableResult
public func createRadialForce(
center: V = .zero,
Expand Down
47 changes: 44 additions & 3 deletions Sources/NDTree/NDBox.swift
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
//
// File.swift
// NDBox.swift
//
//
// Created by li3zhen1 on 10/14/23.
//


/// A box in N-dimensional space.
/// - Note: `p0` is the minimum point of the box, `p1` is the maximum point of the box.
public struct NDBox<V> where V: VectorLike {
/// the minimum anchor of the box
public var p0: V

/// the maximum anchor of the box
public var p1: V

/// Create a box with 2 anchors.
/// - Parameters:
/// - p0: anchor
/// - p1: another anchor in the diagonal position of `p0`
/// - Note: `p0` you pass does not have to be minimum point of the box.
/// `p1` does not have to be maximum point of the box. The initializer will
/// automatically adjust the order of `p0` and `p1` to make sure `p0` is the
/// minimum point of the box and `p1` is the maximum point of the box.
@inlinable public init(p0: V, p1: V) {
#if DEBUG
assert(p0 != p1, "NdBox was initialized with 2 same anchor")
Expand All @@ -26,6 +38,12 @@ public struct NDBox<V> where V: VectorLike {
// TODO: use Mask
}

/// Create a box with 2 anchors.
/// - Parameters:
/// - pMin: minimum anchor of the box
/// - pMax: maximum anchor of the box
/// - Note: Please make sure `pMin` is the minimum point of the box and `pMax` is the
/// maximum point of the box.
@inlinable internal init(pMin: V, pMax: V) {
#if DEBUG
assert(pMin != pMax, "NdBox was initialized with 2 same anchor")
Expand All @@ -34,11 +52,20 @@ public struct NDBox<V> where V: VectorLike {
self.p1 = pMax
}

/// Create a box with 2 zero anchors.
@inlinable public init() {
p0 = .zero
p1 = .zero
}

/// Create a box with 2 anchors.
/// - Parameters:
/// - p0: anchor
/// - p1: another anchor in the diagonal position of `p0`
/// - Note: `p0` you pass does not have to be minimum point of the box.
/// `p1` does not have to be maximum point of the box. The initializer will
/// automatically adjust the order of `p0` and `p1` to make sure `p0` is the
/// minimum point of the box and `p1` is the maximum point of the box.
public init(_ p0: V, _ p1: V) {
self.init(p0: p0, p1: p1)
}
Expand All @@ -52,6 +79,10 @@ extension NDBox {

@inlinable var center: V { (p1 + p0) / V.Scalar(2) }

/// Test if the box contains a point.
/// - Parameter point: N dimensional point
/// - Returns: `true` if the box contains the point, `false` otherwise.
/// The boundary test is similar to ..< operator.
@inlinable func contains(_ point: V) -> Bool {
for i in point.indices {
if p0[i] > point[i] || point[i] >= p1[i] {
Expand Down Expand Up @@ -80,6 +111,10 @@ extension NDBox {


public extension NDBox {

/// Get the small box that contains a list points and guarantees the box's size is at least 1x..x1.
/// - Parameter points: The points to be covered.
/// - Returns: The box that contains all the points.
@inlinable static func cover(of points: [V]) -> Self {

var _p0 = points[0]
Expand All @@ -106,7 +141,13 @@ public extension NDBox {
return Self(_p0, _p1)
}


/// Get the small box that contains a list points and guarantees the box's size is at least 1x..x1.
/// Please note that KeyPath is slow.
///
/// - Parameter
/// - points: The points to be covered.
/// - keyPath: The key path to get the vector from the point.
/// - Returns: The box that contains all the points.
@inlinable static func cover<T>(of points: [T], keyPath: KeyPath<T,V>) -> Self {

var _p0 = points[0][keyPath: keyPath]
Expand Down
5 changes: 4 additions & 1 deletion Sources/NDTree/NDTree+Traversable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ public protocol Traversable {

extension NDTree: Traversable {

/// Visit the tree in pre-order.
/// - Parameter shouldVisitChildren: a closure that returns a boolean value indicating whether should continue to visit children.
@inlinable public func visit(shouldVisitChildren: (NDTree<V,D>) -> Bool) {
if shouldVisitChildren(self), let children {
// this is an internal node
Expand All @@ -29,7 +31,8 @@ extension NDTree: Traversable {
}
}


/// Visit the tree in post-order.
/// - Parameter action: a closure that takes a tree as its argument.
@inlinable public func visitPostOrdered(
_ action: (NDTree<V, D>) -> ()
) {
Expand Down
Loading

0 comments on commit 2173f9f

Please sign in to comment.