package plots.views;
import org.eclipse.swt.graphics.Rectangle;
/**
* - Each plot has a span in the domain and co-domain.
* - The View keeps a visible range in the domain that is common to all plots
* - Each plot has also a display rectangle (in widget coordinates)
*
* Here we need to map the plot data into the display rectangle, i.e.
*
* for each x in the display rectangle find the corresponding data value.
* which translates in having a scale factor from display coordinates to domain indexes
*
* @author iannetti
*
*/
public class PlotRange {
// the data span
private int dataStart;
private int dataLength;
// the range itself
private int rangeStart;
private int rangeLength;
public PlotRange(int dataStart, int dataLength) {
this.dataStart = dataStart;
this.dataLength = dataLength;
this.rangeStart = dataStart;
this.rangeLength = dataLength;
}
public PlotRange setRange(int rangeStart, int rangeLength) {
this.rangeStart = rangeStart;
this.rangeLength = rangeLength;
return this;
}
/**
* Return a rectangle that contains the whole data span
* and has the same scale as the given one has for the range.
*
* @return the domain display rectangle
*/
public Rectangle domainDisplayRect(Rectangle displayRect) {
Rectangle s = new Rectangle(displayRect.x, displayRect.y, displayRect.width, displayRect.height);
s.x += (dataStart - rangeStart) * dataLength / rangeLength;
s.width = displayRect.width * dataLength / rangeLength;
return s;
}
/**
* Clip the display rectangle so that it does not exceed the
* data domain when mapped to the range (the range can
* exceed the data domain).
*
* @return the clipped rectangle
*/
public Rectangle clippedDisplayRect(Rectangle displayRect) {
Rectangle r = new Rectangle(displayRect.x, displayRect.y, displayRect.width, displayRect.height);
r.intersect(domainDisplayRect(displayRect));
return r;
}
/**
* Return the factor that converts from display coordinates
* to domain values where the given rectangle maps to the
* full domain.
*
* X = f * (x - offsetX)
*
* if x is in the x range of the rectangle returned by {@link #clippedDisplayRect()}
* then it is guaranteed that X is within the domain range.
*
* offsetX can be obtained by calling the method {@link #offsetX()}.
*
* @return the scale factor f
*/
public float scaleFactorX(Rectangle displayRect) {
float f = displayRect.width / rangeLength;
return f;
}
/**
* The offset to be used in the formula described in {@link #scaleFactorX()}.
*
* @return the offset
*/
public int offsetX(Rectangle displayRect) {
return displayRect.x;
}
public int getDomainStartIndex(int[] domain) {
int from = rangeStart;
// check if the requested position is outside
// the domain
if (from <= domain[0])
return domain[0];
if (from >= domain[domain.length - 1])
return domain[domain.length - 1];
// TODO: can I use the stdlib binary search here?
int i,j, k;
i = 0;
j = domain.length;
k = (i + j) / 2;
while (!(domain[k] <= from && domain[k + 1] > from)) {
System.out.printf("xstart: check k=%d for vl=%d\n", k, from);
if (domain[k] < from) {// 12 -> [10 11 12] -> [11 12]
i = k;
} else {
j = k;
}
k = (i + j) / 2;
}
System.out.printf("xstart: k=%d for vl=%d\n", k, from);
return k;
}
public int getDomainEndIndex(int[] indexes) {
int to = rangeStart + rangeLength;
// check if the requested position is outside
// the domain
if (to <= indexes[0])
return 0;
if (to >= indexes[indexes.length - 1])
return indexes.length - 1;
// TODO: can I use the stdlib binary search here?
int i,j, k;
i = 0;
j = indexes.length;
k = (i + j) / 2;
while (!(indexes[k - 1] < to && indexes[k] >= to)) {
System.out.printf("xend : check k=%d for vl=%d\n", k, to);
if (indexes[k] < to) {
i = k;
} else {
j = k;
}
k = (i + j) / 2;
}
System.out.printf("xend : k=%d for vl=%d\n", k, to);
return k;
}
public int getSpan() {
return rangeLength;
}
public int getRangeStart() {
return rangeStart;
}
public int getRangeLength() {
return rangeLength;
}
}