diff --git a/examples/atx-bench-supply/atx.go b/examples/atx-bench-supply/atx.go index ee50be4..5c8408f 100644 --- a/examples/atx-bench-supply/atx.go +++ b/examples/atx-bench-supply/atx.go @@ -59,14 +59,14 @@ func main() { // Begin working on regulated step-down block regOut = sdf.Array2D(bananaPlugSmall, sdf.V2i{2, 1}, r2.Vec{bananaSpacing, bananaSpacing}) - bplugX := regOut.BoundingBox().Size().X + bplugX := bbSize(regBlock.Bounds()).X vDisp := sdf.Transform2D(voltageDisplay, sdf.Translate2d(r2.Vec{bplugX / 2, vDispH/2 + bananaSpacing/2})) regOut = sdf.Union2D(regOut, vDisp) regOut = sdf.Transform2D(regOut, sdf.Translate2d(r2.Vec{-atxW/2 - bplugX/2 + vDispW/2 + 12, atxH/2 - 12 - vDispH/2 - bananaSpacing})) // Create mound for step up outputs. - regSz := regOut.BoundingBox().Size() + regSz := bbSize(regBlock.Bounds()) regBlock = form2.Box(r2.Vec{regSz.X + regBlockMargin, regSz.Y + regBlockMargin}, regBlockMargin/2) - regBlock = sdf.Transform2D(regBlock, sdf.Translate2d(regOut.BoundingBox().Center())) + regBlock = sdf.Transform2D(regBlock, sdf.Translate2d(bbCenter(regOut.Bounds()))) regBlock = sdf.Difference2D(regBlock, regOut) regBlock3 := sdf.Extrude3D(regBlock, panelThickness+regBlockDepth) // extrude does it both ways. regBlock3 = sdf.Transform3D(regBlock3, sdf.Translate3D(r3.Vec{0, 0, regBlockDepth / 2})) @@ -96,3 +96,11 @@ func must(err error) { panic(err) } } + +func bbSize(bb r2.Box) r2.Vec { + return r2.Sub(bb.Max, bb.Min) +} + +func bbCenter(bb r2.Box) r2.Vec { + return r2.Add(bb.Min, r2.Scale(0.5, bbSize(bb))) +} diff --git a/form2/must2/basic.go b/form2/must2/basic.go index f635a04..8a258a1 100644 --- a/form2/must2/basic.go +++ b/form2/must2/basic.go @@ -10,7 +10,7 @@ import ( // circle is the 2d signed distance object for a circle. type circle struct { radius float64 - bb d2.Box + bb r2.Box } // Circle returns the SDF2 for a 2d circle. @@ -21,7 +21,7 @@ func Circle(radius float64) *circle { s := circle{} s.radius = radius d := r2.Vec{radius, radius} - s.bb = d2.Box{r2.Scale(-1, d), d} + s.bb = r2.Box{r2.Scale(-1, d), d} return &s } @@ -31,7 +31,7 @@ func (s *circle) Evaluate(p r2.Vec) float64 { } // BoundingBox returns the bounding box of a 2d circle. -func (s *circle) BoundingBox() d2.Box { +func (s *circle) BoundingBox() r2.Box { return s.bb } @@ -41,7 +41,7 @@ func (s *circle) BoundingBox() d2.Box { type box struct { size r2.Vec round float64 - bb d2.Box + bb r2.Box } // Box returns a 2d box. @@ -50,7 +50,7 @@ func Box(size r2.Vec, round float64) *box { s := box{} s.size = r2.Sub(size, d2.Elem(round)) s.round = round - s.bb = d2.Box{r2.Scale(-1, size), size} + s.bb = r2.Box{r2.Scale(-1, size), size} return &s } @@ -60,7 +60,7 @@ func (s *box) Evaluate(p r2.Vec) float64 { } // BoundingBox returns the bounding box for a 2d box. -func (s *box) BoundingBox() d2.Box { +func (s *box) BoundingBox() r2.Box { return s.bb } @@ -70,7 +70,7 @@ func (s *box) BoundingBox() d2.Box { type line struct { l float64 // line length round float64 // rounding - bb d2.Box // bounding box + bb r2.Box // bounding box } // Line returns a line from (-l/2,0) to (l/2,0). @@ -78,7 +78,7 @@ func Line(l, round float64) *line { s := line{} s.l = l / 2 s.round = round - s.bb = d2.Box{r2.Vec{-s.l - round, -round}, r2.Vec{s.l + round, round}} + s.bb = r2.Box{r2.Vec{-s.l - round, -round}, r2.Vec{s.l + round, round}} return &s } @@ -92,6 +92,6 @@ func (s *line) Evaluate(p r2.Vec) float64 { } // BoundingBox returns the bounding box for a 2d line. -func (s *line) BoundingBox() d2.Box { +func (s *line) BoundingBox() r2.Box { return s.bb } diff --git a/form2/must2/poly.go b/form2/must2/poly.go index 7bd2e78..45d5bf7 100644 --- a/form2/must2/poly.go +++ b/form2/must2/poly.go @@ -14,7 +14,7 @@ type polygon struct { vertex []r2.Vec // vertices vector []r2.Vec // unit line vectors length []float64 // line lengths - bb d2.Box // bounding box + bb r2.Box // bounding box } // Polygon returns an SDF2 made from a closed set of line segments. @@ -48,7 +48,7 @@ func Polygon(vertex []r2.Vec) sdf.SDF2 { vmax = d2.MaxElem(vmax, s.vertex[i]) } - s.bb = d2.Box{r2.Vec{vmin.X, vmin.Y}, r2.Vec{vmax.X, vmax.Y}} + s.bb = r2.Box{r2.Vec{vmin.X, vmin.Y}, r2.Vec{vmax.X, vmax.Y}} return &s } @@ -107,7 +107,7 @@ func (s *polygon) Evaluate(p r2.Vec) float64 { } // BoundingBox returns the bounding box of a 2d polygon. -func (s *polygon) BoundingBox() d2.Box { +func (s *polygon) BoundingBox() r2.Box { return s.bb } diff --git a/form3/must3/cylinders.go b/form3/must3/cylinders.go index dfe048f..ed11dba 100644 --- a/form3/must3/cylinders.go +++ b/form3/must3/cylinders.go @@ -14,7 +14,7 @@ import ( type box struct { size r3.Vec round float64 - bb d3.Box + bb r3.Box } // Box return an SDF3 for a 3d box (rounded corners with round > 0). @@ -30,7 +30,7 @@ func Box(size r3.Vec, round float64) *box { s := box{ size: r3.Sub(size, d3.Elem(round)), round: round, - bb: d3.Box{Min: r3.Scale(-1, size), Max: size}, + bb: r3.Box{Min: r3.Scale(-1, size), Max: size}, } return &s } @@ -41,7 +41,7 @@ func (s *box) Evaluate(p r3.Vec) float64 { } // BoundingBox returns the bounding box for a 3d box. -func (s *box) BoundingBox() d3.Box { +func (s *box) BoundingBox() r3.Box { return s.bb } @@ -50,7 +50,7 @@ func (s *box) BoundingBox() d3.Box { // sphere is a sphere. type sphere struct { radius float64 - bb d3.Box + bb r3.Box } // Sphere return an SDF3 for a sphere. @@ -61,7 +61,7 @@ func Sphere(radius float64) *sphere { d := r3.Vec{radius, radius, radius} s := sphere{ radius: radius, - bb: d3.Box{Min: r3.Scale(-1, d), Max: d}, + bb: r3.Box{Min: r3.Scale(-1, d), Max: d}, } return &s } @@ -72,7 +72,7 @@ func (s *sphere) Evaluate(p r3.Vec) float64 { } // BoundingBox returns the bounding box for a sphere. -func (s *sphere) BoundingBox() d3.Box { +func (s *sphere) BoundingBox() r3.Box { return s.bb } @@ -83,7 +83,7 @@ type cylinder struct { height float64 radius float64 round float64 - bb d3.Box + bb r3.Box } // Cylinder return an SDF3 for a cylinder (rounded edges with round > 0). @@ -105,7 +105,7 @@ func Cylinder(height, radius, round float64) *cylinder { s.radius = radius - round s.round = round d := r3.Vec{radius, radius, height / 2} - s.bb = d3.Box{r3.Scale(-1, d), d} + s.bb = r3.Box{r3.Scale(-1, d), d} return &s } @@ -121,7 +121,7 @@ func (s *cylinder) Evaluate(p r3.Vec) float64 { } // BoundingBox returns the bounding box for a cylinder. -func (s *cylinder) BoundingBox() d3.Box { +func (s *cylinder) BoundingBox() r3.Box { return s.bb } @@ -136,7 +136,7 @@ type cone struct { u r2.Vec // normalized cone slope vector n r2.Vec // normal to cone slope (points outward) l float64 // length of cone slope - bb d3.Box // bounding box + bb r3.Box // bounding box } // Cone returns the SDF3 for a trucated cone (round > 0 gives rounded edges). @@ -164,7 +164,7 @@ func Cone(height, r0, r1, round float64) *cone { s.l = r2.Norm(r2.Vec{s.r1, s.height}.Sub(r2.Vec{s.r0, -s.height})) // work out the bounding box r := math.Max(s.r0+round, s.r1+round) - s.bb = d3.Box{r3.Vec{-r, -r, -height / 2}, r3.Vec{r, r, height / 2}} + s.bb = r3.Box{r3.Vec{-r, -r, -height / 2}, r3.Vec{r, r, height / 2}} return &s } @@ -201,7 +201,7 @@ func (s *cone) Evaluate(p r3.Vec) float64 { } // BoundingBox return the bounding box for the trucated cone.. -func (s *cone) BoundingBox() d3.Box { +func (s *cone) BoundingBox() r3.Box { return s.bb } diff --git a/form3/must3/screw.go b/form3/must3/screw.go index 99542c6..6aa6340 100644 --- a/form3/must3/screw.go +++ b/form3/must3/screw.go @@ -4,7 +4,6 @@ import ( "math" "github.com/soypat/sdf" - "github.com/soypat/sdf/internal/d3" "gonum.org/v1/gonum/spatial/r2" "gonum.org/v1/gonum/spatial/r3" ) @@ -17,7 +16,7 @@ type screw struct { length float64 // total length of screw taper float64 // thread taper angle // starts int // number of thread starts - bb d3.Box // bounding box + bb r3.Box // bounding box } // Screw returns a screw SDF3. @@ -49,11 +48,11 @@ func Screw(thread sdf.SDF2, length float64, taper float64, pitch float64, starts s.lead = -pitch * float64(starts) // Work out the bounding box. // The max-y axis of the sdf2 bounding box is the radius of the thread. - bb := s.thread.BoundingBox() + bb := s.thread.Bounds() r := bb.Max.Y // add the taper increment r += s.length * math.Tan(taper) - s.bb = d3.Box{r3.Vec{X: -r, Y: -r, Z: -s.length}, r3.Vec{X: r, Y: r, Z: s.length}} + s.bb = r3.Box{r3.Vec{X: -r, Y: -r, Z: -s.length}, r3.Vec{X: r, Y: r, Z: s.length}} return &s } @@ -80,6 +79,6 @@ func (s *screw) Evaluate(p r3.Vec) float64 { } // BoundingBox returns the bounding box for a 3d screw form. -func (s *screw) BoundingBox() d3.Box { +func (s *screw) BoundingBox() r3.Box { return s.bb } diff --git a/internal/d2/box.go b/internal/d2/box.go index d749ac6..b2660a6 100644 --- a/internal/d2/box.go +++ b/internal/d2/box.go @@ -8,9 +8,7 @@ import ( ) // Box is a 2d bounding box. -type Box struct { - Min, Max r2.Vec -} +type Box r2.Box // NewBox2 creates a 2d box with a given center and size. func NewBox2(center, size r2.Vec) Box { diff --git a/internal/d3/box.go b/internal/d3/box.go index f74940d..a0b5344 100644 --- a/internal/d3/box.go +++ b/internal/d3/box.go @@ -8,9 +8,7 @@ import ( ) // d3.Box is a 3d bounding box. -type Box struct { - Min, Max r3.Vec -} +type Box r3.Box // Newd3.Box creates a 3d box with a given center and size. func NewBox(center, size r3.Vec) Box { diff --git a/matrix.go b/matrix.go index 0c8fd38..20deb56 100644 --- a/matrix.go +++ b/matrix.go @@ -397,7 +397,7 @@ func (a m44) MulPosition(b r3.Vec) r3.Vec { } // MulBox rotates/translates a 3d bounding box and resizes for axis-alignment. -func (a m44) MulBox(box d3.Box) d3.Box { +func (a m44) MulBox(box r3.Box) r3.Box { r := r3.Vec{X: a.x00, Y: a.x10, Z: a.x20} u := r3.Vec{X: a.x01, Y: a.x11, Z: a.x21} b := r3.Vec{X: a.x02, Y: a.x12, Z: a.x22} @@ -414,11 +414,11 @@ func (a m44) MulBox(box d3.Box) d3.Box { za, zb = d3.MinElem(za, zb), d3.MaxElem(za, zb) min := xa.Add(ya).Add(za).Add(t) max := xb.Add(yb).Add(zb).Add(t) - return d3.Box{min, max} + return r3.Box{min, max} } // MulBox rotates/translates a 2d bounding box and resizes for axis-alignment. -func (a m33) MulBox(box d2.Box) d2.Box { +func (a m33) MulBox(box r2.Box) r2.Box { r := r2.Vec{a.x00, a.x10} u := r2.Vec{a.x01, a.x11} t := r2.Vec{a.x02, a.x12} @@ -430,7 +430,7 @@ func (a m33) MulBox(box d2.Box) d2.Box { ya, yb = d2.MinElem(ya, yb), d2.MaxElem(ya, yb) min := xa.Add(ya).Add(t) max := xb.Add(yb).Add(t) - return d2.Box{min, max} + return r2.Box{min, max} } // Determinant returns the determinant of a 4x4 matrix. diff --git a/render/internal_test.go b/render/internal_test.go index 7e9aa5e..1230390 100644 --- a/render/internal_test.go +++ b/render/internal_test.go @@ -35,7 +35,7 @@ func TestSTLWriteReadback(t *testing.T) { TotalLength: 40., ShankLength: 10.0, }) - size := r3.Norm(s0.BoundingBox().Size()) + size := r3.Norm(d3.Box(s0.BoundingBox()).Size()) // calculate relative tolerance rtol := tol * size / quality input, err := RenderAll(NewOctreeRenderer(s0, quality)) diff --git a/render/kdrender.go b/render/kdrender.go index 87b978c..47dd655 100644 --- a/render/kdrender.go +++ b/render/kdrender.go @@ -72,14 +72,14 @@ func (s kdSDF) Nearest(v r3.Vec) kdTriangle { return got.(kdTriangle) } -func (s kdSDF) BoundingBox() d3.Box { +func (s kdSDF) BoundingBox() r3.Box { bb := s.tree.Root.Bounding if bb == nil { panic("got nil bounding box?") } tMin := bb.Min.(kdTriangle) tMax := bb.Max.(kdTriangle) - return d3.Box{ + return r3.Box{ Min: d3.MinElem(tMin.V[2], d3.MinElem(tMin.V[0], tMin.V[1])), Max: d3.MaxElem(tMax.V[2], d3.MaxElem(tMax.V[0], tMax.V[1])), } diff --git a/render/octree_renderer.go b/render/octree_renderer.go index c0c8964..617e63d 100644 --- a/render/octree_renderer.go +++ b/render/octree_renderer.go @@ -35,7 +35,7 @@ func NewOctreeRenderer(s sdf.SDF3, meshCells int) *octree { } // Scale the bounding box about the center to make sure the boundaries // aren't on the object surface. - bb := s.BoundingBox() + bb := d3.Box(s.BoundingBox()) bb = bb.ScaleAboutCenter(1.01) longAxis := d3.Max(bb.Size()) // We want to test the smallest cube (side == resolution) for emptiness diff --git a/sdf2.go b/sdf2.go index f30a627..7627ebb 100644 --- a/sdf2.go +++ b/sdf2.go @@ -10,6 +10,7 @@ import ( "math" "github.com/soypat/sdf/internal/d2" + "github.com/soypat/sdf/internal/d3" "gonum.org/v1/gonum/spatial/r2" "gonum.org/v1/gonum/spatial/r3" @@ -18,7 +19,7 @@ import ( // SDF2 is the interface to a 2d signed distance function object. type SDF2 interface { Evaluate(p r2.Vec) float64 - BoundingBox() d2.Box + BoundingBox() r2.Box } type SDF2Union interface { @@ -56,7 +57,7 @@ type CutSDF2 struct { sdf SDF2 a r2.Vec // point on line n r2.Vec // normal to line - bb d2.Box // bounding box + bb r2.Box // bounding box } // Cut2D cuts the SDF2 along a line from a in direction v. @@ -78,7 +79,7 @@ func (s *CutSDF2) Evaluate(p r2.Vec) float64 { } // BoundingBox returns the bounding box for the cut SDF2. -func (s *CutSDF2) BoundingBox() d2.Box { +func (s *CutSDF2) BoundingBox() r2.Box { return s.bb } @@ -88,7 +89,7 @@ func (s *CutSDF2) BoundingBox() d2.Box { type TransformSDF2 struct { sdf SDF2 mInv m33 - bb d2.Box + bb r2.Box } // Transform2D applies a transformation matrix to an SDF2. @@ -109,7 +110,7 @@ func (s *TransformSDF2) Evaluate(p r2.Vec) float64 { } // BoundingBox returns the bounding box of a transformed SDF2. -func (s *TransformSDF2) BoundingBox() d2.Box { +func (s *TransformSDF2) BoundingBox() r2.Box { return s.bb } @@ -119,7 +120,7 @@ func (s *TransformSDF2) BoundingBox() d2.Box { type ScaleUniformSDF2 struct { sdf SDF2 k, invk float64 - bb d2.Box + bb r2.Box } // ScaleUniform2D scales an SDF2 by k on each axis. @@ -141,20 +142,20 @@ func (s *ScaleUniformSDF2) Evaluate(p r2.Vec) float64 { } // BoundingBox returns the bounding box of an SDF2 with uniform scaling. -func (s *ScaleUniformSDF2) BoundingBox() d2.Box { +func (s *ScaleUniformSDF2) BoundingBox() r2.Box { return s.bb } // Center2D centers the origin of an SDF2 on it's bounding box. func Center2D(s SDF2) SDF2 { - ofs := r2.Scale(-1, s.BoundingBox().Center()) + ofs := r2.Scale(-1, d2.Box(s.BoundingBox()).Center()) return Transform2D(s, Translate2d(ofs)) } // CenterAndScale2D centers the origin of an SDF2 on it's bounding box, and then scales it. // Distance is correct with scaling. func CenterAndScale2D(s SDF2, k float64) SDF2 { - ofs := r2.Scale(-1, s.BoundingBox().Center()) + ofs := r2.Scale(-1, d2.Box(s.BoundingBox()).Center()) s = Transform2D(s, Translate2d(ofs)) return ScaleUniform2D(s, k) } @@ -167,7 +168,7 @@ type array2 struct { num V2i // grid size step r2.Vec // grid step size min MinFunc - bb d2.Box + bb r2.Box } // Array2D returns an XY grid array of an existing SDF2. @@ -182,10 +183,10 @@ func Array2D(sdf SDF2, num V2i, step r2.Vec) SDF2Union { s.step = step s.min = math.Min // work out the bounding box - bb0 := sdf.BoundingBox() + bb0 := d2.Box(sdf.BoundingBox()) // TODO verify bb1 := bb0.Translate(d2.MulElem(step, r2.Sub(R2FromI(num), d2.Elem(1)))) // step.Mul(num.SubScalar(1).Tor2.Vec())) - s.bb = bb0.Extend(bb1) + s.bb = r2.Box(bb0.Extend(bb1)) return &s } @@ -207,7 +208,7 @@ func (s *array2) Evaluate(p r2.Vec) float64 { } // BoundingBox returns the bounding box of a grid array of SDF2s. -func (s *array2) BoundingBox() d2.Box { +func (s *array2) BoundingBox() r2.Box { return s.bb } @@ -217,7 +218,7 @@ type rotateUnion2 struct { num int step m33 min MinFunc - bb d2.Box + bb r2.Box } // RotateUnion2D returns a union of rotated SDF2s. @@ -232,7 +233,7 @@ func RotateUnion2D(sdf SDF2, num int, step m33) SDF2 { s.step = step.Inverse() s.min = math.Min // work out the bounding box - vset := sdf.BoundingBox().Vertices() + vset := d2.Box(sdf.BoundingBox()).Vertices() bbMin := vset[0] bbMax := vset[0] for i := 0; i < s.num; i++ { @@ -241,7 +242,7 @@ func RotateUnion2D(sdf SDF2, num int, step m33) SDF2 { bbMax = d2.MaxElem(bbMax, vset.Max()) MulVertices2(vset, step) } - s.bb = d2.Box{bbMin, bbMax} + s.bb = r2.Box{bbMin, bbMax} return &s } @@ -263,7 +264,7 @@ func (s *rotateUnion2) SetMin(min MinFunc) { } // BoundingBox returns the bounding box of a union of rotated SDF2s. -func (s *rotateUnion2) BoundingBox() d2.Box { +func (s *rotateUnion2) BoundingBox() r2.Box { return s.bb } @@ -271,7 +272,7 @@ func (s *rotateUnion2) BoundingBox() d2.Box { type rotateCopy2 struct { sdf SDF2 theta float64 - bb d2.Box + bb r2.Box } // RotateCopy2D rotates and copies an SDF2 n times in a full circle. @@ -284,7 +285,7 @@ func RotateCopy2D(sdf SDF2, n int) SDF2 { s.sdf = sdf s.theta = 2 * math.Pi / float64(n) // work out the bounding box - bb := sdf.BoundingBox() + bb := d2.Box(sdf.BoundingBox()) rmax := 0.0 // find the bounding box vertex with the greatest distance from the origin for _, v := range bb.Vertices() { @@ -293,7 +294,7 @@ func RotateCopy2D(sdf SDF2, n int) SDF2 { rmax = l } } - s.bb = d2.Box{r2.Vec{-rmax, -rmax}, r2.Vec{rmax, rmax}} + s.bb = r2.Box{r2.Vec{-rmax, -rmax}, r2.Vec{rmax, rmax}} return &s } @@ -305,7 +306,7 @@ func (s *rotateCopy2) Evaluate(p r2.Vec) float64 { } // BoundingBox returns the bounding box of a rotate/copy SDF2. -func (s *rotateCopy2) BoundingBox() d2.Box { +func (s *rotateCopy2) BoundingBox() r2.Box { return s.bb } @@ -315,7 +316,7 @@ type slice2 struct { a r3.Vec // 3d point for 2d origin u r3.Vec // vector for the 2d x-axis v r3.Vec // vector for the 2d y-axis - bb d2.Box // bounding box + bb r2.Box // bounding box } // Slice2D returns an SDF2 created from a planar slice through an SDF3. @@ -341,7 +342,7 @@ func Slice2D(sdf SDF3, a, n r3.Vec) SDF2 { // TODO: This is bigger than it needs to be. We could consider intersection // between the plane and the edges of the 3d bounding box for a smaller 2d // bounding box in some circumstances. - v3 := sdf.BoundingBox().Vertices() + v3 := d3.Box(sdf.BoundingBox()).Vertices() vec := make(d2.Set, len(v3)) n = r3.Unit(n) for i, v := range v3 { @@ -351,7 +352,7 @@ func Slice2D(sdf SDF3, a, n r3.Vec) SDF2 { // work out the 3d point in terms of the 2d unit vectors vec[i] = r2.Vec{pa.Dot(s.u), pa.Dot(s.v)} } - s.bb = d2.Box{vec.Min(), vec.Max()} + s.bb = r2.Box{vec.Min(), vec.Max()} return &s } @@ -363,7 +364,7 @@ func (s *slice2) Evaluate(p r2.Vec) float64 { } // BoundingBox returns the bounding box of the sliced SDF2. -func (s *slice2) BoundingBox() d2.Box { +func (s *slice2) BoundingBox() r2.Box { return s.bb } @@ -371,7 +372,7 @@ func (s *slice2) BoundingBox() d2.Box { type union2 struct { sdf []SDF2 min MinFunc - bb d2.Box + bb r2.Box } // Union2D returns the union of multiple SDF2 objects. @@ -386,11 +387,11 @@ func Union2D(sdf ...SDF2) SDF2Union { } } // work out the bounding box - bb := s.sdf[0].BoundingBox() + bb := d2.Box(s.sdf[0].BoundingBox()) for _, x := range s.sdf { - bb = bb.Extend(x.BoundingBox()) + bb = bb.Extend(d2.Box(x.BoundingBox())) } - s.bb = bb + s.bb = r2.Box(bb) s.min = math.Min return &s } @@ -402,7 +403,7 @@ func (s *union2) Evaluate(p r2.Vec) float64 { minDist2 := -1.0 minIndex := 0 for i := range s.sdf { - vs[i] = s.sdf[i].BoundingBox().MinMaxDist2(p) + vs[i] = d2.Box(s.sdf[i].BoundingBox()).MinMaxDist2(p) // as we go record the sdf with the minimum minimum d2 value if minDist2 < 0 || vs[i].X < minDist2 { minDist2 = vs[i].X @@ -448,7 +449,7 @@ func (s *union2) SetMin(min MinFunc) { } // BoundingBox returns the bounding box of an SDF2 union. -func (s *union2) BoundingBox() d2.Box { +func (s *union2) BoundingBox() r2.Box { return s.bb } @@ -457,7 +458,7 @@ type diff2 struct { s0 SDF2 s1 SDF2 max MaxFunc - bb d2.Box + bb r2.Box } // Difference2D returns the difference of two SDF2 objects, s0 - s1. @@ -484,7 +485,7 @@ func (s *diff2) SetMax(max MaxFunc) { } // BoundingBox returns the bounding box of the difference of two SDF2s. -func (s *diff2) BoundingBox() d2.Box { +func (s *diff2) BoundingBox() r2.Box { return s.bb } @@ -492,7 +493,7 @@ func (s *diff2) BoundingBox() d2.Box { type elongate2 struct { sdf SDF2 // the sdf being elongated hp, hn r2.Vec // positive/negative elongation vector - bb d2.Box // bounding box + bb r2.Box // bounding box } // Elongate2D returns the elongation of an SDF2. @@ -504,10 +505,10 @@ func Elongate2D(sdf SDF2, h r2.Vec) SDF2 { hn: r2.Scale(0.5, h), } // bounding box - bb := sdf.BoundingBox() + bb := d2.Box(sdf.BoundingBox()) bb0 := bb.Translate(s.hp) bb1 := bb.Translate(s.hn) - s.bb = bb0.Extend(bb1) + s.bb = r2.Box(bb0.Extend(bb1)) return &s } @@ -518,15 +519,15 @@ func (s *elongate2) Evaluate(p r2.Vec) float64 { } // BoundingBox returns the bounding box of an elongated SDF2. -func (s *elongate2) BoundingBox() d2.Box { +func (s *elongate2) BoundingBox() r2.Box { return s.bb } -// GenerateMesh2D generates a set of internal mesh points for an SDF2. -func GenerateMesh2D(s SDF2, grid V2i) (d2.Set, error) { +// generateMesh2D generates a set of internal mesh points for an SDF2. +func generateMesh2D(s SDF2, grid V2i) (d2.Set, error) { // create the grid mapping for the bounding box - m, err := newMap2(s.BoundingBox(), grid, false) + m, err := newMap2(d2.Box(s.BoundingBox()), grid, false) if err != nil { return nil, err } @@ -586,7 +587,7 @@ func Multi2D(s SDF2, positions d2.Set) SDF2 { type offset2 struct { sdf SDF2 offset float64 - bb d2.Box + bb r2.Box } // Offset2D returns an SDF2 that offsets the distance function of another SDF2. @@ -595,8 +596,8 @@ func Offset2D(sdf SDF2, offset float64) SDF2 { s.sdf = sdf s.offset = offset // work out the bounding box - bb := sdf.BoundingBox() - s.bb = d2.NewBox2(bb.Center(), r2.Add(bb.Size(), d2.Elem(2*offset))) //NewBox2(bb.Center(), r2.Add(bb.Size(), d2.Elem(2*offset))) + bb := d2.Box(sdf.BoundingBox()) + s.bb = r2.Box(d2.NewBox2(bb.Center(), r2.Add(bb.Size(), d2.Elem(2*offset)))) //NewBox2(bb.Center(), r2.Add(bb.Size(), d2.Elem(2*offset))) return &s } @@ -606,7 +607,7 @@ func (s *offset2) Evaluate(p r2.Vec) float64 { } // BoundingBox returns the bounding box of an offset SDF2. -func (s *offset2) BoundingBox() d2.Box { +func (s *offset2) BoundingBox() r2.Box { return s.bb } @@ -615,7 +616,7 @@ type intersection2 struct { s0 SDF2 s1 SDF2 max MaxFunc - bb d2.Box + bb r2.Box } // Intersect2D returns the intersection of two SDF2s. @@ -643,12 +644,12 @@ func (s *intersection2) SetMax(max MaxFunc) { } // BoundingBox returns the bounding box of an SDF2 intersection. -func (s *intersection2) BoundingBox() d2.Box { +func (s *intersection2) BoundingBox() r2.Box { return s.bb } func empty2From(s SDF2) empty2 { return empty2{ - center: s.BoundingBox().Center(), + center: d2.Box(s.BoundingBox()).Center(), } } @@ -662,8 +663,8 @@ func (e empty2) Evaluate(r2.Vec) float64 { return math.MaxFloat64 } -func (e empty2) BoundingBox() d2.Box { - return d2.Box{ +func (e empty2) BoundingBox() r2.Box { + return r2.Box{ Min: e.center, Max: e.center, } diff --git a/sdf3.go b/sdf3.go index 489a2d1..e419e5d 100644 --- a/sdf3.go +++ b/sdf3.go @@ -12,7 +12,7 @@ import ( // SDF3 is the interface to a 3d signed distance function object. type SDF3 interface { Evaluate(p r3.Vec) float64 - BoundingBox() d3.Box + BoundingBox() r3.Box } type SDF3Union interface { @@ -30,7 +30,7 @@ type revolution3 struct { sdf SDF2 theta float64 // angle for partial revolutions norm r2.Vec // pre-calculated normal to theta line - bb d3.Box + bb r3.Box } // Revolve3D returns an SDF3 for a solid of revolution. @@ -70,11 +70,11 @@ func Revolve3D(sdf SDF2, theta float64) SDF3 { vset = append(vset, r2.Vec{0, -1}) } } - bb := s.sdf.BoundingBox() + bb := s.sdf.Bounds() l := math.Max(math.Abs(bb.Min.X), math.Abs(bb.Max.X)) vmin := r2.Scale(l, vset.Min()) vmax := r2.Scale(l, vset.Max()) - s.bb = d3.Box{r3.Vec{vmin.X, vmin.Y, bb.Min.Y}, r3.Vec{vmax.X, vmax.Y, bb.Max.Y}} + s.bb = r3.Box{r3.Vec{vmin.X, vmin.Y, bb.Min.Y}, r3.Vec{vmax.X, vmax.Y, bb.Max.Y}} return &s } @@ -97,7 +97,7 @@ func (s *revolution3) Evaluate(p r3.Vec) float64 { } // BoundingBox returns the bounding box for a solid of revolution. -func (s *revolution3) BoundingBox() d3.Box { +func (s *revolution3) BoundingBox() r3.Box { return s.bb } @@ -106,7 +106,7 @@ type extrude3 struct { sdf SDF2 height float64 extrude ExtrudeFunc - bb d3.Box + bb r3.Box } // Extrude3D does a linear extrude on an SDF3. @@ -116,8 +116,8 @@ func Extrude3D(sdf SDF2, height float64) SDF3 { s.height = height / 2 s.extrude = NormalExtrude // work out the bounding box - bb := sdf.BoundingBox() - s.bb = d3.Box{r3.Vec{bb.Min.X, bb.Min.Y, -s.height}, r3.Vec{bb.Max.X, bb.Max.Y, s.height}} + bb := sdf.Bounds() + s.bb = r3.Box{r3.Vec{bb.Min.X, bb.Min.Y, -s.height}, r3.Vec{bb.Max.X, bb.Max.Y, s.height}} return &s } @@ -128,9 +128,9 @@ func TwistExtrude3D(sdf SDF2, height, twist float64) SDF3 { s.height = height / 2 s.extrude = TwistExtrude(height, twist) // work out the bounding box - bb := sdf.BoundingBox() + bb := sdf.Bounds() l := r2.Norm(bb.Max) - s.bb = d3.Box{r3.Vec{-l, -l, -s.height}, r3.Vec{l, l, s.height}} + s.bb = r3.Box{r3.Vec{-l, -l, -s.height}, r3.Vec{l, l, s.height}} return &s } @@ -141,9 +141,9 @@ func ScaleExtrude3D(sdf SDF2, height float64, scale r2.Vec) SDF3 { s.height = height / 2 s.extrude = ScaleExtrude(height, scale) // work out the bounding box - bb := sdf.BoundingBox() + bb := d2.Box(sdf.Bounds()) bb = bb.Extend(d2.Box{d2.MulElem(bb.Min, scale), d2.MulElem(bb.Max, scale)}) - s.bb = d3.Box{r3.Vec{bb.Min.X, bb.Min.Y, -s.height}, r3.Vec{bb.Max.X, bb.Max.Y, s.height}} + s.bb = r3.Box{r3.Vec{bb.Min.X, bb.Min.Y, -s.height}, r3.Vec{bb.Max.X, bb.Max.Y, s.height}} return &s } @@ -154,10 +154,10 @@ func ScaleTwistExtrude3D(sdf SDF2, height, twist float64, scale r2.Vec) SDF3 { s.height = height / 2 s.extrude = ScaleTwistExtrude(height, twist, scale) // work out the bounding box - bb := sdf.BoundingBox() + bb := d2.Box(sdf.Bounds()) bb = bb.Extend(d2.Box{d2.MulElem(bb.Min, scale), d2.MulElem(bb.Max, scale)}) l := r2.Norm(bb.Max) - s.bb = d3.Box{r3.Vec{-l, -l, -s.height}, r3.Vec{l, l, s.height}} + s.bb = r3.Box{r3.Vec{-l, -l, -s.height}, r3.Vec{l, l, s.height}} return &s } @@ -177,7 +177,7 @@ func (s *extrude3) SetExtrude(extrude ExtrudeFunc) { } // BoundingBox returns the bounding box for an extrusion. -func (s *extrude3) BoundingBox() d3.Box { +func (s *extrude3) BoundingBox() r3.Box { return s.bb } @@ -190,7 +190,7 @@ type extrudeRounded struct { sdf SDF2 height float64 round float64 - bb d3.Box + bb r3.Box } // ExtrudeRounded3D extrudes an SDF2 to an SDF3 with rounded edges. @@ -213,8 +213,8 @@ func ExtrudeRounded3D(sdf SDF2, height, round float64) SDF3 { round: round, } // work out the bounding box - bb := sdf.BoundingBox() - s.bb = d3.Box{ + bb := sdf.Bounds() + s.bb = r3.Box{ Min: r3.Sub(r3.Vec{bb.Min.X, bb.Min.Y, -s.height}, d3.Elem(round)), Max: r3.Add(r3.Vec{bb.Max.X, bb.Max.Y, s.height}, d3.Elem(round)), } @@ -250,7 +250,7 @@ func (s *extrudeRounded) Evaluate(p r3.Vec) float64 { } // BoundingBox returns the bounding box for a rounded extrusion. -func (s *extrudeRounded) BoundingBox() d3.Box { +func (s *extrudeRounded) BoundingBox() r3.Box { return s.bb } @@ -262,7 +262,7 @@ type loft3 struct { sdf0, sdf1 SDF2 height float64 round float64 - bb d3.Box + bb r3.Box } // Loft3D extrudes an SDF3 that transitions between two SDF2 shapes. @@ -284,10 +284,10 @@ func Loft3D(sdf0, sdf1 SDF2, height, round float64) SDF3 { round: round, } // work out the bounding box - bb0 := sdf0.BoundingBox() - bb1 := sdf1.BoundingBox() + bb0 := d2.Box(sdf0.Bounds()) + bb1 := d2.Box(sdf1.Bounds()) bb := bb0.Extend(bb1) - s.bb = d3.Box{ + s.bb = r3.Box{ Min: r3.Sub(r3.Vec{bb.Min.X, bb.Min.Y, -s.height}, d3.Elem(round)), Max: r3.Add(r3.Vec{bb.Max.X, bb.Max.Y, s.height}, d3.Elem(round))} return &s @@ -327,7 +327,7 @@ func (s *loft3) Evaluate(p r3.Vec) float64 { } // BoundingBox returns the bounding box for a loft extrusion. -func (s *loft3) BoundingBox() d3.Box { +func (s *loft3) BoundingBox() r3.Box { return s.bb } @@ -338,7 +338,7 @@ type transform3 struct { sdf SDF3 matrix m44 inverse m44 - bb d3.Box + bb r3.Box } // Transform3D applies a transformation matrix to an SDF3. @@ -358,7 +358,7 @@ func (s *transform3) Evaluate(p r3.Vec) float64 { } // BoundingBox returns the bounding box of a transformed SDF3. -func (s *transform3) BoundingBox() d3.Box { +func (s *transform3) BoundingBox() r3.Box { return s.bb } @@ -368,7 +368,7 @@ func (s *transform3) BoundingBox() d3.Box { type scaleUniform3 struct { sdf SDF3 k, invK float64 - bb d3.Box + bb r3.Box } // ScaleUniform3D uniformly scales an SDF3 on all axes. @@ -390,7 +390,7 @@ func (s *scaleUniform3) Evaluate(p r3.Vec) float64 { } // BoundingBox returns the bounding box of a uniformly scaled SDF3. -func (s *scaleUniform3) BoundingBox() d3.Box { +func (s *scaleUniform3) BoundingBox() r3.Box { return s.bb } @@ -398,7 +398,7 @@ func (s *scaleUniform3) BoundingBox() d3.Box { type union3 struct { sdf []SDF3 min MinFunc - bb d3.Box + bb r3.Box } // Union3D returns the union of multiple SDF3 objects. @@ -417,11 +417,11 @@ func Union3D(sdf ...SDF3) SDF3Union { } } // work out the bounding box - bb := s.sdf[0].BoundingBox() + bb := d3.Box(s.sdf[0].BoundingBox()) for _, x := range s.sdf { - bb = bb.Extend(x.BoundingBox()) + bb = bb.Extend(d3.Box(x.BoundingBox())) } - s.bb = bb + s.bb = r3.Box(bb) s.min = math.Min return &s } @@ -445,7 +445,7 @@ func (s *union3) SetMin(min MinFunc) { } // BoundingBox returns the bounding box of an SDF3 union. -func (s *union3) BoundingBox() d3.Box { +func (s *union3) BoundingBox() r3.Box { return s.bb } @@ -454,7 +454,7 @@ type diff3 struct { s0 SDF3 s1 SDF3 max MaxFunc - bb d3.Box + bb r3.Box } // Difference3D returns the difference of two SDF3s, s0 - s1. @@ -482,7 +482,7 @@ func (s *diff3) SetMax(max MaxFunc) { } // BoundingBox returns the bounding box of the SDF3 difference. -func (s *diff3) BoundingBox() d3.Box { +func (s *diff3) BoundingBox() r3.Box { return s.bb } @@ -490,7 +490,7 @@ func (s *diff3) BoundingBox() d3.Box { type elongate3 struct { sdf SDF3 // the sdf being elongated hp, hn r3.Vec // positive/negative elongation vector - bb d3.Box // bounding box + bb r3.Box // bounding box } // Elongate3D returns the elongation of an SDF3. @@ -502,10 +502,10 @@ func Elongate3D(sdf SDF3, h r3.Vec) SDF3 { hn: r3.Scale(-0.5, h), } // bounding box - bb := sdf.BoundingBox() + bb := d3.Box(sdf.BoundingBox()) bb0 := bb.Translate(s.hp) bb1 := bb.Translate(s.hn) - s.bb = bb0.Extend(bb1) + s.bb = r3.Box(bb0.Extend(bb1)) return &s } @@ -516,7 +516,7 @@ func (s *elongate3) Evaluate(p r3.Vec) float64 { } // BoundingBox returns the bounding box of an elongated SDF3. -func (s *elongate3) BoundingBox() d3.Box { +func (s *elongate3) BoundingBox() r3.Box { return s.bb } @@ -525,7 +525,7 @@ type intersection3 struct { s0 SDF3 s1 SDF3 max MaxFunc - bb d3.Box + bb r3.Box } // Intersect3D returns the intersection of two SDF3s. @@ -554,7 +554,7 @@ func (s *intersection3) SetMax(max MaxFunc) { } // BoundingBox returns the bounding box of an SDF3 intersection. -func (s *intersection3) BoundingBox() d3.Box { +func (s *intersection3) BoundingBox() r3.Box { return s.bb } @@ -563,7 +563,7 @@ type cut3 struct { sdf SDF3 a r3.Vec // point on plane n r3.Vec // normal to plane - bb d3.Box // bounding box + bb r3.Box // bounding box } // Cut3D cuts an SDF3 along a plane passing through a with normal n. @@ -584,7 +584,7 @@ func (s *cut3) Evaluate(p r3.Vec) float64 { } // BoundingBox returns the bounding box of the cut SDF3. -func (s *cut3) BoundingBox() d3.Box { +func (s *cut3) BoundingBox() r3.Box { return s.bb } @@ -594,7 +594,7 @@ type array3 struct { num V3i step r3.Vec min MinFunc - bb d3.Box + bb r3.Box } // Array3D returns an XYZ array of a given SDF3 @@ -609,9 +609,9 @@ func Array3D(sdf SDF3, num V3i, step r3.Vec) SDF3Union { s.step = step s.min = math.Min // work out the bounding box - bb0 := sdf.BoundingBox() + bb0 := d3.Box(sdf.BoundingBox()) bb1 := bb0.Translate(d3.MulElem(step, num.SubScalar(1).ToV3())) - s.bb = bb0.Extend(bb1) + s.bb = r3.Box(bb0.Extend(bb1)) return &s } @@ -635,7 +635,7 @@ func (s *array3) Evaluate(p r3.Vec) float64 { } // BoundingBox returns the bounding box of an XYZ SDF3 array. -func (s *array3) BoundingBox() d3.Box { +func (s *array3) BoundingBox() r3.Box { return s.bb } @@ -645,7 +645,7 @@ type rotateUnion struct { num int step m44 min MinFunc - bb d3.Box + bb r3.Box } // RotateUnion3D creates a union of SDF3s rotated about the z-axis. @@ -661,7 +661,7 @@ func RotateUnion3D(sdf SDF3, num int, step m44) SDF3Union { s.step = step.Inverse() s.min = math.Min // work out the bounding box - v := sdf.BoundingBox().Vertices() + v := d3.Box(sdf.BoundingBox()).Vertices() bbMin := v[0] bbMax := v[0] for i := 0; i < s.num; i++ { @@ -670,7 +670,7 @@ func RotateUnion3D(sdf SDF3, num int, step m44) SDF3Union { mulVertices3(v, step) // v.MulVertices(step) } - s.bb = d3.Box{bbMin, bbMax} + s.bb = r3.Box{bbMin, bbMax} return &s } @@ -692,7 +692,7 @@ func (s *rotateUnion) SetMin(min MinFunc) { } // BoundingBox returns the bounding box of a rotate/union object. -func (s *rotateUnion) BoundingBox() d3.Box { +func (s *rotateUnion) BoundingBox() r3.Box { return s.bb } @@ -700,7 +700,7 @@ func (s *rotateUnion) BoundingBox() d3.Box { type rotateCopy3 struct { sdf SDF3 theta float64 - bb d3.Box + bb r3.Box } // RotateCopy3D rotates and creates N copies of an SDF3 about the z-axis. @@ -714,7 +714,7 @@ func RotateCopy3D(sdf SDF3, num int) SDF3 { s.sdf = sdf s.theta = tau / float64(num) // work out the bounding box - bb := sdf.BoundingBox() + bb := d3.Box(sdf.BoundingBox()) zmax := bb.Max.Z zmin := bb.Min.Z rmax := 0.0 @@ -726,7 +726,7 @@ func RotateCopy3D(sdf SDF3, num int) SDF3 { rmax = l } } - s.bb = d3.Box{r3.Vec{-rmax, -rmax, zmin}, r3.Vec{rmax, rmax, zmax}} + s.bb = r3.Box{r3.Vec{-rmax, -rmax, zmin}, r3.Vec{rmax, rmax, zmax}} return &s } @@ -739,7 +739,7 @@ func (s *rotateCopy3) Evaluate(p r3.Vec) float64 { } // BoundingBox returns the bounding box of a rotate/copy SDF3. -func (s *rotateCopy3) BoundingBox() d3.Box { +func (s *rotateCopy3) BoundingBox() r3.Box { return s.bb } @@ -790,7 +790,7 @@ func (s *ConnectedSDF3) BoundingBox() d3.Box { type offset3 struct { sdf SDF3 // the underlying SDF distance float64 // the distance the SDF is offset by - bb d3.Box // bounding box + bb r3.Box // bounding box } // Offset3D returns an SDF3 that offsets the distance function of another SDF3. @@ -800,8 +800,8 @@ func Offset3D(sdf SDF3, offset float64) SDF3 { distance: offset, } // bounding box - bb := sdf.BoundingBox() - s.bb = d3.NewBox(bb.Center(), r3.Add(bb.Size(), d3.Elem(2*offset))) + bb := d3.Box(sdf.BoundingBox()) + s.bb = r3.Box(d3.NewBox(bb.Center(), r3.Add(bb.Size(), d3.Elem(2*offset)))) return &s } @@ -811,7 +811,7 @@ func (s *offset3) Evaluate(p r3.Vec) float64 { } // BoundingBox returns the bounding box of an offset SDF3. -func (s *offset3) BoundingBox() d3.Box { +func (s *offset3) BoundingBox() r3.Box { return s.bb } @@ -819,7 +819,7 @@ func (s *offset3) BoundingBox() d3.Box { type shell3 struct { sdf SDF3 // parent sdf3 delta float64 // half shell thickness - bb d3.Box // bounding box + bb r3.Box // bounding box } // Shell3D returns an SDF3 that shells the surface of an existing SDF3. @@ -827,10 +827,11 @@ func Shell3D(sdf SDF3, thickness float64) SDF3 { if thickness <= 0 { return empty3From(sdf) } + bb := d3.Box(sdf.BoundingBox()) return &shell3{ sdf: sdf, delta: 0.5 * thickness, - bb: sdf.BoundingBox().Enlarge(r3.Vec{thickness, thickness, thickness}), + bb: r3.Box(bb.Enlarge(r3.Vec{thickness, thickness, thickness})), } } @@ -840,7 +841,7 @@ func (s *shell3) Evaluate(p r3.Vec) float64 { } // BoundingBox returns the bounding box of a shelled SDF3. -func (s *shell3) BoundingBox() d3.Box { +func (s *shell3) BoundingBox() r3.Box { return s.bb } @@ -893,7 +894,7 @@ func Orient3D(s SDF3, base r3.Vec, directions d3.Set) SDF3 { func empty3From(s SDF3) empty3 { return empty3{ - center: s.BoundingBox().Center(), + center: d3.Box(s.BoundingBox()).Center(), } } @@ -907,8 +908,8 @@ func (e empty3) Evaluate(r3.Vec) float64 { return math.MaxFloat64 } -func (e empty3) BoundingBox() d3.Box { - return d3.Box{ +func (e empty3) BoundingBox() r3.Box { + return r3.Box{ Min: e.center, Max: e.center, } diff --git a/utils.go b/utils.go index 7bdec3b..1ccb1e1 100644 --- a/utils.go +++ b/utils.go @@ -350,7 +350,7 @@ type map2 struct { // newMap2 returns a 2d region to grid coordinates map. func newMap2(bb d2.Box, grid V2i, flipy bool) (*map2, error) { // sanity check the bounding box - bbSize := bb.Size() + bbSize := d2.Box(bb).Size() if bbSize.X <= 0 || bbSize.Y <= 0 { return nil, errors.New("bad bounding box") }