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.
-
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