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 javax.media.opengl.GL;
036import javax.media.opengl.GL2;
037import javax.media.opengl.GLAutoDrawable;
038import javax.media.opengl.fixedfunc.GLMatrixFunc;
039
040import org.openimaj.math.geometry.shape.Rectangle3D;
041
042/**
043 *      Plots rectangles into a 3D space.
044 *
045 *      @author David Dupplaw (dpd@ecs.soton.ac.uk)
046 *  @created 1 Aug 2013
047 *      @version $Author$, $Revision$, $Date$
048 */
049public class Rectangle3DPlotter extends XYZVisualisation3D<Rectangle3D> implements ItemPlotter3D<Rectangle3D>
050{
051        /**
052         *      Where the actual position of the rectangle is relative to the geometry.
053         *
054         *      @author David Dupplaw (dpd@ecs.soton.ac.uk)
055         *  @created 1 Aug 2013
056         *      @version $Author$, $Revision$, $Date$
057         */
058        public static enum RectanglePlotPosition
059        {
060                /** Centre the rectangle on the data point */
061                CENTRAL,
062
063                /** Put the top left of the rectangle on the data point */
064                TOP_LEFT,
065
066                /** Put the bottom left of the rectangle on the data point */
067                BOTTOM_LEFT,
068
069                /** Put the bottom right of the rectangle on the data point */
070                BOTTOM_RIGHT,
071
072                /** Put the top right of the rectangle on the data point */
073                TOP_RIGHT
074        }
075
076        /** The offset for the rectangle position */
077        private final RectanglePlotPosition pos = RectanglePlotPosition.CENTRAL;
078
079        /** Whether to draw a dot at the point (only if centrally drawn) */
080        private final boolean drawDotAtPoint = true;
081
082        /**
083         *      Create a visualisation with the given size
084         *      @param width Width in pixels of the vis
085         *      @param height Height in pixels of the vis
086         */
087        public Rectangle3DPlotter( final int width, final int height )
088        {
089                super( width, height );
090                super.setPlotter( this );
091        }
092
093        /**
094         *      {@inheritDoc}
095         *      @see org.openimaj.vis.general.ItemPlotter3D#renderRestarting()
096         */
097        @Override
098        public void renderRestarting()
099        {
100        }
101
102        /**
103         *      {@inheritDoc}
104         *      @see org.openimaj.vis.general.ItemPlotter3D#plotObject(javax.media.opengl.GLAutoDrawable, org.openimaj.vis.general.XYZVisualisation3D.LocatedObject3D, org.openimaj.vis.general.AxesRenderer3D)
105         */
106        @Override
107        public void plotObject( final GLAutoDrawable drawable, final LocatedObject3D<Rectangle3D> object,
108                        final AxesRenderer3D renderer )
109        {
110                // object.object.x,y,z is where we plot the rectangle.
111                // object.x,y,z is the data point position.
112                final double[] p = renderer.calculatePosition( new double[]
113                                { object.object.x, object.object.y, object.object.z } );
114                final double[] p2 = renderer.calculatePosition( new double[]
115                                { object.x, object.y, object.z } );
116
117                final GL2 gl = drawable.getGL().getGL2();
118
119                gl.glPushMatrix();
120
121                // Translate to the position of the rectangle
122                gl.glMatrixMode( GLMatrixFunc.GL_MODELVIEW );
123                gl.glTranslated( p2[0], p2[1], p2[2] );
124                gl.glRotated( object.object.xRotation, 1, 0, 0 );
125                gl.glRotated( object.object.yRotation, 0, 1, 0 );
126                gl.glRotated( object.object.zRotation, 0, 0, 1 );
127
128                final double[] dims = renderer.scaleDimension( new double[]{object.object.width,object.object.height,0} );
129                final double w = dims[0];
130                final double h = dims[1];
131
132                gl.glBegin( GL.GL_LINE_LOOP );
133                gl.glVertex3d( p2[0]-p[0], p2[1]-p[1], 0 );
134                gl.glVertex3d( p2[0]-p[0]-w, p2[1]-p[1], 0 );
135                gl.glVertex3d( p2[0]-p[0]-w, p2[1]-p[1]-h, 0 );
136                gl.glVertex3d( p2[0]-p[0], p2[1]-p[1]-h, 0 );
137                gl.glEnd();
138
139                gl.glPopMatrix();
140
141                if( this.pos == RectanglePlotPosition.CENTRAL && this.drawDotAtPoint )
142                {
143                        gl.glPushMatrix();
144                        gl.glMatrixMode( GLMatrixFunc.GL_MODELVIEW );
145                        gl.glBegin( GL.GL_POINTS );
146                        gl.glVertex3d( p2[0], p2[1], p2[2] );
147                        gl.glEnd();
148                        gl.glPopMatrix();
149                }
150        }
151
152        @Override
153        public void init( final GLAutoDrawable drawable )
154        {
155                super.init( drawable );
156
157                final float eyeX = 0f, eyeY = 0.1f, eyeZ = 1f;
158                final float lookAtX = 0f, lookAtY = 0f, lookAtZ = 0f;
159                final float upX = 0, upY = 1, upZ = 0;
160                this.glu.gluLookAt( eyeX, eyeY, eyeZ, lookAtX, lookAtY, lookAtZ, upX, upY, upZ );
161
162                // Instantiate the camera mover
163                this.cameraPosition = new RotatingCameraProvider(
164                                eyeX, eyeY, eyeZ,
165                                lookAtX, lookAtY, lookAtZ,
166                                0.0004f, 0.0001f, 0.00001f, 1f, 1f, 1f );
167        }
168
169        /**
170         *      Note that your rectangle may be altered at this point. Pass in a clone
171         *      if you don't want it to get changed.
172         *
173         *      @param rect The rectangle.
174         */
175        public void addRectangle( final Rectangle3D rect )
176        {
177                final double x = rect.x, y = rect.y, z = rect.z;
178                switch( this.pos )
179                {
180                        case CENTRAL:
181                                rect.x -= rect.width/2;
182                                rect.y -= rect.height/2;
183                                break;
184                        case TOP_LEFT:
185                                break;
186                        case TOP_RIGHT:
187                                rect.x -= rect.width;
188                                break;
189                        case BOTTOM_LEFT:
190                                rect.y -= rect.height;
191                                break;
192                        case BOTTOM_RIGHT:
193                                rect.x -= rect.width;
194                                rect.y -= rect.height;
195                                break;
196                }
197
198                super.data.add( new LocatedObject3D<Rectangle3D>( x, y, z, rect ) );
199        }
200
201        /**
202         *
203         *      @param args
204         */
205        public static void main( final String[] args )
206        {
207                final Rectangle3DPlotter rp = new Rectangle3DPlotter( 1000, 800 );
208                rp.getAxesRenderer().setAxesRanges( -1, 1, -1, 1, -1, 1 );
209
210                final int n = 40;
211                for( int i = 0; i < n ; i++ )
212                {
213                        final Rectangle3D r = new Rectangle3D();
214                        r.x = (float)(Math.random()*2-1);
215                        r.y = (float)(Math.random()*2-1);
216                        r.z = (float)(Math.random()*2-1);
217                        r.width = (float)(Math.random()/2);
218                        r.height = r.width;
219                        r.xRotation = Math.random() * 90;
220                        r.yRotation = Math.random() * 90;
221                        r.zRotation = Math.random() * 90;
222
223                        System.out.println( "Rect "+i+" = "+r );
224
225                        rp.addRectangle( r );
226                }
227        }
228}