(defpackage #:3dr.octcone3 (:use #:cl #:alexandria #:fw.lu)) (in-package #:3dr.octcone3) (defun make-adj-arr (&optional (size 25)) (make-array size :adjustable t :fill-pointer 0)) (defstruct (point (:type vector)) x y z) (defclass bintree () ((left :initarg :left :accessor left :initform nil) (right :initarg :right :accessor right :initform nil) (duplicates :initarg :duplicates :accessor duplicates :initform (make-adj-arr)) (center :initarg :center :accessor center))) (defclass quadtree () ((nw :initarg :nw :accessor nw :initform nil) (ne :initarg :ne :accessor ne :initform nil) (se :initarg :se :accessor se :initform nil) (sw :initarg :sw :accessor sw :initform nil) (duplicates :initarg :duplicates :accessor duplicates :initform (make-adj-arr)) (center :initarg :center :accessor center))) (defgeneric insert-in-tree (bintree child)) (defmethod insert-in-tree ((bintree bintree) (child real)) (with-slots (left right duplicates center) bintree (if (= child center) (vector-push-extend center duplicates) (if (< child center) (etypecase left (bintree (insert-in-tree left child)) (real (setf left (make-instance 'bintree :center left)) (insert-in-tree left child)) (null (setf left child))) (etypecase right (bintree (insert-in-tree right child)) (real (setf right (make-instance 'bintree :center right)) (insert-in-tree right child)) (null (setf right child))))))) (defmethod insert-in-tree ((quadtree quadtree) (child vector)) (labels ((vector-value (child) (etypecase child (quadtree (center child)) (vector child))) (dist-to-child (child) (c-distance (center quadtree) (vector-value child))) (replace-bucket (name) (etypecase (slot-value quadtree name) (quadtree (insert-in-tree (slot-value quadtree name) child)) (vector (let ((old-bucket (slot-value quadtree name))) (if (<= (dist-to-child child) (dist-to-child old-bucket)) (let ((new-bucket (make-instance 'quadtree :center child))) (setf (slot-value quadtree name) new-bucket) (with-accessors ((old-bucket-x point-x) (old-bucket-y point-y)) (vector-value old-bucket) (with-accessors ((new-bucket-x point-x) (new-bucket-y point-y)) (vector-value new-bucket) (if (< old-bucket-x new-bucket-x) (if (>= old-bucket-y new-bucket-y) (setf (nw new-bucket) old-bucket) (setf (sw new-bucket) old-bucket)) (if (>= old-bucket-y new-bucket-y) (setf (ne new-bucket) old-bucket) (setf (se new-bucket) old-bucket)))))) (setf (slot-value quadtree name) (make-instance 'quadtree :center old-bucket)))) (insert-in-tree (slot-value quadtree name) child)) (null (setf (slot-value quadtree name) child))))) (with-slots (nw ne se sw duplicates center) quadtree (if (equalp child center) (vector-push-extend center duplicates) (with-accessors ((center-x point-x) (center-y point-y)) center (with-accessors ((child-x point-x) (child-y point-y)) child (if (< child-x center-x) (if (>= child-y center-y) (replace-bucket 'nw) (replace-bucket 'sw)) (if (>= child-y center-y) (replace-bucket 'ne) (replace-bucket 'se))))))))) (defun one-layer-of-octree (quadtree) (flet ((bucket-as-point (b) (etypecase b (null nil) (vector b) (quadtree (center b))))) (with-slots (nw-bucket nw-bucket-bg ne-bucket ne-bucket-bg se-bucket se-bucket-bg sw-bucket sw-bucket-bg) quadtree (list (mapcar #'bucket-as-point (list quadtree nw-bucket nw-bucket-bg ne-bucket ne-bucket-bg se-bucket se-bucket-bg sw-bucket sw-bucket-bg)))))) (defun one-layer-of-bintree (bintree) (flet ((bintree-as-point (b) (etypecase b (null nil) (real b) (bintree (center b))))) (with-slots (left right) bintree (list (mapcar #'bintree-as-point (list bintree left right)))))) (defun one-layer-of-quadtree (quadtree) (flet ((quadtree-as-point (b) (etypecase b (null nil) (vector b) (quadtree (center b))))) (with-slots (nw ne se sw) quadtree (list (mapcar #'quadtree-as-point (list quadtree nw ne se sw)))))) (defun bintree-to-list (bintree) (typecase bintree (vector (list (list bintree nil nil))) (bintree (with-slots (left right) bintree (append (one-layer-of-bintree bintree) (when left (bintree-to-list left)) (when right (bintree-to-list right))))))) (defun quadtree-to-list (quadtree) (typecase quadtree (real (list (list quadtree nil nil))) (quadtree (with-slots (nw ne se sw) quadtree (append (one-layer-of-quadtree quadtree) (when nw (quadtree-to-list nw)) (when ne (quadtree-to-list ne)) (when se (quadtree-to-list se)) (when sw (quadtree-to-list sw))))))) (defun bintreelist-to-graph (bintreelist) (loop for list in bintreelist append (loop with head = (car list) for tail in (cdr list) when tail collect (list head tail)))) (defmethod print-object ((object quadtree) s) (declare (optimize (debug 3))) (print-unreadable-object (object s :type t :identity t) (with-slots (center nw ne se sw duplicates) object (format s "~s x~d: ~@{~a~^ ~}" center (length duplicates) (not (null nw)) (not (null ne)) (not (null sw)) (not (null se)))))) (defun draw-line (buffer p1 p2) (with-accessors ((x1 point-x) (y1 point-y)) p1 (with-accessors ((x2 point-x) (y2 point-y)) p2 (let* ((dist-x (abs (- x1 x2))) (dist-y (abs (- y1 y2))) (steep (> dist-y dist-x))) (when steep (psetf x1 y1 y1 x1 x2 y2 y2 x2)) (when (> x1 x2) (psetf x1 x2 x2 x1 y1 y2 y2 y1)) (let* ((delta-x (- x2 x1)) (delta-y (abs (- y1 y2))) (error (floor delta-x 2)) (y-step (if (< y1 y2) 1 -1)) (y y1)) (loop :for x :upfrom x1 :to x2 :do (if steep (incf (aref buffer x y) 1) (incf (aref buffer y x) 1)) (setf error (- error delta-y)) (when (< error 0) (incf y y-step) (incf error delta-x)))) buffer)))) (defun c-distance (p1 p2) (declare (optimize (debug 3)) (inline c-distance)) (sqrt (loop for c1 across p1 for c2 across p2 sum (expt (- c2 c1) 2)))) (defun main () (let ((res (make-instance 'quadtree :center #(50 50)))) (loop repeat 400 do (insert-in-tree res (vector (random 100) (random 100))) finally (return-from main res))))