|
They start in VVertexA and go orthogonal to the line from LeftData to RightData, so that LeftData is on the left and RightData is on the right.
|
|
|
|
|
Ok, thanks. But what about the vertices. I made a simple polygon generator to test the algorithm and I saw that the location of the vertex for 3 points (i.e. a triangle) is sometimes out of the triangle. But it should be the center of the inscribed circle, shouldn't it ?
VladovsoftSoftware products for fitness and health club management, storehouses, shops and barcode generation.
|
|
|
|
|
No, Voronoi Vertex of a triangle is the center of it's outer circle, which is only inside the triangle for max(angle)<90 degree. (see wiki[^])
B.
|
|
|
|
|
Ok, thanks for the info. I was planning to use Voronoi diagrams for finding the Maximum Inscribed Circle in a simple polygon, but I guess I should read some more information about its properties to determine if it will work for me.
VladovsoftSoftware products for fitness and health club management, storehouses, shops and barcode generation.
|
|
|
|
|
According to this, if I take RightData-LeftData, I get the vector from left to right. Then swapping X and Y and negating one gets an orthogonal vector. Taking the non-unknown point and adding the orthogonal vector should produce the correct ray, with LeftData on the left and RightData on the right. However in some cases it does not, and the ray is cast in the wrong direction, as if LeftData and RightData are in the wrong order.
Do you have a correction for me, or updated version of this code?
|
|
|
|
|
Hi,
sorry, I dont have any free time at the moment... can you verify whether the left/right data points are actually wrong?
B.
|
|
|
|
|
I solved this the same way many other implementations do - don't try to draw the unbounded edges, just contain the points you want to draw within a much larger triangle or square.
With this, I don't have any issues.
|
|
|
|
|
Hello BenDi,
I tried to fix the ray problem many people seem to have. I verified the left/right data points and they really seem to be wrong. If I draw a green/blue line from RightData to LeftData (where the left part of the line is green and the right part is blue) you can see in the picture below, that the right/left side is sometimes wrong.
https://www.dropbox.com/s/1o4zl2izmkuv96d/voronoi_ray_problem.png[^]
Do you have any idea where I could fix that problem? How do you decide which one is the left and which one the right point?
It would be kind if you could help me with this problem, or at least give me a hint. Drawing the rays correctly is really necessary for me and I can't skip them.
Peh
|
|
|
|
|
Hi! As you can see from the image, the left data point (as seen from the center of the VoronoiEdge) is the one with the lower X coordinate.
Can you make the ray problem more precise? Then maybe I can help more.
Cheers,
B.
|
|
|
|
|
Hi,
thanks for your interest in my problem. I understand what you say and you are right for the image I posted. I made a more precise one now.
P are points
M are mids between two points
blue lines point to right data
green lines point to left data
V is the voronoi point (VVertexA)
Rays are drawn by hand so far. Starting at V.
https://www.dropbox.com/s/fqxkg9im5e5bnmk/voronoi_ray_problem2.png[^]
My Problem is how to get the correct direction of the ray vector.
|
|
|
|
|
Ah, I remember.
The right solution was posted a long time by ckaut:
On an unbounded edge, only one point, let's call is 'center', is set. Comput a vector
diff = (left_data+right_data)/2 - center
and paint a line from center to center + N * diff (where N is large enough to go out of your viewing area.
For this it does not matter if left and right are correctly assigned.
BTW: I haven't looked at the code in a while, but it seems like I added
VoronoiEdge.FixedPoint (=center) and VoronoiEdge.DirectionVector (=diff, normalized)
for exactly this purpose Sorry for not documenting it better.
|
|
|
|
|
Yes this looks like a very easy solution and this was what I already tried.
But it's only the solution for the half of this problem.
If the center (V) is within the triangle of the three Points (P) then this way is right (correct for this problem[^]).
But if the center (V) is outside the triangle then it fails too (still fails in this problem[^]). Ray13 should be the other direction here.
|
|
|
|
|
Uh, that's true. Appearantly I did not see this case during debugging.
This will probably need a bit more smarts in the Algorithm itself to correctly assign left and right data points, but I might not have time for that in the near future.
Feel free to give it a shot: in FortuneVoronoi.cs, ProcessDataEvent, left/right data is assigned, but after that there are some special cases for how to insert the new tree nodes. My guess is that left/right data points should be assigned based on the same if/else distinguation. Give it a try!
|
|
|
|
|
This was a nasty trap ;(
I saw this example (Visualization of the 2D Voronoi Diagram and the Delaunay Triangulation[^]) of an implementation of your algorithm. I downloaded both (yours and the example) and picked the wrong one. What I didn't see is that this example is using an old and buggy version of your code.
With the code from this article here I finally got the correct rays by drawing a line using the DirectionVector and the FixedPoint. I better only post a class below how I did it. If anyone is interested in my full example code you can email me, because I don't want anyone to run into the same problems again by republishing another version of this code.
Thanks a lot for your help.
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using BenTools.Mathematics;
namespace FortuneVoronoiVisualisation
{
class Visualisation
{
public static Bitmap GetVoronoiMap(int width, int height, HashSet<Vector> datapoints)
{
Bitmap bmp = new Bitmap(width, height);
VoronoiGraph graph = Fortune.ComputeVoronoiGraph(datapoints);
Graphics g = Graphics.FromImage(bmp);
for (int w = 0; w <= width; w = w + 20)
g.DrawLine(Pens.AntiqueWhite, w, 0, w, height);
for (int h = 0; h <= height; h = h + 20)
g.DrawLine(Pens.AntiqueWhite, 0, h, width, h);
foreach (Vector v in datapoints)
{
g.FillEllipse(Brushes.Red, (int)v[0] - 2, (int)v[1] - 2, 4, 4);
g.DrawEllipse(Pens.Red, (int)v[0] - 2, (int)v[1] - 2, 4, 4);
}
foreach (Vector v in graph.Vertizes)
g.DrawEllipse(Pens.Indigo, (int)v[0] - 2, (int)v[1] - 2, 4, 4);
foreach (VoronoiEdge edge in graph.Edges)
{
try
{
if (!edge.IsPartlyInfinite)
{
g.DrawLine(Pens.Gray, (int)edge.VVertexA[0], (int)edge.VVertexA[1],
(int)edge.VVertexB[0], (int)edge.VVertexB[1]);
}
else
{
if (!edge.IsInfinite)
{
Vector VVertexB = edge.FixedPoint + edge.DirectionVector*edge.VVertexA.SquaredLength;
g.DrawLine(Pens.Blue, (int) edge.VVertexA[0], (int) edge.VVertexA[1],
(int) VVertexB[0], (int) VVertexB[1]);
}
else
{
Vector VVertexA = edge.FixedPoint -
edge.DirectionVector*Math.Sqrt(Math.Pow(width, 2) + Math.Pow(height, 2));
Vector VVertexB = edge.FixedPoint +
edge.DirectionVector*Math.Sqrt(Math.Pow(width, 2) + Math.Pow(height, 2));
g.DrawLine(Pens.Blue, (int)VVertexA[0], (int)VVertexA[1],
(int)VVertexB[0], (int)VVertexB[1]);
}
}
}
catch (Exception e)
{
}
}
return bmp;
}
public static Bitmap GetDelaunayTriangulation(int width, int height, HashSet<Vector> datapoints)
{
Bitmap bmp = new Bitmap(width, height);
VoronoiGraph graph = Fortune.ComputeVoronoiGraph(datapoints);
Graphics g = Graphics.FromImage(bmp);
foreach (Vector v in datapoints)
{
g.FillEllipse(Brushes.Red, (int)v[0] - 2, (int)v[1] - 2, 4, 4);
g.DrawEllipse(Pens.Red, (int)v[0] - 2, (int)v[1] - 2, 4, 4);
foreach (VoronoiEdge edge in graph.Edges)
if (edge.LeftData == v)
g.DrawLine(Pens.Black, (int)edge.LeftData[0], (int)edge.LeftData[1], (int)edge.RightData[0], (int)edge.RightData[1]);
}
return bmp;
}
}
}
|
|
|
|
|
Just a note to say I get the same thing unfortunately.
|
|
|
|
|
In most cases you have 2 infinite edges per area. Just find the crossing point of them and choose direction from this point to the VVertixA (or the midpoint between Left and Right points) of the edge.
|
|
|
|
|
Hi,
Can somebody provides sample code,how to call this function. I am trying following code & getting error as invalid cast
Vector V1 = new Vector(2,2);
Fourtune.ComputeVoronoiGraph(V1);
Quick help would be appreciated.
Thanks
Sunil Terkar
|
|
|
|
|
You need to put your values into a List.. like
List<vector> v=new List<vector>();
v.add(myVector);
//more points added
feed v into ComputeVoronoiGraph
Cheers
Wayne
|
|
|
|
|
Hi great code!
I am trying to change your algorithm to fit the needs of sharpmap.geometries.point.
Sharpamap is a GIS .net .
http://sharpmap.codeplex.com/[^]
As you can imagine I am having some difficulties.
any ideas on the steps i should take ?
|
|
|
|
|
What problems do you have? Contact me by direct message if you want
B.
|
|
|
|
|
i've a problem of virsion with the code diagrm voronoi
i've the virsion 2005 please help me!
|
|
|
|
|
MMMM, very good code! Thank's. I want make class for visualization 2D Voronoi diagram and building Delaunay triangulation.
|
|
|
|
|
Thanks, for the code. Now I'm stuck, I'm trying to make polygons as the input instead of data points for Voronoi diagram. Please help!
|
|
|
|
|
Hi,
as far as I know, the Fortune algorithm is fixed to data points. Dealing with polygon has some nasty possible side-cases (what if they overlap?).
I would suggest this solution:
- Get all points of all polygons
- Compute the voronoi-graph on all points
- 'merge' regions where two neighboring points belong to the same polygon (i.e. remove voronoi edge -> this may also lead to the removal of some voronoi vertices)
if the polygons are sufficiently far from one another, this should give good results. The solution is not perfect because distance to the polygon is interpreted as distance to one of its edges (which is incorrect, distance should also be measured to the edges of the polygons). You can increase precision by artificially creating polygon vertices _on_ the polygon edges, though this will increase processing time, of course.
Just give a try ,
Ben.
|
|
|
|
|
Afternoon
First, great piece of code - have always been interest in Thessien Polygons.
Implementing your code to determine regions of influence use lat/longs as well as using GDI to show the image plot via HTML. Had to add some extra hashing, as well as Convex Hulling to determine boundries to build out necessary polygons - worked perfect.
I have only found one issue, one of lines/vector seem to be computing values that cause the line to plot in the wrong direction. This only occurs if the point it the lowest.
Any ideas ... If you there is way you can get me your email address I will gladly to send you the code or at least send you the out graphic.
Thanks in advance
Ken
Ken
|
|
|
|
|