1 module chipmunk.cpBB;
2 
3 import chipmunk.chipmunk_types;
4 import chipmunk.cpVect;
5 
6 extern (C):
7 
8 struct cpBB
9 {
10     cpFloat l;
11     cpFloat b;
12     cpFloat r;
13     cpFloat t;
14 }
15 
16 // these functions are inlined in the chipmunk headers:
17 
18 static cpBB cpBBNew(const cpFloat l, const cpFloat b, const cpFloat r, const cpFloat t)
19 {
20 	cpBB bb = {l, b, r, t};
21 	return bb;
22 }
23 
24 /// Constructs a cpBB centered on a point with the given extents (half sizes).
25 static cpBB
26 cpBBNewForExtents(const cpVect c, const cpFloat hw, const cpFloat hh)
27 {
28 	return cpBBNew(c.x - hw, c.y - hh, c.x + hw, c.y + hh);
29 }
30 
31 /// Constructs a cpBB for a circle with the given position and radius.
32 static cpBB cpBBNewForCircle(const cpVect p, const cpFloat r)
33 {
34 	return cpBBNewForExtents(p, r, r);
35 }
36 
37 /// Returns true if @c a and @c b intersect.
38 static cpBool cpBBIntersects(const cpBB a, const cpBB b)
39 {
40 	return (a.l <= b.r && b.l <= a.r && a.b <= b.t && b.b <= a.t);
41 }
42 
43 /// Returns true if @c other lies completely within @c bb.
44 static cpBool cpBBContainsBB(const cpBB bb, const cpBB other)
45 {
46 	return (bb.l <= other.l && bb.r >= other.r && bb.b <= other.b && bb.t >= other.t);
47 }
48 
49 /// Returns true if @c bb contains @c v.
50 static cpBool cpBBContainsVect(const cpBB bb, const cpVect v)
51 {
52 	return (bb.l <= v.x && bb.r >= v.x && bb.b <= v.y && bb.t >= v.y);
53 }
54 
55 /// Returns a bounding box that holds both bounding boxes.
56 static cpBB cpBBMerge(const cpBB a, const cpBB b){
57 	return cpBBNew(
58 		cpfmin(a.l, b.l),
59 		cpfmin(a.b, b.b),
60 		cpfmax(a.r, b.r),
61 		cpfmax(a.t, b.t)
62 	);
63 }
64 
65 /// Returns a bounding box that holds both @c bb and @c v.
66 static cpBB cpBBExpand(const cpBB bb, const cpVect v){
67 	return cpBBNew(
68 		cpfmin(bb.l, v.x),
69 		cpfmin(bb.b, v.y),
70 		cpfmax(bb.r, v.x),
71 		cpfmax(bb.t, v.y)
72 	);
73 }
74 
75 /// Returns the center of a bounding box.
76 static cpVect
77 cpBBCenter(cpBB bb)
78 {
79 	return cpvlerp(cpv(bb.l, bb.b), cpv(bb.r, bb.t), 0.5f);
80 }
81 
82 /// Returns the area of the bounding box.
83 static cpFloat cpBBArea(cpBB bb)
84 {
85 	return (bb.r - bb.l)*(bb.t - bb.b);
86 }
87 
88 /// Merges @c a and @c b and returns the area of the merged bounding box.
89 static cpFloat cpBBMergedArea(cpBB a, cpBB b)
90 {
91 	return (cpfmax(a.r, b.r) - cpfmin(a.l, b.l))*(cpfmax(a.t, b.t) - cpfmin(a.b, b.b));
92 }
93 
94 /// Returns the fraction along the segment query the cpBB is hit. Returns INFINITY if it doesn't hit.
95 static cpFloat cpBBSegmentQuery(cpBB bb, cpVect a, cpVect b)
96 {
97 	cpVect delta = cpvsub(b, a);
98 	cpFloat tmin = -INFINITY, tmax = INFINITY;
99 
100 	if(delta.x != 0.0f){
101 		cpFloat t1 = (bb.l - a.x)/delta.x;
102 		cpFloat t2 = (bb.r - a.x)/delta.x;
103 		tmin = cpfmax(tmin, cpfmin(t1, t2));
104 		tmax = cpfmin(tmax, cpfmax(t1, t2));
105 	}
106 
107 	if(delta.y != 0.0f){
108 		cpFloat t1 = (bb.b - a.y)/delta.y;
109 		cpFloat t2 = (bb.t - a.y)/delta.y;
110 		tmin = cpfmax(tmin, cpfmin(t1, t2));
111 		tmax = cpfmin(tmax, cpfmax(t1, t2));
112 	}
113 
114 	if(tmin <= tmax && 0.0f <= tmax && tmin <= 1.0f){
115 		return cpfmax(tmin, 0.0f);
116 	}
117 
118 	return INFINITY;
119 }
120 
121 /// Return true if the bounding box intersects the line segment with ends @c a and @c b.
122 static cpBool cpBBIntersectsSegment(cpBB bb, cpVect a, cpVect b)
123 {
124 	return (cpBBSegmentQuery(bb, a, b) != INFINITY);
125 }
126 
127 /// Clamp a vector to a bounding box.
128 static cpVect
129 cpBBClampVect(const cpBB bb, const cpVect v)
130 {
131 	return cpv(cpfclamp(v.x, bb.l, bb.r), cpfclamp(v.y, bb.b, bb.t));
132 }
133 
134 /// Wrap a vector to a bounding box.
135 static cpVect
136 cpBBWrapVect(const cpBB bb, const cpVect v)
137 {
138 	cpFloat dx = cpfabs(bb.r - bb.l);
139 	cpFloat modx = cpfmod(v.x - bb.l, dx);
140 	cpFloat x = (modx > 0.0f) ? modx : modx + dx;
141 
142 	cpFloat dy = cpfabs(bb.t - bb.b);
143 	cpFloat mody = cpfmod(v.y - bb.b, dy);
144 	cpFloat y = (mody > 0.0f) ? mody : mody + dy;
145 
146 	return cpv(x + bb.l, y + bb.b);
147 }
148 
149 /// Returns a bounding box offseted by @c v.
150 static cpBB
151 cpBBOffset(const cpBB bb, const cpVect v)
152 {
153 	return cpBBNew(
154 		bb.l + v.x,
155 		bb.b + v.y,
156 		bb.r + v.x,
157 		bb.t + v.y
158 	);
159 }
160