b2_polygon_shape.cpp
Go to the documentation of this file.
1 // MIT License
2 
3 // Copyright (c) 2019 Erin Catto
4 
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 
12 // The above copyright notice and this permission notice shall be included in all
13 // copies or substantial portions of the Software.
14 
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 // SOFTWARE.
22 
23 #include "box2d/b2_polygon_shape.h"
25 
26 #include <new>
27 
29 {
30  void* mem = allocator->Allocate(sizeof(b2PolygonShape));
31  b2PolygonShape* clone = new (mem) b2PolygonShape;
32  *clone = *this;
33  return clone;
34 }
35 
36 void b2PolygonShape::SetAsBox(float hx, float hy)
37 {
38  m_count = 4;
39  m_vertices[0].Set(-hx, -hy);
40  m_vertices[1].Set( hx, -hy);
41  m_vertices[2].Set( hx, hy);
42  m_vertices[3].Set(-hx, hy);
43  m_normals[0].Set(0.0f, -1.0f);
44  m_normals[1].Set(1.0f, 0.0f);
45  m_normals[2].Set(0.0f, 1.0f);
46  m_normals[3].Set(-1.0f, 0.0f);
48 }
49 
50 void b2PolygonShape::SetAsBox(float hx, float hy, const b2Vec2& center, float angle)
51 {
52  m_count = 4;
53  m_vertices[0].Set(-hx, -hy);
54  m_vertices[1].Set( hx, -hy);
55  m_vertices[2].Set( hx, hy);
56  m_vertices[3].Set(-hx, hy);
57  m_normals[0].Set(0.0f, -1.0f);
58  m_normals[1].Set(1.0f, 0.0f);
59  m_normals[2].Set(0.0f, 1.0f);
60  m_normals[3].Set(-1.0f, 0.0f);
61  m_centroid = center;
62 
63  b2Transform xf;
64  xf.p = center;
65  xf.q.Set(angle);
66 
67  // Transform vertices and normals.
68  for (int32 i = 0; i < m_count; ++i)
69  {
70  m_vertices[i] = b2Mul(xf, m_vertices[i]);
71  m_normals[i] = b2Mul(xf.q, m_normals[i]);
72  }
73 }
74 
76 {
77  return 1;
78 }
79 
80 static b2Vec2 ComputeCentroid(const b2Vec2* vs, int32 count)
81 {
82  b2Assert(count >= 3);
83 
84  b2Vec2 c(0.0f, 0.0f);
85  float area = 0.0f;
86 
87  // Get a reference point for forming triangles.
88  // Use the first vertex to reduce round-off errors.
89  b2Vec2 s = vs[0];
90 
91  const float inv3 = 1.0f / 3.0f;
92 
93  for (int32 i = 0; i < count; ++i)
94  {
95  // Triangle vertices.
96  b2Vec2 p1 = vs[0] - s;
97  b2Vec2 p2 = vs[i] - s;
98  b2Vec2 p3 = i + 1 < count ? vs[i+1] - s : vs[0] - s;
99 
100  b2Vec2 e1 = p2 - p1;
101  b2Vec2 e2 = p3 - p1;
102 
103  float D = b2Cross(e1, e2);
104 
105  float triangleArea = 0.5f * D;
106  area += triangleArea;
107 
108  // Area weighted centroid
109  c += triangleArea * inv3 * (p1 + p2 + p3);
110  }
111 
112  // Centroid
113  b2Assert(area > b2_epsilon);
114  c = (1.0f / area) * c + s;
115  return c;
116 }
117 
118 void b2PolygonShape::Set(const b2Vec2* vertices, int32 count)
119 {
120  b2Assert(3 <= count && count <= b2_maxPolygonVertices);
121  if (count < 3)
122  {
123  SetAsBox(1.0f, 1.0f);
124  return;
125  }
126 
127  int32 n = b2Min(count, b2_maxPolygonVertices);
128 
129  // Perform welding and copy vertices into local buffer.
131  int32 tempCount = 0;
132  for (int32 i = 0; i < n; ++i)
133  {
134  b2Vec2 v = vertices[i];
135 
136  bool unique = true;
137  for (int32 j = 0; j < tempCount; ++j)
138  {
139  if (b2DistanceSquared(v, ps[j]) < ((0.5f * b2_linearSlop) * (0.5f * b2_linearSlop)))
140  {
141  unique = false;
142  break;
143  }
144  }
145 
146  if (unique)
147  {
148  ps[tempCount++] = v;
149  }
150  }
151 
152  n = tempCount;
153  if (n < 3)
154  {
155  // Polygon is degenerate.
156  b2Assert(false);
157  SetAsBox(1.0f, 1.0f);
158  return;
159  }
160 
161  // Create the convex hull using the Gift wrapping algorithm
162  // http://en.wikipedia.org/wiki/Gift_wrapping_algorithm
163 
164  // Find the right most point on the hull
165  int32 i0 = 0;
166  float x0 = ps[0].x;
167  for (int32 i = 1; i < n; ++i)
168  {
169  float x = ps[i].x;
170  if (x > x0 || (x == x0 && ps[i].y < ps[i0].y))
171  {
172  i0 = i;
173  x0 = x;
174  }
175  }
176 
178  int32 m = 0;
179  int32 ih = i0;
180 
181  for (;;)
182  {
184  hull[m] = ih;
185 
186  int32 ie = 0;
187  for (int32 j = 1; j < n; ++j)
188  {
189  if (ie == ih)
190  {
191  ie = j;
192  continue;
193  }
194 
195  b2Vec2 r = ps[ie] - ps[hull[m]];
196  b2Vec2 v = ps[j] - ps[hull[m]];
197  float c = b2Cross(r, v);
198  if (c < 0.0f)
199  {
200  ie = j;
201  }
202 
203  // Collinearity check
204  if (c == 0.0f && v.LengthSquared() > r.LengthSquared())
205  {
206  ie = j;
207  }
208  }
209 
210  ++m;
211  ih = ie;
212 
213  if (ie == i0)
214  {
215  break;
216  }
217  }
218 
219  if (m < 3)
220  {
221  // Polygon is degenerate.
222  b2Assert(false);
223  SetAsBox(1.0f, 1.0f);
224  return;
225  }
226 
227  m_count = m;
228 
229  // Copy vertices.
230  for (int32 i = 0; i < m; ++i)
231  {
232  m_vertices[i] = ps[hull[i]];
233  }
234 
235  // Compute normals. Ensure the edges have non-zero length.
236  for (int32 i = 0; i < m; ++i)
237  {
238  int32 i1 = i;
239  int32 i2 = i + 1 < m ? i + 1 : 0;
240  b2Vec2 edge = m_vertices[i2] - m_vertices[i1];
242  m_normals[i] = b2Cross(edge, 1.0f);
243  m_normals[i].Normalize();
244  }
245 
246  // Compute the polygon centroid.
248 }
249 
250 bool b2PolygonShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const
251 {
252  b2Vec2 pLocal = b2MulT(xf.q, p - xf.p);
253 
254  for (int32 i = 0; i < m_count; ++i)
255  {
256  float dot = b2Dot(m_normals[i], pLocal - m_vertices[i]);
257  if (dot > 0.0f)
258  {
259  return false;
260  }
261  }
262 
263  return true;
264 }
265 
267  const b2Transform& xf, int32 childIndex) const
268 {
269  B2_NOT_USED(childIndex);
270 
271  // Put the ray into the polygon's frame of reference.
272  b2Vec2 p1 = b2MulT(xf.q, input.p1 - xf.p);
273  b2Vec2 p2 = b2MulT(xf.q, input.p2 - xf.p);
274  b2Vec2 d = p2 - p1;
275 
276  float lower = 0.0f, upper = input.maxFraction;
277 
278  int32 index = -1;
279 
280  for (int32 i = 0; i < m_count; ++i)
281  {
282  // p = p1 + a * d
283  // dot(normal, p - v) = 0
284  // dot(normal, p1 - v) + a * dot(normal, d) = 0
285  float numerator = b2Dot(m_normals[i], m_vertices[i] - p1);
286  float denominator = b2Dot(m_normals[i], d);
287 
288  if (denominator == 0.0f)
289  {
290  if (numerator < 0.0f)
291  {
292  return false;
293  }
294  }
295  else
296  {
297  // Note: we want this predicate without division:
298  // lower < numerator / denominator, where denominator < 0
299  // Since denominator < 0, we have to flip the inequality:
300  // lower < numerator / denominator <==> denominator * lower > numerator.
301  if (denominator < 0.0f && numerator < lower * denominator)
302  {
303  // Increase lower.
304  // The segment enters this half-space.
305  lower = numerator / denominator;
306  index = i;
307  }
308  else if (denominator > 0.0f && numerator < upper * denominator)
309  {
310  // Decrease upper.
311  // The segment exits this half-space.
312  upper = numerator / denominator;
313  }
314  }
315 
316  // The use of epsilon here causes the assert on lower to trip
317  // in some cases. Apparently the use of epsilon was to make edge
318  // shapes work, but now those are handled separately.
319  //if (upper < lower - b2_epsilon)
320  if (upper < lower)
321  {
322  return false;
323  }
324  }
325 
326  b2Assert(0.0f <= lower && lower <= input.maxFraction);
327 
328  if (index >= 0)
329  {
330  output->fraction = lower;
331  output->normal = b2Mul(xf.q, m_normals[index]);
332  return true;
333  }
334 
335  return false;
336 }
337 
338 void b2PolygonShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const
339 {
340  B2_NOT_USED(childIndex);
341 
342  b2Vec2 lower = b2Mul(xf, m_vertices[0]);
343  b2Vec2 upper = lower;
344 
345  for (int32 i = 1; i < m_count; ++i)
346  {
347  b2Vec2 v = b2Mul(xf, m_vertices[i]);
348  lower = b2Min(lower, v);
349  upper = b2Max(upper, v);
350  }
351 
353  aabb->lowerBound = lower - r;
354  aabb->upperBound = upper + r;
355 }
356 
357 void b2PolygonShape::ComputeMass(b2MassData* massData, float density) const
358 {
359  // Polygon mass, centroid, and inertia.
360  // Let rho be the polygon density in mass per unit area.
361  // Then:
362  // mass = rho * int(dA)
363  // centroid.x = (1/mass) * rho * int(x * dA)
364  // centroid.y = (1/mass) * rho * int(y * dA)
365  // I = rho * int((x*x + y*y) * dA)
366  //
367  // We can compute these integrals by summing all the integrals
368  // for each triangle of the polygon. To evaluate the integral
369  // for a single triangle, we make a change of variables to
370  // the (u,v) coordinates of the triangle:
371  // x = x0 + e1x * u + e2x * v
372  // y = y0 + e1y * u + e2y * v
373  // where 0 <= u && 0 <= v && u + v <= 1.
374  //
375  // We integrate u from [0,1-v] and then v from [0,1].
376  // We also need to use the Jacobian of the transformation:
377  // D = cross(e1, e2)
378  //
379  // Simplification: triangle centroid = (1/3) * (p1 + p2 + p3)
380  //
381  // The rest of the derivation is handled by computer algebra.
382 
383  b2Assert(m_count >= 3);
384 
385  b2Vec2 center(0.0f, 0.0f);
386  float area = 0.0f;
387  float I = 0.0f;
388 
389  // Get a reference point for forming triangles.
390  // Use the first vertex to reduce round-off errors.
391  b2Vec2 s = m_vertices[0];
392 
393  const float k_inv3 = 1.0f / 3.0f;
394 
395  for (int32 i = 0; i < m_count; ++i)
396  {
397  // Triangle vertices.
398  b2Vec2 e1 = m_vertices[i] - s;
399  b2Vec2 e2 = i + 1 < m_count ? m_vertices[i+1] - s : m_vertices[0] - s;
400 
401  float D = b2Cross(e1, e2);
402 
403  float triangleArea = 0.5f * D;
404  area += triangleArea;
405 
406  // Area weighted centroid
407  center += triangleArea * k_inv3 * (e1 + e2);
408 
409  float ex1 = e1.x, ey1 = e1.y;
410  float ex2 = e2.x, ey2 = e2.y;
411 
412  float intx2 = ex1*ex1 + ex2*ex1 + ex2*ex2;
413  float inty2 = ey1*ey1 + ey2*ey1 + ey2*ey2;
414 
415  I += (0.25f * k_inv3 * D) * (intx2 + inty2);
416  }
417 
418  // Total mass
419  massData->mass = density * area;
420 
421  // Center of mass
422  b2Assert(area > b2_epsilon);
423  center *= 1.0f / area;
424  massData->center = center + s;
425 
426  // Inertia tensor relative to the local origin (point s).
427  massData->I = density * I;
428 
429  // Shift to center of mass then to original body origin.
430  massData->I += massData->mass * (b2Dot(massData->center, massData->center) - b2Dot(center, center));
431 }
432 
434 {
435  for (int32 i = 0; i < m_count; ++i)
436  {
437  int32 i1 = i;
438  int32 i2 = i < m_count - 1 ? i1 + 1 : 0;
439  b2Vec2 p = m_vertices[i1];
440  b2Vec2 e = m_vertices[i2] - p;
441 
442  for (int32 j = 0; j < m_count; ++j)
443  {
444  if (j == i1 || j == i2)
445  {
446  continue;
447  }
448 
449  b2Vec2 v = m_vertices[j] - p;
450  float c = b2Cross(e, v);
451  if (c < 0.0f)
452  {
453  return false;
454  }
455  }
456  }
457 
458  return true;
459 }
d
float mass
The mass of the shape, usually in kilograms.
Definition: b2_shape.h:36
T b2Min(T a, T b)
Definition: b2_math.h:626
b2Vec2 b2Mul(const b2Mat22 &A, const b2Vec2 &v)
Definition: b2_math.h:422
static b2Vec2 ComputeCentroid(const b2Vec2 *vs, int32 count)
b2Vec2 p
Definition: b2_math.h:360
float b2Dot(const b2Vec2 &a, const b2Vec2 &b)
Perform the dot product on two vectors.
Definition: b2_math.h:395
b2Vec2 lowerBound
the lower vertex
Definition: b2_collision.h:220
b2Rot q
Definition: b2_math.h:361
f
float x
Definition: b2_math.h:128
float y
Definition: b2_math.h:128
XmlRpcServer s
Ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).
Definition: b2_collision.h:153
#define b2_linearSlop
Definition: b2_common.h:65
b2Vec2 center
The position of the shape&#39;s centroid relative to the shape&#39;s origin.
Definition: b2_shape.h:39
void SetZero()
Set this vector to all zeros.
Definition: b2_math.h:50
A 2D column vector.
Definition: b2_math.h:41
doubleAcc dot(const VectorAcc &lhs, const VectorAcc &rhs)
void ComputeMass(b2MassData *massData, float density) const override
bool RayCast(b2RayCastOutput *output, const b2RayCastInput &input, const b2Transform &transform, int32 childIndex) const override
signed int int32
Definition: b2_types.h:28
float b2DistanceSquared(const b2Vec2 &a, const b2Vec2 &b)
Definition: b2_math.h:467
void SetAsBox(float hx, float hy)
bool TestPoint(const b2Transform &transform, const b2Vec2 &p) const override
float m_radius
Definition: b2_shape.h:102
void * Allocate(int32 size)
Allocate memory. This will use b2Alloc if the size is larger than b2_maxBlockSize.
float LengthSquared() const
Definition: b2_math.h:96
#define B2_NOT_USED(x)
Definition: b2_common.h:36
void ComputeAABB(b2AABB *aabb, const b2Transform &transform, int32 childIndex) const override
T b2Max(T a, T b)
Definition: b2_math.h:637
void Set(float x_, float y_)
Set this vector to some specified coordinates.
Definition: b2_math.h:53
float b2Cross(const b2Vec2 &a, const b2Vec2 &b)
Perform the cross product on two vectors. In 2D this produces a scalar.
Definition: b2_math.h:401
b2Vec2 m_vertices[b2_maxPolygonVertices]
float I
The rotational inertia of the shape about the local origin.
Definition: b2_shape.h:42
An axis aligned bounding box.
Definition: b2_collision.h:168
void Set(const b2Vec2 *points, int32 count)
b2Vec2 b2MulT(const b2Mat22 &A, const b2Vec2 &v)
Definition: b2_math.h:429
int32 GetChildCount() const override
#define b2_maxPolygonVertices
Definition: b2_settings.h:53
b2Shape * Clone(b2BlockAllocator *allocator) const override
Implement b2Shape.
bool Validate() const
#define b2_epsilon
Definition: b2_common.h:40
This holds the mass data computed for a shape.
Definition: b2_shape.h:33
#define b2Assert(A)
Definition: b2_common.h:37
b2Vec2 m_normals[b2_maxPolygonVertices]
void Set(float angle)
Set using an angle in radians.
Definition: b2_math.h:300
b2Vec2 upperBound
the upper vertex
Definition: b2_collision.h:221


mvsim
Author(s):
autogenerated on Tue Jul 4 2023 03:08:19