/*
 *  Projection.hpp
 *  GLMap
 *
 *  Created by Harrison on July 5, 2012.
 *  Copyright 2012 TeleNav. All rights reserved.
 *
 */

#ifndef Foundation_Math_Projection_INCLUDED
#define Foundation_Math_Projection_INCLUDED

#include <foundation/TnTypes.h>

#include "Point.hpp"

#include "transform.hpp"
#include "poly.hpp"

/* According to Harrison, this file is a placeholder created by
 * copying TnMapMagic. Ignore it. */


namespace Tn
{

namespace math
{
    
/*!
  Tile dimensions double with each integer increment in the zoom
  level. One can transition smoothly and proportionately through the
  levels by using a linear parameter in 'log 2' space.

  The zoomSpaceToReal function returns a distance that is 'constant'
  relative to the tile size for a given zoom level, but is defined
  smoothly between zoom levels. It is specified in units of tile size.
*/

float zoomSpaceToReal(float zoom, float distance, uint32_t baseTileSize);

float realToZoomSpace(float realDistance, float distance, uint32_t baseTileSize);

/* Integer zoom level for a given point in zoom space. This will only
 * return valid zoom levels. */

uint32_t zoomSpaceToZoomLevel(float zoomSpace);


/*! Returns whether the specified tile is visible. A tile is
 *  considered not visible if it doesn't match the current zoom level,
 *  if it lies beyond the specified range of the origin, or if it lies
 *  completely outside the viewing frustum. The range parameter is
 *  relative to the zoom parameter used to build the camera matrix and
 *  is in units of tile size.  
 *
 *  @TODO: There seems to be a bug in the test when the tile crosses
 *  the eye-local z=0 plane. This tends to happen only when the eye is
 *  really close to a tile of an inappropriately large zoom level.

*/

/*bool isPointVisible(tn::math::Point3i const & point,
                    uint32_t currentZoomLevel,
                    float range,
                    TnMapCamera const & camera);*/

/*! Returns a point in 'global' space, which currently is DM5 Mercator
 *  space, but could in theory be something else. @TODO: find out what
 *  units are going to be used for altitude and compensate for
 *  Mercator distortion in distance. */
    
double latToGlobal(double latitude);
    
Tn::math::Point3d latLonToGlobalNoWrap(Tn::math::Point3d const & point);
Tn::math::Point2d latLonToGlobalNoWrap(Tn::math::Point2d const & point);
Tn::math::Point3d latLonToGlobalNoWrap(double latitude, double longitude, double altitude=0.0);

Tn::math::Point3d latLonToGlobal(Tn::math::Point3d const & point);
Tn::math::Point2d latLonToGlobal(Tn::math::Point2d const & point);
Tn::math::Point3d latLonToGlobal(double latitude, double longitude, double altitude=0.0);
    
uint32_t MaxGlobalCoordinate();
    
/*! Convert from global back to latitude or longitude */
double globalToLat(Tn::math::Point3d const & point);
double globalToLon(Tn::math::Point3d const & point);
double globalToAlt(Tn::math::Point3d const & point);
double globalToLat(Tn::math::Point3i const & point);
double globalToLon(Tn::math::Point3i const & point);
double globalToAlt(Tn::math::Point3i const & point);
double globalToLat(int32_t const & globalY);
double globalToLon(int32_t const & globalX);
double globalToAlt(int32_t const & globalElevationMeters);

Tn::math::Point3d globalToLatLon(Tn::math::Point3d const & point);

/*! Wrap x coordinate around globalMax and clamp Y coordinate */
Tn::math::Point<3,double> globalWrapAndClamp(Tn::math::Point<3,double> const & point);
    
Tn::math::Point3d globalWrapPoint(Tn::math::Point3d const & point);
    
// Convert meters to our global coordinate system, at a given latitude
float metersToGlobalAtLat(float meters, double latitude);

/*! Get if a pre-build table is used for Mercator projection
 */
bool isUsingMercatorTable();    
    
/*! Build table for Mercator projection
 */
void buildMercatorTable(size_t kb);

    
} // namespace math
    
} // end namespace Tn

#endif

