|
@@ -0,0 +1,929 @@
|
|
|
|
|
+(in-package :cl-user)
|
|
|
|
|
+(defpackage #:ocm.s2
|
|
|
|
|
+ (:use :cl))
|
|
|
|
|
+(in-package :ocm.s2)
|
|
|
|
|
+
|
|
|
|
|
+;; In the process of converting a latitude-longitude pair to a 64-bit cell
|
|
|
|
|
+;; id, the following coordinate systems are used:
|
|
|
|
|
+;;
|
|
|
|
|
+;; (id)
|
|
|
|
|
+;; An S2CellId is a 64-bit encoding of a face and a Hilbert curve position
|
|
|
|
|
+;; on that face. The Hilbert curve position implicitly encodes both the
|
|
|
|
|
+;; position of a cell and its subdivision level (see s2cell_id.h).
|
|
|
|
|
+;;
|
|
|
|
|
+;; (face, i, j)
|
|
|
|
|
+;; Leaf-cell coordinates. "i" and "j" are integers in the range
|
|
|
|
|
+;; [0,(2**30)-1] that identify a particular leaf cell on the given face.
|
|
|
|
|
+;; The (i, j) coordinate system is right-handed on each face, and the
|
|
|
|
|
+;; faces are oriented such that Hilbert curves connect continuously from
|
|
|
|
|
+;; one face to the next.
|
|
|
|
|
+;;
|
|
|
|
|
+;; (face, s, t)
|
|
|
|
|
+;; Cell-space coordinates. "s" and "t" are real numbers in the range
|
|
|
|
|
+;; [0,1] that identify a point on the given face. For example, the point
|
|
|
|
|
+;; (s, t) = (0.5, 0.5) corresponds to the center of the top-level face
|
|
|
|
|
+;; cell. This point is also a vertex of exactly four cells at each
|
|
|
|
|
+;; subdivision level greater than zero.
|
|
|
|
|
+;;
|
|
|
|
|
+;; (face, si, ti)
|
|
|
|
|
+;; Discrete cell-space coordinates. These are obtained by multiplying
|
|
|
|
|
+;; "s" and "t" by 2**31 and rounding to the nearest unsigned integer.
|
|
|
|
|
+;; Discrete coordinates lie in the range [0,2**31]. This coordinate
|
|
|
|
|
+;; system can represent the edge and center positions of all cells with
|
|
|
|
|
+;; no loss of precision (including non-leaf cells). In binary, each
|
|
|
|
|
+;; coordinate of a level-k cell center ends with a 1 followed by
|
|
|
|
|
+;; (30 - k) 0s. The coordinates of its edges end with (at least)
|
|
|
|
|
+;; (31 - k) 0s.
|
|
|
|
|
+;;
|
|
|
|
|
+;; (face, u, v)
|
|
|
|
|
+;; Cube-space coordinates in the range [-1,1]. To make the cells at each
|
|
|
|
|
+;; level more uniform in size after they are projected onto the sphere,
|
|
|
|
|
+;; we apply a nonlinear transformation of the form u=f(s), v=f(t).
|
|
|
|
|
+;; The (u, v) coordinates after this transformation give the actual
|
|
|
|
|
+;; coordinates on the cube face (modulo some 90 degree rotations) before
|
|
|
|
|
+;; it is projected onto the unit sphere.
|
|
|
|
|
+;;
|
|
|
|
|
+;; (face, u, v, w)
|
|
|
|
|
+;; Per-face coordinate frame. This is an extension of the (face, u, v)
|
|
|
|
|
+;; cube-space coordinates that adds a third axis "w" in the direction of
|
|
|
|
|
+;; the face normal. It is always a right-handed 3D coordinate system.
|
|
|
|
|
+;; Cube-space coordinates can be converted to this frame by setting w=1,
|
|
|
|
|
+;; while (u,v,w) coordinates can be projected onto the cube face by
|
|
|
|
|
+;; dividing by w, i.e. (face, u/w, v/w).
|
|
|
|
|
+;;
|
|
|
|
|
+;; (x, y, z)
|
|
|
|
|
+;; Direction vector (S2Point). Direction vectors are not necessarily unit
|
|
|
|
|
+;; length, and are often chosen to be points on the biunit cube
|
|
|
|
|
+;; [-1,+1]x[-1,+1]x[-1,+1]. They can be be normalized to obtain the
|
|
|
|
|
+;; corresponding point on the unit sphere.
|
|
|
|
|
+;;
|
|
|
|
|
+;; (lat, lng)
|
|
|
|
|
+;; Latitude and longitude (S2LatLng). Latitudes must be between -90 and
|
|
|
|
|
+;; 90 degrees inclusive, and longitudes must be between -180 and 180
|
|
|
|
|
+;; degrees inclusive.
|
|
|
|
|
+;;
|
|
|
|
|
+;; Note that the (i, j), (s, t), (si, ti), and (u, v) coordinate systems are
|
|
|
|
|
+;; right-handed on all six faces.
|
|
|
|
|
+
|
|
|
|
|
+(defparameter +swap-mask+ 1)
|
|
|
|
|
+(defparameter +invert-mask+ 2)
|
|
|
|
|
+(defparameter +max-cell-level+ 30 "This is the number of levels needed to specify a leaf cell.")
|
|
|
|
|
+(defparameter +limit-ij+ (ash 1 +max-cell-level+) "The maximum index of a valid leaf cell plus one. The range of valid leaf cell indices is [0..+limit-ij+-1].")
|
|
|
|
|
+(defparameter +max-si-ti+ (ash 1 (+ 1 +max-cell-level+)) "The maximum value of an si- or ti-coordinate. The range of valid (si,ti) values is [0..+max-si-ti+].")
|
|
|
|
|
+
|
|
|
|
|
+;; An S2CellId is a 64-bit unsigned integer that uniquely identifies a
|
|
|
|
|
+;; cell in the S2 cell decomposition. It has the following format:
|
|
|
|
|
+;;
|
|
|
|
|
+;; id = [face][face_pos]
|
|
|
|
|
+;;
|
|
|
|
|
+;; face: a 3-bit number (range 0..5) encoding the cube face.
|
|
|
|
|
+;;
|
|
|
|
|
+;; face_pos: a 61-bit number encoding the position of the center of this
|
|
|
|
|
+;; cell along the Hilbert curve over this face (see the Wiki
|
|
|
|
|
+;; pages for details).
|
|
|
|
|
+;;
|
|
|
|
|
+;; Sequentially increasing cell ids follow a continuous space-filling curve
|
|
|
|
|
+;; over the entire sphere. They have the following properties:
|
|
|
|
|
+;;
|
|
|
|
|
+;; - The id of a cell at level k consists of a 3-bit face number followed
|
|
|
|
|
+;; by k bit pairs that recursively select one of the four children of
|
|
|
|
|
+;; each cell. The next bit is always 1, and all other bits are 0.
|
|
|
|
|
+;; Therefore, the level of a cell is determined by the position of its
|
|
|
|
|
+;; lowest-numbered bit that is turned on (for a cell at level k, this
|
|
|
|
|
+;; position is 2 * (kMaxLevel - k).)
|
|
|
|
|
+;;
|
|
|
|
|
+;; - The id of a parent cell is at the midpoint of the range of ids spanned
|
|
|
|
|
+;; by its children (or by its descendants at any level).
|
|
|
|
|
+(defparameter +face-bits+ 3)
|
|
|
|
|
+(defparameter +num-faces+ 6)
|
|
|
|
|
+(defparameter +max-level+ +max-cell-level+)
|
|
|
|
|
+(defparameter +pos-bits+ (1+ (* 2 +max-level+)))
|
|
|
|
|
+(defparameter +max-size+ (ash 1 +max-level+))
|
|
|
|
|
+
|
|
|
|
|
+(defun st-to-ij (s)
|
|
|
|
|
+ (max 0 (min (- +limit-ij+ 1) (round (- (* s +limit-ij+) 0.5d0)))))
|
|
|
|
|
+
|
|
|
|
|
+;; Use quadratic (s,t) -> (u,v) projection. See S2 sources for explanation.
|
|
|
|
|
+(defun st-to-uv (s)
|
|
|
|
|
+ (* (/ 1 3)
|
|
|
|
|
+ (if (>= s 0.5d0)
|
|
|
|
|
+ (- (* 4 s s) 1)
|
|
|
|
|
+ (- 1 (* 4 (- s 1) (- s 1))))))
|
|
|
|
|
+(defun uv-to-st (u)
|
|
|
|
|
+ (if (>= u 0)
|
|
|
|
|
+ (* 0.5d0 (sqrt (+ 1 (* 3 u))))
|
|
|
|
|
+ (- 1 (* 0.5d0 (sqrt (- 1 (* 3 u)))))))
|
|
|
|
|
+
|
|
|
|
|
+(defstruct point
|
|
|
|
|
+ (x 0.0d0 :type double-float)
|
|
|
|
|
+ (y 0.0d0 :type double-float)
|
|
|
|
|
+ (z 0.0d0 :type double-float))
|
|
|
|
|
+
|
|
|
|
|
+(defstruct latlng
|
|
|
|
|
+ (lat 0d0 :type double-float)
|
|
|
|
|
+ (lng 0d0 :type double-float))
|
|
|
|
|
+
|
|
|
|
|
+(defun deg-to-rad (deg)
|
|
|
|
|
+ (* (/ pi 180d0) deg))
|
|
|
|
|
+(defun rad-to-deg (rad)
|
|
|
|
|
+ (* (/ 180d0 pi) rad))
|
|
|
|
|
+
|
|
|
|
|
+(defun from-radians (lat-rad lng-rad)
|
|
|
|
|
+ (make-latlng :lat lat-rad :lng lng-rad))
|
|
|
|
|
+(defun from-degrees (lat-deg lng-deg)
|
|
|
|
|
+ (make-latlng :lat (deg-to-rad lat-deg) :lng (deg-to-rad lng-deg)))
|
|
|
|
|
+(defun to-degrees (latlng)
|
|
|
|
|
+ (declare (type latlng latlng))
|
|
|
|
|
+ (with-slots (lat lng) latlng
|
|
|
|
|
+ (cons (rad-to-deg lat) (rad-to-deg lng))))
|
|
|
|
|
+(defun latlng-to-point (latlng)
|
|
|
|
|
+ (declare (type latlng latlng))
|
|
|
|
|
+ (with-slots (lat lng) latlng
|
|
|
|
|
+ (let* ((phi lat)
|
|
|
|
|
+ (theta lng)
|
|
|
|
|
+ (cos-phi (cos phi)))
|
|
|
|
|
+ (make-point :x (* (cos theta) cos-phi)
|
|
|
|
|
+ :y (* (sin theta) cos-phi)
|
|
|
|
|
+ :z (sin phi)))))
|
|
|
|
|
+(defun point-lat (p)
|
|
|
|
|
+ (declare (type point p))
|
|
|
|
|
+ (with-slots (x y z) p
|
|
|
|
|
+ (atan z (sqrt (+ (* x x) (* y y))))))
|
|
|
|
|
+(defun point-lng (p)
|
|
|
|
|
+ (declare (type point p))
|
|
|
|
|
+ (with-slots (x y z) p
|
|
|
|
|
+ (atan y x)))
|
|
|
|
|
+(defun point-to-lat-lng (p)
|
|
|
|
|
+ (declare (type point p))
|
|
|
|
|
+ (from-radians (point-lat p) (point-lng p)))
|
|
|
|
|
+
|
|
|
|
|
+(defun dot (p1 p2)
|
|
|
|
|
+ (declare (type point p1 p2))
|
|
|
|
|
+ (+ (* (point-x p1) (point-x p2))
|
|
|
|
|
+ (* (point-y p1) (point-y p2))
|
|
|
|
|
+ (* (point-z p1) (point-z p2))))
|
|
|
|
|
+
|
|
|
|
|
+(defparameter +face-uvw-axes+
|
|
|
|
|
+ (make-array '(6 3) :element-type 'point :initial-contents
|
|
|
|
|
+ (list
|
|
|
|
|
+ (list (make-point :y 1d0) (make-point :z 1d0) (make-point :x 1d0))
|
|
|
|
|
+ (list (make-point :x -1d0) (make-point :z 1d0) (make-point :y 1d0))
|
|
|
|
|
+ (list (make-point :x -1d0) (make-point :y -1d0) (make-point :z 1d0))
|
|
|
|
|
+ (list (make-point :z -1d0) (make-point :y -1d0) (make-point :x -1d0))
|
|
|
|
|
+ (list (make-point :z -1d0) (make-point :x 1d0) (make-point :y -1d0))
|
|
|
|
|
+ (list (make-point :y 1d0) (make-point :x 1d0) (make-point :z -1d0))))
|
|
|
|
|
+ "The U,V,W axes for each face.")
|
|
|
|
|
+
|
|
|
|
|
+(defun get-xyz-face (p)
|
|
|
|
|
+ (declare (type point p))
|
|
|
|
|
+ (with-slots (x y z) p
|
|
|
|
|
+ (cond
|
|
|
|
|
+ ((and (> (abs x) (abs y))
|
|
|
|
|
+ (> (abs x) (abs z)))
|
|
|
|
|
+ (if (>= x 0) 0 3))
|
|
|
|
|
+ ((and (> (abs y) (abs x))
|
|
|
|
|
+ (> (abs y) (abs z)))
|
|
|
|
|
+ (if (>= y 0) 1 4))
|
|
|
|
|
+ (t
|
|
|
|
|
+ (if (>= z 0) 2 5)))))
|
|
|
|
|
+
|
|
|
|
|
+(defun get-uvw-axis (face axis)
|
|
|
|
|
+ (aref +face-uvw-axes+ face axis))
|
|
|
|
|
+
|
|
|
|
|
+(defun get-norm (face)
|
|
|
|
|
+ (get-uvw-axis face 2))
|
|
|
|
|
+
|
|
|
|
|
+(defun valid-face-xyz-to-uv (face p)
|
|
|
|
|
+ (declare (type point p))
|
|
|
|
|
+ (assert (> (dot (get-norm face) p) 0))
|
|
|
|
|
+ (with-slots (x y z) p
|
|
|
|
|
+ (ecase face
|
|
|
|
|
+ (0 (values (/ y x) (/ z x)))
|
|
|
|
|
+ (1 (values (/ (- x) y) (/ z y)))
|
|
|
|
|
+ (2 (values (/ (- x) z) (/ (- y) z)))
|
|
|
|
|
+ (3 (values (/ z x) (/ y x)))
|
|
|
|
|
+ (4 (values (/ z y) (/ (- x) y)))
|
|
|
|
|
+ (5 (values (/ (- y) z) (/ (- x) z))))))
|
|
|
|
|
+
|
|
|
|
|
+(defun xyz-to-face-uv (p)
|
|
|
|
|
+ (declare (type point p))
|
|
|
|
|
+ (let ((face (get-xyz-face p)))
|
|
|
|
|
+ (multiple-value-bind (u v)
|
|
|
|
|
+ (valid-face-xyz-to-uv face p)
|
|
|
|
|
+ (values face u v))))
|
|
|
|
|
+
|
|
|
|
|
+(defparameter +lookup-bits+ 4)
|
|
|
|
|
+(defvar *lookup-pos* (make-array (ash 1 (+ 2 (* +lookup-bits+ 2))) :element-type '(unsigned-byte 16)))
|
|
|
|
|
+(defvar *lookup-ij* (make-array (ash 1 (+ 2 (* +lookup-bits+ 2))) :element-type '(unsigned-byte 16)))
|
|
|
|
|
+(defparameter +ij-to-pos+
|
|
|
|
|
+ #(#(0 1 3 2) ; canonical order
|
|
|
|
|
+ #(0 3 1 2) ; axes swapped
|
|
|
|
|
+ #(2 3 1 0) ; bits inverted
|
|
|
|
|
+ #(2 1 3 0)); swapped & inverted
|
|
|
|
|
+ "IJtoPos[orientation][ij] -> pos")
|
|
|
|
|
+(defparameter +pos-to-ij+
|
|
|
|
|
+ #(#(0 1 3 2) ; canonical order: (0,0), (0,1), (1,1), (1,0)
|
|
|
|
|
+ #(0 2 3 1) ; axes swapped: (0,0), (1,0), (1,1), (0,1)
|
|
|
|
|
+ #(3 2 0 1) ; bits inverted: (1,1), (1,0), (0,0), (0,1)
|
|
|
|
|
+ #(3 1 0 2)); swapped & inverted: (1,1), (0,1), (0,0), (1,0)
|
|
|
|
|
+ "PosToIJ[orientation][pos] -> ij")
|
|
|
|
|
+(defparameter +pos-to-orient+
|
|
|
|
|
+ (make-array 4 :element-type '(unsigned-byte 8)
|
|
|
|
|
+ :initial-contents (list +swap-mask+ 0 0 (logior +swap-mask+ +invert-mask+)))
|
|
|
|
|
+ "PosToOrientation[pos] -> orientation_modifier")
|
|
|
|
|
+
|
|
|
|
|
+(defun init-lookup ()
|
|
|
|
|
+ (labels ((init-lookup-cell (level i j orig-orient pos orient)
|
|
|
|
|
+ (if (= level +lookup-bits+)
|
|
|
|
|
+ (let ((ij (+ (ash i +lookup-bits+) j)))
|
|
|
|
|
+ (setf (aref *lookup-pos* (+ (ash ij 2) orig-orient)) (+ (ash pos 2) orient))
|
|
|
|
|
+ (setf (aref *lookup-ij* (+ (ash pos 2) orig-orient)) (+ (ash ij 2) orient)))
|
|
|
|
|
+ (let ((level (1+ level))
|
|
|
|
|
+ (i (ash i 1))
|
|
|
|
|
+ (j (ash j 1))
|
|
|
|
|
+ (pos (ash pos 2))
|
|
|
|
|
+ (r (aref +pos-to-ij+ orient)))
|
|
|
|
|
+ (init-lookup-cell level (+ i (ash (aref r 0) -1)) (+ j (logand (aref r 0) 1))
|
|
|
|
|
+ orig-orient pos (logxor orient (aref +pos-to-orient+ 0)))
|
|
|
|
|
+ (init-lookup-cell level (+ i (ash (aref r 1) -1)) (+ j (logand (aref r 1) 1))
|
|
|
|
|
+ orig-orient (+ pos 1) (logxor orient (aref +pos-to-orient+ 1)))
|
|
|
|
|
+ (init-lookup-cell level (+ i (ash (aref r 2) -1)) (+ j (logand (aref r 2) 1))
|
|
|
|
|
+ orig-orient (+ pos 2) (logxor orient (aref +pos-to-orient+ 2)))
|
|
|
|
|
+ (init-lookup-cell level (+ i (ash (aref r 3) -1)) (+ j (logand (aref r 3) 1))
|
|
|
|
|
+ orig-orient (+ pos 3) (logxor orient (aref +pos-to-orient+ 3)))))))
|
|
|
|
|
+ (init-lookup-cell 0 0 0 0 0 0)
|
|
|
|
|
+ (init-lookup-cell 0 0 0 +swap-mask+ 0 +swap-mask+)
|
|
|
|
|
+ (init-lookup-cell 0 0 0 +invert-mask+ 0 +invert-mask+)
|
|
|
|
|
+ (init-lookup-cell 0 0 0 (logior +swap-mask+ +invert-mask+) 0 (logior +swap-mask+ +invert-mask+))))
|
|
|
|
|
+
|
|
|
|
|
+(eval-when (:execute :compile-toplevel :load-toplevel)
|
|
|
|
|
+ (init-lookup))
|
|
|
|
|
+
|
|
|
|
|
+(defun from-face-ij (face i j)
|
|
|
|
|
+ (let ((n (ash face (1- +pos-bits+)))
|
|
|
|
|
+ (bits (logand face +swap-mask+)))
|
|
|
|
|
+ (macrolet ((get-bits (k)
|
|
|
|
|
+ `(let ((mask (1- (ash 1 +lookup-bits+))))
|
|
|
|
|
+ (setf bits
|
|
|
|
|
+ (aref *lookup-pos*
|
|
|
|
|
+ (+ bits
|
|
|
|
|
+ (ash (logand mask (ash i (- (* ,k +lookup-bits+)))) (+ +lookup-bits+ 2))
|
|
|
|
|
+ (ash (logand mask (ash j (- (* ,k +lookup-bits+)))) 2))))
|
|
|
|
|
+ (setf n (logior n (ash (ash bits -2)
|
|
|
|
|
+ (* ,k 2 +lookup-bits+)))
|
|
|
|
|
+ bits (logand bits (logior +swap-mask+ +invert-mask+))))))
|
|
|
|
|
+ (get-bits 7)
|
|
|
|
|
+ (get-bits 6)
|
|
|
|
|
+ (get-bits 5)
|
|
|
|
|
+ (get-bits 4)
|
|
|
|
|
+ (get-bits 3)
|
|
|
|
|
+ (get-bits 2)
|
|
|
|
|
+ (get-bits 1)
|
|
|
|
|
+ (get-bits 0))
|
|
|
|
|
+ (1+ (* 2 n))))
|
|
|
|
|
+
|
|
|
|
|
+(defun point-to-cell (p)
|
|
|
|
|
+ (multiple-value-bind (face u v)
|
|
|
|
|
+ (xyz-to-face-uv p)
|
|
|
|
|
+ (from-face-ij face
|
|
|
|
|
+ (st-to-ij (uv-to-st u))
|
|
|
|
|
+ (st-to-ij (uv-to-st v)))))
|
|
|
|
|
+
|
|
|
|
|
+(defun cell-to-face-ij-orientation (id)
|
|
|
|
|
+ (let* ((i 0)
|
|
|
|
|
+ (j 0)
|
|
|
|
|
+ (face (cell-face id))
|
|
|
|
|
+ (bits (logand face +swap-mask+)))
|
|
|
|
|
+ (macrolet ((get-bits (k)
|
|
|
|
|
+ `(let ((nbits (if (= ,k 7) (- +max-level+ (* 7 +lookup-bits+)) +lookup-bits+)))
|
|
|
|
|
+ (setf bits (aref *lookup-ij*
|
|
|
|
|
+ (+ bits
|
|
|
|
|
+ (ash (logand (ash id (- (1+ (* ,k 2 +lookup-bits+))))
|
|
|
|
|
+ (1- (ash 1 (* 2 nbits)))) 2))))
|
|
|
|
|
+ (setf i (+ i (ash (ash bits (- (+ +lookup-bits+ 2)))
|
|
|
|
|
+ (* ,k +lookup-bits+)))
|
|
|
|
|
+ j (+ j (ash (logand (ash bits -2)
|
|
|
|
|
+ (1- (ash 1 +lookup-bits+)))
|
|
|
|
|
+ (* ,k +lookup-bits+)))
|
|
|
|
|
+ bits (logand bits (logior +swap-mask+ +invert-mask+))))))
|
|
|
|
|
+ (get-bits 7)
|
|
|
|
|
+ (get-bits 6)
|
|
|
|
|
+ (get-bits 5)
|
|
|
|
|
+ (get-bits 4)
|
|
|
|
|
+ (get-bits 3)
|
|
|
|
|
+ (get-bits 2)
|
|
|
|
|
+ (get-bits 1)
|
|
|
|
|
+ (get-bits 0)
|
|
|
|
|
+ (values face i j (logxor bits (if (zerop (logand (cell-lsb id) #x1111111111111110)) 0 +swap-mask+))))))
|
|
|
|
|
+
|
|
|
|
|
+(defun cell-get-center-face-si-ti (id)
|
|
|
|
|
+ (multiple-value-bind (face i j orient) (cell-to-face-ij-orientation id)
|
|
|
|
|
+ (declare (ignore orient))
|
|
|
|
|
+ (let ((delta (if (cell-is-leaf id) 1 (if (zerop (logand 1 (logxor i (ash id -2)))) 0 2))))
|
|
|
|
|
+ (values face (+ delta (* 2 i)) (+ delta (* 2 j))))))
|
|
|
|
|
+
|
|
|
|
|
+(defun face-si-ti-to-xyz (face si ti)
|
|
|
|
|
+ (face-uv-ti-xyz face
|
|
|
|
|
+ (st-to-uv (si-ti-to-st si))
|
|
|
|
|
+ (st-to-uv (si-ti-to-st ti))))
|
|
|
|
|
+
|
|
|
|
|
+(defun face-uv-ti-xyz (face u v)
|
|
|
|
|
+ (declare (type double-float u v))
|
|
|
|
|
+ (ecase face
|
|
|
|
|
+ (0 (make-point :x 1d0 :y u :z v))
|
|
|
|
|
+ (1 (make-point :x (- u) :y 1d0 :z v))
|
|
|
|
|
+ (2 (make-point :x (- u) :y (- v) :z 1d0))
|
|
|
|
|
+ (3 (make-point :x -1d0 :y (- v) :z (- u)))
|
|
|
|
|
+ (4 (make-point :x v :y -1d0 :z (- u)))
|
|
|
|
|
+ (5 (make-point :x v :y u :z -1d0))))
|
|
|
|
|
+
|
|
|
|
|
+(defun si-ti-to-st (si)
|
|
|
|
|
+ (assert (<= si +max-si-ti+))
|
|
|
|
|
+ (* si (/ 1d0 +max-si-ti+)))
|
|
|
|
|
+
|
|
|
|
|
+(defun cell-to-point-raw (id)
|
|
|
|
|
+ (apply #'face-si-ti-to-xyz (multiple-value-list (cell-get-center-face-si-ti id))))
|
|
|
|
|
+
|
|
|
|
|
+(defun find-lsb-set (num)
|
|
|
|
|
+ (loop for i upto 63 when (logbitp i num) return i))
|
|
|
|
|
+
|
|
|
|
|
+(defun find-msb-set (num)
|
|
|
|
|
+ (loop for i from 63 downto 0 when (logbitp i num) return i))
|
|
|
|
|
+
|
|
|
|
|
+(defun lsb-for-level (level)
|
|
|
|
|
+ (ash 1 (* 2 (- +max-level+ level))))
|
|
|
|
|
+
|
|
|
|
|
+(defun cell-face (id)
|
|
|
|
|
+ (ash id (- +pos-bits+)))
|
|
|
|
|
+
|
|
|
|
|
+(defun cell-lsb (id)
|
|
|
|
|
+ (logand id (1+ (lognot id))))
|
|
|
|
|
+
|
|
|
|
|
+(defun cell-level (id)
|
|
|
|
|
+ (assert (not (zerop id)))
|
|
|
|
|
+ (- +max-level+ (ash (find-lsb-set id) -1)))
|
|
|
|
|
+
|
|
|
|
|
+(defun cell-pos (id)
|
|
|
|
|
+ (logand id (lognot 0)))
|
|
|
|
|
+
|
|
|
|
|
+(defun cell-is-valid (id)
|
|
|
|
|
+ (and (< (cell-face id) +num-faces+)
|
|
|
|
|
+ (not (zerop (logand (cell-lsb id) #x1555555555555555)))))
|
|
|
|
|
+
|
|
|
|
|
+(defun cell-child-position (id &optional level)
|
|
|
|
|
+ (unless level (setf level (cell-level id)))
|
|
|
|
|
+ (assert (cell-is-valid id))
|
|
|
|
|
+ (assert (>= level 1))
|
|
|
|
|
+ (assert (<= level (cell-level id)))
|
|
|
|
|
+ (logand 3 (ash id (- (1+ (* 2 (- +max-level+ level)))))))
|
|
|
|
|
+
|
|
|
|
|
+(defun cell-range-min (id)
|
|
|
|
|
+ (- id (1- (cell-lsb id)) ))
|
|
|
|
|
+(defun cell-range-max (id)
|
|
|
|
|
+ (+ id (1- (cell-lsb id))))
|
|
|
|
|
+(defun cell-is-leaf (id)
|
|
|
|
|
+ (not (zerop (logand id 1))))
|
|
|
|
|
+(defun cell-is-face (id)
|
|
|
|
|
+ (zerop (logand id (1- (lsb-for-level 0)))))
|
|
|
|
|
+
|
|
|
|
|
+(defun cell-parent (id &optional level)
|
|
|
|
|
+ (assert (cell-is-valid id))
|
|
|
|
|
+ (if level (progn
|
|
|
|
|
+ (assert (>= level 0))
|
|
|
|
|
+ (assert (<= level (cell-level id))))
|
|
|
|
|
+ (progn (assert (not (cell-is-face id)))))
|
|
|
|
|
+ (let ((new-lsb (if level (lsb-for-level level) (ash (cell-lsb id) 2))))
|
|
|
|
|
+ (logior new-lsb (logand id (1+ (lognot new-lsb))))))
|
|
|
|
|
+
|
|
|
|
|
+(defun cell-child (id pos)
|
|
|
|
|
+ (assert (cell-is-valid id))
|
|
|
|
|
+ (assert (not (cell-is-leaf id)))
|
|
|
|
|
+ (+ id (* (+ (* 2 pos) 1 -4) (ash (cell-lsb id) -2))))
|
|
|
|
|
+
|
|
|
|
|
+(defun cell-to-string (id)
|
|
|
|
|
+ (format nil "~a/~{~a~}" (cell-face id)
|
|
|
|
|
+ (loop for level from 1 to (cell-level id)
|
|
|
|
|
+ collect (cell-child-position id level))))
|
|
|
|
|
+
|
|
|
|
|
+;;;;;;;;;
|
|
|
|
|
+;;;
|
|
|
|
|
+(defun make-span (vector offset &optional size)
|
|
|
|
|
+ (declare (type vector vector))
|
|
|
|
|
+ (let ((length (length vector)))
|
|
|
|
|
+ (assert (< offset length))
|
|
|
|
|
+ (when size (assert (< (+ offset size) length)))
|
|
|
|
|
+ (make-array (if size size (- length offset))
|
|
|
|
|
+ :element-type (or (cadr (type-of vector)) t)
|
|
|
|
|
+ :displaced-to vector
|
|
|
|
|
+ :displaced-index-offset offset)))
|
|
|
|
|
+
|
|
|
|
|
+(deftype byte-vector () `(vector (unsigned-byte 8)))
|
|
|
|
|
+
|
|
|
|
|
+(defun make-encoder (size)
|
|
|
|
|
+ (make-array size :element-type '(unsigned-byte 8) :fill-pointer 0 :adjustable t))
|
|
|
|
|
+
|
|
|
|
|
+(defun encoder-avail (encoder)
|
|
|
|
|
+ (declare (type byte-vector encoder))
|
|
|
|
|
+ (- (array-total-size encoder)
|
|
|
|
|
+ (fill-pointer encoder)))
|
|
|
|
|
+
|
|
|
|
|
+(defun encoder-ensure (encoder size)
|
|
|
|
|
+ (declare (type byte-vector encoder))
|
|
|
|
|
+ (when (< (encoder-avail encoder) size)
|
|
|
|
|
+ (adjust-array encoder (+ (fill-pointer encoder) size))))
|
|
|
|
|
+
|
|
|
|
|
+(defun encoder-put8 (encoder value)
|
|
|
|
|
+ (declare (type byte-vector encoder)
|
|
|
|
|
+ (type (unsigned-byte 8) value))
|
|
|
|
|
+ (assert (> (encoder-avail encoder) 1))
|
|
|
|
|
+ (vector-push value encoder)
|
|
|
|
|
+ encoder)
|
|
|
|
|
+
|
|
|
|
|
+(defun encoder-putn (encoder vector)
|
|
|
|
|
+ (declare (type byte-vector encoder)
|
|
|
|
|
+ (type byte-vector vector))
|
|
|
|
|
+ (loop for value across vector do (vector-push value encoder))
|
|
|
|
|
+ encoder)
|
|
|
|
|
+
|
|
|
|
|
+(defun encoder-length (encoder)
|
|
|
|
|
+ (declare (type byte-vector encoder))
|
|
|
|
|
+ (fill-pointer encoder))
|
|
|
|
|
+
|
|
|
|
|
+(defparameter +varint-max32+ 5 "Maximum varint encoding length for uint32")
|
|
|
|
|
+(defun encoder-put-varint32 (encoder v)
|
|
|
|
|
+ (declare (type byte-vector encoder)
|
|
|
|
|
+ (type (unsigned-byte 32) v))
|
|
|
|
|
+ (let ((b 128))
|
|
|
|
|
+ (cond
|
|
|
|
|
+ ((< v (ash 1 7)) (encoder-put8 encoder v))
|
|
|
|
|
+ ((< v (ash 1 14))
|
|
|
|
|
+ (encoder-put8 encoder (logand 255 (logior v b)))
|
|
|
|
|
+ (encoder-put8 encoder (logand 255 (ash v -7))))
|
|
|
|
|
+ ((< v (ash 1 21))
|
|
|
|
|
+ (encoder-put8 encoder (logand 255 (logior v b)))
|
|
|
|
|
+ (encoder-put8 encoder (logand 255 (logior (ash v -7) b)))
|
|
|
|
|
+ (encoder-put8 encoder (logand 255 (ash v -14))))
|
|
|
|
|
+ ((< v (ash 1 28))
|
|
|
|
|
+ (encoder-put8 encoder (logand 255 (logior v b)))
|
|
|
|
|
+ (encoder-put8 encoder (logand 255 (logior (ash v -7) b)))
|
|
|
|
|
+ (encoder-put8 encoder (logand 255 (logior (ash v -14) b)))
|
|
|
|
|
+ (encoder-put8 encoder (logand 255 (ash v -21))))
|
|
|
|
|
+ (t
|
|
|
|
|
+ (encoder-put8 encoder (logand 255 (logior v b)))
|
|
|
|
|
+ (encoder-put8 encoder (logand 255 (logior (ash v -7) b)))
|
|
|
|
|
+ (encoder-put8 encoder (logand 255 (logior (ash v -14) b)))
|
|
|
|
|
+ (encoder-put8 encoder (logand 255 (logior (ash v -21) b)))
|
|
|
|
|
+ (encoder-put8 encoder (logand 255 (ash v -28))))))
|
|
|
|
|
+ encoder)
|
|
|
|
|
+
|
|
|
|
|
+(defparameter +varint-max64+ 10 "Maximum varint encoding length for uint64")
|
|
|
|
|
+(defun encoder-put-varint64 (encoder v)
|
|
|
|
|
+ (declare (type byte-vector encoder)
|
|
|
|
|
+ (type (unsigned-byte 64) v))
|
|
|
|
|
+ (if (< v (ash 1 28))
|
|
|
|
|
+ (encoder-put-varint32 encoder v)
|
|
|
|
|
+ (let ((x32 (logand (1- (ash 1 32)) (logior v (ash 1 7) (ash 1 21))))
|
|
|
|
|
+ (y32 (logand (1- (ash 1 32)) (logior v (ash 1 14) (ash 1 28)))))
|
|
|
|
|
+ (encoder-put8 encoder (logand 255 x32))
|
|
|
|
|
+ (encoder-put8 encoder (logand 255 (ash y32 -7)))
|
|
|
|
|
+ (encoder-put8 encoder (logand 255 (ash x32 -14)))
|
|
|
|
|
+ (encoder-put8 encoder (logand 255 (ash y32 -21)))
|
|
|
|
|
+ (if (< v (ash 1 35))
|
|
|
|
|
+ (encoder-put8 encoder (logand 255 (ash v -28)))
|
|
|
|
|
+ (progn
|
|
|
|
|
+ (encoder-put8 encoder (logand 255 (logior (ash v -28) (ash 1 7))))
|
|
|
|
|
+ (encoder-put-varint32 encoder (ash v -35)))))))
|
|
|
|
|
+
|
|
|
|
|
+;;; decoder ;;;
|
|
|
|
|
+(defun make-decoder (size &key (fill-pointer 0) initial-contents initial-element displaced-to)
|
|
|
|
|
+ (apply #'make-array size
|
|
|
|
|
+ :element-type '(unsigned-byte 8)
|
|
|
|
|
+ :fill-pointer fill-pointer
|
|
|
|
|
+ (append
|
|
|
|
|
+ (when initial-contents `(:initial-contents ,initial-contents))
|
|
|
|
|
+ (when initial-element `(:initial-element ,initial-element))
|
|
|
|
|
+ (when displaced-to `(:displaced-to ,displaced-to :displaced-index-offset ,(fill-pointer displaced-to))))))
|
|
|
|
|
+
|
|
|
|
|
+(defun decoder-avail (decoder)
|
|
|
|
|
+ (declare (type byte-vector decoder))
|
|
|
|
|
+ (- (array-total-size decoder)
|
|
|
|
|
+ (fill-pointer decoder)))
|
|
|
|
|
+
|
|
|
|
|
+(defun decoder-skip (decoder &optional (count 1))
|
|
|
|
|
+ (declare (type byte-vector decoder)
|
|
|
|
|
+ (type (unsigned-byte 32) count))
|
|
|
|
|
+ (incf (fill-pointer decoder) count))
|
|
|
|
|
+
|
|
|
|
|
+(defun decoder-reset (decoder)
|
|
|
|
|
+ (declare (type byte-vector decoder))
|
|
|
|
|
+ (setf (fill-pointer decoder) 0)
|
|
|
|
|
+ decoder)
|
|
|
|
|
+
|
|
|
|
|
+(defun make-sub-decoder (decoder size &optional will-decode)
|
|
|
|
|
+ (when (>= (decoder-avail decoder) size)
|
|
|
|
|
+ (prog1 (make-decoder size :fill-pointer (if will-decode 0 size) :displaced-to decoder)
|
|
|
|
|
+ (decoder-skip decoder size))))
|
|
|
|
|
+
|
|
|
|
|
+(defmacro with-decoder-reset ((decoder &optional (offset 0)) &body body)
|
|
|
|
|
+ (let ((fp (gensym "FP"))
|
|
|
|
|
+ (dc (gensym "DC")))
|
|
|
|
|
+ `(let* ((,dc ,decoder)
|
|
|
|
|
+ (,fp (fill-pointer ,dc)))
|
|
|
|
|
+ (unwind-protect
|
|
|
|
|
+ (progn
|
|
|
|
|
+ (setf (fill-pointer ,dc) ,offset)
|
|
|
|
|
+ ,@body)
|
|
|
|
|
+ (setf (fill-pointer ,dc) ,fp)))))
|
|
|
|
|
+
|
|
|
|
|
+(defun decoder-get8 (decoder)
|
|
|
|
|
+ (declare (type byte-vector decoder))
|
|
|
|
|
+ (prog1 (aref decoder (fill-pointer decoder))
|
|
|
|
|
+ (decoder-skip decoder)))
|
|
|
|
|
+
|
|
|
|
|
+(defun decoder-peek (decoder &optional (offset 0))
|
|
|
|
|
+ (declare (type byte-vector decoder)
|
|
|
|
|
+ (type (unsigned-byte 32) offset))
|
|
|
|
|
+ (aref decoder (+ (fill-pointer decoder) offset)))
|
|
|
|
|
+
|
|
|
|
|
+(defun decoder-get-varint64 (decoder)
|
|
|
|
|
+ (declare (type byte-vector decoder))
|
|
|
|
|
+ (loop
|
|
|
|
|
+ for b = (decoder-get8 decoder) then (decoder-get8 decoder)
|
|
|
|
|
+ for i from 0
|
|
|
|
|
+ with result = 0
|
|
|
|
|
+ do (incf result (ash (if (zerop i) b (1- b)) (* i 7)))
|
|
|
|
|
+ until (< b 128)
|
|
|
|
|
+ finally (return result)))
|
|
|
|
|
+
|
|
|
|
|
+;;;
|
|
|
|
|
+;;; encoded-uint-vector ;;;
|
|
|
|
|
+;;;
|
|
|
|
|
+(defun encode-uint-with-length (value length encoder)
|
|
|
|
|
+ (declare (type integer value)
|
|
|
|
|
+ (type (integer 0 8) length)
|
|
|
|
|
+ (type byte-vector encoder))
|
|
|
|
|
+ (assert (>= (encoder-avail encoder) length))
|
|
|
|
|
+ (loop repeat length
|
|
|
|
|
+ do (encoder-put8 encoder (logand value 255))
|
|
|
|
|
+ do (setf value (ash value -8)))
|
|
|
|
|
+ (assert (zerop value))
|
|
|
|
|
+ (values))
|
|
|
|
|
+
|
|
|
|
|
+(defun get-uint-with-length (decoder length)
|
|
|
|
|
+ (declare (type byte-vector decoder)
|
|
|
|
|
+ (type (integer 0 8) length))
|
|
|
|
|
+ (let ((value 0))
|
|
|
|
|
+ (loop for i from (1- length) downto 0
|
|
|
|
|
+ do (setf value (+ (ash value 8)
|
|
|
|
|
+ (decoder-peek decoder i))))
|
|
|
|
|
+ (decoder-skip decoder length)
|
|
|
|
|
+ value))
|
|
|
|
|
+
|
|
|
|
|
+(defun get-type-byte-size (v-type)
|
|
|
|
|
+ (values
|
|
|
|
|
+ (typecase v-type
|
|
|
|
|
+ (list (case (car v-type)
|
|
|
|
|
+ ((array simple-array vector) (get-type-byte-size (cadr v-type)))
|
|
|
|
|
+ ((unsigned-byte signed-byte) (ceiling (cadr v-type) 8))
|
|
|
|
|
+ (integer (when (cadr v-type) (ceiling (log (cadr v-type) 2) 8)))
|
|
|
|
|
+ (t nil)))
|
|
|
|
|
+ (symbol (when (eql v-type 'fixnum) 8))
|
|
|
|
|
+ (t nil))))
|
|
|
|
|
+
|
|
|
|
|
+(defun encode-uint-vector (v encoder)
|
|
|
|
|
+ (declare (type vector v)
|
|
|
|
|
+ (type byte-vector encoder))
|
|
|
|
|
+ (let ((length (1+ (ash (find-msb-set
|
|
|
|
|
+ (loop
|
|
|
|
|
+ for value across v
|
|
|
|
|
+ with bits = 1
|
|
|
|
|
+ do (setf bits (logior bits value))
|
|
|
|
|
+ finally (return bits)))
|
|
|
|
|
+ -3))))
|
|
|
|
|
+ (assert (<= 1 length 8))
|
|
|
|
|
+ (encoder-ensure encoder (+ (* (length v) length)
|
|
|
|
|
+ +varint-max64+))
|
|
|
|
|
+ (encoder-put-varint64 encoder
|
|
|
|
|
+ (logior (* (length v) (get-type-byte-size (type-of v)))
|
|
|
|
|
+ (1- length)))
|
|
|
|
|
+ (loop for value across v
|
|
|
|
|
+ do (encode-uint-with-length value length encoder))
|
|
|
|
|
+ encoder))
|
|
|
|
|
+
|
|
|
|
|
+(defstruct encoded-uint-vector
|
|
|
|
|
+ (size 0 :type (unsigned-byte 32))
|
|
|
|
|
+ (length 1 :type (integer 1 8))
|
|
|
|
|
+ (bytes 8 :type (member 1 2 4 8))
|
|
|
|
|
+ (data nil :type byte-vector))
|
|
|
|
|
+
|
|
|
|
|
+(defun encoded-uint-vector-init (decoder &optional (bytes 8))
|
|
|
|
|
+ (declare (type byte-vector decoder)
|
|
|
|
|
+ (type (member 1 2 4 8) bytes))
|
|
|
|
|
+ (let ((size-len (decoder-get-varint64 decoder)))
|
|
|
|
|
+ (when size-len
|
|
|
|
|
+ (let* ((size (floor size-len bytes))
|
|
|
|
|
+ (length (1+ (logand size-len (1- bytes))))
|
|
|
|
|
+ (bytes-length (* size length))
|
|
|
|
|
+ (data (make-sub-decoder decoder bytes-length)))
|
|
|
|
|
+ (when data
|
|
|
|
|
+ (make-encoded-uint-vector :size size :length length :bytes bytes
|
|
|
|
|
+ :data data))))))
|
|
|
|
|
+
|
|
|
|
|
+(defun encoded-uint-vector-get (euv pos)
|
|
|
|
|
+ (declare (type encoded-uint-vector euv)
|
|
|
|
|
+ (type (unsigned-byte 32) pos))
|
|
|
|
|
+ (with-slots (size data length) euv
|
|
|
|
|
+ (assert (< pos size))
|
|
|
|
|
+ (with-decoder-reset (data (* pos length))
|
|
|
|
|
+ (get-uint-with-length data length))))
|
|
|
|
|
+
|
|
|
|
|
+(defun encoded-uint-vector-decode (euv)
|
|
|
|
|
+ (declare (type encoded-uint-vector euv))
|
|
|
|
|
+ (let* ((size (encoded-uint-vector-size euv))
|
|
|
|
|
+ (result (make-array size :element-type '(unsigned-byte 64))))
|
|
|
|
|
+ (dotimes (i size result)
|
|
|
|
|
+ (setf (aref result i) (encoded-uint-vector-get euv i)))))
|
|
|
|
|
+
|
|
|
|
|
+;; encoded-string-vector
|
|
|
|
|
+(defstruct string-vector-encoder
|
|
|
|
|
+ (offsets (make-array 0 :element-type '(unsigned-byte 64) :adjustable t :fill-pointer 0)
|
|
|
|
|
+ :type (vector (unsigned-byte 64)))
|
|
|
|
|
+ (data (make-encoder 0) :type byte-vector))
|
|
|
|
|
+
|
|
|
|
|
+(defun string-vector-encoder-add-via-encoder (sve)
|
|
|
|
|
+ (declare (type string-vector-encoder sve))
|
|
|
|
|
+ (with-slots (offsets data) sve
|
|
|
|
|
+ (vector-push-extend (length data) offsets)
|
|
|
|
|
+ data))
|
|
|
|
|
+
|
|
|
|
|
+(defun string-vector-encoder-size (sve)
|
|
|
|
|
+ (declare (type string-vector-encoder sve))
|
|
|
|
|
+ (length (string-vector-encoder-offsets sve)))
|
|
|
|
|
+
|
|
|
|
|
+(defun string-vector-encoder-encode (sve encoder)
|
|
|
|
|
+ (declare (type string-vector-encoder sve)
|
|
|
|
|
+ (type byte-vector encoder))
|
|
|
|
|
+ (with-slots (offsets data) sve
|
|
|
|
|
+ (vector-push-extend (length data) offsets)
|
|
|
|
|
+ (encode-uint-vector (make-span offsets 1) encoder)
|
|
|
|
|
+ (encoder-ensure encoder (encoder-length data))
|
|
|
|
|
+ (encoder-putn encoder data)
|
|
|
|
|
+ encoder))
|
|
|
|
|
+
|
|
|
|
|
+(defstruct encoded-string-vector
|
|
|
|
|
+ (offsets nil :type encoded-uint-vector)
|
|
|
|
|
+ (data nil :type byte-vector))
|
|
|
|
|
+
|
|
|
|
|
+(defun encoded-string-vector-init (decoder)
|
|
|
|
|
+ (declare (type byte-vector decoder))
|
|
|
|
|
+ (let ((offsets (encoded-uint-vector-init decoder 8)))
|
|
|
|
|
+ (when offsets
|
|
|
|
|
+ (let* ((size (encoded-uint-vector-size offsets))
|
|
|
|
|
+ (length (if (zerop size) 0 (encoded-uint-vector-get offsets (1- size))))
|
|
|
|
|
+ (data (make-sub-decoder decoder length)))
|
|
|
|
|
+ (when data
|
|
|
|
|
+ (make-encoded-string-vector :offsets offsets :data data))))))
|
|
|
|
|
+
|
|
|
|
|
+(defun encoded-string-vector-size (esv)
|
|
|
|
|
+ (declare (type encoded-string-vector esv))
|
|
|
|
|
+ (encoded-uint-vector-size (encoded-string-vector-offsets esv)))
|
|
|
|
|
+
|
|
|
|
|
+(defun encoded-string-vector-get (esv index &optional fill-pointer)
|
|
|
|
|
+ (declare (type encoded-string-vector esv)
|
|
|
|
|
+ (type (unsigned-byte 32) index))
|
|
|
|
|
+ (with-slots (offsets data) esv
|
|
|
|
|
+ (let* ((start (if (zerop index) 0 (encoded-uint-vector-get offsets (1- index))))
|
|
|
|
|
+ (length (- (encoded-uint-vector-get offsets index) start)))
|
|
|
|
|
+ (with-decoder-reset (data start)
|
|
|
|
|
+ (make-decoder length :displaced-to data :fill-pointer fill-pointer)))))
|
|
|
|
|
+
|
|
|
|
|
+(defun encoded-string-vector-decode (esv)
|
|
|
|
|
+ (declare (type encoded-string-vector esv))
|
|
|
|
|
+ (let* ((size (encoded-string-vector-size esv))
|
|
|
|
|
+ (result (make-array size :element-type '(vector (unsigned-byte 8)))))
|
|
|
|
|
+ (dotimes (i size result)
|
|
|
|
|
+ (setf (aref result i) (encoded-string-vector-get esv i)))))
|
|
|
|
|
+
|
|
|
|
|
+;; encoded-cell-id-vector
|
|
|
|
|
+(defstruct encoded-cell-id-vector
|
|
|
|
|
+ (deltas nil :type encoded-uint-vector)
|
|
|
|
|
+ (base 0 :type (unsigned-byte 64))
|
|
|
|
|
+ (shift 0 :type (unsigned-byte 8)))
|
|
|
|
|
+
|
|
|
|
|
+(defun encoded-cell-id-vector-size (ecv)
|
|
|
|
|
+ (declare (type encoded-cell-id-vector ecv))
|
|
|
|
|
+ (with-slots (deltas) ecv
|
|
|
|
|
+ (when deltas
|
|
|
|
|
+ (encoded-uint-vector-size deltas))))
|
|
|
|
|
+
|
|
|
|
|
+(defun encoded-cell-id-vector-get (ecv i)
|
|
|
|
|
+ (declare (type encoded-cell-id-vector ecv)
|
|
|
|
|
+ (type (unsigned-byte 32) i))
|
|
|
|
|
+ (with-slots (deltas base shift) ecv
|
|
|
|
|
+ (+ base
|
|
|
|
|
+ (ash (encoded-uint-vector-get deltas i) shift))))
|
|
|
|
|
+
|
|
|
|
|
+(defun encoded-cell-id-vector-init (decoder)
|
|
|
|
|
+ (declare (type byte-vector decoder))
|
|
|
|
|
+ (when (>= (decoder-avail decoder) 2)
|
|
|
|
|
+ (let* ((code+len (decoder-get8 decoder))
|
|
|
|
|
+ (shift-code (ash code+len -3)))
|
|
|
|
|
+ (when (= shift-code 31)
|
|
|
|
|
+ (setf shift-code (+ 29 (decoder-get8 decoder))))
|
|
|
|
|
+ (let* ((base-len (logand code+len 7))
|
|
|
|
|
+ (base (get-uint-with-length decoder base-len))
|
|
|
|
|
+ shift)
|
|
|
|
|
+ (when base
|
|
|
|
|
+ (setf base (ash base (- 64 (* 8 (max 1 base-len)))))
|
|
|
|
|
+ (if (>= shift-code 29)
|
|
|
|
|
+ (setf shift (1+ (* 2 (- shift-code 29)))
|
|
|
|
|
+ base (logior base (ash 1 (1- shift))))
|
|
|
|
|
+ (setf shift (* 2 shift-code)))
|
|
|
|
|
+ (make-encoded-cell-id-vector
|
|
|
|
|
+ :deltas (encoded-uint-vector-init decoder 8)
|
|
|
|
|
+ :base base
|
|
|
|
|
+ :shift shift))))))
|
|
|
|
|
+
|
|
|
|
|
+(defun encoded-cell-id-vector-decode (eciv)
|
|
|
|
|
+ (declare (type encoded-cell-id-vector eciv))
|
|
|
|
|
+ (let* ((size (encoded-cell-id-vector-size eciv))
|
|
|
|
|
+ (result (make-array size :element-type '(unsigned-byte 64))))
|
|
|
|
|
+ (dotimes (i size result)
|
|
|
|
|
+ (setf (aref result i) (encoded-cell-id-vector-get eciv i)))))
|
|
|
|
|
+
|
|
|
|
|
+(defun encode-cell-id-vector (v encoder)
|
|
|
|
|
+ (declare (type (vector (unsigned-byte 64)) v)
|
|
|
|
|
+ (type byte-vector encoder))
|
|
|
|
|
+ (destructuring-bind (v-or v-and v-min v-max)
|
|
|
|
|
+ (loop for cell-id across v
|
|
|
|
|
+ with v-or = 0
|
|
|
|
|
+ with v-and = -1
|
|
|
|
|
+ do (setf v-or (logior v-or cell-id)
|
|
|
|
|
+ v-and (logand v-and cell-id))
|
|
|
|
|
+ maximizing cell-id into v-max
|
|
|
|
|
+ minimizing cell-id into v-min
|
|
|
|
|
+ finally (return (list v-or v-and v-min v-max)))
|
|
|
|
|
+ (let ((e-base 0)
|
|
|
|
|
+ (e-base-len 0)
|
|
|
|
|
+ (e-shift 0)
|
|
|
|
|
+ (e-max-delta-msb 0))
|
|
|
|
|
+ (when (> v-or 0)
|
|
|
|
|
+ (setf e-shift (min 56 (dpb 0 (byte 1 0) (find-lsb-set v-or))))
|
|
|
|
|
+ (unless (zerop (logand v-and (ash 1 e-shift)))
|
|
|
|
|
+ (incf e-shift))
|
|
|
|
|
+ (let ((e-bytes (1- (ash 1 65))))
|
|
|
|
|
+ (dotimes (len 8)
|
|
|
|
|
+ (let* ((t-base (mask-field (byte (* 8 len) (- 64 (* 8 len))) v-min))
|
|
|
|
|
+ (t-max-delta-msb (max 0 (1- (integer-length (ash (- v-max t-base)
|
|
|
|
|
+ (- e-shift))))))
|
|
|
|
|
+ (t-bytes (+ len (* (length v) (1+ (ash t-max-delta-msb -3))))))
|
|
|
|
|
+ (when (< t-bytes e-bytes)
|
|
|
|
|
+ (setf e-base t-base
|
|
|
|
|
+ e-base-len len
|
|
|
|
|
+ e-max-delta-msb t-max-delta-msb
|
|
|
|
|
+ e-bytes t-bytes)))))
|
|
|
|
|
+ (when (and (logbitp 0 e-shift)
|
|
|
|
|
+ (not (= (logand e-max-delta-msb 7) 7)))
|
|
|
|
|
+ (decf e-shift)))
|
|
|
|
|
+ (assert (<= e-base-len 7))
|
|
|
|
|
+ (assert (<= e-shift 56))
|
|
|
|
|
+ (encoder-ensure encoder (+ 2 e-base-len))
|
|
|
|
|
+
|
|
|
|
|
+ (let ((shift-code (ash e-shift -1)))
|
|
|
|
|
+ (when (logbitp 0 e-shift)
|
|
|
|
|
+ (setf shift-code (min 31 (+ shift-code 29))))
|
|
|
|
|
+ (encoder-put8 encoder (logior (ash shift-code 3)
|
|
|
|
|
+ e-base-len))
|
|
|
|
|
+ (when (= shift-code 31)
|
|
|
|
|
+ (encoder-put8 encoder (ash e-shift -1))))
|
|
|
|
|
+
|
|
|
|
|
+ (encode-uint-with-length
|
|
|
|
|
+ (ash e-base (- (- 64 (* 8 (max 1 e-base-len))))) e-base-len encoder)
|
|
|
|
|
+
|
|
|
|
|
+ (let ((deltas (make-array (length v) :element-type '(unsigned-byte 64))))
|
|
|
|
|
+ (loop for cell-id across v
|
|
|
|
|
+ for i from 0
|
|
|
|
|
+ do (setf (aref deltas i)
|
|
|
|
|
+ (ash (- cell-id e-base) (- e-shift))))
|
|
|
|
|
+ (encode-uint-vector deltas encoder)))))
|
|
|
|
|
+
|
|
|
|
|
+;; encoded-point-vector
|
|
|
|
|
+(defstruct encoded-point-vector
|
|
|
|
|
+ (size 0 :type (unsigned-byte 32))
|
|
|
|
|
+ (blocks nil :type encoded-string-vector)
|
|
|
|
|
+ (base 0 :type (unsigned-byte 64))
|
|
|
|
|
+ (level 0 :type (unsigned-byte 8))
|
|
|
|
|
+ (have-exceptions nil :type boolean))
|
|
|
|
|
+
|
|
|
|
|
+(defstruct cell-point
|
|
|
|
|
+ (level 0 :type (unsigned-byte 8))
|
|
|
|
|
+ (face 0 :type (unsigned-byte 8))
|
|
|
|
|
+ (si 0 :type (unsigned-byte 32))
|
|
|
|
|
+ (ti 0 :type (unsigned-byte 32)))
|
|
|
|
|
+
|
|
|
|
|
+(defparameter +block-shift+ 4)
|
|
|
|
|
+(defparameter +block-size+ (ash 1 +block-shift+))
|
|
|
|
|
+
|
|
|
|
|
+(defparameter +exception+ -1)
|
|
|
|
|
+
|
|
|
|
|
+(defstruct block-code
|
|
|
|
|
+ (delta-bits 0 :type (signed-byte 32))
|
|
|
|
|
+ (offset-bits 0 :type (signed-byte 32))
|
|
|
|
|
+ (overlap-bits 0 :type (signed-byte 32)))
|
|
|
|
|
+
|
|
|
|
|
+(defun bit-mask (n)
|
|
|
|
|
+ (declare (type (integer 0 64) n))
|
|
|
|
|
+ (if (zerop n) 0
|
|
|
|
|
+ (dpb -1 (byte n 0) 0)))
|
|
|
|
|
+
|
|
|
|
|
+(defun max-bits-for-level (level)
|
|
|
|
|
+ (declare (type (integer 0 30) level))
|
|
|
|
|
+ (+ (* 2 level) 3))
|
|
|
|
|
+
|
|
|
|
|
+(defun base-shift (level base-bits)
|
|
|
|
|
+ (declare (type (integer 0 30) level)
|
|
|
|
|
+ (type (integer 0 64) base-bits))
|
|
|
|
|
+ (max 0 (- (max-bits-for-level level) base-bits)))
|
|
|
|
|
+
|
|
|
|
|
+(defun encode-point-vector-compact (points encoder)
|
|
|
|
|
+ (declare (type (vector point) points)
|
|
|
|
|
+ (type byte-vector encoder))
|
|
|
|
|
+ (multiple-value-bind (level cell-points)
|
|
|
|
|
+ (choose-best-level points)
|
|
|
|
|
+ (when (< level 0)
|
|
|
|
|
+ (return (encode-point-vector-fast points encoder)))
|
|
|
|
|
+ (multiple-value-bind (values have-exceptions) (convert-cells-to-values cell-points level)
|
|
|
|
|
+ (multiple-value-bind (base base-bits) (choose-base values level have-exceptions)
|
|
|
|
|
+ (let ((num-blocks (ash (+ (length values) +block-size+ -1) (- +block-shift+)))
|
|
|
|
|
+ (base-bytes (ash base-bits -3)))
|
|
|
|
|
+ (encoder-ensure encoder (+ 2 base-bytes))
|
|
|
|
|
+ (let ((last-block-count (- (length values) (* +block-size+ (1- num-blocks))))
|
|
|
|
|
+ (blocks (make-string-vector-encoder))
|
|
|
|
|
+ (exceptions (make-array 0 :element-type point :adjustable t)))
|
|
|
|
|
+ (assert (>= last-block-count 0))
|
|
|
|
|
+ (assert (<= last-block-count +block-size+))
|
|
|
|
|
+ (assert (<= base-bytes 7))
|
|
|
|
|
+ (assert (<= level 30))
|
|
|
|
|
+ (encoder-put8 (logior +encoded-point-vector-cell-ids+
|
|
|
|
|
+ (ash have-exceptions 3)
|
|
|
|
|
+ (ash (1- last-block-count) 4)))
|
|
|
|
|
+ (encoder-put8 (logior base-bytes
|
|
|
|
|
+ (ash level 3)))
|
|
|
|
|
+ (encode-uint-with-length (ash base (- (base-shift level base-bits))) base-bytes encoder)
|
|
|
|
|
+
|
|
|
|
|
+ (loop for i from 0 to (length values) step +block-size+
|
|
|
|
|
+ for block-size = (min +block-size+ (- (length values) i))
|
|
|
|
|
+ for code = (get-block-code values i block-size base have-exceptions)
|
|
|
|
|
+ do (let ((block (string-vector-encoder-add-via-encoder blocks))
|
|
|
|
|
+ (offset-bytes (ash (block-code-offset-bits code) -3))
|
|
|
|
|
+ (delta-nibbles (ash (block-code-delta-bits code) -2))
|
|
|
|
|
+ (overlap-nibbles (ash (block-code-overlap-bits code) -2)))
|
|
|
|
|
+ (encoder-ensure block (+ 1 offset-bytes (* delta-nibbles (ash +block-size+ -1))))
|
|
|
|
|
+ (assert (<= (- offset-bytes overlap-nibbles) 7))
|
|
|
|
|
+ (assert (<= overlap-nibbles 1))
|
|
|
|
|
+ (assert (<= delta-nibbles 16))
|
|
|
|
|
+ (encoder-put8 block (logior (- offset-bytes overlap-nibbles)
|
|
|
|
|
+ (ash overlap-nibbles 3)
|
|
|
|
|
+ (ash (1- delta-nibbles) 4)))
|
|
|
|
|
+
|
|
|
|
|
+ (let ((offset (1- (ash 1 65)))
|
|
|
|
|
+ (num-exceptions 0))
|
|
|
|
|
+ (dotimes (i block-size)
|
|
|
|
|
+ (let ((value (aref values (+ i j))))
|
|
|
|
|
+ (if (equalp value +exception+)
|
|
|
|
|
+ (incf num-exceptions)
|
|
|
|
|
+ (progn
|
|
|
|
|
+ (assert (>= value base))
|
|
|
|
|
+ (setf offset (min offset (- value base)))))))
|
|
|
|
|
+ (when (= num-exceptions block-size)
|
|
|
|
|
+ (setf offset))
|
|
|
|
|
+
|
|
|
|
|
+ (let ((offset-shift (- (block-code-delta-bits code)
|
|
|
|
|
+ (block-code-overlap-bits code))))
|
|
|
|
|
+ (setf offset (logand offset (lognot (bit-mask offset-shift))))
|
|
|
|
|
+ (assert (= (zerop offset) (zerop offset-bytes)))
|
|
|
|
|
+ (when (> offset 0)
|
|
|
|
|
+ (encode-uint-with-length (ash offset (- offset-shift)) offset-bytes block))
|
|
|
|
|
+
|
|
|
|
|
+ (let ((delta-bytes (ash (1+ delta-nibbles) -1)))
|
|
|
|
|
+ (setf (fill-pointer exceptions) 0)
|
|
|
|
|
+ (dotimes (j block-size)
|
|
|
|
|
+ (let ((delta 0)
|
|
|
|
|
+ (value (arerf values (+ i j))))
|
|
|
|
|
+ (if (equalp value +exception+)
|
|
|
|
|
+ (progn
|
|
|
|
|
+ (setf delta (length exceptions))
|
|
|
|
|
+ (vector-push-extend (aref points (+ i j)) exceptions))
|
|
|
|
|
+ (progn
|
|
|
|
|
+ (assert (>= value (+ offset base)))
|
|
|
|
|
+ (setf delta (- value (+ offset base)))
|
|
|
|
|
+ (when have-exceptions
|
|
|
|
|
+ (assert (<= delta (- (1- (ash 1 65)) +block-size+)))
|
|
|
|
|
+ (incf delta +block-size+))))
|
|
|
|
|
+ (assert (<= delta (bit-mask (block-code-delta-bits delta))))
|
|
|
|
|
+ (when (and (logbitp delta-nibbles 0)
|
|
|
|
|
+ (logbitp j 0))
|
|
|
|
|
+ ())
|
|
|
|
|
+ )))
|
|
|
|
|
+ ))))
|
|
|
|
|
+))))))
|