Draw rectangular bounding boxes on map with Max/Min coordinates - tableau-api

I've created a table of min and max lat/long coordinates for groups of locations. I'd like to use those to draw rectangular bounding boxes on a map and include other attributes as tooltips, not sure where to start. Some example groups below.
group entities minlat minlong maxlat maxlong
a 44 33.29 (122.45) 41.32 (111.75)
b 39 42.53 (110.97) 48.51 (94.90)
c 37 42.46 (100.34) 45.79 (94.83)
d 31 32.78 (83.97) 35.73 (77.86)
e 30 40.41 (96.41) 43.07 (89.40)
f 28 39.81 (80.47) 42.13 (76.78)

What's your data source? The current version of Tableau supports geography and geometry data types, and you could use that to build the polygons. In SQL Server, I would probably add a calculated field that takes the min/max coordinate ints and creates a polygon based on those with the geography data type. Regardless, you'll need coordinates for each vertex.
Take a look at this video. It shows how to overlay custom polygons onto maps. You need coordinates for each point, then you set marks to Polygon with the points on path.
I took your data and did a quick map. The yellow box looks like a strange shape, I might have mistyped a coordinate. It shows the example regardless though.

Related

Lat/Long spatial reference

I am new to PostGIS, am not getting the area of polygon right, my sample data is from Google maps, I know the area of the polygon is 11 acres, but the area returned by st_area doesn't match,
I already referred to a few links like below, but unable to resolve the issue, Internet says google follows 4326 Spatial references, I tried a lot, can you please help, Image attached is the polygon from google maps.
I am expecting an array of such coordinates from the user, I have to calculate the area from PostGIS and give an error back to the user if the area entered is not approximated to calculated area.
https://gis.stackexchange.com/questions/169422/how-does-st-area-in-postgis-work
How do I convert a latitude/longitude pair into a PostGIS geography type?
https://gis.stackexchange.com/questions/56862/what-spatial-reference-system-do-i-store-google-maps-lat-lng-in/56925
17.475197 78.389024
17.4771 78.39044
17.475657 78.391652
17.474408 78.390847
17.475197 78.389024
l_polygon_text='MULTIPOLYGON(((
17.4771000000000001 78.3904399999999981,
17.4751970000000014 78.3890240000000063,
17.4756570000000018 78.3916519999999934,
17.4751970000000014 78.3890240000000063,
17.4744080000000004 78.3908469999999937,
17.4771000000000001 78.3904399999999981)))';
st_area(ST_GeometryFromText(l_polygon_text,4326))
st_area(ST_GeometryFromText(l_polygon_text,2163));
st_area(ST_GeometryFromText(l_polygon_text,2249));
st_area(ST_GeometryFromText(l_polygon_text,3859));
ST_AREA(ST_Transform(ST_GeomFromText(l_polygon_text,4326),31467));
ST_Area(ST_Transform(ST_SetSRID(ST_GeomFromText(l_polygon_text),4326),900913));
polygon
In PostGIS, coordinates must be expressed as longitude first, then latitude. Google uses the opposite.
After swapping the coordinates to the proper order, you can't directly call st_area, else you would get an area in "square degrees" which is meaningless. You would have to project to a suitable local coordinate system, or you can use the geography type which will return an area in m2.
select st_area(st_geogFromText('MULTIPOLYGON(((78.3904399999999981 17.4771000000000001, 78.3890240000000063 17.4751970000000014,78.3916519999999934 17.4756570000000018,78.3890240000000063 17.4751970000000014,78.3908469999999937 17.4744080000000004,78.3904399999999981 17.4771000000000001)))'));
st_area
--------------------
26956.897848576307
That being said, the example you have provided is about 6.5 acres, not 11, because the polygon is not properly defined:

How to show building floors in Deck.gl/react-map-gl

So I'm currently working on Deck.gl and React and I need to load a geojson file which has an additional property named "floors" or something similar which tells how many floors the building has.
Is there any way to extrude alternating floors horizontally just a little bit so that it looks like a floor edge like some of the buildings in this image (although most of them just go thinner at the top). I tried searching the deck.gl but there is no such thing. I looked up and found MapBox-gl-js has something called an extrusion-base-height which lets you add polygon above another but there is no such thing as extruding horizontally to make 1 floor thinner and then back to the original size. This would give and edge whenever a new floor starts.
I have scoured the docs for deck.gl but couldn't find any thing on extruding horizontally or in another sense changing the polygon area/size so that I can draw multiple size polygons on the same spot.
Another clear picture of what I'm trying
Things I want to do.
The red polygon is tilted. Need to make it's orientation the same as the green one and reducing it's area at the same time.
Move the red polygon base at the top of the green polygon.
The test data I'm using is given below,
var offset = 0.00001;
var data = [{
polygon: [
[-77.014904,38.816248],
[-77.014842,38.816395],
[-77.015056,38.816449],
[-77.015117,38.816302],
[-77.014904,38.816248]
],
height: 30
},
{
polygon: [
[-77.014904 + offset ,38.816248],
[-77.014842 - offset, 38.816395 - offset],
[-77.015056 - offset, 38.816449 - offset],
[-77.015117 + offset, 38.816302],
[-77.014904 + offset, 38.816248]
],
height: 40
}
];
EDIT:- I think the proper way would be to convert longitude/latitude to Cartesian Coordinates, get the vectors to the 4 corners of the polygon translate the vectors to move towards the center by the offset amount then convert back. But this would only work with quad/rectangle polygon, for buildings that are made up of multiple quads I'd need another way.
If I'm understanding correctly, your problem boils down to: given a polygon (the footprint of the lower part of the building), generate a slightly smaller version of the same polygon, centered within it.
Fortunately, this is really easy using Turf's transformScale method.
So your steps will be:
Convert your polygon data into GeoJSON. (Which I assume you have some mechanism to do, in order to display it in Mapbox-GL-JS in the first place.)
Generate a smaller polygon using turf.transformScale(base, 0.9)
Add the new polygon with map.addSource
Display the new polygon with map.addLayer, setting the extrusion base height etc as required.

PostGIS - Create Ellipse

Im trying to build a function to create an Ellipse without passing by classic programming language.
I have these parameters stored in a custom GeoJSON.
smallSide and bigSide has to be expressed in meters. Resulting geometry has to be created with EPSG 4326:
My parameters are:
"geography" : {"type":"Ellipse",
"smallSide":100,
"bigSide" : 110,
"rotation" : 0,
"coordinates":[8.54736328125,46.37156925087649]}
Searching on web I found this solution that is very close to resolve my problem:
ST_AsEWKT(ST_Translate( ST_Rotate( ST_Scale( ST_Buffer(ST_Point(8.54736328125,46.37156925087649)::geography, 3000)::geometry, 0.3,0.5)::geometry, 0), 8.54736328125,46.37156925087649))
This function creates an Ellipse near Norway. Try with: http://geojson.io/#map=11/69.5354/11.1216
The original center is in Switzerland.
This function has 2 big problem:
1. The Ellipse is not centered in the coords;
2. I don't know how to convert xFactor/yFactor of Scale to match meters parameters;
PS. This is the WKT of above function:
SRID=4326;POLYGON((11.123273576134 69.5574277440815,11.1230606869505 69.5547928070317,11.1224064250309 69.55225640052,11.1213360407351 69.5499159578464,11.1198907409861 69.547861360983,11.1181260946945 69.5461714955871,11.1161098932273 69.5449112303195,11.1139195487472 69.544128934906,11.1116391298573 69.5438546306632,11.1093561468668 69.5440988431489,11.1071582077927 69.5448522000687,11.1051296707337 69.5460857895281,11.1033484183676 69.5477522651534,11.1018828760511 69.5497876565102,11.100789386429 69.5521138166206,11.1001100408036 69.554641414163,11.099871051113 69.5572733570283,11.1000817266595 69.5599085170987,11.1007340973332 69.5624456140896,11.1018032006992 69.5647871095818,11.1032480248444 69.5668429613212,11.105013073265 69.5685340926073,11.107030493374 69.5697954420587,11.1092226874817 69.5705784748924,11.1115053053956 69.5708530575261,11.1137905020249 69.5706086220194,11.1159903323456 69.5698545746198,11.1180201503338 69.568619932341,11.1198018783021 69.5669522018393,11.1212670184877 69.5649155445927,11.1223592894673 69.5625883002992,11.1230367854657 69.5600599653373,11.123273576134 69.5574277440815))
Welcome to Stack Overflow! I'm not sure I quite understood the parameters bigSide and smallSide, but if you're only trying to create a buffer around a point using meters as parameter, you can use something like this:
SELECT
ST_AsText(
ST_Rotate(
ST_Buffer(
ST_GeomFromText('SRID=4326;POINT(8.54736328125 46.37156925087649)')::GEOGRAPHY,3000, 'quad_segs=16')::GEOMETRY,0));
Which will draw a buffer around the given point (south of Switzerland):
Note: Calculations using GEOMETRY and GEOGRAPHY are made differently, and so are their results. GEOGRAPHY calculates the coordinates over an spherical surface (which can be much slower than GEOMETRY) and uses meters as unit of measurement, while GEOGRAPHY uses a planar projection and uses the SRS unit. (Text from this answer)
The first problem is that you use the original coordinates of the center to translate the geometry. (I mean deltax and deltay in st_translate())
As far as i understand delta should be the difference beetween coordinates you need and actually have.
So the solution is to calculate preliminary (shifted) polygon:
prePoly := ST_Rotate( ST_Scale( ST_Buffer(ST_Point(8.54736328125,46.37156925087649)::geography,
3000)::geometry, 0.3,0.5)::geometry, 0);
and then translate it calculating deltas:
st_translate(prePoly, 8.54736328125 - st_x(ST_Centroid(prePoly)),46.37156925087649 - st_y(ST_Centroid(prePoly)))
I'm not sure that i got the second problem right, but if you originally have big and small sides in meters, you can take one (for example, big one) as a radius of buffer and than calculate
xFactor = smallSide/bigSide, and yFactor = 1
In this case your ellipse will be ellongated along the Y axis.

How to Calculate Tiles Coordinates in Leaflet to Request TMS Server?

In order to cache tiles for off-line use, I tried to calculate tiles coordinates according to a certain zoom level. Calculated x coordinates were correct but the y coordinates Were not.
This Old example compares actually received coordinates with that calculated. (click in the map to display results)
I was using map.project(latlng,zoom) to get the projected coordinates and then divide by tileSize which is 256. is this approach even correct ?
EDIT :
Thanks to Ivan Sanchez for the orientation about y inversion in TMS. Actually after projecting the point with map.project(latlng,zoom) you need to inverse the y coordinate as follow :
You calculate _globalTileRange(zoom) for the corresponding zoom level, then
InvertedY = _globalTileRange(zoom).max.y - y ;
Here is another Link that shows the correct calculation of y coordinates for the current zoom of the map, for other zoom levels the globalTileRange need to be recalculated accordingly.
Regards,
Your approach is correct. However:
In order to get the tile coordinates loaded by Leaflet, you are looping through all the loaded images and outputting the min/max of those values.
The problem with this approach is that Leaflet doesn't immediately unload off-screen tiles. See the keepBuffer option, bug #4039 and PR #4650.
In order to fetch the bounds of tiles visible within the map bounds, see the private methods used internally by L.GridLayer around this line of code.
In TMS, the y coordinate goes up, and in non-TMS tiles it does down. This is because TMS was done by geographers, where the y coordinate is the northing, and non-TMS tiles were initially done by computer programmers, who interpret the y coordinate as downward pixels.
For more background, read https://wiki.openstreetmap.org/wiki/TMS#The_Y_coordinate and https://wiki.osgeo.org/wiki/Tile_Map_Service_Specification#TileMap_Diagram and https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#X_and_Y

Using STDistance with Spatial index on SQL Server 2012 is slower then using COS, SIN & ACOS Calculations and gives oval shaped results

I have a table in a SQL Server 2012 database with 3.000.000 records. Those records represent a point on a map. Al those records have x, y coordinates and geography point as fields (x, y, geo).
I need to calculate all points within a distance of 10.000 meter from a certain point.
Query no. 1 I use :
DECLARE #point geography
DECLARE #rad float
SET #point = geography::STGeomFromText('POINT(51.2207099068778 4.39961050577564)', 4326);
SET #rad = 10000
SELECT count(1)
FROM t_mailbox WITH (INDEX(SIndx_t_mailbox_geo_MHHM_512))
WHERE
#point.STDistance(geo) <= #rad
Result : It takes 4 seconds to find 273.346 points. Drawing those points on a map results in an oval shape on the map.
For sure this is wrong because not all points are included in the result.
Query no. 2 I use :
declare #radius int = 10000
DECLARE #x float = 51.2207099068778
DECLARE #y float = 4.39961050577564
SELECT count(1)
FROM t_mailbox
WHERE
ACOS(COS(RADIANS(90-#x))*COS(RADIANS(90-x)) +SIN(RADIANS(90-#x)) *SIN(RADIANS(90-x))*COS(RADIANS(#y-y)))*6371000 <= #radius
Result : It takes 2 seconds to find 564.547 points. Drawing those points on a map results in a perfect shaped circle.
Questions :
Why is using SPATIAL INDEX and STDistance slower then the more complicated query with SIN, COS and ACOS?
Why is results in a wrong oval shaped set of points?
What am I doing wrong?
Geography data is drawn on the surface of a sphere. This means it looks different than geometry (flat) data.
Imagine taking a globe, and drawing a point on it. Then take a compass and draw a circle around that point. Now peel the skin off the globe. Notice it does not lie flat, to make it flat you have to stretch it. Now the way most people do that, is the stretch the top and bottom (north/south poles) and stretch it until it is the same length as the equator. This makes the circle you drew an oval which is bigger horizontally than vertically.
Now the formula you used is for points within a radius on flat plane. This means that you assume the distance between two lines of longitude is the same no matter what latitude you are (5 feet away from the north pole, the distance between 90 degrees and 91 degrees longitude is much smaller than at the equator).
On a mercator projection map, this formula will make a map that is a perfect circle, however on a globe, it is not. Hopefully this makes sense.
As for you speed issue: A: Apples to oranges, you are doing different calculations. and B: Without knowing how you have your index set up, it is very difficult to analyze, but geography indexing is pretty bad regardless, it works much better on very large geographies like countries.
Whilst hcaelxxam answers the "why" perfectly, you may find better performance by moving away from STDistance(). Whilst not always the case, I have generally found it better to use STIntersects() or STWithin() for distances - how you do this is pretty easy!
Try changing your query to the following. I'd be interested in the results:
DECLARE #point geography;
DECLARE #rad float = 10000;
SET #point = geography::STGeomFromText('POINT(51.2207099068778 4.39961050577564)', 4326).STBuffer(#rad); -- We're creating the "oval" here
SELECT count(1)
FROM t_mailbox WITH (INDEX(SIndx_t_mailbox_geo_MHHM_512))
WHERE
#point.STIntersects(geo) = 1
You may also like to try with and without the index hint. Sometimes, forcing it can generate an inefficient query plan.