diff --git a/conf/airframes/twinstar1.xml b/conf/airframes/twinstar1.xml
index 5003ab2fa6..182f6afebc 100644
--- a/conf/airframes/twinstar1.xml
+++ b/conf/airframes/twinstar1.xml
@@ -108,7 +108,6 @@
-
# Virtual AC
diff --git a/conf/control_panel.xml.example b/conf/control_panel.xml.example
index 51fc6d472e..049830ed1c 100644
--- a/conf/control_panel.xml.example
+++ b/conf/control_panel.xml.example
@@ -79,6 +79,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/conf/flight_plans/generic.xml b/conf/flight_plans/generic.xml
index 83a87003dd..581506665d 100644
--- a/conf/flight_plans/generic.xml
+++ b/conf/flight_plans/generic.xml
@@ -1,22 +1,42 @@
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
diff --git a/sw/airborne/gps.c b/sw/airborne/gps.c
index 06a3d436e0..100916b8bd 100644
--- a/sw/airborne/gps.c
+++ b/sw/airborne/gps.c
@@ -34,12 +34,13 @@
#include "estimator.h"
#include "ap_downlink.h"
#include "infrared.h"
+#include "nav.h"
uint16_t last_gps_msg_t; /** cputime of the last gps message */
void estimator_update_state_gps( void ) {
- float gps_east = gps_utm_east / 100. - NAV_UTM_EAST0;
- float gps_north = gps_utm_north / 100. - NAV_UTM_NORTH0;
+ float gps_east = gps_utm_east / 100. - nav_utm_east0;
+ float gps_north = gps_utm_north / 100. - nav_utm_north0;
float falt = gps_alt / 100.;
EstimatorSetPos(gps_east, gps_north, falt);
float fspeed = gps_gspeed / 100.;
diff --git a/sw/airborne/main_ap.c b/sw/airborne/main_ap.c
index b41689c4cf..a470d80d3f 100644
--- a/sw/airborne/main_ap.c
+++ b/sw/airborne/main_ap.c
@@ -77,7 +77,7 @@ uint8_t rc_settings_mode = RC_SETTINGS_MODE_NONE;
uint8_t fatal_error_nb = 0;
static const uint16_t version = 1;
-uint8_t pprz_mode = PPRZ_MODE_MANUAL;
+uint8_t pprz_mode = PPRZ_MODE_AUTO2;
uint8_t vertical_mode = VERTICAL_MODE_MANUAL;
uint8_t lateral_mode = LATERAL_MODE_MANUAL;
diff --git a/sw/airborne/nav.c b/sw/airborne/nav.c
index f524fef840..2335c01cdf 100644
--- a/sw/airborne/nav.c
+++ b/sw/airborne/nav.c
@@ -377,7 +377,6 @@ void nav_home(void) {
*/
void nav_update(void) {
compute_dist2_to_home();
-
auto_nav();
}
diff --git a/sw/ground_segment/cockpit/horizon.ml b/sw/ground_segment/cockpit/horizon.ml
index ec1b684fc6..2242bef1ec 100644
--- a/sw/ground_segment/cockpit/horizon.ml
+++ b/sw/ground_segment/cockpit/horizon.ml
@@ -1,3 +1,4 @@
+open Printf
open Latlong
let affine_pos_and_angle xw yw angle =
@@ -5,6 +6,7 @@ let affine_pos_and_angle xw yw angle =
let sin_a = sin angle in
[| cos_a ; sin_a ; ~-. sin_a; cos_a; xw ; yw |]
+let affine_pos xw yw = affine_pos_and_angle xw yw 0.
let arc = fun n r start stop ->
let s = (stop -. start) /. float (n-1) in
@@ -20,39 +22,82 @@ let floats_of_points = fun ps ->
done;
a
+let ruler = fun ?(index_on_right=false) ~text_props ~max ~scale ~w ~index_width ~step ~h root ->
+ let r = GnoCanvas.group root in
+ let height = scale *. float max in
+ let _ = GnoCanvas.rect ~x1:0. ~y1:(-.height) ~x2:w ~y2:height ~fill_color:"#808080" r in
+ for i = 0 to max/step do
+ let i = i * step in
+ let y = -. scale *. float i in
+ let text = Printf.sprintf "%d" i in
+ let _ = GnoCanvas.text ~text ~props:(text_props@[`ANCHOR `EAST]) ~y ~x:(w*.0.75) r in
+ let _ = GnoCanvas.line ~points:[|w*.0.8;y;w;y|] ~fill_color:"white" r in
+ let y = y -. float step /. 2. *. scale in
+ let _ = GnoCanvas.line ~points:[|w*.0.8;y;w;y|] ~fill_color:"white" r in
+ ()
+ done;
+ (** Yellow index *)
+ let _ = GnoCanvas.line ~points:[|0.;0.;w;0.|] ~fill_color:"yellow" root in
+ let s = index_width in
+ let idx = GnoCanvas.polygon ~points:[|0.;0.;-.s;s/.2.;-.s;-.s/.2.|] ~fill_color:"yellow" root in
+ if index_on_right then
+ idx#affine_absolute (affine_pos_and_angle w 0. pi);
+
+ (** Mask (bottom & top) *)
+ let _ = GnoCanvas.rect ~x1:0. ~y1:(-.height) ~x2:w ~y2:(-.h) ~fill_color:"black" root in
+ let _ = GnoCanvas.rect ~x1:0. ~y1:height ~x2:w ~y2:h ~fill_color:"black" root in
+ r
+
+
class h = fun ?packing size ->
let canvas = GnoCanvas.canvas ~aa:true ~width:size ~height:size ?packing () in
+ let _ =
+ canvas#set_center_scroll_region false;
+ in
+
let size = float size in
let size2 = size /. 2. in
+ let left_margin = size2 /. 10. in
let pitch_scale = fun pitch -> pitch *. size2 *. 2. in
+ let speed_scale = size2 /. 10. in
+ let alt_scale = size2 /. 50. in
+ let speed_width = size2/.5. in
+ let alt_width = size2/.2.5 in
+ let index_width = size2 /. 15. in
+
+ let xc = left_margin +. speed_width +. size2
+ and yc = size2*.1.1 in
+
+ let text_props = [`FONT "Sans 10"; `ANCHOR `CENTER; `FILL_COLOR "white"] in
let disc = GnoCanvas.group canvas#root in
let top = GnoCanvas.rect ~x1:(-.size2) ~y1:(-.size2*.5.) ~x2:size2 ~y2:0. ~fill_color:"#0099cb" disc
and bottom = GnoCanvas.rect ~x1:(-.size2) ~y1:0. ~x2:size2 ~y2:(size2*.5.) ~fill_color:"#986701" disc
- and line = GnoCanvas.line ~props:[`WIDTH_PIXELS 4] ~points:[|-.size2;0.;size2;0.|] ~fill_color:"white" disc in
+ and line = GnoCanvas.line ~props:[`WIDTH_PIXELS 4] ~points:[|-.size2;0.;size2;0.|] ~fill_color:"white" disc
+ and _ = GnoCanvas.line ~points:[|0.;-.size2;0.;size2|] ~fill_color:"white" disc
+ in
let grads = fun ?(text=false) n s a b ->
for i = 0 to n do
- let a = float i *. a in
- let y = pitch_scale ((Deg>>Rad)(a+.b)) in
+ let deg = float i *. a +. b in
+ let y = pitch_scale ((Deg>>Rad)deg) in
ignore (GnoCanvas.line ~points:[|-.s; y; s; y|] ~fill_color:"white" disc);
ignore (GnoCanvas.line ~points:[|-.s; -.y; s; -.y|] ~fill_color:"white" disc);
if text then
- let text = Printf.sprintf "-%d" (truncate a)
+ let text = Printf.sprintf "%d" (truncate deg)
and x = 2.*.s in
- ignore (GnoCanvas.text ~props:[`ANCHOR `CENTER; `FILL_COLOR "white"] ~text ~y ~x disc);
- ignore (GnoCanvas.text ~props:[`ANCHOR `CENTER; `FILL_COLOR "white"] ~text ~y ~x:(-.x) disc);
- let y = -. y
- and text = Printf.sprintf "-%d" (truncate a) in
- ignore (GnoCanvas.text ~props:[`ANCHOR `CENTER; `FILL_COLOR "white"] ~text ~y ~x disc);
- ignore (GnoCanvas.text ~props:[`ANCHOR `CENTER; `FILL_COLOR "white"] ~text ~y ~x:(-.x) disc);
+ ignore (GnoCanvas.text ~props:text_props ~text ~y:(-.y) ~x disc);
+ ignore (GnoCanvas.text ~props:text_props ~text ~y:(-.y) ~x:(-.x) disc);
+ let text = "-"^text in
+ ignore (GnoCanvas.text ~props:text_props ~text ~y ~x disc);
+ ignore (GnoCanvas.text ~props:text_props ~text ~y ~x:(-.x) disc);
done in
let _ =
grads 10 (size2/.10.) 5. 2.5;
grads 5 (size2/.7.) 10. 5.;
grads ~text:true 5 (size2/.5.) 10. 10. in
- let mask = GnoCanvas.group canvas#root in
+ let mask = GnoCanvas.group ~x:xc ~y:yc canvas#root in
let center = GnoCanvas.ellipse ~x1:(-3.) ~y1:(-.3.) ~x2:3. ~y2:3. ~fill_color:"black" mask in
let pi6 = pi/.6. in
let n = 20 in
@@ -68,9 +113,60 @@ class h = fun ?packing size ->
ignore (GnoCanvas.polygon ~fill_color:"black" ~points mask);
let s = size2/. 5. in
ignore (GnoCanvas.line ~props:[`WIDTH_PIXELS 4] ~points:[|-.x;0.;-.x-.s;0.;-.x-.s;s|] ~fill_color:"black" mask);
- ignore (GnoCanvas.line ~props:[`WIDTH_PIXELS 4] ~points:[|x;0.;x+.s;0.;x+.s;s|] ~fill_color:"black" mask) in
+ ignore (GnoCanvas.line ~props:[`WIDTH_PIXELS 4] ~points:[|x;0.;x+.s;0.;x+.s;s|] ~fill_color:"black" mask);
+
+ (* Top and bottom graduations *)
+ let g = fun a ->
+ let l = GnoCanvas.line~props:[`WIDTH_PIXELS 2] ~fill_color:"white" ~points:[|0.;-.size2;0.;-.1.2*.size2|] mask in
+ l#affine_relative (affine_pos_and_angle 0. 0. ((Deg>>Rad)a)) in
+ for i = 0 to 4 do
+ let a = float (i*10) in
+ g a; g (-.a)
+ done;
+ let _30 = fun a ->
+ let t = GnoCanvas.text ~text:"30" ~props:text_props ~x:0. ~y:(-1.1*.size2) mask in
+ t#affine_relative (affine_pos_and_angle 0. 0. ((Deg>>Rad)a)) in
+ _30 30.; _30 (-30.)
+ in
+
+ let speed =
+ let g = GnoCanvas.group ~x:left_margin ~y:yc canvas#root in
+ let r = ruler ~text_props ~index_on_right:true ~max:50 ~scale:speed_scale ~w:speed_width ~step:2 ~index_width ~h:(0.75*.size2) g in
+ let mx =
+ GnoCanvas.text ~x:(speed_width/.2.) ~y:(-0.85*.size2) ~props:text_props g
+ and mi =
+ GnoCanvas.text ~x:(speed_width/.2.) ~y:(0.80*.size2) ~props:text_props g in
+ mx#set [`FILL_COLOR "yellow"];
+ mi#set [`FILL_COLOR "yellow"];
+ r, mi, mx
+
+ and alt =
+ let g = GnoCanvas.group ~x:(xc+.size2) ~y:yc canvas#root in
+ ruler ~text_props ~max:3000 ~scale:alt_scale ~w:alt_width ~step:10
+ ~index_width ~h:(0.75*.size2) g
+ in
object (self)
- method draw = fun roll pitch ->
- disc#affine_absolute (affine_pos_and_angle 0. (pitch_scale pitch) (-.roll))
+ method set_attitude = fun roll pitch ->
+ disc#affine_absolute (affine_pos_and_angle xc (yc+.pitch_scale pitch) (-.roll))
+
+ val mutable max_speed = 0.
+ val mutable min_speed = max_float
+ method set_speed = fun (s:float) ->
+ let (r, mi, mx) = speed in
+ r#affine_absolute (affine_pos 0. (speed_scale*.s));
+ min_speed <- min min_speed s;
+ max_speed <- max max_speed s;
+ mi#set [`TEXT (sprintf "%.1f" min_speed)];
+ mx#set [`TEXT (sprintf "%.1f" max_speed)]
+ initializer
+ let (r, _, _) = speed in
+ ignore (r#connect#event (function
+ `BUTTON_PRESS ev ->
+ max_speed <- 0.; min_speed <- max_float; true
+ | _ -> false))
+
+ method set_alt = fun (s:float) ->
+ alt#affine_absolute (affine_pos 0. (alt_scale*.s))
+
end
diff --git a/sw/ground_segment/cockpit/map2d.ml b/sw/ground_segment/cockpit/map2d.ml
index 9e0b8f061b..5948338bd6 100644
--- a/sw/ground_segment/cockpit/map2d.ml
+++ b/sw/ground_segment/cockpit/map2d.ml
@@ -32,6 +32,36 @@ open Latlong
let float_attr = fun xml a -> float_of_string (ExtXml.attrib xml a)
let int_attr = fun xml a -> int_of_string (ExtXml.attrib xml a)
+let pvect (x1,y1) (x2,y2) = x1*.y2-.y1*.x2
+
+let angle (x1,y1) (x2,y2) (x3,y3) =
+ pvect (x3-.x2, y3-.y2) (x1-.x2,y1-.y2)
+
+let rec n_first n = function
+ [] -> []
+ | x::xs -> if n > 0 then x::n_first (n-1) xs else []
+
+
+let discretise = fun n l ->
+ match l with
+ [] -> l
+ | first::ps ->
+ match List.rev l with
+ [] -> failwith "impossible"
+ | last::_ ->
+ let rec angles i previous = function
+ [] -> failwith ""
+ | [p1] -> [(angle first p1 previous, i), p1]
+ | p1::p2::ps ->
+ ((angle p2 p1 previous, i), p1)::angles (i+1) p1 (p2::ps) in
+ let l = angles 0 last l in
+ let l = List.sort (fun x y -> compare x y) l in
+ List.map snd (n_first n l)
+
+let rec list_casso x = function
+ [] -> raise Not_found
+ | (a,b)::abs -> if x = b then a else list_casso x abs
+
let soi = string_of_int
let sof = string_of_float
@@ -50,10 +80,10 @@ let _ =
let fp_example = path_fps // "example.xml"
let speech = ref false
-
let ign = ref false
-
let get_bdortho = ref ""
+let auto_center_new_ac = ref false
+let no_alarm = ref false
let say = fun s ->
if !speech then
@@ -178,31 +208,28 @@ let map_from_region = fun (geomap:G.widget) () ->
(************ Strip handling ***********************************************)
module Strip = struct
type t = {
- ac_id: string;
gauge: GRange.progress_bar ;
labels: (string * (GBin.event_box * GMisc.label)) list
}
- let panel = Hashtbl.create 3
-
let pad = 4
let i2s = string_of_int
let labels_name = [|
[| "AP" ; "alt" ; "->" |]; [| "RC"; "climb"; "/" |]; [| "GPS"; "speed"; "" |];
- [| "settings" ; "throttle"; "rate" |]; [| ""; "wind"; "dir" |];
+ [| "settings" ; "throttle"; "" |]
|]
let labels_print = [|
[| "AP" ; "alt" ; "->" |]; [| "RC"; "climb"; "->" |]; [| "GPS"; "speed"; "" |];
- [| "CAL" ; "throttle"; "rate" |]; [| ""; "wind"; "dir" |];
+ [| "CAL" ; "throttle"; "" |]
|]
let gen_int = let i = ref (-1) in fun () -> incr i; !i
- let rows = Array.length labels_name
+ let rows = Array.length labels_name + 1
(** add a strip to the panel *)
- let add (widget: GPack.table) ac_id config color =
+ let add (widget: GPack.table) config color select center_ac commit_moves =
(* number of the strip *)
let strip_number = gen_int () in
if strip_number > 1 then widget#set_rows strip_number;
@@ -220,16 +247,19 @@ module Strip = struct
let plane_color = GBin.event_box ~width:10 ~height:10 ~packing:(strip#attach ~top:0 ~left: 1) () in
plane_color#coerce#misc#modify_bg [`NORMAL, `NAME color];
+ ignore (plane_color#event#connect#button_press ~callback:(fun _ -> select (); true));
+ let h = GPack.hbox ~packing:plane_color#add () in
+ let ft = GMisc.label ~text: "00:00:00" ~packing:h#add () in
+ ft#set_width_chars 8;
+ add_label ("flight_time_value") (plane_color, ft);
+ let block_name = GMisc.label ~text: "______" ~packing:h#add () in
+ add_label ("block_name_value") (plane_color, block_name);
+
(* battery and flight time *)
- let bat_table = GPack.table ~rows: 2 ~columns: 1 ~packing: (strip#attach ~top:1 ~left:0) () in
- let pb = GRange.progress_bar ~orientation: `BOTTOM_TO_TOP ~packing: (bat_table#attach ~top:0 ~left:0) () in
+ let pb = GRange.progress_bar ~orientation: `BOTTOM_TO_TOP ~packing:(strip#attach ~top:1 ~left:0) () in
pb#coerce#misc#modify_fg [`PRELIGHT, `NAME "green"];
- pb#coerce#misc#modify_font_by_name "sans 18";
- let eb = GBin.event_box ~packing: (bat_table#attach ~top:1 ~left:0) () in
- let ft = GMisc.label ~text: "00:00:00" ~packing:eb#add () in
- ft#set_width_chars 8;
- add_label ("flight_time_value") (eb, ft);
+ pb#coerce#misc#modify_font_by_name "sans 12";
let left_box = GPack.table ~rows ~columns: 6 ~col_spacings: 5
~packing: (strip#attach ~top: 1 ~left: 1) () in
@@ -245,10 +275,12 @@ module Strip = struct
add_label (s^"_value") (eb, lvalue);
) a
) labels_name;
- Hashtbl.add panel ac_id {ac_id = ac_id; gauge=pb ; labels= (!strip_labels)}
+ let b = GButton.button ~label:"Center A/C" ~packing:(left_box#attach ~top:4 ~left:0 ~right:2) () in
+ ignore(b#connect#clicked ~callback:center_ac);
+ let b = GButton.button ~label:"Commit Moves" ~packing:(left_box#attach ~top:4 ~left:2 ~right:4) () in
+ ignore (b#connect#clicked ~callback:commit_moves);
+ {gauge=pb ; labels= (!strip_labels)}
- (** find an aircraft in the list of aircraft *)
- let find ac_id = Hashtbl.find panel ac_id
(** set a label *)
let set_label strip name value =
@@ -373,8 +405,8 @@ module Edit = struct
let close_fp = fun () ->
match !current_fp with
None -> () (* Nothing to close *)
- | Some (fp, _filename) ->
- fp#destroy ();
+ | Some (_fp, _filename, window) ->
+ window#destroy ();
current_fp := None
let load_xml_fp = fun geomap accel_group ?(xml_file=path_fps) xml ->
@@ -386,7 +418,7 @@ module Edit = struct
window#add_accel_group accel_group;
window#show();
ignore (window#connect#destroy ~callback:close_fp);
- current_fp := Some (fp,xml_file);
+ current_fp := Some (fp,xml_file, window);
fp
let labelled_entry = fun ?width_chars text value h ->
@@ -455,14 +487,14 @@ module Edit = struct
None ->
GToolbox.message_box "Error" "Load a flight plan first";
failwith "create_wp"
- | Some (fp,_) ->
+ | Some (fp,_,_) ->
fp#add_waypoint geo
let save_fp = fun () ->
match !current_fp with
None -> () (* Nothing to save *)
- | Some (fp, filename) ->
+ | Some (fp, filename,_) ->
match GToolbox.select_file ~title:"Save Flight Plan" ~filename () with
None -> ()
| Some file ->
@@ -479,7 +511,7 @@ module Edit = struct
(** Calibration of chosen image (requires a dummy flight plan) *)
let calibrate_map = fun (geomap:G.widget) accel_group () ->
match !current_fp with
- | Some (_fp,_) -> GToolbox.message_box "Error" "Close current flight plan before calibration"
+ | Some (_fp,_,_) -> GToolbox.message_box "Error" "Close current flight plan before calibration"
| None ->
match GToolbox.select_file ~filename:default_path_maps ~title:"Open Image" () with
None -> ()
@@ -626,7 +658,7 @@ module Edit = struct
begin
match !current_fp with
None -> ()
- | Some (fp, _) ->
+ | Some (fp, _,_) ->
fp#insert_path (List.map (fun (wp,_,_,_,r) -> (wp, r)) (List.rev ! !path));
end;
path := ref []
@@ -734,10 +766,16 @@ module Live = struct
ir_page : Pages.infrared;
gps_page : Pages.gps;
pfd_page : Pages.pfd;
- settings_page : Pages.settings option
+ misc_page : Pages.misc;
+ settings_page : Pages.settings option;
+ strip : Strip.t;
+ mutable first_pos : bool
}
let live_aircrafts = Hashtbl.create 3
+ let get_ac = fun vs ->
+ let ac_id = Pprz.string_assoc "ac_id" vs in
+ Hashtbl.find live_aircrafts ac_id
let aircraft_pos_msg = fun track wgs84 heading altitude speed climb ->
let h =
@@ -814,10 +852,12 @@ module Live = struct
(Xml.children stages);
List.sort compare !blocks
- let menu_entry_of_block = fun ac (id, name) ->
- let send_msg = fun () ->
- Ground_Pprz.message_send "map2d" "JUMP_TO_BLOCK"
- ["ac_id", Pprz.String ac; "block_id", Pprz.Int id] in
+ let jump_to_block = fun ac_id id ->
+ Ground_Pprz.message_send "map2d" "JUMP_TO_BLOCK"
+ ["ac_id", Pprz.String ac_id; "block_id", Pprz.Int id]
+
+ let menu_entry_of_block = fun ac_id (id, name) ->
+ let send_msg = fun () -> jump_to_block ac_id id in
`I (name, send_msg)
let reset_waypoints = fun fp () ->
@@ -853,7 +893,8 @@ module Live = struct
let track = new MapTrack.track ~name ~color:color geomap in
- ignore (ac_menu_fact#add_item "Center A/C" ~callback:(center geomap track));
+ let center_ac = center geomap track in
+ ignore (ac_menu_fact#add_item "Center A/C" ~callback:center_ac);
ignore (ac_menu_fact#add_item "Clear Track" ~callback:(fun () -> track#clear_map2D));
ignore (ac_menu_fact#add_item "Resize Track" ~callback:(fun () -> resize_track ac_id track));
@@ -861,10 +902,12 @@ module Live = struct
let jump_block_entries = List.map (menu_entry_of_block ac_id) blocks in
+ let commit_moves = fun () ->
+ commit_changes ac_id in
let sm = ac_menu_fact#add_submenu "Datalink" in
let dl_menu = [
`M ("Jump to block", jump_block_entries);
- `I ("Commit Moves", (fun () -> commit_changes ac_id));
+ `I ("Commit Moves", commit_moves);
`I ("Event 1", (fun () -> send_event ac_id 1));
`I ("Event 2", (fun () -> send_event ac_id 2))] in
@@ -903,6 +946,11 @@ module Live = struct
~packing: (ac_notebook#append_page ~tab_label: pfd_label#coerce) () in
let pfd_page = new Pages.pfd pfd_frame in
+ let misc_label = GMisc.label ~text: "Misc" () in
+ let misc_frame = GBin.frame ~shadow_type: `NONE
+ ~packing: (ac_notebook#append_page ~tab_label:misc_label#coerce) () in
+ let misc_page = new Pages.misc ~packing:misc_frame#add misc_frame in
+
let settings_page =
try
let xml_settings = Xml.children (ExtXml.child fp_xml "dl_settings") in
@@ -916,8 +964,18 @@ module Live = struct
with
_ -> None in
- fp#hide ();
+ fp#connect_activated (fun node ->
+ if XmlEdit.tag node = "block" then
+ let block = XmlEdit.attrib node "name" in
+ let id = list_casso block blocks in
+ jump_to_block ac_id id);
ignore (reset_wp_menu#connect#activate (reset_waypoints fp));
+
+ let select_this_tab =
+ let n = fp_notebook#page_num ac_frame#coerce in
+ fun () -> fp_notebook#goto_page n in
+
+ let strip = Strip.add strip_table config color select_this_tab center_ac commit_moves in
Hashtbl.add live_aircrafts ac_id { track = track; color = color;
fp_group = fp ; config = config ;
fp = fp_xml; ac_name = name;
@@ -926,9 +984,10 @@ module Live = struct
ir_page = ir_page;
gps_page = gps_page;
pfd_page = pfd_page;
- settings_page = settings_page
- };
- ignore (Strip.add strip_table ac_id config color)
+ misc_page = misc_page;
+ settings_page = settings_page;
+ strip = strip; first_pos = true
+ }
(** Bind to message while catching all the esceptions of the callback *)
let safe_bind = fun msg cb ->
@@ -955,46 +1014,32 @@ module Live = struct
end
let get_wind_msg = fun sender vs ->
- try
- let ac_strip = Strip.find (Pprz.string_assoc "ac_id" vs) in
- let set_label = fun label_name field_name ->
- Strip.set_label ac_strip label_name
- (Printf.sprintf "%.1f" (Pprz.float_assoc field_name vs))
- in
- set_label "wind" "wspeed";
- set_label "dir" "dir"
- with
- Not_found -> ()
+ let ac = get_ac vs in
+ let value = fun field_name -> sprintf "%.1f" (Pprz.float_assoc field_name vs) in
+ ac.misc_page#set_wind_speed (value "wspeed");
+ ac.misc_page#set_wind_dir (value "dir")
let get_fbw_msg = fun sender vs ->
- try
- let ac_strip = Strip.find (Pprz.string_assoc "ac_id" vs) in
- let status = Pprz.string_assoc "rc_status" vs in
- Strip.set_label ac_strip "RC" status;
- Strip.set_color ac_strip "RC"
- (match status with
- "LOST" -> "orange"
+ let ac = get_ac vs in
+ let status = Pprz.string_assoc "rc_status" vs in
+ Strip.set_label ac.strip "RC" status;
+ Strip.set_color ac.strip "RC"
+ (match status with
+ "LOST" -> "orange"
| "REALLY_LOST" -> "red"
| _ -> "white")
- with
- Not_found -> ()
+
let get_engine_status_msg = fun sender vs ->
- try
- let ac_strip = Strip.find (Pprz.string_assoc "ac_id" vs) in
- Strip.set_label ac_strip "throttle"
- (string_of_float (Pprz.float_assoc "throttle" vs));
- Strip.set_bat ac_strip (Pprz.float_assoc "bat" vs)
- with
- Not_found -> ()
+ let ac = get_ac vs in
+ Strip.set_label ac.strip "throttle"
+ (string_of_float (Pprz.float_assoc "throttle" vs));
+ Strip.set_bat ac.strip (Pprz.float_assoc "bat" vs)
let get_if_calib_msg = fun sender vs ->
- try
- let ac_strip = Strip.find (Pprz.string_assoc "ac_id" vs) in
- Strip.set_label ac_strip "settings" (Pprz.string_assoc "if_mode" vs)
- with
- Not_found -> ()
+ let ac = get_ac vs in
+ Strip.set_label ac.strip "settings" (Pprz.string_assoc "if_mode" vs)
let listen_wind_msg = fun () ->
safe_bind "WIND" get_wind_msg
@@ -1038,19 +1083,23 @@ module Live = struct
end
- let listen_flight_params = fun () ->
+ let listen_flight_params = fun geomap ->
let get_fp = fun _sender vs ->
- let ac_id = Pprz.string_assoc "ac_id" vs in
- let ac_strip = Strip.find ac_id in
- let ac = Hashtbl.find live_aircrafts ac_id in
+ let ac = get_ac vs in
let pfd_page = ac.pfd_page in
pfd_page#set_roll (Pprz.float_assoc "roll" vs);
pfd_page#set_pitch (Pprz.float_assoc "pitch" vs);
pfd_page#set_alt (Pprz.float_assoc "alt" vs);
pfd_page#set_climb (Pprz.float_assoc "climb" vs);
+ pfd_page#set_speed (Pprz.float_assoc "speed" vs);
let a = fun s -> Pprz.float_assoc s vs in
let wgs84 = { posn_lat = (Deg>>Rad)(a "lat"); posn_long = (Deg>>Rad)(a "long") } in
aircraft_pos_msg ac.track wgs84 (a "course") (a "alt") (a "speed") (a "climb");
+ if !auto_center_new_ac && ac.first_pos then begin
+ center geomap ac.track ();
+ ac.first_pos <- false
+ end;
+
let set_label lbl_name field_name =
let s =
if (a field_name) < 0.
@@ -1059,7 +1108,7 @@ module Live = struct
else
Printf.sprintf "%.1f" (a field_name)
in
- Strip.set_label ac_strip lbl_name s
+ Strip.set_label ac.strip lbl_name s
in
set_label "alt" "alt";
set_label "speed" "speed";
@@ -1068,9 +1117,7 @@ module Live = struct
safe_bind "FLIGHT_PARAM" get_fp;
let get_ns = fun _sender vs ->
- let ac_id = Pprz.string_assoc "ac_id" vs in
- let ac_strip = Strip.find ac_id in
- let ac = Hashtbl.find live_aircrafts ac_id in
+ let ac = get_ac vs in
let a = fun s -> Pprz.float_assoc s vs in
let wgs84 = { posn_lat = (Deg>>Rad)(a "target_lat"); posn_long = (Deg>>Rad)(a "target_long") } in
carrot_pos_msg ac.track wgs84;
@@ -1080,9 +1127,10 @@ module Live = struct
let b = String.sub b 0 (min 10 (String.length b)) in
highlight_fp ac cur_block cur_stage;
let set_label = fun l f ->
- Strip.set_label ac_strip l (Printf.sprintf "%.1f" (Pprz.float_assoc f vs)) in
+ Strip.set_label ac.strip l (Printf.sprintf "%.1f" (Pprz.float_assoc f vs)) in
set_label "->" "target_alt";
- set_label "/" "target_climb"
+ set_label "/" "target_climb";
+ Strip.set_label ac.strip "block_name" b
in
safe_bind "NAV_STATUS" get_ns;
@@ -1118,25 +1166,22 @@ module Live = struct
let get_ap_status = fun _sender vs ->
- let ac_id = Pprz.string_assoc "ac_id" vs in
-
- let ac_strip = Strip.find ac_id in
- let ac = Hashtbl.find live_aircrafts ac_id in
+ let ac = get_ac vs in
ap_status_msg ac.track ( float_of_int (Pprz.int32_assoc "flight_time" vs ));
let ap_mode = Pprz.string_assoc "ap_mode" vs in
if ap_mode <> ac.last_ap_mode then begin
say (sprintf "%s, %s" ac.ac_name ap_mode);
ac.last_ap_mode <- ap_mode
end;
- Strip.set_label ac_strip "AP" (Pprz.string_assoc "ap_mode" vs);
- Strip.set_color ac_strip "AP" (if ap_mode="HOME" then "red" else "white");
+ Strip.set_label ac.strip "AP" (Pprz.string_assoc "ap_mode" vs);
+ Strip.set_color ac.strip "AP" (if ap_mode="HOME" then "red" else "white");
let gps_mode = Pprz.string_assoc "gps_mode" vs in
- Strip.set_label ac_strip "GPS" gps_mode;
- Strip.set_color ac_strip "GPS" (if gps_mode<>"3D" then "red" else "white");
+ Strip.set_label ac.strip "GPS" gps_mode;
+ Strip.set_color ac.strip "GPS" (if gps_mode<>"3D" then "red" else "white");
let ft =
let t = Int32.to_int (Int32.of_string (Pprz.string_assoc "flight_time" vs)) in
Printf.sprintf "%02d:%02d:%02d" (t / 3600) ((t mod 3600) / 60) ((t mod 3600) mod 60) in
- Strip.set_label ac_strip "flight_time" ft
+ Strip.set_label ac.strip "flight_time" ft
in
safe_bind "AP_STATUS" get_ap_status;
@@ -1149,13 +1194,14 @@ module Live = struct
(** Not_found catched by safe_bind *)
let wp_id = Pprz.int_assoc "wp_id" vs in
let a = fun s -> Pprz.float_assoc s vs in
- let geo = { posn_lat = (Deg>>Rad)(a "lat"); posn_long = (Deg>>Rad)(a "long") } in
+ let geo = { posn_lat = (Deg>>Rad)(a "lat"); posn_long = (Deg>>Rad)(a "long") }
+ and altitude = a "alt" in
(** No indexed access to waypoints: iter and compare: *)
List.iter (fun w ->
let (i, w) = ac.fp_group#index w in
if i = wp_id then begin
- if not w#moved then w#set geo;
+ if not w#moved then w#set ~altitude ~update:true geo;
raise Exit (** catched by safe_bind *)
end)
ac.fp_group#waypoints
@@ -1218,7 +1264,7 @@ end (** module Live *)
let keys_help = fun () ->
GToolbox.message_box ~title:"Keys" ~ok:"Close"
"Zoom: Mouse Wheel, PgUp, PgDown\n\
- Pan: Shift Middle, Arrows\n\
+ Pan: Left, Arrows\n\
Load Map Tile: Right\n\
Select Region: Shift-Left + Drag\n\
Create Waypoint: Ctrl-Left\n\
@@ -1277,6 +1323,7 @@ let _main =
and maximize = ref false
and projection= ref G.UTM
and auto_ortho = ref false
+ and mplayer = ref ""
and plugin_window = ref "" in
let options =
[ "-b", Arg.String (fun x -> ivy_bus := x), "Bus\tDefault is 127.255.255.25:2010";
@@ -1284,12 +1331,16 @@ let _main =
"-ref", Arg.Set_string geo_ref, "Geographic ref (default '')";
"-zoom", Arg.Set_float zoom, "Initial zoom";
"-center", Arg.Set_string center, "Initial map center";
+ "-center_ac", Arg.Set auto_center_new_ac, "Centers the map on any new A/C";
"-plugin", Arg.Set_string plugin_window, "External X application (launched the id of the plugin window as argument)";
+ "-mplayer", Arg.Set_string mplayer, "Launch mplayer with the given argument as X plugin";
"-mercator", Arg.Unit (fun () -> projection:=G.Mercator),"Switch to (Google Maps) Mercator projection";
"-lambertIIe", Arg.Unit (fun () -> projection:=G.LambertIIe),"Switch to LambertIIe projection";
"-ign", Arg.String (fun s -> ign:=true; IGN.data_path := s), "IGN tiles path";
"-ortho", Arg.Set_string get_bdortho, "IGN tiles path";
+ "-no_alarm", Arg.Set no_alarm, "Disables alarm page";
"-auto_ortho", Arg.Set auto_ortho, "IGN tiles path";
+ "-google_fill", Arg.Set GM.auto, "Google maps auto fill";
"-speech", Arg.Set speech, "Speech";
"-m", Arg.String (fun x -> map_files := x :: !map_files), "Map description file"] in
Arg.parse (options)
@@ -1304,7 +1355,7 @@ let _main =
IGN.cache_path := var_maps_path;
(** window for map2d **)
- let window = GWindow.window ~title: "Map2d" ~border_width:1 ~width:1024 ~height:768 () in
+ let window = GWindow.window ~title: "Map2d" ~border_width:1 ~width:1024 ~height:750 () in
if !maximize then
window#maximize ();
let vbox= GPack.vbox ~packing: window#add () in
@@ -1317,7 +1368,7 @@ let _main =
ignore (window#connect#destroy ~callback:quit);
ignore (vertical_situation#connect#destroy ~callback:quit);
- let geomap = new G.widget ~projection:!projection () in
+ let geomap = new G.widget ~height:500 ~projection:!projection () in
let menu_fact = new GMenu.factory geomap#file_menu in
let accel_group = menu_fact#accel_group in
@@ -1368,7 +1419,7 @@ let _main =
ignore (geomap#factory#add_separator ());
let paned = GPack.paned ~show:true `VERTICAL ~packing:(vbox#pack ~expand:true) () in
- let frame1 = GPack.vbox ~height:600 () in
+ let frame1 = GPack.vbox () in
paned#pack1 ~shrink:true (*** ~expand:true ***) frame1#coerce;
let hpaned = GPack.paned ~show:true `HORIZONTAL ~packing:paned#add2 () in
@@ -1387,9 +1438,12 @@ let _main =
let hpaned3 = GPack.paned ~show:true `HORIZONTAL ~packing:hpaned2#add2 () in
(** Alerts text frame *)
- let alert_page = GBin.frame ~packing:hpaned3#add1 () in
+ let packing = if !no_alarm then fun _ -> () else hpaned3#add1 in
+ let alert_page = GBin.frame ~packing () in
let my_alert = new Pages.alert alert_page in
+ if !mplayer <> "" then
+ plugin_window := sprintf "mplayer -nomouseinput '%s' -wid " !mplayer;
if !plugin_window <> "" then begin
let plugin_width=400 and plugin_height=300 in
let frame2 = GPack.vbox ~width:plugin_width () in
@@ -1417,7 +1471,7 @@ let _main =
Live.safe_bind "NEW_AIRCRAFT" (fun _sender vs -> Live.one_new_ac geomap fp_notebook (Pprz.string_assoc "ac_id" vs));
(** Listen for all messages on ivy *)
- Live.listen_flight_params ();
+ Live.listen_flight_params geomap;
Live.listen_wind_msg ();
Live.listen_fbw_msg ();
Live.listen_engine_status_msg ();
@@ -1441,8 +1495,8 @@ let _main =
(** Center the map as required *)
if !center <> "" then begin
- try geomap#center (Latlong.of_string !center) with
- _ -> GToolbox.message_box "Error" (sprintf "Cannot center at '%s' (no ref ?)" !center)
+ set_georef_if_none geomap (Latlong.of_string !center);
+ geomap#center (Latlong.of_string !center)
end;
say "Welcome to paparazzi";
diff --git a/sw/ground_segment/cockpit/pages.ml b/sw/ground_segment/cockpit/pages.ml
index 7a95a5ca42..543810410f 100644
--- a/sw/ground_segment/cockpit/pages.ml
+++ b/sw/ground_segment/cockpit/pages.ml
@@ -130,14 +130,41 @@ object (this)
method set_roll r =
roll <- r;
- horizon#draw ((Deg>>Rad)roll) ((Deg>>Rad)pitch)
+ horizon#set_attitude ((Deg>>Rad)roll) ((Deg>>Rad)pitch)
method set_pitch p =
pitch <- p;
- horizon#draw ((Deg>>Rad)roll) ((Deg>>Rad)pitch)
- method set_alt (a:float) = ()
+ horizon#set_attitude ((Deg>>Rad)roll) ((Deg>>Rad)pitch)
+ method set_alt (a:float) = horizon#set_alt a
method set_climb (c:float) = ()
+ method set_speed (c:float) = horizon#set_speed c
end
+
+(*****************************************************************************)
+(* Misc page *)
+(*****************************************************************************)
+class misc ~packing (widget: GBin.frame) =
+ let table = GPack.table
+ ~rows: 2
+ ~columns: 2
+ ~row_spacings: 5
+ ~col_spacings: 40
+ ~packing
+ () in
+ let label = fun text i j ->GMisc.label ~text ~packing:(table#attach ~top:i ~left:j) () in
+ let _init =
+ ignore (label "Wind speed" 0 0);
+ ignore (label "Wind direction" 1 0) in
+ let wind_speed = label "" 0 1
+ and wind_dir = label "" 1 1 in
+ object
+ method set_wind_speed s = wind_speed#set_text s
+ method set_wind_dir s = wind_dir#set_text s
+ end
+
+(*****************************************************************************)
+(* Dataling settings paged *)
+(*****************************************************************************)
class settings = fun xml_settings callback ->
let sw = GBin.scrolled_window ~hpolicy:`AUTOMATIC ~vpolicy:`AUTOMATIC () in
let vbox = GPack.vbox ~packing:sw#add_with_viewport () in
diff --git a/sw/ground_segment/cockpit/pages.mli b/sw/ground_segment/cockpit/pages.mli
index 07ebf7c5e0..2573fbaaa6 100644
--- a/sw/ground_segment/cockpit/pages.mli
+++ b/sw/ground_segment/cockpit/pages.mli
@@ -15,6 +15,7 @@ class gps : GBin.frame ->
end
class pfd : GBin.frame ->
object
+ method set_speed : float -> unit
method set_alt : float -> unit
method set_climb : float -> unit
method set_pitch : float -> unit
@@ -26,3 +27,10 @@ class settings : Xml.xml list -> (int -> float -> unit) ->
method set : int -> float -> unit
method widget : GObj.widget
end
+class misc :
+ packing:(GObj.widget -> unit) ->
+ GBin.frame ->
+ object
+ method set_wind_dir : string -> unit
+ method set_wind_speed : string -> unit
+ end
diff --git a/sw/ground_segment/tmtc/server.ml b/sw/ground_segment/tmtc/server.ml
index ad5c2722bc..2e857ee246 100644
--- a/sw/ground_segment/tmtc/server.ml
+++ b/sw/ground_segment/tmtc/server.ml
@@ -305,7 +305,7 @@ let send_cam_status = fun a ->
match a.nav_ref with
None -> () (* No geo ref for camera target *)
| Some nav_ref ->
- let h = a.alt -. float (Srtm.of_utm a.pos) in
+ let h = a.alt -. float (try Srtm.of_utm a.pos with _ -> 0) in
let dx = h *. tan (a.cam.phi -. a.roll)
and dy = h *. tan (a.cam.theta +. a.pitch) in
let alpha = -. a.course in
diff --git a/sw/lib/ocaml/mapCanvas.ml b/sw/lib/ocaml/mapCanvas.ml
index be0f3131e0..43a29c8258 100644
--- a/sw/lib/ocaml/mapCanvas.ml
+++ b/sw/lib/ocaml/mapCanvas.ml
@@ -43,6 +43,10 @@ let distance = fun (x1,y1) (x2,y2) -> sqrt ((x1-.x2)**2.+.(y1-.y2)**2.)
let _ = Srtm.add_path "SRTM"
+let affine_pos_and_angle xw yw angle =
+ let cos_a = cos angle in
+ let sin_a = sin angle in
+ [| cos_a ; sin_a ; ~-. sin_a; cos_a; xw ; yw |]
type projection =
Mercator (* 1e-6 = 1 world unit, y axis reversed *)
@@ -82,6 +86,38 @@ let set_opacity = fun pixbuf opacity ->
pixbuf
+type drawing = NotDrawing | Rectangle of float*float | Polygon of (float*float) list
+
+
+let float_array_of_points = fun l ->
+ Array.of_list (List.fold_right (fun (x,y) r -> x::y::r) l [])
+
+let pvect (x1,y1) (x2,y2) = x1*.y2-.y1*.x2
+
+let rec convexify = fun l ->
+ match l with
+ [] | [_] | [_;_] -> l
+ | (x1,y1)::(x2,y2)::(x3,y3)::l ->
+ if pvect (x3-.x2, y3-.y2) (x1-.x2,y1-.y2) < 0.
+ then convexify ((x1,y1)::(x3,y3)::l)
+ else (x1,y1)::convexify ((x2,y2)::(x3,y3)::l)
+
+let convex = fun l ->
+ match convexify l with
+ [] -> []
+ | (x3,y3)::ps ->
+ (** Remove last bad points *)
+ let rec loop = fun l ->
+ match l with
+ [] | [_] -> l
+ | (x2,y2)::(x1,y1)::pts ->
+ if pvect (x3-.x2, y3-.y2) (x1-.x2,y1-.y2) < 0.
+ then loop ((x1,y1)::pts)
+ else l in
+ (x3,y3)::List.rev (loop (List.rev ps))
+
+
+
(** basic canvas with menubar **************************************
* (the vertical display in map2.ml is an instance of basic_widget)*
*******************************************************************)
@@ -103,15 +139,32 @@ class basic_widget = fun ?(height=800) ?width ?(projection = Mercator) ?georef (
let spin_button = GEdit.spin_button ~rate:0. ~digits:2 ~width:50 (*** ~height:20 ***) ~packing:top_bar#pack () in
let canvas = GnoCanvas.canvas ~packing:(frame#pack ~expand:true) () in
- let background = GnoCanvas.group canvas#root in
+ let background = GnoCanvas.group canvas#root
+ and still = GnoCanvas.group canvas#root in
let view_cbs = Hashtbl.create 3 in (* Store for view event callback *)
let region_rectangle = GnoCanvas.rect canvas#root ~props:[`WIDTH_PIXELS 2; `OUTLINE_COLOR "red"] in
+ let region_polygon = GnoCanvas.polygon canvas#root ~props:[`WIDTH_PIXELS 2; `OUTLINE_COLOR "red"] in
+
+ let s = 50. in
+ let s2 = s/.2. and s4=s/.4. in
+ let points = [|0.;0.; s2;s2; s4;s2; s4;s; -.s4;s; -.s4;s2; -.s2;s2|] in
+ let props = [`FILL_COLOR "#a0a0ff"; `FILL_STIPPLE (Gdk.Bitmap.create_from_data ~width:2 ~height:2 "\002\001")] in
+ let arrow = fun x y angle ->
+ let a = GnoCanvas.polygon still ~points ~props in
+ a#affine_relative (affine_pos_and_angle x y angle);
+ a in
+ let north_arrow = arrow (1.5*.s) 0. 0.
+ and south_arrow = arrow (1.5*.s) (3.*.s) LL.pi
+ and west_arrow = arrow 0. (1.5*.s) (-.LL.pi/.2.)
+ and east_arrow = arrow (3.*.s) (1.5*.s) (LL.pi/.2.) in
object (self)
(** GUI attributes *)
val background = background
+ method still = still
+ method top_still = 3.5*.s
val adj = GData.adjustment
~value:1. ~lower:0.05 ~upper:10.
@@ -126,10 +179,12 @@ class basic_widget = fun ?(height=800) ?width ?(projection = Mercator) ?georef (
val mutable projection = projection
val mutable georef = georef
val mutable dragging = None
- val mutable grouping = None
+ val mutable drawing = NotDrawing
val mutable region = None (* Rectangle selected region *)
+ val mutable polygon = None (* Polygon selected region *)
method region = region
+ method polygon = polygon
(** initialization of instance attributes *)
@@ -140,9 +195,10 @@ class basic_widget = fun ?(height=800) ?width ?(projection = Mercator) ?georef (
(** callback bindings *)
canvas#coerce#misc#modify_bg [`NORMAL, `NAME "black"];
- ignore (canvas#event#connect#motion_notify (self#mouse_motion));
- ignore (canvas#event#connect#button_press (self#button_press));
+ ignore (canvas#event#connect#button_press self#button_press);
ignore (canvas#event#connect#button_release self#button_release);
+ ignore (canvas#event#connect#motion_notify self#mouse_motion);
+ ignore (canvas#event#connect#button_press self#button_press);
ignore (canvas#event#connect#after#key_press self#key_press) ;
ignore (canvas#event#connect#enter_notify (fun _ -> self#canvas#misc#grab_focus () ; false));
ignore (canvas#event#connect#any self#any_event);
@@ -264,22 +320,32 @@ class basic_widget = fun ?(height=800) ?width ?(projection = Mercator) ?georef (
method zoom = fun value ->
adj#set_value value
-
- (** Mouse button events *******************************************)
- method button_press = fun ev ->
- let xc = GdkEvent.Button.x ev in
- let yc = GdkEvent.Button.y ev in
- match GdkEvent.Button.button ev with
- 1 when Gdk.Convert.test_modifier `SHIFT (GdkEvent.Button.state ev) && not (Gdk.Convert.test_modifier `CONTROL (GdkEvent.Button.state ev)) ->
- let (x1,y1) = self#window_to_world xc yc in
- grouping <- Some (x1,y1);
- region_rectangle#set [`X1 x1; `Y1 y1; `X2 x1; `Y2 y1];
- true
- | 2 when Gdk.Convert.test_modifier `SHIFT (GdkEvent.Button.state ev) ->
- dragging <- Some (xc, yc);
- true
- | _ -> false
-
+
+ (** events *******************************************)
+ method button_press = fun ev ->
+ let xc = GdkEvent.Button.x ev
+ and yc = GdkEvent.Button.y ev
+ and state = GdkEvent.Button.state ev in
+ let (x1,y1) = self#window_to_world xc yc in
+ try let _ = canvas#get_item_at x1 y1 in false with
+ Not_found ->
+ begin
+ match GdkEvent.Button.button ev with
+ 1 ->
+ begin
+ match Gdk.Convert.modifier state with
+ [`SHIFT] ->
+ drawing <- Rectangle (x1,y1);
+ region_rectangle#set [`X1 x1; `Y1 y1; `X2 x1; `Y2 y1];
+ true
+ | [] ->
+ drawing <- Polygon [(x1, y1)];
+ true;
+ | _ -> false
+ end
+ | _ -> false
+ end
+
method mouse_motion = fun ev ->
if georef <> None then begin
let xc = GdkEvent.Motion.x ev
@@ -288,38 +354,42 @@ class basic_widget = fun ?(height=800) ?width ?(projection = Mercator) ?georef (
self#display_geo (self#geo_string (self#of_world (xw,yw)));
self#display_alt (self#of_world (xw,yw));
begin
- match dragging with
- Some (x0, y0 ) ->
- let (x, y) = self#canvas#get_scroll_offsets in
- self#canvas#scroll_to (x+truncate (x0-.xc)) (y+truncate (y0-.yc))
- | None -> ()
- end;
- begin
- match grouping with
- Some starting_point ->
- let starting_point = self#of_world starting_point in
+ match drawing with
+ Rectangle (x1,y1) ->
+ let starting_point = self#of_world (x1,y1) in
let starting_point = LL.utm_of LL.WGS84 starting_point in
let current_point = LL.utm_of LL.WGS84 (self#of_world (xw, yw)) in
let (east, north) = LL.utm_sub current_point starting_point in
region_rectangle#set [`X2 xw; `Y2 yw];
self#display_group (sprintf "[%.1fkm %.1fkm]" (east/.1000.) (north/.1000.))
- | None -> ()
- end
+ | Polygon ps ->
+ let points = convex ((xw,yw)::ps) in
+ drawing <- Polygon points;
+ region_polygon#set [`POINTS (float_array_of_points points)]
+ | _ -> ()
+ end;
end;
false
method button_release = fun ev ->
- match GdkEvent.Button.button ev, grouping with
- 2, _ ->
- dragging <- None; false
- | 1, Some starting_point ->
- let xc = GdkEvent.Button.x ev in
- let yc = GdkEvent.Button.y ev in
- let current_point = self#window_to_world xc yc in
- region <- Some (starting_point, current_point);
- self#display_group "";
- grouping <- None;
- false
+ match GdkEvent.Button.button ev with
+ 1 ->
+ begin
+ let xc = GdkEvent.Button.x ev in
+ let yc = GdkEvent.Button.y ev in
+ let current_point = self#window_to_world xc yc in
+ match drawing with
+ Rectangle (x1,y1) ->
+ region <- Some ((x1,y1), current_point);
+ self#display_group "";
+ drawing <- NotDrawing;
+ true
+ | Polygon points ->
+ drawing <- NotDrawing;
+ polygon <- Some points;
+ true
+ | _ -> false
+ end
| _ -> false
method key_press = fun ev ->
@@ -414,7 +484,35 @@ class basic_widget = fun ?(height=800) ?width ?(projection = Mercator) ?georef (
let t = GnoCanvas.text ~x:x1 ~y:y1 ~text:text ~props:[`FILL_COLOR fill_color; `X_OFFSET x_offset; `Y_OFFSET y_offset] group in
t#show ();
t
-
+
+ initializer
+ let replace_still = fun _ ->
+ let (x, y) = canvas#get_scroll_offsets in
+ let (xc, yc) = canvas#window_to_world (float x) (float y) in
+ let z = 1./.self#current_zoom in
+ still#affine_absolute [|z;0.;0.;z;xc;yc|]
+ in
+ self#connect_view replace_still;
+ let move_timer = ref (Glib.Timeout.add 0 (fun _ -> false)) in
+ let move dx dy = function
+ `BUTTON_PRESS _ ->
+ let scroll = fun _ ->
+ let (x, y) = canvas#get_scroll_offsets in
+ canvas#scroll_to (x+dx) (y+dy) ; true in
+ move_timer := Glib.Timeout.add 50 scroll;
+ true
+ | `BUTTON_RELEASE _ ->
+ Glib.Timeout.remove !move_timer;
+ true
+ | _ -> false in
+ let up = move 0 (-pan_step)
+ and down = move 0 pan_step
+ and left = move (-pan_step) 0
+ and right = move pan_step 0 in
+ ignore (north_arrow#connect#event up);
+ ignore (south_arrow#connect#event down);
+ ignore (west_arrow#connect#event left);
+ ignore (east_arrow#connect#event right)
end
diff --git a/sw/lib/ocaml/mapFP.ml b/sw/lib/ocaml/mapFP.ml
index 2a9161d4b8..5dd55e454c 100644
--- a/sw/lib/ocaml/mapFP.ml
+++ b/sw/lib/ocaml/mapFP.ml
@@ -34,7 +34,7 @@ let rec assoc_nocase at = function
if String.uppercase at = String.uppercase a then v else assoc_nocase at avs
(** Connect a change in the XML editor to the graphical rep *)
-let update_wp utm_ref wp = function
+let update_wp utm_ref (wp:MapWaypoints.waypoint) = function
XmlEdit.Deleted -> wp#delete
| XmlEdit.New_child _ -> failwith "update_wp"
| XmlEdit.Modified attribs ->
@@ -216,7 +216,7 @@ class flight_plan = fun ?edit geomap color fp_dtd xml ->
)
path
- method connect_selection = fun cb -> XmlEdit.connect_selection xml_tree_view cb
+ method connect_activated = fun cb -> XmlEdit.connect_activated xml_tree_view cb
initializer (
(** Create a graphic waypoint when it is created from the xml editor *)
diff --git a/sw/lib/ocaml/mapFP.mli b/sw/lib/ocaml/mapFP.mli
index 0f3ea97dda..3bd970d76a 100644
--- a/sw/lib/ocaml/mapFP.mli
+++ b/sw/lib/ocaml/mapFP.mli
@@ -43,7 +43,7 @@ class flight_plan :
method xml : Xml.xml
method insert_path : (MapWaypoints.waypoint * float) list -> unit
method highlight_stage : int -> int -> unit
- method connect_selection : (XmlEdit.node->unit) -> unit
+ method connect_activated : (XmlEdit.node->unit) -> unit
end
(** Extracts [lat0] and [Lon0] attributes *)
diff --git a/sw/lib/ocaml/mapWaypoints.ml b/sw/lib/ocaml/mapWaypoints.ml
index f28fab4e97..971ec72b09 100644
--- a/sw/lib/ocaml/mapWaypoints.ml
+++ b/sw/lib/ocaml/mapWaypoints.ml
@@ -71,7 +71,7 @@ class waypoint = fun (group:group) (name :string) ?(alt=0.) wgs84 ->
end
method alt = alt
method label = label
- method xy = let a = item#i2w_affine in (a.(4), a.(5)) (*** item#i2w 0. 0. causes Seg Fault !***)
+ method xy = let a = item#i2w_affine in (a.(4), a.(5))
method move dx dy = item#move dx dy; label#move dx dy
method edit =
let dialog = GWindow.window ~border_width:10 ~title:"Waypoint Edit" () in
@@ -81,7 +81,14 @@ class waypoint = fun (group:group) (name :string) ?(alt=0.) wgs84 ->
let s = sprintf "WGS84 %s" (geomap#geo_string wgs84) in
let ename = GEdit.entry ~text:name ~editable:false ~packing:dvbx#add () in
let e_pos = GEdit.entry ~text:s ~packing:dvbx#add () in
- let ea = GEdit.entry ~text:(string_of_float alt) ~packing:dvbx#add () in
+ let ha = GPack.hbox ~packing:dvbx#add () in
+ let minus10= GButton.button ~label:"-10" ~packing:ha#add () in
+ let ea = GEdit.entry ~text:(string_of_float alt) ~packing:ha#add () in
+ let plus10= GButton.button ~label:"+10" ~packing:ha#add () in
+ let change_alt = fun x ->
+ ea#set_text (string_of_float (float_of_string ea#text +. x)) in
+ ignore(minus10#connect#pressed (fun _ -> change_alt (-10.)));
+ ignore(plus10#connect#pressed (fun _ -> change_alt (10.)));
let callback = fun _ ->
self#set_name ename#text;
@@ -100,21 +107,18 @@ class waypoint = fun (group:group) (name :string) ?(alt=0.) wgs84 ->
(fun e -> ignore (e#connect#activate ~callback))
[ename; e_pos; ea];
ok#grab_default ();
- ignore(ok#connect#clicked ~callback:dialog#destroy);
+ ignore(ok#connect#clicked ~callback:(fun _ -> callback (); dialog#destroy ()));
dialog#show ()
-
+ val mutable motion = false
method event (ev : GnoCanvas.item_event) =
begin
match ev with
| `BUTTON_PRESS ev ->
begin
match GdkEvent.Button.button ev with
- | 2 -> self#edit
- | 3 ->
- if (GToolbox.question_box ~title:"Confirm delete" ~buttons:["Cancel";"Delete"] ~default:2 (sprintf "Delete '%s' ?" name)) = 2 then
- self#delete
| 1 ->
+ motion <- false;
let x = GdkEvent.Button.x ev
and y = GdkEvent.Button.y ev in
x0 <- x; y0 <- y;
@@ -126,6 +130,7 @@ class waypoint = fun (group:group) (name :string) ?(alt=0.) wgs84 ->
| `MOTION_NOTIFY ev ->
let state = GdkEvent.Motion.state ev in
if Gdk.Convert.test_modifier `BUTTON1 state then begin
+ motion <- true;
let x = GdkEvent.Motion.x ev
and y = GdkEvent.Motion.y ev in
let dx = geomap#current_zoom *. (x-. x0)
@@ -138,7 +143,8 @@ class waypoint = fun (group:group) (name :string) ?(alt=0.) wgs84 ->
| `BUTTON_RELEASE ev ->
if GdkEvent.Button.button ev = 1 then begin
item#ungrab (GdkEvent.Button.time ev);
- moved <- true
+ if not motion then
+ self#edit
end
| _ -> ()
end;
@@ -149,11 +155,17 @@ class waypoint = fun (group:group) (name :string) ?(alt=0.) wgs84 ->
method deleted = deleted
method item = item
method pos = geomap#of_world self#xy
- method set wgs84 =
+ method set ?altitude ?(update=false) wgs84 =
let (xw, yw) = geomap#world_of wgs84
and (xw0, yw0) = self#xy
and z = geomap#zoom_adj#value in
- self#move ((xw-.xw0)*.z) ((yw-.yw0)*.z)
+ self#move ((xw-.xw0)*.z) ((yw-.yw0)*.z);
+ begin
+ match altitude with
+ Some a -> alt <- a
+ | _ -> ()
+ end;
+ if update then updated ()
method delete =
deleted <- true; (* BOF *)
item#destroy ();
diff --git a/sw/lib/ocaml/mapWaypoints.mli b/sw/lib/ocaml/mapWaypoints.mli
index 40e28c8d4a..10488197ed 100644
--- a/sw/lib/ocaml/mapWaypoints.mli
+++ b/sw/lib/ocaml/mapWaypoints.mli
@@ -50,7 +50,7 @@ class waypoint :
method label : GnoCanvas.text
method move : float -> float -> unit
method name : string
- method set : Latlong.geographic -> unit
+ method set : ?altitude:float -> ?update:bool -> Latlong.geographic -> unit
method set_name : string -> unit
method xy : float * float
method zoom : float -> unit
diff --git a/sw/lib/ocaml/xmlEdit.ml b/sw/lib/ocaml/xmlEdit.ml
index face68bc90..acf98124ad 100644
--- a/sw/lib/ocaml/xmlEdit.ml
+++ b/sw/lib/ocaml/xmlEdit.ml
@@ -379,10 +379,10 @@ let connect = fun ((model, path):node) cb ->
let current_cb = try model#get ~row ~column:event with _ -> fun _ -> () in
model#set ~row ~column:event (fun e -> cb e; current_cb e)
-let selection_cbs = Hashtbl.create 3
-let connect_selection = fun (model,_) cb ->
- let l = try Hashtbl.find selection_cbs model with Not_found -> [] in
- Hashtbl.replace selection_cbs model (cb::l)
+let activated_cbs = Hashtbl.create 3
+let connect_activated = fun (model,_) cb ->
+ let l = try Hashtbl.find activated_cbs model with Not_found -> [] in
+ Hashtbl.replace activated_cbs model (cb::l)
@@ -483,13 +483,16 @@ let create = fun ?(edit=true) dtd xml ->
let attribs = tree_model#get ~row ~column:attributes in
attribs_model#clear ();
tag_of_last_selection := tree_model#get ~row ~column:tag_col;
- set_attributes attribs_model attribs;
- let cbs = try (Hashtbl.find selection_cbs tree_model) with Not_found -> [] in
- List.iter (fun cb -> cb (tree_model, path)) cbs
+ set_attributes attribs_model attribs
| _ -> () in
let _c = tree_view#selection#connect#after#changed ~callback:selection_changed in
+ let _ = tree_view#connect#after#row_activated ~callback:
+ (fun path vcol ->
+ let cbs = try (Hashtbl.find activated_cbs tree_model) with Not_found -> [] in
+ List.iter (fun cb -> cb (tree_model, path)) cbs) in
+
if edit then begin
let _c = add_context_menu tree_model tree_view (tree_menu_popup dtd) in
let _c = add_context_menu attribs_model attribs_view ~noselection_menu:(add_one_menu dtd tree_view) (attribs_menu_popup dtd tree_view) in
diff --git a/sw/lib/ocaml/xmlEdit.mli b/sw/lib/ocaml/xmlEdit.mli
index 1d60054b16..299628549d 100644
--- a/sw/lib/ocaml/xmlEdit.mli
+++ b/sw/lib/ocaml/xmlEdit.mli
@@ -65,7 +65,7 @@ val add_child : node -> tag -> attributes -> node
(** Modifications *)
val connect : node -> (event -> unit) -> unit
-val connect_selection : t -> (node -> unit) -> unit
+val connect_activated : t -> (node -> unit) -> unit
(** To be kept informed about modifications *)
val selection : t -> node
diff --git a/sw/simulator/sitl.ml b/sw/simulator/sitl.ml
index 733c1a8be6..ea979798dd 100644
--- a/sw/simulator/sitl.ml
+++ b/sw/simulator/sitl.ml
@@ -107,6 +107,8 @@ module Make(A:Data.MISSION) = struct
rc_channels;
ignore (on_off#connect#toggled (fun () -> sliders#coerce#misc#set_sensitive on_off#active));
+ on_off#set_active false;
+
let send_ppm = fun () ->
if on_off#active then send_ppm () in
diff --git a/sw/tools/gen_flight_plan.ml b/sw/tools/gen_flight_plan.ml
index e900fd80fc..6679fcad62 100644
--- a/sw/tools/gen_flight_plan.ml
+++ b/sw/tools/gen_flight_plan.ml
@@ -374,7 +374,7 @@ let rec print_stage = fun index_of_waypoints sectors x ->
lprintf "return;\n"
| "set" ->
stage ();
- let var = parsed_attrib x "var" in
+ let var = ExtXml.attrib x "var" in
let valuee = parsed_attrib x "value" in
lprintf "%s = %s;\n" var valuee;
begin
@@ -474,16 +474,23 @@ let print_blocks = fun index_of_waypoints sectors bs ->
List.iter (fun b -> incr block; print_block index_of_waypoints sectors b !block) bs
-let define_home = fun waypoints ->
- let rec loop i = function
+let define_waypoint_ids = fun waypoints ->
+ let i = ref 0 in
+ List.iter (fun w ->
+ Xml2h.define (sprintf "WP_%s" (name_of w)) (string_of_int !i);
+ incr i)
+ waypoints
+
+let home = fun waypoints ->
+ let rec loop = function
[] -> failwith "Waypoint 'HOME' required"
| w::ws ->
if name_of w = "HOME" then begin
- Xml2h.define "WP_HOME" (string_of_int i);
(float_attrib w "x", float_attrib w "y")
end else
- loop (i+1) ws in
- loop 0 waypoints
+ loop ws in
+ loop waypoints
+
let check_distance = fun (hx, hy) max_d wp ->
let x = float_attrib wp "x"
@@ -717,7 +724,8 @@ let _ =
let waypoints = dummy_waypoint :: Xml.children waypoints in
- let (hx, hy) = define_home waypoints in
+ define_waypoint_ids waypoints;
+ let (hx, hy) = home waypoints in
List.iter (check_distance (hx, hy) mdfh) waypoints;
Xml2h.define "WAYPOINTS" "{ \\";