Synchronized Visualization

Motivation

Simulation is waiting during drawing frame => no concurrent modification exceptions. Should be used only for layers, which can cause concurrent exceptions (when items added or removed from collecion). Not for layers, which does not cause exceptions (reading info about objects, which are not deleted or created, but the info is changing).

Howto

Generally

  1. create some instance of DrawListener, in method drawFrame(deadline) implement the drawing, watch the deadline !
  2. add it to simulation simulation.setDrawListener(obj);
  3. set timeout and reload time simulation.setDrawTimeout(1000); simulation.setDrawReload(40);
  4. everytime you need to draw the frame, call simulation.requestDraw();, whens simulation has some time, it calls drawListener.drawFrame(deadline)

Using MultipleDrawListener

  1. create instance with pointer to simulation and optional parameters, it will set self to simulation as draw listener and set timeout and reload time
  2. now you can request many listeners, just implement DrawInterface and everytime you need to draw, call multipleListener.requestDraw(drawListener);
    • if simulation is running, it adds the draw listener to queue and requests draw, drawed is when simulation allows it
    • if simulation is stopped, it returns false and does nothing else
    • if drawListener.drawFrame() returns false, it won't be removed from the queue and kept on first place

Creating synchronized VisLayer

Example StyledPointLayer, as you can see, the drawed points are always one step behind the simulation, it doesn't shows current state but past.

  public class EntityLayer extends CommonLayer {
    /** min remaining time in ms when creating points */
    private static int MIN_TIME = 5;
    public static VisLayer createSynchronized(final SomeStorage storage,
            final MultipleDrawListener drawListener) {
        GroupLayer group = GroupLayer.create();
        group.setHelpOverrideString("Some layer");
        group.addSubLayer(StyledPointLayer.create(new ThisElements(storage, drawListener)));
        return group;
    }
    private static class ThisElements implements StyledPointElements, DrawListener {
        private SomeStorage storage;
        private MultipleDrawListener drawListener;
        private Collection < StyledPointImpl > lastPoints;
        public ThisElements(SomeStorage storage, MultipleDrawListener drawListener) {
            this.storage = storage;
            this.drawListener = drawListener;
            lastPoints = new ArrayList < StyledPointImpl > ();
        }
        @Override
        public Iterable < ? extends StyledPoint > getPoints() {
            drawListener.requestDraw(this);
            return lastPoints;
        }
        @Override
        public boolean drawFrame(long deadline) {
            List < StyledPointImpl > points = new ArrayList < StyledPointImpl > ();
            for (Something o : storage.criticalCollection) {
                if (deadline - System.currentTimeMillis() < MIN_TIME) {
                    lastPoints = points;
                    return false;
                }
                points.add(makePoint(o));
            }
            lastPoints = points;
            return true;
        }
        @Override
        public String getName() {
            return "Some point layer";
        }
    }
}

How it works in simulation

  • The timeout is timeout for every drawing. When simulation calls drawFrame(deadline), the implementation must not exceet the deadline or it will cause concurrent access.
    • When the drawListener draws everything, the simulation will immediately continue (or wait the rest, if simulation speed is low).
    • If the drawListener exceets the timeout, simulation will start anyway and can cause exceptions.
  • The reload time is time for simulation to reload from last drawing. It will not draw next frame earlier than this delay.
    • This is because when drawing is requested frequently, the simulation has some time to do its job and not always wait for drawing.
  • If simulation is not running and drawing is requested, it returns false and not draws the frame. Then the frame could be drawed now or not drawed.
    • Recommended is not to draw the frame, because if the frame is being drawed and simulation is started, it is not synchronized and can cause exceptions.