ATAN calculation fails when values are scaled - javascript

Im animating sprites w javacript - these sprites consist of a container DIV and the firstChild is an absolute positioned IMG. The image is comprised of 16 vertical views/angles of the object. When the object moves from A to B, the ATAN2 function calculates the style=top: value appropriate to the direction the object is traveling in. This all works except for another aspect of the sprite - they can change their size. The default size of the sprite is 24px (wide) and this does work with ATAN2, but as soon as the sprite is made bigger the calculation misaligns the sprite's frame-strip. Below is the code, x1 - y1 are the from and to positions, while s is the size (width). the value 128 is the maximum size - and the bracked values are of a sprite allowed and the last calculation assumes this, then computes for the actual size with *(s/128) ...
function P_angle(x1,x2,y1,y2,s)
{
var v=parseInt(Math.atan2(x2-x1,y2-y1)/(Math.PI/180)+180)
return (v>348.75?0:v>326.25?-128:v>303.75?-256:v>281.25?-384:v>258.75?-512:v>236.25?-640:v>213.75?-768:v>191.25?-896:v>168.75?-1024:v>146.25?-1152:v>123.75?-1280:v>101.25?-1408:v>78.75?-1536:v>56.25?-1664:v>33.75?-1792:v>11.25?-1920:0)*(s/128);
}

In the first line you do a floating point calculation and pass the result to a function expecting a string argument... you are saved by implicit conversion, but it's ugly.
The huge conditional in your second line rounds the angle off to the nearest multiple of 22.5 degrees, wrapping around and mapping to negative multiples of 128, then multiplies it with s divided by 128... was it originally designed for 128 pixel sprites? Anyway, you should just be able to do this:
function P_angle(x1,x2,y1,y2,s)
{
return s*(Math.round(Math.atan2(x2-x1,y2-y1)*(8/Math.PI)-8)%16);
}
You don't say how large the misalignment is with your original code, but I suspect it is caused by rounding errors when dividing out the 128 factor, and that you were just lucky that everything rounded right for 24 pixel sprites. With the version here, you are certain to return an exact multiple of s.

Related

3D Calculating the Z position of a point in a triangle

To create my three-dimensional engine, I used rasterization: dividing the triangles at their points.
However to carry out the rasterization I convert the points into the 2 dimensions. I then add the dot to a list that will render them later. To rearrange them, however, I need to know the Z position of the points.
So my question is: I have a triangle in 3 dimensions. I then convert it into the 2 dimensions. For each single point, how do I know the Z position, knowing its position of the 2 dimensions?
I tried a weird formula, which based on the distance from the points averaged the Z positions, but it's not working; Can you help me?

Efficient algorithm for finding which hexagon a point belongs to

I'm trying to find a more efficient way of determining which hexagon a point belongs to from the following:
an array of points - for the sake of argument, 10000 points.
an array of center points of hexagons, approximately 1000 hexagons.
every point will belong to exactly one hexagon, some (most) hexagons will be empty.
The hexagons form a perfect grid, with the point of one hexagon starting in the top left corner (it will overlap the edge of the total area).
My current solution works, but is rather slow n * (m log m) I think, where n=length(points) and m=length(hexagons).
I suspect I can do much better than this, one solution that comes to mind is to sort (just once) both the points and the hexagons by their distance to some arbitrary point (perhaps the middle, perhaps a corner) then iterate over the points and over a subset of the hexagons, starting from the first hexagon whose distance to this point is >= to the last hexagon matched. Similarly, we could stop looking at hexagons once the distance difference between the (point -> ref point) and (hexagon center -> ref point) is larger than the "radius" of the hexagon. In theory, since we know that every point will belong to a hexagon, I don't even have to consider this possibility.
My question is: Is there a Much better way of doing it than this? In terms of complexity, I think it's worst case becomes marginally better n * m but the average case should be very good, probably in the region of n * 20 (e.g., we only need to look at 20 hexagons per point). Below is my current inefficient solution for reference.
points.forEach((p) => {
p.hex = _.sortBy(hexes, (hex) => {
const xDist = Math.abs(hex.middle.x - p.x);
const yDist = Math.abs(hex.middle.y - p.y);
return Math.sqrt((xDist * xDist) + (yDist * yDist));
})[0];
});
For an arbitrary point, you can find the nearest hexagon center in two steps (assuming the same arrangement as that of Futurologist):
divide the abscissa by the horizontal spacing between the centers, and round to the nearest integer.
divide the ordinate by the half of the vertical spacing, and round to the nearest even or odd integer, depending on the parity found above.
consider this center and the six ones around it, and keep the closest to the target point.
This gives you the indexes of the tile, in constant time.
Just a suggestion: assume you have the centers of each regular hexagon from your regular hexagonal grid (if I have understood correctly, that's part of the information you have).
-----
/ \
- ----- -----------> x - axis
\ / \
----- -
/ \ /
- -----
\ / \
----- -
| \ /
| -----
|
|
V
y - axis
You can think that your coordinate system starts from the center of the hexagon in the upper left corner and the y coordinate axis runs vertically down, while the x axis runs from left to right horizontally. The centers of the hexagons from your regular hexagonal grid form an image of the regular square grid, where the integer vertices of the square grid are transformed into the centers of the polygons by simply multiplying the coordinates of points in the square grid by the 2 x 2 square matrix (a sheer metrix)
A = a*[ sqrt(3)/2 0;
1/2 1 ]
where a is a parameter of the hexagonal grid, the distance between the centers of two edge-adjacent hexagons. This provides a way to assign integer indices [m n] to the grid formed by the hexagonal centers. After that, if you are given a point with coordinates [x y] in the hexagonal grid, you can apply the inverse matrix of A
[u; v] = A^(-1)*[x; y]
where
A^(-1) = (2/(a*sqrt(3)))*[ 1 0 ;
-1/2 sqrt(3)/2 ]
([x; y] and [u; v] are column vectors) and then take m = floor(u) and n = floor(v) to determine the integer coordinates (also the indices) [m = floor(u), n = floor(v)] of the upper left corner of the square cell from the square grid (observe that we have chosen the coordinates for both grids to start from the upper left corner). Thus, your point [u, v] is in the square with vertices [m,n] [m+1, n] [m, n+1] [m+1, n+1]
which means that the original point [x y] is in one of the four hexagons whose centers have indices [m,n] [m+1, n] [m, n+1] [m+1, n+1]. So you can use that to check in which of the four hexagons the point [x y] is.
I hope this helps.
Update: Leaving the below comment for posterity
I am now using the code provided here: https://www.redblobgames.com/grids/hexagons/
A really important note, is that your hexagon grid MUST start with the first hexagons mid point at (0, 0) - if it doesn't you get extremely odd results from this, which at first glance appeared as rounding errors (even after accounting for the expected offset). For me, it didn't matter where the first hexagon was positioned, so I just set it to be (0, 0) and it worked great.
Old solution
I'm still hoping for an optimal solution, but I ended up rolling my own which needs only check 6 hexagons per point, with a little overhead (approximately sqrt(m)) needed in addition.
With approximately 3000 points, and 768 hexagons (of which 310 were populated), it correctly assigned the point to the hexagon 100% of the time (as checked against a brute force approach) and took 29 milliseconds, compared to ~840 with brute force.
To start with, I store the hexagons in a map where the key is "${column},${row}". The columns technically overlap, so for the 0th row, the 0th column starts at -0.5 * hexWidth, and for row 1, the 0th column starts at 0px.
Next, I start from the position of the top left hexagon, item "0,0", which should also be at position 0, and increment y by either the height of the hexagon, or the edge length of the hexagon accordingly. When the y is > the points y, I've found the probable row, I then check the row above and below.
For the column within the row, I take the both the Math.floor and Math.ceil of x / hexWidth.
Doing this gives 6 hexagons to check, from this point the solution is identical to the solution in the question.
In theory, this could be used to just look up the correct hexagon, using the x/y position. However in practice, this didn't work for me about 5% of the time with off by 1 errors, likely a rounding problem.
Some other things I looked at:
As suggested by #jason-aller, https://www.redblobgames.com/grids/hexagons/#rounding. Unfortunately, this seems to assume some form of transformation on the hex grid (rotations) and is not easy to follow - continually referencing functions which have yet to be defined.
QuadTree (various implementations) unfortunately, this returned approximately 100 "potential matches" for each point - so the performance improvement was not good. I'm aware that insertion order changes how useful QuadTree is, I tried natural order, sorted by distance from top, left and shuffled, they all performed equally badly. It's likely that an optimal solution with QuadTree would involve populating the tree with the item closest to the mid point, then the items 1/2 from the mid point to each corner, recursively. Too much like hard work for me!

Concept of a sript to calculate mouse velocity

Hi guys:)Could someone explain me this code?I am trying to understand but there is nothing to do.Why this line of code?
Math.sqrt(x_dist*x_dist+y_dist*y_dist)/interval;
Isn't sufficent this?
x_dist+y_dist/interval;
I don't understand the concept of this code...
https://jsfiddle.net/vnodkumar1987/ER8qE/
The first example calculates the hypotenuse, and in so doing achieves an absolute velocity value of the mouse vector.
The second example will give a bad result unless both x_dist and y_dist are positive. In other words, if you were moving down and left, or up and right, the second example would have a subtractive effect, and not represent the true overall velocity. In the case of up and left, the velocity would not only be proportionately incorrect (only useful for comparison purposes), but also result negative sign that you would have to account for. (I am assuming 0,0 represents the upper left of the mouse-able area and x_max,y_max to be the lower right.)
The Math.sqrt may not be necessary if you are just scaling proportionate velocity, but it certainly is if you want to know true pixels/interval. You would also have to take into account how big a variable container you are working with, but I'm sure it would all fit into a double... unless you were looking for extreme precision.
Imagine you travel in a straight line so that you end up at a point 3 miles West, and 4 miles South in exactly 1 hour. The velocity answer is not 3+4=7 miles per hour, nor is it-3+4=1 miles per hour. The correct answer of absolute velocity is the hypotenuse, which would be 5 mph. sqrt(west^2+south^2)
Example #1 would be the proper code. Example #2 could be roughly used if you can ignore the sign, and you needed the code to execute very quickly.
The velocity is distance_travelled/time_taken.
Say the pointer moves from (x1,y1) to (x2,y2) as shown in the figure above. The distance travelled is not the sum of the x and y distances.
Summing up x and y assumes that the pointer went from (x1,y1) to (x2,y1) and then from (x2,y1) to (x2,y2). i.e. the sum of the lengths of the 2 blue lines. But what you need is the length of the black line.
The actual distance travelled is d as shown in the figure. Using Pythagorean theorem, d^2 = x_dist^2 + y_dist^2.
Which leaves you with the line of code you have in the question for the speed
Math.sqrt(x_dist*x_dist+y_dist*y_dist)/interval;
You are making a pythagorean triangle with the two catethus being x_dist and y_dist, which are the distance the mouse moved in each of X and Y axis each frame. What that line of code does is to get the magnitude of the delta position vector of the mouse and divide it by some scalar value.
Also, note that sqrt(a^2 + b^2) does NOT equal a + b.
EDIT: Not velocity, but delta position.

Formula to Mimic 3D Distance in 2D Space?

I'm working on a simple 2D game, and am trying to mimic a 3D perspective (similar to many early games like Monkey Island). I've searched SO for awhile now and everything seems to be dealing with 3D. Does anyone happen to know the formula I would use to scale a DIV down as it moves up (away) from the camera?
Thanks!
In Monkey Island the backgrounds are 2D images with varying degrees of perspective. How a character is scaled depends on the perspective of the background. In some scenes the character only moves across the screen and so no change of scale is needed for the character. In some the character may move down a street and there is a high level of perspective. In some the character may move within a room and there is a small level of perspective.
Calculations regarding the scaling of the character needs to be calculated for each background scene. Perspective lines need to be drawn on the background and lengths measured.
The two examples below show how the scale for the character could be calculated.
In each case the scaling is based on the character as it is currently positioned on the screen. The variable y is a measure of how far the character is from its SMALLEST size position in the vertical direction. The variable h is a measure of the change in height of the character depending of y.
In the room scene the scale is > 1 since the character is currently at the back of the scene.
In the street scene the scale is < 1 since the character is currently at the from of the scene.
Triangular diagrams NOT to scale
I'm not sure what a DIV (I have no JavaScript experience) is but these links may help.
Perspective Projection
Walks you through the math used in perspective projections and includes some sample code (not JavaScript however).
3D Perspective Projection
Another page on perspective projection, with example code in C++.
I would do it like this:
// equation for objects appearing the same size
h=d*tan(α)
// now the scaling the size for arbitrary object
scale d h
1.0 d0 h0 // object with no scaling
0.5 2.0*d0 h0 // half size
0.25 4.0*d0 h0 // quoter size
0.5 d0 0.5 *h0
0.25 d0 0.25*h0
// so scale is:
scale = (d0/d)*(h/h0) // or
scale = (d0*h)/(d*h0)
set d0,h0 constants according to your view
d0 controls the magnification and h0=d0*tan(α)
If your camera has different view angle between axises then you have to apply two scaling factors
one for x axis and one for y axis
computed in the same way, but different angle used
d0 would be the same for both
Usual camera view angles in 3D are 60 or 90 degrees but in this case I would use 30 degrees
if you also view the underground then 60 with camera axis on the ground
In a true perspective projection, the scaling factor is given by S(D) = Df / D, where Df is the depth from the viewer to the full-size object and D the current depth.
For example, if a character is 40 pixels high and 16 large when seen in the foreground (assume 3m from the viewer), it will be 20 by 8 pixels at a depth of 6m and 10 by 4 at 12m.
Closer than the reference distance will result in magnification (80 by 32 at 1.5m).
[If your objects are located with (X, Y, Z) coordinates, X horizontal, Y vertical, Z perpendicular to the screen, pointing to the back, and is 0 at the depth of the screen, you have D = Z + Df and S(D) = Df / (Df + Z).]
Since you are talking about transforming a DIV then you should see CSS transforms. There are 2D transforms and 3D transforms. Keep in mind about the perspective attribute too ;)
Here you can find some examples:
http://desandro.github.io/3dtransforms/docs/perspective.html
http://24ways.org/2010/intro-to-css-3d-transforms/
http://dev.opera.com/articles/understanding-3d-transforms/
http://css-tricks.com/almanac/properties/t/transform/
http://css-tricks.com/almanac/properties/p/perspective/
http://css-tricks.com/almanac/properties/p/perspective-origin/

Rotate a line from one exact point to another

I need to mimic an angled line being drawn between two html elements using another html element that's essentially flat (1 px height by 200 px wide) like a line. Here's an example.
In this example, I hard-coded the angle of the line using the CSS skewY transform to make the lines angle at roughly 10px intervals. The problem is I need to do this dynamically using javascript. While already knowing the origin and destination points, I'll be using jQuery to style the line using skewY which requires a number in degrees.
How does one figure out the angle of the skew in order to have it start and end at 2 exact pixel points? I'm guessing they'll be some algebra involved.
Thanks!
Mark
Given the known starting point, and the known ending point, and the fact that each line appears to be the longest side of a right angle triangle, I would think a bit of trigonometry could come into play.
Assumptions would be that you know the x distance between the start and the end (in your code 'one' and 'two') i.e. the horizontal - call this the adjacent, and that you should be able to establish the distance from the top (the distance from the first two, to nth two), call this the opposite then one could establish the angle (lets call it x) by SOHCAHTOA being the TOA part (or TAN angle = Opposite over adjacent) or TAN x = O/A or x = tan -1 (O/A). If I remember correctly the angle will be in radians, so will need to be converted to degrees (multiple by 180/pi)
Sample code
var O = //to be set
var A = //to be set
var x = Math.atan(O/A) * (180 / Math.PI)

Categories

Resources