Skip to content

Commit

Permalink
Merge pull request #2 from li3zhen1/dev
Browse files Browse the repository at this point in the history
bugfix: quad delegate
  • Loading branch information
li3zhen1 authored Oct 9, 2023
2 parents 8d7fbc6 + ae7b07f commit d9a7d56
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 25 deletions.
2 changes: 2 additions & 0 deletions Sources/ForceSimulation/forces/CollideForce.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ enum CollideForceError: Error {
}




public class CollideForce<N> where N : Identifiable {

let radius: CollideRadius
Expand Down
4 changes: 2 additions & 2 deletions Sources/ForceSimulation/forces/ManyBodyForce.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ final class MassQuadTreeDelegate<N>: QuadDelegate where N : Identifiable {
}


func createForExpanded(towards _: Quadrant, from _: Quad, to _: Quad) -> Self {
func copy() -> Self {
return Self(
initialAccumulatedProperty: self.accumulatedProperty,
initialAccumulatedCount: self.accumulatedCount,
Expand All @@ -66,7 +66,7 @@ final class MassQuadTreeDelegate<N>: QuadDelegate where N : Identifiable {
)
}

func stem() -> Self {
func createNew() -> Self {
return Self(massProvider: self.massProvider)
}

Expand Down
25 changes: 12 additions & 13 deletions Sources/QuadTree/QuadTree2.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,15 @@ public class QuadTreeNode2<N, QD> where N: Identifiable, QD: QuadDelegate, QD.No
) {
self.quad = quad
self.clusterDistance = clusterDistance
self.quadDelegate = rootQuadDelegate.stem()
self.quadDelegate = rootQuadDelegate.createNew()
}

public func add(_ node: N, at point: Vector2f) {
cover(point)

// accumulatedCount += 1

quadDelegate.didAddNode(node, at: point)

// accumulatedProperty += QD.getPropertyFor(node)
// weightedAccumulatedNodePositions += node.quadDelegate * point
defer {
quadDelegate.didAddNode(node, at: point)
}

guard let children = self.children else {
if nodes.isEmpty {
Expand All @@ -79,6 +76,8 @@ public class QuadTreeNode2<N, QD> where N: Identifiable, QD: QuadDelegate, QD.No
if !nodes.isEmpty {
let direction = quad.quadrantOf(nodes.first!.value)
divided[at: direction].nodes = self.nodes
divided[at: direction].quadDelegate = self.quadDelegate
self.quadDelegate = self.quadDelegate.copy()
}
self.nodes = [:]

Expand Down Expand Up @@ -167,15 +166,15 @@ public class QuadTreeNode2<N, QD> where N: Identifiable, QD: QuadDelegate, QD.No
self.quad = newRootQuad
self.children = divided
self.nodes = [:]
self.quadDelegate = quadDelegate.createForExpanded(towards: quadrant, from: copiedCurrentNode.quad, to: newRootQuad)
self.quadDelegate = quadDelegate.copy()
}

private static func divide(quad: Quad, clusterDistance: Float, rootQuadDelegate: QD) -> Children {
let divided = quad.divide()
let northWest = QuadTreeNode2(quad: divided.northWest, clusterDistance: clusterDistance, rootQuadDelegate: rootQuadDelegate)
let northEast = QuadTreeNode2(quad: divided.northEast, clusterDistance: clusterDistance,rootQuadDelegate:rootQuadDelegate)
let southWest = QuadTreeNode2(quad: divided.southWest, clusterDistance: clusterDistance,rootQuadDelegate:rootQuadDelegate)
let southEast = QuadTreeNode2(quad: divided.southEast, clusterDistance: clusterDistance,rootQuadDelegate:rootQuadDelegate)
let northEast = QuadTreeNode2(quad: divided.northEast, clusterDistance: clusterDistance, rootQuadDelegate: rootQuadDelegate)
let southWest = QuadTreeNode2(quad: divided.southWest, clusterDistance: clusterDistance, rootQuadDelegate: rootQuadDelegate)
let southEast = QuadTreeNode2(quad: divided.southEast, clusterDistance: clusterDistance, rootQuadDelegate: rootQuadDelegate)
return Children(northWest, northEast, southWest, southEast)
}

Expand Down Expand Up @@ -355,8 +354,8 @@ public protocol QuadDelegate {

mutating func didAddNode(_ node: Node, at position: Vector2f)
mutating func didRemoveNode(_ node: Node, at position: Vector2f)
func createForExpanded(towards: Quadrant, from oldQuad: Quad, to newQuad: Quad) -> Self
func stem() -> Self
func copy() -> Self
func createNew() -> Self
}


Expand Down
54 changes: 46 additions & 8 deletions Tests/QuadTreeTests/AddTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,36 @@ import XCTest



final class EmptyQuadDelegate: QuadDelegate {

var count: Int

init(count: Int = 0) {
self.count = count
}

func didAddNode(_ node: IdNode, at position: Vector2f) {
count += 1
}

func didRemoveNode(_ node: IdNode, at position: Vector2f) {
count -= 1
}

func copy() -> Self {
return Self(count: self.count)
}

func createNew() -> Self {
return Self(count: 0)
}

typealias Node = IdNode

typealias Property = ()


}



Expand All @@ -21,21 +51,25 @@ final class AddTests: XCTestCase {
});
*/
func testCreatePoint() {
let q = QuadTree<IdNode>.create(startingWith: IdNode.new(), at: Vector2f(x: 0, y:0))
let q = QuadTree2.create(startingWith: IdNode.new(), at: Vector2f(x: 0, y:0)) { EmptyQuadDelegate() }
assert(q.jsStyleDescription ~= "{data: [0.0, 0.0]}")
assert(q.root.quadDelegate.count == 1)

q.add(IdNode.new(), at: Vector2f(x: 0.9, y:0.9))
assert(q.jsStyleDescription ~= "[{data: [0.0, 0.0]},,, {data: [0.9, 0.9]}]")
assert(q.root.quadDelegate.count == 2)

q.add(IdNode.new(), at: Vector2f(x: 0.9, y:0.0))
assert(q.jsStyleDescription ~= "[{data: [0.0, 0.0]}, {data: [0.9, 0.0]},, {data: [0.9, 0.9]}]")
assert(q.root.quadDelegate.count == 3)

q.add(IdNode.new(), at: Vector2f(x: 0.0, y:0.9))
assert(q.jsStyleDescription ~= "[{data: [0.0, 0.0]}, {data: [0.9, 0.0]}, {data: [0.0, 0.9]}, {data: [0.9, 0.9]}]")
assert(q.root.quadDelegate.count == 4)

q.add(IdNode.new(), at: Vector2f(x: 0.4, y:0.4))
assert(q.jsStyleDescription ~= "[[{data: [0.0, 0.0]},,, {data: [0.4, 0.4]}], {data: [0.9, 0.0]}, {data: [0.0, 0.9]}, {data: [0.9, 0.9]}]")

assert(q.root.quadDelegate.count == 5)
}


Expand All @@ -50,19 +84,23 @@ final class AddTests: XCTestCase {
*/
func testCreatePointOnPerimeter() {
let q = QuadTree<IdNode>(quad: Quad(x0: 0.0, x1: 1.0, y0: 0.0, y1: 1.0))
let q = QuadTree2<IdNode, EmptyQuadDelegate>(quad: Quad(x0: 0.0, x1: 1.0, y0: 0.0, y1: 1.0)) { EmptyQuadDelegate() }

q.add(IdNode.new(), at: Vector2f(x: 0, y:0))
assert(q.jsStyleDescription ~= "{data: [0.0, 0.0]}")
assert(q.root.quadDelegate.count == 1)

q.add(IdNode.new(), at: Vector2f(x: 1, y:1))
assert(q.jsStyleDescription ~= "[{data: [0.0, 0.0]},,, {data: [1.0, 1.0]}]")
assert(q.root.quadDelegate.count == 2)

q.add(IdNode.new(), at: Vector2f(x: 1, y:0))
assert(q.jsStyleDescription ~= "[{data: [0.0, 0.0]}, {data: [1.0, 0.0]},, {data: [1.0, 1.0]}]")
assert(q.root.quadDelegate.count == 3)

q.add(IdNode.new(), at: Vector2f(x: 0, y:1))
assert(q.jsStyleDescription ~= "[{data: [0.0, 0.0]}, {data: [1.0, 0.0]}, {data: [0.0, 1.0]}, {data: [1.0, 1.0]}]")
assert(q.root.quadDelegate.count == 4)
}


Expand All @@ -71,7 +109,7 @@ final class AddTests: XCTestCase {
// assert.deepStrictEqual(q.add([1, -1]).extent(), [[0, -4], [8, 4]]);
// });
func testCreatePointOnTop() {
let q = QuadTree<IdNode>(quad: Quad(x0: 0.0, x1: 2.0, y0: 0.0, y1: 2.0))
let q = QuadTree2<IdNode, EmptyQuadDelegate>(quad: Quad(x0: 0.0, x1: 2.0, y0: 0.0, y1: 2.0)) { EmptyQuadDelegate() }
q.add(IdNode.new(), at: Vector2f(x: 1, y:-1))
assert(q.root.quad ~= Quad(x0: 0, x1: 4, y0: -2, y1: 2))
}
Expand All @@ -83,7 +121,7 @@ final class AddTests: XCTestCase {
// assert.deepStrictEqual(q.add([1, 3]).extent(), [[0, 0], [4, 4]]);
// });
func testCreatePointOnBottom() {
let q = QuadTree<IdNode>(quad: Quad(x0: 0.0, x1: 2.0, y0: 0.0, y1: 2.0))
let q = QuadTree2<IdNode, EmptyQuadDelegate>(quad: Quad(x0: 0.0, x1: 2.0, y0: 0.0, y1: 2.0)) { EmptyQuadDelegate() }
q.add(IdNode.new(), at: Vector2f(x: 1, y:3))
assert(q.root.quad ~= Quad(x0: 0, x1: 4, y0: 0, y1: 4))
}
Expand All @@ -93,7 +131,7 @@ final class AddTests: XCTestCase {
// assert.deepStrictEqual(q.add([-1, 1]).extent(), [[-4, 0], [4, 8]]);
// });
func testCreatePointOnLeft() {
let q = QuadTree<IdNode>(quad: Quad(x0: 0.0, x1: 2.0, y0: 0.0, y1: 2.0))
let q = QuadTree2<IdNode, EmptyQuadDelegate>(quad: Quad(x0: 0.0, x1: 2.0, y0: 0.0, y1: 2.0)) { EmptyQuadDelegate() }
q.add(IdNode.new(), at: Vector2f(x: -1, y:1))
assert(q.root.quad ~= Quad(x0: -2, x1: 2, y0: 0, y1: 4))
}
Expand All @@ -106,7 +144,7 @@ final class AddTests: XCTestCase {
// assert.deepStrictEqual(q.add([0, 1]).root(), [{data: [0, 0]}, {data: [1, 0]}, {data: [0, 1], next: {data: [0, 1]}},, ]);
// });
func testCreateCoincidentPoints() {
let q = QuadTree<IdNode>(quad: Quad(x0: 0.0, x1: 1.0, y0: 0.0, y1: 1.0))
let q = QuadTree2<IdNode, EmptyQuadDelegate>(quad: Quad(x0: 0.0, x1: 1.0, y0: 0.0, y1: 1.0)) {EmptyQuadDelegate()}
q.add(IdNode.new(), at: Vector2f(x: 0, y:0))
assert(q.jsStyleDescription ~= "{data: [0.0, 0.0]}")

Expand All @@ -126,7 +164,7 @@ final class AddTests: XCTestCase {
// assert.deepStrictEqual(q.root(), {data: [1, 2]});
// });
func testCreateFirstPoint() {
let q = QuadTree<IdNode>.create(startingWith: .new(), at: .init(1, 2))
let q = QuadTree2<IdNode, EmptyQuadDelegate>.create(startingWith: .new(), at: .init(1, 2)) { EmptyQuadDelegate() }

assert(q.quad ~= Quad(x0: 1, x1: 2, y0: 2, y1: 3))
assert(q.jsStyleDescription ~= "{data: [1.0, 2.0]}")
Expand Down
9 changes: 9 additions & 0 deletions Tests/QuadTreeTests/QuadDelegateTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//
// QuadDelegateTests.swift
//
//
// Created by li3zhen1 on 10/9/23.
//

import Foundation

4 changes: 2 additions & 2 deletions Tests/QuadTreeTests/Utils/Nodes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ struct NamedNode: Identifiable, HasMassLikeProperty {



extension QuadTreeNode {
extension QuadTreeNode2 {
var jsStyleDescription: String {
if let children {
return "[\(children.northWest.jsStyleDescription), \(children.northEast.jsStyleDescription), \(children.southWest.jsStyleDescription), \(children.southEast.jsStyleDescription)]"
Expand Down Expand Up @@ -82,6 +82,6 @@ extension QuadTreeNode {
}
}

extension QuadTree {
extension QuadTree2 {
var jsStyleDescription: String { return self.root.jsStyleDescription }
}

0 comments on commit d9a7d56

Please sign in to comment.