# 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