Hello,
So we came to the conclusion that, holes are not supported by BuildNgonFromPolys
About BuildNgon
the thing i missed is that the Inner edge index must be set twice. For the two polygons, the edge is part of. where
edgeIndex = 4 * polygonIndex + cpolygonSideIndex
Below is the code for a command that will remove all edge on a mesh (of course try it on a plane for example)
It's working with holes of course
static maxon::Result<void> PC23992_cmd(BaseDocument* doc)
{
iferr_scope;
CheckArgument(doc != nullptr);
BaseObject* op = doc->GetFirstObject();
if (op == nullptr)
{
return maxon::NullptrError(MAXON_SOURCE_LOCATION);
}
PolygonObject* polyOp = ToPoly(op);
polyOp->GetAndBuildNgon();
NgonBase* pNgons = polyOp->GetNgonBase();
if (pNgons == nullptr)
return maxon::NullptrError(MAXON_SOURCE_LOCATION);
const CPolygon* polys = polyOp->GetPolygonR();
const Vector* points = polyOp->GetPointR();
Int32 polyCount = polyOp->GetPolygonCount();
maxon::BaseArray<Int32> innerEdges;
using UndirectedEdge = maxon::Pair<Int32, Int32>; // first index in the pair must always be the smaller in between the 2 indices
maxon::HashMap<UndirectedEdge, Int32> undirectedEdges;
// in this case traverse all the polygons
for (Int32 polygonIndex = 0; polygonIndex < polyCount; ++polygonIndex)
{
for (Int32 side = 0; side < 4; ++side) // we collect edges which are used more the once (only inner edges)
{
Int32 pA = NOTOK;
Int32 pB = NOTOK;
polys[polygonIndex].EdgePoints(side, pA, pB); // get edge points
if (polys[polygonIndex].IsTriangle() && side == 2) // skip the invalid edge of triangles
continue;
Int32 edgeIndex = polygonIndex * 4 + side; // build the unique edge index
Bool newInsert = false;
// we check if the point pair is already stored in the hash map, if it is then it means the edge is not on the boundary of the mesh or an hole edge
Int32& entry = undirectedEdges.InsertKey(UndirectedEdge(Min(pA, pB), Max(pA, pB)), newInsert) iferr_return;
if (newInsert)
{
entry = edgeIndex;
}
else
{
innerEdges.Append(edgeIndex) iferr_return;
innerEdges.Append(entry) iferr_return;
}
}
}
if (innerEdges.IsEmpty())
return maxon::OK;
// we pass inner edges to BuildNgon
pNgons->BuildNgon(innerEdges.GetFirst(), nullptr, (Int32)innerEdges.GetCount(), 0, polys, points);
pNgons->InitMap();
pNgons->SetFlags(NGON_FLAG_SETASVALID);
polyOp->Message(MSG_UPDATE);
EventAdd();
return maxon::OK;
}
I've created a code that will create two mesh, one using BuildNgon and the other one BuildNgonFromPolys
static maxon::Result<void> PC12992(BaseDocument* doc)
{
iferr_scope;
const Int32 pcnt = 12;
const Int32 polyCnt = 14;
PolygonObject* obj1 = PolygonObject::Alloc(pcnt, polyCnt);
maxon::BaseArray<Vector> parray;
parray.EnsureCapacity(pcnt) iferr_return;
parray.Append(Vector(-200, 0, -200)) iferr_return;
parray.Append(Vector(200, 0, -200)) iferr_return;
parray.Append(Vector(-200, 0, 200)) iferr_return;
parray.Append(Vector(200, 0, 200)) iferr_return;
parray.Append(Vector(-64.498, 0, -31.85)) iferr_return;
parray.Append(Vector(0.287, 0, -138.37)) iferr_return;
parray.Append(Vector(46.688, 0, 91.877)) iferr_return;
parray.Append(Vector(57.903, 0, -29.617)) iferr_return;
parray.Append(Vector(9.65, 0, 84.86)) iferr_return;
parray.Append(Vector(-16.551, 0, -30.975)) iferr_return;
parray.Append(Vector(-48.354, 0, -137.194)) iferr_return;
parray.Append(Vector(4.068, 0, -11.035)) iferr_return;
Vector* padr = obj1->GetPointW();
CPolygon* vadr = obj1->GetPolygonW();
if (vadr == nullptr || padr == nullptr)
return maxon::NullptrError(MAXON_SOURCE_LOCATION);
if (parray.GetCount() != pcnt)
return maxon::UnknownError(MAXON_SOURCE_LOCATION);
// Sets points position
for (Int32 i = 0; i < pcnt; i++)
{
padr[i] = parray[i];
}
// Defines the polygons
CPolygon poly;
poly.a = 2; poly.b = 4; poly.c = 0; poly.d = poly.c;
vadr[0] = poly;
poly.a = 2; poly.b = 6; poly.c = 8; poly.d = poly.c;
vadr[1] = poly;
poly.a = 7; poly.b = 3; poly.c = 1; poly.d = poly.c;
vadr[2] = poly;
poly.a = 0; poly.b = 5; poly.c = 1; poly.d = poly.c;
vadr[3] = poly;
poly.a = 8; poly.b = 9; poly.c = 4; poly.d = poly.c;
vadr[4] = poly;
poly.a = 0; poly.b = 4; poly.c = 10; poly.d = poly.c;
vadr[5] = poly;
poly.a = 9; poly.b = 1; poly.c = 5; poly.d = poly.c;
vadr[6] = poly;
poly.a = 10; poly.b = 5; poly.c = 0; poly.d = poly.c;
vadr[7] = poly;
poly.a = 9; poly.b = 7; poly.c = 1; poly.d = poly.c;
vadr[8] = poly;
poly.a = 3; poly.b = 7; poly.c = 6; poly.d = poly.c;
vadr[9] = poly;
poly.a = 6; poly.b = 2; poly.c = 3; poly.d = poly.c;
vadr[10] = poly;
poly.a = 4; poly.b = 2; poly.c = 8; poly.d = poly.c;
vadr[11] = poly;
poly.a = 8; poly.b = 11; poly.c = 9; poly.d = poly.c;
vadr[12] = poly;
poly.a = 7; poly.b = 9; poly.c = 11; poly.d = poly.c;
vadr[13] = poly;
// Creates the ngons for object 1
maxon::BaseArray<Int32> inner;
// edge between poly 0 and 11
inner.Append(0) iferr_return; // edge index in poly 0
inner.Append(44) iferr_return; // edge index inpoly 11
// edge between poly 11 and 1
inner.Append(7) iferr_return; // edge index in poly 1
inner.Append(45) iferr_return; // edge index in poly 11
NgonBase* pNgonsObj1;
obj1->GetAndBuildNgon(); // ensure ngonbase is ready
pNgonsObj1 = obj1->GetNgonBase();
if (pNgonsObj1)
{
Int32 ngonIndex = pNgonsObj1->BuildNgon(inner.GetFirst(), nullptr, inner.GetCount(), 0, obj1->GetPolygonR(), obj1->GetPointR());
//Int32 ngonIndex = pNgonsObj1->BuildNgon(inner.GetFirst(), nullptr, inner.GetCount(), 0, obj1->GetPolygonR(), obj1->GetPointR());
if (ngonIndex == -1)
DebugStop();
}
pNgonsObj1->InitMap(); // rebuild the internal n-gon table data
pNgonsObj1->SetFlags(NGON_FLAG_NOVALIDATION);
//-------------------- obj 2 ---------------------------------------------------------
/*
* vertices created
2 ------ 3
| |
| 4
| |
0 ----- 1
*/
const Int32 pcnt2 = 5;
const Int32 polyCnt2 = 2;
PolygonObject* obj2 = PolygonObject::Alloc(pcnt2, polyCnt2);
maxon::BaseArray<Vector> parray2;
parray2.EnsureCapacity(pcnt2) iferr_return;
parray2.Append(Vector(-200, 0, -200)) iferr_return;
parray2.Append(Vector(200, 0, -200)) iferr_return;
parray2.Append(Vector(-200, 0, 200)) iferr_return;
parray2.Append(Vector(200, 0, 200)) iferr_return;
parray2.Append(Vector(250, 0, 140)) iferr_return;
padr = obj2->GetPointW();
vadr = obj2->GetPolygonW();
if (vadr == nullptr || padr == nullptr)
return maxon::NullptrError(MAXON_SOURCE_LOCATION);
if (parray2.GetCount() != pcnt2)
return maxon::UnknownError(MAXON_SOURCE_LOCATION);
// Sets points position
for (Int32 i = 0; i < pcnt2; i++)
{
padr[i] = parray2[i];
}
poly.a = 0; poly.b = 4; poly.c = 1; poly.d = poly.c;
vadr[0] = poly;
poly.a = 0; poly.b = 2; poly.c = 3; poly.d = 4;
vadr[1] = poly;
// Creates ngons for object 2
NgonBase* pNgonsObj2;
obj2->GetAndBuildNgon(); // ensure ngonbase is ready
pNgonsObj2 = obj2->GetNgonBase();
maxon::BaseArray<Int32> polyIdx;
maxon::BaseArray<Int32> verticesIdx;
polyIdx.EnsureCapacity(polyCnt2) iferr_return;
verticesIdx.EnsureCapacity(5) iferr_return;
polyIdx.Append(0) iferr_return;
polyIdx.Append(1) iferr_return;
// Must respect the same order as the polygons (clock or counter clock)
verticesIdx.Append(0) iferr_return;
verticesIdx.Append(2) iferr_return;
verticesIdx.Append(3) iferr_return;
verticesIdx.Append(4) iferr_return;
verticesIdx.Append(1) iferr_return;
if (pNgonsObj2)
{
Int32 ngonIndex2 = pNgonsObj2->BuildNgonFromPolys(polyIdx.GetFirst(), verticesIdx.GetFirst(), polyIdx.GetCount(), verticesIdx.GetCount(), obj2->GetPolygonR(), obj2->GetPointR());
if (ngonIndex2 == -1)
DebugStop();
}
pNgonsObj2->InitMap(); // rebuild the internal n-gon table data
pNgonsObj2->SetFlags(NGON_FLAG_NOVALIDATION);
// Inserts object inside the document
doc->InsertObject(obj1, nullptr, nullptr);
doc->InsertObject(obj2, nullptr, nullptr);
obj2->SetRelPos(Vector(0, 250, 0));
obj1->Message(MSG_UPDATE);
obj2->Message(MSG_UPDATE);
EventAdd();
return maxon::OK;
}
Cheers,
Manuel