001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/model/csct/resources/Geometry.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2001 by:
006     EXSE, Department of Geography, University of Bonn
007     http://www.giub.uni-bonn.de/exse/
008     lat/lon GmbH
009     http://www.lat-lon.de
010    
011     It has been implemented within SEAGIS - An OpenSource implementation of OpenGIS specification
012     (C) 2001, Institut de Recherche pour le D�veloppement (http://sourceforge.net/projects/seagis/)
013     SEAGIS Contacts:  Surveillance de l'Environnement Assist�e par Satellite
014     Institut de Recherche pour le D�veloppement / US-Espace
015     mailto:seasnet@teledetection.fr
016    
017    
018     This library is free software; you can redistribute it and/or
019     modify it under the terms of the GNU Lesser General Public
020     License as published by the Free Software Foundation; either
021     version 2.1 of the License, or (at your option) any later version.
022    
023     This library is distributed in the hope that it will be useful,
024     but WITHOUT ANY WARRANTY; without even the implied warranty of
025     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
026     Lesser General Public License for more details.
027    
028     You should have received a copy of the GNU Lesser General Public
029     License along with this library; if not, write to the Free Software
030     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
031    
032     Contact:
033    
034     Andreas Poth
035     lat/lon GmbH
036     Aennchenstr. 19
037     53115 Bonn
038     Germany
039     E-Mail: poth@lat-lon.de
040    
041     Klaus Greve
042     Department of Geography
043     University of Bonn
044     Meckenheimer Allee 166
045     53115 Bonn
046     Germany
047     E-Mail: klaus.greve@uni-bonn.de
048    
049     
050     ---------------------------------------------------------------------------*/
051    package org.deegree.model.csct.resources;
052    
053    // G�ometry
054    import java.awt.Shape;
055    import java.awt.geom.CubicCurve2D;
056    import java.awt.geom.Ellipse2D;
057    import java.awt.geom.GeneralPath;
058    import java.awt.geom.Line2D;
059    import java.awt.geom.PathIterator;
060    import java.awt.geom.Point2D;
061    import java.awt.geom.QuadCurve2D;
062    
063    /**
064     * Static utilities methods. Those methods operate on geometric
065     * shapes from the <code>java.awt.geom</code> package.
066     *
067     * @version 1.0
068     * @author Martin Desruisseaux
069     */
070    public final class Geometry {
071        /**
072         * Valeur limite pour d�tecter si des points sont
073         * colin�aires ou si des coordonn�es sont identiques.
074         */
075        private static final double EPS = 1E-6;
076    
077        /**
078         * Constante pour les calculs de paraboles. Cette constante indique que l'axe des
079         * <var>x</var> de la parabole doit �tre parall�le � la droite joignant les points
080         * P0 et P2.
081         */
082        public static final int PARALLEL = 0;
083    
084        /**
085         * Constante pour les calculs de paraboles. Cette constante indique que l'axe des
086         * <var>x</var> de la parabole doit �tre horizontale, quelle que soit la pente de
087         * la droite joignant les points P0 et P2.
088         */
089        public static final int HORIZONTAL = 1;
090    
091        /**
092         * Interdit la cr�ation
093         * d'objets de cette classe.
094         */
095        private Geometry() {
096        }
097    
098        /**
099         * Retourne le point d'intersection de deux segments de droites.
100         * Cette m�thode ne prolonge pas les segments de droites � l'infini.
101         * Si les deux segments ne s'interceptent pas (soit par ce qu'ils sont
102         * parall�les, ou soit parce qu'ils ne se prolongent pas assez loin
103         * pour se toucher), alors cette m�thode retourne <code>null</code>.
104         *
105         * @param  a Premi�re ligne.
106         * @param  b Deuxi�me ligne.
107         * @return Si une intersection fut trouv�e, les coordonn�es de cette
108         *         intersection. Si aucune intersection n'a �t� trouv�e, alors
109         *         cette m�thode retourne <code>null</code>.
110         */
111        public static Point2D intersectionPoint( final Line2D a, final Line2D b ) {
112            return intersectionPoint( a.getX1(), a.getY1(), a.getX2(), a.getY2(), b.getX1(), b.getY1(),
113                                      b.getX2(), b.getY2() );
114        }
115    
116        /**
117         * Retourne le point d'intersection de deux segments de droites.
118         * Cette m�thode ne prolonge pas les segments de droites � l'infini.
119         * Si les deux segments ne s'interceptent pas (soit par ce qu'ils sont
120         * parall�les, ou soit parce qu'ils ne se prolongent pas assez loin
121         * pour se toucher), alors cette m�thode retourne <code>null</code>.
122         *
123         * @return Si une intersection fut trouv�e, les coordonn�es de cette
124         *         intersection. Si aucune intersection n'a �t� trouv�e, alors
125         *         cette m�thode retourne <code>null</code>.
126         */
127        public static Point2D intersectionPoint( final double ax1, final double ay1, double ax2,
128                                                double ay2, final double bx1, final double by1,
129                                                double bx2, double by2 ) {
130            ax2 -= ax1;
131            ay2 -= ay1;
132            bx2 -= bx1;
133            by2 -= by1;
134            double x = ay2 * bx2;
135            double y = ax2 * by2;
136            /*
137             * Les x et y calcul�s pr�c�demment ne sont que des valeurs temporaires. Si et
138             * seulement si les deux droites sont parall�les, alors x==y. Ensuite seulement,
139             * la paire (x,y) ci-dessous sera les v�ritables coordonn�es du point d'intersection.
140             */
141            x = ( ( by1 - ay1 ) * ( ax2 * bx2 ) + x * ax1 - y * bx1 ) / ( x - y );
142            y = Math.abs( bx2 ) > Math.abs( ax2 ) ? ( by2 / bx2 ) * ( x - bx1 ) + by1 : ( ay2 / ax2 )
143                                                                                        * ( x - ax1 )
144                                                                                        + ay1;
145            /*
146             * Les expressions '!=0' ci-dessous sont importantes afin d'�viter des probl�mes
147             * d'erreurs d'arrondissement lorsqu'un segment est vertical ou horizontal. Les
148             * '!' qui suivent sont importants pour un fonctionnement correct avec NaN.
149             */
150            if ( ax2 != 0
151                 && !( ax2 < 0 ? ( x <= ax1 && x >= ax1 + ax2 ) : ( x >= ax1 && x <= ax1 + ax2 ) ) )
152                return null;
153            if ( bx2 != 0
154                 && !( bx2 < 0 ? ( x <= bx1 && x >= bx1 + bx2 ) : ( x >= bx1 && x <= bx1 + bx2 ) ) )
155                return null;
156            if ( ay2 != 0
157                 && !( ay2 < 0 ? ( y <= ay1 && y >= ay1 + ay2 ) : ( y >= ay1 && y <= ay1 + ay2 ) ) )
158                return null;
159            if ( by2 != 0
160                 && !( by2 < 0 ? ( y <= by1 && y >= by1 + by2 ) : ( y >= by1 && y <= by1 + by2 ) ) )
161                return null;
162            return new Point2D.Double( x, y );
163        }
164    
165        /**
166         * Retourne le point sur le segment de droite <code>line</code> qui se trouve le
167         * plus pr�s du point <code>point</code> sp�cifi�. Appellons <code>result</code>
168         * le point retourn� par cette m�thode. Il est garanti que <code>result</code>
169         * r�pond aux conditions suivantes (aux erreurs d'arrondissements pr�s):
170         *
171         * <ul>
172         *   <li><code>result</code> est un point du segment de droite <code>line</code>.
173         *       Il ne trouve pas au del� des points extr�mes P1 et P2 de ce segment.</li>
174         *   <li>La distance entre les points <code>result</code> et <code>point</code>
175         *       est la plus courte distance possible pour les points qui respectent la
176         *       condition pr�c�dente. Cette distance peut �tre calcul�e par
177         *       <code>point.distance(result)</code>.</li>
178         * </ul>
179         *
180         * @see #colinearPoint(Line2D, Point2D, double)
181         */
182        public static Point2D nearestColinearPoint( final Line2D segment, final Point2D point ) {
183            return nearestColinearPoint( segment.getX1(), segment.getY1(), segment.getX2(),
184                                         segment.getY2(), point.getX(), point.getY() );
185        }
186    
187        /**
188         * Retourne le point sur le segment de droite <code>(x1,y1)-(x2,y2)</code> qui se trouve le
189         * plus pr�s du point <code>(x,y)</code> sp�cifi�. Appellons <code>result</code> le point
190         * retourn� par cette m�thode. Il est garanti que <code>result</code> r�pond aux conditions
191         * suivantes (aux erreurs d'arrondissements pr�s):
192         *
193         * <ul>
194         *   <li><code>result</code> est un point du segment de droite <code>(x1,y1)-(x2,y2)</code>. Il
195         *       ne trouve pas au del� des points extr�mes <code>(x1,y1)</code> et <code>(x2,y2)</code>
196         *       de ce segment.</li>
197         *   <li>La distance entre les points <code>result</code> et <code>(x,y)</code>
198         *       est la plus courte distance possible pour les points qui respectent la
199         *       condition pr�c�dente. Cette distance peut �tre calcul�e par
200         *       <code>new&nbsp;Point2D.Double(x,y).distance(result)</code>.</li>
201         * </ul>
202         *
203         * @see #colinearPoint(double,double , double,double , double,double , double)
204         */
205        public static Point2D nearestColinearPoint( final double x1, final double y1, final double x2,
206                                                   final double y2, double x, double y ) {
207            final double slope = ( y2 - y1 ) / ( x2 - x1 );
208            if ( !Double.isInfinite( slope ) ) {
209                final double y0 = ( y2 - slope * x2 );
210                x = ( ( y - y0 ) * slope + x ) / ( slope * slope + 1 );
211                y = x * slope + y0;
212            } else
213                x = x2;
214            if ( x1 <= x2 ) {
215                if ( x < x1 )
216                    x = x1;
217                if ( x > x2 )
218                    x = x2;
219            } else {
220                if ( x > x1 )
221                    x = x1;
222                if ( x < x2 )
223                    x = x2;
224            }
225            if ( y1 <= y2 ) {
226                if ( y < y1 )
227                    y = y1;
228                if ( y > y2 )
229                    y = y2;
230            } else {
231                if ( y > y1 )
232                    y = y1;
233                if ( y < y2 )
234                    y = y2;
235            }
236            return new Point2D.Double( x, y );
237        }
238    
239        /**
240         * Retourne le point sur le segment de droite <code>line</code> qui se trouve � la
241         * distance <code>distance</code> sp�cifi�e du point <code>point</code>. Appellons
242         * <code>result</code> le point retourn� par cette m�thode. Si <code>result</code>
243         * est non-nul, alors il est garanti qu'il r�pond aux conditions suivantes (aux
244         * erreurs d'arrondissements pr�s):
245         *
246         * <ul>
247         *   <li><code>result</code> est un point du segment de droite <code>line</code>.
248         *       Il ne trouve pas au del� des points extr�mes P1 et P2 de ce segment.</li>
249         *   <li>La distance entre les points <code>result</code> et <code>point</code>
250         *       est exactement <code>distance</code> (aux erreurs d'arrondissements pr�s).
251         *       Cette distance peut �tre calcul�e par <code>point.distance(result)</code>.</li>
252         * </ul>
253         *
254         * Si aucun point ne peut r�pondre � ces conditions, alors cette m�thode retourne
255         * <code>null</code>. Si deux points peuvent r�pondre � ces conditions, alors par
256         * convention cette m�thode retourne le point le plus pr�s du point <code>line.getP1()</code>.
257         *
258         * @see #nearestColinearPoint(Line2D, Point2D)
259         */
260        public static Point2D colinearPoint( final Line2D line, final Point2D point,
261                                            final double distance ) {
262            return colinearPoint( line.getX1(), line.getY1(), line.getX2(), line.getY2(), point.getX(),
263                                  point.getY(), distance );
264        }
265    
266        /**
267         * Retourne le point sur le segment de droite <code>(x1,y1)-(x2,y2)</code> qui se trouve
268         * � la distance <code>distance</code> sp�cifi�e du point <code>point</code>. Appellons
269         * <code>result</code> le point retourn� par cette m�thode. Si <code>result</code>
270         * est non-nul, alors il est garanti qu'il r�pond aux conditions suivantes (aux
271         * erreurs d'arrondissements pr�s):
272         *
273         * <ul>
274         *   <li><code>result</code> est un point du segment de droite <code>(x1,y1)-(x2,y2)</code>. Il
275         *       ne trouve pas au del� des points extr�mes <code>(x1,y1)</code> et <code>(x2,y2)</code>
276         *       de ce segment.</li>
277         *   <li>La distance entre les points <code>result</code> et <code>point</code>
278         *       est exactement <code>distance</code> (aux erreurs d'arrondissements pr�s).
279         *       Cette distance peut �tre calcul�e par <code>point.distance(result)</code>.</li>
280         * </ul>
281         *
282         * Si aucun point ne peut r�pondre � ces conditions, alors cette m�thode retourne
283         * <code>null</code>. Si deux points peuvent r�pondre � ces conditions, alors par
284         * convention cette m�thode retourne le point le plus pr�s du point <code>(x1,y1)</code>.
285         *
286         * @see #nearestColinearPoint(double,double , double,double , double,double)
287         */
288        public static Point2D colinearPoint( double x1, double y1, double x2, double y2, double x,
289                                            double y, double distance ) {
290            final double ox1 = x1;
291            final double oy1 = y1;
292            final double ox2 = x2;
293            final double oy2 = y2;
294            distance *= distance;
295            if ( x1 == x2 ) {
296                double dy = x1 - x;
297                dy = Math.sqrt( distance - dy * dy );
298                y1 = y - dy;
299                y2 = y + dy;
300            } else if ( y1 == y2 ) {
301                double dx = y1 - y;
302                dx = Math.sqrt( distance - dx * dx );
303                x1 = x - dx;
304                x2 = x + dx;
305            } else {
306                final double m = ( y1 - y2 ) / ( x2 - x1 );
307                final double y0 = ( y2 - y ) + m * ( x2 - x );
308                final double B = m * y0;
309                final double A = m * m + 1;
310                final double C = Math.sqrt( B * B + A * ( distance - y0 * y0 ) );
311                x1 = ( B + C ) / A;
312                x2 = ( B - C ) / A;
313                y1 = y + y0 - m * x1;
314                y2 = y + y0 - m * x2;
315                x1 += x;
316                x2 += x;
317            }
318            boolean in1, in2;
319            if ( oy1 > oy2 ) {
320                in1 = y1 <= oy1 && y1 >= oy2;
321                in2 = y2 <= oy1 && y2 >= oy2;
322            } else {
323                in1 = y1 >= oy1 && y1 <= oy2;
324                in2 = y2 >= oy1 && y2 <= oy2;
325            }
326            if ( ox1 > ox2 ) {
327                in1 &= x1 <= ox1 && x1 >= ox2;
328                in2 &= x2 <= ox1 && x2 >= ox2;
329            } else {
330                in1 &= x1 >= ox1 && x1 <= ox2;
331                in2 &= x2 >= ox1 && x2 <= ox2;
332            }
333            if ( !in1 && !in2 )
334                return null;
335            if ( !in1 )
336                return new Point2D.Double( x2, y2 );
337            if ( !in2 )
338                return new Point2D.Double( x1, y1 );
339            x = x1 - ox1;
340            y = y1 - oy1;
341            final double d1 = x * x + y * y;
342            x = x2 - ox1;
343            y = y2 - oy1;
344            final double d2 = x * x + y * y;
345            if ( d1 > d2 ) {
346                return new Point2D.Double( x2, y2 );
347            }
348                
349            return new Point2D.Double( x1, y1 );
350        }
351    
352        /**
353         * Retourne une courbe quadratique passant par les trois points sp�cifi�s. Il peut exister une infinit� de courbes
354         * quadratiques passant par trois points. On peut voir les choses en disant qu'une courbe quadratique correspond �
355         * une parabole produite par une �quation de la forme <code>y=ax�+bx+c</code>,  mais que l'axe des <var>x</var> de
356         * cette �quation n'est pas n�cessairement horizontal. La direction de cet axe des <var>x</var> d�pend du param�tre
357         * <code>orientation</code> sp�cifi� � cette m�thode. La valeur {@link #HORIZONTAL} signifie que l'axe des <var>x</var>
358         * de la parabole sera toujours horizontal. La courbe quadratique produite ressemblera alors � une parabole classique
359         * telle qu'on en voit dans les ouvrages de math�matiques �l�mentaires. La valeur {@link #PARALLEL} indique plut�t que
360         * l'axe des <var>x</var> de la parabole doit �tre parall�le � la droite joignant les points <code>P0</code> et
361         * <code>P2</code>. Ce dernier type produira le m�me r�sultat que {@link #HORIZONTAL} si <code>P0.y==P2.y</code>.
362         *
363         * @param  P0 Premier point de la courbe quadratique.
364         * @param  P1 Point par lequel la courbe quadratique doit passer. Il n'est pas obligatoire que ce point soit situ�
365         *         entre <code>P0</code> et <code>P1</code>. Toutefois, il ne doit pas �tre colin�aire avec <code>P0</code>
366         *         et <code>P1</code>.
367         * @param  P2 Dernier point de la courbe quadratique.
368         * @param  orientation Orientation de l'axe des <var>x</var> de la parabole: {@link #PARALLEL} ou {@link #HORIZONTAL}.
369         * @return Une courbe quadratique passant par les trois points sp�cifi�s. La courbe commencera au point <code>P0</code>
370         *         et se terminera au point <code>P2</code>. Si deux points ont des coordonn�es presque identiques, ou si les
371         *         trois points sont colin�aires, alors cette m�thode retourne <code>null</code>.
372         * @throws IllegalArgumentException si l'argument <code>orientation</code> n'est pas une des constantes valides.
373         */
374        public static QuadCurve2D fitParabol( final Point2D P0, final Point2D P1, final Point2D P2,
375                                             final int orientation )
376                                throws IllegalArgumentException {
377            return fitParabol( P0.getX(), P0.getY(), P1.getX(), P1.getY(), P2.getX(), P2.getY(),
378                               orientation );
379        }
380    
381        /**
382         * Retourne une courbe quadratique passant par les trois points sp�cifi�s. Il peut exister une infinit� de courbes
383         * quadratiques passant par trois points. On peut voir les choses en disant qu'une courbe quadratique correspond �
384         * une parabole produite par une �quation de la forme <code>y=ax�+bx+c</code>,  mais que l'axe des <var>x</var> de
385         * cette �quation n'est pas n�cessairement horizontal. La direction de cet axe des <var>x</var> d�pend du param�tre
386         * <code>orientation</code> sp�cifi� � cette m�thode. La valeur {@link #HORIZONTAL} signifie que l'axe des <var>x</var>
387         * de la parabole sera toujours horizontal. La courbe quadratique produite ressemblera alors � une parabole classique
388         * telle qu'on en voit dans les ouvrages de math�matiques �l�mentaires. La valeur {@link #PARALLEL} indique plut�t que
389         * l'axe des <var>x</var> de la parabole doit �tre parall�le � la droite joignant les points <code>(x0,y0)</code> et
390         * <code>(x2,y2)</code>. Ce dernier type produira le m�me r�sultat que {@link #HORIZONTAL} si <code>y0==y2</code>.
391         *
392         * @param  orientation Orientation de l'axe des <var>x</var> de la parabole: {@link #PARALLEL} ou {@link #HORIZONTAL}.
393         * @return Une courbe quadratique passant par les trois points sp�cifi�s. La courbe commencera au point <code>(x0,y0)</code>
394         *         et se terminera au point <code>(x2,y2)</code>. Si deux points ont des coordonn�es presque identiques, ou si les
395         *         trois points sont colin�aires, alors cette m�thode retourne <code>null</code>.
396         * @throws IllegalArgumentException si l'argument <code>orientation</code> n'est pas une des constantes valides.
397         */
398        public static QuadCurve2D fitParabol( final double x0, final double y0, final double x1,
399                                             final double y1, final double x2, final double y2,
400                                             final int orientation )
401                                throws IllegalArgumentException {
402            final Point2D p = parabolicControlPoint( x0, y0, x1, y1, x2, y2, orientation, null );
403            return ( p != null ) ? new QuadCurve2D.Double( x0, y0, p.getX(), p.getY(), x2, y2 ) : null;
404        }
405    
406        /**
407         * Retourne le point de contr�le d'une courbe quadratique passant par les trois points sp�cifi�s. Il peut exister une infinit�
408         * de courbes quadratiques passant par trois points. On peut voir les choses en disant qu'une courbe quadratique correspond �
409         * une parabole produite par une �quation de la forme <code>y=ax�+bx+c</code>,  mais que l'axe des <var>x</var> de
410         * cette �quation n'est pas n�cessairement horizontal. La direction de cet axe des <var>x</var> d�pend du param�tre
411         * <code>orientation</code> sp�cifi� � cette m�thode. La valeur {@link #HORIZONTAL} signifie que l'axe des <var>x</var>
412         * de la parabole sera toujours horizontal. La courbe quadratique produite ressemblera alors � une parabole classique
413         * telle qu'on en voit dans les ouvrages de math�matiques �l�mentaires. La valeur {@link #PARALLEL} indique plut�t que
414         * l'axe des <var>x</var> de la parabole doit �tre parall�le � la droite joignant les points <code>(x0,y0)</code> et
415         * <code>(x2,y2)</code>. Ce dernier type produira le m�me r�sultat que {@link #HORIZONTAL} si <code>y0==y2</code>.
416         *
417         * @param  orientation Orientation de l'axe des <var>x</var> de la parabole: {@link #PARALLEL} ou {@link #HORIZONTAL}.
418         * @return Le point de contr�le d'une courbe quadratique passant par les trois points sp�cifi�s. La courbe commencera au
419         *         point <code>(x0,y0)</code> et se terminera au point <code>(x2,y2)</code>. Si deux points ont des coordonn�es
420         *         presque identiques, ou si les trois points sont colin�aires, alors cette m�thode retourne <code>null</code>.
421         * @throws IllegalArgumentException si l'argument <code>orientation</code> n'est pas une des constantes valides.
422         */
423        public static Point2D parabolicControlPoint( final double x0, final double y0, double x1,
424                                                    double y1, double x2, double y2,
425                                                    final int orientation, final Point2D dest )
426                                throws IllegalArgumentException {
427            /*
428             * Applique une translation de fa�on � ce que (x0,y0)
429             * devienne l'origine du syst�me d'axes. Il ne faudra
430             * plus utiliser (x0,y0) avant la fin de ce code.
431             */
432            x1 -= x0;
433            y1 -= y0;
434            x2 -= x0;
435            y2 -= y0;
436            switch ( orientation ) {
437            case PARALLEL: {
438                /*
439                 * Applique une rotation de fa�on � ce que (x2,y2)
440                 * tombe sur l'axe des x, c'est-�-dire que y2=0.
441                 */
442                final double rx2 = x2;
443                final double ry2 = y2;
444                x2 = XMath.hypot( x2, y2 );
445                y2 = ( x1 * rx2 + y1 * ry2 ) / x2; // use 'y2' as a temporary variable for 'x1'
446                y1 = ( y1 * rx2 - x1 * ry2 ) / x2;
447                x1 = y2;
448                y2 = 0;
449                /*
450                 * Calcule maintenant les coordonn�es du point
451                 * de contr�le selon le nouveau syst�me d'axes.
452                 */
453                final double x = 0.5; // Really "x/x2"
454                final double y = ( y1 * x * x2 ) / ( x1 * ( x2 - x1 ) ); // Really "y/y2"
455                final double check = Math.abs( y );
456                if ( !( check <= 1 / EPS ) )
457                    return null; // Deux points ont les m�mes coordonn�es.
458                if ( !( check >= EPS ) )
459                    return null; // Les trois points sont colin�aires.
460                /*
461                 * Applique une rotation inverse puis une translation pour
462                 * ramener le syst�me d'axe dans sa position d'origine.
463                 */
464                x1 = ( x * rx2 - y * ry2 ) + x0;
465                y1 = ( y * rx2 + x * ry2 ) + y0;
466                break;
467            }
468            case HORIZONTAL: {
469                final double a = ( y2 - y1 * x2 / x1 ) / ( x2 - x1 ); // Really "a*x2"
470                final double check = Math.abs( a );
471                if ( !( check <= 1 / EPS ) )
472                    return null; // Deux points ont les m�mes coordonn�es.
473                if ( !( check >= EPS ) )
474                    return null; // Les trois points sont colin�aires.
475                final double b = y2 / x2 - a;
476                x1 = ( 1 + b / ( 2 * a ) ) * x2 - y2 / ( 2 * a );
477                y1 = y0 + b * x1;
478                x1 += x0;
479                break;
480            }
481            default:
482                throw new IllegalArgumentException();
483            }
484            if ( dest != null ) {
485                dest.setLocation( x1, y1 );
486                return dest;
487            }
488            return new Point2D.Double( x1, y1 );
489        }
490    
491        /**
492         * Retourne un cercle qui passe par
493         * chacun des trois points sp�cifi�s.
494         */
495        public static Ellipse2D fitCircle( final Point2D P1, final Point2D P2, final Point2D P3 ) {
496            final Point2D center = circleCentre( P1.getX(), P1.getY(), P2.getX(), P2.getY(), P3.getX(),
497                                                 P3.getY() );
498            final double radius = center.distance( P2 );
499            return new Ellipse2D.Double( center.getX() - radius, center.getY() - radius, 2 * radius,
500                                         2 * radius );
501        }
502    
503        /**
504         * Retourne la coordonn�e centrale d'un cercle passant
505         * pas les trois points sp�cifi�s. La distance entre
506         * le point retourn� et n'importe quel des points
507         * (<var>x</var><sub>1</sub>,<var>y</var><sub>1</sub>),
508         * (<var>x</var><sub>2</sub>,<var>y</var><sub>2</sub>),
509         * (<var>x</var><sub>3</sub>,<var>y</var><sub>3</sub>)
510         * sera constante; ce sera le rayon d'un cercle centr�
511         * au point retourn� et passant par les trois points
512         * sp�cifi�s.
513         */
514        public static Point2D circleCentre( double x1, double y1, double x2, double y2, double x3,
515                                           double y3 ) {
516            x2 -= x1;
517            x3 -= x1;
518            y2 -= y1;
519            y3 -= y1;
520            final double sq2 = ( x2 * x2 + y2 * y2 );
521            final double sq3 = ( x3 * x3 + y3 * y3 );
522            final double x = ( y2 * sq3 - y3 * sq2 ) / ( y2 * x3 - y3 * x2 );
523            return new Point2D.Double( x1 + 0.5 * x, y1 + 0.5 * ( sq2 - x * x2 ) / y2 );
524        }
525    
526        /**
527         * Tente de remplacer la forme g�om�trique <code>path</code> par une des formes standards
528         * de Java2D. Par exemple, si <code>path</code> ne contient qu'un simple segment de droite
529         * ou une courbe quadratique, alors cette m�thode retournera un objet {@link Line2D} ou
530         * {@link QuadCurve2D} respectivement.
531         *
532         * @param  path Forme g�om�trique � simplifier (g�n�ralement un objet {@link GeneralPath}).
533         * @return Forme g�om�trique standard, ou <code>path</code> si aucun remplacement n'est propos�.
534         */
535        public static Shape toPrimitive( final Shape path ) {
536            final float[] buffer = new float[6];
537            final PathIterator it = path.getPathIterator( null );
538            if ( !it.isDone() && it.currentSegment( buffer ) == PathIterator.SEG_MOVETO && !it.isDone() ) {
539                final float x1 = buffer[0];
540                final float y1 = buffer[1];
541                final int code = it.currentSegment( buffer );
542                if ( it.isDone() )
543                    switch ( code ) {
544                    case PathIterator.SEG_LINETO:
545                        return new Line2D.Float( x1, y1, buffer[0], buffer[1] );
546                    case PathIterator.SEG_QUADTO:
547                        return new QuadCurve2D.Float( x1, y1, buffer[0], buffer[1], buffer[2],
548                                                      buffer[3] );
549                    case PathIterator.SEG_CUBICTO:
550                        return new CubicCurve2D.Float( x1, y1, buffer[0], buffer[1], buffer[2],
551                                                       buffer[3], buffer[4], buffer[5] );
552                    }
553            }
554            return path;
555        }
556    }