root/Chameleon/trunk/Chameleon/geomath.php
Revision 13 (checked in by jcleary, 17 years ago) |
---|
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.