Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

bezier.cpp

00001 /*****************************************************************************
00002  * bezier.cpp
00003  *****************************************************************************
00004  * Copyright (C) 2003 the VideoLAN team
00005  * $Id: bezier.cpp 11786 2005-07-18 23:57:41Z asmax $
00006  *
00007  * Authors: Cyril Deguet     <[email protected]>
00008  *          Olivier Teulière <[email protected]>
00009  *
00010  * This program is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00023  *****************************************************************************/
00024 
00025 #include <vlc/vlc.h>
00026 #include "bezier.hpp"
00027 #include <math.h>
00028 
00029 // XXX should be in VLC core
00030 #ifndef HAVE_LRINTF
00031 #   ifdef HAVE_LRINT
00032 #       define lrintf( x ) (int)rint( x )
00033 #   elif defined WIN32
00034             __inline long int lrintf( float x )
00035             {
00036             int i;
00037             _asm fld x __asm fistp i
00038                     return i;
00039         }
00040 #   endif
00041 #endif
00042 
00043 Bezier::Bezier( intf_thread_t *p_intf, const vector<float> &rAbscissas,
00044                 const vector<float> &rOrdinates, Flag_t flag )
00045     : SkinObject( p_intf )
00046 {
00047     // Copy the control points coordinates
00048     m_ptx.assign( rAbscissas.begin(), rAbscissas.end() );
00049     m_pty.assign( rOrdinates.begin(), rOrdinates.end() );
00050 
00051     // We expect m_ptx and m_pty to have the same size, of course
00052     m_nbCtrlPt = m_ptx.size();
00053 
00054     // Precalculate the factoriels
00055     m_ft.push_back( 1 );
00056     for( int i = 1; i < m_nbCtrlPt; i++ )
00057     {
00058         m_ft.push_back( i * m_ft[i - 1] );
00059     }
00060 
00061     // Calculate the first point
00062     int oldx, oldy;
00063     computePoint( 0, oldx, oldy );
00064     m_leftVect.push_back( oldx );
00065     m_topVect.push_back( oldy );
00066     m_percVect.push_back( 0 );
00067 
00068     // Calculate the other points
00069     float percentage;
00070     int cx, cy;
00071     for( float j = 1; j <= MAX_BEZIER_POINT; j++ )
00072     {
00073         percentage = j / MAX_BEZIER_POINT;
00074         computePoint( percentage, cx, cy );
00075         if( ( flag == kCoordsBoth && ( cx != oldx || cy != oldy ) ) ||
00076             ( flag == kCoordsX && cx != oldx ) ||
00077             ( flag == kCoordsY && cy != oldy ) )
00078         {
00079             m_percVect.push_back( percentage );
00080             m_leftVect.push_back( cx );
00081             m_topVect.push_back( cy );
00082             oldx = cx;
00083             oldy = cy;
00084         }
00085     }
00086     m_nbPoints = m_leftVect.size();
00087 
00088     // If we have only one control point, we duplicate it
00089     // This allows to simplify the algorithms used in the class
00090     if( m_nbPoints == 1 )
00091     {
00092         m_leftVect.push_back( m_leftVect[0] );
00093         m_topVect.push_back( m_topVect[0] );
00094         m_percVect.push_back( 1 );
00095         m_nbPoints = 2;
00096    }
00097 
00098     // Ensure that the percentage of the last point is always 1
00099     m_percVect[m_nbPoints - 1] = 1;
00100 }
00101 
00102 
00103 float Bezier::getNearestPercent( int x, int y ) const
00104 {
00105     int nearest = findNearestPoint( x, y );
00106     return m_percVect[nearest];
00107 }
00108 
00109 
00110 float Bezier::getMinDist( int x, int y ) const
00111 {
00112     int nearest = findNearestPoint( x, y );
00113     return sqrt( (double)((m_leftVect[nearest] - x) * (m_leftVect[nearest] - x) +
00114                  (m_topVect[nearest] - y) * (m_topVect[nearest] - y)) );
00115 }
00116 
00117 
00118 void Bezier::getPoint( float t, int &x, int &y ) const
00119 {
00120     // Find the precalculated point whose percentage is nearest from t
00121     int refPoint = 0;
00122     float minDiff = fabs( m_percVect[0] - t );
00123 
00124     // The percentages are stored in increasing order, so we can stop the loop
00125     // as soon as 'diff' starts increasing
00126     float diff;
00127     while( refPoint < m_nbPoints &&
00128            (diff = fabs( m_percVect[refPoint] - t )) <= minDiff )
00129     {
00130         refPoint++;
00131         minDiff = diff;
00132     }
00133 
00134     // The searched point is then (refPoint - 1)
00135     // We know that refPoint > 0 because we looped at least once
00136     x = m_leftVect[refPoint - 1];
00137     y = m_topVect[refPoint - 1];
00138 }
00139 
00140 
00141 int Bezier::getWidth() const
00142 {
00143     int width = 0;
00144     for( int i = 0; i < m_nbPoints; i++ )
00145     {
00146         if( m_leftVect[i] >= width )
00147         {
00148             width = m_leftVect[i] + 1;
00149         }
00150     }
00151     return width;
00152 }
00153 
00154 
00155 int Bezier::getHeight() const
00156 {
00157     int height = 0;
00158     for( int i = 0; i < m_nbPoints; i++ )
00159     {
00160         if( m_topVect[i] >= height )
00161         {
00162             height = m_topVect[i] + 1;
00163         }
00164     }
00165     return height;
00166 }
00167 
00168 
00169 int Bezier::findNearestPoint( int x, int y ) const
00170 {
00171     // The distance to the first point is taken as the reference
00172     int refPoint = 0;
00173     int minDist = (m_leftVect[0] - x) * (m_leftVect[0] - x) +
00174                   (m_topVect[0] - y) * (m_topVect[0] - y);
00175 
00176     int dist;
00177     for( int i = 1; i < m_nbPoints; i++ )
00178     {
00179         dist = (m_leftVect[i] - x) * (m_leftVect[i] - x) +
00180                (m_topVect[i] - y) * (m_topVect[i] - y);
00181         if( dist < minDist )
00182         {
00183             minDist = dist;
00184             refPoint = i;
00185         }
00186     }
00187 
00188     return refPoint;
00189 }
00190 
00191 
00192 void Bezier::computePoint( float t, int &x, int &y ) const
00193 {
00194     // See http://astronomy.swin.edu.au/~pbourke/curves/bezier/ for a simple
00195     // explanation of the algorithm
00196     float xPos = 0;
00197     float yPos = 0;
00198     float coeff;
00199     for( int i = 0; i < m_nbCtrlPt; i++ )
00200     {
00201         coeff = computeCoeff( i, m_nbCtrlPt - 1, t );
00202         xPos += m_ptx[i] * coeff;
00203         yPos += m_pty[i] * coeff;
00204     }
00205 
00206     x = lrintf(xPos);
00207     y = lrintf(yPos);
00208 }
00209 
00210 
00211 inline float Bezier::computeCoeff( int i, int n, float t ) const
00212 {
00213     return (power( t, i ) * power( 1 - t, (n - i) ) *
00214         (m_ft[n] / m_ft[i] / m_ft[n - i]));
00215 }
00216 
00217 
00218 inline float Bezier::power( float x, int n ) const
00219 {
00220     if( n > 0 )
00221         return x * power( x, n - 1);
00222     else
00223         return 1;
00224 }

Generated on Tue Dec 20 10:14:43 2005 for vlc-0.8.4a by  doxygen 1.4.2