11#include " Application.hpp"
2-
32#include < SDL2/SDL.h>
43#include < backends/imgui_impl_sdl2.h>
54#include < backends/imgui_impl_sdlrenderer2.h>
65#include < imgui.h>
7-
86#include < memory>
97#include < string>
108#include < vector>
11-
129#include " Core/DPIHandler.hpp"
1310#include " Core/Debug/Instrumentor.hpp"
1411#include " Core/Log.hpp"
1815#include " exprtk.hpp"
1916#include " funcs.hpp"
2017
18+ using namespace std ;
19+
2120namespace App {
2221
2322Application::Application (const std::string& title) {
@@ -112,15 +111,43 @@ ExitStatus App::Application::run() {
112111 const ImVec2 base_pos = viewport->Pos ;
113112 const ImVec2 base_size = viewport->Size ;
114113
115- static char function[1024 ] = " tanh(x)" ;
116114 static float zoom = 100 .0f ;
115+ struct GraphExpr {
116+ char expr[1024 ];
117+ ImVec4 col;
118+ bool on;
119+ };
120+ static vector<GraphExpr> exprs = {{" sin(x)" , ImVec4 (0 .0f , 0 .5f , 1 .0f , 1 .0f ), true }};
117121
118122 // Left Pane (expression)
119123 {
120124 ImGui::SetNextWindowPos (base_pos);
121125 ImGui::SetNextWindowSize (ImVec2 (base_size.x * 0 .25f , base_size.y ));
122126 ImGui::Begin (" Left Pane" , nullptr , ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar);
123- ImGui::InputTextMultiline (" ##search" , function, sizeof (function), ImVec2 (-FLT_MIN, ImGui::GetTextLineHeight () * 4 ));
127+ ImGui::Text (" Expressions:" );
128+ ImGui::Separator ();
129+ for (int i = 0 ; i < exprs.size (); i++) {
130+ ImGui::PushID (i);
131+ ImGui::InputTextMultiline ((" ##expr" + to_string (i)).c_str (), exprs[i].expr , sizeof (exprs[i].expr ), ImVec2 (-FLT_MIN, ImGui::GetTextLineHeight () * 2 ));
132+ ImGui::SameLine ();
133+ ImGui::ColorEdit3 ((" ##color" + to_string (i)).c_str (), (float *)&exprs[i].col , ImGuiColorEditFlags_NoInputs);
134+ ImGui::Checkbox ((" ##enabled" + to_string (i)).c_str (), &exprs[i].on );
135+ ImGui::SameLine ();
136+ ImGui::Text (" Enabled" );
137+ if (exprs.size () > 1 ) {
138+ ImGui::SameLine ();
139+ if (ImGui::Button (" Delete" )) {
140+ exprs.erase (exprs.begin () + i);
141+ i--;
142+ }
143+ }
144+ ImGui::Separator ();
145+ ImGui::PopID ();
146+ }
147+ if (ImGui::Button (" Add Expression" )) {
148+ exprs.push_back ({" x^2" , ImVec4 (1 .0f , 0 .5f , 0 .0f , 1 .0f ), true });
149+ }
150+ ImGui::Separator ();
124151 ImGui::SliderFloat (" Graph Scale" , &zoom, 10 .0f , 500 .0f , " %.1f" );
125152 ImGui::End ();
126153 }
@@ -139,106 +166,68 @@ ExitStatus App::Application::run() {
139166 float lineThickness = 6 .0f ;
140167 draw_list->AddLine (ImVec2 (canvas_p0.x , origin.y ), ImVec2 (canvas_p1.x , origin.y ), IM_COL32 (0 , 0 , 0 , 255 ), lineThickness);
141168 draw_list->AddLine (ImVec2 (origin.x , canvas_p0.y ), ImVec2 (origin.x , canvas_p1.y ), IM_COL32 (0 , 0 , 0 , 255 ), lineThickness);
142- std::vector<ImVec2> points;
143-
144- // (f(t), g(t))
145- std::string func_str (function);
146-
147-
148- bool plotted = false ;
149-
150- if (!func_str.empty () && func_str.front () == ' (' && func_str.back () == ' )' ) {
151- const std::string inner = func_str.substr (1 , func_str.size () - 2 );
152- // top-level comma separating f and g
153- int depth = 0 ;
154- size_t split_pos = std::string::npos;
155- for (size_t i = 0 ; i < inner.size (); ++i) {
156- char c = inner[i];
157- if (c == ' (' )
158- ++depth;
159- else if (c == ' )' )
160- --depth;
161- else if (c == ' ,' && depth == 0 ) {
162- split_pos = i;
163- break ;
164- }
165- }
166169
167- if (split_pos != std::string::npos) {
168- std::string fx = trim (inner.substr (0 , split_pos));
169- std::string gx = trim (inner.substr (split_pos + 1 ));
170-
171- // Prepare exprtk
172- double t = 0.0 ;
173- exprtk::symbol_table<double > sym_t ;
174- sym_t .add_constants ();
175- addConstants (sym_t );
176- sym_t .add_variable (" t" , t);
177-
178- exprtk::expression<double > expr_fx;
179- expr_fx.register_symbol_table (sym_t );
180- exprtk::expression<double > expr_gx;
181- expr_gx.register_symbol_table (sym_t );
182-
183- exprtk::parser<double > parser;
184- bool ok_fx = parser.compile (fx, expr_fx);
185- bool ok_gx = parser.compile (gx, expr_gx);
186-
187- if (ok_fx && ok_gx) {
188- // iterate t
189- const double t_min = -10.0 ;
190- const double t_max = 10.0 ;
191- const double t_step = 0.02 ;
192-
193- for (t = t_min; t <= t_max; t += t_step) {
194- const double vx = expr_fx.value ();
195- const double vy = expr_gx.value ();
196-
197-
198- ImVec2 screen_pos (origin.x + static_cast <float >(vx * zoom),
199- origin.y - static_cast <float >(vy * zoom));
200- points.push_back (screen_pos);
170+ for (const auto & e : exprs) {
171+ if (!e.on ) continue ;
172+ vector<ImVec2> pts;
173+ string s (e.expr );
174+ bool ok = false ;
175+
176+ if (!s.empty () && s.front () == ' (' && s.back () == ' )' ) {
177+ string inner = s.substr (1 , s.size () - 2 );
178+ int d = 0 ;
179+ size_t pos = string::npos;
180+ for (size_t i = 0 ; i < inner.size (); ++i) {
181+ char c = inner[i];
182+ if (c == ' (' ) ++d;
183+ else if (c == ' )' ) --d;
184+ else if (c == ' ,' && d == 0 ) {
185+ pos = i;
186+ break ;
187+ }
188+ }
189+ if (pos != string::npos) {
190+ string fx = trim (inner.substr (0 , pos));
191+ string gx = trim (inner.substr (pos + 1 ));
192+ double t = 0.0 ;
193+ exprtk::symbol_table<double > st;
194+ st.add_constants ();
195+ addConstants (st);
196+ st.add_variable (" t" , t);
197+ exprtk::expression<double > ef, eg;
198+ ef.register_symbol_table (st);
199+ eg.register_symbol_table (st);
200+ exprtk::parser<double > p;
201+ if (p.compile (fx, ef) && p.compile (gx, eg)) {
202+ for (t = -10.0 ; t <= 10.0 ; t += 0.02 ) {
203+ double vx = ef.value ();
204+ double vy = eg.value ();
205+ pts.push_back (ImVec2 (origin.x + vx * zoom, origin.y - vy * zoom));
206+ }
207+ ImU32 c = IM_COL32 (e.col .x * 255 , e.col .y * 255 , e.col .z * 255 , 255 );
208+ draw_list->AddPolyline (pts.data (), pts.size (), c, ImDrawFlags_None, lineThickness);
209+ ok = true ;
201210 }
202-
203- // Draw curve
204- draw_list->AddPolyline (points.data (),
205- points.size (),
206- IM_COL32 (64 , 128 , 199 , 255 ),
207- ImDrawFlags_None,
208- lineThickness);
209- plotted = true ;
210211 }
211212 }
212- }
213-
214- if (!plotted) {
215- // Fallback to y = f(x) plotting using variable x
216- double x;
217-
218- exprtk::symbol_table<double > symbolTable;
219- symbolTable.add_constants ();
220- addConstants (symbolTable);
221- symbolTable.add_variable (" x" , x);
222-
223- exprtk::expression<double > expression;
224- expression.register_symbol_table (symbolTable);
225-
226- exprtk::parser<double > parser;
227- parser.compile (function, expression);
228-
229- for (x = -canvas_sz.x / (2 * zoom); x < canvas_sz.x / (2 * zoom); x += 0.05 ) {
230- const double y = expression.value ();
231-
232-
233- ImVec2 screen_pos (origin.x + x * zoom, origin.y - y * zoom);
234- points.push_back (screen_pos);
213+ if (!ok) {
214+ double x;
215+ exprtk::symbol_table<double > st;
216+ st.add_constants ();
217+ addConstants (st);
218+ st.add_variable (" x" , x);
219+ exprtk::expression<double > expr;
220+ expr.register_symbol_table (st);
221+ exprtk::parser<double > p;
222+ if (p.compile (s, expr)) {
223+ for (x = -canvas_sz.x / (2 * zoom); x < canvas_sz.x / (2 * zoom); x += 0.05 ) {
224+ double y = expr.value ();
225+ pts.push_back (ImVec2 (origin.x + x * zoom, origin.y - y * zoom));
226+ }
227+ ImU32 c = IM_COL32 (e.col .x * 255 , e.col .y * 255 , e.col .z * 255 , 255 );
228+ draw_list->AddPolyline (pts.data (), pts.size (), c, ImDrawFlags_None, lineThickness);
229+ }
235230 }
236-
237- draw_list->AddPolyline (points.data (),
238- points.size (),
239- IM_COL32 (199 , 68 , 64 , 255 ),
240- ImDrawFlags_None,
241- lineThickness);
242231 }
243232
244233 ImGui::End ();
0 commit comments