diff --git a/implot.h b/implot.h index 42df7f2c..483e1df9 100644 --- a/implot.h +++ b/implot.h @@ -720,6 +720,9 @@ typedef int (*ImPlotFormatter)(double value, char* buff, int size, void* user_da // Callback signature for data getter. typedef ImPlotPoint (*ImPlotGetter)(int idx, void* user_data); +// Callback signature for line segments filters. +typedef bool (*ImPlotFilter)(int idx, ImPlotPoint p1, ImPlotPoint p2, void* user_data); + // Callback signature for axis transform. typedef double (*ImPlotTransform)(double value, void* user_data); @@ -989,6 +992,7 @@ IMPLOT_API void SetNextAxesToFit(); IMPLOT_TMP void PlotLine(const char* label_id, const T* values, int count, double xscale=1, double xstart=0, const ImPlotSpec& spec=ImPlotSpec()); IMPLOT_TMP void PlotLine(const char* label_id, const T* xs, const T* ys, int count, const ImPlotSpec& spec=ImPlotSpec()); IMPLOT_API void PlotLineG(const char* label_id, ImPlotGetter getter, void* data, int count, const ImPlotSpec& spec=ImPlotSpec()); +IMPLOT_API void PlotLineFiltered(const char* label_id, ImPlotGetter getter, ImPlotFilter filter, void* data, int count, const ImPlotSpec& spec=ImPlotSpec()); // Plots a standard 2D scatter plot. Default marker is ImPlotMarker_Circle. IMPLOT_TMP void PlotScatter(const char* label_id, const T* values, int count, double xscale=1, double xstart=0, const ImPlotSpec& spec=ImPlotSpec()); diff --git a/implot_items.cpp b/implot_items.cpp index adea97ef..0c07c1de 100644 --- a/implot_items.cpp +++ b/implot_items.cpp @@ -617,6 +617,21 @@ struct GetterFuncPtr { typedef ImPlotPoint value_type; }; +/// Interprets a user's function pointer as a line segments filter +struct FilterFuncPtr { + FilterFuncPtr(ImPlotFilter filter, void* data) : + Filter(filter), + Data(data) + { } + template IMPLOT_INLINE bool operator()(I idx, ImPlotPoint p1, ImPlotPoint p2) const { + return Filter(idx, p1, p2, Data); + } + ImPlotFilter Filter; + void* const Data; + typedef bool value_type; +}; + + template struct GetterOverrideX { GetterOverrideX(_Getter getter, double x) : Getter(getter), X(x), Count(getter.Count) { } @@ -1005,6 +1020,45 @@ struct RendererLineStrip : RendererBase { mutable ImVec2 UV1; }; +template +struct RendererLineStripFiltered : RendererBase { + RendererLineStripFiltered(const _Getter& getter, const _GetterColor& getter_color, const _Filter& filter, float weight) : + RendererBase(getter.Count - 1, 6, 4), + Getter(getter), + GetterColor(getter_color), + Filter(filter), + HalfWeight(ImMax(1.0f,weight)*0.5f) + { + rawP1 = Getter[0]; + P1 = this->Transformer(rawP1); + } + void Init(ImDrawList& draw_list) const { + GetLineRenderProps(draw_list, HalfWeight, UV0, UV1); + } + IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { + ImPlotPoint rawP2 = Getter[prim + 1]; + ImVec2 P2 = this->Transformer(rawP2); + if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2))) || !Filter(prim + 1, rawP1, rawP2)) { + P1 = P2; + rawP1 = rawP2; + return false; + } + ImU32 col = GetterColor[prim]; + PrimLine(draw_list,P1,P2,HalfWeight,col,UV0,UV1); + P1 = P2; + rawP1 = rawP2; + return true; + } + const _Getter& Getter; + const _GetterColor& GetterColor; + const _Filter& Filter; + mutable float HalfWeight; + mutable ImVec2 P1; + mutable ImPlotPoint rawP1; + mutable ImVec2 UV0; + mutable ImVec2 UV1; +}; + template struct RendererLineStripSkip : RendererBase { RendererLineStripSkip(const _Getter& getter, const _GetterColor& getter_color, float weight) : @@ -1039,6 +1093,49 @@ struct RendererLineStripSkip : RendererBase { mutable ImVec2 UV1; }; +template +struct RendererLineStripSkipFiltered : RendererBase { + RendererLineStripSkipFiltered(const _Getter& getter, const _GetterColor& getter_color, const _Filter& filter, float weight) : + RendererBase(getter.Count - 1, 6, 4), + Getter(getter), + GetterColor(getter_color), + Filter(filter), + HalfWeight(ImMax(1.0f,weight)*0.5f) + { + rawP1 = Getter[0]; + P1 = this->Transformer(rawP1); + } + void Init(ImDrawList& draw_list) const { + GetLineRenderProps(draw_list, HalfWeight, UV0, UV1); + } + IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { + ImPlotPoint rawP2 = Getter[prim + 1]; + ImVec2 P2 = this->Transformer(rawP2); + if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2))) || !Filter(prim + 1, rawP1, rawP2)) { + if (!ImNan(P2.x) && !ImNan(P2.y)){ + P1 = P2; + rawP1 = rawP2; + } + return false; + } + ImU32 col = GetterColor[prim]; + PrimLine(draw_list,P1,P2,HalfWeight,col,UV0,UV1); + if (!ImNan(P2.x) && !ImNan(P2.y)){ + P1 = P2; + rawP1 = rawP2; + } + return true; + } + const _Getter& Getter; + const _GetterColor& GetterColor; + const _Filter& Filter; + mutable float HalfWeight; + mutable ImVec2 P1; + mutable ImPlotPoint rawP1; + mutable ImVec2 UV0; + mutable ImVec2 UV1; +}; + template struct RendererLineSegments1 : RendererBase { RendererLineSegments1(const _Getter& getter, const _GetterColor& getter_color, float weight) : @@ -1066,6 +1163,37 @@ struct RendererLineSegments1 : RendererBase { mutable ImVec2 UV1; }; +template +struct RendererLineSegments1Filtered : RendererBase { + RendererLineSegments1Filtered(const _Getter& getter, const _GetterColor& getter_color, const _Filter& filter, float weight) : + RendererBase(getter.Count / 2, 6, 4), + Getter(getter), + GetterColor(getter_color), + Filter(filter), + HalfWeight(ImMax(1.0f,weight)*0.5f) + { } + void Init(ImDrawList& draw_list) const { + GetLineRenderProps(draw_list, HalfWeight, UV0, UV1); + } + IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { + ImPlotPoint rawP1 = Getter[prim*2+0]; + ImPlotPoint rawP2 = Getter[prim*2+1]; + ImVec2 P1 = this->Transformer(rawP1); + ImVec2 P2 = this->Transformer(rawP2); + if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2))) || !Filter(prim, rawP1, rawP2)) + return false; + ImU32 col = GetterColor[prim*2]; + PrimLine(draw_list,P1,P2,HalfWeight,col,UV0,UV1); + return true; + } + const _Getter& Getter; + const _GetterColor& GetterColor; + const _Filter& Filter; + mutable float HalfWeight; + mutable ImVec2 UV0; + mutable ImVec2 UV1; +}; + template struct RendererLineSegments2 : RendererBase { RendererLineSegments2(const _Getter1& getter1, const _Getter2& getter2, const _GetterColor& getter_color, float weight) : @@ -1095,6 +1223,38 @@ struct RendererLineSegments2 : RendererBase { mutable ImVec2 UV1; }; +template +struct RendererLineSegments2Filtered : RendererBase { + RendererLineSegments2Filtered(const _Getter1& getter1, const _Getter2& getter2, const _GetterColor& getter_color, const _Filter& filter, float weight) : + RendererBase(ImMin(getter1.Count, getter2.Count), 6, 4), + Getter1(getter1), + Getter2(getter2), + GetterColor(getter_color), + HalfWeight(ImMax(1.0f,weight)*0.5f) + {} + void Init(ImDrawList& draw_list) const { + GetLineRenderProps(draw_list, HalfWeight, UV0, UV1); + } + IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { + ImPlotPoint rawP1 = Getter1[prim]; + ImPlotPoint rawP2 = Getter2[prim]; + ImVec2 P1 = this->Transformer(rawP1); + ImVec2 P2 = this->Transformer(rawP2); + if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2))) || !Filter(prim, rawP1, rawP2)) + return false; + ImU32 col = GetterColor[prim]; + PrimLine(draw_list,P1,P2,HalfWeight,col,UV0,UV1); + return true; + } + const _Getter1& Getter1; + const _Getter2& Getter2; + const _GetterColor& GetterColor; + const _Filter& Filter; + mutable float HalfWeight; + mutable ImVec2 UV0; + mutable ImVec2 UV1; +}; + template struct RendererBarsFillV : RendererBase { RendererBarsFillV(const _Getter1& getter1, const _Getter2& getter2, const _GetterColor& getter_color, double width) : @@ -1536,6 +1696,13 @@ void RenderPrimitives2(const _Getter1& getter1, const _Getter2& getter2, Args... RenderPrimitivesEx(_Renderer<_Getter1,_Getter2>(getter1,getter2,args...), draw_list, cull_rect); } +template class _Renderer, class _Getter1, class _Getter2, class _Filter, typename ...Args> +void RenderPrimitives2Filtered(const _Getter1& getter1, const _Getter2& getter2, const _Filter& filter, Args... args){ + ImDrawList& draw_list = *GetPlotDrawList(); + const ImRect& cull_rect = GetCurrentPlot()->PlotRect; + RenderPrimitivesEx(_Renderer<_Getter1,_Getter2, _Filter>(getter1,getter2,filter,args...), draw_list, cull_rect); +} + template