This is driving me a bit nuts. I have a geometry but when I export it to an
STL, importing it to MeshLab will result in a non-watertight object and
NetFabb won't even open it. Makerbot Desktop doesn't seem to have any
problem with it though. However, I need the center of mass of the object,
and I don't know of another way of doing it without MeshLab.
Anyone have any ideas what I can do?
I'll try and post a working minimal model to the forum in a bit.
--
View this message in context: http://forum.openscad.org/STL-is-unreadable-or-not-watertight-tp20642.html
Sent from the OpenSCAD mailing list archive at Nabble.com.
Impossible to say without the file or some code. Basically it means you
have a mesh with hole in it. You can easily make those with polyhedron or
by doing CGS ops on almost coincident surfaces.
On 28 February 2017 at 14:30, adrian adrianh.bsc@gmail.com wrote:
This is driving me a bit nuts. I have a geometry but when I export it to
an
STL, importing it to MeshLab will result in a non-watertight object and
NetFabb won't even open it. Makerbot Desktop doesn't seem to have any
problem with it though. However, I need the center of mass of the object,
and I don't know of another way of doing it without MeshLab.
Anyone have any ideas what I can do?
I'll try and post a working minimal model to the forum in a bit.
--
View this message in context: http://forum.openscad.org/STL-
is-unreadable-or-not-watertight-tp20642.html
Sent from the OpenSCAD mailing list archive at Nabble.com.
OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Nm, seems to be a bug in MeshLab that corrupted the file.
--
View this message in context: http://forum.openscad.org/STL-is-unreadable-or-not-watertight-tp20642p20647.html
Sent from the OpenSCAD mailing list archive at Nabble.com.
Nope, seems to be some operation. Simplifying the model somewhat fixed the
issue. Trying to track down the problem now. Will post later with my
findings.
--
View this message in context: http://forum.openscad.org/STL-is-unreadable-or-not-watertight-tp20642p20649.html
Sent from the OpenSCAD mailing list archive at Nabble.com.
Ok. So the problem is a translation() call is messing up the geometry. Here
is here is the code:
$fn=34;module mirror2(rot){ rotate(rot/2) children();
rotate(-rot/2) mirror([1,0,0]) children();}module
eye(inner=true, outer=true){ if (inner) { if (outer) {
difference() { object(0);
object(wallThickness); } } else {
object(0); } } else { object(wallThickness); }
module object(thickness) { // eye (outer wall)
translate([-4,-5.1,4]) rotate([-90,0,-20]) scale([1.8,
1.1, 1]) sphere(d=2-thickness2); }}module
headSphere(inner=true, outer=true){ if (inner) { if (outer)
{ difference() { object(0);
object(wallThickness); } } else {
object(0); } } else { object(wallThickness); }
module object(thickness) { translate([0,0,-2])
scale([1.3, 1.1, 1.3]) sphere(d=15-thickness2); }}module
mouth(inner=true, outer=true){ if (inner) { if (outer) {
difference() { object(wallThickness);
object(0); } } else {
object(wallThickness); } } else { object(0); }
module object(thickness) { // mouth (outer wall)
translate([0,-7.5,-2]) rotate([-45,0,0]) scale([1.8,
1.1, 1]) sphere(d=5+thickness2); }}module
alignmentHolder(inner=true, outer=true){ if (inner) { if
(outer) { difference() {
object(wallThickness); object(0); } }
else { object(wallThickness); } } else {
object(0); } module object(thickness) { mirror2(0)
translate([1.2-.4-thickness/2, 2, -4+.15]) rotate([0,90,0])
cylinder(d=5.4+thickness,h=.45+thickness); }}module
neckHollow(inner=true, outer=true){ if (inner) { if (outer)
{ difference() { object(wallThickness);
object(0); } } else {
object(wallThickness); } } else { object(0); }
module object(thickness) { translate([0,0,thickness])
// neck hollow translate([0,0,33-44]) scale_([1.3,
4.5, 1], undef, [0, 2, 0]) hull() {
translate([0,2,neckHeight]) cube([5,.001,.001],
center=true); scale([1.3, 1.1, 1])
translate([0,0,-1.2]) linear_extrude(.0001)
circle(d=10); } }}module hair(inner=true,
outer=true){ if (inner) { if (outer) {
difference() { object(0);
object(wallThickness); } } else {
object(0); } } else { object(wallThickness); }
module object(thickness) { difference() {
//mirror2(0) translate([0,0,-15/2-(1.8)])
side(thickness); neckHollow(inner=false); } module
side(thickness) { h = 1; translate([0,0,
h+(thickness ? .00001+thickness : 0)]) difference()
{ linear_extrude(15/2-h)
offset(r=-thickness) hair2d(); }
//neckHollow(outer=false); } module hair2d() {
intersection() { projection()
headSphere(outer=false); translate([-15, -3])
square([30,15]); } } }}module weight(){
translate([0,2,-4+.15]) rotate([90,90,0]) wedge(10, 60,
wedge_centred);}preview = 0;neckHeight=5.5*1.3;wallThickness=.4;module
head(){ difference() { if(1) { // eye
mirror2(0) difference() {
eye(); headSphere(inner=false); }
//mouth intersection() { mouth();
headSphere(inner=false); } // neck hollow
difference() { intersection() {
neckHollow(); headSphere(outer=false); }
alignmentHolder(outer=false); } // alignment holder
difference() { alignmentHolder();
neckHollow(inner=false); } // hair
difference() { hair();
headSphere(inner=false); } // weight
inside of head difference() {
intersection() { weight();
union(1) {
headSphere(inner=false); hair(inner=false);
} } neckHollow(inner=false);
alignmentHolder(outer=false); } // head
difference() { headSphere();
mirror2(0) eye(inner=false);
mouth(inner=false); neckHollow(outer=false);
alignmentHolder(outer=false);
hair(inner=false); } } if (preview) {
// used to see within head translate([6.4,-5,-15/2])
cube([20,7,15]); } }}module scale_(a, v, offset){
translate(offset) scale(a) translate(-offset)
children();}wedge_below_xy = 0;wedge_above_xy = 1;wedge_centred = 2;//
wedge//// Generates a wedge which is off to the right of the y-axis and is
centred on// the x-axis.//// Primary purporse of wedge is to produce a
wedge for intersecting with an// object.//// size// - is matrix then//
length = size[0]2 (y-axis)// width = size[1] (x-axis)// height
= size[2] (z-axis)// angle = has no meaning in this context// - is
a value then// specifies the half base size along xy-plane//
length = size2 (y-axis)// width = size (x-axis)// - if angle
is undefined then// height = size.// else//
height = tan(angle)*size.// type// - is wedge_centred then wedge is
centred around the xy-plane// (See Figure 1)// - is wedge_above_xy
then wedge is above the xy-plane// (See Figure 2)// - is
wedge_below_xy then wedge is below the xy-plane// (See Figure 2)////
E.g. Figure 1: wedge_centred//// y-axis
z-axis// //
|<-width->| | // |.
___ | ___ // | | ^
| /| ^ // | | | | / | |
// | | | | / | | // |
| | | / | | // | | length/2
| / | height// | | | | / | |
// | | | | / angle| | // |
| v |/ | | | // --+ |------ x-axis
---+ <-+ |---|--// | | |\ |
| // | | | \ | | // |
| | \ | | // | |
| \ | | // | | | \ | |
// | | | \ | | // |
| | \ | | // ||
| | v // | |
// | | //// E.g.
Figure 2: wedge_above_xy and wedge_below_xy//// y-axis
z-axis z-axis //
// |<-width->| | |
// |. ___ | ___ |// |
| ^ | /| ^ |// | | |
| / | | |// | | | | / | |
|// | | | | / | | |// |
| length/2 | / | height |// | | |
| / | | | angle// | | | | / |
| | |// | | v |/ | v |
v// --+ |------ x-axis ---+--------+------
---+--------+------// | | | ^
|\ | ^ // | | | | |
\ | | // | | | angle |
\ | | // | | | |
\ | height// | | | |
\ | | // | | | |
\ | | // | | | |
\ | | // || | |
| v // | | |
// | | |
//module wedge(size, angle, type){ ASSERT(type != undef, "Specify type of
wedge"); if (is_matrix(size)) { w(size[0], size[1], size[2],
type); } else { if (angle == undef) {
w(size, size, size, type); } else {
//echo(size=size,angle=angle); ASSERT(-180 < angle && angle < 180
, str("Wedge angle is ", angle, " but must be between (-180, 180)"));
if (angle >= 0) { w(size, size, tan(type ==
wedge_centred ? angle/2 : angle)*size, type); } else
{ // If angle is < 0 then make positive and use below type if
above // or vice versa. This results in the same wedge but
keeps the // face normals going in the correct direction.
w(size, size, tan(type == wedge_centred ? -angle/2 : -angle)*size
, type == wedge_centred ? wedge_centred : !type); }
} } module w(l, w, h, type) { wedge_faces =
[[0,1,2,3],[3,5,4,0],[4,1,0],[2,5,3],[4,5,2,1]]; if (type ==
wedge_centred) { polyhedron(
[[0,-l,0],[w,-l,-h],[w,l,-h],[0,l,0],[w,-l,h],[w,l,h]],
wedge_faces ); } else if (type == wedge_below_xy)
{ echo("ANGLE", angle([w,0,0], [w,0,h])); polyhedron(
[[0,-l,0],[w,-l,-h],[w,l,-h],[0,l,0],[w,-l,0],[w,l,0]],
wedge_faces ); } else if (type == wedge_above_xy)
{ polyhedron(
[[0,-l,0],[w,-l,0],[w,l,0],[0,l,0],[w,-l,h],[w,l,h]],
wedge_faces ); } else {
ASSERT(false, str("Wedge type not valid value (", type, ") when calling
module wedge().")); } }}module ASSERT(x, msg){ if (!x) {
if (msg == undef) { echo(str(" ASSERT FAILURE: No
message.")); } else { echo(str(" ASSERT
FAILURE: ", msg, "")); } }}function is_matrix(x) = len(x)
!= undef && (x[0] != x[0][0] || len(x) != len(str(x)));//
headtranslate([0,0,44]) head();
The 2nd last line when not commented out, will result in an STL that is a
bit corrupted. Very weird, and definitely very wrong.
Tested in OpenSCAD version 2016.10.04 (git 7e0935d) and OpenSCAD version
2015.03-2
--
View this message in context: http://forum.openscad.org/STL-is-unreadable-or-not-watertight-tp20642p20652.html
Sent from the OpenSCAD mailing list archive at Nabble.com.
With or without the translation it has 8 holes according to netfabb and
lots of degenerate faces. They seem to be where the hair joins the head.
Possibly it needs to overlap a bit.
The way a translate can break things (although in this case it seems broken
anyway) is that the precision of floating point numbers gets less as they
get bigger. When you have very close vertices they can collapse when made
more distant from the origin.
On 28 February 2017 at 15:43, adrian adrianh.bsc@gmail.com wrote:
Ok. So the problem is a translation() call is messing up the geometry.
Here is here is the code:
$fn=34;
module mirror2(rot)
{
rotate(rot/2)
children();
rotate(-rot/2)
mirror([1,0,0])
children();
}
module eye(inner=true, outer=true)
{
if (inner)
{
if (outer)
{
difference()
{
object(0);
object(wallThickness);
}
}
else
{
object(0);
}
}
else
{
object(wallThickness);
}
module object(thickness)
{
// eye (outer wall)
translate([-4,-5.1,4])
rotate([-90,0,-20])
scale([1.8, 1.1, 1])
sphere(d=2-thickness*2);
}
}
module headSphere(inner=true, outer=true)
{
if (inner)
{
if (outer)
{
difference()
{
object(0);
object(wallThickness);
}
}
else
{
object(0);
}
}
else
{
object(wallThickness);
}
module object(thickness)
{
translate([0,0,-2])
scale([1.3, 1.1, 1.3])
sphere(d=15-thickness*2);
}
}
module mouth(inner=true, outer=true)
{
if (inner)
{
if (outer)
{
difference()
{
object(wallThickness);
object(0);
}
}
else
{
object(wallThickness);
}
}
else
{
object(0);
}
module object(thickness)
{
// mouth (outer wall)
translate([0,-7.5,-2])
rotate([-45,0,0])
scale([1.8, 1.1, 1])
sphere(d=5+thickness*2);
}
}
module alignmentHolder(inner=true, outer=true)
{
if (inner)
{
if (outer)
{
difference()
{
object(wallThickness);
object(0);
}
}
else
{
object(wallThickness);
}
}
else
{
object(0);
}
module object(thickness)
{
mirror2(0)
translate([1.2-.4-thickness/2, 2, -4+.15])
rotate([0,90,0])
cylinder(d=5.4+thickness,h=.4*5+thickness);
}
}
module neckHollow(inner=true, outer=true)
{
if (inner)
{
if (outer)
{
difference()
{
object(wallThickness);
object(0);
}
}
else
{
object(wallThickness);
}
}
else
{
object(0);
}
module object(thickness)
{
translate([0,0,thickness])
// neck hollow
translate([0,0,33-44])
scale_([1.3, 4.5, 1], undef, [0, 2, 0])
hull()
{
translate([0,2,neckHeight])
cube([5,.001,.001], center=true);
scale([1.3, 1.1, 1])
translate([0,0,-1.2])
linear_extrude(.0001)
circle(d=10);
}
}
}
module hair(inner=true, outer=true)
{
if (inner)
{
if (outer)
{
difference()
{
object(0);
object(wallThickness);
}
}
else
{
object(0);
}
}
else
{
object(wallThickness);
}
module object(thickness)
{
difference()
{
//mirror2(0)
translate([0,0,-15/2-(1.8)])
side(thickness);
neckHollow(inner=false);
}
module side(thickness)
{
h = 1;
translate([0,0, h+(thickness ? .00001+thickness : 0)])
difference()
{
linear_extrude(15/2-h)
offset(r=-thickness)
hair2d();
}
//neckHollow(outer=false);
}
module hair2d()
{
intersection()
{
projection()
headSphere(outer=false);
translate([-15, -3])
square([30,15]);
}
}
}
}
module weight()
{
translate([0,2,-4+.15])
rotate([90,90,0])
wedge(10, 60, wedge_centred);
}
preview = 0;
neckHeight=5.5*1.3;
wallThickness=.4;
module head()
{
difference()
{
if(1)
{
// eye
mirror2(0)
difference()
{
eye();
headSphere(inner=false);
}
//mouth
intersection()
{
mouth();
headSphere(inner=false);
}
// neck hollow
difference()
{
intersection()
{
neckHollow();
headSphere(outer=false);
}
alignmentHolder(outer=false);
}
// alignment holder
difference()
{
alignmentHolder();
neckHollow(inner=false);
}
// hair
difference()
{
hair();
headSphere(inner=false);
}
// weight inside of head
difference()
{
intersection()
{
weight();
union(1)
{
headSphere(inner=false);
hair(inner=false);
}
}
neckHollow(inner=false);
alignmentHolder(outer=false);
}
// head
difference()
{
headSphere();
mirror2(0)
eye(inner=false);
mouth(inner=false);
neckHollow(outer=false);
alignmentHolder(outer=false);
hair(inner=false);
}
}
if (preview)
{
// used to see within head
translate([6.4,-5,-15/2])
cube([20,7,15]);
}
}
}
module scale_(a, v, offset)
{
translate(offset)
scale(a)
translate(-offset)
children();
}
wedge_below_xy = 0;
wedge_above_xy = 1;
wedge_centred = 2;
// wedge
//
// Generates a wedge which is off to the right of the y-axis and is centred on
// the x-axis.
//
// Primary purporse of wedge is to produce a wedge for intersecting with an
// object.
//
// size
// - is matrix then
// length = size[0]2 (y-axis)
// width = size[1] (x-axis)
// height = size[2] (z-axis)
// angle = has no meaning in this context
// - is a value then
// specifies the half base size along xy-plane
// length = size2 (y-axis)
// width = size (x-axis)
// - if angle is undefined then
// height = size.
// else
// height = tan(angle)*size.
// type
// - is wedge_centred then wedge is centred around the xy-plane
// (See Figure 1)
// - is wedge_above_xy then wedge is above the xy-plane
// (See Figure 2)
// - is wedge_below_xy then wedge is below the xy-plane
// (See Figure 2)
//
// E.g. Figure 1: wedge_centred
//
// y-axis z-axis
//
// |<-width->| |
// |. ___ | ___
// | | ^ | /| ^
// | | | | / | |
// | | | | / | |
// | | | | / | |
// | | length/2 | / | height
// | | | | / | |
// | | | | / angle| |
// | | v |/ | | |
// --+ |------ x-axis ---+ <-+ |---|--
// | | |\ | |
// | | | \ | |
// | | | \ | |
// | | | \ | |
// | | | \ | |
// | | | \ | |
// | | | \ | |
// || | | v
// | |
// | |
//
// E.g. Figure 2: wedge_above_xy and wedge_below_xy
//
// y-axis z-axis z-axis
//
// |<-width->| | |
// |. ___ | ___ |
// | | ^ | /| ^ |
// | | | | / | | |
// | | | | / | | |
// | | | | / | | |
// | | length/2 | / | height |
// | | | | / | | | angle
// | | | | / | | | |
// | | v |/ | v | v
// --+ |------ x-axis ---+--------+------ ---+--------+------
// | | | ^ |\ | ^
// | | | | | \ | |
// | | | angle | \ | |
// | | | | \ | height
// | | | | \ | |
// | | | | \ | |
// | | | | \ | |
// || | | | v
// | | |
// | | |
//
module wedge(size, angle, type)
{
ASSERT(type != undef, "Specify type of wedge");
if (is_matrix(size))
{
w(size[0], size[1], size[2], type);
}
else
{
if (angle == undef)
{
w(size, size, size, type);
}
else
{
//echo(size=size,angle=angle);
ASSERT(-180 < angle && angle < 180
, str("Wedge angle is ", angle, " but must be between (-180, 180)"));
if (angle >= 0)
{
w(size, size, tan(type == wedge_centred ? angle/2 : angle)*size, type);
}
else
{
// If angle is < 0 then make positive and use below type if above
// or vice versa. This results in the same wedge but keeps the
// face normals going in the correct direction.
w(size, size, tan(type == wedge_centred ? -angle/2 : -angle)*size
, type == wedge_centred ? wedge_centred : !type);
}
}
}
module w(l, w, h, type)
{
wedge_faces = [[0,1,2,3],[3,5,4,0],[4,1,0],[2,5,3],[4,5,2,1]];
if (type == wedge_centred)
{
polyhedron(
[[0,-l,0],[w,-l,-h],[w,l,-h],[0,l,0],[w,-l,h],[w,l,h]],
wedge_faces
);
}
else if (type == wedge_below_xy)
{
echo("ANGLE", angle([w,0,0], [w,0,h]));
polyhedron(
[[0,-l,0],[w,-l,-h],[w,l,-h],[0,l,0],[w,-l,0],[w,l,0]],
wedge_faces
);
}
else if (type == wedge_above_xy)
{
polyhedron(
[[0,-l,0],[w,-l,0],[w,l,0],[0,l,0],[w,-l,h],[w,l,h]],
wedge_faces
);
}
else
{
ASSERT(false, str("Wedge type not valid value (", type, ") when calling module wedge()."));
}
}
}
module ASSERT(x, msg)
{
if (!x)
{
if (msg == undef)
{
echo(str(" ASSERT FAILURE: No message."));
}
else
{
echo(str(" ASSERT FAILURE: ", msg, ""));
}
}
}
function is_matrix(x) = len(x) != undef && (x[0] != x[0][0] || len(x) != len(str(x)));
// head
translate([0,0,44])
head();
The 2nd last line when not commented out, will result in an STL that is a
bit corrupted. Very weird, and definitely very wrong.
Tested in OpenSCAD version 2016.10.04 (git 7e0935d) and OpenSCAD version
2015.03-2
View this message in context: Re: STL is unreadable or not 'watertight'
http://forum.openscad.org/STL-is-unreadable-or-not-watertight-tp20642p20652.html
Sent from the OpenSCAD mailing list archive http://forum.openscad.org/
at Nabble.com.
OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Then this is an export issue, or a point representation issue? Or is it a
coplanar face issue?
Might have to finally open up the code and take a look at the export.
--
View this message in context: http://forum.openscad.org/STL-is-unreadable-or-not-watertight-tp20642p20666.html
Sent from the OpenSCAD mailing list archive at Nabble.com.
Hi Adrian
Your problem is most likely internal rounding errors, which cause
"degenerate triangles" when OpenSCAD generates the .stl file. "Degenerate
triangles" are faces where at least one altitude is near zero (not, as is
often claimed, the triangle area is near zero). A near zero altitude does
lead to a poorly defined face normal, a crack, or even a reversal of face
orientation - all meaning that e.g. boolean operations on such a .stl file
are impossible. There are further consequences, which I need not detail
here, as you cannot influence them writing an OpenSCAD script.
There are many ways to generate "degenerate triangles". In your code, I spot
many 90 degree rotations, which are a sure way to cause internal rounding
errors, and thus "broken" .stl files. Remove them.
Also scan your code for other opportunities to generate faces with near-zero
altitude, such as scaling. Translations are very low on my list of
candidates that generate broken .stl files. Near-zero, by the way, means 3-5
powers of 10 below the largest length that you use. In that sense, using
cubes like [5,.001,.001] is dangerous, and so is linear_extrude(.0001)
For my colleagues, let me add here two pieces of code, to demonstrate what I
have said. The first one generates a shape that cannot be subjected to
further boolean operations:
// source:
https://github.com/openscad/openscad/blob/master/testdata/scad/3D/issues/issue1258.scad
difference() {
translate([-6, 4, 30]) cube(size = [17.5, 48, 60], center = true);
translate([-10.5, 3, 30]) cube(size = [20.5, 55, 80], center = true);
}
translate([-0.25, -19, 33])
rotate([0, 90, 0])
rotate([0, 0, -45])
cube(size = [15, 15, 3], center = false);
This code generates the same shape, and can be subjected to further boolean
operations. Notice how I have replaced the 90 degree rotation with changes
elsewhere to arrive at the same shape:
difference() {
translate([-6, 4, 30]) cube(size = [17.5, 48, 60], center = true);
translate([-10.5, 3, 30]) cube(size = [20.5, 55, 80], center = true);
}
translate([-0.25, -19, 33])
rotate([45,0,0])
cube(size = [3, 15, 15], center = false);
Create .stl files from both, and have a look at the faces and edges present,
to see examples of some of the further consequences I mentioned above:
vertices where there should be none and faces that should not be present.
wolf
--
View this message in context: http://forum.openscad.org/STL-is-unreadable-or-not-watertight-tp20642p20667.html
Sent from the OpenSCAD mailing list archive at Nabble.com.
What I should have added to my previous post:
difference()
{
union()
{
translate([-10, -19, 33]) rotate([0, 90, 0]) rotate([0, 0, -45])
cube(size = [15, 15,15], center = false);
translate([-3, 4, 30]) cube(size = [17.5, 48, 60], center = true);
}
translate([-10.25, 3, 30]) cube(size = [20, 75, 80], center = true);
translate([12.75, 3, 30]) cube(size = [20, 75, 80], center = true);
}
This is the proper way to create the shape, as it has the proper meshing on
both sides, and the rounding issues due to rotate([0, 90, 0]) have been
wiped out. With no rounding issues present, there are also no "degenerate
triangles" and thus no problems with further boolean operations.
wolf
--
View this message in context: http://forum.openscad.org/STL-is-unreadable-or-not-watertight-tp20642p20671.html
Sent from the OpenSCAD mailing list archive at Nabble.com.
Thanks Wolf,
I don't know the API yet, but that a 90 degree rotation causes degenerate
faces is definitely a bug. I'll try and take a look at this sometime in the
next couple of weeks as this is completely unacceptable.
--
View this message in context: http://forum.openscad.org/STL-is-unreadable-or-not-watertight-tp20642p20678.html
Sent from the OpenSCAD mailing list archive at Nabble.com.