1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2003 VideoLAN
5 * $Id: bezier.cpp,v 1.2 2004/01/11 17:12:17 asmax Exp $
7 * Authors: Cyril Deguet <asmax@via.ecp.fr>
8 * Olivier Teulière <ipkiss@via.ecp.fr>
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.
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.
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 *****************************************************************************/
29 Bezier::Bezier( intf_thread_t *p_intf, const vector<float> &rAbscissas,
30 const vector<float> &rOrdinates, Flag_t flag )
31 : SkinObject( p_intf )
33 // We expect rAbscissas and rOrdinates to have the same size, of course
34 m_nbCtrlPt = rAbscissas.size();
36 // Copy the control points coordinates
37 m_ptx.assign( rAbscissas.begin(), rAbscissas.end() );
38 m_pty.assign( rOrdinates.begin(), rOrdinates.end() );
40 // Precalculate the factoriels
42 for( int i = 1; i < m_nbCtrlPt; i++ )
44 m_ft.push_back( i * m_ft[i - 1] );
48 int cx, cy, oldx, oldy;
49 m_leftVect.reserve( MAX_BEZIER_POINT + 1 );
50 m_topVect.reserve( MAX_BEZIER_POINT + 1 );
52 // Calculate the first point
53 getPoint( 0, oldx, oldy );
57 // Compute the number of different points
59 for( float j = 1; j <= MAX_BEZIER_POINT; j++ )
61 percentage = j / MAX_BEZIER_POINT;
62 getPoint( percentage, cx, cy );
63 if( ( flag == kCoordsBoth && ( cx != oldx || cy != oldy ) ) ||
64 ( flag == kCoordsX && cx != oldx ) ||
65 ( flag == kCoordsY && cy != oldy ) )
67 m_leftVect.push_back( cx );
68 m_topVect.push_back( cy );
73 m_nbPoints = m_leftVect.size();
77 float Bezier::getNearestPercent( int x, int y ) const
79 int nearest = findNearestPoint( x, y );
80 return (float)nearest / (float)(m_nbPoints - 1);
84 float Bezier::getMinDist( int x, int y ) const
86 // XXX: duplicate code with findNearestPoint
87 int minDist = (m_leftVect[0] - x) * (m_leftVect[0] - x) +
88 (m_topVect[0] - y) * (m_topVect[0] - y);
91 for( int i = 1; i < m_nbPoints; i++ )
93 dist = (m_leftVect[i] - x) * (m_leftVect[i] - x) +
94 (m_topVect[i] - y) * (m_topVect[i] - y);
100 return sqrt( minDist );
104 void Bezier::getPoint( float t, int &x, int &y ) const
106 // See http://astronomy.swin.edu.au/~pbourke/curves/bezier/ for a simple
107 // explanation of the algorithm
111 for( int i = 0; i < m_nbCtrlPt; i++ )
113 coeff = computeCoeff( i, m_nbCtrlPt - 1, t );
114 xPos += m_ptx[i] * coeff;
115 yPos += m_pty[i] * coeff;
118 // float cast to avoid strange truncatures
119 // XXX: not very nice...
120 x = (int)(float)xPos;
121 y = (int)(float)yPos;
125 int Bezier::getWidth() const
128 for( int i = 0; i < m_nbPoints; i++ )
130 if( m_leftVect[i] > width )
132 width = m_leftVect[i];
139 int Bezier::getHeight() const
142 for( int i = 0; i < m_nbPoints; i++ )
144 if( m_topVect[i] > height )
146 height = m_topVect[i];
153 int Bezier::findNearestPoint( int x, int y ) const
155 // XXX: duplicate code with getMinDist
156 // The distance to the first point is taken as the reference
158 int minDist = (m_leftVect[0] - x) * (m_leftVect[0] - x) +
159 (m_topVect[0] - y) * (m_topVect[0] - y);
162 for( int i = 1; i < m_nbPoints; i++ )
164 dist = (m_leftVect[i] - x) * (m_leftVect[i] - x) +
165 (m_topVect[i] - y) * (m_topVect[i] - y);
177 inline float Bezier::computeCoeff( int i, int n, float t ) const
179 return (power( t, i ) * power( 1 - t, (n - i) ) *
180 (m_ft[n] / m_ft[i] / m_ft[n - i]));
184 inline float Bezier::power( float x, int n ) const
187 return x * power( x, n - 1);