Repository: sunpy/sunpy

Issue:
Transformation between HGS and HPC fails when using Cartesian representation
Converting  a coordinate in Heliographic-Stonyhurst coordinates with a Cartesian representation to Helioprojective coordinates fails. E.g.,

```python
>>> import astropy.units as u
>>> import astropy.constants as const
>>> import sunpy.coordinates
>>> foo = SkyCoord(x=const.R_sun, y=0.*u.km, z=0.*u.km, 
                   frame='heliographic_stonyhurst', representation='cartesian')
>>> obs = sunpy.coordinates.ephemeris.get_earth()
>>> foo.transform_to(sunpy.coordinates.Helioprojective(observer=obs))
```
raises
```python traceback
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-46-77d08794e7f4> in <module>()
----> 1 foo.transform_to(sunpy.coordinates.Helioprojective(observer=obs))

~/anaconda/envs/synthesizar/lib/python3.6/site-packages/astropy/coordinates/sky_coordinate.py in transform_to(self, frame, merge_attributes)
    480         # Do the transformation, returning a coordinate frame of the desired
    481         # final type (not generic).
--> 482         new_coord = trans(self.frame, generic_frame)
    483 
    484         # Finally make the new SkyCoord object from the `new_coord` and

~/anaconda/envs/synthesizar/lib/python3.6/site-packages/astropy/coordinates/transformations.py in __call__(self, fromcoord, toframe)
   1312 
   1313             curr_toframe = t.tosys(**frattrs)
-> 1314             curr_coord = t(curr_coord, curr_toframe)
   1315 
   1316         # this is safe even in the case where self.transforms is empty, because

~/anaconda/envs/synthesizar/lib/python3.6/site-packages/astropy/coordinates/transformations.py in __call__(self, fromcoord, toframe)
    747 
    748     def __call__(self, fromcoord, toframe):
--> 749         res = self.func(fromcoord, toframe)
    750         if not isinstance(res, self.tosys):
    751             raise TypeError('the transformation function yielded {0} but '

~/anaconda/envs/synthesizar/lib/python3.6/site-packages/sunpy/coordinates/transformations.py in hgs_to_hcc(heliogcoord, heliocframe)
    186     # TODO: Revert this.
    187     from astropy.tests.helper import quantity_allclose
--> 188     hglon = heliogcoord.lon
    189     hglat = heliogcoord.lat
    190     r = heliogcoord.radius

~/anaconda/envs/synthesizar/lib/python3.6/site-packages/astropy/coordinates/baseframe.py in __getattr__(self, attr)
   1249             return val
   1250 
-> 1251         return self.__getattribute__(attr)  # Raise AttributeError.
   1252 
   1253     def __setattr__(self, attr, value):

AttributeError: 'HeliographicStonyhurst' object has no attribute 'lon'
```

However, adding an intermediate step to change to a spherical representation fixes this,

``` python
>>> (foo.transform_to('heliographic_stonyhurst')
        .transform_to(sunpy.coordinates.Helioprojective(observer=obs)))
```


Discussion:

Resolving patch:
diff --git a/sunpy/coordinates/transformations.py b/sunpy/coordinates/transformations.py
--- a/sunpy/coordinates/transformations.py
+++ b/sunpy/coordinates/transformations.py
@@ -72,8 +72,8 @@ def hgs_to_hgc(hgscoord, hgcframe):
                          "Heliographic Carrington, unless both frames have matching obstime.")
 
     c_lon = hgscoord.spherical.lon + _carrington_offset(hgscoord.obstime).to(u.deg)
-    representation = SphericalRepresentation(c_lon, hgscoord.lat,
-                                             hgscoord.radius)
+    representation = SphericalRepresentation(c_lon, hgscoord.spherical.lat,
+                                             hgscoord.spherical.distance)
     hgcframe = hgcframe.__class__(obstime=hgscoord.obstime)
 
     return hgcframe.realize_frame(representation)
@@ -91,8 +91,8 @@ def hgc_to_hgs(hgccoord, hgsframe):
     obstime = hgsframe.obstime
     s_lon = hgccoord.spherical.lon - _carrington_offset(obstime).to(
         u.deg)
-    representation = SphericalRepresentation(s_lon, hgccoord.lat,
-                                             hgccoord.radius)
+    representation = SphericalRepresentation(s_lon, hgccoord.spherical.lat,
+                                             hgccoord.spherical.distance)
 
     return hgsframe.realize_frame(representation)
 
@@ -187,9 +187,9 @@ def hgs_to_hcc(heliogcoord, heliocframe):
     """
     Convert from Heliographic Stonyhurst to Heliocentric Cartesian.
     """
-    hglon = heliogcoord.lon
-    hglat = heliogcoord.lat
-    r = heliogcoord.radius
+    hglon = heliogcoord.spherical.lon
+    hglat = heliogcoord.spherical.lat
+    r = heliogcoord.spherical.distance
     if r.unit is u.one and quantity_allclose(r, 1*u.one):
         r = np.ones_like(r)
         r *= RSUN_METERS


Test patch:
diff --git a/sunpy/coordinates/tests/test_transformations.py b/sunpy/coordinates/tests/test_transformations.py
--- a/sunpy/coordinates/tests/test_transformations.py
+++ b/sunpy/coordinates/tests/test_transformations.py
@@ -155,3 +155,59 @@ def test_hgs_hgc_roundtrip():
 
     assert_quantity_allclose(hgsout.lat, hgsin.lat)
     assert_quantity_allclose(hgsout.lon, hgsin.lon)
+
+
+def test_hgs_cartesian_rep_to_hpc():
+    # This test checks transformation HGS->HPC when the coordinate is in a Cartesian
+    # representation and that it is the same as a transformation from an HGS frame with a
+    # spherical representation
+
+    obstime = "2011-01-01"
+    hgscoord_cart = SkyCoord(x=1*u.km, y=0.*u.km, z=0.*u.km,
+                             frame=HeliographicStonyhurst(obstime=obstime),
+                             representation='cartesian')
+    hgscoord_sph = hgscoord_cart.copy()
+    hgscoord_sph.representation = 'spherical'
+    hpccoord_cart = hgscoord_cart.transform_to(Helioprojective(obstime=obstime))
+    hpccoord_sph = hgscoord_sph.transform_to(Helioprojective(obstime=obstime))
+    assert_quantity_allclose(hpccoord_cart.Tx, hpccoord_sph.Tx)
+    assert_quantity_allclose(hpccoord_cart.Ty, hpccoord_sph.Ty)
+    assert_quantity_allclose(hpccoord_cart.distance, hpccoord_sph.distance)
+
+
+def test_hgs_cartesian_rep_to_hcc():
+    # This test checks transformation HGS->HCC when the coordinate is in a Cartesian
+    # representation and that it is the same as a transformation from an HGS frame with a
+    # spherical representation
+
+    obstime = "2011-01-01"
+    hgscoord_cart = SkyCoord(x=1*u.km, y=0.*u.km, z=0.*u.km,
+                             frame=HeliographicStonyhurst(obstime=obstime),
+                             representation='cartesian')
+    hgscoord_sph = hgscoord_cart.copy()
+    hgscoord_sph.representation = 'spherical'
+    hcccoord_cart = hgscoord_cart.transform_to(Heliocentric(obstime=obstime))
+    hcccoord_sph = hgscoord_sph.transform_to(Heliocentric(obstime=obstime))
+    assert_quantity_allclose(hcccoord_cart.x, hcccoord_sph.x)
+    assert_quantity_allclose(hcccoord_cart.y, hcccoord_sph.y)
+    assert_quantity_allclose(hcccoord_cart.z, hcccoord_sph.z)
+
+
+def test_hgs_cartesian_rep_to_hgc():
+    # This test checks transformation HGS->HCC when the coordinate is in a Cartesian
+    # representation and that it is the same as a transformation from an HGS frame with a
+    # spherical representation
+
+    obstime = "2011-01-01"
+    hgscoord_cart = SkyCoord(x=1*u.km, y=0.*u.km, z=0.*u.km,
+                             frame=HeliographicStonyhurst(obstime=obstime),
+                             representation='cartesian')
+    hgscoord_sph = hgscoord_cart.copy()
+    hgscoord_sph.representation = 'spherical'
+    # HGC
+    hgccoord_cart = hgscoord_cart.transform_to(HeliographicCarrington(obstime=obstime))
+    hgccoord_sph = hgscoord_sph.transform_to(HeliographicCarrington(obstime=obstime))
+    assert_quantity_allclose(hgccoord_cart.lat, hgccoord_sph.lat)
+    assert_quantity_allclose(hgccoord_cart.lon, hgccoord_sph.lon)
+    assert_quantity_allclose(hgccoord_cart.radius, hgccoord_sph.radius)
+    
\ No newline at end of file