diff --git a/YSGraphic_Core/Axis/AbsAxis.cpp b/YSGraphic_Core/Axis/AbsAxis.cpp index f3231d9..15665b2 100644 --- a/YSGraphic_Core/Axis/AbsAxis.cpp +++ b/YSGraphic_Core/Axis/AbsAxis.cpp @@ -168,7 +168,7 @@ namespace YSG { QString AbsAxisPrivate::getTickLabel(double tick, SRC src) { - auto renderState = reinterpret_cast(getState(src)); + auto renderState = reinterpret_cast(state(src)); return renderState->locale.toString(tick, renderState->formatChar.toLatin1(), renderState->numberPrecision); } @@ -215,4 +215,4 @@ namespace YSG { QVector AbsAxis::createSubTickVector(int subTickCount, const QVector &ticks, const Range& range) { return d()->createSubTickVector(subTickCount, ticks, range); } -} \ No newline at end of file +} diff --git a/YSGraphic_Core/Axis/AbsAxis.h b/YSGraphic_Core/Axis/AbsAxis.h index a9bb8c9..6785b94 100644 --- a/YSGraphic_Core/Axis/AbsAxis.h +++ b/YSGraphic_Core/Axis/AbsAxis.h @@ -51,11 +51,11 @@ public: virtual QVector createTickVector(double tickStep, const Range &range); virtual QVector createSubTickVector(int subTickCount, const QVector &ticks, const Range& range); virtual QVector createLabelVector(const QVector &ticks, SRC); - double startCoord(SRC=SRC::Auto); - double endCoord(SRC=SRC::Auto); - Range coordRange(SRC=SRC::Auto); - int getPixelPointSize(Range range, SRC=SRC::Cache); - int getPixelPointSize(SRC=SRC::Cache); + double startCoord(SRC=SRC::Edit); + double endCoord(SRC=SRC::Edit); + Range coordRange(SRC=SRC::Edit); + int getPixelPointSize(Range range, SRC=SRC::Edit); + int getPixelPointSize(SRC=SRC::Edit); template struct BuilderT; }; template diff --git a/YSGraphic_Core/Axis/AbsAxis_p.h b/YSGraphic_Core/Axis/AbsAxis_p.h index be396f8..1db6162 100644 --- a/YSGraphic_Core/Axis/AbsAxis_p.h +++ b/YSGraphic_Core/Axis/AbsAxis_p.h @@ -27,7 +27,7 @@ namespace YSG { void prepareData() override { SpinLockGuard guard(&mBufferLock); - loadCache(); + syncStatePipeline(); } void draw(QPainter* painter) override { @@ -112,11 +112,11 @@ namespace YSG { protected: [[nodiscard]] virtual double pixelToCoord(double pixel, SRC src) { - auto s = static_cast(getState(src)); + auto s = static_cast(state(src)); return s->coordStart + s->coordLength * (pixel - (double)pixelStart)/(double)s->pixelSize; } [[nodiscard]] virtual double coordToPixel(double coord, SRC src) { - auto s = static_cast(getState(src)); + auto s = static_cast(state(src)); return pixelStart + (double)s->pixelSize * (coord - s->coordStart)/s->coordLength; } virtual double getTickStep(const Range &range){ @@ -134,7 +134,7 @@ namespace YSG { void AbsAxis::BuilderT::set(AbsAxis* ret) { ret->init(plot, layerName); AbsAxisPrivate* pd = ret->d(); - AbsAxisRenderState* sc = pd->renderStateCache(); + AbsAxisRenderState* sc = reinterpret_cast(pd->state(State_Edit)); sc->x = this->x; sc->y = this->y; sc->orientation = this->orientation; diff --git a/YSGraphic_Core/Axis/Axis_p.h b/YSGraphic_Core/Axis/Axis_p.h index c7e9620..259a66e 100644 --- a/YSGraphic_Core/Axis/Axis_p.h +++ b/YSGraphic_Core/Axis/Axis_p.h @@ -26,8 +26,8 @@ namespace YSG { const double delta = event->angleDelta().y(); double wheelSteps = delta / 120.0; double factor = std::pow(0.8, wheelSteps); - auto rc = renderStateCache(); - double cursor_coord = pixelToCoord(event->position().x(), SRC::Cache); + auto rc = editState(); + double cursor_coord = pixelToCoord(event->position().x(), SRC::Edit); double new_coordLength = rc->coordLength * factor; double new_coordStart = cursor_coord - new_coordLength * (cursor_coord - rc->coordStart) / rc->coordLength; rc->coordStart = new_coordStart; @@ -46,7 +46,7 @@ namespace YSG { dragging = true; startGlobalPos = QCursor::pos(); startPos = event->pos(); - auto rc = renderStateCache(); + auto rc = editState(); startCoordValue = rc->coordStart; pixelPreCoord = rc->coordLength/static_cast(rc->pixelSize); } @@ -57,7 +57,7 @@ namespace YSG { SpinLockGuard _guard(&mBufferLock); RenderEditGuard _editGuard(this); QPoint delt = startGlobalPos - QCursor::pos(); - auto rc = renderStateCache(); + auto rc = editState(); auto coordDelt = pixelPreCoord * (rc->orientation == Qt::Horizontal ? delt.x() :delt.y()); rc->coordStart = startCoordValue + coordDelt; } @@ -73,7 +73,7 @@ namespace YSG { void Axis::BuilderT::set(Axis* ret) { AbsAxis::BuilderT::set(ret); AxisPrivate* pd = ret->d(); - AxisRenderState* sc = pd->renderStateCache(); + AxisRenderState* sc = reinterpret_cast(pd->state(State_Edit)); PROP_RT(int, numberPrecision) PROP_RT(double, coordStart) PROP_RT(double, coordLength) diff --git a/YSGraphic_Core/Axis/FrequentAxis_p.h b/YSGraphic_Core/Axis/FrequentAxis_p.h index bc24da2..cfafd29 100644 --- a/YSGraphic_Core/Axis/FrequentAxis_p.h +++ b/YSGraphic_Core/Axis/FrequentAxis_p.h @@ -42,7 +42,7 @@ namespace YSG { renderState()->unitText = "频率/" + getXUnitTypeString(xUnitType); { SpinLockGuard _guard (&mBufferLock); - renderStateCache()->unitText = "频率/" + getXUnitTypeString(xUnitType); + editState()->unitText = "频率/" + getXUnitTypeString(xUnitType); } } } diff --git a/YSGraphic_Core/Axis/TimeAxis.cpp b/YSGraphic_Core/Axis/TimeAxis.cpp index cd46156..4a9e36e 100644 --- a/YSGraphic_Core/Axis/TimeAxis.cpp +++ b/YSGraphic_Core/Axis/TimeAxis.cpp @@ -13,7 +13,7 @@ namespace YSG { SpinLockGuard _guard(&pd->mBufferLock); RenderEditGuard _editGuard(pd); std::pair ret = pd->mTimeTicker.getNewDataTickInfo(); - auto td = pd->tempDataCache(); + auto td = reinterpret_cast(pd->mEditTempData); td->mAllTime.push_back(time); if(ret.second) { td->mData.push_front({time, ret.first}); @@ -34,7 +34,7 @@ namespace YSG { auto ret = new TimeAxis(); set(ret); TimeAxisPrivate* pd = ret->d(); - TimeAxisRenderState* sc = pd->renderStateCache(); + TimeAxisRenderState* sc = reinterpret_cast(pd->state(State_Edit)); PROP_R(int, timePointSize) PROP_R(int, tickPixelSpace) PROP_R(QString, timeFormat) diff --git a/YSGraphic_Core/Axis/TimeAxis.h b/YSGraphic_Core/Axis/TimeAxis.h index 94fc981..b0e564c 100644 --- a/YSGraphic_Core/Axis/TimeAxis.h +++ b/YSGraphic_Core/Axis/TimeAxis.h @@ -12,7 +12,7 @@ namespace YSG { PROP(QString, timeFormat) PROP(QFont, font) int giveData(QTime time); - QTime tickToTime(int tick, SRC=SRC::Auto); + QTime tickToTime(int tick, SRC=SRC::Edit); struct Builder; }; diff --git a/YSGraphic_Core/Axis/TimeAxis_p.h b/YSGraphic_Core/Axis/TimeAxis_p.h index 229d423..5dc1c57 100644 --- a/YSGraphic_Core/Axis/TimeAxis_p.h +++ b/YSGraphic_Core/Axis/TimeAxis_p.h @@ -73,7 +73,7 @@ namespace YSG { struct TimeAxisRenderState : AbsAxisRenderState, TimeAxis_Prop { int tickSpace = 4; - int getTickSpaceHint(SRC src = SRC::Cache) { + int getTickSpaceHint(SRC src = SRC::Edit) { QFontMetrics fm(font); double rate = (double)timePointSize/(double)pixelSize; double ret = rate * (tickPixelSpace + (orientation == Qt::Horizontal ? fm.horizontalAdvance(timeFormat) : fm.height())); @@ -92,10 +92,10 @@ namespace YSG { std::list mData; void prepareData() override { SpinLockGuard guard(&mBufferLock); - loadCache(); - auto d = tempData(); + syncStatePipeline(); + auto d = renderTempData(); auto s = renderState(); - auto sc = renderStateCache(); + auto sc = editState(); bool refreshSpace = false; if(mTimeTicker.mTimePointSize != s->timePointSize) { mTimeTicker.setTimePointSize(s->timePointSize); @@ -184,7 +184,7 @@ namespace YSG { } QString getTickLabel(double tick, SRC src) override { - auto renderState = reinterpret_cast(getState(src)); + auto renderState = reinterpret_cast(state(src)); return q()->tickToTime((int)tick, src).toString(renderState->timeFormat); } }; diff --git a/YSGraphic_Core/CacheModel.h b/YSGraphic_Core/CacheModel.h index c859c35..e8aedc4 100644 --- a/YSGraphic_Core/CacheModel.h +++ b/YSGraphic_Core/CacheModel.h @@ -1,16 +1,21 @@ #pragma once -#include "GlobalTypes.h" +#include "RenderAble.h" namespace YSG{ template struct CacheModel { - T render, cache; + std::array buffers; + Triple_Role_Buffer_Control control; SpinLock mLock; - void loadCache() { - render = cache; + void syncStatePipeline() { + auto lease = control.wait_mark_use_role(State_Ready); + buffers[lease.index] = *state(SRC::Edit); + control.unmark_use(lease); + control.wait_swap_role(State_Ready, State_Render, [](const Triple_Buffer_View&) { + return true; + }); } - T* getState(SRC src = SRC::Render) { - if(src == SRC::Cache) return &cache; - return &render; + T* state(SRC src = SRC::Render) { + return &buffers[control.read_view()[static_cast(src)]]; } }; } diff --git a/YSGraphic_Core/GlobalTypes.h b/YSGraphic_Core/GlobalTypes.h index 8a42830..fb40ba3 100644 --- a/YSGraphic_Core/GlobalTypes.h +++ b/YSGraphic_Core/GlobalTypes.h @@ -9,6 +9,7 @@ #include #include #include +#include // Q_DECL_IMPORT @@ -91,17 +92,17 @@ namespace YSG { }; - enum class LIB_DECL SRC { - Auto, //第一次loadCache之前是Cache,其他是Render - Cache, - Render, + enum class LIB_DECL SRC : std::uint8_t { + Edit, + Ready, + Render }; } #define PROP(Type, Name) \ -Type Name(SRC src = SRC::Auto); \ +Type Name(SRC src = SRC::Edit); \ void set_##Name(Type); @@ -184,20 +185,20 @@ return *this; \ #define PROPERTY_H(className, Type, name) \ void set_##name(Type name); \ -Type name(SRC src = SRC::Auto); +Type name(SRC src = SRC::Edit); #define PROPERTY_CPP(className, Type, name) \ public: \ void set_##name(Type name) { \ className##Private* pd = d(); \ - className##RenderState* sc = pd->renderStateCache(); \ - className##TempData* td = pd->tempDataCache(); \ + className##RenderState* sc = reinterpret_cast(pd->state(State_Edit)); \ + className##TempData* td = reinterpret_cast(pd->mEditTempData); \ SpinLockGuard _guard(&pd->mBufferLock); \ sc->##name = name; \ } \ Type name(SRC src) { \ className##Private* privateData = d(); \ - className##RenderState* renderState = reinterpret_cast(d()->getState(src)); \ + className##RenderState* renderState = reinterpret_cast(d()->state(src)); \ return renderState->##name; \ } diff --git a/YSGraphic_Core/RenderAble.cpp b/YSGraphic_Core/RenderAble.cpp index 4141943..cedfa79 100644 --- a/YSGraphic_Core/RenderAble.cpp +++ b/YSGraphic_Core/RenderAble.cpp @@ -45,9 +45,7 @@ namespace YSG { if (mLock) mLock->lock(); } RenderAble::RenderPipeline::RenderPipeline() { - frontColor = &colorBuffers[0]; - readyColor = &colorBuffers[1]; - renderColor = &colorBuffers[2]; + colorControl.reset(); } void RenderAble::RenderPipeline::markEditState() { editStateVersion.fetch_add(1, std::memory_order_release); @@ -55,33 +53,48 @@ namespace YSG { bool RenderAble::RenderPipeline::hasNewState() const { return RenderAble::version_newer(editStateVersion.load(std::memory_order_acquire), renderStateVersion); } - RenderAble::ColorBuffer* RenderAble::RenderPipeline::currentRenderColor() const { - return renderColor; + RenderAble::ColorBuffer* RenderAble::RenderPipeline::colorByIndex(std::uint8_t index) { + return &colorBuffers[index]; + } + RenderAble::ColorBuffer* RenderAble::RenderPipeline::colorByRole(std::uint8_t role) { + return colorByIndex(colorControl.read_view()[role]); + } + RenderAble::ColorBufferLease RenderAble::RenderPipeline::waitRenderColor() { + auto lease = colorControl.wait_mark_use_role(Color_Render); + return {colorByIndex(lease.index), lease}; + } + RenderAble::ColorBufferLease RenderAble::RenderPipeline::tryFrontColor() { + auto record = colorControl.try_mark_use_role(Color_Front); + if(record.result != Triple_Buffer_Result::Success) { + return {}; + } + return {colorByIndex(record.lease.index), record.lease}; + } + void RenderAble::RenderPipeline::unmarkColor(ColorBufferLease lease) { + colorControl.unmark_use(lease.lease); } QRegion RenderAble::RenderPipeline::publishRenderColor() { - QRegion updateRegion; - SpinLockGuard guard(&colorLock); - if(RenderAble::version_newer(renderColor->version, readyColor->version)) { - std::swap(readyColor, renderColor); - dirtyRegion += readyColor->dirtyRegion; + colorControl.wait_swap_role(Color_Ready, Color_Render, [this](const Triple_Buffer_View& view) { + auto render = colorByIndex(view[Color_Render]); + auto ready = colorByIndex(view[Color_Ready]); + return RenderAble::version_newer(render->version.load(std::memory_order_acquire), ready->version.load(std::memory_order_acquire)); + }); + auto view = colorControl.read_view(); + auto ready = colorByIndex(view[Color_Ready]); + auto front = colorByIndex(view[Color_Front]); + if(RenderAble::version_newer(ready->version.load(std::memory_order_acquire), front->version.load(std::memory_order_acquire)) && !paintRequestPending.exchange(true, std::memory_order_acq_rel)) { + return ready->dirtyRegion; } - if(RenderAble::version_newer(readyColor->version, frontColor->version)) { - if(dirtyRegion.isEmpty()) dirtyRegion = readyColor->dirtyRegion; - if(!paintRequestPending) { - paintRequestPending = true; - updateRegion = dirtyRegion; - } - } - return updateRegion; + return {}; } - RenderAble::ColorBuffer* RenderAble::RenderPipeline::consumeReadyColor() { - SpinLockGuard guard(&colorLock); - if(RenderAble::version_newer(readyColor->version, frontColor->version)) { - std::swap(frontColor, readyColor); - } - paintRequestPending = false; - dirtyRegion = QRegion(); - return frontColor; + RenderAble::ColorBufferLease RenderAble::RenderPipeline::consumeReadyColor() { + colorControl.try_swap_role(Color_Front, Color_Ready, [this](const Triple_Buffer_View& view) { + auto ready = colorByIndex(view[Color_Ready]); + auto front = colorByIndex(view[Color_Front]); + return RenderAble::version_newer(ready->version.load(std::memory_order_acquire), front->version.load(std::memory_order_acquire)); + }); + paintRequestPending.store(false, std::memory_order_release); + return tryFrontColor(); } RenderEditGuard::RenderEditGuard(RenderData* data) : mData(data) { } @@ -95,22 +108,23 @@ namespace YSG { plot->mLayerMap[layerName]->mRenderAbles.append(this); mPlot = plot; if(!dPtr) dPtr = createRenderData(); - delete dPtr->mRenderState; - delete dPtr->mRenderStateCache; - delete dPtr->mTempData; - delete dPtr->mTempDataCache; - dPtr->mRenderState = createRenderState(); - dPtr->mRenderStateCache = createRenderState(); - dPtr->mTempData = createTempData(); - dPtr->mTempDataCache = createTempData(); - dPtr->mRenderState->dPtr = dPtr; - dPtr->mRenderStateCache->dPtr = dPtr; + dPtr->clearStateBuffers(); + delete dPtr->mRenderTempData; + delete dPtr->mEditTempData; + dPtr->mStateBuffers[State_Edit] = createRenderState(); + dPtr->mStateBuffers[State_Ready] = createRenderState(); + dPtr->mStateBuffers[State_Render] = createRenderState(); + dPtr->mRenderTempData = createTempData(); + dPtr->mEditTempData = createTempData(); + for(RenderState* state : dPtr->mStateBuffers) { + state->dPtr = dPtr; + } dPtr->qPtr = this; - dPtr->mRenderStateCache->version = 1; + dPtr->mStateBuffers[State_Edit]->version = 1; if(mPlot) mPlot->markRenderStateDirty(); } void RenderAble::markStateDirty() { - if(dPtr && dPtr->mRenderStateCache) ++dPtr->mRenderStateCache->version; + if(dPtr) ++dPtr->state(State_Edit)->version; if(mPlot) mPlot->markRenderStateDirty(); } bool RenderAble::ok() const { @@ -224,6 +238,10 @@ namespace YSG { } SRC RenderState::src() { - return dPtr->mRenderState == this ? SRC::Render : SRC::Cache; + auto view = dPtr->mStateControl.read_view(); + for(std::uint8_t role = State_Edit; role <= State_Render; ++role) { + if(dPtr->mStateBuffers[view[role]] == this) return static_cast(role); + } + return SRC::Edit; } } diff --git a/YSGraphic_Core/RenderAble.h b/YSGraphic_Core/RenderAble.h index ab7ab5d..d584ca2 100644 --- a/YSGraphic_Core/RenderAble.h +++ b/YSGraphic_Core/RenderAble.h @@ -8,8 +8,240 @@ #include #include "GlobalTypes.h" namespace YSG { +static constexpr std::uint8_t triple_buffer_invalid_index = 255; +enum class Triple_Buffer_Result : std::uint8_t { + Success, + Busy, + State_Changed, + Condition_Failed +}; +enum class Triple_Buffer_Mode : std::uint8_t { + Try, + Wait +}; +struct Triple_Buffer_View { + std::array index{}; + std::uint8_t operator[](std::uint8_t role) const { + return index[role]; + } +}; +struct Triple_Buffer_Lease { + std::uint8_t index = triple_buffer_invalid_index; + explicit operator bool() const { + return index != triple_buffer_invalid_index; + } +}; +struct Triple_Buffer_Mark_Record { + Triple_Buffer_Result result = Triple_Buffer_Result::Condition_Failed; + Triple_Buffer_Lease lease{}; + std::uint8_t busy_index = triple_buffer_invalid_index; +}; +struct Triple_Buffer_Swap_Record { + Triple_Buffer_Result result = Triple_Buffer_Result::Condition_Failed; + Triple_Buffer_View old_view{}; + Triple_Buffer_View new_view{}; + std::uint8_t busy_index = triple_buffer_invalid_index; +}; +struct alignas(64) Triple_Buffer_Busy { + std::atomic_bool busy{false}; +}; +class Triple_Role_Buffer_Control { +public: + void reset() { + slot_state.store(0, std::memory_order_release); + for(auto& item : buffer_busy) { + item.busy.store(false, std::memory_order_release); + item.busy.notify_all(); + } + slot_state.notify_all(); + } + Triple_Buffer_View read_view() const { + return decode_order(slot_state.load(std::memory_order_acquire)); + } + Triple_Buffer_Mark_Record try_mark_use_index(std::uint8_t index) { + if(!try_mark_index(index)) { + return {Triple_Buffer_Result::Busy, {}, index}; + } + return {Triple_Buffer_Result::Success, {index}, triple_buffer_invalid_index}; + } + Triple_Buffer_Lease wait_mark_use_index(std::uint8_t index) { + for(;;) { + if(try_mark_index(index)) { + return {index}; + } + wait_index_free(index); + } + } + Triple_Buffer_Mark_Record try_mark_use_role(std::uint8_t role) { + auto order = slot_state.load(std::memory_order_acquire); + auto view = decode_order(order); + auto index = view[role]; + if(!try_mark_index(index)) { + return {Triple_Buffer_Result::Busy, {}, index}; + } + auto cur_order = slot_state.load(std::memory_order_acquire); + if(cur_order != order) { + unmark_index(index); + return {Triple_Buffer_Result::State_Changed, {}, triple_buffer_invalid_index}; + } + return {Triple_Buffer_Result::Success, {index}, triple_buffer_invalid_index}; + } + Triple_Buffer_Lease wait_mark_use_role(std::uint8_t role) { + for(;;) { + auto record = try_mark_use_role(role); + if(record.result == Triple_Buffer_Result::Success) { + return record.lease; + } + if(record.result == Triple_Buffer_Result::Busy) { + wait_index_free(record.busy_index); + } + } + } + void unmark_use(Triple_Buffer_Lease lease) { + unmark_index(lease.index); + } + template + Triple_Buffer_Swap_Record try_swap_role(std::uint8_t left_role, std::uint8_t right_role, Can_Swap can_swap) { + std::uint8_t busy_index = triple_buffer_invalid_index; + return try_swap_role_once(left_role, right_role, can_swap, busy_index); + } + template + Triple_Buffer_Swap_Record wait_swap_role(std::uint8_t left_role, std::uint8_t right_role, Can_Swap can_swap) { + for(;;) { + std::uint8_t busy_index = triple_buffer_invalid_index; + auto record = try_swap_role_once(left_role, right_role, can_swap, busy_index); + if(record.result == Triple_Buffer_Result::Success || record.result == Triple_Buffer_Result::Condition_Failed) { + return record; + } + if(record.result == Triple_Buffer_Result::Busy) { + wait_index_free(busy_index); + } else { + slot_state.wait(encode_order(record.old_view), std::memory_order_acquire); + } + } + } +private: + std::atomic slot_state{0}; + std::array buffer_busy{}; + static Triple_Buffer_View decode_order(std::uint8_t order) { + switch(order) { + case 0: + return {{0, 1, 2}}; + case 1: + return {{0, 2, 1}}; + case 2: + return {{1, 0, 2}}; + case 3: + return {{1, 2, 0}}; + case 4: + return {{2, 0, 1}}; + case 5: + return {{2, 1, 0}}; + } + return {{0, 1, 2}}; + } + static std::uint8_t encode_order(const Triple_Buffer_View& view) { + if(view.index[0] == 0) { + return view.index[1] == 1 ? 0 : 1; + } + if(view.index[0] == 1) { + return view.index[1] == 0 ? 2 : 3; + } + return view.index[1] == 0 ? 4 : 5; + } + static std::uint8_t swap_order(std::uint8_t order, std::uint8_t left_role, std::uint8_t right_role) { + auto view = decode_order(order); + auto temp = view.index[left_role]; + view.index[left_role] = view.index[right_role]; + view.index[right_role] = temp; + return encode_order(view); + } + bool try_mark_index(std::uint8_t index) { + bool expected = false; + return buffer_busy[index].busy.compare_exchange_strong(expected, true, std::memory_order_acq_rel, std::memory_order_acquire); + } + void unmark_index(std::uint8_t index) { + buffer_busy[index].busy.store(false, std::memory_order_release); + buffer_busy[index].busy.notify_all(); + } + void wait_index_free(std::uint8_t index) { + while(buffer_busy[index].busy.load(std::memory_order_acquire)) { + buffer_busy[index].busy.wait(true, std::memory_order_acquire); + } + } + bool try_mark_two_indices(std::uint8_t left_index, std::uint8_t right_index, std::uint8_t& busy_index) { + if(left_index == right_index) { + if(!try_mark_index(left_index)) { + busy_index = left_index; + return false; + } + return true; + } + auto first = left_index < right_index ? left_index : right_index; + auto second = left_index < right_index ? right_index : left_index; + if(!try_mark_index(first)) { + busy_index = first; + return false; + } + if(!try_mark_index(second)) { + unmark_index(first); + busy_index = second; + return false; + } + return true; + } + void unmark_two_indices(std::uint8_t left_index, std::uint8_t right_index) { + if(left_index == right_index) { + unmark_index(left_index); + return; + } + unmark_index(left_index); + unmark_index(right_index); + } + template + Triple_Buffer_Swap_Record try_swap_role_once(std::uint8_t left_role, std::uint8_t right_role, Can_Swap can_swap, std::uint8_t& busy_index) { + auto old_order = slot_state.load(std::memory_order_acquire); + auto old_view = decode_order(old_order); + auto left_index = old_view[left_role]; + auto right_index = old_view[right_role]; + if(!try_mark_two_indices(left_index, right_index, busy_index)) { + return {Triple_Buffer_Result::Busy, old_view, old_view, busy_index}; + } + auto cur_order = slot_state.load(std::memory_order_acquire); + if(cur_order != old_order) { + auto cur_view = decode_order(cur_order); + unmark_two_indices(left_index, right_index); + return {Triple_Buffer_Result::State_Changed, old_view, cur_view, triple_buffer_invalid_index}; + } + if(!can_swap(old_view)) { + unmark_two_indices(left_index, right_index); + return {Triple_Buffer_Result::Condition_Failed, old_view, old_view, triple_buffer_invalid_index}; + } + auto new_order = swap_order(old_order, left_role, right_role); + auto new_view = decode_order(new_order); + auto expected = old_order; + if(!slot_state.compare_exchange_strong(expected, new_order, std::memory_order_acq_rel, std::memory_order_acquire)) { + auto cur_view = decode_order(expected); + unmark_two_indices(left_index, right_index); + return {Triple_Buffer_Result::State_Changed, old_view, cur_view, triple_buffer_invalid_index}; + } + unmark_two_indices(left_index, right_index); + slot_state.notify_all(); + return {Triple_Buffer_Result::Success, old_view, new_view, triple_buffer_invalid_index}; + } +}; +enum State_Role : std::uint8_t { + State_Edit, + State_Ready, + State_Render +}; +enum Color_Role : std::uint8_t { + Color_Front, + Color_Ready, + Color_Render +}; #define INIT_GET(className) className##Private* privateData = d(); \ - className##RenderState* renderState = reinterpret_cast(d()->getState(src)); + className##RenderState* renderState = reinterpret_cast(d()->state(src)); struct TempData { virtual ~TempData() = default; }; @@ -23,40 +255,47 @@ struct RenderData { SpinLock mBufferLock; RenderAble* qPtr{}; bool mRenderStart = false; - RenderState* getState(SRC src) const { - switch (src) { - case SRC::Render: { - return mRenderState; - } - case SRC::Cache: { - return mRenderStateCache; - } - case SRC::Auto: { - return mRenderStart ? mRenderState : mRenderStateCache; - } - } - qDebug() << "RenderState* RenderData::getState(SRC src) error! 不存在的枚举值" << static_cast(src); - return nullptr; + Triple_Role_Buffer_Control mStateControl; + std::array mStateBuffers{}; + RenderState* state(std::uint8_t role) const { + return stateByIndex(mStateControl.read_view()[role]); } - RenderState *mRenderState{}, *mRenderStateCache{}; - TempData *mTempData{}, *mTempDataCache{}; + RenderState* state(SRC src) const { + return state(static_cast(src)); + } + RenderState* stateByIndex(std::uint8_t index) const { + return mStateBuffers[index]; + } + Triple_Buffer_Lease waitMarkStateRole(std::uint8_t role) { + return mStateControl.wait_mark_use_role(role); + } + void unmarkState(Triple_Buffer_Lease lease) { + mStateControl.unmark_use(lease); + } + void clearStateBuffers() { + for(RenderState*& state : mStateBuffers) { + delete state; + state = nullptr; + } + mStateControl.reset(); + } + TempData *mRenderTempData{}, *mEditTempData{}; protected: - virtual void loadCache() = 0; + virtual void syncStatePipeline() = 0; virtual RenderState* renderState() = 0; - virtual RenderState* renderStateCache() = 0; - virtual TempData* tempData() = 0; - virtual TempData* tempDataCache() = 0; + virtual RenderState* readyState() = 0; + virtual RenderState* editState() = 0; + virtual TempData* renderTempData() = 0; + virtual TempData* editTempData() = 0; virtual ~RenderData() { - delete mTempData; - delete mTempDataCache; - delete mRenderState; - delete mRenderStateCache; + clearStateBuffers(); + delete mRenderTempData; + delete mEditTempData; } virtual void draw(QPainter* painter) {} virtual void prepareData() { SpinLockGuard g(&mBufferLock); - //qDebug() << "qPtr->mObjectName " << qPtr->mObjectName; - loadCache(); + syncStatePipeline(); } virtual bool selectTest(const QPointF& pos) { return false; @@ -77,16 +316,19 @@ struct BaseRenderData : RenderData { RenderState* renderState() override { return nullptr; } - RenderState* renderStateCache() override { + RenderState* readyState() override { return nullptr; } - TempData* tempData() override { + RenderState* editState() override { return nullptr; } - TempData* tempDataCache() override { + TempData* renderTempData() override { return nullptr; } - void loadCache() override {} + TempData* editTempData() override { + return nullptr; + } + void syncStatePipeline() override {} }; class Plot; struct LIB_DECL RenderEditGuard { @@ -101,27 +343,34 @@ struct RenderAble { Running }; struct ColorBuffer { - std::uint64_t version = 0; + std::atomic version{0}; QImage image; QRegion dirtyRegion; }; + struct ColorBufferLease { + ColorBuffer* buffer{}; + Triple_Buffer_Lease lease{}; + explicit operator bool() const { + return buffer && lease; + } + }; struct RenderPipeline { - SpinLock colorLock; + Triple_Role_Buffer_Control colorControl; std::array colorBuffers; - ColorBuffer* frontColor{}; - ColorBuffer* readyColor{}; - ColorBuffer* renderColor{}; std::atomic editStateVersion{1}; std::uint64_t renderStateVersion = 0; JobState jobState = JobState::Idle; - bool paintRequestPending = false; - QRegion dirtyRegion; + std::atomic_bool paintRequestPending{false}; RenderPipeline(); void markEditState(); bool hasNewState() const; - ColorBuffer* currentRenderColor() const; + ColorBuffer* colorByIndex(std::uint8_t index); + ColorBuffer* colorByRole(std::uint8_t role); + ColorBufferLease waitRenderColor(); + ColorBufferLease tryFrontColor(); + void unmarkColor(ColorBufferLease lease); QRegion publishRenderColor(); - ColorBuffer* consumeReadyColor(); + ColorBufferLease consumeReadyColor(); }; virtual RenderData* createRenderData() { return new BaseRenderData; @@ -219,38 +468,73 @@ private: RenderState* ClassName::createRenderState() {return new ClassName##RenderState;} \ TempData* ClassName::createTempData() {return new ClassName##TempData;} #define D_Ptr_3(ClassName) \ - ClassName##RenderState* renderState() override {return reinterpret_cast(mRenderState);} \ - ClassName##RenderState* renderStateCache() override {return reinterpret_cast(mRenderStateCache);} \ - ClassName##TempData* tempData() override {return reinterpret_cast(mTempData);} \ - ClassName##TempData* tempDataCache() override {return reinterpret_cast(mTempDataCache);} \ + ClassName##RenderState* renderState() override {return reinterpret_cast(state(State_Render));} \ + ClassName##RenderState* readyState() override {return reinterpret_cast(state(State_Ready));} \ + ClassName##RenderState* editState() override {return reinterpret_cast(state(State_Edit));} \ + ClassName##TempData* renderTempData() override {return reinterpret_cast(mRenderTempData);} \ + ClassName##TempData* editTempData() override {return reinterpret_cast(mEditTempData);} \ friend class ClassName; \ - void loadCache() override { \ - *renderState() = *renderStateCache(); \ - std::swap(mTempData, mTempDataCache); \ - if(!mRenderStart) mRenderStart = true; \ + void syncStatePipeline() override { \ + Triple_Buffer_Lease readyLease = mStateControl.wait_mark_use_role(State_Ready); \ + auto ready = reinterpret_cast(stateByIndex(readyLease.index)); \ + auto edit = editState(); \ + if(RenderAble::version_newer(edit->version, ready->version)) *ready = *edit; \ + mStateControl.unmark_use(readyLease); \ + mStateControl.wait_swap_role(State_Ready, State_Render, [this](const Triple_Buffer_View& view) { \ + auto ready = reinterpret_cast(stateByIndex(view[State_Ready])); \ + auto render = reinterpret_cast(stateByIndex(view[State_Render])); \ + return RenderAble::version_newer(ready->version, render->version); \ + }); \ + std::swap(mRenderTempData, mEditTempData); \ + if(!mRenderStart) mRenderStart = true; \ } #define D_Ptr(ClassName) \ ClassName* q() {return reinterpret_cast(qPtr);} \ - ClassName##RenderState* renderState() override {return reinterpret_cast(mRenderState);} \ - ClassName##RenderState* renderStateCache() override {return reinterpret_cast(mRenderStateCache);} \ - ClassName##TempData* tempData() override {return reinterpret_cast(mTempData);} \ - ClassName##TempData* tempDataCache() override {return reinterpret_cast(mTempDataCache);} \ + ClassName##RenderState* renderState() override {return reinterpret_cast(state(State_Render));} \ + ClassName##RenderState* readyState() override {return reinterpret_cast(state(State_Ready));} \ + ClassName##RenderState* editState() override {return reinterpret_cast(state(State_Edit));} \ + ClassName##TempData* renderTempData() override {return reinterpret_cast(mRenderTempData);} \ + ClassName##TempData* editTempData() override {return reinterpret_cast(mEditTempData);} \ friend class ClassName; \ - void loadCache() override { \ - *renderState() = *renderStateCache(); \ - std::swap(mTempData, mTempDataCache); \ + void syncStatePipeline() override { \ + Triple_Buffer_Lease readyLease = mStateControl.wait_mark_use_role(State_Ready); \ + auto ready = reinterpret_cast(stateByIndex(readyLease.index)); \ + auto edit = editState(); \ + if(RenderAble::version_newer(edit->version, ready->version)) *ready = *edit; \ + mStateControl.unmark_use(readyLease); \ + mStateControl.wait_swap_role(State_Ready, State_Render, [this](const Triple_Buffer_View& view) { \ + auto ready = reinterpret_cast(stateByIndex(view[State_Ready])); \ + auto render = reinterpret_cast(stateByIndex(view[State_Render])); \ + return RenderAble::version_newer(ready->version, render->version); \ + }); \ + std::swap(mRenderTempData, mEditTempData); \ if(!mRenderStart) mRenderStart = true; \ } #define D_Ptr2(ClassName) \ ClassName* q() {return reinterpret_cast(qPtr);} \ - ClassName##RenderState* renderState() override {return reinterpret_cast(mRenderState);} \ - ClassName##RenderState* renderStateCache() override {return reinterpret_cast(mRenderStateCache);} \ - ClassName##TempData* tempData() override {return reinterpret_cast(mTempData);} \ - ClassName##TempData* tempDataCache() override {return reinterpret_cast(mTempDataCache);} \ - friend class ClassName; + ClassName##RenderState* renderState() override {return reinterpret_cast(state(State_Render));} \ + ClassName##RenderState* readyState() override {return reinterpret_cast(state(State_Ready));} \ + ClassName##RenderState* editState() override {return reinterpret_cast(state(State_Edit));} \ + ClassName##TempData* renderTempData() override {return reinterpret_cast(mRenderTempData);} \ + ClassName##TempData* editTempData() override {return reinterpret_cast(mEditTempData);} \ + friend class ClassName; \ + void syncStatePipeline() override { \ + Triple_Buffer_Lease readyLease = mStateControl.wait_mark_use_role(State_Ready); \ + auto ready = reinterpret_cast(stateByIndex(readyLease.index)); \ + auto edit = editState(); \ + if(RenderAble::version_newer(edit->version, ready->version)) *ready = *edit; \ + mStateControl.unmark_use(readyLease); \ + mStateControl.wait_swap_role(State_Ready, State_Render, [this](const Triple_Buffer_View& view) { \ + auto ready = reinterpret_cast(stateByIndex(view[State_Ready])); \ + auto render = reinterpret_cast(stateByIndex(view[State_Render])); \ + return RenderAble::version_newer(ready->version, render->version); \ + }); \ + std::swap(mRenderTempData, mEditTempData); \ + if(!mRenderStart) mRenderStart = true; \ + } #define INIT_SET(className) className##Private* pd = d(); \ - className##RenderState* sc = pd->renderStateCache();\ - className##TempData* td = pd->tempDataCache(); \ + className##RenderState* sc = reinterpret_cast(pd->state(State_Edit));\ + className##TempData* td = reinterpret_cast(pd->mEditTempData); \ SpinLockGuard _guard(&pd->mBufferLock); \ RenderEditGuard _editGuard(pd); } diff --git a/YSGraphic_Core/base/MutiSelectRect.cpp b/YSGraphic_Core/base/MutiSelectRect.cpp index 33c61a8..061163b 100644 --- a/YSGraphic_Core/base/MutiSelectRect.cpp +++ b/YSGraphic_Core/base/MutiSelectRect.cpp @@ -13,7 +13,7 @@ namespace YSG { auto ret = new MutiSelectRect(); ret->init(plot, layerName); MutiSelectRectPrivate* pd = ret->d(); - MutiSelectRectRenderState* sc = pd->renderStateCache(); + MutiSelectRectRenderState* sc = reinterpret_cast(pd->state(State_Edit)); sc->mHorizontalAxis = keyAxis; sc->mVerticalAxis = valueAxis; sc->mFont = font; @@ -67,4 +67,4 @@ namespace YSG { sc->mBorderPen = pen.color().isValid() ? pen : Qt::NoPen; } -} \ No newline at end of file +} diff --git a/YSGraphic_Core/base/MutiSelectRect.h b/YSGraphic_Core/base/MutiSelectRect.h index 3ec8f00..12257c8 100644 --- a/YSGraphic_Core/base/MutiSelectRect.h +++ b/YSGraphic_Core/base/MutiSelectRect.h @@ -9,10 +9,10 @@ namespace YSG { Q_Ptr2(MutiSelectRect) void setHorizontalAxis(AbsAxis* axis); void setVerticalAxis(AbsAxis* axis); - QFont font(SRC=SRC::Auto); - QPen fontPen(SRC=SRC::Auto); - QBrush rectBrush(SRC=SRC::Auto); - QPen borderPen(SRC=SRC::Auto); + QFont font(SRC=SRC::Edit); + QPen fontPen(SRC=SRC::Edit); + QBrush rectBrush(SRC=SRC::Edit); + QPen borderPen(SRC=SRC::Edit); void setFont(const QFont& font); void setFontPen(const QPen& pen); void setRectBrush(const QBrush& brush); diff --git a/YSGraphic_Core/base/MutiSelectRect_p.h b/YSGraphic_Core/base/MutiSelectRect_p.h index 447ea4e..b5644a2 100644 --- a/YSGraphic_Core/base/MutiSelectRect_p.h +++ b/YSGraphic_Core/base/MutiSelectRect_p.h @@ -45,7 +45,7 @@ namespace YSG { // event->buttons():返回一个标志,指示当前按下的所有鼠标按钮。可以在任何鼠标事件中使用,特别是 mouseMoveEvent 中。 void mousePressEvent(QMouseEvent* event) override { if (event->button() != Qt::LeftButton) return; - MutiSelectRectRenderState* sc = renderStateCache(); + MutiSelectRectRenderState* sc = editState(); SpinLockGuard _guard(&mBufferLock); RenderEditGuard _editGuard(this); QVector &rectList = sc->mRects; @@ -68,7 +68,7 @@ namespace YSG { void mouseMoveEvent(QMouseEvent* event) override { if(!(event->buttons() & Qt::LeftButton)) return; - MutiSelectRectRenderState* sc = renderStateCache(); + MutiSelectRectRenderState* sc = editState(); SpinLockGuard _guard(&mBufferLock); RenderEditGuard _editGuard(this); QVector &rectList = sc->mRects; @@ -83,7 +83,7 @@ namespace YSG { void keyPressEvent(QKeyEvent* event) override { if (event->key() != Qt::Key_Escape || !mActive) return; - MutiSelectRectRenderState* sc = renderStateCache(); + MutiSelectRectRenderState* sc = editState(); SpinLockGuard _guard(&mBufferLock); RenderEditGuard _editGuard(this); mActive = false; @@ -93,8 +93,8 @@ namespace YSG { } void keyReleaseEvent(QKeyEvent* event) override { - MutiSelectRectRenderState* sc = renderStateCache(); - MutiSelectRectTempData* td = tempDataCache(); + MutiSelectRectRenderState* sc = editState(); + MutiSelectRectTempData* td = editTempData(); SpinLockGuard _guard(&mBufferLock); } diff --git a/YSGraphic_Core/base/Plot.cpp b/YSGraphic_Core/base/Plot.cpp index 0fd4126..83579fa 100644 --- a/YSGraphic_Core/base/Plot.cpp +++ b/YSGraphic_Core/base/Plot.cpp @@ -125,9 +125,11 @@ namespace YSG { void Plot::paintEvent(QPaintEvent* event) { Q_UNUSED(event) QPainter painter(this); - RenderAble::ColorBuffer* color = d->mPipeline.consumeReadyColor(); + auto colorLease = d->mPipeline.consumeReadyColor(); + RenderAble::ColorBuffer* color = colorLease.buffer; if(color && !color->image.isNull()) painter.drawImage(QPoint(0, 0), color->image); else painter.fillRect(rect(), d->mBackground); + if(colorLease) d->mPipeline.unmarkColor(colorLease); painter.end(); if(d->mShower) d->mShower->counterIncrease("plot paint"); } @@ -178,7 +180,8 @@ namespace YSG { able->mPrepared = false; } } - RenderAble::ColorBuffer* color = pipeline.currentRenderColor(); + auto colorLease = pipeline.waitRenderColor(); + RenderAble::ColorBuffer* color = colorLease.buffer; QColor background = d->mBackground; std::uint64_t version = pipeline.renderStateVersion; TimerThread* thread = d->mTimerThread; @@ -186,12 +189,14 @@ namespace YSG { if(thread) { PlotPrivate* privateData = d; privateData->mActiveRenderTasks.fetch_add(1, std::memory_order_acq_rel); - thread->postCpu([this, privateData, color, renderSize, background, version, thread]() { + thread->postCpu([this, privateData, colorLease, color, renderSize, background, version, thread]() { if(privateData->mDestroying.load(std::memory_order_acquire)) { + privateData->mPipeline.unmarkColor(colorLease); notifyRenderTaskDone(privateData); return; } renderColor(color, renderSize, background, version); + privateData->mPipeline.unmarkColor(colorLease); if(privateData->mDestroying.load(std::memory_order_acquire)) { notifyRenderTaskDone(privateData); return; @@ -203,6 +208,7 @@ namespace YSG { }); } else { renderColor(color, renderSize, background, version); + pipeline.unmarkColor(colorLease); finishRender(); } } @@ -222,9 +228,18 @@ namespace YSG { } color->image.detach(); color->image.fill(background); + QVector leasedData; + QVector stateLeases; QPainter painter(&color->image); { Cacl drawData("draw耗时: %1 avg: %2", d->mShower); + for(Layer* layer : mLayerList) { + for(RenderAble* cur : layer->mRenderAbles) { + if(!cur->mVisable) continue; + leasedData.append(cur->dPtr); + stateLeases.append(cur->dPtr->waitMarkStateRole(State_Render)); + } + } for(Layer* layer : mLayerList) { for(RenderAble* cur : layer->mRenderAbles) { if(!cur->mVisable) continue; @@ -232,8 +247,11 @@ namespace YSG { } } } + for(int i = 0; i < leasedData.size(); ++i) { + leasedData[i]->unmarkState(stateLeases[i]); + } painter.end(); - color->version = version; + color->version.store(version, std::memory_order_release); color->dirtyRegion = QRegion(QRect(QPoint(0, 0), size)); } void Plot::scheduleRenderTimer() { diff --git a/YSGraphic_Core/component/simple_widget.cpp b/YSGraphic_Core/component/simple_widget.cpp index e69de29..b76a866 100644 --- a/YSGraphic_Core/component/simple_widget.cpp +++ b/YSGraphic_Core/component/simple_widget.cpp @@ -0,0 +1,134 @@ +#pragma once +#include "global.h" + +// https://blog.csdn.net/MrHHHHHH/article/details/134182253 +class Input : public QLineEdit { +public: + explicit Input(QWidget* parent = nullptr) : QLineEdit(parent) { + setStyle(new Style()); + setFrame(true); + // 当光标的位置在文本编辑器中改变时,这个信号会被触发。old和new参数分别表示光标改变前后的位置。 + connect(this, &QLineEdit::cursorPositionChanged, this, [=](int nOld, int nNew){ + //qDebug().noquote() << "[" << __FILE__ << __LINE__ << "]" << "nOld :" << nOld << "nNew :" << nNew; + }); + // 当用户完成文本编辑(例如按下Enter键或点击其他区域使编辑结束)时,这个信号会被触发。 + connect(this, &QLineEdit::editingFinished, this, [=](){ + //qDebug().noquote() << "[" << __FILE__ << __LINE__ << "]" << "text :" << this->text(); + }); + // 当用户在文本编辑器中按下Enter键时,这个信号会被触发。 + connect(this, &QLineEdit::returnPressed, this, [=](){ + //qDebug().noquote() << "[" << __FILE__ << __LINE__ << "]" << "text :" << this->text(); + }); + // 当文本编辑器中的选区发生变化时,这个信号会被触发。例如,当用户选择或取消选择文本时。 + connect(this, &QLineEdit::selectionChanged, this, [=](){ + //qDebug().noquote() << "[" << __FILE__ << __LINE__ << "]" << "text :" << this->text(); + }); + // 当文本编辑器中的文本发生更改时,这个信号会被触发。参数text是改变后的文本内容。 + connect(this, &QLineEdit::textChanged, this, [=](const QString& text){ + // qDebug().noquote() << "[" << __FILE__ << __LINE__ << "]" << "text :" << text; + }); + // 当文本编辑器开始编辑新的文本时,这个信号会被触发。参数text是当前编辑的文本内容。 + connect(this, &QLineEdit::textEdited, this, [=](const QString& text){ + //qDebug().noquote() << "[" << __FILE__ << __LINE__ << "]" << "text :" << text; + }); + // update(); + } + QString unit = "MHZ"; + QFont font; + QPen pen; + QColor focus_color = Qt::red; + QColor default_color = Qt::black; +protected: + void paintEvent(QPaintEvent* event) override { + QLineEdit::paintEvent(event); // 调用原始绘制 + auto fm = QFontMetrics(font); + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing, true); + int w = width(); + int h = height(); + int pen_w = 1; + if (QApplication::focusWidget() == this) + { + painter.setPen(QPen(focus_color, pen_w)); + } else + { + painter.setPen(QPen(default_color, pen_w)); + } + painter.drawRoundedRect(rect(), h/4, h/4); + painter.setPen(pen); + painter.setFont(font); + int unitWidth = fm.horizontalAdvance(unit); + int th = fm.height(); + int x = rect().right() - unitWidth - 5; // 计算单位的绘制位置 + painter.drawText(x, height() / 2 + th / 2, unit); + setTextMargins(0, 0, unitWidth + 4, 0); // 右边留出单位的空间 + } + class Style : public QProxyStyle { + public: + void drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption* option, QPainter* painter, + const QWidget* widget) const override { + // 先调用默认的绘制 + auto t = qobject_cast(widget); + if (!t) return; + static bool it = true; + // QProxyStyle::drawPrimitive(element, option, painter, widget); + // qDebug() << "t->hasFrame() == " << t->hasFrame(); + if (it) + { + // QProxyStyle::drawPrimitive(element, option, painter, widget); + it = false; + } + // 行编辑器边框 + if (element == PE_PanelLineEdit) + { + // + } + // 行编辑器边框 + if (element == PE_FrameLineEdit) + { +// qDebug() << "lineEdit drawPrimitive " << element; +// qDebug() << "width " << option->rect.width(); + } + } + void drawComplexControl(ComplexControl control, const QStyleOptionComplex* option, QPainter* painter, + const QWidget* widget) const override { + // auto t = qobject_cast(widget); + // if (!t) return; + // qDebug() << "lineEdit drawComplexControl " << control; + // QProxyStyle::drawComplexControl(control, option, painter, widget); + } + void drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, + const QWidget* widget) const override { + // auto t = qobject_cast(widget); + // qDebug() << "lineEdit drawControl " << element; + // QProxyStyle::drawControl(element, option, painter, widget); + // if (!t) return; + } + // void drawItemText(QPainter* painter, const QRect& rect, int flags, const QPalette& pal, bool enabled, + // const QString& text, QPalette::ColorRole textRole) const override { + // + // + // } + // void drawItemPixmap(QPainter* painter, const QRect& rect, int alignment, const QPixmap& pixmap) const + // override { + // + // } + QRect subElementRect(SubElement element, const QStyleOption* option, const QWidget* widget) const override { + auto t = qobject_cast(widget); + if (!t) + { + return QProxyStyle::subElementRect(element, option, widget); + } + // qDebug() << "lineEdit subElementRect " << element; + // 这里可以自定义返回不同的 QRect 以控制子元素的大小或位置 + if (element == SE_LineEditContents) + { + QRect rect = QProxyStyle::subElementRect(element, option, widget); + // rect.adjust(5, 5, -5, -5); // 例如,让文本内容区域缩小一点 + return rect; + } + return QProxyStyle::subElementRect(element, option, widget); + } + }; +}; + diff --git a/YSGraphic_Core/plottable/Afterglow.cpp b/YSGraphic_Core/plottable/Afterglow.cpp index 68ca63d..c33d8c1 100644 --- a/YSGraphic_Core/plottable/Afterglow.cpp +++ b/YSGraphic_Core/plottable/Afterglow.cpp @@ -14,8 +14,8 @@ namespace YSG { PROP_P(Afterglow, int, initStrongValue) void Afterglow::set_frequentPointSize(int t) { AfterglowPrivate* pd = d(); - AfterglowRenderState* sc = pd->renderStateCache(); - AfterglowTempData* td = pd->tempDataCache(); + AfterglowRenderState* sc = reinterpret_cast(pd->state(State_Edit)); + AfterglowTempData* td = reinterpret_cast(pd->mEditTempData); SpinLockGuard _guard(&pd->mBufferLock); RenderEditGuard _editGuard(pd); sc->frequentPointSize = std::move(t); @@ -23,8 +23,8 @@ namespace YSG { } void Afterglow::set_powerPointSize(int t) { AfterglowPrivate* pd = d(); - AfterglowRenderState* sc = pd->renderStateCache(); - AfterglowTempData* td = pd->tempDataCache(); + AfterglowRenderState* sc = reinterpret_cast(pd->state(State_Edit)); + AfterglowTempData* td = reinterpret_cast(pd->mEditTempData); SpinLockGuard _guard(&pd->mBufferLock); RenderEditGuard _editGuard(pd); sc->powerPointSize = std::move(t); diff --git a/YSGraphic_Core/plottable/Afterglow_p.h b/YSGraphic_Core/plottable/Afterglow_p.h index b234d18..f3cbe76 100644 --- a/YSGraphic_Core/plottable/Afterglow_p.h +++ b/YSGraphic_Core/plottable/Afterglow_p.h @@ -93,7 +93,7 @@ namespace YSG { void prepareData() override { SpinLockGuard guard(&mBufferLock); - loadCache(); + syncStatePipeline(); } }; template @@ -108,7 +108,7 @@ namespace YSG { void Afterglow::BuilderT::set(Afterglow* ret) { ret->init(plot, layerName); AfterglowPrivate* pd = ret->d(); - AfterglowRenderState* sc = pd->renderStateCache(); + AfterglowRenderState* sc = reinterpret_cast(pd->state(State_Edit)); PROP_RT(FrequentAxis*, frequentAxis) PROP_RT(Axis*, powerAxis) PROP_RT(Range, frequentRange) diff --git a/YSGraphic_Core/plottable/AudioFrequent.cpp b/YSGraphic_Core/plottable/AudioFrequent.cpp index 6f31761..47a2df9 100644 --- a/YSGraphic_Core/plottable/AudioFrequent.cpp +++ b/YSGraphic_Core/plottable/AudioFrequent.cpp @@ -21,7 +21,7 @@ namespace YSG { auto ret = new AudioFrequent(); ret->init(plot, layerName); AudioFrequentPrivate* pd = ret->d(); - AudioFrequentRenderState* sc = pd->renderStateCache(); + AudioFrequentRenderState* sc = reinterpret_cast(pd->state(State_Edit)); PROP_R(int, timePointSize) PROP_R(TimeAxis*, timeAxis) PROP_R(Axis*, valueAxis) diff --git a/YSGraphic_Core/plottable/AudioFrequent_p.h b/YSGraphic_Core/plottable/AudioFrequent_p.h index f485680..2e02178 100644 --- a/YSGraphic_Core/plottable/AudioFrequent_p.h +++ b/YSGraphic_Core/plottable/AudioFrequent_p.h @@ -20,9 +20,9 @@ namespace YSG { YSG::MutiRingBuffer mMutiBuffer; void prepareData() override { SpinLockGuard guard(&mBufferLock); - loadCache(); + syncStatePipeline(); AudioFrequentRenderState *s = renderState(); - AudioFrequentTempData *d = tempData(); + AudioFrequentTempData *d = renderTempData(); if(mMutiBuffer.buffers.empty() || mMutiBuffer.n != s->timePointSize) { mMutiBuffer.resize({sizeof(double)}, s->timePointSize, s->timePointSize * 10); PerformanceShower *shower = q()->mPlot->d->mShower; @@ -46,7 +46,7 @@ namespace YSG { .arg(s->timeAxis->timePointSize())); } painter->save(); - AudioFrequentTempData *d = tempData(); + AudioFrequentTempData *d = renderTempData(); QPolygonF polyline; int start = (int)s->timeAxis->startCoord(); QPen newPen = QPen(s->color); diff --git a/YSGraphic_Core/plottable/HoverInfo.h b/YSGraphic_Core/plottable/HoverInfo.h index 0e09ee7..b88ff68 100644 --- a/YSGraphic_Core/plottable/HoverInfo.h +++ b/YSGraphic_Core/plottable/HoverInfo.h @@ -25,48 +25,48 @@ namespace YSG { virtual QVector createHoverString(AbsAxis* h, AbsAxis* v, QPoint pos); virtual ~HoverInfoRenderAbleInterFace() = default; virtual void drawHover(QPainter* painter, AbsAxis *h, AbsAxis *v) { - return getState(SRC::Render)->drawHover(painter, h, v); + return hoverState(SRC::Render)->drawHover(painter, h, v); } virtual bool hoverOK(RenderAble* able) { - return getState(SRC::Render)->hoverOK(able); + return hoverState(SRC::Render)->hoverOK(able); } virtual bool hoverTest(QPoint pos) { return true; } - bool useHoverInfo(SRC src = SRC::Auto) { - return getState(src)->useHoverInfo; + bool useHoverInfo(SRC src = SRC::Edit) { + return hoverState(src)->useHoverInfo; } void setUseHoverInfo(bool use) { SpinLockGuard g(lock()); - getState(SRC::Cache)->useHoverInfo = use; + hoverState(SRC::Edit)->useHoverInfo = use; markHoverInfoDirty(); } void setHoverInfoFont(const QFont& font) { SpinLockGuard g(lock()); - getState(SRC::Cache)->hoverInfoFont = font; + hoverState(SRC::Edit)->hoverInfoFont = font; markHoverInfoDirty(); } - QFont HoverInfoFont(SRC src = SRC::Auto) { - return getState(src)->hoverInfoFont; + QFont HoverInfoFont(SRC src = SRC::Edit) { + return hoverState(src)->hoverInfoFont; } - QBrush hoverInfoBackgroundBrush(SRC src = SRC::Auto) { - return getState(src)->hoverInfoBrush; + QBrush hoverInfoBackgroundBrush(SRC src = SRC::Edit) { + return hoverState(src)->hoverInfoBrush; } void setHoverInfoBackgroundBrush(const QBrush& brush) { SpinLockGuard g(lock()); - getState(SRC::Cache)->hoverInfoBrush = brush.color().isValid() ? brush : Qt::NoBrush; + hoverState(SRC::Edit)->hoverInfoBrush = brush.color().isValid() ? brush : Qt::NoBrush; markHoverInfoDirty(); } - QPen hoverInfoPen(SRC src = SRC::Auto) { - return getState(src)->hoverInfoPen; + QPen hoverInfoPen(SRC src = SRC::Edit) { + return hoverState(src)->hoverInfoPen; } void setHoverInfoPen(const QPen& pen) { SpinLockGuard g(lock()); - getState(SRC::Cache)->hoverInfoPen = pen.color().isValid() ? pen : Qt::NoPen; + hoverState(SRC::Edit)->hoverInfoPen = pen.color().isValid() ? pen : Qt::NoPen; markHoverInfoDirty(); } void getHoverInfoContentsMargins(int& left, int& top, int& right, int& bottom, SRC src) { - auto s = getState(src); + auto s = hoverState(src); left = s->hoverInfoLeft; top = s->hoverInfoTop; right = s->hoverInfoRight; @@ -75,7 +75,7 @@ namespace YSG { void setHoverInfoContentsMargins(int left, int top, int right, int bottom) { SpinLockGuard g(lock()); - auto sc = getState(SRC::Cache); + auto sc = hoverState(SRC::Edit); sc->hoverInfoLeft = left; sc->hoverInfoTop = top; sc->hoverInfoRight = right; @@ -83,7 +83,7 @@ namespace YSG { markHoverInfoDirty(); } protected: - virtual HoverInfoRenderState* getState(SRC src) = 0; + virtual HoverInfoRenderState* hoverState(SRC src) = 0; virtual SpinLock* lock() = 0; virtual void markHoverInfoDirty() {} }; @@ -94,8 +94,8 @@ namespace YSG { SpinLock* lock() override { return &mtx; } - HoverInfoRenderState* getState(SRC src) override { - if(src == SRC::Cache){ + HoverInfoRenderState* hoverState(SRC src) override { + if(src == SRC::Edit) { return ≻ } return &s; @@ -120,9 +120,9 @@ namespace YSG { SpinLock* lock() override { return &that()->dPtr->mBufferLock; } - HoverInfoRenderState* getState(SRC src) override { + HoverInfoRenderState* hoverState(SRC src) override { auto t = that(); - return dynamic_cast(t->dPtr->getState(src)); + return dynamic_cast(t->dPtr->state(src)); } void markHoverInfoDirty() override { that()->markStateDirty(); diff --git a/YSGraphic_Core/plottable/Planisphere.cpp b/YSGraphic_Core/plottable/Planisphere.cpp index cc5f2fb..61a2441 100644 --- a/YSGraphic_Core/plottable/Planisphere.cpp +++ b/YSGraphic_Core/plottable/Planisphere.cpp @@ -34,7 +34,7 @@ namespace YSG { auto ret = new Planisphere(); ret->init(plot, layerName); PlanispherePrivate* pd = ret->d(); - PlanisphereRenderState* sc = pd->renderStateCache(); + PlanisphereRenderState* sc = reinterpret_cast(pd->state(State_Edit)); PROP_R(Axis*, IAxis) PROP_R(Axis*, QAxis) PROP_R(Range, IRange) @@ -47,7 +47,7 @@ namespace YSG { } void Planisphere::setToAxisCenter() { - PlanisphereRenderState *s = d()->renderStateCache(); + PlanisphereRenderState *s = reinterpret_cast(d()->state(State_Edit)); double w = mPlot->width(), h = mPlot->height(); double l = w < h ? w : h; double iL = s->IAxis->coordRange().size()/w * l/2; diff --git a/YSGraphic_Core/plottable/Planisphere_p.h b/YSGraphic_Core/plottable/Planisphere_p.h index e5be19f..dce857c 100644 --- a/YSGraphic_Core/plottable/Planisphere_p.h +++ b/YSGraphic_Core/plottable/Planisphere_p.h @@ -65,8 +65,8 @@ namespace YSG { void prepareData() override { SpinLockGuard guard(&mBufferLock); - loadCache(); - PlanisphereTempData *d = tempData(); + syncStatePipeline(); + PlanisphereTempData *d = renderTempData(); PlanisphereRenderState *s = renderState(); int times = qMax(5, (s->continueMillisecond * q()->mPlot->d->mRefreshTimesPreSecond) / 1000); for(PlanisphereData& data : d->mDataList) { diff --git a/YSGraphic_Core/plottable/Spectrum.cpp b/YSGraphic_Core/plottable/Spectrum.cpp index 8578526..128a49c 100644 --- a/YSGraphic_Core/plottable/Spectrum.cpp +++ b/YSGraphic_Core/plottable/Spectrum.cpp @@ -50,7 +50,7 @@ namespace YSG { auto ret = new Spectrum; ret->init(plot, layerName); SpectrumPrivate* pd = ret->d(); - SpectrumRenderState* sc = pd->renderStateCache(); + SpectrumRenderState* sc = reinterpret_cast(pd->state(State_Edit)); PROP_R(FrequentAxis*, frequentAxis) PROP_R(Axis*, powerAxis); PROP_R(int, frequentPointSize); diff --git a/YSGraphic_Core/plottable/Spectrum.h b/YSGraphic_Core/plottable/Spectrum.h index 8299abe..222b7ac 100644 --- a/YSGraphic_Core/plottable/Spectrum.h +++ b/YSGraphic_Core/plottable/Spectrum.h @@ -31,19 +31,19 @@ namespace YSG { PROP(QPen, middleFrequentPen); PROP(QBrush, sweepRectBrush); void giveData(const QVector &lineData); - double getPower(double frequent, bool& ok, SRC=SRC::Cache); + double getPower(double frequent, bool& ok, SRC=SRC::Edit); void addCustomMarker(double frequent); void addCustomLineMarker(double frequent); void removeCustomMarker(double frequent); - void removeCurrentMarker(SRC=SRC::Auto); - void clearAllCustomMarker(SRC=SRC::Auto); - int selectLineMarkerSize(SRC=SRC::Auto); - int curSelectMarkerIndex(SRC=SRC::Auto); + void removeCurrentMarker(SRC=SRC::Edit); + void clearAllCustomMarker(SRC=SRC::Edit); + int selectLineMarkerSize(SRC=SRC::Edit); + int curSelectMarkerIndex(SRC=SRC::Edit); void setSelectedLineMarker(int markerIndex); - void selectNext(SRC=SRC::Auto); - void unSelectMarker(SRC=SRC::Auto); - void selectPrevious(SRC=SRC::Auto); - double getMarkFrequent(int markIndex, SRC=SRC::Auto); + void selectNext(SRC=SRC::Edit); + void unSelectMarker(SRC=SRC::Edit); + void selectPrevious(SRC=SRC::Edit); + double getMarkFrequent(int markIndex, SRC=SRC::Edit); void setMarkerFrequent(int markerIndex, double frequent); void setCurrentMarkerFrequent(double frequent); struct Builder; diff --git a/YSGraphic_Core/plottable/Spectrum_p.h b/YSGraphic_Core/plottable/Spectrum_p.h index 02030e8..8f76661 100644 --- a/YSGraphic_Core/plottable/Spectrum_p.h +++ b/YSGraphic_Core/plottable/Spectrum_p.h @@ -208,14 +208,14 @@ namespace YSG { void draw(QPainter* painter) override; void prepareData() override { SpinLockGuard guard(&mBufferLock); - loadCache(); + syncStatePipeline(); auto s = renderState(); - auto sc = renderStateCache(); + auto sc = editState(); } bool selectTest(const QPointF& pos) override { - auto sc = renderStateCache(); + auto sc = editState(); double frequent = sc->frequentAxis->pixelToCoord(pos.x(), SRC::Render); bool ok; double power = sc->getY(frequent, ok); @@ -225,7 +225,7 @@ namespace YSG { void setHoverState(const QPoint& pos, bool active) override { SpinLockGuard guard(&mBufferLock); RenderEditGuard editGuard(this); - SpectrumRenderState* sc = renderStateCache(); + SpectrumRenderState* sc = editState(); sc->hoverInfoPos = pos; sc->hoverInfoActive = active; } diff --git a/YSGraphic_Core/plottable/SweepFrequent.cpp b/YSGraphic_Core/plottable/SweepFrequent.cpp index 7c3eae6..a0db226 100644 --- a/YSGraphic_Core/plottable/SweepFrequent.cpp +++ b/YSGraphic_Core/plottable/SweepFrequent.cpp @@ -36,7 +36,7 @@ namespace YSG { auto ret = new SweepFrequent(); ret->init(plot, layerName); SweepFrequentPrivate* pd = ret->d(); - SweepFrequentRenderState* sc = pd->renderStateCache(); + SweepFrequentRenderState* sc = reinterpret_cast(pd->state(State_Edit)); PROP_R(Axis*, frequentAxis) PROP_R(Axis*, powerAxis) PROP_R(Range, frequentRange) diff --git a/YSGraphic_Core/plottable/SweepFrequent_p.h b/YSGraphic_Core/plottable/SweepFrequent_p.h index cfd0b00..8a7fc22 100644 --- a/YSGraphic_Core/plottable/SweepFrequent_p.h +++ b/YSGraphic_Core/plottable/SweepFrequent_p.h @@ -44,9 +44,9 @@ namespace YSG { protected: void prepareData() override { SpinLockGuard guard(&mBufferLock); - loadCache(); + syncStatePipeline(); SweepFrequentRenderState *s = renderState(); - SweepFrequentTempData *d = tempData(); + SweepFrequentTempData *d = renderTempData(); if( mBlockFrquentPointSize != s->blockFrequentPointSize || mBlockNum != s->blockNum || diff --git a/YSGraphic_Core/plottable/WaterFall.cpp b/YSGraphic_Core/plottable/WaterFall.cpp index 6a13745..4eee7c0 100644 --- a/YSGraphic_Core/plottable/WaterFall.cpp +++ b/YSGraphic_Core/plottable/WaterFall.cpp @@ -27,7 +27,7 @@ namespace YSG { auto ret = new WaterFall(); ret->init(plot, layerName); WaterFallPrivate* pd = ret->d(); - WaterFallRenderState* sc = pd->renderStateCache(); + WaterFallRenderState* sc = reinterpret_cast(pd->state(State_Edit)); PROP_R(FrequentAxis*, frequentAxis) PROP_R(TimeAxis*, timeAxis) PROP_R(Range, frequentRange) diff --git a/YSGraphic_Core/plottable/WaterFall_p.h b/YSGraphic_Core/plottable/WaterFall_p.h index 075c5ac..d89e24b 100644 --- a/YSGraphic_Core/plottable/WaterFall_p.h +++ b/YSGraphic_Core/plottable/WaterFall_p.h @@ -1,7 +1,10 @@ #pragma once +#include +#include #include #include - +#include +#include "Core/Base/RingBuffer.hpp" #include "../Axis/FrequentAxis_p.h" #include "../Axis/TimeAxis_p.h" #include "../RenderAble.h" @@ -11,47 +14,85 @@ #include "../base/Plot_p.h" #include "WaterFall.h" - namespace YSG { - - - struct WaterFallData { int mTick; QVector mFrequent; }; - struct WaterFallTempData : TempData { std::list mDataList; }; - struct WaterFallRenderState : RenderState, HoverInfoRenderState, WaterFall_Prop { - }; - + struct WaterFallRingBuffer { + Psc::StreamRingBuffer_ST buffer; + std::vector recordBuffer; + std::vector snapshotBuffer; + std::vector rowBuffer; + std::size_t recordByteSize{}; + std::size_t rowByteSize{}; + int rowCount{}; + int colCount{}; + int dataCount{}; + bool match(int col, int row) const { + return colCount == col && rowCount == row && recordByteSize; + } + void resize(int col, int row) { + colCount = col; + rowCount = row; + dataCount = 0; + rowByteSize = sizeof(double) * colCount; + recordByteSize = rowByteSize + sizeof(int); + recordBuffer.resize(recordByteSize); + snapshotBuffer.resize(recordByteSize * rowCount); + rowBuffer.resize(colCount); + buffer.init(recordByteSize * rowCount); + } + void pushData(const double* data, int tick) { + if(dataCount == rowCount) { + buffer.skip(recordByteSize); + --dataCount; + } + std::memcpy(recordBuffer.data(), data, rowByteSize); + std::memcpy(recordBuffer.data() + rowByteSize, &tick, sizeof(tick)); + buffer.write(recordBuffer.data(), recordByteSize); + ++dataCount; + } + int snapshot() { + buffer.peek_best_effort(snapshotBuffer.data(), recordByteSize * dataCount); + return dataCount; + } + const double* frequentData(int row) { + std::memcpy(rowBuffer.data(), snapshotBuffer.data() + row * recordByteSize, rowByteSize); + return rowBuffer.data(); + } + int tick(int row) const { + int value; + std::memcpy(&value, snapshotBuffer.data() + row * recordByteSize + rowByteSize, sizeof(value)); + return value; + } + }; struct WaterFallPrivate : RenderData { D_Ptr(WaterFall) - YSG::MutiRingBuffer mutiBuffer; + WaterFallRingBuffer ringBuffer; QImage image; - int listByteSize{}; bool selectTest(const QPointF& pos) override {return true;} void setHoverState(const QPoint& pos, bool active) override { SpinLockGuard guard(&mBufferLock); RenderEditGuard editGuard(this); - WaterFallRenderState* sc = renderStateCache(); + WaterFallRenderState* sc = editState(); sc->hoverInfoPos = pos; sc->hoverInfoActive = active; } void prepareData() override { SpinLockGuard guard(&mBufferLock); - loadCache(); - WaterFallTempData* data = tempData(); + syncStatePipeline(); + WaterFallTempData* data = renderTempData(); const WaterFallRenderState* s = renderState(); int colCount = s->frequentPointSize, rowCount = s->timeAxis->timePointSize(); - listByteSize = colCount * (int)sizeof(double); - if(mutiBuffer.n != rowCount || mutiBuffer.buffers.empty() || mutiBuffer.buffers[0].l != listByteSize) { - mutiBuffer.resize({listByteSize, sizeof(int)}, rowCount, rowCount * 10); + if(!ringBuffer.match(colCount, rowCount)) { + ringBuffer.resize(colCount, rowCount); } for(WaterFallData& wd : data->mDataList) { QVector& frequentData = wd.mFrequent; @@ -59,16 +100,13 @@ namespace YSG { qDebug() << "WaterFall 舍弃数据 colCount == " << colCount << " dataSize == " << frequentData.size() << "s FrequentRectCount==" << s->frequentPointSize << - "sc FrequentRectCount==" << renderStateCache()->frequentPointSize; + "sc FrequentRectCount==" << editState()->frequentPointSize; break; } - mutiBuffer.pushData({frequentData.data(), &wd.mTick}); + ringBuffer.pushData(frequentData.data(), wd.mTick); } data->mDataList.clear(); } - - - void draw(QPainter* painter) override { WaterFallRenderState* s = renderState(); PerformanceShower *shower = q()->mPlot->d->mShower; @@ -76,7 +114,7 @@ namespace YSG { shower->mInfoMap["FrequentRectCount"] = PerformanceLine(QString("FrequentRectCount:%1 timePointSize: %2") .arg(s->frequentPointSize).arg(s->timeAxis->timePointSize())); } - WaterFallTempData* data = tempData(); + WaterFallTempData* data = renderTempData(); AbsAxis *hAxis = s->frequentAxis; TimeAxis *vAxis = s->timeAxis; Range hRange = s->frequentRange, vRange = s->timeAxis->coordRange(); @@ -97,43 +135,27 @@ namespace YSG { } double valueStartCoord = s->powerRange.lower; double rate = 256.0 / s->powerRange.size(); - - - auto data2 = mutiBuffer.buffers[0].list(); - auto l2 = mutiBuffer.buffers[1].list(); + int bufferDataCount = ringBuffer.snapshot(); QVector& mColorMap = Global::instance()->mColorMap; { Cacl c("waterfull setTime:%1", q()->mPlot->d->mShower); int startTick = (int)s->timeAxis->startCoord(); - // 不用 mMutiBuffer.buffers[0].f 的话,可能会出现一种情况那就是 - // 意外的通过了 tickOffset < 0 || tickOffset >= rowCount 导致显示0值时的颜色 - // 这种意外的原因时0值的位置 默认tick值0 在当前坐标轴显示的tick范围内 - for(int row = 0; row < mutiBuffer.buffers[0].f; ++row) { - auto list = (double*)(data2+row*listByteSize); - int tick = *(l2 + row); + for(int row = 0; row < bufferDataCount; ++row) { + int bufferRow = bufferDataCount - row - 1; + auto list = ringBuffer.frequentData(bufferRow); + int tick = ringBuffer.tick(bufferRow); int tickOffset = tick - startTick; - // 瀑布图数据对应的 tick 可能不是 timeTick轴能显示的 if(tickOffset < 0 || tickOffset >= rowCount) continue; QRgb* scanLine = reinterpret_cast(image.scanLine(tickOffset)); - - - //std::string color_offset_line = "row: " + std::to_string(row) - // + " tick: " + std::to_string(tick) - // + " tick off: " + std::to_string(tickOffset) + " "; for (int col = 0; col < colCount; ++col) { int colorOffset = int((list[col] - valueStartCoord) * rate); if (colorOffset < 0 || colorOffset > 255) { qDebug() << "colorOffset:" << colorOffset << " value: " << list[col] << s->frequentRange; } - //color_offset_line += std::to_string(colorOffset) + ","; scanLine[col] = mColorMap.at(clamp(colorOffset, 0, 255)); } - - //std::cout << color_offset_line<< std::endl; } } - - double x = hAxis->coordToPixel(hRange.lower, SRC::Render); double y = vAxis->coordToPixel(vRange.lower, SRC::Render); double w = hAxis->coordToPixel(hRange.upper, SRC::Render) - x; @@ -152,5 +174,4 @@ namespace YSG { } } }; - }