### What are degenerate facets anyway?

SL
Steve Lelievre
Mon, Feb 19, 2024 1:57 AM

Please can someone explain to me what a degenerate facet actually is,
and why they arise? I ask because I have what I think is a simple
run-of-the-mill model and I was surprised when PrusaSlicer told me that
there are degenerate facets.

It's not a big deal because PrusaSlicer fixes them and I can print my
model, but it got me wondering about the root of the issue.

I'm using OpenSCAD version 2024.02.11 on Windows 10. My model's source
code is given below. By trial and error, I found that the number of
degenerate facets depends of the value of \$fn, but that bit of
information hasn't actually helped me understand why these things arise.

Cheers,

Steve

\$fn = 30;
difference() {
rotate([13.65, 0, 0]) translate([0, 0, -12.5]) difference() {
hull() for(i = [18, -18], j = [18, -18]) translate([i, j, 0])
cylinder(r = 10, h = 20);
for(i = [20, -20], j = [20, -20]) translate([i, j, 0])
cylinder(r = 1.4, h = 60, center = true);
}
translate([0, -0.15, 0]) union() {
for(i = [0, 180]) rotate(i) translate([18, 0, 2]) cylinder(r =
4, h = 30);
for(i = [0, 180]) rotate(i) translate([18, 0, 0]) cylinder(r =
1.4, h = 30,  center = true);
for(i = [90, 270]) rotate(i) translate([14, 0, 2]) cylinder(r
= 4, h = 30);
for(i = [90, 270]) rotate(i) translate([14, 0, 0]) cylinder(r
= 1.4, h = 30,  center = true);
}
translate([0, 0, -50]) cube(100, center = true);
cube([0.4, 100, 2.1], center = true);
}

Please can someone explain to me what a degenerate facet actually is, and why they arise? I ask because I have what I think is a simple run-of-the-mill model and I was surprised when PrusaSlicer told me that there are degenerate facets. It's not a big deal because PrusaSlicer fixes them and I can print my model, but it got me wondering about the root of the issue. I'm using OpenSCAD version 2024.02.11 on Windows 10. My model's source code is given below. By trial and error, I found that the number of degenerate facets depends of the value of \$fn, but that bit of information hasn't actually helped me understand why these things arise. Cheers, Steve > \$fn = 30; > difference() { >     rotate([13.65, 0, 0]) translate([0, 0, -12.5]) difference() { >         hull() for(i = [18, -18], j = [18, -18]) translate([i, j, 0]) > cylinder(r = 10, h = 20); >         for(i = [20, -20], j = [20, -20]) translate([i, j, 0]) > cylinder(r = 1.4, h = 60, center = true); >     } >     translate([0, -0.15, 0]) union() { >         for(i = [0, 180]) rotate(i) translate([18, 0, 2]) cylinder(r = > 4, h = 30); >         for(i = [0, 180]) rotate(i) translate([18, 0, 0]) cylinder(r = > 1.4, h = 30,  center = true); >         for(i = [90, 270]) rotate(i) translate([14, 0, 2]) cylinder(r > = 4, h = 30); >         for(i = [90, 270]) rotate(i) translate([14, 0, 0]) cylinder(r > = 1.4, h = 30,  center = true); >     } >   translate([0, 0, -50]) cube(100, center = true); >   cube([0.4, 100, 2.1], center = true); > }
CL
Chow Loong Jin
Mon, Feb 19, 2024 3:51 AM

Hi Steve,

On Sun, Feb 18, 2024 at 05:57:38PM -0800, Steve Lelievre via Discuss wrote:

Please can someone explain to me what a degenerate facet actually is, and
why they arise? I ask because I have what I think is a simple
run-of-the-mill model and I was surprised when PrusaSlicer told me that
there are degenerate facets.

It's not a big deal because PrusaSlicer fixes them and I can print my model,
but it got me wondering about the root of the issue.

I'm using OpenSCAD version 2024.02.11 on Windows 10. My model's source code
is given below. By trial and error, I found that the number of degenerate
facets depends of the value of \$fn, but that bit of information hasn't
actually helped me understand why these things arise.

Here's the code that detects degenerate facets in Prusa Slicer:

``````// If any two of the three vertices are found to be exactally the same, call them degenerate and remove the facet.
// Do it before the next step, as the next step stores references to the face indices in the hash tables and removing a facet
// will break the references.
for (uint32_t i = 0; i < stl->stats.number_of_facets;) {
stl_facet &facet = stl->facet_start[i];
if (facet.vertex[0] == facet.vertex[1] || facet.vertex[1] == facet.vertex[2] || facet.vertex[0] == facet.vertex[2]) {
// Remove the degenerate facet.
facet = stl->facet_start[-- stl->stats.number_of_facets];
stl->facet_start.pop_back();
stl->neighbors_start.pop_back();
stl->stats.facets_removed += 1;
stl->stats.degenerate_facets += 1;
} else
++ i;
}
``````

To summarize:

• a facet in an STL is a triangle, so it should have three
vertices/points.

• if two points in the "triangle" are identical, it's no longer a
triangle, hence it's "degenerate".

I'm not actually able to reproduce the degenerate facets issue that
you're facing from the code you attached on my machine (OpenSCAD
20240215 snapshot, Ubuntu 23.10), but I suspect that what's happening is
that you have small circles with too many facets in them (\$fn too high
for a given radius), causing rounding errors to occur during the export,
resulting in STL triangles that are actually lines or single points.

Consider replacing `\$fn = 30;` with `\$fs = 0.4; \$fa = 1;`, which would
give you a more even quality bump (large curves get more vertices, small
curves/circles get fewer vertices, so you no longer end up with points
too close to each other).

--
Kind regards,
Loong Jin

Hi Steve, On Sun, Feb 18, 2024 at 05:57:38PM -0800, Steve Lelievre via Discuss wrote: > > Please can someone explain to me what a degenerate facet actually is, and > why they arise? I ask because I have what I think is a simple > run-of-the-mill model and I was surprised when PrusaSlicer told me that > there are degenerate facets. > > It's not a big deal because PrusaSlicer fixes them and I can print my model, > but it got me wondering about the root of the issue. > > I'm using OpenSCAD version 2024.02.11 on Windows 10. My model's source code > is given below. By trial and error, I found that the number of degenerate > facets depends of the value of \$fn, but that bit of information hasn't > actually helped me understand why these things arise. Here's the code that detects degenerate facets in Prusa Slicer: // If any two of the three vertices are found to be exactally the same, call them degenerate and remove the facet. // Do it before the next step, as the next step stores references to the face indices in the hash tables and removing a facet // will break the references. for (uint32_t i = 0; i < stl->stats.number_of_facets;) { stl_facet &facet = stl->facet_start[i]; if (facet.vertex[0] == facet.vertex[1] || facet.vertex[1] == facet.vertex[2] || facet.vertex[0] == facet.vertex[2]) { // Remove the degenerate facet. facet = stl->facet_start[-- stl->stats.number_of_facets]; stl->facet_start.pop_back(); stl->neighbors_start.pop_back(); stl->stats.facets_removed += 1; stl->stats.degenerate_facets += 1; } else ++ i; } To summarize: - a facet in an STL is a triangle, so it should have three vertices/points. - if two points in the "triangle" are identical, it's no longer a triangle, hence it's "degenerate". I'm not actually able to reproduce the degenerate facets issue that you're facing from the code you attached on my machine (OpenSCAD 20240215 snapshot, Ubuntu 23.10), but I suspect that what's happening is that you have small circles with too many facets in them (\$fn too high for a given radius), causing rounding errors to occur during the export, resulting in STL triangles that are actually lines or single points. Consider replacing `\$fn = 30;` with `\$fs = 0.4; \$fa = 1;`, which would give you a more even quality bump (large curves get more vertices, small curves/circles get fewer vertices, so you no longer end up with points too close to each other). -- Kind regards, Loong Jin
SL
Steve Lelievre
Mon, Feb 19, 2024 4:18 AM

Hi,

I followed your advice and, sure enough, there are no longer any
degenerate facets in the output.

Thank you!

Steve

On 2024-02-18 7:51 p.m., Chow Loong Jin wrote:

Hi Steve,

On Sun, Feb 18, 2024 at 05:57:38PM -0800, Steve Lelievre via Discuss wrote:

Please can someone explain to me what a degenerate facet actually is, and
why they arise? I ask because I have what I think is a simple
run-of-the-mill model and I was surprised when PrusaSlicer told me that
there are degenerate facets.

It's not a big deal because PrusaSlicer fixes them and I can print my model,
but it got me wondering about the root of the issue.

I'm using OpenSCAD version 2024.02.11 on Windows 10. My model's source code
is given below. By trial and error, I found that the number of degenerate
facets depends of the value of \$fn, but that bit of information hasn't
actually helped me understand why these things arise.

Here's the code that detects degenerate facets in Prusa Slicer:

``````	// If any two of the three vertices are found to be exactally the same, call them degenerate and remove the facet.
// Do it before the next step, as the next step stores references to the face indices in the hash tables and removing a facet
// will break the references.
for (uint32_t i = 0; i < stl->stats.number_of_facets;) {
stl_facet &facet = stl->facet_start[i];
if (facet.vertex[0] == facet.vertex[1] || facet.vertex[1] == facet.vertex[2] || facet.vertex[0] == facet.vertex[2]) {
// Remove the degenerate facet.
facet = stl->facet_start[-- stl->stats.number_of_facets];
stl->facet_start.pop_back();
stl->neighbors_start.pop_back();
stl->stats.facets_removed += 1;
stl->stats.degenerate_facets += 1;
} else
++ i;
}
``````

To summarize:

• a facet in an STL is a triangle, so it should have three
vertices/points.

• if two points in the "triangle" are identical, it's no longer a
triangle, hence it's "degenerate".

I'm not actually able to reproduce the degenerate facets issue that
you're facing from the code you attached on my machine (OpenSCAD
20240215 snapshot, Ubuntu 23.10), but I suspect that what's happening is
that you have small circles with too many facets in them (\$fn too high
for a given radius), causing rounding errors to occur during the export,
resulting in STL triangles that are actually lines or single points.

Consider replacing `\$fn = 30;` with `\$fs = 0.4; \$fa = 1;`, which would
give you a more even quality bump (large curves get more vertices, small
curves/circles get fewer vertices, so you no longer end up with points
too close to each other).

Hi, Thank you for your very clear, informative, and helpful explanation. I followed your advice and, sure enough, there are no longer any degenerate facets in the output. Thank you! Steve On 2024-02-18 7:51 p.m., Chow Loong Jin wrote: > Hi Steve, > > On Sun, Feb 18, 2024 at 05:57:38PM -0800, Steve Lelievre via Discuss wrote: >> Please can someone explain to me what a degenerate facet actually is, and >> why they arise? I ask because I have what I think is a simple >> run-of-the-mill model and I was surprised when PrusaSlicer told me that >> there are degenerate facets. >> >> It's not a big deal because PrusaSlicer fixes them and I can print my model, >> but it got me wondering about the root of the issue. >> >> I'm using OpenSCAD version 2024.02.11 on Windows 10. My model's source code >> is given below. By trial and error, I found that the number of degenerate >> facets depends of the value of \$fn, but that bit of information hasn't >> actually helped me understand why these things arise. > Here's the code that detects degenerate facets in Prusa Slicer: > > // If any two of the three vertices are found to be exactally the same, call them degenerate and remove the facet. > // Do it before the next step, as the next step stores references to the face indices in the hash tables and removing a facet > // will break the references. > for (uint32_t i = 0; i < stl->stats.number_of_facets;) { > stl_facet &facet = stl->facet_start[i]; > if (facet.vertex[0] == facet.vertex[1] || facet.vertex[1] == facet.vertex[2] || facet.vertex[0] == facet.vertex[2]) { > // Remove the degenerate facet. > facet = stl->facet_start[-- stl->stats.number_of_facets]; > stl->facet_start.pop_back(); > stl->neighbors_start.pop_back(); > stl->stats.facets_removed += 1; > stl->stats.degenerate_facets += 1; > } else > ++ i; > } > > To summarize: > - a facet in an STL is a triangle, so it should have three > vertices/points. > > - if two points in the "triangle" are identical, it's no longer a > triangle, hence it's "degenerate". > > I'm not actually able to reproduce the degenerate facets issue that > you're facing from the code you attached on my machine (OpenSCAD > 20240215 snapshot, Ubuntu 23.10), but I suspect that what's happening is > that you have small circles with too many facets in them (\$fn too high > for a given radius), causing rounding errors to occur during the export, > resulting in STL triangles that are actually lines or single points. > > Consider replacing `\$fn = 30;` with `\$fs = 0.4; \$fa = 1;`, which would > give you a more even quality bump (large curves get more vertices, small > curves/circles get fewer vertices, so you no longer end up with points > too close to each other). > -- https://www.gnomoni.ca https://www.youtube.com/@gnomonica
CA
Carsten Arnholm
Mon, Feb 19, 2024 8:48 AM

On 2024-02-19 04:51, Chow Loong Jin via Discuss wrote:

• if two points in the "triangle" are identical, it's no longer a
triangle, hence it's "degenerate".

That is one possibility, but not the only one. You can have a degenerate
triangle also without two points being identical. If the 3 triangle
points all lie on a straight line, the triangle is degenerate.

A triangle is degenerate if its area is zero.

Carsten Arnholm

On 2024-02-19 04:51, Chow Loong Jin via Discuss wrote: > - if two points in the "triangle" are identical, it's no longer a > triangle, hence it's "degenerate". That is one possibility, but not the only one. You can have a degenerate triangle also without two points being identical. If the 3 triangle points all lie on a straight line, the triangle is degenerate. A triangle is degenerate if its area is zero. Carsten Arnholm
CL
Chow Loong Jin
Wed, Feb 21, 2024 3:04 AM

On Mon, Feb 19, 2024 at 09:48:36AM +0100, Carsten Arnholm via Discuss wrote:

On 2024-02-19 04:51, Chow Loong Jin via Discuss wrote:

• if two points in the "triangle" are identical, it's no longer a
triangle, hence it's "degenerate".

That is one possibility, but not the only one. You can have a degenerate
triangle also without two points being identical. If the 3 triangle points
all lie on a straight line, the triangle is degenerate.

A triangle is degenerate if its area is zero.

Ooh yeah, thanks for catching that. It doesn't look like the logic in
admesn (embedded in Prusa Slicer) does that check though.

--
Kind regards,
Loong Jin

On Mon, Feb 19, 2024 at 09:48:36AM +0100, Carsten Arnholm via Discuss wrote: > On 2024-02-19 04:51, Chow Loong Jin via Discuss wrote: > > - if two points in the "triangle" are identical, it's no longer a > > triangle, hence it's "degenerate". > > That is one possibility, but not the only one. You can have a degenerate > triangle also without two points being identical. If the 3 triangle points > all lie on a straight line, the triangle is degenerate. > > A triangle is degenerate if its area is zero. Ooh yeah, thanks for catching that. It doesn't look like the logic in admesn (embedded in Prusa Slicer) does that check though. -- Kind regards, Loong Jin
J
jon
Sat, Feb 24, 2024 10:40 PM

I am confused.  If it is as simple as not exporting triangles with zero
area, how is it that ANY STL exporter still creates degenerate facets?
Is this something we could add to STL export, trivially?  What am I missing?

Jon

--
This email has been checked for viruses by AVG antivirus software.
www.avg.com

I am confused.  If it is as simple as not exporting triangles with zero area, how is it that ANY STL exporter still creates degenerate facets?  Is this something we could add to STL export, trivially?  What am I missing? Jon -- This email has been checked for viruses by AVG antivirus software. www.avg.com
NH
Sat, Feb 24, 2024 11:35 PM

As long as there are no self intersections it isn't too hard to remove
degenerate triangles. It isn't trivial though because if you simply omit
them you have a hole in the mesh, so you have to fix that. Since they are
generated by collapsing vertices due to truncating accuracy you always have
the possibility of creating self intersections.

On Sat, 24 Feb 2024 at 22:41, jon via Discuss discuss@lists.openscad.org
wrote:

I am confused.  If it is as simple as not exporting triangles with zero
area, how is it that ANY STL exporter still creates degenerate facets?
Is this something we could add to STL export, trivially?  What am I
missing?

Jon

--
This email has been checked for viruses by AVG antivirus software.
www.avg.com

To unsubscribe send an email to discuss-leave@lists.openscad.org

As long as there are no self intersections it isn't too hard to remove degenerate triangles. It isn't trivial though because if you simply omit them you have a hole in the mesh, so you have to fix that. Since they are generated by collapsing vertices due to truncating accuracy you always have the possibility of creating self intersections. On Sat, 24 Feb 2024 at 22:41, jon via Discuss <discuss@lists.openscad.org> wrote: > I am confused. If it is as simple as not exporting triangles with zero > area, how is it that ANY STL exporter still creates degenerate facets? > Is this something we could add to STL export, trivially? What am I > missing? > > Jon > > > > -- > This email has been checked for viruses by AVG antivirus software. > www.avg.com > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org >
JD
John David
Sat, Feb 24, 2024 11:37 PM

Many CAD related software packages deal with what are called mathematical
"manifolds" (see: https://en.wikipedia.org/wiki/Manifold).  Manifolds have
interesting properties like they are completely closed (sometimes called
"water tight"), and that every face either points outward, or inward (see:
https://cmichel.io/understanding-front-faces-winding-order-and-normals).
So, if you have a single triangle has a normal that points outwards, and
all the rest of them point inward, then it is ill formed or degenerate.
There are other potentially degenerate cases where two corners touch and
share an edge - mathematically you cannot tell if it is a single object or
two.  It is likely that others will have more to say, but I hope that this
helps.

On Sat, Feb 24, 2024 at 5:41 PM jon via Discuss discuss@lists.openscad.org
wrote:

I am confused.  If it is as simple as not exporting triangles with zero
area, how is it that ANY STL exporter still creates degenerate facets?
Is this something we could add to STL export, trivially?  What am I
missing?

Jon

--
This email has been checked for viruses by AVG antivirus software.
www.avg.com

To unsubscribe send an email to discuss-leave@lists.openscad.org

Many CAD related software packages deal with what are called mathematical "manifolds" (see: https://en.wikipedia.org/wiki/Manifold). Manifolds have interesting properties like they are completely closed (sometimes called "water tight"), and that every face either points outward, or inward (see: https://www.youtube.com/watch?v=zGyfiOqiR4s and https://cmichel.io/understanding-front-faces-winding-order-and-normals). So, if you have a single triangle has a normal that points outwards, and all the rest of them point inward, then it is ill formed or degenerate. There are other potentially degenerate cases where two corners touch and share an edge - mathematically you cannot tell if it is a single object or two. It is likely that others will have more to say, but I hope that this helps. On Sat, Feb 24, 2024 at 5:41 PM jon via Discuss <discuss@lists.openscad.org> wrote: > I am confused. If it is as simple as not exporting triangles with zero > area, how is it that ANY STL exporter still creates degenerate facets? > Is this something we could add to STL export, trivially? What am I > missing? > > Jon > > > > -- > This email has been checked for viruses by AVG antivirus software. > www.avg.com > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org >
CA
Carsten Arnholm
Sun, Feb 25, 2024 8:56 AM

On 2024-02-25 00:35, nop head via Discuss wrote:

As long as there are no self intersections it isn't too hard to remove
degenerate triangles. It isn't trivial though because if you simply
omit them you have a hole in the mesh, so you have to fix that.

Removing a triangle with zero area does not leave a hole, because the
'hole' has zero area. If you are thinking topological hole, it doesn't
apply to STL files because they don't contain any topology in the first
place, STL files are 'triangle soups'. With other formats, such as OBJ,
it is a different matter, you could be left with a zero area topological
hole.

Carsten Arnholm

On 2024-02-25 00:35, nop head via Discuss wrote: > As long as there are no self intersections it isn't too hard to remove > degenerate triangles. It isn't trivial though because if you simply > omit them you have a hole in the mesh, so you have to fix that. Removing a triangle with zero area does not leave a hole, because the 'hole' has zero area. If you are thinking topological hole, it doesn't apply to STL files because they don't contain any topology in the first place, STL files are 'triangle soups'. With other formats, such as OBJ, it is a different matter, you could be left with a zero area topological hole. Carsten Arnholm
GS
Guenther Sohler
Sun, Feb 25, 2024 9:19 AM

ITS Not that easy. Removing a Zero area Triangel might make the Solid
non-manifold. ...

Carsten Arnholm via Discuss discuss@lists.openscad.org schrieb am So.,
25. Feb. 2024, 09:56:

On 2024-02-25 00:35, nop head via Discuss wrote:

As long as there are no self intersections it isn't too hard to remove
degenerate triangles. It isn't trivial though because if you simply
omit them you have a hole in the mesh, so you have to fix that.

Removing a triangle with zero area does not leave a hole, because the
'hole' has zero area. If you are thinking topological hole, it doesn't
apply to STL files because they don't contain any topology in the first
place, STL files are 'triangle soups'. With other formats, such as OBJ,
it is a different matter, you could be left with a zero area topological
hole.

Carsten Arnholm