View Javadoc

1   /**
2    * 
3    */
4   package de.desy.acop.video;
5   
6   import java.awt.Dimension;
7   import java.awt.Point;
8   import java.awt.Rectangle;
9   import java.awt.Shape;
10  import java.awt.event.ComponentAdapter;
11  import java.awt.event.ComponentEvent;
12  import java.awt.event.MouseAdapter;
13  import java.awt.event.MouseEvent;
14  import java.awt.geom.GeneralPath;
15  import java.awt.geom.Line2D;
16  import java.awt.geom.Point2D;
17  import java.awt.geom.Rectangle2D;
18  import java.beans.PropertyChangeEvent;
19  import java.beans.PropertyChangeListener;
20  import java.beans.PropertyChangeSupport;
21  
22  import javax.swing.JViewport;
23  import javax.swing.event.ChangeEvent;
24  import javax.swing.event.ChangeListener;
25  
26  import de.desy.acop.video.analysis.AImage;
27  import de.desy.acop.video.analysis.ImageAnalysisEngine;
28  import de.desy.acop.video.displayer.ImageDisplayer;
29  import de.desy.acop.video.displayer.ImageZoom;
30  import de.desy.tine.types.IMAGE;
31  import de.desy.tine.types.IMAGE.FrameHeader;
32  
33  /**
34   * </code>DisplayerManager</code> manages the </code>ImageDisplayer</code> and the two
35   * </code>SideProfileDisplayer</code>s contained in </code>AcopVideo</code>. It is
36   * supposed to give a better overview of updating the displayers.
37   * 
38   * @author Tilen Kusterle, Cosylab
39   *
40   */
41  public class DisplayerManager extends MouseAdapter {
42  	
43  	public static final String PROPERTY_ON_SCREEN_ROI = "onScreenRoi";
44  	
45  	private final ImageAnalysisEngine analysisEngine;
46  	private final ImageDisplayer imageDisp;
47  	private final SideProfileDisplayer horizontalDisp;
48  	private final SideProfileDisplayer verticalDisp;
49  	
50  	private PropertyChangeSupport pcSupport;
51  	
52  	private ScaleHelper scaleHelper;
53  	private ChangeListener viewPortListener;
54  	private AImage aImage;
55  	
56  	private Rectangle2D selectedRectangle;
57  	private Rectangle2D thresholdRectangle;
58  	private Rectangle2D draggingRectangle;
59  	private Rectangle2D crossRect;
60  	private Rectangle2D crossFitRect;
61  	private Rectangle aoiRectangle;
62  	
63  	private boolean dragStarted = false;
64  	private Point2D p1 = null;
65  	private Point2D p2 = null;
66  	private Point2D viewPoint = new Point2D.Double();
67  	
68  	private boolean canChangeSettings = false;
69  	
70  	private boolean displayStatistics = true;
71  	
72  	public DisplayerManager(ImageAnalysisEngine imageAnalysisEngine, ImageDisplayer imageDisplayer, SideProfileDisplayer horizontalDisplayer, SideProfileDisplayer verticalDisplayer) {
73  		analysisEngine = imageAnalysisEngine;
74  		imageDisp = imageDisplayer;
75  		horizontalDisp = horizontalDisplayer;
76  		verticalDisp = verticalDisplayer;
77  		
78  		imageDisp.addMouseListener(this);
79  		imageDisp.addMouseMotionListener(this);
80  		imageDisp.addComponentListener(new ComponentAdapter() {
81  			@Override
82  			public void componentResized(ComponentEvent e) {
83  				getScaleHelper().setComponentDimesnion(imageDisp.getSize());
84  			}
85  		});
86  		imageDisp.addPropertyChangeListener(new PropertyChangeListener() {
87  			@Override
88  			public void propertyChange(PropertyChangeEvent evt) {
89  				String name = evt.getPropertyName();
90  				if (name == ImageDisplayer.PROPERTY_KEEP_ASPECT_RATIO) {
91  					getScaleHelper().setKeepAspectRatio((Boolean) evt.getNewValue());
92  				}
93  				else if (name == ImageDisplayer.PROPERTY_AOI_ZOOM) {
94  					getScaleHelper().setAoiZoom((Boolean) evt.getNewValue());
95  				}
96  				else if (name == ImageDisplayer.PROPERTY_IMAGE_ZOOM) {
97  					getScaleHelper().setImageZoom((ImageZoom) evt.getNewValue());
98  				}
99  			}
100 		});
101 	}
102 	
103 	public void setDisplayStatistics(boolean display) {
104 		this.displayStatistics = display;
105 		horizontalDisp.setDisplayStatistics(display);
106 		verticalDisp.setDisplayStatistics(display);
107 	}
108 	
109 	public boolean isDisplayStatistics() {
110 		return this.displayStatistics;
111 	}
112 	
113 	public void updateImageDisplayerSize(Dimension size) {
114 		getScaleHelper().setComponentDimesnion(size);
115 	}
116 	
117 	public synchronized void updateAImage(AImage aImage) {
118 		if (this.aImage == aImage) return;
119 		boolean clean = true;
120 		if (this.aImage != null && aImage != null) {
121 			clean = this.aImage.getImageW() != aImage.getImageW() ||
122 					this.aImage.getImageH() != aImage.getImageH();
123 		}
124 		this.aImage = aImage;
125 		if (dragStarted && clean) {
126 			p1 = null;
127 			p2 = null;
128 			dragStarted = false;
129 			draggingRectangle = null;
130 			horizontalDisp.clearRoi();
131 			verticalDisp.clearRoi();
132 		}
133 		if (aImage == null) {
134 			crossRect = null;
135 			selectedRectangle = null;
136 			getScaleHelper().setImageData(null, null);
137 			imageDisp.resetForReceiving();
138 			horizontalDisp.clearData();
139 			verticalDisp.clearData();
140 			return;
141 		}
142 		
143 		IMAGE im = aImage.getImage();
144 		FrameHeader fh = im.getFrameHeader();
145 		int offsetX = fh.xStart;
146 		int offsetY = fh.yStart;
147 		int sizeX = (fh.aoiWidth >= 0) ? fh.aoiWidth : fh.sourceWidth;
148 		int sizeY = (fh.aoiHeight >= 0) ? fh.aoiHeight : fh.sourceHeight;
149 //		getScaleHelper().setImageData(new Dimension(fh.sourceWidth, fh.sourceHeight), new Rectangle(offsetX, offsetY, sizeX, sizeY));
150 		aoiRectangle = new Rectangle(offsetX, offsetY, sizeX, sizeY);
151 		getScaleHelper().setImageData(new Dimension(fh.sourceWidth, fh.sourceHeight), aoiRectangle);
152 		
153 		crossRect = new Rectangle2D.Double(aImage.getMeanX()-aImage.getStdX()/2, aImage.getMeanY()-aImage.getStdY()/2, aImage.getStdX(), aImage.getStdY());
154 		
155 		selectedRectangle = new Rectangle2D.Double(aImage.getRoiX(), aImage.getRoiY(), aImage.getRoiW(), aImage.getRoiH());
156 		if (aImage.isCalculateThreshold()) {
157 			thresholdRectangle = new Rectangle2D.Double(aImage.getRoi2X(), aImage.getRoi2Y(), aImage.getRoi2W(), aImage.getRoi2H());
158 		} else {
159 			thresholdRectangle = null;
160 		}
161 		
162 		if (aImage.isPerformFit()) {
163 			crossFitRect = new Rectangle2D.Double(aImage.getMeanXFit() - aImage.getStdXFit()/2, aImage.getMeanYFit()-aImage.getStdYFit()/2,aImage.getStdXFit(),aImage.getStdYFit());
164 		} else {
165 			crossFitRect = null;
166 		}
167 		
168 		imageDisp.updateValue(im);
169 		// update decorations...
170 		adjustSideProfileAspectRatio(false);
171 		horizontalDisp.setData(
172 				aImage.getSideViewX(), aImage.getSideViewAmplitudeX(),
173 				aImage.getMeanX(), aImage.getStdX(), aImage.getSideViewConstX(), 
174 				aImage.getAmplitudeXFit(), aImage.getMeanXFit(), aImage.getStdXFit(), aImage.getConstXFit(),
175 				aImage.getSlopeXFit(),aImage.getRoiX(), aImage.getRoiW(), aImage.isPerformFit()
176 		);
177 		verticalDisp.setData(
178 				aImage.getSideViewY(), aImage.getSideViewAmplitudeY(),
179 				aImage.getMeanY(), aImage.getStdY(), aImage.getSideViewConstY(), 
180 				aImage.getAmplitudeYFit(), aImage.getMeanYFit(), aImage.getStdYFit(), aImage.getConstYFit(),
181 				aImage.getSlopeYFit(),aImage.getRoiY(), aImage.getRoiH(), aImage.isPerformFit()
182 		);
183 	}
184 	
185 	@Override
186 	public void mouseClicked(MouseEvent e) {
187 		if (e.getClickCount() == 2 && aImage != null) {
188 			Rectangle r = getScaleHelper().getImageAoi();
189 			if (canChangeSettings) analysisEngine.setRoi(0, 0, r.width, r.height);
190 			else getPcSupport().firePropertyChange(PROPERTY_ON_SCREEN_ROI, null, r);
191 		}
192 	}
193 
194 	@Override
195 	public void mouseDragged(MouseEvent e) {
196 		if (dragStarted) {
197 			p2 = transformPoint(e.getPoint(), e.getComponent().getSize());
198 			horizontalDisp.setRoi(p1.getX()-viewPoint.getX(), p2.getX()-viewPoint.getX());
199 			verticalDisp.setRoi(p1.getY()-viewPoint.getY(), p2.getY()-viewPoint.getY());
200 			
201 			draggingRectangle = calculateRectangle();
202 			imageDisp.repaint();
203 		}
204 	}
205 
206 	@Override
207 	public void mousePressed(MouseEvent e) {
208 		if (aImage == null) return;
209 		if (e.getButton() == MouseEvent.BUTTON1) {
210 			dragStarted = true;
211 			p1 = transformPoint(e.getPoint(), e.getComponent().getSize());
212 		}
213 	}
214 
215 	@Override
216 	public void mouseReleased(MouseEvent e) {
217 		if (e.getButton() == MouseEvent.BUTTON1) {
218 			if (dragStarted) {
219 				if (p1 != null && p2 != null) {
220 					
221 					Rectangle r = getScaleHelper().componentToImage(calculateRectangle());
222 					Rectangle rect = getScaleHelper().getImageAoi();
223 					r = new Rectangle(r.x + rect.x,r.y + rect.y,r.width,r.height);
224 					if (canChangeSettings) {
225 						horizontalDisp.clearRoi();
226 						verticalDisp.clearRoi();
227 						analysisEngine.setRoi(r.x, r.y, r.width, r.height);
228 					}
229 					else getPcSupport().firePropertyChange(PROPERTY_ON_SCREEN_ROI, null, r);
230 				}
231 				dragStarted = false;
232 				p1 = null;
233 				p2 = null;
234 				draggingRectangle = null;
235 			}
236 		}
237 	}
238 	
239 	private Rectangle2D calculateRectangle() {
240 		double x, y, w, h;
241 		if (p1.getX() < p2.getX()) {
242 			x = p1.getX();
243 			w = p2.getX()-p1.getX();
244 		} else {
245 			x = p2.getX();
246 			w = p1.getX()-p2.getX();
247 		}
248 		if (p1.getY() < p2.getY()) {
249 			y = p1.getY();
250 			h = p2.getY()-p1.getY();
251 		} else {
252 			y = p2.getY();
253 			h = p1.getY()-p2.getY();
254 		}
255 		return new Rectangle2D.Double(x, y, w, h);
256 	}
257 	
258 	private synchronized Point2D transformPoint(Point p, Dimension dim) {
259 		Rectangle2D r = getScaleHelper().getActiveRectangle();
260 		r = getScaleHelper().imageToComponent(getScaleHelper().componentToImage(r));
261 		double x = p.x, y = p.y;
262 		if (p.x < r.getMinX()) x = r.getMinX();
263 		else if (p.x > r.getMaxX()) x = r.getMaxX();
264 		if (p.y < r.getMinY()) y = r.getMinY();
265 		else if (p.y > r.getMaxY()) y = r.getMaxY();
266 		p.setLocation(x, y);
267 		return p;
268 	}
269 	
270 	public Rectangle2D getDraggingRectangle() {
271 		return draggingRectangle;
272 	}
273 	
274 	public boolean isRoiSelected() {
275 		return selectedRectangle != null;
276 	}
277 	
278 	public synchronized Rectangle2D getScaledSelectedRectangle() {
279 		if (selectedRectangle == null) return null;
280 		return getScaleHelper().imageToComponent(selectedRectangle);
281 	}
282 	
283 	public boolean isThresholdROISelected() {
284 		return thresholdRectangle != null;
285 	}
286 	
287 	public synchronized Rectangle2D getScaledThresholdROIRectangle() {
288 		if (thresholdRectangle == null) return null;
289 		return getScaleHelper().imageToComponent(thresholdRectangle);
290 	}
291 	
292 	public boolean isCrossAvailable() {
293 		return crossRect != null && displayStatistics;
294 	}
295 	
296 	public synchronized Shape getCross() {
297 		if (crossRect == null) return null;
298 		Rectangle2D r = getScaleHelper().imageToComponent(crossRect);
299 		if (r == null) return null;
300 		GeneralPath marker = new GeneralPath(new Line2D.Double(r.getCenterX()-r.getWidth()/2, r.getCenterY(), r.getCenterX()+r.getWidth()/2, r.getCenterY()));
301 		marker.append(new Line2D.Double(r.getCenterX(), r.getCenterY()-r.getHeight()/2, r.getCenterX(), r.getCenterY()+r.getHeight()/2), false);
302 		return marker;
303 	}
304 	
305 	public boolean isCrossFitAvailable() {
306 		return crossFitRect != null;
307 	}
308 	
309 	public synchronized Shape getCrossFit() {
310 		if (crossFitRect == null) return null;
311 		Rectangle2D r = getScaleHelper().imageToComponent(crossFitRect);
312 		if (r == null) return null;
313 		GeneralPath marker = new GeneralPath(new Line2D.Double(r.getCenterX()-r.getWidth()/2, r.getCenterY(), r.getCenterX()+r.getWidth()/2, r.getCenterY()));
314 		marker.append(new Line2D.Double(r.getCenterX(), r.getCenterY()-r.getHeight()/2, r.getCenterX(), r.getCenterY()+r.getHeight()/2), false);
315 		return marker;
316 	}
317 	
318 	public ChangeListener getViewPortListener() {
319 		if (viewPortListener == null) {
320 			viewPortListener = new ChangeListener() {
321 				@Override
322 				public void stateChanged(ChangeEvent e) {
323 					JViewport port = (JViewport) e.getSource();
324 					Point p = port.getViewPosition();
325 					if (p.getX() != viewPoint.getX() || p.getY() != viewPoint.getY()) {
326 						viewPoint = p;
327 						horizontalDisp.setCanvasStart(-viewPoint.getX());
328 						verticalDisp.setCanvasStart(-viewPoint.getY());
329 					}
330 				}
331 			};
332 			
333 		}
334 
335 		return viewPortListener;
336 	}
337 	
338 	private synchronized ScaleHelper getScaleHelper() {
339 		if (scaleHelper == null) {
340 			scaleHelper = new ScaleHelper(imageDisp.isKeepAspectRatio(), imageDisp.isAOIZoom(), imageDisp.getImageZoom());
341 			scaleHelper.addPropertyChangeListener(new PropertyChangeListener() {
342 				@Override
343 				public void propertyChange(PropertyChangeEvent evt) {
344 					String name = evt.getPropertyName();
345 					if (name == ScaleHelper.PROPERTY_COMPONENT_DIMENSION) {
346 						adjustSideProfileAspectRatio(true);
347 					}
348 					else if (name == ScaleHelper.PROPERTY_ACTIVE_RECTANGLE) {
349 						adjustSideProfileAspectRatio(true);
350 					}
351 				}
352 			});
353 		}
354 		return scaleHelper;
355 	}
356 	
357 	private void adjustSideProfileAspectRatio(boolean repaintAtOnce) {
358 		Rectangle2D image = getScaleHelper().getActiveRectangle();
359 		if (image == null) return;
360 		image = getScaleHelper().imageToComponent(getScaleHelper().componentToImage(image));
361 		
362 		//+2 because borders are used
363 		horizontalDisp.setCanvasSize(image.getX()-viewPoint.getX(), image.getWidth()+2, repaintAtOnce);
364 		verticalDisp.setCanvasSize(image.getY()-viewPoint.getY(), image.getHeight()+2, repaintAtOnce);
365 	}
366 
367 	/**
368 	 * @return the canChangeSettings
369 	 */
370 	public boolean isCanChangeSettings() {
371 		return canChangeSettings;
372 	}
373 
374 	/**
375 	 * @param canChangeSettings the canChangeSettings to set
376 	 */
377 	public void setCanChangeSettings(boolean canChangeSettings) {
378 		this.canChangeSettings = canChangeSettings;
379 	}
380 
381 	private PropertyChangeSupport getPcSupport() {
382 		if (pcSupport == null) {
383 			pcSupport = new PropertyChangeSupport(this);
384 		}
385 		return pcSupport;
386 	}
387 
388 	/**
389 	 * Adds a </code>PropertyChangeListener</code> for the specified propertyName.
390 	 * @param propertyName the name of the property
391 	 * @param listener the </code>PropertyChangeListener</code> to add
392 	 */
393 	public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
394 		getPcSupport().addPropertyChangeListener(propertyName, listener);
395 	}
396 	
397 	/**
398 	 * Removes a </code>PropertyChangeListener</code> for the specified propertyName.
399 	 * @param propertyName the name of the property
400 	 * @param listener the </code>PropertyChangeListener</code> to remove
401 	 */
402 	public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
403 		getPcSupport().removePropertyChangeListener(propertyName, listener);
404 	}
405 	
406 	/**
407 	 * Adds a </code>PropertyChangeListener</code>.
408 	 * @param listener the </code>PropertyChangeListener</code> to add
409 	 */
410 	public void addPropertyChangeListener(PropertyChangeListener listener) {
411 		getPcSupport().addPropertyChangeListener(listener);
412 	}
413 	
414 	/**
415 	 * Removes a </code>PropertyChangeListener</code>.
416 	 * @param listener the </code>PropertyChangeListener</code> to remove
417 	 */
418 	public void removePropertyChangeListener(PropertyChangeListener listener) {
419 		getPcSupport().removePropertyChangeListener(listener);
420 	}
421 	
422 }