Skip to content

Instantly share code, notes, and snippets.

@k0t0vich
Created November 19, 2014 10:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save k0t0vich/26b2074f119af2480773 to your computer and use it in GitHub Desktop.
Save k0t0vich/26b2074f119af2480773 to your computer and use it in GitHub Desktop.
package ru.yandex.maps.pano.engine.math.utils {
import ru.yandex.maps.geo.GeoPoint;
import ru.yandex.maps.pano.engine.core.SphericalCoordinates;
public class CoordinatesUtil {
public static function sphericalFromGeoPoints(centralPoint:GeoPoint,
geoPoint:GeoPoint):SphericalCoordinates {
var distance:Number = centralPoint.distanceTo(geoPoint);
var azimuth:Number = centralPoint.azimuthTo(geoPoint);
var elevation:Number = -Math.atan2(centralPoint.altitude - geoPoint.altitude, distance);
var radius:Number = Math.sqrt(distance * distance +
centralPoint.altitude * centralPoint.altitude);
var result:SphericalCoordinates = new SphericalCoordinates(azimuth, elevation,
radius);
return result;
}
}
}
package ru.yandex.maps.pano.engine.math.projections.source {
import flash.geom.Point;
import flash.geom.Rectangle;
import ru.yandex.maps.pano.engine.core.SphericalCoordinates;
import ru.yandex.utils.math.AngleUtil;
public class EquirectangularProjection implements ISourceProjection {
public static const projection:ISourceProjection = new EquirectangularProjection();
public function EquirectangularProjection() {
}
public function sphericalToUv(sphericalPoint:SphericalCoordinates, span:Rectangle,
origin:SphericalCoordinates):Point {
// приводим к [0; 2П]
var dx:Number = AngleUtil.diff(sphericalPoint.azimuth, origin.azimuth) / span.width;
var dy:Number = (span.y - sphericalPoint.elevation + origin.elevation) /
span.height;
return new Point(dx, dy);
}
}
}
package ru.yandex.maps.geo {
import flash.geom.Point;
import ru.yandex.utils.math.Range;
public class GeoPoint {
public static function fromMercator(point:Point):GeoPoint {
// Isometric longitude
var lambda:Number = point.x / WGS84.RADIUS;
// Isometric latitude
var xPhi:Number = Math.PI / 2.0
- 2.0 * Math.atan(1.0 / Math.exp(point.y / WGS84.RADIUS));
var phi:Number = xPhi
+ WGS84.AB * Math.sin(2.0 * xPhi)
+ WGS84.BB * Math.sin(4.0 * xPhi)
+ WGS84.CB * Math.sin(6.0 * xPhi)
+ WGS84.DB * Math.sin(8.0 * xPhi);
return new GeoPoint(lambda, phi);
}
public function GeoPoint(longitude:Number = 0,
latitude:Number = 0, altitude:Number = 0) {
_latitude = latitude;
_longitude = longitude;
_altitude = altitude;
}
public function distanceTo(other:GeoPoint):Number {
if (this.equals(other)) {
return 0;
}
return new GeoVector(this, other).distance;
}
public function azimuthTo(other:GeoPoint):Number {
if (this.equals(other)) {
return 0;
}
return new GeoVector(this, other).azimuth;
}
public function toMercator():Point {
var f:Number = WGS84.E2 / 2;
var e:Number = Math.sqrt(f * (2.0 - f));
var eSinLat:Number = e * Math.sin(_latitude);
var temp1:Number = Math.tan(Math.PI / 4.0 + _latitude / 2.0);
var temp2:Number = Math.pow(
Math.tan(Math.PI / 4.0 + Math.asin(eSinLat) / 2.0), e
);
var U:Number = temp1 / temp2;
var y:Number = WGS84.RADIUS * Math.log(U);
var x:Number = WGS84.RADIUS * _longitude;
return new Point(x, y);
}
public function copy(other:GeoPoint):void {
_latitude = other._latitude;
_longitude = other._longitude;
_altitude = other._altitude;
}
public function equals(other:GeoPoint):Boolean {
return other && ((GeoUtil.sign(_longitude - other._longitude) == 0)
&& (GeoUtil.sign(_latitude - other._latitude) == 0)
&& (GeoUtil.sign(_altitude - other._altitude) == 0)
);
}
public function clone():GeoPoint {
return new GeoPoint(_longitude, _latitude, _altitude);
}
public function toString():String {
return "{lat: " + _latitude + ", lng: " + _longitude +
", alt: " + _altitude + "}";
}
private var _latitude:Number;
public function get latitude():Number {
return _latitude;
}
public function set latitude(value:Number):void {
_latitude = value;
}
private var _longitude:Number;
public function get longitude():Number {
return _longitude;
}
public function set longitude(value:Number):void {
_longitude = value;
}
private var _altitude:Number;
public function get altitude():Number {
return _altitude;
}
public function set altitude(value:Number):void {
_altitude = value;
}
}
}
package ru.yandex.maps.geo {
public class GeoUtil {
public static const EPS:Number = 1E-7;
public static function sign(x:Number, epsilon:Number = EPS):int {
if (x < -epsilon) {
return -1;
}
if (x > epsilon) {
return 1;
}
return 0;
}
}
}
package ru.yandex.maps.geo {
import ru.yandex.utils.math.Range;
public class GeoVector {
private var _lon1:Number;
private var _lat1:Number;
private var _lon2:Number;
private var _lat2:Number;
private var _dLambda:Number;
private var _dPhi:Number;
private var _distance:Number;
private var _sphericalAngularDistance:Number;
private var _angularDistance:Number;
private var _azimuth:Number;
public function GeoVector(p1:GeoPoint, p2:GeoPoint) {
_lon1 = p1.longitude;
_lat1 = p1.latitude;
_lon2 = p2.longitude;
_lat2 = p2.latitude;
_dLambda = _lon1 - _lon2;
_dPhi = _lat1 - _lat2;
}
public function calculateAzimuth():Number {
if (isNaN(_azimuth)) {
if (isNaN(_angularDistance)) {
calculateAngularDistance();
}
_azimuth = _angularDistance;
var alpha:Number = Math.abs(_angularDistance);
if ((_lat1 <= _lat2) && (_lon1 <= _lon2)) {
_azimuth = alpha;
} else if ((_lat1 <= _lat2) && (_lon1 >= _lon2)) {
_azimuth = (2.0 * Math.PI - alpha);
} else if ((_lat1 >= _lat2) && (_lon1 >= _lon2)) {
_azimuth = (Math.PI + alpha);
} else if ((_lat1 >= _lat2) && (_lon1 <= _lon2)) {
_azimuth = (Math.PI - alpha);
}
/*if (_lat1 > _lat2) {
_azimuth += Math.PI;
}*/
}
return _azimuth;
}
public function calculateDistance():Number {
if (isNaN(_distance)) {
var phiMean:Number = (_lat1 + _lat2) * 0.5;
var sinPhiMean:Number = Math.sin(phiMean);
var temp:Number = 1.0 - WGS84.E2 * sinPhiMean * sinPhiMean;
var rho:Number = WGS84.RADIUS * (1.0 - WGS84.E2) / Math.pow(temp, 1.5);
var nu:Number = WGS84.RADIUS / Math.sqrt(temp);
if (isNaN(_angularDistance)) {
calculateAngularDistance();
}
var alpha:Number = _angularDistance;
var r:Number = rho * nu / ((rho * Math.pow(Math.sin(alpha), 2))
+ (nu * Math.pow(Math.cos(alpha), 2)));
_distance = _sphericalAngularDistance * r;
}
return _distance;
}
private function calculateAngularDistance():void {
var sinPhi:Number = Math.sin(_dPhi * 0.5);
var sinLambda:Number = Math.sin(_dLambda * 0.5);
var z:Number = Math.sqrt(sinPhi * sinPhi
+ Math.cos(_lat1) * Math.cos(_lat2) * sinLambda * sinLambda);
_sphericalAngularDistance = 2.0 * Math.asin(z);
var alpha:Number = Math.cos(_lat2) * Math.sin(_dLambda) /
Math.sin(_sphericalAngularDistance);
/* This is a HACK to avoid MAPSCORE-1553! */
alpha = new Range(-1, 1).restrict(alpha);
_angularDistance = Math.asin(alpha);
}
public function get angularDistance():Number {
if (isNaN(_angularDistance)) {
calculateAngularDistance();
}
return _angularDistance;
}
public function get azimuth():Number {
if (isNaN(_azimuth)) {
calculateAzimuth();
}
return _azimuth;
}
public function get distance():Number {
if (isNaN(_distance)) {
calculateDistance();
}
return _distance;
}
}
}
package ru.yandex.maps.pano.engine.math.projections.view {
import ru.yandex.maps.pano.engine.core.SphericalCoordinates;
import ru.yandex.maps.pano.engine.core.ViewPoint;
public class RectilinearProjection implements IViewProjection {
public static const projection:IViewProjection = new RectilinearProjection();
public function sphericalToViewport(azimuth:Number, elevation:Number,
cameraVector:SphericalCoordinates):ViewPoint {
var tmp:Number = Math.cos(elevation) * Math.cos(azimuth - cameraVector.azimuth);
var cosC:Number = Math.sin(cameraVector.elevation) * Math.sin(elevation) +
Math.cos(cameraVector.elevation) * tmp;
var x:Number = Math.cos(elevation) * Math.sin(azimuth - cameraVector.azimuth);
var y:Number = Math.cos(cameraVector.elevation) * Math.sin(elevation) -
Math.sin(cameraVector.elevation) * tmp;
x = x * cameraVector.radius / cosC;
y = y * cameraVector.radius / cosC;
return new ViewPoint(x, -y, cosC);
}
public function viewportToSpherical(x:Number, y:Number,
cameraVector:SphericalCoordinates):SphericalCoordinates {
// phi1 = -phi1;
// масштабируем
var x1:Number = x / cameraVector.radius;
var y1:Number = y / cameraVector.radius;
var x2:Number = x1 * x1;
var y2:Number = y1 * y1;
var q:Number = Math.sqrt(x2 + y2);
var c:Number = Math.atan(q);
var del:Number = x1 * Math.sin(c);
var num:Number = q * Math.cos(cameraVector.elevation) * Math.cos(c)
- y1 * Math.sin(cameraVector.elevation) * Math.sin(c);
var phi:Number = Math.asin(Math.cos(c) * Math.sin(cameraVector.elevation) +
y1 * Math.sin(c) * Math.cos(cameraVector.elevation) / q);
var lambda:Number = cameraVector.azimuth + Math.atan2(del, num);
return new SphericalCoordinates(lambda, phi);
}
public function calculatePitch(viewportY:Number, focalLength:Number,
pointElevation:Number):Number {
return pointElevation - Math.atan(viewportY / focalLength);
}
public function calculateRadius(viewportDistance:Number, angle:Number):Number {
return viewportDistance / Math.tan(angle);
}
}
}
package ru.yandex.maps.geo {
public class WGS84 {
/**
* Длина большой полуоси
*/
public static const RADIUS:Number = 6378137.0;
/**
* Удвоенный коэффициент сжатия
*/
public static const E2:Number = 2 / 298.257223563;
public static const AB:Number = 0.00335655146887969400;
public static const BB:Number = 0.00000657187271079536;
public static const CB:Number = 0.00000001764564338702;
public static const DB:Number = 0.00000000005328478445;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment