Index: trunk/extensions/SemanticMaps/SM_GeoCoordsValue.php |
— | — | @@ -1,335 +0,0 @@ |
2 | | -<?php |
3 | | -/** |
4 | | - * File holding the SMGeoCoordsValue class. |
5 | | - * |
6 | | - * @file SM_GeoCoordsValue.php |
7 | | - * @ingroup SMWDataValues |
8 | | - * |
9 | | - * @author Markus Krötzsch |
10 | | - * @author Jeroen De Dauw |
11 | | - */ |
12 | | - |
13 | | -// / Unicode symbols for coordinate minutes and seconds; |
14 | | -// / may not display in every font ... |
15 | | -define( 'SM_GEO_MIN', '′' ); |
16 | | -define( 'SM_GEO_SEC', '″' ); |
17 | | - |
18 | | -/** |
19 | | - * Implementation of datavalues that are geographic coordinates. |
20 | | - * |
21 | | - * @author Markus Krötzsch |
22 | | - * @author Jeroen De Dauw |
23 | | - * |
24 | | - * @ingroup SemanticMaps |
25 | | - */ |
26 | | -class SMGeoCoordsValue extends SMWDataValue { |
27 | | - |
28 | | - protected $m_N = false; // cache for localised direction labels |
29 | | - protected $m_E = false; // cache for localised direction labels |
30 | | - protected $m_W = false; // cache for localised direction labels |
31 | | - protected $m_S = false; // cache for localised direction labels |
32 | | - |
33 | | - protected $m_wikivalue; |
34 | | - protected $m_lat; // decimal latitude of current value |
35 | | - protected $m_long; // decimal longitude of current value |
36 | | - protected $m_latparts; // latitude array of four entries: degrees, minutes, seconds, direction |
37 | | - protected $m_longparts; // longitude array of four entries: degrees, minutes, seconds, direction |
38 | | - // Note: signs are used as e.g. on Google maps, i.e. S and W are negative numbers. |
39 | | - |
40 | | - protected function parseUserValue( $value ) { |
41 | | - $this->m_lat = false; |
42 | | - $this->m_long = false; |
43 | | - $this->m_latparts = false; |
44 | | - $this->m_longparts = false; |
45 | | - $this->m_wikivalue = $value; |
46 | | - |
47 | | - // first normalise some typical symbols |
48 | | - $this->initDirectionLabels(); |
49 | | - $value = str_replace( array( ' ', $this->m_N, $this->m_E, $this->m_W, $this->m_S, ), |
50 | | - array( ' ', 'N', 'E', 'W', 'S' ), $value ); |
51 | | - $value = str_replace( array( '°', '°' ), '°', $value ); |
52 | | - $value = str_replace( array( '´', '´' ), '´', $value ); |
53 | | - $value = str_replace( array( '″', '″', "''", '"', '´´', SM_GEO_MIN . SM_GEO_MIN ), SM_GEO_SEC, $value ); |
54 | | - $value = str_replace( array( '′', '′', "'", '´' ), SM_GEO_MIN, $value ); |
55 | | - // now split the string |
56 | | - $parts = preg_split( '/\s*(°|' . SM_GEO_MIN . '|' . SM_GEO_SEC . '|N|E|W|S|;)\s*/u', str_replace( ', ', ';', $value ) . ';', - 1, PREG_SPLIT_DELIM_CAPTURE ); |
57 | | - $curnum = false; |
58 | | - $angles = array( false, false, false ); // temporary values for deg, min, sec |
59 | | - foreach ( $parts as $part ) { |
60 | | - switch ( $part ) { |
61 | | - case '°': |
62 | | - if ( ( $angles[0] !== false ) && ( $this->m_lat === false ) ) { // work off values found earlier |
63 | | - $this->setAngleValues( 'N', $angles ); |
64 | | - } // else: we do not accept interchange of order (lat must be first), so there are just too many °s |
65 | | - if ( $curnum !== false ) { |
66 | | - $angles[0] = $curnum; |
67 | | - $curnum = false; |
68 | | - } else { |
69 | | - $this->addError( wfMsgForContent( 'semanticmaps_lonely_unit', $part ) ); |
70 | | - } |
71 | | - break; |
72 | | - case SM_GEO_MIN: |
73 | | - if ( ( $curnum !== false ) && ( $angles[1] === false ) ) { |
74 | | - $angles[1] = $curnum; |
75 | | - if ( $angles[0] === false ) $angles[0] = 0; |
76 | | - $curnum = false; |
77 | | - } else { |
78 | | - $this->addError( wfMsgForContent( 'semanticmaps_lonely_unit', $part ) ); |
79 | | - } |
80 | | - break; |
81 | | - case SM_GEO_SEC: |
82 | | - if ( ( $curnum !== false ) && ( $angles[2] === false ) ) { |
83 | | - $angles[2] = $curnum; |
84 | | - if ( $angles[0] === false ) $angles[0] = 0; |
85 | | - if ( $angles[1] === false ) $angles[1] = 0; |
86 | | - $curnum = false; |
87 | | - } else { |
88 | | - $this->addError( wfMsgForContent( 'semanticmaps_lonely_unit', $part ) ); |
89 | | - } |
90 | | - break; |
91 | | - case 'N': case 'S': // interpret findings as latitude |
92 | | - if ( $curnum !== false ) { // work off number without ° |
93 | | - if ( $angles[0] !== false ) { // "12° 34" as coordinate, complain |
94 | | - $this->addError( wfMsgForContent( 'semanticmaps_bad_latlong' ) ); |
95 | | - break; |
96 | | - } else { |
97 | | - $angles[0] = $curnum; |
98 | | - $curnum = false; |
99 | | - } |
100 | | - } |
101 | | - if ( ( $this->m_lat === false ) && ( $angles[0] !== false ) ) { |
102 | | - $this->setAngleValues( $part, $angles ); |
103 | | - } else { |
104 | | - $this->addError( wfMsgForContent( 'semanticmaps_bad_latlong' ) ); |
105 | | - } |
106 | | - break; |
107 | | - case 'E': case 'W': // interpret findings as longitude |
108 | | - if ( $curnum !== false ) { // work off number without ° |
109 | | - if ( $angles[0] !== false ) { // "12° 34" as coordinate, complain |
110 | | - $this->addError( wfMsgForContent( 'semanticmaps_bad_latlong' ) ); |
111 | | - break; |
112 | | - } else { |
113 | | - $angles[0] = $curnum; |
114 | | - $curnum = false; |
115 | | - } |
116 | | - } |
117 | | - if ( ( $this->m_long === false ) && ( $angles[0] !== false ) ) { |
118 | | - $this->setAngleValues( $part, $angles ); |
119 | | - } else { |
120 | | - $this->addError( wfMsgForContent( 'semanticmaps_bad_latlong' ) ); |
121 | | - } |
122 | | - break; |
123 | | - case ';': // interpret findings as latitude |
124 | | - if ( $curnum !== false ) { // work off number without ° |
125 | | - if ( $angles[0] !== false ) { // "12° 34" as coordinate, complain |
126 | | - $this->addError( wfMsgForContent( 'semanticmaps_bad_latlong' ) ); |
127 | | - break; |
128 | | - } else { |
129 | | - $angles[0] = $curnum; |
130 | | - $curnum = false; |
131 | | - } |
132 | | - } |
133 | | - if ( ( $this->m_lat === false ) && ( $angles[0] !== false ) ) { |
134 | | - $this->setAngleValues( 'N', $angles ); |
135 | | - } // else: ignore ";" without complaining |
136 | | - break; |
137 | | - case '': break; // ignore |
138 | | - default: // should be a number (if not, errors appear elsewhere) |
139 | | - // no kiloseps in coordinates, use as decsep as a convenience to some users (Bug 11808): |
140 | | - $curnum = str_replace( wfMsgForContent( 'smw_kiloseparator' ), wfMsgForContent( 'smw_decseparator' ), $part ); |
141 | | - break; |
142 | | - } |
143 | | - } |
144 | | - |
145 | | - if ( ( $this->m_lat !== false ) && ( $this->m_long === false ) && ( $angles[0] !== false ) ) { // no final E or W? |
146 | | - $this->setAngleValues( 'E', $angles ); |
147 | | - } |
148 | | - if ( ( $angles[0] !== false ) || ( $curnum !== false ) ) { // unprocessed chunk, error |
149 | | - |
150 | | - } |
151 | | - |
152 | | - if ( $this->m_caption === false ) { |
153 | | - $this->m_caption = $value; |
154 | | - } |
155 | | - return true; |
156 | | - } |
157 | | - |
158 | | - protected function parseDBkeys( $args ) { |
159 | | - $this->m_lat = false; |
160 | | - $this->m_long = false; |
161 | | - $this->m_latparts = false; |
162 | | - $this->m_longparts = false; |
163 | | - |
164 | | - list( $this->m_lat, $this->m_long ) = explode( ',', $args[0] ); |
165 | | - $this->m_caption = $this->formatAngleValues( true ) . ', ' . $this->formatAngleValues( false ); // this is our output text |
166 | | - $this->m_wikivalue = $this->m_caption; |
167 | | - } |
168 | | - |
169 | | - public function getShortWikiText( $linked = null ) { |
170 | | - if ( $this->isValid() && ( $linked !== null ) && ( $linked !== false ) ) { |
171 | | - SMWOutputs::requireHeadItem( SMW_HEADER_TOOLTIP ); |
172 | | - return '<span class="smwttinline">' . $this->m_caption . '<span class="smwttcontent">' . |
173 | | - wfMsgForContent( 'semanticmaps_label_latitude' ) . ' ' . $this->formatAngleValues( true ) . '<br />' . |
174 | | - wfMsgForContent( 'semanticmaps_label_longitude' ) . ' ' . $this->formatAngleValues( false ) . |
175 | | - '</span></span>'; |
176 | | - } else { |
177 | | - return $this->m_caption; |
178 | | - } |
179 | | - } |
180 | | - |
181 | | - public function getShortHTMLText( $linker = null ) { |
182 | | - return $this->getShortWikiText( $linker ); // should be save (based on xsdvalue) |
183 | | - } |
184 | | - |
185 | | - public function getLongWikiText( $linked = null ) { |
186 | | - if ( !$this->isValid() ) { |
187 | | - return $this->getErrorText(); |
188 | | - } else { |
189 | | - return $this->formatAngleValues( true ) . ', ' . $this->formatAngleValues( false ); |
190 | | - } |
191 | | - } |
192 | | - |
193 | | - public function getLongHTMLText( $linker = null ) { |
194 | | - return $this->getLongWikiText( $linker ); |
195 | | - } |
196 | | - |
197 | | - public function getDBkeys() { |
198 | | - $this->unstub(); |
199 | | - return array( $this->m_lat . ',' . $this->m_long ); |
200 | | - } |
201 | | - |
202 | | - public function getWikiValue() { |
203 | | - $this->unstub(); |
204 | | - return $this->m_wikivalue; |
205 | | - } |
206 | | - |
207 | | - public function getExportData() { |
208 | | - if ( $this->isValid() ) { |
209 | | - $lit = new SMWExpLiteral( $this->formatAngleValues( true, false ) . ', ' . $this->formatAngleValues( false, false ), $this, 'http://www.w3.org/2001/XMLSchema#string' ); |
210 | | - return new SMWExpData( $lit ); |
211 | | - } else { |
212 | | - return null; |
213 | | - } |
214 | | - } |
215 | | - |
216 | | - /** |
217 | | - * Get and cache localised direction labels. Just for convenience. |
218 | | - */ |
219 | | - protected function initDirectionLabels() { |
220 | | - $this->m_N = wfMsgForContent( 'semanticmaps_abb_north' ); |
221 | | - $this->m_E = wfMsgForContent( 'semanticmaps_abb_east' ); |
222 | | - $this->m_W = wfMsgForContent( 'semanticmaps_abb_west' ); |
223 | | - $this->m_S = wfMsgForContent( 'semanticmaps_abb_south' ); |
224 | | - } |
225 | | - |
226 | | - /** |
227 | | - * Helper function: read a possibly incomplete array of angles for one coordinate. |
228 | | - * The direction is one of N, E, W, S, and $angles is an array of three values, |
229 | | - * each possibly false if unset. |
230 | | - */ |
231 | | - protected function setAngleValues( $direction, &$angles ) { |
232 | | - $numvalue = SMWDataValueFactory::newTypeIDValue( '_num' ); |
233 | | - $res = 0; |
234 | | - $factor = 1; |
235 | | - for ( $i = 0; $i < 3; $i++ ) { |
236 | | - if ( $angles[$i] !== false ) { |
237 | | - $numvalue->setUserValue( $angles[$i] ); |
238 | | - if ( $numvalue->isValid() && ( $numvalue->getUnit() == '' ) ) { |
239 | | - $res += $numvalue->getNumericValue() / $factor; |
240 | | - } else { |
241 | | - $this->addError( wfMsgForContent( 'smw_nofloat', $angles[$i] ) ); |
242 | | - } |
243 | | - } |
244 | | - $factor = $factor * 60; |
245 | | - } |
246 | | - switch ( $direction ) { |
247 | | - case 'N': $this->m_lat = $res; break; |
248 | | - case 'S': $this->m_lat = - 1 * $res; break; |
249 | | - case 'E': $this->m_long = $res; break; |
250 | | - case 'W': $this->m_long = - 1 * $res; break; |
251 | | - } |
252 | | - if ( ( ( $direction == 'E' ) || ( $direction == 'W' ) ) && |
253 | | - ( ( $this->m_long > 180 ) || ( $this->m_long <= - 180 ) ) ) { // bring values back into [180, -180) |
254 | | - $this->m_long += ( $this->m_long < 0 ) ? ( round( abs( $this->m_long ) / 360 ) * 360 ):( round( $this->m_long / 360 ) * - 360 ); |
255 | | - } |
256 | | - // /TODO: also make such a normalisation for lat ... |
257 | | - $angles = array( false, false, false ); |
258 | | - } |
259 | | - |
260 | | - /** |
261 | | - * Return array with four entries for deg, min, sec, direction, |
262 | | - * that corresponds to the current latitude or longitude. |
263 | | - */ |
264 | | - protected function getAngleValues( $lat = true ) { |
265 | | - if ( $lat ) { |
266 | | - if ( $this->m_latparts !== false ) { |
267 | | - return $this->m_latparts; |
268 | | - } |
269 | | - $num = abs( $this->m_lat ); |
270 | | - $d = ( $this->m_lat < 0 ) ? 'S':'N'; |
271 | | - } else { |
272 | | - if ( $this->m_longparts !== false ) { |
273 | | - return $this->m_longparts; |
274 | | - } |
275 | | - $num = abs( $this->m_long ); |
276 | | - $d = ( $this->m_long < 0 ) ? 'W':'E'; |
277 | | - } |
278 | | - $result = array( 0, 0, 0, $d ); |
279 | | - $result[0] = floor( $num ); |
280 | | - $num = ( $num - $result[0] ) * 60; |
281 | | - $result[1] = floor( $num ); |
282 | | - $result[2] = ( $num - $result[1] ) * 60; |
283 | | - if ( abs( $result[2] ) < 0.001 ) { // limit precission, avoid conversion generated junk and EXP notation in coords |
284 | | - $result[2] = 0; |
285 | | - } |
286 | | - if ( $lat ) { |
287 | | - $this->m_latparts = $result; |
288 | | - } else { |
289 | | - $this->m_longparts = $result; |
290 | | - } |
291 | | - return $result; |
292 | | - } |
293 | | - |
294 | | - /** |
295 | | - * Format the current latitude or longitude. The parameter $content states |
296 | | - * whether the result is for content printout. Alternatively, a language- |
297 | | - * independent result is generated. |
298 | | - */ |
299 | | - protected function formatAngleValues( $lat = true, $content = true ) { |
300 | | - $values = $this->getAngleValues( $lat ); |
301 | | - if ( $content ) { |
302 | | - $this->initDirectionLabels(); |
303 | | - $result = smwfNumberFormat( $values[0] ) . '°' . smwfNumberFormat( $values[1] ) . SM_GEO_MIN . |
304 | | - smwfNumberFormat( $values[2] ) . SM_GEO_SEC; |
305 | | - switch ( $values[3] ) { |
306 | | - case 'N': return $result . $this->m_N; |
307 | | - case 'E': return $result . $this->m_E; |
308 | | - case 'W': return $result . $this->m_W; |
309 | | - case 'S': return $result . $this->m_S; |
310 | | - } |
311 | | - } else { |
312 | | - return smwfNumberFormat( $values[0] ) . '°' . smwfNumberFormat( $values[1] ) . SM_GEO_MIN . |
313 | | - smwfNumberFormat( $values[2] ) . SM_GEO_SEC . $values[3]; |
314 | | - } |
315 | | - } |
316 | | - |
317 | | - protected function getServiceLinkParams() { |
318 | | - // Create links to mapping services based on a wiki-editable message. The parameters |
319 | | - // available to the message are: |
320 | | - // $1: latitude integer degrees, $2: longitude integer degrees |
321 | | - // $3: latitude integer minutes, $4: longitude integer minutes |
322 | | - // $5: latitude integer seconds, $6: longitude integer seconds, |
323 | | - // $7: latitude direction string (N or S), $8: longitude direction string (W or E) |
324 | | - // $9: latitude in decimal degrees, $10: longitude in decimal degrees |
325 | | - // $11: sign (- if south) for latitude, $12: sign (- if west) for longitude |
326 | | - $latvals = $this->getAngleValues( true ); |
327 | | - $longvals = $this->getAngleValues( false ); |
328 | | - return array( $latvals[0], $longvals[0], |
329 | | - $latvals[1], $longvals[1], |
330 | | - round( $latvals[2] ), round( $longvals[2] ), |
331 | | - $latvals[3], $longvals[3], |
332 | | - abs( $this->m_lat ), abs( $this->m_long ), |
333 | | - $latvals[3] == 'S' ? '-':'', $longvals[3] == 'W' ? '-':'' ); |
334 | | - } |
335 | | - |
336 | | -} |
Index: trunk/extensions/SemanticMaps/GeoCoords/SM_GeoCoordsValue.php |
— | — | @@ -0,0 +1,413 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * File holding the SMGeoCoordsValue class. |
| 5 | + * |
| 6 | + * @file SM_GeoCoordsValue.php |
| 7 | + * @ingroup SMWDataValues |
| 8 | + * @ingroup SemanticMaps |
| 9 | + * |
| 10 | + * @author Markus Krötzsch |
| 11 | + * @author Jeroen De Dauw |
| 12 | + */ |
| 13 | + |
| 14 | +if ( !defined( 'MEDIAWIKI' ) ) { |
| 15 | + die( 'Not an entry point.' ); |
| 16 | +} |
| 17 | + |
| 18 | +// / Unicode symbols for coordinate minutes and seconds; |
| 19 | +// / may not display in every font ... |
| 20 | +define( 'SM_GEO_MIN', '′' ); |
| 21 | +define( 'SM_GEO_SEC', '″' ); |
| 22 | + |
| 23 | +/** |
| 24 | + * Implementation of datavalues that are geographic coordinates. |
| 25 | + * |
| 26 | + * @author Markus Krötzsch |
| 27 | + * @author Jeroen De Dauw |
| 28 | + * |
| 29 | + * @ingroup SemanticMaps |
| 30 | + * |
| 31 | + * TODO: this class should be integrated with Maps's handling of coordinates, as not to have redundant code. |
| 32 | + */ |
| 33 | +class SMGeoCoordsValue extends SMWDataValue { |
| 34 | + |
| 35 | + protected $m_N = false; // cache for localised direction labels |
| 36 | + protected $m_E = false; // cache for localised direction labels |
| 37 | + protected $m_W = false; // cache for localised direction labels |
| 38 | + protected $m_S = false; // cache for localised direction labels |
| 39 | + |
| 40 | + protected $m_wikivalue; |
| 41 | + protected $m_lat; // decimal latitude of current value |
| 42 | + protected $m_long; // decimal longitude of current value |
| 43 | + protected $m_latparts; // latitude array of four entries: degrees, minutes, seconds, direction |
| 44 | + protected $m_longparts; // longitude array of four entries: degrees, minutes, seconds, direction |
| 45 | + // Note: signs are used as e.g. on Google maps, i.e. S and W are negative numbers. |
| 46 | + |
| 47 | + /** |
| 48 | + * @see SMWDataValue::parseUserValue |
| 49 | + */ |
| 50 | + protected function parseUserValue( $value ) { |
| 51 | + return $this->parseUserValueOrQuery( $value, false ); |
| 52 | + } |
| 53 | + |
| 54 | + /** |
| 55 | + * Overwrite SMWDataValue::getQueryDescription() to be able to process |
| 56 | + * comparators between all values. |
| 57 | + * |
| 58 | + * @return SMGeoCoordsValueDescription |
| 59 | + */ |
| 60 | + public function getQueryDescription( $value ) { |
| 61 | + return $this->parseUserValueOrQuery( $value, true ); |
| 62 | + } |
| 63 | + |
| 64 | + /** |
| 65 | + * TODO: support $isQuery=true |
| 66 | + */ |
| 67 | + protected function parseUserValueOrQuery( $value, $isQuery ) { |
| 68 | + if ( $value == '' ) { |
| 69 | + $this->addError( wfMsg( 'smw_novalues' ) ); |
| 70 | + return $isQuery ? new SMWThingDescription() : true; |
| 71 | + } |
| 72 | + |
| 73 | + $this->m_lat = false; |
| 74 | + $this->m_long = false; |
| 75 | + $this->m_latparts = false; |
| 76 | + $this->m_longparts = false; |
| 77 | + $this->m_wikivalue = $value; |
| 78 | + |
| 79 | + // first normalise some typical symbols |
| 80 | + $this->initDirectionLabels(); |
| 81 | + $value = str_replace( array( ' ', $this->m_N, $this->m_E, $this->m_W, $this->m_S, ), |
| 82 | + array( ' ', 'N', 'E', 'W', 'S' ), $value ); |
| 83 | + $value = str_replace( array( '°', '°' ), '°', $value ); |
| 84 | + $value = str_replace( array( '´', '´' ), '´', $value ); |
| 85 | + $value = str_replace( array( '″', '″', "''", '"', '´´', SM_GEO_MIN . SM_GEO_MIN ), SM_GEO_SEC, $value ); |
| 86 | + $value = str_replace( array( '′', '′', "'", '´' ), SM_GEO_MIN, $value ); |
| 87 | + |
| 88 | + // now split the string |
| 89 | + $parts = preg_split( '/\s*(°|' . SM_GEO_MIN . '|' . SM_GEO_SEC . '|N|E|W|S|;)\s*/u', str_replace( ', ', ';', $value ) . ';', - 1, PREG_SPLIT_DELIM_CAPTURE ); |
| 90 | + $curnum = false; |
| 91 | + $angles = array( false, false, false ); // temporary values for deg, min, sec |
| 92 | + |
| 93 | + foreach ( $parts as $part ) { |
| 94 | + switch ( $part ) { |
| 95 | + case '°': |
| 96 | + if ( ( $angles[0] !== false ) && ( $this->m_lat === false ) ) { // work off values found earlier |
| 97 | + $this->setAngleValues( 'N', $angles ); |
| 98 | + } // else: we do not accept interchange of order (lat must be first), so there are just too many °s |
| 99 | + if ( $curnum !== false ) { |
| 100 | + $angles[0] = $curnum; |
| 101 | + $curnum = false; |
| 102 | + } else { |
| 103 | + $this->addError( wfMsgForContent( 'semanticmaps_lonely_unit', $part ) ); |
| 104 | + } |
| 105 | + break; |
| 106 | + case SM_GEO_MIN: |
| 107 | + if ( ( $curnum !== false ) && ( $angles[1] === false ) ) { |
| 108 | + $angles[1] = $curnum; |
| 109 | + if ( $angles[0] === false ) $angles[0] = 0; |
| 110 | + $curnum = false; |
| 111 | + } else { |
| 112 | + $this->addError( wfMsgForContent( 'semanticmaps_lonely_unit', $part ) ); |
| 113 | + } |
| 114 | + break; |
| 115 | + case SM_GEO_SEC: |
| 116 | + if ( ( $curnum !== false ) && ( $angles[2] === false ) ) { |
| 117 | + $angles[2] = $curnum; |
| 118 | + if ( $angles[0] === false ) $angles[0] = 0; |
| 119 | + if ( $angles[1] === false ) $angles[1] = 0; |
| 120 | + $curnum = false; |
| 121 | + } else { |
| 122 | + $this->addError( wfMsgForContent( 'semanticmaps_lonely_unit', $part ) ); |
| 123 | + } |
| 124 | + break; |
| 125 | + case 'N': case 'S': // interpret findings as latitude |
| 126 | + if ( $curnum !== false ) { // work off number without ° |
| 127 | + if ( $angles[0] !== false ) { // "12° 34" as coordinate, complain |
| 128 | + $this->addError( wfMsgForContent( 'semanticmaps_bad_latlong' ) ); |
| 129 | + break; |
| 130 | + } else { |
| 131 | + $angles[0] = $curnum; |
| 132 | + $curnum = false; |
| 133 | + } |
| 134 | + } |
| 135 | + if ( ( $this->m_lat === false ) && ( $angles[0] !== false ) ) { |
| 136 | + $this->setAngleValues( $part, $angles ); |
| 137 | + } else { |
| 138 | + $this->addError( wfMsgForContent( 'semanticmaps_bad_latlong' ) ); |
| 139 | + } |
| 140 | + break; |
| 141 | + case 'E': case 'W': // interpret findings as longitude |
| 142 | + if ( $curnum !== false ) { // work off number without ° |
| 143 | + if ( $angles[0] !== false ) { // "12° 34" as coordinate, complain |
| 144 | + $this->addError( wfMsgForContent( 'semanticmaps_bad_latlong' ) ); |
| 145 | + break; |
| 146 | + } else { |
| 147 | + $angles[0] = $curnum; |
| 148 | + $curnum = false; |
| 149 | + } |
| 150 | + } |
| 151 | + if ( ( $this->m_long === false ) && ( $angles[0] !== false ) ) { |
| 152 | + $this->setAngleValues( $part, $angles ); |
| 153 | + } else { |
| 154 | + $this->addError( wfMsgForContent( 'semanticmaps_bad_latlong' ) ); |
| 155 | + } |
| 156 | + break; |
| 157 | + case ';': // interpret findings as latitude |
| 158 | + if ( $curnum !== false ) { // work off number without ° |
| 159 | + if ( $angles[0] !== false ) { // "12° 34" as coordinate, complain |
| 160 | + $this->addError( wfMsgForContent( 'semanticmaps_bad_latlong' ) ); |
| 161 | + break; |
| 162 | + } else { |
| 163 | + $angles[0] = $curnum; |
| 164 | + $curnum = false; |
| 165 | + } |
| 166 | + } |
| 167 | + if ( ( $this->m_lat === false ) && ( $angles[0] !== false ) ) { |
| 168 | + $this->setAngleValues( 'N', $angles ); |
| 169 | + } // else: ignore ";" without complaining |
| 170 | + break; |
| 171 | + case '': break; // ignore |
| 172 | + default: // should be a number (if not, errors appear elsewhere) |
| 173 | + // no kiloseps in coordinates, use as decsep as a convenience to some users (Bug 11808): |
| 174 | + $curnum = str_replace( wfMsgForContent( 'smw_kiloseparator' ), wfMsgForContent( 'smw_decseparator' ), $part ); |
| 175 | + break; |
| 176 | + } |
| 177 | + } |
| 178 | + |
| 179 | + if ( ( $this->m_lat !== false ) && ( $this->m_long === false ) && ( $angles[0] !== false ) ) { // no final E or W? |
| 180 | + $this->setAngleValues( 'E', $angles ); |
| 181 | + } |
| 182 | + |
| 183 | + if ( ( $angles[0] !== false ) || ( $curnum !== false ) ) { // unprocessed chunk, error |
| 184 | + |
| 185 | + } |
| 186 | + |
| 187 | + if ( $this->m_caption === false ) { |
| 188 | + $this->m_caption = $value; |
| 189 | + } |
| 190 | + |
| 191 | + if ( $isQuery ) { |
| 192 | + return new SMGeoCoordsValueDescription( ); // TODO |
| 193 | + } else { |
| 194 | + return true; |
| 195 | + } |
| 196 | + } |
| 197 | + |
| 198 | + /** |
| 199 | + * @see SMWDataValue::parseDBkeys |
| 200 | + */ |
| 201 | + protected function parseDBkeys( $args ) { |
| 202 | + $this->m_lat = false; |
| 203 | + $this->m_long = false; |
| 204 | + $this->m_latparts = false; |
| 205 | + $this->m_longparts = false; |
| 206 | + |
| 207 | + list( $this->m_lat, $this->m_long ) = explode( ',', $args[0] ); |
| 208 | + |
| 209 | + $this->m_caption = $this->formatAngleValues( true ) . ', ' . $this->formatAngleValues( false ); // this is our output text |
| 210 | + $this->m_wikivalue = $this->m_caption; |
| 211 | + } |
| 212 | + |
| 213 | + /** |
| 214 | + * @see SMWDataValue::getShortWikiText |
| 215 | + */ |
| 216 | + public function getShortWikiText( $linked = null ) { |
| 217 | + if ( $this->isValid() && ( $linked !== null ) && ( $linked !== false ) ) { |
| 218 | + SMWOutputs::requireHeadItem( SMW_HEADER_TOOLTIP ); |
| 219 | + return '<span class="smwttinline">' . $this->m_caption . '<span class="smwttcontent">' . |
| 220 | + wfMsgForContent( 'semanticmaps_label_latitude' ) . ' ' . $this->formatAngleValues( true ) . '<br />' . |
| 221 | + wfMsgForContent( 'semanticmaps_label_longitude' ) . ' ' . $this->formatAngleValues( false ) . |
| 222 | + '</span></span>'; |
| 223 | + } else { |
| 224 | + return $this->m_caption; |
| 225 | + } |
| 226 | + } |
| 227 | + |
| 228 | + /** |
| 229 | + * @see SMWDataValue::getShortHTMLText |
| 230 | + */ |
| 231 | + public function getShortHTMLText( $linker = null ) { |
| 232 | + return $this->getShortWikiText( $linker ); // should be save (based on xsdvalue) |
| 233 | + } |
| 234 | + |
| 235 | + /** |
| 236 | + * @see SMWDataValue::getLongWikiText |
| 237 | + */ |
| 238 | + public function getLongWikiText( $linked = null ) { |
| 239 | + if ( !$this->isValid() ) { |
| 240 | + return $this->getErrorText(); |
| 241 | + } else { |
| 242 | + return $this->formatAngleValues( true ) . ', ' . $this->formatAngleValues( false ); |
| 243 | + } |
| 244 | + } |
| 245 | + |
| 246 | + /** |
| 247 | + * @see SMWDataValue::getLongHTMLText |
| 248 | + */ |
| 249 | + public function getLongHTMLText( $linker = null ) { |
| 250 | + return $this->getLongWikiText( $linker ); |
| 251 | + } |
| 252 | + |
| 253 | + /** |
| 254 | + * @see SMWDataValue::getDBkeys |
| 255 | + */ |
| 256 | + public function getDBkeys() { |
| 257 | + $this->unstub(); |
| 258 | + return array( $this->m_lat . ',' . $this->m_long ); |
| 259 | + } |
| 260 | + |
| 261 | + /** |
| 262 | + * @see SMWDataValue::getWikiValue |
| 263 | + */ |
| 264 | + public function getWikiValue() { |
| 265 | + $this->unstub(); |
| 266 | + return $this->m_wikivalue; |
| 267 | + } |
| 268 | + |
| 269 | + /** |
| 270 | + * @see SMWDataValue::getExportData |
| 271 | + */ |
| 272 | + public function getExportData() { |
| 273 | + if ( $this->isValid() ) { |
| 274 | + $lit = new SMWExpLiteral( $this->formatAngleValues( true, false ) . ', ' . $this->formatAngleValues( false, false ), $this, 'http://www.w3.org/2001/XMLSchema#string' ); |
| 275 | + return new SMWExpData( $lit ); |
| 276 | + } else { |
| 277 | + return null; |
| 278 | + } |
| 279 | + } |
| 280 | + |
| 281 | + /** |
| 282 | + * Get and cache localised direction labels. Just for convenience. |
| 283 | + */ |
| 284 | + protected function initDirectionLabels() { |
| 285 | + $this->m_N = wfMsgForContent( 'semanticmaps_abb_north' ); |
| 286 | + $this->m_E = wfMsgForContent( 'semanticmaps_abb_east' ); |
| 287 | + $this->m_W = wfMsgForContent( 'semanticmaps_abb_west' ); |
| 288 | + $this->m_S = wfMsgForContent( 'semanticmaps_abb_south' ); |
| 289 | + } |
| 290 | + |
| 291 | + /** |
| 292 | + * Helper function: read a possibly incomplete array of angles for one coordinate. |
| 293 | + * The direction is one of N, E, W, S, and $angles is an array of three values, |
| 294 | + * each possibly false if unset. |
| 295 | + */ |
| 296 | + protected function setAngleValues( $direction, &$angles ) { |
| 297 | + $numvalue = SMWDataValueFactory::newTypeIDValue( '_num' ); |
| 298 | + $res = 0; |
| 299 | + $factor = 1; |
| 300 | + |
| 301 | + for ( $i = 0; $i < 3; $i++ ) { |
| 302 | + if ( $angles[$i] !== false ) { |
| 303 | + $numvalue->setUserValue( $angles[$i] ); |
| 304 | + if ( $numvalue->isValid() && ( $numvalue->getUnit() == '' ) ) { |
| 305 | + $res += $numvalue->getNumericValue() / $factor; |
| 306 | + } else { |
| 307 | + $this->addError( wfMsgForContent( 'smw_nofloat', $angles[$i] ) ); |
| 308 | + } |
| 309 | + } |
| 310 | + $factor = $factor * 60; |
| 311 | + } |
| 312 | + |
| 313 | + switch ( $direction ) { |
| 314 | + case 'N': $this->m_lat = $res; break; |
| 315 | + case 'S': $this->m_lat = - 1 * $res; break; |
| 316 | + case 'E': $this->m_long = $res; break; |
| 317 | + case 'W': $this->m_long = - 1 * $res; break; |
| 318 | + } |
| 319 | + |
| 320 | + if ( ( ( $direction == 'E' ) || ( $direction == 'W' ) ) && |
| 321 | + ( ( $this->m_long > 180 ) || ( $this->m_long <= - 180 ) ) ) { // bring values back into [180, -180) |
| 322 | + $this->m_long += ( $this->m_long < 0 ) ? ( round( abs( $this->m_long ) / 360 ) * 360 ):( round( $this->m_long / 360 ) * - 360 ); |
| 323 | + } |
| 324 | + // TODO: also make such a normalisation for lat ... |
| 325 | + |
| 326 | + $angles = array( false, false, false ); |
| 327 | + } |
| 328 | + |
| 329 | + /** |
| 330 | + * Return array with four entries for deg, min, sec, direction, |
| 331 | + * that corresponds to the current latitude or longitude. |
| 332 | + * |
| 333 | + * @param Boolean $lat When true, latitude will be used, otherwise longitude will be. |
| 334 | + */ |
| 335 | + protected function getAngleValues( $lat = true ) { |
| 336 | + if ( $lat ) { |
| 337 | + if ( $this->m_latparts !== false ) { |
| 338 | + return $this->m_latparts; |
| 339 | + } |
| 340 | + $num = abs( $this->m_lat ); |
| 341 | + $d = ( $this->m_lat < 0 ) ? 'S':'N'; |
| 342 | + } else { |
| 343 | + if ( $this->m_longparts !== false ) { |
| 344 | + return $this->m_longparts; |
| 345 | + } |
| 346 | + $num = abs( $this->m_long ); |
| 347 | + $d = ( $this->m_long < 0 ) ? 'W':'E'; |
| 348 | + } |
| 349 | + $result = array( 0, 0, 0, $d ); |
| 350 | + $result[0] = floor( $num ); |
| 351 | + $num = ( $num - $result[0] ) * 60; |
| 352 | + $result[1] = floor( $num ); |
| 353 | + $result[2] = ( $num - $result[1] ) * 60; |
| 354 | + if ( abs( $result[2] ) < 0.001 ) { // limit precission, avoid conversion generated junk and EXP notation in coords |
| 355 | + $result[2] = 0; |
| 356 | + } |
| 357 | + if ( $lat ) { |
| 358 | + $this->m_latparts = $result; |
| 359 | + } else { |
| 360 | + $this->m_longparts = $result; |
| 361 | + } |
| 362 | + return $result; |
| 363 | + } |
| 364 | + |
| 365 | + /** |
| 366 | + * Format the current latitude or longitude. The parameter $content states |
| 367 | + * whether the result is for content printout. Alternatively, a language- |
| 368 | + * independent result is generated. |
| 369 | + * |
| 370 | + * @param Boolean $lat When true, latitude will be used, otherwise longitude will be. |
| 371 | + * @param Boolean $content |
| 372 | + */ |
| 373 | + protected function formatAngleValues( $lat = true, $content = true ) { |
| 374 | + $values = $this->getAngleValues( $lat ); |
| 375 | + |
| 376 | + if ( $content ) { |
| 377 | + $this->initDirectionLabels(); |
| 378 | + $result = smwfNumberFormat( $values[0] ) . '°' . smwfNumberFormat( $values[1] ) . SM_GEO_MIN . |
| 379 | + smwfNumberFormat( $values[2] ) . SM_GEO_SEC; |
| 380 | + switch ( $values[3] ) { |
| 381 | + case 'N': return $result . $this->m_N; |
| 382 | + case 'E': return $result . $this->m_E; |
| 383 | + case 'W': return $result . $this->m_W; |
| 384 | + case 'S': return $result . $this->m_S; |
| 385 | + } |
| 386 | + } else { |
| 387 | + return smwfNumberFormat( $values[0] ) . '°' . smwfNumberFormat( $values[1] ) . SM_GEO_MIN . |
| 388 | + smwfNumberFormat( $values[2] ) . SM_GEO_SEC . $values[3]; |
| 389 | + } |
| 390 | + } |
| 391 | + |
| 392 | + /** |
| 393 | + * Create links to mapping services based on a wiki-editable message. The parameters |
| 394 | + * available to the message are: |
| 395 | + * |
| 396 | + * $1: latitude integer degrees, $2: longitude integer degrees |
| 397 | + * $3: latitude integer minutes, $4: longitude integer minutes |
| 398 | + * $5: latitude integer seconds, $6: longitude integer seconds, |
| 399 | + * $7: latitude direction string (N or S), $8: longitude direction string (W or E) |
| 400 | + * $9: latitude in decimal degrees, $10: longitude in decimal degrees |
| 401 | + * $11: sign (- if south) for latitude, $12: sign (- if west) for longitude |
| 402 | + */ |
| 403 | + protected function getServiceLinkParams() { |
| 404 | + $latvals = $this->getAngleValues( true ); |
| 405 | + $longvals = $this->getAngleValues( false ); |
| 406 | + return array( $latvals[0], $longvals[0], |
| 407 | + $latvals[1], $longvals[1], |
| 408 | + round( $latvals[2] ), round( $longvals[2] ), |
| 409 | + $latvals[3], $longvals[3], |
| 410 | + abs( $this->m_lat ), abs( $this->m_long ), |
| 411 | + $latvals[3] == 'S' ? '-':'', $longvals[3] == 'W' ? '-':'' ); |
| 412 | + } |
| 413 | + |
| 414 | +} |
Property changes on: trunk/extensions/SemanticMaps/GeoCoords/SM_GeoCoordsValue.php |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 415 | + native |
Index: trunk/extensions/SemanticMaps/GeoCoords/SM_GeoCoords.php |
— | — | @@ -0,0 +1,71 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * File containing the registration and initialization code for the Semantic MediaWiki |
| 6 | + * Geographical Coordinates data type, and things it's dependent on. |
| 7 | + * |
| 8 | + * @file SM_GeoCoords.php |
| 9 | + * @ingroup SemanticMaps |
| 10 | + * |
| 11 | + * @author Jeroen De Dauw |
| 12 | + * @author Markus Krötzsch |
| 13 | + */ |
| 14 | + |
| 15 | +// Registration of the Geographical Coordinate type. |
| 16 | +$wgAutoloadClasses['SMGeoCoordsValue'] = $smgDir . 'GeoCoords/SM_GeoCoordsValue.php'; |
| 17 | + |
| 18 | +// Registration of the Geographical Coordinate value description class. |
| 19 | +$wgAutoloadClasses['SMGeoCoordsValueDescription'] = $smgDir . 'GeoCoords/SM_GeoCoordsValueDescription.php'; |
| 20 | + |
| 21 | +// Hook for initializing the Geographical Coordinate type. |
| 22 | +$wgHooks['smwInitDatatypes'][] = 'smfInitGeoCoordsType'; |
| 23 | + |
| 24 | +// Hook for initializing the Geographical Proximity query support. |
| 25 | +$wgHooks['smwGetSQLConditionForValue'][] = 'smfGetGeoProximitySQLCondition'; |
| 26 | + |
| 27 | +/** |
| 28 | + * Adds support for the geographical coordinate data type to Semantic MediaWiki. |
| 29 | + * |
| 30 | + * TODO: i18n keys still need to be moved |
| 31 | + */ |
| 32 | +function smfInitGeoCoordsType() { |
| 33 | + SMWDataValueFactory::registerDatatype( '_geo', 'SMGeoCoordsValue', 'Geographic coordinate' ); |
| 34 | + return true; |
| 35 | +} |
| 36 | + |
| 37 | +/** |
| 38 | + * Custom SQL query extension for matching geographic coordinates. |
| 39 | + * |
| 40 | + * TODO: Parsing latitude and longitude from the DB key of the coordinates |
| 41 | + * value is cleary not a good approach. Instead, the geographic coordinate |
| 42 | + * value object should provide functions to access this data directly. |
| 43 | + * |
| 44 | + * TODO: Add support for a per-coordinate set distance parameter. |
| 45 | + */ |
| 46 | +function smfGetGeoProximitySQLCondition( &$where, $description, $tablename, $fieldname, $dbs ) { |
| 47 | + $where = ''; |
| 48 | + $dv = $description->getDatavalue(); |
| 49 | + |
| 50 | + if ( ( $dv->getTypeID() != '_geo' ) |
| 51 | + || ( !$dv->isValid() ) |
| 52 | + || ( $description->getComparator() != SMW_CMP_LIKE ) |
| 53 | + ) return true; // Only act on certain query conditions. |
| 54 | + |
| 55 | + $keys = $dv->getDBkeys(); |
| 56 | + $geoarray = explode( ',', $keys[0] ); |
| 57 | + |
| 58 | + if ( ( count( $geoarray ) != 2 ) |
| 59 | + || ( $geoarray[0] == '' ) |
| 60 | + || ( $geoarray[1] == '' ) |
| 61 | + ) return true; // There is something wrong with the lat/lon pair |
| 62 | + |
| 63 | + $latitude = $dbs->addQuotes( $geoarray[0] ); |
| 64 | + $longitude = $dbs->addQuotes( $geoarray[1] ); |
| 65 | + |
| 66 | + // Compute distances in miles: |
| 67 | + $distance = "ROUND(((ACOS( SIN({$latitude} * PI()/180 ) * SIN(SUBSTRING_INDEX({$tablename}.{$fieldname}, ',',1) * PI()/180 ) + COS({$latitude} * PI()/180 ) * COS(SUBSTRING_INDEX({$tablename}.{$fieldname}, ',',1) * PI()/180 ) * COS(({$longitude} - SUBSTRING_INDEX({$tablename}.{$fieldname}, ',',-1)) * PI()/180))*180/PI())*60*1.1515),6)"; |
| 68 | + |
| 69 | + $where = "{$distance} <= " . $dbs->addQuotes( "5" ); |
| 70 | + |
| 71 | + return true; |
| 72 | +} |
\ No newline at end of file |
Property changes on: trunk/extensions/SemanticMaps/GeoCoords/SM_GeoCoords.php |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 73 | + native |
Index: trunk/extensions/SemanticMaps/GeoCoords/SM_GeoCoordsValueDescription.php |
— | — | @@ -0,0 +1,32 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * File holding the SMGeoCoordsValueDescription class. |
| 6 | + * |
| 7 | + * @file SM_GeoCoordsValueDescription.php |
| 8 | + * @ingroup SemanticMaps |
| 9 | + * |
| 10 | + * @author Jeroen De Dauw |
| 11 | + */ |
| 12 | + |
| 13 | +if ( !defined( 'MEDIAWIKI' ) ) { |
| 14 | + die( 'Not an entry point.' ); |
| 15 | +} |
| 16 | + |
| 17 | +/** |
| 18 | + * Description of one data value of type Goegraphical Coordinates. |
| 19 | + * |
| 20 | + * @author Jeroen De Dauw |
| 21 | + * |
| 22 | + * @ingroup SemanticMaps |
| 23 | + */ |
| 24 | +class SMGeoCoordsValueDescription extends SMWValueDescription { |
| 25 | + |
| 26 | + protected $m_distance; |
| 27 | + |
| 28 | + public function __construct( SMGeoCoordsValue $datavalue, $distance, $comparator = SMW_CMP_EQ ) { |
| 29 | + parent::__construct( $datavalue, $comparator ); |
| 30 | + $this->m_distance = $distance; |
| 31 | + } |
| 32 | + |
| 33 | +} |
\ No newline at end of file |
Property changes on: trunk/extensions/SemanticMaps/GeoCoords/SM_GeoCoordsValueDescription.php |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 34 | + native |
Index: trunk/extensions/SemanticMaps/SM_Settings.php |
— | — | @@ -60,6 +60,17 @@ |
61 | 61 | |
62 | 62 | |
63 | 63 | |
| 64 | + |
| 65 | +# Geographical Coordinate data type settings |
| 66 | + |
| 67 | +# Integer. The default distance value to be used in geographical distance queries. |
| 68 | +# This value will only be used when the user does not provide one. |
| 69 | +$smgGeoCoordDistance = 5; |
| 70 | + |
| 71 | + |
| 72 | + |
| 73 | + |
| 74 | + |
64 | 75 | # Query Printers |
65 | 76 | |
66 | 77 | # Boolean. The default value for the forceshow parameter. Will force a map to be shown even when there are no query results |
Index: trunk/extensions/SemanticMaps/SemanticMaps.php |
— | — | @@ -35,7 +35,7 @@ |
36 | 36 | |
37 | 37 | // Only initialize the extension when all dependencies are present. |
38 | 38 | if ( defined( 'Maps_VERSION' ) && defined( 'SMW_VERSION' ) ) { |
39 | | - define( 'SM_VERSION', '0.5.5 a1' ); |
| 39 | + define( 'SM_VERSION', '0.5.5 a2' ); |
40 | 40 | |
41 | 41 | $smgScriptPath = ( isset( $wgExtensionAssetsPath ) && $wgExtensionAssetsPath ? $wgExtensionAssetsPath : $wgScriptPath . '/extensions' ) . '/SemanticMaps'; |
42 | 42 | $smgDir = dirname( __FILE__ ) . '/'; |
— | — | @@ -51,9 +51,8 @@ |
52 | 52 | |
53 | 53 | $wgExtensionMessagesFiles['SemanticMaps'] = $smgDir . 'SemanticMaps.i18n.php'; |
54 | 54 | |
55 | | - // Registration of the Geographical Coordinate type. |
56 | | - $wgAutoloadClasses['SMGeoCoordsValue'] = $smgDir . 'SM_GeoCoordsValue.php'; |
57 | | - $wgHooks['smwInitDatatypes'][] = 'smfInitGeoCoordsType'; |
| 55 | + // Include the GeoCoords SMW data type file. |
| 56 | + require_once( $smgDir . '/GeoCoords/SM_GeoCoords.php' ); |
58 | 57 | } |
59 | 58 | |
60 | 59 | /** |
— | — | @@ -80,20 +79,13 @@ |
81 | 80 | 'description' => wfMsgExt( 'semanticmaps_desc', 'parsemag', $services_list ), |
82 | 81 | ); |
83 | 82 | |
| 83 | + // TODO: only add this file when it's required. |
84 | 84 | $wgOut->addScriptFile( $smgScriptPath . '/SMUtilityFunctions.js' ); |
85 | 85 | |
86 | 86 | return true; |
87 | 87 | } |
88 | 88 | |
89 | 89 | /** |
90 | | - * Adds support for the geographical coordinate data type to Semantic MediaWiki. |
91 | | - */ |
92 | | -function smfInitGeoCoordsType() { |
93 | | - SMWDataValueFactory::registerDatatype( '_geo', 'SMGeoCoordsValue', 'Geographic coordinate' ); |
94 | | - return true; |
95 | | -} |
96 | | - |
97 | | -/** |
98 | 90 | * Adds a link to Admin Links page. |
99 | 91 | */ |
100 | 92 | function smfAddToAdminLinks( &$admin_links_tree ) { |