X-Git-Url: https://sigrok.org/gitweb/?p=pulseview.git;a=blobdiff_plain;f=pv%2Fview%2Fanalogsignal.cpp;h=8f6027b7a52f990135fc54cbe0881b93fc4d1c0a;hp=8f79f919eaad3f7e67618378cb6405af9b4f193c;hb=430b94aaa74cbbbf805803a013b77a4d1e18daaf;hpb=b8c4a95bc26d2976ea80001846d1ab7eb15cd3d5 diff --git a/pv/view/analogsignal.cpp b/pv/view/analogsignal.cpp index 8f79f919..8f6027b7 100644 --- a/pv/view/analogsignal.cpp +++ b/pv/view/analogsignal.cpp @@ -31,7 +31,6 @@ #include #include #include -#include #include #include "analogsignal.hpp" @@ -40,9 +39,9 @@ #include "pv/data/logic.hpp" #include "pv/data/logicsegment.hpp" #include "pv/data/signalbase.hpp" -#include "pv/view/view.hpp" -#include "pv/view/logicsignal.hpp" #include "pv/globalsettings.hpp" +#include "pv/view/logicsignal.hpp" +#include "pv/view/view.hpp" #include @@ -68,12 +67,13 @@ const QColor AnalogSignal::SignalColours[4] = { QColor(0x4E, 0x9A, 0x06) // Green }; -const QColor AnalogSignal::GridMajorColor = QColor(0, 0, 0, 40*256/100); -const QColor AnalogSignal::GridMinorColor = QColor(0, 0, 0, 20*256/100); +const QColor AnalogSignal::GridMajorColor = QColor(0, 0, 0, 40 * 256 / 100); +const QColor AnalogSignal::GridMinorColor = QColor(0, 0, 0, 20 * 256 / 100); const QColor AnalogSignal::SamplingPointColour(0x77, 0x77, 0x77); -const float AnalogSignal::EnvelopeThreshold = 256.0f; +const int64_t AnalogSignal::TracePaintBlockSize = 1024 * 1024; // 4 MiB (due to float) +const float AnalogSignal::EnvelopeThreshold = 64.0f; const int AnalogSignal::MaximumVDivs = 10; const int AnalogSignal::MinScaleIndex = -6; @@ -157,16 +157,14 @@ 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; + 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); + scale_index_ = scale_index_drag_offset_ - (offset + h / 2) / (h / 4); update_scale(); } @@ -177,7 +175,7 @@ void AnalogSignal::scale_handle_drag_release() update_scale(); } -void AnalogSignal::paint_back(QPainter &p, const ViewItemPaintParams &pp) +void AnalogSignal::paint_back(QPainter &p, ViewItemPaintParams &pp) { if (base_->enabled()) { Trace::paint_back(p, pp); @@ -185,7 +183,7 @@ void AnalogSignal::paint_back(QPainter &p, const ViewItemPaintParams &pp) } } -void AnalogSignal::paint_mid(QPainter &p, const ViewItemPaintParams &pp) +void AnalogSignal::paint_mid(QPainter &p, ViewItemPaintParams &pp) { assert(base_->analog_data()); assert(owner_); @@ -238,7 +236,7 @@ void AnalogSignal::paint_mid(QPainter &p, const ViewItemPaintParams &pp) } } -void AnalogSignal::paint_fore(QPainter &p, const ViewItemPaintParams &pp) +void AnalogSignal::paint_fore(QPainter &p, ViewItemPaintParams &pp) { if (!enabled()) return; @@ -265,13 +263,19 @@ void AnalogSignal::paint_grid(QPainter &p, int y, int left, int right) { p.setRenderHint(QPainter::Antialiasing, false); + GlobalSettings settings; + const bool show_analog_minor_grid = + settings.value(GlobalSettings::Key_View_ShowAnalogMinorGrid).toBool(); + if (pos_vdivs_ > 0) { p.setPen(QPen(GridMajorColor, 1, Qt::DashLine)); for (int i = 1; i <= pos_vdivs_; i++) { const float dy = i * div_height_; p.drawLine(QLineF(left, y - dy, right, y - dy)); } + } + if ((pos_vdivs_ > 0) && show_analog_minor_grid) { p.setPen(QPen(GridMinorColor, 1, Qt::DashLine)); for (int i = 0; i < pos_vdivs_; i++) { const float dy = i * div_height_; @@ -290,7 +294,9 @@ void AnalogSignal::paint_grid(QPainter &p, int y, int left, int right) const float dy = i * div_height_; p.drawLine(QLineF(left, y + dy, right, y + dy)); } + } + if ((pos_vdivs_ > 0) && show_analog_minor_grid) { p.setPen(QPen(GridMinorColor, 1, Qt::DashLine)); for (int i = 0; i < neg_vdivs_; i++) { const float dy = i * div_height_; @@ -311,6 +317,15 @@ void AnalogSignal::paint_trace(QPainter &p, int y, int left, const int64_t start, const int64_t end, const double pixels_offset, const double samples_per_pixel) { + if (end <= start) + return; + + // Calculate and paint the sampling points if enabled and useful + GlobalSettings settings; + const bool show_sampling_points = + settings.value(GlobalSettings::Key_View_ShowSamplingPoints).toBool() && + (samples_per_pixel < 0.25); + p.setPen(base_->colour()); const int64_t points_count = end - start; @@ -318,38 +333,45 @@ void AnalogSignal::paint_trace(QPainter &p, QPointF *points = new QPointF[points_count]; QPointF *point = points; - QRectF *const sampling_points = new QRectF[points_count]; + QRectF *sampling_points = nullptr; + if (show_sampling_points) + sampling_points = new QRectF[points_count]; QRectF *sampling_point = sampling_points; - pv::data::SegmentAnalogDataIterator* it = - segment->begin_sample_iteration(start); + int64_t sample_count = min(points_count, TracePaintBlockSize); + int64_t block_sample = 0; + const float *sample_block = segment->get_samples(start, start + sample_count); const int w = 2; - for (int64_t sample = start; sample != end; sample++) { + for (int64_t sample = start; sample != end; sample++, block_sample++) { + + if (block_sample == TracePaintBlockSize) { + block_sample = 0; + delete[] sample_block; + sample_count = min(points_count - sample, TracePaintBlockSize); + sample_block = segment->get_samples(sample, sample + sample_count); + } + const float x = (sample / samples_per_pixel - pixels_offset) + left; - *point++ = QPointF(x, y - *((float*)it->value) * scale_); - *sampling_point++ = QRectF(x - (w / 2), y - *((float*)it->value) * scale_ - (w / 2), w, w); + *point++ = QPointF(x, y - sample_block[block_sample] * scale_); - segment->continue_sample_iteration(it, 1); + if (show_sampling_points) + *sampling_point++ = + QRectF(x - (w / 2), y - sample_block[block_sample] * scale_ - (w / 2), w, w); } - segment->end_sample_iteration(it); + delete[] sample_block; p.drawPolyline(points, points_count); - // Paint the sampling points if enabled - GlobalSettings settings; - const bool show_sampling_points = - settings.value(GlobalSettings::Key_View_ShowSamplingPoints).toBool(); - - if (show_sampling_points && (samples_per_pixel < 0.25)) { + if (show_sampling_points) { p.setPen(SamplingPointColour); p.drawRects(sampling_points, points_count); + delete[] sampling_points; } delete[] points; - delete[] sampling_points; } void AnalogSignal::paint_envelope(QPainter &p, @@ -371,7 +393,7 @@ void AnalogSignal::paint_envelope(QPainter &p, QRectF *const rects = new QRectF[e.length]; QRectF *rect = rects; - for (uint64_t sample = 0; sample < e.length-1; sample++) { + for (uint64_t sample = 0; sample < e.length - 1; sample++) { const float x = ((e.scale * sample + e.start) / samples_per_pixel - pixels_offset) + left; const AnalogSegment::EnvelopeSample *const s = @@ -379,8 +401,8 @@ void AnalogSignal::paint_envelope(QPainter &p, // We overlap this sample with the next so that vertical // gaps do not appear during steep rising or falling edges - const float b = y - max(s->max, (s+1)->min) * scale_; - const float t = y - min(s->min, (s+1)->max) * scale_; + const float b = y - max(s->max, (s + 1)->min) * scale_; + const float t = y - min(s->min, (s + 1)->max) * scale_; float h = b - t; if (h >= 0.0f && h <= 1.0f) @@ -397,7 +419,7 @@ void AnalogSignal::paint_envelope(QPainter &p, delete[] e.samples; } -void AnalogSignal::paint_logic_mid(QPainter &p, const ViewItemPaintParams &pp) +void AnalogSignal::paint_logic_mid(QPainter &p, ViewItemPaintParams &pp) { QLineF *line; @@ -407,7 +429,7 @@ void AnalogSignal::paint_logic_mid(QPainter &p, const ViewItemPaintParams &pp) const int y = get_visual_y(); - if (!base_->enabled()) + if (!base_->enabled() || !base_->logic_data()) return; const int signal_margin = @@ -420,6 +442,7 @@ void AnalogSignal::paint_logic_mid(QPainter &p, const ViewItemPaintParams &pp) const deque< shared_ptr > &segments = base_->logic_data()->logic_segments(); + if (segments.empty()) return; @@ -545,7 +568,7 @@ void AnalogSignal::update_conversion_type() owner_->row_item_appearance_changed(false, true); } -void AnalogSignal::perform_autoranging(bool force_update) +void AnalogSignal::perform_autoranging(bool keep_divs, bool force_update) { const deque< shared_ptr > &segments = base_->analog_data()->analog_segments(); @@ -568,18 +591,31 @@ void AnalogSignal::perform_autoranging(bool force_update) prev_min = min; prev_max = max; - // Use all divs for the positive range if there are no negative values - if ((min == 0) && (neg_vdivs_ > 0)) { - pos_vdivs_ += neg_vdivs_; - neg_vdivs_ = 0; - } + // If we're allowed to alter the div assignment... + if (!keep_divs) { + // Use all divs for the positive range if there are no negative values + if ((min == 0) && (neg_vdivs_ > 0)) { + pos_vdivs_ += neg_vdivs_; + neg_vdivs_ = 0; + } - // Split up the divs if there are negative values but no negative divs - if ((min < 0) && (neg_vdivs_ == 0)) { - neg_vdivs_ = pos_vdivs_ / 2; - pos_vdivs_ -= neg_vdivs_; + // Split up the divs if there are negative values but no negative divs + if ((min < 0) && (neg_vdivs_ == 0)) { + neg_vdivs_ = pos_vdivs_ / 2; + pos_vdivs_ -= neg_vdivs_; + } } + // If there is still no positive div when we need it, add one + // (this can happen when pos_vdivs==neg_vdivs==0) + if ((max > 0) && (pos_vdivs_ == 0)) + pos_vdivs_ = 1; + + // If there is still no negative div when we need it, add one + // (this can happen when pos_vdivs was 0 or 1 when trying to split) + if ((min < 0) && (neg_vdivs_ == 0)) + neg_vdivs_ = 1; + double min_value_per_div; if ((pos_vdivs_ > 0) && (neg_vdivs_ > 0)) min_value_per_div = std::max(max / pos_vdivs_, -min / neg_vdivs_); @@ -606,19 +642,19 @@ void AnalogSignal::populate_popup_form(QWidget *parent, QFormLayout *form) QFormLayout *const layout = new QFormLayout; // Add the number of vdivs - QSpinBox *pvdiv_sb = new QSpinBox(parent); - pvdiv_sb->setRange(0, MaximumVDivs); - pvdiv_sb->setValue(pos_vdivs_); - connect(pvdiv_sb, SIGNAL(valueChanged(int)), + pvdiv_sb_ = new QSpinBox(parent); + pvdiv_sb_->setRange(0, MaximumVDivs); + pvdiv_sb_->setValue(pos_vdivs_); + connect(pvdiv_sb_, SIGNAL(valueChanged(int)), this, SLOT(on_pos_vdivs_changed(int))); - layout->addRow(tr("Number of pos vertical divs"), pvdiv_sb); + layout->addRow(tr("Number of pos vertical divs"), pvdiv_sb_); - QSpinBox *nvdiv_sb = new QSpinBox(parent); - nvdiv_sb->setRange(0, MaximumVDivs); - nvdiv_sb->setValue(neg_vdivs_); - connect(nvdiv_sb, SIGNAL(valueChanged(int)), + nvdiv_sb_ = new QSpinBox(parent); + nvdiv_sb_->setRange(0, MaximumVDivs); + nvdiv_sb_->setValue(neg_vdivs_); + connect(nvdiv_sb_, SIGNAL(valueChanged(int)), this, SLOT(on_neg_vdivs_changed(int))); - layout->addRow(tr("Number of neg vertical divs"), nvdiv_sb); + layout->addRow(tr("Number of neg vertical divs"), nvdiv_sb_); // Add the vertical resolution resolution_cb_ = new QComboBox(parent); @@ -685,7 +721,7 @@ void AnalogSignal::populate_popup_form(QWidget *parent, QFormLayout *form) void AnalogSignal::on_samples_added() { - perform_autoranging(); + perform_autoranging(false, false); if (owner_) { // Call order is important, otherwise the lazy event handler won't work @@ -696,10 +732,20 @@ void AnalogSignal::on_samples_added() void AnalogSignal::on_pos_vdivs_changed(int vdivs) { + if (vdivs == pos_vdivs_) + return; + pos_vdivs_ = vdivs; - if (autoranging_) - perform_autoranging(true); + if (autoranging_) { + perform_autoranging(true, true); + + // It could be that a positive or negative div was added, so update + if (pvdiv_sb_) { + pvdiv_sb_->setValue(pos_vdivs_); + nvdiv_sb_->setValue(neg_vdivs_); + } + } if (owner_) { // Call order is important, otherwise the lazy event handler won't work @@ -710,10 +756,20 @@ void AnalogSignal::on_pos_vdivs_changed(int vdivs) void AnalogSignal::on_neg_vdivs_changed(int vdivs) { + if (vdivs == neg_vdivs_) + return; + neg_vdivs_ = vdivs; - if (autoranging_) - perform_autoranging(true); + if (autoranging_) { + perform_autoranging(true, true); + + // It could be that a positive or negative div was added, so update + if (pvdiv_sb_) { + pvdiv_sb_->setValue(pos_vdivs_); + nvdiv_sb_->setValue(neg_vdivs_); + } + } if (owner_) { // Call order is important, otherwise the lazy event handler won't work @@ -736,7 +792,7 @@ void AnalogSignal::on_autoranging_changed(int state) autoranging_ = (state == Qt::Checked); if (autoranging_) - perform_autoranging(true); + perform_autoranging(false, true); if (owner_) { // Call order is important, otherwise the lazy event handler won't work