chipmunk 5.3.4.5 → 6.1.3.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. data/ext/chipmunk/chipmunk.c +199 -28
  2. data/ext/chipmunk/chipmunk.h +123 -68
  3. data/ext/chipmunk/chipmunk_ffi.h +129 -11
  4. data/ext/chipmunk/chipmunk_private.h +232 -16
  5. data/ext/chipmunk/chipmunk_types.h +94 -30
  6. data/ext/chipmunk/chipmunk_unsafe.h +12 -3
  7. data/ext/chipmunk/constraints/cpConstraint.h +90 -34
  8. data/ext/chipmunk/{cpDampedRotarySpring.h → constraints/cpDampedRotarySpring.h} +18 -8
  9. data/ext/chipmunk/{cpDampedSpring.h → constraints/cpDampedSpring.h} +27 -16
  10. data/ext/chipmunk/constraints/cpGearJoint.h +17 -7
  11. data/ext/chipmunk/constraints/cpGrooveJoint.h +19 -10
  12. data/ext/chipmunk/constraints/cpPinJoint.h +17 -8
  13. data/ext/chipmunk/constraints/cpPivotJoint.h +18 -9
  14. data/ext/chipmunk/constraints/cpRatchetJoint.h +17 -8
  15. data/ext/chipmunk/constraints/cpRotaryLimitJoint.h +16 -7
  16. data/ext/chipmunk/{cpSimpleMotor.h → constraints/cpSimpleMotor.h} +15 -6
  17. data/ext/chipmunk/constraints/cpSlideJoint.h +18 -9
  18. data/ext/chipmunk/constraints/util.h +36 -44
  19. data/ext/chipmunk/cpArbiter.c +159 -94
  20. data/ext/chipmunk/cpArbiter.h +135 -129
  21. data/ext/chipmunk/cpArray.c +37 -56
  22. data/ext/chipmunk/cpBB.c +1 -12
  23. data/ext/chipmunk/cpBB.h +80 -18
  24. data/ext/chipmunk/cpBBTree.c +891 -0
  25. data/ext/chipmunk/cpBody.c +185 -47
  26. data/ext/chipmunk/cpBody.h +156 -124
  27. data/ext/chipmunk/cpCollision.c +126 -115
  28. data/ext/chipmunk/cpConstraint.c +10 -6
  29. data/ext/chipmunk/cpDampedRotarySpring.c +26 -17
  30. data/ext/chipmunk/cpDampedSpring.c +25 -18
  31. data/ext/chipmunk/cpGearJoint.c +23 -17
  32. data/ext/chipmunk/cpGrooveJoint.c +26 -22
  33. data/ext/chipmunk/cpHashSet.c +51 -51
  34. data/ext/chipmunk/cpPinJoint.c +26 -19
  35. data/ext/chipmunk/cpPivotJoint.c +23 -19
  36. data/ext/chipmunk/cpPolyShape.c +93 -69
  37. data/ext/chipmunk/cpPolyShape.h +33 -69
  38. data/ext/chipmunk/cpRatchetJoint.c +26 -21
  39. data/ext/chipmunk/cpRotaryLimitJoint.c +28 -22
  40. data/ext/chipmunk/cpShape.c +122 -133
  41. data/ext/chipmunk/cpShape.h +146 -95
  42. data/ext/chipmunk/cpSimpleMotor.c +24 -17
  43. data/ext/chipmunk/cpSlideJoint.c +28 -26
  44. data/ext/chipmunk/cpSpace.c +251 -196
  45. data/ext/chipmunk/cpSpace.h +173 -103
  46. data/ext/chipmunk/cpSpaceComponent.c +236 -159
  47. data/ext/chipmunk/cpSpaceHash.c +259 -159
  48. data/ext/chipmunk/cpSpaceQuery.c +127 -59
  49. data/ext/chipmunk/cpSpaceStep.c +235 -197
  50. data/ext/chipmunk/cpSpatialIndex.c +69 -0
  51. data/ext/chipmunk/cpSpatialIndex.h +227 -0
  52. data/ext/chipmunk/cpSweep1D.c +254 -0
  53. data/ext/chipmunk/cpVect.c +11 -26
  54. data/ext/chipmunk/cpVect.h +76 -71
  55. data/ext/chipmunk/extconf.rb +4 -31
  56. data/ext/chipmunk/prime.h +1 -1
  57. data/ext/chipmunk/rb_chipmunk.c +36 -45
  58. data/ext/chipmunk/rb_chipmunk.h +6 -3
  59. data/ext/chipmunk/rb_cpArbiter.c +2 -2
  60. data/ext/chipmunk/rb_cpBB.c +116 -35
  61. data/ext/chipmunk/rb_cpBody.c +5 -12
  62. data/ext/chipmunk/rb_cpConstraint.c +144 -9
  63. data/ext/chipmunk/rb_cpShape.c +69 -78
  64. data/ext/chipmunk/rb_cpSpace.c +81 -76
  65. metadata +61 -61
  66. data/LICENSE +0 -22
  67. data/README +0 -110
  68. data/Rakefile +0 -102
  69. data/ext/chipmunk/cpArray.h +0 -49
  70. data/ext/chipmunk/cpCollision.h +0 -28
  71. data/ext/chipmunk/cpHashSet.h +0 -82
  72. data/ext/chipmunk/cpSpaceHash.h +0 -110
  73. data/lib/chipmunk.rb +0 -194
@@ -19,85 +19,49 @@
19
19
  * SOFTWARE.
20
20
  */
21
21
 
22
- // Axis structure used by cpPolyShape.
23
- typedef struct cpPolyShapeAxis{
24
- // normal
22
+ /// @defgroup cpPolyShape cpPolyShape
23
+ /// @{
24
+
25
+ /// @private
26
+ typedef struct cpSplittingPlane {
25
27
  cpVect n;
26
- // distance from origin
27
28
  cpFloat d;
28
- } cpPolyShapeAxis;
29
+ } cpSplittingPlane;
29
30
 
30
- // Convex polygon shape structure.
31
- typedef struct cpPolyShape{
32
- CP_PRIVATE(cpShape shape);
31
+ /// @private
32
+ typedef struct cpPolyShape {
33
+ cpShape shape;
33
34
 
34
- // Vertex and axis lists.
35
- CP_PRIVATE(int numVerts);
36
- CP_PRIVATE(cpVect *verts);
37
- CP_PRIVATE(cpPolyShapeAxis *axes);
38
-
39
- // Transformed vertex and axis lists.
40
- CP_PRIVATE(cpVect *tVerts);
41
- CP_PRIVATE(cpPolyShapeAxis *tAxes);
35
+ int numVerts;
36
+ cpVect *verts, *tVerts;
37
+ cpSplittingPlane *planes, *tPlanes;
42
38
  } cpPolyShape;
43
39
 
44
- // Basic allocation functions.
45
- cpPolyShape *cpPolyShapeAlloc(void);
46
- cpPolyShape *cpPolyShapeInit(cpPolyShape *poly, cpBody *body, int numVerts, cpVect *verts, cpVect offset);
47
- cpShape *cpPolyShapeNew(cpBody *body, int numVerts, cpVect *verts, cpVect offset);
40
+ /// Allocate a polygon shape.
41
+ cpPolyShape* cpPolyShapeAlloc(void);
42
+ /// Initialize a polygon shape.
43
+ /// A convex hull will be created from the vertexes.
44
+ cpPolyShape* cpPolyShapeInit(cpPolyShape *poly, cpBody *body, int numVerts, const cpVect *verts, cpVect offset);
45
+ /// Allocate and initialize a polygon shape.
46
+ /// A convex hull will be created from the vertexes.
47
+ cpShape* cpPolyShapeNew(cpBody *body, int numVerts, cpVect *verts, cpVect offset);
48
48
 
49
- cpPolyShape *cpBoxShapeInit(cpPolyShape *poly, cpBody *body, cpFloat width, cpFloat height);
50
- cpShape *cpBoxShapeNew(cpBody *body, cpFloat width, cpFloat height);
49
+ /// Initialize a box shaped polygon shape.
50
+ cpPolyShape* cpBoxShapeInit(cpPolyShape *poly, cpBody *body, cpFloat width, cpFloat height);
51
+ /// Initialize an offset box shaped polygon shape.
52
+ cpPolyShape* cpBoxShapeInit2(cpPolyShape *poly, cpBody *body, cpBB box);
53
+ /// Allocate and initialize a box shaped polygon shape.
54
+ cpShape* cpBoxShapeNew(cpBody *body, cpFloat width, cpFloat height);
55
+ /// Allocate and initialize an offset box shaped polygon shape.
56
+ cpShape* cpBoxShapeNew2(cpBody *body, cpBB box);
51
57
 
52
- // Check that a set of vertexes has a correct winding and that they are convex
58
+ /// Check that a set of vertexes is convex and has a clockwise winding.
59
+ /// NOTE: Due to floating point precision issues, hulls created with cpQuickHull() are not guaranteed to validate!
53
60
  cpBool cpPolyValidate(const cpVect *verts, const int numVerts);
54
61
 
62
+ /// Get the number of verts in a polygon shape.
55
63
  int cpPolyShapeGetNumVerts(cpShape *shape);
64
+ /// Get the @c ith vertex of a polygon shape.
56
65
  cpVect cpPolyShapeGetVert(cpShape *shape, int idx);
57
66
 
58
- // *** inlined utility functions
59
-
60
- // Returns the minimum distance of the polygon to the axis.
61
- static inline cpFloat
62
- cpPolyShapeValueOnAxis(const cpPolyShape *poly, const cpVect n, const cpFloat d)
63
- {
64
- cpVect *verts = poly->CP_PRIVATE(tVerts);
65
- cpFloat min = cpvdot(n, verts[0]);
66
-
67
- int i;
68
- for(i=1; i<poly->CP_PRIVATE(numVerts); i++)
69
- min = cpfmin(min, cpvdot(n, verts[i]));
70
-
71
- return min - d;
72
- }
73
-
74
- // Returns true if the polygon contains the vertex.
75
- static inline cpBool
76
- cpPolyShapeContainsVert(const cpPolyShape *poly, const cpVect v)
77
- {
78
- cpPolyShapeAxis *axes = poly->CP_PRIVATE(tAxes);
79
-
80
- int i;
81
- for(i=0; i<poly->CP_PRIVATE(numVerts); i++){
82
- cpFloat dist = cpvdot(axes[i].n, v) - axes[i].d;
83
- if(dist > 0.0f) return cpFalse;
84
- }
85
-
86
- return cpTrue;
87
- }
88
-
89
- // Same as cpPolyShapeContainsVert() but ignores faces pointing away from the normal.
90
- static inline cpBool
91
- cpPolyShapeContainsVertPartial(const cpPolyShape *poly, const cpVect v, const cpVect n)
92
- {
93
- cpPolyShapeAxis *axes = poly->CP_PRIVATE(tAxes);
94
-
95
- int i;
96
- for(i=0; i<poly->CP_PRIVATE(numVerts); i++){
97
- if(cpvdot(axes[i].n, n) < 0.0f) continue;
98
- cpFloat dist = cpvdot(axes[i].n, v) - axes[i].d;
99
- if(dist > 0.0f) return cpFalse;
100
- }
101
-
102
- return cpTrue;
103
- }
67
+ /// @}
@@ -19,16 +19,14 @@
19
19
  * SOFTWARE.
20
20
  */
21
21
 
22
- #include <stdlib.h>
23
- #include <math.h>
24
-
25
22
  #include "chipmunk_private.h"
26
23
  #include "constraints/util.h"
27
24
 
28
25
  static void
29
- preStep(cpRatchetJoint *joint, cpFloat dt, cpFloat dt_inv)
26
+ preStep(cpRatchetJoint *joint, cpFloat dt)
30
27
  {
31
- CONSTRAINT_BEGIN(joint, a, b);
28
+ cpBody *a = joint->constraint.a;
29
+ cpBody *b = joint->constraint.b;
32
30
 
33
31
  cpFloat angle = joint->angle;
34
32
  cpFloat phase = joint->phase;
@@ -49,35 +47,41 @@ preStep(cpRatchetJoint *joint, cpFloat dt, cpFloat dt_inv)
49
47
 
50
48
  // calculate bias velocity
51
49
  cpFloat maxBias = joint->constraint.maxBias;
52
- joint->bias = cpfclamp(-joint->constraint.biasCoef*dt_inv*pdist, -maxBias, maxBias);
53
-
54
- // compute max impulse
55
- joint->jMax = J_MAX(joint, dt);
50
+ joint->bias = cpfclamp(-bias_coef(joint->constraint.errorBias, dt)*pdist/dt, -maxBias, maxBias);
56
51
 
57
52
  // If the bias is 0, the joint is not at a limit. Reset the impulse.
58
- if(!joint->bias)
59
- joint->jAcc = 0.0f;
53
+ if(!joint->bias) joint->jAcc = 0.0f;
54
+ }
60
55
 
61
- // apply joint torque
62
- a->w -= joint->jAcc*a->i_inv;
63
- b->w += joint->jAcc*b->i_inv;
56
+ static void
57
+ applyCachedImpulse(cpRatchetJoint *joint, cpFloat dt_coef)
58
+ {
59
+ cpBody *a = joint->constraint.a;
60
+ cpBody *b = joint->constraint.b;
61
+
62
+ cpFloat j = joint->jAcc*dt_coef;
63
+ a->w -= j*a->i_inv;
64
+ b->w += j*b->i_inv;
64
65
  }
65
66
 
66
67
  static void
67
- applyImpulse(cpRatchetJoint *joint)
68
+ applyImpulse(cpRatchetJoint *joint, cpFloat dt)
68
69
  {
69
70
  if(!joint->bias) return; // early exit
70
71
 
71
- CONSTRAINT_BEGIN(joint, a, b);
72
+ cpBody *a = joint->constraint.a;
73
+ cpBody *b = joint->constraint.b;
72
74
 
73
75
  // compute relative rotational velocity
74
76
  cpFloat wr = b->w - a->w;
75
77
  cpFloat ratchet = joint->ratchet;
76
78
 
79
+ cpFloat jMax = joint->constraint.maxForce*dt;
80
+
77
81
  // compute normal impulse
78
82
  cpFloat j = -(joint->bias + wr)*joint->iSum;
79
83
  cpFloat jOld = joint->jAcc;
80
- joint->jAcc = cpfclamp((jOld + j)*ratchet, 0.0f, joint->jMax*cpfabs(ratchet))/ratchet;
84
+ joint->jAcc = cpfclamp((jOld + j)*ratchet, 0.0f, jMax*cpfabs(ratchet))/ratchet;
81
85
  j = joint->jAcc - jOld;
82
86
 
83
87
  // apply impulse
@@ -92,16 +96,17 @@ getImpulse(cpRatchetJoint *joint)
92
96
  }
93
97
 
94
98
  static const cpConstraintClass klass = {
95
- (cpConstraintPreStepFunction)preStep,
96
- (cpConstraintApplyImpulseFunction)applyImpulse,
97
- (cpConstraintGetImpulseFunction)getImpulse,
99
+ (cpConstraintPreStepImpl)preStep,
100
+ (cpConstraintApplyCachedImpulseImpl)applyCachedImpulse,
101
+ (cpConstraintApplyImpulseImpl)applyImpulse,
102
+ (cpConstraintGetImpulseImpl)getImpulse,
98
103
  };
99
104
  CP_DefineClassGetter(cpRatchetJoint)
100
105
 
101
106
  cpRatchetJoint *
102
107
  cpRatchetJointAlloc(void)
103
108
  {
104
- return (cpRatchetJoint *)cpmalloc(sizeof(cpRatchetJoint));
109
+ return (cpRatchetJoint *)cpcalloc(1, sizeof(cpRatchetJoint));
105
110
  }
106
111
 
107
112
  cpRatchetJoint *
@@ -19,15 +19,14 @@
19
19
  * SOFTWARE.
20
20
  */
21
21
 
22
- #include <stdlib.h>
23
-
24
22
  #include "chipmunk_private.h"
25
23
  #include "constraints/util.h"
26
24
 
27
25
  static void
28
- preStep(cpRotaryLimitJoint *joint, cpFloat dt, cpFloat dt_inv)
26
+ preStep(cpRotaryLimitJoint *joint, cpFloat dt)
29
27
  {
30
- CONSTRAINT_BEGIN(joint, a, b);
28
+ cpBody *a = joint->constraint.a;
29
+ cpBody *b = joint->constraint.b;
31
30
 
32
31
  cpFloat dist = b->a - a->a;
33
32
  cpFloat pdist = 0.0f;
@@ -38,41 +37,47 @@ preStep(cpRotaryLimitJoint *joint, cpFloat dt, cpFloat dt_inv)
38
37
  }
39
38
 
40
39
  // calculate moment of inertia coefficient.
41
- joint->iSum = 1.0f/(a->i_inv + b->i_inv);
40
+ joint->iSum = 1.0f/(1.0f/a->i + 1.0f/b->i);
42
41
 
43
42
  // calculate bias velocity
44
43
  cpFloat maxBias = joint->constraint.maxBias;
45
- joint->bias = cpfclamp(-joint->constraint.biasCoef*dt_inv*(pdist), -maxBias, maxBias);
46
-
47
- // compute max impulse
48
- joint->jMax = J_MAX(joint, dt);
44
+ joint->bias = cpfclamp(-bias_coef(joint->constraint.errorBias, dt)*pdist/dt, -maxBias, maxBias);
49
45
 
50
46
  // If the bias is 0, the joint is not at a limit. Reset the impulse.
51
- if(!joint->bias)
52
- joint->jAcc = 0.0f;
47
+ if(!joint->bias) joint->jAcc = 0.0f;
48
+ }
53
49
 
54
- // apply joint torque
55
- a->w -= joint->jAcc*a->i_inv;
56
- b->w += joint->jAcc*b->i_inv;
50
+ static void
51
+ applyCachedImpulse(cpRotaryLimitJoint *joint, cpFloat dt_coef)
52
+ {
53
+ cpBody *a = joint->constraint.a;
54
+ cpBody *b = joint->constraint.b;
55
+
56
+ cpFloat j = joint->jAcc*dt_coef;
57
+ a->w -= j*a->i_inv;
58
+ b->w += j*b->i_inv;
57
59
  }
58
60
 
59
61
  static void
60
- applyImpulse(cpRotaryLimitJoint *joint)
62
+ applyImpulse(cpRotaryLimitJoint *joint, cpFloat dt)
61
63
  {
62
64
  if(!joint->bias) return; // early exit
63
65
 
64
- CONSTRAINT_BEGIN(joint, a, b);
66
+ cpBody *a = joint->constraint.a;
67
+ cpBody *b = joint->constraint.b;
65
68
 
66
69
  // compute relative rotational velocity
67
70
  cpFloat wr = b->w - a->w;
68
71
 
72
+ cpFloat jMax = joint->constraint.maxForce*dt;
73
+
69
74
  // compute normal impulse
70
75
  cpFloat j = -(joint->bias + wr)*joint->iSum;
71
76
  cpFloat jOld = joint->jAcc;
72
77
  if(joint->bias < 0.0f){
73
- joint->jAcc = cpfclamp(jOld + j, 0.0f, joint->jMax);
78
+ joint->jAcc = cpfclamp(jOld + j, 0.0f, jMax);
74
79
  } else {
75
- joint->jAcc = cpfclamp(jOld + j, -joint->jMax, 0.0f);
80
+ joint->jAcc = cpfclamp(jOld + j, -jMax, 0.0f);
76
81
  }
77
82
  j = joint->jAcc - jOld;
78
83
 
@@ -88,16 +93,17 @@ getImpulse(cpRotaryLimitJoint *joint)
88
93
  }
89
94
 
90
95
  static const cpConstraintClass klass = {
91
- (cpConstraintPreStepFunction)preStep,
92
- (cpConstraintApplyImpulseFunction)applyImpulse,
93
- (cpConstraintGetImpulseFunction)getImpulse,
96
+ (cpConstraintPreStepImpl)preStep,
97
+ (cpConstraintApplyCachedImpulseImpl)applyCachedImpulse,
98
+ (cpConstraintApplyImpulseImpl)applyImpulse,
99
+ (cpConstraintGetImpulseImpl)getImpulse,
94
100
  };
95
101
  CP_DefineClassGetter(cpRotaryLimitJoint)
96
102
 
97
103
  cpRotaryLimitJoint *
98
104
  cpRotaryLimitJointAlloc(void)
99
105
  {
100
- return (cpRotaryLimitJoint *)cpmalloc(sizeof(cpRotaryLimitJoint));
106
+ return (cpRotaryLimitJoint *)cpcalloc(1, sizeof(cpRotaryLimitJoint));
101
107
  }
102
108
 
103
109
  cpRotaryLimitJoint *
@@ -19,24 +19,21 @@
19
19
  * SOFTWARE.
20
20
  */
21
21
 
22
- #include <stdlib.h>
23
- #include <stdio.h>
24
- #include <math.h>
25
-
26
22
  #include "chipmunk_private.h"
27
23
  #include "chipmunk_unsafe.h"
28
24
 
29
25
  #define CP_DefineShapeGetter(struct, type, member, name) \
30
26
  CP_DeclareShapeGetter(struct, type, name){ \
31
- cpAssert(shape->klass == &struct##Class, "shape is not a "#struct); \
27
+ cpAssertHard(shape->klass == &struct##Class, "shape is not a "#struct); \
32
28
  return ((struct *)shape)->member; \
33
29
  }
34
- cpHashValue SHAPE_ID_COUNTER = 0;
30
+
31
+ static cpHashValue cpShapeIDCounter = 0;
35
32
 
36
33
  void
37
34
  cpResetShapeIdCounter(void)
38
35
  {
39
- SHAPE_ID_COUNTER = 0;
36
+ cpShapeIDCounter = 0;
40
37
  }
41
38
 
42
39
 
@@ -45,8 +42,8 @@ cpShapeInit(cpShape *shape, const cpShapeClass *klass, cpBody *body)
45
42
  {
46
43
  shape->klass = klass;
47
44
 
48
- shape->hashid = SHAPE_ID_COUNTER;
49
- SHAPE_ID_COUNTER++;
45
+ shape->hashid = cpShapeIDCounter;
46
+ cpShapeIDCounter++;
50
47
 
51
48
  shape->body = body;
52
49
  shape->sensor = 0;
@@ -60,9 +57,11 @@ cpShapeInit(cpShape *shape, const cpShapeClass *klass, cpBody *body)
60
57
  shape->layers = CP_ALL_LAYERS;
61
58
 
62
59
  shape->data = NULL;
63
- shape->next = NULL;
64
60
 
65
- // cpShapeCacheBB(shape);
61
+ shape->space = NULL;
62
+
63
+ shape->next = NULL;
64
+ shape->prev = NULL;
66
65
 
67
66
  return shape;
68
67
  }
@@ -70,9 +69,7 @@ cpShapeInit(cpShape *shape, const cpShapeClass *klass, cpBody *body)
70
69
  void
71
70
  cpShapeDestroy(cpShape *shape)
72
71
  {
73
- if(shape->klass && shape->klass->destroy) {
74
- shape->klass->destroy(shape);
75
- }
72
+ if(shape->klass && shape->klass->destroy) shape->klass->destroy(shape);
76
73
  }
77
74
 
78
75
  void
@@ -84,68 +81,85 @@ cpShapeFree(cpShape *shape)
84
81
  }
85
82
  }
86
83
 
87
- // TODO this function should really take a position and rotation explicitly and be renamed
84
+ void
85
+ cpShapeSetBody(cpShape *shape, cpBody *body)
86
+ {
87
+ cpAssertHard(!cpShapeActive(shape), "You cannot change the body on an active shape. You must remove the shape from the space before changing the body.");
88
+ shape->body = body;
89
+ }
90
+
88
91
  cpBB
89
92
  cpShapeCacheBB(cpShape *shape)
90
93
  {
91
94
  cpBody *body = shape->body;
92
-
93
- shape->bb = shape->klass->cacheData(shape, body->p, body->rot);
94
- return shape->bb;
95
+ return cpShapeUpdate(shape, body->p, body->rot);
96
+ }
97
+
98
+ cpBB
99
+ cpShapeUpdate(cpShape *shape, cpVect pos, cpVect rot)
100
+ {
101
+ return (shape->bb = shape->klass->cacheData(shape, pos, rot));
95
102
  }
96
103
 
97
104
  cpBool
98
105
  cpShapePointQuery(cpShape *shape, cpVect p){
99
- return shape->klass->pointQuery(shape, p);
106
+ cpNearestPointQueryInfo info = {NULL, cpvzero, INFINITY};
107
+ cpShapeNearestPointQuery(shape, p, &info);
108
+
109
+ return (info.d < 0.0f);
110
+ }
111
+
112
+ cpFloat
113
+ cpShapeNearestPointQuery(cpShape *shape, cpVect p, cpNearestPointQueryInfo *info)
114
+ {
115
+ cpNearestPointQueryInfo blank = {NULL, cpvzero, INFINITY};
116
+ if(info){
117
+ (*info) = blank;
118
+ } else {
119
+ info = &blank;
120
+ }
121
+
122
+ shape->klass->nearestPointQuery(shape, p, info);
123
+ return info->d;
100
124
  }
101
125
 
126
+
102
127
  cpBool
103
128
  cpShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info){
104
129
  cpSegmentQueryInfo blank = {NULL, 0.0f, cpvzero};
105
- (*info) = blank;
130
+ if(info){
131
+ (*info) = blank;
132
+ } else {
133
+ info = &blank;
134
+ }
106
135
 
107
136
  shape->klass->segmentQuery(shape, a, b, info);
108
137
  return (info->shape != NULL);
109
138
  }
110
139
 
111
- void
112
- cpSegmentQueryInfoPrint(cpSegmentQueryInfo *info)
113
- {
114
- printf("Segment Query:\n");
115
- printf("\tt: %f\n", info->t);
116
- // printf("\tdist: %f\n", info->dist);
117
- // printf("\tpoint: %s\n", cpvstr(info->point));
118
- printf("\tn: %s\n", cpvstr(info->n));
119
- }
120
-
121
-
122
-
123
-
124
140
  cpCircleShape *
125
141
  cpCircleShapeAlloc(void)
126
142
  {
127
143
  return (cpCircleShape *)cpcalloc(1, sizeof(cpCircleShape));
128
144
  }
129
145
 
130
- static inline cpBB
131
- bbFromCircle(const cpVect c, const cpFloat r)
146
+ static cpBB
147
+ cpCircleShapeCacheData(cpCircleShape *circle, cpVect p, cpVect rot)
132
148
  {
133
- return cpBBNew(c.x-r, c.y-r, c.x+r, c.y+r);
149
+ cpVect c = circle->tc = cpvadd(p, cpvrotate(circle->c, rot));
150
+ return cpBBNewForCircle(c, circle->r);
134
151
  }
135
152
 
136
- static cpBB
137
- cpCircleShapeCacheData(cpShape *shape, cpVect p, cpVect rot)
153
+ static void
154
+ cpCicleShapeNearestPointQuery(cpCircleShape *circle, cpVect p, cpNearestPointQueryInfo *info)
138
155
  {
139
- cpCircleShape *circle = (cpCircleShape *)shape;
156
+ cpVect delta = cpvsub(p, circle->tc);
157
+ cpFloat d = cpvlength(delta);
158
+ cpFloat r = circle->r;
140
159
 
141
- circle->tc = cpvadd(p, cpvrotate(circle->c, rot));
142
- return bbFromCircle(circle->tc, circle->r);
143
- }
144
-
145
- static cpBool
146
- cpCircleShapePointQuery(cpShape *shape, cpVect p){
147
- cpCircleShape *circle = (cpCircleShape *)shape;
148
- return cpvnear(circle->tc, p, circle->r);
160
+ info->shape = (cpShape *)circle;
161
+ info->p = cpvadd(circle->tc, cpvmult(delta, r/d)); // TODO div/0
162
+ info->d = d - r;
149
163
  }
150
164
 
151
165
  static void
@@ -172,18 +186,17 @@ circleSegmentQuery(cpShape *shape, cpVect center, cpFloat r, cpVect a, cpVect b,
172
186
  }
173
187
 
174
188
  static void
175
- cpCircleShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info)
189
+ cpCircleShapeSegmentQuery(cpCircleShape *circle, cpVect a, cpVect b, cpSegmentQueryInfo *info)
176
190
  {
177
- cpCircleShape *circle = (cpCircleShape *)shape;
178
- circleSegmentQuery(shape, circle->tc, circle->r, a, b, info);
191
+ circleSegmentQuery((cpShape *)circle, circle->tc, circle->r, a, b, info);
179
192
  }
180
193
 
181
194
  static const cpShapeClass cpCircleShapeClass = {
182
195
  CP_CIRCLE_SHAPE,
183
- cpCircleShapeCacheData,
196
+ (cpShapeCacheDataImpl)cpCircleShapeCacheData,
184
197
  NULL,
185
- cpCircleShapePointQuery,
186
- cpCircleShapeSegmentQuery,
198
+ (cpShapeNearestPointQueryImpl)cpCicleShapeNearestPointQuery,
199
+ (cpShapeSegmentQueryImpl)cpCircleShapeSegmentQuery,
187
200
  };
188
201
 
189
202
  cpCircleShape *
@@ -213,15 +226,13 @@ cpSegmentShapeAlloc(void)
213
226
  }
214
227
 
215
228
  static cpBB
216
- cpSegmentShapeCacheData(cpShape *shape, cpVect p, cpVect rot)
229
+ cpSegmentShapeCacheData(cpSegmentShape *seg, cpVect p, cpVect rot)
217
230
  {
218
- cpSegmentShape *seg = (cpSegmentShape *)shape;
219
-
220
231
  seg->ta = cpvadd(p, cpvrotate(seg->a, rot));
221
232
  seg->tb = cpvadd(p, cpvrotate(seg->b, rot));
222
233
  seg->tn = cpvrotate(seg->n, rot);
223
234
 
224
- cpFloat l,r,s,t;
235
+ cpFloat l,r,b,t;
225
236
 
226
237
  if(seg->ta.x < seg->tb.x){
227
238
  l = seg->ta.x;
@@ -232,96 +243,61 @@ cpSegmentShapeCacheData(cpShape *shape, cpVect p, cpVect rot)
232
243
  }
233
244
 
234
245
  if(seg->ta.y < seg->tb.y){
235
- s = seg->ta.y;
246
+ b = seg->ta.y;
236
247
  t = seg->tb.y;
237
248
  } else {
238
- s = seg->tb.y;
249
+ b = seg->tb.y;
239
250
  t = seg->ta.y;
240
251
  }
241
252
 
242
253
  cpFloat rad = seg->r;
243
- return cpBBNew(l - rad, s - rad, r + rad, t + rad);
254
+ return cpBBNew(l - rad, b - rad, r + rad, t + rad);
244
255
  }
245
256
 
246
- static cpBool
247
- cpSegmentShapePointQuery(cpShape *shape, cpVect p){
248
- if(!cpBBcontainsVect(shape->bb, p)) return cpFalse;
249
-
250
- cpSegmentShape *seg = (cpSegmentShape *)shape;
251
-
252
- // Calculate normal distance from segment.
253
- cpFloat dn = cpvdot(seg->tn, p) - cpvdot(seg->ta, seg->tn);
254
- cpFloat dist = cpfabs(dn) - seg->r;
255
- if(dist > 0.0f) return cpFalse;
257
+ static void
258
+ cpSegmentShapeNearestPointQuery(cpSegmentShape *seg, cpVect p, cpNearestPointQueryInfo *info)
259
+ {
260
+ cpVect closest = cpClosetPointOnSegment(p, seg->ta, seg->tb);
256
261
 
257
- // Calculate tangential distance along segment.
258
- cpFloat dt = -cpvcross(seg->tn, p);
259
- cpFloat dtMin = -cpvcross(seg->tn, seg->ta);
260
- cpFloat dtMax = -cpvcross(seg->tn, seg->tb);
262
+ cpVect delta = cpvsub(p, closest);
263
+ cpFloat d = cpvlength(delta);
264
+ cpFloat r = seg->r;
261
265
 
262
- // Decision tree to decide which feature of the segment to collide with.
263
- if(dt <= dtMin){
264
- if(dt < (dtMin - seg->r)){
265
- return cpFalse;
266
- } else {
267
- return cpvlengthsq(cpvsub(seg->ta, p)) < (seg->r*seg->r);
268
- }
269
- } else {
270
- if(dt < dtMax){
271
- return cpTrue;
272
- } else {
273
- if(dt < (dtMax + seg->r)) {
274
- return cpvlengthsq(cpvsub(seg->tb, p)) < (seg->r*seg->r);
275
- } else {
276
- return cpFalse;
277
- }
278
- }
279
- }
280
-
281
- return cpTrue;
266
+ info->shape = (cpShape *)seg;
267
+ info->p = (d ? cpvadd(closest, cpvmult(delta, r/d)) : closest);
268
+ info->d = d - r;
282
269
  }
283
270
 
284
- static inline cpBool inUnitRange(cpFloat t){return (0.0f < t && t < 1.0f);}
285
-
286
271
  static void
287
- cpSegmentShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info)
272
+ cpSegmentShapeSegmentQuery(cpSegmentShape *seg, cpVect a, cpVect b, cpSegmentQueryInfo *info)
288
273
  {
289
- // TODO this function could be optimized better.
290
-
291
- cpSegmentShape *seg = (cpSegmentShape *)shape;
292
274
  cpVect n = seg->tn;
293
- // flip n if a is behind the axis
294
- if(cpvdot(a, n) < cpvdot(seg->ta, n))
295
- n = cpvneg(n);
275
+ cpFloat d = cpvdot(cpvsub(seg->ta, a), n);
276
+ cpFloat r = seg->r;
296
277
 
297
- cpFloat an = cpvdot(a, n);
298
- cpFloat bn = cpvdot(b, n);
278
+ cpVect flipped_n = (d > 0.0f ? cpvneg(n) : n);
279
+ cpVect seg_offset = cpvsub(cpvmult(flipped_n, r), a);
299
280
 
300
- if(an != bn){
301
- cpFloat d = cpvdot(seg->ta, n) + seg->r;
302
- cpFloat t = (d - an)/(bn - an);
281
+ // Make the endpoints relative to 'a' and move them by the thickness of the segment.
282
+ cpVect seg_a = cpvadd(seg->ta, seg_offset);
283
+ cpVect seg_b = cpvadd(seg->tb, seg_offset);
284
+ cpVect delta = cpvsub(b, a);
285
+
286
+ if(cpvcross(delta, seg_a)*cpvcross(delta, seg_b) <= 0.0f){
287
+ cpFloat d_offset = d + (d > 0.0f ? -r : r);
288
+ cpFloat ad = -d_offset;
289
+ cpFloat bd = cpvdot(delta, n) - d_offset;
303
290
 
304
- if(0.0f < t && t < 1.0f){
305
- cpVect point = cpvlerp(a, b, t);
306
- cpFloat dt = -cpvcross(seg->tn, point);
307
- cpFloat dtMin = -cpvcross(seg->tn, seg->ta);
308
- cpFloat dtMax = -cpvcross(seg->tn, seg->tb);
309
-
310
- if(dtMin < dt && dt < dtMax){
311
- info->shape = shape;
312
- info->t = t;
313
- info->n = n;
314
-
315
- return; // don't continue on and check endcaps
316
- }
291
+ if(ad*bd < 0.0f){
292
+ info->shape = (cpShape *)seg;
293
+ info->t = ad/(ad - bd);
294
+ info->n = flipped_n;
317
295
  }
318
- }
319
-
320
- if(seg->r) {
296
+ } else if(r != 0.0f){
321
297
  cpSegmentQueryInfo info1 = {NULL, 1.0f, cpvzero};
322
298
  cpSegmentQueryInfo info2 = {NULL, 1.0f, cpvzero};
323
- circleSegmentQuery(shape, seg->ta, seg->r, a, b, &info1);
324
- circleSegmentQuery(shape, seg->tb, seg->r, a, b, &info2);
299
+ circleSegmentQuery((cpShape *)seg, seg->ta, seg->r, a, b, &info1);
300
+ circleSegmentQuery((cpShape *)seg, seg->tb, seg->r, a, b, &info2);
325
301
 
326
302
  if(info1.t < info2.t){
327
303
  (*info) = info1;
@@ -333,10 +309,10 @@ cpSegmentShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInf
333
309
 
334
310
  static const cpShapeClass cpSegmentShapeClass = {
335
311
  CP_SEGMENT_SHAPE,
336
- cpSegmentShapeCacheData,
312
+ (cpShapeCacheDataImpl)cpSegmentShapeCacheData,
337
313
  NULL,
338
- cpSegmentShapePointQuery,
339
- cpSegmentShapeSegmentQuery,
314
+ (cpShapeNearestPointQueryImpl)cpSegmentShapeNearestPointQuery,
315
+ (cpShapeSegmentQueryImpl)cpSegmentShapeSegmentQuery,
340
316
  };
341
317
 
342
318
  cpSegmentShape *
@@ -348,6 +324,9 @@ cpSegmentShapeInit(cpSegmentShape *seg, cpBody *body, cpVect a, cpVect b, cpFloa
348
324
 
349
325
  seg->r = r;
350
326
 
327
+ seg->a_tangent = cpvzero;
328
+ seg->b_tangent = cpvzero;
329
+
351
330
  cpShapeInit((cpShape *)seg, &cpSegmentShapeClass, body);
352
331
 
353
332
  return seg;
@@ -364,12 +343,22 @@ CP_DefineShapeGetter(cpSegmentShape, cpVect, b, B)
364
343
  CP_DefineShapeGetter(cpSegmentShape, cpVect, n, Normal)
365
344
  CP_DefineShapeGetter(cpSegmentShape, cpFloat, r, Radius)
366
345
 
346
+ void
347
+ cpSegmentShapeSetNeighbors(cpShape *shape, cpVect prev, cpVect next)
348
+ {
349
+ cpAssertHard(shape->klass == &cpSegmentShapeClass, "Shape is not a segment shape.");
350
+ cpSegmentShape *seg = (cpSegmentShape *)shape;
351
+
352
+ seg->a_tangent = cpvsub(prev, seg->a);
353
+ seg->b_tangent = cpvsub(next, seg->b);
354
+ }
355
+
367
356
  // Unsafe API (chipmunk_unsafe.h)
368
357
 
369
358
  void
370
359
  cpCircleShapeSetRadius(cpShape *shape, cpFloat radius)
371
360
  {
372
- cpAssert(shape->klass == &cpCircleShapeClass, "Shape is not a circle shape.");
361
+ cpAssertHard(shape->klass == &cpCircleShapeClass, "Shape is not a circle shape.");
373
362
  cpCircleShape *circle = (cpCircleShape *)shape;
374
363
 
375
364
  circle->r = radius;
@@ -378,7 +367,7 @@ cpCircleShapeSetRadius(cpShape *shape, cpFloat radius)
378
367
  void
379
368
  cpCircleShapeSetOffset(cpShape *shape, cpVect offset)
380
369
  {
381
- cpAssert(shape->klass == &cpCircleShapeClass, "Shape is not a circle shape.");
370
+ cpAssertHard(shape->klass == &cpCircleShapeClass, "Shape is not a circle shape.");
382
371
  cpCircleShape *circle = (cpCircleShape *)shape;
383
372
 
384
373
  circle->c = offset;
@@ -387,7 +376,7 @@ cpCircleShapeSetOffset(cpShape *shape, cpVect offset)
387
376
  void
388
377
  cpSegmentShapeSetEndpoints(cpShape *shape, cpVect a, cpVect b)
389
378
  {
390
- cpAssert(shape->klass == &cpSegmentShapeClass, "Shape is not a segment shape.");
379
+ cpAssertHard(shape->klass == &cpSegmentShapeClass, "Shape is not a segment shape.");
391
380
  cpSegmentShape *seg = (cpSegmentShape *)shape;
392
381
 
393
382
  seg->a = a;
@@ -398,7 +387,7 @@ cpSegmentShapeSetEndpoints(cpShape *shape, cpVect a, cpVect b)
398
387
  void
399
388
  cpSegmentShapeSetRadius(cpShape *shape, cpFloat radius)
400
389
  {
401
- cpAssert(shape->klass == &cpSegmentShapeClass, "Shape is not a segment shape.");
390
+ cpAssertHard(shape->klass == &cpSegmentShapeClass, "Shape is not a segment shape.");
402
391
  cpSegmentShape *seg = (cpSegmentShape *)shape;
403
392
 
404
393
  seg->r = radius;