Files
Renderive/YSGraphic_Core/Axis/Time_Axis_p.h
T
2026-07-28 10:54:38 +08:00

250 lines
8.6 KiB
C++

#pragma once
#include <QTime>
#include <cstdint>
#include <cstring>
#include <vector>
#include "../architecture/Bounded_Input_Buffer.h"
#include "Abs_Axis_p.h"
#include "Core/Base/RingBuffer.hpp"
#include "Time_Axis.h"
namespace YSG {
struct Time_Ticker {
bool mStartCoordToEndCoord = true;
// 最小值的范围 lower在这里面循环变化
int mLower = 0, mTimePointSize{};
int mLowerMin{}, mLowerMax{}; // 闭区间
int mTickStart = 0, mTickSpace = 4;
[[nodiscard]] int upper() const {
return mLower - 1 + mTimePointSize;
}
void setTickSpace(int tickSpace) {
if (mTickSpace == tickSpace)
return;
mTickSpace = tickSpace;
mTickStart = 0;
}
void setTimePointSize(int time_point_size) {
if (mTimePointSize == time_point_size)
return;
mTimePointSize = time_point_size;
// 除2怕溢出
mLowerMin = std::numeric_limits<int>::min() / 2;
mLowerMax = std::numeric_limits<int>::max() / 2 - time_point_size + 1;
mTickStart = 0;
}
std::pair<int, bool> getNewDataTickInfo() {
{
// 获取 坐标轴的起点
if (mStartCoordToEndCoord) {
if (mLower != mLowerMin)
mLower--;
else {
mLower = mLowerMax;
}
}
else {
if (mLower != mLowerMax)
mLower++;
else {
mLower = mLowerMin;
}
}
}
mTickStart = ++mTickStart % mTickSpace;
int endIndex = mLower + mTimePointSize - 1;
auto startIndex = mLower;
if (mTickStart == 1) {
return {mStartCoordToEndCoord ? startIndex : endIndex, true};
}
return {mStartCoordToEndCoord ? startIndex : endIndex, false};
}
};
struct TimeTick {
QTime mTime;
int mTick{};
};
struct Time_Axis_Input_Data : Abs_Axis_Input_Data {
Bounded_Input_Buffer mData;
Bounded_Input_Buffer mAllTime;
std::vector<TimeTick> mTickReadBuffer;
void push_time(const QTime& time) {
mAllTime.push(&time, sizeof(time));
}
void push_tick(const TimeTick& tick) {
mData.push(&tick, sizeof(tick));
}
template <typename Handler>
void read_all_time(Handler handler) {
mAllTime.read_all([&handler](const void* data, std::size_t size) {
(void)size;
QTime time;
std::memcpy(&time, data, sizeof(time));
handler(time);
});
}
template <typename Handler>
void read_all_tick_reverse(Handler handler) {
mTickReadBuffer.clear();
mData.read_all([this](const void* data, std::size_t size) {
(void)size;
TimeTick tick;
std::memcpy(&tick, data, sizeof(tick));
mTickReadBuffer.push_back(tick);
});
for (int i = static_cast<int>(mTickReadBuffer.size()) - 1; i >= 0; --i) {
handler(mTickReadBuffer[static_cast<std::size_t>(i)]);
}
}
void clear() override {
mData.clear();
mAllTime.clear();
}
std::uint64_t pending_count() const override {
return mData.pending_count() + mAllTime.pending_count();
}
std::uint64_t dropped_count() const override {
return mData.dropped_count() + mAllTime.dropped_count();
}
std::uint64_t pushed_count() const override {
return mData.pushed_count() + mAllTime.pushed_count();
}
};
struct Time_Axis_Render_State : Abs_Axis_Render_State, Time_Axis_Prop {
int tickSpace = 4;
int getTickSpaceHint(SRC src = SRC::Edit) {
QFontMetrics fm(font);
double rate = (double)time_point_size / (double)pixel_size;
double ret = rate * (tick_pixel_space + (orientation == Qt::Horizontal ? fm.horizontalAdvance(time_format) : fm.height()));
return std::max(1, (int)ret);
}
};
struct Time_Axis_Private : Typed_Render_Data_Base<Abs_Axis_Private, Time_Axis, Time_Axis_Render_State, Time_Axis_Input_Data> {
friend class Time_Axis;
Time_Ticker mTimeTicker{};
int mTickPixelSpace;
QFont mFont;
QString mTimeFormat;
Psc::StreamRingBuffer_ST buffer;
std::vector<QTime> mTimeSnapshot;
int mTimeDataCount{};
std::list<TimeTick> mData;
void resize_time_buffer(int count) {
buffer.init(sizeof(QTime) * count);
mTimeSnapshot.resize(count);
mTimeDataCount = 0;
}
void push_time(const QTime& time) {
if (mTimeDataCount == mTimeTicker.mTimePointSize) {
QTime ignored;
std::size_t len = sizeof(QTime);
buffer.read(&ignored, len);
--mTimeDataCount;
}
buffer.write(&time, sizeof(QTime));
++mTimeDataCount;
}
void snapshot_time_buffer() {
buffer.peek_best_effort(mTimeSnapshot.data(), sizeof(QTime) * mTimeDataCount);
}
QTime time_by_offset(int offset) const {
int index = mTimeTicker.mStartCoordToEndCoord ? mTimeDataCount - 1 - offset : offset - (mTimeTicker.mTimePointSize - mTimeDataCount);
if (index < 0 || index >= mTimeDataCount)
return {};
return mTimeSnapshot[index];
}
void prepare_data() override {
sync_state_pipeline();
auto d = render_input_data();
auto s = render_state();
Triple_Buffer_Lease inputLease = mInputControl.wait_mark_use_role(Input_Edit);
Triple_Buffer_Lease stateLease = mStateControl.wait_mark_use_role(State_Edit);
auto sc = reinterpret_cast<Time_Axis_Render_State*>(state_by_index(stateLease.index));
bool refreshSpace = false;
if (mTimeTicker.mTimePointSize != s->time_point_size) {
mTimeTicker.setTimePointSize(s->time_point_size);
resize_time_buffer(s->time_point_size);
mData.clear();
refreshSpace = true;
}
if (mTickPixelSpace != s->tick_pixel_space) {
mTickPixelSpace = s->tick_pixel_space;
refreshSpace = true;
}
if (mFont != s->font) {
mFont = s->font;
refreshSpace = true;
}
if (mTimeFormat != s->time_format) {
mTimeFormat = s->time_format;
if (s->orientation == Qt::Horizontal) {
refreshSpace = true;
}
}
if (refreshSpace) {
s->tickSpace = s->getTickSpaceHint();
sc->tickSpace = s->tickSpace;
if (mTimeTicker.mTickSpace != s->tickSpace) {
mTimeTicker.setTickSpace(s->tickSpace);
mData.resize(0);
}
}
s->coord_start = mTimeTicker.mLower;
s->coord_length = mTimeTicker.mTimePointSize;
sc->coord_start = mTimeTicker.mLower;
sc->coord_length = mTimeTicker.mTimePointSize;
int lowwer = mTimeTicker.mLower;
int upper = mTimeTicker.upper();
if (lowwer > upper)
std::swap(lowwer, upper);
d->read_all_time([this](const QTime& time) {
push_time(time);
});
snapshot_time_buffer();
d->read_all_tick_reverse([this](const TimeTick& tick) {
mData.push_front(tick);
});
clear_render_input();
while (!mData.empty()) {
int tick = mData.back().mTick;
if (tick < lowwer || tick > upper) {
mData.pop_back();
}
else {
break;
}
}
int i = 0;
ticks.clear();
labels.clear();
for (TimeTick& t : mData) {
ticks.append(t.mTick);
labels.append(t.mTime.toString(s->time_format));
++i;
}
mStateControl.unmark_use(stateLease);
mInputControl.unmark_use(inputLease);
}
QVector<QString> create_label_vector(const QVector<double>& ticks, SRC src) override {
return labels;
}
QVector<double> create_tick_vector(double tickStep, const Range& range) override {
return ticks;
}
QVector<double> create_sub_tick_vector(int subTickCount, const QVector<double>& ticks, const Range& range) override {
return {};
}
// 最小值的范围 lower在这里面循环变化
int mLower = 0, mLowerMin = 0, mLowerMax{}; // 闭区间
int mTickStart = 0;
QVector<QString> labels;
QVector<double> ticks;
void draw(QPainter* painter) override {
Abs_Axis_Private::draw(painter);
}
QString get_tick_label(double tick, SRC src) override {
auto render_state = reinterpret_cast<Time_Axis_Render_State*>(state(src));
return q()->tick_to_time((int)tick, src).toString(render_state->time_format);
}
};
} // namespace YSG