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

fix: Fix mtv calculation for both polygon-polygon as well as polygon-circle intersections. #24

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
55 changes: 50 additions & 5 deletions shape.go
Original file line number Diff line number Diff line change
Expand Up @@ -671,16 +671,46 @@ func (cp *ConvexPolygon) calculateMTV(contactSet *ContactSet, otherShape IShape)

}

// If the direction from target to source points opposite to the separation, invert the separation vector.
if cp.Center().Sub(other.Center()).Dot(smallest) < 0 {
smallest = smallest.Invert()
}

case *Circle:

verts := append([]Vector{}, cp.Transformed()...)
// The center point of a contact could also be closer than the verts, particularly if we're testing from a Circle to another Shape.
verts = append(verts, contactSet.Center)
center := other.position
sort.Slice(verts, func(i, j int) bool { return verts[i].Sub(center).Magnitude() < verts[j].Sub(center).Magnitude() })

smallest = Vector{center.X - verts[0].X, center.Y - verts[0].Y}
smallest = smallest.Unit().Scale(smallest.Magnitude() - other.radius)
axis := Vector{center.X - verts[0].X, center.Y - verts[0].Y}
pa := cp.Project(axis)
pb := other.Project(axis)
overlap := pa.Overlap(pb)
if overlap <= 0 {
return Vector{}, false
}
smallest = axis.Unit().Scale(overlap)

for _, axis := range cp.SATAxes() {
pa := cp.Project(axis)
pb := other.Project(axis)

overlap := pa.Overlap(pb)

if overlap <= 0 {
return Vector{}, false
}

if smallest.Magnitude() > overlap {
smallest = axis.Scale(overlap)
}

}

// If the direction from target to source points opposite to the separation, invert the separation vector
if cp.Center().Sub(other.position).Dot(smallest) < 0 {
smallest = smallest.Invert()
}

}

Expand Down Expand Up @@ -830,6 +860,21 @@ func (circle *Circle) Bounds() (Vector, Vector) {
return Vector{circle.position.X - circle.radius, circle.position.Y - circle.radius}, Vector{circle.position.X + circle.radius, circle.position.Y + circle.radius}
}

func (circle *Circle) Project(axis Vector) Projection {
axis = axis.Unit()
projectedCenter := axis.Dot(circle.position)
projectedRadius := axis.Magnitude() * circle.radius * circle.scale

min := projectedCenter - projectedRadius
max := projectedCenter + projectedRadius

if min > max {
min, max = max, min
}

return Projection{min, max}
}

// Intersection tests to see if a Circle intersects with the other given Shape. dx and dy are delta movement variables indicating
// movement to be applied before the intersection check (thereby allowing you to see if a Shape would collide with another if it
// were in a different relative location). If an Intersection is found, a ContactSet will be returned, giving information regarding
Expand Down Expand Up @@ -1188,7 +1233,7 @@ func (projection Projection) Overlapping(other Projection) bool {

// Overlap returns the amount that a Projection is overlapping with the other, provided Projection. Credit to https://dyn4j.org/2010/01/sat/#sat-nointer
func (projection Projection) Overlap(other Projection) float64 {
return math.Min(projection.Max, other.Max) - math.Max(projection.Min, other.Min)
return math.Min(projection.Max - other.Min, other.Max - projection.Min)
}

// IsInside returns whether the Projection is wholly inside of the other, provided Projection.
Expand Down