3 votos

¿Cómo apuntar correctamente al Sol en CesiumJS?

He preparado un Ejemplo de castillo de arena de cesio basado en esta respuesta de @FSimardGIS, pero algo va mal: sólo uno de los muchos rayos apunta correctamente al Sol, el otro parece aleatorio.

Screenshot ¿Qué pasa aquí? Tomé las coordenadas de prueba de la biblioteca SunCalc, pero también puede insertar los datos manualmente, utilizando por ejemplo este sitio para los cálculos:

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

Este es el código fuente de la otra respuesta:

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

Llama con:

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

1voto

TestUser16418 Puntos 282

He construido una solución basada en diferentes algoritmos y funciones de Cesio.

No he entendido nada de las transformaciones y métodos utilizados... :-) , pero funciona bien.

Ejemplo de castillo de arena.

Código fuente:

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

0voto

TestUser16418 Puntos 282

La razón del mal funcionamiento del algoritmo mencionado en la pregunta fueron dos fórmulas erróneas; la función correcta es:

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;

}

Faltaba el factor "Math.cos(vectorPointing.alt * Math.PI / 180)" en los cálculos de myX y myY.

Ahora todo funciona bien:

Screenshot of Cesium

Busque aquí un trabajo ejemplo de castillo de arena

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X