Skip to content

Commit b0af23c

Browse files
committed
feat: add multi-expression plotting support
- Add Expression struct with text and color fields - Add vector of expressions with dynamic add/remove - Add color picker button next to each expression input - Render all expressions in loop with custom colors - Add Add Expression button below inputs - Add /bigobj compiler flag for MSVC Implements OPCODE-Open-Spring-Fest#15 with minimal scope changes
1 parent 42684fc commit b0af23c

File tree

3 files changed

+66
-19
lines changed

3 files changed

+66
-19
lines changed

src/core/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ endif ()
2323

2424
target_include_directories(${NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
2525
target_compile_features(${NAME} PRIVATE cxx_std_20)
26+
27+
# Add /bigobj flag for MSVC to handle large object files
28+
if(MSVC)
29+
target_compile_options(${NAME} PRIVATE /bigobj)
30+
endif()
31+
2632
target_link_libraries(${NAME}
2733
PRIVATE project_warnings
2834
PUBLIC fmt spdlog exprtk SDL2::SDL2 imgui Settings)

src/core/Core/Application.cpp

Lines changed: 53 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -113,15 +113,42 @@ ExitStatus App::Application::run() {
113113
const ImVec2 base_pos = viewport->Pos;
114114
const ImVec2 base_size = viewport->Size;
115115

116-
static char function[1024] = "r = 1 + 0.5*cos(theta)";
117116
static float zoom = 100.0f;
118117

119-
// Left Pane (expression)
118+
// Left Pane (expressions)
120119
{
121120
ImGui::SetNextWindowPos(base_pos);
122121
ImGui::SetNextWindowSize(ImVec2(base_size.x * 0.25f, base_size.y));
123122
ImGui::Begin("Left Pane", nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar);
124-
ImGui::InputTextMultiline("##search", function, sizeof(function), ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 4));
123+
124+
// Loop through all expressions
125+
for (size_t i = 0; i < m_expressions.size(); ++i) {
126+
ImGui::PushID(i);
127+
128+
// Color picker button
129+
ImGui::ColorEdit3("##color", m_expressions[i].color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel);
130+
ImGui::SameLine();
131+
132+
// Expression input
133+
ImGui::InputTextMultiline("##expr", m_expressions[i].text, sizeof(m_expressions[i].text),
134+
ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 2));
135+
136+
ImGui::PopID();
137+
}
138+
139+
// Add expression button
140+
if (ImGui::Button("+ Add Expression")) {
141+
Expression new_expr;
142+
new_expr.text[0] = '\0';
143+
// Cycle through some nice colors
144+
const float colors[][3] = {{0.25f, 0.5f, 0.78f}, {0.8f, 0.2f, 0.2f}, {0.2f, 0.8f, 0.2f}, {0.9f, 0.6f, 0.1f}};
145+
int color_idx = m_expressions.size() % 4;
146+
new_expr.color[0] = colors[color_idx][0];
147+
new_expr.color[1] = colors[color_idx][1];
148+
new_expr.color[2] = colors[color_idx][2];
149+
m_expressions.push_back(new_expr);
150+
}
151+
125152
ImGui::SliderFloat("Graph Scale", &zoom, 10.0f, 500.0f, "%.1f");
126153
ImGui::End();
127154
}
@@ -140,13 +167,22 @@ ExitStatus App::Application::run() {
140167
float lineThickness = 6.0f;
141168
draw_list->AddLine(ImVec2(canvas_p0.x, origin.y), ImVec2(canvas_p1.x, origin.y), IM_COL32(0, 0, 0, 255), lineThickness);
142169
draw_list->AddLine(ImVec2(origin.x, canvas_p0.y), ImVec2(origin.x, canvas_p1.y), IM_COL32(0, 0, 0, 255), lineThickness);
143-
std::vector<ImVec2> points;
144-
145-
// (f(t), g(t))
146-
std::string func_str(function);
147170

148-
149-
bool plotted = false;
171+
// Loop through all expressions and plot each
172+
for (const auto& expr : m_expressions) {
173+
std::string func_str(expr.text);
174+
if (func_str.empty()) continue;
175+
176+
std::vector<ImVec2> points;
177+
bool plotted = false;
178+
179+
// Convert color to ImU32
180+
ImU32 line_color = IM_COL32(
181+
static_cast<int>(expr.color[0] * 255),
182+
static_cast<int>(expr.color[1] * 255),
183+
static_cast<int>(expr.color[2] * 255),
184+
255
185+
);
150186

151187
if (!func_str.empty() && func_str.front() == '(' && func_str.back() == ')') {
152188
const std::string inner = func_str.substr(1, func_str.size() - 2);
@@ -204,7 +240,7 @@ ExitStatus App::Application::run() {
204240
// Draw curve
205241
draw_list->AddPolyline(points.data(),
206242
points.size(),
207-
IM_COL32(64, 128, 199, 255),
243+
line_color,
208244
ImDrawFlags_None,
209245
lineThickness);
210246
plotted = true;
@@ -235,7 +271,6 @@ ExitStatus App::Application::run() {
235271

236272
// adaptive step size with performance limit
237273
const double step = std::max(0.025, 1.5 / zoom);
238-
const ImU32 inequality_color = IM_COL32(100, 150, 255, 180);
239274
const float dot_size = std::max(1.5f, zoom / 60.0f);
240275

241276

@@ -246,7 +281,7 @@ ExitStatus App::Application::run() {
246281
if (expression.value() == 1.0) {
247282
ImVec2 screen_pos(origin.x + static_cast<float>(x * zoom),
248283
origin.y - static_cast<float>(y * zoom));
249-
draw_list->AddCircleFilled(screen_pos, dot_size, inequality_color);
284+
draw_list->AddCircleFilled(screen_pos, dot_size, line_color);
250285
}
251286
}
252287
}
@@ -316,7 +351,6 @@ ExitStatus App::Application::run() {
316351
const double y_max = canvas_sz.y / (2 * zoom);
317352
const double step = std::max(0.008, 1.0 / zoom); //dynamic step based on zoom level
318353

319-
const ImU32 implicit_color = IM_COL32(64, 199, 128, 255);
320354
const float dot_radius = 2.5f;
321355

322356
// scan horizontally for sign changes
@@ -336,7 +370,7 @@ ExitStatus App::Application::run() {
336370
// transform to screen coordinates and draw immediately
337371
ImVec2 screen_pos(origin.x + static_cast<float>(x_zero * zoom),
338372
origin.y - static_cast<float>(y_zero * zoom));
339-
draw_list->AddCircleFilled(screen_pos, dot_radius, implicit_color);
373+
draw_list->AddCircleFilled(screen_pos, dot_radius, line_color);
340374
}
341375

342376
prev_val = curr_val;
@@ -360,7 +394,7 @@ ExitStatus App::Application::run() {
360394

361395
ImVec2 screen_pos(origin.x + static_cast<float>(x_zero * zoom),
362396
origin.y - static_cast<float>(y_zero * zoom));
363-
draw_list->AddCircleFilled(screen_pos, dot_radius, implicit_color);
397+
draw_list->AddCircleFilled(screen_pos, dot_radius, line_color);
364398
}
365399

366400
prev_val = curr_val;
@@ -375,7 +409,6 @@ ExitStatus App::Application::run() {
375409
}
376410

377411
if (!plotted) {
378-
std::string func_str(function);
379412
bool is_polar = func_str.find("r=") != std::string::npos || func_str.find("r =") != std::string::npos;
380413

381414
if (is_polar) {
@@ -419,7 +452,7 @@ ExitStatus App::Application::run() {
419452

420453
draw_list->AddPolyline(points.data(),
421454
points.size(),
422-
IM_COL32(128, 64, 199, 255),
455+
line_color,
423456
ImDrawFlags_None,
424457
lineThickness);
425458
}
@@ -435,7 +468,7 @@ ExitStatus App::Application::run() {
435468
expression.register_symbol_table(symbolTable);
436469

437470
exprtk::parser<double> parser;
438-
parser.compile(function, expression);
471+
parser.compile(expr.text, expression);
439472

440473
for (x = -canvas_sz.x / (2 * zoom); x < canvas_sz.x / (2 * zoom); x += 0.05) {
441474
const double y = expression.value();
@@ -446,11 +479,12 @@ ExitStatus App::Application::run() {
446479

447480
draw_list->AddPolyline(points.data(),
448481
points.size(),
449-
IM_COL32(199, 68, 64, 255),
482+
line_color,
450483
ImDrawFlags_None,
451484
lineThickness);
452485
}
453486
}
487+
} // end expression loop
454488

455489
ImGui::End();
456490
ImGui::PopStyleColor();

src/core/Core/Application.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ class Application {
3131
void on_close();
3232

3333
private:
34+
struct Expression {
35+
char text[1024];
36+
float color[3];
37+
};
38+
3439
ExitStatus m_exit_status{ExitStatus::SUCCESS};
3540
std::unique_ptr<Window> m_window{nullptr};
3641

@@ -39,6 +44,8 @@ class Application {
3944
bool m_show_some_panel{true};
4045
bool m_show_debug_panel{false};
4146
bool m_show_demo_panel{false};
47+
48+
std::vector<Expression> m_expressions{{{"r = 1 + 0.5*cos(theta)"}, {0.25f, 0.5f, 0.78f}}};
4249
};
4350

4451
} // namespace App

0 commit comments

Comments
 (0)