1 /* Copyright (c) 2013 Scott Lembcke and Howling Moon Software
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to deal
5 * in the Software without restriction, including without limitation the rights
6 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 * copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 #include "chipmunk/chipmunk_private.h"
24 //MARK: Nearest Point Query Functions
26 struct PointQueryContext {
30 cpSpacePointQueryFunc func;
34 NearestPointQuery(struct PointQueryContext *context, cpShape *shape, cpCollisionID id, void *data)
37 !cpShapeFilterReject(shape->filter, context->filter)
39 cpPointQueryInfo info;
40 cpShapePointQuery(shape, context->point, &info);
42 if(info.shape && info.distance < context->maxDistance) context->func(shape, info.point, info.distance, info.gradient, data);
49 cpSpacePointQuery(cpSpace *space, cpVect point, cpFloat maxDistance, cpShapeFilter filter, cpSpacePointQueryFunc func, void *data)
51 struct PointQueryContext context = {point, maxDistance, filter, func};
52 cpBB bb = cpBBNewForCircle(point, cpfmax(maxDistance, 0.0f));
55 cpSpatialIndexQuery(space->dynamicShapes, &context, bb, (cpSpatialIndexQueryFunc)NearestPointQuery, data);
56 cpSpatialIndexQuery(space->staticShapes, &context, bb, (cpSpatialIndexQueryFunc)NearestPointQuery, data);
57 } cpSpaceUnlock(space, cpTrue);
61 NearestPointQueryNearest(struct PointQueryContext *context, cpShape *shape, cpCollisionID id, cpPointQueryInfo *out)
64 !cpShapeFilterReject(shape->filter, context->filter) && !shape->sensor
66 cpPointQueryInfo info;
67 cpShapePointQuery(shape, context->point, &info);
69 if(info.distance < out->distance) (*out) = info;
76 cpSpacePointQueryNearest(cpSpace *space, cpVect point, cpFloat maxDistance, cpShapeFilter filter, cpPointQueryInfo *out)
78 cpPointQueryInfo info = {NULL, cpvzero, maxDistance, cpvzero};
85 struct PointQueryContext context = {
91 cpBB bb = cpBBNewForCircle(point, cpfmax(maxDistance, 0.0f));
92 cpSpatialIndexQuery(space->dynamicShapes, &context, bb, (cpSpatialIndexQueryFunc)NearestPointQueryNearest, out);
93 cpSpatialIndexQuery(space->staticShapes, &context, bb, (cpSpatialIndexQueryFunc)NearestPointQueryNearest, out);
95 return (cpShape *)out->shape;
99 //MARK: Segment Query Functions
101 struct SegmentQueryContext {
104 cpShapeFilter filter;
105 cpSpaceSegmentQueryFunc func;
109 SegmentQuery(struct SegmentQueryContext *context, cpShape *shape, void *data)
111 cpSegmentQueryInfo info;
114 !cpShapeFilterReject(shape->filter, context->filter) &&
115 cpShapeSegmentQuery(shape, context->start, context->end, context->radius, &info)
117 context->func(shape, info.point, info.normal, info.alpha, data);
124 cpSpaceSegmentQuery(cpSpace *space, cpVect start, cpVect end, cpFloat radius, cpShapeFilter filter, cpSpaceSegmentQueryFunc func, void *data)
126 struct SegmentQueryContext context = {
133 cpSpaceLock(space); {
134 cpSpatialIndexSegmentQuery(space->staticShapes, &context, start, end, 1.0f, (cpSpatialIndexSegmentQueryFunc)SegmentQuery, data);
135 cpSpatialIndexSegmentQuery(space->dynamicShapes, &context, start, end, 1.0f, (cpSpatialIndexSegmentQueryFunc)SegmentQuery, data);
136 } cpSpaceUnlock(space, cpTrue);
140 SegmentQueryFirst(struct SegmentQueryContext *context, cpShape *shape, cpSegmentQueryInfo *out)
142 cpSegmentQueryInfo info;
145 !cpShapeFilterReject(shape->filter, context->filter) && !shape->sensor &&
146 cpShapeSegmentQuery(shape, context->start, context->end, context->radius, &info) &&
147 info.alpha < out->alpha
156 cpSpaceSegmentQueryFirst(cpSpace *space, cpVect start, cpVect end, cpFloat radius, cpShapeFilter filter, cpSegmentQueryInfo *out)
158 cpSegmentQueryInfo info = {NULL, end, cpvzero, 1.0f};
165 struct SegmentQueryContext context = {
172 cpSpatialIndexSegmentQuery(space->staticShapes, &context, start, end, 1.0f, (cpSpatialIndexSegmentQueryFunc)SegmentQueryFirst, out);
173 cpSpatialIndexSegmentQuery(space->dynamicShapes, &context, start, end, out->alpha, (cpSpatialIndexSegmentQueryFunc)SegmentQueryFirst, out);
175 return (cpShape *)out->shape;
178 //MARK: BB Query Functions
180 struct BBQueryContext {
182 cpShapeFilter filter;
183 cpSpaceBBQueryFunc func;
187 BBQuery(struct BBQueryContext *context, cpShape *shape, cpCollisionID id, void *data)
190 !cpShapeFilterReject(shape->filter, context->filter) &&
191 cpBBIntersects(context->bb, shape->bb)
193 context->func(shape, data);
200 cpSpaceBBQuery(cpSpace *space, cpBB bb, cpShapeFilter filter, cpSpaceBBQueryFunc func, void *data)
202 struct BBQueryContext context = {bb, filter, func};
204 cpSpaceLock(space); {
205 cpSpatialIndexQuery(space->dynamicShapes, &context, bb, (cpSpatialIndexQueryFunc)BBQuery, data);
206 cpSpatialIndexQuery(space->staticShapes, &context, bb, (cpSpatialIndexQueryFunc)BBQuery, data);
207 } cpSpaceUnlock(space, cpTrue);
210 //MARK: Shape Query Functions
212 struct ShapeQueryContext {
213 cpSpaceShapeQueryFunc func;
218 // Callback from the spatial hash.
220 ShapeQuery(cpShape *a, cpShape *b, cpCollisionID id, struct ShapeQueryContext *context)
222 if(cpShapeFilterReject(a->filter, b->filter) || a == b) return id;
224 cpContactPointSet set = cpShapesCollide(a, b);
226 if(context->func) context->func(b, &set, context->data);
227 context->anyCollision = !(a->sensor || b->sensor);
234 cpSpaceShapeQuery(cpSpace *space, cpShape *shape, cpSpaceShapeQueryFunc func, void *data)
236 cpBody *body = shape->body;
237 cpBB bb = (body ? cpShapeUpdate(shape, body->transform) : shape->bb);
238 struct ShapeQueryContext context = {func, data, cpFalse};
240 cpSpaceLock(space); {
241 cpSpatialIndexQuery(space->dynamicShapes, shape, bb, (cpSpatialIndexQueryFunc)ShapeQuery, &context);
242 cpSpatialIndexQuery(space->staticShapes, shape, bb, (cpSpatialIndexQueryFunc)ShapeQuery, &context);
243 } cpSpaceUnlock(space, cpTrue);
245 return context.anyCollision;