-
Notifications
You must be signed in to change notification settings - Fork 48
/
Copy pathCollisionB2CollideCircle.go
120 lines (100 loc) · 3.12 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
119
120
package box2d
func B2CollideCircles(manifold *B2Manifold, circleA *B2CircleShape, xfA B2Transform, circleB *B2CircleShape, xfB B2Transform) {
manifold.PointCount = 0
pA := B2TransformVec2Mul(xfA, circleA.M_p)
pB := B2TransformVec2Mul(xfB, circleB.M_p)
d := B2Vec2Sub(pB, pA)
distSqr := B2Vec2Dot(d, d)
rA := circleA.M_radius
rB := circleB.M_radius
radius := rA + rB
if distSqr > radius*radius {
return
}
manifold.Type = B2Manifold_Type.E_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 B2CollidePolygonAndCircle(manifold *B2Manifold, polygonA *B2PolygonShape, xfA B2Transform, circleB *B2CircleShape, xfB B2Transform) {
manifold.PointCount = 0
// Compute circle position in the frame of the polygon.
c := B2TransformVec2Mul(xfB, circleB.M_p)
cLocal := B2TransformVec2MulT(xfA, c)
// Find the min separating edge.
normalIndex := 0
separation := -B2_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 := B2Vec2Dot(normals[i], B2Vec2Sub(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 < B2_epsilon {
manifold.PointCount = 1
manifold.Type = B2Manifold_Type.E_faceA
manifold.LocalNormal = normals[normalIndex]
manifold.LocalPoint = B2Vec2MulScalar(0.5, B2Vec2Add(v1, v2))
manifold.Points[0].LocalPoint = circleB.M_p
manifold.Points[0].Id.SetKey(0)
return
}
// Compute barycentric coordinates
u1 := B2Vec2Dot(B2Vec2Sub(cLocal, v1), B2Vec2Sub(v2, v1))
u2 := B2Vec2Dot(B2Vec2Sub(cLocal, v2), B2Vec2Sub(v1, v2))
if u1 <= 0.0 {
if B2Vec2DistanceSquared(cLocal, v1) > radius*radius {
return
}
manifold.PointCount = 1
manifold.Type = B2Manifold_Type.E_faceA
manifold.LocalNormal = B2Vec2Sub(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 B2Vec2DistanceSquared(cLocal, v2) > radius*radius {
return
}
manifold.PointCount = 1
manifold.Type = B2Manifold_Type.E_faceA
manifold.LocalNormal = B2Vec2Sub(cLocal, v2)
manifold.LocalNormal.Normalize()
manifold.LocalPoint = v2
manifold.Points[0].LocalPoint = circleB.M_p
manifold.Points[0].Id.SetKey(0)
} else {
faceCenter := B2Vec2MulScalar(0.5, B2Vec2Add(v1, v2))
s := B2Vec2Dot(B2Vec2Sub(cLocal, faceCenter), normals[vertIndex1])
if s > radius {
return
}
manifold.PointCount = 1
manifold.Type = B2Manifold_Type.E_faceA
manifold.LocalNormal = normals[vertIndex1]
manifold.LocalPoint = faceCenter
manifold.Points[0].LocalPoint = circleB.M_p
manifold.Points[0].Id.SetKey(0)
}
}