doug moen doug at moens.org
Thu Jun 16 10:30:38 EDT 2016

```I thought about degenerate shapes some more.

Mathematically, a degenerate shape is one with zero volume. There is an
infinite family of degenerate 3D shapes: 0D points, 1D lines, 2D surfaces,
plus the empty set which contains no points at all. Mathematically,
operations like minkowski sum and convex hull behave differently depending
on what kind of degenerate shape is passed.

Pragmatically, it's different. OpenSCAD can't represent arbitrary 3D
shapes, only polyhedra. Degenerate shapes are a problem. Internally, we use
two different representations. With the mesh representation, a well formed
mesh must not contain any triangles with zero area. With the Nef Polyhedron
representation, AFAIK there is only one degenerate Nef Polyhedron (the
empty set), and not an infinite family.

So in practice, I think OpenSCAD can only have 1 degenerate shape, which we
should treat as the empty set. So union() {}, cube(0), cube([10,0,0]) and
others should all be treated the same way, as the unique degenerate shape.

Minkowski sum treats the empty set as the zero element and the point
[0,0,0] as the identity element, but we can have only one degenerate shape,
so we can't implement these semantics exactly. I think our unique
degenerate shape should be consistently treated as the empty set, so we
don't support an identity element for minkowski sum, only a zero element.

So that means, if you pass the degenerate shape as an argument to
minkowski, then I think the result should be the degenerate shape. It's
like multiplying a number by zero, the result is zero.

Right now, it appears that degenerate shapes aren't treated consistently.
Minkowski treats the void as its identity element, ie as [0,0,0], while
other operations I tested treat it as the empty set.

But, I just read Parkinbot's analysis, and I think he makes a good argument
with this example:
>   minkowski() {  cube();   scale([\$t, \$t, \$t])  sphere(); }

Since we only get to have one degenerate shape, we get to choose how it
works for each operation.

On 15 June 2016 at 20:13, Lucas Vinicius Hartmann <lucas.hartmann at gmail.com>
wrote:

> The hull() case WOULD evaluate to a cube despite having void as the second
> operand. The hull definition is the minimal convex shape that encloses all
> solids in it, and despite the differece returninig void the first operand
> is still a solid.
>
> For the minkowski it is another story... If our math is not supposed to be
> right what would be the point of a programming language? The only example
> you found to justify the current behavior is based on a preexisting
> error... Openscad should warn that C() is void, but do exactly as
> instructed. Remember: Computers (especially programming languages) are not
> supposed to do what they believe you want, they are supposed to do exactly
> what you tell them to.
>
> Anyway... I just finished compiling 2016.06.15 (wow, that's today!) and
> the issue is still the same.
>
> - If a nothing() is originated from a difference or a previous
> intersection, then intersection() { nothing(); something();} works.
> - intersection with void module or void union fails.
> - minkowski fails with any voids.
>
> *And I got ifsolid() to work!* I just made sure the condition is never
> void by adding a far_far_away() particle, and limiting the result to
> universe(). See attached files, animated, from above.
>
> --
> Lucas Vinicius Hartmann
>
> Dizem que se você rodar o CD do Windows ao contrário ele mostra uma
> mensagem demoníaca... Mas isso nem é o pior, se você rodar ele normal ele
> instala o Windows!
>
> 2016-06-15 20:45 GMT-03:00 Parkinbot <rudolf at parkinbot.com>:
>
>> This is one of the typical pathological cases, not worth discussing much
>> in
>> programming context. You are both right, mathematically an empty set used
>> as
>> operand for Minkowski will "eat up" any other operand.
>>
>> But in programming an operator is better defined and implemented to be as
>> robust as possible.
>>
>> It is easy to "prove", that there is no [0,0,0] involved, otherwise the
>> following code would not evaluate to a cube.
>>
>>
>> > hull()
>> > {
>> >   translate([10, 0])
>> >   cube(5);
>> >   difference() // nothing
>> >   {
>> >     sphere(1);
>> >     sphere(2);
>> >   }
>> > }
>>
>> OpenSCAD implements Minkowski as I would expect it, and do it myself.
>>
>> I would want
>>
>>
>> > minkowski(){}
>>
>> not to throw an error. And
>>
>>
>> > minkowski(){
>> > cube[a,b,c];
>> > };
>>
>> to have cube[a,b,c] as unchanged result, instead of getting a not-defined
>> error. Same applies for intersection(), union() and so on.
>>
>> Second, I would not want any shape evaluating to empty to eat up
>> everthing.
>>
>>
>> > minkowski(){
>> > A();
>> > B();
>> > C();
>> > ...
>> > }
>>
>> Imagine C() is not defined (missing library) and a warning is issued.
>> Should
>> the result then be empty? For what? For mathematical correctness?
>>
>>
>>
>>
>>
>> --
>> View this message in context:
>> Sent from the OpenSCAD mailing list archive at Nabble.com.
>>
>> _______________________________________________
>>
>
>
> _______________________________________________