| 39 | | function _normaliseAddress($address) { |
|---|
| 40 | | $nAddress = strtolower($address); |
|---|
| 41 | | |
|---|
| 42 | | if (stristr($nAddress, "<br/>")) { $nAddress = str_replace("<br/>", "\n", $nAddress); } |
|---|
| 43 | | if (stristr($nAddress, "<br>")) { $nAddress = str_replace("<br>", "\n", $nAddress); } |
|---|
| 44 | | if (stristr($nAddress, "</p>")) { $nAddress = str_replace("</p>", "\n", $nAddress); } |
|---|
| 45 | | if (stristr($nAddress, ",")) { $nAddress = str_replace(",", "\n", $nAddress); } |
|---|
| 46 | | |
|---|
| 47 | | //d("nAddress: $nAddress",Null, True); |
|---|
| 48 | | return $nAddress; |
|---|
| 49 | | } |
|---|
| 50 | | |
|---|
| 51 | | function _validateUKLocation($loc) { |
|---|
| 52 | | /* Check in UK */ |
|---|
| 53 | | if ($loc["status"] != 200) { |
|---|
| 54 | | return Null; |
|---|
| 55 | | } |
|---|
| 56 | | |
|---|
| 57 | | if ($loc["latitude"] > 62.0 or $loc["latitude"] < 50.0) { |
|---|
| 58 | | return Null; |
|---|
| 59 | | } |
|---|
| 60 | | |
|---|
| 61 | | if ($loc["longitude"] < -12.0 or $loc["longitude"] > 4.0) { |
|---|
| 62 | | return Null; |
|---|
| 63 | | } |
|---|
| 64 | | |
|---|
| 65 | | return $loc; |
|---|
| 66 | | } |
|---|
| 67 | | |
|---|
| 68 | | function _smart_geocode($address, $areaCode=Null) { |
|---|
| 69 | | |
|---|
| 70 | | // Get area code (eg. postcode). |
|---|
| 71 | | $areaLoc = gmap_geocode($areaCode); |
|---|
| 72 | | $areaLoc = _validateUKLocation($areaLoc); |
|---|
| 73 | | |
|---|
| 74 | | // Normalise address into lines. |
|---|
| 75 | | $nAddress = _normaliseAddress($address); |
|---|
| 76 | | $addressLines = split("[\n]+", $nAddress); |
|---|
| 77 | | //d("addressLines", $addressLines, True); |
|---|
| 78 | | |
|---|
| 79 | | $addressLoc = Null; |
|---|
| 80 | | |
|---|
| 81 | | /* Sometimes the postcode throws google api off, so if we have an explicit postcode, remove it from address. */ |
|---|
| 82 | | //if (preg_match('/^[0-9]*$/i', $addressLines[count($addressLines)-1])) { |
|---|
| 83 | | // $addressLines[count($addressLines)-1] = ""; |
|---|
| 84 | | //} |
|---|
| 85 | | |
|---|
| 86 | | /* Google doesn't like the things at the top of address (e.g. company name, building), so prune it down. */ |
|---|
| 87 | | while ($addressLines) { |
|---|
| 88 | | $partAddress = implode(", ", $addressLines); |
|---|
| 89 | | |
|---|
| 90 | | $partLoc = gmap_geocode($partAddress); |
|---|
| 91 | | $partLoc = _validateUKLocation($partLoc); |
|---|
| 92 | | |
|---|
| 93 | | if ($partLoc["status"] != 200) { |
|---|
| 94 | | //pass |
|---|
| 95 | | } else { |
|---|
| 96 | | if ($areaLoc) { |
|---|
| 97 | | $dist = _location_dist($areaLoc, $partLoc); |
|---|
| 98 | | } else { |
|---|
| 99 | | $dist = PROXIMITY_THRESHOLD * 0.5; |
|---|
| 100 | | } |
|---|
| 101 | | |
|---|
| 102 | | if ($dist < PROXIMITY_THRESHOLD) { |
|---|
| 103 | | if ($addressLoc) { |
|---|
| 104 | | if ($partLoc["accuracy"] > $addressLoc["accuracy"]) { |
|---|
| 105 | | $addressLoc = $partLoc; |
|---|
| 106 | | } |
|---|
| 107 | | } else { |
|---|
| 108 | | $addressLoc = $partLoc; |
|---|
| 109 | | } |
|---|
| 110 | | } |
|---|
| 111 | | } |
|---|
| 112 | | |
|---|
| 113 | | //d("partAddress $partAddress", $partLoc, True); |
|---|
| 114 | | array_shift($addressLines); |
|---|
| 115 | | } |
|---|
| 116 | | |
|---|
| 117 | | // Choose the most accurate location. |
|---|
| 118 | | if ($addressLoc and !$areaLoc) { |
|---|
| 119 | | return $addressLoc; |
|---|
| 120 | | } else if ($areaLoc and !$addressLoc) { |
|---|
| 121 | | return $areaLoc; |
|---|
| 122 | | } else if ($addressLoc and $areaLoc) { |
|---|
| 123 | | if ($addressLoc["accuracy"] > $areaLoc["accuracy"]) { |
|---|
| 124 | | return $addressLoc; |
|---|
| 125 | | } else { |
|---|
| 126 | | return $areaLoc; |
|---|
| 127 | | } |
|---|
| 128 | | } |
|---|
| 129 | | |
|---|
| 130 | | return Null; |
|---|
| 131 | | } |
|---|
| 132 | | |
|---|
| 133 | | function _set_node_geocode(&$node) { |
|---|
| 134 | | //Updates the location of a node based on specific fields (e.g. address, postcode). |
|---|
| 135 | | |
|---|
| 136 | | $addressField = variable_get("simplemap.addressfield", "field_address"); |
|---|
| 137 | | eval("\$address = \$node->".$addressField."[0]['value'];"); |
|---|
| 138 | | |
|---|
| 139 | | // Try to find a postcode cck field. |
|---|
| 140 | | $postcode = $node->field_postcode[0]["value"]; |
|---|
| 141 | | |
|---|
| 142 | | if (!$address and !$postcode) { |
|---|
| 143 | | variable_del("simplemap.nloc-$node->nid"); |
|---|
| 144 | | return; |
|---|
| 145 | | } |
|---|
| 146 | | |
|---|
| 147 | | // Do geocode lookup. |
|---|
| 148 | | $location = _smart_geocode($address, $postcode); |
|---|
| 149 | | //d("lookup of $address/$postcode", $location); |
|---|
| 150 | | |
|---|
| 151 | | if ($location["status"] != "200") { |
|---|
| 152 | | variable_del("simplemap.nloc-$node->nid"); |
|---|
| 153 | | return; |
|---|
| 154 | | } |
|---|
| 155 | | |
|---|
| 156 | | variable_set("simplemap.nloc-$node->nid", $location); |
|---|
| 157 | | drupal_set_message("The geographic location of this $node->type has been found and set."); |
|---|
| 158 | | } |
|---|
| 159 | | |
|---|
| 160 | | function _get_node_location($nid) { |
|---|
| 161 | | // Gets the geographic location of a node with nid. |
|---|
| 162 | | return variable_get("simplemap.nloc-$nid", Null); |
|---|
| 163 | | } |
|---|
| 164 | | |
|---|
| | 66 | |
|---|
| | 67 | /* Capture node saves to process geocodes. */ |
|---|
| 175 | | function _get_markers($view) { |
|---|
| 176 | | |
|---|
| 177 | | global $base_url; |
|---|
| 178 | | |
|---|
| 179 | | $markers = array(); |
|---|
| 180 | | $viewResults = views_build_view('items', $view, Null, false, $view->nodes_per_block); |
|---|
| 181 | | foreach ($viewResults['items'] as $i => $item) { |
|---|
| 182 | | //d("item",$item); |
|---|
| 183 | | $location = _get_node_location($item->nid); |
|---|
| 184 | | //$location = _smart_geocode("Warwickshire Association of Youth Clubs Jubilee House, Westlea Road Leamington Spa, CV31 3JE"); |
|---|
| 185 | | //$location = _smart_geocode("Westlea Road Leamington Spa CV31 3JE"); |
|---|
| 186 | | //$location = _smart_geocode("CV31 3JE"); |
|---|
| 187 | | if (!$location) { |
|---|
| 188 | | d("$item->node_title as no location"); |
|---|
| 189 | | continue; |
|---|
| 190 | | } |
|---|
| 191 | | |
|---|
| 192 | | $url = "$base_url/node/$item->nid"; |
|---|
| 193 | | |
|---|
| 194 | | $markers[] = array( |
|---|
| 195 | | 'latitude' => $location["latitude"], |
|---|
| 196 | | 'longitude' => $location["longitude"], |
|---|
| 197 | | 'markername' => "", |
|---|
| 198 | | 'text' => "<a href='$url'>".$item->node_title."</a>", |
|---|
| 199 | | 'offset' => 0, |
|---|
| 200 | | ); |
|---|
| 201 | | } |
|---|
| 202 | | |
|---|
| 203 | | //d("markers",$markers); |
|---|
| 204 | | return $markers; |
|---|
| 205 | | } |
|---|
| 206 | | |
|---|
| 207 | | function _render_map($markers=Null) { |
|---|
| 208 | | $output = ""; |
|---|
| 209 | | $map = gmap_defaults(); |
|---|
| 210 | | |
|---|
| 211 | | if ($markers) { |
|---|
| 212 | | $map["markers"] = $markers; |
|---|
| 213 | | } |
|---|
| 214 | | //d("",$map); |
|---|
| 215 | | $output .= theme('gmap', array('#settings' => $map)); |
|---|
| 216 | | |
|---|
| 217 | | return $output; |
|---|
| 218 | | } |
|---|
| 219 | | |
|---|
| 220 | | |
|---|
| | 78 | |
|---|
| | 79 | /* Initialise the module. */ |
|---|
| | 80 | function simple_maps_init() { |
|---|
| | 81 | //cache_clear_all('*', 'cache_menu', TRUE); |
|---|
| | 82 | //_tests(); |
|---|
| | 83 | //_update_locations(); |
|---|
| | 84 | } |
|---|
| | 85 | |
|---|
| | 86 | |
|---|
| | 87 | /* |
|---|
| | 88 | * =============================== |
|---|
| | 89 | * PAGES |
|---|
| | 90 | * =============================== |
|---|
| | 91 | */ |
|---|
| | 92 | |
|---|
| | 93 | |
|---|
| | 94 | /* Display a map of location-aware nodes in the specified view. */ |
|---|
| | 146 | |
|---|
| | 147 | /* |
|---|
| | 148 | * =============================== |
|---|
| | 149 | * MAIN FUNCTIONS |
|---|
| | 150 | * =============================== |
|---|
| | 151 | */ |
|---|
| | 152 | |
|---|
| | 153 | /* Looks at permutations of the address and postcode to try to improve accuracy of google api. */ |
|---|
| | 154 | function _smart_geocode($address, $areaCode=Null) { |
|---|
| | 155 | |
|---|
| | 156 | // Get area code (eg. postcode). |
|---|
| | 157 | $areaLoc = gmap_geocode($areaCode); |
|---|
| | 158 | $areaLoc = _validateUKLocation($areaLoc); |
|---|
| | 159 | $addressLoc = Null; |
|---|
| | 160 | |
|---|
| | 161 | // Normalise address into lines. |
|---|
| | 162 | $nAddress = _normaliseAddress($address); |
|---|
| | 163 | $addressLines = split("[\n]+", $nAddress); |
|---|
| | 164 | //d("addressLines", $addressLines, True); |
|---|
| | 165 | |
|---|
| | 166 | |
|---|
| | 167 | /* Sometimes the postcode throws google api off, so if we have an explicit postcode, remove it from address. */ |
|---|
| | 168 | //if (preg_match('/^[0-9]*$/i', $addressLines[count($addressLines)-1])) { |
|---|
| | 169 | // $addressLines[count($addressLines)-1] = ""; |
|---|
| | 170 | //} |
|---|
| | 171 | |
|---|
| | 172 | /* Google doesn't like the things at the top of address (e.g. company name, building), so prune it down, line-by-line. */ |
|---|
| | 173 | while ($addressLines) { |
|---|
| | 174 | |
|---|
| | 175 | /* Create comma seperated part-address */ |
|---|
| | 176 | $partAddress = implode(", ", $addressLines); |
|---|
| | 177 | |
|---|
| | 178 | /* Do a lookup */ |
|---|
| | 179 | $partLoc = gmap_geocode($partAddress); |
|---|
| | 180 | $partLoc = _validateUKLocation($partLoc); |
|---|
| | 181 | |
|---|
| | 182 | if ($partLoc["status"] != 200) { |
|---|
| | 183 | // pass: google could not find it. |
|---|
| | 184 | } else { |
|---|
| | 185 | /* If we have a postcode, use it as a reference point for finding more accurate location nearby. */ |
|---|
| | 186 | if ($areaLoc) { |
|---|
| | 187 | $dist = _location_dist($areaLoc, $partLoc); |
|---|
| | 188 | } else { |
|---|
| | 189 | $dist = PROXIMITY_THRESHOLD * 0.5; |
|---|
| | 190 | } |
|---|
| | 191 | |
|---|
| | 192 | if ($dist < PROXIMITY_THRESHOLD) { |
|---|
| | 193 | if ($addressLoc) { |
|---|
| | 194 | if ($partLoc["accuracy"] > $addressLoc["accuracy"]) { |
|---|
| | 195 | $addressLoc = $partLoc; |
|---|
| | 196 | } |
|---|
| | 197 | } else { |
|---|
| | 198 | $addressLoc = $partLoc; |
|---|
| | 199 | } |
|---|
| | 200 | } |
|---|
| | 201 | } |
|---|
| | 202 | |
|---|
| | 203 | //d("partAddress $partAddress", $partLoc, True); |
|---|
| | 204 | /* Prune a line from the top of the address. */ |
|---|
| | 205 | array_shift($addressLines); |
|---|
| | 206 | } |
|---|
| | 207 | |
|---|
| | 208 | // Return the most accurate location. |
|---|
| | 209 | if ($addressLoc and !$areaLoc) { |
|---|
| | 210 | return $addressLoc; |
|---|
| | 211 | } else if ($areaLoc and !$addressLoc) { |
|---|
| | 212 | return $areaLoc; |
|---|
| | 213 | } else if ($addressLoc and $areaLoc) { |
|---|
| | 214 | if ($addressLoc["accuracy"] > $areaLoc["accuracy"]) { |
|---|
| | 215 | return $addressLoc; |
|---|
| | 216 | } else { |
|---|
| | 217 | return $areaLoc; |
|---|
| | 218 | } |
|---|
| | 219 | } |
|---|
| | 220 | |
|---|
| | 221 | return Null; |
|---|
| | 222 | } |
|---|
| | 223 | |
|---|
| | 224 | /* This automatically tries to find a location for a node, based on a CCK field called 'address' or on a 'postcode' field. */ |
|---|
| | 225 | function _set_node_geocode(&$node) { |
|---|
| | 226 | |
|---|
| | 227 | $addressField = variable_get("simplemap.addressfield", "field_address"); |
|---|
| | 228 | eval("\$address = \$node->".$addressField."[0]['value'];"); |
|---|
| | 229 | |
|---|
| | 230 | // Try to find a postcode cck field. |
|---|
| | 231 | $postcode = $node->field_postcode[0]["value"]; |
|---|
| | 232 | |
|---|
| | 233 | /* If no address info could be find, remove the location var for this node - if there was one. */ |
|---|
| | 234 | if (!$address and !$postcode) { |
|---|
| | 235 | variable_del("simplemap.nloc-$node->nid"); |
|---|
| | 236 | return; |
|---|
| | 237 | } |
|---|
| | 238 | |
|---|
| | 239 | // Do geocode lookup. |
|---|
| | 240 | $location = _smart_geocode($address, $postcode); |
|---|
| | 241 | //d("lookup of $address/$postcode", $location); |
|---|
| | 242 | |
|---|
| | 243 | /* If the lookcup failed, unset the location info for this node. */ |
|---|
| | 244 | if ($location["status"] != "200") { |
|---|
| | 245 | variable_del("simplemap.nloc-$node->nid"); |
|---|
| | 246 | return; |
|---|
| | 247 | } |
|---|
| | 248 | |
|---|
| | 249 | /* Store the location info for this node. */ |
|---|
| | 250 | variable_set("simplemap.nloc-$node->nid", $location); |
|---|
| | 251 | drupal_set_message("The geographic location of '$node->title' has been found and set."); |
|---|
| | 252 | } |
|---|
| | 253 | |
|---|
| | 254 | |
|---|
| | 255 | /* Gets the location of this node, if there is one. */ |
|---|
| | 256 | function _get_node_location($nid) { |
|---|
| | 257 | // Gets the geographic location of a node with nid. |
|---|
| | 258 | return variable_get("simplemap.nloc-$nid", Null); |
|---|
| | 259 | } |
|---|
| | 260 | |
|---|
| | 261 | |
|---|
| | 262 | |
|---|
| | 263 | /* |
|---|
| | 264 | * =============================== |
|---|
| | 265 | * UTILITY FUNCTIONS |
|---|
| | 266 | * =============================== |
|---|
| | 267 | */ |
|---|
| | 268 | |
|---|
| | 269 | |
|---|
| | 270 | /* Normalises an geographical address so that it has newlines for easier parsing. */ |
|---|
| | 271 | function _normaliseAddress($address) { |
|---|
| | 272 | $nAddress = strtolower($address); |
|---|
| | 273 | |
|---|
| | 274 | if (stristr($nAddress, "<br/>")) { $nAddress = str_replace("<br/>", "\n", $nAddress); } |
|---|
| | 275 | if (stristr($nAddress, "<br>")) { $nAddress = str_replace("<br>", "\n", $nAddress); } |
|---|
| | 276 | if (stristr($nAddress, "</p>")) { $nAddress = str_replace("</p>", "\n", $nAddress); } |
|---|
| | 277 | if (stristr($nAddress, ",")) { $nAddress = str_replace(",", "\n", $nAddress); } |
|---|
| | 278 | |
|---|
| | 279 | //d("nAddress: $nAddress",Null, True); |
|---|
| | 280 | return $nAddress; |
|---|
| | 281 | } |
|---|
| | 282 | |
|---|
| | 283 | |
|---|
| | 284 | /* Sanity check that a location lies in or around the UK. */ |
|---|
| | 285 | function _validateUKLocation($loc) { |
|---|
| | 286 | |
|---|
| | 287 | if ($loc["status"] != 200) { |
|---|
| | 288 | return Null; |
|---|
| | 289 | } |
|---|
| | 290 | |
|---|
| | 291 | if ($loc["latitude"] > 62.0 or $loc["latitude"] < 50.0) { |
|---|
| | 292 | return Null; |
|---|
| | 293 | } |
|---|
| | 294 | |
|---|
| | 295 | if ($loc["longitude"] < -12.0 or $loc["longitude"] > 4.0) { |
|---|
| | 296 | return Null; |
|---|
| | 297 | } |
|---|
| | 298 | |
|---|
| | 299 | return $loc; |
|---|
| | 300 | } |
|---|
| | 301 | |
|---|
| | 302 | |
|---|
| | 303 | /* Given a view, returns a list of gmap markers of node locations in the view. */ |
|---|
| | 304 | function _get_markers($view) { |
|---|
| | 305 | |
|---|
| | 306 | global $base_url; |
|---|
| | 307 | |
|---|
| | 308 | $markers = array(); |
|---|
| | 309 | $viewResults = views_build_view('items', $view, Null, false, $view->nodes_per_block); |
|---|
| | 310 | foreach ($viewResults['items'] as $i => $item) { |
|---|
| | 311 | //d("item",$item); |
|---|
| | 312 | $location = _get_node_location($item->nid); |
|---|
| | 313 | //$location = _smart_geocode("Warwickshire Association of Youth Clubs Jubilee House, Westlea Road Leamington Spa, CV31 3JE"); |
|---|
| | 314 | //$location = _smart_geocode("Westlea Road Leamington Spa CV31 3JE"); |
|---|
| | 315 | //$location = _smart_geocode("CV31 3JE"); |
|---|
| | 316 | if (!$location) { |
|---|
| | 317 | d("$item->node_title as no location"); |
|---|
| | 318 | continue; |
|---|
| | 319 | } |
|---|
| | 320 | |
|---|
| | 321 | $url = "$base_url/node/$item->nid"; |
|---|
| | 322 | |
|---|
| | 323 | $markers[] = array( |
|---|
| | 324 | 'latitude' => $location["latitude"], |
|---|
| | 325 | 'longitude' => $location["longitude"], |
|---|
| | 326 | 'markername' => "", |
|---|
| | 327 | 'text' => "<a href='$url'>".$item->node_title."</a>", |
|---|
| | 328 | 'offset' => 0, |
|---|
| | 329 | ); |
|---|
| | 330 | } |
|---|
| | 331 | |
|---|
| | 332 | //d("markers",$markers); |
|---|
| | 333 | return $markers; |
|---|
| | 334 | } |
|---|
| | 335 | |
|---|
| | 336 | /* Renders a gmap to diaply the specified markers. */ |
|---|
| | 337 | function _render_map($markers=Null) { |
|---|
| | 338 | $output = ""; |
|---|
| | 339 | $map = gmap_defaults(); |
|---|
| | 340 | |
|---|
| | 341 | if ($markers) { |
|---|
| | 342 | $map["markers"] = $markers; |
|---|
| | 343 | } |
|---|
| | 344 | //d("",$map); |
|---|
| | 345 | $output .= theme('gmap', array('#settings' => $map)); |
|---|
| | 346 | |
|---|
| | 347 | return $output; |
|---|
| | 348 | } |
|---|
| | 349 | |
|---|
| | 350 | /* Calculates the distance between two locations. */ |
|---|
| | 351 | function _location_dist($loc1, $loc2) { |
|---|
| | 352 | return sqrt(pow($loc2["latitude"] - $loc1["latitude"], 2) + pow($loc2["longitude"] - $loc1["longitude"], 2)); |
|---|
| | 353 | } |
|---|
| | 354 | |
|---|
| | 355 | /* Update the locations of all nodes in the site - for debug really. */ |
|---|