/**
 * GeoDa TM, Copyright (C) 2011-2015 by Luc Anselin - all rights reserved
 *
 * This file is part of GeoDa.
 * 
 * GeoDa is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * GeoDa is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
 * Fhe following functions: findArea and ComputeArea2D
 *     are borrowed from FastArea.c++
 *
 * From the paper:
 *
 *      Daniel Sunday
 *      "Fast Polygon Area and Newell Normal Computation"
 *      journal of graphics tools, 7(2):9-13, 2002
 *
 */

#ifndef __GEODA_CENTER_GEN_GEOM_ALGS_H__
#define __GEODA_CENTER_GEN_GEOM_ALGS_H__


namespace GenGeomAlgs {
	const double pi = 3.141592653589793238463;
	const double pi_x_2 = pi*2.0;
	const double pi_x_1_5 = pi*1.5;
	const double pi_ovr_2 = pi/2.0;
	const double d180_ovr_pi = 180.0/pi;
	const double pi_ovr_180 = pi/180.0;
	const double one_mi_in_km = 1.609344; // 1 Statute mi in km
	const double earth_radius_km = 6371.0;
	const double earth_radius_mi = earth_radius_km / one_mi_in_km;
	double DegToRad(double deg);
	double RadToDeg(double rad);
	double NormLonDeg(double lon);
	double NormLonRad(double lon);
	double NormLatDeg(double lat);
	double NormLatRad(double lat);
	void LongLatDegToUnit(const double& lon, const double& lat,
						  double& x, double& y, double& z);
	void LongLatRadToUnit(const double& lon, const double& lat,
						  double& x, double& y, double& z);
	void UnitToLongLatDeg(const double& x, const double& y, const double& z,
						  double& lon, double& lat);
	void UnitToLongLatRad(const double& x, const double& y, const double& z,
						  double& lon, double& lat);
	/** Convert unit sphere euclidean distance to radians. */
	double UnitDistToRad(double d);
	double UnitDistToDeg(double d);
	/** Convert radians to straight-line euclidean distance on unit sphere. */
	double RadToUnitDist(double r);
	double DegToUnitDist(double r);
	/** Limit angle to between 0 and pi radians (shortest distance
	 * around circle). */
	double ShortestRad(double r);
	/** Limit angle to between 0 and 180 radians (shortest distance
	 * around circle). */
	double ShortestDeg(double d);
	double ComputeEucDist(double x1, double y1, double x2, double y2);
	double ComputeArcDistMi(double lon1, double lat1, double lon2, double lat2);
	double ComputeArcDistKm(double lon1, double lat1, double lon2, double lat2);
	double ComputeArcDistRad(double lon1, double lat1, double lon2, double lat2);
	double LonLatRadDistRad(double lon1, double lat1, double lon2, double lat2);
	double ComputeArcDistDeg(double lon1, double lat1, double lon2, double lat2);
	double EarthRadToKm(double radians);
	double EarthRadToMi(double radians);
	double EarthKmToRad(double d);
	double EarthMiToRad(double d);
	double ComputePerimeter2D(int n, double *x, double *y);
	double ComputeArea2D(int n, double *x, double *y);    // output unit normal
	double findArea(int n, double *x, double *y);         // 2D polygon
	bool ClipToBB(double& x0, double& y0, double& x1, double& y1,
				  const double& xmin, const double& ymin,
				  const double& xmax, const double& ymax);
	
	
	
	bool ExtendRayToBB(double x0, double y0, double x1, double y1,
										 double& x2, double& y2,
										 const double xmin, const double ymin,
										 const double xmax, const double ymax);
	
	bool nearlyEqual(double x, double y);
}

#endif
