Commit 0236f68b authored by Léo-Paul Géneau's avatar Léo-Paul Géneau 👾

Multicopter API

See merge request !2004
parents 036f0c50 37a38939
Pipeline #38192 failed with stage
in 0 seconds
...@@ -5,21 +5,149 @@ ...@@ -5,21 +5,149 @@
var FixedWingDroneAPI = /** @class */ (function () { var FixedWingDroneAPI = /** @class */ (function () {
"use strict"; "use strict";
var DEFAULT_SPEED = 16, var EARTH_GRAVITY = 9.81,
PARACHUTE_SPEED = 8,
EARTH_GRAVITY = 9.81,
LOITER_LIMIT = 30, LOITER_LIMIT = 30,
MAX_ACCELERATION = 6, MAX_MESSAGE_SIZE = 1024,
MAX_DECELERATION = 1, PARACHUTE_SPEED = 8,
MIN_SPEED = 12, VIEW_SCOPE = 100;
MAX_SPEED = 26,
MAX_ROLL = 35, FixedWingDroneAPI.DRONE_TYPE = "Fixed Wings";
MIN_PITCH = -20, FixedWingDroneAPI.SCRIPT_NAME =
MAX_PITCH = 25, "gadget_erp5_page_drone_capture_flag_fixedwingdrone.js";
MAX_CLIMB_RATE = 8, FixedWingDroneAPI.FORM_VIEW = {
MAX_SINK_RATE = 3, "my_drone_min_speed": {
VIEW_SCOPE = 100, "description": "",
MAX_MESSAGE_SIZE = 1024; "title": "Drone min speed",
"default": 12,
"css_class": "",
"required": 1,
"editable": 1,
"key": "minSpeed",
"hidden": 0,
"type": "IntegerField"
},
"my_drone_speed": {
"description": "",
"title": "Drone speed",
"default": 16,
"css_class": "",
"required": 1,
"editable": 1,
"key": "speed",
"hidden": 0,
"type": "FloatField"
},
"my_drone_max_speed": {
"description": "",
"title": "Drone max speed",
"default": 26,
"css_class": "",
"required": 1,
"editable": 1,
"key": "maxSpeed",
"hidden": 0,
"type": "IntegerField"
},
"my_drone_max_acceleration": {
"description": "",
"title": "Drone max Acceleration",
"default": 6,
"css_class": "",
"required": 1,
"editable": 1,
"key": "maxAcceleration",
"hidden": 0,
"type": "FloatField"
},
"my_drone_max_deceleration": {
"description": "",
"title": "Drone max Deceleration",
"default": 1,
"css_class": "",
"required": 1,
"editable": 1,
"key": "maxDeceleration",
"hidden": 0,
"type": "IntegerField"
},
"my_drone_max_roll": {
"description": "",
"title": "Drone max roll",
"default": 35,
"css_class": "",
"required": 1,
"editable": 1,
"key": "maxRoll",
"hidden": 0,
"type": "FloatField"
},
"my_drone_min_pitch": {
"description": "",
"title": "Drone min pitch",
"default": -20,
"css_class": "",
"required": 1,
"editable": 1,
"key": "minPitchAngle",
"hidden": 0,
"type": "FloatField"
},
"my_drone_max_pitch": {
"description": "",
"title": "Drone max pitch",
"default": 25,
"css_class": "",
"required": 1,
"editable": 1,
"key": "maxPitchAngle",
"hidden": 0,
"type": "FloatField"
},
"my_drone_max_sink_rate": {
"description": "",
"title": "Drone max sink rate",
"default": 3,
"css_class": "",
"required": 1,
"editable": 1,
"key": "maxSinkRate",
"hidden": 0,
"type": "FloatField"
},
"my_drone_max_climb_rate": {
"description": "",
"title": "Drone max climb rate",
"default": 8,
"css_class": "",
"required": 1,
"editable": 1,
"key": "maxClimbRate",
"hidden": 0,
"type": "FloatField"
},
"my_drone_speed_factor": {
"description": "",
"title": "Drone speed factor",
"default": 1,
"css_class": "",
"required": 1,
"editable": 1,
"key": "speedFactor",
"hidden": 0,
"type": "FloatField"
},
"my_drone_max_command_frequency": {
"description": "",
"title": "Drone max command frequency",
"default": 5,
"css_class": "",
"required": 1,
"editable": 1,
"key": "maxCommandFrequency",
"hidden": 0,
"type": "FloatField"
}
};
//** CONSTRUCTOR //** CONSTRUCTOR
function FixedWingDroneAPI(gameManager, drone_info, flight_parameters, id) { function FixedWingDroneAPI(gameManager, drone_info, flight_parameters, id) {
...@@ -98,14 +226,47 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -98,14 +226,47 @@ var FixedWingDroneAPI = /** @class */ (function () {
/* /*
** Function called on every drone update, right before onUpdate AI script ** Function called on every drone update, right before onUpdate AI script
*/ */
FixedWingDroneAPI.prototype.internal_position_update = function (context, delta_time) { FixedWingDroneAPI.prototype.internal_position_update =
if (context.position.z > 0) { function (context, delta_time) {
this._updateSpeed(context, delta_time); var currentGeoCoordinates = this._mapManager.convertToGeoCoordinates(
this._updatePosition(context, delta_time); context.position.x,
context.position.y,
context.position.z
),
targetCoordinates = this._mapManager.convertToGeoCoordinates(
context._targetCoordinates.x,
context._targetCoordinates.y,
context._targetCoordinates.z
),
bearing = this._computeBearing(
currentGeoCoordinates.latitude,
currentGeoCoordinates.longitude,
targetCoordinates.latitude,
targetCoordinates.longitude
),
distanceToTarget,
newYaw;
if (this._loiter_mode) {
distanceToTarget = Math.sqrt(
Math.pow(context._targetCoordinates.x - context.position.x, 2)
+ Math.pow(context._targetCoordinates.y - context.position.y, 2)
);
if (Math.abs(distanceToTarget - this._loiter_radius) <= 1) {
newYaw = bearing - 90;
} else if (distanceToTarget < this._loiter_radius) {
newYaw = bearing - 135;
} else {
newYaw = this._getNewYaw(context, bearing, delta_time);
}
} else { } else {
context.setDirection(0, 0, 0); newYaw = this._getNewYaw(context, bearing, delta_time);
} }
this._updateSpeed(context, delta_time);
this._updatePosition(context, newYaw, delta_time);
context._controlMesh.computeWorldMatrix(true); context._controlMesh.computeWorldMatrix(true);
context._mesh.computeWorldMatrix(true); context._mesh.computeWorldMatrix(true);
}; };
...@@ -140,115 +301,42 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -140,115 +301,42 @@ var FixedWingDroneAPI = /** @class */ (function () {
}; };
FixedWingDroneAPI.prototype._updateSpeed = function (drone, delta_time) { FixedWingDroneAPI.prototype._updateSpeed = function (drone, delta_time) {
var speed = drone.get3DSpeed(), speedDiff, speedUpdate; var speed = drone.get3DSpeed(), speedDiff,
speedUpdate = drone._acceleration * delta_time / 1000;
if (speed > this._targetSpeed) {
speedUpdate *= -1;
}
if (speed !== this._targetSpeed) { if (speed !== this._targetSpeed) {
speedDiff = this._targetSpeed - speed; speedDiff = this._targetSpeed - speed;
speedUpdate = drone._acceleration * delta_time / 1000;
if (Math.abs(speedDiff) < Math.abs(speedUpdate)) { if (Math.abs(speedDiff) < Math.abs(speedUpdate)) {
drone._speed = this._targetSpeed; drone._speed = this._targetSpeed;
drone._acceleration = 0;
} else { } else {
drone._speed += speedUpdate; drone._speed += speedUpdate;
} }
} }
}; };
FixedWingDroneAPI.prototype._updatePosition = function (drone, delta_time) { FixedWingDroneAPI.prototype._updatePosition =
var R = 6371e3, function (drone, yaw, delta_time) {
currentGeoCoordinates = this._mapManager.convertToGeoCoordinates( var speed = drone.get3DSpeed(),
drone.position.x, positionUpdate = speed * delta_time / 1000,
drone.position.y, yawToDirection = this._toRad(-yaw + 90),
drone.position.z zNorm = this._getVerticalSpeed(drone) / speed,
), xyCoef = Math.sqrt(1 - Math.abs(zNorm));
targetCoordinates = this._mapManager.convertToGeoCoordinates(
drone._targetCoordinates.x,
drone._targetCoordinates.y,
drone._targetCoordinates.z
),
bearing = this._computeBearing(
currentGeoCoordinates.latitude,
currentGeoCoordinates.longitude,
targetCoordinates.latitude,
targetCoordinates.longitude
),
currentCosLat,
currentLatRad,
distance,
distanceCos,
distanceSin,
distanceToTarget,
currentSinLat,
currentLonRad,
groundSpeed,
newCoordinates,
newLatRad,
newLonRad,
newYaw,
newYawRad,
verticalSpeed,
yawToDirection;
if (this._loiter_mode) {
distanceToTarget = Math.sqrt(
Math.pow(drone._targetCoordinates.x - drone.position.x, 2)
+ Math.pow(drone._targetCoordinates.y - drone.position.y, 2)
);
if (Math.abs(distanceToTarget - this._loiter_radius) <= 1) {
newYaw = bearing - 90;
} else if (distanceToTarget < this._loiter_radius) {
newYaw = bearing - 135;
} else {
newYaw = this._getNewYaw(drone, bearing, delta_time);
}
} else {
newYaw = this._getNewYaw(drone, bearing, delta_time);
}
newYawRad = this._toRad(newYaw);
currentLatRad = this._toRad(currentGeoCoordinates.latitude);
currentCosLat = Math.cos(currentLatRad);
currentSinLat = Math.sin(currentLatRad);
currentLonRad = this._toRad(currentGeoCoordinates.longitude);
verticalSpeed = this._getVerticalSpeed(drone);
groundSpeed = Math.sqrt(
Math.pow(drone.get3DSpeed(), 2) - Math.pow(verticalSpeed, 2)
);
distance = (groundSpeed * delta_time / 1000) / R;
distanceCos = Math.cos(distance);
distanceSin = Math.sin(distance);
newLatRad = Math.asin(
currentSinLat * distanceCos +
currentCosLat * distanceSin * Math.cos(newYawRad)
);
newLonRad = currentLonRad + Math.atan2(
Math.sin(newYawRad) * distanceSin * currentCosLat,
distanceCos - currentSinLat * Math.sin(newLatRad)
);
newCoordinates = this._mapManager.convertToLocalCoordinates( drone.setDirection(
this._toDeg(newLatRad), xyCoef * Math.cos(yawToDirection),
this._toDeg(newLonRad), xyCoef * Math.sin(yawToDirection),
drone.position.z zNorm
); );
// swap y and z axis so z axis represents altitude
drone._controlMesh.position.addInPlace(new BABYLON.Vector3( drone._controlMesh.position.addInPlace(new BABYLON.Vector3(
Math.abs(newCoordinates.x - drone.position.x) * drone._direction.x * positionUpdate,
(newCoordinates.x < drone.position.x ? -1 : 1), drone._direction.y * positionUpdate,
verticalSpeed * delta_time / 1000, drone._direction.z * positionUpdate
Math.abs(newCoordinates.y - drone.position.y) *
(newCoordinates.y < drone.position.y ? -1 : 1)
)); ));
yawToDirection = this._toRad(-newYaw + 90);
drone.setDirection(
groundSpeed * Math.cos(yawToDirection),
groundSpeed * Math.sin(yawToDirection),
verticalSpeed
);
}; };
FixedWingDroneAPI.prototype._getNewYaw = FixedWingDroneAPI.prototype._getNewYaw =
...@@ -289,14 +377,20 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -289,14 +377,20 @@ var FixedWingDroneAPI = /** @class */ (function () {
return verticalSpeed; return verticalSpeed;
}; };
FixedWingDroneAPI.prototype._setSpeedInternal = function (speed) {
this._targetSpeed = speed;
};
FixedWingDroneAPI.prototype.setSpeed = function (drone, speed) { FixedWingDroneAPI.prototype.setSpeed = function (drone, speed) {
this._targetSpeed = Math.max( if (speed < this.getMinSpeed()) {
Math.min(speed, this.getMaxSpeed()), throw new Error('Requested speed must be greater than '
this.getMinSpeed() + this.getMinSpeed());
); }
this._requestedSpeed = Math.min(speed, this.getMaxSpeed());
this._setSpeedInternal(this._requestedSpeed * this.getSpeedFactor());
drone._acceleration = (this._targetSpeed > drone.get3DSpeed()) ? drone._acceleration = (this._targetSpeed > drone.get3DSpeed())
this.getMaxAcceleration() : -this.getMaxDeceleration(); ? this.getMaxAcceleration() : this.getMaxDeceleration();
}; };
FixedWingDroneAPI.prototype.setStartingPosition = function (drone, x, y, z) { FixedWingDroneAPI.prototype.setStartingPosition = function (drone, x, y, z) {
...@@ -460,6 +554,9 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -460,6 +554,9 @@ var FixedWingDroneAPI = /** @class */ (function () {
FixedWingDroneAPI.prototype.getMaxClimbRate = function () { FixedWingDroneAPI.prototype.getMaxClimbRate = function () {
return this._flight_parameters.drone.maxClimbRate; return this._flight_parameters.drone.maxClimbRate;
}; };
FixedWingDroneAPI.prototype.getSpeedFactor = function () {
return this._flight_parameters.drone.speedFactor;
};
FixedWingDroneAPI.prototype.getMaxCommandFrequency = function () { FixedWingDroneAPI.prototype.getMaxCommandFrequency = function () {
return this._flight_parameters.drone.maxCommandFrequency; return this._flight_parameters.drone.maxCommandFrequency;
}; };
...@@ -511,7 +608,7 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -511,7 +608,7 @@ var FixedWingDroneAPI = /** @class */ (function () {
Math.pow(direction.z * drone.get3DSpeed(), 2) Math.pow(direction.z * drone.get3DSpeed(), 2)
); );
}; };
FixedWingDroneAPI.prototype.takeOff = function () { FixedWingDroneAPI.prototype.takeOff = function (drone) {
return console.log("Fixed-wing drones can only be taken off manually."); return console.log("Fixed-wing drones can only be taken off manually.");
}; };
FixedWingDroneAPI.prototype.land = function (drone) { FixedWingDroneAPI.prototype.land = function (drone) {
......
...@@ -246,7 +246,7 @@ ...@@ -246,7 +246,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1015.64140.4755.42274</string> </value> <value> <string>1020.30340.52915.63897</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -266,7 +266,7 @@ ...@@ -266,7 +266,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1713430403.75</float> <float>1730817258.54</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -426,7 +426,7 @@ var DroneManager = /** @class */ (function () { ...@@ -426,7 +426,7 @@ var DroneManager = /** @class */ (function () {
return; return;
}; };
DroneManager.prototype.takeOff = function () { DroneManager.prototype.takeOff = function () {
return this._API.takeOff(); return this._API.takeOff(this);
}; };
DroneManager.prototype.land = function () { DroneManager.prototype.land = function () {
if (!this.isLanding()) { if (!this.isLanding()) {
...@@ -773,6 +773,7 @@ var GameManager = /** @class */ (function () { ...@@ -773,6 +773,7 @@ var GameManager = /** @class */ (function () {
} }
this.APIs_dict = { this.APIs_dict = {
FixedWingDroneAPI: FixedWingDroneAPI, FixedWingDroneAPI: FixedWingDroneAPI,
MulticopterDroneAPI: MulticopterDroneAPI,
EnemyDroneAPI: EnemyDroneAPI EnemyDroneAPI: EnemyDroneAPI
}; };
if (this._game_parameters_json.debug_test_mode) { if (this._game_parameters_json.debug_test_mode) {
...@@ -895,15 +896,8 @@ var GameManager = /** @class */ (function () { ...@@ -895,15 +896,8 @@ var GameManager = /** @class */ (function () {
if (drone.team === TEAM_ENEMY) { if (drone.team === TEAM_ENEMY) {
return; return;
} }
function distance(a, b) { if (drone.colliderMesh &&
return Math.sqrt(Math.pow((a.x - b.x), 2) + Math.pow((a.y - b.y), 2) + drone.colliderMesh.intersectsMesh(flag, true)) {
Math.pow((a.z - b.z), 2));
}
if (drone.position) {
//TODO epsilon distance is 15 because of fixed wing loiter flights
//there is not a proper collision
if (distance(drone.position, flag.location) <=
this._mapManager.getMapInfo().flag_distance_epsilon) {
drone._internal_crash(new Error('Drone ' + drone.id + drone._internal_crash(new Error('Drone ' + drone.id +
' touched flag ' + flag.id), false); ' touched flag ' + flag.id), false);
if (flag.weight > 0) { if (flag.weight > 0) {
...@@ -911,7 +905,6 @@ var GameManager = /** @class */ (function () { ...@@ -911,7 +905,6 @@ var GameManager = /** @class */ (function () {
drone.score += flag.score; // move score to a global place? GM, MM? drone.score += flag.score; // move score to a global place? GM, MM?
} }
} }
}
}; };
GameManager.prototype._checkCollision = function (drone, other) { GameManager.prototype._checkCollision = function (drone, other) {
...@@ -1061,11 +1054,14 @@ var GameManager = /** @class */ (function () { ...@@ -1061,11 +1054,14 @@ var GameManager = /** @class */ (function () {
drone_position.z drone_position.z
); );
game_manager._flight_log[index].push([ game_manager._flight_log[index].push([
current_time, geo_coordinates.latitude, current_time.toFixed(0),
geo_coordinates.longitude, geo_coordinates.latitude.toFixed(4),
map_info.start_AMSL + drone_position.z, geo_coordinates.longitude.toFixed(4),
drone_position.z, drone.getYaw(), drone.getSpeed(), (map_info.start_AMSL + drone_position.z).toFixed(4),
drone.getClimbRate() drone_position.z.toFixed(4),
drone.getYaw().toFixed(0),
drone.getSpeed().toFixed(2),
drone.getClimbRate().toFixed(6)
]); ]);
} }
} }
......
...@@ -246,7 +246,7 @@ ...@@ -246,7 +246,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1017.22735.36044.31948</string> </value> <value> <string>1020.30714.54302.56558</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -266,7 +266,7 @@ ...@@ -266,7 +266,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1718719762.65</float> <float>1730822107.38</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
var MapUtils = /** @class */ (function () { var MapUtils = /** @class */ (function () {
"use strict"; "use strict";
var FLAG_EPSILON = 15, R = 6371e3, FLAG_WEIGHT = 5, FLAG_SCORE = 5; var R = 6371e3, FLAG_WEIGHT = 5, FLAG_SCORE = 5;
//** CONSTRUCTOR //** CONSTRUCTOR
function MapUtils(map_param) { function MapUtils(map_param) {
...@@ -27,8 +27,7 @@ var MapUtils = /** @class */ (function () { ...@@ -27,8 +27,7 @@ var MapUtils = /** @class */ (function () {
); );
_this.map_info = { _this.map_info = {
"depth": _this.map_param.depth, "depth": _this.map_param.depth,
"width": _this.map_param.width, "width": _this.map_param.width
"flag_distance_epsilon": map_param.flag_distance_epsilon || FLAG_EPSILON
}; };
_this.map_info.height = _this.map_param.height; _this.map_info.height = _this.map_param.height;
_this.map_info.start_AMSL = _this.map_param.start_AMSL; _this.map_info.start_AMSL = _this.map_param.start_AMSL;
......
...@@ -242,7 +242,7 @@ ...@@ -242,7 +242,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1017.22488.12960.6280</string> </value> <value> <string>1020.30710.25287.37376</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -262,7 +262,7 @@ ...@@ -262,7 +262,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1718708011.02</float> <float>1730822161.12</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
/*global BABYLON, console*/
/*jslint nomen: true, indent: 2, maxlen: 80, todo: true */
/************************** MULTICOPTER DRONE API ****************************/
var MulticopterDroneAPI = /** @class */ (function () {
"use strict";
var DEFAULT_SPEED = 5,
DEFAULT_TAKEOFF_ALTITUDE = 7,
MAX_MESSAGE_SIZE = 1024,
VIEW_SCOPE = 100;
MulticopterDroneAPI.DRONE_TYPE = "Multicopter";
MulticopterDroneAPI.SCRIPT_NAME =
"gadget_erp5_page_drone_capture_flag_multicopterdrone.js";
MulticopterDroneAPI.FORM_VIEW = {
"my_drone_max_speed": {
"description": "",
"title": "Drone max speed",
"default": 16,
"css_class": "",
"required": 1,
"editable": 1,
"key": "maxSpeed",
"hidden": 0,
"type": "IntegerField"
},
"my_drone_max_acceleration": {
"description": "",
"title": "Drone max Acceleration",
"default": 1,
"css_class": "",
"required": 1,
"editable": 1,
"key": "maxAcceleration",
"hidden": 0,
"type": "FloatField"
},
"my_drone_max_deceleration": {
"description": "",
"title": "Drone max Deceleration",
"default": 3,
"css_class": "",
"required": 1,
"editable": 1,
"key": "maxDeceleration",
"hidden": 0,
"type": "IntegerField"
},
"my_drone_max_roll": {
"description": "",
"title": "Drone max roll",
"default": 13,
"css_class": "",
"required": 1,
"editable": 1,
"key": "maxRoll",
"hidden": 0,
"type": "FloatField"
},
"my_drone_speed_factor": {
"description": "",
"title": "Drone speed factor",
"default": 1.2,
"css_class": "",
"required": 1,
"editable": 1,
"key": "speedFactor",
"hidden": 0,
"type": "FloatField"
},
"my_drone_min_approach_speed": {
"description": "",
"title": "Drone min approach speed",
"default": 0.1,
"css_class": "",
"required": 1,
"editable": 1,
"key": "minApproachSpeed",
"hidden": 0,
"type": "FloatField"
},
"my_drone_take_off_factor": {
"description": "",
"title": "Drone take off factor",
"default": 20,
"css_class": "",
"required": 1,
"editable": 1,
"key": "takeOffFactor",
"hidden": 0,
"type": "FloatField"
},
"my_drone_yaw_acceptance": {
"description": "",
"title": "Drone yaw acceptance",
"default": 1,
"css_class": "",
"required": 1,
"editable": 1,
"key": "yawAcceptance",
"hidden": 0,
"type": "FloatField"
},
"my_drone_max_command_frequency": {
"description": "",
"title": "Drone max command frequency",
"default": 2,
"css_class": "",
"required": 1,
"editable": 1,
"key": "maxCommandFrequency",
"hidden": 0,
"type": "FloatField"
}
};
//** CONSTRUCTOR
function MulticopterDroneAPI(gameManager, drone_info, flight_parameters, id) {
this._gameManager = gameManager;
this._mapManager = this._gameManager._mapManager;
this._map_dict = this._mapManager.getMapInfo();
this._flight_parameters = flight_parameters;
this._id = id;
this._drone_info = drone_info;
//this._start_altitude = 0;
this._is_landing = false;
this._is_ready_to_fly = false;
this._drone_dict_list = [];
}
/*
** Function called on start phase of the drone, just before onStart AI script
*/
MulticopterDroneAPI.prototype.internal_start = function (drone) {
if (this.getMaxDeceleration() <= 0) {
throw new Error('max deceleration must be superior to 0');
}
if (this.getMaxAcceleration() <= 0) {
throw new Error('max acceleration must be superior to 0');
}
if (this.getMaxSpeed() <= 0) {
throw new Error('Max speed must be superior to 0');
}
drone._speed = drone._targetSpeed = 0;
if (this.getMaxRollAngle() <= 0) {
throw new Error('max roll angle must be superior to 0');
}
if (this.getMaxCommandFrequency() <= 0) {
throw new Error('max command frequence must be superior to 0');
}
return;
};
/*
** Function called on every drone update, right before onUpdate AI script
*/
MulticopterDroneAPI.prototype.internal_position_update =
function (context, delta_time) {
var currentGeoCoordinates = this._mapManager.convertToGeoCoordinates(
context.position.x,
context.position.y,
context.position.z
),
targetCoordinates = this._mapManager.convertToGeoCoordinates(
context._targetCoordinates.x,
context._targetCoordinates.y,
context._targetCoordinates.z
),
bearing = this._computeBearing(
currentGeoCoordinates.latitude,
currentGeoCoordinates.longitude,
targetCoordinates.latitude,
targetCoordinates.longitude
),
newYaw = this._getNewYaw(context, bearing, delta_time);
if (!this.isReadyToFly() && !this.isLanding()
&& context.position.z >= DEFAULT_TAKEOFF_ALTITUDE) {
this._is_ready_to_fly = true;
context._speed = 0;
}
if (Math.abs(bearing - newYaw) < this.getYawAcceptance()) {
this._updateSpeed(context, currentGeoCoordinates, targetCoordinates,
delta_time);
}
this._updatePosition(context, newYaw, delta_time);
context._controlMesh.computeWorldMatrix(true);
context._mesh.computeWorldMatrix(true);
};
/*
** Function called on every drone update, right after onUpdate AI script
*/
MulticopterDroneAPI.prototype.internal_info_update = function (drone) {
var _this = this, drone_position = drone.getCurrentPosition(), drone_info;
/*if (_this._start_altitude > 0) { //TODO move start_altitude here
_this.reachAltitude(drone);
}*/
if (drone_position) {
drone_info = {
'altitudeRel' : drone_position.altitude,
'altitudeAbs' : _this._mapManager.getMapInfo().start_AMSL +
drone_position.altitude,
'latitude' : drone_position.latitude,
'longitude' : drone_position.longitude,
'yaw': drone.getYaw(),
'speed': drone.getSpeed(),
'climbRate': drone.getClimbRate(),
'timestamp': drone_position.timestamp
};
_this._drone_dict_list[_this._id] = drone_info;
//broadcast drone info using internal msg
_this._gameManager._droneList.forEach(function (drone) {
if (drone.id !== _this._id) {
drone.internal_getMsg(drone_info, _this._id);
}
});
}
};
MulticopterDroneAPI.prototype._updateSpeed =
function (drone, currentGeoCoordinates, targetCoordinates, delta_time) {
var speed = drone.get3DSpeed(), speedDiff, speedUpdate,
distance = Math.sqrt(
Math.pow(
this._mapManager.mapUtils.latLonDistance(
[currentGeoCoordinates.latitude, currentGeoCoordinates.longitude],
[targetCoordinates.latitude, targetCoordinates.longitude]
),
2
) + Math.pow(
targetCoordinates.altitude - currentGeoCoordinates.altitude,
2
)
);
if (this._targetSpeed > distance) {
drone._acceleration = this.getMaxDeceleration();
this._targetSpeed = Math.max(distance, this.getMinApproachSpeed());
}
speedUpdate = drone._acceleration * delta_time / 1000;
if (speed > this._targetSpeed) {
speedUpdate *= -1;
}
if (speed !== this._targetSpeed) {
speedDiff = this._targetSpeed - speed;
if (Math.abs(speedDiff) < Math.abs(speedUpdate)) {
drone._speed = this._targetSpeed;
} else {
drone._speed += speedUpdate;
}
}
};
MulticopterDroneAPI.prototype._updatePosition =
function (drone, yaw, delta_time) {
var positionUpdate = drone.get3DSpeed() * delta_time / 1000,
yawToDirection = this._toRad(-yaw + 90),
xDiff = drone._targetCoordinates.x - drone.position.x,
yDiff = drone._targetCoordinates.y - drone.position.y,
zDiff = drone._targetCoordinates.z - drone.position.z,
distanceToTarget = Math.sqrt(
Math.pow(xDiff, 2) + Math.pow(yDiff, 2) + Math.pow(zDiff, 2)
),
zNorm = zDiff / distanceToTarget,
xyCoef = Math.sqrt(1 - Math.abs(zNorm));
drone.setDirection(
xyCoef * Math.cos(yawToDirection),
xyCoef * Math.sin(yawToDirection),
zNorm
);
drone._controlMesh.position.addInPlace(new BABYLON.Vector3(
drone._direction.x * positionUpdate,
drone._direction.y * positionUpdate,
drone._direction.z * positionUpdate
));
};
MulticopterDroneAPI.prototype._getNewYaw =
function (drone, bearing, delta_time) {
// swap y and z axis so z axis represents altitude
var yaw = drone.getYaw(),
yawDiff = this._computeYawDiff(yaw, bearing),
yawUpdate = this.getYawVelocity(drone) * delta_time / 1000;
if (yawUpdate >= Math.abs(yawDiff)) {
yawUpdate = yawDiff;
} else if (yawDiff < 0) {
yawUpdate *= -1;
}
return yaw + yawUpdate;
};
MulticopterDroneAPI.prototype._setSpeedInternal = function (speed) {
this._targetSpeed = speed;
};
MulticopterDroneAPI.prototype.setSpeed = function (drone, speed) {
if (speed < 0) {
throw new Error('Requested speed must positive');
}
this._requestedSpeed = Math.min(speed, this.getMaxSpeed());
this._setSpeedInternal(this._requestedSpeed * this.getSpeedFactor());
drone._acceleration = (this._targetSpeed > drone.get3DSpeed())
? this.getMaxAcceleration() : this.getMaxDeceleration();
};
MulticopterDroneAPI.prototype.setStartingPosition =
function (drone, x, y, z) {
if (!drone._canPlay) {
if (z <= 0.05) {
z = 0.05;
}
drone._controlMesh.position = new BABYLON.Vector3(x, z, y);
}
drone._controlMesh.computeWorldMatrix(true);
drone._mesh.computeWorldMatrix(true);
};
MulticopterDroneAPI.prototype.internal_getMsg = function (msg, id) {
this._drone_dict_list[id] = msg;
};
MulticopterDroneAPI.prototype.internal_setTargetCoordinates =
function (drone, coordinates, speed, radius) {
this.setSpeed(drone, speed);
};
MulticopterDroneAPI.prototype.sendMsg = function (msg, to) {
if (JSON.stringify(msg).length > MAX_MESSAGE_SIZE) {
//TODO what to do? truncate the msg? log a warning? crash the drone?
msg = {"error": "message too long (max 1024)"};
}
var _this = this,
droneList = _this._gameManager._droneList;
_this._gameManager.delay(function () {
if (to < 0) {
// Send to all drones
droneList.forEach(function (drone) {
if (drone.infosMesh) {
try {
drone.onGetMsg(msg);
} catch (error) {
console.warn('Drone crashed on onGetMsg due to error:', error);
drone._internal_crash();
}
}
});
} else {
// Send to specific drone
if (droneList[to].infosMesh) {
try {
droneList[to].onGetMsg(msg);
} catch (error) {
console.warn('Drone crashed on onGetMsg due to error:', error);
droneList[to]._internal_crash();
}
}
}
}, _this._flight_parameters.latency.communication);
};
MulticopterDroneAPI.prototype.log = function (msg) {
console.log("API say : " + msg);
};
MulticopterDroneAPI.prototype.getGameParameter = function (name) {
if (["gameTime", "map"].includes(name)) {
return this._gameManager.gameParameter[name];
}
};
/*
** Converts geo latitude-longitud coordinates (º) to x,y plane coordinates (m)
*/
MulticopterDroneAPI.prototype.processCoordinates = function (lat, lon, z) {
if (isNaN(lat) || isNaN(lon) || isNaN(z)) {
throw new Error('Target coordinates must be numbers');
}
var processed_coordinates =
this._mapManager.convertToLocalCoordinates(lat, lon, z);
return processed_coordinates;
};
MulticopterDroneAPI.prototype.getCurrentPosition = function (x, y, z) {
return this._mapManager.convertToGeoCoordinates(x, y, z);
};
MulticopterDroneAPI.prototype.getDroneViewInfo = function (drone) {
var context = this, result = { "obstacles": [], "drones": [] }, distance,
other_position, drone_position = drone.getCurrentPosition();
function calculateDistance(a, b, _this) {
return _this._mapManager.latLonDistance([a.latitude, a.longitude],
[b.latitude, b.longitude]);
}
context._gameManager._droneList.forEach(function (other) {
if (other.can_play && drone.id !== other.id) {
other_position = other.getCurrentPosition();
distance = calculateDistance(drone_position, other_position, context);
if (distance <= VIEW_SCOPE) {
result.drones.push({
position: other.getCurrentPosition(),
direction: other.direction,
rotation: other.rotation,
speed: other.speed,
team: other.team
});
}
}
});
context._map_dict.obstacle_list.forEach(function (obstacle) {
distance = calculateDistance(drone_position, obstacle.position, context);
if (distance <= VIEW_SCOPE) {
result.obstacles.push(obstacle);
}
});
if (drone.__is_getting_drone_view !== true) {
drone.__is_getting_drone_view = true;
context._gameManager.delay(function () {
drone.__is_getting_drone_view = false;
try {
drone.onDroneViewInfo(result);
} catch (error) {
console.warn('Drone crashed on drone view due to error:', error);
drone._internal_crash();
}
}, 1000);
}
};
MulticopterDroneAPI.prototype.getDroneAI = function () {
return null;
};
MulticopterDroneAPI.prototype.getMaxSpeed = function () {
return this._flight_parameters.drone.maxSpeed;
};
MulticopterDroneAPI.prototype.getMaxDeceleration = function () {
return this._flight_parameters.drone.maxDeceleration;
};
MulticopterDroneAPI.prototype.getMaxAcceleration = function () {
return this._flight_parameters.drone.maxAcceleration;
};
MulticopterDroneAPI.prototype.getMaxRollAngle = function () {
return this._flight_parameters.drone.maxRoll;
};
MulticopterDroneAPI.prototype.getMaxSinkRate = function () {
return this._flight_parameters.drone.maxSpeed;
};
MulticopterDroneAPI.prototype.getMaxClimbRate = function () {
return this._flight_parameters.drone.maxSpeed;
};
MulticopterDroneAPI.prototype.getSpeedFactor = function () {
return this._flight_parameters.drone.speedFactor;
};
MulticopterDroneAPI.prototype.getMinApproachSpeed = function () {
return this._flight_parameters.drone.minApproachSpeed;
};
MulticopterDroneAPI.prototype.getTakeOffFactor = function () {
return this._flight_parameters.drone.takeOffFactor;
};
MulticopterDroneAPI.prototype.getYawAcceptance = function () {
return this._flight_parameters.drone.yawAcceptance;
};
MulticopterDroneAPI.prototype.getMaxCommandFrequency = function () {
return this._flight_parameters.drone.maxCommandFrequency;
};
MulticopterDroneAPI.prototype.getYawVelocity = function (drone) {
return this.getMaxRollAngle();
};
MulticopterDroneAPI.prototype.getYaw = function (drone) {
var direction = drone.worldDirection;
return this._toDeg(Math.atan2(direction.x, direction.z));
};
MulticopterDroneAPI.prototype._computeBearing =
function (lat1, lon1, lat2, lon2) {
var dLon = this._toRad(lon2 - lon1),
lat1Rad = this._toRad(lat1),
lat2Rad = this._toRad(lat2),
x = Math.cos(lat2Rad) * Math.sin(dLon),
y = Math.cos(lat1Rad) * Math.sin(lat2Rad)
- Math.sin(lat1Rad) * Math.cos(lat2Rad) * Math.cos(dLon);
return this._toDeg(Math.atan2(x, y));
};
MulticopterDroneAPI.prototype._computeYawDiff = function (yaw1, yaw2) {
var diff = yaw2 - yaw1;
diff += (diff > 180) ? -360 : (diff < -180) ? 360 : 0;
return diff;
};
MulticopterDroneAPI.prototype._toRad = function (angle) {
return angle * Math.PI / 180;
};
MulticopterDroneAPI.prototype._toDeg = function (angle) {
return angle * 180 / Math.PI;
};
MulticopterDroneAPI.prototype.getClimbRate = function (drone) {
return drone.worldDirection.y * drone.get3DSpeed();
};
MulticopterDroneAPI.prototype.getSpeed = function (drone) {
var direction = drone.worldDirection;
return Math.sqrt(
Math.pow(direction.x * drone.get3DSpeed(), 2)
+ Math.pow(direction.z * drone.get3DSpeed(), 2)
);
};
MulticopterDroneAPI.prototype.takeOff = function (drone) {
var drone_pos = drone.getCurrentPosition();
drone._internal_setTargetCoordinates(
drone_pos.latitude,
drone_pos.longitude,
DEFAULT_TAKEOFF_ALTITUDE,
DEFAULT_SPEED
);
drone._acceleration = this.getMaxAcceleration() / this.getTakeOffFactor();
};
MulticopterDroneAPI.prototype.land = function (drone) {
var drone_pos = drone.getCurrentPosition();
drone._internal_setTargetCoordinates(
drone_pos.latitude,
drone_pos.longitude,
0,
DEFAULT_SPEED
);
this._is_ready_to_fly = false;
this._is_landing = true;
};
MulticopterDroneAPI.prototype.isReadyToFly = function () {
return this._is_ready_to_fly;
};
MulticopterDroneAPI.prototype.isLanding = function () {
return this._is_landing;
};
MulticopterDroneAPI.prototype.getInitialAltitude = function () {
return this._map_dict.start_AMSL;
};
MulticopterDroneAPI.prototype.getAltitudeAbs = function (altitude) {
return altitude + this._map_dict.start_AMSL;
};
MulticopterDroneAPI.prototype.getMinHeight = function () {
return 0;
};
MulticopterDroneAPI.prototype.getMaxHeight = function () {
return 800;
};
MulticopterDroneAPI.prototype.getOnUpdateInterval = function () {
return this._flight_parameters.drone.onUpdateInterval;
};
MulticopterDroneAPI.prototype.getFlightParameters = function () {
return this._flight_parameters;
};
return MulticopterDroneAPI;
}());
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Web Script" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_Access_contents_information_Permission</string> </key>
<value>
<tuple>
<string>Anonymous</string>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Add_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Change_local_roles_Permission</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Modify_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_View_Permission</string> </key>
<value>
<tuple>
<string>Anonymous</string>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>content_md5</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>gadget_erp5_page_drone_capture_flag_multicopterdrone.js</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>drone_capture_flag_multicopterdrone_js</string> </value>
</item>
<item>
<key> <string>language</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Web Script</string> </value>
</item>
<item>
<key> <string>short_title</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Multicopter Drone (API)</string> </value>
</item>
<item>
<key> <string>version</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>document_publication_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>edit_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
<item>
<key> <string>processing_status_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAU=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>publish_alive</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <unicode>zope</unicode> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="DateTime" module="DateTime.DateTime"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1730800031.8</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>published_alive</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>edit</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <unicode>zope</unicode> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>1020.34636.19071.11520</string> </value>
</item>
<item>
<key> <string>state</string> </key>
<value> <string>current</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="DateTime" module="DateTime.DateTime"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1731937150.42</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="5" aka="AAAAAAAAAAU=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>detect_converted_file</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <unicode>zope</unicode> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_processing_state</string> </key>
<value> <string>converted</string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>0.0.0.0</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="DateTime" module="DateTime.DateTime"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1730799819.74</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -146,7 +146,7 @@ ...@@ -146,7 +146,7 @@
<div class="line"></div> <div class="line"></div>
<h1>Fixed Wings Drone API</h1> <h1>Drone API</h1>
<h3>API functions</h3> <h3>API functions</h3>
...@@ -454,7 +454,7 @@ ...@@ -454,7 +454,7 @@
<!-- loiter --> <!-- loiter -->
<h4 class="item-name" id="loiter"><span>loiter</span><span>: void</span></h4> <h4 class="item-name" id="loiter"><span>loiter</span><span>: void</span></h4>
<p class="item-descr">Set the drone to loiter mode, it will loiter around the target coordinates. If the given radius is inferior to LOITER_LIMIT (30), then the chosen radius will be the last accepted value when calling loiter function (100 by default).</p> <p class="item-descr">Set the drone to loiter mode (only exists for fixed-wings drones), it will loiter around the target coordinates. If the given radius is inferior to LOITER_LIMIT (30), then the chosen radius will be the last accepted value when calling loiter function (100 by default).</p>
<div> <div>
<h5 class="item-param-1">Param</h5> <h5 class="item-param-1">Param</h5>
......
...@@ -244,7 +244,7 @@ ...@@ -244,7 +244,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1015.13928.44848.25668</string> </value> <value> <string>1017.23884.35535.62190</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -264,7 +264,7 @@ ...@@ -264,7 +264,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1710867839.5</float> <float>1731938073.03</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -19,6 +19,10 @@ ...@@ -19,6 +19,10 @@
<script type="text/javascript" src="./libraries/seedrandom.min.js"></script> <script type="text/javascript" src="./libraries/seedrandom.min.js"></script>
<script src="gadget_erp5_page_drone_capture_map_utils.js" type="text/javascript"></script> <script src="gadget_erp5_page_drone_capture_map_utils.js" type="text/javascript"></script>
<!-- API scripts -->
<script src="gadget_erp5_page_drone_capture_flag_fixedwingdrone.js" type="text/javascript"></script>
<script src="gadget_erp5_page_drone_capture_flag_multicopterdrone.js" type="text/javascript"></script>
<script src="gadget_erp5_page_drone_capture_flag_script_page.js" type="text/javascript"></script> <script src="gadget_erp5_page_drone_capture_flag_script_page.js" type="text/javascript"></script>
</head> </head>
......
...@@ -244,7 +244,7 @@ ...@@ -244,7 +244,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1010.65526.46361.27613</string> </value> <value> <string>1017.23884.35535.62190</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -264,7 +264,7 @@ ...@@ -264,7 +264,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1694194019.23</float> <float>1730801080.42</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
/*jslint indent: 2, maxlen: 100*/ /*jslint indent: 2, maxlen: 100*/
/*global window, rJS, domsugar, document, Blob, MapUtils, RSVP*/ /*global window, rJS, domsugar, document, Blob, MapUtils, RSVP, FixedWingDroneAPI,
MulticopterDroneAPI*/
/******************************* OPERATOR API ********************************/ /******************************* OPERATOR API ********************************/
var OperatorAPI = /** @class */ (function () { var OperatorAPI = /** @class */ (function () {
...@@ -23,10 +24,9 @@ var OperatorAPI = /** @class */ (function () { ...@@ -23,10 +24,9 @@ var OperatorAPI = /** @class */ (function () {
return OperatorAPI; return OperatorAPI;
}()); }());
(function (window, rJS, domsugar, document, Blob, MapUtils, RSVP) { (function (window, rJS, domsugar, document, Blob, MapUtils, RSVP, API_LIST) {
"use strict"; "use strict";
//Drone default values - TODO: get them from the drone API
var SIMULATION_SPEED = 60, var SIMULATION_SPEED = 60,
SIMULATION_TIME = 270, SIMULATION_TIME = 270,
//default square map //default square map
...@@ -65,21 +65,10 @@ var OperatorAPI = /** @class */ (function () { ...@@ -65,21 +65,10 @@ var OperatorAPI = /** @class */ (function () {
"altitude": 15}}], "altitude": 15}}],
"initial_position": {"latitude": 45.642813275, "initial_position": {"latitude": 45.642813275,
"longitude": 14.270231599999988, "longitude": 14.270231599999988,
"altitude": 15} "altitude": 0}
}, },
DEFAULT_SPEED = 16, DEFAULT_SPEED = 16,
MAX_ACCELERATION = 6,
MAX_DECELERATION = 1,
MIN_SPEED = 12,
MAX_SPEED = 26,
MAX_ROLL = 35,
MIN_PITCH = -20,
MAX_PITCH = 25,
MAX_CLIMB_RATE = 8,
MAX_SINK_RATE = 3,
MAX_COMMAND_FREQUENCY = 2,
NUMBER_OF_DRONES = 5, NUMBER_OF_DRONES = 5,
// Non-inputs parameters
EPSILON = "15", EPSILON = "15",
DEFAULT_OPERATOR_SCRIPT = 'var map = operator.getMapJSON();\n' + DEFAULT_OPERATOR_SCRIPT = 'var map = operator.getMapJSON();\n' +
'operator.sendMsg({flag_positions: map.flag_list});\n', 'operator.sendMsg({flag_positions: map.flag_list});\n',
...@@ -109,6 +98,7 @@ var OperatorAPI = /** @class */ (function () { ...@@ -109,6 +98,7 @@ var OperatorAPI = /** @class */ (function () {
' me.direction_set = false;\n' + ' me.direction_set = false;\n' +
' me.dodging = false;\n' + ' me.dodging = false;\n' +
' me.ongoing_detection = false;\n' + ' me.ongoing_detection = false;\n' +
' me.takeOff();\n' +
'};\n' + '};\n' +
'\n' + '\n' +
'me.onGetMsg = function (msg) {\n' + 'me.onGetMsg = function (msg) {\n' +
...@@ -119,6 +109,9 @@ var OperatorAPI = /** @class */ (function () { ...@@ -119,6 +109,9 @@ var OperatorAPI = /** @class */ (function () {
'};\n' + '};\n' +
'\n' + '\n' +
'me.onUpdate = function (timestamp) {\n' + 'me.onUpdate = function (timestamp) {\n' +
' if (!me.isReadyToFly()) {\n' +
' return;\n' +
' }\n' +
' if (!me.flag_positions) return;\n' + ' if (!me.flag_positions) return;\n' +
' if (me.dodging) {\n' + ' if (me.dodging) {\n' +
' me.current_position = me.getCurrentPosition();\n' + ' me.current_position = me.getCurrentPosition();\n' +
...@@ -189,9 +182,10 @@ var OperatorAPI = /** @class */ (function () { ...@@ -189,9 +182,10 @@ var OperatorAPI = /** @class */ (function () {
LOGIC_FILE_LIST = [ LOGIC_FILE_LIST = [
'gadget_erp5_page_drone_capture_flag_logic.js', 'gadget_erp5_page_drone_capture_flag_logic.js',
'gadget_erp5_page_drone_capture_map_utils.js', 'gadget_erp5_page_drone_capture_map_utils.js',
'gadget_erp5_page_drone_capture_flag_fixedwingdrone.js',
'gadget_erp5_page_drone_capture_flag_enemydrone.js' 'gadget_erp5_page_drone_capture_flag_enemydrone.js'
], ].concat(API_LIST.map(function (api) {
return api.SCRIPT_NAME;
})),
DISPLAY_MAP_PARAMETER = 'display_map_parameter', DISPLAY_MAP_PARAMETER = 'display_map_parameter',
DISPLAY_RANDOMIZE = 'display_randomize', DISPLAY_RANDOMIZE = 'display_randomize',
DISPLAY_OPERATOR_PARAMETER = 'display_operator_parameter', DISPLAY_OPERATOR_PARAMETER = 'display_operator_parameter',
...@@ -199,6 +193,12 @@ var OperatorAPI = /** @class */ (function () { ...@@ -199,6 +193,12 @@ var OperatorAPI = /** @class */ (function () {
DISPLAY_GAME_PARAMETER = 'display_game_parameter', DISPLAY_GAME_PARAMETER = 'display_game_parameter',
DISPLAY_PLAY = "display_play"; DISPLAY_PLAY = "display_play";
function getAPI(droneType) {
return API_LIST.find(function (api) {
return api.DRONE_TYPE === droneType;
});
}
function renderGadgetHeader(gadget, loading) { function renderGadgetHeader(gadget, loading) {
var element_list = [], var element_list = [],
game_map_icon = 'ui-icon-map-marker', game_map_icon = 'ui-icon-map-marker',
...@@ -534,7 +534,7 @@ var OperatorAPI = /** @class */ (function () { ...@@ -534,7 +534,7 @@ var OperatorAPI = /** @class */ (function () {
// Game parameters // Game parameters
////////////////////////////////////////////////// //////////////////////////////////////////////////
function renderGameParameterView(gadget) { function renderGameParameterView(gadget) {
var form_gadget; var api = getAPI(gadget.state.drone_type), erp5_view, form_gadget;
renderGadgetHeader(gadget, true); renderGadgetHeader(gadget, true);
return gadget.declareGadget("gadget_erp5_form.html", { return gadget.declareGadget("gadget_erp5_form.html", {
scope: "parameter_form" scope: "parameter_form"
...@@ -542,9 +542,21 @@ var OperatorAPI = /** @class */ (function () { ...@@ -542,9 +542,21 @@ var OperatorAPI = /** @class */ (function () {
.push(function (sub_gadget) { .push(function (sub_gadget) {
form_gadget = sub_gadget; form_gadget = sub_gadget;
return form_gadget.render({ erp5_view = {
erp5_document: { "my_drone_type": {
"_embedded": {"_view": { "description": "Type of drone to simulate",
"title": "Drone Type",
"items": API_LIST.map(function (api) {
return api.DRONE_TYPE;
}),
"value": gadget.state.drone_type,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_type",
"hidden": 0,
"type": "ListField"
},
"my_simulation_speed": { "my_simulation_speed": {
"description": "", "description": "",
"title": "Simulation Speed", "title": "Simulation Speed",
...@@ -578,127 +590,6 @@ var OperatorAPI = /** @class */ (function () { ...@@ -578,127 +590,6 @@ var OperatorAPI = /** @class */ (function () {
"hidden": 0, "hidden": 0,
"type": "IntegerField" "type": "IntegerField"
}, },
"my_drone_min_speed": {
"description": "",
"title": "Drone min speed",
"default": gadget.state.drone_min_speed,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_min_speed",
"hidden": 0,
"type": "IntegerField"
},
"my_drone_speed": {
"description": "",
"title": "Drone speed",
"default": gadget.state.drone_speed,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_speed",
"hidden": 0,
"type": "FloatField"
},
"my_drone_max_speed": {
"description": "",
"title": "Drone max speed",
"default": gadget.state.drone_max_speed,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_max_speed",
"hidden": 0,
"type": "IntegerField"
},
"my_drone_max_acceleration": {
"description": "",
"title": "Drone max Acceleration",
"default": gadget.state.drone_max_acceleration,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_max_acceleration",
"hidden": 0,
"type": "IntegerField"
},
"my_drone_max_deceleration": {
"description": "",
"title": "Drone max Deceleration",
"default": gadget.state.drone_max_deceleration,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_max_deceleration",
"hidden": 0,
"type": "IntegerField"
},
"my_drone_max_roll": {
"description": "",
"title": "Drone max roll",
"default": gadget.state.drone_max_roll,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_max_roll",
"hidden": 0,
"type": "FloatField"
},
"my_drone_min_pitch": {
"description": "",
"title": "Drone min pitch",
"default": gadget.state.drone_min_pitch,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_min_pitch",
"hidden": 0,
"type": "FloatField"
},
"my_drone_max_pitch": {
"description": "",
"title": "Drone max pitch",
"default": gadget.state.drone_max_pitch,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_max_pitch",
"hidden": 0,
"type": "FloatField"
},
"my_drone_max_sink_rate": {
"description": "",
"title": "Drone max sink rate",
"default": gadget.state.drone_max_sink_rate,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_max_sink_rate",
"hidden": 0,
"type": "FloatField"
},
"my_drone_max_climb_rate": {
"description": "",
"title": "Drone max climb rate",
"default": gadget.state.drone_max_climb_rate,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_max_climb_rate",
"hidden": 0,
"type": "FloatField"
},
"my_drone_max_command_frequency": {
"description": "",
"title": "Drone max command frequency",
"default": gadget.state.drone_max_command_frequency,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_max_command_frequency",
"hidden": 0,
"type": "FloatField"
},
"my_number_of_drones": { "my_number_of_drones": {
"description": "", "description": "",
"title": "Number of drones", "title": "Number of drones",
...@@ -710,7 +601,15 @@ var OperatorAPI = /** @class */ (function () { ...@@ -710,7 +601,15 @@ var OperatorAPI = /** @class */ (function () {
"hidden": 0, "hidden": 0,
"type": "IntegerField" "type": "IntegerField"
} }
}}, };
Object.keys(api.FORM_VIEW).forEach(function (parameter) {
erp5_view[parameter] = api.FORM_VIEW[parameter];
erp5_view[parameter].default = gadget.state[erp5_view[parameter].key];
});
return form_gadget.render({
erp5_document: {
"_embedded": {"_view": erp5_view},
"_links": { "_links": {
"type": { "type": {
name: "" name: ""
...@@ -720,15 +619,13 @@ var OperatorAPI = /** @class */ (function () { ...@@ -720,15 +619,13 @@ var OperatorAPI = /** @class */ (function () {
form_definition: { form_definition: {
group_list: [[ group_list: [[
"left", "left",
[["my_simulation_speed"], ["my_simulation_time"], ["my_onupdate_interval"], [["my_drone_type"], ["my_simulation_speed"], ["my_simulation_time"],
["my_number_of_drones"], ["my_map_seed"]] ["my_onupdate_interval"], ["my_number_of_drones"]]
], [ ], [
"right", "right",
[["my_drone_min_speed"], ["my_drone_speed"], ["my_drone_max_speed"], Object.keys(api.FORM_VIEW).map(function (property_name) {
["my_drone_max_acceleration"], ["my_drone_max_deceleration"], return [property_name];
["my_drone_max_roll"], ["my_drone_min_pitch"], ["my_drone_max_pitch"], })
["my_drone_max_sink_rate"], ["my_drone_max_climb_rate"],
["my_drone_max_command_frequency"]]
]] ]]
} }
}); });
...@@ -806,6 +703,13 @@ var OperatorAPI = /** @class */ (function () { ...@@ -806,6 +703,13 @@ var OperatorAPI = /** @class */ (function () {
}); });
} }
function formToFilename(form, drone) {
return Object.keys(form).map(function (field_name) {
var key = form[field_name].key;
return key + "_" + drone[key];
});
}
rJS(window) rJS(window)
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// Acquired methods // Acquired methods
...@@ -817,10 +721,33 @@ var OperatorAPI = /** @class */ (function () { ...@@ -817,10 +721,33 @@ var OperatorAPI = /** @class */ (function () {
return this.triggerSubmit(); return this.triggerSubmit();
}) })
.allowPublicAcquisition('notifyChange', function (argument_list, scope) {
return this.triggerAPIChange(scope);
})
.declareMethod("triggerSubmit", function () { .declareMethod("triggerSubmit", function () {
return; return;
}) })
.declareMethod("triggerAPIChange", function (scope) {
var gadget = this,
sub_gadget;
return gadget.getDeclaredGadget(scope)
.push(function (result) {
sub_gadget = result;
return sub_gadget.getContent();
})
.push(function (result) {
if (result.hasOwnProperty("drone_type")
&& gadget.state.drone_type !== result.drone_type) {
return gadget.changeState({
drone_type: result.drone_type
});
}
});
})
.declareJob('runGame', function runGame(do_nothing) { .declareJob('runGame', function runGame(do_nothing) {
if (do_nothing) { if (do_nothing) {
// Cancel the previous job execution // Cancel the previous job execution
...@@ -829,13 +756,14 @@ var OperatorAPI = /** @class */ (function () { ...@@ -829,13 +756,14 @@ var OperatorAPI = /** @class */ (function () {
var gadget = this, var gadget = this,
i, i,
parsed_map, parsed_map,
fragment = gadget.element.querySelector('.simulator_div'),
game_parameters_json,
drone_list = [];
fragment = domsugar(gadget.element.querySelector('.simulator_div'), fragment = domsugar(gadget.element.querySelector('.simulator_div'),
[domsugar('div')]).firstElementChild; [domsugar('div')]).firstElementChild,
game_parameters_json,
drone_list = [],
api = getAPI(gadget.state.drone_type),
drone_parameter_list = Object.keys(api.FORM_VIEW);
for (i = 0; i < gadget.state.number_of_drones; i += 1) { for (i = 0; i < gadget.state.number_of_drones; i += 1) {
drone_list[i] = {"id": i, "type": "FixedWingDroneAPI", drone_list[i] = {"id": i, "type": api.name,
"script_content": gadget.state.drone_script}; "script_content": gadget.state.drone_script};
} }
try { try {
...@@ -846,17 +774,6 @@ var OperatorAPI = /** @class */ (function () { ...@@ -846,17 +774,6 @@ var OperatorAPI = /** @class */ (function () {
} }
game_parameters_json = { game_parameters_json = {
"drone": { "drone": {
"maxAcceleration": parseInt(gadget.state.drone_max_acceleration, 10),
"maxDeceleration": parseInt(gadget.state.drone_max_deceleration, 10),
"minSpeed": parseInt(gadget.state.drone_min_speed, 10),
"speed": parseFloat(gadget.state.drone_speed),
"maxSpeed": parseInt(gadget.state.drone_max_speed, 10),
"maxRoll": parseFloat(gadget.state.drone_max_roll),
"minPitchAngle": parseFloat(gadget.state.drone_min_pitch),
"maxPitchAngle": parseFloat(gadget.state.drone_max_pitch),
"maxSinkRate": parseFloat(gadget.state.drone_max_sink_rate),
"maxClimbRate": parseFloat(gadget.state.drone_max_climb_rate),
"maxCommandFrequency": parseFloat(gadget.state.drone_max_command_frequency),
"onUpdateInterval": parseInt(gadget.state.onupdate_interval, 10), "onUpdateInterval": parseInt(gadget.state.onupdate_interval, 10),
"list": drone_list "list": drone_list
}, },
...@@ -873,6 +790,19 @@ var OperatorAPI = /** @class */ (function () { ...@@ -873,6 +790,19 @@ var OperatorAPI = /** @class */ (function () {
"log_drone_flight": LOG, "log_drone_flight": LOG,
"log_interval_time": LOG_TIME "log_interval_time": LOG_TIME
}; };
drone_parameter_list.forEach(function (parameter) {
var field = api.FORM_VIEW[parameter];
switch (field.type) {
case 'IntegerField':
game_parameters_json.drone[field.key] = parseInt(gadget.state[field.key], 10);
break;
case 'FloatField':
game_parameters_json.drone[field.key] = parseFloat(gadget.state[field.key]);
break;
default:
throw new Error("Unhandled field type");
}
});
return gadget.declareGadget("babylonjs.gadget.html", return gadget.declareGadget("babylonjs.gadget.html",
{element: fragment, scope: 'simulator'}) {element: fragment, scope: 'simulator'})
.push(function () { .push(function () {
...@@ -932,18 +862,9 @@ var OperatorAPI = /** @class */ (function () { ...@@ -932,18 +862,9 @@ var OperatorAPI = /** @class */ (function () {
blob = new Blob([log_content], {type: 'text/plain'}); blob = new Blob([log_content], {type: 'text/plain'});
a = domsugar('a', { a = domsugar('a', {
text: 'Download Simulation LOG ' + i, text: 'Download Simulation LOG ' + i,
download: 'simulation_log_' + i + download: ['simulation_log_' + i].concat(
'_speed_' + game_parameters_json.drone.speed + formToFilename(api.FORM_VIEW, game_parameters_json.drone)
'_min-speed_' + game_parameters_json.drone.minSpeed + ).join("_") + ".txt",
'_max-speed_' + game_parameters_json.drone.maxSpeed +
'_max-accel_' + game_parameters_json.drone.maxAcceleration +
'_max-decel_' + game_parameters_json.drone.maxDeceleration +
'_max-roll_' + game_parameters_json.drone.maxRoll +
'_min-pitch_' + game_parameters_json.drone.minPitchAngle +
'_max-pitch_' + game_parameters_json.drone.maxPitchAngle +
'_max-sink_' + game_parameters_json.drone.maxSinkRate +
'_max-climb_' + game_parameters_json.drone.maxClimbRate +
'.txt',
href: window.URL.createObjectURL(blob) href: window.URL.createObjectURL(blob)
}); });
log = domsugar('textarea', log = domsugar('textarea',
...@@ -969,20 +890,10 @@ var OperatorAPI = /** @class */ (function () { ...@@ -969,20 +890,10 @@ var OperatorAPI = /** @class */ (function () {
}) })
.setState({ .setState({
drone_type: API_LIST[0].DRONE_TYPE,
operator_script: DEFAULT_OPERATOR_SCRIPT, operator_script: DEFAULT_OPERATOR_SCRIPT,
drone_script: DEFAULT_SCRIPT_CONTENT, drone_script: DEFAULT_SCRIPT_CONTENT,
number_of_drones: NUMBER_OF_DRONES, number_of_drones: NUMBER_OF_DRONES,
drone_max_command_frequency: MAX_COMMAND_FREQUENCY,
drone_max_climb_rate: MAX_CLIMB_RATE,
drone_max_sink_rate: MAX_SINK_RATE,
drone_max_pitch: MAX_PITCH,
drone_min_pitch: MIN_PITCH,
drone_max_roll: MAX_ROLL,
drone_max_deceleration: MAX_DECELERATION,
drone_max_acceleration: MAX_ACCELERATION,
drone_max_speed: MAX_SPEED,
drone_speed: DEFAULT_SPEED,
drone_min_speed: MIN_SPEED,
onupdate_interval: ONUPDATE_INTERVAL, onupdate_interval: ONUPDATE_INTERVAL,
simulation_time: SIMULATION_TIME, simulation_time: SIMULATION_TIME,
simulation_speed: SIMULATION_SPEED, simulation_speed: SIMULATION_SPEED,
...@@ -994,10 +905,14 @@ var OperatorAPI = /** @class */ (function () { ...@@ -994,10 +905,14 @@ var OperatorAPI = /** @class */ (function () {
}) })
.declareMethod('render', function render() { .declareMethod('render', function render() {
var gadget = this; var gadget = this,
return gadget.changeState({ api = getAPI(gadget.state.drone_type),
display_step: DISPLAY_PLAY new_state = { display_step: DISPLAY_PLAY };
}) Object.keys(api.FORM_VIEW).forEach(function (parameter) {
var field = api.FORM_VIEW[parameter];
new_state[field.key] = field.default;
});
return gadget.changeState(new_state)
.push(function () { .push(function () {
return gadget.updateHeader({ return gadget.updateHeader({
page_title: 'Drone Capture Flag', page_title: 'Drone Capture Flag',
...@@ -1007,7 +922,7 @@ var OperatorAPI = /** @class */ (function () { ...@@ -1007,7 +922,7 @@ var OperatorAPI = /** @class */ (function () {
}) })
.onStateChange(function (modification_dict) { .onStateChange(function (modification_dict) {
var gadget = this; var gadget = this, api;
if (gadget.state.display_step === DISPLAY_MAP_PARAMETER) { if (gadget.state.display_step === DISPLAY_MAP_PARAMETER) {
if (modification_dict.hasOwnProperty('display_step')) { if (modification_dict.hasOwnProperty('display_step')) {
...@@ -1048,6 +963,15 @@ var OperatorAPI = /** @class */ (function () { ...@@ -1048,6 +963,15 @@ var OperatorAPI = /** @class */ (function () {
return renderPlayView(gadget); return renderPlayView(gadget);
} }
if (modification_dict.hasOwnProperty('drone_type')) {
api = getAPI(gadget.state.drone_type);
Object.keys(api.FORM_VIEW).forEach(function (parameter) {
var field = api.FORM_VIEW[parameter];
gadget.state[field.key] = field.default;
});
return renderGameParameterView(gadget);
}
if (modification_dict.hasOwnProperty('display_step')) { if (modification_dict.hasOwnProperty('display_step')) {
throw new Error('Unhandled display step: ' + gadget.state.display_step); throw new Error('Unhandled display step: ' + gadget.state.display_step);
} }
...@@ -1170,4 +1094,4 @@ var OperatorAPI = /** @class */ (function () { ...@@ -1170,4 +1094,4 @@ var OperatorAPI = /** @class */ (function () {
}(window, rJS, domsugar, document, Blob, MapUtils, RSVP)); }(window, rJS, domsugar, document, Blob, MapUtils, RSVP, [MulticopterDroneAPI, FixedWingDroneAPI]));
\ No newline at end of file \ No newline at end of file
...@@ -246,7 +246,7 @@ ...@@ -246,7 +246,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1016.21921.52144.47906</string> </value> <value> <string>1020.51982.55228.2918</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -266,7 +266,7 @@ ...@@ -266,7 +266,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1714738877.83</float> <float>1732098322.73</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -63,6 +63,42 @@ ...@@ -63,6 +63,42 @@
<td>//textarea[@id="log_result_0"]</td> <td>//textarea[@id="log_result_0"]</td>
<td></td> <td></td>
<tr> <tr>
<!-- Change drone type -->
<tr>
<td>click</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_page_drone_capture_flag_script_page.html')]//button[text()="Parameters"]</td>
<td></td>
<tr>
<tr>
<td>waitForElementPresent</td>
<td>//label[text()='Drone Type']</td>
<td></td>
<tr>
<tr>
<td>select</td>
<td>//select[@name="drone_type"]</td>
<td>value=Fixed Wings</td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//label[text()='Drone min speed']</td>
<td></td>
<tr>
<tr>
<td>click</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_page_drone_capture_flag_script_page.html')]//button[text()="Run"]</td>
<td></td>
<tr>
<tr>
<td>waitForElementPresent</td>
<td>//span[@id="loading"]</td>
<td></td>
<tr>
<tr>
<td>waitForElementPresent</td>
<td>//a[contains(text(), 'Download Simulation LOG')]</td>
<td></td>
<tr>
</tbody></table> </tbody></table>
</body> </body>
</html> </html>
\ No newline at end of file
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>testDroneSimulatorFlight</string> </value> <value> <string>testDroneCaptureFlagFixedWingFlight</string> </value>
</item> </item>
<item> <item>
<key> <string>output_encoding</string> </key> <key> <string>output_encoding</string> </key>
......
...@@ -9,19 +9,19 @@ ...@@ -9,19 +9,19 @@
<body> <body>
<table cellpadding="1" cellspacing="1" border="1"> <table cellpadding="1" cellspacing="1" border="1">
<thead> <thead>
<tr><td rowspan="1" colspan="3">Test Drone Capture Flag OJS app (expected failure)</td></tr> <tr><td rowspan="1" colspan="3">Test Fixed Wing Drone Capture Flag OJS app (expected failure)</td></tr>
</thead><tbody> </thead><tbody>
<tal:block metal:use-macro="here/Zuite_CommonTemplate/macros/init" /> <tal:block metal:use-macro="here/Zuite_CommonTemplate/macros/init" />
<!-- Go to site --> <!-- Go to site -->
<tr> <tr>
<td>open</td> <td>open</td>
<td>${base_url}/web_site_module/officejs_drone_capture_flag/app/#/?page=drone_capture_flag_test_page</td> <td>${base_url}/web_site_module/officejs_drone_capture_flag/app/#/?page=drone_capture_flag_fixed_wing_test_page</td>
<td></td> <td></td>
</tr> </tr>
<tr> <tr>
<td>waitForElementPresent</td> <td>waitForElementPresent</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_page_drone_capture_flag_test_page.html')]//input[@type="submit" and @name="action_run"]</td> <td>//div[contains(@data-gadget-url, 'gadget_erp5_page_drone_capture_flag_fixed_wing_test_page.html')]//input[@type="submit" and @name="action_run"]</td>
<td></td> <td></td>
<tr> <tr>
<tr> <tr>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ZopePageTemplate" module="Products.PageTemplates.ZopePageTemplate"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>expand</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>testDroneCaptureFlagMulticopterFlight</string> </value>
</item>
<item>
<key> <string>output_encoding</string> </key>
<value> <string>utf-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <unicode></unicode> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<html xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test Drone Capture Flag OJS app (expected failure)</title>
<!-- This test is expected to fail as the drone simulator runs on a web worker canvas, which relies on a very new feature: offscreen canvas
---- This feature is not supported yet by the latest Firefox ESR used in the test nodes -->
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Test Multicopter Drone Capture Flag OJS app (expected failure)</td></tr>
</thead><tbody>
<tal:block metal:use-macro="here/Zuite_CommonTemplate/macros/init" />
<!-- Go to site -->
<tr>
<td>open</td>
<td>${base_url}/web_site_module/officejs_drone_capture_flag/app/#/?page=drone_capture_flag_multicopter_test_page</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_page_drone_capture_flag_multicopter_test_page.html')]//input[@type="submit" and @name="action_run"]</td>
<td></td>
<tr>
<tr>
<td>waitForElementPresent</td>
<td>//span[@id="loading"]</td>
<td></td>
<tr>
<tr>
<td>waitForElementPresent</td>
<td>//div[contains(@data-gadget-url, 'babylonjs.gadget.html')]</td>
<td></td>
<tr>
<tr>
<td>waitForElementPresent</td>
<td>//div[contains(@data-gadget-url, 'babylonjs.gadget.html')]//canvas[contains(@data-engine, 'Babylon.js')]</td>
<td></td>
<tr>
<tr>
<td>waitForElementPresent</td>
<td>//div[contains(text(), 'CONSOLE LOG ENTRIES:')]</td>
<td></td>
<tr>
<tr>
<td>assertElementPresent</td>
<td>//div[contains(text(), 'Initial speed: OK')]</td>
<td></td>
<tr>
<tr>
<td>assertElementPresent</td>
<td>//div[contains(text(), 'Yaw angle: OK')]</td>
<td></td>
<tr>
<tr>
<td>assertElementPresent</td>
<td>//div[contains(text(), 'Timestamp: OK')]</td>
<td></td>
<tr>
<tr>
<td>assertElementPresent</td>
<td>//div[contains(text(), 'Distance: OK')]</td>
<td></td>
<tr>
<tr>
<td>assertElementPresent</td>
<td>//div[contains(text(), 'Latitude: OK')]</td>
<td></td>
<tr>
<tr>
<td>assertElementPresent</td>
<td>//div[contains(text(), 'Longitude: OK')]</td>
<td></td>
<tr>
<tr>
<td>assertElementPresent</td>
<td>//div[contains(text(), 'Altitude: OK')]</td>
<td></td>
<tr>
<tr>
<td>assertElementPresent</td>
<td>//div[contains(text(), 'Timeout: OK')]</td>
<td></td>
<tr>
</tbody></table>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html>
<!--
data-i18n=Others
data-i18n=Tools
-->
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width" />
<title>Drone Simulator Test Page</title>
<link rel="http://www.renderjs.org/rel/interface" href="interface_page.html">
<!-- renderjs -->
<script src="rsvp.js" type="text/javascript"></script>
<script src="renderjs.js" type="text/javascript"></script>
<!-- custom script -->
<script src="jiodev.js" type="text/javascript"></script>
<script src="gadget_global.js" type="text/javascript"></script>
<script src="domsugar.js" type="text/javascript"></script>
<!-- API scripts -->
<script src="gadget_erp5_page_drone_capture_flag_fixedwingdrone.js" type="text/javascript"></script>
<script src="gadget_erp5_page_drone_capture_flag_fixed_wing_test_page.js" type="text/javascript"></script>
</head>
<body>
<form>
<div data-gadget-url="gadget_erp5_form.html"
data-gadget-scope="form_view"
data-gadget-sandbox="public">
</div>
<input name="action_run" class="dialogconfirm" type="submit" value="Run" style="margin-bottom: 20pt;margin-top: 20pt;">
<a data-i18n="Storages"></a> <!-- for zelenium test common macro -->
<div class="simulator_div"></div>
<div data-gadget-url="gadget_erp5_form.html"
data-gadget-scope="form_view_babylonjs"
data-gadget-sandbox="public">
</div>
<div class="test_log"></div>
</form>
</body>
</html>
\ No newline at end of file
...@@ -73,7 +73,7 @@ ...@@ -73,7 +73,7 @@
</item> </item>
<item> <item>
<key> <string>default_reference</string> </key> <key> <string>default_reference</string> </key>
<value> <string>gadget_erp5_page_drone_capture_flag_test_page.html</string> </value> <value> <string>gadget_erp5_page_drone_capture_flag_fixed_wing_test_page.html</string> </value>
</item> </item>
<item> <item>
<key> <string>description</string> </key> <key> <string>description</string> </key>
...@@ -83,7 +83,7 @@ ...@@ -83,7 +83,7 @@
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>test_capture_drone_flight_html</string> </value> <value> <string>test_capture_drone_fixed_wing_flight_html</string> </value>
</item> </item>
<item> <item>
<key> <string>language</string> </key> <key> <string>language</string> </key>
...@@ -103,7 +103,7 @@ ...@@ -103,7 +103,7 @@
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
<value> <string>Drone Capture Flag Test Page</string> </value> <value> <string>Drone Capture Flag Fixed Wing Test Page</string> </value>
</item> </item>
<item> <item>
<key> <string>version</string> </key> <key> <string>version</string> </key>
...@@ -244,7 +244,7 @@ ...@@ -244,7 +244,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1009.56051.5673.26368</string> </value> <value> <string>1020.30404.9679.22971</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -264,7 +264,7 @@ ...@@ -264,7 +264,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1690898380.88</float> <float>1730823497.17</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
/*jslint indent: 2, maxlen: 100*/ /*jslint indent: 2, maxlen: 100*/
/*global window, rJS, domsugar, document*/ /*global window, rJS, domsugar, document, FixedWingDroneAPI*/
(function (window, rJS, domsugar, document) { (function (window, rJS, domsugar, document, FixedWingDroneAPI) {
"use strict"; "use strict";
var SIMULATION_SPEED = 1, var SIMULATION_SPEED = 1,
...@@ -17,17 +17,7 @@ ...@@ -17,17 +17,7 @@
INIT_LAT = 45.6412, INIT_LAT = 45.6412,
INIT_ALT = 15, INIT_ALT = 15,
DEFAULT_SPEED = 16, DEFAULT_SPEED = 16,
MAX_ACCELERATION = 6,
MAX_DECELERATION = 1,
MIN_SPEED = 12,
MAX_SPEED = 26,
MAX_ROLL = 35,
MIN_PITCH = -20,
MAX_PITCH = 25,
MAX_CLIMB_RATE = 8,
MAX_SINK_RATE = 3,
NUMBER_OF_DRONES = 1, NUMBER_OF_DRONES = 1,
// Non-inputs parameters
DEFAULT_SCRIPT_CONTENT = DEFAULT_SCRIPT_CONTENT =
'function assert(a, b, msg) {\n' + 'function assert(a, b, msg) {\n' +
' if (a === b)\n' + ' if (a === b)\n' +
...@@ -49,14 +39,14 @@ ...@@ -49,14 +39,14 @@
'}\n' + '}\n' +
'\n' + '\n' +
'function compare(coord1, coord2) {\n' + 'function compare(coord1, coord2) {\n' +
' assert(coord1.latitude, coord2.latitude, "Latitude")\n' + ' assert(coord1.latitude, coord2.latitude, "Latitude");\n' +
' assert(coord1.longitude, coord2.longitude, "Longitude")\n' + ' assert(coord1.longitude, coord2.longitude, "Longitude");\n' +
' assert(coord1.altitude, coord2.altitude, "Altitude")\n' + ' assert(coord1.altitude, coord2.altitude, "Altitude");\n' +
'}\n' + '}\n' +
'\n' + '\n' +
'me.onStart = function (timestamp) {\n' + 'me.onStart = function (timestamp) {\n' +
' assert(me.getSpeed(), ' + DEFAULT_SPEED + ', "Initial speed");\n' + ' assert(me.getSpeed(), ' + DEFAULT_SPEED + ', "Initial speed");\n' +
' assert(me.getYaw(), 0, "Yaw angle")\n' + ' assert(me.getYaw(), 0, "Yaw angle");\n' +
' me.initialPosition = me.getCurrentPosition();\n' + ' me.initialPosition = me.getCurrentPosition();\n' +
' me.start_time = timestamp;\n' + ' me.start_time = timestamp;\n' +
' me.setTargetCoordinates(\n' + ' me.setTargetCoordinates(\n' +
...@@ -95,8 +85,9 @@ ...@@ -95,8 +85,9 @@
LOGIC_FILE_LIST = [ LOGIC_FILE_LIST = [
'gadget_erp5_page_drone_capture_flag_logic.js', 'gadget_erp5_page_drone_capture_flag_logic.js',
'gadget_erp5_page_drone_capture_map_utils.js', 'gadget_erp5_page_drone_capture_map_utils.js',
'gadget_erp5_page_drone_capture_flag_fixedwingdrone.js', 'gadget_erp5_page_drone_capture_flag_multicopterdrone.js',
'gadget_erp5_page_drone_capture_flag_enemydrone.js' 'gadget_erp5_page_drone_capture_flag_enemydrone.js',
FixedWingDroneAPI.SCRIPT_NAME
]; ];
rJS(window) rJS(window)
...@@ -118,7 +109,7 @@ ...@@ -118,7 +109,7 @@
fragment = domsugar(gadget.element.querySelector('.simulator_div'), fragment = domsugar(gadget.element.querySelector('.simulator_div'),
[domsugar('div')]).firstElementChild; [domsugar('div')]).firstElementChild;
for (i = 0; i < NUMBER_OF_DRONES; i += 1) { for (i = 0; i < NUMBER_OF_DRONES; i += 1) {
DRONE_LIST[i] = {"id": i, "type": "FixedWingDroneAPI", DRONE_LIST[i] = {"id": i, "type": FixedWingDroneAPI.name,
"script_content": DEFAULT_SCRIPT_CONTENT}; "script_content": DEFAULT_SCRIPT_CONTENT};
} }
map_json = { map_json = {
...@@ -144,16 +135,6 @@ ...@@ -144,16 +135,6 @@
game_parameters_json = { game_parameters_json = {
"debug_test_mode": true, "debug_test_mode": true,
"drone": { "drone": {
"maxAcceleration": MAX_ACCELERATION,
"maxDeceleration": MAX_DECELERATION,
"minSpeed": MIN_SPEED,
"speed": DEFAULT_SPEED,
"maxSpeed": MAX_SPEED,
"maxRoll": MAX_ROLL,
"minPitchAngle": MIN_PITCH,
"maxPitchAngle": MAX_PITCH,
"maxSinkRate": MAX_SINK_RATE,
"maxClimbRate": MAX_CLIMB_RATE,
"onUpdateInterval": ON_UPDATE_INTERVAL, "onUpdateInterval": ON_UPDATE_INTERVAL,
"list": DRONE_LIST "list": DRONE_LIST
}, },
...@@ -170,6 +151,10 @@ ...@@ -170,6 +151,10 @@
"log_drone_flight": LOG, "log_drone_flight": LOG,
"log_interval_time": LOG_TIME "log_interval_time": LOG_TIME
}; };
Object.keys(FixedWingDroneAPI.FORM_VIEW).forEach(function (parameter) {
var field = FixedWingDroneAPI.FORM_VIEW[parameter];
game_parameters_json.drone[field.key] = field.default;
});
return gadget.declareGadget("babylonjs.gadget.html", return gadget.declareGadget("babylonjs.gadget.html",
{element: fragment, scope: 'simulator'}) {element: fragment, scope: 'simulator'})
.push(function () { .push(function () {
...@@ -241,4 +226,4 @@ ...@@ -241,4 +226,4 @@
}); });
}); });
}(window, rJS, domsugar, document)); }(window, rJS, domsugar, document, FixedWingDroneAPI));
\ No newline at end of file \ No newline at end of file
...@@ -75,7 +75,7 @@ ...@@ -75,7 +75,7 @@
</item> </item>
<item> <item>
<key> <string>default_reference</string> </key> <key> <string>default_reference</string> </key>
<value> <string>gadget_erp5_page_drone_capture_flag_test_page.js</string> </value> <value> <string>gadget_erp5_page_drone_capture_flag_fixed_wing_test_page.js</string> </value>
</item> </item>
<item> <item>
<key> <string>description</string> </key> <key> <string>description</string> </key>
...@@ -85,7 +85,7 @@ ...@@ -85,7 +85,7 @@
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>test_capture_drone_flight_js</string> </value> <value> <string>test_capture_drone_fixed_wing_flight_js</string> </value>
</item> </item>
<item> <item>
<key> <string>language</string> </key> <key> <string>language</string> </key>
...@@ -105,7 +105,7 @@ ...@@ -105,7 +105,7 @@
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
<value> <string>Drone Capture Flag Test Page JS</string> </value> <value> <string>Drone Capture Flag Fixed Wing Test Page JS</string> </value>
</item> </item>
<item> <item>
<key> <string>version</string> </key> <key> <string>version</string> </key>
...@@ -246,7 +246,7 @@ ...@@ -246,7 +246,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1015.64187.34381.50346</string> </value> <value> <string>1020.30719.39240.47462</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -266,7 +266,7 @@ ...@@ -266,7 +266,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1713428877.4</float> <float>1730823482.02</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
<!DOCTYPE html>
<html>
<!--
data-i18n=Others
data-i18n=Tools
-->
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width" />
<title>Drone Simulator Test Page</title>
<link rel="http://www.renderjs.org/rel/interface" href="interface_page.html">
<!-- renderjs -->
<script src="rsvp.js" type="text/javascript"></script>
<script src="renderjs.js" type="text/javascript"></script>
<!-- custom script -->
<script src="jiodev.js" type="text/javascript"></script>
<script src="gadget_global.js" type="text/javascript"></script>
<script src="domsugar.js" type="text/javascript"></script>
<!-- API scripts -->
<script src="gadget_erp5_page_drone_capture_flag_multicopterdrone.js" type="text/javascript"></script>
<script src="gadget_erp5_page_drone_capture_flag_multicopter_test_page.js" type="text/javascript"></script>
</head>
<body>
<form>
<div data-gadget-url="gadget_erp5_form.html"
data-gadget-scope="form_view"
data-gadget-sandbox="public">
</div>
<input name="action_run" class="dialogconfirm" type="submit" value="Run" style="margin-bottom: 20pt;margin-top: 20pt;">
<a data-i18n="Storages"></a> <!-- for zelenium test common macro -->
<div class="simulator_div"></div>
<div data-gadget-url="gadget_erp5_form.html"
data-gadget-scope="form_view_babylonjs"
data-gadget-sandbox="public">
</div>
<div class="test_log"></div>
</form>
</body>
</html>
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Web Page" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_Access_contents_information_Permission</string> </key>
<value>
<tuple>
<string>Anonymous</string>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Add_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Change_local_roles_Permission</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Modify_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_View_Permission</string> </key>
<value>
<tuple>
<string>Anonymous</string>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>content_md5</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>gadget_erp5_page_drone_capture_flag_multicopter_test_page.html</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>test_capture_drone_multicopter_flight_html</string> </value>
</item>
<item>
<key> <string>language</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Web Page</string> </value>
</item>
<item>
<key> <string>short_title</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Drone Capture Flag Multicopter Test Page</string> </value>
</item>
<item>
<key> <string>version</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>document_publication_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>edit_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
<item>
<key> <string>processing_status_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAU=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>publish_alive</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <unicode>zope</unicode> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="DateTime" module="DateTime.DateTime"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1730804860.17</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>published_alive</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>edit</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <unicode>zope</unicode> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>1020.30427.43889.21077</string> </value>
</item>
<item>
<key> <string>state</string> </key>
<value> <string>current</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="DateTime" module="DateTime.DateTime"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1730823425.6</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="5" aka="AAAAAAAAAAU=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>detect_converted_file</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <unicode>zope</unicode> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_processing_state</string> </key>
<value> <string>converted</string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>0.0.0.0</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="DateTime" module="DateTime.DateTime"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1730804628.76</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
/*jslint indent: 2, maxlen: 100*/
/*global window, rJS, domsugar, document, MulticopterDroneAPI*/
(function (window, rJS, domsugar, document, MulticopterDroneAPI) {
"use strict";
var SIMULATION_SPEED = 100,
LOOP_INTERVAL = 1000 / 60,
ON_UPDATE_INTERVAL = LOOP_INTERVAL,
SIMULATION_TIME = 714 * LOOP_INTERVAL / 1000,
MIN_LAT = 45.6364,
MAX_LAT = 45.65,
MIN_LON = 14.2521,
MAX_LON = 14.2766,
map_height = 700,
start_AMSL = 595,
INIT_LON = 14.2658,
INIT_LAT = 45.6412,
INIT_ALT = 0,
DEFAULT_SPEED = 5,
STEP = 2.3992831666911723e-06 / 16,
TAKEOFF_ALTITUDE = 7,
NUMBER_OF_DRONES = 1,
DEFAULT_SCRIPT_CONTENT =
'function assert(a, b, msg) {\n' +
' if (a === b)\n' +
' console.log(msg + ": OK");\n' +
' else\n' +
' console.log(msg + ": FAIL");\n' +
'}\n' +
'\n' +
'function distance(lat1, lon1, lat2, lon2) {\n' +
' var R = 6371e3, // meters\n' +
' la1 = lat1 * Math.PI / 180, // lat, lon in radians\n' +
' la2 = lat2 * Math.PI / 180,\n' +
' lo1 = lon1 * Math.PI / 180,\n' +
' lo2 = lon2 * Math.PI / 180,\n' +
' haversine_phi = Math.pow(Math.sin((la2 - la1) / 2), 2),\n' +
' sin_lon = Math.sin((lo2 - lo1) / 2),\n' +
' h = haversine_phi + Math.cos(la1) * Math.cos(la2) * sin_lon * sin_lon;\n' +
' return 2 * R * Math.asin(Math.sqrt(h));\n' +
'}\n' +
'\n' +
'function compare(coord1, coord2) {\n' +
' assert(coord1.latitude, coord2.latitude, "Latitude");\n' +
' assert(coord1.longitude, coord2.longitude, "Longitude");\n' +
' assert(coord1.altitude, coord2.altitude, "Altitude");\n' +
'}\n' +
'\n' +
'me.onStart = function (timestamp) {\n' +
' assert(me.getSpeed(), 0, "Initial speed");\n' +
' assert(me.getYaw(), 0, "Yaw angle");\n' +
' me.start_time = timestamp;\n' +
' me.takeOff();\n' +
' me.direction_set = false;\n' +
' me.interval_ckecked = false;\n' +
'};\n' +
'\n' +
'me.onUpdate = function (timestamp) {\n' +
' if (!me.interval_ckecked) {\n' +
' var time_interval = timestamp - me.start_time,\n' +
' expected_interval = ' + LOOP_INTERVAL + ';\n' +
' assert(time_interval.toFixed(4), expected_interval.toFixed(4), "Timestamp");\n' +
' assert(Date.now(), timestamp, "Date");\n' +
' me.interval_ckecked = true;\n' +
' }\n' +
' if (!me.isReadyToFly()) {\n' +
' return;\n' +
' } else {\n' +
' if (me.direction_set === false) {\n' +
' me.initialPosition = me.getCurrentPosition();\n' +
' me.initialPosition.altitude = me.initialPosition.altitude.toFixed(2);\n' +
' assert(me.initialPosition.altitude, (' + TAKEOFF_ALTITUDE + ').toFixed(2),\n' +
' "Altitude");\n' +
' me.direction_set = true;\n' +
' return me.setTargetCoordinates(\n' +
' me.initialPosition.latitude + 0.01,\n' +
' me.initialPosition.longitude,\n' +
' me.getAltitudeAbs(),\n' +
' ' + DEFAULT_SPEED + '\n' +
' );\n' +
' }\n' +
' }\n' +
' var current_position = me.getCurrentPosition(),\n' +
' realDistance = distance(\n' +
' me.initialPosition.latitude,\n' +
' me.initialPosition.longitude,\n' +
' me.getCurrentPosition().latitude,\n' +
' me.getCurrentPosition().longitude\n' +
' ).toFixed(8),\n' +
' expectedDistance = (me.getSpeed() * ' + LOOP_INTERVAL + ' / 1000).toFixed(8);\n' +
' assert(realDistance, expectedDistance, "Distance");\n' +
' current_position.latitude = current_position.latitude.toFixed(7);\n' +
' current_position.altitude = current_position.altitude.toFixed(2);\n' +
' compare(current_position, {\n' +
' latitude: (me.initialPosition.latitude + me.getSpeed() *' + STEP + ').toFixed(7),\n' +
' longitude: me.initialPosition.longitude,\n' +
' altitude: me.initialPosition.altitude\n' +
' });\n' +
'};',
DRAW = true,
LOG = true,
LOG_TIME = 1662.7915426540285,
DRONE_LIST = [],
LOGIC_FILE_LIST = [
'gadget_erp5_page_drone_capture_flag_logic.js',
'gadget_erp5_page_drone_capture_map_utils.js',
'gadget_erp5_page_drone_capture_flag_fixedwingdrone.js',
'gadget_erp5_page_drone_capture_flag_enemydrone.js',
MulticopterDroneAPI.SCRIPT_NAME
];
rJS(window)
/////////////////////////////////////////////////////////////////
// Acquired methods
/////////////////////////////////////////////////////////////////
.declareAcquiredMethod("notifySubmitted", "notifySubmitted")
.declareMethod('render', function render() {
var gadget = this;
return gadget.runGame();
})
.declareJob('runGame', function runGame() {
var gadget = this, i,
fragment = gadget.element.querySelector('.simulator_div'),
game_parameters_json, map_json, operator_init_msg;
DRONE_LIST = [];
fragment = domsugar(gadget.element.querySelector('.simulator_div'),
[domsugar('div')]).firstElementChild;
for (i = 0; i < NUMBER_OF_DRONES; i += 1) {
DRONE_LIST[i] = {"id": i, "type": MulticopterDroneAPI.name,
"script_content": DEFAULT_SCRIPT_CONTENT};
}
map_json = {
"height": map_height,
"start_AMSL": start_AMSL,
"min_lat": MIN_LAT,
"max_lat": MAX_LAT,
"min_lon": MIN_LON,
"max_lon": MAX_LON,
"flag_list": [],
"obstacle_list" : [],
"enemy_list" : [],
"initial_position": {
"longitude": INIT_LON,
"latitude": INIT_LAT,
"altitude": INIT_ALT
}
};
operator_init_msg = {
"flag_positions": []
};
/*jslint evil: false*/
game_parameters_json = {
"debug_test_mode": true,
"drone": {
"onUpdateInterval": ON_UPDATE_INTERVAL,
"list": DRONE_LIST
},
"gameTime": SIMULATION_TIME,
"simulation_speed": SIMULATION_SPEED,
"latency": {
"information": 0,
"communication": 0
},
"map": map_json,
"operator_init_msg": operator_init_msg,
"draw_flight_path": DRAW,
"temp_flight_path": true,
"log_drone_flight": LOG,
"log_interval_time": LOG_TIME
};
Object.keys(MulticopterDroneAPI.FORM_VIEW).forEach(function (parameter) {
var field = MulticopterDroneAPI.FORM_VIEW[parameter];
game_parameters_json.drone[field.key] = field.default;
});
return gadget.declareGadget("babylonjs.gadget.html",
{element: fragment, scope: 'simulator'})
.push(function () {
return gadget.getDeclaredGadget('form_view_babylonjs');
})
.push(function (form_gadget) {
return form_gadget.render({
erp5_document: {
"_embedded": {"_view": {
"my_babylonjs": {
"default": "",
"css_class": "",
"required": 0,
"editable": 1,
"key": "babylonjs",
"hidden": 0,
"type": "GadgetField",
"url": "babylonjs.gadget.html",
"sandbox": "public",
"renderjs_extra": '{"autorun": false, ' +
'"logic_file_list": ' + JSON.stringify(LOGIC_FILE_LIST) + ', ' +
'"game_parameters": ' + JSON.stringify(game_parameters_json) +
'}'
}
}},
"_links": {
"type": {
name: ""
}
}
},
form_definition: {
group_list: [[
"bottom",
[["my_babylonjs"]]
]]
}
});
})
.push(function () {
return gadget.getDeclaredGadget('form_view_babylonjs');
})
.push(function (form_gadget) {
return form_gadget.getContent();
})
.push(function (result) {
var div = domsugar('div', { text: "CONSOLE LOG ENTRIES:" }), lines,
l, test_log_node = document.querySelector('.test_log');
document.querySelector('.container').parentNode.appendChild(div);
function appendToTestLog(test_log_node, message) {
var log_node = document.createElement("div"),
textNode = document.createTextNode(message);
log_node.appendChild(textNode);
test_log_node.appendChild(log_node);
}
lines = result.console_log.split('\n');
for (l = 0; l < lines.length; l += 1) {
if (lines[l] !== 'TIMEOUT!') {
appendToTestLog(test_log_node, lines[l]);
} else {
appendToTestLog(test_log_node, 'Timeout: OK');
return;
}
}
appendToTestLog(test_log_node, 'Timeout: FAILED');
}, function (error) {
return gadget.notifySubmitted({message: "Error: " + error.message,
status: 'error'});
});
});
}(window, rJS, domsugar, document, MulticopterDroneAPI));
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Web Script" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_Access_contents_information_Permission</string> </key>
<value>
<tuple>
<string>Anonymous</string>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Add_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Change_local_roles_Permission</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Modify_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_View_Permission</string> </key>
<value>
<tuple>
<string>Anonymous</string>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>content_md5</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>gadget_erp5_page_drone_capture_flag_multicopter_test_page.js</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>test_capture_drone_multicopter_flight_js</string> </value>
</item>
<item>
<key> <string>language</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Web Script</string> </value>
</item>
<item>
<key> <string>short_title</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Drone Capture Flag Multicopter Test Page JS</string> </value>
</item>
<item>
<key> <string>version</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>document_publication_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>edit_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
<item>
<key> <string>processing_status_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAU=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>publish_alive</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <unicode>zope</unicode> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="DateTime" module="DateTime.DateTime"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1730805477.59</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>published_alive</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>edit</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <unicode>zope</unicode> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>1020.30724.64753.62276</string> </value>
</item>
<item>
<key> <string>state</string> </key>
<value> <string>current</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="DateTime" module="DateTime.DateTime"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1730823460.82</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="5" aka="AAAAAAAAAAU=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>detect_converted_file</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <unicode>zope</unicode> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_processing_state</string> </key>
<value> <string>converted</string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>0.0.0.0</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="DateTime" module="DateTime.DateTime"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1730804884.44</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
var DroneLogAPI = /** @class */ (function () { var DroneLogAPI = /** @class */ (function () {
"use strict"; "use strict";
var TOP_SPEED = 250; //so fast that it virtually "teleports" to target var TOP_SPEED = 250; //so fast that it virtually "teleports" to target
DroneLogAPI.SCRIPT_NAME =
"gadget_erp5_page_drone_simulator_dronelogfollower.js";
//** CONSTRUCTOR //** CONSTRUCTOR
function DroneLogAPI(gameManager, drone_info, flight_parameters, id) { function DroneLogAPI(gameManager, drone_info, flight_parameters, id) {
this._gameManager = gameManager; this._gameManager = gameManager;
......
...@@ -246,7 +246,7 @@ ...@@ -246,7 +246,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1015.64101.28159.26163</string> </value> <value> <string>1017.23884.35535.62190</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -266,7 +266,7 @@ ...@@ -266,7 +266,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1713425784.77</float> <float>1730898672.15</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -6,19 +6,147 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -6,19 +6,147 @@ var FixedWingDroneAPI = /** @class */ (function () {
"use strict"; "use strict";
// var TAKEOFF_RADIUS = 60, // var TAKEOFF_RADIUS = 60,
var DEFAULT_SPEED = 16, var EARTH_GRAVITY = 9.81,
PARACHUTE_SPEED = 8,
EARTH_GRAVITY = 9.81,
LOITER_LIMIT = 30, LOITER_LIMIT = 30,
MAX_ACCELERATION = 6, PARACHUTE_SPEED = 8;
MAX_DECELERATION = 1,
MIN_SPEED = 12, FixedWingDroneAPI.DRONE_TYPE = "Fixed Wings";
MAX_SPEED = 26, FixedWingDroneAPI.SCRIPT_NAME =
MAX_ROLL = 35, "gadget_erp5_page_drone_simulator_fixedwingdrone.js";
MIN_PITCH = -20, FixedWingDroneAPI.FORM_VIEW = {
MAX_PITCH = 25, "my_drone_min_speed": {
MAX_CLIMB_RATE = 8, "description": "",
MAX_SINK_RATE = 3; "title": "Drone min speed",
"default": 12,
"css_class": "",
"required": 1,
"editable": 1,
"key": "minSpeed",
"hidden": 0,
"type": "IntegerField"
},
"my_drone_speed": {
"description": "",
"title": "Drone speed",
"default": 16,
"css_class": "",
"required": 1,
"editable": 1,
"key": "speed",
"hidden": 0,
"type": "FloatField"
},
"my_drone_max_speed": {
"description": "",
"title": "Drone max speed",
"default": 26,
"css_class": "",
"required": 1,
"editable": 1,
"key": "maxSpeed",
"hidden": 0,
"type": "IntegerField"
},
"my_drone_max_acceleration": {
"description": "",
"title": "Drone max Acceleration",
"default": 6,
"css_class": "",
"required": 1,
"editable": 1,
"key": "maxAcceleration",
"hidden": 0,
"type": "FloatField"
},
"my_drone_max_deceleration": {
"description": "",
"title": "Drone max Deceleration",
"default": 1,
"css_class": "",
"required": 1,
"editable": 1,
"key": "maxDeceleration",
"hidden": 0,
"type": "IntegerField"
},
"my_drone_max_roll": {
"description": "",
"title": "Drone max roll",
"default": 35,
"css_class": "",
"required": 1,
"editable": 1,
"key": "maxRoll",
"hidden": 0,
"type": "FloatField"
},
"my_drone_min_pitch": {
"description": "",
"title": "Drone min pitch",
"default": -20,
"css_class": "",
"required": 1,
"editable": 1,
"key": "minPitchAngle",
"hidden": 0,
"type": "FloatField"
},
"my_drone_max_pitch": {
"description": "",
"title": "Drone max pitch",
"default": 25,
"css_class": "",
"required": 1,
"editable": 1,
"key": "maxPitchAngle",
"hidden": 0,
"type": "FloatField"
},
"my_drone_max_sink_rate": {
"description": "",
"title": "Drone max sink rate",
"default": 3,
"css_class": "",
"required": 1,
"editable": 1,
"key": "maxSinkRate",
"hidden": 0,
"type": "FloatField"
},
"my_drone_max_climb_rate": {
"description": "",
"title": "Drone max climb rate",
"default": 8,
"css_class": "",
"required": 1,
"editable": 1,
"key": "maxClimbRate",
"hidden": 0,
"type": "FloatField"
},
"my_drone_speed_factor": {
"description": "",
"title": "Drone speed factor",
"default": 1,
"css_class": "",
"required": 1,
"editable": 1,
"key": "speedFactor",
"hidden": 0,
"type": "FloatField"
},
"my_drone_max_command_frequency": {
"description": "",
"title": "Drone max command frequency",
"default": 5,
"css_class": "",
"required": 1,
"editable": 1,
"key": "maxCommandFrequency",
"hidden": 0,
"type": "FloatField"
}
};
//** CONSTRUCTOR //** CONSTRUCTOR
function FixedWingDroneAPI(gameManager, drone_info, flight_parameters, id) { function FixedWingDroneAPI(gameManager, drone_info, flight_parameters, id) {
...@@ -102,9 +230,46 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -102,9 +230,46 @@ var FixedWingDroneAPI = /** @class */ (function () {
/* /*
** Function called on every drone update, right before onUpdate AI script ** Function called on every drone update, right before onUpdate AI script
*/ */
FixedWingDroneAPI.prototype.internal_position_update = function (context, delta_time) { FixedWingDroneAPI.prototype.internal_position_update =
function (context, delta_time) {
var currentGeoCoordinates = this._mapManager.convertToGeoCoordinates(
context.position.x,
context.position.y,
context.position.z
),
targetCoordinates = this._mapManager.convertToGeoCoordinates(
context._targetCoordinates.x,
context._targetCoordinates.y,
context._targetCoordinates.z
),
bearing = this._computeBearing(
currentGeoCoordinates.latitude,
currentGeoCoordinates.longitude,
targetCoordinates.latitude,
targetCoordinates.longitude
),
distanceToTarget,
newYaw;
if (this._loiter_mode) {
distanceToTarget = Math.sqrt(
Math.pow(context._targetCoordinates.x - context.position.x, 2)
+ Math.pow(context._targetCoordinates.y - context.position.y, 2)
);
if (Math.abs(distanceToTarget - this._loiter_radius) <= 1) {
newYaw = bearing - 90;
} else if (distanceToTarget < this._loiter_radius) {
newYaw = bearing - 135;
} else {
newYaw = this._getNewYaw(context, bearing, delta_time);
}
} else {
newYaw = this._getNewYaw(context, bearing, delta_time);
}
this._updateSpeed(context, delta_time); this._updateSpeed(context, delta_time);
this._updatePosition(context, delta_time); this._updatePosition(context, newYaw, delta_time);
context._controlMesh.computeWorldMatrix(true); context._controlMesh.computeWorldMatrix(true);
context._mesh.computeWorldMatrix(true); context._mesh.computeWorldMatrix(true);
...@@ -140,115 +305,42 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -140,115 +305,42 @@ var FixedWingDroneAPI = /** @class */ (function () {
}; };
FixedWingDroneAPI.prototype._updateSpeed = function (drone, delta_time) { FixedWingDroneAPI.prototype._updateSpeed = function (drone, delta_time) {
var speed = drone.get3DSpeed(), speedDiff, speedUpdate; var speed = drone.get3DSpeed(), speedDiff,
speedUpdate = drone._acceleration * delta_time / 1000;
if (speed > this._targetSpeed) {
speedUpdate *= -1;
}
if (speed !== this._targetSpeed) { if (speed !== this._targetSpeed) {
speedDiff = this._targetSpeed - speed; speedDiff = this._targetSpeed - speed;
speedUpdate = drone._acceleration * delta_time / 1000;
if (Math.abs(speedDiff) < Math.abs(speedUpdate)) { if (Math.abs(speedDiff) < Math.abs(speedUpdate)) {
drone._speed = this._targetSpeed; drone._speed = this._targetSpeed;
drone._acceleration = 0;
} else { } else {
drone._speed += speedUpdate; drone._speed += speedUpdate;
} }
} }
}; };
FixedWingDroneAPI.prototype._updatePosition = function (drone, delta_time) { FixedWingDroneAPI.prototype._updatePosition =
var R = 6371e3, function (drone, yaw, delta_time) {
currentGeoCoordinates = this._mapManager.convertToGeoCoordinates( var speed = drone.get3DSpeed(),
drone.position.x, positionUpdate = speed * delta_time / 1000,
drone.position.y, yawToDirection = this._toRad(-yaw + 90),
drone.position.z zNorm = this._getVerticalSpeed(drone) / speed,
), xyCoef = Math.sqrt(1 - Math.abs(zNorm));
targetCoordinates = this._mapManager.convertToGeoCoordinates(
drone._targetCoordinates.x,
drone._targetCoordinates.y,
drone._targetCoordinates.z
),
bearing = this._computeBearing(
currentGeoCoordinates.latitude,
currentGeoCoordinates.longitude,
targetCoordinates.latitude,
targetCoordinates.longitude
),
currentCosLat,
currentLatRad,
distance,
distanceCos,
distanceSin,
distanceToTarget,
currentSinLat,
currentLonRad,
groundSpeed,
newCoordinates,
newLatRad,
newLonRad,
newYaw,
newYawRad,
verticalSpeed,
yawToDirection;
if (this._loiter_mode) {
distanceToTarget = Math.sqrt(
Math.pow(drone._targetCoordinates.x - drone.position.x, 2)
+ Math.pow(drone._targetCoordinates.y - drone.position.y, 2)
);
if (Math.abs(distanceToTarget - this._loiter_radius) <= 1) { drone.setDirection(
newYaw = bearing - 90; xyCoef * Math.cos(yawToDirection),
} else if (distanceToTarget < this._loiter_radius) { xyCoef * Math.sin(yawToDirection),
newYaw = bearing - 135; zNorm
} else {
newYaw = this._getNewYaw(drone, bearing, delta_time);
}
} else {
newYaw = this._getNewYaw(drone, bearing, delta_time);
}
newYawRad = this._toRad(newYaw);
currentLatRad = this._toRad(currentGeoCoordinates.latitude);
currentCosLat = Math.cos(currentLatRad);
currentSinLat = Math.sin(currentLatRad);
currentLonRad = this._toRad(currentGeoCoordinates.longitude);
verticalSpeed = this._getVerticalSpeed(drone);
groundSpeed = Math.sqrt(
Math.pow(drone.get3DSpeed(), 2) - Math.pow(verticalSpeed, 2)
);
distance = (groundSpeed * delta_time / 1000) / R;
distanceCos = Math.cos(distance);
distanceSin = Math.sin(distance);
newLatRad = Math.asin(
currentSinLat * distanceCos
+ currentCosLat * distanceSin * Math.cos(newYawRad)
);
newLonRad = currentLonRad + Math.atan2(
Math.sin(newYawRad) * distanceSin * currentCosLat,
distanceCos - currentSinLat * Math.sin(newLatRad)
);
newCoordinates = this._mapManager.convertToLocalCoordinates(
this._toDeg(newLatRad),
this._toDeg(newLonRad),
drone.position.z
); );
// swap y and z axis so z axis represents altitude
drone._controlMesh.position.addInPlace(new BABYLON.Vector3( drone._controlMesh.position.addInPlace(new BABYLON.Vector3(
Math.abs(newCoordinates.x - drone.position.x) drone._direction.x * positionUpdate,
* (newCoordinates.x < drone.position.x ? -1 : 1), drone._direction.y * positionUpdate,
verticalSpeed * delta_time / 1000, drone._direction.z * positionUpdate
Math.abs(newCoordinates.y - drone.position.y)
* (newCoordinates.y < drone.position.y ? -1 : 1)
)); ));
yawToDirection = this._toRad(-newYaw + 90);
drone.setDirection(
groundSpeed * Math.cos(yawToDirection),
groundSpeed * Math.sin(yawToDirection),
verticalSpeed
);
}; };
FixedWingDroneAPI.prototype._getNewYaw = FixedWingDroneAPI.prototype._getNewYaw =
...@@ -289,14 +381,20 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -289,14 +381,20 @@ var FixedWingDroneAPI = /** @class */ (function () {
return verticalSpeed; return verticalSpeed;
}; };
FixedWingDroneAPI.prototype._setSpeedInternal = function (speed) {
this._targetSpeed = speed;
};
FixedWingDroneAPI.prototype.setSpeed = function (drone, speed) { FixedWingDroneAPI.prototype.setSpeed = function (drone, speed) {
this._targetSpeed = Math.max( if (speed < this.getMinSpeed()) {
Math.min(speed, this.getMaxSpeed()), throw new Error('Requested speed must be greater than '
this.getMinSpeed() + this.getMinSpeed());
); }
this._requestedSpeed = Math.min(speed, this.getMaxSpeed());
this._setSpeedInternal(this._requestedSpeed * this.getSpeedFactor());
drone._acceleration = (this._targetSpeed > drone.get3DSpeed()) drone._acceleration = (this._targetSpeed > drone.get3DSpeed())
? this.getMaxAcceleration() : -this.getMaxDeceleration(); ? this.getMaxAcceleration() : this.getMaxDeceleration();
}; };
FixedWingDroneAPI.prototype.setStartingPosition = function (drone, x, y, z) { FixedWingDroneAPI.prototype.setStartingPosition = function (drone, x, y, z) {
...@@ -412,6 +510,9 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -412,6 +510,9 @@ var FixedWingDroneAPI = /** @class */ (function () {
FixedWingDroneAPI.prototype.getMaxClimbRate = function () { FixedWingDroneAPI.prototype.getMaxClimbRate = function () {
return this._flight_parameters.drone.maxClimbRate; return this._flight_parameters.drone.maxClimbRate;
}; };
FixedWingDroneAPI.prototype.getSpeedFactor = function () {
return this._flight_parameters.drone.speedFactor;
};
FixedWingDroneAPI.prototype.getMaxCommandFrequency = function () { FixedWingDroneAPI.prototype.getMaxCommandFrequency = function () {
return this._flight_parameters.drone.maxCommandFrequency; return this._flight_parameters.drone.maxCommandFrequency;
}; };
...@@ -464,7 +565,7 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -464,7 +565,7 @@ var FixedWingDroneAPI = /** @class */ (function () {
+ Math.pow(direction.z * drone.get3DSpeed(), 2) + Math.pow(direction.z * drone.get3DSpeed(), 2)
); );
}; };
FixedWingDroneAPI.prototype.takeOff = function () { FixedWingDroneAPI.prototype.takeOff = function (drone) {
return console.log("Fixed-wing drones can only be taken off manually."); return console.log("Fixed-wing drones can only be taken off manually.");
}; };
FixedWingDroneAPI.prototype.land = function (drone) { FixedWingDroneAPI.prototype.land = function (drone) {
......
...@@ -85,7 +85,7 @@ ...@@ -85,7 +85,7 @@
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>drone_simulator_fixedwingdrone_js</string> </value> <value> <string>drone_simulator_fixed_wing_drone_js</string> </value>
</item> </item>
<item> <item>
<key> <string>language</string> </key> <key> <string>language</string> </key>
...@@ -240,7 +240,7 @@ ...@@ -240,7 +240,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1015.64203.48820.61559</string> </value> <value> <string>1020.30338.10759.37171</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -260,7 +260,7 @@ ...@@ -260,7 +260,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1713429850.09</float> <float>1730799505.92</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -376,7 +376,7 @@ var DroneManager = /** @class */ (function () { ...@@ -376,7 +376,7 @@ var DroneManager = /** @class */ (function () {
return this._API.getClimbRate(this); return this._API.getClimbRate(this);
}; };
DroneManager.prototype.takeOff = function () { DroneManager.prototype.takeOff = function () {
return this._API.takeOff(); return this._API.takeOff(this);
}; };
DroneManager.prototype.land = function () { DroneManager.prototype.land = function () {
if (!this.isLanding()) { if (!this.isLanding()) {
...@@ -649,7 +649,7 @@ var GameManager = /** @class */ (function () { ...@@ -649,7 +649,7 @@ var GameManager = /** @class */ (function () {
header_list = ["timestamp (ms)", "latitude (°)", "longitude (°)", header_list = ["timestamp (ms)", "latitude (°)", "longitude (°)",
"AMSL (m)", "rel altitude (m)", "yaw (°)", "AMSL (m)", "rel altitude (m)", "yaw (°)",
"ground speed (m/s)", "climb rate (m/s)"]; "ground speed (m/s)", "climb rate (m/s)"];
for (drone = 0; drone < GAMEPARAMETERS.droneList.length; drone += 1) { for (drone = 0; drone < GAMEPARAMETERS.drone.list.length; drone += 1) {
this._flight_log[drone] = []; this._flight_log[drone] = [];
this._flight_log[drone].push(header_list); this._flight_log[drone].push(header_list);
this._log_count[drone] = 0; this._log_count[drone] = 0;
...@@ -671,6 +671,7 @@ var GameManager = /** @class */ (function () { ...@@ -671,6 +671,7 @@ var GameManager = /** @class */ (function () {
} }
this.APIs_dict = { this.APIs_dict = {
FixedWingDroneAPI: FixedWingDroneAPI, FixedWingDroneAPI: FixedWingDroneAPI,
MulticopterDroneAPI: MulticopterDroneAPI,
DroneLogAPI: DroneLogAPI DroneLogAPI: DroneLogAPI
}; };
if (this._game_parameters_json.debug_test_mode) { if (this._game_parameters_json.debug_test_mode) {
...@@ -844,11 +845,14 @@ var GameManager = /** @class */ (function () { ...@@ -844,11 +845,14 @@ var GameManager = /** @class */ (function () {
drone_position.z drone_position.z
); );
game_manager._flight_log[index].push([ game_manager._flight_log[index].push([
current_time, geo_coordinates.latitude, current_time.toFixed(0),
geo_coordinates.longitude, geo_coordinates.latitude.toFixed(4),
map_info.start_AMSL + drone_position.z, geo_coordinates.longitude.toFixed(4),
drone_position.z, drone.getYaw(), drone.getSpeed(), (map_info.start_AMSL + drone_position.z).toFixed(4),
drone.getClimbRate() drone_position.z.toFixed(4),
drone.getYaw().toFixed(0),
drone.getSpeed().toFixed(2),
drone.getClimbRate().toFixed(6)
]); ]);
} }
} }
...@@ -987,7 +991,7 @@ var GameManager = /** @class */ (function () { ...@@ -987,7 +991,7 @@ var GameManager = /** @class */ (function () {
_this._mapManager = new MapManager(ctx._scene, GAMEPARAMETERS.map, _this._mapManager = new MapManager(ctx._scene, GAMEPARAMETERS.map,
GAMEPARAMETERS.initialPosition); GAMEPARAMETERS.initialPosition);
ctx._spawnDrones(_this._mapManager.getMapInfo().initial_position, ctx._spawnDrones(_this._mapManager.getMapInfo().initial_position,
GAMEPARAMETERS.droneList, ctx); GAMEPARAMETERS.drone.list, ctx);
// Hide the drone prefab // Hide the drone prefab
DroneManager.Prefab.isVisible = false; DroneManager.Prefab.isVisible = false;
//Hack to make advanced texture work //Hack to make advanced texture work
...@@ -1000,7 +1004,7 @@ var GameManager = /** @class */ (function () { ...@@ -1000,7 +1004,7 @@ var GameManager = /** @class */ (function () {
ctx._scene ctx._scene
); );
document = documentTmp; document = documentTmp;
for (count = 0; count < GAMEPARAMETERS.droneList.length; count += 1) { for (count = 0; count < GAMEPARAMETERS.drone.list.length; count += 1) {
controlMesh = ctx._droneList[count].infosMesh; controlMesh = ctx._droneList[count].infosMesh;
rect = new BABYLON.GUI.Rectangle(); rect = new BABYLON.GUI.Rectangle();
rect.width = "10px"; rect.width = "10px";
......
...@@ -240,7 +240,7 @@ ...@@ -240,7 +240,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1017.22776.49981.4147</string> </value> <value> <string>1020.23547.6727.25736</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -260,7 +260,7 @@ ...@@ -260,7 +260,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1718722284.77</float> <float>1730712553.54</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
/*global BABYLON, console*/
/*jslint nomen: true, indent: 2, maxlen: 80, todo: true */
/************************** MULTICOPTER DRONE API ****************************/
var MulticopterDroneAPI = /** @class */ (function () {
"use strict";
var DEFAULT_SPEED = 5,
DEFAULT_TAKEOFF_ALTITUDE = 7;
MulticopterDroneAPI.DRONE_TYPE = "Multicopter";
MulticopterDroneAPI.SCRIPT_NAME =
"gadget_erp5_page_drone_simulator_multicopterdrone.js";
MulticopterDroneAPI.FORM_VIEW = {
"my_drone_max_speed": {
"description": "",
"title": "Drone max speed",
"default": 16,
"css_class": "",
"required": 1,
"editable": 1,
"key": "maxSpeed",
"hidden": 0,
"type": "IntegerField"
},
"my_drone_max_acceleration": {
"description": "",
"title": "Drone max Acceleration",
"default": 1,
"css_class": "",
"required": 1,
"editable": 1,
"key": "maxAcceleration",
"hidden": 0,
"type": "FloatField"
},
"my_drone_max_deceleration": {
"description": "",
"title": "Drone max Deceleration",
"default": 3,
"css_class": "",
"required": 1,
"editable": 1,
"key": "maxDeceleration",
"hidden": 0,
"type": "IntegerField"
},
"my_drone_max_roll": {
"description": "",
"title": "Drone max roll",
"default": 13,
"css_class": "",
"required": 1,
"editable": 1,
"key": "maxRoll",
"hidden": 0,
"type": "FloatField"
},
"my_drone_speed_factor": {
"description": "",
"title": "Drone speed factor",
"default": 1.2,
"css_class": "",
"required": 1,
"editable": 1,
"key": "speedFactor",
"hidden": 0,
"type": "FloatField"
},
"my_drone_min_approach_speed": {
"description": "",
"title": "Drone min approach speed",
"default": 0.1,
"css_class": "",
"required": 1,
"editable": 1,
"key": "minApproachSpeed",
"hidden": 0,
"type": "FloatField"
},
"my_drone_take_off_factor": {
"description": "",
"title": "Drone take off factor",
"default": 20,
"css_class": "",
"required": 1,
"editable": 1,
"key": "takeOffFactor",
"hidden": 0,
"type": "FloatField"
},
"my_drone_yaw_acceptance": {
"description": "",
"title": "Drone yaw acceptance",
"default": 1,
"css_class": "",
"required": 1,
"editable": 1,
"key": "yawAcceptance",
"hidden": 0,
"type": "FloatField"
},
"my_drone_max_command_frequency": {
"description": "",
"title": "Drone max command frequency",
"default": 2,
"css_class": "",
"required": 1,
"editable": 1,
"key": "maxCommandFrequency",
"hidden": 0,
"type": "FloatField"
}
};
//** CONSTRUCTOR
function MulticopterDroneAPI(gameManager, drone_info, flight_parameters, id) {
this._gameManager = gameManager;
this._mapManager = this._gameManager._mapManager;
this._map_dict = this._mapManager.getMapInfo();
this._flight_parameters = flight_parameters;
this._id = id;
this._drone_info = drone_info;
//this._start_altitude = 0;
this._is_landing = false;
this._is_ready_to_fly = false;
this._drone_dict_list = [];
}
Object.defineProperty(MulticopterDroneAPI.prototype, "isCollidable", {
get: function () { return true; },
enumerable: true,
configurable: true
});
/*
** Function called on start phase of the drone, just before onStart AI script
*/
MulticopterDroneAPI.prototype.internal_start = function (drone) {
if (this.getMaxDeceleration() <= 0) {
throw new Error('max deceleration must be superior to 0');
}
if (this.getMaxAcceleration() <= 0) {
throw new Error('max acceleration must be superior to 0');
}
if (this.getMaxSpeed() <= 0) {
throw new Error('Max speed must be superior to 0');
}
drone._speed = drone._targetSpeed = 0;
if (this.getMaxRollAngle() <= 0) {
throw new Error('max roll angle must be superior to 0');
}
if (this.getMaxCommandFrequency() <= 0) {
throw new Error('max command frequence must be superior to 0');
}
return;
};
/*
** Function called on every drone update, right before onUpdate AI script
*/
MulticopterDroneAPI.prototype.internal_position_update =
function (context, delta_time) {
var currentGeoCoordinates = this._mapManager.convertToGeoCoordinates(
context.position.x,
context.position.y,
context.position.z
),
targetCoordinates = this._mapManager.convertToGeoCoordinates(
context._targetCoordinates.x,
context._targetCoordinates.y,
context._targetCoordinates.z
),
bearing = this._computeBearing(
currentGeoCoordinates.latitude,
currentGeoCoordinates.longitude,
targetCoordinates.latitude,
targetCoordinates.longitude
),
newYaw = this._getNewYaw(context, bearing, delta_time);
if (!this.isReadyToFly() && !this.isLanding()
&& context.position.z >= DEFAULT_TAKEOFF_ALTITUDE) {
this._is_ready_to_fly = true;
context._speed = 0;
}
if (Math.abs(bearing - newYaw) < this.getYawAcceptance()) {
this._updateSpeed(context, currentGeoCoordinates, targetCoordinates,
delta_time);
}
this._updatePosition(context, newYaw, delta_time);
context._controlMesh.computeWorldMatrix(true);
context._mesh.computeWorldMatrix(true);
};
/*
** Function called on every drone update, right after onUpdate AI script
*/
MulticopterDroneAPI.prototype.internal_info_update = function (drone) {
var _this = this, drone_position = drone.getCurrentPosition(), drone_info;
/*if (_this._start_altitude > 0) { //TODO move start_altitude here
_this.reachAltitude(drone);
}*/
if (drone_position) {
drone_info = {
'altitudeRel' : drone_position.altitude,
'altitudeAbs' : _this._mapManager.getMapInfo().start_AMSL +
drone_position.altitude,
'latitude' : drone_position.latitude,
'longitude' : drone_position.longitude,
'yaw': drone.getYaw(),
'speed': drone.getSpeed(),
'climbRate': drone.getClimbRate(),
'timestamp': drone_position.timestamp
};
_this._drone_dict_list[_this._id] = drone_info;
//broadcast drone info using internal msg
_this._gameManager._droneList.forEach(function (drone) {
if (drone.id !== _this._id) {
drone.internal_getMsg(drone_info, _this._id);
}
});
}
};
MulticopterDroneAPI.prototype._updateSpeed =
function (drone, currentGeoCoordinates, targetCoordinates, delta_time) {
var speed = drone.get3DSpeed(), speedDiff, speedUpdate,
distance = Math.sqrt(
Math.pow(
this._mapManager.mapUtils.latLonDistance(
[currentGeoCoordinates.latitude, currentGeoCoordinates.longitude],
[targetCoordinates.latitude, targetCoordinates.longitude]
),
2
) + Math.pow(
targetCoordinates.altitude - currentGeoCoordinates.altitude,
2
)
);
if (this._targetSpeed > distance) {
drone._acceleration = this.getMaxDeceleration();
this._targetSpeed = Math.max(distance, this.getMinApproachSpeed());
}
speedUpdate = drone._acceleration * delta_time / 1000;
if (speed > this._targetSpeed) {
speedUpdate *= -1;
}
if (speed !== this._targetSpeed) {
speedDiff = this._targetSpeed - speed;
if (Math.abs(speedDiff) < Math.abs(speedUpdate)) {
drone._speed = this._targetSpeed;
} else {
drone._speed += speedUpdate;
}
}
};
MulticopterDroneAPI.prototype._updatePosition =
function (drone, yaw, delta_time) {
var positionUpdate = drone.get3DSpeed() * delta_time / 1000,
yawToDirection = this._toRad(-yaw + 90),
xDiff = drone._targetCoordinates.x - drone.position.x,
yDiff = drone._targetCoordinates.y - drone.position.y,
zDiff = drone._targetCoordinates.z - drone.position.z,
distanceToTarget = Math.sqrt(
Math.pow(xDiff, 2) + Math.pow(yDiff, 2) + Math.pow(zDiff, 2)
),
zNorm = zDiff / distanceToTarget,
xyCoef = Math.sqrt(1 - Math.abs(zNorm));
drone.setDirection(
xyCoef * Math.cos(yawToDirection),
xyCoef * Math.sin(yawToDirection),
zNorm
);
drone._controlMesh.position.addInPlace(new BABYLON.Vector3(
drone._direction.x * positionUpdate,
drone._direction.y * positionUpdate,
drone._direction.z * positionUpdate
));
};
MulticopterDroneAPI.prototype._getNewYaw =
function (drone, bearing, delta_time) {
// swap y and z axis so z axis represents altitude
var yaw = drone.getYaw(),
yawDiff = this._computeYawDiff(yaw, bearing),
yawUpdate = this.getYawVelocity(drone) * delta_time / 1000;
if (yawUpdate >= Math.abs(yawDiff)) {
yawUpdate = yawDiff;
} else if (yawDiff < 0) {
yawUpdate *= -1;
}
return yaw + yawUpdate;
};
MulticopterDroneAPI.prototype._setSpeedInternal = function (speed) {
this._targetSpeed = speed;
};
MulticopterDroneAPI.prototype.setSpeed = function (drone, speed) {
if (speed < 0) {
throw new Error('Requested speed must positive');
}
this._requestedSpeed = Math.min(speed, this.getMaxSpeed());
this._setSpeedInternal(this._requestedSpeed * this.getSpeedFactor());
drone._acceleration = (this._targetSpeed > drone.get3DSpeed())
? this.getMaxAcceleration() : this.getMaxDeceleration();
};
MulticopterDroneAPI.prototype.setStartingPosition =
function (drone, x, y, z) {
if (!drone._canPlay) {
if (z <= 0.05) {
z = 0.05;
}
drone._controlMesh.position = new BABYLON.Vector3(x, z, y);
}
drone._controlMesh.computeWorldMatrix(true);
drone._mesh.computeWorldMatrix(true);
};
MulticopterDroneAPI.prototype.internal_getMsg = function (msg, id) {
this._drone_dict_list[id] = msg;
};
MulticopterDroneAPI.prototype.internal_setTargetCoordinates =
function (drone, coordinates, speed, radius) {
this.setSpeed(drone, speed);
};
MulticopterDroneAPI.prototype.sendMsg = function (msg, to) {
var _this = this,
droneList = _this._gameManager._droneList;
_this._gameManager.delay(function () {
if (to < 0) {
// Send to all drones
droneList.forEach(function (drone) {
if (drone.infosMesh) {
try {
drone.onGetMsg(msg);
} catch (error) {
console.warn('Drone crashed on sendMsg due to error:', error);
drone._internal_crash();
}
}
});
} else {
// Send to specific drone
if (droneList[to].infosMesh) {
try {
droneList[to].onGetMsg(msg);
} catch (error) {
console.warn('Drone crashed on sendMsg due to error:', error);
droneList[to]._internal_crash();
}
}
}
}, _this._flight_parameters.latency.communication);
};
MulticopterDroneAPI.prototype.log = function (msg) {
console.log("API say : " + msg);
};
MulticopterDroneAPI.prototype.getGameParameter = function (name) {
if (["gameTime", "map"].includes(name)) {
return this._gameManager.gameParameter[name];
}
};
/*
** Converts geo latitude-longitud coordinates (º) to x,y plane coordinates (m)
*/
MulticopterDroneAPI.prototype.processCoordinates = function (lat, lon, z) {
if (isNaN(lat) || isNaN(lon) || isNaN(z)) {
throw new Error('Target coordinates must be numbers');
}
var processed_coordinates =
this._mapManager.convertToLocalCoordinates(lat, lon, z);
return processed_coordinates;
};
MulticopterDroneAPI.prototype.getCurrentPosition = function (x, y, z) {
return this._mapManager.convertToGeoCoordinates(x, y, z);
};
MulticopterDroneAPI.prototype.getDroneAI = function () {
return null;
};
MulticopterDroneAPI.prototype.getMaxSpeed = function () {
return this._flight_parameters.drone.maxSpeed;
};
MulticopterDroneAPI.prototype.getMaxDeceleration = function () {
return this._flight_parameters.drone.maxDeceleration;
};
MulticopterDroneAPI.prototype.getMaxAcceleration = function () {
return this._flight_parameters.drone.maxAcceleration;
};
MulticopterDroneAPI.prototype.getMaxRollAngle = function () {
return this._flight_parameters.drone.maxRoll;
};
MulticopterDroneAPI.prototype.getMaxSinkRate = function () {
return this._flight_parameters.drone.maxSpeed;
};
MulticopterDroneAPI.prototype.getMaxClimbRate = function () {
return this._flight_parameters.drone.maxSpeed;
};
MulticopterDroneAPI.prototype.getSpeedFactor = function () {
return this._flight_parameters.drone.speedFactor;
};
MulticopterDroneAPI.prototype.getMinApproachSpeed = function () {
return this._flight_parameters.drone.minApproachSpeed;
};
MulticopterDroneAPI.prototype.getTakeOffFactor = function () {
return this._flight_parameters.drone.takeOffFactor;
};
MulticopterDroneAPI.prototype.getYawAcceptance = function () {
return this._flight_parameters.drone.yawAcceptance;
};
MulticopterDroneAPI.prototype.getMaxCommandFrequency = function () {
return this._flight_parameters.drone.maxCommandFrequency;
};
MulticopterDroneAPI.prototype.getYawVelocity = function (drone) {
return this.getMaxRollAngle();
};
MulticopterDroneAPI.prototype.getYaw = function (drone) {
var direction = drone.worldDirection;
return this._toDeg(Math.atan2(direction.x, direction.z));
};
MulticopterDroneAPI.prototype._computeBearing =
function (lat1, lon1, lat2, lon2) {
var dLon = this._toRad(lon2 - lon1),
lat1Rad = this._toRad(lat1),
lat2Rad = this._toRad(lat2),
x = Math.cos(lat2Rad) * Math.sin(dLon),
y = Math.cos(lat1Rad) * Math.sin(lat2Rad)
- Math.sin(lat1Rad) * Math.cos(lat2Rad) * Math.cos(dLon);
return this._toDeg(Math.atan2(x, y));
};
MulticopterDroneAPI.prototype._computeYawDiff = function (yaw1, yaw2) {
var diff = yaw2 - yaw1;
diff += (diff > 180) ? -360 : (diff < -180) ? 360 : 0;
return diff;
};
MulticopterDroneAPI.prototype._toRad = function (angle) {
return angle * Math.PI / 180;
};
MulticopterDroneAPI.prototype._toDeg = function (angle) {
return angle * 180 / Math.PI;
};
MulticopterDroneAPI.prototype.getClimbRate = function (drone) {
return drone.worldDirection.y * drone.get3DSpeed();
};
MulticopterDroneAPI.prototype.getSpeed = function (drone) {
var direction = drone.worldDirection;
return Math.sqrt(
Math.pow(direction.x * drone.get3DSpeed(), 2)
+ Math.pow(direction.z * drone.get3DSpeed(), 2)
);
};
MulticopterDroneAPI.prototype.takeOff = function (drone) {
var drone_pos = drone.getCurrentPosition();
drone._internal_setTargetCoordinates(
drone_pos.latitude,
drone_pos.longitude,
DEFAULT_TAKEOFF_ALTITUDE,
DEFAULT_SPEED
);
drone._acceleration = this.getMaxAcceleration() / this.getTakeOffFactor();
};
MulticopterDroneAPI.prototype.land = function (drone) {
var drone_pos = drone.getCurrentPosition();
drone._internal_setTargetCoordinates(
drone_pos.latitude,
drone_pos.longitude,
0,
DEFAULT_SPEED
);
this._is_ready_to_fly = false;
this._is_landing = true;
};
MulticopterDroneAPI.prototype.isReadyToFly = function () {
return this._is_ready_to_fly;
};
MulticopterDroneAPI.prototype.isLanding = function () {
return this._is_landing;
};
MulticopterDroneAPI.prototype.getInitialAltitude = function () {
return this._map_dict.start_AMSL;
};
MulticopterDroneAPI.prototype.getAltitudeAbs = function (altitude) {
return altitude + this._map_dict.start_AMSL;
};
MulticopterDroneAPI.prototype.getMinHeight = function () {
return 0;
};
MulticopterDroneAPI.prototype.getMaxHeight = function () {
return 800;
};
MulticopterDroneAPI.prototype.getOnUpdateInterval = function () {
return this._flight_parameters.drone.onUpdateInterval;
};
MulticopterDroneAPI.prototype.getFlightParameters = function () {
return this._flight_parameters;
};
return MulticopterDroneAPI;
}());
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Web Script" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_Access_contents_information_Permission</string> </key>
<value>
<tuple>
<string>Anonymous</string>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Add_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Change_local_roles_Permission</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Modify_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_View_Permission</string> </key>
<value>
<tuple>
<string>Anonymous</string>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>content_md5</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>gadget_erp5_page_drone_simulator_multicopterdrone.js</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>drone_simulator_multicopterdrone_js</string> </value>
</item>
<item>
<key> <string>language</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Web Script</string> </value>
</item>
<item>
<key> <string>short_title</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Multicopter Drone (API)</string> </value>
</item>
<item>
<key> <string>version</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>document_publication_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>edit_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
<item>
<key> <string>processing_status_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAU=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>publish_alive</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <unicode>zope</unicode> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="DateTime" module="DateTime.DateTime"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1700754908.42</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>published_alive</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>edit</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <unicode>zope</unicode> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>1020.34636.19071.11520</string> </value>
</item>
<item>
<key> <string>state</string> </key>
<value> <string>current</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="DateTime" module="DateTime.DateTime"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1731937140.0</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="5" aka="AAAAAAAAAAU=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>detect_converted_file</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <unicode>zope</unicode> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_processing_state</string> </key>
<value> <string>converted</string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>0.0.0.0</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="DateTime" module="DateTime.DateTime"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1700754774.95</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -19,6 +19,11 @@ ...@@ -19,6 +19,11 @@
<script src="gadget_global.js" type="text/javascript"></script> <script src="gadget_global.js" type="text/javascript"></script>
<script src="domsugar.js" type="text/javascript"></script> <script src="domsugar.js" type="text/javascript"></script>
<!-- API scripts -->
<script src="gadget_erp5_page_drone_simulator_fixedwingdrone.js" type="text/javascript"></script>
<script src="gadget_erp5_page_drone_simulator_multicopterdrone.js" type="text/javascript"></script>
<script src="gadget_erp5_page_drone_simulator_dronelogfollower.js" type="text/javascript"></script>
<script src="gadget_erp5_page_drone_simulator_log_page.js" type="text/javascript"></script> <script src="gadget_erp5_page_drone_simulator_log_page.js" type="text/javascript"></script>
</head> </head>
......
...@@ -230,7 +230,7 @@ ...@@ -230,7 +230,7 @@
</item> </item>
<item> <item>
<key> <string>actor</string> </key> <key> <string>actor</string> </key>
<value> <string>zope</string> </value> <value> <unicode>zope</unicode> </value>
</item> </item>
<item> <item>
<key> <string>comment</string> </key> <key> <string>comment</string> </key>
...@@ -244,7 +244,7 @@ ...@@ -244,7 +244,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1004.22391.16038.6980</string> </value> <value> <string>1017.23884.35535.62190</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -264,7 +264,7 @@ ...@@ -264,7 +264,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1671109341.4</float> <float>1730898722.9</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
/*jslint indent: 2, maxlen: 100*/ /*jslint indent: 2, maxlen: 100*/
/*global window, rJS, domsugar, document*/ /*global window, rJS, domsugar, document, DroneLogAPI, FixedWingDroneAPI, MulticopterDroneAPI*/
(function (window, rJS, domsugar, document) { (function (window, rJS, domsugar, document, API_LIST) {
"use strict"; "use strict";
var SIMULATION_SPEED = 200, var SIMULATION_SPEED = 200,
...@@ -8,16 +8,16 @@ ...@@ -8,16 +8,16 @@
DRAW = true, DRAW = true,
LOG = false, LOG = false,
DRONE_LIST = [ DRONE_LIST = [
{"id": 0, "type": "DroneLogAPI", "log_content": ""}, {"id": 0, "type": API_LIST[0].name, "log_content": ""},
{"id": 1, "type": "DroneLogAPI", "log_content": ""} {"id": 1, "type": API_LIST[0].name, "log_content": ""}
], ],
WIDTH = 680, WIDTH = 680,
HEIGHT = 340, HEIGHT = 340,
LOGIC_FILE_LIST = [ LOGIC_FILE_LIST = [
'gadget_erp5_page_drone_simulator_logic.js', 'gadget_erp5_page_drone_simulator_logic.js'
'gadget_erp5_page_drone_simulator_fixedwingdrone.js', ].concat(API_LIST.map(function (api) {
'gadget_erp5_page_drone_simulator_dronelogfollower.js' return api.SCRIPT_NAME;
]; }));
rJS(window) rJS(window)
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
...@@ -221,7 +221,8 @@ ...@@ -221,7 +221,8 @@
game_parameters_json = { game_parameters_json = {
"drone": { "drone": {
"maxAcceleration": 1, "maxAcceleration": 1,
"maxSpeed": 1 "maxSpeed": 1,
"list": DRONE_LIST
}, },
"gameTime": SIMULATION_TIME, "gameTime": SIMULATION_TIME,
"simulation_speed": parseFloat(options.simulation_speed), "simulation_speed": parseFloat(options.simulation_speed),
...@@ -244,8 +245,7 @@ ...@@ -244,8 +245,7 @@
}, },
"draw_flight_path": DRAW, "draw_flight_path": DRAW,
"log_drone_flight": LOG, "log_drone_flight": LOG,
"temp_flight_path": false, "temp_flight_path": false
"droneList": DRONE_LIST
}; };
return gadget.declareGadget("babylonjs.gadget.html", return gadget.declareGadget("babylonjs.gadget.html",
{element: fragment, scope: 'simulator'}) {element: fragment, scope: 'simulator'})
...@@ -295,4 +295,4 @@ ...@@ -295,4 +295,4 @@
}); });
}); });
}(window, rJS, domsugar, document)); }(window, rJS, domsugar, document, [DroneLogAPI, FixedWingDroneAPI, MulticopterDroneAPI]));
\ No newline at end of file \ No newline at end of file
...@@ -246,7 +246,7 @@ ...@@ -246,7 +246,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1011.48769.44767.36898</string> </value> <value> <string>1020.32016.49807.50141</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -266,7 +266,7 @@ ...@@ -266,7 +266,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1697034365.81</float> <float>1730900244.98</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -19,6 +19,10 @@ ...@@ -19,6 +19,10 @@
<script src="gadget_global.js" type="text/javascript"></script> <script src="gadget_global.js" type="text/javascript"></script>
<script src="domsugar.js" type="text/javascript"></script> <script src="domsugar.js" type="text/javascript"></script>
<!-- API scripts -->
<script src="gadget_erp5_page_drone_simulator_fixedwingdrone.js" type="text/javascript"></script>
<script src="gadget_erp5_page_drone_simulator_multicopterdrone.js" type="text/javascript"></script>
<script src="gadget_erp5_page_drone_simulator_script_page.js" type="text/javascript"></script> <script src="gadget_erp5_page_drone_simulator_script_page.js" type="text/javascript"></script>
</head> </head>
......
...@@ -230,7 +230,7 @@ ...@@ -230,7 +230,7 @@
</item> </item>
<item> <item>
<key> <string>actor</string> </key> <key> <string>actor</string> </key>
<value> <string>zope</string> </value> <value> <unicode>zope</unicode> </value>
</item> </item>
<item> <item>
<key> <string>comment</string> </key> <key> <string>comment</string> </key>
...@@ -244,7 +244,7 @@ ...@@ -244,7 +244,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1004.65523.1234.17</string> </value> <value> <string>1020.30362.56361.22715</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -264,7 +264,7 @@ ...@@ -264,7 +264,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1671032907.71</float> <float>1730800996.91</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
/*jslint indent: 2, maxlen: 100*/ /*jslint indent: 2, maxlen: 100*/
/*global window, rJS, domsugar, document, Blob*/ /*global window, rJS, domsugar, document, Blob, FixedWingDroneAPI, MulticopterDroneAPI*/
(function (window, rJS, domsugar, document, Blob) { (function (window, rJS, domsugar, document, Blob, API_LIST) {
"use strict"; "use strict";
//Default values - TODO: get them from the drone API
var SIMULATION_SPEED = 200, var SIMULATION_SPEED = 200,
SIMULATION_TIME = 1500, SIMULATION_TIME = 1500,
min_lat = 45.6364, min_lat = 45.6364,
...@@ -11,74 +10,98 @@ ...@@ -11,74 +10,98 @@
min_lon = 14.2521, min_lon = 14.2521,
max_lon = 14.2766, max_lon = 14.2766,
map_height = 100, map_height = 100,
start_AMSL = 595, start_AMSL = 100,
DEFAULT_SPEED = 16, DEFAULT_SPEED = 16,
MAX_ACCELERATION = 6,
MAX_DECELERATION = 1,
MIN_SPEED = 12,
MAX_SPEED = 26,
MAX_ROLL = 35,
MIN_PITCH = -20,
MAX_PITCH = 25,
MAX_CLIMB_RATE = 8,
MAX_SINK_RATE = 3,
MAX_COMMAND_FREQUENCY = 2,
INITIAL_POSITION = { INITIAL_POSITION = {
"latitude": 45.6412, "latitude": 45.6412,
"longitude": 14.2658, "longitude": 14.2658,
"altitude": 15 "altitude": 0
}, },
NUMBER_OF_DRONES = 2, NUMBER_OF_DRONES = 2,
// Non-inputs parameters
DEFAULT_SCRIPT_CONTENT = DEFAULT_SCRIPT_CONTENT =
'var ALTITUDE = 100,\n' + '/*jslint nomen: true, indent: 2, maxerr: 3, maxlen: 80 */\n' +
'/*global console, me*/\n' +
'\n' +
'(function (console, me) {\n' +
' "use strict";\n' +
'\n' +
' var ALTITUDE = 100,\n' +
' EPSILON = 9,\n' + ' EPSILON = 9,\n' +
' CHECKPOINT_LIST = [\n' + ' CHECKPOINT_LIST = [],\n' +
' DIRECTION_LIST = [\n' +
' {\n' + ' {\n' +
' altitude: 585.1806861589965,\n' + ' distance: 1053,\n' +
' latitude: 45.64492790560583,\n' + ' bearing: 293\n' +
' longitude: 14.25334942966329\n' +
' },\n' + ' },\n' +
' {\n' + ' {\n' +
' altitude: 589.8802607573035,\n' + ' distance: 800,\n' +
' latitude: 45.64316335436476,\n' + ' bearing: 104\n' +
' longitude: 14.26332880184475\n' +
' },\n' + ' },\n' +
' {\n' + ' {\n' +
' altitude: 608.6648153348965,\n' + ' distance: 669,\n' +
' latitude: 45.64911917196595,\n' + ' bearing: 352\n' +
' longitude: 14.26214792790128\n' +
' },\n' + ' },\n' +
' {\n' + ' {\n' +
' altitude: 606.1448368129072,\n' + ' distance: 925,\n' +
' latitude: 45.64122685351364,\n' + ' bearing: 162\n' +
' longitude: 14.26590493128597\n' +
' },\n' + ' },\n' +
' {\n' + ' {\n' +
' altitude: 630.0829598206344,\n' + ' distance: 690,\n' +
' latitude: 45.64543355564817,\n' + ' bearing: 47\n' +
' longitude: 14.27242391207985\n' +
' },\n' + ' },\n' +
' {\n' + ' {\n' +
' altitude: 616.1839898415284,\n' + ' distance: 935,\n' +
' latitude: 45.6372792927328,\n' + ' bearing: 166\n' +
' longitude: 14.27533492411138\n' +
' },\n' + ' },\n' +
' {\n' + ' {\n' +
' altitude: 598.0603137354178,\n' + ' distance: 1129,\n' +
' latitude: 45.64061299543953,\n' + ' bearing: 289\n' +
' longitude: 14.26161958465814\n' +
' },\n' + ' },\n' +
' {\n' + ' {\n' +
' altitude: 607.1243119862851,\n' + ' distance: 520,\n' +
' latitude: 45.64032340702919,\n' + ' bearing: 94\n' +
' longitude: 14.2682896662383\n' + ' }\n' +
' ],\n' +
' R = 6371e3; // meters\n' +
'\n' +
' function to_deg(rad) {\n' +
' return rad * 180 / Math.PI;\n' +
' }\n' + ' }\n' +
' ];\n' +
'\n' + '\n' +
'function distance(lat1, lon1, lat2, lon2) {\n' + ' function to_rad(deg) {\n' +
' var R = 6371e3, // meters\n' + ' return deg * Math.PI / 180;\n' +
' la1 = lat1 * Math.PI / 180, // lat, lon in radians\n' + ' }\n' +
'\n' +
' function set_checkpoints(lat, lon) {\n' +
' var bearing_rad,\n' +
' lat_end,\n' +
' lon_end,\n' +
' lat_start = to_rad(lat),\n' +
' lon_start = to_rad(lon),\n' +
' relative_d;\n' +
'\n' +
' DIRECTION_LIST.forEach(function (e) {\n' +
' bearing_rad = to_rad(e.bearing);\n' +
' relative_d = e.distance / R;\n' +
'\n' +
' lat_end = Math.asin(Math.sin(lat_start) * Math.cos(relative_d) +\n' +
' Math.cos(lat_start) * Math.sin(relative_d) * Math.cos(bearing_rad));\n' +
' lon_end = lon_start + Math.atan2(\n' +
' Math.sin(bearing_rad) * Math.sin(relative_d) * Math.cos(lat_start),\n' +
' Math.cos(relative_d) - Math.sin(lat_start) * Math.sin(lon_start));\n' +
'\n' +
' CHECKPOINT_LIST.push({' +
' latitude: to_deg(lat_end),\n' +
' longitude: to_deg(lon_end)\n' +
' });\n' +
'\n' +
' lat_start = lat_end;\n' +
' lon_start = lon_end;\n' +
' });\n' +
' }\n' +
'\n' +
' function distance(lat1, lon1, lat2, lon2) {\n' +
' var la1 = lat1 * Math.PI / 180, // lat, lon in radians\n' +
' la2 = lat2 * Math.PI / 180,\n' + ' la2 = lat2 * Math.PI / 180,\n' +
' lo1 = lon1 * Math.PI / 180,\n' + ' lo1 = lon1 * Math.PI / 180,\n' +
' lo2 = lon2 * Math.PI / 180,\n' + ' lo2 = lon2 * Math.PI / 180,\n' +
...@@ -86,27 +109,39 @@ ...@@ -86,27 +109,39 @@
' sin_lon = Math.sin((lo2 - lo1) / 2),\n' + ' sin_lon = Math.sin((lo2 - lo1) / 2),\n' +
' h = haversine_phi + Math.cos(la1) * Math.cos(la2) * sin_lon * sin_lon;\n' + ' h = haversine_phi + Math.cos(la1) * Math.cos(la2) * sin_lon * sin_lon;\n' +
' return 2 * R * Math.asin(Math.sqrt(h));\n' + ' return 2 * R * Math.asin(Math.sqrt(h));\n' +
'}\n' + ' }\n' +
'\n' + '\n' +
'me.onStart = function (timestamp) {\n' + ' me.onStart = function (timestamp) {\n' +
' me.direction_set = false;\n' + ' me.direction_set = false;\n' +
' me.next_checkpoint = 0;\n' + ' me.next_checkpoint = 0;\n' +
'};\n' + ' me.takeOff();\n' +
' };\n' +
'\n' +
' me.onUpdate = function (timestamp) {\n' +
' if (!me.isReadyToFly()) {\n' +
' return;\n' +
' }\n' +
'\n' +
' me.current_position = me.getCurrentPosition();\n' +
' if (CHECKPOINT_LIST.length === 0) {\n' +
' set_checkpoints(me.current_position.latitude,\n' +
' me.current_position.longitude);\n' +
' }\n' +
'\n' + '\n' +
'me.onUpdate = function (timestamp) {\n' +
' if (!me.direction_set) {\n' + ' if (!me.direction_set) {\n' +
' if (me.next_checkpoint < CHECKPOINT_LIST.length) {\n' + ' if (me.next_checkpoint < CHECKPOINT_LIST.length) {\n' +
' me.setTargetCoordinates(\n' + ' me.setTargetCoordinates(\n' +
' CHECKPOINT_LIST[me.next_checkpoint].latitude,\n' + ' CHECKPOINT_LIST[me.next_checkpoint].latitude,\n' +
' CHECKPOINT_LIST[me.next_checkpoint].longitude,\n' + ' CHECKPOINT_LIST[me.next_checkpoint].longitude,\n' +
' CHECKPOINT_LIST[me.next_checkpoint].altitude + ALTITUDE + ALTITUDE * me.id,\n' + ' ' + start_AMSL + ' + ALTITUDE + ALTITUDE * me.id,\n' +
' ' + DEFAULT_SPEED + '\n' + ' ' + DEFAULT_SPEED + '\n' +
' );\n' + ' );\n' +
' console.log("[DEMO] Going to Checkpoint %d", me.next_checkpoint);\n' + ' console.log("[DEMO] Going to Checkpoint", me.next_checkpoint);\n' +
' }\n' + ' }\n' +
' me.direction_set = true;\n' + ' me.direction_set = true;\n' +
' return;\n' + ' return;\n' +
' }\n' + ' }\n' +
'\n' +
' if (me.next_checkpoint < CHECKPOINT_LIST.length) {\n' + ' if (me.next_checkpoint < CHECKPOINT_LIST.length) {\n' +
' me.current_position = me.getCurrentPosition();\n' + ' me.current_position = me.getCurrentPosition();\n' +
' me.distance = distance(\n' + ' me.distance = distance(\n' +
...@@ -116,65 +151,83 @@ ...@@ -116,65 +151,83 @@
' CHECKPOINT_LIST[me.next_checkpoint].longitude\n' + ' CHECKPOINT_LIST[me.next_checkpoint].longitude\n' +
' );\n' + ' );\n' +
' if (me.distance <= EPSILON) {\n' + ' if (me.distance <= EPSILON) {\n' +
' console.log("[DEMO] Reached Checkpoint %d", me.next_checkpoint);\n' + ' console.log("[DEMO] Reached Checkpoint", me.next_checkpoint);\n' +
' me.next_checkpoint += 1;\n' + ' me.next_checkpoint += 1;\n' +
' me.direction_set = false;\n' + ' me.direction_set = false;\n' +
' }\n' + ' }\n' +
' return;\n' + ' return;\n' +
' }\n' + ' }\n' +
' if (!me.isLanding()) { me.land() };\n' + '\n' +
' if (me.getCurrentPosition().altitude <= 0) { me.exit(0) };\n' + ' if (!me.isLanding()) {\n' +
'};', ' me.land();\n' +
' }\n' +
' if (me.getCurrentPosition().altitude <= 0) {\n' +
' me.exit(0);\n' +
' }\n' +
' };\n' +
'}(console, me));\n',
DRAW = true, DRAW = true,
LOG = true, LOG = true,
LOG_TIME = 1662.7915426540285, LOG_TIME = 1662.7915426540285,
ONUPDATE_INTERVAL = 100, ONUPDATE_INTERVAL = 100,
DRONE_LIST = [],
WIDTH = 680,
HEIGHT = 340,
LOGIC_FILE_LIST = [ LOGIC_FILE_LIST = [
'gadget_erp5_page_drone_simulator_logic.js', 'gadget_erp5_page_drone_simulator_logic.js',
'gadget_erp5_page_drone_simulator_fixedwingdrone.js',
'gadget_erp5_page_drone_simulator_dronelogfollower.js' 'gadget_erp5_page_drone_simulator_dronelogfollower.js'
]; ].concat(API_LIST.map(function (api) {
return api.SCRIPT_NAME;
rJS(window) }));
/////////////////////////////////////////////////////////////////
// Acquired methods
/////////////////////////////////////////////////////////////////
.declareAcquiredMethod("updateHeader", "updateHeader")
.declareAcquiredMethod("notifySubmitted", "notifySubmitted")
.allowPublicAcquisition('notifySubmit', function () { function getAPI(droneType) {
return this.triggerSubmit(); return API_LIST.find(function (api) {
}) return api.DRONE_TYPE === droneType;
});
.declareMethod("triggerSubmit", function () { }
return this.element.querySelector('input[type="submit"]').click();
})
.onEvent('submit', function () { function getContentFromParameterForm(gadget) {
var gadget = this; return gadget.getDeclaredGadget('parameter_form')
return gadget.getDeclaredGadget('form_view')
.push(function (form_gadget) { .push(function (form_gadget) {
return form_gadget.getContent(); return form_gadget.getContent();
}) })
.push(function (input) { .push(function (content_dict) {
gadget.runGame(input); var key;
for (key in content_dict) {
if (content_dict.hasOwnProperty(key)) {
gadget.state[key] = content_dict[key];
}
}
}); });
}
//////////////////////////////////////////////////
// Game parameters
//////////////////////////////////////////////////
function renderGameParameterView(gadget) {
var api = getAPI(gadget.state.drone_type), erp5_view, form_gadget;
return gadget.declareGadget("gadget_erp5_form.html", {
scope: "parameter_form"
}) })
.push(function (sub_gadget) {
form_gadget = sub_gadget;
.declareMethod('render', function render() { erp5_view = {
var gadget = this; "my_drone_type": {
return gadget.getDeclaredGadget('form_view') "description": "Type of drone to simulate",
.push(function (form_gadget) { "title": "Drone Type",
return form_gadget.render({ "items": API_LIST.map(function (api) {
erp5_document: { return api.DRONE_TYPE;
"_embedded": {"_view": { }),
"value": gadget.state.drone_type,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_type",
"hidden": 0,
"type": "ListField"
},
"my_simulation_speed": { "my_simulation_speed": {
"description": "", "description": "",
"title": "Simulation Speed", "title": "Simulation Speed",
"default": SIMULATION_SPEED, "default": gadget.state.simulation_speed,
"css_class": "", "css_class": "",
"required": 1, "required": 1,
"editable": 1, "editable": 1,
...@@ -185,7 +238,7 @@ ...@@ -185,7 +238,7 @@
"my_simulation_time": { "my_simulation_time": {
"description": "Duration of the simulation (in seconds)", "description": "Duration of the simulation (in seconds)",
"title": "Simulation Time", "title": "Simulation Time",
"default": SIMULATION_TIME, "default": gadget.state.simulation_time,
"css_class": "", "css_class": "",
"required": 1, "required": 1,
"editable": 1, "editable": 1,
...@@ -196,7 +249,7 @@ ...@@ -196,7 +249,7 @@
"my_onupdate_interval": { "my_onupdate_interval": {
"description": "Minimum interval (in milliseconds) between 2 executions of onUpdate function as well as periodicity to send telemetry to the swarm", "description": "Minimum interval (in milliseconds) between 2 executions of onUpdate function as well as periodicity to send telemetry to the swarm",
"title": "OnUpdate interval", "title": "OnUpdate interval",
"default": ONUPDATE_INTERVAL, "default": gadget.state.onupdate_interval,
"css_class": "", "css_class": "",
"required": 1, "required": 1,
"editable": 1, "editable": 1,
...@@ -204,127 +257,6 @@ ...@@ -204,127 +257,6 @@
"hidden": 0, "hidden": 0,
"type": "IntegerField" "type": "IntegerField"
}, },
"my_drone_min_speed": {
"description": "",
"title": "Drone min speed",
"default": MIN_SPEED,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_min_speed",
"hidden": 0,
"type": "IntegerField"
},
"my_drone_speed": {
"description": "",
"title": "Drone speed",
"default": DEFAULT_SPEED,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_speed",
"hidden": 0,
"type": "FloatField"
},
"my_drone_max_speed": {
"description": "",
"title": "Drone max speed",
"default": MAX_SPEED,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_max_speed",
"hidden": 0,
"type": "IntegerField"
},
"my_drone_max_acceleration": {
"description": "",
"title": "Drone max Acceleration",
"default": MAX_ACCELERATION,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_max_acceleration",
"hidden": 0,
"type": "IntegerField"
},
"my_drone_max_deceleration": {
"description": "",
"title": "Drone max Deceleration",
"default": MAX_DECELERATION,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_max_deceleration",
"hidden": 0,
"type": "IntegerField"
},
"my_drone_max_roll": {
"description": "",
"title": "Drone max roll",
"default": MAX_ROLL,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_max_roll",
"hidden": 0,
"type": "FloatField"
},
"my_drone_min_pitch": {
"description": "",
"title": "Drone min pitch",
"default": MIN_PITCH,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_min_pitch",
"hidden": 0,
"type": "FloatField"
},
"my_drone_max_pitch": {
"description": "",
"title": "Drone max pitch",
"default": MAX_PITCH,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_max_pitch",
"hidden": 0,
"type": "FloatField"
},
"my_drone_max_sink_rate": {
"description": "",
"title": "Drone max sink rate",
"default": MAX_SINK_RATE,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_max_sink_rate",
"hidden": 0,
"type": "FloatField"
},
"my_drone_max_climb_rate": {
"description": "",
"title": "Drone max climb rate",
"default": MAX_CLIMB_RATE,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_max_climb_rate",
"hidden": 0,
"type": "FloatField"
},
"my_drone_max_command_frequency": {
"description": "",
"title": "Drone max command frequency",
"default": MAX_COMMAND_FREQUENCY,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_max_command_frequency",
"hidden": 0,
"type": "FloatField"
},
"my_minimum_latitud": { "my_minimum_latitud": {
"description": "", "description": "",
"title": "Minimum latitude", "title": "Minimum latitude",
...@@ -427,7 +359,7 @@ ...@@ -427,7 +359,7 @@
"my_number_of_drones": { "my_number_of_drones": {
"description": "", "description": "",
"title": "Number of drones", "title": "Number of drones",
"default": NUMBER_OF_DRONES, "default": gadget.state.number_of_drones,
"css_class": "", "css_class": "",
"required": 1, "required": 1,
"editable": 1, "editable": 1,
...@@ -435,19 +367,32 @@ ...@@ -435,19 +367,32 @@
"hidden": 0, "hidden": 0,
"type": "IntegerField" "type": "IntegerField"
}, },
"my_script": { "my_drone_script": {
"default": DEFAULT_SCRIPT_CONTENT, "description": "",
"title": "Drone script",
"default": gadget.state.drone_script,
"css_class": "", "css_class": "",
"required": 1, "required": 1,
"editable": 1, "editable": 1,
"key": "script", "key": "drone_script",
"hidden": 0, "hidden": 0,
"type": "GadgetField",
"renderjs_extra": '{"editor": "codemirror", "maximize": true}',
"url": "gadget_editor.html", "url": "gadget_editor.html",
"sandbox": "public" "renderjs_extra": JSON.stringify({
"maximize": true,
"language": "en",
"portal_type": "Web Script",
"editor": "codemirror"
}),
"type": "GadgetField"
} }
}}, };
Object.keys(api.FORM_VIEW).forEach(function (key) {
erp5_view[key] = api.FORM_VIEW[key];
});
return form_gadget.render({
erp5_document: {
"_embedded": {"_view": erp5_view},
"_links": { "_links": {
"type": { "type": {
name: "" name: ""
...@@ -457,84 +402,157 @@ ...@@ -457,84 +402,157 @@
form_definition: { form_definition: {
group_list: [[ group_list: [[
"left", "left",
[["my_simulation_speed"], ["my_simulation_time"], ["my_onupdate_interval"], [["my_drone_type"], ["my_simulation_speed"], ["my_simulation_time"], ["my_onupdate_interval"],
["my_number_of_drones"], ["my_minimum_latitud"], ["my_maximum_latitud"], ["my_number_of_drones"], ["my_minimum_latitud"], ["my_maximum_latitud"],
["my_minimum_longitud"], ["my_maximum_longitud"], ["my_minimum_longitud"], ["my_maximum_longitud"],
["my_init_pos_lat"], ["my_init_pos_lon"], ["my_init_pos_alt"], ["my_init_pos_lat"], ["my_init_pos_lon"], ["my_init_pos_alt"],
["my_map_height"]] ["my_map_height"]]
], [ ], [
"right", "right",
[["my_start_AMSL"], ["my_drone_min_speed"], ["my_drone_speed"], [["my_start_AMSL"]].concat(
["my_drone_max_speed"], ["my_drone_max_acceleration"], Object.keys(api.FORM_VIEW).map(function (property_name) {
["my_drone_max_deceleration"], ["my_drone_max_roll"], ["my_drone_min_pitch"], return [property_name];
["my_drone_max_pitch"], ["my_drone_max_sink_rate"], ["my_drone_max_climb_rate"], })
["my_drone_max_command_frequency"]] )
], [ ], [
"bottom", "bottom",
[["my_script"]] [["my_drone_script"]]
]] ]]
} }
}); });
}) })
.push(function () { .push(function () {
return gadget.updateHeader({ // Attach the form to the page
page_title: 'Drone Simulator - Edit and run script', domsugar(gadget.element.querySelector('div[data-gadget-scope="form_view"]'), [
page_icon: 'puzzle-piece' form_gadget.element
]);
});
}
//////////////////////////////////////////////////
// Play
//////////////////////////////////////////////////
function renderPlayView(gadget) {
return gadget.declareGadget("gadget_erp5_form.html", {
scope: "form_view_babylonjs"
})
.push(function (sub_gadget) {
// Attach the form to the page
domsugar(gadget.element.querySelector('div[data-gadget-scope="form_view_babylonjs"]'), [
domsugar('div', {
'class': 'simulator_div'
}),
sub_gadget.element
]);
gadget.runGame();
});
}
function formToFilename(form, drone) {
return Object.keys(form).map(function (field_name) {
var key = form[field_name].key;
return key + "_" + drone[key];
});
}
rJS(window)
/////////////////////////////////////////////////////////////////
// Acquired methods
/////////////////////////////////////////////////////////////////
.declareAcquiredMethod("updateHeader", "updateHeader")
.declareAcquiredMethod("notifySubmitted", "notifySubmitted")
.allowPublicAcquisition('notifySubmit', function () {
return this.triggerSubmit();
})
.allowPublicAcquisition('notifyChange', function (argument_list, scope) {
return this.triggerAPIChange(scope);
})
.declareMethod("triggerSubmit", function () {
return this.element.querySelector('input[type="submit"]').click();
})
.onEvent('submit', function () {
return this.getContent();
})
.declareMethod("triggerAPIChange", function (scope) {
var gadget = this,
sub_gadget;
return gadget.getDeclaredGadget(scope)
.push(function (result) {
sub_gadget = result;
return sub_gadget.getContent();
})
.push(function (result) {
if (gadget.state.drone_type !== result.drone_type) {
return gadget.changeState({
drone_type: result.drone_type
}); });
}
}); });
}) })
.declareJob('runGame', function runGame(options) { .declareJob('runGame', function runGame() {
var gadget = this, i, var gadget = this, i,
fragment = gadget.element.querySelector('.simulator_div'),
game_parameters_json;
fragment = domsugar(gadget.element.querySelector('.simulator_div'), fragment = domsugar(gadget.element.querySelector('.simulator_div'),
[domsugar('div')]).firstElementChild; [domsugar('div')]).firstElementChild,
DRONE_LIST = []; game_parameters_json,
for (i = 0; i < options.number_of_drones; i += 1) { drone_list = [],
DRONE_LIST[i] = {"id": i, "type": "FixedWingDroneAPI", api = getAPI(gadget.state.drone_type),
"script_content": options.script}; drone_parameter_list = Object.keys(api.FORM_VIEW);
for (i = 0; i < gadget.state.number_of_drones; i += 1) {
drone_list[i] = {"id": i, "type": api.name,
"script_content": gadget.state.drone_script};
} }
game_parameters_json = { game_parameters_json = {
"drone": { "drone": {
"maxAcceleration": parseInt(options.drone_max_acceleration, 10), "onUpdateInterval": parseInt(gadget.state.onupdate_interval, 10),
"maxDeceleration": parseInt(options.drone_max_deceleration, 10), "list": drone_list
"minSpeed": parseInt(options.drone_min_speed, 10),
"speed": parseFloat(options.drone_speed),
"maxSpeed": parseInt(options.drone_max_speed, 10),
"maxRoll": parseFloat(options.drone_max_roll),
"minPitchAngle": parseFloat(options.drone_min_pitch),
"maxPitchAngle": parseFloat(options.drone_max_pitch),
"maxSinkRate": parseFloat(options.drone_max_sink_rate),
"maxClimbRate": parseFloat(options.drone_max_climb_rate),
"maxCommandFrequency": parseFloat(options.drone_max_command_frequency),
"onUpdateInterval": parseInt(options.onupdate_interval, 10)
}, },
"gameTime": parseInt(options.simulation_time, 10), "gameTime": parseInt(gadget.state.simulation_time, 10),
"simulation_speed": parseInt(options.simulation_speed, 10), "simulation_speed": parseInt(gadget.state.simulation_speed, 10),
"latency": { "latency": {
"information": 0, "information": 0,
"communication": 0 "communication": 0
}, },
"map": { "map": {
"min_lat": parseFloat(options.min_lat), "min_lat": parseFloat(gadget.state.min_lat),
"max_lat": parseFloat(options.max_lat), "max_lat": parseFloat(gadget.state.max_lat),
"min_lon": parseFloat(options.min_lon), "min_lon": parseFloat(gadget.state.min_lon),
"max_lon": parseFloat(options.max_lon), "max_lon": parseFloat(gadget.state.max_lon),
"height": parseInt(options.map_height, 10), "height": parseInt(gadget.state.map_height, 10),
"start_AMSL": parseFloat(options.start_AMSL) "start_AMSL": parseFloat(gadget.state.start_AMSL)
}, },
"initialPosition": { "initialPosition": {
"longitude": parseFloat(options.init_pos_lon), "longitude": parseFloat(gadget.state.init_pos_lon),
"latitude": parseFloat(options.init_pos_lat), "latitude": parseFloat(gadget.state.init_pos_lat),
"altitude": parseFloat(options.init_pos_alt) "altitude": parseFloat(gadget.state.init_pos_alt)
}, },
"draw_flight_path": DRAW, "draw_flight_path": DRAW,
"temp_flight_path": true, "temp_flight_path": true,
"log_drone_flight": LOG, "log_drone_flight": LOG,
"log_interval_time": LOG_TIME, "log_interval_time": LOG_TIME
"droneList": DRONE_LIST
}; };
drone_parameter_list.forEach(function (parameter) {
var field = api.FORM_VIEW[parameter];
switch (field.type) {
case 'IntegerField':
game_parameters_json.drone[field.key] = parseInt(gadget.state[field.key], 10);
break;
case 'FloatField':
game_parameters_json.drone[field.key] = parseFloat(gadget.state[field.key]);
break;
default:
throw new Error("Unhandled field type");
}
});
return gadget.declareGadget("babylonjs.gadget.html", return gadget.declareGadget("babylonjs.gadget.html",
{element: fragment, scope: 'simulator'}) {element: fragment, scope: 'simulator'})
.push(function () { .push(function () {
...@@ -554,8 +572,7 @@ ...@@ -554,8 +572,7 @@
"type": "GadgetField", "type": "GadgetField",
"url": "babylonjs.gadget.html", "url": "babylonjs.gadget.html",
"sandbox": "public", "sandbox": "public",
"renderjs_extra": '{"autorun": false, "width": ' + WIDTH + ', ' + "renderjs_extra": '{"autorun": false, ' +
'"height": ' + HEIGHT + ', ' +
'"logic_file_list": ' + JSON.stringify(LOGIC_FILE_LIST) + ', ' + '"logic_file_list": ' + JSON.stringify(LOGIC_FILE_LIST) + ', ' +
'"game_parameters": ' + JSON.stringify(game_parameters_json) + '"game_parameters": ' + JSON.stringify(game_parameters_json) +
'}' '}'
...@@ -590,18 +607,9 @@ ...@@ -590,18 +607,9 @@
blob = new Blob([log_content], {type: 'text/plain'}); blob = new Blob([log_content], {type: 'text/plain'});
a = domsugar('a', { a = domsugar('a', {
text: 'Download Simulation LOG ' + i, text: 'Download Simulation LOG ' + i,
download: 'simulation_log_' + i download: ['simulation_log_' + i].concat(
+ '_speed_' + game_parameters_json.drone.speed formToFilename(api.FORM_VIEW, game_parameters_json.drone)
+ '_min-speed_' + game_parameters_json.drone.minSpeed ).join("_") + ".txt",
+ '_max-speed_' + game_parameters_json.drone.maxSpeed
+ '_max-accel_' + game_parameters_json.drone.maxAcceleration
+ '_max-decel_' + game_parameters_json.drone.maxDeceleration
+ '_max-roll_' + game_parameters_json.drone.maxRoll
+ '_min-pitch_' + game_parameters_json.drone.minPitchAngle
+ '_max-pitch_' + game_parameters_json.drone.maxPitchAngle
+ '_max-sink_' + game_parameters_json.drone.maxSinkRate
+ '_max-climb_' + game_parameters_json.drone.maxClimbRate
+ '.txt',
href: window.URL.createObjectURL(blob) href: window.URL.createObjectURL(blob)
}); });
log = domsugar('textarea', { value: log_content, id: 'log_result_' + i }); log = domsugar('textarea', { value: log_content, id: 'log_result_' + i });
...@@ -617,6 +625,54 @@ ...@@ -617,6 +625,54 @@
return gadget.notifySubmitted({message: "Error: " + error.message, return gadget.notifySubmitted({message: "Error: " + error.message,
status: 'error'}); status: 'error'});
}); });
})
.setState({
drone_type: API_LIST[0].DRONE_TYPE,
drone_script: DEFAULT_SCRIPT_CONTENT,
number_of_drones: NUMBER_OF_DRONES,
onupdate_interval: ONUPDATE_INTERVAL,
simulation_time: SIMULATION_TIME,
simulation_speed: SIMULATION_SPEED,
min_lat: min_lat,
max_lat: max_lat,
min_lon: min_lon,
max_lon: max_lon,
height: map_height,
start_AMSL: start_AMSL,
longitude: INITIAL_POSITION.longitude,
latitude: INITIAL_POSITION.latitude,
altitude: INITIAL_POSITION.altitude
})
.declareMethod('render', function render() {
var gadget = this;
return renderGameParameterView(gadget)
.push(function () {
return gadget.updateHeader({
page_title: 'Drone Simulator - Edit and run script',
page_icon: 'puzzle-piece'
});
});
})
.onStateChange(function (modification_dict) {
var gadget = this;
if (modification_dict.hasOwnProperty('drone_type')) {
return getContentFromParameterForm(this)
.push(function () {
return renderGameParameterView(gadget);
});
}
})
.declareMethod('getContent', function () {
var gadget = this;
return getContentFromParameterForm(this)
.push(function () {
return renderPlayView(gadget);
}); });
}, {mutex: 'changestate'});
}(window, rJS, domsugar, document, Blob)); }(window, rJS, domsugar, document, Blob, [MulticopterDroneAPI, FixedWingDroneAPI]));
\ No newline at end of file \ No newline at end of file
...@@ -246,7 +246,7 @@ ...@@ -246,7 +246,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1015.64120.46679.6946</string> </value> <value> <string>1020.49358.42946.36915</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -266,7 +266,7 @@ ...@@ -266,7 +266,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1713425712.2</float> <float>1731940826.8</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -19,9 +19,11 @@ ...@@ -19,9 +19,11 @@
<td>${base_url}/web_site_module/officejs_drone_simulator/</td> <td>${base_url}/web_site_module/officejs_drone_simulator/</td>
<td></td> <td></td>
</tr> </tr>
<!-- error on /Zuite_waitForActivities
<tal:block tal:define="web_site_name python: 'officejs_drone_simulator'"> <tal:block tal:define="web_site_name python: 'officejs_drone_simulator'">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForOfficejsUi/macros/install_offline_and_redirect" /> <tal:block metal:use-macro="here/Zuite_CommonTemplateForOfficejsUi/macros/install_offline_and_redirect" />
</tal:block> </tal:block>
-->
<!-- Check form --> <!-- Check form -->
<tr> <tr>
<td>waitForElementPresent</td> <td>waitForElementPresent</td>
...@@ -68,17 +70,17 @@ ...@@ -68,17 +70,17 @@
<!-- Check simulator gadget and babylon lib --> <!-- Check simulator gadget and babylon lib -->
<tr> <tr>
<td>waitForElementPresent</td> <td>waitForElementPresent</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_page_drone_simulator_gadget.html')]</td> <td>//div[contains(@data-gadget-url, 'babylonjs.gadget.html')]</td>
<td></td> <td></td>
<tr> <tr>
<tr> <tr>
<td>waitForElementPresent</td> <td>waitForElementPresent</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_page_drone_simulator_gadget.html')]//canvas[contains(@data-engine, 'Babylon.js')]</td> <td>//div[contains(@data-gadget-url, 'babylonjs.gadget.html')]//canvas[contains(@data-engine, 'Babylon.js')]</td>
<td></td> <td></td>
<tr> <tr>
<tr> <tr>
<td>waitForElementPresent</td> <td>waitForElementPresent</td>
<td>//div[@class="container"]//a[contains(text(), 'Download Simulation LOG')]</td> <td>//a[contains(text(), 'Download Simulation LOG')]</td>
<td></td> <td></td>
<tr> <tr>
<tr> <tr>
...@@ -86,6 +88,32 @@ ...@@ -86,6 +88,32 @@
<td>//div[@class="container"]//textarea</td> <td>//div[@class="container"]//textarea</td>
<td></td> <td></td>
<tr> <tr>
<!-- Change drone type -->
<tr>
<td>select</td>
<td>//select[@name="drone_type"]</td>
<td>value=Fixed Wings</td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//label[text()='Drone min speed']</td>
<td></td>
<tr>
<tr>
<td>click</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_page_drone_simulator_script_page.html')]//input[@type="submit" and @name="action_run"]</td>
<td></td>
<tr>
<tr>
<td>waitForElementPresent</td>
<td>//span[@id="loading"]</td>
<td></td>
<tr>
<tr>
<td>waitForElementPresent</td>
<td>//a[contains(text(), 'Download Simulation LOG')]</td>
<td></td>
<tr>
<!-- Go to log page --> <!-- Go to log page -->
<tr> <tr>
<td>click</td> <td>click</td>
...@@ -124,14 +152,14 @@ ...@@ -124,14 +152,14 @@
<tr> <tr>
<td>type</td> <td>type</td>
<td>//textarea[@id="log_1"]</td> <td>//textarea[@id="log_1"]</td>
<td>timestamp;;latitude;;longitude;;AMSL (m);;rel altitude (m);;pitch (°);;roll(°);;yaw(°);;air speed (m/s);;throttle(%);;climb rate(m/s) <td>timestamp (ms);latitude (°);longitude (°);AMSL (m);rel altitude (m);yaw (°);ground speed (m/s);climb rate (m/s)
16.666666666666668;45.6412;14.265800000000013;610.328;15</td> 0;45.6412;14.2658;595;0;0;0;0<br />1;45.6403;14.2671;595;0;180;6;0</td>
</tr> </tr>
<tr> <tr>
<td>type</td> <td>type</td>
<td>//textarea[@id="log_2"]</td> <td>//textarea[@id="log_2"]</td>
<td>timestamp;;latitude;;longitude;;AMSL (m);;rel altitude (m);;pitch (°);;roll(°);;yaw(°);;air speed (m/s);;throttle(%);;climb rate(m/s) <td>timestamp (ms);latitude (°);longitude (°);AMSL (m);rel altitude (m);yaw (°);ground speed (m/s);climb rate (m/s)
16.666666666666668;45.6412;14.265800000000013;610.328;15</td> 0;45.6412;14.2658;595;0;0;0;0<br />1;45.6403;14.2671;595;0;180;6;0</td>
</tr> </tr>
<tr> <tr>
<td>click</td> <td>click</td>
...@@ -151,12 +179,12 @@ ...@@ -151,12 +179,12 @@
<!-- Check simulator gadget and babylon lib --> <!-- Check simulator gadget and babylon lib -->
<tr> <tr>
<td>waitForElementPresent</td> <td>waitForElementPresent</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_page_drone_simulator_gadget.html')]</td> <td>//div[contains(@data-gadget-url, 'babylonjs.gadget.html')]</td>
<td></td> <td></td>
<tr> <tr>
<tr> <tr>
<td>waitForElementPresent</td> <td>waitForElementPresent</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_page_drone_simulator_gadget.html')]//canvas[contains(@data-engine, 'Babylon.js')]</td> <td>//div[contains(@data-gadget-url, 'babylonjs.gadget.html')]//canvas[contains(@data-engine, 'Babylon.js')]</td>
<td></td> <td></td>
<tr> <tr>
</tbody></table> </tbody></table>
......
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>testDroneCaptureFlagFlight</string> </value> <value> <string>testDroneSimulatorFixedWingFlight</string> </value>
</item> </item>
<item> <item>
<key> <string>output_encoding</string> </key> <key> <string>output_encoding</string> </key>
......
...@@ -9,14 +9,14 @@ ...@@ -9,14 +9,14 @@
<body> <body>
<table cellpadding="1" cellspacing="1" border="1"> <table cellpadding="1" cellspacing="1" border="1">
<thead> <thead>
<tr><td rowspan="1" colspan="3">Test Drone Simulator OJS app (expected failure)</td></tr> <tr><td rowspan="1" colspan="3">Test Fixed Wing Drone Simulator OJS app (expected failure)</td></tr>
</thead><tbody> </thead><tbody>
<tal:block metal:use-macro="here/Zuite_CommonTemplate/macros/init" /> <tal:block metal:use-macro="here/Zuite_CommonTemplate/macros/init" />
<!-- Go to site --> <!-- Go to site -->
<tr> <tr>
<td>open</td> <td>open</td>
<td>${base_url}/web_site_module/officejs_drone_simulator/app/#/?page=drone_simulator_test_page</td> <td>${base_url}/web_site_module/officejs_drone_simulator/app/#/?page=drone_simulator_fixed_wing_test_page</td>
<td></td> <td></td>
</tr> </tr>
<tr> <tr>
...@@ -26,12 +26,12 @@ ...@@ -26,12 +26,12 @@
<tr> <tr>
<tr> <tr>
<td>waitForElementPresent</td> <td>waitForElementPresent</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_page_drone_simulator_test_page.html')]//input[@type="submit" and @name="action_run"]</td> <td>//div[contains(@data-gadget-url, 'gadget_erp5_page_drone_simulator_fixed_wing_test_page.html')]//input[@type="submit" and @name="action_run"]</td>
<td></td> <td></td>
<tr> <tr>
<tr> <tr>
<td>click</td> <td>click</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_page_drone_simulator_test_page.html')]//input[@type="submit" and @name="action_run"]</td> <td>//div[contains(@data-gadget-url, 'gadget_erp5_page_drone_simulator_fixed_wing_test_page.html')]//input[@type="submit" and @name="action_run"]</td>
<td></td> <td></td>
<tr> <tr>
<tr> <tr>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ZopePageTemplate" module="Products.PageTemplates.ZopePageTemplate"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>expand</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>testDroneSimulatorMulticopterFlight</string> </value>
</item>
<item>
<key> <string>output_encoding</string> </key>
<value> <string>utf-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <unicode></unicode> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<html xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test Drone Simulator OJS app (expected failure)</title>
<!-- This test is expected to fail as the drone simulator runs on a web worker canvas, which relies on a very new feature: offscreen canvas
---- This feature is not supported yet by the latest Firefox ESR used in the test nodes -->
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Test Multicopter Drone Simulator OJS app (expected failure)</td></tr>
</thead><tbody>
<tal:block metal:use-macro="here/Zuite_CommonTemplate/macros/init" />
<!-- Go to site -->
<tr>
<td>open</td>
<td>${base_url}/web_site_module/officejs_drone_simulator/app/#/?page=drone_simulator_multicopter_test_page</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//div[contains(@data-gadget-url, 'codemirror.gadget.html')]</td>
<td></td>
<tr>
<tr>
<td>waitForElementPresent</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_page_drone_simulator_multicopter_test_page.html')]//input[@type="submit" and @name="action_run"]</td>
<td></td>
<tr>
<tr>
<td>click</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_page_drone_simulator_multicopter_test_page.html')]//input[@type="submit" and @name="action_run"]</td>
<td></td>
<tr>
<tr>
<td>waitForElementPresent</td>
<td>//span[@id="loading"]</td>
<td></td>
<tr>
<tr>
<td>waitForElementPresent</td>
<td>//div[contains(@data-gadget-url, 'babylonjs.gadget.html')]</td>
<td></td>
<tr>
<tr>
<td>waitForElementPresent</td>
<td>//div[contains(@data-gadget-url, 'babylonjs.gadget.html')]//canvas[contains(@data-engine, 'Babylon.js')]</td>
<td></td>
<tr>
<tr>
<td>waitForElementPresent</td>
<td>//div[contains(text(), 'CONSOLE LOG ENTRIES:')]</td>
<td></td>
<tr>
<tr>
<td>assertElementPresent</td>
<td>//div[contains(text(), 'Initial speed: OK')]</td>
<td></td>
<tr>
<tr>
<td>assertElementPresent</td>
<td>//div[contains(text(), 'Yaw angle: OK')]</td>
<td></td>
<tr>
<tr>
<td>assertElementPresent</td>
<td>//div[contains(text(), 'Timestamp: OK')]</td>
<td></td>
<tr>
<tr>
<td>assertElementPresent</td>
<td>//div[contains(text(), 'Distance: OK')]</td>
<td></td>
<tr>
<tr>
<td>assertElementPresent</td>
<td>//div[contains(text(), 'Latitude: OK')]</td>
<td></td>
<tr>
<tr>
<td>assertElementPresent</td>
<td>//div[contains(text(), 'Longitude: OK')]</td>
<td></td>
<tr>
<tr>
<td>assertElementPresent</td>
<td>//div[contains(text(), 'Altitude: OK')]</td>
<td></td>
<tr>
<tr>
<td>assertElementPresent</td>
<td>//div[contains(text(), 'Timeout: OK')]</td>
<td></td>
<tr>
</tbody></table>
</body>
</html>
\ No newline at end of file
...@@ -19,7 +19,10 @@ ...@@ -19,7 +19,10 @@
<script src="gadget_global.js" type="text/javascript"></script> <script src="gadget_global.js" type="text/javascript"></script>
<script src="domsugar.js" type="text/javascript"></script> <script src="domsugar.js" type="text/javascript"></script>
<script src="gadget_erp5_page_drone_capture_flag_test_page.js" type="text/javascript"></script> <!-- API scripts -->
<script src="gadget_erp5_page_drone_simulator_fixedwingdrone.js" type="text/javascript"></script>
<script src="gadget_erp5_page_drone_simulator_fixed_wing_test_page.js" type="text/javascript"></script>
</head> </head>
<body> <body>
......
...@@ -73,7 +73,7 @@ ...@@ -73,7 +73,7 @@
</item> </item>
<item> <item>
<key> <string>default_reference</string> </key> <key> <string>default_reference</string> </key>
<value> <string>gadget_erp5_page_drone_simulator_test_page.html</string> </value> <value> <string>gadget_erp5_page_drone_simulator_fixed_wing_test_page.html</string> </value>
</item> </item>
<item> <item>
<key> <string>description</string> </key> <key> <string>description</string> </key>
...@@ -83,7 +83,7 @@ ...@@ -83,7 +83,7 @@
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>test_drone_simulator_flight_html</string> </value> <value> <string>test_drone_simulator_fixed_wing_flight_html</string> </value>
</item> </item>
<item> <item>
<key> <string>language</string> </key> <key> <string>language</string> </key>
...@@ -103,7 +103,7 @@ ...@@ -103,7 +103,7 @@
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
<value> <string>Drone Simulator Test Page</string> </value> <value> <string>Drone Simulator Fixed Wing Test Page</string> </value>
</item> </item>
<item> <item>
<key> <string>version</string> </key> <key> <string>version</string> </key>
...@@ -244,7 +244,7 @@ ...@@ -244,7 +244,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1010.3732.28220.36454</string> </value> <value> <string>1020.14908.61242.50278</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -264,7 +264,7 @@ ...@@ -264,7 +264,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1690898356.42</float> <float>1730738493.75</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
/*jslint indent: 2, maxlen: 100*/ /*jslint indent: 2, maxlen: 100*/
/*global window, rJS, domsugar, document, URLSearchParams, Blob*/ /*global window, rJS, domsugar, document, FixedWingDroneAPI*/
(function (window, rJS, domsugar, document, URLSearchParams, Blob) { (function (window, rJS, domsugar, document, FixedWingDroneAPI) {
"use strict"; "use strict";
var SIMULATION_SPEED = 1, var SIMULATION_SPEED = 1,
...@@ -8,15 +8,6 @@ ...@@ -8,15 +8,6 @@
ON_UPDATE_INTERVAL = LOOP_INTERVAL, ON_UPDATE_INTERVAL = LOOP_INTERVAL,
SIMULATION_TIME = LOOP_INTERVAL / 1000, SIMULATION_TIME = LOOP_INTERVAL / 1000,
DEFAULT_SPEED = 16, DEFAULT_SPEED = 16,
MAX_ACCELERATION = 6,
MAX_DECELERATION = 1,
MIN_SPEED = 12,
MAX_SPEED = 26,
MAX_ROLL = 35,
MIN_PITCH = -20,
MAX_PITCH = 25,
MAX_CLIMB_RATE = 8,
MAX_SINK_RATE = 3,
NUMBER_OF_DRONES = 1, NUMBER_OF_DRONES = 1,
MIN_LAT = 45.6364, MIN_LAT = 45.6364,
MAX_LAT = 45.65, MAX_LAT = 45.65,
...@@ -49,14 +40,14 @@ ...@@ -49,14 +40,14 @@
'}\n' + '}\n' +
'\n' + '\n' +
'function compare(coord1, coord2) {\n' + 'function compare(coord1, coord2) {\n' +
' assert(coord1.latitude, coord2.latitude, "Latitude")\n' + ' assert(coord1.latitude, coord2.latitude, "Latitude");\n' +
' assert(coord1.longitude, coord2.longitude, "Longitude")\n' + ' assert(coord1.longitude, coord2.longitude, "Longitude");\n' +
' assert(coord1.altitude, coord2.altitude, "Altitude")\n' + ' assert(coord1.altitude, coord2.altitude, "Altitude");\n' +
'}\n' + '}\n' +
'\n' + '\n' +
'me.onStart = function (timestamp) {\n' + 'me.onStart = function (timestamp) {\n' +
' assert(me.getSpeed(), ' + DEFAULT_SPEED + ', "Initial speed");\n' + ' assert(me.getSpeed(), ' + DEFAULT_SPEED + ', "Initial speed");\n' +
' assert(me.getYaw(), 0, "Yaw angle")\n' + ' assert(me.getYaw(), 0, "Yaw angle");\n' +
' me.initialPosition = me.getCurrentPosition();\n' + ' me.initialPosition = me.getCurrentPosition();\n' +
' me.start_time = timestamp;\n' + ' me.start_time = timestamp;\n' +
' me.setTargetCoordinates(\n' + ' me.setTargetCoordinates(\n' +
...@@ -94,8 +85,9 @@ ...@@ -94,8 +85,9 @@
DRONE_LIST = [], DRONE_LIST = [],
LOGIC_FILE_LIST = [ LOGIC_FILE_LIST = [
'gadget_erp5_page_drone_simulator_logic.js', 'gadget_erp5_page_drone_simulator_logic.js',
'gadget_erp5_page_drone_simulator_fixedwingdrone.js', 'gadget_erp5_page_drone_simulator_multicopterdrone.js',
'gadget_erp5_page_drone_simulator_dronelogfollower.js' 'gadget_erp5_page_drone_simulator_dronelogfollower.js',
FixedWingDroneAPI.SCRIPT_NAME
]; ];
rJS(window) rJS(window)
...@@ -138,9 +130,12 @@ ...@@ -138,9 +130,12 @@
"key": "script", "key": "script",
"hidden": 0, "hidden": 0,
"type": "GadgetField", "type": "GadgetField",
"renderjs_extra": '{"editor": "codemirror", "maximize": true}', "renderjs_extra": JSON.stringify({
"url": "gadget_editor.html", "language": "en",
"sandbox": "public" "portal_type": "Web Script",
"editor": "codemirror"
}),
"url": "gadget_editor.html"
} }
}}, }},
"_links": { "_links": {
...@@ -167,23 +162,14 @@ ...@@ -167,23 +162,14 @@
fragment = domsugar(gadget.element.querySelector('.simulator_div'), fragment = domsugar(gadget.element.querySelector('.simulator_div'),
[domsugar('div')]).firstElementChild; [domsugar('div')]).firstElementChild;
for (i = 0; i < NUMBER_OF_DRONES; i += 1) { for (i = 0; i < NUMBER_OF_DRONES; i += 1) {
DRONE_LIST[i] = {"id": i, "type": "FixedWingDroneAPI", DRONE_LIST[i] = {"id": i, "type": FixedWingDroneAPI.name,
"script_content": options.script}; "script_content": options.script};
} }
game_parameters_json = { game_parameters_json = {
"debug_test_mode": true, "debug_test_mode": true,
"drone": { "drone": {
"maxAcceleration": MAX_ACCELERATION, "onUpdateInterval": ON_UPDATE_INTERVAL,
"maxDeceleration": MAX_DECELERATION, "list": DRONE_LIST
"minSpeed": MIN_SPEED,
"speed": DEFAULT_SPEED,
"maxSpeed": MAX_SPEED,
"maxRoll": MAX_ROLL,
"minPitchAngle": MIN_PITCH,
"maxPitchAngle": MAX_PITCH,
"maxSinkRate": MAX_SINK_RATE,
"maxClimbRate": MAX_CLIMB_RATE,
"onUpdateInterval": ON_UPDATE_INTERVAL
}, },
"gameTime": SIMULATION_TIME, "gameTime": SIMULATION_TIME,
"simulation_speed": SIMULATION_SPEED, "simulation_speed": SIMULATION_SPEED,
...@@ -207,9 +193,13 @@ ...@@ -207,9 +193,13 @@
"draw_flight_path": DRAW, "draw_flight_path": DRAW,
"temp_flight_path": true, "temp_flight_path": true,
"log_drone_flight": LOG, "log_drone_flight": LOG,
"log_interval_time": LOG_TIME, "log_interval_time": LOG_TIME
"droneList": DRONE_LIST
}; };
Object.keys(FixedWingDroneAPI.FORM_VIEW).forEach(function (parameter) {
var field = FixedWingDroneAPI.FORM_VIEW[parameter];
game_parameters_json.drone[field.key] = field.default;
});
return gadget.declareGadget("babylonjs.gadget.html", return gadget.declareGadget("babylonjs.gadget.html",
{element: fragment, scope: 'simulator'}) {element: fragment, scope: 'simulator'})
.push(function () { .push(function () {
...@@ -259,7 +249,6 @@ ...@@ -259,7 +249,6 @@
var div = domsugar('div', { text: "CONSOLE LOG ENTRIES:" }), var div = domsugar('div', { text: "CONSOLE LOG ENTRIES:" }),
lines = result.console_log.split('\n'), lines = result.console_log.split('\n'),
line_nb, line_nb,
node,
test_log_node = document.querySelector('.test_log');; test_log_node = document.querySelector('.test_log');;
document.querySelector('.container').parentNode.appendChild(div); document.querySelector('.container').parentNode.appendChild(div);
function appendToTestLog(test_log_node, message) { function appendToTestLog(test_log_node, message) {
...@@ -283,4 +272,4 @@ ...@@ -283,4 +272,4 @@
}); });
}); });
}(window, rJS, domsugar, document, URLSearchParams, Blob)); }(window, rJS, domsugar, document, FixedWingDroneAPI));
\ No newline at end of file \ No newline at end of file
...@@ -75,7 +75,7 @@ ...@@ -75,7 +75,7 @@
</item> </item>
<item> <item>
<key> <string>default_reference</string> </key> <key> <string>default_reference</string> </key>
<value> <string>gadget_erp5_page_drone_simulator_test_page.js</string> </value> <value> <string>gadget_erp5_page_drone_simulator_fixed_wing_test_page.js</string> </value>
</item> </item>
<item> <item>
<key> <string>description</string> </key> <key> <string>description</string> </key>
...@@ -85,7 +85,7 @@ ...@@ -85,7 +85,7 @@
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>test_drone_simulator_flight_js</string> </value> <value> <string>test_drone_simulator_fixed_wing_flight_js</string> </value>
</item> </item>
<item> <item>
<key> <string>language</string> </key> <key> <string>language</string> </key>
...@@ -105,7 +105,7 @@ ...@@ -105,7 +105,7 @@
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
<value> <string>Drone Simulator Test Page JS</string> </value> <value> <string>Drone Simulator Fixed Wing Test Page JS</string> </value>
</item> </item>
<item> <item>
<key> <string>version</string> </key> <key> <string>version</string> </key>
...@@ -246,7 +246,7 @@ ...@@ -246,7 +246,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1015.64176.45813.63488</string> </value> <value> <string>1020.29326.20074.19694</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -266,7 +266,7 @@ ...@@ -266,7 +266,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1713428376.53</float> <float>1730738827.56</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -19,7 +19,10 @@ ...@@ -19,7 +19,10 @@
<script src="gadget_global.js" type="text/javascript"></script> <script src="gadget_global.js" type="text/javascript"></script>
<script src="domsugar.js" type="text/javascript"></script> <script src="domsugar.js" type="text/javascript"></script>
<script src="gadget_erp5_page_drone_simulator_test_page.js" type="text/javascript"></script> <!-- API scripts -->
<script src="gadget_erp5_page_drone_simulator_multicopterdrone.js" type="text/javascript"></script>
<script src="gadget_erp5_page_drone_simulator_multicopter_test_page.js" type="text/javascript"></script>
</head> </head>
<body> <body>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Web Page" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_Access_contents_information_Permission</string> </key>
<value>
<tuple>
<string>Anonymous</string>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Add_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Change_local_roles_Permission</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Modify_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_View_Permission</string> </key>
<value>
<tuple>
<string>Anonymous</string>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>content_md5</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>gadget_erp5_page_drone_simulator_multicopter_test_page.html</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>test_drone_simulator_multicopter_flight_html</string> </value>
</item>
<item>
<key> <string>language</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Web Page</string> </value>
</item>
<item>
<key> <string>short_title</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Drone Simulator Multicopter Test Page</string> </value>
</item>
<item>
<key> <string>version</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>document_publication_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>edit_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
<item>
<key> <string>processing_status_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAU=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>publish_alive</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <unicode>zope</unicode> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="DateTime" module="DateTime.DateTime"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1729873773.39</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>published_alive</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>edit</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <unicode>zope</unicode> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>1020.14910.8112.57787</string> </value>
</item>
<item>
<key> <string>state</string> </key>
<value> <string>current</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="DateTime" module="DateTime.DateTime"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1730736385.01</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="5" aka="AAAAAAAAAAU=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>detect_converted_file</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <unicode>zope</unicode> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_processing_state</string> </key>
<value> <string>converted</string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>0.0.0.0</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="DateTime" module="DateTime.DateTime"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1729873450.92</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
/*jslint indent: 2, maxlen: 100*/
/*global window, rJS, domsugar, document, MulticopterDroneAPI*/
(function (window, rJS, domsugar, document, MulticopterDroneAPI) {
"use strict";
var SIMULATION_SPEED = 100,
LOOP_INTERVAL = 1000 / 60,
ON_UPDATE_INTERVAL = LOOP_INTERVAL,
SIMULATION_TIME = 714 * LOOP_INTERVAL / 1000,
DEFAULT_SPEED = 5,
NUMBER_OF_DRONES = 1,
MIN_LAT = 45.6364,
MAX_LAT = 45.65,
MIN_LON = 14.2521,
MAX_LON = 14.2766,
HEIGHT = 100,
start_AMSL = 595,
INIT_LON = 14.2658,
INIT_LAT = 45.6412,
INIT_ALT = 0,
STEP = 2.3992831666911723e-06 / 16,
TAKEOFF_ALTITUDE = 7,
DEFAULT_SCRIPT_CONTENT =
'function assert(a, b, msg) {\n' +
' if (a === b) {\n' +
' console.log(msg + ": OK");\n' +
' } else {\n' +
' console.log(msg + ": FAIL");\n' +
' console.log(a, b);\n' +
' }\n' +
'}\n' +
'\n' +
'function distance(lat1, lon1, lat2, lon2) {\n' +
' var R = 6371e3, // meters\n' +
' la1 = lat1 * Math.PI / 180, // lat, lon in radians\n' +
' la2 = lat2 * Math.PI / 180,\n' +
' lo1 = lon1 * Math.PI / 180,\n' +
' lo2 = lon2 * Math.PI / 180,\n' +
' haversine_phi = Math.pow(Math.sin((la2 - la1) / 2), 2),\n' +
' sin_lon = Math.sin((lo2 - lo1) / 2),\n' +
' h = haversine_phi + Math.cos(la1) * Math.cos(la2) * sin_lon * sin_lon;\n' +
' return 2 * R * Math.asin(Math.sqrt(h));\n' +
'}\n' +
'\n' +
'function compare(coord1, coord2) {\n' +
' assert(coord1.latitude, coord2.latitude, "Latitude");\n' +
' assert(coord1.longitude, coord2.longitude, "Longitude");\n' +
' assert(coord1.altitude, coord2.altitude, "Altitude");\n' +
'}\n' +
'\n' +
'me.onStart = function (timestamp) {\n' +
' assert(me.getSpeed(), 0, "Initial speed");\n' +
' assert(me.getYaw(), 0, "Yaw angle");\n' +
' me.start_time = timestamp;\n' +
' me.takeOff();\n' +
' me.direction_set = false;\n' +
' me.interval_ckecked = false;\n' +
'};\n' +
'\n' +
'me.onUpdate = function (timestamp) {\n' +
' if (!me.interval_ckecked) {\n' +
' var time_interval = timestamp - me.start_time,\n' +
' expected_interval = ' + LOOP_INTERVAL + ';\n' +
' assert(time_interval.toFixed(4), expected_interval.toFixed(4), "Timestamp");\n' +
' assert(Date.now(), timestamp, "Date");\n' +
' me.interval_ckecked = true;\n' +
' }\n' +
' if (!me.isReadyToFly()) {\n' +
' return;\n' +
' } else {\n' +
' if (me.direction_set === false) {\n' +
' me.initialPosition = me.getCurrentPosition();\n' +
' me.initialPosition.altitude = me.initialPosition.altitude.toFixed(2);\n' +
' assert(me.initialPosition.altitude, (' + TAKEOFF_ALTITUDE + ').toFixed(2),\n' +
' "Altitude");\n' +
' me.direction_set = true;\n' +
' return me.setTargetCoordinates(\n' +
' me.initialPosition.latitude + 0.01,\n' +
' me.initialPosition.longitude,\n' +
' me.getAltitudeAbs(),\n' +
' ' + DEFAULT_SPEED + '\n' +
' );\n' +
' }\n' +
' }\n' +
' var current_position = me.getCurrentPosition(),\n' +
' realDistance = distance(\n' +
' me.initialPosition.latitude,\n' +
' me.initialPosition.longitude,\n' +
' me.getCurrentPosition().latitude,\n' +
' me.getCurrentPosition().longitude\n' +
' ).toFixed(8),\n' +
' expectedDistance = (me.getSpeed() * ' + LOOP_INTERVAL + ' / 1000).toFixed(8);\n' +
' assert(realDistance, expectedDistance, "Distance");\n' +
' current_position.latitude = current_position.latitude.toFixed(7);\n' +
' current_position.altitude = current_position.altitude.toFixed(2);\n' +
' compare(current_position, {\n' +
' latitude: (me.initialPosition.latitude + me.getSpeed() *' + STEP + ').toFixed(7),\n' +
' longitude: me.initialPosition.longitude,\n' +
' altitude: me.initialPosition.altitude\n' +
' });\n' +
'};',
DRAW = true,
LOG = true,
LOG_TIME = 1662.7915426540285,
DRONE_LIST = [],
LOGIC_FILE_LIST = [
'gadget_erp5_page_drone_simulator_logic.js',
'gadget_erp5_page_drone_simulator_fixedwingdrone.js',
'gadget_erp5_page_drone_simulator_dronelogfollower.js',
MulticopterDroneAPI.SCRIPT_NAME
];
rJS(window)
/////////////////////////////////////////////////////////////////
// Acquired methods
/////////////////////////////////////////////////////////////////
.declareAcquiredMethod("notifySubmitted", "notifySubmitted")
.allowPublicAcquisition('notifySubmit', function () {
return this.triggerSubmit();
})
.declareMethod("triggerSubmit", function () {
return this.element.querySelector('input[type="submit"]').click();
})
.onEvent('submit', function () {
var gadget = this;
return gadget.getDeclaredGadget('form_view')
.push(function (form_gadget) {
return form_gadget.getContent();
})
.push(function (input) {
gadget.runGame(input);
});
})
.declareMethod('render', function render() {
var gadget = this;
return gadget.getDeclaredGadget('form_view')
.push(function (form_gadget) {
return form_gadget.render({
erp5_document: {
"_embedded": {"_view": {
"my_script": {
"default": DEFAULT_SCRIPT_CONTENT,
"css_class": "",
"required": 1,
"editable": 1,
"key": "script",
"hidden": 0,
"type": "GadgetField",
"renderjs_extra": JSON.stringify({
"language": "en",
"portal_type": "Web Script",
"editor": "codemirror"
}),
"url": "gadget_editor.html"
}
}},
"_links": {
"type": {
name: ""
}
}
},
form_definition: {
group_list: [[
"bottom",
[["my_script"]]
]]
}
});
});
})
.declareJob('runGame', function runGame(options) {
var gadget = this, i,
fragment = gadget.element.querySelector('.simulator_div'),
game_parameters_json;
DRONE_LIST = [];
fragment = domsugar(gadget.element.querySelector('.simulator_div'),
[domsugar('div')]).firstElementChild;
for (i = 0; i < NUMBER_OF_DRONES; i += 1) {
DRONE_LIST[i] = {"id": i, "type": MulticopterDroneAPI.name,
"script_content": options.script};
}
game_parameters_json = {
"debug_test_mode": true,
"drone": {
"onUpdateInterval": ON_UPDATE_INTERVAL,
"list": DRONE_LIST
},
"gameTime": SIMULATION_TIME,
"simulation_speed": SIMULATION_SPEED,
"latency": {
"information": 0,
"communication": 0
},
"map": {
"min_lat": MIN_LAT,
"max_lat": MAX_LAT,
"min_lon": MIN_LON,
"max_lon": MAX_LON,
"height": HEIGHT,
"start_AMSL": start_AMSL
},
"initialPosition": {
"longitude": INIT_LON,
"latitude": INIT_LAT,
"altitude": INIT_ALT
},
"draw_flight_path": DRAW,
"temp_flight_path": true,
"log_drone_flight": LOG,
"log_interval_time": LOG_TIME
};
Object.keys(MulticopterDroneAPI.FORM_VIEW).forEach(function (parameter) {
var field = MulticopterDroneAPI.FORM_VIEW[parameter];
game_parameters_json.drone[field.key] = field.default;
});
return gadget.declareGadget("babylonjs.gadget.html",
{element: fragment, scope: 'simulator'})
.push(function () {
return gadget.getDeclaredGadget('form_view_babylonjs');
})
.push(function (form_gadget) {
return form_gadget.render({
erp5_document: {
"_embedded": {"_view": {
"my_babylonjs": {
"default": "",
"css_class": "",
"required": 0,
"editable": 1,
"key": "babylonjs",
"hidden": 0,
"type": "GadgetField",
"url": "babylonjs.gadget.html",
"sandbox": "public",
"renderjs_extra": '{"autorun": false, ' +
'"logic_file_list": ' + JSON.stringify(LOGIC_FILE_LIST) + ', ' +
'"game_parameters": ' + JSON.stringify(game_parameters_json) +
'}'
}
}},
"_links": {
"type": {
name: ""
}
}
},
form_definition: {
group_list: [[
"bottom",
[["my_babylonjs"]]
]]
}
});
})
.push(function () {
return gadget.getDeclaredGadget('form_view_babylonjs');
})
.push(function (form_gadget) {
return form_gadget.getContent();
})
.push(function (result) {
var div = domsugar('div', { text: "CONSOLE LOG ENTRIES:" }),
lines = result.console_log.split('\n'),
line_nb,
test_log_node = document.querySelector('.test_log');
document.querySelector('.container').parentNode.appendChild(div);
function appendToTestLog(test_log_node, message) {
var log_node = document.createElement("div"),
textNode = document.createTextNode(message);
log_node.appendChild(textNode);
test_log_node.appendChild(log_node);
}
for (line_nb = 0; line_nb < lines.length; line_nb += 1) {
if (lines[line_nb] !== 'TIMEOUT!') {
appendToTestLog(test_log_node, lines[line_nb]);
} else {
appendToTestLog(test_log_node, 'Timeout: OK');
return;
}
}
appendToTestLog(test_log_node, 'Timeout: FAILED');
}, function (error) {
return gadget.notifySubmitted({message: "Error: " + error.message,
status: 'error'});
});
});
}(window, rJS, domsugar, document, MulticopterDroneAPI));
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Web Script" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_Access_contents_information_Permission</string> </key>
<value>
<tuple>
<string>Anonymous</string>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Add_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Change_local_roles_Permission</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Modify_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_View_Permission</string> </key>
<value>
<tuple>
<string>Anonymous</string>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>content_md5</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>gadget_erp5_page_drone_simulator_multicopter_test_page.js</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>test_drone_simulator_multicopter_flight_js</string> </value>
</item>
<item>
<key> <string>language</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Web Script</string> </value>
</item>
<item>
<key> <string>short_title</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Drone Simulator Multicopter Test Page JS</string> </value>
</item>
<item>
<key> <string>version</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>document_publication_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>edit_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
<item>
<key> <string>processing_status_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAU=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>publish_alive</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <unicode>zope</unicode> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="DateTime" module="DateTime.DateTime"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1729871328.22</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>published_alive</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>edit</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <unicode>zope</unicode> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>1020.29316.53379.55108</string> </value>
</item>
<item>
<key> <string>state</string> </key>
<value> <string>current</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="DateTime" module="DateTime.DateTime"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1730738357.0</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="5" aka="AAAAAAAAAAU=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>detect_converted_file</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <unicode>zope</unicode> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_processing_state</string> </key>
<value> <string>converted</string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>0.0.0.0</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="DateTime" module="DateTime.DateTime"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1729871118.19</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment