-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvectors8.nim
More file actions
169 lines (134 loc) · 6.34 KB
/
vectors8.nim
File metadata and controls
169 lines (134 loc) · 6.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# ****************************************************************************************
#
# raylib [vectors] lesson 8 - Graphing Trigonometric Functions
#
# This lesson demonstrates:
# - How to plot sine and cosine functions.
# - The relationship between sin(x) and cos(x).
# - Refactoring drawing code into reusable procedures.
# - Using a generic procedure to plot any mathematical function.
#
# ****************************************************************************************
import raylib
import raymath
import math
import strformat
const
screenWidth = 800
screenHeight = 600
# --- Graphing Helper Types and Procs ---
type
GraphSpace = object
origin: Vector2 # Screen coordinates of the graph's (0,0) point
scale: Vector2 # Pixels per unit for x and y
DisplayMode = enum
ShowSin, ShowCos, ShowBoth
# Function to convert a point from graph space to screen space
proc toScreenSpace(p: Vector2, graph: GraphSpace): Vector2 =
result.x = graph.origin.x + p.x * graph.scale.x
result.y = graph.origin.y - p.y * graph.scale.y # Y is inverted in screen space
# --- Drawing Procedures ---
proc drawGrid(graph: GraphSpace, font: Font) =
# Draw X and Y axes
let xAxisStart = toScreenSpace(Vector2(x: -20, y: 0), graph)
let xAxisEnd = toScreenSpace(Vector2(x: 20, y: 0), graph)
drawLine(xAxisStart, xAxisEnd, 2.0, LightGray)
let yAxisStart = toScreenSpace(Vector2(x: 0, y: -20), graph)
let yAxisEnd = toScreenSpace(Vector2(x: 0, y: 20), graph)
drawLine(yAxisStart, yAxisEnd, 2.0, LightGray)
# Draw unit markers on the axes
for i in -10..10:
if i == 0: continue
# X-axis markers (at PI intervals)
let xMarkerGraph = Vector2(x: i.float * PI, y: 0.1)
let xMarkerScreen = toScreenSpace(xMarkerGraph, graph)
let xMarkerScreenEnd = toScreenSpace(Vector2(x: xMarkerGraph.x, y: -0.1), graph)
drawLine(xMarkerScreen, xMarkerScreenEnd, 2.0, LightGray)
if i mod 2 == 0: # Label every 2*PI
drawText(font, fmt"{i}pi", Vector2(
x: xMarkerScreen.x - 10, y: xMarkerScreen.y + 5), 10.0, 1.0, Gray)
# Y-axis markers
let yMarkerGraph = Vector2(x: 0.1, y: i.float)
let yMarkerScreen = toScreenSpace(yMarkerGraph, graph)
let yMarkerScreenEnd = toScreenSpace(Vector2(x: -0.1, y: yMarkerGraph.y), graph)
drawLine(yMarkerScreen, yMarkerScreenEnd, 2.0, LightGray)
if i != 0:
drawText(font, fmt"{i}", Vector2(
x: yMarkerScreen.x + 5, y: yMarkerScreen.y - 5), 10.0, 1.0, Gray)
proc drawFunction(graph: GraphSpace, color: Color, funcToPlot: proc(x: float32): float32) =
let steps = 400 # More steps for a smoother curve.
let graphWidth = screenWidth.float / graph.scale.x
let startX = -graphWidth / 2.0
for i in 0 ..< steps:
let x1_graph = startX + (i.float / steps.float) * graphWidth
let y1_graph = funcToPlot(x1_graph)
let p1_screen = toScreenSpace(Vector2(x: x1_graph, y: y1_graph), graph)
let x2_graph = startX + ((i+1).float / steps.float) * graphWidth
let y2_graph = funcToPlot(x2_graph)
let p2_screen = toScreenSpace(Vector2(x: x2_graph, y: y2_graph), graph)
drawLine(p1_screen, p2_screen, 2.0, color)
proc drawUI(mode: DisplayMode, font: Font) =
drawText(font, "Trigonometric Visualizer", Vector2(x: 20, y: 20), 40.0, 1.0, DarkGray)
if mode == ShowSin or mode == ShowBoth:
drawText(font, "Function: y = sin(x)", Vector2(x: 20, y: 80), 20.0, 1.0, Red)
if mode == ShowCos or mode == ShowBoth:
drawText(font, "Function: y = cos(x)", Vector2(x: 20, y: 110), 20.0, 1.0, Blue)
drawText(font, "These functions describe wave-like patterns.",
Vector2(x: 20, y: 150), 20.0, 1.0, Gray)
drawText(font, "They are fundamental in describing rotation and oscillation.",
Vector2(x: 20, y: 170), 20.0, 1.0, Gray)
if mode == ShowBoth:
drawText(font, "Notice that cos(x) is the same as sin(x), but shifted to " &
"the left by pi/2.", Vector2(x: 20, y: 200), 20.0, 1.0, Gray)
drawText(font, "The x-axis markers are placed at intervals of pi.",
Vector2(x: 20, y: 230), 20.0, 1.0, Gray)
drawText(font, "Press [Space] to cycle through views.",
Vector2(x: 20, y: screenHeight - 40), 20.0, 1.0, LightGray)
proc main =
initWindow(screenWidth, screenHeight, "raylib [vectors] lesson 8 - Trigonometric Functions")
setTargetFPS(60)
# Define the graph space.
# We want to see the waves, so we scale Y more than X.
# X scale is set so we can see a few cycles (e.g., -2π to 2π).
let graph = GraphSpace(
origin: Vector2(x: screenWidth / 2.0, y: screenHeight / 2.0),
scale: Vector2(x: 50.0, y: 150.0) # 50 pixels per 1 unit on X, 150 on Y
)
let font = getFontDefault()
var currentMode = ShowSin
# Main game loop
# --------------------------------------------------------------------------------------
while not windowShouldClose():
# Update
# ----------------------------------------------------------------------------------
if isKeyPressed(Space):
# Cycle through the display modes: ShowSin -> ShowCos -> ShowBoth -> ShowSin
currentMode = cast[DisplayMode]((currentMode.ord + 1) mod (DisplayMode.high.ord + 1))
# Draw
# ------------------------------------------------------------------------------------
beginDrawing()
clearBackground(RayWhite)
drawGrid(graph, font)
# Draw the functions
if currentMode == ShowSin or currentMode == ShowBoth:
drawFunction(graph, Red, sin)
if currentMode == ShowCos or currentMode == ShowBoth:
drawFunction(graph, Blue, cos)
# Pass the loaded font to the UI drawing procedure
drawUI(currentMode, font)
endDrawing()
# ------------------------------------------------------------------------------------
# De-Initialization
# --------------------------------------------------------------------------------------
closeWindow()
# --------------------------------------------------------------------------------------
main()
#[
This lesson shows how to plot continuous functions like sin and cos.
Key takeaways:
- A generic `drawFunction` procedure can plot any `proc(x: float32): float32`,
making it highly reusable.
- Adjusting the `graph.scale` is crucial for getting a good view of the function.
Here, the Y-axis is "stretched" to make the -1 to 1 range of sin/cos clearly visible.
- The relationship between sin and cos (a phase shift of π/2) becomes visually obvious.
]#