Skip to content

Commit fe9e057

Browse files
committed
Improve README and add cached points structure
Made-with: Cursor
1 parent 8720bbe commit fe9e057

3 files changed

Lines changed: 78 additions & 15 deletions

File tree

README.md

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,39 @@
11
Plot Genius
2+
==========
23

3-
A cross-platform mathematical function plotting application.
4+
Plot Genius is a fast, crossplatform function plotter built with modern C++ and Qt 6.
45

5-
Features
6+
It is designed as a small, focused desktop tool that feels native on each platform while still showing solid engineering practices under the hood.
67

7-
- Parse and evaluate mathematical expressions
8-
- Interactive graph with pan and zoom
9-
- Multiple equation management
10-
- Graph export (PNG/JPEG)
11-
- Customizable appearance
12-
- Automatic theme detection
8+
Features
9+
--------
10+
- **Math expressions**: Parse and evaluate real‑valued functions of \(x\) (for example `x^2 + 2*x + 1`).
11+
- **Multiple equations**: Add, remove, enable, or disable several curves at once.
12+
- **Interactive graph**: Pan, zoom, and auto‑fit the viewport to all visible equations.
13+
- **Graph export**: Save the current graph as PNG or JPEG.
14+
- **Adaptive theming**: Follows the system theme (with native macOS styling where available).
15+
- **Performance aware**: Caches sampled points and surfaces basic render metrics for repeatable, smooth updates.
1316

14-
Building
17+
Build
18+
-----
1519

1620
Requirements:
1721
- C++17 compiler
1822
- CMake 3.16+
19-
- Qt6 (Core, Widgets, Gui)
23+
- Qt 6 (Core, Widgets, Gui)
24+
25+
Steps:
2026

21-
Build:
2227
```bash
23-
mkdir build && cd build
24-
cmake ..
28+
mkdir build
29+
cd build
30+
cmake .. -DCMAKE_BUILD_TYPE=Release
2531
cmake --build . -j4
2632
```
2733

34+
On success, the executable will be built as `Plot Genius` inside the `build` directory.
35+
2836
License
37+
-------
2938

3039
MIT License

include/graph/graph.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <memory>
1313
#include <vector>
1414
#include <string>
15+
#include <optional>
1516

1617
namespace plot_genius {
1718
namespace graph {
@@ -76,9 +77,19 @@ class Graph {
7677
std::string get_last_error() const { return m_parser.get_last_error(); }
7778

7879
private:
80+
struct PointsCache {
81+
double x_min{};
82+
double x_max{};
83+
int num_points{};
84+
std::vector<std::vector<core::Point>> series;
85+
std::vector<const core::ASTNode*> ast_snapshot;
86+
std::vector<bool> enabled_snapshot;
87+
};
88+
7989
std::vector<Equation> m_equations;
8090
core::Parser m_parser;
8191
Viewport m_viewport;
92+
mutable std::optional<PointsCache> m_points_cache;
8293
};
8394

8495
} // namespace graph

src/graph/graph.cpp

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,31 +23,61 @@ bool Graph::add_equation(const std::string& expression) {
2323
eq.enabled = true;
2424

2525
m_equations.push_back(std::move(eq));
26+
m_points_cache.reset();
2627
return true;
2728
}
2829

2930
void Graph::remove_equation(size_t index) {
3031
if (index < m_equations.size()) {
3132
m_equations.erase(m_equations.begin() + index);
33+
m_points_cache.reset();
3234
}
3335
}
3436

3537
void Graph::clear_all_equations() {
3638
m_equations.clear();
39+
m_points_cache.reset();
3740
}
3841

3942
void Graph::set_equation_enabled(size_t index, bool enabled) {
4043
if (index < m_equations.size()) {
4144
m_equations[index].enabled = enabled;
45+
m_points_cache.reset();
4246
}
4347
}
4448

4549
std::vector<std::vector<core::Point>> Graph::generate_all_points(int num_points) const {
46-
std::vector<std::vector<core::Point>> all_points;
47-
4850
double x_min, x_max, y_min, y_max;
4951
m_viewport.get_range(x_min, x_max, y_min, y_max);
5052

53+
// Reuse cached series when viewport and equation set have not changed.
54+
if (m_points_cache) {
55+
const auto& cache = *m_points_cache;
56+
if (cache.num_points == num_points &&
57+
cache.x_min == x_min &&
58+
cache.x_max == x_max &&
59+
cache.ast_snapshot.size() == m_equations.size() &&
60+
cache.enabled_snapshot.size() == m_equations.size()) {
61+
62+
bool matches = true;
63+
for (std::size_t i = 0; i < m_equations.size(); ++i) {
64+
const auto& eq = m_equations[i];
65+
if (cache.ast_snapshot[i] != eq.ast.get() ||
66+
cache.enabled_snapshot[i] != eq.enabled) {
67+
matches = false;
68+
break;
69+
}
70+
}
71+
72+
if (matches) {
73+
return cache.series;
74+
}
75+
}
76+
}
77+
78+
std::vector<std::vector<core::Point>> all_points;
79+
all_points.reserve(m_equations.size());
80+
5181
for (const auto& eq : m_equations) {
5282
if (eq.enabled && eq.ast) {
5383
auto points = core::Evaluator::generate_points(
@@ -57,6 +87,19 @@ std::vector<std::vector<core::Point>> Graph::generate_all_points(int num_points)
5787
}
5888
}
5989

90+
PointsCache cache;
91+
cache.x_min = x_min;
92+
cache.x_max = x_max;
93+
cache.num_points = num_points;
94+
cache.series = all_points;
95+
cache.ast_snapshot.reserve(m_equations.size());
96+
cache.enabled_snapshot.reserve(m_equations.size());
97+
for (const auto& eq : m_equations) {
98+
cache.ast_snapshot.push_back(eq.ast.get());
99+
cache.enabled_snapshot.push_back(eq.enabled);
100+
}
101+
m_points_cache = std::move(cache);
102+
60103
return all_points;
61104
}
62105

0 commit comments

Comments
 (0)