I have a function here (inspired by https://github.com/amitp/mapgen2/blob/master/Map.as in the islandshape factory function) that should seperate a square map into land and water.
Like so: disregard the different biomes
Buut, in the function I use below, the whole thing seems to just come out as water...
--makeRadial decides which points are on land or water based on overlapping sine waves (random radial island)
function makeRadial(seed) --factory function to return same randoms for inside(), unless new island is created
local bumps = math.random(1, 6)
math.randomseed(seed)
local startAngle = math.random() * (2*math.pi)
local dipAngle = math.random() * (2*math.pi)
local dipWidth = math.random() * 0.5 + 0.2
local inside = function (point)
if not point then return end
local angle = math.atan2(point.y, point.x)
local length = 0.5 * (math.max(math.abs(point.x), math.abs(point.y) + point.magnitude))
local r1 = 0.5 + 0.40*math.sin(startAngle + bumps*angle + math.cos((bumps+3)*angle))
local r2 = 0.7 - 0.20*math.sin(startAngle + bumps*angle - math.sin((bumps+2)*angle))
if math.abs(angle - dipAngle) < dipWidth
or math.abs(angle - dipAngle + 2*math.pi) < dipWidth
or math.abs(angle - dipAngle - 2*math.pi) < dipWidth then
r1, r2 = 0.2, 0.2
end
print("length:"..length.." < ".." r1:"..r1.." or < ".." r2:"..r2)
return length < r1 or (length > r1*ISLAND_FACTOR and length < r2)
end
return {
inside = inside
}
end
And the function below just redistributes the points from -1.0 to 1.0 and plugs them into the actual function
function inside(point, SIZE)
local islandshape = makeradial(*random seed*)
return islandshape.inside(2*(point.x/SIZE - 0.5), 2*(point.y/SIZE - 0.5))
end
This algorithm creates an island based on overlapping sine waves (smooth single large island with mostly no tiny islands off to the side). However, there is a problem with the length variable.
Just as a note: I discern water from land by setting a water boolean to each corner of a tile (corner.water = not inside(corner.point)) and then setting the tile as water based on the average of its corners.
Anyways the length variable seems to always come out greater than r1 and r2:
length:1.1783428788185 r1:0.76499270607242 r2:0.68719228997449
length:1.1779255270958 r1:0.76592961292669 r2:0.68729183465378
length:1.1775082945824 r1:0.7668633458924 r2:0.68739145169441
I'm not an expert in trigonometry, so I don't know if length is the problem here... but I think it may be a factor since I translated this from C. FYI, point.magnitude is just the distance of the point from 0,0.
Thanks in advance!
I am using the equations and data for Mars here
http://ssd.jpl.nasa.gov/txt/aprx_pos_planets.pdf
and the solution for the eccentric anomaly kepler equation given here at the top of page four
http://murison.alpheratz.net/dynamics/twobody/KeplerIterations_summary.pdf
And checking the output by modifying the date in the get_centuries_past to the following dates and looking at page E-7 for the actual x,y,z coordinates of Mars (sample data below, but link for the curious:
http://books.google.com/books/about/Astronomical_Almanac_for_the_Year_2013_a.html?id=7fl_-DLwJ8YC)
date 2456320.5 is 2013, 1, 28 and should output
x = 1.283762
y = -0.450111
z = -0.241123
date 2456357.5 is 2013, 3, 6 and should output
x = 1.300366
y = 0.533593
z = 0.209626
date 2456539.500000 is 2013, 9, 4 and should output
x = - 0.325604
y = 1.418110
z = 0.659236
I tested mean anomaly equation and it was fine. However, I cannot get a good set of x,y,z coordinates. I have been tweaking my kepler and coordinate function but cannot get them to match the tables in the astronomical almanac.
Any suggestions or advice on solving the positions of the stars is greatly appreciated. The code below can be put in a .rb file and running it on the command line will output the x,y,z values.
def get_centuries_past_j2000()
#second number is from DateTime.new(2000,1,1,12).amjd.to_f - 1 the modified julian date for the J2000 Epoch
#Date.today.jd.to_f - 51544.5
(DateTime.new(2013,1,28).amjd.to_f - 51544.5)/36525
end
class Planet
attr_accessor :semi_major_axis, :semi_major_axis_delta, :eccentricity, :eccentricity_delta,
:inclination, :inclination_delta, :mean_longitude, :mean_longitude_delta, :longitude_of_perihelion,
:longitude_of_perihelion_delta, :longitude_of_ascending_node, :longitude_of_ascending_node_delta, :time_delta
def initialize(semi_major_axis, semi_major_axis_delta, eccentricity, eccentricity_delta,
inclination, inclination_delta, mean_longitude, mean_longitude_delta, longitude_of_perihelion,
longitude_of_perihelion_delta, longitude_of_ascending_node, longitude_of_ascending_node_delta, time_delta)
#semi_major_axis = semi_major_axis + (semi_major_axis_delta * time_delta)
#eccentricity = eccentricity + (eccentricity_delta * time_delta)
#inclination = inclination + (inclination_delta * time_delta)
#mean_longitude = mean_longitude + (mean_longitude_delta * time_delta)
#longitude_of_perihelion = longitude_of_perihelion + (longitude_of_perihelion_delta * time_delta)
#longitude_of_ascending_node = longitude_of_ascending_node + (longitude_of_ascending_node_delta * time_delta)
#argument_of_perhelion = #longitude_of_perihelion - #longitude_of_ascending_node
end
def mean_anomaly
((#mean_longitude - #longitude_of_perihelion)%360).round(8)
end
def eccentric_anomaly
mod_mean_anomaly = mean_anomaly
if mod_mean_anomaly > 180
mod_mean_anomaly = mod_mean_anomaly - 360
elsif mod_mean_anomaly < -180
mod_mean_anomaly = mod_mean_anomaly + 360
end
e34 = #eccentricity**2
e35 = #eccentricity*e34
e33 = Math.cos(mod_mean_anomaly*Math::PI/180)
mod_mean_anomaly + (-0.5 * e35 + #eccentricity + (e34 + 1.5 * e33 * e35) * e33) * Math.sin(mod_mean_anomaly*Math::PI/180)
end
def J2000_ecliptic_plane
x_prime = #semi_major_axis * (Math.cos(eccentric_anomaly*Math::PI/180) - #eccentricity)
y_prime = #semi_major_axis * Math.sqrt(1-#eccentricity**2) * Math.sin(eccentric_anomaly*Math::PI/180)
z_prime = 0
x = x_prime * (Math.cos(#argument_of_perhelion*Math::PI/180) * Math.cos(#longitude_of_ascending_node*Math::PI/180) - Math.sin(#argument_of_perhelion * Math::PI/180) * Math.sin(#longitude_of_ascending_node * Math::PI/180) * Math.cos(#inclination * Math::PI/180)) + y_prime * (-Math.sin(#argument_of_perhelion* Math::PI/180) * Math.cos(#longitude_of_ascending_node * Math::PI/180) - Math.cos(#argument_of_perhelion * Math::PI/180) * Math.sin(#longitude_of_ascending_node * Math::PI/180) * Math.cos(#inclination * Math::PI/180))
y = x_prime * (Math.cos(#argument_of_perhelion*Math::PI/180) * Math.sin(#longitude_of_ascending_node*Math::PI/180) + Math.sin(#argument_of_perhelion * Math::PI/180) * Math.cos(#longitude_of_ascending_node * Math::PI/180) * Math.cos(#inclination * Math::PI/180)) + y_prime * (-Math.sin(#argument_of_perhelion* Math::PI/180) * Math.sin(#longitude_of_ascending_node * Math::PI/180) + Math.cos(#argument_of_perhelion * Math::PI/180) * Math.cos(#longitude_of_ascending_node * Math::PI/180) * Math.cos(#inclination * Math::PI/180))
z = x_prime * Math.sin(#argument_of_perhelion*Math::PI/180) * Math.sin(#inclination*Math::PI/180) + y_prime * Math.cos(#argument_of_perhelion*Math::PI/180) * Math.sin(#inclination*Math::PI/180)
return x, y, z
end
end
time = get_centuries_past_j2000
mars = Planet.new(1.52371034, 0.00001847, 0.09339410, 0.00007882, 1.84969142, -0.00813131, -4.553443205, 19140.30268499, -23.94362959, 0.44441088, 49.55952891, -0.29257343, time)
puts time
puts mars.mean_anomaly
puts mars.eccentric_anomaly
puts mars.J2000_ecliptic_plane
This may be helpful although I don't agree with arguments of perihelion for Earth. Longitude of perihelion is fine. The inclination is so small that it doesn't really apply for Earth as it does for other planets. And finding values for Omega is challenging. The perihelion is ever changing. FYI in 1248 AD it coincided with the winter solstice.
Firstly IAU has free SOFA C and FORTRAN lib's with standardized astronomical functions. Matric tables are included in certain routines so you don't have to go look them up.
But if you are so inclined to use old school methods then this site has what you need http://www.stjarnhimlen.se/comp/tutorial.html
NOVA C and JAVA, MICA, JPL catalogs, Jean Meeus book, AA USNO and a host of others beside wikipedia have tons of information. It looks like you want rectangular values so I think Paul Schlyter can help you out.
SOFA has these as well but documentation on how to use them is not going to teach the techniques. It will take a lot of research to understand them.
It looks like you are using Ruby and there is a wrapper gem for the SOFA lib named Celes. Just gem install celes and you'll have it.
Try looking at the fundamental arguments which all begin with fa:
** iauFal03 mean anomaly of the Moon
** iauFaf03 mean argument of the latitude of the Moon
** iauFaom03 mean longitude of the Moon's ascending node
** iauFame03 mean longitude of Mercury
** iauFave03 mean longitude of Venus
** iauFae03 mean longitude of Earth
** iauFama03 mean longitude of Mars
** iauFaju03 mean longitude of Jupiter
** iauFasa03 mean longitude of Saturn
** iauFaur03 mean longitude of Uranus
** iauFapa03 general accumulated precession in longitude
Have fun!
Edit Update:
Two functions in this gem that will give you heliocentric and barycentric x,y,z for Earth.
p is position and v is velocity.
h is heliocentric and b is barycentric.
pvh = Celes.epv00(jd_now, 0.0)[0]
pvb = Celes.epv00(jd_now, 0.0)[1]
sc = Celes.pv2s(pvh)
sc means spherical coordinates.
As you can see, all you need to provide is a JD time value.
So lots of good stuff in that gem and the SOFA C code.
I have yet to learn how to use them all.
I'm wondering if there's a way to calculate the distance of two GPS coordinates without relying on Google Maps API.
My app may receive the coordinates in float or I would have to do reverse GEO on the addresses.
Distance between two coordinates on earth is usually calculated using Haversine formula. This formula takes into consideration earth shape and radius. This is the code I use to calculate distance in meters.
def distance(loc1, loc2)
rad_per_deg = Math::PI/180 # PI / 180
rkm = 6371 # Earth radius in kilometers
rm = rkm * 1000 # Radius in meters
dlat_rad = (loc2[0]-loc1[0]) * rad_per_deg # Delta, converted to rad
dlon_rad = (loc2[1]-loc1[1]) * rad_per_deg
lat1_rad, lon1_rad = loc1.map {|i| i * rad_per_deg }
lat2_rad, lon2_rad = loc2.map {|i| i * rad_per_deg }
a = Math.sin(dlat_rad/2)**2 + Math.cos(lat1_rad) * Math.cos(lat2_rad) * Math.sin(dlon_rad/2)**2
c = 2 * Math::atan2(Math::sqrt(a), Math::sqrt(1-a))
rm * c # Delta in meters
end
puts distance([46.3625, 15.114444],[46.055556, 14.508333])
# => 57794.35510874037
You can use the geokit ruby gem. It does these calculations internally, but also supports resolving addresses via google and other services if you need it to.
require 'geokit'
current_location = Geokit::LatLng.new(37.79363,-122.396116)
destination = "37.786217,-122.41619"
current_location.distance_to(destination)
# Returns distance in miles: 1.211200074136264
You can also find out the bearing_to (direction expressed as a float in degrees between 0-360) and midpoint_to (returns an object you can run .latitude and .longitude methods on).
Just a little shorter & separated parameter version of #Lunivore's answer
RAD_PER_DEG = Math::PI / 180
RM = 6371000 # Earth radius in meters
def distance_between(lat1, lon1, lat2, lon2)
lat1_rad, lat2_rad = lat1 * RAD_PER_DEG, lat2 * RAD_PER_DEG
lon1_rad, lon2_rad = lon1 * RAD_PER_DEG, lon2 * RAD_PER_DEG
a = Math.sin((lat2_rad - lat1_rad) / 2) ** 2 + Math.cos(lat1_rad) * Math.cos(lat2_rad) * Math.sin((lon2_rad - lon1_rad) / 2) ** 2
c = 2 * Math::atan2(Math::sqrt(a), Math::sqrt(1 - a))
RM * c # Delta in meters
end
I'm not sure of any prepackaged solution, but it seems a fairly straightforward calculation: http://www.movable-type.co.uk/scripts/latlong.html
You can use the loc gem like this :
require 'loc'
loc1 = Loc::Location[49.1, 2]
loc2 = Loc::Location[50, 3]
loc1.distance_to(loc2)
=> 123364.76538823603 # km
Look at gem Geocoder(railscast)
If you store your coordinates in db, it calculate distance using database. But works good in other cases too.
Converted the accepted answer to Swift 3.1 (works on Xcode 8.3), in case anyone needs it:
public static func calculateDistanceMeters(departure: CLLocationCoordinate2D, arrival: CLLocationCoordinate2D) -> Double {
let rad_per_deg = Double.pi / 180.0 // PI / 180
let rkm = 6371.0 // Earth radius in kilometers
let rm = rkm * 1000.0 // Radius in meters
let dlat_rad = (arrival.latitude - departure.latitude) * rad_per_deg // Delta, converted to rad
let dlon_rad = (arrival.longitude - departure.longitude) * rad_per_deg
let lat1_rad = departure.latitude * rad_per_deg
let lat2_rad = arrival.latitude * rad_per_deg
let sinDlat = sin(dlat_rad/2)
let sinDlon = sin(dlon_rad/2)
let a = sinDlat * sinDlat + cos(lat1_rad) * cos(lat2_rad) * sinDlon * sinDlon
let c = 2.0 * atan2(sqrt(a), sqrt(1-a))
return rm * c
}
require 'rgeo'
point_1 = RGeo::Cartesian.factory.point(0, 0)
point_2 = RGeo::Cartesian.factory.point(0, 2)
p point_1.distance(point_2)
# => 2.0
I want to create 2 new longitude and 2 new latitudes based on a coordinate and a distance in meters, I want to create a nice bounding box around a certain point. It is for a part of a city and max ±1500 meters. I therefore don't think the curvature of earth has to be taken into account.
So I have 50.0452345 (x) and 4.3242234 (y) and I want to know x + 500 meters, x - 500 meters, y - 500 meters, y + 500 meters
I found many algorithms but almost all seem to deal with the distance between points.
The number of kilometers per degree of longitude is approximately
(pi/180) * r_earth * cos(theta*pi/180)
where theta is the latitude in degrees and r_earth is approximately 6378 km.
The number of kilometers per degree of latitude is approximately the same at all locations, approx
(pi/180) * r_earth = 111 km / degree
So you can do:
new_latitude = latitude + (dy / r_earth) * (180 / pi);
new_longitude = longitude + (dx / r_earth) * (180 / pi) / cos(latitude * pi/180);
As long as dx and dy are small compared to the radius of the earth and you don't get too close to the poles.
The accepted answer is perfectly right and works. I made some tweaks and turned into this:
double meters = 50;
// number of km per degree = ~111km (111.32 in google maps, but range varies
// between 110.567km at the equator and 111.699km at the poles)
//
// 111.32km = 111320.0m (".0" is used to make sure the result of division is
// double even if the "meters" variable can't be explicitly declared as double)
double coef = meters / 111320.0;
double new_lat = my_lat + coef;
// pi / 180 ~= 0.01745
double new_long = my_long + coef / Math.cos(my_lat * 0.01745);
Hope this helps too.
For latitude do:
var earth = 6378.137, //radius of the earth in kilometer
pi = Math.PI,
m = (1 / ((2 * pi / 360) * earth)) / 1000; //1 meter in degree
var new_latitude = latitude + (your_meters * m);
For longitude do:
var earth = 6378.137, //radius of the earth in kilometer
pi = Math.PI,
cos = Math.cos,
m = (1 / ((2 * pi / 360) * earth)) / 1000; //1 meter in degree
var new_longitude = longitude + (your_meters * m) / cos(latitude * (pi / 180));
The variable your_meters can contain a positive or a negative value.
I had to spend about two hours to work out the solution by #nibot , I simply needed a method to create a boundary box given its center point and width/height (or radius) in kilometers:
I don't fully understand the solution mathematically/ geographically.
I tweaked the solution (by trial and error) to get the four coordinates. Distances in km, given the current position and distance we shift to the new position in the four coordinates:
North:
private static Position ToNorthPosition(Position center, double northDistance)
{
double r_earth = 6378;
var pi = Math.PI;
var new_latitude = center.Lat + (northDistance / r_earth) * (180 / pi);
return new Position(new_latitude, center.Long);
}
East:
private static Position ToEastPosition(Position center, double eastDistance)
{
double r_earth = 6378;
var pi = Math.PI;
var new_longitude = center.Long + (eastDistance / r_earth) * (180 / pi) / Math.Cos(center.Lat * pi / 180);
return new Position(center.Lat, new_longitude);
}
South:
private static Position ToSouthPosition(Position center, double southDistance)
{
double r_earth = 6378;
var pi = Math.PI;
var new_latitude = center.Lat - (southDistance / r_earth) * (180 / pi);
return new Position(new_latitude, center.Long);
}
West:
private static Position ToWestPosition(Position center, double westDistance)
{
double r_earth = 6378;
var pi = Math.PI;
var new_longitude = center.Long - (westDistance / r_earth) * (180 / pi) / Math.Cos(center.Lat * pi / 180);
return new Position(center.Lat, new_longitude);
}
Have you checked out: How do I find the lat/long that is x km north of a given lat/long ?
These calculations are annoying at best, I've done many of them. The haversine formula will be your friend.
Some reference: http://www.movable-type.co.uk/scripts/latlong.html
Posting this method for sake of completeness.
Use this method "as it is" to:
Move any (lat,long) point by given meters in either axis.
Python method to move any point by defined meters.
def translate_latlong(lat,long,lat_translation_meters,long_translation_meters):
''' method to move any lat,long point by provided meters in lat and long direction.
params :
lat,long: lattitude and longitude in degrees as decimal values, e.g. 37.43609517497065, -122.17226450150885
lat_translation_meters: movement of point in meters in lattitude direction.
positive value: up move, negative value: down move
long_translation_meters: movement of point in meters in longitude direction.
positive value: left move, negative value: right move
'''
earth_radius = 6378.137
#Calculate top, which is lat_translation_meters above
m_lat = (1 / ((2 * math.pi / 360) * earth_radius)) / 1000;
lat_new = lat + (lat_translation_meters * m_lat)
#Calculate right, which is long_translation_meters right
m_long = (1 / ((2 * math.pi / 360) * earth_radius)) / 1000; # 1 meter in degree
long_new = long + (long_translation_meters * m_long) / math.cos(lat * (math.pi / 180));
return lat_new,long_new
Working Python code to offset coordinates by 10 metres.
def add_blur(lat, long):
meters = 10
blur_factor = meters * 0.000006279
new_lat = lat + blur_factor
new_long = long + blur_factor / math.cos(lat * 0.018)
return new_lat, new_long
if you don't have to be very exact then: each 10000 meters is about 0.1 for latitude and longitude.
for example I want to load locations 3000 meters around point_A from my database:
double newMeter = 3000 * 0.1 / 10000;
double lat1 = point_A.latitude - newMeter;
double lat2 = point_A.latitude + newMeter;
double lon1 = point_A.longitude - newMeter;
double lon1 = point_A.longitude + newMeter;
Cursor c = mDb.rawQuery("select * from TABLE1 where lat >= " + lat1 + " and lat <= " + lat2 + " and lon >= " + lon1 + " and lon <= " + lon2 + " order by id", null);
public double MeterToDegree(double meters, double latitude)
{
return meters / (111.32 * 1000 * Math.Cos(latitude * (Math.PI / 180)));
}
var meters = 50;
var coef = meters * 0.0000089;
var new_lat = map.getCenter().lat.apply() + coef;
var new_long = map.getCenter().lng.apply() + coef / Math.cos(new_lat * 0.018);
map.setCenter({lat:new_lat, lng:new_long});
See from Official Google Maps Documentation (link below) as they solve on easy/simple maps the problems with distance by countries :)
I recommended this solution to easy/simply solve issue with boundaries that you can know which area you're solving the problem with boundaries (not recommended globally)
Note:
Latitude lines run west-east and mark the position south-north of a point. Lines of latitude are called parallels and in total there are 180 degrees of latitude. The distance between each degree of latitude is about 69 miles (110 kilometers).
The distance between longitudes narrows the further away from the equator. The distance between longitudes at the equator is the same as latitude, roughly 69 miles (110 kilometers) . At 45 degrees north or south, the distance between is about 49 miles (79 kilometers). The distance between longitudes reaches zero at the poles as the lines of meridian converge at that point.
Original source 1
Original source 2
Official Google Maps Documentation: Code Example: Autocomplete Restricted to Multiple Countries
See the part of their code how they solve problem with distance center + 10 kilometers by +/- 0.1 degree
function initMap(): void {
const map = new google.maps.Map(
document.getElementById("map") as HTMLElement,
{
center: { lat: 50.064192, lng: -130.605469 },
zoom: 3,
}
);
const card = document.getElementById("pac-card") as HTMLElement;
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(card);
const center = { lat: 50.064192, lng: -130.605469 };
// Create a bounding box with sides ~10km away from the center point
const defaultBounds = {
north: center.lat + 0.1,
south: center.lat - 0.1,
east: center.lng + 0.1,
west: center.lng - 0.1,
};
const input = document.getElementById("pac-input") as HTMLInputElement;
const options = {
bounds: defaultBounds,
componentRestrictions: { country: "us" },
fields: ["address_components", "geometry", "icon", "name"],
origin: center,
strictBounds: false,
types: ["establishment"],
};
This is what I did in VBA that seems to be working for me. Calculation is in feet not meters though
Public Function CalcLong(OrigLong As Double, OrigLat As Double, DirLong As String, DirLat As String, DistLong As Double, DistLat As Double)
Dim FT As Double
Dim NewLong, NewLat As Double
FT = 1 / ((2 * WorksheetFunction.Pi / 360) * 20902230.971129)
If DirLong = "W" Then
NewLat = CalcLat(OrigLong, OrigLat, DirLong, DirLat, DistLong, DistLat)
NewLong = OrigLong - ((FT * DistLong) / Cos(NewLat * (WorksheetFunction.Pi / 180)))
CalcLong = NewLong
Else
NewLong = OrigLong + ((FT * DistLong) / Math.Cos(CalcLat(OrigLong, OrigLat, DirLong, DirLat, DistLong, DistLat) * (WorksheetFunction.Pi / 180)))
CalcLong = NewLong
End If
End Function
Public Function CalcLat(OrigLong As Double, OrigLat As Double, DirLong As String, DirLat As String, DistLong As Double, DistLat As Double) As Double
Dim FT As Double
Dim NewLat As Double
FT = 1 / ((2 * WorksheetFunction.Pi / 360) * 20902230.971129)
If DirLat = "S" Then
NewLat = (OrigLat - (FT * DistLat))
CalcLat = NewLat
Else
NewLat = (OrigLat + (FT * DistLat))
CalcLat = NewLat
End If
End Function
Original poster said:
"So I have 50.0452345 (x) and 4.3242234 (y) and I want to know x + 500 meters..."
I will assume the units of the x and y values he gave there were in meters (and not degrees Longitude, Latitude). If so then he is stating measurements to 0.1 micrometer, so I will assume he needs similar accuracy for the translated output. I also will assume by "+500 meters" etc. he meant
the direction to be due North-South and due East-West.
He refers to a reference point:
"2 new latitudes based on a coordinate";
but he did not give the Longitude and Latitude,
so to explain the procedure concretely I will give
the Latitudes and Longitudes for the corners of the
500 meter box he requested around the point
[30 degrees Longitude,30 degrees Latitude].
The exact solution on the surface of the GRS80 Ellipsoid is
given with the following set of functions
(I wrote these for the free-open-source-mac-pc math program called "PARI"
which allows any number of digits precision to be setup):
\\=======Arc lengths along Latitude and Longitude and the respective scales:
dms(u)=[truncate(u),truncate((u-truncate(u))*60),((u-truncate(u))*60-truncate((u-truncate(u))*60))*60];
SpinEarthRadiansPerSec=7.292115e-5;\
GMearth=3986005e8;\
J2earth=108263e-8;\
re=6378137;\
ecc=solve(ecc=.0001,.9999,eccp=ecc/sqrt(1-ecc^2);qecc=(1+3/eccp^2)*atan(eccp)-3/eccp;ecc^2-(3*J2earth+4/15*SpinEarthRadiansPerSec^2*re^3/GMearth*ecc^3/qecc));\
e2=ecc^2;\
b2=1-e2;\
b=sqrt(b2);\
fl=1-b;\
rfl=1/fl;\
U0=GMearth/ecc/re*atan(eccp)+1/3*SpinEarthRadiansPerSec^2*re^2;\
HeightAboveEllipsoid=0;\
reh=re+HeightAboveEllipsoid;\
longscale(lat)=reh*Pi/648000/sqrt(1+b2*(tan(lat))^2);
latscale(lat)=reh*b*Pi/648000/(1-e2*(sin(lat))^2)^(3/2);
longarc(lat,long1,long2)=longscale(lat)*648000/Pi*(long2-long1);
latarc(lat1,lat2)=(intnum(th=lat1,lat2,sqrt(1-e2*(sin(th))^2))+e2/2*sin(2*lat1)/sqrt(1-e2*(sin(lat1))^2)-e2/2*sin(2*lat2)/sqrt(1-e2*(sin(lat2))^2))*reh;
\\=======
I then plugged the reference point [30,30]
into those functions at the PARI command prompt
and had PARI solve for the point +/- 500 meters away
from it, giving the two new Longitudes and
two new Latitudes that the original poster asked for.
Here is the input and output showing that:
? dms(solve(x=29,31,longarc(30*Pi/180,30*Pi/180,x*Pi/180)+500))
cpu time = 1 ms, real time = 1 ms.
%1172 = [29, 59, 41.3444979398934670450280297216509190843055]
? dms(solve(x=29,31,longarc(30*Pi/180,30*Pi/180,x*Pi/180)-500))
cpu time = 1 ms, real time = 1 ms.
%1173 = [30, 0, 18.6555020601065329549719702783490809156945]
? dms(solve(x=29,31,latarc(30*Pi/180,x*Pi/180)+500))
cpu time = 1,357 ms, real time = 1,358 ms.
%1174 = [29, 59, 43.7621925447500548285775757329518579545513]
? dms(solve(x=29,31,latarc(30*Pi/180,x*Pi/180)-500))
cpu time = 1,365 ms, real time = 1,368 ms.
%1175 = [30, 0, 16.2377963202802863245716034907838199823349]
?
i have two rotation matrices that describe arbitrary rotations. (4x4 opengl compatible)
now i want to interpolate between them, so that it follows a radial path from one rotation to the other. think of a camera on a tripod looking one way and then rotating.
if i interpolate every component i get a squeezing result, so i think i need to interpolate only certain components of the matrix. but which ones?
You have to use SLERP for the rotational parts of the matrices, and linear for the other parts. The best way is to turn your matrices into quaternions and use the (simpler) quaternion SLERP: http://en.wikipedia.org/wiki/Slerp.
I suggest reading Graphic Gems II or III,specifically the sections about decomposing matrices into simpler transformations. Here's Spencer W. Thomas' source for this chapter:
http://tog.acm.org/resources/GraphicsGems/gemsii/unmatrix.c
Of course, I suggest you learn how to do this yourself. It's really not that hard, just a lot of annoying algebra. And finally, here's a great paper on how to turn a matrix into a quaternion, and back, by Id software: http://www.mrelusive.com/publications/papers/SIMD-From-Quaternion-to-Matrix-and-Back.pdf
Edit: This is the formula pretty much everyone cites, it's from a 1985 SIGGRAPH paper.
Where:
- qm = interpolated quaternion
- qa = quaternion a (first quaternion to be interpolated between)
- qb = quaternion b (second quaternion to be interpolated between)
- t = a scalar between 0.0 (at qa) and 1.0 (at qb)
- θ is half the angle between qa and qb
Code:
quat slerp(quat qa, quat qb, double t) {
// quaternion to return
quat qm = new quat();
// Calculate angle between them.
double cosHalfTheta = qa.w * qb.w + qa.x * qb.x + qa.y * qb.y + qa.z * qb.z;
// if qa=qb or qa=-qb then theta = 0 and we can return qa
if (abs(cosHalfTheta) >= 1.0){
qm.w = qa.w;qm.x = qa.x;qm.y = qa.y;qm.z = qa.z;
return qm;
}
// Calculate temporary values.
double halfTheta = acos(cosHalfTheta);
double sinHalfTheta = sqrt(1.0 - cosHalfTheta*cosHalfTheta);
// if theta = 180 degrees then result is not fully defined
// we could rotate around any axis normal to qa or qb
if (fabs(sinHalfTheta) < 0.001){ // fabs is floating point absolute
qm.w = (qa.w * 0.5 + qb.w * 0.5);
qm.x = (qa.x * 0.5 + qb.x * 0.5);
qm.y = (qa.y * 0.5 + qb.y * 0.5);
qm.z = (qa.z * 0.5 + qb.z * 0.5);
return qm;
}
double ratioA = sin((1 - t) * halfTheta) / sinHalfTheta;
double ratioB = sin(t * halfTheta) / sinHalfTheta;
//calculate Quaternion.
qm.w = (qa.w * ratioA + qb.w * ratioB);
qm.x = (qa.x * ratioA + qb.x * ratioB);
qm.y = (qa.y * ratioA + qb.y * ratioB);
qm.z = (qa.z * ratioA + qb.z * ratioB);
return qm;
}
From: http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
You need to convert the matrix into a different representation - quaternions work well for this, and interpolating quaternions is a well-defined operation.