Creating X and Y axis for a game - math

Recently I was thinking about creating my own axis x/y, especially 'x', but in that game in which I want to create it, there are no values below 0, because pointX = 0 is on left screen border.
I want to create function which will smoothly count all values depends on our game resolution X.
For example:
parameters: min value, max value, screenX, cursorPosition
if(cursorPosition == screenWidth/2) then
return 0
end
When cursor position is below screenWidth/2, function will smoothly count value between -0 and min value (min value will be, when cursor position = 0)
and the same when cursor pos is above screenWidth/2, function will smoothly count value between 0 and max value (max value will be when cursor position = our screenX)
Can anyone explain to me, how can I reach an effect like that? :)
Regards

use linear interpolation to change the dynamic range. Let assume your view has xs,ys resolution and point (0,0) is top left corner. so the dynamic range per each axis is:
x = <0,xs-1>
y = <0,ys-1>
and you want to change it to:
x' = <minx,maxx>
y' = <miny,maxy>
So do this:
x' = minx + x*(maxx-minx)/(xs-1)
y' = miny + y*(maxy-miny)/(ys-1)
and if you need to go back for any reason:
x = (x'-minx)*(xs-1)/(maxx-minx)
y = (y'-miny)*(ys-1)/(maxy-miny)
where (minx,miny) is top left corner and (maxx,maxy) is bottom right corner. If you want to change also the sign of any axis then you can as minx<maxx is not required for this so just swap the initial values so minx>maxx.
Not coding in lua but If your values are floating then beware integer rounding while mixing integers and floats together.

Related

How can I seamlessly wrap map tiles around cylindrically?

I'm creating a game that takes place on a map, and the player should be able to scroll around the map. I'm using real-world data from NASA as a 5700 by 2700 pixel image split into 4 smaller ones, each corresponding to a hemisphere:
How I split up the image:
The player will be viewing the world through a camera, which is currently in a 4:3 aspect ratio, which can be moved around. Its height and width can be described as two variables x and y, currently at 480 and 360 respectively.
Model of the camera:
In practice, the camera is "fixed" and instead the tiles move. The camera's center is described as two variables: xcam and ycam.
Currently, the 4 tiles move and hide flawlessly. The problem arises when the camera passes over the "edge" at 180 degrees latitude. What should happen is that the tiles on one side should show and move as if the world was a cylinder without any noticeable gaps. I update xcam by doing this equation to it:
xcam = ((xcam + (2700 - x) mod (5400 - x)) - (2700 - x)
And the tiles' centers update according to these equations (I will focus only on tiles 1 and 2 for simplicity):
tile1_x = xcam - 1350
tile1_y = ycam + 650
tile2_x = xcam + 1350
tile2_y = ycam + 650
Using this, whenever the camera moves past the leftmost edge of tile 1, it "skips" and instead of tile 1 still being visible with tile 2 in view, it moves enough so that tile 2's rightmost edge is in the camera's rightmost edge.
Here's what happens in reality: ,
and here's what I want to happen: .
So, is there any way to update the equations I'm using (or even completely redo everything) so that I can get smooth wrapping?
I think you unnecessarily hard-code a number of tiles and their sizes, and thus bind your code to those data. In my opinion it would be better to store them in some variables, so that they can be easily modified in one place if data ever changes. This also allows us to write a more flexible code.
So, let's assume we have variables:
// logical size of the whole Earth's map,
// currently 2 and 2
int ncols, nrows;
// single tile's size, currently 2700 and 1350
int wtile, htile;
// the whole Earth map's size
// always ncols*wtile and nrows*htile
int wmap, hmap;
Tile tiles[nrows][ncols];
// viewport's center in map coordinates
int xcam, ycam;
// viewport's size in map coordinates, currently 480 and 360
int wcam, hcam;
Whenever we update the player's position, we need to make sure the position falls within an allowed range. But, we need to establish the coordinates system first in order to define the allowed range. For example, if x values span from 0 to wmap-1, increasing rightwards (towards East), and y values span from 0 to hmap-1, increasing downwards (toward South), then:
// player's displacement
int dx, dy;
xcam = (xcam + dx) mod wmap
ycam = (ycam + dy) mod hmap
assures the camera position is always within the map. (Assumed the mod operator always returns non-negative value. Should it work like the C language % operator, which returns negative result for negative dividend, one needs to add a divisor first to make sure the first argument is non-negative: xcam = (xcam + dx + wmap) mod wmap, etc.)
If you'd rather like to have xcam,ycam = 0,0 at the center of a map (that is, at the Greenwich meridian and the equator), then the allowed range would be -wmap/2 through wmap/2-1 for x and -hmap/2 through hmap/2 - 1 for y. Then:
xcam = (xcam + dx + wmap/2) mod wmap - wmap/2
ycam = (ycam + dy + hmap/2) mod hmap - hmap/2
More generally, let x0, y0 denote the 'zero' position of camera relative to the upper-left corner of the map. Then we can update the camera position by transforming it to the map's coordinates, then shifting and wrapping, and finally transforming back to camera's coordinates:
xmap = xcam + x0
ymap = ycam + y0
xmap = (xmap + dx) mod wmap
ymap = (ymap + dy) mod hmap
xcam = xmap - x0
ycam = ymap - y0
or, more compactly:
xcam = (xcam + dx + x0) mod wmap - x0
ycam = (ycam + dy + y0) mod hmap - y0
Now, when we know the position of the viewport (camera) relative to the map, we need to fill it with the map tiles. And a new decision must be made here.
When we travel from Anchorage, Alaska (western hemisphere) to the North, we eventually reach the North Pole and then we'll find ourselves in the eastern hemisphere, headin South. If we proceed in the same direction, we'll get to Kuusamo, Norway, then Sankt Petersburg, Russia, then Kiev, Ukraine... But that would be a travel to the South! We usually do not describe it as a next part of the initial North route. Consequently, we do not show the part 'past the pole' as an upside-down extension of a map. Hence the map should never show tiles above row number 0 or below row nrows-1.
On the other hand, when we travel along circles of latitude, we smoothly cross the 0 and 180 meridians and switch between the eastern and western hemisphere. So if the camera view covers area on both sides of the left or right edge of the map, we need to continue filling the view with tiles from the other end of the tiles array. If we use a map scaled down, so that it is smaller than the viewport, we may even need to iterate that more than once!
The left edge of a camera view corresponds to the 'longitude' of xleft = xcam - wcam/2 and the right one to xrght = xcam + wcam/2. So we can step across the viewport by the tile's width to find out appropriate columns and show them:
x = xleft
repeat
show a column at x
x = x + wtile
until x >= xrght
The 'show a column at x' part requires finding appropriate column, then iterating across the column to show corresponding tiles. Let's find out which tiles fit the camera view:
ytop = ycam - hcam/2
ybot = ycam + hcam/2
y=ytop
repeat
show a tile at x,y
y = y + htile
until y >= ybot
To show the tile we need to locate appropriate tile and then send it to appropriate position in the camera view.
However, we treat column number differently from the row number: columns wrap while rows do not:
row = y/htile
if (0 <= row) and (row < nrows) then
col = (x/wtile) mod ncols
xtile = x - (x mod wtile)
ytile = y - (y mod htile)
display tile[row][col] at xtile,ytile
endif
Of course xtile and ytile are our map-scale longitude and latitude, so the 'display tile at' routine must transform them to the camera view coordinates by subtracting the camera position from them:
xinwiev = xtile - xcam
yinview = ytile - ycam
and then apply the resulting values relative to the camera view's center at the displaying device (screen).
Another level of complication will appear if you want to implement zooming in and out the view, that is dynamic scaling of the map, but I'm sure you'll find out yourself which calculations will need applying the zoom factor for correct results. :)

determine if a point is left or right from another point on a circle in 3d space?

I want to determine if a point from another point on a circle in the left section or in the right section. (left & right just a matter of sign interpretaton). For that I have calculated the cross product of those two points for creating the normal vector.
So the problem which I am facing is how I can interpret the normal as an scalar which has a sign which indicates whether its in the right or in the left half of the circle.
I have created a gif as for illustration (C' is just the animated point C):
My idea was to add all values within the vector v. For instance:
v = (0.16, 0.1, -0.2)
vSum = v.x + v.y + v.z = 0.06
result = sign(vSum) = 1
o = (-0.16, -0.1, 0.2)
oSum = o.x + o.y + o.z = -0.06
result = sign(oSum) = -1
unfortunately this does only work if the circle is static and does not rotate. If its rotating the sign changes so my result is flipped which leads to reversed left and right sites. And the dot product results positive values only, but this is a value which doesnt changes while rotating the circle. Maybe this is something which can help me ?
I assume, your cross product is the following:
c = cross(p - circle center, reference - circle center)
Then you can take the dot product with the circle normal to get the sign:
sign(dot(c, circle normal))

Screen coordinates to isometric coordinates

I'm struggling at converting mouse/screen coordinates to isometric tile index. I have tried about every formula I could find here or on internet but none of them seems to work or I am missing something.
Here is a picture, origin is in the top left corner and dimensions of one tile are 128x64px.
I would appreciate any help, thanks.
Basically, you need to apply a rotation matrix with a few other bits. Here's some sample code written in AWK which should be easy to port to any other language:
END {
PI = 3.1415;
x = 878.0;
y = 158.0;
# Translate one origin to the other
x1 = x - 128*5;
# Stretch the height so that it's the same as the width in the isometric
# This makes the rotation easier
# Invert the sign because y is upwards in math but downwards in graphics
y1 = y * -2;
# Apply a counter-clockwise rotation of 45 degrees
xr = cos(PI/4)*x1 - sin(PI/4)*y1;
yr = sin(PI/4)*x1 + cos(PI/4)*y1;
# The side of each isometric tile (which is now a square after the stretch)
diag = 64 * sqrt(2);
# Calculate which tile the coordinate belongs to
x2 = int(xr / diag);
# Don't forget to invert the sign again
y2 = int(yr * -1 / diag);
# See the final result
print x2, y2;
}
I tested it with a few different coordinates and the results seem correct.
I tried the solution by acfrancis and I found that the function has its limits when it comes to negative indices. Just in case someone else will tackle this issue:
Reason for issue: negative values like -0.1.... will be cast to 0 instead of -1.
Its the classic "there is only one zero" problem for arrays.
To solve it: before casting the x2, y2 values to int:
check if xr/diag < 0 and, if true, result = result - 1
(respectively for y2: yr * -1 / diag < 0 then result = result -1)
you then cast the result values to int like before.
Hope it helps.
Addition:
The translation of the origin by 128*5 seems to specific to a certain case so i guess this should be removed in order to generalize the function.

How to calculate the z-distance of a camera to view an image at 100% of its original scale in a 3D space

How can one calculate the camera distance from an object in 3D space (an image in this case) such that the image is at its original pixel width.
Am I right in assuming that this is possible given the aspect ratio of the camera, fov, and the original width/height of the image in pixels?
(In case it is relevant, I am using THREE.js in this particular instance).
Thanks to anyone who can help or lead me in the right direction!
Thanks everyone for all the input!
After doing some digging and then working out how this all fits into the exact problem I was trying to solve with THREE.js, this was the answer I came up with in JavaScript as the target Z distance for displaying things at their original scale:
var vFOV = this.camera.fov * (Math.PI / 180), // convert VERTICAL fov to radians
var targetZ = window.innerHeight / (2 * Math.tan(vFOV / 2) );
I was trying to figure out which one to mark as the answer but I kind of combined all of them into this solution.
Trigonometrically:
A line segment of length l at a right angle to the view plane and at a distance of n perpendicular to it will subtend arctan(l/n) degrees on the camera. You can arrive at that result by simple trigonometry.
Hence if your field of view in direction of the line is q, amounting to p pixels, you'll end up occupying p*arctan(l/n)/q pixels.
So, using y as the output number of pixels:
y = p*arctan(l/n)/q
y*q/p = arctan(l/n)
l/tan(y*q/p) = n
Linear algebra:
In a camera with a field-of-view of 90 degrees and a viewport of 2w pixels wide, the projection into screen space is equivalent to:
x' = w - w*x/z
When perpendicular, the length of a line on screen is the difference between two such xs so by normal associativity and commutivity rules:
l' = w - w*l/z
Hence:
w - l' = w*l/z
z = (w - l') / (w*l)
If your field of view is actually q degrees rather than 90 then you can use the cotangent to scale appropriately.
In your original question you said that you're using css3D. I suggest that you do the following:
Set up an orthographic camera with fov = 1..179 degrees, where left = screenWidth / 2, right = screenWidth / - 2, top = screenHeight / 2, bottom = screenHeight / - 2. Near and far planes do not affect CSS3D rendering as far as I can tell from experience.
camera = new THREE.OrthographicCamera(left, right, top, bottom, near, far);
camera.fov = 75;
now you need to calculate the distance between the camera and object in such way that when the object is projected using the camera with settings above, the object has 1:1 coordinate correspondence on screen. This can be done in following way:
var camscale = Math.tan(( camera.fov / 2 ) / 180 * Math.PI);
var camfix = screenHeight / 2 / camscale;
place your div to position: x, y, z
set the camera's position to 0, 0, z + camfix
This should give you 1:1 coordinate correspondence with rendered result and your pixel values in css / div styles. Remember that the origin is in center and the object's position is the center of the object so you need to do adjustments in order to achieve coordinate specs from top-left corner for example
object.x = ( screenWidth - objectWidth ) / 2 + positionLeft
object.y = ( screenHeight - objectHeight ) / 2 + positionTop
object.z = 0
I hope this helps, I was struggling with same thing (exact control of the css3d scene) but managed to figure out that the Orthographic camera + viewport size adjusted distance from object did the trick. Don't alter the camera rotation or its x and y coordinates, just fiddle with the z and you're safe.

Drawing ECG in VB6.0

Whether is it possible to draw ECG in VB6.0? As i am not that much familiar with VB any type of help will be appreciated.Please help me .thanks in advance.
The simplest method to do this is to use a picture box with the AutoRedraw property set to true and the ScaleMode set to vbPixels.
For each point, you calculate the Y value (dependant on the minimum and maximum allowable values). To make it scan, just increment the X value for each point you draw wrapping back to 0 when it gets to the width of the picture box (.ScaleWidth).
You can use the picture box's .Line method to blank the areas behind the current X point and the .PSet method to draw the new point.
Dim X As Long
Dim LastValue As Long
Private Sub AddPoint(ByVal Value As Long)
'Clear the line behind (for 5 pixels forward)
Picture1.Line (X, 0)-(X + 5, Picture1.ScaleHeight), vbBlack, BF
'Draw the new point and the line from the previous point
Picture1.Line (X - 1, LastValue)-(X, Value), vbGreen
Picture1.PSet (X, Value), vbGreen
'Update the last value so we can draw the line between them
LastValue = Value
'Increment the X value for the next point
X = X + 1
If X = Picture1.ScaleWidth Then X = 0
End Sub
A better method is to use an off screen picture that you update using a similar method and just update the picturebox when needed.

Resources