/// <summary> /// Returns all the objects within a given bounding box and filtered by a given filter. /// </summary> /// <param name="box"></param> /// <param name="filter"></param> /// <returns></returns> public override IList<OsmGeo> Get(GeoCoordinateBox box, Filter filter) { List<OsmGeo> res = new List<OsmGeo>(); // load all nodes and keep the ids in a collection. HashSet<long> ids = new HashSet<long>(); foreach (Node node in _nodes.Values) { if ((filter == null || filter.Evaluate(node)) && box.Contains(new GeoCoordinate(node.Latitude.Value, node.Longitude.Value))) { res.Add(node); ids.Add(node.Id.Value); } } // load all ways that contain the nodes that have been found. res.AddRange(this.GetWaysFor(ids).Cast<OsmGeo>()); // the .Cast<> is here for Windows Phone. // get relations containing any of the nodes or ways in the current results-list. List<Relation> relations = new List<Relation>(); HashSet<long> relationIds = new HashSet<long>(); foreach (OsmGeo osmGeo in res) { IList<Relation> relationsFor = this.GetRelationsFor(osmGeo); foreach (Relation relation in relationsFor) { if (!relationIds.Contains(relation.Id.Value)) { relations.Add(relation); relationIds.Add(relation.Id.Value); } } } // recursively add all relations containing other relations as a member. do { res.AddRange(relations.Cast<OsmGeo>()); // the .Cast<> is here for Windows Phone. List<Relation> newRelations = new List<Relation>(); foreach (OsmGeo osmGeo in relations) { IList<Relation> relationsFor = this.GetRelationsFor(osmGeo); foreach (Relation relation in relationsFor) { if (!relationIds.Contains(relation.Id.Value)) { newRelations.Add(relation); relationIds.Add(relation.Id.Value); } } } relations = newRelations; } while (relations.Count > 0); if (filter != null) { List<OsmGeo> filtered = new List<OsmGeo>(); foreach (OsmGeo geo in res) { if (filter.Evaluate(geo)) { filtered.Add(geo); } } } return res; }
/// <summary> /// Utility method for ensuring a view stays within a bounding box of geo coordinated. /// </summary> /// <param name="center">The map center we want to move to.</param> /// <param name="boundingBox">A GeoCoordinateBox defining the bounding box.</param> /// <param name="view" The current view.</param> /// <returns>Returns a center geo coordinate that is corrected so the view stays within the bounding box.</returns> public GeoCoordinate EnsureViewWithinBoundingBox(GeoCoordinate center, GeoCoordinateBox boundingBox, View2D view) { double[] mapCenterSceneCoords = this.Projection.ToPixel(center); var toViewPort = view.CreateToViewPort(view.Width, view.Height); double mapCenterPixelsX, mapCenterPixelsY; toViewPort.Apply(mapCenterSceneCoords[0], mapCenterSceneCoords[1], out mapCenterPixelsX, out mapCenterPixelsY); //double[] mapCenterPixels = view.ToViewPort(view.Width, view.Height, mapCenterSceneCoords[0], mapCenterSceneCoords[1]); var fromViewPort = view.CreateFromViewPort(view.Height, view.Width); double leftScene, topScene, rightScene, bottomScene; fromViewPort.Apply(mapCenterPixelsX - (view.Width) / 2.0, mapCenterPixelsY - (view.Height) / 2.0, out leftScene, out topScene); //double[] topLeftSceneCoordinates = view.FromViewPort(view.Width, // view.Height, // mapCenterPixels[0] - (view.Width) / 2.0, // mapCenterPixels[1] - (view.Height) / 2.0); GeoCoordinate topLeft = this.Projection.ToGeoCoordinates(leftScene, topScene); //GeoCoordinate topLeft = this.Projection.ToGeoCoordinates(topLeftSceneCoordinates[0], topLeftSceneCoordinates[1]); fromViewPort.Apply(mapCenterPixelsX + (view.Width) / 2.0, mapCenterPixelsY + (view.Height) / 2.0, out rightScene, out bottomScene); //double[] bottomRightSceneCoordinates = view.FromViewPort(view.Width, // view.Height, // mapCenterPixels[0] + (view.Width) / 2.0, // mapCenterPixels[1] + (view.Height) / 2.0); GeoCoordinate bottomRight = this.Projection.ToGeoCoordinates(rightScene, bottomScene); // Early exit when the view is inside the box. if (boundingBox.Contains(topLeft) && boundingBox.Contains(bottomRight)) return center; double viewNorth = topLeft.Latitude; double viewEast = bottomRight.Longitude; double viewSouth = bottomRight.Latitude; double viewWest = topLeft.Longitude; double boxNorth = boundingBox.MaxLat; double boxEast = boundingBox.MaxLon; double boxSouth = boundingBox.MinLat; double boxWest = boundingBox.MinLon; //TODO: Check if the view acrually fits the bounding box, if not resize the view. // Correct all view bounds if neccecary. if (viewNorth > boxNorth) { viewSouth -= viewNorth - boxNorth; viewNorth = boxNorth; } if (viewEast > boxEast) { viewWest -= viewEast - boxEast; viewEast = boxEast; } if (viewSouth < boxSouth) { viewNorth += boxSouth - viewSouth; viewSouth = boxSouth; } if (viewWest < boxWest) { viewEast += boxWest - viewWest; viewWest = boxWest; } // Compute and return corrected map center return new GeoCoordinate(viewSouth + (viewNorth - viewSouth) / 2.0f, viewWest + (viewEast - viewWest) / 2.0f); }
/// <summary> /// Returns true if this point is visible inside the given bounding box. /// </summary> /// <returns></returns> public override bool IsInside(GeoCoordinateBox box) { if (box == null) { throw new ArgumentNullException(); } return box.Contains(this.Coordinate); }