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 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 }