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.Arc2D; 29 import com.sun.javafx.scene.DirtyBits; 30 import com.sun.javafx.scene.NodeHelper; 31 import com.sun.javafx.scene.shape.ArcHelper; 32 import com.sun.javafx.sg.prism.NGArc; 33 import com.sun.javafx.sg.prism.NGNode; 34 import javafx.beans.property.DoubleProperty; 35 import javafx.beans.property.DoublePropertyBase; 36 import javafx.beans.property.ObjectProperty; 37 import javafx.beans.property.ObjectPropertyBase; 38 import javafx.scene.Node; 39 import javafx.scene.paint.Paint; 40 41 42 /** 43 * The {@code Arc} class represents a 2D arc object, defined by a center point, 44 * start angle (in degrees), angular extent (length of the arc in degrees), 45 * and an arc type ({@link ArcType#OPEN}, {@link ArcType#CHORD}, 46 * or {@link ArcType#ROUND}). 47 * 48 * <p>Example usage: the following code creates an Arc which is centered around 49 * 50,50, has a radius of 25 and extends from the angle 45 to the angle 315 50 * (270 degrees long), and is round. 51 * 52 <PRE> 53 import javafx.scene.shape.*; 54 55 Arc arc = new Arc(); 56 arc.setCenterX(50.0f); 57 arc.setCenterY(50.0f); 58 arc.setRadiusX(25.0f); 59 arc.setRadiusY(25.0f); 60 arc.setStartAngle(45.0f); 61 arc.setLength(270.0f); 62 arc.setType(ArcType.ROUND); 63 </PRE> 64 * @since JavaFX 2.0 65 */ 66 public class Arc extends Shape { 67 static { 68 ArcHelper.setArcAccessor(new ArcHelper.ArcAccessor() { 69 @Override 70 public NGNode doCreatePeer(Node node) { 71 return ((Arc) node).doCreatePeer(); 72 } 73 74 @Override 75 public void doUpdatePeer(Node node) { 76 ((Arc) node).doUpdatePeer(); 77 } 78 79 @Override 80 public com.sun.javafx.geom.Shape doConfigShape(Shape shape) { 81 return ((Arc) shape).doConfigShape(); 82 } 83 }); 84 } 85 86 private final Arc2D shape = new Arc2D(); 87 88 { 89 // To initialize the class helper at the begining each constructor of this class 90 ArcHelper.initHelper(this); 91 } 92 93 /** 94 * Creates an empty instance of Arc. 95 */ 96 public Arc() { 97 } 98 99 /** 100 * Creates a new instance of Arc. 101 * @param centerX the X coordinate of the center point of the arc 102 * @param centerY the Y coordinate of the center point of the arc 103 * @param radiusX the overall width (horizontal radius) of the full ellipse 104 * of which this arc is a partial section 105 * @param radiusY the overall height (vertical radius) of the full ellipse 106 * of which this arc is a partial section 107 * @param startAngle the starting angle of the arc in degrees 108 * @param length the angular extent of the arc in degrees 109 */ 110 public Arc(double centerX, double centerY, double radiusX, double radiusY, double startAngle, double length) { 111 setCenterX(centerX); 112 setCenterY(centerY); 113 setRadiusX(radiusX); 114 setRadiusY(radiusY); 115 setStartAngle(startAngle); 116 setLength(length); 117 } 118 119 /** 120 * Defines the X coordinate of the center point of the arc. 121 * 122 * @defaultValue 0.0 123 */ 124 private DoubleProperty centerX; 125 126 public final void setCenterX(double value) { 127 if (centerX != null || value != 0.0) { 128 centerXProperty().set(value); 129 } 130 } 131 132 public final double getCenterX() { 133 return centerX == null ? 0.0 : centerX.get(); 134 } 135 136 public final DoubleProperty centerXProperty() { 137 if (centerX == null) { 138 centerX = new DoublePropertyBase() { 139 140 @Override 141 public void invalidated() { 142 NodeHelper.markDirty(Arc.this, DirtyBits.NODE_GEOMETRY); 143 impl_geomChanged(); 144 } 145 146 @Override 147 public Object getBean() { 148 return Arc.this; 149 } 150 151 @Override 152 public String getName() { 153 return "centerX"; 154 } 155 }; 156 } 157 return centerX; 158 } 159 160 /** 161 * Defines the Y coordinate of the center point of the arc. 162 * 163 * @defaultValue 0.0 164 */ 165 private DoubleProperty centerY; 166 167 public final void setCenterY(double value) { 168 if (centerY != null || value != 0.0) { 169 centerYProperty().set(value); 170 } 171 } 172 173 public final double getCenterY() { 174 return centerY == null ? 0.0 : centerY.get(); 175 } 176 177 public final DoubleProperty centerYProperty() { 178 if (centerY == null) { 179 centerY = new DoublePropertyBase() { 180 181 @Override 182 public void invalidated() { 183 NodeHelper.markDirty(Arc.this, DirtyBits.NODE_GEOMETRY); 184 impl_geomChanged(); 185 } 186 187 @Override 188 public Object getBean() { 189 return Arc.this; 190 } 191 192 @Override 193 public String getName() { 194 return "centerY"; 195 } 196 }; 197 } 198 return centerY; 199 } 200 201 /** 202 * Defines the overall width (horizontal radius) of the full ellipse 203 * of which this arc is a partial section. 204 * 205 * @defaultValue 0.0 206 */ 207 private final DoubleProperty radiusX = new DoublePropertyBase() { 208 209 @Override 210 public void invalidated() { 211 NodeHelper.markDirty(Arc.this, DirtyBits.NODE_GEOMETRY); 212 impl_geomChanged(); 213 } 214 215 @Override 216 public Object getBean() { 217 return Arc.this; 218 } 219 220 @Override 221 public String getName() { 222 return "radiusX"; 223 } 224 }; 225 226 public final void setRadiusX(double value) { 227 radiusX.set(value); 228 } 229 230 public final double getRadiusX() { 231 return radiusX.get(); 232 } 233 234 public final DoubleProperty radiusXProperty() { 235 return radiusX; 236 } 237 238 /** 239 * Defines the overall height (vertical radius) of the full ellipse 240 * of which this arc is a partial section. 241 * 242 * @defaultValue 0.0 243 */ 244 private final DoubleProperty radiusY = new DoublePropertyBase() { 245 246 @Override 247 public void invalidated() { 248 NodeHelper.markDirty(Arc.this, DirtyBits.NODE_GEOMETRY); 249 impl_geomChanged(); 250 } 251 252 @Override 253 public Object getBean() { 254 return Arc.this; 255 } 256 257 @Override 258 public String getName() { 259 return "radiusY"; 260 } 261 }; 262 263 public final void setRadiusY(double value) { 264 radiusY.set(value); 265 } 266 267 public final double getRadiusY() { 268 return radiusY.get(); 269 } 270 271 public final DoubleProperty radiusYProperty() { 272 return radiusY; 273 } 274 275 /** 276 * Defines the starting angle of the arc in degrees. 277 * 278 * @defaultValue 0.0 279 */ 280 private DoubleProperty startAngle; 281 282 public final void setStartAngle(double value) { 283 if (startAngle != null || value != 0.0) { 284 startAngleProperty().set(value); 285 } 286 } 287 288 public final double getStartAngle() { 289 return startAngle == null ? 0.0 : startAngle.get(); 290 } 291 292 public final DoubleProperty startAngleProperty() { 293 if (startAngle == null) { 294 startAngle = new DoublePropertyBase() { 295 296 @Override 297 public void invalidated() { 298 NodeHelper.markDirty(Arc.this, DirtyBits.NODE_GEOMETRY); 299 impl_geomChanged(); 300 } 301 302 @Override 303 public Object getBean() { 304 return Arc.this; 305 } 306 307 @Override 308 public String getName() { 309 return "startAngle"; 310 } 311 }; 312 } 313 return startAngle; 314 } 315 316 /** 317 * Defines the angular extent of the arc in degrees. 318 * 319 * @defaultValue 0.0 320 */ 321 private final DoubleProperty length = new DoublePropertyBase() { 322 323 @Override 324 public void invalidated() { 325 NodeHelper.markDirty(Arc.this, DirtyBits.NODE_GEOMETRY); 326 impl_geomChanged(); 327 } 328 329 @Override 330 public Object getBean() { 331 return Arc.this; 332 } 333 334 @Override 335 public String getName() { 336 return "length"; 337 } 338 }; 339 340 public final void setLength(double value) { 341 length.set(value); 342 } 343 344 public final double getLength() { 345 return length.get(); 346 } 347 348 public final DoubleProperty lengthProperty() { 349 return length; 350 } 351 352 /** 353 * Defines the closure type for the arc: 354 * {@link ArcType#OPEN}, {@link ArcType#CHORD},or {@link ArcType#ROUND}. 355 * 356 * @defaultValue OPEN 357 */ 358 private ObjectProperty<ArcType> type; 359 360 361 362 public final void setType(ArcType value) { 363 if (type != null || value != ArcType.OPEN) { 364 typeProperty().set(value); 365 } 366 } 367 368 public final ArcType getType() { 369 return type == null ? ArcType.OPEN : type.get(); 370 } 371 372 public final ObjectProperty<ArcType> typeProperty() { 373 if (type == null) { 374 type = new ObjectPropertyBase<ArcType>(ArcType.OPEN) { 375 376 @Override 377 public void invalidated() { 378 NodeHelper.markDirty(Arc.this, DirtyBits.NODE_GEOMETRY); 379 impl_geomChanged(); 380 } 381 382 @Override 383 public Object getBean() { 384 return Arc.this; 385 } 386 387 @Override 388 public String getName() { 389 return "type"; 390 } 391 }; 392 } 393 return type; 394 } 395 396 /* 397 * Note: This method MUST only be called via its accessor method. 398 */ 399 private NGNode doCreatePeer() { 400 return new NGArc(); 401 } 402 403 /* 404 * Note: This method MUST only be called via its accessor method. 405 */ 406 private Arc2D doConfigShape() { 407 short tmpType; 408 switch (getTypeInternal()) { 409 case OPEN: 410 tmpType = 0; 411 break; 412 case CHORD: 413 tmpType = 1; 414 break; 415 default: 416 tmpType = 2; 417 break; 418 } 419 420 shape.setArc( 421 (float)(getCenterX() - getRadiusX()), // x 422 (float)(getCenterY() - getRadiusY()), // y 423 (float)(getRadiusX() * 2.0), // w 424 (float)(getRadiusY() * 2.0), // h 425 (float)getStartAngle(), 426 (float)getLength(), 427 tmpType); 428 429 return shape; 430 } 431 432 private final ArcType getTypeInternal() { 433 ArcType t = getType(); 434 return t == null ? ArcType.OPEN : t; 435 } 436 437 /* 438 * Note: This method MUST only be called via its accessor method. 439 */ 440 private void doUpdatePeer() { 441 if (NodeHelper.isDirty(this, DirtyBits.NODE_GEOMETRY)) { 442 final NGArc peer = NodeHelper.getPeer(this); 443 peer.updateArc((float)getCenterX(), 444 (float)getCenterY(), 445 (float)getRadiusX(), 446 (float)getRadiusY(), 447 (float)getStartAngle(), 448 (float)getLength(), 449 getTypeInternal()); 450 } 451 } 452 453 /** 454 * Returns a string representation of this {@code Arc} object. 455 * @return a string representation of this {@code Arc} object. 456 */ 457 @Override 458 public String toString() { 459 final StringBuilder sb = new StringBuilder("Arc["); 460 461 String id = getId(); 462 if (id != null) { 463 sb.append("id=").append(id).append(", "); 464 } 465 466 sb.append("centerX=").append(getCenterX()); 467 sb.append(", centerY=").append(getCenterY()); 468 sb.append(", radiusX=").append(getRadiusX()); 469 sb.append(", radiusY=").append(getRadiusY()); 470 sb.append(", startAngle=").append(getStartAngle()); 471 sb.append(", length=").append(getLength()); 472 sb.append(", type=").append(getType()); 473 474 sb.append(", fill=").append(getFill()); 475 476 Paint stroke = getStroke(); 477 if (stroke != null) { 478 sb.append(", stroke=").append(stroke); 479 sb.append(", strokeWidth=").append(getStrokeWidth()); 480 } 481 482 return sb.append("]").toString(); 483 } 484 }