View Full Version : Edges Connection Graph

devdept

05-04-2010, 05:08 AM

Hi All,

Does an efficient implementation to extract edges from a mesh of triangles without duplicates?

I mean:

1) Vertices are a list of 3D points

2) Triangles are a list of 3 indices pointing to vertices above

We want to find very quickly:

1) A list of 2 indices representing the triangle sides but *without* duplicates (of course, you always get two with opposite direction)

Thanks,

Alberto

Ilian Dinev

05-04-2010, 05:58 AM

struct LLNodeEdge{

LLNodeEdge* pNext;

int otherVtx; // index of other vertex

};

int NumTris = ; // arg

int NumVerts= ; // arg

int* TriIndices = ; // arg

LLNodeEdge** edges = new LLNodeEdge*[NumVerts];

int outNumEdges=0;

memset(edges,0,NumVerts*4);

LLNodeEdge* scratch_original = new LLNodeEdge[NumTris*3];

LLNodeEdge* scratch = scratch_original;

int* pidx = TriIndices;

int pcount = NumTris;

do{

for(int i=0;i<3;i++){ // unroll manually

int idx1 = pidx[i];

int idx2 = pidx[(i+1)%3]; // fix in manual unroll

if(idx1>idx2){ SWAP(idx1,idx2); } // cmovgt

LLNodeEdge* n = edges[idx1];

while(n){

if(n->otherVtx==idx2)break;

n = n->pNext;

}

if(!n){

n = scratch; scratch++;

n->otherVtx = idx2;

n->pNext = edges[idx1];

edges[idx1]=n;

outNumEdges++;

}

}

pidx+=3;

}while(--pcount); // dec + jnz

int* outEdges = new int[outNumEdges *2];

// now cycle through linked-lists, to fill-in data. Then delete "scratch_original" and "edges"

devdept

05-04-2010, 06:34 AM

Thanks Ilian,

We'll give this a try, has this approach a specific name or it is your own ?

Alberto

Ilian Dinev

05-04-2010, 07:20 AM

It's fairly simple and natural; the key point is to search by tuples of {idx1,idx2} where idx1<idx2. I've also seen this idea elsewhere, but it was wrapped in STL hell. I just embedded this keypoint around a bunch of optimizations:

- pre-allocate a scratch array. Homework: Actually only one "new char[xyz]" chunk is necessary, instead of two. (wrote them as two for clarity). Do pointer-maths.

- don't store idx1 (in the linked-list). Homework: after "do{" add idx3, make idx1<idx2<idx3 ; can get nicely optimized.

Another natural approach is to use "int NumUsersOfVertex[NumVerts]; int* edges[NumVerts]; " to replace the linked-lists by arrays, for nice memory prefetch pipelining.

devdept

06-01-2010, 09:24 AM

Hi Ilian,

You're algorithm is very fast, thanks.

Do you have something to share also to convert Mesh of triangles defined as three 3D points to vertices and indices?

I mean from this format:

Triangle 1:

p1 = 4.22, 23.54, 32.444

p2 = 4.22, 66.54, 32.444

p3 = 4.22, 23.54, 77.444

Triangle 2:

p1 = 4.22, 11.54, 44.444

p2 = 6.22, 6.54, 32.666

p3 = 7.22, 23.54, 77.444

...

To this format:

Vertices:

v1 = 4.22, 23.54, 32.444

v2 = 4.22, 66.54, 32.444

v3 = 4.22, 23.54, 77.444

v4 = 4.22, 11.54, 44.444

...

Triangles:

t1 = 0,1,2

t2 = 0,1,3

...

Now we are doing this without optimizations and it is very slow.

Thanks,

Alberto

Ilian Dinev

06-01-2010, 01:25 PM

I'd suggest a 16-bit hashmap;

struct LLNodeVtx{

LLNodeVtx* pNext;

union{

vec3 position;

int ipos[3];

}

int DifferentFrom(const LLNodeVtx& v2); // optimize with XOR and OR of ipos[]

int CalculateHash(); // XOR and SHR of ipos[]

}; // 16 bytes

Reuse the ideas of

LLNodeEdge* scratch_original = new LLNodeEdge[NumTris*3];

LLNodeEdge* scratch = scratch_original;

for the fast allocation of nodes.

kd-trees might be helpful, too. I've only met this in offline preprocessing code, so I only use a simple HashMap.

devdept

06-02-2010, 07:43 AM

Thanks Ilian,

Althought your code snippet looks to much concise to me, I will study hashmaps before asking.

Alberto

devdept

06-02-2010, 10:32 AM

Ilian,

What do you mean we SHR in the following?

int CalculateHash(); // XOR and SHR of ipos[]

Thanks,

Alberto

Ilian Dinev

06-02-2010, 11:48 AM

shift-right, >> in C++

Basically I've been mentioning x86 asm opcodes as hints to the optimization.

devdept

06-07-2010, 07:08 AM

Ilian,

Do you use hash codes to quickly compare XYZ values? What does int iPos[3] holds?

We can't use your code without some more help, sorry.

Thanks.

Alberto

Ilian Dinev

06-07-2010, 01:50 PM

// NUM_VERTICES = NUM_TRIANGLES * 3

vec3 Vertices[NUM_VERTICES]; // input

int Indices[NUM_TRIANGLES*3]; // output . For triangles

int NumUniqueVertices=0; // output

vec3* outVertices; // output

//----------------------------------------------

struct LLNodeVtx{

LLNodeVtx* pNext;

int index;

union{

vec3 position;

int ipos[3];

}

};

LLNodeVtx* HashMap[65536]={0};

for(int vertexIdx=0;vertexIdx<NUM_VERTICES;vertexIdx++){

LLNodeVtx n;

n.position = Vertices[vertexIdx];

//-------[ calculate hash ]----------------------[

int hash16 = (n.ipos[0] ^ n.ipos[1] ^ n.ipos[1]);

hash16 = hash16 ^ (hash16>>16);

hash16 &= 65535;

//------------------------------------------------/

//-----[ find if already existing ]-------------[

LLNodeVtx* list = HashMap[hash16];

while(list){

if(list->ipos[0]==n.ipos[0] && list->ipos[1]==n.ipos[1] && list->ipos[2]==n.ipos[2]){

break;

}

list=list->pNext;

}

//----------------------------------------------/

if(list){ // found

Indices[vertexIdx] = list->index;

}else{

n.index = NumUniqueVertices;

n.pNext = HashMap[hash16];

list = new LLNodeVtx; // allocate LL node

*list = n; // copy from cache

HashMap[hash16] = list;

outVertices[NumUniqueVertices] = n.position;

NumUniqueVertices++;

}

}

devdept

06-09-2010, 12:09 AM

Hi Ilian,

Thanks so much for your patience. Can you tell me what iPos contain here:

//-------[ calculate hash ]----------------------[

int hash16 = (n.ipos[0] ^ n.ipos[1] ^ n.ipos[1]);

hash16 = hash16 ^ (hash16>>16);

hash16 &= 65535;

//------------------------------------------------/

Initially ipos[0], ipos[1], ipos[2] are all zero.

Thanks,

Alberto

Ilian Dinev

06-09-2010, 12:26 AM

http://msdn.microsoft.com/en-us/library/5dxy4b7b%28VS.80%29.aspx

During the "n.position = Vertices[vertexIdx]; " operation, the ipos[] get filled-in.

Also, I just noticed there's a typo in

"int hash16 = (n.ipos[0] ^ n.ipos[1] ^ n.ipos[1]);"

Has to be

"int hash16 = (n.ipos[0] ^ n.ipos[1] ^ n.ipos[2]);"

devdept

06-09-2010, 12:52 AM

Vertices[vertexIdx] is a vec3 (3 floats), right?

How can you fill a 3 floats and 3 integers from 3 floats only?

union {

vec3 position;

int ipos[3];

}

In addition what it the name of this union?

Thanks again,

Alberto

Powered by vBulletin® Version 4.2.2 Copyright © 2014 vBulletin Solutions, Inc. All rights reserved.