fixed the issue of entire Y-axis being plotted due to an overflow error
This commit is contained in:
parent
71e22ebaae
commit
fcff945372
56
src/main.zig
56
src/main.zig
@ -17,20 +17,21 @@ pub fn main() !void {
|
|||||||
defer rl.closeWindow();
|
defer rl.closeWindow();
|
||||||
|
|
||||||
rl.setTargetFPS(60);
|
rl.setTargetFPS(60);
|
||||||
|
|
||||||
// todo move away from being a loop, a static trigonometry should not be redrawn every frame
|
|
||||||
rl.beginDrawing();
|
rl.beginDrawing();
|
||||||
|
|
||||||
rl.clearBackground(rl.Color.white);
|
rl.clearBackground(rl.Color.white);
|
||||||
|
|
||||||
try markAxis(allocator);
|
|
||||||
plotGraph();
|
plotGraph();
|
||||||
drawAxis();
|
drawAxis();
|
||||||
|
try markAxis(allocator);
|
||||||
|
|
||||||
rl.endDrawing();
|
rl.endDrawing();
|
||||||
|
|
||||||
while (!rl.windowShouldClose()) {
|
while (!rl.windowShouldClose()) {
|
||||||
rl.beginDrawing();
|
rl.beginDrawing();
|
||||||
|
// DEBUG
|
||||||
|
// const pos = rl.getMousePosition();
|
||||||
|
// std.debug.print("x: {d} y:{}\n", .{ pos.x, pos.y });
|
||||||
rl.endDrawing();
|
rl.endDrawing();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -55,7 +56,7 @@ fn markAxis(allocator: std.mem.Allocator) !void {
|
|||||||
var cnt: usize = 0;
|
var cnt: usize = 0;
|
||||||
var i: i32 = start_x;
|
var i: i32 = start_x;
|
||||||
while (i <= SCREENWIDTH) : (i += SCALE) {
|
while (i <= SCREENWIDTH) : (i += SCALE) {
|
||||||
// get
|
// int to string
|
||||||
const text = try std.fmt.bufPrintZ(&buf, "{}", .{cnt});
|
const text = try std.fmt.bufPrintZ(&buf, "{}", .{cnt});
|
||||||
cnt += 1;
|
cnt += 1;
|
||||||
// 0 is due to us working with C-style strings
|
// 0 is due to us working with C-style strings
|
||||||
@ -75,17 +76,30 @@ fn markAxis(allocator: std.mem.Allocator) !void {
|
|||||||
rl.drawText(text_back, SCREENWIDTH - i - diff - diff / 2, start_y + diff, font_size, rl.Color.black);
|
rl.drawText(text_back, SCREENWIDTH - i - diff - diff / 2, start_y + diff, font_size, rl.Color.black);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// start at 1 as we're not drawing 0 this time
|
||||||
|
cnt = 1;
|
||||||
i = start_y;
|
i = start_y;
|
||||||
while (i <= SCREENHEIGHT) : (i += SCALE) {
|
while (i <= SCREENHEIGHT) : (i += SCALE) {
|
||||||
// +y
|
// skip 0 as it is already rendered during x scale
|
||||||
rl.drawCircle(start_x, @intCast(i), radius, rl.Color.black);
|
if (i == start_y) continue;
|
||||||
|
|
||||||
|
const text = try std.fmt.bufPrintZ(&buf, "{}", .{cnt});
|
||||||
|
cnt += 1;
|
||||||
|
var text_back = try allocator.allocSentinel(u8, text.len + 1, 0);
|
||||||
|
defer allocator.free(text_back);
|
||||||
|
@memcpy(text_back[0..1], "-");
|
||||||
|
@memcpy(text_back[1..], text);
|
||||||
|
|
||||||
// -y
|
// -y
|
||||||
|
rl.drawCircle(start_x, @intCast(i), radius, rl.Color.black);
|
||||||
|
rl.drawText(text_back, start_x + diff, @as(i32, @intCast(i)) - diff, font_size, rl.Color.black);
|
||||||
|
|
||||||
|
// +y
|
||||||
rl.drawCircle(start_x, SCREENHEIGHT - i, radius, rl.Color.black);
|
rl.drawCircle(start_x, SCREENHEIGHT - i, radius, rl.Color.black);
|
||||||
|
rl.drawText(text, start_x + diff, SCREENHEIGHT - i - diff, font_size, rl.Color.black);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo in the future we will do calculations only once and just repeat displaying
|
|
||||||
fn plotGraph() void {
|
fn plotGraph() void {
|
||||||
const diff: f32 = 0.01;
|
const diff: f32 = 0.01;
|
||||||
const thickness = 2.5;
|
const thickness = 2.5;
|
||||||
@ -94,36 +108,36 @@ fn plotGraph() void {
|
|||||||
while (x_value <= SCREENWIDTH) : (x_value += diff) {
|
while (x_value <= SCREENWIDTH) : (x_value += diff) {
|
||||||
const cur_pos = adjustForGridSystem(rl.Vector2{
|
const cur_pos = adjustForGridSystem(rl.Vector2{
|
||||||
.x = x_value,
|
.x = x_value,
|
||||||
.y = getY(x_value),
|
.y = getY(x_value) catch {
|
||||||
|
continue;
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// this is to ensure the value doesn't wrap around to zero causing the entire Y-axis to be graphed
|
||||||
|
if (cur_pos.y > SCREENHEIGHT) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const next_pos = adjustForGridSystem(rl.Vector2{
|
const next_pos = adjustForGridSystem(rl.Vector2{
|
||||||
.x = x_value + diff,
|
.x = x_value + diff,
|
||||||
.y = getY(x_value + diff),
|
.y = getY(x_value + diff) catch {
|
||||||
|
continue;
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// test
|
|
||||||
if (cur_pos.x == 0 or next_pos.x == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
rl.drawLineEx(cur_pos, next_pos, thickness, rl.Color.dark_blue);
|
rl.drawLineEx(cur_pos, next_pos, thickness, rl.Color.dark_blue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// f(x)
|
// f(x)
|
||||||
fn getY(x: f32) f32 {
|
fn getY(x: f32) !f32 {
|
||||||
const min_threshold = 1e-3;
|
return math.calculate(x, -3, .Power);
|
||||||
const a = x / 10;
|
|
||||||
var b: f32 = 1.0;
|
|
||||||
if (b == 0) b = a / min_threshold;
|
|
||||||
|
|
||||||
return a / b;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn adjustForGridSystem(input_vector: rl.Vector2) rl.Vector2 {
|
fn adjustForGridSystem(input_vector: rl.Vector2) rl.Vector2 {
|
||||||
// std.debug.print("{d} => {d}\n", .{ input_vector.x, input_vector.x * SCALE });
|
// std.debug.print("{d} => {d}\n", .{ input_vector.x, input_vector.x * SCALE });
|
||||||
const new_vector = rl.Vector2{
|
const new_vector = rl.Vector2{
|
||||||
|
// we add screenwidth because in traditional gui libraries the grid starts in top left and not in the center like the coordinate system
|
||||||
.x = input_vector.x * SCALE + SCREENWIDTH / 2,
|
.x = input_vector.x * SCALE + SCREENWIDTH / 2,
|
||||||
.y = -input_vector.y * SCALE + SCREENHEIGHT / 2, // minus is there because y works the opposite in gui libraries than in coordination system
|
.y = -input_vector.y * SCALE + SCREENHEIGHT / 2, // minus is there because y works the opposite in gui libraries than in coordination system
|
||||||
};
|
};
|
||||||
|
36
src/math.zig
36
src/math.zig
@ -1,4 +1,36 @@
|
|||||||
pub fn abs(a: f32) f32 {
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub const MathOperation = enum {
|
||||||
|
Division,
|
||||||
|
Power,
|
||||||
|
Root,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn calculate(first: f32, second: f32, op: MathOperation) !f32 {
|
||||||
|
switch (op) {
|
||||||
|
.Division => {
|
||||||
|
if (second == 0) {
|
||||||
|
return error.InvalidParam;
|
||||||
|
}
|
||||||
|
return first / second;
|
||||||
|
},
|
||||||
|
.Power => {
|
||||||
|
if (first == 0) std.debug.print("KOK", .{});
|
||||||
|
if (first == 0 and second < 0) {
|
||||||
|
return error.InvalidParam;
|
||||||
|
}
|
||||||
|
return pow(first, @intFromFloat(second));
|
||||||
|
},
|
||||||
|
.Root => {
|
||||||
|
if (first < 0 or second < 0) {
|
||||||
|
return error.InvalidParam;
|
||||||
|
}
|
||||||
|
return std.math.sqrt(second);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn abs(a: f32) f32 {
|
||||||
if (a < 0) {
|
if (a < 0) {
|
||||||
return -a;
|
return -a;
|
||||||
}
|
}
|
||||||
@ -6,7 +38,7 @@ pub fn abs(a: f32) f32 {
|
|||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pow(a: f32, b: i32) f32 {
|
fn pow(a: f32, b: i32) f32 {
|
||||||
var res: f32 = 1.0;
|
var res: f32 = 1.0;
|
||||||
var n: usize = undefined;
|
var n: usize = undefined;
|
||||||
var f: f32 = undefined;
|
var f: f32 = undefined;
|
||||||
|
Reference in New Issue
Block a user