Class NetworkDeclutterSimulation

java.lang.Object
edu.cnu.mdi.sim.demo.network.NetworkDeclutterSimulation
All Implemented Interfaces:
Simulation

public final class NetworkDeclutterSimulation extends Object implements Simulation
Force-directed "decluttering" simulation for a server/client network using normalized world coordinates.

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:

  1. Springs (edges) for each client→server connection: F = k * (r - r0) * rhat
    • r is current distance between endpoints
    • r0 is the equilibrium distance
    • k controls stiffness
  2. Repulsion (all pairs) for node separation: approximately F ~ repulsionC / (r^2 + eps) along rhat.

    Repulsion is increased if icons are close enough to overlap and may be further increased when one or both nodes are servers via serverRepulsion.

  3. 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() after minSteps, or
  • maxSteps is reached.

Parameter tuning hints (unit-square world)

  • Servers clump in the center: increase serverRepulsion, increase repulsionC, reduce centerK, or reduce k.
  • Clients collapse onto servers: increase r0 and/or repulsionC.
  • Layout “rings” the boundary: increase centerK slightly (but not too much) and/or reduce repulsionC.
  • Jitter/oscillation: increase damping, reduce k, reduce vmax.
  • Constructor Details

    • NetworkDeclutterSimulation

      public NetworkDeclutterSimulation(NetworkModel model)
      Create a decluttering simulation for the given model.
      Parameters:
      model - the world network model to update in-place (non-null)
      Throws:
      IllegalArgumentException - if model is null
  • Method Details

    • getPrinterKBoost

      public double getPrinterKBoost()
      Return the printer spring-constant multiplier.
      Returns:
      the current printerKBoost value
    • 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

      public NetworkModel getModel()
      Get the model being updated by this simulation.

      Views typically use this to render nodes/edges.

      Returns:
      the model (never null)
    • setEngine

      public void setEngine(SimulationEngine engine)
      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

      public void init(SimulationContext ctx) throws Exception
      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:
      init in interface Simulation
      Parameters:
      ctx - the simulation context (not used directly, but required by the Simulation contract)
      Throws:
      Exception - not thrown by this implementation
    • step

      public boolean step(SimulationContext ctx)
      Description copied from interface: Simulation
      Execute a single step of the simulation. Called repeatedly on the simulation thread while running.
      Specified by:
      step in interface Simulation
      Parameters:
      ctx - simulation context
      Returns:
      true to continue running; false to stop (normal completion)
    • cancel

      public void cancel(SimulationContext ctx)
      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 of step(SimulationContext).

      Specified by:
      cancel in interface Simulation
      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 its onRefresh callback on the EDT. ConcurrentLinkedQueue is 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

      public NetworkDeclutterSimulation.Energy computeEnergy()
      Compute a pseudo-energy snapshot for the current layout.

      Delegates to computeEnergyInternal(), the single canonical implementation shared with computeDiagnostics(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.Energy record for the current node positions and velocities
    • computeDiagnostics

      public NetworkDeclutterSimulation.Diagnostics computeDiagnostics(double avgSpeed, int vmaxHitCount, double FrmsNow)
      Compute a NetworkDeclutterSimulation.Diagnostics snapshot for the current model state.

      Energies are obtained from computeEnergyInternal() — the single canonical implementation shared with computeEnergy() — so the two can never diverge.

      The caller may supply avgSpeed and vmaxHitCount from values already computed during the integration step to avoid an extra O(N) scan. Pass Double.NaN / -1 to have this method recompute them from the current node velocities.

      Parameters:
      avgSpeed - mean node speed in world-units/step from the most recent integration, or Double.NaN to recompute
      vmaxHitCount - number of nodes that hit the speed clamp in the most recent integration step, or -1 to recompute
      FrmsNow - force RMS computed during the current step
      Returns:
      a fully-populated NetworkDeclutterSimulation.Diagnostics for the current step