1
0
Fork 0
mirror of https://github.com/gwm17/implot.git synced 2024-10-09 23:57:26 -04:00

checkpoint

This commit is contained in:
Evan Pezent 2020-05-16 21:09:36 -05:00
parent 98ff9e8795
commit 226ae4c10b
3 changed files with 98 additions and 77 deletions

View File

@ -102,13 +102,16 @@ ImPlotStyle::ImPlotStyle() {
Colors[ImPlotCol_Query] = ImVec4(0,1,0,1); 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; return v >= Min && v <= Max;
} }
float ImPlotRange::Size() const { ImPlotFloat ImPlotRange::Size() const {
return Max - Min; return Max - Min;
} }
@ -118,10 +121,6 @@ bool ImPlotLimits::Contains(const ImVec2& p) const {
return X.Contains(p.x) && Y.Contains(p.y); return X.Contains(p.x) && Y.Contains(p.y);
} }
ImVec2 ImPlotLimits::Size() const {
return ImVec2(X.Size(),Y.Size());
}
namespace ImPlot { namespace ImPlot {
namespace { namespace {
@ -143,27 +142,28 @@ inline void FlipFlag(TSet& set, TFlag flag) {
} }
/// Linearly remaps float x from [x0 x1] to [y0 y1]. /// 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); return y0 + (x - x0) * (y1 - y0) / (x1 - x0);
} }
/// Turns NANs to 0s /// Turns NANs to 0s
inline float ConstrainNan(float val) { inline ImPlotFloat ConstrainNan(ImPlotFloat val) {
return isnan(val) ? 0 : val; return isnan(val) ? 0 : val;
} }
/// Turns INFINITYs to FLT_MAXs /// Turns INFINITYs to FLT_MAXs
inline float ConstrainInf(float val) { inline ImPlotFloat ConstrainInf(ImPlotFloat val) {
return val == INFINITY ? FLT_MAX : val == -INFINITY ? -FLT_MAX : 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?) /// 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; return val <= 0 ? 0.001f : val;
} }
/// Returns true if val is NAN or INFINITY /// 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); return val == INFINITY || val == -INFINITY || isnan(val);
} }
@ -236,12 +236,12 @@ ImVec4 NextColor();
/// Tick mark info /// Tick mark info
struct ImTick { struct ImTick {
ImTick(double value, bool major, bool render_label = true) { ImTick(ImPlotFloat value, bool major, bool render_label = true) {
PlotPos = value; PlotPos = value;
Major = major; Major = major;
RenderLabel = render_label; RenderLabel = render_label;
} }
double PlotPos; ImPlotFloat PlotPos;
float PixelPos; float PixelPos;
ImVec2 Size; ImVec2 Size;
int TextOffset; int TextOffset;
@ -356,11 +356,11 @@ struct ImPlotContext {
// Transformation cache // Transformation cache
ImRect PixelRange[MAX_Y_AXES]; ImRect PixelRange[MAX_Y_AXES];
// linear scale (slope) // linear scale (slope)
float Mx; ImPlotFloat Mx;
float My[MAX_Y_AXES]; ImPlotFloat My[MAX_Y_AXES];
// log scale denominator // log scale denominator
float LogDenX; ImPlotFloat LogDenX;
float LogDenY[MAX_Y_AXES]; ImPlotFloat LogDenY[MAX_Y_AXES];
// Data extents // Data extents
ImPlotRange ExtentsX; ImPlotRange ExtentsX;
ImPlotRange ExtentsY[MAX_Y_AXES]; ImPlotRange ExtentsY[MAX_Y_AXES];
@ -373,7 +373,7 @@ struct ImPlotContext {
// Render flags // Render flags
bool RenderX, RenderY[MAX_Y_AXES]; bool RenderX, RenderY[MAX_Y_AXES];
// Mouse pos // Mouse pos
ImVec2 LastMousePos[MAX_Y_AXES]; ImPlotPoint LastMousePos[MAX_Y_AXES];
// Style // Style
ImVector<ImVec4> ColorMap; ImVector<ImVec4> ColorMap;
ImPlotStyle Style; 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(); 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()!"); 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; 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.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; 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)) { 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; plt.x = pow(10.0f, t * gp.LogDenX) * gp.CurrentPlot->XAxis.Range.Min;
} }
if (HasFlag(gp.CurrentPlot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) { 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; plt.y = pow(10.0f, t * gp.LogDenY[y_axis]) * gp.CurrentPlot->YAxis[y_axis].Range.Min;
} }
return plt; 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); 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. // 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()!"); 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; const int y_axis = y_axis_in >= 0 ? y_axis_in : gp.CurrentPlot->CurrentYAxis;
ImVec2 pix; ImVec2 pix;
if (HasFlag(gp.CurrentPlot->XAxis.Flags, ImPlotAxisFlags_LogScale)) { if (HasFlag(gp.CurrentPlot->XAxis.Flags, ImPlotAxisFlags_LogScale)) {
float t = log10(x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX; ImPlotFloat t = log10(x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX;
x = ImLerp(gp.CurrentPlot->XAxis.Range.Min, gp.CurrentPlot->XAxis.Range.Max, t); x = ImLerp(gp.CurrentPlot->XAxis.Range.Min, gp.CurrentPlot->XAxis.Range.Max, (float)t);
} }
if (HasFlag(gp.CurrentPlot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) { 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]; 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, t); 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.x = (float)(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.y = (float)(gp.PixelRange[y_axis].Min.y + gp.My[y_axis] * (y - gp.CurrentPlot->YAxis[y_axis].Range.Min));
return pix; return pix;
} }
// This function is convenient but should not be used to process a high volume of points. Use the Transformer structs below instead. // 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); return PlotToPixels(plt.x, plt.y, y_axis);
} }
@ -484,7 +484,7 @@ struct Plt2PixLinLin {
Plt2PixLinLin(int y_axis_in) : y_axis(y_axis_in) {} Plt2PixLinLin(int y_axis_in) : y_axis(y_axis_in) {}
ImVec2 operator()(const ImVec2& plt) { return (*this)(plt.x, plt.y); } 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), 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) ); 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)); 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) { struct ImPlotAxisScale {
return ImRect( ImPlotAxisScale(int y_axis, float tx, float ty, float zoom_rate) {
PixelsToPlot(gp.BB_Grid.Min - gp.BB_Grid.GetSize() * ImVec2(tx * zoom_rate, ty * zoom_rate), y_axis), Min = 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)); 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 { class YPadCalculator {
public: public:
@ -1004,8 +1006,8 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
if (drag_in_progress) { if (drag_in_progress) {
UpdateTransformCache(); UpdateTransformCache();
if (!x.lock && plot.XAxis.Dragging) { if (!x.lock && plot.XAxis.Dragging) {
ImVec2 plot_tl = PixelsToPlot(gp.BB_Grid.Min - IO.MouseDelta, 0); ImPlotPoint plot_tl = PixelsToPlot(gp.BB_Grid.Min - IO.MouseDelta, 0);
ImVec2 plot_br = PixelsToPlot(gp.BB_Grid.Max - IO.MouseDelta, 0); ImPlotPoint plot_br = PixelsToPlot(gp.BB_Grid.Max - IO.MouseDelta, 0);
if (!x.lock_min) if (!x.lock_min)
plot.XAxis.Range.Min = x.flip ? plot_br.x : plot_tl.x; plot.XAxis.Range.Min = x.flip ? plot_br.x : plot_tl.x;
if (!x.lock_max) 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++) { for (int i = 0; i < MAX_Y_AXES; i++) {
if (!y[i].lock && plot.YAxis[i].Dragging) { if (!y[i].lock && plot.YAxis[i].Dragging) {
ImVec2 plot_tl = PixelsToPlot(gp.BB_Grid.Min - IO.MouseDelta, i); ImPlotPoint plot_tl = PixelsToPlot(gp.BB_Grid.Min - IO.MouseDelta, i);
ImVec2 plot_br = PixelsToPlot(gp.BB_Grid.Max - IO.MouseDelta, i); ImPlotPoint plot_br = PixelsToPlot(gp.BB_Grid.Max - IO.MouseDelta, i);
if (!y[i].lock_min) if (!y[i].lock_min)
plot.YAxis[i].Range.Min = y[i].flip ? plot_tl.y : plot_br.y; 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 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); 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) { if (hov_x_axis_region && !x.lock) {
ImRect axis_scale = GetAxisScale(0, tx, ty, zoom_rate); ImPlotAxisScale axis_scale(0, tx, ty, zoom_rate);
const ImVec2& plot_tl = axis_scale.Min; const ImPlotPoint& plot_tl = axis_scale.Min;
const ImVec2& plot_br = axis_scale.Max; const ImPlotPoint& plot_br = axis_scale.Max;
if (!x.lock_min) if (!x.lock_min)
plot.XAxis.Range.Min = x.flip ? plot_br.x : plot_tl.x; 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++) { for (int i = 0; i < MAX_Y_AXES; i++) {
if (hov_y_axis_region[i] && !y[i].lock) { if (hov_y_axis_region[i] && !y[i].lock) {
ImRect axis_scale = GetAxisScale(i, tx, ty, zoom_rate); ImPlotAxisScale axis_scale(i, tx, ty, zoom_rate);
const ImVec2& plot_tl = axis_scale.Min; const ImPlotPoint& plot_tl = axis_scale.Min;
const ImVec2& plot_br = axis_scale.Max; const ImPlotPoint& plot_br = axis_scale.Max;
if (!y[i].lock_min) if (!y[i].lock_min)
plot.YAxis[i].Range.Min = y[i].flip ? plot_tl.y : plot_br.y; plot.YAxis[i].Range.Min = y[i].flip ? plot_tl.y : plot_br.y;
if (!y[i].lock_max) if (!y[i].lock_max)
@ -1097,8 +1098,8 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
UpdateTransformCache(); UpdateTransformCache();
ImVec2 select_size = plot.SelectStart - IO.MousePos; ImVec2 select_size = plot.SelectStart - IO.MousePos;
if (HasFlag(plot.Flags, ImPlotFlags_BoxSelect) && ImFabs(select_size.x) > 2 && ImFabs(select_size.y) > 2) { if (HasFlag(plot.Flags, ImPlotFlags_BoxSelect) && ImFabs(select_size.x) > 2 && ImFabs(select_size.y) > 2) {
ImVec2 p1 = PixelsToPlot(plot.SelectStart); ImPlotPoint p1 = PixelsToPlot(plot.SelectStart);
ImVec2 p2 = PixelsToPlot(IO.MousePos); ImPlotPoint p2 = PixelsToPlot(IO.MousePos);
if (!x.lock_min && !IO.KeyAlt) if (!x.lock_min && !IO.KeyAlt)
plot.XAxis.Range.Min = ImMin(p1.x, p2.x); plot.XAxis.Range.Min = ImMin(p1.x, p2.x);
if (!x.lock_max && !IO.KeyAlt) 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 // 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) { inline void AxisMenu(ImPlotAxis& Axis) {
ImGui::PushItemWidth(75); ImGui::PushItemWidth(75);
bool lock_min = HasFlag(Axis.Flags, ImPlotAxisFlags_LockMin); bool lock_min = HasFlag(Axis.Flags, ImPlotAxisFlags_LockMin);
@ -1329,7 +1335,7 @@ inline void AxisMenu(ImPlotAxis& Axis) {
ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.25f); 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) { if (lock_min) {
ImGui::PopItemFlag(); ImGui::PopItemFlag();
ImGui::PopStyleVar(); } ImGui::PopStyleVar(); }
@ -1340,7 +1346,7 @@ inline void AxisMenu(ImPlotAxis& Axis) {
if (lock_max) { if (lock_max) {
ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.25f); } 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) { if (lock_max) {
ImGui::PopItemFlag(); ImGui::PopItemFlag();
ImGui::PopStyleVar(); ImGui::PopStyleVar();
@ -1761,7 +1767,7 @@ bool IsPlotHovered() {
IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "IsPlotHovered() Needs to be called between BeginPlot() and EndPlot()!"); IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "IsPlotHovered() Needs to be called between BeginPlot() and EndPlot()!");
return gp.Hov_Grid; 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(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()!"); 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; 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; const int y_axis = y_axis_in >= 0 ? y_axis_in : gp.CurrentPlot->CurrentYAxis;
UpdateTransformCache(); UpdateTransformCache();
ImVec2 p1 = PixelsToPlot(plot.QueryRect.Min + gp.BB_Grid.Min, y_axis); ImPlotPoint p1 = PixelsToPlot(plot.QueryRect.Min + gp.BB_Grid.Min, y_axis);
ImVec2 p2 = PixelsToPlot(plot.QueryRect.Max + gp.BB_Grid.Min, y_axis); ImPlotPoint p2 = PixelsToPlot(plot.QueryRect.Max + gp.BB_Grid.Min, y_axis);
ImPlotLimits result; ImPlotLimits result;
result.X.Min = ImMin(p1.x, p2.x); 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 // 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 const float resolution = 50 / (2 * IM_PI);
static ImVec2 buffer[50]; static ImVec2 buffer[50];
buffer[0] = PlotToPixels(center); 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()!"); IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PieChart() Needs to be called between BeginPlot() and EndPlot()!");
ImDrawList & DrawList = *ImGui::GetWindowDrawList(); 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; const bool normalize = sum > 1.0f;
ImPlotPoint center(x,y);
PushPlotClipRect(); PushPlotClipRect();
float a0 = angle0 * 2 * IM_PI / 360.0f; float a0 = angle0 * 2 * IM_PI / 360.0f;
float a1 = 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()!"); IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "Text() Needs to be called between BeginPlot() and EndPlot()!");
ImDrawList & DrawList = *ImGui::GetWindowDrawList(); ImDrawList & DrawList = *ImGui::GetWindowDrawList();
PushPlotClipRect(); PushPlotClipRect();
ImVec2 pos = PlotToPixels(ImVec2(x,y)) + pixel_offset; ImVec2 pos = PlotToPixels(ImPlotPoint(x,y)) + pixel_offset;
if (vertical) if (vertical)
AddTextVertical(&DrawList, text, pos, gp.Col_Txt); AddTextVertical(&DrawList, text, pos, gp.Col_Txt);
else else

View File

@ -25,6 +25,13 @@
#pragma once #pragma once
#include "imgui.h" #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 // 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) 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. // A range defined by a min/max value. Used for plot axes ranges.
struct ImPlotRange { struct ImPlotRange {
float Min, Max; ImPlotFloat Min, Max;
ImPlotRange(); ImPlotRange();
bool Contains(float value) const; bool Contains(ImPlotFloat value) const;
float Size() const; ImPlotFloat Size() const;
}; };
// Combination of two ranges for X and Y axes. // Combination of two ranges for X and Y axes.
@ -127,7 +140,6 @@ struct ImPlotLimits {
ImPlotRange X, Y; ImPlotRange X, Y;
ImPlotLimits(); ImPlotLimits();
bool Contains(const ImVec2& p) const; bool Contains(const ImVec2& p) const;
ImVec2 Size() const;
}; };
// Plot style structure // 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, 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); 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. // 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. // 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, 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); 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. /// Returns true if the plot area in the current or most recent plot is hovered.
bool IsPlotHovered(); 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). /// 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). /// 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); ImPlotLimits GetPlotLimits(int y_axis = -1);
/// Returns true if the current or most recent plot is being queried. /// Returns true if the current or most recent plot is being queried.
@ -263,9 +275,9 @@ ImVec2 GetPlotPos();
ImVec2 GetPlotSize(); 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). // 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). // 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 // Push clip rect for rendering to current plot area
void PushPlotClipRect(); void PushPlotClipRect();

View File

@ -240,12 +240,10 @@ void ShowDemoWindow(bool* p_open) {
if (ImGui::CollapsingHeader("Pie Charts")) { if (ImGui::CollapsingHeader("Pie Charts")) {
static const char* labels1[] = {"Frogs","Hogs","Dogs","Logs"}; static const char* labels1[] = {"Frogs","Hogs","Dogs","Logs"};
static float pre_normalized[] = {0.15f, 0.30f, 0.45f, 0.10f}; 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); SetNextPlotLimits(0,1,0,1,ImGuiCond_Always);
if (ImPlot::BeginPlot("##Pie1", NULL, NULL, ImVec2(250,250), ImPlotFlags_Legend, 0, 0)) { 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(); ImPlot::EndPlot();
} }
ImGui::SameLine(); ImGui::SameLine();
@ -262,7 +260,7 @@ void ShowDemoWindow(bool* p_open) {
static const char* labels2[] = {"One","Two","Three","Four","Five"}; static const char* labels2[] = {"One","Two","Three","Four","Five"};
static float not_normalized[] = {1,2,3,4,5}; static float not_normalized[] = {1,2,3,4,5};
if (ImPlot::BeginPlot("##Pie2", NULL, NULL, ImVec2(250,250), ImPlotFlags_Legend, 0, 0)) { 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::EndPlot();
} }
ImPlot::RestorePalette(); ImPlot::RestorePalette();
@ -459,8 +457,11 @@ void ShowDemoWindow(bool* p_open) {
static ImVector<ImVec2> data; static ImVector<ImVec2> data;
ImPlotLimits range, query; ImPlotLimits range, query;
if (ImPlot::BeginPlot("##Drawing", NULL, NULL, ImVec2(-1,0), ImPlotFlags_Default | ImPlotFlags_Query, ImPlotAxisFlags_GridLines, ImPlotAxisFlags_GridLines)) { 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) if (ImPlot::IsPlotHovered() && ImGui::IsMouseClicked(0) && ImGui::GetIO().KeyCtrl) {
data.push_back(ImPlot::GetPlotMousePos()); ImPlotPoint pt = ImPlot::GetPlotMousePos();
data.push_back(ImVec2(pt.x, pt.y));
}
ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Diamond); ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Diamond);
if (data.size() > 0) 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(float));
@ -762,9 +763,9 @@ void ShowDemoWindow(bool* p_open) {
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
if (ImGui::CollapsingHeader("Custom Rendering")) { if (ImGui::CollapsingHeader("Custom Rendering")) {
if (ImPlot::BeginPlot("##CustomRend")) { if (ImPlot::BeginPlot("##CustomRend")) {
ImVec2 cntr = ImPlot::PlotToPixels(ImVec2(0.5f, 0.5f)); ImVec2 cntr = ImPlot::PlotToPixels(ImPlotPoint(0.5f, 0.5f));
ImVec2 rmin = ImPlot::PlotToPixels(ImVec2(0.25f, 0.75f)); ImVec2 rmin = ImPlot::PlotToPixels(ImPlotPoint(0.25f, 0.75f));
ImVec2 rmax = ImPlot::PlotToPixels(ImVec2(0.75f, 0.25f)); ImVec2 rmax = ImPlot::PlotToPixels(ImPlotPoint(0.75f, 0.25f));
ImPlot::PushPlotClipRect(); ImPlot::PushPlotClipRect();
ImGui::GetWindowDrawList()->AddCircleFilled(cntr,20,IM_COL32(255,255,0,255),20); ImGui::GetWindowDrawList()->AddCircleFilled(cntr,20,IM_COL32(255,255,0,255),20);
ImGui::GetWindowDrawList()->AddRect(rmin, rmax, IM_COL32(128,0,255,255)); ImGui::GetWindowDrawList()->AddRect(rmin, rmax, IM_COL32(128,0,255,255));