/** * Get POIs * * @param Filter $filter * * @return POI[] * * @throws Exception */ public function getPOIs(Filter $filter = NULL) { $libxmlErrorHandlingState = libxml_use_internal_errors(TRUE); $lat = $filter->lat; $lon = $filter->lon; $radius = $filter->radius; $accuracy = $filter->accuracy; // calculate here to prevent recalculation on each foreach loop later $dlat = GeoUtil::getLatitudinalDistance(($radius + $accuracy) * 1.25, $lat); $dlon = GeoUtil::getLongitudinalDistance(($radius + $accuracy) * 1.25, $lat); $simpleXML = $this->getSimpleXMLFromSource(); $result = array(); $requestedPOI = NULL; $xpathQuery = $this->buildQuery($filter); foreach ($simpleXML->xpath($xpathQuery) as $poiData) { $poi = new POI(); foreach ($poiData->children() as $child) { $nodeName = $child->getName(); if ($nodeName == "action") { $poi->actions[] = new POIAction($child); } else { if ($nodeName == "anchor") { $poi->anchor = new POIAnchor($child); } else { if ($nodeName == "icon") { $poi->icon = new POIIcon($child); } else { if ($nodeName == "object") { $poi->object = new POIObject($child); } else { if ($nodeName == "text") { $poi->text = new POIText($child); } else { if ($nodeName == "transform") { $poi->transform = new POITransform($child); } else { if ($nodeName == "animation") { if (in_array((string) $child, array("drop", "spin", "grow"))) { $poi->animations = (string) $child; } else { $events = (string) $child["events"]; if (!empty($events)) { foreach (array("onCreate", "onUpdate", "onDelete", "onFocus", "onClick") as $event) { if (strpos($events, $event) !== FALSE) { $poi->animations[$event][] = new Animation($child); } } } } } else { switch ($nodeName) { case "dimension": case "type": case "relativeAlt": $value = (int) $child; break; case "showSmallBiw": case "showBiwOnClick": case "doNotIndex": $value = (bool) (string) $child; break; default: $value = (string) $child; break; } $poi->{$nodeName} = $value; } } } } } } } } if (empty($filter)) { $result[] = $poi; } else { if (!empty($filter->requestedPoiId) && $filter->requestedPoiId == $poi->id) { // always return the requested POI at the top of the list to // prevent cutoff by the 50 POI response limit $poi->distance = GeoUtil::getGreatCircleDistance(deg2rad($lat), deg2rad($lon), deg2rad($poi->anchor->geolocation['lat']), deg2rad($poi->anchor->geolocation['lon'])); $requestedPOI = $poi; } else { if ($this->passesFilter($poi, $filter)) { if (empty($radius)) { $poi->distance = GeoUtil::getGreatCircleDistance(deg2rad($lat), deg2rad($lon), deg2rad($poi->anchor->geolocation['lat']), deg2rad($poi->anchor->geolocation['lon'])); $result[] = $poi; } else { // verify if POI falls in bounding box (with 25% margin) /** @todo handle wraparound */ if (isset($poi->anchor->referenceImage)) { $result[] = $poi; } elseif ((double) $poi->anchor->geolocation['lat'] >= $lat - $dlat && $poi->anchor->geolocation['lat'] <= $lat + $dlat && $poi->anchor->geolocation['lon'] >= $lon - $dlon && $poi->anchor->geolocation['lon'] <= $lon + $dlon) { $poi->distance = GeoUtil::getGreatCircleDistance(deg2rad($lat), deg2rad($lon), deg2rad($poi->anchor->geolocation['lat']), deg2rad($poi->anchor->geolocation['lon'])); // filter passed, see if radius allows for inclusion if ($poi->distance < $radius + $accuracy) { $result[] = $poi; } } } } } } } libxml_use_internal_errors($libxmlErrorHandlingState); if (!empty($filter)) { // sort if filter is set $result = objectSort("distance", $result); } if (!empty($requestedPOI)) { // always make sure that the requested POI is the first to be returned array_unshift($result, $requestedPOI); } return $result; }