# Convert from Alt/Az coordinates w.r.t. point on surface to (x,y,z) w.r.t Earth centre?

I know how an antenna located on Earth surface is pointing to an object in space, by means of Altitude and Azimuth.

I would like to show the pointed object in the 3d view, so, as far as I can understand, I need its position in (x,y,z) format (Cartesian3 object?)

But I can't understand exactly which is the exact process to follow.

I am using this example using CesiumJS library to make experiments; I added one point on surface by adding these lines inside function addMultiplePoints() :

``````viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(290.6, -35.78),
point: {
color: Cesium.Color.RED,
pixelSize: 18,
},
label: {
text: "MLG",
font: "14px Helvetica",
pixelOffset: new Cesium.Cartesian2(0.0, 20),
},
description : "MLG"
});
``````

Now I have to add a point with specific location w.r.t this point, say Alt=30, Az=0.

I am trying with this... but nothing happens; indeed, in this code there is no origin point for the coordinates...

``````  H2pointing = {"alt" : 30, "az" : 0};
clock = 90 - H2pointing.az;
cone = 90 - H2pointing.alt;
H2spherical = new Cesium.Spherical(clock, cone, 10);
console.log(clock);
console.log(cone);
console.log(H2spherical);
H2cartesian = Cesium.Cartesian3.fromSpherical(H2spherical, null);

position: H2cartesian,
point: {
color: Cesium.Color.BLUE,
pixelSize: 18,
},
label: {
text: "Hayabusa2",
font: "14px Helvetica",
pixelOffset: new Cesium.Cartesian2(0.0, 20),
},
description : "Hayabusa2"
});
``````

So, assuming my calculations are right (are they?), how do I center this point on previous point?

Maybe I could use another method:

``````Cesium.Transforms.headingPitchRollToFixedFrame(origin, headingPitchRoll, ellipsoid, fixedFrameTransform, result)
``````

If I specify Roll = 0, I should get the equivalent of Altitude and Azimuth.

But, also in this case, how to apply this transform to a point?

headingPitchRollToFixedFrame Computes a 4x4 transformation matrix from a reference frame with axes computed from the heading-pitch-roll angles centered at the provided origin to the provided ellipsoid's fixed reference frame. Heading is the rotation from the local north direction where a positive angle is increasing eastward. Pitch is the rotation from the local east-north plane. Positive pitch angles are above the plane. Negative pitch angles are below the plane. Roll is the first rotation applied about the local east axis.

In order to calculate a new point from an origin, you will also need a distance from the origin to the point in question. Here I assumed that you have a distance value available.

An option would be to create a function calculating the target point from an origin and a vector:

``````function CalcPosFromAltAzDist(startPoint, vectorPointing) {

var ellipsoid = Cesium.Ellipsoid.WGS84;
var ENU = new Cesium.Matrix4();
Cesium.Transforms.eastNorthUpToFixedFrame(startPoint,ellipsoid,ENU);
var myX = vectorPointing.dist * Math.cos(vectorPointing.alt * Math.PI / 180) * Math.sin(vectorPointing.az * Math.PI / 180);
var myY = vectorPointing.dist * Math.cos(vectorPointing.alt * Math.PI / 180) * Math.cos(vectorPointing.az * Math.PI / 180);
var myZ = vectorPointing.dist * Math.sin(vectorPointing.alt * Math.PI / 180);
var offset = new Cesium.Cartesian3(myX,myY,myZ);
var finalPoint = Cesium.Matrix4.multiplyByPoint(ENU, offset, new Cesium.Cartesian3());
return finalPoint;

}
``````

I used the method `eastNorthUpToFixedFrame` to compute a transformation matrix from the local ENU frame at the origin, and used that along with the cartesian offset to compute the final point.

Then you can call that function when adding the points:

``````function addMultiplePoints() {

var origin = Cesium.Cartesian3.fromDegrees(290.6, -35.78);

position: origin,
point: {
color: Cesium.Color.RED,
pixelSize: 18,
},
label: {
text: "MLG",
font: "14px Helvetica",
pixelOffset: new Cesium.Cartesian2(0.0, 20),
},
description : "MLG"
});

var H2pointing = {"alt" : 30, "az" : 0, "dist" : 150};

position: new CalcPosFromAltAzDist(origin, H2pointing),
point: {
color: Cesium.Color.BLUE,
pixelSize: 18,
},
label: {
text: "Hayabusa2",
font: "14px Helvetica",
pixelOffset: new Cesium.Cartesian2(0.0, 20),
},
description : "Hayabusa2"
});

}
``````
• actually no, I don't have a distance, I only know the direction, but using a dummy distance does the trick, thanks. Nov 13, 2020 at 20:52
• does this algoritm have any limitation? I get weird results upon attempting to convert negative elevations such as Sun Elev = -73.09 Sun Az = 9.88 from location LAT= 36.13 , LON= 138.36 , or Sun Elev = -77.57 Sun Az = 341.08 from LAT= 31.25 , LON= 131.08 Nov 18, 2020 at 15:26
• please have a look at this answer/question: gis.stackexchange.com/questions/379843/… I found an alternative solution, but I would like to know why yours does not work. Nov 26, 2020 at 18:30
• Oh, I realized that I omitted the Cosine(alt) multiplication for the x and y ENU coordinates in the CalcPosFromAltAzDist function. That might be the issue. Sorry about that. Can you test it again with my updated function? Nov 27, 2020 at 1:21
• Thanks, now it works; I updated my answer and the sandcastle link for testing. Nov 27, 2020 at 9:01

Based on @FSimardGIS I prepared a smaller snippet of code with plenty of comments, to enable other readers to better understand how to implement the solution:

``````function CalcPosFromAltAzDist(center, vectorPointing) {
// Extract single data from input:
var Altitude = vectorPointing.alt  * Math.PI / 180;
var Azimuth = vectorPointing.az  * Math.PI / 180;
var Length = vectorPointing.dist;

// Calculate cartesian coordinate of a point on a generic sphere
// of radius = length and centered on (0,0,0):
var genericX = Length * Math.cos(Altitude) * Math.sin(Azimuth);
var genericY = Length * Math.cos(Altitude) * Math.cos(Azimuth);
var genericZ = Length * Math.sin(Altitude);

// Assign the coordinates to a Cartesian3 object:
var floatingPoint = new Cesium.Cartesian3(genericX, genericY, genericZ);

// Setup function to turn generic coordinates into
// referenced coordinates:
var toENU = Cesium.Transforms.eastNorthUpToFixedFrame(center);

// Put the point into a reference system (East-North-Up):
var referencedPoint = Cesium.Matrix4.multiplyByPoint(toENU, floatingPoint, new Cesium.Cartesian3());

return referencedPoint;
}
``````

Calling example:

``````  // Position on surface in degrees and meters:
var origin = Cesium.Cartesian3.fromDegrees(lon, lat, alt);

// Location to point at:
var pointing = {"alt" : alt, "az" : az, "dist" : 7000000000};

// Calculate position of pointed location w.r.t
// a specified point (origin):
var pos = new CalcPosFromAltAzDist(origin, pointing);
``````

Once the position of the pointed location in new reference frame has been calculated, it is also possible to draw an arrow from the origin of the reference frame to the point:

``````var pointer = viewer.entities.add({
name: "Arrow",
polyline: {
positions: [
origin,
pos,
],
width: 1,
arcType: Cesium.ArcType.NONE, // straight line, not arc
},
});
``````