Skip to content
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ A graphing calculator written in C++ with an ImGui user interface rendered with
## How to get started

The codebase of this repo is quite big, but the file that is of interest to you as a contributor is [
`src/code/Core/Application.cpp`](src/core/Core/Application.cpp). It contains the code for parsing expressions
`src/core/Core/Application.cpp`](src/core/Core/Application.cpp). It contains the code for parsing expressions
(using [ExprTk](https://github.com/ArashPartow/exprtk)) and the rendering logic for calculating the graph's points. Most,
if not all features can be implemented by only modifying this one file.

Expand Down
91 changes: 81 additions & 10 deletions src/core/Core/Application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,18 +212,88 @@ ExitStatus App::Application::run() {
}
}

// check for implicit form: f(x,y) = g(x,y)
if (!plotted) {
size_t equals_pos = findTopLevelEquals(func_str);
// check for inequality
if (!plotted && hasInequalityOperator(func_str)) {
double x = 0.0, y = 0.0;
exprtk::symbol_table<double> symbol_table;
symbol_table.add_constants();
addConstants(symbol_table);
symbol_table.add_variable("x", x);
symbol_table.add_variable("y", y);

exprtk::expression<double> expression;
expression.register_symbol_table(symbol_table);

exprtk::parser<double> parser;

if (equals_pos != std::string::npos) {
// split into LHS and RHS
std::string lhs = trim(func_str.substr(0, equals_pos));
std::string rhs = trim(func_str.substr(equals_pos + 1));
if (parser.compile(func_str, expression)) {
// grid parameters
const double x_min = -canvas_sz.x / (2 * zoom);
const double x_max = canvas_sz.x / (2 * zoom);
const double y_min = -canvas_sz.y / (2 * zoom);
const double y_max = canvas_sz.y / (2 * zoom);

// create expression: LHS - RHS
std::string implicit_expr = "(" + lhs + ") - (" + rhs + ")";
// adaptive step size with performance limit
const double step = std::max(0.025, 1.5 / zoom);
const ImU32 inequality_color = IM_COL32(100, 150, 255, 180);
const float dot_size = std::max(1.5f, zoom / 60.0f);


for (y = y_min; y <= y_max; y += step) {
for (x = x_min; x <= x_max; x += step) {

// if expression is true, plot the point
if (expression.value() == 1.0) {
ImVec2 screen_pos(origin.x + static_cast<float>(x * zoom),
origin.y - static_cast<float>(y * zoom));
draw_list->AddCircleFilled(screen_pos, dot_size, inequality_color);
}
}
}

plotted = true;
}
}

// check for implicit form: f(x,y) = g(x,y)
if (!plotted) {
size_t equals_pos = findTopLevelEquals(func_str);
bool has_double_equals = hasEqualsEqualsOperator(func_str);

if (equals_pos != std::string::npos || has_double_equals) {

std::string implicit_expr;

if (has_double_equals) {
// Handle == operator
std::string temp_str = func_str;
int depth = 0;
size_t eq_pos = std::string::npos;

for (size_t i = 0; i < temp_str.size() - 1; ++i) {
char c = temp_str[i];
if (c == '(') ++depth;
else if (c == ')') --depth;
else if (depth == 0 && c == '=' && temp_str[i+1] == '=') {
eq_pos = i;
break;
}
}

if (eq_pos != std::string::npos) {
std::string lhs = trim(temp_str.substr(0, eq_pos));
std::string rhs = trim(temp_str.substr(eq_pos + 2)); // +2 to skip ==
implicit_expr = "(" + lhs + ") - (" + rhs + ")";
}
} else {
// Handle = operator
std::string lhs = trim(func_str.substr(0, equals_pos));
std::string rhs = trim(func_str.substr(equals_pos + 1));
implicit_expr = "(" + lhs + ") - (" + rhs + ")";
}

if (!implicit_expr.empty()) {

// setup exprtk with x and y variables
double x = 0.0, y = 0.0;
exprtk::symbol_table<double> symbolTable;
Expand Down Expand Up @@ -298,7 +368,8 @@ ExitStatus App::Application::run() {
}
}

plotted = true;
plotted = true;
}
}
}
}
Expand Down
42 changes: 42 additions & 0 deletions src/core/Core/funcs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,47 @@ static size_t findTopLevelEquals(const std::string& str) {
return std::string::npos;
}

//function to check for == operator specifically
static bool hasEqualsEqualsOperator(const std::string& str) {
int depth = 0;
for (size_t i = 0; i < str.size(); ++i) {
char c = str[i];

if (c == '(') {
++depth;
} else if (c == ')') {
--depth;
} else if (depth == 0) {
if (c == '=' && i + 1 < str.size() && str[i+1] == '=') {
return true;
}
}
}
return false;
}

// function to check if expression contains inequality operators
static bool hasInequalityOperator(const std::string& str) {
int depth = 0;
for (size_t i = 0; i < str.size(); ++i) {
char c = str[i];

if (c == '(') {
++depth;
} else if (c == ')') {
--depth;
} else if (depth == 0) {
// check for <, >, <=, >=, !=
if (c == '<' || c == '>') {
return true;
}
if (c == '!' && i + 1 < str.size() && str[i+1] == '=') {
return true;
}
}
}
return false;
}

#endif // IMGRAPH_FUNCS_HPP

Loading