1
0
Fork 0
mirror of https://github.com/gwm17/implot.git synced 2024-11-26 20:28:50 -05:00

Merge pull request #6 from ozlb/master

PlotDigital
This commit is contained in:
Evan Pezent 2020-05-05 13:45:36 -05:00 committed by GitHub
commit 8253189fc8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 261 additions and 17 deletions

View File

@ -49,6 +49,7 @@ ImPlotStyle::ImPlotStyle() {
MarkerWeight = 1;
ErrorBarSize = 5;
ErrorBarWeight = 1.5;
DigitalBitHeight = 7;
Colors[ImPlotCol_Line] = IM_COL_AUTO;
Colors[ImPlotCol_Fill] = IM_COL_AUTO;
@ -327,6 +328,8 @@ struct ImPlotContext {
ImVector<ImGuiColorMod> ColorModifiers; // Stack for PushStyleColor()/PopStyleColor()
ImVector<ImGuiStyleMod> StyleModifiers; // Stack for PushStyleVar()/PopStyleVar()
ImNextPlotData NextPlotData;
// Digital plot item count
int DigitalPlotItemCnt;
};
/// Global plot context
@ -1051,6 +1054,8 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
gp.Extents.Max.y = -INFINITY;
// clear item names
gp.LegendLabels.Buf.resize(0);
// reset digital plot items count
gp.DigitalPlotItemCnt = 0;
return true;
}
@ -1463,7 +1468,8 @@ static const ImPlotStyleVarInfo GPlotStyleVarInfo[] =
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, MarkerSize) }, // ImPlotStyleVar_MarkerSize
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, MarkerWeight) }, // ImPlotStyleVar_MarkerWeight
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, ErrorBarSize) }, // ImPlotStyleVar_ErrorBarSize
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, ErrorBarWeight) } // ImPlotStyleVar_ErrorBarWeight
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, ErrorBarWeight) }, // ImPlotStyleVar_ErrorBarWeight
{ ImGuiDataType_S32, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, DigitalBitHeight) } // ImPlotStyleVar_DigitalBitHeight
};
static const ImPlotStyleVarInfo* GetPlotStyleVarInfo(ImPlotStyleVar idx)
@ -2202,4 +2208,91 @@ void PlotLabel(const char* text, float x, float y, bool vertical, const ImVec2&
PopPlotClipRect();
}
template <typename Getter>
inline void PlotDigitalEx(const char* label_id, Getter getter, int count, int offset)
{
IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "Plot() Needs to be called between BeginPlot() and EndPlot()!");
ImPlotItem* item = RegisterItem(label_id);
if (!item->Show)
return;
ImDrawList & DrawList = *ImGui::GetWindowDrawList();
const bool rend_line = gp.Style.Colors[ImPlotCol_Line].w != 0 && gp.Style.LineWeight > 0;
if (gp.Style.Colors[ImPlotCol_Line].w != -1)
item->Color = gp.Style.Colors[ImPlotCol_Line];
// find data extents
if (gp.FitThisFrame) {
for (int i = 0; i < count; ++i) {
ImVec2 p = getter(i);
FitPoint(p);
}
}
ImGui::PushClipRect(gp.BB_Grid.Min, gp.BB_Grid.Max, true);
bool cull = HasFlag(gp.CurrentPlot->Flags, ImPlotFlags_CullData);
const float line_weight = item->Highlight ? gp.Style.LineWeight * 2 : gp.Style.LineWeight;
// render digital signals as "pixel bases" rectangles
if (count > 1 && rend_line) {
//
const float mx = (gp.PixelRange.Max.x - gp.PixelRange.Min.x) / (gp.CurrentPlot->XAxis.Max - gp.CurrentPlot->XAxis.Min);
int pixY_0 = line_weight;
int pixY_1 = gp.Style.DigitalBitHeight;
int pixY_Offset = 20;//20 pixel from bottom due to mouse cursor label
int pixY_chOffset = pixY_1 + 3; //3 pixels between channels
ImVec2 pMin, pMax;
float y0 = (gp.PixelRange.Min.y) + ((-pixY_chOffset * gp.DigitalPlotItemCnt) - pixY_0 - pixY_Offset);
float y1 = (gp.PixelRange.Min.y) + ((-pixY_chOffset * gp.DigitalPlotItemCnt) - pixY_1 - pixY_Offset);
const int segments = count - 1;
int i1 = offset;
for (int s = 0; s < segments; ++s) {
const int i2 = (i1 + 1) % count;
ImVec2 itemData1 = getter(i1);
ImVec2 itemData2 = getter(i2);
i1 = i2;
pMin.x = gp.PixelRange.Min.x + mx * (itemData1.x - gp.CurrentPlot->XAxis.Min);
pMin.y = (gp.PixelRange.Min.y) + ((-pixY_chOffset * gp.DigitalPlotItemCnt) - pixY_Offset);
pMax.x = gp.PixelRange.Min.x + mx * (itemData2.x - gp.CurrentPlot->XAxis.Min);
pMax.y = ((int) itemData1.y == 0) ? y0 : y1;
//plot only one rectangle for same digital state
while (((s+2) < segments) && ((int) itemData1.y == (int) itemData2.y)) {
const int i2 = (i1 + 1) % count;
itemData2 = getter(i2);
pMax.x = gp.PixelRange.Min.x + mx * (itemData2.x - gp.CurrentPlot->XAxis.Min);
i1 = i2;
s++;
}
//do not extend plot outside plot range
if (pMin.x < gp.PixelRange.Min.x) pMin.x = gp.PixelRange.Min.x;
if (pMax.x < gp.PixelRange.Min.x) pMax.x = gp.PixelRange.Min.x;
if (pMin.x > gp.PixelRange.Max.x) pMin.x = gp.PixelRange.Max.x;
if (pMax.x > gp.PixelRange.Max.x) pMax.x = gp.PixelRange.Max.x;
//plot a rectangle that extends up to x2 with y1 height
if ((pMax.x > pMin.x) && (!cull || gp.BB_Grid.Contains(pMin) || gp.BB_Grid.Contains(pMax))) {
auto colAlpha = item->Color;
colAlpha.w = item->Highlight ? 1.0 : 0.9;
DrawList.AddRectFilled(pMin, pMax, GetColorU32(colAlpha));
}
}
gp.DigitalPlotItemCnt++;
}
ImGui::PopClipRect();
}
void PlotDigital(const char* label_id, const float* xs, const float* ys, int count, int offset, int stride) {
Getter2D getter(xs,ys,stride);
return PlotDigitalEx(label_id, getter, count, offset);
}
void PlotDigital(const char* label_id, ImVec2 (*getter_func)(void* data, int idx), void* data, int count, int offset) {
GetterFuncPtrImVec2 getter(getter_func,data);
return PlotDigitalEx(label_id, getter, count, offset);
}
} // namespace ImGui

View File

@ -88,6 +88,7 @@ enum ImPlotStyleVar_ {
ImPlotStyleVar_MarkerWeight, // float, outline weight of markers in pixels
ImPlotStyleVar_ErrorBarSize, // float, error bar whisker width in pixels
ImPlotStyleVar_ErrorBarWeight, // float, error bar whisker weight in pixels
ImPlotStyleVar_DigitalBitHeight, // int, digital channels bit height (at 1)
ImPlotStyleVar_COUNT
};
@ -121,6 +122,7 @@ struct ImPlotStyle {
float MarkerWeight; // = 1, outline weight of markers in pixels
float ErrorBarSize; // = 5, error bar whisker width in pixels
float ErrorBarWeight; // = 1.5, error bar whisker weight in pixels
int DigitalBitHeight; // = 7, digital channels bit height (at 1)
ImVec4 Colors[ImPlotCol_COUNT]; // array of plot specific colors
ImPlotStyle();
};
@ -173,6 +175,9 @@ void PlotErrorBars(const char* label_id, ImVec4 (*getter)(void* data, int idx),
void PlotPieChart(const char** label_ids, float* values, int count, const ImVec2& center, float radius, bool show_percents = true, float angle0 = 90);
// Plots a text label at point x,y.
void PlotLabel(const char* text, float x, float y, bool vertical = false, const ImVec2& pixel_offset = ImVec2(0,0));
// Plots digital channels.
void PlotDigital(const char* label_id, const float* xs, const float* ys, int count, int offset = 0, int stride = sizeof(float) + sizeof(bool));
void PlotDigital(const char* label_id, ImVec2 (*getter)(void* data, int idx), void* data, int count, int offset = 0);
//-----------------------------------------------------------------------------
// Plot Queries

View File

@ -46,6 +46,12 @@ struct ScrollingData {
Offset = (Offset + 1) % MaxSize;
}
}
void Erase() {
if (Data.size() > 0) {
Data.clear();
Offset = 0;
}
}
};
struct RollingData {
@ -81,7 +87,7 @@ namespace ImGui {
void ShowImPlotDemoWindow(bool* p_open) {
ImVec2 main_viewport_pos = ImGui::GetMainViewport()->Pos;
//ImVec2 main_viewport_pos = ImGui::GetMainViewport()->Pos;
ImGui::SetNextWindowPos(ImVec2(50, 50), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(520, 750), ImGuiCond_FirstUseEver);
ImGui::Begin("ImPlot Demo", p_open);
@ -513,6 +519,146 @@ void ShowImPlotDemoWindow(bool* p_open) {
ImGui::EndDragDropTarget();
}
}
if (ImGui::CollapsingHeader("Digital")) {
static int bitHeight = 7;
ImGui::SetNextItemWidth(100);
ImGui::DragInt("Bit Hieght", &bitHeight, 0.2, 5, 50);
/// Set the X axis range of the next plot. Call right before BeginPlot(). If ImGuiCond_Always is used, the axis will be locked.
//void SetNextPlotRangeX(float x_min, float x_max, ImGuiCond cond = ImGuiCond_Once);
static bool paused = false;
#define K_PLOT_DIGITAL_CH_COUNT 8
#define K_PLOT_ANALOG_CH_COUNT 8
static ScrollingData dataDigital[K_PLOT_DIGITAL_CH_COUNT];
static ScrollingData dataAnalog[K_PLOT_ANALOG_CH_COUNT];
static bool showDigital[K_PLOT_DIGITAL_CH_COUNT];
static bool showAnalog[K_PLOT_ANALOG_CH_COUNT];
ImGui::BulletText("Drag data items from the left column onto the plot.");
ImGui::BeginGroup();
if (ImGui::Button("Clear", {100, 0})) {
for (int i = 0; i < K_PLOT_DIGITAL_CH_COUNT; ++i)
showDigital[i] = false;
for (int i = 0; i < K_PLOT_ANALOG_CH_COUNT; ++i)
showAnalog[i] = false;
}
if (ImGui::Button(paused ? "Resume" : "Pause", {100,0}))
paused = !paused;
ImGui::Separator();
for (int i = 0; i < K_PLOT_DIGITAL_CH_COUNT; ++i) {
char label[32];
sprintf(label, "digital_data_%d", i);
ImGui::Checkbox(label, &showDigital[i]);
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
ImGui::SetDragDropPayload("DND_DIGITAL_PLOT", &i, sizeof(int));
ImGui::TextUnformatted(label);
ImGui::EndDragDropSource();
}
}
for (int i = 0; i < K_PLOT_ANALOG_CH_COUNT; ++i) {
char label[32];
sprintf(label, "analog_data_%d", i);
ImGui::Checkbox(label, &showAnalog[i]);
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
ImGui::SetDragDropPayload("DND_ANALOG_PLOT", &i, sizeof(int));
ImGui::TextUnformatted(label);
ImGui::EndDragDropSource();
}
}
ImGui::EndGroup();
ImGui::SameLine();
static float t = 0;
if (true) {
t += ImGui::GetIO().DeltaTime;
//digital signal values
int i = 0;
if (showDigital[i])
dataDigital[i].AddPoint(t, sin(t) > 0.45);
i++;
if (showDigital[i])
dataDigital[i].AddPoint(t, sin(t) < 0.45);
i++;
if (showDigital[i])
dataDigital[i].AddPoint(t, sin(t) > 0.83);
i++;
if (showDigital[i])
dataDigital[i].AddPoint(t, sin(t) < 0.17);
i++;
if (showDigital[i])
dataDigital[i].AddPoint(t, cos(t) > 0.45);
i++;
if (showDigital[i])
dataDigital[i].AddPoint(t, cos(t) < 0.45);
i++;
if (showDigital[i])
dataDigital[i].AddPoint(t, cos(t) > 0.83);
i++;
if (showDigital[i])
dataDigital[i].AddPoint(t, cos(t) < 0.17);
//Analog signal values
i = 0;
if (showAnalog[i])
dataAnalog[i].AddPoint(t, sin(t));
i++;
if (showAnalog[i])
dataAnalog[i].AddPoint(t, cos(t));
i++;
if (showAnalog[i])
dataAnalog[i].AddPoint(t, sin(t) * cos(t));
i++;
if (showAnalog[i])
dataAnalog[i].AddPoint(t, sin(t) - cos(t));
i++;
if (showAnalog[i])
dataAnalog[i].AddPoint(t, cos(t) - sin(t));
i++;
if (showAnalog[i])
dataAnalog[i].AddPoint(t, sin(t) + cos(t));
i++;
if (showAnalog[i])
dataAnalog[i].AddPoint(t, (sin(t) + cos(t)) / (sin(t) * cos(t)));
i++;
if (showAnalog[i])
dataAnalog[i].AddPoint(t, (cos(t) + cos(t)) / (cos(t) * cos(t)));
i++;
}
ImGui::SetNextPlotRangeX(t - 60.0f, t, paused ? ImGuiCond_Once : ImGuiCond_Always);
if (ImGui::BeginPlot("##DND", NULL, NULL, ImVec2(-1,300), ImPlotFlags_Default)) {
for (int i = 0; i < K_PLOT_DIGITAL_CH_COUNT; ++i) {
if (showDigital[i]) {
char label[32];
sprintf(label, "digital_data_%d", i);
ImGui::PushPlotStyleVar(ImPlotStyleVar_DigitalBitHeight, bitHeight);
ImGui::PlotDigital(label, &dataDigital[i].Data[0].x, &dataDigital[i].Data[0].y, dataDigital[i].Data.size(), dataDigital[i].Offset, 2 * sizeof(float));
ImGui::PopPlotStyleVar();
}
}
for (int i = 0; i < K_PLOT_ANALOG_CH_COUNT; ++i) {
if (showAnalog[i]) {
char label[32];
sprintf(label, "analog_data_%d", i);
if (dataAnalog[i].Data.size() > 0)
ImGui::Plot(label, &dataAnalog[i].Data[0].x, &dataAnalog[i].Data[0].y, dataAnalog[i].Data.size(), dataAnalog[i].Offset, 2 * sizeof(float));
}
}
ImGui::EndPlot();
}
if (ImGui::BeginDragDropTarget()) {
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("DND_DIGITAL_PLOT")) {
int i = *(int*)payload->Data;
showDigital[i] = true;
}
else if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("DND_ANALOG_PLOT")) {
int i = *(int*)payload->Data;
showAnalog[i] = true;
}
ImGui::EndDragDropTarget();
}
}
//-------------------------------------------------------------------------
if (ImGui::CollapsingHeader("Custom Styles")) {
static ImVec4 my_palette[3] = {