Efficient way of finding points in a hexgrid - geojson

I am displaying a 10km cell hexGrid overlay on a map (approx 1000kmĀ²).
I have a geoJSON file containing around 5000 coordinate points, along with a 'score' value for each point. I want to collect all the points that fall into each hex cell, and modify the cell colour based on the average of the score for all points in that cell.
My (simplified) code is as follows:
let map = L.map('map')
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png').addTo(map)
let hexgrid = turf.hexGrid(mapBound, cellSize, options)
L.geoJson(hexgrid, {onEachFeature: onEachHex}).addTo(map)
function onEachHex(feature, layer) {
// find all points within this hex
let found = turf.pointsWithinPolygon(pointsData, turf.polygon(feature.geometry.coordinates))
// hexStyle defines a colour from the average scores in 'found' properties
layer.setStyle(hexStyle)
}
The problem I am having is that with a 10km cell size, there are several thousand cells, and there are 5000 points to evaluate for each hex. This obviously takes a very long time to render.
Can anyone suggest a better way of achieving this? The best option I can think of so far is to throw away the found points from pointsData each time, but I don't fancy trying to unpick the geoJson manually to achieve this!
Any tips greatly appreciated!

Related

Tableau: How to display size as the number of records for the same lat,long

On the same (lat,long) on a Tableau-Desktop map, I want the size of a dot to be proportional to the number of records at that location. I tried count/sum(Number of Records) built-in tableau measure, I created a SeqId and tried count(SeqId) for Size, neither worked. Here is a sample of my data, as you can see:
(44.92810490,-74.89186500) has one Record
(44.69948730,-73.45291240) has five Records
(44.72143010,-73.72375280) has 10 records
I would like the point to be proportional to the number of records at that location. Help is Much appreciated
Musa
Seq Id,Census,Gender,Lat,Long
1,1860,F,44.92810490,-74.89186500
2,1870,M,44.69948730,-73.45291240
3,1870,F,44.69948730,-73.45291240
4,1870,M,44.69948730,-73.45291240
5,1870,F,44.69948730,-73.45291240
6,1870,F,44.69948730,-73.45291240
7,1870,M,44.72143010,-73.72375280
8,1870,M,44.72143010,-73.72375280
9,1870,M,44.72143010,-73.72375280
10,1870,M,44.72143010,-73.72375280
11,1870,M,44.72143010,-73.72375280
12,1870,M,44.72143010,-73.72375280
13,1870,M,44.72143010,-73.72375280
14,1870,M,44.72143010,-73.72375280
15,1870,M,44.72143010,-73.72375280
16,1870,M,44.72143010,-73.72375280
Can you try this?
Create a calculated field "Geo" with this definition
IFNULL(STR([Lat]),"")+ ","+IFNULL(STR([Long],"")
Move this field in "size" mark using Count([Geo])
Hope this should give you the desired result.
Put Latitude on the Rows shelf, and then right click on the pill and convert it to a dimension. Make sure it stays continuous.
Likewise, put Longitude on the Columns shelf and convert it to a dimension
Put SUM(Number of Records) on the size shelf
Important, Don't have any other dimensions on any shelves, leave SeqId off
This approach will make one mark for each unique latitude/longitude pair and size that mark according to how many times that pair appears in the data set.
A problem you will probably notice is that two latitudes that differ only in the final decimal place are treated as distinct latitudes. That may not make the most useful visualization. You can bin nearby latitudes together by making a calculated field to round values to the degree you wish. If you do that, be sure to make your field a continuous dimension, and also set its geographic role. It has the effect of snapping lat/long pairs to a grid. As an alternative to rounding, you can look into the hexbinx() and hexbiny() functions.
For a heat map based on square or hex grids, you may want to try using (partially transparent) colors instead of size to indicate density.

Endless scrolling over a 3d map

I have some experience with Metal and quite a bit with Unity and am familiar with setting up meshes, buffers, and the backing data for drawing; but not so much the math/shader side. What I'm struggling with is how to get an endless scrolling world. So if I pan far to the right side I can see the left side and keep going.
The application of this would be a seamless terrain that a player could scroll in any direction forever and have it just wrap.
I don't want to duplicate everything on draw and offset it, that seems horrendously inefficient. I am hoping for a way to either use some magic matrix math or some sort of shader to get things wrapping/drawing where they should when panning the map. I've searched all over for some sort of guide or explanation of how to get this working but haven't come up with anything.
I know a lot of old (dos) games did this somehow, is it still possible? Is there a reason why it seems the industry has migrated away from this type of scrolling (bounding to edges vs wrapping)?
I have created a simple example demonstrating what you're looking for (I think).
The basic idea of it is that you draw the map in a repeating grid, using the drawPrimitives(type:vertexStart:vertexCount:instanceCount:) method on MTLRenderCommandEncoder. As the instance count you want to pass in the number of identical maps you want to draw, extending it as far as needed to not see where it ends. In my example I used a simple 5x5 grid.
To not have the user see the edge of the map, we're gonna calculate their position modulo 1 (or whatever size your map is):
func didDrag(dx: CGFloat, dy: CGFloat) {
// Move user position on drag, adding 1 to not get below 0
x += Float(dx) * draggingSpeed + 1
z += Float(dy) * draggingSpeed + 1
x.formTruncatingRemainder(dividingBy: 1)
z.formTruncatingRemainder(dividingBy: 1)
}
This is how it looks:
Just a follow up on what I have actually implemented. First I essentially have an array of x,y points with altitude, terrain type and all that jazz. Using some simple % and additions/subtractions it is trivial to get the nodes around a point to generate triangles
On a draw I calculate the first showing point and the last showing point and calculate the groups of triangles shown between those points. The first/last point take into account wrapping, it is then pretty trivial to have an endless wrapping world. For each group a translation offset is passed via a uniform matrix for that group which will position that section where it should belong.
I set it via renderEncoder.setVertexBytes(&uniform, length:..., offset:...)

PaintCode - move object on the path

I would like draw a curved line and attach an object to it. Is it possible to create fraction (from 0.0 to 1.0) which makes move my object on the path? When fraction is 0 then object is on the beginning, when 0.5 is on half way and finally when is on 1.0 it is at the end. Of course i want a curved path, not a straight line :) Is it possible to do in PaintCode?
If you need it only as a progress bar, it is possible in PaintCode. The trick is to use dashed stroke with very large Gap and then just change the Dash.
Then just attach a Variable and you are done.
Edit: Regarding the discussion under the original post, this solution uses points as the unit, so it will be distributed equally along the curve, no matter how curved the bezier is.
Based on the fact that you're going to walk along the curve using linear distance, a thing Bezier curves are terrible for, you need to build the linear mapping yourself. That's fairly simple though:
When you draw the curve, also build a look-up table that samples the curve once, at say 100 points (t=0, t=0.01, t=0.02, etc). In pseudocode:
lut = [];
lut[0] = 0;
tlen = curve.length();
for(v=0; v<=100; v++) {
t = v/100;
clen = curve.split(0,t).length();
percent = 100*clen/tlen;
lut[percent] = t;
}
This may leave gaps in your LUT - you can either fix those as a secondary step, or just leave them in and do a binary scan on your array to find the nearest "does have a value" percentage.
Then, when you need to show your progress as some percentage value, you just look up the corresponding t value: say you need to show 83%, you look up lut[83] and draw your object at the value that gives you.

OpenCV: Generating points from image after thinning

I've ran in to an issue concerning generating floating point coordinates from an image.
The original problem is as follows:
the input image is handwritten text. From this I want to generate a set of points (just x,y coordinates) that make up the individual characters.
At first I used findContours in order to generate the points. Since this finds the edges of the characters it first needs to be ran through a thinning algorithm, since I'm not interested in the shape of the characters, only the lines or as in this case, points.
Input:
thinning:
So, I run my input through the thinning algorithm and all is fine, output looks good. Running findContours on this however does not work out so good, it skips a lot of stuff and I end up with something unusable.
The second idea was to generate bounding boxes (with findContours), use these bounding boxes to grab the characters from the thinning process and grab all none-white pixel indices as "points" and offset them by the bounding box position. This generates even worse output, and seems like a bad method.
Horrible code for this:
Mat temp = new Mat(edges, bb);
byte roi_buff[] = new byte[(int) (temp.total() * temp.channels())];
temp.get(0, 0, roi_buff);
int COLS = temp.cols();
List<Point> preArrayList = new ArrayList<Point>();
for(int i = 0; i < roi_buff.length; i++)
{
if(roi_buff[i] != 0)
{
Point tempP = bb.tl();
tempP.x += i%COLS;
tempP.y += i/COLS;
preArrayList.add(tempP);
}
}
Is there any alternatives or am I overlooking something?
UPDATE:
I overlooked the fact that I need the points (pixels) to be ordered. In the method above I simply do scanline approach to grabbing all the pixels. If you look at the 'o' for example, it would grab first the point on the left hand side, then the one on the right hand side. I would need them to be ordered by their neighbouring pixels since I want to draw paths with the points later on (outside of opencv).
Is this possible?
You should look into implementing your own connected components labelling. The concept is very simple: you scan the first line and assign unique labels to each horizontally connected strip of pixels. You basically check for every pixel if it is connected to its left neighbour and assign it either that neighbour's label or a new label. In the second row you do the same, but you also check against the pixels above it. Sometimes you need a label merge: two strips that were not connected in the previous row are joined in the current row. The way to deal with this is either to keep a list of label equivalences or use pointers to labels (so you can easily do a complete label change for an object).
This is basically what findContours does, but if you implement it yourself you have the freedom to go for 8-connectedness and even bridge a single-pixel or two-pixel gap. That way you get "almost-connected components labelling". It looks like you need this for the "w" in your example picture.
Once you have the image labelled this way, you can push all the pixels of a single label to a vector, and order them something like this. Find the top left pixel, push it to a new vector and erase it from the original vector. Now find the pixel in the original vector closest to it, push it to the new vector and erase from the original. Continue until all pixels have been transferred.
It will not be very fast this way, but it should be a start.

Repeating 2d world

How to make a 2d world with fixed size, which would repeat itself when reached any side of the map?
When you reach a side of a map you see the opposite side of the map which merged togeather with this one. The idea is that if you didn't have a minimap you would not even notice the transition of map repeating itself.
I have a few ideas how to make it:
1) Keeping total of 3x3 world like these all the time which are exactly the same and updated the same way, just the players exists in only one of them.
2) Another way would be to seperate the map into smaller peaces and add them to required place when asked.
Either way it can be complicated to complete it. I remember that more thatn 10 years ago i played some game like that with soldiers following each other in a repeating wold shooting other AI soldiers.
Mostly waned to hear your thoughts about the idea and how it could be achieved. I'm coding in XNA(C#).
Another alternative is to generate noise using libnoise libraries. The beauty of this is that you can generate noise over a theoretical infinite amount of space.
Take a look at the following:
http://libnoise.sourceforge.net/tutorials/tutorial3.html#tile
There is also an XNA port of the above at: http://bigblackblock.com/tools/libnoisexna
If you end up using the XNA port, you can do something like this:
Perlin perlin = new Perlin();
perlin.Frequency = 0.5f; //height
perlin.Lacunarity = 2f; //frequency increase between octaves
perlin.OctaveCount = 5; //Number of passes
perlin.Persistence = 0.45f; //
perlin.Quality = QualityMode.High;
perlin.Seed = 8;
//Create our 2d map
Noise2D _map = new Noise2D(CHUNKSIZE_WIDTH, CHUNKSIZE_HEIGHT, perlin);
//Get a section
_map.GeneratePlanar(left, right, top, down);
GeneratePlanar is the function to call to get the sections in each direction that will connect seamlessly with the rest of your world.
If the game is tile based I think what you should do is:
Keep only one array for the game area.
Determine the visible area using modulo arithmetics over the size of the game area mod w and h where these are the width and height of the table.
E.g. if the table is 80x100 (0,0) top left coordinates with a width of 80 and height of 100 and the rect of the viewport is at (70,90) with a width of 40 and height of 20 you index with [70-79][0-29] for the x coordinate and [90-99][0-9] for the y. This can be achieved by calculating the index with the following formula:
idx = (n+i)%80 (or%100) where n is the top coordinate(x or y) for the rect and i is in the range for the width/height of the viewport.
This assumes that one step of movement moves the camera with non fractional coordinates.
So this is your second alternative in a little bit more detailed way. If you only want to repeat the terrain, you should separate the contents of the tile. In this case the contents will most likely be generated on the fly since you don't store them.
Hope this helped.

Resources