github.com/df-mc/dragonfly@v0.9.13/server/block/cube/trace/trace.go (about) 1 package trace 2 3 import ( 4 "github.com/df-mc/dragonfly/server/block/cube" 5 "github.com/go-gl/mathgl/mgl64" 6 "math" 7 ) 8 9 // TraverseBlocks performs a ray trace between the start and end coordinates. 10 // A function 'f' is passed which is called for each voxel, if f returns false, the function will return. 11 // TraverseBlocks panics if the start and end positions are the same. 12 func TraverseBlocks(start, end mgl64.Vec3, f func(pos cube.Pos) (con bool)) { 13 dir := end.Sub(start) 14 if mgl64.FloatEqual(dir.LenSqr(), 0) { 15 panic("start and end points are the same, giving a zero direction vector") 16 } 17 dir = dir.Normalize() 18 19 b := cube.PosFromVec3(start) 20 21 step := signVec3(dir) 22 stepX, stepY, stepZ := int(step[0]), int(step[1]), int(step[2]) 23 max := boundaryVec3(start, dir) 24 25 delta := safeDivideVec3(step, dir) 26 27 r := start.Sub(end).Len() 28 for { 29 if !f(b) { 30 return 31 } 32 33 if max[0] < max[1] && max[0] < max[2] { 34 if max[0] > r { 35 return 36 } 37 b[0] += stepX 38 max[0] += delta[0] 39 } else if max[1] < max[2] { 40 if max[1] > r { 41 return 42 } 43 b[1] += stepY 44 max[1] += delta[1] 45 } else { 46 if max[2] > r { 47 return 48 } 49 b[2] += stepZ 50 max[2] += delta[2] 51 } 52 } 53 } 54 55 // safeDivideVec3 ... 56 func safeDivideVec3(dividend, divisor mgl64.Vec3) mgl64.Vec3 { 57 return mgl64.Vec3{ 58 safeDivide(dividend[0], divisor[0]), 59 safeDivide(dividend[1], divisor[1]), 60 safeDivide(dividend[2], divisor[2]), 61 } 62 } 63 64 // safeDivide divides the dividend by the divisor, but if the divisor is 0, it returns 0. 65 func safeDivide(dividend, divisor float64) float64 { 66 if divisor == 0.0 { 67 return 0.0 68 } 69 return dividend / divisor 70 } 71 72 // boundaryVec3 ... 73 func boundaryVec3(v1, v2 mgl64.Vec3) mgl64.Vec3 { 74 return mgl64.Vec3{boundary(v1[0], v2[0]), boundary(v1[1], v2[1]), boundary(v1[2], v2[2])} 75 } 76 77 // boundary returns the distance that must be travelled on an axis from the start point with the direction vector 78 // component to cross a block boundary. 79 func boundary(start, dir float64) float64 { 80 if dir == 0.0 { 81 return math.Inf(1) 82 } 83 84 if dir < 0.0 { 85 start, dir = -start, -dir 86 if math.Floor(start) == start { 87 return 0.0 88 } 89 } 90 91 return (1 - (start - math.Floor(start))) / dir 92 } 93 94 // signVec3 ... 95 func signVec3(v1 mgl64.Vec3) mgl64.Vec3 { 96 return mgl64.Vec3{sign(v1[0]), sign(v1[1]), sign(v1[2])} 97 } 98 99 // sign ... 100 func sign(f float64) float64 { 101 switch { 102 case f > 0.0: 103 return 1.0 104 case f < 0.0: 105 return -1.0 106 } 107 return 0.0 108 }