feat(jdk8): move files to new folder to avoid resources compiled.

This commit is contained in:
2025-09-07 15:25:52 +08:00
parent 3f0047bf6f
commit 8c35cfb1c0
17415 changed files with 217 additions and 213 deletions

View File

@@ -0,0 +1,561 @@
/*
* Copyright (c) 1998, 2003, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.awt.geom;
import java.util.Vector;
import java.util.Enumeration;
import java.util.Comparator;
import java.util.Arrays;
public abstract class AreaOp {
public static abstract class CAGOp extends AreaOp {
boolean inLeft;
boolean inRight;
boolean inResult;
public void newRow() {
inLeft = false;
inRight = false;
inResult = false;
}
public int classify(Edge e) {
if (e.getCurveTag() == CTAG_LEFT) {
inLeft = !inLeft;
} else {
inRight = !inRight;
}
boolean newClass = newClassification(inLeft, inRight);
if (inResult == newClass) {
return ETAG_IGNORE;
}
inResult = newClass;
return (newClass ? ETAG_ENTER : ETAG_EXIT);
}
public int getState() {
return (inResult ? RSTAG_INSIDE : RSTAG_OUTSIDE);
}
public abstract boolean newClassification(boolean inLeft,
boolean inRight);
}
public static class AddOp extends CAGOp {
public boolean newClassification(boolean inLeft, boolean inRight) {
return (inLeft || inRight);
}
}
public static class SubOp extends CAGOp {
public boolean newClassification(boolean inLeft, boolean inRight) {
return (inLeft && !inRight);
}
}
public static class IntOp extends CAGOp {
public boolean newClassification(boolean inLeft, boolean inRight) {
return (inLeft && inRight);
}
}
public static class XorOp extends CAGOp {
public boolean newClassification(boolean inLeft, boolean inRight) {
return (inLeft != inRight);
}
}
public static class NZWindOp extends AreaOp {
private int count;
public void newRow() {
count = 0;
}
public int classify(Edge e) {
// Note: the right curves should be an empty set with this op...
// assert(e.getCurveTag() == CTAG_LEFT);
int newCount = count;
int type = (newCount == 0 ? ETAG_ENTER : ETAG_IGNORE);
newCount += e.getCurve().getDirection();
count = newCount;
return (newCount == 0 ? ETAG_EXIT : type);
}
public int getState() {
return ((count == 0) ? RSTAG_OUTSIDE : RSTAG_INSIDE);
}
}
public static class EOWindOp extends AreaOp {
private boolean inside;
public void newRow() {
inside = false;
}
public int classify(Edge e) {
// Note: the right curves should be an empty set with this op...
// assert(e.getCurveTag() == CTAG_LEFT);
boolean newInside = !inside;
inside = newInside;
return (newInside ? ETAG_ENTER : ETAG_EXIT);
}
public int getState() {
return (inside ? RSTAG_INSIDE : RSTAG_OUTSIDE);
}
}
private AreaOp() {
}
/* Constants to tag the left and right curves in the edge list */
public static final int CTAG_LEFT = 0;
public static final int CTAG_RIGHT = 1;
/* Constants to classify edges */
public static final int ETAG_IGNORE = 0;
public static final int ETAG_ENTER = 1;
public static final int ETAG_EXIT = -1;
/* Constants used to classify result state */
public static final int RSTAG_INSIDE = 1;
public static final int RSTAG_OUTSIDE = -1;
public abstract void newRow();
public abstract int classify(Edge e);
public abstract int getState();
public Vector calculate(Vector left, Vector right) {
Vector edges = new Vector();
addEdges(edges, left, AreaOp.CTAG_LEFT);
addEdges(edges, right, AreaOp.CTAG_RIGHT);
edges = pruneEdges(edges);
if (false) {
System.out.println("result: ");
int numcurves = edges.size();
Curve[] curvelist = (Curve[]) edges.toArray(new Curve[numcurves]);
for (int i = 0; i < numcurves; i++) {
System.out.println("curvelist["+i+"] = "+curvelist[i]);
}
}
return edges;
}
private static void addEdges(Vector edges, Vector curves, int curvetag) {
Enumeration enum_ = curves.elements();
while (enum_.hasMoreElements()) {
Curve c = (Curve) enum_.nextElement();
if (c.getOrder() > 0) {
edges.add(new Edge(c, curvetag));
}
}
}
private static Comparator YXTopComparator = new Comparator() {
public int compare(Object o1, Object o2) {
Curve c1 = ((Edge) o1).getCurve();
Curve c2 = ((Edge) o2).getCurve();
double v1, v2;
if ((v1 = c1.getYTop()) == (v2 = c2.getYTop())) {
if ((v1 = c1.getXTop()) == (v2 = c2.getXTop())) {
return 0;
}
}
if (v1 < v2) {
return -1;
}
return 1;
}
};
private Vector pruneEdges(Vector edges) {
int numedges = edges.size();
if (numedges < 2) {
return edges;
}
Edge[] edgelist = (Edge[]) edges.toArray(new Edge[numedges]);
Arrays.sort(edgelist, YXTopComparator);
if (false) {
System.out.println("pruning: ");
for (int i = 0; i < numedges; i++) {
System.out.println("edgelist["+i+"] = "+edgelist[i]);
}
}
Edge e;
int left = 0;
int right = 0;
int cur = 0;
int next = 0;
double yrange[] = new double[2];
Vector subcurves = new Vector();
Vector chains = new Vector();
Vector links = new Vector();
// Active edges are between left (inclusive) and right (exclusive)
while (left < numedges) {
double y = yrange[0];
// Prune active edges that fall off the top of the active y range
for (cur = next = right - 1; cur >= left; cur--) {
e = edgelist[cur];
if (e.getCurve().getYBot() > y) {
if (next > cur) {
edgelist[next] = e;
}
next--;
}
}
left = next + 1;
// Grab a new "top of Y range" if the active edges are empty
if (left >= right) {
if (right >= numedges) {
break;
}
y = edgelist[right].getCurve().getYTop();
if (y > yrange[0]) {
finalizeSubCurves(subcurves, chains);
}
yrange[0] = y;
}
// Incorporate new active edges that enter the active y range
while (right < numedges) {
e = edgelist[right];
if (e.getCurve().getYTop() > y) {
break;
}
right++;
}
// Sort the current active edges by their X values and
// determine the maximum valid Y range where the X ordering
// is correct
yrange[1] = edgelist[left].getCurve().getYBot();
if (right < numedges) {
y = edgelist[right].getCurve().getYTop();
if (yrange[1] > y) {
yrange[1] = y;
}
}
if (false) {
System.out.println("current line: y = ["+
yrange[0]+", "+yrange[1]+"]");
for (cur = left; cur < right; cur++) {
System.out.println(" "+edgelist[cur]);
}
}
// Note: We could start at left+1, but we need to make
// sure that edgelist[left] has its equivalence set to 0.
int nexteq = 1;
for (cur = left; cur < right; cur++) {
e = edgelist[cur];
e.setEquivalence(0);
for (next = cur; next > left; next--) {
Edge prevedge = edgelist[next-1];
int ordering = e.compareTo(prevedge, yrange);
if (yrange[1] <= yrange[0]) {
throw new InternalError("backstepping to "+yrange[1]+
" from "+yrange[0]);
}
if (ordering >= 0) {
if (ordering == 0) {
// If the curves are equal, mark them to be
// deleted later if they cancel each other
// out so that we avoid having extraneous
// curve segments.
int eq = prevedge.getEquivalence();
if (eq == 0) {
eq = nexteq++;
prevedge.setEquivalence(eq);
}
e.setEquivalence(eq);
}
break;
}
edgelist[next] = prevedge;
}
edgelist[next] = e;
}
if (false) {
System.out.println("current sorted line: y = ["+
yrange[0]+", "+yrange[1]+"]");
for (cur = left; cur < right; cur++) {
System.out.println(" "+edgelist[cur]);
}
}
// Now prune the active edge list.
// For each edge in the list, determine its classification
// (entering shape, exiting shape, ignore - no change) and
// record the current Y range and its classification in the
// Edge object for use later in constructing the new outline.
newRow();
double ystart = yrange[0];
double yend = yrange[1];
for (cur = left; cur < right; cur++) {
e = edgelist[cur];
int etag;
int eq = e.getEquivalence();
if (eq != 0) {
// Find one of the segments in the "equal" range
// with the right transition state and prefer an
// edge that was either active up until ystart
// or the edge that extends the furthest downward
// (i.e. has the most potential for continuation)
int origstate = getState();
etag = (origstate == AreaOp.RSTAG_INSIDE
? AreaOp.ETAG_EXIT
: AreaOp.ETAG_ENTER);
Edge activematch = null;
Edge longestmatch = e;
double furthesty = yend;
do {
// Note: classify() must be called
// on every edge we consume here.
classify(e);
if (activematch == null &&
e.isActiveFor(ystart, etag))
{
activematch = e;
}
y = e.getCurve().getYBot();
if (y > furthesty) {
longestmatch = e;
furthesty = y;
}
} while (++cur < right &&
(e = edgelist[cur]).getEquivalence() == eq);
--cur;
if (getState() == origstate) {
etag = AreaOp.ETAG_IGNORE;
} else {
e = (activematch != null ? activematch : longestmatch);
}
} else {
etag = classify(e);
}
if (etag != AreaOp.ETAG_IGNORE) {
e.record(yend, etag);
links.add(new CurveLink(e.getCurve(), ystart, yend, etag));
}
}
// assert(getState() == AreaOp.RSTAG_OUTSIDE);
if (getState() != AreaOp.RSTAG_OUTSIDE) {
System.out.println("Still inside at end of active edge list!");
System.out.println("num curves = "+(right-left));
System.out.println("num links = "+links.size());
System.out.println("y top = "+yrange[0]);
if (right < numedges) {
System.out.println("y top of next curve = "+
edgelist[right].getCurve().getYTop());
} else {
System.out.println("no more curves");
}
for (cur = left; cur < right; cur++) {
e = edgelist[cur];
System.out.println(e);
int eq = e.getEquivalence();
if (eq != 0) {
System.out.println(" was equal to "+eq+"...");
}
}
}
if (false) {
System.out.println("new links:");
for (int i = 0; i < links.size(); i++) {
CurveLink link = (CurveLink) links.elementAt(i);
System.out.println(" "+link.getSubCurve());
}
}
resolveLinks(subcurves, chains, links);
links.clear();
// Finally capture the bottom of the valid Y range as the top
// of the next Y range.
yrange[0] = yend;
}
finalizeSubCurves(subcurves, chains);
Vector ret = new Vector();
Enumeration enum_ = subcurves.elements();
while (enum_.hasMoreElements()) {
CurveLink link = (CurveLink) enum_.nextElement();
ret.add(link.getMoveto());
CurveLink nextlink = link;
while ((nextlink = nextlink.getNext()) != null) {
if (!link.absorb(nextlink)) {
ret.add(link.getSubCurve());
link = nextlink;
}
}
ret.add(link.getSubCurve());
}
return ret;
}
public static void finalizeSubCurves(Vector subcurves, Vector chains) {
int numchains = chains.size();
if (numchains == 0) {
return;
}
if ((numchains & 1) != 0) {
throw new InternalError("Odd number of chains!");
}
ChainEnd[] endlist = new ChainEnd[numchains];
chains.toArray(endlist);
for (int i = 1; i < numchains; i += 2) {
ChainEnd open = endlist[i - 1];
ChainEnd close = endlist[i];
CurveLink subcurve = open.linkTo(close);
if (subcurve != null) {
subcurves.add(subcurve);
}
}
chains.clear();
}
private static CurveLink[] EmptyLinkList = new CurveLink[2];
private static ChainEnd[] EmptyChainList = new ChainEnd[2];
public static void resolveLinks(Vector subcurves,
Vector chains,
Vector links)
{
int numlinks = links.size();
CurveLink[] linklist;
if (numlinks == 0) {
linklist = EmptyLinkList;
} else {
if ((numlinks & 1) != 0) {
throw new InternalError("Odd number of new curves!");
}
linklist = new CurveLink[numlinks+2];
links.toArray(linklist);
}
int numchains = chains.size();
ChainEnd[] endlist;
if (numchains == 0) {
endlist = EmptyChainList;
} else {
if ((numchains & 1) != 0) {
throw new InternalError("Odd number of chains!");
}
endlist = new ChainEnd[numchains+2];
chains.toArray(endlist);
}
int curchain = 0;
int curlink = 0;
chains.clear();
ChainEnd chain = endlist[0];
ChainEnd nextchain = endlist[1];
CurveLink link = linklist[0];
CurveLink nextlink = linklist[1];
while (chain != null || link != null) {
/*
* Strategy 1:
* Connect chains or links if they are the only things left...
*/
boolean connectchains = (link == null);
boolean connectlinks = (chain == null);
if (!connectchains && !connectlinks) {
// assert(link != null && chain != null);
/*
* Strategy 2:
* Connect chains or links if they close off an open area...
*/
connectchains = ((curchain & 1) == 0 &&
chain.getX() == nextchain.getX());
connectlinks = ((curlink & 1) == 0 &&
link.getX() == nextlink.getX());
if (!connectchains && !connectlinks) {
/*
* Strategy 3:
* Connect chains or links if their successor is
* between them and their potential connectee...
*/
double cx = chain.getX();
double lx = link.getX();
connectchains =
(nextchain != null && cx < lx &&
obstructs(nextchain.getX(), lx, curchain));
connectlinks =
(nextlink != null && lx < cx &&
obstructs(nextlink.getX(), cx, curlink));
}
}
if (connectchains) {
CurveLink subcurve = chain.linkTo(nextchain);
if (subcurve != null) {
subcurves.add(subcurve);
}
curchain += 2;
chain = endlist[curchain];
nextchain = endlist[curchain+1];
}
if (connectlinks) {
ChainEnd openend = new ChainEnd(link, null);
ChainEnd closeend = new ChainEnd(nextlink, openend);
openend.setOtherEnd(closeend);
chains.add(openend);
chains.add(closeend);
curlink += 2;
link = linklist[curlink];
nextlink = linklist[curlink+1];
}
if (!connectchains && !connectlinks) {
// assert(link != null);
// assert(chain != null);
// assert(chain.getEtag() == link.getEtag());
chain.addLink(link);
chains.add(chain);
curchain++;
chain = nextchain;
nextchain = endlist[curchain+1];
curlink++;
link = nextlink;
nextlink = linklist[curlink+1];
}
}
if ((chains.size() & 1) != 0) {
System.out.println("Odd number of chains!");
}
}
/*
* Does the position of the next edge at v1 "obstruct" the
* connectivity between current edge and the potential
* partner edge which is positioned at v2?
*
* Phase tells us whether we are testing for a transition
* into or out of the interior part of the resulting area.
*
* Require 4-connected continuity if this edge and the partner
* edge are both "entering into" type edges
* Allow 8-connected continuity for "exiting from" type edges
*/
public static boolean obstructs(double v1, double v2, int phase) {
return (((phase & 1) == 0) ? (v1 <= v2) : (v1 < v2));
}
}

View File

@@ -0,0 +1,117 @@
/*
* Copyright (c) 1998, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.awt.geom;
final class ChainEnd {
CurveLink head;
CurveLink tail;
ChainEnd partner;
int etag;
public ChainEnd(CurveLink first, ChainEnd partner) {
this.head = first;
this.tail = first;
this.partner = partner;
this.etag = first.getEdgeTag();
}
public CurveLink getChain() {
return head;
}
public void setOtherEnd(ChainEnd partner) {
this.partner = partner;
}
public ChainEnd getPartner() {
return partner;
}
/*
* Returns head of a complete chain to be added to subcurves
* or null if the links did not complete such a chain.
*/
public CurveLink linkTo(ChainEnd that) {
if (etag == AreaOp.ETAG_IGNORE ||
that.etag == AreaOp.ETAG_IGNORE)
{
throw new InternalError("ChainEnd linked more than once!");
}
if (etag == that.etag) {
throw new InternalError("Linking chains of the same type!");
}
ChainEnd enter, exit;
// assert(partner.etag != that.partner.etag);
if (etag == AreaOp.ETAG_ENTER) {
enter = this;
exit = that;
} else {
enter = that;
exit = this;
}
// Now make sure these ChainEnds are not linked to any others...
etag = AreaOp.ETAG_IGNORE;
that.etag = AreaOp.ETAG_IGNORE;
// Now link everything up...
enter.tail.setNext(exit.head);
enter.tail = exit.tail;
if (partner == that) {
// Curve has closed on itself...
return enter.head;
}
// Link this chain into one end of the chain formed by the partners
ChainEnd otherenter = exit.partner;
ChainEnd otherexit = enter.partner;
otherenter.partner = otherexit;
otherexit.partner = otherenter;
if (enter.head.getYTop() < otherenter.head.getYTop()) {
enter.tail.setNext(otherenter.head);
otherenter.head = enter.head;
} else {
otherexit.tail.setNext(enter.head);
otherexit.tail = enter.tail;
}
return null;
}
public void addLink(CurveLink newlink) {
if (etag == AreaOp.ETAG_ENTER) {
tail.setNext(newlink);
tail = newlink;
} else {
newlink.setNext(head);
head = newlink;
}
}
public double getX() {
if (etag == AreaOp.ETAG_ENTER) {
return tail.getXBot();
} else {
return head.getXBot();
}
}
}

View File

@@ -0,0 +1,522 @@
/*
* Copyright (c) 1998, 2003, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.awt.geom;
import java.awt.geom.PathIterator;
import java.util.Vector;
import java.util.Enumeration;
public abstract class Crossings {
public static final boolean debug = false;
int limit = 0;
double yranges[] = new double[10];
double xlo, ylo, xhi, yhi;
public Crossings(double xlo, double ylo, double xhi, double yhi) {
this.xlo = xlo;
this.ylo = ylo;
this.xhi = xhi;
this.yhi = yhi;
}
public final double getXLo() {
return xlo;
}
public final double getYLo() {
return ylo;
}
public final double getXHi() {
return xhi;
}
public final double getYHi() {
return yhi;
}
public abstract void record(double ystart, double yend, int direction);
public void print() {
System.out.println("Crossings [");
System.out.println(" bounds = ["+ylo+", "+yhi+"]");
for (int i = 0; i < limit; i += 2) {
System.out.println(" ["+yranges[i]+", "+yranges[i+1]+"]");
}
System.out.println("]");
}
public final boolean isEmpty() {
return (limit == 0);
}
public abstract boolean covers(double ystart, double yend);
public static Crossings findCrossings(Vector curves,
double xlo, double ylo,
double xhi, double yhi)
{
Crossings cross = new EvenOdd(xlo, ylo, xhi, yhi);
Enumeration enum_ = curves.elements();
while (enum_.hasMoreElements()) {
Curve c = (Curve) enum_.nextElement();
if (c.accumulateCrossings(cross)) {
return null;
}
}
if (debug) {
cross.print();
}
return cross;
}
public static Crossings findCrossings(PathIterator pi,
double xlo, double ylo,
double xhi, double yhi)
{
Crossings cross;
if (pi.getWindingRule() == pi.WIND_EVEN_ODD) {
cross = new EvenOdd(xlo, ylo, xhi, yhi);
} else {
cross = new NonZero(xlo, ylo, xhi, yhi);
}
// coords array is big enough for holding:
// coordinates returned from currentSegment (6)
// OR
// two subdivided quadratic curves (2+4+4=10)
// AND
// 0-1 horizontal splitting parameters
// OR
// 2 parametric equation derivative coefficients
// OR
// three subdivided cubic curves (2+6+6+6=20)
// AND
// 0-2 horizontal splitting parameters
// OR
// 3 parametric equation derivative coefficients
double coords[] = new double[23];
double movx = 0;
double movy = 0;
double curx = 0;
double cury = 0;
double newx, newy;
while (!pi.isDone()) {
int type = pi.currentSegment(coords);
switch (type) {
case PathIterator.SEG_MOVETO:
if (movy != cury &&
cross.accumulateLine(curx, cury, movx, movy))
{
return null;
}
movx = curx = coords[0];
movy = cury = coords[1];
break;
case PathIterator.SEG_LINETO:
newx = coords[0];
newy = coords[1];
if (cross.accumulateLine(curx, cury, newx, newy)) {
return null;
}
curx = newx;
cury = newy;
break;
case PathIterator.SEG_QUADTO:
newx = coords[2];
newy = coords[3];
if (cross.accumulateQuad(curx, cury, coords)) {
return null;
}
curx = newx;
cury = newy;
break;
case PathIterator.SEG_CUBICTO:
newx = coords[4];
newy = coords[5];
if (cross.accumulateCubic(curx, cury, coords)) {
return null;
}
curx = newx;
cury = newy;
break;
case PathIterator.SEG_CLOSE:
if (movy != cury &&
cross.accumulateLine(curx, cury, movx, movy))
{
return null;
}
curx = movx;
cury = movy;
break;
}
pi.next();
}
if (movy != cury) {
if (cross.accumulateLine(curx, cury, movx, movy)) {
return null;
}
}
if (debug) {
cross.print();
}
return cross;
}
public boolean accumulateLine(double x0, double y0,
double x1, double y1)
{
if (y0 <= y1) {
return accumulateLine(x0, y0, x1, y1, 1);
} else {
return accumulateLine(x1, y1, x0, y0, -1);
}
}
public boolean accumulateLine(double x0, double y0,
double x1, double y1,
int direction)
{
if (yhi <= y0 || ylo >= y1) {
return false;
}
if (x0 >= xhi && x1 >= xhi) {
return false;
}
if (y0 == y1) {
return (x0 >= xlo || x1 >= xlo);
}
double xstart, ystart, xend, yend;
double dx = (x1 - x0);
double dy = (y1 - y0);
if (y0 < ylo) {
xstart = x0 + (ylo - y0) * dx / dy;
ystart = ylo;
} else {
xstart = x0;
ystart = y0;
}
if (yhi < y1) {
xend = x0 + (yhi - y0) * dx / dy;
yend = yhi;
} else {
xend = x1;
yend = y1;
}
if (xstart >= xhi && xend >= xhi) {
return false;
}
if (xstart > xlo || xend > xlo) {
return true;
}
record(ystart, yend, direction);
return false;
}
private Vector tmp = new Vector();
public boolean accumulateQuad(double x0, double y0, double coords[]) {
if (y0 < ylo && coords[1] < ylo && coords[3] < ylo) {
return false;
}
if (y0 > yhi && coords[1] > yhi && coords[3] > yhi) {
return false;
}
if (x0 > xhi && coords[0] > xhi && coords[2] > xhi) {
return false;
}
if (x0 < xlo && coords[0] < xlo && coords[2] < xlo) {
if (y0 < coords[3]) {
record(Math.max(y0, ylo), Math.min(coords[3], yhi), 1);
} else if (y0 > coords[3]) {
record(Math.max(coords[3], ylo), Math.min(y0, yhi), -1);
}
return false;
}
Curve.insertQuad(tmp, x0, y0, coords);
Enumeration enum_ = tmp.elements();
while (enum_.hasMoreElements()) {
Curve c = (Curve) enum_.nextElement();
if (c.accumulateCrossings(this)) {
return true;
}
}
tmp.clear();
return false;
}
public boolean accumulateCubic(double x0, double y0, double coords[]) {
if (y0 < ylo && coords[1] < ylo &&
coords[3] < ylo && coords[5] < ylo)
{
return false;
}
if (y0 > yhi && coords[1] > yhi &&
coords[3] > yhi && coords[5] > yhi)
{
return false;
}
if (x0 > xhi && coords[0] > xhi &&
coords[2] > xhi && coords[4] > xhi)
{
return false;
}
if (x0 < xlo && coords[0] < xlo &&
coords[2] < xlo && coords[4] < xlo)
{
if (y0 <= coords[5]) {
record(Math.max(y0, ylo), Math.min(coords[5], yhi), 1);
} else {
record(Math.max(coords[5], ylo), Math.min(y0, yhi), -1);
}
return false;
}
Curve.insertCubic(tmp, x0, y0, coords);
Enumeration enum_ = tmp.elements();
while (enum_.hasMoreElements()) {
Curve c = (Curve) enum_.nextElement();
if (c.accumulateCrossings(this)) {
return true;
}
}
tmp.clear();
return false;
}
public final static class EvenOdd extends Crossings {
public EvenOdd(double xlo, double ylo, double xhi, double yhi) {
super(xlo, ylo, xhi, yhi);
}
public final boolean covers(double ystart, double yend) {
return (limit == 2 && yranges[0] <= ystart && yranges[1] >= yend);
}
public void record(double ystart, double yend, int direction) {
if (ystart >= yend) {
return;
}
int from = 0;
// Quickly jump over all pairs that are completely "above"
while (from < limit && ystart > yranges[from+1]) {
from += 2;
}
int to = from;
while (from < limit) {
double yrlo = yranges[from++];
double yrhi = yranges[from++];
if (yend < yrlo) {
// Quickly handle insertion of the new range
yranges[to++] = ystart;
yranges[to++] = yend;
ystart = yrlo;
yend = yrhi;
continue;
}
// The ranges overlap - sort, collapse, insert, iterate
double yll, ylh, yhl, yhh;
if (ystart < yrlo) {
yll = ystart;
ylh = yrlo;
} else {
yll = yrlo;
ylh = ystart;
}
if (yend < yrhi) {
yhl = yend;
yhh = yrhi;
} else {
yhl = yrhi;
yhh = yend;
}
if (ylh == yhl) {
ystart = yll;
yend = yhh;
} else {
if (ylh > yhl) {
ystart = yhl;
yhl = ylh;
ylh = ystart;
}
if (yll != ylh) {
yranges[to++] = yll;
yranges[to++] = ylh;
}
ystart = yhl;
yend = yhh;
}
if (ystart >= yend) {
break;
}
}
if (to < from && from < limit) {
System.arraycopy(yranges, from, yranges, to, limit-from);
}
to += (limit-from);
if (ystart < yend) {
if (to >= yranges.length) {
double newranges[] = new double[to+10];
System.arraycopy(yranges, 0, newranges, 0, to);
yranges = newranges;
}
yranges[to++] = ystart;
yranges[to++] = yend;
}
limit = to;
}
}
public final static class NonZero extends Crossings {
private int crosscounts[];
public NonZero(double xlo, double ylo, double xhi, double yhi) {
super(xlo, ylo, xhi, yhi);
crosscounts = new int[yranges.length / 2];
}
public final boolean covers(double ystart, double yend) {
int i = 0;
while (i < limit) {
double ylo = yranges[i++];
double yhi = yranges[i++];
if (ystart >= yhi) {
continue;
}
if (ystart < ylo) {
return false;
}
if (yend <= yhi) {
return true;
}
ystart = yhi;
}
return (ystart >= yend);
}
public void remove(int cur) {
limit -= 2;
int rem = limit - cur;
if (rem > 0) {
System.arraycopy(yranges, cur+2, yranges, cur, rem);
System.arraycopy(crosscounts, cur/2+1,
crosscounts, cur/2,
rem/2);
}
}
public void insert(int cur, double lo, double hi, int dir) {
int rem = limit - cur;
double oldranges[] = yranges;
int oldcounts[] = crosscounts;
if (limit >= yranges.length) {
yranges = new double[limit+10];
System.arraycopy(oldranges, 0, yranges, 0, cur);
crosscounts = new int[(limit+10)/2];
System.arraycopy(oldcounts, 0, crosscounts, 0, cur/2);
}
if (rem > 0) {
System.arraycopy(oldranges, cur, yranges, cur+2, rem);
System.arraycopy(oldcounts, cur/2,
crosscounts, cur/2+1,
rem/2);
}
yranges[cur+0] = lo;
yranges[cur+1] = hi;
crosscounts[cur/2] = dir;
limit += 2;
}
public void record(double ystart, double yend, int direction) {
if (ystart >= yend) {
return;
}
int cur = 0;
// Quickly jump over all pairs that are completely "above"
while (cur < limit && ystart > yranges[cur+1]) {
cur += 2;
}
if (cur < limit) {
int rdir = crosscounts[cur/2];
double yrlo = yranges[cur+0];
double yrhi = yranges[cur+1];
if (yrhi == ystart && rdir == direction) {
// Remove the range from the list and collapse it
// into the range being inserted. Note that the
// new combined range may overlap the following range
// so we must not simply combine the ranges in place
// unless we are at the last range.
if (cur+2 == limit) {
yranges[cur+1] = yend;
return;
}
remove(cur);
ystart = yrlo;
rdir = crosscounts[cur/2];
yrlo = yranges[cur+0];
yrhi = yranges[cur+1];
}
if (yend < yrlo) {
// Just insert the new range at the current location
insert(cur, ystart, yend, direction);
return;
}
if (yend == yrlo && rdir == direction) {
// Just prepend the new range to the current one
yranges[cur] = ystart;
return;
}
// The ranges must overlap - (yend > yrlo && yrhi > ystart)
if (ystart < yrlo) {
insert(cur, ystart, yrlo, direction);
cur += 2;
ystart = yrlo;
} else if (yrlo < ystart) {
insert(cur, yrlo, ystart, rdir);
cur += 2;
yrlo = ystart;
}
// assert(yrlo == ystart);
int newdir = rdir + direction;
double newend = Math.min(yend, yrhi);
if (newdir == 0) {
remove(cur);
} else {
crosscounts[cur/2] = newdir;
yranges[cur++] = ystart;
yranges[cur++] = newend;
}
ystart = yrlo = newend;
if (yrlo < yrhi) {
insert(cur, yrlo, yrhi, rdir);
}
}
if (ystart < yend) {
insert(cur, ystart, yend, direction);
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,114 @@
/*
* Copyright (c) 1998, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.awt.geom;
final class CurveLink {
Curve curve;
double ytop;
double ybot;
int etag;
CurveLink next;
public CurveLink(Curve curve, double ystart, double yend, int etag) {
this.curve = curve;
this.ytop = ystart;
this.ybot = yend;
this.etag = etag;
if (ytop < curve.getYTop() || ybot > curve.getYBot()) {
throw new InternalError("bad curvelink ["+ytop+"=>"+ybot+"] for "+curve);
}
}
public boolean absorb(CurveLink link) {
return absorb(link.curve, link.ytop, link.ybot, link.etag);
}
public boolean absorb(Curve curve, double ystart, double yend, int etag) {
if (this.curve != curve || this.etag != etag ||
ybot < ystart || ytop > yend)
{
return false;
}
if (ystart < curve.getYTop() || yend > curve.getYBot()) {
throw new InternalError("bad curvelink ["+ystart+"=>"+yend+"] for "+curve);
}
this.ytop = Math.min(ytop, ystart);
this.ybot = Math.max(ybot, yend);
return true;
}
public boolean isEmpty() {
return (ytop == ybot);
}
public Curve getCurve() {
return curve;
}
public Curve getSubCurve() {
if (ytop == curve.getYTop() && ybot == curve.getYBot()) {
return curve.getWithDirection(etag);
}
return curve.getSubCurve(ytop, ybot, etag);
}
public Curve getMoveto() {
return new Order0(getXTop(), getYTop());
}
public double getXTop() {
return curve.XforY(ytop);
}
public double getYTop() {
return ytop;
}
public double getXBot() {
return curve.XforY(ybot);
}
public double getYBot() {
return ybot;
}
public double getX() {
return curve.XforY(ytop);
}
public int getEdgeTag() {
return etag;
}
public void setNext(CurveLink link) {
this.next = link;
}
public CurveLink getNext() {
return next;
}
}

View File

@@ -0,0 +1,125 @@
/*
* Copyright (c) 1998, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.awt.geom;
final class Edge {
static final int INIT_PARTS = 4;
static final int GROW_PARTS = 10;
Curve curve;
int ctag;
int etag;
double activey;
int equivalence;
public Edge(Curve c, int ctag) {
this(c, ctag, AreaOp.ETAG_IGNORE);
}
public Edge(Curve c, int ctag, int etag) {
this.curve = c;
this.ctag = ctag;
this.etag = etag;
}
public Curve getCurve() {
return curve;
}
public int getCurveTag() {
return ctag;
}
public int getEdgeTag() {
return etag;
}
public void setEdgeTag(int etag) {
this.etag = etag;
}
public int getEquivalence() {
return equivalence;
}
public void setEquivalence(int eq) {
equivalence = eq;
}
private Edge lastEdge;
private int lastResult;
private double lastLimit;
public int compareTo(Edge other, double yrange[]) {
if (other == lastEdge && yrange[0] < lastLimit) {
if (yrange[1] > lastLimit) {
yrange[1] = lastLimit;
}
return lastResult;
}
if (this == other.lastEdge && yrange[0] < other.lastLimit) {
if (yrange[1] > other.lastLimit) {
yrange[1] = other.lastLimit;
}
return 0-other.lastResult;
}
//long start = System.currentTimeMillis();
int ret = curve.compareTo(other.curve, yrange);
//long end = System.currentTimeMillis();
/*
System.out.println("compare: "+
((System.identityHashCode(this) <
System.identityHashCode(other))
? this+" to "+other
: other+" to "+this)+
" == "+ret+" at "+yrange[1]+
" in "+(end-start)+"ms");
*/
lastEdge = other;
lastLimit = yrange[1];
lastResult = ret;
return ret;
}
public void record(double yend, int etag) {
this.activey = yend;
this.etag = etag;
}
public boolean isActiveFor(double y, int etag) {
return (this.etag == etag && this.activey >= y);
}
public String toString() {
return ("Edge["+curve+
", "+
(ctag == AreaOp.CTAG_LEFT ? "L" : "R")+
", "+
(etag == AreaOp.ETAG_ENTER ? "I" :
(etag == AreaOp.ETAG_EXIT ? "O" : "N"))+
"]");
}
}

View File

@@ -0,0 +1,142 @@
/*
* Copyright (c) 1998, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.awt.geom;
import java.awt.geom.Rectangle2D;
import java.awt.geom.PathIterator;
import java.util.Vector;
final class Order0 extends Curve {
private double x;
private double y;
public Order0(double x, double y) {
super(INCREASING);
this.x = x;
this.y = y;
}
public int getOrder() {
return 0;
}
public double getXTop() {
return x;
}
public double getYTop() {
return y;
}
public double getXBot() {
return x;
}
public double getYBot() {
return y;
}
public double getXMin() {
return x;
}
public double getXMax() {
return x;
}
public double getX0() {
return x;
}
public double getY0() {
return y;
}
public double getX1() {
return x;
}
public double getY1() {
return y;
}
public double XforY(double y) {
return y;
}
public double TforY(double y) {
return 0;
}
public double XforT(double t) {
return x;
}
public double YforT(double t) {
return y;
}
public double dXforT(double t, int deriv) {
return 0;
}
public double dYforT(double t, int deriv) {
return 0;
}
public double nextVertical(double t0, double t1) {
return t1;
}
public int crossingsFor(double x, double y) {
return 0;
}
public boolean accumulateCrossings(Crossings c) {
return (x > c.getXLo() &&
x < c.getXHi() &&
y > c.getYLo() &&
y < c.getYHi());
}
public void enlarge(Rectangle2D r) {
r.add(x, y);
}
public Curve getSubCurve(double ystart, double yend, int dir) {
return this;
}
public Curve getReversedCurve() {
return this;
}
public int getSegment(double coords[]) {
coords[0] = x;
coords[1] = y;
return PathIterator.SEG_MOVETO;
}
}

View File

@@ -0,0 +1,312 @@
/*
* Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.awt.geom;
import java.awt.geom.Rectangle2D;
import java.awt.geom.PathIterator;
import java.util.Vector;
final class Order1 extends Curve {
private double x0;
private double y0;
private double x1;
private double y1;
private double xmin;
private double xmax;
public Order1(double x0, double y0,
double x1, double y1,
int direction)
{
super(direction);
this.x0 = x0;
this.y0 = y0;
this.x1 = x1;
this.y1 = y1;
if (x0 < x1) {
this.xmin = x0;
this.xmax = x1;
} else {
this.xmin = x1;
this.xmax = x0;
}
}
public int getOrder() {
return 1;
}
public double getXTop() {
return x0;
}
public double getYTop() {
return y0;
}
public double getXBot() {
return x1;
}
public double getYBot() {
return y1;
}
public double getXMin() {
return xmin;
}
public double getXMax() {
return xmax;
}
public double getX0() {
return (direction == INCREASING) ? x0 : x1;
}
public double getY0() {
return (direction == INCREASING) ? y0 : y1;
}
public double getX1() {
return (direction == DECREASING) ? x0 : x1;
}
public double getY1() {
return (direction == DECREASING) ? y0 : y1;
}
public double XforY(double y) {
if (x0 == x1 || y <= y0) {
return x0;
}
if (y >= y1) {
return x1;
}
// assert(y0 != y1); /* No horizontal lines... */
return (x0 + (y - y0) * (x1 - x0) / (y1 - y0));
}
public double TforY(double y) {
if (y <= y0) {
return 0;
}
if (y >= y1) {
return 1;
}
return (y - y0) / (y1 - y0);
}
public double XforT(double t) {
return x0 + t * (x1 - x0);
}
public double YforT(double t) {
return y0 + t * (y1 - y0);
}
public double dXforT(double t, int deriv) {
switch (deriv) {
case 0:
return x0 + t * (x1 - x0);
case 1:
return (x1 - x0);
default:
return 0;
}
}
public double dYforT(double t, int deriv) {
switch (deriv) {
case 0:
return y0 + t * (y1 - y0);
case 1:
return (y1 - y0);
default:
return 0;
}
}
public double nextVertical(double t0, double t1) {
return t1;
}
public boolean accumulateCrossings(Crossings c) {
double xlo = c.getXLo();
double ylo = c.getYLo();
double xhi = c.getXHi();
double yhi = c.getYHi();
if (xmin >= xhi) {
return false;
}
double xstart, ystart, xend, yend;
if (y0 < ylo) {
if (y1 <= ylo) {
return false;
}
ystart = ylo;
xstart = XforY(ylo);
} else {
if (y0 >= yhi) {
return false;
}
ystart = y0;
xstart = x0;
}
if (y1 > yhi) {
yend = yhi;
xend = XforY(yhi);
} else {
yend = y1;
xend = x1;
}
if (xstart >= xhi && xend >= xhi) {
return false;
}
if (xstart > xlo || xend > xlo) {
return true;
}
c.record(ystart, yend, direction);
return false;
}
public void enlarge(Rectangle2D r) {
r.add(x0, y0);
r.add(x1, y1);
}
public Curve getSubCurve(double ystart, double yend, int dir) {
if (ystart == y0 && yend == y1) {
return getWithDirection(dir);
}
if (x0 == x1) {
return new Order1(x0, ystart, x1, yend, dir);
}
double num = x0 - x1;
double denom = y0 - y1;
double xstart = (x0 + (ystart - y0) * num / denom);
double xend = (x0 + (yend - y0) * num / denom);
return new Order1(xstart, ystart, xend, yend, dir);
}
public Curve getReversedCurve() {
return new Order1(x0, y0, x1, y1, -direction);
}
public int compareTo(Curve other, double yrange[]) {
if (!(other instanceof Order1)) {
return super.compareTo(other, yrange);
}
Order1 c1 = (Order1) other;
if (yrange[1] <= yrange[0]) {
throw new InternalError("yrange already screwed up...");
}
yrange[1] = Math.min(Math.min(yrange[1], y1), c1.y1);
if (yrange[1] <= yrange[0]) {
throw new InternalError("backstepping from "+yrange[0]+" to "+yrange[1]);
}
if (xmax <= c1.xmin) {
return (xmin == c1.xmax) ? 0 : -1;
}
if (xmin >= c1.xmax) {
return 1;
}
/*
* If "this" is curve A and "other" is curve B, then...
* xA(y) = x0A + (y - y0A) (x1A - x0A) / (y1A - y0A)
* xB(y) = x0B + (y - y0B) (x1B - x0B) / (y1B - y0B)
* xA(y) == xB(y)
* x0A + (y - y0A) (x1A - x0A) / (y1A - y0A)
* == x0B + (y - y0B) (x1B - x0B) / (y1B - y0B)
* 0 == x0A (y1A - y0A) (y1B - y0B) + (y - y0A) (x1A - x0A) (y1B - y0B)
* - x0B (y1A - y0A) (y1B - y0B) - (y - y0B) (x1B - x0B) (y1A - y0A)
* 0 == (x0A - x0B) (y1A - y0A) (y1B - y0B)
* + (y - y0A) (x1A - x0A) (y1B - y0B)
* - (y - y0B) (x1B - x0B) (y1A - y0A)
* If (dxA == x1A - x0A), etc...
* 0 == (x0A - x0B) * dyA * dyB
* + (y - y0A) * dxA * dyB
* - (y - y0B) * dxB * dyA
* 0 == (x0A - x0B) * dyA * dyB
* + y * dxA * dyB - y0A * dxA * dyB
* - y * dxB * dyA + y0B * dxB * dyA
* 0 == (x0A - x0B) * dyA * dyB
* + y * dxA * dyB - y * dxB * dyA
* - y0A * dxA * dyB + y0B * dxB * dyA
* 0 == (x0A - x0B) * dyA * dyB
* + y * (dxA * dyB - dxB * dyA)
* - y0A * dxA * dyB + y0B * dxB * dyA
* y == ((x0A - x0B) * dyA * dyB
* - y0A * dxA * dyB + y0B * dxB * dyA)
* / (-(dxA * dyB - dxB * dyA))
* y == ((x0A - x0B) * dyA * dyB
* - y0A * dxA * dyB + y0B * dxB * dyA)
* / (dxB * dyA - dxA * dyB)
*/
double dxa = x1 - x0;
double dya = y1 - y0;
double dxb = c1.x1 - c1.x0;
double dyb = c1.y1 - c1.y0;
double denom = dxb * dya - dxa * dyb;
double y;
if (denom != 0) {
double num = ((x0 - c1.x0) * dya * dyb
- y0 * dxa * dyb
+ c1.y0 * dxb * dya);
y = num / denom;
if (y <= yrange[0]) {
// intersection is above us
// Use bottom-most common y for comparison
y = Math.min(y1, c1.y1);
} else {
// intersection is below the top of our range
if (y < yrange[1]) {
// If intersection is in our range, adjust valid range
yrange[1] = y;
}
// Use top-most common y for comparison
y = Math.max(y0, c1.y0);
}
} else {
// lines are parallel, choose any common y for comparison
// Note - prefer an endpoint for speed of calculating the X
// (see shortcuts in Order1.XforY())
y = Math.max(y0, c1.y0);
}
return orderof(XforY(y), c1.XforY(y));
}
public int getSegment(double coords[]) {
if (direction == INCREASING) {
coords[0] = x1;
coords[1] = y1;
} else {
coords[0] = x0;
coords[1] = y0;
}
return PathIterator.SEG_LINETO;
}
}

View File

@@ -0,0 +1,453 @@
/*
* Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.awt.geom;
import java.awt.geom.Rectangle2D;
import java.awt.geom.PathIterator;
import java.awt.geom.QuadCurve2D;
import java.util.Vector;
final class Order2 extends Curve {
private double x0;
private double y0;
private double cx0;
private double cy0;
private double x1;
private double y1;
private double xmin;
private double xmax;
private double xcoeff0;
private double xcoeff1;
private double xcoeff2;
private double ycoeff0;
private double ycoeff1;
private double ycoeff2;
public static void insert(Vector curves, double tmp[],
double x0, double y0,
double cx0, double cy0,
double x1, double y1,
int direction)
{
int numparams = getHorizontalParams(y0, cy0, y1, tmp);
if (numparams == 0) {
// We are using addInstance here to avoid inserting horisontal
// segments
addInstance(curves, x0, y0, cx0, cy0, x1, y1, direction);
return;
}
// assert(numparams == 1);
double t = tmp[0];
tmp[0] = x0; tmp[1] = y0;
tmp[2] = cx0; tmp[3] = cy0;
tmp[4] = x1; tmp[5] = y1;
split(tmp, 0, t);
int i0 = (direction == INCREASING)? 0 : 4;
int i1 = 4 - i0;
addInstance(curves, tmp[i0], tmp[i0 + 1], tmp[i0 + 2], tmp[i0 + 3],
tmp[i0 + 4], tmp[i0 + 5], direction);
addInstance(curves, tmp[i1], tmp[i1 + 1], tmp[i1 + 2], tmp[i1 + 3],
tmp[i1 + 4], tmp[i1 + 5], direction);
}
public static void addInstance(Vector curves,
double x0, double y0,
double cx0, double cy0,
double x1, double y1,
int direction) {
if (y0 > y1) {
curves.add(new Order2(x1, y1, cx0, cy0, x0, y0, -direction));
} else if (y1 > y0) {
curves.add(new Order2(x0, y0, cx0, cy0, x1, y1, direction));
}
}
/*
* Return the count of the number of horizontal sections of the
* specified quadratic Bezier curve. Put the parameters for the
* horizontal sections into the specified <code>ret</code> array.
* <p>
* If we examine the parametric equation in t, we have:
* Py(t) = C0*(1-t)^2 + 2*CP*t*(1-t) + C1*t^2
* = C0 - 2*C0*t + C0*t^2 + 2*CP*t - 2*CP*t^2 + C1*t^2
* = C0 + (2*CP - 2*C0)*t + (C0 - 2*CP + C1)*t^2
* Py(t) = (C0 - 2*CP + C1)*t^2 + (2*CP - 2*C0)*t + (C0)
* If we take the derivative, we get:
* Py(t) = At^2 + Bt + C
* dPy(t) = 2At + B = 0
* 2*(C0 - 2*CP + C1)t + 2*(CP - C0) = 0
* 2*(C0 - 2*CP + C1)t = 2*(C0 - CP)
* t = 2*(C0 - CP) / 2*(C0 - 2*CP + C1)
* t = (C0 - CP) / (C0 - CP + C1 - CP)
* Note that this method will return 0 if the equation is a line,
* which is either always horizontal or never horizontal.
* Completely horizontal curves need to be eliminated by other
* means outside of this method.
*/
public static int getHorizontalParams(double c0, double cp, double c1,
double ret[]) {
if (c0 <= cp && cp <= c1) {
return 0;
}
c0 -= cp;
c1 -= cp;
double denom = c0 + c1;
// If denom == 0 then cp == (c0+c1)/2 and we have a line.
if (denom == 0) {
return 0;
}
double t = c0 / denom;
// No splits at t==0 and t==1
if (t <= 0 || t >= 1) {
return 0;
}
ret[0] = t;
return 1;
}
/*
* Split the quadratic Bezier stored at coords[pos...pos+5] representing
* the paramtric range [0..1] into two subcurves representing the
* parametric subranges [0..t] and [t..1]. Store the results back
* into the array at coords[pos...pos+5] and coords[pos+4...pos+9].
*/
public static void split(double coords[], int pos, double t) {
double x0, y0, cx, cy, x1, y1;
coords[pos+8] = x1 = coords[pos+4];
coords[pos+9] = y1 = coords[pos+5];
cx = coords[pos+2];
cy = coords[pos+3];
x1 = cx + (x1 - cx) * t;
y1 = cy + (y1 - cy) * t;
x0 = coords[pos+0];
y0 = coords[pos+1];
x0 = x0 + (cx - x0) * t;
y0 = y0 + (cy - y0) * t;
cx = x0 + (x1 - x0) * t;
cy = y0 + (y1 - y0) * t;
coords[pos+2] = x0;
coords[pos+3] = y0;
coords[pos+4] = cx;
coords[pos+5] = cy;
coords[pos+6] = x1;
coords[pos+7] = y1;
}
public Order2(double x0, double y0,
double cx0, double cy0,
double x1, double y1,
int direction)
{
super(direction);
// REMIND: Better accuracy in the root finding methods would
// ensure that cy0 is in range. As it stands, it is never
// more than "1 mantissa bit" out of range...
if (cy0 < y0) {
cy0 = y0;
} else if (cy0 > y1) {
cy0 = y1;
}
this.x0 = x0;
this.y0 = y0;
this.cx0 = cx0;
this.cy0 = cy0;
this.x1 = x1;
this.y1 = y1;
xmin = Math.min(Math.min(x0, x1), cx0);
xmax = Math.max(Math.max(x0, x1), cx0);
xcoeff0 = x0;
xcoeff1 = cx0 + cx0 - x0 - x0;
xcoeff2 = x0 - cx0 - cx0 + x1;
ycoeff0 = y0;
ycoeff1 = cy0 + cy0 - y0 - y0;
ycoeff2 = y0 - cy0 - cy0 + y1;
}
public int getOrder() {
return 2;
}
public double getXTop() {
return x0;
}
public double getYTop() {
return y0;
}
public double getXBot() {
return x1;
}
public double getYBot() {
return y1;
}
public double getXMin() {
return xmin;
}
public double getXMax() {
return xmax;
}
public double getX0() {
return (direction == INCREASING) ? x0 : x1;
}
public double getY0() {
return (direction == INCREASING) ? y0 : y1;
}
public double getCX0() {
return cx0;
}
public double getCY0() {
return cy0;
}
public double getX1() {
return (direction == DECREASING) ? x0 : x1;
}
public double getY1() {
return (direction == DECREASING) ? y0 : y1;
}
public double XforY(double y) {
if (y <= y0) {
return x0;
}
if (y >= y1) {
return x1;
}
return XforT(TforY(y));
}
public double TforY(double y) {
if (y <= y0) {
return 0;
}
if (y >= y1) {
return 1;
}
return TforY(y, ycoeff0, ycoeff1, ycoeff2);
}
public static double TforY(double y,
double ycoeff0, double ycoeff1, double ycoeff2)
{
// The caller should have already eliminated y values
// outside of the y0 to y1 range.
ycoeff0 -= y;
if (ycoeff2 == 0.0) {
// The quadratic parabola has degenerated to a line.
// ycoeff1 should not be 0.0 since we have already eliminated
// totally horizontal lines, but if it is, then we will generate
// infinity here for the root, which will not be in the [0,1]
// range so we will pass to the failure code below.
double root = -ycoeff0 / ycoeff1;
if (root >= 0 && root <= 1) {
return root;
}
} else {
// From Numerical Recipes, 5.6, Quadratic and Cubic Equations
double d = ycoeff1 * ycoeff1 - 4.0 * ycoeff2 * ycoeff0;
// If d < 0.0, then there are no roots
if (d >= 0.0) {
d = Math.sqrt(d);
// For accuracy, calculate one root using:
// (-ycoeff1 +/- d) / 2ycoeff2
// and the other using:
// 2ycoeff0 / (-ycoeff1 +/- d)
// Choose the sign of the +/- so that ycoeff1+d
// gets larger in magnitude
if (ycoeff1 < 0.0) {
d = -d;
}
double q = (ycoeff1 + d) / -2.0;
// We already tested ycoeff2 for being 0 above
double root = q / ycoeff2;
if (root >= 0 && root <= 1) {
return root;
}
if (q != 0.0) {
root = ycoeff0 / q;
if (root >= 0 && root <= 1) {
return root;
}
}
}
}
/* We failed to find a root in [0,1]. What could have gone wrong?
* First, remember that these curves are constructed to be monotonic
* in Y and totally horizontal curves have already been eliminated.
* Now keep in mind that the Y coefficients of the polynomial form
* of the curve are calculated from the Y coordinates which define
* our curve. They should theoretically define the same curve,
* but they can be off by a couple of bits of precision after the
* math is done and so can represent a slightly modified curve.
* This is normally not an issue except when we have solutions near
* the endpoints. Since the answers we get from solving the polynomial
* may be off by a few bits that means that they could lie just a
* few bits of precision outside the [0,1] range.
*
* Another problem could be that while the parametric curve defined
* by the Y coordinates has a local minima or maxima at or just
* outside of the endpoints, the polynomial form might express
* that same min/max just inside of and just shy of the Y coordinate
* of that endpoint. In that case, if we solve for a Y coordinate
* at or near that endpoint, we may be solving for a Y coordinate
* that is below that minima or above that maxima and we would find
* no solutions at all.
*
* In either case, we can assume that y is so near one of the
* endpoints that we can just collapse it onto the nearest endpoint
* without losing more than a couple of bits of precision.
*/
// First calculate the midpoint between y0 and y1 and choose to
// return either 0.0 or 1.0 depending on whether y is above
// or below the midpoint...
// Note that we subtracted y from ycoeff0 above so both y0 and y1
// will be "relative to y" so we are really just looking at where
// zero falls with respect to the "relative midpoint" here.
double y0 = ycoeff0;
double y1 = ycoeff0 + ycoeff1 + ycoeff2;
return (0 < (y0 + y1) / 2) ? 0.0 : 1.0;
}
public double XforT(double t) {
return (xcoeff2 * t + xcoeff1) * t + xcoeff0;
}
public double YforT(double t) {
return (ycoeff2 * t + ycoeff1) * t + ycoeff0;
}
public double dXforT(double t, int deriv) {
switch (deriv) {
case 0:
return (xcoeff2 * t + xcoeff1) * t + xcoeff0;
case 1:
return 2 * xcoeff2 * t + xcoeff1;
case 2:
return 2 * xcoeff2;
default:
return 0;
}
}
public double dYforT(double t, int deriv) {
switch (deriv) {
case 0:
return (ycoeff2 * t + ycoeff1) * t + ycoeff0;
case 1:
return 2 * ycoeff2 * t + ycoeff1;
case 2:
return 2 * ycoeff2;
default:
return 0;
}
}
public double nextVertical(double t0, double t1) {
double t = -xcoeff1 / (2 * xcoeff2);
if (t > t0 && t < t1) {
return t;
}
return t1;
}
public void enlarge(Rectangle2D r) {
r.add(x0, y0);
double t = -xcoeff1 / (2 * xcoeff2);
if (t > 0 && t < 1) {
r.add(XforT(t), YforT(t));
}
r.add(x1, y1);
}
public Curve getSubCurve(double ystart, double yend, int dir) {
double t0, t1;
if (ystart <= y0) {
if (yend >= y1) {
return getWithDirection(dir);
}
t0 = 0;
} else {
t0 = TforY(ystart, ycoeff0, ycoeff1, ycoeff2);
}
if (yend >= y1) {
t1 = 1;
} else {
t1 = TforY(yend, ycoeff0, ycoeff1, ycoeff2);
}
double eqn[] = new double[10];
eqn[0] = x0;
eqn[1] = y0;
eqn[2] = cx0;
eqn[3] = cy0;
eqn[4] = x1;
eqn[5] = y1;
if (t1 < 1) {
split(eqn, 0, t1);
}
int i;
if (t0 <= 0) {
i = 0;
} else {
split(eqn, 0, t0 / t1);
i = 4;
}
return new Order2(eqn[i+0], ystart,
eqn[i+2], eqn[i+3],
eqn[i+4], yend,
dir);
}
public Curve getReversedCurve() {
return new Order2(x0, y0, cx0, cy0, x1, y1, -direction);
}
public int getSegment(double coords[]) {
coords[0] = cx0;
coords[1] = cy0;
if (direction == INCREASING) {
coords[2] = x1;
coords[3] = y1;
} else {
coords[2] = x0;
coords[3] = y0;
}
return PathIterator.SEG_QUADTO;
}
public String controlPointString() {
return ("("+round(cx0)+", "+round(cy0)+"), ");
}
}

View File

@@ -0,0 +1,634 @@
/*
* Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.awt.geom;
import java.awt.geom.Rectangle2D;
import java.awt.geom.PathIterator;
import java.awt.geom.QuadCurve2D;
import java.util.Vector;
final class Order3 extends Curve {
private double x0;
private double y0;
private double cx0;
private double cy0;
private double cx1;
private double cy1;
private double x1;
private double y1;
private double xmin;
private double xmax;
private double xcoeff0;
private double xcoeff1;
private double xcoeff2;
private double xcoeff3;
private double ycoeff0;
private double ycoeff1;
private double ycoeff2;
private double ycoeff3;
public static void insert(Vector curves, double tmp[],
double x0, double y0,
double cx0, double cy0,
double cx1, double cy1,
double x1, double y1,
int direction)
{
int numparams = getHorizontalParams(y0, cy0, cy1, y1, tmp);
if (numparams == 0) {
// We are using addInstance here to avoid inserting horisontal
// segments
addInstance(curves, x0, y0, cx0, cy0, cx1, cy1, x1, y1, direction);
return;
}
// Store coordinates for splitting at tmp[3..10]
tmp[3] = x0; tmp[4] = y0;
tmp[5] = cx0; tmp[6] = cy0;
tmp[7] = cx1; tmp[8] = cy1;
tmp[9] = x1; tmp[10] = y1;
double t = tmp[0];
if (numparams > 1 && t > tmp[1]) {
// Perform a "2 element sort"...
tmp[0] = tmp[1];
tmp[1] = t;
t = tmp[0];
}
split(tmp, 3, t);
if (numparams > 1) {
// Recalculate tmp[1] relative to the range [tmp[0]...1]
t = (tmp[1] - t) / (1 - t);
split(tmp, 9, t);
}
int index = 3;
if (direction == DECREASING) {
index += numparams * 6;
}
while (numparams >= 0) {
addInstance(curves,
tmp[index + 0], tmp[index + 1],
tmp[index + 2], tmp[index + 3],
tmp[index + 4], tmp[index + 5],
tmp[index + 6], tmp[index + 7],
direction);
numparams--;
if (direction == INCREASING) {
index += 6;
} else {
index -= 6;
}
}
}
public static void addInstance(Vector curves,
double x0, double y0,
double cx0, double cy0,
double cx1, double cy1,
double x1, double y1,
int direction) {
if (y0 > y1) {
curves.add(new Order3(x1, y1, cx1, cy1, cx0, cy0, x0, y0,
-direction));
} else if (y1 > y0) {
curves.add(new Order3(x0, y0, cx0, cy0, cx1, cy1, x1, y1,
direction));
}
}
/*
* Return the count of the number of horizontal sections of the
* specified cubic Bezier curve. Put the parameters for the
* horizontal sections into the specified <code>ret</code> array.
* <p>
* If we examine the parametric equation in t, we have:
* Py(t) = C0(1-t)^3 + 3CP0 t(1-t)^2 + 3CP1 t^2(1-t) + C1 t^3
* = C0 - 3C0t + 3C0t^2 - C0t^3 +
* 3CP0t - 6CP0t^2 + 3CP0t^3 +
* 3CP1t^2 - 3CP1t^3 +
* C1t^3
* Py(t) = (C1 - 3CP1 + 3CP0 - C0) t^3 +
* (3C0 - 6CP0 + 3CP1) t^2 +
* (3CP0 - 3C0) t +
* (C0)
* If we take the derivative, we get:
* Py(t) = Dt^3 + At^2 + Bt + C
* dPy(t) = 3Dt^2 + 2At + B = 0
* 0 = 3*(C1 - 3*CP1 + 3*CP0 - C0)t^2
* + 2*(3*CP1 - 6*CP0 + 3*C0)t
* + (3*CP0 - 3*C0)
* 0 = 3*(C1 - 3*CP1 + 3*CP0 - C0)t^2
* + 3*2*(CP1 - 2*CP0 + C0)t
* + 3*(CP0 - C0)
* 0 = (C1 - CP1 - CP1 - CP1 + CP0 + CP0 + CP0 - C0)t^2
* + 2*(CP1 - CP0 - CP0 + C0)t
* + (CP0 - C0)
* 0 = (C1 - CP1 + CP0 - CP1 + CP0 - CP1 + CP0 - C0)t^2
* + 2*(CP1 - CP0 - CP0 + C0)t
* + (CP0 - C0)
* 0 = ((C1 - CP1) - (CP1 - CP0) - (CP1 - CP0) + (CP0 - C0))t^2
* + 2*((CP1 - CP0) - (CP0 - C0))t
* + (CP0 - C0)
* Note that this method will return 0 if the equation is a line,
* which is either always horizontal or never horizontal.
* Completely horizontal curves need to be eliminated by other
* means outside of this method.
*/
public static int getHorizontalParams(double c0, double cp0,
double cp1, double c1,
double ret[]) {
if (c0 <= cp0 && cp0 <= cp1 && cp1 <= c1) {
return 0;
}
c1 -= cp1;
cp1 -= cp0;
cp0 -= c0;
ret[0] = cp0;
ret[1] = (cp1 - cp0) * 2;
ret[2] = (c1 - cp1 - cp1 + cp0);
int numroots = QuadCurve2D.solveQuadratic(ret, ret);
int j = 0;
for (int i = 0; i < numroots; i++) {
double t = ret[i];
// No splits at t==0 and t==1
if (t > 0 && t < 1) {
if (j < i) {
ret[j] = t;
}
j++;
}
}
return j;
}
/*
* Split the cubic Bezier stored at coords[pos...pos+7] representing
* the parametric range [0..1] into two subcurves representing the
* parametric subranges [0..t] and [t..1]. Store the results back
* into the array at coords[pos...pos+7] and coords[pos+6...pos+13].
*/
public static void split(double coords[], int pos, double t) {
double x0, y0, cx0, cy0, cx1, cy1, x1, y1;
coords[pos+12] = x1 = coords[pos+6];
coords[pos+13] = y1 = coords[pos+7];
cx1 = coords[pos+4];
cy1 = coords[pos+5];
x1 = cx1 + (x1 - cx1) * t;
y1 = cy1 + (y1 - cy1) * t;
x0 = coords[pos+0];
y0 = coords[pos+1];
cx0 = coords[pos+2];
cy0 = coords[pos+3];
x0 = x0 + (cx0 - x0) * t;
y0 = y0 + (cy0 - y0) * t;
cx0 = cx0 + (cx1 - cx0) * t;
cy0 = cy0 + (cy1 - cy0) * t;
cx1 = cx0 + (x1 - cx0) * t;
cy1 = cy0 + (y1 - cy0) * t;
cx0 = x0 + (cx0 - x0) * t;
cy0 = y0 + (cy0 - y0) * t;
coords[pos+2] = x0;
coords[pos+3] = y0;
coords[pos+4] = cx0;
coords[pos+5] = cy0;
coords[pos+6] = cx0 + (cx1 - cx0) * t;
coords[pos+7] = cy0 + (cy1 - cy0) * t;
coords[pos+8] = cx1;
coords[pos+9] = cy1;
coords[pos+10] = x1;
coords[pos+11] = y1;
}
public Order3(double x0, double y0,
double cx0, double cy0,
double cx1, double cy1,
double x1, double y1,
int direction)
{
super(direction);
// REMIND: Better accuracy in the root finding methods would
// ensure that cys are in range. As it stands, they are never
// more than "1 mantissa bit" out of range...
if (cy0 < y0) cy0 = y0;
if (cy1 > y1) cy1 = y1;
this.x0 = x0;
this.y0 = y0;
this.cx0 = cx0;
this.cy0 = cy0;
this.cx1 = cx1;
this.cy1 = cy1;
this.x1 = x1;
this.y1 = y1;
xmin = Math.min(Math.min(x0, x1), Math.min(cx0, cx1));
xmax = Math.max(Math.max(x0, x1), Math.max(cx0, cx1));
xcoeff0 = x0;
xcoeff1 = (cx0 - x0) * 3.0;
xcoeff2 = (cx1 - cx0 - cx0 + x0) * 3.0;
xcoeff3 = x1 - (cx1 - cx0) * 3.0 - x0;
ycoeff0 = y0;
ycoeff1 = (cy0 - y0) * 3.0;
ycoeff2 = (cy1 - cy0 - cy0 + y0) * 3.0;
ycoeff3 = y1 - (cy1 - cy0) * 3.0 - y0;
YforT1 = YforT2 = YforT3 = y0;
}
public int getOrder() {
return 3;
}
public double getXTop() {
return x0;
}
public double getYTop() {
return y0;
}
public double getXBot() {
return x1;
}
public double getYBot() {
return y1;
}
public double getXMin() {
return xmin;
}
public double getXMax() {
return xmax;
}
public double getX0() {
return (direction == INCREASING) ? x0 : x1;
}
public double getY0() {
return (direction == INCREASING) ? y0 : y1;
}
public double getCX0() {
return (direction == INCREASING) ? cx0 : cx1;
}
public double getCY0() {
return (direction == INCREASING) ? cy0 : cy1;
}
public double getCX1() {
return (direction == DECREASING) ? cx0 : cx1;
}
public double getCY1() {
return (direction == DECREASING) ? cy0 : cy1;
}
public double getX1() {
return (direction == DECREASING) ? x0 : x1;
}
public double getY1() {
return (direction == DECREASING) ? y0 : y1;
}
private double TforY1;
private double YforT1;
private double TforY2;
private double YforT2;
private double TforY3;
private double YforT3;
/*
* Solve the cubic whose coefficients are in the a,b,c,d fields and
* return the first root in the range [0, 1].
* The cubic solved is represented by the equation:
* x^3 + (ycoeff2)x^2 + (ycoeff1)x + (ycoeff0) = y
* @return the first valid root (in the range [0, 1])
*/
public double TforY(double y) {
if (y <= y0) return 0;
if (y >= y1) return 1;
if (y == YforT1) return TforY1;
if (y == YforT2) return TforY2;
if (y == YforT3) return TforY3;
// From Numerical Recipes, 5.6, Quadratic and Cubic Equations
if (ycoeff3 == 0.0) {
// The cubic degenerated to quadratic (or line or ...).
return Order2.TforY(y, ycoeff0, ycoeff1, ycoeff2);
}
double a = ycoeff2 / ycoeff3;
double b = ycoeff1 / ycoeff3;
double c = (ycoeff0 - y) / ycoeff3;
int roots = 0;
double Q = (a * a - 3.0 * b) / 9.0;
double R = (2.0 * a * a * a - 9.0 * a * b + 27.0 * c) / 54.0;
double R2 = R * R;
double Q3 = Q * Q * Q;
double a_3 = a / 3.0;
double t;
if (R2 < Q3) {
double theta = Math.acos(R / Math.sqrt(Q3));
Q = -2.0 * Math.sqrt(Q);
t = refine(a, b, c, y, Q * Math.cos(theta / 3.0) - a_3);
if (t < 0) {
t = refine(a, b, c, y,
Q * Math.cos((theta + Math.PI * 2.0)/ 3.0) - a_3);
}
if (t < 0) {
t = refine(a, b, c, y,
Q * Math.cos((theta - Math.PI * 2.0)/ 3.0) - a_3);
}
} else {
boolean neg = (R < 0.0);
double S = Math.sqrt(R2 - Q3);
if (neg) {
R = -R;
}
double A = Math.pow(R + S, 1.0 / 3.0);
if (!neg) {
A = -A;
}
double B = (A == 0.0) ? 0.0 : (Q / A);
t = refine(a, b, c, y, (A + B) - a_3);
}
if (t < 0) {
//throw new InternalError("bad t");
double t0 = 0;
double t1 = 1;
while (true) {
t = (t0 + t1) / 2;
if (t == t0 || t == t1) {
break;
}
double yt = YforT(t);
if (yt < y) {
t0 = t;
} else if (yt > y) {
t1 = t;
} else {
break;
}
}
}
if (t >= 0) {
TforY3 = TforY2;
YforT3 = YforT2;
TforY2 = TforY1;
YforT2 = YforT1;
TforY1 = t;
YforT1 = y;
}
return t;
}
public double refine(double a, double b, double c,
double target, double t)
{
if (t < -0.1 || t > 1.1) {
return -1;
}
double y = YforT(t);
double t0, t1;
if (y < target) {
t0 = t;
t1 = 1;
} else {
t0 = 0;
t1 = t;
}
double origt = t;
double origy = y;
boolean useslope = true;
while (y != target) {
if (!useslope) {
double t2 = (t0 + t1) / 2;
if (t2 == t0 || t2 == t1) {
break;
}
t = t2;
} else {
double slope = dYforT(t, 1);
if (slope == 0) {
useslope = false;
continue;
}
double t2 = t + ((target - y) / slope);
if (t2 == t || t2 <= t0 || t2 >= t1) {
useslope = false;
continue;
}
t = t2;
}
y = YforT(t);
if (y < target) {
t0 = t;
} else if (y > target) {
t1 = t;
} else {
break;
}
}
boolean verbose = false;
if (false && t >= 0 && t <= 1) {
y = YforT(t);
long tdiff = diffbits(t, origt);
long ydiff = diffbits(y, origy);
long yerr = diffbits(y, target);
if (yerr > 0 || (verbose && tdiff > 0)) {
System.out.println("target was y = "+target);
System.out.println("original was y = "+origy+", t = "+origt);
System.out.println("final was y = "+y+", t = "+t);
System.out.println("t diff is "+tdiff);
System.out.println("y diff is "+ydiff);
System.out.println("y error is "+yerr);
double tlow = prev(t);
double ylow = YforT(tlow);
double thi = next(t);
double yhi = YforT(thi);
if (Math.abs(target - ylow) < Math.abs(target - y) ||
Math.abs(target - yhi) < Math.abs(target - y))
{
System.out.println("adjacent y's = ["+ylow+", "+yhi+"]");
}
}
}
return (t > 1) ? -1 : t;
}
public double XforY(double y) {
if (y <= y0) {
return x0;
}
if (y >= y1) {
return x1;
}
return XforT(TforY(y));
}
public double XforT(double t) {
return (((xcoeff3 * t) + xcoeff2) * t + xcoeff1) * t + xcoeff0;
}
public double YforT(double t) {
return (((ycoeff3 * t) + ycoeff2) * t + ycoeff1) * t + ycoeff0;
}
public double dXforT(double t, int deriv) {
switch (deriv) {
case 0:
return (((xcoeff3 * t) + xcoeff2) * t + xcoeff1) * t + xcoeff0;
case 1:
return ((3 * xcoeff3 * t) + 2 * xcoeff2) * t + xcoeff1;
case 2:
return (6 * xcoeff3 * t) + 2 * xcoeff2;
case 3:
return 6 * xcoeff3;
default:
return 0;
}
}
public double dYforT(double t, int deriv) {
switch (deriv) {
case 0:
return (((ycoeff3 * t) + ycoeff2) * t + ycoeff1) * t + ycoeff0;
case 1:
return ((3 * ycoeff3 * t) + 2 * ycoeff2) * t + ycoeff1;
case 2:
return (6 * ycoeff3 * t) + 2 * ycoeff2;
case 3:
return 6 * ycoeff3;
default:
return 0;
}
}
public double nextVertical(double t0, double t1) {
double eqn[] = {xcoeff1, 2 * xcoeff2, 3 * xcoeff3};
int numroots = QuadCurve2D.solveQuadratic(eqn, eqn);
for (int i = 0; i < numroots; i++) {
if (eqn[i] > t0 && eqn[i] < t1) {
t1 = eqn[i];
}
}
return t1;
}
public void enlarge(Rectangle2D r) {
r.add(x0, y0);
double eqn[] = {xcoeff1, 2 * xcoeff2, 3 * xcoeff3};
int numroots = QuadCurve2D.solveQuadratic(eqn, eqn);
for (int i = 0; i < numroots; i++) {
double t = eqn[i];
if (t > 0 && t < 1) {
r.add(XforT(t), YforT(t));
}
}
r.add(x1, y1);
}
public Curve getSubCurve(double ystart, double yend, int dir) {
if (ystart <= y0 && yend >= y1) {
return getWithDirection(dir);
}
double eqn[] = new double[14];
double t0, t1;
t0 = TforY(ystart);
t1 = TforY(yend);
eqn[0] = x0;
eqn[1] = y0;
eqn[2] = cx0;
eqn[3] = cy0;
eqn[4] = cx1;
eqn[5] = cy1;
eqn[6] = x1;
eqn[7] = y1;
if (t0 > t1) {
/* This happens in only rare cases where ystart is
* very near yend and solving for the yend root ends
* up stepping slightly lower in t than solving for
* the ystart root.
* Ideally we might want to skip this tiny little
* segment and just fudge the surrounding coordinates
* to bridge the gap left behind, but there is no way
* to do that from here. Higher levels could
* potentially eliminate these tiny "fixup" segments,
* but not without a lot of extra work on the code that
* coalesces chains of curves into subpaths. The
* simplest solution for now is to just reorder the t
* values and chop out a miniscule curve piece.
*/
double t = t0;
t0 = t1;
t1 = t;
}
if (t1 < 1) {
split(eqn, 0, t1);
}
int i;
if (t0 <= 0) {
i = 0;
} else {
split(eqn, 0, t0 / t1);
i = 6;
}
return new Order3(eqn[i+0], ystart,
eqn[i+2], eqn[i+3],
eqn[i+4], eqn[i+5],
eqn[i+6], yend,
dir);
}
public Curve getReversedCurve() {
return new Order3(x0, y0, cx0, cy0, cx1, cy1, x1, y1, -direction);
}
public int getSegment(double coords[]) {
if (direction == INCREASING) {
coords[0] = cx0;
coords[1] = cy0;
coords[2] = cx1;
coords[3] = cy1;
coords[4] = x1;
coords[5] = y1;
} else {
coords[0] = cx1;
coords[1] = cy1;
coords[2] = cx0;
coords[3] = cy0;
coords[4] = x0;
coords[5] = y0;
}
return PathIterator.SEG_CUBICTO;
}
public String controlPointString() {
return (("("+round(getCX0())+", "+round(getCY0())+"), ")+
("("+round(getCX1())+", "+round(getCY1())+"), "));
}
}

View File

@@ -0,0 +1,78 @@
/*
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.awt.geom;
public interface PathConsumer2D {
/**
* @see java.awt.geom.Path2D.Float.moveTo
*/
public void moveTo(float x, float y);
/**
* @see java.awt.geom.Path2D.Float.lineTo
*/
public void lineTo(float x, float y);
/**
* @see java.awt.geom.Path2D.Float.quadTo
*/
public void quadTo(float x1, float y1,
float x2, float y2);
/**
* @see java.awt.geom.Path2D.Float.curveTo
*/
public void curveTo(float x1, float y1,
float x2, float y2,
float x3, float y3);
/**
* @see java.awt.geom.Path2D.Float.closePath
*/
public void closePath();
/**
* Called after the last segment of the last subpath when the
* iteration of the path segments is completely done. This
* method serves to trigger the end of path processing in the
* consumer that would normally be triggered when a
* {@link java.awt.geom.PathIterator PathIterator}
* returns {@code true} from its {@code done} method.
*/
public void pathDone();
/**
* If a given PathConsumer performs all or most of its work
* natively then it can return a (non-zero) pointer to a
* native function vector that defines C functions for all
* of the above methods.
* The specific pointer it returns is a pointer to a
* PathConsumerVec structure as defined in the include file
* src/share/native/sun/java2d/pipe/PathConsumer2D.h
* @return a native pointer to a PathConsumerVec structure.
*/
public long getNativeConsumer();
}