// License: GPL. For details, see LICENSE file.
package s57;
import java.util.ArrayList;
import s57.S57map.AttMap;
import s57.S57map.Edge;
import s57.S57map.Feature;
import s57.S57map.ObjTab;
import s57.S57map.Pflag;
import s57.S57map.Prim;
import s57.S57map.Rflag;
import s57.S57map.Snode;
import s57.S57obj.Obj;
/**
* @author Malcolm Herring
*/
public final class S57box { //S57 bounding box truncation
private S57box() {
// Hide default constructor for utilities classes
}
// CHECKSTYLE.OFF: LineLength
enum Ext { I, N, W, S, E }
static Ext getExt(S57map map, double lat, double lon) {
if ((lat >= map.bounds.maxlat) && (lon < map.bounds.maxlon)) {
return Ext.N;
} else if (lon <= map.bounds.minlon) {
return Ext.W;
} else if (lat <= map.bounds.minlat) {
return Ext.S;
} else if (lon >= map.bounds.maxlon) {
return Ext.E;
}
return Ext.I;
}
public static void bBox(S57map map) {
/* Truncations
* Points: delete point features outside BB
* Lines: Truncate edges at BB boundaries
* Areas: Truncate edges of outers & inners and add new border edges. Merge inners to outer where necessary
* Remove nodes outside BB
* Remove edges that are completely outside BB
*/
class Land {
long first;
Snode start;
Ext sbound;
long last;
Snode end;
Ext ebound;
Feature land;
Land(Feature l) {
land = l;
first = last = 0;
start = end = null;
sbound = ebound = Ext.I;
}
}
if (map.features.get(Obj.COALNE) != null) {
ArrayList<Feature> coasts = new ArrayList<>();
ArrayList<Land> lands = new ArrayList<>();
if (map.features.get(Obj.LNDARE) == null) {
map.features.put(Obj.LNDARE, new ArrayList<Feature>());
}
for (Feature feature : map.features.get(Obj.COALNE)) {
Feature land = new Feature();
land.id = ++map.xref;
land.type = Obj.LNDARE;
land.reln = Rflag.MASTER;
land.objs.put(Obj.LNDARE, new ObjTab());
land.objs.get(Obj.LNDARE).put(0, new AttMap());
if (feature.geom.prim == Pflag.AREA) {
land.geom = feature.geom;
map.features.get(Obj.LNDARE).add(land);
} else if (feature.geom.prim == Pflag.LINE) {
land.geom.prim = Pflag.LINE;
land.geom.elems.addAll(feature.geom.elems);
coasts.add(land);
}
}
while (coasts.size() > 0) {
Feature land = coasts.remove(0);
Edge fedge = map.edges.get(land.geom.elems.get(0).id);
long first = fedge.first;
long last = map.edges.get(land.geom.elems.get(land.geom.elems.size() - 1).id).last;
if (coasts.size() > 0) {
boolean added = true;
while (added) {
added = false;
for (int i = 0; i < coasts.size(); i++) {
Feature coast = coasts.get(i);
Edge edge = map.edges.get(coast.geom.elems.get(0).id);
if (edge.first == last) {
land.geom.elems.add(coast.geom.elems.get(0));
last = edge.last;
coasts.remove(i--);
added = true;
} else if (edge.last == first) {
land.geom.elems.add(0, coast.geom.elems.get(0));
first = edge.first;
coasts.remove(i--);
added = true;
}
}
}
}
lands.add(new Land(land));
}
ArrayList<Land> islands = new ArrayList<>();
for (Land land : lands) {
map.sortGeom(land.land);
if (land.land.geom.prim == Pflag.AREA) {
islands.add(land);
map.features.get(Obj.LNDARE).add(land.land);
}
}
for (Land island : islands) {
lands.remove(island);
}
for (Land land : lands) {
land.first = map.edges.get(land.land.geom.elems.get(0).id).first;
land.start = map.nodes.get(land.first);
land.sbound = getExt(map, land.start.lat, land.start.lon);
land.last = map.edges.get(land.land.geom.elems.get(land.land.geom.comps.get(0).size - 1).id).last;
land.end = map.nodes.get(land.last);
land.ebound = getExt(map, land.end.lat, land.end.lon);
}
islands = new ArrayList<>();
for (Land land : lands) {
if ((land.sbound == Ext.I) || (land.ebound == Ext.I)) {
islands.add(land);
}
}
for (Land island : islands) {
lands.remove(island);
}
for (Land land : lands) {
Edge nedge = new Edge();
nedge.first = land.last;
nedge.last = land.first;
Ext bound = land.ebound;
while (bound != land.sbound) {
switch (bound) {
case N:
nedge.nodes.add(1L);
bound = Ext.W;
break;
case W:
nedge.nodes.add(2L);
bound = Ext.S;
break;
case S:
nedge.nodes.add(3L);
bound = Ext.E;
break;
case E:
nedge.nodes.add(4L);
bound = Ext.N;
break;
default:
continue;
}
}
map.edges.put(++map.xref, nedge);
land.land.geom.elems.add(new Prim(map.xref));
land.land.geom.comps.get(0).size++;
land.land.geom.prim = Pflag.AREA;
map.features.get(Obj.LNDARE).add(land.land);
}
}
return;
}
}