forked from ByteArena/box2d
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCollisionB2CollideCircle.go
118 lines (100 loc) · 3.02 KB
/
CollisionB2CollideCircle.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package box2d
func CollideCircles(manifold *Manifold, circleA *CircleShape, xfA Transform, circleB *CircleShape, xfB Transform) {
manifold.PointCount = 0
pA := TransformVec2Mul(xfA, circleA.M_p)
pB := TransformVec2Mul(xfB, circleB.M_p)
d := Vec2Sub(pB, pA)
distSqr := Vec2Dot(d, d)
rA := circleA.M_radius
rB := circleB.M_radius
radius := rA + rB
if distSqr > radius*radius {
return
}
manifold.Type = ManifoldType.Circles
manifold.LocalPoint = circleA.M_p
manifold.LocalNormal.SetZero()
manifold.PointCount = 1
manifold.Points[0].LocalPoint = circleB.M_p
manifold.Points[0].Id.SetKey(0)
}
func CollidePolygonAndCircle(manifold *Manifold, polygonA *PolygonShape, xfA Transform, circleB *CircleShape, xfB Transform) {
manifold.PointCount = 0
// Compute circle position in the frame of the polygon.
c := TransformVec2Mul(xfB, circleB.M_p)
cLocal := TransformVec2MulT(xfA, c)
// Find the min separating edge.
normalIndex := 0
separation := -maxFloat
radius := polygonA.M_radius + circleB.M_radius
vertexCount := polygonA.M_count
vertices := polygonA.M_vertices
normals := polygonA.M_normals
for i := 0; i < vertexCount; i++ {
s := Vec2Dot(normals[i], Vec2Sub(cLocal, vertices[i]))
if s > radius {
// Early out.
return
}
if s > separation {
separation = s
normalIndex = i
}
}
// Vertices that subtend the incident face.
vertIndex1 := normalIndex
vertIndex2 := 0
if vertIndex1+1 < vertexCount {
vertIndex2 = vertIndex1 + 1
}
v1 := vertices[vertIndex1]
v2 := vertices[vertIndex2]
// If the center is inside the polygon ...
if separation < epsilon {
manifold.PointCount = 1
manifold.Type = ManifoldType.FaceA
manifold.LocalNormal = normals[normalIndex]
manifold.LocalPoint = Vec2MulScalar(0.5, Vec2Add(v1, v2))
manifold.Points[0].LocalPoint = circleB.M_p
manifold.Points[0].Id.SetKey(0)
return
}
// Compute barycentric coordinates
u1 := Vec2Dot(Vec2Sub(cLocal, v1), Vec2Sub(v2, v1))
u2 := Vec2Dot(Vec2Sub(cLocal, v2), Vec2Sub(v1, v2))
if u1 <= 0.0 {
if Vec2DistanceSquared(cLocal, v1) > radius*radius {
return
}
manifold.PointCount = 1
manifold.Type = ManifoldType.FaceA
manifold.LocalNormal = Vec2Sub(cLocal, v1)
manifold.LocalNormal.Normalize()
manifold.LocalPoint = v1
manifold.Points[0].LocalPoint = circleB.M_p
manifold.Points[0].Id.SetKey(0)
} else if u2 <= 0.0 {
if Vec2DistanceSquared(cLocal, v2) > radius*radius {
return
}
manifold.PointCount = 1
manifold.Type = ManifoldType.FaceA
manifold.LocalNormal = Vec2Sub(cLocal, v2)
manifold.LocalNormal.Normalize()
manifold.LocalPoint = v2
manifold.Points[0].LocalPoint = circleB.M_p
manifold.Points[0].Id.SetKey(0)
} else {
faceCenter := Vec2MulScalar(0.5, Vec2Add(v1, v2))
s := Vec2Dot(Vec2Sub(cLocal, faceCenter), normals[vertIndex1])
if s > radius {
return
}
manifold.PointCount = 1
manifold.Type = ManifoldType.FaceA
manifold.LocalNormal = normals[vertIndex1]
manifold.LocalPoint = faceCenter
manifold.Points[0].LocalPoint = circleB.M_p
manifold.Points[0].Id.SetKey(0)
}
}