]> git.openstreetmap.org Git - nominatim.git/commitdiff
Merge pull request #2597 from lonvia/reorganise-interpolations
authorSarah Hoffmann <lonvia@denofr.de>
Fri, 28 Jan 2022 07:40:08 +0000 (08:40 +0100)
committerGitHub <noreply@github.com>
Fri, 28 Jan 2022 07:40:08 +0000 (08:40 +0100)
Reorganise interpolation code

21 files changed:
.github/workflows/ci-tests.yml
docs/admin/Faq.md
docs/admin/Installation.md
lib-php/PlaceLookup.php
lib-php/ReverseGeocode.php
lib-php/SearchDescription.php
lib-php/lib.php
lib-sql/functions/interpolation.sql
lib-sql/functions/place_triggers.sql
lib-sql/functions/placex_triggers.sql
lib-sql/indices.sql
lib-sql/tables.sql
lib-sql/tiger_import_finish.sql
lib-sql/tiger_import_start.sql
module/CMakeLists.txt
nominatim/tools/migration.py
nominatim/version.py
test/bdd/api/reverse/queries.feature
test/bdd/db/import/interpolation.feature
test/bdd/db/update/interpolation.feature
test/php/Nominatim/LibTest.php

index 88de09a1eb8d74ecd22744c1a59eee37b1512c29..ac8ad5af43d248468241694edfe8b4c8a8765f76 100644 (file)
@@ -40,7 +40,7 @@ jobs:
                 ubuntu: [18, 20]
                 include:
                     - ubuntu: 18
-                      postgresql: 9.5
+                      postgresql: 9.6
                       postgis: 2.5
                       pytest: pytest
                       php: 7.2
index d933a84d468a0fc55440944e56e51b727eae57fd..5737cef5540c5a3a4887a7f0fdb67c8ddbb1bb76 100644 (file)
@@ -79,7 +79,7 @@ When running the import you may get a version mismatch:
 
 pg_config seems to use bad includes sometimes when multiple versions
 of PostgreSQL are available in the system. Make sure you remove the
-server development libraries (`postgresql-server-dev-9.5` on Ubuntu)
+server development libraries (`postgresql-server-dev-13` on Ubuntu)
 and recompile (`cmake .. && make`).
 
 
index 6b63b0d3cfe62266240d4067ff75cb7315e742e6..19ad2dbb9b0be7853a67346edf17d2fd1d5606db 100644 (file)
@@ -41,7 +41,7 @@ For compiling:
 
 For running Nominatim:
 
-  * [PostgreSQL](https://www.postgresql.org) (9.5+ will work, 11+ strongly recommended)
+  * [PostgreSQL](https://www.postgresql.org) (9.6+ will work, 11+ strongly recommended)
   * [PostGIS](https://postgis.net) (2.2+ will work, 3.0+ strongly recommended)
   * [Python 3](https://www.python.org/) (3.6+)
   * [Psycopg2](https://www.psycopg.org) (2.7+)
index 09acb54444c86872fe1cd6682a15d7f2b0664c35..120f55436acb482de8d374019b2a30b05ffd2c0b 100644 (file)
@@ -348,7 +348,9 @@ class PlaceLookup
                     $sSQL .= '     null::text AS extra_place ';
                     $sSQL .= ' FROM (';
                     $sSQL .= '     SELECT place_id, ';    // interpolate the Tiger housenumbers here
-                    $sSQL .= '         ST_LineInterpolatePoint(linegeo, (housenumber_for_place-startnumber::float)/(endnumber-startnumber)::float) AS centroid, ';
+                    $sSQL .= '         CASE WHEN startnumber != endnumber';
+                    $sSQL .= '              THEN ST_LineInterpolatePoint(linegeo, (housenumber_for_place-startnumber::float)/(endnumber-startnumber)::float)';
+                    $sSQL .= '              ELSE ST_LineInterpolatePoint(linegeo, 0.5) END AS centroid, ';
                     $sSQL .= '         parent_place_id, ';
                     $sSQL .= '         housenumber_for_place';
                     $sSQL .= '     FROM (';
@@ -405,7 +407,7 @@ class PlaceLookup
                 $sSQL .= '         CASE ';             // interpolate the housenumbers here
                 $sSQL .= '           WHEN startnumber != endnumber ';
                 $sSQL .= '           THEN ST_LineInterpolatePoint(linegeo, (housenumber_for_place-startnumber::float)/(endnumber-startnumber)::float) ';
-                $sSQL .= '           ELSE ST_LineInterpolatePoint(linegeo, 0.5) ';
+                $sSQL .= '           ELSE linegeo ';
                 $sSQL .= '         END as centroid, ';
                 $sSQL .= '         parent_place_id, ';
                 $sSQL .= '         housenumber_for_place ';
index 5a8528891b195399dd513424350a35d98638f04f..646c592b9f5d4b3dc5efba035406602f0b44d3bc 100644 (file)
@@ -64,8 +64,8 @@ class ReverseGeocode
     {
         Debug::newFunction('lookupInterpolation');
         $sSQL = 'SELECT place_id, parent_place_id, 30 as rank_search,';
-        $sSQL .= '  ST_LineLocatePoint(linegeo,'.$sPointSQL.') as fraction,';
-        $sSQL .= '  startnumber, endnumber, interpolationtype,';
+        $sSQL .= '  (endnumber - startnumber) * ST_LineLocatePoint(linegeo,'.$sPointSQL.') as fhnr,';
+        $sSQL .= '  startnumber, endnumber, step,';
         $sSQL .= '  ST_Distance(linegeo,'.$sPointSQL.') as distance';
         $sSQL .= ' FROM location_property_osmline';
         $sSQL .= ' WHERE ST_DWithin('.$sPointSQL.', linegeo, '.$fSearchDiam.')';
@@ -327,9 +327,9 @@ class ReverseGeocode
                     && $this->iMaxRank >= 28
                 ) {
                     $sSQL = 'SELECT place_id,parent_place_id,30 as rank_search,';
-                    $sSQL .= 'ST_LineLocatePoint(linegeo,'.$sPointSQL.') as fraction,';
-                    $sSQL .= 'ST_distance('.$sPointSQL.', linegeo) as distance,';
-                    $sSQL .= 'startnumber,endnumber,interpolationtype';
+                    $sSQL .= '      (endnumber - startnumber) * ST_LineLocatePoint(linegeo,'.$sPointSQL.') as fhnr,';
+                    $sSQL .= '      startnumber, endnumber, step,';
+                    $sSQL .= '      ST_Distance('.$sPointSQL.', linegeo) as distance';
                     $sSQL .= ' FROM location_property_tiger WHERE parent_place_id = '.$oResult->iId;
                     $sSQL .= ' AND ST_DWithin('.$sPointSQL.', linegeo, 0.001)';
                     $sSQL .= ' ORDER BY distance ASC limit 1';
@@ -341,7 +341,11 @@ class ReverseGeocode
                     if ($aPlaceTiger) {
                         $aPlace = $aPlaceTiger;
                         $oResult = new Result($aPlaceTiger['place_id'], Result::TABLE_TIGER);
-                        $oResult->iHouseNumber = closestHouseNumber($aPlaceTiger);
+                        $iRndNum = max(0, round($aPlaceTiger['fhnr'] / $aPlaceTiger['step']) * $aPlaceTiger['step']);
+                        $oResult->iHouseNumber = $aPlaceTiger['startnumber'] + $iRndNum;
+                        if ($oResult->iHouseNumber > $aPlaceTiger['endnumber']) {
+                            $oResult->iHouseNumber = $aPlaceTiger['endnumber'];
+                        }
                         $iRankAddress = 30;
                     }
                 }
@@ -363,7 +367,11 @@ class ReverseGeocode
 
                 if ($aHouse) {
                     $oResult = new Result($aHouse['place_id'], Result::TABLE_OSMLINE);
-                    $oResult->iHouseNumber = closestHouseNumber($aHouse);
+                    $iRndNum = max(0, round($aHouse['fhnr'] / $aHouse['step']) * $aHouse['step']);
+                    $oResult->iHouseNumber = $aHouse['startnumber'] + $iRndNum;
+                    if ($oResult->iHouseNumber > $aHouse['endnumber']) {
+                        $oResult->iHouseNumber = $aHouse['endnumber'];
+                    }
                     $aPlace = $aHouse;
                 }
             }
index 089f09c0d258d954701abcb4424604f489d79964..d2995e8e08ea3e62c859c537b3ff7c35356a626c 100644 (file)
@@ -769,18 +769,9 @@ class SearchDescription
             // if nothing found, search in the interpolation line table
             $sSQL = 'SELECT distinct place_id FROM location_property_osmline';
             $sSQL .= ' WHERE startnumber is not NULL';
-            $sSQL .= '  AND parent_place_id in ('.$sRoadPlaceIDs.') AND (';
-            if ($iHousenumber % 2 == 0) {
-                // If housenumber is even, look for housenumber in streets
-                // with interpolationtype even or all.
-                $sSQL .= "interpolationtype='even'";
-            } else {
-                // Else look for housenumber with interpolationtype odd or all.
-                $sSQL .= "interpolationtype='odd'";
-            }
-            $sSQL .= " or interpolationtype='all') and ";
-            $sSQL .= $iHousenumber.'>=startnumber and ';
-            $sSQL .= $iHousenumber.'<=endnumber';
+            $sSQL .= '  and parent_place_id in ('.$sRoadPlaceIDs.')';
+            $sSQL .= '  and ('.$iHousenumber.' - startnumber) % step = 0';
+            $sSQL .= '  and '.$iHousenumber.' between startnumber and endnumber';
             $sSQL .= $this->oContext->excludeSQL(' AND place_id');
 
             Debug::printSQL($sSQL);
@@ -795,15 +786,9 @@ class SearchDescription
         // If nothing found then search in Tiger data (location_property_tiger)
         if (CONST_Use_US_Tiger_Data && $sRoadPlaceIDs && $bIsIntHouseNumber && empty($aResults)) {
             $sSQL = 'SELECT place_id FROM location_property_tiger';
-            $sSQL .= ' WHERE parent_place_id in ('.$sRoadPlaceIDs.') and (';
-            if ($iHousenumber % 2 == 0) {
-                $sSQL .= "interpolationtype='even'";
-            } else {
-                $sSQL .= "interpolationtype='odd'";
-            }
-            $sSQL .= " or interpolationtype='all') and ";
-            $sSQL .= $iHousenumber.'>=startnumber and ';
-            $sSQL .= $iHousenumber.'<=endnumber';
+            $sSQL .= ' WHERE parent_place_id in ('.$sRoadPlaceIDs.')';
+            $sSQL .= '  and ('.$iHousenumber.' - startnumber) % step = 0';
+            $sSQL .= '  and '.$iHousenumber.' between startnumber and endnumber';
             $sSQL .= $this->oContext->excludeSQL(' AND place_id');
 
             Debug::printSQL($sSQL);
index 3ba50dc03fd7533c6c7dcc2982f66a0ff2e86f46..9babe5ed907ca91c290b967630f777510fe21df9 100644 (file)
@@ -206,26 +206,6 @@ function parseLatLon($sQuery)
     return array($sFound, $fQueryLat, $fQueryLon);
 }
 
-function closestHouseNumber($aRow)
-{
-    $fHouse = $aRow['startnumber']
-                + ($aRow['endnumber'] - $aRow['startnumber']) * $aRow['fraction'];
-
-    switch ($aRow['interpolationtype']) {
-        case 'odd':
-            $iHn = (int)($fHouse/2) * 2 + 1;
-            break;
-        case 'even':
-            $iHn = (int)(round($fHouse/2)) * 2;
-            break;
-        default:
-            $iHn = (int)(round($fHouse));
-            break;
-    }
-
-    return max(min($aRow['endnumber'], $iHn), $aRow['startnumber']);
-}
-
 if (!function_exists('array_key_last')) {
     function array_key_last(array $array)
     {
index a8ef37715f59266f5bbfb57add57e2709fc7f9bc..64775678bb26f8159969ca1144a64aa05ab18ce3 100644 (file)
@@ -7,17 +7,6 @@
 
 -- Functions for address interpolation objects in location_property_osmline.
 
--- Splits the line at the given point and returns the two parts
--- in a multilinestring.
-CREATE OR REPLACE FUNCTION split_line_on_node(line GEOMETRY, point GEOMETRY)
-RETURNS GEOMETRY
-  AS $$
-BEGIN
-  RETURN ST_Split(ST_Snap(line, point, 0.0005), point);
-END;
-$$
-LANGUAGE plpgsql IMMUTABLE;
-
 
 CREATE OR REPLACE FUNCTION get_interpolation_address(in_address HSTORE, wayid BIGINT)
 RETURNS HSTORE
@@ -64,9 +53,13 @@ BEGIN
   IF parent_place_id is null THEN
     FOR location IN SELECT place_id FROM placex
         WHERE ST_DWithin(geom, placex.geometry, 0.001) and placex.rank_search = 26
-        ORDER BY (ST_distance(placex.geometry, ST_LineInterpolatePoint(geom,0))+
+        ORDER BY CASE WHEN ST_GeometryType(geom) = 'ST_Line' THEN
+                  (ST_distance(placex.geometry, ST_LineInterpolatePoint(geom,0))+
                   ST_distance(placex.geometry, ST_LineInterpolatePoint(geom,0.5))+
-                  ST_distance(placex.geometry, ST_LineInterpolatePoint(geom,1))) ASC limit 1
+                  ST_distance(placex.geometry, ST_LineInterpolatePoint(geom,1)))
+                 ELSE ST_distance(placex.geometry, geom) END
+              ASC
+        LIMIT 1
     LOOP
       parent_place_id := location.place_id;
     END LOOP;
@@ -82,24 +75,38 @@ $$
 LANGUAGE plpgsql STABLE;
 
 
-CREATE OR REPLACE FUNCTION osmline_reinsert(node_id BIGINT, geom GEOMETRY)
-  RETURNS BOOLEAN
+CREATE OR REPLACE FUNCTION reinsert_interpolation(way_id BIGINT, addr HSTORE,
+                                                  geom GEOMETRY)
+  RETURNS INT
   AS $$
 DECLARE
-  existingline RECORD;
+  existing BIGINT[];
 BEGIN
-   SELECT w.id FROM planet_osm_ways w, location_property_osmline p
-     WHERE p.linegeo && geom and p.osm_id = w.id and p.indexed_status = 0
-           and node_id = any(w.nodes) INTO existingline;
-
-   IF existingline.id is not NULL THEN
-       DELETE FROM location_property_osmline WHERE osm_id = existingline.id;
-       INSERT INTO location_property_osmline (osm_id, address, linegeo)
-         SELECT osm_id, address, geometry FROM place
-           WHERE osm_type = 'W' and osm_id = existingline.id;
-   END IF;
-
-   RETURN true;
+  -- Get the existing entry from the interpolation table.
+  SELECT array_agg(place_id) INTO existing
+    FROM location_property_osmline WHERE osm_id = way_id;
+
+  IF existing IS NULL or array_length(existing, 1) = 0 THEN
+    INSERT INTO location_property_osmline (osm_id, address, linegeo)
+      VALUES (way_id, addr, geom);
+  ELSE
+    -- Update the interpolation table:
+    --   The first entry gets the original data, all other entries
+    --   are removed and will be recreated on indexing.
+    --   (An interpolation can be split up, if it has more than 2 address nodes)
+    UPDATE location_property_osmline
+      SET address = addr,
+          linegeo = geom,
+          startnumber = null,
+          indexed_status = 1
+      WHERE place_id = existing[1];
+    IF array_length(existing, 1) > 1 THEN
+      DELETE FROM location_property_osmline
+        WHERE place_id = any(existing[2:]);
+    END IF;
+  END IF;
+
+  RETURN 1;
 END;
 $$
 LANGUAGE plpgsql;
@@ -114,8 +121,10 @@ BEGIN
 
   IF NEW.indexed_status IS NULL THEN
       IF NEW.address is NULL OR NOT NEW.address ? 'interpolation'
-         OR NEW.address->'interpolation' NOT IN ('odd', 'even', 'all') THEN
-          -- other interpolation types than odd/even/all (e.g. numeric ones) are not supported
+         OR NOT (NEW.address->'interpolation' in ('odd', 'even', 'all')
+                 or NEW.address->'interpolation' similar to '[1-9]')
+      THEN
+          -- alphabetic interpolation is not supported
           RETURN NULL;
       END IF;
 
@@ -136,18 +145,20 @@ CREATE OR REPLACE FUNCTION osmline_update()
   RETURNS TRIGGER
   AS $$
 DECLARE
-  place_centroid GEOMETRY;
   waynodes BIGINT[];
   prevnode RECORD;
   nextnode RECORD;
   startnumber INTEGER;
   endnumber INTEGER;
-  housenum INTEGER;
+  newstart INTEGER;
+  newend INTEGER;
+  moddiff SMALLINT;
   linegeo GEOMETRY;
   splitline GEOMETRY;
   sectiongeo GEOMETRY;
   interpol_postcode TEXT;
   postcode TEXT;
+  stepmod SMALLINT;
 BEGIN
   -- deferred delete
   IF OLD.indexed_status = 100 THEN
@@ -159,107 +170,139 @@ BEGIN
     RETURN NEW;
   END IF;
 
-  NEW.interpolationtype = NEW.address->'interpolation';
-
-  place_centroid := ST_PointOnSurface(NEW.linegeo);
-  NEW.parent_place_id = get_interpolation_parent(NEW.token_info, NEW.partition,
-                                                 place_centroid, NEW.linegeo);
+  NEW.parent_place_id := get_interpolation_parent(NEW.token_info, NEW.partition,
+                                                 ST_PointOnSurface(NEW.linegeo),
+                                                 NEW.linegeo);
 
   interpol_postcode := token_normalized_postcode(NEW.address->'postcode');
 
   NEW.token_info := token_strip_info(NEW.token_info);
   IF NEW.address ? '_inherited' THEN
-    NEW.address := hstore('interpolation', NEW.interpolationtype);
+    NEW.address := hstore('interpolation', NEW.address->'interpolation');
   END IF;
 
-  -- if the line was newly inserted, split the line as necessary
+  -- If the line was newly inserted, split the line as necessary.
   IF OLD.indexed_status = 1 THEN
-      select nodes from planet_osm_ways where id = NEW.osm_id INTO waynodes;
-
-      IF array_upper(waynodes, 1) IS NULL THEN
-        RETURN NEW;
+    IF NEW.address->'interpolation' in ('odd', 'even') THEN
+      NEW.step := 2;
+      stepmod := CASE WHEN NEW.address->'interpolation' = 'odd' THEN 1 ELSE 0 END;
+    ELSE
+      NEW.step := CASE WHEN NEW.address->'interpolation' = 'all'
+                       THEN 1
+                       ELSE (NEW.address->'interpolation')::SMALLINT END;
+      stepmod := NULL;
+    END IF;
+
+    SELECT nodes INTO waynodes
+      FROM planet_osm_ways WHERE id = NEW.osm_id;
+
+    IF array_upper(waynodes, 1) IS NULL THEN
+      RETURN NEW;
+    END IF;
+
+    linegeo := null;
+    SELECT null::integer as hnr INTO prevnode;
+
+    -- Go through all nodes on the interpolation line that have a housenumber.
+    FOR nextnode IN
+      SELECT DISTINCT ON (nodeidpos)
+          osm_id, address, geometry,
+          substring(address->'housenumber','[0-9]+')::integer as hnr
+        FROM placex, generate_series(1, array_upper(waynodes, 1)) nodeidpos
+        WHERE osm_type = 'N' and osm_id = waynodes[nodeidpos]::BIGINT
+              and address is not NULL and address ? 'housenumber'
+        ORDER BY nodeidpos
+    LOOP
+      RAISE WARNING 'processing point % (%)', nextnode.hnr, ST_AsText(nextnode.geometry);
+      IF linegeo is null THEN
+        linegeo := NEW.linegeo;
+      ELSE
+        splitline := ST_Split(ST_Snap(linegeo, nextnode.geometry, 0.0005), nextnode.geometry);
+        sectiongeo := ST_GeometryN(splitline, 1);
+        linegeo := ST_GeometryN(splitline, 2);
       END IF;
 
-      linegeo := NEW.linegeo;
-      startnumber := NULL;
-
-      FOR nodeidpos in 1..array_upper(waynodes, 1) LOOP
-
-        select osm_id, address, geometry
-          from place where osm_type = 'N' and osm_id = waynodes[nodeidpos]::BIGINT
-                           and address is not NULL and address ? 'housenumber' limit 1 INTO nextnode;
-        --RAISE NOTICE 'Nextnode.place_id: %s', nextnode.place_id;
-        IF nextnode.osm_id IS NOT NULL THEN
-          --RAISE NOTICE 'place_id is not null';
-          IF nodeidpos > 1 and nodeidpos < array_upper(waynodes, 1) THEN
-            -- Make sure that the point is actually on the line. That might
-            -- be a bit paranoid but ensures that the algorithm still works
-            -- should osm2pgsql attempt to repair geometries.
-            splitline := split_line_on_node(linegeo, nextnode.geometry);
-            sectiongeo := ST_GeometryN(splitline, 1);
-            linegeo := ST_GeometryN(splitline, 2);
+      IF prevnode.hnr is not null
+         -- Check if there are housenumbers to interpolate between the
+         -- regularly mapped housenumbers.
+         -- (Conveniently also fails if one of the house numbers is not a number.)
+         and abs(prevnode.hnr - nextnode.hnr) > NEW.step
+      THEN
+        IF prevnode.hnr < nextnode.hnr THEN
+          startnumber := prevnode.hnr;
+          endnumber := nextnode.hnr;
+        ELSE
+          startnumber := nextnode.hnr;
+          endnumber := prevnode.hnr;
+          sectiongeo := ST_Reverse(sectiongeo);
+        END IF;
+
+        -- Adjust the interpolation, so that only inner housenumbers
+        -- are taken into account.
+        IF stepmod is null THEN
+          newstart := startnumber + NEW.step;
+        ELSE
+          newstart := startnumber + 1;
+          moddiff := newstart % NEW.step - stepmod;
+          IF moddiff < 0 THEN
+            newstart := newstart + (NEW.step + moddiff);
           ELSE
-            sectiongeo = linegeo;
-          END IF;
-          endnumber := substring(nextnode.address->'housenumber','[0-9]+')::integer;
-
-          IF startnumber IS NOT NULL AND endnumber IS NOT NULL
-             AND startnumber != endnumber
-             AND ST_GeometryType(sectiongeo) = 'ST_LineString' THEN
-
-            IF (startnumber > endnumber) THEN
-              housenum := endnumber;
-              endnumber := startnumber;
-              startnumber := housenum;
-              sectiongeo := ST_Reverse(sectiongeo);
-            END IF;
-
-            -- determine postcode
-            postcode := coalesce(interpol_postcode,
-                                 token_normalized_postcode(prevnode.address->'postcode'),
-                                 token_normalized_postcode(nextnode.address->'postcode'),
-                                 postcode);
-
-            IF postcode is NULL THEN
-                SELECT token_normalized_postcode(placex.postcode)
-                  FROM placex WHERE place_id = NEW.parent_place_id INTO postcode;
-            END IF;
-            IF postcode is NULL THEN
-                postcode := get_nearest_postcode(NEW.country_code, nextnode.geometry);
-            END IF;
-
-            IF NEW.startnumber IS NULL THEN
-                NEW.startnumber := startnumber;
-                NEW.endnumber := endnumber;
-                NEW.linegeo := sectiongeo;
-                NEW.postcode := postcode;
-             ELSE
-              insert into location_property_osmline
-                     (linegeo, partition, osm_id, parent_place_id,
-                      startnumber, endnumber, interpolationtype,
-                      address, postcode, country_code,
-                      geometry_sector, indexed_status)
-              values (sectiongeo, NEW.partition, NEW.osm_id, NEW.parent_place_id,
-                      startnumber, endnumber, NEW.interpolationtype,
-                      NEW.address, postcode,
-                      NEW.country_code, NEW.geometry_sector, 0);
-             END IF;
+            newstart := newstart + moddiff;
           END IF;
+        END IF;
+        newend := newstart + ((endnumber - 1 - newstart) / NEW.step) * NEW.step;
+
+        -- If newstart and newend are the same, then this returns a point.
+        sectiongeo := ST_LineSubstring(sectiongeo,
+                              (newstart - startnumber)::float / (endnumber - startnumber)::float,
+                              (newend - startnumber)::float / (endnumber - startnumber)::float);
+        startnumber := newstart;
+        endnumber := newend;
+
+        -- determine postcode
+        postcode := coalesce(interpol_postcode,
+                             token_normalized_postcode(prevnode.address->'postcode'),
+                             token_normalized_postcode(nextnode.address->'postcode'),
+                             postcode);
+        IF postcode is NULL THEN
+            SELECT token_normalized_postcode(placex.postcode)
+              FROM placex WHERE place_id = NEW.parent_place_id INTO postcode;
+        END IF;
+        IF postcode is NULL THEN
+            postcode := get_nearest_postcode(NEW.country_code, nextnode.geometry);
+        END IF;
 
-          -- early break if we are out of line string,
-          -- might happen when a line string loops back on itself
-          IF ST_GeometryType(linegeo) != 'ST_LineString' THEN
-              RETURN NEW;
-          END IF;
+        -- Add the interpolation. If this is the first segment, just modify
+        -- the interpolation to be inserted, otherwise add an additional one
+        -- (marking it indexed already).
+        IF NEW.startnumber IS NULL THEN
+            NEW.startnumber := startnumber;
+            NEW.endnumber := endnumber;
+            NEW.linegeo := sectiongeo;
+            NEW.postcode := postcode;
+        ELSE
+          INSERT INTO location_property_osmline
+                 (linegeo, partition, osm_id, parent_place_id,
+                  startnumber, endnumber, step,
+                  address, postcode, country_code,
+                  geometry_sector, indexed_status)
+          VALUES (sectiongeo, NEW.partition, NEW.osm_id, NEW.parent_place_id,
+                  startnumber, endnumber, NEW.step,
+                  NEW.address, postcode,
+                  NEW.country_code, NEW.geometry_sector, 0);
+        END IF;
 
-          startnumber := substring(nextnode.address->'housenumber','[0-9]+')::integer;
-          prevnode := nextnode;
+        -- early break if we are out of line string,
+        -- might happen when a line string loops back on itself
+        IF ST_GeometryType(linegeo) != 'ST_LineString' THEN
+            RETURN NEW;
         END IF;
-      END LOOP;
+      END IF;
+
+      prevnode := nextnode;
+    END LOOP;
   END IF;
 
-  -- marking descendants for reparenting is not needed, because there are
-  -- actually no descendants for interpolation lines
   RETURN NEW;
 END;
 $$
index 4e316990786b152c8698b06eee1bf6e35629845a..a472d26d898e5b9df70e06014ca55b936e28eb5c 100644 (file)
@@ -13,8 +13,8 @@ DECLARE
   country RECORD;
   existing RECORD;
   existingplacex RECORD;
-  existingline RECORD;
-  result BOOLEAN;
+  existingline BIGINT[];
+  interpol RECORD;
 BEGIN
   {% if debug %}
     RAISE WARNING 'place_insert: % % % % %',NEW.osm_type,NEW.osm_id,NEW.class,NEW.type,st_area(NEW.geometry);
@@ -57,19 +57,7 @@ BEGIN
   IF NEW.class='place' and NEW.type='houses'
      and NEW.osm_type='W' and ST_GeometryType(NEW.geometry) = 'ST_LineString'
   THEN
-    -- Get the existing entry from the interpolation table.
-    SELECT * INTO existingline
-      FROM location_property_osmline WHERE osm_id = NEW.osm_id;
-
-    -- Update the interpolation table:
-    --   delete all old interpolation lines with same osm_id
-    --   and insert the new one(s) (they can be split up, if they have > 2 nodes)
-    IF existingline.osm_id IS NOT NULL THEN
-      DELETE FROM location_property_osmline where osm_id = NEW.osm_id;
-    END IF;
-
-    INSERT INTO location_property_osmline (osm_id, address, linegeo)
-      VALUES (NEW.osm_id, NEW.address, NEW.geometry);
+    PERFORM reinsert_interpolation(NEW.osm_id, NEW.address, NEW.geometry);
 
     -- Now invalidate all address nodes on the line.
     -- They get their parent from the interpolation.
@@ -156,6 +144,28 @@ BEGIN
     RETURN null;
   END IF;
 
+  -- If an address node is part of a interpolation line and changes or is
+  -- newly inserted (happens when the node already existed but now gets address
+  -- information), then mark the interpolation line for reparenting.
+  -- (Already here, because interpolation lines are reindexed before nodes,
+  --  so in the second call it would be too late.)
+  IF NEW.osm_type='N'
+     and coalesce(existing.address, ''::hstore) != coalesce(NEW.address, ''::hstore)
+  THEN
+      FOR interpol IN
+        SELECT DISTINCT osm_id, address, geometry FROM place, planet_osm_ways w
+        WHERE NEW.geometry && place.geometry
+              and place.osm_type = 'W'
+              and exists (SELECT * FROM location_property_osmline
+                          WHERE osm_id = place.osm_id
+                                and indexed_status in (0, 2))
+              and w.id = place.osm_id and NEW.osm_id = any (w.nodes)
+      LOOP
+        PERFORM reinsert_interpolation(interpol.osm_id, interpol.address,
+                                       interpol.geometry);
+      END LOOP;
+  END IF;
+
   -- Get the existing placex entry.
   SELECT * INTO existingplacex
     FROM placex
@@ -278,16 +288,6 @@ BEGIN
           geometry = NEW.geometry
       WHERE place_id = existingplacex.place_id;
 
-    -- If an address node which is part of a interpolation line changes
-    -- mark this line for reparenting.
-    -- (Already here, because interpolation lines are reindexed before nodes,
-    --  so in the second call it would be too late.)
-    IF NEW.osm_type='N'
-       and coalesce(existing.address, ''::hstore) != coalesce(NEW.address, ''::hstore)
-    THEN
-        result:= osmline_reinsert(NEW.osm_id, NEW.geometry);
-    END IF;
-
     -- Invalidate linked places: they potentially get a new name and addresses.
     IF existingplacex.linked_place_id is not NULL THEN
       UPDATE placex x
index 1b96f87e4f079ce094e813d8e4dcddfe798a9f81..6ab73a3b4143dea539d7304ce8cc464d2109e7a5 100644 (file)
@@ -29,9 +29,9 @@ DECLARE
 BEGIN
   -- For POI nodes, check if the address should be derived from a surrounding
   -- building.
-  IF p.rank_search < 30 OR p.osm_type != 'N' OR p.address is not null THEN
+  IF p.rank_search < 30 OR p.osm_type != 'N' THEN
     result.address := p.address;
-  ELSE
+  ELSEIF p.address is null THEN
     -- The additional && condition works around the misguided query
     -- planner of postgis 3.0.
     SELECT placex.address || hstore('_inherited', '') INTO result.address
@@ -42,6 +42,20 @@ BEGIN
            and (placex.address ? 'housenumber' or placex.address ? 'street' or placex.address ? 'place')
            and rank_search = 30 AND ST_GeometryType(geometry) in ('ST_Polygon','ST_MultiPolygon')
      LIMIT 1;
+  ELSE
+    result.address := p.address;
+    -- See if we can inherit addtional address tags from an interpolation.
+    -- These will become permanent.
+    FOR location IN
+      SELECT (address - 'interpolation'::text - 'housenumber'::text) as address
+        FROM place, planet_osm_ways w
+        WHERE place.osm_type = 'W' and place.address ? 'interpolation'
+              and place.geometry && p.geometry
+              and place.osm_id = w.id
+              and p.osm_id = any(w.nodes)
+    LOOP
+      result.address := location.address || result.address;
+    END LOOP;
   END IF;
 
   result.address := result.address - '_unlisted_place'::TEXT;
@@ -131,18 +145,6 @@ BEGIN
   END IF;
 
   IF parent_place_id is null and poi_osm_type = 'N' THEN
-    -- Is this node part of an interpolation?
-    FOR location IN
-      SELECT q.parent_place_id
-        FROM location_property_osmline q, planet_osm_ways x
-       WHERE q.linegeo && bbox and x.id = q.osm_id
-             and poi_osm_id = any(x.nodes)
-       LIMIT 1
-    LOOP
-      {% if debug %}RAISE WARNING 'Get parent from interpolation: %', location.parent_place_id;{% endif %}
-      RETURN location.parent_place_id;
-    END LOOP;
-
     FOR location IN
       SELECT p.place_id, p.osm_id, p.rank_search, p.address,
              coalesce(p.centroid, ST_Centroid(p.geometry)) as centroid
@@ -626,10 +628,7 @@ BEGIN
 {% if not disable_diff_updates %}
   -- The following is not needed until doing diff updates, and slows the main index process down
 
-  IF NEW.osm_type = 'N' and NEW.rank_search > 28 THEN
-      -- might be part of an interpolation
-      result := osmline_reinsert(NEW.osm_id, NEW.geometry);
-  ELSEIF NEW.rank_address > 0 THEN
+  IF NEW.rank_address > 0 THEN
     IF (ST_GeometryType(NEW.geometry) in ('ST_Polygon','ST_MultiPolygon') AND ST_IsValid(NEW.geometry)) THEN
       -- Performance: We just can't handle re-indexing for country level changes
       IF st_area(NEW.geometry) < 1 THEN
@@ -656,7 +655,7 @@ BEGIN
           -- roads may cause reparenting for >27 rank places
           update placex set indexed_status = 2 where indexed_status = 0 and rank_search > NEW.rank_search and ST_DWithin(placex.geometry, NEW.geometry, diameter);
           -- reparenting also for OSM Interpolation Lines (and for Tiger?)
-          update location_property_osmline set indexed_status = 2 where indexed_status = 0 and ST_DWithin(location_property_osmline.linegeo, NEW.geometry, diameter);
+          update location_property_osmline set indexed_status = 2 where indexed_status = 0 and startnumber is not null and ST_DWithin(location_property_osmline.linegeo, NEW.geometry, diameter);
         ELSEIF NEW.rank_search >= 16 THEN
           -- up to rank 16, street-less addresses may need reparenting
           update placex set indexed_status = 2 where indexed_status = 0 and rank_search > NEW.rank_search and ST_DWithin(placex.geometry, NEW.geometry, diameter) and (rank_search < 28 or name is not null or address ? 'place');
index bbcaf43da553d43d6a9e7e783392cd4f79ea1b95..ad6753c6a4b03766101ac556040929dae8cc6d79 100644 (file)
@@ -28,7 +28,8 @@ CREATE INDEX IF NOT EXISTS idx_placex_geometry_reverse_lookupPolygon
     AND name is not null AND indexed_status = 0 AND linked_place_id is null;
 
 CREATE INDEX IF NOT EXISTS idx_osmline_parent_place_id
-  ON location_property_osmline USING BTREE (parent_place_id) {{db.tablespace.search_index}};
+  ON location_property_osmline USING BTREE (parent_place_id) {{db.tablespace.search_index}}
+  WHERE parent_place_id is not null;
 
 CREATE INDEX IF NOT EXISTS idx_osmline_parent_osm_id
   ON location_property_osmline USING BTREE (osm_id) {{db.tablespace.search_index}};
@@ -48,6 +49,10 @@ CREATE INDEX IF NOT EXISTS idx_postcode_postcode
 
   CREATE UNIQUE INDEX IF NOT EXISTS idx_place_osm_unique
     ON place USING btree(osm_id, osm_type, class, type) {{db.tablespace.address_index}};
+
+  CREATE INDEX IF NOT EXISTS idx_place_interpolations
+    ON place USING gist(geometry) {{db.tablespace.address_index}}
+    WHERE osm_type = 'W' and address ? 'interpolation';
 {% endif %}
 
 -- Indices only needed for search.
@@ -62,8 +67,12 @@ CREATE INDEX IF NOT EXISTS idx_postcode_postcode
 
   {% if postgres.has_index_non_key_column %}
     CREATE INDEX IF NOT EXISTS idx_placex_housenumber
-      ON placex USING btree (parent_place_id) INCLUDE (housenumber) WHERE housenumber is not null;
+      ON placex USING btree (parent_place_id) {{db.tablespace.search_index}}
+      INCLUDE (housenumber)
+      WHERE housenumber is not null;
     CREATE INDEX IF NOT EXISTS idx_osmline_parent_osm_id_with_hnr
-      ON location_property_osmline USING btree(parent_place_id) INCLUDE (startnumber, endnumber);
+      ON location_property_osmline USING btree(parent_place_id) {{db.tablespace.search_index}}
+      INCLUDE (startnumber, endnumber)
+      WHERE startnumber is not null;
   {% endif %}
 {% endif %}
index 0b35cad2d27db9ebc812f1cdc62fd9de8a095c26..f554c58f54ca4576e1b90f8a84559e59787c2c80 100644 (file)
@@ -80,9 +80,9 @@ CREATE TABLE location_property_tiger (
   parent_place_id BIGINT,
   startnumber INTEGER,
   endnumber INTEGER,
+  step SMALLINT,
   partition SMALLINT,
   linegeo GEOMETRY,
-  interpolationtype TEXT,
   postcode TEXT);
 GRANT SELECT ON location_property_tiger TO "{{config.DATABASE_WEBUSER}}";
 
@@ -95,10 +95,10 @@ CREATE TABLE location_property_osmline (
     indexed_date TIMESTAMP,
     startnumber INTEGER,
     endnumber INTEGER,
+    step SMALLINT,
     partition SMALLINT,
     indexed_status SMALLINT,
     linegeo GEOMETRY,
-    interpolationtype TEXT,
     address HSTORE,
     token_info JSONB, -- custom column for tokenizer use only
     postcode TEXT,
@@ -106,7 +106,8 @@ CREATE TABLE location_property_osmline (
   ){{db.tablespace.search_data}};
 CREATE UNIQUE INDEX idx_osmline_place_id ON location_property_osmline USING BTREE (place_id) {{db.tablespace.search_index}};
 CREATE INDEX idx_osmline_geometry_sector ON location_property_osmline USING BTREE (geometry_sector) {{db.tablespace.address_index}};
-CREATE INDEX idx_osmline_linegeo ON location_property_osmline USING GIST (linegeo) {{db.tablespace.search_index}};
+CREATE INDEX idx_osmline_linegeo ON location_property_osmline USING GIST (linegeo) {{db.tablespace.search_index}}
+  WHERE startnumber is not null;
 GRANT SELECT ON location_property_osmline TO "{{config.DATABASE_WEBUSER}}";
 
 drop table IF EXISTS search_name;
index afe69c379494b1cf559a8072ec1d0adbdbf20b0f..c02ce2a3d79cc396c5bb9c33de4cdf38295847b6 100644 (file)
@@ -9,7 +9,7 @@
 CREATE INDEX IF NOT EXISTS idx_location_property_tiger_parent_place_id_imp
   ON location_property_tiger_import (parent_place_id)
 {% if postgres.has_index_non_key_column %}
-  INCLUDE (startnumber, endnumber)
+  INCLUDE (startnumber, endnumber, step)
 {% endif %}
   {{db.tablespace.aux_index}};
 CREATE UNIQUE INDEX IF NOT EXISTS idx_location_property_tiger_place_id_imp
index 0ad38fbb32a87329101586aabb8cdaf623980cee..0ff534368d0929f6c58eb7b2fb6b2b6ab9d5402a 100644 (file)
@@ -5,7 +5,15 @@
 -- Copyright (C) 2022 by the Nominatim developer community.
 -- For a full list of authors see the git log.
 DROP TABLE IF EXISTS location_property_tiger_import;
-CREATE TABLE location_property_tiger_import (linegeo GEOMETRY, place_id BIGINT, partition INTEGER, parent_place_id BIGINT, startnumber INTEGER, endnumber INTEGER, interpolationtype TEXT, postcode TEXT);
+CREATE TABLE location_property_tiger_import (
+  linegeo GEOMETRY,
+  place_id BIGINT,
+  partition INTEGER,
+  parent_place_id BIGINT,
+  startnumber INTEGER,
+  endnumber INTEGER,
+  step SMALLINT,
+  postcode TEXT);
 
 CREATE OR REPLACE FUNCTION tiger_line_import(linegeo GEOMETRY, in_startnumber INTEGER,
                                              in_endnumber INTEGER, interpolationtype TEXT,
@@ -24,11 +32,12 @@ DECLARE
 BEGIN
 
   IF in_endnumber > in_startnumber THEN
-    startnumber = in_startnumber;
-    endnumber = in_endnumber;
+    startnumber := in_startnumber;
+    endnumber := in_endnumber;
   ELSE
-    startnumber = in_endnumber;
-    endnumber = in_startnumber;
+    startnumber := in_endnumber;
+    endnumber := in_startnumber;
+    linegeo := ST_Reverse(linegeo);
   END IF;
 
   IF startnumber < 0 THEN
@@ -50,8 +59,10 @@ BEGIN
   END IF;
 
   -- Filter out really broken tiger data
-  IF numberrange > 0 AND (numberrange::float/stepsize::float > 500)
-                    AND ST_length(linegeo)/(numberrange::float/stepsize::float) < 0.000001 THEN
+  IF numberrange > 0
+     and numberrange::float/stepsize::float > 500
+     and ST_length(linegeo)/(numberrange::float/stepsize::float) < 0.000001
+  THEN
     RAISE WARNING 'Road too short for number range % to % (%)',startnumber,endnumber,
                   ST_length(linegeo)/(numberrange::float/stepsize::float);
     RETURN 0;
@@ -74,8 +85,12 @@ BEGIN
   END IF;
 
 --insert street(line) into import table
-insert into location_property_tiger_import (linegeo, place_id, partition, parent_place_id, startnumber, endnumber, interpolationtype, postcode)
-values (linegeo, nextval('seq_place'), out_partition, out_parent_place_id, startnumber, endnumber, interpolationtype, in_postcode);
+insert into location_property_tiger_import (linegeo, place_id, partition,
+                                            parent_place_id, startnumber, endnumber,
+                                            step, postcode)
+values (linegeo, nextval('seq_place'), out_partition,
+        out_parent_place_id, startnumber, endnumber,
+        stepsize, in_postcode);
 
   RETURN 1;
 END;
index 6aef6a5acfb12ad4d9bfc3f664f55701c21ef266..9684a8172ef0fdf7fc7de08564b99e3cb634a695 100644 (file)
@@ -1,6 +1,6 @@
 # just use the pgxs makefile
 
-foreach(suffix ${PostgreSQL_ADDITIONAL_VERSIONS} "13" "12" "11" "10" "9.6" "9.5" "9.4" "9.3")
+foreach(suffix ${PostgreSQL_ADDITIONAL_VERSIONS} "14" "13" "12" "11" "10" "9.6")
     list(APPEND PG_CONFIG_HINTS
          "/usr/pgsql-${suffix}/bin")
 endforeach()
index 94058f334e94ef9954e0f6ea15a0bbbafd875d9f..dc6dfecabd811f1bad1faa4eb923323565611e8b 100644 (file)
@@ -216,3 +216,58 @@ def create_tiger_housenumber_index(conn, **_):
                             ON location_property_tiger
                             USING btree(parent_place_id)
                             INCLUDE (startnumber, endnumber) """)
+
+
+@_migration(4, 0, 99, 1)
+def create_interpolation_index_on_place(conn, **_):
+    """ Create idx_place_interpolations for lookup of interpolation lines
+        on updates.
+    """
+    with conn.cursor() as cur:
+        cur.execute("""CREATE INDEX IF NOT EXISTS idx_place_interpolations
+                       ON place USING gist(geometry)
+                       WHERE osm_type = 'W' and address ? 'interpolation'""")
+
+
+@_migration(4, 0, 99, 2)
+def add_step_column_for_interpolation(conn, **_):
+    """ Add a new column 'step' to the interpolations table.
+
+        Also convers the data into the stricter format which requires that
+        startnumbers comply with the odd/even requirements.
+    """
+    with conn.cursor() as cur:
+        # Mark invalid all interpolations with no intermediate numbers.
+        cur.execute("""UPDATE location_property_osmline SET startnumber = null
+                       WHERE endnumber - startnumber <= 1 """)
+        # Align the start numbers where odd/even does not match.
+        cur.execute("""UPDATE location_property_osmline
+                       SET startnumber = startnumber + 1,
+                           linegeo = ST_LineSubString(linegeo,
+                                                      1.0 / (endnumber - startnumber)::float,
+                                                      1)
+                       WHERE (interpolationtype = 'odd' and startnumber % 2 = 0)
+                              or (interpolationtype = 'even' and startnumber % 2 = 1)
+                    """)
+        # Mark invalid odd/even interpolations with no intermediate numbers.
+        cur.execute("""UPDATE location_property_osmline SET startnumber = null
+                       WHERE interpolationtype in ('odd', 'even')
+                             and endnumber - startnumber = 2""")
+        # Finally add the new column and populate it.
+        cur.execute("ALTER TABLE location_property_osmline ADD COLUMN step SMALLINT")
+        cur.execute("""UPDATE location_property_osmline
+                         SET step = CASE WHEN interpolationtype = 'all'
+                                         THEN 1 ELSE 2 END
+                    """)
+
+
+@_migration(4, 0, 99, 3)
+def add_step_column_for_tiger(conn, **_):
+    """ Add a new column 'step' to the tiger data table.
+    """
+    with conn.cursor() as cur:
+        cur.execute("ALTER TABLE location_property_tiger ADD COLUMN step SMALLINT")
+        cur.execute("""UPDATE location_property_tiger
+                         SET step = CASE WHEN interpolationtype = 'all'
+                                         THEN 1 ELSE 2 END
+                    """)
index cb7f59bc8a5ea5037f25f88e5d3ac79aa58d0649..289af9346ef3c7957ca6c7873c54172759c090bb 100644 (file)
@@ -20,11 +20,11 @@ Version information for Nominatim.
 # to 99 to make sure that the migration is applied when updating from a
 # patch release to the next minor version. Patch releases usually shouldn't
 # have migrations in them. When they are needed, then make sure that the
-# migration can reapplied and set the migration version to the appropriate
+# migration can be reapplied and set the migration version to the appropriate
 # patch level when cherry-picking the commit with the migration.
 #
 # Released versions always have a database patch level of 0.
-NOMINATIM_VERSION = (4, 0, 99, 1)
+NOMINATIM_VERSION = (4, 0, 99, 4)
 
 POSTGRESQL_REQUIRED_VERSION = (9, 5)
 POSTGIS_REQUIRED_VERSION = (2, 2)
index 303af2c35734120872587911f1d7282a15f24c39..a2b0f033739e7088fd843874ae77a92a87aee206 100644 (file)
@@ -10,7 +10,7 @@ Feature: Reverse geocoding
           | way      | place    | house |
         And result addresses contain
           | house_number | road                | postcode | country_code |
-          | 697          | Upper Kingston Road | 36067    | us |
+          | 707          | Upper Kingston Road | 36067    | us |
 
     @Tiger
     Scenario: No TIGER house number for zoom < 18
index 181e87eec56f3b471616cf883964f4e84eb4bd2b..54d22962c5373cde05aad755c91d2c1fadc485cb 100644 (file)
@@ -16,23 +16,23 @@ Feature: Import of address interpolations
         When importing
         Then W1 expands to interpolation
           | start | end | geometry |
-          | 2     | 6   | 1 1, 1 1.001 |
+          | 4     | 4   | 1 1.0005 |
 
     Scenario: Backwards even two point interpolation line
         Given the places
           | osm | class | type   | housenr | geometry |
           | N1  | place | house  | 2       | 1 1 |
-          | N2  | place | house  | 6       | 1 1.001 |
+          | N2  | place | house  | 8       | 1 1.003 |
         And the places
           | osm | class | type   | addr+interpolation | geometry |
-          | W1  | place | houses | even    | 1 1.001, 1 1 |
+          | W1  | place | houses | even    | 1 1.003, 1 1 |
         And the ways
           | id | nodes |
           | 1  | 2,1 |
         When importing
         Then W1 expands to interpolation
           | start | end | geometry |
-          | 2     | 6   | 1 1, 1 1.001 |
+          | 4     | 6   | 1 1.001, 1 1.002 |
 
     Scenario: Simple odd two point interpolation
         Given the places
@@ -48,23 +48,23 @@ Feature: Import of address interpolations
         When importing
         Then W1 expands to interpolation
           | start | end | geometry |
-          | 1     | 11  | 1 1, 1 1.001 |
+          | 3     | 9  | 1 1.0002, 1 1.0008 |
 
     Scenario: Simple all two point interpolation
         Given the places
           | osm | class | type   | housenr | geometry |
           | N1  | place | house  | 1       | 1 1 |
-          | N2  | place | house  | 3       | 1 1.001 |
+          | N2  | place | house  | 4       | 1 1.003 |
         And the places
           | osm | class | type   | addr+interpolation | geometry |
-          | W1  | place | houses | all     | 1 1, 1 1.001 |
+          | W1  | place | houses | all     | 1 1, 1 1.003 |
         And the ways
           | id | nodes |
           | 1  | 1,2 |
         When importing
         Then W1 expands to interpolation
           | start | end | geometry |
-          | 1     | 3   | 1 1, 1 1.001 |
+          | 2     | 3   | 1 1.001, 1 1.002 |
 
     Scenario: Even two point interpolation line with intermediate empty node
         Given the places
@@ -80,7 +80,7 @@ Feature: Import of address interpolations
         When importing
         Then W1 expands to interpolation
           | start | end | geometry |
-          | 2     | 10  | 1 1, 1 1.001, 1.001 1.001 |
+          | 4     | 8   | 1 1.0005, 1 1.001, 1.0005 1.001 |
 
     Scenario: Even two point interpolation line with intermediate duplicated empty node
         Given the places
@@ -96,7 +96,7 @@ Feature: Import of address interpolations
         When importing
         Then W1 expands to interpolation
           | start | end | geometry |
-          | 2     | 10  | 1 1, 1 1.001, 1.001 1.001 |
+          | 4     | 8   | 1 1.0005, 1 1.001, 1.0005 1.001 |
 
     Scenario: Simple even three point interpolation line
         Given the places
@@ -113,8 +113,8 @@ Feature: Import of address interpolations
         When importing
         Then W1 expands to interpolation
           | start | end | geometry |
-          | 2     | 10  | 1 1, 1 1.001 |
-          | 10    | 14  | 1 1.001, 1.001 1.001 |
+          | 4     |  8  | 1 1.00025, 1 1.00075 |
+          | 12    | 12  | 1.0005 1.001 |
 
     Scenario: Simple even four point interpolation line
         Given the places
@@ -132,9 +132,9 @@ Feature: Import of address interpolations
         When importing
         Then W1 expands to interpolation
           | start | end | geometry |
-          | 2     | 10  | 1 1, 1 1.001 |
-          | 10    | 14  | 1 1.001, 1.001 1.001 |
-          | 14    | 18  | 1.001 1.001, 1.001 1.002 |
+          | 4     | 8   | 1 1.00025, 1 1.00075 |
+          | 12    | 12  | 1.0005 1.001 |
+          | 16    | 16  | 1.001 1.0015 |
 
     Scenario: Reverse simple even three point interpolation line
         Given the places
@@ -151,8 +151,8 @@ Feature: Import of address interpolations
         When importing
         Then W1 expands to interpolation
           | start | end | geometry |
-          | 2     | 10  | 1 1, 1 1.001 |
-          | 10    | 14  | 1 1.001, 1.001 1.001 |
+          | 4     |  8  | 1 1.00025, 1 1.00075 |
+          | 12    | 12  | 1.0005 1.001 |
 
     Scenario: Even three point interpolation line with odd center point
         Given the places
@@ -169,8 +169,7 @@ Feature: Import of address interpolations
         When importing
         Then W1 expands to interpolation
           | start | end | geometry |
-          | 2     | 7   | 1 1, 1 1.001 |
-          | 7     | 8   | 1 1.001, 1.001 1.001 |
+          | 4     | 6   | 1 1.0004, 1 1.0008 |
 
     Scenario: Interpolation line with self-intersecting way
         Given the places
@@ -187,9 +186,9 @@ Feature: Import of address interpolations
         When importing
         Then W1 expands to interpolation
           | start | end | geometry |
-          | 2     | 6   | 0 0, 0 0.001 |
-          | 6     | 10  | 0 0.001, 0 0.002 |
-          | 6     | 10  | 0 0.001, 0 0.002 |
+          | 4     | 4   | 0 0.0005 |
+          | 8     | 8   | 0 0.0015 |
+          | 8     | 8   | 0 0.0015 |
 
     Scenario: Interpolation line with self-intersecting way II
         Given the places
@@ -205,7 +204,7 @@ Feature: Import of address interpolations
         When importing
         Then W1 expands to interpolation
           | start | end | geometry |
-          | 2     | 6   | 0 0, 0 0.001 |
+          | 4     | 4   | 0 0.0005 |
 
     Scenario: addr:street on interpolation way
         Given the scene parallel-road
@@ -236,10 +235,10 @@ Feature: Import of address interpolations
           | N4     | W3 |
         Then W10 expands to interpolation
           | parent_place_id | start | end |
-          | W2              | 2     | 6 |
+          | W2              | 4     | 4 |
         Then W11 expands to interpolation
           | parent_place_id | start | end |
-          | W3              | 12    | 16 |
+          | W3              | 14    | 14 |
         When sending search query "16 Cloud Street"
         Then results contain
          | ID | osm_type | osm_id |
@@ -278,10 +277,10 @@ Feature: Import of address interpolations
           | N4     | W3 |
         Then W10 expands to interpolation
           | parent_place_id | start | end |
-          | W2              | 2     | 6 |
+          | W2              | 4     | 4 |
         Then W11 expands to interpolation
           | parent_place_id | start | end |
-          | W3              | 12    | 16 |
+          | W3              | 14    | 14 |
         When sending search query "16 Cloud Street"
         Then results contain
          | ID | osm_type | osm_id |
@@ -306,8 +305,8 @@ Feature: Import of address interpolations
         When importing
         Then W1 expands to interpolation
           | start | end | geometry |
-          | 2     | 6   | 144.9629794 -37.7630755, 144.9630541 -37.7628174 |
-          | 6     | 10  | 144.9630541 -37.7628174, 144.9632341 -37.76163 |
+          | 4     | 4   | 144.963016 -37.762946 |
+          | 8     | 8   | 144.963144 -37.7622237 |
 
     Scenario: Place with missing address information
         Given the grid
@@ -326,7 +325,7 @@ Feature: Import of address interpolations
         When importing
         Then W1 expands to interpolation
           | start | end | geometry |
-          | 23    | 29  | 1,2,3 |
+          | 25    | 27  | 0.000016 0,0.00002 0,0.000033 0 |
 
     Scenario: Ways without node entries are ignored
         Given the places
@@ -348,7 +347,7 @@ Feature: Import of address interpolations
         Given the places
           | osm | class | type   | housenr | geometry |
           | N1  | place | house  | 0       | 1 1 |
-          | N2  | place | house  |       | 1 1.001 |
+          | N2  | place | house  | 10      | 1 1.001 |
         And the places
           | osm | class | type   | addr+interpolation | geometry |
           | W1  | place | houses | even     | 1 1, 1 1.001 |
@@ -358,9 +357,8 @@ Feature: Import of address interpolations
         When importing
         Then W1 expands to interpolation
           | start | end | geometry |
-          | 0     | 2   | 1 1, 1 1.001 |
+          | 2     | 8   | 1 1.0002, 1 1.0008 |
         When sending jsonv2 reverse coordinates 1,1
         Then results contain
           | ID | osm_type | osm_id | type  | display_name |
-          | 0  | way      | 1      | house | 0 |
-
+          | 0  | node     | 1      | house | 0 |
index 27ac552e4d907315b2c711d756ddefdc317bf9b5..5c07f434e1ec715b9132d4ab620babf0bd3fc56d 100644 (file)
@@ -26,7 +26,7 @@ Feature: Update of address interpolations
           | N2     | W2 |
       And W10 expands to interpolation
           | parent_place_id | start | end |
-          | W2              | 2     | 6 |
+          | W2              | 4     | 4   |
 
     Scenario: addr:street added to interpolation
       Given the scene parallel-road
@@ -51,7 +51,7 @@ Feature: Update of address interpolations
           | N2     | W2 |
       And W10 expands to interpolation
           | parent_place_id | start | end |
-          | W2              | 2     | 6 |
+          | W2              | 4     | 4   |
       When updating places
           | osm | class   | type    | addr+interpolation | street       | geometry |
           | W10 | place   | houses  | even    | Cloud Street | :w-middle |
@@ -61,7 +61,7 @@ Feature: Update of address interpolations
           | N2     | W3 |
       And W10 expands to interpolation
           | parent_place_id | start | end |
-          | W3              | 2     | 6 |
+          | W3              | 4     | 4   |
 
     Scenario: addr:street added to housenumbers
       Given the scene parallel-road
@@ -86,7 +86,7 @@ Feature: Update of address interpolations
           | N2     | W2 |
       And W10 expands to interpolation
           | parent_place_id | start | end |
-          | W2              | 2     | 6 |
+          | W2              | 4     | 4 |
       When updating places
           | osm | class | type  | street      | housenr | geometry |
           | N1  | place | house | Cloud Street| 2       | :n-middle-w |
@@ -97,7 +97,7 @@ Feature: Update of address interpolations
           | N2     | W3 |
       And W10 expands to interpolation
           | parent_place_id | start | end |
-          | W3              | 2     | 6 |
+          | W3              | 4     | 4   |
 
     Scenario: interpolation tag removed
       Given the scene parallel-road
@@ -122,7 +122,7 @@ Feature: Update of address interpolations
           | N2     | W2 |
       And W10 expands to interpolation
           | parent_place_id | start | end |
-          | W2              | 2     | 6 |
+          | W2              | 4     | 4   |
       When marking for delete W10
       Then W10 expands to no interpolation
       And placex contains
@@ -152,7 +152,7 @@ Feature: Update of address interpolations
           | N2     | W2 |
       And W10 expands to interpolation
           | parent_place_id | start | end |
-          | W2              | 2     | 6 |
+          | W2              | 4     | 4 |
       When updating places
           | osm | class   | type         | name         | geometry |
           | W3  | highway | unclassified | Cloud Street | :w-south |
@@ -162,7 +162,7 @@ Feature: Update of address interpolations
           | N2     | W3 |
       And W10 expands to interpolation
           | parent_place_id | start | end |
-          | W3              | 2     | 6 |
+          | W3              | 4     | 4   |
 
     Scenario: referenced road deleted
       Given the scene parallel-road
@@ -187,7 +187,7 @@ Feature: Update of address interpolations
           | N2     | W3 |
       And W10 expands to interpolation
           | parent_place_id | start | end |
-          | W3              | 2     | 6 |
+          | W3              | 4     | 4   |
       When marking for delete W3
       Then placex contains
           | object | parent_place_id |
@@ -195,7 +195,7 @@ Feature: Update of address interpolations
           | N2     | W2 |
       And W10 expands to interpolation
           | parent_place_id | start | end |
-          | W2              | 2     | 6 |
+          | W2              | 4     | 4   |
 
     Scenario: building becomes interpolation
       Given the scene building-with-parallel-streets
@@ -222,7 +222,7 @@ Feature: Update of address interpolations
       Then placex has no entry for W1
       And W1 expands to interpolation
           | parent_place_id | start | end |
-          | W2              | 2     | 6 |
+          | W2              | 4     | 4   |
 
     Scenario: interpolation becomes building
       Given the scene building-with-parallel-streets
@@ -243,7 +243,7 @@ Feature: Update of address interpolations
       Then placex has no entry for W1
       And W1 expands to interpolation
           | parent_place_id | start | end |
-          | W2              | 2     | 6 |
+          | W2              | 4     | 4   |
       When updating places
           | osm | class    | type  | housenr | geometry |
           | W1  | place    | house | 3       | :w-building |
@@ -273,7 +273,7 @@ Feature: Update of address interpolations
           | W1  | place   | houses  | even    | Cloud Street| :w-north |
       Then W1 expands to interpolation
           | parent_place_id | start | end |
-          | W2              | 2     | 6 |
+          | W2              | 4     | 4   |
 
     Scenario: housenumber added in middle of interpolation
       Given the grid
@@ -294,15 +294,15 @@ Feature: Update of address interpolations
           | N5  | place | house | 10      |
       When importing
       Then W2 expands to interpolation
-          | parent_place_id | start | end | geometry |
-          | W1              | 2     | 10  | 3,4,5    |
+          | parent_place_id | start | end |
+          | W1              | 4     | 8  |
       When updating places
           | osm | class | type  | housenr |
           | N4  | place | house | 6       |
       Then W2 expands to interpolation
-          | parent_place_id | start | end | geometry |
-          | W1              | 2     | 6   | 3,4      |
-          | W1              | 6     | 10  | 4,5      |
+          | parent_place_id | start | end |
+          | W1              | 4     | 4   |
+          | W1              | 8     | 8   |
 
     @Fail
     Scenario: housenumber removed in middle of interpolation
@@ -325,13 +325,13 @@ Feature: Update of address interpolations
           | N5  | place | house | 10      |
       When importing
       Then W2 expands to interpolation
-          | parent_place_id | start | end | geometry |
-          | W1              | 2     | 6   | 3,4      |
-          | W1              | 6     | 10  | 4,5      |
+          | parent_place_id | start | end |
+          | W1              | 4     | 4   |
+          | W1              | 8     | 8   |
       When marking for delete N4
       Then W2 expands to interpolation
-          | parent_place_id | start | end | geometry |
-          | W1              | 2     | 10  | 3,4,5    |
+          | parent_place_id | start | end |
+          | W1              | 4     | 8   |
 
     Scenario: Change the start housenumber
       Given the grid
@@ -352,12 +352,12 @@ Feature: Update of address interpolations
           | N4  | place | house | 6       |
       When importing
       Then W2 expands to interpolation
-          | parent_place_id | start | end | geometry |
-          | W1              | 2     | 6   | 3,4      |
+          | parent_place_id | start | end |
+          | W1              | 4     | 4   |
       When updating places
           | osm | class | type  | housenr |
           | N4  | place | house | 8       |
       Then W2 expands to interpolation
-          | parent_place_id | start | end | geometry |
-          | W1              | 2     | 8   | 3,4      |
+          | parent_place_id | start | end |
+          | W1              | 4     | 6   |
 
index 249adce28052ddb7ad3dd12a7b6e02039d04d634..5d711240d152f55dcaf622725d8a474216c2a2eb 100644 (file)
@@ -91,33 +91,4 @@ class LibTest extends \PHPUnit\Framework\TestCase
             $this->assertEquals($sQuery, $aRes[0]);
         }
     }
-
-    private function closestHouseNumberEvenOddOther($startnumber, $endnumber, $fraction, $aExpected)
-    {
-        foreach (array('even', 'odd', 'other') as $itype) {
-            $this->assertEquals(
-                $aExpected[$itype],
-                closestHouseNumber(array(
-                                    'startnumber' => $startnumber,
-                                    'endnumber' => $endnumber,
-                                    'fraction' => $fraction,
-                                    'interpolationtype' => $itype
-                                   )),
-                "$startnumber => $endnumber, $fraction, $itype"
-            );
-        }
-    }
-
-    public function testClosestHouseNumber()
-    {
-        $this->closestHouseNumberEvenOddOther(50, 100, 0.5, array('even' => 76, 'odd' => 75, 'other' => 75));
-        // upper bound
-        $this->closestHouseNumberEvenOddOther(50, 100, 1.5, array('even' => 100, 'odd' => 100, 'other' => 100));
-        // lower bound
-        $this->closestHouseNumberEvenOddOther(50, 100, -0.5, array('even' => 50, 'odd' => 50, 'other' => 50));
-        // fraction 0
-        $this->closestHouseNumberEvenOddOther(50, 100, 0, array('even' => 50, 'odd' => 51, 'other' => 50));
-        // start == end
-        $this->closestHouseNumberEvenOddOther(50, 50, 0.5, array('even' => 50, 'odd' => 50, 'other' => 50));
-    }
 }