Source Code Cross Referenced for ShapeUtilities.java in  » GIS » GeoTools-2.4.1 » org » geotools » resources » geometry » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » GIS » GeoTools 2.4.1 » org.geotools.resources.geometry 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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