🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Generating voroni diagrams while limiting its divergence inside bounding boxes

Started by
14 comments, last by JoeJ 1 year, 5 months ago

Aren't you just clipping the convex regions of the Voronoi diagram against other arbitrary regions like the square hole in the first screenshot? It doesn't require any Voronoi diagram specific logic, except deciding what sites should be used to draw the diagram: only those in the clipping region, as most answers assume, or also invisible clipped ones that affect the Voronoi region boundaries “from the outside”, as seems to be the case in the first screenshot where, for instance, the square hides the sites of the two green regions.

Omae Wa Mou Shindeiru

Advertisement

AhmedSaleh said:
Can you show me a pseudo code of that approach? It looks promising ? As usual. I think that library gives the triangulation part of the voroni… so I can use the centers of the triangles ? but how ?

A pseudo code would totally depend on the data structure used to represent a mesh, and how this data structure allows to traverse the mesh.
Basically you need a way to traverse all triangles at a vertex in clockwise (or counterclockwise) order. Then you can form new polygons from the centers of those triangles, like the black one i have drawn as example.

The problem usually is to create adjacency information while (or after) creating a new mesh. To traverse and process the resulting new mesh using the same data structures, you must know the polygons at both sides of an edge, for example.
That's never easy, but again depends on the data structure.

The most widely used data structure seems the ‘Half Edge’ data structure. I use it too, and here are some code examples:

	class HEMesh
	{
	public:

		typedef int32_t Index;

		// edges
		struct HalfEdge
		{
			Index pair; // the other half edge pointing to the other side
			Index next; // next half edge on a polygon in clock wise order
			Index poly; // the polygon this half edge belongs to
			Index vertex; // the single vertex this half edge comes from. to get the poly on the other side, or the second vertex, we would use the pair to get them

			HalfEdge ()
			{
				pair = -1;
				next = -1;
				poly = -1;
				vertex = -1;
			}
		};
		std::vector<HalfEdge> mEdge;

		// vertices
		std::vector<Index> mVertexEdge; // vertices know only one edge connected to them. we get the others using traversal
		std::vector<vec> mVertexPosition;
		
		// polys
		std::vector<Index> mPolyEdge; // a plogon knows only one half edge, we get the rest using traversal
	}

Example to calculate the center (and area) of a polygon, which is an example to traverse all edges around a polygon:

vec HEMesh::CalcPolyCenterAndArea (float &area, const int poly) const
{
	assert (poly!=-1);

	vec center (0);
	float count = 0;
	int eI = GetPolyEdge(poly);
	vec o = GetEdgeVertexPos(eI);
	do {
		eI = GetEdgeNext(eI); // we follow the next edge...
		vec v = GetEdgeVertexPos(eI) - o;
		center += v;
		count += 1.0f;
	} while (eI != GetPolyEdge(poly)); // ... until we are back to the start 
	center /= count;
	center += o;

	// todo: area mostly unused - seperate functions
	vec u = GetEdgeVertexPos(eI) - center;
	area = 0;
	do {
		eI = GetEdgeNext(eI);
		vec v = GetEdgeVertexPos(eI) - center;

		float a = (v.Cross(u)).Length();
		area += a;
		u = v;
	} while (eI != GetPolyEdge(poly));
	area /= 2;

	return center;
}

Calculate the normal of a vertex, which is an example to traverse the edges around a vertex:

vec HEMesh::CalcVertexNormal (const int vertex) const
{
	assert (vertex!=-1);
	int eI = GetVertexEdge(vertex); 
	if (eI==-1) return vec(0);
	vec o = GetVertexPos (vertex);
	vec norm (0);
	do {
		eI = GetEdgePair(eI); // we walk to the other half of the current edge
		
		assert (eI!=-1);
		int pI = GetEdgePoly(eI);
		vec u = GetEdgeVertexPos(eI) - o;

		eI = GetEdgeNext(eI); // then we follow one step to the next, to iterate in a star shaped way around the edges around given vertex

		if (pI != -1)
		{
			vec v = GetEdgeVertexPos(GetEdgePair(eI)) - o;
			float U = u.SqL();
			float V = v.SqL();
			if (U>FP_EPSILON2 && V>FP_EPSILON2)
			{
				float dot = vec(u / sqrt(U)).Dot(v / sqrt(V));
				if (fabs(dot) < 1.0f-FP_EPSILON2)
				{
					float angle = acos(max(-1,min(1, dot)));	
					vec n = vec(u.Cross(v)).Unit();
					norm += n * angle;
				}
			}
		}

	} while (eI != GetVertexEdge(vertex)); 

	float sql = norm.SqL();
	if (sql > FP_EPSILON2) norm /= sqrt(sql);
	else norm = vec(0);
	return norm;
}

The half edge data structure is general and good for all sorts of problems. But as you see, code is hardly readable. You need to get used to it and gather some experience first.

If we only work on one specific problem, like Voronoi Triangulation, V-Diagrams, Convex Hulls, etc., it's more likely people come up with a custom data structure just for the task.
The library you posted seems an example. But then you need to figure out those traversal practices for their data structures, and the snippets you have posted are good examples to get started on that.

LorenzoGatti said:
Aren't you just clipping the convex regions of the Voronoi diagram against other arbitrary regions like the square hole in the first screenshot?

So now it's three of us not exactly knowing what the OP tries to do exactly. ; )

@JoeJ

Basically I wanna do those steps ?

Game Programming is the process of converting dead pictures to live ones .

Ok, then i got you right from the start.

I forgot to mention There are ofc. many ‘centers’ of a triangle or polygon. The simplest one from my code example is just the average of the vertices.

Then there is circumcenter:

Or area center, which is like the center of mass, so we could balance the cut out polygon on a pencil.

And some others…

But instead 'scaling down' around such center, you may want want to move the edges by a constant distance offset from their initial line.
This would give you ‘streets’ all having the same width. Gnollrunners picture also did this i guess.

This topic is closed to new replies.

Advertisement