2015-01-21 21:58:35 +01:00
|
|
|
/*******************************************************************************
|
2015-10-22 00:25:12 +02:00
|
|
|
* Copyright (c) 2015 MINRES Technologies GmbH and others.
|
2015-01-21 21:58:35 +01:00
|
|
|
* All rights reserved. This program and the accompanying materials
|
|
|
|
* are made available under the terms of the Eclipse Public License v1.0
|
|
|
|
* which accompanies this distribution, and is available at
|
|
|
|
* http://www.eclipse.org/legal/epl-v10.html
|
|
|
|
*
|
|
|
|
* Contributors:
|
|
|
|
* MINRES Technologies GmbH - initial API and implementation
|
|
|
|
*******************************************************************************/
|
2020-07-15 21:42:10 +02:00
|
|
|
package com.minres.scviewer.database.ui.swt.internal;
|
2015-01-20 18:50:15 +01:00
|
|
|
|
2020-11-29 12:42:51 +01:00
|
|
|
import java.util.Arrays;
|
2018-10-11 14:44:41 +02:00
|
|
|
import java.util.Collection;
|
2015-01-20 18:50:15 +01:00
|
|
|
import java.util.Map.Entry;
|
|
|
|
import java.util.NavigableMap;
|
|
|
|
|
2017-01-21 13:13:05 +01:00
|
|
|
import javax.swing.JPanel;
|
|
|
|
|
2015-01-20 18:50:15 +01:00
|
|
|
import org.eclipse.swt.SWT;
|
|
|
|
import org.eclipse.swt.graphics.Color;
|
2017-01-21 13:13:05 +01:00
|
|
|
import org.eclipse.swt.graphics.FontData;
|
2015-01-20 18:50:15 +01:00
|
|
|
import org.eclipse.swt.graphics.GC;
|
2017-01-21 13:13:05 +01:00
|
|
|
import org.eclipse.swt.graphics.Point;
|
2015-01-20 18:50:15 +01:00
|
|
|
import org.eclipse.swt.graphics.Rectangle;
|
|
|
|
|
2018-11-05 18:23:17 +01:00
|
|
|
import com.minres.scviewer.database.BitVector;
|
2020-11-28 14:08:34 +01:00
|
|
|
import com.minres.scviewer.database.DoubleVal;
|
|
|
|
import com.minres.scviewer.database.IEvent;
|
|
|
|
import com.minres.scviewer.database.IWaveform;
|
2015-11-12 23:35:13 +01:00
|
|
|
import com.minres.scviewer.database.ui.TrackEntry;
|
|
|
|
import com.minres.scviewer.database.ui.WaveformColors;
|
2015-01-20 18:50:15 +01:00
|
|
|
|
2017-01-21 13:13:05 +01:00
|
|
|
public class SignalPainter extends TrackPainter {
|
|
|
|
private class SignalChange {
|
|
|
|
long time;
|
2020-11-28 14:08:34 +01:00
|
|
|
IEvent value;
|
2017-01-21 13:13:05 +01:00
|
|
|
boolean fromMap;
|
|
|
|
|
2020-11-28 14:08:34 +01:00
|
|
|
public SignalChange(Entry<Long, IEvent[]> entry) {
|
2017-01-21 13:13:05 +01:00
|
|
|
time = entry.getKey();
|
2020-11-28 14:08:34 +01:00
|
|
|
value = entry.getValue()[0];
|
2017-01-21 13:13:05 +01:00
|
|
|
fromMap = true;
|
|
|
|
}
|
|
|
|
|
2020-11-28 14:08:34 +01:00
|
|
|
public void set(Entry<Long, IEvent[]> entry, Long actTime) {
|
2017-01-21 13:13:05 +01:00
|
|
|
if (entry != null) {
|
|
|
|
time = entry.getKey();
|
2020-11-28 14:08:34 +01:00
|
|
|
value = entry.getValue()[0];
|
2017-01-21 13:13:05 +01:00
|
|
|
fromMap = true;
|
|
|
|
} else {
|
|
|
|
time = actTime;
|
|
|
|
fromMap = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void assign(SignalChange other) {
|
|
|
|
time = other.time;
|
|
|
|
value = other.value;
|
|
|
|
fromMap = other.fromMap;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-20 18:50:15 +01:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
2017-01-21 13:13:05 +01:00
|
|
|
private static final JPanel DUMMY_PANEL = new JPanel();
|
|
|
|
|
2015-01-20 18:50:15 +01:00
|
|
|
private final WaveformCanvas waveCanvas;
|
|
|
|
|
2017-01-21 13:13:05 +01:00
|
|
|
int yOffsetT;
|
|
|
|
int yOffsetM;
|
|
|
|
int yOffsetB;
|
2019-03-17 20:03:22 +01:00
|
|
|
/// maximum visible canvas position in canvas coordinates
|
|
|
|
int maxPosX;
|
|
|
|
/// maximum visible position in waveform coordinates
|
|
|
|
int maxValX;
|
2017-01-21 13:13:05 +01:00
|
|
|
|
2015-11-06 19:29:36 +01:00
|
|
|
public SignalPainter(WaveformCanvas txDisplay, boolean even, TrackEntry trackEntry) {
|
|
|
|
super(trackEntry, even);
|
2015-01-20 18:50:15 +01:00
|
|
|
this.waveCanvas = txDisplay;
|
2017-01-21 13:13:05 +01:00
|
|
|
}
|
|
|
|
|
2019-03-17 20:03:22 +01:00
|
|
|
private int getXPosEnd(long time) {
|
2020-06-20 17:58:26 +02:00
|
|
|
long ltmp = time / this.waveCanvas.getScaleFactor();
|
2019-03-17 20:03:22 +01:00
|
|
|
return ltmp > maxPosX ? maxPosX : (int) ltmp;
|
|
|
|
}
|
|
|
|
|
2020-06-20 17:58:26 +02:00
|
|
|
public void paintArea(Projection proj, Rectangle area) {
|
2020-11-28 14:08:34 +01:00
|
|
|
IWaveform signal = trackEntry.waveform;
|
2017-01-21 13:13:05 +01:00
|
|
|
if (trackEntry.selected)
|
2020-11-28 19:41:00 +01:00
|
|
|
proj.setBackground(this.waveCanvas.styleProvider.getColor(WaveformColors.TRACK_BG_HIGHLITE));
|
2015-01-21 21:58:35 +01:00
|
|
|
else
|
2020-11-28 19:41:00 +01:00
|
|
|
proj.setBackground(this.waveCanvas.styleProvider.getColor(even ? WaveformColors.TRACK_BG_EVEN : WaveformColors.TRACK_BG_ODD));
|
2020-06-20 17:58:26 +02:00
|
|
|
proj.setFillRule(SWT.FILL_EVEN_ODD);
|
|
|
|
proj.fillRectangle(area);
|
2019-03-17 20:03:22 +01:00
|
|
|
|
|
|
|
long scaleFactor = this.waveCanvas.getScaleFactor();
|
|
|
|
long beginPos = area.x;
|
2020-06-20 17:58:26 +02:00
|
|
|
long beginTime = beginPos*scaleFactor;
|
2019-03-17 20:03:22 +01:00
|
|
|
long endTime = beginTime + area.width*scaleFactor;
|
|
|
|
|
2020-11-28 14:08:34 +01:00
|
|
|
Entry<Long, IEvent[]> first = signal.getEvents().floorEntry(beginTime);
|
|
|
|
Entry<Long, IEvent[]> last = signal.getEvents().floorEntry(endTime);
|
2017-01-21 13:13:05 +01:00
|
|
|
if (first == null) {
|
|
|
|
if (last == null)
|
|
|
|
return;
|
|
|
|
first = signal.getEvents().firstEntry();
|
|
|
|
} else if (last == null) {
|
|
|
|
last = signal.getEvents().lastEntry();
|
2015-01-20 18:50:15 +01:00
|
|
|
}
|
2020-11-28 19:41:00 +01:00
|
|
|
proj.setForeground(this.waveCanvas.styleProvider.getColor(WaveformColors.LINE));
|
2020-06-20 17:58:26 +02:00
|
|
|
proj.setLineStyle(SWT.LINE_SOLID);
|
|
|
|
proj.setLineWidth(1);
|
2020-11-28 14:08:34 +01:00
|
|
|
NavigableMap<Long, IEvent[]> entries = signal.getEvents().subMap(first.getKey(), false, last.getKey(), true);
|
2017-01-21 13:13:05 +01:00
|
|
|
SignalChange left = new SignalChange(first);
|
|
|
|
SignalChange right = new SignalChange(entries.size() > 0 ? entries.firstEntry() : first);
|
2019-03-17 20:03:22 +01:00
|
|
|
maxPosX = area.x + area.width;
|
2020-11-28 19:41:00 +01:00
|
|
|
yOffsetT = this.waveCanvas.styleProvider.getTrackHeight() / 5 + area.y;
|
|
|
|
yOffsetM = this.waveCanvas.styleProvider.getTrackHeight() / 2 + area.y;
|
|
|
|
yOffsetB = 4 * this.waveCanvas.styleProvider.getTrackHeight() / 5 + area.y;
|
2020-06-20 17:58:26 +02:00
|
|
|
int xSigChangeBeginVal = Math.max(area.x, (int) (left.time / this.waveCanvas.getScaleFactor()));
|
2019-03-17 20:03:22 +01:00
|
|
|
int xSigChangeBeginPos = area.x;
|
|
|
|
int xSigChangeEndPos = Math.max(area.x, getXPosEnd(right.time));
|
|
|
|
|
2017-01-21 13:13:05 +01:00
|
|
|
boolean multiple = false;
|
2019-03-17 20:03:22 +01:00
|
|
|
if (xSigChangeEndPos == xSigChangeBeginPos) {
|
2017-01-21 13:13:05 +01:00
|
|
|
// this can trigger if
|
|
|
|
// a) left == right
|
|
|
|
// b) left to close to right
|
|
|
|
if (left.time == right.time) {
|
|
|
|
right.time = endTime;
|
|
|
|
} else {
|
|
|
|
multiple = true;
|
2019-03-17 20:03:22 +01:00
|
|
|
long eTime = (xSigChangeBeginVal + 1) * this.waveCanvas.getScaleFactor();
|
2017-01-21 13:13:05 +01:00
|
|
|
right.set(entries.floorEntry(eTime), endTime);
|
|
|
|
right.time = eTime;
|
2015-01-20 18:50:15 +01:00
|
|
|
}
|
2019-03-17 20:03:22 +01:00
|
|
|
xSigChangeEndPos = getXPosEnd(right.time);
|
2017-01-21 13:13:05 +01:00
|
|
|
}
|
|
|
|
|
2019-03-17 20:03:22 +01:00
|
|
|
|
2020-06-20 17:58:26 +02:00
|
|
|
SignalStencil stencil = getStencil(proj.getGC(), left, entries);
|
2020-11-29 12:42:51 +01:00
|
|
|
if(stencil!=null) do {
|
2020-06-20 17:58:26 +02:00
|
|
|
stencil.draw(proj, area, left.value, right.value, xSigChangeBeginPos, xSigChangeEndPos, multiple);
|
2017-01-21 13:13:05 +01:00
|
|
|
if (right.time >= endTime)
|
|
|
|
break;
|
|
|
|
left.assign(right);
|
2019-03-17 20:03:22 +01:00
|
|
|
xSigChangeBeginPos = xSigChangeEndPos;
|
2017-01-21 13:13:05 +01:00
|
|
|
right.set(entries.higherEntry(left.time), endTime);
|
2019-03-17 20:03:22 +01:00
|
|
|
xSigChangeEndPos = getXPosEnd(right.time);
|
2017-01-21 13:13:05 +01:00
|
|
|
multiple = false;
|
2019-03-17 20:03:22 +01:00
|
|
|
if (xSigChangeEndPos == xSigChangeBeginPos) {
|
2017-01-21 13:13:05 +01:00
|
|
|
multiple = true;
|
2019-03-17 20:03:22 +01:00
|
|
|
long eTime = (xSigChangeBeginPos + 1) * this.waveCanvas.getScaleFactor();
|
2020-11-28 14:08:34 +01:00
|
|
|
Entry<Long, IEvent[]> entry = entries.floorEntry(eTime);
|
2018-08-27 16:27:11 +02:00
|
|
|
if(entry!=null && entry.getKey()> right.time)
|
|
|
|
right.set(entry, endTime);
|
2019-03-17 20:03:22 +01:00
|
|
|
xSigChangeEndPos = getXPosEnd(eTime);
|
2017-01-21 13:13:05 +01:00
|
|
|
}
|
|
|
|
} while (left.time < endTime);
|
|
|
|
}
|
|
|
|
|
2020-11-28 14:08:34 +01:00
|
|
|
private SignalStencil getStencil(GC gc, SignalChange left, NavigableMap<Long, IEvent[]> entries) {
|
|
|
|
IEvent val = left.value;
|
2018-11-05 18:23:17 +01:00
|
|
|
if(val instanceof BitVector) {
|
|
|
|
BitVector bv = (BitVector) val;
|
|
|
|
if(bv.getWidth()==1)
|
|
|
|
return new SingleBitStencil();
|
2018-10-14 08:59:17 +02:00
|
|
|
if(trackEntry.waveDisplay==TrackEntry.WaveDisplay.DEFAULT)
|
|
|
|
return new MultiBitStencil(gc);
|
|
|
|
else
|
|
|
|
return new MultiBitStencilAnalog(entries, left.value,
|
|
|
|
trackEntry.waveDisplay==TrackEntry.WaveDisplay.CONTINOUS,
|
|
|
|
trackEntry.valueDisplay==TrackEntry.ValueDisplay.SIGNED);
|
2020-11-28 14:08:34 +01:00
|
|
|
} else if (val instanceof DoubleVal)
|
2018-10-14 08:59:17 +02:00
|
|
|
return new RealStencil(entries, left.value, trackEntry.waveDisplay==TrackEntry.WaveDisplay.CONTINOUS);
|
2018-10-11 14:44:41 +02:00
|
|
|
else
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2017-01-21 13:13:05 +01:00
|
|
|
private interface SignalStencil {
|
|
|
|
|
2020-11-28 14:08:34 +01:00
|
|
|
public void draw(Projection proj, Rectangle area, IEvent left, IEvent right, int xBegin, int xEnd, boolean multiple);
|
2017-01-21 13:13:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private class MultiBitStencil implements SignalStencil {
|
|
|
|
|
|
|
|
private java.awt.Font tmpAwtFont;
|
|
|
|
private int height;
|
|
|
|
|
|
|
|
public MultiBitStencil(GC gc) {
|
|
|
|
FontData fd = gc.getFont().getFontData()[0];
|
|
|
|
height = gc.getDevice().getDPI().y * fd.getHeight() / 72;
|
|
|
|
tmpAwtFont = new java.awt.Font(fd.getName(), fd.getStyle(), height);
|
|
|
|
}
|
|
|
|
|
2020-11-28 14:08:34 +01:00
|
|
|
public void draw(Projection proj, Rectangle area, IEvent left, IEvent right, int xBegin, int xEnd, boolean multiple) {
|
2020-11-28 19:41:00 +01:00
|
|
|
Color colorBorder = waveCanvas.styleProvider.getColor(WaveformColors.SIGNAL0);
|
2018-11-05 18:23:17 +01:00
|
|
|
BitVector last = (BitVector) left;
|
2020-11-29 12:42:51 +01:00
|
|
|
if (Arrays.toString(last.getValue()).contains("X")) {
|
2020-11-28 19:41:00 +01:00
|
|
|
colorBorder = waveCanvas.styleProvider.getColor(WaveformColors.SIGNALX);
|
2020-11-29 12:42:51 +01:00
|
|
|
} else if (Arrays.toString(last.getValue()).contains("Z")) {
|
2020-11-28 19:41:00 +01:00
|
|
|
colorBorder = waveCanvas.styleProvider.getColor(WaveformColors.SIGNALZ);
|
2017-01-21 13:13:05 +01:00
|
|
|
}
|
|
|
|
int width = xEnd - xBegin;
|
|
|
|
if (width > 1) {
|
|
|
|
int[] points = {
|
|
|
|
xBegin, yOffsetM,
|
|
|
|
xBegin + 1, yOffsetT,
|
|
|
|
xEnd - 1, yOffsetT,
|
|
|
|
xEnd, yOffsetM,
|
|
|
|
xEnd - 1, yOffsetB,
|
|
|
|
xBegin + 1, yOffsetB
|
2015-01-20 18:50:15 +01:00
|
|
|
};
|
2020-06-20 17:58:26 +02:00
|
|
|
proj.setForeground(colorBorder);
|
|
|
|
proj.drawPolygon(points);
|
2020-11-28 19:41:00 +01:00
|
|
|
proj.setForeground(waveCanvas.styleProvider.getColor(WaveformColors.SIGNAL_TEXT));
|
2018-10-14 08:59:17 +02:00
|
|
|
String label = null;
|
|
|
|
switch(trackEntry.valueDisplay) {
|
|
|
|
case SIGNED:
|
2018-11-05 18:23:17 +01:00
|
|
|
label=Long.toString(last.toSignedValue());
|
2018-10-14 08:59:17 +02:00
|
|
|
break;
|
|
|
|
case UNSIGNED:
|
2018-11-05 18:23:17 +01:00
|
|
|
label=Long.toString(last.toUnsignedValue());
|
2018-10-14 08:59:17 +02:00
|
|
|
break;
|
|
|
|
default:
|
2018-11-05 18:23:17 +01:00
|
|
|
label="h'"+last.toHexString();
|
2018-10-14 08:59:17 +02:00
|
|
|
}
|
2020-06-20 17:58:26 +02:00
|
|
|
Point bb = new Point(DUMMY_PANEL.getFontMetrics(tmpAwtFont).stringWidth(label), height);
|
2017-01-21 13:13:05 +01:00
|
|
|
if (xBegin < area.x) {
|
|
|
|
xBegin = area.x;
|
|
|
|
width = xEnd - xBegin;
|
|
|
|
}
|
|
|
|
if (width > (bb.x+1)) {
|
2020-06-20 17:58:26 +02:00
|
|
|
Rectangle old = proj.getClipping();
|
|
|
|
proj.setClipping(xBegin + 3, yOffsetT, xEnd - xBegin - 5, yOffsetB - yOffsetT);
|
|
|
|
proj.drawText(label, xBegin + 3, yOffsetM - bb.y / 2 - 1);
|
|
|
|
proj.setClipping(old);
|
2015-01-20 18:50:15 +01:00
|
|
|
}
|
2017-01-21 13:13:05 +01:00
|
|
|
} else {
|
2020-06-20 17:58:26 +02:00
|
|
|
proj.setForeground(colorBorder);
|
|
|
|
proj.drawLine(xEnd, yOffsetT, xEnd, yOffsetB);
|
2015-01-20 18:50:15 +01:00
|
|
|
}
|
|
|
|
}
|
2017-01-21 13:13:05 +01:00
|
|
|
|
2015-01-20 18:50:15 +01:00
|
|
|
}
|
|
|
|
|
2018-10-14 08:59:17 +02:00
|
|
|
private class MultiBitStencilAnalog implements SignalStencil {
|
|
|
|
|
|
|
|
final boolean continous;
|
2020-11-28 19:41:00 +01:00
|
|
|
final boolean signed;
|
|
|
|
private long maxVal;
|
2018-10-14 08:59:17 +02:00
|
|
|
private long minVal;
|
2020-07-11 19:36:45 +02:00
|
|
|
double yRange = (yOffsetB-yOffsetT);
|
2020-11-28 14:08:34 +01:00
|
|
|
public MultiBitStencilAnalog(NavigableMap<Long, IEvent[]> entries, Object left, boolean continous, boolean signed) {
|
2018-10-14 08:59:17 +02:00
|
|
|
this.continous=continous;
|
2020-11-28 19:41:00 +01:00
|
|
|
this.signed=signed;
|
2020-11-28 14:08:34 +01:00
|
|
|
Collection<IEvent[]> values = entries.values();
|
2020-11-28 19:41:00 +01:00
|
|
|
minVal=signed?((BitVector)left).toSignedValue():((BitVector)left).toUnsignedValue();
|
2018-10-14 08:59:17 +02:00
|
|
|
if(!values.isEmpty()) {
|
2020-11-28 19:41:00 +01:00
|
|
|
maxVal=minVal;
|
2020-11-28 14:08:34 +01:00
|
|
|
for (IEvent[] tp : entries.values())
|
|
|
|
for(IEvent e: tp) {
|
2020-11-28 19:41:00 +01:00
|
|
|
long v = signed?((BitVector)e).toSignedValue():((BitVector)e).toUnsignedValue();
|
2020-11-28 14:08:34 +01:00
|
|
|
maxVal=Math.max(maxVal, v);
|
|
|
|
minVal=Math.min(minVal, v);
|
|
|
|
}
|
2018-10-14 08:59:17 +02:00
|
|
|
if(maxVal==minVal) {
|
|
|
|
maxVal--;
|
|
|
|
minVal++;
|
|
|
|
}
|
2020-11-28 19:41:00 +01:00
|
|
|
} else {
|
2018-10-14 08:59:17 +02:00
|
|
|
minVal--;
|
2020-11-28 19:41:00 +01:00
|
|
|
maxVal=minVal+2;
|
|
|
|
}
|
2018-10-14 08:59:17 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-11-28 14:08:34 +01:00
|
|
|
public void draw(Projection proj, Rectangle area, IEvent left, IEvent right, int xBegin, int xEnd, boolean multiple) {
|
2020-11-28 19:41:00 +01:00
|
|
|
long leftVal = signed?((BitVector)left).toSignedValue():((BitVector)left).toUnsignedValue();
|
|
|
|
long rightVal= signed?((BitVector)right).toSignedValue():((BitVector)right).toUnsignedValue();
|
|
|
|
proj.setForeground(waveCanvas.styleProvider.getColor(WaveformColors.SIGNAL_REAL));
|
|
|
|
long range = maxVal-minVal;
|
2020-07-11 19:36:45 +02:00
|
|
|
int yOffsetLeft = (int) ((leftVal-minVal) * yRange / range);
|
|
|
|
int yOffsetRight = (int) ((rightVal-minVal) * yRange / range);
|
2018-10-14 08:59:17 +02:00
|
|
|
if(continous) {
|
2019-03-17 20:03:22 +01:00
|
|
|
if (xEnd > maxPosX) {
|
2020-06-20 17:58:26 +02:00
|
|
|
proj.drawLine(xBegin, yOffsetB-yOffsetLeft, maxPosX, yOffsetB-yOffsetRight);
|
2018-10-14 08:59:17 +02:00
|
|
|
} else {
|
2020-06-20 17:58:26 +02:00
|
|
|
proj.drawLine(xBegin, yOffsetB-yOffsetLeft, xEnd, yOffsetB-yOffsetRight);
|
2018-10-14 08:59:17 +02:00
|
|
|
}
|
|
|
|
} else {
|
2019-03-17 20:03:22 +01:00
|
|
|
if (xEnd > maxPosX) {
|
2020-06-20 17:58:26 +02:00
|
|
|
proj.drawLine(xBegin, yOffsetB-yOffsetLeft, maxPosX, yOffsetB-yOffsetLeft);
|
2018-10-14 08:59:17 +02:00
|
|
|
} else {
|
2020-06-20 17:58:26 +02:00
|
|
|
proj.drawLine(xBegin, yOffsetB-yOffsetLeft, xEnd, yOffsetB-yOffsetLeft);
|
2018-10-14 08:59:17 +02:00
|
|
|
if(yOffsetRight!=yOffsetLeft) {
|
2020-06-20 17:58:26 +02:00
|
|
|
proj.drawLine(xEnd, yOffsetB-yOffsetLeft, xEnd, yOffsetB-yOffsetRight);
|
2018-10-14 08:59:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-21 13:13:05 +01:00
|
|
|
private class SingleBitStencil implements SignalStencil {
|
2020-11-28 14:08:34 +01:00
|
|
|
public void draw(Projection proj, Rectangle area, IEvent left, IEvent right, int xBegin, int xEnd, boolean multiple) {
|
2017-01-21 13:13:05 +01:00
|
|
|
if (multiple) {
|
2020-11-28 19:41:00 +01:00
|
|
|
proj.setForeground(waveCanvas.styleProvider.getColor(WaveformColors.SIGNALU));
|
2020-06-20 17:58:26 +02:00
|
|
|
proj.drawLine(xBegin, yOffsetT, xBegin, yOffsetB);
|
2018-10-11 14:44:41 +02:00
|
|
|
if(xEnd>xBegin)
|
2020-06-20 17:58:26 +02:00
|
|
|
proj.drawLine(xEnd, yOffsetT, xEnd, yOffsetB);
|
2017-01-21 13:13:05 +01:00
|
|
|
} else {
|
2020-11-28 19:41:00 +01:00
|
|
|
Color color = waveCanvas.styleProvider.getColor(WaveformColors.SIGNALX);
|
2017-01-21 13:13:05 +01:00
|
|
|
int yOffset = yOffsetM;
|
2018-11-05 18:23:17 +01:00
|
|
|
switch (((BitVector) left).getValue()[0]) {
|
2017-01-21 13:13:05 +01:00
|
|
|
case '1':
|
2020-11-28 19:41:00 +01:00
|
|
|
color = waveCanvas.styleProvider.getColor(WaveformColors.SIGNAL1);
|
2017-01-21 13:13:05 +01:00
|
|
|
yOffset = yOffsetT;
|
|
|
|
break;
|
|
|
|
case '0':
|
2020-11-28 19:41:00 +01:00
|
|
|
color = waveCanvas.styleProvider.getColor(WaveformColors.SIGNAL0);
|
2017-01-21 13:13:05 +01:00
|
|
|
yOffset = yOffsetB;
|
|
|
|
break;
|
|
|
|
case 'Z':
|
2020-11-28 19:41:00 +01:00
|
|
|
color = waveCanvas.styleProvider.getColor(WaveformColors.SIGNALZ);
|
2017-01-21 13:13:05 +01:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
}
|
2020-06-20 17:58:26 +02:00
|
|
|
proj.setForeground(color);
|
2019-03-17 20:03:22 +01:00
|
|
|
if (xEnd > maxPosX) {
|
2020-06-20 17:58:26 +02:00
|
|
|
proj.drawLine(xBegin, yOffset, maxPosX, yOffset);
|
2017-01-21 13:13:05 +01:00
|
|
|
} else {
|
2020-06-20 17:58:26 +02:00
|
|
|
proj.drawLine(xBegin, yOffset, xEnd, yOffset);
|
2017-01-21 13:13:05 +01:00
|
|
|
int yNext = yOffsetM;
|
2018-11-05 18:23:17 +01:00
|
|
|
switch (((BitVector) right).getValue()[0]) {
|
2017-01-21 13:13:05 +01:00
|
|
|
case '1':
|
|
|
|
yNext = yOffsetT;
|
|
|
|
break;
|
|
|
|
case '0':
|
|
|
|
yNext = yOffsetB;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
if (yOffset != yNext)
|
2020-06-20 17:58:26 +02:00
|
|
|
proj.drawLine(xEnd, yOffset, xEnd, yNext);
|
2017-01-21 13:13:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-01-20 18:50:15 +01:00
|
|
|
|
2018-10-11 14:44:41 +02:00
|
|
|
private class RealStencil implements SignalStencil {
|
|
|
|
|
2020-11-29 12:42:51 +01:00
|
|
|
double minVal;
|
|
|
|
double range;
|
2018-10-11 14:44:41 +02:00
|
|
|
|
|
|
|
final double scaleFactor = 1.05;
|
|
|
|
|
2018-10-14 08:59:17 +02:00
|
|
|
boolean continous=true;
|
2018-10-11 14:44:41 +02:00
|
|
|
|
2020-11-28 14:08:34 +01:00
|
|
|
public RealStencil(NavigableMap<Long, IEvent[]> entries, Object left, boolean continous) {
|
2018-10-14 08:59:17 +02:00
|
|
|
this.continous=continous;
|
2020-11-29 12:42:51 +01:00
|
|
|
Collection<IEvent[]> values = entries.values();
|
2018-11-05 18:23:17 +01:00
|
|
|
minVal=(Double) left;
|
2018-10-11 14:44:41 +02:00
|
|
|
range=2.0;
|
|
|
|
if(!values.isEmpty()) {
|
|
|
|
double maxVal=minVal;
|
2020-11-29 12:42:51 +01:00
|
|
|
for (IEvent[] val : entries.values())
|
|
|
|
for(IEvent e:val) {
|
|
|
|
double v = ((DoubleVal)e).value;
|
|
|
|
if(Double.isNaN(maxVal))
|
|
|
|
maxVal=v;
|
|
|
|
else if(!Double.isNaN(v))
|
|
|
|
maxVal=Math.max(maxVal, v);
|
|
|
|
if(Double.isNaN(minVal))
|
|
|
|
minVal=v;
|
|
|
|
else if(!Double.isNaN(v))
|
|
|
|
minVal=Math.min(minVal, v);
|
|
|
|
}
|
2018-10-14 08:59:17 +02:00
|
|
|
if(Double.isNaN(maxVal)){
|
|
|
|
maxVal=minVal=0.0;
|
2018-10-11 14:44:41 +02:00
|
|
|
}
|
|
|
|
range = (maxVal-minVal)*scaleFactor;
|
|
|
|
double avg = (maxVal+minVal)/2.0;
|
|
|
|
minVal=avg-(avg-minVal)*scaleFactor;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-28 14:08:34 +01:00
|
|
|
public void draw(Projection proj, Rectangle area, IEvent left, IEvent right, int xBegin, int xEnd, boolean multiple) {
|
|
|
|
double leftVal = ((DoubleVal) left).value;
|
|
|
|
double rightVal= ((DoubleVal) right).value;
|
2018-10-14 08:59:17 +02:00
|
|
|
if(Double.isNaN(leftVal)) {
|
2020-11-28 19:41:00 +01:00
|
|
|
Color color = waveCanvas.styleProvider.getColor(WaveformColors.SIGNAL_NAN);
|
2018-10-14 08:59:17 +02:00
|
|
|
int width = xEnd - xBegin;
|
|
|
|
if (width > 1) {
|
|
|
|
int[] points = {
|
|
|
|
xBegin, yOffsetT,
|
|
|
|
xEnd, yOffsetT,
|
|
|
|
xEnd, yOffsetB,
|
|
|
|
xBegin, yOffsetB
|
|
|
|
};
|
2020-06-20 17:58:26 +02:00
|
|
|
proj.setForeground(color);
|
|
|
|
proj.drawPolygon(points);
|
|
|
|
proj.setBackground(color);
|
|
|
|
proj.fillPolygon(points);
|
2018-10-11 14:44:41 +02:00
|
|
|
} else {
|
2020-06-20 17:58:26 +02:00
|
|
|
proj.setForeground(color);
|
|
|
|
proj.drawLine(xEnd, yOffsetT, xEnd, yOffsetB);
|
2018-10-11 14:44:41 +02:00
|
|
|
}
|
2018-10-14 08:59:17 +02:00
|
|
|
} else {
|
2020-11-28 19:41:00 +01:00
|
|
|
proj.setForeground(waveCanvas.styleProvider.getColor(WaveformColors.SIGNAL_REAL));
|
2020-07-11 19:36:45 +02:00
|
|
|
int yOffsetLeft = (int) ((leftVal-minVal) * (yOffsetB-yOffsetT) / range);
|
|
|
|
int yOffsetRight = Double.isNaN(rightVal)?yOffsetLeft:(int) ((rightVal-minVal) * (yOffsetB-yOffsetT) / range);
|
2018-10-14 08:59:17 +02:00
|
|
|
if(continous) {
|
2019-03-17 20:03:22 +01:00
|
|
|
if (xEnd > maxPosX) {
|
2020-06-20 17:58:26 +02:00
|
|
|
proj.drawLine(xBegin, yOffsetB-yOffsetLeft, maxPosX, yOffsetB-yOffsetRight);
|
2018-10-14 08:59:17 +02:00
|
|
|
} else {
|
2020-06-20 17:58:26 +02:00
|
|
|
proj.drawLine(xBegin, yOffsetB-yOffsetLeft, xEnd, yOffsetB-yOffsetRight);
|
2018-10-14 08:59:17 +02:00
|
|
|
}
|
2018-10-11 14:44:41 +02:00
|
|
|
} else {
|
2019-03-17 20:03:22 +01:00
|
|
|
if (xEnd > maxPosX) {
|
2020-06-20 17:58:26 +02:00
|
|
|
proj.drawLine(xBegin, yOffsetB-yOffsetLeft, maxPosX, yOffsetB-yOffsetLeft);
|
2018-10-14 08:59:17 +02:00
|
|
|
} else {
|
2020-06-20 17:58:26 +02:00
|
|
|
proj.drawLine(xBegin, yOffsetB-yOffsetLeft, xEnd, yOffsetB-yOffsetLeft);
|
2018-10-14 08:59:17 +02:00
|
|
|
if(yOffsetRight!=yOffsetLeft) {
|
2020-06-20 17:58:26 +02:00
|
|
|
proj.drawLine(xEnd, yOffsetB-yOffsetLeft, xEnd, yOffsetB-yOffsetRight);
|
2018-10-14 08:59:17 +02:00
|
|
|
}
|
|
|
|
}
|
2018-10-11 14:44:41 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|