osgEarth 2.1.1
|
Functions | |
bool | latLonToFaceCoords (double lat_deg, double lon_deg, double &out_x, double &out_y, int &out_face, int faceHint=-1) |
bool | faceCoordsToLatLon (double x, double y, int face, double &out_lat_deg, double &out_lon_deg) |
bool | cubeToFace (double &in_out_x, double &in_out_y, int &out_face) |
bool | cubeToFace (double &in_out_xmin, double &in_out_ymin, double &in_out_xmax, double &in_out_ymax, int &out_face) |
bool | faceToCube (double &in_out_x, double &in_out_y, int face) |
osg::Vec3d | face2dc (int face, const osg::Vec2d &faceCoord) |
double | arcLength (const osg::Vec2d &coord1, const osg::Vec2d &coord2, int face) |
double | distanceToSegment (const osg::Vec3d &p, const osg::Vec2d &coord1, const osg::Vec2d &coord2, int face) |
double | distanceToSegment (const osg::Vec3d &p, const osg::Vec3d &coord1, const osg::Vec3d &coord2) |
bool | lineLineIntersect (const Vec3d &p1, const Vec3d &p2, const Vec3d &p3, const Vec3d &p4, Vec3d &pa, Vec3d &pb, double &mua, double &mub) |
Vec3d | latLon2xyz (double lat_deg, double lon_deg) |
int | getFace (const Vec3d &vec) |
Vec3d | xyz2qrs (const Vec3d &xyz, int face) |
Vec3d | face2qrs (const Vec2d &face) |
Vec3d | qrs2xyz (const Vec3d &local, int face) |
Vec3d | face2dc (int faceNum, const Vec2d &faceCoord) |
double | arcLength (const Vec2d &coord1, const Vec2d &coord2, int face) |
static osg::Vec3d | closestPointOnLine (const osg::Vec3d &p1, const osg::Vec3d &p2, const osg::Vec3d &p3) |
double | distanceToLine (const Vec3d &p1, const Vec3d &p2, const Vec3d &p3) |
double | distanceToSegment (const Vec3d &p, const Vec3d &geo1, const Vec3d &geo2, const Vec3d &norm) |
Vec3d | getNormalToSegment (const Vec2d &coord1, const Vec2d &coord2, int face) |
double | distanceToSegment (const Vec3d &p, const Vec2d &coord1, const Vec2d &coord2, int face) |
The Euler cube
The faces of a cube are projected onto the spherical globe. Within a cube face, the coordinates are specified as as angles from the fixed axes parallel to the cube face. For example, the x coordinate of equatorial faces is equivalent to longitude. The y coordinate is not latitude, because it is not measured in the longitudinal plane. The major effect of this is that the grid lines on the cube faces are great circles.
The cube is layed out like a flattened cut-out. the x,y coordinates range from (0,0) to (4, 3). In the equatorial region, x is 0-4 and y is 1-2. North Pole is (0, 2) ->(1,3); South Pole is (0,0)->(1,1).
Face 0 is centered on lat lon (0, 0). Faces 1-3 are the equatorial faces to the East. 4 is the North Pole, 5 is the South.
Within each face, the conversion formulas assume that coordinate values range from -1 to 1.
double seamless::euler::arcLength | ( | const osg::Vec2d & | coord1, |
const osg::Vec2d & | coord2, | ||
int | face | ||
) |
Length of great circle arc between face coordinates. This will be the length of a grid edge if the points share a coordinate.
double seamless::euler::arcLength | ( | const Vec2d & | coord1, |
const Vec2d & | coord2, | ||
int | face | ||
) |
Definition at line 336 of file Euler.cpp.
{ if (coord1.x() != coord2.x() && coord1.y() != coord2.y()) { Vec3d geo1 = face2dc(face, coord1); Vec3d geo2 = face2dc(face, coord2); Vec3d norm = geo1 ^ geo2; return atan2(norm.length(), geo1 * geo2) * WGS_84_RADIUS_EQUATOR; } double x1, y1, x2, y2; if (coord1.x() == coord2.x()) { x1 = coord1.x() * PI_4; y1 = coord1.y() * PI_4; x2 = coord2.x() * PI_4; y2 = coord2.y() * PI_4; } else { x1 = coord1.y() * PI_4; y1 = coord1.x() * PI_4; x2 = coord2.y() * PI_4; y2 = coord2.x() * PI_4; } double tanPhi1 = cos(x1) * tan(y1); double tanPhi2 = cos(x2) * tan(y2); // tan(phi2 - phi1) = (tan(phi2) - tan(hi1)) / (1 + tan(phi2) * tan(phi1)) return fabs(atan2(tanPhi2 - tanPhi1, 1 + tanPhi2 * tanPhi1)) * WGS_84_RADIUS_EQUATOR; }
static osg::Vec3d seamless::euler::closestPointOnLine | ( | const osg::Vec3d & | p1, |
const osg::Vec3d & | p2, | ||
const osg::Vec3d & | p3 | ||
) | [static] |
bool seamless::euler::cubeToFace | ( | double & | in_out_xmin, |
double & | in_out_ymin, | ||
double & | in_out_xmax, | ||
double & | in_out_ymax, | ||
int & | out_face | ||
) |
Converts cube coordinates (0,0=>4,3) to face coordinates (-1,-1=>1,1,F). This version takes an extent, which is better than the non-extent version since it can resolve face-border ambiguity.
Definition at line 266 of file Euler.cpp.
{ double xmin, xmax, ymin, ymax; if (in_out_ymin > 1.0 - 1e-11 && in_out_ymax < 2.0 + 1e-11) { double faceMin = floor(in_out_xmin + 1e-11); double faceMax = floor(in_out_xmax - 1e-11); if (faceMin != faceMax) { OE_WARN << LC << "Min face <> Max face!\n"; return false; } xmin = in_out_xmin - faceMin; xmax = in_out_xmax - faceMin; ymin = in_out_ymin - 1.0; ymax = in_out_ymax - 1.0; out_face = static_cast<int>(faceMin); } else if (in_out_ymin > 2.0 - 1e-11 && in_out_ymax > 2.0 + 1e-11) { out_face = 4; ymin = in_out_ymin - 2.0; ymax = in_out_ymax - 2.0; xmin = in_out_xmin; xmax = in_out_xmax; } else if (in_out_ymax < 1.0 + 1e-11) { out_face = 5; ymin = in_out_ymin; ymax = in_out_ymax; xmin = in_out_xmin; xmax = in_out_xmax; } else { OE_WARN << LC << "can't determine face for (" << in_out_xmin << ", " << in_out_ymin << "), (" << in_out_xmax << ", " << in_out_ymax << ")\n"; return false; } in_out_xmin = xmin * 2.0 - 1.0; in_out_xmax = xmax * 2.0 - 1.0; in_out_ymin = ymin * 2.0 - 1.0; in_out_ymax = ymax * 2.0 - 1.0; return true; }
bool seamless::euler::cubeToFace | ( | double & | in_out_x, |
double & | in_out_y, | ||
int & | out_face | ||
) |
Converts cube coordinates (0,0=>4,3) to face coordinates (-1,-1=>1,1,F). WARNING. If the cube coordinate lies on a face boundary, this method will always return the lower-numbered face. The "extent" version of this method (below) is better b/c it's unambiguous.
Definition at line 227 of file Euler.cpp.
{ double x, y; if (in_out_x > 1.0 + 1e-11) { double face = floor(in_out_x); x = in_out_x - face; if (x < 1e-11) { face += -1.0; x += 1.0; } y = in_out_y - 1.0; out_face = static_cast<int>(face); } else { if (in_out_y > 2.0 + 1e-11) { out_face = 4; y = in_out_y - 2.0; } else if (in_out_y < 1.0 + 1e-11) { out_face = 5; y = in_out_y; } else { out_face = 0; y = in_out_y - 1.0; } x = in_out_x; } in_out_x = x * 2.0 - 1.0; in_out_y = y * 2.0 - 1.0; return true; }
double seamless::euler::distanceToLine | ( | const Vec3d & | p1, |
const Vec3d & | p2, | ||
const Vec3d & | p3 | ||
) |
Definition at line 383 of file Euler.cpp.
{ Vec3d pt = closestPointOnLine(p1, p2, p3); return (p3 - pt).length(); }
double seamless::euler::distanceToSegment | ( | const osg::Vec3d & | p, |
const osg::Vec2d & | coord1, | ||
const osg::Vec2d & | coord2, | ||
int | face | ||
) |
Distance between a point and an arc on a face.
p | the point, for example the eyepoint. |
coord1 | beginning of segment in face coordinates |
coord2 | end of segment in face coordinates |
face | cube face. coord1 and coord2 lie on the same face. |
double seamless::euler::distanceToSegment | ( | const osg::Vec3d & | p, |
const osg::Vec3d & | coord1, | ||
const osg::Vec3d & | coord2 | ||
) |
Distance between a point and an arc on the spherical earth.
p | the point, for example the eyepoint. |
coord1 | beginning of the arc as a direction cosine. |
coord2 | end of the arc as a direction cosine. |
double seamless::euler::distanceToSegment | ( | const Vec3d & | p, |
const Vec3d & | geo1, | ||
const Vec3d & | geo2, | ||
const Vec3d & | norm | ||
) |
Definition at line 389 of file Euler.cpp.
{ // Find the distance to the closet point on the circle that // contains the segment. If that point lies on the segment, that's // the shortest distance; otherwise, the distance to one of the // end points is the shortest. // Project p into plane of circle Vec3d q = p - norm * (norm * p); // If q = (0, 0, 0) -- the center of the circle -- then all points // on the circle are equidistant. // qnorm will be on unit circle const double r = WGS_84_RADIUS_EQUATOR; if (equivalent(q.length2(), 0)) { return sqrt(r * r + p.length2()); } Vec3d qnorm = q / q.length(); // Vec3d x = q * r / q.length(); const Vec3d zero; Vec3d end1, end2; double mua, mub; if (lineLineIntersect(zero, qnorm, geo1, geo2, end1, end2, mua, mub) && mub >= 0.0 && mub <= 1.0) { return (p - qnorm * r).length(); } else { return minimum((p - geo1 * r).length(), (p - geo2 * r).length()); } }
double seamless::euler::distanceToSegment | ( | const Vec3d & | p, |
const Vec2d & | coord1, | ||
const Vec2d & | coord2, | ||
int | face | ||
) |
Definition at line 445 of file Euler.cpp.
{ Vec3d norm = getNormalToSegment(coord1, coord2, face); Vec3d geo1 = face2dc(face, coord1); Vec3d geo2 = face2dc(face, coord2); return distanceToSegment(p, geo1, geo2, norm); }
Vec3d seamless::euler::face2dc | ( | int | faceNum, |
const Vec2d & | faceCoord | ||
) |
osg::Vec3d seamless::euler::face2dc | ( | int | face, |
const osg::Vec2d & | faceCoord | ||
) |
Calculate the direction cosine representation (unit vector from the origin) of a face coordinate's geographic location.
Vec3d seamless::euler::face2qrs | ( | const Vec2d & | face | ) |
Definition at line 145 of file Euler.cpp.
{ double xang = face[0] * osg::PI_4; double yang = face[1] * osg::PI_4; double sx = sin(xang), cx = cos(xang); double ty = tan(yang); // phi is a latitude measure, in the longitudinal plane double tanPhi = cx * ty; double radical = sqrt(1 + tanPhi * tanPhi); double c = 1.0 / radical; Vec3d result; double b = tanPhi * c; // b gets the right sign result.x() = c * sx; result.y() = b; result.z() = c * cx; return result; }
bool seamless::euler::faceCoordsToLatLon | ( | double | x, |
double | y, | ||
int | face, | ||
double & | out_lat_deg, | ||
double & | out_lon_deg | ||
) |
Converts face coordinates into lat/long.
Definition at line 196 of file Euler.cpp.
{ double lat, lon; const double l = x * osg::PI_4; const double ty = tan(y * osg::PI_4); if (face < 4) { lon = face * osg::PI_2 + l; lon = fmod(lon + osg::PI, 2.0 * osg::PI) - osg::PI; lat = atan(cos(l) * ty); } else { const double tx = tan(x * osg::PI_4); lat = osg::PI_2 - atan(sqrt(tx * tx + ty * ty)); if (face == 5) { lon = atan2(tx, ty); lat = -lat; } else { lon = atan2(tx, -ty); } } out_lon_deg = RadiansToDegrees(lon); out_lat_deg = RadiansToDegrees(lat); return true; }
bool seamless::euler::faceToCube | ( | double & | in_out_x, |
double & | in_out_y, | ||
int | face | ||
) |
Converts face coordinates (-1,-1=>1,1 +F) to cube coordinates (0,0=>4,3).
Definition at line 316 of file Euler.cpp.
{ double x = (in_out_x + 1.0) * .5; double y = (in_out_y + 1.0) * .5; if (face < 4) { in_out_x = x + face; in_out_y = y + 1.0; } else { in_out_x = x; if (face == 4) in_out_y = y + 2.0; else in_out_y = y; } return true; }
int seamless::euler::getFace | ( | const Vec3d & | vec | ) | [inline] |
Definition at line 68 of file Euler.cpp.
{ double absx = fabs(vec.x()); double absy = fabs(vec.y()); double absz = fabs(vec.z()); // pole faces if (absz > (absx + 1e-11) && absz > (absy + 1e-11)) { if (vec.z() > 0.0) return 4; else return 5; } // One of the X faces, unless on a border else if (absx > absy || equivalent(absx, absy, 1e-11)) { if (vec.x() > 0.0) return 0; else if (equivalent(vec.x(), -vec.y(), 1e-11)) return 1; // Boundary between 1 and 2 else return 2; } // One of the Y faces else { if (vec.y() > 0.0) return 1; else return 3; } }
Vec3d seamless::euler::getNormalToSegment | ( | const Vec2d & | coord1, |
const Vec2d & | coord2, | ||
int | face | ||
) |
Definition at line 427 of file Euler.cpp.
{ if (coord1.x() == coord2.x()) { double xang = coord1.x() * PI_4; double sx = sin(xang), cx = cos(xang); Vec3d qrsNormal(cx, 0.0, -sx); return qrs2xyz(qrsNormal, face); } else { double yang = coord1.y() * PI_4; double sy = sin(yang), cy = cos(yang); Vec3d qrsNormal(0.0, cy, -sy); return qrs2xyz(qrsNormal, face); } }
Vec3d seamless::euler::latLon2xyz | ( | double | lat_deg, |
double | lon_deg | ||
) | [inline] |
Definition at line 56 of file Euler.cpp.
{ Vec3d result; result.z() = sin(DegreesToRadians(lat_deg)); double hyp = sqrt(1 - result.z() * result.z()); double long_rad = DegreesToRadians(lon_deg); result.x() = hyp * cos(long_rad); result.y() = hyp * sin(long_rad); return result; }
bool seamless::euler::latLonToFaceCoords | ( | double | lat_deg, |
double | lon_deg, | ||
double & | out_x, | ||
double & | out_y, | ||
int & | out_face, | ||
int | faceHint = -1 |
||
) |
Definition at line 127 of file Euler.cpp.
{ if (lat_deg > 90.0 || lat_deg < -90.0 || lon_deg < -180.0 || lon_deg > 180.0) return false; Vec3d xyz = latLon2xyz(lat_deg, lon_deg); out_face = faceHint >= 0 ? faceHint : getFace(xyz); Vec3d qrs = xyz2qrs(xyz, out_face); double xang = atan2(qrs[0], qrs[2]); double yang = atan2(qrs[1], qrs[2]); out_x = xang / osg::PI_4; out_y = yang / osg::PI_4; return true; }
bool seamless::euler::lineLineIntersect | ( | const Vec3d & | p1, |
const Vec3d & | p2, | ||
const Vec3d & | p3, | ||
const Vec3d & | p4, | ||
Vec3d & | pa, | ||
Vec3d & | pb, | ||
double & | mua, | ||
double & | mub | ||
) |
Definition at line 463 of file Euler.cpp.
{ Vec3d p13, p43, p21; double d1343, d4321, d1321, d4343, d2121; double numer, denom; p13 = p1 - p3; p43 = p4 - p3; if (equivalent(p43.length2(), 0.0, 1e-11)) return false; p21 = p2 - p1; if (equivalent(p21.length2(), 0.0, 1e-11)) return false; d1343 = p13.x() * p43.x() + p13.y() * p43.y() + p13.z() * p43.z(); d4321 = p43.x() * p21.x() + p43.y() * p21.y() + p43.z() * p21.z(); d1321 = p13.x() * p21.x() + p13.y() * p21.y() + p13.z() * p21.z(); d4343 = p43.x() * p43.x() + p43.y() * p43.y() + p43.z() * p43.z(); d2121 = p21.x() * p21.x() + p21.y() * p21.y() + p21.z() * p21.z(); denom = d2121 * d4343 - d4321 * d4321; if (equivalent(denom, 0.0, 1e-11)) return false; numer = d1343 * d4321 - d1321 * d4343; mua = numer / denom; mub = (d1343 + d4321 * (mua)) / d4343; pa = p1 + p21 * mua; pb = p3 + p43 * mub; return true; }
Vec3d seamless::euler::qrs2xyz | ( | const Vec3d & | local, |
int | face | ||
) |
Definition at line 163 of file Euler.cpp.
{ switch (face) { case 0: return Vec3d(local.z(), local.x(), local.y()); break; case 1: return Vec3d(-local.x(), local.z(), local.y()); break; case 2: return Vec3d(-local.z(), -local.x(), local.y()); case 3: return Vec3d(local.x(), -local.z(), local.y()); case 4: return Vec3d(-local.y(),local.x(), local.z()); case 5: return Vec3d(local.y(), local.x(), -local.z()); default: return Vec3d(0,0,0); } }
Vec3d seamless::euler::xyz2qrs | ( | const Vec3d & | xyz, |
int | face | ||
) |
Definition at line 106 of file Euler.cpp.
{ switch (face) { case 0: return Vec3d(xyz.y(), xyz.z(), xyz.x()); case 1: return Vec3d(-xyz.x(), xyz.z(), xyz.y()); case 2: return Vec3d(-xyz.y(), xyz.z(), -xyz.x()); case 3: return Vec3d(xyz.x(), xyz.z(), -xyz.y()); case 4: return Vec3d(xyz.y(), -xyz.x(), xyz.z()); case 5: return Vec3d(xyz.y(), xyz.x(), -xyz.z()); default: return Vec3d(0, 0, 0); } }