I know this is a lot to ask, but I need help translating some WorldWind functions to Cesium equivalents. I know it’s a lot of code. My hope is that there may be an approach in Cesium that can simplify this.

We have software built on top of WorldWind in which we save parameters related to the current view. We can later retrieve those parameters resulting in 2 positions that we pass to a WorldWind method called setOrientation which orients the view to match the view that was saved. We are trying to use these same saved parameters (again that we ultimately convert to 2 positions) to set the view in a Cesium app. But in order to do this I find there is quite a bit of code in WorldWind that I’m struggling to reproduce in Cesium.

My hope is that there may be other methods in Cesium that would shortcut some of the WorldWind process. But I quickly get out of my depth when starting to deal with Matrices and Quaternions and Transforms.

Below I’ll paste what I believe is the pertinent WorldWind code (with error checking stripped out). And below that my attempt thus far to translate to Cesium code.

I’ve included the majority of the WorldWind code in order to hopefully give a full picture of what WorldWind is doing.

WorldWind code I want to translate to Cesium code…

public void setOrientation(Position eyePosition, Position centerPosition) {

`Vec4 newEyePoint = globe.computePointFromPosition(eyePosition); Vec4 newCenterPoint = globe.computePointFromPosition(centerPosition); // If eye lat/lon != center lat/lon, then the surface normal at the center point will be a good value // for the up direction. Vec4 up = globe.computeSurfaceNormalAtPoint(newCenterPoint); // Otherwise, estimate the up direction by using the *current* heading with the new center position. Vec4 forward = newCenterPoint.subtract3(newEyePoint).normalize3(); if (forward.cross3(up).getLength3() < 0.001) { Matrix modelview = computeTransformMatrix(globe, eyePosition, heading, Angle.ZERO, Angle.ZERO); if (modelview != null) { Matrix modelviewInv = modelview.getInverse(); if (modelviewInv != null) { up = Vec4.UNIT_Y.transformBy4(modelviewInv); } } } ViewState modelCoords = computeViewState(this.globe, newEyePoint, newCenterPoint, up); setViewState(modelCoords);`

}

public static Matrix computeTransformMatrix(Globe globe, Position position, Angle heading, Angle pitch, Angle roll) {

`// To get a yaw-pitch-roll transform, do the view transform in reverse (i.e. roll-pitch-yaw) Matrix transform = Matrix.IDENTITY; transform = transform.multiply(Matrix.fromAxisAngle(roll, 0, 0, 1)); transform = transform.multiply(Matrix.fromAxisAngle(pitch, -1, 0, 0)); transform = transform.multiply(Matrix.fromAxisAngle(heading, 0, 0, 1)); transform = transform.multiply(computePositionTransform(globe, position)); return transform;`

}

public static Matrix computePositionTransform(Globe globe, Position center) {

`// The view eye position will be the same as the center position. // This is only the case without any zoom, heading, and pitch. Vec4 eyePoint = globe.computePointFromPosition(center); // The view forward direction will be colinear with the // geoid surface normal at the center position. Vec4 normal = globe.computeSurfaceNormalAtLocation(center.getLatitude(), center.getLongitude()); Vec4 lookAtPoint = eyePoint.subtract3(normal); // The up direction will be pointing towards the north pole. Vec4 north = globe.computeNorthPointingTangentAtLocation(center.getLatitude(), center.getLongitude()); // Creates a viewing matrix looking from eyePoint towards lookAtPoint, // with the given up direction. The forward, right, and up vectors // contained in the matrix are guaranteed to be orthogonal. This means // that the Matrix's up may not be equivalent to the specified up vector // here (though it will point in the same general direction). // In this case, the forward direction would not be affected. return Matrix.fromViewLookAt(eyePoint, lookAtPoint, north);`

}

public static ViewState computeViewState(Globe globe, Vec4 eyePoint, Vec4 centerPoint, Vec4 up) {

if (up == null) {

up = ViewUtil.getUpVector(globe, centerPoint);

}`Matrix modelview = Matrix.fromViewLookAt(eyePoint, centerPoint, up); return computeModelCoordinates(globe, modelview, centerPoint, eyePoint);`

}

public static Vec4 getUpVector(Globe globe, Vec4 lookAtPoint) {

return globe.computeSurfaceNormalAtPoint(lookAtPoint);

}public static ViewState computeModelCoordinates(Globe globe, Matrix modelTransform, Vec4 centerPoint, Vec4 eyePoint) {

`// Compute the center position. Position centerPos = globe.computePositionFromPoint(centerPoint); // Compute the center position transform. Matrix centerTransform = computePositionTransform(globe, centerPos); Matrix centerTransformInv = centerTransform.getInverse(); // Compute the heading-pitch-zoom transform. Matrix hpzTransform = modelTransform.multiply(centerTransformInv); // Extract the heading, pitch, and zoom values from the transform. Angle heading = computeHeading(hpzTransform); Angle pitch = computePitch(hpzTransform); if (heading == null || pitch == null) { return null; } Position viewPosition = globe.computePositionFromPoint(eyePoint); return new ViewState(viewPosition, heading, pitch, Angle.ZERO);`

}

public static Angle computeHeading(Matrix headingPitchZoomTransform) {

return headingPitchZoomTransform.getRotationZ();

}public static Angle computePitch(Matrix transform) {

Angle a = transform.getRotationX();

if (a != null) {

a = a.multiply(-1.0);

}

return a;

}public static Angle computeRoll(Matrix transform) {

return transform.getRotationY();

}protected void setViewState(ViewState modelCoords) {

if (modelCoords != null) {

if (modelCoords.getPosition() != null) {

eyePosition = normalizedEyePosition(modelCoords.getPosition());

}

if (modelCoords.getHeading() != null) {

heading = normalizedHeading(modelCoords.getHeading());

}

if (modelCoords.getPitch() != null) {

pitch = normalizedPitch(modelCoords.getPitch());

}

if (modelCoords.getRoll() != null) {

roll = normalizedRoll(modelCoords.getRoll());

}

}

}public static Position normalizedEyePosition(Position unnormalizedPosition){

if (unnormalizedPosition == null)

{

String message = Logging.getMessage(“nullValue.PositionIsNull”);

Logging.logger().severe(message);

throw new IllegalArgumentException(message);

}`return new Position( Angle.normalizedLatitude(unnormalizedPosition.getLatitude()), Angle.normalizedLongitude(unnormalizedPosition.getLongitude()), unnormalizedPosition.getElevation());`

}

public static Angle normalizedHeading(Angle unnormalizedHeading){

if (unnormalizedHeading == null)

{

String message = Logging.getMessage(“nullValue.AngleIsNull”);

Logging.logger().severe(message);

throw new IllegalArgumentException(message);

}`double degrees = unnormalizedHeading.degrees; double heading = degrees % 360; return Angle.fromDegrees(heading > 180 ? heading - 360 : (heading < -180 ? 360 + heading : heading));`

}

public static Angle normalizedPitch(Angle unnormalizedPitch){

if (unnormalizedPitch == null)

{

String message = Logging.getMessage(“nullValue.AngleIsNull”);

Logging.logger().severe(message);

throw new IllegalArgumentException(message);

}`// Normalize pitch to the range [-180, 180]. double degrees = unnormalizedPitch.degrees; double pitch = degrees % 360; return Angle.fromDegrees(pitch > 180 ? pitch - 360 : (pitch < -180 ? 360 + pitch : pitch));`

}

public static Angle normalizedRoll(Angle unnormalizedRoll){

if (unnormalizedRoll == null)

{

String message = Logging.getMessage(“nullValue.AngleIsNull”);

Logging.logger().severe(message);

throw new IllegalArgumentException(message);

}`double degrees = unnormalizedRoll.degrees; double roll = degrees % 360; return Angle.fromDegrees(roll > 180 ? roll - 360 : (roll < -180 ? 360 + roll : roll));`

}

``

Here’s what I have so far in my attempt to translate to Cesium…

function setOrientation(eyePoint, centerPoint, heading) {

`// If eye lat/lon != center lat/lon, then the surface normal at the center point will be a good value // for the up direction. var up = scene.globe.ellipsoid.geodeticSurfaceNormal(centerPoint); // Otherwise, estimate the up direction by using the *current* heading with the new center position. var forward = Cesium.Cartesian3.subtract(eyePoint, centerPoint, new Cesium.Cartesian3()); forward = Cesium.Cartesian3.normalize(forward, forward); var cross = Cesium.Cartesian3.cross(forward, up, new Cesium.Cartesian3()); cross = getLength3(cross); if (cross < 0.001) { var modelMatrix = Cesium.Transforms.headingPitchRollQuaternion(eyePoint, heading, 0.0, 0.0); // Was this the right thing to do or do I need to duplicate the computeTransformMatrix function? if (modelMatrix) { var modelMatrixInv = Cesium.Quaternion.inverse(modelMatrix, new Cesium.Quaternion()); if (modelMatrixInv) { up = Vec4.UNIT_Y.transformBy4(modelMatrixInv); // What's equivalent in Cesium? } } } var modelCoords = computeViewState(globe, newEyePoint, newCenterPoint, up); setViewState(modelCoords);`

}

function getLength3(objCartesian3) {

return Math.sqrt(getLengthSquared3(objCartesian3));

}function getLengthSquared3(objCartesian3) {

return (objCartesian3.x * objCartesian3.x)

+ (objCartesian3.y * objCartesian3.y)

+ (objCartesian3.z * objCartesian3.z);

}function computeViewState(globe, eyePoint, centerPoint, up) {

if (typeof up === “undefined”)

up = getUpVector(centerPoint);

}`var modelMatrix = Matrix.fromViewLookAt(eyePoint, centerPoint, up); // What's equivalent in Cesium? return computeModelCoordinates(globe, modelMatrix, centerPoint, eyePoint);`

}

function getUpVector(lookAtPoint) {

return scene.globe.ellipsoid.geodeticSurfaceNormal(lookAtPoint);

}function computeModelCoordinates(globe, modelMatrix, centerPoint, eyePoint) {

`// Compute the center position. var centerPos = scene.globe.ellipsoid.cartesianToCartographic(centerPoint); // Compute the center position transform. var centerTransformMatrix = computePositionTransform(globe, centerPos); var centerTransformMatrixInv = Cesium.Quaternion.inverse(centerTransformMatrix, new Cesium.Quaternion()); // Compute the heading-pitch-zoom transform. var hpzTransformMatrix = modelMatrix.multiply(centerTransformMatrixInv); // What's equivalent in Cesium? // Extract the heading, pitch, and zoom values from the transform. var headingAngle = computeHeading(hpzTransformMatrix); var pitchAngle = computePitch(hpzTransformMatrix); if (headingAngle == null || pitchAngle == null) { return null; } var viewPosition = scene.globe.ellipsoid.cartesianToCartographic(eyePoint); return new ViewState(viewPosition, headingAngle, pitchAngle, Angle.ZERO);`

}

function computePositionTransform(globe, center) {

`// The view eye position will be the same as the center position. // This is only the case without any zoom, heading, and pitch. var eyePoint = scene.globe.ellipsoid.cartographicToCartesian(center); // The view forward direction will be colinear with the // geoid surface normal at the center position. var normal = scene.globe.ellipsoid.geodeticSurfaceNormal(eyePoint); var lookAtPoint = eyePoint.subtract3(normal); // The up direction will be pointing towards the north pole. var north = globe.computeNorthPointingTangentAtLocation(center.getLatitude(), center.getLongitude()); // What's equivalent in Cesium? // Creates a viewing matrix looking from eyePoint towards lookAtPoint, // with the given up direction. The forward, right, and up vectors // contained in the matrix are guaranteed to be orthogonal. This means // that the Matrix's up may not be equivalent to the specified up vector // here (though it will point in the same general direction). // In this case, the forward direction would not be affected. return Matrix.fromViewLookAt(eyePoint, lookAtPoint, north); // What's equivalent in Cesium?`

}

function computeHeading(headingPitchZoomTransform) {

return headingPitchZoomTransform.getRotationZ(); // What’s equivalent in Cesium?

}function computePitch(Matrix transform) {

Angle a = transform.getRotationX(); // What’s equivalent in Cesium?

if (a != null) {

a = a.multiply(-1.0); // What’s equivalent in Cesium?

}

return a;

}function computeRoll(Matrix transform) {

return transform.getRotationY(); // What’s equivalent in Cesium?

}function setViewState(ViewState modelCoords) {

if (modelCoords != null) {

if (modelCoords.getPosition() != null) {

eyePosition = normalizedEyePosition(modelCoords.getPosition());

}

if (modelCoords.getHeading() != null) {

heading = normalizedHeading(modelCoords.getHeading());

}

if (modelCoords.getPitch() != null) {

pitch = normalizedPitch(modelCoords.getPitch());

}

if (modelCoords.getRoll() != null) {

roll = normalizedRoll(modelCoords.getRoll());

}

}

}

``

If anyone is willing to take the time to provide any instructions/education/help it would be greatly appreciated!

As an aside… I would love to understand these concepts (Matrices, Quaternions, Transforms). If anyone could point me to a good educational source that would help with practical understanding I would appreciate that as well.

Thanks,

Rob