// License: GPL. For details, see LICENSE file. package indoor_sweepline; import java.util.List; import java.util.Vector; import javax.swing.DefaultComboBoxModel; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.data.coor.LatLon; import org.openstreetmap.josm.gui.layer.OsmDataLayer; /* TODO: - focus to useful table entry after cell edit - keyboard shortcuts */ public class IndoorSweeplineModel { public enum Type { CORRIDOR, PLATFORM } public IndoorSweeplineModel(OsmDataLayer activeLayer, LatLon center) { target = new ModelGeography(activeLayer.data, center); beams = new Vector<>(); strips = new Vector<>(); type = Type.CORRIDOR; level = "-1"; addBeam(); addStrip(); addBeam(); structureBox = new DefaultComboBoxModel<>(); } private ModelGeography target; public void addBeam() { CorridorPart.ReachableSide side = CorridorPart.ReachableSide.LEFT; if (beams.size() == 0) side = CorridorPart.ReachableSide.RIGHT; /*double width = 10.; if (beams.size() > 0) { width = 0; for (CorridorPart part : beams.elementAt(beams.size() - 1).getBeamParts()) width += part.width; } double offset = 0; for (int i = 0; i < strips.size(); ++i) offset += strips.elementAt(i).width;*/ if (strips.size() == 0) { Vector<Double> blueprint = new Vector<>(); blueprint.addElement(0.); blueprint.addElement(10.); beams.add(new Beam(blueprint, 0., side)); } else beams.add(new Beam(strips.elementAt(strips.size()-1).lhs, beams.elementAt(beams.size()-1).getBeamOffset(), side)); if (strips.size() > 0) strips.elementAt(beams.size()-2).rhs = beams.elementAt(beams.size()-1).leftHandSideStrips(); updateOsmModel(); } public void addStrip() { strips.add(new Strip(target.getDataSet())); if (beams.size() > 1) { beams.elementAt(beams.size()-1).setDefaultSide(CorridorPart.ReachableSide.ALL); strips.elementAt(strips.size()-2).rhs = beams.elementAt(strips.size()-1).leftHandSideStrips(); } strips.elementAt(strips.size()-1).lhs = beams.elementAt(strips.size()-1).rightHandSideStrips(); updateOsmModel(); } public int leftRightCount() { return beams.size() + strips.size(); } public DefaultComboBoxModel<String> structures() { structureBox.removeAllElements(); double offset = 0; for (int i = 0; i < strips.size(); ++i) { if (i < beams.size()) structureBox.addElement(Double.toString(offset)); structureBox.addElement(Double.toString(offset) + " - " + Double.toString(offset + strips.elementAt(i).width)); offset += strips.elementAt(i).width; } if (strips.size() < beams.size()) structureBox.addElement(Double.toString(offset)); return structureBox; } public Strip getStrip(int index) { return strips.elementAt(index / 2); } public double getStripWidth(int index) { return strips.elementAt(index / 2).width; } public void setStripWidth(int index, double value) { strips.elementAt(index / 2).width = value; updateOsmModel(); } public double getBeamOffset(int index) { return beams.elementAt(index / 2).getBeamOffset(); } public void setBeamOffset(int index, double beamOffset) { beams.elementAt(index / 2).setBeamOffset(beamOffset); updateOsmModel(); } public List<CorridorPart> getBeamParts(int index) { return beams.elementAt(index / 2).getBeamParts(); } public void addCorridorPart(int beamIndex, boolean append, double value) { beams.elementAt(beamIndex / 2).addCorridorPart(append, value); if (beamIndex / 2 > 0) strips.elementAt(beamIndex / 2 - 1).rhs = beams.elementAt(beamIndex / 2).leftHandSideStrips(); if (beamIndex / 2 < strips.size()) strips.elementAt(beamIndex / 2).lhs = beams.elementAt(beamIndex / 2).rightHandSideStrips(); updateOsmModel(); } public void setCorridorPartWidth(int beamIndex, int partIndex, double value) { beams.elementAt(beamIndex / 2).setCorridorPartWidth(partIndex, value); if (beamIndex / 2 > 0) strips.elementAt(beamIndex / 2 - 1).rhs = beams.elementAt(beamIndex / 2).leftHandSideStrips(); if (beamIndex / 2 < strips.size()) strips.elementAt(beamIndex / 2).lhs = beams.elementAt(beamIndex / 2).rightHandSideStrips(); updateOsmModel(); } public void setCorridorPartType(int beamIndex, int partIndex, CorridorPart.Type type) { if (beamIndex % 2 == 0) { beams.elementAt(beamIndex / 2).setCorridorPartType(partIndex, type); if (beamIndex / 2 > 0) strips.elementAt(beamIndex / 2 - 1).rhs = beams.elementAt(beamIndex / 2).leftHandSideStrips(); if (beamIndex / 2 < strips.size()) strips.elementAt(beamIndex / 2).lhs = beams.elementAt(beamIndex / 2).rightHandSideStrips(); } else { if (type != CorridorPart.Type.PASSAGE && type != CorridorPart.Type.VOID) strips.elementAt(beamIndex / 2).setCorridorPartType(partIndex, type); } updateOsmModel(); } public void setCorridorPartSide(int beamIndex, int partIndex, CorridorPart.ReachableSide side) { beams.elementAt(beamIndex / 2).setCorridorPartSide(partIndex, side); if (beamIndex / 2 > 0) strips.elementAt(beamIndex / 2 - 1).rhs = beams.elementAt(beamIndex / 2).leftHandSideStrips(); if (beamIndex / 2 < strips.size()) strips.elementAt(beamIndex / 2).lhs = beams.elementAt(beamIndex / 2).rightHandSideStrips(); updateOsmModel(); } public Type getType() { return type; } public void setType(Type type) { this.type = type; updateOsmModel(); } public String getLevel() { return level; } public void setLevel(String level) { this.level = level; updateOsmModel(); } private Vector<Beam> beams; private Vector<Strip> strips; private Type type; private String level; DefaultComboBoxModel<String> structureBox; private void updateOsmModel() { distributeWays(); Main.map.mapView.repaint(); } public class SweepPolygonCursor { public SweepPolygonCursor(int stripIndex, int partIndex) { this.stripIndex = stripIndex; this.partIndex = partIndex; } public boolean equals(SweepPolygonCursor rhs) { return rhs != null && stripIndex == rhs.stripIndex && partIndex == rhs.partIndex; } public int stripIndex; public int partIndex; } private void distributeWays() { target.startGeographyBuild(beams, strips); Vector<Vector<Boolean>> stripRefs = new Vector<>(); for (Strip strip : strips) { Vector<Boolean> refs = new Vector<>(); if (strip.lhs.size() < strip.rhs.size()) refs.setSize(strip.rhs.size()); else refs.setSize(strip.lhs.size()); stripRefs.add(refs); } Boolean truePtr = new Boolean(true); for (int i = 0; i < stripRefs.size(); ++i) { Vector<Boolean> refs = stripRefs.elementAt(i); for (int j = 0; j < refs.size(); ++j) { if (refs.elementAt(j) == null) { target.startWay(); SweepPolygonCursor cursor = new SweepPolygonCursor(i, j); boolean toTheLeft = true; while (stripRefs.elementAt(cursor.stripIndex).elementAt(cursor.partIndex) == null) { stripRefs.elementAt(cursor.stripIndex).setElementAt(truePtr, cursor.partIndex); if (toTheLeft && cursor.partIndex < strips.elementAt(cursor.stripIndex).lhs.size()) { target.appendCorridorPart( strips.elementAt(cursor.stripIndex).partAt(cursor.partIndex), strips.elementAt(cursor.stripIndex).geographyAt(cursor.partIndex), cursor.stripIndex, beams.elementAt(cursor.stripIndex).getBeamPartIndex(!toTheLeft, cursor.partIndex), level); toTheLeft = beams.elementAt(cursor.stripIndex).appendNodes( cursor, toTheLeft, target.beamAt(cursor.stripIndex), level); } else if (!toTheLeft && cursor.partIndex < strips.elementAt(cursor.stripIndex).rhs.size()) { target.appendCorridorPart( strips.elementAt(cursor.stripIndex).partAt(cursor.partIndex), strips.elementAt(cursor.stripIndex).geographyAt(cursor.partIndex), cursor.stripIndex + 1, beams.elementAt(cursor.stripIndex + 1).getBeamPartIndex(!toTheLeft, cursor.partIndex), level); toTheLeft = beams.elementAt(cursor.stripIndex + 1).appendNodes( cursor, toTheLeft, target.beamAt(cursor.stripIndex + 1), level); } else toTheLeft = appendUturn(cursor, toTheLeft); } target.finishWay(strips.elementAt(cursor.stripIndex), cursor.partIndex, j % 2 == 0, level); } } } target.finishGeographyBuild(type, level); } private boolean appendUturn(SweepPolygonCursor cursor, boolean toTheLeft) { Strip strip = strips.elementAt(cursor.stripIndex); target.appendUturnNode(strip, cursor.partIndex, cursor.stripIndex, beams.elementAt(toTheLeft ? cursor.stripIndex + 1 : cursor.stripIndex). getBeamPartIndex(toTheLeft, cursor.partIndex), toTheLeft, level); if (cursor.partIndex % 2 == 0) ++cursor.partIndex; else --cursor.partIndex; return !toTheLeft; } }