# How to properly point the Sun in CesiumJS?

I prepared a Cesium sandcastle example based on this answer from @FSimardGIS, but something is going wrong: only one of many rays correctly points to the Sun, the other appears random.

What's wrong here? I took the test coordinates from SunCalc library, but you can also insert data manually, using for example this site for calculations:

https://planetcalc.com/320/?day=2020-11-19%2004:31:37&plat=36.13&plon=138.36&gmtdiff=0&UTCoffset=0

This is the source code from the other answer:

``````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.sin(vectorPointing.az * Math.PI / 180);
var myY = vectorPointing.dist * 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;
}
``````

Call with:

``````vectorPointing= {"alt" : 30, "az" : 0};
startPoint= Cesium.Cartesian3.fromDegrees(290.6, -35.78);
``````
• Oops, the cos(alt) factor in the myX and myY calculation is missing. I updated my answer to correct the issue. Nov 27, 2020 at 2:36

I have built a solution based on different algorithm and Cesium functions.

I didn't understand anything about the transformations and methods used... :-) , but it works fine.

Sandcastle example.

Source code:

``````var viewer = new Cesium.Viewer("cesiumContainer");
viewer.scene.globe.enableLighting = true;

var suntest = [];

suntest[0] = {'time' : '2020-11-20T12:00:00.000Z', 'lat' : 0, 'lon' :-180, 'alt' : -69.936132980914, 'az' :170.491579546217};
suntest[1] = {'time' : '2020-11-20T12:00:00.000Z', 'lat' : 0, 'lon' :-150, 'alt' : -51.732788127111, 'az' :123.115116564788};
suntest[2] = {'time' : '2020-11-20T12:00:00.000Z', 'lat' : 0, 'lon' :-120, 'alt' : -24.870948550859, 'az' :111.897154212120};
suntest[3] = {'time' : '2020-11-20T12:00:00.000Z', 'lat' : 0, 'lon' :-90, 'alt' : 3.248817322124, 'az' :109.809795550210};
suntest[4] = {'time' : '2020-11-20T12:00:00.000Z', 'lat' : 0, 'lon' :-60, 'alt' : 31.247432115441, 'az' :113.313745536185};
suntest[5] = {'time' : '2020-11-20T12:00:00.000Z', 'lat' : 0, 'lon' :-30, 'alt' : 57.331014803665, 'az' :128.816746856710};
suntest[6] = {'time' : '2020-11-20T12:00:00.000Z', 'lat' : 0, 'lon' :0, 'alt' : 69.936132980893, 'az' :189.508420454115};
suntest[7] = {'time' : '2020-11-20T12:00:00.000Z', 'lat' : 0, 'lon' :30, 'alt' : 51.732788127357, 'az' :236.884883435008};
suntest[8] = {'time' : '2020-11-20T12:00:00.000Z', 'lat' : 0, 'lon' :60, 'alt' : 24.870948550745, 'az' :248.102845787901};
suntest[9] = {'time' : '2020-11-20T12:00:00.000Z', 'lat' : 0, 'lon' :90, 'alt' : -3.248817321848, 'az' :250.190204449796};
suntest[10] = {'time' : '2020-11-20T12:00:00.000Z', 'lat' : 0, 'lon' :120, 'alt' : -31.247432115554, 'az' :246.686254463785};
suntest[11] = {'time' : '2020-11-20T12:00:00.000Z', 'lat' : 0, 'lon' :150, 'alt' : -57.331014803436, 'az' :231.183253143577};
suntest[12] = {'time' : '2020-11-20T12:00:00.000Z', 'lat' : 0, 'lon' :180, 'alt' : -69.936132980873, 'az' :170.491579545552};
suntest[13] = {'time' : '2020-11-20T12:00:00.000Z', 'lat' : 10, 'lon' :-180, 'alt' : -79.671227366220, 'az' :161.573903931188};
suntest[14] = {'time' : '2020-11-20T12:00:00.000Z', 'lat' : 10, 'lon' :-150, 'alt' : -56.300357978857, 'az' :110.783422611356};
suntest[15] = {'time' : '2020-11-20T12:00:00.000Z', 'lat' : 10, 'lon' :-120, 'alt' : -28.225368684317, 'az' :107.175147833478};
suntest[16] = {'time' : '2020-11-20T12:00:00.000Z', 'lat' : 10, 'lon' :-90, 'alt' : -0.168643089275, 'az' :110.063187466725};
suntest[17] = {'time' : '2020-11-20T12:00:00.000Z', 'lat' : 10, 'lon' :-60, 'alt' : 26.878473297456, 'az' :118.330636399825};
suntest[18] = {'time' : '2020-11-20T12:00:00.000Z', 'lat' : 10, 'lon' :-30, 'alt' : 50.377210160732, 'az' :138.739128733690};
suntest[19] = {'time' : '2020-11-20T12:00:00.000Z', 'lat' : 10, 'lon' :0, 'alt' : 60.029872737499, 'az' :186.514048228677};
suntest[20] = {'time' : '2020-11-20T12:00:00.000Z', 'lat' : 10, 'lon' :30, 'alt' : 45.598015050067, 'az' :227.849125941148};

function drawLine(x1,y1,z1, x2, y2, z2) {
var origin = new Cesium.Cartesian3(x1,y1,z1);
var dest = new Cesium.Cartesian3(x2,y2,z2);

polyline: {
positions: [
origin,
dest
],
arcType: Cesium.ArcType.NONE   ,
width: 20,
material: new Cesium.PolylineArrowMaterialProperty(Cesium.Color.WHITE)
}
});
}

function createROIfromRotation(position,  rotation, lengthKM) {
// position: Cartographic - {latitude, longitude, altitude})

// Based on answer found here:
// https://stackoverflow.com/questions/58021985/create-a-point-in-a-direction-in-cesiumjs

var cartesianPosition = Cesium.Ellipsoid.WGS84.cartographicToCartesian(position);

var rotationMatrix = Cesium.Matrix3.fromQuaternion(referenceFrame1, new Cesium.Matrix3());
var rotationScaled = Cesium.Matrix3.multiplyByVector(rotationMatrix, new Cesium.Cartesian3(lengthKM * 1000.0, 0, 0), new Cesium.Cartesian3());
var roiPos = Cesium.Cartesian3.add(cartesianPosition, rotationScaled, new Cesium.Cartesian3());
return roiPos;
}

function arrowFromTo(latitude, longitude, height, elev, azimut, lengthKM){
var origin = new Cesium.Cartographic(longitude, latitude, height);
var originC3 = new Cesium.Cartographic.toCartesian(origin);

// Altitude (aka Elevation) and Azimuth can also be seen as Pitch and Heading, with Roll = 0:
var roll = 0.0;

////////////
var result = createROIfromRotation(origin, direction, lengthKM);
////////////

drawLine(originC3.x ,originC3.y, originC3.z, result.x ,result.y, result.z);
}

// Bind button to test function:
var obsLat = document.getElementById("obsLat").value * 1.0;
var obsLon = document.getElementById("obsLon").value * 1.0;
var obsAlt = document.getElementById("obsAlt").value * 1.0;
var sunAlt = document.getElementById("sunAlt").value * 1.0;
var sunAz = document.getElementById("sunAz").value * 1.0;
var userDate = document.getElementById("userDate").value;

viewer.clock.currentTime = Cesium.JulianDate.fromDate(new Date(userDate));
arrowFromTo(obsLat,obsLon,obsAlt,sunAlt,sunAz,150000000);
//latitude, longitude, height, elev, azimut, lengthKM
});

///////////////////////
// Draw test lines:
viewer.clock.currentTime = Cesium.JulianDate.fromDate(new Date(suntest[0].time));

for (var i = 0; i<suntest.length; i++) {
arrowFromTo(suntest[i].lat, suntest[i].lon, 0, suntest[i].alt, suntest[i].az,150000000 );
}

``````

The reason of malfunctioning of the algorith mentioned in the question were two wrong formulas; right function is:

``````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;

}
``````

"Math.cos(vectorPointing.alt * Math.PI / 180)" factor was missing in myX and myY calculations.

Now all works fine:

Look here for a working sandcastle example