Subversion Repositories mkgmap

Rev

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

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

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import uk.me.parabola.imgfmt.app.Coord;
import uk.me.parabola.mkgmap.general.MapShape;
//import uk.me.parabola.util.GpxCreator;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Test;


public class ShapeMergeFilterTest {
        // create one Coord instance for each point in a small test grid
        private static final HashMap<Integer,Coord> map = new HashMap<Integer,Coord>(){
                {
                        for (int lat30 = 0; lat30 < 100; lat30 +=5){
                                for (int lon30 = 0; lon30 < 100; lon30 += 5){
                                        Coord co = Coord.makeHighPrecCoord(lat30, lon30);
                                        put(lat30*1000 + lon30,co);
                                }
                        }
                }
        };

        @Test
        public void testAreaTestVal(){
                List<Coord> points = new ArrayList<Coord>(){{
                        add(getPoint(10,10));
                        add(getPoint(30,10));
                        add(getPoint(30,30));
                        add(getPoint(10,30));
                        add(getPoint(10,10)); // close
                       
                }};
                assertEquals(2 * (20 * 20),ShapeMergeFilter.calcAreaSizeTestVal(points));
        }      
        /**
         * two simple shapes, sharing one point
         */

        @Test
        public void testSimpleSharingOne(){
                List<Coord> points1 = new ArrayList<Coord>(){{
                        add(getPoint(15,10));
                        add(getPoint(30,25));
                        add(getPoint(25,30));
                        add(getPoint(10,30));
                        add(getPoint(5,20));
                        add(getPoint(15,10)); // close
                }};
               
                List<Coord> points2 = new ArrayList<Coord>(){{
                        add(getPoint(25,30));
                        add(getPoint(30,35));
                        add(getPoint(20,40));
                        add(getPoint(15,35));
                        add(getPoint(25,30));
                }};
                testVariants("simple shapes sharing one point", points1, points2,1,10);
        }
       
        /**
         * two simple shapes, sharing one edge
         */

        @Test
        public void testSimpleNonOverlapping(){
                List<Coord> points1 = new ArrayList<Coord>(){{
                        add(getPoint(15,10));
                        add(getPoint(30,25));
                        add(getPoint(25,30));
                        add(getPoint(15,35));
                        add(getPoint(5,20));
                        add(getPoint(15,10)); // close
                }};
               
                List<Coord> points2 = new ArrayList<Coord>(){{
                        add(getPoint(25,30));
                        add(getPoint(30,35));
                        add(getPoint(20,40));
                        add(getPoint(15,35));
                        add(getPoint(25,30));
                }};
                testVariants("simple shapes", points1, points2,1,8);
        }

        /**
         * two simple shapes, sharing three consecutive points
         */


        @Test
        public void test3SharedPointsNonOverlapping(){
                List<Coord> points1 = new ArrayList<Coord>(){{
                        add(getPoint(15,10));
                        add(getPoint(30,25));
                        add(getPoint(25,30));
                        add(getPoint(20,35));
                        add(getPoint(15,35));
                        add(getPoint(5,20));
                        add(getPoint(15,10));// close
                }};
               
                List<Coord> points2 = new ArrayList<Coord>(){{
                        add(getPoint(25,30));
                        add(getPoint(30,35));
                        add(getPoint(20,40));
                        add(getPoint(15,35));
                        add(getPoint(20,35));
                        add(getPoint(25,30));// close
                }};
                testVariants("test 3 consecutive shared points", points1, points2, 1, 8);
        }
       
        /**
         * two simple shapes, sharing three consecutive points
         */


        @Test
        public void test2SharedPointsNoEdge(){
                List<Coord> points1 = new ArrayList<Coord>(){{
                        add(getPoint(15,10));
                        add(getPoint(30,25));
                        add(getPoint(25,30));
                        add(getPoint(15,35));
                        add(getPoint(5,20));
                        add(getPoint(15,10));// close
                }};
               
                List<Coord> points2 = new ArrayList<Coord>(){{
                        add(getPoint(25,30));
                        add(getPoint(30,35));
                        add(getPoint(20,40));
                        add(getPoint(15,35));
                        add(getPoint(20,35));
                        add(getPoint(25,30));// close
                }};
                testVariants("test 2 non-consecutive shared points", points1, points2, 1, 11);
        }
       
        /**
         * one u-formed shape, the other closes it to a rectangular shape with a hole
         * They are sharing 4 points.
         */


        @Test
        public void testCloseUFormed(){
                List<Coord> points1 = new ArrayList<Coord>(){{
                        // u-formed shaped (open at top)
                        add(getPoint(15,50));
                        add(getPoint(30,50));
                        add(getPoint(30,55));
                        add(getPoint(20,55));
                        add(getPoint(20,65));
                        add(getPoint(30,65));
                        add(getPoint(30,70));
                        add(getPoint(15,70));
                        add(getPoint(15,50));// close
                }};


                List<Coord> points2 = new ArrayList<Coord>(){{
                        add(getPoint(35,50));
                        add(getPoint(35,70));
                        add(getPoint(30,70));
                        add(getPoint(30,65));
                        add(getPoint(30,55));
                        add(getPoint(30,50));
                        add(getPoint(35,50)); // close
                }};
               
                testVariants("test close U formed shape", points1, points2, 1, 11);
        }
       
        /**
         * one u-formed shape, the fits into the u and shares all points
         */


        @Test
        public void testFillUFormed(){
                List<Coord> points1 = new ArrayList<Coord>(){{
                        // u-formed shaped (open at top)
                        add(getPoint(15,50));
                        add(getPoint(30,50));
                        add(getPoint(30,55));
                        add(getPoint(20,55));
                        add(getPoint(20,65));
                        add(getPoint(30,65));
                        add(getPoint(30,70));
                        add(getPoint(15,70));
                        add(getPoint(15,50)); // close
                }};

               
                List<Coord> points2 = new ArrayList<Coord>(){{
                        add(getPoint(30,55));
                        add(getPoint(30,65));
                        add(getPoint(20,65));
                        add(getPoint(20,55));
                        add(getPoint(30,55)); // close
                }};
                testVariants("test fill U-formed shape", points1, points2, 1, 5);
        }
       
        /**
         * one u-formed shape, the fits into the u and shares all points
         */


        @Test
        public void testFillHole(){
                List<Coord> points1 = new ArrayList<Coord>(){{
                        // a rectangle with a hole
                        add(getPoint(35,50));
                        add(getPoint(35,70));
                        add(getPoint(15,70));
                        add(getPoint(15,50));
                        add(getPoint(30,50));
                        add(getPoint(30,55));
                        add(getPoint(20,55));
                        add(getPoint(20,65));
                        add(getPoint(30,65));
                        add(getPoint(30,50));
                        add(getPoint(35,50));// close
                }};

                List<Coord> points2 = new ArrayList<Coord>(){{
                        add(getPoint(30,55));
                        add(getPoint(30,65));
                        add(getPoint(20,65));
                        add(getPoint(20,55));
                        add(getPoint(30,55)); // close
                }};
                testVariants("test-fill-hole", points1, points2, 1, 6); // expect 8 points if spike is not removed  
        }

        @Test
        public void testDuplicate(){
                List<Coord> points1 = new ArrayList<Coord>(){{
                        add(getPoint(30,55));
                        add(getPoint(30,65));
                        add(getPoint(20,65));
                        add(getPoint(20,55));
                        add(getPoint(30,55)); // close
                }};
                List<Coord> points2 = new ArrayList<Coord>(points1);
               
                testVariants("test duplicate", points1, points2, 1, 5);
        }

        @Test
        public void testOverlap(){
                List<Coord> points1 = new ArrayList<Coord>(){{
                        add(getPoint(30,55));
                        add(getPoint(30,65));
                        add(getPoint(20,65));
                        add(getPoint(20,55));
                        add(getPoint(30,55)); // close
                }};

                List<Coord> points2 = new ArrayList<Coord>(){{
                        add(getPoint(30,55));
                        add(getPoint(30,65));
                        add(getPoint(25,65));
                        add(getPoint(25,55));
                        add(getPoint(30,55)); // close
                }};
                // no merge expected
                testVariants("test overlap", points1, points2, 2, 5);
        }

        /*
         * shapes are connected at multiple edges like two
         * w-formed shapes.
         */

        @Test
        public void testTwoWShaped(){
                List<Coord> points1 = new ArrayList<Coord>(){{
                        add(getPoint(0,5));
                        add(getPoint(35,5));
                        add(getPoint(35,20));
                        add(getPoint(30,15));
                        add(getPoint(25,20));
                        add(getPoint(25,10));
                        add(getPoint(15,10));
                        add(getPoint(15,20));
                        add(getPoint(10,15));
                        add(getPoint(5,20));
                        add(getPoint(0,20));
                        add(getPoint(0,5)); // close
                }};

                List<Coord> points2 = new ArrayList<Coord>(){{
                        add(getPoint(35,35));
                        add(getPoint(35,20));
                        add(getPoint(30,15));
                        add(getPoint(25,20));
                        add(getPoint(25,25));
                        add(getPoint(15,25));
                        add(getPoint(15,20));
                        add(getPoint(10,15));
                        add(getPoint(5,20));
                        add(getPoint(0,20));
                        add(getPoint(5,35));
                        add(getPoint(35,35)); // close
                }};
               
                // wanted: merge that removes at least the longer shared sequence
                testVariants("test two w-shaped", points1, points2, 1, 16);
        }

        /**
         * Test all variants regarding clockwise/ccw direction and positions of the points
         * in the list and the order of shapes.
         * @param list1
         * @param list2
         */

        void testVariants(String msg, List<Coord> list1, List<Coord> list2, int expectedNumShapes, int expectedNumPoints){
                MapShape s1 = new MapShape(1);
                MapShape s2 = new MapShape(2);
                s1.setMinResolution(22);
                s2.setMinResolution(22);
                for (int i = 0; i < 4; i++){
                        for (int j = 0; j < list1.size(); j++){
                                List<Coord> points1 = new ArrayList<>(list1);
                                if ((i & 1) != 0)
                                        Collections.reverse(points1);
                                points1.remove(points1.size()-1);
                                Collections.rotate(points1, j);
                                points1.add(points1.get(0));
                                s1.setPoints(points1);
                                for (int k = 0; k < list2.size(); k++){
                                        List<Coord> points2 = new ArrayList<>(list2);
                                        if ((i & 2) != 0)
                                                Collections.reverse(points2);
                                        points2.remove(points2.size()-1);
                                        Collections.rotate(points2, k);
                                        points2.add(points2.get(0));
                                        s2.setPoints(points2);
                                       
                                        for (int l = 0; l < 2; l++){
                                                String testId = msg+" i="+i+",j="+j+",k="+k+",l="+l;
                                                if (l == 0)
                                                        testOneVariant(testId, s1, s2, expectedNumShapes,expectedNumPoints);
                                                else
                                                        testOneVariant(testId, s2, s1, expectedNumShapes,expectedNumPoints);
                                        }
                                }
                        }
                }
                return;
        }
       
        void testOneVariant(String testId, MapShape s1, MapShape s2, int expectedNumShapes, int expectedNumPoints){
                ShapeMergeFilter smf = new ShapeMergeFilter(24);
                List<MapShape> res = smf.merge(Arrays.asList(s1,s2));
                assertTrue(testId, res != null);
                assertEquals(testId,expectedNumShapes, res.size() );
//              if (res.get(0).getPoints().size() != expectedNumPoints){
//                      GpxCreator.createGpx("e:/ld/s1", s1.getPoints());
//                      GpxCreator.createGpx("e:/ld/s2", s2.getPoints());
//                      GpxCreator.createGpx("e:/ld/res", res.get(0).getPoints());
//              }
                assertEquals(testId, expectedNumPoints, res.get(0).getPoints().size());
                // TODO: test shape size
        }
        Coord getPoint(int lat, int lon){
                Coord co = map.get(lat*1000+lon);
                assert co != null;
                return co;
        }
}