sdf

package module
v0.0.0-...-6596a10 Latest Latest
Warning

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

Go to latest
Published: Aug 12, 2024 License: MIT Imports: 8 Imported by: 4

README

Go Report Card GoDoc

⚠️ ARCHIVED ⚠️

Development has moved to https://github.com/soypat/gsdf.

This project has been archived in favor of developing a more advanced solution. gsdf redesigns APIs to be vectorised speeding things up considerably and enabling usage of GPU which enables real-time visualization of shapes with infinite detail (no triangle rendering step required).

Most functionality in sdf has already been reimplemented at the time of archiving. Feel free to ask questions in the issue tracker!

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.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

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 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) Bounds

func (s *CutSDF2) Bounds() r2.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(n int, k float64) MaxFunc

MaxPoly creates a n-degree polynomial MaxFunc with parameter k that controls radius of the smoothing function. Implementation untested.

type MinFunc

type MinFunc func(a, b float64) float64

MinFunc is a minimum functions for SDF blending.

func MinExp

func MinExp(k float64) MinFunc

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

func MinPoly

func MinPoly(n int, k float64) MinFunc

MinPoly creates a n-degree polynomial MinFunc with parameter k that controls radius of the smoothing function.

  • n<0 or k<=0 undefined output
  • n=0 returns a chamfer-like MinFunc
  • n=1 returns math.Min

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 takes a point in 2D space as input and returns
	// the minimum distance of the SDF2 to the point. The distance
	// is negative if the point is contained within the SDF3.
	Evaluate(p r2.Vec) float64

	// Bounds returns the bounding box that completely contains the SDF2.
	Bounds() r2.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 takes a point in 3D space as input and returns
	// the minimum distance of the SDF3 to the point. The distance
	// is negative if the point is contained within the SDF3.
	Evaluate(p r3.Vec) float64
	// Bounds returns the bounding box that completely contains
	// the SDF3.
	Bounds() r3.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) Bounds

func (s *ScaleUniformSDF2) Bounds() r2.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) Bounds

func (s *TransformSDF2) Bounds() r2.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.

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

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

Jump to

Keyboard shortcuts

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