(in-package :cl-user) (defpackage #:ocm.s2 (:use :cl)) (in-package :ocm.s2) ;; This file contains documentation of the various coordinate systems used ;; throughout the library. Most importantly, S2 defines a framework for ;; decomposing the unit sphere into a hierarchy of "cells". Each cell is a ;; quadrilateral bounded by four geodesics. The top level of the hierarchy is ;; obtained by projecting the six faces of a cube onto the unit sphere, and ;; lower levels are obtained by subdividing each cell into four children ;; recursively. Cells are numbered such that sequentially increasing cells ;; follow a continuous space-filling curve over the entire sphere. The ;; transformation is designed to make the cells at each level fairly uniform ;; in size. ;; ;; ;; ////////////////////////// S2Cell Decomposition ///////////////////////// ;; ;; The following methods define the cube-to-sphere projection used by ;; the S2Cell decomposition. ;; ;; 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. (defconstant +swap-mask+ 1) (defconstant +invert-mask+ 2) (defconstant +max-cell-level+ 28 "This is the number of levels needed to specify a leaf cell.") (defconstant +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].") (defconstant +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+].") (deftype ij () `(integer 0 ,+limit-ij+)) (deftype si-ti () `(integer 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). (defconstant +face-bits+ 3) (defconstant +num-faces+ 6) (defconstant +max-level+ +max-cell-level+) (defconstant +pos-bits+ (1+ (* 2 +max-level+))) (defconstant +max-size+ (ash 1 +max-level+)) (deftype level () `(integer 0 ,+max-level+)) (deftype face () `(integer 0 ,(1- +num-faces+))) (deftype cell-id () `(integer 0 ,(1- (ash 1 (+ +face-bits+ +pos-bits+))))) (declaim (inline ij-to-stmin)) (defun ij-to-stmin (i) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type ij i)) (* i (/ 1d0 +limit-ij+))) (declaim (inline st-to-ij)) (defun st-to-ij (s) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (double-float s)) (max 0 (min (1- +limit-ij+) (the ij (round (- (* s +limit-ij+) 0.5d0)))))) ;; Use quadratic (s,t) -> (u,v) projection. See S2 sources for explanation. (declaim (inline st-to-uv)) (defun st-to-uv (s) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type double-float s)) (* (/ 1 3d0) (if (>= s 0.5d0) (1- (* 4 s s)) (- 1 (* 4 (- 1 s) (- 1 s)))))) (declaim (inline uv-to-st)) (defun uv-to-st (u) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type double-float u)) (if (>= u 0) (* 0.5d0 (the double-float (sqrt (1+ (* 3 u))))) (- 1 (* 0.5d0 (the double-float (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)) (declaim (inline deg-to-rad)) (defun deg-to-rad (deg) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type double-float deg)) (* (/ pi 180d0) deg)) (declaim (inline rad-to-deg)) (defun rad-to-deg (rad) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type double-float 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 (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type latlng latlng)) (with-slots (lat lng) latlng (cons (rad-to-deg lat) (rad-to-deg lng)))) (defun latlng-to-point (latlng) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (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 (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type point p)) (with-slots (x y z) p (atan z (sqrt (+ (* x x) (* y y)))))) (defun point-lng (p) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type point p)) (with-slots (x y) p (atan y x))) (defun point-to-lat-lng (p) (declare (type point p)) (from-radians (point-lat p) (point-lng p))) (declaim (inline dot)) (defun dot (p1 p2) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (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 (optimize (speed 3) (safety 0) (debug 0) (space 0)) (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))))) (declaim (inline get-uvw-axis)) (defun get-uvw-axis (face axis) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type (simple-array point *) +face-uvw-axes+) (type face face axis)) (aref +face-uvw-axes+ face axis)) (declaim (inline get-norm)) (defun get-norm (face) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type face face)) (get-uvw-axis face 2)) (defun valid-face-xyz-to-uv (face p) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type point p) (type face face)) (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 (optimize (speed 3) (safety 0) (debug 0) (space 0)) (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)))) ;; The following lookup tables are used to convert efficiently between an ;; (i,j) cell index and the corresponding position along the Hilbert curve. ;; "lookup_pos" maps 4 bits of "i", 4 bits of "j", and 2 bits representing the ;; orientation of the current cell into 8 bits representing the order in which ;; that subcell is visited by the Hilbert curve, plus 2 bits indicating the ;; new orientation of the Hilbert curve within that subcell. (Cell ;; orientations are represented as combination of kSwapMask and kInvertMask.) ;; ;; "lookup_ij" is an inverted table used for mapping in the opposite ;; direction. ;; ;; We also experimented with looking up 16 bits at a time (14 bits of position ;; plus 2 of orientation) but found that smaller lookup tables gave better ;; performance. (2KB fits easily in the primary cache.) (defconstant +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,0) (0,1) (1,0) (1,1) #(#(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 2 3 #(#(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)) (declaim (inline lsb32)) (defun lsb32 (n) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type (integer 0 #xFFFFFFFF) n)) (loop with rc of-type (integer 0 31) = 31 for i from 4 downto 0 for shift of-type (integer 0 16) = (ash 1 4) then (ash shift -1) for x = (logand #xFFFFFFFF (ash n shift)) when (not (zerop x)) do (setf n x rc (- rc shift)) finally (return rc))) (declaim (inline lsb62)) (defun lsb62 (n) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type fixnum n)) (let ((bottombits (logand #xFFFFFFFF n))) (if (zerop bottombits) (+ 32 (the (integer 0 31) (lsb32 (ash n -32)))) (lsb32 bottombits)))) (declaim (inline find-lsb-set)) (defun find-lsb-set (num) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type cell-id num)) (lsb62 num) ; (or (loop for i upto +pos-bits+ when (logbitp i num) return i) 0) ) (declaim (inline log2floor32)) (defun log2floor32 (n) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type (unsigned-byte 32) n)) (if (zerop n) -1 (loop with log of-type (integer 0 31) = 0 with value of-type (integer 0 #xFFFFFFFF) = n for i from 4 downto 0 for shift of-type (integer 0 16) = (ash 1 i) for x = (ash value (- shift)) when (not (zerop x)) do (setf value x log (+ log shift)) finally (return log)))) (declaim (inline log2floor62)) (defun log2floor62 (n) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type fixnum n)) (let ((topbits (ash n -32))) (if (zerop topbits) (log2floor32 (logand n #xFFFFFFFF)) (+ 32 (the (integer 0 31) (log2floor32 topbits)))))) (declaim (inline find-msb-set)) (defun find-msb-set (num) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type cell-id num)) (log2floor62 num)) (declaim (inline cell-lsb)) (defun cell-lsb (id) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type cell-id id)) (logand id (1+ (lognot id)))) (declaim (inline lsb-for-level)) (defun lsb-for-level (level) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type level level)) (ash 1 (* 2 (- +max-level+ level)))) (declaim (inline cell-face)) (defun cell-face (id) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type cell-id id)) (ash id (- +pos-bits+))) (declaim (inline cell-pos)) (defun cell-pos (id) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (cell-id id)) (logand id (1- (ash 1 +pos-bits+)))) (declaim (inline cell-is-valid)) (defun cell-is-valid (id) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (cell-id id)) (and (< (cell-face id) +num-faces+) (not (zerop (logand (cell-lsb id) #x5555555555555555 (1- (ash 1 +pos-bits+))))))) (defun cell-level (id) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type cell-id id)) (assert (not (zerop id))) (- +max-level+ (ash (find-lsb-set id) -1))) (defun from-face-ij (face i j) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type face face) (type ij i j) (type (simple-array (unsigned-byte 16) *) *lookup-pos*)) (let ((n (ash face (1- +pos-bits+))) (bits (logand face +swap-mask+)) (mask (1- (ash 1 +lookup-bits+)))) (declare (type cell-id n)) (macrolet ((get-bits (k) `(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))) n (logior n (the cell-id (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+ (ash n 1)))) (defun point-to-cell (p) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type point 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))))) (declaim (inline si-ti-to-st)) (defun si-ti-to-st (si) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type si-ti si)) (* si (/ 1d0 +max-si-ti+))) (defun face-uv-ti-xyz (face u v) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type double-float u v) (type face face)) (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 face-si-ti-to-xyz (face si ti) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type si-ti si ti) (type face face)) (face-uv-ti-xyz face (st-to-uv (si-ti-to-st si)) (st-to-uv (si-ti-to-st ti)))) (declaim (inline cell-child-position)) (defun cell-child-position (id &optional level) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type cell-id id) (type (or null level) level)) (unless level (setf level (cell-level id))) (assert (cell-is-valid id)) (assert (>= level 1)) (assert (<= level (the level (cell-level id)))) (logand 3 (ash id (- (1+ (* 2 (- +max-level+ level))))))) (declaim (inline cell-is-leaf)) (defun cell-is-leaf (id) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type cell-id id)) (not (zerop (logand id 1)))) (declaim (inline cell-is-face)) (defun cell-is-face (id) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type cell-id id)) (zerop (logand id (1- (lsb-for-level 0))))) (declaim (inline cell-range-min)) (defun cell-range-min (id) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type cell-id id)) (- id (1- (cell-lsb id)))) (declaim (inline cell-range-max)) (defun cell-range-max (id) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type cell-id id)) (+ id (1- (cell-lsb id)))) (declaim (inline cell-parent)) (defun cell-parent (id &optional level) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type cell-id id) (type (or null level) level)) (assert (cell-is-valid id)) (if level (progn (assert (>= level 0)) (assert (<= level (the 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)))))) (declaim (inline cell-child)) (defun cell-child (id pos) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type cell-id id) (type (integer 0 3) 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-face-ij-orientation (id) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type cell-id id) (type (simple-array (unsigned-byte 16) *) *lookup-ij*)) (let* ((i 0) (j 0) (face (cell-face id)) (bits (logand face +swap-mask+))) (declare (type ij i j) (type face face) (type (integer 0 3) bits)) (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) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type cell-id id)) (multiple-value-bind (face i j orient) (cell-to-face-ij-orientation id) (declare (ignore orient) (type ij i j)) (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 cell-to-point-raw (id) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type cell-id id)) (apply #'face-si-ti-to-xyz (multiple-value-list (cell-get-center-face-si-ti id)))) (defun cell-to-string (id) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type cell-id id)) (format nil "~a/~{~a~}" (cell-face id) (loop for level from 1 to (the level (cell-level id)) collect (cell-child-position id level)))) ;;;;;;;;; ;;; (defun make-span (vector offset &optional size) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type vector vector) (type fixnum offset) (type (or null fixnum) size)) (let ((length (length vector))) (assert (< offset length)) (when size (assert (< (the fixnum (+ offset size)) length))) (make-array (or size (the fixnum (- 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) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type fixnum size)) (make-array size :element-type '(unsigned-byte 8) :fill-pointer 0 :adjustable t)) (declaim (inline encoder-length)) (defun encoder-length (encoder) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type byte-vector encoder)) (fill-pointer encoder)) (declaim (inline encoder-avail)) (defun encoder-avail (encoder) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type byte-vector encoder)) (- (array-total-size encoder) (fill-pointer encoder))) (declaim (inline encoder-ensure)) (defun encoder-ensure (encoder size) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type byte-vector encoder) (type fixnum size)) (when (< (encoder-avail encoder) size) (adjust-array encoder (+ (fill-pointer encoder) size)))) (declaim (inline encoder-put8)) (defun encoder-put8 (encoder value) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type byte-vector encoder) (type (unsigned-byte 8) value)) (assert (> (encoder-avail encoder) 1)) (vector-push value encoder) encoder) (declaim (inline encoder-putn)) (defun encoder-putn (encoder vector) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type byte-vector encoder) (type byte-vector vector)) (loop for value across vector do (vector-push value encoder)) encoder) (defconstant +varint-max32+ 5 "Maximum varint encoding length for uint32") (declaim (inline encoder-put-varint32)) (defun encoder-put-varint32 (encoder v) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (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) (defconstant +varint-max64+ 10 "Maximum varint encoding length for uint64") (defun encoder-put-varint64 (encoder v) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (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)))))) (declaim (inline decoder-avail)) (defun decoder-avail (decoder) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type byte-vector decoder)) (- (array-total-size decoder) (fill-pointer decoder))) (declaim (inline decoder-skip)) (defun decoder-skip (decoder &optional (count 1)) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type byte-vector decoder) (type fixnum count)) (incf (fill-pointer decoder) count)) (declaim (inline decoder-reset)) (defun decoder-reset (decoder) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type byte-vector decoder)) (setf (fill-pointer decoder) 0)) (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))))) (declaim (inline decoder-get8)) (defun decoder-get8 (decoder) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type byte-vector decoder)) (prog1 (aref decoder (fill-pointer decoder)) (decoder-skip decoder))) (declaim (inline decoder-peek)) (defun decoder-peek (decoder &optional (offset 0)) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type byte-vector decoder) (type fixnum offset)) (aref decoder (+ (fill-pointer decoder) offset))) (deftype varint-length () `(integer 0 ,+varint-max64+)) (defun decoder-get-varint64 (decoder) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type byte-vector decoder)) (loop for b = (decoder-get8 decoder) then (decoder-get8 decoder) for i of-type varint-length from 0 upto (decoder-avail decoder) with result of-type (unsigned-byte 64) = 0 do (incf result (the (unsigned-byte 64) (ash (if (zerop i) b (1- b)) (* i 7)))) until (< b 128) finally (return result))) (defun decoder-get-varint-fixnum (decoder) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (type byte-vector decoder)) (loop for b = (decoder-get8 decoder) then (decoder-get8 decoder) for i of-type varint-length from 0 upto (decoder-avail decoder) with result of-type fixnum = 0 do (incf result (the fixnum (ash (if (zerop i) b (1- b)) (* i 7)))) until (< b 128) finally (return result))) ;;; ;;; encoded-uint-vector ;;; ;;; (template () (defun encode-uint-with-length (value length encoder) (declare (type 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)) ()) ))) )))) ))))))