Coder Social home page Coder Social logo

soypat / sdf Goto Github PK

View Code? Open in Web Editor NEW
89.0 4.0 9.0 1.14 MB

A Go library for signed distance function shape generation. Read as 3D printing shape design.

License: MIT License

Go 100.00%
3d-models 3d-printing cad go golang mesh-generation sdf signed-distance-functions stl

sdf's Introduction

Go Report Card GoDoc

sdf (originally sdfx)

A rewrite of the original Signed Distance Function CAD package sdfx for generating 2D and 3D geometry using Go.

Highlights

  • GUI with real-time rendering using sdf3ui (or SDF Viewer).
  • 3d and 2d objects modelled with signed distance functions (SDFs).
  • Minimal and idiomatic API.
  • Render objects as triangles or save to STL, 3MF(experimental) file format.
  • End-to-end testing using image comparison.
  • must and form packages provide panicking and normal error handling basic shape generation APIs for different scenarios.
  • Dead-simple, single method Renderer interface.
  • Import mesh files: Edit STL and 3MF files as if they were native SDFs using sdfexp.ImportModel
  • Tetrahedron mesher: Measure volume or create physics models of your shapes using sdfexp.UniformTetrahedronMesh. Experimental feature. Example result image.

Examples

For real-world examples with images see examples directory README.

See images of rendered shapes in render/testdata.

Here is a rendered bolt from one of the unit tests under form3_test.go renderedBolt

Roadmap

  • Clean up thread API mess
  • Add a 2D renderer and it's respective Renderer2 interface.
  • Make 3D renderer multicore

Comparison

deadsy/sdfx

Advantages of deadsy/sdfx:

  • Widely used
  • More helper functions
  • Working 2D renderer

Advantages of soypat/sdf:

  • Very fast rendering
    • deadsy/sdfx is over 2 times slower and has ~5 times more allocations.
  • Minimal and idiomatic API
  • Renderer interface is dead-simple, idiomatic Go and not limited to SDFs
    • deadsy/sdfx Renderer3 interface has filled render package with technical debt.
  • Has SDFUnion and SDFDiff interfaces for blending shapes easily
    • MinPoly redesign to allow for n-degree polynomials. Also returns a sensible "undefined output" MinFunc before dividing by zero.
  • No nil valued SDFs
    • deadsy/sdfx internally makes use of nil SDFs as "empty" objects. This can later cause panics during rendering well after the point of failure causing hard to debug issues.
  • Well defined package organization.
    • deadsy/sdfx dumps helper and utility functions in sdf
  • End-to-end tested.
    • Ensures functioning renderer and SDF functions using image comparison preventing accidental changes.
  • Error-free API under must3 and must2 packages for makers.
    • For simple projects these packages allow for streamlined error handling process using panic instead of returned errors.
    • deadsy/sdfx only allows for Go-style error handling like the form3 and form2 packages.
  • Sound use of math package for best precision and overflow prevention.
    • math.Hypot used for all length calculations. deadsy/sdfx does not use math.Hypot.
  • Uses gonum's spatial package
    • sdfx has own vector types with methods which hurt code legibility
    • spatial types from gonum library with correct Triangle degeneracy calculation. deadsy/sdfx's Degenerate calculation is incorrect.
  • Idiomatic thread package. Define arbitrary threads with ease using Threader interface.
    • deadsy/sdfx defines threads with strings i.e. "M16x2". sdf Defines threads with types corresponding to standards. i.e: thread.ISO{D:16, P:2}, which defines an M16x2 ISO thread.

Contributing

See CONTRIBUTING.

Why was sdfx rewritten?

The original sdfx package is amazing. I thank deadsy for putting all that great work into making an amazing tool I use daily. That said, there are some things that were not compatible with my needs:

Rendering speed

Here is a benchmark rendering a threaded bolt:

$ go test -benchmem -run=^$ -bench ^(BenchmarkSDFXBolt|BenchmarkBolt)$ ./render
goos: linux
goarch: amd64
pkg: github.com/soypat/sdf/render
cpu: AMD Ryzen 5 3400G with Radeon Vega Graphics    
BenchmarkSDFXBolt-8   	       6	 196941244 ns/op	14700786 B/op	   98261 allocs/op
BenchmarkBolt-8       	      13	  87547265 ns/op	18136785 B/op	   20754 allocs/op
PASS
ok  	github.com/soypat/sdf/render	4.390s

BenchmarkBolt-8 is this implementation of Octree. BenchmarkSDFXBolt-8 is the sdfx implementation of said algorithm.

Unwieldy API design

The vector math functions are methods which yield hard to follow operations. i.e:

return bb.Min.Add(bb.Size().Mul(i.ToV3().DivScalar(float64(node.meshSize)).
    Div(node.cellCounts.ToV3().DivScalar(float64(node.meshSize))))) // actual code from original sdfx.

A more pressing issue was the Renderer3 interface definition method, Render

type Renderer3 interface {
    // ...
    Render(s sdf.SDF3, meshCells int, output chan<- *Triangle3)
}

This presented a few problems:

  1. Raises many questions about usage of the function Render- who closes the channel? Does this function block? Do I have to call it as a goroutine?

  2. To implement a renderer one needs to bake in concurrency which is a hard thing to get right from the start. This also means all rendering code besides having the responsibility of computing geometry, it also has to handle concurrency features of the language. This leads to rendering functions with dual responsibility- compute geometry and also handle the multi-core aspect of the computation making code harder to maintain in the long run

  3. Using a channel to send individual triangles is probably a bottleneck.

  4. I would liken meshCells to an implementation detail of the renderer used. This can be passed as an argument when instantiating the renderer used.

  5. Who's to say we have to limit ourselves to signed distance functions? With the new proposed Renderer interface this is no longer the case.

sdf and sdfx consolidation

None planned.

Logo work

Gopher rendition by Juliette Whittingslow.
Gopher design authored by Renée French is licensed by the Creative Commons Attribution 3.0 licensed.

sdf's People

Contributors

cactorium avatar soypat avatar yeicor avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

sdf's Issues

Importing STL files shows all sorts of artifacts

Importing the HeartGears2-3.stl file from here:

https://www.thingiverse.com/thing:243278/files

using this code, has lots of artifacts, and holes in the outputed stl file.

package main 
 
import ( 
    "github.com/hschendel/stl" 
    "github.com/soypat/sdf/helpers/sdfexp" 
    "github.com/soypat/sdf/render" 
) 
 
func main() { 
 
    solid, err := stl.ReadFile("HeartGears2-3.stl") 
    if err != nil { 
        panic(err) 
    } 
 
    tris := make([]render.Triangle3, len(solid.Triangles)) 
 
    for i, t := range solid.Triangles { 
        for k := 0; k < 3; k++ { 
            tris[i][k].X = float64(t.Vertices[k][0]) 
            tris[i][k].Y = float64(t.Vertices[k][1]) 
            tris[i][k].Z = float64(t.Vertices[k][2]) 
        } 
    } 
 
    object, err := sdfexp.ImportModel(tris, 0) 
    if err != nil { 
        panic(err) 
    } 
 
    err = render.CreateSTL("out.stl", render.NewOctreeRenderer(object, 500)) 
    if err != nil { 
        panic(err)
    }
            
} 

Composite literal uses unkeyed fields

Hi Patricio
I agree with the way you are doing the SDF function types as I was wrapping the SDFX functions to get the same effect. I am having a go at porting sdfx-ui to using sdf.

I am using go 1.18 and go vet complains about composite literal using unkeyed fields.

So I am testing adding
// New func to replace composite literal construction with unkeyed fields
func NewV2(x, y float64) r2.Vec {
return r2.Vec{X: x, Y: y}
}
to vector.gox`x

So the code changes (example of old and new):
v[1] = NewV2(a.Max.X, a.Min.Y) // br
v[2] = r2.Vec{a.Min.X, a.Max.Y} // tl

If you think it is a good idea I will try and create pull request when I am done.

Breaking changes: `Box` and `Triangle` types replaced with gonum types

Breaking changes are incoming as soon as gonum/gonum#1791 is resolved. This would replace the d3.Box, render.Triangle3 and d2.Box types with their respective gonum types.

Box change

This change would allow users to work with the Box types freely in their code. As of now the Box types are hidden behind an internal wall which makes them invalid for use in external code.

Triangle change

The Triangle type would further decouple the render package and make the Renderer interface more flexible and dependable as the Triangle type would be tied to a solid, trusted and tested library.

Replace Matrix types with gonum Transform

When gonum/gonum#1797 is accepted this can be discussed and implemented.

  • Replace sdf.m44 with r3.Transform
  • Replace sdf.m33 with r2.Transform

This should not be a breaking change for anyone who has not been using sdf.m44 and sdf.m33 types for anything other than the sdf.Transform3D and sdf.Transform2D functions.

Can't build by adding github.com/soypat/sdf

While cloning this entire repo and building everything including examples works, starting with a new project and trying to reference soypat/sdf does not. It gives build errors. Following similar steps with sdfx do work but not in sdf. To reproduce:

  1. mkdir myexample
  2. cd myexample
  3. go mod init github.com/me/myexample
  4. Create a file with the contents of one of the example go files from soypat/sdf/examples
  5. go mod tidy
  6. go build

The following output comes from the build:

# github.com/soypat/sdf/internal/d2
../../go/pkg/mod/github.com/soypat/[email protected]/internal/d2/box.go:16:20: center.Sub undefined (type r2.Vec has no field or method Sub)
../../go/pkg/mod/github.com/soypat/[email protected]/internal/d2/box.go:16:38: center.Add undefined (type r2.Vec has no field or method Add)
../../go/pkg/mod/github.com/soypat/[email protected]/internal/d2/box.go:39:19: a.Min.Add undefined (type r2.Vec has no field or method Add)
../../go/pkg/mod/github.com/soypat/[email protected]/internal/d2/box.go:39:33: a.Max.Add undefined (type r2.Vec has no field or method Add)
../../go/pkg/mod/github.com/soypat/[email protected]/internal/d2/box.go:44:15: a.Max.Sub undefined (type r2.Vec has no field or method Sub)
../../go/pkg/mod/github.com/soypat/[email protected]/internal/d2/box.go:49:15: a.Min.Add undefined (type r2.Vec has no field or method Add)
../../go/pkg/mod/github.com/soypat/[email protected]/internal/d2/box.go:62:19: a.Min.Sub undefined (type r2.Vec has no field or method Sub)
../../go/pkg/mod/github.com/soypat/[email protected]/internal/d2/box.go:62:33: a.Max.Add undefined (type r2.Vec has no field or method Add)
../../go/pkg/mod/github.com/soypat/[email protected]/internal/d2/transform.go:106:12: xa.Add undefined (type r2.Vec has no field or method Add)
../../go/pkg/mod/github.com/soypat/[email protected]/internal/d2/transform.go:107:12: xb.Add undefined (type r2.Vec has no field or method Add)
../../go/pkg/mod/github.com/soypat/[email protected]/internal/d2/transform.go:107:12: too many errors
# github.com/soypat/sdf/internal/d3
../../go/pkg/mod/github.com/soypat/[email protected]/internal/d3/box.go:50:19: a.Min.Add undefined (type r3.Vec has no field or method Add)
../../go/pkg/mod/github.com/soypat/[email protected]/internal/d3/box.go:50:33: a.Max.Add undefined (type r3.Vec has no field or method Add)
../../go/pkg/mod/github.com/soypat/[email protected]/internal/d3/box.go:55:15: a.Max.Sub undefined (type r3.Vec has no field or method Sub)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.