git.fiddlerwoaroof.com
octcone.lisp
f8737faa
 (in-package #:3dr.octcone)
 
 (defun make-adj-arr (&optional (size 25))
   (make-array size :adjustable t :fill-pointer 0))
 
 (defstruct (bounds (:type vector))
   tl tr bl br)
 
 (defclass octcone ()
   ((nw-bucket :initarg :nw-bucket :accessor nw-bucket :initform (make-adj-arr))
    (ne-bucket :initarg :ne-bucket :accessor ne-bucket :initform (make-adj-arr))
    (sw-bucket :initarg :sw-bucket :accessor sw-bucket :initform (make-adj-arr))
    (se-bucket :initarg :se-bucket :accessor se-bucket :initform (make-adj-arr))
    (overflow-bucket :initarg :overflow-bucket :accessor overflow-bucket :initform (make-adj-arr))
    (center :initarg :center :accessor center)))
 
 (defun bucket-point (point octcone)
   (with-slots (nw-bucket ne-bucket sw-bucket se-bucket center) octcone
3bf1c97c
     (with-accessors ((center-y 3dr::point-y) (center-z 3dr::point-z)) center
f8737faa
       (with-accessors ((point-y 3dr::point-y) (point-z 3dr::point-z)) point
3bf1c97c
         (vector-push-extend
           point
           (if (< point-y center-y)
             (if (< point-z center-z)
               sw-bucket
               nw-bucket)
             (if (< point-z center-z)
               se-bucket
               ne-bucket)))))))
f8737faa
 
98876dd5
 (defun normalize-bucket (octcone bucket)
   (let ((the-bucket (slot-value octcone bucket)))
     (setf (slot-value octcone bucket)
           (sort the-bucket #'< :key (lambda (point) (3dr::c-distance point #(0 0 0)))))))
 
 (defun normalize-buckets (octcone)
   (loop for bucket in '(nw-bucket ne-bucket se-bucket sw-bucket)
         collect (normalize-bucket octcone bucket)))
 
 (defun half-power-two (low high)
3bf1c97c
   (* (signum low)
      (expt 2
            (floor (log (abs (+ low
                                (floor (- high low)
                                       2)))
                        2)))))
98876dd5
 
 (defun subdivide-bucket (octcone bucket)
3bf1c97c
   (declare (optimize (debug 3)))
98876dd5
   (let ((the-bucket (slot-value octcone bucket)))
3bf1c97c
     (check-type the-bucket vector)
     (if (< 1 (length the-bucket))
98876dd5
       (let* ((max-y (reduce #'max the-bucket :key #'3dr::point-y))
              (min-y (reduce #'min the-bucket :key #'3dr::point-y))
3bf1c97c
 
98876dd5
              (max-z (reduce #'max the-bucket :key #'3dr::point-z))
              (min-z (reduce #'min the-bucket :key #'3dr::point-z))
3bf1c97c
 
98876dd5
              (new-octc (make-instance 'octcone
                                       :center (vector 0
                                                       (half-power-two min-y max-y)
                                                       (half-power-two min-z max-z)))))
3bf1c97c
 
98876dd5
         (values (prog1 new-octc
3bf1c97c
                   (when (or (= min-y max-y) (= min-z max-z))
                     (setf (slot-value octcone bucket)
                           new-octc)
                     (map nil
                          (lambda (point)
                            (bucket-point point new-octc))
                          the-bucket)))
98876dd5
                 (vector min-y max-y)
3bf1c97c
                 (vector min-z max-z)))
       nil)))
 
 (defmethod bucket-length (bucket)
   (declare (optimize (debug 3)))
   (typecase bucket
     (vector (length bucket))
     (octcone
       (with-slots (nw-bucket ne-bucket sw-bucket se-bucket overflow-bucket) bucket
         (+ (bucket-length nw-bucket)
            (bucket-length ne-bucket)
            (bucket-length se-bucket)
            (bucket-length sw-bucket)
            (bucket-length overflow-bucket))))))
 
 (defmethod print-object ((object octcone) s)
   (print-unreadable-object (object s :type t :identity t)
     (with-slots (nw-bucket ne-bucket sw-bucket se-bucket overflow-bucket center) object
       (format s "center: (~{~a~^,~}) sizes: nw ~d, ne ~d, se ~d, sw ~d, overflow ~d"
               (coerce center 'list)
               (bucket-length nw-bucket)
               (bucket-length ne-bucket)
               (bucket-length se-bucket)
               (bucket-length sw-bucket)
               (bucket-length overflow-bucket)))))
98876dd5
 
 (defun subdivide-buckets (octcone)
3bf1c97c
   (let ((result (loop for bucket in '(nw-bucket ne-bucket se-bucket sw-bucket)
                       collect (subdivide-bucket octcone bucket))))))
98876dd5
 
 (defun show-bucket-sizes (octcone)
   (loop for bucket in '(nw-bucket ne-bucket se-bucket sw-bucket)
         collect (length (slot-value octcone bucket))))
 
 (defvar *octc*)
 (defvar *points*)
 
 (defun main ()
   (setf *octc* (make-instance 'octcone :center (vector 0 0 0)))
 
   (flet ((100- (x) (- 100 x)))
     (setf *points*
           (loop repeat 1000
                 collect (vector (random 200) (100- (random 200)) (100- (random 200))))))
 
   (mapcar (lambda (x)
             (bucket-point x *octc*))
           *points*))
f8737faa
 
3bf1c97c
 (defun make-graph-conns (conns)
   (format nil "~:{~4t~(\"~a\" -> \"~a\"~%~)~}" conns))
 
 (defun make-graph (conns)
   (format nil "digraph {~%~a~%}~%" (make-graph-conns conns)))
 
 (defun bucket-to-pair (bucket parent)
   (declare (optimize (debug 3)))
   (flet ((bucket-to-string (center bucket title)
            (format nil "\"(~a: <~{~d~^, ~}> ~d)\""
                    (sxhash bucket)
                    (coerce center 'list)
                    (bucket-length bucket))))
     (with-slots (center) bucket
       (with-slots ((parent-center center)) parent
         (list (bucket-to-string parent-center parent)
               (bucket-to-string center bucket))))))
 
 (defun octcone-to-graph-pairs (octcone)
   (declare (optimize (debug 3)))
   (with-slots (nw-bucket ne-bucket se-bucket sw-bucket center) octcone
     (list
       (typecase nw-bucket
         (octcone (bucket-to-pair nw-bucket octcone)))
       (typecase ne-bucket
         (octcone (bucket-to-pair ne-bucket octcone)))
       (typecase se-bucket
         (octcone (bucket-to-pair se-bucket octcone)))
       (typecase sw-bucket
         (octcone (bucket-to-pair sw-bucket octcone))))))
 
 (defun bucket-to-graph-list (bucket)
   (declare (optimize (debug 3)))
   (typecase bucket
     (octcone
       (with-slots (nw-bucket ne-bucket se-bucket sw-bucket center) bucket
         (append (octcone-to-graph-pairs bucket)
                 (bucket-to-graph-list nw-bucket)
                 (bucket-to-graph-list ne-bucket)
                 (bucket-to-graph-list sw-bucket)
                 (bucket-to-graph-list se-bucket))))))