package org.osm2world.core.world.network; import java.util.ArrayList; import java.util.List; import org.osm2world.core.map_data.data.MapNode; import org.osm2world.core.map_data.data.MapSegment; import org.osm2world.core.map_data.data.MapWaySegment; import org.osm2world.core.math.InvalidGeometryException; import org.osm2world.core.math.SimplePolygonXZ; import org.osm2world.core.math.VectorXZ; import org.osm2world.core.world.creation.NetworkCalculator; import org.osm2world.core.world.data.OutlineNodeWorldObject; public abstract class VisibleConnectorNodeWorldObject extends OutlineNodeWorldObject { protected boolean informationProvided; protected VectorXZ cutVector; protected VectorXZ startPos; protected VectorXZ endPos; protected float startWidth; protected float endWidth; /** * returns the length required by this node representation. * Adjacent lines will be pushed back accordingly. * * If this is 0, this has the same effect as an invisible * connector node (adjacent line representations * directly touching each other). Examples where non-zero values * are needed include crossings at nodes in roads. * * Needs to be provided by the implementing class before the * calculation in {@link NetworkCalculator} starts. */ abstract public float getLength(); /** * sets the results of {@link NetworkCalculator}'s calculations. * Most methods in this class cannot be used until this method * has provided the required information! */ public void setInformation(VectorXZ cutVector, VectorXZ startPos, VectorXZ endPos, float startWidth, float endWidth) { this.informationProvided = true; this.cutVector = cutVector; this.startPos = startPos; this.endPos = endPos; this.startWidth = startWidth; this.endWidth = endWidth; } public VisibleConnectorNodeWorldObject(MapNode node) { super(node); } @Override public SimplePolygonXZ getOutlinePolygonXZ() { List<VectorXZ> outlineXZ = new ArrayList<VectorXZ>(getOutlineXZ(0, 0)); outlineXZ.addAll(getOutlineXZ(1, 1)); if (outlineXZ.size() > 2) { try { //TODO better handling of broken outlines outlineXZ.add(outlineXZ.get(0)); return new SimplePolygonXZ(outlineXZ); } catch (InvalidGeometryException e) {} } return null; } /** * provides outline for the areas covered by the connector. * * The from and to indices refer to the list * returned by the underlying {@link MapNode}'s * {@link MapNode#getConnectedSegments()} method. */ protected List<VectorXZ> getOutlineXZ(int from, int to) { checkInformationProvided(); List<VectorXZ> outline = new ArrayList<VectorXZ>(); List<MapSegment> segments = node.getConnectedSegments(); assert from >= 0 && from < segments.size(); assert to >= 0 && to < segments.size(); if (((from == 1 && to == 0) || (from == 0 && to == 1))) { if (from == 0) { VectorXZ pos1 = startPos .add(cutVector.mult(startWidth)); VectorXZ pos2 = endPos .add(cutVector.mult(endWidth)); outline.add(pos1); outline.add(pos2); } else { VectorXZ pos1 = endPos .subtract(cutVector.mult(endWidth)); VectorXZ pos2 = startPos .subtract(cutVector.mult(startWidth)); outline.add(pos1); outline.add(pos2); } } else if (from == to && segments.get(from) instanceof MapWaySegment) { //usually at the end of a noexit road MapWaySegment segment = (MapWaySegment) segments.get(from); if (segment.getPrimaryRepresentation() instanceof NetworkWaySegmentWorldObject) { NetworkWaySegmentWorldObject rep = (NetworkWaySegmentWorldObject) segment.getPrimaryRepresentation(); //TODO: the calculations for pos1/2 should be part of the NetworkLineRepresentation (it's used quite often) if (segment.getEndNode() == node) { //inbound segment VectorXZ pos1 = node.getPos() .add(rep.getEndOffset()) .add(rep.getEndCutVector().mult(rep.getWidth()/2)); VectorXZ pos2 = node.getPos() .add(rep.getEndOffset()) .subtract(rep.getEndCutVector().mult(rep.getWidth()/2)); outline.add(pos1); outline.add(pos2); } else { //outbound segment VectorXZ pos1 = node.getPos() .add(rep.getStartOffset()) .subtract(rep.getStartCutVector().mult(rep.getWidth()/2)); VectorXZ pos2 = node.getPos() .add(rep.getStartOffset()) .add(rep.getStartCutVector().mult(rep.getWidth()/2)); outline.add(pos1); outline.add(pos2); } } } return outline; } /** * throws an IllegalStateException if information hasn't been * provided by a {@link NetworkCalculator} */ private void checkInformationProvided() throws IllegalStateException { if (!informationProvided) { throw new IllegalStateException("no connector information" + " has been set for this representation.\n" + "node: " + node); } } }