How to calculate an orbit around the earth with respect to Mercator projection? - three.js

I'm trying to create a small interactive UFO-flying-around-the-earth scene in three.js.
I thought it would be good to control the UFO on a 2D projection of the map (like a minimap), convert the pixel coordinates to lat/lng coordinates and finally transform lat/lng to a Vector that I can use for my 3D scene.
As it turns out, it wasn't.
Works great if the UFO flies around the Equator (+/- some degrees), but for sure I forgot to apply the projection to my 2D controls:
Now I'm a little bit lost. My controls (WASD keys) basically sets the speed and the rotation of the UFO on the minimap, but I have to add some sort of "correction" to the player. That's how the values are set at the moment:
let left = parseFloat(this.minimapPlayer.style.left) + this.speed * Math.cos(Math.PI / 180 * this.rotation)
let top = parseFloat(this.minimapPlayer.style.top) + this.speed * Math.sin(Math.PI / 180 * this.rotation)
Is there a way to create a "real" orbit, so that my UFO doesn't always fly through both poles? Or may there be a better approach to handle the orbit of the UFO (maybe without the minimap)?
Here's the full animation code so far:
animatePlane(firstRender) {
requestAnimationFrame(this.animatePlane)
// set next position
let left = parseFloat(this.minimapPlayer.style.left) + this.speed * Math.cos(Math.PI / 180 * this.rotation)
let top = parseFloat(this.minimapPlayer.style.top) + this.speed * Math.sin(Math.PI / 180 * this.rotation)
// handle border collisions
if (left < 0) {
left = this.minimapBounds.width
}
if (left > this.minimapBounds.width) {
left = 0
}
if (top < 0 || top > this.minimapBounds.height) {
this.rotation = this.rotation * -1
if (this.rotation > 0) {
this.plane.up.set(0, 1, 0)
} else {
this.plane.up.set(0, -1, 0)
}
top = top + this.speed * Math.sin(Math.PI / 180 * this.rotation)
if (left < this.minimapBounds.width / 2) {
left = left + this.speed * Math.cos(Math.PI / 180 * this.rotation) + this.minimapBounds.width / 2
} else {
left = left + this.speed * Math.cos(Math.PI / 180 * this.rotation) - this.minimapBounds.width / 2
}
}
this.minimapPlayer.style.left = `${left}px`
this.minimapPlayer.style.top = `${top}px`
// convert to lat/lng
const lat = (180 / this.minimapBounds.height) * (top - this.minimapBounds.height / 2) * -1
const lng = (360 / this.minimapBounds.width) * (left - this.minimapBounds.width / 2)
// convert to vector
const p = this.latLongToVector3(lat, lng, this.radius, 200)
this.plane.position.set(p.x, p.y, p.z)
// bottom of the plane should always look the the middle of the earth
this.plane.lookAt(new THREE.Vector3(0,0,0))
}

Related

Calculate square around a lat/long

I'm trying to calc a square around a single point but I keep getting a rectangle.
This is the point -80.42816162109375, 26.686729520004036.
Here's what it looks like:
What am I doing wrong?
int lat_feet = long_feet = 50;
double lat_meters = lat_feet * .3048;
double long_meters = long_feet * .3048;
var earth = 6378137;
var l1 = lat + (180 / Math.PI) * (lat_meters / earth);
var l2 = llong + (180 / Math.PI) * (long_meters / earth) / Math.Cos(lat);

Moving a line geometry with three.js using GLSL

I have a line geometry made with three.js, which I want to move as a spermatozoid (i.e. the head moves first, then all of the points along the tail move accordingly to the head) using GLSL.
Here is a visual representation of what I want:
So as you can see, point G eases to (follows) H, which in turn follows point E, which in turn follows the head.
I have a working examples, being animated on the CPU. Here is the code:
class Boid {
constructor (position) {
this.position = position
this.speed = 0.0009 + Math.random() * 0.0003
this.pointsNum = 12
this.points = []
this.line = null
this.angle = Math.random() * 360
for (let i = 0; i < this.pointsNum; i += 1) {
this.points.push(new THREE.Vector3(1, 1, 1))
}
this.angle = 0
}
update (target, time) {
if (time) {
this.line.geometry.verticesNeedUpdate = true
this.line.geometry.vertices.forEach((p, i) => {
let nextP = this.line.geometry.vertices[i + 1]
if (nextP) {
// if it's not the HEAD point, follow the next point in the geometry vertices
p.x += (nextP.x - p.x) * (time * 8.0)
p.y += (nextP.y - p.y) * (time * 8.0)
p.z += (nextP.z - p.z) * (time * 8.0)
} else {
// if the point is in fact the head, ease it according to some random moving point in our scene (target)
p.x += (target.x - p.x) * time
p.y += (target.y - p.y) * time
p.z += (target.z - p.z) * time
}
})
}
}
}
And here is a working example.
This technique is working, but would like to accomplish the same stuff with GLSL. My question is how should I approach it? Should I pass the next vertex position to the previous one and ease in my vertex shader? How should I keep track of the next's point position?
Any help is more then appreciated, I have been thinking about this a lot without any success.

Formula to translate xy movement with rotation

i have a canvas element that i rotate with context.rotate();
when i drag around the image in the canvas if i rotated lets say 90 degrees, and i move to the left, the image moves down,
is there a formula in which i can apply a movement of
for example
x+5 y+2 * degrees
and i get the real movement i need to do to move the rotated canvas in the direction i want? I would like to apply it to this function which works but with the undesired efect of moving left and the image moving down `
vm.canvasMouseMove = function (event) {
vm.delta = Date.now();
if (vm.mouseisdown && vm.delta - vm.now > (1000 / 60) && (event.clientX > 0 && event.clientY > 0)) {
vm.now = vm.delta
vm.snapshot.mouse.x -= event.clientX;
vm.snapshot.offsetSlider.value -= vm.snapshot.mouse.x;
if (vm.snapshot.offsetSlider.value < -160) {
vm.snapshot.offsetSlider.value = -160
}
else if (vm.snapshot.offsetSlider.value > 160) {
vm.snapshot.offsetSlider.value = 160
}
vm.snapshot.mouse.y -= event.clientY;
vm.snapshot.verticalOffsetSlider.value += vm.snapshot.mouse.y;
if (vm.snapshot.verticalOffsetSlider.value < -120) {
vm.snapshot.verticalOffsetSlider.value = -120
}
else if (vm.snapshot.verticalOffsetSlider.value > 120) {
vm.snapshot.verticalOffsetSlider.value = 120
}
vm.snapshot.mouse.x = event.clientX;
vm.snapshot.mouse.y = event.clientY;
}
};`
This draws
ctx.translate(canvas.width / 2, canvas.height / 2);
ctx.rotate(vm.snapshot.rotationSlider.value * Math.PI / 180);
ctx.drawImage(image, vm.snapshot.offsetSlider.value - (canvas.width / 2), (vm.snapshot.verticalOffsetSlider.value * -1) - (canvas.height / 2), vm.scaledImageW * vm.snapshot.zoomSlider.value / 100, vm.scaledImageH * vm.snapshot.zoomSlider.value / 100);
ctx.rotate(-1 * vm.snapshot.rotationSlider.value * Math.PI / 180);
ctx.translate(-canvas.width / 2, -canvas.height / 2);
vm.donePicture = canvas.toDataURL();
This made the trick, passing the offset to the translate method, then draw the image only taking into account the canvas half translation
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.translate((canvas.width / 2) + (vm.snapshot.offsetSlider.value), (canvas.height / 2) - vm.snapshot.verticalOffsetSlider.value);
ctx.rotate(vm.snapshot.rotationSlider.value * Math.PI / 180);
ctx.drawImage(vm.canvasImage, 0 - (canvas.width/2), 0 - (canvas.height/2), vm.scaledImageW * vm.snapshot.zoomSlider.value / 100, vm.scaledImageH * vm.snapshot.zoomSlider.value / 100);
ctx.restore();

Scaling small objects using THREE.TransformControls

I have a simple editor for 3D models using three.js.
This is my camera:
new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 0.01, 10);
And this is my mesh's geometry:
new THREE.BoxGeometry(0.3, 0.3, 0.3);
I'm using THREE.TransformControls to scale the mesh.
Scaling works perfectly fine when meshes have units ~ 100, but when an object is between 0 and 1, scaling is very slow. With slow, I mean that when you drag the scale slider half the canvas size, the mesh increases or decreases only a few percentages in size. I don't have this problem with other TransformControls modes.
JSFiddle demonstrating slow scaling
I could switch to bigger units, but I'd like to know if this can be solved without having to replace all units throughout my app code.
So my question: In THREE.TransformControls, is there a way to translate dragging to scaling in a more natural way while dealing with small units?
The problem is that TransformControls scales the distance of the mouse movement by a seemingly arbitrary amount (1/50) within the onMouseMove function:
} else if (_mode == "scale") {
point.sub(offset);
point.multiply(parentScale);
if (scope.space == "local") {
if (scope.axis == "XYZ") {
scale = 1 + ((point.y) / 50);
scope.object.scale.x = oldScale.x * scale;
scope.object.scale.y = oldScale.y * scale;
scope.object.scale.z = oldScale.z * scale;
} else {
point.applyMatrix4(tempMatrix.getInverse(worldRotationMatrix));
if (scope.axis == "X") scope.object.scale.x = oldScale.x * (1 + point.x / 50);
if (scope.axis == "Y") scope.object.scale.y = oldScale.y * (1 + point.y / 50);
if (scope.axis == "Z") scope.object.scale.z = oldScale.z * (1 + point.z / 50);
}
}
}
This parameter (50) effectively controls the "speed" at which the object is scaled (compared to how far the mouse is dragged). You're going to need to patch TransformControls in order to change it; I got it to work better by changing 50 to something smaller, like 1.
} else if (_mode == "scale") {
point.sub(offset);
point.multiply(parentScale);
// by default this is 50; set it to smaller values if you're using smaller units
scaleSpeed = 1;
if (scope.space == "local") {
if (scope.axis == "XYZ") {
scale = 1 + ((point.y) / scaleSpeed);
scope.object.scale.x = oldScale.x * scale;
scope.object.scale.y = oldScale.y * scale;
scope.object.scale.z = oldScale.z * scale;
} else {
point.applyMatrix4(tempMatrix.getInverse(worldRotationMatrix));
if (scope.axis == "X") scope.object.scale.x = oldScale.x * (1 + point.x / scaleSpeed);
if (scope.axis == "Y") scope.object.scale.y = oldScale.y * (1 + point.y / scaleSpeed);
if (scope.axis == "Z") scope.object.scale.z = oldScale.z * (1 + point.z / scaleSpeed);
}
}
}
Working fiddle: http://jsfiddle.net/494uvxfg/ .
three.js r68

scale rotating boundingbox

I recently started to develop a Windows Phone game with XNA. I have problem as you might have guessed collision detection. After looking up tutorials about all the types that can be achieved I decided I will go for the basic rectangular collision detection. I have a rotating sprite and a method that calculates the bounding box every time in the Update() method so I know where it's bounding box is then I simply check for intersection between all the lines of the box with all the lines of the other sprite's boxes. But since my box is appearing square shaped and my texture of that rotating sprite is Rectangular I wanna scale the bounding box so it will be closer to the texture's size. Here is what I have for calculating the corners of the rotating bounding box:
double baseAngle = Math.Atan(this.Height / this.Width);
double len = Math.Sqrt(this.Height * this.Height / 4 + this.Width * this.Width / 4);
Vector2 tr = new Vector2((float)(Math.Sin(baseAngle + this.Rotation) * len) + this.Position.X, (float)(Math.Cos(baseAngle + this.Rotation) * len) + this.Position.Y);
Vector2 tl = new Vector2((float)(Math.Sin(Math.PI - baseAngle + this.Rotation) * len) + this.Position.X, (float)(Math.Cos(Math.PI - baseAngle + this.Rotation) * len) + this.Position.Y);
Vector2 bl = new Vector2((float)(Math.Sin(Math.PI + baseAngle + this.Rotation) * len) + this.Position.X, (float)(Math.Cos(Math.PI + baseAngle + this.Rotation) * len) + this.Position.Y);
Vector2 br = new Vector2((float)(Math.Sin(2 * Math.PI - baseAngle + this.Rotation) * len) + this.Position.X, (float)(Math.Cos(2 * Math.PI - baseAngle + this.Rotation) * len) + this.Position.Y);`
any help would be appreciated. Thanks
when you scale, it only appears bigger widht and height are same. so bounding box is same as for original. try multypllying height and width with scale number where you calculate bounding box.
and you cannot rotate bounding box, you will have to use matrix.class but you can allways use circle collision.
circle collision
int circlesColliding(int x1, int y1, int radius1, int x2, int y2, int radius2) {
//compare the distance to combined radii
int dx = x2 - x1;
int dy = y2 - y1;
int radii = radius1 + radius2;
if ((dx * dx) + (dy * dy) < radii * radii) {
return true;
} else {
return false;
}
}

Resources