< prev index next >

modules/javafx.graphics/src/main/java/com/sun/marlin/Helpers.java

Print this page


   1 /*
   2  * Copyright (c) 2007, 2017, 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 com.sun.marlin;
  27 
  28 import com.sun.javafx.geom.PathConsumer2D;
  29 import static java.lang.Math.PI;
  30 import java.util.Arrays;
  31 import com.sun.marlin.stats.Histogram;
  32 import com.sun.marlin.stats.StatLong;
  33 
  34 final class Helpers implements MarlinConst {
  35 
  36     private Helpers() {
  37         throw new Error("This is a non instantiable class");
  38     }
  39 
  40     static boolean within(final float x, final float y, final float err) {
  41         final float d = y - x;
  42         return (d <= err && d >= -err);
  43     }
  44 
  45     static boolean within(final double x, final double y, final double err) {
  46         final double d = y - x;
  47         return (d <= err && d >= -err);
  48     }
  49 
  50     static int quadraticRoots(final float a, final float b,
  51                               final float c, float[] zeroes, final int off)













  52     {
  53         int ret = off;
  54         float t;
  55         if (a != 0.0f) {
  56             final float dis = b*b - 4*a*c;
  57             if (dis > 0.0f) {
  58                 final float sqrtDis = (float) Math.sqrt(dis);
  59                 // depending on the sign of b we use a slightly different
  60                 // algorithm than the traditional one to find one of the roots
  61                 // so we can avoid adding numbers of different signs (which
  62                 // might result in loss of precision).
  63                 if (b >= 0.0f) {
  64                     zeroes[ret++] = (2.0f * c) / (-b - sqrtDis);
  65                     zeroes[ret++] = (-b - sqrtDis) / (2.0f * a);
  66                 } else {
  67                     zeroes[ret++] = (-b + sqrtDis) / (2.0f * a);
  68                     zeroes[ret++] = (2.0f * c) / (-b + sqrtDis);
  69                 }
  70             } else if (dis == 0.0f) {
  71                 t = (-b) / (2.0f * a);
  72                 zeroes[ret++] = t;
  73             }
  74         } else {
  75             if (b != 0.0f) {
  76                 t = (-c) / b;
  77                 zeroes[ret++] = t;
  78             }


  79         }
  80         return ret - off;
  81     }
  82 
  83     // find the roots of g(t) = d*t^3 + a*t^2 + b*t + c in [A,B)
  84     static int cubicRootsInAB(float d, float a, float b, float c,
  85                               float[] pts, final int off,
  86                               final float A, final float B)
  87     {
  88         if (d == 0.0f) {
  89             int num = quadraticRoots(a, b, c, pts, off);
  90             return filterOutNotInAB(pts, off, num, A, B) - off;
  91         }
  92         // From Graphics Gems:
  93         // http://tog.acm.org/resources/GraphicsGems/gems/Roots3And4.c
  94         // (also from awt.geom.CubicCurve2D. But here we don't need as
  95         // much accuracy and we don't want to create arrays so we use
  96         // our own customized version).
  97 
  98         // normal form: x^3 + ax^2 + bx + c = 0
  99         a /= d;
 100         b /= d;
 101         c /= d;





 102 
 103         //  substitute x = y - A/3 to eliminate quadratic term:
 104         //     x^3 +Px + Q = 0
 105         //
 106         // Since we actually need P/3 and Q/2 for all of the
 107         // calculations that follow, we will calculate
 108         // p = P/3
 109         // q = Q/2
 110         // instead and use those values for simplicity of the code.
 111         double sq_A = a * a;
 112         double p = (1.0d/3.0d) * ((-1.0d/3.0d) * sq_A + b);
 113         double q = (1.0d/2.0d) * ((2.0d/27.0d) * a * sq_A - (1.0d/3.0d) * a * b + c);

 114 
 115         // use Cardano's formula
 116 
 117         double cb_p = p * p * p;
 118         double D = q * q + cb_p;
 119 
 120         int num;
 121         if (D < 0.0d) {
 122             // see: http://en.wikipedia.org/wiki/Cubic_function#Trigonometric_.28and_hyperbolic.29_method
 123             final double phi = (1.0d/3.0d) * Math.acos(-q / Math.sqrt(-cb_p));
 124             final double t = 2.0d * Math.sqrt(-p);
 125 
 126             pts[ off+0 ] = (float) ( t * Math.cos(phi));
 127             pts[ off+1 ] = (float) (-t * Math.cos(phi + (PI / 3.0d)));
 128             pts[ off+2 ] = (float) (-t * Math.cos(phi - (PI / 3.0d)));
 129             num = 3;
 130         } else {
 131             final double sqrt_D = Math.sqrt(D);
 132             final double u =   Math.cbrt(sqrt_D - q);
 133             final double v = - Math.cbrt(sqrt_D + q);
 134 
 135             pts[ off ] = (float) (u + v);
 136             num = 1;
 137 
 138             if (within(D, 0.0d, 1e-8d)) {
 139                 pts[off+1] = -(pts[off] / 2.0f);
 140                 num = 2;
 141             }
 142         }
 143 
 144         final float sub = (1.0f/3.0f) * a;
 145 
 146         for (int i = 0; i < num; ++i) {
 147             pts[ off+i ] -= sub;
 148         }
 149 
 150         return filterOutNotInAB(pts, off, num, A, B) - off;
 151     }
 152 
 153     static float evalCubic(final float a, final float b,
 154                            final float c, final float d,
 155                            final float t)
 156     {
 157         return t * (t * (t * a + b) + c) + d;
 158     }
 159 
 160     static float evalQuad(final float a, final float b,
 161                           final float c, final float t)
 162     {
 163         return t * (t * a + b) + c;
 164     }
 165 
 166     // returns the index 1 past the last valid element remaining after filtering
 167     static int filterOutNotInAB(float[] nums, final int off, final int len,
 168                                 final float a, final float b)
 169     {
 170         int ret = off;
 171         for (int i = off, end = off + len; i < end; i++) {
 172             if (nums[i] >= a && nums[i] < b) {
 173                 nums[ret++] = nums[i];
 174             }
 175         }
 176         return ret;
 177     }
 178 
 179     static float linelen(float x1, float y1, float x2, float y2) {
 180         final float dx = x2 - x1;
 181         final float dy = y2 - y1;
 182         return (float) Math.sqrt(dx*dx + dy*dy);


























































































































































 183     }
 184 
 185     static void subdivide(float[] src, int srcoff, float[] left, int leftoff,
 186                           float[] right, int rightoff, int type)

 187     {
 188         switch(type) {
 189         case 6:
 190             Helpers.subdivideQuad(src, srcoff, left, leftoff, right, rightoff);
 191             return;
 192         case 8:
 193             Helpers.subdivideCubic(src, srcoff, left, leftoff, right, rightoff);



 194             return;
 195         default:
 196             throw new InternalError("Unsupported curve type");
 197         }
 198     }
 199 
 200     static void isort(float[] a, int off, int len) {
 201         for (int i = off + 1, end = off + len; i < end; i++) {
 202             float ai = a[i];
 203             int j = i - 1;
 204             for (; j >= off && a[j] > ai; j--) {
 205                 a[j+1] = a[j];
 206             }
 207             a[j+1] = ai;
 208         }
 209     }
 210 
 211     // Most of these are copied from classes in java.awt.geom because we need
 212     // both single and double precision variants of these functions, and Line2D,
 213     // CubicCurve2D, QuadCurve2D don't provide them.
 214     /**
 215      * Subdivides the cubic curve specified by the coordinates
 216      * stored in the <code>src</code> array at indices <code>srcoff</code>
 217      * through (<code>srcoff</code>&nbsp;+&nbsp;7) and stores the
 218      * resulting two subdivided curves into the two result arrays at the
 219      * corresponding indices.
 220      * Either or both of the <code>left</code> and <code>right</code>
 221      * arrays may be <code>null</code> or a reference to the same array
 222      * as the <code>src</code> array.
 223      * Note that the last point in the first subdivided curve is the
 224      * same as the first point in the second subdivided curve. Thus,
 225      * it is possible to pass the same array for <code>left</code>
 226      * and <code>right</code> and to use offsets, such as <code>rightoff</code>
 227      * equals (<code>leftoff</code> + 6), in order
 228      * to avoid allocating extra storage for this common point.
 229      * @param src the array holding the coordinates for the source curve
 230      * @param srcoff the offset into the array of the beginning of the
 231      * the 6 source coordinates
 232      * @param left the array for storing the coordinates for the first
 233      * half of the subdivided curve
 234      * @param leftoff the offset into the array of the beginning of the
 235      * the 6 left coordinates
 236      * @param right the array for storing the coordinates for the second
 237      * half of the subdivided curve
 238      * @param rightoff the offset into the array of the beginning of the
 239      * the 6 right coordinates
 240      * @since 1.7
 241      */
 242     static void subdivideCubic(float[] src, int srcoff,
 243                                float[] left, int leftoff,
 244                                float[] right, int rightoff)
 245     {
 246         float x1 = src[srcoff + 0];
 247         float y1 = src[srcoff + 1];
 248         float ctrlx1 = src[srcoff + 2];
 249         float ctrly1 = src[srcoff + 3];
 250         float ctrlx2 = src[srcoff + 4];
 251         float ctrly2 = src[srcoff + 5];
 252         float x2 = src[srcoff + 6];
 253         float y2 = src[srcoff + 7];
 254         if (left != null) {
 255             left[leftoff + 0] = x1;
 256             left[leftoff + 1] = y1;
 257         }
 258         if (right != null) {
 259             right[rightoff + 6] = x2;
 260             right[rightoff + 7] = y2;
 261         }
 262         x1 = (x1 + ctrlx1) / 2.0f;
 263         y1 = (y1 + ctrly1) / 2.0f;
 264         x2 = (x2 + ctrlx2) / 2.0f;
 265         y2 = (y2 + ctrly2) / 2.0f;
 266         float centerx = (ctrlx1 + ctrlx2) / 2.0f;
 267         float centery = (ctrly1 + ctrly2) / 2.0f;
 268         ctrlx1 = (x1 + centerx) / 2.0f;
 269         ctrly1 = (y1 + centery) / 2.0f;
 270         ctrlx2 = (x2 + centerx) / 2.0f;
 271         ctrly2 = (y2 + centery) / 2.0f;
 272         centerx = (ctrlx1 + ctrlx2) / 2.0f;
 273         centery = (ctrly1 + ctrly2) / 2.0f;
 274         if (left != null) {
 275             left[leftoff + 2] = x1;
 276             left[leftoff + 3] = y1;
 277             left[leftoff + 4] = ctrlx1;
 278             left[leftoff + 5] = ctrly1;
 279             left[leftoff + 6] = centerx;
 280             left[leftoff + 7] = centery;
 281         }
 282         if (right != null) {
 283             right[rightoff + 0] = centerx;
 284             right[rightoff + 1] = centery;
 285             right[rightoff + 2] = ctrlx2;
 286             right[rightoff + 3] = ctrly2;
 287             right[rightoff + 4] = x2;
 288             right[rightoff + 5] = y2;
 289         }
 290     }
 291 
 292 
 293     static void subdivideCubicAt(float t, float[] src, int srcoff,
 294                                  float[] left, int leftoff,
 295                                  float[] right, int rightoff)
 296     {
 297         float x1 = src[srcoff + 0];
 298         float y1 = src[srcoff + 1];
 299         float ctrlx1 = src[srcoff + 2];
 300         float ctrly1 = src[srcoff + 3];
 301         float ctrlx2 = src[srcoff + 4];
 302         float ctrly2 = src[srcoff + 5];
 303         float x2 = src[srcoff + 6];
 304         float y2 = src[srcoff + 7];
 305         if (left != null) {
 306             left[leftoff + 0] = x1;
 307             left[leftoff + 1] = y1;
 308         }
 309         if (right != null) {
 310             right[rightoff + 6] = x2;
 311             right[rightoff + 7] = y2;
 312         }
 313         x1 = x1 + t * (ctrlx1 - x1);
 314         y1 = y1 + t * (ctrly1 - y1);
 315         x2 = ctrlx2 + t * (x2 - ctrlx2);
 316         y2 = ctrly2 + t * (y2 - ctrly2);
 317         float centerx = ctrlx1 + t * (ctrlx2 - ctrlx1);
 318         float centery = ctrly1 + t * (ctrly2 - ctrly1);
 319         ctrlx1 = x1 + t * (centerx - x1);
 320         ctrly1 = y1 + t * (centery - y1);
 321         ctrlx2 = centerx + t * (x2 - centerx);
 322         ctrly2 = centery + t * (y2 - centery);
 323         centerx = ctrlx1 + t * (ctrlx2 - ctrlx1);
 324         centery = ctrly1 + t * (ctrly2 - ctrly1);
 325         if (left != null) {
 326             left[leftoff + 2] = x1;
 327             left[leftoff + 3] = y1;
 328             left[leftoff + 4] = ctrlx1;
 329             left[leftoff + 5] = ctrly1;
 330             left[leftoff + 6] = centerx;
 331             left[leftoff + 7] = centery;
 332         }
 333         if (right != null) {
 334             right[rightoff + 0] = centerx;
 335             right[rightoff + 1] = centery;
 336             right[rightoff + 2] = ctrlx2;
 337             right[rightoff + 3] = ctrly2;
 338             right[rightoff + 4] = x2;
 339             right[rightoff + 5] = y2;
 340         }
 341     }
 342 
 343     static void subdivideQuad(float[] src, int srcoff,
 344                               float[] left, int leftoff,
 345                               float[] right, int rightoff)
 346     {
 347         float x1 = src[srcoff + 0];
 348         float y1 = src[srcoff + 1];
 349         float ctrlx = src[srcoff + 2];
 350         float ctrly = src[srcoff + 3];
 351         float x2 = src[srcoff + 4];
 352         float y2 = src[srcoff + 5];
 353         if (left != null) {
 354             left[leftoff + 0] = x1;
 355             left[leftoff + 1] = y1;
 356         }
 357         if (right != null) {
 358             right[rightoff + 4] = x2;
 359             right[rightoff + 5] = y2;
 360         }
 361         x1 = (x1 + ctrlx) / 2.0f;
 362         y1 = (y1 + ctrly) / 2.0f;
 363         x2 = (x2 + ctrlx) / 2.0f;
 364         y2 = (y2 + ctrly) / 2.0f;
 365         ctrlx = (x1 + x2) / 2.0f;
 366         ctrly = (y1 + y2) / 2.0f;
 367         if (left != null) {
 368             left[leftoff + 2] = x1;
 369             left[leftoff + 3] = y1;
 370             left[leftoff + 4] = ctrlx;
 371             left[leftoff + 5] = ctrly;
 372         }
 373         if (right != null) {
 374             right[rightoff + 0] = ctrlx;
 375             right[rightoff + 1] = ctrly;
 376             right[rightoff + 2] = x2;
 377             right[rightoff + 3] = y2;
 378         }
 379     }
 380 
 381     static void subdivideQuadAt(float t, float[] src, int srcoff,
 382                                 float[] left, int leftoff,
 383                                 float[] right, int rightoff)
 384     {
 385         float x1 = src[srcoff + 0];
 386         float y1 = src[srcoff + 1];
 387         float ctrlx = src[srcoff + 2];
 388         float ctrly = src[srcoff + 3];
 389         float x2 = src[srcoff + 4];
 390         float y2 = src[srcoff + 5];
 391         if (left != null) {
 392             left[leftoff + 0] = x1;
 393             left[leftoff + 1] = y1;
 394         }
 395         if (right != null) {
 396             right[rightoff + 4] = x2;
 397             right[rightoff + 5] = y2;
 398         }
 399         x1 = x1 + t * (ctrlx - x1);
 400         y1 = y1 + t * (ctrly - y1);
 401         x2 = ctrlx + t * (x2 - ctrlx);
 402         y2 = ctrly + t * (y2 - ctrly);
 403         ctrlx = x1 + t * (x2 - x1);
 404         ctrly = y1 + t * (y2 - y1);
 405         if (left != null) {
 406             left[leftoff + 2] = x1;
 407             left[leftoff + 3] = y1;
 408             left[leftoff + 4] = ctrlx;
 409             left[leftoff + 5] = ctrly;
 410         }
 411         if (right != null) {
 412             right[rightoff + 0] = ctrlx;
 413             right[rightoff + 1] = ctrly;
 414             right[rightoff + 2] = x2;
 415             right[rightoff + 3] = y2;
 416         }
 417     }
 418 
 419     static void subdivideAt(float t, float[] src, int srcoff,
 420                             float[] left, int leftoff,
 421                             float[] right, int rightoff, int size)
 422     {
 423         switch(size) {
 424         case 8:
 425             subdivideCubicAt(t, src, srcoff, left, leftoff, right, rightoff);
 426             return;
 427         case 6:
 428             subdivideQuadAt(t, src, srcoff, left, leftoff, right, rightoff);
 429             return;
















 430         }
 431     }
 432 
 433     // From sun.java2d.loops.GeneralRenderer:
 434 
 435     static int outcode(final float x, final float y,
 436                        final float[] clipRect)
 437     {
 438         int code;
 439         if (y < clipRect[0]) {
 440             code = OUTCODE_TOP;
 441         } else if (y >= clipRect[1]) {
 442             code = OUTCODE_BOTTOM;
 443         } else {
 444             code = 0;
 445         }
 446         if (x < clipRect[2]) {
 447             code |= OUTCODE_LEFT;
 448         } else if (x >= clipRect[3]) {
 449             code |= OUTCODE_RIGHT;


 596             }
 597             if (DO_STATS) {
 598                 // update used marks:
 599                 if (numCurves > curveTypesUseMark) {
 600                     curveTypesUseMark = numCurves;
 601                 }
 602                 if (end > curvesUseMark) {
 603                     curvesUseMark = end;
 604                 }
 605             }
 606             final byte[]  _curveTypes = curveTypes;
 607             final float[] _curves = curves;
 608             int e = 0;
 609 
 610             for (int i = 0; i < nc; i++) {
 611                 switch(_curveTypes[i]) {
 612                 case TYPE_LINETO:
 613                     io.lineTo(_curves[e], _curves[e+1]);
 614                     e += 2;
 615                     continue;
 616                 case TYPE_QUADTO:
 617                     io.quadTo(_curves[e+0], _curves[e+1],
 618                               _curves[e+2], _curves[e+3]);
 619                     e += 4;
 620                     continue;
 621                 case TYPE_CUBICTO:
 622                     io.curveTo(_curves[e+0], _curves[e+1],
 623                                _curves[e+2], _curves[e+3],
 624                                _curves[e+4], _curves[e+5]);
 625                     e += 6;
 626                     continue;





 627                 default:
 628                 }
 629             }
 630             numCurves = 0;
 631             end = 0;
 632         }
 633 
 634         void popAll(final PathConsumer2D io) {
 635             int nc = numCurves;
 636             if (nc == 0) {
 637                 return;
 638             }
 639             if (DO_STATS) {
 640                 // update used marks:
 641                 if (numCurves > curveTypesUseMark) {
 642                     curveTypesUseMark = numCurves;
 643                 }
 644                 if (end > curvesUseMark) {
 645                     curvesUseMark = end;
 646                 }
 647             }
 648             final byte[]  _curveTypes = curveTypes;
 649             final float[] _curves = curves;
 650             int e  = end;
 651 
 652             while (nc != 0) {
 653                 switch(_curveTypes[--nc]) {
 654                 case TYPE_LINETO:
 655                     e -= 2;
 656                     io.lineTo(_curves[e], _curves[e+1]);
 657                     continue;
 658                 case TYPE_QUADTO:
 659                     e -= 4;
 660                     io.quadTo(_curves[e+0], _curves[e+1],
 661                               _curves[e+2], _curves[e+3]);
 662                     continue;
 663                 case TYPE_CUBICTO:
 664                     e -= 6;
 665                     io.curveTo(_curves[e+0], _curves[e+1],
 666                                _curves[e+2], _curves[e+3],
 667                                _curves[e+4], _curves[e+5]);





 668                     continue;
 669                 default:
 670                 }
 671             }
 672             numCurves = 0;
 673             end = 0;
 674         }
 675 
 676         @Override
 677         public String toString() {
 678             String ret = "";
 679             int nc = numCurves;
 680             int last = end;
 681             int len;
 682             while (nc != 0) {
 683                 switch(curveTypes[--nc]) {
 684                 case TYPE_LINETO:
 685                     len = 2;
 686                     ret += "line: ";
 687                     break;


   1 /*
   2  * Copyright (c) 2007, 2018, 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 com.sun.marlin;
  27 
  28 import com.sun.javafx.geom.PathConsumer2D;

  29 import java.util.Arrays;
  30 import com.sun.marlin.stats.Histogram;
  31 import com.sun.marlin.stats.StatLong;
  32 
  33 final class Helpers implements MarlinConst {
  34 
  35     private Helpers() {
  36         throw new Error("This is a non instantiable class");
  37     }
  38 
  39     static boolean within(final float x, final float y, final float err) {
  40         final float d = y - x;
  41         return (d <= err && d >= -err);
  42     }
  43 
  44     static boolean within(final double x, final double y, final double err) {
  45         final double d = y - x;
  46         return (d <= err && d >= -err);
  47     }
  48 
  49     static float evalCubic(final float a, final float b,
  50                            final float c, final float d,
  51                            final float t)
  52     {
  53         return t * (t * (t * a + b) + c) + d;
  54     }
  55 
  56     static float evalQuad(final float a, final float b,
  57                           final float c, final float t)
  58     {
  59         return t * (t * a + b) + c;
  60     }
  61 
  62     static int quadraticRoots(final float a, final float b, final float c,
  63                               final float[] zeroes, final int off)
  64     {
  65         int ret = off;

  66         if (a != 0.0f) {
  67             final float dis = b*b - 4.0f * a * c;
  68             if (dis > 0.0f) {
  69                 final float sqrtDis = (float) Math.sqrt(dis);
  70                 // depending on the sign of b we use a slightly different
  71                 // algorithm than the traditional one to find one of the roots
  72                 // so we can avoid adding numbers of different signs (which
  73                 // might result in loss of precision).
  74                 if (b >= 0.0f) {
  75                     zeroes[ret++] = (2.0f * c) / (-b - sqrtDis);
  76                     zeroes[ret++] = (-b - sqrtDis) / (2.0f * a);
  77                 } else {
  78                     zeroes[ret++] = (-b + sqrtDis) / (2.0f * a);
  79                     zeroes[ret++] = (2.0f * c) / (-b + sqrtDis);
  80                 }
  81             } else if (dis == 0.0f) {
  82                 zeroes[ret++] = -b / (2.0f * a);






  83             }
  84         } else if (b != 0.0f) {
  85             zeroes[ret++] = -c / b;
  86         }
  87         return ret - off;
  88     }
  89 
  90     // find the roots of g(t) = d*t^3 + a*t^2 + b*t + c in [A,B)
  91     static int cubicRootsInAB(final float d0, float a0, float b0, float c0,
  92                               final float[] pts, final int off,
  93                               final float A, final float B)
  94     {
  95         if (d0 == 0.0f) {
  96             final int num = quadraticRoots(a0, b0, c0, pts, off);
  97             return filterOutNotInAB(pts, off, num, A, B) - off;
  98         }
  99         // From Graphics Gems:
 100         // https://github.com/erich666/GraphicsGems/blob/master/gems/Roots3And4.c
 101         // (also from awt.geom.CubicCurve2D. But here we don't need as
 102         // much accuracy and we don't want to create arrays so we use
 103         // our own customized version).
 104 
 105         // normal form: x^3 + ax^2 + bx + c = 0
 106 
 107         // 2018.1: Need double precision if d is very small (flat curve) !
 108         /*
 109          * TODO: cleanup all that code after reading Roots3And4.c
 110          */
 111         final double a = ((double)a0) / d0;
 112         final double b = ((double)b0) / d0;
 113         final double c = ((double)c0) / d0;
 114 
 115         //  substitute x = y - A/3 to eliminate quadratic term:
 116         //     x^3 +Px + Q = 0
 117         //
 118         // Since we actually need P/3 and Q/2 for all of the
 119         // calculations that follow, we will calculate
 120         // p = P/3
 121         // q = Q/2
 122         // instead and use those values for simplicity of the code.
 123         final double sub = (1.0d / 3.0d) * a;
 124         final double sq_A = a * a;
 125         final double p = (1.0d / 3.0d) * ((-1.0d / 3.0d) * sq_A + b);
 126         final double q = (1.0d / 2.0d) * ((2.0d / 27.0d) * a * sq_A - sub * b + c);
 127 
 128         // use Cardano's formula
 129 
 130         final double cb_p = p * p * p;
 131         final double D = q * q + cb_p;
 132 
 133         int num;
 134         if (D < 0.0d) {
 135             // see: http://en.wikipedia.org/wiki/Cubic_function#Trigonometric_.28and_hyperbolic.29_method
 136             final double phi = (1.0d / 3.0d) * Math.acos(-q / Math.sqrt(-cb_p));
 137             final double t = 2.0d * Math.sqrt(-p);
 138 
 139             pts[off    ] = (float) ( t * Math.cos(phi) - sub);
 140             pts[off + 1] = (float) (-t * Math.cos(phi + (Math.PI / 3.0d)) - sub);
 141             pts[off + 2] = (float) (-t * Math.cos(phi - (Math.PI / 3.0d)) - sub);
 142             num = 3;
 143         } else {
 144             final double sqrt_D = Math.sqrt(D);
 145             final double u =   Math.cbrt(sqrt_D - q);
 146             final double v = - Math.cbrt(sqrt_D + q);
 147 
 148             pts[off    ] = (float) (u + v - sub);
 149             num = 1;
 150 
 151             if (within(D, 0.0d, 1e-8d)) {
 152                 pts[off + 1] = (float)((-1.0d / 2.0d) * (u + v) - sub);
 153                 num = 2;
 154             }
 155         }
 156 






 157         return filterOutNotInAB(pts, off, num, A, B) - off;
 158     }
 159 













 160     // returns the index 1 past the last valid element remaining after filtering
 161     static int filterOutNotInAB(final float[] nums, final int off, final int len,
 162                                 final float a, final float b)
 163     {
 164         int ret = off;
 165         for (int i = off, end = off + len; i < end; i++) {
 166             if (nums[i] >= a && nums[i] < b) {
 167                 nums[ret++] = nums[i];
 168             }
 169         }
 170         return ret;
 171     }
 172 
 173     static float fastLineLen(final float x0, final float y0,
 174                              final float x1, final float y1)
 175     {
 176         final float dx = x1 - x0;
 177         final float dy = y1 - y0;
 178 
 179         // use manhattan norm:
 180         return Math.abs(dx) + Math.abs(dy);
 181     }
 182 
 183     static float linelen(final float x0, final float y0,
 184                          final float x1, final float y1)
 185     {
 186         final float dx = x1 - x0;
 187         final float dy = y1 - y0;
 188         return (float) Math.sqrt(dx * dx + dy * dy);
 189     }
 190 
 191     static float fastQuadLen(final float x0, final float y0,
 192                              final float x1, final float y1,
 193                              final float x2, final float y2)
 194     {
 195         final float dx1 = x1 - x0;
 196         final float dx2 = x2 - x1;
 197         final float dy1 = y1 - y0;
 198         final float dy2 = y2 - y1;
 199 
 200         // use manhattan norm:
 201         return Math.abs(dx1) + Math.abs(dx2)
 202              + Math.abs(dy1) + Math.abs(dy2);
 203     }
 204 
 205     static float quadlen(final float x0, final float y0,
 206                          final float x1, final float y1,
 207                          final float x2, final float y2)
 208     {
 209         return (linelen(x0, y0, x1, y1)
 210                 + linelen(x1, y1, x2, y2)
 211                 + linelen(x0, y0, x2, y2)) / 2.0f;
 212     }
 213 
 214 
 215     static float fastCurvelen(final float x0, final float y0,
 216                               final float x1, final float y1,
 217                               final float x2, final float y2,
 218                               final float x3, final float y3)
 219     {
 220         final float dx1 = x1 - x0;
 221         final float dx2 = x2 - x1;
 222         final float dx3 = x3 - x2;
 223         final float dy1 = y1 - y0;
 224         final float dy2 = y2 - y1;
 225         final float dy3 = y3 - y2;
 226 
 227         // use manhattan norm:
 228         return Math.abs(dx1) + Math.abs(dx2) + Math.abs(dx3)
 229              + Math.abs(dy1) + Math.abs(dy2) + Math.abs(dy3);
 230     }
 231 
 232     static float curvelen(final float x0, final float y0,
 233                           final float x1, final float y1,
 234                           final float x2, final float y2,
 235                           final float x3, final float y3)
 236     {
 237         return (linelen(x0, y0, x1, y1)
 238               + linelen(x1, y1, x2, y2)
 239               + linelen(x2, y2, x3, y3)
 240               + linelen(x0, y0, x3, y3)) / 2.0f;
 241     }
 242 
 243     // finds values of t where the curve in pts should be subdivided in order
 244     // to get good offset curves a distance of w away from the middle curve.
 245     // Stores the points in ts, and returns how many of them there were.
 246     static int findSubdivPoints(final Curve c, final float[] pts,
 247                                 final float[] ts, final int type,
 248                                 final float w2)
 249     {
 250         final float x12 = pts[2] - pts[0];
 251         final float y12 = pts[3] - pts[1];
 252         // if the curve is already parallel to either axis we gain nothing
 253         // from rotating it.
 254         if ((y12 != 0.0f && x12 != 0.0f)) {
 255             // we rotate it so that the first vector in the control polygon is
 256             // parallel to the x-axis. This will ensure that rotated quarter
 257             // circles won't be subdivided.
 258             final float hypot = (float)Math.sqrt(x12 * x12 + y12 * y12);
 259             final float cos = x12 / hypot;
 260             final float sin = y12 / hypot;
 261             final float x1 = cos * pts[0] + sin * pts[1];
 262             final float y1 = cos * pts[1] - sin * pts[0];
 263             final float x2 = cos * pts[2] + sin * pts[3];
 264             final float y2 = cos * pts[3] - sin * pts[2];
 265             final float x3 = cos * pts[4] + sin * pts[5];
 266             final float y3 = cos * pts[5] - sin * pts[4];
 267 
 268             switch(type) {
 269             case 8:
 270                 final float x4 = cos * pts[6] + sin * pts[7];
 271                 final float y4 = cos * pts[7] - sin * pts[6];
 272                 c.set(x1, y1, x2, y2, x3, y3, x4, y4);
 273                 break;
 274             case 6:
 275                 c.set(x1, y1, x2, y2, x3, y3);
 276                 break;
 277             default:
 278             }
 279         } else {
 280             c.set(pts, type);
 281         }
 282 
 283         int ret = 0;
 284         // we subdivide at values of t such that the remaining rotated
 285         // curves are monotonic in x and y.
 286         ret += c.dxRoots(ts, ret);
 287         ret += c.dyRoots(ts, ret);
 288 
 289         // subdivide at inflection points.
 290         if (type == 8) {
 291             // quadratic curves can't have inflection points
 292             ret += c.infPoints(ts, ret);
 293         }
 294 
 295         // now we must subdivide at points where one of the offset curves will have
 296         // a cusp. This happens at ts where the radius of curvature is equal to w.
 297         ret += c.rootsOfROCMinusW(ts, ret, w2, 0.0001f);
 298 
 299         ret = filterOutNotInAB(ts, 0, ret, 0.0001f, 0.9999f);
 300         isort(ts, ret);
 301         return ret;
 302     }
 303 
 304     // finds values of t where the curve in pts should be subdivided in order
 305     // to get intersections with the given clip rectangle.
 306     // Stores the points in ts, and returns how many of them there were.
 307     static int findClipPoints(final Curve curve, final float[] pts,
 308                               final float[] ts, final int type,
 309                               final int outCodeOR,
 310                               final float[] clipRect)
 311     {
 312         curve.set(pts, type);
 313 
 314         // clip rectangle (ymin, ymax, xmin, xmax)
 315         int ret = 0;
 316 
 317         if ((outCodeOR & OUTCODE_LEFT) != 0) {
 318             ret += curve.xPoints(ts, ret, clipRect[2]);
 319         }
 320         if ((outCodeOR & OUTCODE_RIGHT) != 0) {
 321             ret += curve.xPoints(ts, ret, clipRect[3]);
 322         }
 323         if ((outCodeOR & OUTCODE_TOP) != 0) {
 324             ret += curve.yPoints(ts, ret, clipRect[0]);
 325         }
 326         if ((outCodeOR & OUTCODE_BOTTOM) != 0) {
 327             ret += curve.yPoints(ts, ret, clipRect[1]);
 328         }
 329         isort(ts, ret);
 330         return ret;
 331     }
 332 
 333     static void subdivide(final float[] src,
 334                           final float[] left, final float[] right,
 335                           final int type)
 336     {
 337         switch(type) {



 338         case 8:
 339             subdivideCubic(src, left, right);
 340             return;
 341         case 6:
 342             subdivideQuad(src, left, right);
 343             return;
 344         default:
 345             throw new InternalError("Unsupported curve type");
 346         }
 347     }
 348 
 349     static void isort(final float[] a, final int len) {
 350         for (int i = 1, j; i < len; i++) {
 351             final float ai = a[i];
 352             j = i - 1;
 353             for (; j >= 0 && a[j] > ai; j--) {
 354                 a[j + 1] = a[j];
 355             }
 356             a[j + 1] = ai;
 357         }
 358     }
 359 
 360     // Most of these are copied from classes in java.awt.geom because we need
 361     // both single and double precision variants of these functions, and Line2D,
 362     // CubicCurve2D, QuadCurve2D don't provide them.
 363     /**
 364      * Subdivides the cubic curve specified by the coordinates
 365      * stored in the <code>src</code> array at indices <code>srcoff</code>
 366      * through (<code>srcoff</code>&nbsp;+&nbsp;7) and stores the
 367      * resulting two subdivided curves into the two result arrays at the
 368      * corresponding indices.
 369      * Either or both of the <code>left</code> and <code>right</code>
 370      * arrays may be <code>null</code> or a reference to the same array
 371      * as the <code>src</code> array.
 372      * Note that the last point in the first subdivided curve is the
 373      * same as the first point in the second subdivided curve. Thus,
 374      * it is possible to pass the same array for <code>left</code>
 375      * and <code>right</code> and to use offsets, such as <code>rightoff</code>
 376      * equals (<code>leftoff</code> + 6), in order
 377      * to avoid allocating extra storage for this common point.
 378      * @param src the array holding the coordinates for the source curve


 379      * @param left the array for storing the coordinates for the first
 380      * half of the subdivided curve


 381      * @param right the array for storing the coordinates for the second
 382      * half of the subdivided curve


 383      * @since 1.7
 384      */
 385     static void subdivideCubic(final float[] src,
 386                                final float[] left,
 387                                final float[] right)
 388     {
 389         float  x1 = src[0];
 390         float  y1 = src[1];
 391         float cx1 = src[2];
 392         float cy1 = src[3];
 393         float cx2 = src[4];
 394         float cy2 = src[5];
 395         float  x2 = src[6];
 396         float  y2 = src[7];
 397 
 398         left[0]  = x1;
 399         left[1]  = y1;
 400 
 401         right[6] = x2;
 402         right[7] = y2;
 403 
 404         x1 = (x1 + cx1) / 2.0f;
 405         y1 = (y1 + cy1) / 2.0f;
 406         x2 = (x2 + cx2) / 2.0f;
 407         y2 = (y2 + cy2) / 2.0f;
 408 
 409         float cx = (cx1 + cx2) / 2.0f;
 410         float cy = (cy1 + cy2) / 2.0f;
 411 
 412         cx1 = (x1 + cx) / 2.0f;
 413         cy1 = (y1 + cy) / 2.0f;
 414         cx2 = (x2 + cx) / 2.0f;
 415         cy2 = (y2 + cy) / 2.0f;
 416         cx  = (cx1 + cx2) / 2.0f;
 417         cy  = (cy1 + cy2) / 2.0f;
 418 
 419         left[2] = x1;
 420         left[3] = y1;
 421         left[4] = cx1;
 422         left[5] = cy1;
 423         left[6] = cx;
 424         left[7] = cy;
 425 
 426         right[0] = cx;
 427         right[1] = cy;
 428         right[2] = cx2;
 429         right[3] = cy2;
 430         right[4] = x2;
 431         right[5] = y2;
 432     }
 433 
 434     static void subdivideCubicAt(final float t,
 435                                  final float[] src, final int offS,
 436                                  final float[] pts, final int offL, final int offR)
 437     {
 438         float  x1 = src[offS    ];
 439         float  y1 = src[offS + 1];
 440         float cx1 = src[offS + 2];
 441         float cy1 = src[offS + 3];
 442         float cx2 = src[offS + 4];
 443         float cy2 = src[offS + 5];
 444         float  x2 = src[offS + 6];
 445         float  y2 = src[offS + 7];
 446 
 447         pts[offL    ] = x1;
 448         pts[offL + 1] = y1;
 449 
 450         pts[offR + 6] = x2;
 451         pts[offR + 7] = y2;
 452 
 453         x1 =  x1 + t * (cx1 - x1);
 454         y1 =  y1 + t * (cy1 - y1);
 455         x2 = cx2 + t * (x2 - cx2);
 456         y2 = cy2 + t * (y2 - cy2);
 457 
 458         float cx = cx1 + t * (cx2 - cx1);
 459         float cy = cy1 + t * (cy2 - cy1);
 460 
 461         cx1 =  x1 + t * (cx - x1);
 462         cy1 =  y1 + t * (cy - y1);
 463         cx2 =  cx + t * (x2 - cx);
 464         cy2 =  cy + t * (y2 - cy);
 465         cx  = cx1 + t * (cx2 - cx1);
 466         cy  = cy1 + t * (cy2 - cy1);
 467 
 468         pts[offL + 2] = x1;
 469         pts[offL + 3] = y1;
 470         pts[offL + 4] = cx1;
 471         pts[offL + 5] = cy1;
 472         pts[offL + 6] = cx;
 473         pts[offL + 7] = cy;
 474 
 475         pts[offR    ] = cx;
 476         pts[offR + 1] = cy;
 477         pts[offR + 2] = cx2;
 478         pts[offR + 3] = cy2;
 479         pts[offR + 4] = x2;
 480         pts[offR + 5] = y2;
 481     }
 482 
 483     static void subdivideQuad(final float[] src,
 484                               final float[] left,
 485                               final float[] right)
 486     {
 487         float x1 = src[0];
 488         float y1 = src[1];
 489         float cx = src[2];
 490         float cy = src[3];
 491         float x2 = src[4];
 492         float y2 = src[5];
 493 
 494         left[0]  = x1;
 495         left[1]  = y1;
 496 
 497         right[4] = x2;
 498         right[5] = y2;
 499 
 500         x1 = (x1 + cx) / 2.0f;
 501         y1 = (y1 + cy) / 2.0f;
 502         x2 = (x2 + cx) / 2.0f;
 503         y2 = (y2 + cy) / 2.0f;
 504         cx = (x1 + x2) / 2.0f;
 505         cy = (y1 + y2) / 2.0f;
 506 
 507         left[2] = x1;
 508         left[3] = y1;
 509         left[4] = cx;
 510         left[5] = cy;
 511 
 512         right[0] = cx;
 513         right[1] = cy;
 514         right[2] = x2;
 515         right[3] = y2;
 516     }
 517 
 518     static void subdivideQuadAt(final float t,
 519                                 final float[] src, final int offS,
 520                                 final float[] pts, final int offL, final int offR)
 521     {
 522         float x1 = src[offS    ];
 523         float y1 = src[offS + 1];
 524         float cx = src[offS + 2];
 525         float cy = src[offS + 3];
 526         float x2 = src[offS + 4];
 527         float y2 = src[offS + 5];
 528 
 529         pts[offL    ] = x1;
 530         pts[offL + 1] = y1;
 531 
 532         pts[offR + 4] = x2;
 533         pts[offR + 5] = y2;
 534 
 535         x1 = x1 + t * (cx - x1);
 536         y1 = y1 + t * (cy - y1);
 537         x2 = cx + t * (x2 - cx);
 538         y2 = cy + t * (y2 - cy);
 539         cx = x1 + t * (x2 - x1);
 540         cy = y1 + t * (y2 - y1);
 541 
 542         pts[offL + 2] = x1;
 543         pts[offL + 3] = y1;
 544         pts[offL + 4] = cx;
 545         pts[offL + 5] = cy;
 546 
 547         pts[offR    ] = cx;
 548         pts[offR + 1] = cy;
 549         pts[offR + 2] = x2;
 550         pts[offR + 3] = y2;
 551     }
 552 
 553     static void subdivideLineAt(final float t,
 554                                 final float[] src, final int offS,
 555                                 final float[] pts, final int offL, final int offR)
 556     {
 557         float x1 = src[offS    ];
 558         float y1 = src[offS + 1];
 559         float x2 = src[offS + 2];
 560         float y2 = src[offS + 3];
 561 
 562         pts[offL    ] = x1;
 563         pts[offL + 1] = y1;
 564 
 565         pts[offR + 2] = x2;
 566         pts[offR + 3] = y2;
 567 
 568         x1 = x1 + t * (x2 - x1);
 569         y1 = y1 + t * (y2 - y1);
 570 
 571         pts[offL + 2] = x1;
 572         pts[offL + 3] = y1;
 573 
 574         pts[offR    ] = x1;
 575         pts[offR + 1] = y1;
 576     }
 577 
 578     static void subdivideAt(final float t,
 579                             final float[] src, final int offS,
 580                             final float[] pts, final int offL, final int type)
 581     {
 582         // if instead of switch (perf + most probable cases first)
 583         if (type == 8) {
 584             subdivideCubicAt(t, src, offS, pts, offL, offL + type);
 585         } else if (type == 4) {
 586             subdivideLineAt(t, src, offS, pts, offL, offL + type);
 587         } else {
 588             subdivideQuadAt(t, src, offS, pts, offL, offL + type);
 589         }
 590     }
 591 
 592     // From sun.java2d.loops.GeneralRenderer:
 593 
 594     static int outcode(final float x, final float y,
 595                        final float[] clipRect)
 596     {
 597         int code;
 598         if (y < clipRect[0]) {
 599             code = OUTCODE_TOP;
 600         } else if (y >= clipRect[1]) {
 601             code = OUTCODE_BOTTOM;
 602         } else {
 603             code = 0;
 604         }
 605         if (x < clipRect[2]) {
 606             code |= OUTCODE_LEFT;
 607         } else if (x >= clipRect[3]) {
 608             code |= OUTCODE_RIGHT;


 755             }
 756             if (DO_STATS) {
 757                 // update used marks:
 758                 if (numCurves > curveTypesUseMark) {
 759                     curveTypesUseMark = numCurves;
 760                 }
 761                 if (end > curvesUseMark) {
 762                     curvesUseMark = end;
 763                 }
 764             }
 765             final byte[]  _curveTypes = curveTypes;
 766             final float[] _curves = curves;
 767             int e = 0;
 768 
 769             for (int i = 0; i < nc; i++) {
 770                 switch(_curveTypes[i]) {
 771                 case TYPE_LINETO:
 772                     io.lineTo(_curves[e], _curves[e+1]);
 773                     e += 2;
 774                     continue;





 775                 case TYPE_CUBICTO:
 776                     io.curveTo(_curves[e],   _curves[e+1],
 777                                _curves[e+2], _curves[e+3],
 778                                _curves[e+4], _curves[e+5]);
 779                     e += 6;
 780                     continue;
 781                 case TYPE_QUADTO:
 782                     io.quadTo(_curves[e],   _curves[e+1],
 783                               _curves[e+2], _curves[e+3]);
 784                     e += 4;
 785                     continue;
 786                 default:
 787                 }
 788             }
 789             numCurves = 0;
 790             end = 0;
 791         }
 792 
 793         void popAll(final PathConsumer2D io) {
 794             int nc = numCurves;
 795             if (nc == 0) {
 796                 return;
 797             }
 798             if (DO_STATS) {
 799                 // update used marks:
 800                 if (numCurves > curveTypesUseMark) {
 801                     curveTypesUseMark = numCurves;
 802                 }
 803                 if (end > curvesUseMark) {
 804                     curvesUseMark = end;
 805                 }
 806             }
 807             final byte[]  _curveTypes = curveTypes;
 808             final float[] _curves = curves;
 809             int e  = end;
 810 
 811             while (nc != 0) {
 812                 switch(_curveTypes[--nc]) {
 813                 case TYPE_LINETO:
 814                     e -= 2;
 815                     io.lineTo(_curves[e], _curves[e+1]);
 816                     continue;





 817                 case TYPE_CUBICTO:
 818                     e -= 6;
 819                     io.curveTo(_curves[e],   _curves[e+1],
 820                                _curves[e+2], _curves[e+3],
 821                                _curves[e+4], _curves[e+5]);
 822                     continue;
 823                 case TYPE_QUADTO:
 824                     e -= 4;
 825                     io.quadTo(_curves[e],   _curves[e+1],
 826                               _curves[e+2], _curves[e+3]);
 827                     continue;
 828                 default:
 829                 }
 830             }
 831             numCurves = 0;
 832             end = 0;
 833         }
 834 
 835         @Override
 836         public String toString() {
 837             String ret = "";
 838             int nc = numCurves;
 839             int last = end;
 840             int len;
 841             while (nc != 0) {
 842                 switch(curveTypes[--nc]) {
 843                 case TYPE_LINETO:
 844                     len = 2;
 845                     ret += "line: ";
 846                     break;


< prev index next >