Index: src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java	(revision 2484)
+++ src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java	(working copy)
@@ -49,6 +49,7 @@
 import uk.me.parabola.mkgmap.general.MapRoad;
 import uk.me.parabola.mkgmap.general.MapShape;
 import uk.me.parabola.mkgmap.general.RoadNetwork;
+import uk.me.parabola.mkgmap.osmstyle.housenumber.HousenumberGenerator;
 import uk.me.parabola.mkgmap.reader.osm.CoordPOI;
 import uk.me.parabola.mkgmap.reader.osm.Element;
 import uk.me.parabola.mkgmap.reader.osm.FeatureKind;
@@ -114,6 +115,8 @@
 	
 	private int nextNodeId = 1;
 	
+	private HousenumberGenerator housenumberGenerator;
+	
 	private final Rule wayRules;
 	private final Rule nodeRules;
 	private final Rule lineRules;
@@ -170,6 +173,8 @@
 		nodeRules = style.getNodeRules();
 		lineRules = style.getLineRules();
 		polygonRules = style.getPolygonRules();
+		
+		housenumberGenerator = new HousenumberGenerator();
 
 		ignoreMaxspeeds = props.getProperty("ignore-maxspeeds") != null;
 		driveOnLeft = props.getProperty("drive-on-left") != null;
@@ -205,6 +210,8 @@
 
 		preConvertRules(way);
 
+		housenumberGenerator.addWay(way);
+		
 		Rule rules;
 		if ("polyline".equals(way.getTag("mkgmap:stylefilter")))
 			rules = lineRules;
@@ -257,6 +264,8 @@
 
 		preConvertRules(node);
 
+		housenumberGenerator.addNode(node);
+		
 		nodeRules.resolveType(node, new TypeResult() {
 			public void add(Element el, GType type) {
 				if (type.isContinueSearch()) {
@@ -331,6 +340,9 @@
 		}
 		roads = null;
 		roadTypes = null;
+		
+		housenumberGenerator.generate(lineAdder);
+		
 		Collection<List<RestrictionRelation>> lists = restrictions.values();
 		for (List<RestrictionRelation> l : lists) {
 
@@ -401,6 +413,8 @@
 			return;
 		}
 
+		housenumberGenerator.addRelation(relation);
+
 		// relation rules are not applied here because they are applied
 		// earlier by the RelationStyleHook
 		
@@ -1584,7 +1598,8 @@
 			road.setInternalNodes(hasInternalNodes);
 		}
 
-		lineAdder.add(road);
+		housenumberGenerator.addRoad(road);
+//		lineAdder.add(road);
 
 		if(trailingWay != null)
 			addRoadWithoutLoops(trailingWay, gt);
Index: src/uk/me/parabola/mkgmap/osmstyle/housenumber/HousenumberGenerator.java
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/housenumber/HousenumberGenerator.java	(revision 0)
+++ src/uk/me/parabola/mkgmap/osmstyle/housenumber/HousenumberGenerator.java	(revision 0)
@@ -0,0 +1,302 @@
+package uk.me.parabola.mkgmap.osmstyle.housenumber;
+
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map.Entry;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.imgfmt.app.net.NumberStyle;
+import uk.me.parabola.imgfmt.app.net.Numbers;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.general.LineAdder;
+import uk.me.parabola.mkgmap.general.MapRoad;
+import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.reader.osm.Node;
+import uk.me.parabola.mkgmap.reader.osm.Relation;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+import uk.me.parabola.util.GpxCreator;
+import uk.me.parabola.util.MultiHashMap;
+
+public class HousenumberGenerator {
+
+	private static final Logger log = Logger
+			.getLogger(HousenumberGenerator.class);
+
+	private MultiHashMap<String, MapRoad> roadByNames;
+	private List<MapRoad> roads;
+	private MultiHashMap<String, Element> houseNumbers;
+	
+	
+	
+	public HousenumberGenerator() {
+		this.roadByNames = new MultiHashMap<String,MapRoad>();
+		this.houseNumbers = new MultiHashMap<String,Element>();
+		this.roads = new ArrayList<MapRoad>();
+	}
+
+	private void checkTags(Element e) {
+		if (e.getTag("addr:housenumber") != null && e.getTag("mkgmap:housenumber") == null){
+			e.addTag("mkgmap:housenumber", e.getTag("addr:housenumber"));
+		}
+		if (e.getTag("addr:street") != null && e.getTag("mkgmap:street") == null){
+			e.addTag("mkgmap:street", e.getTag("addr:street"));
+		}
+		
+	}
+	
+	public void addNode(Node n) {
+		checkTags(n);
+		if (n.getTag("mkgmap:housenumber") != null) {
+			String streetname = n.getTag("mkgmap:street");
+			if (streetname != null) {
+				houseNumbers.add(streetname, n);
+			}
+		}
+	}
+	
+	public void addWay(Way w) {
+		checkTags(w);
+		if (w.getTag("mkgmap:housenumber") != null) {
+			String streetname = w.getTag("mkgmap:street");
+			if (streetname != null) {
+				houseNumbers.add(streetname, w);
+			}
+		}
+	}
+	
+	public void addRoad(MapRoad road) {
+		roads.add(road);
+		if (road.getName() != null) {
+			roadByNames.add(road.getName(), road);
+		} 
+	}
+	
+	public void addRelation(Relation r) {
+		// TODO 
+	}
+	
+	public void generate(LineAdder adder) {
+		for (Entry<String, List<Element>> numbers : houseNumbers.entrySet()) {
+			List<MapRoad> possibleRoads = roadByNames.get(numbers.getKey());
+			
+			if (possibleRoads.isEmpty()) {
+				continue;
+			}
+			
+			match(numbers.getKey(), numbers.getValue(), possibleRoads);
+		}
+		
+		for (MapRoad r : roads) {
+			adder.add(r);
+		}
+		
+		houseNumbers.clear();
+		roadByNames.clear();
+		roads.clear();
+	}
+	
+	private void match(String streetname, List<Element> nodes, List<MapRoad> roads) {
+		MultiHashMap<MapRoad, Entry<Integer, Integer>> leftHousenumbers = new MultiHashMap<MapRoad, Entry<Integer, Integer>>();
+		MultiHashMap<MapRoad, Entry<Integer, Integer>> rightHousenumbers = new MultiHashMap<MapRoad, Entry<Integer, Integer>>();
+		
+		for (Element n : nodes) {
+			int number = -1;
+		
+			try {
+				number = Integer.parseInt(n.getTag("mkgmap:housenumber"));
+			} catch (NumberFormatException exp) {
+				continue;
+			}
+			
+			double dClosest = Double.POSITIVE_INFINITY;
+			boolean onLeft = true;
+			MapRoad closestRoad = null;
+			int bestNode = -1;
+
+			for (MapRoad r : roads) {
+				int node = -1;
+				Coord c1 = null;
+				for (Coord c2 : r.getPoints()) {
+					if (c1 != null) {
+						Coord cx = (n instanceof Node ? ((Node)n).getLocation() : ((Way)n).getCofG());
+						double dist = distanceToSegment(c1,c2,cx);
+						if (dist < dClosest) {
+							dClosest = dist;
+							closestRoad = r;
+							onLeft = isLeft(c1, c2, cx);
+							bestNode = node;
+						}
+					}
+					c1 = c2;
+					node++;
+				}
+			}
+			
+			if (closestRoad != null) {
+				MultiHashMap<MapRoad, Entry<Integer, Integer>> sideNumbers = (onLeft ? leftHousenumbers : rightHousenumbers);
+				sideNumbers.add(closestRoad, new AbstractMap.SimpleEntry<Integer, Integer>(number, bestNode));
+			}
+		}
+		
+		// go through all roads and apply the house numbers
+		for (MapRoad r : roads) {
+			List<Entry<Integer, Integer>> leftNumbers = leftHousenumbers.get(r);
+			List<Entry<Integer, Integer>> rightNumbers = rightHousenumbers.get(r);
+			
+			log.info("Housenumbers for",r.getName(),r.getCity());
+			
+			Numbers numbers = new Numbers();
+			numbers.setNodeNumber(0);
+			numbers.setRnodNumber(0);
+			numbers.setLeftNumberStyle(getNumberStyle(leftNumbers));
+			if (numbers.getLeftNumberStyle() != NumberStyle.NONE) {
+				numbers.setLeftStart(getNumber(true, leftNumbers));
+				numbers.setLeftEnd(getNumber(false,leftNumbers));
+			}
+			log.info("Left: ",numbers.getLeftNumberStyle(),"Start:",numbers.getLeftStart(),"End:",numbers.getLeftEnd(), "All: "+leftNumbers);
+			
+			numbers.setRightNumberStyle(getNumberStyle(rightNumbers));
+			if (numbers.getRightNumberStyle() != NumberStyle.NONE) {
+				numbers.setRightStart(getNumber(true,rightNumbers));
+				numbers.setRightEnd(getNumber(false,rightNumbers));
+			}
+			log.info("Right:",numbers.getRightNumberStyle(),"Start:",numbers.getRightStart(),"End:",numbers.getRightEnd(), "All: "+rightNumbers);
+	
+			if (numbers.getLeftNumberStyle() != NumberStyle.NONE || numbers.getRightNumberStyle() != NumberStyle.NONE) {
+				List<Numbers> ns = new ArrayList<Numbers>();
+				ns.add(numbers);
+				r.setNumbers(ns);
+			}
+		}
+	}
+	
+	private int getNumber(boolean start, List<Entry<Integer, Integer>> housenumbers) {
+		List<Integer> bestNumbers = new ArrayList<Integer>();
+		int bestNode = (start ? Integer.MAX_VALUE : Integer.MIN_VALUE);
+		
+		int minNumber = Integer.MAX_VALUE;
+		int maxNumber = Integer.MIN_VALUE;
+		
+		
+		for (Entry<Integer, Integer> n : housenumbers) {
+			if (start && n.getValue() < bestNode) {
+				bestNumbers.clear();
+				bestNode = n.getValue();
+			} else if (start == false && n.getValue() > bestNode) {
+				bestNumbers.clear();
+				bestNode = n.getValue();
+			}
+			
+			if (n.getValue() == bestNode) {
+				bestNumbers.add(n.getKey());
+			}
+			
+			if (n.getKey() < minNumber) {
+				minNumber = n.getKey();
+			}
+			if (n.getKey() > maxNumber) {
+				maxNumber = n.getKey();
+			}
+		}
+		
+		if (bestNumbers.size() == 1) {
+			return bestNumbers.get(0);
+		} else {
+			int minBest = Collections.min(bestNumbers);
+			int maxBest = Collections.max(bestNumbers);
+			
+			if (start) {
+			if (minBest == minNumber) 
+				return minBest;
+				
+			if (maxBest == maxNumber) 
+				return maxBest;
+			} else {
+				if (maxBest == maxNumber) 
+					return maxBest;
+
+				if (minBest == minNumber) 
+					return minBest;
+			}
+			
+			if (start) 
+				return minBest;
+			else
+				return maxBest;
+			
+		}
+	}
+	
+	private NumberStyle getNumberStyle(List<Entry<Integer, Integer>> housenumbers) {
+		if (housenumbers.isEmpty()) {
+			return NumberStyle.NONE;
+		}
+		boolean even = false;
+		boolean odd = false;
+		for (Entry<Integer, Integer> n : housenumbers) {
+			if (n.getKey() % 2 == 0) {
+				even = true;
+			} else {
+				odd = true;
+			}
+			
+			if (even && odd) {
+				return NumberStyle.BOTH;
+			}
+		}
+		
+		if (even) {
+			return NumberStyle.EVEN;
+		} else {
+			return NumberStyle.ODD;
+		}
+	}
+	
+	
+	int gid = 0;
+	public boolean isLeft(Coord spoint1, Coord spoint2, Coord point) {
+		
+		boolean left =  ((spoint2.getLongitude() - spoint1.getLongitude())
+				* (point.getLatitude() - spoint1.getLatitude()) - (spoint2.getLatitude() - spoint1
+				.getLatitude()) * (point.getLongitude() - spoint1.getLongitude())) > 0;
+				if (gid < 100) {
+				ArrayList<Coord> l = new ArrayList<Coord>(2);
+				l.add(spoint1);
+				l.add(spoint2);
+				GpxCreator.createGpx(GpxCreator.getGpxBaseName()+(left?"l_":"r_")+(++gid), l, Collections.singletonList(point));
+				}
+				return left;
+	}
+	
+	/**
+	 * Calculates the distance to the given segment in meter.
+	 * @param spoint1 segment point 1
+	 * @param spoint2 segment point 2
+	 * @param point point
+	 * @return the distance in meter
+	 */
+	private double distanceToSegment(Coord spoint1, Coord spoint2, Coord point) {
+
+		double dx = spoint2.getLongitude() - spoint1.getLongitude();
+		double dy = spoint2.getLatitude() - spoint1.getLatitude();
+
+		if ((dx == 0) && (dy == 0)) {
+			return spoint1.distance(point);
+		}
+
+		double frac = ((point.getLongitude() - spoint1.getLongitude()) * dx + (point
+				.getLatitude() - spoint1.getLatitude()) * dy)
+				/ (dx * dx + dy * dy);
+
+		if (frac < 0) {
+			return spoint1.distance(point);
+		} else if (frac > 1) {
+			return spoint2.distance(point);
+		} else {
+			return spoint1.makeBetweenPoint(spoint2, frac).distance(point);
+		}
+
+	}
+}
