All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openimaj.vis.VisualisationImpl Maven / Gradle / Ivy

Go to download

A library that contains classes for visualising various different features, such as audio and video.

There is a newer version: 1.3.10
Show newest version
/**
 * Copyright (c) 2011, The University of Southampton and the individual contributors.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 *   * 	Redistributions of source code must retain the above copyright notice,
 * 	this list of conditions and the following disclaimer.
 *
 *   *	Redistributions in binary form must reproduce the above copyright notice,
 * 	this list of conditions and the following disclaimer in the documentation
 * 	and/or other materials provided with the distribution.
 *
 *   *	Neither the name of the University of Southampton nor the names of its
 * 	contributors may be used to endorse or promote products derived from this
 * 	software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
/**
 *
 */
package org.openimaj.vis;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;

import org.openimaj.image.ImageUtilities;
import org.openimaj.image.MBFImage;

/**
 *	A top level class for visualisations. This class handles the creation
 *	of an image (MBFImage) for drawing the visualisation into. It also makes
 *	the visualisation available as a Swing JPanel and, using {@link #showWindow(String)},
 *	allows the visualisation to be displayed in a window.
 *	

* This class is abstract - it does not know how to paint the data on which it * is typed. It is therefore necessary to subclass this class with specific * implementations of visualisations for specific types. To do this, override * the {@link #update()} method in this class to draw the visualisation into * the visImage member. The implementation of the {@link #update()} * method may call {@link #repaint()} if it so wishes to update any displays * of the data. This is called automatically when {@link #setData(Object)} is * called to update the data object. *

* The class also allows for linking visualisations so that one visualisation * can draw on top of another visualisation's output. However, the visualisations * do not affect each other's visualisation images. If you call the constructor * that takes a visualisation, this visualisation will become an overlay of * the given visualisation. Each time the underlying visualisation is updated, * a copy of the visualisation is stored in this visualisation for drawing as * a background. This means that this visualisation can update more often than * the underlying visualisation, however, it can be slow if the underlying * visualisation updates often because it's making a copy of the image. * * @author David Dupplaw ([email protected]) * @created 27 Jul 2012 * @version $Author$, $Revision$, $Date$ * @param The type of the data to be visualised */ public abstract class VisualisationImpl extends JPanel implements ComponentListener, Visualisation, AnimatedVisualisationListener { /** */ private static final long serialVersionUID = 1L; /** The visualisation image */ protected MBFImage visImage = null; /** The double buffer image */ private MBFImage dbImage = null; /** The data to be visualised */ protected T data = null; /** Whether to allow resizing of the visualisation */ private boolean allowResize = true; /** The overlay image */ private MBFImage overlayImage = null; /** The list of visualisations that wish to overlay on this vis */ private final List> overlays = new ArrayList>(); /** Whether to clear the image before redrawing */ protected boolean clearBeforeDraw = true; /** The background colour to clear the image to */ private final Float[] backgroundColour = new Float[]{0f,0f,0f,1f}; /** The visualisation that this vis is being overlaid on */ private VisualisationImpl overlaidOn = null; /** The required size of the vis */ private Dimension requiredSize = new Dimension( 400, 400 ); /** * Default constructor */ protected VisualisationImpl() {} /** * Create a new visualisation with the given width and height * @param width The width * @param height The height */ public VisualisationImpl( final int width, final int height ) { this.visImage = new MBFImage( width, height, 4 ); this.dbImage = this.visImage.clone(); this.setPreferredSize( new Dimension( width, height ) ); this.setSize( new Dimension( width, height ) ); this.requiredSize = new Dimension( width, height ); } /** * Create a new visualisation using an existing image. * @param overlayOn The visualisation on which to overlay */ public VisualisationImpl( final VisualisationImpl overlayOn ) { this.overlaidOn = overlayOn; // Create an image the same size as the overlay vis final MBFImage vi = overlayOn.getVisualisationImage(); this.visImage = new MBFImage( vi.getWidth(), vi.getHeight(), 4 ); this.dbImage = this.visImage.clone(); this.setPreferredSize( new Dimension( vi.getWidth(), vi.getHeight() ) ); this.setSize( new Dimension( vi.getWidth(), vi.getHeight() ) ); this.requiredSize = this.getSize(); // Add this as an overlay on the other vis. This also forces // an update so that we get their visualisation to overlay on overlayOn.addOverlay( this ); this.addComponentListener( this ); } /** * Add an overlay to this visualisation * @param v The visualisation to overlay on this visualisation */ public void addOverlay( final VisualisationImpl v ) { this.overlays.add( v ); v.updateVis( this.visImage ); } /** * Remove the given overlay from this visualisation * @param v The visualisation to remove */ public void removeOverlay( final VisualisationImpl v ) { this.overlays.remove( v ); } /** * Called to update the visualisation. This method can expect the * visImage member to be available and of the correct size. * The method simply needs to draw the visualisation to this {@link MBFImage}. * You should wrap any drawing code in a synchronized block, synchronized on * the visImage - this stops the image being repainted to the screen half way * through drawing. *

* Update is called from the paint() method so should * ideally not force a repaint() as this will call a continuous repaint * loop. */ public abstract void update(); /** * Call to force and update of the visualisation */ @Override public void updateVis() { if( this.visImage == null ) { this.visImage = new MBFImage( (int)this.requiredSize.getWidth(), (int)this.requiredSize.getHeight(), 4 ); this.dbImage = this.visImage.clone(); } // System.out.println( "Updating "+this ); synchronized( this.visImage ) { if( this.allowResize && (this.visImage.getWidth() != this.requiredSize.getWidth() || this.visImage.getHeight() != this.requiredSize.getHeight()) ) { this.visImage = new MBFImage( (int)this.requiredSize.getWidth(), (int)this.requiredSize.getHeight(), 4 ); this.dbImage = this.visImage.clone(); System.out.println( this.requiredSize ); } if( this.clearBeforeDraw ) this.visImage.fill( this.backgroundColour ); if( this.overlayImage != null ) this.visImage.drawImage( this.overlayImage, 0, 0 ); } this.update(); synchronized( this.visImage ) { for( final VisualisationImpl v : this.overlays ) v.updateVis( this.visImage ); final MBFImage t = this.dbImage; this.dbImage = this.visImage; this.visImage = t; } this.repaint(); } /** * Update the visualisation using the given image as the base image * on which to overlay. * @param overlay The overlay */ public void updateVis( final MBFImage overlay ) { if( overlay != null ) this.overlayImage = overlay.clone(); else this.overlayImage = null; this.updateVis(); } /** * Set the data to be visualised. * @param data The data to be visualised */ @Override public void setData( final T data ) { synchronized( data ) { this.data = data; } this.updateVis(); } /** * Returns the image to which the bars will be drawn. * @return The image */ @Override public MBFImage getVisualisationImage() { // The implementation of this appears to return our double // buffered image. That's because at the end of the updateVis() // method we swap the images over, so the last drawn image is // only available in dbImage. (Any drawing that's occuring right // now will be happening on visImage, so it's ok to access this // here.) return this.dbImage.clone(); } /** * {@inheritDoc} * @see javax.swing.JComponent#paint(java.awt.Graphics) */ @Override public void paint( final Graphics g ) { synchronized( this.visImage ) { final BufferedImage bi = ImageUtilities.createBufferedImageForDisplay( this.dbImage ); g.drawImage( bi, 0, 0, null ); } } /** * {@inheritDoc} * @see javax.swing.JComponent#update(java.awt.Graphics) */ @Override public void update( final Graphics g ) { this.updateVis(); this.repaint(); } /** * Show a window containing this visualisation * @param title The title of the window * @return The window that was created */ public JFrame showWindow( final String title ) { final JFrame f = new JFrame( title ); f.getContentPane().setLayout( new GridLayout(1,1) ); f.getContentPane().add( this ); f.setResizable( this.allowResize ); f.pack(); f.setVisible( true ); this.addComponentListener( this ); this.requiredSize = this.getSize(); this.updateVis(); return f; } /** * Whether this visualisation can be resized. * @return TRUE if this visualisation can be resized. */ public boolean isAllowResize() { return this.allowResize; } /** * Set whether this visualisation can be resized. * @param allowResize TRUE to allow the visualisation to be resizable */ public void setAllowResize( final boolean allowResize ) { this.allowResize = allowResize; } /** * Set the required size of the vis * @param d The required size */ @Override public void setRequiredSize( final Dimension d ) { this.requiredSize = d; } /** * Get the current required size of the vis * @return The required size */ public Dimension getRequiredSize() { return this.requiredSize; } /** * Sets whether to clear the image before drawing. Has no effect if * fade drawing is used. * @param tf TRUE to clear the image */ public void setClearBeforeDraw( final boolean tf ) { this.clearBeforeDraw = tf; } @Override public void componentHidden( final ComponentEvent e ) { } @Override public void componentMoved( final ComponentEvent e ) { } @Override public void componentShown( final ComponentEvent e ) { } @Override public void componentResized( final ComponentEvent e ) { if( this.getSize().width == this.visImage.getWidth() && this.getSize().height == this.visImage.getHeight() ) return; this.requiredSize = this.getSize(); if( this.overlaidOn != null ) this.overlaidOn.setSize( this.getSize() ); else this.updateVis(); } /** * {@inheritDoc} * @see org.openimaj.vis.AnimatedVisualisationListener#newVisualisationAvailable(org.openimaj.vis.AnimatedVisualisationProvider) */ @Override public void newVisualisationAvailable( final AnimatedVisualisationProvider avp ) { // avp.updateVis(); this.updateVis(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy