Defines a title using mouse cursor coordinates. Isometric social games - javascript

In the Social Isometric Games book, page 53, there is a description of the method, that defines a title using mouse cursor coordinates. It works well, but it is not clear what principles are used to make it work. Can someone explain this algorithm in details? Maybe you have some links to the formula. Or maybe you can advise me on which field of science i should look at.
Here is an example of a code that I am interested in:
var col = (e.clientY - gridOffsetY) * 2; //???
col = ((gridOffsetX + col) - e.clientX) / 2; //???
var row = ((e.clientX + col) - tile.height) - gridOffsetX; //???

As I can see, height of the rhombus cell is 2*p, width is 4*p, where p is characteristic size value.
Let's coordinates of base point - top vertice of top cell is (0, 0).
So top-right edge vector is tr=(2p, p), top-left vector is tl=(-2p, p).
Let's mouse point is (mx, my) relative to base point. To find what cell it belongs to, one could decompose vector (mx, my) by basis vectors tl, tr
mx = R * tl.x + C * tr.x
my = R * tl.y + C * tr.y
or
mx = R * 2 * p + C * p
my = R * (- 2 * p) + C * p
to find C , we can add both equations
mx + my = 2 * C * p
C = (mx + my) / (2 * p)
column = Floor(C) //integer part of C
to find R, subtract equations
R = (mx - my) / (4 * p)
row = Floor(R)
other calculations take into account shift of the grid on the screen

Related

Create a function that finds the points distanced r units by two lines

I have two lines defined by two points each(P1, P2, P3, P4).
I'd like to find the 2 points(X0, Y0) that are distanced r units from both lines.
I found a way but I think it's too long to solve(too difficult for me) and maybe there's one shorter(https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line).
my way:
Without solving it it's impossible tp create the function
I'd like to have the solution not the sistem.
Example(I'd like to find the yellow points knowing r):
Thanks.
(Sorry for my terrible english)
Variant A:
represent your lines in general form
a * x + b * y + c = 0
d * x + e * y + f = 0
with normalized coefficients (divide equation by Sqrt(a^2+b^2))
For this form point lies at distance r if
|a * x + b * y + c| = r
|d * x + e * y + f| = r
Open absolute value brackets with all possible +/- sign combinations and get 4 linear systems for 4 possible points
Variant B:
1) Find unit direction vectors of both lines da and db
2) Find intersection point C of two lines
3) Calculate angle between lines as
Fi = atan2(da.cross.db, da.dot.db)
4) Find unit bisector vector
b = (da + db).Normalized
5) Find perpendicular bisector
pb = (-b.y, b.x)
6) Get needed points as
C + b * r / Sin(Fi/2)
C - b * r / Sin(Fi/2)
C + pb * r / Cos(Fi/2)
C - pb * r / Cos(Fi/2)

Program to find line segment and bezier curve intersection

Consider the given image of the soccer field
As you can see in the image the various ball movements, some of them are curved(i.e. in case of (1), (2), (3) in the image)) and some may not(i.e a line(4)),
so I need to find the intersection points of ball path with goalline and sideline. Sometimes the input may not be a curve(i.e a line) like in case of (4) given image
I have written a program, I have no clue what is wrong - is this right way to solve this kind of program.
if yes then, how to convert bezier curve into an equation for better solving
considering the given as
beizer curve eqaution -> a(x*x) + b*x + c
and line segment equation -> y = y1 + m(x-x1)
//maxCurvedPoint is the topmost of the curve
var getIntersectionPoint = function (room, ballFromPosition, ballToPosition, maxCurvePoint)
{
var linepoints = [[m1,n1], [m2, n2], [m3, n3], [m4, n4]];
//converting three points(ballFromPosition, maxCurvePoint, ballToPosition) into the quadratic equation (Bezier curve) --(1)
//getting the equation of the line segment using the linepoints --(2)
//equating (1) and (2) and getting a quadratic equation and solving and finding intersection points
return intersectionPoint;
}
// solves //(-b(+-)sqrt(b*b - 4ac)/2ac)
function solve(a, b, c)
{
//check curve intersects line or not
if((Math.pow(b, 2) - (4 * a * c)) >= 0)
{
result1 = (-1 * b + Math.sqrt(Math.pow(b, 2) - (4 * a * c))) / (2 * a);
result2 = (-1 * b - Math.sqrt(Math.pow(b, 2) - (4 * a * c))) / (2 * a);
return [result1, result2];
}
return [];
}
Can anyone help me with this? Also is the most curve point can be called vertex of the curve?
I find it easier to work with vector equations since the algebra will be rotation-invariant (hence you don't have to re-write the code to deal with e.g. a "horizontal" parabola).
1. Curve representation + Intersection test
Consider a quadratic Bezier curve with endpoints A, C, control point B and parameter t:
And an infinite line with source O, direction D and parameter s:
Equating P and R give a pair of quadratic simultaneous equations, which can be re-arranged to eliminate s and find the parabolic parameter t:
Solve this quadratic equation for t, and only accept real roots in the range [0, 1]. This ensures that any intersection point is always on the segment itself.
2. Dealing with line segments
You can also restrict the intersection point to a line segment, by computing s from t using the equations above, and limiting its value - which equals the distance along the line from O if D is normalized.
3. Computing the control point B
Note that a general value of the control point B will not give a symmetrical parabola. To compute B for a general symmetric curve:
Defining the variables:
M: midpoint of AB
n: clockwise normal to the direction AC
q: signed bulge distance - absolute value is the distance from M to the midpoint of the curve
k: signed distance from M to B
A surprisingly simple result.
4. Sample C# (-style) code
public static Vector2[] computeIntersection
(
Vector2 A, Vector2 C, double q, // parabola segment
Vector2 O, Vector2 P // line segment
)
{
// quadratic solve
double[] solve(double a, double b, double c)
{
double d = b * b - 4.0 * a * c;
if (d < 0.0) // imaginary roots - no intersection at all
return null;
if (d > 0.0) // two distinct real roots
{
double sd = Math.Sqrt(d);
return new double[2] { (-b + sd) / (2.0 * a),
(-b - sd) / (2.0 * a) };
}
else // only one (line segment is tangent to curve)
{
return new double[1] { -b / (2.0 * a) };
}
}
// cross product (in-case undefined)
double cross(Vector2 i, Vector2 j)
{
return i.x * j.y - i.y * j.x;
}
// validity check for t and s
bool valid(double v)
{
return (v >= 0.0) && (v <= 1.0);
}
// compute control point B
Vector2 E = C - A;
Vector2 M = 0.5 * (A + C);
Vector2 N = (new Vector2(E.y, -E.x)).normalize();
Vector2 B = M + (2.0 * q) * N;
// solving for t
Vector2 D = P - O;
bool useX = Math.Abs(D.X) > Math.Abs(D.Y);
double[] T = solve(cross(A + C - 2.0 * B, D),
cross(B - A, D) * 2.0,
cross(A - O, D));
if (T == null) return null;
Vector2[] I = new Vector2[2];
int c = 0;
for (int i = 0; i < T.Length; i++)
{
// check if t is within curve range
double t = T[i];
if (!valid(t)) continue;
// solve for s and check if is within line range
double u = (1 - t) * (1 - t);
double v = 2 * t * (1 - t);
double w = t * t;
double s = useX ? ((u * A.X + v * B.X + w * C.X - O.X) / D.X)
: ((u * A.Y + v * B.Y + w * C.Y - O.Y) / D.Y);
if (!valid(s)) continue;
// compute the corresponding intersection point
I[c++] = O + s * D;
}
// only return valid solutions
if (c == 0) return null;
Array.Resize(ref I, c);
return I;
}
If you translate and rotate all the endpoints in such a way that the line segment becomes (0, 0)-(d, 0), the problem simplifies.
Let the control points be (Xk, Yk), k= 0, 1, 2. The intersections with the axis X are obtained by solving for t the quadratic equation
Y0 (1-t)² + 2 Y1 t(1-t) + Y2 t² = 0.
The corresponding abscissas are given by
X0 (1-t)² + 2 X1 t(1-t) + X2 t² = 0.
You can check if these belong to the interval [0, d]. Then apply the reverse rotation and translation.
Addendum: intersection of two quadratic Beziers
The vector equation of one of the curves can be written
P = P0 (1 - t)² + 2 P1 t (1 - t) + P2 t²
= P0 + 2 (P1 - P0) t + (P0 - 2 P1 + P2) t².
If you apply the affine change of coordinates such that the reference frame becomes (P0, P1 - P0, P0 - 2 P1 + P2), the equation simplifies to
X = 2t
Y = t²
which is the implicit equation
X² = 4Y.
Now by applying the same transform to the control points of the second curve and plugging the parametric equations in the above, you get a quartic equation in t (square of a quadratic polynomial on one side, quadratic polynomial on the other).
There are closed-form formulas for the roots of a quartic equation, and there can be four of them. After selecting the real roots in [0, 1], you evaluate the t parameter of the first curve and also check membership in [0, 1].
Don't forget to restore the original coordinates.

canvas spiral rise effect with turning points

There is a spiral rise effect as showed bellow: A demo can be found here: http://openlayers.org/en/latest/examples/dynamic-data.html
In the bottom of the demo page, an algorithm is used to implement this effect. But I can not figure out how does it work.
var t = theta + 2 * Math.PI * i / n;
var x = (R + r) * Math.cos(t) + p * Math.cos((R + r) * t / r);
var y = (R + r) * Math.sin(t) + p * Math.sin((R + r) * t / r);
What does R, r and p means? And how to understand the formula above? Can someone explain detail for me? Any help is appreciated.
I can recognize that code draws epicycloid curve (+ it's phase theta permanently changes to provide moving effect).
You can refer to R as radius of inner (here bigger) circle, p and r (equal values here) as radius of outer (here smaller) circle. Here r looks like radius of coil of toroidal spring.
The first summands correspond to the center of outer circle, the second ones - to the second-order rotation about outer circle center.
Play with these values and observe effects
Note that if you change p to make it not equal to r, you'll get epitrochoid curve (more general kind of epicycloid)

Rotating point by its form axe makes itself move to the left-top

Firstly, I need to rotate a single line about its own axe to be rendered in HTML5 canvas.I'm not actually rotating a line, but I'm rotating its points coordinates before I render it.
I've specific bounds which refers to the total size of what will be drawn in a path (e.g, the line), they're used to construct a point B, which is the center point of the path.
form.bx = x + (w / 2);
form.by = y + (h / 2);
Note: form is actually a path generated by my interface, it contains the rotation angle, etc.
Both of these functions rotates coordinates of a point and return them. Parameters:
x – the x coor. of the A point.
y – the y coor. of the A point.
c – the angle cosine (Math.cos(angle)).
s – the angle sine (Math.sin(angle)).
Bx – the x coor. of the point on which point A will be rotated about.
By – the y coor. of the point on which point A will be rotated about.
function rotatePointX(x, y, c, s, Bx, By) {
return Math.round(((Bx - x) * c) - ((By - y) * s));
}
function rotatePointY(x, y, c, s, Bx, By) {
return Math.round(((Bx - x) * s) + ((By - y) * c));
}
The problem: the rotation makes my line move to the left-top of the canvas.
Fiddle
My line should be in its specific position. What am I doing wrong? Thanks
Rotation always occurs relative to the origin, if you want to rotate relative to some other point you have to
move all your space so that the new origin is the point the rotation will occur about
perform the rotation
move all your space back to its original position
1)
x' = x - Bx
y' = y - By
2)
x'' = x' * cos(angle) - y' * sin(angle)
y'' = x' * sin(angle) + y' * cos(angle)
3)
x''' = x'' + Bx
y''' = y'' + By
To find the value of x''', y''' you have to replace 1 and 2 in 3
1 in 2:
x'' = (x - Bx) * cos(angle) - (y - By) * sin(angle)
y'' = (x - Bx) * sin(angle) + (y - By) * cos(angle)
2 in 3:
x''' = (x - Bx) * cos(angle) - (y - By) * sin(angle) + Bx
y''' = (x - Bx) * sin(angle) + (y - By) * cos(angle) + By
You can avoid all this mess by performing the transform doing matrix multiplication like so
[x'''] = [1 0 Bx] [cos(angle) -sin(angle) 0] [1 0 -Bx] [x]
[y'''] [0 1 By] [sin(angle) cos(angle) 0] [0 1 -By] [y]
[1 ] [0 0 1] [ 0 0 1] [0 0 1] [1]
The additional dimension is used to be able to perform translation since translation is a shearing mapping
https://jsfiddle.net/hnv0dcs6/2/

Perspective Coords for 2D Hex Grid

Here's a stumper...
Porting some old code, I have this 2D hex grid being rendered in 2.5D:
The y-scale & position of the tiles is calculated for perspective, but I'd like to scale & position them for perspective horizontally as well (the toons at the top of the board look squished). Here's the current code:
const SCALE_X = PixiStages.game._width * 0.0012;
const SCALE_Y = PixiStages.game._height * 0.0018;
this.scale.x = SCALE_X;
this.scale.y = SCALE_Y * ( 0.5 + 0.5 * gamePiece.y / Game.TILE_ROWS );
const getStageXFromBoardX = ( board_x ) => {
const tileWidth = SCALE_X * 38;
return board_x*tileWidth;
}
const getStageYFromBoardY = ( board_y ) => {
const tileHeight = SCALE_Y * 44;
return board_y*tileHeight/4 + board_y*board_y*tileHeight / (8*Game.TILE_ROWS);
}
Simply changing the x-scale to this.scale.x = SCALE_X * ( 0.5 + 0.5 * gamePiece.y / Game.TILE_ROWS ); looks like this:
... so I guess I just need an equation to set their x-position correctly.
Any ideas or links? Thanks!
Note that X-coordinate after perspective transformation depends both on X and on Y source coordinates. General expression
XPersp = (A * X + B * Y + C) / (G * X + H * Y + 1)
For your case (perspective sight along central axis) transformation of rectangle with corners (XCenter-W,0)-(XCenter +W, H) to trapezoid centered vertically at XCenter, shifted up by YShift, is:
XPersp = XCenter + (X - XCenter) / (H * Y + 1)
YPersp = (YShift + E * Y) / (H * Y + 1)
where H, E are some coefficients, adapted for good look.
Vary E (defines trapezoid height) about 0.5-2.0, H (defines trapezoid tilt) about 0.005

Categories

Resources