fixed the issue of entire Y-axis being plotted due to an overflow error
This commit is contained in:
		
							
								
								
									
										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