git.fiddlerwoaroof.com
Raw Blame History
(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
    (with-accessors ((center-y 3dr::point-y) (center-z 3dr::point-z)) center
      (with-accessors ((point-y 3dr::point-y) (point-z 3dr::point-z)) point
        (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)))))))

(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)
  (* (signum low)
     (expt 2
           (floor (log (abs (+ low
                               (floor (- high low)
                                      2)))
                       2)))))

(defun subdivide-bucket (octcone bucket)
  (declare (optimize (debug 3)))
  (let ((the-bucket (slot-value octcone bucket)))
    (check-type the-bucket vector)
    (if (< 1 (length the-bucket))
      (let* ((max-y (reduce #'max the-bucket :key #'3dr::point-y))
             (min-y (reduce #'min the-bucket :key #'3dr::point-y))

             (max-z (reduce #'max the-bucket :key #'3dr::point-z))
             (min-z (reduce #'min the-bucket :key #'3dr::point-z))

             (new-octc (make-instance 'octcone
                                      :center (vector 0
                                                      (half-power-two min-y max-y)
                                                      (half-power-two min-z max-z)))))

        (values (prog1 new-octc
                  (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)))
                (vector min-y max-y)
                (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)))))

(defun subdivide-buckets (octcone)
  (let ((result (loop for bucket in '(nw-bucket ne-bucket se-bucket sw-bucket)
                      collect (subdivide-bucket octcone bucket))))))

(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*))

(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))))))