Package org.osm2world.core.world.modules

Source Code of org.osm2world.core.world.modules.WaterModule$AreaFountain

package org.osm2world.core.world.modules;

import static com.google.common.collect.Iterables.any;
import static java.util.Arrays.asList;
import static java.util.Collections.nCopies;
import static org.osm2world.core.map_elevation.creation.EleConstraintEnforcer.ConstraintType.MAX;
import static org.osm2world.core.target.common.material.Materials.*;
import static org.osm2world.core.target.common.material.NamedTexCoordFunction.*;
import static org.osm2world.core.target.common.material.TexCoordUtil.*;
import static org.osm2world.core.util.Predicates.hasType;
import static org.osm2world.core.world.modules.common.WorldModuleGeometryUtil.*;

import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.openstreetmap.josm.plugins.graphview.core.data.Tag;
import org.osm2world.core.map_data.data.MapArea;
import org.osm2world.core.map_data.data.MapData;
import org.osm2world.core.map_data.data.MapNode;
import org.osm2world.core.map_data.data.MapWaySegment;
import org.osm2world.core.map_data.data.overlaps.MapOverlap;
import org.osm2world.core.map_elevation.creation.EleConstraintEnforcer;
import org.osm2world.core.map_elevation.data.GroundState;
import org.osm2world.core.math.PolygonXYZ;
import org.osm2world.core.math.SimplePolygonXZ;
import org.osm2world.core.math.TriangleXYZ;
import org.osm2world.core.math.VectorXYZ;
import org.osm2world.core.target.RenderableToAllTargets;
import org.osm2world.core.target.Target;
import org.osm2world.core.target.common.material.Materials;
import org.osm2world.core.world.data.AbstractAreaWorldObject;
import org.osm2world.core.world.data.TerrainBoundaryWorldObject;
import org.osm2world.core.world.modules.common.ConfigurableWorldModule;
import org.osm2world.core.world.modules.common.WorldModuleParseUtil;
import org.osm2world.core.world.network.AbstractNetworkWaySegmentWorldObject;
import org.osm2world.core.world.network.JunctionNodeWorldObject;
import org.osm2world.core.world.network.NetworkAreaWorldObject;

/**
* adds water bodies, streams, rivers and fountains to the world
*/
public class WaterModule extends ConfigurableWorldModule {

  //TODO: add canal, ditch, drain

  private static final Tag WATER_TAG = new Tag("natural", "water");
  private static final Tag RIVERBANK_TAG = new Tag("waterway", "riverbank");
 
  private static final Map<String, Float> WATERWAY_WIDTHS;
 
  static {
    WATERWAY_WIDTHS = new HashMap<String, Float>();
    WATERWAY_WIDTHS.put("river", 3f);
    WATERWAY_WIDTHS.put("stream", 0.5f);
    WATERWAY_WIDTHS.put("canal", 2f);
    WATERWAY_WIDTHS.put("ditch", 1f);
    WATERWAY_WIDTHS.put("drain", 1f);
  }
 
  //TODO: apply to is almost always the same! create a superclass handling this!
 
  @Override
  public void applyTo(MapData mapData) {
   
    for (MapWaySegment line : mapData.getMapWaySegments()) {
      for (String value : WATERWAY_WIDTHS.keySet()) {
        if (line.getTags().contains("waterway", value)) {
          line.addRepresentation(new Waterway(line));
        }
      }
    }

    for (MapNode node : mapData.getMapNodes()) {
     
      int connectedRivers = 0;
     
      for (MapWaySegment line : node.getConnectedWaySegments()) {
        if (any(line.getRepresentations(), hasType(Waterway.class))) {
          connectedRivers += 1;
        }
      }
           
      if (connectedRivers > 2) {
        node.addRepresentation(new RiverJunction(node));
      }
     
    }

    for (MapArea area : mapData.getMapAreas()) {
      if (area.getTags().contains(WATER_TAG)
          || area.getTags().contains(RIVERBANK_TAG)) {
        area.addRepresentation(new Water(area));
      }
      if (area.getTags().contains("amenity", "fountain")) {
        area.addRepresentation(new AreaFountain(area));
      }
    }
   
  }
 
  public static class Waterway extends AbstractNetworkWaySegmentWorldObject
    implements RenderableToAllTargets, TerrainBoundaryWorldObject {
   
    public Waterway(MapWaySegment line) {
      super(line);
    }
   
    @Override
    public void defineEleConstraints(EleConstraintEnforcer enforcer) {
     
      super.defineEleConstraints(enforcer);
     
      /* enforce downhill flow */
     
      if (!segment.getTags().containsKey("incline")) {
        enforcer.requireIncline(MAX, 0, getCenterlineEleConnectors());
      }
     
    }
   
    public float getWidth() {
      return WorldModuleParseUtil.parseWidth(segment.getTags(),
          WATERWAY_WIDTHS.get(segment.getTags().getValue("waterway")));
    }
   
    @Override
    public PolygonXYZ getOutlinePolygon() {
      if (isContainedWithinRiverbank()) {
        return null;
      } else {
        return super.getOutlinePolygon();
      }
    }
   
    @Override
    public SimplePolygonXZ getOutlinePolygonXZ() {
      if (isContainedWithinRiverbank()) {
        return null;
      } else {
        return super.getOutlinePolygonXZ();
      }
    }
   
    @Override
    public void renderTo(Target<?> target) {
     
      //note: simply "extending" a river cannot work - unlike streets -
      //      because there can be islands within the riverbank polygon.
      //      That's why rivers will be *replaced* with Water areas instead.
     
      /* only draw the river if it doesn't have a riverbank */
     
      //TODO: handle case where a river is completely within riverbanks, but not a *single* riverbank
           
      if (! isContainedWithinRiverbank()) {
       
        List<VectorXYZ> leftOutline = getOutline(false);
        List<VectorXYZ> rightOutline = getOutline(true);
       
        List<VectorXYZ> leftWaterBorder = createLineBetween(
            leftOutline, rightOutline, 0.05f);
        List<VectorXYZ> rightWaterBorder = createLineBetween(
            leftOutline, rightOutline, 0.95f);
       
        modifyLineHeight(leftWaterBorder, -0.2f);
        modifyLineHeight(rightWaterBorder, -0.2f);
 
        List<VectorXYZ> leftGround = createLineBetween(
            leftOutline, rightOutline, 0.35f);
        List<VectorXYZ> rightGround = createLineBetween(
            leftOutline, rightOutline, 0.65f);
       
        modifyLineHeight(leftGround, -1);
        modifyLineHeight(rightGround, -1);
       
        /* render ground */
       
        @SuppressWarnings("unchecked") // generic vararg is intentional
        List<List<VectorXYZ>> strips = asList(
          createTriangleStripBetween(
              leftOutline, leftWaterBorder),
          createTriangleStripBetween(
              leftWaterBorder, leftGround),
          createTriangleStripBetween(
              leftGround, rightGround),
          createTriangleStripBetween(
              rightGround, rightWaterBorder),
          createTriangleStripBetween(
              rightWaterBorder, rightOutline)
        );
       
        for (List<VectorXYZ> strip : strips) {
          target.drawTriangleStrip(TERRAIN_DEFAULT, strip,
            texCoordLists(strip, TERRAIN_DEFAULT, GLOBAL_X_Z));
        }
       
        /* render water */
       
        List<VectorXYZ> vs = createTriangleStripBetween(
            leftWaterBorder, rightWaterBorder);
       
        target.drawTriangleStrip(WATER, vs,
            texCoordLists(vs, WATER, GLOBAL_X_Z));
       
      }
     
    }

    private boolean isContainedWithinRiverbank() {
      boolean containedWithinRiverbank = false;
     
      for (MapOverlap<?,?> overlap : segment.getOverlaps()) {
        if (overlap.getOther(segment) instanceof MapArea) {
          MapArea area = (MapArea)overlap.getOther(segment);
          if (area.getPrimaryRepresentation() instanceof Water &&
              area.getPolygon().contains(segment.getLineSegment())) {
            containedWithinRiverbank = true;
            break;
          }
        }
      }
      return containedWithinRiverbank;
    }

    private static void modifyLineHeight(List<VectorXYZ> leftWaterBorder, float yMod) {
      for (int i = 0; i < leftWaterBorder.size(); i++) {
        VectorXYZ v = leftWaterBorder.get(i);
        leftWaterBorder.set(i, v.y(v.y+yMod));
      }
    }
   
  }

  public static class RiverJunction
    extends JunctionNodeWorldObject
    implements TerrainBoundaryWorldObject, RenderableToAllTargets {

    public RiverJunction(MapNode node) {
      super(node);
    }

    @Override
    public GroundState getGroundState() {
      return GroundState.ON;
    }

    @Override
    public void renderTo(Target<?> target) {
     
      //TODO: check whether it's within a riverbank (as with Waterway)
     
      List<VectorXYZ> vertices = getOutlinePolygon().getVertices();
     
      target.drawConvexPolygon(WATER, vertices,
          texCoordLists(vertices, WATER, GLOBAL_X_Z));
     
      //TODO: only cover with water to 0.95 * distance to center; add land below
     
    }
   
  }
 
  public static class Water extends NetworkAreaWorldObject
    implements RenderableToAllTargets, TerrainBoundaryWorldObject {
   
    //TODO: only cover with water to 0.95 * distance to center; add land below.
    // possible algorithm: for each node of the outer polygon, check whether it
    // connects to another water surface. If it doesn't move it inwards,
    // where "inwards" is calculated based on the two adjacent polygon segments.
   
    public Water(MapArea area) {
      super(area);
    }

    @Override
    public GroundState getGroundState() {
      return GroundState.ON;
    }
   
    @Override
    public void defineEleConstraints(EleConstraintEnforcer enforcer) {
      enforcer.requireSameEle(getEleConnectors());
    }
   
    @Override
    public void renderTo(Target<?> target) {
      Collection<TriangleXYZ> triangles = getTriangulation();
      target.drawTriangles(WATER, triangles,
          triangleTexCoordLists(triangles, WATER, GLOBAL_X_Z));
    }
   
  }
 
  private static class AreaFountain extends AbstractAreaWorldObject
    implements RenderableToAllTargets, TerrainBoundaryWorldObject {

    public AreaFountain(MapArea area) {
      super(area);
    }

    @Override
    public GroundState getGroundState() {
      return GroundState.ON;
    }

    @Override
    public void renderTo(Target<?> target) {

      /* render water */
       
      Collection<TriangleXYZ> triangles = getTriangulation();
      target.drawTriangles(PURIFIED_WATER, triangles,
          triangleTexCoordLists(triangles, PURIFIED_WATER, GLOBAL_X_Z));
     
      /* render walls */
      //note: mostly copy-pasted from BarrierModule
     
      double width=0.1;
      double height=0.5;
     
      List<VectorXYZ> wallShape = asList(
          new VectorXYZ(-width/2, 0, 0),
          new VectorXYZ(-width/2, height, 0),
          new VectorXYZ(+width/2, height, 0),
          new VectorXYZ(+width/2, 0, 0)
      );
     
      List<VectorXYZ> path = getOutlinePolygon().getVertexLoop();
     
      List<List<VectorXYZ>> strips = createShapeExtrusionAlong(
          wallShape,
          path,
          nCopies(path.size(), VectorXYZ.Y_UNIT));
     
      for (List<VectorXYZ> strip : strips) {
        target.drawTriangleStrip(Materials.CONCRETE, strip,
            texCoordLists(strip, Materials.CONCRETE, STRIP_WALL));
      }
             
    }

  }
}
TOP

Related Classes of org.osm2world.core.world.modules.WaterModule$AreaFountain

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.