bezier.cpp
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:6k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * bezier.cpp
  3.  *****************************************************************************
  4.  * Copyright (C) 2003 the VideoLAN team
  5.  * $Id: defccf05aeb54d3ba28398da15aa559ba8b96327 $
  6.  *
  7.  * Authors: Cyril Deguet     <asmax@via.ecp.fr>
  8.  *          Olivier Teulière <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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  23.  *****************************************************************************/
  24. #ifdef HAVE_CONFIG_H
  25. # include "config.h"
  26. #endif
  27. #include <vlc_common.h>
  28. #include "bezier.hpp"
  29. #include <math.h>
  30. // XXX should be in VLC core
  31. #ifndef HAVE_LRINTF
  32. #   ifdef HAVE_LRINT
  33. #       define lrintf( x ) (int)rint( x )
  34. #   elif defined WIN32
  35.         __inline long int lrintf( float x )
  36.         {
  37.             int i;
  38.             _asm fld x __asm fistp i
  39.             return i;
  40.         }
  41. #   endif
  42. #endif
  43. Bezier::Bezier( intf_thread_t *p_intf, const vector<float> &rAbscissas,
  44.                 const vector<float> &rOrdinates, Flag_t flag )
  45.     : SkinObject( p_intf )
  46. {
  47.     // Copy the control points coordinates
  48.     m_ptx.assign( rAbscissas.begin(), rAbscissas.end() );
  49.     m_pty.assign( rOrdinates.begin(), rOrdinates.end() );
  50.     // We expect m_ptx and m_pty to have the same size, of course
  51.     m_nbCtrlPt = m_ptx.size();
  52.     // Precalculate the factoriels
  53.     m_ft.push_back( 1 );
  54.     for( int i = 1; i < m_nbCtrlPt; i++ )
  55.     {
  56.         m_ft.push_back( i * m_ft[i - 1] );
  57.     }
  58.     // Calculate the first point
  59.     int oldx, oldy;
  60.     computePoint( 0, oldx, oldy );
  61.     m_leftVect.push_back( oldx );
  62.     m_topVect.push_back( oldy );
  63.     m_percVect.push_back( 0 );
  64.     // Calculate the other points
  65.     float percentage;
  66.     int cx, cy;
  67.     for( float j = 1; j <= MAX_BEZIER_POINT; j++ )
  68.     {
  69.         percentage = j / MAX_BEZIER_POINT;
  70.         computePoint( percentage, cx, cy );
  71.         if( ( flag == kCoordsBoth && ( cx != oldx || cy != oldy ) ) ||
  72.             ( flag == kCoordsX && cx != oldx ) ||
  73.             ( flag == kCoordsY && cy != oldy ) )
  74.         {
  75.             m_percVect.push_back( percentage );
  76.             m_leftVect.push_back( cx );
  77.             m_topVect.push_back( cy );
  78.             oldx = cx;
  79.             oldy = cy;
  80.         }
  81.     }
  82.     m_nbPoints = m_leftVect.size();
  83.     // If we have only one control point, we duplicate it
  84.     // This allows to simplify the algorithms used in the class
  85.     if( m_nbPoints == 1 )
  86.     {
  87.         m_leftVect.push_back( m_leftVect[0] );
  88.         m_topVect.push_back( m_topVect[0] );
  89.         m_percVect.push_back( 1 );
  90.         m_nbPoints = 2;
  91.    }
  92.     // Ensure that the percentage of the last point is always 1
  93.     m_percVect[m_nbPoints - 1] = 1;
  94. }
  95. float Bezier::getNearestPercent( int x, int y ) const
  96. {
  97.     int nearest = findNearestPoint( x, y );
  98.     return m_percVect[nearest];
  99. }
  100. float Bezier::getMinDist( int x, int y, float xScale, float yScale ) const
  101. {
  102.     int nearest = findNearestPoint( x, y );
  103.     double xDist = xScale * (m_leftVect[nearest] - x);
  104.     double yDist = yScale * (m_topVect[nearest] - y);
  105.     return sqrt( xDist * xDist + yDist * yDist );
  106. }
  107. void Bezier::getPoint( float t, int &x, int &y ) const
  108. {
  109.     // Find the precalculated point whose percentage is nearest from t
  110.     int refPoint = 0;
  111.     float minDiff = fabs( m_percVect[0] - t );
  112.     // The percentages are stored in increasing order, so we can stop the loop
  113.     // as soon as 'diff' starts increasing
  114.     float diff;
  115.     while( refPoint < m_nbPoints &&
  116.            (diff = fabs( m_percVect[refPoint] - t )) <= minDiff )
  117.     {
  118.         refPoint++;
  119.         minDiff = diff;
  120.     }
  121.     // The searched point is then (refPoint - 1)
  122.     // We know that refPoint > 0 because we looped at least once
  123.     x = m_leftVect[refPoint - 1];
  124.     y = m_topVect[refPoint - 1];
  125. }
  126. int Bezier::getWidth() const
  127. {
  128.     int width = 0;
  129.     for( int i = 0; i < m_nbPoints; i++ )
  130.     {
  131.         if( m_leftVect[i] >= width )
  132.         {
  133.             width = m_leftVect[i] + 1;
  134.         }
  135.     }
  136.     return width;
  137. }
  138. int Bezier::getHeight() const
  139. {
  140.     int height = 0;
  141.     for( int i = 0; i < m_nbPoints; i++ )
  142.     {
  143.         if( m_topVect[i] >= height )
  144.         {
  145.             height = m_topVect[i] + 1;
  146.         }
  147.     }
  148.     return height;
  149. }
  150. int Bezier::findNearestPoint( int x, int y ) const
  151. {
  152.     // The distance to the first point is taken as the reference
  153.     int refPoint = 0;
  154.     int minDist = (m_leftVect[0] - x) * (m_leftVect[0] - x) +
  155.                   (m_topVect[0] - y) * (m_topVect[0] - y);
  156.     int dist;
  157.     for( int i = 1; i < m_nbPoints; i++ )
  158.     {
  159.         dist = (m_leftVect[i] - x) * (m_leftVect[i] - x) +
  160.                (m_topVect[i] - y) * (m_topVect[i] - y);
  161.         if( dist < minDist )
  162.         {
  163.             minDist = dist;
  164.             refPoint = i;
  165.         }
  166.     }
  167.     return refPoint;
  168. }
  169. void Bezier::computePoint( float t, int &x, int &y ) const
  170. {
  171.     // See http://astronomy.swin.edu.au/~pbourke/curves/bezier/ for a simple
  172.     // explanation of the algorithm
  173.     float xPos = 0;
  174.     float yPos = 0;
  175.     float coeff;
  176.     for( int i = 0; i < m_nbCtrlPt; i++ )
  177.     {
  178.         coeff = computeCoeff( i, m_nbCtrlPt - 1, t );
  179.         xPos += m_ptx[i] * coeff;
  180.         yPos += m_pty[i] * coeff;
  181.     }
  182.     x = lrintf(xPos);
  183.     y = lrintf(yPos);
  184. }
  185. inline float Bezier::computeCoeff( int i, int n, float t ) const
  186. {
  187.     return (power( t, i ) * power( 1 - t, (n - i) ) *
  188.         (m_ft[n] / m_ft[i] / m_ft[n - i]));
  189. }
  190. inline float Bezier::power( float x, int n ) const
  191. {
  192.     if( n > 0 )
  193.         return x * power( x, n - 1);
  194.     else
  195.         return 1;
  196. }