heyarne.rect-packing/src/heyarne/rect_packing/core.cljs
2022-01-01 12:11:50 +01:00

74 lines
2.8 KiB
Clojure

(ns heyarne.rect-packing.core
(:require [reagent.core :as r]
[reagent.dom :as dom]
[thi.ng.geom.core :as geom]
[thi.ng.geom.rect :as rect]
[thi.ng.geom.vector :as v]))
(defonce state (r/atom {:rects []
:frame (rect/rect 500 500)}))
(comment
(swap! state update :rects empty)
(swap! state update :rects conj (rect/rect 200 200))
;; fill with random rectangles
(swap! state assoc :rects
(repeatedly 20 #(rect/rect (+ 50 (rand-int 50)) (+ 50 (rand-int 50)))))
)
(defn pack-rects-naive
"Sorts all rectangles by height and places them next to each other into frame,
starting at the top left."
[frame rects]
(let [rects (sort-by (comp - geom/height) rects)]
(-> (reduce (fn [acc rect]
;; a word on "top" vs "bottom": the thi.ng coordinate system
;; works like the ones you know from scool, i.e. [0 1] is
;; above [0 0]. the svg coordinate system uses screen
;; coordinates, where [0 0] is at the top left. if you see
;; rect/bottom we're actually looking at the top edge that is
;; drawn in the svg.
(let [last-placed (or (last (:result acc)) (rect/rect 0 0))
moved-right (geom/translate rect [(rect/right last-placed) (rect/bottom (:row-start acc))])]
;; do we still have enough space to the right?
(if (<= (rect/right moved-right) (rect/right frame))
;; if yes, everything is bon
(update acc :result conj moved-right)
;; if no, move to the bottom
(let [moved-bottom (geom/translate rect [0 (rect/top (:row-start acc))])]
(-> (assoc acc :row-start moved-bottom)
(update :result conj moved-bottom))))))
{:row-start (first rects)
:result []}
rects)
:result)))
#_(pack-rects-naive (:frame @state) (:rects @state))
(defn main []
(let [{:keys [frame rects]} @state
sorted (map-indexed vector (pack-rects-naive frame rects))]
[:main
[:h1 "Visualization"]
[:svg.visualization {:viewBox "-0.5 -0.5 501 501" :xmlns "http://www.w3.org/2000/svg"}
[:rect {:width (geom/width frame)
:height (geom/height frame)}]
(for [[idx rect] sorted]
^{:key idx} [:rect {:width (geom/width rect) :height (geom/height rect)
:x (-> rect :p :x)
:y (-> rect :p :y)}])]
[:h2 "Rectangles"]
[:ul
(for [[idx rect] sorted]
^{:key idx} [:li [:pre (pr-str rect)]])]]))
(defn ^:dev/after-load init []
(println "Initializing…")
(dom/render [main] (.querySelector js/document "#app")))
(defonce app (init))
(+ 1 2)