plugin/box2d: updated (thanks Novo)

git-svn-id: svn://ultimatepp.org/upp/trunk@15930 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2021-04-21 07:47:15 +00:00
parent f07d121833
commit ecaf46cff5
152 changed files with 18268 additions and 11877 deletions

View file

@ -1,62 +1,6 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef _plugin_box2d_Box2D_h_
#define _plugin_box2d_Box2D_h_
#ifndef BOX2D_H
#define BOX2D_H
/**
\mainpage Box2D API Documentation
\section intro_sec Getting Started
For documentation please see http://box2d.org/documentation.html
For discussion please visit http://box2d.org/forum
*/
// These include files constitute the main Box2D API
#include "b2Settings.h"
#include "b2CircleShape.h"
#include "b2PolygonShape.h"
#include "b2BroadPhase.h"
#include "b2Distance.h"
#include "b2DynamicTree.h"
#include "b2TimeOfImpact.h"
#include "b2Body.h"
#include "b2Fixture.h"
#include "b2WorldCallbacks.h"
#include "b2TimeStep.h"
#include "b2World.h"
#include "b2Contact.h"
#include "b2DistanceJoint.h"
#include "b2FrictionJoint.h"
#include "b2GearJoint.h"
#include "b2LineJoint.h"
#include "b2MouseJoint.h"
#include "b2PrismaticJoint.h"
#include "b2PulleyJoint.h"
#include "b2RevoluteJoint.h"
#include "b2WeldJoint.h"
#include "include/box2d/box2d.h"
#endif

View file

@ -1,15 +0,0 @@
Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.

View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Erin Catto
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -1,59 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_BLOCK_ALLOCATOR_H
#define B2_BLOCK_ALLOCATOR_H
#include "b2Settings.h"
const int32 b2_chunkSize = 4096;
const int32 b2_maxBlockSize = 640;
const int32 b2_blockSizes = 14;
const int32 b2_chunkArrayIncrement = 128;
struct b2Block;
struct b2Chunk;
// This is a small object allocator used for allocating small
// objects that persist for more than one time step.
// See: http://www.codeproject.com/useritems/Small_Block_Allocator.asp
class b2BlockAllocator
{
public:
b2BlockAllocator();
~b2BlockAllocator();
void* Allocate(int32 size);
void Free(void* p, int32 size);
void Clear();
private:
b2Chunk* m_chunks;
int32 m_chunkCount;
int32 m_chunkSpace;
b2Block* m_freeLists[b2_blockSizes];
static int32 s_blockSizes[b2_blockSizes];
static uint8 s_blockSizeLookup[b2_maxBlockSize + 1];
static bool s_blockSizeLookupInitialized;
};
#endif

View file

@ -1,52 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "b2CircleContact.h"
#include "b2Body.h"
#include "b2Fixture.h"
#include "b2WorldCallbacks.h"
#include "b2BlockAllocator.h"
#include "b2TimeOfImpact.h"
#include <new>
b2Contact* b2CircleContact::Create(b2Fixture* fixtureA, b2Fixture* fixtureB, b2BlockAllocator* allocator)
{
void* mem = allocator->Allocate(sizeof(b2CircleContact));
return new (mem) b2CircleContact(fixtureA, fixtureB);
}
void b2CircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)
{
((b2CircleContact*)contact)->~b2CircleContact();
allocator->Free(contact, sizeof(b2CircleContact));
}
b2CircleContact::b2CircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB)
: b2Contact(fixtureA, fixtureB)
{
b2Assert(m_fixtureA->GetType() == b2Shape::e_circle);
b2Assert(m_fixtureB->GetType() == b2Shape::e_circle);
}
void b2CircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB)
{
b2CollideCircles(manifold,
(b2CircleShape*)m_fixtureA->GetShape(), xfA,
(b2CircleShape*)m_fixtureB->GetShape(), xfB);
}

View file

@ -1,38 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_CIRCLE_CONTACT_H
#define B2_CIRCLE_CONTACT_H
#include "b2Contact.h"
class b2BlockAllocator;
class b2CircleContact : public b2Contact
{
public:
static b2Contact* Create(b2Fixture* fixtureA, b2Fixture* fixtureB, b2BlockAllocator* allocator);
static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);
b2CircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB);
~b2CircleContact() {}
void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB);
};
#endif

View file

@ -1,89 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "b2CircleShape.h"
#include <new>
b2Shape* b2CircleShape::Clone(b2BlockAllocator* allocator) const
{
void* mem = allocator->Allocate(sizeof(b2CircleShape));
b2CircleShape* clone = new (mem) b2CircleShape;
*clone = *this;
return clone;
}
bool b2CircleShape::TestPoint(const b2Transform& transform, const b2Vec2& p) const
{
b2Vec2 center = transform.position + b2Mul(transform.R, m_p);
b2Vec2 d = p - center;
return b2Dot(d, d) <= m_radius * m_radius;
}
// Collision Detection in Interactive 3D Environments by Gino van den Bergen
// From Section 3.1.2
// x = s + a * r
// norm(x) = radius
bool b2CircleShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, const b2Transform& transform) const
{
b2Vec2 position = transform.position + b2Mul(transform.R, m_p);
b2Vec2 s = input.p1 - position;
float32 b = b2Dot(s, s) - m_radius * m_radius;
// Solve quadratic equation.
b2Vec2 r = input.p2 - input.p1;
float32 c = b2Dot(s, r);
float32 rr = b2Dot(r, r);
float32 sigma = c * c - rr * b;
// Check for negative discriminant and short segment.
if (sigma < 0.0f || rr < b2_epsilon)
{
return false;
}
// Find the point of intersection of the line with the circle.
float32 a = -(c + b2Sqrt(sigma));
// Is the intersection point on the segment?
if (0.0f <= a && a <= input.maxFraction * rr)
{
a /= rr;
output->fraction = a;
output->normal = s + a * r;
output->normal.Normalize();
return true;
}
return false;
}
void b2CircleShape::ComputeAABB(b2AABB* aabb, const b2Transform& transform) const
{
b2Vec2 p = transform.position + b2Mul(transform.R, m_p);
aabb->lowerBound.Set(p.x - m_radius, p.y - m_radius);
aabb->upperBound.Set(p.x + m_radius, p.y + m_radius);
}
void b2CircleShape::ComputeMass(b2MassData* massData, float32 density) const
{
massData->mass = density * b2_pi * m_radius * m_radius;
massData->center = m_p;
// inertia about the local origin
massData->I = massData->mass * (0.5f * m_radius * m_radius + b2Dot(m_p, m_p));
}

View file

@ -1,87 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_CIRCLE_SHAPE_H
#define B2_CIRCLE_SHAPE_H
#include "b2Shape.h"
/// A circle shape.
class b2CircleShape : public b2Shape
{
public:
b2CircleShape();
/// Implement b2Shape.
b2Shape* Clone(b2BlockAllocator* allocator) const;
/// Implement b2Shape.
bool TestPoint(const b2Transform& transform, const b2Vec2& p) const;
/// Implement b2Shape.
bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, const b2Transform& transform) const;
/// @see b2Shape::ComputeAABB
void ComputeAABB(b2AABB* aabb, const b2Transform& transform) const;
/// @see b2Shape::ComputeMass
void ComputeMass(b2MassData* massData, float32 density) const;
/// Get the supporting vertex index in the given direction.
int32 GetSupport(const b2Vec2& d) const;
/// Get the supporting vertex in the given direction.
const b2Vec2& GetSupportVertex(const b2Vec2& d) const;
/// Get the vertex count.
int32 GetVertexCount() const { return 1; }
/// Get a vertex by index. Used by b2Distance.
const b2Vec2& GetVertex(int32 index) const;
/// Position
b2Vec2 m_p;
};
inline b2CircleShape::b2CircleShape()
{
m_type = e_circle;
m_radius = 0.0f;
m_p.SetZero();
}
inline int32 b2CircleShape::GetSupport(const b2Vec2 &d) const
{
B2_NOT_USED(d);
return 0;
}
inline const b2Vec2& b2CircleShape::GetSupportVertex(const b2Vec2 &d) const
{
B2_NOT_USED(d);
return m_p;
}
inline const b2Vec2& b2CircleShape::GetVertex(int32 index) const
{
B2_NOT_USED(index);
b2Assert(index == 0);
return m_p;
}
#endif

View file

@ -1,306 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "b2Collision.h"
#include "b2PolygonShape.h"
// Find the separation between poly1 and poly2 for a give edge normal on poly1.
static float32 b2EdgeSeparation(const b2PolygonShape* poly1, const b2Transform& xf1, int32 edge1,
const b2PolygonShape* poly2, const b2Transform& xf2)
{
int32 count1 = poly1->m_vertexCount;
const b2Vec2* vertices1 = poly1->m_vertices;
const b2Vec2* normals1 = poly1->m_normals;
int32 count2 = poly2->m_vertexCount;
const b2Vec2* vertices2 = poly2->m_vertices;
b2Assert(0 <= edge1 && edge1 < count1);
// Convert normal from poly1's frame into poly2's frame.
b2Vec2 normal1World = b2Mul(xf1.R, normals1[edge1]);
b2Vec2 normal1 = b2MulT(xf2.R, normal1World);
// Find support vertex on poly2 for -normal.
int32 index = 0;
float32 minDot = b2_maxFloat;
for (int32 i = 0; i < count2; ++i)
{
float32 dot = b2Dot(vertices2[i], normal1);
if (dot < minDot)
{
minDot = dot;
index = i;
}
}
b2Vec2 v1 = b2Mul(xf1, vertices1[edge1]);
b2Vec2 v2 = b2Mul(xf2, vertices2[index]);
float32 separation = b2Dot(v2 - v1, normal1World);
return separation;
}
// Find the max separation between poly1 and poly2 using edge normals from poly1.
static float32 b2FindMaxSeparation(int32* edgeIndex,
const b2PolygonShape* poly1, const b2Transform& xf1,
const b2PolygonShape* poly2, const b2Transform& xf2)
{
int32 count1 = poly1->m_vertexCount;
const b2Vec2* normals1 = poly1->m_normals;
// Vector pointing from the centroid of poly1 to the centroid of poly2.
b2Vec2 d = b2Mul(xf2, poly2->m_centroid) - b2Mul(xf1, poly1->m_centroid);
b2Vec2 dLocal1 = b2MulT(xf1.R, d);
// Find edge normal on poly1 that has the largest projection onto d.
int32 edge = 0;
float32 maxDot = -b2_maxFloat;
for (int32 i = 0; i < count1; ++i)
{
float32 dot = b2Dot(normals1[i], dLocal1);
if (dot > maxDot)
{
maxDot = dot;
edge = i;
}
}
// Get the separation for the edge normal.
float32 s = b2EdgeSeparation(poly1, xf1, edge, poly2, xf2);
// Check the separation for the previous edge normal.
int32 prevEdge = edge - 1 >= 0 ? edge - 1 : count1 - 1;
float32 sPrev = b2EdgeSeparation(poly1, xf1, prevEdge, poly2, xf2);
// Check the separation for the next edge normal.
int32 nextEdge = edge + 1 < count1 ? edge + 1 : 0;
float32 sNext = b2EdgeSeparation(poly1, xf1, nextEdge, poly2, xf2);
// Find the best edge and the search direction.
int32 bestEdge;
float32 bestSeparation;
int32 increment;
if (sPrev > s && sPrev > sNext)
{
increment = -1;
bestEdge = prevEdge;
bestSeparation = sPrev;
}
else if (sNext > s)
{
increment = 1;
bestEdge = nextEdge;
bestSeparation = sNext;
}
else
{
*edgeIndex = edge;
return s;
}
// Perform a local search for the best edge normal.
for ( ; ; )
{
if (increment == -1)
edge = bestEdge - 1 >= 0 ? bestEdge - 1 : count1 - 1;
else
edge = bestEdge + 1 < count1 ? bestEdge + 1 : 0;
s = b2EdgeSeparation(poly1, xf1, edge, poly2, xf2);
if (s > bestSeparation)
{
bestEdge = edge;
bestSeparation = s;
}
else
{
break;
}
}
*edgeIndex = bestEdge;
return bestSeparation;
}
static void b2FindIncidentEdge(b2ClipVertex c[2],
const b2PolygonShape* poly1, const b2Transform& xf1, int32 edge1,
const b2PolygonShape* poly2, const b2Transform& xf2)
{
int32 count1 = poly1->m_vertexCount;
const b2Vec2* normals1 = poly1->m_normals;
int32 count2 = poly2->m_vertexCount;
const b2Vec2* vertices2 = poly2->m_vertices;
const b2Vec2* normals2 = poly2->m_normals;
b2Assert(0 <= edge1 && edge1 < count1);
// Get the normal of the reference edge in poly2's frame.
b2Vec2 normal1 = b2MulT(xf2.R, b2Mul(xf1.R, normals1[edge1]));
// Find the incident edge on poly2.
int32 index = 0;
float32 minDot = b2_maxFloat;
for (int32 i = 0; i < count2; ++i)
{
float32 dot = b2Dot(normal1, normals2[i]);
if (dot < minDot)
{
minDot = dot;
index = i;
}
}
// Build the clip vertices for the incident edge.
int32 i1 = index;
int32 i2 = i1 + 1 < count2 ? i1 + 1 : 0;
c[0].v = b2Mul(xf2, vertices2[i1]);
c[0].id.features.referenceEdge = (uint8)edge1;
c[0].id.features.incidentEdge = (uint8)i1;
c[0].id.features.incidentVertex = 0;
c[1].v = b2Mul(xf2, vertices2[i2]);
c[1].id.features.referenceEdge = (uint8)edge1;
c[1].id.features.incidentEdge = (uint8)i2;
c[1].id.features.incidentVertex = 1;
}
// Find edge normal of max separation on A - return if separating axis is found
// Find edge normal of max separation on B - return if separation axis is found
// Choose reference edge as min(minA, minB)
// Find incident edge
// Clip
// The normal points from 1 to 2
void b2CollidePolygons(b2Manifold* manifold,
const b2PolygonShape* polyA, const b2Transform& xfA,
const b2PolygonShape* polyB, const b2Transform& xfB)
{
manifold->pointCount = 0;
float32 totalRadius = polyA->m_radius + polyB->m_radius;
int32 edgeA = 0;
float32 separationA = b2FindMaxSeparation(&edgeA, polyA, xfA, polyB, xfB);
if (separationA > totalRadius)
return;
int32 edgeB = 0;
float32 separationB = b2FindMaxSeparation(&edgeB, polyB, xfB, polyA, xfA);
if (separationB > totalRadius)
return;
const b2PolygonShape* poly1; // reference polygon
const b2PolygonShape* poly2; // incident polygon
b2Transform xf1, xf2;
int32 edge1; // reference edge
uint8 flip;
const float32 k_relativeTol = 0.98f;
const float32 k_absoluteTol = 0.001f;
if (separationB > k_relativeTol * separationA + k_absoluteTol)
{
poly1 = polyB;
poly2 = polyA;
xf1 = xfB;
xf2 = xfA;
edge1 = edgeB;
manifold->type = b2Manifold::e_faceB;
flip = 1;
}
else
{
poly1 = polyA;
poly2 = polyB;
xf1 = xfA;
xf2 = xfB;
edge1 = edgeA;
manifold->type = b2Manifold::e_faceA;
flip = 0;
}
b2ClipVertex incidentEdge[2];
b2FindIncidentEdge(incidentEdge, poly1, xf1, edge1, poly2, xf2);
int32 count1 = poly1->m_vertexCount;
const b2Vec2* vertices1 = poly1->m_vertices;
b2Vec2 v11 = vertices1[edge1];
b2Vec2 v12 = edge1 + 1 < count1 ? vertices1[edge1+1] : vertices1[0];
b2Vec2 localTangent = v12 - v11;
localTangent.Normalize();
b2Vec2 localNormal = b2Cross(localTangent, 1.0f);
b2Vec2 planePoint = 0.5f * (v11 + v12);
b2Vec2 tangent = b2Mul(xf1.R, localTangent);
b2Vec2 normal = b2Cross(tangent, 1.0f);
v11 = b2Mul(xf1, v11);
v12 = b2Mul(xf1, v12);
// Face offset.
float32 frontOffset = b2Dot(normal, v11);
// Side offsets, extended by polytope skin thickness.
float32 sideOffset1 = -b2Dot(tangent, v11) + totalRadius;
float32 sideOffset2 = b2Dot(tangent, v12) + totalRadius;
// Clip incident edge against extruded edge1 side edges.
b2ClipVertex clipPoints1[2];
b2ClipVertex clipPoints2[2];
int np;
// Clip to box side 1
np = b2ClipSegmentToLine(clipPoints1, incidentEdge, -tangent, sideOffset1);
if (np < 2)
return;
// Clip to negative box side 1
np = b2ClipSegmentToLine(clipPoints2, clipPoints1, tangent, sideOffset2);
if (np < 2)
{
return;
}
// Now clipPoints2 contains the clipped points.
manifold->localNormal = localNormal;
manifold->localPoint = planePoint;
int32 pointCount = 0;
for (int32 i = 0; i < b2_maxManifoldPoints; ++i)
{
float32 separation = b2Dot(normal, clipPoints2[i].v) - frontOffset;
if (separation <= totalRadius)
{
b2ManifoldPoint* cp = manifold->points + pointCount;
cp->localPoint = b2MulT(xf2, clipPoints2[i].v);
cp->id = clipPoints2[i].id;
cp->id.features.flip = flip;
++pointCount;
}
}
manifold->pointCount = pointCount;
}

View file

@ -1,226 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "b2Contact.h"
#include "b2CircleContact.h"
#include "b2PolygonAndCircleContact.h"
#include "b2PolygonContact.h"
#include "b2ContactSolver.h"
#include "b2Collision.h"
#include "b2TimeOfImpact.h"
#include "b2Shape.h"
#include "b2BlockAllocator.h"
#include "b2Body.h"
#include "b2Fixture.h"
#include "b2World.h"
b2ContactRegister b2Contact::s_registers[b2Shape::e_typeCount][b2Shape::e_typeCount];
bool b2Contact::s_initialized = false;
void b2Contact::InitializeRegisters()
{
AddType(b2CircleContact::Create, b2CircleContact::Destroy, b2Shape::e_circle, b2Shape::e_circle);
AddType(b2PolygonAndCircleContact::Create, b2PolygonAndCircleContact::Destroy, b2Shape::e_polygon, b2Shape::e_circle);
AddType(b2PolygonContact::Create, b2PolygonContact::Destroy, b2Shape::e_polygon, b2Shape::e_polygon);
}
void b2Contact::AddType(b2ContactCreateFcn* createFcn, b2ContactDestroyFcn* destoryFcn,
b2Shape::Type type1, b2Shape::Type type2)
{
b2Assert(b2Shape::e_unknown < type1 && type1 < b2Shape::e_typeCount);
b2Assert(b2Shape::e_unknown < type2 && type2 < b2Shape::e_typeCount);
s_registers[type1][type2].createFcn = createFcn;
s_registers[type1][type2].destroyFcn = destoryFcn;
s_registers[type1][type2].primary = true;
if (type1 != type2)
{
s_registers[type2][type1].createFcn = createFcn;
s_registers[type2][type1].destroyFcn = destoryFcn;
s_registers[type2][type1].primary = false;
}
}
b2Contact* b2Contact::Create(b2Fixture* fixtureA, b2Fixture* fixtureB, b2BlockAllocator* allocator)
{
if (s_initialized == false)
{
InitializeRegisters();
s_initialized = true;
}
b2Shape::Type type1 = fixtureA->GetType();
b2Shape::Type type2 = fixtureB->GetType();
b2Assert(b2Shape::e_unknown < type1 && type1 < b2Shape::e_typeCount);
b2Assert(b2Shape::e_unknown < type2 && type2 < b2Shape::e_typeCount);
b2ContactCreateFcn* createFcn = s_registers[type1][type2].createFcn;
if (createFcn)
{
if (s_registers[type1][type2].primary)
{
return createFcn(fixtureA, fixtureB, allocator);
}
else
{
return createFcn(fixtureB, fixtureA, allocator);
}
}
else
{
return NULL;
}
}
void b2Contact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)
{
b2Assert(s_initialized == true);
if (contact->m_manifold.pointCount > 0)
{
contact->GetFixtureA()->GetBody()->SetAwake(true);
contact->GetFixtureB()->GetBody()->SetAwake(true);
}
b2Shape::Type typeA = contact->GetFixtureA()->GetType();
b2Shape::Type typeB = contact->GetFixtureB()->GetType();
b2Assert(b2Shape::e_unknown < typeA && typeB < b2Shape::e_typeCount);
b2Assert(b2Shape::e_unknown < typeA && typeB < b2Shape::e_typeCount);
b2ContactDestroyFcn* destroyFcn = s_registers[typeA][typeB].destroyFcn;
destroyFcn(contact, allocator);
}
b2Contact::b2Contact(b2Fixture* fA, b2Fixture* fB)
{
m_flags = e_enabledFlag;
m_fixtureA = fA;
m_fixtureB = fB;
m_manifold.pointCount = 0;
m_prev = NULL;
m_next = NULL;
m_nodeA.contact = NULL;
m_nodeA.prev = NULL;
m_nodeA.next = NULL;
m_nodeA.other = NULL;
m_nodeB.contact = NULL;
m_nodeB.prev = NULL;
m_nodeB.next = NULL;
m_nodeB.other = NULL;
m_toiCount = 0;
}
// Update the contact manifold and touching status.
// Note: do not assume the fixture AABBs are overlapping or are valid.
void b2Contact::Update(b2ContactListener* listener)
{
b2Manifold oldManifold = m_manifold;
// Re-enable this contact.
m_flags |= e_enabledFlag;
bool touching = false;
bool wasTouching = (m_flags & e_touchingFlag) == e_touchingFlag;
bool sensorA = m_fixtureA->IsSensor();
bool sensorB = m_fixtureB->IsSensor();
bool sensor = sensorA || sensorB;
b2Body* bodyA = m_fixtureA->GetBody();
b2Body* bodyB = m_fixtureB->GetBody();
const b2Transform& xfA = bodyA->GetTransform();
const b2Transform& xfB = bodyB->GetTransform();
// Is this contact a sensor?
if (sensor)
{
const b2Shape* shapeA = m_fixtureA->GetShape();
const b2Shape* shapeB = m_fixtureB->GetShape();
touching = b2TestOverlap(shapeA, shapeB, xfA, xfB);
// Sensors don't generate manifolds.
m_manifold.pointCount = 0;
}
else
{
Evaluate(&m_manifold, xfA, xfB);
touching = m_manifold.pointCount > 0;
// Match old contact ids to new contact ids and copy the
// stored impulses to warm start the solver.
for (int32 i = 0; i < m_manifold.pointCount; ++i)
{
b2ManifoldPoint* mp2 = m_manifold.points + i;
mp2->normalImpulse = 0.0f;
mp2->tangentImpulse = 0.0f;
b2ContactID id2 = mp2->id;
for (int32 j = 0; j < oldManifold.pointCount; ++j)
{
b2ManifoldPoint* mp1 = oldManifold.points + j;
if (mp1->id.key == id2.key)
{
mp2->normalImpulse = mp1->normalImpulse;
mp2->tangentImpulse = mp1->tangentImpulse;
break;
}
}
}
if (touching != wasTouching)
{
bodyA->SetAwake(true);
bodyB->SetAwake(true);
}
}
if (touching)
{
m_flags |= e_touchingFlag;
}
else
{
m_flags &= ~e_touchingFlag;
}
if (wasTouching == false && touching == true && listener)
{
listener->BeginContact(this);
}
if (wasTouching == true && touching == false && listener)
{
listener->EndContact(this);
}
if (sensor == false && touching && listener)
{
listener->PreSolve(this, &oldManifold);
}
}

View file

@ -1,242 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_CONTACT_H
#define B2_CONTACT_H
#include "b2Math.h"
#include "b2Collision.h"
#include "b2Shape.h"
#include "b2Contact.h"
#include "b2Fixture.h"
class b2Body;
class b2Contact;
class b2Fixture;
class b2World;
class b2BlockAllocator;
class b2StackAllocator;
class b2ContactListener;
typedef b2Contact* b2ContactCreateFcn(b2Fixture* fixtureA, b2Fixture* fixtureB, b2BlockAllocator* allocator);
typedef void b2ContactDestroyFcn(b2Contact* contact, b2BlockAllocator* allocator);
struct b2ContactRegister
{
b2ContactCreateFcn* createFcn;
b2ContactDestroyFcn* destroyFcn;
bool primary;
};
/// A contact edge is used to connect bodies and contacts together
/// in a contact graph where each body is a node and each contact
/// is an edge. A contact edge belongs to a doubly linked list
/// maintained in each attached body. Each contact has two contact
/// nodes, one for each attached body.
struct b2ContactEdge
{
b2Body* other; ///< provides quick access to the other body attached.
b2Contact* contact; ///< the contact
b2ContactEdge* prev; ///< the previous contact edge in the body's contact list
b2ContactEdge* next; ///< the next contact edge in the body's contact list
};
/// The class manages contact between two shapes. A contact exists for each overlapping
/// AABB in the broad-phase (except if filtered). Therefore a contact object may exist
/// that has no contact points.
class b2Contact
{
public:
/// Get the contact manifold. Do not modify the manifold unless you understand the
/// internals of Box2D.
b2Manifold* GetManifold();
const b2Manifold* GetManifold() const;
/// Get the world manifold.
void GetWorldManifold(b2WorldManifold* worldManifold) const;
/// Is this contact touching?
bool IsTouching() const;
/// Enable/disable this contact. This can be used inside the pre-solve
/// contact listener. The contact is only disabled for the current
/// time step (or sub-step in continuous collisions).
void SetEnabled(bool flag);
/// Has this contact been disabled?
bool IsEnabled() const;
/// Get the next contact in the world's contact list.
b2Contact* GetNext();
const b2Contact* GetNext() const;
/// Get the first fixture in this contact.
b2Fixture* GetFixtureA();
const b2Fixture* GetFixtureA() const;
/// Get the second fixture in this contact.
b2Fixture* GetFixtureB();
const b2Fixture* GetFixtureB() const;
/// Evaluate this contact with your own manifold and transforms.
virtual void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) = 0;
protected:
friend class b2ContactManager;
friend class b2World;
friend class b2ContactSolver;
friend class b2Body;
friend class b2Fixture;
// Flags stored in m_flags
enum
{
// Used when crawling contact graph when forming islands.
e_islandFlag = 0x0001,
// Set when the shapes are touching.
e_touchingFlag = 0x0002,
// This contact can be disabled (by user)
e_enabledFlag = 0x0004,
// This contact needs filtering because a fixture filter was changed.
e_filterFlag = 0x0008,
// This bullet contact had a TOI event
e_bulletHitFlag = 0x0010,
};
/// Flag this contact for filtering. Filtering will occur the next time step.
void FlagForFiltering();
static void AddType(b2ContactCreateFcn* createFcn, b2ContactDestroyFcn* destroyFcn,
b2Shape::Type typeA, b2Shape::Type typeB);
static void InitializeRegisters();
static b2Contact* Create(b2Fixture* fixtureA, b2Fixture* fixtureB, b2BlockAllocator* allocator);
static void Destroy(b2Contact* contact, b2Shape::Type typeA, b2Shape::Type typeB, b2BlockAllocator* allocator);
static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);
b2Contact() : m_fixtureA(NULL), m_fixtureB(NULL) {}
b2Contact(b2Fixture* fixtureA, b2Fixture* fixtureB);
virtual ~b2Contact() {}
void Update(b2ContactListener* listener);
static b2ContactRegister s_registers[b2Shape::e_typeCount][b2Shape::e_typeCount];
static bool s_initialized;
uint32 m_flags;
// World pool and list pointers.
b2Contact* m_prev;
b2Contact* m_next;
// Nodes for connecting bodies.
b2ContactEdge m_nodeA;
b2ContactEdge m_nodeB;
b2Fixture* m_fixtureA;
b2Fixture* m_fixtureB;
b2Manifold m_manifold;
int32 m_toiCount;
// float32 m_toi;
};
inline b2Manifold* b2Contact::GetManifold()
{
return &m_manifold;
}
inline const b2Manifold* b2Contact::GetManifold() const
{
return &m_manifold;
}
inline void b2Contact::GetWorldManifold(b2WorldManifold* worldManifold) const
{
const b2Body* bodyA = m_fixtureA->GetBody();
const b2Body* bodyB = m_fixtureB->GetBody();
const b2Shape* shapeA = m_fixtureA->GetShape();
const b2Shape* shapeB = m_fixtureB->GetShape();
worldManifold->Initialize(&m_manifold, bodyA->GetTransform(), shapeA->m_radius, bodyB->GetTransform(), shapeB->m_radius);
}
inline void b2Contact::SetEnabled(bool flag)
{
if (flag)
{
m_flags |= e_enabledFlag;
}
else
{
m_flags &= ~e_enabledFlag;
}
}
inline bool b2Contact::IsEnabled() const
{
return (m_flags & e_enabledFlag) == e_enabledFlag;
}
inline bool b2Contact::IsTouching() const
{
return (m_flags & e_touchingFlag) == e_touchingFlag;
}
inline b2Contact* b2Contact::GetNext()
{
return m_next;
}
inline const b2Contact* b2Contact::GetNext() const
{
return m_next;
}
inline b2Fixture* b2Contact::GetFixtureA()
{
return m_fixtureA;
}
inline const b2Fixture* b2Contact::GetFixtureA() const
{
return m_fixtureA;
}
inline b2Fixture* b2Contact::GetFixtureB()
{
return m_fixtureB;
}
inline const b2Fixture* b2Contact::GetFixtureB() const
{
return m_fixtureB;
}
inline void b2Contact::FlagForFiltering()
{
m_flags |= e_filterFlag;
}
#endif

View file

@ -1,52 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_CONTACT_MANAGER_H
#define B2_CONTACT_MANAGER_H
#include "b2BroadPhase.h"
class b2Contact;
class b2ContactFilter;
class b2ContactListener;
class b2BlockAllocator;
// Delegate of b2World.
class b2ContactManager
{
public:
b2ContactManager();
// Broad-phase callback.
void AddPair(void* proxyUserDataA, void* proxyUserDataB);
void FindNewContacts();
void Destroy(b2Contact* c);
void Collide();
b2BroadPhase m_broadPhase;
b2Contact* m_contactList;
int32 m_contactCount;
b2ContactFilter* m_contactFilter;
b2ContactListener* m_contactListener;
b2BlockAllocator* m_allocator;
};
#endif

View file

@ -1,623 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "b2ContactSolver.h"
#include "b2Contact.h"
#include "b2Body.h"
#include "b2Fixture.h"
#include "b2World.h"
#include "b2StackAllocator.h"
#define B2_DEBUG_SOLVER 0
b2ContactSolver::b2ContactSolver(b2Contact** contacts, int32 contactCount,
b2StackAllocator* allocator, float32 impulseRatio)
{
m_allocator = allocator;
m_constraintCount = contactCount;
m_constraints = (b2ContactConstraint*)m_allocator->Allocate(m_constraintCount * sizeof(b2ContactConstraint));
for (int32 i = 0; i < m_constraintCount; ++i)
{
b2Contact* contact = contacts[i];
b2Fixture* fixtureA = contact->m_fixtureA;
b2Fixture* fixtureB = contact->m_fixtureB;
b2Shape* shapeA = fixtureA->GetShape();
b2Shape* shapeB = fixtureB->GetShape();
float32 radiusA = shapeA->m_radius;
float32 radiusB = shapeB->m_radius;
b2Body* bodyA = fixtureA->GetBody();
b2Body* bodyB = fixtureB->GetBody();
b2Manifold* manifold = contact->GetManifold();
float32 friction = b2MixFriction(fixtureA->GetFriction(), fixtureB->GetFriction());
float32 restitution = b2MixRestitution(fixtureA->GetRestitution(), fixtureB->GetRestitution());
b2Vec2 vA = bodyA->m_linearVelocity;
b2Vec2 vB = bodyB->m_linearVelocity;
float32 wA = bodyA->m_angularVelocity;
float32 wB = bodyB->m_angularVelocity;
b2Assert(manifold->pointCount > 0);
b2WorldManifold worldManifold;
worldManifold.Initialize(manifold, bodyA->m_xf, radiusA, bodyB->m_xf, radiusB);
b2ContactConstraint* cc = m_constraints + i;
cc->bodyA = bodyA;
cc->bodyB = bodyB;
cc->manifold = manifold;
cc->normal = worldManifold.normal;
cc->pointCount = manifold->pointCount;
cc->friction = friction;
cc->localNormal = manifold->localNormal;
cc->localPoint = manifold->localPoint;
cc->radius = radiusA + radiusB;
cc->type = manifold->type;
for (int32 j = 0; j < cc->pointCount; ++j)
{
b2ManifoldPoint* cp = manifold->points + j;
b2ContactConstraintPoint* ccp = cc->points + j;
ccp->normalImpulse = impulseRatio * cp->normalImpulse;
ccp->tangentImpulse = impulseRatio * cp->tangentImpulse;
ccp->localPoint = cp->localPoint;
ccp->rA = worldManifold.points[j] - bodyA->m_sweep.c;
ccp->rB = worldManifold.points[j] - bodyB->m_sweep.c;
float32 rnA = b2Cross(ccp->rA, cc->normal);
float32 rnB = b2Cross(ccp->rB, cc->normal);
rnA *= rnA;
rnB *= rnB;
float32 kNormal = bodyA->m_invMass + bodyB->m_invMass + bodyA->m_invI * rnA + bodyB->m_invI * rnB;
b2Assert(kNormal > b2_epsilon);
ccp->normalMass = 1.0f / kNormal;
b2Vec2 tangent = b2Cross(cc->normal, 1.0f);
float32 rtA = b2Cross(ccp->rA, tangent);
float32 rtB = b2Cross(ccp->rB, tangent);
rtA *= rtA;
rtB *= rtB;
float32 kTangent = bodyA->m_invMass + bodyB->m_invMass + bodyA->m_invI * rtA + bodyB->m_invI * rtB;
b2Assert(kTangent > b2_epsilon);
ccp->tangentMass = 1.0f / kTangent;
// Setup a velocity bias for restitution.
ccp->velocityBias = 0.0f;
float32 vRel = b2Dot(cc->normal, vB + b2Cross(wB, ccp->rB) - vA - b2Cross(wA, ccp->rA));
if (vRel < -b2_velocityThreshold)
{
ccp->velocityBias = -restitution * vRel;
}
}
// If we have two points, then prepare the block solver.
if (cc->pointCount == 2)
{
b2ContactConstraintPoint* ccp1 = cc->points + 0;
b2ContactConstraintPoint* ccp2 = cc->points + 1;
float32 invMassA = bodyA->m_invMass;
float32 invIA = bodyA->m_invI;
float32 invMassB = bodyB->m_invMass;
float32 invIB = bodyB->m_invI;
float32 rn1A = b2Cross(ccp1->rA, cc->normal);
float32 rn1B = b2Cross(ccp1->rB, cc->normal);
float32 rn2A = b2Cross(ccp2->rA, cc->normal);
float32 rn2B = b2Cross(ccp2->rB, cc->normal);
float32 k11 = invMassA + invMassB + invIA * rn1A * rn1A + invIB * rn1B * rn1B;
float32 k22 = invMassA + invMassB + invIA * rn2A * rn2A + invIB * rn2B * rn2B;
float32 k12 = invMassA + invMassB + invIA * rn1A * rn2A + invIB * rn1B * rn2B;
// Ensure a reasonable condition number.
const float32 k_maxConditionNumber = 100.0f;
if (k11 * k11 < k_maxConditionNumber * (k11 * k22 - k12 * k12))
{
// K is safe to invert.
cc->K.col1.Set(k11, k12);
cc->K.col2.Set(k12, k22);
cc->normalMass = cc->K.GetInverse();
}
else
{
// The constraints are redundant, just use one.
// TODO_ERIN use deepest?
cc->pointCount = 1;
}
}
}
}
b2ContactSolver::~b2ContactSolver()
{
m_allocator->Free(m_constraints);
}
void b2ContactSolver::WarmStart()
{
// Warm start.
for (int32 i = 0; i < m_constraintCount; ++i)
{
b2ContactConstraint* c = m_constraints + i;
b2Body* bodyA = c->bodyA;
b2Body* bodyB = c->bodyB;
float32 invMassA = bodyA->m_invMass;
float32 invIA = bodyA->m_invI;
float32 invMassB = bodyB->m_invMass;
float32 invIB = bodyB->m_invI;
b2Vec2 normal = c->normal;
b2Vec2 tangent = b2Cross(normal, 1.0f);
for (int32 j = 0; j < c->pointCount; ++j)
{
b2ContactConstraintPoint* ccp = c->points + j;
b2Vec2 P = ccp->normalImpulse * normal + ccp->tangentImpulse * tangent;
bodyA->m_angularVelocity -= invIA * b2Cross(ccp->rA, P);
bodyA->m_linearVelocity -= invMassA * P;
bodyB->m_angularVelocity += invIB * b2Cross(ccp->rB, P);
bodyB->m_linearVelocity += invMassB * P;
}
}
}
void b2ContactSolver::SolveVelocityConstraints()
{
for (int32 i = 0; i < m_constraintCount; ++i)
{
b2ContactConstraint* c = m_constraints + i;
b2Body* bodyA = c->bodyA;
b2Body* bodyB = c->bodyB;
float32 wA = bodyA->m_angularVelocity;
float32 wB = bodyB->m_angularVelocity;
b2Vec2 vA = bodyA->m_linearVelocity;
b2Vec2 vB = bodyB->m_linearVelocity;
float32 invMassA = bodyA->m_invMass;
float32 invIA = bodyA->m_invI;
float32 invMassB = bodyB->m_invMass;
float32 invIB = bodyB->m_invI;
b2Vec2 normal = c->normal;
b2Vec2 tangent = b2Cross(normal, 1.0f);
float32 friction = c->friction;
b2Assert(c->pointCount == 1 || c->pointCount == 2);
// Solve tangent constraints
for (int32 j = 0; j < c->pointCount; ++j)
{
b2ContactConstraintPoint* ccp = c->points + j;
// Relative velocity at contact
b2Vec2 dv = vB + b2Cross(wB, ccp->rB) - vA - b2Cross(wA, ccp->rA);
// Compute tangent force
float32 vt = b2Dot(dv, tangent);
float32 lambda = ccp->tangentMass * (-vt);
// b2Clamp the accumulated force
float32 maxFriction = friction * ccp->normalImpulse;
float32 newImpulse = b2Clamp(ccp->tangentImpulse + lambda, -maxFriction, maxFriction);
lambda = newImpulse - ccp->tangentImpulse;
// Apply contact impulse
b2Vec2 P = lambda * tangent;
vA -= invMassA * P;
wA -= invIA * b2Cross(ccp->rA, P);
vB += invMassB * P;
wB += invIB * b2Cross(ccp->rB, P);
ccp->tangentImpulse = newImpulse;
}
// Solve normal constraints
if (c->pointCount == 1)
{
b2ContactConstraintPoint* ccp = c->points + 0;
// Relative velocity at contact
b2Vec2 dv = vB + b2Cross(wB, ccp->rB) - vA - b2Cross(wA, ccp->rA);
// Compute normal impulse
float32 vn = b2Dot(dv, normal);
float32 lambda = -ccp->normalMass * (vn - ccp->velocityBias);
// b2Clamp the accumulated impulse
float32 newImpulse = b2Max(ccp->normalImpulse + lambda, 0.0f);
lambda = newImpulse - ccp->normalImpulse;
// Apply contact impulse
b2Vec2 P = lambda * normal;
vA -= invMassA * P;
wA -= invIA * b2Cross(ccp->rA, P);
vB += invMassB * P;
wB += invIB * b2Cross(ccp->rB, P);
ccp->normalImpulse = newImpulse;
}
else
{
// Block solver developed in collaboration with Dirk Gregorius (back in 01/07 on Box2D_Lite).
// Build the mini LCP for this contact patch
//
// vn = A * x + b, vn >= 0, , vn >= 0, x >= 0 and vn_i * x_i = 0 with i = 1..2
//
// A = J * W * JT and J = ( -n, -r1 x n, n, r2 x n )
// b = vn_0 - velocityBias
//
// The system is solved using the "Total enumeration method" (s. Murty). The complementary constraint vn_i * x_i
// implies that we must have in any solution either vn_i = 0 or x_i = 0. So for the 2D contact problem the cases
// vn1 = 0 and vn2 = 0, x1 = 0 and x2 = 0, x1 = 0 and vn2 = 0, x2 = 0 and vn1 = 0 need to be tested. The first valid
// solution that satisfies the problem is chosen.
//
// In order to account of the accumulated impulse 'a' (because of the iterative nature of the solver which only requires
// that the accumulated impulse is clamped and not the incremental impulse) we change the impulse variable (x_i).
//
// Substitute:
//
// x = x' - a
//
// Plug into above equation:
//
// vn = A * x + b
// = A * (x' - a) + b
// = A * x' + b - A * a
// = A * x' + b'
// b' = b - A * a;
b2ContactConstraintPoint* cp1 = c->points + 0;
b2ContactConstraintPoint* cp2 = c->points + 1;
b2Vec2 a(cp1->normalImpulse, cp2->normalImpulse);
b2Assert(a.x >= 0.0f && a.y >= 0.0f);
// Relative velocity at contact
b2Vec2 dv1 = vB + b2Cross(wB, cp1->rB) - vA - b2Cross(wA, cp1->rA);
b2Vec2 dv2 = vB + b2Cross(wB, cp2->rB) - vA - b2Cross(wA, cp2->rA);
// Compute normal velocity
float32 vn1 = b2Dot(dv1, normal);
float32 vn2 = b2Dot(dv2, normal);
b2Vec2 b;
b.x = vn1 - cp1->velocityBias;
b.y = vn2 - cp2->velocityBias;
b -= b2Mul(c->K, a);
const float32 k_errorTol = 1e-3f;
B2_NOT_USED(k_errorTol);
for (;;)
{
//
// Case 1: vn = 0
//
// 0 = A * x' + b'
//
// Solve for x':
//
// x' = - inv(A) * b'
//
b2Vec2 x = - b2Mul(c->normalMass, b);
if (x.x >= 0.0f && x.y >= 0.0f)
{
// Resubstitute for the incremental impulse
b2Vec2 d = x - a;
// Apply incremental impulse
b2Vec2 P1 = d.x * normal;
b2Vec2 P2 = d.y * normal;
vA -= invMassA * (P1 + P2);
wA -= invIA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2));
vB += invMassB * (P1 + P2);
wB += invIB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2));
// Accumulate
cp1->normalImpulse = x.x;
cp2->normalImpulse = x.y;
#if B2_DEBUG_SOLVER == 1
// Postconditions
dv1 = vB + b2Cross(wB, cp1->rB) - vA - b2Cross(wA, cp1->rA);
dv2 = vB + b2Cross(wB, cp2->rB) - vA - b2Cross(wA, cp2->rA);
// Compute normal velocity
vn1 = b2Dot(dv1, normal);
vn2 = b2Dot(dv2, normal);
b2Assert(b2Abs(vn1 - cp1->velocityBias) < k_errorTol);
b2Assert(b2Abs(vn2 - cp2->velocityBias) < k_errorTol);
#endif
break;
}
//
// Case 2: vn1 = 0 and x2 = 0
//
// 0 = a11 * x1' + a12 * 0 + b1'
// vn2 = a21 * x1' + a22 * 0 + b2'
//
x.x = - cp1->normalMass * b.x;
x.y = 0.0f;
vn1 = 0.0f;
vn2 = c->K.col1.y * x.x + b.y;
if (x.x >= 0.0f && vn2 >= 0.0f)
{
// Resubstitute for the incremental impulse
b2Vec2 d = x - a;
// Apply incremental impulse
b2Vec2 P1 = d.x * normal;
b2Vec2 P2 = d.y * normal;
vA -= invMassA * (P1 + P2);
wA -= invIA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2));
vB += invMassB * (P1 + P2);
wB += invIB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2));
// Accumulate
cp1->normalImpulse = x.x;
cp2->normalImpulse = x.y;
#if B2_DEBUG_SOLVER == 1
// Postconditions
dv1 = vB + b2Cross(wB, cp1->rB) - vA - b2Cross(wA, cp1->rA);
// Compute normal velocity
vn1 = b2Dot(dv1, normal);
b2Assert(b2Abs(vn1 - cp1->velocityBias) < k_errorTol);
#endif
break;
}
//
// Case 3: vn2 = 0 and x1 = 0
//
// vn1 = a11 * 0 + a12 * x2' + b1'
// 0 = a21 * 0 + a22 * x2' + b2'
//
x.x = 0.0f;
x.y = - cp2->normalMass * b.y;
vn1 = c->K.col2.x * x.y + b.x;
vn2 = 0.0f;
if (x.y >= 0.0f && vn1 >= 0.0f)
{
// Resubstitute for the incremental impulse
b2Vec2 d = x - a;
// Apply incremental impulse
b2Vec2 P1 = d.x * normal;
b2Vec2 P2 = d.y * normal;
vA -= invMassA * (P1 + P2);
wA -= invIA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2));
vB += invMassB * (P1 + P2);
wB += invIB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2));
// Accumulate
cp1->normalImpulse = x.x;
cp2->normalImpulse = x.y;
#if B2_DEBUG_SOLVER == 1
// Postconditions
dv2 = vB + b2Cross(wB, cp2->rB) - vA - b2Cross(wA, cp2->rA);
// Compute normal velocity
vn2 = b2Dot(dv2, normal);
b2Assert(b2Abs(vn2 - cp2->velocityBias) < k_errorTol);
#endif
break;
}
//
// Case 4: x1 = 0 and x2 = 0
//
// vn1 = b1
// vn2 = b2;
x.x = 0.0f;
x.y = 0.0f;
vn1 = b.x;
vn2 = b.y;
if (vn1 >= 0.0f && vn2 >= 0.0f )
{
// Resubstitute for the incremental impulse
b2Vec2 d = x - a;
// Apply incremental impulse
b2Vec2 P1 = d.x * normal;
b2Vec2 P2 = d.y * normal;
vA -= invMassA * (P1 + P2);
wA -= invIA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2));
vB += invMassB * (P1 + P2);
wB += invIB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2));
// Accumulate
cp1->normalImpulse = x.x;
cp2->normalImpulse = x.y;
break;
}
// No solution, give up. This is hit sometimes, but it doesn't seem to matter.
break;
}
}
bodyA->m_linearVelocity = vA;
bodyA->m_angularVelocity = wA;
bodyB->m_linearVelocity = vB;
bodyB->m_angularVelocity = wB;
}
}
void b2ContactSolver::StoreImpulses()
{
for (int32 i = 0; i < m_constraintCount; ++i)
{
b2ContactConstraint* c = m_constraints + i;
b2Manifold* m = c->manifold;
for (int32 j = 0; j < c->pointCount; ++j)
{
m->points[j].normalImpulse = c->points[j].normalImpulse;
m->points[j].tangentImpulse = c->points[j].tangentImpulse;
}
}
}
struct b2PositionSolverManifold
{
void Initialize(b2ContactConstraint* cc, int32 index)
{
b2Assert(cc->pointCount > 0);
switch (cc->type)
{
case b2Manifold::e_circles:
{
b2Vec2 pointA = cc->bodyA->GetWorldPoint(cc->localPoint);
b2Vec2 pointB = cc->bodyB->GetWorldPoint(cc->points[0].localPoint);
if (b2DistanceSquared(pointA, pointB) > b2_epsilon * b2_epsilon)
{
normal = pointB - pointA;
normal.Normalize();
}
else
{
normal.Set(1.0f, 0.0f);
}
point = 0.5f * (pointA + pointB);
separation = b2Dot(pointB - pointA, normal) - cc->radius;
}
break;
case b2Manifold::e_faceA:
{
normal = cc->bodyA->GetWorldVector(cc->localNormal);
b2Vec2 planePoint = cc->bodyA->GetWorldPoint(cc->localPoint);
b2Vec2 clipPoint = cc->bodyB->GetWorldPoint(cc->points[index].localPoint);
separation = b2Dot(clipPoint - planePoint, normal) - cc->radius;
point = clipPoint;
}
break;
case b2Manifold::e_faceB:
{
normal = cc->bodyB->GetWorldVector(cc->localNormal);
b2Vec2 planePoint = cc->bodyB->GetWorldPoint(cc->localPoint);
b2Vec2 clipPoint = cc->bodyA->GetWorldPoint(cc->points[index].localPoint);
separation = b2Dot(clipPoint - planePoint, normal) - cc->radius;
point = clipPoint;
// Ensure normal points from A to B
normal = -normal;
}
break;
}
}
b2Vec2 normal;
b2Vec2 point;
float32 separation;
};
// Sequential solver.
bool b2ContactSolver::SolvePositionConstraints(float32 baumgarte)
{
float32 minSeparation = 0.0f;
for (int32 i = 0; i < m_constraintCount; ++i)
{
b2ContactConstraint* c = m_constraints + i;
b2Body* bodyA = c->bodyA;
b2Body* bodyB = c->bodyB;
float32 invMassA = bodyA->m_mass * bodyA->m_invMass;
float32 invIA = bodyA->m_mass * bodyA->m_invI;
float32 invMassB = bodyB->m_mass * bodyB->m_invMass;
float32 invIB = bodyB->m_mass * bodyB->m_invI;
// Solve normal constraints
for (int32 j = 0; j < c->pointCount; ++j)
{
b2PositionSolverManifold psm;
psm.Initialize(c, j);
b2Vec2 normal = psm.normal;
b2Vec2 point = psm.point;
float32 separation = psm.separation;
b2Vec2 rA = point - bodyA->m_sweep.c;
b2Vec2 rB = point - bodyB->m_sweep.c;
// Track max constraint error.
minSeparation = b2Min(minSeparation, separation);
// Prevent large corrections and allow slop.
float32 C = b2Clamp(baumgarte * (separation + b2_linearSlop), -b2_maxLinearCorrection, 0.0f);
// Compute the effective mass.
float32 rnA = b2Cross(rA, normal);
float32 rnB = b2Cross(rB, normal);
float32 K = invMassA + invMassB + invIA * rnA * rnA + invIB * rnB * rnB;
// Compute normal impulse
float32 impulse = K > 0.0f ? - C / K : 0.0f;
b2Vec2 P = impulse * normal;
bodyA->m_sweep.c -= invMassA * P;
bodyA->m_sweep.a -= invIA * b2Cross(rA, P);
bodyA->SynchronizeTransform();
bodyB->m_sweep.c += invMassB * P;
bodyB->m_sweep.a += invIB * b2Cross(rB, P);
bodyB->SynchronizeTransform();
}
}
// We can't expect minSpeparation >= -b2_linearSlop because we don't
// push the separation above -b2_linearSlop.
return minSeparation >= -1.5f * b2_linearSlop;
}

View file

@ -1,78 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_CONTACT_SOLVER_H
#define B2_CONTACT_SOLVER_H
#include "b2Math.h"
#include "b2Collision.h"
#include "b2Island.h"
class b2Contact;
class b2Body;
class b2StackAllocator;
struct b2ContactConstraintPoint
{
b2Vec2 localPoint;
b2Vec2 rA;
b2Vec2 rB;
float32 normalImpulse;
float32 tangentImpulse;
float32 normalMass;
float32 tangentMass;
float32 velocityBias;
};
struct b2ContactConstraint
{
b2ContactConstraintPoint points[b2_maxManifoldPoints];
b2Vec2 localNormal;
b2Vec2 localPoint;
b2Vec2 normal;
b2Mat22 normalMass;
b2Mat22 K;
b2Body* bodyA;
b2Body* bodyB;
b2Manifold::Type type;
float32 radius;
float32 friction;
int32 pointCount;
b2Manifold* manifold;
};
class b2ContactSolver
{
public:
b2ContactSolver(b2Contact** contacts, int32 contactCount,
b2StackAllocator* allocator, float32 impulseRatio);
~b2ContactSolver();
void WarmStart();
void SolveVelocityConstraints();
void StoreImpulses();
bool SolvePositionConstraints(float32 baumgarte);
b2StackAllocator* m_allocator;
b2ContactConstraint* m_constraints;
int m_constraintCount;
};
#endif

View file

@ -1,141 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_DISTANCE_H
#define B2_DISTANCE_H
#include "b2Math.h"
#include <climits>
class b2Shape;
/// A distance proxy is used by the GJK algorithm.
/// It encapsulates any shape.
struct b2DistanceProxy
{
b2DistanceProxy() : m_vertices(NULL), m_count(0), m_radius(0.0f) {}
/// Initialize the proxy using the given shape. The shape
/// must remain in scope while the proxy is in use.
void Set(const b2Shape* shape);
/// Get the supporting vertex index in the given direction.
int32 GetSupport(const b2Vec2& d) const;
/// Get the supporting vertex in the given direction.
const b2Vec2& GetSupportVertex(const b2Vec2& d) const;
/// Get the vertex count.
int32 GetVertexCount() const;
/// Get a vertex by index. Used by b2Distance.
const b2Vec2& GetVertex(int32 index) const;
const b2Vec2* m_vertices;
int32 m_count;
float32 m_radius;
};
/// Used to warm start b2Distance.
/// Set count to zero on first call.
struct b2SimplexCache
{
float32 metric; ///< length or area
uint16 count;
uint8 indexA[3]; ///< vertices on shape A
uint8 indexB[3]; ///< vertices on shape B
};
/// Input for b2Distance.
/// You have to option to use the shape radii
/// in the computation. Even
struct b2DistanceInput
{
b2DistanceProxy proxyA;
b2DistanceProxy proxyB;
b2Transform transformA;
b2Transform transformB;
bool useRadii;
};
/// Output for b2Distance.
struct b2DistanceOutput
{
b2Vec2 pointA; ///< closest point on shapeA
b2Vec2 pointB; ///< closest point on shapeB
float32 distance;
int32 iterations; ///< number of GJK iterations used
};
/// Compute the closest points between two shapes. Supports any combination of:
/// b2CircleShape, b2PolygonShape, b2EdgeShape. The simplex cache is input/output.
/// On the first call set b2SimplexCache.count to zero.
void b2Distance(b2DistanceOutput* output,
b2SimplexCache* cache,
const b2DistanceInput* input);
//////////////////////////////////////////////////////////////////////////
inline int32 b2DistanceProxy::GetVertexCount() const
{
return m_count;
}
inline const b2Vec2& b2DistanceProxy::GetVertex(int32 index) const
{
b2Assert(0 <= index && index < m_count);
return m_vertices[index];
}
inline int32 b2DistanceProxy::GetSupport(const b2Vec2& d) const
{
int32 bestIndex = 0;
float32 bestValue = b2Dot(m_vertices[0], d);
for (int32 i = 1; i < m_count; ++i)
{
float32 value = b2Dot(m_vertices[i], d);
if (value > bestValue)
{
bestIndex = i;
bestValue = value;
}
}
return bestIndex;
}
inline const b2Vec2& b2DistanceProxy::GetSupportVertex(const b2Vec2& d) const
{
int32 bestIndex = 0;
float32 bestValue = b2Dot(m_vertices[0], d);
for (int32 i = 1; i < m_count; ++i)
{
float32 value = b2Dot(m_vertices[i], d);
if (value > bestValue)
{
bestIndex = i;
bestValue = value;
}
}
return m_vertices[bestIndex];
}
#endif

View file

@ -1,211 +0,0 @@
/*
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "b2DistanceJoint.h"
#include "b2Body.h"
#include "b2TimeStep.h"
// 1-D constrained system
// m (v2 - v1) = lambda
// v2 + (beta/h) * x1 + gamma * lambda = 0, gamma has units of inverse mass.
// x2 = x1 + h * v2
// 1-D mass-damper-spring system
// m (v2 - v1) + h * d * v2 + h * k *
// C = norm(p2 - p1) - L
// u = (p2 - p1) / norm(p2 - p1)
// Cdot = dot(u, v2 + cross(w2, r2) - v1 - cross(w1, r1))
// J = [-u -cross(r1, u) u cross(r2, u)]
// K = J * invM * JT
// = invMass1 + invI1 * cross(r1, u)^2 + invMass2 + invI2 * cross(r2, u)^2
void b2DistanceJointDef::Initialize(b2Body* b1, b2Body* b2,
const b2Vec2& anchor1, const b2Vec2& anchor2)
{
bodyA = b1;
bodyB = b2;
localAnchorA = bodyA->GetLocalPoint(anchor1);
localAnchorB = bodyB->GetLocalPoint(anchor2);
b2Vec2 d = anchor2 - anchor1;
length = d.Length();
}
b2DistanceJoint::b2DistanceJoint(const b2DistanceJointDef* def)
: b2Joint(def)
{
m_localAnchor1 = def->localAnchorA;
m_localAnchor2 = def->localAnchorB;
m_length = def->length;
m_frequencyHz = def->frequencyHz;
m_dampingRatio = def->dampingRatio;
m_impulse = 0.0f;
m_gamma = 0.0f;
m_bias = 0.0f;
}
void b2DistanceJoint::InitVelocityConstraints(const b2TimeStep& step)
{
b2Body* b1 = m_bodyA;
b2Body* b2 = m_bodyB;
// Compute the effective mass matrix.
b2Vec2 r1 = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter());
b2Vec2 r2 = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter());
m_u = b2->m_sweep.c + r2 - b1->m_sweep.c - r1;
// Handle singularity.
float32 length = m_u.Length();
if (length > b2_linearSlop)
{
m_u *= 1.0f / length;
}
else
{
m_u.Set(0.0f, 0.0f);
}
float32 cr1u = b2Cross(r1, m_u);
float32 cr2u = b2Cross(r2, m_u);
float32 invMass = b1->m_invMass + b1->m_invI * cr1u * cr1u + b2->m_invMass + b2->m_invI * cr2u * cr2u;
m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f;
if (m_frequencyHz > 0.0f)
{
float32 C = length - m_length;
// Frequency
float32 omega = 2.0f * b2_pi * m_frequencyHz;
// Damping coefficient
float32 d = 2.0f * m_mass * m_dampingRatio * omega;
// Spring stiffness
float32 k = m_mass * omega * omega;
// magic formulas
m_gamma = step.dt * (d + step.dt * k);
m_gamma = m_gamma != 0.0f ? 1.0f / m_gamma : 0.0f;
m_bias = C * step.dt * k * m_gamma;
m_mass = invMass + m_gamma;
m_mass = m_mass != 0.0f ? 1.0f / m_mass : 0.0f;
}
if (step.warmStarting)
{
// Scale the impulse to support a variable time step.
m_impulse *= step.dtRatio;
b2Vec2 P = m_impulse * m_u;
b1->m_linearVelocity -= b1->m_invMass * P;
b1->m_angularVelocity -= b1->m_invI * b2Cross(r1, P);
b2->m_linearVelocity += b2->m_invMass * P;
b2->m_angularVelocity += b2->m_invI * b2Cross(r2, P);
}
else
{
m_impulse = 0.0f;
}
}
void b2DistanceJoint::SolveVelocityConstraints(const b2TimeStep& step)
{
B2_NOT_USED(step);
b2Body* b1 = m_bodyA;
b2Body* b2 = m_bodyB;
b2Vec2 r1 = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter());
b2Vec2 r2 = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter());
// Cdot = dot(u, v + cross(w, r))
b2Vec2 v1 = b1->m_linearVelocity + b2Cross(b1->m_angularVelocity, r1);
b2Vec2 v2 = b2->m_linearVelocity + b2Cross(b2->m_angularVelocity, r2);
float32 Cdot = b2Dot(m_u, v2 - v1);
float32 impulse = -m_mass * (Cdot + m_bias + m_gamma * m_impulse);
m_impulse += impulse;
b2Vec2 P = impulse * m_u;
b1->m_linearVelocity -= b1->m_invMass * P;
b1->m_angularVelocity -= b1->m_invI * b2Cross(r1, P);
b2->m_linearVelocity += b2->m_invMass * P;
b2->m_angularVelocity += b2->m_invI * b2Cross(r2, P);
}
bool b2DistanceJoint::SolvePositionConstraints(float32 baumgarte)
{
B2_NOT_USED(baumgarte);
if (m_frequencyHz > 0.0f)
{
// There is no position correction for soft distance constraints.
return true;
}
b2Body* b1 = m_bodyA;
b2Body* b2 = m_bodyB;
b2Vec2 r1 = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter());
b2Vec2 r2 = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter());
b2Vec2 d = b2->m_sweep.c + r2 - b1->m_sweep.c - r1;
float32 length = d.Normalize();
float32 C = length - m_length;
C = b2Clamp(C, -b2_maxLinearCorrection, b2_maxLinearCorrection);
float32 impulse = -m_mass * C;
m_u = d;
b2Vec2 P = impulse * m_u;
b1->m_sweep.c -= b1->m_invMass * P;
b1->m_sweep.a -= b1->m_invI * b2Cross(r1, P);
b2->m_sweep.c += b2->m_invMass * P;
b2->m_sweep.a += b2->m_invI * b2Cross(r2, P);
b1->SynchronizeTransform();
b2->SynchronizeTransform();
return b2Abs(C) < b2_linearSlop;
}
b2Vec2 b2DistanceJoint::GetAnchorA() const
{
return m_bodyA->GetWorldPoint(m_localAnchor1);
}
b2Vec2 b2DistanceJoint::GetAnchorB() const
{
return m_bodyB->GetWorldPoint(m_localAnchor2);
}
b2Vec2 b2DistanceJoint::GetReactionForce(float32 inv_dt) const
{
b2Vec2 F = (inv_dt * m_impulse) * m_u;
return F;
}
float32 b2DistanceJoint::GetReactionTorque(float32 inv_dt) const
{
B2_NOT_USED(inv_dt);
return 0.0f;
}

View file

@ -1,140 +0,0 @@
/*
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_DISTANCE_JOINT_H
#define B2_DISTANCE_JOINT_H
#include "b2Joint.h"
/// Distance joint definition. This requires defining an
/// anchor point on both bodies and the non-zero length of the
/// distance joint. The definition uses local anchor points
/// so that the initial configuration can violate the constraint
/// slightly. This helps when saving and loading a game.
/// @warning Do not use a zero or short length.
struct b2DistanceJointDef : public b2JointDef
{
b2DistanceJointDef()
{
type = e_distanceJoint;
localAnchorA.Set(0.0f, 0.0f);
localAnchorB.Set(0.0f, 0.0f);
length = 1.0f;
frequencyHz = 0.0f;
dampingRatio = 0.0f;
}
/// Initialize the bodies, anchors, and length using the world
/// anchors.
void Initialize(b2Body* bodyA, b2Body* bodyB,
const b2Vec2& anchorA, const b2Vec2& anchorB);
/// The local anchor point relative to body1's origin.
b2Vec2 localAnchorA;
/// The local anchor point relative to body2's origin.
b2Vec2 localAnchorB;
/// The natural length between the anchor points.
float32 length;
/// The mass-spring-damper frequency in Hertz.
float32 frequencyHz;
/// The damping ratio. 0 = no damping, 1 = critical damping.
float32 dampingRatio;
};
/// A distance joint constrains two points on two bodies
/// to remain at a fixed distance from each other. You can view
/// this as a massless, rigid rod.
class b2DistanceJoint : public b2Joint
{
public:
b2Vec2 GetAnchorA() const;
b2Vec2 GetAnchorB() const;
b2Vec2 GetReactionForce(float32 inv_dt) const;
float32 GetReactionTorque(float32 inv_dt) const;
/// Set/get the natural length.
/// Manipulating the length can lead to non-physical behavior when the frequency is zero.
void SetLength(float32 length);
float32 GetLength() const;
// Set/get frequency in Hz.
void SetFrequency(float32 hz);
float32 GetFrequency() const;
// Set/get damping ratio.
void SetDampingRatio(float32 ratio);
float32 GetDampingRatio() const;
protected:
friend class b2Joint;
b2DistanceJoint(const b2DistanceJointDef* data);
void InitVelocityConstraints(const b2TimeStep& step);
void SolveVelocityConstraints(const b2TimeStep& step);
bool SolvePositionConstraints(float32 baumgarte);
b2Vec2 m_localAnchor1;
b2Vec2 m_localAnchor2;
b2Vec2 m_u;
float32 m_frequencyHz;
float32 m_dampingRatio;
float32 m_gamma;
float32 m_bias;
float32 m_impulse;
float32 m_mass;
float32 m_length;
};
inline void b2DistanceJoint::SetLength(float32 length)
{
m_length = length;
}
inline float32 b2DistanceJoint::GetLength() const
{
return m_length;
}
inline void b2DistanceJoint::SetFrequency(float32 hz)
{
m_frequencyHz = hz;
}
inline float32 b2DistanceJoint::GetFrequency() const
{
return m_frequencyHz;
}
inline void b2DistanceJoint::SetDampingRatio(float32 ratio)
{
m_dampingRatio = ratio;
}
inline float32 b2DistanceJoint::GetDampingRatio() const
{
return m_dampingRatio;
}
#endif

View file

@ -1,365 +0,0 @@
/*
* Copyright (c) 2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "b2DynamicTree.h"
#include <cstring>
#include <cfloat>
b2DynamicTree::b2DynamicTree()
{
m_root = b2_nullNode;
m_nodeCapacity = 16;
m_nodeCount = 0;
m_nodes = (b2DynamicTreeNode*)b2Alloc(m_nodeCapacity * sizeof(b2DynamicTreeNode));
memset(m_nodes, 0, m_nodeCapacity * sizeof(b2DynamicTreeNode));
// Build a linked list for the free list.
for (int32 i = 0; i < m_nodeCapacity - 1; ++i)
{
m_nodes[i].next = i + 1;
}
m_nodes[m_nodeCapacity-1].next = b2_nullNode;
m_freeList = 0;
m_path = 0;
m_insertionCount = 0;
}
b2DynamicTree::~b2DynamicTree()
{
// This frees the entire tree in one shot.
b2Free(m_nodes);
}
// Allocate a node from the pool. Grow the pool if necessary.
int32 b2DynamicTree::AllocateNode()
{
// Expand the node pool as needed.
if (m_freeList == b2_nullNode)
{
b2Assert(m_nodeCount == m_nodeCapacity);
// The free list is empty. Rebuild a bigger pool.
b2DynamicTreeNode* oldNodes = m_nodes;
m_nodeCapacity *= 2;
m_nodes = (b2DynamicTreeNode*)b2Alloc(m_nodeCapacity * sizeof(b2DynamicTreeNode));
memcpy(m_nodes, oldNodes, m_nodeCount * sizeof(b2DynamicTreeNode));
b2Free(oldNodes);
// Build a linked list for the free list. The parent
// pointer becomes the "next" pointer.
for (int32 i = m_nodeCount; i < m_nodeCapacity - 1; ++i)
{
m_nodes[i].next = i + 1;
}
m_nodes[m_nodeCapacity-1].next = b2_nullNode;
m_freeList = m_nodeCount;
}
// Peel a node off the free list.
int32 nodeId = m_freeList;
m_freeList = m_nodes[nodeId].next;
m_nodes[nodeId].parent = b2_nullNode;
m_nodes[nodeId].child1 = b2_nullNode;
m_nodes[nodeId].child2 = b2_nullNode;
++m_nodeCount;
return nodeId;
}
// Return a node to the pool.
void b2DynamicTree::FreeNode(int32 nodeId)
{
b2Assert(0 <= nodeId && nodeId < m_nodeCapacity);
b2Assert(0 < m_nodeCount);
m_nodes[nodeId].next = m_freeList;
m_freeList = nodeId;
--m_nodeCount;
}
// Create a proxy in the tree as a leaf node. We return the index
// of the node instead of a pointer so that we can grow
// the node pool.
int32 b2DynamicTree::CreateProxy(const b2AABB& aabb, void* userData)
{
int32 proxyId = AllocateNode();
// Fatten the aabb.
b2Vec2 r(b2_aabbExtension, b2_aabbExtension);
m_nodes[proxyId].aabb.lowerBound = aabb.lowerBound - r;
m_nodes[proxyId].aabb.upperBound = aabb.upperBound + r;
m_nodes[proxyId].userData = userData;
InsertLeaf(proxyId);
// Rebalance if necessary.
int32 iterationCount = m_nodeCount >> 4;
int32 tryCount = 0;
int32 height = ComputeHeight();
while (height > 64 && tryCount < 10)
{
Rebalance(iterationCount);
height = ComputeHeight();
++tryCount;
}
return proxyId;
}
void b2DynamicTree::DestroyProxy(int32 proxyId)
{
b2Assert(0 <= proxyId && proxyId < m_nodeCapacity);
b2Assert(m_nodes[proxyId].IsLeaf());
RemoveLeaf(proxyId);
FreeNode(proxyId);
}
bool b2DynamicTree::MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement)
{
b2Assert(0 <= proxyId && proxyId < m_nodeCapacity);
b2Assert(m_nodes[proxyId].IsLeaf());
if (m_nodes[proxyId].aabb.Contains(aabb))
{
return false;
}
RemoveLeaf(proxyId);
// Extend AABB.
b2AABB b = aabb;
b2Vec2 r(b2_aabbExtension, b2_aabbExtension);
b.lowerBound = b.lowerBound - r;
b.upperBound = b.upperBound + r;
// Predict AABB displacement.
b2Vec2 d = b2_aabbMultiplier * displacement;
if (d.x < 0.0f)
{
b.lowerBound.x += d.x;
}
else
{
b.upperBound.x += d.x;
}
if (d.y < 0.0f)
{
b.lowerBound.y += d.y;
}
else
{
b.upperBound.y += d.y;
}
m_nodes[proxyId].aabb = b;
InsertLeaf(proxyId);
return true;
}
void b2DynamicTree::InsertLeaf(int32 leaf)
{
++m_insertionCount;
if (m_root == b2_nullNode)
{
m_root = leaf;
m_nodes[m_root].parent = b2_nullNode;
return;
}
// Find the best sibling for this node.
b2Vec2 center = m_nodes[leaf].aabb.GetCenter();
int32 sibling = m_root;
if (m_nodes[sibling].IsLeaf() == false)
{
do
{
int32 child1 = m_nodes[sibling].child1;
int32 child2 = m_nodes[sibling].child2;
b2Vec2 delta1 = b2Abs(m_nodes[child1].aabb.GetCenter() - center);
b2Vec2 delta2 = b2Abs(m_nodes[child2].aabb.GetCenter() - center);
float32 norm1 = delta1.x + delta1.y;
float32 norm2 = delta2.x + delta2.y;
if (norm1 < norm2)
{
sibling = child1;
}
else
{
sibling = child2;
}
}
while(m_nodes[sibling].IsLeaf() == false);
}
// Create a parent for the siblings.
int32 node1 = m_nodes[sibling].parent;
int32 node2 = AllocateNode();
m_nodes[node2].parent = node1;
m_nodes[node2].userData = NULL;
m_nodes[node2].aabb.Combine(m_nodes[leaf].aabb, m_nodes[sibling].aabb);
if (node1 != b2_nullNode)
{
if (m_nodes[m_nodes[sibling].parent].child1 == sibling)
{
m_nodes[node1].child1 = node2;
}
else
{
m_nodes[node1].child2 = node2;
}
m_nodes[node2].child1 = sibling;
m_nodes[node2].child2 = leaf;
m_nodes[sibling].parent = node2;
m_nodes[leaf].parent = node2;
do
{
if (m_nodes[node1].aabb.Contains(m_nodes[node2].aabb))
{
break;
}
m_nodes[node1].aabb.Combine(m_nodes[m_nodes[node1].child1].aabb, m_nodes[m_nodes[node1].child2].aabb);
node2 = node1;
node1 = m_nodes[node1].parent;
}
while(node1 != b2_nullNode);
}
else
{
m_nodes[node2].child1 = sibling;
m_nodes[node2].child2 = leaf;
m_nodes[sibling].parent = node2;
m_nodes[leaf].parent = node2;
m_root = node2;
}
}
void b2DynamicTree::RemoveLeaf(int32 leaf)
{
if (leaf == m_root)
{
m_root = b2_nullNode;
return;
}
int32 node2 = m_nodes[leaf].parent;
int32 node1 = m_nodes[node2].parent;
int32 sibling;
if (m_nodes[node2].child1 == leaf)
{
sibling = m_nodes[node2].child2;
}
else
{
sibling = m_nodes[node2].child1;
}
if (node1 != b2_nullNode)
{
// Destroy node2 and connect node1 to sibling.
if (m_nodes[node1].child1 == node2)
{
m_nodes[node1].child1 = sibling;
}
else
{
m_nodes[node1].child2 = sibling;
}
m_nodes[sibling].parent = node1;
FreeNode(node2);
// Adjust ancestor bounds.
while (node1 != b2_nullNode)
{
b2AABB oldAABB = m_nodes[node1].aabb;
m_nodes[node1].aabb.Combine(m_nodes[m_nodes[node1].child1].aabb, m_nodes[m_nodes[node1].child2].aabb);
if (oldAABB.Contains(m_nodes[node1].aabb))
{
break;
}
node1 = m_nodes[node1].parent;
}
}
else
{
m_root = sibling;
m_nodes[sibling].parent = b2_nullNode;
FreeNode(node2);
}
}
void b2DynamicTree::Rebalance(int32 iterations)
{
if (m_root == b2_nullNode)
{
return;
}
for (int32 i = 0; i < iterations; ++i)
{
int32 node = m_root;
uint32 bit = 0;
while (m_nodes[node].IsLeaf() == false)
{
int32* children = &m_nodes[node].child1;
node = children[(m_path >> bit) & 1];
bit = (bit + 1) & (8* sizeof(uint32) - 1);
}
++m_path;
RemoveLeaf(node);
InsertLeaf(node);
}
}
// Compute the height of a sub-tree.
int32 b2DynamicTree::ComputeHeight(int32 nodeId) const
{
if (nodeId == b2_nullNode)
{
return 0;
}
b2Assert(0 <= nodeId && nodeId < m_nodeCapacity);
b2DynamicTreeNode* node = m_nodes + nodeId;
int32 height1 = ComputeHeight(node->child1);
int32 height2 = ComputeHeight(node->child2);
return 1 + b2Max(height1, height2);
}
int32 b2DynamicTree::ComputeHeight() const
{
return ComputeHeight(m_root);
}

View file

@ -1,163 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "b2Fixture.h"
#include "b2Contact.h"
#include "b2CircleShape.h"
#include "b2PolygonShape.h"
#include "b2BroadPhase.h"
#include "b2Collision.h"
#include "b2BlockAllocator.h"
b2Fixture::b2Fixture()
{
m_userData = NULL;
m_body = NULL;
m_next = NULL;
m_proxyId = b2BroadPhase::e_nullProxy;
m_shape = NULL;
m_density = 0.0f;
}
b2Fixture::~b2Fixture()
{
b2Assert(m_shape == NULL);
b2Assert(m_proxyId == b2BroadPhase::e_nullProxy);
}
void b2Fixture::Create(b2BlockAllocator* allocator, b2Body* body, const b2FixtureDef* def)
{
m_userData = def->userData;
m_friction = def->friction;
m_restitution = def->restitution;
m_body = body;
m_next = NULL;
m_filter = def->filter;
m_isSensor = def->isSensor;
m_shape = def->shape->Clone(allocator);
m_density = def->density;
}
void b2Fixture::Destroy(b2BlockAllocator* allocator)
{
// The proxy must be destroyed before calling this.
b2Assert(m_proxyId == b2BroadPhase::e_nullProxy);
// Free the child shape.
switch (m_shape->m_type)
{
case b2Shape::e_circle:
{
b2CircleShape* s = (b2CircleShape*)m_shape;
s->~b2CircleShape();
allocator->Free(s, sizeof(b2CircleShape));
}
break;
case b2Shape::e_polygon:
{
b2PolygonShape* s = (b2PolygonShape*)m_shape;
s->~b2PolygonShape();
allocator->Free(s, sizeof(b2PolygonShape));
}
break;
default:
b2Assert(false);
break;
}
m_shape = NULL;
}
void b2Fixture::CreateProxy(b2BroadPhase* broadPhase, const b2Transform& xf)
{
b2Assert(m_proxyId == b2BroadPhase::e_nullProxy);
// Create proxy in the broad-phase.
m_shape->ComputeAABB(&m_aabb, xf);
m_proxyId = broadPhase->CreateProxy(m_aabb, this);
}
void b2Fixture::DestroyProxy(b2BroadPhase* broadPhase)
{
if (m_proxyId == b2BroadPhase::e_nullProxy)
{
return;
}
// Destroy proxy in the broad-phase.
broadPhase->DestroyProxy(m_proxyId);
m_proxyId = b2BroadPhase::e_nullProxy;
}
void b2Fixture::Synchronize(b2BroadPhase* broadPhase, const b2Transform& transform1, const b2Transform& transform2)
{
if (m_proxyId == b2BroadPhase::e_nullProxy)
{
return;
}
// Compute an AABB that covers the swept shape (may miss some rotation effect).
b2AABB aabb1, aabb2;
m_shape->ComputeAABB(&aabb1, transform1);
m_shape->ComputeAABB(&aabb2, transform2);
m_aabb.Combine(aabb1, aabb2);
b2Vec2 displacement = transform2.position - transform1.position;
broadPhase->MoveProxy(m_proxyId, m_aabb, displacement);
}
void b2Fixture::SetFilterData(const b2Filter& filter)
{
m_filter = filter;
if (m_body == NULL)
{
return;
}
// Flag associated contacts for filtering.
b2ContactEdge* edge = m_body->GetContactList();
while (edge)
{
b2Contact* contact = edge->contact;
b2Fixture* fixtureA = contact->GetFixtureA();
b2Fixture* fixtureB = contact->GetFixtureB();
if (fixtureA == this || fixtureB == this)
{
contact->FlagForFiltering();
}
edge = edge->next;
}
}
void b2Fixture::SetSensor(bool sensor)
{
m_isSensor = sensor;
}

View file

@ -1,229 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "b2FrictionJoint.h"
#include "b2Body.h"
#include "b2TimeStep.h"
// Point-to-point constraint
// Cdot = v2 - v1
// = v2 + cross(w2, r2) - v1 - cross(w1, r1)
// J = [-I -r1_skew I r2_skew ]
// Identity used:
// w k % (rx i + ry j) = w * (-ry i + rx j)
// Angle constraint
// Cdot = w2 - w1
// J = [0 0 -1 0 0 1]
// K = invI1 + invI2
void b2FrictionJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor)
{
bodyA = bA;
bodyB = bB;
localAnchorA = bodyA->GetLocalPoint(anchor);
localAnchorB = bodyB->GetLocalPoint(anchor);
}
b2FrictionJoint::b2FrictionJoint(const b2FrictionJointDef* def)
: b2Joint(def)
{
m_localAnchorA = def->localAnchorA;
m_localAnchorB = def->localAnchorB;
m_linearImpulse.SetZero();
m_angularImpulse = 0.0f;
m_maxForce = def->maxForce;
m_maxTorque = def->maxTorque;
}
void b2FrictionJoint::InitVelocityConstraints(const b2TimeStep& step)
{
b2Body* bA = m_bodyA;
b2Body* bB = m_bodyB;
// Compute the effective mass matrix.
b2Vec2 rA = b2Mul(bA->GetTransform().R, m_localAnchorA - bA->GetLocalCenter());
b2Vec2 rB = b2Mul(bB->GetTransform().R, m_localAnchorB - bB->GetLocalCenter());
// J = [-I -r1_skew I r2_skew]
// [ 0 -1 0 1]
// r_skew = [-ry; rx]
// Matlab
// K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB]
// [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB]
// [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB]
float32 mA = bA->m_invMass, mB = bB->m_invMass;
float32 iA = bA->m_invI, iB = bB->m_invI;
b2Mat22 K1;
K1.col1.x = mA + mB; K1.col2.x = 0.0f;
K1.col1.y = 0.0f; K1.col2.y = mA + mB;
b2Mat22 K2;
K2.col1.x = iA * rA.y * rA.y; K2.col2.x = -iA * rA.x * rA.y;
K2.col1.y = -iA * rA.x * rA.y; K2.col2.y = iA * rA.x * rA.x;
b2Mat22 K3;
K3.col1.x = iB * rB.y * rB.y; K3.col2.x = -iB * rB.x * rB.y;
K3.col1.y = -iB * rB.x * rB.y; K3.col2.y = iB * rB.x * rB.x;
b2Mat22 K = K1 + K2 + K3;
m_linearMass = K.GetInverse();
m_angularMass = iA + iB;
if (m_angularMass > 0.0f)
{
m_angularMass = 1.0f / m_angularMass;
}
if (step.warmStarting)
{
// Scale impulses to support a variable time step.
m_linearImpulse *= step.dtRatio;
m_angularImpulse *= step.dtRatio;
b2Vec2 P(m_linearImpulse.x, m_linearImpulse.y);
bA->m_linearVelocity -= mA * P;
bA->m_angularVelocity -= iA * (b2Cross(rA, P) + m_angularImpulse);
bB->m_linearVelocity += mB * P;
bB->m_angularVelocity += iB * (b2Cross(rB, P) + m_angularImpulse);
}
else
{
m_linearImpulse.SetZero();
m_angularImpulse = 0.0f;
}
}
void b2FrictionJoint::SolveVelocityConstraints(const b2TimeStep& step)
{
B2_NOT_USED(step);
b2Body* bA = m_bodyA;
b2Body* bB = m_bodyB;
b2Vec2 vA = bA->m_linearVelocity;
float32 wA = bA->m_angularVelocity;
b2Vec2 vB = bB->m_linearVelocity;
float32 wB = bB->m_angularVelocity;
float32 mA = bA->m_invMass, mB = bB->m_invMass;
float32 iA = bA->m_invI, iB = bB->m_invI;
b2Vec2 rA = b2Mul(bA->GetTransform().R, m_localAnchorA - bA->GetLocalCenter());
b2Vec2 rB = b2Mul(bB->GetTransform().R, m_localAnchorB - bB->GetLocalCenter());
// Solve angular friction
{
float32 Cdot = wB - wA;
float32 impulse = -m_angularMass * Cdot;
float32 oldImpulse = m_angularImpulse;
float32 maxImpulse = step.dt * m_maxTorque;
m_angularImpulse = b2Clamp(m_angularImpulse + impulse, -maxImpulse, maxImpulse);
impulse = m_angularImpulse - oldImpulse;
wA -= iA * impulse;
wB += iB * impulse;
}
// Solve linear friction
{
b2Vec2 Cdot = vB + b2Cross(wB, rB) - vA - b2Cross(wA, rA);
b2Vec2 impulse = -b2Mul(m_linearMass, Cdot);
b2Vec2 oldImpulse = m_linearImpulse;
m_linearImpulse += impulse;
float32 maxImpulse = step.dt * m_maxForce;
if (m_linearImpulse.LengthSquared() > maxImpulse * maxImpulse)
{
m_linearImpulse.Normalize();
m_linearImpulse *= maxImpulse;
}
impulse = m_linearImpulse - oldImpulse;
vA -= mA * impulse;
wA -= iA * b2Cross(rA, impulse);
vB += mB * impulse;
wB += iB * b2Cross(rB, impulse);
}
bA->m_linearVelocity = vA;
bA->m_angularVelocity = wA;
bB->m_linearVelocity = vB;
bB->m_angularVelocity = wB;
}
bool b2FrictionJoint::SolvePositionConstraints(float32 baumgarte)
{
B2_NOT_USED(baumgarte);
return true;
}
b2Vec2 b2FrictionJoint::GetAnchorA() const
{
return m_bodyA->GetWorldPoint(m_localAnchorA);
}
b2Vec2 b2FrictionJoint::GetAnchorB() const
{
return m_bodyB->GetWorldPoint(m_localAnchorB);
}
b2Vec2 b2FrictionJoint::GetReactionForce(float32 inv_dt) const
{
return inv_dt * m_linearImpulse;
}
float32 b2FrictionJoint::GetReactionTorque(float32 inv_dt) const
{
return inv_dt * m_angularImpulse;
}
void b2FrictionJoint::SetMaxForce(float32 force)
{
b2Assert(b2IsValid(force) && force >= 0.0f);
m_maxForce = force;
}
float32 b2FrictionJoint::GetMaxForce() const
{
return m_maxForce;
}
void b2FrictionJoint::SetMaxTorque(float32 torque)
{
b2Assert(b2IsValid(torque) && torque >= 0.0f);
m_maxTorque = torque;
}
float32 b2FrictionJoint::GetMaxTorque() const
{
return m_maxTorque;
}

View file

@ -1,99 +0,0 @@
/*
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_FRICTION_JOINT_H
#define B2_FRICTION_JOINT_H
#include "b2Joint.h"
/// Friction joint definition.
struct b2FrictionJointDef : public b2JointDef
{
b2FrictionJointDef()
{
type = e_frictionJoint;
localAnchorA.SetZero();
localAnchorB.SetZero();
maxForce = 0.0f;
maxTorque = 0.0f;
}
/// Initialize the bodies, anchors, axis, and reference angle using the world
/// anchor and world axis.
void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor);
/// The local anchor point relative to bodyA's origin.
b2Vec2 localAnchorA;
/// The local anchor point relative to bodyB's origin.
b2Vec2 localAnchorB;
/// The maximum friction force in N.
float32 maxForce;
/// The maximum friction torque in N-m.
float32 maxTorque;
};
/// Friction joint. This is used for top-down friction.
/// It provides 2D translational friction and angular friction.
class b2FrictionJoint : public b2Joint
{
public:
b2Vec2 GetAnchorA() const;
b2Vec2 GetAnchorB() const;
b2Vec2 GetReactionForce(float32 inv_dt) const;
float32 GetReactionTorque(float32 inv_dt) const;
/// Set the maximum friction force in N.
void SetMaxForce(float32 force);
/// Get the maximum friction force in N.
float32 GetMaxForce() const;
/// Set the maximum friction torque in N*m.
void SetMaxTorque(float32 torque);
/// Get the maximum friction torque in N*m.
float32 GetMaxTorque() const;
protected:
friend class b2Joint;
b2FrictionJoint(const b2FrictionJointDef* def);
void InitVelocityConstraints(const b2TimeStep& step);
void SolveVelocityConstraints(const b2TimeStep& step);
bool SolvePositionConstraints(float32 baumgarte);
b2Vec2 m_localAnchorA;
b2Vec2 m_localAnchorB;
b2Mat22 m_linearMass;
float32 m_angularMass;
b2Vec2 m_linearImpulse;
float32 m_angularImpulse;
float32 m_maxForce;
float32 m_maxTorque;
};
#endif

View file

@ -1,259 +0,0 @@
/*
* Copyright (c) 2007 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "b2GearJoint.h"
#include "b2RevoluteJoint.h"
#include "b2PrismaticJoint.h"
#include "b2Body.h"
#include "b2TimeStep.h"
// Gear Joint:
// C0 = (coordinate1 + ratio * coordinate2)_initial
// C = C0 - (cordinate1 + ratio * coordinate2) = 0
// Cdot = -(Cdot1 + ratio * Cdot2)
// J = -[J1 ratio * J2]
// K = J * invM * JT
// = J1 * invM1 * J1T + ratio * ratio * J2 * invM2 * J2T
//
// Revolute:
// coordinate = rotation
// Cdot = angularVelocity
// J = [0 0 1]
// K = J * invM * JT = invI
//
// Prismatic:
// coordinate = dot(p - pg, ug)
// Cdot = dot(v + cross(w, r), ug)
// J = [ug cross(r, ug)]
// K = J * invM * JT = invMass + invI * cross(r, ug)^2
b2GearJoint::b2GearJoint(const b2GearJointDef* def)
: b2Joint(def)
{
b2JointType type1 = def->joint1->GetType();
b2JointType type2 = def->joint2->GetType();
b2Assert(type1 == e_revoluteJoint || type1 == e_prismaticJoint);
b2Assert(type2 == e_revoluteJoint || type2 == e_prismaticJoint);
b2Assert(def->joint1->GetBodyA()->GetType() == b2_staticBody);
b2Assert(def->joint2->GetBodyA()->GetType() == b2_staticBody);
m_revolute1 = NULL;
m_prismatic1 = NULL;
m_revolute2 = NULL;
m_prismatic2 = NULL;
float32 coordinate1, coordinate2;
m_ground1 = def->joint1->GetBodyA();
m_bodyA = def->joint1->GetBodyB();
if (type1 == e_revoluteJoint)
{
m_revolute1 = (b2RevoluteJoint*)def->joint1;
m_groundAnchor1 = m_revolute1->m_localAnchor1;
m_localAnchor1 = m_revolute1->m_localAnchor2;
coordinate1 = m_revolute1->GetJointAngle();
}
else
{
m_prismatic1 = (b2PrismaticJoint*)def->joint1;
m_groundAnchor1 = m_prismatic1->m_localAnchor1;
m_localAnchor1 = m_prismatic1->m_localAnchor2;
coordinate1 = m_prismatic1->GetJointTranslation();
}
m_ground2 = def->joint2->GetBodyA();
m_bodyB = def->joint2->GetBodyB();
if (type2 == e_revoluteJoint)
{
m_revolute2 = (b2RevoluteJoint*)def->joint2;
m_groundAnchor2 = m_revolute2->m_localAnchor1;
m_localAnchor2 = m_revolute2->m_localAnchor2;
coordinate2 = m_revolute2->GetJointAngle();
}
else
{
m_prismatic2 = (b2PrismaticJoint*)def->joint2;
m_groundAnchor2 = m_prismatic2->m_localAnchor1;
m_localAnchor2 = m_prismatic2->m_localAnchor2;
coordinate2 = m_prismatic2->GetJointTranslation();
}
m_ratio = def->ratio;
m_constant = coordinate1 + m_ratio * coordinate2;
m_impulse = 0.0f;
}
void b2GearJoint::InitVelocityConstraints(const b2TimeStep& step)
{
b2Body* g1 = m_ground1;
b2Body* g2 = m_ground2;
b2Body* b1 = m_bodyA;
b2Body* b2 = m_bodyB;
float32 K = 0.0f;
m_J.SetZero();
if (m_revolute1)
{
m_J.angularA = -1.0f;
K += b1->m_invI;
}
else
{
b2Vec2 ug = b2Mul(g1->GetTransform().R, m_prismatic1->m_localXAxis1);
b2Vec2 r = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter());
float32 crug = b2Cross(r, ug);
m_J.linearA = -ug;
m_J.angularA = -crug;
K += b1->m_invMass + b1->m_invI * crug * crug;
}
if (m_revolute2)
{
m_J.angularB = -m_ratio;
K += m_ratio * m_ratio * b2->m_invI;
}
else
{
b2Vec2 ug = b2Mul(g2->GetTransform().R, m_prismatic2->m_localXAxis1);
b2Vec2 r = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter());
float32 crug = b2Cross(r, ug);
m_J.linearB = -m_ratio * ug;
m_J.angularB = -m_ratio * crug;
K += m_ratio * m_ratio * (b2->m_invMass + b2->m_invI * crug * crug);
}
// Compute effective mass.
m_mass = K > 0.0f ? 1.0f / K : 0.0f;
if (step.warmStarting)
{
// Warm starting.
b1->m_linearVelocity += b1->m_invMass * m_impulse * m_J.linearA;
b1->m_angularVelocity += b1->m_invI * m_impulse * m_J.angularA;
b2->m_linearVelocity += b2->m_invMass * m_impulse * m_J.linearB;
b2->m_angularVelocity += b2->m_invI * m_impulse * m_J.angularB;
}
else
{
m_impulse = 0.0f;
}
}
void b2GearJoint::SolveVelocityConstraints(const b2TimeStep& step)
{
B2_NOT_USED(step);
b2Body* b1 = m_bodyA;
b2Body* b2 = m_bodyB;
float32 Cdot = m_J.Compute( b1->m_linearVelocity, b1->m_angularVelocity,
b2->m_linearVelocity, b2->m_angularVelocity);
float32 impulse = m_mass * (-Cdot);
m_impulse += impulse;
b1->m_linearVelocity += b1->m_invMass * impulse * m_J.linearA;
b1->m_angularVelocity += b1->m_invI * impulse * m_J.angularA;
b2->m_linearVelocity += b2->m_invMass * impulse * m_J.linearB;
b2->m_angularVelocity += b2->m_invI * impulse * m_J.angularB;
}
bool b2GearJoint::SolvePositionConstraints(float32 baumgarte)
{
B2_NOT_USED(baumgarte);
float32 linearError = 0.0f;
b2Body* b1 = m_bodyA;
b2Body* b2 = m_bodyB;
float32 coordinate1, coordinate2;
if (m_revolute1)
{
coordinate1 = m_revolute1->GetJointAngle();
}
else
{
coordinate1 = m_prismatic1->GetJointTranslation();
}
if (m_revolute2)
{
coordinate2 = m_revolute2->GetJointAngle();
}
else
{
coordinate2 = m_prismatic2->GetJointTranslation();
}
float32 C = m_constant - (coordinate1 + m_ratio * coordinate2);
float32 impulse = m_mass * (-C);
b1->m_sweep.c += b1->m_invMass * impulse * m_J.linearA;
b1->m_sweep.a += b1->m_invI * impulse * m_J.angularA;
b2->m_sweep.c += b2->m_invMass * impulse * m_J.linearB;
b2->m_sweep.a += b2->m_invI * impulse * m_J.angularB;
b1->SynchronizeTransform();
b2->SynchronizeTransform();
// TODO_ERIN not implemented
return linearError < b2_linearSlop;
}
b2Vec2 b2GearJoint::GetAnchorA() const
{
return m_bodyA->GetWorldPoint(m_localAnchor1);
}
b2Vec2 b2GearJoint::GetAnchorB() const
{
return m_bodyB->GetWorldPoint(m_localAnchor2);
}
b2Vec2 b2GearJoint::GetReactionForce(float32 inv_dt) const
{
// TODO_ERIN not tested
b2Vec2 P = m_impulse * m_J.linearB;
return inv_dt * P;
}
float32 b2GearJoint::GetReactionTorque(float32 inv_dt) const
{
// TODO_ERIN not tested
b2Vec2 r = b2Mul(m_bodyB->GetTransform().R, m_localAnchor2 - m_bodyB->GetLocalCenter());
b2Vec2 P = m_impulse * m_J.linearB;
float32 L = m_impulse * m_J.angularB - b2Cross(r, P);
return inv_dt * L;
}
void b2GearJoint::SetRatio(float32 ratio)
{
b2Assert(b2IsValid(ratio));
m_ratio = ratio;
}
float32 b2GearJoint::GetRatio() const
{
return m_ratio;
}

View file

@ -1,111 +0,0 @@
/*
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_GEAR_JOINT_H
#define B2_GEAR_JOINT_H
#include "b2Joint.h"
class b2RevoluteJoint;
class b2PrismaticJoint;
/// Gear joint definition. This definition requires two existing
/// revolute or prismatic joints (any combination will work).
/// The provided joints must attach a dynamic body to a static body.
struct b2GearJointDef : public b2JointDef
{
b2GearJointDef()
{
type = e_gearJoint;
joint1 = NULL;
joint2 = NULL;
ratio = 1.0f;
}
/// The first revolute/prismatic joint attached to the gear joint.
b2Joint* joint1;
/// The second revolute/prismatic joint attached to the gear joint.
b2Joint* joint2;
/// The gear ratio.
/// @see b2GearJoint for explanation.
float32 ratio;
};
/// A gear joint is used to connect two joints together. Either joint
/// can be a revolute or prismatic joint. You specify a gear ratio
/// to bind the motions together:
/// coordinate1 + ratio * coordinate2 = constant
/// The ratio can be negative or positive. If one joint is a revolute joint
/// and the other joint is a prismatic joint, then the ratio will have units
/// of length or units of 1/length.
/// @warning The revolute and prismatic joints must be attached to
/// fixed bodies (which must be body1 on those joints).
class b2GearJoint : public b2Joint
{
public:
b2Vec2 GetAnchorA() const;
b2Vec2 GetAnchorB() const;
b2Vec2 GetReactionForce(float32 inv_dt) const;
float32 GetReactionTorque(float32 inv_dt) const;
/// Set/Get the gear ratio.
void SetRatio(float32 ratio);
float32 GetRatio() const;
protected:
friend class b2Joint;
b2GearJoint(const b2GearJointDef* data);
void InitVelocityConstraints(const b2TimeStep& step);
void SolveVelocityConstraints(const b2TimeStep& step);
bool SolvePositionConstraints(float32 baumgarte);
b2Body* m_ground1;
b2Body* m_ground2;
// One of these is NULL.
b2RevoluteJoint* m_revolute1;
b2PrismaticJoint* m_prismatic1;
// One of these is NULL.
b2RevoluteJoint* m_revolute2;
b2PrismaticJoint* m_prismatic2;
b2Vec2 m_groundAnchor1;
b2Vec2 m_groundAnchor2;
b2Vec2 m_localAnchor1;
b2Vec2 m_localAnchor2;
b2Jacobian m_J;
float32 m_constant;
float32 m_ratio;
// Effective mass
float32 m_mass;
// Impulse for accumulation/warm starting.
float32 m_impulse;
};
#endif

View file

@ -1,374 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "b2Island.h"
#include "b2Body.h"
#include "b2Fixture.h"
#include "b2World.h"
#include "b2Contact.h"
#include "b2ContactSolver.h"
#include "b2Joint.h"
#include "b2StackAllocator.h"
/*
Position Correction Notes
=========================
I tried the several algorithms for position correction of the 2D revolute joint.
I looked at these systems:
- simple pendulum (1m diameter sphere on massless 5m stick) with initial angular velocity of 100 rad/s.
- suspension bridge with 30 1m long planks of length 1m.
- multi-link chain with 30 1m long links.
Here are the algorithms:
Baumgarte - A fraction of the position error is added to the velocity error. There is no
separate position solver.
Pseudo Velocities - After the velocity solver and position integration,
the position error, Jacobian, and effective mass are recomputed. Then
the velocity constraints are solved with pseudo velocities and a fraction
of the position error is added to the pseudo velocity error. The pseudo
velocities are initialized to zero and there is no warm-starting. After
the position solver, the pseudo velocities are added to the positions.
This is also called the First Order World method or the Position LCP method.
Modified Nonlinear Gauss-Seidel (NGS) - Like Pseudo Velocities except the
position error is re-computed for each constraint and the positions are updated
after the constraint is solved. The radius vectors (aka Jacobians) are
re-computed too (otherwise the algorithm has horrible instability). The pseudo
velocity states are not needed because they are effectively zero at the beginning
of each iteration. Since we have the current position error, we allow the
iterations to terminate early if the error becomes smaller than b2_linearSlop.
Full NGS or just NGS - Like Modified NGS except the effective mass are re-computed
each time a constraint is solved.
Here are the results:
Baumgarte - this is the cheapest algorithm but it has some stability problems,
especially with the bridge. The chain links separate easily close to the root
and they jitter as they struggle to pull together. This is one of the most common
methods in the field. The big drawback is that the position correction artificially
affects the momentum, thus leading to instabilities and false bounce. I used a
bias factor of 0.2. A larger bias factor makes the bridge less stable, a smaller
factor makes joints and contacts more spongy.
Pseudo Velocities - the is more stable than the Baumgarte method. The bridge is
stable. However, joints still separate with large angular velocities. Drag the
simple pendulum in a circle quickly and the joint will separate. The chain separates
easily and does not recover. I used a bias factor of 0.2. A larger value lead to
the bridge collapsing when a heavy cube drops on it.
Modified NGS - this algorithm is better in some ways than Baumgarte and Pseudo
Velocities, but in other ways it is worse. The bridge and chain are much more
stable, but the simple pendulum goes unstable at high angular velocities.
Full NGS - stable in all tests. The joints display good stiffness. The bridge
still sags, but this is better than infinite forces.
Recommendations
Pseudo Velocities are not really worthwhile because the bridge and chain cannot
recover from joint separation. In other cases the benefit over Baumgarte is small.
Modified NGS is not a robust method for the revolute joint due to the violent
instability seen in the simple pendulum. Perhaps it is viable with other constraint
types, especially scalar constraints where the effective mass is a scalar.
This leaves Baumgarte and Full NGS. Baumgarte has small, but manageable instabilities
and is very fast. I don't think we can escape Baumgarte, especially in highly
demanding cases where high constraint fidelity is not needed.
Full NGS is robust and easy on the eyes. I recommend this as an option for
higher fidelity simulation and certainly for suspension bridges and long chains.
Full NGS might be a good choice for ragdolls, especially motorized ragdolls where
joint separation can be problematic. The number of NGS iterations can be reduced
for better performance without harming robustness much.
Each joint in a can be handled differently in the position solver. So I recommend
a system where the user can select the algorithm on a per joint basis. I would
probably default to the slower Full NGS and let the user select the faster
Baumgarte method in performance critical scenarios.
*/
/*
Cache Performance
The Box2D solvers are dominated by cache misses. Data structures are designed
to increase the number of cache hits. Much of misses are due to random access
to body data. The constraint structures are iterated over linearly, which leads
to few cache misses.
The bodies are not accessed during iteration. Instead read only data, such as
the mass values are stored with the constraints. The mutable data are the constraint
impulses and the bodies velocities/positions. The impulses are held inside the
constraint structures. The body velocities/positions are held in compact, temporary
arrays to increase the number of cache hits. Linear and angular velocity are
stored in a single array since multiple arrays lead to multiple misses.
*/
/*
2D Rotation
R = [cos(theta) -sin(theta)]
[sin(theta) cos(theta) ]
thetaDot = omega
Let q1 = cos(theta), q2 = sin(theta).
R = [q1 -q2]
[q2 q1]
q1Dot = -thetaDot * q2
q2Dot = thetaDot * q1
q1_new = q1_old - dt * w * q2
q2_new = q2_old + dt * w * q1
then normalize.
This might be faster than computing sin+cos.
However, we can compute sin+cos of the same angle fast.
*/
b2Island::b2Island(
int32 bodyCapacity,
int32 contactCapacity,
int32 jointCapacity,
b2StackAllocator* allocator,
b2ContactListener* listener)
{
m_bodyCapacity = bodyCapacity;
m_contactCapacity = contactCapacity;
m_jointCapacity = jointCapacity;
m_bodyCount = 0;
m_contactCount = 0;
m_jointCount = 0;
m_allocator = allocator;
m_listener = listener;
m_bodies = (b2Body**)m_allocator->Allocate(bodyCapacity * sizeof(b2Body*));
m_contacts = (b2Contact**)m_allocator->Allocate(contactCapacity * sizeof(b2Contact*));
m_joints = (b2Joint**)m_allocator->Allocate(jointCapacity * sizeof(b2Joint*));
m_velocities = (b2Velocity*)m_allocator->Allocate(m_bodyCapacity * sizeof(b2Velocity));
m_positions = (b2Position*)m_allocator->Allocate(m_bodyCapacity * sizeof(b2Position));
}
b2Island::~b2Island()
{
// Warning: the order should reverse the constructor order.
m_allocator->Free(m_positions);
m_allocator->Free(m_velocities);
m_allocator->Free(m_joints);
m_allocator->Free(m_contacts);
m_allocator->Free(m_bodies);
}
void b2Island::Solve(const b2TimeStep& step, const b2Vec2& gravity, bool allowSleep)
{
// Integrate velocities and apply damping.
for (int32 i = 0; i < m_bodyCount; ++i)
{
b2Body* b = m_bodies[i];
if (b->GetType() != b2_dynamicBody)
{
continue;
}
// Integrate velocities.
b->m_linearVelocity += step.dt * (gravity + b->m_invMass * b->m_force);
b->m_angularVelocity += step.dt * b->m_invI * b->m_torque;
// Apply damping.
// ODE: dv/dt + c * v = 0
// Solution: v(t) = v0 * exp(-c * t)
// Time step: v(t + dt) = v0 * exp(-c * (t + dt)) = v0 * exp(-c * t) * exp(-c * dt) = v * exp(-c * dt)
// v2 = exp(-c * dt) * v1
// Taylor expansion:
// v2 = (1.0f - c * dt) * v1
b->m_linearVelocity *= b2Clamp(1.0f - step.dt * b->m_linearDamping, 0.0f, 1.0f);
b->m_angularVelocity *= b2Clamp(1.0f - step.dt * b->m_angularDamping, 0.0f, 1.0f);
}
// Partition contacts so that contacts with static bodies are solved last.
int32 i1 = -1;
for (int32 i2 = 0; i2 < m_contactCount; ++i2)
{
b2Fixture* fixtureA = m_contacts[i2]->GetFixtureA();
b2Fixture* fixtureB = m_contacts[i2]->GetFixtureB();
b2Body* bodyA = fixtureA->GetBody();
b2Body* bodyB = fixtureB->GetBody();
bool nonStatic = bodyA->GetType() != b2_staticBody && bodyB->GetType() != b2_staticBody;
if (nonStatic)
{
++i1;
b2Swap(m_contacts[i1], m_contacts[i2]);
}
}
// Initialize velocity constraints.
b2ContactSolver contactSolver(m_contacts, m_contactCount, m_allocator, step.dtRatio);
contactSolver.WarmStart();
for (int32 i = 0; i < m_jointCount; ++i)
{
m_joints[i]->InitVelocityConstraints(step);
}
// Solve velocity constraints.
for (int32 i = 0; i < step.velocityIterations; ++i)
{
for (int32 j = 0; j < m_jointCount; ++j)
{
m_joints[j]->SolveVelocityConstraints(step);
}
contactSolver.SolveVelocityConstraints();
}
// Post-solve (store impulses for warm starting).
contactSolver.StoreImpulses();
// Integrate positions.
for (int32 i = 0; i < m_bodyCount; ++i)
{
b2Body* b = m_bodies[i];
if (b->GetType() == b2_staticBody)
{
continue;
}
// Check for large velocities.
b2Vec2 translation = step.dt * b->m_linearVelocity;
if (b2Dot(translation, translation) > b2_maxTranslationSquared)
{
float32 ratio = b2_maxTranslation / translation.Length();
b->m_linearVelocity *= ratio;
}
float32 rotation = step.dt * b->m_angularVelocity;
if (rotation * rotation > b2_maxRotationSquared)
{
float32 ratio = b2_maxRotation / b2Abs(rotation);
b->m_angularVelocity *= ratio;
}
// Store positions for continuous collision.
b->m_sweep.c0 = b->m_sweep.c;
b->m_sweep.a0 = b->m_sweep.a;
// Integrate
b->m_sweep.c += step.dt * b->m_linearVelocity;
b->m_sweep.a += step.dt * b->m_angularVelocity;
// Compute new transform
b->SynchronizeTransform();
// Note: shapes are synchronized later.
}
// Iterate over constraints.
for (int32 i = 0; i < step.positionIterations; ++i)
{
bool contactsOkay = contactSolver.SolvePositionConstraints(b2_contactBaumgarte);
bool jointsOkay = true;
for (int32 i = 0; i < m_jointCount; ++i)
{
bool jointOkay = m_joints[i]->SolvePositionConstraints(b2_contactBaumgarte);
jointsOkay = jointsOkay && jointOkay;
}
if (contactsOkay && jointsOkay)
{
// Exit early if the position errors are small.
break;
}
}
Report(contactSolver.m_constraints);
if (allowSleep)
{
float32 minSleepTime = b2_maxFloat;
const float32 linTolSqr = b2_linearSleepTolerance * b2_linearSleepTolerance;
const float32 angTolSqr = b2_angularSleepTolerance * b2_angularSleepTolerance;
for (int32 i = 0; i < m_bodyCount; ++i)
{
b2Body* b = m_bodies[i];
if (b->GetType() == b2_staticBody)
{
continue;
}
if ((b->m_flags & b2Body::e_autoSleepFlag) == 0)
{
b->m_sleepTime = 0.0f;
minSleepTime = 0.0f;
}
if ((b->m_flags & b2Body::e_autoSleepFlag) == 0 ||
b->m_angularVelocity * b->m_angularVelocity > angTolSqr ||
b2Dot(b->m_linearVelocity, b->m_linearVelocity) > linTolSqr)
{
b->m_sleepTime = 0.0f;
minSleepTime = 0.0f;
}
else
{
b->m_sleepTime += step.dt;
minSleepTime = b2Min(minSleepTime, b->m_sleepTime);
}
}
if (minSleepTime >= b2_timeToSleep)
{
for (int32 i = 0; i < m_bodyCount; ++i)
{
b2Body* b = m_bodies[i];
b->SetAwake(false);
}
}
}
}
void b2Island::Report(const b2ContactConstraint* constraints)
{
if (m_listener == NULL)
{
return;
}
for (int32 i = 0; i < m_contactCount; ++i)
{
b2Contact* c = m_contacts[i];
const b2ContactConstraint* cc = constraints + i;
b2ContactImpulse impulse;
for (int32 j = 0; j < cc->pointCount; ++j)
{
impulse.normalImpulses[j] = cc->points[j].normalImpulse;
impulse.tangentImpulses[j] = cc->points[j].tangentImpulse;
}
m_listener->PostSolve(c, &impulse);
}
}

View file

@ -1,105 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_ISLAND_H
#define B2_ISLAND_H
#include "b2Math.h"
#include "b2Body.h"
#include "b2TimeStep.h"
class b2Contact;
class b2Joint;
class b2StackAllocator;
class b2ContactListener;
struct b2ContactConstraint;
/// This is an internal structure.
struct b2Position
{
b2Vec2 x;
float32 a;
};
/// This is an internal structure.
struct b2Velocity
{
b2Vec2 v;
float32 w;
};
/// This is an internal class.
class b2Island
{
public:
b2Island(int32 bodyCapacity, int32 contactCapacity, int32 jointCapacity,
b2StackAllocator* allocator, b2ContactListener* listener);
~b2Island();
void Clear()
{
m_bodyCount = 0;
m_contactCount = 0;
m_jointCount = 0;
}
void Solve(const b2TimeStep& step, const b2Vec2& gravity, bool allowSleep);
void Add(b2Body* body)
{
b2Assert(m_bodyCount < m_bodyCapacity);
body->m_islandIndex = m_bodyCount;
m_bodies[m_bodyCount++] = body;
}
void Add(b2Contact* contact)
{
b2Assert(m_contactCount < m_contactCapacity);
m_contacts[m_contactCount++] = contact;
}
void Add(b2Joint* joint)
{
b2Assert(m_jointCount < m_jointCapacity);
m_joints[m_jointCount++] = joint;
}
void Report(const b2ContactConstraint* constraints);
b2StackAllocator* m_allocator;
b2ContactListener* m_listener;
b2Body** m_bodies;
b2Contact** m_contacts;
b2Joint** m_joints;
b2Position* m_positions;
b2Velocity* m_velocities;
int32 m_bodyCount;
int32 m_jointCount;
int32 m_contactCount;
int32 m_bodyCapacity;
int32 m_contactCapacity;
int32 m_jointCapacity;
int32 m_positionIterationCount;
};
#endif

View file

@ -1,186 +0,0 @@
/*
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "b2Joint.h"
#include "b2DistanceJoint.h"
#include "b2LineJoint.h"
#include "b2MouseJoint.h"
#include "b2RevoluteJoint.h"
#include "b2PrismaticJoint.h"
#include "b2PulleyJoint.h"
#include "b2GearJoint.h"
#include "b2WeldJoint.h"
#include "b2FrictionJoint.h"
#include "b2Body.h"
#include "b2World.h"
#include "b2BlockAllocator.h"
#include <new>
b2Joint* b2Joint::Create(const b2JointDef* def, b2BlockAllocator* allocator)
{
b2Joint* joint = NULL;
switch (def->type)
{
case e_distanceJoint:
{
void* mem = allocator->Allocate(sizeof(b2DistanceJoint));
joint = new (mem) b2DistanceJoint((b2DistanceJointDef*)def);
}
break;
case e_mouseJoint:
{
void* mem = allocator->Allocate(sizeof(b2MouseJoint));
joint = new (mem) b2MouseJoint((b2MouseJointDef*)def);
}
break;
case e_prismaticJoint:
{
void* mem = allocator->Allocate(sizeof(b2PrismaticJoint));
joint = new (mem) b2PrismaticJoint((b2PrismaticJointDef*)def);
}
break;
case e_revoluteJoint:
{
void* mem = allocator->Allocate(sizeof(b2RevoluteJoint));
joint = new (mem) b2RevoluteJoint((b2RevoluteJointDef*)def);
}
break;
case e_pulleyJoint:
{
void* mem = allocator->Allocate(sizeof(b2PulleyJoint));
joint = new (mem) b2PulleyJoint((b2PulleyJointDef*)def);
}
break;
case e_gearJoint:
{
void* mem = allocator->Allocate(sizeof(b2GearJoint));
joint = new (mem) b2GearJoint((b2GearJointDef*)def);
}
break;
case e_lineJoint:
{
void* mem = allocator->Allocate(sizeof(b2LineJoint));
joint = new (mem) b2LineJoint((b2LineJointDef*)def);
}
break;
case e_weldJoint:
{
void* mem = allocator->Allocate(sizeof(b2WeldJoint));
joint = new (mem) b2WeldJoint((b2WeldJointDef*)def);
}
break;
case e_frictionJoint:
{
void* mem = allocator->Allocate(sizeof(b2FrictionJoint));
joint = new (mem) b2FrictionJoint((b2FrictionJointDef*)def);
}
break;
default:
b2Assert(false);
break;
}
return joint;
}
void b2Joint::Destroy(b2Joint* joint, b2BlockAllocator* allocator)
{
joint->~b2Joint();
switch (joint->m_type)
{
case e_distanceJoint:
allocator->Free(joint, sizeof(b2DistanceJoint));
break;
case e_mouseJoint:
allocator->Free(joint, sizeof(b2MouseJoint));
break;
case e_prismaticJoint:
allocator->Free(joint, sizeof(b2PrismaticJoint));
break;
case e_revoluteJoint:
allocator->Free(joint, sizeof(b2RevoluteJoint));
break;
case e_pulleyJoint:
allocator->Free(joint, sizeof(b2PulleyJoint));
break;
case e_gearJoint:
allocator->Free(joint, sizeof(b2GearJoint));
break;
case e_lineJoint:
allocator->Free(joint, sizeof(b2LineJoint));
break;
case e_weldJoint:
allocator->Free(joint, sizeof(b2WeldJoint));
break;
case e_frictionJoint:
allocator->Free(joint, sizeof(b2FrictionJoint));
break;
default:
b2Assert(false);
break;
}
}
b2Joint::b2Joint(const b2JointDef* def)
{
b2Assert(def->bodyA != def->bodyB);
m_type = def->type;
m_prev = NULL;
m_next = NULL;
m_bodyA = def->bodyA;
m_bodyB = def->bodyB;
m_collideConnected = def->collideConnected;
m_islandFlag = false;
m_userData = def->userData;
m_edgeA.joint = NULL;
m_edgeA.other = NULL;
m_edgeA.prev = NULL;
m_edgeA.next = NULL;
m_edgeB.joint = NULL;
m_edgeB.other = NULL;
m_edgeB.prev = NULL;
m_edgeB.next = NULL;
}
bool b2Joint::IsActive() const
{
return m_bodyA->IsActive() && m_bodyB->IsActive();
}

View file

@ -1,226 +0,0 @@
/*
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_JOINT_H
#define B2_JOINT_H
#include "b2Math.h"
class b2Body;
class b2Joint;
struct b2TimeStep;
class b2BlockAllocator;
enum b2JointType
{
e_unknownJoint,
e_revoluteJoint,
e_prismaticJoint,
e_distanceJoint,
e_pulleyJoint,
e_mouseJoint,
e_gearJoint,
e_lineJoint,
e_weldJoint,
e_frictionJoint,
};
enum b2LimitState
{
e_inactiveLimit,
e_atLowerLimit,
e_atUpperLimit,
e_equalLimits
};
struct b2Jacobian
{
b2Vec2 linearA;
float32 angularA;
b2Vec2 linearB;
float32 angularB;
void SetZero();
void Set(const b2Vec2& x1, float32 a1, const b2Vec2& x2, float32 a2);
float32 Compute(const b2Vec2& x1, float32 a1, const b2Vec2& x2, float32 a2);
};
/// A joint edge is used to connect bodies and joints together
/// in a joint graph where each body is a node and each joint
/// is an edge. A joint edge belongs to a doubly linked list
/// maintained in each attached body. Each joint has two joint
/// nodes, one for each attached body.
struct b2JointEdge
{
b2Body* other; ///< provides quick access to the other body attached.
b2Joint* joint; ///< the joint
b2JointEdge* prev; ///< the previous joint edge in the body's joint list
b2JointEdge* next; ///< the next joint edge in the body's joint list
};
/// Joint definitions are used to construct joints.
struct b2JointDef
{
b2JointDef()
{
type = e_unknownJoint;
userData = NULL;
bodyA = NULL;
bodyB = NULL;
collideConnected = false;
}
/// The joint type is set automatically for concrete joint types.
b2JointType type;
/// Use this to attach application specific data to your joints.
void* userData;
/// The first attached body.
b2Body* bodyA;
/// The second attached body.
b2Body* bodyB;
/// Set this flag to true if the attached bodies should collide.
bool collideConnected;
};
/// The base joint class. Joints are used to constraint two bodies together in
/// various fashions. Some joints also feature limits and motors.
class b2Joint
{
public:
/// Get the type of the concrete joint.
b2JointType GetType() const;
/// Get the first body attached to this joint.
b2Body* GetBodyA();
/// Get the second body attached to this joint.
b2Body* GetBodyB();
/// Get the anchor point on bodyA in world coordinates.
virtual b2Vec2 GetAnchorA() const = 0;
/// Get the anchor point on bodyB in world coordinates.
virtual b2Vec2 GetAnchorB() const = 0;
/// Get the reaction force on body2 at the joint anchor in Newtons.
virtual b2Vec2 GetReactionForce(float32 inv_dt) const = 0;
/// Get the reaction torque on body2 in N*m.
virtual float32 GetReactionTorque(float32 inv_dt) const = 0;
/// Get the next joint the world joint list.
b2Joint* GetNext();
/// Get the user data pointer.
void* GetUserData() const;
/// Set the user data pointer.
void SetUserData(void* data);
/// Short-cut function to determine if either body is inactive.
bool IsActive() const;
protected:
friend class b2World;
friend class b2Body;
friend class b2Island;
static b2Joint* Create(const b2JointDef* def, b2BlockAllocator* allocator);
static void Destroy(b2Joint* joint, b2BlockAllocator* allocator);
b2Joint(const b2JointDef* def);
virtual ~b2Joint() {}
virtual void InitVelocityConstraints(const b2TimeStep& step) = 0;
virtual void SolveVelocityConstraints(const b2TimeStep& step) = 0;
// This returns true if the position errors are within tolerance.
virtual bool SolvePositionConstraints(float32 baumgarte) = 0;
b2JointType m_type;
b2Joint* m_prev;
b2Joint* m_next;
b2JointEdge m_edgeA;
b2JointEdge m_edgeB;
b2Body* m_bodyA;
b2Body* m_bodyB;
bool m_islandFlag;
bool m_collideConnected;
void* m_userData;
// Cache here per time step to reduce cache misses.
b2Vec2 m_localCenterA, m_localCenterB;
float32 m_invMassA, m_invIA;
float32 m_invMassB, m_invIB;
};
inline void b2Jacobian::SetZero()
{
linearA.SetZero(); angularA = 0.0f;
linearB.SetZero(); angularB = 0.0f;
}
inline void b2Jacobian::Set(const b2Vec2& x1, float32 a1, const b2Vec2& x2, float32 a2)
{
linearA = x1; angularA = a1;
linearB = x2; angularB = a2;
}
inline float32 b2Jacobian::Compute(const b2Vec2& x1, float32 a1, const b2Vec2& x2, float32 a2)
{
return b2Dot(linearA, x1) + angularA * a1 + b2Dot(linearB, x2) + angularB * a2;
}
inline b2JointType b2Joint::GetType() const
{
return m_type;
}
inline b2Body* b2Joint::GetBodyA()
{
return m_bodyA;
}
inline b2Body* b2Joint::GetBodyB()
{
return m_bodyB;
}
inline b2Joint* b2Joint::GetNext()
{
return m_next;
}
inline void* b2Joint::GetUserData() const
{
return m_userData;
}
inline void b2Joint::SetUserData(void* data)
{
m_userData = data;
}
#endif

View file

@ -1,591 +0,0 @@
/*
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "b2LineJoint.h"
#include "b2Body.h"
#include "b2TimeStep.h"
// Linear constraint (point-to-line)
// d = p2 - p1 = x2 + r2 - x1 - r1
// C = dot(perp, d)
// Cdot = dot(d, cross(w1, perp)) + dot(perp, v2 + cross(w2, r2) - v1 - cross(w1, r1))
// = -dot(perp, v1) - dot(cross(d + r1, perp), w1) + dot(perp, v2) + dot(cross(r2, perp), v2)
// J = [-perp, -cross(d + r1, perp), perp, cross(r2,perp)]
//
// K = J * invM * JT
//
// J = [-a -s1 a s2]
// a = perp
// s1 = cross(d + r1, a) = cross(p2 - x1, a)
// s2 = cross(r2, a) = cross(p2 - x2, a)
// Motor/Limit linear constraint
// C = dot(ax1, d)
// Cdot = = -dot(ax1, v1) - dot(cross(d + r1, ax1), w1) + dot(ax1, v2) + dot(cross(r2, ax1), v2)
// J = [-ax1 -cross(d+r1,ax1) ax1 cross(r2,ax1)]
// Block Solver
// We develop a block solver that includes the joint limit. This makes the limit stiff (inelastic) even
// when the mass has poor distribution (leading to large torques about the joint anchor points).
//
// The Jacobian has 3 rows:
// J = [-uT -s1 uT s2] // linear
// [-vT -a1 vT a2] // limit
//
// u = perp
// v = axis
// s1 = cross(d + r1, u), s2 = cross(r2, u)
// a1 = cross(d + r1, v), a2 = cross(r2, v)
// M * (v2 - v1) = JT * df
// J * v2 = bias
//
// v2 = v1 + invM * JT * df
// J * (v1 + invM * JT * df) = bias
// K * df = bias - J * v1 = -Cdot
// K = J * invM * JT
// Cdot = J * v1 - bias
//
// Now solve for f2.
// df = f2 - f1
// K * (f2 - f1) = -Cdot
// f2 = invK * (-Cdot) + f1
//
// Clamp accumulated limit impulse.
// lower: f2(2) = max(f2(2), 0)
// upper: f2(2) = min(f2(2), 0)
//
// Solve for correct f2(1)
// K(1,1) * f2(1) = -Cdot(1) - K(1,2) * f2(2) + K(1,1:2) * f1
// = -Cdot(1) - K(1,2) * f2(2) + K(1,1) * f1(1) + K(1,2) * f1(2)
// K(1,1) * f2(1) = -Cdot(1) - K(1,2) * (f2(2) - f1(2)) + K(1,1) * f1(1)
// f2(1) = invK(1,1) * (-Cdot(1) - K(1,2) * (f2(2) - f1(2))) + f1(1)
//
// Now compute impulse to be applied:
// df = f2 - f1
void b2LineJointDef::Initialize(b2Body* b1, b2Body* b2, const b2Vec2& anchor, const b2Vec2& axis)
{
bodyA = b1;
bodyB = b2;
localAnchorA = bodyA->GetLocalPoint(anchor);
localAnchorB = bodyB->GetLocalPoint(anchor);
localAxisA = bodyA->GetLocalVector(axis);
}
b2LineJoint::b2LineJoint(const b2LineJointDef* def)
: b2Joint(def)
{
m_localAnchor1 = def->localAnchorA;
m_localAnchor2 = def->localAnchorB;
m_localXAxis1 = def->localAxisA;
m_localYAxis1 = b2Cross(1.0f, m_localXAxis1);
m_impulse.SetZero();
m_motorMass = 0.0;
m_motorImpulse = 0.0f;
m_lowerTranslation = def->lowerTranslation;
m_upperTranslation = def->upperTranslation;
m_maxMotorForce = def->maxMotorForce;
m_motorSpeed = def->motorSpeed;
m_enableLimit = def->enableLimit;
m_enableMotor = def->enableMotor;
m_limitState = e_inactiveLimit;
m_axis.SetZero();
m_perp.SetZero();
}
void b2LineJoint::InitVelocityConstraints(const b2TimeStep& step)
{
b2Body* b1 = m_bodyA;
b2Body* b2 = m_bodyB;
m_localCenterA = b1->GetLocalCenter();
m_localCenterB = b2->GetLocalCenter();
b2Transform xf1 = b1->GetTransform();
b2Transform xf2 = b2->GetTransform();
// Compute the effective masses.
b2Vec2 r1 = b2Mul(xf1.R, m_localAnchor1 - m_localCenterA);
b2Vec2 r2 = b2Mul(xf2.R, m_localAnchor2 - m_localCenterB);
b2Vec2 d = b2->m_sweep.c + r2 - b1->m_sweep.c - r1;
m_invMassA = b1->m_invMass;
m_invIA = b1->m_invI;
m_invMassB = b2->m_invMass;
m_invIB = b2->m_invI;
// Compute motor Jacobian and effective mass.
{
m_axis = b2Mul(xf1.R, m_localXAxis1);
m_a1 = b2Cross(d + r1, m_axis);
m_a2 = b2Cross(r2, m_axis);
m_motorMass = m_invMassA + m_invMassB + m_invIA * m_a1 * m_a1 + m_invIB * m_a2 * m_a2;
if (m_motorMass > b2_epsilon)
{
m_motorMass = 1.0f / m_motorMass;
}
else
{
m_motorMass = 0.0f;
}
}
// Prismatic constraint.
{
m_perp = b2Mul(xf1.R, m_localYAxis1);
m_s1 = b2Cross(d + r1, m_perp);
m_s2 = b2Cross(r2, m_perp);
float32 m1 = m_invMassA, m2 = m_invMassB;
float32 i1 = m_invIA, i2 = m_invIB;
float32 k11 = m1 + m2 + i1 * m_s1 * m_s1 + i2 * m_s2 * m_s2;
float32 k12 = i1 * m_s1 * m_a1 + i2 * m_s2 * m_a2;
float32 k22 = m1 + m2 + i1 * m_a1 * m_a1 + i2 * m_a2 * m_a2;
m_K.col1.Set(k11, k12);
m_K.col2.Set(k12, k22);
}
// Compute motor and limit terms.
if (m_enableLimit)
{
float32 jointTranslation = b2Dot(m_axis, d);
if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop)
{
m_limitState = e_equalLimits;
}
else if (jointTranslation <= m_lowerTranslation)
{
if (m_limitState != e_atLowerLimit)
{
m_limitState = e_atLowerLimit;
m_impulse.y = 0.0f;
}
}
else if (jointTranslation >= m_upperTranslation)
{
if (m_limitState != e_atUpperLimit)
{
m_limitState = e_atUpperLimit;
m_impulse.y = 0.0f;
}
}
else
{
m_limitState = e_inactiveLimit;
m_impulse.y = 0.0f;
}
}
else
{
m_limitState = e_inactiveLimit;
}
if (m_enableMotor == false)
{
m_motorImpulse = 0.0f;
}
if (step.warmStarting)
{
// Account for variable time step.
m_impulse *= step.dtRatio;
m_motorImpulse *= step.dtRatio;
b2Vec2 P = m_impulse.x * m_perp + (m_motorImpulse + m_impulse.y) * m_axis;
float32 L1 = m_impulse.x * m_s1 + (m_motorImpulse + m_impulse.y) * m_a1;
float32 L2 = m_impulse.x * m_s2 + (m_motorImpulse + m_impulse.y) * m_a2;
b1->m_linearVelocity -= m_invMassA * P;
b1->m_angularVelocity -= m_invIA * L1;
b2->m_linearVelocity += m_invMassB * P;
b2->m_angularVelocity += m_invIB * L2;
}
else
{
m_impulse.SetZero();
m_motorImpulse = 0.0f;
}
}
void b2LineJoint::SolveVelocityConstraints(const b2TimeStep& step)
{
b2Body* b1 = m_bodyA;
b2Body* b2 = m_bodyB;
b2Vec2 v1 = b1->m_linearVelocity;
float32 w1 = b1->m_angularVelocity;
b2Vec2 v2 = b2->m_linearVelocity;
float32 w2 = b2->m_angularVelocity;
// Solve linear motor constraint.
if (m_enableMotor && m_limitState != e_equalLimits)
{
float32 Cdot = b2Dot(m_axis, v2 - v1) + m_a2 * w2 - m_a1 * w1;
float32 impulse = m_motorMass * (m_motorSpeed - Cdot);
float32 oldImpulse = m_motorImpulse;
float32 maxImpulse = step.dt * m_maxMotorForce;
m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse);
impulse = m_motorImpulse - oldImpulse;
b2Vec2 P = impulse * m_axis;
float32 L1 = impulse * m_a1;
float32 L2 = impulse * m_a2;
v1 -= m_invMassA * P;
w1 -= m_invIA * L1;
v2 += m_invMassB * P;
w2 += m_invIB * L2;
}
float32 Cdot1 = b2Dot(m_perp, v2 - v1) + m_s2 * w2 - m_s1 * w1;
if (m_enableLimit && m_limitState != e_inactiveLimit)
{
// Solve prismatic and limit constraint in block form.
float32 Cdot2 = b2Dot(m_axis, v2 - v1) + m_a2 * w2 - m_a1 * w1;
b2Vec2 Cdot(Cdot1, Cdot2);
b2Vec2 f1 = m_impulse;
b2Vec2 df = m_K.Solve(-Cdot);
m_impulse += df;
if (m_limitState == e_atLowerLimit)
{
m_impulse.y = b2Max(m_impulse.y, 0.0f);
}
else if (m_limitState == e_atUpperLimit)
{
m_impulse.y = b2Min(m_impulse.y, 0.0f);
}
// f2(1) = invK(1,1) * (-Cdot(1) - K(1,2) * (f2(2) - f1(2))) + f1(1)
float32 b = -Cdot1 - (m_impulse.y - f1.y) * m_K.col2.x;
float32 f2r;
if (m_K.col1.x != 0.0f)
{
f2r = b / m_K.col1.x + f1.x;
}
else
{
f2r = f1.x;
}
m_impulse.x = f2r;
df = m_impulse - f1;
b2Vec2 P = df.x * m_perp + df.y * m_axis;
float32 L1 = df.x * m_s1 + df.y * m_a1;
float32 L2 = df.x * m_s2 + df.y * m_a2;
v1 -= m_invMassA * P;
w1 -= m_invIA * L1;
v2 += m_invMassB * P;
w2 += m_invIB * L2;
}
else
{
// Limit is inactive, just solve the prismatic constraint in block form.
float32 df;
if (m_K.col1.x != 0.0f)
{
df = - Cdot1 / m_K.col1.x;
}
else
{
df = 0.0f;
}
m_impulse.x += df;
b2Vec2 P = df * m_perp;
float32 L1 = df * m_s1;
float32 L2 = df * m_s2;
v1 -= m_invMassA * P;
w1 -= m_invIA * L1;
v2 += m_invMassB * P;
w2 += m_invIB * L2;
}
b1->m_linearVelocity = v1;
b1->m_angularVelocity = w1;
b2->m_linearVelocity = v2;
b2->m_angularVelocity = w2;
}
bool b2LineJoint::SolvePositionConstraints(float32 baumgarte)
{
B2_NOT_USED(baumgarte);
b2Body* b1 = m_bodyA;
b2Body* b2 = m_bodyB;
b2Vec2 c1 = b1->m_sweep.c;
float32 a1 = b1->m_sweep.a;
b2Vec2 c2 = b2->m_sweep.c;
float32 a2 = b2->m_sweep.a;
// Solve linear limit constraint.
float32 linearError = 0.0f, angularError = 0.0f;
bool active = false;
float32 C2 = 0.0f;
b2Mat22 R1(a1), R2(a2);
b2Vec2 r1 = b2Mul(R1, m_localAnchor1 - m_localCenterA);
b2Vec2 r2 = b2Mul(R2, m_localAnchor2 - m_localCenterB);
b2Vec2 d = c2 + r2 - c1 - r1;
if (m_enableLimit)
{
m_axis = b2Mul(R1, m_localXAxis1);
m_a1 = b2Cross(d + r1, m_axis);
m_a2 = b2Cross(r2, m_axis);
float32 translation = b2Dot(m_axis, d);
if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop)
{
// Prevent large angular corrections
C2 = b2Clamp(translation, -b2_maxLinearCorrection, b2_maxLinearCorrection);
linearError = b2Abs(translation);
active = true;
}
else if (translation <= m_lowerTranslation)
{
// Prevent large linear corrections and allow some slop.
C2 = b2Clamp(translation - m_lowerTranslation + b2_linearSlop, -b2_maxLinearCorrection, 0.0f);
linearError = m_lowerTranslation - translation;
active = true;
}
else if (translation >= m_upperTranslation)
{
// Prevent large linear corrections and allow some slop.
C2 = b2Clamp(translation - m_upperTranslation - b2_linearSlop, 0.0f, b2_maxLinearCorrection);
linearError = translation - m_upperTranslation;
active = true;
}
}
m_perp = b2Mul(R1, m_localYAxis1);
m_s1 = b2Cross(d + r1, m_perp);
m_s2 = b2Cross(r2, m_perp);
b2Vec2 impulse;
float32 C1;
C1 = b2Dot(m_perp, d);
linearError = b2Max(linearError, b2Abs(C1));
angularError = 0.0f;
if (active)
{
float32 m1 = m_invMassA, m2 = m_invMassB;
float32 i1 = m_invIA, i2 = m_invIB;
float32 k11 = m1 + m2 + i1 * m_s1 * m_s1 + i2 * m_s2 * m_s2;
float32 k12 = i1 * m_s1 * m_a1 + i2 * m_s2 * m_a2;
float32 k22 = m1 + m2 + i1 * m_a1 * m_a1 + i2 * m_a2 * m_a2;
m_K.col1.Set(k11, k12);
m_K.col2.Set(k12, k22);
b2Vec2 C;
C.x = C1;
C.y = C2;
impulse = m_K.Solve(-C);
}
else
{
float32 m1 = m_invMassA, m2 = m_invMassB;
float32 i1 = m_invIA, i2 = m_invIB;
float32 k11 = m1 + m2 + i1 * m_s1 * m_s1 + i2 * m_s2 * m_s2;
float32 impulse1;
if (k11 != 0.0f)
{
impulse1 = - C1 / k11;
}
else
{
impulse1 = 0.0f;
}
impulse.x = impulse1;
impulse.y = 0.0f;
}
b2Vec2 P = impulse.x * m_perp + impulse.y * m_axis;
float32 L1 = impulse.x * m_s1 + impulse.y * m_a1;
float32 L2 = impulse.x * m_s2 + impulse.y * m_a2;
c1 -= m_invMassA * P;
a1 -= m_invIA * L1;
c2 += m_invMassB * P;
a2 += m_invIB * L2;
// TODO_ERIN remove need for this.
b1->m_sweep.c = c1;
b1->m_sweep.a = a1;
b2->m_sweep.c = c2;
b2->m_sweep.a = a2;
b1->SynchronizeTransform();
b2->SynchronizeTransform();
return linearError <= b2_linearSlop && angularError <= b2_angularSlop;
}
b2Vec2 b2LineJoint::GetAnchorA() const
{
return m_bodyA->GetWorldPoint(m_localAnchor1);
}
b2Vec2 b2LineJoint::GetAnchorB() const
{
return m_bodyB->GetWorldPoint(m_localAnchor2);
}
b2Vec2 b2LineJoint::GetReactionForce(float32 inv_dt) const
{
return inv_dt * (m_impulse.x * m_perp + (m_motorImpulse + m_impulse.y) * m_axis);
}
float32 b2LineJoint::GetReactionTorque(float32 inv_dt) const
{
B2_NOT_USED(inv_dt);
return 0.0f;
}
float32 b2LineJoint::GetJointTranslation() const
{
b2Body* b1 = m_bodyA;
b2Body* b2 = m_bodyB;
b2Vec2 p1 = b1->GetWorldPoint(m_localAnchor1);
b2Vec2 p2 = b2->GetWorldPoint(m_localAnchor2);
b2Vec2 d = p2 - p1;
b2Vec2 axis = b1->GetWorldVector(m_localXAxis1);
float32 translation = b2Dot(d, axis);
return translation;
}
float32 b2LineJoint::GetJointSpeed() const
{
b2Body* b1 = m_bodyA;
b2Body* b2 = m_bodyB;
b2Vec2 r1 = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter());
b2Vec2 r2 = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter());
b2Vec2 p1 = b1->m_sweep.c + r1;
b2Vec2 p2 = b2->m_sweep.c + r2;
b2Vec2 d = p2 - p1;
b2Vec2 axis = b1->GetWorldVector(m_localXAxis1);
b2Vec2 v1 = b1->m_linearVelocity;
b2Vec2 v2 = b2->m_linearVelocity;
float32 w1 = b1->m_angularVelocity;
float32 w2 = b2->m_angularVelocity;
float32 speed = b2Dot(d, b2Cross(w1, axis)) + b2Dot(axis, v2 + b2Cross(w2, r2) - v1 - b2Cross(w1, r1));
return speed;
}
bool b2LineJoint::IsLimitEnabled() const
{
return m_enableLimit;
}
void b2LineJoint::EnableLimit(bool flag)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_enableLimit = flag;
}
float32 b2LineJoint::GetLowerLimit() const
{
return m_lowerTranslation;
}
float32 b2LineJoint::GetUpperLimit() const
{
return m_upperTranslation;
}
void b2LineJoint::SetLimits(float32 lower, float32 upper)
{
b2Assert(lower <= upper);
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_lowerTranslation = lower;
m_upperTranslation = upper;
}
bool b2LineJoint::IsMotorEnabled() const
{
return m_enableMotor;
}
void b2LineJoint::EnableMotor(bool flag)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_enableMotor = flag;
}
void b2LineJoint::SetMotorSpeed(float32 speed)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_motorSpeed = speed;
}
void b2LineJoint::SetMaxMotorForce(float32 force)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_maxMotorForce = force;
}
float32 b2LineJoint::GetMotorForce() const
{
return m_motorImpulse;
}

View file

@ -1,170 +0,0 @@
/*
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_LINE_JOINT_H
#define B2_LINE_JOINT_H
#include "b2Joint.h"
/// Line joint definition. This requires defining a line of
/// motion using an axis and an anchor point. The definition uses local
/// anchor points and a local axis so that the initial configuration
/// can violate the constraint slightly. The joint translation is zero
/// when the local anchor points coincide in world space. Using local
/// anchors and a local axis helps when saving and loading a game.
struct b2LineJointDef : public b2JointDef
{
b2LineJointDef()
{
type = e_lineJoint;
localAnchorA.SetZero();
localAnchorB.SetZero();
localAxisA.Set(1.0f, 0.0f);
enableLimit = false;
lowerTranslation = 0.0f;
upperTranslation = 0.0f;
enableMotor = false;
maxMotorForce = 0.0f;
motorSpeed = 0.0f;
}
/// Initialize the bodies, anchors, axis, and reference angle using the world
/// anchor and world axis.
void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor, const b2Vec2& axis);
/// The local anchor point relative to body1's origin.
b2Vec2 localAnchorA;
/// The local anchor point relative to body2's origin.
b2Vec2 localAnchorB;
/// The local translation axis in body1.
b2Vec2 localAxisA;
/// Enable/disable the joint limit.
bool enableLimit;
/// The lower translation limit, usually in meters.
float32 lowerTranslation;
/// The upper translation limit, usually in meters.
float32 upperTranslation;
/// Enable/disable the joint motor.
bool enableMotor;
/// The maximum motor torque, usually in N-m.
float32 maxMotorForce;
/// The desired motor speed in radians per second.
float32 motorSpeed;
};
/// A line joint. This joint provides two degrees of freedom: translation
/// along an axis fixed in body1 and rotation in the plane. You can use a
/// joint limit to restrict the range of motion and a joint motor to drive
/// the motion or to model joint friction.
class b2LineJoint : public b2Joint
{
public:
b2Vec2 GetAnchorA() const;
b2Vec2 GetAnchorB() const;
b2Vec2 GetReactionForce(float32 inv_dt) const;
float32 GetReactionTorque(float32 inv_dt) const;
/// Get the current joint translation, usually in meters.
float32 GetJointTranslation() const;
/// Get the current joint translation speed, usually in meters per second.
float32 GetJointSpeed() const;
/// Is the joint limit enabled?
bool IsLimitEnabled() const;
/// Enable/disable the joint limit.
void EnableLimit(bool flag);
/// Get the lower joint limit, usually in meters.
float32 GetLowerLimit() const;
/// Get the upper joint limit, usually in meters.
float32 GetUpperLimit() const;
/// Set the joint limits, usually in meters.
void SetLimits(float32 lower, float32 upper);
/// Is the joint motor enabled?
bool IsMotorEnabled() const;
/// Enable/disable the joint motor.
void EnableMotor(bool flag);
/// Set the motor speed, usually in meters per second.
void SetMotorSpeed(float32 speed);
/// Get the motor speed, usually in meters per second.
float32 GetMotorSpeed() const;
/// Set/Get the maximum motor force, usually in N.
void SetMaxMotorForce(float32 force);
float32 GetMaxMotorForce() const;
/// Get the current motor force, usually in N.
float32 GetMotorForce() const;
protected:
friend class b2Joint;
b2LineJoint(const b2LineJointDef* def);
void InitVelocityConstraints(const b2TimeStep& step);
void SolveVelocityConstraints(const b2TimeStep& step);
bool SolvePositionConstraints(float32 baumgarte);
b2Vec2 m_localAnchor1;
b2Vec2 m_localAnchor2;
b2Vec2 m_localXAxis1;
b2Vec2 m_localYAxis1;
b2Vec2 m_axis, m_perp;
float32 m_s1, m_s2;
float32 m_a1, m_a2;
b2Mat22 m_K;
b2Vec2 m_impulse;
float32 m_motorMass; // effective mass for motor/limit translational constraint.
float32 m_motorImpulse;
float32 m_lowerTranslation;
float32 m_upperTranslation;
float32 m_maxMotorForce;
float32 m_motorSpeed;
bool m_enableLimit;
bool m_enableMotor;
b2LimitState m_limitState;
};
inline float32 b2LineJoint::GetMotorSpeed() const
{
return m_motorSpeed;
}
#endif

View file

@ -1,55 +0,0 @@
/*
* Copyright (c) 2007-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "b2Math.h"
const b2Vec2 b2Vec2_zero(0.0f, 0.0f);
const b2Mat22 b2Mat22_identity(1.0f, 0.0f, 0.0f, 1.0f);
const b2Transform b2Transform_identity(b2Vec2_zero, b2Mat22_identity);
/// Solve A * x = b, where b is a column vector. This is more efficient
/// than computing the inverse in one-shot cases.
b2Vec3 b2Mat33::Solve33(const b2Vec3& b) const
{
float32 det = b2Dot(col1, b2Cross(col2, col3));
if (det != 0.0f)
{
det = 1.0f / det;
}
b2Vec3 x;
x.x = det * b2Dot(b, b2Cross(col2, col3));
x.y = det * b2Dot(col1, b2Cross(b, col3));
x.z = det * b2Dot(col1, b2Cross(col2, b));
return x;
}
/// Solve A * x = b, where b is a column vector. This is more efficient
/// than computing the inverse in one-shot cases.
b2Vec2 b2Mat33::Solve22(const b2Vec2& b) const
{
float32 a11 = col1.x, a12 = col2.x, a21 = col1.y, a22 = col2.y;
float32 det = a11 * a22 - a12 * a21;
if (det != 0.0f)
{
det = 1.0f / det;
}
b2Vec2 x;
x.x = det * (a22 * b.x - a12 * b.y);
x.y = det * (a11 * b.y - a21 * b.x);
return x;
}

View file

@ -1,197 +0,0 @@
/*
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "b2MouseJoint.h"
#include "b2Body.h"
#include "b2TimeStep.h"
// p = attached point, m = mouse point
// C = p - m
// Cdot = v
// = v + cross(w, r)
// J = [I r_skew]
// Identity used:
// w k % (rx i + ry j) = w * (-ry i + rx j)
b2MouseJoint::b2MouseJoint(const b2MouseJointDef* def)
: b2Joint(def)
{
b2Assert(def->target.IsValid());
b2Assert(b2IsValid(def->maxForce) && def->maxForce >= 0.0f);
b2Assert(b2IsValid(def->frequencyHz) && def->frequencyHz >= 0.0f);
b2Assert(b2IsValid(def->dampingRatio) && def->dampingRatio >= 0.0f);
m_target = def->target;
m_localAnchor = b2MulT(m_bodyB->GetTransform(), m_target);
m_maxForce = def->maxForce;
m_impulse.SetZero();
m_frequencyHz = def->frequencyHz;
m_dampingRatio = def->dampingRatio;
m_beta = 0.0f;
m_gamma = 0.0f;
}
void b2MouseJoint::SetTarget(const b2Vec2& target)
{
if (m_bodyB->IsAwake() == false)
{
m_bodyB->SetAwake(true);
}
m_target = target;
}
const b2Vec2& b2MouseJoint::GetTarget() const
{
return m_target;
}
void b2MouseJoint::SetMaxForce(float32 force)
{
m_maxForce = force;
}
float32 b2MouseJoint::GetMaxForce() const
{
return m_maxForce;
}
void b2MouseJoint::SetFrequency(float32 hz)
{
m_frequencyHz = hz;
}
float32 b2MouseJoint::GetFrequency() const
{
return m_frequencyHz;
}
void b2MouseJoint::SetDampingRatio(float32 ratio)
{
m_dampingRatio = ratio;
}
float32 b2MouseJoint::GetDampingRatio() const
{
return m_dampingRatio;
}
void b2MouseJoint::InitVelocityConstraints(const b2TimeStep& step)
{
b2Body* b = m_bodyB;
float32 mass = b->GetMass();
// Frequency
float32 omega = 2.0f * b2_pi * m_frequencyHz;
// Damping coefficient
float32 d = 2.0f * mass * m_dampingRatio * omega;
// Spring stiffness
float32 k = mass * (omega * omega);
// magic formulas
// gamma has units of inverse mass.
// beta has units of inverse time.
b2Assert(d + step.dt * k > b2_epsilon);
m_gamma = step.dt * (d + step.dt * k);
if (m_gamma != 0.0f)
{
m_gamma = 1.0f / m_gamma;
}
m_beta = step.dt * k * m_gamma;
// Compute the effective mass matrix.
b2Vec2 r = b2Mul(b->GetTransform().R, m_localAnchor - b->GetLocalCenter());
// K = [(1/m1 + 1/m2) * eye(2) - skew(r1) * invI1 * skew(r1) - skew(r2) * invI2 * skew(r2)]
// = [1/m1+1/m2 0 ] + invI1 * [r1.y*r1.y -r1.x*r1.y] + invI2 * [r1.y*r1.y -r1.x*r1.y]
// [ 0 1/m1+1/m2] [-r1.x*r1.y r1.x*r1.x] [-r1.x*r1.y r1.x*r1.x]
float32 invMass = b->m_invMass;
float32 invI = b->m_invI;
b2Mat22 K1;
K1.col1.x = invMass; K1.col2.x = 0.0f;
K1.col1.y = 0.0f; K1.col2.y = invMass;
b2Mat22 K2;
K2.col1.x = invI * r.y * r.y; K2.col2.x = -invI * r.x * r.y;
K2.col1.y = -invI * r.x * r.y; K2.col2.y = invI * r.x * r.x;
b2Mat22 K = K1 + K2;
K.col1.x += m_gamma;
K.col2.y += m_gamma;
m_mass = K.GetInverse();
m_C = b->m_sweep.c + r - m_target;
// Cheat with some damping
b->m_angularVelocity *= 0.98f;
// Warm starting.
m_impulse *= step.dtRatio;
b->m_linearVelocity += invMass * m_impulse;
b->m_angularVelocity += invI * b2Cross(r, m_impulse);
}
void b2MouseJoint::SolveVelocityConstraints(const b2TimeStep& step)
{
b2Body* b = m_bodyB;
b2Vec2 r = b2Mul(b->GetTransform().R, m_localAnchor - b->GetLocalCenter());
// Cdot = v + cross(w, r)
b2Vec2 Cdot = b->m_linearVelocity + b2Cross(b->m_angularVelocity, r);
b2Vec2 impulse = b2Mul(m_mass, -(Cdot + m_beta * m_C + m_gamma * m_impulse));
b2Vec2 oldImpulse = m_impulse;
m_impulse += impulse;
float32 maxImpulse = step.dt * m_maxForce;
if (m_impulse.LengthSquared() > maxImpulse * maxImpulse)
{
m_impulse *= maxImpulse / m_impulse.Length();
}
impulse = m_impulse - oldImpulse;
b->m_linearVelocity += b->m_invMass * impulse;
b->m_angularVelocity += b->m_invI * b2Cross(r, impulse);
}
b2Vec2 b2MouseJoint::GetAnchorA() const
{
return m_target;
}
b2Vec2 b2MouseJoint::GetAnchorB() const
{
return m_bodyB->GetWorldPoint(m_localAnchor);
}
b2Vec2 b2MouseJoint::GetReactionForce(float32 inv_dt) const
{
return inv_dt * m_impulse;
}
float32 b2MouseJoint::GetReactionTorque(float32 inv_dt) const
{
return inv_dt * 0.0f;
}

View file

@ -1,114 +0,0 @@
/*
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_MOUSE_JOINT_H
#define B2_MOUSE_JOINT_H
#include "b2Joint.h"
/// Mouse joint definition. This requires a world target point,
/// tuning parameters, and the time step.
struct b2MouseJointDef : public b2JointDef
{
b2MouseJointDef()
{
type = e_mouseJoint;
target.Set(0.0f, 0.0f);
maxForce = 0.0f;
frequencyHz = 5.0f;
dampingRatio = 0.7f;
}
/// The initial world target point. This is assumed
/// to coincide with the body anchor initially.
b2Vec2 target;
/// The maximum constraint force that can be exerted
/// to move the candidate body. Usually you will express
/// as some multiple of the weight (multiplier * mass * gravity).
float32 maxForce;
/// The response speed.
float32 frequencyHz;
/// The damping ratio. 0 = no damping, 1 = critical damping.
float32 dampingRatio;
};
/// A mouse joint is used to make a point on a body track a
/// specified world point. This a soft constraint with a maximum
/// force. This allows the constraint to stretch and without
/// applying huge forces.
/// NOTE: this joint is not documented in the manual because it was
/// developed to be used in the testbed. If you want to learn how to
/// use the mouse joint, look at the testbed.
class b2MouseJoint : public b2Joint
{
public:
/// Implements b2Joint.
b2Vec2 GetAnchorA() const;
/// Implements b2Joint.
b2Vec2 GetAnchorB() const;
/// Implements b2Joint.
b2Vec2 GetReactionForce(float32 inv_dt) const;
/// Implements b2Joint.
float32 GetReactionTorque(float32 inv_dt) const;
/// Use this to update the target point.
void SetTarget(const b2Vec2& target);
const b2Vec2& GetTarget() const;
/// Set/get the maximum force in Newtons.
void SetMaxForce(float32 force);
float32 GetMaxForce() const;
/// Set/get the frequency in Hertz.
void SetFrequency(float32 hz);
float32 GetFrequency() const;
/// Set/get the damping ratio (dimensionless).
void SetDampingRatio(float32 ratio);
float32 GetDampingRatio() const;
protected:
friend class b2Joint;
b2MouseJoint(const b2MouseJointDef* def);
void InitVelocityConstraints(const b2TimeStep& step);
void SolveVelocityConstraints(const b2TimeStep& step);
bool SolvePositionConstraints(float32 baumgarte) { B2_NOT_USED(baumgarte); return true; }
b2Vec2 m_localAnchor;
b2Vec2 m_target;
b2Vec2 m_impulse;
b2Mat22 m_mass; // effective mass for point-to-point constraint.
b2Vec2 m_C; // position error
float32 m_maxForce;
float32 m_frequencyHz;
float32 m_dampingRatio;
float32 m_beta;
float32 m_gamma;
};
#endif

View file

@ -1,52 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "b2PolygonAndCircleContact.h"
#include "b2BlockAllocator.h"
#include "b2TimeOfImpact.h"
#include "b2Body.h"
#include "b2Fixture.h"
#include "b2WorldCallbacks.h"
#include <new>
b2Contact* b2PolygonAndCircleContact::Create(b2Fixture* fixtureA, b2Fixture* fixtureB, b2BlockAllocator* allocator)
{
void* mem = allocator->Allocate(sizeof(b2PolygonAndCircleContact));
return new (mem) b2PolygonAndCircleContact(fixtureA, fixtureB);
}
void b2PolygonAndCircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)
{
((b2PolygonAndCircleContact*)contact)->~b2PolygonAndCircleContact();
allocator->Free(contact, sizeof(b2PolygonAndCircleContact));
}
b2PolygonAndCircleContact::b2PolygonAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB)
: b2Contact(fixtureA, fixtureB)
{
b2Assert(m_fixtureA->GetType() == b2Shape::e_polygon);
b2Assert(m_fixtureB->GetType() == b2Shape::e_circle);
}
void b2PolygonAndCircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB)
{
b2CollidePolygonAndCircle( manifold,
(b2PolygonShape*)m_fixtureA->GetShape(), xfA,
(b2CircleShape*)m_fixtureB->GetShape(), xfB);
}

View file

@ -1,38 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_POLYGON_AND_CIRCLE_CONTACT_H
#define B2_POLYGON_AND_CIRCLE_CONTACT_H
#include "b2Contact.h"
class b2BlockAllocator;
class b2PolygonAndCircleContact : public b2Contact
{
public:
static b2Contact* Create(b2Fixture* fixtureA, b2Fixture* fixtureB, b2BlockAllocator* allocator);
static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);
b2PolygonAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB);
~b2PolygonAndCircleContact() {}
void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB);
};
#endif

View file

@ -1,52 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "b2PolygonContact.h"
#include "b2BlockAllocator.h"
#include "b2TimeOfImpact.h"
#include "b2Body.h"
#include "b2Fixture.h"
#include "b2WorldCallbacks.h"
#include <new>
b2Contact* b2PolygonContact::Create(b2Fixture* fixtureA, b2Fixture* fixtureB, b2BlockAllocator* allocator)
{
void* mem = allocator->Allocate(sizeof(b2PolygonContact));
return new (mem) b2PolygonContact(fixtureA, fixtureB);
}
void b2PolygonContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)
{
((b2PolygonContact*)contact)->~b2PolygonContact();
allocator->Free(contact, sizeof(b2PolygonContact));
}
b2PolygonContact::b2PolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB)
: b2Contact(fixtureA, fixtureB)
{
b2Assert(m_fixtureA->GetType() == b2Shape::e_polygon);
b2Assert(m_fixtureB->GetType() == b2Shape::e_polygon);
}
void b2PolygonContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB)
{
b2CollidePolygons( manifold,
(b2PolygonShape*)m_fixtureA->GetShape(), xfA,
(b2PolygonShape*)m_fixtureB->GetShape(), xfB);
}

View file

@ -1,38 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_POLYGON_CONTACT_H
#define B2_POLYGON_CONTACT_H
#include "b2Contact.h"
class b2BlockAllocator;
class b2PolygonContact : public b2Contact
{
public:
static b2Contact* Create(b2Fixture* fixtureA, b2Fixture* fixtureB, b2BlockAllocator* allocator);
static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);
b2PolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB);
~b2PolygonContact() {}
void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB);
};
#endif

View file

@ -1,434 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "b2PolygonShape.h"
#include <new>
b2Shape* b2PolygonShape::Clone(b2BlockAllocator* allocator) const
{
void* mem = allocator->Allocate(sizeof(b2PolygonShape));
b2PolygonShape* clone = new (mem) b2PolygonShape;
*clone = *this;
return clone;
}
void b2PolygonShape::SetAsBox(float32 hx, float32 hy)
{
m_vertexCount = 4;
m_vertices[0].Set(-hx, -hy);
m_vertices[1].Set( hx, -hy);
m_vertices[2].Set( hx, hy);
m_vertices[3].Set(-hx, hy);
m_normals[0].Set(0.0f, -1.0f);
m_normals[1].Set(1.0f, 0.0f);
m_normals[2].Set(0.0f, 1.0f);
m_normals[3].Set(-1.0f, 0.0f);
m_centroid.SetZero();
}
void b2PolygonShape::SetAsBox(float32 hx, float32 hy, const b2Vec2& center, float32 angle)
{
m_vertexCount = 4;
m_vertices[0].Set(-hx, -hy);
m_vertices[1].Set( hx, -hy);
m_vertices[2].Set( hx, hy);
m_vertices[3].Set(-hx, hy);
m_normals[0].Set(0.0f, -1.0f);
m_normals[1].Set(1.0f, 0.0f);
m_normals[2].Set(0.0f, 1.0f);
m_normals[3].Set(-1.0f, 0.0f);
m_centroid = center;
b2Transform xf;
xf.position = center;
xf.R.Set(angle);
// Transform vertices and normals.
for (int32 i = 0; i < m_vertexCount; ++i)
{
m_vertices[i] = b2Mul(xf, m_vertices[i]);
m_normals[i] = b2Mul(xf.R, m_normals[i]);
}
}
void b2PolygonShape::SetAsEdge(const b2Vec2& v1, const b2Vec2& v2)
{
m_vertexCount = 2;
m_vertices[0] = v1;
m_vertices[1] = v2;
m_centroid = 0.5f * (v1 + v2);
m_normals[0] = b2Cross(v2 - v1, 1.0f);
m_normals[0].Normalize();
m_normals[1] = -m_normals[0];
}
static b2Vec2 ComputeCentroid(const b2Vec2* vs, int32 count)
{
b2Assert(count >= 2);
b2Vec2 c; c.Set(0.0f, 0.0f);
float32 area = 0.0f;
if (count == 2)
{
c = 0.5f * (vs[0] + vs[1]);
return c;
}
// pRef is the reference point for forming triangles.
// It's location doesn't change the result (except for rounding error).
b2Vec2 pRef(0.0f, 0.0f);
#if 0
// This code would put the reference point inside the polygon.
for (int32 i = 0; i < count; ++i)
{
pRef += vs[i];
}
pRef *= 1.0f / count;
#endif
const float32 inv3 = 1.0f / 3.0f;
for (int32 i = 0; i < count; ++i)
{
// Triangle vertices.
b2Vec2 p1 = pRef;
b2Vec2 p2 = vs[i];
b2Vec2 p3 = i + 1 < count ? vs[i+1] : vs[0];
b2Vec2 e1 = p2 - p1;
b2Vec2 e2 = p3 - p1;
float32 D = b2Cross(e1, e2);
float32 triangleArea = 0.5f * D;
area += triangleArea;
// Area weighted centroid
c += triangleArea * inv3 * (p1 + p2 + p3);
}
// Centroid
b2Assert(area > b2_epsilon);
c *= 1.0f / area;
return c;
}
void b2PolygonShape::Set(const b2Vec2* vertices, int32 count)
{
b2Assert(2 <= count && count <= b2_maxPolygonVertices);
m_vertexCount = count;
// Copy vertices.
for (int32 i = 0; i < m_vertexCount; ++i)
{
m_vertices[i] = vertices[i];
}
// Compute normals. Ensure the edges have non-zero length.
for (int32 i = 0; i < m_vertexCount; ++i)
{
int32 i1 = i;
int32 i2 = i + 1 < m_vertexCount ? i + 1 : 0;
b2Vec2 edge = m_vertices[i2] - m_vertices[i1];
b2Assert(edge.LengthSquared() > b2_epsilon * b2_epsilon);
m_normals[i] = b2Cross(edge, 1.0f);
m_normals[i].Normalize();
}
#ifdef _DEBUG
// Ensure the polygon is convex and the interior
// is to the left of each edge.
for (int32 i = 0; i < m_vertexCount; ++i)
{
int32 i1 = i;
int32 i2 = i + 1 < m_vertexCount ? i + 1 : 0;
b2Vec2 edge = m_vertices[i2] - m_vertices[i1];
for (int32 j = 0; j < m_vertexCount; ++j)
{
// Don't check vertices on the current edge.
if (j == i1 || j == i2)
{
continue;
}
b2Vec2 r = m_vertices[j] - m_vertices[i1];
// Your polygon is non-convex (it has an indentation) or
// has colinear edges.
float32 s = b2Cross(edge, r);
b2Assert(s > 0.0f);
}
}
#endif
// Compute the polygon centroid.
m_centroid = ComputeCentroid(m_vertices, m_vertexCount);
}
bool b2PolygonShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const
{
b2Vec2 pLocal = b2MulT(xf.R, p - xf.position);
for (int32 i = 0; i < m_vertexCount; ++i)
{
float32 dot = b2Dot(m_normals[i], pLocal - m_vertices[i]);
if (dot > 0.0f)
{
return false;
}
}
return true;
}
bool b2PolygonShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, const b2Transform& xf) const
{
// Put the ray into the polygon's frame of reference.
b2Vec2 p1 = b2MulT(xf.R, input.p1 - xf.position);
b2Vec2 p2 = b2MulT(xf.R, input.p2 - xf.position);
b2Vec2 d = p2 - p1;
if (m_vertexCount == 2)
{
b2Vec2 v1 = m_vertices[0];
b2Vec2 v2 = m_vertices[1];
b2Vec2 normal = m_normals[0];
// q = p1 + t * d
// dot(normal, q - v1) = 0
// dot(normal, p1 - v1) + t * dot(normal, d) = 0
float32 numerator = b2Dot(normal, v1 - p1);
float32 denominator = b2Dot(normal, d);
if (denominator == 0.0f)
{
return false;
}
float32 t = numerator / denominator;
if (t < 0.0f || 1.0f < t)
{
return false;
}
b2Vec2 q = p1 + t * d;
// q = v1 + s * r
// s = dot(q - v1, r) / dot(r, r)
b2Vec2 r = v2 - v1;
float32 rr = b2Dot(r, r);
if (rr == 0.0f)
{
return false;
}
float32 s = b2Dot(q - v1, r) / rr;
if (s < 0.0f || 1.0f < s)
{
return false;
}
output->fraction = t;
if (numerator > 0.0f)
{
output->normal = -normal;
}
else
{
output->normal = normal;
}
return true;
}
else
{
float32 lower = 0.0f, upper = input.maxFraction;
int32 index = -1;
for (int32 i = 0; i < m_vertexCount; ++i)
{
// p = p1 + a * d
// dot(normal, p - v) = 0
// dot(normal, p1 - v) + a * dot(normal, d) = 0
float32 numerator = b2Dot(m_normals[i], m_vertices[i] - p1);
float32 denominator = b2Dot(m_normals[i], d);
if (denominator == 0.0f)
{
if (numerator < 0.0f)
{
return false;
}
}
else
{
// Note: we want this predicate without division:
// lower < numerator / denominator, where denominator < 0
// Since denominator < 0, we have to flip the inequality:
// lower < numerator / denominator <==> denominator * lower > numerator.
if (denominator < 0.0f && numerator < lower * denominator)
{
// Increase lower.
// The segment enters this half-space.
lower = numerator / denominator;
index = i;
}
else if (denominator > 0.0f && numerator < upper * denominator)
{
// Decrease upper.
// The segment exits this half-space.
upper = numerator / denominator;
}
}
// The use of epsilon here causes the assert on lower to trip
// in some cases. Apparently the use of epsilon was to make edge
// shapes work, but now those are handled separately.
//if (upper < lower - b2_epsilon)
if (upper < lower)
{
return false;
}
}
b2Assert(0.0f <= lower && lower <= input.maxFraction);
if (index >= 0)
{
output->fraction = lower;
output->normal = b2Mul(xf.R, m_normals[index]);
return true;
}
}
return false;
}
void b2PolygonShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf) const
{
b2Vec2 lower = b2Mul(xf, m_vertices[0]);
b2Vec2 upper = lower;
for (int32 i = 1; i < m_vertexCount; ++i)
{
b2Vec2 v = b2Mul(xf, m_vertices[i]);
lower = b2Min(lower, v);
upper = b2Max(upper, v);
}
b2Vec2 r(m_radius, m_radius);
aabb->lowerBound = lower - r;
aabb->upperBound = upper + r;
}
void b2PolygonShape::ComputeMass(b2MassData* massData, float32 density) const
{
// Polygon mass, centroid, and inertia.
// Let rho be the polygon density in mass per unit area.
// Then:
// mass = rho * int(dA)
// centroid.x = (1/mass) * rho * int(x * dA)
// centroid.y = (1/mass) * rho * int(y * dA)
// I = rho * int((x*x + y*y) * dA)
//
// We can compute these integrals by summing all the integrals
// for each triangle of the polygon. To evaluate the integral
// for a single triangle, we make a change of variables to
// the (u,v) coordinates of the triangle:
// x = x0 + e1x * u + e2x * v
// y = y0 + e1y * u + e2y * v
// where 0 <= u && 0 <= v && u + v <= 1.
//
// We integrate u from [0,1-v] and then v from [0,1].
// We also need to use the Jacobian of the transformation:
// D = cross(e1, e2)
//
// Simplification: triangle centroid = (1/3) * (p1 + p2 + p3)
//
// The rest of the derivation is handled by computer algebra.
b2Assert(m_vertexCount >= 2);
// A line segment has zero mass.
if (m_vertexCount == 2)
{
massData->center = 0.5f * (m_vertices[0] + m_vertices[1]);
massData->mass = 0.0f;
massData->I = 0.0f;
return;
}
b2Vec2 center; center.Set(0.0f, 0.0f);
float32 area = 0.0f;
float32 I = 0.0f;
// pRef is the reference point for forming triangles.
// It's location doesn't change the result (except for rounding error).
b2Vec2 pRef(0.0f, 0.0f);
#if 0
// This code would put the reference point inside the polygon.
for (int32 i = 0; i < m_vertexCount; ++i)
{
pRef += m_vertices[i];
}
pRef *= 1.0f / count;
#endif
const float32 k_inv3 = 1.0f / 3.0f;
for (int32 i = 0; i < m_vertexCount; ++i)
{
// Triangle vertices.
b2Vec2 p1 = pRef;
b2Vec2 p2 = m_vertices[i];
b2Vec2 p3 = i + 1 < m_vertexCount ? m_vertices[i+1] : m_vertices[0];
b2Vec2 e1 = p2 - p1;
b2Vec2 e2 = p3 - p1;
float32 D = b2Cross(e1, e2);
float32 triangleArea = 0.5f * D;
area += triangleArea;
// Area weighted centroid
center += triangleArea * k_inv3 * (p1 + p2 + p3);
float32 px = p1.x, py = p1.y;
float32 ex1 = e1.x, ey1 = e1.y;
float32 ex2 = e2.x, ey2 = e2.y;
float32 intx2 = k_inv3 * (0.25f * (ex1*ex1 + ex2*ex1 + ex2*ex2) + (px*ex1 + px*ex2)) + 0.5f*px*px;
float32 inty2 = k_inv3 * (0.25f * (ey1*ey1 + ey2*ey1 + ey2*ey2) + (py*ey1 + py*ey2)) + 0.5f*py*py;
I += D * (intx2 + inty2);
}
// Total mass
massData->mass = density * area;
// Center of mass
b2Assert(area > b2_epsilon);
center *= 1.0f / area;
massData->center = center;
// Inertia tensor relative to the local origin.
massData->I = density * I;
}

View file

@ -1,131 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_POLYGON_SHAPE_H
#define B2_POLYGON_SHAPE_H
#include "b2Shape.h"
/// A convex polygon. It is assumed that the interior of the polygon is to
/// the left of each edge.
class b2PolygonShape : public b2Shape
{
public:
b2PolygonShape();
/// Implement b2Shape.
b2Shape* Clone(b2BlockAllocator* allocator) const;
/// Copy vertices. This assumes the vertices define a convex polygon.
/// It is assumed that the exterior is the the right of each edge.
void Set(const b2Vec2* vertices, int32 vertexCount);
/// Build vertices to represent an axis-aligned box.
/// @param hx the half-width.
/// @param hy the half-height.
void SetAsBox(float32 hx, float32 hy);
/// Build vertices to represent an oriented box.
/// @param hx the half-width.
/// @param hy the half-height.
/// @param center the center of the box in local coordinates.
/// @param angle the rotation of the box in local coordinates.
void SetAsBox(float32 hx, float32 hy, const b2Vec2& center, float32 angle);
/// Set this as a single edge.
void SetAsEdge(const b2Vec2& v1, const b2Vec2& v2);
/// @see b2Shape::TestPoint
bool TestPoint(const b2Transform& transform, const b2Vec2& p) const;
/// Implement b2Shape.
bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, const b2Transform& transform) const;
/// @see b2Shape::ComputeAABB
void ComputeAABB(b2AABB* aabb, const b2Transform& transform) const;
/// @see b2Shape::ComputeMass
void ComputeMass(b2MassData* massData, float32 density) const;
/// Get the supporting vertex index in the given direction.
int32 GetSupport(const b2Vec2& d) const;
/// Get the supporting vertex in the given direction.
const b2Vec2& GetSupportVertex(const b2Vec2& d) const;
/// Get the vertex count.
int32 GetVertexCount() const { return m_vertexCount; }
/// Get a vertex by index.
const b2Vec2& GetVertex(int32 index) const;
b2Vec2 m_centroid;
b2Vec2 m_vertices[b2_maxPolygonVertices];
b2Vec2 m_normals[b2_maxPolygonVertices];
int32 m_vertexCount;
};
inline b2PolygonShape::b2PolygonShape()
{
m_type = e_polygon;
m_radius = b2_polygonRadius;
m_vertexCount = 0;
m_centroid.SetZero();
}
inline int32 b2PolygonShape::GetSupport(const b2Vec2& d) const
{
int32 bestIndex = 0;
float32 bestValue = b2Dot(m_vertices[0], d);
for (int32 i = 1; i < m_vertexCount; ++i)
{
float32 value = b2Dot(m_vertices[i], d);
if (value > bestValue)
{
bestIndex = i;
bestValue = value;
}
}
return bestIndex;
}
inline const b2Vec2& b2PolygonShape::GetSupportVertex(const b2Vec2& d) const
{
int32 bestIndex = 0;
float32 bestValue = b2Dot(m_vertices[0], d);
for (int32 i = 1; i < m_vertexCount; ++i)
{
float32 value = b2Dot(m_vertices[i], d);
if (value > bestValue)
{
bestIndex = i;
bestValue = value;
}
}
return m_vertices[bestIndex];
}
inline const b2Vec2& b2PolygonShape::GetVertex(int32 index) const
{
b2Assert(0 <= index && index < m_vertexCount);
return m_vertices[index];
}
#endif

View file

@ -1,586 +0,0 @@
/*
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "b2PrismaticJoint.h"
#include "b2Body.h"
#include "b2TimeStep.h"
// Linear constraint (point-to-line)
// d = p2 - p1 = x2 + r2 - x1 - r1
// C = dot(perp, d)
// Cdot = dot(d, cross(w1, perp)) + dot(perp, v2 + cross(w2, r2) - v1 - cross(w1, r1))
// = -dot(perp, v1) - dot(cross(d + r1, perp), w1) + dot(perp, v2) + dot(cross(r2, perp), v2)
// J = [-perp, -cross(d + r1, perp), perp, cross(r2,perp)]
//
// Angular constraint
// C = a2 - a1 + a_initial
// Cdot = w2 - w1
// J = [0 0 -1 0 0 1]
//
// K = J * invM * JT
//
// J = [-a -s1 a s2]
// [0 -1 0 1]
// a = perp
// s1 = cross(d + r1, a) = cross(p2 - x1, a)
// s2 = cross(r2, a) = cross(p2 - x2, a)
// Motor/Limit linear constraint
// C = dot(ax1, d)
// Cdot = = -dot(ax1, v1) - dot(cross(d + r1, ax1), w1) + dot(ax1, v2) + dot(cross(r2, ax1), v2)
// J = [-ax1 -cross(d+r1,ax1) ax1 cross(r2,ax1)]
// Block Solver
// We develop a block solver that includes the joint limit. This makes the limit stiff (inelastic) even
// when the mass has poor distribution (leading to large torques about the joint anchor points).
//
// The Jacobian has 3 rows:
// J = [-uT -s1 uT s2] // linear
// [0 -1 0 1] // angular
// [-vT -a1 vT a2] // limit
//
// u = perp
// v = axis
// s1 = cross(d + r1, u), s2 = cross(r2, u)
// a1 = cross(d + r1, v), a2 = cross(r2, v)
// M * (v2 - v1) = JT * df
// J * v2 = bias
//
// v2 = v1 + invM * JT * df
// J * (v1 + invM * JT * df) = bias
// K * df = bias - J * v1 = -Cdot
// K = J * invM * JT
// Cdot = J * v1 - bias
//
// Now solve for f2.
// df = f2 - f1
// K * (f2 - f1) = -Cdot
// f2 = invK * (-Cdot) + f1
//
// Clamp accumulated limit impulse.
// lower: f2(3) = max(f2(3), 0)
// upper: f2(3) = min(f2(3), 0)
//
// Solve for correct f2(1:2)
// K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:3) * f1
// = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:2) * f1(1:2) + K(1:2,3) * f1(3)
// K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3)) + K(1:2,1:2) * f1(1:2)
// f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2)
//
// Now compute impulse to be applied:
// df = f2 - f1
void b2PrismaticJointDef::Initialize(b2Body* b1, b2Body* b2, const b2Vec2& anchor, const b2Vec2& axis)
{
bodyA = b1;
bodyB = b2;
localAnchorA = bodyA->GetLocalPoint(anchor);
localAnchorB = bodyB->GetLocalPoint(anchor);
localAxis1 = bodyA->GetLocalVector(axis);
referenceAngle = bodyB->GetAngle() - bodyA->GetAngle();
}
b2PrismaticJoint::b2PrismaticJoint(const b2PrismaticJointDef* def)
: b2Joint(def)
{
m_localAnchor1 = def->localAnchorA;
m_localAnchor2 = def->localAnchorB;
m_localXAxis1 = def->localAxis1;
m_localYAxis1 = b2Cross(1.0f, m_localXAxis1);
m_refAngle = def->referenceAngle;
m_impulse.SetZero();
m_motorMass = 0.0;
m_motorImpulse = 0.0f;
m_lowerTranslation = def->lowerTranslation;
m_upperTranslation = def->upperTranslation;
m_maxMotorForce = def->maxMotorForce;
m_motorSpeed = def->motorSpeed;
m_enableLimit = def->enableLimit;
m_enableMotor = def->enableMotor;
m_limitState = e_inactiveLimit;
m_axis.SetZero();
m_perp.SetZero();
}
void b2PrismaticJoint::InitVelocityConstraints(const b2TimeStep& step)
{
b2Body* b1 = m_bodyA;
b2Body* b2 = m_bodyB;
m_localCenterA = b1->GetLocalCenter();
m_localCenterB = b2->GetLocalCenter();
b2Transform xf1 = b1->GetTransform();
b2Transform xf2 = b2->GetTransform();
// Compute the effective masses.
b2Vec2 r1 = b2Mul(xf1.R, m_localAnchor1 - m_localCenterA);
b2Vec2 r2 = b2Mul(xf2.R, m_localAnchor2 - m_localCenterB);
b2Vec2 d = b2->m_sweep.c + r2 - b1->m_sweep.c - r1;
m_invMassA = b1->m_invMass;
m_invIA = b1->m_invI;
m_invMassB = b2->m_invMass;
m_invIB = b2->m_invI;
// Compute motor Jacobian and effective mass.
{
m_axis = b2Mul(xf1.R, m_localXAxis1);
m_a1 = b2Cross(d + r1, m_axis);
m_a2 = b2Cross(r2, m_axis);
m_motorMass = m_invMassA + m_invMassB + m_invIA * m_a1 * m_a1 + m_invIB * m_a2 * m_a2;
if (m_motorMass > b2_epsilon)
{
m_motorMass = 1.0f / m_motorMass;
}
}
// Prismatic constraint.
{
m_perp = b2Mul(xf1.R, m_localYAxis1);
m_s1 = b2Cross(d + r1, m_perp);
m_s2 = b2Cross(r2, m_perp);
float32 m1 = m_invMassA, m2 = m_invMassB;
float32 i1 = m_invIA, i2 = m_invIB;
float32 k11 = m1 + m2 + i1 * m_s1 * m_s1 + i2 * m_s2 * m_s2;
float32 k12 = i1 * m_s1 + i2 * m_s2;
float32 k13 = i1 * m_s1 * m_a1 + i2 * m_s2 * m_a2;
float32 k22 = i1 + i2;
float32 k23 = i1 * m_a1 + i2 * m_a2;
float32 k33 = m1 + m2 + i1 * m_a1 * m_a1 + i2 * m_a2 * m_a2;
m_K.col1.Set(k11, k12, k13);
m_K.col2.Set(k12, k22, k23);
m_K.col3.Set(k13, k23, k33);
}
// Compute motor and limit terms.
if (m_enableLimit)
{
float32 jointTranslation = b2Dot(m_axis, d);
if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop)
{
m_limitState = e_equalLimits;
}
else if (jointTranslation <= m_lowerTranslation)
{
if (m_limitState != e_atLowerLimit)
{
m_limitState = e_atLowerLimit;
m_impulse.z = 0.0f;
}
}
else if (jointTranslation >= m_upperTranslation)
{
if (m_limitState != e_atUpperLimit)
{
m_limitState = e_atUpperLimit;
m_impulse.z = 0.0f;
}
}
else
{
m_limitState = e_inactiveLimit;
m_impulse.z = 0.0f;
}
}
else
{
m_limitState = e_inactiveLimit;
m_impulse.z = 0.0f;
}
if (m_enableMotor == false)
{
m_motorImpulse = 0.0f;
}
if (step.warmStarting)
{
// Account for variable time step.
m_impulse *= step.dtRatio;
m_motorImpulse *= step.dtRatio;
b2Vec2 P = m_impulse.x * m_perp + (m_motorImpulse + m_impulse.z) * m_axis;
float32 L1 = m_impulse.x * m_s1 + m_impulse.y + (m_motorImpulse + m_impulse.z) * m_a1;
float32 L2 = m_impulse.x * m_s2 + m_impulse.y + (m_motorImpulse + m_impulse.z) * m_a2;
b1->m_linearVelocity -= m_invMassA * P;
b1->m_angularVelocity -= m_invIA * L1;
b2->m_linearVelocity += m_invMassB * P;
b2->m_angularVelocity += m_invIB * L2;
}
else
{
m_impulse.SetZero();
m_motorImpulse = 0.0f;
}
}
void b2PrismaticJoint::SolveVelocityConstraints(const b2TimeStep& step)
{
b2Body* b1 = m_bodyA;
b2Body* b2 = m_bodyB;
b2Vec2 v1 = b1->m_linearVelocity;
float32 w1 = b1->m_angularVelocity;
b2Vec2 v2 = b2->m_linearVelocity;
float32 w2 = b2->m_angularVelocity;
// Solve linear motor constraint.
if (m_enableMotor && m_limitState != e_equalLimits)
{
float32 Cdot = b2Dot(m_axis, v2 - v1) + m_a2 * w2 - m_a1 * w1;
float32 impulse = m_motorMass * (m_motorSpeed - Cdot);
float32 oldImpulse = m_motorImpulse;
float32 maxImpulse = step.dt * m_maxMotorForce;
m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse);
impulse = m_motorImpulse - oldImpulse;
b2Vec2 P = impulse * m_axis;
float32 L1 = impulse * m_a1;
float32 L2 = impulse * m_a2;
v1 -= m_invMassA * P;
w1 -= m_invIA * L1;
v2 += m_invMassB * P;
w2 += m_invIB * L2;
}
b2Vec2 Cdot1;
Cdot1.x = b2Dot(m_perp, v2 - v1) + m_s2 * w2 - m_s1 * w1;
Cdot1.y = w2 - w1;
if (m_enableLimit && m_limitState != e_inactiveLimit)
{
// Solve prismatic and limit constraint in block form.
float32 Cdot2;
Cdot2 = b2Dot(m_axis, v2 - v1) + m_a2 * w2 - m_a1 * w1;
b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2);
b2Vec3 f1 = m_impulse;
b2Vec3 df = m_K.Solve33(-Cdot);
m_impulse += df;
if (m_limitState == e_atLowerLimit)
{
m_impulse.z = b2Max(m_impulse.z, 0.0f);
}
else if (m_limitState == e_atUpperLimit)
{
m_impulse.z = b2Min(m_impulse.z, 0.0f);
}
// f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2)
b2Vec2 b = -Cdot1 - (m_impulse.z - f1.z) * b2Vec2(m_K.col3.x, m_K.col3.y);
b2Vec2 f2r = m_K.Solve22(b) + b2Vec2(f1.x, f1.y);
m_impulse.x = f2r.x;
m_impulse.y = f2r.y;
df = m_impulse - f1;
b2Vec2 P = df.x * m_perp + df.z * m_axis;
float32 L1 = df.x * m_s1 + df.y + df.z * m_a1;
float32 L2 = df.x * m_s2 + df.y + df.z * m_a2;
v1 -= m_invMassA * P;
w1 -= m_invIA * L1;
v2 += m_invMassB * P;
w2 += m_invIB * L2;
}
else
{
// Limit is inactive, just solve the prismatic constraint in block form.
b2Vec2 df = m_K.Solve22(-Cdot1);
m_impulse.x += df.x;
m_impulse.y += df.y;
b2Vec2 P = df.x * m_perp;
float32 L1 = df.x * m_s1 + df.y;
float32 L2 = df.x * m_s2 + df.y;
v1 -= m_invMassA * P;
w1 -= m_invIA * L1;
v2 += m_invMassB * P;
w2 += m_invIB * L2;
}
b1->m_linearVelocity = v1;
b1->m_angularVelocity = w1;
b2->m_linearVelocity = v2;
b2->m_angularVelocity = w2;
}
bool b2PrismaticJoint::SolvePositionConstraints(float32 baumgarte)
{
B2_NOT_USED(baumgarte);
b2Body* b1 = m_bodyA;
b2Body* b2 = m_bodyB;
b2Vec2 c1 = b1->m_sweep.c;
float32 a1 = b1->m_sweep.a;
b2Vec2 c2 = b2->m_sweep.c;
float32 a2 = b2->m_sweep.a;
// Solve linear limit constraint.
float32 linearError = 0.0f, angularError = 0.0f;
bool active = false;
float32 C2 = 0.0f;
b2Mat22 R1(a1), R2(a2);
b2Vec2 r1 = b2Mul(R1, m_localAnchor1 - m_localCenterA);
b2Vec2 r2 = b2Mul(R2, m_localAnchor2 - m_localCenterB);
b2Vec2 d = c2 + r2 - c1 - r1;
if (m_enableLimit)
{
m_axis = b2Mul(R1, m_localXAxis1);
m_a1 = b2Cross(d + r1, m_axis);
m_a2 = b2Cross(r2, m_axis);
float32 translation = b2Dot(m_axis, d);
if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop)
{
// Prevent large angular corrections
C2 = b2Clamp(translation, -b2_maxLinearCorrection, b2_maxLinearCorrection);
linearError = b2Abs(translation);
active = true;
}
else if (translation <= m_lowerTranslation)
{
// Prevent large linear corrections and allow some slop.
C2 = b2Clamp(translation - m_lowerTranslation + b2_linearSlop, -b2_maxLinearCorrection, 0.0f);
linearError = m_lowerTranslation - translation;
active = true;
}
else if (translation >= m_upperTranslation)
{
// Prevent large linear corrections and allow some slop.
C2 = b2Clamp(translation - m_upperTranslation - b2_linearSlop, 0.0f, b2_maxLinearCorrection);
linearError = translation - m_upperTranslation;
active = true;
}
}
m_perp = b2Mul(R1, m_localYAxis1);
m_s1 = b2Cross(d + r1, m_perp);
m_s2 = b2Cross(r2, m_perp);
b2Vec3 impulse;
b2Vec2 C1;
C1.x = b2Dot(m_perp, d);
C1.y = a2 - a1 - m_refAngle;
linearError = b2Max(linearError, b2Abs(C1.x));
angularError = b2Abs(C1.y);
if (active)
{
float32 m1 = m_invMassA, m2 = m_invMassB;
float32 i1 = m_invIA, i2 = m_invIB;
float32 k11 = m1 + m2 + i1 * m_s1 * m_s1 + i2 * m_s2 * m_s2;
float32 k12 = i1 * m_s1 + i2 * m_s2;
float32 k13 = i1 * m_s1 * m_a1 + i2 * m_s2 * m_a2;
float32 k22 = i1 + i2;
float32 k23 = i1 * m_a1 + i2 * m_a2;
float32 k33 = m1 + m2 + i1 * m_a1 * m_a1 + i2 * m_a2 * m_a2;
m_K.col1.Set(k11, k12, k13);
m_K.col2.Set(k12, k22, k23);
m_K.col3.Set(k13, k23, k33);
b2Vec3 C;
C.x = C1.x;
C.y = C1.y;
C.z = C2;
impulse = m_K.Solve33(-C);
}
else
{
float32 m1 = m_invMassA, m2 = m_invMassB;
float32 i1 = m_invIA, i2 = m_invIB;
float32 k11 = m1 + m2 + i1 * m_s1 * m_s1 + i2 * m_s2 * m_s2;
float32 k12 = i1 * m_s1 + i2 * m_s2;
float32 k22 = i1 + i2;
m_K.col1.Set(k11, k12, 0.0f);
m_K.col2.Set(k12, k22, 0.0f);
b2Vec2 impulse1 = m_K.Solve22(-C1);
impulse.x = impulse1.x;
impulse.y = impulse1.y;
impulse.z = 0.0f;
}
b2Vec2 P = impulse.x * m_perp + impulse.z * m_axis;
float32 L1 = impulse.x * m_s1 + impulse.y + impulse.z * m_a1;
float32 L2 = impulse.x * m_s2 + impulse.y + impulse.z * m_a2;
c1 -= m_invMassA * P;
a1 -= m_invIA * L1;
c2 += m_invMassB * P;
a2 += m_invIB * L2;
// TODO_ERIN remove need for this.
b1->m_sweep.c = c1;
b1->m_sweep.a = a1;
b2->m_sweep.c = c2;
b2->m_sweep.a = a2;
b1->SynchronizeTransform();
b2->SynchronizeTransform();
return linearError <= b2_linearSlop && angularError <= b2_angularSlop;
}
b2Vec2 b2PrismaticJoint::GetAnchorA() const
{
return m_bodyA->GetWorldPoint(m_localAnchor1);
}
b2Vec2 b2PrismaticJoint::GetAnchorB() const
{
return m_bodyB->GetWorldPoint(m_localAnchor2);
}
b2Vec2 b2PrismaticJoint::GetReactionForce(float32 inv_dt) const
{
return inv_dt * (m_impulse.x * m_perp + (m_motorImpulse + m_impulse.z) * m_axis);
}
float32 b2PrismaticJoint::GetReactionTorque(float32 inv_dt) const
{
return inv_dt * m_impulse.y;
}
float32 b2PrismaticJoint::GetJointTranslation() const
{
b2Body* b1 = m_bodyA;
b2Body* b2 = m_bodyB;
b2Vec2 p1 = b1->GetWorldPoint(m_localAnchor1);
b2Vec2 p2 = b2->GetWorldPoint(m_localAnchor2);
b2Vec2 d = p2 - p1;
b2Vec2 axis = b1->GetWorldVector(m_localXAxis1);
float32 translation = b2Dot(d, axis);
return translation;
}
float32 b2PrismaticJoint::GetJointSpeed() const
{
b2Body* b1 = m_bodyA;
b2Body* b2 = m_bodyB;
b2Vec2 r1 = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter());
b2Vec2 r2 = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter());
b2Vec2 p1 = b1->m_sweep.c + r1;
b2Vec2 p2 = b2->m_sweep.c + r2;
b2Vec2 d = p2 - p1;
b2Vec2 axis = b1->GetWorldVector(m_localXAxis1);
b2Vec2 v1 = b1->m_linearVelocity;
b2Vec2 v2 = b2->m_linearVelocity;
float32 w1 = b1->m_angularVelocity;
float32 w2 = b2->m_angularVelocity;
float32 speed = b2Dot(d, b2Cross(w1, axis)) + b2Dot(axis, v2 + b2Cross(w2, r2) - v1 - b2Cross(w1, r1));
return speed;
}
bool b2PrismaticJoint::IsLimitEnabled() const
{
return m_enableLimit;
}
void b2PrismaticJoint::EnableLimit(bool flag)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_enableLimit = flag;
}
float32 b2PrismaticJoint::GetLowerLimit() const
{
return m_lowerTranslation;
}
float32 b2PrismaticJoint::GetUpperLimit() const
{
return m_upperTranslation;
}
void b2PrismaticJoint::SetLimits(float32 lower, float32 upper)
{
b2Assert(lower <= upper);
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_lowerTranslation = lower;
m_upperTranslation = upper;
}
bool b2PrismaticJoint::IsMotorEnabled() const
{
return m_enableMotor;
}
void b2PrismaticJoint::EnableMotor(bool flag)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_enableMotor = flag;
}
void b2PrismaticJoint::SetMotorSpeed(float32 speed)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_motorSpeed = speed;
}
void b2PrismaticJoint::SetMaxMotorForce(float32 force)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_maxMotorForce = force;
}
float32 b2PrismaticJoint::GetMotorForce() const
{
return m_motorImpulse;
}

View file

@ -1,175 +0,0 @@
/*
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_PRISMATIC_JOINT_H
#define B2_PRISMATIC_JOINT_H
#include "b2Joint.h"
/// Prismatic joint definition. This requires defining a line of
/// motion using an axis and an anchor point. The definition uses local
/// anchor points and a local axis so that the initial configuration
/// can violate the constraint slightly. The joint translation is zero
/// when the local anchor points coincide in world space. Using local
/// anchors and a local axis helps when saving and loading a game.
/// @warning at least one body should by dynamic with a non-fixed rotation.
struct b2PrismaticJointDef : public b2JointDef
{
b2PrismaticJointDef()
{
type = e_prismaticJoint;
localAnchorA.SetZero();
localAnchorB.SetZero();
localAxis1.Set(1.0f, 0.0f);
referenceAngle = 0.0f;
enableLimit = false;
lowerTranslation = 0.0f;
upperTranslation = 0.0f;
enableMotor = false;
maxMotorForce = 0.0f;
motorSpeed = 0.0f;
}
/// Initialize the bodies, anchors, axis, and reference angle using the world
/// anchor and world axis.
void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor, const b2Vec2& axis);
/// The local anchor point relative to body1's origin.
b2Vec2 localAnchorA;
/// The local anchor point relative to body2's origin.
b2Vec2 localAnchorB;
/// The local translation axis in body1.
b2Vec2 localAxis1;
/// The constrained angle between the bodies: body2_angle - body1_angle.
float32 referenceAngle;
/// Enable/disable the joint limit.
bool enableLimit;
/// The lower translation limit, usually in meters.
float32 lowerTranslation;
/// The upper translation limit, usually in meters.
float32 upperTranslation;
/// Enable/disable the joint motor.
bool enableMotor;
/// The maximum motor torque, usually in N-m.
float32 maxMotorForce;
/// The desired motor speed in radians per second.
float32 motorSpeed;
};
/// A prismatic joint. This joint provides one degree of freedom: translation
/// along an axis fixed in body1. Relative rotation is prevented. You can
/// use a joint limit to restrict the range of motion and a joint motor to
/// drive the motion or to model joint friction.
class b2PrismaticJoint : public b2Joint
{
public:
b2Vec2 GetAnchorA() const;
b2Vec2 GetAnchorB() const;
b2Vec2 GetReactionForce(float32 inv_dt) const;
float32 GetReactionTorque(float32 inv_dt) const;
/// Get the current joint translation, usually in meters.
float32 GetJointTranslation() const;
/// Get the current joint translation speed, usually in meters per second.
float32 GetJointSpeed() const;
/// Is the joint limit enabled?
bool IsLimitEnabled() const;
/// Enable/disable the joint limit.
void EnableLimit(bool flag);
/// Get the lower joint limit, usually in meters.
float32 GetLowerLimit() const;
/// Get the upper joint limit, usually in meters.
float32 GetUpperLimit() const;
/// Set the joint limits, usually in meters.
void SetLimits(float32 lower, float32 upper);
/// Is the joint motor enabled?
bool IsMotorEnabled() const;
/// Enable/disable the joint motor.
void EnableMotor(bool flag);
/// Set the motor speed, usually in meters per second.
void SetMotorSpeed(float32 speed);
/// Get the motor speed, usually in meters per second.
float32 GetMotorSpeed() const;
/// Set the maximum motor force, usually in N.
void SetMaxMotorForce(float32 force);
/// Get the current motor force, usually in N.
float32 GetMotorForce() const;
protected:
friend class b2Joint;
friend class b2GearJoint;
b2PrismaticJoint(const b2PrismaticJointDef* def);
void InitVelocityConstraints(const b2TimeStep& step);
void SolveVelocityConstraints(const b2TimeStep& step);
bool SolvePositionConstraints(float32 baumgarte);
b2Vec2 m_localAnchor1;
b2Vec2 m_localAnchor2;
b2Vec2 m_localXAxis1;
b2Vec2 m_localYAxis1;
float32 m_refAngle;
b2Vec2 m_axis, m_perp;
float32 m_s1, m_s2;
float32 m_a1, m_a2;
b2Mat33 m_K;
b2Vec3 m_impulse;
float32 m_motorMass; // effective mass for motor/limit translational constraint.
float32 m_motorImpulse;
float32 m_lowerTranslation;
float32 m_upperTranslation;
float32 m_maxMotorForce;
float32 m_motorSpeed;
bool m_enableLimit;
bool m_enableMotor;
b2LimitState m_limitState;
};
inline float32 b2PrismaticJoint::GetMotorSpeed() const
{
return m_motorSpeed;
}
#endif

View file

@ -1,427 +0,0 @@
/*
* Copyright (c) 2007 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "b2PulleyJoint.h"
#include "b2Body.h"
#include "b2TimeStep.h"
// Pulley:
// length1 = norm(p1 - s1)
// length2 = norm(p2 - s2)
// C0 = (length1 + ratio * length2)_initial
// C = C0 - (length1 + ratio * length2) >= 0
// u1 = (p1 - s1) / norm(p1 - s1)
// u2 = (p2 - s2) / norm(p2 - s2)
// Cdot = -dot(u1, v1 + cross(w1, r1)) - ratio * dot(u2, v2 + cross(w2, r2))
// J = -[u1 cross(r1, u1) ratio * u2 ratio * cross(r2, u2)]
// K = J * invM * JT
// = invMass1 + invI1 * cross(r1, u1)^2 + ratio^2 * (invMass2 + invI2 * cross(r2, u2)^2)
//
// Limit:
// C = maxLength - length
// u = (p - s) / norm(p - s)
// Cdot = -dot(u, v + cross(w, r))
// K = invMass + invI * cross(r, u)^2
// 0 <= impulse
void b2PulleyJointDef::Initialize(b2Body* b1, b2Body* b2,
const b2Vec2& ga1, const b2Vec2& ga2,
const b2Vec2& anchor1, const b2Vec2& anchor2,
float32 r)
{
bodyA = b1;
bodyB = b2;
groundAnchorA = ga1;
groundAnchorB = ga2;
localAnchorA = bodyA->GetLocalPoint(anchor1);
localAnchorB = bodyB->GetLocalPoint(anchor2);
b2Vec2 d1 = anchor1 - ga1;
lengthA = d1.Length();
b2Vec2 d2 = anchor2 - ga2;
lengthB = d2.Length();
ratio = r;
b2Assert(ratio > b2_epsilon);
float32 C = lengthA + ratio * lengthB;
maxLengthA = C - ratio * b2_minPulleyLength;
maxLengthB = (C - b2_minPulleyLength) / ratio;
}
b2PulleyJoint::b2PulleyJoint(const b2PulleyJointDef* def)
: b2Joint(def)
{
m_groundAnchor1 = def->groundAnchorA;
m_groundAnchor2 = def->groundAnchorB;
m_localAnchor1 = def->localAnchorA;
m_localAnchor2 = def->localAnchorB;
b2Assert(def->ratio != 0.0f);
m_ratio = def->ratio;
m_constant = def->lengthA + m_ratio * def->lengthB;
m_maxLength1 = b2Min(def->maxLengthA, m_constant - m_ratio * b2_minPulleyLength);
m_maxLength2 = b2Min(def->maxLengthB, (m_constant - b2_minPulleyLength) / m_ratio);
m_impulse = 0.0f;
m_limitImpulse1 = 0.0f;
m_limitImpulse2 = 0.0f;
}
void b2PulleyJoint::InitVelocityConstraints(const b2TimeStep& step)
{
b2Body* b1 = m_bodyA;
b2Body* b2 = m_bodyB;
b2Vec2 r1 = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter());
b2Vec2 r2 = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter());
b2Vec2 p1 = b1->m_sweep.c + r1;
b2Vec2 p2 = b2->m_sweep.c + r2;
b2Vec2 s1 = m_groundAnchor1;
b2Vec2 s2 = m_groundAnchor2;
// Get the pulley axes.
m_u1 = p1 - s1;
m_u2 = p2 - s2;
float32 length1 = m_u1.Length();
float32 length2 = m_u2.Length();
if (length1 > b2_linearSlop)
{
m_u1 *= 1.0f / length1;
}
else
{
m_u1.SetZero();
}
if (length2 > b2_linearSlop)
{
m_u2 *= 1.0f / length2;
}
else
{
m_u2.SetZero();
}
float32 C = m_constant - length1 - m_ratio * length2;
if (C > 0.0f)
{
m_state = e_inactiveLimit;
m_impulse = 0.0f;
}
else
{
m_state = e_atUpperLimit;
}
if (length1 < m_maxLength1)
{
m_limitState1 = e_inactiveLimit;
m_limitImpulse1 = 0.0f;
}
else
{
m_limitState1 = e_atUpperLimit;
}
if (length2 < m_maxLength2)
{
m_limitState2 = e_inactiveLimit;
m_limitImpulse2 = 0.0f;
}
else
{
m_limitState2 = e_atUpperLimit;
}
// Compute effective mass.
float32 cr1u1 = b2Cross(r1, m_u1);
float32 cr2u2 = b2Cross(r2, m_u2);
m_limitMass1 = b1->m_invMass + b1->m_invI * cr1u1 * cr1u1;
m_limitMass2 = b2->m_invMass + b2->m_invI * cr2u2 * cr2u2;
m_pulleyMass = m_limitMass1 + m_ratio * m_ratio * m_limitMass2;
b2Assert(m_limitMass1 > b2_epsilon);
b2Assert(m_limitMass2 > b2_epsilon);
b2Assert(m_pulleyMass > b2_epsilon);
m_limitMass1 = 1.0f / m_limitMass1;
m_limitMass2 = 1.0f / m_limitMass2;
m_pulleyMass = 1.0f / m_pulleyMass;
if (step.warmStarting)
{
// Scale impulses to support variable time steps.
m_impulse *= step.dtRatio;
m_limitImpulse1 *= step.dtRatio;
m_limitImpulse2 *= step.dtRatio;
// Warm starting.
b2Vec2 P1 = -(m_impulse + m_limitImpulse1) * m_u1;
b2Vec2 P2 = (-m_ratio * m_impulse - m_limitImpulse2) * m_u2;
b1->m_linearVelocity += b1->m_invMass * P1;
b1->m_angularVelocity += b1->m_invI * b2Cross(r1, P1);
b2->m_linearVelocity += b2->m_invMass * P2;
b2->m_angularVelocity += b2->m_invI * b2Cross(r2, P2);
}
else
{
m_impulse = 0.0f;
m_limitImpulse1 = 0.0f;
m_limitImpulse2 = 0.0f;
}
}
void b2PulleyJoint::SolveVelocityConstraints(const b2TimeStep& step)
{
B2_NOT_USED(step);
b2Body* b1 = m_bodyA;
b2Body* b2 = m_bodyB;
b2Vec2 r1 = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter());
b2Vec2 r2 = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter());
if (m_state == e_atUpperLimit)
{
b2Vec2 v1 = b1->m_linearVelocity + b2Cross(b1->m_angularVelocity, r1);
b2Vec2 v2 = b2->m_linearVelocity + b2Cross(b2->m_angularVelocity, r2);
float32 Cdot = -b2Dot(m_u1, v1) - m_ratio * b2Dot(m_u2, v2);
float32 impulse = m_pulleyMass * (-Cdot);
float32 oldImpulse = m_impulse;
m_impulse = b2Max(0.0f, m_impulse + impulse);
impulse = m_impulse - oldImpulse;
b2Vec2 P1 = -impulse * m_u1;
b2Vec2 P2 = -m_ratio * impulse * m_u2;
b1->m_linearVelocity += b1->m_invMass * P1;
b1->m_angularVelocity += b1->m_invI * b2Cross(r1, P1);
b2->m_linearVelocity += b2->m_invMass * P2;
b2->m_angularVelocity += b2->m_invI * b2Cross(r2, P2);
}
if (m_limitState1 == e_atUpperLimit)
{
b2Vec2 v1 = b1->m_linearVelocity + b2Cross(b1->m_angularVelocity, r1);
float32 Cdot = -b2Dot(m_u1, v1);
float32 impulse = -m_limitMass1 * Cdot;
float32 oldImpulse = m_limitImpulse1;
m_limitImpulse1 = b2Max(0.0f, m_limitImpulse1 + impulse);
impulse = m_limitImpulse1 - oldImpulse;
b2Vec2 P1 = -impulse * m_u1;
b1->m_linearVelocity += b1->m_invMass * P1;
b1->m_angularVelocity += b1->m_invI * b2Cross(r1, P1);
}
if (m_limitState2 == e_atUpperLimit)
{
b2Vec2 v2 = b2->m_linearVelocity + b2Cross(b2->m_angularVelocity, r2);
float32 Cdot = -b2Dot(m_u2, v2);
float32 impulse = -m_limitMass2 * Cdot;
float32 oldImpulse = m_limitImpulse2;
m_limitImpulse2 = b2Max(0.0f, m_limitImpulse2 + impulse);
impulse = m_limitImpulse2 - oldImpulse;
b2Vec2 P2 = -impulse * m_u2;
b2->m_linearVelocity += b2->m_invMass * P2;
b2->m_angularVelocity += b2->m_invI * b2Cross(r2, P2);
}
}
bool b2PulleyJoint::SolvePositionConstraints(float32 baumgarte)
{
B2_NOT_USED(baumgarte);
b2Body* b1 = m_bodyA;
b2Body* b2 = m_bodyB;
b2Vec2 s1 = m_groundAnchor1;
b2Vec2 s2 = m_groundAnchor2;
float32 linearError = 0.0f;
if (m_state == e_atUpperLimit)
{
b2Vec2 r1 = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter());
b2Vec2 r2 = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter());
b2Vec2 p1 = b1->m_sweep.c + r1;
b2Vec2 p2 = b2->m_sweep.c + r2;
// Get the pulley axes.
m_u1 = p1 - s1;
m_u2 = p2 - s2;
float32 length1 = m_u1.Length();
float32 length2 = m_u2.Length();
if (length1 > b2_linearSlop)
{
m_u1 *= 1.0f / length1;
}
else
{
m_u1.SetZero();
}
if (length2 > b2_linearSlop)
{
m_u2 *= 1.0f / length2;
}
else
{
m_u2.SetZero();
}
float32 C = m_constant - length1 - m_ratio * length2;
linearError = b2Max(linearError, -C);
C = b2Clamp(C + b2_linearSlop, -b2_maxLinearCorrection, 0.0f);
float32 impulse = -m_pulleyMass * C;
b2Vec2 P1 = -impulse * m_u1;
b2Vec2 P2 = -m_ratio * impulse * m_u2;
b1->m_sweep.c += b1->m_invMass * P1;
b1->m_sweep.a += b1->m_invI * b2Cross(r1, P1);
b2->m_sweep.c += b2->m_invMass * P2;
b2->m_sweep.a += b2->m_invI * b2Cross(r2, P2);
b1->SynchronizeTransform();
b2->SynchronizeTransform();
}
if (m_limitState1 == e_atUpperLimit)
{
b2Vec2 r1 = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter());
b2Vec2 p1 = b1->m_sweep.c + r1;
m_u1 = p1 - s1;
float32 length1 = m_u1.Length();
if (length1 > b2_linearSlop)
{
m_u1 *= 1.0f / length1;
}
else
{
m_u1.SetZero();
}
float32 C = m_maxLength1 - length1;
linearError = b2Max(linearError, -C);
C = b2Clamp(C + b2_linearSlop, -b2_maxLinearCorrection, 0.0f);
float32 impulse = -m_limitMass1 * C;
b2Vec2 P1 = -impulse * m_u1;
b1->m_sweep.c += b1->m_invMass * P1;
b1->m_sweep.a += b1->m_invI * b2Cross(r1, P1);
b1->SynchronizeTransform();
}
if (m_limitState2 == e_atUpperLimit)
{
b2Vec2 r2 = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter());
b2Vec2 p2 = b2->m_sweep.c + r2;
m_u2 = p2 - s2;
float32 length2 = m_u2.Length();
if (length2 > b2_linearSlop)
{
m_u2 *= 1.0f / length2;
}
else
{
m_u2.SetZero();
}
float32 C = m_maxLength2 - length2;
linearError = b2Max(linearError, -C);
C = b2Clamp(C + b2_linearSlop, -b2_maxLinearCorrection, 0.0f);
float32 impulse = -m_limitMass2 * C;
b2Vec2 P2 = -impulse * m_u2;
b2->m_sweep.c += b2->m_invMass * P2;
b2->m_sweep.a += b2->m_invI * b2Cross(r2, P2);
b2->SynchronizeTransform();
}
return linearError < b2_linearSlop;
}
b2Vec2 b2PulleyJoint::GetAnchorA() const
{
return m_bodyA->GetWorldPoint(m_localAnchor1);
}
b2Vec2 b2PulleyJoint::GetAnchorB() const
{
return m_bodyB->GetWorldPoint(m_localAnchor2);
}
b2Vec2 b2PulleyJoint::GetReactionForce(float32 inv_dt) const
{
b2Vec2 P = m_impulse * m_u2;
return inv_dt * P;
}
float32 b2PulleyJoint::GetReactionTorque(float32 inv_dt) const
{
B2_NOT_USED(inv_dt);
return 0.0f;
}
b2Vec2 b2PulleyJoint::GetGroundAnchorA() const
{
return m_groundAnchor1;
}
b2Vec2 b2PulleyJoint::GetGroundAnchorB() const
{
return m_groundAnchor2;
}
float32 b2PulleyJoint::GetLength1() const
{
b2Vec2 p = m_bodyA->GetWorldPoint(m_localAnchor1);
b2Vec2 s = m_groundAnchor1;
b2Vec2 d = p - s;
return d.Length();
}
float32 b2PulleyJoint::GetLength2() const
{
b2Vec2 p = m_bodyB->GetWorldPoint(m_localAnchor2);
b2Vec2 s = m_groundAnchor2;
b2Vec2 d = p - s;
return d.Length();
}
float32 b2PulleyJoint::GetRatio() const
{
return m_ratio;
}

View file

@ -1,148 +0,0 @@
/*
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_PULLEY_JOINT_H
#define B2_PULLEY_JOINT_H
#include "b2Joint.h"
const float32 b2_minPulleyLength = 2.0f;
/// Pulley joint definition. This requires two ground anchors,
/// two dynamic body anchor points, max lengths for each side,
/// and a pulley ratio.
struct b2PulleyJointDef : public b2JointDef
{
b2PulleyJointDef()
{
type = e_pulleyJoint;
groundAnchorA.Set(-1.0f, 1.0f);
groundAnchorB.Set(1.0f, 1.0f);
localAnchorA.Set(-1.0f, 0.0f);
localAnchorB.Set(1.0f, 0.0f);
lengthA = 0.0f;
maxLengthA = 0.0f;
lengthB = 0.0f;
maxLengthB = 0.0f;
ratio = 1.0f;
collideConnected = true;
}
/// Initialize the bodies, anchors, lengths, max lengths, and ratio using the world anchors.
void Initialize(b2Body* bodyA, b2Body* bodyB,
const b2Vec2& groundAnchorA, const b2Vec2& groundAnchorB,
const b2Vec2& anchorA, const b2Vec2& anchorB,
float32 ratio);
/// The first ground anchor in world coordinates. This point never moves.
b2Vec2 groundAnchorA;
/// The second ground anchor in world coordinates. This point never moves.
b2Vec2 groundAnchorB;
/// The local anchor point relative to bodyA's origin.
b2Vec2 localAnchorA;
/// The local anchor point relative to bodyB's origin.
b2Vec2 localAnchorB;
/// The a reference length for the segment attached to bodyA.
float32 lengthA;
/// The maximum length of the segment attached to bodyA.
float32 maxLengthA;
/// The a reference length for the segment attached to bodyB.
float32 lengthB;
/// The maximum length of the segment attached to bodyB.
float32 maxLengthB;
/// The pulley ratio, used to simulate a block-and-tackle.
float32 ratio;
};
/// The pulley joint is connected to two bodies and two fixed ground points.
/// The pulley supports a ratio such that:
/// length1 + ratio * length2 <= constant
/// Yes, the force transmitted is scaled by the ratio.
/// The pulley also enforces a maximum length limit on both sides. This is
/// useful to prevent one side of the pulley hitting the top.
class b2PulleyJoint : public b2Joint
{
public:
b2Vec2 GetAnchorA() const;
b2Vec2 GetAnchorB() const;
b2Vec2 GetReactionForce(float32 inv_dt) const;
float32 GetReactionTorque(float32 inv_dt) const;
/// Get the first ground anchor.
b2Vec2 GetGroundAnchorA() const;
/// Get the second ground anchor.
b2Vec2 GetGroundAnchorB() const;
/// Get the current length of the segment attached to body1.
float32 GetLength1() const;
/// Get the current length of the segment attached to body2.
float32 GetLength2() const;
/// Get the pulley ratio.
float32 GetRatio() const;
protected:
friend class b2Joint;
b2PulleyJoint(const b2PulleyJointDef* data);
void InitVelocityConstraints(const b2TimeStep& step);
void SolveVelocityConstraints(const b2TimeStep& step);
bool SolvePositionConstraints(float32 baumgarte);
b2Vec2 m_groundAnchor1;
b2Vec2 m_groundAnchor2;
b2Vec2 m_localAnchor1;
b2Vec2 m_localAnchor2;
b2Vec2 m_u1;
b2Vec2 m_u2;
float32 m_constant;
float32 m_ratio;
float32 m_maxLength1;
float32 m_maxLength2;
// Effective masses
float32 m_pulleyMass;
float32 m_limitMass1;
float32 m_limitMass2;
// Impulses for accumulation/warm starting.
float32 m_impulse;
float32 m_limitImpulse1;
float32 m_limitImpulse2;
b2LimitState m_state;
b2LimitState m_limitState1;
b2LimitState m_limitState2;
};
#endif

View file

@ -1,478 +0,0 @@
/*
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "b2RevoluteJoint.h"
#include "b2Body.h"
#include "b2TimeStep.h"
// Point-to-point constraint
// C = p2 - p1
// Cdot = v2 - v1
// = v2 + cross(w2, r2) - v1 - cross(w1, r1)
// J = [-I -r1_skew I r2_skew ]
// Identity used:
// w k % (rx i + ry j) = w * (-ry i + rx j)
// Motor constraint
// Cdot = w2 - w1
// J = [0 0 -1 0 0 1]
// K = invI1 + invI2
void b2RevoluteJointDef::Initialize(b2Body* b1, b2Body* b2, const b2Vec2& anchor)
{
bodyA = b1;
bodyB = b2;
localAnchorA = bodyA->GetLocalPoint(anchor);
localAnchorB = bodyB->GetLocalPoint(anchor);
referenceAngle = bodyB->GetAngle() - bodyA->GetAngle();
}
b2RevoluteJoint::b2RevoluteJoint(const b2RevoluteJointDef* def)
: b2Joint(def)
{
m_localAnchor1 = def->localAnchorA;
m_localAnchor2 = def->localAnchorB;
m_referenceAngle = def->referenceAngle;
m_impulse.SetZero();
m_motorImpulse = 0.0f;
m_lowerAngle = def->lowerAngle;
m_upperAngle = def->upperAngle;
m_maxMotorTorque = def->maxMotorTorque;
m_motorSpeed = def->motorSpeed;
m_enableLimit = def->enableLimit;
m_enableMotor = def->enableMotor;
m_limitState = e_inactiveLimit;
}
void b2RevoluteJoint::InitVelocityConstraints(const b2TimeStep& step)
{
b2Body* b1 = m_bodyA;
b2Body* b2 = m_bodyB;
if (m_enableMotor || m_enableLimit)
{
// You cannot create a rotation limit between bodies that
// both have fixed rotation.
b2Assert(b1->m_invI > 0.0f || b2->m_invI > 0.0f);
}
// Compute the effective mass matrix.
b2Vec2 r1 = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter());
b2Vec2 r2 = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter());
// J = [-I -r1_skew I r2_skew]
// [ 0 -1 0 1]
// r_skew = [-ry; rx]
// Matlab
// K = [ m1+r1y^2*i1+m2+r2y^2*i2, -r1y*i1*r1x-r2y*i2*r2x, -r1y*i1-r2y*i2]
// [ -r1y*i1*r1x-r2y*i2*r2x, m1+r1x^2*i1+m2+r2x^2*i2, r1x*i1+r2x*i2]
// [ -r1y*i1-r2y*i2, r1x*i1+r2x*i2, i1+i2]
float32 m1 = b1->m_invMass, m2 = b2->m_invMass;
float32 i1 = b1->m_invI, i2 = b2->m_invI;
m_mass.col1.x = m1 + m2 + r1.y * r1.y * i1 + r2.y * r2.y * i2;
m_mass.col2.x = -r1.y * r1.x * i1 - r2.y * r2.x * i2;
m_mass.col3.x = -r1.y * i1 - r2.y * i2;
m_mass.col1.y = m_mass.col2.x;
m_mass.col2.y = m1 + m2 + r1.x * r1.x * i1 + r2.x * r2.x * i2;
m_mass.col3.y = r1.x * i1 + r2.x * i2;
m_mass.col1.z = m_mass.col3.x;
m_mass.col2.z = m_mass.col3.y;
m_mass.col3.z = i1 + i2;
m_motorMass = i1 + i2;
if (m_motorMass > 0.0f)
{
m_motorMass = 1.0f / m_motorMass;
}
if (m_enableMotor == false)
{
m_motorImpulse = 0.0f;
}
if (m_enableLimit)
{
float32 jointAngle = b2->m_sweep.a - b1->m_sweep.a - m_referenceAngle;
if (b2Abs(m_upperAngle - m_lowerAngle) < 2.0f * b2_angularSlop)
{
m_limitState = e_equalLimits;
}
else if (jointAngle <= m_lowerAngle)
{
if (m_limitState != e_atLowerLimit)
{
m_impulse.z = 0.0f;
}
m_limitState = e_atLowerLimit;
}
else if (jointAngle >= m_upperAngle)
{
if (m_limitState != e_atUpperLimit)
{
m_impulse.z = 0.0f;
}
m_limitState = e_atUpperLimit;
}
else
{
m_limitState = e_inactiveLimit;
m_impulse.z = 0.0f;
}
}
else
{
m_limitState = e_inactiveLimit;
}
if (step.warmStarting)
{
// Scale impulses to support a variable time step.
m_impulse *= step.dtRatio;
m_motorImpulse *= step.dtRatio;
b2Vec2 P(m_impulse.x, m_impulse.y);
b1->m_linearVelocity -= m1 * P;
b1->m_angularVelocity -= i1 * (b2Cross(r1, P) + m_motorImpulse + m_impulse.z);
b2->m_linearVelocity += m2 * P;
b2->m_angularVelocity += i2 * (b2Cross(r2, P) + m_motorImpulse + m_impulse.z);
}
else
{
m_impulse.SetZero();
m_motorImpulse = 0.0f;
}
}
void b2RevoluteJoint::SolveVelocityConstraints(const b2TimeStep& step)
{
b2Body* b1 = m_bodyA;
b2Body* b2 = m_bodyB;
b2Vec2 v1 = b1->m_linearVelocity;
float32 w1 = b1->m_angularVelocity;
b2Vec2 v2 = b2->m_linearVelocity;
float32 w2 = b2->m_angularVelocity;
float32 m1 = b1->m_invMass, m2 = b2->m_invMass;
float32 i1 = b1->m_invI, i2 = b2->m_invI;
// Solve motor constraint.
if (m_enableMotor && m_limitState != e_equalLimits)
{
float32 Cdot = w2 - w1 - m_motorSpeed;
float32 impulse = m_motorMass * (-Cdot);
float32 oldImpulse = m_motorImpulse;
float32 maxImpulse = step.dt * m_maxMotorTorque;
m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse);
impulse = m_motorImpulse - oldImpulse;
w1 -= i1 * impulse;
w2 += i2 * impulse;
}
// Solve limit constraint.
if (m_enableLimit && m_limitState != e_inactiveLimit)
{
b2Vec2 r1 = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter());
b2Vec2 r2 = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter());
// Solve point-to-point constraint
b2Vec2 Cdot1 = v2 + b2Cross(w2, r2) - v1 - b2Cross(w1, r1);
float32 Cdot2 = w2 - w1;
b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2);
b2Vec3 impulse = m_mass.Solve33(-Cdot);
if (m_limitState == e_equalLimits)
{
m_impulse += impulse;
}
else if (m_limitState == e_atLowerLimit)
{
float32 newImpulse = m_impulse.z + impulse.z;
if (newImpulse < 0.0f)
{
b2Vec2 reduced = m_mass.Solve22(-Cdot1);
impulse.x = reduced.x;
impulse.y = reduced.y;
impulse.z = -m_impulse.z;
m_impulse.x += reduced.x;
m_impulse.y += reduced.y;
m_impulse.z = 0.0f;
}
}
else if (m_limitState == e_atUpperLimit)
{
float32 newImpulse = m_impulse.z + impulse.z;
if (newImpulse > 0.0f)
{
b2Vec2 reduced = m_mass.Solve22(-Cdot1);
impulse.x = reduced.x;
impulse.y = reduced.y;
impulse.z = -m_impulse.z;
m_impulse.x += reduced.x;
m_impulse.y += reduced.y;
m_impulse.z = 0.0f;
}
}
b2Vec2 P(impulse.x, impulse.y);
v1 -= m1 * P;
w1 -= i1 * (b2Cross(r1, P) + impulse.z);
v2 += m2 * P;
w2 += i2 * (b2Cross(r2, P) + impulse.z);
}
else
{
b2Vec2 r1 = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter());
b2Vec2 r2 = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter());
// Solve point-to-point constraint
b2Vec2 Cdot = v2 + b2Cross(w2, r2) - v1 - b2Cross(w1, r1);
b2Vec2 impulse = m_mass.Solve22(-Cdot);
m_impulse.x += impulse.x;
m_impulse.y += impulse.y;
v1 -= m1 * impulse;
w1 -= i1 * b2Cross(r1, impulse);
v2 += m2 * impulse;
w2 += i2 * b2Cross(r2, impulse);
}
b1->m_linearVelocity = v1;
b1->m_angularVelocity = w1;
b2->m_linearVelocity = v2;
b2->m_angularVelocity = w2;
}
bool b2RevoluteJoint::SolvePositionConstraints(float32 baumgarte)
{
// TODO_ERIN block solve with limit.
B2_NOT_USED(baumgarte);
b2Body* b1 = m_bodyA;
b2Body* b2 = m_bodyB;
float32 angularError = 0.0f;
float32 positionError = 0.0f;
// Solve angular limit constraint.
if (m_enableLimit && m_limitState != e_inactiveLimit)
{
float32 angle = b2->m_sweep.a - b1->m_sweep.a - m_referenceAngle;
float32 limitImpulse = 0.0f;
if (m_limitState == e_equalLimits)
{
// Prevent large angular corrections
float32 C = b2Clamp(angle - m_lowerAngle, -b2_maxAngularCorrection, b2_maxAngularCorrection);
limitImpulse = -m_motorMass * C;
angularError = b2Abs(C);
}
else if (m_limitState == e_atLowerLimit)
{
float32 C = angle - m_lowerAngle;
angularError = -C;
// Prevent large angular corrections and allow some slop.
C = b2Clamp(C + b2_angularSlop, -b2_maxAngularCorrection, 0.0f);
limitImpulse = -m_motorMass * C;
}
else if (m_limitState == e_atUpperLimit)
{
float32 C = angle - m_upperAngle;
angularError = C;
// Prevent large angular corrections and allow some slop.
C = b2Clamp(C - b2_angularSlop, 0.0f, b2_maxAngularCorrection);
limitImpulse = -m_motorMass * C;
}
b1->m_sweep.a -= b1->m_invI * limitImpulse;
b2->m_sweep.a += b2->m_invI * limitImpulse;
b1->SynchronizeTransform();
b2->SynchronizeTransform();
}
// Solve point-to-point constraint.
{
b2Vec2 r1 = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter());
b2Vec2 r2 = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter());
b2Vec2 C = b2->m_sweep.c + r2 - b1->m_sweep.c - r1;
positionError = C.Length();
float32 invMass1 = b1->m_invMass, invMass2 = b2->m_invMass;
float32 invI1 = b1->m_invI, invI2 = b2->m_invI;
// Handle large detachment.
const float32 k_allowedStretch = 10.0f * b2_linearSlop;
if (C.LengthSquared() > k_allowedStretch * k_allowedStretch)
{
// Use a particle solution (no rotation).
b2Vec2 u = C; u.Normalize();
float32 m = invMass1 + invMass2;
if (m > 0.0f)
{
m = 1.0f / m;
}
b2Vec2 impulse = m * (-C);
const float32 k_beta = 0.5f;
b1->m_sweep.c -= k_beta * invMass1 * impulse;
b2->m_sweep.c += k_beta * invMass2 * impulse;
C = b2->m_sweep.c + r2 - b1->m_sweep.c - r1;
}
b2Mat22 K1;
K1.col1.x = invMass1 + invMass2; K1.col2.x = 0.0f;
K1.col1.y = 0.0f; K1.col2.y = invMass1 + invMass2;
b2Mat22 K2;
K2.col1.x = invI1 * r1.y * r1.y; K2.col2.x = -invI1 * r1.x * r1.y;
K2.col1.y = -invI1 * r1.x * r1.y; K2.col2.y = invI1 * r1.x * r1.x;
b2Mat22 K3;
K3.col1.x = invI2 * r2.y * r2.y; K3.col2.x = -invI2 * r2.x * r2.y;
K3.col1.y = -invI2 * r2.x * r2.y; K3.col2.y = invI2 * r2.x * r2.x;
b2Mat22 K = K1 + K2 + K3;
b2Vec2 impulse = K.Solve(-C);
b1->m_sweep.c -= b1->m_invMass * impulse;
b1->m_sweep.a -= b1->m_invI * b2Cross(r1, impulse);
b2->m_sweep.c += b2->m_invMass * impulse;
b2->m_sweep.a += b2->m_invI * b2Cross(r2, impulse);
b1->SynchronizeTransform();
b2->SynchronizeTransform();
}
return positionError <= b2_linearSlop && angularError <= b2_angularSlop;
}
b2Vec2 b2RevoluteJoint::GetAnchorA() const
{
return m_bodyA->GetWorldPoint(m_localAnchor1);
}
b2Vec2 b2RevoluteJoint::GetAnchorB() const
{
return m_bodyB->GetWorldPoint(m_localAnchor2);
}
b2Vec2 b2RevoluteJoint::GetReactionForce(float32 inv_dt) const
{
b2Vec2 P(m_impulse.x, m_impulse.y);
return inv_dt * P;
}
float32 b2RevoluteJoint::GetReactionTorque(float32 inv_dt) const
{
return inv_dt * m_impulse.z;
}
float32 b2RevoluteJoint::GetJointAngle() const
{
b2Body* b1 = m_bodyA;
b2Body* b2 = m_bodyB;
return b2->m_sweep.a - b1->m_sweep.a - m_referenceAngle;
}
float32 b2RevoluteJoint::GetJointSpeed() const
{
b2Body* b1 = m_bodyA;
b2Body* b2 = m_bodyB;
return b2->m_angularVelocity - b1->m_angularVelocity;
}
bool b2RevoluteJoint::IsMotorEnabled() const
{
return m_enableMotor;
}
void b2RevoluteJoint::EnableMotor(bool flag)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_enableMotor = flag;
}
float32 b2RevoluteJoint::GetMotorTorque() const
{
return m_motorImpulse;
}
void b2RevoluteJoint::SetMotorSpeed(float32 speed)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_motorSpeed = speed;
}
void b2RevoluteJoint::SetMaxMotorTorque(float32 torque)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_maxMotorTorque = torque;
}
bool b2RevoluteJoint::IsLimitEnabled() const
{
return m_enableLimit;
}
void b2RevoluteJoint::EnableLimit(bool flag)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_enableLimit = flag;
}
float32 b2RevoluteJoint::GetLowerLimit() const
{
return m_lowerAngle;
}
float32 b2RevoluteJoint::GetUpperLimit() const
{
return m_upperAngle;
}
void b2RevoluteJoint::SetLimits(float32 lower, float32 upper)
{
b2Assert(lower <= upper);
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_lowerAngle = lower;
m_upperAngle = upper;
}

View file

@ -1,174 +0,0 @@
/*
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_REVOLUTE_JOINT_H
#define B2_REVOLUTE_JOINT_H
#include "b2Joint.h"
/// Revolute joint definition. This requires defining an
/// anchor point where the bodies are joined. The definition
/// uses local anchor points so that the initial configuration
/// can violate the constraint slightly. You also need to
/// specify the initial relative angle for joint limits. This
/// helps when saving and loading a game.
/// The local anchor points are measured from the body's origin
/// rather than the center of mass because:
/// 1. you might not know where the center of mass will be.
/// 2. if you add/remove shapes from a body and recompute the mass,
/// the joints will be broken.
struct b2RevoluteJointDef : public b2JointDef
{
b2RevoluteJointDef()
{
type = e_revoluteJoint;
localAnchorA.Set(0.0f, 0.0f);
localAnchorB.Set(0.0f, 0.0f);
referenceAngle = 0.0f;
lowerAngle = 0.0f;
upperAngle = 0.0f;
maxMotorTorque = 0.0f;
motorSpeed = 0.0f;
enableLimit = false;
enableMotor = false;
}
/// Initialize the bodies, anchors, and reference angle using a world
/// anchor point.
void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor);
/// The local anchor point relative to body1's origin.
b2Vec2 localAnchorA;
/// The local anchor point relative to body2's origin.
b2Vec2 localAnchorB;
/// The body2 angle minus body1 angle in the reference state (radians).
float32 referenceAngle;
/// A flag to enable joint limits.
bool enableLimit;
/// The lower angle for the joint limit (radians).
float32 lowerAngle;
/// The upper angle for the joint limit (radians).
float32 upperAngle;
/// A flag to enable the joint motor.
bool enableMotor;
/// The desired motor speed. Usually in radians per second.
float32 motorSpeed;
/// The maximum motor torque used to achieve the desired motor speed.
/// Usually in N-m.
float32 maxMotorTorque;
};
/// A revolute joint constrains two bodies to share a common point while they
/// are free to rotate about the point. The relative rotation about the shared
/// point is the joint angle. You can limit the relative rotation with
/// a joint limit that specifies a lower and upper angle. You can use a motor
/// to drive the relative rotation about the shared point. A maximum motor torque
/// is provided so that infinite forces are not generated.
class b2RevoluteJoint : public b2Joint
{
public:
b2Vec2 GetAnchorA() const;
b2Vec2 GetAnchorB() const;
b2Vec2 GetReactionForce(float32 inv_dt) const;
float32 GetReactionTorque(float32 inv_dt) const;
/// Get the current joint angle in radians.
float32 GetJointAngle() const;
/// Get the current joint angle speed in radians per second.
float32 GetJointSpeed() const;
/// Is the joint limit enabled?
bool IsLimitEnabled() const;
/// Enable/disable the joint limit.
void EnableLimit(bool flag);
/// Get the lower joint limit in radians.
float32 GetLowerLimit() const;
/// Get the upper joint limit in radians.
float32 GetUpperLimit() const;
/// Set the joint limits in radians.
void SetLimits(float32 lower, float32 upper);
/// Is the joint motor enabled?
bool IsMotorEnabled() const;
/// Enable/disable the joint motor.
void EnableMotor(bool flag);
/// Set the motor speed in radians per second.
void SetMotorSpeed(float32 speed);
/// Get the motor speed in radians per second.
float32 GetMotorSpeed() const;
/// Set the maximum motor torque, usually in N-m.
void SetMaxMotorTorque(float32 torque);
/// Get the current motor torque, usually in N-m.
float32 GetMotorTorque() const;
protected:
friend class b2Joint;
friend class b2GearJoint;
b2RevoluteJoint(const b2RevoluteJointDef* def);
void InitVelocityConstraints(const b2TimeStep& step);
void SolveVelocityConstraints(const b2TimeStep& step);
bool SolvePositionConstraints(float32 baumgarte);
b2Vec2 m_localAnchor1; // relative
b2Vec2 m_localAnchor2;
b2Vec3 m_impulse;
float32 m_motorImpulse;
b2Mat33 m_mass; // effective mass for point-to-point constraint.
float32 m_motorMass; // effective mass for motor/limit angular constraint.
bool m_enableMotor;
float32 m_maxMotorTorque;
float32 m_motorSpeed;
bool m_enableLimit;
float32 m_referenceAngle;
float32 m_lowerAngle;
float32 m_upperAngle;
b2LimitState m_limitState;
};
inline float32 b2RevoluteJoint::GetMotorSpeed() const
{
return m_motorSpeed;
}
#endif

View file

@ -1,33 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "b2Settings.h"
#include <cstdlib>
b2Version b2_version = {2, 1, 2};
// Memory allocators. Modify these to use your own allocator.
void* b2Alloc(int32 size)
{
return malloc(size);
}
void b2Free(void* mem)
{
free(mem);
}

View file

@ -1,95 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_SHAPE_H
#define B2_SHAPE_H
#include "b2BlockAllocator.h"
#include "b2Math.h"
#include "b2Collision.h"
/// This holds the mass data computed for a shape.
struct b2MassData
{
/// The mass of the shape, usually in kilograms.
float32 mass;
/// The position of the shape's centroid relative to the shape's origin.
b2Vec2 center;
/// The rotational inertia of the shape about the local origin.
float32 I;
};
/// A shape is used for collision detection. You can create a shape however you like.
/// Shapes used for simulation in b2World are created automatically when a b2Fixture
/// is created.
class b2Shape
{
public:
enum Type
{
e_unknown= -1,
e_circle = 0,
e_polygon = 1,
e_typeCount = 2,
};
b2Shape() { m_type = e_unknown; }
virtual ~b2Shape() {}
/// Clone the concrete shape using the provided allocator.
virtual b2Shape* Clone(b2BlockAllocator* allocator) const = 0;
/// Get the type of this shape. You can use this to down cast to the concrete shape.
/// @return the shape type.
Type GetType() const;
/// Test a point for containment in this shape. This only works for convex shapes.
/// @param xf the shape world transform.
/// @param p a point in world coordinates.
virtual bool TestPoint(const b2Transform& xf, const b2Vec2& p) const = 0;
/// Cast a ray against this shape.
/// @param output the ray-cast results.
/// @param input the ray-cast input parameters.
/// @param transform the transform to be applied to the shape.
virtual bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, const b2Transform& transform) const = 0;
/// Given a transform, compute the associated axis aligned bounding box for this shape.
/// @param aabb returns the axis aligned box.
/// @param xf the world transform of the shape.
virtual void ComputeAABB(b2AABB* aabb, const b2Transform& xf) const = 0;
/// Compute the mass properties of this shape using its dimensions and density.
/// The inertia tensor is computed about the local origin.
/// @param massData returns the mass data for this shape.
/// @param density the density in kilograms per meter squared.
virtual void ComputeMass(b2MassData* massData, float32 density) const = 0;
Type m_type;
float32 m_radius;
};
inline b2Shape::Type b2Shape::GetType() const
{
return m_type;
}
#endif

View file

@ -1,83 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "b2StackAllocator.h"
#include "b2Math.h"
b2StackAllocator::b2StackAllocator()
{
m_index = 0;
m_allocation = 0;
m_maxAllocation = 0;
m_entryCount = 0;
}
b2StackAllocator::~b2StackAllocator()
{
b2Assert(m_index == 0);
b2Assert(m_entryCount == 0);
}
void* b2StackAllocator::Allocate(int32 size)
{
b2Assert(m_entryCount < b2_maxStackEntries);
b2StackEntry* entry = m_entries + m_entryCount;
entry->size = size;
if (m_index + size > b2_stackSize)
{
entry->data = (char*)b2Alloc(size);
entry->usedMalloc = true;
}
else
{
entry->data = m_data + m_index;
entry->usedMalloc = false;
m_index += size;
}
m_allocation += size;
m_maxAllocation = b2Max(m_maxAllocation, m_allocation);
++m_entryCount;
return entry->data;
}
void b2StackAllocator::Free(void* p)
{
b2Assert(m_entryCount > 0);
b2StackEntry* entry = m_entries + m_entryCount - 1;
b2Assert(p == entry->data);
if (entry->usedMalloc)
{
b2Free(p);
}
else
{
m_index -= entry->size;
}
m_allocation -= entry->size;
--m_entryCount;
p = NULL;
}
int32 b2StackAllocator::GetMaxAllocation() const
{
return m_maxAllocation;
}

View file

@ -1,60 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_STACK_ALLOCATOR_H
#define B2_STACK_ALLOCATOR_H
#include "b2Settings.h"
const int32 b2_stackSize = 100 * 1024; // 100k
const int32 b2_maxStackEntries = 32;
struct b2StackEntry
{
char* data;
int32 size;
bool usedMalloc;
};
// This is a stack allocator used for fast per step allocations.
// You must nest allocate/free pairs. The code will assert
// if you try to interleave multiple allocate/free pairs.
class b2StackAllocator
{
public:
b2StackAllocator();
~b2StackAllocator();
void* Allocate(int32 size);
void Free(void* p);
int32 GetMaxAllocation() const;
private:
char m_data[b2_stackSize];
int32 m_index;
int32 m_allocation;
int32 m_maxAllocation;
b2StackEntry m_entries[b2_maxStackEntries];
int32 m_entryCount;
};
#endif

View file

@ -1,231 +0,0 @@
/*
* Copyright (c) 2006-2010 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "b2TOISolver.h"
#include "b2Contact.h"
#include "b2Body.h"
#include "b2Fixture.h"
#include "b2StackAllocator.h"
struct b2TOIConstraint
{
b2Vec2 localPoints[b2_maxManifoldPoints];
b2Vec2 localNormal;
b2Vec2 localPoint;
b2Manifold::Type type;
float32 radius;
int32 pointCount;
b2Body* bodyA;
b2Body* bodyB;
};
b2TOISolver::b2TOISolver(b2StackAllocator* allocator)
{
m_allocator = allocator;
m_constraints = NULL;
m_count = NULL;
m_toiBody = NULL;
}
b2TOISolver::~b2TOISolver()
{
Clear();
}
void b2TOISolver::Clear()
{
if (m_allocator && m_constraints)
{
m_allocator->Free(m_constraints);
m_constraints = NULL;
}
}
void b2TOISolver::Initialize(b2Contact** contacts, int32 count, b2Body* toiBody)
{
Clear();
m_count = count;
m_toiBody = toiBody;
m_constraints = (b2TOIConstraint*) m_allocator->Allocate(m_count * sizeof(b2TOIConstraint));
for (int32 i = 0; i < m_count; ++i)
{
b2Contact* contact = contacts[i];
b2Fixture* fixtureA = contact->GetFixtureA();
b2Fixture* fixtureB = contact->GetFixtureB();
b2Shape* shapeA = fixtureA->GetShape();
b2Shape* shapeB = fixtureB->GetShape();
float32 radiusA = shapeA->m_radius;
float32 radiusB = shapeB->m_radius;
b2Body* bodyA = fixtureA->GetBody();
b2Body* bodyB = fixtureB->GetBody();
b2Manifold* manifold = contact->GetManifold();
b2Assert(manifold->pointCount > 0);
b2TOIConstraint* constraint = m_constraints + i;
constraint->bodyA = bodyA;
constraint->bodyB = bodyB;
constraint->localNormal = manifold->localNormal;
constraint->localPoint = manifold->localPoint;
constraint->type = manifold->type;
constraint->pointCount = manifold->pointCount;
constraint->radius = radiusA + radiusB;
for (int32 j = 0; j < constraint->pointCount; ++j)
{
b2ManifoldPoint* cp = manifold->points + j;
constraint->localPoints[j] = cp->localPoint;
}
}
}
struct b2TOISolverManifold
{
void Initialize(b2TOIConstraint* cc, int32 index)
{
b2Assert(cc->pointCount > 0);
switch (cc->type)
{
case b2Manifold::e_circles:
{
b2Vec2 pointA = cc->bodyA->GetWorldPoint(cc->localPoint);
b2Vec2 pointB = cc->bodyB->GetWorldPoint(cc->localPoints[0]);
if (b2DistanceSquared(pointA, pointB) > b2_epsilon * b2_epsilon)
{
normal = pointB - pointA;
normal.Normalize();
}
else
{
normal.Set(1.0f, 0.0f);
}
point = 0.5f * (pointA + pointB);
separation = b2Dot(pointB - pointA, normal) - cc->radius;
}
break;
case b2Manifold::e_faceA:
{
normal = cc->bodyA->GetWorldVector(cc->localNormal);
b2Vec2 planePoint = cc->bodyA->GetWorldPoint(cc->localPoint);
b2Vec2 clipPoint = cc->bodyB->GetWorldPoint(cc->localPoints[index]);
separation = b2Dot(clipPoint - planePoint, normal) - cc->radius;
point = clipPoint;
}
break;
case b2Manifold::e_faceB:
{
normal = cc->bodyB->GetWorldVector(cc->localNormal);
b2Vec2 planePoint = cc->bodyB->GetWorldPoint(cc->localPoint);
b2Vec2 clipPoint = cc->bodyA->GetWorldPoint(cc->localPoints[index]);
separation = b2Dot(clipPoint - planePoint, normal) - cc->radius;
point = clipPoint;
// Ensure normal points from A to B
normal = -normal;
}
break;
}
}
b2Vec2 normal;
b2Vec2 point;
float32 separation;
};
// Push out the toi body to provide clearance for further simulation.
bool b2TOISolver::Solve(float32 baumgarte)
{
float32 minSeparation = 0.0f;
for (int32 i = 0; i < m_count; ++i)
{
b2TOIConstraint* c = m_constraints + i;
b2Body* bodyA = c->bodyA;
b2Body* bodyB = c->bodyB;
float32 massA = bodyA->m_mass;
float32 massB = bodyB->m_mass;
// Only the TOI body should move.
if (bodyA == m_toiBody)
{
massB = 0.0f;
}
else
{
massA = 0.0f;
}
float32 invMassA = massA * bodyA->m_invMass;
float32 invIA = massA * bodyA->m_invI;
float32 invMassB = massB * bodyB->m_invMass;
float32 invIB = massB * bodyB->m_invI;
// Solve normal constraints
for (int32 j = 0; j < c->pointCount; ++j)
{
b2TOISolverManifold psm;
psm.Initialize(c, j);
b2Vec2 normal = psm.normal;
b2Vec2 point = psm.point;
float32 separation = psm.separation;
b2Vec2 rA = point - bodyA->m_sweep.c;
b2Vec2 rB = point - bodyB->m_sweep.c;
// Track max constraint error.
minSeparation = b2Min(minSeparation, separation);
// Prevent large corrections and allow slop.
float32 C = b2Clamp(baumgarte * (separation + b2_linearSlop), -b2_maxLinearCorrection, 0.0f);
// Compute the effective mass.
float32 rnA = b2Cross(rA, normal);
float32 rnB = b2Cross(rB, normal);
float32 K = invMassA + invMassB + invIA * rnA * rnA + invIB * rnB * rnB;
// Compute normal impulse
float32 impulse = K > 0.0f ? - C / K : 0.0f;
b2Vec2 P = impulse * normal;
bodyA->m_sweep.c -= invMassA * P;
bodyA->m_sweep.a -= invIA * b2Cross(rA, P);
bodyA->SynchronizeTransform();
bodyB->m_sweep.c += invMassB * P;
bodyB->m_sweep.a += invIB * b2Cross(rB, P);
bodyB->SynchronizeTransform();
}
}
// We can't expect minSpeparation >= -b2_linearSlop because we don't
// push the separation above -b2_linearSlop.
return minSeparation >= -1.5f * b2_linearSlop;
}

View file

@ -1,51 +0,0 @@
/*
* Copyright (c) 2006-2010 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_TOI_SOLVER_H
#define B2_TOI_SOLVER_H
#include "b2Math.h"
class b2Contact;
class b2Body;
struct b2TOIConstraint;
class b2StackAllocator;
/// This is a pure position solver for a single movable body in contact with
/// multiple non-moving bodies.
class b2TOISolver
{
public:
b2TOISolver(b2StackAllocator* allocator);
~b2TOISolver();
void Initialize(b2Contact** contacts, int32 contactCount, b2Body* toiBody);
void Clear();
// Perform one solver iteration. Returns true if converged.
bool Solve(float32 baumgarte);
private:
b2TOIConstraint* m_constraints;
int32 m_count;
b2Body* m_toiBody;
b2StackAllocator* m_allocator;
};
#endif

View file

@ -1,59 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_TIME_OF_IMPACT_H
#define B2_TIME_OF_IMPACT_H
#include "b2Math.h"
#include "b2Distance.h"
#include <climits>
/// Input parameters for b2TimeOfImpact
struct b2TOIInput
{
b2DistanceProxy proxyA;
b2DistanceProxy proxyB;
b2Sweep sweepA;
b2Sweep sweepB;
float32 tMax; // defines sweep interval [0, tMax]
};
// Output parameters for b2TimeOfImpact.
struct b2TOIOutput
{
enum State
{
e_unknown,
e_failed,
e_overlapped,
e_touching,
e_separated
};
State state;
float32 t;
};
/// Compute the upper bound on time before two shapes penetrate. Time is represented as
/// a fraction between [0,tMax]. This uses a swept separating axis and may miss some intermediate,
/// non-tunneling collision. If you change the time interval, you should call this function
/// again.
/// Note: use b2Distance to compute the contact point and normal at the time of impact.
void b2TimeOfImpact(b2TOIOutput* output, const b2TOIInput* input);
#endif

View file

@ -1,35 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_TIME_STEP_H
#define B2_TIME_STEP_H
#include "b2Settings.h"
/// This is an internal structure.
struct b2TimeStep
{
float32 dt; // time step
float32 inv_dt; // inverse time step (0 if dt == 0).
float32 dtRatio; // dt * inv_dt0
int32 velocityIterations;
int32 positionIterations;
bool warmStarting;
};
#endif

View file

@ -1,219 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "b2WeldJoint.h"
#include "b2Body.h"
#include "b2TimeStep.h"
// Point-to-point constraint
// C = p2 - p1
// Cdot = v2 - v1
// = v2 + cross(w2, r2) - v1 - cross(w1, r1)
// J = [-I -r1_skew I r2_skew ]
// Identity used:
// w k % (rx i + ry j) = w * (-ry i + rx j)
// Angle constraint
// C = angle2 - angle1 - referenceAngle
// Cdot = w2 - w1
// J = [0 0 -1 0 0 1]
// K = invI1 + invI2
void b2WeldJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor)
{
bodyA = bA;
bodyB = bB;
localAnchorA = bodyA->GetLocalPoint(anchor);
localAnchorB = bodyB->GetLocalPoint(anchor);
referenceAngle = bodyB->GetAngle() - bodyA->GetAngle();
}
b2WeldJoint::b2WeldJoint(const b2WeldJointDef* def)
: b2Joint(def)
{
m_localAnchorA = def->localAnchorA;
m_localAnchorB = def->localAnchorB;
m_referenceAngle = def->referenceAngle;
m_impulse.SetZero();
}
void b2WeldJoint::InitVelocityConstraints(const b2TimeStep& step)
{
b2Body* bA = m_bodyA;
b2Body* bB = m_bodyB;
// Compute the effective mass matrix.
b2Vec2 rA = b2Mul(bA->GetTransform().R, m_localAnchorA - bA->GetLocalCenter());
b2Vec2 rB = b2Mul(bB->GetTransform().R, m_localAnchorB - bB->GetLocalCenter());
// J = [-I -r1_skew I r2_skew]
// [ 0 -1 0 1]
// r_skew = [-ry; rx]
// Matlab
// K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB]
// [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB]
// [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB]
float32 mA = bA->m_invMass, mB = bB->m_invMass;
float32 iA = bA->m_invI, iB = bB->m_invI;
m_mass.col1.x = mA + mB + rA.y * rA.y * iA + rB.y * rB.y * iB;
m_mass.col2.x = -rA.y * rA.x * iA - rB.y * rB.x * iB;
m_mass.col3.x = -rA.y * iA - rB.y * iB;
m_mass.col1.y = m_mass.col2.x;
m_mass.col2.y = mA + mB + rA.x * rA.x * iA + rB.x * rB.x * iB;
m_mass.col3.y = rA.x * iA + rB.x * iB;
m_mass.col1.z = m_mass.col3.x;
m_mass.col2.z = m_mass.col3.y;
m_mass.col3.z = iA + iB;
if (step.warmStarting)
{
// Scale impulses to support a variable time step.
m_impulse *= step.dtRatio;
b2Vec2 P(m_impulse.x, m_impulse.y);
bA->m_linearVelocity -= mA * P;
bA->m_angularVelocity -= iA * (b2Cross(rA, P) + m_impulse.z);
bB->m_linearVelocity += mB * P;
bB->m_angularVelocity += iB * (b2Cross(rB, P) + m_impulse.z);
}
else
{
m_impulse.SetZero();
}
}
void b2WeldJoint::SolveVelocityConstraints(const b2TimeStep& step)
{
B2_NOT_USED(step);
b2Body* bA = m_bodyA;
b2Body* bB = m_bodyB;
b2Vec2 vA = bA->m_linearVelocity;
float32 wA = bA->m_angularVelocity;
b2Vec2 vB = bB->m_linearVelocity;
float32 wB = bB->m_angularVelocity;
float32 mA = bA->m_invMass, mB = bB->m_invMass;
float32 iA = bA->m_invI, iB = bB->m_invI;
b2Vec2 rA = b2Mul(bA->GetTransform().R, m_localAnchorA - bA->GetLocalCenter());
b2Vec2 rB = b2Mul(bB->GetTransform().R, m_localAnchorB - bB->GetLocalCenter());
// Solve point-to-point constraint
b2Vec2 Cdot1 = vB + b2Cross(wB, rB) - vA - b2Cross(wA, rA);
float32 Cdot2 = wB - wA;
b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2);
b2Vec3 impulse = m_mass.Solve33(-Cdot);
m_impulse += impulse;
b2Vec2 P(impulse.x, impulse.y);
vA -= mA * P;
wA -= iA * (b2Cross(rA, P) + impulse.z);
vB += mB * P;
wB += iB * (b2Cross(rB, P) + impulse.z);
bA->m_linearVelocity = vA;
bA->m_angularVelocity = wA;
bB->m_linearVelocity = vB;
bB->m_angularVelocity = wB;
}
bool b2WeldJoint::SolvePositionConstraints(float32 baumgarte)
{
B2_NOT_USED(baumgarte);
b2Body* bA = m_bodyA;
b2Body* bB = m_bodyB;
float32 mA = bA->m_invMass, mB = bB->m_invMass;
float32 iA = bA->m_invI, iB = bB->m_invI;
b2Vec2 rA = b2Mul(bA->GetTransform().R, m_localAnchorA - bA->GetLocalCenter());
b2Vec2 rB = b2Mul(bB->GetTransform().R, m_localAnchorB - bB->GetLocalCenter());
b2Vec2 C1 = bB->m_sweep.c + rB - bA->m_sweep.c - rA;
float32 C2 = bB->m_sweep.a - bA->m_sweep.a - m_referenceAngle;
// Handle large detachment.
const float32 k_allowedStretch = 10.0f * b2_linearSlop;
float32 positionError = C1.Length();
float32 angularError = b2Abs(C2);
if (positionError > k_allowedStretch)
{
iA *= 1.0f;
iB *= 1.0f;
}
m_mass.col1.x = mA + mB + rA.y * rA.y * iA + rB.y * rB.y * iB;
m_mass.col2.x = -rA.y * rA.x * iA - rB.y * rB.x * iB;
m_mass.col3.x = -rA.y * iA - rB.y * iB;
m_mass.col1.y = m_mass.col2.x;
m_mass.col2.y = mA + mB + rA.x * rA.x * iA + rB.x * rB.x * iB;
m_mass.col3.y = rA.x * iA + rB.x * iB;
m_mass.col1.z = m_mass.col3.x;
m_mass.col2.z = m_mass.col3.y;
m_mass.col3.z = iA + iB;
b2Vec3 C(C1.x, C1.y, C2);
b2Vec3 impulse = m_mass.Solve33(-C);
b2Vec2 P(impulse.x, impulse.y);
bA->m_sweep.c -= mA * P;
bA->m_sweep.a -= iA * (b2Cross(rA, P) + impulse.z);
bB->m_sweep.c += mB * P;
bB->m_sweep.a += iB * (b2Cross(rB, P) + impulse.z);
bA->SynchronizeTransform();
bB->SynchronizeTransform();
return positionError <= b2_linearSlop && angularError <= b2_angularSlop;
}
b2Vec2 b2WeldJoint::GetAnchorA() const
{
return m_bodyA->GetWorldPoint(m_localAnchorA);
}
b2Vec2 b2WeldJoint::GetAnchorB() const
{
return m_bodyB->GetWorldPoint(m_localAnchorB);
}
b2Vec2 b2WeldJoint::GetReactionForce(float32 inv_dt) const
{
b2Vec2 P(m_impulse.x, m_impulse.y);
return inv_dt * P;
}
float32 b2WeldJoint::GetReactionTorque(float32 inv_dt) const
{
return inv_dt * m_impulse.z;
}

View file

@ -1,82 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_WELD_JOINT_H
#define B2_WELD_JOINT_H
#include "b2Joint.h"
/// Weld joint definition. You need to specify local anchor points
/// where they are attached and the relative body angle. The position
/// of the anchor points is important for computing the reaction torque.
struct b2WeldJointDef : public b2JointDef
{
b2WeldJointDef()
{
type = e_weldJoint;
localAnchorA.Set(0.0f, 0.0f);
localAnchorB.Set(0.0f, 0.0f);
referenceAngle = 0.0f;
}
/// Initialize the bodies, anchors, and reference angle using a world
/// anchor point.
void Initialize(b2Body* body1, b2Body* body2, const b2Vec2& anchor);
/// The local anchor point relative to body1's origin.
b2Vec2 localAnchorA;
/// The local anchor point relative to body2's origin.
b2Vec2 localAnchorB;
/// The body2 angle minus body1 angle in the reference state (radians).
float32 referenceAngle;
};
/// A weld joint essentially glues two bodies together. A weld joint may
/// distort somewhat because the island constraint solver is approximate.
class b2WeldJoint : public b2Joint
{
public:
b2Vec2 GetAnchorA() const;
b2Vec2 GetAnchorB() const;
b2Vec2 GetReactionForce(float32 inv_dt) const;
float32 GetReactionTorque(float32 inv_dt) const;
protected:
friend class b2Joint;
b2WeldJoint(const b2WeldJointDef* def);
void InitVelocityConstraints(const b2TimeStep& step);
void SolveVelocityConstraints(const b2TimeStep& step);
bool SolvePositionConstraints(float32 baumgarte);
b2Vec2 m_localAnchorA;
b2Vec2 m_localAnchorB;
float32 m_referenceAngle;
b2Vec3 m_impulse;
b2Mat33 m_mass;
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,61 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "b2WorldCallbacks.h"
#include "b2Fixture.h"
// Return true if contact calculations should be performed between these two shapes.
// If you implement your own collision filter you may want to build from this implementation.
bool b2ContactFilter::ShouldCollide(b2Fixture* fixtureA, b2Fixture* fixtureB)
{
const b2Filter& filterA = fixtureA->GetFilterData();
const b2Filter& filterB = fixtureB->GetFilterData();
if (filterA.groupIndex == filterB.groupIndex && filterA.groupIndex != 0)
{
return filterA.groupIndex > 0;
}
bool collide = (filterA.maskBits & filterB.categoryBits) != 0 && (filterA.categoryBits & filterB.maskBits) != 0;
return collide;
}
b2DebugDraw::b2DebugDraw()
{
m_drawFlags = 0;
}
void b2DebugDraw::SetFlags(uint32 flags)
{
m_drawFlags = flags;
}
uint32 b2DebugDraw::GetFlags() const
{
return m_drawFlags;
}
void b2DebugDraw::AppendFlags(uint32 flags)
{
m_drawFlags |= flags;
}
void b2DebugDraw::ClearFlags(uint32 flags)
{
m_drawFlags &= ~flags;
}

View file

@ -1,82 +1,110 @@
description "Box2D\3770,128,128";
include
include,
src;
file
Box2D.h,
Collision readonly separator,
b2BroadPhase.cpp,
b2BroadPhase.h,
b2CollideCircle.cpp,
b2CollidePolygon.cpp,
b2Collision.cpp,
b2Collision.h,
b2Distance.cpp,
b2Distance.h,
b2DynamicTree.cpp,
b2DynamicTree.h,
b2TimeOfImpact.cpp,
b2TimeOfImpact.h,
Shapes readonly separator,
b2CircleShape.cpp,
b2CircleShape.h,
b2PolygonShape.cpp,
b2PolygonShape.h,
b2Shape.h,
Include readonly separator,
include/box2d/b2_api.h,
include/box2d/b2_block_allocator.h,
include/box2d/b2_body.h,
include/box2d/b2_broad_phase.h,
include/box2d/b2_chain_shape.h,
include/box2d/b2_circle_shape.h,
include/box2d/b2_collision.h,
include/box2d/b2_common.h,
include/box2d/b2_contact.h,
include/box2d/b2_contact_manager.h,
include/box2d/b2_distance.h,
include/box2d/b2_distance_joint.h,
include/box2d/b2_draw.h,
include/box2d/b2_dynamic_tree.h,
include/box2d/b2_edge_shape.h,
include/box2d/b2_fixture.h,
include/box2d/b2_friction_joint.h,
include/box2d/b2_gear_joint.h,
include/box2d/b2_growable_stack.h,
include/box2d/b2_joint.h,
include/box2d/b2_math.h,
include/box2d/b2_motor_joint.h,
include/box2d/b2_mouse_joint.h,
include/box2d/b2_polygon_shape.h,
include/box2d/b2_prismatic_joint.h,
include/box2d/b2_pulley_joint.h,
include/box2d/b2_revolute_joint.h,
include/box2d/b2_rope.h,
include/box2d/b2_settings.h,
include/box2d/b2_shape.h,
include/box2d/b2_stack_allocator.h,
include/box2d/b2_time_of_impact.h,
include/box2d/b2_time_step.h,
include/box2d/b2_timer.h,
include/box2d/b2_types.h,
include/box2d/b2_weld_joint.h,
include/box2d/b2_wheel_joint.h,
include/box2d/b2_world.h,
include/box2d/b2_world_callbacks.h,
include/box2d/box2d.h,
Common readonly separator,
b2BlockAllocator.cpp,
b2BlockAllocator.h,
b2Math.cpp,
b2Math.h,
b2Settings.cpp,
b2Settings.h,
b2StackAllocator.cpp,
b2StackAllocator.h,
src/common/b2_block_allocator.cpp,
src/common/b2_draw.cpp,
src/common/b2_math.cpp,
src/common/b2_settings.cpp,
src/common/b2_stack_allocator.cpp,
src/common/b2_timer.cpp,
Collision readonly separator,
src/collision/b2_broad_phase.cpp,
src/collision/b2_chain_shape.cpp,
src/collision/b2_circle_shape.cpp,
src/collision/b2_collide_circle.cpp,
src/collision/b2_collide_edge.cpp,
src/collision/b2_collide_polygon.cpp,
src/collision/b2_collision.cpp,
src/collision/b2_distance.cpp,
src/collision/b2_dynamic_tree.cpp,
src/collision/b2_edge_shape.cpp,
src/collision/b2_polygon_shape.cpp,
src/collision/b2_time_of_impact.cpp,
Dynamics readonly separator,
b2Body.cpp,
b2Body.h,
b2ContactManager.cpp,
b2ContactManager.h,
b2Fixture.cpp,
b2Fixture.h,
b2Island.cpp,
b2Island.h,
b2TimeStep.h,
b2World.cpp,
b2World.h,
b2WorldCallbacks.cpp,
b2WorldCallbacks.h,
Contacts readonly separator,
b2CircleContact.cpp,
b2CircleContact.h,
b2Contact.cpp,
b2Contact.h,
b2ContactSolver.cpp,
b2ContactSolver.h,
b2PolygonAndCircleContact.cpp,
b2PolygonAndCircleContact.h,
b2PolygonContact.cpp,
b2PolygonContact.h,
b2TOISolver.cpp,
b2TOISolver.h,
Joints readonly separator,
b2DistanceJoint.cpp,
b2DistanceJoint.h,
b2FrictionJoint.cpp,
b2FrictionJoint.h,
b2GearJoint.cpp,
b2GearJoint.h,
b2Joint.cpp,
b2Joint.h,
b2LineJoint.cpp,
b2LineJoint.h,
b2MouseJoint.cpp,
b2MouseJoint.h,
b2PrismaticJoint.cpp,
b2PrismaticJoint.h,
b2PulleyJoint.cpp,
b2PulleyJoint.h,
b2RevoluteJoint.cpp,
b2RevoluteJoint.h,
b2WeldJoint.cpp,
b2WeldJoint.h,
Copying;
src/dynamics/b2_body.cpp,
src/dynamics/b2_chain_circle_contact.cpp,
src/dynamics/b2_chain_circle_contact.h,
src/dynamics/b2_chain_polygon_contact.cpp,
src/dynamics/b2_chain_polygon_contact.h,
src/dynamics/b2_circle_contact.cpp,
src/dynamics/b2_circle_contact.h,
src/dynamics/b2_contact.cpp,
src/dynamics/b2_contact_manager.cpp,
src/dynamics/b2_contact_solver.cpp,
src/dynamics/b2_contact_solver.h,
src/dynamics/b2_distance_joint.cpp,
src/dynamics/b2_edge_circle_contact.cpp,
src/dynamics/b2_edge_circle_contact.h,
src/dynamics/b2_edge_polygon_contact.cpp,
src/dynamics/b2_edge_polygon_contact.h,
src/dynamics/b2_fixture.cpp,
src/dynamics/b2_friction_joint.cpp,
src/dynamics/b2_gear_joint.cpp,
src/dynamics/b2_island.cpp,
src/dynamics/b2_island.h,
src/dynamics/b2_joint.cpp,
src/dynamics/b2_motor_joint.cpp,
src/dynamics/b2_mouse_joint.cpp,
src/dynamics/b2_polygon_circle_contact.cpp,
src/dynamics/b2_polygon_circle_contact.h,
src/dynamics/b2_polygon_contact.cpp,
src/dynamics/b2_polygon_contact.h,
src/dynamics/b2_prismatic_joint.cpp,
src/dynamics/b2_pulley_joint.cpp,
src/dynamics/b2_revolute_joint.cpp,
src/dynamics/b2_weld_joint.cpp,
src/dynamics/b2_wheel_joint.cpp,
src/dynamics/b2_world.cpp,
src/dynamics/b2_world_callbacks.cpp,
Rope readonly separator,
src/rope/b2_rope.cpp,
License readonly separator,
LICENSE;

View file

@ -1,29 +0,0 @@
@files = glob("*.cpp *.h");
foreach $f (@files)
{
print("Processing $f\n");
open(IN, "<$f");
@file = <IN>;
close(IN);
open(IN, ">$f");
foreach $line (@file) {
if($line =~ /(\<Box2D[\w\d\_\/\.]+\>)/) {
$oi = $1;
if($oi =~ /([\w\d\_]+\.h)/)
{
$ni = "\"$1\"";
$line =~ s/$oi/$ni/g;
}
print "$line";
}
print IN $line;
}
close IN;
}

View file

@ -0,0 +1,52 @@
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_API_H
#define B2_API_H
#ifdef B2_SHARED
#if defined _WIN32 || defined __CYGWIN__
#ifdef box2d_EXPORTS
#ifdef __GNUC__
#define B2_API __attribute__ ((dllexport))
#else
#define B2_API __declspec(dllexport)
#endif
#else
#ifdef __GNUC__
#define B2_API __attribute__ ((dllimport))
#else
#define B2_API __declspec(dllimport)
#endif
#endif
#else
#if __GNUC__ >= 4
#define B2_API __attribute__ ((visibility ("default")))
#else
#define B2_API
#endif
#endif
#else
#define B2_API
#endif
#endif

View file

@ -0,0 +1,60 @@
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_BLOCK_ALLOCATOR_H
#define B2_BLOCK_ALLOCATOR_H
#include "b2_api.h"
#include "b2_settings.h"
const int32 b2_blockSizeCount = 14;
struct b2Block;
struct b2Chunk;
/// This is a small object allocator used for allocating small
/// objects that persist for more than one time step.
/// See: http://www.codeproject.com/useritems/Small_Block_Allocator.asp
class B2_API b2BlockAllocator
{
public:
b2BlockAllocator();
~b2BlockAllocator();
/// Allocate memory. This will use b2Alloc if the size is larger than b2_maxBlockSize.
void* Allocate(int32 size);
/// Free memory. This will use b2Free if the size is larger than b2_maxBlockSize.
void Free(void* p, int32 size);
void Clear();
private:
b2Chunk* m_chunks;
int32 m_chunkCount;
int32 m_chunkSpace;
b2Block* m_freeLists[b2_blockSizeCount];
};
#endif

View file

@ -1,27 +1,31 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_BODY_H
#define B2_BODY_H
#include "b2Math.h"
#include "b2Shape.h"
#include <memory>
#include "b2_api.h"
#include "b2_math.h"
#include "b2_shape.h"
class b2Fixture;
class b2Joint;
@ -40,17 +44,16 @@ enum b2BodyType
{
b2_staticBody = 0,
b2_kinematicBody,
b2_dynamicBody,
b2_dynamicBody
};
/// A body definition holds all the data needed to construct a rigid body.
/// You can safely re-use body definitions. Shapes are added to a body after construction.
struct b2BodyDef
struct B2_API b2BodyDef
{
/// This constructor sets the body definition default values.
b2BodyDef()
{
userData = NULL;
position.Set(0.0f, 0.0f);
angle = 0.0f;
linearVelocity.Set(0.0f, 0.0f);
@ -62,8 +65,8 @@ struct b2BodyDef
fixedRotation = false;
bullet = false;
type = b2_staticBody;
active = true;
inertiaScale = 1.0f;
enabled = true;
gravityScale = 1.0f;
}
/// The body type: static, kinematic, or dynamic.
@ -75,23 +78,25 @@ struct b2BodyDef
b2Vec2 position;
/// The world angle of the body in radians.
float32 angle;
float angle;
/// The linear velocity of the body's origin in world co-ordinates.
b2Vec2 linearVelocity;
/// The angular velocity of the body.
float32 angularVelocity;
float angularVelocity;
/// Linear damping is use to reduce the linear velocity. The damping parameter
/// can be larger than 1.0f but the damping effect becomes sensitive to the
/// time step when the damping parameter is large.
float32 linearDamping;
/// Units are 1/time
float linearDamping;
/// Angular damping is use to reduce the angular velocity. The damping parameter
/// can be larger than 1.0f but the damping effect becomes sensitive to the
/// time step when the damping parameter is large.
float32 angularDamping;
/// Units are 1/time
float angularDamping;
/// Set this flag to false if this body should never fall asleep. Note that
/// this increases CPU usage.
@ -109,18 +114,18 @@ struct b2BodyDef
/// @warning You should use this flag sparingly since it increases processing time.
bool bullet;
/// Does this body start out active?
bool active;
/// Does this body start out enabled?
bool enabled;
/// Use this to store application specific body data.
void* userData;
b2BodyUserData userData;
/// Experimental: scales the inertia tensor.
float32 inertiaScale;
/// Scale the gravity applied to this body.
float gravityScale;
};
/// A rigid body. These are created via b2World::CreateBody.
class b2Body
class B2_API b2Body
{
public:
/// Creates a fixture and attach it to this body. Use this function if you need
@ -139,7 +144,7 @@ public:
/// @param shape the shape to be cloned.
/// @param density the shape density (set to zero for static bodies).
/// @warning This function is locked during callbacks.
b2Fixture* CreateFixture(const b2Shape* shape, float32 density);
b2Fixture* CreateFixture(const b2Shape* shape, float density);
/// Destroy a fixture. This removes the fixture from the broad-phase and
/// destroys all contacts associated with this fixture. This will
@ -151,11 +156,11 @@ public:
void DestroyFixture(b2Fixture* fixture);
/// Set the position of the body's origin and rotation.
/// This breaks any contacts and wakes the other bodies.
/// Manipulating a body's transform may cause non-physical behavior.
/// Note: contacts are updated on the next call to b2World::Step.
/// @param position the world position of the body's local origin.
/// @param angle the world rotation in radians.
void SetTransform(const b2Vec2& position, float32 angle);
void SetTransform(const b2Vec2& position, float angle);
/// Get the body transform for the body's origin.
/// @return the world transform of the body's origin.
@ -167,7 +172,7 @@ public:
/// Get the angle in radians.
/// @return the current world rotation angle in radians.
float32 GetAngle() const;
float GetAngle() const;
/// Get the world position of the center of mass.
const b2Vec2& GetWorldCenter() const;
@ -181,47 +186,60 @@ public:
/// Get the linear velocity of the center of mass.
/// @return the linear velocity of the center of mass.
b2Vec2 GetLinearVelocity() const;
const b2Vec2& GetLinearVelocity() const;
/// Set the angular velocity.
/// @param omega the new angular velocity in radians/second.
void SetAngularVelocity(float32 omega);
void SetAngularVelocity(float omega);
/// Get the angular velocity.
/// @return the angular velocity in radians/second.
float32 GetAngularVelocity() const;
float GetAngularVelocity() const;
/// Apply a force at a world point. If the force is not
/// applied at the center of mass, it will generate a torque and
/// affect the angular velocity. This wakes up the body.
/// @param force the world force vector, usually in Newtons (N).
/// @param point the world position of the point of application.
void ApplyForce(const b2Vec2& force, const b2Vec2& point);
/// @param wake also wake up the body
void ApplyForce(const b2Vec2& force, const b2Vec2& point, bool wake);
/// Apply a force to the center of mass. This wakes up the body.
/// @param force the world force vector, usually in Newtons (N).
/// @param wake also wake up the body
void ApplyForceToCenter(const b2Vec2& force, bool wake);
/// Apply a torque. This affects the angular velocity
/// without affecting the linear velocity of the center of mass.
/// This wakes up the body.
/// @param torque about the z-axis (out of the screen), usually in N-m.
void ApplyTorque(float32 torque);
/// @param wake also wake up the body
void ApplyTorque(float torque, bool wake);
/// Apply an impulse at a point. This immediately modifies the velocity.
/// It also modifies the angular velocity if the point of application
/// is not at the center of mass. This wakes up the body.
/// @param impulse the world impulse vector, usually in N-seconds or kg-m/s.
/// @param point the world position of the point of application.
void ApplyLinearImpulse(const b2Vec2& impulse, const b2Vec2& point);
/// @param wake also wake up the body
void ApplyLinearImpulse(const b2Vec2& impulse, const b2Vec2& point, bool wake);
/// Apply an impulse to the center of mass. This immediately modifies the velocity.
/// @param impulse the world impulse vector, usually in N-seconds or kg-m/s.
/// @param wake also wake up the body
void ApplyLinearImpulseToCenter(const b2Vec2& impulse, bool wake);
/// Apply an angular impulse.
/// @param impulse the angular impulse in units of kg*m*m/s
void ApplyAngularImpulse(float32 impulse);
/// @param wake also wake up the body
void ApplyAngularImpulse(float impulse, bool wake);
/// Get the total mass of the body.
/// @return the mass, usually in kilograms (kg).
float32 GetMass() const;
float GetMass() const;
/// Get the rotational inertia of the body about the local origin.
/// @return the rotational inertia, usually in kg-m^2.
float32 GetInertia() const;
float GetInertia() const;
/// Get the mass data of the body.
/// @return a struct containing the mass, inertia and center of the body.
@ -231,7 +249,7 @@ public:
/// Note that this changes the center of mass position.
/// Note that creating or destroying fixtures can also alter the mass.
/// This function has no effect if the body isn't dynamic.
/// @param massData the mass properties.
/// @param data the mass properties.
void SetMassData(const b2MassData* data);
/// This resets the mass properties to the sum of the mass properties of the fixtures.
@ -250,36 +268,42 @@ public:
b2Vec2 GetWorldVector(const b2Vec2& localVector) const;
/// Gets a local point relative to the body's origin given a world point.
/// @param a point in world coordinates.
/// @param worldPoint a point in world coordinates.
/// @return the corresponding local point relative to the body's origin.
b2Vec2 GetLocalPoint(const b2Vec2& worldPoint) const;
/// Gets a local vector given a world vector.
/// @param a vector in world coordinates.
/// @param worldVector a vector in world coordinates.
/// @return the corresponding local vector.
b2Vec2 GetLocalVector(const b2Vec2& worldVector) const;
/// Get the world linear velocity of a world point attached to this body.
/// @param a point in world coordinates.
/// @param worldPoint a point in world coordinates.
/// @return the world velocity of a point.
b2Vec2 GetLinearVelocityFromWorldPoint(const b2Vec2& worldPoint) const;
/// Get the world velocity of a local point.
/// @param a point in local coordinates.
/// @param localPoint a point in local coordinates.
/// @return the world velocity of a point.
b2Vec2 GetLinearVelocityFromLocalPoint(const b2Vec2& localPoint) const;
/// Get the linear damping of the body.
float32 GetLinearDamping() const;
float GetLinearDamping() const;
/// Set the linear damping of the body.
void SetLinearDamping(float32 linearDamping);
void SetLinearDamping(float linearDamping);
/// Get the angular damping of the body.
float32 GetAngularDamping() const;
float GetAngularDamping() const;
/// Set the angular damping of the body.
void SetAngularDamping(float32 angularDamping);
void SetAngularDamping(float angularDamping);
/// Get the gravity scale of the body.
float GetGravityScale() const;
/// Set the gravity scale of the body.
void SetGravityScale(float scale);
/// Set the type of this body. This may alter the mass and velocity.
void SetType(b2BodyType type);
@ -302,30 +326,29 @@ public:
/// Set the sleep state of the body. A sleeping body has very
/// low CPU cost.
/// @param flag set to true to put body to sleep, false to wake it.
/// @param flag set to true to wake the body, false to put it to sleep.
void SetAwake(bool flag);
/// Get the sleeping state of this body.
/// @return true if the body is sleeping.
/// @return true if the body is awake.
bool IsAwake() const;
/// Set the active state of the body. An inactive body is not
/// simulated and cannot be collided with or woken up.
/// If you pass a flag of true, all fixtures will be added to the
/// broad-phase.
/// If you pass a flag of false, all fixtures will be removed from
/// the broad-phase and all contacts will be destroyed.
/// Allow a body to be disabled. A disabled body is not simulated and cannot
/// be collided with or woken up.
/// If you pass a flag of true, all fixtures will be added to the broad-phase.
/// If you pass a flag of false, all fixtures will be removed from the
/// broad-phase and all contacts will be destroyed.
/// Fixtures and joints are otherwise unaffected. You may continue
/// to create/destroy fixtures and joints on inactive bodies.
/// Fixtures on an inactive body are implicitly inactive and will
/// to create/destroy fixtures and joints on disabled bodies.
/// Fixtures on a disabled body are implicitly disabled and will
/// not participate in collisions, ray-casts, or queries.
/// Joints connected to an inactive body are implicitly inactive.
/// An inactive body is still owned by a b2World object and remains
/// Joints connected to a disabled body are implicitly disabled.
/// An diabled body is still owned by a b2World object and remains
/// in the body list.
void SetActive(bool flag);
void SetEnabled(bool flag);
/// Get the active state of the body.
bool IsActive() const;
bool IsEnabled() const;
/// Set this body to have fixed rotation. This causes the mass
/// to be reset.
@ -353,32 +376,34 @@ public:
const b2Body* GetNext() const;
/// Get the user data pointer that was provided in the body definition.
void* GetUserData() const;
/// Set the user data. Use this to store your application specific data.
void SetUserData(void* data);
b2BodyUserData& GetUserData();
/// Get the parent world of this body.
b2World* GetWorld();
const b2World* GetWorld() const;
/// Dump this body to a file
void Dump();
private:
friend class b2World;
friend class b2Island;
friend class b2ContactManager;
friend class b2ContactSolver;
friend class b2TOISolver;
friend class b2Contact;
friend class b2DistanceJoint;
friend class b2FrictionJoint;
friend class b2GearJoint;
friend class b2LineJoint;
friend class b2MotorJoint;
friend class b2MouseJoint;
friend class b2PrismaticJoint;
friend class b2PulleyJoint;
friend class b2RevoluteJoint;
friend class b2RopeJoint;
friend class b2WeldJoint;
friend class b2FrictionJoint;
friend class b2WheelJoint;
// m_flags
enum
@ -388,8 +413,8 @@ private:
e_autoSleepFlag = 0x0004,
e_bulletFlag = 0x0008,
e_fixedRotationFlag = 0x0010,
e_activeFlag = 0x0020,
e_toiFlag = 0x0040,
e_enabledFlag = 0x0020,
e_toiFlag = 0x0040
};
b2Body(const b2BodyDef* bd, b2World* world);
@ -402,7 +427,7 @@ private:
// It may lie, depending on the collideConnected flag.
bool ShouldCollide(const b2Body* other) const;
void Advance(float32 t);
void Advance(float t);
b2BodyType m_type;
@ -414,10 +439,10 @@ private:
b2Sweep m_sweep; // the swept motion for CCD
b2Vec2 m_linearVelocity;
float32 m_angularVelocity;
float m_angularVelocity;
b2Vec2 m_force;
float32 m_torque;
float m_torque;
b2World* m_world;
b2Body* m_prev;
@ -429,17 +454,18 @@ private:
b2JointEdge* m_jointList;
b2ContactEdge* m_contactList;
float32 m_mass, m_invMass;
float m_mass, m_invMass;
// Rotational inertia about the center of mass.
float32 m_I, m_invI;
float m_I, m_invI;
float32 m_linearDamping;
float32 m_angularDamping;
float m_linearDamping;
float m_angularDamping;
float m_gravityScale;
float32 m_sleepTime;
float m_sleepTime;
void* m_userData;
b2BodyUserData m_userData;
};
inline b2BodyType b2Body::GetType() const
@ -454,10 +480,10 @@ inline const b2Transform& b2Body::GetTransform() const
inline const b2Vec2& b2Body::GetPosition() const
{
return m_xf.position;
return m_xf.p;
}
inline float32 b2Body::GetAngle() const
inline float b2Body::GetAngle() const
{
return m_sweep.a;
}
@ -487,12 +513,12 @@ inline void b2Body::SetLinearVelocity(const b2Vec2& v)
m_linearVelocity = v;
}
inline b2Vec2 b2Body::GetLinearVelocity() const
inline const b2Vec2& b2Body::GetLinearVelocity() const
{
return m_linearVelocity;
}
inline void b2Body::SetAngularVelocity(float32 w)
inline void b2Body::SetAngularVelocity(float w)
{
if (m_type == b2_staticBody)
{
@ -507,17 +533,17 @@ inline void b2Body::SetAngularVelocity(float32 w)
m_angularVelocity = w;
}
inline float32 b2Body::GetAngularVelocity() const
inline float b2Body::GetAngularVelocity() const
{
return m_angularVelocity;
}
inline float32 b2Body::GetMass() const
inline float b2Body::GetMass() const
{
return m_mass;
}
inline float32 b2Body::GetInertia() const
inline float b2Body::GetInertia() const
{
return m_I + m_mass * b2Dot(m_sweep.localCenter, m_sweep.localCenter);
}
@ -536,7 +562,7 @@ inline b2Vec2 b2Body::GetWorldPoint(const b2Vec2& localPoint) const
inline b2Vec2 b2Body::GetWorldVector(const b2Vec2& localVector) const
{
return b2Mul(m_xf.R, localVector);
return b2Mul(m_xf.q, localVector);
}
inline b2Vec2 b2Body::GetLocalPoint(const b2Vec2& worldPoint) const
@ -546,7 +572,7 @@ inline b2Vec2 b2Body::GetLocalPoint(const b2Vec2& worldPoint) const
inline b2Vec2 b2Body::GetLocalVector(const b2Vec2& worldVector) const
{
return b2MulT(m_xf.R, worldVector);
return b2MulT(m_xf.q, worldVector);
}
inline b2Vec2 b2Body::GetLinearVelocityFromWorldPoint(const b2Vec2& worldPoint) const
@ -559,26 +585,36 @@ inline b2Vec2 b2Body::GetLinearVelocityFromLocalPoint(const b2Vec2& localPoint)
return GetLinearVelocityFromWorldPoint(GetWorldPoint(localPoint));
}
inline float32 b2Body::GetLinearDamping() const
inline float b2Body::GetLinearDamping() const
{
return m_linearDamping;
}
inline void b2Body::SetLinearDamping(float32 linearDamping)
inline void b2Body::SetLinearDamping(float linearDamping)
{
m_linearDamping = linearDamping;
}
inline float32 b2Body::GetAngularDamping() const
inline float b2Body::GetAngularDamping() const
{
return m_angularDamping;
}
inline void b2Body::SetAngularDamping(float32 angularDamping)
inline void b2Body::SetAngularDamping(float angularDamping)
{
m_angularDamping = angularDamping;
}
inline float b2Body::GetGravityScale() const
{
return m_gravityScale;
}
inline void b2Body::SetGravityScale(float scale)
{
m_gravityScale = scale;
}
inline void b2Body::SetBullet(bool flag)
{
if (flag)
@ -598,13 +634,15 @@ inline bool b2Body::IsBullet() const
inline void b2Body::SetAwake(bool flag)
{
if (m_type == b2_staticBody)
{
return;
}
if (flag)
{
if ((m_flags & e_awakeFlag) == 0)
{
m_flags |= e_awakeFlag;
m_sleepTime = 0.0f;
}
m_flags |= e_awakeFlag;
m_sleepTime = 0.0f;
}
else
{
@ -622,23 +660,9 @@ inline bool b2Body::IsAwake() const
return (m_flags & e_awakeFlag) == e_awakeFlag;
}
inline bool b2Body::IsActive() const
inline bool b2Body::IsEnabled() const
{
return (m_flags & e_activeFlag) == e_activeFlag;
}
inline void b2Body::SetFixedRotation(bool flag)
{
if (flag)
{
m_flags |= e_fixedRotationFlag;
}
else
{
m_flags &= ~e_fixedRotationFlag;
}
ResetMassData();
return (m_flags & e_enabledFlag) == e_enabledFlag;
}
inline bool b2Body::IsFixedRotation() const
@ -704,89 +728,141 @@ inline const b2Body* b2Body::GetNext() const
return m_next;
}
inline void b2Body::SetUserData(void* data)
{
m_userData = data;
}
inline void* b2Body::GetUserData() const
inline b2BodyUserData& b2Body::GetUserData()
{
return m_userData;
}
inline void b2Body::ApplyForce(const b2Vec2& force, const b2Vec2& point)
inline void b2Body::ApplyForce(const b2Vec2& force, const b2Vec2& point, bool wake)
{
if (m_type != b2_dynamicBody)
{
return;
}
if (IsAwake() == false)
if (wake && (m_flags & e_awakeFlag) == 0)
{
SetAwake(true);
}
m_force += force;
m_torque += b2Cross(point - m_sweep.c, force);
// Don't accumulate a force if the body is sleeping.
if (m_flags & e_awakeFlag)
{
m_force += force;
m_torque += b2Cross(point - m_sweep.c, force);
}
}
inline void b2Body::ApplyTorque(float32 torque)
inline void b2Body::ApplyForceToCenter(const b2Vec2& force, bool wake)
{
if (m_type != b2_dynamicBody)
{
return;
}
if (IsAwake() == false)
if (wake && (m_flags & e_awakeFlag) == 0)
{
SetAwake(true);
}
m_torque += torque;
// Don't accumulate a force if the body is sleeping
if (m_flags & e_awakeFlag)
{
m_force += force;
}
}
inline void b2Body::ApplyLinearImpulse(const b2Vec2& impulse, const b2Vec2& point)
inline void b2Body::ApplyTorque(float torque, bool wake)
{
if (m_type != b2_dynamicBody)
{
return;
}
if (IsAwake() == false)
if (wake && (m_flags & e_awakeFlag) == 0)
{
SetAwake(true);
}
m_linearVelocity += m_invMass * impulse;
m_angularVelocity += m_invI * b2Cross(point - m_sweep.c, impulse);
// Don't accumulate a force if the body is sleeping
if (m_flags & e_awakeFlag)
{
m_torque += torque;
}
}
inline void b2Body::ApplyAngularImpulse(float32 impulse)
inline void b2Body::ApplyLinearImpulse(const b2Vec2& impulse, const b2Vec2& point, bool wake)
{
if (m_type != b2_dynamicBody)
{
return;
}
if (IsAwake() == false)
if (wake && (m_flags & e_awakeFlag) == 0)
{
SetAwake(true);
}
m_angularVelocity += m_invI * impulse;
// Don't accumulate velocity if the body is sleeping
if (m_flags & e_awakeFlag)
{
m_linearVelocity += m_invMass * impulse;
m_angularVelocity += m_invI * b2Cross(point - m_sweep.c, impulse);
}
}
inline void b2Body::ApplyLinearImpulseToCenter(const b2Vec2& impulse, bool wake)
{
if (m_type != b2_dynamicBody)
{
return;
}
if (wake && (m_flags & e_awakeFlag) == 0)
{
SetAwake(true);
}
// Don't accumulate velocity if the body is sleeping
if (m_flags & e_awakeFlag)
{
m_linearVelocity += m_invMass * impulse;
}
}
inline void b2Body::ApplyAngularImpulse(float impulse, bool wake)
{
if (m_type != b2_dynamicBody)
{
return;
}
if (wake && (m_flags & e_awakeFlag) == 0)
{
SetAwake(true);
}
// Don't accumulate velocity if the body is sleeping
if (m_flags & e_awakeFlag)
{
m_angularVelocity += m_invI * impulse;
}
}
inline void b2Body::SynchronizeTransform()
{
m_xf.R.Set(m_sweep.a);
m_xf.position = m_sweep.c - b2Mul(m_xf.R, m_sweep.localCenter);
m_xf.q.Set(m_sweep.a);
m_xf.p = m_sweep.c - b2Mul(m_xf.q, m_sweep.localCenter);
}
inline void b2Body::Advance(float32 t)
inline void b2Body::Advance(float alpha)
{
// Advance to the new safe time.
m_sweep.Advance(t);
// Advance to the new safe time. This doesn't sync the broad-phase.
m_sweep.Advance(alpha);
m_sweep.c = m_sweep.c0;
m_sweep.a = m_sweep.a0;
SynchronizeTransform();
m_xf.q.Set(m_sweep.a);
m_xf.p = m_sweep.c - b2Mul(m_xf.q, m_sweep.localCenter);
}
inline b2World* b2Body::GetWorld()

View file

@ -1,46 +1,49 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_BROAD_PHASE_H
#define B2_BROAD_PHASE_H
#include "b2Settings.h"
#include "b2Collision.h"
#include "b2DynamicTree.h"
#include <algorithm>
#include "b2_api.h"
#include "b2_settings.h"
#include "b2_collision.h"
#include "b2_dynamic_tree.h"
struct b2Pair
struct B2_API b2Pair
{
int32 proxyIdA;
int32 proxyIdB;
int32 next;
};
/// The broad-phase is used for computing pairs and performing volume queries and ray casts.
/// This broad-phase does not persist pairs. Instead, this reports potentially new pairs.
/// It is up to the client to consume the new pairs and to track subsequent overlap.
class b2BroadPhase
class B2_API b2BroadPhase
{
public:
enum
{
e_nullProxy = -1,
e_nullProxy = -1
};
b2BroadPhase();
@ -57,10 +60,13 @@ public:
/// call UpdatePairs to finalized the proxy pairs (for your time step).
void MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement);
/// Call to trigger a re-processing of it's pairs on the next call to UpdatePairs.
void TouchProxy(int32 proxyId);
/// Get the fat AABB for a proxy.
const b2AABB& GetFatAABB(int32 proxyId) const;
/// Get user data from a proxy. Returns NULL if the id is invalid.
/// Get user data from a proxy. Returns nullptr if the id is invalid.
void* GetUserData(int32 proxyId) const;
/// Test overlap of fat AABBs.
@ -88,8 +94,19 @@ public:
template <typename T>
void RayCast(T* callback, const b2RayCastInput& input) const;
/// Compute the height of the embedded tree.
int32 ComputeHeight() const;
/// Get the height of the embedded tree.
int32 GetTreeHeight() const;
/// Get the balance of the embedded tree.
int32 GetTreeBalance() const;
/// Get the quality metric of the embedded tree.
float GetTreeQuality() const;
/// Shift the world origin. Useful for large worlds.
/// The shift formula is: position -= newOrigin
/// @param newOrigin the new origin with respect to the old origin
void ShiftOrigin(const b2Vec2& newOrigin);
private:
@ -115,22 +132,6 @@ private:
int32 m_queryProxyId;
};
/// This is used to sort pairs.
inline bool b2PairLessThan(const b2Pair& pair1, const b2Pair& pair2)
{
if (pair1.proxyIdA < pair2.proxyIdA)
{
return true;
}
if (pair1.proxyIdA == pair2.proxyIdA)
{
return pair1.proxyIdB < pair2.proxyIdB;
}
return false;
}
inline void* b2BroadPhase::GetUserData(int32 proxyId) const
{
return m_tree.GetUserData(proxyId);
@ -153,9 +154,19 @@ inline int32 b2BroadPhase::GetProxyCount() const
return m_proxyCount;
}
inline int32 b2BroadPhase::ComputeHeight() const
inline int32 b2BroadPhase::GetTreeHeight() const
{
return m_tree.ComputeHeight();
return m_tree.GetHeight();
}
inline int32 b2BroadPhase::GetTreeBalance() const
{
return m_tree.GetMaxBalance();
}
inline float b2BroadPhase::GetTreeQuality() const
{
return m_tree.GetAreaRatio();
}
template <typename T>
@ -181,37 +192,30 @@ void b2BroadPhase::UpdatePairs(T* callback)
m_tree.Query(this, fatAABB);
}
// Reset move buffer
m_moveCount = 0;
// Sort the pair buffer to expose duplicates.
std::sort(m_pairBuffer, m_pairBuffer + m_pairCount, b2PairLessThan);
// Send the pairs back to the client.
int32 i = 0;
while (i < m_pairCount)
// Send pairs to caller
for (int32 i = 0; i < m_pairCount; ++i)
{
b2Pair* primaryPair = m_pairBuffer + i;
void* userDataA = m_tree.GetUserData(primaryPair->proxyIdA);
void* userDataB = m_tree.GetUserData(primaryPair->proxyIdB);
callback->AddPair(userDataA, userDataB);
++i;
// Skip any duplicate pairs.
while (i < m_pairCount)
{
b2Pair* pair = m_pairBuffer + i;
if (pair->proxyIdA != primaryPair->proxyIdA || pair->proxyIdB != primaryPair->proxyIdB)
{
break;
}
++i;
}
}
// Try to keep the tree balanced.
m_tree.Rebalance(4);
// Clear move flags
for (int32 i = 0; i < m_moveCount; ++i)
{
int32 proxyId = m_moveBuffer[i];
if (proxyId == e_nullProxy)
{
continue;
}
m_tree.ClearMoved(proxyId);
}
// Reset move buffer
m_moveCount = 0;
}
template <typename T>
@ -226,4 +230,9 @@ inline void b2BroadPhase::RayCast(T* callback, const b2RayCastInput& input) cons
m_tree.RayCast(callback, input);
}
inline void b2BroadPhase::ShiftOrigin(const b2Vec2& newOrigin)
{
m_tree.ShiftOrigin(newOrigin);
}
#endif

View file

@ -0,0 +1,101 @@
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_CHAIN_SHAPE_H
#define B2_CHAIN_SHAPE_H
#include "b2_api.h"
#include "b2_shape.h"
class b2EdgeShape;
/// A chain shape is a free form sequence of line segments.
/// The chain has one-sided collision, with the surface normal pointing to the right of the edge.
/// This provides a counter-clockwise winding like the polygon shape.
/// Connectivity information is used to create smooth collisions.
/// @warning the chain will not collide properly if there are self-intersections.
class B2_API b2ChainShape : public b2Shape
{
public:
b2ChainShape();
/// The destructor frees the vertices using b2Free.
~b2ChainShape();
/// Clear all data.
void Clear();
/// Create a loop. This automatically adjusts connectivity.
/// @param vertices an array of vertices, these are copied
/// @param count the vertex count
void CreateLoop(const b2Vec2* vertices, int32 count);
/// Create a chain with ghost vertices to connect multiple chains together.
/// @param vertices an array of vertices, these are copied
/// @param count the vertex count
/// @param prevVertex previous vertex from chain that connects to the start
/// @param nextVertex next vertex from chain that connects to the end
void CreateChain(const b2Vec2* vertices, int32 count,
const b2Vec2& prevVertex, const b2Vec2& nextVertex);
/// Implement b2Shape. Vertices are cloned using b2Alloc.
b2Shape* Clone(b2BlockAllocator* allocator) const override;
/// @see b2Shape::GetChildCount
int32 GetChildCount() const override;
/// Get a child edge.
void GetChildEdge(b2EdgeShape* edge, int32 index) const;
/// This always return false.
/// @see b2Shape::TestPoint
bool TestPoint(const b2Transform& transform, const b2Vec2& p) const override;
/// Implement b2Shape.
bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
const b2Transform& transform, int32 childIndex) const override;
/// @see b2Shape::ComputeAABB
void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const override;
/// Chains have zero mass.
/// @see b2Shape::ComputeMass
void ComputeMass(b2MassData* massData, float density) const override;
/// The vertices. Owned by this class.
b2Vec2* m_vertices;
/// The vertex count.
int32 m_count;
b2Vec2 m_prevVertex, m_nextVertex;
};
inline b2ChainShape::b2ChainShape()
{
m_type = e_chain;
m_radius = b2_polygonRadius;
m_vertices = nullptr;
m_count = 0;
}
#endif

View file

@ -0,0 +1,67 @@
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_CIRCLE_SHAPE_H
#define B2_CIRCLE_SHAPE_H
#include "b2_api.h"
#include "b2_shape.h"
/// A solid circle shape
class B2_API b2CircleShape : public b2Shape
{
public:
b2CircleShape();
/// Implement b2Shape.
b2Shape* Clone(b2BlockAllocator* allocator) const override;
/// @see b2Shape::GetChildCount
int32 GetChildCount() const override;
/// Implement b2Shape.
bool TestPoint(const b2Transform& transform, const b2Vec2& p) const override;
/// Implement b2Shape.
/// @note because the circle is solid, rays that start inside do not hit because the normal is
/// not defined.
bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
const b2Transform& transform, int32 childIndex) const override;
/// @see b2Shape::ComputeAABB
void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const override;
/// @see b2Shape::ComputeMass
void ComputeMass(b2MassData* massData, float density) const override;
/// Position
b2Vec2 m_p;
};
inline b2CircleShape::b2CircleShape()
{
m_type = e_circle;
m_radius = 0.0f;
m_p.SetZero();
}
#endif

View file

@ -1,26 +1,32 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_COLLISION_H
#define B2_COLLISION_H
#include "b2Math.h"
#include <climits>
#include <limits.h>
#include "b2_api.h"
#include "b2_math.h"
/// @file
/// Structures and functions used for computing contact points, distance
@ -28,21 +34,31 @@
class b2Shape;
class b2CircleShape;
class b2EdgeShape;
class b2PolygonShape;
const uint8 b2_nullFeature = UCHAR_MAX;
/// Contact ids to facilitate warm starting.
union b2ContactID
/// The features that intersect to form the contact point
/// This must be 4 bytes or less.
struct B2_API b2ContactFeature
{
/// The features that intersect to form the contact point
struct Features
enum Type
{
uint8 referenceEdge; ///< The edge that defines the outward contact normal.
uint8 incidentEdge; ///< The edge most anti-parallel to the reference edge.
uint8 incidentVertex; ///< The vertex (0 or 1) on the incident edge that was clipped.
uint8 flip; ///< A value of 1 indicates that the reference edge is on shape2.
} features;
e_vertex = 0,
e_face = 1
};
uint8 indexA; ///< Feature index on shapeA
uint8 indexB; ///< Feature index on shapeB
uint8 typeA; ///< The feature type on shapeA
uint8 typeB; ///< The feature type on shapeB
};
/// Contact ids to facilitate warm starting.
union B2_API b2ContactID
{
b2ContactFeature cf;
uint32 key; ///< Used to quickly compare contact ids.
};
@ -56,11 +72,11 @@ union b2ContactID
/// This structure is stored across time steps, so we keep it small.
/// Note: the impulses are used for internal caching and may not
/// provide reliable contact forces, especially for high speed collisions.
struct b2ManifoldPoint
struct B2_API b2ManifoldPoint
{
b2Vec2 localPoint; ///< usage depends on manifold type
float32 normalImpulse; ///< the non-penetration impulse
float32 tangentImpulse; ///< the friction impulse
float normalImpulse; ///< the non-penetration impulse
float tangentImpulse; ///< the friction impulse
b2ContactID id; ///< uniquely identifies a contact point between two shapes
};
@ -80,7 +96,7 @@ struct b2ManifoldPoint
/// account for movement, which is critical for continuous physics.
/// All contact scenarios must be expressed in one of these types.
/// This structure is stored across time steps, so we keep it small.
struct b2Manifold
struct B2_API b2Manifold
{
enum Type
{
@ -97,18 +113,19 @@ struct b2Manifold
};
/// This is used to compute the current state of a contact manifold.
struct b2WorldManifold
struct B2_API b2WorldManifold
{
/// Evaluate the manifold with supplied transforms. This assumes
/// modest motion from the original state. This does not change the
/// point count, impulses, etc. The radii must come from the shapes
/// that generated the manifold.
void Initialize(const b2Manifold* manifold,
const b2Transform& xfA, float32 radiusA,
const b2Transform& xfB, float32 radiusB);
const b2Transform& xfA, float radiusA,
const b2Transform& xfB, float radiusB);
b2Vec2 normal; ///< world vector pointing from A to B
b2Vec2 points[b2_maxManifoldPoints]; ///< world contact point (point of intersection)
b2Vec2 normal; ///< world vector pointing from A to B
b2Vec2 points[b2_maxManifoldPoints]; ///< world contact point (point of intersection)
float separations[b2_maxManifoldPoints]; ///< a negative value indicates overlap, in meters
};
/// This is used for determining the state of contact points.
@ -122,33 +139,33 @@ enum b2PointState
/// Compute the point states given two manifolds. The states pertain to the transition from manifold1
/// to manifold2. So state1 is either persist or remove while state2 is either add or persist.
void b2GetPointStates(b2PointState state1[b2_maxManifoldPoints], b2PointState state2[b2_maxManifoldPoints],
B2_API void b2GetPointStates(b2PointState state1[b2_maxManifoldPoints], b2PointState state2[b2_maxManifoldPoints],
const b2Manifold* manifold1, const b2Manifold* manifold2);
/// Used for computing contact manifolds.
struct b2ClipVertex
struct B2_API b2ClipVertex
{
b2Vec2 v;
b2ContactID id;
};
/// Ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).
struct b2RayCastInput
struct B2_API b2RayCastInput
{
b2Vec2 p1, p2;
float32 maxFraction;
float maxFraction;
};
/// Ray-cast output data. The ray hits at p1 + fraction * (p2 - p1), where p1 and p2
/// come from b2RayCastInput.
struct b2RayCastOutput
struct B2_API b2RayCastOutput
{
b2Vec2 normal;
float32 fraction;
float fraction;
};
/// An axis aligned bounding box.
struct b2AABB
struct B2_API b2AABB
{
/// Verify that the bounds are sorted.
bool IsValid() const;
@ -165,6 +182,21 @@ struct b2AABB
return 0.5f * (upperBound - lowerBound);
}
/// Get the perimeter length
float GetPerimeter() const
{
float wx = upperBound.x - lowerBound.x;
float wy = upperBound.y - lowerBound.y;
return 2.0f * (wx + wy);
}
/// Combine an AABB into this one.
void Combine(const b2AABB& aabb)
{
lowerBound = b2Min(lowerBound, aabb.lowerBound);
upperBound = b2Max(upperBound, aabb.upperBound);
}
/// Combine two AABBs into this one.
void Combine(const b2AABB& aabb1, const b2AABB& aabb2)
{
@ -190,27 +222,38 @@ struct b2AABB
};
/// Compute the collision manifold between two circles.
void b2CollideCircles(b2Manifold* manifold,
const b2CircleShape* circle1, const b2Transform& xf1,
const b2CircleShape* circle2, const b2Transform& xf2);
B2_API void b2CollideCircles(b2Manifold* manifold,
const b2CircleShape* circleA, const b2Transform& xfA,
const b2CircleShape* circleB, const b2Transform& xfB);
/// Compute the collision manifold between a polygon and a circle.
void b2CollidePolygonAndCircle(b2Manifold* manifold,
const b2PolygonShape* polygon, const b2Transform& xf1,
const b2CircleShape* circle, const b2Transform& xf2);
B2_API void b2CollidePolygonAndCircle(b2Manifold* manifold,
const b2PolygonShape* polygonA, const b2Transform& xfA,
const b2CircleShape* circleB, const b2Transform& xfB);
/// Compute the collision manifold between two polygons.
void b2CollidePolygons(b2Manifold* manifold,
const b2PolygonShape* polygon1, const b2Transform& xf1,
const b2PolygonShape* polygon2, const b2Transform& xf2);
B2_API void b2CollidePolygons(b2Manifold* manifold,
const b2PolygonShape* polygonA, const b2Transform& xfA,
const b2PolygonShape* polygonB, const b2Transform& xfB);
/// Compute the collision manifold between an edge and a circle.
B2_API void b2CollideEdgeAndCircle(b2Manifold* manifold,
const b2EdgeShape* polygonA, const b2Transform& xfA,
const b2CircleShape* circleB, const b2Transform& xfB);
/// Compute the collision manifold between an edge and a polygon.
B2_API void b2CollideEdgeAndPolygon(b2Manifold* manifold,
const b2EdgeShape* edgeA, const b2Transform& xfA,
const b2PolygonShape* circleB, const b2Transform& xfB);
/// Clipping for contact manifolds.
int32 b2ClipSegmentToLine(b2ClipVertex vOut[2], const b2ClipVertex vIn[2],
const b2Vec2& normal, float32 offset);
B2_API int32 b2ClipSegmentToLine(b2ClipVertex vOut[2], const b2ClipVertex vIn[2],
const b2Vec2& normal, float offset, int32 vertexIndexA);
/// Determine if two generic shapes overlap.
bool b2TestOverlap(const b2Shape* shapeA, const b2Shape* shapeB,
const b2Transform& xfA, const b2Transform& xfB);
B2_API bool b2TestOverlap( const b2Shape* shapeA, int32 indexA,
const b2Shape* shapeB, int32 indexB,
const b2Transform& xfA, const b2Transform& xfB);
// ---------------- Inline Functions ------------------------------------------

View file

@ -1,38 +1,41 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
// MIT License
#ifndef B2_SETTINGS_H
#define B2_SETTINGS_H
// Copyright (c) 2019 Erin Catto
#include <cassert>
#include <cmath>
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_COMMON_H
#define B2_COMMON_H
#include "b2_settings.h"
#include <stddef.h>
#include <assert.h>
#include <float.h>
#if !defined(NDEBUG)
#define b2DEBUG
#endif
#define B2_NOT_USED(x) ((void)(x))
#define b2Assert(A) assert(A)
typedef signed char int8;
typedef signed short int16;
typedef signed int int32;
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
typedef float float32;
#define b2_maxFloat FLT_MAX
#define b2_epsilon FLT_EPSILON
#define b2_pi 3.14159265359f
@ -43,25 +46,23 @@ typedef float float32;
// Collision
/// The maximum number of contact points between two convex shapes.
/// The maximum number of contact points between two convex shapes. Do
/// not change this value.
#define b2_maxManifoldPoints 2
/// The maximum number of vertices on a convex polygon.
#define b2_maxPolygonVertices 8
/// This is used to fatten AABBs in the dynamic tree. This allows proxies
/// to move by a small amount without triggering a tree adjustment.
/// This is in meters.
#define b2_aabbExtension 0.1f
#define b2_aabbExtension (0.1f * b2_lengthUnitsPerMeter)
/// This is used to fatten AABBs in the dynamic tree. This is used to predict
/// the future position based on the current displacement.
/// This is a dimensionless multiplier.
#define b2_aabbMultiplier 2.0f
#define b2_aabbMultiplier 4.0f
/// A small length used as a collision and constraint tolerance. Usually it is
/// chosen to be numerically significant, but visually insignificant.
#define b2_linearSlop 0.005f
/// chosen to be numerically significant, but visually insignificant. In meters.
#define b2_linearSlop (0.005f * b2_lengthUnitsPerMeter)
/// A small angle used as a collision and constraint tolerance. Usually it is
/// chosen to be numerically significant, but visually insignificant.
@ -72,27 +73,26 @@ typedef float float32;
/// Making it larger may create artifacts for vertex collision.
#define b2_polygonRadius (2.0f * b2_linearSlop)
/// Maximum number of sub-steps per contact in continuous physics simulation.
#define b2_maxSubSteps 8
// Dynamics
/// Maximum number of contacts to be handled to solve a TOI impact.
#define b2_maxTOIContacts 32
/// A velocity threshold for elastic collisions. Any collision with a relative linear
/// velocity below this threshold will be treated as inelastic.
#define b2_velocityThreshold 1.0f
/// The maximum linear position correction used when solving constraints. This helps to
/// prevent overshoot.
#define b2_maxLinearCorrection 0.2f
/// prevent overshoot. Meters.
#define b2_maxLinearCorrection (0.2f * b2_lengthUnitsPerMeter)
/// The maximum angular position correction used when solving constraints. This helps to
/// prevent overshoot.
#define b2_maxAngularCorrection (8.0f / 180.0f * b2_pi)
/// The maximum linear velocity of a body. This limit is very large and is used
/// to prevent numerical problems. You shouldn't need to adjust this.
#define b2_maxTranslation 2.0f
/// The maximum linear translation of a body per step. This limit is very large and is used
/// to prevent numerical problems. You shouldn't need to adjust this. Meters.
#define b2_maxTranslation (2.0f * b2_lengthUnitsPerMeter)
#define b2_maxTranslationSquared (b2_maxTranslation * b2_maxTranslation)
/// The maximum angular velocity of a body. This limit is very large and is used
@ -103,7 +103,9 @@ typedef float float32;
/// This scale factor controls how fast overlap is resolved. Ideally this would be 1 so
/// that overlap is removed in one time step. However using values close to 1 often lead
/// to overshoot.
#define b2_contactBaumgarte 0.2f
#define b2_baumgarte 0.2f
#define b2_toiBaumgarte 0.75f
// Sleep
@ -111,18 +113,15 @@ typedef float float32;
#define b2_timeToSleep 0.5f
/// A body cannot sleep if its linear velocity is above this tolerance.
#define b2_linearSleepTolerance 0.01f
#define b2_linearSleepTolerance (0.01f * b2_lengthUnitsPerMeter)
/// A body cannot sleep if its angular velocity is above this tolerance.
#define b2_angularSleepTolerance (2.0f / 180.0f * b2_pi)
// Memory Allocation
/// Implement this function to use your own memory allocator.
void* b2Alloc(int32 size);
/// If you implement b2Alloc, you should also implement this function.
void b2Free(void* mem);
/// Dump to a file. Only one dump file allowed at a time.
void b2OpenDump(const char* fileName);
void b2Dump(const char* string, ...);
void b2CloseDump();
/// Version numbering scheme.
/// See http://en.wikipedia.org/wiki/Software_versioning
@ -134,18 +133,6 @@ struct b2Version
};
/// Current version.
extern b2Version b2_version;
/// Friction mixing law. Feel free to customize this.
inline float32 b2MixFriction(float32 friction1, float32 friction2)
{
return sqrtf(friction1 * friction2);
}
/// Restitution mixing law. Feel free to customize this.
inline float32 b2MixRestitution(float32 restitution1, float32 restitution2)
{
return restitution1 > restitution2 ? restitution1 : restitution2;
}
extern B2_API b2Version b2_version;
#endif

View file

@ -0,0 +1,386 @@
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_CONTACT_H
#define B2_CONTACT_H
#include "b2_api.h"
#include "b2_collision.h"
#include "b2_fixture.h"
#include "b2_math.h"
#include "b2_shape.h"
class b2Body;
class b2Contact;
class b2Fixture;
class b2World;
class b2BlockAllocator;
class b2StackAllocator;
class b2ContactListener;
/// Friction mixing law. The idea is to allow either fixture to drive the friction to zero.
/// For example, anything slides on ice.
inline float b2MixFriction(float friction1, float friction2)
{
return b2Sqrt(friction1 * friction2);
}
/// Restitution mixing law. The idea is allow for anything to bounce off an inelastic surface.
/// For example, a superball bounces on anything.
inline float b2MixRestitution(float restitution1, float restitution2)
{
return restitution1 > restitution2 ? restitution1 : restitution2;
}
/// Restitution mixing law. This picks the lowest value.
inline float b2MixRestitutionThreshold(float threshold1, float threshold2)
{
return threshold1 < threshold2 ? threshold1 : threshold2;
}
typedef b2Contact* b2ContactCreateFcn( b2Fixture* fixtureA, int32 indexA,
b2Fixture* fixtureB, int32 indexB,
b2BlockAllocator* allocator);
typedef void b2ContactDestroyFcn(b2Contact* contact, b2BlockAllocator* allocator);
struct B2_API b2ContactRegister
{
b2ContactCreateFcn* createFcn;
b2ContactDestroyFcn* destroyFcn;
bool primary;
};
/// A contact edge is used to connect bodies and contacts together
/// in a contact graph where each body is a node and each contact
/// is an edge. A contact edge belongs to a doubly linked list
/// maintained in each attached body. Each contact has two contact
/// nodes, one for each attached body.
struct B2_API b2ContactEdge
{
b2Body* other; ///< provides quick access to the other body attached.
b2Contact* contact; ///< the contact
b2ContactEdge* prev; ///< the previous contact edge in the body's contact list
b2ContactEdge* next; ///< the next contact edge in the body's contact list
};
/// The class manages contact between two shapes. A contact exists for each overlapping
/// AABB in the broad-phase (except if filtered). Therefore a contact object may exist
/// that has no contact points.
class B2_API b2Contact
{
public:
/// Get the contact manifold. Do not modify the manifold unless you understand the
/// internals of Box2D.
b2Manifold* GetManifold();
const b2Manifold* GetManifold() const;
/// Get the world manifold.
void GetWorldManifold(b2WorldManifold* worldManifold) const;
/// Is this contact touching?
bool IsTouching() const;
/// Enable/disable this contact. This can be used inside the pre-solve
/// contact listener. The contact is only disabled for the current
/// time step (or sub-step in continuous collisions).
void SetEnabled(bool flag);
/// Has this contact been disabled?
bool IsEnabled() const;
/// Get the next contact in the world's contact list.
b2Contact* GetNext();
const b2Contact* GetNext() const;
/// Get fixture A in this contact.
b2Fixture* GetFixtureA();
const b2Fixture* GetFixtureA() const;
/// Get the child primitive index for fixture A.
int32 GetChildIndexA() const;
/// Get fixture B in this contact.
b2Fixture* GetFixtureB();
const b2Fixture* GetFixtureB() const;
/// Get the child primitive index for fixture B.
int32 GetChildIndexB() const;
/// Override the default friction mixture. You can call this in b2ContactListener::PreSolve.
/// This value persists until set or reset.
void SetFriction(float friction);
/// Get the friction.
float GetFriction() const;
/// Reset the friction mixture to the default value.
void ResetFriction();
/// Override the default restitution mixture. You can call this in b2ContactListener::PreSolve.
/// The value persists until you set or reset.
void SetRestitution(float restitution);
/// Get the restitution.
float GetRestitution() const;
/// Reset the restitution to the default value.
void ResetRestitution();
/// Override the default restitution velocity threshold mixture. You can call this in b2ContactListener::PreSolve.
/// The value persists until you set or reset.
void SetRestitutionThreshold(float threshold);
/// Get the restitution threshold.
float GetRestitutionThreshold() const;
/// Reset the restitution threshold to the default value.
void ResetRestitutionThreshold();
/// Set the desired tangent speed for a conveyor belt behavior. In meters per second.
void SetTangentSpeed(float speed);
/// Get the desired tangent speed. In meters per second.
float GetTangentSpeed() const;
/// Evaluate this contact with your own manifold and transforms.
virtual void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) = 0;
protected:
friend class b2ContactManager;
friend class b2World;
friend class b2ContactSolver;
friend class b2Body;
friend class b2Fixture;
// Flags stored in m_flags
enum
{
// Used when crawling contact graph when forming islands.
e_islandFlag = 0x0001,
// Set when the shapes are touching.
e_touchingFlag = 0x0002,
// This contact can be disabled (by user)
e_enabledFlag = 0x0004,
// This contact needs filtering because a fixture filter was changed.
e_filterFlag = 0x0008,
// This bullet contact had a TOI event
e_bulletHitFlag = 0x0010,
// This contact has a valid TOI in m_toi
e_toiFlag = 0x0020
};
/// Flag this contact for filtering. Filtering will occur the next time step.
void FlagForFiltering();
static void AddType(b2ContactCreateFcn* createFcn, b2ContactDestroyFcn* destroyFcn,
b2Shape::Type typeA, b2Shape::Type typeB);
static void InitializeRegisters();
static b2Contact* Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator);
static void Destroy(b2Contact* contact, b2Shape::Type typeA, b2Shape::Type typeB, b2BlockAllocator* allocator);
static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);
b2Contact() : m_fixtureA(nullptr), m_fixtureB(nullptr) {}
b2Contact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB);
virtual ~b2Contact() {}
void Update(b2ContactListener* listener);
static b2ContactRegister s_registers[b2Shape::e_typeCount][b2Shape::e_typeCount];
static bool s_initialized;
uint32 m_flags;
// World pool and list pointers.
b2Contact* m_prev;
b2Contact* m_next;
// Nodes for connecting bodies.
b2ContactEdge m_nodeA;
b2ContactEdge m_nodeB;
b2Fixture* m_fixtureA;
b2Fixture* m_fixtureB;
int32 m_indexA;
int32 m_indexB;
b2Manifold m_manifold;
int32 m_toiCount;
float m_toi;
float m_friction;
float m_restitution;
float m_restitutionThreshold;
float m_tangentSpeed;
};
inline b2Manifold* b2Contact::GetManifold()
{
return &m_manifold;
}
inline const b2Manifold* b2Contact::GetManifold() const
{
return &m_manifold;
}
inline void b2Contact::GetWorldManifold(b2WorldManifold* worldManifold) const
{
const b2Body* bodyA = m_fixtureA->GetBody();
const b2Body* bodyB = m_fixtureB->GetBody();
const b2Shape* shapeA = m_fixtureA->GetShape();
const b2Shape* shapeB = m_fixtureB->GetShape();
worldManifold->Initialize(&m_manifold, bodyA->GetTransform(), shapeA->m_radius, bodyB->GetTransform(), shapeB->m_radius);
}
inline void b2Contact::SetEnabled(bool flag)
{
if (flag)
{
m_flags |= e_enabledFlag;
}
else
{
m_flags &= ~e_enabledFlag;
}
}
inline bool b2Contact::IsEnabled() const
{
return (m_flags & e_enabledFlag) == e_enabledFlag;
}
inline bool b2Contact::IsTouching() const
{
return (m_flags & e_touchingFlag) == e_touchingFlag;
}
inline b2Contact* b2Contact::GetNext()
{
return m_next;
}
inline const b2Contact* b2Contact::GetNext() const
{
return m_next;
}
inline b2Fixture* b2Contact::GetFixtureA()
{
return m_fixtureA;
}
inline const b2Fixture* b2Contact::GetFixtureA() const
{
return m_fixtureA;
}
inline b2Fixture* b2Contact::GetFixtureB()
{
return m_fixtureB;
}
inline int32 b2Contact::GetChildIndexA() const
{
return m_indexA;
}
inline const b2Fixture* b2Contact::GetFixtureB() const
{
return m_fixtureB;
}
inline int32 b2Contact::GetChildIndexB() const
{
return m_indexB;
}
inline void b2Contact::FlagForFiltering()
{
m_flags |= e_filterFlag;
}
inline void b2Contact::SetFriction(float friction)
{
m_friction = friction;
}
inline float b2Contact::GetFriction() const
{
return m_friction;
}
inline void b2Contact::ResetFriction()
{
m_friction = b2MixFriction(m_fixtureA->m_friction, m_fixtureB->m_friction);
}
inline void b2Contact::SetRestitution(float restitution)
{
m_restitution = restitution;
}
inline float b2Contact::GetRestitution() const
{
return m_restitution;
}
inline void b2Contact::ResetRestitution()
{
m_restitution = b2MixRestitution(m_fixtureA->m_restitution, m_fixtureB->m_restitution);
}
inline void b2Contact::SetRestitutionThreshold(float threshold)
{
m_restitutionThreshold = threshold;
}
inline float b2Contact::GetRestitutionThreshold() const
{
return m_restitutionThreshold;
}
inline void b2Contact::ResetRestitutionThreshold()
{
m_restitutionThreshold = b2MixRestitutionThreshold(m_fixtureA->m_restitutionThreshold, m_fixtureB->m_restitutionThreshold);
}
inline void b2Contact::SetTangentSpeed(float speed)
{
m_tangentSpeed = speed;
}
inline float b2Contact::GetTangentSpeed() const
{
return m_tangentSpeed;
}
#endif

View file

@ -0,0 +1,57 @@
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_CONTACT_MANAGER_H
#define B2_CONTACT_MANAGER_H
#include "b2_api.h"
#include "b2_broad_phase.h"
class b2Contact;
class b2ContactFilter;
class b2ContactListener;
class b2BlockAllocator;
// Delegate of b2World.
class B2_API b2ContactManager
{
public:
b2ContactManager();
// Broad-phase callback.
void AddPair(void* proxyUserDataA, void* proxyUserDataB);
void FindNewContacts();
void Destroy(b2Contact* c);
void Collide();
b2BroadPhase m_broadPhase;
b2Contact* m_contactList;
int32 m_contactCount;
b2ContactFilter* m_contactFilter;
b2ContactListener* m_contactListener;
b2BlockAllocator* m_allocator;
};
#endif

View file

@ -0,0 +1,171 @@
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_DISTANCE_H
#define B2_DISTANCE_H
#include "b2_api.h"
#include "b2_math.h"
class b2Shape;
/// A distance proxy is used by the GJK algorithm.
/// It encapsulates any shape.
struct B2_API b2DistanceProxy
{
b2DistanceProxy() : m_vertices(nullptr), m_count(0), m_radius(0.0f) {}
/// Initialize the proxy using the given shape. The shape
/// must remain in scope while the proxy is in use.
void Set(const b2Shape* shape, int32 index);
/// Initialize the proxy using a vertex cloud and radius. The vertices
/// must remain in scope while the proxy is in use.
void Set(const b2Vec2* vertices, int32 count, float radius);
/// Get the supporting vertex index in the given direction.
int32 GetSupport(const b2Vec2& d) const;
/// Get the supporting vertex in the given direction.
const b2Vec2& GetSupportVertex(const b2Vec2& d) const;
/// Get the vertex count.
int32 GetVertexCount() const;
/// Get a vertex by index. Used by b2Distance.
const b2Vec2& GetVertex(int32 index) const;
b2Vec2 m_buffer[2];
const b2Vec2* m_vertices;
int32 m_count;
float m_radius;
};
/// Used to warm start b2Distance.
/// Set count to zero on first call.
struct B2_API b2SimplexCache
{
float metric; ///< length or area
uint16 count;
uint8 indexA[3]; ///< vertices on shape A
uint8 indexB[3]; ///< vertices on shape B
};
/// Input for b2Distance.
/// You have to option to use the shape radii
/// in the computation. Even
struct B2_API b2DistanceInput
{
b2DistanceProxy proxyA;
b2DistanceProxy proxyB;
b2Transform transformA;
b2Transform transformB;
bool useRadii;
};
/// Output for b2Distance.
struct B2_API b2DistanceOutput
{
b2Vec2 pointA; ///< closest point on shapeA
b2Vec2 pointB; ///< closest point on shapeB
float distance;
int32 iterations; ///< number of GJK iterations used
};
/// Compute the closest points between two shapes. Supports any combination of:
/// b2CircleShape, b2PolygonShape, b2EdgeShape. The simplex cache is input/output.
/// On the first call set b2SimplexCache.count to zero.
B2_API void b2Distance(b2DistanceOutput* output,
b2SimplexCache* cache,
const b2DistanceInput* input);
/// Input parameters for b2ShapeCast
struct B2_API b2ShapeCastInput
{
b2DistanceProxy proxyA;
b2DistanceProxy proxyB;
b2Transform transformA;
b2Transform transformB;
b2Vec2 translationB;
};
/// Output results for b2ShapeCast
struct B2_API b2ShapeCastOutput
{
b2Vec2 point;
b2Vec2 normal;
float lambda;
int32 iterations;
};
/// Perform a linear shape cast of shape B moving and shape A fixed. Determines the hit point, normal, and translation fraction.
/// @returns true if hit, false if there is no hit or an initial overlap
B2_API bool b2ShapeCast(b2ShapeCastOutput* output, const b2ShapeCastInput* input);
//////////////////////////////////////////////////////////////////////////
inline int32 b2DistanceProxy::GetVertexCount() const
{
return m_count;
}
inline const b2Vec2& b2DistanceProxy::GetVertex(int32 index) const
{
b2Assert(0 <= index && index < m_count);
return m_vertices[index];
}
inline int32 b2DistanceProxy::GetSupport(const b2Vec2& d) const
{
int32 bestIndex = 0;
float bestValue = b2Dot(m_vertices[0], d);
for (int32 i = 1; i < m_count; ++i)
{
float value = b2Dot(m_vertices[i], d);
if (value > bestValue)
{
bestIndex = i;
bestValue = value;
}
}
return bestIndex;
}
inline const b2Vec2& b2DistanceProxy::GetSupportVertex(const b2Vec2& d) const
{
int32 bestIndex = 0;
float bestValue = b2Dot(m_vertices[0], d);
for (int32 i = 1; i < m_count; ++i)
{
float value = b2Dot(m_vertices[i], d);
if (value > bestValue)
{
bestIndex = i;
bestValue = value;
}
}
return m_vertices[bestIndex];
}
#endif

View file

@ -0,0 +1,176 @@
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_DISTANCE_JOINT_H
#define B2_DISTANCE_JOINT_H
#include "b2_api.h"
#include "b2_joint.h"
/// Distance joint definition. This requires defining an anchor point on both
/// bodies and the non-zero distance of the distance joint. The definition uses
/// local anchor points so that the initial configuration can violate the
/// constraint slightly. This helps when saving and loading a game.
struct B2_API b2DistanceJointDef : public b2JointDef
{
b2DistanceJointDef()
{
type = e_distanceJoint;
localAnchorA.Set(0.0f, 0.0f);
localAnchorB.Set(0.0f, 0.0f);
length = 1.0f;
minLength = 0.0f;
maxLength = FLT_MAX;
stiffness = 0.0f;
damping = 0.0f;
}
/// Initialize the bodies, anchors, and rest length using world space anchors.
/// The minimum and maximum lengths are set to the rest length.
void Initialize(b2Body* bodyA, b2Body* bodyB,
const b2Vec2& anchorA, const b2Vec2& anchorB);
/// The local anchor point relative to bodyA's origin.
b2Vec2 localAnchorA;
/// The local anchor point relative to bodyB's origin.
b2Vec2 localAnchorB;
/// The rest length of this joint. Clamped to a stable minimum value.
float length;
/// Minimum length. Clamped to a stable minimum value.
float minLength;
/// Maximum length. Must be greater than or equal to the minimum length.
float maxLength;
/// The linear stiffness in N/m.
float stiffness;
/// The linear damping in N*s/m.
float damping;
};
/// A distance joint constrains two points on two bodies to remain at a fixed
/// distance from each other. You can view this as a massless, rigid rod.
class B2_API b2DistanceJoint : public b2Joint
{
public:
b2Vec2 GetAnchorA() const override;
b2Vec2 GetAnchorB() const override;
/// Get the reaction force given the inverse time step.
/// Unit is N.
b2Vec2 GetReactionForce(float inv_dt) const override;
/// Get the reaction torque given the inverse time step.
/// Unit is N*m. This is always zero for a distance joint.
float GetReactionTorque(float inv_dt) const override;
/// The local anchor point relative to bodyA's origin.
const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; }
/// The local anchor point relative to bodyB's origin.
const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; }
/// Get the rest length
float GetLength() const { return m_length; }
/// Set the rest length
/// @returns clamped rest length
float SetLength(float length);
/// Get the minimum length
float GetMinLength() const { return m_minLength; }
/// Set the minimum length
/// @returns the clamped minimum length
float SetMinLength(float minLength);
/// Get the maximum length
float GetMaxLength() const { return m_maxLength; }
/// Set the maximum length
/// @returns the clamped maximum length
float SetMaxLength(float maxLength);
/// Get the current length
float GetCurrentLength() const;
/// Set/get the linear stiffness in N/m
void SetStiffness(float stiffness) { m_stiffness = stiffness; }
float GetStiffness() const { return m_stiffness; }
/// Set/get linear damping in N*s/m
void SetDamping(float damping) { m_damping = damping; }
float GetDamping() const { return m_damping; }
/// Dump joint to dmLog
void Dump() override;
///
void Draw(b2Draw* draw) const override;
protected:
friend class b2Joint;
b2DistanceJoint(const b2DistanceJointDef* data);
void InitVelocityConstraints(const b2SolverData& data) override;
void SolveVelocityConstraints(const b2SolverData& data) override;
bool SolvePositionConstraints(const b2SolverData& data) override;
float m_stiffness;
float m_damping;
float m_bias;
float m_length;
float m_minLength;
float m_maxLength;
// Solver shared
b2Vec2 m_localAnchorA;
b2Vec2 m_localAnchorB;
float m_gamma;
float m_impulse;
float m_lowerImpulse;
float m_upperImpulse;
// Solver temp
int32 m_indexA;
int32 m_indexB;
b2Vec2 m_u;
b2Vec2 m_rA;
b2Vec2 m_rB;
b2Vec2 m_localCenterA;
b2Vec2 m_localCenterB;
float m_currentLength;
float m_invMassA;
float m_invMassB;
float m_invIA;
float m_invIB;
float m_softMass;
float m_mass;
};
#endif

View file

@ -0,0 +1,102 @@
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_DRAW_H
#define B2_DRAW_H
#include "b2_api.h"
#include "b2_math.h"
/// Color for debug drawing. Each value has the range [0,1].
struct B2_API b2Color
{
b2Color() {}
b2Color(float rIn, float gIn, float bIn, float aIn = 1.0f)
{
r = rIn; g = gIn; b = bIn; a = aIn;
}
void Set(float rIn, float gIn, float bIn, float aIn = 1.0f)
{
r = rIn; g = gIn; b = bIn; a = aIn;
}
float r, g, b, a;
};
/// Implement and register this class with a b2World to provide debug drawing of physics
/// entities in your game.
class B2_API b2Draw
{
public:
b2Draw();
virtual ~b2Draw() {}
enum
{
e_shapeBit = 0x0001, ///< draw shapes
e_jointBit = 0x0002, ///< draw joint connections
e_aabbBit = 0x0004, ///< draw axis aligned bounding boxes
e_pairBit = 0x0008, ///< draw broad-phase pairs
e_centerOfMassBit = 0x0010 ///< draw center of mass frame
};
/// Set the drawing flags.
void SetFlags(uint32 flags);
/// Get the drawing flags.
uint32 GetFlags() const;
/// Append flags to the current flags.
void AppendFlags(uint32 flags);
/// Clear flags from the current flags.
void ClearFlags(uint32 flags);
/// Draw a closed polygon provided in CCW order.
virtual void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0;
/// Draw a solid closed polygon provided in CCW order.
virtual void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0;
/// Draw a circle.
virtual void DrawCircle(const b2Vec2& center, float radius, const b2Color& color) = 0;
/// Draw a solid circle.
virtual void DrawSolidCircle(const b2Vec2& center, float radius, const b2Vec2& axis, const b2Color& color) = 0;
/// Draw a line segment.
virtual void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) = 0;
/// Draw a transform. Choose your own length scale.
/// @param xf a transform.
virtual void DrawTransform(const b2Transform& xf) = 0;
/// Draw a point.
virtual void DrawPoint(const b2Vec2& p, float size, const b2Color& color) = 0;
protected:
uint32 m_drawFlags;
};
#endif

View file

@ -1,42 +1,45 @@
/*
* Copyright (c) 2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_DYNAMIC_TREE_H
#define B2_DYNAMIC_TREE_H
#include "b2Collision.h"
/// A dynamic AABB tree broad-phase, inspired by Nathanael Presson's btDbvt.
#include "b2_api.h"
#include "b2_collision.h"
#include "b2_growable_stack.h"
#define b2_nullNode (-1)
/// A node in the dynamic tree. The client does not interact with this directly.
struct b2DynamicTreeNode
struct B2_API b2TreeNode
{
bool IsLeaf() const
{
return child1 == b2_nullNode;
}
/// This is the fattened AABB.
/// Enlarged AABB
b2AABB aabb;
//int32 userData;
void* userData;
union
@ -47,8 +50,14 @@ struct b2DynamicTreeNode
int32 child1;
int32 child2;
// leaf = 0, free node = -1
int32 height;
bool moved;
};
/// A dynamic AABB tree broad-phase, inspired by Nathanael Presson's btDbvt.
/// A dynamic tree arranges data in a binary tree to accelerate
/// queries such as volume queries and ray casts. Leafs are proxies
/// with an AABB. In the tree we expand the proxy AABB by b2_fatAABBFactor
@ -56,10 +65,9 @@ struct b2DynamicTreeNode
/// object to move by small amounts without triggering a tree update.
///
/// Nodes are pooled and relocatable, so we use node indices rather than pointers.
class b2DynamicTree
class B2_API b2DynamicTree
{
public:
/// Constructing the tree initializes the node pool.
b2DynamicTree();
@ -78,19 +86,16 @@ public:
/// @return true if the proxy was re-inserted.
bool MoveProxy(int32 proxyId, const b2AABB& aabb1, const b2Vec2& displacement);
/// Perform some iterations to re-balance the tree.
void Rebalance(int32 iterations);
/// Get proxy user data.
/// @return the proxy user data or 0 if the id is invalid.
void* GetUserData(int32 proxyId) const;
bool WasMoved(int32 proxyId) const;
void ClearMoved(int32 proxyId);
/// Get the fat AABB for a proxy.
const b2AABB& GetFatAABB(int32 proxyId) const;
/// Compute the height of the tree.
int32 ComputeHeight() const;
/// Query an AABB for overlapping proxies. The callback class
/// is called for each proxy that overlaps the supplied AABB.
template <typename T>
@ -106,6 +111,28 @@ public:
template <typename T>
void RayCast(T* callback, const b2RayCastInput& input) const;
/// Validate this tree. For testing.
void Validate() const;
/// Compute the height of the binary tree in O(N) time. Should not be
/// called often.
int32 GetHeight() const;
/// Get the maximum balance of an node in the tree. The balance is the difference
/// in height of the two children of a node.
int32 GetMaxBalance() const;
/// Get the ratio of the sum of the node areas to the root area.
float GetAreaRatio() const;
/// Build an optimal tree. Very expensive. For testing.
void RebuildBottomUp();
/// Shift the world origin. Useful for large worlds.
/// The shift formula is: position -= newOrigin
/// @param newOrigin the new origin with respect to the old origin
void ShiftOrigin(const b2Vec2& newOrigin);
private:
int32 AllocateNode();
@ -114,19 +141,22 @@ private:
void InsertLeaf(int32 node);
void RemoveLeaf(int32 node);
int32 Balance(int32 index);
int32 ComputeHeight() const;
int32 ComputeHeight(int32 nodeId) const;
void ValidateStructure(int32 index) const;
void ValidateMetrics(int32 index) const;
int32 m_root;
b2DynamicTreeNode* m_nodes;
b2TreeNode* m_nodes;
int32 m_nodeCount;
int32 m_nodeCapacity;
int32 m_freeList;
/// This is used incrementally traverse the tree for re-balancing.
uint32 m_path;
int32 m_insertionCount;
};
@ -136,6 +166,18 @@ inline void* b2DynamicTree::GetUserData(int32 proxyId) const
return m_nodes[proxyId].userData;
}
inline bool b2DynamicTree::WasMoved(int32 proxyId) const
{
b2Assert(0 <= proxyId && proxyId < m_nodeCapacity);
return m_nodes[proxyId].moved;
}
inline void b2DynamicTree::ClearMoved(int32 proxyId)
{
b2Assert(0 <= proxyId && proxyId < m_nodeCapacity);
m_nodes[proxyId].moved = false;
}
inline const b2AABB& b2DynamicTree::GetFatAABB(int32 proxyId) const
{
b2Assert(0 <= proxyId && proxyId < m_nodeCapacity);
@ -145,21 +187,18 @@ inline const b2AABB& b2DynamicTree::GetFatAABB(int32 proxyId) const
template <typename T>
inline void b2DynamicTree::Query(T* callback, const b2AABB& aabb) const
{
const int32 k_stackSize = 128;
int32 stack[k_stackSize];
b2GrowableStack<int32, 256> stack;
stack.Push(m_root);
int32 count = 0;
stack[count++] = m_root;
while (count > 0)
while (stack.GetCount() > 0)
{
int32 nodeId = stack[--count];
int32 nodeId = stack.Pop();
if (nodeId == b2_nullNode)
{
continue;
}
const b2DynamicTreeNode* node = m_nodes + nodeId;
const b2TreeNode* node = m_nodes + nodeId;
if (b2TestOverlap(node->aabb, aabb))
{
@ -173,15 +212,8 @@ inline void b2DynamicTree::Query(T* callback, const b2AABB& aabb) const
}
else
{
if (count < k_stackSize)
{
stack[count++] = node->child1;
}
if (count < k_stackSize)
{
stack[count++] = node->child2;
}
stack.Push(node->child1);
stack.Push(node->child2);
}
}
}
@ -203,7 +235,7 @@ inline void b2DynamicTree::RayCast(T* callback, const b2RayCastInput& input) con
// Separating axis for segment (Gino, p80).
// |dot(v, p1 - c)| > dot(|v|, h)
float32 maxFraction = input.maxFraction;
float maxFraction = input.maxFraction;
// Build a bounding box for the segment.
b2AABB segmentAABB;
@ -213,21 +245,18 @@ inline void b2DynamicTree::RayCast(T* callback, const b2RayCastInput& input) con
segmentAABB.upperBound = b2Max(p1, t);
}
const int32 k_stackSize = 128;
int32 stack[k_stackSize];
b2GrowableStack<int32, 256> stack;
stack.Push(m_root);
int32 count = 0;
stack[count++] = m_root;
while (count > 0)
while (stack.GetCount() > 0)
{
int32 nodeId = stack[--count];
int32 nodeId = stack.Pop();
if (nodeId == b2_nullNode)
{
continue;
}
const b2DynamicTreeNode* node = m_nodes + nodeId;
const b2TreeNode* node = m_nodes + nodeId;
if (b2TestOverlap(node->aabb, segmentAABB) == false)
{
@ -238,7 +267,7 @@ inline void b2DynamicTree::RayCast(T* callback, const b2RayCastInput& input) con
// |dot(v, p1 - c)| > dot(|v|, h)
b2Vec2 c = node->aabb.GetCenter();
b2Vec2 h = node->aabb.GetExtents();
float32 separation = b2Abs(b2Dot(v, p1 - c)) - b2Dot(abs_v, h);
float separation = b2Abs(b2Dot(v, p1 - c)) - b2Dot(abs_v, h);
if (separation > 0.0f)
{
continue;
@ -251,7 +280,7 @@ inline void b2DynamicTree::RayCast(T* callback, const b2RayCastInput& input) con
subInput.p2 = input.p2;
subInput.maxFraction = maxFraction;
float32 value = callback->RayCastCallback(subInput, nodeId);
float value = callback->RayCastCallback(subInput, nodeId);
if (value == 0.0f)
{
@ -270,15 +299,8 @@ inline void b2DynamicTree::RayCast(T* callback, const b2RayCastInput& input) con
}
else
{
if (count < k_stackSize)
{
stack[count++] = node->child1;
}
if (count < k_stackSize)
{
stack[count++] = node->child2;
}
stack.Push(node->child1);
stack.Push(node->child2);
}
}
}

View file

@ -0,0 +1,86 @@
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_EDGE_SHAPE_H
#define B2_EDGE_SHAPE_H
#include "b2_api.h"
#include "b2_shape.h"
/// A line segment (edge) shape. These can be connected in chains or loops
/// to other edge shapes. Edges created independently are two-sided and do
/// no provide smooth movement across junctions.
class B2_API b2EdgeShape : public b2Shape
{
public:
b2EdgeShape();
/// Set this as a part of a sequence. Vertex v0 precedes the edge and vertex v3
/// follows. These extra vertices are used to provide smooth movement
/// across junctions. This also makes the collision one-sided. The edge
/// normal points to the right looking from v1 to v2.
void SetOneSided(const b2Vec2& v0, const b2Vec2& v1,const b2Vec2& v2, const b2Vec2& v3);
/// Set this as an isolated edge. Collision is two-sided.
void SetTwoSided(const b2Vec2& v1, const b2Vec2& v2);
/// Implement b2Shape.
b2Shape* Clone(b2BlockAllocator* allocator) const override;
/// @see b2Shape::GetChildCount
int32 GetChildCount() const override;
/// @see b2Shape::TestPoint
bool TestPoint(const b2Transform& transform, const b2Vec2& p) const override;
/// Implement b2Shape.
bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
const b2Transform& transform, int32 childIndex) const override;
/// @see b2Shape::ComputeAABB
void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const override;
/// @see b2Shape::ComputeMass
void ComputeMass(b2MassData* massData, float density) const override;
/// These are the edge vertices
b2Vec2 m_vertex1, m_vertex2;
/// Optional adjacent vertices. These are used for smooth collision.
b2Vec2 m_vertex0, m_vertex3;
/// Uses m_vertex0 and m_vertex3 to create smooth collision.
bool m_oneSided;
};
inline b2EdgeShape::b2EdgeShape()
{
m_type = e_edge;
m_radius = b2_polygonRadius;
m_vertex0.x = 0.0f;
m_vertex0.y = 0.0f;
m_vertex3.x = 0.0f;
m_vertex3.y = 0.0f;
m_oneSided = false;
}
#endif

View file

@ -1,35 +1,48 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_FIXTURE_H
#define B2_FIXTURE_H
#include "b2Body.h"
#include "b2Collision.h"
#include "b2Shape.h"
#include "b2_api.h"
#include "b2_body.h"
#include "b2_collision.h"
#include "b2_shape.h"
class b2BlockAllocator;
class b2Body;
class b2BroadPhase;
class b2Fixture;
/// This holds contact filtering data.
struct b2Filter
struct B2_API b2Filter
{
b2Filter()
{
categoryBits = 0x0001;
maskBits = 0xFFFF;
groupIndex = 0;
}
/// The collision category bits. Normally you would just set one bit.
uint16 categoryBits;
@ -45,39 +58,38 @@ struct b2Filter
/// A fixture definition is used to create a fixture. This class defines an
/// abstract fixture definition. You can reuse fixture definitions safely.
struct b2FixtureDef
struct B2_API b2FixtureDef
{
/// The constructor sets the default fixture definition values.
b2FixtureDef()
{
shape = NULL;
userData = NULL;
shape = nullptr;
friction = 0.2f;
restitution = 0.0f;
restitutionThreshold = 1.0f * b2_lengthUnitsPerMeter;
density = 0.0f;
filter.categoryBits = 0x0001;
filter.maskBits = 0xFFFF;
filter.groupIndex = 0;
isSensor = false;
}
virtual ~b2FixtureDef() {}
/// The shape, this must be set. The shape will be cloned, so you
/// can create the shape on the stack.
const b2Shape* shape;
/// Use this to store application specific fixture data.
void* userData;
b2FixtureUserData userData;
/// The friction coefficient, usually in the range [0,1].
float32 friction;
float friction;
/// The restitution (elasticity) usually in the range [0,1].
float32 restitution;
float restitution;
/// Restitution velocity threshold, usually in m/s. Collisions above this
/// speed have restitution applied (will bounce).
float restitutionThreshold;
/// The density, usually in kg/m^2.
float32 density;
float density;
/// A sensor shape collects contact information but never generates a collision
/// response.
@ -87,13 +99,21 @@ struct b2FixtureDef
b2Filter filter;
};
/// This proxy is used internally to connect fixtures to the broad-phase.
struct B2_API b2FixtureProxy
{
b2AABB aabb;
b2Fixture* fixture;
int32 childIndex;
int32 proxyId;
};
/// A fixture is used to attach a shape to a body for collision detection. A fixture
/// inherits its transform from its parent. Fixtures hold additional non-geometric data
/// such as friction, collision filters, etc.
/// Fixtures are created via b2Body::CreateFixture.
/// @warning you cannot reuse fixtures.
class b2Fixture
class B2_API b2Fixture
{
public:
/// Get the type of the child shape. You can use this to down cast to the concrete shape.
@ -115,12 +135,16 @@ public:
/// Set the contact filtering data. This will not update contacts until the next time
/// step when either parent body is active and awake.
/// This automatically calls Refilter.
void SetFilterData(const b2Filter& filter);
/// Get the contact filtering data.
const b2Filter& GetFilterData() const;
/// Get the parent body of this fixture. This is NULL if the fixture is not attached.
/// Call this if you want to establish collision that was previously disabled by b2ContactFilter::ShouldCollide.
void Refilter();
/// Get the parent body of this fixture. This is nullptr if the fixture is not attached.
/// @return the parent body.
b2Body* GetBody();
const b2Body* GetBody() const;
@ -132,20 +156,17 @@ public:
/// Get the user data that was assigned in the fixture definition. Use this to
/// store your application specific data.
void* GetUserData() const;
/// Set the user data. Use this to store your application specific data.
void SetUserData(void* data);
b2FixtureUserData& GetUserData();
/// Test a point for containment in this fixture.
/// @param xf the shape world transform.
/// @param p a point in world coordinates.
bool TestPoint(const b2Vec2& p) const;
/// Cast a ray against this shape.
/// @param output the ray-cast results.
/// @param input the ray-cast input parameters.
bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input) const;
/// @param childIndex the child shape index (e.g. edge index)
bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, int32 childIndex) const;
/// Get the mass data for this fixture. The mass data is based on the density and
/// the shape. The rotational inertia is about the shape's origin. This operation
@ -154,27 +175,39 @@ public:
/// Set the density of this fixture. This will _not_ automatically adjust the mass
/// of the body. You must call b2Body::ResetMassData to update the body's mass.
void SetDensity(float32 density);
void SetDensity(float density);
/// Get the density of this fixture.
float32 GetDensity() const;
float GetDensity() const;
/// Get the coefficient of friction.
float32 GetFriction() const;
float GetFriction() const;
/// Set the coefficient of friction.
void SetFriction(float32 friction);
/// Set the coefficient of friction. This will _not_ change the friction of
/// existing contacts.
void SetFriction(float friction);
/// Get the coefficient of restitution.
float32 GetRestitution() const;
float GetRestitution() const;
/// Set the coefficient of restitution.
void SetRestitution(float32 restitution);
/// Set the coefficient of restitution. This will _not_ change the restitution of
/// existing contacts.
void SetRestitution(float restitution);
/// Get the restitution velocity threshold.
float GetRestitutionThreshold() const;
/// Set the restitution threshold. This will _not_ change the restitution threshold of
/// existing contacts.
void SetRestitutionThreshold(float threshold);
/// Get the fixture's AABB. This AABB may be enlarge and/or stale.
/// If you need a more accurate AABB, compute it using the shape and
/// the body transform.
const b2AABB& GetAABB() const;
const b2AABB& GetAABB(int32 childIndex) const;
/// Dump this fixture to the log file.
void Dump(int32 bodyIndex);
protected:
@ -184,7 +217,6 @@ protected:
friend class b2ContactManager;
b2Fixture();
~b2Fixture();
// We need separation create/destroy functions from the constructor/destructor because
// the destructor cannot access the allocator (no destructor arguments allowed by C++).
@ -192,29 +224,30 @@ protected:
void Destroy(b2BlockAllocator* allocator);
// These support body activation/deactivation.
void CreateProxy(b2BroadPhase* broadPhase, const b2Transform& xf);
void DestroyProxy(b2BroadPhase* broadPhase);
void CreateProxies(b2BroadPhase* broadPhase, const b2Transform& xf);
void DestroyProxies(b2BroadPhase* broadPhase);
void Synchronize(b2BroadPhase* broadPhase, const b2Transform& xf1, const b2Transform& xf2);
b2AABB m_aabb;
float32 m_density;
float m_density;
b2Fixture* m_next;
b2Body* m_body;
b2Shape* m_shape;
float32 m_friction;
float32 m_restitution;
float m_friction;
float m_restitution;
float m_restitutionThreshold;
b2FixtureProxy* m_proxies;
int32 m_proxyCount;
int32 m_proxyId;
b2Filter m_filter;
bool m_isSensor;
void* m_userData;
b2FixtureUserData m_userData;
};
inline b2Shape::Type b2Fixture::GetType() const
@ -242,16 +275,11 @@ inline const b2Filter& b2Fixture::GetFilterData() const
return m_filter;
}
inline void* b2Fixture::GetUserData() const
inline b2FixtureUserData& b2Fixture::GetUserData()
{
return m_userData;
}
inline void b2Fixture::SetUserData(void* data)
{
m_userData = data;
}
inline b2Body* b2Fixture::GetBody()
{
return m_body;
@ -272,45 +300,55 @@ inline const b2Fixture* b2Fixture::GetNext() const
return m_next;
}
inline void b2Fixture::SetDensity(float32 density)
inline void b2Fixture::SetDensity(float density)
{
b2Assert(b2IsValid(density) && density >= 0.0f);
m_density = density;
}
inline float32 b2Fixture::GetDensity() const
inline float b2Fixture::GetDensity() const
{
return m_density;
}
inline float32 b2Fixture::GetFriction() const
inline float b2Fixture::GetFriction() const
{
return m_friction;
}
inline void b2Fixture::SetFriction(float32 friction)
inline void b2Fixture::SetFriction(float friction)
{
m_friction = friction;
}
inline float32 b2Fixture::GetRestitution() const
inline float b2Fixture::GetRestitution() const
{
return m_restitution;
}
inline void b2Fixture::SetRestitution(float32 restitution)
inline void b2Fixture::SetRestitution(float restitution)
{
m_restitution = restitution;
}
inline float b2Fixture::GetRestitutionThreshold() const
{
return m_restitutionThreshold;
}
inline void b2Fixture::SetRestitutionThreshold(float threshold)
{
m_restitutionThreshold = threshold;
}
inline bool b2Fixture::TestPoint(const b2Vec2& p) const
{
return m_shape->TestPoint(m_body->GetTransform(), p);
}
inline bool b2Fixture::RayCast(b2RayCastOutput* output, const b2RayCastInput& input) const
inline bool b2Fixture::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, int32 childIndex) const
{
return m_shape->RayCast(output, input, m_body->GetTransform());
return m_shape->RayCast(output, input, m_body->GetTransform(), childIndex);
}
inline void b2Fixture::GetMassData(b2MassData* massData) const
@ -318,9 +356,10 @@ inline void b2Fixture::GetMassData(b2MassData* massData) const
m_shape->ComputeMass(massData, m_density);
}
inline const b2AABB& b2Fixture::GetAABB() const
inline const b2AABB& b2Fixture::GetAABB(int32 childIndex) const
{
return m_aabb;
b2Assert(0 <= childIndex && childIndex < m_proxyCount);
return m_proxies[childIndex].aabb;
}
#endif

View file

@ -0,0 +1,124 @@
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_FRICTION_JOINT_H
#define B2_FRICTION_JOINT_H
#include "b2_api.h"
#include "b2_joint.h"
/// Friction joint definition.
struct B2_API b2FrictionJointDef : public b2JointDef
{
b2FrictionJointDef()
{
type = e_frictionJoint;
localAnchorA.SetZero();
localAnchorB.SetZero();
maxForce = 0.0f;
maxTorque = 0.0f;
}
/// Initialize the bodies, anchors, axis, and reference angle using the world
/// anchor and world axis.
void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor);
/// The local anchor point relative to bodyA's origin.
b2Vec2 localAnchorA;
/// The local anchor point relative to bodyB's origin.
b2Vec2 localAnchorB;
/// The maximum friction force in N.
float maxForce;
/// The maximum friction torque in N-m.
float maxTorque;
};
/// Friction joint. This is used for top-down friction.
/// It provides 2D translational friction and angular friction.
class B2_API b2FrictionJoint : public b2Joint
{
public:
b2Vec2 GetAnchorA() const override;
b2Vec2 GetAnchorB() const override;
b2Vec2 GetReactionForce(float inv_dt) const override;
float GetReactionTorque(float inv_dt) const override;
/// The local anchor point relative to bodyA's origin.
const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; }
/// The local anchor point relative to bodyB's origin.
const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; }
/// Set the maximum friction force in N.
void SetMaxForce(float force);
/// Get the maximum friction force in N.
float GetMaxForce() const;
/// Set the maximum friction torque in N*m.
void SetMaxTorque(float torque);
/// Get the maximum friction torque in N*m.
float GetMaxTorque() const;
/// Dump joint to dmLog
void Dump() override;
protected:
friend class b2Joint;
b2FrictionJoint(const b2FrictionJointDef* def);
void InitVelocityConstraints(const b2SolverData& data) override;
void SolveVelocityConstraints(const b2SolverData& data) override;
bool SolvePositionConstraints(const b2SolverData& data) override;
b2Vec2 m_localAnchorA;
b2Vec2 m_localAnchorB;
// Solver shared
b2Vec2 m_linearImpulse;
float m_angularImpulse;
float m_maxForce;
float m_maxTorque;
// Solver temp
int32 m_indexA;
int32 m_indexB;
b2Vec2 m_rA;
b2Vec2 m_rB;
b2Vec2 m_localCenterA;
b2Vec2 m_localCenterB;
float m_invMassA;
float m_invMassB;
float m_invIA;
float m_invIB;
b2Mat22 m_linearMass;
float m_angularMass;
};
#endif

View file

@ -0,0 +1,130 @@
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_GEAR_JOINT_H
#define B2_GEAR_JOINT_H
#include "b2_joint.h"
/// Gear joint definition. This definition requires two existing
/// revolute or prismatic joints (any combination will work).
/// @warning bodyB on the input joints must both be dynamic
struct B2_API b2GearJointDef : public b2JointDef
{
b2GearJointDef()
{
type = e_gearJoint;
joint1 = nullptr;
joint2 = nullptr;
ratio = 1.0f;
}
/// The first revolute/prismatic joint attached to the gear joint.
b2Joint* joint1;
/// The second revolute/prismatic joint attached to the gear joint.
b2Joint* joint2;
/// The gear ratio.
/// @see b2GearJoint for explanation.
float ratio;
};
/// A gear joint is used to connect two joints together. Either joint
/// can be a revolute or prismatic joint. You specify a gear ratio
/// to bind the motions together:
/// coordinate1 + ratio * coordinate2 = constant
/// The ratio can be negative or positive. If one joint is a revolute joint
/// and the other joint is a prismatic joint, then the ratio will have units
/// of length or units of 1/length.
/// @warning You have to manually destroy the gear joint if joint1 or joint2
/// is destroyed.
class B2_API b2GearJoint : public b2Joint
{
public:
b2Vec2 GetAnchorA() const override;
b2Vec2 GetAnchorB() const override;
b2Vec2 GetReactionForce(float inv_dt) const override;
float GetReactionTorque(float inv_dt) const override;
/// Get the first joint.
b2Joint* GetJoint1() { return m_joint1; }
/// Get the second joint.
b2Joint* GetJoint2() { return m_joint2; }
/// Set/Get the gear ratio.
void SetRatio(float ratio);
float GetRatio() const;
/// Dump joint to dmLog
void Dump() override;
protected:
friend class b2Joint;
b2GearJoint(const b2GearJointDef* data);
void InitVelocityConstraints(const b2SolverData& data) override;
void SolveVelocityConstraints(const b2SolverData& data) override;
bool SolvePositionConstraints(const b2SolverData& data) override;
b2Joint* m_joint1;
b2Joint* m_joint2;
b2JointType m_typeA;
b2JointType m_typeB;
// Body A is connected to body C
// Body B is connected to body D
b2Body* m_bodyC;
b2Body* m_bodyD;
// Solver shared
b2Vec2 m_localAnchorA;
b2Vec2 m_localAnchorB;
b2Vec2 m_localAnchorC;
b2Vec2 m_localAnchorD;
b2Vec2 m_localAxisC;
b2Vec2 m_localAxisD;
float m_referenceAngleA;
float m_referenceAngleB;
float m_constant;
float m_ratio;
float m_impulse;
// Solver temp
int32 m_indexA, m_indexB, m_indexC, m_indexD;
b2Vec2 m_lcA, m_lcB, m_lcC, m_lcD;
float m_mA, m_mB, m_mC, m_mD;
float m_iA, m_iB, m_iC, m_iD;
b2Vec2 m_JvAC, m_JvBD;
float m_JwA, m_JwB, m_JwC, m_JwD;
float m_mass;
};
#endif

View file

@ -0,0 +1,91 @@
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_GROWABLE_STACK_H
#define B2_GROWABLE_STACK_H
#include <string.h>
#include "b2_settings.h"
/// This is a growable LIFO stack with an initial capacity of N.
/// If the stack size exceeds the initial capacity, the heap is used
/// to increase the size of the stack.
template <typename T, int32 N>
class b2GrowableStack
{
public:
b2GrowableStack()
{
m_stack = m_array;
m_count = 0;
m_capacity = N;
}
~b2GrowableStack()
{
if (m_stack != m_array)
{
b2Free(m_stack);
m_stack = nullptr;
}
}
void Push(const T& element)
{
if (m_count == m_capacity)
{
T* old = m_stack;
m_capacity *= 2;
m_stack = (T*)b2Alloc(m_capacity * sizeof(T));
memcpy(m_stack, old, m_count * sizeof(T));
if (old != m_array)
{
b2Free(old);
}
}
m_stack[m_count] = element;
++m_count;
}
T Pop()
{
b2Assert(m_count > 0);
--m_count;
return m_stack[m_count];
}
int32 GetCount()
{
return m_count;
}
private:
T* m_stack;
T m_array[N];
int32 m_count;
int32 m_capacity;
};
#endif

View file

@ -0,0 +1,228 @@
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_JOINT_H
#define B2_JOINT_H
#include "b2_api.h"
#include "b2_math.h"
class b2Body;
class b2Draw;
class b2Joint;
struct b2SolverData;
class b2BlockAllocator;
enum b2JointType
{
e_unknownJoint,
e_revoluteJoint,
e_prismaticJoint,
e_distanceJoint,
e_pulleyJoint,
e_mouseJoint,
e_gearJoint,
e_wheelJoint,
e_weldJoint,
e_frictionJoint,
e_ropeJoint,
e_motorJoint
};
struct B2_API b2Jacobian
{
b2Vec2 linear;
float angularA;
float angularB;
};
/// A joint edge is used to connect bodies and joints together
/// in a joint graph where each body is a node and each joint
/// is an edge. A joint edge belongs to a doubly linked list
/// maintained in each attached body. Each joint has two joint
/// nodes, one for each attached body.
struct B2_API b2JointEdge
{
b2Body* other; ///< provides quick access to the other body attached.
b2Joint* joint; ///< the joint
b2JointEdge* prev; ///< the previous joint edge in the body's joint list
b2JointEdge* next; ///< the next joint edge in the body's joint list
};
/// Joint definitions are used to construct joints.
struct B2_API b2JointDef
{
b2JointDef()
{
type = e_unknownJoint;
bodyA = nullptr;
bodyB = nullptr;
collideConnected = false;
}
/// The joint type is set automatically for concrete joint types.
b2JointType type;
/// Use this to attach application specific data to your joints.
b2JointUserData userData;
/// The first attached body.
b2Body* bodyA;
/// The second attached body.
b2Body* bodyB;
/// Set this flag to true if the attached bodies should collide.
bool collideConnected;
};
/// Utility to compute linear stiffness values from frequency and damping ratio
B2_API void b2LinearStiffness(float& stiffness, float& damping,
float frequencyHertz, float dampingRatio,
const b2Body* bodyA, const b2Body* bodyB);
/// Utility to compute rotational stiffness values frequency and damping ratio
B2_API void b2AngularStiffness(float& stiffness, float& damping,
float frequencyHertz, float dampingRatio,
const b2Body* bodyA, const b2Body* bodyB);
/// The base joint class. Joints are used to constraint two bodies together in
/// various fashions. Some joints also feature limits and motors.
class B2_API b2Joint
{
public:
/// Get the type of the concrete joint.
b2JointType GetType() const;
/// Get the first body attached to this joint.
b2Body* GetBodyA();
/// Get the second body attached to this joint.
b2Body* GetBodyB();
/// Get the anchor point on bodyA in world coordinates.
virtual b2Vec2 GetAnchorA() const = 0;
/// Get the anchor point on bodyB in world coordinates.
virtual b2Vec2 GetAnchorB() const = 0;
/// Get the reaction force on bodyB at the joint anchor in Newtons.
virtual b2Vec2 GetReactionForce(float inv_dt) const = 0;
/// Get the reaction torque on bodyB in N*m.
virtual float GetReactionTorque(float inv_dt) const = 0;
/// Get the next joint the world joint list.
b2Joint* GetNext();
const b2Joint* GetNext() const;
/// Get the user data pointer.
b2JointUserData& GetUserData();
/// Short-cut function to determine if either body is enabled.
bool IsEnabled() const;
/// Get collide connected.
/// Note: modifying the collide connect flag won't work correctly because
/// the flag is only checked when fixture AABBs begin to overlap.
bool GetCollideConnected() const;
/// Dump this joint to the log file.
virtual void Dump() { b2Dump("// Dump is not supported for this joint type.\n"); }
/// Shift the origin for any points stored in world coordinates.
virtual void ShiftOrigin(const b2Vec2& newOrigin) { B2_NOT_USED(newOrigin); }
/// Debug draw this joint
virtual void Draw(b2Draw* draw) const;
protected:
friend class b2World;
friend class b2Body;
friend class b2Island;
friend class b2GearJoint;
static b2Joint* Create(const b2JointDef* def, b2BlockAllocator* allocator);
static void Destroy(b2Joint* joint, b2BlockAllocator* allocator);
b2Joint(const b2JointDef* def);
virtual ~b2Joint() {}
virtual void InitVelocityConstraints(const b2SolverData& data) = 0;
virtual void SolveVelocityConstraints(const b2SolverData& data) = 0;
// This returns true if the position errors are within tolerance.
virtual bool SolvePositionConstraints(const b2SolverData& data) = 0;
b2JointType m_type;
b2Joint* m_prev;
b2Joint* m_next;
b2JointEdge m_edgeA;
b2JointEdge m_edgeB;
b2Body* m_bodyA;
b2Body* m_bodyB;
int32 m_index;
bool m_islandFlag;
bool m_collideConnected;
b2JointUserData m_userData;
};
inline b2JointType b2Joint::GetType() const
{
return m_type;
}
inline b2Body* b2Joint::GetBodyA()
{
return m_bodyA;
}
inline b2Body* b2Joint::GetBodyB()
{
return m_bodyB;
}
inline b2Joint* b2Joint::GetNext()
{
return m_next;
}
inline const b2Joint* b2Joint::GetNext() const
{
return m_next;
}
inline b2JointUserData& b2Joint::GetUserData()
{
return m_userData;
}
inline bool b2Joint::GetCollideConnected() const
{
return m_collideConnected;
}
#endif

View file

@ -1,96 +1,68 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_MATH_H
#define B2_MATH_H
#include "b2Settings.h"
#include <math.h>
#include <cmath>
#include <cfloat>
#include <cstddef>
#include <limits>
#include "b2_api.h"
#include "b2_settings.h"
/// This function is used to ensure that a floating point number is
/// not a NaN or infinity.
inline bool b2IsValid(float32 x)
/// This function is used to ensure that a floating point number is not a NaN or infinity.
inline bool b2IsValid(float x)
{
if (x != x)
{
// NaN.
return false;
}
float32 infinity = std::numeric_limits<float32>::infinity();
return -infinity < x && x < infinity;
}
/// This is a approximate yet fast inverse square-root.
inline float32 b2InvSqrt(float32 x)
{
union
{
float32 x;
int32 i;
} convert;
convert.x = x;
float32 xhalf = 0.5f * x;
convert.i = 0x5f3759df - (convert.i >> 1);
x = convert.x;
x = x * (1.5f - xhalf * x * x);
return x;
return isfinite(x);
}
#define b2Sqrt(x) sqrtf(x)
#define b2Atan2(y, x) atan2f(y, x)
inline float32 b2Abs(float32 a)
{
return a > 0.0f ? a : -a;
}
/// A 2D column vector.
struct b2Vec2
struct B2_API b2Vec2
{
/// Default constructor does nothing (for performance).
b2Vec2() {}
/// Construct using coordinates.
b2Vec2(float32 x, float32 y) : x(x), y(y) {}
b2Vec2(float xIn, float yIn) : x(xIn), y(yIn) {}
/// Set this vector to all zeros.
void SetZero() { x = 0.0f; y = 0.0f; }
/// Set this vector to some specified coordinates.
void Set(float32 x_, float32 y_) { x = x_; y = y_; }
void Set(float x_, float y_) { x = x_; y = y_; }
/// Negate this vector.
b2Vec2 operator -() const { b2Vec2 v; v.Set(-x, -y); return v; }
/// Read from and indexed element.
float32 operator () (int32 i) const
float operator () (int32 i) const
{
return (&x)[i];
}
/// Write to an indexed element.
float32& operator () (int32 i)
float& operator () (int32 i)
{
return (&x)[i];
}
@ -100,7 +72,7 @@ struct b2Vec2
{
x += v.x; y += v.y;
}
/// Subtract a vector from this vector.
void operator -= (const b2Vec2& v)
{
@ -108,33 +80,33 @@ struct b2Vec2
}
/// Multiply this vector by a scalar.
void operator *= (float32 a)
void operator *= (float a)
{
x *= a; y *= a;
}
/// Get the length of this vector (the norm).
float32 Length() const
float Length() const
{
return b2Sqrt(x * x + y * y);
}
/// Get the length squared. For performance, use this instead of
/// b2Vec2::Length (if possible).
float32 LengthSquared() const
float LengthSquared() const
{
return x * x + y * y;
}
/// Convert this vector into a unit vector. Returns the length.
float32 Normalize()
float Normalize()
{
float32 length = Length();
float length = Length();
if (length < b2_epsilon)
{
return 0.0f;
}
float32 invLength = 1.0f / length;
float invLength = 1.0f / length;
x *= invLength;
y *= invLength;
@ -147,23 +119,29 @@ struct b2Vec2
return b2IsValid(x) && b2IsValid(y);
}
float32 x, y;
/// Get the skew vector such that dot(skew_vec, other) == cross(vec, other)
b2Vec2 Skew() const
{
return b2Vec2(-y, x);
}
float x, y;
};
/// A 2D column vector with 3 elements.
struct b2Vec3
struct B2_API b2Vec3
{
/// Default constructor does nothing (for performance).
b2Vec3() {}
/// Construct using coordinates.
b2Vec3(float32 x, float32 y, float32 z) : x(x), y(y), z(z) {}
b2Vec3(float xIn, float yIn, float zIn) : x(xIn), y(yIn), z(zIn) {}
/// Set this vector to all zeros.
void SetZero() { x = 0.0f; y = 0.0f; z = 0.0f; }
/// Set this vector to some specified coordinates.
void Set(float32 x_, float32 y_, float32 z_) { x = x_; y = y_; z = z_; }
void Set(float x_, float y_, float z_) { x = x_; y = y_; z = z_; }
/// Negate this vector.
b2Vec3 operator -() const { b2Vec3 v; v.Set(-x, -y, -z); return v; }
@ -181,16 +159,16 @@ struct b2Vec3
}
/// Multiply this vector by a scalar.
void operator *= (float32 s)
void operator *= (float s)
{
x *= s; y *= s; z *= s;
}
float32 x, y, z;
float x, y, z;
};
/// A 2-by-2 matrix. Stored in column-major order.
struct b2Mat22
struct B2_API b2Mat22
{
/// The default constructor does nothing (for performance).
b2Mat22() {}
@ -198,75 +176,49 @@ struct b2Mat22
/// Construct this matrix using columns.
b2Mat22(const b2Vec2& c1, const b2Vec2& c2)
{
col1 = c1;
col2 = c2;
ex = c1;
ey = c2;
}
/// Construct this matrix using scalars.
b2Mat22(float32 a11, float32 a12, float32 a21, float32 a22)
b2Mat22(float a11, float a12, float a21, float a22)
{
col1.x = a11; col1.y = a21;
col2.x = a12; col2.y = a22;
}
/// Construct this matrix using an angle. This matrix becomes
/// an orthonormal rotation matrix.
explicit b2Mat22(float32 angle)
{
// TODO_ERIN compute sin+cos together.
float32 c = cosf(angle), s = sinf(angle);
col1.x = c; col2.x = -s;
col1.y = s; col2.y = c;
ex.x = a11; ex.y = a21;
ey.x = a12; ey.y = a22;
}
/// Initialize this matrix using columns.
void Set(const b2Vec2& c1, const b2Vec2& c2)
{
col1 = c1;
col2 = c2;
}
/// Initialize this matrix using an angle. This matrix becomes
/// an orthonormal rotation matrix.
void Set(float32 angle)
{
float32 c = cosf(angle), s = sinf(angle);
col1.x = c; col2.x = -s;
col1.y = s; col2.y = c;
ex = c1;
ey = c2;
}
/// Set this to the identity matrix.
void SetIdentity()
{
col1.x = 1.0f; col2.x = 0.0f;
col1.y = 0.0f; col2.y = 1.0f;
ex.x = 1.0f; ey.x = 0.0f;
ex.y = 0.0f; ey.y = 1.0f;
}
/// Set this matrix to all zeros.
void SetZero()
{
col1.x = 0.0f; col2.x = 0.0f;
col1.y = 0.0f; col2.y = 0.0f;
}
/// Extract the angle from this matrix (assumed to be
/// a rotation matrix).
float32 GetAngle() const
{
return b2Atan2(col1.y, col1.x);
ex.x = 0.0f; ey.x = 0.0f;
ex.y = 0.0f; ey.y = 0.0f;
}
b2Mat22 GetInverse() const
{
float32 a = col1.x, b = col2.x, c = col1.y, d = col2.y;
float a = ex.x, b = ey.x, c = ex.y, d = ey.y;
b2Mat22 B;
float32 det = a * d - b * c;
float det = a * d - b * c;
if (det != 0.0f)
{
det = 1.0f / det;
}
B.col1.x = det * d; B.col2.x = -det * b;
B.col1.y = -det * c; B.col2.y = det * a;
B.ex.x = det * d; B.ey.x = -det * b;
B.ex.y = -det * c; B.ey.y = det * a;
return B;
}
@ -274,8 +226,8 @@ struct b2Mat22
/// than computing the inverse in one-shot cases.
b2Vec2 Solve(const b2Vec2& b) const
{
float32 a11 = col1.x, a12 = col2.x, a21 = col1.y, a22 = col2.y;
float32 det = a11 * a22 - a12 * a21;
float a11 = ex.x, a12 = ey.x, a21 = ex.y, a22 = ey.y;
float det = a11 * a22 - a12 * a21;
if (det != 0.0f)
{
det = 1.0f / det;
@ -286,11 +238,11 @@ struct b2Mat22
return x;
}
b2Vec2 col1, col2;
b2Vec2 ex, ey;
};
/// A 3-by-3 matrix. Stored in column-major order.
struct b2Mat33
struct B2_API b2Mat33
{
/// The default constructor does nothing (for performance).
b2Mat33() {}
@ -298,17 +250,17 @@ struct b2Mat33
/// Construct this matrix using columns.
b2Mat33(const b2Vec3& c1, const b2Vec3& c2, const b2Vec3& c3)
{
col1 = c1;
col2 = c2;
col3 = c3;
ex = c1;
ey = c2;
ez = c3;
}
/// Set this matrix to all zeros.
void SetZero()
{
col1.SetZero();
col2.SetZero();
col3.SetZero();
ex.SetZero();
ey.SetZero();
ez.SetZero();
}
/// Solve A * x = b, where b is a column vector. This is more efficient
@ -320,92 +272,147 @@ struct b2Mat33
/// 2-by-2 matrix equation.
b2Vec2 Solve22(const b2Vec2& b) const;
b2Vec3 col1, col2, col3;
/// Get the inverse of this matrix as a 2-by-2.
/// Returns the zero matrix if singular.
void GetInverse22(b2Mat33* M) const;
/// Get the symmetric inverse of this matrix as a 3-by-3.
/// Returns the zero matrix if singular.
void GetSymInverse33(b2Mat33* M) const;
b2Vec3 ex, ey, ez;
};
/// Rotation
struct B2_API b2Rot
{
b2Rot() {}
/// Initialize from an angle in radians
explicit b2Rot(float angle)
{
/// TODO_ERIN optimize
s = sinf(angle);
c = cosf(angle);
}
/// Set using an angle in radians.
void Set(float angle)
{
/// TODO_ERIN optimize
s = sinf(angle);
c = cosf(angle);
}
/// Set to the identity rotation
void SetIdentity()
{
s = 0.0f;
c = 1.0f;
}
/// Get the angle in radians
float GetAngle() const
{
return b2Atan2(s, c);
}
/// Get the x-axis
b2Vec2 GetXAxis() const
{
return b2Vec2(c, s);
}
/// Get the u-axis
b2Vec2 GetYAxis() const
{
return b2Vec2(-s, c);
}
/// Sine and cosine
float s, c;
};
/// A transform contains translation and rotation. It is used to represent
/// the position and orientation of rigid frames.
struct b2Transform
struct B2_API b2Transform
{
/// The default constructor does nothing (for performance).
/// The default constructor does nothing.
b2Transform() {}
/// Initialize using a position vector and a rotation matrix.
b2Transform(const b2Vec2& position, const b2Mat22& R) : position(position), R(R) {}
/// Initialize using a position vector and a rotation.
b2Transform(const b2Vec2& position, const b2Rot& rotation) : p(position), q(rotation) {}
/// Set this to the identity transform.
void SetIdentity()
{
position.SetZero();
R.SetIdentity();
p.SetZero();
q.SetIdentity();
}
/// Set this based on the position and angle.
void Set(const b2Vec2& p, float32 angle)
void Set(const b2Vec2& position, float angle)
{
position = p;
R.Set(angle);
p = position;
q.Set(angle);
}
/// Calculate the angle that the rotation matrix represents.
float32 GetAngle() const
{
return b2Atan2(R.col1.y, R.col1.x);
}
b2Vec2 position;
b2Mat22 R;
b2Vec2 p;
b2Rot q;
};
/// This describes the motion of a body/shape for TOI computation.
/// Shapes are defined with respect to the body origin, which may
/// no coincide with the center of mass. However, to support dynamics
/// we must interpolate the center of mass position.
struct b2Sweep
struct B2_API b2Sweep
{
/// Get the interpolated transform at a specific time.
/// @param alpha is a factor in [0,1], where 0 indicates t0.
void GetTransform(b2Transform* xf, float32 alpha) const;
/// @param transform the output transform
/// @param beta is a factor in [0,1], where 0 indicates alpha0.
void GetTransform(b2Transform* transform, float beta) const;
/// Advance the sweep forward, yielding a new initial state.
/// @param t the new initial time.
void Advance(float32 t);
/// @param alpha the new initial time.
void Advance(float alpha);
/// Normalize the angles.
void Normalize();
b2Vec2 localCenter; ///< local center of mass position
b2Vec2 c0, c; ///< center world positions
float32 a0, a; ///< world angles
float a0, a; ///< world angles
/// Fraction of the current time step in the range [0,1]
/// c0 and a0 are the positions at alpha0.
float alpha0;
};
extern const b2Vec2 b2Vec2_zero;
extern const b2Mat22 b2Mat22_identity;
extern const b2Transform b2Transform_identity;
/// Useful constant
extern B2_API const b2Vec2 b2Vec2_zero;
/// Perform the dot product on two vectors.
inline float32 b2Dot(const b2Vec2& a, const b2Vec2& b)
inline float b2Dot(const b2Vec2& a, const b2Vec2& b)
{
return a.x * b.x + a.y * b.y;
}
/// Perform the cross product on two vectors. In 2D this produces a scalar.
inline float32 b2Cross(const b2Vec2& a, const b2Vec2& b)
inline float b2Cross(const b2Vec2& a, const b2Vec2& b)
{
return a.x * b.y - a.y * b.x;
}
/// Perform the cross product on a vector and a scalar. In 2D this produces
/// a vector.
inline b2Vec2 b2Cross(const b2Vec2& a, float32 s)
inline b2Vec2 b2Cross(const b2Vec2& a, float s)
{
return b2Vec2(s * a.y, -s * a.x);
}
/// Perform the cross product on a scalar and a vector. In 2D this produces
/// a vector.
inline b2Vec2 b2Cross(float32 s, const b2Vec2& a)
inline b2Vec2 b2Cross(float s, const b2Vec2& a)
{
return b2Vec2(-s * a.y, s * a.x);
}
@ -414,14 +421,14 @@ inline b2Vec2 b2Cross(float32 s, const b2Vec2& a)
/// then this transforms the vector from one frame to another.
inline b2Vec2 b2Mul(const b2Mat22& A, const b2Vec2& v)
{
return b2Vec2(A.col1.x * v.x + A.col2.x * v.y, A.col1.y * v.x + A.col2.y * v.y);
return b2Vec2(A.ex.x * v.x + A.ey.x * v.y, A.ex.y * v.x + A.ey.y * v.y);
}
/// Multiply a matrix transpose times a vector. If a rotation matrix is provided,
/// then this transforms the vector from one frame to another (inverse transform).
inline b2Vec2 b2MulT(const b2Mat22& A, const b2Vec2& v)
{
return b2Vec2(b2Dot(v, A.col1), b2Dot(v, A.col2));
return b2Vec2(b2Dot(v, A.ex), b2Dot(v, A.ey));
}
/// Add two vectors component-wise.
@ -436,7 +443,7 @@ inline b2Vec2 operator - (const b2Vec2& a, const b2Vec2& b)
return b2Vec2(a.x - b.x, a.y - b.y);
}
inline b2Vec2 operator * (float32 s, const b2Vec2& a)
inline b2Vec2 operator * (float s, const b2Vec2& a)
{
return b2Vec2(s * a.x, s * a.y);
}
@ -446,19 +453,24 @@ inline bool operator == (const b2Vec2& a, const b2Vec2& b)
return a.x == b.x && a.y == b.y;
}
inline float32 b2Distance(const b2Vec2& a, const b2Vec2& b)
inline bool operator != (const b2Vec2& a, const b2Vec2& b)
{
return a.x != b.x || a.y != b.y;
}
inline float b2Distance(const b2Vec2& a, const b2Vec2& b)
{
b2Vec2 c = a - b;
return c.Length();
}
inline float32 b2DistanceSquared(const b2Vec2& a, const b2Vec2& b)
inline float b2DistanceSquared(const b2Vec2& a, const b2Vec2& b)
{
b2Vec2 c = a - b;
return b2Dot(c, c);
}
inline b2Vec3 operator * (float32 s, const b2Vec3& a)
inline b2Vec3 operator * (float s, const b2Vec3& a)
{
return b2Vec3(s * a.x, s * a.y, s * a.z);
}
@ -476,7 +488,7 @@ inline b2Vec3 operator - (const b2Vec3& a, const b2Vec3& b)
}
/// Perform the dot product on two vectors.
inline float32 b2Dot(const b2Vec3& a, const b2Vec3& b)
inline float b2Dot(const b2Vec3& a, const b2Vec3& b)
{
return a.x * b.x + a.y * b.y + a.z * b.z;
}
@ -489,40 +501,115 @@ inline b2Vec3 b2Cross(const b2Vec3& a, const b2Vec3& b)
inline b2Mat22 operator + (const b2Mat22& A, const b2Mat22& B)
{
return b2Mat22(A.col1 + B.col1, A.col2 + B.col2);
return b2Mat22(A.ex + B.ex, A.ey + B.ey);
}
// A * B
inline b2Mat22 b2Mul(const b2Mat22& A, const b2Mat22& B)
{
return b2Mat22(b2Mul(A, B.col1), b2Mul(A, B.col2));
return b2Mat22(b2Mul(A, B.ex), b2Mul(A, B.ey));
}
// A^T * B
inline b2Mat22 b2MulT(const b2Mat22& A, const b2Mat22& B)
{
b2Vec2 c1(b2Dot(A.col1, B.col1), b2Dot(A.col2, B.col1));
b2Vec2 c2(b2Dot(A.col1, B.col2), b2Dot(A.col2, B.col2));
b2Vec2 c1(b2Dot(A.ex, B.ex), b2Dot(A.ey, B.ex));
b2Vec2 c2(b2Dot(A.ex, B.ey), b2Dot(A.ey, B.ey));
return b2Mat22(c1, c2);
}
/// Multiply a matrix times a vector.
inline b2Vec3 b2Mul(const b2Mat33& A, const b2Vec3& v)
{
return v.x * A.col1 + v.y * A.col2 + v.z * A.col3;
return v.x * A.ex + v.y * A.ey + v.z * A.ez;
}
/// Multiply a matrix times a vector.
inline b2Vec2 b2Mul22(const b2Mat33& A, const b2Vec2& v)
{
return b2Vec2(A.ex.x * v.x + A.ey.x * v.y, A.ex.y * v.x + A.ey.y * v.y);
}
/// Multiply two rotations: q * r
inline b2Rot b2Mul(const b2Rot& q, const b2Rot& r)
{
// [qc -qs] * [rc -rs] = [qc*rc-qs*rs -qc*rs-qs*rc]
// [qs qc] [rs rc] [qs*rc+qc*rs -qs*rs+qc*rc]
// s = qs * rc + qc * rs
// c = qc * rc - qs * rs
b2Rot qr;
qr.s = q.s * r.c + q.c * r.s;
qr.c = q.c * r.c - q.s * r.s;
return qr;
}
/// Transpose multiply two rotations: qT * r
inline b2Rot b2MulT(const b2Rot& q, const b2Rot& r)
{
// [ qc qs] * [rc -rs] = [qc*rc+qs*rs -qc*rs+qs*rc]
// [-qs qc] [rs rc] [-qs*rc+qc*rs qs*rs+qc*rc]
// s = qc * rs - qs * rc
// c = qc * rc + qs * rs
b2Rot qr;
qr.s = q.c * r.s - q.s * r.c;
qr.c = q.c * r.c + q.s * r.s;
return qr;
}
/// Rotate a vector
inline b2Vec2 b2Mul(const b2Rot& q, const b2Vec2& v)
{
return b2Vec2(q.c * v.x - q.s * v.y, q.s * v.x + q.c * v.y);
}
/// Inverse rotate a vector
inline b2Vec2 b2MulT(const b2Rot& q, const b2Vec2& v)
{
return b2Vec2(q.c * v.x + q.s * v.y, -q.s * v.x + q.c * v.y);
}
inline b2Vec2 b2Mul(const b2Transform& T, const b2Vec2& v)
{
float32 x = T.position.x + T.R.col1.x * v.x + T.R.col2.x * v.y;
float32 y = T.position.y + T.R.col1.y * v.x + T.R.col2.y * v.y;
float x = (T.q.c * v.x - T.q.s * v.y) + T.p.x;
float y = (T.q.s * v.x + T.q.c * v.y) + T.p.y;
return b2Vec2(x, y);
}
inline b2Vec2 b2MulT(const b2Transform& T, const b2Vec2& v)
{
return b2MulT(T.R, v - T.position);
float px = v.x - T.p.x;
float py = v.y - T.p.y;
float x = (T.q.c * px + T.q.s * py);
float y = (-T.q.s * px + T.q.c * py);
return b2Vec2(x, y);
}
// v2 = A.q.Rot(B.q.Rot(v1) + B.p) + A.p
// = (A.q * B.q).Rot(v1) + A.q.Rot(B.p) + A.p
inline b2Transform b2Mul(const b2Transform& A, const b2Transform& B)
{
b2Transform C;
C.q = b2Mul(A.q, B.q);
C.p = b2Mul(A.q, B.p) + A.p;
return C;
}
// v2 = A.q' * (B.q * v1 + B.p - A.p)
// = A.q' * B.q * v1 + A.q' * (B.p - A.p)
inline b2Transform b2MulT(const b2Transform& A, const b2Transform& B)
{
b2Transform C;
C.q = b2MulT(A.q, B.q);
C.p = b2MulT(A.q, B.p - A.p);
return C;
}
template <typename T>
inline T b2Abs(T a)
{
return a > T(0) ? a : -a;
}
inline b2Vec2 b2Abs(const b2Vec2& a)
@ -532,7 +619,7 @@ inline b2Vec2 b2Abs(const b2Vec2& a)
inline b2Mat22 b2Abs(const b2Mat22& A)
{
return b2Mat22(b2Abs(A.col1), b2Abs(A.col2));
return b2Mat22(b2Abs(A.ex), b2Abs(A.ey));
}
template <typename T>
@ -596,27 +683,31 @@ inline bool b2IsPowerOfTwo(uint32 x)
return result;
}
inline void b2Sweep::GetTransform(b2Transform* xf, float32 alpha) const
// https://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/
inline void b2Sweep::GetTransform(b2Transform* xf, float beta) const
{
xf->position = (1.0f - alpha) * c0 + alpha * c;
float32 angle = (1.0f - alpha) * a0 + alpha * a;
xf->R.Set(angle);
xf->p = (1.0f - beta) * c0 + beta * c;
float angle = (1.0f - beta) * a0 + beta * a;
xf->q.Set(angle);
// Shift to origin
xf->position -= b2Mul(xf->R, localCenter);
xf->p -= b2Mul(xf->q, localCenter);
}
inline void b2Sweep::Advance(float32 t)
inline void b2Sweep::Advance(float alpha)
{
c0 = (1.0f - t) * c0 + t * c;
a0 = (1.0f - t) * a0 + t * a;
b2Assert(alpha0 < 1.0f);
float beta = (alpha - alpha0) / (1.0f - alpha0);
c0 += beta * (c - c0);
a0 += beta * (a - a0);
alpha0 = alpha;
}
/// Normalize an angle in radians to be between -pi and pi
inline void b2Sweep::Normalize()
{
float32 twoPi = 2.0f * b2_pi;
float32 d = twoPi * floorf(a0 / twoPi);
float twoPi = 2.0f * b2_pi;
float d = twoPi * floorf(a0 / twoPi);
a0 -= d;
a -= d;
}

View file

@ -0,0 +1,138 @@
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_MOTOR_JOINT_H
#define B2_MOTOR_JOINT_H
#include "b2_api.h"
#include "b2_joint.h"
/// Motor joint definition.
struct B2_API b2MotorJointDef : public b2JointDef
{
b2MotorJointDef()
{
type = e_motorJoint;
linearOffset.SetZero();
angularOffset = 0.0f;
maxForce = 1.0f;
maxTorque = 1.0f;
correctionFactor = 0.3f;
}
/// Initialize the bodies and offsets using the current transforms.
void Initialize(b2Body* bodyA, b2Body* bodyB);
/// Position of bodyB minus the position of bodyA, in bodyA's frame, in meters.
b2Vec2 linearOffset;
/// The bodyB angle minus bodyA angle in radians.
float angularOffset;
/// The maximum motor force in N.
float maxForce;
/// The maximum motor torque in N-m.
float maxTorque;
/// Position correction factor in the range [0,1].
float correctionFactor;
};
/// A motor joint is used to control the relative motion
/// between two bodies. A typical usage is to control the movement
/// of a dynamic body with respect to the ground.
class B2_API b2MotorJoint : public b2Joint
{
public:
b2Vec2 GetAnchorA() const override;
b2Vec2 GetAnchorB() const override;
b2Vec2 GetReactionForce(float inv_dt) const override;
float GetReactionTorque(float inv_dt) const override;
/// Set/get the target linear offset, in frame A, in meters.
void SetLinearOffset(const b2Vec2& linearOffset);
const b2Vec2& GetLinearOffset() const;
/// Set/get the target angular offset, in radians.
void SetAngularOffset(float angularOffset);
float GetAngularOffset() const;
/// Set the maximum friction force in N.
void SetMaxForce(float force);
/// Get the maximum friction force in N.
float GetMaxForce() const;
/// Set the maximum friction torque in N*m.
void SetMaxTorque(float torque);
/// Get the maximum friction torque in N*m.
float GetMaxTorque() const;
/// Set the position correction factor in the range [0,1].
void SetCorrectionFactor(float factor);
/// Get the position correction factor in the range [0,1].
float GetCorrectionFactor() const;
/// Dump to b2Log
void Dump() override;
protected:
friend class b2Joint;
b2MotorJoint(const b2MotorJointDef* def);
void InitVelocityConstraints(const b2SolverData& data) override;
void SolveVelocityConstraints(const b2SolverData& data) override;
bool SolvePositionConstraints(const b2SolverData& data) override;
// Solver shared
b2Vec2 m_linearOffset;
float m_angularOffset;
b2Vec2 m_linearImpulse;
float m_angularImpulse;
float m_maxForce;
float m_maxTorque;
float m_correctionFactor;
// Solver temp
int32 m_indexA;
int32 m_indexB;
b2Vec2 m_rA;
b2Vec2 m_rB;
b2Vec2 m_localCenterA;
b2Vec2 m_localCenterB;
b2Vec2 m_linearError;
float m_angularError;
float m_invMassA;
float m_invMassB;
float m_invIA;
float m_invIB;
b2Mat22 m_linearMass;
float m_angularMass;
};
#endif

View file

@ -0,0 +1,134 @@
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_MOUSE_JOINT_H
#define B2_MOUSE_JOINT_H
#include "b2_api.h"
#include "b2_joint.h"
/// Mouse joint definition. This requires a world target point,
/// tuning parameters, and the time step.
struct B2_API b2MouseJointDef : public b2JointDef
{
b2MouseJointDef()
{
type = e_mouseJoint;
target.Set(0.0f, 0.0f);
maxForce = 0.0f;
stiffness = 0.0f;
damping = 0.0f;
}
/// The initial world target point. This is assumed
/// to coincide with the body anchor initially.
b2Vec2 target;
/// The maximum constraint force that can be exerted
/// to move the candidate body. Usually you will express
/// as some multiple of the weight (multiplier * mass * gravity).
float maxForce;
/// The linear stiffness in N/m
float stiffness;
/// The linear damping in N*s/m
float damping;
};
/// A mouse joint is used to make a point on a body track a
/// specified world point. This a soft constraint with a maximum
/// force. This allows the constraint to stretch and without
/// applying huge forces.
/// NOTE: this joint is not documented in the manual because it was
/// developed to be used in the testbed. If you want to learn how to
/// use the mouse joint, look at the testbed.
class B2_API b2MouseJoint : public b2Joint
{
public:
/// Implements b2Joint.
b2Vec2 GetAnchorA() const override;
/// Implements b2Joint.
b2Vec2 GetAnchorB() const override;
/// Implements b2Joint.
b2Vec2 GetReactionForce(float inv_dt) const override;
/// Implements b2Joint.
float GetReactionTorque(float inv_dt) const override;
/// Use this to update the target point.
void SetTarget(const b2Vec2& target);
const b2Vec2& GetTarget() const;
/// Set/get the maximum force in Newtons.
void SetMaxForce(float force);
float GetMaxForce() const;
/// Set/get the linear stiffness in N/m
void SetStiffness(float stiffness) { m_stiffness = stiffness; }
float GetStiffness() const { return m_stiffness; }
/// Set/get linear damping in N*s/m
void SetDamping(float damping) { m_damping = damping; }
float GetDamping() const { return m_damping; }
/// The mouse joint does not support dumping.
void Dump() override { b2Log("Mouse joint dumping is not supported.\n"); }
/// Implement b2Joint::ShiftOrigin
void ShiftOrigin(const b2Vec2& newOrigin) override;
protected:
friend class b2Joint;
b2MouseJoint(const b2MouseJointDef* def);
void InitVelocityConstraints(const b2SolverData& data) override;
void SolveVelocityConstraints(const b2SolverData& data) override;
bool SolvePositionConstraints(const b2SolverData& data) override;
b2Vec2 m_localAnchorB;
b2Vec2 m_targetA;
float m_stiffness;
float m_damping;
float m_beta;
// Solver shared
b2Vec2 m_impulse;
float m_maxForce;
float m_gamma;
// Solver temp
int32 m_indexA;
int32 m_indexB;
b2Vec2 m_rB;
b2Vec2 m_localCenterB;
float m_invMassB;
float m_invIB;
b2Mat22 m_mass;
b2Vec2 m_C;
};
#endif

View file

@ -0,0 +1,95 @@
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_POLYGON_SHAPE_H
#define B2_POLYGON_SHAPE_H
#include "b2_api.h"
#include "b2_shape.h"
/// A solid convex polygon. It is assumed that the interior of the polygon is to
/// the left of each edge.
/// Polygons have a maximum number of vertices equal to b2_maxPolygonVertices.
/// In most cases you should not need many vertices for a convex polygon.
class B2_API b2PolygonShape : public b2Shape
{
public:
b2PolygonShape();
/// Implement b2Shape.
b2Shape* Clone(b2BlockAllocator* allocator) const override;
/// @see b2Shape::GetChildCount
int32 GetChildCount() const override;
/// Create a convex hull from the given array of local points.
/// The count must be in the range [3, b2_maxPolygonVertices].
/// @warning the points may be re-ordered, even if they form a convex polygon
/// @warning collinear points are handled but not removed. Collinear points
/// may lead to poor stacking behavior.
void Set(const b2Vec2* points, int32 count);
/// Build vertices to represent an axis-aligned box centered on the local origin.
/// @param hx the half-width.
/// @param hy the half-height.
void SetAsBox(float hx, float hy);
/// Build vertices to represent an oriented box.
/// @param hx the half-width.
/// @param hy the half-height.
/// @param center the center of the box in local coordinates.
/// @param angle the rotation of the box in local coordinates.
void SetAsBox(float hx, float hy, const b2Vec2& center, float angle);
/// @see b2Shape::TestPoint
bool TestPoint(const b2Transform& transform, const b2Vec2& p) const override;
/// Implement b2Shape.
/// @note because the polygon is solid, rays that start inside do not hit because the normal is
/// not defined.
bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
const b2Transform& transform, int32 childIndex) const override;
/// @see b2Shape::ComputeAABB
void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const override;
/// @see b2Shape::ComputeMass
void ComputeMass(b2MassData* massData, float density) const override;
/// Validate convexity. This is a very time consuming operation.
/// @returns true if valid
bool Validate() const;
b2Vec2 m_centroid;
b2Vec2 m_vertices[b2_maxPolygonVertices];
b2Vec2 m_normals[b2_maxPolygonVertices];
int32 m_count;
};
inline b2PolygonShape::b2PolygonShape()
{
m_type = e_polygon;
m_radius = b2_polygonRadius;
m_count = 0;
m_centroid.SetZero();
}
#endif

View file

@ -0,0 +1,205 @@
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_PRISMATIC_JOINT_H
#define B2_PRISMATIC_JOINT_H
#include "b2_api.h"
#include "b2_joint.h"
/// Prismatic joint definition. This requires defining a line of
/// motion using an axis and an anchor point. The definition uses local
/// anchor points and a local axis so that the initial configuration
/// can violate the constraint slightly. The joint translation is zero
/// when the local anchor points coincide in world space. Using local
/// anchors and a local axis helps when saving and loading a game.
struct B2_API b2PrismaticJointDef : public b2JointDef
{
b2PrismaticJointDef()
{
type = e_prismaticJoint;
localAnchorA.SetZero();
localAnchorB.SetZero();
localAxisA.Set(1.0f, 0.0f);
referenceAngle = 0.0f;
enableLimit = false;
lowerTranslation = 0.0f;
upperTranslation = 0.0f;
enableMotor = false;
maxMotorForce = 0.0f;
motorSpeed = 0.0f;
}
/// Initialize the bodies, anchors, axis, and reference angle using the world
/// anchor and unit world axis.
void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor, const b2Vec2& axis);
/// The local anchor point relative to bodyA's origin.
b2Vec2 localAnchorA;
/// The local anchor point relative to bodyB's origin.
b2Vec2 localAnchorB;
/// The local translation unit axis in bodyA.
b2Vec2 localAxisA;
/// The constrained angle between the bodies: bodyB_angle - bodyA_angle.
float referenceAngle;
/// Enable/disable the joint limit.
bool enableLimit;
/// The lower translation limit, usually in meters.
float lowerTranslation;
/// The upper translation limit, usually in meters.
float upperTranslation;
/// Enable/disable the joint motor.
bool enableMotor;
/// The maximum motor torque, usually in N-m.
float maxMotorForce;
/// The desired motor speed in radians per second.
float motorSpeed;
};
/// A prismatic joint. This joint provides one degree of freedom: translation
/// along an axis fixed in bodyA. Relative rotation is prevented. You can
/// use a joint limit to restrict the range of motion and a joint motor to
/// drive the motion or to model joint friction.
class B2_API b2PrismaticJoint : public b2Joint
{
public:
b2Vec2 GetAnchorA() const override;
b2Vec2 GetAnchorB() const override;
b2Vec2 GetReactionForce(float inv_dt) const override;
float GetReactionTorque(float inv_dt) const override;
/// The local anchor point relative to bodyA's origin.
const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; }
/// The local anchor point relative to bodyB's origin.
const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; }
/// The local joint axis relative to bodyA.
const b2Vec2& GetLocalAxisA() const { return m_localXAxisA; }
/// Get the reference angle.
float GetReferenceAngle() const { return m_referenceAngle; }
/// Get the current joint translation, usually in meters.
float GetJointTranslation() const;
/// Get the current joint translation speed, usually in meters per second.
float GetJointSpeed() const;
/// Is the joint limit enabled?
bool IsLimitEnabled() const;
/// Enable/disable the joint limit.
void EnableLimit(bool flag);
/// Get the lower joint limit, usually in meters.
float GetLowerLimit() const;
/// Get the upper joint limit, usually in meters.
float GetUpperLimit() const;
/// Set the joint limits, usually in meters.
void SetLimits(float lower, float upper);
/// Is the joint motor enabled?
bool IsMotorEnabled() const;
/// Enable/disable the joint motor.
void EnableMotor(bool flag);
/// Set the motor speed, usually in meters per second.
void SetMotorSpeed(float speed);
/// Get the motor speed, usually in meters per second.
float GetMotorSpeed() const;
/// Set the maximum motor force, usually in N.
void SetMaxMotorForce(float force);
float GetMaxMotorForce() const { return m_maxMotorForce; }
/// Get the current motor force given the inverse time step, usually in N.
float GetMotorForce(float inv_dt) const;
/// Dump to b2Log
void Dump() override;
///
void Draw(b2Draw* draw) const override;
protected:
friend class b2Joint;
friend class b2GearJoint;
b2PrismaticJoint(const b2PrismaticJointDef* def);
void InitVelocityConstraints(const b2SolverData& data) override;
void SolveVelocityConstraints(const b2SolverData& data) override;
bool SolvePositionConstraints(const b2SolverData& data) override;
b2Vec2 m_localAnchorA;
b2Vec2 m_localAnchorB;
b2Vec2 m_localXAxisA;
b2Vec2 m_localYAxisA;
float m_referenceAngle;
b2Vec2 m_impulse;
float m_motorImpulse;
float m_lowerImpulse;
float m_upperImpulse;
float m_lowerTranslation;
float m_upperTranslation;
float m_maxMotorForce;
float m_motorSpeed;
bool m_enableLimit;
bool m_enableMotor;
// Solver temp
int32 m_indexA;
int32 m_indexB;
b2Vec2 m_localCenterA;
b2Vec2 m_localCenterB;
float m_invMassA;
float m_invMassB;
float m_invIA;
float m_invIB;
b2Vec2 m_axis, m_perp;
float m_s1, m_s2;
float m_a1, m_a2;
b2Mat22 m_K;
float m_translation;
float m_axialMass;
};
inline float b2PrismaticJoint::GetMotorSpeed() const
{
return m_motorSpeed;
}
#endif

View file

@ -0,0 +1,157 @@
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_PULLEY_JOINT_H
#define B2_PULLEY_JOINT_H
#include "b2_api.h"
#include "b2_joint.h"
const float b2_minPulleyLength = 2.0f;
/// Pulley joint definition. This requires two ground anchors,
/// two dynamic body anchor points, and a pulley ratio.
struct B2_API b2PulleyJointDef : public b2JointDef
{
b2PulleyJointDef()
{
type = e_pulleyJoint;
groundAnchorA.Set(-1.0f, 1.0f);
groundAnchorB.Set(1.0f, 1.0f);
localAnchorA.Set(-1.0f, 0.0f);
localAnchorB.Set(1.0f, 0.0f);
lengthA = 0.0f;
lengthB = 0.0f;
ratio = 1.0f;
collideConnected = true;
}
/// Initialize the bodies, anchors, lengths, max lengths, and ratio using the world anchors.
void Initialize(b2Body* bodyA, b2Body* bodyB,
const b2Vec2& groundAnchorA, const b2Vec2& groundAnchorB,
const b2Vec2& anchorA, const b2Vec2& anchorB,
float ratio);
/// The first ground anchor in world coordinates. This point never moves.
b2Vec2 groundAnchorA;
/// The second ground anchor in world coordinates. This point never moves.
b2Vec2 groundAnchorB;
/// The local anchor point relative to bodyA's origin.
b2Vec2 localAnchorA;
/// The local anchor point relative to bodyB's origin.
b2Vec2 localAnchorB;
/// The a reference length for the segment attached to bodyA.
float lengthA;
/// The a reference length for the segment attached to bodyB.
float lengthB;
/// The pulley ratio, used to simulate a block-and-tackle.
float ratio;
};
/// The pulley joint is connected to two bodies and two fixed ground points.
/// The pulley supports a ratio such that:
/// length1 + ratio * length2 <= constant
/// Yes, the force transmitted is scaled by the ratio.
/// Warning: the pulley joint can get a bit squirrelly by itself. They often
/// work better when combined with prismatic joints. You should also cover the
/// the anchor points with static shapes to prevent one side from going to
/// zero length.
class B2_API b2PulleyJoint : public b2Joint
{
public:
b2Vec2 GetAnchorA() const override;
b2Vec2 GetAnchorB() const override;
b2Vec2 GetReactionForce(float inv_dt) const override;
float GetReactionTorque(float inv_dt) const override;
/// Get the first ground anchor.
b2Vec2 GetGroundAnchorA() const;
/// Get the second ground anchor.
b2Vec2 GetGroundAnchorB() const;
/// Get the current length of the segment attached to bodyA.
float GetLengthA() const;
/// Get the current length of the segment attached to bodyB.
float GetLengthB() const;
/// Get the pulley ratio.
float GetRatio() const;
/// Get the current length of the segment attached to bodyA.
float GetCurrentLengthA() const;
/// Get the current length of the segment attached to bodyB.
float GetCurrentLengthB() const;
/// Dump joint to dmLog
void Dump() override;
/// Implement b2Joint::ShiftOrigin
void ShiftOrigin(const b2Vec2& newOrigin) override;
protected:
friend class b2Joint;
b2PulleyJoint(const b2PulleyJointDef* data);
void InitVelocityConstraints(const b2SolverData& data) override;
void SolveVelocityConstraints(const b2SolverData& data) override;
bool SolvePositionConstraints(const b2SolverData& data) override;
b2Vec2 m_groundAnchorA;
b2Vec2 m_groundAnchorB;
float m_lengthA;
float m_lengthB;
// Solver shared
b2Vec2 m_localAnchorA;
b2Vec2 m_localAnchorB;
float m_constant;
float m_ratio;
float m_impulse;
// Solver temp
int32 m_indexA;
int32 m_indexB;
b2Vec2 m_uA;
b2Vec2 m_uB;
b2Vec2 m_rA;
b2Vec2 m_rB;
b2Vec2 m_localCenterA;
b2Vec2 m_localCenterB;
float m_invMassA;
float m_invMassB;
float m_invIA;
float m_invIB;
float m_mass;
};
#endif

View file

@ -0,0 +1,211 @@
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_REVOLUTE_JOINT_H
#define B2_REVOLUTE_JOINT_H
#include "b2_api.h"
#include "b2_joint.h"
/// Revolute joint definition. This requires defining an anchor point where the
/// bodies are joined. The definition uses local anchor points so that the
/// initial configuration can violate the constraint slightly. You also need to
/// specify the initial relative angle for joint limits. This helps when saving
/// and loading a game.
/// The local anchor points are measured from the body's origin
/// rather than the center of mass because:
/// 1. you might not know where the center of mass will be.
/// 2. if you add/remove shapes from a body and recompute the mass,
/// the joints will be broken.
struct B2_API b2RevoluteJointDef : public b2JointDef
{
b2RevoluteJointDef()
{
type = e_revoluteJoint;
localAnchorA.Set(0.0f, 0.0f);
localAnchorB.Set(0.0f, 0.0f);
referenceAngle = 0.0f;
lowerAngle = 0.0f;
upperAngle = 0.0f;
maxMotorTorque = 0.0f;
motorSpeed = 0.0f;
enableLimit = false;
enableMotor = false;
}
/// Initialize the bodies, anchors, and reference angle using a world
/// anchor point.
void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor);
/// The local anchor point relative to bodyA's origin.
b2Vec2 localAnchorA;
/// The local anchor point relative to bodyB's origin.
b2Vec2 localAnchorB;
/// The bodyB angle minus bodyA angle in the reference state (radians).
float referenceAngle;
/// A flag to enable joint limits.
bool enableLimit;
/// The lower angle for the joint limit (radians).
float lowerAngle;
/// The upper angle for the joint limit (radians).
float upperAngle;
/// A flag to enable the joint motor.
bool enableMotor;
/// The desired motor speed. Usually in radians per second.
float motorSpeed;
/// The maximum motor torque used to achieve the desired motor speed.
/// Usually in N-m.
float maxMotorTorque;
};
/// A revolute joint constrains two bodies to share a common point while they
/// are free to rotate about the point. The relative rotation about the shared
/// point is the joint angle. You can limit the relative rotation with
/// a joint limit that specifies a lower and upper angle. You can use a motor
/// to drive the relative rotation about the shared point. A maximum motor torque
/// is provided so that infinite forces are not generated.
class B2_API b2RevoluteJoint : public b2Joint
{
public:
b2Vec2 GetAnchorA() const override;
b2Vec2 GetAnchorB() const override;
/// The local anchor point relative to bodyA's origin.
const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; }
/// The local anchor point relative to bodyB's origin.
const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; }
/// Get the reference angle.
float GetReferenceAngle() const { return m_referenceAngle; }
/// Get the current joint angle in radians.
float GetJointAngle() const;
/// Get the current joint angle speed in radians per second.
float GetJointSpeed() const;
/// Is the joint limit enabled?
bool IsLimitEnabled() const;
/// Enable/disable the joint limit.
void EnableLimit(bool flag);
/// Get the lower joint limit in radians.
float GetLowerLimit() const;
/// Get the upper joint limit in radians.
float GetUpperLimit() const;
/// Set the joint limits in radians.
void SetLimits(float lower, float upper);
/// Is the joint motor enabled?
bool IsMotorEnabled() const;
/// Enable/disable the joint motor.
void EnableMotor(bool flag);
/// Set the motor speed in radians per second.
void SetMotorSpeed(float speed);
/// Get the motor speed in radians per second.
float GetMotorSpeed() const;
/// Set the maximum motor torque, usually in N-m.
void SetMaxMotorTorque(float torque);
float GetMaxMotorTorque() const { return m_maxMotorTorque; }
/// Get the reaction force given the inverse time step.
/// Unit is N.
b2Vec2 GetReactionForce(float inv_dt) const override;
/// Get the reaction torque due to the joint limit given the inverse time step.
/// Unit is N*m.
float GetReactionTorque(float inv_dt) const override;
/// Get the current motor torque given the inverse time step.
/// Unit is N*m.
float GetMotorTorque(float inv_dt) const;
/// Dump to b2Log.
void Dump() override;
///
void Draw(b2Draw* draw) const override;
protected:
friend class b2Joint;
friend class b2GearJoint;
b2RevoluteJoint(const b2RevoluteJointDef* def);
void InitVelocityConstraints(const b2SolverData& data) override;
void SolveVelocityConstraints(const b2SolverData& data) override;
bool SolvePositionConstraints(const b2SolverData& data) override;
// Solver shared
b2Vec2 m_localAnchorA;
b2Vec2 m_localAnchorB;
b2Vec2 m_impulse;
float m_motorImpulse;
float m_lowerImpulse;
float m_upperImpulse;
bool m_enableMotor;
float m_maxMotorTorque;
float m_motorSpeed;
bool m_enableLimit;
float m_referenceAngle;
float m_lowerAngle;
float m_upperAngle;
// Solver temp
int32 m_indexA;
int32 m_indexB;
b2Vec2 m_rA;
b2Vec2 m_rB;
b2Vec2 m_localCenterA;
b2Vec2 m_localCenterB;
float m_invMassA;
float m_invMassB;
float m_invIA;
float m_invIB;
b2Mat22 m_K;
float m_angle;
float m_axialMass;
};
inline float b2RevoluteJoint::GetMotorSpeed() const
{
return m_motorSpeed;
}
#endif

View file

@ -0,0 +1,153 @@
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_ROPE_H
#define B2_ROPE_H
#include "b2_api.h"
#include "b2_math.h"
class b2Draw;
struct b2RopeStretch;
struct b2RopeBend;
enum b2StretchingModel
{
b2_pbdStretchingModel,
b2_xpbdStretchingModel
};
enum b2BendingModel
{
b2_springAngleBendingModel = 0,
b2_pbdAngleBendingModel,
b2_xpbdAngleBendingModel,
b2_pbdDistanceBendingModel,
b2_pbdHeightBendingModel,
b2_pbdTriangleBendingModel
};
///
struct B2_API b2RopeTuning
{
b2RopeTuning()
{
stretchingModel = b2_pbdStretchingModel;
bendingModel = b2_pbdAngleBendingModel;
damping = 0.0f;
stretchStiffness = 1.0f;
bendStiffness = 0.5f;
bendHertz = 1.0f;
bendDamping = 0.0f;
isometric = false;
fixedEffectiveMass = false;
warmStart = false;
}
b2StretchingModel stretchingModel;
b2BendingModel bendingModel;
float damping;
float stretchStiffness;
float stretchHertz;
float stretchDamping;
float bendStiffness;
float bendHertz;
float bendDamping;
bool isometric;
bool fixedEffectiveMass;
bool warmStart;
};
///
struct B2_API b2RopeDef
{
b2RopeDef()
{
position.SetZero();
vertices = nullptr;
count = 0;
masses = nullptr;
gravity.SetZero();
}
b2Vec2 position;
b2Vec2* vertices;
int32 count;
float* masses;
b2Vec2 gravity;
b2RopeTuning tuning;
};
///
class B2_API b2Rope
{
public:
b2Rope();
~b2Rope();
///
void Create(const b2RopeDef& def);
///
void SetTuning(const b2RopeTuning& tuning);
///
void Step(float timeStep, int32 iterations, const b2Vec2& position);
///
void Reset(const b2Vec2& position);
///
void Draw(b2Draw* draw) const;
private:
void SolveStretch_PBD();
void SolveStretch_XPBD(float dt);
void SolveBend_PBD_Angle();
void SolveBend_XPBD_Angle(float dt);
void SolveBend_PBD_Distance();
void SolveBend_PBD_Height();
void SolveBend_PBD_Triangle();
void ApplyBendForces(float dt);
b2Vec2 m_position;
int32 m_count;
int32 m_stretchCount;
int32 m_bendCount;
b2RopeStretch* m_stretchConstraints;
b2RopeBend* m_bendConstraints;
b2Vec2* m_bindPositions;
b2Vec2* m_ps;
b2Vec2* m_p0s;
b2Vec2* m_vs;
float* m_invMasses;
b2Vec2 m_gravity;
b2RopeTuning m_tuning;
};
#endif

View file

@ -0,0 +1,127 @@
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_SETTINGS_H
#define B2_SETTINGS_H
#include "b2_types.h"
#include "b2_api.h"
/// @file
/// Settings that can be overriden for your application
///
/// Define this macro in your build if you want to override settings
#ifdef B2_USER_SETTINGS
/// This is a user file that includes custom definitions of the macros, structs, and functions
/// defined below.
#include "b2_user_settings.h"
#else
#include <stdarg.h>
#include <stdint.h>
// Tunable Constants
/// You can use this to change the length scale used by your game.
/// For example for inches you could use 39.4.
#define b2_lengthUnitsPerMeter 1.0f
/// The maximum number of vertices on a convex polygon. You cannot increase
/// this too much because b2BlockAllocator has a maximum object size.
#define b2_maxPolygonVertices 8
// User data
/// You can define this to inject whatever data you want in b2Body
struct B2_API b2BodyUserData
{
b2BodyUserData()
{
pointer = 0;
}
/// For legacy compatibility
uintptr_t pointer;
};
/// You can define this to inject whatever data you want in b2Fixture
struct B2_API b2FixtureUserData
{
b2FixtureUserData()
{
pointer = 0;
}
/// For legacy compatibility
uintptr_t pointer;
};
/// You can define this to inject whatever data you want in b2Joint
struct B2_API b2JointUserData
{
b2JointUserData()
{
pointer = 0;
}
/// For legacy compatibility
uintptr_t pointer;
};
// Memory Allocation
/// Default allocation functions
B2_API void* b2Alloc_Default(int32 size);
B2_API void b2Free_Default(void* mem);
/// Implement this function to use your own memory allocator.
inline void* b2Alloc(int32 size)
{
return b2Alloc_Default(size);
}
/// If you implement b2Alloc, you should also implement this function.
inline void b2Free(void* mem)
{
b2Free_Default(mem);
}
/// Default logging function
B2_API void b2Log_Default(const char* string, va_list args);
/// Implement this to use your own logging.
inline void b2Log(const char* string, ...)
{
va_list args;
va_start(args, string);
b2Log_Default(string, args);
va_end(args);
}
#endif // B2_USER_SETTINGS
#include "b2_common.h"
#endif

View file

@ -0,0 +1,110 @@
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_SHAPE_H
#define B2_SHAPE_H
#include "b2_api.h"
#include "b2_math.h"
#include "b2_collision.h"
class b2BlockAllocator;
/// This holds the mass data computed for a shape.
struct B2_API b2MassData
{
/// The mass of the shape, usually in kilograms.
float mass;
/// The position of the shape's centroid relative to the shape's origin.
b2Vec2 center;
/// The rotational inertia of the shape about the local origin.
float I;
};
/// A shape is used for collision detection. You can create a shape however you like.
/// Shapes used for simulation in b2World are created automatically when a b2Fixture
/// is created. Shapes may encapsulate a one or more child shapes.
class B2_API b2Shape
{
public:
enum Type
{
e_circle = 0,
e_edge = 1,
e_polygon = 2,
e_chain = 3,
e_typeCount = 4
};
virtual ~b2Shape() {}
/// Clone the concrete shape using the provided allocator.
virtual b2Shape* Clone(b2BlockAllocator* allocator) const = 0;
/// Get the type of this shape. You can use this to down cast to the concrete shape.
/// @return the shape type.
Type GetType() const;
/// Get the number of child primitives.
virtual int32 GetChildCount() const = 0;
/// Test a point for containment in this shape. This only works for convex shapes.
/// @param xf the shape world transform.
/// @param p a point in world coordinates.
virtual bool TestPoint(const b2Transform& xf, const b2Vec2& p) const = 0;
/// Cast a ray against a child shape.
/// @param output the ray-cast results.
/// @param input the ray-cast input parameters.
/// @param transform the transform to be applied to the shape.
/// @param childIndex the child shape index
virtual bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
const b2Transform& transform, int32 childIndex) const = 0;
/// Given a transform, compute the associated axis aligned bounding box for a child shape.
/// @param aabb returns the axis aligned box.
/// @param xf the world transform of the shape.
/// @param childIndex the child shape
virtual void ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const = 0;
/// Compute the mass properties of this shape using its dimensions and density.
/// The inertia tensor is computed about the local origin.
/// @param massData returns the mass data for this shape.
/// @param density the density in kilograms per meter squared.
virtual void ComputeMass(b2MassData* massData, float density) const = 0;
Type m_type;
/// Radius of a shape. For polygonal shapes this must be b2_polygonRadius. There is no support for
/// making rounded polygons.
float m_radius;
};
inline b2Shape::Type b2Shape::GetType() const
{
return m_type;
}
#endif

View file

@ -0,0 +1,65 @@
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_STACK_ALLOCATOR_H
#define B2_STACK_ALLOCATOR_H
#include "b2_api.h"
#include "b2_settings.h"
const int32 b2_stackSize = 100 * 1024; // 100k
const int32 b2_maxStackEntries = 32;
struct B2_API b2StackEntry
{
char* data;
int32 size;
bool usedMalloc;
};
// This is a stack allocator used for fast per step allocations.
// You must nest allocate/free pairs. The code will assert
// if you try to interleave multiple allocate/free pairs.
class B2_API b2StackAllocator
{
public:
b2StackAllocator();
~b2StackAllocator();
void* Allocate(int32 size);
void Free(void* p);
int32 GetMaxAllocation() const;
private:
char m_data[b2_stackSize];
int32 m_index;
int32 m_allocation;
int32 m_maxAllocation;
b2StackEntry m_entries[b2_maxStackEntries];
int32 m_entryCount;
};
#endif

View file

@ -0,0 +1,63 @@
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_TIME_OF_IMPACT_H
#define B2_TIME_OF_IMPACT_H
#include "b2_api.h"
#include "b2_math.h"
#include "b2_distance.h"
/// Input parameters for b2TimeOfImpact
struct B2_API b2TOIInput
{
b2DistanceProxy proxyA;
b2DistanceProxy proxyB;
b2Sweep sweepA;
b2Sweep sweepB;
float tMax; // defines sweep interval [0, tMax]
};
/// Output parameters for b2TimeOfImpact.
struct B2_API b2TOIOutput
{
enum State
{
e_unknown,
e_failed,
e_overlapped,
e_touching,
e_separated
};
State state;
float t;
};
/// Compute the upper bound on time before two shapes penetrate. Time is represented as
/// a fraction between [0,tMax]. This uses a swept separating axis and may miss some intermediate,
/// non-tunneling collisions. If you change the time interval, you should call this function
/// again.
/// Note: use b2Distance to compute the contact point and normal at the time of impact.
B2_API void b2TimeOfImpact(b2TOIOutput* output, const b2TOIInput* input);
#endif

View file

@ -0,0 +1,74 @@
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_TIME_STEP_H
#define B2_TIME_STEP_H
#include "b2_api.h"
#include "b2_math.h"
/// Profiling data. Times are in milliseconds.
struct B2_API b2Profile
{
float step;
float collide;
float solve;
float solveInit;
float solveVelocity;
float solvePosition;
float broadphase;
float solveTOI;
};
/// This is an internal structure.
struct B2_API b2TimeStep
{
float dt; // time step
float inv_dt; // inverse time step (0 if dt == 0).
float dtRatio; // dt * inv_dt0
int32 velocityIterations;
int32 positionIterations;
bool warmStarting;
};
/// This is an internal structure.
struct B2_API b2Position
{
b2Vec2 c;
float a;
};
/// This is an internal structure.
struct B2_API b2Velocity
{
b2Vec2 v;
float w;
};
/// Solver Data
struct B2_API b2SolverData
{
b2TimeStep step;
b2Position* positions;
b2Velocity* velocities;
};
#endif

View file

@ -0,0 +1,55 @@
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_TIMER_H
#define B2_TIMER_H
#include "b2_api.h"
#include "b2_settings.h"
/// Timer for profiling. This has platform specific code and may
/// not work on every platform.
class B2_API b2Timer
{
public:
/// Constructor
b2Timer();
/// Reset the timer.
void Reset();
/// Get the time since construction or the last reset.
float GetMilliseconds() const;
private:
#if defined(_WIN32)
double m_start;
static double s_invFrequency;
#elif defined(__linux__) || defined (__APPLE__)
unsigned long long m_start_sec;
unsigned long long m_start_usec;
#endif
};
#endif

View file

@ -0,0 +1,44 @@
// MIT License
// Copyright (c) 2020 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_TYPES_H
#define B2_TYPES_H
#include <Core/Core.h>
using int8 = Upp::int8;
using int16 = Upp::int16;
using int32 = Upp::int32;
using uint8 = Upp::uint8;
using uint16 = Upp::uint16;
using uint32 = Upp::uint32;
/*
typedef signed char int8;
typedef signed short int16;
typedef signed int int32;
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
*/
#endif

View file

@ -0,0 +1,133 @@
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_WELD_JOINT_H
#define B2_WELD_JOINT_H
#include "b2_api.h"
#include "b2_joint.h"
/// Weld joint definition. You need to specify local anchor points
/// where they are attached and the relative body angle. The position
/// of the anchor points is important for computing the reaction torque.
struct B2_API b2WeldJointDef : public b2JointDef
{
b2WeldJointDef()
{
type = e_weldJoint;
localAnchorA.Set(0.0f, 0.0f);
localAnchorB.Set(0.0f, 0.0f);
referenceAngle = 0.0f;
stiffness = 0.0f;
damping = 0.0f;
}
/// Initialize the bodies, anchors, reference angle, stiffness, and damping.
/// @param bodyA the first body connected by this joint
/// @param bodyB the second body connected by this joint
/// @param anchor the point of connection in world coordinates
void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor);
/// The local anchor point relative to bodyA's origin.
b2Vec2 localAnchorA;
/// The local anchor point relative to bodyB's origin.
b2Vec2 localAnchorB;
/// The bodyB angle minus bodyA angle in the reference state (radians).
float referenceAngle;
/// The rotational stiffness in N*m
/// Disable softness with a value of 0
float stiffness;
/// The rotational damping in N*m*s
float damping;
};
/// A weld joint essentially glues two bodies together. A weld joint may
/// distort somewhat because the island constraint solver is approximate.
class B2_API b2WeldJoint : public b2Joint
{
public:
b2Vec2 GetAnchorA() const override;
b2Vec2 GetAnchorB() const override;
b2Vec2 GetReactionForce(float inv_dt) const override;
float GetReactionTorque(float inv_dt) const override;
/// The local anchor point relative to bodyA's origin.
const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; }
/// The local anchor point relative to bodyB's origin.
const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; }
/// Get the reference angle.
float GetReferenceAngle() const { return m_referenceAngle; }
/// Set/get stiffness in N*m
void SetStiffness(float hz) { m_stiffness = hz; }
float GetStiffness() const { return m_stiffness; }
/// Set/get damping in N*m*s
void SetDamping(float damping) { m_damping = damping; }
float GetDamping() const { return m_damping; }
/// Dump to b2Log
void Dump() override;
protected:
friend class b2Joint;
b2WeldJoint(const b2WeldJointDef* def);
void InitVelocityConstraints(const b2SolverData& data) override;
void SolveVelocityConstraints(const b2SolverData& data) override;
bool SolvePositionConstraints(const b2SolverData& data) override;
float m_stiffness;
float m_damping;
float m_bias;
// Solver shared
b2Vec2 m_localAnchorA;
b2Vec2 m_localAnchorB;
float m_referenceAngle;
float m_gamma;
b2Vec3 m_impulse;
// Solver temp
int32 m_indexA;
int32 m_indexB;
b2Vec2 m_rA;
b2Vec2 m_rB;
b2Vec2 m_localCenterA;
b2Vec2 m_localCenterB;
float m_invMassA;
float m_invMassB;
float m_invIA;
float m_invIB;
b2Mat33 m_mass;
};
#endif

View file

@ -0,0 +1,240 @@
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_WHEEL_JOINT_H
#define B2_WHEEL_JOINT_H
#include "b2_api.h"
#include "b2_joint.h"
/// Wheel joint definition. This requires defining a line of
/// motion using an axis and an anchor point. The definition uses local
/// anchor points and a local axis so that the initial configuration
/// can violate the constraint slightly. The joint translation is zero
/// when the local anchor points coincide in world space. Using local
/// anchors and a local axis helps when saving and loading a game.
struct B2_API b2WheelJointDef : public b2JointDef
{
b2WheelJointDef()
{
type = e_wheelJoint;
localAnchorA.SetZero();
localAnchorB.SetZero();
localAxisA.Set(1.0f, 0.0f);
enableLimit = false;
lowerTranslation = 0.0f;
upperTranslation = 0.0f;
enableMotor = false;
maxMotorTorque = 0.0f;
motorSpeed = 0.0f;
stiffness = 0.0f;
damping = 0.0f;
}
/// Initialize the bodies, anchors, axis, and reference angle using the world
/// anchor and world axis.
void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor, const b2Vec2& axis);
/// The local anchor point relative to bodyA's origin.
b2Vec2 localAnchorA;
/// The local anchor point relative to bodyB's origin.
b2Vec2 localAnchorB;
/// The local translation axis in bodyA.
b2Vec2 localAxisA;
/// Enable/disable the joint limit.
bool enableLimit;
/// The lower translation limit, usually in meters.
float lowerTranslation;
/// The upper translation limit, usually in meters.
float upperTranslation;
/// Enable/disable the joint motor.
bool enableMotor;
/// The maximum motor torque, usually in N-m.
float maxMotorTorque;
/// The desired motor speed in radians per second.
float motorSpeed;
/// Suspension stiffness. Typically in units N/m.
float stiffness;
/// Suspension damping. Typically in units of N*s/m.
float damping;
};
/// A wheel joint. This joint provides two degrees of freedom: translation
/// along an axis fixed in bodyA and rotation in the plane. In other words, it is a point to
/// line constraint with a rotational motor and a linear spring/damper. The spring/damper is
/// initialized upon creation. This joint is designed for vehicle suspensions.
class B2_API b2WheelJoint : public b2Joint
{
public:
b2Vec2 GetAnchorA() const override;
b2Vec2 GetAnchorB() const override;
b2Vec2 GetReactionForce(float inv_dt) const override;
float GetReactionTorque(float inv_dt) const override;
/// The local anchor point relative to bodyA's origin.
const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; }
/// The local anchor point relative to bodyB's origin.
const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; }
/// The local joint axis relative to bodyA.
const b2Vec2& GetLocalAxisA() const { return m_localXAxisA; }
/// Get the current joint translation, usually in meters.
float GetJointTranslation() const;
/// Get the current joint linear speed, usually in meters per second.
float GetJointLinearSpeed() const;
/// Get the current joint angle in radians.
float GetJointAngle() const;
/// Get the current joint angular speed in radians per second.
float GetJointAngularSpeed() const;
/// Is the joint limit enabled?
bool IsLimitEnabled() const;
/// Enable/disable the joint translation limit.
void EnableLimit(bool flag);
/// Get the lower joint translation limit, usually in meters.
float GetLowerLimit() const;
/// Get the upper joint translation limit, usually in meters.
float GetUpperLimit() const;
/// Set the joint translation limits, usually in meters.
void SetLimits(float lower, float upper);
/// Is the joint motor enabled?
bool IsMotorEnabled() const;
/// Enable/disable the joint motor.
void EnableMotor(bool flag);
/// Set the motor speed, usually in radians per second.
void SetMotorSpeed(float speed);
/// Get the motor speed, usually in radians per second.
float GetMotorSpeed() const;
/// Set/Get the maximum motor force, usually in N-m.
void SetMaxMotorTorque(float torque);
float GetMaxMotorTorque() const;
/// Get the current motor torque given the inverse time step, usually in N-m.
float GetMotorTorque(float inv_dt) const;
/// Access spring stiffness
void SetStiffness(float stiffness);
float GetStiffness() const;
/// Access damping
void SetDamping(float damping);
float GetDamping() const;
/// Dump to b2Log
void Dump() override;
///
void Draw(b2Draw* draw) const override;
protected:
friend class b2Joint;
b2WheelJoint(const b2WheelJointDef* def);
void InitVelocityConstraints(const b2SolverData& data) override;
void SolveVelocityConstraints(const b2SolverData& data) override;
bool SolvePositionConstraints(const b2SolverData& data) override;
b2Vec2 m_localAnchorA;
b2Vec2 m_localAnchorB;
b2Vec2 m_localXAxisA;
b2Vec2 m_localYAxisA;
float m_impulse;
float m_motorImpulse;
float m_springImpulse;
float m_lowerImpulse;
float m_upperImpulse;
float m_translation;
float m_lowerTranslation;
float m_upperTranslation;
float m_maxMotorTorque;
float m_motorSpeed;
bool m_enableLimit;
bool m_enableMotor;
float m_stiffness;
float m_damping;
// Solver temp
int32 m_indexA;
int32 m_indexB;
b2Vec2 m_localCenterA;
b2Vec2 m_localCenterB;
float m_invMassA;
float m_invMassB;
float m_invIA;
float m_invIB;
b2Vec2 m_ax, m_ay;
float m_sAx, m_sBx;
float m_sAy, m_sBy;
float m_mass;
float m_motorMass;
float m_axialMass;
float m_springMass;
float m_bias;
float m_gamma;
};
inline float b2WheelJoint::GetMotorSpeed() const
{
return m_motorSpeed;
}
inline float b2WheelJoint::GetMaxMotorTorque() const
{
return m_maxMotorTorque;
}
#endif

View file

@ -1,48 +1,54 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_WORLD_H
#define B2_WORLD_H
#include "b2Math.h"
#include "b2BlockAllocator.h"
#include "b2StackAllocator.h"
#include "b2ContactManager.h"
#include "b2WorldCallbacks.h"
#include "b2_api.h"
#include "b2_block_allocator.h"
#include "b2_contact_manager.h"
#include "b2_math.h"
#include "b2_stack_allocator.h"
#include "b2_time_step.h"
#include "b2_world_callbacks.h"
struct b2AABB;
struct b2BodyDef;
struct b2Color;
struct b2JointDef;
struct b2TimeStep;
class b2Body;
class b2Draw;
class b2Fixture;
class b2Joint;
/// The world class manages all physics entities, dynamic simulation,
/// and asynchronous queries. The world also contains efficient memory
/// management facilities.
class b2World
class B2_API b2World
{
public:
/// Construct a world object.
/// @param gravity the world gravity vector.
/// @param doSleep improve performance by not simulating inactive bodies.
b2World(const b2Vec2& gravity, bool doSleep);
b2World(const b2Vec2& gravity);
/// Destruct the world. All physics entities are destroyed and all heap memory is released.
~b2World();
@ -53,7 +59,7 @@ public:
/// Register a contact filter to provide specific control over collision.
/// Otherwise the default filter is used (b2_defaultFilter). The listener is
/// owned by you and must remain in scope.
/// owned by you and must remain in scope.
void SetContactFilter(b2ContactFilter* filter);
/// Register a contact event listener. The listener is owned by you and must
@ -61,9 +67,9 @@ public:
void SetContactListener(b2ContactListener* listener);
/// Register a routine for debug drawing. The debug draw functions are called
/// inside with b2World::DrawDebugData method. The debug draw object is owned
/// inside with b2World::DebugDraw method. The debug draw object is owned
/// by you and must remain in scope.
void SetDebugDraw(b2DebugDraw* debugDraw);
void SetDebugDraw(b2Draw* debugDraw);
/// Create a rigid body given a definition. No reference to the definition
/// is retained.
@ -90,18 +96,21 @@ public:
/// @param timeStep the amount of time to simulate, this should not vary.
/// @param velocityIterations for the velocity constraint solver.
/// @param positionIterations for the position constraint solver.
void Step( float32 timeStep,
void Step( float timeStep,
int32 velocityIterations,
int32 positionIterations);
/// Call this after you are done with time steps to clear the forces. You normally
/// call this after each call to Step, unless you are performing sub-steps. By default,
/// forces will be automatically cleared, so you don't need to call this function.
/// Manually clear the force buffer on all bodies. By default, forces are cleared automatically
/// after each call to Step. The default behavior is modified by calling SetAutoClearForces.
/// The purpose of this function is to support sub-stepping. Sub-stepping is often used to maintain
/// a fixed sized time step under a variable frame-rate.
/// When you perform sub-stepping you will disable auto clearing of forces and instead call
/// ClearForces after all sub-steps are complete in one pass of your game loop.
/// @see SetAutoClearForces
void ClearForces();
/// Call this to draw shapes and other debug draw data.
void DrawDebugData();
/// Call this to draw shapes and other debug draw data. This is intentionally non-const.
void DebugDraw();
/// Query the world for all fixtures that potentially overlap the
/// provided AABB.
@ -118,26 +127,40 @@ public:
void RayCast(b2RayCastCallback* callback, const b2Vec2& point1, const b2Vec2& point2) const;
/// Get the world body list. With the returned body, use b2Body::GetNext to get
/// the next body in the world list. A NULL body indicates the end of the list.
/// the next body in the world list. A nullptr body indicates the end of the list.
/// @return the head of the world body list.
b2Body* GetBodyList();
const b2Body* GetBodyList() const;
/// Get the world joint list. With the returned joint, use b2Joint::GetNext to get
/// the next joint in the world list. A NULL joint indicates the end of the list.
/// the next joint in the world list. A nullptr joint indicates the end of the list.
/// @return the head of the world joint list.
b2Joint* GetJointList();
const b2Joint* GetJointList() const;
/// Get the world contact list. With the returned contact, use b2Contact::GetNext to get
/// the next contact in the world list. A NULL contact indicates the end of the list.
/// the next contact in the world list. A nullptr contact indicates the end of the list.
/// @return the head of the world contact list.
/// @warning contacts are
/// @warning contacts are created and destroyed in the middle of a time step.
/// Use b2ContactListener to avoid missing contacts.
b2Contact* GetContactList();
const b2Contact* GetContactList() const;
/// Enable/disable sleep.
void SetAllowSleeping(bool flag);
bool GetAllowSleeping() const { return m_allowSleep; }
/// Enable/disable warm starting. For testing.
void SetWarmStarting(bool flag) { m_warmStarting = flag; }
bool GetWarmStarting() const { return m_warmStarting; }
/// Enable/disable continuous physics. For testing.
void SetContinuousPhysics(bool flag) { m_continuousPhysics = flag; }
bool GetContinuousPhysics() const { return m_continuousPhysics; }
/// Enable/disable single stepped continuous physics. For testing.
void SetSubStepping(bool flag) { m_subStepping = flag; }
bool GetSubStepping() const { return m_subStepping; }
/// Get the number of broad-phase proxies.
int32 GetProxyCount() const;
@ -151,9 +174,19 @@ public:
/// Get the number of contacts (each may have 0 or more contact points).
int32 GetContactCount() const;
/// Get the height of the dynamic tree.
int32 GetTreeHeight() const;
/// Get the balance of the dynamic tree.
int32 GetTreeBalance() const;
/// Get the quality metric of the dynamic tree. The smaller the better.
/// The minimum is 1.
float GetTreeQuality() const;
/// Change the global gravity vector.
void SetGravity(const b2Vec2& gravity);
/// Get the global gravity vector.
b2Vec2 GetGravity() const;
@ -166,32 +199,36 @@ public:
/// Get the flag that controls automatic clearing of forces after each time step.
bool GetAutoClearForces() const;
/// Shift the world origin. Useful for large worlds.
/// The body shift formula is: position -= newOrigin
/// @param newOrigin the new origin with respect to the old origin
void ShiftOrigin(const b2Vec2& newOrigin);
/// Get the contact manager for testing.
const b2ContactManager& GetContactManager() const;
/// Get the current profile.
const b2Profile& GetProfile() const;
/// Dump the world into the log file.
/// @warning this should be called outside of a time step.
void Dump();
private:
// m_flags
enum
{
e_newFixture = 0x0001,
e_locked = 0x0002,
e_clearForces = 0x0004,
};
friend class b2Body;
friend class b2Fixture;
friend class b2ContactManager;
friend class b2Controller;
void Solve(const b2TimeStep& step);
void SolveTOI();
void SolveTOI(b2Body* body);
void SolveTOI(const b2TimeStep& step);
void DrawJoint(b2Joint* joint);
void DrawShape(b2Fixture* shape, const b2Transform& xf, const b2Color& color);
b2BlockAllocator m_blockAllocator;
b2StackAllocator m_stackAllocator;
int32 m_flags;
b2ContactManager m_contactManager;
b2Body* m_bodyList;
@ -203,20 +240,25 @@ private:
b2Vec2 m_gravity;
bool m_allowSleep;
b2Body* m_groundBody;
b2DestructionListener* m_destructionListener;
b2DebugDraw* m_debugDraw;
b2Draw* m_debugDraw;
// This is used to compute the time step ratio to
// support a variable time step.
float32 m_inv_dt0;
float m_inv_dt0;
// This is for debugging the solver.
bool m_newContacts;
bool m_locked;
bool m_clearForces;
// These are for debugging the solver.
bool m_warmStarting;
// This is for debugging the solver.
bool m_continuousPhysics;
bool m_subStepping;
bool m_stepComplete;
b2Profile m_profile;
};
inline b2Body* b2World::GetBodyList()
@ -224,16 +266,31 @@ inline b2Body* b2World::GetBodyList()
return m_bodyList;
}
inline const b2Body* b2World::GetBodyList() const
{
return m_bodyList;
}
inline b2Joint* b2World::GetJointList()
{
return m_jointList;
}
inline const b2Joint* b2World::GetJointList() const
{
return m_jointList;
}
inline b2Contact* b2World::GetContactList()
{
return m_contactManager.m_contactList;
}
inline const b2Contact* b2World::GetContactList() const
{
return m_contactManager.m_contactList;
}
inline int32 b2World::GetBodyCount() const
{
return m_bodyCount;
@ -261,25 +318,28 @@ inline b2Vec2 b2World::GetGravity() const
inline bool b2World::IsLocked() const
{
return (m_flags & e_locked) == e_locked;
return m_locked;
}
inline void b2World::SetAutoClearForces(bool flag)
{
if (flag)
{
m_flags |= e_clearForces;
}
else
{
m_flags &= ~e_clearForces;
}
m_clearForces = flag;
}
/// Get the flag that controls automatic clearing of forces after each time step.
inline bool b2World::GetAutoClearForces() const
{
return (m_flags & e_clearForces) == e_clearForces;
return m_clearForces;
}
inline const b2ContactManager& b2World::GetContactManager() const
{
return m_contactManager;
}
inline const b2Profile& b2World::GetProfile() const
{
return m_profile;
}
#endif

View file

@ -1,25 +1,30 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef B2_WORLD_CALLBACKS_H
#define B2_WORLD_CALLBACKS_H
#include "b2Settings.h"
#include "b2_api.h"
#include "b2_settings.h"
struct b2Vec2;
struct b2Transform;
@ -27,14 +32,13 @@ class b2Fixture;
class b2Body;
class b2Joint;
class b2Contact;
struct b2ContactPoint;
struct b2ContactResult;
struct b2Manifold;
/// Joints and fixtures are destroyed when their associated
/// body is destroyed. Implement this listener so that you
/// may nullify references to these joints and shapes.
class b2DestructionListener
class B2_API b2DestructionListener
{
public:
virtual ~b2DestructionListener() {}
@ -50,7 +54,7 @@ public:
/// Implement this class to provide collision filtering. In other words, you can implement
/// this class if you want finer control over contact creation.
class b2ContactFilter
class B2_API b2ContactFilter
{
public:
virtual ~b2ContactFilter() {}
@ -63,10 +67,11 @@ public:
/// Contact impulses for reporting. Impulses are used instead of forces because
/// sub-step forces may approach infinity for rigid body collisions. These
/// match up one-to-one with the contact points in b2Manifold.
struct b2ContactImpulse
struct B2_API b2ContactImpulse
{
float32 normalImpulses[b2_maxManifoldPoints];
float32 tangentImpulses[b2_maxManifoldPoints];
float normalImpulses[b2_maxManifoldPoints];
float tangentImpulses[b2_maxManifoldPoints];
int32 count;
};
/// Implement this class to get contact information. You can use these results for
@ -78,7 +83,7 @@ struct b2ContactImpulse
/// You should strive to make your callbacks efficient because there may be
/// many callbacks per time step.
/// @warning You cannot create/destroy Box2D entities inside these callbacks.
class b2ContactListener
class B2_API b2ContactListener
{
public:
virtual ~b2ContactListener() {}
@ -120,7 +125,7 @@ public:
/// Callback class for AABB queries.
/// See b2World::Query
class b2QueryCallback
class B2_API b2QueryCallback
{
public:
virtual ~b2QueryCallback() {}
@ -132,7 +137,7 @@ public:
/// Callback class for ray casts.
/// See b2World::RayCast
class b2RayCastCallback
class B2_API b2RayCastCallback
{
public:
virtual ~b2RayCastCallback() {}
@ -146,72 +151,11 @@ public:
/// @param fixture the fixture hit by the ray
/// @param point the point of initial intersection
/// @param normal the normal vector at the point of intersection
/// @param fraction the fraction along the ray at the point of intersection
/// @return -1 to filter, 0 to terminate, fraction to clip the ray for
/// closest hit, 1 to continue
virtual float32 ReportFixture( b2Fixture* fixture, const b2Vec2& point,
const b2Vec2& normal, float32 fraction) = 0;
};
/// Color for debug drawing. Each value has the range [0,1].
struct b2Color
{
b2Color() {}
b2Color(float32 r, float32 g, float32 b) : r(r), g(g), b(b) {}
void Set(float32 ri, float32 gi, float32 bi) { r = ri; g = gi; b = bi; }
float32 r, g, b;
};
/// Implement and register this class with a b2World to provide debug drawing of physics
/// entities in your game.
class b2DebugDraw
{
public:
b2DebugDraw();
virtual ~b2DebugDraw() {}
enum
{
e_shapeBit = 0x0001, ///< draw shapes
e_jointBit = 0x0002, ///< draw joint connections
e_aabbBit = 0x0004, ///< draw axis aligned bounding boxes
e_pairBit = 0x0008, ///< draw broad-phase pairs
e_centerOfMassBit = 0x0010, ///< draw center of mass frame
};
/// Set the drawing flags.
void SetFlags(uint32 flags);
/// Get the drawing flags.
uint32 GetFlags() const;
/// Append flags to the current flags.
void AppendFlags(uint32 flags);
/// Clear flags from the current flags.
void ClearFlags(uint32 flags);
/// Draw a closed polygon provided in CCW order.
virtual void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0;
/// Draw a solid closed polygon provided in CCW order.
virtual void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0;
/// Draw a circle.
virtual void DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color) = 0;
/// Draw a solid circle.
virtual void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color) = 0;
/// Draw a line segment.
virtual void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) = 0;
/// Draw a transform. Choose your own length scale.
/// @param xf a transform.
virtual void DrawTransform(const b2Transform& xf) = 0;
protected:
uint32 m_drawFlags;
virtual float ReportFixture( b2Fixture* fixture, const b2Vec2& point,
const b2Vec2& normal, float fraction) = 0;
};
#endif

View file

@ -0,0 +1,58 @@
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BOX2D_H
#define BOX2D_H
// These include files constitute the main Box2D API
#include "b2_settings.h"
#include "b2_draw.h"
#include "b2_timer.h"
#include "b2_chain_shape.h"
#include "b2_circle_shape.h"
#include "b2_edge_shape.h"
#include "b2_polygon_shape.h"
#include "b2_broad_phase.h"
#include "b2_dynamic_tree.h"
#include "b2_body.h"
#include "b2_contact.h"
#include "b2_fixture.h"
#include "b2_time_step.h"
#include "b2_world.h"
#include "b2_world_callbacks.h"
#include "b2_distance_joint.h"
#include "b2_friction_joint.h"
#include "b2_gear_joint.h"
#include "b2_motor_joint.h"
#include "b2_mouse_joint.h"
#include "b2_prismatic_joint.h"
#include "b2_pulley_joint.h"
#include "b2_revolute_joint.h"
#include "b2_weld_joint.h"
#include "b2_wheel_joint.h"
#endif

View file

@ -1,23 +1,27 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
// MIT License
#include "b2BroadPhase.h"
#include <cstring>
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include "box2d/b2_broad_phase.h"
#include <string.h>
b2BroadPhase::b2BroadPhase()
{
@ -62,6 +66,11 @@ void b2BroadPhase::MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& di
}
}
void b2BroadPhase::TouchProxy(int32 proxyId)
{
BufferMove(proxyId);
}
void b2BroadPhase::BufferMove(int32 proxyId)
{
if (m_moveCount == m_moveCapacity)
@ -84,7 +93,6 @@ void b2BroadPhase::UnBufferMove(int32 proxyId)
if (m_moveBuffer[i] == proxyId)
{
m_moveBuffer[i] = e_nullProxy;
return;
}
}
}
@ -98,11 +106,18 @@ bool b2BroadPhase::QueryCallback(int32 proxyId)
return true;
}
const bool moved = m_tree.WasMoved(proxyId);
if (moved && proxyId > m_queryProxyId)
{
// Both proxies are moving. Avoid duplicate pairs.
return true;
}
// Grow the pair buffer as needed.
if (m_pairCount == m_pairCapacity)
{
b2Pair* oldBuffer = m_pairBuffer;
m_pairCapacity *= 2;
m_pairCapacity = m_pairCapacity + (m_pairCapacity >> 1);
m_pairBuffer = (b2Pair*)b2Alloc(m_pairCapacity * sizeof(b2Pair));
memcpy(m_pairBuffer, oldBuffer, m_pairCount * sizeof(b2Pair));
b2Free(oldBuffer);

View file

@ -0,0 +1,185 @@
// MIT License
// Copyright (c) 2019 Erin Catto
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include "box2d/b2_chain_shape.h"
#include "box2d/b2_edge_shape.h"
#include "box2d/b2_block_allocator.h"
#include <new>
#include <string.h>
b2ChainShape::~b2ChainShape()
{
Clear();
}
void b2ChainShape::Clear()
{
b2Free(m_vertices);
m_vertices = nullptr;
m_count = 0;
}
void b2ChainShape::CreateLoop(const b2Vec2* vertices, int32 count)
{
b2Assert(m_vertices == nullptr && m_count == 0);
b2Assert(count >= 3);
if (count < 3)
{
return;
}
for (int32 i = 1; i < count; ++i)
{
b2Vec2 v1 = vertices[i-1];
b2Vec2 v2 = vertices[i];
// If the code crashes here, it means your vertices are too close together.
b2Assert(b2DistanceSquared(v1, v2) > b2_linearSlop * b2_linearSlop);
}
m_count = count + 1;
m_vertices = (b2Vec2*)b2Alloc(m_count * sizeof(b2Vec2));
memcpy(m_vertices, vertices, count * sizeof(b2Vec2));
m_vertices[count] = m_vertices[0];
m_prevVertex = m_vertices[m_count - 2];
m_nextVertex = m_vertices[1];
}
void b2ChainShape::CreateChain(const b2Vec2* vertices, int32 count, const b2Vec2& prevVertex, const b2Vec2& nextVertex)
{
b2Assert(m_vertices == nullptr && m_count == 0);
b2Assert(count >= 2);
for (int32 i = 1; i < count; ++i)
{
// If the code crashes here, it means your vertices are too close together.
b2Assert(b2DistanceSquared(vertices[i-1], vertices[i]) > b2_linearSlop * b2_linearSlop);
}
m_count = count;
m_vertices = (b2Vec2*)b2Alloc(count * sizeof(b2Vec2));
memcpy(m_vertices, vertices, m_count * sizeof(b2Vec2));
m_prevVertex = prevVertex;
m_nextVertex = nextVertex;
}
b2Shape* b2ChainShape::Clone(b2BlockAllocator* allocator) const
{
void* mem = allocator->Allocate(sizeof(b2ChainShape));
b2ChainShape* clone = new (mem) b2ChainShape;
clone->CreateChain(m_vertices, m_count, m_prevVertex, m_nextVertex);
return clone;
}
int32 b2ChainShape::GetChildCount() const
{
// edge count = vertex count - 1
return m_count - 1;
}
void b2ChainShape::GetChildEdge(b2EdgeShape* edge, int32 index) const
{
b2Assert(0 <= index && index < m_count - 1);
edge->m_type = b2Shape::e_edge;
edge->m_radius = m_radius;
edge->m_vertex1 = m_vertices[index + 0];
edge->m_vertex2 = m_vertices[index + 1];
edge->m_oneSided = true;
if (index > 0)
{
edge->m_vertex0 = m_vertices[index - 1];
}
else
{
edge->m_vertex0 = m_prevVertex;
}
if (index < m_count - 2)
{
edge->m_vertex3 = m_vertices[index + 2];
}
else
{
edge->m_vertex3 = m_nextVertex;
}
}
bool b2ChainShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const
{
B2_NOT_USED(xf);
B2_NOT_USED(p);
return false;
}
bool b2ChainShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
const b2Transform& xf, int32 childIndex) const
{
b2Assert(childIndex < m_count);
b2EdgeShape edgeShape;
int32 i1 = childIndex;
int32 i2 = childIndex + 1;
if (i2 == m_count)
{
i2 = 0;
}
edgeShape.m_vertex1 = m_vertices[i1];
edgeShape.m_vertex2 = m_vertices[i2];
return edgeShape.RayCast(output, input, xf, 0);
}
void b2ChainShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const
{
b2Assert(childIndex < m_count);
int32 i1 = childIndex;
int32 i2 = childIndex + 1;
if (i2 == m_count)
{
i2 = 0;
}
b2Vec2 v1 = b2Mul(xf, m_vertices[i1]);
b2Vec2 v2 = b2Mul(xf, m_vertices[i2]);
b2Vec2 lower = b2Min(v1, v2);
b2Vec2 upper = b2Max(v1, v2);
b2Vec2 r(m_radius, m_radius);
aabb->lowerBound = lower - r;
aabb->upperBound = upper + r;
}
void b2ChainShape::ComputeMass(b2MassData* massData, float density) const
{
B2_NOT_USED(density);
massData->mass = 0.0f;
massData->center.SetZero();
massData->I = 0.0f;
}

Some files were not shown because too many files have changed in this diff Show more