Rev 1771 |
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 paved ways
private final HashMap<Arc,
Integer> pavedArcs =
new LinkedHashMap<Arc,
Integer>();
// arcs for unpaved ways
private final HashMap<Arc,
Integer> unpavedArcs =
new LinkedHashMap<Arc,
Integer>();
// arcs for ferry ways
private final HashMap<Arc,
Integer> ferryArcs =
new LinkedHashMap<Arc,
Integer>();
private static int count
;
private boolean frozen
; // true when no more arcs should be added
public TableA
() {
log.
debug("creating TableA", count
);
count++
;
}
/**
* Internal class tracking all the data a Table A entry needs.
* Basically a "forward arc".
*/
private class Arc
{
final RouteNode first
; final RouteNode second
;
final RoadDef roadDef
;
Arc
(RouteArc arc
) {
if (arc.
isForward()) {
first = arc.
getSource();
second = arc.
getDest();
} else {
first = arc.
getDest();
second = arc.
getSource();
}
roadDef = arc.
getRoadDef();
}
public boolean equals
(Object obj
) {
if (this == obj
) return true;
if (obj ==
null || getClass
() != obj.
getClass()) return false;
Arc arc =
(Arc
) obj
;
return first.
equals(arc.
first)
&& second.
equals(arc.
second)
&& roadDef.
equals(arc.
roadDef);
}
public int hashCode
() {
return first.
hashCode() +
2*second.
hashCode() + roadDef.
hashCode();
}
public String toString
() {
return "" + first +
"->" + second +
" (" + roadDef +
")";
}
}
/**
* 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 fulfills the size constraint.
*/
public void addArc
(RouteArc arc
) {
assert !frozen :
"trying to add arc to Table A after it has been frozen";
Arc narc =
new Arc
(arc
);
int i
;
if(arc.
getRoadDef().
ferry()) {
if (!ferryArcs.
containsKey(narc
)) {
i = ferryArcs.
size();
ferryArcs.
put(narc, i
);
log.
debug("added ferry arc", count, narc, i
);
}
}
else if(arc.
getRoadDef().
paved()) {
if (!pavedArcs.
containsKey(narc
)) {
i = pavedArcs.
size();
pavedArcs.
put(narc, i
);
log.
debug("added paved arc", count, narc, i
);
}
}
else {
if (!unpavedArcs.
containsKey(narc
)) {
i = unpavedArcs.
size();
unpavedArcs.
put(narc, i
);
log.
debug("added unpaved arc", count, narc, i
);
}
}
}
/**
* Retrieve an arc's index.
*/
public byte getIndex
(RouteArc arc
) {
frozen =
true; // don't allow any more arcs to be added
Arc narc =
new Arc
(arc
);
int i
;
if(arc.
getRoadDef().
ferry()) {
assert ferryArcs.
containsKey(narc
):
"Trying to read Table A index for non-registered arc: " + count +
" " + narc
;
i = unpavedArcs.
size() + ferryArcs.
get(narc
);
}
else if(arc.
getRoadDef().
paved()) {
assert pavedArcs.
containsKey(narc
):
"Trying to read Table A index for non-registered arc: " + count +
" " + narc
;
i = unpavedArcs.
size() + ferryArcs.
size() + pavedArcs.
get(narc
);
}
else {
assert unpavedArcs.
containsKey(narc
):
"Trying to read Table A index for non-registered arc: " + count +
" " + narc
;
i = unpavedArcs.
get(narc
);
}
assert i
< 0x100 :
"Table A index too large: " + narc
;
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 ferryArcs.
size() + unpavedArcs.
size() + pavedArcs.
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 (Arc arc : unpavedArcs.
keySet()) {
writePost
(writer, arc
);
}
// followed by the ferry arcs
for (Arc arc : ferryArcs.
keySet()) {
writePost
(writer, arc
);
}
// followed by the paved arcs
for (Arc arc : pavedArcs.
keySet()) {
writePost
(writer, arc
);
}
}
public void writePost
(ImgFileWriter writer, Arc arc
) {
// 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 = arc.
roadDef.
getOffsetNet1();
int access = arc.
roadDef.
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) arc.
roadDef.
getTabAInfo());
writer.
put((byte) access
);
}
}