Package org.osm2world.core.target.common.rendering

Source Code of org.osm2world.core.target.common.rendering.OrthoTilesUtil

package org.osm2world.core.target.common.rendering;

import static java.lang.Math.PI;
import static org.osm2world.core.math.AxisAlignedBoundingBoxXZ.union;

import java.util.Arrays;
import java.util.List;

import org.osm2world.core.map_data.creation.MapProjection;
import org.osm2world.core.math.AxisAlignedBoundingBoxXZ;
import org.osm2world.core.math.VectorXYZ;
import org.osm2world.core.math.VectorXZ;

/**
* calculates camera and projection information for orthographic tiles.
*/
public final class OrthoTilesUtil {

  /** 4 cardinal directions, can be used for camera placement */
  public static enum CardinalDirection {
   
    N, E, S, W;
   
    /**
     * returns the closest cardinal direction for an angle
     * @param angle  angle to north direction in radians;
     *               consistent with {@link VectorXZ#angle()}
     */
    public static CardinalDirection closestCardinal(double angle) {
      angle = angle % (2 * PI);
      if (angle < PI / 4) { return N; }
      else if (angle < 3 * PI / 4) { return E; }
      else if (angle < 5 * PI / 4) { return S; }
      else if (angle < 7 * PI / 4) { return W; }
      else { return N; }
    }
   
    public boolean isOppositeOf(CardinalDirection other) {
      return this == N && other == S
          || this == E && other == W
          || this == S && other == N
          || this == W && other == E;
    }
 
  };
 
  /** prevents instantiation */
  private OrthoTilesUtil() { }
 
  public static final Camera cameraForTile(MapProjection mapProjection,
      TileNumber tile, double angleDeg, CardinalDirection from) {
    return cameraForBounds(boundsForTile(mapProjection, tile),
        angleDeg, from);
  }
 
  public static final Camera cameraForTiles(MapProjection mapProjection,
      List<TileNumber> tiles, double angleDeg, CardinalDirection from) {
   
    if (tiles.isEmpty()) { throw new IllegalArgumentException("empty tiles list"); }
   
    AxisAlignedBoundingBoxXZ result = boundsForTiles(mapProjection, tiles);
   
    return cameraForBounds(result, angleDeg, from);
   
  }

  public static final Camera cameraForBounds(
      AxisAlignedBoundingBoxXZ bounds, double angleDeg,
      CardinalDirection from) {
   
    Camera result = new Camera();
   
    VectorXYZ lookAt = new VectorXYZ(
        bounds.minX + bounds.sizeX() / 2,
        0,
        bounds.minZ + bounds.sizeZ() / 2);
   
    // calculate camera position (start with position for view from south,
    // then modify it depending on parameters)
   
    double cameraDistance = Math.max(bounds.sizeX(), bounds.sizeZ());
     
    double cameraOffsetX = 0;
    double cameraOffsetZ = - cameraDistance * Math.cos(Math.toRadians(angleDeg));
       
    if (from == CardinalDirection.W || from == CardinalDirection.E) {
      double temp = cameraOffsetX;
      cameraOffsetX = cameraOffsetZ;
      cameraOffsetZ = temp;
    }
   
    if (from == CardinalDirection.N || from == CardinalDirection.E) {
      cameraOffsetX = -cameraOffsetX;
      cameraOffsetZ = -cameraOffsetZ;
    }
   
    result.setCamera(lookAt.x + cameraOffsetX,
             cameraDistance * Math.sin(Math.toRadians(angleDeg)),
             lookAt.z + cameraOffsetZ,
             lookAt.x, lookAt.y, lookAt.z);
   
    return result;
  }
 
  public static final Projection projectionForTile(MapProjection mapProjection,
      TileNumber tile, double angleDeg, CardinalDirection from) {
    AxisAlignedBoundingBoxXZ tileBounds = boundsForTile(mapProjection, tile);
    return projectionForBounds(tileBounds, angleDeg, from);
  }

  public static final Projection projectionForTiles(MapProjection mapProjection,
      List<TileNumber> tiles, double angleDeg, CardinalDirection from) {
   
    if (tiles.isEmpty()) { throw new IllegalArgumentException("empty tiles list"); }
   
    AxisAlignedBoundingBoxXZ result = boundsForTiles(mapProjection, tiles);
   
    return projectionForBounds(result, angleDeg, from);
   
  }
 
  public static final Projection projectionForBounds(
      AxisAlignedBoundingBoxXZ bounds, double angleDeg,
      CardinalDirection from) {
   
    double sin = Math.sin(Math.toRadians(angleDeg));
   
    double sizeX = bounds.sizeX();
    double sizeZ = bounds.sizeZ();
   
    if (from == CardinalDirection.W || from == CardinalDirection.E) {
      double temp = sizeX;
      sizeX = sizeZ;
      sizeZ = temp;
    }
   
    return new Projection(true,
         sizeX / (sizeZ * sin),
         Double.NaN,
         sizeZ * sin,
         -10000, 10000);
   
  }
 
  private static final AxisAlignedBoundingBoxXZ boundsForTile(
      MapProjection mapProjection, TileNumber tile) {
   
    VectorXZ tilePos1 = mapProjection.calcPos(
        tile2lat(tile.y, tile.zoom), tile2lon(tile.x, tile.zoom));
 
    VectorXZ tilePos2 = mapProjection.calcPos(
        tile2lat(tile.y+1, tile.zoom), tile2lon(tile.x+1, tile.zoom));
   
    return new AxisAlignedBoundingBoxXZ(Arrays.asList(tilePos1, tilePos2));
   
  }

  private static final AxisAlignedBoundingBoxXZ boundsForTiles(
      MapProjection mapProjection, List<TileNumber> tiles) {
   
    AxisAlignedBoundingBoxXZ result = boundsForTile(mapProjection, tiles.get(0));
   
    for (int i=1; i<tiles.size(); i++) {
      AxisAlignedBoundingBoxXZ newBox = boundsForTile(mapProjection, tiles.get(i));
      result = union(result, newBox);
    }
   
    return result;
   
  }
 
  private static final double tile2lon(int x, int z) {
    return x / Math.pow(2.0, z) * 360.0 - 180;
  }
 
  private static final double tile2lat(int y, int z) {
    double n = Math.PI - (2.0 * Math.PI * y) / Math.pow(2.0, z);
    return Math.toDegrees(Math.atan(Math.sinh(n)));
  }
 
}
TOP

Related Classes of org.osm2world.core.target.common.rendering.OrthoTilesUtil

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.