1 """Define the :class:`~geographiclib.geodesicline.GeodesicLine` class 
    3 The constructor defines the starting point of the line.  Points on the 
    6   * :meth:`~geographiclib.geodesicline.GeodesicLine.Position` position 
    7     given in terms of distance 
    8   * :meth:`~geographiclib.geodesicline.GeodesicLine.ArcPosition` position 
    9     given in terms of spherical arc length 
   11 A reference point 3 can be defined with 
   13   * :meth:`~geographiclib.geodesicline.GeodesicLine.SetDistance` set 
   14     position of 3 in terms of the distance from the starting point 
   15   * :meth:`~geographiclib.geodesicline.GeodesicLine.SetArc` set 
   16     position of 3 in terms of the spherical arc length from the starting point 
   18 The object can also be constructed by 
   20   * :meth:`Geodesic.Line <geographiclib.geodesic.Geodesic.Line>` 
   21   * :meth:`Geodesic.DirectLine <geographiclib.geodesic.Geodesic.DirectLine>` 
   22   * :meth:`Geodesic.ArcDirectLine 
   23     <geographiclib.geodesic.Geodesic.ArcDirectLine>` 
   24   * :meth:`Geodesic.InverseLine <geographiclib.geodesic.Geodesic.InverseLine>` 
   26 The public attributes for this class are 
   28   * :attr:`~geographiclib.geodesicline.GeodesicLine.a` 
   29     :attr:`~geographiclib.geodesicline.GeodesicLine.f` 
   30     :attr:`~geographiclib.geodesicline.GeodesicLine.caps` 
   31     :attr:`~geographiclib.geodesicline.GeodesicLine.lat1` 
   32     :attr:`~geographiclib.geodesicline.GeodesicLine.lon1` 
   33     :attr:`~geographiclib.geodesicline.GeodesicLine.azi1` 
   34     :attr:`~geographiclib.geodesicline.GeodesicLine.salp1` 
   35     :attr:`~geographiclib.geodesicline.GeodesicLine.calp1` 
   36     :attr:`~geographiclib.geodesicline.GeodesicLine.s13` 
   37     :attr:`~geographiclib.geodesicline.GeodesicLine.a13` 
   64   """Points on a geodesic path""" 
   67                caps = GeodesicCapability.STANDARD |
 
   68                GeodesicCapability.DISTANCE_IN,
 
   69                salp1 = Math.nan, calp1 = Math.nan):
 
   70     """Construct a GeodesicLine object 
   72     :param geod: a :class:`~geographiclib.geodesic.Geodesic` object 
   73     :param lat1: latitude of the first point in degrees 
   74     :param lon1: longitude of the first point in degrees 
   75     :param azi1: azimuth at the first point in degrees 
   76     :param caps: the :ref:`capabilities <outmask>` 
   78     This creates an object allowing points along a geodesic starting at 
   79     (*lat1*, *lon1*), with azimuth *azi1* to be found.  The default 
   80     value of *caps* is STANDARD | DISTANCE_IN.  The optional parameters 
   81     *salp1* and *calp1* should not be supplied; they are part of the 
   88     """The equatorial radius in meters (readonly)""" 
   90     """The flattening (readonly)""" 
   94     self.
caps = (caps | Geodesic.LATITUDE | Geodesic.AZIMUTH |
 
   96     """the capabilities (readonly)""" 
   99     self.
lat1 = Math.LatFix(lat1)
 
  100     """the latitude of the first point in degrees (readonly)""" 
  102     """the longitude of the first point in degrees (readonly)""" 
  103     if Math.isnan(salp1) 
or Math.isnan(calp1):
 
  104       self.
azi1 = Math.AngNormalize(azi1)
 
  105       self.
salp1, self.
calp1 = Math.sincosd(Math.AngRound(azi1))
 
  108       """the azimuth at the first point in degrees (readonly)""" 
  110       """the sine of the azimuth at the first point (readonly)""" 
  112       """the cosine of the azimuth at the first point (readonly)""" 
  115     sbet1, cbet1 = Math.sincosd(Math.AngRound(lat1)); sbet1 *= self.
_f1 
  117     sbet1, cbet1 = Math.norm(sbet1, cbet1); cbet1 = 
max(Geodesic.tiny_, cbet1)
 
  118     self.
_dn1 = math.sqrt(1 + geod._ep2 * Math.sq(sbet1))
 
  136                                  if sbet1 != 0 
or self.
calp1 != 0 
else 1)
 
  142     self.
_k2 = Math.sq(self.
_calp0) * geod._ep2
 
  143     eps = self.
_k2 / (2 * (1 + math.sqrt(1 + self.
_k2)) + self.
_k2)
 
  145     if self.
caps & Geodesic.CAP_C1:
 
  148       Geodesic._C1f(eps, self.
_C1a)
 
  149       self.
_B11 = Geodesic._SinCosSeries(
 
  158     if self.
caps & Geodesic.CAP_C1p:
 
  162     if self.
caps & Geodesic.CAP_C2:
 
  165       Geodesic._C2f(eps, self.
_C2a)
 
  166       self.
_B21 = Geodesic._SinCosSeries(
 
  169     if self.
caps & Geodesic.CAP_C3:
 
  171       geod._C3f(eps, self.
_C3a)
 
  173       self.
_B31 = Geodesic._SinCosSeries(
 
  176     if self.
caps & Geodesic.CAP_C4:
 
  181       self.
_B41 = Geodesic._SinCosSeries(
 
  184     """the distance between point 1 and point 3 in meters (readonly)""" 
  186     """the arc length between point 1 and point 3 in degrees (readonly)""" 
  190     """Private: General solution of position along geodesic""" 
  192     a12 = lat2 = lon2 = azi2 = s12 = m12 = M12 = M21 = S12 = Math.nan
 
  193     outmask &= self.
caps & Geodesic.OUT_MASK
 
  195             (self.
caps & (Geodesic.OUT_MASK & Geodesic.DISTANCE_IN))):
 
  197       return a12, lat2, lon2, azi2, s12, m12, M12, M21, S12
 
  203       sig12 = math.radians(s12_a12)
 
  204       ssig12, csig12 = Math.sincosd(s12_a12)
 
  207       tau12 = s12_a12 / (self.
_b * (1 + self.
_A1m1))
 
  208       s = math.sin(tau12); c = math.cos(tau12)
 
  210       B12 = - Geodesic._SinCosSeries(
True,
 
  214       sig12 = tau12 - (B12 - self.
_B11)
 
  215       ssig12 = math.sin(sig12); csig12 = math.cos(sig12)
 
  216       if abs(self.
f) > 0.01:
 
  240         B12 = Geodesic._SinCosSeries(
True, ssig2, csig2, self.
_C1a)
 
  241         serr = ((1 + self.
_A1m1) * (sig12 + (B12 - self.
_B11)) -
 
  243         sig12 = sig12 - serr / math.sqrt(1 + self.
_k2 * Math.sq(ssig2))
 
  244         ssig12 = math.sin(sig12); csig12 = math.cos(sig12)
 
  252     dn2 = math.sqrt(1 + self.
_k2 * Math.sq(ssig2))
 
  254       Geodesic.DISTANCE | Geodesic.REDUCEDLENGTH | Geodesic.GEODESICSCALE):
 
  255       if arcmode 
or abs(self.
f) > 0.01:
 
  256         B12 = Geodesic._SinCosSeries(
True, ssig2, csig2, self.
_C1a)
 
  257       AB1 = (1 + self.
_A1m1) * (B12 - self.
_B11)
 
  259     sbet2 = self.
_calp0 * ssig2
 
  264       cbet2 = csig2 = Geodesic.tiny_
 
  268     if outmask & Geodesic.DISTANCE:
 
  269       s12 = self.
_b * ((1 + self.
_A1m1) * sig12 + AB1) 
if arcmode 
else s12_a12
 
  271     if outmask & Geodesic.LONGITUDE:
 
  273       somg2 = self.
_salp0 * ssig2; comg2 = csig2 
 
  274       E = Math.copysign(1, self.
_salp0)          
 
  277                     - (math.atan2(          ssig2,       csig2) -
 
  279                     + (math.atan2(E *       somg2,       comg2) -
 
  281                if outmask & Geodesic.LONG_UNROLL
 
  282                else math.atan2(somg2 * self.
_comg1 - comg2 * self.
_somg1,
 
  284       lam12 = omg12 + self.
_A3c * (
 
  285         sig12 + (Geodesic._SinCosSeries(
True, ssig2, csig2, self.
_C3a)
 
  287       lon12 = math.degrees(lam12)
 
  288       lon2 = (self.
lon1 + lon12 
if outmask & Geodesic.LONG_UNROLL 
else 
  289               Math.AngNormalize(Math.AngNormalize(self.
lon1) +
 
  290                                 Math.AngNormalize(lon12)))
 
  292     if outmask & Geodesic.LATITUDE:
 
  293       lat2 = Math.atan2d(sbet2, self.
_f1 * cbet2)
 
  295     if outmask & Geodesic.AZIMUTH:
 
  296       azi2 = Math.atan2d(salp2, calp2)
 
  298     if outmask & (Geodesic.REDUCEDLENGTH | Geodesic.GEODESICSCALE):
 
  299       B22 = Geodesic._SinCosSeries(
True, ssig2, csig2, self.
_C2a)
 
  300       AB2 = (1 + self.
_A2m1) * (B22 - self.
_B21)
 
  301       J12 = (self.
_A1m1 - self.
_A2m1) * sig12 + (AB1 - AB2)
 
  302       if outmask & Geodesic.REDUCEDLENGTH:
 
  305         m12 = self.
_b * ((      dn2 * (self.
_csig1 * ssig2) -
 
  307                          - self.
_csig1 * csig2 * J12)
 
  308       if outmask & Geodesic.GEODESICSCALE:
 
  311         M12 = csig12 + (t * ssig2 - csig2 * J12) * self.
_ssig1 / self.
_dn1 
  312         M21 = csig12 - (t * self.
_ssig1 - self.
_csig1 * J12) * ssig2 / dn2
 
  314     if outmask & Geodesic.AREA:
 
  315       B42 = Geodesic._SinCosSeries(
False, ssig2, csig2, self.
_C4a)
 
  319         salp12 = salp2 * self.
calp1 - calp2 * self.
salp1 
  320         calp12 = calp2 * self.
calp1 + salp2 * self.
salp1 
  331           self.
_csig1 * (1 - csig12) + ssig12 * self.
_ssig1 if csig12 <= 0
 
  332           else ssig12 * (self.
_csig1 * ssig12 / (1 + csig12) + self.
_ssig1))
 
  333         calp12 = (Math.sq(self.
_salp0) +
 
  335       S12 = (self.
_c2 * math.atan2(salp12, calp12) +
 
  338     a12 = s12_a12 
if arcmode 
else math.degrees(sig12)
 
  339     return a12, lat2, lon2, azi2, s12, m12, M12, M21, S12
 
  341   def Position(self, s12, outmask = GeodesicCapability.STANDARD):
 
  342     """Find the position on the line given *s12* 
  344     :param s12: the distance from the first point to the second in 
  346     :param outmask: the :ref:`output mask <outmask>` 
  347     :return: a :ref:`dict` 
  349     The default value of *outmask* is STANDARD, i.e., the *lat1*, 
  350     *lon1*, *azi1*, *lat2*, *lon2*, *azi2*, *s12*, *a12* entries are 
  351     returned.  The :class:`~geographiclib.geodesicline.GeodesicLine` 
  352     object must have been constructed with the DISTANCE_IN capability. 
  357     result = {
'lat1': self.
lat1,
 
  358               'lon1': self.
lon1 if outmask & Geodesic.LONG_UNROLL 
else 
  359               Math.AngNormalize(self.
lon1),
 
  360               'azi1': self.
azi1, 
's12': s12}
 
  361     a12, lat2, lon2, azi2, s12, m12, M12, M21, S12 = self.
_GenPosition(
 
  363     outmask &= Geodesic.OUT_MASK
 
  365     if outmask & Geodesic.LATITUDE: result[
'lat2'] = lat2
 
  366     if outmask & Geodesic.LONGITUDE: result[
'lon2'] = lon2
 
  367     if outmask & Geodesic.AZIMUTH: result[
'azi2'] = azi2
 
  368     if outmask & Geodesic.REDUCEDLENGTH: result[
'm12'] = m12
 
  369     if outmask & Geodesic.GEODESICSCALE:
 
  370       result[
'M12'] = M12; result[
'M21'] = M21
 
  371     if outmask & Geodesic.AREA: result[
'S12'] = S12
 
  374   def ArcPosition(self, a12, outmask = GeodesicCapability.STANDARD):
 
  375     """Find the position on the line given *a12* 
  377     :param a12: spherical arc length from the first point to the second 
  379     :param outmask: the :ref:`output mask <outmask>` 
  380     :return: a :ref:`dict` 
  382     The default value of *outmask* is STANDARD, i.e., the *lat1*, 
  383     *lon1*, *azi1*, *lat2*, *lon2*, *azi2*, *s12*, *a12* entries are 
  389     result = {
'lat1': self.
lat1,
 
  390               'lon1': self.
lon1 if outmask & Geodesic.LONG_UNROLL 
else 
  391               Math.AngNormalize(self.
lon1),
 
  392               'azi1': self.
azi1, 
'a12': a12}
 
  393     a12, lat2, lon2, azi2, s12, m12, M12, M21, S12 = self.
_GenPosition(
 
  395     outmask &= Geodesic.OUT_MASK
 
  396     if outmask & Geodesic.DISTANCE: result[
's12'] = s12
 
  397     if outmask & Geodesic.LATITUDE: result[
'lat2'] = lat2
 
  398     if outmask & Geodesic.LONGITUDE: result[
'lon2'] = lon2
 
  399     if outmask & Geodesic.AZIMUTH: result[
'azi2'] = azi2
 
  400     if outmask & Geodesic.REDUCEDLENGTH: result[
'm12'] = m12
 
  401     if outmask & Geodesic.GEODESICSCALE:
 
  402       result[
'M12'] = M12; result[
'M21'] = M21
 
  403     if outmask & Geodesic.AREA: result[
'S12'] = S12
 
  407     """Specify the position of point 3 in terms of distance 
  409     :param s13: distance from point 1 to point 3 in meters 
  414     self.
a13, _, _, _, _, _, _, _, _ = self.
_GenPosition(
False, self.
s13, 0)
 
  417     """Specify the position of point 3 in terms of arc length 
  419     :param a13: spherical arc length from point 1 to point 3 in degrees 
  425     _, _, _, _, self.
s13, _, _, _, _ = self.
_GenPosition(
True, self.
a13,