How to check if multiple GeoJSON objects form one complete area? - geojson

I have a Javascript array of GeoJSON objects, which are all by default Polygons. I am currently using Turf.js with intersect to check if two features overlap, but how do I check if 2+ can all form a single cohesive area?
There is no upper limit to the number of mini-areas
If there are 3 locations for example, location 1 and 3 don't have to intersect each other as long as they both intersect location 2 (i.e. the idea is to be able to form one new polygon at the end)
I have tried something along the lines of the following, but it doesn't seem very efficient
var locationsToCheck = [...]; // Populated with GeoJSON objects
var currLocation = locationsToCheck.pop();
while (locationsToCheck.length > 0) {
var currLocationTwo = locationsToCheck.pop();
var intersection = turf.intersect(currLocation, currLocationTwo);
if (intersection != null) {
currLocation = intersection;
} else {
locationsToCheck.unshift(currLocationTwo);
}
}
and it ends in an infinite loop if there are areas that never intersect at all. I thought of creating a second array to store the ones that have been checked once already, but that produces the same infinite loop again. What would be the optimal way to achieve this?
Note: The reason I use unshift to insert the area again, is it because it might intersect with another mini-area later in the list

Related

How to compare values within two List<List<CustomClass>> in Dart?

I have a 2048-type game where the gameboard grid is made up of a list of 4 other lists (each of which contain 4 Tiles).
Each time a move is made, the newGameboardGrid is saved in yet another list (so that removeLast can be called when a player wants to undo a move).
When a player swipes, I need to compare the newGameboardGrid grid with the previous one to see if any actual movement took place or if the tile values are still the same (as would happen if a player swiped in a direction where no movement was possible).
I tried this code:
if (newGameboardGrid == listOfGameboardGrids.last) {
// do something
}
It almost works in that it is comparing the <List<List< Tile>> from the new move with the <List<List< Tile>> of the last move, but the problem is that it never results in the two <List<List< Tile>> as being equal, even when all the tile values are identical. I believe it's because it is comparing hashcodes and/or other things.
The Tile class has lots of stuff in it, but the thing I would like to compare is that int named "value". Is it possible to compare only the "value" variable for these two <List<List< Tile>>?
Thanks in advance for any help! (And apologies if any of my terms are imprecise.)
Dart list implementations do not override the operator== of Object, so they are only ever equal to themselves. The elements are not checked.
IF you want to compare the elements (and here, the elements of the list elements), you can use the Equality classes from package:collection:
const boardEquality = ListEquality(ListEquality(DefaultEquality()));
This creates a ListEquality object which compares two lists of lists of elements by checking that they contain the same number of lists, which again contains the same number of equal elements. (I assume that Tile implements operator==).
You can the use it as: if (boardEquality.equals(newGameboardGrid, listOfGameboardGrids.last)) { ... }.
You could do an extension method on your particular list type and make an isEqual method for that compares each Tile:
extension TileListComp on List<List<Tile>> {
bool isEqual(List<List<Tile>> other) {
if(this.length != other.length || this[0]?.length != other[0]?.length) {
return false;
}
for(int x = 0; x < this.length; x++) {
for(int y = 0; y < this[0].length; y++) {
if(this[x][y] != other[x][y]) {
return false;
}
}
}
return true;
}
}
If you have not implemented any kind of comparison for your Tile class, you will need to do so. I can advise if necessary.

Getting data from a table

Using Tiled I generated a Lua file which contains a table. So I figured that I'd write a for loop which cycles through the table gets the tile id and checks if collision is true and add collision if it was. But, I've been unable to get the tile id's or check they're properties. But it returned a error saying that I tried to index nil value tileData.
Here is the Map file
return {
version = "1.1",
luaversion = "5.1",
-- more misc. data
tilesets = {
{
name = "Tileset1",
firstgid = 1,
tilewidth = 16,
tileheight = 16,
tiles = {
{
id = 0,
properties = {
["Collision"] = false
}
},
}
}
layers = {
{
type = "tilelayer",
name = "Tile Layer 1"
data = {
-- array of tile id's
}
}
}
}
And here is the for loop I wrote to cycle through the table
require("Protyping")
local map = love.filesystem.load("Protyping.lua")()
local tileset1 = map.tilesets
local tileData = tileset1.tiles
local colision_layer = map.layers[1].data
for y=1,16 do
for x=1,16 do
if tileData[colision_layer[x*y]].properties["Colision"] == true then
world:add("collider "..x*y,x*map.tilewidth, y*tileheight,tilewidth,tileheight)
end
end
end
Try this:
tileset1 = map.tilesets[1]
instead of
tileset1 = map.tilesets
lhf's answer (map.tilesets[1] instead of map.tilesets) fixes the error you were getting, but there are at least two other things you'll need to fix for your code to work.
The first is consistent spelling: you have a Collision property in your map data and a Colision check in your code.
The second thing you'll need to fix is the way that the individual tiles are being referenced. Tiled's layer data is made of 2-dimensional tile data laid out in a 1-dimensional array from left-to-right, starting at the top, so the index numbers look like this:
You would think you could just do x * y to get the index, but if you look closely, you'll see that this doesn't work. Instead, you have to do x + (y - 1) * width.
Or if you use zero-based x and y, it looks like this:
Personally, I prefer 0-based x and y (but as I get more comfortable with Lua, that may change, as Lua has 1-based arrays). If you do go with 0-based x and y, then the formula is x + 1 + y * width.
I happen to have just written a tutorial this morning that goes over the Tiled format and has some helper functions that do exactly this (using the 0-based formula). You may find it helpful: https://github.com/prust/sti-pg-example.
The tutorial uses Simple Tiled Implementation, which is a very nice library for working with Tiled lua files. Since you're trying to do collision, I should mention that STI has a plugins for both the bump collision library and the box2d (physics) collision library.

OpenLayers 3 how can I create an ol.geom.Polygon from an array of ol.geom.Point features

I see that it is possible to pass in an array of ol.coordinate elements but I don't see an obvious way to pass in an array of ol.geom.Point features. What is the most efficient way to create a polygon from an array of point features?
Loop in all your points to collect their geometry, then create your polygon from that collection.
var coordinates = [];
points.forEach(function(point) {
coodinates.push(point.getCoordinates());
});
var polygon = new ol.geom.Polygon([coordinates]);

Three JS select geometry by id

Background: I'm a dev that knows JS, but is relatively new to Three JS. I've done a few small projects that involve static scenes with basic repeating animation.
I'm currently working on a modified version of Google's Globe project http://workshop.chromeexperiments.com/globe/. Looking back, I probably should have just started from scratch, but it was a good tool to see the approach their dev took. I just wish I could now update ThreeJS w/o the whole thing falling apart (too many unsupported methods and some bugs I never could fix, at least not in the hour I attempted it).
In the original, they are merging all of the geometric points into one object to speed up FPS. For my purposes, I'm updating the points on the globe using JSON, and there will never be more than 100 (probably no more than 60 actually), so they need to remain individual. I've removed the "combine" phase so I can now individually assign data to the points and then TWEEN the height change animation.
My question is, how do I manually select a single point (which is a Cube Geometry) so that I can modify the height value? I've looked through Stack Overflow and Three JS on GitHub and I'm not sure I understand the process. I'm assigning an ID to make it directly relate to the data that is being passed into it (I know WebGL adds an individual name/ID for particles, but I need something that is more directly related to what I'm doing for the sake of simplicity). That seems to work fine. But again, as a JS dev I've tried .getElementById(id) and $('#'+id) in jQuery, and neither works. I realize that Geometry objects don't behave the same way as HTML DOM objects, so I guess that's where I'm having struggles.
Code to add a point of data to the globe:
function addPoint(lat, lng, size, color, server) {
geometry = new THREE.Cube(0.75, 0.75, 1, 1, 1, 1, null, false, { px: true,
nx: true, py: true, ny: true, pz: false, nz: true});
for (var i = 0; i < geometry.vertices.length; i++) {
var vertex = geometry.vertices[i];
vertex.position.z += 0.5;
}
var point = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial ({
vertexColors: THREE.FaceColors
}));
var phi = (90 - lat) * Math.PI / 180;
var theta = (180 - lng) * Math.PI / 180;
point.position.x = 200 * Math.sin(phi) * Math.cos(theta);
point.position.y = 200 * Math.cos(phi);
point.position.z = 200 * Math.sin(phi) * Math.sin(theta);
if($('#'+server).length > 0) {
server = server+'b';
}
point.id = server;
point.lookAt(mesh.position);
point.scale.z = -size;
point.updateMatrix();
for (var i = 0; i < point.geometry.faces.length; i++) {
point.geometry.faces[i].color = color;
}
console.log(point.id);
scene.addObject(point);
}
So now to go back, I know I can't use point.id because obviously that will only reference inside the function. But I've tried 'Globe.id', 'Globe.object.id', 'object.id', and nothing seems to work. I know it is possible, I just can't seem to find a method that works.
Okay, I found a method that works for this by playing with the structure.
Essentially, the scene is labeled "globe" and all objects are its children. So treating the scene as an array, we can successfully pass an object into a var using the following structure:
Globe > Scene > Children > [Object]
Using a matching function, we loop through each item and find the desired geometric object and assign it to a temporary var for animation/adjustment:
function updatePoints(server){
var p, lineObject;
$.getJSON('/JSON/'+server+'.json', function(serverdata) {
/* script that sets p to either 0 or 1 depending on dataset */
var pointId = server+p;
//Cycle through all of the child objects and find a patch in
for(var t = 3; t < globe.scene.children.length; t++) {
if(globe.scene.children[t].name === pointId) {
//set temp var "lineObject" to the matched object
lineObject = globe.scene.children[t];
}
}
/* Manipulation based on data here, using lineObject */
});
}
I don't know if this is something that anyone else has had questions on, but I hope it helps someone else! :)
EDIT: Just realized this isn't a keyed array so I can use .length to get total # of objects

add mouseevents to webgl objects

im using xtk to visualize medical data in a webgl canvas. currently im playing around with this lesson:
lesson 10
this library is pretty good but not very well documented. i want to get rid of that gui and add some mouseevents. if i load the mesh from the gui how can i add a mouse event to the mesh? i actually don't know where to start. it's a little bit confusing to get started with this library....
i tried
mesh.click(function(){
alert("yes");
})
or
mesh.mousedown(function(){
alert("yes");
}
Objects rendered in WebGL are not part of the DOM, and as such don't generate events like DOM elements do. This means that for events like these you have to implement the mouse interaction code yourself.
Traditionally in WebGL/OpenGL this process is known as "Picking", and there's several decent resources for it online. (For example: http://webgldemos.thoughtsincomputation.com/engine_tests/picking) The core process is something like this, though:
For each pickable object in your scene, assign it a color. Put this in a lookup table somewhere
Re-render the entire scene to a texture, rendering each pickable object with it's assigned color
Once the scene is rendered, determine your mouse coordinates and read back the color of the texture at that X/Y.
Fetch the object associated with that color from your lookup table. This is the object your mouse cursor is pointing at!
As you can see, while not a difficult method conceptually this also involves several mid-level WebGL topics, such as rendering to a texture, and as such is not usually recommended for beginners. I'm not sure if there are any features in xtk to assist with this (honestly I had never heard of the library before your post), but I would guess that this is something that you'll have to implement on your own.
DOM events are not supported but you can do it with xtk. Check out this JSFiddle
http://jsfiddle.net/haehn/r7Ugf/
// create and initialize a 3D renderer
var r = new X.renderer3D();
r.init();
// create a cube and a sphere
cube = new X.cube();
sphere = new X.sphere();
sphere.center = [-20, 0, 0];
r.interactor.onMouseMove = function() {
// grab the current mouse position
var _pos = r.interactor.mousePosition;
// pick the current object
var _id = r.pick(_pos[0], _pos[1]);
if (_id != 0) {
// grab the object and turn it red
r.get(_id).color = [1, 0, 0];
} else {
// no object under the mouse
cube.color = [1, 1, 1];
sphere.color = [1, 1, 1];
}
r.render();
}
r.interactor.onMouseDown = function(left, middle, right) {
// only observe right mouse clicks
if (!right) return;
// grab the current mouse position
var _pos = r.interactor.mousePosition;
// pick the current object
var _id = r.pick(_pos[0], _pos[1]);
if (_id == sphere.id) {
// turn the sphere green
sphere.color = [0, 1, 0];
r.render();
}
}
r.add(cube); // add the cube to the renderer
r.add(sphere); // and the sphere as well
r.render(); // ..and render it
Easy, no?
XTK implements picking the way Toji explained (i.e. with a frameBuffer where every object is rendered in a different RGBA "color"). It will work while you have less than 255^4 objects, so almost always. There are other methods like unprojecting but they would be longer I think.
So with X.renderer.pick and X.renderer.get you can find the object under the mouse and change its properties. However for the moment you can only change vizualisation properties (see the setGetter and setSetter in every class) but you cannot move an X.object (since X.object._transform attribute is private and there is no getter/setter for it yet).
That's something interesting to deal with : adding a pair of getter/setter for X.object's transform would allow, for example, an user to put medical stuff (modelized by a mesh or something else) in the scene and place to mesure distances or see if it will fit for an operation or something like that. Shouldn't be a good idea Haehn ? And it's a minor change in the framework.

Resources