bezier.cpp
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:6k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * bezier.cpp
  3.  *****************************************************************************
  4.  * Copyright (C) 2003 VideoLAN
  5.  * $Id: bezier.cpp 7217 2004-04-01 09:07:37Z gbazin $
  6.  *
  7.  * Authors: Cyril Deguet     <asmax@via.ecp.fr>
  8.  *          Olivier Teuli鑢e <ipkiss@via.ecp.fr>
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License as published by
  12.  * the Free Software Foundation; either version 2 of the License, or
  13.  * (at your option) any later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  * GNU General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU General Public License
  21.  * along with this program; if not, write to the Free Software
  22.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  23.  *****************************************************************************/
  24. #include <vlc/vlc.h>
  25. #include "bezier.hpp"
  26. #include <math.h>
  27. #ifndef HAVE_LRINTF
  28. #   define lrintf(a) (int)rint(a)
  29. #endif
  30. Bezier::Bezier( intf_thread_t *p_intf, const vector<float> &rAbscissas,
  31.                 const vector<float> &rOrdinates, Flag_t flag )
  32.     : SkinObject( p_intf )
  33. {
  34.     // Copy the control points coordinates
  35.     m_ptx.assign( rAbscissas.begin(), rAbscissas.end() );
  36.     m_pty.assign( rOrdinates.begin(), rOrdinates.end() );
  37.     // We expect m_ptx and m_pty to have the same size, of course
  38.     m_nbCtrlPt = m_ptx.size();
  39.     // Precalculate the factoriels
  40.     m_ft.push_back( 1 );
  41.     for( int i = 1; i < m_nbCtrlPt; i++ )
  42.     {
  43.         m_ft.push_back( i * m_ft[i - 1] );
  44.     }
  45.     // Calculate the first point
  46.     int oldx, oldy;
  47.     computePoint( 0, oldx, oldy );
  48.     m_leftVect.push_back( oldx );
  49.     m_topVect.push_back( oldy );
  50.     m_percVect.push_back( 0 );
  51.     // Calculate the other points
  52.     float percentage;
  53.     int cx, cy;
  54.     for( float j = 1; j <= MAX_BEZIER_POINT; j++ )
  55.     {
  56.         percentage = j / MAX_BEZIER_POINT;
  57.         computePoint( percentage, cx, cy );
  58.         if( ( flag == kCoordsBoth && ( cx != oldx || cy != oldy ) ) ||
  59.             ( flag == kCoordsX && cx != oldx ) ||
  60.             ( flag == kCoordsY && cy != oldy ) )
  61.         {
  62.             m_percVect.push_back( percentage );
  63.             m_leftVect.push_back( cx );
  64.             m_topVect.push_back( cy );
  65.             oldx = cx;
  66.             oldy = cy;
  67.         }
  68.     }
  69.     m_nbPoints = m_leftVect.size();
  70.     // If we have only one control point, we duplicate it
  71.     // This allows to simplify the algorithms used in the class
  72.     if( m_nbPoints == 1 )
  73.     {
  74.         m_leftVect.push_back( m_leftVect[0] );
  75.         m_topVect.push_back( m_topVect[0] );
  76.         m_percVect.push_back( 1 );
  77.         m_nbPoints = 2;
  78.    }
  79.     // Ensure that the percentage of the last point is always 1
  80.     m_percVect[m_nbPoints - 1] = 1;
  81. }
  82. float Bezier::getNearestPercent( int x, int y ) const
  83. {
  84.     int nearest = findNearestPoint( x, y );
  85.     return m_percVect[nearest];
  86. }
  87. float Bezier::getMinDist( int x, int y ) const
  88. {
  89.     int nearest = findNearestPoint( x, y );
  90.     return sqrt( (m_leftVect[nearest] - x) * (m_leftVect[nearest] - x) +
  91.                  (m_topVect[nearest] - y) * (m_topVect[nearest] - y) );
  92. }
  93. void Bezier::getPoint( float t, int &x, int &y ) const
  94. {
  95.     // Find the precalculated point whose percentage is nearest from t
  96.     int refPoint = 0;
  97.     float minDiff = fabs( m_percVect[0] - t );
  98.     // The percentages are stored in increasing order, so we can stop the loop
  99.     // as soon as 'diff' starts increasing
  100.     float diff;
  101.     while( refPoint < m_nbPoints &&
  102.            (diff = fabs( m_percVect[refPoint] - t )) <= minDiff )
  103.     {
  104.         refPoint++;
  105.         minDiff = diff;
  106.     }
  107.     // The searched point is then (refPoint - 1)
  108.     // We know that refPoint > 0 because we looped at least once
  109.     x = m_leftVect[refPoint - 1];
  110.     y = m_topVect[refPoint - 1];
  111. }
  112. int Bezier::getWidth() const
  113. {
  114.     int width = 0;
  115.     for( int i = 0; i < m_nbPoints; i++ )
  116.     {
  117.         if( m_leftVect[i] > width )
  118.         {
  119.             width = m_leftVect[i];
  120.         }
  121.     }
  122.     return width;
  123. }
  124. int Bezier::getHeight() const
  125. {
  126.     int height = 0;
  127.     for( int i = 0; i < m_nbPoints; i++ )
  128.     {
  129.         if( m_topVect[i] > height )
  130.         {
  131.             height = m_topVect[i];
  132.         }
  133.     }
  134.     return height;
  135. }
  136. int Bezier::findNearestPoint( int x, int y ) const
  137. {
  138.     // The distance to the first point is taken as the reference
  139.     int refPoint = 0;
  140.     int minDist = (m_leftVect[0] - x) * (m_leftVect[0] - x) +
  141.                   (m_topVect[0] - y) * (m_topVect[0] - y);
  142.     int dist;
  143.     for( int i = 1; i < m_nbPoints; i++ )
  144.     {
  145.         dist = (m_leftVect[i] - x) * (m_leftVect[i] - x) +
  146.                (m_topVect[i] - y) * (m_topVect[i] - y);
  147.         if( dist < minDist )
  148.         {
  149.             minDist = dist;
  150.             refPoint = i;
  151.         }
  152.     }
  153.     return refPoint;
  154. }
  155. void Bezier::computePoint( float t, int &x, int &y ) const
  156. {
  157.     // See http://astronomy.swin.edu.au/~pbourke/curves/bezier/ for a simple
  158.     // explanation of the algorithm
  159.     float xPos = 0;
  160.     float yPos = 0;
  161.     float coeff;
  162.     for( int i = 0; i < m_nbCtrlPt; i++ )
  163.     {
  164.         coeff = computeCoeff( i, m_nbCtrlPt - 1, t );
  165.         xPos += m_ptx[i] * coeff;
  166.         yPos += m_pty[i] * coeff;
  167.     }
  168.     x = lrintf(xPos);
  169.     y = lrintf(yPos);
  170. }
  171. inline float Bezier::computeCoeff( int i, int n, float t ) const
  172. {
  173.     return (power( t, i ) * power( 1 - t, (n - i) ) *
  174.         (m_ft[n] / m_ft[i] / m_ft[n - i]));
  175. }
  176. inline float Bezier::power( float x, int n ) const
  177. {
  178.     if( n > 0 )
  179.         return x * power( x, n - 1);
  180.     else
  181.         return 1;
  182. }