# Determine if object is within viewport on Earth with GPS

This is a practical question, so if you find something missing, please assume a real life scenario.

The question is related to GPS and the Earth.

lat1: my latitude, GPS position I'm standing at (degrees)
lon1: my longitude, GPS position I'm standing at (degrees)
dir1: my direction I'm facing (from north, 0-360°, positive clockwise)
lat2: latitude of object
lon2: longitude of object
view: my viewport

I'm a person with position lat1, lon1, facing dir1. My viewport is 180°. Object is located at lat2, lon2.

How do I calculate that object is within my viewport?

Edit: viewport is assumed to be 180° and has a 1km radius.

-
Do you assume that you can see over the horizon? Any limit to that? –  John M Jul 24 '11 at 4:49
I guess you could post your calculations, but before you do that, I'd check to make sure how well-posed your problem is. The way I see it, if you have a 180 degree view, but there is no limit to how far you can see, then you should be able to see any point on the globe, just by following a great circle route. So I would say the answer is that every object is in your viewport. –  John M Jul 24 '11 at 6:32
@bizso09: Since you mention the frustrating waste of your time, you will probably be able to appreciate that the downvoters are frustrated about the waste of their time by scores of sloppily posed questions where one realizes after taking the time to read through them and think about them that the person who posed them didn't take the time and care to make sure all the relevant information is included. You've now further exacerbated that by forcing them to read through long comments before they get to an essential piece of information; you should edit that into the question. –  joriki Jul 24 '11 at 7:54
@bizso09: It's fairly standard here to let people you don't know edit their own questions if they know how they should. Downvotes are a symbolic action designed to grade a user's effort and sincerity behind a post; joriki's action fulfilled that purpose faithfully. It's always the OP's responsibility to craft & improve any post - if he/she leaves it to the comment section they disservice readers. Taking the time to explain these things to newcomers is a separate affair. That said, I truly do understand the aggravation of lonely, grueling calculations - we've all been there. Live and learn bro. –  anon Jul 24 '11 at 10:27

Read up on vectors if you are not already into the subject.

Translation from coordinates to unit vectors (vectors of length 1), where the origin is centre of the Earth, X-axis points to N0,E0, Y-axis points to N0,E90 and Z-axis points to the North pole:

posX=cos(lon)*cos(lat)
posY=sin(lon)*cos(lat)
posZ=sin(lat)

faceNorthX=-cos(lon)*sin(lat)
faceNorthY=-sin(lon)*sin(lat)
faceNorthZ=cos(lat)

faceEastX=-sin(lon)
faceEastY=cos(lon)
faceEastZ=0

faceDir=faceNorth*cos(dir)+faceEast*sin(dir)


Now if

dotProduct(faceDir1,pos2-pos1)


is positive, then you are according to your definition facing pos2 from pos1.

More general

dotProduct(vector1,vector2) / (length(vector1) * length(vector1))


is cosine of the angle between the vectors.

This is useful for calculating the surface distance between two points, since the vectors generated so far are all unit vectors the expression can be simplified a bit for this use.

surfaceDistance=Earth.radius*arccos(dotProduct(pos1,pos2))


The direct distance is simply

directDistance=Earth.radius*length(pos2-pos1)

-

Ok folks, this is what I could come up with in 4 hours LOL. Could any of you please check that this is correct? Probably I'll write a bunch of unit tests anyway, but I'm so confused...

public class GpsPosition {

private double              mLatitude;
private double              mLongitude;
private double              mDirection;

public boolean isInViewport(GpsPosition otherPos) {
double otherDir = directionTowards(otherPos);
double range = VIEWPORT_DEGREE / 2;
double minRange = mDirection - range;
double maxRange = mDirection + range;

if (minRange < 0) {
minRange = 360 + minRange;
if (otherDir >= minRange) {
return true;
} else if (otherDir <= maxRange) {
return true;
} else {
return false;
}
} else if (maxRange > 360) {
maxRange = maxRange - 360;
if (otherDir <= maxRange) {
return true;
} else if (otherDir >= minRange) {
return true;
} else {
return false;
}
} else if (minRange >= 0 && maxRange <= 360) {
if (otherDir <= maxRange && otherDir >= minRange) {
return true;
} else {
return false;
}
} else {
throw new AssertionError("I'm sorry, Dave, I'm afraid I can't do that.");
}

}

double directionTowards(GpsPosition otherPos) {
GpsPosition northPole = new GpsPosition(90,0,0);
double a = distanceTo(otherPos);
double b = distanceTo(northPole);
double c = otherPos.distanceTo(northPole);

//Laws of cosines
double gamma = Math.acos((a*a + b*b - c*c)/(2*a*b));

boolean negative = (otherPos.mLongitude - mLongitude) < 0;//potential bug at 180° longitude, ignore for now
if (negative) {
gamma = 360 - gamma;
}
return gamma;

}

double distanceTo(GpsPosition otherPos) {

double R = EARTH_PERIMETER; //6371.0 km
double lat1 = mLatitude;
double lon1 = mLongitude;
double lat2 = otherPos.mLatitude;
double lon2 = otherPos.mLongitude;