// License: GPL. For details, see LICENSE file. package indoor_sweepline; import java.util.List; import java.util.Vector; import org.openstreetmap.josm.data.coor.LatLon; import org.openstreetmap.josm.data.osm.DataSet; import org.openstreetmap.josm.data.osm.Node; import org.openstreetmap.josm.data.osm.OsmPrimitive; import org.openstreetmap.josm.data.osm.Relation; import org.openstreetmap.josm.data.osm.RelationMember; import org.openstreetmap.josm.data.osm.Way; public class ModelGeography { public ModelGeography(DataSet dataSet, LatLon center) { beamsGeography = new Vector<>(); this.dataSet = dataSet; this.center = center; wayPool = new Vector<>(); wayPoolCount = 0; nodePool = new Vector<>(); nodePoolCount = 0; nodes = null; multipolygon = null; members = null; } private Vector<BeamGeography> beamsGeography; private DataSet dataSet; private LatLon center; private Vector<Way> wayPool; private int wayPoolCount; private Vector<Node> nodePool; private int nodePoolCount; private Vector<Node> nodes; private Relation multipolygon; private Vector<RelationMember> members; public void appendNode(Node node) { nodes.add(node); } public DataSet getDataSet() { return dataSet; } public BeamGeography beamAt(int i) { return beamsGeography.elementAt(i); } public void startGeographyBuild(Vector<Beam> beams, Vector<Strip> strips) { if (beamsGeography.size() < beams.size()) beamsGeography.setSize(beams.size()); double offset = 0; for (int i = 0; i < beams.size(); ++i) { if (beamsGeography.elementAt(i) == null) beamsGeography.setElementAt(new BeamGeography(dataSet, this), i); beamsGeography.elementAt(i).adjustNodes(new LatLon(center.lat(), addMetersToLon(center, offset)), beams.elementAt(i).getBeamParts(), beams.elementAt(i).getBeamOffset()); if (i < strips.size()) offset += strips.elementAt(i).width; } nodePoolCount = 0; wayPoolCount = 0; members = new Vector<>(); if (multipolygon != null) multipolygon.setMembers(members); } public void startWay() { nodes = new Vector<>(); } public void finishWay(Strip strip, int partIndex, boolean isOuter, String level) { if (nodes.size() > 0) { CorridorPart part = strip.partAt(partIndex); strip.geographyAt(partIndex).appendNodes(part.getType(), part.getSide(), level, nodes.elementAt(nodes.size()-1).getCoor(), nodes.elementAt(0).getCoor(), this); nodes.add(nodes.elementAt(0)); } assignNds(nodes); members.add(new RelationMember(isOuter ? "outer" : "inner", wayPool.elementAt(wayPoolCount))); ++wayPoolCount; } public void appendCorridorPart(CorridorPart part, CorridorGeography partGeography, int beamIndex, int partIndex, String level) { if (nodes.size() > 0) partGeography.appendNodes(part.getType(), part.getSide(), level, nodes.elementAt(nodes.size()-1).getCoor(), beamsGeography.elementAt(beamIndex).coorAt(partIndex), this); } public void appendUturnNode(Strip strip, int partIndex, int stripIndex, int beamNodeIndex, boolean toTheLeft, String level) { if (toTheLeft) assignCoor(addMeterOffset(beamsGeography.elementAt(stripIndex + 1).coorAt(beamNodeIndex), 0, -strip.width / 2.)); else assignCoor(addMeterOffset(beamsGeography.elementAt(stripIndex).coorAt(beamNodeIndex), 0, strip.width / 2.)); if (nodes.size() > 0) { CorridorPart part = strip.partAt(partIndex); strip.geographyAt(partIndex).appendNodes(part.getType(), part.getSide(), level, nodes.elementAt(nodes.size()-1).getCoor(), nodePool.elementAt(nodePoolCount).getCoor(), this); } nodes.add(nodePool.elementAt(nodePoolCount)); ++nodePoolCount; } public void finishGeographyBuild(IndoorSweeplineModel.Type type, String level) { for (int i = nodePoolCount; i < nodePool.size(); ++i) { nodePool.elementAt(i).setDeleted(true); } nodePool.setSize(nodePoolCount); for (int i = wayPoolCount; i < wayPool.size(); ++i) { wayPool.elementAt(i).setDeleted(true); } wayPool.setSize(wayPoolCount); adjustMultipolygonRelation(type, level); } private static LatLon addMeterOffset(LatLon latLon, double south, double east) { double scale = Math.cos(latLon.lat() * (Math.PI/180.)); return new LatLon(latLon.lat() - south *(360./4e7), latLon.lon() + east / scale *(360./4e7)); } private static double addMetersToLon(LatLon latLon, double east) { double scale = Math.cos(latLon.lat() * (Math.PI/180.)); return latLon.lon() + east / scale *(360./4e7); } private void assignCoor(LatLon latLon) { if (nodePoolCount < nodePool.size()) nodePool.elementAt(nodePoolCount).setCoor(latLon); else { Node node = new Node(latLon); dataSet.addPrimitive(node); nodePool.add(node); } } private void assignNds(List<Node> nodes) { if (wayPoolCount < wayPool.size()) wayPool.elementAt(wayPoolCount).setNodes(nodes); else { Way way = new Way(); way.setNodes(nodes); dataSet.addPrimitive(way); wayPool.add(way); } } private static void addPolygonTags(IndoorSweeplineModel.Type type, String level, OsmPrimitive obj) { if (type == IndoorSweeplineModel.Type.PLATFORM) { obj.put("railway", "platform"); obj.put("public_transport", "platform"); obj.put("area", "yes"); obj.put("level", level); } else { obj.put("highway", "pedestrian"); obj.put("indoor", "corridor"); obj.put("area", "yes"); obj.put("level", level); } } private void adjustMultipolygonRelation(IndoorSweeplineModel.Type type, String level) { if (members.size() > 1) { if (wayPool.size() > 0) wayPool.elementAt(0).removeAll(); if (multipolygon == null) { multipolygon = new Relation(); dataSet.addPrimitive(multipolygon); } multipolygon.removeAll(); multipolygon.put("type", "multipolygon"); addPolygonTags(type, level, multipolygon); multipolygon.setMembers(members); } else { if (multipolygon != null) { multipolygon.setDeleted(true); multipolygon = null; } if (wayPool.size() == 1) { wayPool.elementAt(0).removeAll(); addPolygonTags(type, level, wayPool.elementAt(0)); } } } }