File: Box2D_inline.i

package info (click to toggle)
python-box2d 2.3.2~dfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 3,596 kB
  • ctags: 5,116
  • sloc: python: 14,384; cpp: 13,393; makefile: 8; sh: 6
file content (276 lines) | stat: -rw-r--r-- 8,869 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
/*
* pybox2d -- http://pybox2d.googlecode.com
*
* Copyright (c) 2010 Ken Lauer / sirkne at gmail dot 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.
*/

%typemap(out) bool b2CheckPolygon(b2PolygonShape*) {
    if (!$1) 
        SWIG_fail;
    else
        $result = SWIG_From_bool(static_cast< bool >($1));
}

%inline %{
    // Wrap toi settings
    extern int32 b2_toiMaxIters, b2_toiMaxRootIters;

    // Add support for == and != in Python for shapes, joints, and bodies.
    bool __jointeq(b2Joint* a, b2Joint* b) {
        return a==b;
    }
    bool __bodyeq(b2Body* a, b2Body* b) {
        return a==b;
    }
    bool __shapeeq(b2Shape* a, b2Shape* b) {
        return a==b;
    }
    bool __fixtureeq(b2Fixture* a, b2Fixture* b) {
        return a==b;
    }

    // Modified from the b2PolygonShape constructor
    // Should be as accurate as the original version
    b2Vec2 __b2ComputeCentroid(const b2Vec2* vs, int32 count) {
        b2Vec2 c; c.Set(0.0f, 0.0f);
        if (count < 3 || count > b2_maxPolygonVertices) {
            PyErr_SetString(PyExc_ValueError, "Vertex count must be >= 3 and <= b2_maxPolygonVertices");
            return c;
        }

        float32 area = 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);

        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
        if (area <= b2_epsilon) {
            PyErr_SetString(PyExc_ValueError, "ComputeCentroid: area <= FLT_EPSILON");
            return c;
        }

        c *= 1.0f / area;
        return c;
    }

    bool b2CheckVertices(b2Vec2* vertices, int32 count, bool additional_checks=true) {
        // Get the vertices transformed into the body frame.
        if (count < 2 || count > b2_maxPolygonVertices) {
            PyErr_SetString(PyExc_ValueError, "Vertex count must be >= 2 and <= b2_maxPolygonVertices");
            return false;
        }

        // Compute normals. Ensure the edges have non-zero length.
        b2Vec2 m_normals[b2_maxPolygonVertices];
        for (int32 i = 0; i < count; ++i)
        {
            int32 i1 = i;
            int32 i2 = i + 1 < count ? i + 1 : 0;
            b2Vec2 edge = vertices[i2] - vertices[i1];
            if (edge.LengthSquared() <= b2_epsilon * b2_epsilon) {
                PyErr_SetString(PyExc_ValueError, "edge.LengthSquared < FLT_EPSILON**2");
                return false;
            }
            
            m_normals[i] = b2Cross(edge, 1.0f);
            m_normals[i].Normalize();
        }

        // Compute the polygon centroid.
        b2Vec2 m_centroid = __b2ComputeCentroid(vertices, count);

        if (!additional_checks)
            return true;

        // Ensure the polygon is convex and the interior
        // is to the left of each edge.
        for (int32 i = 0; i < count; ++i)
        {
            int32 i1 = i;
            int32 i2 = i + 1 < count ? i + 1 : 0;
            b2Vec2 edge = vertices[i2] - vertices[i1];

            for (int32 j = 0; j < count; ++j)
            {
                // Don not check vertices on the current edge.
                if (j == i1 || j == i2)
                {
                    continue;
                }
                
                b2Vec2 r = vertices[j] - vertices[i1];

                // Your polygon is non-convex (it has an indentation) or
                // has colinear edges.
                float32 s = b2Cross(edge, r);
                if (s <= 0.0f) {
                    PyErr_SetString(PyExc_ValueError, "Your polygon is non-convex (it has an indentation) or has colinear edges.");
                    return false;
                }
            }
        }

        return true;
    }

    bool b2CheckPolygon(b2PolygonShape *shape, bool additional_checks=true) {
        if (!shape)
            return false;

        return b2CheckVertices(shape->m_vertices, shape->m_count, additional_checks);
    }

    /* As of Box2D SVN r191, these functions are no longer in b2Math.h,
       so re-add them here for backwards compatibility */
    #define RAND_LIMIT      32767      
    // Random number in range [-1,1]
    float32 b2Random()      
    {      
            float32 r = (float32)(rand() & (RAND_LIMIT));      
            r /= RAND_LIMIT;      
            r = 2.0f * r - 1.0f;      
            return r;      
    }      
          
    /// Random floating point number in range [lo, hi]      
    float32 b2Random(float32 lo, float32 hi)      
    {      
            float32 r = (float32)(rand() & (RAND_LIMIT));      
            r /= RAND_LIMIT;      
            r = (hi - lo) * r + lo;      
            return r;      
    }

%}

/* Additional supporting Python code */
%pythoncode %{
b2_epsilon = 1.192092896e-07

class _indexable_generator(list):
    def __init__(self, iter):
        list.__init__(self)
        self.iter=iter
        self.__full=False
    def __len__(self):
        self.__fill_list__()
        return super(_indexable_generator, self).__len__()
    def __iter__(self):
        for item in self.iter:
            self.append(item)
            yield item
        self.__full=True
    def __fill_list__(self):
        for item in self.iter:
            self.append(item)
        self.__full=True
    def __getitem__(self, i):
        """Support indexing positive/negative elements of the generator,
        but no slices. If you want those, use list(generator)"""
        if not self.__full:
            if i < 0:
                self.__fill_list__()
            elif i >= list.__len__(self):
                diff=i-list.__len__(self)+1
                for j in range(diff):
                    value = next(self.iter)
                    self.append(value)

        return super(_indexable_generator, self).__getitem__(i)

def _generator_from_linked_list(first):
    if first:
        one = first
        while one:
            yield one
            one = one.next

def _list_from_linked_list(first):
    if not first:
        return []

    one = first
    lst = []
    while one:
        lst.append(one)
        one = one.next

    # linked lists are stored in reverse order from creation order
    lst.reverse() 
    return lst

# Support using == on bodies, joints, and shapes
def b2ShapeCompare(a, b):
    if not isinstance(a, b2Shape) or not isinstance(b, b2Shape):
        return False
    return __shapeeq(a, b)
def b2BodyCompare(a, b):
    if not isinstance(a, b2Body) or not isinstance(b, b2Body):
        return False
    return __bodyeq(a, b)
def b2JointCompare(a, b):
    if not isinstance(a, b2Joint) or not isinstance(b, b2Joint):
        return False
    return __jointeq(a, b)
def b2FixtureCompare(a, b):
    if not isinstance(a, b2Fixture) or not isinstance(b, b2Fixture):
        return False
    return __fixtureeq(a, b)

%}

%feature("docstring") b2CheckPolygon "
    Checks the Polygon definition to see if upon creation it will cause an assertion.
    Raises ValueError if an assertion would be raised.

    b2PolygonDef* poly     - the polygon definition
    bool additional_checks - whether or not to run additional checks

    Additional checking: usually only in DEBUG mode on the C++ code.

    While shapes that pass this test can be created without assertions,
    they will ultimately create unexpected behavior. It's recommended
    to _not_ use any polygon that fails this test.
";

%feature("docstring") b2AABBOverlaps "Checks if two AABBs overlap, or if a point
lies in an AABB

b2AABBOverlaps(AABB1, [AABB2/point])
";