<?php
/*
ABOUT: web service to fetch the NOAA chart numbers for charts that contain the given lat/lng point
USE: http://vislab-ccom.unh.edu/~briana/rnc/getChartsWPoint.php?lat=43.1569&lng=-70.7008
AUTHOR: briana sullivan
ORG: UNH Center for Coastal and Ocean Mapping / Joint Hydrographic Center
DATE: 04/02/2013
INPUT: lat/lng point
OUTPUT: JSON formatted data for charts that contain the given lat/lng point

References: http://assemblysys.com/php-point-in-polygon-algorythm/ 
*/

/*
 * Copyright (c) 2013 University of New Hampshire CCOM-JHC VisLab, vislab-ccom.unh.edu/~briana
 * 
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sub-license, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * Prior to any sale of the Software and any and all derivative works, 
 * including modifications of the Software, seller shall first contact 
 * the University of New Hampshire Office for Research Partnerships and 
 * Commercialization to obtain a license.  
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

	ini_set('display_errors', 1); 
	error_reporting(E_ALL);
	include_once 'decodePolylineToArray.php';
	
	$lat = $_GET["lat"];
	$lng = $_GET["lng"];
	$point = array(floatval($lat),floatval($lng));
	
	if($lat == NULL){
		echo "<p>You need to have a <strong>lat value</strong> in the URL: http://vislab-ccom.unh.edu/~briana/rnc/getChartsWPoint.php?<b>lat=43.1569</b>&lng=-70.7008</p>";
		return;
	}
	if($lng == NULL){
		echo "<p>You need to have a <strong>lng value</strong> in the URL: http://vislab-ccom.unh.edu/~briana/rnc/getChartsWPoint.php?lat=43.1569&<b>lng=-70.7008</b></p>";
		return;
	}
		

	$url = "http://cordc.ucsd.edu/js/RNC/rnc.php";
	
	// create a new cURL resource
	$ch = curl_init();

	// set options
	curl_setopt($ch,CURLOPT_URL,$url);
	curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,2);
	curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);

	$buffer = curl_exec($ch);
	
	// close cURL resource, and free up system resources
	curl_close($ch);

	if (empty($buffer)){
    	print "<p>Sorry, the rnc product catalog is unavailable at the moment<p>";
	}
	else{
		// put the chart catalog data into a variable for accessing
		$rncCat = json_decode($buffer,true);		
		
		$panels = array();
		$charts = array();
		
		// set up panels array
		foreach($rncCat as $item){		
			foreach($item["panels"] as $panel){
				// add the item to the panel array
				$panels[] = new panel($item["chart_id"],$panel["panel_no"],$panel["encoded_polygon"]);
			}			
		}
		
		// check the point against all the panels
		foreach($panels as $panel){
			if($panel->contains($point)){
				$charts[] = $panel->getChartNo();			
			}
		}
				
		$json = json_encode($charts);	
							
	
		if($json){		
			Header('Content-type: application/json');
			print($json);
		}else{		
			print("<br/><br/>There are no charts available for that point.");		
		}
	}
	
	class panel{
		private $panel_no;
		private $chart_no;
		private $polygon = array();
		
		function __construct($chart_no,$panel_no,$encoded_poly){			
			$this->chart_no = $chart_no;
			$this->panel_no = $panel_no;
			$this->polygon = new Poly($encoded_poly);
			//$this->showPanel();
		}
		function showPanel(){
			echo "<br/>chart = $this->chart_no: panel = $this->panel_no<br/>";
			$this->polygon->toString();
			echo "<br/>";
		}
		function contains($point){
			// check if the point is exactly on a vertex
			if($this->polygon->pointOnVertex($point))
				return true;
			// check if the point is inside the polygon or on the boundary				
			if($this->polygon->pointInsidePoly($point))
				return true;
			
			return false;			
		}
		function getChartNo(){
			return $this->chart_no;
		}		
	}
	
	class Poly{
		private $points = array();
		private $vert_count;
		function __construct($encoded_poly){		
			$this->points = decodePolylineToArray($encoded_poly);
			$this->vert_count = sizeof($this->points);		
		}
		
		function toString(){
			var_dump($this->points);
		}
		
		function pointOnVertex($point){		
			foreach($this->points as $vertex){
				if($point[0] == $vertex[0] && $point[1] == $vertex[1]){
					return true;
				}
				else
					return false;								
			}
		}
		
		function pointInsidePoly($point){
		//point is given in index 0=lat, index 1 = lng
			$intersections = 0;

			for($i=1; $i<$this->vert_count; $i++){
				$v1 = $this->points[$i-1];

				$v2 = $this->points[$i];
				// check if the point is on a horizontal polygon boundary
				if($v1[0] == $v2[0] and $v1[0] == $point[0] and $point[1] > min($v1[1],$v2[1]) and $point[1] < max($v1[1], $v2[1])){
					return true; // on the boundary
				}
				
				if($point[0] > min($v1[0], $v2[0]) and $point[0] <= max($v1[0], $v2[0]) and $point[1] <= max($v1[1], $v2[1]) and $v1[0] != $v2[0]){
				   $xinters = ($point[0] - $v1[0]) * ($v2[1] - $v1[1]) / ($v2[0] - $v1[0]) + $v1[1];  
					if ($xinters == $point[1]) { // Check if point is on the polygon boundary (other than horizontal)
						return true; // on the boundary
					}
					if ($v1[1] == $v2[1] || $point[1] <= $xinters) {
						$intersections++; 
					}
				}												
			}
			// If the number of edges we passed through is even, then it's in the polygon. 
        	if ($intersections % 2 != 0) {
            	return true; //inside the polygon
	        } else {
    	        return false; //outside the polygon
        	}		 		
		}
	}
?>