204 lines
7.0 KiB
C++
204 lines
7.0 KiB
C++
#pragma once
|
|
#include "Abs_Axis_p.h"
|
|
#include "Core/Base/RingBuffer.hpp"
|
|
#include "Time_Axis.h"
|
|
#include <cstdint>
|
|
#include <cstring>
|
|
#include <QTime>
|
|
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 {
|
|
std::list<TimeTick> mData;
|
|
std::list<QTime> mAllTime;
|
|
void clear() override {
|
|
mData.clear();
|
|
mAllTime.clear();
|
|
}
|
|
};
|
|
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);
|
|
for (QTime& time : d->mAllTime) {
|
|
push_time(time);
|
|
}
|
|
snapshot_time_buffer();
|
|
d->mAllTime.clear();
|
|
mData.splice(mData.begin(), d->mData);
|
|
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);
|
|
}
|
|
};
|
|
}
|
|
|