1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2003 the VideoLAN team
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
29 // XXX should be in VLC core
32 # define lrintf( x ) (int)rint( x )
34 __inline long int lrintf( float x )
37 _asm fld x __asm fistp i
43 Bezier::Bezier( intf_thread_t *p_intf, const vector<float> &rAbscissas,
44 const vector<float> &rOrdinates, Flag_t flag )
45 : SkinObject( p_intf )
47 // Copy the control points coordinates
48 m_ptx.assign( rAbscissas.begin(), rAbscissas.end() );
49 m_pty.assign( rOrdinates.begin(), rOrdinates.end() );
51 // We expect m_ptx and m_pty to have the same size, of course
52 m_nbCtrlPt = m_ptx.size();
54 // Precalculate the factoriels
56 for( int i = 1; i < m_nbCtrlPt; i++ )
58 m_ft.push_back( i * m_ft[i - 1] );
61 // Calculate the first point
63 computePoint( 0, oldx, oldy );
64 m_leftVect.push_back( oldx );
65 m_topVect.push_back( oldy );
66 m_percVect.push_back( 0 );
68 // Calculate the other points
71 for( float j = 1; j <= MAX_BEZIER_POINT; j++ )
73 percentage = j / MAX_BEZIER_POINT;
74 computePoint( percentage, cx, cy );
75 if( ( flag == kCoordsBoth && ( cx != oldx || cy != oldy ) ) ||
76 ( flag == kCoordsX && cx != oldx ) ||
77 ( flag == kCoordsY && cy != oldy ) )
79 m_percVect.push_back( percentage );
80 m_leftVect.push_back( cx );
81 m_topVect.push_back( cy );
86 m_nbPoints = m_leftVect.size();
88 // If we have only one control point, we duplicate it
89 // This allows to simplify the algorithms used in the class
92 m_leftVect.push_back( m_leftVect[0] );
93 m_topVect.push_back( m_topVect[0] );
94 m_percVect.push_back( 1 );
98 // Ensure that the percentage of the last point is always 1
99 m_percVect[m_nbPoints - 1] = 1;
103 float Bezier::getNearestPercent( int x, int y ) const
105 int nearest = findNearestPoint( x, y );
106 return m_percVect[nearest];
110 float Bezier::getMinDist( int x, int y, float xScale, float yScale ) const
112 int nearest = findNearestPoint( x, y );
113 double xDist = xScale * (m_leftVect[nearest] - x);
114 double yDist = yScale * (m_topVect[nearest] - y);
115 return sqrt( xDist * xDist + yDist * yDist );
119 void Bezier::getPoint( float t, int &x, int &y ) const
121 // Find the precalculated point whose percentage is nearest from t
123 float minDiff = fabs( m_percVect[0] - t );
125 // The percentages are stored in increasing order, so we can stop the loop
126 // as soon as 'diff' starts increasing
128 while( refPoint < m_nbPoints &&
129 (diff = fabs( m_percVect[refPoint] - t )) <= minDiff )
135 // The searched point is then (refPoint - 1)
136 // We know that refPoint > 0 because we looped at least once
137 x = m_leftVect[refPoint - 1];
138 y = m_topVect[refPoint - 1];
142 int Bezier::getWidth() const
145 for( int i = 0; i < m_nbPoints; i++ )
147 if( m_leftVect[i] >= width )
149 width = m_leftVect[i] + 1;
156 int Bezier::getHeight() const
159 for( int i = 0; i < m_nbPoints; i++ )
161 if( m_topVect[i] >= height )
163 height = m_topVect[i] + 1;
170 int Bezier::findNearestPoint( int x, int y ) const
172 // The distance to the first point is taken as the reference
174 int minDist = (m_leftVect[0] - x) * (m_leftVect[0] - x) +
175 (m_topVect[0] - y) * (m_topVect[0] - y);
178 for( int i = 1; i < m_nbPoints; i++ )
180 dist = (m_leftVect[i] - x) * (m_leftVect[i] - x) +
181 (m_topVect[i] - y) * (m_topVect[i] - y);
193 void Bezier::computePoint( float t, int &x, int &y ) const
195 // See http://astronomy.swin.edu.au/~pbourke/curves/bezier/ for a simple
196 // explanation of the algorithm
200 for( int i = 0; i < m_nbCtrlPt; i++ )
202 coeff = computeCoeff( i, m_nbCtrlPt - 1, t );
203 xPos += m_ptx[i] * coeff;
204 yPos += m_pty[i] * coeff;
212 inline float Bezier::computeCoeff( int i, int n, float t ) const
214 return (power( t, i ) * power( 1 - t, (n - i) ) *
215 (m_ft[n] / m_ft[i] / m_ft[n - i]));
219 inline float Bezier::power( float x, int n ) const
222 return x * power( x, n - 1);