001/** 002 * Copyright (c) 2011, The University of Southampton and the individual contributors. 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without modification, 006 * are permitted provided that the following conditions are met: 007 * 008 * * Redistributions of source code must retain the above copyright notice, 009 * this list of conditions and the following disclaimer. 010 * 011 * * Redistributions in binary form must reproduce the above copyright notice, 012 * this list of conditions and the following disclaimer in the documentation 013 * and/or other materials provided with the distribution. 014 * 015 * * Neither the name of the University of Southampton nor the names of its 016 * contributors may be used to endorse or promote products derived from this 017 * software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030/** 031 * 032 */ 033package org.openimaj.vis.general; 034 035import org.openimaj.image.DisplayUtilities; 036import org.openimaj.image.Image; 037import org.openimaj.image.MBFImage; 038import org.openimaj.image.colour.RGBColour; 039import org.openimaj.math.geometry.line.Line2d; 040import org.openimaj.math.geometry.point.Point2d; 041import org.openimaj.math.geometry.point.Point2dImpl; 042import org.openimaj.math.geometry.transforms.TransformUtilities; 043import org.openimaj.vis.DataUnitsTransformer; 044 045import Jama.Matrix; 046 047 048/** 049 * 050 * 051 * @author David Dupplaw (dpd@ecs.soton.ac.uk) 052 * @param <Q> 053 * @created 9 Jul 2013 054 */ 055public class AxisRenderer2D<Q> extends AxisRenderer<Q> 056 implements DataUnitsTransformer<Q,Double,double[]> 057{ 058 /** The image we're drawing to */ 059 private Image<Q,?> image; 060 061 /** Desired size of the axis in pixels */ 062 protected double axisLength = 100; 063 064 /** The data point transform we've calculated */ 065 private Matrix transform; 066 067 /** The axis line we've calculated */ 068 private Line2d axisLine; 069 070 /** Units to pixels scaling */ 071 private double currentScale = 1; 072 073 /** 074 * Default constructor 075 */ 076 public AxisRenderer2D() 077 { 078 } 079 080 /** 081 * Constructor to set the config 082 * @param conf The config 083 */ 084 public AxisRenderer2D( final AxisConfig<Q> conf ) 085 { 086 this.config = conf; 087 } 088 089 @Override 090 public double[] scaleDimension( final Double dimension ) 091 { 092 return new double[] { dimension * this.getCurrentScale() }; 093 } 094 095 @Override 096 public void precalc() 097 { 098 // Create an axis line between the min and max value 099 this.axisLine = new Line2d( (float)this.config.getMinValue(), 0, 100 (float)this.config.getMaxValue(), 0 ); 101 102 // Transform to (0,0) in data units 103 this.transform = TransformUtilities.translateMatrix( -this.config.getMinValue(), 0 ); 104 105 // Scale to pixels 106 this.currentScale = this.axisLength / (this.config.getMaxValue() - this.config.getMinValue()); 107 this.transform = TransformUtilities.scaleMatrix( (float)this.currentScale, 1 ) 108 .times(this.transform); 109 110 // Rotate to the preferred orientation 111 this.transform = TransformUtilities.rotationMatrix( this.config.getOrientation()[0] ) 112 .times(this.transform); 113 114 // Translate to the preferred position 115 this.transform = TransformUtilities.translateMatrix( 116 this.config.getLocation()[0], this.config.getLocation()[1] ) 117 .times( this.transform ); 118 119 // Transform the axis 120 this.axisLine = this.axisLine.transform( this.transform ); 121 } 122 123 /** 124 * {@inheritDoc} 125 * @see org.openimaj.vis.general.AxisRenderer#drawAxis(org.openimaj.vis.general.AxisConfig) 126 */ 127 @Override 128 public void drawAxis( final AxisConfig<Q> config ) 129 { 130 if( this.axisLine == null ) this.precalc( ); 131 132 this.image.drawLine( this.axisLine, 133 (int)config.getRenderingConfig().getThickness(), 134 config.getRenderingConfig().getColour() ); 135 } 136 137 /** 138 * {@inheritDoc} 139 * @see org.openimaj.vis.general.AxisRenderer#drawAxisLabel(org.openimaj.vis.general.AxisConfig) 140 */ 141 @Override 142 public void drawAxisLabel( final AxisConfig<Q> config ) 143 { 144 } 145 146 /** 147 * {@inheritDoc} 148 * @see org.openimaj.vis.general.AxisRenderer#drawMajorTick(double, org.openimaj.vis.general.AxisConfig) 149 */ 150 @Override 151 public void drawMajorTick( final double location, final AxisConfig<Q> config ) 152 { 153 if( this.transform == null ) this.precalc( ); 154 155 final float x = (float)location; 156 final float y = (float)config.getRenderingConfig().getMajorTickLength(); 157 Line2d l = new Line2d( x, -y, x, y ); 158 l = l.transform( this.transform ); 159 this.image.drawLine( l, (int)config.getRenderingConfig().getMajorTickThickness(), 160 config.getRenderingConfig().getMajorTickColour() ); 161 } 162 163 /** 164 * {@inheritDoc} 165 * @see org.openimaj.vis.general.AxisRenderer#drawMajorTickGridline(double, org.openimaj.vis.general.AxisConfig) 166 */ 167 @Override 168 public void drawMajorTickGridline( final double location, final AxisConfig<Q> config ) 169 { 170 if( this.transform == null ) this.precalc( ); 171 172 final float x = (float)location; 173 final float y = this.image.getHeight()*2; 174 Line2d l = new Line2d( x, -y, x, y ); 175 l = l.transform( this.transform ); 176 this.image.drawLine( l, (int)config.getRenderingConfig().getMajorGridThickness(), 177 config.getRenderingConfig().getMajorGridColour() ); 178 } 179 180 /** 181 * {@inheritDoc} 182 * @see org.openimaj.vis.general.AxisRenderer#drawMinorTick(double, org.openimaj.vis.general.AxisConfig) 183 */ 184 @Override 185 public void drawMinorTick( final double location, final AxisConfig<Q> config ) 186 { 187 if( this.transform == null ) this.precalc( ); 188 189 final float x = (float)location; 190 final float y = (float)config.getRenderingConfig().getMinorTickLength(); 191 Line2d l = new Line2d( x, -y, x, y ); 192 l = l.transform( this.transform ); 193 this.image.drawLine( l, (int)config.getRenderingConfig().getMinorTickThickness(), 194 config.getRenderingConfig().getMinorTickColour() ); 195 } 196 197 /** 198 * {@inheritDoc} 199 * @see org.openimaj.vis.general.AxisRenderer#drawMinorTickGridline(double, org.openimaj.vis.general.AxisConfig) 200 */ 201 @Override 202 public void drawMinorTickGridline( final double location, final AxisConfig<Q> config ) 203 { 204 if( this.transform == null ) this.precalc( ); 205 206 final float x = (float)location; 207 final float y = this.image.getHeight()*2; 208 Line2d l = new Line2d( x, -y, x, y ); 209 l = l.transform( this.transform ); 210 this.image.drawLine( l, (int)config.getRenderingConfig().getMinorGridThickness(), 211 config.getRenderingConfig().getMinorGridColour() ); 212 } 213 214 /** 215 * @return the axisLength 216 */ 217 public double getAxisLength() 218 { 219 return this.axisLength; 220 } 221 222 /** 223 * @param axisLength the axisLength to set 224 */ 225 public void setAxisLength( final double axisLength ) 226 { 227 this.axisLength = axisLength; 228 this.precalc(); 229 } 230 231 /** 232 * {@inheritDoc} 233 * @see org.openimaj.vis.DataUnitsTransformer#calculatePosition(java.lang.Object) 234 */ 235 @Override 236 public double[] calculatePosition( final Double units ) 237 { 238 if( this.transform == null ) this.precalc(); 239 240 final Point2d p = new Point2dImpl( units.floatValue(), 0f ); 241 final Point2d p2 = p.transform( this.transform ); 242 return new double[] {p2.getX(), p2.getY()}; 243 } 244 245 /** 246 * {@inheritDoc} 247 * @see org.openimaj.vis.DataUnitsTransformer#calculateUnitsAt(java.lang.Object) 248 */ 249 @Override 250 public Double calculateUnitsAt( final double[] position ) 251 { 252 if( this.transform == null ) this.precalc( ); 253 254 final Point2d p = new Point2dImpl( (float)position[0], (float)position[1] ); 255 final Point2d p2 = p.transform( this.transform.inverse() ); 256 return new Double(p2.getX()); 257 } 258 259 /** 260 * @return the image 261 */ 262 public Image<Q, ?> getImage() 263 { 264 return this.image; 265 } 266 267 /** 268 * @param image the image to set 269 */ 270 public void setImage( final Image<Q, ?> image ) 271 { 272 this.image = image; 273 } 274 275 /** 276 * @return the currentScale 277 */ 278 public double getCurrentScale() 279 { 280 return this.currentScale; 281 } 282 283 /** 284 * @return the config 285 */ 286 @Override 287 public AxisConfig<Q> getConfig() 288 { 289 return this.config; 290 } 291 292 /** 293 * @param config the config to set 294 */ 295 @Override 296 public void setConfig( final AxisConfig<Q> config ) 297 { 298 this.config = config; 299 } 300 301 /** 302 * Simple test 303 * @param args command-line args (not used) 304 */ 305 public static void main( final String[] args ) 306 { 307 // Create the image to draw into 308 final MBFImage img = new MBFImage( 400, 400, 3 ); 309 310 // Create the configuration for our axis 311 final AxisConfig<Float[]> conf = new AxisConfig<Float[]>(); 312 conf.setLocation( new double[]{ 20, 200 } ); 313 conf.setOrientation( new double[] {0/(360/(2*Math.PI))} ); 314 conf.setMaxValue( 10 ); 315 conf.setMinValue( 5 ); 316 conf.getRenderingConfig().setMajorTickSpacing( 1 ); 317 conf.getRenderingConfig().setMinorTickSpacing( 0.5d ); 318 conf.getRenderingConfig().setColour( RGBColour.WHITE ); 319 conf.getRenderingConfig().setMajorTickColour( RGBColour.WHITE ); 320 conf.getRenderingConfig().setMinorTickColour( RGBColour.WHITE ); 321 conf.getRenderingConfig().setMinorGridColour( RGBColour.GRAY ); 322 conf.getRenderingConfig().setMajorGridColour( RGBColour.GRAY ); 323 conf.getRenderingConfig().setDrawMajorGrid( true ); 324 conf.getRenderingConfig().setDrawMinorGrid( true ); 325 326 // Create the axis renderer for the image 327 final AxisRenderer2D<Float[]> r = new AxisRenderer2D<Float[]>( conf ); 328 r.setAxisLength( 360 ); 329 r.setImage( img ); 330 331 r.renderAxis(); 332 333 DisplayUtilities.display( img ); 334 } 335}