package org.osm2world.core.world.data; import java.util.Collection; import java.util.Collections; import org.osm2world.core.map_data.data.MapArea; import org.osm2world.core.map_elevation.creation.EleConstraintEnforcer; import org.osm2world.core.map_elevation.data.EleConnectorGroup; import org.osm2world.core.math.AxisAlignedBoundingBoxXZ; import org.osm2world.core.math.LineSegmentXZ; import org.osm2world.core.math.PolygonXYZ; import org.osm2world.core.math.SimplePolygonXZ; import org.osm2world.core.math.TriangleXYZ; import org.osm2world.core.math.TriangleXZ; import org.osm2world.core.math.VectorXZ; import org.osm2world.core.math.algorithms.JTSTriangulationUtil; import org.osm2world.core.math.algorithms.Poly2TriTriangulationUtil; import org.osm2world.core.math.datastructures.IntersectionTestObject; import org.osm2world.core.util.exception.TriangulationException; /** * implementation of {@link AreaWorldObject} that offers some basic features: * < ul><li> providing the object outline based on the {@link MapArea} * </li><li> providing bounding geometry for intersection tests * </li><li> calculating a triangulation of the surface for rendering * </ul> */ public abstract class AbstractAreaWorldObject implements WorldObjectWithOutline, AreaWorldObject, IntersectionTestObject { protected final MapArea area; private final SimplePolygonXZ outlinePolygonXZ; private EleConnectorGroup connectors; protected AbstractAreaWorldObject(MapArea area) { this.area = area; outlinePolygonXZ = area.getPolygon().getOuter().makeCounterclockwise(); } @Override public EleConnectorGroup getEleConnectors() { if (connectors == null) { connectors = new EleConnectorGroup(); connectors.addConnectorsForTriangulation( getTriangulationXZ(), null, getGroundState()); } return connectors; } @Override public void defineEleConstraints(EleConstraintEnforcer enforcer) {} @Override public SimplePolygonXZ getOutlinePolygonXZ() { return outlinePolygonXZ; } @Override public PolygonXYZ getOutlinePolygon() { return connectors.getPosXYZ(outlinePolygonXZ); } @Override public AxisAlignedBoundingBoxXZ getAxisAlignedBoundingBoxXZ() { return new AxisAlignedBoundingBoxXZ( area.getOuterPolygon().getVertexCollection()); } @Override public final MapArea getPrimaryMapElement() { return area; } /** * decompose this area into counterclockwise triangles. */ protected Collection<TriangleXZ> getTriangulationXZ() { try { return Poly2TriTriangulationUtil.triangulate( area.getPolygon().getOuter(), area.getPolygon().getHoles(), Collections.<LineSegmentXZ>emptyList(), Collections.<VectorXZ>emptyList()); } catch (TriangulationException e) { System.err.println("Poly2Tri exception for " + this + ":"); e.printStackTrace(); System.err.println("... falling back to JTS triangulation."); return JTSTriangulationUtil.triangulate( area.getPolygon().getOuter(), area.getPolygon().getHoles(), Collections.<LineSegmentXZ>emptyList(), Collections.<VectorXZ>emptyList()); } } /** * decompose this area into counterclockwise 3d triangles. * Only available after elevation calculation. */ protected Collection<TriangleXYZ> getTriangulation() { return connectors.getTriangulationXYZ(getTriangulationXZ()); } @Override public String toString() { return this.getClass().getSimpleName() + "(" + area + ")"; } }