package org.opensha2.function; import static com.google.common.base.Preconditions.checkArgument; import java.awt.geom.Point2D; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.Iterator; /** * <b>Title:</b> ArbitrarilyDiscretizedFunc<p> * * <b>Description:</b> This class is a sublcass implementation of a * DiscretizedFunc that stores the data internaly as a sorted TreeMap of * DataPoint2D. This subclass distinguishes itself by the fact that it assumes * no spacing interval along the x-axis. Consecutive points can be spread out or * bunched up in no predicatable order. For at least the default comparator * (DataPoint2DComparator), the tolerance determines whether the set() methods * add the point (if x value is more than tolerance away from that of all * existing points) or whether they replace an existing point (if within * tolerance). A tolerance of less than about 1e-16 is effectively about 1e-16 * due to the numerical precision of floating point arithmetic (1.0 - * (1.0+1e-16) = 1.0). <p> * * @author Steven W. Rock, Gupta Brothers * @version 1.0 */ public class ArbitrarilyDiscretizedFunc extends AbstractDiscretizedFunc { /** * The set of DataPoints2D that conprise the discretized function. These are * stored in a Point2D TreeMap so they are sorted on the X-Values.<p> * * This TreeMap will not allow identical DataPoint2D. A comparator and * equals() is used to determine equality. Since you can specify any * comparator you want, this ArbitrarilyDiscretizedFunc can be adopted for * most purposes.<p> * * Note: SWR: I had to make a special org.opensha. version of the Java TreeMap * and subclass DataPoint2DTreeMap to access internal objects in the Java * TreeMap. Java's Treemap had internal objects hidden as private, I exposed * them to subclasses by making them protected in org.opensha.data.TreeMap. * This was neccessary for index access to the points in the TreeMap. Seems * like a poor oversight on the part of Java.<p> */ protected Point2DToleranceSortedList points = null; private static String TAB = "\t"; /** * Creates an ArbitrarilyDiscretizedFunc from an DiscretizedFunc * * @param func */ public ArbitrarilyDiscretizedFunc(AbstractDiscretizedFunc func) { this(func.getTolerance()); Iterator<Point2D> it = func.iterator(); while (it.hasNext()) { this.set(it.next()); } this.setInfo(func.getInfo()); this.setName(func.name()); this.setXAxisName(func.getXAxisName()); this.setYAxisName(func.getYAxisName()); } /** * Constructor that takes a Point2D Comparator. The comparator is used for * sorting the DataPoint2D. Using the no-arg constructor instantiates the * default Comparator that compares only x-values within tolerance to * determine if two points are equal.<p> * * The passed in comparator must be an implementor of * DataPoint2DComparatorAPI. These comparators know they are dealing with a * Point2D and usually only compare the x-values for sorting. Special * comparators may wish to sort on both the x and y values, i.e. the data * points are geographical locations. */ public ArbitrarilyDiscretizedFunc(Point2DComparator comparator) { this(new Point2DToleranceSortedArrayList(comparator)); } /** * No-Arg Constructor that uses the default DataPoint2DToleranceComparator * comparator. The comparator is used for sorting the DataPoint2D. This * default Comparator compares only x-values within tolerance to determine if * two points are equal.<p> * * made private pending ticket #341 */ private ArbitrarilyDiscretizedFunc(double tolerance) { this(new Point2DToleranceComparator(tolerance)); } /** * No-Arg Constructor that uses the default DataPoint2DToleranceComparator * comparator. The comparator is used for sorting the DataPoint2D. This * default Comparator compares only x-values within tolerance to determine if * two points are equal.<p> * * The default tolerance of 0 is used. This means that two x-values must be * exactly equal doubles to be considered equal. */ public ArbitrarilyDiscretizedFunc() { this(new Point2DToleranceComparator()); } /** * Creates a default arbitrarily discretized function with the given name * @param name */ public ArbitrarilyDiscretizedFunc(String name) { this(); setName(name); } public ArbitrarilyDiscretizedFunc(Point2DToleranceSortedList points) { this.points = points; } /** * Sets the tolerance of this function. Overides the default function in the * abstract class in that it calls setTolerance in the tree map which updates * the comparator in there. * * These field getters and setters provide the basic information to describe a * function. All functions have a name, information string, and a tolerance * level that specifies how close two points have to be along the x axis to be * considered equal. A tolerance of less than about 1e-16 is effectively about * 1e-16 due to the numerical precision of floating point arithmetic (1.0 - * (1.0+1e-16) = 1.0). */ @Override public void setTolerance(double newTolerance) { checkArgument(newTolerance >= 0, "Tolerance must be larger or equal to 0"); points.setTolerance(newTolerance); tolerance = newTolerance; } /** returns the number of points in this function list */ @Override public int getNum() { return points.size(); } /** * return the minimum x value along the x-axis. Since the values are sorted * this is a very quick lookup */ @Override public double getMinX() { ; return points.getMinX(); } /** * return the maximum x value along the x-axis. Since the values are sorted * this is a very quick lookup */ @Override public double getMaxX() { return points.getMaxX(); } /** * Return the minimum y value along the y-axis. This value is calculated every * time a Point2D is added to the list and cached as a variable so this * function returns very quickly. Slows down adding new points slightly. I * assume that most of the time these lists will be created once, then used * for plotting and in other functions, in other words more lookups than * inserts. */ @Override public double getMinY() { return points.getMinY(); } /** * Return the maximum y value along the y-axis. This value is calculated every * time a Point2D is added to the list and cached as a variable so this * function returns very quickly. Slows down adding new points slightly. I * assume that most of the time these lists will be created once, then used * for plotting and in other functions, in other words more lookups than * inserts. */ @Override public double getMaxY() { return points.getMaxY(); } /** * Returns the nth (x,y) point in the Function, else null if this index point * doesn't exist */ @Override public Point2D get(int index) { return points.get(index); } /** Returns the x value of a point given the index */ @Override public double getX(int index) { Point2D pt = get(index); if (pt == null) { throw new IndexOutOfBoundsException("no point at index " + index); } return pt.getX(); } /** Returns the y value of a point given the index */ @Override public double getY(int index) { Point2D pt = get(index); if (pt == null) { throw new IndexOutOfBoundsException("no point at index " + index); } return pt.getY(); } /** * returns the Y value given an x value - within tolerance, returns null if * not found */ @Override public double getY(double x) { return points.get(x).getY(); } /** * returns the Y value given an x value - within tolerance, returns null if * not found */ @Override public int getIndex(Point2D point) { return points.indexOf(point); } /** Returns the x value of a point given the index or -1 if not found */ @Override public int getXIndex(double x) { return points.indexOf(new Point2D.Double(x, 0.0)); } /** * Either adds a new DataPoint, or replaces an existing one, within tolerance */ @Override public void set(Point2D point) { points.add(point); // wtf; the exception below can never be thrown; parent add // implementations // never return false // if (!points.add(point)) // throw new RuntimeException("set called but nothing changed!"); } /** * Either adds a new DataPoint, or replaces an existing one, within tolerance, * created from the input x and y values. */ @Override public void set(double x, double y) { set(new Point2D.Double(x, y)); } /** * Replaces a y value for an existing point, accessed by index. If no * DataPoint exists nothing is done. */ @Override public void set(int index, double y) { Point2D point = get(index); if (point != null) { point.setLocation(point.getX(), y); set(point); } else { throw new IndexOutOfBoundsException(); } } /** * Determinces if a DataPoit2D exists in the treemap base on it's x value * lookup. Returns true if found, else false if point not in list. */ @Override public boolean hasPoint(Point2D point) { int index = getIndex(point); if (index < 0) { return false; } else { return true; } } /** * Determinces if a DataPoit2D exists in the treemap base on it's x value * lookup. Returns true if found, else false if point not in list. */ @Override public boolean hasPoint(double x, double y) { return hasPoint(new Point2D.Double(x, y)); } /** * Returns an iterator over all datapoints in the list. Results returned in * sorted order. Returns null if no points present. */ public Iterator<Point2D> getPointsIterator() { return points.iterator(); } @Override public Iterator<Point2D> iterator() { return points.iterator(); } /** * Given the imput y value, finds the two sequential x values with the closest * y values, then calculates an interpolated x value for this y value, fitted * to the curve. <p> * * Since there may be multiple y values with the same value, this function * just matches the first found. * * @param y value for which interpolated first x value has to be found * @return x the interpolated x based on the given y value */ @Override public double getFirstInterpolatedX(double y) { // finds the size of the point array int max = points.size(); // if Size of the function is 1 and Y value is equal to Y val of // function // return the only X value if (max == 1 && y == getY(0)) { return getX(0); } double y1 = Double.NaN; double y2 = Double.NaN; int i; boolean found = false; // this boolean hold whether the passed y value // lies within range // finds the Y values within which the the given y value lies for (i = 0; i < max - 1; ++i) { y1 = getY(i); y2 = getY(i + 1); if ((y <= y1 && y >= y2 && y2 <= y1) || (y >= y1 && y <= y2 && y2 >= y1)) { found = true; break; } } // if passed parameter(y value) is not within range then throw exception checkArgument(found, "Y Value (%s) must be within the range: %s and %s", y, getY(0), getY(max - 1)); // finding the x values for the coressponding y values double x1 = getX(i); double x2 = getX(i + 1); // using the linear interpolation equation finding the value of x for // given y double x = ((y - y1) * (x2 - x1)) / (y2 - y1) + x1; return x; } /** * Given the input y value, finds the two sequential x values with the closest * y values, then calculates an interpolated x value for this y value, fitted * to the curve. The interpolated Y value returned is in the linear space but * the interpolation is done in the log space. Since there may be multiple y * values with the same value, this function just matches the first found * starting at the x-min point along the x-axis. * @param y : Y value in the linear space coressponding to which we are * required to find the interpolated x value in the log space. * @return x(this is the interpolated x based on the given y value) */ @Override public double getFirstInterpolatedX_inLogXLogYDomain(double y) { // finds the size of the point array int max = points.size(); // if Size of the function is 1 and Y value is equal to Y val of // function // return the only X value if (max == 1 && y == getY(0)) { return getX(0); } double y1 = Double.NaN; double y2 = Double.NaN; int i; boolean found = false; // this boolean hold whether the passed y value // lies within range // finds the Y values within which the the given y value lies for (i = 0; i < max - 1; ++i) { y1 = getY(i); y2 = getY(i + 1); if ((y <= y1 && y >= y2) || (y >= y1 && y <= y2)) { found = true; break; } } // if passed parameter(y value) is not within range then throw exception checkArgument(found, "Y Value (%s) must be within the range: %s and %s", y, getY(0), getY(max - 1)); // finding the x values for the coressponding y values double x1 = Math.log(getX(i)); double x2 = Math.log(getX(i + 1)); y1 = Math.log(y1); y2 = Math.log(y2); y = Math.log(y); // using the linear interpolation equation finding the value of x for // given y double x = ((y - y1) * (x2 - x1)) / (y2 - y1) + x1; return Math.exp(x); } private int getXIndexBefore(double x) { int ind = points.binarySearch(new Point2D.Double(x, 0)); if (ind < 0) { return -ind - 2; } return ind - 1; } /** * Given the imput x value, finds the two sequential x values with the closest * x values, then calculates an interpolated y value for this x value, fitted * to the curve. * * @param x value for which interpolated first y value has to be found * @return y the interpolated x based on the given x value */ @Override public double getInterpolatedY(double x) { // finds the size of the point array int max = points.size(); // if passed parameter(x value) is not within range then throw exception checkArgument(x <= getX(max - 1) && x >= getX(0), "x-value (%s) must be within the range: %s and %s", x, getX(0), getX(max - 1)); // if x value is equal to the maximum value of all given X's then return // the corresponding Y value if (x == getX(max - 1)) { return getY(x); } // finds the X values within which the the given x value lies int x1Ind = getXIndexBefore(x); if (x1Ind == -1) { // this means that it matches at index 0 return getY(0); } int x2Ind = x1Ind + 1; Point2D pt1 = get(x1Ind); Point2D pt2 = get(x2Ind); double x1 = pt1.getX(); double y1 = pt1.getY(); double x2 = pt2.getX(); double y2 = pt2.getY(); // using the linear interpolation equation finding the value of y for // given x double y = ((y2 - y1) * (x - x1)) / (x2 - x1) + y1; return y; } /** * This function interpolates the y-axis value corresponding to the given * value of x. the interpolation of the Y value is done in the log space for x * and y values. The Y value returned is in the linear space but the * interpolation is done in the log space. If both bounding y values are zero, * then zero is returned. If only one of the bounding y values is zero, that * value is converted to Double.MIN_VALUE. If the interpolated y value is * Double.MIN_VALUE, it is converted to 0.0. * @param x : X value in the linear space corresponding to which we are * required to find the interpolated y value in log space. * @return y(this is the interpolated y in linear space based on the given x * value) */ @Override public double getInterpolatedY_inLogXLogYDomain(double x) { // finds the size of the point array int max = points.size(); // if passed parameter(x value) is not within range then throw exception checkArgument(x <= getX(max - 1) && x >= getX(0), "x-value (%s) must be within the range: %s and %s", x, getX(0), getX(max - 1)); // if x value is equal to the maximum value of all given X's then return // the corresponding Y value if (x == getX(max - 1)) { return getY(x); } int x1Ind = getXIndexBefore(x); int x2Ind = x1Ind + 1; Point2D pt1 = get(x1Ind); Point2D pt2 = get(x2Ind); double x1 = pt1.getX(); double y1 = pt1.getY(); double x2 = pt2.getX(); double y2 = pt2.getY(); if (y1 == 0 && y2 == 0) { return 0; } if (y1 == 0) { y1 = Double.MIN_VALUE; } if (y2 == 0) { y2 = Double.MIN_VALUE; } double logY1 = Math.log(y1); double logY2 = Math.log(y2); x1 = Math.log(x1); x2 = Math.log(x2); x = Math.log(x); // using the linear interpolation equation finding the value of y for // given x double y = ((logY2 - logY1) * (x - x1)) / (x2 - x1) + logY1; double expY = Math.exp(y); if (expY == Double.MIN_VALUE) { expY = 0.0; } return expY; } /* * THIS WAS FOR DEBUGGING WHERE ERRORS OCCURRED IF ONLY ONE Y-VALUE WAS 0.0 * public double getInterpolatedY_inLogXLogYDomain(double x, boolean debug){ * // finds the size of the point array int max=points.size(); double * x1=Double.NaN; double x2=Double.NaN; //if passed parameter(x value) is not * within range then throw exception if(x>getX(max-1) || x<getX(0)) throw new * InvalidRangeException("x Value must be within the range: " +getX(0)+" and " * +getX(max-1)); //if x value is equal to the maximum value of all given X's * then return the corresponding Y value if(x==getX(max-1)) return getY(x); * //finds the X values within which the the given x value lies for(int * i=0;i<max-1;++i) { x1=getX(i); x2=getX(i+1); if(x>=x1 && x<=x2) break; } * //finding the y values for the coressponding x values double y1 = getY(x1); * double y2 = getY(x2); if(y1==0 && y2==0) return 0; if(y1==0) y1 = * Double.MIN_VALUE; if(y2==0) y2 = Double.MIN_VALUE; double * logY1=Math.log(y1); double logY2=Math.log(y2); if(debug) { * System.out.println("tol="+this.tolerance); * System.out.print(x1+"\t"+x2+"\t"+x+"\t"); } x1 = Math.log(x1); x2 = * Math.log(x2); x = Math.log(x); //using the linear interpolation equation * finding the value of y for given x double y= ((logY2-logY1)*(x-x1))/(x2-x1) * + logY1; double expY = Math.exp(y); if (expY == Double.MIN_VALUE) expY = * 0.0; if(debug) { * System.out.println(y1+"\t"+y2+"\t"+logY1+"\t"+logY2+"\t"+x1+"\t"+x2+"\t"+ * x+ "\t"+y+"\t"+Math.exp(x1)+"\t"+Math.exp(x2)+"\t"+Math.exp(x)+"\t"+expY+ * "\t"+Double.MIN_VALUE); } * * return expY; * * } */ /** * This function interpolates the y-axis value corresponding to the given * value of x. the interpolation of the Y value is done in the log-y space. * The Y value returned is in the linear space. * @param x : X value in the linear space corresponding to which we are * required to find the interpolated y value in log space. * @return y(this is the interpolated y in linear space based on the given x * value) */ @Override public double getInterpolatedY_inLogYDomain(double x) { // finds the size of the point array int max = points.size(); // if passed parameter(x value) is not within range then throw exception checkArgument(x <= getX(max - 1) && x >= getX(0), "x-value (%s) must be within the range: %s and %s", x, getX(0), getX(max - 1)); // if x value is equal to the maximum value of all given X's then return // the corresponding Y value if (x == getX(max - 1)) { return getY(x); } // finds the X values within which the the given x value lies int x1Ind = getXIndexBefore(x); int x2Ind = x1Ind + 1; Point2D pt1 = get(x1Ind); Point2D pt2 = get(x2Ind); double x1 = pt1.getX(); double y1 = pt1.getY(); double x2 = pt2.getX(); double y2 = pt2.getY(); if (y1 == 0 && y2 == 0) { return 0; } double logY1 = Math.log(y1); double logY2 = Math.log(y2); // using the linear interpolation equation finding the value of y for // given x double y = ((logY2 - logY1) * (x - x1)) / (x2 - x1) + logY1; return Math.exp(y); } private double extrapolate(double x1, double x2, double y1, double y2, double x) { // Create the linear regression function (slope and intercept) // System.out.printf("\textrapolating(%f, %f, %f, %f, %f)\n", // x1, x2, y1, y2, x); double slope = (y2 - y1) / (x2 - x1); double intercept = y1 - (slope * x1); // System.out.printf("\tSlope is: %f\tIntercept is: %f\n", // slope, intercept); return (slope * x) + intercept; } public double getInterpExterpY_inLogYDomain(double x) { try { double v = getInterpolatedY_inLogYDomain(x); // System.err.println("interpolating(" + x + ")..."); return v; } catch (IllegalArgumentException iae) { // System.err.println("extrapolating(" + x + ")..."); // We gotta extrapolate... if (x < getX(0)) { return Math.exp(extrapolate(getX(0), getX(1), Math.log(getY(0)), Math.log(getY(1)), x)); } int max = points.size(); return Math.exp(extrapolate(getX(max - 2), getX(max - 1), Math.log(getY(max - 2)), Math.log(getY(max - 1)), x)); } } /** * This function returns a new copy of this list, including copies of all the * points. A shallow clone would only create a new DiscretizedFunc instance, * but would maintain a reference to the original points. <p> * * Since this is a clone, you can modify it without changing the original. */ @Override public ArbitrarilyDiscretizedFunc deepClone() { ArbitrarilyDiscretizedFunc function = new ArbitrarilyDiscretizedFunc(); function.setName(name()); function.setTolerance(getTolerance()); function.setInfo(getInfo()); function.setXAxisName(this.getXAxisName()); function.setYAxisName(this.getYAxisName()); Iterator it = this.iterator(); if (it != null) { while (it.hasNext()) { function.set((Point2D) ((Point2D) it.next()).clone()); } } return function; } /** * Determines if two functions are the same by comparing that each point x * value is the same. This requires the two lists to have the same number of * points. */ public boolean equalXValues(DiscretizedFunc function) { // String S = C + ": equalXValues():"; if (this.getNum() != function.getNum()) { return false; } Iterator it = this.iterator(); while (it.hasNext()) { Point2D point = (Point2D) it.next(); if (!function.hasPoint(point)) { return false; } } return true; } /** * Standard java function, usually used for debugging, prints out the state of * the list, such as number of points, the value of each point, etc. */ @Override public String toString() { StringBuffer b = new StringBuffer(); b.append("Name: " + name() + '\n'); b.append("Num Points: " + getNum() + '\n'); b.append("Info: " + getInfo() + "\n\n"); b.append("X, Y Data:" + '\n'); b.append(getMetadataString() + '\n'); return b.toString(); } /** * * @return value of each point in the function in String format */ @Override public String getMetadataString() { StringBuffer b = new StringBuffer(); Iterator it2 = this.iterator(); while (it2.hasNext()) { Point2D point = (Point2D) it2.next(); double x = point.getX(); double y = point.getY(); b.append((float) x + TAB + (float) y + '\n'); } return b.toString(); } /** * Almost the same as toString() but used specifically in a debugging context. * Formatted slightly different */ public String toDebugString() { StringBuffer b = new StringBuffer(); b.append(C + ": Log values:\n"); Iterator it = this.iterator(); while (it.hasNext()) { Point2D point = (Point2D) it.next(); b.append(point.toString() + '\n'); } return b.toString(); } /** * This method creates serialized Outputstream for the DataPoint2D * @param s */ private void writeObject(ObjectOutputStream s) { Iterator<Point2D> it = iterator(); try { s.writeObject(points.getComparator()); s.writeObject(new Integer(getNum())); while (it.hasNext()) { Point2D data = (Point2D) it.next(); // System.out.println("Data: "+data.toString()); s.writeObject(data); } } catch (IOException e) { e.printStackTrace(); } } /** * This method deserialises InputStream for the DataPoint2D * @param s */ private void readObject(ObjectInputStream s) { try { Point2DComparator comp = (Point2DComparator) s.readObject(); points = new Point2DToleranceSortedArrayList(comp); int num = ((Integer) s.readObject()).intValue(); for (int i = 0; i < num; ++i) { Point2D data = (Point2D) s.readObject(); set(data); } // System.out.println("Data Object read: "+data.toString()); } catch (ClassNotFoundException e) { System.out.println("Class not found"); e.printStackTrace(); } catch (IOException e) { System.out.println("IO Exception "); e.printStackTrace(); } } /** * This function creates a new ArbitrarilyDiscretizedFunc whose X values are * the Y values of the calling function and Y values are the Y values of the * function passed as argument. * @param function DiscretizedFuncAPI function whose Y values will the Y * values of the new ArbitrarilyDiscretizedFunc. * @return ArbitrarilyDiscretizedFunc new ArbitrarilyDiscretizedFunc */ public ArbitrarilyDiscretizedFunc getYY_Function(DiscretizedFunc function) { checkArgument(getNum() == function.getNum(), "This operation cannot be performed on functions with different size"); ArbitrarilyDiscretizedFunc newFunction = new ArbitrarilyDiscretizedFunc(); int numPoints = function.getNum(); for (int j = 0; j < numPoints; ++j) { newFunction.set(getY(j), function.getY(j)); } return newFunction; } /** * Clear all the X and Y values from this function */ public void clear() { points.clear(); } public double[] getXVals() { double[] d = new double[points.size()]; for (int i = 0; i < points.size(); ++i) { d[i] = getX(i); } return d; } public double[] getYVals() { double[] d = new double[points.size()]; for (int i = 0; i < points.size(); ++i) { d[i] = getY(i); } return d; } public static void main(String[] args) { ArbitrarilyDiscretizedFunc f = new ArbitrarilyDiscretizedFunc(); f.set(100d, 0.013609); f.set(250d, 0.033695); f.set(500d, 0.059583); f.set(1000d, 0.093446); f.set(1500d, 0.119977); f.set(2500d, 0.163888); f.set(3000d, 0.177374); f.set(5000d, 0.228356); f.set(7000d, 0.265878); f.set(10000d, 0.314945); // double[] lookups = // {10,20,30,40,50,60,70,80,100,150,200,250,333,475,700,800,1000,1200,1300,1500,1800,2000,2475,10000}; double[] lookups = { 150, 200, 250, 333, 475, 700, 800, 1000, 1200, 1300, 1500, 1800, 2000, 2475, 10000 }; for (double v : lookups) { int iBefore = f.getXIndexBefore(v); double yInterp = f.getInterpolatedY_inLogXLogYDomain(v); System.out.println("lookup: " + v); System.out.println(" iBefore: " + iBefore); System.out.println(" yInterp: " + yInterp); } } /* * temp main method to investige numerical precision issues public static void * main( String[] args ) { * * ArbitrarilyDiscretizedFunc func = new ArbitrarilyDiscretizedFunc(); // * func.setTolerance(Double.MIN_VALUE); func.set(1.0,0); * func.set(Double.MIN_VALUE,0); func.set(1+1e-16,1); func.set(1+2e-16,2); * func.set(1+3e-16,3); func.set(1+4e-16,4); func.set(1+5e-16,5); * func.set(1+6e-16,6); func.set(1+7e-16,7); func.set(1+8e-16,8); * func.set(1+9e-16,9); func.set(1+10e-16,10); Iterator it = func.iterator(); * Point2D point; while( it.hasNext()) { point = (Point2D) it.next(); * System.out.println(point.getX()+" "+point.getY()); } } * */ /* * public void rebuild(){ * * // make temporary storage ArrayList points = new ArrayList(); * * // get all points Iterator it = getPointsIterator(); if( it != null ) * while(it.hasNext()) { points.add( (Point2D)it.next() ); } * * // get all non-log points if any it = getNonLogPointsIterator(); if( it != * null ) while(it.hasNext()) { points.add( (Point2D)it.next() ); } * * // clear permanent storage points.clear(); nonPositivepoints.clear(); * * // rebuild permanent storage it = points.listIterator(); if( it != null ) * while(it.hasNext()) { set( (Point2D)it.next() ); } * * if( D ) System.out.println("rebuild: " + toDebugString()); points = null; } * * public boolean isYLog() { return yLog; } public void setYLog(boolean yLog) * { * * if( yLog != this.yLog ) { this.yLog = yLog; rebuild(); } } * * public boolean isXLog() { return xLog; } public void setXLog(boolean xLog) * { if( xLog != this.xLog ) { this.xLog = xLog; rebuild(); } } * */ }