From fbbc60a39c5ffc87f530c91dd321450cd55cb45f Mon Sep 17 00:00:00 2001 From: arne Date: Fri, 20 Feb 2026 08:54:19 +0100 Subject: [PATCH] Start scribbling around again --- src/aphorisms/fourty.clj | 73 ++++++++++++++++++++++++++ src/aphorisms/fourty_one.clj | 99 ++++++++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+) create mode 100644 src/aphorisms/fourty.clj create mode 100644 src/aphorisms/fourty_one.clj diff --git a/src/aphorisms/fourty.clj b/src/aphorisms/fourty.clj new file mode 100644 index 0000000..d6ba72d --- /dev/null +++ b/src/aphorisms/fourty.clj @@ -0,0 +1,73 @@ +(ns aphorisms.fourty + (:require [thi.ng.geom.core :as g] + [thi.ng.geom.vector :as v] + [quil.core :as q] + [quil.middleware :as qm] + [thi.ng.geom.rect :as r] + [aphorisms.utils.middleware :refer [screenshottable]] + )) + +;; Getting a feeling for the `thi.ng` API again; mostly playing around with how +;; to partition geometries into a grid and how to position things relative to +;; each other. + +(def height 500 #_(int (* width (Math/sqrt 2)))) +(def width #_500 (int (* height (Math/sqrt 2)))) +(def padding (* height 0.1)) +(def canvas (r/rect width height)) + +(defn center-in + "Centers `r2` in or around `r1`." + [r1 r2] + (g/translate (assoc r2 :p (:p r1)) + (v/vec2 (* 0.5 (- (g/width r1) (g/width r2))) + (* 0.5 (- (g/height r1) (g/height r2)))))) + +(def bounds (center-in canvas (r/rect (- width (* 2 padding)) (- height (* 2 padding))))) + +(defn as-grid [rect cell-size] + (let [n-x (int (/ (g/width rect) cell-size)) + n-y (int (/ (g/height rect) cell-size)) + t (v/vec2 (* (mod (g/width rect) n-x) 0.5) + (* (mod (g/height rect) n-x) 0.5))] + (for [x (range n-x) + y (range n-y)] + (-> (r/rect (* x cell-size) (* y cell-size) cell-size) + (g/translate (:p rect)) + (g/translate t ))))) + +(def grid (as-grid bounds 20)) + +;; below is the rendering logic + +(defn setup [] + (q/frame-rate 30) + (q/color-mode :hsb 360 100 100) + (q/rect-mode :center) + (q/ellipse-mode :center) + (q/background 350) + {}) + +(defn update-state [state] + state) + +(defn draw-state [state] + (q/translate -0.5) + (q/background 180 0 98) + (q/stroke-weight 0.5) + (q/no-fill) + (q/stroke 320 100 70) + (doseq [cell grid + :let [[x y] (g/centroid cell)]] + (q/ellipse x y 10 10))) + +#_:clj-kondo/ignore +(q/defsketch fourty + :title "Fourty" + :size [width height] + :settings #(q/pixel-density (q/display-density)) + :setup setup + :update update-state + :draw draw-state + :features [:keep-on-top :no-bind-output] + :middleware [qm/pause-on-error qm/fun-mode (screenshottable)]) diff --git a/src/aphorisms/fourty_one.clj b/src/aphorisms/fourty_one.clj new file mode 100644 index 0000000..4dc910c --- /dev/null +++ b/src/aphorisms/fourty_one.clj @@ -0,0 +1,99 @@ +(ns aphorisms.fourty-one + (:require [thi.ng.geom.core :as g] + [thi.ng.geom.vector :as v] + [quil.core :as q] + [quil.middleware :as qm] + [thi.ng.geom.rect :as r] + [aphorisms.utils.middleware :refer [screenshottable]] + + [thi.ng.geom.line :as l] + [thi.ng.math.core :as m] + [thi.ng.geom.utils.intersect :as isec])) + +;; More practice to get a feeling for the `thi.ng` API again +;; Resizing cells in the grid, generating random lines and playing with intersections + +(def height 500 #_(int (* width (Math/sqrt 2)))) +(def width #_500 (int (* height (Math/sqrt 2)))) +(def padding (* height 0.1)) +(def canvas (r/rect width height)) + +(defn center-in + "Centers `r2` in or around `r1`." + [r1 r2] + (g/translate (assoc r2 :p (:p r1)) + (v/vec2 (* 0.5 (- (g/width r1) (g/width r2))) + (* 0.5 (- (g/height r1) (g/height r2)))))) + +(def bounds (center-in canvas (r/rect (- width (* 2 padding)) (- height (* 2 padding))))) + +(defn as-grid [rect cell-size] + (let [n-x (int (/ (g/width rect) cell-size)) + n-y (int (/ (g/height rect) cell-size)) + t (v/vec2 (* (mod (g/width rect) n-x) 0.5) + (* (mod (g/height rect) n-x) 0.5))] + (for [x (range n-x) + y (range n-y)] + (-> (r/rect (* x cell-size) (* y cell-size) cell-size) + (g/translate (:p rect)) + (g/translate t ))))) + +(def grid (map #(g/scale-size % 0.92) (as-grid bounds 50))) + +(defn line-inside [rect] + (l/line2 (g/random-point-inside rect) (g/random-point-inside rect))) + +;; below is the rendering logic + +(defn setup [] + (q/frame-rate 30) + (q/color-mode :hsb 360 100 100) + (q/rect-mode :center) + (q/ellipse-mode :center) + (q/background 350) + {:lines (repeatedly 5 #(line-inside bounds))}) + +(defn update-state [state] + state) + +(defn mouse-pressed [state _] + (assoc state :lines (repeatedly 20 #(line-inside bounds)))) + +(let [l (l/line2 50 50 200 210)] + (g/intersect-line l (first (g/edges (first grid))))) + +(defn draw-state [state] + (q/translate -0.5 -0.5) + (q/background 180 0 98) + (q/stroke-weight 0.5) + (q/no-fill) + (q/stroke 320 100 70) + (doseq [line (:lines state) + :let [[a b] (g/vertices line)]] + (q/line a b)) + (doseq [cell grid + [a b] (g/edges cell)] + (q/line a b)) + (q/no-stroke) + (q/fill 320 100 70) + (doseq [cell grid + line (:lines state) + isecs (->> + (map #(g/intersect-line line %) (g/edges cell)) + (keep #(when (= (:type %) :intersect) (:p %)))) + :let [[i1 i2] isecs]] + (q/ellipse i1 i2 5 5))) + +#_:clj-kondo/ignore +(q/defsketch fourty-one + :title "Fourty One" + :size [width height] + :settings (fn [] + (q/smooth 2) + (q/pixel-density (q/display-density))) + :setup setup + :update #'update-state + :mouse-pressed #'mouse-pressed + :draw #'draw-state + :features [:keep-on-top :no-bind-output] + :middleware [qm/pause-on-error qm/fun-mode (screenshottable)])