compress method
Compresses a desired section of an array
to a smaller
newLength
, defaulting to 1024.
ixFirst_
, ixLast_
are the left and right section limits (indices).
Returns a CompressedArray1D object with cArray being the
compressed values if separate
is false. If true, the compressed values are
instead stored in 2 arrays, cArrayPos and cArrayNeg, with only positive and
negative values.
The algorithm fragments the considered section into intervals with a size
computed from newLength
. In each interval, it discards all but 2 values,
the minimum and maximum.
NOTE: If newLength
is not a divisor of the array
length, the last
compressed values are sampled from a wider index interval than the other
compressed values!
Implementation
static CompressedArray1D compress(
Float64List array, int ixFirst_, int ixLast_, bool separate,
[int newLength]) {
if (newLength == null) newLength = 1024;
if (newLength <= 0) newLength = array.length;
if (newLength % 2 != 0) {
newLength += 1; // make even for the following algorithms
}
int ixFirst = ixFirst_, ixLast = ixLast_;
// make some index checks and adjustment if indices out of range
if (ixFirst == null) ixFirst = 0;
if (ixLast == null) ixLast = array.length - 1;
if (ixLast <= ixFirst) {
ixLast = ixFirst + 1;
}
if (ixFirst < 0 || ixFirst > array.length - 1) ixFirst = 0;
if (ixLast > array.length - 1 || ixLast < 0) ixLast = array.length - 1;
// build subset of full data containing only the data from ixFirst to ixLast
int rangeLength = ixLast - ixFirst + 1;
Float64List arrayRange;
if (rangeLength == array.length) {
arrayRange = array;
} else {
arrayRange = new Float64List(ixLast - ixFirst + 1);
for (int i = ixFirst; i < ixLast + 1; i++) {
arrayRange[i - ixFirst] = array[i];
}
}
List<int> indexList;
// return the original data if the input data are too short.
// use all data
if (!separate && arrayRange.length <= 2 * newLength) {
indexList = new List<int>(arrayRange.length);
for (int i = 0; i < arrayRange.length; i++) {
indexList[i] = ixFirst + i;
}
return new CompressedArray1D(arrayRange, indexList, 1);
}
// perform the compression:
// First select newLength*2 rangeLength from the original array because
// we need an x for ymax and one for ymin
indexList = getCompressionIntervals(arrayRange, newLength * 2, ixFirst);
int ixLeft, ixRight;
List<double> yminMax;
Float64List curYvalues;
Float64List newYvalues, newYvaluesPos, newYvaluesNeg;
if (separate) {
newYvaluesPos = new Float64List(newLength);
newYvaluesNeg = new Float64List(newLength);
} else {
newYvalues = new Float64List(newLength * 2);
}
int curix = 0;
for (int i = 0; i < indexList.length; i += 2) {
ixLeft = indexList[i] - ixFirst;
if ((i + 2 > indexList.length - 1) && (i + 1 > indexList.length - 1)) {
ixRight = indexList.last;
} else if (i + 2 > indexList.length - 1) {
ixRight = indexList[i + 1] - ixFirst;
} else {
// we skip one index to double the interval size because from each
// interval we get ymax/ymin
ixRight = indexList[i + 2] - ixFirst;
}
curYvalues = new Float64List(ixRight - ixLeft);
// extract all y values from interval
for (int k = ixLeft; k < ixRight; k++) {
curYvalues[k - ixLeft] = arrayRange[k];
}
if (curYvalues.isEmpty) {}
yminMax = Array1D.getMinMaxVals(curYvalues); // put min/max in right order
if (separate) {
// separate the positive and negative values in separate arrays
if (curix == newYvaluesPos.length - 1) {
yminMax = [array[ixLast - 1], array[ixLast]];
print("XX=$yminMax");
}
double min = Array1D.getMinVal(new Float64List.fromList(yminMax));
if (min < 0)
newYvaluesNeg[curix] = min;
else if (min > 0) newYvaluesPos[curix] = min;
double max = Array1D.getMaxInRange(
new Float64List.fromList(yminMax), null, null);
if (max < 0)
newYvaluesNeg[curix] = max;
else if (max > 0) newYvaluesPos[curix] = max;
if (curix > 120) print("X1000=$i $curix $max $min");
curix++;
} else {
// normal case
newYvalues[curix] = yminMax[0];
curix++;
newYvalues[curix] = yminMax[1];
curix++;
}
// print("i=$i ixLeft=$ixLeft ixRight=$ixRight yminMax=$yminMax newLength=$newLength ${indexList.length}");
}
int cpdIndexIncrement = 1;
int delta;
for (int i = 0; i < indexList.length - 1; i++) // find largest delta
{
delta = indexList[i + 1] - indexList[i];
if (delta > cpdIndexIncrement) cpdIndexIncrement = delta;
}
if (separate)
return new CompressedArray1D.sep(
newYvaluesPos, newYvaluesNeg, indexList, cpdIndexIncrement);
else
return new CompressedArray1D(newYvalues, indexList, cpdIndexIncrement);
}