1 /*
   2  * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javafx.scene.shape;
  27 
  28 import com.sun.javafx.geom.CubicCurve2D;
  29 import com.sun.javafx.scene.DirtyBits;
  30 import com.sun.javafx.scene.NodeHelper;
  31 import com.sun.javafx.scene.shape.CubicCurveHelper;
  32 import com.sun.javafx.sg.prism.NGCubicCurve;
  33 import com.sun.javafx.sg.prism.NGNode;
  34 import javafx.beans.property.DoubleProperty;
  35 import javafx.beans.property.DoublePropertyBase;
  36 import javafx.scene.Node;
  37 import javafx.scene.paint.Paint;
  38 
  39 
  40 /**
  41  * <p>The {@code CubiCurve} class defines a cubic B&eacute;zier parametric curve segment
  42  * in (x,y) coordinate space. Drawing a curve that intersects both the specified
  43  * coordinates {@code (startX, startY)} and {@code (endX, enfY)}, using the
  44  * specified points {@code (controlX1, controlY1)} and {@code (controlX2, controlY2)}
  45  * as B&eacute;zier control points.
  46  * Example:</p>
  47  *
  48 <PRE>
  49 import javafx.scene.shape.*;
  50 
  51 CubicCurve cubic = new CubicCurve();
  52 cubic.setStartX(0.0f);
  53 cubic.setStartY(50.0f);
  54 cubic.setControlX1(25.0f);
  55 cubic.setControlY1(0.0f);
  56 cubic.setControlX2(75.0f);
  57 cubic.setControlY2(100.0f);
  58 cubic.setEndX(100.0f);
  59 cubic.setEndY(50.0f);
  60 }
  61 </PRE>
  62  * @since JavaFX 2.0
  63  */
  64 public class CubicCurve extends Shape {
  65     static {
  66         CubicCurveHelper.setCubicCurveAccessor(new CubicCurveHelper.CubicCurveAccessor() {
  67             @Override
  68             public NGNode doCreatePeer(Node node) {
  69                 return ((CubicCurve) node).doCreatePeer();
  70             }
  71 
  72             @Override
  73             public void doUpdatePeer(Node node) {
  74                 ((CubicCurve) node).doUpdatePeer();
  75             }
  76 
  77             @Override
  78             public com.sun.javafx.geom.Shape doConfigShape(Shape shape) {
  79                 return ((CubicCurve) shape).doConfigShape();
  80             }
  81         });
  82     }
  83 
  84     private final CubicCurve2D shape = new CubicCurve2D();
  85     /**
  86      * Defines the X coordinate of the start point of the cubic curve segment.
  87      *
  88      * @defaultValue 0.0
  89      */
  90     private DoubleProperty startX;
  91 
  92     {
  93         // To initialize the class helper at the begining each constructor of this class
  94         CubicCurveHelper.initHelper(this);
  95     }
  96 
  97     /**
  98      * Creates an empty instance of CubicCurve.
  99      */
 100     public CubicCurve() {
 101     }
 102 
 103     /**
 104      * Creates a new instance of CubicCurve.
 105      * @param startX the X coordinate of the start point
 106      * @param startY the Y coordinate of the start point
 107      * @param controlX1 the X coordinate of the first control point
 108      * @param controlY1 the Y coordinate of the first control point
 109      * @param controlX2 the X coordinate of the second control point
 110      * @param controlY2 the Y coordinate of the second control point
 111      * @param endX the X coordinate of the end point
 112      * @param endY the Y coordinate of the end point
 113      * @since JavaFX 2.1
 114      */
 115     public CubicCurve(double startX, double startY, double controlX1,
 116             double controlY1, double controlX2, double controlY2,
 117             double endX, double endY) {
 118         setStartX(startX);
 119         setStartY(startY);
 120         setControlX1(controlX1);
 121         setControlY1(controlY1);
 122         setControlX2(controlX2);
 123         setControlY2(controlY2);
 124         setEndX(endX);
 125         setEndY(endY);
 126     }
 127 
 128     public final void setStartX(double value) {
 129         if (startX != null || value != 0.0) {
 130             startXProperty().set(value);
 131         }
 132     }
 133 
 134     public final double getStartX() {
 135         return startX == null ? 0.0 : startX.get();
 136     }
 137 
 138     public final DoubleProperty startXProperty() {
 139         if (startX == null) {
 140             startX = new DoublePropertyBase() {
 141 
 142                 @Override
 143                 public void invalidated() {
 144                     NodeHelper.markDirty(CubicCurve.this, DirtyBits.NODE_GEOMETRY);
 145                     impl_geomChanged();
 146                 }
 147 
 148                 @Override
 149                 public Object getBean() {
 150                     return CubicCurve.this;
 151                 }
 152 
 153                 @Override
 154                 public String getName() {
 155                     return "startX";
 156                 }
 157             };
 158         }
 159         return startX;
 160     }
 161 
 162     /**
 163      * Defines the Y coordinate of the start point of the cubic curve segment.
 164      *
 165      * @defaultValue 0.0
 166      */
 167     private DoubleProperty startY;
 168 
 169     public final void setStartY(double value) {
 170         if (startY != null || value != 0.0) {
 171             startYProperty().set(value);
 172         }
 173     }
 174 
 175     public final double getStartY() {
 176         return startY == null ? 0.0 : startY.get();
 177     }
 178 
 179     public final DoubleProperty startYProperty() {
 180         if (startY == null) {
 181             startY = new DoublePropertyBase() {
 182 
 183                 @Override
 184                 public void invalidated() {
 185                     NodeHelper.markDirty(CubicCurve.this, DirtyBits.NODE_GEOMETRY);
 186                     impl_geomChanged();
 187                 }
 188 
 189                 @Override
 190                 public Object getBean() {
 191                     return CubicCurve.this;
 192                 }
 193 
 194                 @Override
 195                 public String getName() {
 196                     return "startY";
 197                 }
 198             };
 199         }
 200         return startY;
 201     }
 202 
 203     /**
 204      * Defines the X coordinate of the first control point
 205      * of the cubic curve segment.
 206      *
 207      * @defaultValue 0.0
 208      */
 209     private DoubleProperty controlX1;
 210 
 211     public final void setControlX1(double value) {
 212         if (controlX1 != null || value != 0.0) {
 213             controlX1Property().set(value);
 214         }
 215     }
 216 
 217     public final double getControlX1() {
 218         return controlX1 == null ? 0.0 : controlX1.get();
 219     }
 220 
 221     public final DoubleProperty controlX1Property() {
 222         if (controlX1 == null) {
 223             controlX1 = new DoublePropertyBase() {
 224 
 225                 @Override
 226                 public void invalidated() {
 227                     NodeHelper.markDirty(CubicCurve.this, DirtyBits.NODE_GEOMETRY);
 228                     impl_geomChanged();
 229                 }
 230 
 231                 @Override
 232                 public Object getBean() {
 233                     return CubicCurve.this;
 234                 }
 235 
 236                 @Override
 237                 public String getName() {
 238                     return "controlX1";
 239                 }
 240             };
 241         }
 242         return controlX1;
 243     }
 244 
 245     /**
 246      * Defines the Y coordinate of the first control point
 247      * of the cubic curve segment.
 248      *
 249      * @defaultValue 0.0
 250      */
 251     private DoubleProperty controlY1;
 252 
 253     public final void setControlY1(double value) {
 254         if (controlY1 != null || value != 0.0) {
 255             controlY1Property().set(value);
 256         }
 257     }
 258 
 259     public final double getControlY1() {
 260         return controlY1 == null ? 0.0 : controlY1.get();
 261     }
 262 
 263     public final DoubleProperty controlY1Property() {
 264         if (controlY1 == null) {
 265             controlY1 = new DoublePropertyBase() {
 266 
 267                 @Override
 268                 public void invalidated() {
 269                     NodeHelper.markDirty(CubicCurve.this, DirtyBits.NODE_GEOMETRY);
 270                     impl_geomChanged();
 271                 }
 272 
 273                 @Override
 274                 public Object getBean() {
 275                     return CubicCurve.this;
 276                 }
 277 
 278                 @Override
 279                 public String getName() {
 280                     return "controlY1";
 281                 }
 282             };
 283         }
 284         return controlY1;
 285     }
 286 
 287     /**
 288      * Defines the X coordinate of the second control point
 289      * of the cubic curve segment.
 290      *
 291      * @defaultValue 0.0
 292      */
 293     private DoubleProperty controlX2;
 294 
 295     public final void setControlX2(double value) {
 296         if (controlX2 != null || value != 0.0) {
 297             controlX2Property().set(value);
 298         }
 299     }
 300 
 301     public final double getControlX2() {
 302         return controlX2 == null ? 0.0 : controlX2.get();
 303     }
 304 
 305     public final DoubleProperty controlX2Property() {
 306         if (controlX2 == null) {
 307             controlX2 = new DoublePropertyBase() {
 308 
 309                 @Override
 310                 public void invalidated() {
 311                     NodeHelper.markDirty(CubicCurve.this, DirtyBits.NODE_GEOMETRY);
 312                     impl_geomChanged();
 313                 }
 314 
 315                 @Override
 316                 public Object getBean() {
 317                     return CubicCurve.this;
 318                 }
 319 
 320                 @Override
 321                 public String getName() {
 322                     return "controlX2";
 323                 }
 324             };
 325         }
 326         return controlX2;
 327     }
 328 
 329     /**
 330      * Defines the Y coordinate of the second control point
 331      * of the cubic curve segment.
 332      *
 333      * @defaultValue 0.0
 334      */
 335     private DoubleProperty controlY2;
 336 
 337     public final void setControlY2(double value) {
 338         if (controlY2 != null || value != 0.0) {
 339             controlY2Property().set(value);
 340         }
 341     }
 342 
 343     public final double getControlY2() {
 344         return controlY2 == null ? 0.0 : controlY2.get();
 345     }
 346 
 347     public final DoubleProperty controlY2Property() {
 348         if (controlY2 == null) {
 349             controlY2 = new DoublePropertyBase() {
 350 
 351                 @Override
 352                 public void invalidated() {
 353                     NodeHelper.markDirty(CubicCurve.this, DirtyBits.NODE_GEOMETRY);
 354                     impl_geomChanged();
 355                 }
 356 
 357                 @Override
 358                 public Object getBean() {
 359                     return CubicCurve.this;
 360                 }
 361 
 362                 @Override
 363                 public String getName() {
 364                     return "controlY2";
 365                 }
 366             };
 367         }
 368         return controlY2;
 369     }
 370 
 371     /**
 372      * Defines the X coordinate of the end point of the cubic curve segment.
 373      *
 374      * @defaultValue 0.0
 375      */
 376     private DoubleProperty endX;
 377 
 378     public final void setEndX(double value) {
 379         if (endX != null || value != 0.0) {
 380             endXProperty().set(value);
 381         }
 382     }
 383 
 384     public final double getEndX() {
 385         return endX == null ? 0.0 : endX.get();
 386     }
 387 
 388     public final DoubleProperty endXProperty() {
 389         if (endX == null) {
 390             endX = new DoublePropertyBase() {
 391 
 392                 @Override
 393                 public void invalidated() {
 394                     NodeHelper.markDirty(CubicCurve.this, DirtyBits.NODE_GEOMETRY);
 395                     impl_geomChanged();
 396                 }
 397 
 398                 @Override
 399                 public Object getBean() {
 400                     return CubicCurve.this;
 401                 }
 402 
 403                 @Override
 404                 public String getName() {
 405                     return "endX";
 406                 }
 407             };
 408         }
 409         return endX;
 410     }
 411 
 412     /**
 413      * Defines the Y coordinate of the end point of the cubic curve segment.
 414      *
 415      * @defaultValue 0.0
 416      */
 417     private DoubleProperty endY;
 418 
 419     public final void setEndY(double value) {
 420         if (endY != null || value != 0.0) {
 421             endYProperty().set(value);
 422         }
 423     }
 424 
 425     public final double getEndY() {
 426         return endY == null ? 0.0 : endY.get();
 427     }
 428 
 429     public final DoubleProperty endYProperty() {
 430         if (endY == null) {
 431             endY = new DoublePropertyBase() {
 432 
 433                 @Override
 434                 public void invalidated() {
 435                     NodeHelper.markDirty(CubicCurve.this, DirtyBits.NODE_GEOMETRY);
 436                     impl_geomChanged();
 437                 }
 438 
 439                 @Override
 440                 public Object getBean() {
 441                     return CubicCurve.this;
 442                 }
 443 
 444                 @Override
 445                 public String getName() {
 446                     return "endY";
 447                 }
 448             };
 449         }
 450         return endY;
 451     }
 452 
 453     /*
 454      * Note: This method MUST only be called via its accessor method.
 455      */
 456     private CubicCurve2D doConfigShape() {
 457         shape.x1 = (float)getStartX();
 458         shape.y1 = (float)getStartY();
 459         shape.ctrlx1 = (float)getControlX1();
 460         shape.ctrly1 = (float)getControlY1();
 461         shape.ctrlx2 = (float)getControlX2();
 462         shape.ctrly2 = (float)getControlY2();
 463         shape.x2 = (float)getEndX();
 464         shape.y2 = (float)getEndY();
 465         return shape;
 466     }
 467 
 468     /*
 469      * Note: This method MUST only be called via its accessor method.
 470      */
 471     private NGNode doCreatePeer() {
 472         return new NGCubicCurve();
 473     }
 474 
 475     /*
 476      * Note: This method MUST only be called via its accessor method.
 477      */
 478     private void doUpdatePeer() {
 479         if (NodeHelper.isDirty(this, DirtyBits.NODE_GEOMETRY)) {
 480             final NGCubicCurve peer = NodeHelper.getPeer(this);
 481             peer.updateCubicCurve((float)getStartX(),
 482                 (float)getStartY(),
 483                 (float)getEndX(),
 484                 (float)getEndY(),
 485                 (float)getControlX1(),
 486                 (float)getControlY1(),
 487                 (float)getControlX2(),
 488                 (float)getControlY2());
 489         }
 490     }
 491 
 492     /**
 493      * Returns a string representation of this {@code CubicCurve} object.
 494      * @return a string representation of this {@code CubicCurve} object.
 495      */
 496     @Override
 497     public String toString() {
 498         final StringBuilder sb = new StringBuilder("CubicCurve[");
 499 
 500         String id = getId();
 501         if (id != null) {
 502             sb.append("id=").append(id).append(", ");
 503         }
 504 
 505         sb.append("startX=").append(getStartX());
 506         sb.append(", startY=").append(getStartY());
 507         sb.append(", controlX1=").append(getControlX1());
 508         sb.append(", controlY1=").append(getControlY1());
 509         sb.append(", controlX2=").append(getControlX2());
 510         sb.append(", controlY2=").append(getControlY2());
 511         sb.append(", endX=").append(getEndX());
 512         sb.append(", endY=").append(getEndY());
 513 
 514         sb.append(", fill=").append(getFill());
 515 
 516         Paint stroke = getStroke();
 517         if (stroke != null) {
 518             sb.append(", stroke=").append(stroke);
 519             sb.append(", strokeWidth=").append(getStrokeWidth());
 520         }
 521 
 522         return sb.append("]").toString();
 523     }
 524 }
 525