Merge branch 'interpolations'

This commit is contained in:
Sarah Hoffmann
2016-06-04 23:29:11 +02:00
27 changed files with 2030 additions and 1593 deletions

View File

@@ -431,24 +431,23 @@
if (30 >= $this->iMinAddressRank && 30 <= $this->iMaxAddressRank) if (30 >= $this->iMinAddressRank && 30 <= $this->iMaxAddressRank)
{ {
//only Tiger housenumbers and interpolation lines need to be interpolated, because they are saved as lines
// with start- and endnumber, the common osm housenumbers are usually saved as points
$sHousenumbers = "";
$i = 0;
$length = count($aPlaceIDs);
foreach($aPlaceIDs as $placeID => $housenumber)
{
$i++;
$sHousenumbers .= "(".$placeID.", ".$housenumber.")";
if($i<$length)
$sHousenumbers .= ", ";
}
if (CONST_Use_US_Tiger_Data) if (CONST_Use_US_Tiger_Data)
{ {
//query also location_property_tiger and location_property_aux
//Tiger search only if a housenumber was searched and if it was found (i.e. aPlaceIDs[placeID] = housenumber != -1) (realized through a join) //Tiger search only if a housenumber was searched and if it was found (i.e. aPlaceIDs[placeID] = housenumber != -1) (realized through a join)
//only Tiger housenumbers need to be interpolated, because they are saved as lines with start- and endnumber, the common osm housenumbers are usually saved as points $sSQL .= " union";
$sHousenumbers = ""; $sSQL .= " select 'T' as osm_type, place_id as osm_id, 'place' as class, 'house' as type, null as admin_level, 30 as rank_search, 30 as rank_address, min(place_id) as place_id, min(parent_place_id) as parent_place_id, 'us' as country_code";
$i = 0;
$length = count($aPlaceIDs);
foreach($aPlaceIDs as $placeID => $housenumber)
{
$i++;
$sHousenumbers .= "(".$placeID.", ".$housenumber.")";
if($i<$length)
$sHousenumbers .= ", ";
}
$sSQL .= "union ";
$sSQL .= "select 'T' as osm_type, place_id as osm_id, 'place' as class, 'house' as type, null as admin_level, 30 as rank_search, 30 as rank_address, min(place_id) as place_id, min(parent_place_id) as parent_place_id, 'us' as country_code";
$sSQL .= ", get_address_by_language(place_id, housenumber_for_place, $sLanguagePrefArraySQL) as langaddress "; $sSQL .= ", get_address_by_language(place_id, housenumber_for_place, $sLanguagePrefArraySQL) as langaddress ";
$sSQL .= ", null as placename"; $sSQL .= ", null as placename";
$sSQL .= ", null as ref"; $sSQL .= ", null as ref";
@@ -460,13 +459,37 @@
$sSQL .= ", null as extra_place "; $sSQL .= ", null as extra_place ";
$sSQL .= " from (select place_id"; $sSQL .= " from (select place_id";
//interpolate the Tiger housenumbers here //interpolate the Tiger housenumbers here
$sSQL .= ", ST_LineInterpolatePoint(linegeo, (housenumber_for_place-startnumber::float)/(endnumber-startnumber)::float) as centroid, parent_place_id, housenumber_for_place "; $sSQL .= ", ST_LineInterpolatePoint(linegeo, (housenumber_for_place-startnumber::float)/(endnumber-startnumber)::float) as centroid, parent_place_id, housenumber_for_place";
$sSQL .= "from (location_property_tiger "; $sSQL .= " from (location_property_tiger ";
$sSQL .= " join (values ".$sHousenumbers.") as housenumbers(place_id, housenumber_for_place) using(place_id)) "; $sSQL .= " join (values ".$sHousenumbers.") as housenumbers(place_id, housenumber_for_place) using(place_id)) ";
$sSQL .= " where housenumber_for_place>=0 and 30 between $this->iMinAddressRank and $this->iMaxAddressRank) as blub"; //postgres wants an alias here $sSQL .= " where housenumber_for_place>=0 and 30 between $this->iMinAddressRank and $this->iMaxAddressRank) as blub"; //postgres wants an alias here
$sSQL .= " group by place_id, housenumber_for_place"; //is this group by really needed?, place_id + housenumber (in combination) are unique $sSQL .= " group by place_id, housenumber_for_place"; //is this group by really needed?, place_id + housenumber (in combination) are unique
if (!$this->bDeDupe) $sSQL .= ", place_id "; if (!$this->bDeDupe) $sSQL .= ", place_id ";
} }
// osmline
// interpolation line search only if a housenumber was searched and if it was found (i.e. aPlaceIDs[placeID] = housenumber != -1) (realized through a join)
$sSQL .= " union ";
$sSQL .= "select 'W' as osm_type, place_id as osm_id, 'place' as class, 'house' as type, null as admin_level, 30 as rank_search, 30 as rank_address, min(place_id) as place_id, min(parent_place_id) as parent_place_id, calculated_country_code as country_code, ";
$sSQL .= "get_address_by_language(place_id, housenumber_for_place, $sLanguagePrefArraySQL) as langaddress, ";
$sSQL .= "null as placename, ";
$sSQL .= "null as ref, ";
if ($this->bIncludeExtraTags) $sSQL .= "null as extra, ";
if ($this->bIncludeNameDetails) $sSQL .= "null as names, ";
$sSQL .= " avg(st_x(centroid)) as lon, avg(st_y(centroid)) as lat,";
$sSQL .= $sImportanceSQL."-0.1 as importance, "; // slightly smaller than the importance for normal houses with rank 30, which is 0
$sSQL .= " (select max(p.importance*(p.rank_address+2)) from place_addressline s, placex p";
$sSQL .= " where s.place_id = min(blub.parent_place_id) and p.place_id = s.address_place_id and s.isaddress and p.importance is not null) as addressimportance,";
$sSQL .= " null as extra_place ";
$sSQL .= " from (select place_id, calculated_country_code ";
//interpolate the housenumbers here
$sSQL .= ", CASE WHEN startnumber != endnumber 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, housenumber_for_place ";
$sSQL .= " from (location_property_osmline ";
$sSQL .= " join (values ".$sHousenumbers.") as housenumbers(place_id, housenumber_for_place) using(place_id)) ";
$sSQL .= " where housenumber_for_place>=0 and 30 between $this->iMinAddressRank and $this->iMaxAddressRank) as blub"; //postgres wants an alias here
$sSQL .= " group by place_id, housenumber_for_place, calculated_country_code "; //is this group by really needed?, place_id + housenumber (in combination) are unique
if (!$this->bDeDupe) $sSQL .= ", place_id ";
if (CONST_Use_Aux_Location_data) if (CONST_Use_Aux_Location_data)
{ {
@@ -879,7 +902,7 @@
// Do we have anything that looks like a lat/lon pair? // Do we have anything that looks like a lat/lon pair?
if ( $aLooksLike = looksLikeLatLonPair($sQuery) ) if ( $aLooksLike = looksLikeLatLonPair($sQuery) )
{ {
$this->setNearPoint(array($aLooksLike['lat'], $aLooksLike['lon'])); $this->setNearPoint(array($aLooksLike['lat'], $aLooksLike['lon']));
$sQuery = $aLooksLike['query']; $sQuery = $aLooksLike['query'];
} }
@@ -1307,7 +1330,13 @@
if ($aSearch['sHouseNumber'] && sizeof($aSearch['aAddress'])) if ($aSearch['sHouseNumber'] && sizeof($aSearch['aAddress']))
{ {
$sHouseNumberRegex = '\\\\m'.$aSearch['sHouseNumber'].'\\\\M'; $sHouseNumberRegex = '\\\\m'.$aSearch['sHouseNumber'].'\\\\M';
$aOrder[] = "exists(select place_id from placex where parent_place_id = search_name.place_id and transliteration(housenumber) ~* E'".$sHouseNumberRegex."' limit 1) desc"; $aOrder[] = "";
$aOrder[0] = " (exists(select place_id from placex where parent_place_id = search_name.place_id";
$aOrder[0] .= " and transliteration(housenumber) ~* E'".$sHouseNumberRegex."' limit 1) ";
// also housenumbers from interpolation lines table are needed
$aOrder[0] .= " or exists(select place_id from location_property_osmline where parent_place_id = search_name.place_id";
$aOrder[0] .= " and ".intval($aSearch['sHouseNumber']).">=startnumber and ".intval($aSearch['sHouseNumber'])."<=endnumber limit 1))";
$aOrder[0] .= " desc";
} }
// TODO: filter out the pointless search terms (2 letter name tokens and less) // TODO: filter out the pointless search terms (2 letter name tokens and less)
@@ -1422,10 +1451,11 @@
//now search for housenumber, if housenumber provided //now search for housenumber, if housenumber provided
if ($aSearch['sHouseNumber'] && sizeof($aPlaceIDs)) if ($aSearch['sHouseNumber'] && sizeof($aPlaceIDs))
{ {
$searchedHousenumber = intval($aSearch['sHouseNumber']);
$aRoadPlaceIDs = $aPlaceIDs; $aRoadPlaceIDs = $aPlaceIDs;
$sPlaceIDs = join(',',$aPlaceIDs); $sPlaceIDs = join(',',$aPlaceIDs);
// Now they are indexed look for a house attached to a street we found // Now they are indexed, look for a house attached to a street we found
$sHouseNumberRegex = '\\\\m'.$aSearch['sHouseNumber'].'\\\\M'; $sHouseNumberRegex = '\\\\m'.$aSearch['sHouseNumber'].'\\\\M';
$sSQL = "select place_id from placex where parent_place_id in (".$sPlaceIDs.") and transliteration(housenumber) ~* E'".$sHouseNumberRegex."'"; $sSQL = "select place_id from placex where parent_place_id in (".$sPlaceIDs.") and transliteration(housenumber) ~* E'".$sHouseNumberRegex."'";
if (sizeof($this->aExcludePlaceIDs)) if (sizeof($this->aExcludePlaceIDs))
@@ -1435,21 +1465,44 @@
$sSQL .= " limit $this->iLimit"; $sSQL .= " limit $this->iLimit";
if (CONST_Debug) var_dump($sSQL); if (CONST_Debug) var_dump($sSQL);
$aPlaceIDs = $this->oDB->getCol($sSQL); $aPlaceIDs = $this->oDB->getCol($sSQL);
// if nothing found, search in the interpolation line table
if(!sizeof($aPlaceIDs))
{
// do we need to use transliteration and the regex for housenumbers???
//new query for lines, not housenumbers anymore
if($searchedHousenumber%2 == 0){
//if housenumber is even, look for housenumber in streets with interpolationtype even or all
$sSQL = "select distinct place_id from location_property_osmline where parent_place_id in (".$sPlaceIDs.") and (interpolationtype='even' or interpolationtype='all') and ".$searchedHousenumber.">=startnumber and ".$searchedHousenumber."<=endnumber";
}else{
//look for housenumber in streets with interpolationtype odd or all
$sSQL = "select distinct place_id from location_property_osmline where parent_place_id in (".$sPlaceIDs.") and (interpolationtype='odd' or interpolationtype='all') and ".$searchedHousenumber.">=startnumber and ".$searchedHousenumber."<=endnumber";
}
if (sizeof($this->aExcludePlaceIDs))
{
$sSQL .= " and parent_place_id not in (".join(',', $this->aExcludePlaceIDs).")";
}
//$sSQL .= " limit $this->iLimit";
if (CONST_Debug) var_dump($sSQL);
//get place IDs
$aPlaceIDs = $this->oDB->getCol($sSQL, 0);
}
// If nothing found try the aux fallback table // If nothing found try the aux fallback table
if (CONST_Use_Aux_Location_data && !sizeof($aPlaceIDs)) if (CONST_Use_Aux_Location_data && !sizeof($aPlaceIDs))
{ {
$sSQL = "select place_id from location_property_aux where parent_place_id in (".$sPlaceIDs.") and housenumber = '".pg_escape_string($aSearch['sHouseNumber'])."'"; $sSQL = "select place_id from location_property_aux where parent_place_id in (".$sPlaceIDs.") and housenumber = '".pg_escape_string($aSearch['sHouseNumber'])."'";
if (sizeof($this->aExcludePlaceIDs)) if (sizeof($this->aExcludePlaceIDs))
{ {
$sSQL .= " and place_id not in (".join(',',$this->aExcludePlaceIDs).")"; $sSQL .= " and parent_place_id not in (".join(',',$this->aExcludePlaceIDs).")";
} }
//$sSQL .= " limit $this->iLimit"; //$sSQL .= " limit $this->iLimit";
if (CONST_Debug) var_dump($sSQL); if (CONST_Debug) var_dump($sSQL);
$aPlaceIDs = $this->oDB->getCol($sSQL); $aPlaceIDs = $this->oDB->getCol($sSQL);
} }
//if nothing was found in placex or location_property_aux, then search in Tiger data for this housenumber(location_property_tiger) //if nothing was found in placex or location_property_aux, then search in Tiger data for this housenumber(location_property_tiger)
$searchedHousenumber = intval($aSearch['sHouseNumber']);
if (CONST_Use_US_Tiger_Data && !sizeof($aPlaceIDs)) if (CONST_Use_US_Tiger_Data && !sizeof($aPlaceIDs))
{ {
//new query for lines, not housenumbers anymore //new query for lines, not housenumbers anymore
@@ -1478,7 +1531,7 @@
//set to -1, if no housenumbers were found //set to -1, if no housenumbers were found
$searchedHousenumber = -1; $searchedHousenumber = -1;
} }
//else: housenumber was found, remains saved in searchedHousenumber //else: housenumber was found, remains saved in searchedHousenumber
} }
@@ -1618,6 +1671,7 @@
{ {
// Need to verify passes rank limits before dropping out of the loop (yuk!) // Need to verify passes rank limits before dropping out of the loop (yuk!)
// reduces the number of place ids, like a filter // reduces the number of place ids, like a filter
// rank_address is 30 for interpolated housenumbers
$sSQL = "select place_id from placex where place_id in (".join(',',array_keys($aResultPlaceIDs)).") "; $sSQL = "select place_id from placex where place_id in (".join(',',array_keys($aResultPlaceIDs)).") ";
$sSQL .= "and (placex.rank_address between $this->iMinAddressRank and $this->iMaxAddressRank "; $sSQL .= "and (placex.rank_address between $this->iMinAddressRank and $this->iMaxAddressRank ";
if (14 >= $this->iMinAddressRank && 14 <= $this->iMaxAddressRank) $sSQL .= " OR (extratags->'place') = 'city'"; if (14 >= $this->iMinAddressRank && 14 <= $this->iMaxAddressRank) $sSQL .= " OR (extratags->'place') = 'city'";
@@ -1628,12 +1682,13 @@
$sSQL .= "and (30 between $this->iMinAddressRank and $this->iMaxAddressRank "; $sSQL .= "and (30 between $this->iMinAddressRank and $this->iMaxAddressRank ";
if ($this->aAddressRankList) $sSQL .= " OR 30 in (".join(',',$this->aAddressRankList).")"; if ($this->aAddressRankList) $sSQL .= " OR 30 in (".join(',',$this->aAddressRankList).")";
} }
$sSQL .= ")"; $sSQL .= ") UNION select place_id from location_property_osmline where place_id in (".join(',',array_keys($aResultPlaceIDs)).")";
$sSQL .= " and (30 between $this->iMinAddressRank and $this->iMaxAddressRank)";
if (CONST_Debug) var_dump($sSQL); if (CONST_Debug) var_dump($sSQL);
$aFilteredPlaceIDs = $this->oDB->getCol($sSQL); $aFilteredPlaceIDs = $this->oDB->getCol($sSQL);
$tempIDs = array(); $tempIDs = array();
foreach($aFilteredPlaceIDs as $placeID) foreach($aFilteredPlaceIDs as $placeID)
{ {
$tempIDs[$placeID] = $aResultPlaceIDs[$placeID]; //assign housenumber to placeID $tempIDs[$placeID] = $aResultPlaceIDs[$placeID]; //assign housenumber to placeID
} }
$aResultPlaceIDs = $tempIDs; $aResultPlaceIDs = $tempIDs;

View File

@@ -111,7 +111,7 @@
{ {
$this->setOSMID($details['osm_type'], $details['osm_id']); $this->setOSMID($details['osm_type'], $details['osm_id']);
} }
if (isset($details['fraction'])) $this->fTigerFraction = $details['fraction']; if (isset($details['fraction'])) $this->fInterpolFraction = $details['fraction'];
return $this->lookup(); return $this->lookup();
} }
@@ -134,12 +134,33 @@
if ($this->bNameDetails) $sSQL .= " null as names,"; if ($this->bNameDetails) $sSQL .= " null as names,";
$sSQL .= " ST_X(point) as lon, ST_Y(point) as lat from (select *, ST_LineInterpolatePoint(linegeo, (housenumber-startnumber::float)/(endnumber-startnumber)::float) as point from "; $sSQL .= " ST_X(point) as lon, ST_Y(point) as lat from (select *, ST_LineInterpolatePoint(linegeo, (housenumber-startnumber::float)/(endnumber-startnumber)::float) as point from ";
$sSQL .= " (select *, "; $sSQL .= " (select *, ";
$sSQL .= " CASE WHEN interpolationtype='odd' THEN floor((".$this->fTigerFraction."*(endnumber-startnumber)+startnumber)/2)::int*2+1"; $sSQL .= " CASE WHEN interpolationtype='odd' THEN floor((".$this->fInterpolFraction."*(endnumber-startnumber)+startnumber)/2)::int*2+1";
$sSQL .= " WHEN interpolationtype='even' THEN ((".$this->fTigerFraction."*(endnumber-startnumber)+startnumber+1)/2)::int*2"; $sSQL .= " WHEN interpolationtype='even' THEN ((".$this->fInterpolFraction."*(endnumber-startnumber)+startnumber)/2)::int*2";
$sSQL .= " WHEN interpolationtype='all' THEN (".$this->fTigerFraction."*(endnumber-startnumber)+startnumber)::int"; $sSQL .= " WHEN interpolationtype='all' THEN (".$this->fInterpolFraction."*(endnumber-startnumber)+startnumber)::int";
$sSQL .= " END as housenumber"; $sSQL .= " END as housenumber";
$sSQL .= " from location_property_tiger where place_id = ".(int)$this->iPlaceID.") as blub1) as blub2"; $sSQL .= " from location_property_tiger where place_id = ".(int)$this->iPlaceID.") as blub1) as blub2";
} }
else if ($this->sType == 'interpolation')
{
$sSQL = "select place_id, partition, 'W' as osm_type, osm_id, 'place' as class, 'house' as type, null admin_level, housenumber, null as street, null as isin, postcode,";
$sSQL .= " calculated_country_code as country_code, parent_place_id, null as linked_place_id, 30 as rank_address, 30 as rank_search,";
$sSQL .= " (0.75-(30::float/40)) as importance, null as indexed_status, null as indexed_date, null as wikipedia, calculated_country_code, ";
$sSQL .= " get_address_by_language(place_id, housenumber, $sLanguagePrefArraySQL) as langaddress,";
$sSQL .= " null as placename,";
$sSQL .= " null as ref,";
if ($this->bExtraTags) $sSQL .= " null as extra,";
if ($this->bNameDetails) $sSQL .= " null as names,";
$sSQL .= " ST_X(point) as lon, ST_Y(point) as lat from (select *, ST_LineInterpolatePoint(linegeo, (housenumber-startnumber::float)/(endnumber-startnumber)::float) as point from ";
$sSQL .= " (select *, ";
$sSQL .= " CASE WHEN interpolationtype='odd' THEN floor((".$this->fInterpolFraction."*(endnumber-startnumber)+startnumber)/2)::int*2+1";
$sSQL .= " WHEN interpolationtype='even' THEN ((".$this->fInterpolFraction."*(endnumber-startnumber)+startnumber)/2)::int*2";
$sSQL .= " WHEN interpolationtype='all' THEN (".$this->fInterpolFraction."*(endnumber-startnumber)+startnumber)::int";
$sSQL .= " END as housenumber";
$sSQL .= " from location_property_osmline where place_id = ".(int)$this->iPlaceID.") as blub1) as blub2";
// testcase: interpolationtype=odd, startnumber=1000, endnumber=1006, fInterpolFraction=1 => housenumber=1007 => error in st_lineinterpolatepoint
// but this will never happen, because if the searched point is that close to the endnumber, the endnumber house will be directly taken from placex (in ReverseGeocode.php line 220)
// and not interpolated
}
else else
{ {
$sSQL = "select placex.place_id, partition, osm_type, osm_id, class, type, admin_level, housenumber, street, isin, postcode, country_code, parent_place_id, linked_place_id, rank_address, rank_search, "; $sSQL = "select placex.place_id, partition, osm_type, osm_id, class, type, admin_level, housenumber, street, isin, postcode, country_code, parent_place_id, linked_place_id, rank_address, rank_search, ";
@@ -166,7 +187,7 @@
if ($this->bAddressDetails) if ($this->bAddressDetails)
{ {
if(CONST_Use_US_Tiger_Data && $this->sType == 'tiger') // to get addressdetails for tiger data, the housenumber is needed if(CONST_Use_US_Tiger_Data && $this->sType == 'tiger' || $this->sType == 'interpolation') // to get addressdetails for tiger data, the housenumber is needed
$aAddress = $this->getAddressNames($aPlace['housenumber']); $aAddress = $this->getAddressNames($aPlace['housenumber']);
else else
$aAddress = $this->getAddressNames(); $aAddress = $this->getAddressNames();

View File

@@ -121,6 +121,7 @@
$fMaxAreaDistance = 1; $fMaxAreaDistance = 1;
$bIsInUnitedStates = false; $bIsInUnitedStates = false;
$bPlaceIsTiger = false; $bPlaceIsTiger = false;
$bPlaceIsLine = false;
while(!$iPlaceID && $fSearchDiam < $fMaxAreaDistance) while(!$iPlaceID && $fSearchDiam < $fMaxAreaDistance)
{ {
$fSearchDiam = $fSearchDiam * 2; $fSearchDiam = $fSearchDiam * 2;
@@ -156,7 +157,78 @@
$iParentPlaceID = $aPlace['parent_place_id']; $iParentPlaceID = $aPlace['parent_place_id'];
$bIsInUnitedStates = ($aPlace['calculated_country_code'] == 'us'); $bIsInUnitedStates = ($aPlace['calculated_country_code'] == 'us');
} }
// if a street or house was found, look in interpolation lines table
if ($iMaxRank_orig >= 28 && $aPlace && $aPlace['rank_search'] >= 26)
{
// if a house was found, search the interpolation line that is at least as close as the house
$sSQL = 'SELECT place_id, parent_place_id, 30 as rank_search, ST_line_locate_point(linegeo,'.$sPointSQL.') as fraction';
$sSQL .= ' FROM location_property_osmline';
$sSQL .= ' WHERE ST_DWithin('.$sPointSQL.', linegeo, '.$fSearchDiam.')';
$sSQL .= ' and indexed_status = 0 ';
$sSQL .= ' ORDER BY ST_distance('.$sPointSQL.', linegeo) ASC limit 1';
if (CONST_Debug)
{
$sSQL = preg_replace('/limit 1/', 'limit 100', $sSQL);
var_dump($sSQL);
$aAllHouses = $this->oDB->getAll($sSQL);
foreach($aAllHouses as $i)
{
echo $i['housenumber'] . ' | ' . $i['distance'] * 1000 . ' | ' . $i['lat'] . ' | ' . $i['lon']. ' | '. "<br>\n";
}
}
$aPlaceLine = $this->oDB->getRow($sSQL);
if (PEAR::IsError($aPlaceLine))
{
failInternalError("Could not determine closest housenumber on an osm interpolation line.", $sSQL, $aPlaceLine);
}
if ($aPlaceLine)
{
if (CONST_Debug) var_dump('found housenumber in interpolation lines table', $aPlaceLine);
if ($aPlace['rank_search'] == 30)
{
// if a house was already found in placex, we have to find out,
// if the placex house or the interpolated house are closer to the searched point
// distance between point and placex house
$sSQL = 'SELECT ST_distance('.$sPointSQL.', house.geometry) as distance FROM placex as house WHERE house.place_id='.$iPlaceID;
$aDistancePlacex = $this->oDB->getRow($sSQL);
if (PEAR::IsError($aDistancePlacex))
{
failInternalError("Could not determine distance between searched point and placex house.", $sSQL, $aDistancePlacex);
}
$fDistancePlacex = $aDistancePlacex['distance'];
// distance between point and interpolated house (fraction on interpolation line)
$sSQL = 'SELECT ST_distance('.$sPointSQL.', ST_LineInterpolatePoint(linegeo, '.$aPlaceLine['fraction'].')) as distance';
$sSQL .= ' FROM location_property_osmline WHERE place_id = '.$aPlaceLine['place_id'];
$aDistanceInterpolation = $this->oDB->getRow($sSQL);
if (PEAR::IsError($aDistanceInterpolation))
{
failInternalError("Could not determine distance between searched point and interpolated house.", $sSQL, $aDistanceInterpolation);
}
$fDistanceInterpolation = $aDistanceInterpolation['distance'];
if ($fDistanceInterpolation < $fDistancePlacex)
{
// interpolation is closer to point than placex house
$bPlaceIsLine = true;
$aPlace = $aPlaceLine;
$iPlaceID = $aPlaceLine['place_id'];
$iParentPlaceID = $aPlaceLine['parent_place_id']; // the street
$fFraction = $aPlaceLine['fraction'];
}
// else: nothing to do, take placex house from above
}
else
{
$bPlaceIsLine = true;
$aPlace = $aPlaceLine;
$iPlaceID = $aPlaceLine['place_id'];
$iParentPlaceID = $aPlaceLine['parent_place_id']; // the street
$fFraction = $aPlaceLine['fraction'];
}
}
}
// Only street found? If it's in the US we can check TIGER data for nearest housenumber // Only street found? If it's in the US we can check TIGER data for nearest housenumber
if (CONST_Use_US_Tiger_Data && $bIsInUnitedStates && $iMaxRank_orig >= 28 && $iPlaceID && ($aPlace['rank_search'] == 26 || $aPlace['rank_search'] == 27 )) if (CONST_Use_US_Tiger_Data && $bIsInUnitedStates && $iMaxRank_orig >= 28 && $iPlaceID && ($aPlace['rank_search'] == 26 || $aPlace['rank_search'] == 27 ))
{ {
@@ -180,25 +252,25 @@
} }
$aPlaceTiger = $this->oDB->getRow($sSQL); $aPlaceTiger = $this->oDB->getRow($sSQL);
if (PEAR::IsError($aPlace)) if (PEAR::IsError($aPlaceTiger))
{ {
failInternalError("Could not determine closest Tiger place.", $sSQL, $aPlaceTiger); failInternalError("Could not determine closest Tiger place.", $sSQL, $aPlaceTiger);
} }
if ($aPlaceTiger) if ($aPlaceTiger)
{ {
if (CONST_Debug) var_dump('found Tiger place', $aPlaceTiger); if (CONST_Debug) var_dump('found Tiger housenumber', $aPlaceTiger);
$bPlaceIsTiger = true; $bPlaceIsTiger = true;
$aPlace = $aPlaceTiger; $aPlace = $aPlaceTiger;
$iPlaceID = $aPlaceTiger['place_id']; $iPlaceID = $aPlaceTiger['place_id'];
$iParentPlaceID = $aPlaceTiger['parent_place_id']; // the street $iParentPlaceID = $aPlaceTiger['parent_place_id']; // the street
$iFraction = $aPlaceTiger['fraction']; $fFraction = $aPlaceTiger['fraction'];
} }
} }
// The point we found might be too small - use the address to find what it is a child of // The point we found might be too small - use the address to find what it is a child of
if ($iPlaceID && $iMaxRank < 28) if ($iPlaceID && $iMaxRank < 28)
{ {
if ($aPlace['rank_search'] > 28 && $iParentPlaceID && !$bPlaceIsTiger) if (($aPlace['rank_search'] > 28 || $bPlaceIsTiger || $bPlaceIsLine) && $iParentPlaceID)
{ {
$iPlaceID = $iParentPlaceID; $iPlaceID = $iParentPlaceID;
} }
@@ -217,10 +289,9 @@
$iPlaceID = $aPlace['place_id']; $iPlaceID = $aPlace['place_id'];
} }
} }
return array('place_id' => $iPlaceID, return array('place_id' => $iPlaceID,
'type' => $bPlaceIsTiger ? 'tiger' : 'osm', 'type' => $bPlaceIsTiger ? 'tiger' : $bPlaceIsLine ? 'interpolation' : 'osm',
'fraction' => $bPlaceIsTiger ? $iFraction : -1); 'fraction' => ($bPlaceIsTiger || $bPlaceIsLine) ? $fFraction : -1);
} }
} }

View File

@@ -12,7 +12,8 @@
{ {
if (isset($aPlace['place_id'])) $aFilteredPlaces['place_id'] = $aPlace['place_id']; if (isset($aPlace['place_id'])) $aFilteredPlaces['place_id'] = $aPlace['place_id'];
$aFilteredPlaces['licence'] = "Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright"; $aFilteredPlaces['licence'] = "Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright";
$sOSMType = ($aPlace['osm_type'] == 'N'?'node':($aPlace['osm_type'] == 'W'?'way':($aPlace['osm_type'] == 'R'?'relation':''))); $sOSMType = ($aPlace['osm_type'] == 'N'?'node':($aPlace['osm_type'] == 'W'?'way':($aPlace['osm_type'] == 'R'?'relation':
($aPlace['osm_type'] == 'T'?'tiger':($aPlace['osm_type'] == 'I'?'interpolation':'')))));
if ($sOSMType) if ($sOSMType)
{ {
$aFilteredPlaces['osm_type'] = $sOSMType; $aFilteredPlaces['osm_type'] = $sOSMType;

View File

@@ -12,7 +12,8 @@
{ {
if ($aPlace['place_id']) $aFilteredPlaces['place_id'] = $aPlace['place_id']; if ($aPlace['place_id']) $aFilteredPlaces['place_id'] = $aPlace['place_id'];
$aFilteredPlaces['licence'] = "Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright"; $aFilteredPlaces['licence'] = "Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright";
$sOSMType = ($aPlace['osm_type'] == 'N'?'node':($aPlace['osm_type'] == 'W'?'way':($aPlace['osm_type'] == 'R'?'relation':''))); $sOSMType = ($aPlace['osm_type'] == 'N'?'node':($aPlace['osm_type'] == 'W'?'way':($aPlace['osm_type'] == 'R'?'relation':
($aPlace['osm_type'] == 'T'?'tiger':($aPlace['osm_type'] == 'I'?'interpolation':'')))));
if ($sOSMType) if ($sOSMType)
{ {
$aFilteredPlaces['osm_type'] = $sOSMType; $aFilteredPlaces['osm_type'] = $sOSMType;

View File

@@ -22,7 +22,8 @@
{ {
echo "<result"; echo "<result";
if ($aPlace['place_id']) echo ' place_id="'.$aPlace['place_id'].'"'; if ($aPlace['place_id']) echo ' place_id="'.$aPlace['place_id'].'"';
$sOSMType = ($aPlace['osm_type'] == 'N'?'node':($aPlace['osm_type'] == 'W'?'way':($aPlace['osm_type'] == 'R'?'relation':''))); $sOSMType = ($aPlace['osm_type'] == 'N'?'node':($aPlace['osm_type'] == 'W'?'way':($aPlace['osm_type'] == 'R'?'relation':
($aPlace['osm_type'] == 'T'?'tiger':($aPlace['osm_type'] == 'I'?'interpolation':'')))));
if ($sOSMType) echo ' osm_type="'.$sOSMType.'"'.' osm_id="'.$aPlace['osm_id'].'"'; if ($sOSMType) echo ' osm_type="'.$sOSMType.'"'.' osm_id="'.$aPlace['osm_id'].'"';
if ($aPlace['ref']) echo ' ref="'.htmlspecialchars($aPlace['ref']).'"'; if ($aPlace['ref']) echo ' ref="'.htmlspecialchars($aPlace['ref']).'"';
if (isset($aPlace['lat'])) echo ' lat="'.htmlspecialchars($aPlace['lat']).'"'; if (isset($aPlace['lat'])) echo ' lat="'.htmlspecialchars($aPlace['lat']).'"';

View File

@@ -9,7 +9,8 @@
'licence'=>"Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright", 'licence'=>"Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright",
); );
$sOSMType = ($aPointDetails['osm_type'] == 'N'?'node':($aPointDetails['osm_type'] == 'W'?'way':($aPointDetails['osm_type'] == 'R'?'relation':($aPointDetails['osm_type'] == 'T'?'tiger':'')))); $sOSMType = ($aPointDetails['osm_type'] == 'N'?'node':($aPointDetails['osm_type'] == 'W'?'way':($aPointDetails['osm_type'] == 'R'?
'relation':($aPointDetails['osm_type'] == 'T'?'tiger':($aPointDetails['osm_type'] == 'I'?'interpolation':'')))));
if ($sOSMType) if ($sOSMType)
{ {
$aPlace['osm_type'] = $sOSMType; $aPlace['osm_type'] = $sOSMType;

View File

@@ -7,7 +7,7 @@
'licence'=>"Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright", 'licence'=>"Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright",
); );
$sOSMType = ($aPointDetails['osm_type'] == 'N'?'node':($aPointDetails['osm_type'] == 'W'?'way':($aPointDetails['osm_type'] == 'R'?'relation':($aPointDetails['osm_type'] == 'T'?'tiger':'')))); $sOSMType = ($aPointDetails['osm_type'] == 'N'?'node':($aPointDetails['osm_type'] == 'W'?'way':($aPointDetails['osm_type'] == 'R'?'relation':($aPointDetails['osm_type'] == 'T'?'tiger':($aPointDetails['osm_type'] == 'I'?'interpolation':'')))));
if ($sOSMType) if ($sOSMType)
{ {
$aPlace['osm_type'] = $sOSMType; $aPlace['osm_type'] = $sOSMType;

View File

@@ -25,7 +25,8 @@
foreach($aSearchResults as $iResNum => $aResult) foreach($aSearchResults as $iResNum => $aResult)
{ {
echo "<place place_id='".$aResult['place_id']."'"; echo "<place place_id='".$aResult['place_id']."'";
$sOSMType = ($aResult['osm_type'] == 'N'?'node':($aResult['osm_type'] == 'W'?'way':($aResult['osm_type'] == 'R'?'relation':($aResult['osm_type'] == 'T'?'tiger':'')))); $sOSMType = ($aResult['osm_type'] == 'N'?'node':($aResult['osm_type'] == 'W'?'way':($aResult['osm_type'] == 'R'?'relation':
($aResult['osm_type'] == 'T'?'tiger':($aResult['osm_type'] == 'I'?'interpolation':'')))));
if ($sOSMType) if ($sOSMType)
{ {
echo " osm_type='$sOSMType'"; echo " osm_type='$sOSMType'";

View File

@@ -1,4 +1,6 @@
/* /*
* triggers indexing (reparenting etc.) through setting resetting indexed_status: update placex/osmline set indexed_status = 0 where indexed_status > 0
* triggers placex_update and osmline_update
*/ */
#include <stdio.h> #include <stdio.h>
@@ -19,34 +21,255 @@
extern int verbose; extern int verbose;
void nominatim_index(int rank_min, int rank_max, int num_threads, const char *conninfo, const char *structuredoutputfile) void run_indexing(int rank, int interpolation, PGconn *conn, int num_threads,
struct index_thread_data * thread_data, const char *structuredoutputfile)
{ {
struct index_thread_data * thread_data;
pthread_mutex_t count_mutex = PTHREAD_MUTEX_INITIALIZER;
int tuples, count, sleepcount; int tuples, count, sleepcount;
pthread_mutex_t count_mutex = PTHREAD_MUTEX_INITIALIZER;
time_t rankStartTime; time_t rankStartTime;
int rankTotalTuples; int rankTotalTuples;
int rankCountTuples; int rankCountTuples;
float rankPerSecond; float rankPerSecond;
PGconn *conn;
PGresult * res;
PGresult * resSectors; PGresult * resSectors;
PGresult * resPlaces; PGresult * resPlaces;
PGresult * resNULL; PGresult * resNULL;
int rank;
int i; int i;
int iSector; int iSector;
int iResult; int iResult;
const char *paramValues[2]; const char *paramValues[2];
int paramLengths[2]; int paramLengths[2];
int paramFormats[2]; int paramFormats[2];
uint32_t paramRank; uint32_t paramRank;
uint32_t paramSector; uint32_t paramSector;
uint32_t sector; uint32_t sector;
xmlTextWriterPtr writer;
pthread_mutex_t writer_mutex = PTHREAD_MUTEX_INITIALIZER;
// Create the output file
writer = NULL;
if (structuredoutputfile)
{
writer = nominatim_exportXMLStart(structuredoutputfile);
}
if (interpolation)
{
fprintf(stderr, "Starting interpolation lines (location_property_osmline)\n");
}
else
{
fprintf(stderr, "Starting rank %d\n", rank);
}
rankCountTuples = 0;
rankPerSecond = 0;
paramRank = PGint32(rank);
paramValues[0] = (char *)&paramRank;
paramLengths[0] = sizeof(paramRank);
paramFormats[0] = 1;
if (interpolation)
{
resSectors = PQexecPrepared(conn, "index_sectors_osmline", 0, NULL, 0, NULL, 1);
}
else
{
resSectors = PQexecPrepared(conn, "index_sectors", 1, paramValues, paramLengths, paramFormats, 1);
}
if (PQresultStatus(resSectors) != PGRES_TUPLES_OK)
{
fprintf(stderr, "index_sectors: SELECT failed: %s", PQerrorMessage(conn));
PQclear(resSectors);
exit(EXIT_FAILURE);
}
if (PQftype(resSectors, 0) != PG_OID_INT4)
{
fprintf(stderr, "Sector value has unexpected type\n");
PQclear(resSectors);
exit(EXIT_FAILURE);
}
if (PQftype(resSectors, 1) != PG_OID_INT8)
{
fprintf(stderr, "Sector value has unexpected type\n");
PQclear(resSectors);
exit(EXIT_FAILURE);
}
rankTotalTuples = 0;
for (iSector = 0; iSector < PQntuples(resSectors); iSector++)
{
rankTotalTuples += PGint64(*((uint64_t *)PQgetvalue(resSectors, iSector, 1)));
}
rankStartTime = time(0);
for (iSector = 0; iSector <= PQntuples(resSectors); iSector++)
{
if (iSector > 0)
{
resPlaces = PQgetResult(conn);
if (PQresultStatus(resPlaces) != PGRES_TUPLES_OK)
{
fprintf(stderr, "index_sector_places: SELECT failed: %s", PQerrorMessage(conn));
PQclear(resPlaces);
exit(EXIT_FAILURE);
}
if (PQftype(resPlaces, 0) != PG_OID_INT8)
{
fprintf(stderr, "Place_id value has unexpected type\n");
PQclear(resPlaces);
exit(EXIT_FAILURE);
}
resNULL = PQgetResult(conn);
if (resNULL != NULL)
{
fprintf(stderr, "Unexpected non-null response\n");
exit(EXIT_FAILURE);
}
}
if (iSector < PQntuples(resSectors))
{
sector = PGint32(*((uint32_t *)PQgetvalue(resSectors, iSector, 0)));
// fprintf(stderr, "\n Starting sector %d size %ld\n", sector, PGint64(*((uint64_t *)PQgetvalue(resSectors, iSector, 1))));
// Get all the place_id's for this sector
paramRank = PGint32(rank);
paramSector = PGint32(sector);
if (rankTotalTuples-rankCountTuples < num_threads*1000)
{
// no sectors
if (interpolation)
{
iResult = PQsendQueryPrepared(conn, "index_nosector_places_osmline", 0, NULL, 0, NULL, 1);
}
else
{
paramValues[0] = (char *)&paramRank;
paramLengths[0] = sizeof(paramRank);
paramFormats[0] = 1;
iResult = PQsendQueryPrepared(conn, "index_nosector_places", 1, paramValues, paramLengths, paramFormats, 1);
}
}
else
{
if (interpolation)
{
iResult = PQsendQueryPrepared(conn, "index_sector_places_osmline", 1, paramValues, paramLengths, paramFormats, 1);
paramValues[0] = (char *)&paramSector;
paramLengths[0] = sizeof(paramSector);
paramFormats[0] = 1;
}
else
{
paramValues[0] = (char *)&paramRank;
paramLengths[0] = sizeof(paramRank);
paramFormats[0] = 1;
paramValues[1] = (char *)&paramSector;
paramLengths[1] = sizeof(paramSector);
paramFormats[1] = 1;
iResult = PQsendQueryPrepared(conn, "index_sector_places", 2, paramValues, paramLengths, paramFormats, 1);
}
}
if (!iResult)
{
fprintf(stderr, "index_sector_places: SELECT failed: %s", PQerrorMessage(conn));
PQclear(resPlaces);
exit(EXIT_FAILURE);
}
}
if (iSector > 0)
{
count = 0;
rankPerSecond = 0;
tuples = PQntuples(resPlaces);
if (tuples > 0)
{
// Spawn threads
for (i = 0; i < num_threads; i++)
{
thread_data[i].res = resPlaces;
thread_data[i].tuples = tuples;
thread_data[i].count = &count;
thread_data[i].count_mutex = &count_mutex;
thread_data[i].writer = writer;
thread_data[i].writer_mutex = &writer_mutex;
if (interpolation)
{
thread_data[i].table = 0; // use interpolations table
}
else
{
thread_data[i].table = 1; // use placex table
}
pthread_create(&thread_data[i].thread, NULL, &nominatim_indexThread, (void *)&thread_data[i]);
}
// Monitor threads to give user feedback
sleepcount = 0;
while (count < tuples)
{
usleep(1000);
// Aim for one update per second
if (sleepcount++ > 500)
{
rankPerSecond = ((float)rankCountTuples + (float)count) / MAX(difftime(time(0), rankStartTime),1);
if(interpolation)
{
fprintf(stderr, " Done %i in %i @ %f per second - Interpolation lines ETA (seconds): %f\n", (rankCountTuples + count), (int)(difftime(time(0), rankStartTime)), rankPerSecond, ((float)(rankTotalTuples - (rankCountTuples + count)))/rankPerSecond);
}
else
{
fprintf(stderr, " Done %i in %i @ %f per second - Rank %i ETA (seconds): %f\n", (rankCountTuples + count), (int)(difftime(time(0), rankStartTime)), rankPerSecond, rank, ((float)(rankTotalTuples - (rankCountTuples + count)))/rankPerSecond);
}
sleepcount = 0;
}
}
// Wait for everything to finish
for (i = 0; i < num_threads; i++)
{
pthread_join(thread_data[i].thread, NULL);
}
rankCountTuples += tuples;
}
// Finished sector
rankPerSecond = (float)rankCountTuples / MAX(difftime(time(0), rankStartTime),1);
fprintf(stderr, " Done %i in %i @ %f per second - ETA (seconds): %f\n", rankCountTuples, (int)(difftime(time(0), rankStartTime)), rankPerSecond, ((float)(rankTotalTuples - rankCountTuples))/rankPerSecond);
PQclear(resPlaces);
}
if (rankTotalTuples-rankCountTuples < num_threads*20 && iSector < PQntuples(resSectors))
{
iSector = PQntuples(resSectors) - 1;
}
}
// Finished rank
fprintf(stderr, "\r Done %i in %i @ %f per second - FINISHED\n\n", rankCountTuples, (int)(difftime(time(0), rankStartTime)), rankPerSecond);
PQclear(resSectors);
}
void nominatim_index(int rank_min, int rank_max, int num_threads, const char *conninfo, const char *structuredoutputfile)
{
struct index_thread_data * thread_data;
PGconn *conn;
PGresult * res;
int rank;
int i;
xmlTextWriterPtr writer; xmlTextWriterPtr writer;
pthread_mutex_t writer_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t writer_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -70,6 +293,16 @@ void nominatim_index(int rank_min, int rank_max, int num_threads, const char *co
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
PQclear(res); PQclear(res);
res = PQprepare(conn, "index_sectors_osmline",
"select geometry_sector,count(*) from location_property_osmline where indexed_status > 0 group by geometry_sector order by geometry_sector",
0, NULL);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "Failed preparing index_sectors: %s\n", PQerrorMessage(conn));
exit(EXIT_FAILURE);
}
PQclear(res);
pg_prepare_params[0] = PG_OID_INT4; pg_prepare_params[0] = PG_OID_INT4;
res = PQprepare(conn, "index_nosectors", res = PQprepare(conn, "index_nosectors",
@@ -104,7 +337,28 @@ void nominatim_index(int rank_min, int rank_max, int num_threads, const char *co
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
PQclear(res); PQclear(res);
pg_prepare_params[0] = PG_OID_INT4;
res = PQprepare(conn, "index_sector_places_osmline",
"select place_id from location_property_osmline where geometry_sector = $1 and indexed_status > 0",
1, pg_prepare_params);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "Failed preparing index_sector_places: %s\n", PQerrorMessage(conn));
exit(EXIT_FAILURE);
}
PQclear(res);
res = PQprepare(conn, "index_nosector_places_osmline",
"select place_id from location_property_osmline where indexed_status > 0 order by geometry_sector",
0, NULL);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "Failed preparing index_nosector_places: %s\n", PQerrorMessage(conn));
exit(EXIT_FAILURE);
}
PQclear(res);
// Build the data for each thread // Build the data for each thread
thread_data = (struct index_thread_data *)malloc(sizeof(struct index_thread_data)*num_threads); thread_data = (struct index_thread_data *)malloc(sizeof(struct index_thread_data)*num_threads);
for (i = 0; i < num_threads; i++) for (i = 0; i < num_threads; i++)
@@ -126,6 +380,17 @@ void nominatim_index(int rank_min, int rank_max, int num_threads, const char *co
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
PQclear(res); PQclear(res);
pg_prepare_params[0] = PG_OID_INT8;
res = PQprepare(thread_data[i].conn, "index_osmline",
"update location_property_osmline set indexed_status = 0 where place_id = $1",
1, pg_prepare_params);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "Failed preparing index_osmline: %s\n", PQerrorMessage(conn));
exit(EXIT_FAILURE);
}
PQclear(res);
/*res = PQexec(thread_data[i].conn, "set enable_seqscan = false"); /*res = PQexec(thread_data[i].conn, "set enable_seqscan = false");
if (PQresultStatus(res) != PGRES_COMMAND_OK) if (PQresultStatus(res) != PGRES_COMMAND_OK)
@@ -138,183 +403,25 @@ void nominatim_index(int rank_min, int rank_max, int num_threads, const char *co
nominatim_exportCreatePreparedQueries(thread_data[i].conn); nominatim_exportCreatePreparedQueries(thread_data[i].conn);
} }
// Create the output file
writer = NULL;
if (structuredoutputfile)
{
writer = nominatim_exportXMLStart(structuredoutputfile);
}
fprintf(stderr, "Starting indexing rank (%i to %i) using %i threads\n", rank_min, rank_max, num_threads); fprintf(stderr, "Starting indexing rank (%i to %i) using %i threads\n", rank_min, rank_max, num_threads);
for (rank = rank_min; rank <= rank_max; rank++) for (rank = rank_min; rank <= rank_max; rank++)
{ {
fprintf(stderr, "Starting rank %d\n", rank); // OSMLINE: do reindexing (=> reparenting) for interpolation lines at rank 30, but before all other objects of rank 30
rankCountTuples = 0; // reason: houses (rank 30) depend on the updated interpolation line, when reparenting (see placex_update in functions.sql)
rankPerSecond = 0; if (rank == 30)
paramRank = PGint32(rank);
paramValues[0] = (char *)&paramRank;
paramLengths[0] = sizeof(paramRank);
paramFormats[0] = 1;
// if (rank < 16)
// resSectors = PQexecPrepared(conn, "index_nosectors", 1, paramValues, paramLengths, paramFormats, 1);
// else
resSectors = PQexecPrepared(conn, "index_sectors", 1, paramValues, paramLengths, paramFormats, 1);
if (PQresultStatus(resSectors) != PGRES_TUPLES_OK)
{ {
fprintf(stderr, "index_sectors: SELECT failed: %s", PQerrorMessage(conn)); run_indexing(rank, 1, conn, num_threads, thread_data, structuredoutputfile);
PQclear(resSectors);
exit(EXIT_FAILURE);
} }
if (PQftype(resSectors, 0) != PG_OID_INT4) run_indexing(rank, 0, conn, num_threads, thread_data, structuredoutputfile);
{
fprintf(stderr, "Sector value has unexpected type\n");
PQclear(resSectors);
exit(EXIT_FAILURE);
}
if (PQftype(resSectors, 1) != PG_OID_INT8)
{
fprintf(stderr, "Sector value has unexpected type\n");
PQclear(resSectors);
exit(EXIT_FAILURE);
}
rankTotalTuples = 0;
for (iSector = 0; iSector < PQntuples(resSectors); iSector++)
{
rankTotalTuples += PGint64(*((uint64_t *)PQgetvalue(resSectors, iSector, 1)));
}
rankStartTime = time(0);
for (iSector = 0; iSector <= PQntuples(resSectors); iSector++)
{
if (iSector > 0)
{
resPlaces = PQgetResult(conn);
if (PQresultStatus(resPlaces) != PGRES_TUPLES_OK)
{
fprintf(stderr, "index_sector_places: SELECT failed: %s", PQerrorMessage(conn));
PQclear(resPlaces);
exit(EXIT_FAILURE);
}
if (PQftype(resPlaces, 0) != PG_OID_INT8)
{
fprintf(stderr, "Place_id value has unexpected type\n");
PQclear(resPlaces);
exit(EXIT_FAILURE);
}
resNULL = PQgetResult(conn);
if (resNULL != NULL)
{
fprintf(stderr, "Unexpected non-null response\n");
exit(EXIT_FAILURE);
}
}
if (iSector < PQntuples(resSectors))
{
sector = PGint32(*((uint32_t *)PQgetvalue(resSectors, iSector, 0)));
// fprintf(stderr, "\n Starting sector %d size %ld\n", sector, PGint64(*((uint64_t *)PQgetvalue(resSectors, iSector, 1))));
// Get all the place_id's for this sector
paramRank = PGint32(rank);
paramValues[0] = (char *)&paramRank;
paramLengths[0] = sizeof(paramRank);
paramFormats[0] = 1;
paramSector = PGint32(sector);
paramValues[1] = (char *)&paramSector;
paramLengths[1] = sizeof(paramSector);
paramFormats[1] = 1;
if (rankTotalTuples-rankCountTuples < num_threads*1000)
{
iResult = PQsendQueryPrepared(conn, "index_nosector_places", 1, paramValues, paramLengths, paramFormats, 1);
}
else
{
iResult = PQsendQueryPrepared(conn, "index_sector_places", 2, paramValues, paramLengths, paramFormats, 1);
}
if (!iResult)
{
fprintf(stderr, "index_sector_places: SELECT failed: %s", PQerrorMessage(conn));
PQclear(resPlaces);
exit(EXIT_FAILURE);
}
}
if (iSector > 0)
{
count = 0;
rankPerSecond = 0;
tuples = PQntuples(resPlaces);
if (tuples > 0)
{
// Spawn threads
for (i = 0; i < num_threads; i++)
{
thread_data[i].res = resPlaces;
thread_data[i].tuples = tuples;
thread_data[i].count = &count;
thread_data[i].count_mutex = &count_mutex;
thread_data[i].writer = writer;
thread_data[i].writer_mutex = &writer_mutex;
pthread_create(&thread_data[i].thread, NULL, &nominatim_indexThread, (void *)&thread_data[i]);
}
// Monitor threads to give user feedback
sleepcount = 0;
while (count < tuples)
{
usleep(1000);
// Aim for one update per second
if (sleepcount++ > 500)
{
rankPerSecond = ((float)rankCountTuples + (float)count) / MAX(difftime(time(0), rankStartTime),1);
fprintf(stderr, " Done %i in %i @ %f per second - Rank %i ETA (seconds): %f\n", (rankCountTuples + count), (int)(difftime(time(0), rankStartTime)), rankPerSecond, rank, ((float)(rankTotalTuples - (rankCountTuples + count)))/rankPerSecond);
sleepcount = 0;
}
}
// Wait for everything to finish
for (i = 0; i < num_threads; i++)
{
pthread_join(thread_data[i].thread, NULL);
}
rankCountTuples += tuples;
}
// Finished sector
rankPerSecond = (float)rankCountTuples / MAX(difftime(time(0), rankStartTime),1);
fprintf(stderr, " Done %i in %i @ %f per second - ETA (seconds): %f\n", rankCountTuples, (int)(difftime(time(0), rankStartTime)), rankPerSecond, ((float)(rankTotalTuples - rankCountTuples))/rankPerSecond);
PQclear(resPlaces);
}
if (rankTotalTuples-rankCountTuples < num_threads*20 && iSector < PQntuples(resSectors))
{
iSector = PQntuples(resSectors) - 1;
}
}
// Finished rank
fprintf(stderr, "\r Done %i in %i @ %f per second - FINISHED \n\n", rankCountTuples, (int)(difftime(time(0), rankStartTime)), rankPerSecond);
PQclear(resSectors);
} }
// Close all connections
if (writer) for (i = 0; i < num_threads; i++)
{ {
nominatim_exportXMLEnd(writer); PQfinish(thread_data[i].conn);
} }
PQfinish(conn);
// Close all connections
for (i = 0; i < num_threads; i++)
{
PQfinish(thread_data[i].conn);
}
PQfinish(conn);
} }
void *nominatim_indexThread(void * thread_data_in) void *nominatim_indexThread(void * thread_data_in)
@@ -324,12 +431,15 @@ void *nominatim_indexThread(void * thread_data_in)
PGresult *res; PGresult *res;
const char *paramValues[1]; const char *paramValues[1];
int paramLengths[1]; int paramLengths[1];
int paramFormats[1]; int paramFormats[1];
uint64_t paramPlaceID; uint64_t paramPlaceID;
uint64_t place_id; uint64_t place_id;
time_t updateStartTime; time_t updateStartTime;
uint table;
table = (uint)(thread_data->table);
while (1) while (1)
{ {
@@ -348,37 +458,58 @@ void *nominatim_indexThread(void * thread_data_in)
if (verbose) fprintf(stderr, " Processing place_id %ld\n", place_id); if (verbose) fprintf(stderr, " Processing place_id %ld\n", place_id);
updateStartTime = time(0); updateStartTime = time(0);
int done = 0; int done = 0;
if (thread_data->writer) if (thread_data->writer)
{ {
nominatim_exportPlaceQueries(place_id, thread_data->conn, &querySet); nominatim_exportPlaceQueries(place_id, thread_data->conn, &querySet);
} }
while(!done) while(!done)
{ {
paramPlaceID = PGint64(place_id); paramPlaceID = PGint64(place_id);
paramValues[0] = (char *)&paramPlaceID; paramValues[0] = (char *)&paramPlaceID;
paramLengths[0] = sizeof(paramPlaceID); paramLengths[0] = sizeof(paramPlaceID);
paramFormats[0] = 1; paramFormats[0] = 1;
res = PQexecPrepared(thread_data->conn, "index_placex", 1, paramValues, paramLengths, paramFormats, 1); if (table == 1) // table=1 for placex
if (PQresultStatus(res) == PGRES_COMMAND_OK) {
done = 1; res = PQexecPrepared(thread_data->conn, "index_placex", 1, paramValues, paramLengths, paramFormats, 1);
else }
{ else // table=0 for osmline
if (!strncmp(PQerrorMessage(thread_data->conn), "ERROR: deadlock detected", 25)) {
{ res = PQexecPrepared(thread_data->conn, "index_osmline", 1, paramValues, paramLengths, paramFormats, 1);
fprintf(stderr, "index_placex: UPDATE failed - deadlock, retrying (%ld)\n", place_id); }
PQclear(res); if (PQresultStatus(res) == PGRES_COMMAND_OK)
sleep(rand() % 10); done = 1;
} else
else {
{ if (!strncmp(PQerrorMessage(thread_data->conn), "ERROR: deadlock detected", 25))
fprintf(stderr, "index_placex: UPDATE failed: %s", PQerrorMessage(thread_data->conn)); {
PQclear(res); if (table == 1)
exit(EXIT_FAILURE); {
} fprintf(stderr, "index_placex: UPDATE failed - deadlock, retrying (%ld)\n", place_id);
} }
else
{
fprintf(stderr, "index_osmline: UPDATE failed - deadlock, retrying (%ld)\n", place_id);
}
PQclear(res);
sleep(rand() % 10);
}
else
{
if (table == 1)
{
fprintf(stderr, "index_placex: UPDATE failed: %s", PQerrorMessage(thread_data->conn));
}
else
{
fprintf(stderr, "index_osmline: UPDATE failed: %s", PQerrorMessage(thread_data->conn));
}
PQclear(res);
exit(EXIT_FAILURE);
}
}
} }
PQclear(res); PQclear(res);
if (difftime(time(0), updateStartTime) > 1) fprintf(stderr, " Slow place_id %ld\n", place_id); if (difftime(time(0), updateStartTime) > 1) fprintf(stderr, " Slow place_id %ld\n", place_id);

View File

@@ -14,6 +14,7 @@ struct index_thread_data
pthread_mutex_t * count_mutex; pthread_mutex_t * count_mutex;
xmlTextWriterPtr writer; xmlTextWriterPtr writer;
pthread_mutex_t * writer_mutex; pthread_mutex_t * writer_mutex;
uint table;
}; };
void nominatim_index(int rank_min, int rank_max, int num_threads, const char *conninfo, const char *structuredoutputfile); void nominatim_index(int rank_min, int rank_max, int num_threads, const char *conninfo, const char *structuredoutputfile);
void *nominatim_indexThread(void * thread_data_in); void *nominatim_indexThread(void * thread_data_in);

File diff suppressed because it is too large Load Diff

View File

@@ -17,6 +17,8 @@ CREATE INDEX idx_placex_parent_place_id ON placex USING BTREE (parent_place_id)
CREATE INDEX idx_placex_reverse_geometry ON placex USING gist (geometry) {ts:search-index} where rank_search != 28 and (name is not null or housenumber is not null) and class not in ('waterway','railway','tunnel','bridge','man_made'); CREATE INDEX idx_placex_reverse_geometry ON placex USING gist (geometry) {ts:search-index} where rank_search != 28 and (name is not null or housenumber is not null) and class not in ('waterway','railway','tunnel','bridge','man_made');
CREATE INDEX idx_location_area_country_place_id ON location_area_country USING BTREE (place_id) {ts:address-index}; CREATE INDEX idx_location_area_country_place_id ON location_area_country USING BTREE (place_id) {ts:address-index};
CREATE INDEX idx_osmline_parent_place_id ON location_property_osmline USING BTREE (parent_place_id) {ts:search-index};
CREATE INDEX idx_search_name_country_centroid ON search_name_country USING GIST (centroid) {ts:address-index}; CREATE INDEX idx_search_name_country_centroid ON search_name_country USING GIST (centroid) {ts:address-index};
DROP INDEX IF EXISTS place_id_idx; DROP INDEX IF EXISTS place_id_idx;

View File

@@ -75,6 +75,37 @@ CREATE TABLE location_property (
); );
SELECT AddGeometryColumn('location_property', 'centroid', 4326, 'POINT', 2); SELECT AddGeometryColumn('location_property', 'centroid', 4326, 'POINT', 2);
CREATE TABLE location_property_aux () INHERITS (location_property);
CREATE INDEX idx_location_property_aux_place_id ON location_property_aux USING BTREE (place_id);
CREATE INDEX idx_location_property_aux_parent_place_id ON location_property_aux USING BTREE (parent_place_id);
CREATE INDEX idx_location_property_aux_housenumber_parent_place_id ON location_property_aux USING BTREE (parent_place_id, housenumber);
GRANT SELECT ON location_property_aux TO "{www-user}";
CREATE TABLE location_property_tiger (linegeo GEOMETRY, place_id BIGINT, partition INTEGER, parent_place_id BIGINT, startnumber INTEGER, endnumber INTEGER, interpolationtype TEXT, postcode TEXT);
GRANT SELECT ON location_property_tiger TO "{www-user}";
drop table if exists location_property_osmline;
CREATE TABLE location_property_osmline (
linegeo GEOMETRY,
place_id BIGINT NOT NULL,
partition INTEGER,
osm_id BIGINT,
parent_place_id BIGINT,
startnumber INTEGER,
endnumber INTEGER,
interpolationtype TEXT,
street TEXT,
addr_place TEXT,
postcode TEXT,
calculated_country_code VARCHAR(2),
geometry_sector INTEGER,
indexed_status INTEGER,
indexed_date TIMESTAMP){ts:search-data};
CREATE UNIQUE INDEX idx_osmline_place_id ON location_property_osmline USING BTREE (place_id) {ts:search-index};
CREATE INDEX idx_osmline_geometry_sector ON location_property_osmline USING BTREE (geometry_sector) {ts:address-index};
CREATE INDEX idx_osmline_linegeo ON location_property_osmline USING GIST (linegeo) {ts:search-index};
GRANT SELECT ON location_property_osmline TO "{www-user}";
drop table IF EXISTS search_name; drop table IF EXISTS search_name;
CREATE TABLE search_name ( CREATE TABLE search_name (
place_id BIGINT, place_id BIGINT,
@@ -133,13 +164,15 @@ GRANT SELECT ON planet_osm_ways to "{www-user}" ;
GRANT SELECT ON planet_osm_rels to "{www-user}" ; GRANT SELECT ON planet_osm_rels to "{www-user}" ;
GRANT SELECT on location_area to "{www-user}" ; GRANT SELECT on location_area to "{www-user}" ;
-- insert creates the location tagbles, creates location indexes if indexed == true -- insert creates the location tables, creates location indexes if indexed == true
CREATE TRIGGER placex_before_insert BEFORE INSERT ON placex CREATE TRIGGER placex_before_insert BEFORE INSERT ON placex
FOR EACH ROW EXECUTE PROCEDURE placex_insert(); FOR EACH ROW EXECUTE PROCEDURE placex_insert();
-- update insert creates the location tables -- update insert creates the location tables
CREATE TRIGGER placex_before_update BEFORE UPDATE ON placex CREATE TRIGGER placex_before_update BEFORE UPDATE ON placex
FOR EACH ROW EXECUTE PROCEDURE placex_update(); FOR EACH ROW EXECUTE PROCEDURE placex_update();
CREATE TRIGGER osmline_before_update BEFORE UPDATE ON location_property_osmline
FOR EACH ROW EXECUTE PROCEDURE osmline_update();
-- diff update triggers -- diff update triggers
CREATE TRIGGER placex_before_delete AFTER DELETE ON placex CREATE TRIGGER placex_before_delete AFTER DELETE ON placex

View File

@@ -18,7 +18,10 @@ Feature: Reverse geocoding
| xml | 4 | xml | 4
When looking up coordinates 53.9788769,13.0830313 When looking up coordinates 53.9788769,13.0830313
And results contain valid boundingboxes And results contain valid boundingboxes
Scenario: Reverse geocoding for odd interpolated housenumber
Scenario: Reverse geocoding for even interpolated housenumber
@Tiger @Tiger
Scenario: TIGER house number Scenario: TIGER house number

View File

@@ -2,41 +2,23 @@
Feature: Import of address interpolations Feature: Import of address interpolations
Tests that interpolated addresses are added correctly Tests that interpolated addresses are added correctly
Scenario: Simple even two point interpolation Scenario: Simple even interpolation line with two points
Given the place nodes Given the place nodes
| osm_id | class | type | housenumber | geometry | osm_id | osm_type | class | type | housenumber | geometry
| 1 | place | house | 2 | 1 1 | 1 | N | place | house | 2 | 1 1
| 2 | place | house | 6 | 1 1.001 | 2 | N | place | house | 6 | 1 1.001
And the place ways And the place ways
| osm_id | class | type | housenumber | geometry | osm_id | osm_type | class | type | housenumber | geometry
| 1 | place | houses | even | 1 1, 1 1.001 | 1 | W | place | houses | even | 1 1, 1 1.001
And the ways And the ways
| id | nodes | id | nodes
| 1 | 1,2 | 1 | 1,2
When importing When importing
Then way 1 expands to housenumbers Then way 1 expands to lines
| housenumber | centroid | startnumber | endnumber | geometry
| 4 | 1,1.0005 | 2 | 6 | 1 1, 1 1.001
Scenario: Simple even two point interpolation with zero beginning Scenario: Backwards even two point interpolation line
Given the place nodes
| osm_id | class | type | housenumber | geometry
| 1 | place | house | 0 | 1 1
| 2 | place | house | 8 | 1 1.001
And the place ways
| osm_id | class | type | housenumber | geometry
| 1 | place | houses | even | 1 1, 1 1.001
And the ways
| id | nodes
| 1 | 1,2
When importing
Then way 1 expands to housenumbers
| housenumber | centroid
| 2 | 1,1.00025
| 4 | 1,1.0005
| 6 | 1,1.00075
Scenario: Backwards even two point interpolation
Given the place nodes Given the place nodes
| osm_id | class | type | housenumber | geometry | osm_id | class | type | housenumber | geometry
| 1 | place | house | 2 | 1 1 | 1 | place | house | 2 | 1 1
@@ -48,77 +30,9 @@ Feature: Import of address interpolations
| id | nodes | id | nodes
| 1 | 2,1 | 1 | 2,1
When importing When importing
Then way 1 expands to housenumbers Then way 1 expands to lines
| housenumber | centroid | startnumber | endnumber | geometry
| 4 | 1,1.0005 | 2 | 6 | 1 1, 1 1.001
Scenario: Even two point interpolation with odd beginning
Given the place nodes
| osm_id | class | type | housenumber | geometry
| 1 | place | house | 11 | 1 1
| 2 | place | house | 16 | 1 1.001
And the place ways
| osm_id | class | type | housenumber | geometry
| 1 | place | houses | even | 1 1, 1 1.001
And the ways
| id | nodes
| 1 | 1,2
When importing
Then way 1 expands to housenumbers
| housenumber | centroid
| 12 | 1,1.0002
| 14 | 1,1.0006
Scenario: Even two point interpolation with odd end
Given the place nodes
| osm_id | class | type | housenumber | geometry
| 1 | place | house | 10 | 1 1
| 2 | place | house | 15 | 1 1.001
And the place ways
| osm_id | class | type | housenumber | geometry
| 1 | place | houses | even | 1 1, 1 1.001
And the ways
| id | nodes
| 1 | 1,2
When importing
Then way 1 expands to housenumbers
| housenumber | centroid
| 12 | 1,1.0004
| 14 | 1,1.0008
Scenario: Reverse even two point interpolation with odd beginning
Given the place nodes
| osm_id | class | type | housenumber | geometry
| 1 | place | house | 11 | 1 1
| 2 | place | house | 16 | 1 1.001
And the place ways
| osm_id | class | type | housenumber | geometry
| 1 | place | houses | even | 1 1.001, 1 1
And the ways
| id | nodes
| 1 | 2,1
When importing
Then way 1 expands to housenumbers
| housenumber | centroid
| 12 | 1,1.0002
| 14 | 1,1.0006
Scenario: Reverse even two point interpolation with odd end
Given the place nodes
| osm_id | class | type | housenumber | geometry
| 1 | place | house | 10 | 1 1
| 2 | place | house | 15 | 1 1.001
And the place ways
| osm_id | class | type | housenumber | geometry
| 1 | place | houses | even | 1 1.001, 1 1
And the ways
| id | nodes
| 1 | 2,1
When importing
Then way 1 expands to housenumbers
| housenumber | centroid
| 12 | 1,1.0004
| 14 | 1,1.0008
Scenario: Simple odd two point interpolation Scenario: Simple odd two point interpolation
Given the place nodes Given the place nodes
@@ -132,29 +46,9 @@ Feature: Import of address interpolations
| id | nodes | id | nodes
| 1 | 1,2 | 1 | 1,2
When importing When importing
Then way 1 expands to housenumbers Then way 1 expands to lines
| housenumber | centroid | startnumber | endnumber | geometry
| 3 | 1,1.0002 | 1 | 11 | 1 1, 1 1.001
| 5 | 1,1.0004
| 7 | 1,1.0006
| 9 | 1,1.0008
Scenario: Odd two point interpolation with even beginning
Given the place nodes
| osm_id | class | type | housenumber | geometry
| 1 | place | house | 2 | 1 1
| 2 | place | house | 7 | 1 1.001
And the place ways
| osm_id | class | type | housenumber | geometry
| 1 | place | houses | odd | 1 1, 1 1.001
And the ways
| id | nodes
| 1 | 1,2
When importing
Then way 1 expands to housenumbers
| housenumber | centroid
| 3 | 1,1.0002
| 5 | 1,1.0006
Scenario: Simple all two point interpolation Scenario: Simple all two point interpolation
Given the place nodes Given the place nodes
@@ -168,27 +62,11 @@ Feature: Import of address interpolations
| id | nodes | id | nodes
| 1 | 1,2 | 1 | 1,2
When importing When importing
Then way 1 expands to housenumbers Then way 1 expands to lines
| housenumber | centroid | startnumber | endnumber | geometry
| 2 | 1,1.0005 | 1 | 3 | 1 1, 1 1.001
Scenario: Simple numbered two point interpolation Scenario: Even two point interpolation line with intermediate empty node
Given the place nodes
| osm_id | class | type | housenumber | geometry
| 1 | place | house | 3 | 1 1
| 2 | place | house | 9 | 1 1.001
And the place ways
| osm_id | class | type | housenumber | geometry
| 1 | place | houses | 3 | 1 1, 1 1.001
And the ways
| id | nodes
| 1 | 1,2
When importing
Then way 1 expands to housenumbers
| housenumber | centroid
| 6 | 1,1.0005
Scenario: Even two point interpolation with intermediate empty node
Given the place nodes Given the place nodes
| osm_id | class | type | housenumber | geometry | osm_id | class | type | housenumber | geometry
| 1 | place | house | 2 | 1 1 | 1 | place | house | 2 | 1 1
@@ -200,14 +78,11 @@ Feature: Import of address interpolations
| id | nodes | id | nodes
| 1 | 1,3,2 | 1 | 1,3,2
When importing When importing
Then way 1 expands to housenumbers Then way 1 expands to lines
| housenumber | centroid | startnumber | endnumber | geometry
| 4 | 1,1.0005 | 2 | 10 | 1 1, 1 1.001, 1.001 1.001
| 6 | 1,1.001
| 8 | 1.0005,1.001
Scenario: Even two point interpolation line with intermediate duplicated empty node
Scenario: Even two point interpolation with intermediate duplicated empty node
Given the place nodes Given the place nodes
| osm_id | class | type | housenumber | geometry | osm_id | class | type | housenumber | geometry
| 1 | place | house | 2 | 1 1 | 1 | place | house | 2 | 1 1
@@ -219,13 +94,11 @@ Feature: Import of address interpolations
| id | nodes | id | nodes
| 1 | 1,3,3,2 | 1 | 1,3,3,2
When importing When importing
Then way 1 expands to housenumbers Then way 1 expands to lines
| housenumber | centroid | startnumber | endnumber | geometry
| 4 | 1,1.0005 | 2 | 10 | 1 1, 1 1.001, 1.001 1.001
| 6 | 1,1.001
| 8 | 1.0005,1.001
Scenario: Simple even three point interpolation Scenario: Simple even three point interpolation line
Given the place nodes Given the place nodes
| osm_id | class | type | housenumber | geometry | osm_id | class | type | housenumber | geometry
| 1 | place | house | 2 | 1 1 | 1 | place | house | 2 | 1 1
@@ -238,14 +111,12 @@ Feature: Import of address interpolations
| id | nodes | id | nodes
| 1 | 1,3,2 | 1 | 1,3,2
When importing When importing
Then way 1 expands to housenumbers Then way 1 expands to lines
| housenumber | centroid | startnumber | endnumber | geometry
| 4 | 1,1.00025 | 2 | 10 | 1 1, 1 1.001
| 6 | 1,1.0005 | 10 | 14 | 1 1.001, 1.001 1.001
| 8 | 1,1.00075
| 12 | 1.0005,1.001
Scenario: Simple even four point interpolation Scenario: Simple even four point interpolation line
Given the place nodes Given the place nodes
| osm_id | class | type | housenumber | geometry | osm_id | class | type | housenumber | geometry
| 1 | place | house | 2 | 1 1 | 1 | place | house | 2 | 1 1
@@ -259,15 +130,13 @@ Feature: Import of address interpolations
| id | nodes | id | nodes
| 1 | 1,3,2,4 | 1 | 1,3,2,4
When importing When importing
Then way 1 expands to housenumbers Then way 1 expands to lines
| housenumber | centroid | startnumber | endnumber | geometry
| 4 | 1,1.00025 | 2 | 10 | 1 1, 1 1.001
| 6 | 1,1.0005 | 10 | 14 | 1 1.001, 1.001 1.001
| 8 | 1,1.00075 | 14 | 18 | 1.001 1.001, 1.001 1.002
| 12 | 1.0005,1.001
| 16 | 1.001,1.0015
Scenario: Reverse simple even three point interpolation Scenario: Reverse simple even three point interpolation line
Given the place nodes Given the place nodes
| osm_id | class | type | housenumber | geometry | osm_id | class | type | housenumber | geometry
| 1 | place | house | 2 | 1 1 | 1 | place | house | 2 | 1 1
@@ -280,14 +149,12 @@ Feature: Import of address interpolations
| id | nodes | id | nodes
| 1 | 2,3,1 | 1 | 2,3,1
When importing When importing
Then way 1 expands to housenumbers Then way 1 expands to lines
| housenumber | centroid | startnumber | endnumber | geometry
| 4 | 1,1.00025 | 2 | 10 | 1 1, 1 1.001
| 6 | 1,1.0005 | 10 | 14 | 1 1.001, 1.001 1.001
| 8 | 1,1.00075
| 12 | 1.0005,1.001
Scenario: Even three point interpolation with odd center point Scenario: Even three point interpolation line with odd center point
Given the place nodes Given the place nodes
| osm_id | class | type | housenumber | geometry | osm_id | class | type | housenumber | geometry
| 1 | place | house | 2 | 1 1 | 1 | place | house | 2 | 1 1
@@ -300,12 +167,12 @@ Feature: Import of address interpolations
| id | nodes | id | nodes
| 1 | 1,3,2 | 1 | 1,3,2
When importing When importing
Then way 1 expands to housenumbers Then way 1 expands to lines
| housenumber | centroid | startnumber | endnumber | geometry
| 4 | 1,1.0004 | 2 | 7 | 1 1, 1 1.001
| 6 | 1,1.0008 | 7 | 8 | 1 1.001, 1.001 1.001
Scenario: Interpolation on self-intersecting way Scenario: Interpolation line with self-intersecting way
Given the place nodes Given the place nodes
| osm_id | class | type | housenumber | geometry | osm_id | class | type | housenumber | geometry
| 1 | place | house | 2 | 0 0 | 1 | place | house | 2 | 0 0
@@ -318,12 +185,13 @@ Feature: Import of address interpolations
| id | nodes | id | nodes
| 1 | 1,2,3,2 | 1 | 1,2,3,2
When importing When importing
Then way 1 expands to housenumbers Then way 1 expands to lines
| housenumber | centroid | startnumber | endnumber | geometry
| 4 | 0,0.0005 | 2 | 6 | 0 0, 0 0.001
| 8 | 0,0.0015 | 6 | 10 | 0 0.001, 0 0.002
| 6 | 10 | 0 0.001, 0 0.002
Scenario: Interpolation on self-intersecting way II Scenario: Interpolation line with self-intersecting way II
Given the place nodes Given the place nodes
| osm_id | class | type | housenumber | geometry | osm_id | class | type | housenumber | geometry
| 1 | place | house | 2 | 0 0 | 1 | place | house | 2 | 0 0
@@ -335,24 +203,24 @@ Feature: Import of address interpolations
| id | nodes | id | nodes
| 1 | 1,2,3,2 | 1 | 1,2,3,2
When importing When importing
Then way 1 expands to housenumbers Then way 1 expands to lines
| housenumber | centroid | startnumber | endnumber | geometry
| 4 | 0,0.0005 | 2 | 6 | 0 0, 0 0.001
Scenario: addr:street on interpolation way Scenario: addr:street on interpolation way
Given the scene parallel-road Given the scene parallel-road
And the place nodes And the place nodes
| osm_id | class | type | housenumber | geometry | osm_id | class | type | housenumber | geometry
| 1 | place | house | 2 | :n-middle-w | 1 | place | house | 2 | :n-middle-w
| 2 | place | house | 6 | :n-middle-e | 2 | place | house | 6 | :n-middle-e
| 3 | place | house | 12 | :n-middle-w | 3 | place | house | 12 | :n-middle-w
| 4 | place | house | 16 | :n-middle-e | 4 | place | house | 16 | :n-middle-e
And the place ways And the place ways
| osm_id | class | type | housenumber | street | geometry | osm_id | class | type | housenumber | street | geometry
| 10 | place | houses | even | | :w-middle | 10 | place | houses | even | | :w-middle
| 11 | place | houses | even | Cloud Street | :w-middle | 11 | place | houses | even | Cloud Street | :w-middle
And the place ways And the place ways
| osm_id | class | type | name | geometry | osm_id | class | type | name | geometry
| 2 | highway | tertiary | 'name' : 'Sun Way' | :w-north | 2 | highway | tertiary | 'name' : 'Sun Way' | :w-north
| 3 | highway | tertiary | 'name' : 'Cloud Street' | :w-south | 3 | highway | tertiary | 'name' : 'Cloud Street' | :w-south
@@ -360,49 +228,49 @@ Feature: Import of address interpolations
| id | nodes | id | nodes
| 10 | 1,100,101,102,2 | 10 | 1,100,101,102,2
| 11 | 3,200,201,202,4 | 11 | 3,200,201,202,4
When importing When importing
Then table placex contains Then table placex contains
| object | parent_place_id | object | parent_place_id
| N1 | W2 | N1 | W2
| N2 | W2 | N2 | W2
| N3 | W3 | N3 | W3
| N4 | W3 | N4 | W3
| W10 | W2 Then table location_property_osmline contains
| W11 | W3 | object | parent_place_id | startnumber | endnumber
And way 10 expands exactly to housenumbers 4 | W10 | W2 | 2 | 6
And way 11 expands exactly to housenumbers 14 | W11 | W3 | 12 | 16
Scenario: addr:street on housenumber way Scenario: addr:street on housenumber way
Given the scene parallel-road Given the scene parallel-road
And the place nodes And the place nodes
| osm_id | class | type | housenumber | street | geometry | osm_id | class | type | housenumber | street | geometry
| 1 | place | house | 2 | | :n-middle-w | 1 | place | house | 2 | | :n-middle-w
| 2 | place | house | 6 | | :n-middle-e | 2 | place | house | 6 | | :n-middle-e
| 3 | place | house | 12 | Cloud Street | :n-middle-w | 3 | place | house | 12 | Cloud Street | :n-middle-w
| 4 | place | house | 16 | Cloud Street | :n-middle-e | 4 | place | house | 16 | Cloud Street | :n-middle-e
And the place ways And the place ways
| osm_id | class | type | housenumber | geometry | osm_id | class | type | housenumber | geometry
| 10 | place | houses | even | :w-middle | 10 | place | houses | even | :w-middle
| 11 | place | houses | even | :w-middle | 11 | place | houses | even | :w-middle
And the place ways And the place ways
| osm_id | class | type | name | geometry | osm_id | class | type | name | geometry
| 2 | highway | tertiary | 'name' : 'Sun Way' | :w-north | 2 | highway | tertiary | 'name' : 'Sun Way' | :w-north
| 3 | highway | tertiary | 'name' : 'Cloud Street' | :w-south | 3 | highway | tertiary | 'name' : 'Cloud Street' | :w-south
And the ways And the ways
| id | nodes | id | nodes
| 10 | 1,100,101,102,2 | 10 | 1,100,101,102,2
| 11 | 3,200,201,202,4 | 11 | 3,200,201,202,4
When importing When importing
Then table placex contains Then table placex contains
| object | parent_place_id | object | parent_place_id
| N1 | W2 | N1 | W2
| N2 | W2 | N2 | W2
| N3 | W3 | N3 | W3
| N4 | W3 | N4 | W3
| W10 | W2 And table location_property_osmline contains
| W11 | W3 | object | parent_place_id | startnumber | endnumber
And way 10 expands exactly to housenumbers 4 | W10 | W2 | 2 | 6
And way 11 expands exactly to housenumbers 14 | W11 | W3 | 12 | 16
Scenario: Geometry of points and way don't match (github #253) Scenario: Geometry of points and way don't match (github #253)
Given the place nodes Given the place nodes
@@ -417,10 +285,10 @@ Feature: Import of address interpolations
| id | nodes | id | nodes
| 1 | 1,2,3 | 1 | 1,2,3
When importing When importing
Then way 1 expands to housenumbers Then way 1 expands to lines
| housenumber | centroid | startnumber | endnumber | geometry
| 4 | 144.963016723312,-37.7629464422819+-0.000005 | 2 | 6 | 144.9629794 -37.7630755, 144.9630541 -37.7628174
| 8 | 144.9631440856,-37.762223694978+-0.000005 | 6 | 10 | 144.9630541 -37.7628174, 144.9632341 -37.76163
Scenario: Place with missing address information Scenario: Place with missing address information
Given the place nodes Given the place nodes
@@ -435,7 +303,6 @@ Feature: Import of address interpolations
| id | nodes | id | nodes
| 1 | 1,2,3 | 1 | 1,2,3
When importing When importing
Then way 1 expands to housenumbers Then way 1 expands to lines
| housenumber | centroid | startnumber | endnumber | geometry
| 25 | 0.0001,0.0002 | 23 | 29 | 0.0001 0.0001, 0.0001 0.0002, 0.0001 0.0004
| 27 | 0.0001,0.0003

View File

@@ -23,19 +23,20 @@ Feature: Update of address interpolations
| object | parent_place_id | object | parent_place_id
| N1 | W2 | N1 | W2
| N2 | W2 | N2 | W2
| W10 | W2 And table location_property_osmline contains
And way 10 expands exactly to housenumbers 4 | object | parent_place_id | startnumber | endnumber
| W10 | W2 | 2 | 6
When updating place ways When updating place ways
| osm_id | class | type | housenumber | street | geometry | osm_id | class | type | housenumber | street | geometry
| 10 | place | houses | even | Cloud Street | :w-middle | 10 | place | houses | even | Cloud Street | :w-middle
Then way 10 expands exactly to housenumbers 4 Then table placex contains
And table placex contains
| object | parent_place_id | object | parent_place_id
| N1 | W3 | N1 | W3
| N2 | W3 | N2 | W3
| W10 | W3 And table location_property_osmline contains
| object | parent_place_id | startnumber | endnumber
| W10 | W3 | 2 | 6
@Fail
Scenario: addr:street added to housenumbers Scenario: addr:street added to housenumbers
Given the scene parallel-road Given the scene parallel-road
And the place nodes And the place nodes
@@ -57,18 +58,20 @@ Feature: Update of address interpolations
| object | parent_place_id | object | parent_place_id
| N1 | W2 | N1 | W2
| N2 | W2 | N2 | W2
| W10 | W2 And table location_property_osmline contains
And way 10 expands exactly to housenumbers 4 | object | parent_place_id | startnumber | endnumber
| W10 | W2 | 2 | 6
When updating place nodes When updating place nodes
| osm_id | class | type | street | housenumber | geometry | osm_id | class | type | street | housenumber | geometry
| 1 | place | house | Cloud Street| 2 | :n-middle-w | 1 | place | house | Cloud Street| 2 | :n-middle-w
| 2 | place | house | Cloud Street| 6 | :n-middle-e | 2 | place | house | Cloud Street| 6 | :n-middle-e
Then way 10 expands exactly to housenumbers 4 Then table placex contains
And table placex contains
| object | parent_place_id | object | parent_place_id
| N1 | W3 | N1 | W3
| N2 | W3 | N2 | W3
| W10 | W3 And table location_property_osmline contains
| object | parent_place_id | startnumber | endnumber
| W10 | W3 | 2 | 6
Scenario: interpolation tag removed Scenario: interpolation tag removed
@@ -92,10 +95,11 @@ Feature: Update of address interpolations
| object | parent_place_id | object | parent_place_id
| N1 | W2 | N1 | W2
| N2 | W2 | N2 | W2
| W10 | W2 And table location_property_osmline contains
And way 10 expands exactly to housenumbers 4 | object | parent_place_id | startnumber | endnumber
| W10 | W2 | 2 | 6
When marking for delete W10 When marking for delete W10
Then way 10 expands to no housenumbers Then table location_property_osmline has no entry for W10
And table placex contains And table placex contains
| object | parent_place_id | object | parent_place_id
| N1 | W2 | N1 | W2
@@ -122,17 +126,19 @@ Feature: Update of address interpolations
| object | parent_place_id | object | parent_place_id
| N1 | W2 | N1 | W2
| N2 | W2 | N2 | W2
| W10 | W2 And table location_property_osmline contains
And way 10 expands exactly to housenumbers 4 | object | parent_place_id | startnumber | endnumber
| W10 | W2 | 2 | 6
When updating place ways When updating place ways
| osm_id | class | type | name | geometry | osm_id | class | type | name | geometry
| 3 | highway | unclassified | 'name' : 'Cloud Street' | :w-south | 3 | highway | unclassified | 'name' : 'Cloud Street' | :w-south
Then way 10 expands exactly to housenumbers 4 Then table placex contains
And table placex contains
| object | parent_place_id | object | parent_place_id
| N1 | W3 | N1 | W3
| N2 | W3 | N2 | W3
| W10 | W3 And table location_property_osmline contains
| object | parent_place_id | startnumber | endnumber
| W10 | W3 | 2 | 6
Scenario: referenced road deleted Scenario: referenced road deleted
@@ -156,12 +162,97 @@ Feature: Update of address interpolations
| object | parent_place_id | object | parent_place_id
| N1 | W3 | N1 | W3
| N2 | W3 | N2 | W3
| W10 | W3 And table location_property_osmline contains
And way 10 expands exactly to housenumbers 4 | object | parent_place_id | startnumber | endnumber
| W10 | W3 | 2 | 6
When marking for delete W3 When marking for delete W3
Then way 10 expands exactly to housenumbers 4 Then table placex contains
And table placex contains
| object | parent_place_id | object | parent_place_id
| N1 | W2 | N1 | W2
| N2 | W2 | N2 | W2
| W10 | W2 And table location_property_osmline contains
| object | parent_place_id | startnumber | endnumber
| W10 | W2 | 2 | 6
Scenario: building becomes interpolation
Given the scene building-with-parallel-streets
And the place ways
| osm_id | class | type | housenumber | geometry
| 1 | place | house | 3 | :w-building
And the place ways
| osm_id | class | type | name | geometry
| 2 | highway | unclassified | 'name' : 'Cloud Street' | :w-south
When importing
Then table placex contains
| object | parent_place_id
| W1 | W2
When updating place nodes
| osm_id | class | type | housenumber | geometry
| 1 | place | house | 2 | :n-north-w
| 2 | place | house | 6 | :n-north-e
And the ways
| id | nodes
| 1 | 1,100,101,102,2
And updating place ways
| osm_id | class | type | housenumber | street | geometry
| 1 | place | houses | even | Cloud Street| :w-north
Then table placex has no entry for W1
And table location_property_osmline contains
| object | parent_place_id | startnumber | endnumber
| W1 | W2 | 2 | 6
Scenario: interpolation becomes building
Given the scene building-with-parallel-streets
And the place nodes
| osm_id | class | type | housenumber | geometry
| 1 | place | house | 2 | :n-north-w
| 2 | place | house | 6 | :n-north-e
And the place ways
| osm_id | class | type | name | geometry
| 2 | highway | unclassified | 'name' : 'Cloud Street' | :w-south
And the ways
| id | nodes
| 1 | 1,100,101,102,2
And the place ways
| osm_id | class | type | housenumber | street | geometry
| 1 | place | houses | even | Cloud Street| :w-north
When importing
Then table placex has no entry for W1
And table location_property_osmline contains
| object | parent_place_id | startnumber | endnumber
| W1 | W2 | 2 | 6
When updating place ways
| osm_id | class | type | housenumber | geometry
| 1 | place | house | 3 | :w-building
Then table placex contains
| object | parent_place_id
| W1 | W2
Scenario: housenumbers added to interpolation
Given the scene building-with-parallel-streets
And the place ways
| osm_id | class | type | name | geometry
| 2 | highway | unclassified | 'name' : 'Cloud Street' | :w-south
And the ways
| id | nodes
| 1 | 1,100,101,102,2
And the place ways
| osm_id | class | type | housenumber | geometry
| 1 | place | houses | even | :w-north
When importing
Then table location_property_osmline has no entry for W1
When updating place nodes
| osm_id | class | type | housenumber | geometry
| 1 | place | house | 2 | :n-north-w
| 2 | place | house | 6 | :n-north-e
And updating place ways
| osm_id | class | type | housenumber | street | geometry
| 1 | place | houses | even | Cloud Street| :w-north
Then table location_property_osmline contains
| object | parent_place_id | startnumber | endnumber
| W1 | W2 | 2 | 6

View File

@@ -24,3 +24,4 @@ osm2wkt: osm2wkt.cc
$(CXX) $(CXXFLAGS) $(CXXFLAGS_WARNINGS) -o $@ $< $(LDFLAGS) $(LIB_IO) $(CXX) $(CXXFLAGS) $(CXXFLAGS_WARNINGS) -o $@ $< $(LDFLAGS) $(LIB_IO)
scenarios: osm2wkt scenarios: osm2wkt
./make_scenes.sh

View File

@@ -1,4 +1,4 @@
#/bin/bash -e #!/bin/bash -e
# #
# Regenerates wkts for scenarios. # Regenerates wkts for scenarios.
# #
@@ -11,10 +11,10 @@ if [ ! -d "$datadir" ]; then
fi fi
echo "Using datadir $datadir" echo "Using datadir $datadir"
pushd $datadir cd $datadir
# remove old wkts # remove old wkts
rm $datadir/*.wkt rm -f $datadir/*.wkt
# create wkts from SQL scripts # create wkts from SQL scripts
for fl in *.sql; do for fl in *.sql; do
@@ -27,5 +27,3 @@ for fl in *.osm; do
echo "Processing $fl.." echo "Processing $fl.."
../bin/osm2wkt $fl ../bin/osm2wkt $fl
done done
popd

View File

@@ -92,10 +92,6 @@ int main(int argc, char* argv[]) {
reader2.close(); reader2.close();
export_handler.close(); export_handler.close();
std::cerr << "Pass 2 done\n"; std::cerr << "Pass 2 done\n";
google::protobuf::ShutdownProtobufLibrary();
} }

View File

@@ -0,0 +1,7 @@
n-south-w | POINT(1.0031633 2.001023)
n-south-e | POINT(1.0043359 2.0010068)
n-north-w | POINT(1.0031511 2.0012655)
n-north-e | POINT(1.0043238 2.0012493)
w-south | LINESTRING(1.0031633 2.001023,1.0036943 2.0010149,1.0040717 2.0010203,1.0043359 2.0010068)
w-north | LINESTRING(1.0031511 2.0012655,1.0036822 2.0012574,1.0040596 2.0012628,1.0043238 2.0012493)
w-building | LINESTRING(1.0036157 2.0011891,1.0036166 2.0010787,1.0038457 2.0010805,1.0038448 2.001191,1.0036157 2.0011891)

View File

@@ -56,7 +56,7 @@
cz | POINT(16.3209805488586 49.5069274902344) cz | POINT(16.3209805488586 49.5069274902344)
de | POINT(9.30716800689697 50.2128944396973) de | POINT(9.30716800689697 50.2128944396973)
dj | POINT(42.969040422876 11.41542855) dj | POINT(42.969040422876 11.41542855)
dk | POINT(9.18490123748779 55.5634002685547) dk | POINT(9.18490123748779 55.9891662597656)
dm | POINT(-61.0035801928854 15.6547055) dm | POINT(-61.0035801928854 15.6547055)
do | POINT(-69.6285591125488 18.5884169089722) do | POINT(-69.6285591125488 18.5884169089722)
dz | POINT(4.24749487638474 25.797215461731) dz | POINT(4.24749487638474 25.797215461731)
@@ -69,7 +69,7 @@
et | POINT(38.6169757843018 7.71399855613708) et | POINT(38.6169757843018 7.71399855613708)
fi | POINT(26.8979873657227 63.5619449615479) fi | POINT(26.8979873657227 63.5619449615479)
fj | POINT(177.918533325195 -17.7423753738403) fj | POINT(177.918533325195 -17.7423753738403)
fk | POINT(-60.0855102539062 -51.6555919647217) fk | POINT(-58.9904479980469 -51.3450936007813)
fm | POINT(151.9535889125 8.5045) fm | POINT(151.9535889125 8.5045)
fo | POINT(-6.60483694084778 62.10000995) fo | POINT(-6.60483694084778 62.10000995)
fr | POINT(0.284105718135834 47.5104522705078) fr | POINT(0.284105718135834 47.5104522705078)
@@ -105,7 +105,7 @@
in | POINT(88.6762087020508 27.86155515) in | POINT(88.6762087020508 27.86155515)
io | POINT(71.4274391359073 -6.14349685) io | POINT(71.4274391359073 -6.14349685)
iq | POINT(42.5810985565186 34.2610359191895) iq | POINT(42.5810985565186 34.2610359191895)
ir | POINT(51.268892288208 34.1931705474854) ir | POINT(56.0935573577881 30.4675178527832)
is | POINT(-17.5178508758545 64.7168769836426) is | POINT(-17.5178508758545 64.7168769836426)
it | POINT(10.4263944625854 44.8790493011475) it | POINT(10.4263944625854 44.8790493011475)
je | POINT(-2.19261599848299 49.1245833) je | POINT(-2.19261599848299 49.1245833)
@@ -156,7 +156,7 @@
mw | POINT(33.9572296142578 -12.2821822166443) mw | POINT(33.9572296142578 -12.2821822166443)
mx | POINT(-105.892219543457 25.8682699203491) mx | POINT(-105.892219543457 25.8682699203491)
my | POINT(112.711540222168 2.10098683834076) my | POINT(112.711540222168 2.10098683834076)
mz | POINT(37.5868968963623 -15.5801844596863) mz | POINT(37.5868968963623 -13.7268223762512)
na | POINT(16.6856970787048 -21.4657220840454) na | POINT(16.6856970787048 -21.4657220840454)
nc | POINT(164.953224182129 -20.3888988494873) nc | POINT(164.953224182129 -20.3888988494873)
ne | POINT(10.060417175293 19.0827360153198) ne | POINT(10.060417175293 19.0827360153198)
@@ -204,7 +204,7 @@
sm | POINT(12.4606268797657 43.9427969) sm | POINT(12.4606268797657 43.9427969)
sn | POINT(-15.3711128234863 14.9947791099548) sn | POINT(-15.3711128234863 14.9947791099548)
so | POINT(46.9338359832764 9.34094429016113) so | POINT(46.9338359832764 9.34094429016113)
sr | POINT(-56.4855213165283 4.5773549079895) sr | POINT(-55.4286479949951 4.5698549747467)
ss | POINT(28.1357345581055 8.50933408737183) ss | POINT(28.1357345581055 8.50933408737183)
st | POINT(6.61025854583333 0.2215) st | POINT(6.61025854583333 0.2215)
sv | POINT(-89.3666543301004 13.4307287) sv | POINT(-89.3666543301004 13.4307287)

View File

@@ -1,347 +1,399 @@
<?xml version='1.0' encoding='UTF-8'?> <?xml version='1.0' encoding='UTF-8'?>
<osm version='0.6' upload='false' generator='JOSM'> <osm version='0.6' upload='false' generator='JOSM'>
<node id='-197' action='modify' visible='true' lat='2.0006515863' lon='1.0057464449'> <node id='-11' action='modify' visible='true' lat='2.0006515863' lon='1.0057464449'>
<tag k='name' v='split-road' /> <tag k='name' v='split-road' />
</node> </node>
<node id='-195' action='modify' visible='true' lat='2.00053508276' lon='1.00574909433' /> <node id='-13' action='modify' visible='true' lat='2.00053508276' lon='1.00574909433' />
<node id='-193' action='modify' visible='true' lat='2.00054302619' lon='1.00589746199' /> <node id='-15' action='modify' visible='true' lat='2.00054302619' lon='1.00589746199' />
<node id='-191' action='modify' visible='true' lat='2.00054302619' lon='1.0060511285' /> <node id='-17' action='modify' visible='true' lat='2.00054302619' lon='1.0060511285' />
<node id='-189' action='modify' visible='true' lat='2.00053243496' lon='1.00613061118' /> <node id='-19' action='modify' visible='true' lat='2.00053243496' lon='1.00613061118' />
<node id='-187' action='modify' visible='true' lat='2.00052449153' lon='1.00551064629' /> <node id='-21' action='modify' visible='true' lat='2.00052449153' lon='1.00551064629' />
<node id='-185' action='modify' visible='true' lat='2.00056685646' lon='1.00560867493' /> <node id='-23' action='modify' visible='true' lat='2.00056685646' lon='1.00560867493' />
<node id='-183' action='modify' visible='true' lat='2.00056156084' lon='1.00568550818' /> <node id='-25' action='modify' visible='true' lat='2.00056156084' lon='1.00568550818' />
<node id='-181' action='modify' visible='true' lat='2.00050066126' lon='1.00573584721' /> <node id='-27' action='modify' visible='true' lat='2.00050066126' lon='1.00573584721' />
<node id='-179' action='modify' visible='true' lat='2.00050595688' lon='1.0059107091' /> <node id='-29' action='modify' visible='true' lat='2.00050595688' lon='1.0059107091' />
<node id='-177' action='modify' visible='true' lat='2.00051125249' lon='1.00605377792' /> <node id='-31' action='modify' visible='true' lat='2.00051125249' lon='1.00605377792' />
<node id='-175' action='modify' visible='true' lat='2.00049536565' lon='1.00613591002' /> <node id='-33' action='modify' visible='true' lat='2.00049536565' lon='1.00613591002' />
<node id='-173' action='modify' visible='true' lat='2.0005139003' lon='1.00628427769' /> <node id='-35' action='modify' visible='true' lat='2.0005139003' lon='1.00628427769' />
<node id='-171' action='modify' visible='true' lat='2.00047153538' lon='1.00637170863' /> <node id='-37' action='modify' visible='true' lat='2.00047153538' lon='1.00637170863' />
<node id='-169' action='modify' visible='true' lat='2.00029678005' lon='1.00635846152' /> <node id='-39' action='modify' visible='true' lat='2.00029678005' lon='1.00635846152' />
<node id='-167' action='modify' visible='true' lat='2.00026235854' lon='1.00628162826' /> <node id='-41' action='modify' visible='true' lat='2.00026235854' lon='1.00628162826' />
<node id='-165' action='modify' visible='true' lat='2.00033914498' lon='1.00619949616' /> <node id='-43' action='modify' visible='true' lat='2.00033914498' lon='1.00619949616' />
<node id='-163' action='modify' visible='true' lat='2.00035767963' lon='1.00610411695' /> <node id='-45' action='modify' visible='true' lat='2.00035767963' lon='1.00610411695' />
<node id='-161' action='modify' visible='true' lat='2.00034973621' lon='1.00600343889' /> <node id='-47' action='modify' visible='true' lat='2.00034973621' lon='1.00600343889' />
<node id='-159' action='modify' visible='true' lat='2.00032590594' lon='1.0058868643' /> <node id='-49' action='modify' visible='true' lat='2.00032590594' lon='1.0058868643' />
<node id='-157' action='modify' visible='true' lat='2.0002808932' lon='1.00579413451' /> <node id='-51' action='modify' visible='true' lat='2.0002808932' lon='1.00579413451' />
<node id='-155' action='modify' visible='true' lat='2.00027824539' lon='1.00563516915' /> <node id='-53' action='modify' visible='true' lat='2.00027824539' lon='1.00563516915' />
<node id='-153' action='modify' visible='true' lat='2.00036032744' lon='1.00547090495' /> <node id='-55' action='modify' visible='true' lat='2.00036032744' lon='1.00547090495' />
<node id='-151' action='modify' visible='true' lat='2.00072654218' lon='1.00470543134'> <node id='-57' action='modify' visible='true' lat='2.00072654218' lon='1.00470543134'>
<tag k='name' v='points-on-road' /> <tag k='name' v='points-on-road' />
</node> </node>
<node id='-149' action='modify' visible='true' lat='2.00051552538' lon='1.00492201384' /> <node id='-59' action='modify' visible='true' lat='2.00051552538' lon='1.00492201384' />
<node id='-147' action='modify' visible='true' lat='2.00051552538' lon='1.00492201384'> <node id='-61' action='modify' visible='true' lat='2.00051552538' lon='1.00492201384'>
<tag k='test:id' v='n-N-unglued' /> <tag k='test:id' v='n-N-unglued' />
<tag k='test:section' v='points-on-roads' /> <tag k='test:section' v='points-on-roads' />
</node> </node>
<node id='-145' action='modify' visible='true' lat='2.00029485534' lon='1.00462587591'> <node id='-63' action='modify' visible='true' lat='2.00029485534' lon='1.00462587591'>
<tag k='test:id' v='n-S-unglued' /> <tag k='test:id' v='n-S-unglued' />
<tag k='test:section' v='points-on-roads' /> <tag k='test:section' v='points-on-roads' />
</node> </node>
<node id='-143' action='modify' visible='true' lat='2.00029485534' lon='1.00462587591' /> <node id='-65' action='modify' visible='true' lat='2.00029485534' lon='1.00462587591' />
<node id='-141' action='modify' visible='true' lat='2.00061177404' lon='1.00506613814'> <node id='-67' action='modify' visible='true' lat='2.00061177404' lon='1.00506613814'>
<tag k='test:id' v='n-NE' /> <tag k='test:id' v='n-NE' />
<tag k='test:section' v='points-on-roads' /> <tag k='test:section' v='points-on-roads' />
</node> </node>
<node id='-139' action='modify' visible='true' lat='2.00033485479' lon='1.00513387079'> <node id='-69' action='modify' visible='true' lat='2.00033485479' lon='1.00513387079'>
<tag k='test:id' v='n-SE' /> <tag k='test:id' v='n-SE' />
<tag k='test:section' v='points-on-roads' /> <tag k='test:section' v='points-on-roads' />
</node> </node>
<node id='-137' action='modify' visible='true' lat='2.00062408156' lon='1.00531551745' /> <node id='-71' action='modify' visible='true' lat='2.00062408156' lon='1.00531551745' />
<node id='-135' action='modify' visible='true' lat='2.00040869993' lon='1.00475826245'> <node id='-73' action='modify' visible='true' lat='2.00040869993' lon='1.00475826245'>
<tag k='test:id' v='n-NW' /> <tag k='test:id' v='n-NW' />
<tag k='test:section' v='points-on-roads' /> <tag k='test:section' v='points-on-roads' />
</node> </node>
<node id='-133' action='modify' visible='true' lat='2.00038408489' lon='1.00462587591' /> <node id='-75' action='modify' visible='true' lat='2.00038408489' lon='1.00462587591' />
<node id='-131' action='modify' visible='true' lat='2.00043023809' lon='1.00449964688' /> <node id='-77' action='modify' visible='true' lat='2.00043023809' lon='1.00449964688' />
<node id='-129' action='modify' visible='true' lat='2.00036870048' lon='1.00532783248' /> <node id='-79' action='modify' visible='true' lat='2.00036870048' lon='1.00532783248' />
<node id='-127' action='modify' visible='true' lat='2.00026408654' lon='1.00493683035' /> <node id='-81' action='modify' visible='true' lat='2.00026408654' lon='1.00493683035' />
<node id='-125' action='modify' visible='true' lat='2.00029177846' lon='1.00482599511' /> <node id='-83' action='modify' visible='true' lat='2.00029177846' lon='1.00482599511' />
<node id='-123' action='modify' visible='true' lat='2.00035639296' lon='1.00472747489'> <node id='-85' action='modify' visible='true' lat='2.00035639296' lon='1.00472747489'>
<tag k='test:id' v='n-SW' /> <tag k='test:id' v='n-SW' />
<tag k='test:section' v='points-on-roads' /> <tag k='test:section' v='points-on-roads' />
</node> </node>
<node id='-121' action='modify' visible='true' lat='2.00022408708' lon='1.00452427693' /> <node id='-87' action='modify' visible='true' lat='2.00022408708' lon='1.00452427693' />
<node id='-119' action='modify' visible='true' lat='2.00071561841' lon='1.00183227343'> <node id='-89' action='modify' visible='true' lat='2.00071561841' lon='1.00183227343'>
<tag k='name' v='road-with-alley' /> <tag k='name' v='road-with-alley' />
</node> </node>
<node id='-117' action='modify' visible='true' lat='2.00072864414' lon='1.00046699629'> <node id='-91' action='modify' visible='true' lat='2.00072864414' lon='1.00046699629'>
<tag k='name' v='roads-with-pois' /> <tag k='name' v='roads-with-pois' />
</node> </node>
<node id='-115' action='modify' visible='true' lat='2.00035415446' lon='1.00244811443'> <node id='-93' action='modify' visible='true' lat='2.00035415446' lon='1.00244811443'>
<tag k='test:id' v='n-main-east' /> <tag k='test:id' v='n-main-east' />
<tag k='test:section' v='road-with-alley' /> <tag k='test:section' v='road-with-alley' />
</node> </node>
<node id='-113' action='modify' visible='true' lat='2.00026623078' lon='1.00155204948'> <node id='-95' action='modify' visible='true' lat='2.00026623078' lon='1.00155204948'>
<tag k='test:id' v='n-main-west' /> <tag k='test:id' v='n-main-west' />
<tag k='test:section' v='road-with-alley' /> <tag k='test:section' v='road-with-alley' />
</node> </node>
<node id='-111' action='modify' visible='true' lat='2.00054628396' lon='1.00192350914'> <node id='-97' action='modify' visible='true' lat='2.00054628396' lon='1.00192350914'>
<tag k='test:id' v='n-alley' /> <tag k='test:id' v='n-alley' />
<tag k='test:section' v='road-with-alley' /> <tag k='test:section' v='road-with-alley' />
</node> </node>
<node id='-109' action='modify' visible='true' lat='2.00035415446' lon='1.00192350914'> <node id='-99' action='modify' visible='true' lat='2.00035415446' lon='1.00192350914'>
<tag k='test:id' v='n-corner' /> <tag k='test:id' v='n-corner' />
<tag k='test:section' v='road-with-alley' /> <tag k='test:section' v='road-with-alley' />
</node> </node>
<node id='-107' action='modify' visible='true' lat='2.00057559185' lon='1.00195935173' /> <node id='-101' action='modify' visible='true' lat='2.00057559185' lon='1.00195935173' />
<node id='-105' action='modify' visible='true' lat='2.00029879511' lon='1.00260777692' /> <node id='-103' action='modify' visible='true' lat='2.00029879511' lon='1.00260777692' />
<node id='-103' action='modify' visible='true' lat='2.00031182084' lon='1.0023699124' /> <node id='-105' action='modify' visible='true' lat='2.00031182084' lon='1.0023699124' />
<node id='-101' action='modify' visible='true' lat='2.00031507727' lon='1.00212553105' /> <node id='-107' action='modify' visible='true' lat='2.00031507727' lon='1.00212553105' />
<node id='-99' action='modify' visible='true' lat='2.00030856441' lon='1.00195935173' /> <node id='-109' action='modify' visible='true' lat='2.00030856441' lon='1.00195935173' />
<node id='-97' action='modify' visible='true' lat='2.00030530797' lon='1.00167586937' /> <node id='-111' action='modify' visible='true' lat='2.00030530797' lon='1.00167586937' />
<node id='-95' action='modify' visible='true' lat='2.00031182084' lon='1.00134351073' /> <node id='-113' action='modify' visible='true' lat='2.00031182084' lon='1.00134351073' />
<node id='-93' action='modify' visible='true' lat='2.00040546963' lon='1.00011736285'> <node id='-115' action='modify' visible='true' lat='2.00040546963' lon='1.00011736285'>
<tag k='test:section' v='roads-with-pois' /> <tag k='test:section' v='roads-with-pois' />
</node> </node>
<node id='-91' action='modify' visible='true' lat='2.00039759893' lon='1.00042975784'> <node id='-117' action='modify' visible='true' lat='2.00039759893' lon='1.00042975784'>
<tag k='test:section' v='roads-with-pois' /> <tag k='test:section' v='roads-with-pois' />
</node> </node>
<node id='-89' action='modify' visible='true' lat='2.000457941' lon='1.00066077263'> <node id='-119' action='modify' visible='true' lat='2.000457941' lon='1.00066077263'>
<tag k='test:section' v='roads-with-pois' /> <tag k='test:section' v='roads-with-pois' />
</node> </node>
<node id='-87' action='modify' visible='true' lat='2.00054189517' lon='1.00106242333'> <node id='-121' action='modify' visible='true' lat='2.00054189517' lon='1.00106242333'>
<tag k='test:section' v='roads-with-pois' /> <tag k='test:section' v='roads-with-pois' />
</node> </node>
<node id='-85' action='modify' visible='true' lat='2.00019033703' lon='1.00013836419'> <node id='-123' action='modify' visible='true' lat='2.00019033703' lon='1.00013836419'>
<tag k='test:section' v='roads-with-pois' /> <tag k='test:section' v='roads-with-pois' />
</node> </node>
<node id='-83' action='modify' visible='true' lat='2.00019820773' lon='1.00072115149'> <node id='-125' action='modify' visible='true' lat='2.00019820773' lon='1.00072115149'>
<tag k='test:section' v='roads-with-pois' /> <tag k='test:section' v='roads-with-pois' />
</node> </node>
<node id='-81' action='modify' visible='true' lat='2.00021919628' lon='1.00106767367'> <node id='-127' action='modify' visible='true' lat='2.00021919628' lon='1.00106767367'>
<tag k='test:section' v='roads-with-pois' /> <tag k='test:section' v='roads-with-pois' />
</node> </node>
<node id='-79' action='modify' visible='true' lat='2.00033988043' lon='1.00039038032'> <node id='-129' action='modify' visible='true' lat='2.00033988043' lon='1.00039038032'>
<tag k='test:id' v='p-N2' /> <tag k='test:id' v='p-N2' />
<tag k='test:section' v='roads-with-pois' /> <tag k='test:section' v='roads-with-pois' />
</node> </node>
<node id='-77' action='modify' visible='true' lat='2.0002926562' lon='1.0008104072'> <node id='-131' action='modify' visible='true' lat='2.0002926562' lon='1.0008104072'>
<tag k='test:id' v='p-S1' /> <tag k='test:id' v='p-S1' />
<tag k='test:section' v='roads-with-pois' /> <tag k='test:section' v='roads-with-pois' />
</node> </node>
<node id='-75' action='modify' visible='true' lat='2.00052877733' lon='1.0005321394'> <node id='-133' action='modify' visible='true' lat='2.00052877733' lon='1.0005321394'>
<tag k='test:id' v='p-N1' /> <tag k='test:id' v='p-N1' />
<tag k='test:section' v='roads-with-pois' /> <tag k='test:section' v='roads-with-pois' />
</node> </node>
<node id='-73' action='modify' visible='true' lat='2.00010638283' lon='1.00063977128'> <node id='-135' action='modify' visible='true' lat='2.00010638283' lon='1.00063977128'>
<tag k='test:id' v='p-S2' /> <tag k='test:id' v='p-S2' />
<tag k='test:section' v='roads-with-pois' /> <tag k='test:section' v='roads-with-pois' />
</node> </node>
<node id='-71' action='modify' visible='true' lat='2.00072116924' lon='1.00358286582'> <node id='-137' action='modify' visible='true' lat='2.00072116924' lon='1.00358286582'>
<tag k='name' v='building-on-street-corner' /> <tag k='name' v='building-on-street-corner' />
</node> </node>
<node id='-69' action='modify' visible='true' lat='2.00023163534' lon='1.00317592051' /> <node id='-139' action='modify' visible='true' lat='2.00023163534' lon='1.00317592051' />
<node id='-67' action='modify' visible='true' lat='2.00022108767' lon='1.00403607904' /> <node id='-141' action='modify' visible='true' lat='2.00022108767' lon='1.00403607904' />
<node id='-65' action='modify' visible='true' lat='2.0002263615' lon='1.00427354612' /> <node id='-143' action='modify' visible='true' lat='2.0002263615' lon='1.00427354612' />
<node id='-63' action='modify' visible='true' lat='2.00010506339' lon='1.00404135609' /> <node id='-145' action='modify' visible='true' lat='2.00010506339' lon='1.00404135609' />
<node id='-61' action='modify' visible='true' lat='2.00063772026' lon='1.00403639915' /> <node id='-147' action='modify' visible='true' lat='2.00063772026' lon='1.00403639915' />
<node id='-59' action='modify' visible='true' lat='2.00043885695' lon='1.0039042871' /> <node id='-149' action='modify' visible='true' lat='2.00043885695' lon='1.0039042871' />
<node id='-57' action='modify' visible='true' lat='2.00043855477' lon='1.00400225362' /> <node id='-151' action='modify' visible='true' lat='2.00043855477' lon='1.00400225362' />
<node id='-55' action='modify' visible='true' lat='2.0002343878' lon='1.00400162309' /> <node id='-153' action='modify' visible='true' lat='2.0002343878' lon='1.00400162309' />
<node id='-53' action='modify' visible='true' lat='2.00023468998' lon='1.00390365657' /> <node id='-155' action='modify' visible='true' lat='2.00023468998' lon='1.00390365657' />
<node id='-51' action='modify' visible='true' lat='2.00032403886' lon='1.00400189996'> <node id='-157' action='modify' visible='true' lat='2.00032403886' lon='1.00400189996'>
<tag k='test:id' v='n-edge-NS' /> <tag k='test:id' v='n-edge-NS' />
<tag k='test:section' v='building-on-street-corner' /> <tag k='test:section' v='building-on-street-corner' />
</node> </node>
<node id='-49' action='modify' visible='true' lat='2.00035479802' lon='1.00393848586'> <node id='-159' action='modify' visible='true' lat='2.00035479802' lon='1.00393848586'>
<tag k='test:id' v='n-inner' /> <tag k='test:id' v='n-inner' />
<tag k='test:section' v='building-on-street-corner' /> <tag k='test:section' v='building-on-street-corner' />
</node> </node>
<node id='-47' action='modify' visible='true' lat='2.00046760515' lon='1.00394781445'> <node id='-161' action='modify' visible='true' lat='2.00046760515' lon='1.00394781445'>
<tag k='test:id' v='n-outer' /> <tag k='test:id' v='n-outer' />
<tag k='test:section' v='building-on-street-corner' /> <tag k='test:section' v='building-on-street-corner' />
</node> </node>
<node id='-45' action='modify' visible='true' lat='2.00023451637' lon='1.00395994156'> <node id='-163' action='modify' visible='true' lat='2.00023451637' lon='1.00395994156'>
<tag k='test:id' v='n-edge-WE' /> <tag k='test:id' v='n-edge-WE' />
<tag k='test:section' v='building-on-street-corner' /> <tag k='test:section' v='building-on-street-corner' />
</node> </node>
<node id='-43' action='modify' visible='true' lat='2.0001892102' lon='1.00653236169' /> <node id='-165' action='modify' visible='true' lat='2.0001892102' lon='1.00653236169' />
<node id='-41' action='modify' visible='true' lat='2.00027856164' lon='1.00667595302' /> <node id='-167' action='modify' visible='true' lat='2.00027856164' lon='1.00667595302' />
<node id='-39' action='modify' visible='true' lat='2.00027856164' lon='1.00681954435' /> <node id='-169' action='modify' visible='true' lat='2.00027856164' lon='1.00681954435' />
<node id='-37' action='modify' visible='true' lat='2.00025148545' lon='1.00691707809' /> <node id='-171' action='modify' visible='true' lat='2.00025148545' lon='1.00691707809' />
<node id='-35' action='modify' visible='true' lat='2.0001892102' lon='1.00704170453' /> <node id='-173' action='modify' visible='true' lat='2.0001892102' lon='1.00704170453' />
<node id='-33' action='modify' visible='true' lat='2.00017296448' lon='1.00724219054' /> <node id='-175' action='modify' visible='true' lat='2.00017296448' lon='1.00724219054' />
<node id='-31' action='modify' visible='true' lat='2.00062243814' lon='1.00685396461'> <node id='-177' action='modify' visible='true' lat='2.00062243814' lon='1.00685396461'>
<tag k='name' v='parallel-road' /> <tag k='name' v='parallel-road' />
</node> </node>
<node id='-29' action='modify' visible='true' lat='2.00033813812' lon='1.00653156143'> <node id='-179' action='modify' visible='true' lat='2.00033813812' lon='1.00653156143'>
<tag k='test:id' v='n-middle-w' /> <tag k='test:id' v='n-middle-w' />
<tag k='test:section' v='parallel-road' /> <tag k='test:section' v='parallel-road' />
</node> </node>
<node id='-27' action='modify' visible='true' lat='2.00042478194' lon='1.00668598984' /> <node id='-181' action='modify' visible='true' lat='2.00042478194' lon='1.00668598984' />
<node id='-25' action='modify' visible='true' lat='2.00041665908' lon='1.00690002221' /> <node id='-183' action='modify' visible='true' lat='2.00041665908' lon='1.00690002221' />
<node id='-23' action='modify' visible='true' lat='2.00034084574' lon='1.00723597174'> <node id='-185' action='modify' visible='true' lat='2.00034084574' lon='1.00723597174'>
<tag k='test:id' v='n-middle-e' /> <tag k='test:id' v='n-middle-e' />
<tag k='test:section' v='parallel-road' /> <tag k='test:section' v='parallel-road' />
</node> </node>
<node id='-21' action='modify' visible='true' lat='2.00041801289' lon='1.00653968924' /> <node id='-187' action='modify' visible='true' lat='2.00041801289' lon='1.00653968924' />
<node id='-19' action='modify' visible='true' lat='2.00050736432' lon='1.00668328057' /> <node id='-189' action='modify' visible='true' lat='2.00050736432' lon='1.00668328057' />
<node id='-17' action='modify' visible='true' lat='2.00050736432' lon='1.00682687191' /> <node id='-191' action='modify' visible='true' lat='2.00050736432' lon='1.00682687191' />
<node id='-15' action='modify' visible='true' lat='2.00048028813' lon='1.00692440564' /> <node id='-193' action='modify' visible='true' lat='2.00048028813' lon='1.00692440564' />
<node id='-13' action='modify' visible='true' lat='2.00041801289' lon='1.00704903208' /> <node id='-195' action='modify' visible='true' lat='2.00041801289' lon='1.00704903208' />
<node id='-11' action='modify' visible='true' lat='2.00040176717' lon='1.00724951809' /> <node id='-197' action='modify' visible='true' lat='2.00040176717' lon='1.00724951809' />
<node id='-199' action='modify' visible='true' lat='2.00102300625' lon='1.00316327416'>
<tag k='test:id' v='n-south-w' />
<tag k='test:section' v='building-with-parallel-streets' />
</node>
<node id='-201' action='modify' visible='true' lat='2.00101492424' lon='1.00369431688' />
<node id='-203' action='modify' visible='true' lat='2.00102031225' lon='1.00407170765' />
<node id='-205' action='modify' visible='true' lat='2.00100684223' lon='1.00433588118'>
<tag k='test:id' v='n-south-e' />
<tag k='test:section' v='building-with-parallel-streets' />
</node>
<node id='-207' action='modify' visible='true' lat='2.00148637497' lon='1.00362153438'>
<tag k='name' v='building-with-parallel-streets' />
</node>
<node id='-209' action='modify' visible='true' lat='2.00126546664' lon='1.00315114374'>
<tag k='test:id' v='n-north-w' />
<tag k='test:section' v='building-with-parallel-streets' />
</node>
<node id='-211' action='modify' visible='true' lat='2.00125738463' lon='1.00368218646' />
<node id='-213' action='modify' visible='true' lat='2.00126277264' lon='1.00405957723' />
<node id='-215' action='modify' visible='true' lat='2.00124930262' lon='1.00432375077'>
<tag k='test:id' v='n-north-e' />
<tag k='test:section' v='building-with-parallel-streets' />
</node>
<node id='-217' action='modify' visible='true' lat='2.00118914388' lon='1.00361572227' />
<node id='-219' action='modify' visible='true' lat='2.0010786539' lon='1.00361659971' />
<node id='-221' action='modify' visible='true' lat='2.001080471' lon='1.003845694' />
<node id='-223' action='modify' visible='true' lat='2.00119096098' lon='1.00384481656' />
<node id='100000' timestamp='2014-01-01T00:00:00Z' uid='1' user='test' visible='true' version='1' changeset='1' lat='2.0' lon='1.0' /> <node id='100000' timestamp='2014-01-01T00:00:00Z' uid='1' user='test' visible='true' version='1' changeset='1' lat='2.0' lon='1.0' />
<node id='100001' timestamp='2014-01-01T00:00:00Z' uid='1' user='test' visible='true' version='1' changeset='1' lat='3.0' lon='1.0' /> <node id='100001' timestamp='2014-01-01T00:00:00Z' uid='1' user='test' visible='true' version='1' changeset='1' lat='3.0' lon='1.0' />
<node id='100002' timestamp='2014-01-01T00:00:00Z' uid='1' user='test' visible='true' version='1' changeset='1' lat='3.0' lon='2.0' /> <node id='100002' timestamp='2014-01-01T00:00:00Z' uid='1' user='test' visible='true' version='1' changeset='1' lat='3.0' lon='2.0' />
<node id='100003' timestamp='2014-01-01T00:00:00Z' uid='1' user='test' visible='true' version='1' changeset='1' lat='2.0' lon='2.0' /> <node id='100003' timestamp='2014-01-01T00:00:00Z' uid='1' user='test' visible='true' version='1' changeset='1' lat='2.0' lon='2.0' />
<way id='-237' action='modify' visible='true'> <way id='-229' action='modify' visible='true'>
<nd ref='-183' /> <nd ref='-25' />
<nd ref='-185' /> <nd ref='-23' />
<nd ref='-187' /> <nd ref='-21' />
<tag k='test:id' v='w-5' /> <tag k='test:id' v='w-5' />
<tag k='test:section' v='split-road' /> <tag k='test:section' v='split-road' />
</way> </way>
<way id='-235' action='modify' visible='true'> <way id='-231' action='modify' visible='true'>
<nd ref='-173' /> <nd ref='-35' />
<nd ref='-175' /> <nd ref='-33' />
<nd ref='-177' /> <nd ref='-31' />
<nd ref='-179' /> <nd ref='-29' />
<nd ref='-181' /> <nd ref='-27' />
<nd ref='-183' /> <nd ref='-25' />
<tag k='test:id' v='w-4a' /> <tag k='test:id' v='w-4a' />
<tag k='test:section' v='split-road' /> <tag k='test:section' v='split-road' />
</way> </way>
<way id='-233' action='modify' visible='true'> <way id='-233' action='modify' visible='true'>
<nd ref='-165' />
<nd ref='-167' />
<nd ref='-169' />
<nd ref='-171' />
<nd ref='-173' />
<tag k='test:id' v='w-3' />
<tag k='test:section' v='split-road' />
</way>
<way id='-231' action='modify' visible='true'>
<nd ref='-157' />
<nd ref='-159' />
<nd ref='-161' />
<nd ref='-163' />
<nd ref='-165' />
<tag k='test:id' v='w-2' />
<tag k='test:section' v='split-road' />
</way>
<way id='-229' action='modify' visible='true'>
<nd ref='-173' />
<nd ref='-189' />
<nd ref='-191' />
<nd ref='-193' />
<nd ref='-195' />
<nd ref='-183' />
<tag k='test:id' v='w-4b' />
<tag k='test:section' v='split-road' />
</way>
<way id='-227' action='modify' visible='true'>
<nd ref='-153' />
<nd ref='-155' />
<nd ref='-157' />
<tag k='test:id' v='w-1' />
<tag k='test:section' v='split-road' />
</way>
<way id='-225' action='modify' visible='true'>
<nd ref='-131' />
<nd ref='-133' />
<nd ref='-135' />
<nd ref='-149' />
<nd ref='-141' />
<nd ref='-137' />
<tag k='test:id' v='w-north' />
<tag k='test:section' v='points-on-roads' />
</way>
<way id='-223' action='modify' visible='true'>
<nd ref='-121' />
<nd ref='-143' />
<nd ref='-123' />
<nd ref='-125' />
<nd ref='-127' />
<nd ref='-139' />
<nd ref='-129' />
<tag k='test:id' v='w-south' />
<tag k='test:section' v='points-on-roads' />
</way>
<way id='-221' action='modify' visible='true'>
<nd ref='-99' />
<nd ref='-107' />
<tag k='test:id' v='w-alley' />
<tag k='test:section' v='road-with-alley' />
</way>
<way id='-219' action='modify' visible='true'>
<nd ref='-95' />
<nd ref='-97' />
<nd ref='-99' />
<nd ref='-101' />
<nd ref='-103' />
<nd ref='-105' />
<tag k='test:id' v='w-main' />
<tag k='test:section' v='road-with-alley' />
</way>
<way id='-217' action='modify' visible='true'>
<nd ref='-93' />
<nd ref='-91' />
<nd ref='-89' />
<nd ref='-87' />
<tag k='test:id' v='w-north' />
<tag k='test:section' v='roads-with-pois' />
</way>
<way id='-215' action='modify' visible='true'>
<nd ref='-85' />
<nd ref='-83' />
<nd ref='-81' />
<tag k='test:id' v='w-south' />
<tag k='test:section' v='roads-with-pois' />
</way>
<way id='-213' action='modify' visible='true'>
<nd ref='-69' />
<nd ref='-67' />
<nd ref='-65' />
<tag k='test:id' v='w-WE' />
<tag k='test:section' v='building-on-street-corner' />
</way>
<way id='-211' action='modify' visible='true'>
<nd ref='-63' />
<nd ref='-67' />
<nd ref='-61' />
<tag k='test:id' v='w-NS' />
<tag k='test:section' v='building-on-street-corner' />
</way>
<way id='-209' action='modify' visible='true'>
<nd ref='-59' />
<nd ref='-57' />
<nd ref='-51' />
<nd ref='-55' />
<nd ref='-45' />
<nd ref='-53' />
<nd ref='-59' />
<tag k='area' v='yes' />
<tag k='test:id' v='w-building' />
<tag k='test:section' v='building-on-street-corner' />
</way>
<way id='-207' action='modify' visible='true'>
<nd ref='-43' /> <nd ref='-43' />
<nd ref='-41' /> <nd ref='-41' />
<nd ref='-39' /> <nd ref='-39' />
<nd ref='-37' /> <nd ref='-37' />
<nd ref='-35' /> <nd ref='-35' />
<nd ref='-33' /> <tag k='test:id' v='w-3' />
<tag k='test:id' v='w-south' /> <tag k='test:section' v='split-road' />
<tag k='test:section' v='parallel-road' />
</way> </way>
<way id='-205' action='modify' visible='true'> <way id='-235' action='modify' visible='true'>
<nd ref='-29' /> <nd ref='-51' />
<nd ref='-27' /> <nd ref='-49' />
<nd ref='-25' /> <nd ref='-47' />
<nd ref='-23' /> <nd ref='-45' />
<tag k='test:id' v='w-middle' /> <nd ref='-43' />
<tag k='test:section' v='parallel-road' /> <tag k='test:id' v='w-2' />
<tag k='test:section' v='split-road' />
</way> </way>
<way id='-203' action='modify' visible='true'> <way id='-237' action='modify' visible='true'>
<nd ref='-21' /> <nd ref='-35' />
<nd ref='-19' /> <nd ref='-19' />
<nd ref='-17' /> <nd ref='-17' />
<nd ref='-15' /> <nd ref='-15' />
<nd ref='-13' /> <nd ref='-13' />
<nd ref='-11' /> <nd ref='-25' />
<tag k='test:id' v='w-4b' />
<tag k='test:section' v='split-road' />
</way>
<way id='-239' action='modify' visible='true'>
<nd ref='-55' />
<nd ref='-53' />
<nd ref='-51' />
<tag k='test:id' v='w-1' />
<tag k='test:section' v='split-road' />
</way>
<way id='-241' action='modify' visible='true'>
<nd ref='-77' />
<nd ref='-75' />
<nd ref='-73' />
<nd ref='-59' />
<nd ref='-67' />
<nd ref='-71' />
<tag k='test:id' v='w-north' />
<tag k='test:section' v='points-on-roads' />
</way>
<way id='-243' action='modify' visible='true'>
<nd ref='-87' />
<nd ref='-65' />
<nd ref='-85' />
<nd ref='-83' />
<nd ref='-81' />
<nd ref='-69' />
<nd ref='-79' />
<tag k='test:id' v='w-south' />
<tag k='test:section' v='points-on-roads' />
</way>
<way id='-245' action='modify' visible='true'>
<nd ref='-109' />
<nd ref='-101' />
<tag k='test:id' v='w-alley' />
<tag k='test:section' v='road-with-alley' />
</way>
<way id='-247' action='modify' visible='true'>
<nd ref='-113' />
<nd ref='-111' />
<nd ref='-109' />
<nd ref='-107' />
<nd ref='-105' />
<nd ref='-103' />
<tag k='test:id' v='w-main' />
<tag k='test:section' v='road-with-alley' />
</way>
<way id='-249' action='modify' visible='true'>
<nd ref='-115' />
<nd ref='-117' />
<nd ref='-119' />
<nd ref='-121' />
<tag k='test:id' v='w-north' />
<tag k='test:section' v='roads-with-pois' />
</way>
<way id='-251' action='modify' visible='true'>
<nd ref='-123' />
<nd ref='-125' />
<nd ref='-127' />
<tag k='test:id' v='w-south' />
<tag k='test:section' v='roads-with-pois' />
</way>
<way id='-253' action='modify' visible='true'>
<nd ref='-139' />
<nd ref='-141' />
<nd ref='-143' />
<tag k='test:id' v='w-WE' />
<tag k='test:section' v='building-on-street-corner' />
</way>
<way id='-255' action='modify' visible='true'>
<nd ref='-145' />
<nd ref='-141' />
<nd ref='-147' />
<tag k='test:id' v='w-NS' />
<tag k='test:section' v='building-on-street-corner' />
</way>
<way id='-257' action='modify' visible='true'>
<nd ref='-149' />
<nd ref='-151' />
<nd ref='-157' />
<nd ref='-153' />
<nd ref='-163' />
<nd ref='-155' />
<nd ref='-149' />
<tag k='area' v='yes' />
<tag k='test:id' v='w-building' />
<tag k='test:section' v='building-on-street-corner' />
</way>
<way id='-259' action='modify' visible='true'>
<nd ref='-165' />
<nd ref='-167' />
<nd ref='-169' />
<nd ref='-171' />
<nd ref='-173' />
<nd ref='-175' />
<tag k='test:id' v='w-south' />
<tag k='test:section' v='parallel-road' />
</way>
<way id='-261' action='modify' visible='true'>
<nd ref='-179' />
<nd ref='-181' />
<nd ref='-183' />
<nd ref='-185' />
<tag k='test:id' v='w-middle' />
<tag k='test:section' v='parallel-road' />
</way>
<way id='-263' action='modify' visible='true'>
<nd ref='-187' />
<nd ref='-189' />
<nd ref='-191' />
<nd ref='-193' />
<nd ref='-195' />
<nd ref='-197' />
<tag k='test:id' v='w-north' /> <tag k='test:id' v='w-north' />
<tag k='test:section' v='parallel-road' /> <tag k='test:section' v='parallel-road' />
</way> </way>
<way id='-265' action='modify' visible='true'>
<nd ref='-199' />
<nd ref='-201' />
<nd ref='-203' />
<nd ref='-205' />
<tag k='test:id' v='w-south' />
<tag k='test:section' v='building-with-parallel-streets' />
</way>
<way id='-267' action='modify' visible='true'>
<nd ref='-209' />
<nd ref='-211' />
<nd ref='-213' />
<nd ref='-215' />
<tag k='test:id' v='w-north' />
<tag k='test:section' v='building-with-parallel-streets' />
</way>
<way id='-269' action='modify' visible='true'>
<nd ref='-217' />
<nd ref='-219' />
<nd ref='-221' />
<nd ref='-223' />
<nd ref='-217' />
<tag k='test:id' v='w-building' />
<tag k='test:section' v='building-with-parallel-streets' />
</way>
<way id='100000' timestamp='2014-01-01T00:00:00Z' uid='1' user='test' visible='true' version='1' changeset='1'> <way id='100000' timestamp='2014-01-01T00:00:00Z' uid='1' user='test' visible='true' version='1' changeset='1'>
<nd ref='100000' /> <nd ref='100000' />
<nd ref='100001' /> <nd ref='100001' />

View File

@@ -35,6 +35,7 @@ def check_placex_names(step, osmtyp, osmid):
@step(u'table ([a-z_]+) contains$') @step(u'table ([a-z_]+) contains$')
def check_placex_content(step, tablename): def check_placex_content(step, tablename):
""" check that the given lines are in the given table """ check that the given lines are in the given table
@@ -49,13 +50,22 @@ def check_placex_content(step, tablename):
q = 'SELECT *' q = 'SELECT *'
if tablename == 'placex': if tablename == 'placex':
q = q + ", ST_X(centroid) as clat, ST_Y(centroid) as clon" q = q + ", ST_X(centroid) as clat, ST_Y(centroid) as clon"
q = q + ", ST_GeometryType(geometry) as geometrytype" if tablename == 'location_property_osmline':
q = q + ' FROM %s where osm_type = %%s and osm_id = %%s' % (tablename,) q = q + ' FROM %s where osm_id = %%s' % (tablename,)
else:
q = q + ", ST_GeometryType(geometry) as geometrytype"
q = q + ' FROM %s where osm_type = %%s and osm_id = %%s' % (tablename,)
if cls is None: if cls is None:
params = (osmtype, osmid) if tablename == 'location_property_osmline':
params = (osmid,)
else:
params = (osmtype, osmid)
else: else:
q = q + ' and class = %s' q = q + ' and class = %s'
params = (osmtype, osmid, cls) if tablename == 'location_property_osmline':
params = (osmid, cls)
else:
params = (osmtype, osmid, cls)
cur.execute(q, params) cur.execute(q, params)
assert(cur.rowcount > 0) assert(cur.rowcount > 0)
for res in cur: for res in cur:
@@ -92,6 +102,18 @@ def check_placex_missing(step, tablename, osmtyp, osmid, placeclass):
cur.close() cur.close()
world.conn.commit() world.conn.commit()
@step(u'table location_property_osmline has no entry for W(\d+)?')
def check_osmline_missing(step, osmid):
cur = world.conn.cursor()
try:
q = 'SELECT count(*) FROM location_property_osmline where osm_id = %s' % (osmid, )
cur.execute(q)
numres = cur.fetchone()[0]
assert_equals (numres, 0)
finally:
cur.close()
world.conn.commit()
@step(u'search_name table contains$') @step(u'search_name table contains$')
def check_search_name_content(step): def check_search_name_content(step):
cur = world.conn.cursor(cursor_factory=psycopg2.extras.DictCursor) cur = world.conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
@@ -118,27 +140,26 @@ def check_search_name_content(step):
else: else:
raise Exception("Cannot handle field %s in search_name table" % (k, )) raise Exception("Cannot handle field %s in search_name table" % (k, ))
@step(u'way (\d+) expands to housenumbers') @step(u'way (\d+) expands to lines')
def check_interpolated_housenumbers(step, nodeid): def check_interpolation_lines(step, wayid):
"""Check that the exact set of housenumbers has been entered in """Check that the correct interpolation line has been entered in
placex for the given source node. Expected are two columns: location_property_osmline for the given source line/nodes.
housenumber and centroid Expected are three columns:
startnumber, endnumber and linegeo
""" """
numbers = {} lines = []
for line in step.hashes: for line in step.hashes:
assert line["housenumber"] not in numbers lines.append((line["startnumber"], line["endnumber"], line["geometry"]))
numbers[line["housenumber"]] = line["centroid"]
cur = world.conn.cursor(cursor_factory=psycopg2.extras.DictCursor) cur = world.conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
cur.execute("""SELECT DISTINCT housenumber, cur.execute("""SELECT startnumber::text, endnumber::text, st_astext(linegeo) as geometry
ST_X(centroid) as clat, ST_Y(centroid) as clon FROM location_property_osmline WHERE osm_id = %s""",
FROM placex WHERE osm_type = 'W' and osm_id = %s (int(wayid),))
and class = 'place' and type = 'address'""", assert_equals(len(lines), cur.rowcount)
(int(nodeid),))
assert_equals(len(numbers), cur.rowcount)
for r in cur: for r in cur:
assert_in(r["housenumber"], numbers) linegeo = str(str(r["geometry"].split('(')[1]).split(')')[0]).replace(',', ', ')
world.match_geometry((r['clat'], r['clon']), numbers[r["housenumber"]]) exp = (r["startnumber"], r["endnumber"], linegeo)
del numbers[r["housenumber"]] assert_in(exp, lines)
lines.remove(exp)
@step(u'way (\d+) expands exactly to housenumbers ([0-9,]*)') @step(u'way (\d+) expands exactly to housenumbers ([0-9,]*)')
def check_interpolated_housenumber_list(step, nodeid, numberlist): def check_interpolated_housenumber_list(step, nodeid, numberlist):
@@ -149,7 +170,7 @@ def check_interpolated_housenumber_list(step, nodeid, numberlist):
cur = world.conn.cursor() cur = world.conn.cursor()
cur.execute("""SELECT housenumber FROM placex cur.execute("""SELECT housenumber FROM placex
WHERE osm_type = 'W' and osm_id = %s WHERE osm_type = 'W' and osm_id = %s
and class = 'place' and type = 'address'""", (int(nodeid),)) and class = 'place' and type = 'address'""", (int(nodeid),))
for r in cur: for r in cur:
assert_in(r[0], expected, "Unexpected house number %s for node %s." % (r[0], nodeid)) assert_in(r[0], expected, "Unexpected house number %s for node %s." % (r[0], nodeid))
expected.remove(r[0]) expected.remove(r[0])

View File

@@ -23,6 +23,7 @@ import os
import subprocess import subprocess
import random import random
import base64 import base64
import sys
psycopg2.extensions.register_type(psycopg2.extensions.UNICODE) psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
@@ -143,8 +144,8 @@ def import_set_scene(step, scene):
@step(u'the (named )?place (node|way|area)s') @step(u'the (named )?place (node|way|area)s')
def import_place_table_nodes(step, named, osmtype): def import_place_table_nodes(step, named, osmtype):
"""Insert a list of nodes into the placex table. """Insert a list of nodes into the place table.
Expects a table where columns are named in the same way as placex. Expects a table where columns are named in the same way as place.
""" """
cur = world.conn.cursor() cur = world.conn.cursor()
cur.execute('ALTER TABLE place DISABLE TRIGGER place_before_insert') cur.execute('ALTER TABLE place DISABLE TRIGGER place_before_insert')
@@ -214,18 +215,19 @@ def import_database(step):
""" Runs the actual indexing. """ """ Runs the actual indexing. """
world.run_nominatim_script('setup', 'create-functions', 'create-partition-functions') world.run_nominatim_script('setup', 'create-functions', 'create-partition-functions')
cur = world.conn.cursor() cur = world.conn.cursor()
#world.db_dump_table('place')
cur.execute("""insert into placex (osm_type, osm_id, class, type, name, admin_level, cur.execute("""insert into placex (osm_type, osm_id, class, type, name, admin_level,
housenumber, street, addr_place, isin, postcode, country_code, extratags, housenumber, street, addr_place, isin, postcode, country_code, extratags,
geometry) select * from place""") geometry) select * from place where not (class='place' and type='houses' and osm_type='W')""")
cur.execute("""select insert_osmline (osm_id, housenumber, street, addr_place, postcode, country_code, geometry) from place where class='place' and type='houses' and osm_type='W'""")
world.conn.commit() world.conn.commit()
world.run_nominatim_script('setup', 'index', 'index-noanalyse') world.run_nominatim_script('setup', 'index', 'index-noanalyse')
#world.db_dump_table('placex') #world.db_dump_table('placex')
#world.db_dump_table('location_property_osmline')
@step(u'updating place (node|way|area)s') @step(u'updating place (node|way|area)s')
def update_place_table_nodes(step, osmtype): def update_place_table_nodes(step, osmtype):
""" Replace a geometry in place by reinsertion and reindex database. """ Replace a geometry in place by reinsertion and reindex database."""
"""
world.run_nominatim_script('setup', 'create-functions', 'create-partition-functions', 'enable-diff-updates') world.run_nominatim_script('setup', 'create-functions', 'create-partition-functions', 'enable-diff-updates')
if osmtype == 'node': if osmtype == 'node':
_insert_place_table_nodes(step.hashes, False) _insert_place_table_nodes(step.hashes, False)

View File

@@ -123,16 +123,19 @@ def match_geometry(coord, matchstring):
logger.debug("Distances expected: %f, got: %f" % (expdist, dist)) logger.debug("Distances expected: %f, got: %f" % (expdist, dist))
assert dist <= expdist, "Geometry too far away, expected: %f, got: %f" % (expdist, dist) assert dist <= expdist, "Geometry too far away, expected: %f, got: %f" % (expdist, dist)
@world.absorb
def print_statement(element):
print '\n\n\n'+str(element)+'\n\n\n'
@world.absorb @world.absorb
def db_dump_table(table): def db_dump_table(table):
cur = world.conn.cursor() cur = world.conn.cursor()
cur.execute('SELECT * FROM %s' % table) cur.execute('SELECT * FROM %s' % table)
print '<<<<<<< BEGIN OF TABLE DUMP %s' % table print '\n\n\n<<<<<<< BEGIN OF TABLE DUMP %s' % table
for res in cur: for res in cur:
print res print res
print '<<<<<<< END OF TABLE DUMP %s' % table print '<<<<<<< END OF TABLE DUMP %s\n\n\n' % table
@world.absorb @world.absorb
def db_drop_database(name): def db_drop_database(name):

View File

@@ -353,6 +353,8 @@
echo '.'; echo '.';
if (!pg_query($oDB->connection, 'TRUNCATE placex')) fail(pg_last_error($oDB->connection)); if (!pg_query($oDB->connection, 'TRUNCATE placex')) fail(pg_last_error($oDB->connection));
echo '.'; echo '.';
if (!pg_query($oDB->connection, 'TRUNCATE location_property_osmline')) fail(pg_last_error($oDB->connection));
echo '.';
if (!pg_query($oDB->connection, 'TRUNCATE place_addressline')) fail(pg_last_error($oDB->connection)); if (!pg_query($oDB->connection, 'TRUNCATE place_addressline')) fail(pg_last_error($oDB->connection));
echo '.'; echo '.';
if (!pg_query($oDB->connection, 'TRUNCATE place_boundingbox')) fail(pg_last_error($oDB->connection)); if (!pg_query($oDB->connection, 'TRUNCATE place_boundingbox')) fail(pg_last_error($oDB->connection));
@@ -394,20 +396,30 @@
echo "Load Data\n"; echo "Load Data\n";
$aDBInstances = array(); $aDBInstances = array();
for($i = 0; $i < $iInstances; $i++) $iLoadThreads = max(1, $iInstances - 1);
for($i = 0; $i < $iLoadThreads; $i++)
{ {
$aDBInstances[$i] =& getDB(true); $aDBInstances[$i] =& getDB(true);
$sSQL = 'insert into placex (osm_type, osm_id, class, type, name, admin_level, '; $sSQL = 'insert into placex (osm_type, osm_id, class, type, name, admin_level, ';
$sSQL .= 'housenumber, street, addr_place, isin, postcode, country_code, extratags, '; $sSQL .= 'housenumber, street, addr_place, isin, postcode, country_code, extratags, ';
$sSQL .= 'geometry) select * from place where osm_id % '.$iInstances.' = '.$i; $sSQL .= 'geometry) select * from place where osm_id % '.$iLoadThreads.' = '.$i;
$sSQL .= " and not (class='place' and type='houses' and osm_type='W' and ST_GeometryType(geometry) = 'ST_LineString')";
if ($aCMDResult['verbose']) echo "$sSQL\n"; if ($aCMDResult['verbose']) echo "$sSQL\n";
if (!pg_send_query($aDBInstances[$i]->connection, $sSQL)) fail(pg_last_error($oDB->connection)); if (!pg_send_query($aDBInstances[$i]->connection, $sSQL)) fail(pg_last_error($oDB->connection));
} }
// last thread for interpolation lines
$aDBInstances[$iLoadThreads] =& getDB(true);
$sSQL = 'select insert_osmline (osm_id, housenumber, street, addr_place, postcode, country_code, ';
$sSQL .= 'geometry) from place where ';
$sSQL .= "class='place' and type='houses' and osm_type='W' and ST_GeometryType(geometry) = 'ST_LineString'";
if ($aCMDResult['verbose']) echo "$sSQL\n";
if (!pg_send_query($aDBInstances[$i]->connection, $sSQL)) fail(pg_last_error($oDB->connection));
$bAnyBusy = true; $bAnyBusy = true;
while($bAnyBusy) while($bAnyBusy)
{ {
$bAnyBusy = false; $bAnyBusy = false;
for($i = 0; $i < $iInstances; $i++) for($i = 0; $i <= $iLoadThreads; $i++)
{ {
if (pg_connection_busy($aDBInstances[$i]->connection)) $bAnyBusy = true; if (pg_connection_busy($aDBInstances[$i]->connection)) $bAnyBusy = true;
} }