Calculate Z Rotation of a face in Tensorflow.js - javascript

Note: This question has NOTHING to do with Three.js, it's only Tensorflow.js and Trigonometry.
I am trying to rotate a 3D object in Three.js by rotating my face. I have used this code by akhirai560 for rotating in X and Y axis.:
function normal(vec) {
let norm = 0;
for (const v of vec) {
norm += v * v;
}
return Math.sqrt(norm);
}
function getHeadAnglesCos(keypoints) {
// Vertical (Y-Axis) Rotation
const faceVerticalCentralPoint = [
0,
(keypoints[10][1] + keypoints[152][1]) * 0.5,
(keypoints[10][2] + keypoints[152][2]) * 0.5,
];
const verticalAdjacent = keypoints[10][2] - faceVerticalCentralPoint[2];
const verticalOpposite = keypoints[10][1] - faceVerticalCentralPoint[1];
const verticalHypotenuse = normal([verticalAdjacent, verticalOpposite]);
const verticalCos = verticalAdjacent / verticalHypotenuse;
// Horizontal (X-Axis) Rotation
const faceHorizontalCentralPoint = [
(keypoints[226][0] + keypoints[446][0]) * 0.5,
0,
(keypoints[226][2] + keypoints[446][2]) * 0.5,
];
const horizontalAdjacent = keypoints[226][2] - faceHorizontalCentralPoint[2];
const horizontalOpposite = keypoints[226][0] - faceHorizontalCentralPoint[0];
const horizontalHypotenuse = normal([horizontalAdjacent, horizontalOpposite]);
const horizontalCos = horizontalAdjacent / horizontalHypotenuse;
return [horizontalCos, verticalCos];
}
It calculates the rotation by finding the cos of these points (original image source):
I also want to calculate the cos of Z axis rotation. Thanks!

Am not fully clear of the end goal of the question, but if simply looking to rotate about the Z axis, the following snippet will assist.
center = { x: 50, y: 50 };
points = [
{ x: 60, y: 60 },
{ x: 50, y: 100 }
]
function rotateAboutZ( xyRotationPoint, points, zRotation ) {
let result = points.map( p => {
// Adjust the point based on the center of rotation.
let x = p.x - xyRotationPoint.x;
let y = p.y - xyRotationPoint.y;
// Calculate the radius and angle in preparation for rotation
// about the Z axis.
let radius = Math.sqrt( x * x + y * y );
let angle = Math.atan2( y, x );
// Adjust the angle by the requested rotation.
let angleRotated = angle + zRotation;
// Finally, calculate the new XY coordinates, and re-adjust
// based on the center of rotation.
let xRotated = radius * Math.cos( angleRotated ) + xyRotationPoint.x;
let yRotated = radius * Math.sin( angleRotated ) + xyRotationPoint.y;
return { x: xRotated, y: yRotated };
} );
return result;
}
// Let's rotate the points by 180 degrees around the
// center point of (50,50).
let result = rotateAboutZ( center, points, Math.PI );
console.log( result );

Related

Rotate leaflet Polyline/Rectangle

I'am trying to rotate Leaflet Rectangle using code from this question.
rotatePoints (center, points, yaw) {
const res = []
const angle = yaw * (Math.PI / 180)
for (let i = 0; i < points.length; i++) {
const p = points[i]
// translate to center
const p2 = new LatLng(p.lat - center.lat, p.lng - center.lng)
// rotate using matrix rotation
const p3 = new LatLng(Math.cos(angle) * p2.lat - Math.sin(angle) * p2.lng, Math.sin(angle) * p2.lat + Math.cos(angle) * p2.lng)
// translate back to center
const p4 = new LatLng(p3.lat + center.lat, p3.lng + center.lng)
// done with that point
res.push(p4)
}
return res
}
The problem is that the rectangle is skewed while rotating.
Any ideas how to optimize this function?
Fixed
Final code:
rotatePoints (center, points, yaw) {
const res = []
const centerPoint = map.latLngToLayerPoint(center)
const angle = yaw * (Math.PI / 180)
for (let i = 0; i < points.length; i++) {
const p = map.latLngToLayerPoint(points[i])
// translate to center
const p2 = new Point(p.x - centerPoint.x, p.y - centerPoint.y)
// rotate using matrix rotation
const p3 = new Point(Math.cos(angle) * p2.x - Math.sin(angle) * p2.y, Math.sin(angle) * p2.x + Math.cos(angle) * p2.y)
// translate back to center
let p4 = new Point(p3.x + centerPoint.x, p3.y + centerPoint.y)
// done with that point
p4 = map.layerPointToLatLng(p4)
res.push(p4)
}
return res
}
What is "rectangle" on sphere? It is result of applying of current projection to such coordinates that their image on the map/screen form rectangle. Note that lat-long coordinates are not ought to be equal for every rectangle side (for example, longitude for equator-aligned rectangle will differ for top and bottom point in the most of usual projections)
So to to get good-looking rectangle in map, you need to rotate vertices in screen coordinates, and make back-projection into lat-long space.

Calculation lat/long- points for a pentagon around center

I'm looking for a way to retrieve five points that would make a pentagon around a given center and a given distance.
Something like this:
getPentagonPoints = (latlng, distance) => {
var pentagonLatLng = [];
//magic calculations goes here
return pentagonLatLng;
}
You can do it like this:
function getPentagonPoints(latlng, distance) {
var pentagonLatLng = [];
for (let i = 0; i < 5; i++) {
// Pi * 2 is 360 degrees, in radians
// We add 270 degrees (Pi * 1.5 radians) to start at the top
const angle = Math.PI * 2 / 5 * i + Math.PI * 1.5; // in radians
const lng = distance * Math.cos(angle) + latlng.lng;
const lat = distance * Math.sin(angle) + latlng.lat;
pentagonLatLng.push({lat, lng});
}
return pentagonLatLng;
}
// Just for the demo
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
const latLng = { lat: 90, lng: 200 };
const points = getPentagonPoints(latLng, 50);
points.forEach((point, i) => {
if (i === 0) { ctx.moveTo(point.lng, point.lat); }
ctx.lineTo(point.lng, point.lat);
if (i === points.length - 1) { ctx.lineTo(points[0].lng, points[0].lat); }
});
ctx.stroke();
<canvas width="400" height="160"></canvas>

Calculate corners of rotated rectangle in container

I'm having some issues calculating the corners of a rotated rectangle within a rotated container with both having offset x/y co-ords.
The pivot is off but I'm not sure of the solution. The following scenarios work:
(x, y, rotation)
image = 0, 0, 45
container = 100, 100, 45
image = 200, 0, 45
container = 100, 100, 0
however setting the rotation of the container, and the image co-ords messes up the pivot e.g.
image = 200, 0, 45
container = 100, 100, 45
Below is the code for calculating the corners of the image in global co-ordinate space:
public get corners() {
const worldData = this.worldData;
//Get angle of object in radians;
const radAngle = worldData.rotation * Math.PI / 180;
const pivotX = worldData.pivotX;
const pivotY = worldData.pivotY;
const width = this.sourceWidth * worldData.scaleX;
const height = this.sourceHeight * worldData.scaleY;
const x = worldData.x;//this.x;
const y = worldData.y;//this.y;
//Get the corners
const c1 = this.getCorner(pivotX, pivotY, x, y, radAngle);
const c2 = this.getCorner(pivotX, pivotY, x + width, y, radAngle);
const c3 = this.getCorner(pivotX, pivotY, x + width, y + height, radAngle);
const c4 = this.getCorner(pivotX, pivotY, x, y + height, radAngle);
return {c1, c2, c3, c4};
}
public get worldData() {
let x = this.x;
let y = this.y;
let pivotX = this.x;
let pivotY = this.y;
let rotation = this.rotation;
let scaleX = this.scaleX;
let scaleY = this.scaleY;
let parent = this.parent;
while(parent) {
x += parent.x;
y += parent.y;
pivotX += parent.x;
pivotY += parent.y;
rotation += parent.rotation;
scaleX *= parent.scaleX;
scaleY *= parent.scaleY;
parent = parent.parent;
}
return {x, y, scaleX, scaleY, rotation, pivotX, pivotY}
}
protected getCorner(pivotX:number, pivotY:number, cornerX:number, cornerY:number, angle:number) {
let x, y, distance, diffX, diffY;
/// get distance from center to point
diffX = cornerX - pivotX;
diffY = cornerY - pivotY;
distance = Math.sqrt(diffX * diffX + diffY * diffY);
/// find angle from pivot to corner
angle += Math.atan2(diffY, diffX);
/// get new x and y and round it off to integer
x = pivotX + distance * Math.cos(angle);
y = pivotY + distance * Math.sin(angle);
return {x, y};
}
Let's suppose that the scenario is as follows:
where the lower left corner of the image (solid line) has coordinates (x_i, y_i) and the lower left corner of the container (dashed line) has coordinates (X_c, Y_c). Moreover, the image (of width w and height h) is rotated counter-clockwise by angle beta with respect to the laboratory frame, while the container itself is rotated (also counter-clockwise) by angle alpha.
Now, let's focus for example on the upper-right corner P. With respect to the laboratory frame (global canvas), its coordinates can be expressed as:
R(beta) . ( w, h ) + ( x_i, y_i )
where . denotes matrix multiplication, and R is a counter-clockwise rotation matrix
R(beta) = [ cos(beta) -sin(beta) ]
[ sin(beta) cos(beta) ]
Now, we need to transform this into a coordinate frame with respect to the container. Formally, this means that we need first to subtract the offset and then to rotate by -alpha (or alpha clock-wise). Thus with everything together:
R(-alpha).( R(beta) . (w, h) + (x_i, y_i) - (X_c, Y_c) )
The other corners can be handled similarly, just by replacing (w, h) with the proper coordinates...
In terms of code, one might implement these formulae as:
//counter-clock-wise rotation by given angle in degrees
function rotateCCWBy(angle, {x, y}) {
const angle_rad = angle * Math.PI / 180;
const cos_a = Math.cos(angle_rad),
sin_a = Math.sin(angle_rad);
return {
x: cos_a * x - sin_a * y,
y: sin_a * x + cos_a * y
};
}
//shift by a multiple fac of an offset {xref, yref}
function offsetBy(fac, {x:xref, y:yref}, {x, y}) {
return {
x: fac*xref + x,
y: fac*yref + y
};
}
const image = {
coords: {x: 200, y: 0}, //lab-frame coordinates
angle: 45, //lab-frame rotation angle
width: 50,
height: 10
};
const container = {
coords: {x: 100, y: 100}, //lab-frame coordinates
angle: 45 //lab-frame rotation angle
};
//calculate the coordinates of the image's top-right corner
//with respect to the container
const corner = rotateCCWBy(-container.angle,
offsetBy(
-1, container.coords,
offsetBy(
+1, image.coords,
rotateCCWBy(image.angle,
{x: image.width, y: image.height}
)
)
)
);
console.log(corner);
EDIT:
In case the y-axis is supposed to point "downwards", the formulas above work as well, one just needs to interpret the angles as clock-wise instead of counter-clockwise (so in principle the function rotateCCWBy should be renamed to rotateCWBy). As an example, let's consider this scenario:
Here, the top-left corner of the container is located at position (2,1) and the container itself is rotated by 15 degrees. The image (black rectangle) of width 4 and height 2 is rotated by 30 degrees and its top-left corner is located at position (3, 3). Now, we want to calculate the coordinates (x, y) of point P with respect to the container.
Using:
const image = {
coords: {x: 3, y: 3}, //lab-frame coordinates
angle: 30, //lab-frame rotation angle
width: 4,
height: 2
};
const container = {
coords: {x: 2, y: 1}, //lab-frame coordinates
angle: 15 //lab-frame rotation angle
};
//calculate the coordinates of the image's top-left corner
//with respect to the container
const corner = rotateCCWBy(-container.angle,
offsetBy(
-1, container.coords,
offsetBy(
+1, image.coords,
rotateCCWBy(image.angle,
{x: image.width, y: image.height}
)
)
)
);
console.log(corner);
yields
{ x: 4.8296291314453415, y: 4.640160440463835 }
which can be (approximately) visually verified from the attached figure.
EDIT2:
After additional clarification, the coordinates of the image are not supposed to be "lab-frame" (i.e., with respect to the canvas), but with respect to the already rotated container. Thus the transformation needs to be adapted as:
const corner =
offsetBy(
+1, container.coords,
rotateCCWBy(container.angle,
offsetBy(
+1, image.coords,
rotateCCWBy(image.angle,
{x: image.width, y: image.height}
)
)
)
);
function rotateCCWBy(angle, {x, y}) {
const angle_rad = angle * Math.PI / 180;
const cos_a = Math.cos(angle_rad),
sin_a = Math.sin(angle_rad);
return {
x: cos_a * x - sin_a * y,
y: sin_a * x + cos_a * y
};
}

rotate only an image in a canvas

I'm trying to rotate an image inside a canvas.
Here's my Fiddle: https://jsfiddle.net/kevinludwig11/s6rgpjm9/
I try it with save and restore, but the path is also rotating.
The falcon should fly with his face towards and change the angle in the corners.
Can anybody help me?
Edit: One solution i've found: save the image 360 times with every rotation and load every image in the right position. But i think thats not the smartest solution.
Canvas 2D image lookat transform.
No need to create 360 images to rotate a single image. Also you had a few incorrect ways of doing things.
Code problems
Only load the image once. You were loading it each time it was rendered.
Use requestAnimationFrame on its own. Putting it inside a timer makes its use completely redundant.
If you find yourself typing in long lists of numbers, and especially if you repeat these numbers in other sections of code you should use a single store to hold everything. Eg your paths were all hand coded. Move them into an array then iterate the array for the various things you need to do with the paths. One of the top ten programing rules. "Don't repeat/duplicate anything."
The lookat transform
To do the bird you will need to get the direction it is heading towards so I added a second point on the curves that is ahead of the bird. With these two points (birds pos and lookat pos) I then create a transformation using the lookat direction as the xAxis of the transformation. See function drawImageLookat(image,pos,lookat) I found that the image is not along the X axis so I rotate the bird 90deg after finding the lookat transformation.
Lookat function
// function assumes front (forward) of image is along the x axis to the right
function drawImageLookat(image, point, lookat ) {
var xAx,xAy; // vector for x Axis of image
var x,y;
x = lookat.x - point.x;
y = lookat.y - point.y;
var dist = Math.max(0.01,Math.sqrt(x * x + y * y)); // Math.max to avoid zero which will create NaN
xAx = x / dist; // get x component of x Axis
xAy = y / dist; // get y component of x Axis
// y axis is at 90 deg so dont need y axis vector
ctx.setTransform( // position the image using transform
xAx, xAy, // set direction of x Axis
-xAy, xAx, // set direction oy y axis
point.x, point.y
);
ctx.drawImage(image, -image.width / 2, -image.height / 2);
}
Demo from fiddle.
Your code that I took from the fiddle https://jsfiddle.net/kevinludwig11/s6rgpjm9/ and modified to run as your question implies.
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
// only load image once
var birdImage = new Image();
birdImage.src = 'http://www.happy-innovation.de/images/Falke_Flug.png';
birdImage.onload = function(){animate()}; // start animation when image has loaded
// set starting values
var speed = 0.25
var percent = speed;
var direction = speed;
var length = 300;
function animate() {
ctx.setTransform(1,0,0,1,0,0); // restore default transform incase its not
ctx.clearRect(0, 0, canvas.width, canvas.height);
percent += direction;
// need to keep the position away from the ends as there is no lookat beyond the path.
if(percent >= length - speed){
percent = length- speed;
direction = -speed;
}else if(percent <= speed){
percent = speed;
direction = speed;
}
draw(percent,direction);
requestAnimationFrame(animate);
}
function P(x,y){return {x,y}}; // quick way to create a point
var paths = [
{col : 'red', points : [P(100, 200), P(600, 350), P( 700, 400)]},
{col : "green", points : [P(700, 400), P( 900, 500), P( 200, 600), P( 950, 900)]},
{col : "blue", points : [P(950, 900), P(1200, 950), P( 300, 200), P( 150, 1200)]},
{col : "brown", points : [P(150, 1200),P( 120, 1700),P( 1000, 700),P(850, 1500)]},
{col : "Purple",points : [P(850, 1500),P(800, 1900), P( 200, 900), P( 250, 1800)]},
{col : "yellow", points : [P(250, 1800),P(250, 1950), P( 600, 1500),P(950, 1800)]},
]
// draw the current frame based on sliderValue
function draw(sliderValue,direction) {
var getPos = false; // true if need pos on current curve
var getForwardPos = false; // true if need pos on current curve
var percent,percent1; // get the percentage on curves
var birdPos; // get bird pos
var birdLookAtPos; // get bird look at pos
ctx.lineWidth = 5;
for(var i = 0; i < paths.length; i ++){
var path = paths[i]; // get a path from array
var p = path.points;
ctx.strokeStyle = path.col;
ctx.beginPath();
ctx.moveTo(p[0].x,p[0].y);
if(sliderValue >= i * 50 && sliderValue < (i+1) * 50){
getPos = true;
percent = (sliderValue % 50) / 50;
}
if(sliderValue + direction >= i * 50 && sliderValue + direction < (i+1) * 50){
getForwardPos = true;
percent1 = ((sliderValue + direction) % 50) / 50;
}
if(p.length > 3){
ctx.bezierCurveTo(p[1].x,p[1].y,p[2].x,p[2].y,p[3].x,p[3].y);
if(getPos){
birdPos = getCubicBezierXYatPercent(p[0],p[1],p[2],p[3],percent);
getPos = false;
}
if(getForwardPos){
birdLookAtPos = getCubicBezierXYatPercent(p[0],p[1],p[2],p[3],percent1);
getForwardPos = false;
}
}else{
ctx.quadraticCurveTo(p[1].x,p[1].y,p[2].x,p[2].y);
if(getPos){
birdPos = getQuadraticBezierXYatPercent(p[0],p[1],p[2],percent);
getPos = false;
}
if(getForwardPos){
birdLookAtPos = getQuadraticBezierXYatPercent(p[0],p[1],p[2],percent1);
getForwardPos = false;
}
}
ctx.stroke();
}
drawImageLookingAt(birdImage,birdPos,birdLookAtPos);
}
function drawImageLookingAt(image, point, lookat ) {
if(lookat === undefined){ // if no lookat then exit or it will crash.
return;
}
var xAx,xAy; // vector for x Axis of image
var x,y;
x = lookat.x - point.x;
y = lookat.y - point.y;
var dist = Math.max(0.01,Math.sqrt(x * x + y * y)); // Math.max to avoid zero which will create NaN
xAx = x / dist; // get x component of x Axis
xAy = y / dist; // get y component of x Axis
// y axis is at 90 deg so dont need y axis vector
ctx.setTransform( // position the image using transform
xAx, xAy, // set direction of x Axis
-xAy, xAx, // set direction oy y axis
point.x, point.y
);
// bird is pointing in the wrong direction. Not along x axis
// so rotate the image 90 deg clockwise
ctx.rotate(Math.PI / 2);
ctx.drawImage(image, -image.width / 2, -image.height / 2);
ctx.setTransform(1,0,0,1,0,0); // Restore default Not really needed if you only use setTransform to do transforms
// but in case you use transform, rotate, translate or scale you need to reset the
// transform.
}
// line: percent is 0-1
function getLineXYatPercent(startPt, endPt, percent) {
var dx = endPt.x - startPt.x;
var dy = endPt.y - startPt.y;
var X = startPt.x + dx * percent;
var Y = startPt.y + dy * percent;
return ({
x: X,
y: Y
});
}
// quadratic bezier: percent is 0-1
function getQuadraticBezierXYatPercent(startPt, controlPt, endPt, percent) {
var x = Math.pow(1 - percent, 2) * startPt.x + 2 * (1 - percent) * percent * controlPt.x + Math.pow(percent, 2) * endPt.x;
var y = Math.pow(1 - percent, 2) * startPt.y + 2 * (1 - percent) * percent * controlPt.y + Math.pow(percent, 2) * endPt.y;
return ({
x: x,
y: y
});
}
// cubic bezier percent is 0-1
function getCubicBezierXYatPercent(startPt, controlPt1, controlPt2, endPt, percent) {
var x = CubicN(percent, startPt.x, controlPt1.x, controlPt2.x, endPt.x);
var y = CubicN(percent, startPt.y, controlPt1.y, controlPt2.y, endPt.y);
return ({
x: x,
y: y
});
}
// cubic helper formula at percent distance
function CubicN(pct, a, b, c, d) {
var t2 = pct * pct;
var t3 = t2 * pct;
return a + (-a * 3 + pct * (3 * a - a * pct)) * pct + (3 * b + pct * (-6 * b + b * 3 * pct)) * pct + (c * 3 - c * 3 * pct) * t2 + d * t3;
}
<canvas height="1961" width="1000" id="canvas"></canvas>

Cone rotation around apex with Cesium.js

I am trying to rotate a cone from its apex, rather than its centre, so that the apex remains in the same position.
I've found the example below from the following link:
https://groups.google.com/forum/#!topic/cesium-dev/f9ZiSWPMgus
But it only shows how to rotate the cone by 90 degrees, if you choose a different value for roll, like 45 or 30 degrees, it gets skewed, and the apex ends up in the wrong place.
I know its something to do with the offset, but can't make any progress from there. Is there some way to calculate the correct offset for any value of roll?
I'd also like to extend the length of the cone when its rotated, so that when its rotated 30 degrees for example, the bottom of the cone will still reach the ground in that direction, while the apex still remains in its original place, I don't know how feasible that is though.
Here's a glitch of the code sample below:
https://glitch.com/edit/#!/cesium-cone-rotation
var viewer = new Cesium.Viewer('cesiumContainer');
var position = Cesium.Cartesian3.fromDegrees(-75, 40, 90);
//Original, non-rotated cone for comparison.
viewer.entities.add(new Cesium.Entity({
position: position,
point: {
color: Cesium.Color.YELLOW,
show: true,
pixelSize: 20
},
cylinder: {
topRadius: 0,
bottomRadius: 45,
length: 180,
material: Cesium.Color.YELLOW.withAlpha(0.5)
}
}));
var heading = Cesium.Math.toRadians(0.0);
var pitch = Cesium.Math.toRadians(0.0);
var roll = Cesium.Math.toRadians(90.0);
var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
//Create a rotation
var orientation = Cesium.Transforms.headingPitchRollQuaternion(position, hpr);
// offset the rotation so it's rotating from the apex of the cone, instead of the centre
var offset = new Cesium.Cartesian3(0, 90, 90);
//Create a transform for the offset.
var enuTransform = Cesium.Transforms.eastNorthUpToFixedFrame(position);
//Transform the offset
Cesium.Matrix4.multiplyByPointAsVector(enuTransform, offset, offset);
//Add the offset to the original position to get the final value.
Cesium.Cartesian3.add(position, offset, position);
viewer.entities.add(new Cesium.Entity({
position: position,
orientation: orientation,
point: {
color: Cesium.Color.YELLOW,
show: true,
pixelSize: 20
},
cylinder: {
topRadius: 0,
bottomRadius: 45,
length: 180,
material: Cesium.Color.YELLOW.withAlpha(0.5)
}
}));
viewer.zoomTo(viewer.entities);
Here's what I came up with to rotate and translate a cylinder when you want to point it in a specific orientation specified by an azimuth and elevation.
/**
* Calculate the position and orientation needed for the beam entity.
* #param {Cesium.Cartesian3} position - The position of the desired origin.
* #param {Number} az - The azimuth of the beam center in radians.
* #param {Number} el - The elevation of the beam center in radians.
* #param {Number} range - The range of the beam in meters.
*
* #returns {[Cesium.Cartesian3, Cesium.Quaternion]} Array of the position and
* orientation to use for the beam.
*/
calculateBeam(position, az, el, range) {
// The origin of Cesium Cylinder entities is the center of the cylinder.
// They are also pointed straight down towards the local East-North plane. The
// math below rotates and translates the cylinder so that its origin is the tip
// of the cylinder and its orientation is pointed in the direction specified by
// the az/el.
let heading = az - Cesium.Math.toRadians(90);
let pitch = Cesium.Math.toRadians(90) + el;
let hpr = new Cesium.HeadingPitchRoll(heading, pitch, 0.0);
let x = range/2.0 * Math.sin(pitch) * Math.cos(heading);
let y = -range/2.0 * Math.sin(heading) * Math.sin(pitch);
let z = -range/2.0 * Math.cos(pitch);
var offset = new Cesium.Cartesian3(x, y, z);
let enuTransform = Cesium.Transforms.eastNorthUpToFixedFrame(position);
Cesium.Matrix4.multiplyByPointAsVector(enuTransform, offset, offset);
let newPosition = Cesium.Cartesian3.add(position, offset, new Cesium.Cartesian3());
let orientation = Cesium.Transforms.headingPitchRollQuaternion(position, hpr);
return [newPosition, orientation];
}
This will give you the position/orientation to use when you create the cylinder entity. It will place the cylinder such that the tip of the cylinder is located at 'position' and it is pointed in the direction specified by the azimuth and elevation. Azimuth is relative to North with positive angles towards East. Elevation is relative to the North-East plane, with positive angles up. Range is the length of the cylinder.
This doesn't get you the behavior you wanted as far as lengthening the cylinder as you rotate it, but hopefully it helps.
I have the same problem as you. This is my reference code. This is a function of computing the matrix of a cone at any angle.
computedModelMatrix(Cartesian3: any, attitude: any, length: any) {
//锥体距离卫星的高度
let oldLength = length / 2;
let centerCartesian3 = new Cesium.Cartesian3(Cartesian3.x, Cartesian3.y, Cartesian3.z);
let oldX = 0, oldY = 0, oldZ = -oldLength, newX = 0, newY = 0, newZ = 0;
let heading = attitude.heading;
//规定顺时针为正旋转,正东方向为0度
if (heading < 0) {
heading = heading + 360;
}
let roll = attitude.roll;
let pitch = attitude.pitch;
let headingRadians = Cesium.Math.toRadians(heading);
let pitchRadians = Cesium.Math.toRadians(pitch);
let rollRadians = Cesium.Math.toRadians(roll);
let hpr = new Cesium.HeadingPitchRoll(headingRadians, pitchRadians, rollRadians);
let orientation = Cesium.Transforms.headingPitchRollQuaternion(centerCartesian3, hpr);
//旋转roll
newY = oldY + oldLength * Math.sin(rollRadians);
newZ = oldZ + oldLength - oldLength * Math.cos(rollRadians);
let pitchTouying = oldLength * Math.cos(rollRadians);//进行pitch变化时在Y轴和Z轴组成的平面的投影
//旋转pitch
newX = oldX + pitchTouying * Math.sin(pitchRadians);
newZ = newZ + (pitchTouying - pitchTouying * Math.cos(pitchRadians));
if (heading != 0) {
let headingTouying = Math.sqrt(Math.pow(Math.abs(newX), 2) + Math.pow(Math.abs(newY), 2));//进行heading变化时在Y轴和X轴组成的平面的投影
//旋转heading
let Xdeg = Cesium.Math.toDegrees(Math.acos(Math.abs(newX) / Math.abs(headingTouying)));//现有投影线与X轴的夹角
let newXdeg = 0;//旋转heading后与X轴的夹角
let newXRadians = 0;//旋转heading后与X轴的夹角弧度
if (newX >= 0 && newY >= 0) {
newXdeg = heading - Xdeg;
} else if (newX > 0 && newY < 0) {
newXdeg = heading + Xdeg;
} else if (newX < 0 && newY > 0) {
newXdeg = heading + (180 + Xdeg);
} else {
newXdeg = heading + (180 - Xdeg)
}
if (newXdeg >= 360) {
newXdeg = 360 - newXdeg;
}
if (newXdeg >= 0 && newXdeg <= 90) {
newXRadians = Cesium.Math.toRadians(newXdeg);
newY = -headingTouying * Math.sin(newXRadians);
newX = headingTouying * Math.cos(newXRadians);
} else if (newXdeg > 90 && newXdeg <= 180) {
newXRadians = Cesium.Math.toRadians(180 - newXdeg);
newY = -headingTouying * Math.sin(newXRadians);
newX = -headingTouying * Math.cos(newXRadians)
} else if (newXdeg > 180 && newXdeg <= 270) {
newXRadians = Cesium.Math.toRadians(newXdeg - 180);
newY = headingTouying * Math.sin(newXRadians);
newX = -(headingTouying * Math.cos(newXRadians))
} else {
newXRadians = Cesium.Math.toRadians(360 - newXdeg);
newY = headingTouying * Math.sin(newXRadians);
newX = headingTouying * Math.cos(newXRadians)
}
}
let offset = new Cesium.Cartesian3(newX, newY, newZ);
let newPosition = this.computeOffset(centerCartesian3, offset);
return Cesium.Matrix4.fromTranslationQuaternionRotationScale(newPosition, orientation, new Cesium.Cartesian3(1, 1, 1))
}
computeOffset(Cartesian3: any, offset: any) {
let enuTransform = Cesium.Transforms.eastNorthUpToFixedFrame(Cartesian3);
Cesium.Matrix4.multiplyByPointAsVector(enuTransform, offset, offset);
return Cesium.Cartesian3.add(Cartesian3, offset, new Cesium.Cartesian3());
}

Categories