/**
* Copyright 2010-2013 Jingjing Li.
*
* This file is part of jplot2d.
*
* jplot2d is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or any later version.
*
* jplot2d 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 Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with jplot2d. If not, see .
*/
package org.jplot2d.data;
import org.jplot2d.util.Range;
/**
* Immutable. This class keep (x,y) data pairs and compute data feature such as max/min, NaN indexes.
*
* @author Jingjing Li
*/
public final class XYGraphData implements GraphData {
/** the default capacity for idx lists */
private static final int DEFAULT_CAPACITY = 4;
private final ArrayPair _xy;
private final ArrayPair _errorX, _errorY;
/** A pair of arrays to store NaN data range */
private int[] _rsIdxes, _reIdxes;
/** the last index in the array of NaN data ranges */
private int _nraLastIdx;
private int _nanCount;
private boolean xPositiveInfinity;
private boolean xNegativeInfinity;
private boolean yPositiveInfinity;
private boolean yNegativeInfinity;
private double _xmin = Double.NaN;
private double _xmax = Double.NaN;
private double _ymin = Double.NaN;
private double _ymax = Double.NaN;
private final Range _xboundary;
private final Range _yboundary;
private boolean hasPointOutsideXBounds, hasPointOutsideYBounds;
public XYGraphData(ArrayPair xy) {
this(xy, null, null);
}
public XYGraphData(ArrayPair xy, ArrayPair errorX, ArrayPair errorY) {
this(xy, errorX, errorY, null, null);
}
private XYGraphData(ArrayPair xy, ArrayPair errorX, ArrayPair errorY, Range xboundary, Range yboundary) {
_xy = xy;
_errorX = errorX;
_errorY = errorY;
_xboundary = xboundary;
_yboundary = yboundary;
extractDataFeature();
}
public XYGraphData applyBoundary(Range xboundary, Range yboundary) {
return new XYGraphData(_xy, _errorX, _errorY, xboundary, yboundary);
}
/**
* Extracts the data feature form the XY array.
*
*/
private final void extractDataFeature() {
_rsIdxes = new int[DEFAULT_CAPACITY];
_reIdxes = new int[DEFAULT_CAPACITY];
_nraLastIdx = -1;
for (int i = 0; i < _xy.size(); i++) {
double x = getX(i);
double y = getY(i);
if (Double.isNaN(x) || Double.isNaN(y)) {
addNaNIdx(i);
} else if (x == Double.POSITIVE_INFINITY) {
xPositiveInfinity = true;
} else if (x == Double.NEGATIVE_INFINITY) {
xNegativeInfinity = true;
} else if (y == Double.POSITIVE_INFINITY) {
yPositiveInfinity = true;
} else if (y == Double.NEGATIVE_INFINITY) {
yNegativeInfinity = true;
} else {
double xlow = x, xhigh = x, ylow = y, yhigh = y;
if (_errorX != null && i < _errorX.size()) {
double xel = getXErrorLow(i);
double xeh = getXErrorHigh(i);
if (!Double.isNaN(xel) && !Double.isInfinite(xel)) {
double xelow = x - xel;
if (xlow > xelow) {
xlow = xelow;
}
if (xhigh < xelow) {
xhigh = xelow;
}
}
if (!Double.isNaN(xeh) && !Double.isInfinite(xeh)) {
double xehigh = x + xeh;
if (xlow > xehigh) {
xlow = xehigh;
}
if (xhigh < xehigh) {
xhigh = xehigh;
}
}
}
if (_errorY != null && i < _errorY.size()) {
double yel = getYErrorLow(i);
double yeh = getYErrorHigh(i);
if (!Double.isNaN(yel) && !Double.isInfinite(yel)) {
double yelow = y - yel;
if (ylow > yelow) {
ylow = yelow;
}
if (yhigh < yelow) {
yhigh = yelow;
}
}
if (!Double.isNaN(yeh) && !Double.isInfinite(yeh)) {
double yehigh = y + yeh;
if (ylow > yehigh) {
ylow = yehigh;
}
if (yhigh < yehigh) {
yhigh = yehigh;
}
}
}
if (inXBoundary(x) && inYBoundary(y)) {
if (inXBoundary(xlow)) {
if (!(_xmin <= xlow)) {
_xmin = xlow;
}
} else {
if (!(_xmin <= x)) {
_xmin = x;
}
}
if (inXBoundary(xhigh)) {
if (!(_xmax >= xhigh)) {
_xmax = xhigh;
}
} else {
if (!(_xmax >= x)) {
_xmax = x;
}
}
if (inYBoundary(ylow)) {
if (!(_ymin <= ylow)) {
_ymin = ylow;
}
} else {
if (!(_ymin <= y)) {
_ymin = y;
}
}
if (inYBoundary(yhigh)) {
if (!(_ymax >= yhigh)) {
_ymax = yhigh;
}
} else {
if (!(_ymax >= y)) {
_ymax = y;
}
}
} else {
if (!inXBoundary(x)) {
hasPointOutsideXBounds = true;
}
if (!inYBoundary(y)) {
hasPointOutsideYBounds = true;
}
}
}
}
}
/**
* Returns true if the given x is in the x boundary
*/
private boolean inXBoundary(double x) {
return (_xboundary == null) ? true : _xboundary.contains(x);
}
/**
* Returns true if the given y is in the y boundary
*/
private boolean inYBoundary(double y) {
return (_yboundary == null) ? true : _yboundary.contains(y);
}
private void addNaNIdx(int idx) {
_nanCount++;
if (_nraLastIdx == -1) { // first idx
_nraLastIdx = 0;
_rsIdxes[_nraLastIdx] = _reIdxes[_nraLastIdx] = idx;
} else if (idx == _reIdxes[_nraLastIdx] + 1) { // continuous idx
_reIdxes[_nraLastIdx] = idx;
} else { // new range
_nraLastIdx++;
/* ensure capacity */
if (_nraLastIdx == _rsIdxes.length) {
int[] rstmp = new int[_rsIdxes.length * 2];
System.arraycopy(_rsIdxes, 0, rstmp, 0, _rsIdxes.length);
_rsIdxes = rstmp;
int[] retmp = new int[_reIdxes.length * 2];
System.arraycopy(_reIdxes, 0, retmp, 0, _reIdxes.length);
_reIdxes = retmp;
}
_rsIdxes[_nraLastIdx] = _reIdxes[_nraLastIdx] = idx;
}
}
/**
* Returns a new LineData that contains the appended points.
*
* @param xy
* @return a new LineData object.
*/
public XYGraphData addPoints(ArrayPair xy) {
if (xy != null) {
XYGraphData nld = new XYGraphData(_xy.append(xy), _errorX, _errorY);
return nld;
}
return this;
}
public ArrayPair getXy() {
return _xy;
}
/**
* Get the X coordinate array.
*/
public double getX(int idx) {
return _xy.getPDouble(idx);
}
/**
* Get the Y coordinate array.
*/
public double getY(int idx) {
return _xy.getQDouble(idx);
}
public Range getXRange() {
return new Range.Double(_xmin, _xmax);
}
public Range getYRange() {
return new Range.Double(_ymin, _ymax);
}
public boolean hasPointOutsideXBounds() {
return hasPointOutsideXBounds;
}
public boolean hasPointOutsideYBounds() {
return hasPointOutsideYBounds;
}
/**
* Returns if there is a infinity value in x array.
*
* @return if there is a infinity value in x array.
*/
public boolean isInfiniteX() {
return xPositiveInfinity || xNegativeInfinity;
}
/**
* Returns if there is a infinity value in x array.
*
* @return if there is a infinity value in x array.
*/
public boolean isInfiniteY() {
return yPositiveInfinity || yNegativeInfinity;
}
/**
* Returns the array of indexes of non-real values.
*
* @return the array of indexes.
*/
public int[][] getNaNIndexes() {
int[][] result = new int[2][_nraLastIdx + 1];
System.arraycopy(_rsIdxes, 0, result[0], 0, _nraLastIdx + 1);
System.arraycopy(_reIdxes, 0, result[1], 0, _nraLastIdx + 1);
return result;
}
public int getNaNIndexesCount() {
return _nanCount;
}
/**
* Returns the number of elements in this line data.
*
* @return the number of elements in this line data.
*/
public int size() {
return _xy.size();
}
public ArrayPair getXError() {
return _errorX;
}
public ArrayPair getYError() {
return _errorY;
}
public double getXErrorLow(int idx) {
return _errorX.getPDouble(idx);
}
public double getXErrorHigh(int idx) {
return _errorX.getQDouble(idx);
}
public double getYErrorLow(int idx) {
return _errorY.getPDouble(idx);
}
public double getYErrorHigh(int idx) {
return _errorY.getQDouble(idx);
}
}
Ads help maintain this website.