Subversion Repositories mkgmap

Rev

Rev 4464 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * Copyright (C) 2020.
 *
 * 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.util;

import static org.junit.Assert.assertTrue;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import org.junit.Test;

import func.lib.Args;
import uk.me.parabola.imgfmt.Utils;
import uk.me.parabola.imgfmt.app.Area;
import uk.me.parabola.imgfmt.app.Coord;
import uk.me.parabola.mkgmap.osmstyle.function.IsInFunction;
import uk.me.parabola.mkgmap.reader.osm.Element;
import uk.me.parabola.mkgmap.reader.osm.FeatureKind;
import uk.me.parabola.mkgmap.reader.osm.Node;
import uk.me.parabola.mkgmap.reader.osm.OsmMapDataSource;
import uk.me.parabola.mkgmap.reader.osm.Way;

/*
Source: test/resources/in/osm/is-in-samples.osm
errors: test-reports/uk/me/parabola/util/62_IsInUtilTest-err.html
*/


public class IsInUtilTest {

        Area testSourceBbox = null;

        private static final String allPointMethods = "in,in_or_on,on";
        private static final String allLineMethods = "all,all_in_or_on,on,any,none";
        private static final String allPolygonMethods = "all,any";

        private static final Map<Integer, String> pointMethods = new HashMap<>();
        private static final Map<Integer, String> lineMethods = new HashMap<>();
        private static final Map<Integer, String> polygonMethods = new HashMap<>();

        public IsInUtilTest() {
                // set up the methods that should return true for the 'expected' value
                pointMethods.put(1, "in,in_or_on");
                pointMethods.put(2, "in_or_on,on");
                pointMethods.put(4, "");

/* all=someInNoneOut, any=anyIn, none=someOutNoneIn
     1  2  4
a 1) IN        all allInOrOn    any
b 3) IN ON     all allInOrOn    any
c 7) IN ON OUT                  any
d 2)    ON         allInOrOn on
e 6)    ON OUT                      none
f 4)       OUT                      none
*/

                lineMethods.put(1, "all,all_in_or_on,any");
                lineMethods.put(2, "all_in_or_on,on");
                lineMethods.put(3, "all,all_in_or_on,any");
                lineMethods.put(4, "none");
                //lineMethods.put(5, "");
                lineMethods.put(6, "none");
                lineMethods.put(7, "any");

                polygonMethods.put(1, "all,any");
                polygonMethods.put(2, "all,any");
                polygonMethods.put(3, "all,any");
                polygonMethods.put(4, "");
                //polygonMethods.put(5, "");
                polygonMethods.put(6, "");
                polygonMethods.put(7, "any");
        }

        private static boolean invokeMethod(IsInFunction anInst, String method, FeatureKind kind, Element el) {
                anInst.setParams(Arrays.asList("landuse", "residential", method), kind); // tag key/value don't matter
                String rslt = anInst.calcImpl(el);
                return "true".equals(rslt);
        }

        public List<String> testWithVariants(FeatureKind kind, Element el, String name, Set<Way> polygons) {
                List<String> errors = new ArrayList<>();

                IsInFunction anInst = new IsInFunction();
                List<Element> matchingPolygons = new ArrayList<>();
                for (Way polygon : polygons)
                        matchingPolygons.add(polygon);
                anInst.unitTestAugment(new ElementQuadTree(testSourceBbox, matchingPolygons));
               
                String expectedVal = el.getTag("expected");
                if (expectedVal != null && !"?".equals(expectedVal)) {
                        int expected = Integer.parseInt(expectedVal);
                        String allMethods = "";
                        Map<Integer, String> methods = null;
                        switch (kind) {
                        case POINT:
                                allMethods = allPointMethods;
                                methods = pointMethods;
                                break;
                        case POLYLINE:
                                allMethods = allLineMethods;
                                methods = lineMethods;
                                break;
                        case POLYGON:
                                allMethods = allPolygonMethods;
                                methods = polygonMethods;
                                break;
                        }
                        if (!methods.containsKey(expected)) {
                                errors.add(name + " failed, no methods for expected: " + expectedVal);
                                return errors;
                        }
                        String[] trueMethods = methods.get(expected).split(",");
                        if (trueMethods[0].isEmpty())
                                trueMethods = new String[0];
                        List<String> falseMethods = new ArrayList<>();
                        for (String tstMethod : allMethods.split(",")) {
                                boolean inList = false;
                                for (String trueMethod : trueMethods)
                                        if (tstMethod.equals(trueMethod)) {
                                                inList = true;
                                                break;
                                        }
                                if (!inList)
                                        falseMethods.add(tstMethod);
                        }

                        for (String tstMethod : trueMethods)
                                if (!invokeMethod(anInst, tstMethod, kind, el))
                                        errors.add(name + " failed, expected: " + expectedVal + ". " + tstMethod + " should be true");
                        for (String tstMethod : falseMethods)
                                if (invokeMethod(anInst, tstMethod, kind, el))
                                        errors.add(name + " failed, expected: " + expectedVal + ". " + tstMethod + " should be false");

                        if (!errors.isEmpty() || !(el instanceof Way))
                                return errors;
                        Way w2 = (Way) el.copy();
                        Collections.reverse(w2.getPoints());
                        for (String tstMethod : trueMethods)
                                if (!invokeMethod(anInst, tstMethod, kind, w2))
                                        errors.add(name + " failed reversed, expected: " + expectedVal + ". " + tstMethod + " should be true");
                        for (String tstMethod : falseMethods)
                                if (invokeMethod(anInst, tstMethod, kind, w2))
                                        errors.add(name + " failed reversed, expected: " + expectedVal + ". " + tstMethod + " should be false");

                        if (!errors.isEmpty() || !w2.hasIdenticalEndPoints())
                                return errors;
                        List<Coord> points = w2.getPoints();
                        for (int i = 1; i < w2.getPoints().size(); i++) {
                                points.remove(points.size() - 1);
                                Collections.rotate(points, 1);
                                points.add(points.get(0));
                                for (String tstMethod : trueMethods)
                                        if (!invokeMethod(anInst, tstMethod, kind, w2))
                                                errors.add(name + " failed rotated, expected: " + expectedVal + ". " + tstMethod + " should be true");
                                for (String tstMethod : falseMethods)
                                        if (invokeMethod(anInst, tstMethod, kind, w2))
                                                errors.add(name + " failed rotated, expected: " + expectedVal + ". " + tstMethod + " should be false");
                        }
                }
                return errors;
        }

        @Test
        public void testBasic() throws FileNotFoundException {

                // just loads the file
                class TestSource extends OsmMapDataSource {
                        @Override
                        public Set<String> getUsedTags() {
                                // return null => all tags are used
                                return null;
                        }
                       
                        @Override
                        public void load(String name, boolean addBackground) throws FileNotFoundException {
                                try (InputStream is = Utils.openFile(name)) {
                                        parse(is, name);
                                } catch (IOException e) {
                                        // exception thrown from implicit call to close() on resource variable 'is'
                                }
                               
                                elementSaver.finishLoading();
                        }
                }
                TestSource src = new TestSource();
                src.config(new EnhancedProperties());
                src.load(Args.TEST_RESOURCE_OSM + "is-in-samples.osm", false);
                testSourceBbox = src.getElementSaver().getBoundingBox();
               
                ElementQuadTree qt = IsInFunction.buildTree(src.getElementSaver(), "landuse", "residential");
                ArrayList<String> allErrors = new ArrayList<>();
                for (Node n: src.getElementSaver().getNodes().values()) {
                        String name = n.getTag("name");
                        if (name != null) {
                                Area elementBbox = Area.getBBox(Collections.singletonList((n).getLocation()));
                                Set<Way> polygons = qt.get(elementBbox).stream().map(e -> (Way) e)
                                                .collect(Collectors.toCollection(LinkedHashSet::new));
                                allErrors.addAll(testWithVariants(FeatureKind.POINT, n, name, polygons));
                        }
                }
                for (Way w: src.getElementSaver().getWays().values()) {
                        String name = w.getTag("name");
                        if (name != null) {
                                Area elementBbox = Area.getBBox(w.getPoints());
                                Set<Way> polygons = qt.get(elementBbox).stream().map(e -> (Way) e)
                                                .collect(Collectors.toCollection(LinkedHashSet::new));
                                if (name.startsWith("w"))
                                        allErrors.addAll(testWithVariants(FeatureKind.POLYLINE, w, name, polygons));
                                else
                                        allErrors.addAll(testWithVariants(FeatureKind.POLYGON, w, name, polygons));
                        }
                }
                for (String msg : allErrors) {
                        System.err.println(msg);
                }
                assertTrue("Found errors. Check System.err content", allErrors.isEmpty());
        }
}