Wie kann man die Sonne in CäsiumJS richtig ausrichten?

Nov 21 2020

Ich habe ein Cäsium-Sandburg-Beispiel basierend auf dieser Antwort von @FSimardGIS vorbereitet, aber etwas läuft schief: Nur einer von vielen Strahlen zeigt korrekt auf die Sonne, der andere erscheint zufällig.

Was ist hier los? Ich habe die Testkoordinaten aus der SunCalc-Bibliothek übernommen, aber Sie können Daten auch manuell einfügen, indem Sie beispielsweise diese Site für Berechnungen verwenden:

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

Dies ist der Quellcode aus der anderen Antwort:

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

Rufen Sie an mit:

vectorPointing= {"alt" : 30, "az" : 0};
startPoint= Cesium.Cartesian3.fromDegrees(290.6, -35.78);

Antworten

1 jumpjack Nov 25 2020 at 21:50

Ich habe eine Lösung entwickelt, die auf verschiedenen Algorithmen und Cäsium-Funktionen basiert.

Ich habe nichts über die verwendeten Transformationen und Methoden verstanden ... :-), aber es funktioniert gut.

Sandburg Beispiel.

Quellcode:

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);
 
  viewer.entities.add({
    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})
  // rotation: HeadingPitchRoll - {heading, pitch, roll}
  
  // 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);

    rotation.heading = rotation.heading - Cesium.Math.toRadians(90);
    var referenceFrame1 = Cesium.Transforms.headingPitchRollQuaternion(cartesianPosition, rotation);
    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){
  latitude = Cesium.Math.toRadians(latitude);
  longitude = Cesium.Math.toRadians(longitude);
  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 heading = Cesium.Math.toRadians(azimut);
  var pitch = Cesium.Math.toRadians(elev);
  var roll = 0.0;
  var direction = new Cesium.HeadingPitchRoll(heading, pitch, roll);
 
  
  ////////////
  var result = createROIfromRotation(origin, direction, lengthKM);
  ////////////
  
  drawLine(originC3.x ,originC3.y, originC3.z, result.x ,result.y, result.z);
}



// Bind button to test function:
document.getElementById("btnCalc").addEventListener("click",function(a,b,c) {
  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 );
  }

  
jumpjack Nov 27 2020 at 16:04

Der Grund für die Fehlfunktion des in der Frage genannten Algorithmus waren zwei falsche Formeln; Die richtige Funktion ist:

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

Der Faktor "Math.cos (vectorPointing.alt * Math.PI / 180)" fehlte in myX- und myY-Berechnungen.

Jetzt funktioniert alles gut:

Hier finden Sie ein Beispiel für eine funktionierende Sandburg