compatible.lua 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773
  1. -- Määrame skeemi keskkonnamuutujast või vaikimisi 'public'
  2. local schema = os.getenv("PGSCHEMA") or "public"
  3. -- This config example file is released into the Public Domain.
  4. -- This configuration for the flex output tries to be compatible with the
  5. -- original pgsql C transform output. There might be some corner cases but
  6. -- it should do exactly the same in almost all cases.
  7. -- The output projection used (3857, web mercator is the default). Set this
  8. -- to 4326 if you were using the -l|--latlong option or to the EPSG
  9. -- code you were using on the -E|-proj option.
  10. local srid = 3857
  11. -- Set this to true if you were using option -K|--keep-coastlines.
  12. local keep_coastlines = false
  13. -- Set this to the table name prefix (what used to be option -p|--prefix).
  14. local prefix = 'orig'
  15. -- Set this to true if multipolygons should be written as multipolygons into
  16. -- db (what used to be option -G|--multi-geometry).
  17. local multi_geometry = false
  18. -- Set this to true if you want an hstore column (what used to be option
  19. -- -k|--hstore). Can not be true if "hstore_all" is true.
  20. local hstore = false
  21. -- Set this to true if you want all tags in an hstore column (what used to
  22. -- be option -j|--hstore-all). Can not be true if "hstore" is true.
  23. local hstore_all = false
  24. -- Only keep objects that have a value in one of the non-hstore columns
  25. -- (normal action with --hstore is to keep all objects). Equivalent to
  26. -- what used to be set through option --hstore-match-only.
  27. local hstore_match_only = false
  28. -- Set this to add an additional hstore (key/value) column containing all tags
  29. -- that start with the specified string, eg "name:". Will produce an extra
  30. -- hstore column that contains all "name:xx" tags. Equivalent to what used to
  31. -- be set through option -z|--hstore-column. Unlike the -z option which can
  32. -- be specified multiple time, this does only support a single additional
  33. -- hstore column.
  34. local hstore_column = nil
  35. -- If this is set, area calculations are always in Mercator coordinates units
  36. -- irrespective of the srid setting.
  37. -- Set this to true if you used --reproject-area before.
  38. local reproject_area = false
  39. -- There is some very old specialized handling of route relations in osm2pgsql,
  40. -- which you probably don't need. This is disabled here, but you can enable
  41. -- it by setting this to true. If you don't understand this, leave it alone.
  42. local enable_legacy_route_processing = false
  43. -- ---------------------------------------------------------------------------
  44. if hstore and hstore_all then
  45. error("hstore and hstore_all can't be both true")
  46. end
  47. -- Used for splitting up long linestrings
  48. local max_length = 1
  49. if srid == 3857 then
  50. max_length = 100000
  51. end
  52. -- Ways with any of the following keys will be treated as polygon
  53. local polygon_keys = {
  54. 'aeroway',
  55. 'amenity',
  56. 'building',
  57. 'harbour',
  58. 'historic',
  59. 'landuse',
  60. 'leisure',
  61. 'man_made',
  62. 'military',
  63. 'natural',
  64. 'office',
  65. 'place',
  66. 'power',
  67. 'public_transport',
  68. 'shop',
  69. 'sport',
  70. 'tourism',
  71. 'water',
  72. 'waterway',
  73. 'wetland',
  74. 'abandoned:aeroway',
  75. 'abandoned:amenity',
  76. 'abandoned:building',
  77. 'abandoned:landuse',
  78. 'abandoned:power',
  79. 'area:highway'
  80. }
  81. -- Objects without any of the following keys will be deleted
  82. local generic_keys = {
  83. 'access',
  84. 'addr:housename',
  85. 'addr:housenumber',
  86. 'addr:interpolation',
  87. 'admin_level',
  88. 'aerialway',
  89. 'aeroway',
  90. 'amenity',
  91. 'area',
  92. 'barrier',
  93. 'bicycle',
  94. 'boundary',
  95. 'brand',
  96. 'bridge',
  97. 'building',
  98. 'capital',
  99. 'construction',
  100. 'covered',
  101. 'culvert',
  102. 'cutting',
  103. 'denomination',
  104. 'disused',
  105. 'ele',
  106. 'embankment',
  107. 'foot',
  108. 'generation:source',
  109. 'harbour',
  110. 'highway',
  111. 'historic',
  112. 'hours',
  113. 'intermittent',
  114. 'junction',
  115. 'landuse',
  116. 'layer',
  117. 'leisure',
  118. 'lock',
  119. 'man_made',
  120. 'military',
  121. 'motorcar',
  122. 'name',
  123. 'natural',
  124. 'office',
  125. 'oneway',
  126. 'operator',
  127. 'place',
  128. 'population',
  129. 'power',
  130. 'power_source',
  131. 'public_transport',
  132. 'railway',
  133. 'ref',
  134. 'religion',
  135. 'route',
  136. 'service',
  137. 'shop',
  138. 'sport',
  139. 'surface',
  140. 'toll',
  141. 'tourism',
  142. 'tower:type',
  143. 'tracktype',
  144. 'tunnel',
  145. 'water',
  146. 'waterway',
  147. 'wetland',
  148. 'width',
  149. 'wood',
  150. 'abandoned:aeroway',
  151. 'abandoned:amenity',
  152. 'abandoned:building',
  153. 'abandoned:landuse',
  154. 'abandoned:power',
  155. 'area:highway'
  156. }
  157. -- The following keys will be deleted
  158. local delete_keys = {
  159. 'attribution',
  160. 'comment',
  161. 'created_by',
  162. 'fixme',
  163. 'note',
  164. 'note:*',
  165. 'odbl',
  166. 'odbl:note',
  167. 'source',
  168. 'source:*',
  169. 'source_ref',
  170. 'way',
  171. 'way_area',
  172. 'z_order',
  173. }
  174. local point_columns = {
  175. 'access',
  176. 'addr:housename',
  177. 'addr:housenumber',
  178. 'addr:interpolation',
  179. 'admin_level',
  180. 'aerialway',
  181. 'aeroway',
  182. 'amenity',
  183. 'area',
  184. 'barrier',
  185. 'bicycle',
  186. 'brand',
  187. 'bridge',
  188. 'boundary',
  189. 'building',
  190. 'capital',
  191. 'construction',
  192. 'covered',
  193. 'culvert',
  194. 'cutting',
  195. 'denomination',
  196. 'disused',
  197. 'ele',
  198. 'embankment',
  199. 'foot',
  200. 'generator:source',
  201. 'harbour',
  202. 'highway',
  203. 'historic',
  204. 'horse',
  205. 'intermittent',
  206. 'junction',
  207. 'landuse',
  208. 'layer',
  209. 'leisure',
  210. 'lock',
  211. 'man_made',
  212. 'military',
  213. 'motorcar',
  214. 'name',
  215. 'natural',
  216. 'office',
  217. 'oneway',
  218. 'operator',
  219. 'place',
  220. 'population',
  221. 'power',
  222. 'power_source',
  223. 'public_transport',
  224. 'railway',
  225. 'ref',
  226. 'religion',
  227. 'route',
  228. 'service',
  229. 'shop',
  230. 'sport',
  231. 'surface',
  232. 'toll',
  233. 'tourism',
  234. 'tower:type',
  235. 'tunnel',
  236. 'water',
  237. 'waterway',
  238. 'wetland',
  239. 'width',
  240. 'wood',
  241. }
  242. local non_point_columns = {
  243. 'access',
  244. 'addr:housename',
  245. 'addr:housenumber',
  246. 'addr:interpolation',
  247. 'admin_level',
  248. 'aerialway',
  249. 'aeroway',
  250. 'amenity',
  251. 'area',
  252. 'barrier',
  253. 'bicycle',
  254. 'brand',
  255. 'bridge',
  256. 'boundary',
  257. 'building',
  258. 'construction',
  259. 'covered',
  260. 'culvert',
  261. 'cutting',
  262. 'denomination',
  263. 'disused',
  264. 'embankment',
  265. 'foot',
  266. 'generator:source',
  267. 'harbour',
  268. 'highway',
  269. 'historic',
  270. 'horse',
  271. 'intermittent',
  272. 'junction',
  273. 'landuse',
  274. 'layer',
  275. 'leisure',
  276. 'lock',
  277. 'man_made',
  278. 'military',
  279. 'motorcar',
  280. 'name',
  281. 'natural',
  282. 'office',
  283. 'oneway',
  284. 'operator',
  285. 'place',
  286. 'population',
  287. 'power',
  288. 'power_source',
  289. 'public_transport',
  290. 'railway',
  291. 'ref',
  292. 'religion',
  293. 'route',
  294. 'service',
  295. 'shop',
  296. 'sport',
  297. 'surface',
  298. 'toll',
  299. 'tourism',
  300. 'tower:type',
  301. 'tracktype',
  302. 'tunnel',
  303. 'water',
  304. 'waterway',
  305. 'wetland',
  306. 'width',
  307. 'wood',
  308. }
  309. local function gen_columns(text_columns, with_hstore, area, geometry_type)
  310. local columns = {}
  311. local add_column = function (name, type)
  312. columns[#columns + 1] = { column = name, type = type }
  313. end
  314. for _, c in ipairs(text_columns) do
  315. add_column(c, 'text')
  316. end
  317. add_column('z_order', 'int')
  318. if area then
  319. add_column('way_area', 'real')
  320. end
  321. if hstore_column then
  322. add_column(hstore_column, 'hstore')
  323. end
  324. if with_hstore then
  325. add_column('tags', 'hstore')
  326. end
  327. add_column('way', geometry_type)
  328. columns[#columns].projection = srid
  329. columns[#columns].not_null = true
  330. return columns
  331. end
  332. local tables = {}
  333. tables.point = osm2pgsql.define_table{
  334. name = prefix .. '_point',
  335. schema = schema,
  336. ids = { type = 'node', id_column = 'osm_id' },
  337. columns = gen_columns(point_columns, hstore or hstore_all, false, 'point')
  338. }
  339. tables.line = osm2pgsql.define_table{
  340. name = prefix .. '_line',
  341. schema = schema,
  342. ids = { type = 'way', id_column = 'osm_id' },
  343. columns = gen_columns(non_point_columns, hstore or hstore_all, true, 'linestring')
  344. }
  345. tables.polygon = osm2pgsql.define_table{
  346. name = prefix .. '_polygon',
  347. schema = schema,
  348. ids = { type = 'area', id_column = 'osm_id' },
  349. columns = gen_columns(non_point_columns, hstore or hstore_all, true, 'geometry')
  350. }
  351. tables.roads = osm2pgsql.define_table{
  352. name = prefix .. '_roads',
  353. schema = schema,
  354. ids = { type = 'way', id_column = 'osm_id' },
  355. columns = gen_columns(non_point_columns, hstore or hstore_all, true, 'linestring')
  356. }
  357. local z_order_lookup = {
  358. proposed = {1, false},
  359. construction = {2, false},
  360. steps = {10, false},
  361. cycleway = {10, false},
  362. bridleway = {10, false},
  363. footway = {10, false},
  364. path = {10, false},
  365. track = {11, false},
  366. service = {15, false},
  367. tertiary_link = {24, false},
  368. secondary_link = {25, true},
  369. primary_link = {27, true},
  370. trunk_link = {28, true},
  371. motorway_link = {29, true},
  372. raceway = {30, false},
  373. pedestrian = {31, false},
  374. living_street = {32, false},
  375. road = {33, false},
  376. unclassified = {33, false},
  377. residential = {33, false},
  378. tertiary = {34, false},
  379. secondary = {36, true},
  380. primary = {37, true},
  381. trunk = {38, true},
  382. motorway = {39, true}
  383. }
  384. local function as_bool(value)
  385. return value == 'yes' or value == 'true' or value == '1'
  386. end
  387. local function get_z_order(tags)
  388. local z_order = 100 * math.floor(tonumber(tags.layer or '0') or 0)
  389. local roads = false
  390. local highway = tags['highway']
  391. if highway then
  392. local r = z_order_lookup[highway] or {0, false}
  393. z_order = z_order + r[1]
  394. roads = r[2]
  395. end
  396. if tags.railway then
  397. z_order = z_order + 35
  398. roads = true
  399. end
  400. if tags.boundary and tags.boundary == 'administrative' then
  401. roads = true
  402. end
  403. if as_bool(tags.bridge) then
  404. z_order = z_order + 100
  405. end
  406. if as_bool(tags.tunnel) then
  407. z_order = z_order - 100
  408. end
  409. return z_order, roads
  410. end
  411. local function make_check_in_list_func(list)
  412. local h = {}
  413. for _, k in ipairs(list) do
  414. h[k] = true
  415. end
  416. return function(tags)
  417. for k, _ in pairs(tags) do
  418. if h[k] then
  419. return true
  420. end
  421. end
  422. return false
  423. end
  424. end
  425. local is_polygon = make_check_in_list_func(polygon_keys)
  426. local clean_tags = osm2pgsql.make_clean_tags_func(delete_keys)
  427. local function make_column_hash(columns)
  428. local h = {}
  429. for _, k in ipairs(columns) do
  430. h[k] = true
  431. end
  432. return h
  433. end
  434. local function make_get_output(columns)
  435. local h = make_column_hash(columns)
  436. if hstore_all then
  437. return function(tags)
  438. local output = {}
  439. local hstore_entries = {}
  440. for k, _ in pairs(tags) do
  441. if h[k] then
  442. output[k] = tags[k]
  443. end
  444. hstore_entries[k] = tags[k]
  445. end
  446. return output, hstore_entries
  447. end
  448. else
  449. return function(tags)
  450. local output = {}
  451. local hstore_entries = {}
  452. for k, _ in pairs(tags) do
  453. if h[k] then
  454. output[k] = tags[k]
  455. else
  456. hstore_entries[k] = tags[k]
  457. end
  458. end
  459. return output, hstore_entries
  460. end
  461. end
  462. end
  463. local has_generic_tag = make_check_in_list_func(generic_keys)
  464. local get_point_output = make_get_output(point_columns)
  465. local get_non_point_output = make_get_output(non_point_columns)
  466. local function get_hstore_column(tags)
  467. local len = #hstore_column
  468. local h = {}
  469. for k, v in pairs(tags) do
  470. if k:sub(1, len) == hstore_column then
  471. h[k:sub(len + 1)] = v
  472. end
  473. end
  474. if next(h) then
  475. return h
  476. end
  477. return nil
  478. end
  479. function osm2pgsql.process_node(object)
  480. if clean_tags(object.tags) then
  481. return
  482. end
  483. local output
  484. local output_hstore = {}
  485. if hstore or hstore_all then
  486. output, output_hstore = get_point_output(object.tags)
  487. if not next(output) and not next(output_hstore) then
  488. return
  489. end
  490. if hstore_match_only and not has_generic_tag(object.tags) then
  491. return
  492. end
  493. else
  494. output = object.tags
  495. if not has_generic_tag(object.tags) then
  496. return
  497. end
  498. end
  499. output.tags = output_hstore
  500. if hstore_column then
  501. output[hstore_column] = get_hstore_column(object.tags)
  502. end
  503. output.way = object:as_point()
  504. tables.point:insert(output)
  505. end
  506. local function add_line(output, geom, roads)
  507. for sgeom in geom:segmentize(max_length):geometries() do
  508. output.way = sgeom
  509. tables.line:insert(output)
  510. if roads then
  511. tables.roads:insert(output)
  512. end
  513. end
  514. end
  515. local function compute_geom_and_area(geom)
  516. local area, projected_geom
  517. projected_geom = geom:transform(srid)
  518. if reproject_area and srid ~= 3857 then
  519. area = geom:transform(3857):area()
  520. else
  521. area = projected_geom:area()
  522. end
  523. return projected_geom, area
  524. end
  525. function osm2pgsql.process_way(object)
  526. if clean_tags(object.tags) then
  527. return
  528. end
  529. local add_area = false
  530. if object.tags.natural == 'coastline' then
  531. add_area = true
  532. if not keep_coastlines then
  533. object.tags.natural = nil
  534. end
  535. end
  536. local output
  537. local output_hstore = {}
  538. if hstore or hstore_all then
  539. output, output_hstore = get_non_point_output(object.tags)
  540. if not next(output) and not next(output_hstore) then
  541. return
  542. end
  543. if hstore_match_only and not has_generic_tag(object.tags) then
  544. return
  545. end
  546. if add_area and hstore_all then
  547. output_hstore.area = 'yes'
  548. end
  549. else
  550. output = object.tags
  551. if not has_generic_tag(object.tags) then
  552. return
  553. end
  554. end
  555. local polygon
  556. local area_tag = object.tags.area
  557. if area_tag == 'yes' or area_tag == '1' or area_tag == 'true' then
  558. polygon = true
  559. elseif area_tag == 'no' or area_tag == '0' or area_tag == 'false' then
  560. polygon = false
  561. else
  562. polygon = is_polygon(object.tags)
  563. end
  564. if add_area then
  565. output.area = 'yes'
  566. polygon = true
  567. end
  568. local z_order, roads = get_z_order(object.tags)
  569. output.z_order = z_order
  570. output.tags = output_hstore
  571. if hstore_column then
  572. output[hstore_column] = get_hstore_column(object.tags)
  573. end
  574. if polygon and object.is_closed then
  575. local pgeom, area = compute_geom_and_area(object:as_polygon())
  576. output.way = pgeom
  577. output.way_area = area
  578. tables.polygon:insert(output)
  579. else
  580. add_line(output, object:as_linestring(), roads)
  581. end
  582. end
  583. function osm2pgsql.process_relation(object)
  584. if clean_tags(object.tags) then
  585. return
  586. end
  587. local rtype = object:grab_tag('type')
  588. if (rtype ~= 'route') and (rtype ~= 'multipolygon') and (rtype ~= 'boundary') then
  589. return
  590. end
  591. local output
  592. local output_hstore = {}
  593. if hstore or hstore_all then
  594. output, output_hstore = get_non_point_output(object.tags)
  595. if not next(output) and not next(output_hstore) then
  596. return
  597. end
  598. if hstore_match_only and not has_generic_tag(object.tags) then
  599. return
  600. end
  601. else
  602. output = object.tags
  603. if not has_generic_tag(object.tags) then
  604. return
  605. end
  606. end
  607. if not next(output) and not next(output_hstore) then
  608. return
  609. end
  610. if enable_legacy_route_processing and (hstore or hstore_all) and rtype == 'route' then
  611. if not object.tags.route_name then
  612. output_hstore.route_name = object.tags.name
  613. end
  614. local state = object.tags.state
  615. if state ~= 'alternate' and state ~= 'connection' then
  616. state = 'yes'
  617. end
  618. local network = object.tags.network
  619. if network == 'lcn' then
  620. output_hstore.lcn = output_hstore.lcn or state
  621. output_hstore.lcn_ref = output_hstore.lcn_ref or object.tags.ref
  622. elseif network == 'rcn' then
  623. output_hstore.rcn = output_hstore.rcn or state
  624. output_hstore.rcn_ref = output_hstore.rcn_ref or object.tags.ref
  625. elseif network == 'ncn' then
  626. output_hstore.ncn = output_hstore.ncn or state
  627. output_hstore.ncn_ref = output_hstore.ncn_ref or object.tags.ref
  628. elseif network == 'lwn' then
  629. output_hstore.lwn = output_hstore.lwn or state
  630. output_hstore.lwn_ref = output_hstore.lwn_ref or object.tags.ref
  631. elseif network == 'rwn' then
  632. output_hstore.rwn = output_hstore.rwn or state
  633. output_hstore.rwn_ref = output_hstore.rwn_ref or object.tags.ref
  634. elseif network == 'nwn' then
  635. output_hstore.nwn = output_hstore.nwn or state
  636. output_hstore.nwn_ref = output_hstore.nwn_ref or object.tags.ref
  637. end
  638. local pc = object.tags.preferred_color
  639. if pc == '0' or pc == '1' or pc == '2' or pc == '3' or pc == '4' then
  640. output_hstore.route_pref_color = pc
  641. else
  642. output_hstore.route_pref_color = '0'
  643. end
  644. end
  645. local make_boundary = false
  646. local make_polygon = false
  647. if rtype == 'boundary' then
  648. make_boundary = true
  649. elseif rtype == 'multipolygon' and object.tags.boundary then
  650. make_boundary = true
  651. elseif rtype == 'multipolygon' then
  652. make_polygon = true
  653. end
  654. local z_order, roads = get_z_order(object.tags)
  655. output.z_order = z_order
  656. output.tags = output_hstore
  657. if hstore_column then
  658. output[hstore_column] = get_hstore_column(object.tags)
  659. end
  660. if not make_polygon then
  661. add_line(output, object:as_multilinestring(), roads)
  662. end
  663. if make_boundary or make_polygon then
  664. local geom = object:as_multipolygon()
  665. if multi_geometry then
  666. local pgeom, area = compute_geom_and_area(geom)
  667. output.way = pgeom
  668. output.way_area = area
  669. tables.polygon:insert(output)
  670. else
  671. for sgeom in geom:geometries() do
  672. local pgeom, area = compute_geom_and_area(sgeom)
  673. output.way = pgeom
  674. output.way_area = area
  675. tables.polygon:insert(output)
  676. end
  677. end
  678. end
  679. end