1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

examples: improve the pendulum simulation, with several modes and diagrams (#13446)

This commit is contained in:
Ulises Jeremias Cornejo Fandos
2022-02-12 14:38:07 -03:00
committed by GitHub
parent a74d28ae5f
commit 4391ae563d
26 changed files with 1501 additions and 366 deletions

View File

@ -0,0 +1,74 @@
module img
import gx
import os
import sim
[params]
pub struct ImageSettings {
pub:
width int = sim.default_width
height int = sim.default_height
cache_size int = 200
}
pub fn new_image_settings(settings ImageSettings) ImageSettings {
return ImageSettings{
...settings
}
}
pub fn image_settings_from_grid(grid sim.GridSettings) ImageSettings {
return ImageSettings{
width: grid.width
height: grid.height
}
}
pub fn (s ImageSettings) to_grid_settings() sim.GridSettings {
return sim.GridSettings{
width: s.width
height: s.height
}
}
pub struct PPMWriter {
mut:
file os.File
cache []byte
cache_size int
}
pub fn ppm_writer_for_fname(fname string, settings ImageSettings) ?&PPMWriter {
mut writer := &PPMWriter{
cache_size: settings.cache_size
cache: []byte{cap: settings.cache_size}
}
writer.start_for_file(fname, settings) ?
return writer
}
pub fn (mut writer PPMWriter) start_for_file(fname string, settings ImageSettings) ? {
writer.file = os.create(fname) ?
writer.file.writeln('P6 $settings.width $settings.height 255') ?
}
pub fn (mut writer PPMWriter) handle_pixel(p gx.Color) ? {
if writer.cache.len >= writer.cache_size {
writer.write() ?
writer.flush() ?
}
writer.cache << [p.r, p.g, p.b]
}
pub fn (mut writer PPMWriter) flush() ? {
writer.cache.clear()
}
pub fn (mut writer PPMWriter) write() ? {
writer.file.write(writer.cache) ?
}
pub fn (mut writer PPMWriter) close() {
writer.file.close()
}

View File

@ -0,0 +1,40 @@
module img
import benchmark
import sim
pub fn image_worker(mut writer PPMWriter, result_chan chan &sim.SimResult, settings ImageSettings) {
width := settings.width
height := settings.height
total_pixels := width * height
// as new pixels come in, write them to the image file
mut current_index := u64(0)
mut pixel_buf := []ValidColor{len: total_pixels, init: ValidColor{
valid: false
}}
mut bmark := benchmark.new_benchmark()
for {
result := <-result_chan or { break }
// find the closest magnet
pixel_buf[result.id].Color = compute_pixel(result)
pixel_buf[result.id].valid = true
for current_index < total_pixels && pixel_buf[current_index].valid {
bmark.step()
writer.handle_pixel(pixel_buf[current_index].Color) or {
bmark.fail()
sim.log(@MOD + '.' + @FN + ': pixel handler failed. Error $err')
break
}
bmark.ok()
current_index++
}
}
bmark.stop()
println(bmark.total_message(@FN))
writer.write() or { panic('Could not write image') }
}

View File

@ -0,0 +1,68 @@
module img
import gx
import sim
pub struct ValidColor {
gx.Color
pub mut:
valid bool
}
pub struct ImageWritter {
settings ImageSettings
pub mut:
writer PPMWriter
current_index int
buffer []ValidColor
}
pub fn new_image_writer(mut writer PPMWriter, settings ImageSettings) &ImageWritter {
total_pixels := settings.width * settings.height
mut buffer := []ValidColor{len: total_pixels, init: ValidColor{
valid: false
}}
return &ImageWritter{
writer: writer
settings: settings
buffer: buffer
}
}
pub fn (mut iw ImageWritter) handle(result sim.SimResult) ?int {
total_pixels := iw.settings.width * iw.settings.height
// find the closest magnet
iw.buffer[result.id].Color = compute_pixel(result)
iw.buffer[result.id].valid = true
for iw.current_index < total_pixels && iw.buffer[iw.current_index].valid {
iw.writer.handle_pixel(iw.buffer[iw.current_index].Color) or {
sim.log(@MOD + '.' + @FN + ': pixel handler failed. Error $err')
break
}
iw.current_index++
}
if iw.current_index == total_pixels {
iw.writer.write() or { panic('Could not write image') }
return none
}
return iw.current_index
}
pub fn compute_pixel(result sim.SimResult) gx.Color {
closest_to_m1 := result.magnet1_distance < result.magnet2_distance
&& result.magnet1_distance < result.magnet3_distance
closest_to_m2 := result.magnet2_distance < result.magnet1_distance
&& result.magnet2_distance < result.magnet3_distance
if closest_to_m1 {
return gx.red
} else if closest_to_m2 {
return gx.green
} else {
return gx.blue
}
}