/* * Copyright (c) 2009. * * 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. * * Created: 13 Sep 2009 * By: steve */ package uk.me.parabola.mkgmap.reader.osm; import java.util.Formatter; import uk.me.parabola.imgfmt.ExitException; import uk.me.parabola.log.Logger; import uk.me.parabola.mkgmap.general.LevelInfo; /** * Holds the garmin type of an element and all the information that * will be needed to represent it on the map. So we have a range of * resolutions at which it will be present. */ public class GType { private static final Logger log = Logger.getLogger(GType.class); private final FeatureKind featureKind; private final int type; private int minResolution = 24; private int maxResolution = 24; private int maxLevel = -1; private int minLevel; private String defaultName; // road class and speed will be set on roads. private int roadClass; private int roadSpeed; private boolean hasRoadAttribute; private boolean levelsWereFixed = false; /** If this is set, then we look for further types after this one is matched */ private boolean continueSearch; // by default, a rule's actions are skipped when searching for // further rules to match - by setting this true, the rule's // actions will always be executed private boolean propogateActionsOnContinue; public static boolean checkType(FeatureKind featureKind, int type) { if (type >= 0x010000){ if ((type & 0xff) > 0x1f) return false; } else { if (featureKind == FeatureKind.POLYLINE && type > 0x3f) return false; else if (featureKind == FeatureKind.POLYGON && (type> 0x7f || type == 0x4a)) return false; else if (featureKind == FeatureKind.POINT){ if (type < 0x0100 || (type & 0x00ff) > 0x1f) return false; } } return true; } public GType(FeatureKind featureKind, String type) { this.featureKind = featureKind; try { int t = Integer.decode(type); if (featureKind == FeatureKind.POLYGON){ // allow 0xYY00 instead of 0xYY if (t >= 0x100 && t < 0x10000 && (t & 0xff) == 0) t >>= 8; } this.type = t; } catch (NumberFormatException e) { log.error("not numeric " + type); throw new ExitException("non-numeric type in style file"); } } public FeatureKind getFeatureKind() { return featureKind; } public int getType() { return type; } public int getMinResolution() { return minResolution; } public void setMinResolution(int minResolution) { this.minResolution = minResolution; } public int getMaxResolution() { return maxResolution; } public void setMaxResolution(int maxResolution) { this.maxResolution = maxResolution; } public String getDefaultName() { return defaultName; } public void setDefaultName(String defaultName) { this.defaultName = defaultName; } /** * Set minLevel and maxLevel based on the resolution values set and * the given levels info. We do this because we used to work only * on resolution, but we want to move more towards working with * levels. */ public void fixLevels(LevelInfo[] levels) { for (LevelInfo info : levels) { if (info.getBits() <= minResolution) maxLevel = info.getLevel(); if (info.getBits() <= maxResolution) minLevel = info.getLevel(); } levelsWereFixed = true; } public String toString() { StringBuilder sb = new StringBuilder(); Formatter fmt = new Formatter(sb); sb.append('['); fmt.format("%#x", type); if (maxLevel == -1) { if (maxResolution == 24) fmt.format(" resolution %d", minResolution); else fmt.format(" resolution %d-%d", maxResolution, minResolution); } else { if (minLevel == 0) fmt.format(" level %d", maxLevel); else fmt.format(" level %d-%d", minLevel, maxLevel); } if (hasRoadAttribute) fmt.format(" road_class=%d road_speed=%d", roadClass, roadSpeed); if (continueSearch) fmt.format(" continue"); if (propogateActionsOnContinue) fmt.format(" propagate"); sb.append(']'); String res = sb.toString(); fmt.close(); return res; } public int getMinLevel() { return minLevel; } public int getMaxLevel() { return maxLevel; } public int getRoadClass() { return roadClass; } public void setRoadClass(int roadClass) { // road class might also be set for nodes used by the link-pois-to-ways option if (getFeatureKind() == FeatureKind.POLYLINE) hasRoadAttribute = true; this.roadClass = roadClass; } public int getRoadSpeed() { return roadSpeed; } public void setRoadSpeed(int roadSpeed) { // road speed might also be set for nodes used by the link-pois-to-ways option if (getFeatureKind() == FeatureKind.POLYLINE) hasRoadAttribute = true; this.roadSpeed = roadSpeed; } public boolean hasRoadAttribute() { return hasRoadAttribute; } /** * @return true if the object has valid attributes to be used as a routable way */ public boolean isRoad() { if (!levelsWereFixed) log.error("internal: isRoad() called before fixLevels()"); return hasRoadAttribute && minLevel == 0; } public boolean isContinueSearch() { return continueSearch; } public void propagateActions(boolean propagate) { propogateActionsOnContinue = propagate; } public boolean isPropogateActions() { return !continueSearch || propogateActionsOnContinue; } public void setContinueSearch(boolean continueSearch) { this.continueSearch = continueSearch; } /** * * @param type the type value * @return true if the type can be used for routable lines */ public static boolean isRoutableLineType(int type){ return type >= 0x01 && type <= 0x3f; } /** * * @param type the type value * @return true if the type is known as routable in Garmin maps. These are * known to cause routing errors if used for non-routable lines. */ public static boolean isSpecialRoutableLineType(int type){ return type >= 0x01 && type <= 0x13 || type == 0x16 || type == 0x1b; } /** * Return a type value in the commonly used hex format * @param type the integer value * @return a hex string with even number of digits */ public static String formatType(int type){ String s = String.format("%x", type); return (s.length() % 2 != 0 ? "0x0":"0x") + s; } }