def test_setRigidBody(self): """ Set and retrieve object attributes like position, velocity, acceleration, and rotation. """ # Instantiate a Leonard. leo = getLeonard() # Test constants. body_new = { 'imass': 2, 'scale': 3, 'cshapes': {'csempty': getCSEmpty()}, 'position': (1, 2, 5), 'velocityLin': (8, 9, 10.5), 'velocityRot': (9, 10, 11.5), 'rotation': (11, 12.5, 13, 13.5) } # Create a test body. id_1 = 0 body = getRigidBody(cshapes={'csempty': getCSEmpty()}) # Add the object to the DB with ID=0. assert leoAPI.addCmdSpawn([(id_1, body)]).ok leo.processCommandsAndSync() # Modify the state vector for body with id_1. assert leoAPI.addCmdModifyBodyState(id_1, body_new).ok leo.processCommandsAndSync() # Query the body again and verify the changes are in effect. ret = leo.allBodies[id_1] assert ret.imass == body_new['imass'] assert ret.scale == body_new['scale'] assert np.array_equal(ret.position, body_new['position']) assert np.array_equal(ret.velocityLin, body_new['velocityLin']) assert np.array_equal(ret.velocityRot, body_new['velocityRot']) assert np.array_equal(ret.rotation, body_new['rotation']) # Query the AABB, update the collision shapes, and verify that the new # AABBs are in effect. assert leo.allAABBs[id_1] == {} # Modify the body state by adding a collision shape. body_new = {'cshapes': {'cssphere': getCSSphere(radius=1)}} assert body_new is not None assert leoAPI.addCmdModifyBodyState(id_1, body_new).ok leo.processCommandsAndSync() assert leo.allAABBs[id_1] == {'cssphere': [0, 0, 0, 1, 1, 1]} # Modify the body state by adding a collision shape. cs_a = getCSSphere(radius=1, pos=(1, 2, 3)) cs_b = getCSSphere(radius=2, pos=(4, 5, 6)) cshapes = {'1': cs_a, '2': getCSEmpty(), '3': cs_b} body_new = {'cshapes': cshapes} assert leoAPI.addCmdModifyBodyState(id_1, body_new).ok leo.processCommandsAndSync() correct = {'1': [1, 2, 3, 1, 1, 1], '3': [4, 5, 6, 2, 2, 2]} assert leo.allAABBs[id_1] == correct
def test_move_single_object(self, clsLeonard): """ Create a single object with non-zero initial speed and ensure Leonard moves it accordingly. """ # Get a Leonard instance. leo = getLeonard(clsLeonard) # Constants and parameters for this test. id_0 = 0 # Spawn an object. assert leoAPI.addCmdSpawn([(id_0, getRigidBody())]).ok # Advance the simulation by 1s and verify that nothing has moved. leo.step(1.0, 60) assert np.array_equal(leo.allBodies[id_0].position, [0, 0, 0]) # Give the object a velocity. body = {'velocityLin': np.array([1, 0, 0])} assert leoAPI.addCmdModifyBodyState(id_0, body).ok del body # Advance the simulation by another second and verify the objects have # moved accordingly. leo.step(1.0, 60) body = leo.allBodies[id_0] assert 0.9 <= body.position[0] < 1.1 assert body.position[1] == body.position[2] == 0
def test_setRigidBody_advanced(self, clsLeonard): """ Similar to test_setRigidBody_basic but modify the collision shape information as well, namely their mass- and type. """ # Get a Leonard instance. leo = getLeonard(clsLeonard) # Parameters and constants for this test. cshape_box = {'1': getCSBox()} cshape_sphere = {'1': getCSSphere()} body = getRigidBody(imass=2, scale=3, cshapes=cshape_sphere) # Spawn an object. objID = 1 assert leoAPI.addCmdSpawn([(objID, body)]).ok del body # Verify the body data. leo.processCommandsAndSync() assert leo.allBodies[objID].imass == 2 assert leo.allBodies[objID].scale == 3 assert leo.allBodies[objID].cshapes == cshape_sphere # Update the body. cs_new = {'imass': 4, 'scale': 5, 'cshapes': cshape_box} assert leoAPI.addCmdModifyBodyState(objID, cs_new).ok # Verify the body data. leo.processCommandsAndSync() ret = leo.allBodies[objID] assert (ret.imass == 4) and (ret.scale == 5) assert ret.cshapes == cshape_box
def test_setRigidBody_basic(self, clsLeonard): """ Spawn an object, specify its State Variables explicitly, and verify the change propagated through Azrael. """ # Get a Leonard instance. leo = getLeonard(clsLeonard) # Parameters and constants for this test. id_1 = 1 # Body data. p = np.array([1, 2, 5]) vl = np.array([8, 9, 10.5]) vr = vl + 1 body = {'position': p, 'velocityLin': vl, 'velocityRot': vr} del p, vl, vr # Spawn a new object. It must have ID=1. assert leoAPI.addCmdSpawn([(id_1, getRigidBody())]).ok # Update the object's body. assert leoAPI.addCmdModifyBodyState(id_1, body).ok # Sync the commands to Leonard. leo.processCommandsAndSync() # Verify that the attributes were correctly updated. ret = leo.allBodies[id_1] assert np.array_equal(ret.position, body['position']) assert np.array_equal(ret.velocityLin, body['velocityLin']) assert np.array_equal(ret.velocityRot, body['velocityRot'])
def test_processCommandQueue(self): """ Create commands to spawn-, delete, and modify objects or their booster values. Then verify that ``processCommandQueue`` corrently updates Leonard's object cache. """ # Get a Leonard instance. leo = getLeonard(azrael.leonard.LeonardDistributedZeroMQ) # Convenience. body_1 = getRigidBody(imass=1) body_2 = getRigidBody(imass=2) id_1, id_2 = 1, 2 # Cache must be empty. assert len(leo.allBodies) == len(leo.allForces) == 0 # Spawn two objects. tmp = [(id_1, body_1), (id_2, body_2)] assert leoAPI.addCmdSpawn(tmp).ok leo.processCommandsAndSync() # Verify the local cache (forces and torques must default to zero). assert getRigidBody(*leo.allBodies[id_1]) == body_1 assert getRigidBody(*leo.allBodies[id_2]) == body_2 tmp = leo.allForces[id_1] assert tmp.forceDirect == tmp.torqueDirect == [0, 0, 0] assert tmp.forceBoost == tmp.torqueBoost == [0, 0, 0] del tmp # Remove first object. assert leoAPI.addCmdRemoveObject(id_1).ok leo.processCommandsAndSync() assert id_1 not in leo.allBodies assert id_1 not in leo.allForces # Change the State Vector of id_2. pos = (10, 11.5, 12) body_3 = {'position': pos} assert leo.allBodies[id_2].position == (0, 0, 0) assert leoAPI.addCmdModifyBodyState(id_2, body_3).ok leo.processCommandsAndSync() assert leo.allBodies[id_2].position == pos # Apply a direct force and torque to id_2. force, torque = [1, 2, 3], [4, 5, 6] assert leoAPI.addCmdDirectForce(id_2, force, torque).ok leo.processCommandsAndSync() assert leo.allForces[id_2].forceDirect == force assert leo.allForces[id_2].torqueDirect == torque # Specify a new force- and torque value due to booster activity. force, torque = [1, 2, 3], [4, 5, 6] assert leoAPI.addCmdBoosterForce(id_2, force, torque).ok leo.processCommandsAndSync() assert leo.allForces[id_2].forceBoost == force assert leo.allForces[id_2].torqueBoost == torque
def test_setRigidBody(self): """ Set and retrieve object attributes like position, velocity, acceleration, and rotation. """ # Instantiate a Leonard. leo = getLeonard() # Test constants. body_new = { 'imass': 2, 'scale': 3, 'cshapes': { 'csempty': getCSEmpty() }, 'position': (1, 2, 5), 'velocityLin': (8, 9, 10.5), 'velocityRot': (9, 10, 11.5), 'rotation': (11, 12.5, 13, 13.5) } # Create a test body. id_1 = '0' body = getRigidBody(cshapes={'csempty': getCSEmpty()}) # Add the object to the DB with ID=0. assert leoAPI.addCmdSpawn([(id_1, body)]).ok leo.processCommandsAndSync() # Modify the state vector for body with id_1. assert leoAPI.addCmdModifyBodyState(id_1, body_new).ok leo.processCommandsAndSync() # Query the body again and verify the changes are in effect. ret = leo.allBodies[id_1] assert ret.imass == body_new['imass'] assert ret.scale == body_new['scale'] assert np.array_equal(ret.position, body_new['position']) assert np.array_equal(ret.velocityLin, body_new['velocityLin']) assert np.array_equal(ret.velocityRot, body_new['velocityRot']) assert np.array_equal(ret.rotation, body_new['rotation']) # Query the AABB, update the collision shapes, and verify that the new # AABBs are in effect. assert leo.allAABBs[id_1] == {} # Modify the body state by adding a collision shape. body_new = {'cshapes': {'cssphere': getCSSphere(radius=1)}} assert body_new is not None assert leoAPI.addCmdModifyBodyState(id_1, body_new).ok leo.processCommandsAndSync() assert leo.allAABBs[id_1] == {'cssphere': [0, 0, 0, 1, 1, 1]} # Modify the body state by adding a collision shape. cs_a = getCSSphere(radius=1, pos=(1, 2, 3)) cs_b = getCSSphere(radius=2, pos=(4, 5, 6)) cshapes = {'1': cs_a, '2': getCSEmpty(), '3': cs_b} body_new = {'cshapes': cshapes} assert leoAPI.addCmdModifyBodyState(id_1, body_new).ok leo.processCommandsAndSync() correct = {'1': [1, 2, 3, 1, 1, 1], '3': [4, 5, 6, 2, 2, 2]} assert leo.allAABBs[id_1] == correct
def test_commandQueue(self): """ Add-, query, and remove commands from the command queue. """ # Convenience. body_1 = getRigidBody() body_2 = {'imass': 2, 'scale': 3} id_1, id_2 = '0', '1' # The command queue must be empty for every category. ret = leoAPI.dequeueCommands() assert ret.ok assert ret.data['spawn'] == [] assert ret.data['remove'] == [] assert ret.data['modify'] == [] assert ret.data['direct_force'] == [] assert ret.data['booster_force'] == [] # Spawn two objects with id_1 and id_2. tmp = [(id_1, body_1), (id_2, body_1)] assert leoAPI.addCmdSpawn(tmp).ok # Verify that the spawn commands were added. ret = leoAPI.dequeueCommands() assert ret.ok spawn = ret.data['spawn'] assert {spawn[0]['objID'], spawn[1]['objID']} == {id_1, id_2} assert ret.data['remove'] == [] assert ret.data['modify'] == [] assert ret.data['direct_force'] == [] assert ret.data['booster_force'] == [] # De-queuing the commands once more must not return any results because # they have already been removed. ret = leoAPI.dequeueCommands() assert ret.ok assert ret.data['spawn'] == [] assert ret.data['remove'] == [] assert ret.data['modify'] == [] assert ret.data['direct_force'] == [] assert ret.data['booster_force'] == [] # Modify state variable for body with id_1. newSV = {'imass': 10, 'position': [3, 4, 5]} assert leoAPI.addCmdModifyBodyState(id_1, newSV).ok ret = leoAPI.dequeueCommands() modify = ret.data['modify'] assert ret.ok and len(modify) == 1 assert modify[0]['objID'] == id_1 assert modify[0]['rbs'] == newSV del newSV # Set the direct force and torque for id_2. force, torque = [1, 2, 3], [4, 5, 6] assert leoAPI.addCmdDirectForce(id_2, force, torque).ok ret = leoAPI.dequeueCommands() fat = ret.data['direct_force'] assert ret.ok assert len(fat) == 1 assert fat[0]['objID'] == id_2 assert fat[0]['force'] == force assert fat[0]['torque'] == torque # Set the booster force and torque for id_1. force, torque = [1, 2, 3], [4, 5, 6] assert leoAPI.addCmdBoosterForce(id_1, force, torque).ok ret = leoAPI.dequeueCommands() fat = ret.data['booster_force'] assert ret.ok assert len(fat) == 1 assert fat[0]['objID'] == id_1 assert fat[0]['force'] == force assert fat[0]['torque'] == torque # Remove an object. assert leoAPI.addCmdRemoveObject(id_1).ok ret = leoAPI.dequeueCommands() assert ret.ok and ret.data['remove'][0]['objID'] == id_1 # Add commands for two objects (it is perfectly ok to add commands for # non-existing body IDs since this is just a command queue - Leonard # will skip commands for non-existing IDs automatically). force, torque = [7, 8, 9], [10, 11.5, 12.5] for objID in (id_1, id_2): assert leoAPI.addCmdSpawn([(objID, body_1)]).ok assert leoAPI.addCmdModifyBodyState(objID, body_2).ok assert leoAPI.addCmdRemoveObject(objID).ok assert leoAPI.addCmdDirectForce(objID, force, torque).ok assert leoAPI.addCmdBoosterForce(objID, force, torque).ok # De-queue all commands. ret = leoAPI.dequeueCommands() assert ret.ok assert len(ret.data['spawn']) == 2 assert len(ret.data['remove']) == 2 assert len(ret.data['modify']) == 2 assert len(ret.data['direct_force']) == 2 assert len(ret.data['booster_force']) == 2
def test_commandQueue(self): """ Add-, query, and remove commands from the command queue. """ # Convenience. body_1 = getRigidBody() body_2 = {'imass': 2, 'scale': 3} id_1, id_2 = 0, 1 # The command queue must be empty for every category. ret = leoAPI.dequeueCommands() assert ret.ok assert ret.data['spawn'] == [] assert ret.data['remove'] == [] assert ret.data['modify'] == [] assert ret.data['direct_force'] == [] assert ret.data['booster_force'] == [] # Spawn two objects with id_1 and id_2. tmp = [(id_1, body_1), (id_2, body_1)] assert leoAPI.addCmdSpawn(tmp).ok # Verify that the spawn commands were added. ret = leoAPI.dequeueCommands() assert ret.ok assert ret.data['spawn'][0]['objID'] == id_1 assert ret.data['spawn'][1]['objID'] == id_2 assert ret.data['remove'] == [] assert ret.data['modify'] == [] assert ret.data['direct_force'] == [] assert ret.data['booster_force'] == [] # De-queuing the commands once more must not return any results because # they have already been removed. ret = leoAPI.dequeueCommands() assert ret.ok assert ret.data['spawn'] == [] assert ret.data['remove'] == [] assert ret.data['modify'] == [] assert ret.data['direct_force'] == [] assert ret.data['booster_force'] == [] # Modify state variable for body with id_1. newSV = {'imass': 10, 'position': [3, 4, 5]} assert leoAPI.addCmdModifyBodyState(id_1, newSV).ok ret = leoAPI.dequeueCommands() modify = ret.data['modify'] assert ret.ok and len(modify) == 1 assert modify[0]['objID'] == id_1 assert modify[0]['rbs'] == newSV del newSV # Set the direct force and torque for id_2. force, torque = [1, 2, 3], [4, 5, 6] assert leoAPI.addCmdDirectForce(id_2, force, torque).ok ret = leoAPI.dequeueCommands() fat = ret.data['direct_force'] assert ret.ok assert len(fat) == 1 assert fat[0]['objID'] == id_2 assert fat[0]['force'] == force assert fat[0]['torque'] == torque # Set the booster force and torque for id_1. force, torque = [1, 2, 3], [4, 5, 6] assert leoAPI.addCmdBoosterForce(id_1, force, torque).ok ret = leoAPI.dequeueCommands() fat = ret.data['booster_force'] assert ret.ok assert len(fat) == 1 assert fat[0]['objID'] == id_1 assert fat[0]['force'] == force assert fat[0]['torque'] == torque # Remove an object. assert leoAPI.addCmdRemoveObject(id_1).ok ret = leoAPI.dequeueCommands() assert ret.ok and ret.data['remove'][0]['objID'] == id_1 # Add commands for two objects (it is perfectly ok to add commands for # non-existing body IDs since this is just a command queue - Leonard # will skip commands for non-existing IDs automatically). force, torque = [7, 8, 9], [10, 11.5, 12.5] for objID in (id_1, id_2): assert leoAPI.addCmdSpawn([(objID, body_1)]).ok assert leoAPI.addCmdModifyBodyState(objID, body_2).ok assert leoAPI.addCmdRemoveObject(objID).ok assert leoAPI.addCmdDirectForce(objID, force, torque).ok assert leoAPI.addCmdBoosterForce(objID, force, torque).ok # De-queue all commands. ret = leoAPI.dequeueCommands() assert ret.ok assert len(ret.data['spawn']) == 2 assert len(ret.data['remove']) == 2 assert len(ret.data['modify']) == 2 assert len(ret.data['direct_force']) == 2 assert len(ret.data['booster_force']) == 2