Пример #1
0
    def test_add_unique_bug1(self, getCon):
        """
        Add two constraints that are identical except for their 'aid'.

        In the original implementation this was handled incorrectly
        because the 'aid' was not considered when adding constraints.
        This made it impossible to add more than once constraint of each
        type (eg more than one Point2Point constraint between objects).
        """
        # Convenience.
        igor = self.igor

        # Two constraints that only differ in their 'aid' attribute.
        c1 = getCon('foo', '1', '2')
        c2 = getCon('bar', '1', '2')

        # Attempt to add the first constraint twice. Igor must detect this and
        # only add it once.
        assert igor.reset().ok
        assert igor.addConstraints([c1, c1]).ok is False

        # Attempt to both constraints. Without the bug fix Igor would only add
        # the first one, whereas with the bug fix it adds both.
        assert igor.reset().ok
        assert igor.addConstraints([c1, c2]) == (True, None, [True] * 2)

        # Update the local cache and verify that really both constraints are
        # available.
        assert igor.updateLocalCache() == (True, None, 2)
        assert sorted(igor.getConstraints(None).data) == sorted((c1, c2))
Пример #2
0
    def test_add_unique_bug1(self, getCon):
        """
        Add two constraints that are identical except for their 'aid'.

        In the original implementation this was handled incorrectly
        because the 'aid' was not considered when adding constraints.
        This made it impossible to add more than once constraint of each
        type (eg more than one Point2Point constraint between objects).
        """
        # Convenience.
        igor = self.igor

        # Two constraints that only differ in their 'aid' attribute.
        c1 = getCon('foo', 1, 2)
        c2 = getCon('bar', 1, 2)

        # Attempt to add the first constraint twice. Igor must detect this and
        # only add it once.
        assert igor.reset().ok
        assert igor.addConstraints([c1, c1]) == (True, None, 1)

        # Attempt to both constraints. Without the bug fix Igor would only add
        # the first one, whereas with the bug fix it adds both.
        assert igor.reset().ok
        assert igor.addConstraints([c1, c2]) == (True, None, 2)

        # Update the local cache and verify that really both constraints are
        # available.
        assert igor.updateLocalCache() == (True, None, 2)
        assert sorted(igor.getConstraints(None).data) == sorted((c1, c2))
Пример #3
0
    def test_update_and_add(self, getCon):
        """
        Verify that 'updateLocalCache' downloads the correct number of
        constraints.
        """
        # Convenience.
        igor = self.igor
        igor.reset()

        # Create the constraints for this test.
        c1 = getCon('foo', 1, 2)
        c2 = getCon('foo', 2, 3)
        c3 = getCon('foo', 3, 4)
        c4 = getCon('foo', 4, 5)
        c5 = getCon('foo', 5, 6)
        c6 = getCon('foo', 6, 7)

        # There must not be any objects to download.
        assert igor.updateLocalCache() == (True, None, 0)

        # Pass an empty list.
        assert igor.addConstraints([]) == (True, None, 0)

        # Add one constraint and update the cache.
        assert igor.addConstraints([c1]) == (True, None, 1)
        assert igor.updateLocalCache() == (True, None, 1)

        # Add the same constraint. This must add no constraint, but the update
        # function must still fetch exactly one constraint.
        assert igor.addConstraints([c1]) == (True, None, 0)
        assert igor.updateLocalCache() == (True, None, 1)

        # Add two new constraints.
        assert igor.addConstraints([c2, c3]) == (True, None, 2)
        assert igor.updateLocalCache() == (True, None, 3)

        # Add two more constraints, one of which is not new. This must add one
        # new constraint and increase the total number of unique constraints to
        # four.
        assert igor.addConstraints([c3, c4]) == (True, None, 1)
        assert igor.updateLocalCache() == (True, None, 4)

        # Add five more constaints, but only two of them are actually unique.
        assert igor.addConstraints([c5, c5, c6, c6, c6]) == (True, None, 2)
        assert igor.updateLocalCache() == (True, None, 6)
        ref = sorted((c1, c2, c3, c4, c5, c6))
        assert sorted(igor.getConstraints(None).data) == ref

        # Reset igor and add two constraints, of which only one has a valid
        # 'contype'. The 'addConstraints' must only add the valid one.
        c6 = c6._replace(contype='foo')
        assert igor.reset().ok
        assert igor.addConstraints([c1, c6]) == (True, None, 1)
        assert igor.updateLocalCache() == (True, None, 1)
Пример #4
0
    def test_getConstraints_all(self, getCon):
        """
        Add constraints and very that Igor can return them after cache updates.
        """
        # Convenience.
        igor = self.igor

        # Create the constraints for this test.
        c1 = getCon('foo', 2, 3)
        c2 = getCon('foo', 3, 4)
        c3 = getCon('foo', 4, 5)

        # The list of constraints must be empty after a reset.
        assert igor.reset() == (True, None, None)
        assert igor.getConstraints(None).data == tuple()
        assert igor.updateLocalCache() == (True, None, 0)
        assert igor.getConstraints(None).data == tuple()

        # Add two constraints and verify that Igor returns them *after* a cache
        # update.
        assert igor.addConstraints([c1, c2]) == (True, None, 2)
        assert igor.getConstraints(None).data == tuple()
        assert igor.updateLocalCache() == (True, None, 2)
        assert sorted(igor.getConstraints(None).data) == sorted((c1, c2))

        # Add another two constraints, only one of which is new. Verify that
        # Igor returns the correct three constraints.
        assert igor.addConstraints([c2, c3]) == (True, None, 1)
        assert igor.updateLocalCache() == (True, None, 3)
        assert sorted(igor.getConstraints(None).data) == sorted((c1, c2, c3))
Пример #5
0
    def test_update_and_add(self, getCon):
        """
        Verify that 'updateLocalCache' downloads the correct number of
        constraints.
        """
        # Convenience.
        igor = self.igor

        # Create the constraints for this test.
        c1 = getCon('foo', '1', '2')
        c2 = getCon('foo', '2', '3')
        c3 = getCon('foo', '3', '4')
        c4 = getCon('foo', '4', '5')
        c5 = getCon('foo', '5', '6')
        c6 = getCon('foo', '6', '7')

        # There must not be any objects to download.
        assert igor.updateLocalCache() == (True, None, 0)

        # Pass an empty list.
        assert igor.addConstraints([]) == (True, None, 0)

        # Add one constraint and update the cache.
        assert igor.addConstraints([c1]) == (True, None, [True])
        assert igor.updateLocalCache() == (True, None, 1)

        # Add the same constraint. This must add no constraint, but the update
        # function must still fetch exactly one constraint.
        assert igor.addConstraints([c1]) == (True, None, [False])
        assert igor.updateLocalCache() == (True, None, 1)

        # Add two new constraints.
        assert igor.addConstraints([c2, c3]) == (True, None, [True] * 2)
        assert igor.updateLocalCache() == (True, None, 3)

        # Add two more constraints, one of which is not new. This must add one
        # new constraint and increase the total number of unique constraints to
        # four.
        assert igor.addConstraints([c3, c4]) == (True, None, [False, True])
        assert igor.updateLocalCache() == (True, None, 4)

        # Add five more constraints, only two of which are actually unique.
        # This must return with an error and do nothing.
        assert igor.addConstraints([c5, c5, c6, c6, c6]).ok is False
        assert igor.updateLocalCache() == (True, None, 4)
        ref = sorted((c1, c2, c3, c4))
        assert sorted(igor.getConstraints(None).data) == ref

        # Reset igor and add two constraints. Only one has a valid
        # 'contype'. The 'addConstraints' must only add the valid one.
        c6 = c6._replace(contype='foo')
        assert igor.reset().ok
        assert igor.addConstraints([c1, c6]).ok is False
        assert igor.updateLocalCache() == (True, None, 0)
Пример #6
0
    def test_update_and_add(self, getCon):
        """
        Verify that 'updateLocalCache' downloads the correct number of
        constraints.
        """
        # Convenience.
        igor = self.igor

        # Create the constraints for this test.
        c1 = getCon('foo', '1', '2')
        c2 = getCon('foo', '2', '3')
        c3 = getCon('foo', '3', '4')
        c4 = getCon('foo', '4', '5')
        c5 = getCon('foo', '5', '6')
        c6 = getCon('foo', '6', '7')

        # There must not be any objects to download.
        assert igor.updateLocalCache() == (True, None, 0)

        # Pass an empty list.
        assert igor.addConstraints([]) == (True, None, 0)

        # Add one constraint and update the cache.
        assert igor.addConstraints([c1]) == (True, None, [True])
        assert igor.updateLocalCache() == (True, None, 1)

        # Add the same constraint. This must add no constraint, but the update
        # function must still fetch exactly one constraint.
        assert igor.addConstraints([c1]) == (True, None, [False])
        assert igor.updateLocalCache() == (True, None, 1)

        # Add two new constraints.
        assert igor.addConstraints([c2, c3]) == (True, None, [True] * 2)
        assert igor.updateLocalCache() == (True, None, 3)

        # Add two more constraints, one of which is not new. This must add one
        # new constraint and increase the total number of unique constraints to
        # four.
        assert igor.addConstraints([c3, c4]) == (True, None, [False, True])
        assert igor.updateLocalCache() == (True, None, 4)

        # Add five more constraints, only two of which are actually unique.
        # This must return with an error and do nothing.
        assert igor.addConstraints([c5, c5, c6, c6, c6]).ok is False
        assert igor.updateLocalCache() == (True, None, 4)
        ref = sorted((c1, c2, c3, c4))
        assert sorted(igor.getConstraints(None).data) == ref

        # Reset igor and add two constraints. Only one has a valid
        # 'contype'. The 'addConstraints' must only add the valid one.
        c6 = c6._replace(contype='foo')
        assert igor.reset().ok
        assert igor.addConstraints([c1, c6]).ok is False
        assert igor.updateLocalCache() == (True, None, 0)
Пример #7
0
    def test_add_get_remove_constraints(self, client_type):
        """
        Create some bodies. Then add/query/remove constraints.

        This test only verifies that the Igor interface works. It does *not*
        verify that the objects are really linked in the actual simulation.
        """
        # Reset the constraint database.
        igor = azrael.igor.Igor()
        assert igor.reset().ok

        # Get the client for this test.
        client = self.clients[client_type]

        # Spawn the two bodies.
        pos_1, pos_2, pos_3 = [-2, 0, 0], [2, 0, 0], [6, 0, 0]
        new_objs = [
            {'templateID': '_templateSphere', 'rbs': {'position': pos_1}},
            {'templateID': '_templateSphere', 'rbs': {'position': pos_2}},
            {'templateID': '_templateSphere', 'rbs': {'position': pos_3}}
        ]
        id_1, id_2, id_3 = 1, 2, 3
        assert client.spawn(new_objs) == (True, None, [id_1, id_2, id_3])

        # Define the constraints.
        con_1 = getP2P(rb_a=id_1, rb_b=id_2, pivot_a=pos_2, pivot_b=pos_1)
        con_2 = get6DofSpring2(rb_a=id_2, rb_b=id_3)

        # Verify that no constraints are currently active.
        assert client.getConstraints(None) == (True, None, [])
        assert client.getConstraints([id_1]) == (True, None, [])

        # Add both constraints and verify they are returned correctly.
        assert client.addConstraints([con_1, con_2]) == (True, None, 2)
        ret = client.getConstraints(None)
        assert ret.ok and (sorted(ret.data) == sorted([con_1, con_2]))

        ret = client.getConstraints([id_2])
        assert ret.ok and (sorted(ret.data) == sorted([con_1, con_2]))

        assert client.getConstraints([id_1]) == (True, None, [con_1])
        assert client.getConstraints([id_3]) == (True, None, [con_2])

        # Remove the second constraint and verify the remaining constraint is
        # returned correctly.
        assert client.deleteConstraints([con_2]) == (True, None, 1)
        assert client.getConstraints(None) == (True, None, [con_1])
        assert client.getConstraints([id_1]) == (True, None, [con_1])
        assert client.getConstraints([id_2]) == (True, None, [con_1])
        assert client.getConstraints([id_3]) == (True, None, [])
Пример #8
0
    def test_delete(self, getCon):
        """
        Add- and delete several constraints.
        """
        # Convenience.
        igor = self.igor

        # Create the constraints for this test.
        c1 = getCon('foo', 1, 2)
        c2 = getCon('foo', 2, 3)
        c3 = getCon('foo', 3, 4)

        # Attempt to delete a non-existing constraint. This must neither return
        # an error not delete anything.
        assert igor.reset().ok
        assert igor.deleteConstraints([c1]) == (True, None, 0)
        assert igor.deleteConstraints([c1, c2]) == (True, None, 0)
        assert igor.updateLocalCache() == (True, None, 0)

        # Add some constraints, delete them, and update the cache.
        assert igor.addConstraints([c1, c2, c3]) == (True, None, 3)
        assert igor.updateLocalCache() == (True, None, 3)
        assert igor.deleteConstraints([c1, c2]) == (True, None, 2)
        assert igor.updateLocalCache() == (True, None, 1)

        # Add/delete more constraints without every updating the cache. These
        # operations must not affect the local cache of constraints in Igor.
        assert igor.reset().ok
        assert igor.addConstraints([c1, c2, c3]) == (True, None, 3)
        assert igor.deleteConstraints([c1, c2]) == (True, None, 2)
        assert igor.deleteConstraints([c1, c2]) == (True, None, 0)
        assert igor.addConstraints([c1, c2]) == (True, None, 2)
        assert igor.deleteConstraints([c1]) == (True, None, 1)
        assert igor.deleteConstraints([c1, c2]) == (True, None, 1)
        assert igor.deleteConstraints([c1, c2]) == (True, None, 0)
        assert igor.updateLocalCache() == (True, None, 1)
        assert igor.getConstraints(None).data == (c3, )
Пример #9
0
    def test_delete(self, getCon):
        """
        Add- and delete several constraints.
        """
        # Convenience.
        igor = self.igor

        # Create the constraints for this test.
        c1 = getCon('foo', '1', '2')
        c2 = getCon('foo', '2', '3')
        c3 = getCon('foo', '3', '4')

        # Attempt to delete a non-existing constraint. This must neither return
        # an error nor delete anything.
        assert igor.reset().ok
        assert igor.removeConstraints([c1]) == (True, None, 0)
        assert igor.removeConstraints([c1, c2]) == (True, None, 0)
        assert igor.updateLocalCache() == (True, None, 0)

        # Add some constraints, delete them, and update the cache.
        assert igor.addConstraints([c1, c2, c3]) == (True, None, [True] * 3)
        assert igor.updateLocalCache() == (True, None, 3)
        assert igor.removeConstraints([c1, c2]) == (True, None, 2)
        assert igor.updateLocalCache() == (True, None, 1)

        # Add/delete more constraints without every updating the cache. These
        # operations must not affect the local cache of constraints in Igor.
        assert igor.reset().ok
        assert igor.addConstraints([c1, c2, c3]) == (True, None, [True] * 3)
        assert igor.removeConstraints([c1, c2]) == (True, None, 2)
        assert igor.removeConstraints([c1, c2]) == (True, None, 0)
        assert igor.addConstraints([c1, c2]) == (True, None, [True] * 2)
        assert igor.removeConstraints([c1]) == (True, None, 1)
        assert igor.removeConstraints([c1, c2]) == (True, None, 1)
        assert igor.removeConstraints([c1, c2]) == (True, None, 0)
        assert igor.updateLocalCache() == (True, None, 1)
        assert igor.getConstraints(None).data == (c3, )
Пример #10
0
    def test_getConstraint(self, getCon):
        """
        Verify that Igor returns the correct constraints.
        """
        # Convenience.
        igor = self.igor

        # Create the constraints for this test.
        c1 = getCon('foo', 1, 2)
        c2 = getCon('foo', 2, 3)
        c3 = getCon('foo', 3, 4)

        # Query the constraints for bodies that do not feature in any
        # constraints.
        assert igor.reset() == (True, None, None)
        assert igor.getConstraints([]) == (True, None, tuple())
        assert igor.getConstraints([1]) == (True, None, tuple())
        assert igor.getConstraints([1, 2]) == (True, None, tuple())

        # Add four constraints for the following tests.
        assert igor.addConstraints([c1, c2, c3]) == (True, None, 3)

        # Query the constraints that involve object one. This must return only
        # the first object, and only *after* the local Igor cache was updated.
        assert igor.getConstraints([1]) == (True, None, ())
        assert igor.updateLocalCache() == (True, None, 3)
        ret = igor.getConstraints([1])
        assert ret.data == (c1, )

        # Query the constraints that involve body 1 & 5. This must again return
        # only a single hit because body 5 is not part of any constraint.
        ret = igor.getConstraints([1, 5])
        assert ret.data == (c1, )

        # Objects 1 & 4 feature in to individual constraints.
        ret = igor.getConstraints([1, 4])
        assert sorted(ret.data) == sorted((c1, c3))

        # Objects 1 & 2 & 4 feature in all three constraints.
        ret = igor.getConstraints([1, 2, 4])
        assert len(ret.data) == 3
        assert sorted(ret.data) == sorted((c1, c2, c3))

        # Body 2 features in two constraints whereas body 10 features in none.
        ret = igor.getConstraints([2, 10])
        assert sorted(ret.data) == sorted((c1, c2))
Пример #11
0
    def test_uniquePairs(self, getCon):
        """
        Add- and delete constraints and verify that Igor maintins a consistent
        list of unique body pairs.
        """
        # Convenience.
        igor = self.igor

        # Create the constraints for this test.
        c1 = getCon('foo', 1, 2)
        c2 = getCon('foo', 2, 3)
        c3 = getCon('foo', 3, 4)

        # There must not be any pairs after a reset.
        assert igor.reset() == (True, None, None)
        assert igor.uniquePairs() == (True, None, tuple())

        # Adding a constraint must result in one unique pair of IDs *after*
        # updating the Igor cache.
        assert igor.addConstraints([c1]) == (True, None, 1)
        assert igor.uniquePairs() == (True, None, tuple())
        assert igor.updateLocalCache() == (True, None, 1)
        assert igor.uniquePairs().data == ((c1.rb_a, c1.rb_b), )

        # Add three more constraints, only two of which are actually new.
        assert igor.addConstraints([c1, c2, c3]) == (True, None, 2)
        assert igor.updateLocalCache() == (True, None, 3)

        # Verify that the set of unique pairs now covers those involved in the
        # constraints.
        ref = [(_.rb_a, _.rb_b) for _ in (c1, c2, c3)]
        assert set(igor.uniquePairs().data) == set(tuple(ref))

        # Delete two constraints.
        assert igor.deleteConstraints([c1, c3]) == (True, None, 2)
        assert set(igor.uniquePairs().data) == set(tuple(ref))
        assert igor.updateLocalCache() == (True, None, 1)
        assert igor.uniquePairs().data == ((c2.rb_a, c2.rb_b), )
Пример #12
0
    def test_create_constraints_with_physics(self, client_type):
        """
        Spawn two rigid bodies and define a Point2Point constraint among them.
        Then apply a force onto one of them and verify the second one moves
        accordingly.
        """
        # Reset the constraint database.
        igor = azrael.igor.Igor()
        assert igor.reset().ok

        # Get the client for this test.
        client = self.clients[client_type]

        # Reset the database and instantiate a Leonard.
        leo = getLeonard(azrael.leonard.LeonardBullet)

        # Spawn two bodies.
        pos_a, pos_b = [-2, 0, 0], [2, 0, 0]
        new_objs = [
            {'templateID': '_templateSphere',
             'rbs': {'position': pos_a}},
            {'templateID': '_templateSphere',
             'rbs': {'position': pos_b}},
        ]
        id_1, id_2 = 1, 2
        assert client.spawn(new_objs) == (True, None, [id_1, id_2])

        # Verify the position of the bodies.
        ret = client.getObjectStates([id_1, id_2])
        assert ret.ok
        assert ret.data[id_1]['rbs']['position'] == pos_a
        assert ret.data[id_2]['rbs']['position'] == pos_b

        # Define- and add the constraints.
        con = [getP2P(rb_a=id_1, rb_b=id_2, pivot_a=pos_b, pivot_b=pos_a)]
        assert client.addConstraints(con) == (True, None, 1)

        # Apply a force that will pull the left object further to the left.
        # However, both objects must move the same distance in the same
        # direction because they are now linked together.
        assert client.setForce(id_1, [-10, 0, 0]).ok
        leo.processCommandsAndSync()
        leo.step(1.0, 60)

        # Query the object positions. Due to some database timings is sometimes
        # happen that the objects appear to not have moved. In that case retry
        # the query a few times before moving to the comparison.
        for ii in range(10):
            assert ii < 9

            # Query the objects and put their positions into convenience
            # variables.
            ret = client.getRigidBodies([id_1, id_2])
            pos_a2 = ret.data[id_1]['rbs'].position
            pos_b2 = ret.data[id_2]['rbs'].position

            # Exit this loop if both objects have moved.
            if (pos_a != pos_a2) and (pos_b != pos_b2):
                break
            time.sleep(0.1)

        # Verify that the objects have moved to the left and maintained their
        # distance.
        delta_a = np.array(pos_a2) - np.array(pos_a)
        delta_b = np.array(pos_b2) - np.array(pos_b)
        assert delta_a[0] < pos_a[0]
        assert np.allclose(delta_a, delta_b)