NCCOOS Trac Projects: Top | Web | Platforms | Processing | Viz | Sprints | Sandbox | (Wind)

root/Chameleon/trunk/Chameleon/geomath.php

Revision 13 (checked in by jcleary, 17 years ago)

Latest Chameleon code checkout from previous repository

Line 
1 <?php
2 /**
3  * Math utils function
4  *
5  * @project     CWC2
6  * @revision    $Id:
7  * @purpose     FindDealers Widget class
8  * @author      DM Solutions Group (lacroix@dmsolutions.ca)
9  * @copyright
10  * <b>Copyright (c) 2003, DM Solutions Group Inc.</b>
11  * Permission is hereby granted, free of charge, to any person obtaining a
12  * copy of this software and associated documentation files (the "Software"),
13  * to deal in the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15  * and/or sell copies of the Software, and to permit persons to whom the
16  * Software is furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included
19  * in all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
24  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27  * DEALINGS IN THE SOFTWARE.
28  */
29
30 /**
31  * Number of KM in a MILE
32  * there are 5280 feet in a mile        : start with 5280
33  * there are 12 inches in a foot        : multiple by 12
34  * there are 0.0254 meters in an inch   : multiple by 0.0254
35  * there are 1000 meters in a kilometer : divide by 1000
36  */
37 define( "KM_PER_MILE", (5280 * 12 * 0.0254 / 1000) );
38
39 /**
40  * Constant returns miles per degree of latitude which is 69.
41  */
42 define( "MilesPerDegreeLat", 69 );
43 define( "DegreesLatPerMile", (1 / 69.0) );
44
45
46 /**
47  * function LonToLatRatio
48  *
49  * Given a latitude in decimal degrees, it will return the ratio of
50  * longitude degress to latitude degrees.
51  */
52 function LonToLatRatio ($latitude)
53 {
54     return cos($latitude * M_PI / 180);
55 }
56
57 /**
58  * MilesPerDegreeLon($latitude)
59  *
60  * Given a latitude in decimal degrees, it will return the
61  * miles per degree of longitude.
62  */
63 function MilesPerDegreeLon ($latitude)
64 {
65     return 69 * LonToLatRatio($latitude);
66 }
67
68 /**
69  * DegreesLonPerMile($latitude)
70  *
71  * Given a latitude in decimal degrees, it will return the
72  * degrees of longitude per mile.
73  */
74 function DegreesLonPerMile ($latitude)
75 {
76     return 1 / MilesPerDegreeLon( $latitude );
77 }
78
79 /**
80  * decimal_degrees($degrees, $minutes, $seconds)
81  *
82  * Given whole degrees, minutes, and seconds, B<decimal_degrees> will
83  * return the equivalent number of decimal degrees. B<dd> function
84  * takes the same inputs as B<decimal_degrees> but returns a result
85  * limited to 5 decimal places.
86  */
87 function decimal_degrees ($degrees, $minutes, $seconds)
88 {
89     // if degrees are negative, subtrack minutes and seconds.
90     if ($degrees < 0) {
91         return $degrees - ( $minutes / 60 ) - ( $seconds / 3600);
92     }
93     // if degrees are positve, add minutes and seconds.
94     return $degrees + ( $minutes / 60 ) + ( $seconds / 3600);
95 }
96
97 function dd ($degrees, $minutes, $seconds)
98 {
99     return sprintf("%.5f", decimal_degrees($degrees, $minutes, $seconds));
100 }
101
102 /**
103  * Lon2DMS(I<longitude>)
104  *
105  * Given a longitude in decimal degrees, returns a string in the form of:
106  *
107  * I<degrees>B<d>I<minutes>B<'>I<seconds>B<">I<cardinal>
108  *
109  * where I<cardinal> is C<W> for negative longitudes and C<E> for
110  * positive longitudes.
111  */
112 function Lon2DMS ($longitude)
113 {
114     $degrees = intval( $longitude );
115     $minutes = intval( ( $longitude - $degrees ) * 60 );
116     $seconds = intval( ( $longitude - $degrees ) * 3600 ) - ( $minutes * 60 );
117
118       // west if longitude is negative
119     if ($longitude < 0) {
120         return abs($degrees) . 'd' .
121                abs($minutes) . "'" .
122                sprintf('%.3f', abs($seconds)) . '"W';
123     }
124       // east if longitude is positive
125     return abs($degrees) . 'd' .
126            abs($minutes) . "'" .
127            sprintf('%.3f', abs($seconds)) . '"E';
128 }
129
130 /**
131  * Lat2DMS(I<latitude>)
132  *
133  * Given a latitude in decimal degrees, returns a string in the form of:
134  *
135  * I<degrees>B<d>I<minutes>B<'>I<seconds>B<">I<cardinal>
136  *
137  * where I<cardinal> is C<S> for negative longitudes and C<N> for
138  * positive longitudes.
139  */
140 function Lat2DMS ($latitude)
141 {
142     $degrees = intval( $latitude );
143     $minutes = intval( ( $latitude - $degrees ) * 60 );
144     $seconds = intval( ( $latitude - $degrees ) * 3600 ) - ( $minutes * 60 );
145
146     // south if latitude is negative
147     if ($latitude < 0) {
148         return abs($degrees) . 'd' .
149             abs($minutes) . "'" .
150             sprintf('%.3f', abs($seconds)) . '"S';
151     }
152     // north if latitude is positive
153     return abs($degrees) . 'd' .
154         abs($minutes) . "'" .
155         sprintf('%.3f', abs($seconds)) . '"N';
156 }
157
158 /*
159  * deprecated - only used by mapimagesharedresource widget, changed to Pix2Geo (below)
160 function Pix2Georef ( $nX,   $nY,
161              $dfGeoMiddleX, $dfGeoMiddleY,
162              $dfGeoWidth,   $dfGeoHeight,
163              $nPixelWidth,  $nPixelHeight  )
164 {
165
166     // --------------------------------------------------------------------
167     //      Calculate first the extent in georef as does mapserver
168     //      (fcution msAdjustScale in maputil.c).
169     // --------------------------------------------------------------------
170     
171     $dfGeoMinX = $dfGeoMiddleX - ($dfGeoWidth/2);
172     $dfGeoMaxX = $dfGeoMiddleX + ($dfGeoWidth/2);
173     $dfGeoMinY = $dfGeoMiddleY - ($dfGeoHeight/2);
174     $dfGeoMaxY = $dfGeoMiddleY + ($dfGeoHeight/2);
175     
176     $dfTmp1 = ($dfGeoMaxX - $dfGeoMinX)/$nPixelWidth;
177     $dfTmp2 = ($dfGeoMaxY - $dfGeoMinY)/$nPixelHeight;
178     
179     $cellsize = max($dfTmp1, $dfTmp2);
180     
181     if ($cellsize > 0)
182     {
183     
184         $dfTmp1 = max(($nPixelWidth - ($dfGeoMaxX - $dfGeoMinX)/$cellsize)/2 , 0);
185         $dfTmp2 = max(($nPixelHeight - ($dfGeoMaxY - $dfGeoMinY)/$cellsize)/2 , 0);
186     
187         $ox = $oy = 0;
188     
189         if ($dfTmp1 >= 0.0)
190         {
191             $ox =   intval($dfTmp1 + 0.5);
192         }
193         else
194         {
195             $ox =   intval($dfTmp1 - 0.5);
196         }
197     
198         if ($dfTmp2 >= 0.0) {
199             $oy =   intval($dfTmp2 + 0.5);
200         }
201         else
202         {
203             $oy =   intval($dfTmp2 - 0.5);
204         }
205     
206     
207         $dfGeoMinX = $dfGeoMinX - $ox*$cellsize;
208         $dfGeoMaxX = $dfGeoMaxX + $ox*$cellsize;
209         $dfGeoMinY = $dfGeoMinY - $oy*$cellsize;
210         $dfGeoMaxY = $dfGeoMaxY + $oy*$cellsize;
211     
212     
213         $dfPix2GeoX = ($dfGeoMaxX - $dfGeoMinX) / $nPixelWidth;
214         $dfPix2GeoY = ($dfGeoMaxY - $dfGeoMinY) / $nPixelHeight;
215     
216         $nDeltaPixX =  $nX;
217         $nDeltaPixY =  $nPixelHeight - $nY;# - $nPixelHeight;
218     
219     
220         $dfDeltaGeoX = $nDeltaPixX * $dfPix2GeoX;
221         $dfDeltaGeoY = $nDeltaPixY * $dfPix2GeoY;
222     
223         $dfPosGeoX = $dfGeoMinX + $dfDeltaGeoX;
224         $dfPosGeoY = $dfGeoMinY + $dfDeltaGeoY;
225     
226         $aLatLong = array();
227         $aLatLong[0] = $dfPosGeoX;
228         $aLatLong[1] = $dfPosGeoY;
229     
230         return $aLatLong;
231     }
232 }
233 */
234     
235 /**
236  * convert a pixel position to a georef position
237  *
238  * @param nPixPos integer the pixel position
239  * @param dfPixMin float the minimum pixel position
240  * @param dfPixMax float the maximum pixel position
241  * @param dfGeoMin float the minimum georeferenced position
242  * @param dfGeoMax float the maximum georeferenced position
243  * @param nInversePix boolean, flag to invert Y coordinates if UL > LR
244  * @return double geocoded position.
245  */
246 function Pix2Geo($nPixPos, $dfPixMin, $dfPixMax, $dfGeoMin, $dfGeoMax,
247                  $nInversePix = false)
248 {
249     $dfWidthGeo = $dfGeoMax - $dfGeoMin;
250     $dfWidthPix = $dfPixMax - $dfPixMin;
251
252     $dfPixToGeo = $dfWidthGeo / $dfWidthPix;
253
254     if (!$nInversePix)
255         $dfDeltaPix = $nPixPos - $dfPixMin;
256     else
257         $dfDeltaPix = $dfPixMax - $nPixPos;
258
259     $dfDeltaGeo = $dfDeltaPix * $dfPixToGeo;
260
261
262     $dfPosGeo = $dfGeoMin + $dfDeltaGeo;
263
264     return ($dfPosGeo);
265 }
266  
267 /**
268  * convert a geocoded position to pixel coord
269  *
270  * @param nGeoPos double Geocoded position
271  * @param dfPixMin double minimum map pixel value
272  * @param dfPixMax double maximum map pixel value
273  * @param dfGeoMin double minimum map geocoded value
274  * @param dfGeoMax double maximum map geocoded value
275  * @param nInverseGeo integer optional flag to inverse , set to 1 for
276  *                            Y pixel coordinates where UL > LR
277  * @return double geocoded position
278  */
279 function Geo2Pix ($nGeoPos, $dfPixMin, $dfPixMax, $dfGeoMin,
280                      $dfGeoMax, $nInverseGeo = "")
281 {
282     // calculate the geocoded & pixel width
283     $dfWidthGeo = abs($dfGeoMax - $dfGeoMin);
284     $dfWidthPix = abs($dfPixMax - $dfPixMin);
285
286     // get ratio
287     if ( $dfWidthGeo <= 0 )
288     {
289         return 0;
290     }
291     $dfGeoToPix = $dfWidthPix / $dfWidthGeo;
292
293     // get difference
294     if (!$nInverseGeo)
295         $dfDeltaGeo = $nGeoPos - $dfGeoMin;
296     else
297         $dfDeltaGeo = $dfGeoMax - $nGeoPos;
298
299     // calculate
300     $dfDeltaPix = $dfDeltaGeo * $dfGeoToPix;
301     $dfPosPix = $dfPixMin + $dfDeltaPix;
302
303     // return value
304     return round ($dfPosPix);
305
306     // end pixel_to_geo function
307 }
308     
309 /**
310  * reproject a point nX,nY
311  * no reprojection happens if either projection is
312  * empty or if they are the same. Will prepend
313  * init= if either contains epsg (or EPSG)
314  *
315  * @param nX float reference the x coordinate to project
316  * @param nY float reference to the y coordinate to project
317  * @param szFrom string the projection of nX,nY
318  * @param szTo string the projection to convert to
319  * @return none.  Variables nX, nY are modified directly
320  */
321 function reprojectPoint( &$nX, &$nY, $szFrom, $szTo )
322 {
323     //echo "reproject $nX,$nY from $szFrom to $szTo<BR>\n";
324     
325     //check to see if reprojection is necessary
326     if ($szFrom == '' || $szTo == '')
327     {
328         return;
329     }
330     
331     if (stristr($szFrom, "epsg") !== false &&
332         stristr( $szFrom, "init=") == false)
333     {
334         $szFrom = "init=".strtolower($szFrom);
335     }
336     if (stristr($szTo, "epsg") !== false &&
337         stristr( $szTo, "init=") == false)
338     {
339         $szTo = "init=".strtolower($szTo);
340     }
341     
342     if ($szFrom == $szTo)
343     {
344         return;
345     }
346     
347     $oPoint = ms_newPointObj();
348     $oPoint->setXY( $nX, $nY );
349     $oPoint->project( ms_newProjectionObj( $szFrom ),
350                       ms_newProjectionObj( $szTo )
351                        );
352     $nX = $oPoint->x;
353     $nY = $oPoint->y;   
354     
355     //echo "reprojection result: $nX, $nY<BR>\n";
356 }
357 ?>
358
Note: See TracBrowser for help on using the browser.