Rev 3408 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
* Copyright (C) 2008
*
* 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.
*
* Create date: 07-Jul-2008
*/
package uk.me.parabola.imgfmt.app.net;
import java.util.ArrayList;
import java.util.List;
import uk.me.parabola.imgfmt.app.ImgFileWriter;
import static uk.me.parabola.imgfmt.app.net.AccessTagsAndBits.*;
/**
* A restriction in the routing graph.
*
* A routing restriction has two or more arcs.
* The first arc is the "from" arc, the last is the "to" arc,
* and other arc is a "via" arc.
*
* A from-to-via restriction says you can't go along arc "to"
* if you came to node to.getSource() == from.getSource()
* via the inverse arc of "from". We're using the inverse of
* "from" since that has the information we need for writing
* the Table C entry.
*
* @author Robert Vollmert
*/
public class RouteRestriction
{
//private static final Logger log = Logger.getLogger(RouteRestriction.class);
// first three bytes of the header -- might specify the type of restriction
// and when it is active
private static final byte RESTRICTION_TYPE = 0x05
; // 0x07 spotted, meaning?
// To specify that a node is given by a relative offset instead
// of an entry to Table B.
private static final int F_INTERNAL = 0x8000
;
// the arcs
private final List<RouteArc
> arcs
;
private final RouteNode viaNode
;
// offset in Table C
private byte offsetSize
;
private int offsetC
;
// last restriction in a node
private boolean last
;
// mask that specifies which vehicle types the restriction doesn't apply to
private final byte exceptMask
;
private final byte flags
; // meaning of bits 0x01 and 0x10 are not clear
private final static byte F_EXCEPT_FOOT = 0x02
;
private final static byte F_EXCEPT_EMERGENCY = 0x04
;
private final static byte F_MORE_EXCEPTIONS = 0x08
;
private final static byte EXCEPT_CAR = 0x01
;
private final static byte EXCEPT_BUS = 0x02
;
private final static byte EXCEPT_TAXI = 0x04
;
private final static byte EXCEPT_DELIVERY = 0x10
;
private final static byte EXCEPT_BICYCLE = 0x20
;
private final static byte EXCEPT_TRUCK = 0x40
;
/**
*
* @param viaNode the node to which this restriction is related
* @param traffArcs the arcs that describe the "forbidden" path
* @param mkgmapExceptMask the exception mask in the mkgmap format
*/
public RouteRestriction
(RouteNode viaNode,
List<RouteArc
> traffArcs,
byte mkgmapExceptMask
) {
this.
viaNode = viaNode
;
this.
arcs =
new ArrayList<>(traffArcs
);
for (int i =
0; i
< arcs.
size(); i++
){
RouteArc arc = arcs.
get(i
);
assert arc.
getDest() != viaNode
;
}
byte flags =
0;
if ((mkgmapExceptMask
& FOOT
) !=
0)
flags |= F_EXCEPT_FOOT
;
if ((mkgmapExceptMask
& EMERGENCY
) !=
0)
flags |= F_EXCEPT_EMERGENCY
;
exceptMask = translateExceptMask
(mkgmapExceptMask
);
if(exceptMask
!=
0)
flags |= F_MORE_EXCEPTIONS
;
int numArcs = arcs.
size();
assert numArcs
< 8;
flags |=
((numArcs
) << 5);
this.
flags = flags
;
}
/**
* Translate the mkgmap internal representation of vehicles to the one used in the img format
* @param mkgmapExceptMask
* @return
*/
private byte translateExceptMask
(byte mkgmapExceptMask
) {
byte mask =
0;
if ((mkgmapExceptMask
& CAR
) !=
0)
mask |= EXCEPT_CAR
;
if ((mkgmapExceptMask
& BUS
) !=
0)
mask |= EXCEPT_BUS
;
if ((mkgmapExceptMask
& TAXI
) !=
0)
mask |= EXCEPT_TAXI
;
if ((mkgmapExceptMask
& DELIVERY
) !=
0)
mask |= EXCEPT_DELIVERY
;
if ((mkgmapExceptMask
& BIKE
) !=
0)
mask |= EXCEPT_BICYCLE
;
if ((mkgmapExceptMask
& TRUCK
) !=
0)
mask |= EXCEPT_TRUCK
;
return mask
;
}
private int calcOffset
(RouteNode node,
int tableOffset
) {
int offset = tableOffset - node.
getOffsetNod1();
assert offset
>=
0 :
"node behind start of tables";
assert offset
< 0x8000 :
"node offset too large";
return offset | F_INTERNAL
;
}
public List<RouteArc
> getArcs
(){
return arcs
;
}
/**
* Writes a Table C entry with 3 or more nodes.
*
* @param writer The writer.
* @param tableOffset The offset in NOD 1 of the tables area.
*
*/
public void write
(ImgFileWriter writer,
int tableOffset
) {
writer.
put(RESTRICTION_TYPE
);
writer.
put(flags
);
writer.
put((byte)0); // meaning ?
if(exceptMask
!=
0)
writer.
put(exceptMask
);
int numArcs = arcs.
size();
int[] offsets =
new int[numArcs+
1];
int pos =
0;
boolean viaWritten =
false;
for (int i =
0; i
< numArcs
; i++
){
RouteArc arc = arcs.
get(i
);
// the arcs must have a specific order and direction
// first arc: dest is from node , last arc: dest is to node
// if there only two arcs, both will have the via node as source node.
// For more n via nodes, the order is like this:
// from <- via(1) <- via(2) <- ... <- this via node -> via( n-1) -> via(n) -> to
if (arc.
isInternal())
offsets
[pos++
] = calcOffset
(arc.
getDest(), tableOffset
);
else
offsets
[pos++
] = arc.
getIndexB();
if (arc.
getSource() == viaNode
){
// there will be two nodes with source node = viaNode, but we write the source only once
if (!viaWritten
){
offsets
[pos++
] = calcOffset
(viaNode, tableOffset
);
viaWritten =
true;
}
}
}
for (int offset : offsets
)
writer.
putChar((char) offset
);
for (RouteArc arc: arcs
)
writer.
put(arc.
getIndexA());
}
/**
* Write this restriction's offset within Table C into a node record.
*/
public void writeOffset
(ImgFileWriter writer
) {
assert 0 < offsetSize
&& offsetSize
<=
2 :
"illegal offset size";
int offset = offsetC
;
if (offsetSize ==
1) {
assert offset
< 0x80
;
if (last
)
offset |= 0x80
;
writer.
put((byte) offset
);
} else {
assert offset
< 0x8000
;
if (last
)
offset |= 0x8000
;
writer.
putChar((char) offset
);
}
}
/**
* Size in bytes of the Table C entry.
*/
public int getSize
() {
int size =
3; // header length
if(exceptMask
!=
0)
++size
;
size += arcs.
size() +
(arcs.
size()+
1) * 2;
return size
;
}
public void setOffsetC
(int offsetC
) {
this.
offsetC = offsetC
;
}
public int getOffsetC
() {
return offsetC
;
}
public void setOffsetSize
(byte size
) {
offsetSize = size
;
}
public void setLast
() {
last =
true;
}
}