HTML5 Canvas ScreenToIso - html

I am try create Isometric in HTML5 Canvas, but don't know how to convert HTML5 Canvas Screen coordinates to Isometric coordinates.
My code now is:
var mouseX = 0;
var mouseY = 0;
function mouseCheck(event) {
mouseX = event.pageX;
mouseY = event.pageY;
}
And I get Canvas coordinates. But how to convert this coordinates to Isometric coordinates? If I am something like use 16x16 tiles.
Thanks for everyone reply for this question and sorry for my English language.

If you want to translate standard coords to isometric - you should use such formulas (cos(30) = 0.866 & sin(30) = 0.5 are factors to use 30 degrees isometric projection)
xi = (y + x) * 0.866;
yi = (y - x) * 0.5;
So, if you want to do back translate - we can find our formula:
y = yi + xi / (0.866 * 2);
x = y - 2 * yi;
E.G. We have coords [3, 1] and wants to find isometric coords, so it is ease:
xi = (1 + 3) * 0.866 = 3.464;
yi = (1 - 3) * 0.5 = -1;
So, view coords of this cell is [3.464, -1]
E.G User clicked at [5.2, 1]. It is ease to count new value:
y = 1 + 5.2 / 1.732 = 4;
x = 4 - 2 * 1 = 2;
So, the clicked sell is [4, 2]
Example via LibCanvas: http://libcanvas.github.com/games/isometric/

Related

How to draw a triangle given two points using an html canvas and typescript

I am sure I have missed something obvious, but I am trying to draw a quadratic curve between two points using an html canvas, for which I need a 'control point' to set the curve. The start and end point of the curve are known, the control point is unknown because the lines are dynamically rotated. I just need to find this third point of the triangle in order to set the control point
I use this function to find the mid point of the line:
lineMidPoint(p: Point, q: Point): Point {
let x = (p.x + q.x) / 2;
let y = (p.y + q.y) / 2;
return { x: x, y: y } as Point;
}
This function works as expected.
Then a second function to get the angle of the line relative to the origin:
getAngleRelativeToOrigin(start: Point, end: Point): number {
let dx = start.x - end.x;
let dy = start.y - end.y;
let radians = Math.atan2(dy, dx);
return radians * (180/Math.PI);
}
It is hard to verify that this function is working.
Then finally I have a function for rotating the midpoint around either the start or the end of the line in order to find the control point:
getControlPoint(start: Point, end: Point): Point {
let midPoint = this.lineMidPoint(start, end);
let offset = 45 * (Math.PI / 180);
let theta = this.getAngleRelativeToOrigin(start, end) + offset;
let x = Math.cos(theta) * (start.x - midPoint.x) - Math.sin(theta) * (start.y - midPoint.y) + midPoint.x;
let y = Math.sin(theta) * (start.x - midPoint.x) - Math.cos(theta) * (start.y - midPoint.y) + midPoint.y;
return { x: x, y: y } as Point;
}
The result is this:
Those lines that are not connected to circles (for instance on the far right) should all be the length of the line they start from / 2, but they are clearly inconsistent.
When I draw the quadratic curves they are all wonky:
Can anyone lend a hand and tell me where Ive gone wrong?
OK, your middle point is correct.
Now determine difference vector and perpendicular to the line
let dx = start.x - end.x;
let dy = start.y - end.y;
let leng = Math.hypot(dx, dy);
let px = - dy / leng; //and get perpendicular unit vector
let py = dx / leng;
I am not sure what logic you wanted to implement, so I propose to get control point at distance d from line middle (so curve is symmetrical)
let xxx = midPoint.x + d * px;
let yyy = midPoint.y + d * py;
If you want to rotate middle point about start point, it might be done using the next approach:
let cost = Math.cos(45 * (Math.PI / 180));
let sint = Math.sin(45 * (Math.PI / 180));
let x = start.x + 0.5 * dx * cost - 0.5 * dy * sint;
let y = start.y + 0.5 * dx * sint + 0.5 * dy * cost;

Error in a changing delta angle radial coordinate system

I feel like this has probably been asked/answered here, and if so, I apologize for the bandwidth, but I don't see any explanation.
The problem is as follows:
I have 3 points .1 point (target) moves around 2 points (pointer). 3 point (ship) goes to 1 (target). I need to, at the angle α <90 degrees (Math.PI/2) 2 point (pointer) changed in the opposite direction.
Thanks!
function MovePointer(ship:Object, targ:Object, point:Object, R:Number, DAngle:Number):Number
{
var angle = Math.atan2(point.y - targ.y, point.x - targ.x);
if ( Math.abs( Math.PI-( angle - (Math.PI+Math.atan2(ship.y - targ.y, ship.x - targ.x)) ) ) < Math.PI/2 )
{
DAngle=-DAngle;
}
angle += DAngle;
point.x = targ.x + R * Math.cos(angle);
point.y = targ.y + R * Math.sin(angle);
return DAngle;
}
To calculate the angle and rotation should leave your
const product : Number = (point.y - targ.y) * (ship.y - targ.y) + (point.x - targ.x) * (ship.x - targ.x);
if (product > 0) {
DAngle = -DAngle;
}

Get longitude and latitude from the Globe in WebGL

I'm using WebGL globe from http://workshop.chromeexperiments.com/globe/. If any point of the globe is clicked, I need to get the longitude and latitude of that point. These parameters are to be passed to the Google Maps for 2D map.
How can I get the long. and lat. from the webgl globe?
Through this function I'm getting the double clicked point, and through this point I'm finding the long. and lat. But the results are not correct. It seems that the clicked point is not determined properly.
function onDoubleClick(event) {
event.preventDefault();
var vector = new THREE.Vector3(
( event.clientX / window.innerWidth ) * 2 - 1,
-( event.clientY / window.innerHeight ) * 2 + 1,
0.5
);
projector.unprojectVector(vector, camera);
var ray = new THREE.Ray(camera.position, vector.subSelf(camera.position).normalize());
var intersects = ray.intersectObject(globe3d);
if (intersects.length > 0) {
object = intersects[ 0 ];
console.log(object);
r = object.object.boundRadius;
x = object.point.x;
y = object.point.y;
z = object.point.z;
console.log(Math.sqrt(x * x + y * y + z * z));
lat = 90 - (Math.acos(y / r)) * 180 / Math.PI;
lon = ((270 + (Math.atan2(x, z)) * 180 / Math.PI) % 360) - 180;
console.log(lat);
console.log(lon);
}
}
Get the WebGL Globe here https://github.com/dataarts/webgl-globe/archive/master.zip
You can open it directly on Mozilla, if you open it in Chrome it works with earth surface image lack because of Cross-Origin Resource Sharing policy. It needs to be put in a virtual host.
Try to use the function in this way
function onDoubleClick(event) {
event.preventDefault();
var canvas = renderer.domElement;
var vector = new THREE.Vector3( ( (event.offsetX) / canvas.width ) * 2 - 1, - ( (event.offsetY) / canvas.height) * 2 + 1,
0.5 );
projector.unprojectVector( vector, camera );
var ray = new THREE.Ray(camera.position, vector.subSelf(camera.position).normalize());
var intersects = ray.intersectObject(globe3d);
if (intersects.length > 0) {
object = intersects[0];
r = object.object.boundRadius;
x = object.point.x;
y = object.point.y;
z = object.point.z;
lat = 90 - (Math.acos(y / r)) * 180 / Math.PI;
lon = ((270 + (Math.atan2(x, z)) * 180 / Math.PI) % 360) - 180;
lat = Math.round(lat * 100000) / 100000;
lon = Math.round(lon * 100000) / 100000;
window.location.href = 'gmaps?lat='+lat+'&lon='+lon;
}
}
I used the code you share with a little correction and it works great.
The way to let it work correctly is to understand exactly what you pass to the new THREE.Vector3.
This function need three parameters (x, y, z)
z in our/your case is sculpted as 0.5 and it's ok
x and y must be a number among -1 and 1, so, to obtain this values you need to catch the click coordinates on your canvas and then, with this formula, reduce them to a value in this range (-1...0...1);
var vectorX = ((p_coord_X / canvas.width ) * 2 - 1);
var vectorY = -((p_coord_Y / canvas.height ) * 2 - 1);
where p_coord_X and p_coord_Y are the coordinates of the click (referred to the left top corner of your canvas) and canvas is the canvas area where lives your webgl globe.
The problem is how to get the click X and Y coordinates in pixel, because it depends by how your canvas is placed in your HTML enviroment.
For my cases the solution over proposed where not suitable cause i returned always false results; so i build a solution to get extacly the x and y coordinates of my canvas area as i clicked on it (i had for my case too to insert a scrollY page correction).
Now imagine to devide in 4 square your canvas area, a click in the NW quadrant will return for example a -0.8, -05 x and y values, a click in SE i.e. a couple of 0.6, 0.4 values.
The ray.intersectObject() function that follows uses then our click-vector-converted data to understand if our click intersects the globe, if it matches, return correctly the coordinates lat and lon.

find angle and velocity for a parabola that meet specific range

i'm a little ashamed to ask this, but i have tried a lot of different things and can't make it work.
i have a game that shots a bullet, i have made the code that calculates the parabola trajectory given a an angle and a velocity, but i'm trying to make the calculus needed to get the angle and velocity needed to reach X point (the user enemy tank) and i'm unable to make it work as i need.
my current code is:
var startingPointX:Number = globalCoord.x;
var startingPointY:Number = globalCoord.y;
var targetX:Number = tankPlayer.x;
var targetY:Number = tankPlayer.y;
//distance between user and enemy tank
var distanceTarget = Math.sqrt(( startingPointX - targetX ) * ( startingPointX - targetX ) + ( startingPointY - targetY ) * ( startingPointY - targetY ));
var fixedVel = (distanceTarget/10)*2;
var fixedG = bullet.g;
// launch angle
var o:Number = -(Math.asin((0.5 * Math.atan(fixedG * distanceTarget / fixedVel * fixedVel))) * 180 / Math.PI);
bullet.init(startingPointX, startingPointY, o, fixedVel);
and the functions in the bullet object that actually position the bullet in the parabola trajectory is:
public function init(x, y:Number, rot:Number, speed:Number) {
// set the start position
var initialMove:Number = 35.0;
this.x = x + initialMove * Math.cos(2 * Math.PI * rot / 360);
this.y = y + initialMove * Math.sin(2 * Math.PI * rot / 360);
this.rotation = rot;
//get speed
dx = speed * Math.cos(2 * Math.PI * rot / 360);
dy = speed * Math.sin(2 * Math.PI * rot / 360);
//animation
lastTime = getTimer();
addEventListener(Event.ENTER_FRAME,moveBullet);
}
public function moveBullet(event:Event)
{
//get the time passed
var timePassed:int = getTimer() - lastTime;
lastTime += timePassed;
//move bullet
dy += g * timePassed / 1000;
this.x += dx * timePassed / 1000;
this.y += dy * timePassed / 1000;
//bullet past the top of the screen
if (this.y < 0)
{
deleteBullet();
}
}
any help would be really useful, thanks ! :D
Regards,
Shadow.
If this is a ballistics problem in the sense that you project a particle from point A with velocity v at an angle theta and you want it to hit a point T where the y coordinates of A and T match (ie they lie on a plane perpendicular to the vector of gravitational force vector) then you can calculate the required angle and velocity from this equation (See your wiki link where this is defined):
R = (v * v * sin(2 * theta))/g
Here R is the distance travelled in the x direction from your start point A . The problem you are facing is you are trying to interpolate a parabola through just 2 points. There are an infinite amount of parabolas that will interpolate 2 points while the parabola through 3 points is unique. Essentially there are an infinite amount of choices for velocity and angle such that you can hit your target.
You will either need to fix the angle, or the velocity of the bullet in order to use the above equation to find the value you require. If not, you have an infinite number of parabolas that can hit your target.
The above assumes that air resistance is ignored.
EDIT : Thus if you know velocity v already you can get theta from simple rearrangement of the above :
( asin(g * R / (v * v)) ) / 2 = theta
Based on the suggestion from #mathematician1975 i resolved the code to this and works perfectly :D
var distanceTarget = startingPointX - targetX ;
var fixedVel = 100;
var fixedG = tmpB.g;
var o:Number = (0.5 * Math.atan((fixedG * distanceTarget / (fixedVel * fixedVel)))) * 180 / Math.PI;
//this is only necessary why the enemy tank is facing left
o -= 180;
what i made is:
set a fixed velocity as #mathematician1975 said, a lot bigger than before
the distance between starting and ending point is lineal and not using Pythagoras.
the -180 is just why the enemy tanks is facing left.
i hope someone would find it useful in the future :D
Regards,
Shadow.

draw square and rotate it?

how come this doesn't work? does rotate only work with images?
context.moveTo(60,60);
context.lineTo(200,60);
context.lineTo(200,200);
context.lineTo(60,200);
context.lineTo(60,60);
context.stroke();
context.rotate(45 * Math.PI / 180);
context.restore();
You are rotating the whole canvas when you use context.rotate, and since the pivot point is defaulted at the coordinates (0, 0), your square sometimes will be drawn out of bounds.
By moving the pivot point to the middle of the square, you can then rotate it successfully.
Note: Make sure you rotate the canvas before you draw the square.
// pivot point coordinates = the center of the square
var cx = 130; // (60+200)/2
var cy = 130; // (60+200)/2
// Note that the x and y values of the square
// are relative to the pivot point.
var x = -70; // cx + x = 130 - 70 = 60
var y = -70; // cy + y = 130 - 70 = 60
var w = 140; // (cx + x) + w = 60 + w = 200
var h = 140; // (cy + y) + h = 60 + h = 200
var deg = 45;
context.save();
context.translate(cx, cy);
context.rotate(deg * Math.PI/180);
context.fillRect(x, y, w, h);
context.restore();
Explanation:
context.save(); saves the current state of the coordinate system.
context.translate(cx, cy); moves the pivot point.
context.rotate(deg * Math.PI/180); rotates the square to deg degrees (Note that the parameter is in radians, not degrees)
context.fillRect( x, y, w, h ); draws the square
context.restore(); restores the last state of the coordinate system.
Here is a JS Fiddle example.
Here is another JS Fiddle example that features a HTML5 slider.