Source Code Cross Referenced for CubicCurve2D.java in  » 6.0-JDK-Core » AWT » java » awt » geom » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Home
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
26.ERP CRM Financial
27.ESB
28.Forum
29.Game
30.GIS
31.Graphic 3D
32.Graphic Library
33.Groupware
34.HTML Parser
35.IDE
36.IDE Eclipse
37.IDE Netbeans
38.Installer
39.Internationalization Localization
40.Inversion of Control
41.Issue Tracking
42.J2EE
43.J2ME
44.JBoss
45.JMS
46.JMX
47.Library
48.Mail Clients
49.Music
50.Net
51.Parser
52.PDF
53.Portal
54.Profiler
55.Project Management
56.Report
57.RSS RDF
58.Rule Engine
59.Science
60.Scripting
61.Search Engine
62.Security
63.Sevlet Container
64.Source Control
65.Swing Library
66.Template Engine
67.Test Coverage
68.Testing
69.UML
70.Web Crawler
71.Web Framework
72.Web Mail
73.Web Server
74.Web Services
75.Web Services apache cxf 2.2.6
76.Web Services AXIS2
77.Wiki Engine
78.Workflow Engines
79.XML
80.XML UI
Java Source Code / Java Documentation » 6.0 JDK Core » AWT » java.awt.geom 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001        /*
0002         * Copyright 1997-2006 Sun Microsystems, Inc.  All Rights Reserved.
0003         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004         *
0005         * This code is free software; you can redistribute it and/or modify it
0006         * under the terms of the GNU General Public License version 2 only, as
0007         * published by the Free Software Foundation.  Sun designates this
0008         * particular file as subject to the "Classpath" exception as provided
0009         * by Sun in the LICENSE file that accompanied this code.
0010         *
0011         * This code is distributed in the hope that it will be useful, but WITHOUT
0012         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
0014         * version 2 for more details (a copy is included in the LICENSE file that
0015         * accompanied this code).
0016         *
0017         * You should have received a copy of the GNU General Public License version
0018         * 2 along with this work; if not, write to the Free Software Foundation,
0019         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020         *
0021         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022         * CA 95054 USA or visit www.sun.com if you need additional information or
0023         * have any questions.
0024         */
0025
0026        package java.awt.geom;
0027
0028        import java.awt.Shape;
0029        import java.awt.Rectangle;
0030        import java.util.Arrays;
0031        import java.io.Serializable;
0032        import sun.awt.geom.Curve;
0033
0034        /**
0035         * The <code>CubicCurve2D</code> class defines a cubic parametric curve 
0036         * segment in {@code (x,y)} coordinate space.
0037         * <p>
0038         * This class is only the abstract superclass for all objects which
0039         * store a 2D cubic curve segment.
0040         * The actual storage representation of the coordinates is left to
0041         * the subclass.
0042         *
0043         * @version 	1.42, 05/05/07
0044         * @author	Jim Graham
0045         * @since 1.2
0046         */
0047        public abstract class CubicCurve2D implements  Shape, Cloneable {
0048
0049            /**
0050             * A cubic parametric curve segment specified with
0051             * {@code float} coordinates.
0052             * @since 1.2
0053             */
0054            public static class Float extends CubicCurve2D implements 
0055                    Serializable {
0056                /**
0057                 * The X coordinate of the start point
0058                 * of the cubic curve segment.
0059                 * @since 1.2
0060                 * @serial
0061                 */
0062                public float x1;
0063
0064                /**
0065                 * The Y coordinate of the start point
0066                 * of the cubic curve segment.
0067                 * @since 1.2
0068                 * @serial
0069                 */
0070                public float y1;
0071
0072                /**
0073                 * The X coordinate of the first control point
0074                 * of the cubic curve segment.
0075                 * @since 1.2
0076                 * @serial
0077                 */
0078                public float ctrlx1;
0079
0080                /**
0081                 * The Y coordinate of the first control point
0082                 * of the cubic curve segment.
0083                 * @since 1.2
0084                 * @serial
0085                 */
0086                public float ctrly1;
0087
0088                /**
0089                 * The X coordinate of the second control point
0090                 * of the cubic curve segment.
0091                 * @since 1.2
0092                 * @serial
0093                 */
0094                public float ctrlx2;
0095
0096                /**
0097                 * The Y coordinate of the second control point
0098                 * of the cubic curve segment.
0099                 * @since 1.2
0100                 * @serial
0101                 */
0102                public float ctrly2;
0103
0104                /**
0105                 * The X coordinate of the end point
0106                 * of the cubic curve segment.
0107                 * @since 1.2
0108                 * @serial
0109                 */
0110                public float x2;
0111
0112                /**
0113                 * The Y coordinate of the end point
0114                 * of the cubic curve segment.
0115                 * @since 1.2
0116                 * @serial
0117                 */
0118                public float y2;
0119
0120                /**
0121                 * Constructs and initializes a CubicCurve with coordinates
0122                 * (0, 0, 0, 0, 0, 0, 0, 0).
0123                 * @since 1.2
0124                 */
0125                public Float() {
0126                }
0127
0128                /**
0129                 * Constructs and initializes a {@code CubicCurve2D} from
0130                 * the specified {@code float} coordinates.
0131                 *
0132                 * @param x1 the X coordinate for the start point
0133                 *           of the resulting {@code CubicCurve2D}
0134                 * @param y1 the Y coordinate for the start point
0135                 *           of the resulting {@code CubicCurve2D}
0136                 * @param ctrlx1 the X coordinate for the first control point
0137                 *               of the resulting {@code CubicCurve2D}
0138                 * @param ctrly1 the Y coordinate for the first control point
0139                 *               of the resulting {@code CubicCurve2D}
0140                 * @param ctrlx2 the X coordinate for the second control point
0141                 *               of the resulting {@code CubicCurve2D}
0142                 * @param ctrly2 the Y coordinate for the second control point
0143                 *               of the resulting {@code CubicCurve2D}
0144                 * @param x2 the X coordinate for the end point
0145                 *           of the resulting {@code CubicCurve2D}
0146                 * @param y2 the Y coordinate for the end point
0147                 *           of the resulting {@code CubicCurve2D}
0148                 * @since 1.2
0149                 */
0150                public Float(float x1, float y1, float ctrlx1, float ctrly1,
0151                        float ctrlx2, float ctrly2, float x2, float y2) {
0152                    setCurve(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2);
0153                }
0154
0155                /**
0156                 * {@inheritDoc}
0157                 * @since 1.2
0158                 */
0159                public double getX1() {
0160                    return (double) x1;
0161                }
0162
0163                /**
0164                 * {@inheritDoc}
0165                 * @since 1.2
0166                 */
0167                public double getY1() {
0168                    return (double) y1;
0169                }
0170
0171                /**
0172                 * {@inheritDoc}
0173                 * @since 1.2
0174                 */
0175                public Point2D getP1() {
0176                    return new Point2D.Float(x1, y1);
0177                }
0178
0179                /**
0180                 * {@inheritDoc}
0181                 * @since 1.2
0182                 */
0183                public double getCtrlX1() {
0184                    return (double) ctrlx1;
0185                }
0186
0187                /**
0188                 * {@inheritDoc}
0189                 * @since 1.2
0190                 */
0191                public double getCtrlY1() {
0192                    return (double) ctrly1;
0193                }
0194
0195                /**
0196                 * {@inheritDoc}
0197                 * @since 1.2
0198                 */
0199                public Point2D getCtrlP1() {
0200                    return new Point2D.Float(ctrlx1, ctrly1);
0201                }
0202
0203                /**
0204                 * {@inheritDoc}
0205                 * @since 1.2
0206                 */
0207                public double getCtrlX2() {
0208                    return (double) ctrlx2;
0209                }
0210
0211                /**
0212                 * {@inheritDoc}
0213                 * @since 1.2
0214                 */
0215                public double getCtrlY2() {
0216                    return (double) ctrly2;
0217                }
0218
0219                /**
0220                 * {@inheritDoc}
0221                 * @since 1.2
0222                 */
0223                public Point2D getCtrlP2() {
0224                    return new Point2D.Float(ctrlx2, ctrly2);
0225                }
0226
0227                /**
0228                 * {@inheritDoc}
0229                 * @since 1.2
0230                 */
0231                public double getX2() {
0232                    return (double) x2;
0233                }
0234
0235                /**
0236                 * {@inheritDoc}
0237                 * @since 1.2
0238                 */
0239                public double getY2() {
0240                    return (double) y2;
0241                }
0242
0243                /**
0244                 * {@inheritDoc}
0245                 * @since 1.2
0246                 */
0247                public Point2D getP2() {
0248                    return new Point2D.Float(x2, y2);
0249                }
0250
0251                /**
0252                 * {@inheritDoc}
0253                 * @since 1.2
0254                 */
0255                public void setCurve(double x1, double y1, double ctrlx1,
0256                        double ctrly1, double ctrlx2, double ctrly2, double x2,
0257                        double y2) {
0258                    this .x1 = (float) x1;
0259                    this .y1 = (float) y1;
0260                    this .ctrlx1 = (float) ctrlx1;
0261                    this .ctrly1 = (float) ctrly1;
0262                    this .ctrlx2 = (float) ctrlx2;
0263                    this .ctrly2 = (float) ctrly2;
0264                    this .x2 = (float) x2;
0265                    this .y2 = (float) y2;
0266                }
0267
0268                /**
0269                 * Sets the location of the end points and control points
0270                 * of this curve to the specified {@code float} coordinates.
0271                 *
0272                 * @param x1 the X coordinate used to set the start point
0273                 *           of this {@code CubicCurve2D}
0274                 * @param y1 the Y coordinate used to set the start point
0275                 *           of this {@code CubicCurve2D}
0276                 * @param ctrlx1 the X coordinate used to set the first control point
0277                 *               of this {@code CubicCurve2D}
0278                 * @param ctrly1 the Y coordinate used to set the first control point
0279                 *               of this {@code CubicCurve2D}
0280                 * @param ctrlx2 the X coordinate used to set the second control point
0281                 *               of this {@code CubicCurve2D}
0282                 * @param ctrly2 the Y coordinate used to set the second control point
0283                 *               of this {@code CubicCurve2D}
0284                 * @param x2 the X coordinate used to set the end point
0285                 *           of this {@code CubicCurve2D}
0286                 * @param y2 the Y coordinate used to set the end point
0287                 *           of this {@code CubicCurve2D}
0288                 * @since 1.2
0289                 */
0290                public void setCurve(float x1, float y1, float ctrlx1,
0291                        float ctrly1, float ctrlx2, float ctrly2, float x2,
0292                        float y2) {
0293                    this .x1 = x1;
0294                    this .y1 = y1;
0295                    this .ctrlx1 = ctrlx1;
0296                    this .ctrly1 = ctrly1;
0297                    this .ctrlx2 = ctrlx2;
0298                    this .ctrly2 = ctrly2;
0299                    this .x2 = x2;
0300                    this .y2 = y2;
0301                }
0302
0303                /**
0304                 * {@inheritDoc}
0305                 * @since 1.2
0306                 */
0307                public Rectangle2D getBounds2D() {
0308                    float left = Math.min(Math.min(x1, x2), Math.min(ctrlx1,
0309                            ctrlx2));
0310                    float top = Math.min(Math.min(y1, y2), Math.min(ctrly1,
0311                            ctrly2));
0312                    float right = Math.max(Math.max(x1, x2), Math.max(ctrlx1,
0313                            ctrlx2));
0314                    float bottom = Math.max(Math.max(y1, y2), Math.max(ctrly1,
0315                            ctrly2));
0316                    return new Rectangle2D.Float(left, top, right - left,
0317                            bottom - top);
0318                }
0319
0320                /*
0321                 * JDK 1.6 serialVersionUID
0322                 */
0323                private static final long serialVersionUID = -1272015596714244385L;
0324            }
0325
0326            /**
0327             * A cubic parametric curve segment specified with
0328             * {@code double} coordinates.
0329             * @since 1.2
0330             */
0331            public static class Double extends CubicCurve2D implements 
0332                    Serializable {
0333                /**
0334                 * The X coordinate of the start point
0335                 * of the cubic curve segment.
0336                 * @since 1.2
0337                 * @serial
0338                 */
0339                public double x1;
0340
0341                /**
0342                 * The Y coordinate of the start point
0343                 * of the cubic curve segment.
0344                 * @since 1.2
0345                 * @serial
0346                 */
0347                public double y1;
0348
0349                /**
0350                 * The X coordinate of the first control point
0351                 * of the cubic curve segment.
0352                 * @since 1.2
0353                 * @serial
0354                 */
0355                public double ctrlx1;
0356
0357                /**
0358                 * The Y coordinate of the first control point
0359                 * of the cubic curve segment.
0360                 * @since 1.2
0361                 * @serial
0362                 */
0363                public double ctrly1;
0364
0365                /**
0366                 * The X coordinate of the second control point
0367                 * of the cubic curve segment.
0368                 * @since 1.2
0369                 * @serial
0370                 */
0371                public double ctrlx2;
0372
0373                /**
0374                 * The Y coordinate of the second control point
0375                 * of the cubic curve segment.
0376                 * @since 1.2
0377                 * @serial
0378                 */
0379                public double ctrly2;
0380
0381                /**
0382                 * The X coordinate of the end point
0383                 * of the cubic curve segment.
0384                 * @since 1.2
0385                 * @serial
0386                 */
0387                public double x2;
0388
0389                /**
0390                 * The Y coordinate of the end point
0391                 * of the cubic curve segment.
0392                 * @since 1.2
0393                 * @serial
0394                 */
0395                public double y2;
0396
0397                /**
0398                 * Constructs and initializes a CubicCurve with coordinates
0399                 * (0, 0, 0, 0, 0, 0, 0, 0).
0400                 * @since 1.2
0401                 */
0402                public Double() {
0403                }
0404
0405                /**
0406                 * Constructs and initializes a {@code CubicCurve2D} from
0407                 * the specified {@code double} coordinates.
0408                 *
0409                 * @param x1 the X coordinate for the start point
0410                 *           of the resulting {@code CubicCurve2D}
0411                 * @param y1 the Y coordinate for the start point
0412                 *           of the resulting {@code CubicCurve2D}
0413                 * @param ctrlx1 the X coordinate for the first control point
0414                 *               of the resulting {@code CubicCurve2D}
0415                 * @param ctrly1 the Y coordinate for the first control point
0416                 *               of the resulting {@code CubicCurve2D}
0417                 * @param ctrlx2 the X coordinate for the second control point
0418                 *               of the resulting {@code CubicCurve2D}
0419                 * @param ctrly2 the Y coordinate for the second control point
0420                 *               of the resulting {@code CubicCurve2D}
0421                 * @param x2 the X coordinate for the end point
0422                 *           of the resulting {@code CubicCurve2D}
0423                 * @param y2 the Y coordinate for the end point
0424                 *           of the resulting {@code CubicCurve2D}
0425                 * @since 1.2
0426                 */
0427                public Double(double x1, double y1, double ctrlx1,
0428                        double ctrly1, double ctrlx2, double ctrly2, double x2,
0429                        double y2) {
0430                    setCurve(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2);
0431                }
0432
0433                /**
0434                 * {@inheritDoc}
0435                 * @since 1.2
0436                 */
0437                public double getX1() {
0438                    return x1;
0439                }
0440
0441                /**
0442                 * {@inheritDoc}
0443                 * @since 1.2
0444                 */
0445                public double getY1() {
0446                    return y1;
0447                }
0448
0449                /**
0450                 * {@inheritDoc}
0451                 * @since 1.2
0452                 */
0453                public Point2D getP1() {
0454                    return new Point2D.Double(x1, y1);
0455                }
0456
0457                /**
0458                 * {@inheritDoc}
0459                 * @since 1.2
0460                 */
0461                public double getCtrlX1() {
0462                    return ctrlx1;
0463                }
0464
0465                /**
0466                 * {@inheritDoc}
0467                 * @since 1.2
0468                 */
0469                public double getCtrlY1() {
0470                    return ctrly1;
0471                }
0472
0473                /**
0474                 * {@inheritDoc}
0475                 * @since 1.2
0476                 */
0477                public Point2D getCtrlP1() {
0478                    return new Point2D.Double(ctrlx1, ctrly1);
0479                }
0480
0481                /**
0482                 * {@inheritDoc}
0483                 * @since 1.2
0484                 */
0485                public double getCtrlX2() {
0486                    return ctrlx2;
0487                }
0488
0489                /**
0490                 * {@inheritDoc}
0491                 * @since 1.2
0492                 */
0493                public double getCtrlY2() {
0494                    return ctrly2;
0495                }
0496
0497                /**
0498                 * {@inheritDoc}
0499                 * @since 1.2
0500                 */
0501                public Point2D getCtrlP2() {
0502                    return new Point2D.Double(ctrlx2, ctrly2);
0503                }
0504
0505                /**
0506                 * {@inheritDoc}
0507                 * @since 1.2
0508                 */
0509                public double getX2() {
0510                    return x2;
0511                }
0512
0513                /**
0514                 * {@inheritDoc}
0515                 * @since 1.2
0516                 */
0517                public double getY2() {
0518                    return y2;
0519                }
0520
0521                /**
0522                 * {@inheritDoc}
0523                 * @since 1.2
0524                 */
0525                public Point2D getP2() {
0526                    return new Point2D.Double(x2, y2);
0527                }
0528
0529                /**
0530                 * {@inheritDoc}
0531                 * @since 1.2
0532                 */
0533                public void setCurve(double x1, double y1, double ctrlx1,
0534                        double ctrly1, double ctrlx2, double ctrly2, double x2,
0535                        double y2) {
0536                    this .x1 = x1;
0537                    this .y1 = y1;
0538                    this .ctrlx1 = ctrlx1;
0539                    this .ctrly1 = ctrly1;
0540                    this .ctrlx2 = ctrlx2;
0541                    this .ctrly2 = ctrly2;
0542                    this .x2 = x2;
0543                    this .y2 = y2;
0544                }
0545
0546                /**
0547                 * {@inheritDoc}
0548                 * @since 1.2
0549                 */
0550                public Rectangle2D getBounds2D() {
0551                    double left = Math.min(Math.min(x1, x2), Math.min(ctrlx1,
0552                            ctrlx2));
0553                    double top = Math.min(Math.min(y1, y2), Math.min(ctrly1,
0554                            ctrly2));
0555                    double right = Math.max(Math.max(x1, x2), Math.max(ctrlx1,
0556                            ctrlx2));
0557                    double bottom = Math.max(Math.max(y1, y2), Math.max(ctrly1,
0558                            ctrly2));
0559                    return new Rectangle2D.Double(left, top, right - left,
0560                            bottom - top);
0561                }
0562
0563                /*
0564                 * JDK 1.6 serialVersionUID
0565                 */
0566                private static final long serialVersionUID = -4202960122839707295L;
0567            }
0568
0569            /**
0570             * This is an abstract class that cannot be instantiated directly.
0571             * Type-specific implementation subclasses are available for
0572             * instantiation and provide a number of formats for storing
0573             * the information necessary to satisfy the various accessor
0574             * methods below.
0575             *
0576             * @see java.awt.geom.CubicCurve2D.Float
0577             * @see java.awt.geom.CubicCurve2D.Double
0578             * @since 1.2
0579             */
0580            protected CubicCurve2D() {
0581            }
0582
0583            /**
0584             * Returns the X coordinate of the start point in double precision.
0585             * @return the X coordinate of the start point of the
0586             *         {@code CubicCurve2D}.
0587             * @since 1.2
0588             */
0589            public abstract double getX1();
0590
0591            /**
0592             * Returns the Y coordinate of the start point in double precision.
0593             * @return the Y coordinate of the start point of the
0594             *         {@code CubicCurve2D}.
0595             * @since 1.2
0596             */
0597            public abstract double getY1();
0598
0599            /**
0600             * Returns the start point.
0601             * @return a {@code Point2D} that is the start point of 
0602             *         the {@code CubicCurve2D}.
0603             * @since 1.2
0604             */
0605            public abstract Point2D getP1();
0606
0607            /**
0608             * Returns the X coordinate of the first control point in double precision.
0609             * @return the X coordinate of the first control point of the
0610             *         {@code CubicCurve2D}.
0611             * @since 1.2
0612             */
0613            public abstract double getCtrlX1();
0614
0615            /**
0616             * Returns the Y coordinate of the first control point in double precision.
0617             * @return the Y coordinate of the first control point of the
0618             *         {@code CubicCurve2D}.
0619             * @since 1.2
0620             */
0621            public abstract double getCtrlY1();
0622
0623            /**
0624             * Returns the first control point.
0625             * @return a {@code Point2D} that is the first control point of 
0626             *         the {@code CubicCurve2D}.
0627             * @since 1.2
0628             */
0629            public abstract Point2D getCtrlP1();
0630
0631            /**
0632             * Returns the X coordinate of the second control point
0633             * in double precision.
0634             * @return the X coordinate of the second control point of the
0635             *         {@code CubicCurve2D}.
0636             * @since 1.2
0637             */
0638            public abstract double getCtrlX2();
0639
0640            /**
0641             * Returns the Y coordinate of the second control point
0642             * in double precision.
0643             * @return the Y coordinate of the second control point of the
0644             *         {@code CubicCurve2D}.
0645             * @since 1.2
0646             */
0647            public abstract double getCtrlY2();
0648
0649            /**
0650             * Returns the second control point.
0651             * @return a {@code Point2D} that is the second control point of 
0652             *         the {@code CubicCurve2D}.
0653             * @since 1.2
0654             */
0655            public abstract Point2D getCtrlP2();
0656
0657            /**
0658             * Returns the X coordinate of the end point in double precision.
0659             * @return the X coordinate of the end point of the
0660             *         {@code CubicCurve2D}.
0661             * @since 1.2
0662             */
0663            public abstract double getX2();
0664
0665            /**
0666             * Returns the Y coordinate of the end point in double precision.
0667             * @return the Y coordinate of the end point of the
0668             *         {@code CubicCurve2D}.
0669             * @since 1.2
0670             */
0671            public abstract double getY2();
0672
0673            /**
0674             * Returns the end point.
0675             * @return a {@code Point2D} that is the end point of 
0676             *         the {@code CubicCurve2D}.
0677             * @since 1.2
0678             */
0679            public abstract Point2D getP2();
0680
0681            /**
0682             * Sets the location of the end points and control points of this curve
0683             * to the specified double coordinates.
0684             *
0685             * @param x1 the X coordinate used to set the start point
0686             *           of this {@code CubicCurve2D}
0687             * @param y1 the Y coordinate used to set the start point
0688             *           of this {@code CubicCurve2D}
0689             * @param ctrlx1 the X coordinate used to set the first control point
0690             *               of this {@code CubicCurve2D}
0691             * @param ctrly1 the Y coordinate used to set the first control point
0692             *               of this {@code CubicCurve2D}
0693             * @param ctrlx2 the X coordinate used to set the second control point
0694             *               of this {@code CubicCurve2D}
0695             * @param ctrly2 the Y coordinate used to set the second control point
0696             *               of this {@code CubicCurve2D}
0697             * @param x2 the X coordinate used to set the end point
0698             *           of this {@code CubicCurve2D}
0699             * @param y2 the Y coordinate used to set the end point
0700             *           of this {@code CubicCurve2D}
0701             * @since 1.2
0702             */
0703            public abstract void setCurve(double x1, double y1, double ctrlx1,
0704                    double ctrly1, double ctrlx2, double ctrly2, double x2,
0705                    double y2);
0706
0707            /**
0708             * Sets the location of the end points and control points of this curve
0709             * to the double coordinates at the specified offset in the specified
0710             * array.
0711             * @param coords a double array containing coordinates
0712             * @param offset the index of <code>coords</code> from which to begin 
0713             *          setting the end points and control points of this curve
0714             *		to the coordinates contained in <code>coords</code>	
0715             * @since 1.2
0716             */
0717            public void setCurve(double[] coords, int offset) {
0718                setCurve(coords[offset + 0], coords[offset + 1],
0719                        coords[offset + 2], coords[offset + 3],
0720                        coords[offset + 4], coords[offset + 5],
0721                        coords[offset + 6], coords[offset + 7]);
0722            }
0723
0724            /**
0725             * Sets the location of the end points and control points of this curve
0726             * to the specified <code>Point2D</code> coordinates.
0727             * @param p1 the first specified <code>Point2D</code> used to set the
0728             *		start point of this curve
0729             * @param cp1 the second specified <code>Point2D</code> used to set the
0730             *		first control point of this curve
0731             * @param cp2 the third specified <code>Point2D</code> used to set the
0732             *		second control point of this curve
0733             * @param p2 the fourth specified <code>Point2D</code> used to set the
0734             *		end point of this curve
0735             * @since 1.2
0736             */
0737            public void setCurve(Point2D p1, Point2D cp1, Point2D cp2,
0738                    Point2D p2) {
0739                setCurve(p1.getX(), p1.getY(), cp1.getX(), cp1.getY(), cp2
0740                        .getX(), cp2.getY(), p2.getX(), p2.getY());
0741            }
0742
0743            /**
0744             * Sets the location of the end points and control points of this curve
0745             * to the coordinates of the <code>Point2D</code> objects at the specified 
0746             * offset in the specified array.
0747             * @param pts an array of <code>Point2D</code> objects
0748             * @param offset  the index of <code>pts</code> from which to begin setting
0749             *          the end points and control points of this curve to the 
0750             *		points contained in <code>pts</code>
0751             * @since 1.2
0752             */
0753            public void setCurve(Point2D[] pts, int offset) {
0754                setCurve(pts[offset + 0].getX(), pts[offset + 0].getY(),
0755                        pts[offset + 1].getX(), pts[offset + 1].getY(),
0756                        pts[offset + 2].getX(), pts[offset + 2].getY(),
0757                        pts[offset + 3].getX(), pts[offset + 3].getY());
0758            }
0759
0760            /**
0761             * Sets the location of the end points and control points of this curve
0762             * to the same as those in the specified <code>CubicCurve2D</code>.
0763             * @param c the specified <code>CubicCurve2D</code>
0764             * @since 1.2
0765             */
0766            public void setCurve(CubicCurve2D c) {
0767                setCurve(c.getX1(), c.getY1(), c.getCtrlX1(), c.getCtrlY1(), c
0768                        .getCtrlX2(), c.getCtrlY2(), c.getX2(), c.getY2());
0769            }
0770
0771            /**
0772             * Returns the square of the flatness of the cubic curve specified
0773             * by the indicated control points. The flatness is the maximum distance 
0774             * of a control point from the line connecting the end points.
0775             *
0776             * @param x1 the X coordinate that specifies the start point
0777             *           of a {@code CubicCurve2D}
0778             * @param y1 the Y coordinate that specifies the start point
0779             *           of a {@code CubicCurve2D}
0780             * @param ctrlx1 the X coordinate that specifies the first control point
0781             *               of a {@code CubicCurve2D}
0782             * @param ctrly1 the Y coordinate that specifies the first control point
0783             *               of a {@code CubicCurve2D}
0784             * @param ctrlx2 the X coordinate that specifies the second control point
0785             *               of a {@code CubicCurve2D}
0786             * @param ctrly2 the Y coordinate that specifies the second control point
0787             *               of a {@code CubicCurve2D}
0788             * @param x2 the X coordinate that specifies the end point
0789             *           of a {@code CubicCurve2D}
0790             * @param y2 the Y coordinate that specifies the end point
0791             *           of a {@code CubicCurve2D}
0792             * @return the square of the flatness of the {@code CubicCurve2D}
0793             *		represented by the specified coordinates.
0794             * @since 1.2
0795             */
0796            public static double getFlatnessSq(double x1, double y1,
0797                    double ctrlx1, double ctrly1, double ctrlx2, double ctrly2,
0798                    double x2, double y2) {
0799                return Math.max(Line2D.ptSegDistSq(x1, y1, x2, y2, ctrlx1,
0800                        ctrly1), Line2D.ptSegDistSq(x1, y1, x2, y2, ctrlx2,
0801                        ctrly2));
0802
0803            }
0804
0805            /**
0806             * Returns the flatness of the cubic curve specified
0807             * by the indicated control points. The flatness is the maximum distance 
0808             * of a control point from the line connecting the end points.
0809             *
0810             * @param x1 the X coordinate that specifies the start point
0811             *           of a {@code CubicCurve2D}
0812             * @param y1 the Y coordinate that specifies the start point
0813             *           of a {@code CubicCurve2D}
0814             * @param ctrlx1 the X coordinate that specifies the first control point
0815             *               of a {@code CubicCurve2D}
0816             * @param ctrly1 the Y coordinate that specifies the first control point
0817             *               of a {@code CubicCurve2D}
0818             * @param ctrlx2 the X coordinate that specifies the second control point
0819             *               of a {@code CubicCurve2D}
0820             * @param ctrly2 the Y coordinate that specifies the second control point
0821             *               of a {@code CubicCurve2D}
0822             * @param x2 the X coordinate that specifies the end point
0823             *           of a {@code CubicCurve2D}
0824             * @param y2 the Y coordinate that specifies the end point
0825             *           of a {@code CubicCurve2D}
0826             * @return the flatness of the {@code CubicCurve2D}
0827             *		represented by the specified coordinates.
0828             * @since 1.2
0829             */
0830            public static double getFlatness(double x1, double y1,
0831                    double ctrlx1, double ctrly1, double ctrlx2, double ctrly2,
0832                    double x2, double y2) {
0833                return Math.sqrt(getFlatnessSq(x1, y1, ctrlx1, ctrly1, ctrlx2,
0834                        ctrly2, x2, y2));
0835            }
0836
0837            /**
0838             * Returns the square of the flatness of the cubic curve specified
0839             * by the control points stored in the indicated array at the 
0840             * indicated index. The flatness is the maximum distance 
0841             * of a control point from the line connecting the end points.
0842             * @param coords an array containing coordinates
0843             * @param offset the index of <code>coords</code> from which to begin 
0844             *          getting the end points and control points of the curve
0845             * @return the square of the flatness of the <code>CubicCurve2D</code>
0846             *		specified by the coordinates in <code>coords</code> at
0847             *		the specified offset.
0848             * @since 1.2
0849             */
0850            public static double getFlatnessSq(double coords[], int offset) {
0851                return getFlatnessSq(coords[offset + 0], coords[offset + 1],
0852                        coords[offset + 2], coords[offset + 3],
0853                        coords[offset + 4], coords[offset + 5],
0854                        coords[offset + 6], coords[offset + 7]);
0855            }
0856
0857            /**
0858             * Returns the flatness of the cubic curve specified
0859             * by the control points stored in the indicated array at the 
0860             * indicated index.  The flatness is the maximum distance 
0861             * of a control point from the line connecting the end points.
0862             * @param coords an array containing coordinates
0863             * @param offset the index of <code>coords</code> from which to begin 
0864             *          getting the end points and control points of the curve
0865             * @return the flatness of the <code>CubicCurve2D</code>
0866             *		specified by the coordinates in <code>coords</code> at
0867             *		the specified offset.
0868             * @since 1.2
0869             */
0870            public static double getFlatness(double coords[], int offset) {
0871                return getFlatness(coords[offset + 0], coords[offset + 1],
0872                        coords[offset + 2], coords[offset + 3],
0873                        coords[offset + 4], coords[offset + 5],
0874                        coords[offset + 6], coords[offset + 7]);
0875            }
0876
0877            /**
0878             * Returns the square of the flatness of this curve.  The flatness is the 
0879             * maximum distance of a control point from the line connecting the 
0880             * end points.
0881             * @return the square of the flatness of this curve.
0882             * @since 1.2
0883             */
0884            public double getFlatnessSq() {
0885                return getFlatnessSq(getX1(), getY1(), getCtrlX1(),
0886                        getCtrlY1(), getCtrlX2(), getCtrlY2(), getX2(), getY2());
0887            }
0888
0889            /**
0890             * Returns the flatness of this curve.  The flatness is the 
0891             * maximum distance of a control point from the line connecting the 
0892             * end points.
0893             * @return the flatness of this curve.
0894             * @since 1.2
0895             */
0896            public double getFlatness() {
0897                return getFlatness(getX1(), getY1(), getCtrlX1(), getCtrlY1(),
0898                        getCtrlX2(), getCtrlY2(), getX2(), getY2());
0899            }
0900
0901            /**
0902             * Subdivides this cubic curve and stores the resulting two
0903             * subdivided curves into the left and right curve parameters.
0904             * Either or both of the left and right objects may be the same
0905             * as this object or null.
0906             * @param left the cubic curve object for storing for the left or
0907             * first half of the subdivided curve
0908             * @param right the cubic curve object for storing for the right or
0909             * second half of the subdivided curve
0910             * @since 1.2
0911             */
0912            public void subdivide(CubicCurve2D left, CubicCurve2D right) {
0913                subdivide(this , left, right);
0914            }
0915
0916            /**
0917             * Subdivides the cubic curve specified by the <code>src</code> parameter
0918             * and stores the resulting two subdivided curves into the 
0919             * <code>left</code> and <code>right</code> curve parameters.
0920             * Either or both of the <code>left</code> and <code>right</code> objects 
0921             * may be the same as the <code>src</code> object or <code>null</code>.
0922             * @param src the cubic curve to be subdivided
0923             * @param left the cubic curve object for storing the left or
0924             * first half of the subdivided curve
0925             * @param right the cubic curve object for storing the right or
0926             * second half of the subdivided curve
0927             * @since 1.2
0928             */
0929            public static void subdivide(CubicCurve2D src, CubicCurve2D left,
0930                    CubicCurve2D right) {
0931                double x1 = src.getX1();
0932                double y1 = src.getY1();
0933                double ctrlx1 = src.getCtrlX1();
0934                double ctrly1 = src.getCtrlY1();
0935                double ctrlx2 = src.getCtrlX2();
0936                double ctrly2 = src.getCtrlY2();
0937                double x2 = src.getX2();
0938                double y2 = src.getY2();
0939                double centerx = (ctrlx1 + ctrlx2) / 2.0;
0940                double centery = (ctrly1 + ctrly2) / 2.0;
0941                ctrlx1 = (x1 + ctrlx1) / 2.0;
0942                ctrly1 = (y1 + ctrly1) / 2.0;
0943                ctrlx2 = (x2 + ctrlx2) / 2.0;
0944                ctrly2 = (y2 + ctrly2) / 2.0;
0945                double ctrlx12 = (ctrlx1 + centerx) / 2.0;
0946                double ctrly12 = (ctrly1 + centery) / 2.0;
0947                double ctrlx21 = (ctrlx2 + centerx) / 2.0;
0948                double ctrly21 = (ctrly2 + centery) / 2.0;
0949                centerx = (ctrlx12 + ctrlx21) / 2.0;
0950                centery = (ctrly12 + ctrly21) / 2.0;
0951                if (left != null) {
0952                    left.setCurve(x1, y1, ctrlx1, ctrly1, ctrlx12, ctrly12,
0953                            centerx, centery);
0954                }
0955                if (right != null) {
0956                    right.setCurve(centerx, centery, ctrlx21, ctrly21, ctrlx2,
0957                            ctrly2, x2, y2);
0958                }
0959            }
0960
0961            /**
0962             * Subdivides the cubic curve specified by the coordinates
0963             * stored in the <code>src</code> array at indices <code>srcoff</code> 
0964             * through (<code>srcoff</code>&nbsp;+&nbsp;7) and stores the
0965             * resulting two subdivided curves into the two result arrays at the
0966             * corresponding indices.
0967             * Either or both of the <code>left</code> and <code>right</code>
0968             * arrays may be <code>null</code> or a reference to the same array 
0969             * as the <code>src</code> array.
0970             * Note that the last point in the first subdivided curve is the
0971             * same as the first point in the second subdivided curve. Thus,
0972             * it is possible to pass the same array for <code>left</code>
0973             * and <code>right</code> and to use offsets, such as <code>rightoff</code>
0974             * equals (<code>leftoff</code> + 6), in order
0975             * to avoid allocating extra storage for this common point.
0976             * @param src the array holding the coordinates for the source curve
0977             * @param srcoff the offset into the array of the beginning of the
0978             * the 6 source coordinates
0979             * @param left the array for storing the coordinates for the first
0980             * half of the subdivided curve
0981             * @param leftoff the offset into the array of the beginning of the
0982             * the 6 left coordinates
0983             * @param right the array for storing the coordinates for the second
0984             * half of the subdivided curve
0985             * @param rightoff the offset into the array of the beginning of the
0986             * the 6 right coordinates
0987             * @since 1.2
0988             */
0989            public static void subdivide(double src[], int srcoff,
0990                    double left[], int leftoff, double right[], int rightoff) {
0991                double x1 = src[srcoff + 0];
0992                double y1 = src[srcoff + 1];
0993                double ctrlx1 = src[srcoff + 2];
0994                double ctrly1 = src[srcoff + 3];
0995                double ctrlx2 = src[srcoff + 4];
0996                double ctrly2 = src[srcoff + 5];
0997                double x2 = src[srcoff + 6];
0998                double y2 = src[srcoff + 7];
0999                if (left != null) {
1000                    left[leftoff + 0] = x1;
1001                    left[leftoff + 1] = y1;
1002                }
1003                if (right != null) {
1004                    right[rightoff + 6] = x2;
1005                    right[rightoff + 7] = y2;
1006                }
1007                x1 = (x1 + ctrlx1) / 2.0;
1008                y1 = (y1 + ctrly1) / 2.0;
1009                x2 = (x2 + ctrlx2) / 2.0;
1010                y2 = (y2 + ctrly2) / 2.0;
1011                double centerx = (ctrlx1 + ctrlx2) / 2.0;
1012                double centery = (ctrly1 + ctrly2) / 2.0;
1013                ctrlx1 = (x1 + centerx) / 2.0;
1014                ctrly1 = (y1 + centery) / 2.0;
1015                ctrlx2 = (x2 + centerx) / 2.0;
1016                ctrly2 = (y2 + centery) / 2.0;
1017                centerx = (ctrlx1 + ctrlx2) / 2.0;
1018                centery = (ctrly1 + ctrly2) / 2.0;
1019                if (left != null) {
1020                    left[leftoff + 2] = x1;
1021                    left[leftoff + 3] = y1;
1022                    left[leftoff + 4] = ctrlx1;
1023                    left[leftoff + 5] = ctrly1;
1024                    left[leftoff + 6] = centerx;
1025                    left[leftoff + 7] = centery;
1026                }
1027                if (right != null) {
1028                    right[rightoff + 0] = centerx;
1029                    right[rightoff + 1] = centery;
1030                    right[rightoff + 2] = ctrlx2;
1031                    right[rightoff + 3] = ctrly2;
1032                    right[rightoff + 4] = x2;
1033                    right[rightoff + 5] = y2;
1034                }
1035            }
1036
1037            /**
1038             * Solves the cubic whose coefficients are in the <code>eqn</code> 
1039             * array and places the non-complex roots back into the same array, 
1040             * returning the number of roots.  The solved cubic is represented 
1041             * by the equation:
1042             * <pre>
1043             *     eqn = {c, b, a, d}
1044             *     dx^3 + ax^2 + bx + c = 0
1045             * </pre>
1046             * A return value of -1 is used to distinguish a constant equation
1047             * that might be always 0 or never 0 from an equation that has no
1048             * zeroes.
1049             * @param eqn an array containing coefficients for a cubic
1050             * @return the number of roots, or -1 if the equation is a constant.
1051             * @since 1.2
1052             */
1053            public static int solveCubic(double eqn[]) {
1054                return solveCubic(eqn, eqn);
1055            }
1056
1057            /**
1058             * Solve the cubic whose coefficients are in the <code>eqn</code>
1059             * array and place the non-complex roots into the <code>res</code>
1060             * array, returning the number of roots.
1061             * The cubic solved is represented by the equation:
1062             *     eqn = {c, b, a, d}
1063             *     dx^3 + ax^2 + bx + c = 0
1064             * A return value of -1 is used to distinguish a constant equation,
1065             * which may be always 0 or never 0, from an equation which has no
1066             * zeroes.
1067             * @param eqn the specified array of coefficients to use to solve
1068             *        the cubic equation
1069             * @param res the array that contains the non-complex roots 
1070             *        resulting from the solution of the cubic equation
1071             * @return the number of roots, or -1 if the equation is a constant
1072             * @since 1.3
1073             */
1074            public static int solveCubic(double eqn[], double res[]) {
1075                // From Numerical Recipes, 5.6, Quadratic and Cubic Equations
1076                double d = eqn[3];
1077                if (d == 0.0) {
1078                    // The cubic has degenerated to quadratic (or line or ...).
1079                    return QuadCurve2D.solveQuadratic(eqn, res);
1080                }
1081                double a = eqn[2] / d;
1082                double b = eqn[1] / d;
1083                double c = eqn[0] / d;
1084                int roots = 0;
1085                double Q = (a * a - 3.0 * b) / 9.0;
1086                double R = (2.0 * a * a * a - 9.0 * a * b + 27.0 * c) / 54.0;
1087                double R2 = R * R;
1088                double Q3 = Q * Q * Q;
1089                a = a / 3.0;
1090                if (R2 < Q3) {
1091                    double theta = Math.acos(R / Math.sqrt(Q3));
1092                    Q = -2.0 * Math.sqrt(Q);
1093                    if (res == eqn) {
1094                        // Copy the eqn so that we don't clobber it with the
1095                        // roots.  This is needed so that fixRoots can do its
1096                        // work with the original equation.
1097                        eqn = new double[4];
1098                        System.arraycopy(res, 0, eqn, 0, 4);
1099                    }
1100                    res[roots++] = Q * Math.cos(theta / 3.0) - a;
1101                    res[roots++] = Q * Math.cos((theta + Math.PI * 2.0) / 3.0)
1102                            - a;
1103                    res[roots++] = Q * Math.cos((theta - Math.PI * 2.0) / 3.0)
1104                            - a;
1105                    fixRoots(res, eqn);
1106                } else {
1107                    boolean neg = (R < 0.0);
1108                    double S = Math.sqrt(R2 - Q3);
1109                    if (neg) {
1110                        R = -R;
1111                    }
1112                    double A = Math.pow(R + S, 1.0 / 3.0);
1113                    if (!neg) {
1114                        A = -A;
1115                    }
1116                    double B = (A == 0.0) ? 0.0 : (Q / A);
1117                    res[roots++] = (A + B) - a;
1118                }
1119                return roots;
1120            }
1121
1122            /*
1123             * This pruning step is necessary since solveCubic uses the
1124             * cosine function to calculate the roots when there are 3
1125             * of them.  Since the cosine method can have an error of
1126             * +/- 1E-14 we need to make sure that we don't make any
1127             * bad decisions due to an error.
1128             * 
1129             * If the root is not near one of the endpoints, then we will
1130             * only have a slight inaccuracy in calculating the x intercept
1131             * which will only cause a slightly wrong answer for some
1132             * points very close to the curve.  While the results in that
1133             * case are not as accurate as they could be, they are not
1134             * disastrously inaccurate either.
1135             * 
1136             * On the other hand, if the error happens near one end of
1137             * the curve, then our processing to reject values outside
1138             * of the t=[0,1] range will fail and the results of that
1139             * failure will be disastrous since for an entire horizontal
1140             * range of test points, we will either overcount or undercount
1141             * the crossings and get a wrong answer for all of them, even
1142             * when they are clearly and obviously inside or outside the
1143             * curve.
1144             * 
1145             * To work around this problem, we try a couple of Newton-Raphson
1146             * iterations to see if the true root is closer to the endpoint
1147             * or further away.  If it is further away, then we can stop
1148             * since we know we are on the right side of the endpoint.  If
1149             * we change direction, then either we are now being dragged away
1150             * from the endpoint in which case the first condition will cause
1151             * us to stop, or we have passed the endpoint and are headed back.
1152             * In the second case, we simply evaluate the slope at the
1153             * endpoint itself and place ourselves on the appropriate side
1154             * of it or on it depending on that result.
1155             */
1156            private static void fixRoots(double res[], double eqn[]) {
1157                final double EPSILON = 1E-5;
1158                for (int i = 0; i < 3; i++) {
1159                    double t = res[i];
1160                    if (Math.abs(t) < EPSILON) {
1161                        res[i] = findZero(t, 0, eqn);
1162                    } else if (Math.abs(t - 1) < EPSILON) {
1163                        res[i] = findZero(t, 1, eqn);
1164                    }
1165                }
1166            }
1167
1168            private static double solveEqn(double eqn[], int order, double t) {
1169                double v = eqn[order];
1170                while (--order >= 0) {
1171                    v = v * t + eqn[order];
1172                }
1173                return v;
1174            }
1175
1176            private static double findZero(double t, double target,
1177                    double eqn[]) {
1178                double slopeqn[] = { eqn[1], 2 * eqn[2], 3 * eqn[3] };
1179                double slope;
1180                double origdelta = 0;
1181                double origt = t;
1182                while (true) {
1183                    slope = solveEqn(slopeqn, 2, t);
1184                    if (slope == 0) {
1185                        // At a local minima - must return
1186                        return t;
1187                    }
1188                    double y = solveEqn(eqn, 3, t);
1189                    if (y == 0) {
1190                        // Found it! - return it
1191                        return t;
1192                    }
1193                    // assert(slope != 0 && y != 0);
1194                    double delta = -(y / slope);
1195                    // assert(delta != 0);
1196                    if (origdelta == 0) {
1197                        origdelta = delta;
1198                    }
1199                    if (t < target) {
1200                        if (delta < 0)
1201                            return t;
1202                    } else if (t > target) {
1203                        if (delta > 0)
1204                            return t;
1205                    } else { /* t == target */
1206                        return (delta > 0 ? (target + java.lang.Double.MIN_VALUE)
1207                                : (target - java.lang.Double.MIN_VALUE));
1208                    }
1209                    double newt = t + delta;
1210                    if (t == newt) {
1211                        // The deltas are so small that we aren't moving...
1212                        return t;
1213                    }
1214                    if (delta * origdelta < 0) {
1215                        // We have reversed our path.
1216                        int tag = (origt < t ? getTag(target, origt, t)
1217                                : getTag(target, t, origt));
1218                        if (tag != INSIDE) {
1219                            // Local minima found away from target - return the middle
1220                            return (origt + t) / 2;
1221                        }
1222                        // Local minima somewhere near target - move to target
1223                        // and let the slope determine the resulting t.
1224                        t = target;
1225                    } else {
1226                        t = newt;
1227                    }
1228                }
1229            }
1230
1231            /**
1232             * {@inheritDoc}
1233             * @since 1.2
1234             */
1235            public boolean contains(double x, double y) {
1236                if (!(x * 0.0 + y * 0.0 == 0.0)) {
1237                    /* Either x or y was infinite or NaN.
1238                     * A NaN always produces a negative response to any test
1239                     * and Infinity values cannot be "inside" any path so
1240                     * they should return false as well.
1241                     */
1242                    return false;
1243                }
1244                // We count the "Y" crossings to determine if the point is
1245                // inside the curve bounded by its closing line.
1246                double x1 = getX1();
1247                double y1 = getY1();
1248                double x2 = getX2();
1249                double y2 = getY2();
1250                int crossings = (Curve.pointCrossingsForLine(x, y, x1, y1, x2,
1251                        y2) + Curve.pointCrossingsForCubic(x, y, x1, y1,
1252                        getCtrlX1(), getCtrlY1(), getCtrlX2(), getCtrlY2(), x2,
1253                        y2, 0));
1254                return ((crossings & 1) == 1);
1255            }
1256
1257            /**
1258             * {@inheritDoc}
1259             * @since 1.2
1260             */
1261            public boolean contains(Point2D p) {
1262                return contains(p.getX(), p.getY());
1263            }
1264
1265            /*
1266             * Fill an array with the coefficients of the parametric equation
1267             * in t, ready for solving against val with solveCubic.
1268             * We currently have:
1269             * <pre>
1270             *   val = P(t) = C1(1-t)^3 + 3CP1 t(1-t)^2 + 3CP2 t^2(1-t) + C2 t^3
1271             *              = C1 - 3C1t + 3C1t^2 - C1t^3 +
1272             *                3CP1t - 6CP1t^2 + 3CP1t^3 +
1273             *                3CP2t^2 - 3CP2t^3 +
1274             *                C2t^3
1275             *            0 = (C1 - val) +
1276             *                (3CP1 - 3C1) t +
1277             *                (3C1 - 6CP1 + 3CP2) t^2 +
1278             *                (C2 - 3CP2 + 3CP1 - C1) t^3
1279             *            0 = C + Bt + At^2 + Dt^3
1280             *     C = C1 - val
1281             *     B = 3*CP1 - 3*C1
1282             *     A = 3*CP2 - 6*CP1 + 3*C1
1283             *     D = C2 - 3*CP2 + 3*CP1 - C1
1284             * </pre>
1285             */
1286            private static void fillEqn(double eqn[], double val, double c1,
1287                    double cp1, double cp2, double c2) {
1288                eqn[0] = c1 - val;
1289                eqn[1] = (cp1 - c1) * 3.0;
1290                eqn[2] = (cp2 - cp1 - cp1 + c1) * 3.0;
1291                eqn[3] = c2 + (cp1 - cp2) * 3.0 - c1;
1292                return;
1293            }
1294
1295            /*
1296             * Evaluate the t values in the first num slots of the vals[] array
1297             * and place the evaluated values back into the same array.  Only
1298             * evaluate t values that are within the range <0, 1>, including
1299             * the 0 and 1 ends of the range iff the include0 or include1
1300             * booleans are true.  If an "inflection" equation is handed in,
1301             * then any points which represent a point of inflection for that
1302             * cubic equation are also ignored.
1303             */
1304            private static int evalCubic(double vals[], int num,
1305                    boolean include0, boolean include1, double inflect[],
1306                    double c1, double cp1, double cp2, double c2) {
1307                int j = 0;
1308                for (int i = 0; i < num; i++) {
1309                    double t = vals[i];
1310                    if ((include0 ? t >= 0 : t > 0)
1311                            && (include1 ? t <= 1 : t < 1)
1312                            && (inflect == null || inflect[1]
1313                                    + (2 * inflect[2] + 3 * inflect[3] * t) * t != 0)) {
1314                        double u = 1 - t;
1315                        vals[j++] = c1 * u * u * u + 3 * cp1 * t * u * u + 3
1316                                * cp2 * t * t * u + c2 * t * t * t;
1317                    }
1318                }
1319                return j;
1320            }
1321
1322            private static final int BELOW = -2;
1323            private static final int LOWEDGE = -1;
1324            private static final int INSIDE = 0;
1325            private static final int HIGHEDGE = 1;
1326            private static final int ABOVE = 2;
1327
1328            /*
1329             * Determine where coord lies with respect to the range from
1330             * low to high.  It is assumed that low <= high.  The return
1331             * value is one of the 5 values BELOW, LOWEDGE, INSIDE, HIGHEDGE,
1332             * or ABOVE.
1333             */
1334            private static int getTag(double coord, double low, double high) {
1335                if (coord <= low) {
1336                    return (coord < low ? BELOW : LOWEDGE);
1337                }
1338                if (coord >= high) {
1339                    return (coord > high ? ABOVE : HIGHEDGE);
1340                }
1341                return INSIDE;
1342            }
1343
1344            /*
1345             * Determine if the pttag represents a coordinate that is already
1346             * in its test range, or is on the border with either of the two
1347             * opttags representing another coordinate that is "towards the
1348             * inside" of that test range.  In other words, are either of the
1349             * two "opt" points "drawing the pt inward"?
1350             */
1351            private static boolean inwards(int pttag, int opt1tag, int opt2tag) {
1352                switch (pttag) {
1353                case BELOW:
1354                case ABOVE:
1355                default:
1356                    return false;
1357                case LOWEDGE:
1358                    return (opt1tag >= INSIDE || opt2tag >= INSIDE);
1359                case INSIDE:
1360                    return true;
1361                case HIGHEDGE:
1362                    return (opt1tag <= INSIDE || opt2tag <= INSIDE);
1363                }
1364            }
1365
1366            /**
1367             * {@inheritDoc}
1368             * @since 1.2
1369             */
1370            public boolean intersects(double x, double y, double w, double h) {
1371                // Trivially reject non-existant rectangles
1372                if (w <= 0 || h <= 0) {
1373                    return false;
1374                }
1375
1376                // Trivially accept if either endpoint is inside the rectangle
1377                // (not on its border since it may end there and not go inside)
1378                // Record where they lie with respect to the rectangle.
1379                //     -1 => left, 0 => inside, 1 => right
1380                double x1 = getX1();
1381                double y1 = getY1();
1382                int x1tag = getTag(x1, x, x + w);
1383                int y1tag = getTag(y1, y, y + h);
1384                if (x1tag == INSIDE && y1tag == INSIDE) {
1385                    return true;
1386                }
1387                double x2 = getX2();
1388                double y2 = getY2();
1389                int x2tag = getTag(x2, x, x + w);
1390                int y2tag = getTag(y2, y, y + h);
1391                if (x2tag == INSIDE && y2tag == INSIDE) {
1392                    return true;
1393                }
1394
1395                double ctrlx1 = getCtrlX1();
1396                double ctrly1 = getCtrlY1();
1397                double ctrlx2 = getCtrlX2();
1398                double ctrly2 = getCtrlY2();
1399                int ctrlx1tag = getTag(ctrlx1, x, x + w);
1400                int ctrly1tag = getTag(ctrly1, y, y + h);
1401                int ctrlx2tag = getTag(ctrlx2, x, x + w);
1402                int ctrly2tag = getTag(ctrly2, y, y + h);
1403
1404                // Trivially reject if all points are entirely to one side of
1405                // the rectangle.
1406                if (x1tag < INSIDE && x2tag < INSIDE && ctrlx1tag < INSIDE
1407                        && ctrlx2tag < INSIDE) {
1408                    return false; // All points left
1409                }
1410                if (y1tag < INSIDE && y2tag < INSIDE && ctrly1tag < INSIDE
1411                        && ctrly2tag < INSIDE) {
1412                    return false; // All points above
1413                }
1414                if (x1tag > INSIDE && x2tag > INSIDE && ctrlx1tag > INSIDE
1415                        && ctrlx2tag > INSIDE) {
1416                    return false; // All points right
1417                }
1418                if (y1tag > INSIDE && y2tag > INSIDE && ctrly1tag > INSIDE
1419                        && ctrly2tag > INSIDE) {
1420                    return false; // All points below
1421                }
1422
1423                // Test for endpoints on the edge where either the segment
1424                // or the curve is headed "inwards" from them
1425                // Note: These tests are a superset of the fast endpoint tests
1426                //       above and thus repeat those tests, but take more time
1427                //       and cover more cases
1428                if (inwards(x1tag, x2tag, ctrlx1tag)
1429                        && inwards(y1tag, y2tag, ctrly1tag)) {
1430                    // First endpoint on border with either edge moving inside
1431                    return true;
1432                }
1433                if (inwards(x2tag, x1tag, ctrlx2tag)
1434                        && inwards(y2tag, y1tag, ctrly2tag)) {
1435                    // Second endpoint on border with either edge moving inside
1436                    return true;
1437                }
1438
1439                // Trivially accept if endpoints span directly across the rectangle
1440                boolean xoverlap = (x1tag * x2tag <= 0);
1441                boolean yoverlap = (y1tag * y2tag <= 0);
1442                if (x1tag == INSIDE && x2tag == INSIDE && yoverlap) {
1443                    return true;
1444                }
1445                if (y1tag == INSIDE && y2tag == INSIDE && xoverlap) {
1446                    return true;
1447                }
1448
1449                // We now know that both endpoints are outside the rectangle
1450                // but the 4 points are not all on one side of the rectangle.
1451                // Therefore the curve cannot be contained inside the rectangle,
1452                // but the rectangle might be contained inside the curve, or
1453                // the curve might intersect the boundary of the rectangle.
1454
1455                double[] eqn = new double[4];
1456                double[] res = new double[4];
1457                if (!yoverlap) {
1458                    // Both y coordinates for the closing segment are above or
1459                    // below the rectangle which means that we can only intersect
1460                    // if the curve crosses the top (or bottom) of the rectangle
1461                    // in more than one place and if those crossing locations
1462                    // span the horizontal range of the rectangle.
1463                    fillEqn(eqn, (y1tag < INSIDE ? y : y + h), y1, ctrly1,
1464                            ctrly2, y2);
1465                    int num = solveCubic(eqn, res);
1466                    num = evalCubic(res, num, true, true, null, x1, ctrlx1,
1467                            ctrlx2, x2);
1468                    // odd counts imply the crossing was out of [0,1] bounds
1469                    // otherwise there is no way for that part of the curve to
1470                    // "return" to meet its endpoint
1471                    return (num == 2 && getTag(res[0], x, x + w)
1472                            * getTag(res[1], x, x + w) <= 0);
1473                }
1474
1475                // Y ranges overlap.  Now we examine the X ranges
1476                if (!xoverlap) {
1477                    // Both x coordinates for the closing segment are left of
1478                    // or right of the rectangle which means that we can only
1479                    // intersect if the curve crosses the left (or right) edge
1480                    // of the rectangle in more than one place and if those
1481                    // crossing locations span the vertical range of the rectangle.
1482                    fillEqn(eqn, (x1tag < INSIDE ? x : x + w), x1, ctrlx1,
1483                            ctrlx2, x2);
1484                    int num = solveCubic(eqn, res);
1485                    num = evalCubic(res, num, true, true, null, y1, ctrly1,
1486                            ctrly2, y2);
1487                    // odd counts imply the crossing was out of [0,1] bounds
1488                    // otherwise there is no way for that part of the curve to
1489                    // "return" to meet its endpoint
1490                    return (num == 2 && getTag(res[0], y, y + h)
1491                            * getTag(res[1], y, y + h) <= 0);
1492                }
1493
1494                // The X and Y ranges of the endpoints overlap the X and Y
1495                // ranges of the rectangle, now find out how the endpoint
1496                // line segment intersects the Y range of the rectangle
1497                double dx = x2 - x1;
1498                double dy = y2 - y1;
1499                double k = y2 * x1 - x2 * y1;
1500                int c1tag, c2tag;
1501                if (y1tag == INSIDE) {
1502                    c1tag = x1tag;
1503                } else {
1504                    c1tag = getTag(
1505                            (k + dx * (y1tag < INSIDE ? y : y + h)) / dy, x, x
1506                                    + w);
1507                }
1508                if (y2tag == INSIDE) {
1509                    c2tag = x2tag;
1510                } else {
1511                    c2tag = getTag(
1512                            (k + dx * (y2tag < INSIDE ? y : y + h)) / dy, x, x
1513                                    + w);
1514                }
1515                // If the part of the line segment that intersects the Y range
1516                // of the rectangle crosses it horizontally - trivially accept
1517                if (c1tag * c2tag <= 0) {
1518                    return true;
1519                }
1520
1521                // Now we know that both the X and Y ranges intersect and that
1522                // the endpoint line segment does not directly cross the rectangle.
1523                //
1524                // We can almost treat this case like one of the cases above
1525                // where both endpoints are to one side, except that we may
1526                // get one or three intersections of the curve with the vertical
1527                // side of the rectangle.  This is because the endpoint segment
1528                // accounts for the other intersection in an even pairing.  Thus,
1529                // with the endpoint crossing we end up with 2 or 4 total crossings.
1530                //
1531                // (Remember there is overlap in both the X and Y ranges which
1532                //  means that the segment itself must cross at least one vertical
1533                //  edge of the rectangle - in particular, the "near vertical side"
1534                //  - leaving an odd number of intersections for the curve.)
1535                //
1536                // Now we calculate the y tags of all the intersections on the
1537                // "near vertical side" of the rectangle.  We will have one with
1538                // the endpoint segment, and one or three with the curve.  If
1539                // any pair of those vertical intersections overlap the Y range
1540                // of the rectangle, we have an intersection.  Otherwise, we don't.
1541
1542                // c1tag = vertical intersection class of the endpoint segment
1543                //
1544                // Choose the y tag of the endpoint that was not on the same
1545                // side of the rectangle as the subsegment calculated above.
1546                // Note that we can "steal" the existing Y tag of that endpoint
1547                // since it will be provably the same as the vertical intersection.
1548                c1tag = ((c1tag * x1tag <= 0) ? y1tag : y2tag);
1549
1550                // Now we have to calculate an array of solutions of the curve
1551                // with the "near vertical side" of the rectangle.  Then we
1552                // need to sort the tags and do a pairwise range test to see
1553                // if either of the pairs of crossings spans the Y range of
1554                // the rectangle.
1555                //
1556                // Note that the c2tag can still tell us which vertical edge
1557                // to test against.
1558                fillEqn(eqn, (c2tag < INSIDE ? x : x + w), x1, ctrlx1, ctrlx2,
1559                        x2);
1560                int num = solveCubic(eqn, res);
1561                num = evalCubic(res, num, true, true, null, y1, ctrly1, ctrly2,
1562                        y2);
1563
1564                // Now put all of the tags into a bucket and sort them.  There
1565                // is an intersection iff one of the pairs of tags "spans" the
1566                // Y range of the rectangle.
1567                int tags[] = new int[num + 1];
1568                for (int i = 0; i < num; i++) {
1569                    tags[i] = getTag(res[i], y, y + h);
1570                }
1571                tags[num] = c1tag;
1572                Arrays.sort(tags);
1573                return ((num >= 1 && tags[0] * tags[1] <= 0) || (num >= 3 && tags[2]
1574                        * tags[3] <= 0));
1575            }
1576
1577            /**
1578             * {@inheritDoc}
1579             * @since 1.2
1580             */
1581            public boolean intersects(Rectangle2D r) {
1582                return intersects(r.getX(), r.getY(), r.getWidth(), r
1583                        .getHeight());
1584            }
1585
1586            /**
1587             * {@inheritDoc}
1588             * @since 1.2
1589             */
1590            public boolean contains(double x, double y, double w, double h) {
1591                if (w <= 0 || h <= 0) {
1592                    return false;
1593                }
1594                // Assertion: Cubic curves closed by connecting their
1595                // endpoints form either one or two convex halves with
1596                // the closing line segment as an edge of both sides.
1597                if (!(contains(x, y) && contains(x + w, y)
1598                        && contains(x + w, y + h) && contains(x, y + h))) {
1599                    return false;
1600                }
1601                // Either the rectangle is entirely inside one of the convex
1602                // halves or it crosses from one to the other, in which case
1603                // it must intersect the closing line segment.
1604                Rectangle2D rect = new Rectangle2D.Double(x, y, w, h);
1605                return !rect.intersectsLine(getX1(), getY1(), getX2(), getY2());
1606            }
1607
1608            /**
1609             * {@inheritDoc}
1610             * @since 1.2
1611             */
1612            public boolean contains(Rectangle2D r) {
1613                return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
1614            }
1615
1616            /**
1617             * {@inheritDoc}
1618             * @since 1.2
1619             */
1620            public Rectangle getBounds() {
1621                return getBounds2D().getBounds();
1622            }
1623
1624            /**
1625             * Returns an iteration object that defines the boundary of the
1626             * shape.
1627             * The iterator for this class is not multi-threaded safe,
1628             * which means that this <code>CubicCurve2D</code> class does not
1629             * guarantee that modifications to the geometry of this
1630             * <code>CubicCurve2D</code> object do not affect any iterations of
1631             * that geometry that are already in process.
1632             * @param at an optional <code>AffineTransform</code> to be applied to the
1633             * coordinates as they are returned in the iteration, or <code>null</code>
1634             * if untransformed coordinates are desired
1635             * @return    the <code>PathIterator</code> object that returns the
1636             *          geometry of the outline of this <code>CubicCurve2D</code>, one
1637             *          segment at a time.
1638             * @since 1.2
1639             */
1640            public PathIterator getPathIterator(AffineTransform at) {
1641                return new CubicIterator(this , at);
1642            }
1643
1644            /**
1645             * Return an iteration object that defines the boundary of the
1646             * flattened shape.
1647             * The iterator for this class is not multi-threaded safe,
1648             * which means that this <code>CubicCurve2D</code> class does not
1649             * guarantee that modifications to the geometry of this
1650             * <code>CubicCurve2D</code> object do not affect any iterations of
1651             * that geometry that are already in process.
1652             * @param at an optional <code>AffineTransform</code> to be applied to the
1653             * coordinates as they are returned in the iteration, or <code>null</code>
1654             * if untransformed coordinates are desired
1655             * @param flatness the maximum amount that the control points
1656             * for a given curve can vary from colinear before a subdivided
1657             * curve is replaced by a straight line connecting the end points
1658             * @return    the <code>PathIterator</code> object that returns the
1659             * geometry of the outline of this <code>CubicCurve2D</code>,
1660             * one segment at a time.
1661             * @since 1.2
1662             */
1663            public PathIterator getPathIterator(AffineTransform at,
1664                    double flatness) {
1665                return new FlatteningPathIterator(getPathIterator(at), flatness);
1666            }
1667
1668            /**
1669             * Creates a new object of the same class as this object.
1670             *
1671             * @return     a clone of this instance.
1672             * @exception  OutOfMemoryError            if there is not enough memory.
1673             * @see        java.lang.Cloneable
1674             * @since      1.2
1675             */
1676            public Object clone() {
1677                try {
1678                    return super .clone();
1679                } catch (CloneNotSupportedException e) {
1680                    // this shouldn't happen, since we are Cloneable
1681                    throw new InternalError();
1682                }
1683            }
1684        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.