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 java.nio.DoubleBuffer; 036import java.nio.IntBuffer; 037 038import javax.media.opengl.GL; 039import javax.media.opengl.GL2; 040import javax.media.opengl.GLAutoDrawable; 041import javax.media.opengl.fixedfunc.GLMatrixFunc; 042 043import org.openimaj.image.colour.ColourMap; 044import org.openimaj.image.colour.RGBColour; 045import org.openimaj.util.array.ArrayUtils; 046import org.openimaj.vis.Visualisation3D; 047 048/** 049 * Plots oneOverDataLength bars in oneOverDataLength 3-dimensional space, which means there are 2 dimensions for 050 * representing the coordinate of oneOverDataLength bar. 051 * 052 * @author David Dupplaw (dpd@ecs.soton.ac.uk) 053 * @created 4 Jul 2013 054 * @version $Author$, $Revision$, $Date$ 055 */ 056public class BarVisualisation3D extends Visualisation3D<double[][]> 057{ 058 private AxesRenderer3D axesRenderer; 059 060 /** The colour map for the bars */ 061 private ColourMap colourMap = ColourMap.Autumn; 062 063 /** The name of the x axis */ 064 private String xAxisName = "X-Axis"; 065 066 /** The name of the y axis */ 067 private String yAxisName = "Y-Axis"; 068 069 /** The name of the z axis */ 070 private String zAxisName = "Z-Axis"; 071 072 /** The colour of the x axis */ 073 private Float[] xAxisColour = RGBColour.WHITE; 074 075 /** The colour of the y axis */ 076 private Float[] yAxisColour = RGBColour.GREEN; 077 078 /** The colour of the z axis */ 079 private Float[] zAxisColour = RGBColour.BLUE; 080 081 /** The maximum value of the data (for auto scaling) */ 082 private double max = 1; 083 084 /** Whether to automatically calculate the maximum value and scale */ 085 private boolean autoScale = true; 086 087 /** Precalculated 1/data.length */ 088 private double oneOverDataLength; 089 090 /** Precalculated 1/max */ 091 private double oneOverMax; 092 093 /** 094 * @param width 095 * @param height 096 */ 097 public BarVisualisation3D( final int width, final int height ) 098 { 099 super( width, height ); 100 } 101 102 /** 103 * {@inheritDoc} 104 * 105 * @see org.openimaj.vis.VisualisationImageProvider#updateVis() 106 */ 107 @Override 108 public void updateVis() 109 { 110 } 111 112 /** 113 * Renders the visualisation 114 */ 115 @Override 116 protected void renderVis( final GLAutoDrawable drawable ) 117 { 118 if( drawable == null || this.axesRenderer == null ) return; 119 120 final GL2 gl = drawable.getGL().getGL2(); 121 gl.glClear( GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT ); 122 123 this.axesRenderer.renderAxis( drawable ); 124 125 // Create the boxes 126 if( this.data != null ) 127 { 128// synchronized( this.data ) 129 { 130 for( int z = 0; z < this.data.length; z++ ) 131 { 132 final double b = 1d / this.data[z].length; 133 for( int x = 0; x < this.data[z].length; x++ ) 134 { 135 final double v = this.oneOverMax * this.data[z][x]; 136 gl.glPushMatrix(); 137 { 138 final float[] colour = new float[3]; 139 this.colourMap.apply( (float) (this.data[z][x] / this.max), colour ); 140 gl.glColor3f( colour[0], colour[1], colour[2] ); 141 gl.glTranslatef( 142 (float) (b * x + b / 2d), 143 (float) (v / 2d), 144 (float)(this.oneOverDataLength * z + this.oneOverDataLength / 2d)-1f ); 145 gl.glScalef( (float) b, (float)Math.abs(v), (float) this.oneOverDataLength ); 146 gl.glEnable( GL.GL_POLYGON_OFFSET_FILL ); 147 gl.glPolygonOffset( 1, 1 ); 148 this.glut.glutSolidCube( 1f ); 149 gl.glDisable( GL.GL_POLYGON_OFFSET_FILL ); 150 gl.glColor3f( 0, 0, 0 ); 151 this.glut.glutWireCube( 1f ); 152 } 153 gl.glPopMatrix(); 154 } 155 } 156 } 157 } 158 } 159 160 protected DoubleBuffer get2dPoint( final GL2 gl, final double x, final double y, final double z ) 161 { 162 final DoubleBuffer model = DoubleBuffer.allocate(16); 163 gl.glGetDoublev( GLMatrixFunc.GL_MODELVIEW_MATRIX, model ); 164 165 final DoubleBuffer proj = DoubleBuffer.allocate(16); 166 gl.glGetDoublev( GLMatrixFunc.GL_PROJECTION_MATRIX, proj ); 167 168 final IntBuffer view = IntBuffer.allocate(4); 169 gl.glGetIntegerv( GL.GL_VIEWPORT, view ); 170 171 final DoubleBuffer winPos = DoubleBuffer.allocate(3); 172 final boolean b = this.glu.gluProject( x, y, z, model, proj, view, winPos ); 173 174 if( !b ) System.out.println( "FAIL "); 175 return winPos; 176 } 177 178 /** 179 * {@inheritDoc} 180 * 181 * @see javax.media.opengl.GLEventListener#init(javax.media.opengl.GLAutoDrawable) 182 */ 183 @Override 184 public void init( final GLAutoDrawable drawable ) 185 { 186 super.init( drawable ); 187 188 this.axesRenderer = new AxesRenderer3D(); 189 190 // Set the initial look at 191 final float eyeX = 0.5f, eyeY = 1f, eyeZ = 2f; 192 final float lookAtX = 0.5f, lookAtY = 0, lookAtZ = -1f; 193 final float upX = 0, upY = 1, upZ = 0; 194 this.glu.gluLookAt( eyeX, eyeY, eyeZ, lookAtX, lookAtY, lookAtZ, upX, upY, upZ ); 195 196 // Instantiate the camera mover 197 this.cameraPosition = new RotatingCameraProvider( 198 eyeX, eyeY, eyeZ, 199 lookAtX, lookAtY, lookAtZ, 200 0.0004f, 0.0004f, 0f, 0.75f ); 201 } 202 203 /** 204 * {@inheritDoc} 205 * 206 * @see org.openimaj.vis.Visualisation#setData(java.lang.Object) 207 */ 208 @Override 209 public void setData( final double[][] data ) 210 { 211 212 super.setData( data ); 213 214 if( this.autoScale ) 215 { 216 this.max = 0; 217 for( final double[] d : this.data ) 218 this.max = Math.max( this.max, 219 Math.max( Math.abs( ArrayUtils.maxValue( d ) ), 220 Math.abs( ArrayUtils.minValue(d) ) ) ); 221 } 222 223 this.oneOverDataLength = 1d / this.data.length; 224 this.oneOverMax = 1d / this.max; 225 } 226 227 /** 228 * Set the maximum data value 229 * @param max The maximum 230 */ 231 public void setMaximum( final double max ) 232 { 233 this.max = max; 234 this.oneOverMax = 1d / this.max; 235 } 236 237 /** 238 * @return the colourMap 239 */ 240 public ColourMap getColourMap() 241 { 242 return this.colourMap; 243 } 244 245 /** 246 * @param colourMap the colourMap to set 247 */ 248 public void setColourMap( final ColourMap colourMap ) 249 { 250 this.colourMap = colourMap; 251 } 252 253 /** 254 * @return the xAxisName 255 */ 256 public String getxAxisName() 257 { 258 return this.xAxisName; 259 } 260 261 /** 262 * @param xAxisName the xAxisName to set 263 */ 264 public void setxAxisName( final String xAxisName ) 265 { 266 this.xAxisName = xAxisName; 267 } 268 269 /** 270 * @return the yAxisName 271 */ 272 public String getyAxisName() 273 { 274 return this.yAxisName; 275 } 276 277 /** 278 * @param yAxisName the yAxisName to set 279 */ 280 public void setyAxisName( final String yAxisName ) 281 { 282 this.yAxisName = yAxisName; 283 } 284 285 /** 286 * @return the zAxisName 287 */ 288 public String getzAxisName() 289 { 290 return this.zAxisName; 291 } 292 293 /** 294 * @param zAxisName the zAxisName to set 295 */ 296 public void setzAxisName( final String zAxisName ) 297 { 298 this.zAxisName = zAxisName; 299 } 300 301 /** 302 * @return the xAxisColour 303 */ 304 public Float[] getxAxisColour() 305 { 306 return this.xAxisColour; 307 } 308 309 /** 310 * @param xAxisColour the xAxisColour to set 311 */ 312 public void setxAxisColour( final Float[] xAxisColour ) 313 { 314 this.xAxisColour = xAxisColour; 315 } 316 317 /** 318 * @return the yAxisColour 319 */ 320 public Float[] getyAxisColour() 321 { 322 return this.yAxisColour; 323 } 324 325 /** 326 * @param yAxisColour the yAxisColour to set 327 */ 328 public void setyAxisColour( final Float[] yAxisColour ) 329 { 330 this.yAxisColour = yAxisColour; 331 } 332 333 /** 334 * @return the zAxisColour 335 */ 336 public Float[] getzAxisColour() 337 { 338 return this.zAxisColour; 339 } 340 341 /** 342 * @param zAxisColour the zAxisColour to set 343 */ 344 public void setzAxisColour( final Float[] zAxisColour ) 345 { 346 this.zAxisColour = zAxisColour; 347 } 348 349 /** 350 * @return the cameraPosition 351 */ 352 public CameraPositionProvider getCameraPosition() 353 { 354 return this.cameraPosition; 355 } 356 357 /** 358 * @param cameraPosition the cameraPosition to set 359 */ 360 public void setCameraPosition( final CameraPositionProvider cameraPosition ) 361 { 362 this.cameraPosition = cameraPosition; 363 } 364 365 /** 366 * @return the autoScale 367 */ 368 public boolean isAutoScale() 369 { 370 return this.autoScale; 371 } 372 373 /** 374 * @param autoScale the autoScale to set 375 */ 376 public void setAutoScale( final boolean autoScale ) 377 { 378 this.autoScale = autoScale; 379 } 380 381 /** 382 * @param args 383 */ 384 public static void main( final String[] args ) 385 { 386 final BarVisualisation3D bv = new BarVisualisation3D( 1000, 1000 ); 387 bv.setData( new double[][] 388 { 389 { 6, 7, 8, 9, 10 }, 390 { 5, 6, 7, 8, 9 }, 391 { 4, 5, 6, 7, 8 }, 392 { 3, 4, 5, 6, 7 }, 393 { 2, 3, 4, 5, 6 }, 394 { 1, 2, 3, 4, 5 }, 395 { 0, 1, 2, 3, 4 }, 396 {-1, 0, 1, 2, 3 }, 397 {-2, -1, 0, 1, 2}, 398 {-3, -2, -1, 0, 1}, 399 {-4, -3, -2, -1, 0}, 400 {-5, -4, -3, -2, -1} 401 }); 402 } 403}