void Init(Tuple <GeoAnchor, GeoAnchor> anchors) { // To compute the distance between two geographical co-ordinates, we first need to // convert to MapKit co-ordinates fromAnchorFloorplanPoint = anchors.Item1.Pixel; fromAnchorMKPoint = MKMapPoint.FromCoordinate(anchors.Item1.LatitudeLongitude); MKMapPoint toAnchorMKPoint = MKMapPoint.FromCoordinate(anchors.Item2.LatitudeLongitude); // So that we can use MapKit's helper function to compute distance. // this helper function takes into account the curvature of the earth. var distanceBetweenPointsMeters = (nfloat)MKGeometry.MetersBetweenMapPoints(fromAnchorMKPoint, toAnchorMKPoint); var dx = anchors.Item1.Pixel.X - anchors.Item2.Pixel.X; var dy = anchors.Item1.Pixel.Y - anchors.Item2.Pixel.Y; // Distance between two points in pixels (on the floorplan image) var distanceBetweenPointsPixels = Hypot(dx, dy); // This gives us pixels/meter PixelsPerMeter = distanceBetweenPointsPixels / distanceBetweenPointsMeters; // Get the 2nd anchor's eastward/southward distance in meters from the first anchor point. var hyp = FetchRect(fromAnchorMKPoint, toAnchorMKPoint); // Angle of diagonal to east (in geographic) nfloat angleFromEastAndHypo = NMath.Atan2(hyp.South, hyp.East); // Angle of diagonal to horizontal (in floorplan) nfloat angleFromXAndHypo = NMath.Atan2(dy, dx); // Rotation amount from the geographic anchor line segment // to the floorplan anchor line segment // This is angle between X axis and East direction. This angle shows how you floor plan exists in real world radiansRotated = angleFromXAndHypo - angleFromEastAndHypo; }
// MapKit alternative public static double MKGetDistanceBetween(Airport airport1, Airport airport2) { CLLocationCoordinate2D loc1 = new CLLocationCoordinate2D(airport1.Latitude, airport1.Longitude); CLLocationCoordinate2D loc2 = new CLLocationCoordinate2D(airport2.Latitude, airport2.Longitude); MKMapPoint point1 = MKMapPoint.FromCoordinate(loc1); MKMapPoint point2 = MKMapPoint.FromCoordinate(loc2); return(MKGeometry.MetersBetweenMapPoints(point1, point2) / MetersPerNauticalMile); }
// Two points in rectangular co-ordinate system create a rectange static EastSouthDistance FetchRect(MKMapPoint fromAnchorMKPoint, MKMapPoint toPoint) { double latitude = MKMapPoint.ToCoordinate(fromAnchorMKPoint).Latitude; nfloat metersPerMapPoint = (nfloat)MKGeometry.MetersPerMapPointAtLatitude(latitude); var eastSouthDistance = new EastSouthDistance { East = (nfloat)(toPoint.X - fromAnchorMKPoint.X) * metersPerMapPoint, South = (nfloat)(toPoint.Y - fromAnchorMKPoint.Y) * metersPerMapPoint }; return(eastSouthDistance); }
public void MetersPerMapPointAtLatitude() { Assert.That(MKGeometry.MetersPerMapPointAtLatitude(0), Is.EqualTo(0.148).Within(0.001), "0"); Assert.That(MKGeometry.MetersPerMapPointAtLatitude(90), Is.EqualTo(0.254).Within(0.001), "90"); Assert.That(MKGeometry.MetersPerMapPointAtLatitude(91), Is.EqualTo(Double.PositiveInfinity), "91"); Assert.That(MKGeometry.MetersPerMapPointAtLatitude(-90), Is.EqualTo(0.000416).Within(0.000001), "-90"); Assert.That(MKGeometry.MetersPerMapPointAtLatitude(-91), Is.EqualTo(Double.PositiveInfinity), "-91"); Assert.That(MKGeometry.MetersPerMapPointAtLatitude(Double.NaN), Is.NaN, "NaN"); Assert.That(MKGeometry.MetersPerMapPointAtLatitude(Double.NegativeInfinity), Is.NaN, "NegativeInfinity"); Assert.That(MKGeometry.MetersPerMapPointAtLatitude(Double.PositiveInfinity), Is.NaN, "PositiveInfinity"); }
public void MapPointsPerMeterAtLatitude() { Assert.That(MKGeometry.MapPointsPerMeterAtLatitude(0), Is.EqualTo(6.743).Within(0.001), "0"); Assert.That(MKGeometry.MapPointsPerMeterAtLatitude(90), Is.EqualTo(3.936).Within(0.001), "90"); Assert.That(MKGeometry.MapPointsPerMeterAtLatitude(91), Is.EqualTo(0), "91"); Assert.That(MKGeometry.MapPointsPerMeterAtLatitude(-90), Is.EqualTo(2399.37).Within(0.01), "-90"); Assert.That(MKGeometry.MapPointsPerMeterAtLatitude(-91), Is.EqualTo(0), "-91"); Assert.That(MKGeometry.MapPointsPerMeterAtLatitude(Double.NaN), Is.NaN, "NaN"); Assert.That(MKGeometry.MapPointsPerMeterAtLatitude(Double.NegativeInfinity), Is.NaN, "NegativeInfinity"); Assert.That(MKGeometry.MapPointsPerMeterAtLatitude(Double.PositiveInfinity), Is.NaN, "PositiveInfinity"); }
public void MetersBetweenMapPoints() { MKMapPoint a = new MKMapPoint(); Assert.That(MKGeometry.MetersBetweenMapPoints(a, a), Is.EqualTo(0.0), "a-a"); MKMapPoint b = new MKMapPoint(1000, 1000); Assert.That(MKGeometry.MetersBetweenMapPoints(b, b), Is.EqualTo(0.0), "b-b"); Assert.That(MKGeometry.MetersBetweenMapPoints(a, b), Is.EqualTo(18.153).Within(0.001), "a-b"); Assert.That(MKGeometry.MetersBetweenMapPoints(b, a), Is.EqualTo(18.153).Within(0.001), "b-a"); MKMapPoint c = new MKMapPoint(Double.NaN, Double.NaN); Assert.That(MKGeometry.MetersBetweenMapPoints(a, c), Is.NaN, "NaN"); }
public MapCluster(List <MapPointAnnotation> annotations, int depth, MKMapRect mapRect, double gamma, string clusterTitle, bool showSubtitle) { Depth = depth; _mapRect = mapRect; _clusterTitle = clusterTitle; ShowSubtitle = showSubtitle; switch (annotations.Count) { case 0: _leftChild = null; _rightChild = null; Annotation = null; ClusterCoordinate = new CLLocationCoordinate2D(91, 181); // Todo: Invalid, instead of constant. break; case 1: _leftChild = null; _rightChild = null; Annotation = annotations.Last(); ClusterCoordinate = Annotation.Annotation.Coordinate; break; default: { Annotation = null; // Principal Component Analysis // If cov(x,y) = ∑(x-x_mean) * (y-y_mean) != 0 (covariance different from zero), we are looking for the following principal vector: // a (aX) // (aY) // // x_ = x - x_mean ; y_ = y - y_mean // // aX = cov(x_,y_) // // // aY = 0.5/n * ( ∑(x_^2) + ∑(y_^2) + sqrt( (∑(x_^2) + ∑(y_^2))^2 + 4 * cov(x_,y_)^2 ) ) // compute the means of the coordinate var xSum = 0.0; var ySum = 0.0; foreach (var annotation in annotations) { xSum += annotation.MapPoint.X; ySum += annotation.MapPoint.Y; } var xMean = xSum / annotations.Count; var yMean = ySum / annotations.Count; if (gamma != 1.0) { // take gamma weight into account var gammaSumX = 0.0; var gammaSumY = 0.0; var maxDistance = 0.0; var meanCenter = new MKMapPoint(xMean, yMean); foreach (var annotation in annotations) { var distance = MKGeometry.MetersBetweenMapPoints(annotation.MapPoint, meanCenter); if (distance > maxDistance) { maxDistance = distance; } } var totalWeight = 0.0; foreach (var annotation in annotations) { var point = annotation.MapPoint; var distance = MKGeometry.MetersBetweenMapPoints(point, meanCenter); var normalizedDistance = maxDistance != 0.0 ? distance / maxDistance : 1.0; var weight = Math.Pow(normalizedDistance, gamma - 1.0); gammaSumX += point.X * weight; gammaSumY += point.Y * weight; totalWeight += weight; } xMean = gammaSumX / totalWeight; yMean = gammaSumY / totalWeight; } // compute coefficients var sumXsquared = 0.0; var sumYsquared = 0.0; var sumXy = 0.0; foreach (var annotation in annotations) { var x = annotation.MapPoint.X - xMean; var y = annotation.MapPoint.Y - yMean; sumXsquared += x * x; sumYsquared += y * y; sumXy += x * y; } double aX; double aY; if (Math.Abs(sumXy) / annotations.Count > MapConstants.ClusterDiscriminationPrecision) { aX = sumXy; var lambda = 0.5 * ((sumXsquared + sumYsquared) + Math.Sqrt((sumXsquared + sumYsquared) * (sumXsquared + sumYsquared) + 4 * sumXy * sumXy)); aY = lambda - sumXsquared; } else { aX = sumXsquared > sumYsquared ? 1.0 : 0.0; aY = sumXsquared > sumYsquared ? 0.0 : 1.0; } List <MapPointAnnotation> leftAnnotations; List <MapPointAnnotation> rightAnnotations; if (Math.Abs(sumXsquared) / annotations.Count < MapConstants.ClusterDiscriminationPrecision || Math.Abs(sumYsquared) / annotations.Count < MapConstants.ClusterDiscriminationPrecision) { // then every x equals XMean and we have to arbitrarily choose where to put the pivotIndex var pivotIndex = annotations.Count / 2; leftAnnotations = annotations.GetRange(0, pivotIndex); rightAnnotations = annotations.GetRange(pivotIndex, annotations.Count - pivotIndex); } else { // compute scalar product between the vector of this regression line and the vector // (x - x(mean)) // (y - y(mean)) // the sign of this scalar product determines which cluster the point belongs to leftAnnotations = new List <MapPointAnnotation>(); rightAnnotations = new List <MapPointAnnotation>(); foreach (var annotation in annotations) { var point = annotation.MapPoint; var positivityConditionOfScalarProduct = true; // TODO: Don't know why this is here... its there in the original code. Or is it a wrong Objective-C interpretation? if (true) { positivityConditionOfScalarProduct = (point.X - xMean) * aX + (point.Y - yMean) * aY > 0.0; } else { positivityConditionOfScalarProduct = (point.Y - yMean) > 0.0; } if (positivityConditionOfScalarProduct) { leftAnnotations.Add(annotation); } else { rightAnnotations.Add(annotation); } } } // compute map rects double xMin = float.MaxValue, xMax = 0.0f, yMin = float.MaxValue, yMax = 0.0f; foreach (var point in leftAnnotations.Select(annotation => annotation.MapPoint)) { if (point.X > xMax) { xMax = point.X; } if (point.Y > yMax) { yMax = point.Y; } if (point.X < xMin) { xMin = point.X; } if (point.Y < yMin) { yMin = point.Y; } } var leftMapRect = new MKMapRect(xMin, yMin, xMax - xMin, yMax - yMin); xMin = float.MaxValue; xMax = 0.0; yMin = float.MaxValue; yMax = 0.0; foreach (var point in rightAnnotations.Select(annotation => annotation.MapPoint)) { if (point.X > xMax) { xMax = point.X; } if (point.Y > yMax) { yMax = point.Y; } if (point.X < xMin) { xMin = point.X; } if (point.Y < yMin) { yMin = point.Y; } } var rightMapRect = new MKMapRect(xMin, yMin, xMax - xMin, yMax - yMin); ClusterCoordinate = MKMapPoint.ToCoordinate(new MKMapPoint(xMean, yMean)); _leftChild = new MapCluster(leftAnnotations, depth + 1, leftMapRect, gamma, clusterTitle, showSubtitle); _rightChild = new MapCluster(rightAnnotations, depth + 1, rightMapRect, gamma, clusterTitle, showSubtitle); } break; } }