5858import org .signalml .domain .signal .raw .RawSignalSampleSource ;
5959import org .signalml .domain .signal .samplesource .MultichannelSampleSource ;
6060import org .signalml .domain .signal .samplesource .OriginalMultichannelSampleSource ;
61+ import org .signalml .domain .tag .MonitorTag ;
6162import org .signalml .domain .tag .StyledTagSet ;
6263import org .signalml .domain .tag .TagDifference ;
6364import org .signalml .domain .tag .TagDifferenceSet ;
@@ -179,6 +180,9 @@ public class SignalPlot extends JComponent implements PropertyChangeListener, Ch
179180 private int horizontalPixelLead ;
180181 private int verticalPixelLead ;
181182
183+ /** used for static (non-scrolling) rendering of on-line signal tags */
184+ private final StaticRenderingHelper staticRendering ;
185+
182186 private boolean compensationEnabled = true ;
183187 private boolean ignoreSliderEvents = false ;
184188
@@ -214,8 +218,9 @@ public SignalPlot(SignalDocument document, SignalView view, SignalPlot masterPlo
214218 setBackground (Color .WHITE );
215219 setFocusable (true );
216220
217- if (document .getSampleSource () instanceof RawSignalSampleSource ) {
218- double timestamp = ((RawSignalSampleSource ) document .getSampleSource ()).getFirstSampleTimestamp ();
221+ OriginalMultichannelSampleSource sampleSource = document .getSampleSource ();
222+ if (sampleSource instanceof RawSignalSampleSource ) {
223+ double timestamp = ((RawSignalSampleSource ) sampleSource ).getFirstSampleTimestamp ();
219224 firstSampleTimestamp = Math .round (timestamp );
220225 } else {
221226 firstSampleTimestamp = 0 ;
@@ -328,8 +333,15 @@ private void maybeShowPopupMenu(MouseEvent e) {
328333
329334 });
330335 if (document instanceof MonitorSignalDocument ) {
336+ if (!config .isScrollingMode ()) {
337+ staticRendering = new StaticRenderingHelper (sampleSource .getChannelCount (), sampleSource .getSampleCount (0 ), sampleSource .getSamplingFrequency ());
338+ } else {
339+ staticRendering = null ;
340+ }
331341 //for online signals renderrer should know that it's online
332342 renderer .setOnline (true );
343+ } else {
344+ staticRendering = null ;
333345 }
334346
335347 }
@@ -832,6 +844,16 @@ protected void paintComponent(Graphics gOrig) {
832844 int clipEndX = clip .x + clip .width - 1 ;
833845 int clipEndY = clip .y + clip .height - 1 ;
834846
847+ if (staticRendering != null ) try {
848+ // pre-fetching data and updating rendering state
849+ // to avoid mismatch between signal and tags
850+ staticRendering .fetchSamples (signalChain );
851+ } catch (RuntimeException ex ) {
852+ logger .error ("failed to read samples in static rendering mode" , ex );
853+ setVisible (false );
854+ throw ex ;
855+ }
856+
835857 prepareToPaintTags ();
836858
837859 PositionedTag tagSelection = view .getTagSelection (this );
@@ -918,10 +940,8 @@ protected void paintComponent(Graphics gOrig) {
918940 }
919941
920942 visibleCount = 0 ;
921- channel = startChannel ;
922- while (visibleCount < maxNumberOfChannels && channel < channelCount ) {
943+ for (channel =startChannel ; visibleCount < maxNumberOfChannels && channel < channelCount ; ++channel ) {
923944 if (!isChannelVisible (channel )) {
924- channel ++;
925945 continue ;
926946 }
927947 visibleCount ++;
@@ -938,8 +958,12 @@ protected void paintComponent(Graphics gOrig) {
938958 }
939959
940960 try {
941-
942- signalChain .getSamples (channel , samples , firstSample , length , 0 );
961+ if (staticRendering != null ) {
962+ int samplesMargin = (int ) (10 / timeZoomFactor ); // 10 pixels
963+ staticRendering .getSamples (samplesMargin , channel , samples , firstSample , length );
964+ } else {
965+ signalChain .getSamples (channel , samples , firstSample , length , 0 );
966+ }
943967 } catch (RuntimeException ex ) {
944968 logger .error (format ("failed to read %d samples starting at %d, till %d, channel %d" ,
945969 length , firstSample , lastSample , sampleCount [channel ]));
@@ -954,8 +978,6 @@ protected void paintComponent(Graphics gOrig) {
954978 channelLevel [channel ], timeZoomFactor , pixelPerValueForChannel ,
955979 clamped ? clampLimit : null , dcOffsetRemoved
956980 );
957-
958- channel ++;
959981 }
960982
961983 if (signalXOR ) {
@@ -1472,14 +1494,23 @@ public int toChannelSpace(Point p) {
14721494 return channel + numberOfInvisibleChannels ;
14731495 }
14741496
1497+ TagTiming computeTagTiming (SignalSelection tag ) {
1498+ if (staticRendering != null && (tag instanceof MonitorTag )) {
1499+ return staticRendering .computeTagTiming ((MonitorTag ) tag );
1500+ } else {
1501+ return new TagTiming (tag .getPosition (), tag .getLength ());
1502+ }
1503+ }
1504+
14751505 public Rectangle getPixelSelectionBounds (SignalSelection selection , Rectangle useRect ) {
14761506
1477- double position = selection .getPosition ();
1478- double length = selection .getLength ();
1507+ TagTiming timing = computeTagTiming (selection );
1508+ final double position = timing .position ;
1509+ final double length = timing .length ;
14791510 SignalSelectionType type = selection .getType ();
14801511
1481- int selLeft = (int ) Math .floor (selection . getPosition () * pixelPerSecond );
1482- int selRight = (int ) Math .ceil (selection . getLength ( ) * pixelPerSecond );
1512+ int selLeft = (int ) Math .floor (position * pixelPerSecond );
1513+ int selRight = (int ) Math .ceil (( position + length ) * pixelPerSecond );
14831514 int selTop ;
14841515 int selBottom ;
14851516
@@ -1528,7 +1559,7 @@ public Rectangle getPixelBlockTagBounds(SignalSelection tag, boolean marker, int
15281559 Rectangle rect = getTagSelectionRectangle (tag , marker , tagCnt , useRect );
15291560
15301561 if (rect .x > 0 && blockLinesVisible && pixelPerBlock > 4 ) {
1531- int linePosition = (int ) ((int ) ((tag . getPosition () / blockSize )) * pixelPerBlock );
1562+ int linePosition = (int ) ((int ) ((computeTagTiming ( tag ). position / blockSize )) * pixelPerBlock );
15321563 if (linePosition == rect .x ) {
15331564 rect .x ++; // block tags are drawn only inside the block
15341565 }
@@ -1577,6 +1608,9 @@ public Rectangle getTagSelectionRectangle(SignalSelection tag, boolean marker, i
15771608 rect = useRect ;
15781609 }
15791610
1611+ TagTiming timing = computeTagTiming (tag );
1612+ double position = timing .position ;
1613+ double length = timing .length ;
15801614 if (marker ) {
15811615
15821616 int rWidth = pixelPerChannel / (3 * tagCnt ); // 1/3 of the height for this tag
@@ -1585,12 +1619,12 @@ public Rectangle getTagSelectionRectangle(SignalSelection tag, boolean marker, i
15851619 } else if (rWidth < 5 ) {
15861620 rWidth = 5 ;
15871621 }
1588- rect .x = (int ) (tag . getPosition () * pixelPerSecond ) - rWidth / 2 ;
1622+ rect .x = (int ) (position * pixelPerSecond ) - rWidth / 2 ;
15891623 rect .width = rWidth ;
15901624
15911625 } else {
1592- rect .x = (int ) (tag . getPosition () * pixelPerSecond );
1593- rect .width = (int ) (tag . getLength () * pixelPerSecond );
1626+ rect .x = (int ) (position * pixelPerSecond );
1627+ rect .width = (int ) (length * pixelPerSecond );
15941628 }
15951629
15961630 return rect ;
@@ -1797,7 +1831,7 @@ public SignalSelection getChannelSelection(float fromPosition, float toPosition,
17971831 */
17981832 protected SignalSelection transformToMarkerSelection (SignalSelection selection ) {
17991833
1800- double startPosition = selection . getPosition () ;
1834+ double startPosition = computeTagTiming ( selection ). position ;
18011835 int sampleAtPoint = (int ) (startPosition * samplingFrequency );
18021836 float newStartPosition = sampleAtPoint / samplingFrequency ;
18031837
@@ -2039,23 +2073,26 @@ public ArrayList<PositionedTag> getTagsAtPoint(Point point, ArrayList<Positioned
20392073 continue ;
20402074 }
20412075
2076+ TagTiming timing = computeTagTiming (tag );
2077+ double position = timing .position ;
2078+ double length = timing .length ;
20422079 if (tag .getStyle ().getType () == SignalSelectionType .BLOCK ) {
2043- if (time >= tag . getPosition () && time < ( tag . getPosition () + tag . getLength ()) ) {
2080+ if (time >= position && time < position + length ) {
20442081 tagBounds = getPixelBlockTagBounds (tag , tag .isMarker (), tagCnt , cnt , viewportPoint , viewportSize , plotSize , comparing , tempBounds );
20452082 if (tagBounds .contains (point )) {
20462083 list .add (new PositionedTag (tag , tagIndex ));
20472084 }
20482085 }
20492086 } else if (tag .getStyle ().getType () == SignalSelectionType .CHANNEL ) {
20502087 if (tag .getChannel () == channel ) {
2051- if (tag .isMarker () || (time >= tag . getPosition () && time < tag . getEndPosition () )) {
2088+ if (tag .isMarker () || (time >= position && time < position + length )) {
20522089 tagBounds = getPixelChannelTagBoundsInChannel (tag , tag .isMarker (), tagCnt , cnt , viewChannel , comparing , tempBounds );
20532090 if (tagBounds .contains (point )) {
20542091 list .add (new PositionedTag (tag , tagIndex ));
20552092 }
20562093 }
20572094 } else if (tag .getChannel () == Tag .CHANNEL_NULL ) {
2058- if (tag .isMarker () || (time >= tag . getPosition () && time < ( tag . getPosition () + tag . getLength ()) )) {
2095+ if (tag .isMarker () || (time >= position && time < position + length )) {
20592096 tagBounds = getPixelBlockTagBounds (tag , tag .isMarker (), tagCnt , cnt , viewportPoint , viewportSize , plotSize , comparing , tempBounds );
20602097 if (tagBounds .contains (point )) {
20612098 list .add (new PositionedTag (tag , tagIndex ));
0 commit comments