Class NetworkDeclutterSimulation
- All Implemented Interfaces:
Simulation
The model lives in the unit square:
x in [0,1]y in [0,1]
Rendering is responsible for mapping world coordinates into pixel coordinates. The view should also compute and populate NetworkModel.Node.worldRadius for each node every frame (or whenever the viewport size changes), so this simulation can:
- apply overlap-aware repulsion based on icon size
- clamp positions so icons remain fully visible inside the unit square
Force model
Each step computes the net force on each node as the sum of:
- Springs (edges) for each client→server connection:
F = k * (r - r0) * rhatris current distance between endpointsr0is the equilibrium distancekcontrols stiffness
- Repulsion (all pairs) for node separation: approximately
F ~ repulsionC / (r^2 + eps)alongrhat.Repulsion is increased if icons are close enough to overlap and may be further increased when one or both nodes are servers via
serverRepulsion. - Centering toward (0.5, 0.5):
F = -centerK * (x - 0.5, y - 0.5).This prevents the common “everything evacuates to the boundary” artifact in layouts that combine repulsion with hard clamping. Set too high, it can also cause “all servers pile up in the center”, so keep it small.
Integration and convergence
Velocity is updated with damping:
v from damping * v + dt * F x from x + v
A per-component velocity clamp (vmax) limits occasional numeric
spikes. The simulation stops when either:
- cancel is requested,
- the average node speed falls below
settleVel()afterminSteps, or maxStepsis reached.
Parameter tuning hints (unit-square world)
- Servers clump in the center: increase
serverRepulsion, increaserepulsionC, reducecenterK, or reducek. - Clients collapse onto servers: increase
r0and/orrepulsionC. - Layout “rings” the boundary: increase
centerKslightly (but not too much) and/or reducerepulsionC. - Jitter/oscillation: increase
damping, reducek, reducevmax.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic final classPer-step diagnostics useful for plots and tuning.static final classEnergy diagnostics for the current simulation state. -
Constructor Summary
ConstructorsConstructorDescriptionCreate a decluttering simulation for the given model. -
Method Summary
Modifier and TypeMethodDescriptionvoidcancel(SimulationContext ctx) Cancellation hook called by the engine on the simulation thread.computeDiagnostics(double avgSpeed, int vmaxHitCount, double FrmsNow) Compute aNetworkDeclutterSimulation.Diagnosticssnapshot for the current model state.Compute a pseudo-energy snapshot for the current layout.Return the queue of per-step diagnostic samples produced during the simulation.getModel()Get the model being updated by this simulation.doubleReturn the printer spring-constant multiplier.intgetStep()Return the current simulation step index (1-based; 0 before the first step has completed).voidinit(SimulationContext ctx) Initialize the simulation: reset the step counter and post an initial refresh so the user sees the starting layout before it starts moving.voidsetEngine(SimulationEngine engine) Attach the engine so this simulation can post messages/progress/refresh.voidsetPrinterKBoost(double printerKBoost) Set the printer spring-constant multiplier.booleanstep(SimulationContext ctx) Execute a single step of the simulation.Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, waitMethods inherited from interface edu.cnu.mdi.sim.Simulation
shutdown
-
Constructor Details
-
NetworkDeclutterSimulation
Create a decluttering simulation for the given model.- Parameters:
model- the world network model to update in-place (non-null)- Throws:
IllegalArgumentException- ifmodelis null
-
-
Method Details
-
getPrinterKBoost
public double getPrinterKBoost()Return the printer spring-constant multiplier.- Returns:
- the current
printerKBoostvalue
-
setPrinterKBoost
public void setPrinterKBoost(double printerKBoost) Set the printer spring-constant multiplier.- Parameters:
printerKBoost- the new multiplier; values less than 1.0 make printer springs softer than the base constant, values greater than 1.0 make them stiffer
-
getModel
Get the model being updated by this simulation.Views typically use this to render nodes/edges.
- Returns:
- the model (never null)
-
setEngine
Attach the engine so this simulation can post messages/progress/refresh.This is optional. If unset, the simulation still runs but does not emit UI hints beyond what the engine itself already provides.
- Parameters:
engine- engine executing this simulation (may be null)
-
init
Initialize the simulation: reset the step counter and post an initial refresh so the user sees the starting layout before it starts moving.- Specified by:
initin interfaceSimulation- Parameters:
ctx- the simulation context (not used directly, but required by theSimulationcontract)- Throws:
Exception- not thrown by this implementation
-
step
Description copied from interface:SimulationExecute a single step of the simulation. Called repeatedly on the simulation thread while running.- Specified by:
stepin interfaceSimulation- Parameters:
ctx- simulation context- Returns:
- true to continue running; false to stop (normal completion)
-
cancel
Cancellation hook called by the engine on the simulation thread.Posts a UI message and indeterminate progress indicator so the user sees immediate feedback. The engine calls
Simulation.shutdown(SimulationContext)immediately after this method returns.No separate simulation-side cancellation flag is needed:
SimulationContext.isCancelRequested()is the authoritative cancellation signal and is already checked at the top ofstep(SimulationContext).- Specified by:
cancelin interfaceSimulation- Parameters:
ctx- the simulation context
-
getDiagnosticsSamples
Return the queue of per-step diagnostic samples produced during the simulation.The simulation enqueues a sample every 5 steps on the simulation thread. The view drains the queue by calling
Queue.poll()repeatedly inside itsonRefreshcallback on the EDT.ConcurrentLinkedQueueis lock-free, so concurrent access from both threads is safe without any additional synchronization.- Returns:
- the live diagnostics queue; never
null
-
getStep
public int getStep()Return the current simulation step index (1-based; 0 before the first step has completed).- Returns:
- the step count
-
computeEnergy
Compute a pseudo-energy snapshot for the current layout.Delegates to
computeEnergyInternal(), the single canonical implementation shared withcomputeDiagnostics(double, int, double)to eliminate code duplication.Note: These values are not a conserved Hamiltonian. See
computeEnergyInternal()for the full explanation of the force/energy mismatch and other non-conservative effects.- Returns:
- an
NetworkDeclutterSimulation.Energyrecord for the current node positions and velocities
-
computeDiagnostics
public NetworkDeclutterSimulation.Diagnostics computeDiagnostics(double avgSpeed, int vmaxHitCount, double FrmsNow) Compute aNetworkDeclutterSimulation.Diagnosticssnapshot for the current model state.Energies are obtained from
computeEnergyInternal()— the single canonical implementation shared withcomputeEnergy()— so the two can never diverge.The caller may supply
avgSpeedandvmaxHitCountfrom values already computed during the integration step to avoid an extra O(N) scan. PassDouble.NaN/-1to have this method recompute them from the current node velocities.- Parameters:
avgSpeed- mean node speed in world-units/step from the most recent integration, orDouble.NaNto recomputevmaxHitCount- number of nodes that hit the speed clamp in the most recent integration step, or-1to recomputeFrmsNow- force RMS computed during the current step- Returns:
- a fully-populated
NetworkDeclutterSimulation.Diagnosticsfor the current step
-