/*
* Copyright (c) 2010, Scott Crosby
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 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.splitter.parser;
import crosby.binary.BinaryParser;
import crosby.binary.Osmformat;
import crosby.binary.file.FileBlockPosition;
import it.unimi.dsi.fastutil.shorts.ShortArrayList;
import uk.me.parabola.splitter.Area;
import uk.me.parabola.splitter.MapProcessor;
import uk.me.parabola.splitter.Node;
import uk.me.parabola.splitter.Relation;
import uk.me.parabola.splitter.UnknownFeatureException;
import uk.me.parabola.splitter.Utils;
import uk.me.parabola.splitter.Way;
import java.util.List;
public class BinaryMapParser
extends BinaryParser
{
private static final short TYPE_DENSE = 0x1
;
private static final short TYPE_NODES = 0x2
;
private static final short TYPE_WAYS = 0x4
;
private static final short TYPE_RELS = 0x8
;
private final ShortArrayList blockTypes =
new ShortArrayList
();
private final ShortArrayList knownBlockTypes
;
// for status messages
private final ElementCounter elemCounter =
new ElementCounter
();
private short blockType = -
1;
private int blockCount = -
1;
private boolean skipTags
;
private boolean skipNodes
;
private boolean skipWays
;
private boolean skipRels
;
private short wantedTypeMask =
0;
private int msgLevel
;
public BinaryMapParser
(MapProcessor processor, ShortArrayList knownBlockTypes,
int msgLevel
) {
this.
processor = processor
;
this.
knownBlockTypes = knownBlockTypes
;
this.
skipTags = processor.
skipTags();
this.
skipNodes = processor.
skipNodes();
this.
skipWays = processor.
skipWays();
this.
skipRels = processor.
skipRels();
this.
msgLevel = msgLevel
;
if (skipNodes ==
false) {
wantedTypeMask |= TYPE_DENSE
;
wantedTypeMask |= TYPE_NODES
;
}
if (skipWays ==
false)
wantedTypeMask |= TYPE_WAYS
;
if (skipRels ==
false)
wantedTypeMask |= TYPE_RELS
;
}
MapProcessor processor
;
public ShortArrayList getBlockList
() {
return blockTypes
;
}
@
Override
public boolean skipBlock
(FileBlockPosition block
) {
blockCount++
;
if (knownBlockTypes
!=
null) {
blockType = knownBlockTypes.
getShort(blockCount
);
if (blockType
!=
0 && (blockType
& wantedTypeMask
) ==
0)
return true;
} else if (blockType
!= -
1) {
// System.out.println("previous block contained " + blockType );
blockTypes.
add(blockType
);
}
blockType =
0;
// System.out.println("Seeing block of type: "+block.getType());
if (block.
getType().
equals("OSMData"))
return false;
if (block.
getType().
equals("OSMHeader"))
return false;
System.
out.
println("Skipped block of type: " + block.
getType());
return true;
}
@
Override
public void complete
() {
blockTypes.
add(blockType
);
// End of map is sent when all input files are processed.
// So do nothing else.
}
// Per-block state for parsing, set when processing the header of a block;
@
Override
protected void parseDense
(Osmformat.
DenseNodes nodes
) {
blockType |= TYPE_DENSE
;
if (skipNodes
)
return;
long last_id =
0, last_lat =
0, last_lon =
0;
int j =
0;
int maxi = nodes.
getIdCount();
Node tmp =
new Node();
for (int i =
0; i
< maxi
; i++
) {
long lat = nodes.
getLat(i
) + last_lat
;
last_lat = lat
;
long lon = nodes.
getLon(i
) + last_lon
;
last_lon = lon
;
long id = nodes.
getId(i
) + last_id
;
last_id = id
;
double latf = parseLat
(lat
), lonf = parseLon
(lon
);
tmp =
new Node();
tmp.
set(id, latf, lonf
);
if (nodes.
hasDenseinfo())
tmp.
setVersion(nodes.
getDenseinfo().
getVersion(i
));
if (!skipTags
) {
if (nodes.
getKeysValsCount() > 0) {
while (nodes.
getKeysVals(j
) !=
0) {
int keyid = nodes.
getKeysVals(j++
);
int valid = nodes.
getKeysVals(j++
);
tmp.
addTag(getStringById
(keyid
), getStringById
(valid
));
}
j++
; // Skip over the '0' delimiter.
}
}
processor.
processNode(tmp
);
elemCounter.
countNode(tmp.
getId());
}
}
@
Override
protected void parseNodes
(List<Osmformat.
Node> nodes
) {
if (nodes.
size() ==
0)
return;
blockType |= TYPE_NODES
;
if (skipNodes
)
return;
for (Osmformat.
Node i : nodes
) {
Node tmp =
new Node();
for (int j =
0; j
< i.
getKeysCount(); j++
)
tmp.
addTag(getStringById
(i.
getKeys(j
)), getStringById
(i.
getVals(j
)));
long id = i.
getId();
double latf = parseLat
(i.
getLat()), lonf = parseLon
(i.
getLon());
tmp.
set(id, latf, lonf
);
if (i.
hasInfo())
tmp.
setVersion(i.
getInfo().
getVersion());
processor.
processNode(tmp
);
elemCounter.
countNode(tmp.
getId());
}
}
@
Override
protected void parseWays
(List<Osmformat.
Way> ways
) {
long numways = ways.
size();
if (numways ==
0)
return;
blockType |= TYPE_WAYS
;
if (skipWays
)
return;
for (Osmformat.
Way i : ways
) {
Way tmp =
new Way
();
if (skipTags ==
false) {
for (int j =
0; j
< i.
getKeysCount(); j++
)
tmp.
addTag(getStringById
(i.
getKeys(j
)), getStringById
(i.
getVals(j
)));
}
long last_id =
0;
for (long j : i.
getRefsList()) {
tmp.
addRef(j + last_id
);
last_id = j + last_id
;
}
long id = i.
getId();
tmp.
setId(id
);
if (i.
hasInfo())
tmp.
setVersion(i.
getInfo().
getVersion());
processor.
processWay(tmp
);
elemCounter.
countWay(i.
getId());
}
}
@
Override
protected void parseRelations
(List<Osmformat.
Relation> rels
) {
if (rels.
size() ==
0)
return;
blockType |= TYPE_RELS
;
if (skipRels
)
return;
for (Osmformat.
Relation i : rels
) {
Relation tmp =
new Relation();
if (skipTags ==
false) {
for (int j =
0; j
< i.
getKeysCount(); j++
)
tmp.
addTag(getStringById
(i.
getKeys(j
)), getStringById
(i.
getVals(j
)));
}
long id = i.
getId();
tmp.
setId(id
);
tmp.
setVersion(i.
getInfo().
getVersion());
long last_mid =
0;
for (int j =
0; j
< i.
getMemidsCount(); j++
) {
long mid = last_mid + i.
getMemids(j
);
last_mid = mid
;
String role = getStringById
(i.
getRolesSid(j
));
String etype =
null;
if (i.
getTypes(j
) == Osmformat.
Relation.
MemberType.
NODE)
etype =
"node";
else if (i.
getTypes(j
) == Osmformat.
Relation.
MemberType.
WAY)
etype =
"way";
else if (i.
getTypes(j
) == Osmformat.
Relation.
MemberType.
RELATION)
etype =
"relation";
else
assert false; // TODO; Illegal file?
tmp.
addMember(etype, mid, role
);
}
processor.
processRelation(tmp
);
elemCounter.
countRelation(tmp.
getId());
}
}
@
Override
public void parse
(Osmformat.
HeaderBlock block
) {
for (String s : block.
getRequiredFeaturesList()) {
if (s.
equals("OsmSchema-V0.6"))
continue; // OK.
if (s.
equals("DenseNodes"))
continue; // OK.
throw new UnknownFeatureException
(s
);
}
if (block.
hasBbox()) {
final double multiplier = .000000001
;
double rightf = block.
getBbox().
getRight() * multiplier
;
double leftf = block.
getBbox().
getLeft() * multiplier
;
double topf = block.
getBbox().
getTop() * multiplier
;
double bottomf = block.
getBbox().
getBottom() * multiplier
;
if (msgLevel
> 0)
System.
out.
println("Bounding box " + leftf +
" " + bottomf +
" " + rightf +
" " + topf
);
Area area =
new Area(Utils.
toMapUnit(bottomf
), Utils.
toMapUnit(leftf
), Utils.
toMapUnit(topf
),
Utils.
toMapUnit(rightf
));
if (!area.
verify())
throw new IllegalArgumentException("invalid bbox area in pbf file: " + area
);
processor.
boundTag(area
);
}
}
}