Commit 7788e556 authored by Gauthier Quesnel's avatar Gauthier Quesnel
Browse files

implot: add new plot library

parent 16d22725
Pipeline #15048 passed with stage
in 1 minute and 7 seconds
......@@ -2,8 +2,8 @@ cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
project(irritator-gui VERSION 0.1.0 LANGUAGES CXX)
set(gui_sources
dialog-file.cpp gui.hpp imnodes.cpp imnodes.hpp window-logger.cpp
node-editor.hpp node-editor.cpp
dialog-file.cpp gui.hpp imnodes.cpp imnodes.hpp implot.h implot.cpp
window-logger.cpp node-editor.hpp node-editor.cpp
${PROJECT_SOURCE_DIR}/../../external/imgui/imgui.cpp
${PROJECT_SOURCE_DIR}/../../external/imgui/imgui.h
${PROJECT_SOURCE_DIR}/../../external/imgui/imgui_demo.cpp
......
// MIT License
// Copyright (c) 2020 Evan Pezent
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// ImPlot v0.4 WIP
/*
API BREAKING CHANGES
====================
Occasionally introducing changes that are breaking the API. We try to make the breakage minor and easy to fix.
Below is a change-log of API breaking changes only. If you are using one of the functions listed, expect to have to fix some code.
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/06/13 (0.4) - The flags `ImPlotAxisFlag_Adaptive` and `ImPlotFlags_Cull` were removed. Both are now done internally by default.
- 2020/06/03 (0.3) - The signature and behavior of PlotPieChart was changed so that data with sum less than 1 can optionally be normalized. The label format can now be specified as well.
- 2020/06/01 (0.3) - SetPalette was changed to `SetColormap` for consistency with other plotting libraries. `RestorePalette` was removed. Use `SetColormap(ImPlotColormap_Default)`.
- 2020/05/31 (0.3) - Plot functions taking custom ImVec2* getters were removed. Use the ImPlotPoint* getter versions instead.
- 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.
- 2020/05/13 (0.2) - `ImMarker` was change to `ImPlotMarker` and `ImAxisFlags` was changed to `ImPlotAxisFlags`.
- 2020/05/11 (0.2) - `ImPlotFlags_Selection` was changed to `ImPlotFlags_BoxSelect`
- 2020/05/11 (0.2) - The namespace ImGui:: was replaced with ImPlot::. As a result, the following additional changes were made:
- Functions that were prefixed or decorated with the word "Plot" have been truncated. E.g., `ImGui::PlotBars` is now just `ImPlot::Bar`.
It should be fairly obvious what was what.
- Some functions have been given names that would have otherwise collided with the ImGui namespace. This has been done to maintain a consistent
style with ImGui. E.g., 'ImGui::PushPlotStyleVar` is now 'ImPlot::PushStyleVar'.
- 2020/05/10 (0.2) - The following function/struct names were changes:
- ImPlotRange -> ImPlotLimits
- GetPlotRange() -> GetPlotLimits()
- SetNextPlotRange -> SetNextPlotLimits
- SetNextPlotRangeX -> SetNextPlotLimitsX
- SetNextPlotRangeY -> SetNextPlotLimitsY
- 2020/05/10 (0.2) - Plot queries are pixel based by default. Query rects that maintain relative plot position have been removed. This was done to support multi-y-axis.
*/
#ifndef IMGUI_DEFINE_MATH_OPERATORS
#define IMGUI_DEFINE_MATH_OPERATORS
#endif
#include "implot.h"
#include "imgui_internal.h"
#ifdef _MSC_VER
#define sprintf sprintf_s
#endif
#define IM_NORMALIZE2F_OVER_ZERO(VX, VY) \
{ \
float d2 = VX * VX + VY * VY; \
if (d2 > 0.0f) { \
float inv_len = 1.0f / ImSqrt(d2); \
VX *= inv_len; \
VY *= inv_len; \
} \
}
// 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;
MarkerSize = 4;
MarkerWeight = 1;
FillAlpha = 1;
ErrorBarSize = 5;
ErrorBarWeight = 1.5;
DigitalBitHeight = 8;
DigitalBitGap = 4;
Colors[ImPlotCol_Line] = IMPLOT_COL_AUTO;
Colors[ImPlotCol_Fill] = IMPLOT_COL_AUTO;
Colors[ImPlotCol_MarkerOutline] = IMPLOT_COL_AUTO;
Colors[ImPlotCol_MarkerFill] = IMPLOT_COL_AUTO;
Colors[ImPlotCol_ErrorBar] = IMPLOT_COL_AUTO;
Colors[ImPlotCol_FrameBg] = IMPLOT_COL_AUTO;
Colors[ImPlotCol_PlotBg] = IMPLOT_COL_AUTO;
Colors[ImPlotCol_PlotBorder] = IMPLOT_COL_AUTO;
Colors[ImPlotCol_XAxis] = IMPLOT_COL_AUTO;
Colors[ImPlotCol_YAxis] = IMPLOT_COL_AUTO;
Colors[ImPlotCol_YAxis2] = IMPLOT_COL_AUTO;
Colors[ImPlotCol_YAxis3] = IMPLOT_COL_AUTO;
Colors[ImPlotCol_Selection] = ImVec4(1,1,0,1);
Colors[ImPlotCol_Query] = ImVec4(0,1,0,1);
}
ImPlotRange::ImPlotRange() {
Min = NAN;
Max = NAN;
}
bool ImPlotRange::Contains(double v) const {
return v >= Min && v <= Max;
}
double ImPlotRange::Size() const {
return Max - Min;
}
ImPlotLimits::ImPlotLimits() {}
bool ImPlotLimits::Contains(const ImPlotPoint& p) const {
return Contains(p.x, p.y);
}
bool ImPlotLimits::Contains(double x, double y) const {
return X.Contains(x) && Y.Contains(y);
}
ImPlotInputMap::ImPlotInputMap() {
PanButton = ImGuiMouseButton_Left;
PanMod = ImGuiKeyModFlags_None;
FitButton = ImGuiMouseButton_Left;
ContextMenuButton = ImGuiMouseButton_Right;
BoxSelectButton = ImGuiMouseButton_Right;
BoxSelectMod = ImGuiKeyModFlags_None;
BoxSelectCancelButton = ImGuiMouseButton_Left;
QueryButton = ImGuiMouseButton_Middle;
QueryMod = ImGuiKeyModFlags_None;
QueryToggleMod = ImGuiKeyModFlags_Ctrl;
HorizontalMod = ImGuiKeyModFlags_Alt;
VerticalMod = ImGuiKeyModFlags_Shift;
}
namespace ImPlot {
namespace {
//-----------------------------------------------------------------------------
// Private Utils
//-----------------------------------------------------------------------------
template <int Count>
struct OffsetCalculator {
OffsetCalculator(int* sizes) {
Offsets[0] = 0;
for (int i = 1; i < Count; ++i)
Offsets[i] = Offsets[i-1] + sizes[i-1];
}
int Offsets[Count];
};
template <typename T>
void FillRange(ImVector<T>& buffer, int n, T vmin, T vmax) {
buffer.resize(n);
T step = (vmax - vmin) / (n - 1);
for (int i = 0; i < n; ++i) {
buffer[i] = vmin + i * step;
}
}
// Returns true if a flag is set
template <typename TSet, typename TFlag>
inline bool HasFlag(TSet set, TFlag flag) {
return (set & flag) == flag;
}
// Flips a flag in a flagset
template <typename TSet, typename TFlag>
inline void FlipFlag(TSet& set, TFlag flag) {
HasFlag(set, flag) ? set &= ~flag : set |= flag;
}
// Linearly remaps x from [x0 x1] to [y0 y1].
template <typename T>
inline T Remap(T x, T x0, T x1, T y0, T y1) {
return y0 + (x - x0) * (y1 - y0) / (x1 - x0);
}
// Returns always positive modulo
inline int PosMod(int l, int r) {
return (l % r + r) % r;
}
// Returns the intersection point of two lines A and B (assumes they are not parallel!)
inline ImVec2 Intersection(const ImVec2& a1, const ImVec2& a2, const ImVec2& b1, const ImVec2& b2) {
float v1 = (a1.x * a2.y - a1.y * a2.x);
float v2 = (b1.x * b2.y - b1.y * b2.x);
float v3 = ((a1.x - a2.x) * (b1.y - b2.y) - (a1.y - a2.y) * (b1.x - b2.x));
return ImVec2((v1 * (b1.x - b2.x) - v2 * (a1.x - a2.x)) / v3,
(v1 * (b1.y - b2.y) - v2 * (a1.y - a2.y)) / v3);
}
// Turns NANs to 0s
inline double ConstrainNan(double val) {
return isnan(val) ? 0 : val;
}
// Turns infinity to floating point maximums
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 double ConstrainLog(double val) {
return val <= 0 ? 0.001f : val;
}
// Returns true if val is NAN or INFINITY
inline bool NanOrInf(double val) {
return val == HUGE_VAL || val == -HUGE_VAL || isnan(val);
}
// Computes order of magnitude of double.
inline int OrderOfMagnitude(double val) {
return val == 0 ? 0 : (int)(floor(log10(fabs(val))));
}
// Returns the precision required for a order of magnitude.
inline int OrderToPrecision(int order) {
return order > 0 ? 0 : 1 - order;
}
// Returns a floating point precision to use given a value
inline int Precision(double val) {
return OrderToPrecision(OrderOfMagnitude(val));
}
// Draws vertical text. The position is the bottom left of the text rect.
inline void AddTextVertical(ImDrawList *DrawList, const char *text, ImVec2 pos, ImU32 text_color) {
pos.x = IM_ROUND(pos.x);
pos.y = IM_ROUND(pos.y);
ImFont * font = GImGui->Font;
const ImFontGlyph *glyph;
for (char c = *text++; c; c = *text++) {
glyph = font->FindGlyph(c);
if (!glyph)
continue;
DrawList->PrimReserve(6, 4);
DrawList->PrimQuadUV(
pos + ImVec2(glyph->Y0, -glyph->X0), pos + ImVec2(glyph->Y0, -glyph->X1),
pos + ImVec2(glyph->Y1, -glyph->X1), pos + ImVec2(glyph->Y1, -glyph->X0),
ImVec2(glyph->U0, glyph->V0), ImVec2(glyph->U1, glyph->V0),
ImVec2(glyph->U1, glyph->V1), ImVec2(glyph->U0, glyph->V1), text_color);
pos.y -= glyph->AdvanceX;
}
}
// Calculates the size of vertical text
inline ImVec2 CalcTextSizeVertical(const char *text) {
ImVec2 sz = ImGui::CalcTextSize(text);
return ImVec2(sz.y, sz.x);
}
/// Returns white or black text given background color
inline ImU32 CalcTextColor(const ImVec4& bg) {
return (bg.x * 0.299 + bg.y * 0.587 + bg.z * 0.114) > 0.729 ? IM_COL32_BLACK : IM_COL32_WHITE;
}
} // private namespace
//-----------------------------------------------------------------------------
// Forwards
//-----------------------------------------------------------------------------
ImVec4 NextColor();
//-----------------------------------------------------------------------------
// Structs
//-----------------------------------------------------------------------------
// Tick mark info
struct ImPlotTick {
ImPlotTick(double value, bool major, bool render_label = true) {
PlotPos = value;
Major = major;
RenderLabel = render_label;
Labeled = false;
}
double PlotPos;
float PixelPos;
ImVec2 Size;
int TextOffset;
bool Major;
bool RenderLabel;
bool Labeled;
};
// Axis state information that must persist after EndPlot
struct ImPlotAxis {
ImPlotAxis() {
Dragging = false;
Range.Min = 0;
Range.Max = 1;
Flags = PreviousFlags = ImPlotAxisFlags_Default;
}
bool Dragging;
ImPlotRange Range;
ImPlotAxisFlags Flags, PreviousFlags;
};
// Axis state information only needed between BeginPlot/EndPlot
struct ImPlotAxisState {
ImPlotAxis* Axis;
bool HasRange;
ImGuiCond RangeCond;
bool Present;
int PresentSoFar;
bool Invert;
bool LockMin;
bool LockMax;
bool Lock;
ImPlotAxisState(ImPlotAxis& axis, bool has_range, ImGuiCond range_cond, bool present, int previous_present) :
Axis(&axis),
HasRange(has_range),
RangeCond(range_cond),
Present(present),
PresentSoFar(previous_present + (Present ? 1 : 0)),
Invert(HasFlag(Axis->Flags, ImPlotAxisFlags_Invert)),
LockMin(HasFlag(Axis->Flags, ImPlotAxisFlags_LockMin) || (HasRange && RangeCond == ImGuiCond_Always)),
LockMax(HasFlag(Axis->Flags, ImPlotAxisFlags_LockMax) || (HasRange && RangeCond == ImGuiCond_Always)),
Lock(!Present || ((LockMin && LockMax) || (HasRange && RangeCond == ImGuiCond_Always)))
{}
ImPlotAxisState() :
Axis(), HasRange(), RangeCond(), Present(), PresentSoFar(),Invert(),LockMin(), LockMax(), Lock()
{}
};
struct ImPlotAxisColor {
ImPlotAxisColor() : Major(), Minor(), Txt() {}
ImU32 Major, Minor, Txt;
};
// State information for Plot items
struct ImPlotItem {
ImPlotItem() {
Show = true;
SeenThisFrame = false;
Highlight = false;
Color = NextColor();
NameOffset = -1;
ID = 0;
}
~ImPlotItem() { ID = 0; }
bool Show;
bool SeenThisFrame;
bool Highlight;
ImVec4 Color;
int NameOffset;
ImGuiID ID;
};
// Holds Plot state information that must persist after EndPlot
struct ImPlotState {
ImPlotState() {
Selecting = Querying = Queried = DraggingQuery = false;
SelectStart = QueryStart = ImVec2(0,0);
Flags = PreviousFlags = ImPlotFlags_Default;
ColorIdx = 0;
CurrentYAxis = 0;
}
ImPool<ImPlotItem> Items;
ImRect BB_Legend;
ImVec2 SelectStart;
bool Selecting;
bool Querying;
bool Queried;
bool DraggingQuery;
ImVec2 QueryStart;
ImRect QueryRect; // relative to BB_Plot!!
ImPlotAxis XAxis;
ImPlotAxis YAxis[MAX_Y_AXES];
ImPlotFlags Flags, PreviousFlags;
int ColorIdx;
int CurrentYAxis;
};
struct ImPlotNextPlotData {
ImPlotNextPlotData() {
HasXRange = false;
ShowDefaultTicksX = true;
for (int i = 0; i < MAX_Y_AXES; ++i) {
HasYRange[i] = false;
ShowDefaultTicksY[i] = true;
}
}
ImGuiCond XRangeCond;
ImGuiCond YRangeCond[MAX_Y_AXES];
bool HasXRange;
bool HasYRange[MAX_Y_AXES];
ImPlotRange X;
ImPlotRange Y[MAX_Y_AXES];
bool ShowDefaultTicksX;
bool ShowDefaultTicksY[MAX_Y_AXES];
};
// Holds Plot state information that must persist only between calls to BeginPlot()/EndPlot()
struct ImPlotContext {
ImPlotContext() : RenderX(), RenderY() {
ChildWindowMade = false;
Reset();
SetColormap(ImPlotColormap_Default);
}
void Reset() {
// end child window if it was made
if (ChildWindowMade)
ImGui::EndChild();
ChildWindowMade = false;
// reset the next plot data
NextPlotData = ImPlotNextPlotData();
// reset items count
VisibleItemCount = 0;
// reset legend items
LegendIndices.shrink(0);
LegendLabels.Buf.shrink(0);
// reset ticks/labels
XTicks.shrink(0);
XTickLabels.Buf.shrink(0);
for (int i = 0; i < 3; ++i) {
YTicks[i].shrink(0);
YTickLabels[i].Buf.shrink(0);
}
// reset extents
FitX = false;
ExtentsX.Min = HUGE_VAL;
ExtentsX.Max = -HUGE_VAL;
for (int i = 0; i < MAX_Y_AXES; i++) {
ExtentsY[i].Min = HUGE_VAL;
ExtentsY[i].Max = -HUGE_VAL;
FitY[i] = false;
}
// reset digital plot items count
DigitalPlotItemCnt = 0;
DigitalPlotOffset = 0;
// nullify plot
CurrentPlot = NULL;
}
// ALl Plots
ImPool<ImPlotState> Plots;
// Current Plot
ImPlotState* CurrentPlot;
// Legend
ImVector<int> LegendIndices;
ImGuiTextBuffer LegendLabels;
// Bounding regions
ImRect BB_Frame;
ImRect BB_Canvas;
ImRect BB_Plot;
// Cached Colors
ImU32 Col_Frame, Col_Bg, Col_Border,
Col_Txt, Col_TxtDis,
Col_SlctBg, Col_SlctBd,
Col_QryBg, Col_QryBd;
ImPlotAxisColor Col_X;
ImPlotAxisColor Col_Y[MAX_Y_AXES];
ImPlotAxisState X;
ImPlotAxisState Y[MAX_Y_AXES];
// Tick marks
ImVector<ImPlotTick> XTicks, YTicks[MAX_Y_AXES];
ImGuiTextBuffer XTickLabels, YTickLabels[MAX_Y_AXES];
float AxisLabelReference[MAX_Y_AXES];
// Transformation cache
ImRect PixelRange[MAX_Y_AXES];
// linear scale (slope)
double Mx;
double My[MAX_Y_AXES];
// log scale denominator
double LogDenX;
double LogDenY[MAX_Y_AXES];
// Data extents
ImPlotRange ExtentsX;
ImPlotRange ExtentsY[MAX_Y_AXES];
int VisibleItemCount;
bool FitThisFrame; bool FitX;
bool FitY[MAX_Y_AXES];
// Hover states
bool Hov_Frame;
bool Hov_Plot;
// Render flags
bool RenderX, RenderY[MAX_Y_AXES];
// Lock info
bool LockPlot;
bool ChildWindowMade;
// Mouse pos
ImPlotPoint LastMousePos[MAX_Y_AXES];
// Style
ImVec4* Colormap;
int ColormapSize;
ImPlotStyle Style;
ImPlotInputMap InputMap;
ImVector<ImGuiColorMod> ColorModifiers; // Stack for PushStyleColor()/PopStyleColor()
ImVector<ImGuiStyleMod> StyleModifiers; // Stack for PushStyleVar()/PopStyleVar()
ImPlotNextPlotData NextPlotData;
// Digital plot item count
int DigitalPlotItemCnt;
int DigitalPlotOffset;
};
// Global plot context
static ImPlotContext gp;
//-----------------------------------------------------------------------------
// Context Utils
//-----------------------------------------------------------------------------
ImPlotInputMap& GetInputMap() {
return gp.InputMap;
}
// Returns the next unused default plot color
ImVec4 NextColor() {
ImVec4 col = gp.Colormap[gp.CurrentPlot->ColorIdx % gp.ColormapSize];
gp.CurrentPlot->ColorIdx++;
return col;
}
inline void FitPoint(const ImPlotPoint& p) {
ImPlotRange* extents_x = &gp.ExtentsX;
ImPlotRange* extents_y = &gp.ExtentsY[gp.CurrentPlot->CurrentYAxis];
if (!NanOrInf(p.x)) {
extents_x->Min = p.x < extents_x->Min ? p.x : extents_x->Min;
extents_x->Max = p.x > extents_x->Max ? p.x : extents_x->Max;
}
if (!NanOrInf(p.y)) {
extents_y->Min = p.y < extents_y->Min ? p.y : extents_y->Min;
extents_y->Max = p.y > extents_y->Max ? p.y : extents_y->Max;
}
}
//-----------------------------------------------------------------------------
// Coordinate Transforms
//-----------------------------------------------------------------------------
inline void UpdateTransformCache() {
// get pixels for transforms
for (int i = 0; i < MAX_Y_AXES; i++) {
gp.PixelRange[i] = ImRect(HasFlag(gp.CurrentPlot->XAxis.Flags, ImPlotAxisFlags_Invert) ? gp.BB_Plot.Max.x : gp.BB_Plot.Min.x,
HasFlag(gp.CurrentPlot->YAxis[i].Flags, ImPlotAxisFlags_Invert) ? gp.BB_Plot.Min.y : gp.BB_Plot.Max.y,
HasFlag(gp.CurrentPlot->XAxis.Flags, ImPlotAxisFlags_Invert) ? gp.BB_Plot.Min.x : gp.BB_Plot.Max.x,
HasFlag(gp.CurrentPlot->YAxis[i].Flags, ImPlotAxisFlags_Invert) ? gp.BB_Plot.Max.y : gp.BB_Plot.Min.y);
gp.My[i] = (gp.PixelRange[i].Max.y - gp.PixelRange[i].Min.y) / gp.CurrentPlot->YAxis[i].Range.Size();
}
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] = 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();
}
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;
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)) {
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)) {
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;
}
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(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