File size: 5,049 Bytes
09a6f7f |
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 |
/**
* @classdesc Abstract class for agent's morphologies
*/
class AbstractBody {
/**
* @constructor
* @param scale {number} - Scale of the environment
* @param motors_torque {number}
*/
constructor(scale, motors_torque){
this.SCALE = scale;
this.MOTORS_TORQUE = motors_torque;
this.body_parts = [];
this.motors = [];
this.is_selected = false;
}
/**
* Gets the size of the motors state.
* @return {number}
*/
get_state_size(){
return this.get_motors_state().length;
}
/**
* Gets the motors state.
* @return {Array}
*/
get_motors_state(){
let state = [];
for(let motor of this.motors){
let motor_info = motor.GetUserData();
if(motor_info.check_contact){
let s = [
motor.GetJointAngle() + motor_info.angle_correction,
motor.GetJointSpeed() / motor_info.speed_control,
0.0
]
if(motor_info.contact_body.GetUserData().has_contact){
s[2] = 1.0;
}
state = state.concat(s);
}
else{
state = state.concat([
motor.GetJointAngle() + motor_info.angle_correction,
motor.GetJointSpeed() / motor_info.speed_control
])
}
}
return state;
}
/**
* Gets the size of the action space.
* @return {number}
*/
get_action_size(){
return this.motors.length;
}
/**
* Activates the motors according to the given actions by setting the motors speed and torque.
* @param actions {Array}
*/
activate_motors(actions){
for(let i = 0; i < this.motors.length; i++){
this.motors[i].SetMotorSpeed(this.motors[i].GetUserData().speed_control * Math.sign(actions[i]));
let clamp01 = Math.max(0, Math.min(Math.abs(actions[i]), 1));
this.motors[i].SetMaxMotorTorque(this.MOTORS_TORQUE * clamp01);
}
}
/**
* Creates the Box2D body parts, joints and sensors of the agent.
* @param world {Object} - Box2D world
* @param init_x {number}
* @param init_y {number}
* @param force_to_center {number}
*/
draw(world, init_x, init_y, force_to_center){}
/**
* Gets all the body parts
* @return {Array}
*/
get_elements_to_render(){
return this.body_parts;
}
/**
* Checks if the given position is inside the agent's morphology
* @param pos {{x: number, y: number}}
* @return {boolean}
*/
isPosInside(pos){
for(let body of this.body_parts){
let shape = body.GetFixtureList().GetShape();
let vertices = [];
for(let i = 0; i < shape.m_count; i++){
let world_pos = body.GetWorldPoint(shape.m_vertices[i]);
vertices.push({x: world_pos.x, y: world_pos.y});
}
// Counts the number of intersections between the edges of the polygon and the line of equation y = pos.y which are to the right of pos.x
let nb_intersections = 0;
for(let i = 0; i < vertices.length; i++){
let v1 = vertices[i];
let v2;
if(i == vertices.length - 1){
v2 = vertices[0];
}
else {
v2 = vertices[i+1];
}
// Checks if the edge between v1 and v2 cross the mouse y-coordinate
if(pos.y >= Math.min(v1.y, v2.y) && pos.y <= Math.max(v1.y, v2.y)){
let intersection_x;
// Computes the equation of the line between v1 and v2
let a = (v2.y - v1.y) / (v2.x - v1.x);
let b = v1.y - a * v1.x;
// Computes the x-coordinate of the intersection point
if(Math.abs(a) == Infinity){
intersection_x = v1.x;
}
else{
intersection_x = (pos.y - b) / a;
}
// Increases the number of intersection only if the intersection point is to the right of the mouse x-coordinate
if(intersection_x >= pos.x) {
nb_intersections += 1;
}
}
}
// The pos is inside the agent's body if there is an odd number of intersections, else it is outside
if(nb_intersections % 2 != 0){
return true;
}
}
return false;
}
/**
* Destroys all the body parts of the agents.
* @param world {Object} - Box2D world
*/
destroy(world){
for(let body of this.body_parts){
world.DestroyBody(body);
}
this.body_parts = [];
this.motors = [];
}
} |