Add your own alternative version
Stats
173.4K views 1.4K downloads 21 bookmarked
Posted
6 Feb 2002

Comments and Discussions



hello viewres please give your suggestions. im having a dfx object and i want to cut the object in slicing means im having 10/10 mm squere object. i want it to cut it in 10 parts so each part is containing 10 mm width and 1 mm height. and i also need it's vertex values in opengl. so please send me the suggestions. any suggestion most welcome
hi





I found this routine sometimes produces incorrect tesselation. When certain points in the polygon winding are colinear, it can skip over them and produce triangles outside of the original polygon.
My fix simply classifies points on the edge of the test triangle as 'inside' instead of 'outside'. This appears to be a stable and beneficial fix so far.
Example Input:
poly normal (0.000f,0.500f,0.866f)
poly points
(0.700f,6.500f,4.071f)
(0.700f,5.500f,3.494f)
(1.700f,5.500f,3.494f)
(1.700f,6.500f,4.071f)
(2.500f,6.500f,4.071f)
(7.300f,1.700f,1.300f)
(11.300f,1.700f,1.300f)
(7.500f,5.500f,3.494f)
(4.300f,5.500f,3.494f)
(4.300f,6.500f,4.071f)
Old Code in function IsPointInside():
pmq2.Vector(m_e1,ntmp); if( (B0=m_N.Dot(ntmp)) <= 0.0 ) return false;
m_e0.Vector(pmq2,ntmp); if( (B1=m_N.Dot(ntmp)) <= 0.0 ) return false;
return ( (m_AB0B1) > 0.0 ? true : false );
New Code:
pmq2.Vector(m_e1,ntmp); if( (B0=m_N.Dot(ntmp)) < 0.0 ) return false;
m_e0.Vector(pmq2,ntmp); if( (B1=m_N.Dot(ntmp)) < 0.0 ) return false;
return ( (m_AB0B1) < 0.0 ? false : true);
Helpful explaination of internal variables:
Edit....
Further testing shows that neither the old or new code correctly and consistently handles coincident and colinear points. (Eg. An example of a coincident point, is a Figure '8' polygons that does not actually cross over, just converges in the middle.)
Example Input:
poly normal (0.000f,0.500f,0.866f)
poly points
(1.700f,6.300f,2.801f)
(4.300f,3.700f,1.300f)
(5.700f,3.700f,1.300f)
(7.000f,5.000f,2.051f)
(8.300f,3.700f,1.300f)
(9.300f,3.700f,1.300f)
(8.000f,5.000f,2.051f)
(7.000f,5.000f,2.051f)
(1.700f,10.300f,5.111f)
This should help more with coincident points: Old code in IsAnyPointInside():
if( ( ip < i  ip > k ) &&
IsPointInside(points[m_nIndex[ip]],points[ik]) )
{
return true;
}
New code:
if( ip < i  ip > k )
{
if( points[m_nIndex[ip]].Equal(points[m_nIndex[i]])
 points[m_nIndex[ip]].Equal(points[m_nIndex[j]])
 points[m_nIndex[ip]].Equal(points[m_nIndex[k]])
)
{
continue;
}
if( IsPointInside(points[m_nIndex[ip]],points[ik]) )
{
return true;
}
}
If topus's suggested change is valid, it should read
if( ((FLT_EPSILON) < m_A && m_A < FLT_EPSILON) 
((FLT_EPSILON) < m_N[0] && m_N[0] < FLT_EPSILON &&
(FLT_EPSILON) < m_N[1] && m_N[1] < FLT_EPSILON &&
(FLT_EPSILON) < m_N[2] && m_N[2] < FLT_EPSILON ))
return degenerate;
Also note that you can help the algorithm by removing 'junk' before processing. Eg. project 3D points onto plane (of which normal is used). Remove degeneracies like coincident and colinear points. Snapping and merging points may help, but could lead to badsnaps that cause self intersections.
Edit: I have found another case which I believe shows a flaw in the algorithm. As 'ears' are clipped off the polygon, the remaining polygon can become self intersecting and fail 'point in poly' test, to produce triangles outside the original shape.
Example input:
poly normal(0,0,1)
(10.52881622f,1.25890017f,0.00000000f)
(10.52881241f,0.24110639f,0.00000000f)
(1.47119045f,0.24110317f,0.00000000f)
(1.47119141f,1.25889719f,0.00000000f)
(4.52881575f,1.25890088f,0.00000000f)
(4.52881479f,3.25889254f,0.00000000f)
(6.08583260f,3.25889111f,0.00000000f)
(6.08583069f,1.25889945f,0.00000000f)
The fix: in function Triangulate() in 'case convex :' in else, after 'RemoveVertex'
i = j;
j = k;
k++;
This allows the point AFTER the removed triangle point to be the start of the next test triangle. This helps with near colinear points that fan out from an otherwise stationary start point.
Edit: There are still issues with the code. The bottom line is that the original algorithm does not handle simple noncovex polys with colinear, but non intersecting segments. The overall algorithm does not handle polygons that intersect in anyway, including at single points, though it often produces a correct or near correct result.
Please comment on this.





In my crossplatform c++ framework ( www.amanith.org ) i've implemented a fast sweepline tesselator that can handle non simple polygons with holes , and some common degenerations. For every questions abuot this, email me at: mfabbri@amanith.org





You had implemented it? My god! Your code is too similiar to SGI/libtess. Such functions as "sweepevent", "TessellateMonotoneRegion" ..., are almost the same to SGI/libtess. I suggest you add " Thanks to SGI/libtess " in the header.
Hey, kavenger, you should not always call "AddContourPoint", If you had research the struct of Mesh carefully,you can add all your vertex once together. This can make you function 100% faster.
============================ Gods know that I really love you from the bottom of my heart,but I forget to tell you that...





Hey Liu, I have read all libtess sources/docs, and got inspired during the writing of my tessellator, as weel as for another good paper, that explain the sweepline algorithm in details ( http://www.cs.ucsb.edu/~suri/cs235/Triangulation.pdf ).So, yes, i'll follow your suggestion adding the greetings to SGI. My decision to rewite a tesselator instead of using the libtess ones is due to the fact that i had a try to be more robust and support more degeneration cases, without to introduce overheads of any kind. Anyway, now, i'm oriented in a direction to use OpenGL drawing tecniques that don't need of the tesselation step, beacuse this step is too expensive, and it needs a too high robustness level. Just for curiosity, Are you using Amanith? Do u use the tessellation for drawing purposes or for something other? ( my mail is: mfabbri ]at[ amanith ]dot[ org )





Change the line:
for( register int i=0 , j=1 ; j < nPoints ; i++ , j++ ){ to:
for( register int i=0 , j=1 ; i < nPoints ; i++ , j++, j=j%nPoints ){
and normal of the polygon will be calculated correctly.
Torsten





It could be better for performance issue to exclude the case of last j from the for loop, in order not to compute the modulo each time.
I would do : normal[0]=normal[1]=normal[2]=0.0f; for( register int i=0 , j=1 ; j < nPoints ; i++ , j++ ){ normal[0]+= ( points[i][1]  points[j][1] ) * ( points[i][2] + points[j][2] ) ; normal[1]+= ( points[i][2]  points[j][2] ) * ( points[i][0] + points[j][0] ) ; normal[2]+= ( points[i][0]  points[j][0] ) * ( points[i][1] + points[j][1] ) ; }
// last case : normal[0]+= ( points[i][1]  points[0][1] ) * ( points[i][2] + points[0][2] ) ; normal[1]+= ( points[i][2]  points[0][2] ) * ( points[i][0] + points[0][0] ) ; normal[2]+= ( points[i][0]  points[0][0] ) * ( points[i][1] + points[0][1] ) ; 
It would also be a good idea to delete Vector3F array in CPolyTryView::OnDraw(CDC* pDC) after call to triangulate() to avoid memory leaks !





Area computation is bugged :
you should add in CPolyTriView::OnDraw()
existing : // for( int i=0 ; i < m_nPoints ; i++ ){ points[i][0] = m_points[i].x; points[i][1] = m_points[i].y; if( i ) Area+= ( m_points[i].x * m_points[i1].y  m_points[i1].x * m_points[i].y) * 0.5f; } // // added after for loop : Area += ( m_points[0].x * m_points[i1].y  m_points[i1].x * m_points[0].y) * 0.5f;
Also, if area computation is only used for normal deduction, you can avoid *0.5f as it will not change area sign.





Thanks for the code.
Martin





Thank you very much for this example! It's the simple and best tesselation algorithm I found over the internet!
I found a special case that popup an index range error (very hard to find!!! ) in the Triangulate function.
The "k" index missed 2 hits because it starts at k=2... So I did a little patch!
New loop: for( int i=0 , j=1 , k=2 ; k < nVertex+3 ; ) New indexes: int ib = i % nVertex;
int jb = j % nVertex;
int kb = k % nVertex;
Here is the modified function:
int nTriangle= 0;
int nVertex = nCount;
AllocIndex(nCount);
bool bNoErrors = true;
while( nVertex > 3 && bNoErrors )
{
bNoErrors = false;
for( int i=0 , j=1 , k=2 ; k < nVertex+3 ; )
{
if( nVertex == 0 )
break;
int ib = i % nVertex;
int jb = j % nVertex;
int kb = k % nVertex;
switch( TriangleArea(points,
m_nIndex[ib],
m_nIndex[jb],
m_nIndex[kb],
normal) )
{
case convex :
if( IsAnyPointInside(points,ib,jb,kb,nVertex) ){
i = j;
j = k;
k++;
}
else
{
nTriangle++;
AddFace(points,m_nIndex[ib],m_nIndex[jb],m_nIndex[kb]);
nVertex = RemoveVertex(jb, nVertex);
bNoErrors= true;
}
break;
case concave :
i = j;
j = k;
k++;
break;
case degenerate :
nVertex = RemoveVertex(jb, nVertex);
bNoErrors= true;
break;
}
}
}
return nTriangle;
TruePyroman





Another litle improvement: Use previus code and change the line while( nVertex > 3 && bNoErrors ) with the line while( nVertex >= 3 && bNoErrors ) Also to solve the problem with degenerate points (alligned or suballigned) replace the test in function Triangle Area (that work fine for planar 2D polygon's) // // j is alligned from i to k ? // if( (FLT_EPSILON) < m_A && m_A < FLT_EPSILON ) return degenerate; with: // // j is alligned from i to k ? // if( (FLT_EPSILON) < m_A && m_A < FLT_EPSILON && (FLT_EPSILON) < m_N[0] && m_N[0] < FLT_EPSILON && (FLT_EPSILON) < m_N[1] && m_N[1] < FLT_EPSILON && (FLT_EPSILON) < m_N[2] && m_N[2] < FLT_EPSILON ) return degenerate; Last (but not least) if some consecutive triangles as the same origin vertex you can optimizing opengl drawing code collecting the common side (from two consecutive triangles) and using triangle fan (example triangle vertex 0,1,2 && 0,2,3 etc.. can be collected in a triangle fan 0,1,2,3 etc..) Thanks very much for this very speedy code





Hi ,
Ok Delauney rules in good tesselation. But in the case of nonconvex poly you have to use the constrained form of the algorithm (DCT). You can achieve good tesselation without get rid of your algorithm : as a post  process phase you can "mimimize" the edge size of convex quads. It's like use the turn edge tools in 3ds max. In this way, long triangles are converted in more equilaterals ones. If i got time i'll try and send it to you.





A more little explanation about my article. In order to tesselate the polygon i use this tecnique: First compute the normal of polygon (i use the newell method see Graphic Gems..) For each sequence of three vertex ( i, j, k ) in the polygon compute the vector area (alias normal of triangle). If the normal go in the opposite direction of polygon normal the triangle is 'concave' and go ahead. If the area il 0.0 the point j is alligned from i to k and eliminated from the list of vertex. If the normal of triangle is in the same direction of polygon normal the triangle is convex. In the last case check if any other point is inside the triangle (the IsPointInside function). This function test if the point is on solid angle ik ^ jk. if this is true compute distance of intersection k>point to line ij and test distance. If all is good emit triangle, remove vertex j from list and go to the next triplet.... The reason for wich i posted this article is that i don't find this tecnique in any book or article and ave a doubt about the mathematical basic of my algoritm In other words is true that it work in any case ? (my experience ask yes but is very far from a theorem...) The Delauney algortim work fine but is 'computational' more expensive than my algortim (using my Delauney implementation) for this reason i try this way. At the end my apologize for my poor english but my sincerly idea is to contribute to codeproject and suggest a way to resolv a problem that i found. Thanks pepito.





(excuse me for my poor english too ) )
I didn't want you to use a delaunay algorithm. My message intention was to show another way than Delaunay to improve you algorithm. The one i describe is only an idea to turn edges to have better result. And i don't take it from any book too and i don't think it's computationnal intensive. I think this idea can be plug as a post process of you algorithm. I respect you intention to contribute. And my idea is to contribute to the improvment of your. This was my only intention. Thanks
Jeckle





This is a good start towards providing more information in your article. If you can provide a bit more detail then you should consider updating it.





I would suggest using a delauney triangulation  it will cut down the number of thin strips, and produce a much better tesselation.
Here's a link..
or do a search on google.





It appeared as though the Delauney method only worked for polygons that were contained within the convex hull of the set of polygons. It appears as the method shown here works on concave polygons as well.





A more little explanation about my article. In order to tesselate the polygon i use this tecnique: First compute the normal of polygon (i use the newell method see Graphic Gems..) For each sequence of three vertex ( i, j, k ) in the polygon compute the vector area (alias normal of triangle). If the normal go in the opposite direction of polygon normal the triangle is 'concave' and go ahead. If the area il 0.0 the point j is alligned from i to k and eliminated from the list of vertex. If the normal of triangle is in the same direction of polygon normal the triangle is convex. In the last case check if any other point is inside the triangle (the IsPointInside function). This function test if the point is on solid angle ik ^ jk. if this is true compute distance of intersection k>point to line ij and test distance. If all is good emit triangle, remove vertex j from list and go to the next triplet.... The reason for wich i posted this article is that i don't find this tecnique in any book or article and ave a doubt about the mathematical basic of my algoritm In other words is true that it work in any case ? (my experience ask yes but is very far from a theorem...) The Delauney algortim work fine but is 'computational' more expensive than my algortim (using my Delauney implementation) for this reason i try this way. At the end my apologize fro my poor english but my sincerly idea is to contribute to codeproject and suggest a way to resolv a problem that i found. Thanks pepito.





Pepito Sbazzeguti... "Gratta il Pepito, viene fuori il Peppone!" Certo che avresti potuto essere più originale con lo pseudonimo. Samantha Fox





Peppone for President!
Don Camillo





thank you guys ! I am only a senator but in the future, with some TV network...D





Ah, spiritoso, eh? Forza Berlusca, non ti curar di lor ma guarda e passa! Samantha Fox





I have a suggestion for you: Write up that article properly!
That is, why don't you put some explanation of the problem itself, the solution utilized by your code, the potential use of the code and some code examples of how to use it in another application etc. ?





Sorry, and my apologize, but my english is very poor.!!!! This is a basic class to use in alternative to tools like gluTesselate. The glu function is much flexible but in the (frequent) case in wich you ave a simple polygon this class let you to take a more control. For instance: dont insert new points in the polygon (and if you attach vertex property like color or vertex texture coordinate dont request any interpolation of this parameters) dont use expensive time functions like square root etc. is fast like gluTesselate (try it) work in 3D
Pepito





Perhaps because his English isn't too hot? Who made you the article Gestapo around here?





Anonymous wrote: Perhaps because his English isn't too hot? Who made you the article Gestapo around here?
You must understand that it takes more than just good code to make a good article. An explanation of how and why is essential.
Even if English isn't your first language, there's no reason an author shouldn't write it first in his or her own native language and then ask for assistance (via the Collaboration/Testing forum or even the Lounge) in translating it into English before posting.
Of course, these days you can also do some limited translation via the web, which may be enough.
Remember that there's no need to worry about English in an article being perfect  CPians are pretty understanding of language barriers.
Andy Metcalfe  Sonardyne International Ltd
Trouble with resource IDs? Try the Resource ID Organiser AddIn for Visual C++
"I would be careful in separating your wierdness, a good quirky weirdness, from the disturbed wierdness of people who take pleasure from PVC sheep with fruit repositories."  Paul Watson





What is wrong with you people? The guy has put together an interesting piece of code that people like me and possibly many others appreciate. Whilst I agree it is possible to get far more out of an article when it is properly written up, if someone submitting an article doesn't want to, or feels it would take excessive time to translate into a language that is not their own, then it is up to them. I wish people would stop being so critical of other people's efforts. If you don't like the article don't read it. If you have a criticism to make then at least be constructive. If you are that bothered Andy then why not offer to translate an article yourself. And as for George...
People contibuting code should be encouraged. It takes 5 minutes to write a criticism and boost your ego, it takes a lot more effort to write a decent peice of code.
Gary McHale





Andy, don't waste your time talking to the anonymous cowards. Just ignore them.
Andy Metcalfe wrote: Of course, these days you can also do some limited translation via the web, which may be enough.
I think the translation engines were chocking on that part: "____ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ____ "






Nish [BusterBoy] wrote: LOL
What's that?
Mazy
Don't Marry a Person You Can Live With... Marry Someone You Can Not Live Without






Does putting my name on a post make me an anonymous coward? Get a life George.
Gary McHale






Or is it a code "AdLib"? (the childrens fill in the blank language game, not the old sound card company) ____ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ________ ____ ____





Articles have to have a minimum num of words. He is probably using the dashes as padding.
Nish
Sonork ID 100.9786 voidmain www.busterboy.org If you don't find me on CP, I'll be at Bob's HungOut





Why would you do something like this? What practical application does this have?





Ever programmed in 3d?
Tesselating (or triangulating) polys to triangles is a very good thing for graphics cards to optimise. Makes things go zip...





A 3D graphics pipeline often is optimized to handle triangular polygons. Since many polygons aren't necessarily triangles, tesselation breaks up polys into triangle segments.
Josh Knox thatguy.net
"Before you criticize someone, walk a mile in their shoes. That way, when you criticize them, you're a mile away, and you have their shoes."  author unknown





Because current hardware is optimized for triangles and not polygons of an x number vertices.
Elmar





I have a polygonal load you can apply on a surface. Now I must reduce the load to triangles (or quads) in order to get them into an FEA program.
Gernot.







General News Suggestion Question Bug Answer Joke Praise Rant Admin Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

