Replies: 5 comments 25 replies
-
|
Not sure I understand what is shown in the image and what is it you would like to achieve? |
Beta Was this translation helpful? Give feedback.
-
|
Ok, I'm sorry being not clear. The image presents 2 valid triangulations of exactly same input, red and green. Yellow edges are ones that are identical in both triangulations. What I would like to achieve is a way to extract 'unified polygonal mesh' for degenerated parts of triangulations (triangles adjacent to each other with vertices sharing same circumcenter). |
Beta Was this translation helpful? Give feedback.
-
|
Is this possible to make such tests using current CDT api or should I route my code directly to predicates library? |
Beta Was this translation helpful? Give feedback.
-
|
I've finished 'polygonization' routine. It makes possible to compare results even if there are multiple valid solutions to the same input. Suggestions are welcome! typedef std::vector<TriInd> Poly;
template <typename T, typename L = LocatorKDTree<T> >
std::vector<Poly> Polygonize(Triangulation<T, L>& cdt)
{
typedef TriInd PolyInd;
// for every tri, here we store index of the poly the tri belongs to
auto map = std::vector<PolyInd>(cdt.triangles.size());
// vector of Polys, each as a vector of tri indices belonging to the Poly
auto polys = std::vector<Poly>();
for (TriInd iT = 0; iT < cdt.triangles.size(); iT++)
{
const auto& tri = cdt.triangles[iT];
auto merged = false;
// compare i'th tri with its adjacent tris
for (const auto adj : tri.neighbors)
{
// but only if there's adjacent tri and it is processed already
if (adj == noNeighbor || adj > iT)
continue;
// locate reflex vert in adj triangle
const auto& vr =
cdt.vertices[opposedVertex(cdt.triangles[adj], iT)];
const auto& v1 = cdt.vertices[tri.vertices[0]];
const auto& v2 = cdt.vertices[tri.vertices[1]];
const auto& v3 = cdt.vertices[tri.vertices[2]];
using predicates::adaptive::incircle;
if (!incircle(vr.x, vr.y, v1.x, v1.y, v2.x, v2.y, v3.x, v3.y))
{
if (!merged)
{
// append tri to already existing poly
merged = true;
const auto append_to = map[adj];
map[iT] = append_to;
polys[append_to].push_back(iT);
}
else
{
const auto merge_to = map[iT];
const auto merge_from = map[adj];
if (merge_to == merge_from)
continue;
// funny case, tri is a bridge between 2 polys merge'em all
// together
for (const auto i : polys[merge_from])
{
map[i] = merge_to; // remap
polys[merge_to].push_back(i); // merge
}
if (merge_from != polys.size() - 1)
{
// replace merge_from poly with last poly in polys
polys[merge_from] = polys.back();
for (const auto i : polys[merge_from])
{
map[i] = merge_from; // remap
}
}
polys.pop_back();
}
}
}
if (!merged)
{
// at the moment, just alone tri
// make a new poly for it
map[iT] = polys.size();
polys.push_back({ iT });
}
}
// post-proc
// first triangle in poly should define first 3 vertices at Triangle::vertices[0,1,2]
// every next triangle should define additional 1 vertex at Triangle::vertices[0]
// triangle iterator around vertex,
// noNeighbor is not checked here!
struct Stepper
{
const Triangulation<T, L>& cdt;
TriInd current;
int around;
Stepper(const Triangulation<T, L>& cdt, TriInd t, int a) : cdt(cdt), current(t), around(a) {}
void StepOver(int a)
{
around = a;
}
TriInd Clockwise()
{
const auto& prev = cdt.triangles[current];
current = prev.neighbors[around];
const auto& next = cdt.triangles[current];
VertInd v = prev.vertices[around];
if (next.vertices[0] == v)
around = 0;
else
if (next.vertices[1] == v)
around = 1;
else
around = 2;
return current;
}
};
// bit-mask of a real poly index (without marker)
const PolyInd mask = (~(PolyInd)0) >> 1;
for (PolyInd p = 0; p < polys.size(); p++)
{
// single triangle polys are ok already
if (polys[p].size() == 1)
continue;
// q = unmarked poly index p
const PolyInd q = p | ~mask;
// find good starting triangle,
// one with exeactly 1 inner edge
TriInd first = noNeighbor;
for (const auto t : polys[p])
{
if (first == noNeighbor)
{
const auto& tri = cdt.triangles[t];
int inner_edges =
(tri.neighbors[0] != noNeighbor && (map[tri.neighbors[0]] & mask) == p) +
(tri.neighbors[1] != noNeighbor && (map[tri.neighbors[1]] & mask) == p) +
(tri.neighbors[2] != noNeighbor && (map[tri.neighbors[2]] & mask) == p);
if (inner_edges == 1)
first = t;
}
// unmark all tris (not inserted to final poly)
map[t] = q;
}
// we can clear current poly now,
// as we depend only on map and adjacency
polys[p].clear();
TriInd f = first; // current face
bool step_on = false; // true if current vertex is inserted
int insert = 2; // 2 for first triangle, all other 0
Stepper it(cdt, f,
cdt.triangles[f].neighbors[0] != noNeighbor && map[cdt.triangles[f].neighbors[0]] == q ? 0 :
cdt.triangles[f].neighbors[1] != noNeighbor && map[cdt.triangles[f].neighbors[1]] == q ? 1 : 2);
while (1)
{
if (!step_on && map[f] == q)
{
step_on = true;
map[f] = p; // mark as inserted
if (it.around != insert)
{
// need to rotate
auto& tri = cdt.triangles[f];
static const int rot[3][3] = { {0,1,2},{2,0,1},{1,2,0} };
const int r = rot[it.around][insert];
const auto v = tri.vertices[r];
const auto n = tri.neighbors[r];
switch (r)
{
case 1:
tri.vertices[1] = tri.vertices[0];
tri.vertices[0] = tri.vertices[2];
tri.vertices[2] = v;
tri.neighbors[1] = tri.neighbors[0];
tri.neighbors[0] = tri.neighbors[2];
tri.neighbors[2] = n;
break;
case 2:
tri.vertices[2] = tri.vertices[0];
tri.vertices[0] = tri.vertices[1];
tri.vertices[1] = v;
tri.neighbors[2] = tri.neighbors[0];
tri.neighbors[0] = tri.neighbors[1];
tri.neighbors[1] = n;
break;
default:
break;
}
// adjust iterator after rotation
it.StepOver(insert);
}
polys[p].push_back(f);
// everything but first should use 0
insert = 0;
}
TriInd probe = cdt.triangles[f].neighbors[it.around];
if (probe == noNeighbor || (map[probe] & mask) != p)
{
// we're on the last tri inside poly (marked or unmarked)
assert(step_on);
// step on the other leg (ccw in current tri):
static const int other_leg[3] = { 1,2,0 };
it.StepOver(other_leg[it.around]);
step_on = false;
continue;
}
f = it.Clockwise();
if (f == first)
break;
}
}
return polys;
} |
Beta Was this translation helpful? Give feedback.
-
|
Hi @artem-ogre |
Beta Was this translation helpful? Give feedback.


Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Is this possible, without re-inventing the wheel, to detect and extract info on degenerated triangulations?
Simply grouping triangles into 'polygons' would be sufficient in my case, although extracting N-gon mesh (with adjacencies, etc) is the nicest way to go.
Beta Was this translation helpful? Give feedback.
All reactions