Esempio n. 1
0
                void way(const osmium::Way& way) {
                    if (m_write_change_ops) {
                        open_close_op_tag(way.visible() ? (way.version() == 1 ? operation::op_create : operation::op_modify) : operation::op_delete);
                    }

                    write_prefix();
                    m_out += "<way";
                    write_meta(way);

                    if (way.tags().empty() && way.nodes().empty()) {
                        m_out += "/>\n";
                        return;
                    }

                    m_out += ">\n";

                    for (const auto& node_ref : way.nodes()) {
                        write_prefix();
                        oprintf(m_out, "  <nd ref=\"%" PRId64 "\"/>\n", node_ref.ref());
                    }

                    write_tags(way.tags());

                    write_prefix();
                    m_out += "</way>\n";
                }
Esempio n. 2
0
  double getNodeDistance(osmium::Way& w)
  {
    const char* way = w.tags() ["highway"];
    const char* maxspeed = w.tags() ["maxspeed"];
    double nodeDistance;
                                                                        // std::cout<<way<<std::endl;
    if(!maxspeed)
    {
    if(!strcmp (way, "primary")
    || !strcmp (way, "secondary")
    || !strcmp (way,"tertiary")
    || !strcmp (way, "unclassified")
    || !strcmp (way ,"road")
    || !strcmp (way, "primary_link")  
    || !strcmp (way, "secondary_link"))
    {
      maxspeed = "90";
    }

    if(!strcmp(way,"trunk")
    || !strcmp(way,"trunk_link"))
    {
      maxspeed = "110";
    }

    if(!strcmp(way, "motorway"))
    {
      maxspeed = "130";
    }

    if(!strcmp (way, "residential")
    || !strcmp (way, "track"))
    {
      maxspeed = "50";
    }
    
    if(!strcmp (way, "platform")
    || !strcmp (way, "service")
    || !strcmp (way, "path")
    || !strcmp (way, "living_street"))
    {
      maxspeed = "20";
    }
       }
       else
        maxspeed = "30";

      nodeDistance = atoi(maxspeed) * 0.2 / 3.6;
    return nodeDistance;
  }
Esempio n. 3
0
 // Many pubs are mapped as a way (often tagged as building=yes too).
 // Potentially a pub could be mapped as just building=pub - but this is exceedingly rare, so it is not tested here
 void way(const osmium::Way& way) {
     const char* amenity = way.tags().get_value_by_key("amenity");
     if (amenity && !strcmp(amenity, "pub")) {
         // For such buildings one may want to confirm the way is closed before doing more processing eg:
         //if (!way.is_closed()) {
         //  return;
         //}
         // However for just listing names, the above check is not really necessary
         const char* name = way.tags().get_value_by_key("name");
         if (name) {
             std::cout << name << std::endl;
         }
     }
 }
Esempio n. 4
0
    void way(const osmium::Way& way) {
        m_length += osmium::geom::haversine::distance(way.nodes());
        try {
            std::unique_ptr<OGRLineString> ogrlinestring = m_factory.create_linestring(way);
            gdalcpp::Feature feature(m_layer_ways, std::move(ogrlinestring));
            feature.set_field("way_id", std::to_string(way.id()).c_str());
            feature.set_field("name", way.tags().get_value_by_key("name"));
            feature.set_field("source", way.tags().get_value_by_key("source"));

            const bool bogus = way.tags().has_tag("coastline", "bogus");
            feature.set_field("bogus", bogus ? "t" : "f");
            feature.add_to_layer();
        } catch (const osmium::geometry_error&) {
            std::cerr << "Ignoring illegal geometry for way " << way.id() << ".\n";
        }
    }
    inline void parseWay(const osmium::Way& way)
    {
        const auto& tags = way.tags();
        auto it = std::find_if(tags.begin(), tags.end(), highway_filter);
        if (it == tags.end())
        {
            return;
        }

        const osmium::NodeRef& first = way.nodes().front();
        const osmium::NodeRef& last = way.nodes().back();

        // filter out closed ways, generally this will just cause false
        // positives with round-a-abouts
        if (first == last)
        {
            return;
        }

        const char* name = tags.get_value_by_key("name", "");
        const char* ref = tags.get_value_by_key("ref", "");

        unsigned name_id = getStringID(name);
        unsigned ref_id = getStringID(ref);

        // we can't use osmium ids because MultiMap expects unsigned keys
        unsigned long firstID = static_cast<unsigned long>(first.ref());
        unsigned long lastID = static_cast<unsigned long>(last.ref());

        const unsigned wayIdx = parsed_ways->size();
        endpoint_way_map->unsorted_set(firstID, wayIdx);
        endpoint_way_map->unsorted_set(lastID,  wayIdx);

        parsed_ways->emplace_back(way.id(), firstID, lastID, name_id, ref_id);
    }
    // The way handler is called for each node in the input data.
    void way(const osmium::Way& way) {
        {
            osmium::builder::WayBuilder builder{m_buffer};
            copy_attributes(builder, way);
            copy_tags(builder, way.tags());

            // Copy the node list over to the new way.
            builder.add_item(way.nodes());
        }
        m_buffer.commit();
    }
Esempio n. 7
0
void middle_pgsql_t::ways_set(osmium::Way const &way)
{
    copy_buffer.reserve(way.nodes().size() * 10 + way.tags().byte_size() + 100);
    bool copy = way_table->copyMode;
    char delim = copy ? '\t' : '\0';
    // Three params: id, nodes, tags */
    const char *paramValues[4] = { copy_buffer.c_str(), };

    copy_buffer = std::to_string(way.id());
    copy_buffer += delim;

    paramValues[1] = paramValues[0] + copy_buffer.size();
    if (way.nodes().size() == 0) {
        copy_buffer += "{}";
    } else {
        copy_buffer += "{";
        for (auto const &n : way.nodes()) {
            copy_buffer += std::to_string(n.ref());
            copy_buffer += ',';
        }
        copy_buffer[copy_buffer.size() - 1] = '}';
    }
    copy_buffer += delim;

    if (way.tags().empty() && !out_options->extra_attributes) {
        paramValues[2] = nullptr;
        copy_buffer += "\\N";
    } else {
        paramValues[2] = paramValues[0] + copy_buffer.size();
        buffer_store_tags(way, out_options->extra_attributes, copy);
    }

    if (copy) {
        copy_buffer += '\n';
        pgsql_CopyData(__FUNCTION__, way_table->sql_conn, copy_buffer);
    } else {
        buffer_correct_params(paramValues, 3);
        pgsql_execPrepared(way_table->sql_conn, "insert_way", 3,
                           (const char * const *)paramValues, PGRES_COMMAND_OK);
    }
}
    void way(const osmium::Way& way) {
        try {
            std::unique_ptr<OGRLineString> ogr_linestring = m_ogr_factory.create_linestring(way);
            OGRFeature* feature = OGRFeature::CreateFeature(m_layer_linestring->GetLayerDefn());
            feature->SetGeometry(ogr_linestring.get());
            feature->SetField("id", static_cast<double>(way.id()));
            feature->SetField("type", way.tags().get_value_by_key("type"));

            if (m_layer_linestring->CreateFeature(feature) != OGRERR_NONE) {
                std::cerr << "Failed to create feature.\n";
                exit(1);
            }

            OGRFeature::DestroyFeature(feature);
        } catch (osmium::geometry_error&) {
            std::cerr << "Ignoring illegal geometry for way " << way.id() << ".\n";
        }
    }
Esempio n. 9
0
            bool create_area(osmium::memory::Buffer& out_buffer, const osmium::Way& way) {
                osmium::builder::AreaBuilder builder{out_buffer};
                builder.initialize_from_object(way);

                const bool area_okay = create_rings();
                if (area_okay || config().create_empty_areas) {
                    builder.add_item(way.tags());
                }
                if (area_okay) {
                    add_rings_to_area(builder);
                }

                if (report_ways()) {
                    config().problem_reporter->report_way(way);
                }

                return area_okay || config().create_empty_areas;
            }
	void feed_way(const osmium::Way& way) {
		try {
			const char* building = way.tags().get_value_by_key("building");
			if (building && way.is_closed()) {
				const char* street   = way.tags().get_value_by_key("addr:street");
				const char* houseno  = way.tags().get_value_by_key("addr:housenumber");
				
				if (street || houseno) {
					std::unique_ptr<OGRLineString> ogr_linestring = m_factory.create_linestring(way);
					OGRFeature* feature = OGRFeature::CreateFeature(m_layer->GetLayerDefn());
					OGRPolygon polygon;
					polygon.addRing(static_cast<OGRLinearRing*>(ogr_linestring.get()));
					feature->SetGeometry(static_cast<OGRGeometry*>(&polygon));
					feature->SetField("way_id", static_cast<double>(way.id())); //TODO: node.id() is of type int64_t. is this ok?
					feature->SetField("lastchange", way.timestamp().to_iso().c_str());

					const char* postcode = way.tags().get_value_by_key("addr:postcode");
					const char* city     = way.tags().get_value_by_key("addr:city");
					const char* country  = way.tags().get_value_by_key("addr:country");
					const char* fulladdr = way.tags().get_value_by_key("addr:full");
					const char* place    = way.tags().get_value_by_key("addr:place");

					if (street)   { feature->SetField("street"  , street);   }
					if (houseno)  { feature->SetField("houseno" , houseno);  }
					if (postcode) { feature->SetField("postcode", postcode); }
					if (city)     { feature->SetField("city",     city);     }
					if (country)  { feature->SetField("country",  country);  }
					if (fulladdr) { feature->SetField("fulladdr", fulladdr); }
					if (place)    { feature->SetField("place",    place);    }

					create_feature(feature);

				}
			}
		}
		catch (osmium::geometry_error& e) {
			catch_geometry_error(e, way);
		}
	}
	void feed_way(const osmium::Way& way) {
		try {
			const char* building = way.tags().get_value_by_key("building");

			if (building && way.is_closed()) {
				std::unique_ptr<OGRLineString> ogr_linestring = m_factory.create_linestring(way);
				OGRFeature* feature = OGRFeature::CreateFeature(m_layer->GetLayerDefn());
				OGRPolygon polygon;
				polygon.addRing(static_cast<OGRLinearRing*>(ogr_linestring.get()));
				feature->SetGeometry(static_cast<OGRGeometry*>(&polygon));

				feature->SetField("way_id", static_cast<double>(way.id())); //TODO: node.id() is of type int64_t. is this ok?
				feature->SetField("lastchange", way.timestamp().to_iso().c_str());

				create_feature(feature);
			}

		} catch (osmium::geom::geometry_error& e) {
			catch_geometry_error(e, way);
		}
	}
Esempio n. 12
0
  void way ( osmium::Way& way )
  {

    const char* highway = way.tags() ["highway"];
    if ( !highway )
      return;
    // http://wiki.openstreetmap.org/wiki/Key:highway
    if ( !strcmp ( highway, "footway" )
         || !strcmp ( highway, "cycleway" )
         || !strcmp ( highway, "bridleway" )
         || !strcmp ( highway, "steps" )
         || !strcmp ( highway, "path" )
         || !strcmp ( highway, "construction" ) )
      return;

    onewayf = false;
    const char* oneway = way.tags() ["oneway"];
    if ( oneway )
      {
        onewayf = true;
        ++onewayc;
      }

    ++nOSM_ways;

    double way_length = osmium::geom::haversine::distance ( way.nodes() );
    sum_highhway_length += way_length;

    int node_counter {0};
    int unique_node_counter {0};
    osmium::Location from_loc;

    osmium::unsigned_object_id_type vertex_old;

    for ( const osmium::NodeRef& nr : way.nodes() )
      {

        osmium::unsigned_object_id_type vertex = nr.positive_ref();

        way2nodes[way.id()].push_back ( vertex );

        try
          {

            vert.get ( vertex );

          }
        catch ( std::exception& e )
          {

            vert.set ( vertex, 1 );

            ++unique_node_counter;

            //waynode_locations.set ( vertex, nr.location() );
            waynode_locations[vertex] = nr.location();

          }

        if ( node_counter > 0 )
          {

            if ( !edge ( vertex_old, vertex ) )
              {

                alist[vertex_old].push_back ( vertex );

                double edge_length = distance ( vertex_old, vertex );

                palist[vertex_old].push_back ( edge_length / 3.0 );

                if ( edge_length>max_edge_length )
                  max_edge_length = edge_length;

                mean_edge_length += edge_length;

                ++m_estimator;
                ++cedges;


              }
            else
              ++edge_multiplicity;

            if ( !onewayf )
              {

                if ( !edge ( vertex, vertex_old ) )
                  {

                    alist[vertex].push_back ( vertex_old );

                    double edge_length = distance ( vertex_old, vertex );

                    palist[vertex].push_back ( edge_length / 3.0 );

                    if ( edge_length>max_edge_length )
                      max_edge_length = edge_length;

                    mean_edge_length += edge_length;

                    ++m_estimator;
                    ++cedges;


                  }
                else
                  ++edge_multiplicity;

              }

          }

        vertex_old = vertex;

        ++node_counter;
      }

    sum_highhway_nodes += node_counter;
    sum_unique_highhway_nodes  += unique_node_counter;

  }
	void feed_way(const osmium::Way& way) {
		try {
			const char* interpolation = way.tags().get_value_by_key("addr:interpolation");

			if (interpolation) {

				std::unique_ptr<OGRLineString> ogr_linestring = m_factory.create_linestring(way);

				OGRFeature* feature = OGRFeature::CreateFeature(m_layer->GetLayerDefn());

				const osmium::object_id_type first_node_id = m_geometry_helper.get_first_node_id(way);
				const osmium::object_id_type last_node_id  = m_geometry_helper.get_last_node_id(way);

				feature->SetGeometry(ogr_linestring.get());
				feature->SetField("way_id", static_cast<double>(way.id())); //TODO: node.id() is of type int64_t. is this ok?
				feature->SetField("typename", interpolation);
				feature->SetField("firstid",  static_cast<double>(first_node_id)); //TODO: node.id() is of type int64_t. is cast do double ok?
				feature->SetField("lastid",   static_cast<double>(last_node_id)); //TODO: node.id() is of type int64_t. is cast do double ok?
				feature->SetField("lastchange", way.timestamp().to_iso().c_str());

				AltTagList first_taglist = m_addr_interpolation_node_map->get(first_node_id);
				AltTagList last_taglist  = m_addr_interpolation_node_map->get(last_node_id);

				std::string first_node_housenumber = first_taglist.get_value_by_key(std::string("addr:housenumber"));
				std::string last_node_housenumber  = last_taglist.get_value_by_key(std::string("addr:housenumber"));

				unsigned int first;
				unsigned int last;

				if (first_node_housenumber != "") {
					feature->SetField("firstno", first_node_housenumber.c_str());
					first = atoi(first_node_housenumber.c_str());
				} else {
					first = 0;
				}

				if (last_node_housenumber != "") {
					feature->SetField("lastno",  last_node_housenumber.c_str());
					last  = atoi(last_node_housenumber.c_str());
				} else {
					last = 0;
				}


				if (!(!strcmp(interpolation,"all") || !strcmp(interpolation,"even") || !strcmp(interpolation,"odd"))) { // TODO: add support for 'alphabetic'
					feature->SetField("error", "unknown interpolation type");
				} else if (
						first == 0 ||
						last  == 0 ||
						first_node_housenumber.length() != floor(log10(first))+1 || // make sure 123%& is not recognized as 123
						 last_node_housenumber.length() != floor(log10(last) )+1    //
					) {
					feature->SetField("error", "endpoint hast wrong format");
				} else 	if (abs(first-last) > 1000) {
					feature->SetField("error", "range too large");
				} else if (((!strcmp(interpolation,"even") || !strcmp(interpolation,"odd")) && abs(first-last)==2) ||
							(!strcmp(interpolation,"all")                                   && abs(first-last)==1) ) {
					feature->SetField("error", "needless interpolation");
				} else if (!strcmp(interpolation,"even") && ( first%2==1 || last%2==1 )) {
					feature->SetField("error", "interpolation even but number odd");
				} else if (!strcmp(interpolation,"odd") && ( first%2==0 || last%2==0 )) {
					feature->SetField("error", "interpolation odd but number even");
				} else if (
					(first_taglist.get_value_by_key(std::string("addr:street"))   != last_taglist.get_value_by_key(std::string("addr:street")))   ||
					(first_taglist.get_value_by_key(std::string("addr:postcode")) != last_taglist.get_value_by_key(std::string("addr:postcode"))) ||
					(first_taglist.get_value_by_key(std::string("addr:city"))     != last_taglist.get_value_by_key(std::string("addr:city")))     ||
					(first_taglist.get_value_by_key(std::string("addr:country"))  != last_taglist.get_value_by_key(std::string("addr:country")))  ||
					(first_taglist.get_value_by_key(std::string("addr:full"))     != last_taglist.get_value_by_key(std::string("addr:full")))     ||
					(first_taglist.get_value_by_key(std::string("addr:place"))    != last_taglist.get_value_by_key(std::string("addr:place"))) ) {

					feature->SetField("error", "different tags on endpoints");
				} else if ( // no interpolation error
						(!strcmp(interpolation, "all")) ||
						(!strcmp(interpolation, "odd")) ||
						(!strcmp(interpolation, "even")) ) {
					double length = ogr_linestring.get()->get_Length();
					int increment;
					if (strcmp(interpolation, "all")) {
						increment = 2;
					} else {
						increment = 1;
					}
					double fraction;
					unsigned int lower, upper;
					if (first < last) {
						fraction = 1/static_cast<double>(last-first);
						lower = first;
						upper = last;
					} else {
						fraction = 1/static_cast<double>(first-last);
						increment *= -1;
						lower = last;
						upper = first;
					}

					for (unsigned int nr=first+increment; nr<upper && nr>lower; nr+=increment) {
						std::unique_ptr<OGRPoint> point (new OGRPoint);
						if (increment > 0) {
							ogr_linestring.get()->Value((nr-lower)*fraction*length, point.get());
						} else {
							ogr_linestring.get()->Value((1-((nr-lower)*fraction))*length, point.get());
						}

						std::string road_id("");

						m_clpp.process_interpolated_node(
								*(point.get()),
								road_id,
								first_taglist.get_value_by_key(std::string("addr:street"))
						);

						m_nwa_writer.process_interpolated_node(
								*(point.get()),
								nr,
								first_taglist.get_value_by_key(std::string("addr:street")),
								first_taglist.get_value_by_key(std::string("addr:postcode")),
								first_taglist.get_value_by_key(std::string("addr:city")),
								first_taglist.get_value_by_key(std::string("addr:country")),
								first_taglist.get_value_by_key(std::string("addr:full")),
								first_taglist.get_value_by_key(std::string("addr:place")),
								road_id
						);
					}
				}

				create_feature(feature);

			}


		} catch (osmium::geom::geometry_error& e) {
			catch_geometry_error(e, way);
		}
	}
 // If the way has a "highway" tag, find its length and add it to the
 // overall length.
 void way(const osmium::Way& way) {
     const char* highway = way.tags()["highway"];
     if (highway) {
         length += osmium::geom::haversine::distance(way.nodes());
     }
 }
	void feed_way(const osmium::Way& way) {
		try {
			const char* street             = way.tags().get_value_by_key("addr:street");
			const char* housenumber        = way.tags().get_value_by_key("addr:housenumber");
			const char* full               = way.tags().get_value_by_key("addr:full");
			const char* conscriptionnumber = way.tags().get_value_by_key("addr:conscriptionnumber");
			const char* housename          = way.tags().get_value_by_key("addr:housename");
			const char* place              = way.tags().get_value_by_key("addr:place");
			const char* postcode           = way.tags().get_value_by_key("addr:postcode");
			const char* flats              = way.tags().get_value_by_key("addr:flats");
			const char* door               = way.tags().get_value_by_key("addr:door");
			const char* unit               = way.tags().get_value_by_key("addr:unit");
			const char* floor              = way.tags().get_value_by_key("addr:floor");
			const char* city               = way.tags().get_value_by_key("addr:city");
			const char* country            = way.tags().get_value_by_key("addr:country");
			const char* hamlet             = way.tags().get_value_by_key("addr:hamlet");
			const char* suburb             = way.tags().get_value_by_key("addr:suburb");
			const char* district           = way.tags().get_value_by_key("addr:district");
			const char* subdistrict        = way.tags().get_value_by_key("addr:subdistrict");
			const char* province           = way.tags().get_value_by_key("addr:province");
			const char* region             = way.tags().get_value_by_key("addr:region");
			const char* state              = way.tags().get_value_by_key("addr:state");

			if (!way.is_closed() && (street || housenumber || full ||
					conscriptionnumber || housename || place || postcode ||
					flats || door || unit || floor || city || country ||
					hamlet || suburb || district || subdistrict || province ||
					region || state)) {

				std::unique_ptr<OGRLineString> ogr_linestring = m_factory.create_linestring(way);
				OGRFeature* const feature = OGRFeature::CreateFeature(m_layer->GetLayerDefn());

				feature->SetGeometryDirectly(static_cast<OGRGeometry*>(ogr_linestring.release()));
				feature->SetField("way_id", static_cast<double>(way.id())); //TODO: node.id() is of type int64_t. is this ok?
				feature->SetField("lastchange", way.timestamp().to_iso().c_str());

				create_feature(feature);
			}

		} catch (osmium::geometry_error& e) {
			catch_geometry_error(e, way);
		}
	}
Esempio n. 16
0
  void way ( osmium::Way& way )
  {

    const char* highway = way.tags() ["highway"];         
    if ( !highway )                                     
      return;                                             
                                                          // http://wiki.openstreetmap.org/wiki/Key:highway
    if ( !strcmp ( highway, "footway" )                   
         || !strcmp ( highway, "cycleway" )               
         || !strcmp ( highway, "bridleway" )
         || !strcmp ( highway, "steps" )
         || !strcmp ( highway, "pedestrian")
         || !strcmp ( highway, "construction" ) )
      return;

    double dist = getNodeDistance(way);                         //inicializáljuk a sebességét az utaknak, amit egy külön függvényben
  //  std::cout<<speed;                                   //írtunk meg,hogy melyik úthoz milyen sebesség tartozik.

    onewayf = false;
    const char* oneway = way.tags() ["oneway"];           
    if ( oneway )
      {
        onewayf = true;                                   
        ++onewayc;                                        //oneway counter
      }

    ++nOSM_ways;

    double way_length = osmium::geom::haversine::distance ( way.nodes() );
    sum_highhway_length += way_length;

    int node_counter {0};
    int unique_node_counter {0};
    osmium::Location from_loc;

    osmium::unsigned_object_id_type vertex_old;     

    for ( const osmium::NodeRef& nr : way.nodes() )
      {

        osmium::unsigned_object_id_type vertex = nr.positive_ref(); //Get absolute value of the reference ID of this NodeRef.   

        way2nodes[way.id()].push_back ( vertex );     //Get ID of this object with way.id() and push the actual vertex to their vector

        try
          {

            vert.get ( vertex );                //Retrieve value by id. Does not check for overflow or empty fields. 

          }
        catch ( std::exception& e )
          {

            vert.set ( vertex, 1 );         //Set the field with id to value. 

            ++unique_node_counter;

            //waynode_locations.set ( vertex, nr.location() );
            waynode_locations[vertex] = nr.location();    //Get location of this NodeRef. 

          }

        if ( node_counter > 0 )     
          {

            if ( !edge ( vertex_old, vertex ) )   
              {

                alist[vertex_old].push_back ( vertex );

                double edge_length = distance ( vertex_old, vertex );

                palist[vertex_old].push_back ( edge_length / dist );

                if ( edge_length>max_edge_length )
                  max_edge_length = edge_length;

                mean_edge_length += edge_length;

                ++m_estimator;
                ++cedges;


              }
            else
              ++edge_multiplicity;

            if ( !onewayf )
              {

                if ( !edge ( vertex, vertex_old ) )
                  {

                    alist[vertex].push_back ( vertex_old );         //

                    double edge_length = distance ( vertex_old, vertex );

                    palist[vertex].push_back ( edge_length / dist );

                    if ( edge_length>max_edge_length )
                      max_edge_length = edge_length;

                    mean_edge_length += edge_length;

                    ++m_estimator;
                    ++cedges;


                  }
                else
                  ++edge_multiplicity;

              }

          }

        vertex_old = vertex;

        ++node_counter;
      }

    sum_highhway_nodes += node_counter;
    sum_unique_highhway_nodes  += unique_node_counter;

  }
Esempio n. 17
0
	void feed_way(const osmium::Way& way) {
		try {
			const char* interpolation = way.tags().get_value_by_key("addr:interpolation");

			if (interpolation) {

				std::unique_ptr<OGRLineString> ogr_linestring = m_factory.create_linestring(way);

				OGRFeature* feature = OGRFeature::CreateFeature(m_layer->GetLayerDefn());

				const osmium::object_id_type first_node_id = m_geometry_helper.get_first_node_id(way);
				const osmium::object_id_type last_node_id  = m_geometry_helper.get_last_node_id(way);

				feature->SetGeometry(ogr_linestring.get());
				feature->SetField("way_id", static_cast<double>(way.id())); //TODO: node.id() is of type int64_t. is this ok?
				feature->SetField("typename", interpolation);
				feature->SetField("firstid",  static_cast<double>(first_node_id)); //TODO: node.id() is of type int64_t. is cast do double ok?
				feature->SetField("lastid",   static_cast<double>(last_node_id)); //TODO: node.id() is of type int64_t. is cast do double ok?
				feature->SetField("lastchange", way.timestamp().to_iso().c_str());

				AltTagList first_taglist =
						m_addr_interpolation_node_map->get(first_node_id);
				AltTagList last_taglist  =
						m_addr_interpolation_node_map->get(last_node_id);

				// the raw expression given in the first addr:housenumber= entry
				std::string first_raw =
						first_taglist.get_value_by_key("addr:housenumber");

				// the raw expression given in the last addr:housenumber= entry
				std::string last_raw  =
						last_taglist.get_value_by_key("addr:housenumber");

				unsigned int first;
				unsigned int last;
				std::string first_numeric; // the numeric part of the first housenumber
				std::string last_numeric;  // the numeric part of the last housenumber

				bool is_alphabetic_ip_correct = false;

				if (first_raw != "") {
					feature->SetField("firstno", first_raw.c_str());
					first = atoi(first_raw.c_str());
				} else {
					first = 0;
				}

				if (last_raw != "") {
					feature->SetField("lastno",  last_raw.c_str());
					last  = atoi(last_raw.c_str());
				} else {
					last = 0;
				}

				if (!strcmp(interpolation, "alphabetic") &&
						// second last characters are numbers?
						!isalpha(first_raw[first_raw.length()-2]) &&
						!isalpha(last_raw[last_raw.length()-2])){

					// last characters are letters?
					if (isalpha(first_raw[first_raw.length()-1]) &&
							isalpha(last_raw[last_raw.length()-1])) {

						first_numeric = std::string(first_raw.begin(), first_raw.end() - 1);
						last_numeric  = std::string(last_raw.begin(),  last_raw.end()  - 1);

						if (first_numeric == last_numeric) {
							first = first_raw[first_raw.length() - 1];
							last = last_raw[last_raw.length() - 1];
							is_alphabetic_ip_correct = true;
						} else {
							is_alphabetic_ip_correct = false;
							feature->SetField("error", "numeric parts of housenumbers not identical");
						}

					} else {
						is_alphabetic_ip_correct = false;
						feature->SetField("error", "no alphabetic part in addr:housenumber");
					}
				}

				if (!(
						!strcmp(interpolation, "all")  ||
						!strcmp(interpolation, "even") ||
						!strcmp(interpolation, "odd")  ||
						!strcmp(interpolation, "alphabetic"))) {

					feature->SetField("error", "unknown interpolation type");

				} else if (
						strcmp(interpolation, "alphabetic") && // don't overwrite more precise error messages set before
						(first == 0 ||
						 last  == 0 ||
						 first_raw.length() != floor(log10(first))+1 || // make sure 123%& is not recognized as 123
						  last_raw.length() != floor(log10(last) )+1    //
						)) {

					feature->SetField("error", "endpoint has wrong format");

				} else if (abs_diff(first,last) > 1000) {
					feature->SetField("error", "range too large");

				} else if (((!strcmp(interpolation,"even") || !strcmp(interpolation,"odd")) && abs_diff(first,last)==2) ||
							(!strcmp(interpolation,"all")                                   && abs_diff(first,last)==1) ) {
					feature->SetField("error", "needless interpolation");

				} else if (!strcmp(interpolation,"even") && ( first%2==1 || last%2==1 )) {
					feature->SetField("error", "interpolation even but number odd");

				} else if (!strcmp(interpolation,"odd") && ( first%2==0 || last%2==0 )) {
					feature->SetField("error", "interpolation odd but number even");

				} else if (
					(first_taglist.get_value_by_key("addr:street")   != last_taglist.get_value_by_key("addr:street"))   ||
					(first_taglist.get_value_by_key("addr:postcode") != last_taglist.get_value_by_key("addr:postcode")) ||
					(first_taglist.get_value_by_key("addr:city")     != last_taglist.get_value_by_key("addr:city"))     ||
					(first_taglist.get_value_by_key("addr:country")  != last_taglist.get_value_by_key("addr:country"))  ||
					(first_taglist.get_value_by_key("addr:full")     != last_taglist.get_value_by_key("addr:full"))     ||
					(first_taglist.get_value_by_key("addr:place")    != last_taglist.get_value_by_key("addr:place")) ) {
					feature->SetField("error", "different tags on endpoints");
				} else if (way.is_closed()) {
				    feature->SetField("error", "interpolation is a closed way");
				} else if ( // no interpolation error
						(!strcmp(interpolation, "all")) ||
						(!strcmp(interpolation, "odd")) ||
						(!strcmp(interpolation, "even")) ||
						(is_alphabetic_ip_correct == true)) {
					double length = ogr_linestring.get()->get_Length();
					int increment;

					if (strcmp(interpolation, "all") && strcmp(interpolation, "alphabetic")) {
						increment = 2; // even , odd
					} else {
						increment = 1; //all , alphabetic
					}

					double fraction;
					unsigned int lower, upper;

					
					if (first < last) {
						fraction = 1/static_cast<double>(last-first);
						lower = first;
						upper = last;
					} else {
						fraction = 1/static_cast<double>(first-last);
						increment *= -1;
						lower = last;
						upper = first;
					}
					
					for (unsigned int nr=first+increment; nr<upper && nr>lower; nr+=increment) {
						std::unique_ptr<OGRPoint> point (new OGRPoint);
						if (increment > 0) {
							ogr_linestring.get()->Value((nr-lower)*fraction*length, point.get());
						} else {
							ogr_linestring.get()->Value((1-((nr-lower)*fraction))*length, point.get());
						}

						std::string road_id("");
						std::string nrstr;
						
						if(strcmp(interpolation, "alphabetic")) {
							nrstr = std::to_string(nr);
						} else { // is alphabetic
							// std::string strend = printf("%d", nr);
							nrstr = first_numeric + static_cast<char>(nr);
						}

						m_clpp.process_interpolated_node( // osmi_addresses_connection_line 
								*(point.get()),
								road_id,
								first_taglist.get_value_by_key("addr:street")
						);
						m_nwa_writer.process_interpolated_node( //osmi_addresses_nodes_with_addresses
							*(point.get()),
								nrstr,
								//nr,
								//std::to_string(nr),
								first_taglist.get_value_by_key("addr:street"),
								first_taglist.get_value_by_key("addr:postcode"),
								first_taglist.get_value_by_key("addr:city"),
								first_taglist.get_value_by_key("addr:country"),
								first_taglist.get_value_by_key("addr:full"),
								first_taglist.get_value_by_key("addr:place"),
								road_id
						);
					}
				}

				create_feature(feature);

			}


		} catch (osmium::geometry_error& e) {
			catch_geometry_error(e, way);
		}
	}
    void way(const osmium::Way& way)
    {
        const char* inter = way.tags().get_value_by_key("addr:interpolation");
        if (inter)
        {
            interpolation_count ++;
            osmium::unsigned_object_id_type fromnode = way.nodes().front().ref();
            osmium::unsigned_object_id_type tonode = way.nodes().back().ref();
            uint16_t fromhouse = housenumberMap[fromnode];
            uint16_t tohouse = housenumberMap[tonode];

            // back out if we don't have both house numbers
            if (!(fromhouse && tohouse)) 
            {
                interpolation_error++;
                if (debug)
                {

                    if (!fromhouse) std::cerr << "interpolation way " << way.id() << " references node " << fromnode << " which has no addr:housenumber" << std::endl;
                    if (!tohouse) std::cerr << "interpolation way " << way.id() << " references node " << tonode << " which has no addr:housenumber" << std::endl;
                }
                return;
            }

            // swap if range is backwards
            if (tohouse < fromhouse) 
            {
                fromhouse = tohouse;
                tohouse = housenumberMap[fromnode];
            }

            if (!strcmp(inter, "even"))
            {
                if ((fromhouse %2 == 1) || (tohouse %2 == 1))
                {
                    if (debug)
                    {
                        if (fromhouse%2==1) std::cerr << "interpolation way " << way.id() << " (addr:interpolation=even) references node " << fromnode << " which has an odd house number of " << fromhouse << std::endl;
                        if (tohouse%2==1) std::cerr << "interpolation way " << way.id() << " (addr:interpolation=even) references node " << tonode << " which has an odd house number of " << tohouse << std::endl;
                    }
                    interpolation_error++;
                    return;
                }
                numbers_through_interpolation += (tohouse - fromhouse) / 2 - 1;
            }
            else if (!strcmp(inter, "odd"))
            {
                if ((fromhouse %2 == 0) || (tohouse %2 == 0))
                {
                    if (debug)
                    {
                        if (fromhouse%2==1) std::cerr << "interpolation way " << way.id() << " (addr:interpolation=odd) references node " << fromnode << " which has an even house number of " << fromhouse << std::endl;
                        if (tohouse%2==1) std::cerr << "interpolation way " << way.id() << " (addr:interpolation=odd) references node " << tonode << " which has an even house number of " << tohouse << std::endl;
                    }
                    interpolation_error++;
                    return;
                }
                numbers_through_interpolation += (tohouse - fromhouse) / 2 - 1;
            }
            else if (!strcmp(inter, "both") || !strcmp(inter, "all"))
            {
                numbers_through_interpolation += (tohouse - fromhouse) - 1;
            }
            else
            {
                if (debug)
                {
                    std::cerr << "interpolation way " << way.id() << " has invalid interpolation mode '" << inter << "'" << std::endl;
                }
                interpolation_error++;
            }
            // slight error here - if interpolation way contains intermediate nodes with addresses then these are counted twice.
        }
        else
        {
            const char *hno = way.tags().get_value_by_key("addr:housenumber");
            if (hno)
            {
                numbers_ways_overall ++;
                if (way.tags().get_value_by_key("addr:street")) numbers_ways_withstreet ++;
                if (way.tags().get_value_by_key("addr:city")) numbers_ways_withcity ++;
                if (way.tags().get_value_by_key("addr:country")) numbers_ways_withcountry ++;
                if (way.tags().get_value_by_key("addr:postcode"))
                {
                    numbers_ways_withpostcode ++;
                    postcode[way.tags().get_value_by_key("addr:postcode")] = true;
                }
            }
            else
            {
                const char *bdy = way.tags().get_value_by_key("boundary");
                if (bdy && !strcmp(bdy, "postal_code")) 
                {
                    postcode_boundaries++;
                    const char *ref = way.tags().get_value_by_key("ref");
                    if (ref) postcode[ref]=true;
                }
            }
        }
    }