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 :)
Related
We have a legacy application that is built using C# System.Windows.Forms.DataVisualization.Charting. We've been asked to create a graph that shows a series of bubble points floating at the same y distance above a horizontal line, scattered left to right based on their values. So far, no problem. However, the next requirement has me a bit stumped. Where two bubbles overlap, they would like the overlapping region to be shaded darker, essentially summing the two colors. Like a Venn diagram but with several dozen data points.
Does anyone know if there is a simple setting we can use to do this? If not, I might have to tell them that its a) not possible with this tool set or b) the best I can do is to increase the shading on an entire bubble when there are multiple data points with the same (or within a range) value.
REWRITE: I wasn't getting much feedback on this question, I assume I did not write it properly and am attempting to clarify.
I am making a program that lets people created countries. The thick red lines in the picture below are the borders to said countries. I am trying to figure out how to generate a polygon that will fill the entire area inside of the "border" lines. I have the triangulation code that accepts the polygons working - I tested that out with a polygon I entered manually - now I'm trying to figure out how to generate the polygon from the lines/linked point.
For more info - all the red lines are how the yellow dots are linked together. The users drag the yellow dots together to link the lines. It is possible for the polygon to have a hole inside and be open - what I am trying to do is make code that handles open polygons and polygons with holes inside it and generates an output of all the yellow dot's locations (vector3's with x and z as it lies at 0 on the y plane) for my triangulation code.
I'm still looking up way to figure this out but I haven't come up with even where to start looking for solutions. Thanks for all the help.
OLD QUESTION BELOW
I'm trying to find a way to link points together to form an internal polygon. Basically, I'm creating a program that lets people link lines together. After a closed polygon is made, it is supposed to generate a new polygon object inside the lines.
I'm not too sure how to do this - I have made it so they can generate the lines and link them together, but how to do a closed polygon escapes me. I looked at convex hulls but this isn't the same, and tried looking or thinking up a few different things that don't seem to work. I'm curious if anyone can point me in the write direction/a tutorial or idea on how to continue on my creation.
I have two pictures uploaded to help show my point.
Above is what I am trying to do but not too sure how - basically, when the user finished a closed polygon (all the yellow dots are the polygon's external points), I want it to generate an internal polygon (marked by the black 1, 2 and 3).
You may be interessted in Polylines. This could help you to prevent lots of research on graph theory. Like the Polygon class, you can fill a Polyline object. The documentation says:
This object is similar to the Polyline object, except that this object must be a closed shape.
Since you want your shape to be "open", this could help you.
And the linked manual page even includes an example of how to create the Polyline programmatically:
// Add the Polyline Element
myPolyline = new Polyline();
myPolyline.Stroke = System.Windows.Media.Brushes.SlateGray;
myPolyline.StrokeThickness = 2;
myPolyline.FillRule = FillRule.EvenOdd;
System.Windows.Point Point4 = new System.Windows.Point(1, 50);
System.Windows.Point Point5 = new System.Windows.Point(10, 80);
System.Windows.Point Point6 = new System.Windows.Point(20, 40);
PointCollection myPointCollection2 = new PointCollection();
myPointCollection2.Add(Point4);
myPointCollection2.Add(Point5);
myPointCollection2.Add(Point6);
myPolyline.Points = myPointCollection2;
myGrid.Children.Add(myPolyline);
Your second requirement is, that your shape can have "holes".
Notice, that you don't have to take care of filling the Polyline. By setting myPolyline.FillRule you can have "holes" inside of your shape. See the Polyline.FillRule page on MSDN, which shows:
If you have further wishes on how to make "holes", have a look at the Geometry.Combine Method and especially the GeometryCombineMode.
An example that demonstrates GeometryCombineModes...
Have fun : )
Pictures and code are example content, provided by Microsoft and were extracted from MSDN. Please take care of the copyrights, which are available through the given links, when reusing it. For using those contents here, I want to refer to the Microsoft Limited Public License.
What about a derivative of Marching Quads? you could have something like this :
for each three points (grouped in creation order inside of the mesh) find the center of the polygon and let the user assign a bool value to it which will define if this polygon is inside or outside the mesh and then draw it or not
You can't create an open polygon. It's only becomes a polygon when it's closed. But, here is an approach that might serve your needs.
Create a closed polygon by connecting all of the available lines, and then calculate the final line that links the starting point with the end point while it's in an intermediate state.
Then,
Draw (not fill) the polygon with a different color than the
background.
Draw the final calculated line with the background color so it disappears.
That approach, or a modified version, will create the illusion of an open polygon.
Commenter #SamyS.Rathore is right. If your question is "How do I find the closed areas (polygons) in a planar graph given its vertices and edges?" then you want to look into Simple Circle algorithms like https://stackoverflow.com/a/14115627/642532 there.
However after finding those circles additional work is required to support holes. Basically what you want to do is to detect wether a polygon is inside another one and then geometrically subtract it.
Simple Circles doesn't deal with partially opened areas. But that shouldn't be a problem in your case, because those areas can only exist at the outer borders of the playing field and the user can easily close them at will.
I got this done by taking every point and linking it to a class that had a base vector3 that was the location of the point, as well as every linked line that went out from it. Basically.
class DoubleV3
Vector3 MiddleVector
List LinkedVectors
I also take care of people having accidentally or purposefully put the same entries multiple times right now by remove all redundant lines.
After that I go through the entire thing and check every doubleV3's linked vectors, I go from every linkedvector to the left-most vector beyond it (basically, I check the last vector and next vector of every linkedvectors list to a north vector 1 up from the middle and take the smallest angle). This gives me a bunch of closed polygons (yes, I know now the proper term is cycle, I now use that). This deals with open cycles (which I do not want). It won't deal with complex cycles that come from overlapping lines, but I deal with that in another method.
After that I simply remove all duplicate polygons and check to make sure no polygon in inside another (I also throw out all internal cycles that aren't part of the outer hull).
Thanks everyone for helping me ^.^ This is how I ended up doing it in case anyone else is in my situation.
I'm looking for an algorithm that can cut a shape with holes into shapes without holes. Language is preferably C#.
Here's an example image of such a shape.
I'd like to cut that shape into the least amount of smaller shapes without holes getting rid of most of the empty space (white). In this case this might probabyl be a bunch of rectangles. But the original shape might be more complex with rounded holes for example.
For me this sounds like some sort of a bin packing problem and therefore might be solved best with a genetical algorithm.
But in case you know a better approach, it's why I ask.
//edit: alright, I've obviously got some things to explain:
The shape is a Geometry object (WPF) resulting from the subtraction of a bunch of small Geometries from a larger Geometry. So I guess there are vertex points stored somewhere.
The amount of resulting shapes should be minimized, yes, the smallest set.
The resulting shapes should have edges that are as straight as possible with the smallest amount of corners possible.
Unfortunately, I can't provide any code, yet, since I have no clou whatsoever how to practically approach this programmatically. I'm really sorry.
The resulting shapes should be complex but don't have to.
To explain the reason for this: I'm working on a textile crafting (in particular patchworking) program with which one can create patchworks and calculate how much fabric is needed and the cost. Placing the patches on the fabric panel already works somehow using a Tetris like algorithm where patches get placed as close together as possible to reduce waste.
Additionally, everywhere the shape gets cut I need to add a seam allowance to the resulting parts (that's what you can already see in green in the example image).
//edit 2 An acceptable solution might look as follows. Red lines show where shape gets cut in order to get an amount of resulting shapes that don't have holes. The result set contains six large and 25 small rectangles:
However depending on the original shape which might look totally different, even with rounded edges (circular holes), acceptable solutions also might look different. The goal is to get rid of the white areas as far as possible while maintaining some convenience regarding the later actual cutting of the fabric. It'd be somehow counter-productive to have lots of shred that has to be sewed together again (and hence all need seam allowances) only to save a little bit fabric more.
I'm not sure how you want the resulting shapes to be but I'm going to assume that you want them in Polygon. As in an object Polygon which is a vector of 2D vertex points (x,y). What you can do now is use this Clipper library for solving geometric spatial problems. It does polygon subtraction, addition, intersection, and a bit more. Its also fast, free, and no license is needed.
http://sourceforge.net/projects/polyclipping/
Afterwards, you can calculate your seam lengths by just finding the distances along each polygon vertex and adding them up. However, this library does not support curved contours.
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 have a following problem. A large rectangle contains smaller non-intersecting rectangles (The black rectangles in the picture below) and I need to find an algorithm to fill remaining free area with non-intersecting rectangles(red ones in the picture below). Speed is not an issue for the algorithm. Also if someone would have an example source code of the algorithm I would really appreciate that.
Edit. Small clarification I need to get the coordinates of the red rectangles not to draw them. I am also working with point data not images.
http://koti.mbnet.fi/niempi2/Squares.gif
Like most bin-packing problems this one looks like an NP-hard problem to me. With 2 rectangles, there are 8! (= 40320) possible arrangements you need to consider. Three rectangles produces 12! possibilities, a cool 480 million.
You'll need an heuristic to make this computable. Beyond favoring the outer edges of the rectangles closest to the bounding rectangle, I don't see a good one. You'd need tighter requirements on the resulting rectangles you accept, the number of them isn't going to help. Glad this is not my problem :)
Although there are multiple possible solutions, I think you can get to one fairly easily.
I would work in increasing values along one axis. By scanning all rectangles and ordering their edge's appearances along that axis, you could walk through them and create rectangles as you go. Each time you hit a new pair of corners, you can compare with the rectangles you currently have 'open' and determine what to do (close them, start new, divide, etc).
That statement isn't a complete solution, but I think it gets you from a complex solution to a simple one. It also doesn't seem to be NP complete in terms of performance. You might even be able to get O(n) perf.
An interesting problem. Let us know how you get on.
Look at the Region class.