1/* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.graphics; 18 19import android.annotation.NonNull; 20import android.annotation.Nullable; 21 22/** 23 * The Path class encapsulates compound (multiple contour) geometric paths 24 * consisting of straight line segments, quadratic curves, and cubic curves. 25 * It can be drawn with canvas.drawPath(path, paint), either filled or stroked 26 * (based on the paint's Style), or it can be used for clipping or to draw 27 * text on a path. 28 */ 29public class Path { 30 /** 31 * @hide 32 */ 33 public long mNativePath; 34 35 /** 36 * @hide 37 */ 38 public boolean isSimplePath = true; 39 /** 40 * @hide 41 */ 42 public Region rects; 43 private Direction mLastDirection = null; 44 45 /** 46 * Create an empty path 47 */ 48 public Path() { 49 mNativePath = init1(); 50 } 51 52 /** 53 * Create a new path, copying the contents from the src path. 54 * 55 * @param src The path to copy from when initializing the new path 56 */ 57 public Path(Path src) { 58 long valNative = 0; 59 if (src != null) { 60 valNative = src.mNativePath; 61 isSimplePath = src.isSimplePath; 62 if (src.rects != null) { 63 rects = new Region(src.rects); 64 } 65 } 66 mNativePath = init2(valNative); 67 } 68 69 /** 70 * Clear any lines and curves from the path, making it empty. 71 * This does NOT change the fill-type setting. 72 */ 73 public void reset() { 74 isSimplePath = true; 75 mLastDirection = null; 76 if (rects != null) rects.setEmpty(); 77 // We promised not to change this, so preserve it around the native 78 // call, which does now reset fill type. 79 final FillType fillType = getFillType(); 80 native_reset(mNativePath); 81 setFillType(fillType); 82 } 83 84 /** 85 * Rewinds the path: clears any lines and curves from the path but 86 * keeps the internal data structure for faster reuse. 87 */ 88 public void rewind() { 89 isSimplePath = true; 90 mLastDirection = null; 91 if (rects != null) rects.setEmpty(); 92 native_rewind(mNativePath); 93 } 94 95 /** Replace the contents of this with the contents of src. 96 */ 97 public void set(@NonNull Path src) { 98 if (this == src) { 99 return; 100 } 101 isSimplePath = src.isSimplePath; 102 native_set(mNativePath, src.mNativePath); 103 if (!isSimplePath) { 104 return; 105 } 106 107 if (rects != null && src.rects != null) { 108 rects.set(src.rects); 109 } else if (rects != null && src.rects == null) { 110 rects.setEmpty(); 111 } else if (src.rects != null) { 112 rects = new Region(src.rects); 113 } 114 } 115 116 /** 117 * The logical operations that can be performed when combining two paths. 118 * 119 * @see #op(Path, android.graphics.Path.Op) 120 * @see #op(Path, Path, android.graphics.Path.Op) 121 */ 122 public enum Op { 123 /** 124 * Subtract the second path from the first path. 125 */ 126 DIFFERENCE, 127 /** 128 * Intersect the two paths. 129 */ 130 INTERSECT, 131 /** 132 * Union (inclusive-or) the two paths. 133 */ 134 UNION, 135 /** 136 * Exclusive-or the two paths. 137 */ 138 XOR, 139 /** 140 * Subtract the first path from the second path. 141 */ 142 REVERSE_DIFFERENCE 143 } 144 145 /** 146 * Set this path to the result of applying the Op to this path and the specified path. 147 * The resulting path will be constructed from non-overlapping contours. 148 * The curve order is reduced where possible so that cubics may be turned 149 * into quadratics, and quadratics maybe turned into lines. 150 * 151 * @param path The second operand (for difference, the subtrahend) 152 * 153 * @return True if operation succeeded, false otherwise and this path remains unmodified. 154 * 155 * @see Op 156 * @see #op(Path, Path, android.graphics.Path.Op) 157 */ 158 public boolean op(Path path, Op op) { 159 return op(this, path, op); 160 } 161 162 /** 163 * Set this path to the result of applying the Op to the two specified paths. 164 * The resulting path will be constructed from non-overlapping contours. 165 * The curve order is reduced where possible so that cubics may be turned 166 * into quadratics, and quadratics maybe turned into lines. 167 * 168 * @param path1 The first operand (for difference, the minuend) 169 * @param path2 The second operand (for difference, the subtrahend) 170 * 171 * @return True if operation succeeded, false otherwise and this path remains unmodified. 172 * 173 * @see Op 174 * @see #op(Path, android.graphics.Path.Op) 175 */ 176 public boolean op(Path path1, Path path2, Op op) { 177 if (native_op(path1.mNativePath, path2.mNativePath, op.ordinal(), this.mNativePath)) { 178 isSimplePath = false; 179 rects = null; 180 return true; 181 } 182 return false; 183 } 184 185 /** 186 * Returns the path's convexity, as defined by the content of the path. 187 * <p> 188 * A path is convex if it has a single contour, and only ever curves in a 189 * single direction. 190 * <p> 191 * This function will calculate the convexity of the path from its control 192 * points, and cache the result. 193 * 194 * @return True if the path is convex. 195 */ 196 public boolean isConvex() { 197 return native_isConvex(mNativePath); 198 } 199 200 /** 201 * Enum for the ways a path may be filled. 202 */ 203 public enum FillType { 204 // these must match the values in SkPath.h 205 /** 206 * Specifies that "inside" is computed by a non-zero sum of signed 207 * edge crossings. 208 */ 209 WINDING (0), 210 /** 211 * Specifies that "inside" is computed by an odd number of edge 212 * crossings. 213 */ 214 EVEN_ODD (1), 215 /** 216 * Same as {@link #WINDING}, but draws outside of the path, rather than inside. 217 */ 218 INVERSE_WINDING (2), 219 /** 220 * Same as {@link #EVEN_ODD}, but draws outside of the path, rather than inside. 221 */ 222 INVERSE_EVEN_ODD(3); 223 224 FillType(int ni) { 225 nativeInt = ni; 226 } 227 228 final int nativeInt; 229 } 230 231 // these must be in the same order as their native values 232 static final FillType[] sFillTypeArray = { 233 FillType.WINDING, 234 FillType.EVEN_ODD, 235 FillType.INVERSE_WINDING, 236 FillType.INVERSE_EVEN_ODD 237 }; 238 239 /** 240 * Return the path's fill type. This defines how "inside" is 241 * computed. The default value is WINDING. 242 * 243 * @return the path's fill type 244 */ 245 public FillType getFillType() { 246 return sFillTypeArray[native_getFillType(mNativePath)]; 247 } 248 249 /** 250 * Set the path's fill type. This defines how "inside" is computed. 251 * 252 * @param ft The new fill type for this path 253 */ 254 public void setFillType(FillType ft) { 255 native_setFillType(mNativePath, ft.nativeInt); 256 } 257 258 /** 259 * Returns true if the filltype is one of the INVERSE variants 260 * 261 * @return true if the filltype is one of the INVERSE variants 262 */ 263 public boolean isInverseFillType() { 264 final int ft = native_getFillType(mNativePath); 265 return (ft & FillType.INVERSE_WINDING.nativeInt) != 0; 266 } 267 268 /** 269 * Toggles the INVERSE state of the filltype 270 */ 271 public void toggleInverseFillType() { 272 int ft = native_getFillType(mNativePath); 273 ft ^= FillType.INVERSE_WINDING.nativeInt; 274 native_setFillType(mNativePath, ft); 275 } 276 277 /** 278 * Returns true if the path is empty (contains no lines or curves) 279 * 280 * @return true if the path is empty (contains no lines or curves) 281 */ 282 public boolean isEmpty() { 283 return native_isEmpty(mNativePath); 284 } 285 286 /** 287 * Returns true if the path specifies a rectangle. If so, and if rect is 288 * not null, set rect to the bounds of the path. If the path does not 289 * specify a rectangle, return false and ignore rect. 290 * 291 * @param rect If not null, returns the bounds of the path if it specifies 292 * a rectangle 293 * @return true if the path specifies a rectangle 294 */ 295 public boolean isRect(RectF rect) { 296 return native_isRect(mNativePath, rect); 297 } 298 299 /** 300 * Compute the bounds of the control points of the path, and write the 301 * answer into bounds. If the path contains 0 or 1 points, the bounds is 302 * set to (0,0,0,0) 303 * 304 * @param bounds Returns the computed bounds of the path's control points. 305 * @param exact This parameter is no longer used. 306 */ 307 @SuppressWarnings({"UnusedDeclaration"}) 308 public void computeBounds(RectF bounds, boolean exact) { 309 native_computeBounds(mNativePath, bounds); 310 } 311 312 /** 313 * Hint to the path to prepare for adding more points. This can allow the 314 * path to more efficiently allocate its storage. 315 * 316 * @param extraPtCount The number of extra points that may be added to this 317 * path 318 */ 319 public void incReserve(int extraPtCount) { 320 native_incReserve(mNativePath, extraPtCount); 321 } 322 323 /** 324 * Set the beginning of the next contour to the point (x,y). 325 * 326 * @param x The x-coordinate of the start of a new contour 327 * @param y The y-coordinate of the start of a new contour 328 */ 329 public void moveTo(float x, float y) { 330 native_moveTo(mNativePath, x, y); 331 } 332 333 /** 334 * Set the beginning of the next contour relative to the last point on the 335 * previous contour. If there is no previous contour, this is treated the 336 * same as moveTo(). 337 * 338 * @param dx The amount to add to the x-coordinate of the end of the 339 * previous contour, to specify the start of a new contour 340 * @param dy The amount to add to the y-coordinate of the end of the 341 * previous contour, to specify the start of a new contour 342 */ 343 public void rMoveTo(float dx, float dy) { 344 native_rMoveTo(mNativePath, dx, dy); 345 } 346 347 /** 348 * Add a line from the last point to the specified point (x,y). 349 * If no moveTo() call has been made for this contour, the first point is 350 * automatically set to (0,0). 351 * 352 * @param x The x-coordinate of the end of a line 353 * @param y The y-coordinate of the end of a line 354 */ 355 public void lineTo(float x, float y) { 356 isSimplePath = false; 357 native_lineTo(mNativePath, x, y); 358 } 359 360 /** 361 * Same as lineTo, but the coordinates are considered relative to the last 362 * point on this contour. If there is no previous point, then a moveTo(0,0) 363 * is inserted automatically. 364 * 365 * @param dx The amount to add to the x-coordinate of the previous point on 366 * this contour, to specify a line 367 * @param dy The amount to add to the y-coordinate of the previous point on 368 * this contour, to specify a line 369 */ 370 public void rLineTo(float dx, float dy) { 371 isSimplePath = false; 372 native_rLineTo(mNativePath, dx, dy); 373 } 374 375 /** 376 * Add a quadratic bezier from the last point, approaching control point 377 * (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for 378 * this contour, the first point is automatically set to (0,0). 379 * 380 * @param x1 The x-coordinate of the control point on a quadratic curve 381 * @param y1 The y-coordinate of the control point on a quadratic curve 382 * @param x2 The x-coordinate of the end point on a quadratic curve 383 * @param y2 The y-coordinate of the end point on a quadratic curve 384 */ 385 public void quadTo(float x1, float y1, float x2, float y2) { 386 isSimplePath = false; 387 native_quadTo(mNativePath, x1, y1, x2, y2); 388 } 389 390 /** 391 * Same as quadTo, but the coordinates are considered relative to the last 392 * point on this contour. If there is no previous point, then a moveTo(0,0) 393 * is inserted automatically. 394 * 395 * @param dx1 The amount to add to the x-coordinate of the last point on 396 * this contour, for the control point of a quadratic curve 397 * @param dy1 The amount to add to the y-coordinate of the last point on 398 * this contour, for the control point of a quadratic curve 399 * @param dx2 The amount to add to the x-coordinate of the last point on 400 * this contour, for the end point of a quadratic curve 401 * @param dy2 The amount to add to the y-coordinate of the last point on 402 * this contour, for the end point of a quadratic curve 403 */ 404 public void rQuadTo(float dx1, float dy1, float dx2, float dy2) { 405 isSimplePath = false; 406 native_rQuadTo(mNativePath, dx1, dy1, dx2, dy2); 407 } 408 409 /** 410 * Add a cubic bezier from the last point, approaching control points 411 * (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been 412 * made for this contour, the first point is automatically set to (0,0). 413 * 414 * @param x1 The x-coordinate of the 1st control point on a cubic curve 415 * @param y1 The y-coordinate of the 1st control point on a cubic curve 416 * @param x2 The x-coordinate of the 2nd control point on a cubic curve 417 * @param y2 The y-coordinate of the 2nd control point on a cubic curve 418 * @param x3 The x-coordinate of the end point on a cubic curve 419 * @param y3 The y-coordinate of the end point on a cubic curve 420 */ 421 public void cubicTo(float x1, float y1, float x2, float y2, 422 float x3, float y3) { 423 isSimplePath = false; 424 native_cubicTo(mNativePath, x1, y1, x2, y2, x3, y3); 425 } 426 427 /** 428 * Same as cubicTo, but the coordinates are considered relative to the 429 * current point on this contour. If there is no previous point, then a 430 * moveTo(0,0) is inserted automatically. 431 */ 432 public void rCubicTo(float x1, float y1, float x2, float y2, 433 float x3, float y3) { 434 isSimplePath = false; 435 native_rCubicTo(mNativePath, x1, y1, x2, y2, x3, y3); 436 } 437 438 /** 439 * Append the specified arc to the path as a new contour. If the start of 440 * the path is different from the path's current last point, then an 441 * automatic lineTo() is added to connect the current contour to the 442 * start of the arc. However, if the path is empty, then we call moveTo() 443 * with the first point of the arc. 444 * 445 * @param oval The bounds of oval defining shape and size of the arc 446 * @param startAngle Starting angle (in degrees) where the arc begins 447 * @param sweepAngle Sweep angle (in degrees) measured clockwise, treated 448 * mod 360. 449 * @param forceMoveTo If true, always begin a new contour with the arc 450 */ 451 public void arcTo(RectF oval, float startAngle, float sweepAngle, 452 boolean forceMoveTo) { 453 arcTo(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, forceMoveTo); 454 } 455 456 /** 457 * Append the specified arc to the path as a new contour. If the start of 458 * the path is different from the path's current last point, then an 459 * automatic lineTo() is added to connect the current contour to the 460 * start of the arc. However, if the path is empty, then we call moveTo() 461 * with the first point of the arc. 462 * 463 * @param oval The bounds of oval defining shape and size of the arc 464 * @param startAngle Starting angle (in degrees) where the arc begins 465 * @param sweepAngle Sweep angle (in degrees) measured clockwise 466 */ 467 public void arcTo(RectF oval, float startAngle, float sweepAngle) { 468 arcTo(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, false); 469 } 470 471 /** 472 * Append the specified arc to the path as a new contour. If the start of 473 * the path is different from the path's current last point, then an 474 * automatic lineTo() is added to connect the current contour to the 475 * start of the arc. However, if the path is empty, then we call moveTo() 476 * with the first point of the arc. 477 * 478 * @param startAngle Starting angle (in degrees) where the arc begins 479 * @param sweepAngle Sweep angle (in degrees) measured clockwise, treated 480 * mod 360. 481 * @param forceMoveTo If true, always begin a new contour with the arc 482 */ 483 public void arcTo(float left, float top, float right, float bottom, float startAngle, 484 float sweepAngle, boolean forceMoveTo) { 485 isSimplePath = false; 486 native_arcTo(mNativePath, left, top, right, bottom, startAngle, sweepAngle, forceMoveTo); 487 } 488 489 /** 490 * Close the current contour. If the current point is not equal to the 491 * first point of the contour, a line segment is automatically added. 492 */ 493 public void close() { 494 isSimplePath = false; 495 native_close(mNativePath); 496 } 497 498 /** 499 * Specifies how closed shapes (e.g. rects, ovals) are oriented when they 500 * are added to a path. 501 */ 502 public enum Direction { 503 /** clockwise */ 504 CW (0), // must match enum in SkPath.h 505 /** counter-clockwise */ 506 CCW (1); // must match enum in SkPath.h 507 508 Direction(int ni) { 509 nativeInt = ni; 510 } 511 final int nativeInt; 512 } 513 514 private void detectSimplePath(float left, float top, float right, float bottom, Direction dir) { 515 if (mLastDirection == null) { 516 mLastDirection = dir; 517 } 518 if (mLastDirection != dir) { 519 isSimplePath = false; 520 } else { 521 if (rects == null) rects = new Region(); 522 rects.op((int) left, (int) top, (int) right, (int) bottom, Region.Op.UNION); 523 } 524 } 525 526 /** 527 * Add a closed rectangle contour to the path 528 * 529 * @param rect The rectangle to add as a closed contour to the path 530 * @param dir The direction to wind the rectangle's contour 531 */ 532 public void addRect(RectF rect, Direction dir) { 533 addRect(rect.left, rect.top, rect.right, rect.bottom, dir); 534 } 535 536 /** 537 * Add a closed rectangle contour to the path 538 * 539 * @param left The left side of a rectangle to add to the path 540 * @param top The top of a rectangle to add to the path 541 * @param right The right side of a rectangle to add to the path 542 * @param bottom The bottom of a rectangle to add to the path 543 * @param dir The direction to wind the rectangle's contour 544 */ 545 public void addRect(float left, float top, float right, float bottom, Direction dir) { 546 detectSimplePath(left, top, right, bottom, dir); 547 native_addRect(mNativePath, left, top, right, bottom, dir.nativeInt); 548 } 549 550 /** 551 * Add a closed oval contour to the path 552 * 553 * @param oval The bounds of the oval to add as a closed contour to the path 554 * @param dir The direction to wind the oval's contour 555 */ 556 public void addOval(RectF oval, Direction dir) { 557 addOval(oval.left, oval.top, oval.right, oval.bottom, dir); 558 } 559 560 /** 561 * Add a closed oval contour to the path 562 * 563 * @param dir The direction to wind the oval's contour 564 */ 565 public void addOval(float left, float top, float right, float bottom, Direction dir) { 566 isSimplePath = false; 567 native_addOval(mNativePath, left, top, right, bottom, dir.nativeInt); 568 } 569 570 /** 571 * Add a closed circle contour to the path 572 * 573 * @param x The x-coordinate of the center of a circle to add to the path 574 * @param y The y-coordinate of the center of a circle to add to the path 575 * @param radius The radius of a circle to add to the path 576 * @param dir The direction to wind the circle's contour 577 */ 578 public void addCircle(float x, float y, float radius, Direction dir) { 579 isSimplePath = false; 580 native_addCircle(mNativePath, x, y, radius, dir.nativeInt); 581 } 582 583 /** 584 * Add the specified arc to the path as a new contour. 585 * 586 * @param oval The bounds of oval defining the shape and size of the arc 587 * @param startAngle Starting angle (in degrees) where the arc begins 588 * @param sweepAngle Sweep angle (in degrees) measured clockwise 589 */ 590 public void addArc(RectF oval, float startAngle, float sweepAngle) { 591 addArc(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle); 592 } 593 594 /** 595 * Add the specified arc to the path as a new contour. 596 * 597 * @param startAngle Starting angle (in degrees) where the arc begins 598 * @param sweepAngle Sweep angle (in degrees) measured clockwise 599 */ 600 public void addArc(float left, float top, float right, float bottom, float startAngle, 601 float sweepAngle) { 602 isSimplePath = false; 603 native_addArc(mNativePath, left, top, right, bottom, startAngle, sweepAngle); 604 } 605 606 /** 607 * Add a closed round-rectangle contour to the path 608 * 609 * @param rect The bounds of a round-rectangle to add to the path 610 * @param rx The x-radius of the rounded corners on the round-rectangle 611 * @param ry The y-radius of the rounded corners on the round-rectangle 612 * @param dir The direction to wind the round-rectangle's contour 613 */ 614 public void addRoundRect(RectF rect, float rx, float ry, Direction dir) { 615 addRoundRect(rect.left, rect.top, rect.right, rect.bottom, rx, ry, dir); 616 } 617 618 /** 619 * Add a closed round-rectangle contour to the path 620 * 621 * @param rx The x-radius of the rounded corners on the round-rectangle 622 * @param ry The y-radius of the rounded corners on the round-rectangle 623 * @param dir The direction to wind the round-rectangle's contour 624 */ 625 public void addRoundRect(float left, float top, float right, float bottom, float rx, float ry, 626 Direction dir) { 627 isSimplePath = false; 628 native_addRoundRect(mNativePath, left, top, right, bottom, rx, ry, dir.nativeInt); 629 } 630 631 /** 632 * Add a closed round-rectangle contour to the path. Each corner receives 633 * two radius values [X, Y]. The corners are ordered top-left, top-right, 634 * bottom-right, bottom-left 635 * 636 * @param rect The bounds of a round-rectangle to add to the path 637 * @param radii Array of 8 values, 4 pairs of [X,Y] radii 638 * @param dir The direction to wind the round-rectangle's contour 639 */ 640 public void addRoundRect(RectF rect, float[] radii, Direction dir) { 641 if (rect == null) { 642 throw new NullPointerException("need rect parameter"); 643 } 644 addRoundRect(rect.left, rect.top, rect.right, rect.bottom, radii, dir); 645 } 646 647 /** 648 * Add a closed round-rectangle contour to the path. Each corner receives 649 * two radius values [X, Y]. The corners are ordered top-left, top-right, 650 * bottom-right, bottom-left 651 * 652 * @param radii Array of 8 values, 4 pairs of [X,Y] radii 653 * @param dir The direction to wind the round-rectangle's contour 654 */ 655 public void addRoundRect(float left, float top, float right, float bottom, float[] radii, 656 Direction dir) { 657 if (radii.length < 8) { 658 throw new ArrayIndexOutOfBoundsException("radii[] needs 8 values"); 659 } 660 isSimplePath = false; 661 native_addRoundRect(mNativePath, left, top, right, bottom, radii, dir.nativeInt); 662 } 663 664 /** 665 * Add a copy of src to the path, offset by (dx,dy) 666 * 667 * @param src The path to add as a new contour 668 * @param dx The amount to translate the path in X as it is added 669 */ 670 public void addPath(Path src, float dx, float dy) { 671 isSimplePath = false; 672 native_addPath(mNativePath, src.mNativePath, dx, dy); 673 } 674 675 /** 676 * Add a copy of src to the path 677 * 678 * @param src The path that is appended to the current path 679 */ 680 public void addPath(Path src) { 681 isSimplePath = false; 682 native_addPath(mNativePath, src.mNativePath); 683 } 684 685 /** 686 * Add a copy of src to the path, transformed by matrix 687 * 688 * @param src The path to add as a new contour 689 */ 690 public void addPath(Path src, Matrix matrix) { 691 if (!src.isSimplePath) isSimplePath = false; 692 native_addPath(mNativePath, src.mNativePath, matrix.native_instance); 693 } 694 695 /** 696 * Offset the path by (dx,dy) 697 * 698 * @param dx The amount in the X direction to offset the entire path 699 * @param dy The amount in the Y direction to offset the entire path 700 * @param dst The translated path is written here. If this is null, then 701 * the original path is modified. 702 */ 703 public void offset(float dx, float dy, @Nullable Path dst) { 704 if (dst != null) { 705 dst.set(this); 706 } else { 707 dst = this; 708 } 709 dst.offset(dx, dy); 710 } 711 712 /** 713 * Offset the path by (dx,dy) 714 * 715 * @param dx The amount in the X direction to offset the entire path 716 * @param dy The amount in the Y direction to offset the entire path 717 */ 718 public void offset(float dx, float dy) { 719 if (isSimplePath && rects == null) { 720 // nothing to offset 721 return; 722 } 723 if (isSimplePath && dx == Math.rint(dx) && dy == Math.rint(dy)) { 724 rects.translate((int) dx, (int) dy); 725 } else { 726 isSimplePath = false; 727 } 728 native_offset(mNativePath, dx, dy); 729 } 730 731 /** 732 * Sets the last point of the path. 733 * 734 * @param dx The new X coordinate for the last point 735 * @param dy The new Y coordinate for the last point 736 */ 737 public void setLastPoint(float dx, float dy) { 738 isSimplePath = false; 739 native_setLastPoint(mNativePath, dx, dy); 740 } 741 742 /** 743 * Transform the points in this path by matrix, and write the answer 744 * into dst. If dst is null, then the the original path is modified. 745 * 746 * @param matrix The matrix to apply to the path 747 * @param dst The transformed path is written here. If dst is null, 748 * then the the original path is modified 749 */ 750 public void transform(Matrix matrix, Path dst) { 751 long dstNative = 0; 752 if (dst != null) { 753 dst.isSimplePath = false; 754 dstNative = dst.mNativePath; 755 } 756 native_transform(mNativePath, matrix.native_instance, dstNative); 757 } 758 759 /** 760 * Transform the points in this path by matrix. 761 * 762 * @param matrix The matrix to apply to the path 763 */ 764 public void transform(Matrix matrix) { 765 isSimplePath = false; 766 native_transform(mNativePath, matrix.native_instance); 767 } 768 769 protected void finalize() throws Throwable { 770 try { 771 finalizer(mNativePath); 772 mNativePath = 0; // Other finalizers can still call us. 773 } finally { 774 super.finalize(); 775 } 776 } 777 778 final long ni() { 779 return mNativePath; 780 } 781 782 /** 783 * Approximate the <code>Path</code> with a series of line segments. 784 * This returns float[] with the array containing point components. 785 * There are three components for each point, in order: 786 * <ul> 787 * <li>Fraction along the length of the path that the point resides</li> 788 * <li>The x coordinate of the point</li> 789 * <li>The y coordinate of the point</li> 790 * </ul> 791 * <p>Two points may share the same fraction along its length when there is 792 * a move action within the Path.</p> 793 * 794 * @param acceptableError The acceptable error for a line on the 795 * Path. Typically this would be 0.5 so that 796 * the error is less than half a pixel. 797 * @return An array of components for points approximating the Path. 798 * @hide 799 */ 800 public float[] approximate(float acceptableError) { 801 return native_approximate(mNativePath, acceptableError); 802 } 803 804 private static native long init1(); 805 private static native long init2(long nPath); 806 private static native void native_reset(long nPath); 807 private static native void native_rewind(long nPath); 808 private static native void native_set(long native_dst, long native_src); 809 private static native boolean native_isConvex(long nPath); 810 private static native int native_getFillType(long nPath); 811 private static native void native_setFillType(long nPath, int ft); 812 private static native boolean native_isEmpty(long nPath); 813 private static native boolean native_isRect(long nPath, RectF rect); 814 private static native void native_computeBounds(long nPath, RectF bounds); 815 private static native void native_incReserve(long nPath, int extraPtCount); 816 private static native void native_moveTo(long nPath, float x, float y); 817 private static native void native_rMoveTo(long nPath, float dx, float dy); 818 private static native void native_lineTo(long nPath, float x, float y); 819 private static native void native_rLineTo(long nPath, float dx, float dy); 820 private static native void native_quadTo(long nPath, float x1, float y1, 821 float x2, float y2); 822 private static native void native_rQuadTo(long nPath, float dx1, float dy1, 823 float dx2, float dy2); 824 private static native void native_cubicTo(long nPath, float x1, float y1, 825 float x2, float y2, float x3, float y3); 826 private static native void native_rCubicTo(long nPath, float x1, float y1, 827 float x2, float y2, float x3, float y3); 828 private static native void native_arcTo(long nPath, float left, float top, 829 float right, float bottom, float startAngle, 830 float sweepAngle, boolean forceMoveTo); 831 private static native void native_close(long nPath); 832 private static native void native_addRect(long nPath, float left, float top, 833 float right, float bottom, int dir); 834 private static native void native_addOval(long nPath, float left, float top, 835 float right, float bottom, int dir); 836 private static native void native_addCircle(long nPath, float x, float y, float radius, int dir); 837 private static native void native_addArc(long nPath, float left, float top, 838 float right, float bottom, 839 float startAngle, float sweepAngle); 840 private static native void native_addRoundRect(long nPath, float left, float top, 841 float right, float bottom, 842 float rx, float ry, int dir); 843 private static native void native_addRoundRect(long nPath, float left, float top, 844 float right, float bottom, 845 float[] radii, int dir); 846 private static native void native_addPath(long nPath, long src, float dx, float dy); 847 private static native void native_addPath(long nPath, long src); 848 private static native void native_addPath(long nPath, long src, long matrix); 849 private static native void native_offset(long nPath, float dx, float dy); 850 private static native void native_setLastPoint(long nPath, float dx, float dy); 851 private static native void native_transform(long nPath, long matrix, long dst_path); 852 private static native void native_transform(long nPath, long matrix); 853 private static native boolean native_op(long path1, long path2, int op, long result); 854 private static native void finalizer(long nPath); 855 private static native float[] native_approximate(long nPath, float error); 856} 857