-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathFractalGeneration
261 lines (221 loc) · 10.2 KB
/
FractalGeneration
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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
#lang racket
;; === Required Libraries ===
(require racket/draw)
(require racket/gui/base)
(require racket/string)
(require racket/place)
(require racket/future)
;; === Constants ===
(define imageWidth 1920) ; Width of each frame in pixels
(define imageHeight 1080) ; Height of each frame in pixels
(define output-dir "cactus_output") ; Directory to save generated frames
(define MIN-SCALE-FRACTION 0.0001) ; Fraction of visible width for min-detail-size (smaller for deeper recursion)
(define INITIAL-SCALE 20.0) ; Initial scale of the fractal
(define TOTAL-FRAMES 600) ; Total number of frames to generate
(define FRAME-RATE 30) ; Frames per second for the video
(define ZOOM-SPEED 1.01) ; Zoom factor per frame
(define COLOR_SHIFT_SPEED 0.001) ; Speed at which colors shift per frame
;; === Structures ===
(struct target-point (x y size) #:transparent)
(struct rectangle (left top right bottom) #:transparent)
;; === Globals ===
(define smallest-point (box #f))
(define total-polygon-count 0)
;; === Helper Functions ===
;; Function to zero-pad frame numbers (e.g., 1 -> "0001")
(define (zero-pad num width)
(let ([str (number->string num)])
(string-append (make-string (max 0 (- width (string-length str))) #\0) str)))
;; Function to check if a point is within a rectangle
(define (rectangle-contains-point? rect x y)
(and (<= (rectangle-left rect) x (rectangle-right rect))
(<= (rectangle-top rect) y (rectangle-bottom rect))))
;; Function to perform a quick visibility check
(define (quick-visibility-check x y size visible-area)
(define expanded-rect
(rectangle
(- (rectangle-left visible-area) size)
(- (rectangle-top visible-area) size)
(+ (rectangle-right visible-area) size)
(+ (rectangle-bottom visible-area) size)))
(rectangle-contains-point? expanded-rect x y))
;; Function to generate hexagon points
(define (generate-hexagon-points x y size angle)
(for/list ([i (in-range 6)])
(define point-angle (+ angle (* i (/ (* 2 pi) 6))))
(cons (+ x (* size (cos point-angle)))
(+ y (* size (sin point-angle))))))
;; Function to convert HSV to RGB (returns exact integers)
(define (hsv->rgb h s v)
(define h-sector (* 6 h))
(define sector (floor h-sector))
(define fractional (- h-sector sector))
(define p (* v (- 1 s)))
(define q (* v (- 1 (* s fractional))))
(define t (* v (- 1 (* s (- 1 fractional)))))
(define color-case (cond
[(= sector 0) (list v t p)]
[(= sector 1) (list q v p)]
[(= sector 2) (list p v t)]
[(= sector 3) (list p q v)]
[(= sector 4) (list t p v)]
[(= sector 5) (list v p q)]
[else (list 0 0 0)])) ; Fallback to black
;; Ensure exact integers are returned
(map (λ (c) (exact-round (* 255 c))) color-case))
;; Function to compute fill color based on level and frame number - FIXED VERSION
(define (compute-fill-color level frame-num total-frames)
;; Assign a base hue based on the recursion level
;; Base hues are spaced evenly around the color wheel
(define base-hue (/ level 10.0)) ; Adjust divisor for desired color spacing
;; Apply a dynamic shift based on the frame number
(define dynamic-shift (* frame-num COLOR_SHIFT_SPEED))
;; Combine base hue and dynamic shift, ensuring it wraps around [0,1)
(define hue (- (+ base-hue dynamic-shift)
(floor (+ base-hue dynamic-shift)))) ; Fixed floating-point wrap
(define saturation 1.0)
(define value 1.0)
(define rgb (hsv->rgb hue saturation value))
(make-color
(list-ref rgb 0) ; Red component
(list-ref rgb 1) ; Green component
(list-ref rgb 2))) ; Blue component
;; Function to draw a filled hexagon
(define (draw-filled-hexagon dc x y size angle color visible-left visible-top visible-width visible-height)
(define points (generate-hexagon-points x y size angle))
(define mapped-points
(for/list ([pt points])
(define x_w (car pt))
(define y_w (cdr pt))
;; Map world coordinates to screen coordinates
(define x_s (* (- x_w visible-left) (/ imageWidth visible-width)))
(define y_s (* (- y_w visible-top) (/ imageHeight visible-height)))
(cons x_s y_s)))
(send dc set-brush color 'solid)
(send dc set-pen "black" 0.5 'solid)
(send dc draw-polygon mapped-points))
;; Function to update the smallest point found (optional for debugging)
(define (update-smallest-point! x y size smallest-point-box)
(when (< size (or (and (unbox smallest-point-box) (target-point-size (unbox smallest-point-box))) +inf.0))
(set-box! smallest-point-box (target-point x y size))))
;; === Fractal Drawing Functions ===
;; Recursive function to draw the fractal with level tracking
(define (draw-fractal dc x y size angle visible-area min-detail-size frame-num total-frames level)
;; Termination condition based on size
(when (>= size min-detail-size)
;; Compute dynamic fill color based on level and frame number
(define fill-color (compute-fill-color level frame-num total-frames))
(draw-filled-hexagon dc x y (/ size 2) angle fill-color
(rectangle-left visible-area)
(rectangle-top visible-area)
(- (rectangle-right visible-area) (rectangle-left visible-area))
(- (rectangle-bottom visible-area) (rectangle-top visible-area)))
;; Recursive branches
(for ([i (in-range 6)])
(define branch-angle (+ angle (* i (/ (* 2 pi) 6))))
(define end-x (+ x (* size (cos branch-angle))))
(define end-y (+ y (* size (sin branch-angle))))
(define new-size (* size 0.5)) ; Reduce size for recursion
;; Increment the recursion level
(draw-fractal dc end-x end-y new-size branch-angle
visible-area min-detail-size frame-num total-frames
(+ level 1)))))
;; Function to create the fractal for a given frame
(define (create-fractal dc visible-area min-detail-size frame-num total-frames)
;; Starting point at the center of the visible area
(define center-x (/ (+ (rectangle-left visible-area) (rectangle-right visible-area)) 2))
(define center-y (/ (+ (rectangle-top visible-area) (rectangle-bottom visible-area)) 2))
;; Initial recursion level is 0
(define initial-level 0)
;; Draw the fractal starting from the center
(draw-fractal dc center-x center-y INITIAL-SCALE 0
visible-area min-detail-size frame-num total-frames
initial-level))
;; === Frame Generation ===
;; Function to generate a single frame
(define (generate-frame frame-num)
(define zoom-factor (expt ZOOM-SPEED frame-num))
(define frame-bitmap (make-bitmap imageWidth imageHeight))
(define frame-dc (new bitmap-dc% [bitmap frame-bitmap]))
;; Set background to black
(send frame-dc set-background (make-color 0 0 0))
(send frame-dc clear)
;; Center coordinates for zoom (assuming starting from center)
(define center-x (/ imageWidth 2))
(define center-y (/ imageHeight 2))
;; Visible area calculations
(define visible-width (/ imageWidth zoom-factor))
(define visible-height (/ imageHeight zoom-factor))
(define visible-left (- center-x (/ visible-width 2)))
(define visible-top (- center-y (/ visible-height 2)))
(define visible-area
(rectangle visible-left visible-top
(+ visible-left visible-width)
(+ visible-top visible-height)))
;; Dynamically adjust min-detail-size based on zoom level
(define min-detail-size (* MIN-SCALE-FRACTION visible-width))
;; Draw fractal with dynamic coloring
(create-fractal frame-dc visible-area min-detail-size frame-num TOTAL-FRAMES)
;; Print out the world window size
(printf "Frame ~a: Window [~a, ~a, ~a, ~a]~n"
frame-num
(rectangle-left visible-area)
(rectangle-top visible-area)
(rectangle-right visible-area)
(rectangle-bottom visible-area))
;; Save frame as PNG
(define frame-filename
(format "frame_~a.png"
(zero-pad frame-num 4)))
(send frame-bitmap save-file
(build-path output-dir frame-filename)
'png)
;; Log progress
(printf "Generated frame ~a/~a (~a%% complete)~n"
(add1 frame-num)
TOTAL-FRAMES
(inexact->exact (floor (* 100 (/ (add1 frame-num) TOTAL-FRAMES))))))
;; Clean up
(send frame-dc flush)
;; (send frame-bitmap release) ; Removed as bitmap% doesn't have a 'release' method
)
;; === Parallel Frame Generation ===
;; Function to generate all frames in parallel
(define (generate-all-frames)
;; Create output directory if it doesn't exist
(unless (directory-exists? output-dir)
(make-directory output-dir))
;; Determine number of worker threads
(define num-workers (min (processor-count) 8)) ; Adjust based on your CPU
;; Determine frames per worker
(define frames-per-worker (ceiling (/ TOTAL-FRAMES num-workers)))
;; Create worker futures
(define workers
(for/list ([i num-workers])
(define start (* i frames-per-worker))
(define end (min TOTAL-FRAMES (* (+ i 1) frames-per-worker)))
(future (λ ()
(for ([frame-num (in-range start end)])
(generate-frame frame-num))))))
;; Wait for all workers to complete
(for ([w workers])
(touch w)))
;; === Main Execution ===
(module+ main
(printf "Starting fractal zoom animation generation with ~a frames...~n" TOTAL-FRAMES)
;; Start frame generation
(time (generate-all-frames))
;; After frames are generated, create video using ffmpeg
(printf "All frames generated. Creating video using ffmpeg...~n")
;; FFmpeg command construction
(define ffmpeg-cmd
(string-append "ffmpeg -y -framerate "
(number->string FRAME-RATE)
" -i " output-dir "/frame_%04d.png "
"-c:v libx264 -pix_fmt yuv420p -crf 23 cactus_zoom.mp4"))
;; Execute FFmpeg command
(define ffmpeg-exit-code (system ffmpeg-cmd))
;; Check FFmpeg execution
(if (= ffmpeg-exit-code 0)
(printf "Video successfully created as cactus_zoom.mp4~n")
(printf "FFmpeg failed with exit code ~a~n" ffmpeg-exit-code)))