Index: trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(revision 15068)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(revision 15069)
@@ -5,4 +5,5 @@
 
 import java.text.MessageFormat;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -313,4 +314,6 @@
 
         private class ContainsFinder extends AbstractFinder {
+            protected List<IPrimitive> toCheck;
+
             protected ContainsFinder(Environment e) {
                 super(e);
@@ -319,22 +322,27 @@
 
             @Override
-            public void visit(INode n) {
-                if (left.matches(new Environment(n).withParent(e.osm))
-                    && ((e.osm instanceof IWay && Geometry.nodeInsidePolygon(n, ((IWay<?>) e.osm).getNodes()))
-                            || (e.osm instanceof Relation && (
-                                    (Relation) e.osm).isMultipolygon() && Geometry.isNodeInsideMultiPolygon(n, (Relation) e.osm, null)))) {
-                    addToChildren(e, n);
-                }
-            }
-
-            @Override
-            public void visit(IWay<?> w) {
-                if (left.matches(new Environment(w).withParent(e.osm))
-                    && ((e.osm instanceof IWay && Geometry.PolygonIntersection.FIRST_INSIDE_SECOND.equals(
-                            Geometry.polygonIntersection(w.getNodes(), ((IWay<?>) e.osm).getNodes())))
-                            || (e.osm instanceof Relation && (
-                                    (Relation) e.osm).isMultipolygon()
-                                    && Geometry.isPolygonInsideMultiPolygon(w.getNodes(), (Relation) e.osm, null)))) {
-                    addToChildren(e, w);
+            public void visit(Collection<? extends IPrimitive> primitives) {
+                for (IPrimitive p : primitives) {
+                    if (p != e.osm && isPrimitiveUsable(p) && left.matches(new Environment(p).withParent(e.osm))) {
+                        if (toCheck == null) {
+                            toCheck = new ArrayList<>();
+                        }
+                        toCheck.add(p);
+                    }
+                }
+            }
+
+            void execGeometryTests() {
+                if (toCheck == null || toCheck.isEmpty())
+                    return;
+
+                if (e.osm instanceof IWay) {
+                    for (IPrimitive p : Geometry.filterInsidePolygon(toCheck, (IWay<?>) e.osm)) {
+                        addToChildren(e, p);
+                    }
+                } else if (e.osm instanceof Relation) {
+                    for (IPrimitive p : Geometry.filterInsideMultipolygon(toCheck, (Relation) e.osm)) {
+                        addToChildren(e, p);
+                    }
                 }
             }
@@ -364,9 +372,12 @@
                         containsFinder.visit(e.osm.getDataSet().searchWays(e.osm.getBBox()));
                     }
+                    if (((OptimizedGeneralSelector) left).matchesBase(OsmPrimitiveType.RELATION)) {
+                        containsFinder.visit(e.osm.getDataSet().searchRelations(e.osm.getBBox()));
+                    }
                 } else {
                     // use slow test
                     containsFinder.visit(e.osm.getDataSet().allPrimitives());
                 }
-
+                containsFinder.execGeometryTests();
                 return e.children != null;
 
Index: trunk/src/org/openstreetmap/josm/tools/Geometry.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/Geometry.java	(revision 15068)
+++ trunk/src/org/openstreetmap/josm/tools/Geometry.java	(revision 15069)
@@ -30,4 +30,5 @@
 import org.openstreetmap.josm.data.osm.INode;
 import org.openstreetmap.josm.data.osm.IPrimitive;
+import org.openstreetmap.josm.data.osm.IWay;
 import org.openstreetmap.josm.data.osm.MultipolygonBuilder;
 import org.openstreetmap.josm.data.osm.MultipolygonBuilder.JoinedPolygon;
@@ -39,4 +40,5 @@
 import org.openstreetmap.josm.data.osm.WaySegment;
 import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon;
+import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon.PolyData;
 import org.openstreetmap.josm.data.osm.visitor.paint.relations.MultipolygonCache;
 import org.openstreetmap.josm.data.projection.Projection;
@@ -965,4 +967,5 @@
      * Tests if the {@code node} is inside the multipolygon {@code multiPolygon}. The nullable argument
      * {@code isOuterWayAMatch} allows to decide if the immediate {@code outer} way of the multipolygon is a match.
+     * For repeated tests against {@code multiPolygon} better use {@link Geometry#filterInsideMultipolygon}.
      * @param node node
      * @param multiPolygon multipolygon
@@ -977,4 +980,5 @@
      * Tests if the polygon formed by {@code nodes} is inside the multipolygon {@code multiPolygon}. The nullable argument
      * {@code isOuterWayAMatch} allows to decide if the immediate {@code outer} way of the multipolygon is a match.
+     * For repeated tests against {@code multiPolygon} better use {@link Geometry#filterInsideMultipolygon}.
      * <p>
      * If {@code nodes} contains exactly one element, then it is checked whether that one node is inside the multipolygon.
@@ -982,8 +986,121 @@
      * @param multiPolygon multipolygon
      * @param isOuterWayAMatch allows to decide if the immediate {@code outer} way of the multipolygon is a match
-     * @return {@code true} if the polygon formed by nodes is inside the multipolygon
+     * @return {@code true} if the multipolygon is valid and the polygon formed by nodes is inside the multipolygon
      */
     public static boolean isPolygonInsideMultiPolygon(List<? extends INode> nodes, Relation multiPolygon, Predicate<Way> isOuterWayAMatch) {
-        // Extract outer/inner members from multipolygon
+        try {
+            return isPolygonInsideMultiPolygon(nodes, MultipolygonBuilder.joinWays(multiPolygon), isOuterWayAMatch);
+        } catch (MultipolygonBuilder.JoinedPolygonCreationException ex) {
+            Logging.trace(ex);
+            Logging.debug("Invalid multipolygon " + multiPolygon);
+            return false;
+        }
+    }
+
+    /**
+     * Tests if the polygon formed by {@code nodes} is inside the multipolygon {@code multiPolygon}. The nullable argument
+     * {@code isOuterWayAMatch} allows to decide if the immediate {@code outer} way of the multipolygon is a match.
+     * For repeated tests against {@code multiPolygon} better use {@link Geometry#filterInsideMultipolygon}.
+     * <p>
+     * If {@code nodes} contains exactly one element, then it is checked whether that one node is inside the multipolygon.
+     * @param nodes nodes forming the polygon
+     * @param outerInner result of {@link MultipolygonBuilder#joinWays(Relation)}
+     * @param isOuterWayAMatch allows to decide if the immediate {@code outer} way of the multipolygon is a match
+     * @return {@code true} if the multipolygon is valid and the polygon formed by nodes is inside the multipolygon
+     * @since 15069
+     */
+    public static boolean isPolygonInsideMultiPolygon(List<? extends INode> nodes, Pair<List<JoinedPolygon>,
+            List<JoinedPolygon>> outerInner, Predicate<Way> isOuterWayAMatch) {
+        Area a1 = nodes.size() == 1 ? null : getArea(nodes);
+        // Test if object is inside an outer member
+        for (JoinedPolygon out : outerInner.a) {
+            if (a1 == null
+                    ? nodeInsidePolygon(nodes.get(0), out.getNodes())
+                    : PolygonIntersection.FIRST_INSIDE_SECOND == polygonIntersection(a1, out.area)) {
+                boolean insideInner = false;
+                // If inside an outer, check it is not inside an inner
+                for (JoinedPolygon in : outerInner.b) {
+                    if (a1 == null ? nodeInsidePolygon(nodes.get(0), in.getNodes())
+                            : in.area.getBounds2D().contains(a1.getBounds2D())
+                                    && polygonIntersection(a1, in.area) == PolygonIntersection.FIRST_INSIDE_SECOND
+                                    && polygonIntersection(in.area, out.area) == PolygonIntersection.FIRST_INSIDE_SECOND) {
+                        insideInner = true;
+                        break;
+                    }
+                }
+                if (!insideInner) {
+                    // Final check using predicate
+                    if (isOuterWayAMatch == null || isOuterWayAMatch.test(out.ways.get(0)
+                            /* TODO give a better representation of the outer ring to the predicate */)) {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Find all primitives in the given collection which are inside the given polygon.
+     * @param primitives the primitives
+     * @param polygon the polygon
+     * @return a new list containing the found primitives, empty if polygon is invalid or nothing was found.
+     * @since 15069
+     */
+
+    public static List<IPrimitive> filterInsidePolygon(List<IPrimitive> primitives, IWay<?> polygon) {
+        List<IPrimitive> res = new ArrayList<>();
+        if (!polygon.isClosed() || polygon.getNodesCount() <= 3)
+            return res;
+        /** polygon area in east north space, calculated only when really needed */
+        Area polygonArea = null;
+        for (IPrimitive p : primitives) {
+            if (p instanceof INode) {
+                if (nodeInsidePolygon((INode) p, polygon.getNodes())) {
+                    res.add(p);
+                }
+            } else if (p instanceof IWay) {
+                if (polygonArea == null) {
+                    polygonArea = getArea(polygon.getNodes());
+                }
+                if (PolygonIntersection.FIRST_INSIDE_SECOND == polygonIntersection(getArea(((IWay<?>) p).getNodes()),
+                        polygonArea)) {
+                    res.add(p);
+                }
+            } else if (p.isMultipolygon()) {
+                if (polygonArea == null) {
+                    polygonArea = getArea(polygon.getNodes());
+                }
+                Multipolygon mp = new Multipolygon((Relation) p);
+                boolean inside = true;
+                // a (valid) multipolygon is inside the polygon if all outer rings are inside
+                for (PolyData outer : mp.getOuterPolygons()) {
+                    if (PolygonIntersection.FIRST_INSIDE_SECOND != polygonIntersection(getArea(outer.getNodes()),
+                            polygonArea)) {
+                        inside = false;
+                        break;
+                    }
+                }
+                if (inside) {
+                    res.add(p);
+                }
+            }
+        }
+        return res;
+    }
+
+    /**
+     * Find all primitives in the given collection which are inside the given multipolygon. Members of the multipolygon are
+     * ignored.
+     * @param primitives the primitives
+     * @param multiPolygon the multipolygon relation
+     * @return a new list containing the found primitives, empty if multipolygon is invalid or nothing was found.
+     * @since 15069
+     */
+    public static List<IPrimitive> filterInsideMultipolygon(Collection<IPrimitive> primitives, Relation multiPolygon) {
+        List<IPrimitive> res = new ArrayList<>();
+        if (primitives.isEmpty())
+            return res;
+
         final Pair<List<JoinedPolygon>, List<JoinedPolygon>> outerInner;
         try {
@@ -992,34 +1109,37 @@
             Logging.trace(ex);
             Logging.debug("Invalid multipolygon " + multiPolygon);
-            return false;
-        }
-        // Test if object is inside an outer member
-        for (JoinedPolygon out : outerInner.a) {
-            if (nodes.size() == 1
-                    ? nodeInsidePolygon(nodes.get(0), out.getNodes())
-                    : PolygonIntersection.FIRST_INSIDE_SECOND == polygonIntersection(nodes, out.getNodes())) {
-                boolean insideInner = false;
-                // If inside an outer, check it is not inside an inner
-                for (JoinedPolygon in : outerInner.b) {
-                    if (nodes.size() == 1 ? nodeInsidePolygon(nodes.get(0), in.getNodes())
-                            : polygonIntersection(nodes, in.getNodes()) == PolygonIntersection.FIRST_INSIDE_SECOND
-                                    && polygonIntersection(in.getNodes(),
-                                            out.getNodes()) == PolygonIntersection.FIRST_INSIDE_SECOND) {
-                        insideInner = true;
+            return res;
+        }
+
+        Set<OsmPrimitive> members = multiPolygon.getMemberPrimitives();
+        for (IPrimitive p : primitives) {
+            if (members.contains(p))
+                continue;
+            if (p instanceof Node) {
+                if (isPolygonInsideMultiPolygon(Collections.singletonList((Node) p), outerInner, null)) {
+                    res.add(p);
+                }
+            } else if (p instanceof Way) {
+                if (isPolygonInsideMultiPolygon(((Way) p).getNodes(), outerInner, null)) {
+                    res.add(p);
+                }
+            } else if (p.isMultipolygon()) {
+                Multipolygon mp = new Multipolygon((Relation) p);
+                boolean inside = true;
+                // a (valid) multipolygon is inside multiPolygon if all outer rings are inside
+                for (PolyData outer : mp.getOuterPolygons()) {
+                    if (!isPolygonInsideMultiPolygon(outer.getNodes(), outerInner, null)) {
+                        inside = false;
                         break;
                     }
                 }
-                // Inside outer but not inside inner -> the polygon appears to be inside a the multipolygon
-                if (!insideInner) {
-                    // Final check using predicate
-                    if (isOuterWayAMatch == null || isOuterWayAMatch.test(out.ways.get(0)
-                            /* TODO give a better representation of the outer ring to the predicate */)) {
-                        return true;
-                    }
-                }
-            }
-        }
-        return false;
-    }
+                if (inside) {
+                    res.add(p);
+                }
+            }
+        }
+        return res;
+    }
+
 
     /**
Index: trunk/test/data/regress/17695/bib2.osm
===================================================================
--- trunk/test/data/regress/17695/bib2.osm	(revision 15069)
+++ trunk/test/data/regress/17695/bib2.osm	(revision 15069)
@@ -0,0 +1,242 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version='0.6' generator='JOSM' upload='never'>
+  <node id='-102236' action='modify' visible='true' lat='52.89733676698' lon='8.4603267498' />
+  <node id='-102238' action='modify' visible='true' lat='52.89732696084' lon='8.46285139425' />
+  <node id='-102242' action='modify' visible='true' lat='52.89615602196' lon='8.46303385762' />
+  <node id='-102244' action='modify' visible='true' lat='52.89611905028' lon='8.46044047743' />
+  <node id='-102248' action='modify' visible='true' lat='52.89715816378' lon='8.4608902313' />
+  <node id='-102250' action='modify' visible='true' lat='52.89711883103' lon='8.46193285455' />
+  <node id='-102252' action='modify' visible='true' lat='52.89643633706' lon='8.46202305064' />
+  <node id='-102254' action='modify' visible='true' lat='52.89648815049' lon='8.46079534734' />
+  <node id='-102292' action='modify' visible='true' lat='52.89718353496' lon='8.46227297414' />
+  <node id='-102294' action='modify' visible='true' lat='52.8968188065' lon='8.46230807347' />
+  <node id='-102296' action='modify' visible='true' lat='52.89682975541' lon='8.46262071435' />
+  <node id='-102298' action='modify' visible='true' lat='52.89719448378' lon='8.46258561501' />
+  <node id='-102333' action='modify' visible='true' lat='52.89619435334' lon='8.46625117412' />
+  <node id='-102335' action='modify' visible='true' lat='52.89615738169' lon='8.46365779393' />
+  <node id='-102337' action='modify' visible='true' lat='52.89719649427' lon='8.46410754779' />
+  <node id='-102339' action='modify' visible='true' lat='52.89715716156' lon='8.46515017105' />
+  <node id='-102341' action='modify' visible='true' lat='52.89647466818' lon='8.46524036714' />
+  <node id='-102343' action='modify' visible='true' lat='52.89652648157' lon='8.46401266384' />
+  <node id='-102345' action='modify' visible='true' lat='52.89722186543' lon='8.46549029064' />
+  <node id='-102347' action='modify' visible='true' lat='52.89686808619' lon='8.46583803084' />
+  <node id='-102349' action='modify' visible='true' lat='52.89685713729' lon='8.46552538997' />
+  <node id='-102351' action='modify' visible='true' lat='52.89723281424' lon='8.46580293151' />
+  <node id='-102353' action='modify' visible='true' lat='52.89737509731' lon='8.46354406629' />
+  <node id='-102355' action='modify' visible='true' lat='52.89736529118' lon='8.46606871075' />
+  <node id='-102459' action='modify' visible='true' lat='52.89540612124' lon='8.46420574137' />
+  <node id='-102461' action='modify' visible='true' lat='52.89536678691' lon='8.46524836462' />
+  <node id='-102463' action='modify' visible='true' lat='52.89468426533' lon='8.46533856071' />
+  <node id='-102465' action='modify' visible='true' lat='52.89473608086' lon='8.46411085741' />
+  <node id='-102467' action='modify' visible='true' lat='52.89527712192' lon='8.4645123706' />
+  <node id='-102469' action='modify' visible='true' lat='52.89492332681' lon='8.46486011081' />
+  <node id='-102471' action='modify' visible='true' lat='52.89491237741' lon='8.46454746994' />
+  <node id='-102473' action='modify' visible='true' lat='52.89528807122' lon='8.46482501148' />
+  <node id='-102475' action='modify' visible='true' lat='52.89558473166' lon='8.46364225987' />
+  <node id='-102477' action='modify' visible='true' lat='52.89557492512' lon='8.46616690432' />
+  <node id='-102479' action='modify' visible='true' lat='52.89440393891' lon='8.46634936769' />
+  <node id='-102481' action='modify' visible='true' lat='52.89436696574' lon='8.4637559875' />
+  <node id='-105602' action='modify' visible='true' lat='52.89549777816' lon='8.46058045197' />
+  <node id='-105604' action='modify' visible='true' lat='52.89552727685' lon='8.4630351299' />
+  <node id='-105606' action='modify' visible='true' lat='52.89439143731' lon='8.46307263546' />
+  <node id='-105608' action='modify' visible='true' lat='52.89436193784' lon='8.46061795753' />
+  <node id='-105610' action='modify' visible='true' lat='52.89523228897' lon='8.46092273774' />
+  <node id='-105612' action='modify' visible='true' lat='52.89524408852' lon='8.46232121959' />
+  <node id='-105614' action='modify' visible='true' lat='52.89465232478' lon='8.46233493865' />
+  <node id='-105616' action='modify' visible='true' lat='52.89464052506' lon='8.46093645681' />
+  <node id='-105623' action='modify' visible='true' lat='52.89498154473' lon='8.46127480799' />
+  <node id='-105625' action='modify' visible='true' lat='52.89498690023' lon='8.46190953673' />
+  <node id='-105627' action='modify' visible='true' lat='52.89494614585' lon='8.46191048156' />
+  <node id='-105629' action='modify' visible='true' lat='52.89494079035' lon='8.46127575281' />
+  <node id='-105912' action='modify' visible='true' lat='52.8935794489' lon='8.46089783301' />
+  <node id='-105914' action='modify' visible='true' lat='52.89392562521' lon='8.46177079193' />
+  <node id='-105916' action='modify' visible='true' lat='52.89341244577' lon='8.46252214927' />
+  <node id='-105918' action='modify' visible='true' lat='52.8930092104' lon='8.46148875658' />
+  <node id='-105920' action='modify' visible='true' lat='52.89363423585' lon='8.46133294523' />
+  <node id='-105922' action='modify' visible='true' lat='52.89373812737' lon='8.46159451477' />
+  <node id='-105924' action='modify' visible='true' lat='52.89343295493' lon='8.46192753951' />
+  <node id='-105926' action='modify' visible='true' lat='52.89332906269' lon='8.46166596997' />
+  <node id='-106033' action='modify' visible='true' lat='52.89362388571' lon='8.46152785035' />
+  <node id='-106035' action='modify' visible='true' lat='52.89361503572' lon='8.46171855242' />
+  <node id='-106037' action='modify' visible='true' lat='52.89347562201' lon='8.46170077657' />
+  <node id='-106039' action='modify' visible='true' lat='52.89348447203' lon='8.4615100745' />
+  <node id='-106656' action='modify' visible='true' lat='52.89385092093' lon='8.46480705795' />
+  <node id='-106657' action='modify' visible='true' lat='52.89354574929' lon='8.46514008269' />
+  <node id='-106659' action='modify' visible='true' lat='52.89344185732' lon='8.46487851314' />
+  <node id='-106665' action='modify' visible='true' lat='52.89374436656' lon='8.46413369749' />
+  <node id='-106667' action='modify' visible='true' lat='52.89402866691' lon='8.46506602807' />
+  <node id='-106668' action='modify' visible='true' lat='52.89346745157' lon='8.46571621045' />
+  <node id='-106669' action='modify' visible='true' lat='52.89313742214' lon='8.46461376748' />
+  <node id='-106670' action='modify' visible='true' lat='52.89374702969' lon='8.46454548841' />
+  <node id='-106718' action='modify' visible='true' lat='52.89363848503' lon='8.46489167529'>
+    <tag k='building' v='yes' />
+  </node>
+  <way id='-106040' action='modify' visible='true'>
+    <nd ref='-102236' />
+    <nd ref='-102238' />
+    <nd ref='-102242' />
+    <nd ref='-102244' />
+    <nd ref='-102236' />
+  </way>
+  <way id='-106041' action='modify' visible='true'>
+    <nd ref='-102248' />
+    <nd ref='-102250' />
+    <nd ref='-102252' />
+    <nd ref='-102254' />
+    <nd ref='-102248' />
+    <tag k='building' v='yes' />
+  </way>
+  <way id='-106042' action='modify' visible='true'>
+    <nd ref='-102292' />
+    <nd ref='-102298' />
+    <nd ref='-102296' />
+    <nd ref='-102294' />
+    <nd ref='-102292' />
+  </way>
+  <way id='-106043' action='modify' visible='true'>
+    <nd ref='-102337' />
+    <nd ref='-102339' />
+    <nd ref='-102341' />
+    <nd ref='-102343' />
+    <nd ref='-102337' />
+    <tag k='building' v='yes' />
+  </way>
+  <way id='-106044' action='modify' visible='true'>
+    <nd ref='-102345' />
+    <nd ref='-102351' />
+    <nd ref='-102347' />
+    <nd ref='-102349' />
+    <nd ref='-102345' />
+  </way>
+  <way id='-106045' action='modify' visible='true'>
+    <nd ref='-102353' />
+    <nd ref='-102355' />
+    <nd ref='-102333' />
+    <nd ref='-102335' />
+    <nd ref='-102353' />
+    <tag k='building' v='yes' />
+  </way>
+  <way id='-106046' action='modify' visible='true'>
+    <nd ref='-102467' />
+    <nd ref='-102473' />
+    <nd ref='-102469' />
+    <nd ref='-102471' />
+    <nd ref='-102467' />
+  </way>
+  <way id='-106047' action='modify' visible='true'>
+    <nd ref='-102459' />
+    <nd ref='-102461' />
+    <nd ref='-102463' />
+    <nd ref='-102465' />
+    <nd ref='-102459' />
+    <tag k='building' v='yes' />
+  </way>
+  <way id='-106048' action='modify' visible='true'>
+    <nd ref='-102475' />
+    <nd ref='-102477' />
+    <nd ref='-102479' />
+    <nd ref='-102481' />
+    <nd ref='-102475' />
+    <tag k='building' v='yes' />
+  </way>
+  <way id='-106049' action='modify' visible='true'>
+    <nd ref='-105602' />
+    <nd ref='-105604' />
+    <nd ref='-105606' />
+    <nd ref='-105608' />
+    <nd ref='-105602' />
+    <tag k='building' v='yes' />
+  </way>
+  <way id='-106050' action='modify' visible='true'>
+    <nd ref='-105610' />
+    <nd ref='-105612' />
+    <nd ref='-105614' />
+    <nd ref='-105616' />
+    <nd ref='-105610' />
+  </way>
+  <way id='-106051' action='modify' visible='true'>
+    <nd ref='-105623' />
+    <nd ref='-105625' />
+    <nd ref='-105627' />
+    <nd ref='-105629' />
+    <nd ref='-105623' />
+  </way>
+  <way id='-106052' action='modify' visible='true'>
+    <nd ref='-105912' />
+    <nd ref='-105914' />
+    <nd ref='-105916' />
+    <nd ref='-105918' />
+    <nd ref='-105912' />
+  </way>
+  <way id='-106053' action='modify' visible='true'>
+    <nd ref='-105920' />
+    <nd ref='-105922' />
+    <nd ref='-105924' />
+    <nd ref='-105926' />
+    <nd ref='-105920' />
+    <tag k='building' v='yes' />
+  </way>
+  <way id='-106054' action='modify' visible='true'>
+    <nd ref='-106033' />
+    <nd ref='-106035' />
+    <nd ref='-106037' />
+    <nd ref='-106039' />
+    <nd ref='-106033' />
+    <tag k='building' v='yes' />
+  </way>
+  <way id='-106658' action='modify' visible='true'>
+    <nd ref='-106665' />
+    <nd ref='-106667' />
+    <nd ref='-106668' />
+    <nd ref='-106669' />
+    <nd ref='-106665' />
+  </way>
+  <way id='-106661' action='modify' visible='true'>
+    <nd ref='-106670' />
+    <nd ref='-106656' />
+    <nd ref='-106657' />
+    <nd ref='-106659' />
+    <nd ref='-106670' />
+    <tag k='building' v='yes' />
+  </way>
+  <relation id='-106055' action='modify' visible='true'>
+    <member type='way' ref='-106040' role='outer' />
+    <member type='way' ref='-106042' role='inner' />
+    <tag k='building' v='yes' />
+    <tag k='name' v='R1' />
+    <tag k='type' v='multipolygon' />
+  </relation>
+  <relation id='-106056' action='modify' visible='true'>
+    <member type='way' ref='-106045' role='outer' />
+    <member type='way' ref='-106044' role='inner' />
+    <tag k='name' v='R2' />
+    <tag k='type' v='multipolygon' />
+  </relation>
+  <relation id='-106057' action='modify' visible='true'>
+    <member type='way' ref='-106047' role='outer' />
+    <member type='way' ref='-106046' role='inner' />
+    <tag k='name' v='R4' />
+    <tag k='type' v='multipolygon' />
+  </relation>
+  <relation id='-106058' action='modify' visible='true'>
+    <member type='way' ref='-106050' role='outer' />
+    <member type='way' ref='-106051' role='inner' />
+    <tag k='building' v='yes' />
+    <tag k='name' v='R3' />
+    <tag k='type' v='multipolygon' />
+  </relation>
+  <relation id='-106059' action='modify' visible='true'>
+    <member type='way' ref='-106052' role='outer' />
+    <member type='way' ref='-106053' role='inner' />
+    <tag k='amenity' v='parking' />
+    <tag k='name' v='R5' />
+    <tag k='type' v='multipolygon' />
+  </relation>
+  <relation id='-106856' action='modify' visible='true'>
+    <member type='way' ref='-106658' role='outer' />
+    <member type='way' ref='-106661' role='inner' />
+    <tag k='amenity' v='parking' />
+    <tag k='name' v='R6' />
+    <tag k='type' v='multipolygon' />
+  </relation>
+</osm>
Index: trunk/test/unit/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerTest.java	(revision 15068)
+++ trunk/test/unit/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerTest.java	(revision 15069)
@@ -339,3 +339,21 @@
         assertEquals(1, errors.size());
     }
+
+    /**
+     * Non-regression test for <a href="https://josm.openstreetmap.de/ticket/17695">Bug #17695</a>.
+     * @throws Exception if an error occurs
+     */
+    @Test
+    public void testTicket17695() throws Exception {
+        final MapCSSTagChecker test = buildTagChecker(
+                "*[building] ∈  *[building] {" +
+                "throwWarning: tr(\"Building inside building\");" +
+                "}");
+        try (InputStream is = TestUtils.getRegressionDataStream(17695, "bib2.osm")) {
+            test.visit(OsmReader.parseDataSet(is, null).allPrimitives());
+            List<TestError> errors = test.getErrors();
+            assertEquals(6, errors.size());
+        }
+    }
+
 }
Index: trunk/test/unit/org/openstreetmap/josm/tools/GeometryTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/tools/GeometryTest.java	(revision 15068)
+++ trunk/test/unit/org/openstreetmap/josm/tools/GeometryTest.java	(revision 15069)
@@ -265,4 +265,46 @@
 
     /**
+     * Test of {@link Geometry#filterInsideMultipolygon}
+     */
+    @Test
+    public void testFilterInsideMultiPolygon() {
+        Node node1 = new Node(new LatLon(1.01, 1.0));
+        Node node2 = new Node(new LatLon(1.01, 1.1));
+        Node node3 = new Node(new LatLon(1.02, 1.05));
+        Way w1 = new Way();
+        w1.setNodes(Arrays.asList(node1, node2, node3, node1));
+        w1.put("building", "yes");
+        Relation mp1 = new Relation();
+        mp1.addMember(new RelationMember("outer", w1));
+        mp1.put("type", "multipolygon");
+
+        Node node4 = new Node(new LatLon(1.0, 1.09));
+        Node node5 = new Node(new LatLon(1.0, 1.12));
+        Node node6 = new Node(new LatLon(1.1, 1.12));
+        Node node7 = new Node(new LatLon(1.1, 1.09));
+        Way outer = new Way();
+        outer.setNodes(Arrays.asList(node4, node5, node6, node7, node4));
+        Node node8 = new Node(new LatLon(1.04, 1.1));
+        Node node9 = new Node(new LatLon(1.04, 1.11));
+        Node node10 = new Node(new LatLon(1.06, 1.105));
+        Way inner = new Way();
+        inner.setNodes(Arrays.asList(node8, node9, node10, node8));
+        Relation mp2 = new Relation();
+        mp2.addMember(new RelationMember("outer", outer));
+        mp2.addMember(new RelationMember("inner", inner));
+        mp2.put("type", "multipolygon");
+        assertFalse(Geometry.isPolygonInsideMultiPolygon(w1.getNodes(), mp2, null));
+        assertFalse(Geometry.filterInsideMultipolygon(Arrays.asList(w1), mp2).contains(w1));
+
+        node4.setCoor(new LatLon(1.006, 0.99));
+        // now w1 is inside
+        assertTrue(Geometry.isPolygonInsideMultiPolygon(w1.getNodes(), mp2, null));
+        assertTrue(Geometry.filterInsideMultipolygon(Arrays.asList(w1), mp2).contains(w1));
+        assertTrue(Geometry.filterInsideMultipolygon(Arrays.asList(mp1), mp2).contains(mp1));
+        assertTrue(Geometry.filterInsideMultipolygon(Arrays.asList(w1, mp1), mp2).contains(w1));
+        assertTrue(Geometry.filterInsideMultipolygon(Arrays.asList(w1, mp1), mp2).contains(mp1));
+    }
+
+    /**
      * Test of {@link Geometry#getDistance} method.
      */
