Index: src/uk/me/parabola/imgfmt/app/Coord.java
===================================================================
--- src/uk/me/parabola/imgfmt/app/Coord.java	(revision 4400)
+++ src/uk/me/parabola/imgfmt/app/Coord.java	(working copy)
@@ -880,5 +880,17 @@
 		double newLon = lon + Math.atan2(Math.sin(bearing) * Math.sin(angularDistance) * Math.cos(lat), Math.cos(angularDistance) - Math.sin(lat) * Math.sin(newLat));
 		return new Coord(Math.toDegrees(newLat), Math.toDegrees(newLon));
 	}
-	
+
+	/**
+	 * Calculate if this point lies on the left or right of the line through the given points.
+	 * @param p0 first point
+	 * @param p2 second point
+	 * @return positive value if on left, negative value if on the right, 0 if on the line
+	 */
+	public long isLeft(final Coord p1, final Coord p2) {
+		long p1Lat = p1.getHighPrecLat();
+		long p1Lon = p1.getHighPrecLon();
+		return ((long) p2.getHighPrecLon() - p1Lon) * ((long) this.getHighPrecLat() - p1Lat)
+				- ((long) p2.getHighPrecLat() - p1Lat) * ((long) this.getHighPrecLon() - p1Lon);
+	}
 }
Index: src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java	(revision 4400)
+++ src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java	(working copy)
@@ -61,7 +61,6 @@
 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.ElementSaver;
 import uk.me.parabola.mkgmap.reader.osm.FakeIdGenerator;
 import uk.me.parabola.mkgmap.reader.osm.FeatureKind;
 import uk.me.parabola.mkgmap.reader.osm.GType;
Index: src/uk/me/parabola/mkgmap/osmstyle/function/IsInFunction.java
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/function/IsInFunction.java	(revision 4403)
+++ src/uk/me/parabola/mkgmap/osmstyle/function/IsInFunction.java	(working copy)
@@ -1,7 +1,22 @@
+/*
+ * Copyright (C) 2019.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 or
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
 package uk.me.parabola.mkgmap.osmstyle.function;
 
+import java.awt.geom.Line2D;
 import java.awt.geom.Path2D;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
@@ -11,11 +26,32 @@
 import uk.me.parabola.imgfmt.app.Coord;
 import uk.me.parabola.log.Logger;
 import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.reader.osm.MultiPolygonRelation;
 import uk.me.parabola.mkgmap.reader.osm.Node;
 import uk.me.parabola.mkgmap.reader.osm.Way;
+import uk.me.parabola.mkgmap.reader.osm.boundary.BoundaryUtil;
 import uk.me.parabola.util.ElementQuadTree;
+import uk.me.parabola.util.GpxCreator;
 import uk.me.parabola.util.Java2DConverter;
 
+/**
+ * Implements insideness tests for points, polyline and polygon.  
+ * We distinguish 3 cases for points:
+ * <br> 1: the point is outside the polygon
+ * <br> 2: the point is on the boundary of the polygon (or very close to it)
+ * <br> 3: the point in inside the polygon
+ * 
+ * We distinguish 6 cases for lines:
+ * <br> 1: all of the line is outside the polygon
+ * <br> 2: some of the line is outside and the rest touches or runs along the polygon edge
+ * <br> 3: all of the line runs along the polygon edge
+ * <br> 4: some of the line is inside and the rest touches or runs along.
+ * <br> 5: all of the line is inside the polygon
+ * <br> 6: some is inside and some outside the polygon. Obviously some point is on the polygon edge but we don't care if runs along the edge.
+
+ * @author Gerd Petermann
+ *
+ */
 public class IsInFunction extends StyleFunction {
 	private static final Logger log = Logger.getLogger(IsInFunction.class);
 
@@ -35,13 +71,6 @@
 		if (qt != null && !qt.isEmpty()) {
 			Set<Element> polygons;
 			Area bbox;
-			/**
-			 * TODO: calculate bbox of element, 
-			 * retrieve closed ways which match the tag given with parameters
-			 * use spatial index if that improves performance
-			 * calculate insideness  
-			 */
-			
 			// this is just some test code to give different answers...
 			if (el instanceof Node) {
 				Coord c = ((Node) el).getLocation();
@@ -49,7 +78,7 @@
 				polygons = qt.get(bbox);
 				for (Element e : polygons) {
 					Way poly = (Way) e;
-					if (Java2DConverter.createHighPrecPolygon(poly.getPoints()).contains(c.getHighPrecLon(), c.getHighPrecLat())) {
+					if (BoundaryUtil.insidePolygon(c, poly.getPoints())) {
 						answer = true;
 						break;
 					}
@@ -59,7 +88,7 @@
 				if (w.isComplete()) {
 					bbox = Area.getBBox(w.getPoints());
 					polygons = qt.get(bbox);
-					if (!polygons.isEmpty()) {
+					if (polygons.size() > 1) {
 						// combine all polygons which intersect the bbox of the element if possible
 						Path2D.Double path = new Path2D.Double();
 						for (Element e : polygons) {
@@ -68,7 +97,16 @@
 							path.append(polyPath, false);
 						}
 						java.awt.geom.Area polygonsArea = new java.awt.geom.Area(path);
-						List<Coord> intersections = new ArrayList<>();
+						
+						double x1 = (double) w.getFirstPoint().getHighPrecLon() / (1 << Coord.DELTA_SHIFT);
+						double y1 = (double) w.getFirstPoint().getHighPrecLat() / (1 << Coord.DELTA_SHIFT);
+						boolean res0 = polygonsArea.contains(x1, y1);
+						if (res0 && "any".equals(params.get(2)))
+							return String.valueOf(true);
+						if (!res0 && "all".equals(params.get(2)))
+							return String.valueOf(false);
+						
+						List<Coord> boundaries = new ArrayList<>();
 						//TODO: need to know if this function is used in lines or polygons rules
 						List<List<Coord>> mergedShapes = Java2DConverter.areaToShapes(polygonsArea);
 						// brute force search for intersections between way segments
@@ -81,18 +119,13 @@
 									Coord p22 = w.getPoints().get(k + 1);
 									Coord x = Utils.getSegmentSegmentIntersection(p11, p12, p21, p22);
 									if (x != null) {
-										intersections.add(x);
 										// intersection found, maybe they are crossing, maybe they are touching 
-										double x1 = (double)p21.getHighPrecLon()/ (1<<Coord.DELTA_SHIFT); 
-										double y1 = (double)p21.getHighPrecLat() / (1<<Coord.DELTA_SHIFT); 
-										double x2 = (double)p22.getHighPrecLon()/ (1<<Coord.DELTA_SHIFT); 
-										double y2 = (double)p22.getHighPrecLat() / (1<<Coord.DELTA_SHIFT); 
-
-										// TODO: replace area.contains() 
-										// with method that returns only
-										// true for nodes which are inside
-										// and not on the boundary
-										if (polygonsArea.contains(x1,y1) != polygonsArea.contains(x2,y2)) {
+										if (x.distance(p21) < 0.01) {
+											boundaries.add(p21);
+										} else if (x.distance(p22) < 0.01) {
+											boundaries.add(p22);
+										} else {
+											// real intersection found
 											if ("any".equals(params.get(2)))
 												return String.valueOf(true);
 											if ("all".equals(params.get(2)))
@@ -102,11 +135,9 @@
 								}
 							}
 						}
-						// found no intersection, way is either inside or outside, use result for 1st point
-						// TODO: make sure that tested node is not on boundary
-						double x1 = (double) w.getFirstPoint().getHighPrecLon() / (1 << Coord.DELTA_SHIFT);
-						double y1 = (double) w.getFirstPoint().getHighPrecLat() / (1 << Coord.DELTA_SHIFT);
-						answer = polygonsArea.contains(x1, y1);
+						answer = res0;
+					} else if (polygons.size() == 1) {
+						answer = checkWayAgainsShape(w, ((Way) polygons.iterator().next()).getPoints(), params.get(2));
 					}
 				}
 			}
@@ -117,9 +148,49 @@
 		return String.valueOf(answer);
 	}
 
+	private enum Status {
+		IN , ON , OUT;
+	}
+
 	@Override
 	public String value(Element el) {
-		return calcImpl(el);
+//		if ("b5".equals(el.getTag("name"))) {
+//			long dd = 4;
+//		}
+		String res = calcImpl(el);
+		String expected = el.getTag("expected");
+		if (expected != null && "landuse".equals(params.get(0)) && "residential".equals(params.get(1))) {
+			if (el instanceof Way) {
+				Way w2 = (Way) el.copy();
+				Collections.reverse(w2.getPoints());
+				String res2 = calcImpl(w2);
+				if (!res.equals(res2)) {
+					log.error(el.getTag("name"), res, res2, params,"oops reverse");
+				}
+			}
+			boolean b1 = Boolean.parseBoolean(res);
+			boolean in = "in".equals(expected);
+			boolean straddle = "straddle".equals(expected);
+			boolean out = "out".equals(expected);
+			if (b1 && out) {
+				log.error(el.getTag("name"), res, params,"oops");
+			}
+			if ("any".equals(params.get(2))) {
+				if (!b1 && (in || straddle)) {
+					log.error(el.getTag("name"), res, params,"oops");
+				}
+			}
+			if ("all".equals(params.get(2))) {
+				if (!b1 && in) {
+					log.error(el.getTag("name"), res, params,"oops");
+				}
+				if (b1 && (straddle)) {
+					log.error(el.getTag("name"), res, params,"oops");
+				}
+			}
+		}
+//		log.error(el, res, params);
+		return res;
 	}
     
 	@Override
@@ -152,7 +223,8 @@
 	public void augmentWith(uk.me.parabola.mkgmap.reader.osm.ElementSaver elementSaver) {
 		List<Element> matchingPolygons = new ArrayList<>();
 		for (Way w : elementSaver.getWays().values()) {
-			if (w.isComplete() && w.hasIdenticalEndPoints()) {
+			if (w.isComplete() && w.hasIdenticalEndPoints()
+					&& !"polyline".equals(w.getTag(MultiPolygonRelation.STYLE_FILTER_TAG))) {
 				String val = w.getTag(params.get(0));
 				if (val != null && val.equals(params.get(1))) {
 					matchingPolygons.add(w);
@@ -163,4 +235,93 @@
 			qt = new ElementQuadTree(elementSaver.getBoundingBox(), matchingPolygons);
 		}
 	}
+	
+	private static boolean checkWayAgainsShape(Way w, List<Coord> shape, String mode) {
+		Status statusFirst = checkPointAgainstShape(w.getFirstPoint(), shape);
+		if (statusFirst == Status.IN && "any".equals(mode))
+			return true;
+		if (statusFirst == Status.OUT  && "all".equals(mode))
+			return false;
+		Status statusLast = checkPointAgainstShape(w.getLastPoint(), shape);
+		if (statusLast == Status.IN && "any".equals(mode))
+			return true;
+		if (statusLast == Status.OUT  && "all".equals(mode))
+			return false;
+		if (statusFirst == Status.ON) {
+			long dd = 4;
+		}
+//		List<Coord> boundaries = new ArrayList<>();
+		final int n = w.getPoints().size();
+		for (int i = 0; i < shape.size() - 1; i++) {
+			Coord p11 = shape.get(i);
+			Coord p12 = shape.get(i + 1);
+//			GpxCreator.createGpx("e:/ld/s", Arrays.asList(p11,p12));
+			for (int k = 0; k < n - 1; k++) {
+				Coord p21 = w.getPoints().get(k);
+				Coord p22 = w.getPoints().get(k + 1);
+//				GpxCreator.createGpx("e:/ld/w", Arrays.asList(p21,p22));
+				
+				Coord x = Utils.getSegmentSegmentIntersection(p11, p12, p21, p22);
+				if (x != null) {
+					// segments have at least one common point 
+					boolean isCrossing = false;
+					if (x.distance(p21) < 0.01) {
+//						boundaries.add(p21);
+						if (k > 0) {
+							long isLeftPrev = w.getPoints().get(k-1).isLeft(p11, p12);
+							long isLeftNext = p22.isLeft(p11, p12);
+							if (isLeftPrev< 0 && isLeftNext > 0 || isLeftPrev > 0 && isLeftNext < 0) {
+								// shape is crossed at p21 or shape is touched
+								// check if previous point of shape is left or right of element segment
+								
+								//TODO: detect touching
+								
+								isCrossing = true;
+							}
+						}
+					} else if (x.distance(p22) < 0.01) {
+//						boundaries.add(p22);
+					} else {
+						isCrossing = true;
+					}
+					if (isCrossing) {
+						// real intersection found 
+						if ("any".equals(mode))
+							return true;
+						if ("all".equals(mode))
+							return false;
+					}
+				}
+			}
+		}
+//		if (!boundaries.isEmpty()) {
+//			//TODO
+//		}
+		// found no intersection
+		if (statusFirst == Status.ON && statusLast == Status.ON) {
+			for (int i = 1; i < n - 1; i++) {
+				Status inner = checkPointAgainstShape(w.getPoints().get(i), shape);
+				if (inner != Status.ON)
+					return inner == Status.IN;
+			}
+			if (n == 2) {
+				Coord pTest = w.getFirstPoint().makeBetweenPoint(w.getLastPoint(), 0.5);
+				return checkPointAgainstShape(pTest, shape) == Status.IN;
+			}
+		}
+		return statusFirst ==  Status.IN || statusLast == Status.IN;
+	}
+
+	private static Status checkPointAgainstShape(Coord p, List<Coord> shape) {
+		boolean res0 = BoundaryUtil.insidePolygon(p, true, shape.toArray(new Coord[0]));
+		Status status = res0 ? Status.IN : Status.OUT;
+		if (status == Status.IN) {
+			// point is in or on
+			boolean res1 = BoundaryUtil.insidePolygon(p, false, shape.toArray(new Coord[0]));
+			if (res0 != res1) {
+				status = Status.ON;
+			}
+		}		
+		return status;
+	}
 }
Index: src/uk/me/parabola/mkgmap/reader/osm/OsmMapDataSource.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/OsmMapDataSource.java	(revision 4400)
+++ src/uk/me/parabola/mkgmap/reader/osm/OsmMapDataSource.java	(working copy)
@@ -258,6 +258,8 @@
 	protected OsmReadingHooks pluginChain(ElementSaver saver, EnhancedProperties props) {
 		List<OsmReadingHooks> plugins = new ArrayList<>();
 		for (OsmReadingHooks p : getPossibleHooks()) {
+			if (p instanceof ResidentialHook && !style.getUsedTags().contains("mkgmap:residential"))
+				continue;
 			if (p.init(saver, props)){
 				plugins.add(p);
 				if (p instanceof RelationStyleHook)
Index: src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryQuadTree.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryQuadTree.java	(revision 4400)
+++ src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryQuadTree.java	(working copy)
@@ -163,22 +163,37 @@
 	 * The returned Tags must not be modified by the caller.   
 	 */
 	public Tags get(Coord co){
-		Tags res = root.get(co/*, "_"*/);
-		if (res == null && bbox.contains(co.getLongitude(),co.getLatitude())){
-			// we did not find the point, probably it lies on a boundary and
-			// the clauses regarding insideness of areas make it "invisible"
-			// try again a few other nearby points 
-			Coord neighbour1 = new Coord(co.getLatitude()-1, co.getLongitude());
-			Coord neighbour2 = new Coord(co.getLatitude()  , co.getLongitude()-1);
-			Coord neighbour3 = new Coord(co.getLatitude()+1, co.getLongitude());
-			Coord neighbour4 = new Coord(co.getLatitude()  , co.getLongitude()+1);
-			res = root.get(neighbour1/*, "_"*/);
-			if (res == null)
-				res = root.get(neighbour2/*, "_"*/);
-			if (res == null)
-				res = root.get(neighbour3/*, "_"*/);
-			if (res == null)
-				res = root.get(neighbour4/*, "_"*/);
+		return get(co, true);
+	}
+	
+	/**
+	 * Return location relevant Tags for the point defined by Coord 
+	 * @param co the point
+	 * @param tryAlsoNearby if true, try also nearby points to circumvent problem in 
+	 * the insideness test of java shapes
+	 * @return a reference to the internal Tags or null if the point was not found. 
+	 * The returned Tags must not be modified by the caller.   
+	 */
+	public Tags get(Coord co, boolean tryAlsoNearby) {
+		Tags res = root.get(co);
+		if (res == null && tryAlsoNearby) {
+			int lonHp = co.getHighPrecLon();
+			int latHp = co.getHighPrecLat();
+			double x = (double) lonHp / (1 << Coord.DELTA_SHIFT);
+			double y = (double) latHp / (1 << Coord.DELTA_SHIFT);
+
+			if ( bbox.contains(x, y)) {
+				// we did not find the point, probably it lies on a boundary and
+				// the clauses regarding insideness of areas make it "invisible"
+				// try again a few other nearby points
+				res = root.get(Coord.makeHighPrecCoord(latHp + 1, lonHp));
+				if (res == null)
+					res = root.get(Coord.makeHighPrecCoord(latHp, lonHp + 1));
+				if (res == null)
+					res = root.get(Coord.makeHighPrecCoord(latHp - 1, lonHp));
+				if (res == null)
+					res = root.get(Coord.makeHighPrecCoord(latHp, lonHp - 1));
+			}
 		}
 		return res;
 	}
@@ -242,14 +257,14 @@
 	/**
 	 * Return boundary names relevant for the point defined by Coord 
 	 * @param co the point
+     * @param onBoundary the value that should be returned if the point is on the boundary
 	 * @return A string with a boundary Id, optionally followed by pairs of admlevel:boundary Id.
 	 * Sample: r1184826;6:r62579;4:r62372;2:r51477  
 	 */
-	public String getBoundaryNames(Coord co){
-		return root.getBoundaryNames(co);
+	public String getBoundaryNames(Coord co, boolean onBoundary) {
+		return root.getBoundaryNames(co, onBoundary);
 	}
 
-
 	/**
 	 * Save the BoundaryQuadTree to an open stream. The format is QUADTREE_DATA_FORMAT.
 	 * @param stream
@@ -326,7 +341,7 @@
 		try {
 			while (true) {
 				String type = inpStream.readUTF();
-				if (type.equals("TAGS")){
+				if ("TAGS".equals(type)){
 					String id = inpStream.readUTF();
 					Tags tags = new Tags();
 					int noOfTags = inpStream.readInt();
@@ -337,7 +352,7 @@
 					}
 					boundaryTags.put(id, tags);
 				}
-				else if (type.equals("AREA")){
+				else if ("AREA".equals(type)){
 					if (isFirstArea){
 						isFirstArea = false;
 						prepareLocationInfo();
@@ -460,30 +475,28 @@
 		/**
 		 * Return boundary names relevant for the point defined by Coord 
 		 * @param co the point
+		 * @param onBoundary the value that should be returned if the point is on the boundary
 		 * @return A string with a boundary Id, optionally followed by pairs of admlevel:boundary Id.
 		 * Sample: r1184826;6:r62579;4:r62372;2:r51477  
 		 */
-		private String getBoundaryNames(Coord co) {
+		private String getBoundaryNames(Coord co, boolean onBoundary) {
 			if (!this.bounds.contains(co))
 				return null;
-			if (isLeaf){
+			if (isLeaf) {
 				if (nodes == null || nodes.isEmpty())
 					return null;
-				int lon = co.getLongitude();
-				int lat = co.getLatitude();
 				for (NodeElem nodeElem : nodes) {
-					if (nodeElem.tagMask > 0 && nodeElem.getArea().contains(lon, lat)) {
+					if (nodeElem.tagMask > 0 && BoundaryUtil.pointInsideArea(co, onBoundary, nodeElem.getArea())) {
 						if (nodeElem.locationDataSrc != null)
 							return nodeElem.boundaryId + ";" + nodeElem.locationDataSrc;
 						return nodeElem.boundaryId;
 					}
 				}
-			}
-			else {
-				for (int i = 0; i < 4; i++){
-					String res = childs[i].getBoundaryNames(co);
-					if (res != null) 
-						return res; 
+			} else {
+				for (int i = 0; i < 4; i++) {
+					String res = childs[i].getBoundaryNames(co, onBoundary);
+					if (res != null)
+						return res;
 				}
 			}
 			return null;
@@ -498,22 +511,19 @@
 		private Tags get(Coord co/*, String treePath*/){
 			if (!this.bounds.contains(co))
 				return null;
-			if (isLeaf){
+			if (isLeaf) {
 				if (nodes == null || nodes.isEmpty())
 					return null;
-				int lon = co.getLongitude();
-				int lat = co.getLatitude();
 				for (NodeElem nodeElem : nodes) {
-					if (nodeElem.tagMask > 0 && nodeElem.getArea().contains(lon, lat)) {
+					if (nodeElem.tagMask > 0 && BoundaryUtil.pointInsideArea(co, true, nodeElem.getArea())) {
 						return nodeElem.locTags;
 					}
 				}
-			}
-			else {
-				for (int i = 0; i < 4; i++){
-					Tags res = childs[i].get(co/*, treePath+i*/);
-					if (res != null) 
-						return res; 
+			} else {
+				for (int i = 0; i < 4; i++) {
+					Tags res = childs[i].get(co/* , treePath+i */);
+					if (res != null)
+						return res;
 				}
 			}
 			return null;
@@ -755,7 +765,7 @@
 			}
 			long t1 = System.currentTimeMillis();
 			if (DEBUG){
-				if (treePath.equals(DEBUG_TREEPATH) || DEBUG_TREEPATH.equals("all")){
+				if (treePath.equals(DEBUG_TREEPATH) || "all".equals(DEBUG_TREEPATH)) {
 					for (NodeElem nodeElem: nodes){
 						nodeElem.saveGPX("start",treePath);
 					}			
@@ -773,7 +783,7 @@
 			for (int i=0; i < nodes.size(); i++){
 				NodeElem toAdd = nodes.get(i);
 				if (DEBUG) {
-					if (treePath.equals(DEBUG_TREEPATH) || DEBUG_TREEPATH.equals("all")) {
+					if (treePath.equals(DEBUG_TREEPATH) || "all".equals(DEBUG_TREEPATH)) {
 						for (NodeElem nodeElem : reworked) {
 							nodeElem.saveGPX("debug" + i, treePath);
 						}
@@ -1375,4 +1385,5 @@
 		Area testArea = new Area(path);
 		return !testArea.isEmpty();
 	}
+
 }
Index: src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryUtil.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryUtil.java	(revision 4400)
+++ src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryUtil.java	(working copy)
@@ -800,4 +800,148 @@
 		}
 		return splits;
 	}
+    /**
+     * Tests if point is inside an area. 
+     * @param point the point to test
+     * @param onBoundary the value that should be returned if the point is on the boundary
+     * @param fullArea a singular area 
+     * @return true if the point is inside polygon.
+     */
+    public static boolean pointInsideArea(Coord point, boolean onBoundary, Area fullArea) {
+    	double x = (double) point.getHighPrecLon() / (1 << Coord.DELTA_SHIFT);
+    	double y = (double) point.getHighPrecLat() / (1 << Coord.DELTA_SHIFT);
+    	Rectangle2D r = fullArea.getBounds2D();
+        double x0 = r.getX();
+        double y0 = r.getY();
+		boolean insideOrOnBounaryOfRect = (x >= x0 && y >= y0 && x <= x0 + r.getWidth() && y <= y0 + r.getHeight());
+		if (!insideOrOnBounaryOfRect) 
+			return false;
+    	List<Area> singularAreas = Java2DConverter.areaToSingularAreas(fullArea);
+    	for (Area area : singularAreas) {
+    		if (pointInsideSingularArea(point, onBoundary, area))
+    			return true;
+    	}
+    	return false;
+    }
+
+    /**
+     * Tests if point is inside or on boundary of an area.
+     * @param point the point to test
+     * @param onBoundary the value that should be returned if the point is on the boundary
+     * @param area a singular area 
+     * @return true if the point is inside polygon.
+     */
+    public static boolean pointInsideSingularArea(Coord point, boolean onBoundary, Area area) {
+    	List<Coord> polygonNodes = Java2DConverter.singularAreaToPoints(area);
+    	if (polygonNodes == null)
+    		return false;
+
+//    	double x = (double) point.getHighPrecLon() / (1 << Coord.DELTA_SHIFT);
+//    	double y = (double) point.getHighPrecLat() / (1 << Coord.DELTA_SHIFT);
+//    	boolean inside2 = area.contains(x, y); //TODO remove
+    	boolean inside3 = insidePolygon(point, onBoundary, polygonNodes.toArray(new Coord[0]));
+//    	if (inside3 ) {
+//    		GpxCreator.createGpx("e:/ld/diff", polygonNodes, Arrays.asList(point));
+//    		long dd = 4;
+//    	}
+    	return inside3;
+    }
+    
+    /**
+     * Check if node is in polygon using winding counter. 
+     * Based on code from Dan Sunday, but allows to define how to handle nodes on boundary.   
+     * @param p the point to test
+     * @param onBoundary the value that should be returned if the point is on the boundary
+     * @param v vector of points describing the polygon
+     * @return true if p is inside the polygon, false if outside, the value of onBoundary if its on the boundary
+     * <p>
+     * Copyright 2000 softSurfer, 2012 Dan Sunday
+     * This code may be freely used and modified for any purpose
+     * providing that this copyright notice is included with it.
+     * SoftSurfer makes no warranty for this code, and cannot be held
+     * liable for any real or imagined damage resulting from its use.
+     * Users of this code must verify correctness for their application.     
+     * See http://geomalgorithms.com/a03-_inclusion.html
+     */
+    public static final boolean insidePolygon (final Coord p, boolean onBoundary, final Coord... v) {
+        final int y = p.getHighPrecLat();
+        final int len = v.length;
+        // the winding number counter
+        int wn = 0;
+        Coord c = v[0], n; // current & next points from vertex array
+       
+		for (int i = 0; ++i < len; c = n) {
+			n = v[i];
+			if (p.highPrecEquals(n)) {
+				return onBoundary;
+			}
+			if (c.getHighPrecLat() <= y) { // starting y <= p.y
+				// an upward crossing and p left of edge:
+				if (n.getHighPrecLat() > y) {
+					long l = p.isLeft(c, n);
+					if (l > 0) {
+						++wn;
+					} else if (l == 0) {
+						return onBoundary; 
+					}
+				}
+
+			} else if (n.getHighPrecLat() <= y) {
+				// a downward crossing and p right of edge.
+				long l = p.isLeft(c, n);
+				if (l < 0) {
+					--wn;
+				} else if (l == 0) {
+					return onBoundary; 
+				}
+			}
+		}
+       
+        return wn != 0; // if 0 point is outside
+    }
+
+    /**
+     * Check if node is in polygon using winding counter. 
+     * @param p the point to test
+     * @param vertex vector of points describing the polygon
+     * @return true if p is inside the polygon, false if outside or on boundary
+     * <p>
+     * Copyright 2000 softSurfer, 2012 Dan Sunday
+     * This code may be freely used and modified for any purpose
+     * providing that this copyright notice is included with it.
+     * SoftSurfer makes no warranty for this code, and cannot be held
+     * liable for any real or imagined damage resulting from its use.
+     * Users of this code must verify correctness for their application.     
+     * See http://geomalgorithms.com/a03-_inclusion.html
+     */
+    public static final boolean insidePolygon (final Coord p, final List<Coord> vertex) {
+        final int y = p.getHighPrecLat();
+        final int len = vertex.size();
+        // the winding number counter
+        int wn = 0;
+        Coord curr = vertex.get(0), next; // current & next points from vertex list
+       
+		for (int i = 0; ++i < len; curr = next) {
+			next = vertex.get(i);
+			if (curr.getHighPrecLat() <= y) { // starting y <= p.y
+				// an upward crossing and p left of edge:
+				if (next.getHighPrecLat() > y) {
+					if (p.isLeft(curr, next) > 0) {
+						++wn;
+					}
+				}
+
+			} else if (next.getHighPrecLat() <= y) {
+				// a downward crossing and p right of edge.
+				if (p.isLeft(curr, next) < 0) {
+					--wn;
+				}
+			}
+		}
+       
+        return wn != 0; // if 0 point is outside
+    }
+
+
+	
 }
