I am drawing a hexagonal grid using javascript and svg. The grid needs to have a fixed width (let's say, of 1000px). The dimensions of the grid can differ, but I have that information (the columns and rows). I have written a function that given a hexagons 'bounding box' width (the height is a factor 0.8660254 of the width), will calculate all 6 points and draw a polygon between them. I am staggering the x coordinate such that the polygons neatly connect.
However, the part I am stuck on currently is: How do I figure out the width of the polygons such that they take up the most available space on the canvas? I cannot simply do width of the canvas / number of columns because that doesn't take into account the staggering (see the image below)
How can I figure out how to stretch the hexagons such that they all fit and take up as much space as they can?
If you have C columns and hexagon side size (unknown yet) is x, we can write inequality:
x/2 + C*x*3/2 <= width
x*(1+3*C)>=2*width
x <= 2*width / (1+3*C)
So calculate the right part and get floored integer (if you need integer side)
For height with R rows:
x*sqrt(3)/2 + R*x*sqrt(3)/2 <= height
x <= 2*height / (sqrt(3) + R*sqrt(3))
Get min value from calculated sizes to fit both width and height
You need some trigonometry
Each Hexigon neighbor is at an increment of 60 degrees (pi/3) angle. Use cos (pi/3) * radius for the x location adjustment, and +/- sin (pi/3) * radius for height adjustment.
Related
I have an 2D grid made from 1D array with with and height property. In that grid I have a box object which I want to rotate by X amount of degrees.
I have used this formula to rotate each pixel of object in grid:
newX = floor(cos(angle)*x - sin(angle)*y)
newY = floor(sin(angle)*x + cos(angle)*y)
It works fine when the box is small but if the box is bigger I get some empty cells. How can I fill empty spaces witch should be filled.
Here is an example of box with width and height 10 and then rotated by 45 degrees:
Perform reverse mapping:
Walk through all pixels of result. You can use bounding box of rotated image and scan its lines.
For every pixel one get coordinates of corresponding source pixel. If they lie in valid range (source rectangle), then copy source color to result.
To get reverse mapping formula, just change angle sign (if you have pure rotation without shift)
oldx = cos(angle)*newx + sin(angle)*newy
oldy = -sin(angle)*newx + cos(angle)*newy
In the example in Leaflet (for non geographic image), they set "bounds". I am trying to understand how they computed the values
var bounds = [[-26.5,-25], [1021.5,1023]];
The origin is bottom-left and y increases upwards / x towards the right. How did negative numbers turn up here? Also, after experimentation, I see that the actual pixel coordinates change if you specify different coordinates for bounds. I have a custom png map which I would like to use but I am unable to proceed due to this.
Oh, you mean this image:
If you open the full file (available at https://github.com/Leaflet/Leaflet/blob/v1.4.0/docs/examples/crs-simple/uqm_map_full.png ) with an image editor, you'll see that it measures 2315x2315 pixels. Now, the pixel that represents the (0,0) coordinate is not at a corner of the image, but rather 56 pixels away from the lower-left corner of the image:
Similarly, the (1000, 1000) coordinate is about 48 pixels from the top-right corner of the image:
Therefore, if we measure pixel coordinates of the grid corners:
Game coordinate (0, 0) → Pixel coordinate (59, 56)
Game coordinate (1000, 1000) → Pixel coordinate (2264, 2267)
The problem here is finding the bounds (measured in game coordinates) of the image. Or, in other words:
Pixel coordinate (0, 0) → Game coordinate (?, ?)
Pixel coordinate (2315, 2315) → Game coordinate (?, ?)
We know that the pixel-to-game-coordinate ratio is constant, we know the image size and the distance to the coordinates grid, so we can infer stuff:
1000 horizontal game units = image width - left margin - right margin
or
1000 horizontal game units = 2315px - 56px - 48px = 2213px
therefore the pixel/game unit ratio is
2213px / 1000 game units = 2.213 px/unit
therefore the left margin is...
~59px = ~59px / (2.213px/unit) ~= 26.66 game units
...therefore the left edge of the image is at ~ -26.66 game units. Idem for the right margin...
~51px = ~51px / (2.213px/unit) = ~23.04 game units
...therefore the right edge of the image is at ~1023.04 game units
Repeating that for the top and bottom margins we can fill up all the numbers:
Pixel coordinate (0, 0) → Game coordinate (-26.66, -25)
Pixel coordinate (2315, 2315) → Game coordinate (1023.04, 1025)
Why don't these numbers match the ones in the example exactly? Because I might have used a different pixel for measurement when I wrote that Leaflet tutorial. Still, the error is negligible.
Let me remark a sentence from that tutorial:
One common mistake when using CRS.Simple is assuming that the map units equal image pixels. In this case, the map covers 1000x1000 units, but the image is 2315x2315 pixels big. Different cases will call for one pixel = one map unit, or 64 pixels = one map unit, or anything. Think in map units in a grid, and then add your layers (L.ImageOverlays, L.Markers and so on) accordingly.
If you have your own game map (or anything else), you should ask yourself: Where is the (0,0) coordinate? What are the coordinates of the image edges in the units I'm gonna use?
I am trying to find the best dimmensions for a container.
I have to work with these values:
Window max width
Window max height
Items to fit in each column
Items to fit in each row
Each item needs to be a square, and the container has to fit the items exactly. I also need the container to be as big as possible, without it getting larger than max width in x direction, and max height in y direction.
My current code, (Which does not really work), looks like this:
[dWidth, dHeight] = [window.innerWidth, window.innerHeight];
// Adjust sizes, for the tiles
var tiles = (width + height) / 2;
dSize = (dWidth / tiles) > (dHeight / tiles) ?
(dHeight / tiles) : (dWidth / tiles);
dSize |= 0,
dWidth = width * dSize,
dHeight = height * dSize,
dWidth is the width for the container I want to create
dHeight is the height for the container I want to create
width is the amount of columns I have
height is the amount of rows I have
dSize is the height and width of every item.
No need to worry about the weird dWidth assignment, it's temporary.
No need to worry about dSize |= 0, I will not get negative values.
No need to worry about the snippet ending with a comma, the next lines is just assigning the dWidth and dHeight to a canvas.
The number of squares you can fit horizontally is dWidth/width and the number you can fit vertically is dHeight/height. Therefore you can work out the maximum number that will fit like so:
var dSize = Math.min(dWidth/width, dHeight/height);
If you need an absolute value, go ahead and use Math.floor on the result.
I'm having a hard time figuring out the trigonometry for the following; I need to draw the outline of a circle with an opening in it of certain pixels in width. The circle can be of various radius but the opening should always be of the same size. In other words if the radius (r) is known and gap width (w) is known, how do you get the gap angle (a)?
I wish I could append an image but I'm not allowed as I don't have enough reputation points.
If
chordLength = 2 * radius * sin(angle/2)
Then with some algebra
angle = arcsin(chordLength/(2*radius))*2
http://mathworld.wolfram.com/CircularSegment.html
Manipulating the slider until the end, the circle that represents the star disappears or does a different motion. See: jsfiddle.net/NxNXJ/13 Unlike this: astro.unl.edu/naap/hr/animations/hrExplorer.html
Can you help me?? Thanks
When you supply a big luminosity, You're rendering a circle which is millions of pixels tall. The broswer might not render it because it's so big.
However, you are really only interested in a small slice of that big circle - namely, the bit that fits in your tiny window.
At some point, it doesn't make sense to increase the size of the circle, since you can't observe a change in the curvature of the circle - it just looks like a straight vertical line.
This apparent verticality occurs around when x^2 + y^2 = R^2, where R is the radius of the star, Y is half the height of your window, and x is R-1. Solve for R in terms of Y, and you get
function maximumNecessaryRadius(windowHeight){
y = windowHeight / 2;
maxRadius = (y*y - 1)/2;
return Math.round(maxRadius);
}
When resizing the star, check to make sure that its radius doesn't exceed the maximum necessary radius. Rendering it any larger than that is overkill.
Example Implementation