using std::deque;
using std::div;
using std::div_t;
-using std::isnan;
+// Note that "using std::isnan;" is _not_ put here since that would break
+// compilation on some platforms. Use "std::isnan()" instead in checks below.
using std::max;
using std::make_pair;
using std::min;
using std::shared_ptr;
using std::vector;
+using pv::data::LogicSegment;
using pv::data::SignalBase;
using pv::util::SIPrefix;
shared_ptr<data::SignalBase> base) :
Signal(session, base),
scale_index_(4), // 20 per div
- scale_index_drag_offset_(0),
pos_vdivs_(1),
neg_vdivs_(1),
resolution_(0),
display_type_(DisplayBoth),
- autoranging_(true)
+ autoranging_(true),
+ value_at_hover_pos_(std::numeric_limits<float>::quiet_NaN())
{
axis_pen_ = AxisPen;
return make_pair(-ph, nh);
}
-int AnalogSignal::scale_handle_offset() const
-{
- const int h = (pos_vdivs_ + neg_vdivs_) * div_height_;
-
- return ((scale_index_drag_offset_ - scale_index_) * h / 4) - h / 2;
-}
-
-void AnalogSignal::scale_handle_dragged(int offset)
-{
- const int h = (pos_vdivs_ + neg_vdivs_) * div_height_;
-
- scale_index_ = scale_index_drag_offset_ - (offset + h / 2) / (h / 4);
-
- update_scale();
-}
-
-void AnalogSignal::scale_handle_drag_release()
-{
- scale_index_drag_offset_ = scale_index_;
- update_scale();
-}
-
void AnalogSignal::on_setting_changed(const QString &key, const QVariant &value)
{
Signal::on_setting_changed(key, value);
paint_axis(p, pp, get_visual_y());
} else {
- Trace::paint_back(p, pp);
+ Signal::paint_back(p, pp);
paint_axis(p, pp, get_visual_y());
}
}
// Show the info section on the right side of the trace, including
// the value at the hover point when the hover marker is enabled
// and we have corresponding data available
- if (show_hover_marker_ && !isnan(value_at_hover_pos_)) {
+ if (show_hover_marker_ && !std::isnan(value_at_hover_pos_)) {
infotext = QString("[%1] %2 V/div")
.arg(format_value_si(value_at_hover_pos_, SIPrefix::unspecified, 0, "V", false))
.arg(resolution_);
const int nh = min(neg_vdivs_, 1) * div_height_;
const float high_offset = y - ph + signal_margin + 0.5f;
const float low_offset = y + nh - signal_margin - 0.5f;
+ const float signal_height = low_offset - high_offset;
shared_ptr<pv::data::LogicSegment> segment = get_logic_segment_to_paint();
if (!segment || (segment->get_sample_count() == 0))
samples_per_pixel / LogicSignal::Oversampling, 0);
assert(edges.size() >= 2);
+ const float first_sample_x =
+ pp.left() + (edges.front().first / samples_per_pixel - pixels_offset);
+ const float last_sample_x =
+ pp.left() + (edges.back().first / samples_per_pixel - pixels_offset);
+
// Check whether we need to paint the sampling points
GlobalSettings settings;
const bool show_sampling_points =
(samples_per_pixel < 0.25);
vector<QRectF> sampling_points;
- float sampling_point_x = 0.0f;
+ float sampling_point_x = first_sample_x;
int64_t sampling_point_sample = start_sample;
const int w = 2;
- if (show_sampling_points) {
+ if (show_sampling_points)
sampling_points.reserve(end_sample - start_sample + 1);
- sampling_point_x = (edges.cbegin()->first / samples_per_pixel - pixels_offset) + pp.left();
- }
+
+ // Check whether we need to fill the high areas
+ const bool fill_high_areas =
+ settings.value(GlobalSettings::Key_View_FillSignalHighAreas).toBool();
+ vector<QRectF> high_rects;
+ float rising_edge_x;
+ bool rising_edge_seen = false;
// Paint the edges
const unsigned int edge_count = edges.size() - 2;
QLineF *const edge_lines = new QLineF[edge_count];
line = edge_lines;
+ if (edges.front().second) {
+ // Beginning of trace is high
+ rising_edge_x = first_sample_x;
+ rising_edge_seen = true;
+ }
+
for (auto i = edges.cbegin() + 1; i != edges.cend() - 1; i++) {
- const float x = ((*i).first / samples_per_pixel -
- pixels_offset) + pp.left();
+ // Note: multiple edges occupying a single pixel are represented by an edge
+ // with undefined logic level. This means that only the first falling edge
+ // after a rising edge corresponds to said rising edge - and vice versa. If
+ // more edges with the same logic level follow, they denote multiple edges.
+
+ const float x = pp.left() + ((*i).first / samples_per_pixel - pixels_offset);
*line++ = QLineF(x, high_offset, x, low_offset);
+ if (fill_high_areas) {
+ // Any edge terminates a high area
+ if (rising_edge_seen) {
+ const int width = x - rising_edge_x;
+ if (width > 0)
+ high_rects.emplace_back(rising_edge_x, high_offset,
+ width, signal_height);
+ rising_edge_seen = false;
+ }
+
+ // Only rising edges start high areas
+ if ((*i).second) {
+ rising_edge_x = x;
+ rising_edge_seen = true;
+ }
+ }
+
if (show_sampling_points)
while (sampling_point_sample < (*i).first) {
const float y = (*i).second ? low_offset : high_offset;
sampling_point_x += pixels_per_sample;
};
+ if (fill_high_areas) {
+ // Add last high rectangle if the signal is still high at the end of the trace
+ if (rising_edge_seen && (edges.cend() - 1)->second)
+ high_rects.emplace_back(rising_edge_x, high_offset,
+ last_sample_x - rising_edge_x, signal_height);
+
+ const QColor fill_color = QColor::fromRgba(settings.value(
+ GlobalSettings::Key_View_FillSignalHighAreaColor).value<uint32_t>());
+ p.setPen(fill_color);
+ p.setBrush(fill_color);
+ p.drawRects((const QRectF*)(high_rects.data()), high_rects.size());
+ }
+
p.setPen(LogicSignal::EdgeColor);
p.drawLines(edge_lines, edge_count);
delete[] edge_lines;
conv_threshold_cb_->blockSignals(true);
// Set available options depending on chosen conversion
- for (pair<QString, int> preset : presets)
+ for (pair<QString, int>& preset : presets)
conv_threshold_cb_->addItem(preset.first, preset.second);
map < QString, QVariant > options = base_->get_conversion_options();
conv_threshold_cb_->blockSignals(false);
}
+vector<data::LogicSegment::EdgePair> AnalogSignal::get_nearest_level_changes(uint64_t sample_pos)
+{
+ assert(base_);
+ assert(owner_);
+
+ // Return if there's no logic data or we're showing only the analog trace
+ if (!base_->logic_data() || (display_type_ == DisplayAnalog))
+ return vector<data::LogicSegment::EdgePair>();
+
+ if (sample_pos == 0)
+ return vector<LogicSegment::EdgePair>();
+
+ shared_ptr<LogicSegment> segment = get_logic_segment_to_paint();
+ if (!segment || (segment->get_sample_count() == 0))
+ return vector<LogicSegment::EdgePair>();
+
+ const View *view = owner_->view();
+ assert(view);
+ const double samples_per_pixel = base_->get_samplerate() * view->scale();
+
+ vector<LogicSegment::EdgePair> edges;
+
+ segment->get_surrounding_edges(edges, sample_pos,
+ samples_per_pixel / LogicSignal::Oversampling, 0);
+
+ if (edges.empty())
+ return vector<LogicSegment::EdgePair>();
+
+ return edges;
+}
+
void AnalogSignal::perform_autoranging(bool keep_divs, bool force_update)
{
const deque< shared_ptr<pv::data::AnalogSegment> > &segments =
static double prev_min = 0, prev_max = 0;
double min = 0, max = 0;
- for (shared_ptr<pv::data::AnalogSegment> segment : segments) {
+ for (const shared_ptr<pv::data::AnalogSegment>& segment : segments) {
pair<double, double> mm = segment->get_min_max();
min = std::min(min, mm.first);
max = std::max(max, mm.second);
{
// Note: NAN is used to indicate the non-existance of a value at this pixel
- if (isnan(prev_value_at_pixel_)) {
+ if (std::isnan(prev_value_at_pixel_)) {
if (x < 0) {
min_value_at_pixel_ = value;
max_value_at_pixel_ = value;
if (pixel_pos > current_pixel_pos_) {
if (pixel_pos - current_pixel_pos_ == 1) {
- if (isnan(prev_value_at_pixel_)) {
+ if (std::isnan(prev_value_at_pixel_)) {
value_at_pixel_pos_.push_back(prev_value_at_pixel_);
} else {
// Average the min/max range to create one value for the previous pixel
connect(conv_threshold_cb_, SIGNAL(currentIndexChanged(int)),
this, SLOT(on_conv_threshold_changed(int)));
- connect(conv_threshold_cb_, SIGNAL(editTextChanged(const QString)),
+ connect(conv_threshold_cb_, SIGNAL(editTextChanged(const QString&)),
this, SLOT(on_conv_threshold_changed())); // index will be -1
// Add the display type dropdown
} else {
try {
value_at_hover_pos_ = value_at_pixel_pos_.at(hp.x());
- } catch (out_of_range) {
+ } catch (out_of_range&) {
value_at_hover_pos_ = std::numeric_limits<float>::quiet_NaN();
}
}