/* * Copyright 2003-2010 Tufts University Licensed under the * Educational Community License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may * obtain a copy of the License at * * http://www.osedu.org/licenses/ECL-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an "AS IS" * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing * permissions and limitations under the License. */ package tufts.vue.shape; 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) { 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; } }