From: Mikko Rasa Date: Tue, 16 Nov 2010 17:53:13 +0000 (+0000) Subject: Rename the project to R²C² X-Git-Url: http://git.tdb.fi/?p=r2c2.git;a=commitdiff_plain;h=1ff06c5bc46a677fa389ef86c6b26664368f1653 Rename the project to R²C² --- diff --git a/Build b/Build index 6c6687d..fbced14 100644 --- a/Build +++ b/Build @@ -1,4 +1,4 @@ -package "märklin" +package "r2c2" { require "mspcore"; require "sigc++-2.0"; @@ -9,38 +9,38 @@ package "märklin" build_info { incpath "source"; - library "marklin"; + library "r2c2"; }; require "mspdatafile"; }; - library "marklin" + library "r2c2" { - source "source/libmarklin"; + source "source/libr2c2"; require "mspdatafile"; install true; }; - library "marklin3d" + library "r2c2_3d" { source "source/3d"; require "mspgl"; build_info { incpath "source"; - library "marklin"; + library "r2c2"; }; install true; }; - library "marklinnet" + library "r2c2_net" { source "source/network"; require "mspnet"; build_info { incpath "source"; - library "marklin"; + library "r2c2"; }; install true; }; @@ -55,7 +55,7 @@ package "märklin" build_info { incpath "source"; - library "marklin3d"; + library "r2c2_3d"; }; }; @@ -68,8 +68,8 @@ package "märklin" build_info { incpath "source"; - library "marklin3d"; - library "marklinnet"; + library "r2c2_3d"; + library "r2c2_net"; }; }; @@ -80,7 +80,7 @@ package "märklin" build_info { incpath "source"; - library "marklinnet"; + library "r2c2_net"; }; }; @@ -90,7 +90,7 @@ package "märklin" build_info { incpath "source"; - library "marklinnet"; + library "r2c2_net"; }; }; }; diff --git a/firmware/ctrl.c b/firmware/ctrl.c index 523c702..4e7cb65 100644 --- a/firmware/ctrl.c +++ b/firmware/ctrl.c @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ diff --git a/firmware/delay.h b/firmware/delay.h index 1798cec..e4d9985 100644 --- a/firmware/delay.h +++ b/firmware/delay.h @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ diff --git a/firmware/eeprom.c b/firmware/eeprom.c index b9010f0..248556e 100644 --- a/firmware/eeprom.c +++ b/firmware/eeprom.c @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ diff --git a/firmware/eeprom.h b/firmware/eeprom.h index 97527d6..cd31bab 100644 --- a/firmware/eeprom.h +++ b/firmware/eeprom.h @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ diff --git a/firmware/lcd.c b/firmware/lcd.c index 6ba00d5..397ec10 100644 --- a/firmware/lcd.c +++ b/firmware/lcd.c @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL diff --git a/firmware/lcd.h b/firmware/lcd.h index 2d414dc..822793d 100644 --- a/firmware/lcd.h +++ b/firmware/lcd.h @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ diff --git a/firmware/s88w-r.c b/firmware/s88w-r.c index d2a2109..b537584 100644 --- a/firmware/s88w-r.c +++ b/firmware/s88w-r.c @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL diff --git a/firmware/s88w-t.c b/firmware/s88w-t.c index b39fd79..b7d0a94 100644 --- a/firmware/s88w-t.c +++ b/firmware/s88w-t.c @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL diff --git a/firmware/serial.c b/firmware/serial.c index be3b13a..b0f1b1f 100644 --- a/firmware/serial.c +++ b/firmware/serial.c @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ diff --git a/firmware/serial.h b/firmware/serial.h index 696c20e..e5bfebe 100644 --- a/firmware/serial.h +++ b/firmware/serial.h @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ diff --git a/firmware/timer.c b/firmware/timer.c index 13db1e8..b218ed6 100644 --- a/firmware/timer.c +++ b/firmware/timer.c @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ diff --git a/firmware/timer.h b/firmware/timer.h index 2fbda8e..d7252be 100644 --- a/firmware/timer.h +++ b/firmware/timer.h @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ diff --git a/marklin.res b/marklin.res deleted file mode 100644 index b40871e..0000000 --- a/marklin.res +++ /dev/null @@ -1,547 +0,0 @@ -/* $Id$ */ - -default_font "dejavu-12.font"; - -style "root" -{ - special "children"; -}; - -style "label" -{ - font_color 0 0 0; - special "text"; -}; - -style "image" -{ - special "image" - { - fill 1.0 1.0; - }; -}; - -graphic "tooltip" -{ - texture "gui.png"; - slice 50 93 20 10; - border { top 2; right 2; bottom 2; left 2; }; -}; - -style "label-tooltip" -{ - font_color 0.0 0.0 0.0; - - part - { - graphic NORMAL "tooltip"; - }; - - special "text" - { - align 0.0 0.5; - fill 0.0 0.0; - margin { top 2; right 2; bottom 2; left 2; }; - }; -}; - -graphic "grey_button" -{ - texture "gui.png"; - slice 2 54 21 10; - border { top 2; right 3; bottom 4; left 2; }; - shadow { top 0; right 1; bottom 2; left 0; }; -}; - -graphic "grey_button_pressed" -{ - texture "gui.png"; - slice 25 54 21 10; - border { top 2; right 3; bottom 4; left 2; }; - shadow { top 0; right 1; bottom 2; left 0; }; -}; - -graphic "green_button" -{ - texture "gui.png"; - slice 2 43 21 10; - border { top 2; right 3; bottom 4; left 2; }; - shadow { top 0; right 1; bottom 2; left 0; }; -}; - -graphic "green_button_pressed" -{ - texture "gui.png"; - slice 25 43 21 10; - border { top 2; right 3; bottom 4; left 2; }; - shadow { top 0; right 1; bottom 2; left 0; }; -}; - -graphic "red_button" -{ - texture "gui.png"; - slice 2 32 21 10; - border { top 2; right 3; bottom 4; left 2; }; - shadow { top 0; right 1; bottom 2; left 0; }; -}; - -graphic "red_button_pressed" -{ - texture "gui.png"; - slice 25 32 21 10; - border { top 2; right 3; bottom 4; left 2; }; - shadow { top 0; right 1; bottom 2; left 0; }; -}; - -graphic "up_arrow_button" -{ - texture "gui.png"; - slice 2 18 13 13; - shadow { top 0; right 1; bottom 2; left 0; }; -}; - -graphic "up_arrow_button_pressed" -{ - texture "gui.png"; - slice 17 18 13 13; - shadow { top 0; right 1; bottom 2; left 0; }; -}; - -graphic "down_arrow_button" -{ - texture "gui.png"; - slice 2 4 13 13; - shadow { top 0; right 1; bottom 2; left 0; }; -}; - -graphic "down_arrow_button_pressed" -{ - texture "gui.png"; - slice 17 4 13 13; - shadow { top 0; right 1; bottom 2; left 0; }; -}; - -style "button" -{ - font_color 0 0 0; - - part - { - graphic NORMAL "grey_button"; - graphic ACTIVE "grey_button_pressed"; - align 0.5 0.0; - fill 0.0 0.0; - }; - - special "text" - { - align 0.5 1.0; - fill 0.0 0.0; - }; -}; - -style "button-green" -{ - font_color 0 0 0; - - part - { - graphic NORMAL "green_button"; - graphic ACTIVE "green_button_pressed"; - align 0.5 0.0; - fill 0.0 0.0; - }; - - special "text" - { - align 0.5 1.0; - fill 0.0 0.0; - }; -}; - -style "button-red" -{ - font_color 0 0 0; - - part - { - graphic NORMAL "red_button"; - graphic ACTIVE "red_button_pressed"; - align 0.5 0.0; - fill 0.0 0.0; - }; - - special "text" - { - align 0.5 1.0; - fill 0.0 0.0; - }; -}; - -style "button-arrow_up" -{ - part - { - graphic NORMAL "up_arrow_button"; - graphic ACTIVE "up_arrow_button_pressed"; - align 0.5 0.5; - fill 0.0 0.0; - }; -}; - -style "button-arrow_down" -{ - part - { - graphic NORMAL "down_arrow_button"; - graphic ACTIVE "down_arrow_button_pressed"; - align 0.5 0.5; - fill 0.0 0.0; - }; -}; - -graphic "yellow_lamp" -{ - texture "gui.png"; - slice 28 105 10 10; -}; - -graphic "yellow_lamp_lit" -{ - texture "gui.png"; - slice 28 117 10 10; -}; - -graphic "green_lamp" -{ - texture "gui.png"; - slice 40 105 10 10; -}; - -graphic "green_lamp_lit" -{ - texture "gui.png"; - slice 40 117 10 10; -}; - -graphic "red_lamp" -{ - texture "gui.png"; - slice 52 105 10 10; -}; - -graphic "red_lamp_lit" -{ - texture "gui.png"; - slice 52 116 10 10; -}; - -style "indicator" -{ - part - { - graphic NORMAL "yellow_lamp"; - graphic ACTIVE "yellow_lamp_lit"; - align 0.5 0.5; - fill 0.0 0.0; - }; -}; - -style "indicator-green" -{ - part - { - graphic NORMAL "green_lamp"; - graphic ACTIVE "green_lamp_lit"; - align 0.5 0.5; - fill 0.0 0.0; - }; -}; - -style "indicator-red" -{ - part - { - graphic NORMAL "red_lamp"; - graphic ACTIVE "red_lamp_lit"; - align 0.5 0.5; - fill 0.0 0.0; - }; -}; - -graphic "raised_grey_bg" -{ - texture "gui.png"; - slice 2 74 24 16; - border { top 4; right 4; bottom 4; left 4; }; -}; - -style "panel" -{ - part - { - graphic NORMAL "raised_grey_bg"; - }; - special "children"; -}; - -style "panel-group" -{ - special "children"; -}; - -graphic "sunken_black_bg" -{ - texture "gui.png"; - slice 2 110 24 16; - border { top 4; right 4; bottom 4; left 4; }; -}; - -style "label-digital" -{ - font "digitalreadout-16.font"; - font_color 0.3 1 0.3; - - part - { - graphic NORMAL "sunken_black_bg"; - }; - - special "text" - { - fill 0.0 0.0; - align 0.5 0.5; - margin { top 1; }; - }; -}; - -graphic "sunken_white_bg" -{ - texture "gui.png"; - slice 2 92 24 16; - border { top 4; right 4; bottom 4; left 4; }; -}; - -graphic "cursor" -{ - texture "gui.png"; - slice 40 81 2 10; -}; - -style "entry" -{ - font_color 0 0 0; - - part - { - graphic NORMAL "sunken_white_bg"; - }; - - special "text" - { - align 0.0 0.5; - fill 0.0 0.0; - margin { left 3; right 3; }; - }; - - special "cursor" - { - graphic FOCUS "cursor"; - align 0.0 0.5; - fill 0.0 0.0; - size 2 12; - margin { left 3; right 3; }; - }; -}; - -style "entry-multiline" -{ - font_color 0 0 0; - - part - { - graphic NORMAL "sunken_white_bg"; - }; - - special "text" - { - align 0.0 1.0; - fill 0.0 0.0; - margin { top 2; right 13; left 3; bottom 2; }; - }; - - special "cursor" - { - graphic FOCUS "cursor"; - size 2 12; - }; - - special "slider" - { - align 1.0 0.0; - fill 0.0 1.0; - size 10 0; - margin { top 3; right 2; bottom 3; }; - }; -}; - -graphic "selection" -{ - texture "gui.png"; - slice 44 81 20 10; - border { top 4; right 4; bottom 4; left 4; }; -}; - -style "list" -{ - font_color 0.0 0.0 0.0; - - part - { - graphic NORMAL "sunken_white_bg"; - }; - - special "selection" - { - graphic NORMAL "selection"; - fill 1.0 1.0; - margin { top 2; right 13; bottom 2; left 2; }; - }; - - special "items" - { - margin { top 2; right 13; bottom 2; left 2; }; - }; - - special "slider" - { - align 1.0 0.0; - fill 0.0 1.0; - size 10 0; - margin { top 3; right 2; bottom 3; }; - }; -}; - -style "dropdown" -{ - font_color 0.0 0.0 0.0; - - part - { - graphic NORMAL "sunken_white_bg"; - margin { right 14; }; - }; - - part - { - graphic NORMAL "down_arrow_button"; - graphic ACTIVE "down_arrow_button_pressed"; - align 1.0 0.5; - fill 0.0 0.0; - }; - - special "text" - { - align 0.0 0.5; - fill 0.0 0.0; - margin { left 2; }; - }; - - special "list"; -}; - -graphic "switch_up" -{ - texture "gui.png"; - slice 48 42 20 21; - shadow { top 0; right 2; bottom 3; left 0; }; -}; - -graphic "switch_down" -{ - texture "gui.png"; - slice 48 20 20 21; - shadow { top 0; right 2; bottom 3; left 0; }; -}; - -style "toggle" -{ - font_color 0.0 0.0 0.0; - - special "text" - { - align 0.5 1.0; - fill 0.0 0.0; - }; - - part - { - align 0.5 0.0; - fill 0.0 0.0; - graphic NORMAL "switch_down"; - graphic ACTIVE "switch_up"; - }; -}; - -graphic "horizontal_slot" -{ - texture "gui.png"; - slice 32 97 12 2; - border { left 1; right 1; }; -}; - -graphic "horizontal_knob" -{ - texture "gui.png"; - slice 70 51 32 13; - shadow { top 0; right 2; bottom 3; left 0; }; -}; - -style "hslider" -{ - part - { - graphic NORMAL "horizontal_slot"; - align 0.5 0.5; - fill 1.0 0.0; - margin { left 4; right 4; }; - }; - - special "slider" - { - graphic NORMAL "horizontal_knob"; - fill 0.0 0.0; - }; -}; - -graphic "vertical_slot" -{ - texture "gui.png"; - slice 32 75 2 12; - border { top 1; bottom 1; }; -}; - -graphic "vertical_knob" -{ - texture "gui.png"; - slice 70 17 12 33; - shadow { top 0; right 2; bottom 3; left 0; }; -}; - -style "vslider" -{ - part - { - graphic NORMAL "vertical_slot"; - align 0.5 0.5; - fill 0.0 1.0; - margin { top 4; bottom 4; }; - }; - - special "slider" - { - graphic NORMAL "vertical_knob"; - fill 0.0 0.0; - align 0.0 1.0; - }; -}; diff --git a/r2c2.res b/r2c2.res new file mode 100644 index 0000000..b40871e --- /dev/null +++ b/r2c2.res @@ -0,0 +1,547 @@ +/* $Id$ */ + +default_font "dejavu-12.font"; + +style "root" +{ + special "children"; +}; + +style "label" +{ + font_color 0 0 0; + special "text"; +}; + +style "image" +{ + special "image" + { + fill 1.0 1.0; + }; +}; + +graphic "tooltip" +{ + texture "gui.png"; + slice 50 93 20 10; + border { top 2; right 2; bottom 2; left 2; }; +}; + +style "label-tooltip" +{ + font_color 0.0 0.0 0.0; + + part + { + graphic NORMAL "tooltip"; + }; + + special "text" + { + align 0.0 0.5; + fill 0.0 0.0; + margin { top 2; right 2; bottom 2; left 2; }; + }; +}; + +graphic "grey_button" +{ + texture "gui.png"; + slice 2 54 21 10; + border { top 2; right 3; bottom 4; left 2; }; + shadow { top 0; right 1; bottom 2; left 0; }; +}; + +graphic "grey_button_pressed" +{ + texture "gui.png"; + slice 25 54 21 10; + border { top 2; right 3; bottom 4; left 2; }; + shadow { top 0; right 1; bottom 2; left 0; }; +}; + +graphic "green_button" +{ + texture "gui.png"; + slice 2 43 21 10; + border { top 2; right 3; bottom 4; left 2; }; + shadow { top 0; right 1; bottom 2; left 0; }; +}; + +graphic "green_button_pressed" +{ + texture "gui.png"; + slice 25 43 21 10; + border { top 2; right 3; bottom 4; left 2; }; + shadow { top 0; right 1; bottom 2; left 0; }; +}; + +graphic "red_button" +{ + texture "gui.png"; + slice 2 32 21 10; + border { top 2; right 3; bottom 4; left 2; }; + shadow { top 0; right 1; bottom 2; left 0; }; +}; + +graphic "red_button_pressed" +{ + texture "gui.png"; + slice 25 32 21 10; + border { top 2; right 3; bottom 4; left 2; }; + shadow { top 0; right 1; bottom 2; left 0; }; +}; + +graphic "up_arrow_button" +{ + texture "gui.png"; + slice 2 18 13 13; + shadow { top 0; right 1; bottom 2; left 0; }; +}; + +graphic "up_arrow_button_pressed" +{ + texture "gui.png"; + slice 17 18 13 13; + shadow { top 0; right 1; bottom 2; left 0; }; +}; + +graphic "down_arrow_button" +{ + texture "gui.png"; + slice 2 4 13 13; + shadow { top 0; right 1; bottom 2; left 0; }; +}; + +graphic "down_arrow_button_pressed" +{ + texture "gui.png"; + slice 17 4 13 13; + shadow { top 0; right 1; bottom 2; left 0; }; +}; + +style "button" +{ + font_color 0 0 0; + + part + { + graphic NORMAL "grey_button"; + graphic ACTIVE "grey_button_pressed"; + align 0.5 0.0; + fill 0.0 0.0; + }; + + special "text" + { + align 0.5 1.0; + fill 0.0 0.0; + }; +}; + +style "button-green" +{ + font_color 0 0 0; + + part + { + graphic NORMAL "green_button"; + graphic ACTIVE "green_button_pressed"; + align 0.5 0.0; + fill 0.0 0.0; + }; + + special "text" + { + align 0.5 1.0; + fill 0.0 0.0; + }; +}; + +style "button-red" +{ + font_color 0 0 0; + + part + { + graphic NORMAL "red_button"; + graphic ACTIVE "red_button_pressed"; + align 0.5 0.0; + fill 0.0 0.0; + }; + + special "text" + { + align 0.5 1.0; + fill 0.0 0.0; + }; +}; + +style "button-arrow_up" +{ + part + { + graphic NORMAL "up_arrow_button"; + graphic ACTIVE "up_arrow_button_pressed"; + align 0.5 0.5; + fill 0.0 0.0; + }; +}; + +style "button-arrow_down" +{ + part + { + graphic NORMAL "down_arrow_button"; + graphic ACTIVE "down_arrow_button_pressed"; + align 0.5 0.5; + fill 0.0 0.0; + }; +}; + +graphic "yellow_lamp" +{ + texture "gui.png"; + slice 28 105 10 10; +}; + +graphic "yellow_lamp_lit" +{ + texture "gui.png"; + slice 28 117 10 10; +}; + +graphic "green_lamp" +{ + texture "gui.png"; + slice 40 105 10 10; +}; + +graphic "green_lamp_lit" +{ + texture "gui.png"; + slice 40 117 10 10; +}; + +graphic "red_lamp" +{ + texture "gui.png"; + slice 52 105 10 10; +}; + +graphic "red_lamp_lit" +{ + texture "gui.png"; + slice 52 116 10 10; +}; + +style "indicator" +{ + part + { + graphic NORMAL "yellow_lamp"; + graphic ACTIVE "yellow_lamp_lit"; + align 0.5 0.5; + fill 0.0 0.0; + }; +}; + +style "indicator-green" +{ + part + { + graphic NORMAL "green_lamp"; + graphic ACTIVE "green_lamp_lit"; + align 0.5 0.5; + fill 0.0 0.0; + }; +}; + +style "indicator-red" +{ + part + { + graphic NORMAL "red_lamp"; + graphic ACTIVE "red_lamp_lit"; + align 0.5 0.5; + fill 0.0 0.0; + }; +}; + +graphic "raised_grey_bg" +{ + texture "gui.png"; + slice 2 74 24 16; + border { top 4; right 4; bottom 4; left 4; }; +}; + +style "panel" +{ + part + { + graphic NORMAL "raised_grey_bg"; + }; + special "children"; +}; + +style "panel-group" +{ + special "children"; +}; + +graphic "sunken_black_bg" +{ + texture "gui.png"; + slice 2 110 24 16; + border { top 4; right 4; bottom 4; left 4; }; +}; + +style "label-digital" +{ + font "digitalreadout-16.font"; + font_color 0.3 1 0.3; + + part + { + graphic NORMAL "sunken_black_bg"; + }; + + special "text" + { + fill 0.0 0.0; + align 0.5 0.5; + margin { top 1; }; + }; +}; + +graphic "sunken_white_bg" +{ + texture "gui.png"; + slice 2 92 24 16; + border { top 4; right 4; bottom 4; left 4; }; +}; + +graphic "cursor" +{ + texture "gui.png"; + slice 40 81 2 10; +}; + +style "entry" +{ + font_color 0 0 0; + + part + { + graphic NORMAL "sunken_white_bg"; + }; + + special "text" + { + align 0.0 0.5; + fill 0.0 0.0; + margin { left 3; right 3; }; + }; + + special "cursor" + { + graphic FOCUS "cursor"; + align 0.0 0.5; + fill 0.0 0.0; + size 2 12; + margin { left 3; right 3; }; + }; +}; + +style "entry-multiline" +{ + font_color 0 0 0; + + part + { + graphic NORMAL "sunken_white_bg"; + }; + + special "text" + { + align 0.0 1.0; + fill 0.0 0.0; + margin { top 2; right 13; left 3; bottom 2; }; + }; + + special "cursor" + { + graphic FOCUS "cursor"; + size 2 12; + }; + + special "slider" + { + align 1.0 0.0; + fill 0.0 1.0; + size 10 0; + margin { top 3; right 2; bottom 3; }; + }; +}; + +graphic "selection" +{ + texture "gui.png"; + slice 44 81 20 10; + border { top 4; right 4; bottom 4; left 4; }; +}; + +style "list" +{ + font_color 0.0 0.0 0.0; + + part + { + graphic NORMAL "sunken_white_bg"; + }; + + special "selection" + { + graphic NORMAL "selection"; + fill 1.0 1.0; + margin { top 2; right 13; bottom 2; left 2; }; + }; + + special "items" + { + margin { top 2; right 13; bottom 2; left 2; }; + }; + + special "slider" + { + align 1.0 0.0; + fill 0.0 1.0; + size 10 0; + margin { top 3; right 2; bottom 3; }; + }; +}; + +style "dropdown" +{ + font_color 0.0 0.0 0.0; + + part + { + graphic NORMAL "sunken_white_bg"; + margin { right 14; }; + }; + + part + { + graphic NORMAL "down_arrow_button"; + graphic ACTIVE "down_arrow_button_pressed"; + align 1.0 0.5; + fill 0.0 0.0; + }; + + special "text" + { + align 0.0 0.5; + fill 0.0 0.0; + margin { left 2; }; + }; + + special "list"; +}; + +graphic "switch_up" +{ + texture "gui.png"; + slice 48 42 20 21; + shadow { top 0; right 2; bottom 3; left 0; }; +}; + +graphic "switch_down" +{ + texture "gui.png"; + slice 48 20 20 21; + shadow { top 0; right 2; bottom 3; left 0; }; +}; + +style "toggle" +{ + font_color 0.0 0.0 0.0; + + special "text" + { + align 0.5 1.0; + fill 0.0 0.0; + }; + + part + { + align 0.5 0.0; + fill 0.0 0.0; + graphic NORMAL "switch_down"; + graphic ACTIVE "switch_up"; + }; +}; + +graphic "horizontal_slot" +{ + texture "gui.png"; + slice 32 97 12 2; + border { left 1; right 1; }; +}; + +graphic "horizontal_knob" +{ + texture "gui.png"; + slice 70 51 32 13; + shadow { top 0; right 2; bottom 3; left 0; }; +}; + +style "hslider" +{ + part + { + graphic NORMAL "horizontal_slot"; + align 0.5 0.5; + fill 1.0 0.0; + margin { left 4; right 4; }; + }; + + special "slider" + { + graphic NORMAL "horizontal_knob"; + fill 0.0 0.0; + }; +}; + +graphic "vertical_slot" +{ + texture "gui.png"; + slice 32 75 2 12; + border { top 1; bottom 1; }; +}; + +graphic "vertical_knob" +{ + texture "gui.png"; + slice 70 17 12 33; + shadow { top 0; right 2; bottom 3; left 0; }; +}; + +style "vslider" +{ + part + { + graphic NORMAL "vertical_slot"; + align 0.5 0.5; + fill 0.0 1.0; + margin { top 4; bottom 4; }; + }; + + special "slider" + { + graphic NORMAL "vertical_knob"; + fill 0.0 0.0; + align 0.0 1.0; + }; +}; diff --git a/source/3d/catalogue.cpp b/source/3d/catalogue.cpp index 2f4fc04..8641013 100644 --- a/source/3d/catalogue.cpp +++ b/source/3d/catalogue.cpp @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -13,7 +13,7 @@ Distributed under the GPL using namespace std; using namespace Msp; -namespace Marklin { +namespace R2C2 { Catalogue3D::Catalogue3D(Catalogue &c): catalogue(c), @@ -93,4 +93,4 @@ void Catalogue3D::build_endpoint_mesh() bld.end(); } -} // namespace Marklin +} // namespace R2C2 diff --git a/source/3d/catalogue.h b/source/3d/catalogue.h index 1f33ebb..bda1314 100644 --- a/source/3d/catalogue.h +++ b/source/3d/catalogue.h @@ -1,18 +1,18 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ -#ifndef MARKLIN3D_CATALOGUE_H_ -#define MARKLIN3D_CATALOGUE_H_ +#ifndef R2C2_3D_CATALOGUE_H_ +#define R2C2_3D_CATALOGUE_H_ #include #include -#include "libmarklin/catalogue.h" +#include "libr2c2/catalogue.h" -namespace Marklin { +namespace R2C2 { class TrackType3D; class VehicleType3D; diff --git a/source/3d/endpoint.cpp b/source/3d/endpoint.cpp index 77a8af8..7e33ced 100644 --- a/source/3d/endpoint.cpp +++ b/source/3d/endpoint.cpp @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -14,7 +14,7 @@ Distributed under the GPL using namespace Msp; -namespace Marklin { +namespace R2C2 { Endpoint3D::Endpoint3D(const Track3D &t, unsigned i): track(t), @@ -50,4 +50,4 @@ void Endpoint3D::render(const GL::Tag &tag) const } } -} // namespace Marklin +} // namespace R2C2 diff --git a/source/3d/endpoint.h b/source/3d/endpoint.h index 0abc526..e407127 100644 --- a/source/3d/endpoint.h +++ b/source/3d/endpoint.h @@ -1,18 +1,18 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ -#ifndef MARKLIN3D_ENDPOINT_H_ -#define MARKLIN3D_ENDPOINT_H_ +#ifndef R2C2_3D_ENDPOINT_H_ +#define R2C2_3D_ENDPOINT_H_ #include #include -#include "libmarklin/track.h" +#include "libr2c2/track.h" -namespace Marklin { +namespace R2C2 { class Track3D; @@ -30,6 +30,6 @@ public: virtual void render(const Msp::GL::Tag &) const; }; -} // namespace Marklin +} // namespace R2C2 #endif diff --git a/source/3d/layout.cpp b/source/3d/layout.cpp index 05aaa42..5f01576 100644 --- a/source/3d/layout.cpp +++ b/source/3d/layout.cpp @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -20,7 +20,7 @@ Distributed under the GPL using namespace std; using namespace Msp; -namespace Marklin { +namespace R2C2 { Layout3D::Layout3D(Layout &l): layout(l), @@ -148,4 +148,4 @@ void Layout3D::vehicle_removed(Vehicle &v) delete i->second; } -} // namespace Marklin +} // namespace R2C2 diff --git a/source/3d/layout.h b/source/3d/layout.h index 54269bc..e7f3c33 100644 --- a/source/3d/layout.h +++ b/source/3d/layout.h @@ -1,19 +1,19 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ -#ifndef MARKLIN3D_LAYOUT_H_ -#define MARKLIN3D_LAYOUT_H_ +#ifndef R2C2_3D_LAYOUT_H_ +#define R2C2_3D_LAYOUT_H_ #include #include -#include "libmarklin/layout.h" +#include "libr2c2/layout.h" #include "catalogue.h" -namespace Marklin { +namespace R2C2 { class Track3D; class Vehicle3D; @@ -60,7 +60,7 @@ private: void vehicle_removed(Vehicle &); }; -} // namespace Marklin +} // namespace R2C2 #endif diff --git a/source/3d/object.h b/source/3d/object.h index d2cb911..a9ac715 100644 --- a/source/3d/object.h +++ b/source/3d/object.h @@ -1,16 +1,16 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ -#ifndef MARKLIN3D_OBJECT_H_ -#define MARKLIN3D_OBJECT_H_ +#ifndef R2C2_3D_OBJECT_H_ +#define R2C2_3D_OBJECT_H_ -#include "libmarklin/geometry.h" +#include "libr2c2/geometry.h" -namespace Marklin { +namespace R2C2 { class Object3D { @@ -23,6 +23,6 @@ public: virtual bool is_visible() const = 0; }; -} // namespace Marklin +} // namespace R2C2 #endif diff --git a/source/3d/overlay.cpp b/source/3d/overlay.cpp index 39428a1..ee9fea7 100644 --- a/source/3d/overlay.cpp +++ b/source/3d/overlay.cpp @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -18,7 +18,7 @@ Distributed under the GPL using namespace std; using namespace Msp; -namespace Marklin { +namespace R2C2 { Overlay3D::Overlay3D(const Graphics::Window &w, const GL::Camera &c, const GL::Font &f): window(w), @@ -195,4 +195,4 @@ Overlay3D::Icon::Icon(): background((GL::COLOR4_UBYTE, GL::VERTEX2)) { } -} // namespace Marklin +} // namespace R2C2 diff --git a/source/3d/overlay.h b/source/3d/overlay.h index eac51be..8e818bf 100644 --- a/source/3d/overlay.h +++ b/source/3d/overlay.h @@ -1,12 +1,12 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ -#ifndef MARKLIN3D_OVERLAY_H_ -#define MARKLIN3D_OVERLAY_H_ +#ifndef R2C2_3D_OVERLAY_H_ +#define R2C2_3D_OVERLAY_H_ #include #include @@ -14,7 +14,7 @@ Distributed under the GPL #include #include -namespace Marklin { +namespace R2C2 { class Object3D; @@ -55,6 +55,6 @@ private: void update_icon(Icon &); }; -} // namespace Marklin +} // namespace R2C2 #endif diff --git a/source/3d/path.cpp b/source/3d/path.cpp index b3b2fa1..e4e0b92 100644 --- a/source/3d/path.cpp +++ b/source/3d/path.cpp @@ -1,12 +1,12 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ #include -#include "libmarklin/tracktype.h" +#include "libr2c2/tracktype.h" #include "layout.h" #include "path.h" #include "track.h" @@ -14,7 +14,7 @@ Distributed under the GPL using namespace Msp; -namespace Marklin { +namespace R2C2 { Path3D::Path3D(const Track3D &t): track(t), @@ -81,4 +81,4 @@ void Path3D::render(const GL::Tag &tag) const } } -} // namespace Marklin +} // namespace R2C2 diff --git a/source/3d/path.h b/source/3d/path.h index dd071f7..cd6ad90 100644 --- a/source/3d/path.h +++ b/source/3d/path.h @@ -1,18 +1,18 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ -#ifndef MARKLIN3D_PATH_H_ -#define MARKLIN3D_PATH_H_ +#ifndef R2C2_3D_PATH_H_ +#define R2C2_3D_PATH_H_ #include #include #include -namespace Marklin { +namespace R2C2 { class Track3D; @@ -38,6 +38,6 @@ public: virtual void render(const Msp::GL::Tag &) const; }; -} // namespace Marklin +} // namespace R2C2 #endif diff --git a/source/3d/track.cpp b/source/3d/track.cpp index 5340318..401dd2d 100644 --- a/source/3d/track.cpp +++ b/source/3d/track.cpp @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -8,7 +8,7 @@ Distributed under the GPL #include #include #include -#include "libmarklin/tracktype.h" +#include "libr2c2/tracktype.h" #include "endpoint.h" #include "layout.h" #include "path.h" @@ -18,7 +18,7 @@ Distributed under the GPL using namespace std; using namespace Msp; -namespace Marklin { +namespace R2C2 { Track3D::Track3D(Layout3D &l, Track &t): layout(l), @@ -104,4 +104,4 @@ void Track3D::render(const GL::Tag &tag) const glPopName(); } -} // namespace Marklin +} // namespace R2C2 diff --git a/source/3d/track.h b/source/3d/track.h index e55dc21..7b8c235 100644 --- a/source/3d/track.h +++ b/source/3d/track.h @@ -1,22 +1,22 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ -#ifndef MARKLIN3D_TRACK_H_ -#define MARKLIN3D_TRACK_H_ +#ifndef R2C2_3D_TRACK_H_ +#define R2C2_3D_TRACK_H_ #include #include #include #include -#include "libmarklin/track.h" -#include "libmarklin/trackpart.h" +#include "libr2c2/track.h" +#include "libr2c2/trackpart.h" #include "object.h" -namespace Marklin { +namespace R2C2 { class Endpoint3D; class Layout3D; @@ -49,6 +49,6 @@ public: virtual void render(const Msp::GL::Tag &) const; }; -} // namespace Marklin +} // namespace R2C2 #endif diff --git a/source/3d/tracktype.cpp b/source/3d/tracktype.cpp index 6dab43c..1e20c5d 100644 --- a/source/3d/tracktype.cpp +++ b/source/3d/tracktype.cpp @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -16,7 +16,7 @@ using namespace Msp; namespace { -bool compare_z(const Marklin::Point &p1, const Marklin::Point &p2) +bool compare_z(const R2C2::Point &p1, const R2C2::Point &p2) { return p1.zxx==lowest.x && i->y>lowest.y)) lowest = *i; @@ -69,7 +69,7 @@ Iter graham_scan(Iter begin, Iter end) } -namespace Marklin { +namespace R2C2 { TrackType3D::TrackType3D(const Catalogue3D &cat3d, const TrackType &tt): catalogue(cat3d), @@ -230,4 +230,4 @@ void TrackType3D::build_part(const TrackPart &part, const Profile &profile, cons base_index += (nsegs+1)*(n_points-1)*2; } -} // namespace Marklin +} // namespace R2C2 diff --git a/source/3d/tracktype.h b/source/3d/tracktype.h index 56a4b46..7bf1b2d 100644 --- a/source/3d/tracktype.h +++ b/source/3d/tracktype.h @@ -1,20 +1,20 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ -#ifndef MARKLIN3D_TRACKTYPE_H_ -#define MARKLIN3D_TRACKTYPE_H_ +#ifndef R2C2_3D_TRACKTYPE_H_ +#define R2C2_3D_TRACKTYPE_H_ #include #include #include -#include "libmarklin/profile.h" -#include "libmarklin/tracktype.h" +#include "libr2c2/profile.h" +#include "libr2c2/tracktype.h" -namespace Marklin { +namespace R2C2 { class Catalogue3D; @@ -42,6 +42,6 @@ private: void build_part(const TrackPart &, const Profile &, const Point &, Msp::GL::MeshBuilder &, unsigned &); }; -} // namespace Marklin +} // namespace R2C2 #endif diff --git a/source/3d/vehicle.cpp b/source/3d/vehicle.cpp index 7e4814b..f14f3c2 100644 --- a/source/3d/vehicle.cpp +++ b/source/3d/vehicle.cpp @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -14,7 +14,7 @@ Distributed under the GPL using namespace std; using namespace Msp; -namespace Marklin { +namespace R2C2 { Vehicle3D::Vehicle3D(Layout3D &l, Vehicle &v): layout(l), @@ -91,4 +91,4 @@ void Vehicle3D::render(const GL::Tag &tag) const } } -} // namespace Marklin +} // namespace R2C2 diff --git a/source/3d/vehicle.h b/source/3d/vehicle.h index 075eaef..06e78ef 100644 --- a/source/3d/vehicle.h +++ b/source/3d/vehicle.h @@ -1,18 +1,18 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ -#ifndef LIBMARKLIN3D_VEHICLE_H_ -#define LIBMARKLIN3D_VEHICLE_H_ +#ifndef LIBR2C23D_VEHICLE_H_ +#define LIBR2C23D_VEHICLE_H_ #include -#include "libmarklin/vehicle.h" +#include "libr2c2/vehicle.h" #include "object.h" -namespace Marklin { +namespace R2C2 { class Layout3D; class VehicleType3D; @@ -36,6 +36,6 @@ public: virtual void render(const Msp::GL::Tag &) const; }; -} // namespace Marklin +} // namespace R2C2 #endif diff --git a/source/3d/vehicletype.cpp b/source/3d/vehicletype.cpp index b283edd..fc4f2d4 100644 --- a/source/3d/vehicletype.cpp +++ b/source/3d/vehicletype.cpp @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -29,7 +29,7 @@ T get(const map ¶ms, const string &key, T def = T()) } -namespace Marklin { +namespace R2C2 { VehicleType3D::VehicleType3D(const Catalogue3D &c, const VehicleType &t): catalogue(c), @@ -342,4 +342,4 @@ GL::Mesh *VehicleType3D::create_flat_wagon(const map ¶ms) return mesh; } -} // namespace Marklin +} // namespace R2C2 diff --git a/source/3d/vehicletype.h b/source/3d/vehicletype.h index f38f02d..72c2c23 100644 --- a/source/3d/vehicletype.h +++ b/source/3d/vehicletype.h @@ -1,18 +1,18 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ -#ifndef LIBMARKLIN3D_VEHICLETYPE_H_ -#define LIBMARKLIN3D_VEHICLETYPE_H_ +#ifndef LIBR2C23D_VEHICLETYPE_H_ +#define LIBR2C23D_VEHICLETYPE_H_ #include #include -#include "libmarklin/vehicletype.h" +#include "libr2c2/vehicletype.h" -namespace Marklin { +namespace R2C2 { class Catalogue3D; @@ -42,6 +42,6 @@ private: Msp::GL::Mesh *create_flat_wagon(const std::map &); }; -} // namespace Marklin +} // namespace R2C2 #endif diff --git a/source/designer/cameracontroller.cpp b/source/designer/cameracontroller.cpp index edebff7..6b98f3d 100644 --- a/source/designer/cameracontroller.cpp +++ b/source/designer/cameracontroller.cpp @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -12,7 +12,7 @@ Distributed under the GPL using namespace std; using namespace Msp; -using namespace Marklin; +using namespace R2C2; CameraController::CameraController(Designer &d, Graphics::EventSource &es, GL::Camera &c): designer(d), diff --git a/source/designer/cameracontroller.h b/source/designer/cameracontroller.h index beed68a..b18e251 100644 --- a/source/designer/cameracontroller.h +++ b/source/designer/cameracontroller.h @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ diff --git a/source/designer/designer.cpp b/source/designer/designer.cpp index 23185cf..8ab0465 100644 --- a/source/designer/designer.cpp +++ b/source/designer/designer.cpp @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -26,8 +26,8 @@ Distributed under the GPL #include #include #include -#include "libmarklin/route.h" -#include "libmarklin/tracktype.h" +#include "libr2c2/route.h" +#include "libr2c2/tracktype.h" #include "3d/path.h" #include "designer.h" #include "input.h" @@ -38,14 +38,14 @@ Distributed under the GPL #include "toolbar.h" using namespace std; -using namespace Marklin; +using namespace R2C2; using namespace Msp; Application::RegApp Designer::reg; Designer::Designer(int argc, char **argv): window(1280, 960), - ui_res("marklin.res"), + ui_res("r2c2.res"), root(ui_res, window), base_object(0), cur_route(0), diff --git a/source/designer/designer.h b/source/designer/designer.h index c173668..9fc2961 100644 --- a/source/designer/designer.h +++ b/source/designer/designer.h @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -21,8 +21,8 @@ Distributed under the GPL #include #include #include -#include "libmarklin/catalogue.h" -#include "libmarklin/layout.h" +#include "libr2c2/catalogue.h" +#include "libr2c2/layout.h" #include "3d/layout.h" #include "3d/overlay.h" #include "3d/track.h" @@ -53,15 +53,15 @@ private: Toolbar *toolbar; Msp::GLtk::Label *lbl_status; - Marklin::Catalogue catalogue; - Marklin::Layout3D *cat_layout_3d; + R2C2::Catalogue catalogue; + R2C2::Layout3D *cat_layout_3d; std::string filename; - Marklin::Layout *layout; - Marklin::Layout3D *layout_3d; - Marklin::Overlay3D *overlay; + R2C2::Layout *layout; + R2C2::Layout3D *layout_3d; + R2C2::Overlay3D *overlay; Msp::GL::Object *base_object; - Marklin::Route *cur_route; - std::list new_tracks; + R2C2::Route *cur_route; + std::list new_tracks; Msp::GL::Pipeline *pipeline; Msp::GL::Camera camera; Msp::GL::Lighting lighting; @@ -86,9 +86,9 @@ public: void save(); void quit(); - const Marklin::Catalogue &get_catalogue() const { return catalogue; } - Marklin::Layout &get_layout() { return *layout; } - Marklin::Layout3D &get_layout_3d() { return *layout_3d; } + const R2C2::Catalogue &get_catalogue() const { return catalogue; } + R2C2::Layout &get_layout() { return *layout; } + R2C2::Layout3D &get_layout_3d() { return *layout_3d; } const CameraController &get_camera_controller() const { return camera_ctl; } const Msp::GLtk::Resources &get_ui_resources() const { return ui_res; } Msp::GLtk::Root &get_root() { return root; } @@ -99,11 +99,11 @@ public: void rename_route(); void svg_export(); - void edit_route(Marklin::Route *); - Marklin::Route *get_current_route() const { return cur_route; } + void edit_route(R2C2::Route *); + R2C2::Route *get_current_route() const { return cur_route; } void add_selection_to_route(); - Marklin::Point map_pointer_to_ground(int, int); + R2C2::Point map_pointer_to_ground(int, int); private: void tick(); void key_press(unsigned, unsigned, wchar_t); @@ -111,10 +111,10 @@ private: void pointer_motion(int, int); void apply_camera(); void render(); - void track_added(Marklin::Track &); - void track_removed(Marklin::Track &); - Marklin::Track3D *pick_track(int, int); - void update_track_icon(Marklin::Track3D &); + void track_added(R2C2::Track &); + void track_removed(R2C2::Track &); + R2C2::Track3D *pick_track(int, int); + void update_track_icon(R2C2::Track3D &); void selection_changed(); void manipulation_status(const std::string &); void manipulation_done(bool); @@ -125,7 +125,7 @@ private: void route_name_accept(const std::string &); void svg_export_accept(const std::string &); std::string tooltip(int, int); - void show_route(const Marklin::Route *); + void show_route(const R2C2::Route *); }; #endif diff --git a/source/designer/input.cpp b/source/designer/input.cpp index 26bf9f2..9476bad 100644 --- a/source/designer/input.cpp +++ b/source/designer/input.cpp @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2006-2008, 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ diff --git a/source/designer/input.h b/source/designer/input.h index e3fc7c3..a9ecfe1 100644 --- a/source/designer/input.h +++ b/source/designer/input.h @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2006-2008, 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ diff --git a/source/designer/manipulator.cpp b/source/designer/manipulator.cpp index 3008021..23ea138 100644 --- a/source/designer/manipulator.cpp +++ b/source/designer/manipulator.cpp @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -8,13 +8,13 @@ Distributed under the GPL #include #include #include -#include "libmarklin/tracktype.h" +#include "libr2c2/tracktype.h" #include "designer.h" #include "manipulator.h" #include "selection.h" using namespace std; -using namespace Marklin; +using namespace R2C2; using namespace Msp; Manipulator::Manipulator(Designer &d, Graphics::EventSource &es, Selection &s): @@ -562,7 +562,7 @@ void Manipulator::set_slope(TrackOrder &track, float z, float dz) } } -vector Manipulator::create_straight(const Marklin::Point &start, float dir, float length, float limit) +vector Manipulator::create_straight(const R2C2::Point &start, float dir, float length, float limit) { const Catalogue::TrackMap &track_types = designer.get_catalogue().get_tracks(); std::map types_by_length; diff --git a/source/designer/manipulator.h b/source/designer/manipulator.h index 55d2425..66b5d1a 100644 --- a/source/designer/manipulator.h +++ b/source/designer/manipulator.h @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2006-2008 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -27,19 +27,19 @@ private: struct MTrack { - Marklin::Track *track; - Marklin::Point pos; + R2C2::Track *track; + R2C2::Point pos; float rot; - MTrack(Marklin::Track *); + MTrack(R2C2::Track *); }; struct TrackOrder { - Marklin::Track *track; + R2C2::Track *track; bool rev; - TrackOrder(Marklin::Track *t, bool r): track(t), rev(r) { } + TrackOrder(R2C2::Track *t, bool r): track(t), rev(r) { } }; public: @@ -51,17 +51,17 @@ private: Msp::Graphics::EventSource &event_source; Selection &selection; std::vector tracks; - Marklin::Point center; + R2C2::Point center; - Marklin::Point gpointer; + R2C2::Point gpointer; int pointer_y; Mode mode; - Marklin::Point move_origin; + R2C2::Point move_origin; float angle; float rot_origin; int elev_origin; - std::set neighbors; - std::vector extend_tracks; + std::set neighbors; + std::vector extend_tracks; public: Manipulator(Designer &, Msp::Graphics::EventSource &, Selection &); @@ -82,7 +82,7 @@ private: void update_tracks(); void update_neighbors(); void set_slope(TrackOrder &, float, float); - std::vector create_straight(const Marklin::Point &, float, float, float); + std::vector create_straight(const R2C2::Point &, float, float, float); }; #endif diff --git a/source/designer/measure.cpp b/source/designer/measure.cpp index 201674c..56efc1b 100644 --- a/source/designer/measure.cpp +++ b/source/designer/measure.cpp @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2006-2008 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -12,7 +12,7 @@ Distributed under the GPL #include "measure.h" using namespace std; -using namespace Marklin; +using namespace R2C2; using namespace Msp; Measure::Measure(Designer &d): diff --git a/source/designer/measure.h b/source/designer/measure.h index f68178d..6800ecc 100644 --- a/source/designer/measure.h +++ b/source/designer/measure.h @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2006-2008 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -28,8 +28,8 @@ public: private: Designer &designer; - Marklin::Point pointer; - Marklin::Point spoint; + R2C2::Point pointer; + R2C2::Point spoint; float sdir; float par_dist; float perp_dist; @@ -46,7 +46,7 @@ public: void pointer_motion(int, int, float, float); void render(); private: - void snap_to_tracks(Marklin::Point &, float &); + void snap_to_tracks(R2C2::Point &, float &); }; #endif diff --git a/source/designer/selection.cpp b/source/designer/selection.cpp index c6b1e39..604890b 100644 --- a/source/designer/selection.cpp +++ b/source/designer/selection.cpp @@ -1,16 +1,16 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2006-2008 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ #include -#include "libmarklin/block.h" +#include "libr2c2/block.h" #include "selection.h" using namespace std; -using namespace Marklin; +using namespace R2C2; using namespace Msp; Track *Selection::get_track() const diff --git a/source/designer/selection.h b/source/designer/selection.h index 9d49c76..479f5af 100644 --- a/source/designer/selection.h +++ b/source/designer/selection.h @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2006-2008 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -18,11 +18,11 @@ public: sigc::signal signal_changed; private: - std::set tracks; + std::set tracks; public: - const std::set &get_tracks() const { return tracks; } - Marklin::Track *get_track() const; + const std::set &get_tracks() const { return tracks; } + R2C2::Track *get_track() const; unsigned size() const { return tracks.size(); } void clear(); @@ -35,9 +35,9 @@ public: signal_changed.emit(); } - void add_track(Marklin::Track *); - void remove_track(Marklin::Track *); - void toggle_track(Marklin::Track *); + void add_track(R2C2::Track *); + void remove_track(R2C2::Track *); + void toggle_track(R2C2::Track *); void select_more(); void select_linked(); diff --git a/source/designer/svgexporter.cpp b/source/designer/svgexporter.cpp index 56945f7..a9e13f8 100644 --- a/source/designer/svgexporter.cpp +++ b/source/designer/svgexporter.cpp @@ -1,20 +1,20 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ #include #include -#include "libmarklin/catalogue.h" -#include "libmarklin/track.h" -#include "libmarklin/tracktype.h" +#include "libr2c2/catalogue.h" +#include "libr2c2/track.h" +#include "libr2c2/tracktype.h" #include "svgexporter.h" using namespace std; using namespace Msp; -using namespace Marklin; +using namespace R2C2; SvgExporter::SvgExporter(const Layout &l): layout(l), diff --git a/source/designer/svgexporter.h b/source/designer/svgexporter.h index 6e93ca4..38d77a9 100644 --- a/source/designer/svgexporter.h +++ b/source/designer/svgexporter.h @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -9,21 +9,21 @@ Distributed under the GPL #define SVGEXPORTER_H_ #include -#include "libmarklin/layout.h" +#include "libr2c2/layout.h" class SvgExporter { private: - const Marklin::Layout &layout; + const R2C2::Layout &layout; float gauge; float rail_width; public: - SvgExporter(const Marklin::Layout &); + SvgExporter(const R2C2::Layout &); void save(const std::string &); private: - void save_track(const Marklin::Track &, xmlpp::Element &); + void save_track(const R2C2::Track &, xmlpp::Element &); }; #endif diff --git a/source/designer/toolbar.cpp b/source/designer/toolbar.cpp index 56a5d6d..c6d859b 100644 --- a/source/designer/toolbar.cpp +++ b/source/designer/toolbar.cpp @@ -1,19 +1,19 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2009-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ #include #include -#include "libmarklin/route.h" +#include "libr2c2/route.h" #include "designer.h" #include "toolbar.h" using namespace std; using namespace Msp; -using namespace Marklin; +using namespace R2C2; Toolbar::Toolbar(Designer &d): designer(d) diff --git a/source/designer/toolbar.h b/source/designer/toolbar.h index 2a935d3..9029a9c 100644 --- a/source/designer/toolbar.h +++ b/source/designer/toolbar.h @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2009 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -11,7 +11,7 @@ Distributed under the GPL #include #include #include -#include "libmarklin/route.h" +#include "libr2c2/route.h" class Designer; @@ -26,7 +26,7 @@ public: private: void route_selected(unsigned, const std::string &); void delete_route_clicked(); - void route_added(Marklin::Route &); + void route_added(R2C2::Route &); void update_routes(); }; diff --git a/source/designer/trackwrap.cpp b/source/designer/trackwrap.cpp index b507075..65c33d5 100644 --- a/source/designer/trackwrap.cpp +++ b/source/designer/trackwrap.cpp @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -14,7 +14,7 @@ Distributed under the GPL using namespace std; using namespace Msp; -using namespace Marklin; +using namespace R2C2; TrackWrap::TrackWrap(Designer &d, Selection &s): designer(d), diff --git a/source/designer/trackwrap.h b/source/designer/trackwrap.h index 09bacda..2f21125 100644 --- a/source/designer/trackwrap.h +++ b/source/designer/trackwrap.h @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -10,7 +10,7 @@ Distributed under the GPL #include #include -#include "libmarklin/track.h" +#include "libr2c2/track.h" class Designer; class Selection; @@ -20,13 +20,13 @@ class TrackWrap: public Msp::GL::Renderable private: struct Wrap { - Marklin::Track *track; + R2C2::Track *track; Msp::GL::Mesh *mesh; }; Designer &designer; Selection &selection; - std::map meshes; + std::map meshes; std::list wraps; public: @@ -36,7 +36,7 @@ public: private: void selection_changed(); - Msp::GL::Mesh &get_mesh(const Marklin::TrackType &); + Msp::GL::Mesh &get_mesh(const R2C2::TrackType &); }; #endif diff --git a/source/engineer/dialog.cpp b/source/engineer/dialog.cpp index e71c1ce..2d2bae3 100644 --- a/source/engineer/dialog.cpp +++ b/source/engineer/dialog.cpp @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2009 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ diff --git a/source/engineer/dialog.h b/source/engineer/dialog.h index 5fb694f..0299287 100644 --- a/source/engineer/dialog.h +++ b/source/engineer/dialog.h @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2009 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ diff --git a/source/engineer/engineer.cpp b/source/engineer/engineer.cpp index 7e13f7b..1f3b7dc 100644 --- a/source/engineer/engineer.cpp +++ b/source/engineer/engineer.cpp @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -25,8 +25,8 @@ Distributed under the GPL #include #include #include -#include "libmarklin/driver.h" -#include "libmarklin/tracktype.h" +#include "libr2c2/driver.h" +#include "libr2c2/tracktype.h" #include "3d/path.h" #include "3d/track.h" #include "3d/vehicle.h" @@ -37,7 +37,7 @@ Distributed under the GPL #include "trainview.h" using namespace std; -using namespace Marklin; +using namespace R2C2; using namespace Msp; Application::RegApp Engineer::reg; @@ -61,7 +61,7 @@ Engineer::Engineer(int argc, char **argv): window.set_title("Railroad Engineer"); window.signal_close.connect(sigc::bind(sigc::mem_fun(this, &Engineer::exit), 0)); - DataFile::load(ui_res, "marklin.res"); + DataFile::load(ui_res, "r2c2.res"); root = new GLtk::Root(ui_res, window); root->signal_button_press.connect(sigc::mem_fun(this, &Engineer::button_press)); root->signal_pointer_motion.connect(sigc::mem_fun(this, &Engineer::pointer_motion)); diff --git a/source/engineer/engineer.h b/source/engineer/engineer.h index 61a2f59..4ca753e 100644 --- a/source/engineer/engineer.h +++ b/source/engineer/engineer.h @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -16,8 +16,8 @@ Distributed under the GPL #include #include #include -#include "libmarklin/catalogue.h" -#include "libmarklin/train.h" +#include "libr2c2/catalogue.h" +#include "libr2c2/train.h" #include "3d/layout.h" #include "3d/overlay.h" #include "3d/path.h" @@ -31,7 +31,7 @@ class TrainView; class Engineer: public Msp::Application { public: - sigc::signal signal_pick_done; + sigc::signal signal_pick_done; private: Options options; @@ -40,13 +40,13 @@ private: Msp::GLtk::Resources ui_res; Msp::GLtk::Root *root; - Marklin::Catalogue catalogue; - Marklin::Layout layout; - Marklin::Layout3D layout_3d; - Marklin::Server *server; + R2C2::Catalogue catalogue; + R2C2::Layout layout; + R2C2::Layout3D layout_3d; + R2C2::Server *server; Msp::IO::EventDispatcher event_disp; - Marklin::Overlay3D *overlay; - std::map train_colors; + R2C2::Overlay3D *overlay; + std::map train_colors; Msp::GL::Camera camera; Msp::GL::Lighting lighting; @@ -59,9 +59,9 @@ private: std::list train_views; Msp::Time::TimeStamp status_timeout; bool picking; - Marklin::Track *picking_track; + R2C2::Track *picking_track; int picking_entry; - Marklin::Path3D *picking_path; + R2C2::Path3D *picking_path; int pointer_x; int pointer_y; bool pointer_moved; @@ -72,9 +72,9 @@ public: const Msp::GLtk::Resources &get_ui_resources() const { return ui_res; } Msp::GLtk::Root &get_root() const { return *root; } - const Marklin::Catalogue &get_catalogue() const { return catalogue; } - Marklin::Layout &get_layout() { return layout; } - Marklin::Layout3D &get_layout_3d() { return layout_3d; } + const R2C2::Catalogue &get_catalogue() const { return catalogue; } + R2C2::Layout &get_layout() { return layout; } + R2C2::Layout3D &get_layout_3d() { return layout_3d; } const Msp::GL::Lighting &get_lighting() const { return lighting; } void set_status(const std::string &); void rearrange_panels(); @@ -88,12 +88,12 @@ private: void button_press(int, int, unsigned, unsigned); void pointer_motion(int, int); void view_all(); - void set_block_color(const Marklin::Block &, const Msp::GL::Color &); - void reset_block_color(const Marklin::Block &); + void set_block_color(const R2C2::Block &, const Msp::GL::Color &); + void reset_block_color(const R2C2::Block &); void sensor_event(unsigned, bool); - void block_reserved(const Marklin::Block &, const Marklin::Train *); - Marklin::Track3D *pick_track(int, int); - void train_added(Marklin::Train &); + void block_reserved(const R2C2::Block &, const R2C2::Train *); + R2C2::Track3D *pick_track(int, int); + void train_added(R2C2::Train &); virtual void sighandler(int); static Msp::Application::RegApp reg; diff --git a/source/engineer/mainpanel.cpp b/source/engineer/mainpanel.cpp index 8a292b4..667e95f 100644 --- a/source/engineer/mainpanel.cpp +++ b/source/engineer/mainpanel.cpp @@ -1,12 +1,12 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ #include -#include "libmarklin/driver.h" +#include "libr2c2/driver.h" #include "engineer.h" #include "mainpanel.h" #include "trainproperties.h" @@ -59,7 +59,7 @@ MainPanel::MainPanel(Engineer &e): lbl_status->set_geometry(GLtk::Geometry(10, 10, 180, 20)); lbl_status->set_style("digital"); - Marklin::Driver &driver = engineer.get_layout().get_driver(); + R2C2::Driver &driver = engineer.get_layout().get_driver(); if(driver.get_power()) ind_on->set_active(true); else @@ -86,7 +86,7 @@ void MainPanel::power_off() void MainPanel::toggle_halt() { - Marklin::Driver &driver = engineer.get_layout().get_driver(); + R2C2::Driver &driver = engineer.get_layout().get_driver(); driver.halt(!driver.is_halted()); } diff --git a/source/engineer/mainpanel.h b/source/engineer/mainpanel.h index 17e95db..a4b62b7 100644 --- a/source/engineer/mainpanel.h +++ b/source/engineer/mainpanel.h @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2006-2008 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ diff --git a/source/engineer/options.cpp b/source/engineer/options.cpp index fc7516c..b5c36cd 100644 --- a/source/engineer/options.cpp +++ b/source/engineer/options.cpp @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ diff --git a/source/engineer/options.h b/source/engineer/options.h index 689b22a..e35cc92 100644 --- a/source/engineer/options.h +++ b/source/engineer/options.h @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ diff --git a/source/engineer/routeselect.cpp b/source/engineer/routeselect.cpp index 0e19149..00bf6cf 100644 --- a/source/engineer/routeselect.cpp +++ b/source/engineer/routeselect.cpp @@ -1,18 +1,18 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2009 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ #include #include "engineer.h" -#include "libmarklin/route.h" +#include "libr2c2/route.h" #include "routeselect.h" using namespace std; using namespace Msp; -using namespace Marklin; +using namespace R2C2; RouteSelect::RouteSelect(Engineer &e, Train &t): engineer(e), diff --git a/source/engineer/routeselect.h b/source/engineer/routeselect.h index f6110c5..6552175 100644 --- a/source/engineer/routeselect.h +++ b/source/engineer/routeselect.h @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2009 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -9,7 +9,7 @@ Distributed under the GPL #define ROUTESELECT_H_ #include -#include "libmarklin/train.h" +#include "libr2c2/train.h" #include "dialog.h" class Engineer; @@ -18,11 +18,11 @@ class RouteSelect: public Dialog { private: Engineer &engineer; - Marklin::Train &train; + R2C2::Train &train; Msp::GLtk::Dropdown *drp_route; public: - RouteSelect(Engineer &, Marklin::Train &); + RouteSelect(Engineer &, R2C2::Train &); private: virtual void on_ok_clicked(); }; diff --git a/source/engineer/timetabledialog.cpp b/source/engineer/timetabledialog.cpp index 52f391c..2e50099 100644 --- a/source/engineer/timetabledialog.cpp +++ b/source/engineer/timetabledialog.cpp @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -12,7 +12,7 @@ Distributed under the GPL using namespace std; using namespace Msp; -using namespace Marklin; +using namespace R2C2; TimetableDialog::TimetableDialog(Timetable &tt): timetable(tt) diff --git a/source/engineer/timetabledialog.h b/source/engineer/timetabledialog.h index a1f611d..9c06fc8 100644 --- a/source/engineer/timetabledialog.h +++ b/source/engineer/timetabledialog.h @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -11,17 +11,17 @@ Distributed under the GPL #include #include #include -#include "libmarklin/timetable.h" +#include "libr2c2/timetable.h" class TimetableDialog: public Msp::GLtk::Dialog { private: - Marklin::Timetable &timetable; + R2C2::Timetable &timetable; Msp::GLtk::Entry *ent_timetable; Msp::GLtk::Toggle *tgl_enabled; public: - TimetableDialog(Marklin::Timetable &); + TimetableDialog(R2C2::Timetable &); private: void enabled_toggled(bool); diff --git a/source/engineer/trainpanel.cpp b/source/engineer/trainpanel.cpp index 23e26ee..5d237ec 100644 --- a/source/engineer/trainpanel.cpp +++ b/source/engineer/trainpanel.cpp @@ -1,15 +1,15 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ #include #include -#include "libmarklin/timetable.h" -#include "libmarklin/trackiter.h" -#include "libmarklin/vehicletype.h" +#include "libr2c2/timetable.h" +#include "libr2c2/trackiter.h" +#include "libr2c2/vehicletype.h" #include "engineer.h" #include "routeselect.h" #include "timetabledialog.h" @@ -19,7 +19,7 @@ Distributed under the GPL using namespace std; using namespace Msp; -using namespace Marklin; +using namespace R2C2; TrainPanel::TrainPanel(Engineer &e, Train &t): engineer(e), diff --git a/source/engineer/trainpanel.h b/source/engineer/trainpanel.h index 9a38ca4..d74ccbf 100644 --- a/source/engineer/trainpanel.h +++ b/source/engineer/trainpanel.h @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -14,8 +14,8 @@ Distributed under the GPL #include #include #include -#include "libmarklin/route.h" -#include "libmarklin/train.h" +#include "libr2c2/route.h" +#include "libr2c2/train.h" class Engineer; @@ -23,7 +23,7 @@ class TrainPanel: public Msp::GLtk::Panel, public sigc::trackable { private: Engineer &engineer; - Marklin::Train &train; + R2C2::Train &train; Msp::GLtk::Panel *pnl_basic; Msp::GLtk::Panel *pnl_extra; Msp::GLtk::Button *btn_expand; @@ -39,13 +39,13 @@ private: bool expanded; public: - TrainPanel(Engineer &, Marklin::Train &); + TrainPanel(Engineer &, R2C2::Train &); void expand(bool = true); private: void train_control_changed(const std::string &, float); void train_function_changed(unsigned, bool); - void train_route_changed(const Marklin::Route *); + void train_route_changed(const R2C2::Route *); void train_status_changed(const std::string &); void place_clicked(); void take_clicked(); @@ -58,8 +58,8 @@ private: void speed_slider_changed(double); void forward_toggled(bool); void func_toggled(bool, unsigned); - void place(Marklin::Track *, unsigned); - void go_to(Marklin::Track *, unsigned); + void place(R2C2::Track *, unsigned); + void go_to(R2C2::Track *, unsigned); }; #endif diff --git a/source/engineer/trainproperties.cpp b/source/engineer/trainproperties.cpp index eaddc8b..9686dee 100644 --- a/source/engineer/trainproperties.cpp +++ b/source/engineer/trainproperties.cpp @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -8,15 +8,15 @@ Distributed under the GPL #include #include #include -#include "libmarklin/driver.h" -#include "libmarklin/vehicle.h" -#include "libmarklin/vehicletype.h" +#include "libr2c2/driver.h" +#include "libr2c2/vehicle.h" +#include "libr2c2/vehicletype.h" #include "engineer.h" #include "trainproperties.h" using namespace std; using namespace Msp; -using namespace Marklin; +using namespace R2C2; TrainProperties::TrainProperties(Engineer &e, Train *t): engineer(e), diff --git a/source/engineer/trainproperties.h b/source/engineer/trainproperties.h index 465154d..2445833 100644 --- a/source/engineer/trainproperties.h +++ b/source/engineer/trainproperties.h @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -10,7 +10,7 @@ Distributed under the GPL #include #include -#include +#include #include "dialog.h" class Engineer; @@ -19,7 +19,7 @@ class TrainProperties: public Dialog { private: Engineer &engineer; - Marklin::Train *train; + R2C2::Train *train; Msp::GLtk::Entry *ent_addr; Msp::GLtk::Dropdown *drp_protocol; Msp::GLtk::Dropdown *drp_type; @@ -27,16 +27,16 @@ private: Msp::GLtk::Dropdown *drp_priority; Msp::GLtk::List *lst_vehicles; Msp::GLtk::Dropdown *drp_new_vehicle; - std::vector add_vehicles; + std::vector add_vehicles; std::set rem_vehicles; public: - TrainProperties(Engineer &, Marklin::Train *); + TrainProperties(Engineer &, R2C2::Train *); private: virtual void on_ok_clicked(); void new_vehicle_selected(unsigned, const std::string &); void remove_vehicle_clicked(); - const Marklin::VehicleType &get_vehicle_type(unsigned, bool); + const R2C2::VehicleType &get_vehicle_type(unsigned, bool); }; #endif diff --git a/source/engineer/trainview.cpp b/source/engineer/trainview.cpp index df336d5..f282b4e 100644 --- a/source/engineer/trainview.cpp +++ b/source/engineer/trainview.cpp @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -8,13 +8,13 @@ Distributed under the GPL #include #include #include -#include "libmarklin/vehicle.h" -#include "libmarklin/vehicletype.h" +#include "libr2c2/vehicle.h" +#include "libr2c2/vehicletype.h" #include "engineer.h" #include "trainview.h" using namespace Msp; -using namespace Marklin; +using namespace R2C2; TrainView::TrainView(Engineer &e, const Train &t): engineer(e), diff --git a/source/engineer/trainview.h b/source/engineer/trainview.h index a452a71..c7ba7b9 100644 --- a/source/engineer/trainview.h +++ b/source/engineer/trainview.h @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -13,7 +13,7 @@ Distributed under the GPL #include #include #include -#include "libmarklin/train.h" +#include "libr2c2/train.h" class Engineer; @@ -29,7 +29,7 @@ public: private: Engineer &engineer; - const Marklin::Train &train; + const R2C2::Train &train; Msp::GLtk::Toggle *tgl_forward; Mode mode; bool forward; @@ -41,7 +41,7 @@ private: bool stale; public: - TrainView(Engineer &, const Marklin::Train &); + TrainView(Engineer &, const R2C2::Train &); ~TrainView(); void set_mode(Mode); diff --git a/source/libmarklin/aicontrol.cpp b/source/libmarklin/aicontrol.cpp deleted file mode 100644 index 553159c..0000000 --- a/source/libmarklin/aicontrol.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#include "aicontrol.h" -#include "catalogue.h" -#include "layout.h" -#include "train.h" - -using namespace std; -using namespace Msp; - -namespace Marklin { - -AIControl::AIControl(Train &t, Controller *n): - train(t), - next_ctrl(n), - target_speed(Control::continuous("speed", 0, 1000)), - blocked(false), - approach(false) -{ - target_speed.set(0); - - train.signal_arrived.connect(sigc::mem_fun(this, &AIControl::arrived)); - next_ctrl->signal_control_changed.connect(sigc::mem_fun(this, &AIControl::control_changed)); -} - -AIControl::~AIControl() -{ - delete next_ctrl; -} - -void AIControl::set_control(const string &n, float v) -{ - if(n=="speed") - { - if(v && !train.is_active()) - train.set_active(true); - - target_speed.set(v); - if(!blocked) - { - float approach_speed = 5*train.get_layout().get_catalogue().get_scale(); - if(approach && target_speed.value>approach_speed) - next_ctrl->set_control("speed", approach_speed); - else - next_ctrl->set_control("speed", target_speed.value); - } - - signal_control_changed.emit(target_speed); - } - else - next_ctrl->set_control(n, v); -} - -const Controller::Control &AIControl::get_control(const string &n) const -{ - if(n=="speed") - return target_speed; - else - return next_ctrl->get_control(n); -} - -float AIControl::get_speed() const -{ - return next_ctrl->get_speed(); -} - -bool AIControl::get_reverse() const -{ - return next_ctrl->get_reverse(); -} - -float AIControl::get_braking_distance() const -{ - return next_ctrl->get_braking_distance(); -} - -void AIControl::tick(const Time::TimeDelta &dt) -{ - float scale = train.get_layout().get_catalogue().get_scale(); - float rsv_dist = train.get_reserved_distance(); - float brake_dist = next_ctrl->get_braking_distance(); - float approach_margin = 50*scale; - float approach_speed = 5*scale; - float margin = 10*scale; - - if(!blocked && rsv_distset_control("speed", 0); - } - else if((!approach && rsv_distbrake_dist+margin*2)) - { - blocked = false; - approach = true; - if(target_speed.value>approach_speed) - next_ctrl->set_control("speed", approach_speed); - else - next_ctrl->set_control("speed", target_speed.value); - } - else if((blocked || approach) && rsv_dist>brake_dist*1.3+approach_margin*2) - { - blocked = false; - approach = false; - next_ctrl->set_control("speed", target_speed.value); - } - - next_ctrl->tick(dt); - - if(!target_speed.value && !next_ctrl->get_speed() && train.is_active()) - train.set_active(false); -} - -void AIControl::control_changed(const Control &ctrl) -{ - if(ctrl.name!="speed") - signal_control_changed.emit(ctrl); -} - -void AIControl::arrived() -{ - set_control("speed", 0); -} - -} // namespace Marklin diff --git a/source/libmarklin/aicontrol.h b/source/libmarklin/aicontrol.h deleted file mode 100644 index 462a114..0000000 --- a/source/libmarklin/aicontrol.h +++ /dev/null @@ -1,47 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#ifndef LIBMARKLIN_AICONTROL_H_ -#define LIBMARKLIN_AICONTROL_H_ - -#include -#include "controller.h" - -namespace Marklin { - -class Train; - -class AIControl: public Controller, public sigc::trackable -{ -private: - Train &train; - Controller *next_ctrl; - Control target_speed; - bool blocked; - bool approach; - -public: - AIControl(Train &, Controller *); - virtual ~AIControl(); - - virtual void set_control(const std::string &, float); - virtual const Control &get_control(const std::string &) const; - - virtual float get_speed() const; - virtual bool get_reverse() const; - virtual float get_braking_distance() const; - - virtual void tick(const Msp::Time::TimeDelta &); - -private: - void control_changed(const Control &); - void arrived(); -}; - -} // namespace Marklin - -#endif diff --git a/source/libmarklin/articlenumber.cpp b/source/libmarklin/articlenumber.cpp deleted file mode 100644 index cac3b32..0000000 --- a/source/libmarklin/articlenumber.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#include -#include "articlenumber.h" - -using namespace std; -using namespace Msp; - -namespace Marklin { - -ArticleNumber::ArticleNumber(unsigned n) -{ - Part part; - part.number = n; - part.letter = 0; - parts.push_back(part); -} - -ArticleNumber::ArticleNumber(const string &s) -{ - vector sparts = split(s, '-'); - for(vector::iterator i=sparts.begin(); i!=sparts.end(); ++i) - { - if(i->empty()) - throw InvalidParameterValue("Malformed article number"); - - unsigned nondigit = i->size(); - for(unsigned j=0; jsize(); ++j) - if(!isdigit((*i)[j])) - { - nondigit = j; - break; - } - - if(!nondigit || nondigitsize()-1) - throw InvalidParameterValue("Malformed article number"); - - Part part; - part.number = lexical_cast(i->substr(0, nondigit)); - part.letter = nondigitsize() ? (*i)[nondigit] : 0; - parts.push_back(part); - } -} - -string ArticleNumber::str() const -{ - string result; - for(vector::const_iterator i=parts.begin(); i!=parts.end(); ++i) - { - if(!result.empty()) - result += '-'; - - result += lexical_cast(i->number); - if(i->letter) - result += i->letter; - } - - return result; -} - -bool ArticleNumber::operator<(const ArticleNumber &other) const -{ - return parts>(const LexicalConverter &conv, ArticleNumber &art_nr) -{ - art_nr = ArticleNumber(conv.get()); -} - -void operator<<(LexicalConverter &conv, const ArticleNumber &art_nr) -{ - conv.result(art_nr.str()); -} - -} // namespace Marklin diff --git a/source/libmarklin/articlenumber.h b/source/libmarklin/articlenumber.h deleted file mode 100644 index 0aa6498..0000000 --- a/source/libmarklin/articlenumber.h +++ /dev/null @@ -1,45 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#ifndef LIBMARKLIN_ARTICLENUMBER_H_ -#define LIBMARKLIN_ARTICLENUMBER_H_ - -#include -#include -#include - -namespace Marklin { - -class ArticleNumber -{ -private: - struct Part - { - unsigned number; - char letter; - - bool operator<(const Part &) const; - }; - - std::vector parts; - -public: - ArticleNumber() { } - ArticleNumber(unsigned); - ArticleNumber(const std::string &); - - std::string str() const; - - bool operator<(const ArticleNumber &) const; -}; - -void operator>>(const Msp::LexicalConverter &, ArticleNumber &); -void operator<<(Msp::LexicalConverter &, const ArticleNumber &); - -} // namespace Marklin - -#endif diff --git a/source/libmarklin/block.cpp b/source/libmarklin/block.cpp deleted file mode 100644 index e8e367f..0000000 --- a/source/libmarklin/block.cpp +++ /dev/null @@ -1,222 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#include -#include "block.h" -#include "layout.h" -#include "route.h" -#include "trackiter.h" -#include "tracktype.h" - -using namespace std; -using namespace Msp; - -namespace Marklin { - -Block::Block(Layout &l, Track &start): - layout(l), - id(0), - sensor_id(start.get_sensor_id()), - turnout_id(start.get_turnout_id()), - train(0) -{ - tracks.insert(&start); - start.set_block(this); - - list queue; - queue.push_back(&start); - - while(!queue.empty()) - { - Track *track = queue.front(); - queue.erase(queue.begin()); - - const vector &links = track->get_links(); - for(unsigned i=0; iget_sensor_id()==sensor_id && links[i]->get_turnout_id()==turnout_id) - { - queue.push_back(links[i]); - tracks.insert(links[i]); - links[i]->set_block(this); - } - else - endpoints.push_back(Endpoint(track, i)); - } - } - - determine_id(); - - for(unsigned i=0; i trks = tracks; - tracks.clear(); - for(set::iterator i=trks.begin(); i!=trks.end(); ++i) - (*i)->set_block(0); - - for(vector::iterator i=endpoints.begin(); i!=endpoints.end(); ++i) - if(Block *blk = i->link) - { - i->link = 0; - blk->break_link(*this); - } - - layout.remove_block(*this); -} - -bool Block::has_track(Track &t) const -{ - return tracks.count(&t); -} - -const Block::Endpoint &Block::get_endpoint(unsigned i) const -{ - if(i>=endpoints.size()) - throw InvalidParameterValue("Endpoint index out of range"); - - return endpoints[i]; -} - -int Block::get_endpoint_by_link(Block &other) const -{ - for(unsigned i=0; i=endpoints.size()) - throw InvalidParameterValue("Endpoint index out of range"); - - TrackIter t_iter(endpoints[entry].track, endpoints[entry].track_ep); - - float result = 0; - while(t_iter && has_track(*t_iter)) - { - unsigned path = (route ? route->get_path(*t_iter) : t_iter->get_active_path()); - result += t_iter->get_type().get_path_length(path); - - t_iter = t_iter.next(path); - } - - return result; -} - -void Block::check_link(Block &other) -{ - for(vector::iterator i=endpoints.begin(); i!=endpoints.end(); ++i) - { - if(i->link) - continue; - - for(vector::iterator j=other.endpoints.begin(); j!=other.endpoints.end(); ++j) - if(j->track==i->track->get_link(i->track_ep) && j->track->get_link(j->track_ep)==i->track && !j->link) - { - i->link = &other; - j->link = this; - - determine_id(); - other.determine_id(); - } - } -} - -void Block::break_link(Block &other) -{ - for(vector::iterator i=endpoints.begin(); i!=endpoints.end(); ++i) - if(i->link==&other) - { - i->link = 0; - other.break_link(*this); - determine_id(); - } -} - -Block *Block::get_link(unsigned epi) const -{ - if(epi>=endpoints.size()) - throw InvalidParameterValue("Endpoint index out of range"); - return endpoints[epi].link; -} - -bool Block::reserve(Train *t) -{ - if(!t || !train) - { - train = t; - layout.signal_block_reserved.emit(*this, train); - return true; - } - else - return false; -} - -void Block::find_paths(TrackIter track, unsigned path) -{ - unsigned mask = track.endpoint().paths; - for(unsigned i=0; mask>>i; ++i) - if(mask&(1<::iterator j=endpoints.begin(); j!=endpoints.end(); ++j) - if(j->track==next.track() && j->track_ep==next.entry()) - j->paths |= path; - } - } -} - -void Block::determine_id() -{ - if(sensor_id) - id = 0x1000|sensor_id; - else if(turnout_id) - id = 0x2000|turnout_id; - else if(endpoints.size()==2) - { - unsigned id1 = endpoints[0].link ? endpoints[0].link->get_id() : 1; - unsigned id2 = endpoints[1].link ? endpoints[1].link->get_id() : 1; - if(id2get_id() : 1; - id = 0x10000 | id1; - } -} - - -Block::Endpoint::Endpoint(Track *t, unsigned e): - track(t), - track_ep(e), - link(0), - paths(0) -{ } - -} // namespace Marklin diff --git a/source/libmarklin/block.h b/source/libmarklin/block.h deleted file mode 100644 index 41f9040..0000000 --- a/source/libmarklin/block.h +++ /dev/null @@ -1,70 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#ifndef LIBMARKLIN_BLOCK_H_ -#define LIBMARKLIN_BLOCK_H_ - -#include -#include -#include "track.h" - -namespace Marklin { - -class Layout; -class Route; -class TrackIter; -class Train; - -class Block -{ -public: - struct Endpoint - { - Track *track; - unsigned track_ep; - Block *link; - unsigned paths; - - Endpoint(Track *, unsigned); - }; - -private: - Layout &layout; - unsigned id; - unsigned sensor_id; - unsigned turnout_id; - std::set tracks; - std::vector endpoints; - Train *train; - -public: - Block(Layout &, Track &); - ~Block(); - - unsigned get_id() const { return id; } - unsigned get_sensor_id() const { return sensor_id; } - unsigned get_turnout_id() const { return turnout_id; } - const std::set &get_tracks() const { return tracks; } - bool has_track(Track &) const; - const std::vector &get_endpoints() const { return endpoints; } - const Endpoint &get_endpoint(unsigned) const; - int get_endpoint_by_link(Block &) const; - float get_path_length(unsigned, const Route * = 0) const; - void check_link(Block &); - void break_link(Block &); - Block *get_link(unsigned) const; - bool reserve(Train *); - Train *get_train() const { return train; } - void print_debug(); -private: - void find_paths(TrackIter, unsigned); - void determine_id(); -}; - -} // namespace Marklin - -#endif diff --git a/source/libmarklin/blockiter.cpp b/source/libmarklin/blockiter.cpp deleted file mode 100644 index 245f963..0000000 --- a/source/libmarklin/blockiter.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#include -#include "block.h" -#include "blockiter.h" -#include "route.h" -#include "trackiter.h" - -using namespace std; -using namespace Msp; - -namespace Marklin { - -BlockIter::BlockIter(): - _block(0), - _entry(0) -{ } - -BlockIter::BlockIter(Block *b, unsigned e): - _block(b), - _entry(b ? e : 0) -{ - if(_block && _entry>_block->get_endpoints().size()) - throw InvalidParameterValue("Endpoint index not valid for block"); -} - -TrackIter BlockIter::track_iter() const -{ - if(!_block) - return TrackIter(); - - const Block::Endpoint &ep = _block->get_endpoint(_entry); - return TrackIter(ep.track, ep.track_ep); -} - -const Block::Endpoint &BlockIter::endpoint() const -{ - if(!_block) - throw InvalidState("BlockIter is null"); - - return _block->get_endpoint(_entry); -} - -int BlockIter::get_exit(const Route *route) const -{ - const vector &eps = _block->get_endpoints(); - TrackIter t_iter = track_iter(); - - while(t_iter) - { - if(!_block->has_track(*t_iter)) - throw LogicError("Block traversal strayed out of the block"); - - unsigned path = (route ? route->get_path(*t_iter) : t_iter->get_active_path()); - TrackIter t_exit = t_iter.reverse(path); - - for(unsigned i=0; iget_link(exit); - result._entry = (result._block ? result._block->get_endpoint_by_link(*_block) : 0); - - return result; -} - -BlockIter BlockIter::reverse(const Route *route) const -{ - if(!_block) - return BlockIter(); - - int exit = get_exit(route); - if(exit<0) - return BlockIter(); - - return BlockIter(_block, exit); -} - -BlockIter BlockIter::flip() const -{ - if(!_block) - return BlockIter(); - - BlockIter result; - result._block = _block->get_link(_entry); - result._entry = (result._block ? result._block->get_endpoint_by_link(*_block) : 0); - - return result; -} - -Block &BlockIter::operator*() const -{ - if(!_block) - throw InvalidState("BlockIter is null"); - - return *_block; -} - -bool BlockIter::operator==(const BlockIter &other) const -{ - return _block==other._block && _entry==other._entry; -} - -} // namespace Marklin diff --git a/source/libmarklin/blockiter.h b/source/libmarklin/blockiter.h deleted file mode 100644 index c86a4e5..0000000 --- a/source/libmarklin/blockiter.h +++ /dev/null @@ -1,51 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#ifndef LIBMARKLIN_BLOCKITER_H_ -#define LIBMARKLIN_BLOCKITER_H_ - -namespace Marklin { - -class Block; -class Route; -class TrackIter; - -/** -An iterator for traversing blocks. -*/ -class BlockIter -{ -private: - Block *_block; - unsigned _entry; - -public: - BlockIter(); - BlockIter(Block *, unsigned); - - Block *block() const { return _block; } - unsigned entry() const { return _entry; } - TrackIter track_iter() const; - const Block::Endpoint &endpoint() const; - -private: - int get_exit(const Route *) const; -public: - BlockIter next(const Route * = 0) const; - BlockIter reverse(const Route * = 0) const; - BlockIter flip() const; - - Block &operator*() const; - Block *operator->() const { return _block; } - bool operator==(const BlockIter &) const; - bool operator!=(const BlockIter &other) const { return !(*this==other); } - operator bool() const { return _block!=0; } -}; - -} // namespace Marklin - -#endif diff --git a/source/libmarklin/catalogue.cpp b/source/libmarklin/catalogue.cpp deleted file mode 100644 index 82dde18..0000000 --- a/source/libmarklin/catalogue.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#include -#include -#include "catalogue.h" -#include "tracktype.h" -#include "vehicletype.h" - -using namespace std; -using namespace Msp; - -namespace Marklin { - -Catalogue::Catalogue(): - scale(1), - gauge(1.524), - layout(*this) -{ } - -Catalogue::~Catalogue() -{ - for(TrackMap::iterator i=tracks.begin(); i!=tracks.end(); ++i) - delete i->second; - for(VehicleMap::iterator i=vehicles.begin(); i!=vehicles.end(); ++i) - delete i->second; -} - -float Catalogue::get_rail_elevation() const -{ - return ballast_profile.get_height()+rail_profile.get_height(); -} - -void Catalogue::add_track(TrackType &track) -{ - if(tracks.count(track.get_article_number())) - throw Exception("Duplicate track type"); - - tracks[track.get_article_number()] = &track; - signal_track_added.emit(track); -} - -const TrackType &Catalogue::get_track(const ArticleNumber &art_nr) const -{ - TrackMap::const_iterator i=tracks.find(art_nr); - if(i==tracks.end()) - throw KeyError("Unknown track type"); - - return *i->second; -} - -void Catalogue::add_vehicle(VehicleType &veh) -{ - if(vehicles.count(veh.get_article_number())) - throw Exception("Duplicate vehicle type"); - - vehicles[veh.get_article_number()] = &veh; - signal_vehicle_added.emit(veh); -} - -const VehicleType &Catalogue::get_vehicle(const ArticleNumber &art_nr) const -{ - VehicleMap::const_iterator i = vehicles.find(art_nr); - if(i==vehicles.end()) - throw KeyError("Unknown vehicle type"); - - return *i->second; -} - - -Catalogue::Loader::Loader(Catalogue &c): - DataFile::BasicLoader(c) -{ - add("ballast_profile", &Loader::ballast_profile); - add("gauge", &Loader::gauge); - add("layout", &Loader::layout); - add("rail_profile", &Loader::rail_profile); - add("scale", &Loader::scale); - add("track", static_cast(&Loader::track)); - add("track", static_cast(&Loader::track)); - add("vehicle", static_cast(&Loader::vehicle)); - add("vehicle", static_cast(&Loader::vehicle)); -} - -void Catalogue::Loader::ballast_profile() -{ - load_sub(obj.ballast_profile); -} - -void Catalogue::Loader::gauge(float g) -{ - obj.gauge = g/1000; - obj.path_profile = Profile(); - obj.path_profile.append_point(Point(0.1*obj.gauge, 0)); - obj.path_profile.append_point(Point(-0.1*obj.gauge, 0)); -} - -void Catalogue::Loader::layout() -{ - load_sub(obj.layout); -} - -void Catalogue::Loader::rail_profile() -{ - load_sub(obj.rail_profile); -} - -void Catalogue::Loader::scale(float n, float d) -{ - obj.scale = n/d; -} - -void Catalogue::Loader::track(unsigned art_nr) -{ - track(ArticleNumber(art_nr)); -} - -void Catalogue::Loader::track(ArticleNumber art_nr) -{ - if(obj.tracks.count(art_nr)) - throw KeyError("Duplicate track type", art_nr.str()); - - RefPtr trk = new TrackType(art_nr); - load_sub(*trk); - obj.add_track(*trk.release()); -} - -void Catalogue::Loader::vehicle(unsigned art_nr) -{ - vehicle(ArticleNumber(art_nr)); -} - -void Catalogue::Loader::vehicle(ArticleNumber art_nr) -{ - if(obj.vehicles.count(art_nr)) - throw KeyError("Duplicate vehicle type", art_nr.str()); - - RefPtr veh = new VehicleType(art_nr); - load_sub(*veh); - obj.add_vehicle(*veh.release()); -} - -} // namespace Marklin diff --git a/source/libmarklin/catalogue.h b/source/libmarklin/catalogue.h deleted file mode 100644 index a436994..0000000 --- a/source/libmarklin/catalogue.h +++ /dev/null @@ -1,81 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#ifndef LIBMARKLIN_CATALOGUE_H_ -#define LIBMARKLIN_CATALOGUE_H_ - -#include -#include -#include "articlenumber.h" -#include "layout.h" -#include "profile.h" - -namespace Marklin { - -class TrackType; -class VehicleType; - -class Catalogue -{ -public: - class Loader: public Msp::DataFile::BasicLoader - { - public: - Loader(Catalogue &); - private: - void ballast_profile(); - void gauge(float); - void layout(); - void rail_profile(); - void scale(float, float); - void track(unsigned); - void track(ArticleNumber); - void vehicle(unsigned); - void vehicle(ArticleNumber); - }; - - typedef std::map TrackMap; - typedef std::map VehicleMap; - - sigc::signal signal_track_added; - sigc::signal signal_vehicle_added; - -private: - float scale; - float gauge; - Profile rail_profile; - Profile ballast_profile; - Profile path_profile; - TrackMap tracks; - VehicleMap vehicles; - Layout layout; - -public: - Catalogue(); - ~Catalogue(); - - float get_scale() const { return scale; } - float get_gauge() const { return gauge; } - float get_rail_elevation() const; - const Profile &get_rail_profile() const { return rail_profile; } - const Profile &get_ballast_profile() const { return ballast_profile; } - const Profile &get_path_profile() const { return path_profile; } - - void add_track(TrackType &); - const TrackType &get_track(const ArticleNumber &) const; - const TrackMap &get_tracks() const { return tracks; } - - void add_vehicle(VehicleType &); - const VehicleType &get_vehicle(const ArticleNumber &) const; - const VehicleMap &get_vehicles() const { return vehicles; } - - Layout &get_layout() { return layout; } -}; - -} // namespace Marklin - -#endif diff --git a/source/libmarklin/controller.cpp b/source/libmarklin/controller.cpp deleted file mode 100644 index 8d7be31..0000000 --- a/source/libmarklin/controller.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#include -#include -#include "controller.h" - -using namespace std; -using namespace Msp; - -namespace Marklin { - -void Controller::Control::set(float v) -{ - if(vmax_value) - v = max_value; - else if(type==BINARY) - value = v ? 1 : 0; - else if(type==DISCRETE) - value = min_value+floor((v-min_value)/step)*step; - else if(type==CONTINUOUS) - value = v; -} - -Controller::Control Controller::Control::binary(const string &n) -{ - Controller::Control tc; - tc.name = n; - tc.type = BINARY; - tc.min_value = 0; - tc.max_value = 1; - tc.step = 1; - tc.value = 0; - - return tc; -} - -Controller::Control Controller::Control::discrete(const string &n, float m, float x, float s) -{ - if(x -#include -#include - -namespace Marklin { - -/** -Interface class for train controllers. Takes input through a uniform named -control interface. Provides information about train movement on output. -*/ -class Controller -{ -public: - struct Control - { - enum Type - { - BINARY, - DISCRETE, - CONTINUOUS - }; - - std::string name; - Type type; - float min_value; - float max_value; - float step; - float value; - - private: - Control() { } - - public: - void set(float); - - static Control binary(const std::string &); - static Control discrete(const std::string &, float, float, float); - static Control continuous(const std::string &, float, float); - }; - - sigc::signal signal_control_changed; - -protected: - Controller() { } -public: - virtual ~Controller() { } - - virtual void set_control(const std::string &, float) = 0; - virtual const Control &get_control(const std::string &) const = 0; - - /** Returns the current speed. Always non-negative. */ - virtual float get_speed() const = 0; - - /** Returns true if traveling in reverse. */ - virtual bool get_reverse() const = 0; - - /** Determines the distance required to come to a full stop. */ - virtual float get_braking_distance() const = 0; - - virtual void tick(const Msp::Time::TimeDelta &) = 0; -}; - -} // namespace Marklin - -#endif diff --git a/source/libmarklin/driver.cpp b/source/libmarklin/driver.cpp deleted file mode 100644 index 3bec54e..0000000 --- a/source/libmarklin/driver.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#include -#include "driver.h" -#include "dummy.h" -#include "intellibox.h" - -using namespace std; - -namespace Marklin { - -Driver *Driver::create(const string &str) -{ - string::size_type colon = str.find(':'); - string type = str.substr(0, colon); - string params; - - if(colon!=string::npos) - params = str.substr(colon+1); - - if(type=="ib" || type=="intellibox") - return new Intellibox(params); - else if(type=="dummy") - return new Dummy; - - throw Msp::InvalidParameterValue("Unknown driver"); -} - -} // namespace Marklin diff --git a/source/libmarklin/driver.h b/source/libmarklin/driver.h deleted file mode 100644 index f8d8f9c..0000000 --- a/source/libmarklin/driver.h +++ /dev/null @@ -1,59 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#ifndef LIBMARKLIN_DRIVER_H_ -#define LIBMARKLIN_DRIVER_H_ - -#include -#include - -namespace Marklin { - -class Driver -{ -public: - sigc::signal signal_power; - sigc::signal signal_halt; - sigc::signal signal_loco_speed; - sigc::signal signal_loco_function; - sigc::signal signal_turnout; - sigc::signal signal_sensor; - -protected: - Driver() { } -public: - virtual ~Driver() { } - - virtual void set_power(bool) = 0; - virtual bool get_power() const = 0; - virtual void halt(bool) = 0; - virtual bool is_halted() const = 0; - - virtual const char *enumerate_protocols(unsigned) const = 0; - virtual unsigned get_protocol_speed_steps(const std::string &) const = 0; - virtual void add_loco(unsigned, const std::string &) = 0; - virtual void set_loco_speed(unsigned, unsigned) = 0; - virtual void set_loco_reverse(unsigned, bool) = 0; - virtual void set_loco_function(unsigned, unsigned, bool) = 0; - - virtual void add_turnout(unsigned) = 0; - virtual void set_turnout(unsigned, bool) = 0; - virtual bool get_turnout(unsigned) const = 0; - - virtual void add_sensor(unsigned) = 0; - virtual void set_sensor(unsigned, bool) = 0; - virtual bool get_sensor(unsigned) const = 0; - - virtual void tick() = 0; - virtual void flush() = 0; - - static Driver *create(const std::string &); -}; - -} // namespace Marklin - -#endif diff --git a/source/libmarklin/dummy.cpp b/source/libmarklin/dummy.cpp deleted file mode 100644 index da6c5c9..0000000 --- a/source/libmarklin/dummy.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#include "dummy.h" - -using namespace std; - -namespace Marklin { - -Dummy::Dummy(): - power(true) -{ } - -void Dummy::set_power(bool p) -{ - power = p; - signal_power.emit(power); -} - -const char *Dummy::enumerate_protocols(unsigned i) const -{ - if(i==0) - return "dummy"; - return 0; -} - -unsigned Dummy::get_protocol_speed_steps(const string &) const -{ - return 0; -} - -void Dummy::add_turnout(unsigned addr) -{ - turnouts[addr]; -} - -void Dummy::set_turnout(unsigned addr, bool state) -{ - if(turnouts[addr]!=state) - { - turnouts[addr] = state; - signal_turnout.emit(addr, state); - } -} - -bool Dummy::get_turnout(unsigned addr) const -{ - map::const_iterator i = turnouts.find(addr); - if(i!=turnouts.end()) - return i->second; - return false; -} - -void Dummy::set_loco_speed(unsigned addr, unsigned speed) -{ - LocoState &loco = locos[addr]; - loco.speed = speed; - signal_loco_speed.emit(addr, speed, loco.reverse); -} - -void Dummy::set_loco_reverse(unsigned addr, bool rev) -{ - LocoState &loco = locos[addr]; - loco.reverse = rev; - signal_loco_speed.emit(addr, loco.speed, rev); -} - -void Dummy::set_loco_function(unsigned addr, unsigned func, bool state) -{ - signal_loco_function.emit(addr, func, state); -} - -void Dummy::set_sensor(unsigned addr, bool state) -{ - if(sensors[addr]!=state) - { - sensors[addr] = state; - signal_sensor.emit(addr, state); - } -} - -bool Dummy::get_sensor(unsigned addr) const -{ - map::const_iterator i = sensors.find(addr); - if(i!=sensors.end()) - return i->second; - return false; -} - -} // namespace Marklin diff --git a/source/libmarklin/dummy.h b/source/libmarklin/dummy.h deleted file mode 100644 index 7485fa5..0000000 --- a/source/libmarklin/dummy.h +++ /dev/null @@ -1,59 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#ifndef LIBMARKLIN_DUMMY_H_ -#define LIBMARKLIN_DUMMY_H_ - -#include -#include "driver.h" - -namespace Marklin { - -class Dummy: public Driver -{ -private: - struct LocoState - { - unsigned speed; - bool reverse; - }; - - bool power; - std::map turnouts; - std::map locos; - std::map sensors; - -public: - Dummy(); - - virtual void set_power(bool); - virtual bool get_power() const { return power; } - virtual void halt(bool) { } - virtual bool is_halted() const { return false; } - - virtual const char *enumerate_protocols(unsigned) const; - virtual unsigned get_protocol_speed_steps(const std::string &) const; - virtual void add_loco(unsigned, const std::string &) { } - virtual void set_loco_speed(unsigned, unsigned); - virtual void set_loco_reverse(unsigned, bool); - virtual void set_loco_function(unsigned, unsigned, bool); - - virtual void add_turnout(unsigned); - virtual void set_turnout(unsigned, bool); - virtual bool get_turnout(unsigned) const; - - virtual void add_sensor(unsigned) { } - virtual void set_sensor(unsigned, bool); - virtual bool get_sensor(unsigned) const; - - virtual void tick() { } - virtual void flush() { } -}; - -} // namespace Marklin - -#endif diff --git a/source/libmarklin/geometry.h b/source/libmarklin/geometry.h deleted file mode 100644 index 674a6b9..0000000 --- a/source/libmarklin/geometry.h +++ /dev/null @@ -1,39 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#ifndef LIBMARKLIN_GEOMETRY_H_ -#define LIBMARKLIN_GEOMETRY_H_ - -#include -#include - -namespace Marklin { - -struct Point -{ - float x, y, z; - - Point(): x(0), y(0), z(0) { } - Point(float x_, float y_): x(x_), y(y_), z(0) { } - Point(float x_, float y_, float z_): x(x_), y(y_), z(z_) { } -}; - -inline float distance(const Point &p, const Point &q) -{ return sqrt((p.x-q.x)*(p.x-q.x) + (p.y-q.y)*(p.y-q.y) + (p.z-q.z)*(p.z-q.z)); } - -struct TrackPoint -{ - Point pos; - float dir; - float grade; - - TrackPoint(): dir(0), grade(0) { } -}; - -} // namespace Marklin - -#endif diff --git a/source/libmarklin/intellibox.cpp b/source/libmarklin/intellibox.cpp deleted file mode 100644 index 1dc2e70..0000000 --- a/source/libmarklin/intellibox.cpp +++ /dev/null @@ -1,706 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#include -#include -#include -#include -#include -#include -#include "intellibox.h" - -using namespace std; -using namespace Msp; - -namespace Marklin { - -Intellibox::Intellibox(const string &dev): - power(false), - halted(false), - update_sensors(false), - command_sent(false) -{ - serial_fd = ::open(dev.c_str(), O_RDWR); - if(serial_fd<0) - throw Exception("Couldn't open serial port\n"); - - static unsigned baud[]= - { - 2400, B2400, - 4800, B4800, - 9600, B9600, - 19200, B19200, - 0 - }; - - termios attr; - tcgetattr(serial_fd, &attr); - cfmakeraw(&attr); - attr.c_cflag |= CSTOPB; - - bool ok = false; - bool p50 = false; - for(unsigned i=0; baud[i]; i+=2) - { - cfsetospeed(&attr, baud[i+1]); - tcsetattr(serial_fd, TCSADRAIN, &attr); - - write(serial_fd, "\xC4", 1); - - pollfd pfd = { serial_fd, POLLIN, 0 }; - if(poll(&pfd, 1, 500)>0) - { - IO::print("IB detected at %d bits/s\n", baud[i]); - char buf[2]; - p50 = (read(serial_fd, buf, 2)==2); - ok = true; - break; - } - } - - if(!ok) - throw Exception("IB not detected"); - - if(p50) - write(serial_fd, "xZzA1\r", 6); - - command(CMD_STATUS); -} - -void Intellibox::set_power(bool p) -{ - power = p; - if(power) - command(CMD_POWER_ON); - else - command(CMD_POWER_OFF); - signal_power.emit(power); -} - -void Intellibox::halt(bool h) -{ - halted = h; - if(halted) - { - for(map::iterator i=locos.begin(); i!=locos.end(); ++i) - if(i->second.speed) - set_loco_speed(i->first, 0); - } - - signal_halt.emit(halted); -} - -const char *Intellibox::enumerate_protocols(unsigned i) const -{ - if(i==MM) - return "MM"; - else if(i==MM_27) - return "MM-27"; - return 0; -} - -unsigned Intellibox::get_protocol_speed_steps(const string &proto_name) const -{ - Protocol proto = map_protocol(proto_name); - if(proto==MM) - return 14; - else if(proto==MM_27) - return 27; - return 0; -} - -void Intellibox::add_loco(unsigned addr, const string &proto_name) -{ - Protocol proto = map_protocol(proto_name); - - if(!locos.count(addr)) - { - locos[addr].protocol = proto; - - unsigned char data[2]; - data[0] = addr&0xFF; - data[1] = (addr>>8)&0xFF; - command(CMD_LOK_STATUS, addr, data, 2); - } -} - -void Intellibox::set_loco_speed(unsigned addr, unsigned speed) -{ - Locomotive &loco = locos[addr]; - if(speed==loco.speed) - { - if(loco.pending_half_step) - { - loco.pending_half_step = 0; - loco.half_step_delay = Time::TimeStamp(); - signal_loco_speed.emit(addr, speed, loco.reverse); - } - return; - } - if(speed && halted) - return; - - if(loco.protocol==MM_27) - { - if(speed>27) - speed = 27; - - if(speed>loco.speed && !(speed&1)) - { - loco.pending_half_step = -1; - speed |= 1; - } - else if(speed14) - speed = 14; - - loco_command(addr, speed, loco.reverse, loco.funcs|0x100); - } - loco.speed = speed; -} - -void Intellibox::set_loco_reverse(unsigned addr, bool rev) -{ - Locomotive &loco = locos[addr]; - if(rev==loco.reverse) - return; - - loco.reverse = rev; - loco_command(addr, loco.speed, rev, loco.funcs|0x100); -} - -void Intellibox::set_loco_function(unsigned addr, unsigned func, bool state) -{ - Locomotive &loco = locos[addr]; - if(state) - loco.funcs |= 1<>8)&0xFF; - command(CMD_TURNOUT_STATUS, addr, data, 2); - } -} - -void Intellibox::set_turnout(unsigned addr, bool state) -{ - Turnout &turnout = turnouts[addr]; - if(state==turnout.state || state==turnout.pending) - return; - - turnout.pending = state; - turnout.active = true; - turnout.off_timeout = Time::TimeStamp(); - - turnout_command(addr, state, true); -} - -bool Intellibox::get_turnout(unsigned addr) const -{ - map::const_iterator i = turnouts.find(addr); - if(i!=turnouts.end()) - return i->second.state; - return false; -} - -void Intellibox::add_sensor(unsigned addr) -{ - if(!sensors.count(addr)) - { - sensors[addr]; - update_sensors = true; - } -} - -bool Intellibox::get_sensor(unsigned addr) const -{ - map::const_iterator i = sensors.find(addr); - if(i!=sensors.end()) - return i->second.state; - return false; -} - -void Intellibox::tick() -{ - const Time::TimeStamp t = Time::now(); - - if(t>next_event_query) - { - next_event_query = t+200*Time::msec; - command(CMD_EVENT); - } - - for(map::iterator i=locos.begin(); i!=locos.end(); ++i) - if(i->second.protocol==MM_27 && i->second.pending_half_step && i->second.half_step_delay && t>i->second.half_step_delay) - { - i->second.speed += i->second.pending_half_step; - i->second.pending_half_step = 0; - i->second.half_step_delay = Time::TimeStamp(); - loco_command(i->first, (i->second.speed+1)/2, i->second.reverse, i->second.funcs|0x100); - } - - for(map::iterator i=turnouts.begin(); i!=turnouts.end(); ++i) - if(i->second.active && i->second.off_timeout && t>i->second.off_timeout) - { - i->second.active = false; - i->second.off_timeout = Time::TimeStamp(); - turnout_command(i->first, i->second.state, false); - } - - for(map::iterator i=sensors.begin(); i!=sensors.end(); ++i) - if(i->second.off_timeout && t>i->second.off_timeout) - { - i->second.state = false; - i->second.off_timeout = Time::TimeStamp(); - signal_sensor.emit(i->first, false); - } - - if(update_sensors) - { - unsigned max_addr = (--sensors.end())->first; - unsigned char data[2]; - data[0] = 0; - data[1] = (max_addr+7)/8; - command(CMD_SENSOR_PARAM_SET, data, 2); - command(CMD_SENSOR_REPORT); - update_sensors = false; - } - - if(!queue.empty() && command_sent) - { - pollfd pfd = { serial_fd, POLLIN, 0 }; - if(poll(&pfd, 1, 0)>0) - { - process_reply(t); - queue.erase(queue.begin()); - command_sent = false; - } - else - return; - } - - if(!queue.empty()) - { - const CommandSlot &slot = queue.front(); - write(serial_fd, slot.data, slot.length); - command_sent = true; - } -} - -void Intellibox::flush() -{ - Time::TimeStamp t = Time::now(); - for(list::iterator i=queue.begin(); i!=queue.end(); ++i) - { - write(serial_fd, i->data, i->length); - pollfd pfd = { serial_fd, POLLIN, 0 }; - bool first = true; - while(poll(&pfd, 1, (first ? -1 : 0))>0) - { - char data[16]; - read(serial_fd, data, 16); - first = false; - } - } - - queue.clear(); - command_sent = false; -} - -Intellibox::Protocol Intellibox::map_protocol(const string &name) const -{ - if(name=="MM") - return MM; - else if(name=="MM-27") - return MM_27; - else - throw InvalidParameterValue("Unknown protocol"); -} - -void Intellibox::command(Command cmd) -{ - command(cmd, 0, 0); -} - -void Intellibox::command(Command cmd, const unsigned char *data, unsigned len) -{ - command(cmd, 0, data, len); -} - -void Intellibox::command(Command cmd, unsigned addr, const unsigned char *data, unsigned len) -{ - CommandSlot slot; - slot.cmd = cmd; - slot.addr = addr; - slot.data[0] = cmd; - copy(data, data+len, slot.data+1); - slot.length = 1+len; - queue.push_back(slot); -} - -void Intellibox::loco_command(unsigned addr, unsigned speed, bool rev, unsigned funcs) -{ - unsigned char data[4]; - data[0] = addr&0xFF; - data[1] = (addr>>8)&0xFF; - - if(speed==0) - data[2] = 0; - else if(speed==1) - data[2] = 2; - else - data[2] = (speed*19-18)/2; - - data[3] = (rev ? 0 : 0x20) | ((funcs&1) ? 0x10 : 0); - - if(!(funcs&0x100)) - data[3] |= 0x80 | ((funcs>>1)&0xF); - - command(CMD_LOK, addr, data, 4); -} - -void Intellibox::turnout_command(unsigned addr, bool state, bool active) -{ - unsigned char data[2]; - data[0] = addr&0xFF; - data[1] = ((addr>>8)&0x7) | (active ? 0x40 : 0) | (state ? 0x80 : 0); - command(CMD_TURNOUT, addr, data, 2); -} - -void Intellibox::process_reply(const Time::TimeStamp &t) -{ - Command cmd = queue.front().cmd; - - if(cmd==CMD_STATUS) - { - unsigned char status; - read_all(&status, 1); - power = status&0x08; - signal_power.emit(power); - } - else if(cmd==CMD_EVENT) - { - for(unsigned i=0;; ++i) - { - unsigned char byte; - read_all(&byte, 1); - - if(i==0) - { - if(byte&0x01) - command(CMD_EVENT_LOK); - if(byte&0x20) - command(CMD_EVENT_TURNOUT); - if(byte&0x04) - command(CMD_EVENT_SENSOR); - } - else if(i==1) - { - if(byte&0x40) - command(CMD_STATUS); - } - - if(!(byte&0x80)) - break; - } - } - else if(cmd==CMD_EVENT_LOK) - { - while(1) - { - unsigned char data[5]; - read_all(data, 1); - if(data[0]==0x80) - break; - read_all(data+1, 4); - } - } - else if(cmd==CMD_EVENT_TURNOUT) - { - unsigned char count; - read_all(&count, 1); - for(unsigned i=0; i>(7-i%8))&1; - - Sensor &sensor = sensors[addr]; - if(state) - { - sensor.off_timeout = Time::TimeStamp(); - if(!sensor.state) - { - sensor.state = state; - signal_sensor(addr, state); - } - } - else if(sensor.state) - sensor.off_timeout = t+700*Time::msec; - } - } - } - else if(cmd==CMD_LOK) - { - Error err; - read_status(&err); - - if(err==ERR_NO_ERROR) - { - unsigned addr = queue.front().addr; - Locomotive &loco = locos[addr]; - signal_loco_speed.emit(addr, loco.speed+loco.pending_half_step, loco.reverse); - if(loco.pending_half_step) - loco.half_step_delay = Time::now()+500*Time::msec; - } - else - error(cmd, err); - } - else if(cmd==CMD_TURNOUT) - { - Error err; - read_status(&err); - - unsigned addr = queue.front().addr; - Turnout &turnout = turnouts[addr]; - - if(err==ERR_NO_ERROR) - { - turnout.state = turnout.pending; - if(turnout.active) - { - signal_turnout.emit(addr, turnout.state); - turnout.off_timeout = t+500*Time::msec; - } - } - else if(err==ERR_NO_I2C_SPACE) - queue.push_back(queue.front()); - else - { - turnout.pending = turnout.state; - error(cmd, err); - } - } - else if(cmd==CMD_TURNOUT_STATUS) - { - Error err; - read_status(&err); - - if(err==ERR_NO_ERROR) - { - unsigned char data; - read_all(&data, 1); - - unsigned addr = queue.front().addr; - bool state = data&0x04; - - Turnout &turnout = turnouts[addr]; - if(state!=turnout.state) - { - turnout.state = state; - turnout.pending = state; - signal_turnout.emit(addr, turnout.state); - } - } - else - error(cmd, err); - } - else if(cmd==CMD_LOK_STATUS) - { - Error err; - read_status(&err); - - if(err==ERR_NO_ERROR) - { - unsigned char data[3]; - read_all(data, 3); - - unsigned addr = queue.front().addr; - Locomotive &loco = locos[addr]; - - unsigned speed = (data[0]<=1 ? 0 : data[0]*2/19+1); - bool reverse = !(data[1]&0x20); - if(speed!=loco.speed || reverse!=loco.reverse) - { - loco.speed = speed; - loco.reverse = reverse; - signal_loco_speed.emit(addr, loco.speed, loco.reverse); - } - - unsigned funcs = (data[1]&0xF)<<1; - if(data[1]&0x10) - funcs |= 1; - if(funcs!=loco.funcs) - { - unsigned changed = loco.funcs^funcs; - loco.funcs = funcs; - for(unsigned i=0; i<5; ++i) - if(changed&(1<(c); - return ret; -} - -void Intellibox::error(Command cmd, Error err) -{ - const char *cmd_str = 0; - switch(cmd) - { - case CMD_LOK: cmd_str = "CMD_LOK"; break; - case CMD_LOK_STATUS: cmd_str = "CMD_LOK_STATUS"; break; - case CMD_LOK_CONFIG: cmd_str = "CMD_LOK_CONFIG"; break; - case CMD_FUNC: cmd_str = "CMD_FUNC"; break; - case CMD_FUNC_STATUS: cmd_str = "CMD_FUNC_STATUS"; break; - case CMD_TURNOUT: cmd_str = "CMD_TURNOUT"; break; - case CMD_TURNOUT_FREE: cmd_str = "CMD_TURNOUT_FREE"; break; - case CMD_TURNOUT_STATUS: cmd_str = "CMD_TURNOUT_STATUS"; break; - case CMD_TURNOUT_GROUP_STATUS: cmd_str = "CMD_TURNOUT_GROUP_STATUS"; break; - case CMD_SENSOR_STATUS: cmd_str = "CMD_SENSOR_STATUS"; break; - case CMD_SENSOR_REPORT: cmd_str = "CMD_SENSOR_REPORT"; break; - case CMD_SENSOR_PARAM_SET: cmd_str = "CMD_SENSOR_PARAM_SET"; break; - case CMD_STATUS: cmd_str = "CMD_STATUS"; break; - case CMD_POWER_OFF: cmd_str = "CMD_POWER_OFF"; break; - case CMD_POWER_ON: cmd_str = "CMD_POWER_ON"; break; - case CMD_NOP: cmd_str = "CMD_NOP"; break; - case CMD_EVENT: cmd_str = "CMD_EVENT"; break; - case CMD_EVENT_LOK: cmd_str = "CMD_EVENT_LOK"; break; - case CMD_EVENT_TURNOUT: cmd_str = "CMD_EVENT_TURNOUT"; break; - case CMD_EVENT_SENSOR: cmd_str = "CMD_EVENT_SENSOR"; break; - default: cmd_str = "(unknown command)"; - } - - const char *err_str = 0; - switch(err) - { - case ERR_NO_ERROR: err_str = "ERR_NO_ERROR"; break; - case ERR_SYS_ERROR: err_str = "ERR_SYS_ERROR"; break; - case ERR_BAD_PARAM: err_str = "ERR_BAD_PARAM"; break; - case ERR_POWER_OFF: err_str = "ERR_POWER_OFF"; break; - case ERR_NO_LOK_SPACE: err_str = "ERR_NO_LOK_SPACE"; break; - case ERR_NO_TURNOUT_SPACE: err_str = "ERR_NO_TURNOUT_SPACE"; break; - case ERR_NO_DATA: err_str = "ERR_NO_DATA"; break; - case ERR_NO_SLOT: err_str = "ERR_NO_SLOT"; break; - case ERR_BAD_LOK_ADDR: err_str = "ERR_BAD_LOK_ADDR"; break; - case ERR_LOK_BUSY: err_str = "ERR_LOK_BUSY"; break; - case ERR_BAD_TURNOUT_ADDR: err_str = "ERR_BAD_TURNOUT_ADDR"; break; - case ERR_BAD_SO_VALUE: err_str = "ERR_BAD_SO_VALUE"; break; - case ERR_NO_I2C_SPACE: err_str = "ERR_NO_I2C_SPACE"; break; - case ERR_LOW_TURNOUT_SPACE: err_str = "ERR_LOW_TURNOUT_SPACE"; break; - case ERR_LOK_HALTED: err_str = "ERR_LOK_HALTED"; break; - case ERR_LOK_POWER_OFF: err_str = "ERR_LOK_POWER_OFF"; break; - default: cmd_str = "(unknown error)"; - } - - IO::print("Error: %s: %s\n", cmd_str, err_str); -} - - -Intellibox::Locomotive::Locomotive(): - speed(0), - reverse(false), - funcs(0) -{ } - - -Intellibox::Turnout::Turnout(): - state(false), - active(false), - pending(false) -{ } - - -Intellibox::Sensor::Sensor(): - state(false) -{ } - -} // namespace Marklin diff --git a/source/libmarklin/intellibox.h b/source/libmarklin/intellibox.h deleted file mode 100644 index 6d061a6..0000000 --- a/source/libmarklin/intellibox.h +++ /dev/null @@ -1,170 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#ifndef LIBMARKLIN_INTELLIBOX_H_ -#define LIBMARKLIN_INTELLIBOX_H_ - -#include -#include -#include "driver.h" - -namespace Marklin { - -/** -Driver for Uhlenbrock Intellibox. Uses the P50X binary protocol over RS232. - -Motorola decoders with 27 speed steps are supported by manually generating the -commands necessary to reach the "half-steps". However, sending a rapid stream -of speed changes to the same locomotive seems to cause excessive lag, so we -cheat a bit; instead of sending the half-step command immediately, we send it -with a 500ms delay, but only if no new set_loco_speed calls have occurred. As -a downside from this accelerations and decelerations are still jerky. -*/ -class Intellibox: public Driver -{ -private: - enum Command - { - CMD_LOK=0x80, - CMD_LOK_STATUS=0x84, - CMD_LOK_CONFIG=0x85, - CMD_FUNC=0x88, - CMD_FUNC_STATUS=0x8C, - CMD_TURNOUT=0x90, - CMD_TURNOUT_FREE=0x93, - CMD_TURNOUT_STATUS=0x94, - CMD_TURNOUT_GROUP_STATUS=0x95, - CMD_SENSOR_STATUS=0x98, - CMD_SENSOR_REPORT=0x99, - CMD_SENSOR_PARAM_SET=0x9D, - CMD_STATUS=0xA2, - CMD_POWER_OFF=0xA6, - CMD_POWER_ON=0xA7, - CMD_NOP=0xC4, - CMD_EVENT=0xC8, - CMD_EVENT_LOK=0xC9, - CMD_EVENT_TURNOUT=0xCA, - CMD_EVENT_SENSOR=0xCB - }; - - enum Error - { - ERR_NO_ERROR=0, - ERR_SYS_ERROR, - ERR_BAD_PARAM, - ERR_POWER_OFF=0x6, - ERR_NO_LOK_SPACE=0x8, // No space in lok command buffer - ERR_NO_TURNOUT_SPACE, // No space in turnout command buffer - ERR_NO_DATA, // "no Lok status available (Lok is not in a slot)" - ERR_NO_SLOT, // "there is no slot available" - ERR_BAD_LOK_ADDR, - ERR_LOK_BUSY, - ERR_BAD_TURNOUT_ADDR, - ERR_BAD_SO_VALUE, - ERR_NO_I2C_SPACE, - ERR_LOW_TURNOUT_SPACE=0x40, - ERR_LOK_HALTED, - ERR_LOK_POWER_OFF, - }; - - enum Protocol - { - MM, - MM_27 - }; - - struct Locomotive - { - Protocol protocol; - unsigned speed; - bool reverse; - unsigned funcs; - int pending_half_step; - Msp::Time::TimeStamp half_step_delay; - - Locomotive(); - }; - - struct Turnout - { - bool state; - bool active; - bool pending; - Msp::Time::TimeStamp off_timeout; - - Turnout(); - }; - - struct Sensor - { - bool state; - Msp::Time::TimeStamp off_timeout; - - Sensor(); - }; - - struct CommandSlot - { - Command cmd; - unsigned addr; - unsigned char data[8]; - unsigned length; - }; - - int serial_fd; - bool power; - bool halted; - std::map locos; - std::map turnouts; - std::map sensors; - bool update_sensors; - std::list queue; - bool command_sent; - Msp::Time::TimeStamp next_event_query; - -public: - Intellibox(const std::string &); - - virtual void set_power(bool); - virtual bool get_power() const { return power; } - virtual void halt(bool); - virtual bool is_halted() const { return halted; } - - virtual const char *enumerate_protocols(unsigned) const; - virtual unsigned get_protocol_speed_steps(const std::string &) const; - virtual void add_loco(unsigned, const std::string &); - virtual void set_loco_speed(unsigned, unsigned); - virtual void set_loco_reverse(unsigned, bool); - virtual void set_loco_function(unsigned, unsigned, bool); - - virtual void add_turnout(unsigned); - virtual void set_turnout(unsigned, bool); - virtual bool get_turnout(unsigned) const; - - virtual void add_sensor(unsigned); - virtual void set_sensor(unsigned, bool) { } - virtual bool get_sensor(unsigned) const; - - virtual void tick(); - virtual void flush(); - -private: - Protocol map_protocol(const std::string &) const; - void command(Command); - void command(Command, const unsigned char *, unsigned); - void command(Command, unsigned, const unsigned char *, unsigned); - void loco_command(unsigned, unsigned, bool, unsigned); - void turnout_command(unsigned, bool, bool); - void process_reply(const Msp::Time::TimeStamp &); - unsigned read_all(unsigned char *, unsigned); - unsigned read_status(Error *); - void error(Command, Error); -}; - -} // namespace Marklin - -#endif diff --git a/source/libmarklin/layout.cpp b/source/libmarklin/layout.cpp deleted file mode 100644 index 5f590db..0000000 --- a/source/libmarklin/layout.cpp +++ /dev/null @@ -1,351 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#include -#include -#include -#include -#include -#include -#include "block.h" -#include "catalogue.h" -#include "driver.h" -#include "layout.h" -#include "route.h" -#include "track.h" -#include "tracktype.h" -#include "train.h" -#include "vehicletype.h" - -using namespace std; -using namespace Msp; - -namespace Marklin { - -Layout::Layout(Catalogue &c, Driver *d): - catalogue(c), - driver(d), - next_turnout_id(0x800) -{ - if(driver) - driver->signal_sensor.connect(sigc::mem_fun(this, &Layout::sensor_event)); -} - -Layout::~Layout() -{ - delete driver; - while(!trains.empty()) - delete trains.begin()->second; - while(!routes.empty()) - delete *routes.begin(); - while(!tracks.empty()) - delete *tracks.begin(); - while(!blocks.empty()) - delete *blocks.begin(); -} - -Driver &Layout::get_driver() const -{ - if(!driver) - throw InvalidState("No driver"); - return *driver; -} - -void Layout::add_track(Track &t) -{ - if(tracks.insert(&t).second) - { - create_blocks(); - signal_track_added.emit(t); - } -} - -void Layout::remove_track(Track &t) -{ - if(tracks.erase(&t)) - { - create_blocks(t); - signal_track_removed.emit(t); - } -} - -unsigned Layout::allocate_turnout_id(bool dbl) -{ - set used_ids; - for(set::const_iterator i=tracks.begin(); i!=tracks.end(); ++i) - if((*i)->get_turnout_id()) - used_ids.insert((*i)->get_turnout_id()); - - unsigned result = next_turnout_id; - while(used_ids.count(result) || (dbl && used_ids.count(result+1))) - ++result; - next_turnout_id = result+1+dbl; - - return result; -} - -void Layout::add_block(Block &b) -{ - blocks.insert(&b); -} - -Block &Layout::get_block(unsigned id) const -{ - for(set::const_iterator i=blocks.begin(); i!=blocks.end(); ++i) - if((*i)->get_id()==id) - return **i; - - throw KeyError("Unknown block", lexical_cast(id)); -} - -void Layout::create_blocks() -{ - set used_tracks; - for(set::const_iterator i=blocks.begin(); i!=blocks.end(); ++i) - { - const set &btracks = (*i)->get_tracks(); - used_tracks.insert(btracks.begin(), btracks.end()); - } - - for(set::const_iterator i=tracks.begin(); i!=tracks.end(); ++i) - if(used_tracks.count(*i)==0) - { - Block *block = new Block(*this, **i); - used_tracks.insert(block->get_tracks().begin(), block->get_tracks().end()); - } - - for(set::iterator i=blocks.begin(); i!=blocks.end(); ++i) - for(set::iterator j=i; j!=blocks.end(); ++j) - if(j!=i) - (*i)->check_link(**j); -} - -void Layout::create_blocks(Track &track) -{ - /* Must collect the blocks in a set first while all tracks are still - guaranteed to have blocks and to avoid duplicate deletes */ - set del_blocks; - - del_blocks.insert(&track.get_block()); - - const vector &links = track.get_links(); - for(vector::const_iterator i=links.begin(); i!=links.end(); ++i) - if(*i) - del_blocks.insert(&(*i)->get_block()); - - for(set::iterator i=del_blocks.begin(); i!=del_blocks.end(); ++i) - delete *i; - - create_blocks(); -} - -void Layout::remove_block(Block &b) -{ - blocks.erase(&b); -} - -void Layout::add_route(Route &r) -{ - if(routes.insert(&r).second) - signal_route_added.emit(r); -} - -Route &Layout::get_route(const string &name) const -{ - for(set::const_iterator i=routes.begin(); i!=routes.end(); ++i) - if((*i)->get_name()==name) - return **i; - throw KeyError("Unknown route", name); -} - -void Layout::update_routes() -{ - for(set::iterator i=routes.begin(); i!=routes.end(); ++i) - (*i)->update_turnouts(); -} - -void Layout::remove_route(Route &r) -{ - if(routes.erase(&r)) - signal_route_removed.emit(r); -} - -void Layout::add_train(Train &t) -{ - if(trains.count(t.get_address())) - throw KeyError("Duplicate train address", lexical_cast(t.get_address())); - - trains[t.get_address()] = &t; - signal_train_added.emit(t); -} - -Train &Layout::get_train(unsigned addr) const -{ - map::const_iterator i = trains.find(addr); - if(i==trains.end()) - throw KeyError("Unknown train", lexical_cast(addr)); - return *i->second; -} - -void Layout::remove_train(Train &t) -{ - if(trains.erase(t.get_address())) - signal_train_removed.emit(t); -} - -void Layout::add_vehicle(Vehicle &v) -{ - if(vehicles.insert(&v).second) - signal_vehicle_added.emit(v); -} - -void Layout::remove_vehicle(Vehicle &v) -{ - if(vehicles.erase(&v)) - signal_vehicle_removed.emit(v); -} - -void Layout::tick() -{ - if(driver) - driver->tick(); - - Time::TimeStamp t = Time::now(); - Time::TimeDelta dt; - if(last_tick) - dt = t-last_tick; - last_tick = t; - - for(map::iterator i=trains.begin(); i!=trains.end(); ++i) - i->second->tick(t, dt); -} - -void Layout::emergency(const string &msg) -{ - if(driver) - driver->halt(true); - IO::print("Emergency: %s\n", msg); - signal_emergency.emit(msg); -} - -void Layout::save(const string &fn) -{ - IO::BufferedFile out(fn, IO::M_WRITE); - DataFile::Writer writer(out); - - if(!base.empty()) - writer.write((DataFile::Statement("base"), base)); - - for(set::iterator i=tracks.begin(); i!=tracks.end(); ++i) - { - DataFile::Statement st("track"); - st.append((*i)->get_type().get_article_number()); - (*i)->save(st.sub); - writer.write(st); - } - - for(set::iterator i=routes.begin(); i!=routes.end(); ++i) - { - if((*i)->is_temporary()) - continue; - - DataFile::Statement st("route"); - (*i)->save(st.sub); - writer.write(st); - } -} - -void Layout::save_trains(const string &fn) -{ - IO::BufferedFile out(fn, IO::M_WRITE); - DataFile::Writer writer(out); - - for(map::const_iterator i=trains.begin(); i!=trains.end(); ++i) - { - DataFile::Statement st("train"); - st.append(i->second->get_locomotive_type().get_article_number()); - st.append(i->second->get_address()); - st.append(i->second->get_protocol()); - i->second->save(st.sub); - writer.write(st); - } -} - -void Layout::sensor_event(unsigned addr, bool state) -{ - if(state) - { - for(set::iterator i=blocks.begin(); i!=blocks.end(); ++i) - if((*i)->get_sensor_id()==addr) - { - if(!(*i)->get_train()) - emergency(format("Unreserved sensor %d triggered", addr)); - break; - } - } -} - - -Layout::Loader::Loader(Layout &l): - DataFile::BasicLoader(l), - new_tracks(false) -{ - add("base", &Layout::base); - add("route", static_cast(&Loader::route)); - add("route", static_cast(&Loader::route)); - add("track", static_cast(&Loader::track)); - add("track", static_cast(&Loader::track)); - add("train", static_cast(&Loader::train)); - add("train", static_cast(&Loader::train)); -} - -void Layout::Loader::finish() -{ - for(set::iterator i=obj.tracks.begin(); i!=obj.tracks.end(); ++i) - (*i)->check_slope(); -} - -void Layout::Loader::route() -{ - Route *rte = new Route(obj); - load_sub(*rte); -} - -void Layout::Loader::route(const string &n) -{ - Route *rte = new Route(obj); - rte->set_name(n); - load_sub(*rte); -} - -void Layout::Loader::track(unsigned art_nr) -{ - track(ArticleNumber(art_nr)); -} - -void Layout::Loader::track(ArticleNumber art_nr) -{ - Track *trk = new Track(obj, obj.catalogue.get_track(art_nr)); - load_sub(*trk); - new_tracks = true; - for(set::iterator i=obj.tracks.begin(); i!=obj.tracks.end(); ++i) - if(*i!=trk) - trk->snap_to(**i, true); -} - -void Layout::Loader::train(unsigned art_nr, unsigned addr, const std::string &proto) -{ - train(ArticleNumber(art_nr), addr, proto); -} - -void Layout::Loader::train(ArticleNumber art_nr, unsigned addr, const std::string &proto) -{ - Train *trn = new Train(obj, obj.catalogue.get_vehicle(art_nr), addr, proto); - load_sub(*trn); -} - -} // namespace Marklin diff --git a/source/libmarklin/layout.h b/source/libmarklin/layout.h deleted file mode 100644 index 2fc761a..0000000 --- a/source/libmarklin/layout.h +++ /dev/null @@ -1,118 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#ifndef LIBMARKLIN_LAYOUT_H_ -#define LIBMARKLIN_LAYOUT_H_ - -#include -#include -#include -#include - -namespace Marklin { - -class ArticleNumber; -class Block; -class Catalogue; -class Driver; -class Route; -class Track; -class Train; -class Vehicle; - -class Layout -{ -public: - class Loader: public Msp::DataFile::BasicLoader - { - private: - bool new_tracks; - - public: - Loader(Layout &); - private: - virtual void finish(); - void route(); - void route(const std::string &); - void track(unsigned); - void track(ArticleNumber); - void train(unsigned, unsigned, const std::string &); - void train(ArticleNumber, unsigned, const std::string &); - }; - -public: - sigc::signal signal_track_added; - sigc::signal signal_track_removed; - sigc::signal signal_route_added; - sigc::signal signal_route_removed; - sigc::signal signal_train_added; - sigc::signal signal_train_removed; - sigc::signal signal_vehicle_added; - sigc::signal signal_vehicle_removed; - sigc::signal signal_block_reserved; - sigc::signal signal_emergency; - -private: - Catalogue &catalogue; - Driver *driver; - std::string base; - std::set tracks; - std::set routes; - std::set blocks; - std::map trains; - std::set vehicles; - Msp::Time::TimeStamp last_tick; - unsigned next_turnout_id; - -public: - Layout(Catalogue &, Driver * = 0); - ~Layout(); - - Catalogue &get_catalogue() const { return catalogue; } - bool has_driver() const { return driver; } - Driver &get_driver() const; - const std::string &get_base() const { return base; } - - void add_track(Track &); - const std::set &get_tracks() const { return tracks; } - void remove_track(Track &); - unsigned allocate_turnout_id(bool); - - void add_block(Block &); - Block &get_block(unsigned) const; - const std::set &get_blocks() const { return blocks; } - void create_blocks(); - void create_blocks(Track &); - void remove_block(Block &); - - void add_route(Route &); - const std::set &get_routes() const { return routes; } - Route &get_route(const std::string &) const; - void update_routes(); - void remove_route(Route &); - - void add_train(Train &); - Train &get_train(unsigned) const; - const std::map &get_trains() const { return trains; } - void remove_train(Train &); - - void add_vehicle(Vehicle &); - void remove_vehicle(Vehicle &); - - void tick(); - void emergency(const std::string &); - - void save(const std::string &); - void save_trains(const std::string &); -private: - void sensor_event(unsigned, bool); -}; - -} // namespace Marklin - -#endif - diff --git a/source/libmarklin/profile.cpp b/source/libmarklin/profile.cpp deleted file mode 100644 index 7b9dce5..0000000 --- a/source/libmarklin/profile.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#include -#include "profile.h" - -using namespace std; -using namespace Msp; - -namespace Marklin { - -void Profile::append_point(const Point &p) -{ - points.push_back(p); - if(points.size()==1) - { - min_coords = p; - max_coords = p; - } - else - { - min_coords.x = min(min_coords.x, p.x); - min_coords.y = min(min_coords.y, p.y); - max_coords.x = max(max_coords.x, p.x); - max_coords.y = max(max_coords.y, p.y); - } -} - -const Point &Profile::get_point(unsigned i) const -{ - if(i>=points.size()) - throw InvalidParameterValue("Index out of range"); - return points[i]; -} - -Point Profile::get_edge_normal(unsigned i) const -{ - if(i+1>=points.size()) - throw InvalidParameterValue("Index out of range"); - float dx = points[i+1].x-points[i].x; - float dy = points[i+1].y-points[i].y; - float len = sqrt(dx*dx+dy*dy); - return Point(dy/len, -dx/len); -} - - -Profile::Loader::Loader(Profile &p): - DataFile::ObjectLoader(p) -{ - add("point", &Loader::point); -} - -void Profile::Loader::point(float x, float y) -{ - obj.append_point(Point(x/1000, y/1000)); -} - -} // namespace Marklin diff --git a/source/libmarklin/profile.h b/source/libmarklin/profile.h deleted file mode 100644 index b1082e8..0000000 --- a/source/libmarklin/profile.h +++ /dev/null @@ -1,46 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#ifndef LIBMARKLIN_PROFILE_H_ -#define LIBMARKLIN_PROFILE_H_ - -#include -#include -#include "geometry.h" - -namespace Marklin { - -class Profile -{ -public: - class Loader: public Msp::DataFile::ObjectLoader - { - public: - Loader(Profile &); - private: - void point(float, float); - }; - -private: - std::vector points; - Point min_coords; - Point max_coords; - -public: - void append_point(const Point &); - unsigned get_n_points() const { return points.size(); } - const Point &get_point(unsigned) const; - const Point &get_min_coords() const { return min_coords; } - const Point &get_max_coords() const { return max_coords; } - float get_width() const { return max_coords.x-min_coords.x; } - float get_height() const { return max_coords.y-min_coords.y; } - Point get_edge_normal(unsigned) const; -}; - -} // namespace Marklin - -#endif diff --git a/source/libmarklin/route.cpp b/source/libmarklin/route.cpp deleted file mode 100644 index 79886d2..0000000 --- a/source/libmarklin/route.cpp +++ /dev/null @@ -1,455 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2007-2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#include -#include -#include "layout.h" -#include "route.h" -#include "track.h" -#include "trackiter.h" -#include "tracktype.h" - -using namespace std; -using namespace Msp; - -namespace { - -using namespace Marklin; - -typedef std::pair Key; - -struct Node -{ - TrackIter track; - Node *prev; - float dist; - - Node(): - prev(0), dist(0) - { } - - Node(const TrackIter &t): - track(t), prev(0), dist(0) - { } - - Node(const TrackIter &t, Node &r, float d): - track(t), prev(&r), dist(prev->dist+d) - { } - - bool operator<(const Node &other) const - { return dist>other.dist; } -}; - -struct TrackMatch -{ - Track &track; - - TrackMatch(Track &t): track(t) { } - - bool operator()(Track &t) const { return &t==&track; } -}; - -struct TrackInSet -{ - const set &tracks; - - TrackInSet(const set &t): tracks(t) { } - - bool operator()(Track &t) const { return tracks.count(&t); } -}; - -template -list dijkstra(const TrackIter &from, const Pred &goal) -{ - map track_nodes; - priority_queue nodes; - Node *final = 0; - - nodes.push(from); - - while(!nodes.empty()) - { - Node lowest = nodes.top(); - nodes.pop(); - - Key key(lowest.track.track(), lowest.track.entry()); - if(track_nodes.count(key)) - continue; - - Node &ref = track_nodes[key] = lowest; - if(goal(*lowest.track)) - { - final = &ref; - break; - } - - unsigned paths = lowest.track.endpoint().paths; - for(unsigned i=0; paths>>i; ++i) - if(paths&(1<get_type().get_path_length(i))); - } - } - - list result; - for(Node *node=final; node; node=node->prev) - result.push_front(&*node->track); - - return result; -} - -template -Route *create_route(const TrackIter &from, const Pred &goal) -{ - list tracks = dijkstra(from, goal); - - if(tracks.empty()) - return 0; - - Route *route = new Route(from->get_layout()); - for(list::iterator i=tracks.begin(); i!=tracks.end(); ++i) - route->add_track(**i); - - route->set_name("Pathfinder"); - route->set_temporary(true); - - return route; -} - -} - - -namespace Marklin { - -Route::Route(Layout &l): - layout(l), - temporary(false) -{ - layout.add_route(*this); - layout.signal_track_removed.connect(sigc::mem_fun(this, &Route::track_removed)); -} - -Route::~Route() -{ - layout.remove_route(*this); -} - -void Route::set_name(const string &n) -{ - name = n; - signal_name_changed.emit(name); -} - -void Route::set_temporary(bool t) -{ - temporary = t; -} - -void Route::set_turnout(unsigned addr, unsigned path) -{ - if(!addr) - throw InvalidParameterValue("Invalid turnout address"); - map::iterator i = turnouts.find(addr); - if(i==turnouts.end()) - throw KeyError("Turnout is not in this route"); - if(i->second>=0 && path!=static_cast(i->second)) - throw InvalidState("Setting conflicts with route"); - i->second = path; -} - -void Route::update_turnouts() -{ - set found; - for(set::const_iterator i=tracks.begin(); i!=tracks.end(); ++i) - if(unsigned tid = (*i)->get_turnout_id()) - { - found.insert(tid); - - const vector &endpoints = (*i)->get_type().get_endpoints(); - const vector &links = (*i)->get_links(); - - // Build a combined path mask from linked endpoints - unsigned mask = (*i)->get_type().get_paths(); - for(unsigned j=0; jget_turnout_id()) - { - const TrackType::Endpoint &ep = links[j]->get_type().get_endpoint(links[j]->get_endpoint_by_link(**i)); - int p = get_turnout(tid2); - if(p>=0 && !(ep.paths&(1<>=1, ++path) ; - turnouts[tid] = path; - } - else if(!turnouts.count(tid)) - // More than one possible choice, and no existing entry - set as undecided - turnouts[tid] = -1; - } - - // Remove any turnouts that do not exist in the route - for(map::iterator i=turnouts.begin(); i!=turnouts.end();) - { - if(!found.count(i->first)) - turnouts.erase(i++); - else - ++i; - } -} - -int Route::get_turnout(unsigned id) const -{ - map::const_iterator i = turnouts.find(id); - if(i!=turnouts.end()) - return i->second; - return -1; -} - -unsigned Route::get_path(Track &trk) const -{ - if(unsigned tid = trk.get_turnout_id()) - { - map::const_iterator i = turnouts.find(tid); - if(i!=turnouts.end()) - return i->second; - } - return trk.get_active_path(); -} - -void Route::add_track(Track &trk) -{ - if(tracks.count(&trk)) - return; - - if(!tracks.empty()) - { - unsigned valid = check_validity(trk); - if(!(valid&1)) - throw Exception("Not linked to existing tracks"); - else if(!(valid&2)) - throw Exception("Branching routes not allowed"); - else if(!(valid&4)) - throw Exception("Route must be smooth"); - } - - tracks.insert(&trk); - update_turnouts(); -} - -void Route::add_tracks(const set &trks) -{ - set pending; - for(set::const_iterator i=trks.begin(); i!=trks.end(); ++i) - if(!tracks.count(*i)) - pending.insert(*i); - - while(!pending.empty()) - { - bool found = false; - for(set::const_iterator i=pending.begin(); i!=pending.end(); ++i) - if(tracks.empty() || check_validity(**i)==7) - { - tracks.insert(*i); - pending.erase(*i); - found = true; - break; - } - - if(!found) - throw Exception("Could not add all tracks to route"); - } - - update_turnouts(); -} - -void Route::add_track_chain(Track &start, unsigned ep, const TurnoutMap &trnts) -{ - TrackIter iter(&start, ep); - while(iter) - { - if(iter->get_type().is_dead_end()) - break; - - if(has_track(*iter)) - break; - - int path = 0; - if(iter->get_turnout_id()) - { - TurnoutMap::const_iterator i = trnts.find(iter->get_turnout_id()); - if(i==trnts.end()) - break; - - path = i->second; - } - - add_track(*iter); - - iter = iter.next(path); - } -} - -bool Route::has_track(Track &t) const -{ - return tracks.count(&t); -} - -void Route::save(list &st) const -{ - st.push_back((DataFile::Statement("name"), name)); - for(map::const_iterator i=turnouts.begin(); i!=turnouts.end(); ++i) - st.push_back((DataFile::Statement("turnout"), i->first, i->second)); -} - -unsigned Route::check_validity(Track &trk) const -{ - unsigned result = 4; - const vector &links = trk.get_links(); - for(vector::const_iterator i=links.begin(); i!=links.end(); ++i) - { - if(!*i) - continue; - if(!tracks.count(*i)) - continue; - - // Linked to an existing track - good - result |= 1; - - if(unsigned tid = (*i)->get_turnout_id()) - { - const TrackType::Endpoint &ep = (*i)->get_type().get_endpoint((*i)->get_endpoint_by_link(trk)); - int path = get_turnout(tid); - if(path>=0) - { - // Linking to a turnout with path set is only good if we're continuing that path - if(ep.paths&(1< &tlinks = (*i)->get_links(); - unsigned count = 0; - for(unsigned j=0; jget_turnout_id(); - if(tid2) - { - const TrackType::Endpoint &ep2 = tlinks[j]->get_type().get_endpoint(tlinks[j]->get_endpoint_by_link(**i)); - path = get_turnout(tid2); - // Ignore a linked turnout with some other path set - if(path>0 && !(ep2.paths&(1<get_type().get_endpoint(j); - if(!(ep.paths&ep2.paths)) - // Impossible path through the turnout - not good - result &= 3; - } - - // Only good if at most one other track is linked to the turnout - if(count<=1) - result |= 2; - } - } - else - // Linked to something linear - good - result |= 2; - } - - return result; -} - -void Route::track_removed(Track &t) -{ - tracks.erase(&t); -} - -Route *Route::find(const TrackIter &from, Track &to) -{ - return create_route(from, TrackMatch(to)); -} - -Route *Route::find(const TrackIter &from, const Route &to) -{ - return create_route(from, TrackInSet(to.get_tracks())); -} - -Route *Route::find(const TrackIter &from, const set &to) -{ - return create_route(from, TrackInSet(to)); -} - - -Route::Loader::Loader(Route &r): - DataFile::BasicLoader(r) -{ - add("name", &Route::name); - add("turnout", &Loader::turnout); -} - -void Route::Loader::finish() -{ - const set <racks = obj.layout.get_tracks(); - for(set::const_iterator i=ltracks.begin(); i!=ltracks.end(); ++i) - { - unsigned tid = (*i)->get_turnout_id(); - if(!tid) - continue; - - TurnoutMap::iterator j = turnouts.find(tid); - if(j==turnouts.end()) - continue; - - unsigned path_mask = 1<second; - const vector &eps = (*i)->get_type().get_endpoints(); - for(unsigned k=0; kget_link(k); - if(!obj.tracks.count(link)) - obj.add_track_chain(*link, link->get_endpoint_by_link(**i), turnouts); - if(!obj.tracks.count(*i)) - obj.add_track_chain(**i, k, turnouts); - break; - } - - break; - } -} - -void Route::Loader::turnout(unsigned id, unsigned path) -{ - turnouts[id] = path; -} - -} // namespace Marklin diff --git a/source/libmarklin/route.h b/source/libmarklin/route.h deleted file mode 100644 index 0b03637..0000000 --- a/source/libmarklin/route.h +++ /dev/null @@ -1,80 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2007-2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#ifndef LIBMARKLIN_ROUTE_H_ -#define LIBMARKLIN_ROUTE_H_ - -#include -#include -#include -#include -#include - -namespace Marklin { - -class Layout; -class Track; -class TrackIter; - -class Route: public sigc::trackable -{ -public: - typedef std::map TurnoutMap; - - class Loader: public Msp::DataFile::BasicLoader - { - private: - TurnoutMap turnouts; - - public: - Loader(Route &); - private: - virtual void finish(); - void turnout(unsigned, unsigned); - }; - - sigc::signal signal_name_changed; - -private: - Layout &layout; - std::string name; - bool temporary; - std::set tracks; - TurnoutMap turnouts; - -public: - Route(Layout &); - ~Route(); - - void set_name(const std::string &); - const std::string &get_name() const { return name; } - void set_temporary(bool); - bool is_temporary() const { return temporary; } - void set_turnout(unsigned, unsigned); - void update_turnouts(); - int get_turnout(unsigned) const; - unsigned get_path(Track &) const; - const std::map &get_turnouts() const { return turnouts; } - void add_track(Track &); - void add_tracks(const std::set &); - void add_track_chain(Track &, unsigned, const TurnoutMap &); - const std::set &get_tracks() const { return tracks; } - bool has_track(Track &) const; - void save(std::list &) const; -private: - unsigned check_validity(Track &) const; - void track_removed(Track &); - -public: - static Route *find(const TrackIter &, Track &); - static Route *find(const TrackIter &, const Route &); - static Route *find(const TrackIter &, const std::set &); -}; - -} // namespace Marklin - -#endif diff --git a/source/libmarklin/simplecontroller.cpp b/source/libmarklin/simplecontroller.cpp deleted file mode 100644 index 5744188..0000000 --- a/source/libmarklin/simplecontroller.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#include -#include -#include "simplecontroller.h" - -using namespace std; -using namespace Msp; - -namespace Marklin { - -SimpleController::SimpleController(): - target_speed(Control::continuous("speed", 0, 1000)), - reverse(Control::binary("reverse")), - accel(0.07), - speed(0) -{ - target_speed.set(0); -} - -void SimpleController::set_control(const string &name, float v) -{ - if(name=="speed") - { - target_speed.set(v); - signal_control_changed.emit(target_speed); - } - else if(name=="reverse") - { - if(target_speed.value || speed) - throw InvalidState("Must be stopped to change reverse"); - reverse.set(v); - signal_control_changed.emit(reverse); - } -} - -const Controller::Control &SimpleController::get_control(const string &name) const -{ - if(name=="speed") - return target_speed; - else if(name=="reverse") - return reverse; - else - throw KeyError("Unknown control", name); -} - -float SimpleController::get_braking_distance() const -{ - return speed*speed/(2*accel); -} - -void SimpleController::tick(const Time::TimeDelta &dt) -{ - float secs = dt/Time::sec; - if(speedtarget_speed.value) - speed = target_speed.value; - } - else if(speed>target_speed.value) - { - speed -= secs*accel; - if(speed -#include "controller.h" - -namespace Marklin { - -class SimpleController: public Controller -{ -private: - Control target_speed; - Control reverse; - float accel; - float speed; - -public: - SimpleController(); - - virtual void set_control(const std::string &, float); - virtual const Control &get_control(const std::string &) const; - - virtual float get_speed() const { return speed; } - virtual bool get_reverse() const { return reverse.value; } - virtual float get_braking_distance() const; - - virtual void tick(const Msp::Time::TimeDelta &); -}; - -} // namespace Marklin - -#endif diff --git a/source/libmarklin/timetable.cpp b/source/libmarklin/timetable.cpp deleted file mode 100644 index a699fc8..0000000 --- a/source/libmarklin/timetable.cpp +++ /dev/null @@ -1,337 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#include -#include -#include "block.h" -#include "catalogue.h" -#include "driver.h" -#include "layout.h" -#include "timetable.h" -#include "train.h" - -using namespace std; -using namespace Msp; - -namespace Marklin { - -Timetable::Timetable(Train &t): - train(t), - enabled(false), - current_row(0), - executing(true), - pending_block(0), - pending_train(0) -{ - train.signal_arrived.connect(sigc::mem_fun(this, &Timetable::train_arrived)); - train.get_layout().get_driver().signal_sensor.connect(sigc::mem_fun(this, &Timetable::sensor_event)); -} - -void Timetable::set_enabled(bool e) -{ - enabled = e; -} - -void Timetable::reset() -{ - current_row = 0; - wait_timeout = Time::TimeStamp(); - pending_block = 0; - executing = true; -} - -void Timetable::clear() -{ - rows.clear(); - reset(); -} - -void Timetable::append(const Row &row) -{ - rows.push_back(row); -} - -void Timetable::insert(unsigned i, const Row &row) -{ - if(i>rows.size()) - throw InvalidParameterValue("Insert position out of range"); - - rows.insert(rows.begin()+i, row); - if(i<=current_row) - ++current_row; -} - -const Timetable::Row &Timetable::get_row(unsigned i) const -{ - if(i>=rows.size()) - throw InvalidParameterValue("Row index out of range"); - return rows[i]; -} - -void Timetable::tick(const Time::TimeStamp &t) -{ - if(rows.empty() || !enabled) - return; - - if(wait_timeout && t>=wait_timeout) - { - wait_timeout = Time::TimeStamp(); - current_row = (current_row+1)%rows.size(); - executing = true; - } - - if(executing) - { - Row &row = rows[current_row]; - switch(row.type) - { - case GOTO: - if(!train.go_to(**parse_location(row.get_param(0)).get_tracks().begin())) - set_enabled(false); - break; - case TRAVEL: - pending_block = &parse_location(row.get_param(0)); - pending_train = &train; - executing = false; - break; - case WAIT_TIME: - wait_timeout = t+row.get_param(0)*Time::sec; - executing = false; - break; - case WAIT_TRAIN: - pending_train = &train.get_layout().get_train(row.get_param(0)); - pending_block = &parse_location(row.get_param(1)); - executing = false; - break; - case ARRIVE: - executing = false; - break; - case SPEED: - train.set_control("speed", row.get_param(0)/3.6*train.get_layout().get_catalogue().get_scale()); - break; - case REVERSE: - train.set_control("reverse", !train.get_control("reverse")); - break; - case ROUTE: - if(!train.set_route(&train.get_layout().get_route(row.get_param(0)))) - set_enabled(false); - break; - } - - if(executing) - current_row = (current_row+1)%rows.size(); - } -} - -void Timetable::save(list &st) const -{ - for(vector::const_iterator i=rows.begin(); i!=rows.end(); ++i) - st.push_back(i->save()); -} - -Block &Timetable::parse_location(const string &loc) -{ - if(!loc.compare(0, 7, "sensor ")) - return train.get_layout().get_block(lexical_cast(loc.substr(7))|0x1000); - throw Exception("Named blocks are not supported yet"); -} - -void Timetable::sensor_event(unsigned addr, bool state) -{ - if(pending_block && pending_block->get_train()==pending_train && addr==pending_block->get_sensor_id() && state) - { - pending_block = 0; - current_row = (current_row+1)%rows.size(); - executing = true; - } -} - -void Timetable::train_arrived() -{ - Row &row = rows[current_row]; - if(row.type==ARRIVE) - { - current_row = (current_row+1)%rows.size(); - executing = true; - } -} - - -Timetable::Row::Row(RowType t): - type(t) -{ } - -template -Timetable::Row::Row(RowType t, const T &p): - type(t) -{ - params.push_back(p); -} - -template -const T &Timetable::Row::get_param(unsigned i) const -{ - if(i>=params.size()) - throw InvalidParameterValue("Parameter index out of range"); - return params[i].value(); -} - -string Timetable::Row::str() const -{ - switch(type) - { - case GOTO: - return "set route to "+get_param(0); - case TRAVEL: - return "travel to "+get_param(0); - case WAIT_TIME: - return format("wait for %d seconds", get_param(0)); - case WAIT_TRAIN: - return format("wait for train %d at %s", get_param(0), get_param(1)); - case ARRIVE: - return "travel until arrival"; - case SPEED: - return format("set speed %d km/h", get_param(0)); - case REVERSE: - return "reverse"; - case ROUTE: - return "set route "+get_param(0); - default: - return "invalid row"; - } -} - -DataFile::Statement Timetable::Row::save() const -{ - switch(type) - { - case GOTO: - return DataFile::Statement("goto"), get_param(0); - case TRAVEL: - return DataFile::Statement("travel"), get_param(0); - case WAIT_TIME: - return DataFile::Statement("wait"), get_param(0); - case WAIT_TRAIN: - return DataFile::Statement("wait_train"), get_param(0), get_param(1); - case ARRIVE: - return DataFile::Statement("arrive"); - case SPEED: - return DataFile::Statement("speed"), get_param(0); - case REVERSE: - return DataFile::Statement("reverse"); - case ROUTE: - return DataFile::Statement("route"), get_param(0); - default: - return DataFile::Statement(); - } -} - -Timetable::Row Timetable::Row::parse(const string &s) -{ - if(!s.compare(0, 7, "travel ")) - { - if(!s.compare(7, 3, "to ")) - return Row(TRAVEL, s.substr(10)); - else if(!s.compare(7, string::npos, "until arrival")) - return Row(ARRIVE); - } - else if(!s.compare(0, 9, "wait for ")) - { - if(isdigit(s[9])) - { - unsigned nondigit = 10; - while(nondigit(s.substr(9, nondigit-9))); - } - else if(!s.compare(9, 6, "train ")) - { - string::size_type at = s.find(" at ", 15); - if(at!=string::npos) - { - Row row(WAIT_TRAIN, lexical_cast(s.substr(15, at-15))); - row.params.push_back(s.substr(at+4)); - return row; - } - } - } - else if(!s.compare(0, 10, "set speed ")) - { - unsigned nondigit = 11; - while(nondigit(s.substr(10, nondigit-10))); - } - else if(s=="reverse") - return Row(REVERSE); - else if(!s.compare(0, 10, "set route ")) - { - if(!s.compare(10, 3, "to ")) - return Row(GOTO, s.substr(13)); - return Row(ROUTE, s.substr(10)); - } - - throw InvalidParameterValue("Invalid row"); -} - - -Timetable::Loader::Loader(Timetable &tt): - DataFile::ObjectLoader(tt) -{ - add("arrive", &Loader::arrive); - add("goto", &Loader::go_to); - add("route", &Loader::route); - add("speed", &Loader::speed); - add("reverse", &Loader::reverse); - add("travel", &Loader::travel); - add("wait", &Loader::wait); - add("wait_train", &Loader::wait_train); -} - -void Timetable::Loader::arrive() -{ - obj.rows.push_back(Row(ARRIVE)); -} - -void Timetable::Loader::go_to(const string &t) -{ - obj.rows.push_back(Row(GOTO, t)); -} - -void Timetable::Loader::route(const string &r) -{ - obj.rows.push_back(Row(ROUTE, r)); -} - -void Timetable::Loader::reverse() -{ - obj.rows.push_back(Row(REVERSE)); -} - -void Timetable::Loader::speed(unsigned s) -{ - obj.rows.push_back(Row(SPEED, s)); -} - -void Timetable::Loader::travel(const string &t) -{ - obj.rows.push_back(Row(TRAVEL, t)); -} - -void Timetable::Loader::wait(unsigned t) -{ - obj.rows.push_back(Row(WAIT_TIME, t)); -} - -void Timetable::Loader::wait_train(unsigned t, const string &b) -{ - Row row(WAIT_TRAIN, t); - row.params.push_back(b); - obj.rows.push_back(row); -} - -} // namespace Marklin diff --git a/source/libmarklin/timetable.h b/source/libmarklin/timetable.h deleted file mode 100644 index b4f9cc1..0000000 --- a/source/libmarklin/timetable.h +++ /dev/null @@ -1,105 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#ifndef LIBMARKLIN_TIMETABLE_H_ -#define LIBMARKLIN_TIMETABLE_H_ - -#include -#include -#include -#include -#include - -namespace Marklin { - -class Block; -class Train; - -class Timetable: public sigc::trackable -{ -public: - class Loader: public Msp::DataFile::ObjectLoader - { - public: - Loader(Timetable &); - private: - void arrive(); - void go_to(const std::string &); - void route(const std::string &); - void reverse(); - void speed(unsigned); - void travel(const std::string &); - void wait(unsigned); - void wait_train(unsigned, const std::string &); - }; - - enum RowType - { - GOTO, - TRAVEL, - WAIT_TIME, - WAIT_TRAIN, - ARRIVE, - SPEED, - REVERSE, - ROUTE - }; - - struct Row - { - RowType type; - std::vector params; - - Row(RowType); - - template - Row(RowType, const T &); - - template - const T &get_param(unsigned) const; - - std::string str() const; - - Msp::DataFile::Statement save() const; - - static Row parse(const std::string &); - }; - -private: - Train &train; - bool enabled; - std::vector rows; - unsigned current_row; - bool executing; - Block *pending_block; - Train *pending_train; - Msp::Time::TimeStamp wait_timeout; - -public: - Timetable(Train &); - - void set_enabled(bool); - bool is_enabled() const { return enabled; } - void reset(); - - void clear(); - void append(const Row &); - void insert(unsigned, const Row &); - unsigned get_n_rows() const { return rows.size(); } - const Row &get_row(unsigned) const; - - void tick(const Msp::Time::TimeStamp &); - void save(std::list &) const; -private: - Block &parse_location(const std::string &); - void sensor_event(unsigned, bool); - void train_arrived(); -}; - -} // namespace Marklin - -#endif diff --git a/source/libmarklin/track.cpp b/source/libmarklin/track.cpp deleted file mode 100644 index fbe3f0a..0000000 --- a/source/libmarklin/track.cpp +++ /dev/null @@ -1,392 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#include -#include "block.h" -#include "catalogue.h" -#include "driver.h" -#include "layout.h" -#include "track.h" -#include "tracktype.h" - -using namespace std; -using namespace Msp; - -namespace Marklin { - -Track::Track(Layout &l, const TrackType &t): - layout(l), - type(t), - block(0), - rot(0), - slope(0), - flex(false), - turnout_id(type.is_turnout() ? layout.allocate_turnout_id(type.is_double_address()) : 0), - sensor_id(0), - links(type.get_endpoints().size()), - active_path(0) -{ - layout.add_track(*this); - - if(layout.has_driver()) - layout.get_driver().signal_turnout.connect(sigc::mem_fun(this, &Track::turnout_event)); - - for(unsigned paths = type.get_paths(); !(paths&1); ++active_path, paths>>=1) ; -} - -Track::~Track() -{ - break_links(); - layout.remove_track(*this); -} - -void Track::set_block(Block *b) -{ - if(b && !b->has_track(*this)) - throw InvalidParameterValue("Track is not in the Block"); - if(!b && block && block->has_track(*this)) - throw InvalidState("Track is still in a Block"); - - block = b; -} - -Block &Track::get_block() const -{ - if(!block) - throw InvalidState("No Block"); - - return *block; -} - -void Track::set_position(const Point &p) -{ - pos = p; -} - -void Track::set_rotation(float r) -{ - rot = r; - while(rot<0) - rot += M_PI*2; - while(rot>M_PI*2) - rot -= M_PI*2; -} - -void Track::set_slope(float s) -{ - if(links.size()!=2) - return; - - slope = s; -} - -void Track::set_flex(bool f) -{ - flex = f; -} - -void Track::check_slope() -{ - if(links.size()!=2) - return; - - if(links[0] && links[1]) - { - Point epp0 = links[0]->get_endpoint_position(links[0]->get_endpoint_by_link(*this)); - Point epp1 = links[1]->get_endpoint_position(links[1]->get_endpoint_by_link(*this)); - pos.z = epp0.z; - slope = epp1.z-pos.z; - } - else - { - slope = 0; - if(links[0]) - { - Point epp = links[0]->get_endpoint_position(links[0]->get_endpoint_by_link(*this)); - pos.z = epp.z; - } - else if(links[1]) - { - Point epp = links[1]->get_endpoint_position(links[1]->get_endpoint_by_link(*this)); - pos.z = epp.z; - } - } -} - -void Track::set_turnout_id(unsigned i) -{ - if(!type.is_turnout()) - throw InvalidState("Not a turnout"); - - turnout_id = i; - layout.create_blocks(*this); - layout.update_routes(); - if(layout.has_driver() && turnout_id) - { - layout.get_driver().add_turnout(turnout_id); - if(type.is_double_address()) - layout.get_driver().add_turnout(turnout_id+1); - } -} - -void Track::set_sensor_id(unsigned i) -{ - if(type.is_turnout()) - throw InvalidState("Can't set sensor on a turnout"); - - sensor_id = i; - layout.create_blocks(*this); - if(layout.has_driver() && sensor_id) - layout.get_driver().add_sensor(sensor_id); -} - -void Track::set_active_path(unsigned p) -{ - if(!turnout_id) - throw InvalidState("Not a turnout"); - if(!(type.get_paths()&(1<2) - active_path = (active_path&1) | (p&2); -} - -int Track::get_endpoint_by_link(Track &other) const -{ - for(unsigned i=0; i &eps = type.get_endpoints(); - if(epi>=eps.size()) - throw InvalidParameterValue("TrackType::Endpoint index out of range"); - - const TrackType::Endpoint &ep = eps[epi]; - - float c = cos(rot); - float s = sin(rot); - - Point p(pos.x+c*ep.pos.x-s*ep.pos.y, pos.y+s*ep.pos.x+c*ep.pos.y, pos.z); - if(eps.size()==2 && epi==1) - p.z += slope; - return p; -} - -float Track::get_endpoint_direction(unsigned epi) const -{ - const vector &eps = type.get_endpoints(); - if(epi>=eps.size()) - throw InvalidParameterValue("TrackType::Endpoint index out of range"); - - const TrackType::Endpoint &ep = eps[epi]; - - return rot+ep.dir; -} - -bool Track::snap_to(Track &other, bool link, float limit) -{ - if(!limit || link) - { - limit = layout.get_catalogue().get_gauge(); - if(link && !flex && !other.get_flex()) - limit /= 10; - } - limit *= limit; - - const vector &eps = type.get_endpoints(); - const vector &other_eps = other.get_type().get_endpoints(); - - for(unsigned i=0; i &eps = type.get_endpoints(); - - for(unsigned i=0; i::iterator i=links.begin(); i!=links.end(); ++i) - if(*i==&trk) - { - *i = 0; - trk.break_link(*this); - // XXX Creates the blocks twice - layout.create_blocks(*this); - return; - } -} - -void Track::break_links() -{ - for(vector::iterator i=links.begin(); i!=links.end(); ++i) - if(Track *trk=*i) - { - *i = 0; - trk->break_link(*this); - } -} - -Track *Track::get_link(unsigned i) const -{ - if(i>links.size()) - throw InvalidParameterValue("Link index out of range"); - - return links[i]; -} - -TrackPoint Track::get_point(unsigned epi, unsigned path, float d) const -{ - TrackPoint p = type.get_point(epi, path, d); - float c = cos(rot); - float s = sin(rot); - - p.pos = Point(pos.x+c*p.pos.x-s*p.pos.y, pos.y+s*p.pos.x+c*p.pos.y, pos.z); - p.dir += rot; - if(type.get_endpoints().size()==2) - { - float len = type.get_path_length(path); - float grade = slope/len; - if(epi==0) - { - p.pos.z += grade*d; - p.grade = grade; - } - else - { - p.pos.z += slope-grade*d; - p.grade = -grade; - } - } - - return p; -} - -TrackPoint Track::get_point(unsigned epi, float d) const -{ - return get_point(epi, active_path, d); -} - -void Track::save(list &st) const -{ - st.push_back((DataFile::Statement("position"), pos.x, pos.y, pos.z)); - st.push_back((DataFile::Statement("rotation"), rot)); - st.push_back((DataFile::Statement("slope"), slope)); - if(turnout_id) - st.push_back((DataFile::Statement("turnout_id"), turnout_id)); - if(sensor_id) - st.push_back((DataFile::Statement("sensor_id"), sensor_id)); - if(flex) - st.push_back((DataFile::Statement("flex"), true)); -} - -void Track::turnout_event(unsigned addr, bool state) -{ - if(!turnout_id) - return; - - if(addr==turnout_id) - active_path = (active_path&2) | (state ? 1 : 0); - else if(type.is_double_address() && addr==turnout_id+1) - active_path = (active_path&1) | (state ? 2 : 0); - else - return; - - signal_path_changed.emit(active_path); -} - - -Track::Loader::Loader(Track &t): - DataFile::BasicLoader(t) -{ - add("position", &Loader::position); - add("rotation", &Track::rot); - add("slope", &Track::slope); - add("turnout_id", &Loader::turnout_id); - add("sensor_id", &Loader::sensor_id); - add("flex", &Track::flex); -} - -void Track::Loader::position(float x, float y, float z) -{ - obj.pos = Point(x, y, z); -} - -void Track::Loader::sensor_id(unsigned id) -{ - obj.set_sensor_id(id); -} - -void Track::Loader::turnout_id(unsigned id) -{ - obj.set_turnout_id(id); -} - -} // namespace Marklin diff --git a/source/libmarklin/track.h b/source/libmarklin/track.h deleted file mode 100644 index f065cb6..0000000 --- a/source/libmarklin/track.h +++ /dev/null @@ -1,98 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#ifndef LIBMARKLIN_TRACK_H_ -#define LIBMARKLIN_TRACK_H_ - -#include -#include -#include -#include -#include "geometry.h" - -namespace Marklin { - -class Block; -class Layout; -class TrackType; - -class Track: public sigc::trackable -{ -public: - class Loader: public Msp::DataFile::BasicLoader - { - public: - Loader(Track &); - private: - void position(float, float, float); - void sensor_id(unsigned); - void turnout_id(unsigned); - }; - - sigc::signal signal_path_changed; - -private: - Layout &layout; - const TrackType &type; - Block *block; - Point pos; - float rot; - float slope; - bool flex; - unsigned turnout_id; - unsigned sensor_id; - std::vector links; - unsigned active_path; - - Track(const Track &); - Track &operator=(const Track &); -public: - Track(Layout &, const TrackType &); - ~Track(); - - Layout &get_layout() const { return layout; } - const TrackType &get_type() const { return type; } - - void set_block(Block *); - Block &get_block() const; - void set_position(const Point &); - void set_rotation(float); - void set_slope(float); - void set_flex(bool); - const Point &get_position() const { return pos; } - float get_rotation() const { return rot; } - float get_slope() const { return slope; } - bool get_flex() const { return flex; } - void check_slope(); - - void set_turnout_id(unsigned); - void set_sensor_id(unsigned); - unsigned get_turnout_id() const { return turnout_id; } - unsigned get_sensor_id() const { return sensor_id; } - void set_active_path(unsigned); - unsigned get_active_path() const { return active_path; } - - int get_endpoint_by_link(Track &) const; - Point get_endpoint_position(unsigned) const; - float get_endpoint_direction(unsigned) const; - bool snap_to(Track &, bool, float = 0); - bool snap(Point &, float &) const; - void break_link(Track &); - void break_links(); - const std::vector &get_links() const { return links; } - Track *get_link(unsigned) const; - TrackPoint get_point(unsigned, unsigned, float) const; - TrackPoint get_point(unsigned, float) const; - - void save(std::list &) const; -private: - void turnout_event(unsigned, bool); -}; - -} // namespace Marklin - -#endif diff --git a/source/libmarklin/trackiter.cpp b/source/libmarklin/trackiter.cpp deleted file mode 100644 index b980228..0000000 --- a/source/libmarklin/trackiter.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#include -#include -#include "track.h" -#include "trackiter.h" -#include "tracktype.h" - -using namespace std; -using namespace Msp; - -namespace Marklin { - -TrackIter::TrackIter(): - _track(0), - _entry(0) -{ } - -TrackIter::TrackIter(Track *t, unsigned e): - _track(t), - _entry(t ? e : 0) -{ - if(_track && _entry>_track->get_type().get_endpoints().size()) - throw InvalidParameterValue("Endpoint index not valid for track"); -} - -const TrackType::Endpoint &TrackIter::endpoint() const -{ - if(!_track) - throw InvalidState("TrackIter is null"); - - return _track->get_type().get_endpoint(_entry); -} - -int TrackIter::get_exit(unsigned path) const -{ - const vector &eps = _track->get_type().get_endpoints(); - - // Find an endpoint that's connected to the entry and has the requested path - for(unsigned i=0; iget_active_path()); -} - -TrackIter TrackIter::next(unsigned path) const -{ - if(!_track) - return TrackIter(); - - int exit = get_exit(path); - if(exit<0) - return TrackIter(); - - TrackIter result; - result._track = _track->get_link(exit); - result._entry = (result._track ? result._track->get_endpoint_by_link(*_track) : 0); - - return result; -} - -TrackIter TrackIter::reverse() const -{ - if(!_track) - return TrackIter(); - - return reverse(_track->get_active_path()); -} - -TrackIter TrackIter::reverse(unsigned path) const -{ - if(!_track) - return TrackIter(); - - int exit = get_exit(path); - if(exit<0) - return TrackIter(); - - return TrackIter(_track, exit); -} - -TrackIter TrackIter::flip() const -{ - if(!_track) - return TrackIter(); - - TrackIter result; - result._track = _track->get_link(_entry); - result._entry = (result._track ? result._track->get_endpoint_by_link(*_track) : 0); - - return result; -} - -Track &TrackIter::operator*() const -{ - if(!_track) - throw InvalidState("TrackIter is null"); - - return *_track; -} - -bool TrackIter::operator==(const TrackIter &other) const -{ - return _track==other._track && _entry==other._entry; -} - - -TrackLoopIter::TrackLoopIter(): - _looped(false) -{ } - -TrackLoopIter::TrackLoopIter(Track *t, unsigned e): - TrackIter(t, e), - _visited(new TrackList()), - _last(_visited->insert(_visited->end(), track())), - _looped(false) -{ } - -TrackLoopIter::TrackLoopIter(const TrackIter &i): - TrackIter(i), - _visited(new TrackList()), - _last(_visited->insert(_visited->end(), track())), - _looped(false) -{ } - -TrackLoopIter::TrackLoopIter(const TrackIter &i, RefPtr v, const TrackList::iterator &l): - TrackIter(i), - _looped(false) -{ - if(track()) - { - _visited = v; - _last = l; - _looped = (_visited && find(_visited->begin(), _last, track())!=_last); - - ++_last; - if(_last!=_visited->end()) - { - _visited = new TrackList(_visited->begin(), _last); - _last = _visited->end(); - } - _visited->push_back(track()); - --_last; - } -} - -TrackLoopIter TrackLoopIter::next() const -{ - return TrackLoopIter(TrackIter::next(), _visited, _last); -} - -TrackLoopIter TrackLoopIter::next(unsigned path) const -{ - return TrackLoopIter(TrackIter::next(path), _visited, _last); -} - -} // namespace Marklin diff --git a/source/libmarklin/trackiter.h b/source/libmarklin/trackiter.h deleted file mode 100644 index e2f1d85..0000000 --- a/source/libmarklin/trackiter.h +++ /dev/null @@ -1,85 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#ifndef LIBMARKLIN_TRACKITER_H_ -#define LIBMARKLIN_TRACKITER_H_ - -#include -#include -#include "tracktype.h" - -namespace Marklin { - -class Track; - -/** -An iterator for traversing tracks. -*/ -class TrackIter -{ -private: - Track *_track; - unsigned _entry; - -public: - TrackIter(); - TrackIter(Track *, unsigned); - - Track *track() const { return _track; } - unsigned entry() const { return _entry; } - const TrackType::Endpoint &endpoint() const; - -private: - int get_exit(unsigned) const; -public: - TrackIter next() const; - TrackIter next(unsigned) const; - TrackIter reverse() const; - TrackIter reverse(unsigned) const; - TrackIter flip() const; - - Track &operator*() const; - Track *operator->() const { return _track; } - bool operator==(const TrackIter &) const; - bool operator!=(const TrackIter &other) const { return !(*this==other); } - operator bool() const { return _track!=0; } -}; - - -/** -A track iterator that detects looping. - -A list of visited tracks is maintained internally to the iterator. This list -is shared between iterators as long as next() is only called once per iterator. -Subsequent calls to next() cause the head of the list to be copied. -*/ -class TrackLoopIter: public TrackIter -{ -private: - typedef std::list TrackList; - - Msp::RefPtr _visited; - TrackList::iterator _last; - bool _looped; - -public: - TrackLoopIter(); - TrackLoopIter(Track *, unsigned); - TrackLoopIter(const TrackIter &); -private: - TrackLoopIter(const TrackIter &, Msp::RefPtr, const TrackList::iterator &); - -public: - bool looped() const { return _looped; } - - TrackLoopIter next() const; - TrackLoopIter next(unsigned) const; -}; - -} // namespace Marklin - -#endif diff --git a/source/libmarklin/trackpart.cpp b/source/libmarklin/trackpart.cpp deleted file mode 100644 index 37c5f97..0000000 --- a/source/libmarklin/trackpart.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#include -#include "trackpart.h" - -using namespace std; -using namespace Msp; - -namespace Marklin { - -TrackPart::TrackPart(): - dir(0), - length(0), - radius(0), - path(0), - dead_end(false) -{ - links[0] = 0; - links[1] = 0; -} - -float TrackPart::get_length() const -{ - if(radius) - return abs(radius)*length; - else - return length; -} - -TrackPoint TrackPart::get_point(float d) const -{ - TrackPoint result; - - if(radius) - { - float a = d/radius; - float c = cos(a); - float s = sin(a); - float rx = radius*sin(dir); - float ry = -radius*cos(dir); - result.pos = Point(pos.x+c*rx-s*ry-rx, pos.y+c*ry+s*rx-ry); - result.dir = dir+a; - } - else - { - result.pos = Point(pos.x+cos(dir)*d, pos.y+sin(dir)*d); - result.dir = dir; - } - - return result; -} - -void TrackPart::check_link(TrackPart &other) -{ - unsigned n_eps = (dead_end ? 1 : 2); - unsigned n_other_eps = (other.is_dead_end() ? 1 : 2); - for(unsigned i=0; iM_PI) - da -= M_PI*2; - while(da<-M_PI) - da += M_PI*2; - - if(dx*dx+dy*dy<1e-6 && da>=-0.01 && da<=0.01) - { - links[i] = &other; - other.links[j] = this; - return; - } - } - } -} - -TrackPart *TrackPart::get_link(unsigned i) const -{ - if(i>=2) - throw InvalidParameterValue("Index out of range"); - return links[i]; -} - - -TrackPart::Loader::Loader(TrackPart &p): - Msp::DataFile::BasicLoader(p) -{ - add("start", &Loader::start); - add("length", &TrackPart::length); - add("radius", &TrackPart::radius); - add("path", &TrackPart::path); - add("dead_end", &TrackPart::dead_end); -} - -void TrackPart::Loader::finish() -{ - if(obj.radius) - { - obj.length *= M_PI/180; - obj.radius /= 1000; - } - else - obj.length /= 1000; - - obj.pos.x /= 1000; - obj.pos.y /= 1000; - obj.dir *= M_PI/180; -} - -void TrackPart::Loader::start(float x, float y, float d) -{ - obj.pos = Point(x, y); - obj.dir = d; -} - -} // namespace Marklin diff --git a/source/libmarklin/trackpart.h b/source/libmarklin/trackpart.h deleted file mode 100644 index 13e0f38..0000000 --- a/source/libmarklin/trackpart.h +++ /dev/null @@ -1,51 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#ifndef MARKLIN_TRACKPART_H_ -#define MARKLIN_TRACKPART_H_ - -#include -#include "geometry.h" - -namespace Marklin { - -class TrackPart -{ -public: - class Loader: public Msp::DataFile::BasicLoader - { - public: - Loader(TrackPart &); - private: - virtual void finish(); - void start(float, float, float); - }; - -private: - Point pos; - float dir; - float length; - float radius; - unsigned path; - bool dead_end; - TrackPart *links[2]; - -public: - TrackPart(); - - float get_length() const; - bool is_curved() const { return radius; } - TrackPoint get_point(float) const; - unsigned get_path() const { return path; } - bool is_dead_end() const { return dead_end; } - void check_link(TrackPart &); - TrackPart *get_link(unsigned) const; -}; - -} // namespace Marklin - -#endif diff --git a/source/libmarklin/tracktype.cpp b/source/libmarklin/tracktype.cpp deleted file mode 100644 index 9f2979b..0000000 --- a/source/libmarklin/tracktype.cpp +++ /dev/null @@ -1,194 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#include -#include "tracktype.h" - -using namespace std; -using namespace Msp; - -namespace Marklin { - -TrackType::TrackType(const ArticleNumber &an): - art_nr(an), - double_address(false), - autofit_preference(1) -{ } - -float TrackType::get_total_length() const -{ - return get_path_length(-1); -} - -float TrackType::get_path_length(int p) const -{ - float len = 0; - for(vector::const_iterator i=parts.begin(); i!=parts.end(); ++i) - if(p<0 || i->get_path()==static_cast(p)) - len += i->get_length(); - return len; -} - -unsigned TrackType::get_paths() const -{ - unsigned mask = 0; - for(vector::const_iterator i=parts.begin(); i!=parts.end(); ++i) - mask |= 1<get_path(); - return mask; -} - -unsigned TrackType::get_n_paths() const -{ - unsigned n = 0; - for(unsigned mask = get_paths(); mask; ++n) - mask &= mask-1; - return n; -} - -bool TrackType::is_turnout() const -{ - return endpoints.size()>2; -} - -bool TrackType::is_dead_end() const -{ - return endpoints.size()<2; -} - -const TrackType::Endpoint &TrackType::get_endpoint(unsigned i) const -{ - if(i>=endpoints.size()) - throw InvalidParameterValue("Endpoint index out of range"); - - return endpoints[i]; -} - -TrackPoint TrackType::get_point(unsigned epi, unsigned path, float d) const -{ - if(epi>=endpoints.size()) - throw InvalidParameterValue("Endpoint index out of range"); - - const TrackPart *part = 0; - unsigned part_ep = 0; - for(vector::const_iterator i=parts.begin(); i!=parts.end(); ++i) - { - if((endpoints[epi].paths&(1<get_path()!=path) - continue; - - unsigned n_part_eps = (i->is_dead_end() ? 1 : 2); - for(unsigned j=0; jget_point(j ? i->get_length() : 0); - float dx = p.pos.x-endpoints[epi].pos.x; - float dy = p.pos.y-endpoints[epi].pos.y; - if(dx*dx+dy*dy<1e-6) - { - part = &*i; - part_ep = j; - } - } - } - - if(!part) - throw Exception("Internal error (endpoint does not match any part)"); - - while(1) - { - float plen = part->get_length(); - if(d<=plen) - { - if(part_ep==1) - d = plen-d; - TrackPoint p = part->get_point(d); - if(part_ep==1) - p.dir += M_PI; - return p; - } - else - { - d -= plen; - TrackPart *next = part->get_link(1-part_ep); - if(!next) - throw InvalidParameterValue("Distance out of range"); - part_ep = (next->get_link(0)==part ? 0 : 1); - part = next; - } - } -} - -void TrackType::collect_endpoints() -{ - endpoints.clear(); - - for(vector::iterator i=parts.begin(); i!=parts.end(); ++i) - { - for(vector::iterator j=i; ++j!=parts.end();) - i->check_link(*j); - - unsigned n_part_eps = (i->is_dead_end() ? 1 : 2); - for(unsigned j=0; jget_link(j)) - { - TrackPoint p = i->get_point(j ? i->get_length() : 0); - if(j==0) - p.dir += M_PI; - - bool found = false; - for(vector::iterator k=endpoints.begin(); k!=endpoints.end(); ++k) - { - float dx = k->pos.x-p.pos.x; - float dy = k->pos.y-p.pos.y; - - float da = k->dir-p.dir; - while(da>M_PI) - da -= M_PI*2; - while(da<-M_PI) - da += M_PI*2; - - if(dx*dx+dy*dy<1e-6 && da>-0.01 && da<0.01) - { - k->paths |= 1<get_path(); - found = true; - break; - } - } - - if(!found) - endpoints.push_back(Endpoint(p.pos.x, p.pos.y, p.dir, 1<get_path())); - } - } -} - -TrackType::Endpoint::Endpoint(float x, float y, float d, unsigned p): - pos(x, y), - dir(d), - paths(p) -{ } - - -TrackType::Loader::Loader(TrackType &t): - Msp::DataFile::BasicLoader(t) -{ - add("autofit_preference", &TrackType::autofit_preference); - add("description", &TrackType::description); - add("double_address", &TrackType::double_address); - add("part", &Loader::part); -} - -void TrackType::Loader::finish() -{ - obj.collect_endpoints(); -} - -void TrackType::Loader::part() -{ - TrackPart p; - load_sub(p); - obj.parts.push_back(p); -} - -} // namespace Marklin diff --git a/source/libmarklin/tracktype.h b/source/libmarklin/tracktype.h deleted file mode 100644 index d13ea28..0000000 --- a/source/libmarklin/tracktype.h +++ /dev/null @@ -1,72 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#ifndef LIBMARKLIN_TRACKTYPE_H_ -#define LIBMARKLIN_TRACKTYPE_H_ - -#include -#include "articlenumber.h" -#include "geometry.h" -#include "trackpart.h" - -namespace Marklin { - -class TrackType -{ -public: - struct Endpoint - { - Point pos; - float dir; // Direction outwards from the endpoint - unsigned paths; - - Endpoint(float, float, float, unsigned); - }; - - class Loader: public Msp::DataFile::BasicLoader - { - public: - Loader(TrackType &); - private: - virtual void finish(); - void part(); - void position(float, float, float); - }; - -private: - ArticleNumber art_nr; - std::string description; - std::vector parts; - std::vector endpoints; - bool double_address; - unsigned autofit_preference; - -public: - TrackType(const ArticleNumber &); - - const ArticleNumber &get_article_number() const { return art_nr; } - const std::string &get_description() const { return description; } - float get_total_length() const; - float get_path_length(int) const; - unsigned get_paths() const; - unsigned get_n_paths() const; - bool is_turnout() const; - bool is_dead_end() const; - bool is_double_address() const { return double_address; } - unsigned get_autofit_preference() const { return autofit_preference; } - const std::vector &get_parts() const { return parts; } - const std::vector &get_endpoints() const { return endpoints; } - const Endpoint &get_endpoint(unsigned) const; - TrackPoint get_point(unsigned, unsigned, float) const; - -private: - void collect_endpoints(); -}; - -} // namespace Marklin - -#endif diff --git a/source/libmarklin/train.cpp b/source/libmarklin/train.cpp deleted file mode 100644 index 859d3da..0000000 --- a/source/libmarklin/train.cpp +++ /dev/null @@ -1,1420 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#include -#include -#include -#include -#include "aicontrol.h" -#include "catalogue.h" -#include "driver.h" -#include "layout.h" -#include "route.h" -#include "simplecontroller.h" -#include "timetable.h" -#include "trackiter.h" -#include "tracktype.h" -#include "train.h" -#include "vehicle.h" -#include "vehicletype.h" - -using namespace std; -using namespace Msp; - -namespace { - -struct SetFlag -{ - bool &flag; - - SetFlag(bool &f): flag(f) { flag = true; } - ~SetFlag() { flag = false; } -}; - -} - - -namespace Marklin { - -Train::Train(Layout &l, const VehicleType &t, unsigned a, const string &p): - layout(l), - loco_type(t), - address(a), - protocol(p), - priority(0), - yielding_to(0), - cur_blocks_end(blocks.end()), - clear_blocks_end(blocks.end()), - pending_block(0), - reserving(false), - advancing(false), - controller(new AIControl(*this, new SimpleController)), - timetable(0), - active(false), - current_speed_step(0), - speed_changing(false), - reverse(false), - functions(0), - end_of_route(false), - status("Unplaced"), - travel_dist(0), - pure_speed(false), - real_speed(layout.get_driver().get_protocol_speed_steps(protocol)+1), - accurate_position(false), - overshoot_dist(false) -{ - if(!loco_type.is_locomotive()) - throw InvalidParameterValue("Initial vehicle must be a locomotive"); - - vehicles.push_back(new Vehicle(layout, loco_type)); - - layout.add_train(*this); - - layout.get_driver().add_loco(address, protocol); - layout.get_driver().signal_loco_speed.connect(sigc::mem_fun(this, &Train::loco_speed_event)); - layout.get_driver().signal_loco_function.connect(sigc::mem_fun(this, &Train::loco_func_event)); - - layout.signal_block_reserved.connect(sigc::mem_fun(this, &Train::block_reserved)); - layout.get_driver().signal_sensor.connect(sigc::mem_fun(this, &Train::sensor_event)); - - layout.get_driver().signal_halt.connect(sigc::mem_fun(this, &Train::halt_event)); - - const set &tracks = layout.get_tracks(); - for(set::const_iterator i=tracks.begin(); i!=tracks.end(); ++i) - if((*i)->get_turnout_id()) - (*i)->signal_path_changed.connect(sigc::hide(sigc::bind(sigc::mem_fun(this, &Train::turnout_path_changed), sigc::ref(**i)))); - - controller->signal_control_changed.connect(sigc::mem_fun(this, &Train::control_changed)); -} - -Train::~Train() -{ - delete controller; - delete timetable; - for(vector::iterator i=vehicles.begin(); i!=vehicles.end(); ++i) - delete *i; - layout.remove_train(*this); -} - -void Train::set_name(const string &n) -{ - name = n; - - signal_name_changed.emit(name); -} - -void Train::set_priority(int p) -{ - priority = p; -} - -void Train::yield_to(const Train &t) -{ - yielding_to = &t; -} - -void Train::add_vehicle(const VehicleType &vt) -{ - Vehicle *veh = new Vehicle(layout, vt); - vehicles.back()->attach_back(*veh); - vehicles.push_back(veh); -} - -void Train::remove_vehicle(unsigned i) -{ - if(i>=vehicles.size()) - throw InvalidParameterValue("Vehicle index out of range"); - if(i==0) - throw InvalidParameterValue("Can't remove the locomotive"); - delete vehicles[i]; - vehicles.erase(vehicles.begin()+i); - if(iattach_back(*vehicles[i]); -} - -unsigned Train::get_n_vehicles() const -{ - return vehicles.size(); -} - -Vehicle &Train::get_vehicle(unsigned i) -{ - if(i>=vehicles.size()) - throw InvalidParameterValue("Vehicle index out of range"); - return *vehicles[i]; -} - -const Vehicle &Train::get_vehicle(unsigned i) const -{ - if(i>=vehicles.size()) - throw InvalidParameterValue("Vehicle index out of range"); - return *vehicles[i]; -} - -void Train::set_control(const string &n, float v) -{ - controller->set_control(n, v); -} - -void Train::set_active(bool a) -{ - if(a==active) - return; - if(!a && controller->get_speed()) - throw InvalidState("Can't deactivate while moving"); - - active = a; - if(active) - { - stop_timeout = Time::TimeStamp(); - reserve_more(); - } - else - { - stop_timeout = Time::now()+2*Time::sec; - set_status("Stopped"); - } -} - -void Train::set_function(unsigned func, bool state) -{ - if(!loco_type.get_functions().count(func)) - throw InvalidParameterValue("Invalid function"); - if(func<5) - layout.get_driver().set_loco_function(address, func, state); - else - layout.get_driver().set_loco_function(address+1, func-4, state); -} - -float Train::get_control(const string &ctrl) const -{ - return controller->get_control(ctrl).value; -} - -float Train::get_speed() const -{ - return controller->get_speed(); -} - -bool Train::get_function(unsigned func) const -{ - return (functions>>func)&1; -} - -void Train::set_timetable(Timetable *tt) -{ - delete timetable; - timetable = tt; -} - -bool Train::set_route(const Route *r) -{ - free_noncritical_blocks(); - - Route *lead = 0; - if(r && !blocks.empty()) - { - TrackIter first = blocks.front().track_iter(); - TrackIter next = blocks.back().next().track_iter(); - if(!r->has_track(*next)) - { - lead = Route::find(next, *r); - if(!lead) - return false; - create_lead_route(lead, lead); - routes.push_front(lead); - } - else if(!r->has_track(*first)) - lead = create_lead_route(0, r); - } - - routes.clear(); - if(lead) - routes.push_back(lead); - if(r) - routes.push_back(r); - end_of_route = false; - - reserve_more(); - - signal_route_changed.emit(get_route()); - - return true; -} - -bool Train::go_to(Track &to) -{ - for(BlockList::const_iterator i=blocks.begin(); i!=cur_blocks_end; ++i) - if((*i)->has_track(to)) - { - signal_arrived.emit(); - return set_route(0); - } - - free_noncritical_blocks(); - - TrackIter next = blocks.back().next().track_iter(); - - Route *route = Route::find(next, to); - if(!route) - return false; - create_lead_route(route, route); - return set_route(route); -} - -bool Train::divert(Track &from) -{ - if(!from.get_turnout_id()) - throw InvalidParameterValue("Can't divert from a non-turnout"); - if(routes.empty()) - return false; - - unsigned path = 0; - unsigned entry = 0; - list::iterator route = routes.begin(); - - // Follow our routes to find out where we're entering the turnout - for(TrackLoopIter track = blocks.front().track_iter();;) - { - if(!advance_route(route, *track)) - return false; - - if(&*track==&from) - { - Block &block = track->get_block(); - if(block.get_train()==this && !free_block(block)) - return false; - - int route_path = route->route->get_turnout(from.get_turnout_id()); - - // Check that more than one path is available - unsigned ep_paths = track.endpoint().paths; - if(!(ep_paths&(ep_paths-1))) - return false; - - // Choose some other path - for(int i=0; ep_paths>>i; ++i) - if((ep_paths&(1<route->get_path(*track)); - - if(!track || track.looped()) - return false; - } - - TrackIter track = TrackIter(&from, entry).next(path); - if(!track) - return false; - - set tracks; - for(list::iterator i=routes.begin(); i!=routes.end(); ++i) - tracks.insert(i->route->get_tracks().begin(), i->route->get_tracks().end()); - RefPtr diversion = Route::find(track, tracks); - if(!diversion) - return false; - - diversion->set_name("Diversion"); - diversion->add_track(from); - diversion->set_turnout(from.get_turnout_id(), path); - - if(!is_valid_diversion(*diversion, TrackIter(&from, entry))) - return false; - - // Follow the diversion route until we get back to the original route - list::iterator end = routes.end(); - while(1) - { - for(list::iterator i=route; (end==routes.end() && i!=routes.end()); ++i) - if(i->route->has_track(*track)) - end = i; - - if(end!=routes.end()) - break; - else if(!diversion->has_track(*track)) - throw LogicError("Pathfinder returned a bad route"); - - track = track.next(diversion->get_path(*track)); - } - - if(route==end) - // We are rejoining the same route we diverted from, duplicate it - routes.insert(end, *route); - else - { - ++route; - routes.erase(route, end); - } - routes.insert(end, RouteRef(diversion.release(), from.get_turnout_id())); - - return true; -} - -const Route *Train::get_route() const -{ - if(routes.empty()) - return 0; - return routes.front().route; -} - -void Train::place(Block &block, unsigned entry) -{ - if(controller->get_speed()) - throw InvalidState("Must be stopped before placing"); - - release_blocks(); - - set_active(false); - accurate_position = false; - - if(!block.reserve(this)) - { - set_status("Unplaced"); - return; - } - - blocks.push_back(BlockIter(&block, entry)); - if(reverse) - { - TrackIter track = BlockIter(&block, entry).reverse().track_iter(); - vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_BUFFER); - } - else - { - const Block::Endpoint &bep = block.get_endpoint(entry); - vehicles.back()->place(*bep.track, bep.track_ep, 0, Vehicle::BACK_BUFFER); - } -} - -void Train::unplace() -{ - if(controller->get_speed()) - throw InvalidState("Must be stopped before unplacing"); - - release_blocks(); - - set_active(false); - accurate_position = false; - - for(vector::iterator i=vehicles.begin(); i!=vehicles.end(); ++i) - (*i)->unplace(); - - set_status("Unplaced"); -} - -bool Train::free_block(Block &block) -{ - float margin = 10*layout.get_catalogue().get_scale(); - if(get_reserved_distance_until(&block, false)get_braking_distance()*1.3+margin) - return false; - - unsigned nsens = 0; - for(BlockList::iterator i=cur_blocks_end; i!=blocks.end(); ++i) - { - if(i->block()==&block) - { - if(nsens<1) - return false; - release_blocks(i, blocks.end()); - return true; - } - else if((*i)->get_sensor_id()) - ++nsens; - } - - return false; -} - -void Train::free_noncritical_blocks() -{ - if(blocks.empty()) - return; - - if(controller->get_speed()==0) - { - release_blocks(cur_blocks_end, blocks.end()); - return; - } - - float margin = 10*layout.get_catalogue().get_scale(); - float min_dist = controller->get_braking_distance()*1.3+margin; - - Vehicle &veh = *(reverse ? vehicles.back() : vehicles.front()); - - TrackIter track(veh.get_track(), veh.get_entry()); - BlockList::iterator block = blocks.begin(); - bool in_rsv = false; - while(block!=blocks.end() && !(*block)->has_track(*track)) - { - ++block; - if(block==cur_blocks_end) - in_rsv = true; - } - - float dist = veh.get_offset(); - if(reverse) - track.reverse(); - else - dist = track->get_type().get_path_length(track->get_active_path())-dist; - dist -= veh.get_type().get_length()/2; - - bool nsens = 0; - while(1) - { - track = track.next(); - - if(!(*block)->has_track(*track)) - { - ++block; - if(block==cur_blocks_end) - in_rsv = true; - if(block==blocks.end()) - return; - - if(dist>min_dist && nsens>0) - { - release_blocks(block, blocks.end()); - return; - } - - if(in_rsv && (*block)->get_sensor_id()) - ++nsens; - } - - dist += track->get_type().get_path_length(track->get_active_path()); - } -} - -int Train::get_entry_to_block(Block &block) const -{ - for(BlockList::const_iterator i=blocks.begin(); i!=blocks.end(); ++i) - if(i->block()==&block) - return i->entry(); - return -1; -} - -float Train::get_reserved_distance() const -{ - return get_reserved_distance_until(0, false); -} - -void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt) -{ - if(!active && stop_timeout && t>=stop_timeout) - { - release_blocks(cur_blocks_end, blocks.end()); - stop_timeout = Time::TimeStamp(); - } - - Driver &driver = layout.get_driver(); - - if(timetable) - timetable->tick(t); - controller->tick(dt); - float speed = controller->get_speed(); - unsigned speed_step = find_speed_step(speed); - - if(controller->get_reverse()!=reverse) - { - reverse = controller->get_reverse(); - driver.set_loco_reverse(address, reverse); - - release_blocks(cur_blocks_end, blocks.end()); - reverse_blocks(blocks); - - reserve_more(); - } - if(speed_step!=current_speed_step && !speed_changing && !driver.is_halted() && driver.get_power()) - { - speed_changing = true; - driver.set_loco_speed(address, speed_step); - - pure_speed = false; - - if(speed_step) - set_status(format("Traveling %d kmh", get_travel_speed())); - else - set_status("Waiting"); - } - - if(speed) - { - if(!active) - set_active(true); - - Vehicle &vehicle = *(reverse ? vehicles.back() : vehicles.front()); - Track *track = vehicle.get_track(); - - bool ok = false; - for(BlockList::const_iterator i=blocks.begin(); (!ok && i!=cur_blocks_end); ++i) - ok = (*i)->has_track(*track); - - float d; - if(real_speed.size()>1) - d = get_real_speed(current_speed_step)*(dt/Time::sec); - else - d = speed*(dt/Time::sec); - if(ok) - { - SetFlag setf(advancing); - vehicle.advance(reverse ? -d : d); - } - else if(accurate_position) - { - overshoot_dist += d; - if(overshoot_dist>40*layout.get_catalogue().get_scale()) - { - layout.emergency(name+" has not arrived at sensor"); - accurate_position = false; - } - } - } - else if(end_of_route && cur_blocks_end==blocks.end()) - { - set_active(false); - signal_arrived.emit(); - set_route(0); - } - - if(!blocks.empty() && !blocks.front()->get_sensor_id()) - { - float dist = get_reserved_distance_until(&*blocks.front(), true); - - if(dist>10*layout.get_catalogue().get_scale()) - { - blocks.front()->reserve(0); - blocks.pop_front(); - } - } -} - -void Train::save(list &st) const -{ - st.push_back((DataFile::Statement("name"), name)); - - st.push_back((DataFile::Statement("priority"), priority)); - - for(vector::const_iterator i=vehicles.begin(); i!=vehicles.end(); ++i) - if(i!=vehicles.begin()) - st.push_back((DataFile::Statement("vehicle"), (*i)->get_type().get_article_number())); - - for(unsigned i=0; iget_id())); - - for(BlockList::const_iterator i=blks.begin(); i!=blks.end(); ++i) - st.push_back((DataFile::Statement("block"), (*i)->get_id())); - } - - if(!routes.empty()) - { - list::const_iterator i = routes.begin(); - for(; (i!=routes.end() && i->route->is_temporary()); ++i) ; - if(i!=routes.end()) - st.push_back((DataFile::Statement("route"), i->route->get_name())); - } - - if(timetable) - { - DataFile::Statement ss("timetable"); - timetable->save(ss.sub); - st.push_back(ss); - } -} - -void Train::control_changed(const Controller::Control &ctrl) -{ - signal_control_changed.emit(ctrl.name, ctrl.value); -} - -void Train::loco_speed_event(unsigned addr, unsigned speed, bool) -{ - if(addr==address) - { - current_speed_step = speed; - speed_changing = false; - pure_speed = false; - } -} - -void Train::loco_func_event(unsigned addr, unsigned func, bool state) -{ - if(addr==address || (addr==address+1 && loco_type.get_max_function()>4)) - { - if(addr==address+1) - func += 4; - if(state) - functions |= 1<get_sensor_id()) - { - if((*end)->get_sensor_id()!=addr) - { - if(result==0) - result = 2; - else if(result==1) - break; - } - else if(result==0) - result = 1; - else if(result==2) - result = 3; - } - - if(result==1) - { - // Compute speed and update related state - float travel_time_secs = (Time::now()-last_entry_time)/Time::sec; - - if(pure_speed) - { - if(current_speed_step>0) - { - RealSpeed &rs = real_speed[current_speed_step]; - rs.add(travel_dist/travel_time_secs, travel_time_secs); - } - set_status(format("Traveling %d kmh", get_travel_speed())); - } - - travel_dist = 0; - for(BlockList::iterator j=cur_blocks_end; j!=end; ++j) - { - travel_dist += (*j)->get_path_length(j->entry()); - - if((*j)->get_sensor_id()==addr && !advancing) - { - TrackIter track = j->track_iter(); - if(reverse) - { - track = track.flip(); - vehicles.back()->place(*track, track.entry(), 0, Vehicle::BACK_AXLE); - } - else - vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_AXLE); - } - } - last_entry_time = Time::now(); - pure_speed = true; - accurate_position = true; - overshoot_dist = 0; - - // Check if we've reached the next route - if(routes.size()>1) - { - const Route &route = *(++routes.begin())->route; - for(BlockList::iterator j=cur_blocks_end; j!=end; ++j) - if(route.has_track(*j->track_iter())) - { - routes.pop_front(); - // XXX Exceptions? - signal_route_changed.emit(routes.front().route); - break; - } - } - - // Move blocks up to the next sensor to our current blocks - cur_blocks_end = end; - - // Try to get more blocks if we're moving - if(active) - reserve_more(); - } - else if(result==3) - layout.emergency("Sensor for "+name+" triggered out of order"); - } - else - { - const Vehicle &veh = *(reverse ? vehicles.front() : vehicles.back()); - - // Find the first sensor in our current blocks that's still active - BlockList::iterator end = blocks.begin(); - for(BlockList::iterator i=blocks.begin(); i!=cur_blocks_end; ++i) - { - if((*i)->has_track(*veh.get_track())) - break; - if((*i)->get_sensor_id()) - { - if(layout.get_driver().get_sensor((*i)->get_sensor_id())) - break; - else - { - end = i; - ++end; - } - } - } - - if(end!=blocks.begin() && end!=cur_blocks_end) - // Free blocks up to the last inactive sensor - release_blocks(blocks.begin(), end); - } -} - -void Train::turnout_path_changed(Track &track) -{ - for(list::iterator i=blocks.begin(); i!=blocks.end(); ++i) - if((*i)->get_turnout_id()==track.get_turnout_id() && !reserving) - check_turnout_paths(false); -} - -void Train::halt_event(bool h) -{ - if(h) - accurate_position = false; -} - -void Train::block_reserved(const Block &block, const Train *train) -{ - if(&block==pending_block && !train && !reserving) - reserve_more(); -} - -void Train::reserve_more() -{ - if(!active || blocks.empty() || end_of_route) - return; - - BlockIter start = blocks.back(); - - pending_block = 0; - - // See how many sensor blocks and how much track we already have - unsigned nsens = 0; - float dist = 0; - for(BlockList::const_iterator i=cur_blocks_end; i!=blocks.end(); ++i) - { - if((*i)->get_sensor_id()) - ++nsens; - if(nsens>0) - dist += (*i)->get_path_length(i->entry()); - } - - list::iterator cur_route = routes.begin(); - advance_route(cur_route, *start.track_iter()); - - float approach_margin = 50*layout.get_catalogue().get_scale(); - float min_dist = controller->get_braking_distance()*1.3+approach_margin*2; - - BlockIter block = start; - list::iterator good_end = blocks.end(); - Track *divert_track = 0; - bool try_divert = false; - Train *blocking_train = 0; - BlockList contested_blocks; - - SetFlag setf(reserving); - - while(1) - { - BlockIter last = block; - block = block.next(cur_route!=routes.end() ? cur_route->route : 0); - if(!block || block->get_endpoints().size()<2) - { - if(!blocking_train) - good_end = blocks.end(); - break; - } - - TrackIter track = block.track_iter(); - - if(cur_route!=routes.end()) - { - if(!advance_route(cur_route, *track)) - { - // Keep the blocks if we arrived at the end of the route - if(!blocking_train) - { - good_end = blocks.end(); - end_of_route = true; - } - break; - } - } - - if(block->get_turnout_id() && !last->get_turnout_id()) - { - /* We can keep the blocks if we arrive at a turnout from a non-turnout - block. Having a turnout block as our last reserved block is not good - as it would limit our diversion possibilities for little benefit. */ - good_end = blocks.end(); - if(nsens>=3 && dist>=min_dist) - break; - } - - if(blocking_train) - { - if(block->get_train()!=blocking_train) - { - if(blocking_train->free_block(*contested_blocks.back())) - { - // Roll back and start actually reserving the blocks - block = blocks.back(); - cur_route = routes.begin(); - advance_route(cur_route, *block.track_iter().track()); - if(blocking_train->get_priority()==priority) - blocking_train->yield_to(*this); - blocking_train = 0; - continue; - } - else - { - yield_to(*blocking_train); - pending_block = contested_blocks.front().block(); - try_divert = divert_track; - break; - } - } - else - { - contested_blocks.push_back(block); - continue; - } - } - - bool reserved = block->reserve(this); - if(!reserved) - { - /* We've found another train. If it wants to exit the block from the - same endpoint we're trying to enter from or the other way around, - treat it as coming towards us. Otherwise treat it as going in the - same direction. */ - Train *other_train = block->get_train(); - int other_entry = other_train->get_entry_to_block(*block); - if(other_entry<0) - throw LogicError("Block reservation inconsistency"); - - unsigned exit = block.reverse().entry(); - unsigned other_exit = BlockIter(block.block(), other_entry).reverse().entry(); - bool entry_conflict = (block.entry()==other_exit); - bool exit_conflict = (exit==static_cast(other_entry)); - if(!entry_conflict && !last->get_turnout_id()) - /* The other train is not coming to the blocks we're holding, so we - can keep them. */ - good_end = blocks.end(); - - int other_prio = other_train->get_priority(); - - if(!entry_conflict && !exit_conflict && other_priofree_block(*block)) - reserved = block->reserve(this); - } - else if(other_train!=yielding_to && (other_prioget_turnout_id()) - { - const TrackType::Endpoint &track_ep = track.endpoint(); - bool multiple_paths = (track_ep.paths&(track_ep.paths-1)); - - if(multiple_paths && cur_route!=routes.end() && cur_route->diversion!=block->get_turnout_id()) - /* There's multiple paths to be taken and we are on a route - take - note of the diversion possibility */ - divert_track = &*track; - } - - if(!contested_blocks.empty() && contested_blocks.front()==block) - contested_blocks.pop_front(); - - blocks.push_back(block); - - if(cur_blocks_end==blocks.end()) - --cur_blocks_end; - if(clear_blocks_end==blocks.end()) - --clear_blocks_end; - if(good_end==blocks.end()) - --good_end; - - if(block->get_sensor_id()) - ++nsens; - if(nsens>0) - dist += block->get_path_length(block.entry()); - } - - // Unreserve blocks that were not good - release_blocks(good_end, blocks.end()); - - if(blocks.back()!=start) - // We got some new blocks, so no longer need to yield - yielding_to = 0; - - check_turnout_paths(true); - - // Make any sensorless blocks at the beginning immediately current - while(cur_blocks_end!=clear_blocks_end && !(*cur_blocks_end)->get_sensor_id()) - ++cur_blocks_end; - - if(try_divert && divert(*divert_track)) - reserve_more(); -} - -void Train::check_turnout_paths(bool set) -{ - if(clear_blocks_end==blocks.end()) - return; - - for(list::iterator i=clear_blocks_end; i!=blocks.end(); ++i) - { - if((*i)->get_turnout_id()) - { - TrackIter track = i->track_iter(); - const TrackType::Endpoint &track_ep = track.endpoint(); - - unsigned path = 0; - list::iterator j = i; - if(++j!=blocks.end()) - { - TrackIter rev = j->track_iter().flip(); - unsigned mask = rev.endpoint().paths&track_ep.paths; - for(path=0; mask>1; mask>>=1, ++path) ; - } - else - return; - - if(path!=track->get_active_path()) - { - if(set) - track->set_active_path(path); - - /* Check again, in case the driver was able to service the request - instantly */ - if(!set || path!=track->get_active_path()) - continue; - } - } - - if(i==clear_blocks_end) - ++clear_blocks_end; - } -} - -float Train::get_reserved_distance_until(const Block *until_block, bool back) const -{ - if(blocks.empty()) - return 0; - - Vehicle &veh = *(reverse!=back ? vehicles.back() : vehicles.front()); - const VehicleType &vtype = veh.get_type(); - - TrackIter track(veh.get_track(), veh.get_entry()); - if(!track) // XXX Probably unnecessary - return 0; - - BlockList::const_iterator block = blocks.begin(); - while(block!=clear_blocks_end && !(*block)->has_track(*track)) - ++block; - if(block==clear_blocks_end || &**block==until_block) - return 0; - - float result = veh.get_offset(); - if(reverse!=back) - track = track.reverse(); - else - result = track->get_type().get_path_length(track->get_active_path())-result; - result -= vtype.get_length()/2; - - while(1) - { - track = track.next(); - if(!track) - break; - - if(!(*block)->has_track(*track)) - { - if(back) - { - if(block==blocks.begin()) - break; - --block; - } - else - { - ++block; - if(block==clear_blocks_end) - break; - } - - if(&**block==until_block) - break; - } - - result += track->get_type().get_path_length(track->get_active_path()); - } - - return result; -} - -float Train::get_real_speed(unsigned i) const -{ - if(i==0) - return 0; - if(real_speed[i].weight) - return real_speed[i].speed; - - unsigned low; - unsigned high; - for(low=i; low>0; --low) - if(real_speed[low].weight) - break; - for(high=i; high+1(low*real/real_speed[low].speed), real_speed.size()-1), last+limit); - } - - float f = (real-real_speed[low].speed)/(real_speed[high].speed-real_speed[low].speed); - return static_cast(low*(1-f)+high*f+0.5); -} - -float Train::get_travel_speed() const -{ - float speed = get_real_speed(current_speed_step); - float scale = layout.get_catalogue().get_scale(); - return static_cast(round(speed/scale*3.6/5))*5; -} - -void Train::set_status(const string &s) -{ - status = s; - signal_status_changed.emit(s); -} - -void Train::release_blocks() -{ - release_blocks(blocks.begin(), blocks.end()); -} - -void Train::release_blocks(BlockList::iterator begin, BlockList::iterator end) -{ - while(begin!=end) - { - if(begin==cur_blocks_end) - cur_blocks_end = end; - if(begin==clear_blocks_end) - clear_blocks_end = end; - - Block &block = **begin; - blocks.erase(begin++); - block.reserve(0); - - if(begin==blocks.end()) - end_of_route = false; - } -} - -void Train::reverse_blocks(BlockList &blks) const -{ - blks.reverse(); - for(BlockList::iterator i=blks.begin(); i!=blks.end(); ++i) - *i = i->reverse(); -} - -bool Train::advance_route(list::iterator &iter, Track &track) -{ - while(iter!=routes.end() && !iter->route->has_track(track)) - ++iter; - if(iter==routes.end()) - return false; - - list::iterator next = iter; - ++next; - if(next!=routes.end() && next->diversion && next->route->has_track(track)) - iter = next; - - return true; -} - -Route *Train::create_lead_route(Route *lead, const Route *target) -{ - if(!lead) - { - lead = new Route(layout); - lead->set_name("Lead"); - lead->set_temporary(true); - } - - set tracks; - for(BlockList::iterator i=blocks.begin(); i!=blocks.end(); ++i) - { - const set &btracks = (*i)->get_tracks(); - for(set::const_iterator j=btracks.begin(); j!=btracks.end(); ++j) - if(!target || !target->has_track(**j)) - tracks.insert(*j); - } - - lead->add_tracks(tracks); - - return lead; -} - -bool Train::is_valid_diversion(const Route &diversion, const TrackIter &from) -{ - float diversion_len = 0; - TrackLoopIter track1 = from; - while(diversion.has_track(*track1)) - { - unsigned path = diversion.get_path(*track1); - diversion_len += track1->get_type().get_path_length(path); - - track1 = track1.next(path); - - if(track1.looped()) - return false; - } - - list::iterator route = routes.begin(); - if(!advance_route(route, *from)) - return false; - - float route_len = 0; - TrackLoopIter track2 = from; - while(1) - { - unsigned path = route->route->get_path(*track2); - route_len += track2->get_type().get_path_length(path); - - bool ok = (track2!=from && diversion.has_track(*track2)); - - track2 = track2.next(path); - - if(ok) - break; - - if(track2.looped()) - return false; - - if(!advance_route(route, *track2)) - return false; - } - - // Must end up at the same place through both routes - if(track2!=track1) - return false; - - return diversion_len(t), - prev_block(0), - blocks_valid(true) -{ - add("block", &Loader::block); - add("block_hint", &Loader::block_hint); - add("name", &Loader::name); - add("priority", &Train::priority); - add("real_speed", &Loader::real_speed); - add("route", &Loader::route); - add("timetable", &Loader::timetable); - add("vehicle", &Loader::vehicle); -} - -void Train::Loader::finish() -{ - if(!obj.blocks.empty()) - { - TrackIter track = obj.blocks.front().track_iter(); - float offset = 2*obj.layout.get_catalogue().get_scale(); - obj.vehicles.back()->place(*track, track.entry(), offset, Vehicle::BACK_BUFFER); - - obj.set_status("Stopped"); - } -} - -void Train::Loader::block(unsigned id) -{ - if(!blocks_valid) - return; - - Block *blk; - try - { - blk = &obj.layout.get_block(id); - } - catch(const KeyError &) - { - blocks_valid = false; - return; - } - - int entry = -1; - if(prev_block) - entry = blk->get_endpoint_by_link(*prev_block); - if(entry<0) - entry = 0; - - blk->reserve(&obj); - obj.blocks.push_back(BlockIter(blk, entry)); - - if(blk->get_sensor_id()) - obj.layout.get_driver().set_sensor(blk->get_sensor_id(), true); - - prev_block = blk; -} - -void Train::Loader::block_hint(unsigned id) -{ - try - { - prev_block = &obj.layout.get_block(id); - } - catch(const KeyError &) - { - blocks_valid = false; - } -} - -void Train::Loader::name(const string &n) -{ - obj.set_name(n); -} - -void Train::Loader::real_speed(unsigned i, float speed, float weight) -{ - if(i>=obj.real_speed.size()) - return; - obj.real_speed[i].speed = speed; - obj.real_speed[i].weight = weight; -} - -void Train::Loader::route(const string &n) -{ - obj.set_route(&obj.layout.get_route(n)); -} - -void Train::Loader::timetable() -{ - if(obj.timetable) - throw InvalidState("A timetable has already been loaded"); - - obj.timetable = new Timetable(obj); - load_sub(*obj.timetable); -} - -void Train::Loader::vehicle(ArticleNumber art_nr) -{ - const VehicleType &vtype = obj.layout.get_catalogue().get_vehicle(art_nr); - Vehicle *veh = new Vehicle(obj.layout, vtype); - obj.vehicles.back()->attach_back(*veh); - obj.vehicles.push_back(veh); -} - -} // namespace Marklin diff --git a/source/libmarklin/train.h b/source/libmarklin/train.h deleted file mode 100644 index a13c422..0000000 --- a/source/libmarklin/train.h +++ /dev/null @@ -1,183 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#ifndef LIBMARKLIN_TRAIN_H_ -#define LIBMARKLIN_TRAIN_H_ - -#include -#include -#include -#include "block.h" -#include "blockiter.h" -#include "controller.h" - -namespace Marklin { - -class ArticleNumber; -class Route; -class Timetable; -class Vehicle; -class VehicleType; - -class Train: public sigc::trackable -{ -public: - class Loader: public Msp::DataFile::BasicLoader - { - private: - Block *prev_block; - bool blocks_valid; - - public: - Loader(Train &); - private: - virtual void finish(); - void block(unsigned); - void block_hint(unsigned); - void name(const std::string &); - void real_speed(unsigned, float, float); - void route(const std::string &); - void timetable(); - void vehicle(ArticleNumber); - }; - - sigc::signal signal_name_changed; - sigc::signal signal_control_changed; - sigc::signal signal_function_changed; - sigc::signal signal_route_changed; - sigc::signal signal_arrived; - sigc::signal signal_status_changed; - -private: - struct RouteRef - { - const Route *route; - unsigned diversion; - - RouteRef(const Route *, unsigned = 0); - }; - - struct RealSpeed - { - float speed; - float weight; - - RealSpeed(); - void add(float, float); - }; - - typedef std::list BlockList; - - Layout &layout; - const VehicleType &loco_type; - unsigned address; - std::string protocol; - std::string name; - int priority; - const Train *yielding_to; - std::vector vehicles; - BlockList blocks; - BlockList::iterator cur_blocks_end; - BlockList::iterator clear_blocks_end; - Block *pending_block; - bool reserving; - bool advancing; - Controller *controller; - Timetable *timetable; - bool active; - unsigned current_speed_step; - bool speed_changing; - bool reverse; - Msp::Time::TimeStamp stop_timeout; - unsigned functions; - std::list routes; - bool end_of_route; - std::string status; - - Msp::Time::TimeStamp last_entry_time; - float travel_dist; - bool pure_speed; - std::vector real_speed; - bool accurate_position; - float overshoot_dist; - -public: - Train(Layout &, const VehicleType &, unsigned, const std::string &); - ~Train(); - - Layout &get_layout() const { return layout; } - const VehicleType &get_locomotive_type() const { return loco_type; } - unsigned get_address() const { return address; } - const std::string &get_protocol() const { return protocol; } - void set_name(const std::string &); - const std::string &get_name() const { return name; } - void set_priority(int); - void yield_to(const Train &); - int get_priority() const { return priority; } - Controller &get_controller() const { return *controller; } - - void add_vehicle(const VehicleType &); - void remove_vehicle(unsigned); - unsigned get_n_vehicles() const; - Vehicle &get_vehicle(unsigned); - const Vehicle &get_vehicle(unsigned) const; - - void set_control(const std::string &, float); - void set_active(bool); - void set_function(unsigned, bool); - float get_control(const std::string &) const; - float get_speed() const; - bool is_active() const { return active; } - bool get_function(unsigned) const; - unsigned get_functions() const { return functions; } - - void set_timetable(Timetable *); - Timetable *get_timetable() { return timetable; } - - bool set_route(const Route *); - bool go_to(Track &); - bool divert(Track &); - const Route *get_route() const; - void place(Block &, unsigned); - void unplace(); - bool is_placed() const { return !blocks.empty(); } - bool free_block(Block &); - void free_noncritical_blocks(); - int get_entry_to_block(Block &) const; - float get_reserved_distance() const; - - const std::string &get_status() const { return status; } - - void tick(const Msp::Time::TimeStamp &, const Msp::Time::TimeDelta &); - - void save(std::list &) const; -private: - void control_changed(const Controller::Control &); - void loco_speed_event(unsigned, unsigned, bool); - void loco_func_event(unsigned, unsigned, bool); - void sensor_event(unsigned, bool); - void turnout_path_changed(Track &); - void halt_event(bool); - void block_reserved(const Block &, const Train *); - void reserve_more(); - void check_turnout_paths(bool); - float get_reserved_distance_until(const Block *, bool) const; - float get_real_speed(unsigned) const; - unsigned find_speed_step(float) const; - float get_travel_speed() const; - void set_status(const std::string &); - void release_blocks(); - void release_blocks(BlockList::iterator, BlockList::iterator); - void reverse_blocks(BlockList &) const; - bool advance_route(std::list::iterator &, Track &); - Route *create_lead_route(Route *, const Route *); - bool is_valid_diversion(const Route &, const TrackIter &); -}; - -} // namespace Marklin - -#endif diff --git a/source/libmarklin/vehicle.cpp b/source/libmarklin/vehicle.cpp deleted file mode 100644 index b54b531..0000000 --- a/source/libmarklin/vehicle.cpp +++ /dev/null @@ -1,364 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#include -#include "catalogue.h" -#include "driver.h" -#include "layout.h" -#include "track.h" -#include "trackiter.h" -#include "tracktype.h" -#include "vehicle.h" -#include "vehicletype.h" - -using namespace std; -using namespace Msp; - -namespace Marklin { - -Vehicle::Vehicle(Layout &l, const VehicleType &t): - layout(l), - type(t), - next(0), - prev(0), - direction(0), - bogie_dirs(type.get_bogies().size()), - front_sensor(0), - back_sensor(0) -{ - layout.add_vehicle(*this); -} - -Vehicle::~Vehicle() -{ - if(next) - detach_back(); - if(prev) - detach_front(); - layout.remove_vehicle(*this); -} - -void Vehicle::attach_back(Vehicle &veh) -{ - if(next || veh.prev) - throw InvalidState("Already attached"); - - next = &veh; - veh.prev = this; - - if(track_pos.track) - propagate_backward(); -} - -void Vehicle::attach_front(Vehicle &veh) -{ - if(prev || veh.next) - throw InvalidState("Already attached"); - - prev = &veh; - veh.next = this; - - if(prev->get_track()) - prev->propagate_backward(); -} - -void Vehicle::detach_back() -{ - if(!next) - throw InvalidState("Not attached"); - - next->prev = 0; - next = 0; -} - -void Vehicle::detach_front() -{ - if(!prev) - throw InvalidState("Not attached"); - - prev->next = 0; - prev = 0; -} - -void Vehicle::place(Track &t, unsigned e, float o, PlaceMode m) -{ - track_pos = TrackPosition(&t, e, o); - - if(m==FRONT_AXLE) - track_pos.advance(-type.get_front_axle_offset()); - else if(m==FRONT_BUFFER) - track_pos.advance(-type.get_length()/2); - else if(m==BACK_AXLE) - track_pos.advance(-type.get_back_axle_offset()); - else if(m==BACK_BUFFER) - track_pos.advance(type.get_length()/2); - - update_position(); - propagate_position(); -} - -void Vehicle::unplace() -{ - if(!track_pos.track) - return; - - track_pos = TrackPosition(); - - if(prev) - prev->unplace(); - if(next) - next->unplace(); -} - -void Vehicle::advance(float d) -{ - track_pos.advance(d); - update_position(); - propagate_position(); -} - -float Vehicle::get_bogie_direction(unsigned i) const -{ - if(i>=bogie_dirs.size()) - throw InvalidParameterValue("Bogie index out of range"); - return bogie_dirs[i]; -} - -void Vehicle::update_position() -{ - TrackPoint tp; - - const vector &axles = type.get_axles(); - const vector &bogies = type.get_bogies(); - if(axles.size()>=2) - { - float wheelbase = axles.front().position-axles.back().position; - tp = get_point(track_pos, wheelbase, -axles.back().position/wheelbase); - } - else if(bogies.size()>=2) - { - TrackPosition front = track_pos; - front.advance(bogies.front().position); - TrackPosition back = track_pos; - back.advance(bogies.back().position); - float bogie_spacing = bogies.front().position-bogies.back().position; - adjust_for_distance(front, back, bogie_spacing); - - const vector &front_axles = bogies.front().axles; - float wheelbase = front_axles.front().position-front_axles.back().position; - TrackPoint front_point = get_point(front, wheelbase, -front_axles.back().position/wheelbase); - - const vector &back_axles = bogies.back().axles; - wheelbase = back_axles.front().position-back_axles.back().position; - TrackPoint back_point = get_point(back, wheelbase, -back_axles.back().position/wheelbase); - - tp = get_point(front_point.pos, back_point.pos, -bogies.back().position/bogie_spacing); - - bogie_dirs.front() = front_point.dir-tp.dir; - bogie_dirs.back() = back_point.dir-tp.dir; - } - else - tp = track_pos.get_point(); - - if(!prev) - check_sensor(type.get_front_axle_offset(), front_sensor); - if(!next) - check_sensor(type.get_back_axle_offset(), back_sensor); - - position = tp.pos; - position.z += layout.get_catalogue().get_rail_elevation(); - direction = tp.dir; -} - -void Vehicle::update_position_from(const Vehicle &veh) -{ - int sign = (&veh==prev ? -1 : 1); - - float tdist = (type.get_length()+veh.type.get_length())/2; - float margin = layout.get_catalogue().get_scale(); - - float dist = distance(veh.position, position); - if(disttdist+margin) - { - track_pos = veh.track_pos; - track_pos.advance(sign*tdist); - update_position(); - - dist = distance(veh.position, position); - } - - track_pos.advance(sign*(tdist-dist)); - update_position(); -} - -void Vehicle::propagate_position() -{ - if(prev) - propagate_forward(); - if(next) - propagate_backward(); -} - -void Vehicle::propagate_forward() -{ - prev->update_position_from(*this); - - if(prev->prev) - prev->propagate_forward(); -} - -void Vehicle::propagate_backward() -{ - next->update_position_from(*this); - - if(next->next) - next->propagate_backward(); -} - -void Vehicle::check_sensor(float offset, unsigned &sensor) -{ - TrackPosition pos = track_pos; - pos.advance(offset); - unsigned s = pos.track->get_sensor_id(); - if(s!=sensor) - { - /* Sensor ID under axle has changed. Deduce movement direction by using - the sensor ID under the midpoint of the vehicle. */ - /* XXX This depends on the simulation running fast enough. Something - more robust would be preferable. */ - unsigned old = sensor; - sensor = s; - unsigned mid = track_pos.track->get_sensor_id(); - - if(s && s!=mid) - /* There's a sensor and it's different from mid. We've just entered - that sensor. */ - layout.get_driver().set_sensor(sensor, true); - if(old && old!=mid) - /* A sensor was under the axle and it was different from mid. We've - just left that sensor. */ - layout.get_driver().set_sensor(old, false); - } -} - -void Vehicle::adjust_for_distance(TrackPosition &front, TrackPosition &back, float tdist, float ratio) const -{ - float margin = 0.01*layout.get_catalogue().get_scale(); - int adjust_dir = 0; - while(1) - { - Point front_point = front.get_point().pos; - Point back_point = back.get_point().pos; - - float dx = front_point.x-back_point.x; - float dy = front_point.y-back_point.y; - float dz = front_point.z-back_point.z; - float dist = sqrt(dx*dx+dy*dy+dz*dz); - - float diff = tdist-dist; - if(diff<-margin && adjust_dir<=0) - { - diff -= margin; - adjust_dir = -1; - } - else if(diff>margin && adjust_dir>=0) - { - diff += margin; - adjust_dir = 1; - } - else - return; - - front.advance(diff*(1-ratio)); - back.advance(-diff*ratio); - } -} - -TrackPoint Vehicle::get_point(const Point &front, const Point &back, float ratio) const -{ - float dx = front.x-back.x; - float dy = front.y-back.y; - float dz = front.z-back.z; - - TrackPoint tp; - tp.pos = Point(back.x+dx*ratio, back.y+dy*ratio, back.z+dz*ratio); - tp.dir = atan2(dy, dx); - - return tp; -} - -TrackPoint Vehicle::get_point(const TrackPosition &pos, float tdist, float ratio) const -{ - TrackPosition front = pos; - front.advance(tdist*(1-ratio)); - - TrackPosition back = pos; - back.advance(-tdist*ratio); - - adjust_for_distance(front, back, tdist, ratio); - return get_point(front.get_point().pos, back.get_point().pos, ratio); -} - - -Vehicle::TrackPosition::TrackPosition(): - track(0), - ep(0), - offs(0) -{ } - -Vehicle::TrackPosition::TrackPosition(Track *t, unsigned e, float o): - track(t), - ep(e), - offs(o) -{ } - -void Vehicle::TrackPosition::advance(float d) -{ - if(!track) - return; - - offs += d; - TrackIter iter(track, ep); - while(iter) - { - float path_len = iter->get_type().get_path_length(iter->get_active_path()); - - if(offs>path_len) - { - offs -= path_len; - iter = iter.next(); - } - else - break; - } - - while(iter && offs<0) - { - iter = iter.flip().reverse(); - - if(iter) - { - float path_len = iter->get_type().get_path_length(iter->get_active_path()); - offs += path_len; - } - } - - track = iter.track(); - ep = iter.entry(); - if(!track) - offs = 0; -} - -TrackPoint Vehicle::TrackPosition::get_point() const -{ - if(track) - return track->get_point(ep, offs); - else - return TrackPoint(); -} - -} // namespace Marklin diff --git a/source/libmarklin/vehicle.h b/source/libmarklin/vehicle.h deleted file mode 100644 index 75ae859..0000000 --- a/source/libmarklin/vehicle.h +++ /dev/null @@ -1,92 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#ifndef LIBMARKLIN_VEHICLE_H_ -#define LIBMARKLIN_VEHICLE_H_ - -#include "geometry.h" - -namespace Marklin { - -class Layout; -class Track; -class VehicleType; - -class Vehicle -{ -public: - enum PlaceMode - { - CENTER, - FRONT_AXLE, - FRONT_BUFFER, - BACK_AXLE, - BACK_BUFFER - }; - -private: - struct TrackPosition - { - Track *track; - unsigned ep; - float offs; - - TrackPosition(); - TrackPosition(Track *, unsigned, float); - void advance(float); - TrackPoint get_point() const; - }; - - Layout &layout; - const VehicleType &type; - Vehicle *next; - Vehicle *prev; - TrackPosition track_pos; - Point position; - float direction; - std::vector bogie_dirs; - unsigned front_sensor; - unsigned back_sensor; - -public: - Vehicle(Layout &, const VehicleType &); - ~Vehicle(); - - const VehicleType &get_type() const { return type; } - - void attach_back(Vehicle &); - void attach_front(Vehicle &); - void detach_back(); - void detach_front(); - Vehicle *get_next() const { return next; } - Vehicle *get_previous() const { return prev; } - - void place(Track &, unsigned, float, PlaceMode = CENTER); - void unplace(); - void advance(float); - Track *get_track() const { return track_pos.track; } - unsigned get_entry() const { return track_pos.ep; } - float get_offset() const { return track_pos.offs; } - const Point &get_position() const { return position; } - float get_direction() const { return direction; } - float get_bogie_direction(unsigned) const; -private: - void update_position(); - void update_position_from(const Vehicle &); - void propagate_position(); - void propagate_forward(); - void propagate_backward(); - void check_sensor(float, unsigned &); - - void adjust_for_distance(TrackPosition &, TrackPosition &, float, float = 0.5) const; - TrackPoint get_point(const Point &, const Point &, float = 0.5) const; - TrackPoint get_point(const TrackPosition &, float, float = 0.5) const; -}; - -} // namespace Marklin - -#endif diff --git a/source/libmarklin/vehicletype.cpp b/source/libmarklin/vehicletype.cpp deleted file mode 100644 index 5c14cba..0000000 --- a/source/libmarklin/vehicletype.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#include "vehicletype.h" - -using namespace std; -using namespace Msp; - -namespace Marklin { - -VehicleType::VehicleType(const ArticleNumber &an): - art_nr(an), - locomotive(false), - length(0), - width(0), - height(0) -{ } - -unsigned VehicleType::get_max_function() const -{ - if(functions.empty()) - return 0; - return (--functions.end())->first; -} - -float VehicleType::get_front_axle_offset() const -{ - float front = length/2; - if(!axles.empty()) - front = axles.front().position; - if(!bogies.empty()) - { - const Bogie &bogie = bogies.front(); - front = max(front, bogie.position+bogie.axles.front().position); - } - return front; -} - -float VehicleType::get_back_axle_offset() const -{ - float back = -length/2; - if(!axles.empty()) - back = axles.back().position; - if(!bogies.empty()) - { - const Bogie &bogie = bogies.back(); - back = min(back, bogie.position+bogie.axles.back().position); - } - return back; -} - - -VehicleType::Axle::Axle(): - position(0), - wheel_dia(0), - powered(false) -{ } - - -VehicleType::Bogie::Bogie(): - position(0), - rotate_object(false) -{ } - - -VehicleType::Loader::Loader(VehicleType &vt): - DataFile::ObjectLoader(vt) -{ - add("axle", &Loader::axle); - add("bogie", &Loader::bogie); - add("function", &Loader::function); - add("height", &Loader::height); - add("length", &Loader::length); - add("locomotive", &VehicleType::locomotive); - add("object", &VehicleType::object); - add("name", &VehicleType::name); - add("width", &Loader::width); -} - -void VehicleType::Loader::axle() -{ - Axle axl; - load_sub(axl); - obj.axles.push_back(axl); -} - -void VehicleType::Loader::bogie() -{ - Bogie bog; - load_sub(bog); - obj.bogies.push_back(bog); -} - -void VehicleType::Loader::function(unsigned i, const string &f) -{ - obj.functions[i] = f; -} - -void VehicleType::Loader::height(float h) -{ - obj.height = h/1000; -} - -void VehicleType::Loader::length(float l) -{ - obj.length = l/1000; -} - -void VehicleType::Loader::width(float w) -{ - obj.width = w/1000; -} - - -VehicleType::Axle::Loader::Loader(Axle &a): - DataFile::ObjectLoader(a) -{ - add("object", &Axle::object); - add("position", &Loader::position); - add("powered", &Axle::powered); - add("wheel_diameter", &Loader::wheel_diameter); -} - -void VehicleType::Axle::Loader::position(float p) -{ - obj.position = p/1000; -} - -void VehicleType::Axle::Loader::wheel_diameter(float d) -{ - obj.wheel_dia = d/1000; -} - - -VehicleType::Bogie::Loader::Loader(Bogie &b): - DataFile::ObjectLoader(b) -{ - add("axle", &Loader::axle); - add("object", &Bogie::object); - add("position", &Loader::position); - add("rotate_object", &Bogie::rotate_object); -} - -void VehicleType::Bogie::Loader::axle() -{ - Axle axl; - load_sub(axl); - obj.axles.push_back(axl); -} - -void VehicleType::Bogie::Loader::position(float p) -{ - obj.position = p/1000; -} - -} // namespace Marklin diff --git a/source/libmarklin/vehicletype.h b/source/libmarklin/vehicletype.h deleted file mode 100644 index 7844825..0000000 --- a/source/libmarklin/vehicletype.h +++ /dev/null @@ -1,102 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#ifndef LIBMARKLIN_VEHICLETYPE_H_ -#define LIBMARKLIN_VEHICLETYPE_H_ - -#include -#include "articlenumber.h" - -namespace Marklin { - -class VehicleType -{ -public: - class Loader: public Msp::DataFile::ObjectLoader - { - public: - Loader(VehicleType &); - private: - void axle(); - void bogie(); - void function(unsigned, const std::string &); - void height(float); - void length(float); - void width(float); - }; - - struct Axle - { - class Loader: public Msp::DataFile::ObjectLoader - { - public: - Loader(Axle &); - private: - void position(float); - void wheel_diameter(float); - }; - - float position; - float wheel_dia; - bool powered; - std::string object; - - Axle(); - }; - - struct Bogie - { - class Loader: public Msp::DataFile::ObjectLoader - { - public: - Loader(Bogie &); - private: - void axle(); - void position(float); - }; - - float position; - std::vector axles; - std::string object; - bool rotate_object; - - Bogie(); - }; - -private: - ArticleNumber art_nr; - std::string name; - bool locomotive; - std::map functions; - float length; - float width; - float height; - std::vector axles; - std::vector bogies; - std::string object; - -public: - VehicleType(const ArticleNumber &); - - const ArticleNumber &get_article_number() const { return art_nr; } - const std::string &get_name() const { return name; } - bool is_locomotive() const { return locomotive; } - unsigned get_max_function() const; - const std::map &get_functions() const { return functions; } - float get_length() const { return length; } - float get_width() const { return width; } - float get_height() const { return height; } - const std::vector &get_axles() const { return axles; } - const std::vector &get_bogies() const { return bogies; } - float get_front_axle_offset() const; - float get_back_axle_offset() const; - const std::string &get_object() const { return object; } -}; - -} // namespace Marklin - -#endif diff --git a/source/libr2c2/aicontrol.cpp b/source/libr2c2/aicontrol.cpp new file mode 100644 index 0000000..c2f16e3 --- /dev/null +++ b/source/libr2c2/aicontrol.cpp @@ -0,0 +1,129 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#include "aicontrol.h" +#include "catalogue.h" +#include "layout.h" +#include "train.h" + +using namespace std; +using namespace Msp; + +namespace R2C2 { + +AIControl::AIControl(Train &t, Controller *n): + train(t), + next_ctrl(n), + target_speed(Control::continuous("speed", 0, 1000)), + blocked(false), + approach(false) +{ + target_speed.set(0); + + train.signal_arrived.connect(sigc::mem_fun(this, &AIControl::arrived)); + next_ctrl->signal_control_changed.connect(sigc::mem_fun(this, &AIControl::control_changed)); +} + +AIControl::~AIControl() +{ + delete next_ctrl; +} + +void AIControl::set_control(const string &n, float v) +{ + if(n=="speed") + { + if(v && !train.is_active()) + train.set_active(true); + + target_speed.set(v); + if(!blocked) + { + float approach_speed = 5*train.get_layout().get_catalogue().get_scale(); + if(approach && target_speed.value>approach_speed) + next_ctrl->set_control("speed", approach_speed); + else + next_ctrl->set_control("speed", target_speed.value); + } + + signal_control_changed.emit(target_speed); + } + else + next_ctrl->set_control(n, v); +} + +const Controller::Control &AIControl::get_control(const string &n) const +{ + if(n=="speed") + return target_speed; + else + return next_ctrl->get_control(n); +} + +float AIControl::get_speed() const +{ + return next_ctrl->get_speed(); +} + +bool AIControl::get_reverse() const +{ + return next_ctrl->get_reverse(); +} + +float AIControl::get_braking_distance() const +{ + return next_ctrl->get_braking_distance(); +} + +void AIControl::tick(const Time::TimeDelta &dt) +{ + float scale = train.get_layout().get_catalogue().get_scale(); + float rsv_dist = train.get_reserved_distance(); + float brake_dist = next_ctrl->get_braking_distance(); + float approach_margin = 50*scale; + float approach_speed = 5*scale; + float margin = 10*scale; + + if(!blocked && rsv_distset_control("speed", 0); + } + else if((!approach && rsv_distbrake_dist+margin*2)) + { + blocked = false; + approach = true; + if(target_speed.value>approach_speed) + next_ctrl->set_control("speed", approach_speed); + else + next_ctrl->set_control("speed", target_speed.value); + } + else if((blocked || approach) && rsv_dist>brake_dist*1.3+approach_margin*2) + { + blocked = false; + approach = false; + next_ctrl->set_control("speed", target_speed.value); + } + + next_ctrl->tick(dt); + + if(!target_speed.value && !next_ctrl->get_speed() && train.is_active()) + train.set_active(false); +} + +void AIControl::control_changed(const Control &ctrl) +{ + if(ctrl.name!="speed") + signal_control_changed.emit(ctrl); +} + +void AIControl::arrived() +{ + set_control("speed", 0); +} + +} // namespace R2C2 diff --git a/source/libr2c2/aicontrol.h b/source/libr2c2/aicontrol.h new file mode 100644 index 0000000..0d84218 --- /dev/null +++ b/source/libr2c2/aicontrol.h @@ -0,0 +1,47 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#ifndef LIBR2C2_AICONTROL_H_ +#define LIBR2C2_AICONTROL_H_ + +#include +#include "controller.h" + +namespace R2C2 { + +class Train; + +class AIControl: public Controller, public sigc::trackable +{ +private: + Train &train; + Controller *next_ctrl; + Control target_speed; + bool blocked; + bool approach; + +public: + AIControl(Train &, Controller *); + virtual ~AIControl(); + + virtual void set_control(const std::string &, float); + virtual const Control &get_control(const std::string &) const; + + virtual float get_speed() const; + virtual bool get_reverse() const; + virtual float get_braking_distance() const; + + virtual void tick(const Msp::Time::TimeDelta &); + +private: + void control_changed(const Control &); + void arrived(); +}; + +} // namespace R2C2 + +#endif diff --git a/source/libr2c2/articlenumber.cpp b/source/libr2c2/articlenumber.cpp new file mode 100644 index 0000000..45e526c --- /dev/null +++ b/source/libr2c2/articlenumber.cpp @@ -0,0 +1,90 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#include +#include "articlenumber.h" + +using namespace std; +using namespace Msp; + +namespace R2C2 { + +ArticleNumber::ArticleNumber(unsigned n) +{ + Part part; + part.number = n; + part.letter = 0; + parts.push_back(part); +} + +ArticleNumber::ArticleNumber(const string &s) +{ + vector sparts = split(s, '-'); + for(vector::iterator i=sparts.begin(); i!=sparts.end(); ++i) + { + if(i->empty()) + throw InvalidParameterValue("Malformed article number"); + + unsigned nondigit = i->size(); + for(unsigned j=0; jsize(); ++j) + if(!isdigit((*i)[j])) + { + nondigit = j; + break; + } + + if(!nondigit || nondigitsize()-1) + throw InvalidParameterValue("Malformed article number"); + + Part part; + part.number = lexical_cast(i->substr(0, nondigit)); + part.letter = nondigitsize() ? (*i)[nondigit] : 0; + parts.push_back(part); + } +} + +string ArticleNumber::str() const +{ + string result; + for(vector::const_iterator i=parts.begin(); i!=parts.end(); ++i) + { + if(!result.empty()) + result += '-'; + + result += lexical_cast(i->number); + if(i->letter) + result += i->letter; + } + + return result; +} + +bool ArticleNumber::operator<(const ArticleNumber &other) const +{ + return parts>(const LexicalConverter &conv, ArticleNumber &art_nr) +{ + art_nr = ArticleNumber(conv.get()); +} + +void operator<<(LexicalConverter &conv, const ArticleNumber &art_nr) +{ + conv.result(art_nr.str()); +} + +} // namespace R2C2 diff --git a/source/libr2c2/articlenumber.h b/source/libr2c2/articlenumber.h new file mode 100644 index 0000000..cf69c42 --- /dev/null +++ b/source/libr2c2/articlenumber.h @@ -0,0 +1,45 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#ifndef LIBR2C2_ARTICLENUMBER_H_ +#define LIBR2C2_ARTICLENUMBER_H_ + +#include +#include +#include + +namespace R2C2 { + +class ArticleNumber +{ +private: + struct Part + { + unsigned number; + char letter; + + bool operator<(const Part &) const; + }; + + std::vector parts; + +public: + ArticleNumber() { } + ArticleNumber(unsigned); + ArticleNumber(const std::string &); + + std::string str() const; + + bool operator<(const ArticleNumber &) const; +}; + +void operator>>(const Msp::LexicalConverter &, ArticleNumber &); +void operator<<(Msp::LexicalConverter &, const ArticleNumber &); + +} // namespace R2C2 + +#endif diff --git a/source/libr2c2/block.cpp b/source/libr2c2/block.cpp new file mode 100644 index 0000000..ca404de --- /dev/null +++ b/source/libr2c2/block.cpp @@ -0,0 +1,222 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#include +#include "block.h" +#include "layout.h" +#include "route.h" +#include "trackiter.h" +#include "tracktype.h" + +using namespace std; +using namespace Msp; + +namespace R2C2 { + +Block::Block(Layout &l, Track &start): + layout(l), + id(0), + sensor_id(start.get_sensor_id()), + turnout_id(start.get_turnout_id()), + train(0) +{ + tracks.insert(&start); + start.set_block(this); + + list queue; + queue.push_back(&start); + + while(!queue.empty()) + { + Track *track = queue.front(); + queue.erase(queue.begin()); + + const vector &links = track->get_links(); + for(unsigned i=0; iget_sensor_id()==sensor_id && links[i]->get_turnout_id()==turnout_id) + { + queue.push_back(links[i]); + tracks.insert(links[i]); + links[i]->set_block(this); + } + else + endpoints.push_back(Endpoint(track, i)); + } + } + + determine_id(); + + for(unsigned i=0; i trks = tracks; + tracks.clear(); + for(set::iterator i=trks.begin(); i!=trks.end(); ++i) + (*i)->set_block(0); + + for(vector::iterator i=endpoints.begin(); i!=endpoints.end(); ++i) + if(Block *blk = i->link) + { + i->link = 0; + blk->break_link(*this); + } + + layout.remove_block(*this); +} + +bool Block::has_track(Track &t) const +{ + return tracks.count(&t); +} + +const Block::Endpoint &Block::get_endpoint(unsigned i) const +{ + if(i>=endpoints.size()) + throw InvalidParameterValue("Endpoint index out of range"); + + return endpoints[i]; +} + +int Block::get_endpoint_by_link(Block &other) const +{ + for(unsigned i=0; i=endpoints.size()) + throw InvalidParameterValue("Endpoint index out of range"); + + TrackIter t_iter(endpoints[entry].track, endpoints[entry].track_ep); + + float result = 0; + while(t_iter && has_track(*t_iter)) + { + unsigned path = (route ? route->get_path(*t_iter) : t_iter->get_active_path()); + result += t_iter->get_type().get_path_length(path); + + t_iter = t_iter.next(path); + } + + return result; +} + +void Block::check_link(Block &other) +{ + for(vector::iterator i=endpoints.begin(); i!=endpoints.end(); ++i) + { + if(i->link) + continue; + + for(vector::iterator j=other.endpoints.begin(); j!=other.endpoints.end(); ++j) + if(j->track==i->track->get_link(i->track_ep) && j->track->get_link(j->track_ep)==i->track && !j->link) + { + i->link = &other; + j->link = this; + + determine_id(); + other.determine_id(); + } + } +} + +void Block::break_link(Block &other) +{ + for(vector::iterator i=endpoints.begin(); i!=endpoints.end(); ++i) + if(i->link==&other) + { + i->link = 0; + other.break_link(*this); + determine_id(); + } +} + +Block *Block::get_link(unsigned epi) const +{ + if(epi>=endpoints.size()) + throw InvalidParameterValue("Endpoint index out of range"); + return endpoints[epi].link; +} + +bool Block::reserve(Train *t) +{ + if(!t || !train) + { + train = t; + layout.signal_block_reserved.emit(*this, train); + return true; + } + else + return false; +} + +void Block::find_paths(TrackIter track, unsigned path) +{ + unsigned mask = track.endpoint().paths; + for(unsigned i=0; mask>>i; ++i) + if(mask&(1<::iterator j=endpoints.begin(); j!=endpoints.end(); ++j) + if(j->track==next.track() && j->track_ep==next.entry()) + j->paths |= path; + } + } +} + +void Block::determine_id() +{ + if(sensor_id) + id = 0x1000|sensor_id; + else if(turnout_id) + id = 0x2000|turnout_id; + else if(endpoints.size()==2) + { + unsigned id1 = endpoints[0].link ? endpoints[0].link->get_id() : 1; + unsigned id2 = endpoints[1].link ? endpoints[1].link->get_id() : 1; + if(id2get_id() : 1; + id = 0x10000 | id1; + } +} + + +Block::Endpoint::Endpoint(Track *t, unsigned e): + track(t), + track_ep(e), + link(0), + paths(0) +{ } + +} // namespace R2C2 diff --git a/source/libr2c2/block.h b/source/libr2c2/block.h new file mode 100644 index 0000000..e13e58b --- /dev/null +++ b/source/libr2c2/block.h @@ -0,0 +1,70 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#ifndef LIBR2C2_BLOCK_H_ +#define LIBR2C2_BLOCK_H_ + +#include +#include +#include "track.h" + +namespace R2C2 { + +class Layout; +class Route; +class TrackIter; +class Train; + +class Block +{ +public: + struct Endpoint + { + Track *track; + unsigned track_ep; + Block *link; + unsigned paths; + + Endpoint(Track *, unsigned); + }; + +private: + Layout &layout; + unsigned id; + unsigned sensor_id; + unsigned turnout_id; + std::set tracks; + std::vector endpoints; + Train *train; + +public: + Block(Layout &, Track &); + ~Block(); + + unsigned get_id() const { return id; } + unsigned get_sensor_id() const { return sensor_id; } + unsigned get_turnout_id() const { return turnout_id; } + const std::set &get_tracks() const { return tracks; } + bool has_track(Track &) const; + const std::vector &get_endpoints() const { return endpoints; } + const Endpoint &get_endpoint(unsigned) const; + int get_endpoint_by_link(Block &) const; + float get_path_length(unsigned, const Route * = 0) const; + void check_link(Block &); + void break_link(Block &); + Block *get_link(unsigned) const; + bool reserve(Train *); + Train *get_train() const { return train; } + void print_debug(); +private: + void find_paths(TrackIter, unsigned); + void determine_id(); +}; + +} // namespace R2C2 + +#endif diff --git a/source/libr2c2/blockiter.cpp b/source/libr2c2/blockiter.cpp new file mode 100644 index 0000000..db052ac --- /dev/null +++ b/source/libr2c2/blockiter.cpp @@ -0,0 +1,125 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#include +#include "block.h" +#include "blockiter.h" +#include "route.h" +#include "trackiter.h" + +using namespace std; +using namespace Msp; + +namespace R2C2 { + +BlockIter::BlockIter(): + _block(0), + _entry(0) +{ } + +BlockIter::BlockIter(Block *b, unsigned e): + _block(b), + _entry(b ? e : 0) +{ + if(_block && _entry>_block->get_endpoints().size()) + throw InvalidParameterValue("Endpoint index not valid for block"); +} + +TrackIter BlockIter::track_iter() const +{ + if(!_block) + return TrackIter(); + + const Block::Endpoint &ep = _block->get_endpoint(_entry); + return TrackIter(ep.track, ep.track_ep); +} + +const Block::Endpoint &BlockIter::endpoint() const +{ + if(!_block) + throw InvalidState("BlockIter is null"); + + return _block->get_endpoint(_entry); +} + +int BlockIter::get_exit(const Route *route) const +{ + const vector &eps = _block->get_endpoints(); + TrackIter t_iter = track_iter(); + + while(t_iter) + { + if(!_block->has_track(*t_iter)) + throw LogicError("Block traversal strayed out of the block"); + + unsigned path = (route ? route->get_path(*t_iter) : t_iter->get_active_path()); + TrackIter t_exit = t_iter.reverse(path); + + for(unsigned i=0; iget_link(exit); + result._entry = (result._block ? result._block->get_endpoint_by_link(*_block) : 0); + + return result; +} + +BlockIter BlockIter::reverse(const Route *route) const +{ + if(!_block) + return BlockIter(); + + int exit = get_exit(route); + if(exit<0) + return BlockIter(); + + return BlockIter(_block, exit); +} + +BlockIter BlockIter::flip() const +{ + if(!_block) + return BlockIter(); + + BlockIter result; + result._block = _block->get_link(_entry); + result._entry = (result._block ? result._block->get_endpoint_by_link(*_block) : 0); + + return result; +} + +Block &BlockIter::operator*() const +{ + if(!_block) + throw InvalidState("BlockIter is null"); + + return *_block; +} + +bool BlockIter::operator==(const BlockIter &other) const +{ + return _block==other._block && _entry==other._entry; +} + +} // namespace R2C2 diff --git a/source/libr2c2/blockiter.h b/source/libr2c2/blockiter.h new file mode 100644 index 0000000..5c235a5 --- /dev/null +++ b/source/libr2c2/blockiter.h @@ -0,0 +1,51 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#ifndef LIBR2C2_BLOCKITER_H_ +#define LIBR2C2_BLOCKITER_H_ + +namespace R2C2 { + +class Block; +class Route; +class TrackIter; + +/** +An iterator for traversing blocks. +*/ +class BlockIter +{ +private: + Block *_block; + unsigned _entry; + +public: + BlockIter(); + BlockIter(Block *, unsigned); + + Block *block() const { return _block; } + unsigned entry() const { return _entry; } + TrackIter track_iter() const; + const Block::Endpoint &endpoint() const; + +private: + int get_exit(const Route *) const; +public: + BlockIter next(const Route * = 0) const; + BlockIter reverse(const Route * = 0) const; + BlockIter flip() const; + + Block &operator*() const; + Block *operator->() const { return _block; } + bool operator==(const BlockIter &) const; + bool operator!=(const BlockIter &other) const { return !(*this==other); } + operator bool() const { return _block!=0; } +}; + +} // namespace R2C2 + +#endif diff --git a/source/libr2c2/catalogue.cpp b/source/libr2c2/catalogue.cpp new file mode 100644 index 0000000..838b15b --- /dev/null +++ b/source/libr2c2/catalogue.cpp @@ -0,0 +1,147 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#include +#include +#include "catalogue.h" +#include "tracktype.h" +#include "vehicletype.h" + +using namespace std; +using namespace Msp; + +namespace R2C2 { + +Catalogue::Catalogue(): + scale(1), + gauge(1.524), + layout(*this) +{ } + +Catalogue::~Catalogue() +{ + for(TrackMap::iterator i=tracks.begin(); i!=tracks.end(); ++i) + delete i->second; + for(VehicleMap::iterator i=vehicles.begin(); i!=vehicles.end(); ++i) + delete i->second; +} + +float Catalogue::get_rail_elevation() const +{ + return ballast_profile.get_height()+rail_profile.get_height(); +} + +void Catalogue::add_track(TrackType &track) +{ + if(tracks.count(track.get_article_number())) + throw Exception("Duplicate track type"); + + tracks[track.get_article_number()] = &track; + signal_track_added.emit(track); +} + +const TrackType &Catalogue::get_track(const ArticleNumber &art_nr) const +{ + TrackMap::const_iterator i=tracks.find(art_nr); + if(i==tracks.end()) + throw KeyError("Unknown track type"); + + return *i->second; +} + +void Catalogue::add_vehicle(VehicleType &veh) +{ + if(vehicles.count(veh.get_article_number())) + throw Exception("Duplicate vehicle type"); + + vehicles[veh.get_article_number()] = &veh; + signal_vehicle_added.emit(veh); +} + +const VehicleType &Catalogue::get_vehicle(const ArticleNumber &art_nr) const +{ + VehicleMap::const_iterator i = vehicles.find(art_nr); + if(i==vehicles.end()) + throw KeyError("Unknown vehicle type"); + + return *i->second; +} + + +Catalogue::Loader::Loader(Catalogue &c): + DataFile::BasicLoader(c) +{ + add("ballast_profile", &Loader::ballast_profile); + add("gauge", &Loader::gauge); + add("layout", &Loader::layout); + add("rail_profile", &Loader::rail_profile); + add("scale", &Loader::scale); + add("track", static_cast(&Loader::track)); + add("track", static_cast(&Loader::track)); + add("vehicle", static_cast(&Loader::vehicle)); + add("vehicle", static_cast(&Loader::vehicle)); +} + +void Catalogue::Loader::ballast_profile() +{ + load_sub(obj.ballast_profile); +} + +void Catalogue::Loader::gauge(float g) +{ + obj.gauge = g/1000; + obj.path_profile = Profile(); + obj.path_profile.append_point(Point(0.1*obj.gauge, 0)); + obj.path_profile.append_point(Point(-0.1*obj.gauge, 0)); +} + +void Catalogue::Loader::layout() +{ + load_sub(obj.layout); +} + +void Catalogue::Loader::rail_profile() +{ + load_sub(obj.rail_profile); +} + +void Catalogue::Loader::scale(float n, float d) +{ + obj.scale = n/d; +} + +void Catalogue::Loader::track(unsigned art_nr) +{ + track(ArticleNumber(art_nr)); +} + +void Catalogue::Loader::track(ArticleNumber art_nr) +{ + if(obj.tracks.count(art_nr)) + throw KeyError("Duplicate track type", art_nr.str()); + + RefPtr trk = new TrackType(art_nr); + load_sub(*trk); + obj.add_track(*trk.release()); +} + +void Catalogue::Loader::vehicle(unsigned art_nr) +{ + vehicle(ArticleNumber(art_nr)); +} + +void Catalogue::Loader::vehicle(ArticleNumber art_nr) +{ + if(obj.vehicles.count(art_nr)) + throw KeyError("Duplicate vehicle type", art_nr.str()); + + RefPtr veh = new VehicleType(art_nr); + load_sub(*veh); + obj.add_vehicle(*veh.release()); +} + +} // namespace R2C2 diff --git a/source/libr2c2/catalogue.h b/source/libr2c2/catalogue.h new file mode 100644 index 0000000..c8b006a --- /dev/null +++ b/source/libr2c2/catalogue.h @@ -0,0 +1,81 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#ifndef LIBR2C2_CATALOGUE_H_ +#define LIBR2C2_CATALOGUE_H_ + +#include +#include +#include "articlenumber.h" +#include "layout.h" +#include "profile.h" + +namespace R2C2 { + +class TrackType; +class VehicleType; + +class Catalogue +{ +public: + class Loader: public Msp::DataFile::BasicLoader + { + public: + Loader(Catalogue &); + private: + void ballast_profile(); + void gauge(float); + void layout(); + void rail_profile(); + void scale(float, float); + void track(unsigned); + void track(ArticleNumber); + void vehicle(unsigned); + void vehicle(ArticleNumber); + }; + + typedef std::map TrackMap; + typedef std::map VehicleMap; + + sigc::signal signal_track_added; + sigc::signal signal_vehicle_added; + +private: + float scale; + float gauge; + Profile rail_profile; + Profile ballast_profile; + Profile path_profile; + TrackMap tracks; + VehicleMap vehicles; + Layout layout; + +public: + Catalogue(); + ~Catalogue(); + + float get_scale() const { return scale; } + float get_gauge() const { return gauge; } + float get_rail_elevation() const; + const Profile &get_rail_profile() const { return rail_profile; } + const Profile &get_ballast_profile() const { return ballast_profile; } + const Profile &get_path_profile() const { return path_profile; } + + void add_track(TrackType &); + const TrackType &get_track(const ArticleNumber &) const; + const TrackMap &get_tracks() const { return tracks; } + + void add_vehicle(VehicleType &); + const VehicleType &get_vehicle(const ArticleNumber &) const; + const VehicleMap &get_vehicles() const { return vehicles; } + + Layout &get_layout() { return layout; } +}; + +} // namespace R2C2 + +#endif diff --git a/source/libr2c2/controller.cpp b/source/libr2c2/controller.cpp new file mode 100644 index 0000000..480abc2 --- /dev/null +++ b/source/libr2c2/controller.cpp @@ -0,0 +1,76 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#include +#include +#include "controller.h" + +using namespace std; +using namespace Msp; + +namespace R2C2 { + +void Controller::Control::set(float v) +{ + if(vmax_value) + v = max_value; + else if(type==BINARY) + value = v ? 1 : 0; + else if(type==DISCRETE) + value = min_value+floor((v-min_value)/step)*step; + else if(type==CONTINUOUS) + value = v; +} + +Controller::Control Controller::Control::binary(const string &n) +{ + Controller::Control tc; + tc.name = n; + tc.type = BINARY; + tc.min_value = 0; + tc.max_value = 1; + tc.step = 1; + tc.value = 0; + + return tc; +} + +Controller::Control Controller::Control::discrete(const string &n, float m, float x, float s) +{ + if(x +#include +#include + +namespace R2C2 { + +/** +Interface class for train controllers. Takes input through a uniform named +control interface. Provides information about train movement on output. +*/ +class Controller +{ +public: + struct Control + { + enum Type + { + BINARY, + DISCRETE, + CONTINUOUS + }; + + std::string name; + Type type; + float min_value; + float max_value; + float step; + float value; + + private: + Control() { } + + public: + void set(float); + + static Control binary(const std::string &); + static Control discrete(const std::string &, float, float, float); + static Control continuous(const std::string &, float, float); + }; + + sigc::signal signal_control_changed; + +protected: + Controller() { } +public: + virtual ~Controller() { } + + virtual void set_control(const std::string &, float) = 0; + virtual const Control &get_control(const std::string &) const = 0; + + /** Returns the current speed. Always non-negative. */ + virtual float get_speed() const = 0; + + /** Returns true if traveling in reverse. */ + virtual bool get_reverse() const = 0; + + /** Determines the distance required to come to a full stop. */ + virtual float get_braking_distance() const = 0; + + virtual void tick(const Msp::Time::TimeDelta &) = 0; +}; + +} // namespace R2C2 + +#endif diff --git a/source/libr2c2/driver.cpp b/source/libr2c2/driver.cpp new file mode 100644 index 0000000..ea903af --- /dev/null +++ b/source/libr2c2/driver.cpp @@ -0,0 +1,34 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#include +#include "driver.h" +#include "dummy.h" +#include "intellibox.h" + +using namespace std; + +namespace R2C2 { + +Driver *Driver::create(const string &str) +{ + string::size_type colon = str.find(':'); + string type = str.substr(0, colon); + string params; + + if(colon!=string::npos) + params = str.substr(colon+1); + + if(type=="ib" || type=="intellibox") + return new Intellibox(params); + else if(type=="dummy") + return new Dummy; + + throw Msp::InvalidParameterValue("Unknown driver"); +} + +} // namespace R2C2 diff --git a/source/libr2c2/driver.h b/source/libr2c2/driver.h new file mode 100644 index 0000000..d9d1127 --- /dev/null +++ b/source/libr2c2/driver.h @@ -0,0 +1,59 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#ifndef LIBR2C2_DRIVER_H_ +#define LIBR2C2_DRIVER_H_ + +#include +#include + +namespace R2C2 { + +class Driver +{ +public: + sigc::signal signal_power; + sigc::signal signal_halt; + sigc::signal signal_loco_speed; + sigc::signal signal_loco_function; + sigc::signal signal_turnout; + sigc::signal signal_sensor; + +protected: + Driver() { } +public: + virtual ~Driver() { } + + virtual void set_power(bool) = 0; + virtual bool get_power() const = 0; + virtual void halt(bool) = 0; + virtual bool is_halted() const = 0; + + virtual const char *enumerate_protocols(unsigned) const = 0; + virtual unsigned get_protocol_speed_steps(const std::string &) const = 0; + virtual void add_loco(unsigned, const std::string &) = 0; + virtual void set_loco_speed(unsigned, unsigned) = 0; + virtual void set_loco_reverse(unsigned, bool) = 0; + virtual void set_loco_function(unsigned, unsigned, bool) = 0; + + virtual void add_turnout(unsigned) = 0; + virtual void set_turnout(unsigned, bool) = 0; + virtual bool get_turnout(unsigned) const = 0; + + virtual void add_sensor(unsigned) = 0; + virtual void set_sensor(unsigned, bool) = 0; + virtual bool get_sensor(unsigned) const = 0; + + virtual void tick() = 0; + virtual void flush() = 0; + + static Driver *create(const std::string &); +}; + +} // namespace R2C2 + +#endif diff --git a/source/libr2c2/dummy.cpp b/source/libr2c2/dummy.cpp new file mode 100644 index 0000000..814dce4 --- /dev/null +++ b/source/libr2c2/dummy.cpp @@ -0,0 +1,94 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#include "dummy.h" + +using namespace std; + +namespace R2C2 { + +Dummy::Dummy(): + power(true) +{ } + +void Dummy::set_power(bool p) +{ + power = p; + signal_power.emit(power); +} + +const char *Dummy::enumerate_protocols(unsigned i) const +{ + if(i==0) + return "dummy"; + return 0; +} + +unsigned Dummy::get_protocol_speed_steps(const string &) const +{ + return 0; +} + +void Dummy::add_turnout(unsigned addr) +{ + turnouts[addr]; +} + +void Dummy::set_turnout(unsigned addr, bool state) +{ + if(turnouts[addr]!=state) + { + turnouts[addr] = state; + signal_turnout.emit(addr, state); + } +} + +bool Dummy::get_turnout(unsigned addr) const +{ + map::const_iterator i = turnouts.find(addr); + if(i!=turnouts.end()) + return i->second; + return false; +} + +void Dummy::set_loco_speed(unsigned addr, unsigned speed) +{ + LocoState &loco = locos[addr]; + loco.speed = speed; + signal_loco_speed.emit(addr, speed, loco.reverse); +} + +void Dummy::set_loco_reverse(unsigned addr, bool rev) +{ + LocoState &loco = locos[addr]; + loco.reverse = rev; + signal_loco_speed.emit(addr, loco.speed, rev); +} + +void Dummy::set_loco_function(unsigned addr, unsigned func, bool state) +{ + signal_loco_function.emit(addr, func, state); +} + +void Dummy::set_sensor(unsigned addr, bool state) +{ + if(sensors[addr]!=state) + { + sensors[addr] = state; + signal_sensor.emit(addr, state); + } +} + +bool Dummy::get_sensor(unsigned addr) const +{ + map::const_iterator i = sensors.find(addr); + if(i!=sensors.end()) + return i->second; + return false; +} + +} // namespace R2C2 diff --git a/source/libr2c2/dummy.h b/source/libr2c2/dummy.h new file mode 100644 index 0000000..5357bbd --- /dev/null +++ b/source/libr2c2/dummy.h @@ -0,0 +1,59 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#ifndef LIBR2C2_DUMMY_H_ +#define LIBR2C2_DUMMY_H_ + +#include +#include "driver.h" + +namespace R2C2 { + +class Dummy: public Driver +{ +private: + struct LocoState + { + unsigned speed; + bool reverse; + }; + + bool power; + std::map turnouts; + std::map locos; + std::map sensors; + +public: + Dummy(); + + virtual void set_power(bool); + virtual bool get_power() const { return power; } + virtual void halt(bool) { } + virtual bool is_halted() const { return false; } + + virtual const char *enumerate_protocols(unsigned) const; + virtual unsigned get_protocol_speed_steps(const std::string &) const; + virtual void add_loco(unsigned, const std::string &) { } + virtual void set_loco_speed(unsigned, unsigned); + virtual void set_loco_reverse(unsigned, bool); + virtual void set_loco_function(unsigned, unsigned, bool); + + virtual void add_turnout(unsigned); + virtual void set_turnout(unsigned, bool); + virtual bool get_turnout(unsigned) const; + + virtual void add_sensor(unsigned) { } + virtual void set_sensor(unsigned, bool); + virtual bool get_sensor(unsigned) const; + + virtual void tick() { } + virtual void flush() { } +}; + +} // namespace R2C2 + +#endif diff --git a/source/libr2c2/geometry.h b/source/libr2c2/geometry.h new file mode 100644 index 0000000..48bbd49 --- /dev/null +++ b/source/libr2c2/geometry.h @@ -0,0 +1,39 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#ifndef LIBR2C2_GEOMETRY_H_ +#define LIBR2C2_GEOMETRY_H_ + +#include +#include + +namespace R2C2 { + +struct Point +{ + float x, y, z; + + Point(): x(0), y(0), z(0) { } + Point(float x_, float y_): x(x_), y(y_), z(0) { } + Point(float x_, float y_, float z_): x(x_), y(y_), z(z_) { } +}; + +inline float distance(const Point &p, const Point &q) +{ return sqrt((p.x-q.x)*(p.x-q.x) + (p.y-q.y)*(p.y-q.y) + (p.z-q.z)*(p.z-q.z)); } + +struct TrackPoint +{ + Point pos; + float dir; + float grade; + + TrackPoint(): dir(0), grade(0) { } +}; + +} // namespace R2C2 + +#endif diff --git a/source/libr2c2/intellibox.cpp b/source/libr2c2/intellibox.cpp new file mode 100644 index 0000000..9ac448e --- /dev/null +++ b/source/libr2c2/intellibox.cpp @@ -0,0 +1,706 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#include +#include +#include +#include +#include +#include +#include "intellibox.h" + +using namespace std; +using namespace Msp; + +namespace R2C2 { + +Intellibox::Intellibox(const string &dev): + power(false), + halted(false), + update_sensors(false), + command_sent(false) +{ + serial_fd = ::open(dev.c_str(), O_RDWR); + if(serial_fd<0) + throw Exception("Couldn't open serial port\n"); + + static unsigned baud[]= + { + 2400, B2400, + 4800, B4800, + 9600, B9600, + 19200, B19200, + 0 + }; + + termios attr; + tcgetattr(serial_fd, &attr); + cfmakeraw(&attr); + attr.c_cflag |= CSTOPB; + + bool ok = false; + bool p50 = false; + for(unsigned i=0; baud[i]; i+=2) + { + cfsetospeed(&attr, baud[i+1]); + tcsetattr(serial_fd, TCSADRAIN, &attr); + + write(serial_fd, "\xC4", 1); + + pollfd pfd = { serial_fd, POLLIN, 0 }; + if(poll(&pfd, 1, 500)>0) + { + IO::print("IB detected at %d bits/s\n", baud[i]); + char buf[2]; + p50 = (read(serial_fd, buf, 2)==2); + ok = true; + break; + } + } + + if(!ok) + throw Exception("IB not detected"); + + if(p50) + write(serial_fd, "xZzA1\r", 6); + + command(CMD_STATUS); +} + +void Intellibox::set_power(bool p) +{ + power = p; + if(power) + command(CMD_POWER_ON); + else + command(CMD_POWER_OFF); + signal_power.emit(power); +} + +void Intellibox::halt(bool h) +{ + halted = h; + if(halted) + { + for(map::iterator i=locos.begin(); i!=locos.end(); ++i) + if(i->second.speed) + set_loco_speed(i->first, 0); + } + + signal_halt.emit(halted); +} + +const char *Intellibox::enumerate_protocols(unsigned i) const +{ + if(i==MM) + return "MM"; + else if(i==MM_27) + return "MM-27"; + return 0; +} + +unsigned Intellibox::get_protocol_speed_steps(const string &proto_name) const +{ + Protocol proto = map_protocol(proto_name); + if(proto==MM) + return 14; + else if(proto==MM_27) + return 27; + return 0; +} + +void Intellibox::add_loco(unsigned addr, const string &proto_name) +{ + Protocol proto = map_protocol(proto_name); + + if(!locos.count(addr)) + { + locos[addr].protocol = proto; + + unsigned char data[2]; + data[0] = addr&0xFF; + data[1] = (addr>>8)&0xFF; + command(CMD_LOK_STATUS, addr, data, 2); + } +} + +void Intellibox::set_loco_speed(unsigned addr, unsigned speed) +{ + Locomotive &loco = locos[addr]; + if(speed==loco.speed) + { + if(loco.pending_half_step) + { + loco.pending_half_step = 0; + loco.half_step_delay = Time::TimeStamp(); + signal_loco_speed.emit(addr, speed, loco.reverse); + } + return; + } + if(speed && halted) + return; + + if(loco.protocol==MM_27) + { + if(speed>27) + speed = 27; + + if(speed>loco.speed && !(speed&1)) + { + loco.pending_half_step = -1; + speed |= 1; + } + else if(speed14) + speed = 14; + + loco_command(addr, speed, loco.reverse, loco.funcs|0x100); + } + loco.speed = speed; +} + +void Intellibox::set_loco_reverse(unsigned addr, bool rev) +{ + Locomotive &loco = locos[addr]; + if(rev==loco.reverse) + return; + + loco.reverse = rev; + loco_command(addr, loco.speed, rev, loco.funcs|0x100); +} + +void Intellibox::set_loco_function(unsigned addr, unsigned func, bool state) +{ + Locomotive &loco = locos[addr]; + if(state) + loco.funcs |= 1<>8)&0xFF; + command(CMD_TURNOUT_STATUS, addr, data, 2); + } +} + +void Intellibox::set_turnout(unsigned addr, bool state) +{ + Turnout &turnout = turnouts[addr]; + if(state==turnout.state || state==turnout.pending) + return; + + turnout.pending = state; + turnout.active = true; + turnout.off_timeout = Time::TimeStamp(); + + turnout_command(addr, state, true); +} + +bool Intellibox::get_turnout(unsigned addr) const +{ + map::const_iterator i = turnouts.find(addr); + if(i!=turnouts.end()) + return i->second.state; + return false; +} + +void Intellibox::add_sensor(unsigned addr) +{ + if(!sensors.count(addr)) + { + sensors[addr]; + update_sensors = true; + } +} + +bool Intellibox::get_sensor(unsigned addr) const +{ + map::const_iterator i = sensors.find(addr); + if(i!=sensors.end()) + return i->second.state; + return false; +} + +void Intellibox::tick() +{ + const Time::TimeStamp t = Time::now(); + + if(t>next_event_query) + { + next_event_query = t+200*Time::msec; + command(CMD_EVENT); + } + + for(map::iterator i=locos.begin(); i!=locos.end(); ++i) + if(i->second.protocol==MM_27 && i->second.pending_half_step && i->second.half_step_delay && t>i->second.half_step_delay) + { + i->second.speed += i->second.pending_half_step; + i->second.pending_half_step = 0; + i->second.half_step_delay = Time::TimeStamp(); + loco_command(i->first, (i->second.speed+1)/2, i->second.reverse, i->second.funcs|0x100); + } + + for(map::iterator i=turnouts.begin(); i!=turnouts.end(); ++i) + if(i->second.active && i->second.off_timeout && t>i->second.off_timeout) + { + i->second.active = false; + i->second.off_timeout = Time::TimeStamp(); + turnout_command(i->first, i->second.state, false); + } + + for(map::iterator i=sensors.begin(); i!=sensors.end(); ++i) + if(i->second.off_timeout && t>i->second.off_timeout) + { + i->second.state = false; + i->second.off_timeout = Time::TimeStamp(); + signal_sensor.emit(i->first, false); + } + + if(update_sensors) + { + unsigned max_addr = (--sensors.end())->first; + unsigned char data[2]; + data[0] = 0; + data[1] = (max_addr+7)/8; + command(CMD_SENSOR_PARAM_SET, data, 2); + command(CMD_SENSOR_REPORT); + update_sensors = false; + } + + if(!queue.empty() && command_sent) + { + pollfd pfd = { serial_fd, POLLIN, 0 }; + if(poll(&pfd, 1, 0)>0) + { + process_reply(t); + queue.erase(queue.begin()); + command_sent = false; + } + else + return; + } + + if(!queue.empty()) + { + const CommandSlot &slot = queue.front(); + write(serial_fd, slot.data, slot.length); + command_sent = true; + } +} + +void Intellibox::flush() +{ + Time::TimeStamp t = Time::now(); + for(list::iterator i=queue.begin(); i!=queue.end(); ++i) + { + write(serial_fd, i->data, i->length); + pollfd pfd = { serial_fd, POLLIN, 0 }; + bool first = true; + while(poll(&pfd, 1, (first ? -1 : 0))>0) + { + char data[16]; + read(serial_fd, data, 16); + first = false; + } + } + + queue.clear(); + command_sent = false; +} + +Intellibox::Protocol Intellibox::map_protocol(const string &name) const +{ + if(name=="MM") + return MM; + else if(name=="MM-27") + return MM_27; + else + throw InvalidParameterValue("Unknown protocol"); +} + +void Intellibox::command(Command cmd) +{ + command(cmd, 0, 0); +} + +void Intellibox::command(Command cmd, const unsigned char *data, unsigned len) +{ + command(cmd, 0, data, len); +} + +void Intellibox::command(Command cmd, unsigned addr, const unsigned char *data, unsigned len) +{ + CommandSlot slot; + slot.cmd = cmd; + slot.addr = addr; + slot.data[0] = cmd; + copy(data, data+len, slot.data+1); + slot.length = 1+len; + queue.push_back(slot); +} + +void Intellibox::loco_command(unsigned addr, unsigned speed, bool rev, unsigned funcs) +{ + unsigned char data[4]; + data[0] = addr&0xFF; + data[1] = (addr>>8)&0xFF; + + if(speed==0) + data[2] = 0; + else if(speed==1) + data[2] = 2; + else + data[2] = (speed*19-18)/2; + + data[3] = (rev ? 0 : 0x20) | ((funcs&1) ? 0x10 : 0); + + if(!(funcs&0x100)) + data[3] |= 0x80 | ((funcs>>1)&0xF); + + command(CMD_LOK, addr, data, 4); +} + +void Intellibox::turnout_command(unsigned addr, bool state, bool active) +{ + unsigned char data[2]; + data[0] = addr&0xFF; + data[1] = ((addr>>8)&0x7) | (active ? 0x40 : 0) | (state ? 0x80 : 0); + command(CMD_TURNOUT, addr, data, 2); +} + +void Intellibox::process_reply(const Time::TimeStamp &t) +{ + Command cmd = queue.front().cmd; + + if(cmd==CMD_STATUS) + { + unsigned char status; + read_all(&status, 1); + power = status&0x08; + signal_power.emit(power); + } + else if(cmd==CMD_EVENT) + { + for(unsigned i=0;; ++i) + { + unsigned char byte; + read_all(&byte, 1); + + if(i==0) + { + if(byte&0x01) + command(CMD_EVENT_LOK); + if(byte&0x20) + command(CMD_EVENT_TURNOUT); + if(byte&0x04) + command(CMD_EVENT_SENSOR); + } + else if(i==1) + { + if(byte&0x40) + command(CMD_STATUS); + } + + if(!(byte&0x80)) + break; + } + } + else if(cmd==CMD_EVENT_LOK) + { + while(1) + { + unsigned char data[5]; + read_all(data, 1); + if(data[0]==0x80) + break; + read_all(data+1, 4); + } + } + else if(cmd==CMD_EVENT_TURNOUT) + { + unsigned char count; + read_all(&count, 1); + for(unsigned i=0; i>(7-i%8))&1; + + Sensor &sensor = sensors[addr]; + if(state) + { + sensor.off_timeout = Time::TimeStamp(); + if(!sensor.state) + { + sensor.state = state; + signal_sensor(addr, state); + } + } + else if(sensor.state) + sensor.off_timeout = t+700*Time::msec; + } + } + } + else if(cmd==CMD_LOK) + { + Error err; + read_status(&err); + + if(err==ERR_NO_ERROR) + { + unsigned addr = queue.front().addr; + Locomotive &loco = locos[addr]; + signal_loco_speed.emit(addr, loco.speed+loco.pending_half_step, loco.reverse); + if(loco.pending_half_step) + loco.half_step_delay = Time::now()+500*Time::msec; + } + else + error(cmd, err); + } + else if(cmd==CMD_TURNOUT) + { + Error err; + read_status(&err); + + unsigned addr = queue.front().addr; + Turnout &turnout = turnouts[addr]; + + if(err==ERR_NO_ERROR) + { + turnout.state = turnout.pending; + if(turnout.active) + { + signal_turnout.emit(addr, turnout.state); + turnout.off_timeout = t+500*Time::msec; + } + } + else if(err==ERR_NO_I2C_SPACE) + queue.push_back(queue.front()); + else + { + turnout.pending = turnout.state; + error(cmd, err); + } + } + else if(cmd==CMD_TURNOUT_STATUS) + { + Error err; + read_status(&err); + + if(err==ERR_NO_ERROR) + { + unsigned char data; + read_all(&data, 1); + + unsigned addr = queue.front().addr; + bool state = data&0x04; + + Turnout &turnout = turnouts[addr]; + if(state!=turnout.state) + { + turnout.state = state; + turnout.pending = state; + signal_turnout.emit(addr, turnout.state); + } + } + else + error(cmd, err); + } + else if(cmd==CMD_LOK_STATUS) + { + Error err; + read_status(&err); + + if(err==ERR_NO_ERROR) + { + unsigned char data[3]; + read_all(data, 3); + + unsigned addr = queue.front().addr; + Locomotive &loco = locos[addr]; + + unsigned speed = (data[0]<=1 ? 0 : data[0]*2/19+1); + bool reverse = !(data[1]&0x20); + if(speed!=loco.speed || reverse!=loco.reverse) + { + loco.speed = speed; + loco.reverse = reverse; + signal_loco_speed.emit(addr, loco.speed, loco.reverse); + } + + unsigned funcs = (data[1]&0xF)<<1; + if(data[1]&0x10) + funcs |= 1; + if(funcs!=loco.funcs) + { + unsigned changed = loco.funcs^funcs; + loco.funcs = funcs; + for(unsigned i=0; i<5; ++i) + if(changed&(1<(c); + return ret; +} + +void Intellibox::error(Command cmd, Error err) +{ + const char *cmd_str = 0; + switch(cmd) + { + case CMD_LOK: cmd_str = "CMD_LOK"; break; + case CMD_LOK_STATUS: cmd_str = "CMD_LOK_STATUS"; break; + case CMD_LOK_CONFIG: cmd_str = "CMD_LOK_CONFIG"; break; + case CMD_FUNC: cmd_str = "CMD_FUNC"; break; + case CMD_FUNC_STATUS: cmd_str = "CMD_FUNC_STATUS"; break; + case CMD_TURNOUT: cmd_str = "CMD_TURNOUT"; break; + case CMD_TURNOUT_FREE: cmd_str = "CMD_TURNOUT_FREE"; break; + case CMD_TURNOUT_STATUS: cmd_str = "CMD_TURNOUT_STATUS"; break; + case CMD_TURNOUT_GROUP_STATUS: cmd_str = "CMD_TURNOUT_GROUP_STATUS"; break; + case CMD_SENSOR_STATUS: cmd_str = "CMD_SENSOR_STATUS"; break; + case CMD_SENSOR_REPORT: cmd_str = "CMD_SENSOR_REPORT"; break; + case CMD_SENSOR_PARAM_SET: cmd_str = "CMD_SENSOR_PARAM_SET"; break; + case CMD_STATUS: cmd_str = "CMD_STATUS"; break; + case CMD_POWER_OFF: cmd_str = "CMD_POWER_OFF"; break; + case CMD_POWER_ON: cmd_str = "CMD_POWER_ON"; break; + case CMD_NOP: cmd_str = "CMD_NOP"; break; + case CMD_EVENT: cmd_str = "CMD_EVENT"; break; + case CMD_EVENT_LOK: cmd_str = "CMD_EVENT_LOK"; break; + case CMD_EVENT_TURNOUT: cmd_str = "CMD_EVENT_TURNOUT"; break; + case CMD_EVENT_SENSOR: cmd_str = "CMD_EVENT_SENSOR"; break; + default: cmd_str = "(unknown command)"; + } + + const char *err_str = 0; + switch(err) + { + case ERR_NO_ERROR: err_str = "ERR_NO_ERROR"; break; + case ERR_SYS_ERROR: err_str = "ERR_SYS_ERROR"; break; + case ERR_BAD_PARAM: err_str = "ERR_BAD_PARAM"; break; + case ERR_POWER_OFF: err_str = "ERR_POWER_OFF"; break; + case ERR_NO_LOK_SPACE: err_str = "ERR_NO_LOK_SPACE"; break; + case ERR_NO_TURNOUT_SPACE: err_str = "ERR_NO_TURNOUT_SPACE"; break; + case ERR_NO_DATA: err_str = "ERR_NO_DATA"; break; + case ERR_NO_SLOT: err_str = "ERR_NO_SLOT"; break; + case ERR_BAD_LOK_ADDR: err_str = "ERR_BAD_LOK_ADDR"; break; + case ERR_LOK_BUSY: err_str = "ERR_LOK_BUSY"; break; + case ERR_BAD_TURNOUT_ADDR: err_str = "ERR_BAD_TURNOUT_ADDR"; break; + case ERR_BAD_SO_VALUE: err_str = "ERR_BAD_SO_VALUE"; break; + case ERR_NO_I2C_SPACE: err_str = "ERR_NO_I2C_SPACE"; break; + case ERR_LOW_TURNOUT_SPACE: err_str = "ERR_LOW_TURNOUT_SPACE"; break; + case ERR_LOK_HALTED: err_str = "ERR_LOK_HALTED"; break; + case ERR_LOK_POWER_OFF: err_str = "ERR_LOK_POWER_OFF"; break; + default: cmd_str = "(unknown error)"; + } + + IO::print("Error: %s: %s\n", cmd_str, err_str); +} + + +Intellibox::Locomotive::Locomotive(): + speed(0), + reverse(false), + funcs(0) +{ } + + +Intellibox::Turnout::Turnout(): + state(false), + active(false), + pending(false) +{ } + + +Intellibox::Sensor::Sensor(): + state(false) +{ } + +} // namespace R2C2 diff --git a/source/libr2c2/intellibox.h b/source/libr2c2/intellibox.h new file mode 100644 index 0000000..8655bfc --- /dev/null +++ b/source/libr2c2/intellibox.h @@ -0,0 +1,170 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#ifndef LIBR2C2_INTELLIBOX_H_ +#define LIBR2C2_INTELLIBOX_H_ + +#include +#include +#include "driver.h" + +namespace R2C2 { + +/** +Driver for Uhlenbrock Intellibox. Uses the P50X binary protocol over RS232. + +Motorola decoders with 27 speed steps are supported by manually generating the +commands necessary to reach the "half-steps". However, sending a rapid stream +of speed changes to the same locomotive seems to cause excessive lag, so we +cheat a bit; instead of sending the half-step command immediately, we send it +with a 500ms delay, but only if no new set_loco_speed calls have occurred. As +a downside from this accelerations and decelerations are still jerky. +*/ +class Intellibox: public Driver +{ +private: + enum Command + { + CMD_LOK=0x80, + CMD_LOK_STATUS=0x84, + CMD_LOK_CONFIG=0x85, + CMD_FUNC=0x88, + CMD_FUNC_STATUS=0x8C, + CMD_TURNOUT=0x90, + CMD_TURNOUT_FREE=0x93, + CMD_TURNOUT_STATUS=0x94, + CMD_TURNOUT_GROUP_STATUS=0x95, + CMD_SENSOR_STATUS=0x98, + CMD_SENSOR_REPORT=0x99, + CMD_SENSOR_PARAM_SET=0x9D, + CMD_STATUS=0xA2, + CMD_POWER_OFF=0xA6, + CMD_POWER_ON=0xA7, + CMD_NOP=0xC4, + CMD_EVENT=0xC8, + CMD_EVENT_LOK=0xC9, + CMD_EVENT_TURNOUT=0xCA, + CMD_EVENT_SENSOR=0xCB + }; + + enum Error + { + ERR_NO_ERROR=0, + ERR_SYS_ERROR, + ERR_BAD_PARAM, + ERR_POWER_OFF=0x6, + ERR_NO_LOK_SPACE=0x8, // No space in lok command buffer + ERR_NO_TURNOUT_SPACE, // No space in turnout command buffer + ERR_NO_DATA, // "no Lok status available (Lok is not in a slot)" + ERR_NO_SLOT, // "there is no slot available" + ERR_BAD_LOK_ADDR, + ERR_LOK_BUSY, + ERR_BAD_TURNOUT_ADDR, + ERR_BAD_SO_VALUE, + ERR_NO_I2C_SPACE, + ERR_LOW_TURNOUT_SPACE=0x40, + ERR_LOK_HALTED, + ERR_LOK_POWER_OFF, + }; + + enum Protocol + { + MM, + MM_27 + }; + + struct Locomotive + { + Protocol protocol; + unsigned speed; + bool reverse; + unsigned funcs; + int pending_half_step; + Msp::Time::TimeStamp half_step_delay; + + Locomotive(); + }; + + struct Turnout + { + bool state; + bool active; + bool pending; + Msp::Time::TimeStamp off_timeout; + + Turnout(); + }; + + struct Sensor + { + bool state; + Msp::Time::TimeStamp off_timeout; + + Sensor(); + }; + + struct CommandSlot + { + Command cmd; + unsigned addr; + unsigned char data[8]; + unsigned length; + }; + + int serial_fd; + bool power; + bool halted; + std::map locos; + std::map turnouts; + std::map sensors; + bool update_sensors; + std::list queue; + bool command_sent; + Msp::Time::TimeStamp next_event_query; + +public: + Intellibox(const std::string &); + + virtual void set_power(bool); + virtual bool get_power() const { return power; } + virtual void halt(bool); + virtual bool is_halted() const { return halted; } + + virtual const char *enumerate_protocols(unsigned) const; + virtual unsigned get_protocol_speed_steps(const std::string &) const; + virtual void add_loco(unsigned, const std::string &); + virtual void set_loco_speed(unsigned, unsigned); + virtual void set_loco_reverse(unsigned, bool); + virtual void set_loco_function(unsigned, unsigned, bool); + + virtual void add_turnout(unsigned); + virtual void set_turnout(unsigned, bool); + virtual bool get_turnout(unsigned) const; + + virtual void add_sensor(unsigned); + virtual void set_sensor(unsigned, bool) { } + virtual bool get_sensor(unsigned) const; + + virtual void tick(); + virtual void flush(); + +private: + Protocol map_protocol(const std::string &) const; + void command(Command); + void command(Command, const unsigned char *, unsigned); + void command(Command, unsigned, const unsigned char *, unsigned); + void loco_command(unsigned, unsigned, bool, unsigned); + void turnout_command(unsigned, bool, bool); + void process_reply(const Msp::Time::TimeStamp &); + unsigned read_all(unsigned char *, unsigned); + unsigned read_status(Error *); + void error(Command, Error); +}; + +} // namespace R2C2 + +#endif diff --git a/source/libr2c2/layout.cpp b/source/libr2c2/layout.cpp new file mode 100644 index 0000000..1c0d4cf --- /dev/null +++ b/source/libr2c2/layout.cpp @@ -0,0 +1,351 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#include +#include +#include +#include +#include +#include +#include "block.h" +#include "catalogue.h" +#include "driver.h" +#include "layout.h" +#include "route.h" +#include "track.h" +#include "tracktype.h" +#include "train.h" +#include "vehicletype.h" + +using namespace std; +using namespace Msp; + +namespace R2C2 { + +Layout::Layout(Catalogue &c, Driver *d): + catalogue(c), + driver(d), + next_turnout_id(0x800) +{ + if(driver) + driver->signal_sensor.connect(sigc::mem_fun(this, &Layout::sensor_event)); +} + +Layout::~Layout() +{ + delete driver; + while(!trains.empty()) + delete trains.begin()->second; + while(!routes.empty()) + delete *routes.begin(); + while(!tracks.empty()) + delete *tracks.begin(); + while(!blocks.empty()) + delete *blocks.begin(); +} + +Driver &Layout::get_driver() const +{ + if(!driver) + throw InvalidState("No driver"); + return *driver; +} + +void Layout::add_track(Track &t) +{ + if(tracks.insert(&t).second) + { + create_blocks(); + signal_track_added.emit(t); + } +} + +void Layout::remove_track(Track &t) +{ + if(tracks.erase(&t)) + { + create_blocks(t); + signal_track_removed.emit(t); + } +} + +unsigned Layout::allocate_turnout_id(bool dbl) +{ + set used_ids; + for(set::const_iterator i=tracks.begin(); i!=tracks.end(); ++i) + if((*i)->get_turnout_id()) + used_ids.insert((*i)->get_turnout_id()); + + unsigned result = next_turnout_id; + while(used_ids.count(result) || (dbl && used_ids.count(result+1))) + ++result; + next_turnout_id = result+1+dbl; + + return result; +} + +void Layout::add_block(Block &b) +{ + blocks.insert(&b); +} + +Block &Layout::get_block(unsigned id) const +{ + for(set::const_iterator i=blocks.begin(); i!=blocks.end(); ++i) + if((*i)->get_id()==id) + return **i; + + throw KeyError("Unknown block", lexical_cast(id)); +} + +void Layout::create_blocks() +{ + set used_tracks; + for(set::const_iterator i=blocks.begin(); i!=blocks.end(); ++i) + { + const set &btracks = (*i)->get_tracks(); + used_tracks.insert(btracks.begin(), btracks.end()); + } + + for(set::const_iterator i=tracks.begin(); i!=tracks.end(); ++i) + if(used_tracks.count(*i)==0) + { + Block *block = new Block(*this, **i); + used_tracks.insert(block->get_tracks().begin(), block->get_tracks().end()); + } + + for(set::iterator i=blocks.begin(); i!=blocks.end(); ++i) + for(set::iterator j=i; j!=blocks.end(); ++j) + if(j!=i) + (*i)->check_link(**j); +} + +void Layout::create_blocks(Track &track) +{ + /* Must collect the blocks in a set first while all tracks are still + guaranteed to have blocks and to avoid duplicate deletes */ + set del_blocks; + + del_blocks.insert(&track.get_block()); + + const vector &links = track.get_links(); + for(vector::const_iterator i=links.begin(); i!=links.end(); ++i) + if(*i) + del_blocks.insert(&(*i)->get_block()); + + for(set::iterator i=del_blocks.begin(); i!=del_blocks.end(); ++i) + delete *i; + + create_blocks(); +} + +void Layout::remove_block(Block &b) +{ + blocks.erase(&b); +} + +void Layout::add_route(Route &r) +{ + if(routes.insert(&r).second) + signal_route_added.emit(r); +} + +Route &Layout::get_route(const string &name) const +{ + for(set::const_iterator i=routes.begin(); i!=routes.end(); ++i) + if((*i)->get_name()==name) + return **i; + throw KeyError("Unknown route", name); +} + +void Layout::update_routes() +{ + for(set::iterator i=routes.begin(); i!=routes.end(); ++i) + (*i)->update_turnouts(); +} + +void Layout::remove_route(Route &r) +{ + if(routes.erase(&r)) + signal_route_removed.emit(r); +} + +void Layout::add_train(Train &t) +{ + if(trains.count(t.get_address())) + throw KeyError("Duplicate train address", lexical_cast(t.get_address())); + + trains[t.get_address()] = &t; + signal_train_added.emit(t); +} + +Train &Layout::get_train(unsigned addr) const +{ + map::const_iterator i = trains.find(addr); + if(i==trains.end()) + throw KeyError("Unknown train", lexical_cast(addr)); + return *i->second; +} + +void Layout::remove_train(Train &t) +{ + if(trains.erase(t.get_address())) + signal_train_removed.emit(t); +} + +void Layout::add_vehicle(Vehicle &v) +{ + if(vehicles.insert(&v).second) + signal_vehicle_added.emit(v); +} + +void Layout::remove_vehicle(Vehicle &v) +{ + if(vehicles.erase(&v)) + signal_vehicle_removed.emit(v); +} + +void Layout::tick() +{ + if(driver) + driver->tick(); + + Time::TimeStamp t = Time::now(); + Time::TimeDelta dt; + if(last_tick) + dt = t-last_tick; + last_tick = t; + + for(map::iterator i=trains.begin(); i!=trains.end(); ++i) + i->second->tick(t, dt); +} + +void Layout::emergency(const string &msg) +{ + if(driver) + driver->halt(true); + IO::print("Emergency: %s\n", msg); + signal_emergency.emit(msg); +} + +void Layout::save(const string &fn) +{ + IO::BufferedFile out(fn, IO::M_WRITE); + DataFile::Writer writer(out); + + if(!base.empty()) + writer.write((DataFile::Statement("base"), base)); + + for(set::iterator i=tracks.begin(); i!=tracks.end(); ++i) + { + DataFile::Statement st("track"); + st.append((*i)->get_type().get_article_number()); + (*i)->save(st.sub); + writer.write(st); + } + + for(set::iterator i=routes.begin(); i!=routes.end(); ++i) + { + if((*i)->is_temporary()) + continue; + + DataFile::Statement st("route"); + (*i)->save(st.sub); + writer.write(st); + } +} + +void Layout::save_trains(const string &fn) +{ + IO::BufferedFile out(fn, IO::M_WRITE); + DataFile::Writer writer(out); + + for(map::const_iterator i=trains.begin(); i!=trains.end(); ++i) + { + DataFile::Statement st("train"); + st.append(i->second->get_locomotive_type().get_article_number()); + st.append(i->second->get_address()); + st.append(i->second->get_protocol()); + i->second->save(st.sub); + writer.write(st); + } +} + +void Layout::sensor_event(unsigned addr, bool state) +{ + if(state) + { + for(set::iterator i=blocks.begin(); i!=blocks.end(); ++i) + if((*i)->get_sensor_id()==addr) + { + if(!(*i)->get_train()) + emergency(format("Unreserved sensor %d triggered", addr)); + break; + } + } +} + + +Layout::Loader::Loader(Layout &l): + DataFile::BasicLoader(l), + new_tracks(false) +{ + add("base", &Layout::base); + add("route", static_cast(&Loader::route)); + add("route", static_cast(&Loader::route)); + add("track", static_cast(&Loader::track)); + add("track", static_cast(&Loader::track)); + add("train", static_cast(&Loader::train)); + add("train", static_cast(&Loader::train)); +} + +void Layout::Loader::finish() +{ + for(set::iterator i=obj.tracks.begin(); i!=obj.tracks.end(); ++i) + (*i)->check_slope(); +} + +void Layout::Loader::route() +{ + Route *rte = new Route(obj); + load_sub(*rte); +} + +void Layout::Loader::route(const string &n) +{ + Route *rte = new Route(obj); + rte->set_name(n); + load_sub(*rte); +} + +void Layout::Loader::track(unsigned art_nr) +{ + track(ArticleNumber(art_nr)); +} + +void Layout::Loader::track(ArticleNumber art_nr) +{ + Track *trk = new Track(obj, obj.catalogue.get_track(art_nr)); + load_sub(*trk); + new_tracks = true; + for(set::iterator i=obj.tracks.begin(); i!=obj.tracks.end(); ++i) + if(*i!=trk) + trk->snap_to(**i, true); +} + +void Layout::Loader::train(unsigned art_nr, unsigned addr, const std::string &proto) +{ + train(ArticleNumber(art_nr), addr, proto); +} + +void Layout::Loader::train(ArticleNumber art_nr, unsigned addr, const std::string &proto) +{ + Train *trn = new Train(obj, obj.catalogue.get_vehicle(art_nr), addr, proto); + load_sub(*trn); +} + +} // namespace R2C2 diff --git a/source/libr2c2/layout.h b/source/libr2c2/layout.h new file mode 100644 index 0000000..86db658 --- /dev/null +++ b/source/libr2c2/layout.h @@ -0,0 +1,118 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#ifndef LIBR2C2_LAYOUT_H_ +#define LIBR2C2_LAYOUT_H_ + +#include +#include +#include +#include + +namespace R2C2 { + +class ArticleNumber; +class Block; +class Catalogue; +class Driver; +class Route; +class Track; +class Train; +class Vehicle; + +class Layout +{ +public: + class Loader: public Msp::DataFile::BasicLoader + { + private: + bool new_tracks; + + public: + Loader(Layout &); + private: + virtual void finish(); + void route(); + void route(const std::string &); + void track(unsigned); + void track(ArticleNumber); + void train(unsigned, unsigned, const std::string &); + void train(ArticleNumber, unsigned, const std::string &); + }; + +public: + sigc::signal signal_track_added; + sigc::signal signal_track_removed; + sigc::signal signal_route_added; + sigc::signal signal_route_removed; + sigc::signal signal_train_added; + sigc::signal signal_train_removed; + sigc::signal signal_vehicle_added; + sigc::signal signal_vehicle_removed; + sigc::signal signal_block_reserved; + sigc::signal signal_emergency; + +private: + Catalogue &catalogue; + Driver *driver; + std::string base; + std::set tracks; + std::set routes; + std::set blocks; + std::map trains; + std::set vehicles; + Msp::Time::TimeStamp last_tick; + unsigned next_turnout_id; + +public: + Layout(Catalogue &, Driver * = 0); + ~Layout(); + + Catalogue &get_catalogue() const { return catalogue; } + bool has_driver() const { return driver; } + Driver &get_driver() const; + const std::string &get_base() const { return base; } + + void add_track(Track &); + const std::set &get_tracks() const { return tracks; } + void remove_track(Track &); + unsigned allocate_turnout_id(bool); + + void add_block(Block &); + Block &get_block(unsigned) const; + const std::set &get_blocks() const { return blocks; } + void create_blocks(); + void create_blocks(Track &); + void remove_block(Block &); + + void add_route(Route &); + const std::set &get_routes() const { return routes; } + Route &get_route(const std::string &) const; + void update_routes(); + void remove_route(Route &); + + void add_train(Train &); + Train &get_train(unsigned) const; + const std::map &get_trains() const { return trains; } + void remove_train(Train &); + + void add_vehicle(Vehicle &); + void remove_vehicle(Vehicle &); + + void tick(); + void emergency(const std::string &); + + void save(const std::string &); + void save_trains(const std::string &); +private: + void sensor_event(unsigned, bool); +}; + +} // namespace R2C2 + +#endif + diff --git a/source/libr2c2/profile.cpp b/source/libr2c2/profile.cpp new file mode 100644 index 0000000..b44ee36 --- /dev/null +++ b/source/libr2c2/profile.cpp @@ -0,0 +1,62 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#include +#include "profile.h" + +using namespace std; +using namespace Msp; + +namespace R2C2 { + +void Profile::append_point(const Point &p) +{ + points.push_back(p); + if(points.size()==1) + { + min_coords = p; + max_coords = p; + } + else + { + min_coords.x = min(min_coords.x, p.x); + min_coords.y = min(min_coords.y, p.y); + max_coords.x = max(max_coords.x, p.x); + max_coords.y = max(max_coords.y, p.y); + } +} + +const Point &Profile::get_point(unsigned i) const +{ + if(i>=points.size()) + throw InvalidParameterValue("Index out of range"); + return points[i]; +} + +Point Profile::get_edge_normal(unsigned i) const +{ + if(i+1>=points.size()) + throw InvalidParameterValue("Index out of range"); + float dx = points[i+1].x-points[i].x; + float dy = points[i+1].y-points[i].y; + float len = sqrt(dx*dx+dy*dy); + return Point(dy/len, -dx/len); +} + + +Profile::Loader::Loader(Profile &p): + DataFile::ObjectLoader(p) +{ + add("point", &Loader::point); +} + +void Profile::Loader::point(float x, float y) +{ + obj.append_point(Point(x/1000, y/1000)); +} + +} // namespace R2C2 diff --git a/source/libr2c2/profile.h b/source/libr2c2/profile.h new file mode 100644 index 0000000..00132e9 --- /dev/null +++ b/source/libr2c2/profile.h @@ -0,0 +1,46 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#ifndef LIBR2C2_PROFILE_H_ +#define LIBR2C2_PROFILE_H_ + +#include +#include +#include "geometry.h" + +namespace R2C2 { + +class Profile +{ +public: + class Loader: public Msp::DataFile::ObjectLoader + { + public: + Loader(Profile &); + private: + void point(float, float); + }; + +private: + std::vector points; + Point min_coords; + Point max_coords; + +public: + void append_point(const Point &); + unsigned get_n_points() const { return points.size(); } + const Point &get_point(unsigned) const; + const Point &get_min_coords() const { return min_coords; } + const Point &get_max_coords() const { return max_coords; } + float get_width() const { return max_coords.x-min_coords.x; } + float get_height() const { return max_coords.y-min_coords.y; } + Point get_edge_normal(unsigned) const; +}; + +} // namespace R2C2 + +#endif diff --git a/source/libr2c2/route.cpp b/source/libr2c2/route.cpp new file mode 100644 index 0000000..4f7e778 --- /dev/null +++ b/source/libr2c2/route.cpp @@ -0,0 +1,455 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2007-2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#include +#include +#include "layout.h" +#include "route.h" +#include "track.h" +#include "trackiter.h" +#include "tracktype.h" + +using namespace std; +using namespace Msp; + +namespace { + +using namespace R2C2; + +typedef std::pair Key; + +struct Node +{ + TrackIter track; + Node *prev; + float dist; + + Node(): + prev(0), dist(0) + { } + + Node(const TrackIter &t): + track(t), prev(0), dist(0) + { } + + Node(const TrackIter &t, Node &r, float d): + track(t), prev(&r), dist(prev->dist+d) + { } + + bool operator<(const Node &other) const + { return dist>other.dist; } +}; + +struct TrackMatch +{ + Track &track; + + TrackMatch(Track &t): track(t) { } + + bool operator()(Track &t) const { return &t==&track; } +}; + +struct TrackInSet +{ + const set &tracks; + + TrackInSet(const set &t): tracks(t) { } + + bool operator()(Track &t) const { return tracks.count(&t); } +}; + +template +list dijkstra(const TrackIter &from, const Pred &goal) +{ + map track_nodes; + priority_queue nodes; + Node *final = 0; + + nodes.push(from); + + while(!nodes.empty()) + { + Node lowest = nodes.top(); + nodes.pop(); + + Key key(lowest.track.track(), lowest.track.entry()); + if(track_nodes.count(key)) + continue; + + Node &ref = track_nodes[key] = lowest; + if(goal(*lowest.track)) + { + final = &ref; + break; + } + + unsigned paths = lowest.track.endpoint().paths; + for(unsigned i=0; paths>>i; ++i) + if(paths&(1<get_type().get_path_length(i))); + } + } + + list result; + for(Node *node=final; node; node=node->prev) + result.push_front(&*node->track); + + return result; +} + +template +Route *create_route(const TrackIter &from, const Pred &goal) +{ + list tracks = dijkstra(from, goal); + + if(tracks.empty()) + return 0; + + Route *route = new Route(from->get_layout()); + for(list::iterator i=tracks.begin(); i!=tracks.end(); ++i) + route->add_track(**i); + + route->set_name("Pathfinder"); + route->set_temporary(true); + + return route; +} + +} + + +namespace R2C2 { + +Route::Route(Layout &l): + layout(l), + temporary(false) +{ + layout.add_route(*this); + layout.signal_track_removed.connect(sigc::mem_fun(this, &Route::track_removed)); +} + +Route::~Route() +{ + layout.remove_route(*this); +} + +void Route::set_name(const string &n) +{ + name = n; + signal_name_changed.emit(name); +} + +void Route::set_temporary(bool t) +{ + temporary = t; +} + +void Route::set_turnout(unsigned addr, unsigned path) +{ + if(!addr) + throw InvalidParameterValue("Invalid turnout address"); + map::iterator i = turnouts.find(addr); + if(i==turnouts.end()) + throw KeyError("Turnout is not in this route"); + if(i->second>=0 && path!=static_cast(i->second)) + throw InvalidState("Setting conflicts with route"); + i->second = path; +} + +void Route::update_turnouts() +{ + set found; + for(set::const_iterator i=tracks.begin(); i!=tracks.end(); ++i) + if(unsigned tid = (*i)->get_turnout_id()) + { + found.insert(tid); + + const vector &endpoints = (*i)->get_type().get_endpoints(); + const vector &links = (*i)->get_links(); + + // Build a combined path mask from linked endpoints + unsigned mask = (*i)->get_type().get_paths(); + for(unsigned j=0; jget_turnout_id()) + { + const TrackType::Endpoint &ep = links[j]->get_type().get_endpoint(links[j]->get_endpoint_by_link(**i)); + int p = get_turnout(tid2); + if(p>=0 && !(ep.paths&(1<>=1, ++path) ; + turnouts[tid] = path; + } + else if(!turnouts.count(tid)) + // More than one possible choice, and no existing entry - set as undecided + turnouts[tid] = -1; + } + + // Remove any turnouts that do not exist in the route + for(map::iterator i=turnouts.begin(); i!=turnouts.end();) + { + if(!found.count(i->first)) + turnouts.erase(i++); + else + ++i; + } +} + +int Route::get_turnout(unsigned id) const +{ + map::const_iterator i = turnouts.find(id); + if(i!=turnouts.end()) + return i->second; + return -1; +} + +unsigned Route::get_path(Track &trk) const +{ + if(unsigned tid = trk.get_turnout_id()) + { + map::const_iterator i = turnouts.find(tid); + if(i!=turnouts.end()) + return i->second; + } + return trk.get_active_path(); +} + +void Route::add_track(Track &trk) +{ + if(tracks.count(&trk)) + return; + + if(!tracks.empty()) + { + unsigned valid = check_validity(trk); + if(!(valid&1)) + throw Exception("Not linked to existing tracks"); + else if(!(valid&2)) + throw Exception("Branching routes not allowed"); + else if(!(valid&4)) + throw Exception("Route must be smooth"); + } + + tracks.insert(&trk); + update_turnouts(); +} + +void Route::add_tracks(const set &trks) +{ + set pending; + for(set::const_iterator i=trks.begin(); i!=trks.end(); ++i) + if(!tracks.count(*i)) + pending.insert(*i); + + while(!pending.empty()) + { + bool found = false; + for(set::const_iterator i=pending.begin(); i!=pending.end(); ++i) + if(tracks.empty() || check_validity(**i)==7) + { + tracks.insert(*i); + pending.erase(*i); + found = true; + break; + } + + if(!found) + throw Exception("Could not add all tracks to route"); + } + + update_turnouts(); +} + +void Route::add_track_chain(Track &start, unsigned ep, const TurnoutMap &trnts) +{ + TrackIter iter(&start, ep); + while(iter) + { + if(iter->get_type().is_dead_end()) + break; + + if(has_track(*iter)) + break; + + int path = 0; + if(iter->get_turnout_id()) + { + TurnoutMap::const_iterator i = trnts.find(iter->get_turnout_id()); + if(i==trnts.end()) + break; + + path = i->second; + } + + add_track(*iter); + + iter = iter.next(path); + } +} + +bool Route::has_track(Track &t) const +{ + return tracks.count(&t); +} + +void Route::save(list &st) const +{ + st.push_back((DataFile::Statement("name"), name)); + for(map::const_iterator i=turnouts.begin(); i!=turnouts.end(); ++i) + st.push_back((DataFile::Statement("turnout"), i->first, i->second)); +} + +unsigned Route::check_validity(Track &trk) const +{ + unsigned result = 4; + const vector &links = trk.get_links(); + for(vector::const_iterator i=links.begin(); i!=links.end(); ++i) + { + if(!*i) + continue; + if(!tracks.count(*i)) + continue; + + // Linked to an existing track - good + result |= 1; + + if(unsigned tid = (*i)->get_turnout_id()) + { + const TrackType::Endpoint &ep = (*i)->get_type().get_endpoint((*i)->get_endpoint_by_link(trk)); + int path = get_turnout(tid); + if(path>=0) + { + // Linking to a turnout with path set is only good if we're continuing that path + if(ep.paths&(1< &tlinks = (*i)->get_links(); + unsigned count = 0; + for(unsigned j=0; jget_turnout_id(); + if(tid2) + { + const TrackType::Endpoint &ep2 = tlinks[j]->get_type().get_endpoint(tlinks[j]->get_endpoint_by_link(**i)); + path = get_turnout(tid2); + // Ignore a linked turnout with some other path set + if(path>0 && !(ep2.paths&(1<get_type().get_endpoint(j); + if(!(ep.paths&ep2.paths)) + // Impossible path through the turnout - not good + result &= 3; + } + + // Only good if at most one other track is linked to the turnout + if(count<=1) + result |= 2; + } + } + else + // Linked to something linear - good + result |= 2; + } + + return result; +} + +void Route::track_removed(Track &t) +{ + tracks.erase(&t); +} + +Route *Route::find(const TrackIter &from, Track &to) +{ + return create_route(from, TrackMatch(to)); +} + +Route *Route::find(const TrackIter &from, const Route &to) +{ + return create_route(from, TrackInSet(to.get_tracks())); +} + +Route *Route::find(const TrackIter &from, const set &to) +{ + return create_route(from, TrackInSet(to)); +} + + +Route::Loader::Loader(Route &r): + DataFile::BasicLoader(r) +{ + add("name", &Route::name); + add("turnout", &Loader::turnout); +} + +void Route::Loader::finish() +{ + const set <racks = obj.layout.get_tracks(); + for(set::const_iterator i=ltracks.begin(); i!=ltracks.end(); ++i) + { + unsigned tid = (*i)->get_turnout_id(); + if(!tid) + continue; + + TurnoutMap::iterator j = turnouts.find(tid); + if(j==turnouts.end()) + continue; + + unsigned path_mask = 1<second; + const vector &eps = (*i)->get_type().get_endpoints(); + for(unsigned k=0; kget_link(k); + if(!obj.tracks.count(link)) + obj.add_track_chain(*link, link->get_endpoint_by_link(**i), turnouts); + if(!obj.tracks.count(*i)) + obj.add_track_chain(**i, k, turnouts); + break; + } + + break; + } +} + +void Route::Loader::turnout(unsigned id, unsigned path) +{ + turnouts[id] = path; +} + +} // namespace R2C2 diff --git a/source/libr2c2/route.h b/source/libr2c2/route.h new file mode 100644 index 0000000..86a0f61 --- /dev/null +++ b/source/libr2c2/route.h @@ -0,0 +1,80 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2007-2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#ifndef LIBR2C2_ROUTE_H_ +#define LIBR2C2_ROUTE_H_ + +#include +#include +#include +#include +#include + +namespace R2C2 { + +class Layout; +class Track; +class TrackIter; + +class Route: public sigc::trackable +{ +public: + typedef std::map TurnoutMap; + + class Loader: public Msp::DataFile::BasicLoader + { + private: + TurnoutMap turnouts; + + public: + Loader(Route &); + private: + virtual void finish(); + void turnout(unsigned, unsigned); + }; + + sigc::signal signal_name_changed; + +private: + Layout &layout; + std::string name; + bool temporary; + std::set tracks; + TurnoutMap turnouts; + +public: + Route(Layout &); + ~Route(); + + void set_name(const std::string &); + const std::string &get_name() const { return name; } + void set_temporary(bool); + bool is_temporary() const { return temporary; } + void set_turnout(unsigned, unsigned); + void update_turnouts(); + int get_turnout(unsigned) const; + unsigned get_path(Track &) const; + const std::map &get_turnouts() const { return turnouts; } + void add_track(Track &); + void add_tracks(const std::set &); + void add_track_chain(Track &, unsigned, const TurnoutMap &); + const std::set &get_tracks() const { return tracks; } + bool has_track(Track &) const; + void save(std::list &) const; +private: + unsigned check_validity(Track &) const; + void track_removed(Track &); + +public: + static Route *find(const TrackIter &, Track &); + static Route *find(const TrackIter &, const Route &); + static Route *find(const TrackIter &, const std::set &); +}; + +} // namespace R2C2 + +#endif diff --git a/source/libr2c2/simplecontroller.cpp b/source/libr2c2/simplecontroller.cpp new file mode 100644 index 0000000..7f8b336 --- /dev/null +++ b/source/libr2c2/simplecontroller.cpp @@ -0,0 +1,74 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#include +#include +#include "simplecontroller.h" + +using namespace std; +using namespace Msp; + +namespace R2C2 { + +SimpleController::SimpleController(): + target_speed(Control::continuous("speed", 0, 1000)), + reverse(Control::binary("reverse")), + accel(0.07), + speed(0) +{ + target_speed.set(0); +} + +void SimpleController::set_control(const string &name, float v) +{ + if(name=="speed") + { + target_speed.set(v); + signal_control_changed.emit(target_speed); + } + else if(name=="reverse") + { + if(target_speed.value || speed) + throw InvalidState("Must be stopped to change reverse"); + reverse.set(v); + signal_control_changed.emit(reverse); + } +} + +const Controller::Control &SimpleController::get_control(const string &name) const +{ + if(name=="speed") + return target_speed; + else if(name=="reverse") + return reverse; + else + throw KeyError("Unknown control", name); +} + +float SimpleController::get_braking_distance() const +{ + return speed*speed/(2*accel); +} + +void SimpleController::tick(const Time::TimeDelta &dt) +{ + float secs = dt/Time::sec; + if(speedtarget_speed.value) + speed = target_speed.value; + } + else if(speed>target_speed.value) + { + speed -= secs*accel; + if(speed +#include "controller.h" + +namespace R2C2 { + +class SimpleController: public Controller +{ +private: + Control target_speed; + Control reverse; + float accel; + float speed; + +public: + SimpleController(); + + virtual void set_control(const std::string &, float); + virtual const Control &get_control(const std::string &) const; + + virtual float get_speed() const { return speed; } + virtual bool get_reverse() const { return reverse.value; } + virtual float get_braking_distance() const; + + virtual void tick(const Msp::Time::TimeDelta &); +}; + +} // namespace R2C2 + +#endif diff --git a/source/libr2c2/timetable.cpp b/source/libr2c2/timetable.cpp new file mode 100644 index 0000000..bc8ebe6 --- /dev/null +++ b/source/libr2c2/timetable.cpp @@ -0,0 +1,337 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#include +#include +#include "block.h" +#include "catalogue.h" +#include "driver.h" +#include "layout.h" +#include "timetable.h" +#include "train.h" + +using namespace std; +using namespace Msp; + +namespace R2C2 { + +Timetable::Timetable(Train &t): + train(t), + enabled(false), + current_row(0), + executing(true), + pending_block(0), + pending_train(0) +{ + train.signal_arrived.connect(sigc::mem_fun(this, &Timetable::train_arrived)); + train.get_layout().get_driver().signal_sensor.connect(sigc::mem_fun(this, &Timetable::sensor_event)); +} + +void Timetable::set_enabled(bool e) +{ + enabled = e; +} + +void Timetable::reset() +{ + current_row = 0; + wait_timeout = Time::TimeStamp(); + pending_block = 0; + executing = true; +} + +void Timetable::clear() +{ + rows.clear(); + reset(); +} + +void Timetable::append(const Row &row) +{ + rows.push_back(row); +} + +void Timetable::insert(unsigned i, const Row &row) +{ + if(i>rows.size()) + throw InvalidParameterValue("Insert position out of range"); + + rows.insert(rows.begin()+i, row); + if(i<=current_row) + ++current_row; +} + +const Timetable::Row &Timetable::get_row(unsigned i) const +{ + if(i>=rows.size()) + throw InvalidParameterValue("Row index out of range"); + return rows[i]; +} + +void Timetable::tick(const Time::TimeStamp &t) +{ + if(rows.empty() || !enabled) + return; + + if(wait_timeout && t>=wait_timeout) + { + wait_timeout = Time::TimeStamp(); + current_row = (current_row+1)%rows.size(); + executing = true; + } + + if(executing) + { + Row &row = rows[current_row]; + switch(row.type) + { + case GOTO: + if(!train.go_to(**parse_location(row.get_param(0)).get_tracks().begin())) + set_enabled(false); + break; + case TRAVEL: + pending_block = &parse_location(row.get_param(0)); + pending_train = &train; + executing = false; + break; + case WAIT_TIME: + wait_timeout = t+row.get_param(0)*Time::sec; + executing = false; + break; + case WAIT_TRAIN: + pending_train = &train.get_layout().get_train(row.get_param(0)); + pending_block = &parse_location(row.get_param(1)); + executing = false; + break; + case ARRIVE: + executing = false; + break; + case SPEED: + train.set_control("speed", row.get_param(0)/3.6*train.get_layout().get_catalogue().get_scale()); + break; + case REVERSE: + train.set_control("reverse", !train.get_control("reverse")); + break; + case ROUTE: + if(!train.set_route(&train.get_layout().get_route(row.get_param(0)))) + set_enabled(false); + break; + } + + if(executing) + current_row = (current_row+1)%rows.size(); + } +} + +void Timetable::save(list &st) const +{ + for(vector::const_iterator i=rows.begin(); i!=rows.end(); ++i) + st.push_back(i->save()); +} + +Block &Timetable::parse_location(const string &loc) +{ + if(!loc.compare(0, 7, "sensor ")) + return train.get_layout().get_block(lexical_cast(loc.substr(7))|0x1000); + throw Exception("Named blocks are not supported yet"); +} + +void Timetable::sensor_event(unsigned addr, bool state) +{ + if(pending_block && pending_block->get_train()==pending_train && addr==pending_block->get_sensor_id() && state) + { + pending_block = 0; + current_row = (current_row+1)%rows.size(); + executing = true; + } +} + +void Timetable::train_arrived() +{ + Row &row = rows[current_row]; + if(row.type==ARRIVE) + { + current_row = (current_row+1)%rows.size(); + executing = true; + } +} + + +Timetable::Row::Row(RowType t): + type(t) +{ } + +template +Timetable::Row::Row(RowType t, const T &p): + type(t) +{ + params.push_back(p); +} + +template +const T &Timetable::Row::get_param(unsigned i) const +{ + if(i>=params.size()) + throw InvalidParameterValue("Parameter index out of range"); + return params[i].value(); +} + +string Timetable::Row::str() const +{ + switch(type) + { + case GOTO: + return "set route to "+get_param(0); + case TRAVEL: + return "travel to "+get_param(0); + case WAIT_TIME: + return format("wait for %d seconds", get_param(0)); + case WAIT_TRAIN: + return format("wait for train %d at %s", get_param(0), get_param(1)); + case ARRIVE: + return "travel until arrival"; + case SPEED: + return format("set speed %d km/h", get_param(0)); + case REVERSE: + return "reverse"; + case ROUTE: + return "set route "+get_param(0); + default: + return "invalid row"; + } +} + +DataFile::Statement Timetable::Row::save() const +{ + switch(type) + { + case GOTO: + return DataFile::Statement("goto"), get_param(0); + case TRAVEL: + return DataFile::Statement("travel"), get_param(0); + case WAIT_TIME: + return DataFile::Statement("wait"), get_param(0); + case WAIT_TRAIN: + return DataFile::Statement("wait_train"), get_param(0), get_param(1); + case ARRIVE: + return DataFile::Statement("arrive"); + case SPEED: + return DataFile::Statement("speed"), get_param(0); + case REVERSE: + return DataFile::Statement("reverse"); + case ROUTE: + return DataFile::Statement("route"), get_param(0); + default: + return DataFile::Statement(); + } +} + +Timetable::Row Timetable::Row::parse(const string &s) +{ + if(!s.compare(0, 7, "travel ")) + { + if(!s.compare(7, 3, "to ")) + return Row(TRAVEL, s.substr(10)); + else if(!s.compare(7, string::npos, "until arrival")) + return Row(ARRIVE); + } + else if(!s.compare(0, 9, "wait for ")) + { + if(isdigit(s[9])) + { + unsigned nondigit = 10; + while(nondigit(s.substr(9, nondigit-9))); + } + else if(!s.compare(9, 6, "train ")) + { + string::size_type at = s.find(" at ", 15); + if(at!=string::npos) + { + Row row(WAIT_TRAIN, lexical_cast(s.substr(15, at-15))); + row.params.push_back(s.substr(at+4)); + return row; + } + } + } + else if(!s.compare(0, 10, "set speed ")) + { + unsigned nondigit = 11; + while(nondigit(s.substr(10, nondigit-10))); + } + else if(s=="reverse") + return Row(REVERSE); + else if(!s.compare(0, 10, "set route ")) + { + if(!s.compare(10, 3, "to ")) + return Row(GOTO, s.substr(13)); + return Row(ROUTE, s.substr(10)); + } + + throw InvalidParameterValue("Invalid row"); +} + + +Timetable::Loader::Loader(Timetable &tt): + DataFile::ObjectLoader(tt) +{ + add("arrive", &Loader::arrive); + add("goto", &Loader::go_to); + add("route", &Loader::route); + add("speed", &Loader::speed); + add("reverse", &Loader::reverse); + add("travel", &Loader::travel); + add("wait", &Loader::wait); + add("wait_train", &Loader::wait_train); +} + +void Timetable::Loader::arrive() +{ + obj.rows.push_back(Row(ARRIVE)); +} + +void Timetable::Loader::go_to(const string &t) +{ + obj.rows.push_back(Row(GOTO, t)); +} + +void Timetable::Loader::route(const string &r) +{ + obj.rows.push_back(Row(ROUTE, r)); +} + +void Timetable::Loader::reverse() +{ + obj.rows.push_back(Row(REVERSE)); +} + +void Timetable::Loader::speed(unsigned s) +{ + obj.rows.push_back(Row(SPEED, s)); +} + +void Timetable::Loader::travel(const string &t) +{ + obj.rows.push_back(Row(TRAVEL, t)); +} + +void Timetable::Loader::wait(unsigned t) +{ + obj.rows.push_back(Row(WAIT_TIME, t)); +} + +void Timetable::Loader::wait_train(unsigned t, const string &b) +{ + Row row(WAIT_TRAIN, t); + row.params.push_back(b); + obj.rows.push_back(row); +} + +} // namespace R2C2 diff --git a/source/libr2c2/timetable.h b/source/libr2c2/timetable.h new file mode 100644 index 0000000..9cfda68 --- /dev/null +++ b/source/libr2c2/timetable.h @@ -0,0 +1,105 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#ifndef LIBR2C2_TIMETABLE_H_ +#define LIBR2C2_TIMETABLE_H_ + +#include +#include +#include +#include +#include + +namespace R2C2 { + +class Block; +class Train; + +class Timetable: public sigc::trackable +{ +public: + class Loader: public Msp::DataFile::ObjectLoader + { + public: + Loader(Timetable &); + private: + void arrive(); + void go_to(const std::string &); + void route(const std::string &); + void reverse(); + void speed(unsigned); + void travel(const std::string &); + void wait(unsigned); + void wait_train(unsigned, const std::string &); + }; + + enum RowType + { + GOTO, + TRAVEL, + WAIT_TIME, + WAIT_TRAIN, + ARRIVE, + SPEED, + REVERSE, + ROUTE + }; + + struct Row + { + RowType type; + std::vector params; + + Row(RowType); + + template + Row(RowType, const T &); + + template + const T &get_param(unsigned) const; + + std::string str() const; + + Msp::DataFile::Statement save() const; + + static Row parse(const std::string &); + }; + +private: + Train &train; + bool enabled; + std::vector rows; + unsigned current_row; + bool executing; + Block *pending_block; + Train *pending_train; + Msp::Time::TimeStamp wait_timeout; + +public: + Timetable(Train &); + + void set_enabled(bool); + bool is_enabled() const { return enabled; } + void reset(); + + void clear(); + void append(const Row &); + void insert(unsigned, const Row &); + unsigned get_n_rows() const { return rows.size(); } + const Row &get_row(unsigned) const; + + void tick(const Msp::Time::TimeStamp &); + void save(std::list &) const; +private: + Block &parse_location(const std::string &); + void sensor_event(unsigned, bool); + void train_arrived(); +}; + +} // namespace R2C2 + +#endif diff --git a/source/libr2c2/track.cpp b/source/libr2c2/track.cpp new file mode 100644 index 0000000..0592731 --- /dev/null +++ b/source/libr2c2/track.cpp @@ -0,0 +1,392 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#include +#include "block.h" +#include "catalogue.h" +#include "driver.h" +#include "layout.h" +#include "track.h" +#include "tracktype.h" + +using namespace std; +using namespace Msp; + +namespace R2C2 { + +Track::Track(Layout &l, const TrackType &t): + layout(l), + type(t), + block(0), + rot(0), + slope(0), + flex(false), + turnout_id(type.is_turnout() ? layout.allocate_turnout_id(type.is_double_address()) : 0), + sensor_id(0), + links(type.get_endpoints().size()), + active_path(0) +{ + layout.add_track(*this); + + if(layout.has_driver()) + layout.get_driver().signal_turnout.connect(sigc::mem_fun(this, &Track::turnout_event)); + + for(unsigned paths = type.get_paths(); !(paths&1); ++active_path, paths>>=1) ; +} + +Track::~Track() +{ + break_links(); + layout.remove_track(*this); +} + +void Track::set_block(Block *b) +{ + if(b && !b->has_track(*this)) + throw InvalidParameterValue("Track is not in the Block"); + if(!b && block && block->has_track(*this)) + throw InvalidState("Track is still in a Block"); + + block = b; +} + +Block &Track::get_block() const +{ + if(!block) + throw InvalidState("No Block"); + + return *block; +} + +void Track::set_position(const Point &p) +{ + pos = p; +} + +void Track::set_rotation(float r) +{ + rot = r; + while(rot<0) + rot += M_PI*2; + while(rot>M_PI*2) + rot -= M_PI*2; +} + +void Track::set_slope(float s) +{ + if(links.size()!=2) + return; + + slope = s; +} + +void Track::set_flex(bool f) +{ + flex = f; +} + +void Track::check_slope() +{ + if(links.size()!=2) + return; + + if(links[0] && links[1]) + { + Point epp0 = links[0]->get_endpoint_position(links[0]->get_endpoint_by_link(*this)); + Point epp1 = links[1]->get_endpoint_position(links[1]->get_endpoint_by_link(*this)); + pos.z = epp0.z; + slope = epp1.z-pos.z; + } + else + { + slope = 0; + if(links[0]) + { + Point epp = links[0]->get_endpoint_position(links[0]->get_endpoint_by_link(*this)); + pos.z = epp.z; + } + else if(links[1]) + { + Point epp = links[1]->get_endpoint_position(links[1]->get_endpoint_by_link(*this)); + pos.z = epp.z; + } + } +} + +void Track::set_turnout_id(unsigned i) +{ + if(!type.is_turnout()) + throw InvalidState("Not a turnout"); + + turnout_id = i; + layout.create_blocks(*this); + layout.update_routes(); + if(layout.has_driver() && turnout_id) + { + layout.get_driver().add_turnout(turnout_id); + if(type.is_double_address()) + layout.get_driver().add_turnout(turnout_id+1); + } +} + +void Track::set_sensor_id(unsigned i) +{ + if(type.is_turnout()) + throw InvalidState("Can't set sensor on a turnout"); + + sensor_id = i; + layout.create_blocks(*this); + if(layout.has_driver() && sensor_id) + layout.get_driver().add_sensor(sensor_id); +} + +void Track::set_active_path(unsigned p) +{ + if(!turnout_id) + throw InvalidState("Not a turnout"); + if(!(type.get_paths()&(1<2) + active_path = (active_path&1) | (p&2); +} + +int Track::get_endpoint_by_link(Track &other) const +{ + for(unsigned i=0; i &eps = type.get_endpoints(); + if(epi>=eps.size()) + throw InvalidParameterValue("TrackType::Endpoint index out of range"); + + const TrackType::Endpoint &ep = eps[epi]; + + float c = cos(rot); + float s = sin(rot); + + Point p(pos.x+c*ep.pos.x-s*ep.pos.y, pos.y+s*ep.pos.x+c*ep.pos.y, pos.z); + if(eps.size()==2 && epi==1) + p.z += slope; + return p; +} + +float Track::get_endpoint_direction(unsigned epi) const +{ + const vector &eps = type.get_endpoints(); + if(epi>=eps.size()) + throw InvalidParameterValue("TrackType::Endpoint index out of range"); + + const TrackType::Endpoint &ep = eps[epi]; + + return rot+ep.dir; +} + +bool Track::snap_to(Track &other, bool link, float limit) +{ + if(!limit || link) + { + limit = layout.get_catalogue().get_gauge(); + if(link && !flex && !other.get_flex()) + limit /= 10; + } + limit *= limit; + + const vector &eps = type.get_endpoints(); + const vector &other_eps = other.get_type().get_endpoints(); + + for(unsigned i=0; i &eps = type.get_endpoints(); + + for(unsigned i=0; i::iterator i=links.begin(); i!=links.end(); ++i) + if(*i==&trk) + { + *i = 0; + trk.break_link(*this); + // XXX Creates the blocks twice + layout.create_blocks(*this); + return; + } +} + +void Track::break_links() +{ + for(vector::iterator i=links.begin(); i!=links.end(); ++i) + if(Track *trk=*i) + { + *i = 0; + trk->break_link(*this); + } +} + +Track *Track::get_link(unsigned i) const +{ + if(i>links.size()) + throw InvalidParameterValue("Link index out of range"); + + return links[i]; +} + +TrackPoint Track::get_point(unsigned epi, unsigned path, float d) const +{ + TrackPoint p = type.get_point(epi, path, d); + float c = cos(rot); + float s = sin(rot); + + p.pos = Point(pos.x+c*p.pos.x-s*p.pos.y, pos.y+s*p.pos.x+c*p.pos.y, pos.z); + p.dir += rot; + if(type.get_endpoints().size()==2) + { + float len = type.get_path_length(path); + float grade = slope/len; + if(epi==0) + { + p.pos.z += grade*d; + p.grade = grade; + } + else + { + p.pos.z += slope-grade*d; + p.grade = -grade; + } + } + + return p; +} + +TrackPoint Track::get_point(unsigned epi, float d) const +{ + return get_point(epi, active_path, d); +} + +void Track::save(list &st) const +{ + st.push_back((DataFile::Statement("position"), pos.x, pos.y, pos.z)); + st.push_back((DataFile::Statement("rotation"), rot)); + st.push_back((DataFile::Statement("slope"), slope)); + if(turnout_id) + st.push_back((DataFile::Statement("turnout_id"), turnout_id)); + if(sensor_id) + st.push_back((DataFile::Statement("sensor_id"), sensor_id)); + if(flex) + st.push_back((DataFile::Statement("flex"), true)); +} + +void Track::turnout_event(unsigned addr, bool state) +{ + if(!turnout_id) + return; + + if(addr==turnout_id) + active_path = (active_path&2) | (state ? 1 : 0); + else if(type.is_double_address() && addr==turnout_id+1) + active_path = (active_path&1) | (state ? 2 : 0); + else + return; + + signal_path_changed.emit(active_path); +} + + +Track::Loader::Loader(Track &t): + DataFile::BasicLoader(t) +{ + add("position", &Loader::position); + add("rotation", &Track::rot); + add("slope", &Track::slope); + add("turnout_id", &Loader::turnout_id); + add("sensor_id", &Loader::sensor_id); + add("flex", &Track::flex); +} + +void Track::Loader::position(float x, float y, float z) +{ + obj.pos = Point(x, y, z); +} + +void Track::Loader::sensor_id(unsigned id) +{ + obj.set_sensor_id(id); +} + +void Track::Loader::turnout_id(unsigned id) +{ + obj.set_turnout_id(id); +} + +} // namespace R2C2 diff --git a/source/libr2c2/track.h b/source/libr2c2/track.h new file mode 100644 index 0000000..95f9023 --- /dev/null +++ b/source/libr2c2/track.h @@ -0,0 +1,98 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#ifndef LIBR2C2_TRACK_H_ +#define LIBR2C2_TRACK_H_ + +#include +#include +#include +#include +#include "geometry.h" + +namespace R2C2 { + +class Block; +class Layout; +class TrackType; + +class Track: public sigc::trackable +{ +public: + class Loader: public Msp::DataFile::BasicLoader + { + public: + Loader(Track &); + private: + void position(float, float, float); + void sensor_id(unsigned); + void turnout_id(unsigned); + }; + + sigc::signal signal_path_changed; + +private: + Layout &layout; + const TrackType &type; + Block *block; + Point pos; + float rot; + float slope; + bool flex; + unsigned turnout_id; + unsigned sensor_id; + std::vector links; + unsigned active_path; + + Track(const Track &); + Track &operator=(const Track &); +public: + Track(Layout &, const TrackType &); + ~Track(); + + Layout &get_layout() const { return layout; } + const TrackType &get_type() const { return type; } + + void set_block(Block *); + Block &get_block() const; + void set_position(const Point &); + void set_rotation(float); + void set_slope(float); + void set_flex(bool); + const Point &get_position() const { return pos; } + float get_rotation() const { return rot; } + float get_slope() const { return slope; } + bool get_flex() const { return flex; } + void check_slope(); + + void set_turnout_id(unsigned); + void set_sensor_id(unsigned); + unsigned get_turnout_id() const { return turnout_id; } + unsigned get_sensor_id() const { return sensor_id; } + void set_active_path(unsigned); + unsigned get_active_path() const { return active_path; } + + int get_endpoint_by_link(Track &) const; + Point get_endpoint_position(unsigned) const; + float get_endpoint_direction(unsigned) const; + bool snap_to(Track &, bool, float = 0); + bool snap(Point &, float &) const; + void break_link(Track &); + void break_links(); + const std::vector &get_links() const { return links; } + Track *get_link(unsigned) const; + TrackPoint get_point(unsigned, unsigned, float) const; + TrackPoint get_point(unsigned, float) const; + + void save(std::list &) const; +private: + void turnout_event(unsigned, bool); +}; + +} // namespace R2C2 + +#endif diff --git a/source/libr2c2/trackiter.cpp b/source/libr2c2/trackiter.cpp new file mode 100644 index 0000000..3c6295b --- /dev/null +++ b/source/libr2c2/trackiter.cpp @@ -0,0 +1,171 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#include +#include +#include "track.h" +#include "trackiter.h" +#include "tracktype.h" + +using namespace std; +using namespace Msp; + +namespace R2C2 { + +TrackIter::TrackIter(): + _track(0), + _entry(0) +{ } + +TrackIter::TrackIter(Track *t, unsigned e): + _track(t), + _entry(t ? e : 0) +{ + if(_track && _entry>_track->get_type().get_endpoints().size()) + throw InvalidParameterValue("Endpoint index not valid for track"); +} + +const TrackType::Endpoint &TrackIter::endpoint() const +{ + if(!_track) + throw InvalidState("TrackIter is null"); + + return _track->get_type().get_endpoint(_entry); +} + +int TrackIter::get_exit(unsigned path) const +{ + const vector &eps = _track->get_type().get_endpoints(); + + // Find an endpoint that's connected to the entry and has the requested path + for(unsigned i=0; iget_active_path()); +} + +TrackIter TrackIter::next(unsigned path) const +{ + if(!_track) + return TrackIter(); + + int exit = get_exit(path); + if(exit<0) + return TrackIter(); + + TrackIter result; + result._track = _track->get_link(exit); + result._entry = (result._track ? result._track->get_endpoint_by_link(*_track) : 0); + + return result; +} + +TrackIter TrackIter::reverse() const +{ + if(!_track) + return TrackIter(); + + return reverse(_track->get_active_path()); +} + +TrackIter TrackIter::reverse(unsigned path) const +{ + if(!_track) + return TrackIter(); + + int exit = get_exit(path); + if(exit<0) + return TrackIter(); + + return TrackIter(_track, exit); +} + +TrackIter TrackIter::flip() const +{ + if(!_track) + return TrackIter(); + + TrackIter result; + result._track = _track->get_link(_entry); + result._entry = (result._track ? result._track->get_endpoint_by_link(*_track) : 0); + + return result; +} + +Track &TrackIter::operator*() const +{ + if(!_track) + throw InvalidState("TrackIter is null"); + + return *_track; +} + +bool TrackIter::operator==(const TrackIter &other) const +{ + return _track==other._track && _entry==other._entry; +} + + +TrackLoopIter::TrackLoopIter(): + _looped(false) +{ } + +TrackLoopIter::TrackLoopIter(Track *t, unsigned e): + TrackIter(t, e), + _visited(new TrackList()), + _last(_visited->insert(_visited->end(), track())), + _looped(false) +{ } + +TrackLoopIter::TrackLoopIter(const TrackIter &i): + TrackIter(i), + _visited(new TrackList()), + _last(_visited->insert(_visited->end(), track())), + _looped(false) +{ } + +TrackLoopIter::TrackLoopIter(const TrackIter &i, RefPtr v, const TrackList::iterator &l): + TrackIter(i), + _looped(false) +{ + if(track()) + { + _visited = v; + _last = l; + _looped = (_visited && find(_visited->begin(), _last, track())!=_last); + + ++_last; + if(_last!=_visited->end()) + { + _visited = new TrackList(_visited->begin(), _last); + _last = _visited->end(); + } + _visited->push_back(track()); + --_last; + } +} + +TrackLoopIter TrackLoopIter::next() const +{ + return TrackLoopIter(TrackIter::next(), _visited, _last); +} + +TrackLoopIter TrackLoopIter::next(unsigned path) const +{ + return TrackLoopIter(TrackIter::next(path), _visited, _last); +} + +} // namespace R2C2 diff --git a/source/libr2c2/trackiter.h b/source/libr2c2/trackiter.h new file mode 100644 index 0000000..1dce02a --- /dev/null +++ b/source/libr2c2/trackiter.h @@ -0,0 +1,85 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#ifndef LIBR2C2_TRACKITER_H_ +#define LIBR2C2_TRACKITER_H_ + +#include +#include +#include "tracktype.h" + +namespace R2C2 { + +class Track; + +/** +An iterator for traversing tracks. +*/ +class TrackIter +{ +private: + Track *_track; + unsigned _entry; + +public: + TrackIter(); + TrackIter(Track *, unsigned); + + Track *track() const { return _track; } + unsigned entry() const { return _entry; } + const TrackType::Endpoint &endpoint() const; + +private: + int get_exit(unsigned) const; +public: + TrackIter next() const; + TrackIter next(unsigned) const; + TrackIter reverse() const; + TrackIter reverse(unsigned) const; + TrackIter flip() const; + + Track &operator*() const; + Track *operator->() const { return _track; } + bool operator==(const TrackIter &) const; + bool operator!=(const TrackIter &other) const { return !(*this==other); } + operator bool() const { return _track!=0; } +}; + + +/** +A track iterator that detects looping. + +A list of visited tracks is maintained internally to the iterator. This list +is shared between iterators as long as next() is only called once per iterator. +Subsequent calls to next() cause the head of the list to be copied. +*/ +class TrackLoopIter: public TrackIter +{ +private: + typedef std::list TrackList; + + Msp::RefPtr _visited; + TrackList::iterator _last; + bool _looped; + +public: + TrackLoopIter(); + TrackLoopIter(Track *, unsigned); + TrackLoopIter(const TrackIter &); +private: + TrackLoopIter(const TrackIter &, Msp::RefPtr, const TrackList::iterator &); + +public: + bool looped() const { return _looped; } + + TrackLoopIter next() const; + TrackLoopIter next(unsigned) const; +}; + +} // namespace R2C2 + +#endif diff --git a/source/libr2c2/trackpart.cpp b/source/libr2c2/trackpart.cpp new file mode 100644 index 0000000..af2cf37 --- /dev/null +++ b/source/libr2c2/trackpart.cpp @@ -0,0 +1,127 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#include +#include "trackpart.h" + +using namespace std; +using namespace Msp; + +namespace R2C2 { + +TrackPart::TrackPart(): + dir(0), + length(0), + radius(0), + path(0), + dead_end(false) +{ + links[0] = 0; + links[1] = 0; +} + +float TrackPart::get_length() const +{ + if(radius) + return abs(radius)*length; + else + return length; +} + +TrackPoint TrackPart::get_point(float d) const +{ + TrackPoint result; + + if(radius) + { + float a = d/radius; + float c = cos(a); + float s = sin(a); + float rx = radius*sin(dir); + float ry = -radius*cos(dir); + result.pos = Point(pos.x+c*rx-s*ry-rx, pos.y+c*ry+s*rx-ry); + result.dir = dir+a; + } + else + { + result.pos = Point(pos.x+cos(dir)*d, pos.y+sin(dir)*d); + result.dir = dir; + } + + return result; +} + +void TrackPart::check_link(TrackPart &other) +{ + unsigned n_eps = (dead_end ? 1 : 2); + unsigned n_other_eps = (other.is_dead_end() ? 1 : 2); + for(unsigned i=0; iM_PI) + da -= M_PI*2; + while(da<-M_PI) + da += M_PI*2; + + if(dx*dx+dy*dy<1e-6 && da>=-0.01 && da<=0.01) + { + links[i] = &other; + other.links[j] = this; + return; + } + } + } +} + +TrackPart *TrackPart::get_link(unsigned i) const +{ + if(i>=2) + throw InvalidParameterValue("Index out of range"); + return links[i]; +} + + +TrackPart::Loader::Loader(TrackPart &p): + Msp::DataFile::BasicLoader(p) +{ + add("start", &Loader::start); + add("length", &TrackPart::length); + add("radius", &TrackPart::radius); + add("path", &TrackPart::path); + add("dead_end", &TrackPart::dead_end); +} + +void TrackPart::Loader::finish() +{ + if(obj.radius) + { + obj.length *= M_PI/180; + obj.radius /= 1000; + } + else + obj.length /= 1000; + + obj.pos.x /= 1000; + obj.pos.y /= 1000; + obj.dir *= M_PI/180; +} + +void TrackPart::Loader::start(float x, float y, float d) +{ + obj.pos = Point(x, y); + obj.dir = d; +} + +} // namespace R2C2 diff --git a/source/libr2c2/trackpart.h b/source/libr2c2/trackpart.h new file mode 100644 index 0000000..0a07b4d --- /dev/null +++ b/source/libr2c2/trackpart.h @@ -0,0 +1,51 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#ifndef LIBR2C2_TRACKPART_H_ +#define LIBR2C2_TRACKPART_H_ + +#include +#include "geometry.h" + +namespace R2C2 { + +class TrackPart +{ +public: + class Loader: public Msp::DataFile::BasicLoader + { + public: + Loader(TrackPart &); + private: + virtual void finish(); + void start(float, float, float); + }; + +private: + Point pos; + float dir; + float length; + float radius; + unsigned path; + bool dead_end; + TrackPart *links[2]; + +public: + TrackPart(); + + float get_length() const; + bool is_curved() const { return radius; } + TrackPoint get_point(float) const; + unsigned get_path() const { return path; } + bool is_dead_end() const { return dead_end; } + void check_link(TrackPart &); + TrackPart *get_link(unsigned) const; +}; + +} // namespace R2C2 + +#endif diff --git a/source/libr2c2/tracktype.cpp b/source/libr2c2/tracktype.cpp new file mode 100644 index 0000000..4ac0967 --- /dev/null +++ b/source/libr2c2/tracktype.cpp @@ -0,0 +1,194 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#include +#include "tracktype.h" + +using namespace std; +using namespace Msp; + +namespace R2C2 { + +TrackType::TrackType(const ArticleNumber &an): + art_nr(an), + double_address(false), + autofit_preference(1) +{ } + +float TrackType::get_total_length() const +{ + return get_path_length(-1); +} + +float TrackType::get_path_length(int p) const +{ + float len = 0; + for(vector::const_iterator i=parts.begin(); i!=parts.end(); ++i) + if(p<0 || i->get_path()==static_cast(p)) + len += i->get_length(); + return len; +} + +unsigned TrackType::get_paths() const +{ + unsigned mask = 0; + for(vector::const_iterator i=parts.begin(); i!=parts.end(); ++i) + mask |= 1<get_path(); + return mask; +} + +unsigned TrackType::get_n_paths() const +{ + unsigned n = 0; + for(unsigned mask = get_paths(); mask; ++n) + mask &= mask-1; + return n; +} + +bool TrackType::is_turnout() const +{ + return endpoints.size()>2; +} + +bool TrackType::is_dead_end() const +{ + return endpoints.size()<2; +} + +const TrackType::Endpoint &TrackType::get_endpoint(unsigned i) const +{ + if(i>=endpoints.size()) + throw InvalidParameterValue("Endpoint index out of range"); + + return endpoints[i]; +} + +TrackPoint TrackType::get_point(unsigned epi, unsigned path, float d) const +{ + if(epi>=endpoints.size()) + throw InvalidParameterValue("Endpoint index out of range"); + + const TrackPart *part = 0; + unsigned part_ep = 0; + for(vector::const_iterator i=parts.begin(); i!=parts.end(); ++i) + { + if((endpoints[epi].paths&(1<get_path()!=path) + continue; + + unsigned n_part_eps = (i->is_dead_end() ? 1 : 2); + for(unsigned j=0; jget_point(j ? i->get_length() : 0); + float dx = p.pos.x-endpoints[epi].pos.x; + float dy = p.pos.y-endpoints[epi].pos.y; + if(dx*dx+dy*dy<1e-6) + { + part = &*i; + part_ep = j; + } + } + } + + if(!part) + throw Exception("Internal error (endpoint does not match any part)"); + + while(1) + { + float plen = part->get_length(); + if(d<=plen) + { + if(part_ep==1) + d = plen-d; + TrackPoint p = part->get_point(d); + if(part_ep==1) + p.dir += M_PI; + return p; + } + else + { + d -= plen; + TrackPart *next = part->get_link(1-part_ep); + if(!next) + throw InvalidParameterValue("Distance out of range"); + part_ep = (next->get_link(0)==part ? 0 : 1); + part = next; + } + } +} + +void TrackType::collect_endpoints() +{ + endpoints.clear(); + + for(vector::iterator i=parts.begin(); i!=parts.end(); ++i) + { + for(vector::iterator j=i; ++j!=parts.end();) + i->check_link(*j); + + unsigned n_part_eps = (i->is_dead_end() ? 1 : 2); + for(unsigned j=0; jget_link(j)) + { + TrackPoint p = i->get_point(j ? i->get_length() : 0); + if(j==0) + p.dir += M_PI; + + bool found = false; + for(vector::iterator k=endpoints.begin(); k!=endpoints.end(); ++k) + { + float dx = k->pos.x-p.pos.x; + float dy = k->pos.y-p.pos.y; + + float da = k->dir-p.dir; + while(da>M_PI) + da -= M_PI*2; + while(da<-M_PI) + da += M_PI*2; + + if(dx*dx+dy*dy<1e-6 && da>-0.01 && da<0.01) + { + k->paths |= 1<get_path(); + found = true; + break; + } + } + + if(!found) + endpoints.push_back(Endpoint(p.pos.x, p.pos.y, p.dir, 1<get_path())); + } + } +} + +TrackType::Endpoint::Endpoint(float x, float y, float d, unsigned p): + pos(x, y), + dir(d), + paths(p) +{ } + + +TrackType::Loader::Loader(TrackType &t): + Msp::DataFile::BasicLoader(t) +{ + add("autofit_preference", &TrackType::autofit_preference); + add("description", &TrackType::description); + add("double_address", &TrackType::double_address); + add("part", &Loader::part); +} + +void TrackType::Loader::finish() +{ + obj.collect_endpoints(); +} + +void TrackType::Loader::part() +{ + TrackPart p; + load_sub(p); + obj.parts.push_back(p); +} + +} // namespace R2C2 diff --git a/source/libr2c2/tracktype.h b/source/libr2c2/tracktype.h new file mode 100644 index 0000000..d38f1b2 --- /dev/null +++ b/source/libr2c2/tracktype.h @@ -0,0 +1,72 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#ifndef LIBR2C2_TRACKTYPE_H_ +#define LIBR2C2_TRACKTYPE_H_ + +#include +#include "articlenumber.h" +#include "geometry.h" +#include "trackpart.h" + +namespace R2C2 { + +class TrackType +{ +public: + struct Endpoint + { + Point pos; + float dir; // Direction outwards from the endpoint + unsigned paths; + + Endpoint(float, float, float, unsigned); + }; + + class Loader: public Msp::DataFile::BasicLoader + { + public: + Loader(TrackType &); + private: + virtual void finish(); + void part(); + void position(float, float, float); + }; + +private: + ArticleNumber art_nr; + std::string description; + std::vector parts; + std::vector endpoints; + bool double_address; + unsigned autofit_preference; + +public: + TrackType(const ArticleNumber &); + + const ArticleNumber &get_article_number() const { return art_nr; } + const std::string &get_description() const { return description; } + float get_total_length() const; + float get_path_length(int) const; + unsigned get_paths() const; + unsigned get_n_paths() const; + bool is_turnout() const; + bool is_dead_end() const; + bool is_double_address() const { return double_address; } + unsigned get_autofit_preference() const { return autofit_preference; } + const std::vector &get_parts() const { return parts; } + const std::vector &get_endpoints() const { return endpoints; } + const Endpoint &get_endpoint(unsigned) const; + TrackPoint get_point(unsigned, unsigned, float) const; + +private: + void collect_endpoints(); +}; + +} // namespace R2C2 + +#endif diff --git a/source/libr2c2/train.cpp b/source/libr2c2/train.cpp new file mode 100644 index 0000000..dd7139f --- /dev/null +++ b/source/libr2c2/train.cpp @@ -0,0 +1,1420 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#include +#include +#include +#include +#include "aicontrol.h" +#include "catalogue.h" +#include "driver.h" +#include "layout.h" +#include "route.h" +#include "simplecontroller.h" +#include "timetable.h" +#include "trackiter.h" +#include "tracktype.h" +#include "train.h" +#include "vehicle.h" +#include "vehicletype.h" + +using namespace std; +using namespace Msp; + +namespace { + +struct SetFlag +{ + bool &flag; + + SetFlag(bool &f): flag(f) { flag = true; } + ~SetFlag() { flag = false; } +}; + +} + + +namespace R2C2 { + +Train::Train(Layout &l, const VehicleType &t, unsigned a, const string &p): + layout(l), + loco_type(t), + address(a), + protocol(p), + priority(0), + yielding_to(0), + cur_blocks_end(blocks.end()), + clear_blocks_end(blocks.end()), + pending_block(0), + reserving(false), + advancing(false), + controller(new AIControl(*this, new SimpleController)), + timetable(0), + active(false), + current_speed_step(0), + speed_changing(false), + reverse(false), + functions(0), + end_of_route(false), + status("Unplaced"), + travel_dist(0), + pure_speed(false), + real_speed(layout.get_driver().get_protocol_speed_steps(protocol)+1), + accurate_position(false), + overshoot_dist(false) +{ + if(!loco_type.is_locomotive()) + throw InvalidParameterValue("Initial vehicle must be a locomotive"); + + vehicles.push_back(new Vehicle(layout, loco_type)); + + layout.add_train(*this); + + layout.get_driver().add_loco(address, protocol); + layout.get_driver().signal_loco_speed.connect(sigc::mem_fun(this, &Train::loco_speed_event)); + layout.get_driver().signal_loco_function.connect(sigc::mem_fun(this, &Train::loco_func_event)); + + layout.signal_block_reserved.connect(sigc::mem_fun(this, &Train::block_reserved)); + layout.get_driver().signal_sensor.connect(sigc::mem_fun(this, &Train::sensor_event)); + + layout.get_driver().signal_halt.connect(sigc::mem_fun(this, &Train::halt_event)); + + const set &tracks = layout.get_tracks(); + for(set::const_iterator i=tracks.begin(); i!=tracks.end(); ++i) + if((*i)->get_turnout_id()) + (*i)->signal_path_changed.connect(sigc::hide(sigc::bind(sigc::mem_fun(this, &Train::turnout_path_changed), sigc::ref(**i)))); + + controller->signal_control_changed.connect(sigc::mem_fun(this, &Train::control_changed)); +} + +Train::~Train() +{ + delete controller; + delete timetable; + for(vector::iterator i=vehicles.begin(); i!=vehicles.end(); ++i) + delete *i; + layout.remove_train(*this); +} + +void Train::set_name(const string &n) +{ + name = n; + + signal_name_changed.emit(name); +} + +void Train::set_priority(int p) +{ + priority = p; +} + +void Train::yield_to(const Train &t) +{ + yielding_to = &t; +} + +void Train::add_vehicle(const VehicleType &vt) +{ + Vehicle *veh = new Vehicle(layout, vt); + vehicles.back()->attach_back(*veh); + vehicles.push_back(veh); +} + +void Train::remove_vehicle(unsigned i) +{ + if(i>=vehicles.size()) + throw InvalidParameterValue("Vehicle index out of range"); + if(i==0) + throw InvalidParameterValue("Can't remove the locomotive"); + delete vehicles[i]; + vehicles.erase(vehicles.begin()+i); + if(iattach_back(*vehicles[i]); +} + +unsigned Train::get_n_vehicles() const +{ + return vehicles.size(); +} + +Vehicle &Train::get_vehicle(unsigned i) +{ + if(i>=vehicles.size()) + throw InvalidParameterValue("Vehicle index out of range"); + return *vehicles[i]; +} + +const Vehicle &Train::get_vehicle(unsigned i) const +{ + if(i>=vehicles.size()) + throw InvalidParameterValue("Vehicle index out of range"); + return *vehicles[i]; +} + +void Train::set_control(const string &n, float v) +{ + controller->set_control(n, v); +} + +void Train::set_active(bool a) +{ + if(a==active) + return; + if(!a && controller->get_speed()) + throw InvalidState("Can't deactivate while moving"); + + active = a; + if(active) + { + stop_timeout = Time::TimeStamp(); + reserve_more(); + } + else + { + stop_timeout = Time::now()+2*Time::sec; + set_status("Stopped"); + } +} + +void Train::set_function(unsigned func, bool state) +{ + if(!loco_type.get_functions().count(func)) + throw InvalidParameterValue("Invalid function"); + if(func<5) + layout.get_driver().set_loco_function(address, func, state); + else + layout.get_driver().set_loco_function(address+1, func-4, state); +} + +float Train::get_control(const string &ctrl) const +{ + return controller->get_control(ctrl).value; +} + +float Train::get_speed() const +{ + return controller->get_speed(); +} + +bool Train::get_function(unsigned func) const +{ + return (functions>>func)&1; +} + +void Train::set_timetable(Timetable *tt) +{ + delete timetable; + timetable = tt; +} + +bool Train::set_route(const Route *r) +{ + free_noncritical_blocks(); + + Route *lead = 0; + if(r && !blocks.empty()) + { + TrackIter first = blocks.front().track_iter(); + TrackIter next = blocks.back().next().track_iter(); + if(!r->has_track(*next)) + { + lead = Route::find(next, *r); + if(!lead) + return false; + create_lead_route(lead, lead); + routes.push_front(lead); + } + else if(!r->has_track(*first)) + lead = create_lead_route(0, r); + } + + routes.clear(); + if(lead) + routes.push_back(lead); + if(r) + routes.push_back(r); + end_of_route = false; + + reserve_more(); + + signal_route_changed.emit(get_route()); + + return true; +} + +bool Train::go_to(Track &to) +{ + for(BlockList::const_iterator i=blocks.begin(); i!=cur_blocks_end; ++i) + if((*i)->has_track(to)) + { + signal_arrived.emit(); + return set_route(0); + } + + free_noncritical_blocks(); + + TrackIter next = blocks.back().next().track_iter(); + + Route *route = Route::find(next, to); + if(!route) + return false; + create_lead_route(route, route); + return set_route(route); +} + +bool Train::divert(Track &from) +{ + if(!from.get_turnout_id()) + throw InvalidParameterValue("Can't divert from a non-turnout"); + if(routes.empty()) + return false; + + unsigned path = 0; + unsigned entry = 0; + list::iterator route = routes.begin(); + + // Follow our routes to find out where we're entering the turnout + for(TrackLoopIter track = blocks.front().track_iter();;) + { + if(!advance_route(route, *track)) + return false; + + if(&*track==&from) + { + Block &block = track->get_block(); + if(block.get_train()==this && !free_block(block)) + return false; + + int route_path = route->route->get_turnout(from.get_turnout_id()); + + // Check that more than one path is available + unsigned ep_paths = track.endpoint().paths; + if(!(ep_paths&(ep_paths-1))) + return false; + + // Choose some other path + for(int i=0; ep_paths>>i; ++i) + if((ep_paths&(1<route->get_path(*track)); + + if(!track || track.looped()) + return false; + } + + TrackIter track = TrackIter(&from, entry).next(path); + if(!track) + return false; + + set tracks; + for(list::iterator i=routes.begin(); i!=routes.end(); ++i) + tracks.insert(i->route->get_tracks().begin(), i->route->get_tracks().end()); + RefPtr diversion = Route::find(track, tracks); + if(!diversion) + return false; + + diversion->set_name("Diversion"); + diversion->add_track(from); + diversion->set_turnout(from.get_turnout_id(), path); + + if(!is_valid_diversion(*diversion, TrackIter(&from, entry))) + return false; + + // Follow the diversion route until we get back to the original route + list::iterator end = routes.end(); + while(1) + { + for(list::iterator i=route; (end==routes.end() && i!=routes.end()); ++i) + if(i->route->has_track(*track)) + end = i; + + if(end!=routes.end()) + break; + else if(!diversion->has_track(*track)) + throw LogicError("Pathfinder returned a bad route"); + + track = track.next(diversion->get_path(*track)); + } + + if(route==end) + // We are rejoining the same route we diverted from, duplicate it + routes.insert(end, *route); + else + { + ++route; + routes.erase(route, end); + } + routes.insert(end, RouteRef(diversion.release(), from.get_turnout_id())); + + return true; +} + +const Route *Train::get_route() const +{ + if(routes.empty()) + return 0; + return routes.front().route; +} + +void Train::place(Block &block, unsigned entry) +{ + if(controller->get_speed()) + throw InvalidState("Must be stopped before placing"); + + release_blocks(); + + set_active(false); + accurate_position = false; + + if(!block.reserve(this)) + { + set_status("Unplaced"); + return; + } + + blocks.push_back(BlockIter(&block, entry)); + if(reverse) + { + TrackIter track = BlockIter(&block, entry).reverse().track_iter(); + vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_BUFFER); + } + else + { + const Block::Endpoint &bep = block.get_endpoint(entry); + vehicles.back()->place(*bep.track, bep.track_ep, 0, Vehicle::BACK_BUFFER); + } +} + +void Train::unplace() +{ + if(controller->get_speed()) + throw InvalidState("Must be stopped before unplacing"); + + release_blocks(); + + set_active(false); + accurate_position = false; + + for(vector::iterator i=vehicles.begin(); i!=vehicles.end(); ++i) + (*i)->unplace(); + + set_status("Unplaced"); +} + +bool Train::free_block(Block &block) +{ + float margin = 10*layout.get_catalogue().get_scale(); + if(get_reserved_distance_until(&block, false)get_braking_distance()*1.3+margin) + return false; + + unsigned nsens = 0; + for(BlockList::iterator i=cur_blocks_end; i!=blocks.end(); ++i) + { + if(i->block()==&block) + { + if(nsens<1) + return false; + release_blocks(i, blocks.end()); + return true; + } + else if((*i)->get_sensor_id()) + ++nsens; + } + + return false; +} + +void Train::free_noncritical_blocks() +{ + if(blocks.empty()) + return; + + if(controller->get_speed()==0) + { + release_blocks(cur_blocks_end, blocks.end()); + return; + } + + float margin = 10*layout.get_catalogue().get_scale(); + float min_dist = controller->get_braking_distance()*1.3+margin; + + Vehicle &veh = *(reverse ? vehicles.back() : vehicles.front()); + + TrackIter track(veh.get_track(), veh.get_entry()); + BlockList::iterator block = blocks.begin(); + bool in_rsv = false; + while(block!=blocks.end() && !(*block)->has_track(*track)) + { + ++block; + if(block==cur_blocks_end) + in_rsv = true; + } + + float dist = veh.get_offset(); + if(reverse) + track.reverse(); + else + dist = track->get_type().get_path_length(track->get_active_path())-dist; + dist -= veh.get_type().get_length()/2; + + bool nsens = 0; + while(1) + { + track = track.next(); + + if(!(*block)->has_track(*track)) + { + ++block; + if(block==cur_blocks_end) + in_rsv = true; + if(block==blocks.end()) + return; + + if(dist>min_dist && nsens>0) + { + release_blocks(block, blocks.end()); + return; + } + + if(in_rsv && (*block)->get_sensor_id()) + ++nsens; + } + + dist += track->get_type().get_path_length(track->get_active_path()); + } +} + +int Train::get_entry_to_block(Block &block) const +{ + for(BlockList::const_iterator i=blocks.begin(); i!=blocks.end(); ++i) + if(i->block()==&block) + return i->entry(); + return -1; +} + +float Train::get_reserved_distance() const +{ + return get_reserved_distance_until(0, false); +} + +void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt) +{ + if(!active && stop_timeout && t>=stop_timeout) + { + release_blocks(cur_blocks_end, blocks.end()); + stop_timeout = Time::TimeStamp(); + } + + Driver &driver = layout.get_driver(); + + if(timetable) + timetable->tick(t); + controller->tick(dt); + float speed = controller->get_speed(); + unsigned speed_step = find_speed_step(speed); + + if(controller->get_reverse()!=reverse) + { + reverse = controller->get_reverse(); + driver.set_loco_reverse(address, reverse); + + release_blocks(cur_blocks_end, blocks.end()); + reverse_blocks(blocks); + + reserve_more(); + } + if(speed_step!=current_speed_step && !speed_changing && !driver.is_halted() && driver.get_power()) + { + speed_changing = true; + driver.set_loco_speed(address, speed_step); + + pure_speed = false; + + if(speed_step) + set_status(format("Traveling %d kmh", get_travel_speed())); + else + set_status("Waiting"); + } + + if(speed) + { + if(!active) + set_active(true); + + Vehicle &vehicle = *(reverse ? vehicles.back() : vehicles.front()); + Track *track = vehicle.get_track(); + + bool ok = false; + for(BlockList::const_iterator i=blocks.begin(); (!ok && i!=cur_blocks_end); ++i) + ok = (*i)->has_track(*track); + + float d; + if(real_speed.size()>1) + d = get_real_speed(current_speed_step)*(dt/Time::sec); + else + d = speed*(dt/Time::sec); + if(ok) + { + SetFlag setf(advancing); + vehicle.advance(reverse ? -d : d); + } + else if(accurate_position) + { + overshoot_dist += d; + if(overshoot_dist>40*layout.get_catalogue().get_scale()) + { + layout.emergency(name+" has not arrived at sensor"); + accurate_position = false; + } + } + } + else if(end_of_route && cur_blocks_end==blocks.end()) + { + set_active(false); + signal_arrived.emit(); + set_route(0); + } + + if(!blocks.empty() && !blocks.front()->get_sensor_id()) + { + float dist = get_reserved_distance_until(&*blocks.front(), true); + + if(dist>10*layout.get_catalogue().get_scale()) + { + blocks.front()->reserve(0); + blocks.pop_front(); + } + } +} + +void Train::save(list &st) const +{ + st.push_back((DataFile::Statement("name"), name)); + + st.push_back((DataFile::Statement("priority"), priority)); + + for(vector::const_iterator i=vehicles.begin(); i!=vehicles.end(); ++i) + if(i!=vehicles.begin()) + st.push_back((DataFile::Statement("vehicle"), (*i)->get_type().get_article_number())); + + for(unsigned i=0; iget_id())); + + for(BlockList::const_iterator i=blks.begin(); i!=blks.end(); ++i) + st.push_back((DataFile::Statement("block"), (*i)->get_id())); + } + + if(!routes.empty()) + { + list::const_iterator i = routes.begin(); + for(; (i!=routes.end() && i->route->is_temporary()); ++i) ; + if(i!=routes.end()) + st.push_back((DataFile::Statement("route"), i->route->get_name())); + } + + if(timetable) + { + DataFile::Statement ss("timetable"); + timetable->save(ss.sub); + st.push_back(ss); + } +} + +void Train::control_changed(const Controller::Control &ctrl) +{ + signal_control_changed.emit(ctrl.name, ctrl.value); +} + +void Train::loco_speed_event(unsigned addr, unsigned speed, bool) +{ + if(addr==address) + { + current_speed_step = speed; + speed_changing = false; + pure_speed = false; + } +} + +void Train::loco_func_event(unsigned addr, unsigned func, bool state) +{ + if(addr==address || (addr==address+1 && loco_type.get_max_function()>4)) + { + if(addr==address+1) + func += 4; + if(state) + functions |= 1<get_sensor_id()) + { + if((*end)->get_sensor_id()!=addr) + { + if(result==0) + result = 2; + else if(result==1) + break; + } + else if(result==0) + result = 1; + else if(result==2) + result = 3; + } + + if(result==1) + { + // Compute speed and update related state + float travel_time_secs = (Time::now()-last_entry_time)/Time::sec; + + if(pure_speed) + { + if(current_speed_step>0) + { + RealSpeed &rs = real_speed[current_speed_step]; + rs.add(travel_dist/travel_time_secs, travel_time_secs); + } + set_status(format("Traveling %d kmh", get_travel_speed())); + } + + travel_dist = 0; + for(BlockList::iterator j=cur_blocks_end; j!=end; ++j) + { + travel_dist += (*j)->get_path_length(j->entry()); + + if((*j)->get_sensor_id()==addr && !advancing) + { + TrackIter track = j->track_iter(); + if(reverse) + { + track = track.flip(); + vehicles.back()->place(*track, track.entry(), 0, Vehicle::BACK_AXLE); + } + else + vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_AXLE); + } + } + last_entry_time = Time::now(); + pure_speed = true; + accurate_position = true; + overshoot_dist = 0; + + // Check if we've reached the next route + if(routes.size()>1) + { + const Route &route = *(++routes.begin())->route; + for(BlockList::iterator j=cur_blocks_end; j!=end; ++j) + if(route.has_track(*j->track_iter())) + { + routes.pop_front(); + // XXX Exceptions? + signal_route_changed.emit(routes.front().route); + break; + } + } + + // Move blocks up to the next sensor to our current blocks + cur_blocks_end = end; + + // Try to get more blocks if we're moving + if(active) + reserve_more(); + } + else if(result==3) + layout.emergency("Sensor for "+name+" triggered out of order"); + } + else + { + const Vehicle &veh = *(reverse ? vehicles.front() : vehicles.back()); + + // Find the first sensor in our current blocks that's still active + BlockList::iterator end = blocks.begin(); + for(BlockList::iterator i=blocks.begin(); i!=cur_blocks_end; ++i) + { + if((*i)->has_track(*veh.get_track())) + break; + if((*i)->get_sensor_id()) + { + if(layout.get_driver().get_sensor((*i)->get_sensor_id())) + break; + else + { + end = i; + ++end; + } + } + } + + if(end!=blocks.begin() && end!=cur_blocks_end) + // Free blocks up to the last inactive sensor + release_blocks(blocks.begin(), end); + } +} + +void Train::turnout_path_changed(Track &track) +{ + for(list::iterator i=blocks.begin(); i!=blocks.end(); ++i) + if((*i)->get_turnout_id()==track.get_turnout_id() && !reserving) + check_turnout_paths(false); +} + +void Train::halt_event(bool h) +{ + if(h) + accurate_position = false; +} + +void Train::block_reserved(const Block &block, const Train *train) +{ + if(&block==pending_block && !train && !reserving) + reserve_more(); +} + +void Train::reserve_more() +{ + if(!active || blocks.empty() || end_of_route) + return; + + BlockIter start = blocks.back(); + + pending_block = 0; + + // See how many sensor blocks and how much track we already have + unsigned nsens = 0; + float dist = 0; + for(BlockList::const_iterator i=cur_blocks_end; i!=blocks.end(); ++i) + { + if((*i)->get_sensor_id()) + ++nsens; + if(nsens>0) + dist += (*i)->get_path_length(i->entry()); + } + + list::iterator cur_route = routes.begin(); + advance_route(cur_route, *start.track_iter()); + + float approach_margin = 50*layout.get_catalogue().get_scale(); + float min_dist = controller->get_braking_distance()*1.3+approach_margin*2; + + BlockIter block = start; + list::iterator good_end = blocks.end(); + Track *divert_track = 0; + bool try_divert = false; + Train *blocking_train = 0; + BlockList contested_blocks; + + SetFlag setf(reserving); + + while(1) + { + BlockIter last = block; + block = block.next(cur_route!=routes.end() ? cur_route->route : 0); + if(!block || block->get_endpoints().size()<2) + { + if(!blocking_train) + good_end = blocks.end(); + break; + } + + TrackIter track = block.track_iter(); + + if(cur_route!=routes.end()) + { + if(!advance_route(cur_route, *track)) + { + // Keep the blocks if we arrived at the end of the route + if(!blocking_train) + { + good_end = blocks.end(); + end_of_route = true; + } + break; + } + } + + if(block->get_turnout_id() && !last->get_turnout_id()) + { + /* We can keep the blocks if we arrive at a turnout from a non-turnout + block. Having a turnout block as our last reserved block is not good + as it would limit our diversion possibilities for little benefit. */ + good_end = blocks.end(); + if(nsens>=3 && dist>=min_dist) + break; + } + + if(blocking_train) + { + if(block->get_train()!=blocking_train) + { + if(blocking_train->free_block(*contested_blocks.back())) + { + // Roll back and start actually reserving the blocks + block = blocks.back(); + cur_route = routes.begin(); + advance_route(cur_route, *block.track_iter().track()); + if(blocking_train->get_priority()==priority) + blocking_train->yield_to(*this); + blocking_train = 0; + continue; + } + else + { + yield_to(*blocking_train); + pending_block = contested_blocks.front().block(); + try_divert = divert_track; + break; + } + } + else + { + contested_blocks.push_back(block); + continue; + } + } + + bool reserved = block->reserve(this); + if(!reserved) + { + /* We've found another train. If it wants to exit the block from the + same endpoint we're trying to enter from or the other way around, + treat it as coming towards us. Otherwise treat it as going in the + same direction. */ + Train *other_train = block->get_train(); + int other_entry = other_train->get_entry_to_block(*block); + if(other_entry<0) + throw LogicError("Block reservation inconsistency"); + + unsigned exit = block.reverse().entry(); + unsigned other_exit = BlockIter(block.block(), other_entry).reverse().entry(); + bool entry_conflict = (block.entry()==other_exit); + bool exit_conflict = (exit==static_cast(other_entry)); + if(!entry_conflict && !last->get_turnout_id()) + /* The other train is not coming to the blocks we're holding, so we + can keep them. */ + good_end = blocks.end(); + + int other_prio = other_train->get_priority(); + + if(!entry_conflict && !exit_conflict && other_priofree_block(*block)) + reserved = block->reserve(this); + } + else if(other_train!=yielding_to && (other_prioget_turnout_id()) + { + const TrackType::Endpoint &track_ep = track.endpoint(); + bool multiple_paths = (track_ep.paths&(track_ep.paths-1)); + + if(multiple_paths && cur_route!=routes.end() && cur_route->diversion!=block->get_turnout_id()) + /* There's multiple paths to be taken and we are on a route - take + note of the diversion possibility */ + divert_track = &*track; + } + + if(!contested_blocks.empty() && contested_blocks.front()==block) + contested_blocks.pop_front(); + + blocks.push_back(block); + + if(cur_blocks_end==blocks.end()) + --cur_blocks_end; + if(clear_blocks_end==blocks.end()) + --clear_blocks_end; + if(good_end==blocks.end()) + --good_end; + + if(block->get_sensor_id()) + ++nsens; + if(nsens>0) + dist += block->get_path_length(block.entry()); + } + + // Unreserve blocks that were not good + release_blocks(good_end, blocks.end()); + + if(blocks.back()!=start) + // We got some new blocks, so no longer need to yield + yielding_to = 0; + + check_turnout_paths(true); + + // Make any sensorless blocks at the beginning immediately current + while(cur_blocks_end!=clear_blocks_end && !(*cur_blocks_end)->get_sensor_id()) + ++cur_blocks_end; + + if(try_divert && divert(*divert_track)) + reserve_more(); +} + +void Train::check_turnout_paths(bool set) +{ + if(clear_blocks_end==blocks.end()) + return; + + for(list::iterator i=clear_blocks_end; i!=blocks.end(); ++i) + { + if((*i)->get_turnout_id()) + { + TrackIter track = i->track_iter(); + const TrackType::Endpoint &track_ep = track.endpoint(); + + unsigned path = 0; + list::iterator j = i; + if(++j!=blocks.end()) + { + TrackIter rev = j->track_iter().flip(); + unsigned mask = rev.endpoint().paths&track_ep.paths; + for(path=0; mask>1; mask>>=1, ++path) ; + } + else + return; + + if(path!=track->get_active_path()) + { + if(set) + track->set_active_path(path); + + /* Check again, in case the driver was able to service the request + instantly */ + if(!set || path!=track->get_active_path()) + continue; + } + } + + if(i==clear_blocks_end) + ++clear_blocks_end; + } +} + +float Train::get_reserved_distance_until(const Block *until_block, bool back) const +{ + if(blocks.empty()) + return 0; + + Vehicle &veh = *(reverse!=back ? vehicles.back() : vehicles.front()); + const VehicleType &vtype = veh.get_type(); + + TrackIter track(veh.get_track(), veh.get_entry()); + if(!track) // XXX Probably unnecessary + return 0; + + BlockList::const_iterator block = blocks.begin(); + while(block!=clear_blocks_end && !(*block)->has_track(*track)) + ++block; + if(block==clear_blocks_end || &**block==until_block) + return 0; + + float result = veh.get_offset(); + if(reverse!=back) + track = track.reverse(); + else + result = track->get_type().get_path_length(track->get_active_path())-result; + result -= vtype.get_length()/2; + + while(1) + { + track = track.next(); + if(!track) + break; + + if(!(*block)->has_track(*track)) + { + if(back) + { + if(block==blocks.begin()) + break; + --block; + } + else + { + ++block; + if(block==clear_blocks_end) + break; + } + + if(&**block==until_block) + break; + } + + result += track->get_type().get_path_length(track->get_active_path()); + } + + return result; +} + +float Train::get_real_speed(unsigned i) const +{ + if(i==0) + return 0; + if(real_speed[i].weight) + return real_speed[i].speed; + + unsigned low; + unsigned high; + for(low=i; low>0; --low) + if(real_speed[low].weight) + break; + for(high=i; high+1(low*real/real_speed[low].speed), real_speed.size()-1), last+limit); + } + + float f = (real-real_speed[low].speed)/(real_speed[high].speed-real_speed[low].speed); + return static_cast(low*(1-f)+high*f+0.5); +} + +float Train::get_travel_speed() const +{ + float speed = get_real_speed(current_speed_step); + float scale = layout.get_catalogue().get_scale(); + return static_cast(round(speed/scale*3.6/5))*5; +} + +void Train::set_status(const string &s) +{ + status = s; + signal_status_changed.emit(s); +} + +void Train::release_blocks() +{ + release_blocks(blocks.begin(), blocks.end()); +} + +void Train::release_blocks(BlockList::iterator begin, BlockList::iterator end) +{ + while(begin!=end) + { + if(begin==cur_blocks_end) + cur_blocks_end = end; + if(begin==clear_blocks_end) + clear_blocks_end = end; + + Block &block = **begin; + blocks.erase(begin++); + block.reserve(0); + + if(begin==blocks.end()) + end_of_route = false; + } +} + +void Train::reverse_blocks(BlockList &blks) const +{ + blks.reverse(); + for(BlockList::iterator i=blks.begin(); i!=blks.end(); ++i) + *i = i->reverse(); +} + +bool Train::advance_route(list::iterator &iter, Track &track) +{ + while(iter!=routes.end() && !iter->route->has_track(track)) + ++iter; + if(iter==routes.end()) + return false; + + list::iterator next = iter; + ++next; + if(next!=routes.end() && next->diversion && next->route->has_track(track)) + iter = next; + + return true; +} + +Route *Train::create_lead_route(Route *lead, const Route *target) +{ + if(!lead) + { + lead = new Route(layout); + lead->set_name("Lead"); + lead->set_temporary(true); + } + + set tracks; + for(BlockList::iterator i=blocks.begin(); i!=blocks.end(); ++i) + { + const set &btracks = (*i)->get_tracks(); + for(set::const_iterator j=btracks.begin(); j!=btracks.end(); ++j) + if(!target || !target->has_track(**j)) + tracks.insert(*j); + } + + lead->add_tracks(tracks); + + return lead; +} + +bool Train::is_valid_diversion(const Route &diversion, const TrackIter &from) +{ + float diversion_len = 0; + TrackLoopIter track1 = from; + while(diversion.has_track(*track1)) + { + unsigned path = diversion.get_path(*track1); + diversion_len += track1->get_type().get_path_length(path); + + track1 = track1.next(path); + + if(track1.looped()) + return false; + } + + list::iterator route = routes.begin(); + if(!advance_route(route, *from)) + return false; + + float route_len = 0; + TrackLoopIter track2 = from; + while(1) + { + unsigned path = route->route->get_path(*track2); + route_len += track2->get_type().get_path_length(path); + + bool ok = (track2!=from && diversion.has_track(*track2)); + + track2 = track2.next(path); + + if(ok) + break; + + if(track2.looped()) + return false; + + if(!advance_route(route, *track2)) + return false; + } + + // Must end up at the same place through both routes + if(track2!=track1) + return false; + + return diversion_len(t), + prev_block(0), + blocks_valid(true) +{ + add("block", &Loader::block); + add("block_hint", &Loader::block_hint); + add("name", &Loader::name); + add("priority", &Train::priority); + add("real_speed", &Loader::real_speed); + add("route", &Loader::route); + add("timetable", &Loader::timetable); + add("vehicle", &Loader::vehicle); +} + +void Train::Loader::finish() +{ + if(!obj.blocks.empty()) + { + TrackIter track = obj.blocks.front().track_iter(); + float offset = 2*obj.layout.get_catalogue().get_scale(); + obj.vehicles.back()->place(*track, track.entry(), offset, Vehicle::BACK_BUFFER); + + obj.set_status("Stopped"); + } +} + +void Train::Loader::block(unsigned id) +{ + if(!blocks_valid) + return; + + Block *blk; + try + { + blk = &obj.layout.get_block(id); + } + catch(const KeyError &) + { + blocks_valid = false; + return; + } + + int entry = -1; + if(prev_block) + entry = blk->get_endpoint_by_link(*prev_block); + if(entry<0) + entry = 0; + + blk->reserve(&obj); + obj.blocks.push_back(BlockIter(blk, entry)); + + if(blk->get_sensor_id()) + obj.layout.get_driver().set_sensor(blk->get_sensor_id(), true); + + prev_block = blk; +} + +void Train::Loader::block_hint(unsigned id) +{ + try + { + prev_block = &obj.layout.get_block(id); + } + catch(const KeyError &) + { + blocks_valid = false; + } +} + +void Train::Loader::name(const string &n) +{ + obj.set_name(n); +} + +void Train::Loader::real_speed(unsigned i, float speed, float weight) +{ + if(i>=obj.real_speed.size()) + return; + obj.real_speed[i].speed = speed; + obj.real_speed[i].weight = weight; +} + +void Train::Loader::route(const string &n) +{ + obj.set_route(&obj.layout.get_route(n)); +} + +void Train::Loader::timetable() +{ + if(obj.timetable) + throw InvalidState("A timetable has already been loaded"); + + obj.timetable = new Timetable(obj); + load_sub(*obj.timetable); +} + +void Train::Loader::vehicle(ArticleNumber art_nr) +{ + const VehicleType &vtype = obj.layout.get_catalogue().get_vehicle(art_nr); + Vehicle *veh = new Vehicle(obj.layout, vtype); + obj.vehicles.back()->attach_back(*veh); + obj.vehicles.push_back(veh); +} + +} // namespace R2C2 diff --git a/source/libr2c2/train.h b/source/libr2c2/train.h new file mode 100644 index 0000000..99575bf --- /dev/null +++ b/source/libr2c2/train.h @@ -0,0 +1,183 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#ifndef LIBR2C2_TRAIN_H_ +#define LIBR2C2_TRAIN_H_ + +#include +#include +#include +#include "block.h" +#include "blockiter.h" +#include "controller.h" + +namespace R2C2 { + +class ArticleNumber; +class Route; +class Timetable; +class Vehicle; +class VehicleType; + +class Train: public sigc::trackable +{ +public: + class Loader: public Msp::DataFile::BasicLoader + { + private: + Block *prev_block; + bool blocks_valid; + + public: + Loader(Train &); + private: + virtual void finish(); + void block(unsigned); + void block_hint(unsigned); + void name(const std::string &); + void real_speed(unsigned, float, float); + void route(const std::string &); + void timetable(); + void vehicle(ArticleNumber); + }; + + sigc::signal signal_name_changed; + sigc::signal signal_control_changed; + sigc::signal signal_function_changed; + sigc::signal signal_route_changed; + sigc::signal signal_arrived; + sigc::signal signal_status_changed; + +private: + struct RouteRef + { + const Route *route; + unsigned diversion; + + RouteRef(const Route *, unsigned = 0); + }; + + struct RealSpeed + { + float speed; + float weight; + + RealSpeed(); + void add(float, float); + }; + + typedef std::list BlockList; + + Layout &layout; + const VehicleType &loco_type; + unsigned address; + std::string protocol; + std::string name; + int priority; + const Train *yielding_to; + std::vector vehicles; + BlockList blocks; + BlockList::iterator cur_blocks_end; + BlockList::iterator clear_blocks_end; + Block *pending_block; + bool reserving; + bool advancing; + Controller *controller; + Timetable *timetable; + bool active; + unsigned current_speed_step; + bool speed_changing; + bool reverse; + Msp::Time::TimeStamp stop_timeout; + unsigned functions; + std::list routes; + bool end_of_route; + std::string status; + + Msp::Time::TimeStamp last_entry_time; + float travel_dist; + bool pure_speed; + std::vector real_speed; + bool accurate_position; + float overshoot_dist; + +public: + Train(Layout &, const VehicleType &, unsigned, const std::string &); + ~Train(); + + Layout &get_layout() const { return layout; } + const VehicleType &get_locomotive_type() const { return loco_type; } + unsigned get_address() const { return address; } + const std::string &get_protocol() const { return protocol; } + void set_name(const std::string &); + const std::string &get_name() const { return name; } + void set_priority(int); + void yield_to(const Train &); + int get_priority() const { return priority; } + Controller &get_controller() const { return *controller; } + + void add_vehicle(const VehicleType &); + void remove_vehicle(unsigned); + unsigned get_n_vehicles() const; + Vehicle &get_vehicle(unsigned); + const Vehicle &get_vehicle(unsigned) const; + + void set_control(const std::string &, float); + void set_active(bool); + void set_function(unsigned, bool); + float get_control(const std::string &) const; + float get_speed() const; + bool is_active() const { return active; } + bool get_function(unsigned) const; + unsigned get_functions() const { return functions; } + + void set_timetable(Timetable *); + Timetable *get_timetable() { return timetable; } + + bool set_route(const Route *); + bool go_to(Track &); + bool divert(Track &); + const Route *get_route() const; + void place(Block &, unsigned); + void unplace(); + bool is_placed() const { return !blocks.empty(); } + bool free_block(Block &); + void free_noncritical_blocks(); + int get_entry_to_block(Block &) const; + float get_reserved_distance() const; + + const std::string &get_status() const { return status; } + + void tick(const Msp::Time::TimeStamp &, const Msp::Time::TimeDelta &); + + void save(std::list &) const; +private: + void control_changed(const Controller::Control &); + void loco_speed_event(unsigned, unsigned, bool); + void loco_func_event(unsigned, unsigned, bool); + void sensor_event(unsigned, bool); + void turnout_path_changed(Track &); + void halt_event(bool); + void block_reserved(const Block &, const Train *); + void reserve_more(); + void check_turnout_paths(bool); + float get_reserved_distance_until(const Block *, bool) const; + float get_real_speed(unsigned) const; + unsigned find_speed_step(float) const; + float get_travel_speed() const; + void set_status(const std::string &); + void release_blocks(); + void release_blocks(BlockList::iterator, BlockList::iterator); + void reverse_blocks(BlockList &) const; + bool advance_route(std::list::iterator &, Track &); + Route *create_lead_route(Route *, const Route *); + bool is_valid_diversion(const Route &, const TrackIter &); +}; + +} // namespace R2C2 + +#endif diff --git a/source/libr2c2/vehicle.cpp b/source/libr2c2/vehicle.cpp new file mode 100644 index 0000000..e0a5c96 --- /dev/null +++ b/source/libr2c2/vehicle.cpp @@ -0,0 +1,364 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#include +#include "catalogue.h" +#include "driver.h" +#include "layout.h" +#include "track.h" +#include "trackiter.h" +#include "tracktype.h" +#include "vehicle.h" +#include "vehicletype.h" + +using namespace std; +using namespace Msp; + +namespace R2C2 { + +Vehicle::Vehicle(Layout &l, const VehicleType &t): + layout(l), + type(t), + next(0), + prev(0), + direction(0), + bogie_dirs(type.get_bogies().size()), + front_sensor(0), + back_sensor(0) +{ + layout.add_vehicle(*this); +} + +Vehicle::~Vehicle() +{ + if(next) + detach_back(); + if(prev) + detach_front(); + layout.remove_vehicle(*this); +} + +void Vehicle::attach_back(Vehicle &veh) +{ + if(next || veh.prev) + throw InvalidState("Already attached"); + + next = &veh; + veh.prev = this; + + if(track_pos.track) + propagate_backward(); +} + +void Vehicle::attach_front(Vehicle &veh) +{ + if(prev || veh.next) + throw InvalidState("Already attached"); + + prev = &veh; + veh.next = this; + + if(prev->get_track()) + prev->propagate_backward(); +} + +void Vehicle::detach_back() +{ + if(!next) + throw InvalidState("Not attached"); + + next->prev = 0; + next = 0; +} + +void Vehicle::detach_front() +{ + if(!prev) + throw InvalidState("Not attached"); + + prev->next = 0; + prev = 0; +} + +void Vehicle::place(Track &t, unsigned e, float o, PlaceMode m) +{ + track_pos = TrackPosition(&t, e, o); + + if(m==FRONT_AXLE) + track_pos.advance(-type.get_front_axle_offset()); + else if(m==FRONT_BUFFER) + track_pos.advance(-type.get_length()/2); + else if(m==BACK_AXLE) + track_pos.advance(-type.get_back_axle_offset()); + else if(m==BACK_BUFFER) + track_pos.advance(type.get_length()/2); + + update_position(); + propagate_position(); +} + +void Vehicle::unplace() +{ + if(!track_pos.track) + return; + + track_pos = TrackPosition(); + + if(prev) + prev->unplace(); + if(next) + next->unplace(); +} + +void Vehicle::advance(float d) +{ + track_pos.advance(d); + update_position(); + propagate_position(); +} + +float Vehicle::get_bogie_direction(unsigned i) const +{ + if(i>=bogie_dirs.size()) + throw InvalidParameterValue("Bogie index out of range"); + return bogie_dirs[i]; +} + +void Vehicle::update_position() +{ + TrackPoint tp; + + const vector &axles = type.get_axles(); + const vector &bogies = type.get_bogies(); + if(axles.size()>=2) + { + float wheelbase = axles.front().position-axles.back().position; + tp = get_point(track_pos, wheelbase, -axles.back().position/wheelbase); + } + else if(bogies.size()>=2) + { + TrackPosition front = track_pos; + front.advance(bogies.front().position); + TrackPosition back = track_pos; + back.advance(bogies.back().position); + float bogie_spacing = bogies.front().position-bogies.back().position; + adjust_for_distance(front, back, bogie_spacing); + + const vector &front_axles = bogies.front().axles; + float wheelbase = front_axles.front().position-front_axles.back().position; + TrackPoint front_point = get_point(front, wheelbase, -front_axles.back().position/wheelbase); + + const vector &back_axles = bogies.back().axles; + wheelbase = back_axles.front().position-back_axles.back().position; + TrackPoint back_point = get_point(back, wheelbase, -back_axles.back().position/wheelbase); + + tp = get_point(front_point.pos, back_point.pos, -bogies.back().position/bogie_spacing); + + bogie_dirs.front() = front_point.dir-tp.dir; + bogie_dirs.back() = back_point.dir-tp.dir; + } + else + tp = track_pos.get_point(); + + if(!prev) + check_sensor(type.get_front_axle_offset(), front_sensor); + if(!next) + check_sensor(type.get_back_axle_offset(), back_sensor); + + position = tp.pos; + position.z += layout.get_catalogue().get_rail_elevation(); + direction = tp.dir; +} + +void Vehicle::update_position_from(const Vehicle &veh) +{ + int sign = (&veh==prev ? -1 : 1); + + float tdist = (type.get_length()+veh.type.get_length())/2; + float margin = layout.get_catalogue().get_scale(); + + float dist = distance(veh.position, position); + if(disttdist+margin) + { + track_pos = veh.track_pos; + track_pos.advance(sign*tdist); + update_position(); + + dist = distance(veh.position, position); + } + + track_pos.advance(sign*(tdist-dist)); + update_position(); +} + +void Vehicle::propagate_position() +{ + if(prev) + propagate_forward(); + if(next) + propagate_backward(); +} + +void Vehicle::propagate_forward() +{ + prev->update_position_from(*this); + + if(prev->prev) + prev->propagate_forward(); +} + +void Vehicle::propagate_backward() +{ + next->update_position_from(*this); + + if(next->next) + next->propagate_backward(); +} + +void Vehicle::check_sensor(float offset, unsigned &sensor) +{ + TrackPosition pos = track_pos; + pos.advance(offset); + unsigned s = pos.track->get_sensor_id(); + if(s!=sensor) + { + /* Sensor ID under axle has changed. Deduce movement direction by using + the sensor ID under the midpoint of the vehicle. */ + /* XXX This depends on the simulation running fast enough. Something + more robust would be preferable. */ + unsigned old = sensor; + sensor = s; + unsigned mid = track_pos.track->get_sensor_id(); + + if(s && s!=mid) + /* There's a sensor and it's different from mid. We've just entered + that sensor. */ + layout.get_driver().set_sensor(sensor, true); + if(old && old!=mid) + /* A sensor was under the axle and it was different from mid. We've + just left that sensor. */ + layout.get_driver().set_sensor(old, false); + } +} + +void Vehicle::adjust_for_distance(TrackPosition &front, TrackPosition &back, float tdist, float ratio) const +{ + float margin = 0.01*layout.get_catalogue().get_scale(); + int adjust_dir = 0; + while(1) + { + Point front_point = front.get_point().pos; + Point back_point = back.get_point().pos; + + float dx = front_point.x-back_point.x; + float dy = front_point.y-back_point.y; + float dz = front_point.z-back_point.z; + float dist = sqrt(dx*dx+dy*dy+dz*dz); + + float diff = tdist-dist; + if(diff<-margin && adjust_dir<=0) + { + diff -= margin; + adjust_dir = -1; + } + else if(diff>margin && adjust_dir>=0) + { + diff += margin; + adjust_dir = 1; + } + else + return; + + front.advance(diff*(1-ratio)); + back.advance(-diff*ratio); + } +} + +TrackPoint Vehicle::get_point(const Point &front, const Point &back, float ratio) const +{ + float dx = front.x-back.x; + float dy = front.y-back.y; + float dz = front.z-back.z; + + TrackPoint tp; + tp.pos = Point(back.x+dx*ratio, back.y+dy*ratio, back.z+dz*ratio); + tp.dir = atan2(dy, dx); + + return tp; +} + +TrackPoint Vehicle::get_point(const TrackPosition &pos, float tdist, float ratio) const +{ + TrackPosition front = pos; + front.advance(tdist*(1-ratio)); + + TrackPosition back = pos; + back.advance(-tdist*ratio); + + adjust_for_distance(front, back, tdist, ratio); + return get_point(front.get_point().pos, back.get_point().pos, ratio); +} + + +Vehicle::TrackPosition::TrackPosition(): + track(0), + ep(0), + offs(0) +{ } + +Vehicle::TrackPosition::TrackPosition(Track *t, unsigned e, float o): + track(t), + ep(e), + offs(o) +{ } + +void Vehicle::TrackPosition::advance(float d) +{ + if(!track) + return; + + offs += d; + TrackIter iter(track, ep); + while(iter) + { + float path_len = iter->get_type().get_path_length(iter->get_active_path()); + + if(offs>path_len) + { + offs -= path_len; + iter = iter.next(); + } + else + break; + } + + while(iter && offs<0) + { + iter = iter.flip().reverse(); + + if(iter) + { + float path_len = iter->get_type().get_path_length(iter->get_active_path()); + offs += path_len; + } + } + + track = iter.track(); + ep = iter.entry(); + if(!track) + offs = 0; +} + +TrackPoint Vehicle::TrackPosition::get_point() const +{ + if(track) + return track->get_point(ep, offs); + else + return TrackPoint(); +} + +} // namespace R2C2 diff --git a/source/libr2c2/vehicle.h b/source/libr2c2/vehicle.h new file mode 100644 index 0000000..ec33ede --- /dev/null +++ b/source/libr2c2/vehicle.h @@ -0,0 +1,92 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#ifndef LIBR2C2_VEHICLE_H_ +#define LIBR2C2_VEHICLE_H_ + +#include "geometry.h" + +namespace R2C2 { + +class Layout; +class Track; +class VehicleType; + +class Vehicle +{ +public: + enum PlaceMode + { + CENTER, + FRONT_AXLE, + FRONT_BUFFER, + BACK_AXLE, + BACK_BUFFER + }; + +private: + struct TrackPosition + { + Track *track; + unsigned ep; + float offs; + + TrackPosition(); + TrackPosition(Track *, unsigned, float); + void advance(float); + TrackPoint get_point() const; + }; + + Layout &layout; + const VehicleType &type; + Vehicle *next; + Vehicle *prev; + TrackPosition track_pos; + Point position; + float direction; + std::vector bogie_dirs; + unsigned front_sensor; + unsigned back_sensor; + +public: + Vehicle(Layout &, const VehicleType &); + ~Vehicle(); + + const VehicleType &get_type() const { return type; } + + void attach_back(Vehicle &); + void attach_front(Vehicle &); + void detach_back(); + void detach_front(); + Vehicle *get_next() const { return next; } + Vehicle *get_previous() const { return prev; } + + void place(Track &, unsigned, float, PlaceMode = CENTER); + void unplace(); + void advance(float); + Track *get_track() const { return track_pos.track; } + unsigned get_entry() const { return track_pos.ep; } + float get_offset() const { return track_pos.offs; } + const Point &get_position() const { return position; } + float get_direction() const { return direction; } + float get_bogie_direction(unsigned) const; +private: + void update_position(); + void update_position_from(const Vehicle &); + void propagate_position(); + void propagate_forward(); + void propagate_backward(); + void check_sensor(float, unsigned &); + + void adjust_for_distance(TrackPosition &, TrackPosition &, float, float = 0.5) const; + TrackPoint get_point(const Point &, const Point &, float = 0.5) const; + TrackPoint get_point(const TrackPosition &, float, float = 0.5) const; +}; + +} // namespace R2C2 + +#endif diff --git a/source/libr2c2/vehicletype.cpp b/source/libr2c2/vehicletype.cpp new file mode 100644 index 0000000..3d695f8 --- /dev/null +++ b/source/libr2c2/vehicletype.cpp @@ -0,0 +1,160 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#include "vehicletype.h" + +using namespace std; +using namespace Msp; + +namespace R2C2 { + +VehicleType::VehicleType(const ArticleNumber &an): + art_nr(an), + locomotive(false), + length(0), + width(0), + height(0) +{ } + +unsigned VehicleType::get_max_function() const +{ + if(functions.empty()) + return 0; + return (--functions.end())->first; +} + +float VehicleType::get_front_axle_offset() const +{ + float front = length/2; + if(!axles.empty()) + front = axles.front().position; + if(!bogies.empty()) + { + const Bogie &bogie = bogies.front(); + front = max(front, bogie.position+bogie.axles.front().position); + } + return front; +} + +float VehicleType::get_back_axle_offset() const +{ + float back = -length/2; + if(!axles.empty()) + back = axles.back().position; + if(!bogies.empty()) + { + const Bogie &bogie = bogies.back(); + back = min(back, bogie.position+bogie.axles.back().position); + } + return back; +} + + +VehicleType::Axle::Axle(): + position(0), + wheel_dia(0), + powered(false) +{ } + + +VehicleType::Bogie::Bogie(): + position(0), + rotate_object(false) +{ } + + +VehicleType::Loader::Loader(VehicleType &vt): + DataFile::ObjectLoader(vt) +{ + add("axle", &Loader::axle); + add("bogie", &Loader::bogie); + add("function", &Loader::function); + add("height", &Loader::height); + add("length", &Loader::length); + add("locomotive", &VehicleType::locomotive); + add("object", &VehicleType::object); + add("name", &VehicleType::name); + add("width", &Loader::width); +} + +void VehicleType::Loader::axle() +{ + Axle axl; + load_sub(axl); + obj.axles.push_back(axl); +} + +void VehicleType::Loader::bogie() +{ + Bogie bog; + load_sub(bog); + obj.bogies.push_back(bog); +} + +void VehicleType::Loader::function(unsigned i, const string &f) +{ + obj.functions[i] = f; +} + +void VehicleType::Loader::height(float h) +{ + obj.height = h/1000; +} + +void VehicleType::Loader::length(float l) +{ + obj.length = l/1000; +} + +void VehicleType::Loader::width(float w) +{ + obj.width = w/1000; +} + + +VehicleType::Axle::Loader::Loader(Axle &a): + DataFile::ObjectLoader(a) +{ + add("object", &Axle::object); + add("position", &Loader::position); + add("powered", &Axle::powered); + add("wheel_diameter", &Loader::wheel_diameter); +} + +void VehicleType::Axle::Loader::position(float p) +{ + obj.position = p/1000; +} + +void VehicleType::Axle::Loader::wheel_diameter(float d) +{ + obj.wheel_dia = d/1000; +} + + +VehicleType::Bogie::Loader::Loader(Bogie &b): + DataFile::ObjectLoader(b) +{ + add("axle", &Loader::axle); + add("object", &Bogie::object); + add("position", &Loader::position); + add("rotate_object", &Bogie::rotate_object); +} + +void VehicleType::Bogie::Loader::axle() +{ + Axle axl; + load_sub(axl); + obj.axles.push_back(axl); +} + +void VehicleType::Bogie::Loader::position(float p) +{ + obj.position = p/1000; +} + +} // namespace R2C2 diff --git a/source/libr2c2/vehicletype.h b/source/libr2c2/vehicletype.h new file mode 100644 index 0000000..b97fb92 --- /dev/null +++ b/source/libr2c2/vehicletype.h @@ -0,0 +1,102 @@ +/* $Id$ + +This file is part of R²C² +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#ifndef LIBR2C2_VEHICLETYPE_H_ +#define LIBR2C2_VEHICLETYPE_H_ + +#include +#include "articlenumber.h" + +namespace R2C2 { + +class VehicleType +{ +public: + class Loader: public Msp::DataFile::ObjectLoader + { + public: + Loader(VehicleType &); + private: + void axle(); + void bogie(); + void function(unsigned, const std::string &); + void height(float); + void length(float); + void width(float); + }; + + struct Axle + { + class Loader: public Msp::DataFile::ObjectLoader + { + public: + Loader(Axle &); + private: + void position(float); + void wheel_diameter(float); + }; + + float position; + float wheel_dia; + bool powered; + std::string object; + + Axle(); + }; + + struct Bogie + { + class Loader: public Msp::DataFile::ObjectLoader + { + public: + Loader(Bogie &); + private: + void axle(); + void position(float); + }; + + float position; + std::vector axles; + std::string object; + bool rotate_object; + + Bogie(); + }; + +private: + ArticleNumber art_nr; + std::string name; + bool locomotive; + std::map functions; + float length; + float width; + float height; + std::vector axles; + std::vector bogies; + std::string object; + +public: + VehicleType(const ArticleNumber &); + + const ArticleNumber &get_article_number() const { return art_nr; } + const std::string &get_name() const { return name; } + bool is_locomotive() const { return locomotive; } + unsigned get_max_function() const; + const std::map &get_functions() const { return functions; } + float get_length() const { return length; } + float get_width() const { return width; } + float get_height() const { return height; } + const std::vector &get_axles() const { return axles; } + const std::vector &get_bogies() const { return bogies; } + float get_front_axle_offset() const; + float get_back_axle_offset() const; + const std::string &get_object() const { return object; } +}; + +} // namespace R2C2 + +#endif diff --git a/source/network/client.cpp b/source/network/client.cpp index 50db7df..d418b8c 100644 --- a/source/network/client.cpp +++ b/source/network/client.cpp @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2009 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -10,7 +10,7 @@ Distributed under the GPL using namespace std; using namespace Msp; -namespace Marklin { +namespace R2C2 { Client::Client(const Catalogue &c): catalogue(c), @@ -88,4 +88,4 @@ void Client::receive(const ErrorPacket &pkt) signal_error.emit(pkt.message); } -} // namespace Marklin +} // namespace R2C2 diff --git a/source/network/client.h b/source/network/client.h index 2ab8722..02295df 100644 --- a/source/network/client.h +++ b/source/network/client.h @@ -1,21 +1,21 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2009 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ -#ifndef MARKLINNET_CLIENT_H_ -#define MARKLINNET_CLIENT_H_ +#ifndef R2C2_NET_CLIENT_H_ +#define R2C2_NET_CLIENT_H_ #include #include -#include "libmarklin/catalogue.h" +#include "libr2c2/catalogue.h" #include "packets.h" #include "protocol.h" #include "train.h" -namespace Marklin { +namespace R2C2 { class Client: public Msp::Net::PacketReceiver, Msp::Net::PacketReceiver, @@ -64,6 +64,6 @@ private: virtual void receive(const ErrorPacket &); }; -} // namespace Marklin +} // namespace R2C2 #endif diff --git a/source/network/packets.h b/source/network/packets.h index bb08941..8001b8c 100644 --- a/source/network/packets.h +++ b/source/network/packets.h @@ -1,16 +1,16 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2009 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ -#ifndef MARKLINNET_PACKETS_H_ -#define MARKLINNET_PACKETS_H_ +#ifndef R2C2_NET_PACKETS_H_ +#define R2C2_NET_PACKETS_H_ #include -namespace Marklin { +namespace R2C2 { struct TrainInfoPacket { @@ -54,6 +54,6 @@ struct ErrorPacket std::string message; }; -} // namespace Marklin +} // namespace R2C2 #endif diff --git a/source/network/protocol.cpp b/source/network/protocol.cpp index 623eadb..cfbc0fd 100644 --- a/source/network/protocol.cpp +++ b/source/network/protocol.cpp @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2009 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -8,7 +8,7 @@ Distributed under the GPL #include "packets.h" #include "protocol.h" -namespace Marklin { +namespace R2C2 { Protocol::Protocol() { @@ -26,4 +26,4 @@ Protocol::Protocol() add() (&ErrorPacket::message); } -} // namespace Marklin +} // namespace R2C2 diff --git a/source/network/protocol.h b/source/network/protocol.h index 176fdad..7ed85fe 100644 --- a/source/network/protocol.h +++ b/source/network/protocol.h @@ -1,16 +1,16 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2009 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ -#ifndef MARKLINNET_PROTOCOL_H_ -#define MARKLINNET_PROTOCOL_H_ +#ifndef R2C2_NET_PROTOCOL_H_ +#define R2C2_NET_PROTOCOL_H_ #include -namespace Marklin { +namespace R2C2 { class Protocol: public Msp::Net::Protocol { @@ -18,6 +18,6 @@ public: Protocol(); }; -} // namespace Marklin +} // namespace R2C2 #endif diff --git a/source/network/server.cpp b/source/network/server.cpp index 2bf6412..404faa9 100644 --- a/source/network/server.cpp +++ b/source/network/server.cpp @@ -1,20 +1,20 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2009-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ #include -#include "libmarklin/route.h" -#include "libmarklin/train.h" -#include "libmarklin/vehicletype.h" +#include "libr2c2/route.h" +#include "libr2c2/train.h" +#include "libr2c2/vehicletype.h" #include "server.h" using namespace std; using namespace Msp; -namespace Marklin { +namespace R2C2 { Server::Server(Layout &l): layout(l), @@ -222,4 +222,4 @@ void Server::Connection::error(const string &msg) comm.send(pkt); } -} // namespace Marklin +} // namespace R2C2 diff --git a/source/network/server.h b/source/network/server.h index 056b0dd..ced08aa 100644 --- a/source/network/server.h +++ b/source/network/server.h @@ -1,22 +1,22 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2009-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ -#ifndef MARKLINNET_SERVER_H_ -#define MARKLINNET_SERVER_H_ +#ifndef R2C2_NET_SERVER_H_ +#define R2C2_NET_SERVER_H_ #include #include #include #include -#include "libmarklin/layout.h" +#include "libr2c2/layout.h" #include "packets.h" #include "protocol.h" -namespace Marklin { +namespace R2C2 { class Server { @@ -63,6 +63,6 @@ private: void send(const P &); }; -} // namespace Marklin +} // namespace R2C2 #endif diff --git a/source/network/train.cpp b/source/network/train.cpp index 4b6c8e8..df9367e 100644 --- a/source/network/train.cpp +++ b/source/network/train.cpp @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2009 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -10,7 +10,7 @@ Distributed under the GPL using namespace std; -namespace Marklin { +namespace R2C2 { NetTrain::NetTrain(Client &c, const TrainInfoPacket &pkt): client(c), @@ -88,4 +88,4 @@ void NetTrain::process_packet(const TrainRoutePacket &pkt) signal_route_changed.emit(route); } -} // namespace Marklin +} // namespace R2C2 diff --git a/source/network/train.h b/source/network/train.h index 3de4f7d..bffa8a2 100644 --- a/source/network/train.h +++ b/source/network/train.h @@ -1,18 +1,18 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2009 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ -#ifndef MARKLINNET_TRAIN_H_ -#define MARKLINNET_TRAIN_H_ +#ifndef R2C2_NET_TRAIN_H_ +#define R2C2_NET_TRAIN_H_ #include -#include "libmarklin/vehicletype.h" +#include "libr2c2/vehicletype.h" #include "packets.h" -namespace Marklin { +namespace R2C2 { class Client; @@ -54,6 +54,6 @@ public: void process_packet(const TrainStatusPacket &); }; -} // namespace Marklin +} // namespace R2C2 #endif diff --git a/source/remote/remote.cpp b/source/remote/remote.cpp index a193b2b..830a06d 100644 --- a/source/remote/remote.cpp +++ b/source/remote/remote.cpp @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2009-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -50,7 +50,7 @@ void Remote::tick() gtk.iteration(false); } -void Remote::train_added(Marklin::NetTrain &t) +void Remote::train_added(R2C2::NetTrain &t) { TrainPanel *panel = new TrainPanel(*this, client, t); if(!train_panels.empty()) diff --git a/source/remote/remote.h b/source/remote/remote.h index 6d6be33..0d6d413 100644 --- a/source/remote/remote.h +++ b/source/remote/remote.h @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2009-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -20,8 +20,8 @@ class Remote: public Msp::Application { private: Msp::IO::EventDispatcher event_disp; - Marklin::Catalogue catalogue; - Marklin::Client client; + R2C2::Catalogue catalogue; + R2C2::Client client; Gtk::Main gtk; Gtk::Window window; Gtk::Box *train_box; @@ -32,11 +32,11 @@ private: public: Remote(int argc, char **argv); - const Marklin::Catalogue &get_catalogue() const { return catalogue; } + const R2C2::Catalogue &get_catalogue() const { return catalogue; } private: void tick(); - void train_added(Marklin::NetTrain &); + void train_added(R2C2::NetTrain &); }; #endif diff --git a/source/remote/trainpanel.cpp b/source/remote/trainpanel.cpp index b170edc..cfe0c10 100644 --- a/source/remote/trainpanel.cpp +++ b/source/remote/trainpanel.cpp @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2009-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -12,7 +12,7 @@ Distributed under the GPL using namespace std; -TrainPanel::TrainPanel(Remote &r, Marklin::Client &c, Marklin::NetTrain &t): +TrainPanel::TrainPanel(Remote &r, R2C2::Client &c, R2C2::NetTrain &t): remote(r), client(c), train(t) diff --git a/source/remote/trainpanel.h b/source/remote/trainpanel.h index e1464e3..816d2a0 100644 --- a/source/remote/trainpanel.h +++ b/source/remote/trainpanel.h @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2009-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -29,8 +29,8 @@ private: }; Remote &remote; - Marklin::Client &client; - Marklin::NetTrain &train; + R2C2::Client &client; + R2C2::NetTrain &train; Gtk::Scale *scl_speed; Gtk::Label *lbl_status; Gtk::CheckButton *chk_reverse; @@ -39,7 +39,7 @@ private: std::map chk_funcs; public: - TrainPanel(Remote &, Marklin::Client &, Marklin::NetTrain &); + TrainPanel(Remote &, R2C2::Client &, R2C2::NetTrain &); private: void name_changed(const std::string &); void status_changed(const std::string &); diff --git a/source/serial/serial.cpp b/source/serial/serial.cpp index 4b94034..e812a99 100644 --- a/source/serial/serial.cpp +++ b/source/serial/serial.cpp @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -12,7 +12,7 @@ Distributed under the GPL using namespace std; using namespace Msp; -using namespace Marklin; +using namespace R2C2; Application::RegApp Serial::reg; diff --git a/source/serial/serial.h b/source/serial/serial.h index e03bb50..b40a0b9 100644 --- a/source/serial/serial.h +++ b/source/serial/serial.h @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -16,10 +16,10 @@ class Serial: public Msp::Application { private: Msp::IO::EventDispatcher event_disp; - Marklin::Catalogue catalogue; - Marklin::Client client; + R2C2::Catalogue catalogue; + R2C2::Client client; Msp::IO::Serial serial_port; - Marklin::NetTrain *train; + R2C2::NetTrain *train; bool reverse; char rx_buf[3]; unsigned rx_fill; @@ -31,9 +31,9 @@ public: private: virtual void tick(); - void train_added(Marklin::NetTrain &); + void train_added(R2C2::NetTrain &); void error(const std::string &); - void set_train(Marklin::NetTrain *); + void set_train(R2C2::NetTrain *); void next_train(); void prev_train(); void data_available(); diff --git a/source/shoppinglist/main.cpp b/source/shoppinglist/main.cpp index 2b8f5bf..8390a26 100644 --- a/source/shoppinglist/main.cpp +++ b/source/shoppinglist/main.cpp @@ -1,6 +1,6 @@ /* $Id$ -This file is part of the MSP Märklin suite +This file is part of R²C² Copyright © 2006-2008 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -11,11 +11,11 @@ Distributed under the GPL #include #include #include -#include "libmarklin/articlenumber.h" +#include "libr2c2/articlenumber.h" using namespace std; using namespace Msp; -using namespace Marklin; +using namespace R2C2; class ShoppingList: public Application {