/* * Copyright (C) 2008 Steve Ratcliffe * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License 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. * * * Author: Steve Ratcliffe * Create date: 04-Aug-2008 */ package uk.me.parabola.mkgmap.reader.polish; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import uk.me.parabola.imgfmt.app.Coord; import uk.me.parabola.imgfmt.app.CoordNode; import uk.me.parabola.imgfmt.app.net.AccessTagsAndBits; import uk.me.parabola.imgfmt.app.net.NumberStyle; import uk.me.parabola.imgfmt.app.net.Numbers; import uk.me.parabola.log.Logger; import uk.me.parabola.mkgmap.general.MapLine; import uk.me.parabola.mkgmap.general.MapRoad; /** * Used to remember all the road relevant parameters in a definition which * can occur in any order. Also remembers routing nodes and makes sure * the generated MapRoads all have the same RoutingNode objects. * * Use one instance of RoadHelper per file, and reset after reading * each road. */ class RoadHelper { private static final Logger log = Logger.getLogger(RoadHelper.class); // routing node store, persistent over resets private final Map<Long, CoordNode> nodeCoords = new HashMap<>(); private int roadId; private final List<NodeIndex> nodes = new ArrayList<>(); private int speed; private int roadClass; private boolean oneway; private boolean toll; private byte mkgmapAccess; private List<Numbers> numbers; public RoadHelper() { clear(); } public void clear() { roadId = 0; nodes.clear(); speed = 0; roadClass = 0; oneway = false; toll = false; numbers = null; } public void setRoadId(int roadId) { this.roadId = roadId; } public void addNode(String value) { String[] f = value.split(","); nodes.add(new NodeIndex(f)); } /** * @param param cgpsmapper manual: * RouteParam=speed,road_class,one_way,toll, * denied_emergency,denied_delivery,denied_car,denied_bus,denied_taxi,denied_pedestrain,denied_bicycle,denied_truck */ public void setParam(String param) { String[] f = param.split(","); speed = Integer.parseInt(f[0]); if (speed < 0) speed = 0; if (speed > 7) speed = 7; roadClass = Integer.parseInt(f[1]); if (roadClass < 0) roadClass = 0; if (roadClass > 4) roadClass = 4; oneway = (f.length > 2) ? Integer.parseInt(f[2]) > 0: false; toll = (f.length > 3) ? Integer.parseInt(f[3]) > 0: false; byte noAccess = 0; for (int j = 0; j < f.length - 4; j++){ if (Integer.parseInt(f[4+j]) == 0) continue; switch (j){ case 0: noAccess |= AccessTagsAndBits.EMERGENCY; break; case 1: noAccess |= AccessTagsAndBits.DELIVERY; break; case 2: noAccess |= AccessTagsAndBits.CAR; break; case 3: noAccess |= AccessTagsAndBits.BUS; break; case 4: noAccess |= AccessTagsAndBits.TAXI; break; case 5: noAccess |= AccessTagsAndBits.FOOT; break; case 6: noAccess |= AccessTagsAndBits.BIKE; break; case 7: noAccess |= AccessTagsAndBits.TRUCK; break; } } mkgmapAccess = (byte) ~noAccess; // we store the allowed vehicles } public MapRoad makeRoad(MapLine l) { assert roadId != 0; if (log.isDebugEnabled()) log.debug("finishing road id " + roadId); MapRoad road = new MapRoad(roadId, roadId, l); // Set parameters. road.setRoadClass(roadClass); road.setSpeed(speed); if (oneway) road.setOneway(); if (toll) road.setToll(); road.setAccess(mkgmapAccess); if (numbers != null && !numbers.isEmpty()) { convertNodesForHouseNumbers(road); road.setNumbers(numbers); } List<Coord> points = road.getPoints(); for (NodeIndex ni : nodes) { int n = ni.index; if (log.isDebugEnabled()) log.debug("road has " + points.size() +" points"); Coord coord = points.get(n); long id = coord.getId(); if (id == 0) { CoordNode node = nodeCoords.get((long) ni.nodeId); if (node == null) { node = new CoordNode(coord, ni.nodeId, ni.boundary); nodeCoords.put((long) ni.nodeId, node); } points.set(n, node); } else if (id != ni.nodeId) { log.warn("Inconsistant node ids"); } } return road; } /** * Make sure that each node that is referenced by the house * numbers is a number node. Some of them will later be changed * to routing nodes. * Only called if numbers is non-null and not empty. */ private void convertNodesForHouseNumbers(MapRoad road) { int rNodNumber = 0; for (Numbers n : numbers) { int node = n.getNodeNumber(); n.setIndex(rNodNumber++); road.getPoints().get(node).setNumberNode(true); } } public boolean isRoad() { return roadId != 0; } public Map<Long, CoordNode> getNodeCoords() { return nodeCoords; } public void addNumbers(String value) { if (numbers == null) numbers = new ArrayList<>(); Numbers num = new Numbers(value); if (num.getLeftNumberStyle() != NumberStyle.NONE || num.getRightNumberStyle() != NumberStyle.NONE) numbers.add(num); } private static class NodeIndex { private final int index; private final int nodeId; private boolean boundary; private NodeIndex(String[] f) { // f[0] is the index into the line // f[1] is the node id // f[2] is whether it's a boundary node index = Integer.parseInt(f[0]); nodeId = Integer.parseInt(f[1]); if (f.length > 2) boundary = Integer.parseInt(f[2]) > 0; if (log.isDebugEnabled()) log.debug("ind=" + index + "node=" + nodeId + "bound=" + boundary); } public String toString() { return String.format("%d,%d,%b", index, nodeId, boundary); } } }