Skip to content

Commit 42684fc

Browse files
authored
Merge pull request #18 from atulya-srivastava/feat-inequality-expression
Feat inequality expression
2 parents 0bb670c + 6adea47 commit 42684fc

File tree

3 files changed

+124
-11
lines changed

3 files changed

+124
-11
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ A graphing calculator written in C++ with an ImGui user interface rendered with
77
## How to get started
88

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

src/core/Core/Application.cpp

Lines changed: 81 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -212,18 +212,88 @@ ExitStatus App::Application::run() {
212212
}
213213
}
214214

215-
// check for implicit form: f(x,y) = g(x,y)
216-
if (!plotted) {
217-
size_t equals_pos = findTopLevelEquals(func_str);
215+
// check for inequality
216+
if (!plotted && hasInequalityOperator(func_str)) {
217+
double x = 0.0, y = 0.0;
218+
exprtk::symbol_table<double> symbol_table;
219+
symbol_table.add_constants();
220+
addConstants(symbol_table);
221+
symbol_table.add_variable("x", x);
222+
symbol_table.add_variable("y", y);
223+
224+
exprtk::expression<double> expression;
225+
expression.register_symbol_table(symbol_table);
226+
227+
exprtk::parser<double> parser;
218228

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

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

241+
242+
for (y = y_min; y <= y_max; y += step) {
243+
for (x = x_min; x <= x_max; x += step) {
244+
245+
// if expression is true, plot the point
246+
if (expression.value() == 1.0) {
247+
ImVec2 screen_pos(origin.x + static_cast<float>(x * zoom),
248+
origin.y - static_cast<float>(y * zoom));
249+
draw_list->AddCircleFilled(screen_pos, dot_size, inequality_color);
250+
}
251+
}
252+
}
253+
254+
plotted = true;
255+
}
256+
}
257+
258+
// check for implicit form: f(x,y) = g(x,y)
259+
if (!plotted) {
260+
size_t equals_pos = findTopLevelEquals(func_str);
261+
bool has_double_equals = hasEqualsEqualsOperator(func_str);
262+
263+
if (equals_pos != std::string::npos || has_double_equals) {
264+
265+
std::string implicit_expr;
266+
267+
if (has_double_equals) {
268+
// Handle == operator
269+
std::string temp_str = func_str;
270+
int depth = 0;
271+
size_t eq_pos = std::string::npos;
272+
273+
for (size_t i = 0; i < temp_str.size() - 1; ++i) {
274+
char c = temp_str[i];
275+
if (c == '(') ++depth;
276+
else if (c == ')') --depth;
277+
else if (depth == 0 && c == '=' && temp_str[i+1] == '=') {
278+
eq_pos = i;
279+
break;
280+
}
281+
}
282+
283+
if (eq_pos != std::string::npos) {
284+
std::string lhs = trim(temp_str.substr(0, eq_pos));
285+
std::string rhs = trim(temp_str.substr(eq_pos + 2)); // +2 to skip ==
286+
implicit_expr = "(" + lhs + ") - (" + rhs + ")";
287+
}
288+
} else {
289+
// Handle = operator
290+
std::string lhs = trim(func_str.substr(0, equals_pos));
291+
std::string rhs = trim(func_str.substr(equals_pos + 1));
292+
implicit_expr = "(" + lhs + ") - (" + rhs + ")";
293+
}
294+
295+
if (!implicit_expr.empty()) {
296+
227297
// setup exprtk with x and y variables
228298
double x = 0.0, y = 0.0;
229299
exprtk::symbol_table<double> symbolTable;
@@ -298,7 +368,8 @@ ExitStatus App::Application::run() {
298368
}
299369
}
300370

301-
plotted = true;
371+
plotted = true;
372+
}
302373
}
303374
}
304375
}

src/core/Core/funcs.hpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,47 @@ static size_t findTopLevelEquals(const std::string& str) {
5656
return std::string::npos;
5757
}
5858

59+
//function to check for == operator specifically
60+
static bool hasEqualsEqualsOperator(const std::string& str) {
61+
int depth = 0;
62+
for (size_t i = 0; i < str.size(); ++i) {
63+
char c = str[i];
64+
65+
if (c == '(') {
66+
++depth;
67+
} else if (c == ')') {
68+
--depth;
69+
} else if (depth == 0) {
70+
if (c == '=' && i + 1 < str.size() && str[i+1] == '=') {
71+
return true;
72+
}
73+
}
74+
}
75+
return false;
76+
}
77+
78+
// function to check if expression contains inequality operators
79+
static bool hasInequalityOperator(const std::string& str) {
80+
int depth = 0;
81+
for (size_t i = 0; i < str.size(); ++i) {
82+
char c = str[i];
83+
84+
if (c == '(') {
85+
++depth;
86+
} else if (c == ')') {
87+
--depth;
88+
} else if (depth == 0) {
89+
// check for <, >, <=, >=, !=
90+
if (c == '<' || c == '>') {
91+
return true;
92+
}
93+
if (c == '!' && i + 1 < str.size() && str[i+1] == '=') {
94+
return true;
95+
}
96+
}
97+
}
98+
return false;
99+
}
100+
59101
#endif // IMGRAPH_FUNCS_HPP
60102

0 commit comments

Comments
 (0)