mirror of
https://github.com/gwm17/implot.git
synced 2024-11-26 20:28:50 -05:00
commit
8253189fc8
95
implot.cpp
95
implot.cpp
|
@ -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
|
5
implot.h
5
implot.h
|
@ -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
|
||||
|
|
148
implot_demo.cpp
148
implot_demo.cpp
|
@ -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] = {
|
||||
|
|
Loading…
Reference in New Issue
Block a user