internal double GetGeodesicDistance(MapPoint p1, MapPoint p2) { var meters = GeometryEngine.GeodesicDistance(p1, p2); // convert to current linear unit return(UpdateDistanceFromTo(DistanceTypes.Meters, LineDistanceType, meters)); }
/// <summary> /// Gets a point a certain distance down a polyline /// </summary> /// <param name="dist">Distance in meters along the line</param> /// <param name="course"></param> /// <returns></returns> private double[] PointAlongLine(double dist, out double course) { double accDist = 0; course = double.NaN; if (dist > lineLength) //reached end - move to next direction, or start over { directionIndex++; Route currDir; if (directionIndex >= m_route.Routes.Count) { directionIndex = 0; } currDir = m_route.Routes[directionIndex]; lineLength = GeometryEngine.GeodesicLength(currDir.RouteFeature.Geometry); totalDistance = 0; drivePath = currDir.RouteFeature.Geometry as Polyline; course = 0; dist = 0; } //else { var parts = drivePath.Parts.GetPartsAsPoints().ToList(); for (int j = 0; j < parts.Count; j++) { var part = parts[j].ToList(); for (int i = 0; i < part.Count - 1; i++) { var p1 = part[i]; var p2 = part[i + 1]; if (p1.X == p2.X && p2.Y == p2.Y) { continue; } double distToWaypoint = GeometryEngine.GeodesicDistance(p1, p2, LinearUnits.Meters); if (dist < accDist + distToWaypoint) { var distAlongSegment = dist - accDist; double fraction = distAlongSegment / distToWaypoint; course = GetTrueBearingGeodesic(p1.X, p1.Y, p2.X, p2.Y); return(GetPointFromHeadingGeodesic(new double[] { p1.X, p1.Y }, distAlongSegment, course)); } accDist += distToWaypoint; } } } return(null); }
private void CalculateDistances() { double sum = 0; double maxDistance = 0; double minDistance = double.MaxValue; int distanceCount = 0; Task task = Task.Factory.StartNew(() => { lock (_mapPointLock) { for (int i = 0; i < _mapPoints.Count - 1; i++) { MapPoint outer = _mapPoints[i]; for (int j = i + 1; j < _mapPoints.Count; j++) { MapPoint inner = _mapPoints[j]; double distance = GeometryEngine.GeodesicDistance(outer, inner, LinearUnits.Kilometers); sum += distance; if (maxDistance < distance) { maxDistance = distance; } if (minDistance > distance) { minDistance = distance; } distanceCount++; } } } }); task.Wait(); DistanceSum = sum; MaxDistance = maxDistance; MinDistance = minDistance == double.MaxValue ? 0 : minDistance; if (sum > 0 && distanceCount > 0) { AvgDistance = sum / distanceCount; } }
/// <summary> /// Creates a new camera offset from the provided camera around an ellipse. /// </summary> /// <param name="camera">The starting camera.</param> /// <param name="ellipse">The ellipse around which the camera will rotate.</param> /// <param name="centerPoint">The center point of the ellipse.</param> /// <param name="percentAlong">The percentage around the ellipse to create the camera.</param> private Camera OffsetCamera(Camera camera, Polyline ellipse, MapPoint centerPoint, double percentAlong) { camera = CloneCamera(camera); var fromPoint = GeometryEngine.MovePointAlongLine(ellipse, percentAlong, true, 0); var segment = LineBuilder.CreateLineSegment(new Coordinate2D(centerPoint.X, centerPoint.Y), new Coordinate2D(fromPoint.X, centerPoint.Y), centerPoint.SpatialReference); var difX = GeometryEngine.GeodesicLength(PolylineBuilder.CreatePolyline(segment, segment.SpatialReference)); if (centerPoint.X - fromPoint.X < 0) { difX *= -1; } segment = LineBuilder.CreateLineSegment(new Coordinate2D(centerPoint.X, centerPoint.Y), new Coordinate2D(centerPoint.X, fromPoint.Y), centerPoint.SpatialReference); var difY = GeometryEngine.GeodesicLength(PolylineBuilder.CreatePolyline(segment, segment.SpatialReference)); if (centerPoint.Y - fromPoint.Y < 0) { difY *= -1; } var radian = Math.Atan2(difX, difY); var heading = radian * -180 / Math.PI; camera.Heading = heading; var difZ = centerPoint.Z - (camera.Z * ((camera.SpatialReference.IsGeographic) ? 1.0 : camera.SpatialReference.Unit.ConversionFactor)); var hypotenuse = GeometryEngine.GeodesicDistance(fromPoint, centerPoint); radian = Math.Atan2(difZ, hypotenuse); var pitch = radian * 180 / Math.PI; camera.Pitch = pitch; if (fromPoint.SpatialReference.Wkid != camera.SpatialReference.Wkid) { var transformation = ProjectionTransformation.Create(fromPoint.SpatialReference, camera.SpatialReference); fromPoint = GeometryEngine.ProjectEx(fromPoint, transformation) as MapPoint; } camera.X = fromPoint.X; camera.Y = fromPoint.Y; return(camera); }
private async void MapView_MouseDown(object sender, MouseButtonEventArgs e) { Point screenPoint = e.GetPosition(MyMapView); Graphic graphic = await _graphicsLayer.HitTestAsync(MyMapView, screenPoint); if (_lineGraphic != null) { _graphicsLayer.Graphics.Remove(_lineGraphic); } if (graphic == null) { DistanceTextBlock.Text = ""; return; } graphic.IsSelected = true; if (_selectedGraphic != null) { var mapPoint = graphic.Geometry as MapPoint; var selectedMapPoint = _selectedGraphic.Geometry as MapPoint; if (mapPoint != null && selectedMapPoint != null) { double distance = GeometryEngine.GeodesicDistance(mapPoint, selectedMapPoint, LinearUnits.Kilometers); DistanceTextBlock.Text = String.Format("Distance: {0:0.00}", distance); _lineGraphic = new Graphic(Geodesic.GetGeodesicLine(selectedMapPoint, mapPoint)); _lineGraphic.Symbol = new SimpleLineSymbol { Color = Colors.DarkOrange, Width = 3 }; _graphicsLayer.Graphics.Add(_lineGraphic); } _selectedGraphic.IsSelected = false; } _selectedGraphic = graphic; }
/// <summary> /// Create keyframes centered around a point. /// </summary> /// <param name="point">The center point around which the keyframes are created.</param> internal Task CreateKeyframesAroundPoint(MapPoint point) { return(QueuedTask.Run(() => { var mapView = MapView.Active; var degrees = Animation.Settings.Degrees; if (mapView == null || degrees == 0) { return; } //Get the camera track from the active map's animation. //There will always be only one camera track in the animation. var cameraTrack = mapView.Map.Animation.Tracks.OfType <CameraTrack>().First(); var camera = mapView.Camera; //Calculate the number of keys to create. var keyEvery = (degrees < 0) ? -10 : 10; //10 degrees var numOfKeys = Math.Floor(degrees / keyEvery); var remainder = degrees % keyEvery; //To maintain a constant speed we need to divide the total time we want the animation to take by the number of degrees of rotation. var duration = Animation.Settings.Duration; double timeInterval = duration / Math.Abs(degrees); double currentTimeSeconds = GetInsertTime(mapView.Map.Animation); //Get the distance from the current location to the point we want to rotate around to get the radius. var cameraPoint = MapPointBuilder.CreateMapPoint(camera.X, camera.Y, camera.SpatialReference); var radius = GeometryEngine.GeodesicDistance(cameraPoint, point); var radian = ((camera.Heading - 90) / 180.0) * Math.PI; //If the spatial reference of the point is projected and the unit is not in meters we need to convert the Z values to meters. if (!point.SpatialReference.IsGeographic && point.SpatialReference.Unit.ConversionFactor != 1.0) { point = MapPointBuilder.CreateMapPoint(point.X, point.Y, point.Z * point.SpatialReference.Unit.ConversionFactor, point.SpatialReference); } //For all geodesic calculations we will use WGS84 so we will project the point if it is not already. if (point.SpatialReference.Wkid != SpatialReferences.WGS84.Wkid) { var transformation = ProjectionTransformation.Create(point.SpatialReference, SpatialReferences.WGS84); point = GeometryEngine.ProjectEx(point, transformation) as MapPoint; } //Create an ellipse around the center point. var parameter = new GeometryEngine.GeodesicEllipseParameter(); parameter.Center = point.Coordinate; parameter.SemiAxis1Length = radius; parameter.SemiAxis2Length = radius; parameter.AxisDirection = radian; parameter.LinearUnit = LinearUnit.Meters; parameter.OutGeometryType = GeometryType.Polyline; parameter.VertexCount = 36; var ellipse = GeometryEngine.GeodesicEllipse(parameter, point.SpatialReference) as Polyline; //For each key we will progressively rotate around the ellipse and calculate the camera position at each. for (int i = 0; i <= numOfKeys; i++) { var percentAlong = ((Math.Abs(keyEvery) * i) % 360) / 360.0; if (keyEvery > 0) { percentAlong = 1 - percentAlong; } //Get the camera at the position around the ellipse. camera = OffsetCamera(camera, ellipse, point, percentAlong); //Increment the time by the amount of time per key. if (i != 0) { currentTimeSeconds += (timeInterval * Math.Abs(keyEvery)); } //Create a new keyframe for the camera. cameraTrack.CreateKeyframe(camera, TimeSpan.FromSeconds(currentTimeSeconds), AnimationTransition.FixedArc); } //For any degree rotation left over create a keyframe. For example 155, would have a keyframe every 10 degrees and then one for the final 5 degrees. if (remainder != 0.0) { var percentAlong = ((Math.Abs(keyEvery) * numOfKeys + Math.Abs(remainder)) % 360) / 360.0; if (remainder > 0) { percentAlong = 1 - percentAlong; } OffsetCamera(camera, ellipse, point, percentAlong); //Increment the time and create the keyframe. currentTimeSeconds += (timeInterval * Math.Abs(remainder)); cameraTrack.CreateKeyframe(camera, TimeSpan.FromSeconds(currentTimeSeconds), AnimationTransition.FixedArc); } })); }