chipmunk 5.3.4.5 → 6.1.3.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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;