INTRO
I have an array of X/Y coordinates. This array generates an irregular polygon inside a square area of 128 x 128 pixels. So the value of the coordinates can be only a number from 0 to 127 (0,0 is the left top corner - 127,127 is the right bottom corner).
I have virtually divided this area in 4 small areas of 64 x 64 pixel each.
QUESTION
I would like to calculate 4 percentages where each percentage tells me how much the polygon is covering one of the small areas.
To be clear, I've this screenshot:
A, B, C and D area the small areas.
The red dots are the X/Y coordinates I have in an array.
The green area is the polygon virtually generated by the coordinates.
So, how to calculate the percentages of the areas covered by the polygon? For example, looking the screenshot, I would like to obtain that the A area is 40% covered, the B area is 5% covered, the C area is 15% covered, the D area is 80% covered.
Does anyone know a Javascript script that can perform this kind of calculation? Honestly, I'm not good in geometry!
Related
Tell me who knows about THREE.JS. I implement a map grid similar to the game SimCity 50x50. I rendered blocks of ground with different heights (as in the screenshot), now I want to smooth out the height transitions so that there is a smooth relief, while maintaining the 50x50 grid. As planned, everything should be like in the SimCity game: the user changes the type of landscape, change the relief of the landscape.
Image: How it looks now - Image: What I want to get
Implemented as follows: there is a json array where for each cell its XZ coordinates are listed for placement on a 50x50 map and a Y coordinate for the height of the land block, as well as the type of terrain (grass, earth, stone, etc.). Each block of land is a BoxGeometry.
There were thoughts to somehow add vertices to the upper side and smooth out the transitions by their positions, but I did not find this.
This could be accomplished with BlockGeometry objects, but that would be far more trouble than it's worth. For example, you'd have to analyze the surrounding terrain to know how to rotate the BlockGeometry to modify it correctly, and you might have to rotate it again when the terrain is edited. < That's not to mention the number of objects; at your size of 50×50, you'd be adding 2,500 objects to the scene. > A single mesh is much more natural in these circumstances.
First, notice that the map only comprises four cell shapes, not counting rotations: flat cells, cells that slope parallel opposite edges, cells that bend up to form a corner, and cells that bend down to form a corner.
Think of your terrain not as a set of blocks, but as one continuous surface quilted from square cells. Each cell is a mesh of four triangles.
Looking at a cell down the negative y-axis, starting at the top-left corner and moving clockwise around the cell, we'll label the vertices at the cell's corners a, b, c, and d. We'll place a fifth vertex, e, at the exact middle of the cell when viewed from this perspective. These vertices form four triangles, △abe, △bce, △cde, and △dae.
For any cell, the Y value that you're currently storing becomes the y-position of vertex a< e >.
To get the y-position of vertex b, we look at the cell one column to the right. The y-position of that cell's top-left corner (a), i.e., that cell's stored Y value, is also the y-position of the top-right corner (b) of the cell we're currently building. Similarly, the y-position of our current bottom-right corner (c) is the stored Y value of the cell down one row and to the right one column. The y-position of our current bottom-left corner (d) is the stored Y value of the cell down one row.
Vertex e is a bit trickier, but it can be solved like this:
If any three of a, b, c, and d have the same y-position, then e shares that y-position (this is a level cell or a diagonal slope).
If two adjacent vertices of a, b, c, and d share one y-position and the other two share another y-position, then the y-position of e is the average of those two y-positions.
If neither 1 nor 2 is true, we have an error (because the SimCity 2000 map didn't allow other types of geometry).
Now, actually generating the mesh is another matter, but there are plenty of tutorials available (via Google: Procedural terrain meshes in ThreeJS).
< I've created a proof of concept that you can see at https://pnichols04.github.io/sc2k-map/, with source code at https://github.com/pnichols04/sc2k-map. >
We have a 10x5 rectangle than match a 1000m x 500m field in real life.
The field's orientation is horizontal (floor).
So we get a quadrilateral where 1 virtual unit = 100 units in real world and four 2D corner positions (A,B,C,D)
How can I find the XYZ plane's position and rotation if :
camera.position:(0,10,0) and
camera.rotation(0,0,0) ?
The goal is to place the plane in 3D space as the perspective matches exactly the 2D image.
I think it's related to pnp problem (additional informations here)
(You can imagine the use case of a soccer field, if I have the four xy position of the four corner, ABCD, how can I place a plane in an AR app to match and track the field)
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 have played around with the d3js (v5) maps,
i'm trying to generate this map (the screenshot was taken from a random website),
For my particular case there is no need to present Antarctica.
I have read the documentation here: https://github.com/d3/d3-geo#projections,
and followed the instructions and used geoMercator, got this flat map which gets cutoff in the top north for some reason.
What is the correct approach for getting the first map's layout?
any suggestions?
The projection you are looking at is a Mercator projection.
With d3.geoMercator(), the scale value is derived from the circumference of the cylinder that forms the projection surface. The scale value is the number of pixels per radian. The default value anticipates stretching the 360 degrees of the cylinder over 960 pixels: 960/Math.PI/2.
For vertical angular distances, there is no such scaling factor, as one moves to extreme longitudes, the angular distance between points is increasingly exaggerated, such that the poles will be at ± infinity on the y axis. Because of this Mercator's, especially web Mercator's are often truncated at ±~85 degrees. With an extent of [-180,85] and [180,-85], a Mercator is square.
This limit is incorporated into d3-geoMercator, which "Defines a default projection.clipExtent such that the world is projected to a square, clipped to approximately ±85° latitude. (docs)"
This means that if we want to show the full extent of a d3-geoMercator, across 960 x 960 pixels, we can use:
d3.geoMercator()
.scale(960/Math.PI/2) // 960 pixels over 2 π radians
.translate([480,480]) // the center of the SVG/canvas
Which gives us:
The default center of d3-geoMercator is [0°,0°], so if we want [0°,0°] to be in the middle of the SVG/canvas, we translate the center so that it is in the middle, with a translate of [width/2,height/2]
Now that we are showing the whole world, we can refine to show only the portion we want. The simplest method might just be lopping off pixels from the bottom of the svg/canvas. Using the above code with a canvas/svg height of 700 pixels (and keeping 960 pixels across, using the same scale and translate) I get:
I did not remove Antarctica from this image - it just happens that it is cut off without having to filter it out (this is not necessarily ideal practice: it is still drawn).
So, an SVG/Canvas with width 960, height 700, with a projection scale of 960/Math.PI/2 and a translate of [480,480] appears to be ok. These values will scale together for different view port sizes.
With maps, there is often a lot of eyeballing to get the visual effect desired, tweaking projection.translate() or projection.center() can help shift the map to the desired location. But we can do this computationally. I'll speak to one method here, using projection.fitSize() (though this won't solve the required aspect ratio without extra steps).
Project.fitSize([width,height],geojson) takes an array specifying the dimensions of the SVG/canvas and a geojson object and tweaks the projection scale and translate values so that the geojson feature is contained in the SVG/canvas. The geojson feature could be a bounding box of the part of the world you want to show, so you could use:
projection.fitSize([width,height], {
type: "Polygon",
coordinates: [[
[-179.999,84] ,
[-179.999,-57] ,
[179.999,-57] ,
[179.999,84],
[-179.999,84]
]]
})
Where ~84 degrees north is the north end of Greenland and ~56 degrees south is roughly the tip of South America. This will ensure that the entire portion of the world you want to see is visible. However, as noted above, this doesn't consider aspect, so if you constrain the above extent to square dimensions, you'll still be showing the full extent of the Mercator.
I'm trying to write a game engine in js (canvas). So far so good.
But i got one problem my world is diamond shaped and i render the tiles from top to bottom.
The problem is when i have a tile that's bigger than 1 tile (so 2x2 as example) this will happen:
The house is defined on tile (2,1).
The left rock is placed on (1,0)
The tile (1,0) is rendered first and the next tile is (2,1) because it's on the same row and on the right.
How can you solve this?
You should be able to avoid the problem by breaking your graphics down into smaller pieces - one piece per tile on the grid. A good way to think of it is like this: If you could view the grid from directly above, each sprite should not overflow the edges of the cell they're allocated to.
For example, this cell below should probably only contain the front section of the house shown by the smaller cube:
At some point you may need to also micromanage multiple sprites in the same cell, but that's the same concept in a smaller space.
For this specific example there's a simpler solution.
Right now the house occupies these spaces: 2x0, 3x0, 2x1, 3x1
And you're drawing the house from position 2x1
If you instead drew the house from position 2x0 (and still occupy the same original 4 tiles) all the tiles would draw in correct order.
As long as you're drawing tiles top (back) to bottom (front) in screen rows, you can use oversized tiles that are 2x2, 3x3, 4x4, or any square size easily without slicing. Just draw these larger tiles along their middle row position. I often use the left corner as the grid anchor for these large tiles. It makes sense in my head this way because as soon as you draw the leftmost (or right) corner of a big isometric square, you separate everything already drawn behind it from what comes in front of it.
Rectangular oversized tiles (e.g. 2x1, 2x3, 2x4, 3x4, 4x5) usually require a more complex draw order algorithm than just screen rows top to bottom. I opt to slice these into square tiles.
Side note, that medieval house tile does already have original parts split into vertical slices if you want to go that route (my originals are on OpenGameArt).
I think the best solution here is clearly to divide your graphics using a pre-defined metric (width of a tile for instance).
The tile-based system is widely used for 2D-game, including isometric games.
Example: http://www.spriters-resource.com/pc_computer/fallouttactics/
My solutions (Also thanks to Marty Wallace!)
I can cut the sprite in 3 pieces shown on the image below
The first part gets drawed on coord (2, 0)
The second part gets drawed on coord (2, 1)
The third part gets drawed on coord (3, 1)
So we slice it vertically on the bottom tiles (the drawed tiles are like a V shape)
This should work for every tile size like 4x4
We can forgot about the tile (3, 0)
Blue: The actual png
Red: the cut lines
The lines are a bit off, but it's about the idea
And i need some sleep (that last 2 is 3 ofcourse)
This also gives us a simple calculation:
sizeX - 1 = The number of sides on the right of the middle section (the big one)
sizeY - 1 = The number of sides on the left side of the middle section
And every slice is half the tile width, and the middle slice is the full tile width.
The right slices contain only the most right part of the tile, and the left the most left side.
We can easily use tiles like 3x1 or 1x4 etc