Skip to content
Open
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
15 changes: 14 additions & 1 deletion implot3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
#include "imgui.h"
#ifndef IMGUI_DISABLE

#include <limits.h>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need this for INT_MAX used in IMPLOT3D_DEFAULT_MAJOR_STRIDE. Cannot use sizeof(T), -1(i/uint8) or 0 which are all potentially valid values.
I cannot think of a good value to make IMPLOT3D_DEFAULT_MAJOR_STRIDE other than INT_MAX. Maybe somebody has a better suggestion?


//-----------------------------------------------------------------------------
// [SECTION] Macros and Defines
//-----------------------------------------------------------------------------
Expand All @@ -50,6 +52,7 @@
#define IMPLOT3D_AUTO -1 // Deduce variable automatically
#define IMPLOT3D_AUTO_COL ImVec4(0, 0, 0, -1) // Deduce color automatically
#define IMPLOT3D_TMP template <typename T> IMPLOT3D_API
#define IMPLOT3D_DEFAULT_MAJOR_STRIDE INT_MAX

//-----------------------------------------------------------------------------
// [SECTION] Forward declarations and basic types
Expand Down Expand Up @@ -226,6 +229,13 @@ enum ImPlot3DSurfaceFlags_ {
ImPlot3DSurfaceFlags_NoLines = 1 << 10, // No lines will be rendered
ImPlot3DSurfaceFlags_NoFill = 1 << 11, // No fill will be rendered
ImPlot3DSurfaceFlags_NoMarkers = 1 << 12, // No markers will be rendered

// The plane to use for the surface plot
ImPlot3DSurfaceFlags_PlaneXY = 0, // Use the XY plane and Z values for surface. Default behavior. Use for None flag
ImPlot3DSurfaceFlags_PlaneXZ = 1 << 13, // Use the XZ plane and Y values for surface
ImPlot3DSurfaceFlags_PlaneYZ = 1 << 14, // Use the YZ plane and X values for surface
ImPlot3DSurfaceFlags_SwapAxes = 1 << 15, // Swap the minor and major axis. Only has an effect on the PlotSurface function where only the values are passed in
ImPlot3DSurfaceFlags_PlaneMask_ = ImPlot3DSurfaceFlags_PlaneXY | ImPlot3DSurfaceFlags_PlaneXZ | ImPlot3DSurfaceFlags_PlaneYZ,
};

// Flags for PlotMesh
Expand Down Expand Up @@ -451,8 +461,11 @@ IMPLOT3D_TMP void PlotQuad(const char* label_id, const T* xs, const T* ys, const
// Plot the surface defined by a grid of vertices. The grid is defined by the x and y arrays, and the z array contains the height of each vertex. A
// total of x_count * y_count vertices are expected for each array. Leave #scale_min and #scale_max both at 0 for automatic color scaling, or set them
// to a predefined range
IMPLOT3D_TMP void PlotSurface(const char* label_id, const T* xs, const T* ys, const T* zs, int x_count, int y_count, double scale_min = 0.0,
IMPLOT3D_TMP void PlotSurface(const char* label_id, const T* xs, const T* ys, const T* zs, int minor_count, int major_count, double scale_min = 0.0,
double scale_max = 0.0, ImPlot3DSurfaceFlags flags = 0, int offset = 0, int stride = sizeof(T));
IMPLOT3D_TMP void PlotSurface(const char* label_id, const T* values, int minor_count, int major_count, double scale_min = 0.0, double scale_max = 0.0,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could maybe simplify this. Having all these parameters allows for a lot of control.

ImPlot3DSurfaceFlags flags = 0, const ImVec2& minor_bounds = ImVec2(-1, 1), const ImVec2& major_bounds = ImVec2(-1, 1),
int offset = 0, int stride = sizeof(T), int major_offset = 0, int major_stride = IMPLOT3D_DEFAULT_MAJOR_STRIDE);

IMPLOT3D_API void PlotMesh(const char* label_id, const ImPlot3DPoint* vtx, const unsigned int* idx, int vtx_count, int idx_count,
ImPlot3DMeshFlags flags = 0);
Expand Down
147 changes: 147 additions & 0 deletions implot3d_demo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
// [SECTION] Plots
// [SECTION] Axes
// [SECTION] Custom
// [SECTION] Tools
// [SECTION] Demo Window
// [SECTION] Style Editor
// [SECTION] User Namespace Implementation
Expand Down Expand Up @@ -397,6 +398,61 @@ void DemoSurfacePlots() {
ImPlot3D::PopColormap();
}

void DemoSimplifiedSurfacePlots() {
constexpr int N = 10;
constexpr int M = 20;
static float values[N * M];
static float t = 0.0f;
t += ImGui::GetIO().DeltaTime;

// Define the range for X and Y
constexpr float min_val = -1.0f;
constexpr float max_val = 1.0f;
constexpr float x_step = (max_val - min_val) / (M - 1);
constexpr float y_step = (max_val - min_val) / (N - 1);

// Populate the values array
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
int idx = i * M + j;
float x = min_val + j * x_step;
float y = min_val + i * y_step;
values[idx] = ImSin(2 * t + ImSqrt((x * x + y * y))); // value = sin(2t + sqrt(x^2 + y^2))
}
}

// Select flags for the surface plot
static ImPlot3DSurfaceFlags flags = ImPlot3DSurfaceFlags_NoMarkers;
CHECKBOX_FLAG(flags, ImPlot3DSurfaceFlags_NoLines);
CHECKBOX_FLAG(flags, ImPlot3DSurfaceFlags_NoFill);
CHECKBOX_FLAG(flags, ImPlot3DSurfaceFlags_NoMarkers);

// Begin the plot
ImPlot3D::PushColormap("Jet");
if (ImPlot3D::BeginPlot("Surface Plots", ImVec2(-1, 400), ImPlot3DFlags_NoClip)) {
ImPlot3D::SetupAxes("x", "y", "z");
ImPlot3D::SetupAxesLimits(-10, -5, 5, 10, -1.5, 1.5);

// Set fill style
ImPlot3D::PushStyleVar(ImPlot3DStyleVar_FillAlpha, 0.8f);

// Set line style
ImPlot3D::SetNextLineStyle(ImPlot3D::GetColormapColor(1));

// Set marker style
ImPlot3D::SetNextMarkerStyle(ImPlot3DMarker_Square, IMPLOT3D_AUTO, ImPlot3D::GetColormapColor(2));

// Plot the surface
// Plot the X-Axis range from [-10, -5] and Y-Axis range from [5, 10]
ImPlot3D::PlotSurface("Wave Surface", values, M, N, 0.0, 0.0, flags, ImVec2(-10, -5), ImVec2(5, 10));

// End the plot
ImPlot3D::PopStyleVar();
ImPlot3D::EndPlot();
}
ImPlot3D::PopColormap();
}

void DemoMeshPlots() {
static int mesh_id = 0;
ImGui::Combo("Mesh", &mesh_id, "Duck\0Sphere\0Cube\0\0");
Expand Down Expand Up @@ -737,6 +793,92 @@ void DemoAxisConstraints() {
}
}

//-----------------------------------------------------------------------------
// [SECTION] Tools
//-----------------------------------------------------------------------------

void DemoSurfaceAxisOffsetStride() {
constexpr int N = 10;
constexpr int M = 20;
static float values[N * M];

// Define the range for X and Y
constexpr float min_val = -1.0f;
constexpr float max_val = 1.0f;
constexpr float x_step = (max_val - min_val) / (N - 1);
constexpr float y_step = (max_val - min_val) / (M - 1);

// Populate the values array
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
int idx = i * M + j;
float x = min_val + j * x_step;
float y = min_val + i * y_step;
values[idx] = ImSin(ImSqrt((x * x + y * y))); // value = sin(sqrt(x^2 + y^2))
}
}

// Add offset and stride
static int offset = 0;
static int major_offset = 0;
static int stride = 1;
static int major_stride = 1;
static bool apply_major_stride = true;
if(ImGui::Checkbox("Apply Major stride", &apply_major_stride))
major_stride = 1;
ImGui::SliderInt("Minor Offset", &offset, -200, 200);
ImGui::SliderInt("Major Offset", &major_offset, -20, 20);
ImGui::SliderInt("Minor Stride", &stride, -10, 10);
if (apply_major_stride)
ImGui::SliderInt("Major Stride", &major_stride, -10, 10);

// Select flags for the surface plot
// Default to using ImPlot3DSurfaceFlags_PlaneXY flag. If neither the ImPlot3DSurfaceFlags_PlaneXZ and the ImPlot3DSurfaceFlags_PlaneYZ flag is
// set then use ImPlot3DSurfaceFlags_PlaneXY
static ImPlot3DSurfaceFlags flags = ImPlot3DSurfaceFlags_NoMarkers | ImPlot3DSurfaceFlags_PlaneXY;
CHECKBOX_FLAG(flags, ImPlot3DSurfaceFlags_NoLines);
CHECKBOX_FLAG(flags, ImPlot3DSurfaceFlags_NoFill);
CHECKBOX_FLAG(flags, ImPlot3DSurfaceFlags_NoMarkers);
if (ImGui::CheckboxFlags("ImPlot3DSurfaceFlags_PlaneXZ", &flags, ImPlot3DSurfaceFlags_PlaneXZ))
flags &= ~(ImPlot3DSurfaceFlags_PlaneMask_ & ~ImPlot3DSurfaceFlags_PlaneXZ);
if (ImGui::CheckboxFlags("ImPlot3DSurfaceFlags_PlaneYZ", &flags, ImPlot3DSurfaceFlags_PlaneYZ))
flags &= ~(ImPlot3DSurfaceFlags_PlaneMask_ & ~ImPlot3DSurfaceFlags_PlaneYZ);
CHECKBOX_FLAG(flags, ImPlot3DSurfaceFlags_SwapAxes);

// Begin the plot
ImPlot3D::PushColormap("Jet");
if (ImPlot3D::BeginPlot("Surface Plots", ImVec2(-1, 400), ImPlot3DFlags_NoClip)) {
ImPlot3D::SetupAxes("x", "y", "z");
ImPlot3D::SetupAxesLimits(-1, 1, -1, 1, -1, 1);

// Set fill style
ImPlot3D::PushStyleVar(ImPlot3DStyleVar_FillAlpha, 0.8f);

// Set line style
ImPlot3D::SetNextLineStyle(ImPlot3D::GetColormapColor(1));

// Set marker style
ImPlot3D::SetNextMarkerStyle(ImPlot3DMarker_Square, IMPLOT3D_AUTO, ImPlot3D::GetColormapColor(2));

// Update the number of minor and major items depending on the stride that was selected
const int updated_num_minor = stride == 0 ? M : (M / abs(stride) + (M % stride == 0 ? 0 : 1));
const int updated_num_major = major_stride == 0 ? N : (N / abs(major_stride) + (N % major_stride == 0 ? 0 : 1));

const int array_offset = (major_stride < 0 ? (M * (N - 1)) : 0) + (stride < 0 ? M : 1) - 1;

// Plot the surface
// The surface is flipped around the minor axis by specifying ImVec2(1, -1) for the minor bounds
ImPlot3D::PlotSurface("Wave Surface", &values[array_offset], updated_num_minor, updated_num_major, 0.0, 0.0, flags, ImVec2(1, -1),
ImVec2(-1, 1), offset, stride * sizeof(float), major_offset,
apply_major_stride ? (major_stride * M * sizeof(float)) : IMPLOT3D_DEFAULT_MAJOR_STRIDE);

// End the plot
ImPlot3D::PopStyleVar();
ImPlot3D::EndPlot();
}
ImPlot3D::PopColormap();
}

//-----------------------------------------------------------------------------
// [SECTION] Custom
//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -873,6 +1015,7 @@ void ShowAllDemos() {
DemoHeader("Triangle Plots", DemoTrianglePlots);
DemoHeader("Quad Plots", DemoQuadPlots);
DemoHeader("Surface Plots", DemoSurfacePlots);
DemoHeader("Simplified Surface Plots", DemoSimplifiedSurfacePlots);
DemoHeader("Mesh Plots", DemoMeshPlots);
DemoHeader("Realtime Plots", DemoRealtimePlots);
DemoHeader("Image Plots", DemoImagePlots);
Expand All @@ -887,6 +1030,10 @@ void ShowAllDemos() {
DemoHeader("Axis Constraints", DemoAxisConstraints);
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Tools")) {
DemoHeader("Surface Axis, Offset and Stride Plot", DemoSurfaceAxisOffsetStride);
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Custom")) {
DemoHeader("Custom Styles", DemoCustomStyles);
DemoHeader("Custom Rendering", DemoCustomRendering);
Expand Down
2 changes: 2 additions & 0 deletions implot3d_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ template <typename TSet, typename TFlag> static inline bool ImHasFlag(TSet set,
// Flips a flag in a flagset
template <typename TSet, typename TFlag> static inline void ImFlipFlag(TSet& set, TFlag flag) { ImHasFlag(set, flag) ? set &= ~flag : set |= flag; }
template <typename T> static inline T ImRemap01(T x, T x0, T x1) { return (x1 - x0) ? ((x - x0) / (x1 - x0)) : 0; }
// Returns always positive modulo (assumes r != 0)
static inline int ImPosMod(int l, int r) { return (l % r + r) % r; }
// Returns true if val is NAN
static inline bool ImNan(float val) { return isnan(val); }
// Returns true if val is NAN or INFINITY
Expand Down
Loading
Loading