public function searchByProximity($center, $tolerance = 1000, $maxItems = 0, $dataController = null) { $bbox = normalizedBoundingBox($center, $tolerance, null, null); $params = array($bbox['min']['lat'], $bbox['max']['lat'], $bbox['min']['lon'], $bbox['max']['lon'], $bbox['center']['lat'], $bbox['center']['lat'], $bbox['center']['lon'], $bbox['center']['lon']); $sql = 'SELECT p.*, pc.category_id FROM ' . MapDB::PLACEMARK_TABLE . ' p, ' . MapDB::PLACEMARK_CATEGORY_TABLE . ' pc' . ' WHERE p.placemark_id = pc.placemark_id' . ' AND p.lat = pc.lat AND p.lon = pc.lon' . ' AND p.lat >= ? AND p.lat < ? AND p.lon >= ? AND p.lon < ?' . ' ORDER BY (p.lat - ?)*(p.lat - ?) + (p.lon - ?)*(p.lon - ?)'; $this->getSearchResultsForQuery($sql, $params, $maxItems); $resultsByDistance = array(); foreach ($this->searchResults as $result) { $rCenter = $result->getGeometry()->getCenterCoordinate(); $distance = greatCircleDistance($center['lat'], $center['lon'], $rCenter['lat'], $rCenter['lon']); $result->setField('distance', $distance); // avoid distance collisions while (isset($resultsByDistance[$distance])) { $distance++; } $resultsByDistance[$distance] = $result; } ksort($resultsByDistance); $this->searchResults = array_values($resultsByDistance); return $this->searchResults; }
public function initializeForCommand() { if ($projection = $this->getArg('projection')) { $this->mapProjector = new MapProjector(); $this->mapProjector->setDstProj($projection); } switch ($this->command) { case 'index': $categories = array(); $response = array('displayType' => $this->getModuleDisplayType()); $groups = $this->getFeedGroups(); if ($groups) { foreach ($groups as $id => &$groupData) { if (isset($groupData['center'])) { $latlon = filterLatLon($groupData['center']); $groupData['lat'] = $latlon['lat']; $groupData['lon'] = $latlon['lon']; } $groupData['id'] = $id; $categories[] = $groupData; } $response['categories'] = $categories; } else { $feeds = $this->loadFeedData(); foreach ($feeds as $id => $feedData) { $categories[] = array('title' => $feedData['TITLE'], 'subtitle' => $feedData['SUBTITLE'], 'id' => $id); } } $this->setResponse($response); $this->setResponseVersion(1); break; case 'category': $this->loadFeedData(); $categoryId = $this->getArg('category'); $groups = $this->getFeedGroups(); if (isset($groups[$categoryId])) { $this->feedGroup = $categoryId; $groupData = $this->loadFeedData(); $categories = array(); foreach ($groupData as $id => $feed) { if (!isset($feed['HIDDEN']) || !$feed['HIDDEN']) { $category = array('id' => $id, 'title' => $feed['TITLE']); if (isset($feed['SUBTITLE'])) { $category['subtitle'] = $feed['SUBTITLE']; } $categories[] = $category; } } $response = array('categories' => $categories); $this->setResponse($response); $this->setResponseVersion(1); } else { $controller = $this->getDataModel(); if ($controller) { //if ($categoryId) { // $category = $controller->findCategory($categoryId); // $placemarks = $category->placemarks(); // $categories = $category->categories(); //} else { $placemarks = $controller->placemarks(); $categories = $controller->categories(); //} if ($placemarks) { $response['placemarks'] = array(); foreach ($placemarks as $placemark) { $response['placemarks'][] = $this->arrayFromPlacemark($placemark); } } if ($categories) { foreach ($categories as $aCategory) { $response['categories'][] = $this->arrayFromCategory($aCategory); } } if (!$placemarks && !$categories) { // need something in the response so that it will be // output as a JSON object rather than a JSON array $response = array('categories' => array()); } $this->setResponse($response); $this->setResponseVersion(1); } else { $error = new KurogoError("Could not find data source for requested category"); $this->throwError($error); } } break; case 'detail': $suppress = $this->getOptionalModuleVar('suppress', array(), 'details', 'page-detail'); $tabKeys = $this->getOptionalModuleVar('tabkeys', array(), 'tabs', 'page-detail'); $controller = $this->getDataModel(); $placemarkId = $this->getArg('id', null); if ($controller && $placemarkId !== null) { $placemarks = $controller->selectPlacemark($placemarkId); $placemark = current($placemarks); $fields = $placemark->getFields(); $geometry = $placemark->getGeometry(); $tabs = $this->getTabsForTabKeys($tabKeys, $this->command); $response = array('sections' => $tabs, 'id' => $placemarkId, 'title' => $placemark->getTitle(), 'subtitle' => $placemark->getSubtitle(), 'address' => $placemark->getAddress()); if ($this->requestedVersion >= 2) { $response['description'] = $placemark->getDescription($suppress); $responseVersion = 2; } else { $response['details'] = array('description' => $placemark->getDescription($suppress)); $photoURL = $placemark->getField('PhotoURL'); if ($photoURL) { $response['photoURL'] = $photoURL; } $responseVersion = 1; } if ($geometry) { $center = $geometry->getCenterCoordinate(); $response['lat'] = $center['lat']; $response['lon'] = $center['lon']; $response['geometryType'] = $this->getGeometryType($geometry); $response['geometry'] = $this->formatGeometry($geometry); } $this->setResponse($response); $this->setResponseVersion($responseVersion); } break; case 'search': $mapSearch = $this->getSearchClass($this->args); $lat = $this->getArg('lat', 0); $lon = $this->getArg('lon', 0); if ($lat || $lon) { // defaults values for proximity search $tolerance = 1000; $maxItems = 0; // check for settings in feedgroup config $configData = $this->getDataForGroup($this->feedGroup); if ($configData) { if (isset($configData['NEARBY_THRESHOLD'])) { $tolerance = $configData['NEARBY_THRESHOLD']; } if (isset($configData['NEARBY_ITEMS'])) { $maxItems = $configData['NEARBY_ITEMS']; } } // check for override settings in feeds $configData = $this->getCurrentFeed(); if (isset($configData['NEARBY_THRESHOLD'])) { $tolerance = $configData['NEARBY_THRESHOLD']; } if (isset($configData['NEARBY_ITEMS'])) { $maxItems = $configData['NEARBY_ITEMS']; } $searchResults = $mapSearch->searchByProximity(array('lat' => $lat, 'lon' => $lon), 1000, 10); } else { if ($searchTerms = $this->getArg(array('filter', 'q'))) { $this->setLogData($searchTerms); $searchResults = $mapSearch->searchCampusMap($searchTerms); } } $provider = null; if ($this->requestedVersion >= 2 && $this->getArg('provider', null)) { $providerId = $this->getArg('provider'); switch ($providerId) { case 'google': $provider = new GoogleJSMap(); break; case 'esri': $provider = new ArcGISJSMap(); break; } if ($provider && $projection) { $provider->setMapProjection($projection); } } $places = array(); foreach ($searchResults as $result) { if ($this->requestedVersion >= 2) { $place = array('attribs' => $this->shortArrayFromPlacemark($result)); } else { $place = $this->shortArrayFromPlacemark($result); } if ($provider) { if ($result instanceof MapPolygon) { $place['placemark'] = $provider->jsObjectForPolygon($result); } elseif ($result instanceof MapPolyline) { $place['placemark'] = $provider->jsObjectForPath($result); } else { $place['placemark'] = $provider->jsObjectForMarker($result); } } $places[] = $place; } $response = array('total' => count($places), 'returned' => count($places), 'results' => $places); $this->setResponse($response); $this->setResponseVersion(1); break; // ajax calls // ajax calls case 'projectPoint': $lat = $this->getArg('lat', 0); $lon = $this->getArg('lon', 0); $fromProj = $this->getArg('from', GEOGRAPHIC_PROJECTION); $toProj = $this->getArg('to', GEOGRAPHIC_PROJECTION); $projector = new MapProjector(); $projector->setSrcProj($fromProj); $projector->setDstProj($toProj); $result = $projector->projectPoint(array('lat' => $lat, 'lon' => $lon)); $this->setResponse($result); $this->setResponseVersion(1); break; case 'sortGroupsByDistance': $lat = $this->getArg('lat', 0); $lon = $this->getArg('lon', 0); $categories = array(); $showDistances = $this->getOptionalModuleVar('SHOW_DISTANCES', true); if ($lat || $lon) { foreach ($this->getFeedGroups() as $id => $groupData) { $center = filterLatLon($groupData['center']); $distance = greatCircleDistance($lat, $lon, $center['lat'], $center['lon']); $category = array('title' => $groupData['title'], 'id' => $id); if ($showDistances && ($displayText = $this->displayTextFromMeters($distance))) { $category['distance'] = $displayText; } $categories[] = $category; $distances[] = $distance; } array_multisort($distances, SORT_ASC, $categories); } $this->setResponse($categories); $this->setResponseVersion(1); break; case 'staticImageURL': $params = array('STATIC_MAP_BASE_URL' => $this->getArg('baseURL'), 'STATIC_MAP_CLASS' => $this->getArg('mapClass')); $dc = Kurogo::deviceClassifier(); $mapDevice = new MapDevice($dc->getPagetype(), $dc->getPlatform()); $mapController = MapImageController::factory($params, $mapDevice); if (!$mapController->isStatic()) { $error = new KurogoError(0, "staticImageURL must be used with a StaticMapImageController subclass"); $this->throwError($error); } $currentQuery = $this->getArg('query'); $mapController->parseQuery($currentQuery); $overrides = $this->getArg('overrides'); $mapController->parseQuery($overrides); $zoomDir = $this->getArg('zoom'); if ($zoomDir == 1 || $zoomDir == 'in') { $level = $mapController->getLevelForZooming('in'); $mapController->setZoomLevel($level); } elseif ($zoomDir == -1 || $zoomDir == 'out') { $level = $mapController->getLevelForZooming('out'); $mapController->setZoomLevel($level); } $scrollDir = $this->getArg('scroll'); if ($scrollDir) { $center = $mapController->getCenterForPanning($scrollDir); $mapController->setCenter($center); } $url = $mapController->getImageURL(); $this->setResponse($url); $this->setResponseVersion(1); break; case 'geocode': // TODO: this is not fully implemented. do not use this API. includePackage('Maps', 'Geocoding'); $locationSearchTerms = $this->getArg('q'); $geocodingDataRetrieverClass = $this->getOptionalModuleVar('GEOCODING_DATA_RETRIEVER_CLASS'); $geocodingDataParserClass = $this->getOptionalModuleVar('GEOCODING_DATA_PARSER_CLASS'); $geocoding_base_url = $this->getOptionalModuleVar('GEOCODING_BASE_URL'); $arguments = array('BASE_URL' => $geocoding_base_url, 'CACHE_LIFETIME' => 86400, 'PARSER_CLASS' => $geocodingDataParserClass); $controller = DataRetriever::factory($geocodingDataRetrieverClass, $arguments); $controller->addCustomFilters($locationSearchTerms); $response = $controller->getParsedData(); // checking for Geocoding service error if ($response['errorCode'] == 0) { unset($response['errorCode']); unset($response['errorMessage']); $this->setResponse($response); $this->setResponseVersion(1); } else { $kurogoError = new KurogoError($response['errorCode'], "Geocoding service Erroe", $response['errorMessage']); $this->setResponseError($kurogoError); $this->setResponseVersion(1); } break; default: $this->invalidCommand(); break; } }
public function initializeForCommand() { switch ($this->command) { case 'index': $categories = array(); $groups = $this->getFeedGroups(); if ($groups) { foreach ($groups as $id => &$groupData) { if (isset($groupData['center'])) { $latlon = filterLatLon($groupData['center']); $groupData['lat'] = $latlon['lat']; $groupData['lon'] = $latlon['lon']; } $groupData['id'] = $id; $categories[] = $groupData; } $response = array('categories' => $categories); } else { $feeds = $this->loadFeedData(); foreach ($feeds as $id => $feedData) { $categories[] = array('title' => $feedData['TITLE'], 'subtitle' => $feedData['SUBTITLE'], 'id' => $id); } } $this->setResponse($response); $this->setResponseVersion(1); break; case 'category': $this->loadFeedData(); $category = $this->getArg('category'); $groups = $this->getFeedGroups(); if (isset($groups[$category])) { $this->feedGroup = $category; $groupData = $this->loadFeedData(); $categories = array(); foreach ($groupData as $id => $feed) { if (!isset($feed['HIDDEN']) || !$feed['HIDDEN']) { $category = array('id' => $id, 'title' => $feed['TITLE']); if (isset($feed['SUBTITLE'])) { $category['subtitle'] = $feed['SUBTITLE']; } $categories[] = $category; } } $response = array('categories' => $categories); $this->setResponse($response); $this->setResponseVersion(1); } else { $dataController = $this->getDataController(); if ($dataController) { $listItems = $dataController->getListItems(); $placemarks = array(); $categories = array(); foreach ($listItems as $listItem) { if ($listItem instanceof Placemark) { $placemarks[] = $this->shortArrayFromPlacemark($listItem); } else { $categories[] = $this->arrayFromCategory($listItem); } } $response = array(); if ($placemarks) { $response['placemarks'] = $placemarks; } if ($categories) { $response['categories'] = $categories; } $this->setResponse($response); $this->setResponseVersion(1); } else { $error = new KurogoError("Could not find data source for requested category"); $this->throwError($error); } } break; case 'detail': $dataController = $this->getDataController(); $placemarkId = $this->getArg('id', null); if ($dataController && $placemarkId !== null) { $placemark = $dataController->selectPlacemark($placemarkId); $fields = $placemark->getFields(); $geometry = $placemark->getGeometry(); $response = array('id' => $placemarkId, 'title' => $placemark->getTitle(), 'subtitle' => $placemark->getSubtitle(), 'address' => $placemark->getAddress(), 'details' => $placemark->getFields()); if ($geometry) { $center = $geometry->getCenterCoordinate(); $response['lat'] = $center['lat']; $response['lon'] = $center['lon']; $response['geometryType'] = $this->getGeometryType($geometry); $response['geometry'] = $this->formatGeometry($geometry); } $this->setResponse($response); $this->setResponseVersion(1); } break; case 'search': $mapSearch = $this->getSearchClass($this->args); $lat = $this->getArg('lat', 0); $lon = $this->getArg('lon', 0); if ($lat || $lon) { // defaults values for proximity search $tolerance = 1000; $maxItems = 0; // check for settings in feedgroup config $configData = $this->getDataForGroup($this->feedGroup); if ($configData) { if (isset($configData['NEARBY_THRESHOLD'])) { $tolerance = $configData['NEARBY_THRESHOLD']; } if (isset($configData['NEARBY_ITEMS'])) { $maxItems = $configData['NEARBY_ITEMS']; } } // check for override settings in feeds $configData = $this->getCurrentFeed(); if (isset($configData['NEARBY_THRESHOLD'])) { $tolerance = $configData['NEARBY_THRESHOLD']; } if (isset($configData['NEARBY_ITEMS'])) { $maxItems = $configData['NEARBY_ITEMS']; } $searchResults = $mapSearch->searchByProximity(array('lat' => $lat, 'lon' => $lon), 1000, 10); } else { $searchTerms = $this->getArg('q'); if ($searchTerms) { $searchResults = $mapSearch->searchCampusMap($searchTerms); } } $places = array(); foreach ($searchResults as $result) { $places[] = $this->shortArrayFromPlacemark($result); } $response = array('total' => count($places), 'returned' => count($places), 'results' => $places); $this->setResponse($response); $this->setResponseVersion(1); break; // ajax calls // ajax calls case 'projectPoint': $lat = $this->getArg('lat', 0); $lon = $this->getArg('lon', 0); $fromProj = $this->getArg('from', GEOGRAPHIC_PROJECTION); $toProj = $this->getArg('to', GEOGRAPHIC_PROJECTION); $projector = new MapProjector(); $projector->setSrcProj($fromProj); $projector->setDstProj($toProj); $result = $projector->projectPoint(array('lat' => $lat, 'lon' => $lon)); $this->setResponse($result); $this->setResponseVersion(1); break; case 'sortGroupsByDistance': $lat = $this->getArg('lat', 0); $lon = $this->getArg('lon', 0); $categories = array(); $showDistances = $this->getOptionalModuleVar('SHOW_DISTANCES', true); if ($lat || $lon) { foreach ($this->getFeedGroups() as $id => $groupData) { $center = filterLatLon($groupData['center']); $distance = greatCircleDistance($lat, $lon, $center['lat'], $center['lon']); $category = array('title' => $groupData['title'], 'id' => $id); if ($showDistances && ($displayText = $this->displayTextFromMeters($distance))) { $category['distance'] = $displayText; } $categories[] = $category; $distances[] = $distance; } array_multisort($distances, SORT_ASC, $categories); } $this->setResponse($categories); $this->setResponseVersion(1); break; case 'staticImageURL': $params = array('STATIC_MAP_BASE_URL' => $this->getArg('baseURL'), 'STATIC_MAP_CLASS' => $this->getArg('mapClass')); $dc = Kurogo::deviceClassifier(); $mapDevice = new MapDevice($dc->getPagetype(), $dc->getPlatform()); $mapController = MapImageController::factory($params, $mapDevice); if (!$mapController->isStatic()) { $error = new KurogoError(0, "staticImageURL must be used with a StaticMapImageController subclass"); $this->throwError($error); } $currentQuery = $this->getArg('query'); $mapController->parseQuery($currentQuery); $overrides = $this->getArg('overrides'); $mapController->parseQuery($overrides); $zoomDir = $this->getArg('zoom'); if ($zoomDir == 1 || $zoomDir == 'in') { $level = $mapController->getLevelForZooming('in'); $mapController->setZoomLevel($level); } elseif ($zoomDir == -1 || $zoomDir == 'out') { $level = $mapController->getLevelForZooming('out'); $mapController->setZoomLevel($level); } $scrollDir = $this->getArg('scroll'); if ($scrollDir) { $center = $mapController->getCenterForPanning($scrollDir); $mapController->setCenter($center); } $url = $mapController->getImageURL(); $this->setResponse($url); $this->setResponseVersion(1); break; case 'geocode': $locationSearchTerms = $this->getArg('q'); $geocodingDataControllerClass = $this->getOptionalModuleVar('GEOCODING_DATA_CONTROLLER_CLASS'); $geocodingDataParserClass = $this->getOptionalModuleVar('GEOCODING_DATA_PARSER_CLASS'); $geocoding_base_url = $this->getOptionalModuleVar('GEOCODING_BASE_URL'); $arguments = array('BASE_URL' => $geocoding_base_url, 'CACHE_LIFETIME' => 86400, 'PARSER_CLASS' => $geocodingDataParserClass); $controller = DataController::factory($geocodingDataControllerClass, $arguments); $controller->addCustomFilters($locationSearchTerms); $response = $controller->getParsedData(); // checking for Geocoding service error if ($response['errorCode'] == 0) { unset($response['errorCode']); unset($response['errorMessage']); $this->setResponse($response); $this->setResponseVersion(1); } else { $kurogoError = new KurogoError($response['errorCode'], "Geocoding service Erroe", $response['errorMessage']); $this->setResponseError($kurogoError); $this->setResponseVersion(1); } break; default: $this->invalidCommand(); break; } }
public function searchByProximity($center, $tolerance, $maxItems = null) { $this->setupProjector(); $bbox = normalizedBoundingBox($center, $tolerance, null, null); $results = array(); foreach ($this->getAllLeafNodes() as $item) { $geometry = $item->getGeometry(); if ($geometry) { $featureCenter = $geometry->getCenterCoordinate(); if ($this->projector) { $featureCenter = $this->projector->projectPoint($featureCenter); } if ($featureCenter['lat'] <= $bbox['max']['lat'] && $featureCenter['lat'] >= $bbox['min']['lat'] && $featureCenter['lon'] <= $bbox['max']['lon'] && $featureCenter['lon'] >= $bbox['min']['lon']) { $distance = greatCircleDistance($bbox['center']['lat'], $bbox['center']['lon'], $featureCenter['lat'], $featureCenter['lon']); if ($distance > $tolerance) { continue; } // keep keys unique; give priority to whatever came first $intDist = intval($distance * 1000); while (array_key_exists($intDist, $results)) { $intDist += 1; // one centimeter } $item->setField('distance', $distance); $item->addCategoryId($this->categoryId); $results[$intDist] = $this->getProjectedFeature($item); } } } return $results; }
protected function doSearchByProximity($center, $tolerance = 1000, $maxItems = 0, $dataController = null) { $resultsByDistance = array(); $controllers = array(); if ($dataController !== null) { $controllers[] = $dataController; } else { foreach ($this->feeds as $categoryID => $feedData) { $feedData['group'] = $this->feedGroup; $controller = mapModelFromFeedData($feedData); if ($controller->canSearch()) { // respect config settings $controllers[] = $controller; } } } // keep track of duplicate placemarks $unique = array(); foreach ($controllers as $controller) { try { $results = $controller->searchByProximity($center, $tolerance, $maxItems); // merge arrays manually since keys are numeric foreach ($results as $placemark) { $toCenter = $placemark->getGeometry()->getCenterCoordinate(); // assume if placemarks have the same lat/lon // and title then they are the same place $testString = $toCenter['lat'] . $toCenter['lon'] . $placemark->getTitle(); if (in_array($testString, $unique)) { continue; } $unique[] = $testString; $distance = greatCircleDistance($center['lat'], $center['lon'], $toCenter['lat'], $toCenter['lon']); $placemark->setField('distance', $distance); // avoid distance collisions if (isset($resultsByDistance[$distance])) { $distance++; while (isset($resultsByDistance[$distance])) { $distance++; } } $resultsByDistance[$distance] = $placemark; } } catch (KurogoDataServerException $e) { Kurogo::log(LOG_WARNING, 'encountered KurogoDataServerException for feed config: ' . print_r($feedData, true) . $e->getMessage(), 'maps'); } } ksort($resultsByDistance); if ($maxItems && count($resultsByDistance) > $maxItems) { array_splice($resultsByDistance, $maxItems); } return array_values($resultsByDistance); }
function mingapi_position() { session_write_close(); // NB: Luk session så andre requests fra samme client/session kan køre samtidig $lat = $_REQUEST['lat']; $long = $_REQUEST['long']; $recs = Core::get()->dbQuery("SELECT * FROM pos_info"); $places = array(); foreach ($recs as $rec) { if ($rec->latitude == 0 || $rec->longitude == 0) { continue; } $dist = greatCircleDistance($lat, $long, $rec->latitude, $rec->longitude); if ($dist <= doubleval($rec->radius)) { $dist = doubleval(sprintf("%.2f", $dist)); $place = array('id' => $rec->id, 'place' => $rec->description, 'distance' => $dist, 'latitude' => sprintf("%.6f", $lat), 'longitude' => sprintf("%.6f", $long)); $places[] = $place; } } if (count($places) == 0) { // unknown place $place = array('id' => 0, 'place' => 'Ukendt', 'distance' => 0, 'latitude' => sprintf("%.6f", $lat), 'longitude' => sprintf("%.6f", $long)); echo json_encode($place); return; } $closest = $places[0]; foreach ($places as $place) { if ($place['distance'] < $closest['distance']) { $closest = $place; } } echo json_encode($closest); return; }