I'll first introduce the problem: I'm developing an application where I've to show a map field, and overlay markers and lines. However, in BlacBerry OS 5.0, the only MapField available in the API does not provide means to overlay stuff, only show the map at a location. It also provides methods to transform screen coordinates (pixels) to/from WGS84 coordinates. These methods might be computationally expensive.
So to paint my own items, I need to extend this class and override its paint() method. The extending class will also hold a collection of locations.This is how the overriden method would look like (I'll use Java here):
public void paint (Graphics g) {
super.paint(g); //draws the map
//TODO
//Draw placemarks. The placemarks are basically holder objects
//(for latitude and longitude) stored in a collection in this class.
}
However, to paint these objects in the screen we should first convert the placemark locations (lat, long) to screen coordinates (x,y in pixels). This cannot be done in advance since the map is not static, so it is able to scroll and zoom in an out. This is why in each paint loop we should paint at least THE VISIBLE OBJECTS. That said, my question is:
Given a rectangular perimeter where the corners are geographic locations (the transformed four corners of the portion of the map currently displayed), is there a fast method to loop on every placemark in the collection and determine if they are visible or not?
I don't need this test to be 100% accurate, I don't mind if a few locations outside the screen are painted. But as the placemark collection can contain many elements (< 100), and the paint method will be called on each screen repaint, trying to paint every location in the collection without checking if it is visible or not could affect performance and introduce lag when the user interacts with the map.
Before you try to provide a naive answer, notice that this is not a simple geometrical problem: We're working with geographic coordinates, not with integer screen coordinates. The world doesn't end in longitude +180, or in latitude +90. This function should work in the poles and in the ecuator, so I need it to work also when we have a transition line (from -180 to +180, or from -90 to +90, or both lines) intersecting with the rectangle. As the logic can get complex, I'd like to know if there's an existing algorithm or open source library where this has already been done and tested, rather than implementing my own one.
I could also first convert every location in the collection to screen coordinates, and then easily check against a rectangle composed only by positive screen coordinates (starting from x=0, y=0), but as the transformation functions might be expensive, I think it is better to transform only 4 points in each refresh (the visible map corners) than an indeterminate number of placemarks.
Any other approach or idea would also be appreciated.
Thanks in advance.
Just a primitive idea: Take two opposite corners of your "rectangle", e.g. the upper left one and the lower right one. Transform both corners to Cartesian space coordinate (x,y,z) by:
x = cos[long] cos[lat]
y = sin[long] cos[lat]
z = sin[lat]
Both of the (x,y,z) coordinates are unit vectors (imagine the center of the sphere being in (0,0,0), and the vectors being arrows from there to the surface). Find the "middle" of your map area as the normed average of the two corner vectors (add as vectors, then divide by length of sum vector to make sure you have a new unit vector). When you have the middle (xMiddle,yMiddle,zMiddle), for every placemark coordinate transformed into cartesian (x,y,z), use the dot product with (xMiddle,yMiddle,zMiddle) as a measure of the closeness to the middle.
Now include every placemark whose dot product with (xMiddle,yMiddle,zMiddle) is greater than the upper left corner's dot product with (xMiddle,yMiddle,zMiddle).
This should give you all placemarks inside a circular disk centered at "middle".
You could at least rule out a large number of candidates with a naive box check in map coordinate space. There are probably three main cases here. Either there's a pole is in the rectangle or there isn't. If the pole isn't visible, either the rectangle crosses the +/-180 degrees line or not. There can't be any +/-90 line, because that would put together north and south pole and you're not working with a 4D map, are you? ;-)
Case 1, a pole is visible:
If it's the north pole, figure out which of the corners has the smallest latitude. Any latitude smaller than that is likely off-screen. If it's the south pole just reverse the logic, i.e. use the largest latitude and exclude any items with a greater latitude.
I know, having the pole in one corner and the equator in another means you still include an entire hemisphere. But at least you can cheaply exclude the other half.
Case 2, no pole, not crossing the +/-180 longitude line:
Find the min/max longitude and latitude values and use those for a simple box check. Anything outside the box is off-screen.
Case 3, no pole, but crossing the +/-180 longitude line:
Same as above for latitude. For longitude, find the longitudes furthest away from +180 and -180 respectively. Exclude any items with a latitude outside the min/max or between the two furthest longitudes you found.
The cases 2 and 3 should be able to rule out enough candidates to make a brute-force check for the others feasible. Case 1 may require further post-processing, but I'm afraid that part is a bit too complicated for me if you want something sophisticated.
I suppose you could somehow find an off-screen point closest to the pole if the pole is further away from the center of the screen. Then somehow construct a triangle-like shape with one corner at that point and make it as large as possible without touching the screen rectangle.
I think you just need to Convert your rectengular perimeter to geographic coordinates.
Instead of trying to convert the geogrpahic coordinates to screen coordinates.
I'm sorry that the answer is naive - but you do you ask about logic.
And so the logical thing I visualize is a window sliding on a spehere and that means you need to have that window geographical coordinates as your points of reference.
After you process that "3d" information you can start rendering your view.
Related
I need to get inner border of shape. Previously, I found nearest point to the center of shape in case of square or circle shape, but how can I do it in M-shape case.
What I have (I need marked points at screenshot №2):
Any algorithms, steps to find these points?
UPD: Now, I have segments direction vector like (1, 0) or (0.5, 0.5)
It looks like the first step is to simplify by averaging near-neighbour dots into a single point. Then find the smallest convex polygon that contains all points (easily done). Then selectively punch some sides in to meet the internal points (the polygon becomes concave). There are many ways to select which sides to punch in, and which points to punch in to first, and I can't be sure what's best without knowing more about your specific goals.
A simple approach would be to deal first with those points that are closest to an existing side, and punch the nearest side in to meet them. But you may want to apply other scoring conditions to choose the best points to deal with first and the best sides to punch in. For instance, you may want to give higher scores to points that are closely vertically or horizontally aligned with one of the vertices of the current polygon, so that they are dealt with earlier rather than later; and give the sides adjoining that vertex a higher score as candidates for punching in. You probably also want to award longer sides with higher scores as candidates for punching in.
I imagine that with a few simple weighting criteria such as these, you will quickly get some sensible results.
Finally, if you wish, you can refer back to your original set of unaveraged dots, and make further small adjustments to the shape to ensure that all those dots fall outside its boundaries.
I need to find which of four coordinates is equal to the
top left
top right
bottom left
bottom right
from the perspective of a single point/coordinate.
The format of my data is: [[x1, y1], [x2, y2], [x3, y3], [x4, y4], [x1, y1]]
The polygon that this array of coordinates creates could be located in either of the four quadrants around a central point. I need to find which of the (x?, y?) is the respective corner as if I were standing at the central point and looking at the polygon.
Each polygon represents a row in my stadium and I want to plot n number of seats along that polygon. I know that my seats are numbered increasing from left-to-right clockwise around the stadium, but I need to know what's the "left" side of the polygon, and what's the "right" side (plus top and bottom).
I could probably figure this out using if statements (I'm using C# to plot the seats), but I'm wondering if there is a way to mathematically determine the respective corners from a center point.
I am trying to implement some kind of snapping functionality in WPF for a circle (which represents my mouse) and it should snap to another object (normally this would be a line or a rectangle).
Is there a way to do this kind of functionality with WPF without doing all the calculations on my own and if not is there an easy way (library?) to get this kind of information?
Edit: I want to snap the border of the circle to the border of the rectangle/line.
As a first step, you should find the point on the rectangle that is the closest to the cursor, and the distance between the two: extending the edges of the rectangle, you partition the plane into 9 regions. Depending on the region where the cursor lies, the searched distance will be the distance to a corner (Euclidean distance formula) or the distance to an edge (difference of abscissas or ordinates).
Subtract the circle radius from this distance. This will tell you if you are close enough for a snap.
When a snap is possible, move the cursor along the line from the current cursor position to the closest point until you hit the corner or edge. You will need to use the parametric equation of the line segment.
The complete discussion requires some care but only involves simple math.
A similar approach is possible to snap to a line segment. Here is a trick: if you rotate the line segment to make it horizontal, you can consider the line segment as a degenerate rectangle and use the same snapping algorithm. Rotate the line segment and the cursor, apply the snapping logics and then counter-rotate the updated cursor.
That kind of functionality only takes a few lines of code to replicate... I doubt that you'll find a 'library' of code to do it for you. The method is as follows:
Keep a collection that contains the 4 Points that form each shape's bounding box. You then need to handle to MouseMove event on the Canvas, or shape container. In this event, you simply need to ascertain whether the current mouse position is within a certain distance from any of the shape edges... you'll have a little bit more work to do with non-rectangular shapes to calculate their edges, but the principal is the same.
If you detect the presence of a nearby shape, then you simply need to change the value of the nearest dimension to that of the nearby shape... the snap. That's it... much easier than you think.
So I am working on a Risk type game in XNA/C#. I have a map, similar this one, and I need to be able to detect mouseovers on each territory (number). If these areas were squares, it would be easy, as they could each be represented by a rectangle. However, they are different size polygons. Is there a polygon shape that behaves similar to a square? If there isn't, how would I go about doing this?
I sugest this:attach color to each number, recreate your picture in these colors: every shape will be in its particular color. Dont draw it onscreen, use it only as reference map. And when the user clicks or moves mouse over your original map, you just simply project mouse coordinates into the color map, check the color of pixel laying under the mouse and because you have each color associated to number of territory...
This is not c# specific (as I've never written anything in the language, so no idea of what apis there are), though there are 2 algorithms that come to mind for detecting if a point is inside a polygon (which can be used to detect if a mouse point is over another polygon/map shape).
One is based on raycasting, where you cast a ray in 1 direction from the (mouse) point to "infinity" (edge of the board in this case) and count the number of times it crosses the polygon's edges. If it is odd, then the point is inside the polygon, if it is even, then the point is outside of the polygon.
A wiki link to it: http://en.wikipedia.org/wiki/Point_in_polygon#Ray_casting_algorithm
The other algorithm that comes to mind works only for triangles I think but it can be more simple to implement I think (taking a quick glance at your shapes, I think they can easily be broken down into triangles and some are already triangles). It is to do with checking if the point is on the same (internal) "side" of all the edges in the triangle. To find out what "side" a point is on vs an edge, you'd take create 2 vectors, the first vector would be the edge itself (made up of 2 points) and the other vector would be the first point of that edge to the input point, then calculate the cross product of those 2 vectors. The result will be negative or positive, which can be used to determine the "direction".
A link to it: http://www.blackpawn.com/texts/pointinpoly/default.html
(On that page is another algorithm that can also work for triangles)
Hit testing on a polygon is not so difficult to do in real time. You could use a KD-Tree for optimisation if the map is huge. Otherwise find a simple Contains method for a polygon and use that. I have one on another computer. Let me know if you'd like it.
I'm trying to create a bounding box around a set of coordinates, but I want to 'focus' on groups of coordinates and ignore any that are way off and would mess up the map. (Imagine a map of 10 spots on a city and 1 somewhere in another country)
What would be the best way to build the top-left and bottom-right values?
First I would determine your criteria for "fringe locations"
Something like "outside 2 σ" then you just need to calculate your mean in both dimensions and draw your lines at 2σ. If you want some curvy boundary then things get much more complicated... Start at your criteria and move forward from there.
So let's assume you wanted to exclude things more than 2σ from the mean
You need to calculate:
σ(x), σ(y), mean(x), mean(y)
Then your upper left bound is ( mean(x)-2σ(x) , mean(y)+2σ(y) )
and your lower right bound is ( mean(x)+2σ(x) , mean(y)-2σ(y) )
this will yield a rectangle for 2σ in both dimensions. For a circle things will get a bit more complicated... start with defining you "acceptable region"
Compute the centroid, and then pick the point that's nearest that centroid. Then, throw out any point that's more than some constant distance (or, perhaps, some threshold like one or two standard deviations away from that point). Now, re-compute using the trimmed set of points. Do that until you're happy with the result (i.e. all points are within the boundaries that you define).
As Matthew PK said, this will work will for a simple radius, but if you want some type of curved boundary, it's a lot of additional work.
Put to work what you learned in your statistics courses; e.g.:
Calculate the mean of your X and Y coordinates
Calculate the standard deviation (X and Y)
Discard items that are more than two stdevs from your mean
Calculate your bounding box based on the resulting coordinates