Rev 36 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
* Copyright (C) 2006 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 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.
*
*
* Author: Steve Ratcliffe
* Create date: 16-Dec-2006
*/
package uk.me.parabola.splitter;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
import java.io.IOException;
import java.util.Date;
/**
* Parser for the second pass where we divide up the input file into the
* individual files.
*
* @author Steve Ratcliffe
*/
class SplitParser
extends DefaultHandler {
private static final int MODE_NODE =
1;
private static final int MODE_WAY =
2;
private static final int MODE_RELATION =
3;
private static String last_desc =
"";
private int mode
;
private final SplitIntCharMap coords =
new SplitIntCharMap
();
private final SplitIntMap ways =
new SplitIntMap
();
private final SubArea
[] areas
;
private StringNode currentNode
;
private int currentNodeAreaSet
;
private AreaSet currentNodeSet
;
private StringWay currentWay
;
private int currentWayAreaSet
;
private StringRelation currentRelation
;
private int currentRelAreaSet
;
private Stats stats =
new Stats
();
SplitParser
(SubArea
[] areas
) {
this.
areas = areas
;
}
/**
* Called at the start of an element.
*/
public void startElement
(String uri,
String localName,
String qName,
Attributes attributes
)
throws SAXException
{
if (mode ==
0) {
if (qName.
equals("node")) {
mode = MODE_NODE
;
stats.
nNodes++
;
String id = attributes.
getValue("id");
String slat = attributes.
getValue("lat");
String slon = attributes.
getValue("lon");
double lat =
Double.
parseDouble(slat
);
double lon =
Double.
parseDouble(slon
);
Coord coord =
new Coord
(lat, lon
);
currentNode =
new StringNode
(coord, id, slat, slon
);
currentNodeSet.
reset();
} else if (qName.
equals("way")) {
mode = MODE_WAY
;
stats.
nWays++
;
String id = attributes.
getValue("id");
currentWay =
new StringWay
(id
);
currentWayAreaSet =
0;
} else if (qName.
equals("relation")) {
mode = MODE_RELATION
;
stats.
nRelations++
;
String id = attributes.
getValue("id");
currentRelation =
new StringRelation
(id
);
currentRelAreaSet =
0;
}
} else if (mode == MODE_NODE
) {
if (qName.
equals("tag")) {
currentNode.
addTag(attributes.
getValue("k"), attributes.
getValue("v"));
}
} else if (mode == MODE_WAY
) {
if (qName.
equals("nd")) {
String sid = attributes.
getValue("ref");
// Get the list of areas that the node is in. A node may be in
// more than one area because of overlap.
int set = coords.
get(Integer.
parseInt(sid
));
// add the list of areas to the currentWayAreaSet
if (currentWayAreaSet == set
) {
// nothing to do, this will be the most common case
} else if (currentWayAreaSet ==
0) {
currentWayAreaSet = set
;
} else {
int mask = 0xff
;
for (int slot =
0; slot
< 4; slot++, mask
<<=
8) {
int val =
(set
& mask
) >>> (slot
* 8);
if (val ==
0)
break;
// Now find it in the destination set or add it
currentWayAreaSet = addToSet
(currentWayAreaSet, val,
"Way " + currentWay.
getStringId());
}
}
currentWay.
addRef(sid
);
} else if (qName.
equals("tag")) {
currentWay.
addTag(attributes.
getValue("k"),
attributes.
getValue("v"));
}
} else if (mode == MODE_RELATION
) {
if (qName.
equals("tag")) {
currentRelation.
addTag(attributes.
getValue("k"), attributes.
getValue("v"));
} else if (qName.
equals("member")) {
String type = attributes.
getValue("type");
String ref = attributes.
getValue("ref");
currentRelation.
addMember(type, ref, attributes.
getValue("role"));
int iref =
Integer.
parseInt(ref
);
int set =
0;
if ("node".
equals(type
)) {
set = coords.
get(iref
);
} else if ("way".
equals(type
)) {
set = ways.
get(iref
);
}
if (currentRelAreaSet == set
) {
// nothing to do
} else if (currentRelAreaSet ==
0) {
currentRelAreaSet = set
;
} else {
int mask = 0xff
;
for (int slot =
0; slot
< 4; slot++, mask
<<=
8) {
int val =
(set
& mask
) >>> (slot
* 8);
if (val ==
0)
break;
// Now find it in the destination set or add it
currentRelAreaSet = addToSet
(currentRelAreaSet, val,
"Relation " + currentRelation.
getId());
}
}
}
}
}
/**
* Receive notification of the end of an element.
*
* @param uri The Namespace URI, or the empty string if the
* element has no Namespace URI or if Namespace
* processing is not being performed.
* @param localName The local name (without prefix), or the
* empty string if Namespace processing is not being
* performed.
* @param qName The qualified name (with prefix), or the
* empty string if qualified names are not available.
* @throws SAXException Any SAX exception, possibly
* wrapping another exception.
* @see ContentHandler#endElement
*/
public void endElement
(String uri,
String localName,
String qName
)
throws SAXException
{
if (mode == MODE_NODE
) {
if (qName.
equals("node")) {
mode =
0;
try {
writeNode
();
} catch (IOException e
) {
throw new SAXException("failed to write", e
);
}
}
} else if (mode == MODE_WAY
) {
if (qName.
equals("way")) {
mode =
0;
try {
writeWay
(currentWay
);
} catch (IOException e
) {
throw new SAXException("failed to write way", e
);
}
}
} else if (mode == MODE_RELATION
) {
if (qName.
equals("relation")) {
mode =
0;
try {
writeRelation
(currentRelation
);
} catch (IOException e
) {
throw new SAXException("failed to write relation", e
);
}
}
}
}
private int addToSet
(int set,
int v,
String desc
) {
int val = v
;
for (int mask = 0xff
; mask
!=
0; mask
<<=
8) {
int setval = set
& mask
;
if (setval ==
0) {
return set | val
;
} else if (setval == val
) {
return set
;
}
val
<<=
8;
}
// it was not added
if (!last_desc.
equals(desc
)) {
System.
err.
println(desc +
" in too many areas.");
last_desc = desc
;
}
return set
;
}
private boolean seenRel
;
private void writeRelation
(StringRelation relation
) throws IOException {
if (!seenRel
) {
seenRel =
true;
System.
out.
println("starting rels " +
new Date());
}
for (int slot =
0; slot
< 4; slot++
) {
int n =
(currentRelAreaSet
>> (slot
* 8)) & 0xff
;
if (n ==
0)
break;
// if n is out of bounds, then something has gone wrong
areas
[n -
1].
write(relation
);
}
}
private boolean seenWay
;
private void writeWay
(StringWay way
) throws IOException {
if (!seenWay
) {
seenWay =
true;
System.
out.
println("starting ways " +
new Date());
}
for (int slot =
0; slot
< 4; slot++
) {
int n =
(currentWayAreaSet
>> (slot
* 8)) & 0xff
;
if (n ==
0)
break;
// if n is out of bounds, then something has gone wrong
areas
[n -
1].
write(way
);
}
ways.
put(way.
getId(), currentWayAreaSet
);
}
/**
* Go through all the areas and see which ones the node belongs to. There can be more
* than one, because we test against the extended area which overlaps with other areas.
*
* @throws IOException If the write fails for any reason.
*/
private void writeNode
() throws IOException {
StringNode node = currentNode
;
for (int n =
1; n
<= areas.
length; n++
) {
SubArea a = areas
[n-
1];
if (a.
containedInExtendedArea(node.
getLocation())) {
a.
write(node
);
currentNodeSet.
add(a
);
}
}
//coords.put(node.getId(), currentNodeSet);
}
private void addAreaForNode
(SubArea a
) {
assert false;
}
public void fatalError
(SAXParseException e
) throws SAXException {
System.
err.
println("Error at line " + e.
getLineNumber() +
", col "
+ e.
getColumnNumber());
super.
fatalError(e
);
}
private static class Stats
{
private int nNodes
;
private int nWays
;
private int nRelations
;
private int nNodeOverlaps
;
}
private class AreaSet
{
public void reset
() {
}
public void add
(SubArea area
) {
}
}
}