Subversion Repositories mkgmap

Rev

Rev 4253 | View as "text/plain" | Blame | Compare with Previous | Last modification | View Log | RSS feed

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

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import uk.me.parabola.imgfmt.app.Coord;
import uk.me.parabola.mkgmap.general.MapRoad;
import uk.me.parabola.mkgmap.reader.osm.Way;

/**
 * Stores the matching data between a housenumber and its road.
 * @author WanMil
 */

public class HousenumberMatch extends HousenumberElem {
        private MapRoad road;
        private HousenumberRoad housenumberRoad;
       
        private double distance = Double.POSITIVE_INFINITY;
        private int segment = -1;
        private boolean left;
       
        private double segmentFrac;
       
        private boolean ignored;
        private boolean isDuplicate;
        private boolean interpolated;
        private int moved;
        // distance in m between closest point on road and the point that is found in the address search
        private double searchDist = Double.NaN;
        private boolean isFarDuplicate;
        private HousenumberGroup group;
        private List<MapRoad> alternativeRoads;
        private int intervalInfoRefs; // counter
       
        public HousenumberMatch(HousenumberElem he) {
                super(he);
        }

        public MapRoad getRoad() {
                return road;
        }

        public void setRoad(MapRoad road) {
                this.road = road;
        }

        /**
         * Retrieves the distance to the road.
         * @return distance in m
         */

        public double getDistance() {
                return distance;
        }

        /**
         * Sets the distance to the road
         * @param distance distance in m
         */

        public void setDistance(double distance) {
                this.distance = distance;
        }

        /**
         * Retrieves the segment number the house number belongs to.
         * @return the segment number
         */

        public int getSegment() {
                return segment;
        }

        /**
         * Sets the segment number the house number belongs to.
         * @param segment the segment number
         */

        public void setSegment(int segment) {
                this.segment = segment;
        }

        public boolean isLeft() {
                return left;
        }

        /**
         * Sets if the house number is on the left or right side of the street.
         * @param left {@code true} left side; {@code false} right side
         */

        public void setLeft(boolean left) {
                this.left = left;
        }

        /**
         * Retrieve the relative position of this house number within the segement
         * of the related road.
         * @return the relative position within the roads segment
         */

        public double getSegmentFrac() {
                return segmentFrac;
        }

        /**
         * Sets the relative position of this house number within its segment
         * of the related road.
         * @param segmentFrac relative position within the segment
         */

        public void setSegmentFrac(double segmentFrac) {
                this.segmentFrac = segmentFrac;
        }

        public boolean hasAlternativeRoad() {
                return alternativeRoads != null && !alternativeRoads.isEmpty();
        }

        public boolean isIgnored() {
                return ignored;
        }

        public void setIgnored(boolean ignored) {
                this.ignored = ignored;
        }

        public boolean isDuplicate() {
                return isDuplicate;
        }

        public void setDuplicate(boolean isDuplicate) {
                this.isDuplicate = isDuplicate;
        }

        public boolean isInterpolated() {
                return interpolated;
        }

        public void setInterpolated(boolean interpolated) {
                this.interpolated = interpolated;
        }

        public int getMoved() {
                return moved;
        }

        public void incMoved() {
                this.moved++;
        }

        public double getSearchDist() {
                return searchDist;
        }

        public void setSearchDist(double searchDist) {
                this.searchDist = searchDist;
        }

        public String toString() {
                String s1 = String.valueOf(getHousenumber());
                if (getSign().length() > 2 + s1.length())
                        return s1 + "("+segment+")";
                return getSign() + "("+segment+")";
        }

        public void setFarDuplicate(boolean b) {
                this.isFarDuplicate = b;
               
        }

        public boolean isFarDuplicate() {
                return isFarDuplicate;
        }

        /**
         * @return either an existing point on the road
         * or the calculated perpendicular. In the latter case
         * the highway count is zero.
         *  
         */

        public Coord getClosestPointOnRoad(){
                if (segmentFrac <= 0)
                        return getRoad().getPoints().get(segment);
                if (segmentFrac >= 1)
                        return getRoad().getPoints().get(segment+1);
                Coord c1 = getRoad().getPoints().get(segment);
                Coord c2 = getRoad().getPoints().get(segment+1);
                return c1.makeBetweenPoint(c2, segmentFrac);
        }

        /**
         * @param other a different house on the same road
         * @return  the distance in m between the perpendiculars on the road
         * of two houses.
         */

        public double getDistOnRoad(HousenumberMatch other) {
                if (getRoad() != other.getRoad()){
                        assert false : "cannot compute distance on road for different roads";
                }
                List<Coord> points = getRoad().getPoints();
                HousenumberMatch house1 = this;
                HousenumberMatch house2 = other;
                if (house1.segment > house2.segment || house1.segment == house2.segment && house1.segmentFrac > house2.segmentFrac){
                        house1 = other;
                        house2 = this;
                }
                int s1 = house1.segment;
                int s2 = house2.segment;
                double distOnRoad = 0;
                while (s1 < s2){
                        double segLen = points.get(s1).distance(points.get(s1 + 1));
                        if (s1 == house1.getSegment() && house1.getSegmentFrac() > 0){
                                // rest of first segment
                                distOnRoad += Math.max(0, 1-house1.getSegmentFrac()) * segLen;
                        } else
                                distOnRoad += segLen;
                        s1++;
                }
                double segLen = points.get(s1).distance(points.get(s1 + 1));
                if (house2.getSegmentFrac() > 0)
                        distOnRoad += Math.min(1, house2.getSegmentFrac()) * segLen;
                if (house1.getSegmentFrac() > 0 && s1 == house1.segment)
                        distOnRoad -= Math.min(1, house1.getSegmentFrac()) * segLen;
                return distOnRoad;
        }

        public HousenumberRoad getHousenumberRoad() {
                return housenumberRoad;
        }

        public void setHousenumberRoad(HousenumberRoad housenumberRoad) {
                this.housenumberRoad = housenumberRoad;
        }
       
        public void setGroup(HousenumberGroup housenumberBlock) {
                this.group = housenumberBlock;
        }

        public HousenumberGroup getGroup() {
                return group;
        }

        public void addAlternativeRoad(MapRoad road2) {
                if (alternativeRoads == null){
                        alternativeRoads = new ArrayList<>();
                }
                alternativeRoads.add(road2);
        }
        public List<MapRoad> getAlternativeRoads() {
                if (alternativeRoads == null)
                        return Collections.emptyList();
                return alternativeRoads;
        }
        public void forgetAlternativeRoads(){
                alternativeRoads = null;
        }

        public int getIntervalInfoRefs() {
                return intervalInfoRefs;
        }

        public void incIntervalInfoRefs() {
                intervalInfoRefs++;
        }

        public void decIntervalInfoRefs() {
                if (intervalInfoRefs > 0)
                        --intervalInfoRefs;
        }

        public boolean isDirectlyConnected(HousenumberMatch other){
                if (getElement() instanceof Way && other.getElement() instanceof Way){
                        List<Coord> s1 = ((Way) getElement()).getPoints();
                        List<Coord> s2 = ((Way) other.getElement()).getPoints();
                        for (int i = 0; i+1 < s1.size(); i++){
                            Coord co = s1.get(i);
                            co.setPartOfShape2(false);
                        }
                        for (int i = 0; i+1 < s2.size(); i++){
                            Coord co = s2.get(i);
                            co.setPartOfShape2(true);
                        }
                        for (int i = 0; i+1 < s1.size(); i++){
                            Coord co = s1.get(i);
                            if (co.isPartOfShape2())
                                return true;
                        }
                }
                return false;
        }


        public void calcRoadSide(){
                if (getRoad() == null)
                        return;
                Coord c1 = getRoad().getPoints().get(getSegment());
                Coord c2 = getRoad().getPoints().get(getSegment()+1);
                setLeft(HousenumberGenerator.isLeft(c1, c2, getLocation()));
               
        }
       
        public boolean isEqualAddress(HousenumberElem other){
                if (getRoad() != other.getRoad())
                        return false;
                if (!getSign().equals(other.getSign()))
                        return false;
                if (getPlace() != other.getPlace()) {
                        if (getPlace() == null)
                                return false;
                        if (!getPlace().equals(other.getPlace()))
                                return false;
                }
                if (getZipCode() != null && other.getZipCode() != null){
                        if (!getZipCode().equals(other.getZipCode()))
                                return false;
                }
                if (getCityInfo() != null && other.getCityInfo() != null){
                        if (!getCityInfo().equals(other.getCityInfo()))
                                return false;
                }
                return true;
        }
       
}