Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Doc comments added | everything.go #27

Merged
merged 1 commit into from
Jan 4, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
215 changes: 128 additions & 87 deletions everything.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,46 @@ const (
POOLED_BUFFER_SIZE = 1024
)

// Arbiter states
const (
// Arbiter is active and its the first collision.
CP_ARBITER_STATE_FIRST_COLLISION = iota
// Arbiter is active and its not the first collision.
CP_ARBITER_STATE_NORMAL
// Collision has been explicitly ignored.
// Either by returning false from a begin collision handler or calling cpArbiterIgnore().
CP_ARBITER_STATE_IGNORE
// Collison is no longer active. A space will cache an arbiter for up to cpSpace.collisionPersistence more steps.
CP_ARBITER_STATE_CACHED
// Collison arbiter is invalid because one of the shapes was removed.
CP_ARBITER_STATE_INVALIDATED
)

var (
NO_GROUP uint = 0 // Value for group signifying that a shape is in no group.
ALL_CATEGORIES uint = ^uint(0) // Value for Shape layers signifying that a shape is in every layer.
)

// SHAPE_FILTER_ALL is s collision filter value for a shape that will collide with anything except SHAPE_FILTER_NONE.
var SHAPE_FILTER_ALL = ShapeFilter{NO_GROUP, ALL_CATEGORIES, ALL_CATEGORIES}

// SHAPE_FILTER_NONE is a collision filter value for a shape that does not collide with anything.
var SHAPE_FILTER_NONE = ShapeFilter{NO_GROUP, ^ALL_CATEGORIES, ^ALL_CATEGORIES}

// CollisionBeginFunc is collision begin event function callback type.
//
// Returning false from a begin callback causes the collision to be ignored until the the separate callback is called when the objects stop colliding.
type CollisionBeginFunc func(arb *Arbiter, space *Space, userData interface{}) bool

// CollisionPreSolveFunc is collision pre-solve event function callback type.
//
// Returning false from a pre-step callback causes the collision to be ignored until the next step.
type CollisionPreSolveFunc func(arb *Arbiter, space *Space, userData interface{}) bool

// CollisionPostSolveFunc is collision post-solve event function callback type.
type CollisionPostSolveFunc func(arb *Arbiter, space *Space, userData interface{})

// CollisionSeparateFunc is collision separate event function callback type.
type CollisionSeparateFunc func(arb *Arbiter, space *Space, userData interface{})

type CollisionType uintptr
Expand Down Expand Up @@ -45,21 +82,6 @@ type CollisionHandler struct {
UserData interface{}
}

// Arbiter states
const (
// Arbiter is active and its the first collision.
CP_ARBITER_STATE_FIRST_COLLISION = iota
// Arbiter is active and its not the first collision.
CP_ARBITER_STATE_NORMAL
// Collision has been explicitly ignored.
// Either by returning false from a begin collision handler or calling cpArbiterIgnore().
CP_ARBITER_STATE_IGNORE
// Collison is no longer active. A space will cache an arbiter for up to cpSpace.collisionPersistence more steps.
CP_ARBITER_STATE_CACHED
// Collison arbiter is invalid because one of the shapes was removed.
CP_ARBITER_STATE_INVALIDATED
)

type Contact struct {
r1, r2 Vector

Expand Down Expand Up @@ -87,6 +109,7 @@ func (c *Contact) Clone() Contact {
}
}

// CollisionInfo collision info struct
type CollisionInfo struct {
a, b *Shape
collisionId uint32
Expand All @@ -107,11 +130,13 @@ func (info *CollisionInfo) PushContact(p1, p2 Vector, hash HashValue) {
info.count++
}

// ShapeMassInfo is mass info struct
type ShapeMassInfo struct {
m, i, area float64
cog Vector
}

// PointQueryInfo is point query info struct.
type PointQueryInfo struct {
// The nearest shape, NULL if no shape was within range.
Shape *Shape
Expand All @@ -124,6 +149,7 @@ type PointQueryInfo struct {
Gradient Vector
}

// SegmentQueryInfo is segment query info struct.
type SegmentQueryInfo struct {
// The shape that was hit, or NULL if no collision occurred.
Shape *Shape
Expand All @@ -139,14 +165,7 @@ type SplittingPlane struct {
v0, n Vector
}

var (
NO_GROUP uint = 0
ALL_CATEGORIES uint = ^uint(0)
)

var SHAPE_FILTER_ALL = ShapeFilter{NO_GROUP, ALL_CATEGORIES, ALL_CATEGORIES}
var SHAPE_FILTER_NONE = ShapeFilter{NO_GROUP, ^ALL_CATEGORIES, ^ALL_CATEGORIES}

// ShapeFilter is fast collision filtering type that is used to determine if two objects collide before calling collision or query callbacks.
type ShapeFilter struct {
// Two objects with the same non-zero group value do not collide.
// This is generally used to group objects in a composite object together to disable self collisions.
Expand All @@ -159,6 +178,7 @@ type ShapeFilter struct {
Mask uint
}

// NewShapeFilter creates a new collision filter.
func NewShapeFilter(group, categories, mask uint) ShapeFilter {
return ShapeFilter{group, categories, mask}
}
Expand All @@ -171,27 +191,52 @@ func (a ShapeFilter) Reject(b ShapeFilter) bool {
(b.Categories&a.Mask) == 0
}

func MomentForCircle(m, r1, r2 float64, offset Vector) float64 {
return m * (0.5*(r1*r1+r2*r2) + offset.LengthSq())
// Mat2x2 is a 2x2 matrix type used for tensors and such.
type Mat2x2 struct {
a, b, c, d float64
}

func AreaForCircle(r1, r2 float64) float64 {
return math.Pi * math.Abs(r1*r1-r2*r2)
// Transform transforms Vector v
func (m *Mat2x2) Transform(v Vector) Vector {
return Vector{v.X*m.a + v.Y*m.b, v.X*m.c + v.Y*m.d}
}

func MomentForSegment(m float64, a, b Vector, r float64) float64 {
offset := a.Lerp(b, 0.5)
length := b.Distance(a) + 2.0*r
return m * ((length*length+4.0*r*r)/12.0 + offset.LengthSq())
// MomentForBox calculates the moment of inertia for a solid box.
func MomentForBox(mass, width, height float64) float64 {
return mass * (width*width + height*height) / 12.0
}

func AreaForSegment(a, b Vector, r float64) float64 {
return r * (math.Pi*r + 2.0*a.Distance(b))
// MomentForBox2 calculates the moment of inertia for a solid box.
func MomentForBox2(mass float64, box BB) float64 {
width := box.R - box.L
height := box.T - box.B
offset := Vector{box.L + box.R, box.B + box.T}.Mult(0.5)

// TODO: NaN when offset is 0 and m is INFINITY
return MomentForBox(mass, width, height) + mass*offset.LengthSq()
}

// MomentForCircle calculates the moment of inertia for a circle.
//
// r1 and r2 are the inner and outer diameters. A solid circle has an inner diameter of 0.
func MomentForCircle(mass, r1, r2 float64, offset Vector) float64 {
return mass * (0.5*(r1*r1+r2*r2) + offset.LengthSq())
}

// MomentForSegment calculates the moment of inertia for a line segment.
//
// Beveling radius is not supported.
func MomentForSegment(mass float64, a, b Vector, r float64) float64 {
offset := a.Lerp(b, 0.5)
length := b.Distance(a) + 2.0*r
return mass * ((length*length+4.0*r*r)/12.0 + offset.LengthSq())
}

func MomentForPoly(m float64, count int, verts []Vector, offset Vector, r float64) float64 {
// MomentForPoly calculates the moment of inertia for a solid polygon shape assuming it's center of gravity is at it's centroid.
// The offset is added to each vertex.
func MomentForPoly(mass float64, count int, verts []Vector, offset Vector, r float64) float64 {
if count == 2 {
return MomentForSegment(m, verts[0], verts[1], 0)
return MomentForSegment(mass, verts[0], verts[1], 0)
}

var sum1 float64
Expand All @@ -207,9 +252,24 @@ func MomentForPoly(m float64, count int, verts []Vector, offset Vector, r float6
sum2 += a
}

return (m * sum1) / (6.0 * sum2)
return (mass * sum1) / (6.0 * sum2)
}

// AreaForCircle returns area of a hollow circle.
//
// r1 and r2 are the inner and outer diameters. A solid circle has an inner diameter of 0.
func AreaForCircle(r1, r2 float64) float64 {
return math.Pi * math.Abs(r1*r1-r2*r2)
}

// AreaForSegment calculates the area of a fattened (capsule shaped) line segment.
func AreaForSegment(a, b Vector, r float64) float64 {
return r * (math.Pi*r + 2.0*a.Distance(b))
}

// AreaForPoly calculates the signed area of a polygon.
//
// A Clockwise winding gives positive area. This is probably backwards from what you expect, but matches Chipmunk's the winding for poly shapes.
func AreaForPoly(count int, verts []Vector, r float64) float64 {
var area float64
var perimeter float64
Expand All @@ -224,6 +284,7 @@ func AreaForPoly(count int, verts []Vector, r float64) float64 {
return r*(math.Pi*math.Abs(r)+perimeter) + area/2.0
}

// CentroidForPoly calculates the natural centroid of a polygon.
func CentroidForPoly(count int, verts []Vector) Vector {
var sum float64
vsum := Vector{}
Expand All @@ -240,17 +301,39 @@ func CentroidForPoly(count int, verts []Vector) Vector {
return vsum.Mult(1.0 / (3.0 * sum))
}

func MomentForBox(m, width, height float64) float64 {
return m * (width*width + height*height) / 12.0
}
// DebugInfo returns info of space
func DebugInfo(space *Space) string {
arbiters := len(space.arbiters)
points := 0

func MomentForBox2(m float64, box BB) float64 {
width := box.R - box.L
height := box.T - box.B
offset := Vector{box.L + box.R, box.B + box.T}.Mult(0.5)
for i := 0; i < arbiters; i++ {
points += int(space.arbiters[i].count)
}

// TODO: NaN when offset is 0 and m is INFINITY
return MomentForBox(m, width, height) + m*offset.LengthSq()
constraints := len(space.constraints) + points*int(space.Iterations)
if arbiters > maxArbiters {
maxArbiters = arbiters
}
if points > maxPoints {
maxPoints = points
}
if constraints > maxConstraints {
maxConstraints = constraints
}

var ke float64
for _, body := range space.dynamicBodies {
if body.m == INFINITY || body.i == INFINITY {
continue
}
ke += body.m*body.v.Dot(body.v) + body.i*body.w*body.w
}

return fmt.Sprintf(`Arbiters: %d (%d) - Contact Points: %d (%d)
Other Constraints: %d, Iterations: %d
Constraints x Iterations: %d (%d)
KE: %e`, arbiters, maxArbiters,
points, maxPoints, len(space.constraints), space.Iterations, constraints, maxConstraints, ke)
}

func k_scalar_body(body *Body, r, n Vector) float64 {
Expand Down Expand Up @@ -310,46 +393,4 @@ func bias_coef(errorBias, dt float64) float64 {
return 1.0 - math.Pow(errorBias, dt)
}

type Mat2x2 struct {
a, b, c, d float64
}

func (m *Mat2x2) Transform(v Vector) Vector {
return Vector{v.X*m.a + v.Y*m.b, v.X*m.c + v.Y*m.d}
}

var maxArbiters, maxPoints, maxConstraints int

func DebugInfo(space *Space) string {
arbiters := len(space.arbiters)
points := 0

for i := 0; i < arbiters; i++ {
points += int(space.arbiters[i].count)
}

constraints := len(space.constraints) + points*int(space.Iterations)
if arbiters > maxArbiters {
maxArbiters = arbiters
}
if points > maxPoints {
maxPoints = points
}
if constraints > maxConstraints {
maxConstraints = constraints
}

var ke float64
for _, body := range space.dynamicBodies {
if body.m == INFINITY || body.i == INFINITY {
continue
}
ke += body.m*body.v.Dot(body.v) + body.i*body.w*body.w
}

return fmt.Sprintf(`Arbiters: %d (%d) - Contact Points: %d (%d)
Other Constraints: %d, Iterations: %d
Constraints x Iterations: %d (%d)
KE: %e`, arbiters, maxArbiters,
points, maxPoints, len(space.constraints), space.Iterations, constraints, maxConstraints, ke)
}
Loading