// License: GPL. For details, see LICENSE file.
package js57toosm;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Map;
import java.util.Scanner;
import org.apache.commons.lang3.StringEscapeUtils;
import s57.S57att;
import s57.S57att.Att;
import s57.S57dec;
import s57.S57map;
import s57.S57map.AttMap;
import s57.S57map.Feature;
import s57.S57map.GeomIterator;
import s57.S57map.ObjTab;
import s57.S57map.Pflag;
import s57.S57map.Prim;
import s57.S57map.Rflag;
import s57.S57map.Snode;
import s57.S57obj;
import s57.S57obj.Obj;
import s57.S57val;
import s57.S57val.AttVal;
/**
* @author Malcolm Herring
*/
public final class Js57toosm {
private Js57toosm() {
// Hide default constructor for utilities classes
}
static FileInputStream in;
static PrintStream out;
static S57map map;
static final ArrayList<Att> typatts = new ArrayList<>(); static {
typatts.add(Att.OBJNAM); typatts.add(Att.NOBJNM); typatts.add(Att.STATUS); typatts.add(Att.INFORM); typatts.add(Att.NINFOM);
typatts.add(Att.PEREND); typatts.add(Att.PERSTA); typatts.add(Att.CONDTN); typatts.add(Att.CONRAD); typatts.add(Att.CONVIS);
}
public static void main(String[] args) throws IOException {
ArrayList<Long> done = new ArrayList<>();
if (args.length < 3) {
System.err.println("Usage: java -jar js57toosm.jar S57_filename types_filename OSM_filename");
System.exit(-1);
}
try {
in = new FileInputStream(args[0]);
} catch (IOException e) {
System.err.println("Input file: " + e.getMessage());
System.exit(-1);
}
try {
out = new PrintStream(args[2]);
} catch (IOException e) {
System.err.println("Output file: " + e.getMessage());
in.close();
System.exit(-1);
}
ArrayList<Obj> types = new ArrayList<>();
try {
Scanner tin = new Scanner(new FileInputStream(args[1]));
while (tin.hasNext()) {
Obj type = S57obj.enumType(tin.next());
if (type != Obj.UNKOBJ)
types.add(type);
}
tin.close();
} catch (IOException e) {
System.err.println("Types file: " + e.getMessage());
in.close();
out.close();
System.exit(-1);
}
map = new S57map(true);
S57dec.decodeChart(in, map);
out.format("<?xml version='1.0' encoding='UTF-8'?>%n");
out.format("<osm version='0.6' upload='false' generator='js57toosm'>%n");
out.format("<bounds minlat='%.8f' minlon='%.8f' maxlat='%.8f' maxlon='%.8f'/>%n",
Math.toDegrees(map.bounds.minlat), Math.toDegrees(map.bounds.minlon),
Math.toDegrees(map.bounds.maxlat), Math.toDegrees(map.bounds.maxlon));
for (long id : map.index.keySet()) {
Feature feature = map.index.get(id);
String type = S57obj.stringType(feature.type);
if (!type.isEmpty() && (types.isEmpty() || types.contains(feature.type))) {
if (feature.reln == Rflag.MASTER) {
if (feature.geom.prim == Pflag.POINT) {
for (Prim prim : feature.geom.elems) {
long ref = prim.id;
Snode node;
while ((node = map.nodes.get(ref)) != null) {
if (!done.contains(ref)) {
out.format(" <node id='%d' lat='%.8f' lon='%.8f' version='1'>%n",
-ref, Math.toDegrees(node.lat), Math.toDegrees(node.lon));
out.format(" <tag k='seamark:type' v=\"%s\"/>%n", type);
if ((feature.type == Obj.SOUNDG) && (node.flg == S57map.Nflag.DPTH))
out.format(" <tag k='seamark:sounding:depth' v='%.1f'/>%n", node.val);
writeAtts(feature);
out.format(" </node>%n");
done.add(ref);
}
ref++;
}
}
}
}
}
}
for (long id : map.index.keySet()) {
Feature feature = map.index.get(id);
String type = S57obj.stringType(feature.type);
if (!type.isEmpty() && (types.isEmpty() || types.contains(feature.type))) {
if (feature.reln == Rflag.MASTER) {
if ((feature.geom.prim == Pflag.LINE) ||
((feature.geom.prim == Pflag.AREA) && (feature.geom.outers == 1) && (feature.geom.inners == 0))) {
GeomIterator git = map.new GeomIterator(feature.geom);
while (git.hasComp()) {
git.nextComp();
while (git.hasEdge()) {
git.nextEdge();
while (git.hasNode()) {
long ref = git.nextRef();
Snode node = map.nodes.get(ref);
if (!done.contains(ref)) {
out.format(" <node id='%d' lat='%.8f' lon='%.8f' version='1'/>%n",
-ref, Math.toDegrees(node.lat), Math.toDegrees(node.lon));
done.add(ref);
}
}
}
}
git = map.new GeomIterator(feature.geom);
while (git.hasComp()) {
long edge = git.nextComp();
out.format(" <way id='%d' version='1'>%n", -edge);
while (git.hasEdge()) {
git.nextEdge();
while (git.hasNode()) {
long ref = git.nextRef();
out.format(" <nd ref='%d'/>%n", -ref);
}
}
out.format(" <tag k='seamark:type' v='%s'/>%n", type);
writeAtts(feature);
out.format(" </way>%n");
}
} else if (feature.geom.prim == Pflag.AREA) {
GeomIterator git = map.new GeomIterator(feature.geom);
while (git.hasComp()) {
git.nextComp();
while (git.hasEdge()) {
git.nextEdge();
while (git.hasNode()) {
long ref = git.nextRef();
Snode node = map.nodes.get(ref);
if (!done.contains(ref)) {
out.format(" <node id='%d' lat='%.8f' lon='%.8f' version='1'/>%n",
-ref, Math.toDegrees(node.lat), Math.toDegrees(node.lon));
done.add(ref);
}
}
}
}
git = map.new GeomIterator(feature.geom);
while (git.hasComp()) {
long ref = git.nextComp();
out.format(" <way id='%d' version='1'>%n", -ref);
while (git.hasEdge()) {
git.nextEdge();
while (git.hasNode()) {
ref = git.nextRef();
out.format(" <nd ref='%d'/>%n", -ref);
}
}
out.format(" </way>%n");
}
out.format(" <relation id='%d' version='1'>%n", -map.xref++);
out.format(" <tag k='type' v='multipolygon'/>%n");
git = map.new GeomIterator(feature.geom);
int outers = feature.geom.outers;
while (git.hasComp()) {
long ref = git.nextComp();
if (outers-- > 0) {
out.format(" <member type='way' ref='%d' role='outer'/>%n", -ref);
} else {
out.format(" <member type='way' ref='%d' role='inner'/>%n", -ref);
}
}
out.format(" <tag k='seamark:type' v='%s'/>%n", type);
writeAtts(feature);
out.format(" </relation>%n");
}
}
}
}
out.println("</osm>\n");
out.close();
System.err.println("Finished");
}
static void writeAtts(Feature feature) {
for (Map.Entry<Att, AttVal<?>> item : feature.atts.entrySet()) {
String attstr = S57att.stringAttribute(item.getKey());
String valstr = S57val.stringValue(item.getValue(), item.getKey());
if (!attstr.isEmpty() && !valstr.isEmpty()) {
if (typatts.contains(item.getKey())) {
out.format(" <tag k='seamark:%s' v='%s'/>%n", attstr, StringEscapeUtils.escapeXml10(valstr));
} else {
out.format(" <tag k='seamark:%s:%s' v='%s'/>%n",
S57obj.stringType(feature.type), attstr, StringEscapeUtils.escapeXml10(valstr));
}
}
}
for (Obj obj : feature.objs.keySet()) {
ObjTab tab = feature.objs.get(obj);
for (int ix : tab.keySet()) {
AttMap atts = tab.get(ix);
for (Map.Entry<Att, AttVal<?>> item : atts.entrySet()) {
String attstr = S57att.stringAttribute(item.getKey());
String valstr = S57val.stringValue(item.getValue(), item.getKey());
if (!attstr.isEmpty() && !valstr.isEmpty()) {
if ((ix == 0) && (tab.size() == 1)) {
out.format(" <tag k='seamark:%s:%s' v='%s'/>%n",
S57obj.stringType(obj), attstr, StringEscapeUtils.escapeXml10(valstr));
} else {
out.format(" <tag k='seamark:%s:%d:%s' v='%s'/>%n",
S57obj.stringType(obj), ix + 1, attstr, StringEscapeUtils.escapeXml10(valstr));
}
}
}
}
}
}
}