LatLong falls within a given polygon in D3 + Leaflet - javascript

I am trying to learn how to use the Javascript library leaflet along with d3 to create various map visualisations.
I have been following this tutorial which creates a choropleth map of the United States with some interactivity. This provides some of what I need, but the main functionality I want is to have a list of lat/long coordinates classified according to which region they belong to.
This would mean, in the tutorial map for example, if I had a lat long value (55, -3) which fell within the state of Arizona's polygon, the program could classify this point as belonging to Arizona.
Is there a function in the leaflet (or d3) library which will allow me to enter a lat long coordinate as a parameter and return the name of the feature it belongs to? The tutorial above allows you to attach a function to every feature via the onEveryFeature property and can fire mouseover events when each feature is hovered over. Surely there is a way to extend this functionality to numerically entered data instead of mouse points?

Leaflet would need some tweaking if you wish to do this. It leaves the handling of mouseclicks to the browser and therefore does not need logic for determining if a point lies inside a polygon.
I am not very knowledgeable about d3 but it's not glaringly obvious to me how it'd do this out of the box. Looking at the polygon code, I do find a clipping algorithm and intersection of infinite lines.
If you add a third library, however, this should be rather simple.
The OpenLayers Geometry library can determine if a point lies inside a polygon.
EDIT: I got this to work, see also http://jsfiddle.net/VaY3E/4/
var parser = new OpenLayers.Format.GeoJSON();
var vectors = parser.read(statesData);
var lat = 36;
var lon = -96;
var point = new OpenLayers.Geometry.Point(lon, lat);
for( var i = 0; i< vectors.length; i++ ){
if(vectors[i].geometry.intersects(point)){
alert(vectors[i].attributes['name']);
}
}
Or you could use https://github.com/maxogden/geojson-js-utils , a bit more specific library. It looks like it knows how to read GeoJSON and it has a method gju.pointInPolygon. I've not tested it though.

Related

2D/3D CAD design in JavaScript

I am having 2D design in microstation and I wanted to represent this design in web using any tool(javascript/Unity 3D or any other) where the web tool will not have all the functionality but basic functionality like reshaping or adding a new shape should be available.
As of now, my approach is once I created a design in microstation then I am capturing properties of shapes like the cordinates of a line and now using these coordinates I wanted to represent in the browser since this is a 2D design so it will be plotted in some location (x,y) for example I have created a line in microstation from (2,2) to (10,10) so it will be a straight line and I have all the coordinates I tried redrawing it in Unity which am able to do but I am facing issue to change the length from (2,2) to (20,20) by mouse click. And my goal is to do it in runtime, not in Unity editor tool.
This is an example of a straight line I wanted to do it for all geometric shape,any guidance would be appreciated.
As of now am trying Unity to do so but struggling in the edit part is there a way to achieve this in unity?
I also looked at various javascript libraries like konvaJS, makerJS, ThreeJS, etc. but except konvajs none of the other library provide facilities like reshaping, in Konva also creating shape using a mouse not found any solution for this.
Can we achieve this by any of the two approaches, of course, am not looking for all functionality only a few custom functionality, if yes which approach will be the best, and which tool should I proceed with?
Any guidance will be helpful.
To draw a line-segment, you can use LineRenderer.
//two points of the line-segment are known (or got from the Transform of GameObject)
Vector3 start;
Vector3 end;
GameObject myLine = new GameObject();
myLine.transform.position = start;
myLine.AddComponent<LineRenderer>();
LineRenderer lr = myLine.GetComponent<LineRenderer>();
lr.material = new Material(Shader.Find("Particles/Alpha Blended Premultiply"));
lr.SetColors(color, color);
lr.SetWidth(0.1f, 0.1f);
lr.SetPosition(0, start);
lr.SetPosition(1, end);
//to change the points of this line
myLine.transform.position = another_start;
lr.SetPosition(0, another_start);
lr.SetPosition(1, another_end);
There are also other solutions:
Use scaled cube or capsule primitive.
3rd-party plugins: vectrosity
To get mouse clicked position, use Camera.main.ScreenToWorldPoint(Input.mousePosition).
To determine when your mouse is clicked, use Input.GetMouseButtonUp.

cesium - moving billboards

I am testing Cesiumjs to see if it can reflect a near-real-time expreience - for example: position of airplanes.
For that, I need to draw billboards and make them move - which I know is possible with cesium, just not sure how.
The code looks like this:
var billboards = scene.primitives.add(new Cesium.BillboardCollection());
var billboard = {
image : '/path/to/logo.png',
position : Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883)
};
billboards.add(billboard);
My question is how do I change the position of the billboard. I couldn't find ant documentation that would explain.
I thought doing:
billboard.position = ... //new position
but how will cesium know that I've changed the position attribute unless it somehow turns that reference into a observable object.
So how do I update the location?
Thanks.
Cesium does indeed listen for changes to billboard.position
(source code here), so it is correct behavior for apps to simply write a new position.
Note that you must write the whole position at once, meaning you may not write to billboard.position.x. Instead, keep a "scratch" Cartesian3 around (don't create a new one every animation frame at 60fps), write to the x,y,z properties of your scratch variable, and then assign your scratch variable to billboard.position. You can see in the source that the assigned value will be cloned into another pre-existing Cartesian3, so you may immediately reuse the scratch variable.
Here's an example:
// Just once at app startup. Don't call "new" at 60fps.
var scratchCartesian3 = new Cesium.Cartesian3();
var ellipsoid = viewer.scene.mapProjection.ellipsoid;
function onTick() {
// This is safe to call at 60fps.
billboard.position = Cesium.Cartesian3.fromDegrees(
lon, lat, alt, ellipsoid, scratchCartesian3);
}
Also note that your question and the above answer are focused on the "Graphics Primitive" layer of the Cesium API. Cesium has one higher layer, called the "Entity" API, that you can use if you want Cesium to handle the concept of user-selectable objects with pop-up descriptions etc. Here's a Sandcastle demo showing how to add a billboard as a property of an entity, instead of as a primitive. This allows you to add other properties to the same entity, for example a name, description, label, 3D model, etc, and have them all be controlled from the same position property, and have Cesium take care of popup descriptions. The position property is more complex for entities than for primitives, for example it can be constant or sampled. This allows entities to change position over time when the timeline is shown.

Getting a central point from an esri multipoint with javascript

I have created a webpage displaying markers on an ersi map using javasvipt.
Data:
MapNorth MapEast
439624 504743
439622 504736
439722 504775
439738 504739
439715 504774
439734 504739
The javascript code:
var points = data.map(function(x){
return [x.MapEast, x.MapNorth];
});
var myMultiPoint = {"geometry":{"points":points,"spatialReference":27700},"symbol":{"color":[255,255,255,64],
"size":6,"angle":0,"xoffset":0,"yoffset":0,"type":"esriSMS","style":"esriSMSCircle",
"outline":{"color":[0,0,0,255],"width":6,"type":"esriSLS","style":"esriSLSSolid"}}};
var gra = new esri.Graphic(myMultiPoint);
myMap.graphics.add(gra);
var graExtent = esri.graphicsExtent(myMap.graphics.graphics);
myMap.setExtent(graExtent);
What the above code does is plot markers on the map and then zooms into the extent. What my employers want now is for me to find the central point of all of those points and display one marker in the center.
Can this be done? If so and you tell me how?
Thanks
Paul
Couple of things.
Did you know about gis.stackexchange.com? They might better solve your problem.
What you're trying to do is find the centre of a polygon assuming those points aren't all in a line.
Here's a link with an answer to the question I think you're asking https://gis.stackexchange.com/questions/7998/how-can-i-calculate-the-center-point-inside-a-polygon-in-arcgis-9-3
The solution posted there uses getExtent().getCenter() as seen here
var myPolygonCenterLatLon = myPolygon.getExtent().getCenter();
I think what you want to be doing here is instead of creating a Multipoint, create a Polygon from your array of points. Once you have a polygon defined, you can do something like
var myPolygon = new Polygon(points);
var centroid = myPolygon.getCentroid();
This should get you the centroid of the points making up the Polygon.
https://developers.arcgis.com/javascript/jsapi/polygon-amd.html
Note that this requires at least version 3.7 of the JS API, though.
One thing to point out to those trying to using .getCentriod() , make sure your polygon is closed. Your 1st point and Last Point need to be in the same spot. Otherwise it wont work right. ( I ran into this a year ago, not sure if they changed this)

TileMill Interactive layers not working when added independently with MapBox.js

I have a student who is using MapBox.js (v1.6.0) to display some tiles that they made in TileMill. These tiles use the Tooltip functionality provided by TileMill (documentation) to add some interactivity. My student is also using a MapBox Streets layer to give some detailed views of roadways, etc. The problem is, when I use both of these layers together in the map, the interactivity from the tiles doesn't work.
Here is the code that doesn't work:
var map = L.mapbox.map("map");
var tilesOSM = L.mapbox.tileLayer("username.id1");
var tilesTileMill = L.mapbox.tileLayer("username.id2");
map
.addLayer(tilesOSM)
.addLayer(tilesTileMill)
.setView(L.latLng(61, -160.5), 4)
.setMaxBounds(L.latLngBounds(L.latLng(50,-180), L.latLng(72,-129)));
We have tried several iterations of this code, but the only way we can get it to work is by using the L.mapbox.map(3) method and then using the _ insertAtTheBottom_ parameter of the L.map.addLayer() function.
var map = L.mapbox.map("map", "username.id2", {});
map
.addLayer(L.mapbox.tileLayer("username.id1"), true)
.setView(L.latLng(61, -160.5), 4)
.setMaxBounds(L.latLngBounds(L.latLng(50,-180), L.latLng(72,-129)));
My question is three fold.
What is the difference between these two implementations?
Why is the tileLayer created using L.mapbox.tileLayer() different than the one created and automatically added using L.mapbox.map(3)?
Are there plans to address this discontinuity in future changes to the API or will support for interactive tiles be dropped in TileMill 2?
What is the difference between these two implementations?
If you check out what L.mapbox.map does internally, it adds a gridLayer and gridControl for the layer you specify. Basically the map constructor makes all of the safe assumptions it could make and does them automatically as a convenience.
Why is the tileLayer created using L.mapbox.tileLayer() different than the one created and automatically added using L.mapbox.map(3)?
It's the same - there's a gridLayer and gridControl in the mix when you use L.mapbox.map(3), and those are what make things interactive.
Are there plans to address this discontinuity in future changes to the API
It's not as much a discontinuity than an API design: we decided to keep tileLayers decoupled from gridLayers and gridControls so you can mix & match them - if you want to switch which layer interactive features come from, or disable interactivity without disabling the tile layer, you can.
will support for interactive tiles be dropped in TileMill 2?
No, you can use TileMill 2 and see how it supports interactivity. We aren't going to remove or phase this out, though vector tiles will have new methods of interaction.
For your second example, you would want something like:
var map = L.mapbox.map("map", "username.id2", {});
var gridLayer = L.mapbox.gridLayer("username.id1").addTo(map);
var gridControl = L.mapbox.gridControl(gridLayer).addTo(map);
map
.addLayer(L.mapbox.tileLayer("username.id1"), true)
.setView(L.latLng(61, -160.5), 4)
.setMaxBounds(L.latLngBounds(L.latLng(50,-180), L.latLng(72,-129)));

create 3d shape in google earth plugin

first of all thanks for reading.
I have a web application that heavily uses Google Earth Plugin to show some sensor data and other stuff.
I'm trying to give the user the capability to define areas and volumes drawing them in the plugin.
I was able to add area features (such as creation, visualization, editing and deletion).
Now i'm working on volumes but i really do not know what is the best way to handle them. An inportant thing to note is that i'm only interested in volumes with parallel upper and lower surface (no pyramid, no complex figures, only prisms)
The first idea that came in my mind is to create a custom object made of 2 polygon and an array of edges to connect every polygon vertex of the upper surface to the respective one in the lower surface.
Something like:
//Create the upper surface (polygon)
var aPolygonUpperPlacemark = ge.createPlacemark("");
var aPolygonUpper = ge.createPolygon("");
aPolygonUpper.setAltitudeMode(ge.ALTITUDE_RELATIVE_TO_GROUND);
aPolygonUpperPlacemark.setGeometry(aPolygonUpper);
var aOuterUpper = ge.createLinearRing("");
aPolygonUpper.setOuterBoundary(aOuterUpper);
ge.getFeatures().appendChild(aPolygonUpperPlacemark);
//Create the lower surface (polygon)
var aPolygonLowerPlacemark = ge.createPlacemark("");
var aPolygonLower = ge.createPolygon("");
aPolygonLower.setAltitudeMode(ge.ALTITUDE_RELATIVE_TO_GROUND);
aPolygonLowerPlacemark.setGeometry(aPolygonLower);
var aOuterLower = ge.createLinearRing("");
aPolygonLower.setOuterBoundary(aOuterLower);
ge.getFeatures().appendChild(aPolygonLowerPlacemark);
var myPrism = {
upperSurface: aPolygonUpperPlacemark,
lowerSurface: aPolygonLowerPlacemark,
edges: new Array()
};
The proble here is that the lateral surfaces will not get displayed as real surfaces but only as lines. On the other hand i could probably create another polygon for each lateral surface but this would make the management of such a 3d shape more complex than what i'd like it to be.
So my question is, is there any better way to handle 3d shapes or maybe a built-in geometry?
Nota that i cannot rely in 3d models (so external Kmz cannot be loaded) as at the end the 3d shape creation will be a user's feature.
Just create the upper polygon (e.g. ensure the coordinates include altitude), and then ensure is set to 1. You can do this in the API using setExtrude(true).
See https://developers.google.com/kml/documentation/kml_tut#polygons for details
I'd also recommend you check out the utility library - it makes things like this much more concise. See for example this extruded polygon example: http://earth-api-utility-library.googlecode.com/svn/trunk/extensions/examples/poly-draw-extruded.html

Categories