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.
Related
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.
I need to arrange tooltips for points that are located on a complex 2D shape.
The tooltips have different sizes
They must not obscure the shape itself
The lines that connect the tooltip to the points should not cross one each other.
The tooltip should be as mush closer to the point it belongs to.
I've tried several searches in google but nothing was close enough to what I need.
You've asked quite a doozy. I haven't personally worked on something like this, another SO member will likely be able to give you a complete solution. However, here are some points to consider when finding your solution.
1. The tooltips have different sizes
You will need a way determining this independently of your shape location algorythm. Performing the re-size as part of step 2 would make things much more complicated and may result in inconsistent behavior. So firstly, look into generating the dimensions of your tooltips.
2. They must not obscure the shape itself
In principle, you want a solution where the tooltip is not 'colliding' 'inside' the complex shape. Looking up '2d shape collision detection' would help here. You will need to know the dimensions of the shape of interest. You can't use a picture of a shape (unless you use a map of some sort). Most algorythms will require the following information for shapes containing concave points:
The points (2d vectors) that make up the complex shape
The points from which tooltips "spawn"
The tooltip dimensions (see point 1)
3. The lines that that connect the tooltip to a point should not cross eachover
This makes the problem significantly more complicated because it implies that multiple tooltips generated by #2 may be visible at the same time which will introduce alot of complexity.
Now you have N tooltips which need N locations occupying different areas which may not overlap, collide with the complex shape, or, when a line is drawn from them to point x, does not intersect any other lines from the remaining (N-1) shapes. It means the algorthm must be performed on the entire set and find the correct locations for all of them, a kind of three body problem.
4. The tooltip must be as close as possible to its associated point
This adds another small caveat which, because of stipulations set in #3 may not be able to be met 'ideally' (what if two shapes are colliding near two close points, which one 'wins out'?).
Again, these are some points to consider as you generate a solution. The result is that you have mathematically 'ideal' locations for your tooltips. However, with these considerations in mind, you may want to look into where realistic concessions may be made. If it's for a design project where the complex shape is unlikely to change then semimanual solutions may be better. If it's for a complex piece of software that will require automatically generated locations you may be able to redesign the UI to give the user the necessary feedback without such a complex solution.
A heuristic:
Compute the centroid of the points.
Place a circle, centered at the centroid, fully enclosing the shape.
Find the places on the circle, where a line form the center through each point
intersects the circle, i.e. project the points on the the circle.
These locations would serve as corners for the tooltip, depending on the which quadrant the point on the circle is, relative to the circle center.
You may increase the circle radius a bit, for aesthetic purposes :)
If I'm not mistaken, this should cover requirements (1), (2) and (3). For (4) you can refine the initial place by moving the tooltip towards the sphere center and checking for intersection with the shape, e.g. using binary search.
Something like this:
There are problems with this approach, of course, but nevertheless it may turn out to be a good starting point for refinement :)
Ok, in my XNA project i've added simple shader + model loading code, anything works. I created a very simple low-detailed model in 3Ds Max. Exported and imported to XNA with FBX format.
The problem is:
if i move my simple camera to some distance from this model, one of its components starts to flicker. I tried another model and there is the same situation, some of components start to flicker and only if i get to some distance from model.
This flickering (or blinking or ..) appears only with textured objects (probably), and looks like:
in each frame random parts/pixels of model (or not so random) replaced with object which is behind a model or its component... :(
UPDATE: Now i know - problem is in my model (i checked some other models). I dont understand why but Plane object gives that flickering. Maybe the problem is not in Plane object.
This is only an educated guess but: Your far-plane is too far away, or your near-plane is too close, or both.
A perspective camera gives you a viewable area that looks like this:
Your Z-buffer (depth buffer) covers the range between the near and the far planes. A typical Z-buffer might have 24-bits of precision, giving you 224 possible values. The further apart your near and far planes are, the greater the world-space distance each possible value must covers. In other words: your Z buffer is less accurate.
What you are seeing is known as "Z-fighting". This is where the Z-buffer is not accurate enough to differentiate between the depths of two given pixels. So you end up with pixels that should have been rejected as being "behind" what was already rendered, drawn instead.
(Alternately your model has some coplanar or nearly coplanar triangles - that is triangles who's surfaces are too close together. Same issue: Not enough precision in the Z-buffer to differentiate between the two surfaces.)
You may also wish to enable backface-culling (RasterizerState.CullCounterClockwise), if it is not already enabled. This culls triangles facing away from the camera, removing one possible source of Z-fighting.
I have seen this happen before on models where there are two or more surfaces overlapping in the same plane, one surface is inside the other but in the same plane - so the system can not tell which surface is in front of the other and usually ends up with a mash-up of both surfaces.
It looks like you have a smaller rectangular surface intersecting with a larger rectangular surface that makes up the lower base shape of your model. Probably from another object inside the box? Or from a object subtraction error that left two rectangles inside each other on that surface maybe?
Either way modify the model so there are no longer two surfaces with in each other.
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.
We want a c# solution to correct the scanned image because it is rotated. To solve this problem we must detect the rotation angle first and then rotate the image. This was our first thought for our problem. But then we thought image warping would be more accurate as I think it would make the scanned image like our template. Then we can process it as we know all the coordinates of our template... I searched for a free SDK or a free solution in c#. Helping me in this will be great as it is the last task in our work. Really, thanks for all.
We used the PrimeOCR product to do this. It's not free, but we couldn't find a free program that was comparable.
So, the hard part is to detect the angle of the page.
If you have full control over the template, the simplest way to do this is probably to come up with an easily-detectable symbol (e.g. a solid black circle) and stick 3 of them on the template. Then, detect them (just look for big blocks of pixels with high saturation, in the case of a solid black circle).
So, you'll then have 3 sets of coordinates. If you have a top circle, a left circle, and a right circle with all 3 circles at difference distances from one another, detecting which circle is the top circle should be pretty easy.
Then just call a rotation function. This part is easy and has been done before (e.g. http://www.switchonthecode.com/tutorials/csharp-tutorial-image-editing-rotate ).
Edit:
I suggested a circle because it's easier to find the center, but a rectangle should work, too.
To be more explicit about how to actually locate the rectangles/circles, take the average Brightness value of every a × a group of pixels. If that value is greater than b, then that a × a group of pixels is part of a rectangle. a and b are varables you'll want to come up with yourself.
Use flood-fill (or, more precisely, Connected Component Labeling) group the resulting pixels together. The end result should give you your rectangles.