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.graphics_2d/Stroke.ml.html
Source file Stroke.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(* 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 Stroke.mli for the idea, with a picture *) (* The rectangle around the segment from p0 to p1: p0 and p1 moved by * width/2 on each side, perpendicularly to the segment (along the * segment's direction turned a quarter turn, Vec2.perp) *) let segment_rectangle (p0 : Vec2.t) (p1 : Vec2.t) ~width : Vec2.t list option = let along = Vec2.sub p1 p0 in if Vec2.length along = 0. then None else let side = Vec2.scale (width /. 2.) (Vec2.normalize (Vec2.perp along)) in Some [ Vec2.add p0 side; Vec2.add p1 side; Vec2.sub p1 side; Vec2.sub p0 side ] let disk (center : Vec2.t) ~width : Vec2.t list = let r = width /. 2. in Circle.ellipse_points ~rx:r ~ry:r ~segments:(Circle.segments_for_radius r) |> List.map (Vec2.add center) (* Twice the signed area of a polygon (the "shoelace formula"): the sum * of the 2D cross products of consecutive points, each twice the signed * area of the triangle they make with the origin; its sign says which * way the polygon turns *) let signed_area (points : Vec2.t list) : float = match points with | [] -> 0. | first :: rest -> (* each point with the next one, the last with the first *) List.combine points (rest @ [ first ]) |> List.fold_left (fun acc (p, q) -> acc +. Vec2.cross p q) 0. (* All turned the same way, so that Nonzero adds them up *) let same_way (points : Vec2.t list) : Vec2.t list = if signed_area points < 0. then List.rev points else points let contours (lines : (float * float) list list) ~width : (float * float) list list = let rec segments = function | p :: (q :: _ as rest) -> Option.to_list (segment_rectangle p q ~width) @ segments rest | [ _ ] | [] -> [] in List.concat (List.map (fun line -> segments line @ List.map (disk ~width) line) lines) |> List.map same_way let polylines (fb : Framebuffer.t) (lines : (float * float) list list) ~width ~rgb ~alpha = Fill.polygons ~rule:Nonzero fb (contours lines ~width) ~rgb ~alpha
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>