Rev 3408 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
* 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: 18-Jul-2008
*/
package uk.me.parabola.imgfmt.app.net;
import java.util.HashMap;
import java.util.LinkedHashMap;
import uk.me.parabola.imgfmt.app.ImgFileWriter;
import uk.me.parabola.log.Logger;
/**
* Table A that contains road information for segments in one RouteCenter.
*
* Each arc starting from a node in the RouteCenter has an associated
* entry in Table A, shared by the inverse arc for internal arcs. This
* entry consists of some routing parameters and a link to the road in
* NET.
*/
public class TableA
{
private static final Logger log =
Logger.
getLogger(TableA.
class);
private static final int ITEM_SIZE =
5;
// This table's start position relative to the start of NOD 1
private int offset
;
// arcs for roundabouts
private final HashMap<RoadDef,
Integer> roundaboutArcs =
new LinkedHashMap<RoadDef,
Integer>();
// arcs for unpaved ways
private final HashMap<RoadDef,
Integer> unpavedArcs =
new LinkedHashMap<RoadDef,
Integer>();
// arcs for ferry ways
private final HashMap<RoadDef,
Integer> ferryArcs =
new LinkedHashMap<RoadDef,
Integer>();
// arcs for paved ways
private final HashMap<RoadDef,
Integer> pavedArcs =
new LinkedHashMap<RoadDef,
Integer>();
private static int count
;
private boolean frozen
; // true when no more arcs should be added
public TableA
() {
log.
debug("creating TableA", count
);
count++
;
}
/**
* Add an arc to the table if not present and set its index.
*
* The value may overflow while it isn't certain that
* the table fulfils the size constraint.
*/
public void addArc
(RouteArc arc
) {
assert !frozen :
"trying to add arc to Table A after it has been frozen";
int i
;
RoadDef rd = arc.
getRoadDef();
if(rd.
isRoundabout()) {
if (!roundaboutArcs.
containsKey(rd
)) {
i = roundaboutArcs.
size();
roundaboutArcs.
put(rd, i
);
log.
debug("added roundabout arc", count, rd, i
);
}
}
else if(rd.
ferry()) {
if (!ferryArcs.
containsKey(rd
)) {
i = ferryArcs.
size();
ferryArcs.
put(rd, i
);
log.
debug("added ferry arc", count, rd, i
);
}
}
else if(rd.
paved()) {
if (!pavedArcs.
containsKey(rd
)) {
i = pavedArcs.
size();
pavedArcs.
put(rd, i
);
log.
debug("added paved arc", count, rd, i
);
}
}
else {
if (!unpavedArcs.
containsKey(rd
)) {
i = unpavedArcs.
size();
unpavedArcs.
put(rd, i
);
log.
debug("added unpaved arc", count, rd, i
);
}
}
}
/**
* Retrieve an arc's index.
* Order in table A: roundabouts, unpaved, ferry, paved
*/
public byte getIndex
(RouteArc arc
) {
frozen =
true; // don't allow any more arcs to be added
int i
;
RoadDef rd = arc.
getRoadDef();
if(rd.
isRoundabout()) {
assert roundaboutArcs.
containsKey(rd
):
"Trying to read Table A index for non-registered arc: " + count +
" " + rd
;
i = roundaboutArcs.
get(rd
);
}
else if(rd.
ferry()) {
assert ferryArcs.
containsKey(rd
):
"Trying to read Table A index for non-registered arc: " + count +
" " + rd
;
i = roundaboutArcs.
size() + unpavedArcs.
size() + ferryArcs.
get(rd
);
}
else if(rd.
paved()) {
assert pavedArcs.
containsKey(rd
):
"Trying to read Table A index for non-registered arc: " + count +
" " + rd
;
i = roundaboutArcs.
size() + unpavedArcs.
size() + ferryArcs.
size() + pavedArcs.
get(rd
);
}
else {
assert unpavedArcs.
containsKey(rd
):
"Trying to read Table A index for non-registered arc: " + count +
" " + rd
;
i = roundaboutArcs.
size() + unpavedArcs.
get(rd
);
}
assert i
< 0x100 :
"Table A index too large: " + rd
;
return (byte) i
;
}
/**
* Retrieve the size of the Table as an int.
*
* While Table A is limited to byte size (0x100 entries),
* we temporarily build larger tables while subdividing
* the network.
*/
public int size
() {
return roundaboutArcs.
size() + unpavedArcs.
size() + ferryArcs.
size() + pavedArcs.
size();
}
public int numRoundaboutArcs
() {
return roundaboutArcs.
size();
}
public int numUnpavedArcs
() {
return unpavedArcs.
size();
}
public int numFerryArcs
() {
return ferryArcs.
size();
}
/**
* Retrieve the size of the table as byte.
*
* This value is what should be written to the table
* header. When this is read, the table is assumed to
* be fit for writing, so at this point we check
* it isn't too large.
*/
public byte getNumberOfItems
() {
assert size
() < 0x100 :
"Table A too large";
return (byte)size
();
}
/**
* This is called first to reserve enough space. It will be rewritten
* later.
*/
public void write
(ImgFileWriter writer
) {
offset = writer.
position();
int size = size
() * ITEM_SIZE
;
log.
debug("tab a offset", offset,
"tab a size", size
);
for (int i =
0; i
< size
; i++
)
writer.
put((byte) 0);
}
/**
* Fill in the table once the NET offsets of the roads are known.
*/
public void writePost
(ImgFileWriter writer
) {
writer.
position(offset
);
// unpaved arcs first
for (RoadDef rd: roundaboutArcs.
keySet()) {
writePost
(writer, rd
);
}
for (RoadDef rd: unpavedArcs.
keySet()) {
writePost
(writer, rd
);
}
// followed by the ferry arcs
for (RoadDef rd : ferryArcs.
keySet()) {
writePost
(writer, rd
);
}
// followed by the paved arcs
for (RoadDef rd : pavedArcs.
keySet()) {
writePost
(writer, rd
);
}
}
public void writePost
(ImgFileWriter writer, RoadDef rd
) {
// write the table A entries. Consists of a pointer to net
// followed by 2 bytes of class and speed flags and road restrictions.
int pos = rd.
getOffsetNet1();
int access = rd.
getTabAAccess();
// top bits of access go into net1 offset
final int ACCESS_TOP_BITS = 0xc000
;
pos |=
(access
& ACCESS_TOP_BITS
) << 8;
access
&= ~ACCESS_TOP_BITS
;
writer.
put3(pos
);
writer.
put((byte) rd.
getTabAInfo());
writer.
put((byte) access
);
}
}