/*
* 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.osmstyle;
import java.util.List;
import uk.me.parabola.imgfmt.app.Coord;
import uk.me.parabola.imgfmt.app.trergn.MapObject;
import uk.me.parabola.log.Logger;
import uk.me.parabola.mkgmap.reader.osm.Element;
import uk.me.parabola.mkgmap.reader.osm.GType;
import uk.me.parabola.mkgmap.reader.osm.TagDict;
import uk.me.parabola.mkgmap.reader.osm.Way;
import static uk.me.parabola.imgfmt.app.net.AccessTagsAndBits.*;
/**
* Class that is used to connect an OSM way with the attributes of GType
* after Style processing.
*
* @author GerdP
*
*/
public class ConvertedWay
{
private static final Logger log =
Logger.
getLogger(ConvertedWay.
class);
private final int index
;
private final Way way
; // with tags after Style processing
private final GType gt
;
private byte roadClass
; // 0-4
private byte roadSpeed
; // 0-7
private byte mkgmapAccess
; // bit mask, see ACCESS_TAGS
private final byte routeFlags
; // bit mask, see ROUTING_TAGS
private boolean isRoad
;
private boolean reversed
; // points were reversed
private boolean overlay
; // this is a non-routable overlay line that for a road
public ConvertedWay
(int index, Way way, GType type
) {
this.
index = index
;
this.
way = way
;
this.
gt = type
;
// note that the gt.getType() may not be a routable type when overlays are used
if (type.
isRoad() && MapObject.
hasExtendedType(gt.
getType()) ==
false) {
this.
roadClass =
(byte) gt.
getRoadClass();
this.
roadSpeed =
(byte) gt.
getRoadSpeed();
recalcRoadClass
(way
);
recalcRoadSpeed
(way
);
mkgmapAccess = evalAccessTags
(way
);
routeFlags = evalRouteTags
(way
);
isRoad =
true;
} else {
roadClass =
0;
roadSpeed =
0;
mkgmapAccess =
0;
routeFlags =
0;
isRoad =
false;
}
}
public ConvertedWay
(ConvertedWay other, Way way
){
this.
way = way
;
// copy all other attributes
this.
index = other.
index;
this.
gt = other.
gt;
this.
roadClass = other.
roadClass;
this.
roadSpeed = other.
roadSpeed;
this.
mkgmapAccess = other.
mkgmapAccess;
this.
routeFlags = other.
routeFlags;
}
public int getIndex
(){
return index
;
}
public GType getGType
(){
return gt
;
}
public Way getWay
() {
return way
;
}
public byte getAccess
(){
return mkgmapAccess
;
}
public byte getRoadClass
(){
return roadClass
;
}
public byte getRoadSpeed
(){
return roadSpeed
;
}
public byte getRouteFlags
(){
return routeFlags
;
}
/**
* Recalculates the road class based on the tags
* <ul>
* <li>{@code mkgmap:road-class}</li>
* <li>{@code mkgmap:road-class-min}</li>
* <li>{@code mkgmap:road-class-max}</li>
* </ul>
* The road class is changed if the tags modify its road class.
*
* @param el an element
* @return {@code true} the road class has been changed, else {@code false}
*/
private final static short roadClassTagKey = TagDict.
getInstance().
xlate("mkgmap:road-class");
public boolean recalcRoadClass
(Element el
) {
// save the original road class value
byte oldRoadClass = roadClass
;
String val = el.
getTag(roadClassTagKey
);
if (val
!=
null) {
if (val.
startsWith("-")) {
roadClass -=
Byte.
decode(val.
substring(1));
} else if (val.
startsWith("+")) {
roadClass +=
Byte.
decode(val.
substring(1));
} else {
roadClass =
Byte.
decode(val
);
}
val = el.
getTag("mkgmap:road-class-max");
byte roadClassMax =
4;
if (val
!=
null)
roadClassMax =
Byte.
decode(val
);
val = el.
getTag("mkgmap:road-class-min");
byte roadClassMin =
0;
if (val
!=
null)
roadClassMin =
Byte.
decode(val
);
if (roadClass
> roadClassMax
)
roadClass = roadClassMax
;
else if (roadClass
< roadClassMin
)
roadClass = roadClassMin
;
}
return (roadClass
!= oldRoadClass
);
}
/**
* Recalculates the road speed
* <ul>
* <li>{@code mkgmap:road-speed-class}</li>
* <li>{@code mkgmap:road-speed}</li>
* <li>{@code mkgmap:road-speed-min}</li>
* <li>{@code mkgmap:road-speed-max}</li>
* </ul>
*
* @param el an element
* @return {@code true} the road speed has been changed, else {@code false}
*/
private final static short roadSpeedTagKey = TagDict.
getInstance().
xlate("mkgmap:road-speed");
private final static short roadSpeedClassTagKey = TagDict.
getInstance().
xlate("mkgmap:road-speed-class");
public boolean recalcRoadSpeed
(Element el
) {
// save the original road speed value
byte oldRoadSpeed = roadSpeed
;
// check if the road speed is modified
String roadSpeedOverride = el.
getTag(roadSpeedClassTagKey
);
if (roadSpeedOverride
!=
null) {
try {
byte rs =
Byte.
decode(roadSpeedOverride
);
if (rs
>=
0 && rs
<=
7) {
// override the road speed class
roadSpeed = rs
;
} else {
log.
error(el.
getDebugName()
+
" road classification mkgmap:road-speed-class="
+ roadSpeedOverride +
" must be in [0;7]");
}
} catch (Exception exp
) {
log.
error(el.
getDebugName()
+
" road classification mkgmap:road-speed-class="
+ roadSpeedOverride +
" must be in [0;7]");
}
}
// check if the road speed should be modified more
String val = el.
getTag(roadSpeedTagKey
);
if(val
!=
null) {
if(val.
startsWith("-")) {
roadSpeed -=
Byte.
decode(val.
substring(1));
}
else if(val.
startsWith("+")) {
roadSpeed +=
Byte.
decode(val.
substring(1));
}
else {
roadSpeed =
Byte.
decode(val
);
}
val = el.
getTag("mkgmap:road-speed-max");
byte roadSpeedMax =
7;
if(val
!=
null)
roadSpeedMax =
Byte.
decode(val
);
val = el.
getTag("mkgmap:road-speed-min");
byte roadSpeedMin =
0;
if(val
!=
null)
roadSpeedMin =
Byte.
decode(val
);
if(roadSpeed
> roadSpeedMax
)
roadSpeed = roadSpeedMax
;
else if(roadSpeed
< roadSpeedMin
)
roadSpeed = roadSpeedMin
;
}
return (oldRoadSpeed
!= roadSpeed
);
}
public List<Coord
> getPoints
(){
return way.
getPoints();
}
public boolean isValid
() {
if (way ==
null)
return false;
if (way.
getPoints() ==
null || way.
getPoints().
size()<2)
return false;
return true;
}
public String toString
(){
return getGType
() +
" " + getWay
().
getId() +
" " + getWay
().
toTagString();
}
public boolean isOneway
(){
return (routeFlags
& R_ONEWAY
) !=
0;
}
public boolean isRoundabout
(){
return (routeFlags
& R_ROUNDABOUT
) !=
0;
}
public boolean isToll
(){
return (routeFlags
& R_TOLL
) !=
0;
}
public boolean isUnpaved
(){
return (routeFlags
& R_UNPAVED
) !=
0;
}
public boolean isFerry
(){
return (routeFlags
& R_FERRY
) !=
0;
}
public boolean isCarpool
(){
return (routeFlags
& R_CARPOOL
) !=
0;
}
public boolean isThroughroute
(){
return (routeFlags
& R_THROUGHROUTE
) !=
0;
}
public boolean isRoad
(){
return isRoad
;
}
public boolean isReversed
() {
return reversed
;
}
public void setReversed
(boolean reversed
) {
this.
reversed = reversed
;
}
public void setOverlay
(boolean b
) {
this.
overlay = b
;
}
public boolean isOverlay
() {
return overlay
;
}
}