📄 selectedwfwindowmodel.java
字号:
package org.trinet.jiggle;
import org.trinet.util.TimeSpan;
import org.trinet.jasi.Waveform;
import java.util.*;
import java.awt.*;
import javax.swing.event.*;
/**
* Keeps track the time and amp bounds that are "selected" for a waveform.
* Time bounds are kept as absolute time but amp is <b>relative</b> to the
* full max/min range of the waveform data.
* Treats the max and min bounds of the vertical (amp) dimension as a ratio of
* the full-scale waveform. This is useful when scaling one WFPanel from
* another and the amplitude bounds or units are different in the two views.
* This can happened when the waveform is filtered or demeaned.
* The arguments maxOffset and minOffset are between 0.0 and 1.0 and are measures
* from the <b>top</b> of the data. For example: (0.0, 1.0) would be full scale
* (0.25, 0.75) would show the middle half of the amp range.<p>
* If there is no waveform
*
* */
public class SelectedWFWindowModel extends ChangeModel {
/** The TimeSpan of the selected box */
TimeSpan timeSpan = new TimeSpan();
/** Maximum amplitude as an offset from the "top" or maximum amp value */
double ampTop = 0.0;
/** Minimum amplitude as an offset from the "top" or maximum amp value*/
double ampBot = 1.0;
// These minimums server two purposes:
// 1) prevent /0 errors in scaling calculations when there is no timeseries
// data in a Waveform
// 2) prevent sloppy clicks that are really 1 or 2 pixel drags from zooming
// tiny time windows
/** Minimum possible time dimension in relative units where full scale is 0.0->1.0.
* Default value is 0.001 effectivly limiting zooming to 1000x */
double minTimeSize = 0.001;
/** Minimum possible amp dimension in relative units where full scale is 0.0->1.0.
* Default value is 0.001 effectivly limiting zooming to 1000x */
double minAmpSize = 0.001;
/** Ignore request to move the center time less then this.
* This prevents recursion problems caused by precision jitter in time calculations. */
static final double PRECISION_LIMIT = 0.0001;
//boolean debug = true;
boolean debug = false;
/** Null Constructor */
public SelectedWFWindowModel() {
}
/** Set the minimum allowable range in time (sec) and amp
* (native Waveform units).
* This serves two purposes: <p>
1) prevent /0 errors in scaling calculations when there is no waveform<br>
2) prevent sloppy clicks that are really 1 or 2 pixel drags from zooming tiny time windows
*/
public void setMinSize (double minTime, double minAmp) {
setMinTimeSize(minTime);
setMinAmpSize(minAmp);
}
public void setMinTimeSize (double minTime) {
minTimeSize = minTime;
}
public void setMinAmpSize (double minAmp) {
minAmpSize = minAmp;
}
/** Return the minimum allowable time range in seconds. */
public double getMinTime() {
return minTimeSize;
}
/** Return the minimum allowable amplitude range in counts. */
public double getMinAmpSize() {
return minAmpSize;
}
public TimeSpan getTimeSpan() {
return timeSpan;
}
public double getCenterTime() {
return timeSpan.getCenter();
}
/** Return the length of the time window in seconds. */
public double getTimeSize() {
return getTimeSpan().getEnd() - getTimeSpan().getStart();
}
/** Return the height of the amp window in units native to the Waveform.
* If there is no waveform, returns the minAmpSize.
* @See: Waveform.getAmpUnits()
*/
public double getAmpSize(Waveform wf) {
if (wf == null) return getMinAmpSize();
// enforce min amp size
return Math.max(getMinAmpSize(), wf.rangeAmp() * (ampBot - ampTop));
}
/** Return the max amp in the selected window in units native to the Waveform.
* If there is no waveform, returns the minAmpSize.
* @See: Waveform.getAmpUnits() */
public double getTopAmp(Waveform wf) {
if (wf == null) return getMinAmpSize();
return wf.getMaxAmp() - (getTopAmpOffset()*wf.rangeAmp());
}
/** Return the min amp in the selected window in units native to the Waveform.
* If there is no waveform, returns 0.0.
* @See: Waveform.getAmpUnits() */
public double getBottomAmp(Waveform wf) {
if (wf == null) return 0.0;
return wf.getMaxAmp() - (getBottomAmpOffset()*wf.rangeAmp());
}
/** Return the max amp of the selected window as an offset from the top
* of the amp dimension from 0.0 -> 1.0 */
public double getTopAmpOffset() {
return ampTop;
}
/** Return the min amp of the selected window as an offset from the top
* of the amp dimension from 0.0 -> 1.0 */
public double getBottomAmpOffset() {
return ampBot;
}
/**
* Fires a new stateChange event for the currently selected window.
*/
public boolean reset () {
return fireChange();
}
/** Set the window to the minimum allowable size. Fire change event. */
private void setToMinSize(double centerTime, double centerAmp) {
setFireEvents(false); // temporarily suspend change events until finished
setToMinTimeSize(centerTime);
setToMinAmpSize(centerAmp);
setFireEvents(true);
fireChange();
}
/** Set the window to the minimum allowable size. Does not fire change event.*/
private void setToMinTimeSize(double centerTime) {
double halfTime = getMinTime()/2.0;
setAmpSpanAsRatio(centerTime-halfTime, centerTime+halfTime);
}
/** Set the window to the minimum allowable size. Note that the centerAmp is
* a value between 0.0 and 1.0 and NOT in native amp units. Does not fire change event.*/
private void setToMinAmpSize(double centerAmp) {
double halfAmp = getMinAmpSize()/2.0;
setAmpSpanAsRatio(centerAmp+halfAmp, centerAmp-halfAmp);
}
/** Set the amplitude and time window to the size of the WFView. If the WFView has time-series
* that will determine the window. If not the "view" box will be used.
* Does not fire change event. */
/*
public void setFullView (Waveform wf) {
WFSelectionBox box =
new WFSelectionBox(wf.getTimeSpan(), wf.getMaxAmp(), wf.getMinAmp());
setFullView (wf, box);
}
*/
/** Set the amplitude and time window to the size of this Waveform.
* Fire change event. */
public void setFullView (Waveform wf) {
setFireEvents(false);
setFullAmp(); // doesn't need wf because amps are "relative" (0->1)
setFullTime(wf);
setFireEvents(true);
fireChange();
}
/** Set the amplitude and time window to the size of this WFSelectionBox for this
* Waveform.
* Fire change event. */
public void set(Waveform wf, WFSelectionBox box) {
setFireEvents(false);
setAmpSpan(wf, box);
setTimeSpan(wf, box);
setFireEvents(true);
fireChange();
}
/** Set the time window to the size of the WFSelectionBox for this Waveform.
* Fire change event. */
public void setTimeSpan (Waveform wf, WFSelectionBox box) {
// wf is not really used unless box is null
if (box == null || box.isNull()) {
setFullTime (wf);
} else {
setTimeSpan(box.getTimeSpan());
}
}
/** Set the time window to the size of the data for this Waveform.
* Fire change event. */
public void setFullTime (Waveform wf) {
if (wf != null) setTimeSpan(wf.getTimeSpan());
}
/**
* Set the selected window to the full scale of this waveform.
* Returns 'false' if there was no change because the
* new box is the same as the old. If new box is too small, set the selected
* window to the minimum allowable size centered on the new box. <p>
* Same as setFullView().
*/
public boolean set (Waveform wf) {
setFullView (wf);
return true;
}
/** Set the amplitude to full scale.
* Fire change event. */
public void setFullAmp () {
ampTop = 0.0;
ampBot = 1.0;
fireChange();
}
/** Set the amplitude to full scale. The waveform doesn't really matter, this
* form is here for consistency with the other method calls.
* Fire change event. */
public void setFullAmp (Waveform wf) {
setFullAmp();
}
/** Set the amplitude to full scale.
* Fire change event. */
/*
public void setFullAmp (Waveform wf, WFSelectionBox box) {
setFullAmp();
}
*/
/** Set the selected time window.
* If the value of secs is less than getMinTime() sets duration to getMinTime()
* centered on requested timespan.
* Fires change event. */
public void setTimeSpan (double start, double end) {
if ((end-start) < getMinTime()) {
setCenterTime(new TimeSpan(start, end).getCenter(), getMinTime());
} else {
// synchronized (this) {
timeSpan.set(start, end);
fireChange();
// }
}
}
/** Set the selected time window.
* If the value of secs is less than getMinTime() sets duration to getMinTime().
* Fires change event. */
public void setTimeSpan (TimeSpan timeSpan) {
setTimeSpan(timeSpan.getStart(), timeSpan.getEnd());
}
/** Set the selected time window to this duration, in seconds,
* leaving it centered on the current time.
* If the value of secs is less than getMinTime() sets duration to getMinTime().
* Fires change event. */
public void setTimeSpanDuration (double secs) {
setCenterTime(timeSpan.getCenter(), Math.max(secs, getMinTime()));
}
/**
* Center selected box along time axis and fire change evnt. Returns false
* if there was no change, else true.
*/
public boolean setCenterTime (double centerTime) {
double offset = this.timeSpan.getDuration()/2.0;
setTimeSpan(centerTime-offset, centerTime+offset);
/*
if (Math.abs(centerTime - timeSpan.getCenter()) < PRECISION_LIMIT) return false;
synchronized (this) {
timeSpan.setCenter(centerTime);
fireChange();
}
*/
return true;
}
/**
* Center selected box along time axis and fire change event. Returns false
* if there was no change, else true.
*/
public boolean setCenterTime (double centerTime, double duration) {
if (Math.abs(centerTime - getTimeSpan().getCenter()) < PRECISION_LIMIT &&
Math.abs(duration - getTimeSpan().getDuration()) < PRECISION_LIMIT) return false;
synchronized (this) {
timeSpan.setCenter(centerTime, duration);
fireChange();
}
return true;
}
/** Set the bounds of the amp window as a ratio of the window from 0.0 at the
* bottom to 1.0 at the top. */
/* public void setAmpSpan (double top, double bot) {
}
*/
/** Set the bounds of the amp window as a ratio of the window from 0.0 at the
* top to 1.0 at the bottom. */
public void setAmpSpanAsRatio (double topOffset, double botOffset) {
// sanity checks
if (botOffset < topOffset){
System.out.println("Reversed amp ratio values: "+botOffset+" "+topOffset);
return;
}
// enforce legal bounds
if (botOffset < 0.0) botOffset = 0.0;
if (topOffset < 0.0) topOffset = 0.0;
if (botOffset > 1.0) botOffset = 1.0;
if (topOffset > 1.0) topOffset = 1.0;
synchronized (this) {
if ((botOffset - topOffset) >= getMinAmpSize()) {
ampTop = topOffset;
ampBot = botOffset;
} else {
// Check minimums, force to mins if box is too small
setToMinAmpSize(ampBot - ampTop);
}
fireChange();
}
}
/** Set the max and min bounds of the vertical (amp) dimension to
* the max/min values given in the units of the waveform data.
* */
public void setAmpSpan (Waveform wf, double maxAmp, double minAmp) {
if (wf == null) {
setFullAmp();
} else {
// this looks wierd but is correct, both measure "down" from wf.getMaxAmp()
double top = (wf.getMaxAmp() - maxAmp) / wf.rangeAmp();
double bot = (wf.getMaxAmp() - minAmp) / wf.rangeAmp();
setAmpSpanAsRatio(top, bot);
}
}
/** Set the max and min bounds of the vertical (amp) dimension to
* the max/min values given in the units of the waveform data as defined
* in the WFSelectionBox.
* */
public void setAmpSpan (Waveform wf, WFSelectionBox box) {
setAmpSpan(wf, box.getMaxAmp(), box.getMinAmp());
}
/**
* Center the selection box on this amplitude, keep the size of the box the same.
* Returns false if there was no change, else true.
*/
public boolean setCenterAmp (Waveform wf, double centeramp) {
if (wf == null) {
setFullAmp();
return false;
} else {
// use native amp units of wf
double halfspan = getAmpSize(wf)/2.0;
setAmpSpan(wf, centeramp+halfspan, centeramp-halfspan);
return true;
}
}
/** Return the currenly defined WFSelectionBox in the units of this Waveform.
* WFSelectionBox.isNull() is returned if no selection has been made. */
public WFSelectionBox getSelectionBox(Waveform wf) {
if (debug) {
System.out.println("SelWfMod: "+ getTopAmpOffset() + " "+ getBottomAmpOffset());
}
// must clone the box else you pass a reference to the LIVE one.
return new WFSelectionBox(getTimeSpan(), getTopAmp(wf), getBottomAmp(wf));
}
/** Fire a change event for this model if events have not been "turned off".*/
private boolean fireChange() {
if (getFireEvents()) {
synchronized (this) {
fireStateChanged(this);
}
return true;
} else {
return false;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -