Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/java2d/pisces/Helpers.java
38918 views
/*1* Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.java2d.pisces;2627import java.util.Arrays;28import static java.lang.Math.PI;29import static java.lang.Math.cos;30import static java.lang.Math.sqrt;31import static java.lang.Math.cbrt;32import static java.lang.Math.acos;333435final class Helpers {36private Helpers() {37throw new Error("This is a non instantiable class");38}3940static boolean within(final float x, final float y, final float err) {41final float d = y - x;42return (d <= err && d >= -err);43}4445static boolean within(final double x, final double y, final double err) {46final double d = y - x;47return (d <= err && d >= -err);48}4950static int quadraticRoots(final float a, final float b,51final float c, float[] zeroes, final int off)52{53int ret = off;54float t;55if (a != 0f) {56final float dis = b*b - 4*a*c;57if (dis > 0) {58final float sqrtDis = (float)Math.sqrt(dis);59// depending on the sign of b we use a slightly different60// algorithm than the traditional one to find one of the roots61// so we can avoid adding numbers of different signs (which62// might result in loss of precision).63if (b >= 0) {64zeroes[ret++] = (2 * c) / (-b - sqrtDis);65zeroes[ret++] = (-b - sqrtDis) / (2 * a);66} else {67zeroes[ret++] = (-b + sqrtDis) / (2 * a);68zeroes[ret++] = (2 * c) / (-b + sqrtDis);69}70} else if (dis == 0f) {71t = (-b) / (2 * a);72zeroes[ret++] = t;73}74} else {75if (b != 0f) {76t = (-c) / b;77zeroes[ret++] = t;78}79}80return ret - off;81}8283// find the roots of g(t) = d*t^3 + a*t^2 + b*t + c in [A,B)84static int cubicRootsInAB(float d, float a, float b, float c,85float[] pts, final int off,86final float A, final float B)87{88if (d == 0) {89int num = quadraticRoots(a, b, c, pts, off);90return filterOutNotInAB(pts, off, num, A, B) - off;91}92// From Graphics Gems:93// http://tog.acm.org/resources/GraphicsGems/gems/Roots3And4.c94// (also from awt.geom.CubicCurve2D. But here we don't need as95// much accuracy and we don't want to create arrays so we use96// our own customized version).9798/* normal form: x^3 + ax^2 + bx + c = 0 */99a /= d;100b /= d;101c /= d;102103// substitute x = y - A/3 to eliminate quadratic term:104// x^3 +Px + Q = 0105//106// Since we actually need P/3 and Q/2 for all of the107// calculations that follow, we will calculate108// p = P/3109// q = Q/2110// instead and use those values for simplicity of the code.111double sq_A = a * a;112double p = 1.0/3 * (-1.0/3 * sq_A + b);113double q = 1.0/2 * (2.0/27 * a * sq_A - 1.0/3 * a * b + c);114115/* use Cardano's formula */116117double cb_p = p * p * p;118double D = q * q + cb_p;119120int num;121if (D < 0) {122// see: http://en.wikipedia.org/wiki/Cubic_function#Trigonometric_.28and_hyperbolic.29_method123final double phi = 1.0/3 * acos(-q / sqrt(-cb_p));124final double t = 2 * sqrt(-p);125126pts[ off+0 ] = (float)( t * cos(phi));127pts[ off+1 ] = (float)(-t * cos(phi + PI / 3));128pts[ off+2 ] = (float)(-t * cos(phi - PI / 3));129num = 3;130} else {131final double sqrt_D = sqrt(D);132final double u = cbrt(sqrt_D - q);133final double v = - cbrt(sqrt_D + q);134135pts[ off ] = (float)(u + v);136num = 1;137138if (within(D, 0, 1e-8)) {139pts[off+1] = -(pts[off] / 2);140num = 2;141}142}143144final float sub = 1.0f/3 * a;145146for (int i = 0; i < num; ++i) {147pts[ off+i ] -= sub;148}149150return filterOutNotInAB(pts, off, num, A, B) - off;151}152153// These use a hardcoded factor of 2 for increasing sizes. Perhaps this154// should be provided as an argument.155static float[] widenArray(float[] in, final int cursize, final int numToAdd) {156if (in.length >= cursize + numToAdd) {157return in;158}159return Arrays.copyOf(in, 2 * (cursize + numToAdd));160}161162static int[] widenArray(int[] in, final int cursize, final int numToAdd) {163if (in.length >= cursize + numToAdd) {164return in;165}166return Arrays.copyOf(in, 2 * (cursize + numToAdd));167}168169static float evalCubic(final float a, final float b,170final float c, final float d,171final float t)172{173return t * (t * (t * a + b) + c) + d;174}175176static float evalQuad(final float a, final float b,177final float c, final float t)178{179return t * (t * a + b) + c;180}181182// returns the index 1 past the last valid element remaining after filtering183static int filterOutNotInAB(float[] nums, final int off, final int len,184final float a, final float b)185{186int ret = off;187for (int i = off; i < off + len; i++) {188if (nums[i] >= a && nums[i] < b) {189nums[ret++] = nums[i];190}191}192return ret;193}194195static float polyLineLength(float[] poly, final int off, final int nCoords) {196assert nCoords % 2 == 0 && poly.length >= off + nCoords : "";197float acc = 0;198for (int i = off + 2; i < off + nCoords; i += 2) {199acc += linelen(poly[i], poly[i+1], poly[i-2], poly[i-1]);200}201return acc;202}203204static float linelen(float x1, float y1, float x2, float y2) {205final float dx = x2 - x1;206final float dy = y2 - y1;207return (float)Math.sqrt(dx*dx + dy*dy);208}209210static void subdivide(float[] src, int srcoff, float[] left, int leftoff,211float[] right, int rightoff, int type)212{213switch(type) {214case 6:215Helpers.subdivideQuad(src, srcoff, left, leftoff, right, rightoff);216break;217case 8:218Helpers.subdivideCubic(src, srcoff, left, leftoff, right, rightoff);219break;220default:221throw new InternalError("Unsupported curve type");222}223}224225static void isort(float[] a, int off, int len) {226for (int i = off + 1; i < off + len; i++) {227float ai = a[i];228int j = i - 1;229for (; j >= off && a[j] > ai; j--) {230a[j+1] = a[j];231}232a[j+1] = ai;233}234}235236// Most of these are copied from classes in java.awt.geom because we need237// float versions of these functions, and Line2D, CubicCurve2D,238// QuadCurve2D don't provide them.239/**240* Subdivides the cubic curve specified by the coordinates241* stored in the <code>src</code> array at indices <code>srcoff</code>242* through (<code>srcoff</code> + 7) and stores the243* resulting two subdivided curves into the two result arrays at the244* corresponding indices.245* Either or both of the <code>left</code> and <code>right</code>246* arrays may be <code>null</code> or a reference to the same array247* as the <code>src</code> array.248* Note that the last point in the first subdivided curve is the249* same as the first point in the second subdivided curve. Thus,250* it is possible to pass the same array for <code>left</code>251* and <code>right</code> and to use offsets, such as <code>rightoff</code>252* equals (<code>leftoff</code> + 6), in order253* to avoid allocating extra storage for this common point.254* @param src the array holding the coordinates for the source curve255* @param srcoff the offset into the array of the beginning of the256* the 6 source coordinates257* @param left the array for storing the coordinates for the first258* half of the subdivided curve259* @param leftoff the offset into the array of the beginning of the260* the 6 left coordinates261* @param right the array for storing the coordinates for the second262* half of the subdivided curve263* @param rightoff the offset into the array of the beginning of the264* the 6 right coordinates265* @since 1.7266*/267static void subdivideCubic(float src[], int srcoff,268float left[], int leftoff,269float right[], int rightoff)270{271float x1 = src[srcoff + 0];272float y1 = src[srcoff + 1];273float ctrlx1 = src[srcoff + 2];274float ctrly1 = src[srcoff + 3];275float ctrlx2 = src[srcoff + 4];276float ctrly2 = src[srcoff + 5];277float x2 = src[srcoff + 6];278float y2 = src[srcoff + 7];279if (left != null) {280left[leftoff + 0] = x1;281left[leftoff + 1] = y1;282}283if (right != null) {284right[rightoff + 6] = x2;285right[rightoff + 7] = y2;286}287x1 = (x1 + ctrlx1) / 2.0f;288y1 = (y1 + ctrly1) / 2.0f;289x2 = (x2 + ctrlx2) / 2.0f;290y2 = (y2 + ctrly2) / 2.0f;291float centerx = (ctrlx1 + ctrlx2) / 2.0f;292float centery = (ctrly1 + ctrly2) / 2.0f;293ctrlx1 = (x1 + centerx) / 2.0f;294ctrly1 = (y1 + centery) / 2.0f;295ctrlx2 = (x2 + centerx) / 2.0f;296ctrly2 = (y2 + centery) / 2.0f;297centerx = (ctrlx1 + ctrlx2) / 2.0f;298centery = (ctrly1 + ctrly2) / 2.0f;299if (left != null) {300left[leftoff + 2] = x1;301left[leftoff + 3] = y1;302left[leftoff + 4] = ctrlx1;303left[leftoff + 5] = ctrly1;304left[leftoff + 6] = centerx;305left[leftoff + 7] = centery;306}307if (right != null) {308right[rightoff + 0] = centerx;309right[rightoff + 1] = centery;310right[rightoff + 2] = ctrlx2;311right[rightoff + 3] = ctrly2;312right[rightoff + 4] = x2;313right[rightoff + 5] = y2;314}315}316317318static void subdivideCubicAt(float t, float src[], int srcoff,319float left[], int leftoff,320float right[], int rightoff)321{322float x1 = src[srcoff + 0];323float y1 = src[srcoff + 1];324float ctrlx1 = src[srcoff + 2];325float ctrly1 = src[srcoff + 3];326float ctrlx2 = src[srcoff + 4];327float ctrly2 = src[srcoff + 5];328float x2 = src[srcoff + 6];329float y2 = src[srcoff + 7];330if (left != null) {331left[leftoff + 0] = x1;332left[leftoff + 1] = y1;333}334if (right != null) {335right[rightoff + 6] = x2;336right[rightoff + 7] = y2;337}338x1 = x1 + t * (ctrlx1 - x1);339y1 = y1 + t * (ctrly1 - y1);340x2 = ctrlx2 + t * (x2 - ctrlx2);341y2 = ctrly2 + t * (y2 - ctrly2);342float centerx = ctrlx1 + t * (ctrlx2 - ctrlx1);343float centery = ctrly1 + t * (ctrly2 - ctrly1);344ctrlx1 = x1 + t * (centerx - x1);345ctrly1 = y1 + t * (centery - y1);346ctrlx2 = centerx + t * (x2 - centerx);347ctrly2 = centery + t * (y2 - centery);348centerx = ctrlx1 + t * (ctrlx2 - ctrlx1);349centery = ctrly1 + t * (ctrly2 - ctrly1);350if (left != null) {351left[leftoff + 2] = x1;352left[leftoff + 3] = y1;353left[leftoff + 4] = ctrlx1;354left[leftoff + 5] = ctrly1;355left[leftoff + 6] = centerx;356left[leftoff + 7] = centery;357}358if (right != null) {359right[rightoff + 0] = centerx;360right[rightoff + 1] = centery;361right[rightoff + 2] = ctrlx2;362right[rightoff + 3] = ctrly2;363right[rightoff + 4] = x2;364right[rightoff + 5] = y2;365}366}367368static void subdivideQuad(float src[], int srcoff,369float left[], int leftoff,370float right[], int rightoff)371{372float x1 = src[srcoff + 0];373float y1 = src[srcoff + 1];374float ctrlx = src[srcoff + 2];375float ctrly = src[srcoff + 3];376float x2 = src[srcoff + 4];377float y2 = src[srcoff + 5];378if (left != null) {379left[leftoff + 0] = x1;380left[leftoff + 1] = y1;381}382if (right != null) {383right[rightoff + 4] = x2;384right[rightoff + 5] = y2;385}386x1 = (x1 + ctrlx) / 2.0f;387y1 = (y1 + ctrly) / 2.0f;388x2 = (x2 + ctrlx) / 2.0f;389y2 = (y2 + ctrly) / 2.0f;390ctrlx = (x1 + x2) / 2.0f;391ctrly = (y1 + y2) / 2.0f;392if (left != null) {393left[leftoff + 2] = x1;394left[leftoff + 3] = y1;395left[leftoff + 4] = ctrlx;396left[leftoff + 5] = ctrly;397}398if (right != null) {399right[rightoff + 0] = ctrlx;400right[rightoff + 1] = ctrly;401right[rightoff + 2] = x2;402right[rightoff + 3] = y2;403}404}405406static void subdivideQuadAt(float t, float src[], int srcoff,407float left[], int leftoff,408float right[], int rightoff)409{410float x1 = src[srcoff + 0];411float y1 = src[srcoff + 1];412float ctrlx = src[srcoff + 2];413float ctrly = src[srcoff + 3];414float x2 = src[srcoff + 4];415float y2 = src[srcoff + 5];416if (left != null) {417left[leftoff + 0] = x1;418left[leftoff + 1] = y1;419}420if (right != null) {421right[rightoff + 4] = x2;422right[rightoff + 5] = y2;423}424x1 = x1 + t * (ctrlx - x1);425y1 = y1 + t * (ctrly - y1);426x2 = ctrlx + t * (x2 - ctrlx);427y2 = ctrly + t * (y2 - ctrly);428ctrlx = x1 + t * (x2 - x1);429ctrly = y1 + t * (y2 - y1);430if (left != null) {431left[leftoff + 2] = x1;432left[leftoff + 3] = y1;433left[leftoff + 4] = ctrlx;434left[leftoff + 5] = ctrly;435}436if (right != null) {437right[rightoff + 0] = ctrlx;438right[rightoff + 1] = ctrly;439right[rightoff + 2] = x2;440right[rightoff + 3] = y2;441}442}443444static void subdivideAt(float t, float src[], int srcoff,445float left[], int leftoff,446float right[], int rightoff, int size)447{448switch(size) {449case 8:450subdivideCubicAt(t, src, srcoff, left, leftoff, right, rightoff);451break;452case 6:453subdivideQuadAt(t, src, srcoff, left, leftoff, right, rightoff);454break;455}456}457}458459460