Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SetupAxisTicks for configuring custom ticks #55

Merged
merged 6 commits into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 60 additions & 3 deletions implot3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,11 @@ void RenderGrid(ImDrawList* draw_list, const ImPlot3DPlot& plot, const ImPlot3DP

// Compute position along u
float t_u = (tick.PlotPos - axis_u.Range.Min) / (axis_u.Range.Max - axis_u.Range.Min);

// Skip ticks that are out of range
if (t_u < 0.0f || t_u > 1.0f)
continue;

ImPlot3DPoint p_start = p0 + u_vec * t_u;
ImPlot3DPoint p_end = p3 + u_vec * t_u;

Expand All @@ -618,6 +623,11 @@ void RenderGrid(ImDrawList* draw_list, const ImPlot3DPlot& plot, const ImPlot3DP

// Compute position along v
float t_v = (tick.PlotPos - axis_v.Range.Min) / (axis_v.Range.Max - axis_v.Range.Min);

// Skip ticks that are out of range
if (t_v < 0.0f || t_v > 1.0f)
continue;

ImPlot3DPoint p_start = p0 + v_vec * t_v;
ImPlot3DPoint p_end = p1 + v_vec * t_v;

Expand Down Expand Up @@ -720,6 +730,9 @@ void RenderTickMarks(ImDrawList* draw_list, const ImPlot3DPlot& plot, const ImPl
const ImPlot3DTick& tick = axis.Ticker.Ticks[t];
float v = (tick.PlotPos - axis.Range.Min) / (axis.Range.Max - axis.Range.Min);

// Skip ticks that are out of range
if (v < 0.0f || v > 1.0f)
continue;
ImPlot3DPoint tick_pos_ndc = PlotToNDC(axis_start + axis_dir * (v * axis_len));

// Half tick on each side of the axis line
Expand Down Expand Up @@ -811,6 +824,10 @@ void RenderTickLabels(ImDrawList* draw_list, const ImPlot3DPlot& plot, const ImP

// Compute position along the axis
float t_axis = (tick.PlotPos - axis.Range.Min) / (axis.Range.Max - axis.Range.Min);

// Skip ticks that are out of range
if (t_axis < 0.0f || t_axis > 1.0f)
continue;
ImPlot3DPoint tick_pos = axis_start + axis_dir * t_axis;

// Convert to pixel coordinates
Expand Down Expand Up @@ -1114,6 +1131,15 @@ void Locator_Default(ImPlot3DTicker& ticker, const ImPlot3DRange& range, float p
}
}

void AddTicksCustom(const double* values, const char* const labels[], int n, ImPlot3DTicker& ticker, ImPlot3DFormatter formatter, void* data) {
for (int i = 0; i < n; ++i) {
if (labels != nullptr)
ticker.AddTick(values[i], false, true, labels[i]);
else
ticker.AddTick(values[i], false, true, formatter, data);
}
}

//------------------------------------------------------------------------------
// [SECTION] Context Menus
//------------------------------------------------------------------------------
Expand Down Expand Up @@ -1338,6 +1364,11 @@ bool BeginPlot(const char* title_id, const ImVec2& size, ImPlot3DFlags flags) {
// Reset legend
plot.Items.Legend.Reset();

// Reset axes
for (int i = 0; i < ImAxis3D_COUNT; ++i) {
plot.Axes[i].Reset();
}

// Push frame rect clipping
ImGui::PushClipRect(plot.FrameRect.Min, plot.FrameRect.Max, true);
plot.DrawList._Flags = window->DrawList->Flags;
Expand Down Expand Up @@ -1471,6 +1502,31 @@ void SetupAxisFormat(ImAxis3D idx, ImPlot3DFormatter formatter, void* data) {
axis.FormatterData = data;
}

void SetupAxisTicks(ImAxis3D idx, const double* values, int n_ticks, const char* const labels[], bool keep_default) {
ImPlot3DContext& gp = *GImPlot3D;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr && !gp.CurrentPlot->SetupLocked,
"Setup needs to be called after BeginPlot and before any setup locking functions (e.g. PlotX)!");
ImPlot3DPlot& plot = *gp.CurrentPlot;
ImPlot3DAxis& axis = plot.Axes[idx];
axis.ShowDefaultTicks = keep_default;
AddTicksCustom(values,
labels,
n_ticks,
axis.Ticker,
axis.Formatter ? axis.Formatter : Formatter_Default,
(axis.Formatter && axis.FormatterData) ? axis.FormatterData : (void*)IMPLOT3D_LABEL_FORMAT);
}

void SetupAxisTicks(ImAxis3D idx, double v_min, double v_max, int n_ticks, const char* const labels[], bool keep_default) {
ImPlot3DContext& gp = *GImPlot3D;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr && !gp.CurrentPlot->SetupLocked,
"Setup needs to be called after BeginPlot and before any setup locking functions (e.g. PlotX)!");
n_ticks = n_ticks < 2 ? 2 : n_ticks;
ImVector<double> temp;
FillRange(temp, n_ticks, v_min, v_max);
SetupAxisTicks(idx, temp.Data, n_ticks, labels, keep_default);
}

void SetupAxes(const char* x_label, const char* y_label, const char* z_label, ImPlot3DAxisFlags x_flags, ImPlot3DAxisFlags y_flags, ImPlot3DAxisFlags z_flags) {
SetupAxis(ImAxis3D_X, x_label, x_flags);
SetupAxis(ImAxis3D_Y, y_label, y_flags);
Expand Down Expand Up @@ -2097,9 +2153,10 @@ void SetupLock() {
// Compute ticks
for (int i = 0; i < 3; i++) {
ImPlot3DAxis& axis = plot.Axes[i];
axis.Ticker.Reset();
float pixels = plot.GetBoxZoom() * plot.BoxScale[i];
axis.Locator(axis.Ticker, axis.Range, pixels, axis.Formatter, axis.FormatterData);
if (axis.ShowDefaultTicks) {
float pixels = plot.GetBoxZoom() * plot.BoxScale[i];
axis.Locator(axis.Ticker, axis.Range, pixels, axis.Formatter, axis.FormatterData);
}
}

// Render title
Expand Down
6 changes: 6 additions & 0 deletions implot3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,12 @@ IMPLOT3D_API void SetupAxisLimits(ImAxis3D axis, double v_min, double v_max, ImP

IMPLOT3D_API void SetupAxisFormat(ImAxis3D idx, ImPlot3DFormatter formatter, void* data = nullptr);

// Sets an axis' ticks and optionally the labels. To keep the default ticks, set #keep_default=true
IMPLOT3D_API void SetupAxisTicks(ImAxis3D axis, const double* values, int n_ticks, const char* const labels[] = nullptr, bool keep_default = false);

// Sets an axis' ticks and optionally the labels for the next plot. To keep the default ticks, set #keep_default=true
IMPLOT3D_API void SetupAxisTicks(ImAxis3D axis, double v_min, double v_max, int n_ticks, const char* const labels[] = nullptr, bool keep_default = false);

// Sets the label and/or flags for primary X/Y/Z axes (shorthand for three calls to SetupAxis)
IMPLOT3D_API void SetupAxes(const char* x_label, const char* y_label, const char* z_label, ImPlot3DAxisFlags x_flags = 0, ImPlot3DAxisFlags y_flags = 0, ImPlot3DAxisFlags z_flags = 0);

Expand Down
24 changes: 24 additions & 0 deletions implot3d_demo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,29 @@ void DemoBoxScale() {
}
}

void DemoTickLabels() {
static bool custom_ticks = false;
static bool custom_labels = true;
ImGui::Checkbox("Show Custom Ticks", &custom_ticks);
if (custom_ticks) {
ImGui::SameLine();
ImGui::Checkbox("Show Custom Labels", &custom_labels);
}
const double pi = 3.14;
const char* pi_str[] = {"PI"};
static double letters_ticks[] = {0.0, 0.2, 0.4, 0.6, 0.8, 1.0};
static const char* letters_labels[] = {"A", "B", "C", "D", "E", "F"};
if (ImPlot3D::BeginPlot("##Ticks")) {
ImPlot3D::SetupAxesLimits(2, 5, 0, 1, 0, 1);
if (custom_ticks) {
ImPlot3D::SetupAxisTicks(ImAxis3D_X, &pi, 1, custom_labels ? pi_str : nullptr, true);
ImPlot3D::SetupAxisTicks(ImAxis3D_Y, letters_ticks, 6, custom_labels ? letters_labels : nullptr, false);
ImPlot3D::SetupAxisTicks(ImAxis3D_Z, 0, 1, 6, custom_labels ? letters_labels : nullptr, false);
}
ImPlot3D::EndPlot();
}
}

//-----------------------------------------------------------------------------
// [SECTION] Custom
//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -753,6 +776,7 @@ void ShowDemoWindow(bool* p_open) {
}
if (ImGui::BeginTabItem("Axes")) {
DemoHeader("Box Scale", DemoBoxScale);
DemoHeader("Tick Labels", DemoTickLabels);
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Custom")) {
Expand Down
22 changes: 22 additions & 0 deletions implot3d_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,16 @@ static inline ImU32 ImMixU32(ImU32 a, ImU32 b, ImU32 s) {
#endif
}

// Fills a buffer with n samples linear interpolated from vmin to vmax
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;
}
}

} // namespace ImPlot3D

//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -435,6 +445,7 @@ struct ImPlot3DAxis {
ImPlot3DFormatter Formatter;
void* FormatterData;
ImPlot3DLocator Locator;
bool ShowDefaultTicks;
// Fit data
bool FitThisFrame;
ImPlot3DRange FitExtents;
Expand All @@ -452,6 +463,7 @@ struct ImPlot3DAxis {
Formatter = nullptr;
FormatterData = nullptr;
Locator = nullptr;
ShowDefaultTicks = true;
// Fit data
FitThisFrame = true;
FitExtents.Min = HUGE_VAL;
Expand All @@ -460,6 +472,16 @@ struct ImPlot3DAxis {
Held = false;
}

inline void Reset() {
Formatter = nullptr;
FormatterData = nullptr;
Locator = nullptr;
ShowDefaultTicks = true;
FitExtents.Min = HUGE_VAL;
FitExtents.Max = -HUGE_VAL;
Ticker.Reset();
}

inline void SetRange(double v1, double v2) {
Range.Min = (float)ImMin(v1, v2);
Range.Max = (float)ImMax(v1, v2);
Expand Down