Cinder

  • Main Page
  • Related Pages
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

include/cinder/Arcball.h

Go to the documentation of this file.
00001 /*
00002  Copyright (c) 2010, The Barbarian Group
00003  All rights reserved.
00004 
00005  Redistribution and use in source and binary forms, with or without modification, are permitted provided that
00006  the following conditions are met:
00007 
00008     * Redistributions of source code must retain the above copyright notice, this list of conditions and
00009     the following disclaimer.
00010     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
00011     the following disclaimer in the documentation and/or other materials provided with the distribution.
00012 
00013  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
00014  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00015  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
00016  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
00017  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00018  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00019  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00020  POSSIBILITY OF SUCH DAMAGE.
00021 */
00022 
00023 #pragma once
00024 
00025 #include "cinder/Vector.h"
00026 
00027 namespace cinder {
00028 
00029 class Arcball {
00030  public:
00031     Arcball()
00032     {
00033         setNoConstraintAxis();
00034         mCurrentQuat = mInitialQuat = Quatf( Vec3f::yAxis(), 0 );
00035     }
00036     Arcball( const Vec2i &aScreenSize )
00037         : mWindowSize( aScreenSize )
00038     {   
00039         setCenter( Vec2f( mWindowSize.x / 2.0f, mWindowSize.y / 2.0f ) );
00040         mRadius = std::min( (float)mWindowSize.x / 2, (float)mWindowSize.y / 2 );
00041         setNoConstraintAxis();
00042         mCurrentQuat = mInitialQuat = Quatf( Vec3f::yAxis(), 0 );
00043     }
00044     
00045     void mouseDown( const Vec2i &mousePos )
00046     {
00047         mInitialMousePos = mousePos;
00048         mInitialQuat = mCurrentQuat;
00049     }
00050     
00051     void mouseDrag( const Vec2i &mousePos )
00052     {
00053         Vec3f from = mouseOnSphere( mInitialMousePos );
00054         Vec3f to = mouseOnSphere( mousePos );
00055         if( mUseConstraint ) {
00056             from = constrainToAxis( from, mConstraintAxis );
00057             to = constrainToAxis( to, mConstraintAxis );
00058         }
00059         
00060         Vec3f axis = from.cross( to );
00061         mCurrentQuat = mInitialQuat * Quatf( from.dot( to ), axis.x, axis.y, axis.z );
00062         mCurrentQuat.normalize();
00063     }
00064     
00065     void    resetQuat() { mCurrentQuat = mInitialQuat = Quatf( Vec3f::yAxis(), 0 ); }
00066     Quatf   getQuat() { return mCurrentQuat; }
00067     void    setQuat( const Quatf &quat ) { mCurrentQuat = quat; }
00068     
00069     void    setWindowSize( const Vec2i &aWindowSize ) { mWindowSize = aWindowSize; }
00070     void    setCenter( const Vec2f &aCenter ) { mCenter = aCenter; }
00071     Vec2f   getCenter() const { return mCenter; }
00072     void    setRadius( float aRadius ) { mRadius = aRadius; }
00073     float   getRadius() const { return mRadius; }
00074     void    setConstraintAxis( const Vec3f &aConstraintAxis ) { mConstraintAxis = aConstraintAxis; mUseConstraint = true; }
00075     void    setNoConstraintAxis() { mUseConstraint = false; }
00076     bool    isUsingConstraint() const { return mUseConstraint; }
00077     Vec3f   getConstraintAxis() const { return mConstraintAxis; }
00078     
00079     Vec3f mouseOnSphere( const Vec2i &point ) {
00080         Vec3f result;
00081         
00082         result.x = ( point.x - mCenter.x ) / ( mRadius * 2 );
00083         result.y = ( point.y - mCenter.y ) / ( mRadius * 2 );
00084         result.z = 0.0f;
00085 
00086         float mag = result.lengthSquared();
00087         if( mag > 1.0f ) {
00088             result.normalize();
00089         }
00090         else {
00091             result.z = math<float>::sqrt( 1.0f - mag );
00092             result.normalize();
00093         }
00094 
00095         return result;
00096     }
00097     
00098  private:
00099     // Force sphere point to be perpendicular to axis
00100     Vec3f constrainToAxis( const Vec3f &loose, const Vec3f &axis )
00101     {
00102         float norm;
00103         Vec3f onPlane = loose - axis * axis.dot( loose );
00104         norm = onPlane.lengthSquared();
00105         if( norm > 0.0f ) {
00106             if( onPlane.z < 0.0f )
00107                 onPlane = -onPlane;
00108             return ( onPlane * ( 1.0f / math<float>::sqrt( norm ) ) );
00109         }
00110         
00111         if( axis.dot( Vec3f::zAxis() ) < 0.0001f ) {
00112             onPlane = Vec3f::xAxis();
00113         }
00114         else {
00115             onPlane = Vec3f( -axis.y, axis.x, 0.0f ).normalized();
00116         }
00117         
00118         return onPlane;
00119     }
00120     
00121     Vec2i       mWindowSize;
00122     Vec2i       mInitialMousePos;
00123     Vec2f       mCenter;
00124     Quatf       mCurrentQuat, mInitialQuat;
00125     float       mRadius;
00126     Vec3f       mConstraintAxis;
00127     bool        mUseConstraint;
00128 };
00129 
00130 } // namespace cinder