📄 dynamictimeseriescollection.java
字号:
* Returns the number of items in a series. * <p> * For this implementation, all series have the same number of items. * * @param series the series index (zero-based). * * @return The item count. */ public int getItemCount(final int series) { // all arrays equal length, so ignore argument: return this.historyCount; } // Methods for managing the FIFO's: /** * Re-map an index, for use in retrieving data. * * @param toFetch the index. * * @return The translated index. */ protected int translateGet(final int toFetch) { if (this.oldestAt == 0) { return toFetch; // no translation needed } // else [implicit here] int newIndex = toFetch + this.oldestAt; if (newIndex >= this.historyCount) { newIndex -= this.historyCount; } return newIndex; } /** * Returns the actual index to a time offset by "delta" from newestAt. * * @param delta the delta. * * @return The offset. */ public int offsetFromNewest(final int delta) { return wrapOffset(this.newestAt + delta); } /** * ?? * * @param delta ?? * * @return The offset. */ public int offsetFromOldest(final int delta) { return wrapOffset(this.oldestAt + delta); } /** * ?? * * @param protoIndex the index. * * @return The offset. */ protected int wrapOffset(final int protoIndex) { int tmp = protoIndex; if (tmp >= this.historyCount) { tmp -= this.historyCount; } else if (tmp < 0) { tmp += this.historyCount; } return tmp; } /** * Adjust the array offset as needed when a new time-period is added: * Increments the indices "oldestAt" and "newestAt", mod(array length), * zeroes the series values at newestAt, returns the new TimePeriod. * * @return The new time period. */ public synchronized RegularTimePeriod advanceTime() { final RegularTimePeriod nextInstant = this.pointsInTime[this.newestAt].next(); this.newestAt = this.oldestAt; // newestAt takes value previously held by oldestAT /*** The next 10 lines or so should be expanded if data can be negative ***/ // if the oldest data contained a maximum Y-value, invalidate the stored // Y-max and Y-range data: boolean extremaChanged = false; float oldMax = 0.0f; if (this.maxValue != null) { oldMax = this.maxValue.floatValue(); } for (int s = 0; s < getSeriesCount(); s++) { if (this.valueHistory[s].getData(this.oldestAt) == oldMax) { extremaChanged = true; } if (extremaChanged) { break; } } /*** If data can be < 0, add code here to check the minimum **/ if (extremaChanged) { invalidateRangeInfo(); } // wipe the next (about to be used) set of data slots final float wiper = (float) 0.0; for (int s = 0; s < getSeriesCount(); s++) { this.valueHistory[s].enterData(this.newestAt, wiper); } // Update the array of TimePeriods: this.pointsInTime[this.newestAt] = nextInstant; // Now advance "oldestAt", wrapping at end of the array this.oldestAt++; if (this.oldestAt >= this.historyCount) { this.oldestAt = 0; } // Update the domain limits: final long startL = this.domainStart.longValue(); //(time is kept in msec) this.domainStart = new Long(startL + this.deltaTime); final long endL = this.domainEnd.longValue(); this.domainEnd = new Long(endL + this.deltaTime); this.domainRange = new Range(startL, endL); fireSeriesChanged(); return nextInstant; } // If data can be < 0, the next 2 methods should be modified /** * Invalidates the range info. */ public void invalidateRangeInfo() { this.maxValue = null; this.valueRange = null; } /** * Returns the maximum value. * * @return The maximum value. */ protected double findMaxValue() { double max = 0.0f; for (int s = 0; s < getSeriesCount(); s++) { for (int i = 0; i < this.historyCount; i++) { final double tmp = getY(s, i); if (tmp > max) { max = tmp; } } } return max; } /** End, positive-data-only code **/ /** * Returns the index of the oldest data item. * * @return The index. */ public int getOldestIndex() { return this.oldestAt; } /** * Returns the index of the newest data item. * * @return The index. */ public int getNewestIndex() { return this.newestAt; } // appendData() writes new data at the index position given by newestAt/ // When adding new data dynamically, use advanceTime(), followed by this: /** * Appends new data. * * @param newData the data. */ public void appendData(final float[] newData) { final int nDataPoints = newData.length; if (nDataPoints > this.valueHistory.length) { throw new IllegalArgumentException( "DynamicTimeSeriesCollection.appendData(...): more data than series to put them in"); } int s; // index to select the "series" for (s = 0; s < nDataPoints; s++) { // check whether the "valueHistory" array member exists; if not, create them: if (this.valueHistory[s] == null) { this.valueHistory[s] = new ValueSequence(this.historyCount); } this.valueHistory[s].enterData(this.newestAt, newData[s]); } fireSeriesChanged(); } /** * Appends data at specified index, for loading up with data from file(s). * * @param newData the data * @param insertionIndex the index value at which to put it * @param refresh value of n in "refresh the display on every nth call" * (ignored if <= 0 ) */ public void appendData(final float[] newData, int insertionIndex, final int refresh) { final int nDataPoints = newData.length; if (nDataPoints > this.valueHistory.length) { throw new IllegalArgumentException( "DynamicTimeSeriesCollection.appendData(...): more data than series to put them " + "in"); } for (int s = 0; s < nDataPoints; s++) { if (this.valueHistory[s] == null) { this.valueHistory[s] = new ValueSequence(this.historyCount); } this.valueHistory[s].enterData(insertionIndex, newData[s]); } if (refresh > 0) { insertionIndex++; if (insertionIndex % refresh == 0) { fireSeriesChanged(); } } } /** * Returns the newest time. * * @return The newest time. */ public RegularTimePeriod getNewestTime() { return this.pointsInTime[this.newestAt]; } /** * Returns the oldest time. * * @return The oldest time. */ public RegularTimePeriod getOldestTime() { return this.pointsInTime[this.oldestAt]; } /** * Returns the x-value. * * @param series the series index (zero-based). * @param item the item index (zero-based). * * @return The value. */ // getXxx() ftns can ignore the "series" argument: // Don't synchronize this!! Instead, synchronize the loop that calls it. public Number getXValue(final int series, final int item) { final RegularTimePeriod tp = this.pointsInTime[translateGet(item)]; return new Long(getX(tp)); } /** * Returns the y-value. * * @param series the series index (zero-based). * @param item the item index (zero-based). * * @return The value. */ public double getY(final int series, final int item) { // Don't synchronize this!! final ValueSequence values = this.valueHistory[series]; // Instead, synchronize the loop return values.getData(translateGet(item)); // that calls it. } /** * Returns the y-value. * * @param series the series index (zero-based). * @param item the item index (zero-based). * * @return The value. */ public Number getYValue(final int series, final int item) { return new Float(getY(series, item)); } /** * Returns the start x-value. * * @param series the series index (zero-based). * @param item the item index (zero-based). * * @return The value. */ public Number getStartXValue(final int series, final int item) { final RegularTimePeriod tp = this.pointsInTime[translateGet(item)]; return new Long(tp.getFirstMillisecond(this.workingCalendar)); } /** * Returns the end x-value. * * @param series the series index (zero-based). * @param item the item index (zero-based). * * @return The value. */ public Number getEndXValue(final int series, final int item) { final RegularTimePeriod tp = this.pointsInTime[translateGet(item)]; return new Long(tp.getLastMillisecond(this.workingCalendar)); } /** * Returns the start y-value. * * @param series the series index (zero-based). * @param item the item index (zero-based). * * @return The value. */ public Number getStartYValue(final int series, final int item) { return getYValue(series, item); } /** * Returns the end y-value. * * @param series the series index (zero-based). * @param item the item index (zero-based). * * @return The value. */ public Number getEndYValue(final int series, final int item) { return getYValue(series, item); } /* // "Extras" found useful when analyzing/verifying class behavior: public Number getUntranslatedXValue(int series, int item) { return super.getXValue(series, item); } public float getUntranslatedY(int series, int item) { return super.getY(series, item); } */ /** * Returns the name of a series. * * @param series the series index (zero-based). * * @return The name. */ public String getSeriesName(final int series) { return this.seriesNames[series]; } /** * Sends a {@link SeriesChangeEvent} to all registered listeners. */ protected void fireSeriesChanged() { seriesChanged(new SeriesChangeEvent(this)); } // The next 3 functions override the base-class implementation of // the DomainInfo interface. Using saved limits (updated by // each updateTime() call), improves performance. // /** * Returns the range of values for the domain. * * @return The range. */ public Range getDomainRange() { if (this.domainRange == null) { findDomainLimits(); } return this.domainRange; } /** * Returns the minimum value in the dataset (or null if all the values in * the domain are null). * * @return the minimum value. */ public Number getMinimumDomainValue() { return this.domainStart; // a Long kept updated by advanceTime() } /** * Returns the maximum value in the dataset (or null if all the values in * the domain are null). * * @return the maximum value. */ public Number getMaximumDomainValue() { return this.domainEnd; // a Long kept updated by advanceTime() } /** * Returns the x-value for a time period. * * @param period the period. * * @return The x-value. */ private long getX(final RegularTimePeriod period) { switch (this.position) { case (START) : return period.getFirstMillisecond(this.workingCalendar); case (MIDDLE) : return period.getMiddleMillisecond(this.workingCalendar); case (END) : return period.getLastMillisecond(this.workingCalendar); default: return period.getMiddleMillisecond(this.workingCalendar); } } // The next 3 functions implement the RangeInfo interface. // Using saved limits (updated by each updateTime() call) significantly // improves performance. WARNING: this code makes the simplifying assumption // that data is never negative. Expand as needed for the general case. /** * Returns the minimum range value. * * @return The minimum range value. */ public Number getMinimumRangeValue() { return this.minValue; } /** * Returns the maximum range value. * * @return The maximum range value. */ public Number getMaximumRangeValue() { if (this.maxValue == null) { this.maxValue = new Float(findMaxValue()); } return this.maxValue; } /** * Returns the value range. * * @return The range. */ public Range getValueRange() { if (this.valueRange == null) { final Float maxV = (Float) getMaximumRangeValue(); final double max = maxV.doubleValue(); this.valueRange = new Range(0.0, max); } return this.valueRange; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -