26ed99fda6
Build and deploy / Build (push) Has been cancelled
Build and deploy / Update Contributors (push) Has been cancelled
Build and deploy / Deploy (push) Has been cancelled
110 lines
2.4 KiB
Go
110 lines
2.4 KiB
Go
package trace
|
|
|
|
import (
|
|
"github.com/df-mc/dragonfly/server/block/cube"
|
|
"github.com/go-gl/mathgl/mgl64"
|
|
"math"
|
|
)
|
|
|
|
// TraverseBlocks performs a ray trace between the start and end coordinates.
|
|
// A function 'f' is passed which is called for each voxel, if f returns false, the function will return.
|
|
// TraverseBlocks panics if the start and end positions are the same.
|
|
func TraverseBlocks(start, end mgl64.Vec3, f func(pos cube.Pos) (con bool)) {
|
|
dir := end.Sub(start)
|
|
if mgl64.FloatEqual(dir.LenSqr(), 0) {
|
|
panic("start and end points are the same, giving a zero direction vector")
|
|
}
|
|
dir = dir.Normalize()
|
|
|
|
b := cube.PosFromVec3(start)
|
|
|
|
step := signVec3(dir)
|
|
stepX, stepY, stepZ := int(step[0]), int(step[1]), int(step[2])
|
|
max := boundaryVec3(start, dir)
|
|
|
|
delta := safeDivideVec3(step, dir)
|
|
|
|
r := start.Sub(end).Len()
|
|
for {
|
|
if !f(b) {
|
|
return
|
|
}
|
|
|
|
switch {
|
|
case max[0] < max[1] && max[0] < max[2]:
|
|
if max[0] > r {
|
|
return
|
|
}
|
|
b[0] += stepX
|
|
max[0] += delta[0]
|
|
case max[1] < max[2]:
|
|
if max[1] > r {
|
|
return
|
|
}
|
|
b[1] += stepY
|
|
max[1] += delta[1]
|
|
default:
|
|
if max[2] > r {
|
|
return
|
|
}
|
|
b[2] += stepZ
|
|
max[2] += delta[2]
|
|
}
|
|
}
|
|
}
|
|
|
|
// safeDivideVec3 ...
|
|
func safeDivideVec3(dividend, divisor mgl64.Vec3) mgl64.Vec3 {
|
|
return mgl64.Vec3{
|
|
safeDivide(dividend[0], divisor[0]),
|
|
safeDivide(dividend[1], divisor[1]),
|
|
safeDivide(dividend[2], divisor[2]),
|
|
}
|
|
}
|
|
|
|
// safeDivide divides the dividend by the divisor, but if the divisor is 0, it returns 0.
|
|
func safeDivide(dividend, divisor float64) float64 {
|
|
if divisor == 0.0 {
|
|
return 0.0
|
|
}
|
|
return dividend / divisor
|
|
}
|
|
|
|
// boundaryVec3 ...
|
|
func boundaryVec3(v1, v2 mgl64.Vec3) mgl64.Vec3 {
|
|
return mgl64.Vec3{boundary(v1[0], v2[0]), boundary(v1[1], v2[1]), boundary(v1[2], v2[2])}
|
|
}
|
|
|
|
// boundary returns the distance that must be travelled on an axis from the start point with the direction vector
|
|
// component to cross a block boundary.
|
|
func boundary(start, dir float64) float64 {
|
|
if dir == 0.0 {
|
|
return math.Inf(1)
|
|
}
|
|
|
|
if dir < 0.0 {
|
|
start, dir = -start, -dir
|
|
if math.Floor(start) == start {
|
|
return 0.0
|
|
}
|
|
}
|
|
|
|
return (1 - (start - math.Floor(start))) / dir
|
|
}
|
|
|
|
// signVec3 ...
|
|
func signVec3(v1 mgl64.Vec3) mgl64.Vec3 {
|
|
return mgl64.Vec3{sign(v1[0]), sign(v1[1]), sign(v1[2])}
|
|
}
|
|
|
|
// sign ...
|
|
func sign(f float64) float64 {
|
|
switch {
|
|
case f > 0.0:
|
|
return 1.0
|
|
case f < 0.0:
|
|
return -1.0
|
|
}
|
|
return 0.0
|
|
}
|