Haskell-Things / ImplicitCAD

A math-inspired CAD program in haskell. CSG, bevels, and shells; 2D & 3D geometry; 2D gcode generation...
https://implicitcad.org/
GNU Affero General Public License v3.0
1.41k stars 142 forks source link

Object formed by extrusion is not solid #412

Closed nrnrnr closed 10 months ago

nrnrnr commented 2 years ago

I've defined objects using the following code (complete code in attachments):

test_shape :: ℝ -> SymbolicObj2
test_shape k =
    intersect
    [ implicit (shape k circle_diameter_bottom (twice circle_height))
                   ((-9, -5), (9, 10))
    , rectR 0 (-15, 0) (15, 25)
    ]

test_solid :: ℝ -> SymbolicObj3
test_solid k = extrudeR 0.0 (test_shape k) 7

When I render the two-dimensional test_shape as a PNG, it shows as a solid rectangle with a semicircular bite taken out of it, as expected. But when that shape is extruded into a solid and written as an STL, the resulting STL isn't solid; it's just a bunch of surfaces glued together.

The documentation for the Haskell API is a bit thin, so I'm not sure if there is a fault in the library or if I just don't understand the API. If it's an API misunderstanding, perhaps we can clear it up and I'll send you a PR with revised documentation?

Here is a zip file with the complete source code and the output STL

sorki commented 2 years ago

I've updated your code to work with most recent version and managed to reproduce the problem. I think it is a bug but it's not clear to me what is causing it.

Updated code and pics following:

module Main
where

import Prelude
import Graphics.Implicit
import Graphics.Implicit.Definitions

circle_diameter_bottom = 14.80 -- mm
circle_height = 9.86

root :: ℝ -> ℝ -> ℝ
root n x = x ** (1/n)

shape n width height (V2 x y) =
    1 - root n ((x / half width) ** n + (y / half height) ** n)

half k = k / 2
twice k = 2 * k

test_shape :: ℝ -> SymbolicObj2
test_shape k =
    intersect
    [ implicit
        (shape k circle_diameter_bottom (twice circle_height))
        (V2 (-9) (-5), V2 9 10)
    , rect (V2 (-15) 0) (V2 15 25)
    ]

test_solid :: ℝ -> SymbolicObj3
test_solid k = extrude (test_shape k) 7

main :: IO ()
main = do
  writePNG2 0.5 "test.png" $ test_shape 2
  writeSVG 0.5 "test.svg" $ test_shape 2
  writeSTL 0.5 "test.stl" $ test_solid 2

test test test00

nrnrnr commented 2 years ago

OK. Thanks for having a look. I'll sit tight.

lepsa commented 1 year ago

The SVG not having lines for the top or sides is making me think that something is going wrong somewhere at the 2D level, and it might not be an extrusion issue. I'll have a bit of a poke around and see if I can find anything.

lepsa commented 1 year ago

OK, so I have a finding, and some reasoning as to why we are seeing the missing edges, and a work around for now.

Background The implicit shape function is trying to generate an infinite plane except for the curve in the middle. This can be seen by just rendering the implicit function with a large bounding box. It'll always draw more. The problem seems to lie in the bounding box for this infinite plane.

Workaround Setting the bounding box to (pure (-infty), pure infty) allows the shape to properly render the intersection, showing the rest of the rectangle.

Thoughts From some quick experiments, I think that this will happen whenever the bounding box for an infinite surface doesn't entirely contain the bounding boxes for finite surfaces. I suspect that this is because when the intersection of the boxes is taken, the new bounding box is inside what should be considered solid. The effect of this is that when the bounding box is reached for rendering, nothing more is done and an edge can't be drawn because the implicit functions haven't indicated that one should exist at that position.

As to why the 2D render is showing the bounding box as solid, while the SVG and 3D render aren't I suspect either a bug somewhere in the render for 2D STL or that STL itself is using the bounding box of the render as implicit edges and filling in the gaps. I haven't looked into if this is the case or not however.

Followup

@julialongtin I'll probably need to pick your brains about the rendering code if I dig into this more, consider this a heads up.

image