SQL Server 2012 geography STIntersects understanding - google-maps

I am trying to get all the points inside the polygon and after a few tests I finally caught.
STIntersects always return 1 for all my entities even in cases when a point "visually" not in a polygon.
I have found posts about polygon creation direction and try it but it didnt't help me :)
So I've decided to create simple case:
polygon with 4 vertexes somewhere in Russia (corners: 55 37, 56 38)
one point inside this polygon
and another one outside
here is a link to google map with points
and results of this test knocked me out of a rut
declare #cw geography, #ccw geography, #pointIn geography, #pointOut geography
-- counterclockwise direction from bottom left corner
set #ccw = geography::STPolyFromText (
'POLYGON((
55.0 37.0
,55.0 38.0
,56.0 38.0
,56.0 37.0
,55.0 37.0
))', 4326
)
-- clockwise direction from bottom left corner
set #cw = geography::STPolyFromText (
'POLYGON((
55.0 37.0
,56.0 37.0
,56.0 38.0
,55.0 38.0
,55.0 37.0
))', 4326
)
set #pointIn = geography::Point(55.5, 37.5, 4326)
set #pointOut = geography::Point(54, 36, 4326)
select #pointIn.STIntersects(#ccw) ccw, #pointIn.STIntersects(#cw) cw
-- result: 1 0
--here i should get inversed values, but it didnt happens
select #pointOut.STIntersects(#ccw) ccw, #pointOut.STIntersects(#cw) cw
-- result: 1 0
Why does this happen? I just can't understand what I am missing
I expect that the pointIn should return 1 when my polygon is small and return 0 when my polygon is whole world minus selected area, and pointOut should return 0 in first case and return 1 in the second one
But both points return 1 in counterclockwise polygon.
UPDATE
finaly
My error was in the order of the input parameters of geography::STPolyFromText
first should be lng and the second lat.
and in extension the order is diferent
msdn says: Point ( Lat, Long, SRID )

In SqlGeography instances, #ccw defines a hole (due to it's counter-clockwise order). As this hole is not within a polygon, it becomes a hole in the Globe. Put another way, you get a Polygon covering the entire globe, minus your #cw polygon.
Geography::Point also uses reverse coordinates to WKT and therefore I believe your latitude and longitude coordinates are the wrong way round (impossible to be absolutely sure) as only you know your data. Regardless, the attached image should enough to explain this. The "Orange" colour being #ccw, the blue being #cw, the rest is labelled.
If you have SSMS you can visualise it using the following query, note the points are buffered so you can see them.
select
'Clockwise' AS Label,
#cw AS Item
union all
select
'Counter-Clockwise' AS Label,
#ccw AS Item
union all
select
'Point In' AS Label,
#pointIn.STBuffer(100000) AS Item
union all
select
'Point Out' AS Label,
#pointOut.STBuffer(100000) AS Item
Hope it helps.

Related

MySQL query claims point is not within polygon

I've drawn a polygon which contains a point in Google Maps. But if I pass the coordinates to MySQL to calculate if the point is within the polygon, it returns false.
SELECT ST_Within(
ST_GeomFromText('POINT(8.34047 54.91320)', 4326),
ST_GeomFromText('POLYGON((62.144619879597 10.486242310988,54.622536815923 2.3124141859883,55.403637023919 23.977453248488,62.144619879597 10.486242310988))', 4326)
) AS is_point_within_polygon;
=> returns 0
But the point is obviously within the polygon:
I double-checked that using Python:
import numpy as np
from shapely.geometry import Point
from shapely.geometry.polygon import Polygon
if __name__ == '__main__':
v0 = [62.144619879597, 10.486242310988]
v1 = [54.622536815923, 2.3124141859883]
v2 = [55.403637023919, 23.977453248488]
lats_vect = np.array([v0[0], v1[0], v2[0]])
lons_vect = np.array([v0[1], v1[1], v2[1]])
lats_vect = np.append(lats_vect, lats_vect[0])
lons_vect = np.append(lons_vect, lons_vect[0])
lons_lats_vect = np.column_stack((lons_vect, lats_vect))
polygon = Polygon(lons_lats_vect)
point = Point(8.34047, 54.9132)
print(point.within(polygon))
=> prints True
What's wrong with the MySQL query?
I think there are two issues here:
First with the query. You list polygon in lat-lon order, but the point seems to be in lon-lat order. You probably want
SELECT ST_Within(
ST_GeomFromText('POINT(54.91320 8.34047)', 4326), -- NOTE CHANGE HERE
ST_GeomFromText('POLYGON((62.144619879597 10.486242310988,54.622536815923 2.3124141859883,55.403637023919 23.977453248488,62.144619879597 10.486242310988))', 4326)
) AS is_point_within_polygon;
Even this query returns FALSE, and this is expected in MySQL. 4326 is Geodesic coordinate system, meaning it operates on the spherical Earth, not on this flat map. With geodesic CRS, edges follow the geodesic shortest lines on Earth, not straight lines on flat map, and for really long lines like here and points close to the edge it matter:
Points slightly further North would be within the polygon, e.g. check out
SELECT ST_Within(
ST_GeomFromText('POINT(56 8.34047)', 4326),
ST_GeomFromText('POLYGON((62.144619879597 10.486242310988,54.622536815923 2.3124141859883,55.403637023919 23.977453248488,62.144619879597 10.486242310988))', 4326)
) AS is_point_within_polygon

Maps into Forge Viewer

Trying to follow the steps https://forge.autodesk.com/blog/add-mapbox-google-maps-forge-viewer but i can't place the model correctly on the map.
I am running the functions listed here: https://learn.microsoft.com/en-us/bingmaps/articles/bing-maps-tile-system:
LatLongToPixelXY(latitude, longitude, 7, out pixelX, out pixelY);
PixelXYToTileXY(pixelX, pixelY, out tileX, out tileY);
The result pixelX = 16225, pixelY = 12249, tileX = 63, tileY = 47.
I substitute the previous values:
map.position.set(16225,12249,-45);
class MapPlaneNode extends MapNode {
constructor(parentNode = null, mapView = null, location = MapNode.ROOT, level = 7, x = 63, y = 47)
The result is that the model comes out small and not positioned correctly. In the image, the red arrow is where the model is inserted, and the green arrow is where it should be.
image of result
What am I doing wrong?
Thank you very much
Positioning the model is a little tricky.
In the demo I created, I originally used world coordinates, where I set the root tile as level 0, and used the correct lat/long coordinate utils function to position the revit model in the correct location.
Unfortunately, the precision caused a rendering problem with the post-renderer (line edges were missing, and some strange z-fighting precision issues)...
so, I decided to hack the level, and move the map into the position I wanted and center the revit model at origin 0,0,0.
This made things a lot more manual and rather tricky, but it got around the rendering issue and also limited the user into a small area in the world, which I preferred.
I suggest changing the root tile back to zero, and adjusting the model position globaloffset to the value of the lat/long W84 utils. See the blog post and also the coordinates section of the geo-three repo, for more details here: https://github.com/tentone/geo-three#coordinates
Found a trick to adjust the map. It is still manual but it's fairly quick:
Calculate Tile X and Y (you did that step already, it's just for reference):
Copy the TileSystem class from the the link bing-maps-tile-system you posted into https://dotnetfiddle.net/
(you'll also need to add: using System.Text)
Change the main as follows
public static void Main()
{
int pixelX, pixelY, tileX, tileY;
TileSystem.LatLongToPixelXY(YOUR LAT HERE, YOUR LONG HERE, 7, out pixelX, out pixelY);
Console.WriteLine("LatLongToPixelXY: " + pixelX.ToString() + ", " + pixelY.ToString());
TileSystem.PixelXYToTileXY(pixelX, pixelY, out tileX, out tileY);
Console.WriteLine("PixelXYToTileXY: " + tileX.ToString() + ", " + tileY.ToString());
}
This will give you the TileX and Tile Y that you'll need to replace in the Extension.
Calculate Position
In the Extension set the X, Y position to 0,0, and the adjust the Z so that the map is below your model
map.position.set(0, 0, z);
Run the Extension and see where your project lands on the map. Now locate this landing point in Google maps (I found it useful at this stage to search the map using a corner between two streets by entering for example: Parker St & Wilson Rd). When you've found it, click on the landing point in Google map to place a Marker, then right-click on the marker and select Measure Distance. You will have to measure the distance to your destination both vertically, and horizontally (not directly to it). For example you'll get dH = 43.5km and dV = 17.8km
And this is were the magic happens: Multiply both numbers by 3400 if your distance is in km (or by 2113 if you distance is in miles) and set the position with those values:
dH * 3400 = 147900
dV * 3400 = 60520
If your destination is to the E or S use positive values.
If your destination is to the W or N use negative values
map.position.set(147900, -60520, z);
Now it won't be perfect, but it'll be close enough to finish adjusting the value manually.

Wrapping around 360 degrees with SQL query

I am fairly new with using SQL and I would like to learn how to efficiently filter a data set of ecliptic coordinates (longitude, latitude) for regions of the sky. The data set is in the southern ecliptic hemisphere (from -90 to 0 and 0 to 360) as shown below (simulated in Python with some simple numpy arange commands).
I have figured out how to filter a specific patch of the sky in python with the following code:
x = (eclong + 360 - center) % 360
ind = x > 180
x[ind] = x[ind] - 360 #converts from 0 to 360 to -180 to +180
x = -x #reverses scale where east direction is on left
To allow data points to wrap around the South pole, I also have an additional required condition:
filtered_eclong = (x < 12/np.cos(eclat *np.pi/180)) & (-12/np.cos(eclat *np.pi/180) < x & eclat < 0)
12 degrees is how wide the patch of sky that I want to grab is and center is a variable for the central ecliptic longitude of my desired patch of sky. The last line in the query is a correction to include objects near the southern ecliptic pole. (Note: eclat = ecliptic latitude , eclong = ecliptic longitude, both in degrees) As an example of the results I would like to get, the patch of sky I want to filter is centered on a ecliptic longitude of 315.8 degrees, seen below:
I've saved the entire simulated southern hemisphere as a csv file and uploaded the eclong and eclat values as columns in a sql database. I would like to be able to recreate the same query I performed in my Python code above. This is the closest attempt I have:
select * from coords
where eclat < -6
and mod(abs(eclong-315.8+360),360)-360 < 180
and mod(abs(eclong-315.8),360) < 12/cos(radians(eclat));
which produces this result where the filtered Python result is shown in red and the filtered sql result is shown in blue:
As shown, my query doesn't include things that wrap around from 360 degrees to 0 degrees and I'm not quite sure how to include those missing points.
I think using some combination of THEN, ELSE or CASE statements would help:
select * from Catalog
where eclat < -6
CASE
WHEN mod(abs(eclong-315.8),360) < 12/cos(radians(eclat)) > 0 THEN 'I'm not sure what to do...'
WHEN mod(abs(eclong-315.8),360) < 12/cos(radians(eclat)) < 360 THEN 'I'm not sure what to do...'
into myDB.filename
Any SQL gurus out there?
Though I'm not familiar with ecliptic coordinates, it sounds like you're trying to reconcile the lack of negative numbers based on your title. If that's indeed what you're going for, who cares that there aren't any negative values—let's pretend there are!
To generalize, we'll need to ensure we can safely calculate ±180 degrees from any starting longitude. With this use case, starting from 11 degrees, we could rearrange the unhelpful values by subtracting 360 from anything greater than 11 + 180 and working with the result as a helper. This way, 359 degrees would instead show up as -1, and then you can do normal math. If your starting longitude is above 180, we'd need to get the lowest values above 360. In SQL, here's a (maybe inefficient, but straightforward) way I'd create a helper column:
CASE
WHEN center < 180 THEN CASE
WHEN eclong > center + 180 THEN eclong - 360
ELSE eclong
END
WHEN center > 180 THEN CASE
WHEN eclong < center - 180 THEN eclong + 360
ELSE eclong
END
ELSE eclong
END as friendly_eclong

Create a function to generate random points in a parallelogram

I hope someone can help me here, I have been asked to write some code for an Lua script for a game. Firstly i am not an Lua Scripter and I am defiantly no mathematician.
What i need to do is generate random points within a parallelogram, so over time the entire parallelogram becomes filled. I have played with the scripting and had some success with the parallelogram (rectangle) positioned on a straight up and down or at 90 degrees. My problem comes when the parallelogram is rotated.
As you can see in the image, things are made even worse by the coordinates originating at the centre of the map area, and the parallelogram can be positioned anywhere within the map area. The parallelogram itself is defined by 3 pairs of coordinates, start_X and Start_Y, Height_X and Height_Y and finally Width_X and Width_Y. The random points generated need to be within the bounds of these coordinates regardless of position or orientation.
Map coordinates and example parallelogram
An example of coordinates are...
Start_X = 122.226
Start_Y = -523.541
Height_X = 144.113
Height_Y = -536.169
Width_X = 128.089
Width_Y = -513.825
In my script testing i have eliminated the decimals down to .5 as any smaller seems to have no effect on the final outcome. Also in real terms the start width and height could be in any orientation when in final use.
Is there anyone out there with the patients to explain what i need to do to get this working, my maths is pretty basic, so please be gentle.
Thanks for reading and in anticipation of a reply.
Ian
In Pseudocode
a= random number with 0<=a<=1
b= random number with 0<=b<=1
x= Start_X + a*(Width_X-Start_X) + b*(Height_X-Start_X)
y= Start_Y + a*(Width_Y-Start_Y) + b*(Height_Y-Start_Y)
this should make a random point at coordinates x,y within the parallelogram
The idea is that each point inside the parallelogram can be specified by saying how far you go from Start in the direction of the first edge (a) and how far you go in the direction of the second edge (b).
For example, if you have a=0, and b=0, then you do not move at all and are still at Start.
If you have a=1, and b=0, then you move to Width.
If you have a=1, and b=1, then you move to the opposite corner.
You can use something like "texture coordinates", which are in the range [0,1], to generate X,Y for a point inside your parallelogram. Then, you could generate random numbers (u,v) from range [0,1] and get a random point you want.
To explain this better, here is a picture:
The base is formed by vectors v1 and v2. The four points A,B,C,D represent the corners of the parallelogram. You can see the "texture coordinates" (which I will call u,v) of the points in parentheses, for example A is (0,0), D is (1,1). Every point inside the parallelogram will have coordinates within (0,0) and (1,1), for example the center of the parallelogram has coordinates (0.5,0.5).
To get the vectors v1,v2, you need to do vector subtraction: v1 = B - A, v2 = C - A. When you generate random coordinates u,v for a random point r, you can get back the X,Y using this vector formula: r = A + u*v1 + v*v2.
In Lua, you can do this as follows:
-- let's say that you have A,B,C,D defined as the four corners as {x=...,y=...}
-- (actually, you do not need D, as it is D=v1+v2)
-- returns the vector a+b
function add(a,b)
return {x = a.x + b.x, y = a.y + b.y} end
end
-- returns the vector a-b
function sub(a,b)
return {x = a.x - b.x, y = a.y - b.y} end
end
-- returns the vector v1*u + v2*v
function combine(v1,u,v2,v)
return {x = v1.x*u + v2.x*v, y = v1.y*u + v2.y*v}
end
-- returns a random point in parallelogram defined by 2 vectors and start
function randomPoint(s,v1,v2)
local u,v = math.random(), math.random() -- these are in range [0,1]
return add(s, combine(v1,u,v2,v))
end
v1 = sub(B,A) -- your basis vectors v1, v2
v2 = sub(C,A)
r = randomPoint(A,v1,v2) -- this will be in your parallelogram defined by A,B,C
Note that this will not work with your current layout - start, width, height. How do you want to handle rotation with these parameters?

Determining if a lat-long rect and a circle on a sphere overlap

Suppose I have the following:
A region defined by minimum and maximum latitude and longitude (commonly a 'lat-long rect', though it's not actually rectangular except in certain projections).
A circle, defined by a center lat/long and a radius
How can I determine:
Whether the two shapes overlap?
Whether the circle is entirely contained within the rect?
I'm looking for a complete formula/algorithm, rather than a lesson in the math, per-se.
warning: this can be tricky if the circles / "rectangles" span large portions of the sphere, e.g.:
"rectangle": min long = -90deg, max long = +90deg, min lat = +70deg, max lat = +80deg
circle: center = lat = +85deg, long = +160deg, radius = 20deg (e.g. if point A is on the circle and point C is the circle's center, and point O is the sphere's center, then angle AOC = 40deg).
These intersect but the math is likely to have several cases to check intersection/containment. The following points lie on the circle described above: P1=(+65deg lat,+160deg long), P2=(+75deg lat, -20deg long). P1 is outside the "rectangle" and P2 is inside the "rectangle" so the circle/"rectangle" intersect in at least 2 points.
OK, here's my shot at an outline of the solution:
Let C = circle center with radius R (expressed as a spherical angle as above). C has latitude LATC and longitude LONGC. Since the word "rectangle" is kind of misleading here (lines of constant latitude are not segments of great circles), I'll use the term "bounding box".
function InsideCircle(P) returns +1,0,or -1: +1 if point P is inside the circle, 0 if point P is on the circle, and -1 if point P is outside the circle: calculation of great-circle distance D (expressed as spherical angle) between C and any point P will tell you whether or not P is inside the circle: InsideCircle(P) = sign(R-D) (As user #Die in Sente mentioned, great circle distances have been asked on this forum elsewhere)
Define PANG(x) = the principal angle of x = MOD(x+180deg, 360deg)-180deg. PANG(x) is always between -180deg and +180deg, inclusive (+180deg should map to -180deg).
To define the bounding box, you need to know 4 numbers, but there's a slight issue with longitude. LAT1 and LAT2 represent the bounding latitudes (assuming LAT1 < LAT2); there's no ambiguity there. LONG1 and LONG2 represent the bounding longitudes of a longitude interval, but this gets tricky, and it's easier to rewrite this interval as a center and width, with LONGM = the center of that interval and LONGW = width. NOTE that there are always 2 possibilities for longitude intervals. You have to specify which of these cases it is, whether you are including or excluding the 180deg meridian, e.g. the shortest interval from -179deg to +177deg has LONGM = +179deg and LONGW = 4deg, but the other interval from -179deg to +177deg has LONGM = -1deg and LONGW = 356deg. If you naively try to do "regular" comparisons with the interval [-179,177] you will end up using the larger interval and that's probably not what you want. As an aside, point P, with latitude LATP and longitude LONGP, is inside the bounding box if both of the following are true:
LAT1 <= LATP and LATP <= LAT2 (that part is obvious)
abs(PANG(LONGP-LONGM)) < LONGW/2
The circle intersects the bounding box if ANY of the following points P in PTEST = union(PCORNER,PLAT,PLONG) as described below, do not all return the same result for InsideCircle():
PCORNER = the bounding box's 4 corners
the points PLAT on the bounding box's sides (there are either none or 2) which share the same latitude as the circle's center, if LATC is between LAT1 and LAT2, in which case these points have the latitude LATC and longitude LONG1 and LONG2.
the points PLONG on the bounding box's sides (there are either none or 2 or 4!) which share the same longitude as the circle's center. These points have EITHER longitude = LONGC OR longitude PANG(LONGC-180). If abs(PANG(LONGC-LONGM)) < LONGW/2 then LONGC is a valid longitude. If abs(PANG(LONGC-180-LONGM)) < LONGW/2 then PANG(LONGC-180) is a valid longitude. Either or both or none of these longitudes may be within the longitude interval of the bounding box. Choose points PLONG with valid longitudes, and latitudes LAT1 and LAT2.
These points PLAT and PLONG as listed above are the points on the bounding box that are "closest" to the circle (if the corners are not; I use "closest" in quotes, in the sense of lat/long distance and not great-circle distance), and cover the cases where the circle's center lies on one side of the bounding box's boundary but points on the circle "sneak across" the bounding box boundary.
If all points P in PTEST return InsideCircle(P) == +1 (all inside the circle) then the circle contains the bounding box in its entirety.
If all points P in PTEST return InsideCircle(P) == -1 (all outside the circle) then the circle is contained entirely within the bounding box.
Otherwise there is at least one point of intersection between the circle and the bounding box. Note that this does not calculate where those points are, although if you take any 2 points P1 and P2 in PTEST where InsideCircle(P1) = -InsideCircle(P2), then you could find a point of intersection (inefficiently) by bisection. (If InsideCircle(P) returns 0 then you have a point of intersection, though equality in floating-point math is generally not to be trusted.)
There's probably a more efficient way to do this but the above should work.
Use the Stereographic projection. All circles (specifically latitudes, longitudes and your circle) map to circles (or lines) in the plane. Now it's just a question about circles and lines in plane geometry (even better, all the longitues are lines through 0, and all the latitudes are circles around 0)
Yes, if the box corners contain the circle-center.
Yes, if any of the box corners are within radius of circle-center.
Yes, if the box contains the longitude of circle-center and the longitude intersection of the box-latitude closest to circle-center-latitude is within radius of circle-center.
Yes, if the box contains the latitude of circle-center and the point at radius distance from circle-center on shortest-intersection-bearing is "beyond" the closest box-longitude; where shortest-intersection-bearing is determined by finding the initial bearing from circle-center to a point at latitude zero and a longitude that is pi/2 "beyond" the closest box-longitude.
No, otherwise.
Assumptions:
You can find the initial-bearing of a minimum course from point A to point B.
You can find the distance between two points.
The first check is trivial. The second check just requires finding the four distances. The third check just requires finding the distance from circle-center to (closest-box-latitude, circle-center-longitude).
The fourth check requires finding the longitude line of the bounding box that is closest to the circle-center. Then find the center of the great circle on which that longitude line rests that is furthest from circle-center. Find the initial-bearing from circle-center to the great-circle-center. Find the point circle-radius from circle-center on that bearing. If that point is on the other side of the closest-longitude-line from circle-center, then the circle and bounding box intersect on that side.
It seems to me that there should be a flaw in this, but I haven't been able to find it.
The real problem that I can't seem to solve is to find the bounding-box that perfectly contains the circle (for circles that don't contain a pole). The bearing to the latitude min/max appears to be a function of the latitude of circle-center and circle-radius/(sphere circumference/4). Near the equator, it falls to pi/2 (east) or 3*pi/2 (west). As the center approaches the pole and the radius approaches sphere-circumference/4, the bearing approach zero (north) or pi (south).
How about this?
Find vector v that connects the center of the rectangle, point Cr, to the center of the circle. Find point i where v intersects the rectangle. If ||i-Cr|| + r > ||v|| then they intersect.
In other words, the length of the segment inside the rectangle plus the length of the segment inside the circle should be greater than the total length (of v, the center-connecting line segment).
Finding point i should be the tricky part, especially if it falls on a longitude edge, but you should be able to come up with something faster than I can.
Edit: This method can't tell if the circle is completely within the rectangle. You'd need to find the distance from its center to all four of the rectangle's edges for that.
Edit: The above is incorrect. There are some cases, as Federico Ramponi has suggested, where it does not work even in Euclidean geometry. I'll post another answer. Please unaccept this and feel free to vote down. I'll delete it shortly.
This should work for any points on earth. If you want to change it to a different size sphere just change the kEarchRadiusKms to whatever radius you want for your sphere.
This method is used to calculate the distance between to lat and lon points.
I got this distance formula from here:
http://www.codeproject.com/csharp/distancebetweenlocations.asp
public static double Calc(double Lat1, double Long1, double Lat2, double Long2)
{
double dDistance = Double.MinValue;
double dLat1InRad = Lat1 * (Math.PI / 180.0);
double dLong1InRad = Long1 * (Math.PI / 180.0);
double dLat2InRad = Lat2 * (Math.PI / 180.0);
double dLong2InRad = Long2 * (Math.PI / 180.0);
double dLongitude = dLong2InRad - dLong1InRad;
double dLatitude = dLat2InRad - dLat1InRad;
// Intermediate result a.
double a = Math.Pow(Math.Sin(dLatitude / 2.0), 2.0) +
Math.Cos(dLat1InRad) * Math.Cos(dLat2InRad) *
Math.Pow(Math.Sin(dLongitude / 2.0), 2.0);
// Intermediate result c (great circle distance in Radians).
double c = 2.0 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1.0 - a));
// Distance.
// const Double kEarthRadiusMiles = 3956.0;
const Double kEarthRadiusKms = 6376.5;
dDistance = kEarthRadiusKms * c;
return dDistance;
}
If the distance between any vertex of the rectangle is less than the distance of the radius of the circle then the circle and rectangle overlap. If the distance between the center of the circle and all of the vertices is greater than the radius of the circle and all of those distances are shorter than the width and height of the rectangle then the circle should be inside of the rectangle.
Feel free to correct my code if you can find a problem with it as I'm sure there some condition that I have not thought of.
Also I'm not sure if this works for a rectangle that spans the ends of the hemispheres as the distance equation might break down.
public string Test(double cLat,
double cLon,
double cRadius,
double rlat1,
double rlon1,
double rlat2,
double rlon2,
double rlat3,
double rlon3,
double rlat4,
double rlon4)
{
double d1 = Calc(cLat, cLon, rlat1, rlon1);
double d2 = Calc(cLat, cLon, rlat2, rlon2);
double d3 = Calc(cLat, cLon, rlat3, rlon3);
double d4 = Calc(cLat, cLon, rlat4, rlon4);
if (d1 <= cRadius ||
d2 <= cRadius ||
d3 <= cRadius ||
d4 <= cRadius)
{
return "Circle and Rectangle intersect...";
}
double width = Calc(rlat1, rlon1, rlat2, rlon2);
double height = Calc(rlat1, rlon1, rlat4, rlon4);
if (d1 >= cRadius &&
d2 >= cRadius &&
d3 >= cRadius &&
d4 >= cRadius &&
width >= d1 &&
width >= d2 &&
width >= d3 &&
width >= d4 &&
height >= d1 &&
height >= d2 &&
height >= d3 &&
height >= d4)
{
return "Circle is Inside of Rectangle!";
}
return "NO!";
}
One more try at this...
I think the solution is to test a set of points, just as Jason S has suggested, but I disagree with his selection of points, which I think is mathematically wrong.
You need to find the points on the sides of the lat/long box where the distance to the center of the circle is a local minimum or maximum. Add those points to the set of corners and then the algorithm above should be correct.
I.e, letting longitude be the x dimension and latitude be the y dimension, let each
side of the box be a parametric curve P(t) = P0 + t (P1-P0) for o <= t <= 1.0, where
P0 and P1 are two adjacent corners.
Let f(P) = f(P.x, P.y) be the distance from the center of the circle.
Then f (P0 + t (P1-P0)) is a distance function of t: g(t). Find all the points where the derivative of the distance function is zero: g'(t) == 0. (Discarding solutions outsize the domain 0 <= t <= 1.0, of course)
Unfortunately, this needs to find the zero of a transcendental expression, so there's no closed form solution. This type of equation can only solved by Newton-Raphson iteration.
OK, I realize that you wanted code, not the math. But the math is all I've got.
For the Euclidean geometry answer, see: Circle-Rectangle collision detection (intersection)