Revision 4:5f3a96f034a8

View differences:

src/main/java/cz/agents/alite/visualizer2d/Layer.java
5 5
 */
6 6
public interface Layer<T> {
7 7

  
8
    default public void init(VisPane<T> visPane) {}
9

  
10
    default public void deinit(VisPane<T> visPane) {}
11

  
8 12
    public void paint(VisCanvas canvas, Point2dAdapter<T> adapter);
9 13

  
10 14
}
src/main/java/cz/agents/alite/visualizer2d/LayerContainer.java
1 1
package cz.agents.alite.visualizer2d;
2 2

  
3
import java.util.HashSet;
3 4
import java.util.List;
5
import java.util.Set;
4 6
import java.util.concurrent.CopyOnWriteArrayList;
5 7

  
6 8
/**
7 9
 * @author Ondrej Hrstka (ondrej.hrstka at agents.fel.cvut.cz)
8 10
 */
9
public class LayerContainer<T> {
11
public class LayerContainer<T> implements Layer<T> {
10 12

  
13
    private final Set<VisPane<T>> initializedPanes = new HashSet<>();
11 14
    private final List<Layer<T>> layers = new CopyOnWriteArrayList<>();
12 15

  
13
    final void updateLayers(VisCanvas visCanvas, Point2dAdapter<T> adapter) {
16
    @Override
17
    public synchronized void init(VisPane<T> visPane) {
18
        if (initializedPanes.contains(visPane)) {
19
            initializedPanes.add(visPane);
20
            layers.forEach(layer -> layer.init(visPane));
21
        }
22
    }
23

  
24
    @Override
25
    public synchronized void deinit(VisPane<T> visPane) {
26
        if (initializedPanes.contains(visPane)) {
27
            initializedPanes.remove(visPane);
28
            layers.forEach(layer -> layer.deinit(visPane));
29
        }
30

  
31
    }
32

  
33
    @Override
34
    public final void paint(VisCanvas visCanvas, Point2dAdapter<T> adapter) {
14 35
        for (Layer<T> layer : layers) {
15 36
            layer.paint(visCanvas, adapter);
16 37
        }
17 38
    }
18 39

  
19
    public void addLayer(Layer<T> layer) {
40
    public synchronized void addLayer(Layer<T> layer) {
20 41
        if (!layers.contains(layer)) {
42
            initializedPanes.forEach(layer::init);
21 43
            layers.add(layer);
22 44
        }
23 45
    }
24 46

  
47
    public synchronized boolean removeLayer(Layer<T> layer) {
48
        if (!layers.contains(layer)) {
49
            layers.remove(layer);
50
            //TODO ensure thread safety
51
            initializedPanes.forEach(layer::deinit);
52
            return true;
53
        }
54
        return false;
55
    }
56

  
25 57
}
src/main/java/cz/agents/alite/visualizer2d/VisPane.java
8 8
import java.awt.geom.NoninvertibleTransformException;
9 9
import java.awt.geom.Point2D;
10 10
import java.awt.image.BufferStrategy;
11
import java.util.Optional;
12
import java.util.concurrent.ScheduledFuture;
11 13
import java.util.concurrent.ScheduledThreadPoolExecutor;
12 14
import java.util.concurrent.TimeUnit;
13 15

  
......
16 18
 */
17 19
public final class VisPane<T> {
18 20

  
19
    private AffineTransform transform;
21
    public static final int REFRESH_IN_MS = 40; //25 FPS
22
    private static final ScheduledThreadPoolExecutor EXECUTOR = new ScheduledThreadPoolExecutor(1);
20 23

  
21
    private static final int REFRESH_IN_MS = 40; //25 FPS
22
    private static final int VIS_THREAD_PRIORITY = Thread.MIN_PRIORITY;
24
    private LayerContainer<T> layerContainer;
25
    //TODO solve volatile vs synchronized
26
    private volatile Point2dAdapter<T> adapter;
27
    private volatile Optional<VisCanvas> visCanvas = Optional.empty();
23 28

  
24
    //TODO solve volatile vs synchronized
25
    private volatile LayerContainer<T> layerContainer;
26
    private volatile Point2dAdapter<T> adapter;
29
    private boolean running = false;
30
    private ScheduledFuture<?> updateFuture;
27 31

  
28 32
    private boolean reinitializeBuffers = true;
29 33
    private BufferStrategy strategy;
30 34
    private Graphics2D graphics;
31

  
35
    private final AffineTransform transform = new AffineTransform();
36
    private final Canvas canvas = new Canvas();
32 37
    private final JPanel panel = new JPanel();
33
    private final Canvas canvas = new Canvas();
34 38

  
35 39
    public VisPane(LayerContainer<T> layerContainer, Point2dAdapter<T> adapter) {
36 40
        this.layerContainer = layerContainer;
37 41
        this.adapter = adapter;
38 42

  
39
        transform = new AffineTransform();
40 43
        VisPaneMouseListener mouseListener = new VisPaneMouseListener(this);
41 44
        canvas.addMouseListener(mouseListener);
42 45
        canvas.addMouseMotionListener(mouseListener);
......
55 58
        });
56 59
    }
57 60

  
58
    public void start() {
59
        ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
60
        executor.scheduleAtFixedRate(this::update, 0, REFRESH_IN_MS, TimeUnit.MILLISECONDS);
61
    public synchronized void start() {
62
        if (!running) {
63
            running = true;
64
            layerContainer.init(this);
65
            updateFuture = EXECUTOR.scheduleAtFixedRate(this::update, 0, REFRESH_IN_MS, TimeUnit.MILLISECONDS);
66
        }
67
    }
68

  
69
    public synchronized void stop() {
70
        if (running) {
71
            running = false;
72
            reinitializeBuffers = true;
73
            updateFuture.cancel(true);
74
            updateFuture = null;
75
            layerContainer.deinit(this);
76
        }
61 77
    }
62 78

  
63 79
    public JPanel getPanel() {
......
72 88
        this.adapter = adapter;
73 89
    }
74 90

  
75
    public LayerContainer<T> getLayerContainer() {
91
    public synchronized LayerContainer<T> getLayerContainer() {
76 92
        return layerContainer;
77 93
    }
78 94

  
79
    public void setLayerContainer(LayerContainer<T> layerContainer) {
95
    public synchronized void setLayerContainer(LayerContainer<T> layerContainer) {
96
        boolean wasRunning = running;
97
        stop();
80 98
        this.layerContainer = layerContainer;
99
        if (wasRunning) {
100
            start();
101
        }
102
    }
103

  
104
    public Optional<VisCanvas> getVisCanvas() {
105
        return visCanvas;
81 106
    }
82 107

  
83 108
    public final void translate(int deltaX, int deltaY) {
84 109
        final Point2D deltaScreen = new Point2D.Double(deltaX, deltaY);
85 110

  
86
        synchronized (this) {
111
        synchronized (transform) {
87 112
            try {
88 113
                Point2D deltaWorld = new Point2D.Double();
89 114
                transform.createInverse().deltaTransform(deltaScreen, deltaWorld);
......
99 124
        final Point2D presScale = new Point2D.Double();
100 125
        final Point2D postScale = new Point2D.Double();
101 126

  
102
        synchronized (this) {
127
        synchronized (transform) {
103 128
            try {
104 129
                transform.inverseTransform(scaleCenterScreen, presScale);
105 130
                transform.scale(multiplyFactor, multiplyFactor);
......
115 140
        final double deltaAngleRad = Math.toRadians(deltaAngleDeg);
116 141
        Rectangle bounds = panel.getBounds();
117 142
        final Point2D centerScreen = new Point2D.Double(bounds.getCenterX(), bounds.getCenterY());
118
        synchronized (this) {
143
        synchronized (transform) {
119 144
            Point2D centerWorld = new Point2D.Double();
120 145
            try {
121 146
                transform.inverseTransform(centerScreen, centerWorld);
......
132 157

  
133 158
            AffineTransform originalTransform = graphics.getTransform();
134 159
            AffineTransform affineTransform = calculateAffineTransform();
135
            VisCanvas visCanvas = new VisCanvas(affineTransform, graphics, panel.getBounds());
160
            visCanvas = Optional.of(new VisCanvas(affineTransform, graphics, panel.getBounds()));
136 161

  
137
            layerContainer.updateLayers(visCanvas, adapter);
162
            layerContainer.paint(visCanvas.get(), adapter);
138 163

  
139 164
            graphics.setTransform(originalTransform);
140 165
            strategy.show();
......
158 183
        return false;
159 184
    }
160 185

  
161
    private synchronized AffineTransform calculateAffineTransform() {
162
        return new AffineTransform(transform);
186
    private AffineTransform calculateAffineTransform() {
187
        synchronized (transform) {
188
            return new AffineTransform(transform);
189
        }
163 190
    }
164 191
}
src/main/java/cz/agents/alite/visualizer2d/demo/Demo.java
18 18
public class Demo {
19 19

  
20 20

  
21
    public static void main(String[] args) {
21
    public static void main(String[] args) throws InterruptedException {
22 22
        final AngleProvider angleProvider = new AngleProvider();
23 23

  
24 24
        LayerContainer<Point2d> layers = new LayerContainer<>();
......
37 37

  
38 38
        visPane.start();
39 39
        frame.setVisible(true);
40

  
41
        Thread.sleep(5000);
40 42
        //frame.pack();
41 43
    }
42 44

  

Also available in: Unified diff