osm.lisp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. b(in-package :cl-user)
  2. (defpackage #:ocm.osm
  3. (:use :cl :alexandria))
  4. (in-package :ocm.osm)
  5. (defun next-power-of-two (number)
  6. (ash 1 (ceiling (log number 2))))
  7. (defvar *read-buffer* (proto:make-byte-vector 4096))
  8. (defun ensure-buffer (size)
  9. (when (> size (array-total-size *read-buffer*))
  10. (setf *read-buffer* (proto:make-byte-vector (next-power-of-two size)))))
  11. (defmacro read-big-endian (stream &optional (sizeof 4))
  12. (with-gensyms (i unsigned-value)
  13. `(let ((,unsigned-value 0))
  14. (dotimes (,i ,sizeof ,unsigned-value)
  15. (setf ,unsigned-value (+ (* ,unsigned-value #x100)
  16. (read-byte ,stream)))))))
  17. (defmacro read-little-endian (stream &optional (sizeof 4))
  18. (with-gensyms (i unsigned-value)
  19. `(let ((,unsigned-value 0))
  20. (dotimes (,i ,sizeof ,unsigned-value)
  21. (setf ,unsigned-value (+ ,unsigned-value
  22. (ash (read-byte ,stream )
  23. (* 8 ,i))))))))
  24. (defvar *stream* nil "PBF file stream")
  25. (defvar *blob-header-size* nil "Current header size during file parsing")
  26. (defvar *blob-header* nil "Current header")
  27. (defvar *blob-size* nil "Current blob size during file parsing")
  28. (defvar *blob-type* nil "Current blob type")
  29. (defvar *blob* nil "Current blob")
  30. (defvar *block-size* nil "Current block size")
  31. (defvar *header-block* nil "File header block")
  32. (defvar *primitive-block* nil "Current primitive block")
  33. (defparameter +blob-type-osm-header+ "OSMHeader")
  34. (defparameter +blob-type-osm-data+ "OSMData")
  35. (defun read-proto (type size &optional no-read)
  36. (unless no-read
  37. (ensure-buffer size)
  38. (read-sequence *read-buffer* *stream* :end size))
  39. (proto:deserialize-object type *read-buffer* 0 size))
  40. (defmacro iterate-osm ((filespec) &body body)
  41. `(with-open-file (*stream* ,filespec :element-type 'unsigned-byte)
  42. (handler-case
  43. (loop
  44. (let* ((*blob-header* (read-proto 'osmpbf:blob-header (read-big-endian *stream* 4)))
  45. (*blob-type* (osmpbf:type *blob-header*))
  46. (*blob-size* (osmpbf:datasize *blob-header*)))
  47. (if (or (equal *blob-type* +blob-type-osm-data+)
  48. (equal *blob-type* +blob-type-osm-header+))
  49. (let* ((*blob* (read-proto 'osmpbf:blob *blob-size*))
  50. (*block-size* (unpack-block *blob*)))
  51. (if (equal *blob-type* +blob-type-osm-header+)
  52. (ensure-features (read-proto 'osmpbf:header-block *block-size* t))
  53. (let ((*primitive-block* (read-proto 'osmpbf:primitive-block *block-size* t)))
  54. ,@body)))
  55. (file-position *stream* (+ (file-position *stream*) *blob-size*)))))
  56. (end-of-file (e)
  57. (declare (ignore e))))))
  58. (defun degran-lat (lat block)
  59. (+ (osmpbf:lat-offset block)
  60. (* lat (osmpbf:granularity block))))
  61. (defun degran-lon (lon block)
  62. (+ (osmpbf:lon-offset block)
  63. (* lon (osmpbf:granularity block))))
  64. (defun sid (indexes string-table)
  65. (loop for i in indexes
  66. collect (trivial-utf-8:utf-8-bytes-to-string (elt string-table i))))
  67. (defmacro string-table (block)
  68. `(osmpbf:s (osmpbf:stringtable ,block)))
  69. (defmacro unsid (object accessor block)
  70. `(setf (,accessor ,object)
  71. (sid (,accessor ,object)
  72. (string-table ,block))))
  73. (defun unsid2 (sids string-table)
  74. (loop for i from 0
  75. for sid in sids
  76. do (setf (elt sids i)
  77. (trivial-utf-8:utf-8-bytes-to-string (elt string-table sid)))))
  78. (defmacro iterate-nodes ((node block) &body body)
  79. (with-gensyms (group info)
  80. `(loop for ,group in (osmpbf:primitivegroup ,block)
  81. do (loop for ,node in (osmpbf:nodes ,group)
  82. do (progn
  83. (unsid ,node osmpbf:keys ,block)
  84. (unsid ,node osmpbf:vals ,block)
  85. (when-let (,info (osmpbf:info )))
  86. (setf (osmpbf:lat ,node) (degran-lat (osmpbf:lat ,node) ,block)
  87. (osmpbf:lon ,node) (degran-lon (osmpbf:lon ,node) ,block))
  88. ,@body)))))
  89. (defmacro iterate-dense-nodes ((node block) &body body)
  90. (with-gensyms (group string-table dense dense-info id lat lon tag-start tag-end info ith key val)
  91. `(loop for ,group in (osmpbf:primitivegroup ,block)
  92. with ,string-table = (osmpbf:s (osmpbf:stringtable ,block))
  93. do (when-let (,dense (osmpbf:dense ,group))
  94. (undelta (osmpbf:id ,dense))
  95. (undelta (osmpbf:lat ,dense))
  96. (undelta (osmpbf:lon ,dense))
  97. (when-let (,dense-info (osmpbf:denseinfo ,dense))
  98. (undelta (osmpbf:timestamp ,dense-info))
  99. (undelta (osmpbf:changeset ,dense-info))
  100. (undelta (osmpbf:uid ,dense-info))
  101. (undelta (osmpbf:user-sid ,dense-info)))
  102. (loop
  103. for ,id in (osmpbf:id ,dense)
  104. for ,lat in (osmpbf:lat ,dense)
  105. for ,lon in (osmpbf:lon ,dense)
  106. for ,tag-start = 0 then ,tag-end
  107. for ,tag-end = (position 0 (osmpbf:keys-vals ,dense) :start ,tag-start)
  108. for ,ith from 0
  109. do (let* ((,info (when-let (,dense-info (osmpbf:denseinfo ,dense))
  110. (make-instance 'osmpbf:info
  111. :version (elt (osmpbf:version ,dense-info) ,ith)
  112. :timestamp (elt (osmpbf:timestamp ,dense-info) ,ith)
  113. :changeset (elt (osmpbf:changeset ,dense-info) ,ith)
  114. :uid (elt (osmpbf:uid ,dense-info) ,ith)
  115. :user-sid (car (sid (list (elt (osmpbf:user-sid ,dense-info) ,ith))
  116. ,string-table)))))
  117. (,node (make-instance 'osmpbf:node
  118. :id ,id
  119. :keys (sid (loop for ,key
  120. in (subseq (osmpbf:keys-vals ,dense)
  121. ,tag-start ,tag-end)
  122. by #'cddr
  123. collect ,key)
  124. ,string-table)
  125. :vals (sid (loop for ,val
  126. in (subseq (osmpbf:keys-vals ,dense)
  127. (1+ ,tag-start) ,tag-end)
  128. by #'cddr
  129. collect ,val)
  130. ,string-table)
  131. :lat (degran-lat ,lat ,block)
  132. :lon (degran-lon ,lon ,block)
  133. :info ,info)))
  134. ,@body))))))
  135. (defmacro iterate-dense ((id lat lon keys vals block) &body body)
  136. (with-gensyms (group string-table dense tag-start tag-end key val id-cur lat-cur lon-cur id-prev lat-prev lon-prev lat-acc lon-acc)
  137. `(loop for ,group in (osmpbf:primitivegroup ,block)
  138. with ,string-table = (string-table ,block)
  139. do (when-let (,dense (osmpbf:dense ,group))
  140. (loop
  141. for ,id-cur in (osmpbf:id ,dense)
  142. for ,lat-cur in (osmpbf:lat ,dense)
  143. for ,lon-cur in (osmpbf:lon ,dense)
  144. for ,id-prev = 0 then ,id
  145. for ,lat-prev = 0 then ,lat-acc
  146. for ,lon-prev = 0 then ,lon-acc
  147. for ,tag-start = 0 then ,tag-end
  148. for ,tag-end = (position 0 (osmpbf:keys-vals ,dense) :start ,tag-start)
  149. for ,id = (+ ,id-cur ,id-prev)
  150. for ,lat-acc = (+ ,lat-cur ,lat-prev)
  151. for ,lon-acc = (+ ,lon-cur ,lon-prev)
  152. for ,lat = (degran-lat ,lat-acc ,block)
  153. for ,lon = (degran-lon ,lon-acc ,block)
  154. do (multiple-value-bind (,keys ,vals)
  155. (loop for (,key ,val) on (subseq (osmpbf:keys-vals ,dense) ,tag-start ,tag-end) by #'cddr
  156. collecting ,key into ,keys
  157. collecting ,val into ,vals
  158. finally (return (values ,keys ,vals)))
  159. (let ((,keys (sid ,keys ,string-table))
  160. (,vals (sid ,vals ,string-table)))
  161. ,@body)))))))
  162. (defmacro iterate-ways ((way block) &body body)
  163. (with-gensyms (group)
  164. `(loop for ,group in (osmpbf:primitivegroup ,block)
  165. do (loop for ,way in (osmpbf:ways ,group)
  166. do (progn
  167. (unsid ,way osmpbf:keys ,block)
  168. (unsid ,way osmpbf:vals ,block)
  169. (undelta (osmpbf:refs ,way))
  170. ,@body)))))
  171. (defmacro iterate-rels ((rel block) &body body)
  172. (with-gensyms (group string-table)
  173. `(loop for ,group in (osmpbf:primitivegroup ,block)
  174. with ,string-table = (string-table ,block)
  175. do (loop for ,rel in (osmpbf:relations ,group)
  176. do (progn
  177. (unsid2 (osmpbf:keys ,rel) ,string-table)
  178. (unsid2 (osmpbf:vals ,rel) ,string-table)
  179. (unsid2 (osmpbf:roles-sid ,rel) ,string-table)
  180. (undelta (osmpbf:memids ,rel))
  181. ,@body)))))
  182. (defun get-tags (object string-table)
  183. (loop for key in (osmpbf:keys object)
  184. for val in (osmpbf:vals object)
  185. collect (cons (trivial-utf-8:utf-8-bytes-to-string (elt string-table key))
  186. (trivial-utf-8:utf-8-bytes-to-string (elt string-table val)))))
  187. (defun delta-decode (seq)
  188. (loop for elt in seq
  189. for prev = 0 then cur
  190. for cur = (+ elt prev)
  191. collect cur))
  192. (defmacro iterate-dense2 ((id tags lat lon block) &body body)
  193. (with-gensyms (group string-table dense tag-start tag-end key val id-cur lat-cur lon-cur id-prev lat-prev lon-prev lat-acc lon-acc key-vals clo-start clo-end)
  194. `(loop for ,group in (osmpbf:primitivegroup ,block)
  195. with ,string-table = (string-table ,block)
  196. do (when-let (,dense (osmpbf:dense ,group))
  197. (loop
  198. with ,key-vals = (osmpbf:keys-vals ,dense)
  199. for ,id-cur in (osmpbf:id ,dense)
  200. for ,lat-cur in (osmpbf:lat ,dense)
  201. for ,lon-cur in (osmpbf:lon ,dense)
  202. for ,id-prev = 0 then ,id
  203. for ,lat-prev = 0 then ,lat-acc
  204. for ,lon-prev = 0 then ,lon-acc
  205. for ,tag-start = 0 then ,tag-end
  206. for ,tag-end = (position 0 ,key-vals :start ,tag-start)
  207. for ,id = (+ ,id-cur ,id-prev)
  208. for ,lat-acc = (+ ,lat-cur ,lat-prev)
  209. for ,lon-acc = (+ ,lon-cur ,lon-prev)
  210. for ,lat = (degran-lat ,lat-acc ,block)
  211. for ,lon = (degran-lon ,lon-acc ,block)
  212. for ,tags = (unless (= ,tag-start ,tag-end)
  213. (let ((,clo-start ,tag-start)
  214. (,clo-end ,tag-end))
  215. (lambda ()
  216. (loop for (,key ,val) on (subseq ,key-vals ,clo-start ,clo-end) by #'cddr
  217. collect (cons (trivial-utf-8:utf-8-bytes-to-string
  218. (elt ,string-table ,key))
  219. (trivial-utf-8:utf-8-bytes-to-string
  220. (elt ,string-table ,val)))))))
  221. do (progn ,@body))))))
  222. (defmacro iterate-ways2 ((id tags refs block) &body body)
  223. (with-gensyms (group string-table object o-string-table)
  224. `(loop for ,group in (osmpbf:primitivegroup ,block)
  225. with ,string-table = (string-table ,block)
  226. do (loop for ,object in (osmpbf:ways ,group)
  227. for ,id = (osmpbf:id ,object)
  228. for ,o-string-table = ,string-table
  229. for ,tags = (lambda () (get-tags ,object ,o-string-table))
  230. for ,refs = (lambda () (delta-decode (osmpbf:refs ,object)))
  231. do (progn ,@body)))))
  232. (defmacro iterate-rels2 ((id tags roles memids types block) &body body)
  233. (with-gensyms (group string-table relation)
  234. `(loop for ,group in (osmpbf:primitivegroup ,block)
  235. with ,string-table = (string-table ,block)
  236. do (loop for ,relation in (osmpbf:relations ,group)
  237. for ,id = (osmpbf:id ,relation)
  238. for ,tags = (lambda () (get-tags ,relation ,string-table))
  239. for ,roles = (lambda () (sid (osmpbf:roles-sid ,relation) ,string-table))
  240. for ,memids = (lambda () (delta-decode (osmpbf:memids ,relation)))
  241. for ,types = (lambda () (osmpbf:types ,relation))
  242. do (progn ,@body)))))
  243. (defun undelta (seq)
  244. (when (> (length seq) 1)
  245. (loop for i from 1 below (length seq)
  246. do (incf (elt seq i)
  247. (elt seq (1- i)))))
  248. seq)
  249. (defparameter +supported-features+ '("OsmSchema-V0.6" "DenseNodes"))
  250. (defun ensure-features (header)
  251. (when-let (missing-features (set-difference (osmpbf:required-features header)
  252. +supported-features+
  253. :test 'equal))
  254. (error "Features ~A not supported" missing-features))
  255. (setf *header-block* header))
  256. (defun unpack-block (blob)
  257. (if-let (uncompressed (osmpbf:raw blob))
  258. (let ((size (array-total-size uncompressed)))
  259. (ensure-buffer size)
  260. (dotimes (i (array-total-size uncompressed))
  261. (setf (row-major-aref *read-buffer* i)
  262. (row-major-aref uncompressed i)))
  263. size)
  264. (if-let (zlib-data (osmpbf:zlib-data blob))
  265. (let ((size (osmpbf:raw-size blob)))
  266. (ensure-buffer size)
  267. (chipz:decompress *read-buffer* (chipz:make-dstate :zlib) zlib-data)
  268. size)
  269. (error "Unsupported block compression"))))
  270. (defun type-match (type-expr type)
  271. (etypecase type-expr
  272. (null t)
  273. (symbol (eql type-expr type))
  274. (list (member type type-expr))))
  275. (defun expr-match (template value)
  276. (etypecase template
  277. (null t)
  278. (string (equal template value))
  279. (list (destructuring-bind (type expr) template
  280. (let ((pos (search expr value)))
  281. (ecase type
  282. (:pre (eql pos 0))
  283. (:suf (eql pos (max 0 (- (length value)
  284. (length expr)))))
  285. (:inf (not (null pos)))
  286. (:eql (and (eql pos 0)
  287. (= (length value)
  288. (length expr))))))))))
  289. (defun query-match (query type keys vals)
  290. (or (null query)
  291. (loop for expr in query
  292. when (destructuring-bind (tp &optional keyp valp) expr
  293. (and
  294. (type-match tp type)
  295. (or (and (null keyp) (null valp))
  296. (loop for key in keys
  297. for val in vals
  298. when (and (expr-match keyp key)
  299. (expr-match valp val))
  300. return t))))
  301. return t)))
  302. (defun query-match2 (query type tags-thunk)
  303. (or (null query)
  304. (loop for expr in query
  305. when (destructuring-bind (tp &optional keyp valp) expr
  306. (and
  307. (type-match tp type)
  308. (or (and (null keyp) (null valp))
  309. (and tags-thunk
  310. (loop for (key . val) in (if (functionp tags-thunk) (funcall tags-thunk) tags-thunk)
  311. when (and (expr-match keyp key)
  312. (expr-match valp val))
  313. return t)))))
  314. return t)))
  315. (defun query-has-type (query type)
  316. (or (null query)
  317. (loop for expr in query
  318. when (type-match (car expr) type)
  319. return t)))
  320. (defmacro iterate ((object filespec tags-query) &body body)
  321. (let ((has-rels (query-has-type (cadr tags-query) :rel))
  322. (has-ways (query-has-type (cadr tags-query) :way))
  323. (has-nodes (query-has-type (cadr tags-query) :node)))
  324. (with-gensyms (id lat lon keys vals query)
  325. `(let ((,query ,tags-query))
  326. (iterate-osm (,filespec)
  327. ,@(when has-rels `((iterate-rels (,object *primitive-block*)
  328. (when (query-match ,query :rel (osmpbf:keys ,object) (osmpbf:vals ,object))
  329. ,@body))))
  330. ,@(when has-ways `((iterate-ways (,object *primitive-block*)
  331. (when (query-match ,query :way (osmpbf:keys ,object) (osmpbf:vals ,object))
  332. ,@body))))
  333. ,@(when has-nodes
  334. `((iterate-nodes (,object *primitive-block*)
  335. (when (query-match ,query :node (osmpbf:keys ,object) (osmpbf:vals ,object))
  336. ,@body))
  337. (iterate-dense (,id ,lat ,lon ,keys ,vals *primitive-block*)
  338. (when (query-match ,query :node ,keys ,vals)
  339. (let ((,object (make-instance 'osmpbf:node :id ,id :lat ,lat :lon ,lon
  340. :keys ,keys :vals ,vals)))
  341. ,@body))))))))))
  342. (defstruct obj id tags)
  343. (defstruct (node (:include obj)) lat lon)
  344. (defstruct (way (:include obj)) refs)
  345. (defstruct (rel (:include obj)) roles memids types)
  346. (defmacro iterate2 ((object filespec query) &body body)
  347. (let ((has-rels (query-has-type (cadr query) :rel))
  348. (has-ways (query-has-type (cadr query) :way))
  349. (has-nodes (query-has-type (cadr query) :node)))
  350. (with-gensyms (g-query g-id g-tags g-roles g-memids g-types g-refs g-lat g-lon)
  351. `(let ((,g-query ,query))
  352. (iterate-osm (,filespec)
  353. ,@(when has-rels `((iterate-rels2 (,g-id ,g-tags ,g-roles ,g-memids ,g-types *primitive-block*)
  354. (when (query-match2 ,g-query :rel ,g-tags)
  355. (let ((,object (make-rel :id ,g-id :tags ,g-tags
  356. :roles ,g-roles :memids ,g-memids :types ,g-types)))
  357. ,@body)))))
  358. ,@(when has-ways `((iterate-ways2 (,g-id ,g-tags ,g-refs *primitive-block*)
  359. (when (query-match2 ,g-query :way ,g-tags)
  360. (let ((,object (make-way :id ,g-id :tags ,g-tags
  361. :refs ,g-refs)))
  362. ,@body)))))
  363. ,@(when has-nodes `((iterate-dense2 (,g-id ,g-tags ,g-lat ,g-lon *primitive-block*)
  364. (when (query-match2 ,g-query :node ,g-tags)
  365. (let ((,object (make-node :id ,g-id :tags ,g-tags
  366. :lat ,g-lat :lon ,g-lon)))
  367. ,@body))))))))))
  368. (defparameter +max-rel-pass+ 5 "max rel-2-rel passes")
  369. (defmacro with-related ((object filespec query) &body body)
  370. (with-gensyms (g-object g-filespec g-objects g-idx-rels g-idx-ways g-idx-nodes g-rel g-type g-memid g-indexed
  371. g-dirty g-try g-indexed-list)
  372. `(let ((,g-filespec ,filespec)
  373. ,g-objects
  374. (,g-idx-rels (make-hash-table))
  375. (,g-idx-ways (make-hash-table))
  376. (,g-idx-nodes (make-hash-table)))
  377. (print "iterate queried")
  378. (iterate2 (,g-object ,g-filespec ,query)
  379. (typecase ,g-object
  380. (node (let ((,object ,g-object)) ,@body))
  381. (way (push ,g-object ,g-objects)
  382. (setf (obj-tags ,g-object) (funcall (obj-tags ,g-object))
  383. (way-refs ,g-object) (funcall (way-refs ,g-object)))
  384. (loop for ,g-rel in (way-refs ,g-object)
  385. do (push ,g-object (gethash ,g-rel ,g-idx-nodes))))
  386. (rel (push ,g-object ,g-objects)
  387. (setf (obj-tags ,g-object) (funcall (obj-tags ,g-object))
  388. (rel-roles ,g-object) (funcall (rel-roles ,g-object))
  389. (rel-memids ,g-object) (funcall (rel-memids ,g-object))
  390. (rel-types ,g-object) (funcall (rel-types ,g-object)))
  391. (loop for ,g-memid in (rel-memids ,g-object)
  392. for ,g-type in (rel-types ,g-object)
  393. do (push ,g-object (gethash ,g-memid (ecase ,g-type
  394. (:node ,g-idx-nodes)
  395. (:way ,g-idx-ways)
  396. (:relation ,g-idx-rels))))))))
  397. (when (plusp (hash-table-count ,g-idx-rels))
  398. (loop
  399. for ,g-dirty = nil
  400. for ,g-try from 1 upto +max-rel-pass+
  401. do (format t "iterate rels pass ~a~%" ,g-try)
  402. do (iterate2 (,g-object ,g-filespec '((:rel)))
  403. (when-let ((,g-indexed-list (gethash (obj-id ,g-object) ,g-idx-rels)))
  404. (setf (rel-memids ,g-object) (funcall (rel-memids ,g-object))
  405. (rel-types ,g-object) (funcall (rel-types ,g-object)))
  406. (loop for ,g-indexed in ,g-indexed-list
  407. do (loop
  408. for ,g-memid on (rel-memids ,g-indexed)
  409. for ,g-type in (rel-types ,g-indexed)
  410. when (and (eql ,g-type :relation)
  411. (equal (car ,g-memid) (obj-id ,g-object)))
  412. do (setf (car ,g-memid) ,g-object) and ;; replace memid ref with current rel
  413. do (loop for ,g-memid in (rel-memids ,g-object) ;; add it's references to index
  414. for ,g-type in (rel-types ,g-object)
  415. do (push ,g-object
  416. (gethash ,g-memid (ecase ,g-type
  417. (:node ,g-idx-nodes)
  418. (:way ,g-idx-ways)
  419. (:relation (prog1 ,g-idx-rels
  420. (setf ,g-dirty t)))))))))
  421. (remhash (obj-id ,g-object) ,g-idx-rels))) ;; remove processed rel from index
  422. while ,g-dirty))
  423. (when (plusp (hash-table-count ,g-idx-ways))
  424. (print "iterate ways")
  425. (iterate2 (,g-object ,g-filespec '((:way)))
  426. (when-let ((,g-indexed-list (gethash (obj-id ,g-object) ,g-idx-ways)))
  427. (setf (way-refs ,g-object) (funcall (way-refs ,g-object)))
  428. (loop for ,g-indexed in ,g-indexed-list
  429. do (loop
  430. for ,g-memid on (rel-memids ,g-indexed)
  431. for ,g-type in (rel-types ,g-indexed)
  432. when (and (eql ,g-type :way)
  433. (equal (car ,g-memid) (obj-id ,g-object)))
  434. do (setf (car ,g-memid) ,g-object) and ;; replace memid ref with current way
  435. do (loop for ,g-rel in (way-refs ,g-object) ;; add it's refs to index
  436. do (push ,g-object (gethash ,g-rel ,g-idx-nodes)))))
  437. (remhash (obj-id ,g-object) ,g-idx-ways)))) ;; remove processed way from index
  438. (when (plusp (hash-table-count ,g-idx-nodes))
  439. (print "iterate nodes")
  440. (iterate2 (,g-object ,g-filespec '((:node)))
  441. (when-let ((,g-indexed-list (gethash (obj-id ,g-object) ,g-idx-nodes)))
  442. (loop for ,g-indexed in ,g-indexed-list
  443. do (etypecase ,g-indexed
  444. (rel (loop
  445. for ,g-memid on (rel-memids ,g-indexed)
  446. for ,g-type in (rel-types ,g-indexed)
  447. when (and (eql ,g-type :node)
  448. (equal (car ,g-memid) (obj-id ,g-object)))
  449. do (setf (car ,g-memid) ,g-object))) ;; replace rel's memid with current node
  450. (way (nsubstitute ,g-object (obj-id ,g-object) (way-refs ,g-indexed))))) ;; replace way's ref with current node
  451. (remhash (obj-id ,g-object) ,g-idx-nodes))))
  452. (loop for ,object in (nreverse ,g-objects) ;; Iterate original matched objects
  453. do (progn ,@body)))))