22double d2r(
double degrees)
 
   24    return 2 * M_PI * degrees / 360.0;
 
   27double r2d(
double radians)
 
   29    return 360.0 * radians / (2 * M_PI);
 
   32V3 V3::normal(
const V3 &v1, 
const V3 &v2, 
const V3 &v3)
 
   35    const V3 d21 = V3(v2.x() - v1.x(), v2.y() - v1.y(), v2.z() - v1.z());
 
   36    const V3 d32 = V3(v3.x() - v2.x(), v3.y() - v2.y(), v3.z() - v2.z());
 
   38    const V3 cross = V3(d21.y() * d32.z() - d21.z() * d32.y(),
 
   39                        d21.z() * d32.x() - d21.x() * d32.z(),
 
   40                        d21.x() * d32.y() - d21.y() * d32.x());
 
   42    const double lenSq = cross.x() * cross.x() + cross.y() * cross.y() + cross.z() * cross.z();
 
   43    if (lenSq == 0.0) 
return V3();
 
   44    const double len = sqrt(lenSq);
 
   46    return V3(cross.x() / len, cross.y() / len, cross.z() / len);
 
   51    return sqrt(X * X + Y * Y + Z * Z);
 
   54V3 azAlt2xyz(
const QPointF &azAlt)
 
   58    const double azRadians = d2r(azAlt.
x());
 
   59    const double altRadians = d2r(azAlt.
y());
 
   61    const double theta = -azRadians;
 
   62    const double phi = (M_PI / 2.0) - altRadians;
 
   63    const double x = cos(theta) * sin(phi);
 
   64    const double y = sin(theta) * sin (phi);
 
   65    const double z = cos(phi);
 
   70QPointF xyz2azAlt(
const V3 &xyz)
 
   73    if (xyz.y() == 0.0 && xyz.x() == 0.0)
 
   76        return QPointF(0.0, 90.0);
 
   79    const double azRadians = (xyz.y() == 0) ? 0.0 : -atan2(xyz.y(), xyz.x());
 
   80    const double altRadians = (M_PI / 2.0) - acos(xyz.z());
 
   82    return QPointF(r2d(azRadians), r2d(altRadians));
 
   85V3 haDec2xyz(
const QPointF &haDec, 
double latitude)
 
   87    const double haRadians = d2r(haDec.
x());
 
   89    const double decRadians = d2r(haDec.
y() - 90);
 
   91    const double x = cos(decRadians);
 
   92    const double y = sin(haRadians) * sin(decRadians);
 
   93    const double z = cos(haRadians) * sin(decRadians);
 
   94    return rotateAroundY(V3(x, y, z), -fabs(latitude));
 
   97QPointF xyz2haDec(
const V3 &xyz, 
double latitude)
 
  100    const V3 pt = rotateAroundY(xyz, latitude);
 
  101    const double ha = r2d(atan2(pt.y(), pt.z()));
 
  103    V3 pole = Rotations::azAlt2xyz(QPointF(0, fabs(latitude)));
 
  104    const double dec = 90 - getAngle(xyz, pole);
 
  105    return QPointF(ha, dec);
 
  108V3 getAxis(
const V3 &p1, 
const V3 &p2, 
const V3 &p3)
 
  110    return V3::normal(p1, p2, p3);
 
  115double getAngle(
const V3 &p1, 
const V3 &p2)
 
  117    QPointF a1 = xyz2azAlt(p1);
 
  118    QPointF a2 = xyz2azAlt(p2);
 
  119    return r2d(acos(sin(d2r(a1.
y())) * sin(d2r(a2.
y())) +
 
  120                    cos(d2r(a1.
y())) * cos(d2r(a2.
y())) * cos(d2r(a1.
x()) - d2r(a2.
x()))));
 
  126V3 rotateAroundAxis(
const V3 &point, 
const V3 &axis, 
double degrees)
 
  128    const double cosAngle = cos(d2r(degrees));
 
  129    const double sinAngle = sin(d2r(degrees));
 
  130    const double pointDotAxis = (point.x() * axis.x() + point.y() * axis.y() + point.z() * axis.z());
 
  131    const double x = axis.x() * pointDotAxis * (1.0 - cosAngle) + point.x() * cosAngle + (-axis.z() * point.y() + axis.y() *
 
  132                     point.z()) * sinAngle;
 
  133    const double y = axis.y() * pointDotAxis * (1.0 - cosAngle) + point.y() * cosAngle + (axis.z() * point.x() + -axis.x() *
 
  134                     point.z()) * sinAngle;
 
  135    const double z = axis.z() * pointDotAxis * (1.0 - cosAngle) + point.z() * cosAngle + (-axis.y() * point.x() + axis.x() *
 
  136                     point.y()) * sinAngle;
 
  146V3 rotateAroundY(
const V3 &point, 
double degrees)
 
  148    const double radians = d2r(degrees);
 
  149    const double cosAngle = cos(radians);
 
  150    const double sinAngle = sin(radians);
 
  151    return V3( point.x() * cosAngle + point.z() * sinAngle,
 
  153               -point.x() * sinAngle + point.z() * cosAngle);
 
  156V3 rotateAroundZ(
const V3 &point, 
double degrees)
 
  158    const double radians = d2r(degrees);
 
  159    const double cosAngle = cos(radians);
 
  160    const double sinAngle = sin(radians);
 
  161    return V3( point.x() * cosAngle - point.y() * sinAngle,
 
  162               point.x() * sinAngle + point.y() * cosAngle,
 
  169QPointF rotateRaAxis(
const QPointF &azAltPoint, 
const QPointF &azAltRotation)
 
  171    const V3 point = azAlt2xyz(azAltPoint);
 
  172    const V3 altRotatedPoint = rotateAroundY(point, -azAltRotation.
y());
 
  175    const QPointF altAz = xyz2azAlt(altRotatedPoint);
 
  176    return QPointF(altAz.
x() + azAltRotation.
x(), altAz.
y());
 
QTextStream & dec(QTextStream &stream)