I'm rendering a grid of flat-topped hex tiles onto a HTML5 canvas. Placement and picking work flawlessly. At all times, the whole grid should be visible.
For this I calculate the minimum rectangle containing all hexagons completely and use its height and width to calculate the canvas size (letterboxed). To calculate the size I use the same coordinates I use to pick and layout the tiles and calculate:
tile_width = 2 // 2 * distance center-corner
tile_height = 1.7320508075688772 // sqrt(3) * distance center-corner
horiz_dist = 1.5 // 3/4 * tile_width
width = 1/4 * tile_width + number_x_tiles * horiz_dist
height = 1/2 * tile_height + number_y_tiles * tile_h
aspect = width/height
However, the displayed tiles are distorted, they are stretched in x-direction. Is there anything wrong with my formula? The measurements were derived as the fantastic redblob games resource describes it.
I'm pretty sure the function that applies x- and y-scaling depending on the aspect ratio works fine, as orthogonal maps look exactly as they should.
From your post, you seem to want a flat-topped grid. Given the information from your link,
tile_width = size * 2 = 2
tile_height = sqrt(3) * size = sqrt(3)/2 * tile_width = sqrt(3)
horiz_dist = (tile_width + size) / 2 = tile_width * 3/4 = 1.5
where size = 1 is the length of the edge of the hexagon.
Defining number_x_tiles as being the number of odd columns and even columns in the grid, your computation for the grid width is correct:
width = tile_width + (number_x_tiles - 1) * horiz_dist
= tile_width + (number_x_tiles - 1) * tile_width * 3/4
= tile_width - tile_width * 3/4 + number_x_tiles * tile_width * 3/4
= 1/4 * tile_width + number_x_tiles * horiz_dist
So the problem is in computing the grid height. Your formula
height = 1/2 * tile_height + number_y_tiles * tile_height
is correct when the number of rows of hexagons in an odd column is the same as an even column (by convention say the first column is the even column and the second column is odd). If not, then you need to determine whether there are more rows of hexagons in the odd column versus even column. Therefore, the logic should be:
if (num_rows_in_odd_column == num_rows_in_even_column)
height = 1/2 * tile_height + number_y_tiles * tile_height
else
number_y_tiles = max(num_rows_in_odd_column, num_rows_in_even_column)
height = number_y_tiles * tile_height
Hope this helps.
Related
This question was migrated from Stack Overflow because it can be answered on Mathematics Stack Exchange.
Migrated 24 days ago.
I have a position vector and a normal vector that describes a plane. The plane is always orthogonal to the position vector. On this plane is a circle with its center at the position vector. How do I generate a random point on that circle with a given radius r? I know that in 2d space, I can do
x = cos(2 * PI * random) * radius
y = sin(2 * PI * random) * radius
but... I don't know how to translate that to a circle on a plane.
I tried to find a way to use the position vector and normal vector to generate points, but I just can't think of a correct way to do so. I might not be familiar enough with planes.
At first we need two base vectors in the circle plane.
The first one is arbitrary vector orthogonal to normal n:
Choose component of normal with the largest magnitude, then component with the second magnitude.
Exchange their values, negate the largest, and make the third component zero (note that dot product of result with normal is zero, so they are othogonal)
For example, if n.y is the largest and n.z is the second, make
v = (0, n.z, -n.y)
Then calculate the second base vector using vector product
u = n x v
Normalize vectors v and u (make unit magnitude).
Now we can generate a random point on circumference using center point c (your position, I think):
rho = 2 * PI * random
f.x = c.x + radius * v.x * cos(rho) + radius * u.x * sin(rho)
f.y = c.y + radius * v.y * cos(rho) + radius * u.y * sin(rho)
f.z = c.z + radius * v.z * cos(rho) + radius * u.z * sin(rho)
I need your help to create a code that allows me to project points in a circular grid, divided into segments and levels. I'm asking for your help, because I know that this community is full of great people.
What I would like to do is
create a circle in a Cartesian plane; the coordinates of its centre point must be x=300 and y=300 and its radius r=300;
after constructing the circle, I need to divide it into portions. I need to construct a grid similar to the one you see below, but with 16 segments (with 16 labels, e.g. sector_1 to sector_16) and 5 levels or concentric circles (with 5 labels, e.g. level_1 to level_4 + level_0 for the central circle). So I would need to construct 5 concentric circles and divide the second, third, fourth and fifth into 16 segments. My aim is to obtain a series of regions in which a point could fall;
after constructing this grid, I need to project in it some points that I have and of which I have the x and y coordinates (e.g. point_1 -> x=286; y=342);
R should return to me in which segment and at which level the point is located.
Please, how can I develop code that allows me to do this?
Any help is so welcome and helpful.
Thank you very much for your attention.
You can draw the grid like this:
t <- seq(0, 2 * pi, length = 1000)
plot(300, 300, xlim = c(0, 600), ylim = c(0, 600))
for(i in 0:4) {
lines((300 - (i * 60)) * sin(t) + 300, (300 - (i * 60)) * cos(t) + 300)
}
for(i in 0:7) {
lines(300 * sin(c(i * pi /8, i * pi / 8 + pi)) + 300,
300 * cos(c(i * pi /8, i * pi / 8 + pi)) + 300)
}
To calculate in which segment the point has landed, you calculate the distance from the centre of the circle and find the whole number of 60s this exceeds
sqrt((x - 300)^2 + (y - 300)^2) %/% 60
To find out which segment it belongs in, you need to find its polar angle, which you can get by:
atan2((y - 300), (x - 300))
And you can determine which segment this represents by finding the number of pi/8 it exceeds:
atan2((y - 300), (x - 300)) %/% pi/8
Within a 2D infinite space, I have two circular sprites that represent massive bodies in outer space.
Each body has a pair of x, y coordinates, a mass, a speed and a direction (in radians).
On each frame of animation, I'm running the following code for each body (where this is the body being updated, and other is the other body):
x, y = other.x - this.x, other.y - this.y
angle = atan2(y, x)
distance = root(square(x) + square(y))
force = this.mass * other.mass / square(distance)
Note: I'm ignoring G as it's just a multiplier.
I know how to move the bodies around, based on their coordinates, speed and direction, but do not know how to update this.speed and this.direction to simulate gravity.
The gravitational force acting on a given body is represented as a vector and produces acceleration with components (ax and ay), which are calculated (based on what you already have) like this:
squared_distance = square(x) + square(y)
distance = sqrt(squared_distance)
accel = other.mass / squared_distance
ax = accel * x / distance
ay = accel * y / distance
Note that the angle (force/acceleration direction) is not needed.
Each body should have an associated velocity (instead of speed), which should be a two-component vector (vx and vy). It is updated like this (where dt is the time interval between updates):
this.vx += ax * dt
this.vy += ay * dt
Once the velocity of a given body has been updated, it can then be repositioned (updating its x, y coordinates) like this:
this.x += this.vx * dt
this.y += this.vy * dt
You can calculate the speed and direction if you need them, but they are not needed here.
Essentially I want to make a rectangular plane face an object at all times.
1) I have found my plane equation (ax + by + cz + d = 0)
2) I have the center point of the rectangle (P0 = (x0,y0,z0)), which lays on the plane.
3) I have the width and Height of the rectangle. (W, H)
4) I know that the top two corners of the rectangle will have equal Y values, this goes for bottom 2 corners also. (Y is my up and down axis, the rectangle top and bottom lines will always be parallel to the x,z plane)
Does anyone know how to find the x,y,z values of the four corners C1,C2,C3,C4?
Compute the vector from your plane center to the object you want to face. Call that vector V. Then normalize(V) = (a, b, c) and d = - a*x0 - b*y0 - c*z0. You have the equation for your plane.
Now you can rotate the plane however you want. If you to have the plane to have 0 roll (that is, only ever modify yaw and pitch), you can take the normalized cross product of the world "up" vector (0,0,1) and normalize(V) to get the horizontal vector U for the rectangle. Take the normalized cross product of normalize(V) and U to get the vertical vector W for the rectangle.
The corners of your rectangle are now:
C1 = P0 + (width / 2) * U + (height / 2) * W
C2 = P0 + (width / 2) * U - (height / 2) * W
C3 = P0 - (width / 2) * U + (height / 2) * W
C4 = P0 - (width / 2) * U - (height / 2) * W
Note that this approach has a singularity when the rectangle is directly above or below the object it is supposed to face. You should check for that if appropriate and handle it however makes sense in your scenario.
I need an algorithm which will determine the maximum scale increase that is possible for an image.
The rules (size limitation of a BitmapData object for the Flash Player, but this is not a Flash question):
both the width and length of the image must be less than 8,191 pixels
the maximum number of pixels in the image can not exceed 16,777,215
therefore, as mentioned in the documentation:
if a BitmapData object is 8,191 pixels
wide, it can only be 2,048 pixels
high.
In my code, I first determine if any of these rules are broken and throw and error if they are. this lets me know that any image that is loaded and does not throw an error has scalability.
The image I'm using is 2514 width x 1029 height. This image will not throw an error since both width and height are less than 8,191 and it's pixel count, or width multiplied by height, is less than 16,777,215.
I identify as being right-brained and don't have much confidence in my math skills, but the following is what I've come up with to determine the maximum allowed scale for the image.
private static const MAX_BITMAP_MEASUREMENT:uint = 8191;
private static const MAX_BITMAP_PIXELS:uint = 16777215;
var imageWidth:uint = 2514;
var imageHeight:uint = 1029;
var roughScaleUp:Number = 1.0 / Math.max(imageWidth, imageHeight) * MAX_BITMAP_MEASUREMENT;
var scaleBack:Number = Math.max(Math.min(imageWidth, imageHeight) * roughScaleUp - MAX_BITMAP_PIXELS / MAX_BITMAP_MEASUREMENT, 0);
var maxScale:Number = 1.0 / (Math.max(imageWidth, imageHeight) + scaleBack) * MAX_BITMAP_MEASUREMENT;
This code outputs the maximum scale for my image as 2.145144435977516, but I tested it and there is still a lot of pixel space remaining, so it should be able to be scaled up more and I'm pretty sure my code is terribly wrong.
Any math wizards on here care to help out a lowly art school graduate? I'm fully ready to accept that there is probably a much more simplistic solution to this problem and I'm prepared for the lashings.
You have to multiply both the width and the height by a constant, and the scaled result of the multiplication should be less than 16777215.
So
a^2 * w * h == 16,777,215
Which yields, for your values of w and h
a = 2.5466520486244177 [= Sqrt(16,777,215 / (w*h)) ]
So , for your values for the new w and h, you get:
NewW = a * w = 6402.283250241786
NewH = a * h = 2620.5049580345258
... just round them down :)
Well, here is an ugly solution. I couldn't get the rounding quite right, so I brute forced over the 4 possibilities to get the optimal value. The code should be straightforward enough to understand:
from math import *
def opt_image(w, h):
aspect = w / h
if aspect >= 1:
v = min(sqrt(1677215 / aspect), 8191)
a, b = floor(aspect * v), floor(v)
area, nw, nh = max([ ( (a+x)*(b+y), (a+x), (b+y) ) for x in range(2) for y in range(2) if (a+x)*(b+y) < 1677215 ])
return nw, nh
a, b = opt_image(w, h)
return b, a
For your example with width 2514, height 1029; I got:
(1831.0, 916.0)