sdf

package module
v0.1.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 7, 2022 License: MIT Imports: 7 Imported by: 0

README

Go Report Card GoDoc

sdf (originally sdfx)

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

  • Objects are modelled with 2d and 3d signed distance functions (SDFs).
  • Objects are defined with Go code.
  • Objects are rendered to an STL file to be viewed and/or 3d printed.

Highlights

  • 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.

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

  • 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 drummonds/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
  • Has SDFUnion and SDFDiff interfaces for blending shapes easily
  • 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

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:

Performance

sdfx is needlessly slow. Here is a benchmark rendering a threaded bolt:

$ go test -benchmem -run=^$ -bench ^(BenchmarkSDFXBolt|BenchmarkBolt)$ ./render
goos: linux
goarch: amd64
pkg: github.com/drummonds/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/drummonds/sdf/render	4.390s

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

Questionable 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.

My understanding is the sdfx author has a very different design goal to what I envision. See the bullet-list of issues at the start of Questionable API design.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GenerateMesh2D

func GenerateMesh2D(s SDF2, grid V2i) (d2.Set, error)

GenerateMesh2D generates a set of internal mesh points for an SDF2.

func Identity

func Identity() m22

Identity returns a 2x2 identity matrix.

func Identity2d

func Identity2d() m33

Identity2d returns a 3x3 identity matrix.

func Identity3d

func Identity3d() m44

Identity3d returns a 4x4 identity matrix.

func MirrorX

func MirrorX() m33

MirrorX returns a 3x3 matrix with mirroring across the X axis.

func MirrorXY

func MirrorXY() m44

MirrorXY returns a 4x4 matrix with mirroring across the XY plane.

func MirrorXZ

func MirrorXZ() m44

MirrorXZ returns a 4x4 matrix with mirroring across the XZ plane.

func MirrorXeqY

func MirrorXeqY() m44

MirrorXeqY returns a 4x4 matrix with mirroring across the X == Y plane.

func MirrorY

func MirrorY() m33

MirrorY returns a 3x3 matrix with mirroring across the Y axis.

func MirrorYZ

func MirrorYZ() m44

MirrorYZ returns a 4x4 matrix with mirroring across the YZ plane.

func MulVertices2

func MulVertices2(v d2.Set, a m33)

MulVertices multiples a set of V2 vertices by a rotate/translate matrix.

func MulVertices3

func MulVertices3(v d3.Set, a m44)

MulVertices multiples a set of r3.Vec vertices by a rotate/translate matrix.

func NormalExtrude

func NormalExtrude(p r3.Vec) r2.Vec

NormalExtrude returns an extrusion function.

func R2FromI deprecated

func R2FromI(a V2i) r2.Vec

R2FromI temporary home for this function.

Deprecated: R2FromI is deprecated.

func R3FromI deprecated

func R3FromI(a V3i) r3.Vec

R3FromI temporary home for this function.

Deprecated: R3FromI is deprecated.

func Rotate

func Rotate(a float64) m22

Rotate returns an orthographic 2x2 rotation matrix (right hand rule).

func Rotate2d

func Rotate2d(a float64) m33

Rotate2d returns an orthographic 3x3 rotation matrix (right hand rule).

func Rotate3d

func Rotate3d(v r3.Vec, a float64) m44

Rotate3d returns an orthographic 4x4 rotation matrix (right hand rule).

func RotateX

func RotateX(a float64) m44

RotateX returns a 4x4 matrix with rotation about the X axis.

func RotateY

func RotateY(a float64) m44

RotateY returns a 4x4 matrix with rotation about the Y axis.

func RotateZ

func RotateZ(a float64) m44

RotateZ returns a 4x4 matrix with rotation about the Z axis.

func Scale2d

func Scale2d(v r2.Vec) m33

Scale2d returns a 3x3 scaling matrix. Scaling does not preserve distance. See: ScaleUniform2D().

func Scale3d

func Scale3d(v r3.Vec) m44

Scale3d returns a 4x4 scaling matrix. Scaling does not preserve distance. See: ScaleUniform3D()

func Translate2d

func Translate2d(v r2.Vec) m33

Translate2d returns a 3x3 translation matrix.

func Translate3D

func Translate3D(v r3.Vec) m44

Translate3D returns a 4x4 translation matrix.

Types

type CutSDF2

type CutSDF2 struct {
	// contains filtered or unexported fields
}

CutSDF2 is an SDF2 made by cutting across an existing SDF2.

func (*CutSDF2) BoundingBox

func (s *CutSDF2) BoundingBox() d2.Box

BoundingBox returns the bounding box for the cut SDF2.

func (*CutSDF2) Evaluate

func (s *CutSDF2) Evaluate(p r2.Vec) float64

Evaluate returns the minimum distance to cut SDF2.

type ExtrudeFunc

type ExtrudeFunc func(p r3.Vec) r2.Vec

ExtrudeFunc maps r3.Vec to V2 - the point used to evaluate the SDF2.

func ScaleExtrude

func ScaleExtrude(height float64, scale r2.Vec) ExtrudeFunc

ScaleExtrude returns an extrusion functions that scales with z.

func ScaleTwistExtrude

func ScaleTwistExtrude(height, twist float64, scale r2.Vec) ExtrudeFunc

ScaleTwistExtrude returns an extrusion function that scales and twists with z.

func TwistExtrude

func TwistExtrude(height, twist float64) ExtrudeFunc

TwistExtrude returns an extrusion function that twists with z.

type MaxFunc

type MaxFunc func(a, b float64) float64

MaxFunc is a maximum function for SDF blending.

func MaxPoly

func MaxPoly(k float64) MaxFunc

MaxPoly returns a maximum function (Try k = 0.1, a bigger k gives a bigger fillet).

type MinFunc

type MinFunc func(a, b float64) float64

MinFunc is a minimum functions for SDF blending.

func MinChamfer

func MinChamfer(k float64) MinFunc

MinChamfer returns a minimum function that makes a 45-degree chamfered edge (the diagonal of a square of size <r>). TODO: why the holes in the rendering?

func MinExp

func MinExp(k float64) MinFunc

MinExp returns a minimum function with exponential smoothing (k = 32).

func MinPoly

func MinPoly(k float64) MinFunc

MinPoly returns a minimum function (Try k = 0.1, a bigger k gives a bigger fillet).

func MinPow

func MinPow(k float64) MinFunc

MinPow returns a minimum function (k = 8). TODO - weird results, is this correct?

func MinRound

func MinRound(k float64) MinFunc

MinRound returns a minimum function that uses a quarter-circle to join the two objects smoothly.

type SDF2

type SDF2 interface {
	Evaluate(p r2.Vec) float64
	BoundingBox() d2.Box
}

SDF2 is the interface to a 2d signed distance function object.

func Center2D

func Center2D(s SDF2) SDF2

Center2D centers the origin of an SDF2 on it's bounding box.

func CenterAndScale2D

func CenterAndScale2D(s SDF2, k float64) SDF2

CenterAndScale2D centers the origin of an SDF2 on it's bounding box, and then scales it. Distance is correct with scaling.

func Cut2D

func Cut2D(sdf SDF2, a, v r2.Vec) SDF2

Cut2D cuts the SDF2 along a line from a in direction v. The SDF2 to the right of the line remains.

func Elongate2D

func Elongate2D(sdf SDF2, h r2.Vec) SDF2

Elongate2D returns the elongation of an SDF2.

func LineOf2D

func LineOf2D(s SDF2, p0, p1 r2.Vec, pattern string) SDF2

LineOf2D returns a union of 2D objects positioned along a line from p0 to p1.

func Multi2D

func Multi2D(s SDF2, positions d2.Set) SDF2

Multi2D creates a union of an SDF2 at a set of 2D positions.

func Offset2D

func Offset2D(sdf SDF2, offset float64) SDF2

Offset2D returns an SDF2 that offsets the distance function of another SDF2.

func RotateCopy2D

func RotateCopy2D(sdf SDF2, n int) SDF2

RotateCopy2D rotates and copies an SDF2 n times in a full circle.

func RotateUnion2D

func RotateUnion2D(sdf SDF2, num int, step m33) SDF2

RotateUnion2D returns a union of rotated SDF2s.

func ScaleUniform2D

func ScaleUniform2D(sdf SDF2, k float64) SDF2

ScaleUniform2D scales an SDF2 by k on each axis. Distance is correct with scaling.

func Slice2D

func Slice2D(sdf SDF3, a, n r3.Vec) SDF2

Slice2D returns an SDF2 created from a planar slice through an SDF3. a is point on slicing plane, n is normal to slicing plane

func Transform2D

func Transform2D(sdf SDF2, m m33) SDF2

Transform2D applies a transformation matrix to an SDF2. Distance is *not* preserved with scaling.

type SDF2Diff

type SDF2Diff interface {
	SDF2
	SetMax(MaxFunc)
}

func Difference2D

func Difference2D(s0, s1 SDF2) SDF2Diff

Difference2D returns the difference of two SDF2 objects, s0 - s1.

func Intersect2D

func Intersect2D(s0, s1 SDF2) SDF2Diff

Intersect2D returns the intersection of two SDF2s.

type SDF2Union

type SDF2Union interface {
	SDF2
	SetMin(MinFunc)
}

func Array2D

func Array2D(sdf SDF2, num V2i, step r2.Vec) SDF2Union

Array2D returns an XY grid array of an existing SDF2.

func Union2D

func Union2D(sdf ...SDF2) SDF2Union

Union2D returns the union of multiple SDF2 objects.

type SDF3

type SDF3 interface {
	Evaluate(p r3.Vec) float64
	BoundingBox() d3.Box
}

SDF3 is the interface to a 3d signed distance function object.

func Cut3D

func Cut3D(sdf SDF3, a, n r3.Vec) SDF3

Cut3D cuts an SDF3 along a plane passing through a with normal n. The SDF3 on the same side as the normal remains.

func Elongate3D

func Elongate3D(sdf SDF3, h r3.Vec) SDF3

Elongate3D returns the elongation of an SDF3.

func Extrude3D

func Extrude3D(sdf SDF2, height float64) SDF3

Extrude3D does a linear extrude on an SDF3.

func ExtrudeRounded3D

func ExtrudeRounded3D(sdf SDF2, height, round float64) SDF3

ExtrudeRounded3D extrudes an SDF2 to an SDF3 with rounded edges.

func LineOf3D

func LineOf3D(s SDF3, p0, p1 r3.Vec, pattern string) SDF3

LineOf3D returns a union of 3D objects positioned along a line from p0 to p1.

func Loft3D

func Loft3D(sdf0, sdf1 SDF2, height, round float64) SDF3

Loft3D extrudes an SDF3 that transitions between two SDF2 shapes.

func Multi3D

func Multi3D(s SDF3, positions d3.Set) SDF3

Multi3D creates a union of an SDF3 at translated positions.

func Offset3D

func Offset3D(sdf SDF3, offset float64) SDF3

Offset3D returns an SDF3 that offsets the distance function of another SDF3.

func Orient3D

func Orient3D(s SDF3, base r3.Vec, directions d3.Set) SDF3

Orient3D creates a union of an SDF3 at oriented directions.

func Revolve3D

func Revolve3D(sdf SDF2, theta float64) SDF3

Revolve3D returns an SDF3 for a solid of revolution. theta is in radians. For a full revolution call

Revolve3D(s0, 2*math.Pi)

func RotateCopy3D

func RotateCopy3D(sdf SDF3, num int) SDF3

RotateCopy3D rotates and creates N copies of an SDF3 about the z-axis. num is the number of copies.

func ScaleExtrude3D

func ScaleExtrude3D(sdf SDF2, height float64, scale r2.Vec) SDF3

ScaleExtrude3D extrudes an SDF2 and scales it over the height of the extrusion.

func ScaleTwistExtrude3D

func ScaleTwistExtrude3D(sdf SDF2, height, twist float64, scale r2.Vec) SDF3

ScaleTwistExtrude3D extrudes an SDF2 and scales and twists it over the height of the extrusion.

func ScaleUniform3D

func ScaleUniform3D(sdf SDF3, k float64) SDF3

ScaleUniform3D uniformly scales an SDF3 on all axes.

func Shell3D

func Shell3D(sdf SDF3, thickness float64) SDF3

Shell3D returns an SDF3 that shells the surface of an existing SDF3.

func Transform3D

func Transform3D(sdf SDF3, matrix m44) SDF3

Transform3D applies a transformation matrix to an SDF3.

func TwistExtrude3D

func TwistExtrude3D(sdf SDF2, height, twist float64) SDF3

TwistExtrude3D extrudes an SDF2 while rotating by twist radians over the height of the extrusion.

type SDF3Diff

type SDF3Diff interface {
	SDF3
	SetMax(MaxFunc)
}

func Difference3D

func Difference3D(s0, s1 SDF3) SDF3Diff

Difference3D returns the difference of two SDF3s, s0 - s1. Difference3D will panic if one any of the arguments is nil.

func Intersect3D

func Intersect3D(s0, s1 SDF3) SDF3Diff

Intersect3D returns the intersection of two SDF3s. Intersect3D will panic if any of the arguments are nil.

type SDF3Union

type SDF3Union interface {
	SDF3
	SetMin(MinFunc)
}

func Array3D

func Array3D(sdf SDF3, num V3i, step r3.Vec) SDF3Union

Array3D returns an XYZ array of a given SDF3

func RotateUnion3D

func RotateUnion3D(sdf SDF3, num int, step m44) SDF3Union

RotateUnion3D creates a union of SDF3s rotated about the z-axis. num is the number of copies.

func Union3D

func Union3D(sdf ...SDF3) SDF3Union

Union3D returns the union of multiple SDF3 objects. Union3D will panic if arguments list is empty or if an argument SDF3 is nil.

type ScaleUniformSDF2

type ScaleUniformSDF2 struct {
	// contains filtered or unexported fields
}

ScaleUniformSDF2 scales another SDF2 on each axis.

func (*ScaleUniformSDF2) BoundingBox

func (s *ScaleUniformSDF2) BoundingBox() d2.Box

BoundingBox returns the bounding box of an SDF2 with uniform scaling.

func (*ScaleUniformSDF2) Evaluate

func (s *ScaleUniformSDF2) Evaluate(p r2.Vec) float64

Evaluate returns the minimum distance to an SDF2 with uniform scaling.

type TransformSDF2

type TransformSDF2 struct {
	// contains filtered or unexported fields
}

TransformSDF2 transorms an SDF2 with rotation, translation and scaling.

func (*TransformSDF2) BoundingBox

func (s *TransformSDF2) BoundingBox() d2.Box

BoundingBox returns the bounding box of a transformed SDF2.

func (*TransformSDF2) Evaluate

func (s *TransformSDF2) Evaluate(p r2.Vec) float64

Evaluate returns the minimum distance to a transformed SDF2. Distance is *not* preserved with scaling.

type V2i

type V2i [2]int

V2i is a 2D integer vector.

func R2ToI deprecated

func R2ToI(a r2.Vec) V2i

R2ToI temporary home for this function.

Deprecated: R2ToI is deprecated.

func (V2i) Add

func (a V2i) Add(b V2i) V2i

Add adds two vectors. Return v = a + b.

func (V2i) AddScalar

func (a V2i) AddScalar(b int) V2i

AddScalar adds a scalar to each component of the vector.

func (V2i) SubScalar

func (a V2i) SubScalar(b int) V2i

SubScalar subtracts a scalar from each component of the vector.

func (V2i) ToV3

func (a V2i) ToV3(newZ float64) r3.Vec

ToV3.Vec converts V2i (integer) to r3.Vec (float).

type V3i

type V3i [3]int

V3i is a 3D integer vector.

func R3ToI deprecated

func R3ToI(a r3.Vec) V3i

R3ToI temporary home for this function.

Deprecated: R3ToI is deprecated.

func (V3i) Add

func (a V3i) Add(b V3i) V3i

Add adds two vectors. Return v = a + b.

func (V3i) AddScalar

func (a V3i) AddScalar(b int) V3i

AddScalar adds a scalar to each component of the vector.

func (V3i) SubScalar

func (a V3i) SubScalar(b int) V3i

SubScalar subtracts a scalar from each component of the vector.

func (V3i) ToV3

func (a V3i) ToV3() r3.Vec

ToV3.Vec converts V3i (integer) to r3.Vec (float).

Directories

Path Synopsis
helpers
internal
d2
d3

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL