Google maps polygon optimization - algorithm

I extracted country outline data from somewhere and successfully managed to convert it into an array of lat-lng coordinates that I can feed to Google maps API to draw polyline or polygons.
The problem is that that there are about 1200+ points in that shape. It renders perfectly in Google maps but I need to reduce the number of points from 1200 to less than 100. I don't need a very smooth outline, i just need to throw away the points that I can live without. Any algorithm or an online tool that can help me reduce the number of points is needed.

Found this simple javascript by Bill Chadwick. Just feed in the LatLng to an array and pass in to the source arguments in a function here Douglas Peucker line simplification routine
it will output an array with less points for polygon.
var ArrayforPolygontoUse= GDouglasPeucker(theArrayofLatLng,2000)
var polygon=new google.maps.Polygon({
path:ArrayforPolygontoUse,
geodesic:true,
strokeColor:"#0000FF",
strokeOpacity:0.8,
strokeWeight:2,
fillColor:"#0000FF",
fillOpacity:0.4,
editable:true
});
theArrayofLatLng is an array of latlng that you collected using google maps api.
The 2000 value is kink in metres. My assumption is, the higher the value, more points will be deleted as an output.
For real beginners:
Make sure you declare the js file on your html page before using it. :)
<script type="text/javascript" src="js/GDouglasPeucker.js"></script>

I think MapShaper can do this online
Otherwise, implement some algorithm

If you can install postgis which i think is easy as they provide an installer then you can import the data and execute snaptogrid() or st_simplify() for which i cannot find an equivalent in mysql.If you decide to go with postgis which i recommend cause it will help you down the road i can provide you with the details.
Now for an easy custom solution you can reduce size by cutting or rounding some of the last digits of the coords and then merge the same coords resulting actually in a simple snaptogrid().
Hope it helps

I was looking for exactly the same thing and found Simplify.js. It does exactly what you want and is incredibly easy to use. You simply pass in your coordinates and it will remove all excess points.
simplify(points, tolerance, highQuality)
The points argument should contain an array of your coordinates formatted as {x: 123, y: 123}. (Afterwards you can convert it back to the format you wish.)
The tolerance should be the precision in decimal degrees. E.g. 0.0001 for 11 meters. Increasing this number will reduce the output size.
Set highQuality to true for better results if you don't mind waiting a few milliseconds longer.

Mostly likely what you want to divide the points into 2 half and want to try my Javascript function:
function shortenAndShow ( polyline, color ) {
var dist = 0, copyPoints = Array ( );
for ( var n = 0, var end = polyline.getVertexCount ( ) - 1; n < end ; n++ ) {
dist += polyline.getVertex ( n ).distanceFrom ( polyline.getVertex ( n +1 ) );
copyPoints.push ( polyline.getVertex (n) );
}
var lastPoint = copyPoints [copyPoints.length-1];
var newLine = new GPolyline (copyPoints, color, 2, 1);
gmap2.addOverlay ( newLine );
}

I agree the Unreason's anwser,The website support GeoJson,I used it in my website,and it cut down my geoJson ,But I think you also need this world country geo Json

Related

Limit maximum zoom for a scene in Three.js

I have a Three.js App and I wanna limit the zoom for the scene, because logically at some zoom the user can get inside of my 3D object, which in my oppinion is not a really good UX.
I tried scene.maxZoom = number; but did not work. What can I do?
Here is the code: https://github.com/AlinAlexandruPeter/code/blob/main/code.js
You don't need Three.js to limit the range of numbers, just simple JavaScript. Use Math.min(a, b) to get the lower of the two values.
const MAX_ZOOM = 2.5;
// Clamp user input to 2.5 and below
camera.zoom = Math.min(userInput, MAX_ZOOM);
With this approach, if userInput = 3, it will get clamped at 2.5. There's also Math.max() if you want to clamp it on the lower range.

Performance problems with scenekit

I've got a row dimensional array of values that I want to visualize in 3D and I'm using scene kit under OS X for it. I've done it in a clumsy manner by using each column as a point on the X axis, each row as a point on the Z axis, and each value as a normalized point on the Y axis -- I place a sphere at the vector defined by each data point. It works but it doesn't look too good.
I've also done this by building a mesh of lines based on #Matthew's function in Drawing a line between two points using SceneKit (the answer he posted, not the original question). For each point I use his function to draw two lines - one between my current point and the next point to the right and another between my current point and the next point towards the front (except when there is no additional column/row, of course).
Using the second method, my results look much better... however the performance is quite hideous! It takes quite a long time to complete the initial rendering, and if I use a trackpad/mouse to rotate or translate the scene, I might as well get a cup of coffee to wait until my system is usable again (and this is not much hyperbole). Using the sphere method, things render and update very quickly.
Any advice on how to improve the performance when using the lines method? (Note that I am not trying to add both lines and spheres at the same time.) Code-wise, the only difference between approach is which of the following methods gets called (and that for each point, addPixelAt... is called once, but addLineAt... is called twice for most points).
- (SCNNode *)addPixelAtRow:(CGFloat)row Column:(CGFloat)column size:(CGFloat)size color:(NSColor *)color
{
CGFloat radius = 0.5;
SCNSphere *ball = [SCNSphere sphereWithRadius:radius*1.5];
SCNMaterial *material = [SCNMaterial material];
[[material diffuse] setContents:color];
[[material specular] setContents:color];
[ball setMaterials:#[material]];
SCNNode *ballNode = [SCNNode nodeWithGeometry:ball];
[ballNode setPosition:SCNVector3Make(column, size, row)];
[_baseNode addChildNode:ballNode];
return ballNode;
}
- (SCNNode *)addLineFromRow:(CGFloat)row1 Column:(CGFloat)column1 size:(CGFloat)size1
toRow2:(CGFloat)row2 Column2:(CGFloat)column2 size2:(CGFloat)size2 color:(NSColor *)color
{
SCNVector3 positions[] = {
SCNVector3Make(column1, size1, row1),
SCNVector3Make(column2, size2, row2)
};
int indices[] = {0, 1};
SCNGeometrySource *vertexSource = [SCNGeometrySource geometrySourceWithVertices:positions count:2];
NSData *indexData = [NSData dataWithBytes:indices length:sizeof(indices)];
SCNGeometryElement *element = [SCNGeometryElement geometryElementWithData:indexData
primitiveType:SCNGeometryPrimitiveTypeLine
primitiveCount:1
bytesPerIndex:sizeof(int)];
SCNGeometry *line = [SCNGeometry geometryWithSources:#[vertexSource] elements:#[element]];
SCNMaterial *material = [SCNMaterial material];
[[material diffuse] setContents:color];
[[material specular] setContents:color];
[line setMaterials:#[material]];
SCNNode *lineNode = [SCNNode nodeWithGeometry:line];
[_baseNode addChildNode:lineNode];
return lineNode;
}
From the data that you've shown in your question I would say that your main problem is the number of draw calls. Your's is in the tens of thousands, which is way too much. It should probably be a lot closer to ~100.
The reason why you have so many draw calls is that you have so many distinct objects in your scene (each line). The better (but more advanced solution) would probably be to generate a single element for the entire mesh that consists of all the lines. If you want to achieve the same rendering with that mesh (with a color from cold to warm based on the height) then you could do that in a shader modifier.
However, in your case I would start by flattening all the lines (since that would be the smallest code change and should still have a significant performance improvement in your case).
(Optimizing performance is always an iterative process. Once you fix one thing there will be another thing which is the most expensive operation. Without your code I can only say what would help with the current performance problem)
Create an empty node (without adding it to your scene) and generate all the lines, adding them to this node. Then create a flattened copy of that node by calling flattenedClone on the node that contains all the lines
SCNNode *nodeWithAllTheLines = [SCNNode node];
// create all the lines and add them to it...
SCNNode *flattenedNode = [nodeWithAllTheLines flattenedClone];
[_baseNode addChildNode:flattenedNode];
When you do this you should see a significant drop in the number of draw calls (the number after the diamond in the statistics) and hopefully a big increase in performance.

D3 circle packing diameter calculation

I am using the pack layout for packing different no of equal sized circles. I have a group of clusters to be visualized. So I am calling pack function for each cluster of circles. In all the d3 examples the diameter is either calculated with the given size or fixed diameter. I would like to calculate it according to the no of circles to be packed. So how do I calculate the packing circle diameter?
is there any formula so that I can pack the circles without wasting the space.
If you truly don't care about relative sizing of the circles, then you could make your JSON file represent only the data you care about(say, names) and feed your packing function a dummy value that the 'value' accessor function is expecting.
For instance:
var circleChildren = [{
"value": 1
}, {
"value": 1
}, {
"value": 1
}, {
"value": 1
}];
would give you a JSON object that you can use as children for your packing function:
var circleInput = Object();
circleInput.children = circleChildren;
You can verify that in your console by running:
bubble.nodes(circleInput)
.filter(function (d) {
return !d.children; //we're flattening the 'parent-child' node structure
})
where bubble is your D3 packing bubble variable.
Here's a fiddle that demonstrates that. It may have some extra things but it implements what you're looking for. In addition, you can play around with the number of circles by adding more dummies in the JSON file, as well as changing the SVG container size in the diameter variable. Hope that helps!
EDIT: The size of your layout(in this case, a misnomer of the 'diameter' variable) directly determines the size and diameter of your circles within. At some point you have to assign the pack.size() or pack.radius() value in order for your circles to display within a layout(documentation ):
If size is specified, sets the available layout size to the specified two-element array of numbers representing x and y. If size is not specified, returns the current size, which defaults to 1×1.
Here you have several options:
If you want your circles to be 'dynamically' sized to your available element's width (that is, if you want them to cover up all the element width available) then I'd recommend you get your element's width beforehand, and then apply in your pack() function. The problem is then you have to think about resizing, etc.
If you want to keep the maximum sizing available, then you have to make your viz responsive. There's a really good question already in SO that deals with that.
I know this isn't the full solution but hopefully that points you in the right direction for what you're trying to do.
FURTHER EDIT:
All of a sudden, another idea came to mind. Kind of an implementation of my previous suggestion, but this would ensure you're using the maximum space available at the time for your circle drawing:
zone = d3.select("#myDiv");
myWidth = zone.style("width").substring(0, zone.style("width").length - 2);

matlab: texture classification

I have a histology image like this:
From the image, we can observe there are two kinds of different cells.
and
Is there any way that I can separate these two types of cells into two groups?
How about using your raw image and previous code to achieve this?
% % % your old code
I=imread(file);
t1=graythresh(I);
k1=im2bw(I,t1);
k1=~k1;
se = strel('disk',1);
k0=imfill(~k1,'holes');
cc = conncomp(k0);
k0(cc.PixelIdxList{1})=0;
k1=imfill(k1,'holes');
mask=k0 | k1;
%%%%%%%%%%%%%%%%%%
This will give you:
I=rgb2hsv(I);
I=double(I);
I1=I(:,:,1); % again, the channel that can maximizing the margin between donut and full circle
Imask=(I1-0.2).*(I1-0.9)<0;
k2=mask-Imask;
k2=bwareaopen(k2,100);
This will give you:
k2=mask-Imask;
I2=zeros(size(I1,1),size(I1,2),3);
I2(:,:,1)=(k2==1)*255;
I2(:,:,3)=((I1-0.2).*(I1-0.9)<0)*255;
imshow(I2)
will finally give you (the two types are stored in two channels in the rgb image):
I would use regionprops
props=regionprops(YourBinaryImage, 'Solidity');
The objects with a high solidity will be the disks, those with a lower solidity will be the circles.
(Edit) More formally:
I=imread('yourimage.jpg');
Bw=~im2bw(I, 0.5);
BWnobord = imclearborder(Bw, 4); % clears the partial objects
Props=regionprops(BWnobord, 'All');
solidity=cell2mat({Props.Solidity});
Images={Props.Image};
Access the elements of Images where the value in solidity is higher than 0.9 and you get your disks. The circles are the other ones.
Hope it helps

Algorithm for heat map?

I have a list of values each with latitude and longitude. I'm looking to create a translucent heatmap image to overlay on Google Maps. I know there are server side and flash based solutions already, but I want to build this in javascript using the canvas tag.
However, I can't seem to find a concise description of the algorithm used to turn coordinates and values into a heatmap. Can anyone provide or link to one?
Thanks.
The basic idea would be to create a grid and project every lat,lng coord to that grid. I would use a 2D array of ints.
The psuedo-code would be:
for each coord
cell = coord projected to grid
increment cell value
end
for 0 to # of passes
for each row
for each col
if grid[row,col] > 0 then
grid[row,col] += 1
increment_adjacent_cells(row, col)
end
end
end
end
So, the idea is that the higher the int value, the hotter that cell is. increment_adjacent_cells should increment the values in all 8 adjacent cells.
I have tried to solve this in javascript using the canvas element, here is my current result:
http://gist.github.com/346165
I have to fix the gaussian filter and the color mapping, because it doesn't give good results currently.
A faster way of building a heatmap could be to use a queue:
Pseudocode:
Add an element to queue (first in heatmap(x,y, val))
While (!queue.isEmpty())
{
elem = queue.pop()
queue.push(elem.x + 1, elem.y, val-1)
queue.push(elem.x - 1, elem.y, val-1)
queue.push(elem.x, elem.y + 1, val-1)
queue.push(elem.x, elem.y - 1, val-1)
}
This saves on tons of iterations!
Look at this project if you are looking for something that looks more like 'tv weather maps':
https://github.com/optimisme/javascript-temperatureMap

Resources