Major progress in introducing arbitrary boundaries! EDT in the house.

This commit is contained in:
2025-12-08 21:14:30 -05:00
parent 45b286b66e
commit 48df951042
8 changed files with 521 additions and 29 deletions

View File

@@ -4,6 +4,7 @@
package fluid
import (
"fluids/edt"
"fluids/utils"
"math"
)
@@ -41,6 +42,9 @@ type Fluid struct {
flipPicRatio float32
numSubSteps int //number of simulation substeps
Block bool //rectangular or circular field container
//for arbitrary boundaries
edt *edt.EDT
}
func NewFluid(dimensions FieldVector, spacing float32) *Fluid {
@@ -52,6 +56,7 @@ func NewFluid(dimensions FieldVector, spacing float32) *Fluid {
flipPicRatio: FluidDefaultFlipPicRatio,
numSubSteps: FluidDefaultSubSteps,
Block: true,
edt: nil,
}
f.Initialize()
@@ -268,6 +273,11 @@ func (f *Fluid) HandleParticleCollisions() {
minDist2 := minDist * minDist
*/
if f.edt != nil {
f.HandleBoundaryCollisions()
return
}
if f.Block {
minX := f.Field.H + f.particleRadius
maxX := float32(f.Field.Nx-1)*f.Field.H - f.particleRadius
@@ -651,3 +661,53 @@ func (f *Fluid) SolveIncompressibility() {
func (f *Fluid) ToggleShape() {
f.Block = !f.Block
}
func (f *Fluid) SetBoundary(b *Boundary) {
if b != nil {
dim := edt.Bounds{
X: b.Dimensions.X,
Y: b.Dimensions.Y,
}
f.edt = edt.NewEDT(dim)
f.edt.AssignOccupancy(b.Cells)
f.edt.ComputeDistanceTransform()
} else {
f.edt = nil
}
}
// we perform our boundary resolution on particles according to our defined fluid boundary
func (f *Fluid) HandleBoundaryCollisions() {
//grid spacing within our distance field
dx := f.Field.Dimensions.X / float32(f.edt.Dimensions.X)
dy := f.Field.Dimensions.Y / float32(f.edt.Dimensions.Y)
//find cell of distance field for which particles belong, check if it's in bounds
for i := range f.Particles {
p := &f.Particles[i]
xi := utils.Clamp(int(math.Floor(float64(p.Position.X/dx))), 0, f.edt.Dimensions.X-1)
yi := utils.Clamp(int(math.Floor(float64(p.Position.Y/dy))), 0, f.edt.Dimensions.Y-1)
cellidx := xi + yi*f.edt.Dimensions.X
//if our current cell isn't a boundary, then we skip
if f.edt.D[cellidx] == 0 {
continue
}
//find where the particle actually belongs
pos := f.edt.L[cellidx]
newx := (float32(pos.X-xi) + f.particleRadius) * dx
newy := (float32(pos.Y-yi) + f.particleRadius) * dy
p.Position.X += newx
p.Position.Y += newy
p.Velocity.X = 0
p.Velocity.Y = 0
}
}