Skip to content

Commit

Permalink
Remove force result builder
Browse files Browse the repository at this point in the history
  • Loading branch information
li3zhen1 committed Dec 30, 2024
1 parent af933ac commit db89ed1
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,11 @@ struct Lattice: View {
}

} force: {
LinkForce<Int>(
.link(
originalLength: .constant(0.8),
stiffness: .weightedByDegree { _, _ in 1.0 }
)
ManyBodyForce<Int>(strength: -0.8)
.manyBody(strength: -0.8)
}
.toolbar {
GraphStateToggle(graphStates: graphStates)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,9 @@ struct MermaidVisualization: View {
.stroke(.black, StrokeStyle(lineWidth: 2.0, lineCap: .round, lineJoin: .round))

} force: {
ManyBodyForce<String>()
LinkForce<String>(originalLength: .constant(70))
CenterForce<String>()
.manyBody()
.link(originalLength: .constant(70))
.center()
} emittingNewNodesWithStates: { id in
KineticState(position: getInitialPosition(id: id, r: 100))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ struct MiserableGraph: View {
}

} force: {
ManyBodyForce<String>(strength: -20)
CenterForce<String>()
LinkForce<String>(
.manyBody(strength: -20)
.center()
.link(
originalLength: .constant(35.0),
stiffness: .weightedByDegree { _, _ in 1.0}
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ struct MyRing: View {
@State var graphStates = ForceDirectedGraphState()

var body: some View {

ForceDirectedGraph(states: graphStates) {
Series(0..<20) { i in
NodeMark(id: 3 * i + 0)
Expand All @@ -32,26 +32,29 @@ struct MyRing: View {
.symbolSize(radius:6.0)
.foregroundStyle(.yellow)
.stroke(.clear)

LinkMark(from: 3 * i + 0, to: 3 * i + 1)
LinkMark(from: 3 * i + 1, to: 3 * i + 2)

LinkMark(from: 3 * i + 0, to: 3 * ((i + 1) % 20) + 0)
LinkMark(from: 3 * i + 1, to: 3 * ((i + 1) % 20) + 1)
LinkMark(from: 3 * i + 2, to: 3 * ((i + 1) % 20) + 2)


}
.stroke(.black, StrokeStyle(lineWidth: 1.5, lineCap: .round, lineJoin: .round))
.stroke(
.black,
StrokeStyle(lineWidth: 1.5, lineCap: .round, lineJoin: .round)
)

} force: {
ManyBodyForce<Int>(strength: -15)
LinkForce<Int>(
.manyBody(strength: -15)
.link(
originalLength: .constant(20.0),
stiffness: .weightedByDegree { _, _ in 3.0}
)
CenterForce<Int>()
CollideForce<Int>()
.center()
.collide()
}
.graphOverlay { proxy in
Rectangle().fill(.clear).contentShape(Rectangle())
Expand Down
113 changes: 113 additions & 0 deletions Sources/Grape/Descriptors/ForceDescriptor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,119 @@ public struct SealedForceDescriptor<NodeID: Hashable>: _ForceDescriptor {
}
}


@inlinable
@discardableResult
public static func center(x: Double = 0.0, y: Double = 0.0, strength: Double = 0.5) -> Self {
SealedForceDescriptor([.center(CenterForce(x: x, y: y, strength: strength))])
}

@inlinable
@discardableResult
public static func manyBody(strength: Double = -30.0, mass: ManyBodyForce<NodeID>.NodeMass = .constant(1.0), theta: Double = 0.9) -> Self {
SealedForceDescriptor([.manyBody(ManyBodyForce(strength: strength, mass: mass, theta: theta))])
}

@inlinable
@discardableResult
public static func link(
originalLength: LinkForce<NodeID>.LinkLength = .constant(30.0),
stiffness: LinkForce<NodeID>.Stiffness = .weightedByDegree { _, _ in 1.0 },
iterationsPerTick: UInt = 1
) -> Self {
SealedForceDescriptor([.link(LinkForce(originalLength: originalLength, stiffness: stiffness, iterationsPerTick: iterationsPerTick))])
}

@inlinable
@discardableResult
public static func collide(
strength: Double = 0.5,
radius: CollideForce<NodeID>.CollideRadius = .constant(3.0),
iterationsPerTick: UInt = 1
) -> Self {
SealedForceDescriptor([.collide(CollideForce(strength: strength, radius: radius, iterationsPerTick: iterationsPerTick))])
}

@inlinable
@discardableResult
public static func position(
direction: Kinetics2D.DirectionOfPositionForce,
targetOnDirection: PositionForce<NodeID>.TargetOnDirection,
strength: PositionForce<NodeID>.PositionStrength = .constant(1.0)
) -> Self {
SealedForceDescriptor([.position(PositionForce(direction: direction, targetOnDirection: targetOnDirection, strength: strength))])
}

@inlinable
@discardableResult
public static func radial(
center: SIMD2<Double> = .zero,
strength: RadialForce<NodeID>.RadialStrength = .constant(1.0),
radius: RadialForce<NodeID>.Radius = .constant(3.0)
) -> Self {
SealedForceDescriptor([.radial(RadialForce(center: center, strength: strength, radius: radius))])
}


@inlinable
@discardableResult
public consuming func center(x: Double = 0.0, y: Double = 0.0, strength: Double = 0.5) -> Self {
storage.append(.center(CenterForce(x: x, y: y, strength: strength)))
return self
}

@inlinable
@discardableResult
public consuming func manyBody(strength: Double = -30.0, mass: ManyBodyForce<NodeID>.NodeMass = .constant(1.0), theta: Double = 0.9) -> Self {
storage.append(.manyBody(ManyBodyForce(strength: strength, mass: mass, theta: theta)))
return self
}

@inlinable
@discardableResult
public consuming func link(
originalLength: LinkForce<NodeID>.LinkLength = .constant(30.0),
stiffness: LinkForce<NodeID>.Stiffness = .weightedByDegree { _, _ in 1.0 },
iterationsPerTick: UInt = 1
) -> Self{
storage.append(.link(LinkForce(originalLength: originalLength, stiffness: stiffness, iterationsPerTick: iterationsPerTick)))
return self
}

@inlinable
@discardableResult
public consuming func collide(
strength: Double = 0.5,
radius: CollideForce<NodeID>.CollideRadius = .constant(3.0),
iterationsPerTick: UInt = 1
) -> Self {
storage.append(.collide(CollideForce(strength: strength, radius: radius, iterationsPerTick: iterationsPerTick)))
return self
}

@inlinable
@discardableResult
public consuming func position(
direction: Kinetics2D.DirectionOfPositionForce,
targetOnDirection: PositionForce<NodeID>.TargetOnDirection,
strength: PositionForce<NodeID>.PositionStrength = .constant(1.0)
) -> Self{
storage.append(.position(PositionForce(direction: direction, targetOnDirection: targetOnDirection, strength: strength)))
return self
}

@inlinable
@discardableResult
public consuming func radial(
center: SIMD2<Double> = .zero,
strength: RadialForce<NodeID>.RadialStrength = .constant(1.0),
radius: RadialForce<NodeID>.Radius = .constant(3.0)
) -> Self{
storage.append(.radial(RadialForce(center: center, strength: strength, radius: radius)))
return self
}


@inlinable
init(_ storage: [Entry] = []) {
self.storage = storage
Expand Down
8 changes: 3 additions & 5 deletions Sources/Grape/Views/ForceDirectedGraph.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,9 @@ where NodeID == Content.NodeID {
/// The default force to be applied to the graph
///
/// - Returns: The default forces
@SealedForceDescriptorBuilder<NodeID>
@inlinable
static public func defaultForce() -> SealedForceDescriptor<NodeID> {
LinkForce<NodeID>()
CenterForce<NodeID>()
.link().center()
}

/// Creates a force-directed graph view.
Expand All @@ -81,7 +79,7 @@ where NodeID == Content.NodeID {
states: ForceDirectedGraphState = ForceDirectedGraphState(),
ticksPerSecond: Double = 60.0,
@GraphContentBuilder<NodeID> graph: () -> Content,
@SealedForceDescriptorBuilder<NodeID> force: () -> SealedForceDescriptor<NodeID> = Self.defaultForce,
force buildForce: () -> SealedForceDescriptor<NodeID> = defaultForce,
emittingNewNodesWithStates: @escaping (NodeID) -> KineticState = defaultKineticStateProvider
) {

Expand All @@ -90,7 +88,7 @@ where NodeID == Content.NodeID {

self._graphRenderingContextShadow = gctx

self._forceDescriptors = force()
self._forceDescriptors = buildForce()

self.model = .init(
gctx,
Expand Down

0 comments on commit db89ed1

Please sign in to comment.