/* javac -d ./class encoder/*.java java -Dfile.encoding=UTF-8 -Xmx5g -classpath ./class Encoder japan */ import java.io.*; import java.nio.*; import java.util.*; import java.nio.file.Paths; import javax.xml.parsers.*; import org.xml.sax.*; import org.xml.sax.helpers.DefaultHandler; public class Encoder extends DefaultHandler { enum Section { none, node, way, relation } final double E7 = 10000000.0; String dirDst; DataOutputStream dos; int cntFile; int sizeFile; // 単位: バイト Section section = Section.none; static int sizeStr = 0; static long totalSizeFile = 0; static long maxId = 0; static int nodes=0, ways=0, rels=0; //int tags; // オブジェクト毎のタグ数 ByteBuffer bbTag; HashSet setNodes; // 有効タグを持つノード(ファイル出力したもの) long id; int lon, lat; long[] nids = new long[0x10000000]; int[] lons = new int[0x10000000]; int[] lats = new int[0x10000000]; int nEntry; public Encoder(String dir) { this.dirDst = dir; nEntry = 0; } DataOutputStream getDataOutputStream() { try { sizeFile = 0; String path = dirDst + section.name() + cntFile + ".obf"; return new DataOutputStream(new BufferedOutputStream(new FileOutputStream(path))); } catch (IOException ex) { ex.printStackTrace(); return null; } } void close(DataOutputStream dos) { try { dos.flush(); dos.close(); totalSizeFile += sizeFile; } catch (IOException ex) { ex.printStackTrace(); } } int getLonLatIx(long id) { int ix = binary_search(id, 0, nEntry-1); if (ix < 0) { System.out.println("座標値が見つからない id=" + id); } return ix; } int binary_search(long id, int imin, int imax) { if (imax < imin) { return -1; // id が見つからなかった } else { int imid = imin + (imax - imin) / 2; if (nids[imid] > id) { return binary_search(id, imin, imid - 1); } else if (nids[imid] < id) { return binary_search(id, imid + 1, imax); } else { return imid; } } } public void startElement (String namespaceURI, String localName, String qName, Attributes atts ) { if (qName.equals("node")) { // nodeオブジェクトの開始処理 nodes++; bbTag = ByteBuffer.allocate(1000); if (section != Section.node) { System.out.println("Node Section starts."); section = Section.node; cntFile = 0; dos = getDataOutputStream(); setNodes = new HashSet<>(); } String s_id = atts.getValue("id"); String s_lon = atts.getValue("lon"); String s_lat = atts.getValue("lat"); try { id = Long.parseLong(s_id); lon = (int)(Double.parseDouble(s_lon) * E7); lat = (int)(Double.parseDouble(s_lat) * E7); if (id > maxId) maxId = id; nids[nEntry] = id; lons[nEntry] = lon; lats[nEntry] = lat; nEntry++; } catch (NumberFormatException e) { System.out.printf("Error node: %s %s %s\n", s_id, s_lon, s_lat); } } else if (qName.equals("way")) { // wayオブジェクトの開始処理 ways++; bbTag = ByteBuffer.allocate(1000); if (section != Section.way) { System.out.println("Way Section starts."); section = Section.way; close(dos); cntFile = 0; dos = getDataOutputStream(); } String s_id = atts.getValue("id"); try { id = Long.parseLong(s_id); writeId(2, id); } catch (NumberFormatException e) { System.out.printf("Error way: %s\n", s_id); } } else if (qName.equals("relation")) { // relationオブジェクトの開始処理 rels++; bbTag = ByteBuffer.allocate(1000); if (section != Section.relation) { System.out.println("Relation Section starts."); section = Section.relation; cntFile = 0; close(dos); dos = getDataOutputStream(); } String s_id = atts.getValue("id"); try { id = Long.parseLong(s_id); writeId(3, id); } catch (NumberFormatException e) { System.out.printf("Error relation: %s\n", s_id); } } else if (qName.equals("tag")) { // tagオブジェクトの開始処理 … node, way, relationの子供 String skey = atts.getValue("k"); if (Tag.setKeys.contains(skey)) { String val = atts.getValue("v"); Key key = Key.valueOf(skey); int ikey = key.ordinal(); if (ikey < Key.endCodeKey.ordinal() || ikey > Key.endFloatKey.ordinal()) { if (Tag.setVals.contains(val)) { int ival = Val.valueOf(val).ordinal(); writeInt(ikey); writeInt(ival); } } else if (ikey < Key.endStrKey.ordinal()) { writeInt(ikey); writeBytes(val); } else if (ikey < Key.endIntKey.ordinal()) { try { int v = Integer.parseInt(val); writeInt(ikey); writeInt(v); } catch (NumberFormatException e) { try { Key s_key = Key.valueOf("s_" + skey); writeInt(s_key.ordinal()); writeBytes(val); } catch (Exception ex) { System.out.println("Error IntTag: " + key + "=" + val); } } // エラーがあったときはタグを無視する } else if (ikey <= Key.endFloatKey.ordinal()) { val = val.replace("m", ""); try { float v = Float.parseFloat(val); writeInt(ikey); writeFloat(v); } catch (NumberFormatException e) { try { Key s_key = Key.valueOf("s_" + skey); writeInt(s_key.ordinal()); writeBytes(val); } catch (Exception ex) { System.out.println("Error FloatTag: " + key + "=" + val); } } } else { System.out.println(key + "=" + val); } } } else if (qName.equals("nd")) { // ndオブジェクトの開始処理 … wayオブジェクトの子供 String ref = atts.getValue("ref"); try { long v = Long.parseLong(ref); int ix = getLonLatIx(v); int lon = lons[ix]; int lat = lats[ix]; writeInt(lon); writeInt(lat); } catch (NumberFormatException e) { System.out.println("Error nd.ref: " + ref); } // ここでのエラーはない } else if (qName.equals("member")) { // memberオブジェクトの開始処理 … relationオブジェクトの子供 String s_type = atts.getValue("type"); String s_ref = atts.getValue("ref"); String s_role = atts.getValue("role"); int type = s_type.equals("node") ? 1 : s_type.equals("way") ? 2 : s_type.equals("relation") ? 3 : 0; try { long v = Long.parseLong(s_ref); writeId(20+type, v); writeBytes(s_role); } catch (NumberFormatException e) { System.out.println("Error nd.ref: " + s_ref); } // ここでのエラーはない //System.out.printf("type='%d' ref='%s' role='%s'\n", type, s_ref, s_role); } } public void endElement(String namespaceURI, String localName, String qName) { if (qName.equals("node")) { // nodeオブジェクトの終了処理 if (bbTag.position() > 0) { try { dos.write(bbTag.array(), 0, bbTag.position()); } catch (IOException e) { e.printStackTrace(); } } } else if (qName.equals("way")) { // wayオブジェクトの終了処理 } else if (qName.equals("relation")) { // relationオブジェクトの終了処理 } else if (qName.equals("osm")) { close(dos); // 最後の出力ファイルをクローズする } if (sizeFile >= 1024*1024*1024) { close(dos); cntFile++; dos = getDataOutputStream(); } } void writeInt(int n) { try { dos.writeInt(n); sizeFile += 4; } catch (IOException ex) { ex.printStackTrace(); } } void writeLong(long n) { try { dos.writeLong(n); sizeFile += 8; } catch (IOException ex) { ex.printStackTrace(); } } void writeFloat(float n){ try { dos.writeFloat(n); sizeFile += 4; } catch (IOException ex) { ex.printStackTrace(); } } void writeBytes(String str){ try { dos.writeShort(str.length()*2); dos.writeBytes(str); sizeFile += str.length()*2 + 2; sizeStr += str.length()*2 + 2; } catch (IOException ex) { ex.printStackTrace(); } } void writeId(int type, long n) { try { short high = (short)(n >> 32); int low = (int)(n & 0xffffffff); dos.writeShort((short)type | high); dos.writeInt(low); sizeFile += 6; } catch (IOException ex) { ex.printStackTrace(); } } public static void main( String[] args ) throws Exception { long start = System.currentTimeMillis(); String src = "c:/map/data/" + args[0] + ".osm"; String dstDir = "c:/map/obf/" + args[0] + "/"; SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser parser = factory.newSAXParser(); Encoder handler = new Encoder(dstDir); parser.parse(Paths.get(src).toFile(), handler); System.out.printf("maxId=%X, nodes=%X, ways=%X, rels=%X, sizeStr=%d, 総サイズ=%.2fGB 実行時間: %.2f分\n", maxId, nodes, ways, rels, sizeStr, totalSizeFile/1024.0/1024/1024, (System.currentTimeMillis()-start)/60000.0); } }