From 226ae4c10bce509527b4603f9cacf5b6b0c8208f Mon Sep 17 00:00:00 2001 From: Evan Pezent Date: Sat, 16 May 2020 21:09:36 -0500 Subject: [PATCH 1/5] checkpoint --- implot.cpp | 128 +++++++++++++++++++++++++----------------------- implot.h | 28 ++++++++--- implot_demo.cpp | 19 +++---- 3 files changed, 98 insertions(+), 77 deletions(-) diff --git a/implot.cpp b/implot.cpp index b781efb..00179da 100644 --- a/implot.cpp +++ b/implot.cpp @@ -102,13 +102,16 @@ ImPlotStyle::ImPlotStyle() { Colors[ImPlotCol_Query] = ImVec4(0,1,0,1); } -ImPlotRange::ImPlotRange() : Min(NAN), Max(NAN) {} +ImPlotRange::ImPlotRange() { + Min = NAN; + Max = NAN; +} -bool ImPlotRange::Contains(float v) const { +bool ImPlotRange::Contains(ImPlotFloat v) const { return v >= Min && v <= Max; } -float ImPlotRange::Size() const { +ImPlotFloat ImPlotRange::Size() const { return Max - Min; } @@ -118,10 +121,6 @@ bool ImPlotLimits::Contains(const ImVec2& p) const { return X.Contains(p.x) && Y.Contains(p.y); } -ImVec2 ImPlotLimits::Size() const { - return ImVec2(X.Size(),Y.Size()); -} - namespace ImPlot { namespace { @@ -143,27 +142,28 @@ inline void FlipFlag(TSet& set, TFlag flag) { } /// Linearly remaps float x from [x0 x1] to [y0 y1]. -inline float Remap(float x, float x0, float x1, float y0, float y1) { +inline double Remap(double x, double x0, double x1, double y0, double y1) { return y0 + (x - x0) * (y1 - y0) / (x1 - x0); } /// Turns NANs to 0s -inline float ConstrainNan(float val) { +inline ImPlotFloat ConstrainNan(ImPlotFloat val) { return isnan(val) ? 0 : val; } /// Turns INFINITYs to FLT_MAXs -inline float ConstrainInf(float val) { - return val == INFINITY ? FLT_MAX : val == -INFINITY ? -FLT_MAX : val; +inline ImPlotFloat ConstrainInf(ImPlotFloat val) { + // TODO: FLT_MAX/DBL_MAX templates + return val == INFINITY ? DBL_MAX : val == -INFINITY ? -DBL_MAX : val; } /// Turns numbers less than or equal to 0 to 0.001 (sort of arbitrary, is there a better way?) -inline float ConstrainLog(float val) { +inline ImPlotFloat ConstrainLog(ImPlotFloat val) { return val <= 0 ? 0.001f : val; } /// Returns true if val is NAN or INFINITY -inline bool NanOrInf(float val) { +inline bool NanOrInf(ImPlotFloat val) { return val == INFINITY || val == -INFINITY || isnan(val); } @@ -236,12 +236,12 @@ ImVec4 NextColor(); /// Tick mark info struct ImTick { - ImTick(double value, bool major, bool render_label = true) { + ImTick(ImPlotFloat value, bool major, bool render_label = true) { PlotPos = value; Major = major; RenderLabel = render_label; } - double PlotPos; + ImPlotFloat PlotPos; float PixelPos; ImVec2 Size; int TextOffset; @@ -356,11 +356,11 @@ struct ImPlotContext { // Transformation cache ImRect PixelRange[MAX_Y_AXES]; // linear scale (slope) - float Mx; - float My[MAX_Y_AXES]; + ImPlotFloat Mx; + ImPlotFloat My[MAX_Y_AXES]; // log scale denominator - float LogDenX; - float LogDenY[MAX_Y_AXES]; + ImPlotFloat LogDenX; + ImPlotFloat LogDenY[MAX_Y_AXES]; // Data extents ImPlotRange ExtentsX; ImPlotRange ExtentsY[MAX_Y_AXES]; @@ -373,7 +373,7 @@ struct ImPlotContext { // Render flags bool RenderX, RenderY[MAX_Y_AXES]; // Mouse pos - ImVec2 LastMousePos[MAX_Y_AXES]; + ImPlotPoint LastMousePos[MAX_Y_AXES]; // Style ImVector ColorMap; ImPlotStyle Style; @@ -434,47 +434,47 @@ inline void UpdateTransformCache() { gp.Mx = (gp.PixelRange[0].Max.x - gp.PixelRange[0].Min.x) / gp.CurrentPlot->XAxis.Range.Size(); } -inline ImVec2 PixelsToPlot(float x, float y, int y_axis_in = -1) { +inline ImPlotPoint PixelsToPlot(float x, float y, int y_axis_in = -1) { IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PixelsToPlot() Needs to be called between BeginPlot() and EndPlot()!"); const int y_axis = y_axis_in >= 0 ? y_axis_in : gp.CurrentPlot->CurrentYAxis; - ImVec2 plt; + ImPlotPoint plt; plt.x = (x - gp.PixelRange[y_axis].Min.x) / gp.Mx + gp.CurrentPlot->XAxis.Range.Min; plt.y = (y - gp.PixelRange[y_axis].Min.y) / gp.My[y_axis] + gp.CurrentPlot->YAxis[y_axis].Range.Min; if (HasFlag(gp.CurrentPlot->XAxis.Flags, ImPlotAxisFlags_LogScale)) { - float t = (plt.x - gp.CurrentPlot->XAxis.Range.Min) / gp.CurrentPlot->XAxis.Range.Size(); + ImPlotFloat t = (plt.x - gp.CurrentPlot->XAxis.Range.Min) / gp.CurrentPlot->XAxis.Range.Size(); plt.x = pow(10.0f, t * gp.LogDenX) * gp.CurrentPlot->XAxis.Range.Min; } if (HasFlag(gp.CurrentPlot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) { - float t = (plt.y - gp.CurrentPlot->YAxis[y_axis].Range.Min) / gp.CurrentPlot->YAxis[y_axis].Range.Size(); + ImPlotFloat t = (plt.y - gp.CurrentPlot->YAxis[y_axis].Range.Min) / gp.CurrentPlot->YAxis[y_axis].Range.Size(); plt.y = pow(10.0f, t * gp.LogDenY[y_axis]) * gp.CurrentPlot->YAxis[y_axis].Range.Min; } return plt; } -ImVec2 PixelsToPlot(const ImVec2& pix, int y_axis) { +ImPlotPoint PixelsToPlot(const ImVec2& pix, int y_axis) { return PixelsToPlot(pix.x, pix.y, y_axis); } // This function is convenient but should not be used to process a high volume of points. Use the Transformer structs below instead. -inline ImVec2 PlotToPixels(float x, float y, int y_axis_in = -1) { +inline ImVec2 PlotToPixels(ImPlotFloat x, ImPlotFloat y, int y_axis_in = -1) { IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PlotToPixels() Needs to be called between BeginPlot() and EndPlot()!"); const int y_axis = y_axis_in >= 0 ? y_axis_in : gp.CurrentPlot->CurrentYAxis; ImVec2 pix; if (HasFlag(gp.CurrentPlot->XAxis.Flags, ImPlotAxisFlags_LogScale)) { - float t = log10(x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX; - x = ImLerp(gp.CurrentPlot->XAxis.Range.Min, gp.CurrentPlot->XAxis.Range.Max, t); + ImPlotFloat t = log10(x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX; + x = ImLerp(gp.CurrentPlot->XAxis.Range.Min, gp.CurrentPlot->XAxis.Range.Max, (float)t); } if (HasFlag(gp.CurrentPlot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) { - float t = log10(y / gp.CurrentPlot->YAxis[y_axis].Range.Min) / gp.LogDenY[y_axis]; - y = ImLerp(gp.CurrentPlot->YAxis[y_axis].Range.Min, gp.CurrentPlot->YAxis[y_axis].Range.Max, t); + ImPlotFloat t = log10(y / gp.CurrentPlot->YAxis[y_axis].Range.Min) / gp.LogDenY[y_axis]; + y = ImLerp(gp.CurrentPlot->YAxis[y_axis].Range.Min, gp.CurrentPlot->YAxis[y_axis].Range.Max, (float)t); } - pix.x = gp.PixelRange[y_axis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min); - pix.y = gp.PixelRange[y_axis].Min.y + gp.My[y_axis] * (y - gp.CurrentPlot->YAxis[y_axis].Range.Min); + pix.x = (float)(gp.PixelRange[y_axis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min)); + pix.y = (float)(gp.PixelRange[y_axis].Min.y + gp.My[y_axis] * (y - gp.CurrentPlot->YAxis[y_axis].Range.Min)); return pix; } // This function is convenient but should not be used to process a high volume of points. Use the Transformer structs below instead. -ImVec2 PlotToPixels(const ImVec2& plt, int y_axis) { +ImVec2 PlotToPixels(const ImPlotPoint& plt, int y_axis) { return PlotToPixels(plt.x, plt.y, y_axis); } @@ -484,7 +484,7 @@ struct Plt2PixLinLin { Plt2PixLinLin(int y_axis_in) : y_axis(y_axis_in) {} ImVec2 operator()(const ImVec2& plt) { return (*this)(plt.x, plt.y); } - ImVec2 operator()(float x, float y) { + ImVec2 operator()(ImPlotFloat x, ImPlotFloat y) { return ImVec2( gp.PixelRange[y_axis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min), gp.PixelRange[y_axis].Min.y + gp.My[y_axis] * (y - gp.CurrentPlot->YAxis[y_axis].Range.Min) ); } @@ -668,11 +668,13 @@ void UpdateAxisColor(int axis_flag, ImPlotContext::AxisColor* col) { col->Txt = ImGui::GetColorU32(ImVec4(col_Axis.x, col_Axis.y, col_Axis.z, 1)); } -ImRect GetAxisScale(int y_axis, float tx, float ty, float zoom_rate) { - return ImRect( - PixelsToPlot(gp.BB_Grid.Min - gp.BB_Grid.GetSize() * ImVec2(tx * zoom_rate, ty * zoom_rate), y_axis), - PixelsToPlot(gp.BB_Grid.Max + gp.BB_Grid.GetSize() * ImVec2((1 - tx) * zoom_rate, (1 - ty) * zoom_rate), y_axis)); -} +struct ImPlotAxisScale { + ImPlotAxisScale(int y_axis, float tx, float ty, float zoom_rate) { + Min = PixelsToPlot(gp.BB_Grid.Min - gp.BB_Grid.GetSize() * ImVec2(tx * zoom_rate, ty * zoom_rate), y_axis); + Max = PixelsToPlot(gp.BB_Grid.Max + gp.BB_Grid.GetSize() * ImVec2((1 - tx) * zoom_rate, (1 - ty) * zoom_rate), y_axis); + } + ImPlotPoint Min, Max; +}; class YPadCalculator { public: @@ -1004,8 +1006,8 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons if (drag_in_progress) { UpdateTransformCache(); if (!x.lock && plot.XAxis.Dragging) { - ImVec2 plot_tl = PixelsToPlot(gp.BB_Grid.Min - IO.MouseDelta, 0); - ImVec2 plot_br = PixelsToPlot(gp.BB_Grid.Max - IO.MouseDelta, 0); + ImPlotPoint plot_tl = PixelsToPlot(gp.BB_Grid.Min - IO.MouseDelta, 0); + ImPlotPoint plot_br = PixelsToPlot(gp.BB_Grid.Max - IO.MouseDelta, 0); if (!x.lock_min) plot.XAxis.Range.Min = x.flip ? plot_br.x : plot_tl.x; if (!x.lock_max) @@ -1013,8 +1015,8 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons } for (int i = 0; i < MAX_Y_AXES; i++) { if (!y[i].lock && plot.YAxis[i].Dragging) { - ImVec2 plot_tl = PixelsToPlot(gp.BB_Grid.Min - IO.MouseDelta, i); - ImVec2 plot_br = PixelsToPlot(gp.BB_Grid.Max - IO.MouseDelta, i); + ImPlotPoint plot_tl = PixelsToPlot(gp.BB_Grid.Min - IO.MouseDelta, i); + ImPlotPoint plot_br = PixelsToPlot(gp.BB_Grid.Max - IO.MouseDelta, i); if (!y[i].lock_min) plot.YAxis[i].Range.Min = y[i].flip ? plot_tl.y : plot_br.y; @@ -1067,9 +1069,9 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons float tx = Remap(IO.MousePos.x, gp.BB_Grid.Min.x, gp.BB_Grid.Max.x, 0, 1); float ty = Remap(IO.MousePos.y, gp.BB_Grid.Min.y, gp.BB_Grid.Max.y, 0, 1); if (hov_x_axis_region && !x.lock) { - ImRect axis_scale = GetAxisScale(0, tx, ty, zoom_rate); - const ImVec2& plot_tl = axis_scale.Min; - const ImVec2& plot_br = axis_scale.Max; + ImPlotAxisScale axis_scale(0, tx, ty, zoom_rate); + const ImPlotPoint& plot_tl = axis_scale.Min; + const ImPlotPoint& plot_br = axis_scale.Max; if (!x.lock_min) plot.XAxis.Range.Min = x.flip ? plot_br.x : plot_tl.x; @@ -1078,10 +1080,9 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons } for (int i = 0; i < MAX_Y_AXES; i++) { if (hov_y_axis_region[i] && !y[i].lock) { - ImRect axis_scale = GetAxisScale(i, tx, ty, zoom_rate); - const ImVec2& plot_tl = axis_scale.Min; - const ImVec2& plot_br = axis_scale.Max; - + ImPlotAxisScale axis_scale(i, tx, ty, zoom_rate); + const ImPlotPoint& plot_tl = axis_scale.Min; + const ImPlotPoint& plot_br = axis_scale.Max; if (!y[i].lock_min) plot.YAxis[i].Range.Min = y[i].flip ? plot_tl.y : plot_br.y; if (!y[i].lock_max) @@ -1097,8 +1098,8 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons UpdateTransformCache(); ImVec2 select_size = plot.SelectStart - IO.MousePos; if (HasFlag(plot.Flags, ImPlotFlags_BoxSelect) && ImFabs(select_size.x) > 2 && ImFabs(select_size.y) > 2) { - ImVec2 p1 = PixelsToPlot(plot.SelectStart); - ImVec2 p2 = PixelsToPlot(IO.MousePos); + ImPlotPoint p1 = PixelsToPlot(plot.SelectStart); + ImPlotPoint p2 = PixelsToPlot(IO.MousePos); if (!x.lock_min && !IO.KeyAlt) plot.XAxis.Range.Min = ImMin(p1.x, p2.x); if (!x.lock_max && !IO.KeyAlt) @@ -1313,6 +1314,11 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons // Context Menu //----------------------------------------------------------------------------- + +bool DragDouble(const char* label, double* v, float v_speed = 1.0f, double v_min = 0.0, double v_max = 0.0, const char* format = "%.3f", float power = 1.0f) { + return ImGui::DragScalar(label, ImGuiDataType_Double, v, v_speed, &v_min, &v_max, format, power); +} + inline void AxisMenu(ImPlotAxis& Axis) { ImGui::PushItemWidth(75); bool lock_min = HasFlag(Axis.Flags, ImPlotAxisFlags_LockMin); @@ -1329,7 +1335,7 @@ inline void AxisMenu(ImPlotAxis& Axis) { ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.25f); } - ImGui::DragFloat("Min", &Axis.Range.Min, 0.01f + 0.01f * (Axis.Range.Size()), -INFINITY, Axis.Range.Max - FLT_EPSILON); + DragDouble("Min", &Axis.Range.Min, 0.01f + 0.01f * (Axis.Range.Size()), -INFINITY, Axis.Range.Max - FLT_EPSILON); if (lock_min) { ImGui::PopItemFlag(); ImGui::PopStyleVar(); } @@ -1340,7 +1346,7 @@ inline void AxisMenu(ImPlotAxis& Axis) { if (lock_max) { ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.25f); } - ImGui::DragFloat("Max", &Axis.Range.Max, 0.01f + 0.01f * (Axis.Range.Size()), Axis.Range.Min + FLT_EPSILON, INFINITY); + DragDouble("Max", &Axis.Range.Max, 0.01f + 0.01f * (Axis.Range.Size()), Axis.Range.Min + FLT_EPSILON, INFINITY); if (lock_max) { ImGui::PopItemFlag(); ImGui::PopStyleVar(); @@ -1761,7 +1767,7 @@ bool IsPlotHovered() { IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "IsPlotHovered() Needs to be called between BeginPlot() and EndPlot()!"); return gp.Hov_Grid; } -ImVec2 GetPlotMousePos(int y_axis_in) { +ImPlotPoint GetPlotMousePos(int y_axis_in) { IM_ASSERT_USER_ERROR(y_axis_in >= -1 && y_axis_in < MAX_Y_AXES, "y_axis needs to between -1 and MAX_Y_AXES"); IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "GetPlotMousePos() Needs to be called between BeginPlot() and EndPlot()!"); const int y_axis = y_axis_in >= 0 ? y_axis_in : gp.CurrentPlot->CurrentYAxis; @@ -1793,8 +1799,8 @@ ImPlotLimits GetPlotQuery(int y_axis_in) { const int y_axis = y_axis_in >= 0 ? y_axis_in : gp.CurrentPlot->CurrentYAxis; UpdateTransformCache(); - ImVec2 p1 = PixelsToPlot(plot.QueryRect.Min + gp.BB_Grid.Min, y_axis); - ImVec2 p2 = PixelsToPlot(plot.QueryRect.Max + gp.BB_Grid.Min, y_axis); + ImPlotPoint p1 = PixelsToPlot(plot.QueryRect.Min + gp.BB_Grid.Min, y_axis); + ImPlotPoint p2 = PixelsToPlot(plot.QueryRect.Max + gp.BB_Grid.Min, y_axis); ImPlotLimits result; result.X.Min = ImMin(p1.x, p2.x); @@ -2550,7 +2556,7 @@ void PlotErrorBars(const char* label_id, ImVec4 (*getter_func)(void* data, int i // PLOT MISC //----------------------------------------------------------------------------- -inline void DrawPieSlice(ImDrawList& DrawList, const ImVec2& center, float radius, float a0, float a1, ImU32 col) { +inline void DrawPieSlice(ImDrawList& DrawList, const ImPlotPoint& center, float radius, float a0, float a1, ImU32 col) { static const float resolution = 50 / (2 * IM_PI); static ImVec2 buffer[50]; buffer[0] = PlotToPixels(center); @@ -2564,7 +2570,7 @@ inline void DrawPieSlice(ImDrawList& DrawList, const ImVec2& center, float radiu } -void PlotPieChart(const char** label_ids, float* values, int count, const ImVec2& center, float radius, bool show_percents, float angle0) { +void PlotPieChart(const char** label_ids, float* values, int count, float x, float y, float radius, bool show_percents, float angle0) { IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PieChart() Needs to be called between BeginPlot() and EndPlot()!"); ImDrawList & DrawList = *ImGui::GetWindowDrawList(); @@ -2574,6 +2580,8 @@ void PlotPieChart(const char** label_ids, float* values, int count, const ImVec2 const bool normalize = sum > 1.0f; + ImPlotPoint center(x,y); + PushPlotClipRect(); float a0 = angle0 * 2 * IM_PI / 360.0f; float a1 = angle0 * 2 * IM_PI / 360.0f; @@ -2609,7 +2617,7 @@ void PlotText(const char* text, float x, float y, bool vertical, const ImVec2& p IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "Text() Needs to be called between BeginPlot() and EndPlot()!"); ImDrawList & DrawList = *ImGui::GetWindowDrawList(); PushPlotClipRect(); - ImVec2 pos = PlotToPixels(ImVec2(x,y)) + pixel_offset; + ImVec2 pos = PlotToPixels(ImPlotPoint(x,y)) + pixel_offset; if (vertical) AddTextVertical(&DrawList, text, pos, gp.Col_Txt); else diff --git a/implot.h b/implot.h index 7fe3837..1ca7e5a 100644 --- a/implot.h +++ b/implot.h @@ -25,6 +25,13 @@ #pragma once #include "imgui.h" +// This can be defined in your imconfig.h to change the desired plot precision. +// #ifndef ImPlotFloat +// #define ImPlotFloat double +// #endif + +typedef double ImPlotFloat; + //----------------------------------------------------------------------------- // Basic types and flags //----------------------------------------------------------------------------- @@ -114,12 +121,18 @@ enum ImPlotMarker_ { ImPlotMarker_Asterisk = 1 << 10, // a asterisk marker will be rendered at each point (not filled) }; +struct ImPlotPoint { + ImPlotFloat x, y; + ImPlotPoint() { x = y = 0; } + ImPlotPoint(ImPlotFloat _x, ImPlotFloat _y) { x = _x; y = _y; } +}; + // A range defined by a min/max value. Used for plot axes ranges. struct ImPlotRange { - float Min, Max; + ImPlotFloat Min, Max; ImPlotRange(); - bool Contains(float value) const; - float Size() const; + bool Contains(ImPlotFloat value) const; + ImPlotFloat Size() const; }; // Combination of two ranges for X and Y axes. @@ -127,7 +140,6 @@ struct ImPlotLimits { ImPlotRange X, Y; ImPlotLimits(); bool Contains(const ImVec2& p) const; - ImVec2 Size() const; }; // Plot style structure @@ -195,7 +207,7 @@ void PlotErrorBars(const char* label_id, const float* xs, const float* ys, const void PlotErrorBars(const char* label_id, const float* xs, const float* ys, const float* neg, const float* pos, int count, int offset = 0, int stride = sizeof(float)); void PlotErrorBars(const char* label_id, ImVec4 (*getter)(void* data, int idx), void* data, int count, int offset = 0); // Plots a pie chart. If the sum of values > 1, each value will be normalized. Center and radius are in plot coordinates. -void PlotPieChart(const char** label_ids, float* values, int count, const ImVec2& center, float radius, bool show_percents = true, float angle0 = 90); +void PlotPieChart(const char** label_ids, float* values, int count, float x, float y, float radius, bool show_percents = true, float angle0 = 90); // Plots digital data. void PlotDigital(const char* label_id, const float* xs, const float* ys, int count, int offset = 0, int stride = sizeof(float)); void PlotDigital(const char* label_id, ImVec2 (*getter)(void* data, int idx), void* data, int count, int offset = 0); @@ -209,7 +221,7 @@ void PlotText(const char* text, float x, float y, bool vertical = false, const I /// Returns true if the plot area in the current or most recent plot is hovered. bool IsPlotHovered(); /// Returns the mouse position in x,y coordinates of the current or most recent plot. A negative y_axis uses the current value of SetPlotYAxis (0 initially). -ImVec2 GetPlotMousePos(int y_axis = -1); +ImPlotPoint GetPlotMousePos(int y_axis = -1); /// Returns the current or most recent plot axis range. A negative y_axis uses the current value of SetPlotYAxis (0 initially). ImPlotLimits GetPlotLimits(int y_axis = -1); /// Returns true if the current or most recent plot is being queried. @@ -263,9 +275,9 @@ ImVec2 GetPlotPos(); ImVec2 GetPlotSize(); // Convert pixels to a position in the current plot's coordinate system. A negative y_axis uses the current value of SetPlotYAxis (0 initially). -ImVec2 PixelsToPlot(const ImVec2& pix, int y_axis = -1); +ImPlotPoint PixelsToPlot(const ImVec2& pix, int y_axis = -1); // Convert a position in the current plot's coordinate system to pixels. A negative y_axis uses the current value of SetPlotYAxis (0 initially). -ImVec2 PlotToPixels(const ImVec2& plt, int y_axis = -1); +ImVec2 PlotToPixels(const ImPlotPoint& plt, int y_axis = -1); // Push clip rect for rendering to current plot area void PushPlotClipRect(); diff --git a/implot_demo.cpp b/implot_demo.cpp index 13dfd57..4ba0e07 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -240,12 +240,10 @@ void ShowDemoWindow(bool* p_open) { if (ImGui::CollapsingHeader("Pie Charts")) { static const char* labels1[] = {"Frogs","Hogs","Dogs","Logs"}; static float pre_normalized[] = {0.15f, 0.30f, 0.45f, 0.10f}; - ImVec2 center(0.5f,0.5f); // in plot units, not pixels - float radius = 0.4f; // in plot units, not pixels SetNextPlotLimits(0,1,0,1,ImGuiCond_Always); if (ImPlot::BeginPlot("##Pie1", NULL, NULL, ImVec2(250,250), ImPlotFlags_Legend, 0, 0)) { - ImPlot::PlotPieChart(labels1, pre_normalized, 4, center, radius); + ImPlot::PlotPieChart(labels1, pre_normalized, 4, 0.5f, 0.5f, 0.4f); ImPlot::EndPlot(); } ImGui::SameLine(); @@ -262,7 +260,7 @@ void ShowDemoWindow(bool* p_open) { static const char* labels2[] = {"One","Two","Three","Four","Five"}; static float not_normalized[] = {1,2,3,4,5}; if (ImPlot::BeginPlot("##Pie2", NULL, NULL, ImVec2(250,250), ImPlotFlags_Legend, 0, 0)) { - ImPlot::PlotPieChart(labels2, not_normalized, 5, center, radius); + ImPlot::PlotPieChart(labels2, not_normalized, 5, 0.5f, 0.5f, 0.4f); ImPlot::EndPlot(); } ImPlot::RestorePalette(); @@ -459,8 +457,11 @@ void ShowDemoWindow(bool* p_open) { static ImVector data; ImPlotLimits range, query; if (ImPlot::BeginPlot("##Drawing", NULL, NULL, ImVec2(-1,0), ImPlotFlags_Default | ImPlotFlags_Query, ImPlotAxisFlags_GridLines, ImPlotAxisFlags_GridLines)) { - if (ImPlot::IsPlotHovered() && ImGui::IsMouseClicked(0) && ImGui::GetIO().KeyCtrl) - data.push_back(ImPlot::GetPlotMousePos()); + if (ImPlot::IsPlotHovered() && ImGui::IsMouseClicked(0) && ImGui::GetIO().KeyCtrl) { + ImPlotPoint pt = ImPlot::GetPlotMousePos(); + + data.push_back(ImVec2(pt.x, pt.y)); + } ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Diamond); if (data.size() > 0) ImPlot::PlotScatter("Points", &data[0].x, &data[0].y, data.size(), 0, 2 * sizeof(float)); @@ -762,9 +763,9 @@ void ShowDemoWindow(bool* p_open) { //------------------------------------------------------------------------- if (ImGui::CollapsingHeader("Custom Rendering")) { if (ImPlot::BeginPlot("##CustomRend")) { - ImVec2 cntr = ImPlot::PlotToPixels(ImVec2(0.5f, 0.5f)); - ImVec2 rmin = ImPlot::PlotToPixels(ImVec2(0.25f, 0.75f)); - ImVec2 rmax = ImPlot::PlotToPixels(ImVec2(0.75f, 0.25f)); + ImVec2 cntr = ImPlot::PlotToPixels(ImPlotPoint(0.5f, 0.5f)); + ImVec2 rmin = ImPlot::PlotToPixels(ImPlotPoint(0.25f, 0.75f)); + ImVec2 rmax = ImPlot::PlotToPixels(ImPlotPoint(0.75f, 0.25f)); ImPlot::PushPlotClipRect(); ImGui::GetWindowDrawList()->AddCircleFilled(cntr,20,IM_COL32(255,255,0,255),20); ImGui::GetWindowDrawList()->AddRect(rmin, rmax, IM_COL32(128,0,255,255)); From 2fd9d3f75608ca97c2a5d36a80348d9f0ca9de06 Mon Sep 17 00:00:00 2001 From: Evan Pezent Date: Sat, 16 May 2020 21:53:59 -0500 Subject: [PATCH 2/5] checkpoint --- implot.cpp | 151 ++++++++++++++++++++++++------------------------ implot.h | 12 ++-- implot_demo.cpp | 6 +- 3 files changed, 84 insertions(+), 85 deletions(-) diff --git a/implot.cpp b/implot.cpp index 00179da..74820cc 100644 --- a/implot.cpp +++ b/implot.cpp @@ -142,7 +142,7 @@ inline void FlipFlag(TSet& set, TFlag flag) { } /// Linearly remaps float x from [x0 x1] to [y0 y1]. -inline double Remap(double x, double x0, double x1, double y0, double y1) { +inline float Remap(float x, float x0, float x1, float y0, float y1) { return y0 + (x - x0) * (y1 - y0) / (x1 - x0); } @@ -399,7 +399,7 @@ ImVec4 NextColor() { return col; } -inline void FitPoint(const ImVec2& p) { +inline void FitPoint(const ImPlotPoint& p) { ImPlotRange* extents_x = &gp.ExtentsX; ImPlotRange* extents_y = &gp.ExtentsY[gp.CurrentPlot->CurrentYAxis]; if (!NanOrInf(p.x)) { @@ -483,10 +483,10 @@ ImVec2 PlotToPixels(const ImPlotPoint& plt, int y_axis) { struct Plt2PixLinLin { Plt2PixLinLin(int y_axis_in) : y_axis(y_axis_in) {} - ImVec2 operator()(const ImVec2& plt) { return (*this)(plt.x, plt.y); } + ImVec2 operator()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); } ImVec2 operator()(ImPlotFloat x, ImPlotFloat y) { - return ImVec2( gp.PixelRange[y_axis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min), - gp.PixelRange[y_axis].Min.y + gp.My[y_axis] * (y - gp.CurrentPlot->YAxis[y_axis].Range.Min) ); + return ImVec2( (float)(gp.PixelRange[y_axis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min)), + (float)(gp.PixelRange[y_axis].Min.y + gp.My[y_axis] * (y - gp.CurrentPlot->YAxis[y_axis].Range.Min)) ); } int y_axis; @@ -495,12 +495,12 @@ struct Plt2PixLinLin { struct Plt2PixLogLin { Plt2PixLogLin(int y_axis_in) : y_axis(y_axis_in) {} - ImVec2 operator()(const ImVec2& plt) { return (*this)(plt.x, plt.y); } - ImVec2 operator()(float x, float y) { - float t = log10(x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX; - x = ImLerp(gp.CurrentPlot->XAxis.Range.Min, gp.CurrentPlot->XAxis.Range.Max, t); - return ImVec2( gp.PixelRange[y_axis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min), - gp.PixelRange[y_axis].Min.y + gp.My[y_axis] * (y - gp.CurrentPlot->YAxis[y_axis].Range.Min) ); + ImVec2 operator()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); } + ImVec2 operator()(ImPlotFloat x, ImPlotFloat y) { + ImPlotFloat t = log10(x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX; + x = ImLerp(gp.CurrentPlot->XAxis.Range.Min, gp.CurrentPlot->XAxis.Range.Max, (float)t); + return ImVec2( (float)(gp.PixelRange[y_axis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min)), + (float)(gp.PixelRange[y_axis].Min.y + gp.My[y_axis] * (y - gp.CurrentPlot->YAxis[y_axis].Range.Min)) ); } int y_axis; @@ -509,28 +509,27 @@ struct Plt2PixLogLin { struct Plt2PixLinLog { Plt2PixLinLog(int y_axis_in) : y_axis(y_axis_in) {} - ImVec2 operator()(const ImVec2& plt) { return (*this)(plt.x, plt.y); } - ImVec2 operator()(float x, float y) { - float t = log10(y / gp.CurrentPlot->YAxis[y_axis].Range.Min) / gp.LogDenY[y_axis]; - y = ImLerp(gp.CurrentPlot->YAxis[y_axis].Range.Min, gp.CurrentPlot->YAxis[y_axis].Range.Max, t); - return ImVec2( gp.PixelRange[y_axis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min), - gp.PixelRange[y_axis].Min.y + gp.My[y_axis] * (y - gp.CurrentPlot->YAxis[y_axis].Range.Min) ); + ImVec2 operator()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); } + ImVec2 operator()(ImPlotFloat x, ImPlotFloat y) { + ImPlotFloat t = log10(y / gp.CurrentPlot->YAxis[y_axis].Range.Min) / gp.LogDenY[y_axis]; + y = ImLerp(gp.CurrentPlot->YAxis[y_axis].Range.Min, gp.CurrentPlot->YAxis[y_axis].Range.Max, (float)t); + return ImVec2( (float)(gp.PixelRange[y_axis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min)), + (float)(gp.PixelRange[y_axis].Min.y + gp.My[y_axis] * (y - gp.CurrentPlot->YAxis[y_axis].Range.Min)) ); } - int y_axis; }; struct Plt2PixLogLog { Plt2PixLogLog(int y_axis_in) : y_axis(y_axis_in) {} - ImVec2 operator()(const ImVec2& plt) { return (*this)(plt.x, plt.y); } - ImVec2 operator()(float x, float y) { - float t = log10(x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX; - x = ImLerp(gp.CurrentPlot->XAxis.Range.Min, gp.CurrentPlot->XAxis.Range.Max, t); - t = log10(y / gp.CurrentPlot->YAxis[y_axis].Range.Min) / gp.LogDenY[y_axis]; - y = ImLerp(gp.CurrentPlot->YAxis[y_axis].Range.Min, gp.CurrentPlot->YAxis[y_axis].Range.Max, t); - return ImVec2( gp.PixelRange[y_axis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min), - gp.PixelRange[y_axis].Min.y + gp.My[y_axis] * (y - gp.CurrentPlot->YAxis[y_axis].Range.Min) ); + ImVec2 operator()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); } + ImVec2 operator()(ImPlotFloat x, ImPlotFloat y) { + ImPlotFloat t = log10(x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX; + x = ImLerp(gp.CurrentPlot->XAxis.Range.Min, gp.CurrentPlot->XAxis.Range.Max, (float)t); + t = log10(y / gp.CurrentPlot->YAxis[y_axis].Range.Min) / gp.LogDenY[y_axis]; + y = ImLerp(gp.CurrentPlot->YAxis[y_axis].Range.Min, gp.CurrentPlot->YAxis[y_axis].Range.Max, (float)t); + return ImVec2( (float)(gp.PixelRange[y_axis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min)), + (float)(gp.PixelRange[y_axis].Min.y + gp.My[y_axis] * (y - gp.CurrentPlot->YAxis[y_axis].Range.Min)) ); } int y_axis; @@ -1213,14 +1212,14 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons if (gp.RenderX) { for (int t = 0; t < gp.XTicks.Size; t++) { ImTick *xt = &gp.XTicks[t]; - xt->PixelPos = PlotToPixels((float)xt->PlotPos, 0, 0).x; + xt->PixelPos = PlotToPixels(xt->PlotPos, 0, 0).x; } } for (int i = 0; i < MAX_Y_AXES; i++) { if (gp.RenderY[i]) { for (int t = 0; t < gp.YTicks[i].Size; t++) { ImTick *yt = &gp.YTicks[i][t]; - yt->PixelPos = PlotToPixels(0, (float)yt->PlotPos, i).y; + yt->PixelPos = PlotToPixels(0, yt->PlotPos, i).y; } } } @@ -1716,12 +1715,12 @@ void EndPlot() { // MISC API //----------------------------------------------------------------------------- -void SetNextPlotLimits(float x_min, float x_max, float y_min, float y_max, ImGuiCond cond) { +void SetNextPlotLimits(ImPlotFloat x_min, ImPlotFloat x_max, ImPlotFloat y_min, ImPlotFloat y_max, ImGuiCond cond) { SetNextPlotLimitsX(x_min, x_max, cond); SetNextPlotLimitsY(y_min, y_max, cond); } -void SetNextPlotLimitsX(float x_min, float x_max, ImGuiCond cond) { +void SetNextPlotLimitsX(ImPlotFloat x_min, ImPlotFloat x_max, ImGuiCond cond) { IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. gp.NextPlotData.HasXRange = true; gp.NextPlotData.XRangeCond = cond; @@ -1729,7 +1728,7 @@ void SetNextPlotLimitsX(float x_min, float x_max, ImGuiCond cond) { gp.NextPlotData.X.Max = x_max; } -void SetNextPlotLimitsY(float y_min, float y_max, ImGuiCond cond, int y_axis) { +void SetNextPlotLimitsY(ImPlotFloat y_min, ImPlotFloat y_max, ImGuiCond cond, int y_axis) { IM_ASSERT_USER_ERROR(y_axis >= 0 && y_axis < MAX_Y_AXES, "y_axis Needs to be between 0 and MAX_Y_AXES"); IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. gp.NextPlotData.HasYRange[y_axis] = true; @@ -2147,45 +2146,48 @@ inline void RenderLineStrip(Transformer transformer, ImDrawList& DrawList, Gette // DATA GETTERS //----------------------------------------------------------------------------- -inline float StrideIndex(const float* data, int idx, int stride) { - return *(const float*)(const void*)((const unsigned char*)data + (size_t)idx * stride); +template +inline T StrideIndex(const T* data, int idx, int stride) { + return *(const T*)(const void*)((const unsigned char*)data + (size_t)idx * stride); } +template struct GetterYs { - GetterYs(const float* ys, int stride) { Ys = ys; Stride = stride; } - const float* Ys; + GetterYs(const T* ys, int stride) { Ys = ys; Stride = stride; } + const T* Ys; int Stride; - inline ImVec2 operator()(int idx) { - return ImVec2((float)idx, StrideIndex(Ys, idx, Stride)); + inline ImPlotPoint operator()(int idx) { + return ImPlotPoint((T)idx, StrideIndex(Ys, idx, Stride)); } }; +template struct Getter2D { - Getter2D(const float* xs, const float* ys, int stride) { Xs = xs; Ys = ys; Stride = stride; } - const float* Xs; - const float* Ys; + Getter2D(const T* xs, const T* ys, int stride) { Xs = xs; Ys = ys; Stride = stride; } + const T* Xs; + const T* Ys; int Stride; - inline ImVec2 operator()(int idx) { - return ImVec2(StrideIndex(Xs, idx, Stride), StrideIndex(Ys, idx, Stride)); + inline ImPlotPoint operator()(int idx) { + return ImPlotPoint(StrideIndex(Xs, idx, Stride), StrideIndex(Ys, idx, Stride)); } }; struct GetterImVec2 { GetterImVec2(const ImVec2* data) { Data = data; } - inline ImVec2 operator()(int idx) { return Data[idx]; } + inline ImPlotPoint operator()(int idx) { return ImPlotPoint(Data[idx].x, Data[idx].y); } const ImVec2* Data; }; struct GetterFuncPtrImVec2 { GetterFuncPtrImVec2(ImVec2 (*g)(void* data, int idx), void* d) { getter = g; data = d;} - ImVec2 operator()(int idx) { return getter(data, idx); } + inline ImPlotPoint operator()(int idx) { ImVec2 p = getter(data, idx); return ImPlotPoint(p.x,p.y); } ImVec2 (*getter)(void* data, int idx); void* data; }; struct GetterFuncPtrImVec4 { GetterFuncPtrImVec4(ImVec4 (*g)(void* data, int idx), void* d) { getter = g; data = d;} - ImVec4 operator()(int idx) { return getter(data, idx); } + inline ImVec4 operator()(int idx) { return getter(data, idx); } ImVec4 (*getter)(void* data, int idx); void* data; }; @@ -2225,7 +2227,7 @@ inline void PlotEx(const char* label_id, Getter getter, int count, int offset) // find data extents if (gp.FitThisFrame) { for (int i = 0; i < count; ++i) { - ImVec2 p = getter(i); + ImPlotPoint p = getter(i); FitPoint(p); } } @@ -2326,16 +2328,18 @@ void PlotScatter(const char* label_id, ImVec2 (*getter)(void* data, int idx), vo // PLOT BAR //----------------------------------------------------------------------------- +template struct GetterBarV { - const float* Ys; float XShift; int Stride; - GetterBarV(const float* ys, float xshift, int stride) { Ys = ys; XShift = xshift; Stride = stride; } - inline ImVec2 operator()(int idx) { return ImVec2((float)idx + XShift, StrideIndex(Ys, idx, Stride)); } + const T* Ys; T XShift; int Stride; + GetterBarV(const T* ys, T xshift, int stride) { Ys = ys; XShift = xshift; Stride = stride; } + inline ImPlotPoint operator()(int idx) { return ImPlotPoint((T)idx + XShift, StrideIndex(Ys, idx, Stride)); } }; +template struct GetterBarH { - const float* Xs; float YShift; int Stride; - GetterBarH(const float* xs, float yshift, int stride) { Xs = xs; YShift = yshift; Stride = stride; } - inline ImVec2 operator()(int idx) { return ImVec2(StrideIndex(Xs, idx, Stride), (float)idx + YShift); } + const T* Xs; T YShift; int Stride; + GetterBarH(const T* xs, T yshift, int stride) { Xs = xs; YShift = yshift; Stride = stride; } + inline ImPlotPoint operator()(int idx) { return ImPlotPoint(StrideIndex(Xs, idx, Stride), (T)idx + YShift); } }; @@ -2369,15 +2373,15 @@ void PlotBarsEx(const char* label_id, Getter getter, int count, float width, int // find data extents if (gp.FitThisFrame) { for (int i = 0; i < count; ++i) { - ImVec2 p = getter(i); - FitPoint(ImVec2(p.x - half_width, p.y)); - FitPoint(ImVec2(p.x + half_width, 0)); + ImPlotPoint p = getter(i); + FitPoint(ImPlotPoint(p.x - half_width, p.y)); + FitPoint(ImPlotPoint(p.x + half_width, 0)); } } int idx = offset; for (int i = 0; i < count; ++i) { - ImVec2 p; + ImPlotPoint p; p = getter(idx); idx = (idx + 1) % count; if (p.y == 0) @@ -2439,15 +2443,15 @@ void PlotBarsHEx(const char* label_id, Getter getter, int count, float height, // find data extents if (gp.FitThisFrame) { for (int i = 0; i < count; ++i) { - ImVec2 p = getter(i); - FitPoint(ImVec2(0, p.y - half_height)); - FitPoint(ImVec2(p.x, p.y + half_height)); + ImPlotPoint p = getter(i); + FitPoint(ImPlotPoint(0, p.y - half_height)); + FitPoint(ImPlotPoint(p.x, p.y + half_height)); } } int idx = offset; for (int i = 0; i < count; ++i) { - ImVec2 p; + ImPlotPoint p; p = getter(idx); idx = (idx + 1) % count; if (p.x == 0) @@ -2516,8 +2520,8 @@ void PlotErrorBarsEx(const char* label_id, Getter getter, int count, int offset) if (gp.FitThisFrame) { for (int i = 0; i < count; ++i) { ImVec4 e = getter(i); - FitPoint(ImVec2(e.x , e.y - e.z)); - FitPoint(ImVec2(e.x , e.y + e.w )); + FitPoint(ImPlotPoint(e.x , e.y - e.z)); + FitPoint(ImPlotPoint(e.x , e.y + e.w )); } } @@ -2644,8 +2648,8 @@ inline void PlotDigitalEx(const char* label_id, Getter getter, int count, int of // find data extents if (gp.FitThisFrame) { for (int i = 0; i < count; ++i) { - ImVec2 p = getter(i); - FitPoint(ImVec2(p.x, 0)); + ImPlotPoint p = getter(i); + FitPoint(ImPlotPoint(p.x, 0)); } } @@ -2659,31 +2663,30 @@ inline void PlotDigitalEx(const char* label_id, Getter getter, int count, int of // render digital signals as "pixel bases" rectangles if (count > 1 && rend_line) { // - const float mx = (gp.PixelRange[ax].Max.x - gp.PixelRange[ax].Min.x) / gp.CurrentPlot->XAxis.Range.Size(); - const int segments = count - 1; + const int segments = count - 1; int i1 = offset; int pixYMax = 0; for (int s = 0; s < segments; ++s) { const int i2 = (i1 + 1) % count; - ImVec2 itemData1 = getter(i1); - ImVec2 itemData2 = getter(i2); + ImPlotPoint itemData1 = getter(i1); + ImPlotPoint itemData2 = getter(i2); i1 = i2; int pixY_0 = (int)(line_weight); - float pixY_1_float = gp.Style.DigitalBitHeight * ImMax(0.0f, itemData1.y); + float pixY_1_float = gp.Style.DigitalBitHeight * ImMax(0.0, itemData1.y); int pixY_1 = (int)(pixY_1_float); //allow only positive values int pixY_chPosOffset = (int)(ImMax(gp.Style.DigitalBitHeight, pixY_1_float) + gp.Style.DigitalBitGap); pixYMax = ImMax(pixYMax, pixY_chPosOffset); - ImVec2 pMin, pMax; - pMin.x = gp.PixelRange[ax].Min.x + mx * (itemData1.x - gp.CurrentPlot->XAxis.Range.Min); - pMax.x = gp.PixelRange[ax].Min.x + mx * (itemData2.x - gp.CurrentPlot->XAxis.Range.Min); - int pixY_Offset = 20;//20 pixel from bottom due to mouse cursor label + ImVec2 pMin = PlotToPixels(itemData1); + ImVec2 pMax = PlotToPixels(itemData2); + int pixY_Offset = 20; //20 pixel from bottom due to mouse cursor label + pMin.y = (gp.PixelRange[ax].Min.y) + ((-gp.DigitalPlotOffset) - pixY_Offset); pMax.y = (gp.PixelRange[ax].Min.y) + ((-gp.DigitalPlotOffset) - pixY_0 - pixY_1 - pixY_Offset); //plot only one rectangle for same digital state while (((s+2) < segments) && (itemData1.y == itemData2.y)) { const int i3 = (i1 + 1) % count; itemData2 = getter(i3); - pMax.x = gp.PixelRange[ax].Min.x + mx * (itemData2.x - gp.CurrentPlot->XAxis.Range.Min); + pMax.x = PlotToPixels(itemData2).x; i1 = i3; s++; } diff --git a/implot.h b/implot.h index 1ca7e5a..900c70b 100644 --- a/implot.h +++ b/implot.h @@ -25,11 +25,7 @@ #pragma once #include "imgui.h" -// This can be defined in your imconfig.h to change the desired plot precision. -// #ifndef ImPlotFloat -// #define ImPlotFloat double -// #endif - +// The desired plot precision (float or double) typedef double ImPlotFloat; //----------------------------------------------------------------------------- @@ -260,11 +256,11 @@ void PopStyleVar(int count = 1); //----------------------------------------------------------------------------- /// Set the axes range limits of the next plot. Call right before BeginPlot(). If ImGuiCond_Always is used, the axes limits will be locked. -void SetNextPlotLimits(float x_min, float x_max, float y_min, float y_max, ImGuiCond cond = ImGuiCond_Once); +void SetNextPlotLimits(ImPlotFloat x_min, ImPlotFloat x_max, ImPlotFloat y_min, ImPlotFloat y_max, ImGuiCond cond = ImGuiCond_Once); /// Set the X axis range limits of the next plot. Call right before BeginPlot(). If ImGuiCond_Always is used, the axis limits will be locked. -void SetNextPlotLimitsX(float x_min, float x_max, ImGuiCond cond = ImGuiCond_Once); +void SetNextPlotLimitsX(ImPlotFloat x_min, ImPlotFloat x_max, ImGuiCond cond = ImGuiCond_Once); /// Set the Y axis range limits of the next plot. Call right before BeginPlot(). If ImGuiCond_Always is used, the axis limits will be locked. -void SetNextPlotLimitsY(float y_min, float y_max, ImGuiCond cond = ImGuiCond_Once, int y_axis = 0); +void SetNextPlotLimitsY(ImPlotFloat y_min, ImPlotFloat y_max, ImGuiCond cond = ImGuiCond_Once, int y_axis = 0); /// Select which Y axis will be used for subsequent plot elements. The default is '0', or the first Y axis. void SetPlotYAxis(int y_axis); diff --git a/implot_demo.cpp b/implot_demo.cpp index 4ba0e07..2bad1f0 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -460,7 +460,7 @@ void ShowDemoWindow(bool* p_open) { if (ImPlot::IsPlotHovered() && ImGui::IsMouseClicked(0) && ImGui::GetIO().KeyCtrl) { ImPlotPoint pt = ImPlot::GetPlotMousePos(); - data.push_back(ImVec2(pt.x, pt.y)); + data.push_back(ImVec2((float)pt.x, (float)pt.y)); } ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Diamond); if (data.size() > 0) @@ -719,8 +719,8 @@ void ShowDemoWindow(bool* p_open) { if (ImGui::CollapsingHeader("Offset Data")) { float xs[50], ys[50]; for (int i = 0; i < 50; ++i) { - xs[i] = 0.5 + 0.4 * cos(i/50.f * 6.28); - ys[i] = 0.5 + 0.4 * sin(i/50.f * 6.28); + xs[i] = 0.5f + 0.4f * cos(i/50.f * 6.28f); + ys[i] = 0.5f + 0.4f * sin(i/50.f * 6.28f); } static int offset = 0; ImGui::SliderInt("Offset", &offset, -100, 100); From b62aeeb2ab86abae56442baa4c1d07430c71ebee Mon Sep 17 00:00:00 2001 From: Evan Pezent Date: Sat, 16 May 2020 23:25:15 -0500 Subject: [PATCH 3/5] double precision dev --- implot.cpp | 92 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 64 insertions(+), 28 deletions(-) diff --git a/implot.cpp b/implot.cpp index 74820cc..7ab5525 100644 --- a/implot.cpp +++ b/implot.cpp @@ -57,6 +57,7 @@ You can read releases logs https://github.com/epezent/implot/releases for more d #include "implot.h" #include "imgui_internal.h" +#include #ifdef _MSC_VER #define sprintf sprintf_s @@ -129,6 +130,30 @@ namespace { // Private Utils //----------------------------------------------------------------------------- +template +struct FloatProps { + static inline F Min(); + static inline F Max(); + static inline F Eps(); + static inline F Inf(); +}; + +template <> +struct FloatProps { + static inline float Min() { return FLT_MIN; } + static inline float Max() { return FLT_MAX; } + static inline float Eps() { return FLT_EPSILON; } + static inline float Inf() { return HUGE_VALF; } +}; + +template <> +struct FloatProps { + static inline double Min() { return DBL_MIN; } + static inline double Max() { return DBL_MAX; } + static inline double Eps() { return DBL_EPSILON; } + static inline double Inf() { return HUGE_VAL; } +}; + /// Returns true if a flag is set template inline bool HasFlag(TSet set, TFlag flag) { @@ -151,10 +176,9 @@ inline ImPlotFloat ConstrainNan(ImPlotFloat val) { return isnan(val) ? 0 : val; } -/// Turns INFINITYs to FLT_MAXs +/// Turns infinity to floating point maximums inline ImPlotFloat ConstrainInf(ImPlotFloat val) { - // TODO: FLT_MAX/DBL_MAX templates - return val == INFINITY ? DBL_MAX : val == -INFINITY ? -DBL_MAX : val; + return val == FloatProps::Inf() ? FloatProps::Max() : val == -FloatProps::Inf() ? - FloatProps::Max() : val; } /// Turns numbers less than or equal to 0 to 0.001 (sort of arbitrary, is there a better way?) @@ -164,7 +188,7 @@ inline ImPlotFloat ConstrainLog(ImPlotFloat val) { /// Returns true if val is NAN or INFINITY inline bool NanOrInf(ImPlotFloat val) { - return val == INFINITY || val == -INFINITY || isnan(val); + return val == FloatProps::Inf() || val == -FloatProps::Inf() || isnan(val); } /// Utility function to that rounds x to powers of 2,5 and 10 for generating axis labels @@ -570,37 +594,38 @@ const char* GetLegendLabel(int i) { // Tick Utils //----------------------------------------------------------------------------- -inline void GetTicks(const ImPlotRange& scale, int nMajor, int nMinor, bool logscale, ImVector &out) { +inline void GetTicks(const ImPlotRange& range, int nMajor, int nMinor, bool logscale, ImVector &out) { out.shrink(0); if (logscale) { - if (scale.Min <= 0 || scale.Max <= 0) + if (range.Min <= 0 || range.Max <= 0) return; - int exp_min = (int)(ImFloor(log10(scale.Min))); - int exp_max = (int)(ImCeil(log10(scale.Max))); + int exp_min = (int)log10(range.Min); + int exp_max = (int)(ceil(log10(range.Max))); for (int e = exp_min - 1; e < exp_max + 1; ++e) { double major1 = ImPow(10, (double)(e)); double major2 = ImPow(10, (double)(e + 1)); double interval = (major2 - major1) / 9; - if (major1 >= (scale.Min - FLT_EPSILON) && major1 <= (scale.Max + FLT_EPSILON)) + if (major1 >= (range.Min - FloatProps::Eps()) && major1 <= (range.Max + FloatProps::Eps())) out.push_back(ImTick(major1, true)); for (int i = 1; i < 9; ++i) { double minor = major1 + i * interval; - if (minor >= (scale.Min - FLT_EPSILON) && minor <= (scale.Max + FLT_EPSILON)) + if (minor >= (range.Min - FloatProps::Eps()) && minor <= (range.Max + FloatProps::Eps())) out.push_back(ImTick(minor, false, false)); } } } else { - const double range = NiceNum(scale.Max - scale.Min, 0); - const double interval = NiceNum(range / (nMajor - 1), 1); - const double graphmin = floor(scale.Min / interval) * interval; - const double graphmax = ceil(scale.Max / interval) * interval; + + const double nice_range = NiceNum(range.Size() * 0.99, 0); + const double interval = NiceNum(nice_range / (nMajor - 1), 1); + const double graphmin = floor(range.Min / interval) * interval; + const double graphmax = ceil(range.Max / interval) * interval; for (double major = graphmin; major < graphmax + 0.5 * interval; major += interval) { - if (major >= scale.Min && major <= scale.Max) + if (major >= range.Min && major <= range.Max) out.push_back(ImTick(major, true)); for (int i = 1; i < nMinor; ++i) { double minor = major + i * interval / nMinor; - if (minor >= scale.Min && minor <= scale.Max) + if (minor >= range.Min && minor <= range.Max) out.push_back(ImTick(minor, false)); } } @@ -817,10 +842,10 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons } if (plot.XAxis.Range.Max <= plot.XAxis.Range.Min) - plot.XAxis.Range.Max = plot.XAxis.Range.Min + FLT_EPSILON; + plot.XAxis.Range.Max = plot.XAxis.Range.Min + FloatProps::Eps(); for (int i = 0; i < MAX_Y_AXES; i++) { if (plot.YAxis[i].Range.Max <= plot.YAxis[i].Range.Min) - plot.YAxis[i].Range.Max = plot.YAxis[i].Range.Min + FLT_EPSILON; + plot.YAxis[i].Range.Max = plot.YAxis[i].Range.Min + FloatProps::Eps(); } // adaptive divisions @@ -1212,7 +1237,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons if (gp.RenderX) { for (int t = 0; t < gp.XTicks.Size; t++) { ImTick *xt = &gp.XTicks[t]; - xt->PixelPos = PlotToPixels(xt->PlotPos, 0, 0).x; + xt->PixelPos = PlotToPixels(xt->PlotPos, 0, 0).x; } } for (int i = 0; i < MAX_Y_AXES; i++) { @@ -1295,11 +1320,11 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons // reset items count gp.VisibleItemCount = 0; // reset extents - gp.ExtentsX.Min = INFINITY; - gp.ExtentsX.Max = -INFINITY; + gp.ExtentsX.Min = FloatProps::Inf(); + gp.ExtentsX.Max = -FloatProps::Inf(); for (int i = 0; i < MAX_Y_AXES; i++) { - gp.ExtentsY[i].Min = INFINITY; - gp.ExtentsY[i].Max = -INFINITY; + gp.ExtentsY[i].Min = FloatProps::Inf(); + gp.ExtentsY[i].Max = -FloatProps::Inf(); } // clear item names gp.LegendLabels.Buf.resize(0); @@ -1313,9 +1338,19 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons // Context Menu //----------------------------------------------------------------------------- +template +bool DragImPlotFloat(const char* label, F* v, float v_speed, F v_min, F v_max) { + return false; +} -bool DragDouble(const char* label, double* v, float v_speed = 1.0f, double v_min = 0.0, double v_max = 0.0, const char* format = "%.3f", float power = 1.0f) { - return ImGui::DragScalar(label, ImGuiDataType_Double, v, v_speed, &v_min, &v_max, format, power); +template <> +bool DragImPlotFloat(const char* label, double* v, float v_speed, double v_min, double v_max) { + return ImGui::DragScalar(label, ImGuiDataType_Double, v, v_speed, &v_min, &v_max, "%.3f", 1); +} + +template <> +bool DragImPlotFloat(const char* label, float* v, float v_speed, float v_min, float v_max) { + return ImGui::DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, "%.3f", 1); } inline void AxisMenu(ImPlotAxis& Axis) { @@ -1334,7 +1369,7 @@ inline void AxisMenu(ImPlotAxis& Axis) { ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.25f); } - DragDouble("Min", &Axis.Range.Min, 0.01f + 0.01f * (Axis.Range.Size()), -INFINITY, Axis.Range.Max - FLT_EPSILON); + DragImPlotFloat("Min", &Axis.Range.Min, 0.01f + 0.01f * (float)Axis.Range.Size(), -FloatProps::Inf(), Axis.Range.Max - FloatProps::Eps()); if (lock_min) { ImGui::PopItemFlag(); ImGui::PopStyleVar(); } @@ -1345,7 +1380,7 @@ inline void AxisMenu(ImPlotAxis& Axis) { if (lock_max) { ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.25f); } - DragDouble("Max", &Axis.Range.Max, 0.01f + 0.01f * (Axis.Range.Size()), Axis.Range.Min + FLT_EPSILON, INFINITY); + DragImPlotFloat("Max", &Axis.Range.Max, 0.01f + 0.01f * (float)Axis.Range.Size(), Axis.Range.Min + FloatProps::Eps(), FloatProps::Inf()); if (lock_max) { ImGui::PopItemFlag(); ImGui::PopStyleVar(); @@ -2672,7 +2707,8 @@ inline void PlotDigitalEx(const char* label_id, Getter getter, int count, int of ImPlotPoint itemData2 = getter(i2); i1 = i2; int pixY_0 = (int)(line_weight); - float pixY_1_float = gp.Style.DigitalBitHeight * ImMax(0.0, itemData1.y); + itemData1.y = itemData1.y < 0 ? 0 : itemData1.y; + float pixY_1_float = gp.Style.DigitalBitHeight * (float)itemData1.y; int pixY_1 = (int)(pixY_1_float); //allow only positive values int pixY_chPosOffset = (int)(ImMax(gp.Style.DigitalBitHeight, pixY_1_float) + gp.Style.DigitalBitGap); pixYMax = ImMax(pixYMax, pixY_chPosOffset); From 5e82afdbdd004aa596b55d7804076bb0a1b34505 Mon Sep 17 00:00:00 2001 From: Evan Pezent Date: Fri, 29 May 2020 08:40:04 -0500 Subject: [PATCH 4/5] change transformers names --- implot.cpp | 50 ++++++++++++++++++++++++++------------------------ implot.h | 4 +++- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/implot.cpp b/implot.cpp index 7ab5525..58b584b 100644 --- a/implot.cpp +++ b/implot.cpp @@ -504,11 +504,11 @@ ImVec2 PlotToPixels(const ImPlotPoint& plt, int y_axis) { // Transformer structs -struct Plt2PixLinLin { - Plt2PixLinLin(int y_axis_in) : y_axis(y_axis_in) {} +struct TransformerLinLin { + TransformerLinLin(int y_axis_in) : y_axis(y_axis_in) {} - ImVec2 operator()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); } - ImVec2 operator()(ImPlotFloat x, ImPlotFloat y) { + inline ImVec2 operator()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); } + inline ImVec2 operator()(ImPlotFloat x, ImPlotFloat y) { return ImVec2( (float)(gp.PixelRange[y_axis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min)), (float)(gp.PixelRange[y_axis].Min.y + gp.My[y_axis] * (y - gp.CurrentPlot->YAxis[y_axis].Range.Min)) ); } @@ -516,11 +516,11 @@ struct Plt2PixLinLin { int y_axis; }; -struct Plt2PixLogLin { - Plt2PixLogLin(int y_axis_in) : y_axis(y_axis_in) {} +struct TransformerLogLin { + TransformerLogLin(int y_axis_in) : y_axis(y_axis_in) {} - ImVec2 operator()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); } - ImVec2 operator()(ImPlotFloat x, ImPlotFloat y) { + inline ImVec2 operator()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); } + inline ImVec2 operator()(ImPlotFloat x, ImPlotFloat y) { ImPlotFloat t = log10(x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX; x = ImLerp(gp.CurrentPlot->XAxis.Range.Min, gp.CurrentPlot->XAxis.Range.Max, (float)t); return ImVec2( (float)(gp.PixelRange[y_axis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min)), @@ -530,11 +530,11 @@ struct Plt2PixLogLin { int y_axis; }; -struct Plt2PixLinLog { - Plt2PixLinLog(int y_axis_in) : y_axis(y_axis_in) {} +struct TransformerLinLog { + TransformerLinLog(int y_axis_in) : y_axis(y_axis_in) {} - ImVec2 operator()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); } - ImVec2 operator()(ImPlotFloat x, ImPlotFloat y) { + inline ImVec2 operator()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); } + inline ImVec2 operator()(ImPlotFloat x, ImPlotFloat y) { ImPlotFloat t = log10(y / gp.CurrentPlot->YAxis[y_axis].Range.Min) / gp.LogDenY[y_axis]; y = ImLerp(gp.CurrentPlot->YAxis[y_axis].Range.Min, gp.CurrentPlot->YAxis[y_axis].Range.Max, (float)t); return ImVec2( (float)(gp.PixelRange[y_axis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min)), @@ -543,11 +543,13 @@ struct Plt2PixLinLog { int y_axis; }; -struct Plt2PixLogLog { - Plt2PixLogLog(int y_axis_in) : y_axis(y_axis_in) {} +struct TransformerLogLog { + TransformerLogLog(int y_axis_in) : y_axis(y_axis_in) { - ImVec2 operator()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); } - ImVec2 operator()(ImPlotFloat x, ImPlotFloat y) { + } + + inline ImVec2 operator()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); } + inline ImVec2 operator()(ImPlotFloat x, ImPlotFloat y) { ImPlotFloat t = log10(x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX; x = ImLerp(gp.CurrentPlot->XAxis.Range.Min, gp.CurrentPlot->XAxis.Range.Max, (float)t); t = log10(y / gp.CurrentPlot->YAxis[y_axis].Range.Min) / gp.LogDenY[y_axis]; @@ -2269,24 +2271,24 @@ inline void PlotEx(const char* label_id, Getter getter, int count, int offset) PushPlotClipRect(); if (count > 1 && rend_line) { if (HasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale) && HasFlag(plot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) - RenderLineStrip(Plt2PixLogLog(y_axis), DrawList, getter, count, offset, line_weight, col_line, cull); + RenderLineStrip(TransformerLogLog(y_axis), DrawList, getter, count, offset, line_weight, col_line, cull); else if (HasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale)) - RenderLineStrip(Plt2PixLogLin(y_axis), DrawList, getter, count, offset, line_weight, col_line, cull); + RenderLineStrip(TransformerLogLin(y_axis), DrawList, getter, count, offset, line_weight, col_line, cull); else if (HasFlag(plot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) - RenderLineStrip(Plt2PixLinLog(y_axis), DrawList, getter, count, offset, line_weight, col_line, cull); + RenderLineStrip(TransformerLinLog(y_axis), DrawList, getter, count, offset, line_weight, col_line, cull); else - RenderLineStrip(Plt2PixLinLin(y_axis), DrawList, getter, count, offset, line_weight, col_line, cull); + RenderLineStrip(TransformerLinLin(y_axis), DrawList, getter, count, offset, line_weight, col_line, cull); } // render markers if (gp.Style.Marker != ImPlotMarker_None) { if (HasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale) && HasFlag(plot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) - RenderMarkers(Plt2PixLogLog(y_axis), DrawList, getter, count, offset, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, cull); + RenderMarkers(TransformerLogLog(y_axis), DrawList, getter, count, offset, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, cull); else if (HasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale)) - RenderMarkers(Plt2PixLogLin(y_axis), DrawList, getter, count, offset, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, cull); + RenderMarkers(TransformerLogLin(y_axis), DrawList, getter, count, offset, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, cull); else if (HasFlag(plot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) - RenderMarkers(Plt2PixLinLog(y_axis), DrawList, getter, count, offset, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, cull); + RenderMarkers(TransformerLinLog(y_axis), DrawList, getter, count, offset, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, cull); else - RenderMarkers(Plt2PixLinLin(y_axis), DrawList, getter, count, offset, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, cull); + RenderMarkers(TransformerLinLin(y_axis), DrawList, getter, count, offset, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, cull); } PopPlotClipRect(); } diff --git a/implot.h b/implot.h index 900c70b..db79309 100644 --- a/implot.h +++ b/implot.h @@ -177,7 +177,7 @@ bool BeginPlot(const char* title_id, void EndPlot(); //----------------------------------------------------------------------------- -// Plot Items +// Plot Items (float) //----------------------------------------------------------------------------- // Plots a standard 2D line plot. @@ -210,6 +210,8 @@ void PlotDigital(const char* label_id, ImVec2 (*getter)(void* data, int idx), vo // Plots a text label at point x,y. void PlotText(const char* text, float x, float y, bool vertical = false, const ImVec2& pixel_offset = ImVec2(0,0)); + + //----------------------------------------------------------------------------- // Plot Queries //----------------------------------------------------------------------------- From 43625257b038917842505112745d383e59987125 Mon Sep 17 00:00:00 2001 From: Evan Pezent Date: Fri, 29 May 2020 12:39:30 -0500 Subject: [PATCH 5/5] double precision work complete --- implot.cpp | 547 ++++++++++++++++++++++++++++++------------------ implot.h | 65 ++++-- implot_demo.cpp | 279 +++++++++++++----------- 3 files changed, 544 insertions(+), 347 deletions(-) diff --git a/implot.cpp b/implot.cpp index 58b584b..518c60a 100644 --- a/implot.cpp +++ b/implot.cpp @@ -20,7 +20,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -// ImPlot v0.2 WIP +// ImPlot v0.3 WIP /* @@ -31,6 +31,7 @@ Below is a change-log of API breaking changes only. If you are using one of the When you are not sure about a old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all implot files. You can read releases logs https://github.com/epezent/implot/releases for more details. +- 2020/05/29 (0.3) - The signature of ImPlotLimits::Contains was changed to take two doubles instead of ImVec2 - 2020/05/16 (0.2) - All plotting functions were reverted to being prefixed with "Plot" to maintain a consistent VerbNoun style. `Plot` was split into `PlotLine` and `PlotScatter` (however, `PlotLine` can still be used to plot scatter points as `Plot` did before.). `Bar` is not `PlotBars`, to indicate that multiple bars will be plotted. @@ -78,6 +79,9 @@ You can read releases logs https://github.com/epezent/implot/releases for more d // The maximum number of support y-axes #define MAX_Y_AXES 3 +// static inline float ImLog10(float x) { return log10f(x); } +static inline double ImLog10(double x) { return log10(x); } + ImPlotStyle::ImPlotStyle() { LineWeight = 1; Marker = ImPlotMarker_None; @@ -108,18 +112,18 @@ ImPlotRange::ImPlotRange() { Max = NAN; } -bool ImPlotRange::Contains(ImPlotFloat v) const { +bool ImPlotRange::Contains(double v) const { return v >= Min && v <= Max; } -ImPlotFloat ImPlotRange::Size() const { +double ImPlotRange::Size() const { return Max - Min; } ImPlotLimits::ImPlotLimits() {} -bool ImPlotLimits::Contains(const ImVec2& p) const { - return X.Contains(p.x) && Y.Contains(p.y); +bool ImPlotLimits::Contains(double x, double y) const { + return X.Contains(x) && Y.Contains(y); } namespace ImPlot { @@ -130,30 +134,6 @@ namespace { // Private Utils //----------------------------------------------------------------------------- -template -struct FloatProps { - static inline F Min(); - static inline F Max(); - static inline F Eps(); - static inline F Inf(); -}; - -template <> -struct FloatProps { - static inline float Min() { return FLT_MIN; } - static inline float Max() { return FLT_MAX; } - static inline float Eps() { return FLT_EPSILON; } - static inline float Inf() { return HUGE_VALF; } -}; - -template <> -struct FloatProps { - static inline double Min() { return DBL_MIN; } - static inline double Max() { return DBL_MAX; } - static inline double Eps() { return DBL_EPSILON; } - static inline double Inf() { return HUGE_VAL; } -}; - /// Returns true if a flag is set template inline bool HasFlag(TSet set, TFlag flag) { @@ -172,23 +152,23 @@ inline float Remap(float x, float x0, float x1, float y0, float y1) { } /// Turns NANs to 0s -inline ImPlotFloat ConstrainNan(ImPlotFloat val) { +inline double ConstrainNan(double val) { return isnan(val) ? 0 : val; } /// Turns infinity to floating point maximums -inline ImPlotFloat ConstrainInf(ImPlotFloat val) { - return val == FloatProps::Inf() ? FloatProps::Max() : val == -FloatProps::Inf() ? - FloatProps::Max() : val; +inline double ConstrainInf(double val) { + return val == HUGE_VAL ? DBL_MAX : val == -HUGE_VAL ? - DBL_MAX : val; } /// Turns numbers less than or equal to 0 to 0.001 (sort of arbitrary, is there a better way?) -inline ImPlotFloat ConstrainLog(ImPlotFloat val) { +inline double ConstrainLog(double val) { return val <= 0 ? 0.001f : val; } /// Returns true if val is NAN or INFINITY -inline bool NanOrInf(ImPlotFloat val) { - return val == FloatProps::Inf() || val == -FloatProps::Inf() || isnan(val); +inline bool NanOrInf(double val) { + return val == HUGE_VAL || val == -HUGE_VAL || isnan(val); } /// Utility function to that rounds x to powers of 2,5 and 10 for generating axis labels @@ -196,7 +176,7 @@ inline bool NanOrInf(ImPlotFloat val) { inline double NiceNum(double x, bool round) { double f; /* fractional part of x */ double nf; /* nice, rounded fraction */ - int expv = (int)floor(log10(x)); + int expv = (int)floor(ImLog10(x)); f = x / ImPow(10.0, (double)expv); /* between 1 and 10 */ if (round) if (f < 1.5) @@ -260,17 +240,17 @@ ImVec4 NextColor(); /// Tick mark info struct ImTick { - ImTick(ImPlotFloat value, bool major, bool render_label = true) { + ImTick(double value, bool major, bool render_label = true) { PlotPos = value; Major = major; RenderLabel = render_label; } - ImPlotFloat PlotPos; + double PlotPos; float PixelPos; ImVec2 Size; - int TextOffset; + int TextOffset; bool Major; - bool RenderLabel; + bool RenderLabel; }; struct ImPlotItem { @@ -380,11 +360,11 @@ struct ImPlotContext { // Transformation cache ImRect PixelRange[MAX_Y_AXES]; // linear scale (slope) - ImPlotFloat Mx; - ImPlotFloat My[MAX_Y_AXES]; + double Mx; + double My[MAX_Y_AXES]; // log scale denominator - ImPlotFloat LogDenX; - ImPlotFloat LogDenY[MAX_Y_AXES]; + double LogDenX; + double LogDenY[MAX_Y_AXES]; // Data extents ImPlotRange ExtentsX; ImPlotRange ExtentsY[MAX_Y_AXES]; @@ -393,7 +373,7 @@ struct ImPlotContext { bool FitY[MAX_Y_AXES] = {}; // Hover states bool Hov_Frame; - bool Hov_Grid; + bool Hov_Grid; // Render flags bool RenderX, RenderY[MAX_Y_AXES]; // Mouse pos @@ -451,9 +431,9 @@ inline void UpdateTransformCache() { gp.My[i] = (gp.PixelRange[i].Max.y - gp.PixelRange[i].Min.y) / gp.CurrentPlot->YAxis[i].Range.Size(); } - gp.LogDenX = log10(gp.CurrentPlot->XAxis.Range.Max / gp.CurrentPlot->XAxis.Range.Min); + gp.LogDenX = ImLog10(gp.CurrentPlot->XAxis.Range.Max / gp.CurrentPlot->XAxis.Range.Min); for (int i = 0; i < MAX_Y_AXES; i++) { - gp.LogDenY[i] = log10(gp.CurrentPlot->YAxis[i].Range.Max / gp.CurrentPlot->YAxis[i].Range.Min); + gp.LogDenY[i] = ImLog10(gp.CurrentPlot->YAxis[i].Range.Max / gp.CurrentPlot->YAxis[i].Range.Min); } gp.Mx = (gp.PixelRange[0].Max.x - gp.PixelRange[0].Min.x) / gp.CurrentPlot->XAxis.Range.Size(); } @@ -465,12 +445,12 @@ inline ImPlotPoint PixelsToPlot(float x, float y, int y_axis_in = -1) { plt.x = (x - gp.PixelRange[y_axis].Min.x) / gp.Mx + gp.CurrentPlot->XAxis.Range.Min; plt.y = (y - gp.PixelRange[y_axis].Min.y) / gp.My[y_axis] + gp.CurrentPlot->YAxis[y_axis].Range.Min; if (HasFlag(gp.CurrentPlot->XAxis.Flags, ImPlotAxisFlags_LogScale)) { - ImPlotFloat t = (plt.x - gp.CurrentPlot->XAxis.Range.Min) / gp.CurrentPlot->XAxis.Range.Size(); - plt.x = pow(10.0f, t * gp.LogDenX) * gp.CurrentPlot->XAxis.Range.Min; + double t = (plt.x - gp.CurrentPlot->XAxis.Range.Min) / gp.CurrentPlot->XAxis.Range.Size(); + plt.x = ImPow(10, t * gp.LogDenX) * gp.CurrentPlot->XAxis.Range.Min; } if (HasFlag(gp.CurrentPlot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) { - ImPlotFloat t = (plt.y - gp.CurrentPlot->YAxis[y_axis].Range.Min) / gp.CurrentPlot->YAxis[y_axis].Range.Size(); - plt.y = pow(10.0f, t * gp.LogDenY[y_axis]) * gp.CurrentPlot->YAxis[y_axis].Range.Min; + double t = (plt.y - gp.CurrentPlot->YAxis[y_axis].Range.Min) / gp.CurrentPlot->YAxis[y_axis].Range.Size(); + plt.y = ImPow(10, t * gp.LogDenY[y_axis]) * gp.CurrentPlot->YAxis[y_axis].Range.Min; } return plt; } @@ -480,16 +460,16 @@ ImPlotPoint PixelsToPlot(const ImVec2& pix, int y_axis) { } // This function is convenient but should not be used to process a high volume of points. Use the Transformer structs below instead. -inline ImVec2 PlotToPixels(ImPlotFloat x, ImPlotFloat y, int y_axis_in = -1) { +inline ImVec2 PlotToPixels(double x, double y, int y_axis_in = -1) { IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PlotToPixels() Needs to be called between BeginPlot() and EndPlot()!"); const int y_axis = y_axis_in >= 0 ? y_axis_in : gp.CurrentPlot->CurrentYAxis; ImVec2 pix; if (HasFlag(gp.CurrentPlot->XAxis.Flags, ImPlotAxisFlags_LogScale)) { - ImPlotFloat t = log10(x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX; + double t = ImLog10(x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX; x = ImLerp(gp.CurrentPlot->XAxis.Range.Min, gp.CurrentPlot->XAxis.Range.Max, (float)t); } if (HasFlag(gp.CurrentPlot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) { - ImPlotFloat t = log10(y / gp.CurrentPlot->YAxis[y_axis].Range.Min) / gp.LogDenY[y_axis]; + double t = ImLog10(y / gp.CurrentPlot->YAxis[y_axis].Range.Min) / gp.LogDenY[y_axis]; y = ImLerp(gp.CurrentPlot->YAxis[y_axis].Range.Min, gp.CurrentPlot->YAxis[y_axis].Range.Max, (float)t); } pix.x = (float)(gp.PixelRange[y_axis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min)); @@ -502,13 +482,13 @@ ImVec2 PlotToPixels(const ImPlotPoint& plt, int y_axis) { return PlotToPixels(plt.x, plt.y, y_axis); } -// Transformer structs +// Transformer functors struct TransformerLinLin { TransformerLinLin(int y_axis_in) : y_axis(y_axis_in) {} inline ImVec2 operator()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); } - inline ImVec2 operator()(ImPlotFloat x, ImPlotFloat y) { + inline ImVec2 operator()(double x, double y) { return ImVec2( (float)(gp.PixelRange[y_axis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min)), (float)(gp.PixelRange[y_axis].Min.y + gp.My[y_axis] * (y - gp.CurrentPlot->YAxis[y_axis].Range.Min)) ); } @@ -520,8 +500,8 @@ struct TransformerLogLin { TransformerLogLin(int y_axis_in) : y_axis(y_axis_in) {} inline ImVec2 operator()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); } - inline ImVec2 operator()(ImPlotFloat x, ImPlotFloat y) { - ImPlotFloat t = log10(x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX; + inline ImVec2 operator()(double x, double y) { + double t = ImLog10(x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX; x = ImLerp(gp.CurrentPlot->XAxis.Range.Min, gp.CurrentPlot->XAxis.Range.Max, (float)t); return ImVec2( (float)(gp.PixelRange[y_axis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min)), (float)(gp.PixelRange[y_axis].Min.y + gp.My[y_axis] * (y - gp.CurrentPlot->YAxis[y_axis].Range.Min)) ); @@ -534,9 +514,9 @@ struct TransformerLinLog { TransformerLinLog(int y_axis_in) : y_axis(y_axis_in) {} inline ImVec2 operator()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); } - inline ImVec2 operator()(ImPlotFloat x, ImPlotFloat y) { - ImPlotFloat t = log10(y / gp.CurrentPlot->YAxis[y_axis].Range.Min) / gp.LogDenY[y_axis]; - y = ImLerp(gp.CurrentPlot->YAxis[y_axis].Range.Min, gp.CurrentPlot->YAxis[y_axis].Range.Max, (float)t); + inline ImVec2 operator()(double x, double y) { + double t = ImLog10(y / gp.CurrentPlot->YAxis[y_axis].Range.Min) / gp.LogDenY[y_axis]; + y = ImLerp(gp.CurrentPlot->YAxis[y_axis].Range.Min, gp.CurrentPlot->YAxis[y_axis].Range.Max, (float)t); return ImVec2( (float)(gp.PixelRange[y_axis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min)), (float)(gp.PixelRange[y_axis].Min.y + gp.My[y_axis] * (y - gp.CurrentPlot->YAxis[y_axis].Range.Min)) ); } @@ -549,11 +529,11 @@ struct TransformerLogLog { } inline ImVec2 operator()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); } - inline ImVec2 operator()(ImPlotFloat x, ImPlotFloat y) { - ImPlotFloat t = log10(x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX; - x = ImLerp(gp.CurrentPlot->XAxis.Range.Min, gp.CurrentPlot->XAxis.Range.Max, (float)t); - t = log10(y / gp.CurrentPlot->YAxis[y_axis].Range.Min) / gp.LogDenY[y_axis]; - y = ImLerp(gp.CurrentPlot->YAxis[y_axis].Range.Min, gp.CurrentPlot->YAxis[y_axis].Range.Max, (float)t); + inline ImVec2 operator()(double x, double y) { + double t = ImLog10(x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX; + x = ImLerp(gp.CurrentPlot->XAxis.Range.Min, gp.CurrentPlot->XAxis.Range.Max, (float)t); + t = ImLog10(y / gp.CurrentPlot->YAxis[y_axis].Range.Min) / gp.LogDenY[y_axis]; + y = ImLerp(gp.CurrentPlot->YAxis[y_axis].Range.Min, gp.CurrentPlot->YAxis[y_axis].Range.Max, (float)t); return ImVec2( (float)(gp.PixelRange[y_axis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min)), (float)(gp.PixelRange[y_axis].Min.y + gp.My[y_axis] * (y - gp.CurrentPlot->YAxis[y_axis].Range.Min)) ); } @@ -601,17 +581,17 @@ inline void GetTicks(const ImPlotRange& range, int nMajor, int nMinor, bool logs if (logscale) { if (range.Min <= 0 || range.Max <= 0) return; - int exp_min = (int)log10(range.Min); - int exp_max = (int)(ceil(log10(range.Max))); + int exp_min = (int)ImLog10(range.Min); + int exp_max = (int)(ceil(ImLog10(range.Max))); for (int e = exp_min - 1; e < exp_max + 1; ++e) { double major1 = ImPow(10, (double)(e)); double major2 = ImPow(10, (double)(e + 1)); double interval = (major2 - major1) / 9; - if (major1 >= (range.Min - FloatProps::Eps()) && major1 <= (range.Max + FloatProps::Eps())) + if (major1 >= (range.Min - DBL_EPSILON) && major1 <= (range.Max + DBL_EPSILON)) out.push_back(ImTick(major1, true)); for (int i = 1; i < 9; ++i) { double minor = major1 + i * interval; - if (minor >= (range.Min - FloatProps::Eps()) && minor <= (range.Max + FloatProps::Eps())) + if (minor >= (range.Min - DBL_EPSILON) && minor <= (range.Max + DBL_EPSILON)) out.push_back(ImTick(minor, false, false)); } } @@ -844,10 +824,10 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons } if (plot.XAxis.Range.Max <= plot.XAxis.Range.Min) - plot.XAxis.Range.Max = plot.XAxis.Range.Min + FloatProps::Eps(); + plot.XAxis.Range.Max = plot.XAxis.Range.Min + DBL_EPSILON; for (int i = 0; i < MAX_Y_AXES; i++) { if (plot.YAxis[i].Range.Max <= plot.YAxis[i].Range.Min) - plot.YAxis[i].Range.Max = plot.YAxis[i].Range.Min + FloatProps::Eps(); + plot.YAxis[i].Range.Max = plot.YAxis[i].Range.Min + DBL_EPSILON; } // adaptive divisions @@ -1239,7 +1219,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons if (gp.RenderX) { for (int t = 0; t < gp.XTicks.Size; t++) { ImTick *xt = &gp.XTicks[t]; - xt->PixelPos = PlotToPixels(xt->PlotPos, 0, 0).x; + xt->PixelPos = PlotToPixels(xt->PlotPos, 0, 0).x; } } for (int i = 0; i < MAX_Y_AXES; i++) { @@ -1322,11 +1302,11 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons // reset items count gp.VisibleItemCount = 0; // reset extents - gp.ExtentsX.Min = FloatProps::Inf(); - gp.ExtentsX.Max = -FloatProps::Inf(); + gp.ExtentsX.Min = HUGE_VAL; + gp.ExtentsX.Max = -HUGE_VAL; for (int i = 0; i < MAX_Y_AXES; i++) { - gp.ExtentsY[i].Min = FloatProps::Inf(); - gp.ExtentsY[i].Max = -FloatProps::Inf(); + gp.ExtentsY[i].Min = HUGE_VAL; + gp.ExtentsY[i].Max = -HUGE_VAL; } // clear item names gp.LegendLabels.Buf.resize(0); @@ -1341,17 +1321,17 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons //----------------------------------------------------------------------------- template -bool DragImPlotFloat(const char* label, F* v, float v_speed, F v_min, F v_max) { +bool Dragdouble(const char* label, F* v, float v_speed, F v_min, F v_max) { return false; } template <> -bool DragImPlotFloat(const char* label, double* v, float v_speed, double v_min, double v_max) { +bool Dragdouble(const char* label, double* v, float v_speed, double v_min, double v_max) { return ImGui::DragScalar(label, ImGuiDataType_Double, v, v_speed, &v_min, &v_max, "%.3f", 1); } template <> -bool DragImPlotFloat(const char* label, float* v, float v_speed, float v_min, float v_max) { +bool Dragdouble(const char* label, float* v, float v_speed, float v_min, float v_max) { return ImGui::DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, "%.3f", 1); } @@ -1371,7 +1351,7 @@ inline void AxisMenu(ImPlotAxis& Axis) { ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.25f); } - DragImPlotFloat("Min", &Axis.Range.Min, 0.01f + 0.01f * (float)Axis.Range.Size(), -FloatProps::Inf(), Axis.Range.Max - FloatProps::Eps()); + Dragdouble("Min", &Axis.Range.Min, 0.01f + 0.01f * (float)Axis.Range.Size(), -HUGE_VAL, Axis.Range.Max - DBL_EPSILON); if (lock_min) { ImGui::PopItemFlag(); ImGui::PopStyleVar(); } @@ -1382,7 +1362,7 @@ inline void AxisMenu(ImPlotAxis& Axis) { if (lock_max) { ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.25f); } - DragImPlotFloat("Max", &Axis.Range.Max, 0.01f + 0.01f * (float)Axis.Range.Size(), Axis.Range.Min + FloatProps::Eps(), FloatProps::Inf()); + Dragdouble("Max", &Axis.Range.Max, 0.01f + 0.01f * (float)Axis.Range.Size(), Axis.Range.Min + DBL_EPSILON, HUGE_VAL); if (lock_max) { ImGui::PopItemFlag(); ImGui::PopStyleVar(); @@ -1752,12 +1732,12 @@ void EndPlot() { // MISC API //----------------------------------------------------------------------------- -void SetNextPlotLimits(ImPlotFloat x_min, ImPlotFloat x_max, ImPlotFloat y_min, ImPlotFloat y_max, ImGuiCond cond) { +void SetNextPlotLimits(double x_min, double x_max, double y_min, double y_max, ImGuiCond cond) { SetNextPlotLimitsX(x_min, x_max, cond); SetNextPlotLimitsY(y_min, y_max, cond); } -void SetNextPlotLimitsX(ImPlotFloat x_min, ImPlotFloat x_max, ImGuiCond cond) { +void SetNextPlotLimitsX(double x_min, double x_max, ImGuiCond cond) { IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. gp.NextPlotData.HasXRange = true; gp.NextPlotData.XRangeCond = cond; @@ -1765,7 +1745,7 @@ void SetNextPlotLimitsX(ImPlotFloat x_min, ImPlotFloat x_max, ImGuiCond cond) { gp.NextPlotData.X.Max = x_max; } -void SetNextPlotLimitsY(ImPlotFloat y_min, ImPlotFloat y_max, ImGuiCond cond, int y_axis) { +void SetNextPlotLimitsY(double y_min, double y_max, ImGuiCond cond, int y_axis) { IM_ASSERT_USER_ERROR(y_axis >= 0 && y_axis < MAX_Y_AXES, "y_axis Needs to be between 0 and MAX_Y_AXES"); IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. gp.NextPlotData.HasYRange[y_axis] = true; @@ -2070,7 +2050,7 @@ inline void MarkerCross(ImDrawList& DrawList, const ImVec2& c, float s, bool /*o } template -inline void RenderMarkers(Transformer transformer, ImDrawList& DrawList, Getter getter, int count, int offset, bool rend_mk_line, ImU32 col_mk_line, bool rend_mk_fill, ImU32 col_mk_fill, bool cull) { +inline void RenderMarkers(Getter getter, Transformer transformer, ImDrawList& DrawList, int count, int offset, bool rend_mk_line, ImU32 col_mk_line, bool rend_mk_fill, ImU32 col_mk_fill, bool cull) { int idx = offset; for (int i = 0; i < count; ++i) { ImVec2 c; @@ -2140,8 +2120,8 @@ inline void RenderLineAA(ImDrawList& DrawList, const ImVec2& p1, const ImVec2& p DrawList.AddLine(p1, p2, col_line, line_weight); } -template -inline void RenderLineStrip(Transformer transformer, ImDrawList& DrawList, Getter getter, int count, int offset, float line_weight, ImU32 col_line, bool cull) { +template +inline void RenderLineStrip(Getter getter, Transformer transformer, ImDrawList& DrawList, int count, int offset, float line_weight, ImU32 col_line, bool cull) { // render line segments offset %= count; if (offset < 0) offset += count; // shift negative offset to positive range @@ -2149,16 +2129,16 @@ inline void RenderLineStrip(Transformer transformer, ImDrawList& DrawList, Gette if (i_start >= count ) i_start -= count; int i_end = offset + count; if (i_end >= count) i_end -= count; - + const int segments = count - 1; - ImVec2 p1 = transformer(getter(offset)); + ImVec2 p1 = transformer(getter(offset)); if (HasFlag(gp.CurrentPlot->Flags, ImPlotFlags_AntiAliased)) { for (int i1 = i_start; i1 != i_end; i1 = i1 + 1 < count ? i1 + 1 : i1 + 1 - count) { ImVec2 p2 = transformer(getter(i1)); if (!cull || gp.BB_Grid.Overlaps(ImRect(ImMin(p1,p2), ImMax(p1,p2)))) RenderLineAA(DrawList, p1, p2, line_weight, col_line); - p1 = p2; + p1 = p2; } } else { @@ -2166,7 +2146,7 @@ inline void RenderLineStrip(Transformer transformer, ImDrawList& DrawList, Gette DrawList.PrimReserve(segments * 6, segments * 4); int segments_culled = 0; for (int i1 = i_start; i1 != i_end; i1 = i1 + 1 < count ? i1 + 1 : i1 + 1 - count) { - ImVec2 p2 = transformer(getter(i1)); + ImVec2 p2 = transformer(getter(i1)); if (!cull || gp.BB_Grid.Overlaps(ImRect(ImMin(p1, p2), ImMax(p1, p2)))) RenderLine(DrawList, p1, p2, line_weight, col_line, uv); @@ -2199,8 +2179,8 @@ struct GetterYs { }; template -struct Getter2D { - Getter2D(const T* xs, const T* ys, int stride) { Xs = xs; Ys = ys; Stride = stride; } +struct GetterXsYs { + GetterXsYs(const T* xs, const T* ys, int stride) { Xs = xs; Ys = ys; Stride = stride; } const T* Xs; const T* Ys; int Stride; @@ -2209,6 +2189,19 @@ struct Getter2D { } }; +struct GetterImPlotPoint { + GetterImPlotPoint(const ImPlotPoint* data) { Data = data; } + inline ImPlotPoint operator()(int idx) { return Data[idx]; } + const ImPlotPoint* Data; +}; + +struct GetterFuncPtrImPlotPoint { + GetterFuncPtrImPlotPoint(ImPlotPoint (*g)(void* data, int idx), void* d) { getter = g; data = d;} + inline ImPlotPoint operator()(int idx) { return getter(data, idx); } + ImPlotPoint (*getter)(void* data, int idx); + void* data; +}; + struct GetterImVec2 { GetterImVec2(const ImVec2* data) { Data = data; } inline ImPlotPoint operator()(int idx) { return ImPlotPoint(Data[idx].x, Data[idx].y); } @@ -2222,13 +2215,6 @@ struct GetterFuncPtrImVec2 { void* data; }; -struct GetterFuncPtrImVec4 { - GetterFuncPtrImVec4(ImVec4 (*g)(void* data, int idx), void* d) { getter = g; data = d;} - inline ImVec4 operator()(int idx) { return getter(data, idx); } - ImVec4 (*getter)(void* data, int idx); - void* data; -}; - //----------------------------------------------------------------------------- // PLOT //----------------------------------------------------------------------------- @@ -2271,35 +2257,38 @@ inline void PlotEx(const char* label_id, Getter getter, int count, int offset) PushPlotClipRect(); if (count > 1 && rend_line) { if (HasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale) && HasFlag(plot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) - RenderLineStrip(TransformerLogLog(y_axis), DrawList, getter, count, offset, line_weight, col_line, cull); + RenderLineStrip(getter, TransformerLogLog(y_axis), DrawList, count, offset, line_weight, col_line, cull); else if (HasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale)) - RenderLineStrip(TransformerLogLin(y_axis), DrawList, getter, count, offset, line_weight, col_line, cull); + RenderLineStrip(getter, TransformerLogLin(y_axis), DrawList, count, offset, line_weight, col_line, cull); else if (HasFlag(plot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) - RenderLineStrip(TransformerLinLog(y_axis), DrawList, getter, count, offset, line_weight, col_line, cull); + RenderLineStrip(getter, TransformerLinLog(y_axis), DrawList, count, offset, line_weight, col_line, cull); else - RenderLineStrip(TransformerLinLin(y_axis), DrawList, getter, count, offset, line_weight, col_line, cull); + RenderLineStrip(getter, TransformerLinLin(y_axis), DrawList, count, offset, line_weight, col_line, cull); } // render markers if (gp.Style.Marker != ImPlotMarker_None) { if (HasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale) && HasFlag(plot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) - RenderMarkers(TransformerLogLog(y_axis), DrawList, getter, count, offset, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, cull); + RenderMarkers(getter, TransformerLogLog(y_axis), DrawList, count, offset, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, cull); else if (HasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale)) - RenderMarkers(TransformerLogLin(y_axis), DrawList, getter, count, offset, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, cull); + RenderMarkers(getter, TransformerLogLin(y_axis), DrawList, count, offset, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, cull); else if (HasFlag(plot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) - RenderMarkers(TransformerLinLog(y_axis), DrawList, getter, count, offset, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, cull); + RenderMarkers(getter, TransformerLinLog(y_axis), DrawList, count, offset, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, cull); else - RenderMarkers(TransformerLinLin(y_axis), DrawList, getter, count, offset, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, cull); + RenderMarkers(getter, TransformerLinLin(y_axis), DrawList, count, offset, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, cull); } PopPlotClipRect(); } +//----------------------------------------------------------------------------- +// float + void PlotLine(const char* label_id, const float* values, int count, int offset, int stride) { - GetterYs getter(values,stride); + GetterYs getter(values,stride); PlotEx(label_id, getter, count, offset); } void PlotLine(const char* label_id, const float* xs, const float* ys, int count, int offset, int stride) { - Getter2D getter(xs,ys,stride); + GetterXsYs getter(xs,ys,stride); return PlotEx(label_id, getter, count, offset); } @@ -2313,56 +2302,99 @@ void PlotLine(const char* label_id, ImVec2 (*getter_func)(void* data, int idx), return PlotEx(label_id, getter, count, offset); } +//----------------------------------------------------------------------------- +// double + +void PlotLine(const char* label_id, const double* values, int count, int offset, int stride) { + GetterYs getter(values,stride); + PlotEx(label_id, getter, count, offset); +} + +void PlotLine(const char* label_id, const double* xs, const double* ys, int count, int offset, int stride) { + GetterXsYs getter(xs,ys,stride); + return PlotEx(label_id, getter, count, offset); +} + +void PlotLine(const char* label_id, const ImPlotPoint* data, int count, int offset) { + GetterImPlotPoint getter(data); + return PlotEx(label_id, getter, count, offset); +} + +void PlotLine(const char* label_id, ImPlotPoint (*getter_func)(void* data, int idx), void* data, int count, int offset) { + GetterFuncPtrImPlotPoint getter(getter_func,data); + return PlotEx(label_id, getter, count, offset); +} + //----------------------------------------------------------------------------- // PLOT SCATTER //----------------------------------------------------------------------------- -void PlotScatter(const char* label_id, const float* values, int count, int offset, int stride) { - int pops = 1; +inline int PushScatterStyle() { + int vars = 1; PushStyleVar(ImPlotStyleVar_LineWeight, 0); if (GetStyle().Marker == ImPlotMarker_None) { PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Circle); - pops++; + vars++; } - PlotLine(label_id, values, count, offset, stride); - PopStyleVar(pops); -} - -void PlotScatter(const char* label_id, const float* xs, const float* ys, int count, int offset, int stride) { - int pops = 1; - PushStyleVar(ImPlotStyleVar_LineWeight, 0); - if (GetStyle().Marker == ImPlotMarker_None) { - PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Circle); - pops++; - } - PlotLine(label_id, xs, ys, count, offset, stride); - PopStyleVar(pops); -} - -void PlotScatter(const char* label_id, const ImVec2* data, int count, int offset) { - int pops = 1; - PushStyleVar(ImPlotStyleVar_LineWeight, 0); - if (GetStyle().Marker == ImPlotMarker_None) { - PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Circle); - pops++; - } - PlotLine(label_id, data, count, offset); - PopStyleVar(pops); -} - -void PlotScatter(const char* label_id, ImVec2 (*getter)(void* data, int idx), void* data, int count, int offset) { - int pops = 1; - PushStyleVar(ImPlotStyleVar_LineWeight, 0); - if (GetStyle().Marker == ImPlotMarker_None) { - PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Circle); - pops++; - } - PlotLine(label_id, getter, data, count, offset); - PopStyleVar(pops); + return vars; } //----------------------------------------------------------------------------- -// PLOT BAR +// float + +void PlotScatter(const char* label_id, const float* values, int count, int offset, int stride) { + int vars = PushScatterStyle(); + PlotLine(label_id, values, count, offset, stride); + PopStyleVar(vars); +} + +void PlotScatter(const char* label_id, const float* xs, const float* ys, int count, int offset, int stride) { + int vars = PushScatterStyle(); + PlotLine(label_id, xs, ys, count, offset, stride); + PopStyleVar(vars); +} + +void PlotScatter(const char* label_id, const ImVec2* data, int count, int offset) { + int vars = PushScatterStyle(); + PlotLine(label_id, data, count, offset); + PopStyleVar(vars); +} + +void PlotScatter(const char* label_id, ImVec2 (*getter)(void* data, int idx), void* data, int count, int offset) { + int vars = PushScatterStyle(); + PlotLine(label_id, getter, data, count, offset); + PopStyleVar(vars); +} + +//----------------------------------------------------------------------------- +// double + +void PlotScatter(const char* label_id, const double* values, int count, int offset, int stride) { + int vars = PushScatterStyle(); + PlotLine(label_id, values, count, offset, stride); + PopStyleVar(vars); +} + +void PlotScatter(const char* label_id, const double* xs, const double* ys, int count, int offset, int stride) { + int vars = PushScatterStyle(); + PlotLine(label_id, xs, ys, count, offset, stride); + PopStyleVar(vars); +} + +void PlotScatter(const char* label_id, const ImPlotPoint* data, int count, int offset) { + int vars = PushScatterStyle(); + PlotLine(label_id, data, count, offset); + PopStyleVar(vars); +} + +void PlotScatter(const char* label_id, ImPlotPoint (*getter)(void* data, int idx), void* data, int count, int offset) { + int vars = PushScatterStyle(); + PlotLine(label_id, getter, data, count, offset); + PopStyleVar(vars); +} + +//----------------------------------------------------------------------------- +// PLOT BAR V //----------------------------------------------------------------------------- template @@ -2380,8 +2412,8 @@ struct GetterBarH { }; -template -void PlotBarsEx(const char* label_id, Getter getter, int count, float width, int offset) { +template +void PlotBarsEx(const char* label_id, Getter getter, int count, TWidth width, int offset) { IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "Bar() Needs to be called between BeginPlot() and EndPlot()!"); @@ -2405,7 +2437,7 @@ void PlotBarsEx(const char* label_id, Getter getter, int count, float width, int PushPlotClipRect(); - float half_width = width * 0.5f; + TWidth half_width = width / 2; // find data extents if (gp.FitThisFrame) { @@ -2433,13 +2465,16 @@ void PlotBarsEx(const char* label_id, Getter getter, int count, float width, int PopPlotClipRect(); } +//----------------------------------------------------------------------------- +// float + void PlotBars(const char* label_id, const float* values, int count, float width, float shift, int offset, int stride) { - GetterBarV getter(values,shift,stride); + GetterBarV getter(values,shift,stride); PlotBarsEx(label_id, getter, count, width, offset); } void PlotBars(const char* label_id, const float* xs, const float* ys, int count, float width, int offset, int stride) { - Getter2D getter(xs,ys,stride); + GetterXsYs getter(xs,ys,stride); PlotBarsEx(label_id, getter, count, width, offset); } @@ -2449,9 +2484,29 @@ void PlotBars(const char* label_id, ImVec2 (*getter_func)(void* data, int idx), } //----------------------------------------------------------------------------- +// double -template -void PlotBarsHEx(const char* label_id, Getter getter, int count, float height, int offset) { +void PlotBars(const char* label_id, const double* values, int count, double width, double shift, int offset, int stride) { + GetterBarV getter(values,shift,stride); + PlotBarsEx(label_id, getter, count, width, offset); +} + +void PlotBars(const char* label_id, const double* xs, const double* ys, int count, double width, int offset, int stride) { + GetterXsYs getter(xs,ys,stride); + PlotBarsEx(label_id, getter, count, width, offset); +} + +void PlotBars(const char* label_id, ImPlotPoint (*getter_func)(void* data, int idx), void* data, int count, double width, int offset) { + GetterFuncPtrImPlotPoint getter(getter_func, data); + PlotBarsEx(label_id, getter, count, width, offset); +} + +//----------------------------------------------------------------------------- +// PLOT BAR H +//----------------------------------------------------------------------------- + +template +void PlotBarsHEx(const char* label_id, Getter getter, int count, THeight height, int offset) { IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "BarH() Needs to be called between BeginPlot() and EndPlot()!"); @@ -2475,7 +2530,7 @@ void PlotBarsHEx(const char* label_id, Getter getter, int count, float height, PushPlotClipRect(); - float half_height = height * 0.5f; + THeight half_height = height / 2; // find data extents if (gp.FitThisFrame) { @@ -2503,13 +2558,16 @@ void PlotBarsHEx(const char* label_id, Getter getter, int count, float height, PopPlotClipRect(); } +//----------------------------------------------------------------------------- +// float + void PlotBarsH(const char* label_id, const float* values, int count, float height, float shift, int offset, int stride) { - GetterBarH getter(values,shift,stride); + GetterBarH getter(values,shift,stride); PlotBarsHEx(label_id, getter, count, height, offset); } void PlotBarsH(const char* label_id, const float* xs, const float* ys, int count, float height, int offset, int stride) { - Getter2D getter(xs,ys,stride); + GetterXsYs getter(xs,ys,stride); PlotBarsHEx(label_id, getter, count, height, offset); } @@ -2518,20 +2576,46 @@ void PlotBarsH(const char* label_id, ImVec2 (*getter_func)(void* data, int idx), PlotBarsHEx(label_id, getter, count, height, offset); } +//----------------------------------------------------------------------------- +// double + +void PlotBarsH(const char* label_id, const double* values, int count, double height, double shift, int offset, int stride) { + GetterBarH getter(values,shift,stride); + PlotBarsHEx(label_id, getter, count, height, offset); +} + +void PlotBarsH(const char* label_id, const double* xs, const double* ys, int count, double height, int offset, int stride) { + GetterXsYs getter(xs,ys,stride); + PlotBarsHEx(label_id, getter, count, height, offset); +} + +void PlotBarsH(const char* label_id, ImPlotPoint (*getter_func)(void* data, int idx), void* data, int count, double height, int offset) { + GetterFuncPtrImPlotPoint getter(getter_func, data); + PlotBarsHEx(label_id, getter, count, height, offset); +} + //----------------------------------------------------------------------------- // PLOT ERROR BARS //----------------------------------------------------------------------------- +struct ImPlotPointError { + ImPlotPointError(double _x, double _y, double _neg, double _pos) { + x = _x; y = _y; neg = _neg; pos = _pos; + } + double x, y, neg, pos; +}; + +template struct GetterError { - const float* Xs; const float* Ys; const float* Neg; const float* Pos; int Stride; - GetterError(const float* xs, const float* ys, const float* neg, const float* pos, int stride) { + const T* Xs; const T* Ys; const T* Neg; const T* Pos; int Stride; + GetterError(const T* xs, const T* ys, const T* neg, const T* pos, int stride) { Xs = xs; Ys = ys; Neg = neg; Pos = pos; Stride = stride; } - ImVec4 operator()(int idx) { - return ImVec4(StrideIndex(Xs, idx, Stride), - StrideIndex(Ys, idx, Stride), - StrideIndex(Neg, idx, Stride), - StrideIndex(Pos, idx, Stride)); + ImPlotPointError operator()(int idx) { + return ImPlotPointError(StrideIndex(Xs, idx, Stride), + StrideIndex(Ys, idx, Stride), + StrideIndex(Neg, idx, Stride), + StrideIndex(Pos, idx, Stride)); } }; @@ -2556,19 +2640,18 @@ void PlotErrorBarsEx(const char* label_id, Getter getter, int count, int offset) // find data extents if (gp.FitThisFrame) { for (int i = 0; i < count; ++i) { - ImVec4 e = getter(i); - FitPoint(ImPlotPoint(e.x , e.y - e.z)); - FitPoint(ImPlotPoint(e.x , e.y + e.w )); + ImPlotPointError e = getter(i); + FitPoint(ImPlotPoint(e.x , e.y - e.neg)); + FitPoint(ImPlotPoint(e.x , e.y + e.pos )); } } int idx = offset; for (int i = 0; i < count; ++i) { - ImVec4 e; - e = getter(idx); + ImPlotPointError e = getter(idx); idx = (idx + 1) % count; - ImVec2 p1 = PlotToPixels(e.x, e.y - e.z); - ImVec2 p2 = PlotToPixels(e.x, e.y + e.w); + ImVec2 p1 = PlotToPixels(e.x, e.y - e.neg); + ImVec2 p2 = PlotToPixels(e.x, e.y + e.pos); DrawList.AddLine(p1,p2,col, gp.Style.ErrorBarWeight); if (rend_whisker) { DrawList.AddLine(p1 - ImVec2(half_whisker, 0), p1 + ImVec2(half_whisker, 0), col, gp.Style.ErrorBarWeight); @@ -2578,44 +2661,55 @@ void PlotErrorBarsEx(const char* label_id, Getter getter, int count, int offset) PopPlotClipRect(); } +//----------------------------------------------------------------------------- +// float + void PlotErrorBars(const char* label_id, const float* xs, const float* ys, const float* err, int count, int offset, int stride) { - GetterError getter(xs, ys, err, err, stride); + GetterError getter(xs, ys, err, err, stride); PlotErrorBarsEx(label_id, getter, count, offset); } void PlotErrorBars(const char* label_id, const float* xs, const float* ys, const float* neg, const float* pos, int count, int offset, int stride) { - GetterError getter(xs, ys, neg, pos, stride); - PlotErrorBarsEx(label_id, getter, count, offset); -} - -void PlotErrorBars(const char* label_id, ImVec4 (*getter_func)(void* data, int idx), void* data, int count, int offset) { - GetterFuncPtrImVec4 getter(getter_func, data); + GetterError getter(xs, ys, neg, pos, stride); PlotErrorBarsEx(label_id, getter, count, offset); } //----------------------------------------------------------------------------- -// PLOT MISC +// double + +void PlotErrorBars(const char* label_id, const double* xs, const double* ys, const double* err, int count, int offset, int stride) { + GetterError getter(xs, ys, err, err, stride); + PlotErrorBarsEx(label_id, getter, count, offset); +} + +void PlotErrorBars(const char* label_id, const double* xs, const double* ys, const double* neg, const double* pos, int count, int offset, int stride) { + GetterError getter(xs, ys, neg, pos, stride); + PlotErrorBarsEx(label_id, getter, count, offset); +} + +//----------------------------------------------------------------------------- +// PLOT PIE CHART //----------------------------------------------------------------------------- -inline void DrawPieSlice(ImDrawList& DrawList, const ImPlotPoint& center, float radius, float a0, float a1, ImU32 col) { +inline void DrawPieSlice(ImDrawList& DrawList, const ImPlotPoint& center, double radius, double a0, double a1, ImU32 col) { static const float resolution = 50 / (2 * IM_PI); static ImVec2 buffer[50]; buffer[0] = PlotToPixels(center); int n = ImMax(3, (int)((a1 - a0) * resolution)); - float da = (a1 - a0) / (n - 1); + double da = (a1 - a0) / (n - 1); for (int i = 0; i < n; ++i) { - float a = a0 + i * da; + double a = a0 + i * da; buffer[i + 1] = PlotToPixels(center.x + radius * cos(a), center.y + radius * sin(a)); } DrawList.AddConvexPolyFilled(buffer, n + 1, col); } - -void PlotPieChart(const char** label_ids, float* values, int count, float x, float y, float radius, bool show_percents, float angle0) { +template +void PlotPieChartEx(const char** label_ids, T* values, int count, T x, T y, T radius, bool show_percents, T angle0) { IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PieChart() Needs to be called between BeginPlot() and EndPlot()!"); ImDrawList & DrawList = *ImGui::GetWindowDrawList(); - float sum = 0; + T sum = 0; for (int i = 0; i < count; ++i) sum += values[i]; @@ -2624,12 +2718,12 @@ void PlotPieChart(const char** label_ids, float* values, int count, float x, flo ImPlotPoint center(x,y); PushPlotClipRect(); - float a0 = angle0 * 2 * IM_PI / 360.0f; - float a1 = angle0 * 2 * IM_PI / 360.0f; + T a0 = angle0 * 2 * IM_PI / 360.0f; + T a1 = angle0 * 2 * IM_PI / 360.0f; for (int i = 0; i < count; ++i) { ImPlotItem* item = RegisterItem(label_ids[i]); ImU32 col = ImGui::GetColorU32(item->Color); - float percent = normalize ? values[i] / sum : values[i]; + T percent = normalize ? values[i] / sum : values[i]; a1 = a0 + 2 * IM_PI * percent; if (item->Show) { if (percent < 0.5) { @@ -2643,7 +2737,7 @@ void PlotPieChart(const char** label_ids, float* values, int count, float x, flo char buffer[8]; sprintf(buffer, "%.0f%%", percent * 100); ImVec2 size = ImGui::CalcTextSize(buffer); - float angle = a0 + (a1 - a0) * 0.5f; + T angle = a0 + (a1 - a0) * 0.5f; ImVec2 pos = PlotToPixels(center.x + 0.5f * radius * cos(angle), center.y + 0.5f * radius * sin(angle)); DrawList.AddText(pos - size * 0.5f + ImVec2(1,1), IM_COL32(0,0,0,255), buffer); DrawList.AddText(pos - size * 0.5f, IM_COL32(255,255,255,255), buffer); @@ -2654,18 +2748,24 @@ void PlotPieChart(const char** label_ids, float* values, int count, float x, flo PopPlotClipRect(); } -void PlotText(const char* text, float x, float y, bool vertical, const ImVec2& pixel_offset) { - IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "Text() Needs to be called between BeginPlot() and EndPlot()!"); - ImDrawList & DrawList = *ImGui::GetWindowDrawList(); - PushPlotClipRect(); - ImVec2 pos = PlotToPixels(ImPlotPoint(x,y)) + pixel_offset; - if (vertical) - AddTextVertical(&DrawList, text, pos, gp.Col_Txt); - else - DrawList.AddText(pos, gp.Col_Txt, text); - PopPlotClipRect(); +//----------------------------------------------------------------------------- +// float + +void PlotPieChart(const char** label_ids, float* values, int count, float x, float y, float radius, bool show_percents, float angle0) { + return PlotPieChartEx(label_ids, values, count, x, y, radius, show_percents, angle0); } +//----------------------------------------------------------------------------- +// double + +void PlotPieChart(const char** label_ids, double* values, int count, double x, double y, double radius, bool show_percents, double angle0) { + return PlotPieChartEx(label_ids, values, count, x, y, radius, show_percents, angle0); +} + +//----------------------------------------------------------------------------- +// PLOT DIGITAL +//----------------------------------------------------------------------------- + template inline void PlotDigitalEx(const char* label_id, Getter getter, int count, int offset) { @@ -2681,7 +2781,7 @@ inline void PlotDigitalEx(const char* label_id, Getter getter, int count, int of 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) { @@ -2747,8 +2847,11 @@ inline void PlotDigitalEx(const char* label_id, Getter getter, int count, int of ImGui::PopClipRect(); } +//----------------------------------------------------------------------------- +// float + void PlotDigital(const char* label_id, const float* xs, const float* ys, int count, int offset, int stride) { - Getter2D getter(xs,ys,stride); + GetterXsYs getter(xs,ys,stride); return PlotDigitalEx(label_id, getter, count, offset); } @@ -2757,4 +2860,40 @@ void PlotDigital(const char* label_id, ImVec2 (*getter_func)(void* data, int idx return PlotDigitalEx(label_id, getter, count, offset); } +//----------------------------------------------------------------------------- +// double + +void PlotDigital(const char* label_id, const double* xs, const double* ys, int count, int offset, int stride) { + GetterXsYs getter(xs,ys,stride); + return PlotDigitalEx(label_id, getter, count, offset); +} + +void PlotDigital(const char* label_id, ImPlotPoint (*getter_func)(void* data, int idx), void* data, int count, int offset) { + GetterFuncPtrImPlotPoint getter(getter_func,data); + return PlotDigitalEx(label_id, getter, count, offset); +} + +//----------------------------------------------------------------------------- +// PLOT TEXT +//----------------------------------------------------------------------------- +// float + +void PlotText(const char* text, float x, float y, bool vertical, const ImVec2& pixel_offset) { + return PlotText(text, (double)x, (double)y, vertical, pixel_offset); +} + +//----------------------------------------------------------------------------- +// double +void PlotText(const char* text, double x, double y, bool vertical, const ImVec2& pixel_offset) { + IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "Text() Needs to be called between BeginPlot() and EndPlot()!"); + ImDrawList & DrawList = *ImGui::GetWindowDrawList(); + PushPlotClipRect(); + ImVec2 pos = PlotToPixels(ImPlotPoint(x,y)) + pixel_offset; + if (vertical) + AddTextVertical(&DrawList, text, pos, gp.Col_Txt); + else + DrawList.AddText(pos, gp.Col_Txt, text); + PopPlotClipRect(); +} + } // namespace ImPlot \ No newline at end of file diff --git a/implot.h b/implot.h index db79309..30e6c56 100644 --- a/implot.h +++ b/implot.h @@ -20,14 +20,11 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -// ImPlot v0.2 WIP +// ImPlot v0.3 WIP #pragma once #include "imgui.h" -// The desired plot precision (float or double) -typedef double ImPlotFloat; - //----------------------------------------------------------------------------- // Basic types and flags //----------------------------------------------------------------------------- @@ -117,25 +114,31 @@ enum ImPlotMarker_ { ImPlotMarker_Asterisk = 1 << 10, // a asterisk marker will be rendered at each point (not filled) }; +/// Double precision version of ImVec2 used by ImPlot and extensible by end users struct ImPlotPoint { - ImPlotFloat x, y; - ImPlotPoint() { x = y = 0; } - ImPlotPoint(ImPlotFloat _x, ImPlotFloat _y) { x = _x; y = _y; } + double x, y; + ImPlotPoint() { x = y = 0.0; } + ImPlotPoint(double _x, double _y) { x = _x; y = _y; } + double operator[] (size_t idx) const { return (&x)[idx]; } + double& operator[] (size_t idx) { return (&x)[idx]; } +#ifdef IMPLOT_POINT_CLASS_EXTRA + IMPLOT_POINT_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec2. +#endif }; // A range defined by a min/max value. Used for plot axes ranges. struct ImPlotRange { - ImPlotFloat Min, Max; + double Min, Max; ImPlotRange(); - bool Contains(ImPlotFloat value) const; - ImPlotFloat Size() const; + bool Contains(double value) const; + double Size() const; }; // Combination of two ranges for X and Y axes. struct ImPlotLimits { ImPlotRange X, Y; ImPlotLimits(); - bool Contains(const ImVec2& p) const; + bool Contains(double x, double y) const; }; // Plot style structure @@ -177,7 +180,7 @@ bool BeginPlot(const char* title_id, void EndPlot(); //----------------------------------------------------------------------------- -// Plot Items (float) +// Plot Items (single precision data) //----------------------------------------------------------------------------- // Plots a standard 2D line plot. @@ -201,7 +204,6 @@ void PlotBarsH(const char* label_id, ImVec2 (*getter)(void* data, int idx), void // Plots vertical error bar. void PlotErrorBars(const char* label_id, const float* xs, const float* ys, const float* err, int count, int offset = 0, int stride = sizeof(float)); void PlotErrorBars(const char* label_id, const float* xs, const float* ys, const float* neg, const float* pos, int count, int offset = 0, int stride = sizeof(float)); -void PlotErrorBars(const char* label_id, ImVec4 (*getter)(void* data, int idx), void* data, int count, int offset = 0); // Plots a pie chart. If the sum of values > 1, each value will be normalized. Center and radius are in plot coordinates. void PlotPieChart(const char** label_ids, float* values, int count, float x, float y, float radius, bool show_percents = true, float angle0 = 90); // Plots digital data. @@ -210,7 +212,38 @@ void PlotDigital(const char* label_id, ImVec2 (*getter)(void* data, int idx), vo // Plots a text label at point x,y. void PlotText(const char* text, float x, float y, bool vertical = false, const ImVec2& pixel_offset = ImVec2(0,0)); +//----------------------------------------------------------------------------- +// Plot Items (double precision data) +//----------------------------------------------------------------------------- +// Plots a standard 2D line plot. +void PlotLine(const char* label_id, const double* values, int count, int offset = 0, int stride = sizeof(double)); +void PlotLine(const char* label_id, const double* xs, const double* ys, int count, int offset = 0, int stride = sizeof(double)); +void PlotLine(const char* label_id, const ImPlotPoint* data, int count, int offset = 0); +void PlotLine(const char* label_id, ImPlotPoint (*getter)(void* data, int idx), void* data, int count, int offset = 0); +// Plots a standard 2D scatter plot. +void PlotScatter(const char* label_id, const double* values, int count, int offset = 0, int stride = sizeof(double)); +void PlotScatter(const char* label_id, const double* xs, const double* ys, int count, int offset = 0, int stride = sizeof(double)); +void PlotScatter(const char* label_id, const ImPlotPoint* data, int count, int offset = 0); +void PlotScatter(const char* label_id, ImPlotPoint (*getter)(void* data, int idx), void* data, int count, int offset = 0); +// Plots a vertical bar graph. +void PlotBars(const char* label_id, const double* values, int count, double width = 0.67f, double shift = 0, int offset = 0, int stride = sizeof(double)); +void PlotBars(const char* label_id, const double* xs, const double* ys, int count, double width, int offset = 0, int stride = sizeof(double)); +void PlotBars(const char* label_id, ImPlotPoint (*getter)(void* data, int idx), void* data, int count, double width, int offset = 0); +// Plots a horizontal bar graph. +void PlotBarsH(const char* label_id, const double* values, int count, double height = 0.67f, double shift = 0, int offset = 0, int stride = sizeof(double)); +void PlotBarsH(const char* label_id, const double* xs, const double* ys, int count, double height, int offset = 0, int stride = sizeof(double)); +void PlotBarsH(const char* label_id, ImPlotPoint (*getter)(void* data, int idx), void* data, int count, double height, int offset = 0); +// Plots vertical error bar. +void PlotErrorBars(const char* label_id, const double* xs, const double* ys, const double* err, int count, int offset = 0, int stride = sizeof(double)); +void PlotErrorBars(const char* label_id, const double* xs, const double* ys, const double* neg, const double* pos, int count, int offset = 0, int stride = sizeof(double)); +// Plots a pie chart. If the sum of values > 1, each value will be normalized. Center and radius are in plot coordinates. +void PlotPieChart(const char** label_ids, double* values, int count, double x, double y, double radius, bool show_percents = true, double angle0 = 90); +// Plots digital data. +void PlotDigital(const char* label_id, const double* xs, const double* ys, int count, int offset = 0, int stride = sizeof(double)); +void PlotDigital(const char* label_id, ImPlotPoint (*getter)(void* data, int idx), void* data, int count, int offset = 0); +// Plots a text label at point x,y. +void PlotText(const char* text, double x, double y, bool vertical = false, const ImVec2& pixel_offset = ImVec2(0,0)); //----------------------------------------------------------------------------- // Plot Queries @@ -258,11 +291,11 @@ void PopStyleVar(int count = 1); //----------------------------------------------------------------------------- /// Set the axes range limits of the next plot. Call right before BeginPlot(). If ImGuiCond_Always is used, the axes limits will be locked. -void SetNextPlotLimits(ImPlotFloat x_min, ImPlotFloat x_max, ImPlotFloat y_min, ImPlotFloat y_max, ImGuiCond cond = ImGuiCond_Once); +void SetNextPlotLimits(double x_min, double x_max, double y_min, double y_max, ImGuiCond cond = ImGuiCond_Once); /// Set the X axis range limits of the next plot. Call right before BeginPlot(). If ImGuiCond_Always is used, the axis limits will be locked. -void SetNextPlotLimitsX(ImPlotFloat x_min, ImPlotFloat x_max, ImGuiCond cond = ImGuiCond_Once); +void SetNextPlotLimitsX(double x_min, double x_max, ImGuiCond cond = ImGuiCond_Once); /// Set the Y axis range limits of the next plot. Call right before BeginPlot(). If ImGuiCond_Always is used, the axis limits will be locked. -void SetNextPlotLimitsY(ImPlotFloat y_min, ImPlotFloat y_max, ImGuiCond cond = ImGuiCond_Once, int y_axis = 0); +void SetNextPlotLimitsY(double y_min, double y_max, ImGuiCond cond = ImGuiCond_Once, int y_axis = 0); /// Select which Y axis will be used for subsequent plot elements. The default is '0', or the first Y axis. void SetPlotYAxis(int y_axis); diff --git a/implot_demo.cpp b/implot_demo.cpp index 2bad1f0..230f4a0 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -20,40 +20,62 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -// ImPlot v0.2 WIP - +// ImPlot v0.3 WIP #include "implot.h" #include #include #include -#include // for 'float' overloads of elementary functions (sin,cos,etc) #ifdef _MSC_VER #define sprintf sprintf_s #endif +/// Choose whether the demo uses double or float versions of the ImPlot API. +/// NB: You don't ever need to typdef of define values for ImPlot. This +/// is only being done here for the sake of demoing both precision types. + +// #define IMPLOT_DEMO_USE_DOUBLE +#ifdef IMPLOT_DEMO_USE_DOUBLE +typedef double t_float; +typedef ImPlotPoint t_float2; +#define Sin sin +#define Cos cos +#define Pow pow +#define Log log +#define Fmod fmod +#else +typedef float t_float; +typedef ImVec2 t_float2; +#define Sin sinf +#define Cos cosf +#define Pow powf +#define Log logf +#define Fmod fmodf +#endif + namespace { -float RandomRange( float min, float max ) { - float scale = rand() / (float) RAND_MAX; +t_float RandomRange(t_float min, t_float max) { + t_float scale = rand() / (t_float) RAND_MAX; return min + scale * ( max - min ); } +// utility structure for realtime plot struct ScrollingData { int MaxSize; int Offset; - ImVector Data; - ScrollingData() { + ImVector Data; + ScrollingData() { MaxSize = 1000; Offset = 0; Data.reserve(MaxSize); } - void AddPoint(float x, float y) { + void AddPoint(t_float x, t_float y) { if (Data.size() < MaxSize) - Data.push_back(ImVec2(x,y)); + Data.push_back(t_float2(x,y)); else { - Data[Offset] = ImVec2(x,y); + Data[Offset] = t_float2(x,y); Offset = (Offset + 1) % MaxSize; } } @@ -65,33 +87,35 @@ struct ScrollingData { } }; +// utility structure for realtime plot struct RollingData { - float Span; - ImVector Data; - RollingData() { + t_float Span; + ImVector Data; + RollingData() { Span = 10.0f; Data.reserve(1000); } - void AddPoint(float x, float y) { - float xmod = fmodf(x, Span); + void AddPoint(t_float x, t_float y) { + t_float xmod = Fmod(x, Span); if (!Data.empty() && xmod < Data.back().x) Data.shrink(0); - Data.push_back(ImVec2(xmod, y)); + Data.push_back(t_float2(xmod, y)); } }; +// utility structure for benchmark data struct BenchmarkItem { BenchmarkItem() { - float y = RandomRange(0,1); - Data = new ImVec2[1000]; + t_float y = RandomRange(0,1); + Data = new t_float2[1000]; for (int i = 0; i < 1000; ++i) { Data[i].x = i*0.001f; Data[i].y = y + RandomRange(-0.01f,0.01f); } - Col = ImVec4(RandomRange(0,1),RandomRange(0,1),RandomRange(0,1),1); + Col = ImVec4((float)RandomRange(0,1),(float)RandomRange(0,1),(float)RandomRange(0,1),1); } ~BenchmarkItem() { delete Data; } - ImVec2* Data; + t_float2* Data; ImVec4 Col; }; @@ -139,15 +163,21 @@ void ShowDemoWindow(bool* p_open) { ImGui::Unindent(); ImGui::BulletText("Double right click to open the plot context menu."); ImGui::BulletText("Click legend label icons to show/hide plot items."); +#ifdef IMPLOT_DEMO_USE_DOUBLE + ImGui::BulletText("The demo data precision is: double"); +#else + ImGui::BulletText("The demo data precision is: float"); +#endif + } //------------------------------------------------------------------------- if (ImGui::CollapsingHeader("Line Plots")) { - static float xs1[1001], ys1[1001]; + static t_float xs1[1001], ys1[1001]; for (int i = 0; i < 1001; ++i) { xs1[i] = i * 0.001f; - ys1[i] = 0.5f + 0.5f * sin(50 * xs1[i]); + ys1[i] = 0.5f + 0.5f * Sin(50 * xs1[i]); } - static float xs2[11], ys2[11]; + static t_float xs2[11], ys2[11]; for (int i = 0; i < 11; ++i) { xs2[i] = i * 0.1f; ys2[i] = xs2[i] * xs2[i]; @@ -163,27 +193,25 @@ void ShowDemoWindow(bool* p_open) { //------------------------------------------------------------------------- if (ImGui::CollapsingHeader("Scatter Plots")) { srand(0); - static float xs1[100], ys1[100]; + static t_float xs1[100], ys1[100]; for (int i = 0; i < 100; ++i) { xs1[i] = i * 0.01f; - ys1[i] = xs1[i] + 0.1f * ((float)rand() / (float)RAND_MAX); + ys1[i] = xs1[i] + 0.1f * ((t_float)rand() / (t_float)RAND_MAX); } - static float xs2[50], ys2[50]; + static t_float xs2[50], ys2[50]; for (int i = 0; i < 50; i++) { - xs2[i] = 0.25f + 0.2f * ((float)rand() / (float)RAND_MAX); - ys2[i] = 0.75f + 0.2f * ((float)rand() / (float)RAND_MAX); + xs2[i] = 0.25f + 0.2f * ((t_float)rand() / (t_float)RAND_MAX); + ys2[i] = 0.75f + 0.2f * ((t_float)rand() / (t_float)RAND_MAX); } if (ImPlot::BeginPlot("Scatter Plot", NULL, NULL)) { ImPlot::PlotScatter("Data 1", xs1, ys1, 100); - ImPlot::PushStyleVar(ImPlotStyleVar_MarkerSize, 6); ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Square); - ImPlot::PushStyleColor(ImPlotCol_MarkerFill, ImVec4(1,0,0,0.25f)); - ImPlot::PushStyleColor(ImPlotCol_MarkerOutline, ImVec4(0,0,0,0)); + ImPlot::PushStyleColor(ImPlotCol_MarkerFill, ImVec4(1,0,0,0.25f)); + ImPlot::PushStyleColor(ImPlotCol_MarkerOutline, ImVec4(0,0,0,0)); ImPlot::PlotScatter("Data 2", xs2, ys2, 50); ImPlot::PopStyleColor(2); ImPlot::PopStyleVar(2); - ImPlot::EndPlot(); } } @@ -192,13 +220,13 @@ void ShowDemoWindow(bool* p_open) { static bool horz = false; ImGui::Checkbox("Horizontal",&horz); if (horz) - ImPlot::SetNextPlotLimits(0, 110, -0.5f, 9.5f, ImGuiCond_Always); + ImPlot::SetNextPlotLimits(0, 110, -0.5, 9.5, ImGuiCond_Always); else - ImPlot::SetNextPlotLimits(-0.5f, 9.5f, 0, 110, ImGuiCond_Always); + ImPlot::SetNextPlotLimits(-0.5, 9.5, 0, 110, ImGuiCond_Always); if (ImPlot::BeginPlot("Bar Plot", horz ? "Score": "Student", horz ? "Student" : "Score")) { - static float midtm[10] = {83, 67, 23, 89, 83, 78, 91, 82, 85, 90}; - static float final[10] = {80, 62, 56, 99, 55, 78, 88, 78, 90, 100}; - static float grade[10] = {80, 69, 52, 92, 72, 78, 75, 76, 89, 95}; + static t_float midtm[10] = {83, 67, 23, 89, 83, 78, 91, 82, 85, 90}; + static t_float final[10] = {80, 62, 56, 99, 55, 78, 88, 78, 90, 100}; + static t_float grade[10] = {80, 69, 52, 92, 72, 78, 75, 76, 89, 95}; if (horz) { ImPlot::PlotBarsH("Midterm Exam", midtm, 10, 0.2f, -0.2f); ImPlot::PlotBarsH("Final Exam", final, 10, 0.2f, 0); @@ -214,17 +242,15 @@ void ShowDemoWindow(bool* p_open) { } //------------------------------------------------------------------------- if (ImGui::CollapsingHeader("Error Bars")) { - float xs[5] = {1,2,3,4,5}; - float lin[5] = {8,8,9,7,8}; - float bar[5] = {1,2,5,3,4}; - float err1[5] = {0.2f, 0.4f, 0.2f, 0.6f, 0.4f}; - float err2[5] = {0.4f, 0.2f, 0.4f, 0.8f, 0.6f}; + t_float xs[5] = {1,2,3,4,5}; + t_float lin[5] = {8,8,9,7,8}; + t_float bar[5] = {1,2,5,3,4}; + t_float err1[5] = {0.2f, 0.4f, 0.2f, 0.6f, 0.4f}; + t_float err2[5] = {0.4f, 0.2f, 0.4f, 0.8f, 0.6f}; ImPlot::SetNextPlotLimits(0, 6, 0, 10); if (ImPlot::BeginPlot("##ErrorBars",NULL,NULL)) { - ImPlot::PlotBars("Bar", xs, bar, 5, 0.5f); ImPlot::PlotErrorBars("Bar", xs, bar, err1, 5); - ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Circle); ImPlot::PushStyleVar(ImPlotStyleVar_MarkerSize, 3); ImPlot::PushStyleColor(ImPlotCol_ErrorBar, ImVec4(1,0,0,1)); @@ -232,14 +258,13 @@ void ShowDemoWindow(bool* p_open) { ImPlot::PlotLine("Line", xs, lin, 5); ImPlot::PopStyleVar(2); ImPlot::PopStyleColor(); - ImPlot::EndPlot(); } } //------------------------------------------------------------------------- if (ImGui::CollapsingHeader("Pie Charts")) { static const char* labels1[] = {"Frogs","Hogs","Dogs","Logs"}; - static float pre_normalized[] = {0.15f, 0.30f, 0.45f, 0.10f}; + static t_float pre_normalized[] = {0.15f, 0.30f, 0.45f, 0.10f}; SetNextPlotLimits(0,1,0,1,ImGuiCond_Always); if (ImPlot::BeginPlot("##Pie1", NULL, NULL, ImVec2(250,250), ImPlotFlags_Legend, 0, 0)) { @@ -258,7 +283,7 @@ void ShowDemoWindow(bool* p_open) { ImPlot::SetPalette(YlOrRd, 5); SetNextPlotLimits(0,1,0,1,ImGuiCond_Always); static const char* labels2[] = {"One","Two","Three","Four","Five"}; - static float not_normalized[] = {1,2,3,4,5}; + static t_float not_normalized[] = {1,2,3,4,5}; if (ImPlot::BeginPlot("##Pie2", NULL, NULL, ImVec2(250,250), ImPlotFlags_Legend, 0, 0)) { ImPlot::PlotPieChart(labels2, not_normalized, 5, 0.5f, 0.5f, 0.4f); ImPlot::EndPlot(); @@ -273,7 +298,7 @@ void ShowDemoWindow(bool* p_open) { static ScrollingData sdata1, sdata2; static RollingData rdata1, rdata2; ImVec2 mouse = ImGui::GetMousePos(); - static float t = 0; + static t_float t = 0; if (!paused) { t += ImGui::GetIO().DeltaTime; sdata1.AddPoint(t, mouse.x * 0.0005f); @@ -284,14 +309,14 @@ void ShowDemoWindow(bool* p_open) { ImPlot::SetNextPlotLimitsX(t - 10, t, paused ? ImGuiCond_Once : ImGuiCond_Always); static int rt_axis = ImPlotAxisFlags_Default & ~ImPlotAxisFlags_TickLabels; if (ImPlot::BeginPlot("##Scrolling", NULL, NULL, ImVec2(-1,150), ImPlotFlags_Default, rt_axis, rt_axis)) { - ImPlot::PlotLine("Data 1", &sdata1.Data[0].x, &sdata1.Data[0].y, sdata1.Data.size(), sdata1.Offset, 2 * sizeof(float)); - ImPlot::PlotLine("Data 2", &sdata2.Data[0].x, &sdata2.Data[0].y, sdata2.Data.size(), sdata2.Offset, 2 * sizeof(float)); + ImPlot::PlotLine("Data 1", &sdata1.Data[0].x, &sdata1.Data[0].y, sdata1.Data.size(), sdata1.Offset, 2 * sizeof(t_float)); + ImPlot::PlotLine("Data 2", &sdata2.Data[0].x, &sdata2.Data[0].y, sdata2.Data.size(), sdata2.Offset, 2 * sizeof(t_float)); ImPlot::EndPlot(); } ImPlot::SetNextPlotLimitsX(0, 10, ImGuiCond_Always); if (ImPlot::BeginPlot("##Rolling", NULL, NULL, ImVec2(-1,150), ImPlotFlags_Default, rt_axis, rt_axis)) { - ImPlot::PlotLine("Data 1", &rdata1.Data[0].x, &rdata1.Data[0].y, rdata1.Data.size(), 0, 2 * sizeof(float)); - ImPlot::PlotLine("Data 2", &rdata2.Data[0].x, &rdata2.Data[0].y, rdata2.Data.size(), 0, 2 * sizeof(float)); + ImPlot::PlotLine("Data 1", &rdata1.Data[0].x, &rdata1.Data[0].y, rdata1.Data.size(), 0, 2 * sizeof(t_float)); + ImPlot::PlotLine("Data 2", &rdata2.Data[0].x, &rdata2.Data[0].y, rdata2.Data.size(), 0, 2 * sizeof(t_float)); ImPlot::EndPlot(); } } @@ -299,54 +324,54 @@ void ShowDemoWindow(bool* p_open) { if (ImGui::CollapsingHeader("Markers and Text")) { ImPlot::SetNextPlotLimits(0, 10, 0, 12); if (ImPlot::BeginPlot("##MarkerStyles", NULL, NULL, ImVec2(-1,0), 0, 0, 0)) { - float xs[2] = {1,4}; - float ys[2] = {10,11}; + t_float xs[2] = {1,4}; + t_float ys[2] = {10,11}; // filled ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Circle); - ImPlot::PlotLine("Circle##Fill", xs, ys, 2); + ImPlot::PlotLine("Circle##Fill", xs, ys, 2); ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Square); ys[0]--; ys[1]--; - ImPlot::PlotLine("Square##Fill", xs, ys, 2); + ImPlot::PlotLine("Square##Fill", xs, ys, 2); ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Diamond); ys[0]--; ys[1]--; - ImPlot::PlotLine("Diamond##Fill", xs, ys, 2); + ImPlot::PlotLine("Diamond##Fill", xs, ys, 2); ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Up); ys[0]--; ys[1]--; - ImPlot::PlotLine("Up##Fill", xs, ys, 2); + ImPlot::PlotLine("Up##Fill", xs, ys, 2); ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Down); ys[0]--; ys[1]--; - ImPlot::PlotLine("Down##Fill", xs, ys, 2); + ImPlot::PlotLine("Down##Fill", xs, ys, 2); ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Left); ys[0]--; ys[1]--; - ImPlot::PlotLine("Left##Fill", xs, ys, 2); + ImPlot::PlotLine("Left##Fill", xs, ys, 2); ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Right); ys[0]--; ys[1]--; - ImPlot::PlotLine("Right##Fill", xs, ys, 2); + ImPlot::PlotLine("Right##Fill", xs, ys, 2); ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Cross); ys[0]--; ys[1]--; - ImPlot::PlotLine("Cross##Fill", xs, ys, 2); + ImPlot::PlotLine("Cross##Fill", xs, ys, 2); ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Plus); ys[0]--; ys[1]--; - ImPlot::PlotLine("Plus##Fill", xs, ys, 2); + ImPlot::PlotLine("Plus##Fill", xs, ys, 2); ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Asterisk); ys[0]--; ys[1]--; - ImPlot::PlotLine("Asterisk##Fill", xs, ys, 2); + ImPlot::PlotLine("Asterisk##Fill", xs, ys, 2); ImPlot::PopStyleVar(10); xs[0] = 6; xs[1] = 9; ys[0] = 10; ys[1] = 11; ImPlot::PushStyleColor(ImPlotCol_MarkerFill, ImVec4(0,0,0,0)); ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Circle); - ImPlot::PlotLine("Circle", xs, ys, 2); + ImPlot::PlotLine("Circle", xs, ys, 2); ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Square); ys[0]--; ys[1]--; - ImPlot::PlotLine("Square", xs, ys, 2); + ImPlot::PlotLine("Square", xs, ys, 2); ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Diamond); ys[0]--; ys[1]--; - ImPlot::PlotLine("Diamond", xs, ys, 2); + ImPlot::PlotLine("Diamond", xs, ys, 2); ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Up); ys[0]--; ys[1]--; - ImPlot::PlotLine("Up", xs, ys, 2); + ImPlot::PlotLine("Up", xs, ys, 2); ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Down); ys[0]--; ys[1]--; - ImPlot::PlotLine("Down", xs, ys, 2); + ImPlot::PlotLine("Down", xs, ys, 2); ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Left); ys[0]--; ys[1]--; - ImPlot::PlotLine("Left", xs, ys, 2); + ImPlot::PlotLine("Left", xs, ys, 2); ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Right); ys[0]--; ys[1]--; - ImPlot::PlotLine("Right", xs, ys, 2); + ImPlot::PlotLine("Right", xs, ys, 2); ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Cross); ys[0]--; ys[1]--; - ImPlot::PlotLine("Cross", xs, ys, 2); + ImPlot::PlotLine("Cross", xs, ys, 2); ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Plus); ys[0]--; ys[1]--; - ImPlot::PlotLine("Plus", xs, ys, 2); + ImPlot::PlotLine("Plus", xs, ys, 2); ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Asterisk); ys[0]--; ys[1]--; - ImPlot::PlotLine("Asterisk", xs, ys, 2); + ImPlot::PlotLine("Asterisk", xs, ys, 2); ImPlot::PopStyleColor(); ImPlot::PopStyleVar(10); @@ -356,7 +381,7 @@ void ShowDemoWindow(bool* p_open) { ImPlot::PushStyleVar(ImPlotStyleVar_LineWeight, 2); ImPlot::PushStyleVar(ImPlotStyleVar_MarkerSize, 8); ImPlot::PushStyleVar(ImPlotStyleVar_MarkerWeight, 2); - ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Circle | ImPlotMarker_Cross); + ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Circle | ImPlotMarker_Cross); ImPlot::PushStyleColor(ImPlotCol_MarkerOutline, ImVec4(0,0,0,1)); ImPlot::PushStyleColor(ImPlotCol_MarkerFill, ImVec4(1,1,1,1)); ImPlot::PushStyleColor(ImPlotCol_Line, ImVec4(0,0,0,1)); @@ -374,14 +399,14 @@ void ShowDemoWindow(bool* p_open) { //------------------------------------------------------------------------- if (ImGui::CollapsingHeader("Log Scale")) { ImGui::BulletText("Open the plot context menu (double right click) to change scales."); - static float xs[1001], ys1[1001], ys2[1001], ys3[1001]; + static t_float xs[1001], ys1[1001], ys2[1001], ys3[1001]; for (int i = 0; i < 1001; ++i) { - xs[i] = (float)(i*0.1f); - ys1[i] = sin(xs[i]) + 1; - ys2[i] = log(xs[i]); - ys3[i] = pow(10.0f, xs[i]); + xs[i] = i*0.1f; + ys1[i] = Sin(xs[i]) + 1; + ys2[i] = Log(xs[i]); + ys3[i] = Pow(10.0f, xs[i]); } - ImPlot::SetNextPlotLimits(0.1f, 100, 0, 10); + ImPlot::SetNextPlotLimits(0.1, 100, 0, 10); if (ImPlot::BeginPlot("Log Plot", NULL, NULL, ImVec2(-1,0), ImPlotFlags_Default, ImPlotAxisFlags_Default | ImPlotAxisFlags_LogScale )) { ImPlot::PlotLine("f(x) = x", xs, xs, 1001); ImPlot::PlotLine("f(x) = sin(x)+1", xs, ys1, 1001); @@ -398,7 +423,7 @@ void ShowDemoWindow(bool* p_open) { static ImVec4 y2_col = txt_col; static ImVec4 y3_col = txt_col; - static float xs[1001], xs2[1001], ys1[1001], ys2[1001], ys3[1001]; + static t_float xs[1001], xs2[1001], ys1[1001], ys2[1001], ys3[1001]; static bool y2_axis = true; static bool y3_axis = false; ImGui::Checkbox("Y-Axis 2", &y2_axis); @@ -411,13 +436,13 @@ void ShowDemoWindow(bool* p_open) { ImGui::SameLine(); ImGui::ColorEdit4("##Col3", &y3_col.x, ImGuiColorEditFlags_NoInputs); for (int i = 0; i < 1001; ++i) { - xs[i] = (float)(i*0.1f); - ys1[i] = sin(xs[i]) * 3 + 1; - ys2[i] = cos(xs[i]) * 0.2f + 0.5f; - ys3[i] = sin(xs[i]+0.5f) * 100 + 200; + xs[i] = (i*0.1f); + ys1[i] = Sin(xs[i]) * 3 + 1; + ys2[i] = Cos(xs[i]) * 0.2f + 0.5f; + ys3[i] = Sin(xs[i]+0.5f) * 100 + 200; xs2[i] = xs[i] + 10.0f; } - ImPlot::SetNextPlotLimits(0.1f, 100, 0, 10); + ImPlot::SetNextPlotLimits(0.1, 100, 0, 10); ImPlot::SetNextPlotLimitsY(0, 1, ImGuiCond_Once, 1); ImPlot::SetNextPlotLimitsY(0, 300, ImGuiCond_Once, 2); ImPlot::PushStyleColor(ImPlotCol_YAxis, y1_col); @@ -454,23 +479,23 @@ void ShowDemoWindow(bool* p_open) { ImGui::BulletText("Hold Shift to expand query vertically."); ImGui::BulletText("The query rect can be dragged after it's created."); ImGui::Unindent(); - static ImVector data; + static ImVector data; ImPlotLimits range, query; if (ImPlot::BeginPlot("##Drawing", NULL, NULL, ImVec2(-1,0), ImPlotFlags_Default | ImPlotFlags_Query, ImPlotAxisFlags_GridLines, ImPlotAxisFlags_GridLines)) { if (ImPlot::IsPlotHovered() && ImGui::IsMouseClicked(0) && ImGui::GetIO().KeyCtrl) { ImPlotPoint pt = ImPlot::GetPlotMousePos(); - data.push_back(ImVec2((float)pt.x, (float)pt.y)); + data.push_back(t_float2((t_float)pt.x, (t_float)pt.y)); } ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Diamond); if (data.size() > 0) - ImPlot::PlotScatter("Points", &data[0].x, &data[0].y, data.size(), 0, 2 * sizeof(float)); + ImPlot::PlotScatter("Points", &data[0].x, &data[0].y, data.size(), 0, 2 * sizeof(t_float)); if (ImPlot::IsPlotQueried() && data.size() > 0) { ImPlotLimits range2 = ImPlot::GetPlotQuery(); int cnt = 0; - ImVec2 avg; + t_float2 avg; for (int i = 0; i < data.size(); ++i) { - if (range2.Contains(data[i])) { + if (range2.Contains(data[i].x, data[i].y)) { avg.x += data[i].x; avg.y += data[i].y; cnt++; @@ -493,22 +518,22 @@ void ShowDemoWindow(bool* p_open) { //------------------------------------------------------------------------- if (ImGui::CollapsingHeader("Views")) { // mimic's soulthread's imgui_plot demo - static float x_data[512]; - static float y_data1[512]; - static float y_data2[512]; - static float y_data3[512]; - static float sampling_freq = 44100; - static float freq = 500; + static t_float x_data[512]; + static t_float y_data1[512]; + static t_float y_data2[512]; + static t_float y_data3[512]; + static t_float sampling_freq = 44100; + static t_float freq = 500; for (size_t i = 0; i < 512; ++i) { - const float t = i / sampling_freq; + const t_float t = i / sampling_freq; x_data[i] = t; - const float arg = 2 * 3.14f * freq * t; - y_data1[i] = sin(arg); - y_data2[i] = y_data1[i] * -0.6f + sin(2 * arg) * 0.4f; - y_data3[i] = y_data2[i] * -0.6f + sin(3 * arg) * 0.4f; + const t_float arg = 2 * 3.14f * freq * t; + y_data1[i] = Sin(arg); + y_data2[i] = y_data1[i] * -0.6f + Sin(2 * arg) * 0.4f; + y_data3[i] = y_data2[i] * -0.6f + Sin(3 * arg) * 0.4f; } ImGui::BulletText("Query the first plot to render a subview in the second plot (see above for controls)."); - ImPlot::SetNextPlotLimits(0,0.01f,-1,1); + ImPlot::SetNextPlotLimits(0,0.01,-1,1); ImPlotAxisFlags flgs = ImPlotAxisFlags_Default & ~ImPlotAxisFlags_TickLabels; ImPlotLimits query; if (ImPlot::BeginPlot("##View1",NULL,NULL,ImVec2(-1,150), ImPlotFlags_Default | ImPlotFlags_Query, flgs, flgs)) { @@ -563,23 +588,23 @@ void ShowDemoWindow(bool* p_open) { } ImGui::EndGroup(); ImGui::SameLine(); - static float t = 0; + static t_float t = 0; if (!paused) { t += ImGui::GetIO().DeltaTime; for (int i = 0; i < 10; ++i) { if (show[i]) data[i].AddPoint(t, data[i].Data.empty() ? - 0.25f + 0.5f * (float)rand() / float(RAND_MAX) : - data[i].Data.back().y + (0.005f + 0.0002f * (float)rand() / float(RAND_MAX)) * (-1 + 2 * (float)rand() / float(RAND_MAX))); + 0.25f + 0.5f * (t_float)rand() / t_float(RAND_MAX) : + data[i].Data.back().y + (0.005f + 0.0002f * (t_float)rand() / t_float(RAND_MAX)) * (-1 + 2 * (t_float)rand() / t_float(RAND_MAX))); } } - ImPlot::SetNextPlotLimitsX(t - 10, t, paused ? ImGuiCond_Once : ImGuiCond_Always); + ImPlot::SetNextPlotLimitsX((double)t - 10, t, paused ? ImGuiCond_Once : ImGuiCond_Always); if (ImPlot::BeginPlot("##DND")) { for (int i = 0; i < 10; ++i) { if (show[i]) { char label[8]; sprintf(label, "data_%d", i); - ImPlot::PlotLine(label, &data[i].Data[0].x, &data[i].Data[0].y, data[i].Data.size(), data[i].Offset, 2 * sizeof(float)); + ImPlot::PlotLine(label, &data[i].Data[0].x, &data[i].Data[0].y, data[i].Data.size(), data[i].Offset, 2 * sizeof(t_float)); } } ImPlot::EndPlot(); @@ -645,38 +670,38 @@ void ShowDemoWindow(bool* p_open) { } ImGui::EndGroup(); ImGui::SameLine(); - static float t = 0; + static t_float t = 0; if (!paused) { t += ImGui::GetIO().DeltaTime; //digital signal values int i = 0; if (showDigital[i]) - dataDigital[i].AddPoint(t, sin(2*t) > 0.45); + dataDigital[i].AddPoint(t, Sin(2*t) > 0.45); i++; if (showDigital[i]) - dataDigital[i].AddPoint(t, sin(2*t) < 0.45); + dataDigital[i].AddPoint(t, Sin(2*t) < 0.45); i++; if (showDigital[i]) - dataDigital[i].AddPoint(t, fmod(t,5.0f)); + dataDigital[i].AddPoint(t, Fmod(t,5.0f)); i++; if (showDigital[i]) - dataDigital[i].AddPoint(t, sin(2*t) < 0.17); + dataDigital[i].AddPoint(t, Sin(2*t) < 0.17); //Analog signal values i = 0; if (showAnalog[i]) - dataAnalog[i].AddPoint(t, sin(2*t)); + dataAnalog[i].AddPoint(t, Sin(2*t)); i++; if (showAnalog[i]) - dataAnalog[i].AddPoint(t, cos(2*t)); + dataAnalog[i].AddPoint(t, Cos(2*t)); i++; if (showAnalog[i]) - dataAnalog[i].AddPoint(t, sin(2*t) * cos(2*t)); + dataAnalog[i].AddPoint(t, Sin(2*t) * Cos(2*t)); i++; if (showAnalog[i]) - dataAnalog[i].AddPoint(t, sin(2*t) - cos(2*t)); + dataAnalog[i].AddPoint(t, Sin(2*t) - Cos(2*t)); } ImPlot::SetNextPlotLimitsY(-1, 1); - ImPlot::SetNextPlotLimitsX(t - 10.0f, t, paused ? ImGuiCond_Once : ImGuiCond_Always); + ImPlot::SetNextPlotLimitsX(t - 10.0, t, paused ? ImGuiCond_Once : ImGuiCond_Always); if (ImPlot::BeginPlot("##Digital")) { for (int i = 0; i < K_PLOT_DIGITAL_CH_COUNT; ++i) { if (showDigital[i]) { @@ -684,7 +709,7 @@ void ShowDemoWindow(bool* p_open) { sprintf(label, "digital_%d", i); ImPlot::PushStyleVar(ImPlotStyleVar_DigitalBitHeight, bitHeight); ImPlot::PushStyleVar(ImPlotStyleVar_DigitalBitGap, bitGap); - ImPlot::PlotDigital(label, &dataDigital[i].Data[0].x, &dataDigital[i].Data[0].y, dataDigital[i].Data.size(), dataDigital[i].Offset, 2 * sizeof(float)); + ImPlot::PlotDigital(label, &dataDigital[i].Data[0].x, &dataDigital[i].Data[0].y, dataDigital[i].Data.size(), dataDigital[i].Offset, 2 * sizeof(t_float)); ImPlot::PopStyleVar(2); } } @@ -693,7 +718,7 @@ void ShowDemoWindow(bool* p_open) { char label[32]; sprintf(label, "analog_%d", i); if (dataAnalog[i].Data.size() > 0) - ImPlot::PlotLine(label, &dataAnalog[i].Data[0].x, &dataAnalog[i].Data[0].y, dataAnalog[i].Data.size(), dataAnalog[i].Offset, 2 * sizeof(float)); + ImPlot::PlotLine(label, &dataAnalog[i].Data[0].x, &dataAnalog[i].Data[0].y, dataAnalog[i].Data.size(), dataAnalog[i].Offset, 2 * sizeof(t_float)); } } ImPlot::EndPlot(); @@ -717,10 +742,10 @@ void ShowDemoWindow(bool* p_open) { } //------------------------------------------------------------------------- if (ImGui::CollapsingHeader("Offset Data")) { - float xs[50], ys[50]; + t_float xs[50], ys[50]; for (int i = 0; i < 50; ++i) { - xs[i] = 0.5f + 0.4f * cos(i/50.f * 6.28f); - ys[i] = 0.5f + 0.4f * sin(i/50.f * 6.28f); + xs[i] = 0.5f + 0.4f * Cos(i/50.f * 6.28f); + ys[i] = 0.5f + 0.4f * Sin(i/50.f * 6.28f); } static int offset = 0; ImGui::SliderInt("Offset", &offset, -100, 100); @@ -745,9 +770,9 @@ void ShowDemoWindow(bool* p_open) { ImPlot::PushStyleVar(ImPlotStyleVar_LineWeight, 2); ImPlot::SetNextPlotLimits(-0.5f, 9.5f, -0.5f, 9.5f); if (ImPlot::BeginPlot("##Custom", NULL, NULL, ImVec2(-1,0), ImPlotFlags_Default & ~ImPlotFlags_Legend, 0)) { - float lin[10] = {8,8,9,7,8,8,8,9,7,8}; - float bar[10] = {1,2,5,3,4,1,2,5,3,4}; - float dot[10] = {7,6,6,7,8,5,6,5,8,7}; + t_float lin[10] = {8,8,9,7,8,8,8,9,7,8}; + t_float bar[10] = {1,2,5,3,4,1,2,5,3,4}; + t_float dot[10] = {7,6,6,7,8,5,6,5,8,7}; ImPlot::PlotBars("Bar", bar, 10, 0.5f); ImPlot::PlotLine("Line", lin, 10); ImPlot::PushStyleVar(ImPlotStyleVar_LineWeight, 0);