package tiny_libs
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
From-scratch libraries for teaching: graphics, audio, compression, crypto, networking and more
Install
dune-project
Dependency
Authors
Maintainers
Sources
0.3.6.tar.gz
md5=7c636383d146d30ac6f2fa234a6253c8
sha512=c79f3823c5f8f57e5038eb640d487c61168b84aa07c61999d6622ef9fd0c890e2b03b4c6a7cdbbe9352a49e25dda00ac7bb14693cee8e3d7beeed251351a2af0
doc/src/tiny_libs.physics_2d/Particles.ml.html
Source file Particles.ml
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(* Claude Code * * Copyright (C) 2026 Yoann Padioleau * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public License * (LGPL) as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. *) (* See Particles.mli *) type particle = { pos : Vec2.t; old : Vec2.t; pinned : bool } type stick = { a : int; b : int; length : float } let particle ?(pinned = false) (pos : Vec2.t) : particle = { pos; old = pos; pinned } let velocity ~(dt : float) (p : particle) : Vec2.t = Vec2.scale (1. /. dt) (Vec2.sub p.pos p.old) let step ?(drag = 0.) ~(accel : Vec2.t) ~(dt : float) (particles : particle array) : particle array = particles |> Array.map (fun p -> if p.pinned then p else let moved = Vec2.scale (1. -. drag) (Vec2.sub p.pos p.old) in { p with old = p.pos; pos = Vec2.add (Vec2.add p.pos moved) (Vec2.scale (dt *. dt) accel) }) let relax ~(iterations : int) (sticks : stick list) (particles : particle array) : particle array = let ps = Array.copy particles in for _ = 1 to iterations do sticks |> List.iter (fun s -> let a = ps.(s.a) and b = ps.(s.b) in let d = Vec2.sub b.pos a.pos in let length = Vec2.length d in if length > 0. then (* the excess, as a fraction of the stick, shared by the * free ends *) let excess = Vec2.scale ((length -. s.length) /. length) d in match (a.pinned, b.pinned) with | true, true -> () | true, false -> ps.(s.b) <- { b with pos = Vec2.sub b.pos excess } | false, true -> ps.(s.a) <- { a with pos = Vec2.add a.pos excess } | false, false -> let half = Vec2.scale 0.5 excess in ps.(s.a) <- { a with pos = Vec2.add a.pos half }; ps.(s.b) <- { b with pos = Vec2.sub b.pos half }) done; ps let keep_out ?(friction = 0.3) (polygons : Vec2.t list list) (particles : particle array) : particle array = particles |> Array.map (fun p -> match List.find_opt (Collide.point_in_polygon p.pos) polygons with | Some corners when not p.pinned -> let pos = Collide.nearest_on_outline p.pos corners in (* its velocity, pos - old, scaled by 1 - friction *) { p with pos; old = Vec2.sub pos (Vec2.scale (1. -. friction) (Vec2.sub p.pos p.old)) } | _ -> p) let rope ~(from : Vec2.t) ~(towards : Vec2.t) (n : int) : particle array * stick list = let at i = Vec2.add from (Vec2.scale (float_of_int i /. float_of_int (n - 1)) (Vec2.sub towards from)) in let length = Vec2.length (Vec2.sub towards from) /. float_of_int (n - 1) in (Array.init n (fun i -> particle ~pinned:(i = 0) (at i)), List.init (n - 1) (fun i -> { a = i; b = i + 1; length }))
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>