mirror of
https://github.com/BoredDevNL/BoredOS.git
synced 2026-05-15 18:58:40 +00:00
DOCS: math.h
This commit is contained in:
parent
f0c2963793
commit
c330382436
3 changed files with 387 additions and 1 deletions
|
|
@ -30,5 +30,6 @@ The SDK and toolchain guides for creating your own `.elf` userland binaries.
|
|||
- [`Widget API`](appdev/widget_api.md): High-level UI components like buttons, textboxes, and scrollbars using `libwidget.h`.
|
||||
- [`Custom Apps`](appdev/custom_apps.md): A step-by-step tutorial on writing a new graphical C application, editing the Makefile, and bundling it into the ISO.
|
||||
- [`Example Apps`](appdev/examples/README.md): A collection of sample C applications ranging from basic terminal output to advanced TCP networking.
|
||||
- [`Grapher`](appdev/grapher.md): Full reference for the built-in mathematical graphing application — equation syntax, keyboard controls, architecture, and configuration.
|
||||
|
||||
---
|
||||
|
|
|
|||
330
docs/appdev/grapher.md
Normal file
330
docs/appdev/grapher.md
Normal file
|
|
@ -0,0 +1,330 @@
|
|||
<div align="center">
|
||||
<h1>Grapher</h1>
|
||||
<p><em>An interactive mathematical expression plotter for BoredOS, supporting both 2D and 3D visualizations.</em></p>
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
Grapher is a built-in GUI application that lets you type any mathematical equation and see it plotted in real time. It supports 2D explicit and implicit curves as well as full 3D surface visualization — including both explicit surfaces (`z = f(x, y)`) and implicit surfaces (`f(x, y, z) = c`).
|
||||
|
||||
> [!NOTE]
|
||||
> Grapher is located at `src/userland/gui/grapher.c`. It runs as a standard BoredOS GUI process and can be launched from the terminal or from the dock.
|
||||
|
||||
---
|
||||
|
||||
## Features at a Glance
|
||||
|
||||
| Feature | Details |
|
||||
|---|---|
|
||||
| **2D Explicit** | Plot `y = f(x)` curves |
|
||||
| **2D Implicit** | Plot any `f(x, y) = g(x, y)` contour via marching squares |
|
||||
| **3D Explicit** | Plot `z = f(x, y)` surfaces |
|
||||
| **3D Implicit** | Plot `f(x, y, z) = c` surfaces via Z-axis root finding (has rendering issues in filled mode)|
|
||||
| **Rendering modes** | Wireframe and filled polygon modes |
|
||||
| **Height coloring** | Surfaces are colored by a blue→green→yellow→red gradient based on Z height |
|
||||
| **Phong-style shading** | Filled mode computes per-face normals and applies diffuse + ambient lighting |
|
||||
| **Parallel rendering** | Evaluation and projection are distributed across 4 worker threads via `sys_parallel_run` |
|
||||
| **Preset equations** | 7 built-in presets accessible from the toolbar |
|
||||
| **Auto-fit** | 2D view auto-fits the Y axis to the plotted curve on first plot |
|
||||
| **Z-buffer** | All 3D drawing uses a per-pixel depth buffer with atomic CAS for thread safety |
|
||||
|
||||
---
|
||||
|
||||
## Launching Grapher
|
||||
|
||||
From the BoredOS terminal:
|
||||
```sh
|
||||
grapher
|
||||
```
|
||||
|
||||
Or click the **Grapher icon** in the system dock.
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
### Toolbar Controls
|
||||
|
||||
| Control | Function |
|
||||
|---|---|
|
||||
| **Equation box** | Type your mathematical expression, then press **Enter** or **Plot** |
|
||||
| **Plot button** | Parse and render the current equation |
|
||||
| **Wire / Filled button** | Toggle wireframe vs. shaded polygon mode (3D only) |
|
||||
| **Presets button** | Open a dropdown of example equations |
|
||||
|
||||
### Status Bar Controls (3D mode)
|
||||
|
||||
| Control | Function |
|
||||
|---|---|
|
||||
| **`+` button** | Increase the 3D world range (zoom out in world space) |
|
||||
| **`-` button** | Decrease the 3D world range (zoom in in world space) |
|
||||
|
||||
---
|
||||
|
||||
## Keyboard Shortcuts
|
||||
|
||||
| Shortcut | Action |
|
||||
|---|---|
|
||||
| **Enter** (in equation box) | Plot the equation |
|
||||
| **Ctrl + R** | Reset the view to defaults |
|
||||
| **F** | Toggle filled / wireframe rendering (3D mode) |
|
||||
| **Scroll wheel** | Zoom in/out (2D mode adjusts viewport; 3D mode adjusts camera zoom) |
|
||||
| **Right-click drag** | Rotate the 3D surface |
|
||||
|
||||
---
|
||||
|
||||
## Writing Equations
|
||||
|
||||
Grapher parses equations entered as plain text. It supports a subset of mathematical notation with automatic implicit multiplication.
|
||||
|
||||
### Supported Functions
|
||||
|
||||
| Syntax | Meaning |
|
||||
|---|---|
|
||||
| `sin(x)` | Sine |
|
||||
| `cos(x)` | Cosine |
|
||||
| `tan(x)` | Tangent |
|
||||
| `sqrt(x)` | Square root |
|
||||
| `abs(x)` | Absolute value |
|
||||
| `log(x)` | Natural logarithm (base *e*) |
|
||||
|
||||
### Supported Operators
|
||||
|
||||
| Operator | Meaning |
|
||||
|---|---|
|
||||
| `+` `-` `*` `/` | Arithmetic |
|
||||
| `^` | Exponentiation (right-associative) |
|
||||
| `(` `)` | Grouping |
|
||||
|
||||
### Special Values
|
||||
|
||||
| Token | Value |
|
||||
|---|---|
|
||||
| `pi` or `PI` | π ≈ 3.14159… |
|
||||
|
||||
### Implicit Multiplication
|
||||
|
||||
Adjacent tokens that would normally require a `*` are multiplied automatically:
|
||||
|
||||
```
|
||||
2x → 2 * x
|
||||
3sin(x) → 3 * sin(x)
|
||||
(x+1)(x) → (x+1) * x
|
||||
```
|
||||
|
||||
### How Equations Are Classified
|
||||
|
||||
Grapher looks at which variables appear in your equation to automatically choose the rendering mode:
|
||||
|
||||
| Equation form | Auto-detected as |
|
||||
|---|---|
|
||||
| `y = f(x)` or just `f(x)` | 2D explicit |
|
||||
| `f(x, y) = g(x, y)` | 2D implicit |
|
||||
| `z = f(x, y)` | 3D explicit |
|
||||
| `f(x, y, z) = c` | 3D implicit |
|
||||
|
||||
If you omit the `=` sign, Grapher treats the input as `y = <expression>` when no `y` or `z` is present, or as `<expression> = 0` otherwise.
|
||||
|
||||
---
|
||||
|
||||
## Example Equations
|
||||
|
||||
### 2D Examples
|
||||
|
||||
```
|
||||
y = sin(x)
|
||||
y = x^2
|
||||
y = cos(x)*x
|
||||
y = abs(x) - 2
|
||||
x^2 + y^2 = 25 ← circle (implicit)
|
||||
y = log(x)
|
||||
```
|
||||
|
||||
### 3D Explicit Examples
|
||||
|
||||
```
|
||||
z = sin(x)*cos(y)
|
||||
z = x^2 - y^2 ← saddle surface
|
||||
z = sqrt(25 - x^2 - y^2)
|
||||
```
|
||||
|
||||
### 3D Implicit Examples
|
||||
|
||||
```
|
||||
x^2 + y^2 + z^2 = 25 ← sphere
|
||||
x^2 + y^2 = 16 ← cylinder
|
||||
x^2 + y^2 - z^2 = 1 ← hyperboloid
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Navigation Controls
|
||||
|
||||
### 2D Mode
|
||||
|
||||
| Input | Action |
|
||||
|---|---|
|
||||
| **Scroll up** | Zoom in |
|
||||
| **Scroll down** | Zoom out |
|
||||
| **Ctrl+R** | Reset to default view (`x: [-10, 10]`) |
|
||||
|
||||
### 3D Mode
|
||||
|
||||
| Input | Action |
|
||||
|---|---|
|
||||
| **Right-click drag** | Rotate the surface (orbit camera) |
|
||||
| **Scroll up** | Zoom camera in |
|
||||
| **Scroll down** | Zoom camera out |
|
||||
| **`+` / `-` buttons** | Increase / decrease world range |
|
||||
| **Ctrl+R** | Reset rotation and zoom |
|
||||
|
||||
> [!TIP]
|
||||
> In 3D mode, the surface auto-rotates slowly by default. This can be disabled by setting `#define ROTATE 0` in the source file.
|
||||
|
||||
---
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
Grapher is implemented as a single self-contained C file. Below is a high-level breakdown of its major components:
|
||||
|
||||
### Math Library
|
||||
|
||||
Grapher uses the BoredOS freestanding **`libc/math.h`** library, which provides all the math functions it needs without depending on a host standard library:
|
||||
|
||||
| Function | Description |
|
||||
|---|---|
|
||||
| `sin`, `cos`, `tan` | Trigonometry via Taylor series (8 terms, range-reduced to `[-π, π]`) |
|
||||
| `sqrt` | Newton-Raphson iteration (25 steps) |
|
||||
| `log` | Natural logarithm via Padé-style series |
|
||||
| `log2`, `log10` | Derived from `log` |
|
||||
| `exp` | Range-reduced Taylor series for `e^x` |
|
||||
| `pow` | Integer exponents use fast binary exponentiation; fractional exponents use `exp(e * log(b))` |
|
||||
| `fabs`, `fmod` | Absolute value and floating-point remainder |
|
||||
| `floor`, `ceil` | Rounding |
|
||||
| `sinh`, `cosh`, `tanh` | Hyperbolic functions |
|
||||
| `hypot`, `fmin`, `fmax`, `fclamp` | Utility helpers |
|
||||
|
||||
The constants `M_PI`, `M_E`, `M_LN2`, `M_SQRT2` are also defined in the header.
|
||||
|
||||
This library is automatically linked into every userland ELF — any app can `#include "math.h"` to use it.
|
||||
|
||||
### Expression Parser
|
||||
|
||||
Equations are parsed in three stages:
|
||||
|
||||
1. **Tokenizer** (`tokenize`) — converts the input string into a flat token array. Handles implicit multiplication by inserting `*` tokens where needed.
|
||||
2. **Recursive Descent Parser** (`parse_expr`, `parse_term`, `parse_power`, `parse_unary`, `parse_atom`) — produces an Abstract Syntax Tree (AST) with up to `MAX_NODES = 128` nodes.
|
||||
3. **Bytecode Compiler** (`compile_ast`) — walks the AST in post-order and emits a flat instruction sequence for a simple stack machine. This avoids recursive evaluation during rendering hot paths.
|
||||
|
||||
The resulting bytecode is then executed by `run_bc` for every sample point.
|
||||
|
||||
### Rendering Pipeline
|
||||
|
||||
#### 2D Rendering
|
||||
|
||||
- **Explicit** — evaluates `y = f(x)` at every pixel column and connects adjacent samples with Bresenham lines.
|
||||
- **Implicit** — applies **marching squares** on a 200×130 grid to find sign changes in `f(x,y) - g(x,y)` and plots intersection pixels.
|
||||
|
||||
#### 3D Rendering
|
||||
|
||||
The 3D pipeline is a three-pass system, each parallelised across 4 threads:
|
||||
|
||||
| Pass | Function | Description |
|
||||
|---|---|---|
|
||||
| 1 | **Evaluation** | Samples the surface at every grid point in a `GRID_3D × GRID_3D` grid |
|
||||
| 2 | **Projection** | Projects 3D world coordinates to 2D screen coordinates with perspective |
|
||||
| 3 | **Drawing** | Rasterizes wireframe lines or filled triangles with Z-buffering |
|
||||
|
||||
For **implicit surfaces**, Pass 1 additionally marches along the Z axis at 512 steps per column using bisection (15 iterations) to find up to `MAX_Z_PER_POINT = 4` roots.
|
||||
|
||||
Surface normals are estimated using central finite differences of the implicit function.
|
||||
|
||||
#### Filled Mod
|
||||
|
||||
When filled mode is active, each quad cell is split into two triangles. The average surface normal across the four corner vertices is computed and fed into `apply_shading`, which calculates:
|
||||
|
||||
```
|
||||
intensity = ambient(0.3) + diffuse(0.7) * dot(normal, light_direction)
|
||||
```
|
||||
|
||||
The light direction is fixed at `(0.577, 0.707, 0.408)` (normalized diagonal).
|
||||
|
||||
#### Z-Buffer
|
||||
|
||||
The depth buffer (`graph_zb`) stores integer depth values. `gfb_pixel_z` uses a **compare-and-swap (CAS) loop** via `__atomic_compare_exchange_n` so multiple parallel draw threads cannot produce race conditions.
|
||||
|
||||
### Coordinate Systems
|
||||
|
||||
#### 2D
|
||||
|
||||
World coordinates map linearly to screen pixels:
|
||||
|
||||
```c
|
||||
screen_x = (wx - view_x_min) / (view_x_max - view_x_min) * graph_w
|
||||
screen_y = (view_y_max - wy) / (view_y_max - view_y_min) * graph_h
|
||||
```
|
||||
|
||||
#### 3D
|
||||
|
||||
Points are first rotated by two Euler angles (`rot_y`, `rot_x`) then projected with a simple perspective divide:
|
||||
|
||||
```
|
||||
persp = d / (pz + d) // d = range_3d * 5
|
||||
sx = px * scale * persp + screen_cx
|
||||
sy = -py * scale * persp + screen_cy
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Configuration Constants
|
||||
|
||||
These can be changed at the top of `grapher.c` to tune behaviour:
|
||||
|
||||
| Constant | Default | Effect |
|
||||
|---|---|---|
|
||||
| `ROTATE` | `1` | Set to `0` to disable auto-rotation in 3D mode |
|
||||
| `GRID_3D` | `256` | Grid resolution for 3D sampling. Higher = more detail, much slower |
|
||||
|
||||
> [!WARNING]
|
||||
> Setting `GRID_3D` too high (e.g. 9000) will exhaust available memory. The `surf` grid and `surf_x`/`surf_y_3d` arrays are statically allocated at compile time: memory usage grows as **O(GRID_3D²)**. Values above ~512 are not recommended.
|
||||
|
||||
> [!TIP]
|
||||
> `GRID_3D = 256` gives a good balance of detail and performance on typical BoredOS hardware emulation.
|
||||
|
||||
---
|
||||
|
||||
## Color Palette
|
||||
|
||||
|
||||
3D surfaces are colored by height using a 4-stop rainbow ramp:
|
||||
|
||||
```
|
||||
Low → Blue → Cyan → Green → Yellow → Red → High
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Preset Equations
|
||||
|
||||
The built-in presets are shown in the dropdown when you click **Presets**:
|
||||
|
||||
| Label | Type |
|
||||
|---|---|
|
||||
| `y = sin(x)` | 2D explicit |
|
||||
| `y = x^2` | 2D explicit |
|
||||
| `y = cos(x)*x` | 2D explicit |
|
||||
| `z = sin(x)*cos(y)` | 3D explicit |
|
||||
| `z = x^2 - y^2` | 3D explicit |
|
||||
| `x^2+y^2+z^2=25` | 3D implicit (sphere) |
|
||||
| `x^2+y^2=16` | 3D implicit (cylinder) |
|
||||
|
||||
---
|
||||
|
||||
## Known Limitations
|
||||
|
||||
- **No parameter slider** — equations are static; there is no way to animate a parameter.
|
||||
- **No multiple equations** — only one equation can be graphed at a time.
|
||||
- **Implicit surface gaps** — very thin or high-frequency implicit surfaces may have small gaps due to the fixed Z marching step count (512 steps per column).
|
||||
- **3D implicit performance** — implicit surfaces require significantly more work than explicit ones; evaluating `x^2+y^2+z^2=25` at `GRID_3D=256` takes a noticeable fraction of a second.
|
||||
- **Integer axis labels only for large values** — very large axis values are capped at `>2G` or `<-2G` due to `itoa` limitations.
|
||||
- **3D polygon implicit mode** - 3D polygon implicit mode has problems with connecting hemispheres of a circle causing for dead space on the equator.
|
||||
|
|
@ -8,6 +8,8 @@
|
|||
BoredOS provides a custom `libc` implementation necessary for writing userland applications (`.elf` binaries). By avoiding a full-blown standard library like `glibc`, the OS ensures a minimal executable footprint tailored strictly to the existing kernel features.
|
||||
|
||||
All headers are located in `src/userland/libc/` (standard functions) and `src/wm/` (UI and widgets).
|
||||
- `stdlib.h`: Memory, strings, and basic I/O.
|
||||
- `math.h`: Freestanding floating-point math library.
|
||||
- `libui.h`: Core window and drawing API.
|
||||
- `libwidget.h`: High-level UI components.
|
||||
|
||||
|
|
@ -47,7 +49,60 @@ The standard library wrappers provide memory management, string manipulation, an
|
|||
|
||||
---
|
||||
|
||||
## System Calls (`syscall.h`)
|
||||
## Math Library (`math.h`)
|
||||
|
||||
BoredOS ships a freestanding floating-point math library in `libc/math.h`. It uses pure arithmetic — Taylor series, Newton-Raphson, and range-reduction — with no dependency on a host `libm` or hardware math intrinsics. It is automatically linked into every userland ELF.
|
||||
|
||||
```c
|
||||
#include "math.h"
|
||||
```
|
||||
|
||||
### Constants
|
||||
|
||||
| Constant | Value | Description |
|
||||
|---|---|---|
|
||||
| `M_PI` | 3.14159… | π |
|
||||
| `M_E` | 2.71828… | Euler's number |
|
||||
| `M_LN2` | 0.69315… | Natural log of 2 |
|
||||
| `M_SQRT2` | 1.41421… | √2 |
|
||||
| `HUGE_VAL` | ~+∞ | Overflow sentinel |
|
||||
|
||||
### Functions
|
||||
|
||||
#### Absolute value & remainder
|
||||
* `double fabs(double x);` — Absolute value.
|
||||
* `double fmod(double x, double y);` — Floating-point remainder. Returns `0` when `y == 0`.
|
||||
|
||||
#### Rounding
|
||||
* `double floor(double x);` — Largest integer ≤ x.
|
||||
* `double ceil(double x);` — Smallest integer ≥ x.
|
||||
|
||||
#### Trigonometry *(arguments in radians)*
|
||||
* `double sin(double x);` — Sine. Range-reduced to `[-π, π]` then computed via 8-term Taylor series.
|
||||
* `double cos(double x);` — Cosine. Computed via `sin(x + π/2)`.
|
||||
* `double tan(double x);` — Tangent. Returns sentinel `1e15` near poles.
|
||||
|
||||
#### Exponential & logarithm
|
||||
* `double sqrt(double x);` — Square root via Newton-Raphson (25 iterations). Returns `0` for `x ≤ 0`.
|
||||
* `double log(double x);` — Natural logarithm (ln). Returns `-1e30` for `x ≤ 0`.
|
||||
* `double log2(double x);` — Base-2 logarithm.
|
||||
* `double log10(double x);` — Base-10 logarithm.
|
||||
* `double exp(double x);` — e^x. Saturates to `1e300` for `x > 700`, `0` for `x < -700`.
|
||||
* `double pow(double base, double exponent);` — General power. Integer exponents use fast binary exponentiation; fractional exponents use `exp(e * log(b))`.
|
||||
|
||||
#### Hyperbolic
|
||||
* `double sinh(double x);` — Hyperbolic sine.
|
||||
* `double cosh(double x);` — Hyperbolic cosine.
|
||||
* `double tanh(double x);` — Hyperbolic tangent.
|
||||
|
||||
#### Utility
|
||||
* `double hypot(double x, double y);` — `sqrt(x² + y²)` without intermediate overflow.
|
||||
* `double fmin(double a, double b);` — Minimum of two values.
|
||||
* `double fmax(double a, double b);` — Maximum of two values.
|
||||
* `double fclamp(double x, double lo, double hi);` — Clamps `x` into `[lo, hi]`.
|
||||
|
||||
> [!NOTE]
|
||||
> The implementation file is named `libc/libmath.c` (not `libc/math.c`) to avoid a name collision with the `math` CLI calculator app in userland. The public header is still included as `#include "math.h"`.
|
||||
|
||||
For advanced operations, `syscall.h` provides direct wrappers into the kernel.
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue