]> git.sesse.net Git - vlc/blob - modules/gui/skins2/utils/bezier.cpp
* all: brand new skins interface ( still _experimental_) for x11 and
[vlc] / modules / gui / skins2 / utils / bezier.cpp
1 /*****************************************************************************
2  * bezier.cpp
3  *****************************************************************************
4  * Copyright (C) 2003 VideoLAN
5  * $Id: bezier.cpp,v 1.1 2004/01/03 23:31:34 asmax Exp $
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 #include "bezier.hpp"
26 #include <math.h>
27
28
29 Bezier::Bezier( intf_thread_t *p_intf, const vector<double> &rAbscissas,
30                 const vector<double> &rOrdinates, Flag_t flag )
31     : SkinObject( p_intf )
32 {
33     // We expect rAbscissas and rOrdinates to have the same size, of course
34     m_nbCtrlPt = rAbscissas.size();
35
36     // Copy the control points coordinates
37     m_ptx.assign( rAbscissas.begin(), rAbscissas.end() );
38     m_pty.assign( rOrdinates.begin(), rOrdinates.end() );
39
40     // Precalculate the factoriels
41     m_ft.push_back( 1 );
42     for( int i = 1; i < m_nbCtrlPt; i++ )
43     {
44         m_ft.push_back( i * m_ft[i - 1] );
45     }
46
47     // Initialization
48     int cx, cy, oldx, oldy;
49     m_leftVect.reserve( MAX_BEZIER_POINT + 1 );
50     m_topVect.reserve( MAX_BEZIER_POINT + 1 );
51
52     // Calculate the first point
53     getPoint( 0, oldx, oldy );
54     m_leftVect[0] = oldx;
55     m_topVect[0]  = oldy;
56
57     // Compute the number of different points
58     double percentage;
59     for( double j = 1; j <= MAX_BEZIER_POINT; j++ )
60     {
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 ) )
66         {
67             m_leftVect.push_back( cx );
68             m_topVect.push_back( cy );
69             oldx = cx;
70             oldy = cy;
71         }
72     }
73     m_nbPoints = m_leftVect.size();
74 }
75
76
77 double Bezier::getNearestPercent( int x, int y ) const
78 {
79     int nearest = findNearestPoint( x, y );
80     return (double)nearest / (double)(m_nbPoints - 1);
81 }
82
83
84 double Bezier::getMinDist( int x, int y ) const
85 {
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);
89
90     int dist;
91     for( int i = 1; i < m_nbPoints; i++ )
92     {
93         dist = (m_leftVect[i] - x) * (m_leftVect[i] - x) +
94                (m_topVect[i] - y) * (m_topVect[i] - y);
95         if( dist < minDist )
96         {
97             minDist = dist;
98         }
99     }
100     return sqrt( minDist );
101 }
102
103
104 void Bezier::getPoint( double t, int &x, int &y ) const
105 {
106     // See http://astronomy.swin.edu.au/~pbourke/curves/bezier/ for a simple
107     // explanation of the algorithm
108     double xPos = 0;
109     double yPos = 0;
110     double coeff;
111     for( int i = 0; i < m_nbCtrlPt; i++ )
112     {
113         coeff = computeCoeff( i, m_nbCtrlPt - 1, t );
114         xPos += m_ptx[i] * coeff;
115         yPos += m_pty[i] * coeff;
116     }
117
118     // Double cast to avoid strange truncatures
119     // XXX: not very nice...
120     x = (int)(float)xPos;
121     y = (int)(float)yPos;
122 }
123
124
125 int Bezier::getWidth() const
126 {
127     int width = 0;
128     for( int i = 0; i < m_nbPoints; i++ )
129     {
130         if( m_leftVect[i] > width )
131         {
132             width = m_leftVect[i];
133         }
134     }
135     return width;
136 }
137
138
139 int Bezier::getHeight() const
140 {
141     int height = 0;
142     for( int i = 0; i < m_nbPoints; i++ )
143     {
144         if( m_topVect[i] > height )
145         {
146             height = m_topVect[i];
147         }
148     }
149     return height;
150 }
151
152
153 int Bezier::findNearestPoint( int x, int y ) const
154 {
155     // XXX: duplicate code with getMinDist
156     // The distance to the first point is taken as the reference
157     int refPoint = 0;
158     int minDist = (m_leftVect[0] - x) * (m_leftVect[0] - x) +
159                   (m_topVect[0] - y) * (m_topVect[0] - y);
160
161     int dist;
162     for( int i = 1; i < m_nbPoints; i++ )
163     {
164         dist = (m_leftVect[i] - x) * (m_leftVect[i] - x) +
165                (m_topVect[i] - y) * (m_topVect[i] - y);
166         if( dist < minDist )
167         {
168             minDist = dist;
169             refPoint = i;
170         }
171     }
172
173     return refPoint;
174 }
175
176
177 inline double Bezier::computeCoeff( int i, int n, double t ) const
178 {
179     return (power( t, i ) * power( 1 - t, (n - i) ) *
180         (m_ft[n] / m_ft[i] / m_ft[n - i]));
181 }
182
183
184 inline double Bezier::power( double x, int n ) const
185 {
186     if( n > 0 )
187         return x * power( x, n - 1);
188     else
189         return 1;
190 }
191