]> git.tdb.fi Git - r2c2.git/commitdiff
Rename the project to R²C²
authorMikko Rasa <tdb@tdb.fi>
Tue, 16 Nov 2010 17:53:13 +0000 (17:53 +0000)
committerMikko Rasa <tdb@tdb.fi>
Tue, 16 Nov 2010 17:53:13 +0000 (17:53 +0000)
172 files changed:
Build
firmware/ctrl.c
firmware/delay.h
firmware/eeprom.c
firmware/eeprom.h
firmware/lcd.c
firmware/lcd.h
firmware/s88w-r.c
firmware/s88w-t.c
firmware/serial.c
firmware/serial.h
firmware/timer.c
firmware/timer.h
marklin.res [deleted file]
r2c2.res [new file with mode: 0644]
source/3d/catalogue.cpp
source/3d/catalogue.h
source/3d/endpoint.cpp
source/3d/endpoint.h
source/3d/layout.cpp
source/3d/layout.h
source/3d/object.h
source/3d/overlay.cpp
source/3d/overlay.h
source/3d/path.cpp
source/3d/path.h
source/3d/track.cpp
source/3d/track.h
source/3d/tracktype.cpp
source/3d/tracktype.h
source/3d/vehicle.cpp
source/3d/vehicle.h
source/3d/vehicletype.cpp
source/3d/vehicletype.h
source/designer/cameracontroller.cpp
source/designer/cameracontroller.h
source/designer/designer.cpp
source/designer/designer.h
source/designer/input.cpp
source/designer/input.h
source/designer/manipulator.cpp
source/designer/manipulator.h
source/designer/measure.cpp
source/designer/measure.h
source/designer/selection.cpp
source/designer/selection.h
source/designer/svgexporter.cpp
source/designer/svgexporter.h
source/designer/toolbar.cpp
source/designer/toolbar.h
source/designer/trackwrap.cpp
source/designer/trackwrap.h
source/engineer/dialog.cpp
source/engineer/dialog.h
source/engineer/engineer.cpp
source/engineer/engineer.h
source/engineer/mainpanel.cpp
source/engineer/mainpanel.h
source/engineer/options.cpp
source/engineer/options.h
source/engineer/routeselect.cpp
source/engineer/routeselect.h
source/engineer/timetabledialog.cpp
source/engineer/timetabledialog.h
source/engineer/trainpanel.cpp
source/engineer/trainpanel.h
source/engineer/trainproperties.cpp
source/engineer/trainproperties.h
source/engineer/trainview.cpp
source/engineer/trainview.h
source/libmarklin/aicontrol.cpp [deleted file]
source/libmarklin/aicontrol.h [deleted file]
source/libmarklin/articlenumber.cpp [deleted file]
source/libmarklin/articlenumber.h [deleted file]
source/libmarklin/block.cpp [deleted file]
source/libmarklin/block.h [deleted file]
source/libmarklin/blockiter.cpp [deleted file]
source/libmarklin/blockiter.h [deleted file]
source/libmarklin/catalogue.cpp [deleted file]
source/libmarklin/catalogue.h [deleted file]
source/libmarklin/controller.cpp [deleted file]
source/libmarklin/controller.h [deleted file]
source/libmarklin/driver.cpp [deleted file]
source/libmarklin/driver.h [deleted file]
source/libmarklin/dummy.cpp [deleted file]
source/libmarklin/dummy.h [deleted file]
source/libmarklin/geometry.h [deleted file]
source/libmarklin/intellibox.cpp [deleted file]
source/libmarklin/intellibox.h [deleted file]
source/libmarklin/layout.cpp [deleted file]
source/libmarklin/layout.h [deleted file]
source/libmarklin/profile.cpp [deleted file]
source/libmarklin/profile.h [deleted file]
source/libmarklin/route.cpp [deleted file]
source/libmarklin/route.h [deleted file]
source/libmarklin/simplecontroller.cpp [deleted file]
source/libmarklin/simplecontroller.h [deleted file]
source/libmarklin/timetable.cpp [deleted file]
source/libmarklin/timetable.h [deleted file]
source/libmarklin/track.cpp [deleted file]
source/libmarklin/track.h [deleted file]
source/libmarklin/trackiter.cpp [deleted file]
source/libmarklin/trackiter.h [deleted file]
source/libmarklin/trackpart.cpp [deleted file]
source/libmarklin/trackpart.h [deleted file]
source/libmarklin/tracktype.cpp [deleted file]
source/libmarklin/tracktype.h [deleted file]
source/libmarklin/train.cpp [deleted file]
source/libmarklin/train.h [deleted file]
source/libmarklin/vehicle.cpp [deleted file]
source/libmarklin/vehicle.h [deleted file]
source/libmarklin/vehicletype.cpp [deleted file]
source/libmarklin/vehicletype.h [deleted file]
source/libr2c2/aicontrol.cpp [new file with mode: 0644]
source/libr2c2/aicontrol.h [new file with mode: 0644]
source/libr2c2/articlenumber.cpp [new file with mode: 0644]
source/libr2c2/articlenumber.h [new file with mode: 0644]
source/libr2c2/block.cpp [new file with mode: 0644]
source/libr2c2/block.h [new file with mode: 0644]
source/libr2c2/blockiter.cpp [new file with mode: 0644]
source/libr2c2/blockiter.h [new file with mode: 0644]
source/libr2c2/catalogue.cpp [new file with mode: 0644]
source/libr2c2/catalogue.h [new file with mode: 0644]
source/libr2c2/controller.cpp [new file with mode: 0644]
source/libr2c2/controller.h [new file with mode: 0644]
source/libr2c2/driver.cpp [new file with mode: 0644]
source/libr2c2/driver.h [new file with mode: 0644]
source/libr2c2/dummy.cpp [new file with mode: 0644]
source/libr2c2/dummy.h [new file with mode: 0644]
source/libr2c2/geometry.h [new file with mode: 0644]
source/libr2c2/intellibox.cpp [new file with mode: 0644]
source/libr2c2/intellibox.h [new file with mode: 0644]
source/libr2c2/layout.cpp [new file with mode: 0644]
source/libr2c2/layout.h [new file with mode: 0644]
source/libr2c2/profile.cpp [new file with mode: 0644]
source/libr2c2/profile.h [new file with mode: 0644]
source/libr2c2/route.cpp [new file with mode: 0644]
source/libr2c2/route.h [new file with mode: 0644]
source/libr2c2/simplecontroller.cpp [new file with mode: 0644]
source/libr2c2/simplecontroller.h [new file with mode: 0644]
source/libr2c2/timetable.cpp [new file with mode: 0644]
source/libr2c2/timetable.h [new file with mode: 0644]
source/libr2c2/track.cpp [new file with mode: 0644]
source/libr2c2/track.h [new file with mode: 0644]
source/libr2c2/trackiter.cpp [new file with mode: 0644]
source/libr2c2/trackiter.h [new file with mode: 0644]
source/libr2c2/trackpart.cpp [new file with mode: 0644]
source/libr2c2/trackpart.h [new file with mode: 0644]
source/libr2c2/tracktype.cpp [new file with mode: 0644]
source/libr2c2/tracktype.h [new file with mode: 0644]
source/libr2c2/train.cpp [new file with mode: 0644]
source/libr2c2/train.h [new file with mode: 0644]
source/libr2c2/vehicle.cpp [new file with mode: 0644]
source/libr2c2/vehicle.h [new file with mode: 0644]
source/libr2c2/vehicletype.cpp [new file with mode: 0644]
source/libr2c2/vehicletype.h [new file with mode: 0644]
source/network/client.cpp
source/network/client.h
source/network/packets.h
source/network/protocol.cpp
source/network/protocol.h
source/network/server.cpp
source/network/server.h
source/network/train.cpp
source/network/train.h
source/remote/remote.cpp
source/remote/remote.h
source/remote/trainpanel.cpp
source/remote/trainpanel.h
source/serial/serial.cpp
source/serial/serial.h
source/shoppinglist/main.cpp

diff --git a/Build b/Build
index 6c6687d2c6d23c1caa6a934261c2d7be67c53f02..fbced14d1a328d9adf005514935c0489997c9828 100644 (file)
--- 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";
                };
        };
 };
index 523c702cb140fbef221e429bf841995ea317475c..4e7cb651bc01bf7da3f1ffd729a2a1f19a6c6249 100644 (file)
@@ -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
 */
index 1798cec0a73c79206bcbca6cca5bae406f78b0ab..e4d99854d23e7f6cfcdb13049f5c72aaf160b43c 100644 (file)
@@ -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
 */
index b9010f0f275d7dd5b1ccf0d67d12a000d3dbd426..248556e3fb4607e6eebb0d4a4a77890a396c65b0 100644 (file)
@@ -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
 */
index 97527d67e5dacda89915be9b70e93b1329c890d4..cd31babd02968e906c2c27987c69c3c8fa8e2593 100644 (file)
@@ -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
 */
index 6ba00d54a913c01ba6f2aac24a05f708a40c2a7e..397ec10f4c5f73c14e5fe8b47d09ef1c69a80f2a 100644 (file)
@@ -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
 
index 2d414dcbf646aeace407f4f2a1da42607b4a27f5..822793d3fc325da8dce9539fb72c35df4ee3baf2 100644 (file)
@@ -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
 */
index d2a21092adc82756ad6b99b545dff4e19e64637f..b537584c19ddb698fe9e44ecc4904de47a44568f 100644 (file)
@@ -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
 
index b39fd796fb762199ef311cbada24b5016689a481..b7d0a94f74a7ce89b8152aaf4a5bc5cd53f30c06 100644 (file)
@@ -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
 
index be3b13a925946015c096b103f0b849e2793acbc0..b0f1b1fc39bfa361fba96c896acbcb577e9989f7 100644 (file)
@@ -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
 */
index 696c20e8f37c28d0cf1617873f5c6ca972ecb97b..e5bfebe35569c95ec4988293ecd6bc409f158451 100644 (file)
@@ -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
 */
index 13db1e8672708289631ec5957146101d1c09049e..b218ed607e038370833867ff092c01b8835e82a5 100644 (file)
@@ -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
 */
index 2fbda8e8582a5e96195cda269ddedc532e2a1afb..d7252be28fb427bbddba6ee883b34b035131d507 100644 (file)
@@ -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 (file)
index b40871e..0000000
+++ /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 (file)
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;
+       };
+};
index 2f4fc04ded6ee6923322691354ebcba03c595334..8641013fe3559256a052644267aaf77d7e0869b7 100644 (file)
@@ -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
index 1f33ebb808e7aec3a7af34bc042dd757ec118431..bda1314ce6528a8f4721ca1ed2e9933c1bdbe0b4 100644 (file)
@@ -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 <msp/gl/material.h>
 #include <msp/gl/mesh.h>
-#include "libmarklin/catalogue.h"
+#include "libr2c2/catalogue.h"
 
-namespace Marklin {
+namespace R2C2 {
 
 class TrackType3D;
 class VehicleType3D;
index 77a8af8af9cabdabf870accafa07d8ee657152bd..7e33ced696d92cc2abb3da7b54ddfbcaa0606ed6 100644 (file)
@@ -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
index 0abc52683c3e8e486f61aa2cfc87e8d5857f81d5..e4071278d1f9efa817801a9b8003695772234008 100644 (file)
@@ -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 <msp/gl/mesh.h>
 #include <msp/gl/renderable.h>
-#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
index 05aaa4205bf85053d7a0c1513253fddf5cef87b7..5f015766f6367ad53ae108d379cad9ab0c94861c 100644 (file)
@@ -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
index 54269bc8b42e1d43e32bb56a9e41591a5d313a89..e7f3c33c752d09e821bc5532355ff582f2d4bc7f 100644 (file)
@@ -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 <sigc++/trackable.h>
 #include <msp/gl/scene.h>
-#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
 
index d2cb911c5037a16a486ed3f139a8aca10f6f7475..a9ac7156f6e8af3cc864637b3c21590c5dafb708 100644 (file)
@@ -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
index 39428a166d57ff4f622521b21471d9b9092e9eab..ee9fea7892d465c8e439161cbf4bce17edd0c81f 100644 (file)
@@ -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
index eac51bef810687807ade2e4784108e5d161bf961..8e818bf01e31b59a8fcf2cac1c01f7ecc54354de 100644 (file)
@@ -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 <msp/gbase/window.h>
 #include <msp/gl/camera.h>
@@ -14,7 +14,7 @@ Distributed under the GPL
 #include <msp/gl/mesh.h>
 #include <msp/gl/renderable.h>
 
-namespace Marklin {
+namespace R2C2 {
 
 class Object3D;
 
@@ -55,6 +55,6 @@ private:
        void update_icon(Icon &);
 };
 
-} // namespace Marklin
+} // namespace R2C2
 
 #endif
index b3b2fa1645ad367084d32535afc73bc5614a0a31..e4e0b92989172a64780753af467a80e8f90d9cf3 100644 (file)
@@ -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 <msp/gl/matrix.h>
-#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
index dd071f7d42053031c393c3b93cda52caffb8f986..cd6ad90b8cb996643d15240d39c9e34a74e1ef4a 100644 (file)
@@ -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 <msp/gl/color.h>
 #include <msp/gl/mesh.h>
 #include <msp/gl/renderable.h>
 
-namespace Marklin {
+namespace R2C2 {
 
 class Track3D;
 
@@ -38,6 +38,6 @@ public:
        virtual void render(const Msp::GL::Tag &) const;
 };
 
-} // namespace Marklin
+} // namespace R2C2
 
 #endif
index 5340318063338d9ba6f439df5c831c6be76abd21..401dd2d9634956a15d645047881663e1d355c44c 100644 (file)
@@ -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 <cmath>
 #include <msp/gl/matrix.h>
 #include <msp/gl/misc.h>
-#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
index e55dc21245f146920115c4719acc63267bf54142..7b8c23565f3024ecb1c954f6839a7f3c48fd8925 100644 (file)
@@ -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 <list>
 #include <msp/gl/renderable.h>
 #include <msp/gl/vertexarray.h>
 #include <msp/gl/vertexarraybuilder.h>
-#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
index 6dab43c4f7d59de418bcbbe8622fba641298e7d4..1e20c5d8aa82f966a904970f972d79e92b0feb5b 100644 (file)
@@ -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.z<p2.z;
 }
@@ -27,7 +27,7 @@ Iter graham_scan(Iter begin, Iter end)
        // http://en.wikipedia.org/wiki/Graham_scan
 
        // Find point with lowest X coordinate
-       Marklin::Point lowest = *begin;
+       R2C2::Point lowest = *begin;
        for(Iter i=begin; i!=end; ++i)
                if(i->x<lowest.x || (i->x==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
index 56a4b46ac11c091e460fa8f075bb6f89203a8f96..7bf1b2d5b9241ab931afefe140ec242366afa6e1 100644 (file)
@@ -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 <msp/gl/mesh.h>
 #include <msp/gl/meshbuilder.h>
 #include <msp/gl/renderable.h>
-#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
index 7e4814b008b03a64b588479792959329d7254cf9..f14f3c2c238df933943cc938fabffdf6231241f2 100644 (file)
@@ -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
index 075eaef273cdec1289eb983e81dc6c01e02f77a4..06e78ef4409130094fc922d9e0ff79d1b93352d2 100644 (file)
@@ -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 <msp/gl/renderable.h>
-#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
index b283eddebe896b1307881fef7b96098117dd64b1..fc4f2d49095332c502c36434d81c8af8372d1d95 100644 (file)
@@ -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<string, string> &params, 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<string, string> &params)
        return mesh;
 }
 
-} // namespace Marklin
+} // namespace R2C2
index f38f02d92ea43dab2651d8019884dccf1438e851..72c2c231a1f84e24c57b45646f309b28125cdb5c 100644 (file)
@@ -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 <msp/gl/mesh.h>
 #include <msp/gl/object.h>
-#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<std::string, std::string> &);
 };
 
-} // namespace Marklin
+} // namespace R2C2
 
 #endif
index edebff75f375f7911499e38f7edafb3a592217ec..6b98f3dba1bb32cda7aed57acc4bad688ce42a02 100644 (file)
@@ -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),
index beed68a483c247f106797cc4e4557c8a9e4e422e..b18e2519d25aadecaff80eb4e8c345b7bc7ffb85 100644 (file)
@@ -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
 */
index 23185cf3252e6d15418a563395795b2de3caf41d..8ab0465c2347a89d3bf21352001199f2939084ba 100644 (file)
@@ -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 <msp/strings/utils.h>
 #include <msp/time/units.h>
 #include <msp/time/utils.h>
-#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> 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),
index c173668408a36d1300f8c725a75a9dec18a06a91..9fc2961ddd01ba7ba08da0858e16584100509e5d 100644 (file)
@@ -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 <msp/gltk/resources.h>
 #include <msp/gltk/root.h>
 #include <msp/time/timestamp.h>
-#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<Marklin::Track *> new_tracks;
+       R2C2::Route *cur_route;
+       std::list<R2C2::Track *> 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
index 26bf9f2bfc521165e24d4ae2c5cb7afd22092e29..9476bad4b6197b7d0d0d875fda65ac082bb4f015 100644 (file)
@@ -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
 */
index e3fc7c34147441e335a4e0757f12a29b7d27cc04..a9ecfe1012c77168f24eb2f5d2913866712979b2 100644 (file)
@@ -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
 */
index 300802110e295ae0ba090d3ea722c5294546d908..23ea138623c42809726c0df07c644ad15ba52f99 100644 (file)
@@ -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 <algorithm>
 #include <cmath>
 #include <msp/strings/formatter.h>
-#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<Track *> Manipulator::create_straight(const Marklin::Point &start, float dir, float length, float limit)
+vector<Track *> 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<float, const TrackType *> types_by_length;
index 55d2425ad8bfdb98596bd33877da65eaa25e18a8..66b5d1ae67065e7ee1f275af69c095d8e820127a 100644 (file)
@@ -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<MTrack> 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<Marklin::Track *> neighbors;
-       std::vector<Marklin::Track *> extend_tracks;
+       std::set<R2C2::Track *> neighbors;
+       std::vector<R2C2::Track *> 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<Marklin::Track *> create_straight(const Marklin::Point &, float, float, float);
+       std::vector<R2C2::Track *> create_straight(const R2C2::Point &, float, float, float);
 };
 
 #endif
index 201674c86a206cd025c32da9fa3dd935e84997f2..56efc1b55a16a969b28bbea4e33a69385307037e 100644 (file)
@@ -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):
index f68178dcacaf2b2368a641c53d1fb0fd5426420a..6800ecce307826fa0bcc46d204e0ec84b539b4b4 100644 (file)
@@ -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
index c6b1e390d97cb8f80f2aad3ea3f0cc60171b2ac0..604890b92795c9fb090a6882308d54b96fbe2da4 100644 (file)
@@ -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 <algorithm>
-#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
index 9d49c76d3b924e467f9a60d6efddaade34e341bb..479f5af0b3e2d90226debf1603ae960ec6dee588 100644 (file)
@@ -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<void> signal_changed;
 
 private:
-       std::set<Marklin::Track *> tracks;
+       std::set<R2C2::Track *> tracks;
 
 public:
-       const std::set<Marklin::Track *> &get_tracks() const { return tracks; }
-       Marklin::Track *get_track() const;
+       const std::set<R2C2::Track *> &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();
index 56945f704d8ac44c26047e82bf0287b51ee15397..a9e13f8924db6470b02e27615af3b7cada4a91f3 100644 (file)
@@ -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 <cmath>
 #include <msp/strings/formatter.h>
-#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),
index 6e93ca4de5f881a639b8a716a420e027a2adfd45..38d77a9a4f162ef4aa519de019824c5be5a01362 100644 (file)
@@ -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 <libxml++/libxml++.h>
-#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
index 56a5d6de7e3ac09a30396cc5d1c83913d47cc1cc..c6d859b925a1a0850a1c34e9f89d749d7ecf4396 100644 (file)
@@ -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 <msp/gltk/button.h>
 #include <msp/strings/formatter.h>
-#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)
index 2a935d365fc686c7c7bbfc4d5bf88f95ffaf2e6f..9029a9c1c726fd620be2361c7bc98faec48b0986 100644 (file)
@@ -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 <sigc++/trackable.h>
 #include <msp/gltk/dropdown.h>
 #include <msp/gltk/panel.h>
-#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();
 };
 
index b5070757efad2697e2ddc513934b33f172bc18d7..65c33d5a1ffb0200ffc13adecfd08aa33fc39d7d 100644 (file)
@@ -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),
index 09bacda3e7f8be18ba9dd43ffa802b93b2c89255..2f21125c6b703b2ba05b97b834ec5637c7570565 100644 (file)
@@ -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 <msp/gl/mesh.h>
 #include <msp/gl/renderable.h>
-#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<const Marklin::TrackType *, Msp::GL::Mesh *> meshes;
+       std::map<const R2C2::TrackType *, Msp::GL::Mesh *> meshes;
        std::list<Wrap> 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
index e71c1ce484540487eb22caf68e434fb51a78d56b..2d2bae3c21db1da080a1b3a82ded8ed76b3c1492 100644 (file)
@@ -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
 */
index 5fb694f11ea7a242f75279345d1d6bd3d49e51f6..0299287f23f52bd4fdc5ebe1b28eb303514fe2cb 100644 (file)
@@ -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
 */
index 7e13f7b50471ad61261f43a8cfa7608ede759a9d..1f3b7dc4accc617e56eb8c587f4064c0d9e091d2 100644 (file)
@@ -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 <msp/strings/formatter.h>
 #include <msp/time/units.h>
 #include <msp/time/utils.h>
-#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> 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));
index 61a2f59e37730c53e88a87bccbfd26bda1ea6abc..4ca753e949f230b864acf266f3e07b2403c86294 100644 (file)
@@ -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 <msp/gl/pipeline.h>
 #include <msp/gltk/resources.h>
 #include <msp/gltk/root.h>
-#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<void, Marklin::Track *, int> signal_pick_done;
+       sigc::signal<void, R2C2::Track *, int> 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<Marklin::Train *, Msp::GL::Color> train_colors;
+       R2C2::Overlay3D *overlay;
+       std::map<R2C2::Train *, Msp::GL::Color> train_colors;
 
        Msp::GL::Camera camera;
        Msp::GL::Lighting lighting;
@@ -59,9 +59,9 @@ private:
        std::list<TrainView *> 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<Engineer> reg;
index 8a292b44ff851dbb4a02c84eacc04ad2a7a6cd00..667e95fa17a1fb5c658f18657270a4111bbc8bd0 100644 (file)
@@ -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 <msp/gltk/button.h>
-#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());
 }
 
index 17e95dbfac7e87682a5f093b5abc0f423435375e..a4b62b7316504319dab6786c5082cb0b8f8daf65 100644 (file)
@@ -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
 */
index fc7516c16cc2405d91c7e92cf0944d9be07400f3..b5c36cd5409cca9e43822fda7215e9f1e9018b52 100644 (file)
@@ -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
 */
index 689b22a7bdbb9be16289a175ff6d2c493b78bd07..e35cc92a3f403a7dfee009dd511ee482909ce548 100644 (file)
@@ -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
 */
index 0e191499a0541d89478de35c94b44e7522329163..00bf6cfdcd19cf79d97c316df2def12be7c24785 100644 (file)
@@ -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 <msp/gltk/label.h>
 #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),
index f6110c51739a7e28fbea10c3f650f43c30b7bf60..6552175ea562d625f0ea7cbb52a5d65fcd783420 100644 (file)
@@ -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 <msp/gltk/dropdown.h>
-#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();
 };
index 52f391ce0a85f635d6854fdab66b806ad49f458a..2e50099b01413bf6f5915797af4520922e0f2617 100644 (file)
@@ -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)
index a1f611d10f622461c55dc702c67f16410e64cbe8..9c06fc81acc5e6444818a076977211d5f5e6faae 100644 (file)
@@ -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 <msp/gltk/dialog.h>
 #include <msp/gltk/entry.h>
 #include <msp/gltk/toggle.h>
-#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);
index 23e26eef713e8c0e37606e25a695ae9e704c07c4..5d237ecbca3b912b5297ea01748fcdb190891e71 100644 (file)
@@ -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 <cmath>
 #include <msp/strings/formatter.h>
-#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),
index 9a38ca49d4ed91200b6ede85e980511c793352fa..d74ccbf88695e40c960a93c72975f9de31d33b97 100644 (file)
@@ -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 <msp/gltk/label.h>
 #include <msp/gltk/panel.h>
 #include <msp/gltk/toggle.h>
-#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
index eaddc8bb1c47a38a2ca94c5944deef0592b14773..9686dee485527574cd2b1f78b3c111f3b46a1f09 100644 (file)
@@ -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 <msp/gltk/label.h>
 #include <msp/strings/formatter.h>
 #include <msp/strings/lexicalcast.h>
-#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),
index 465154d2948789734672233ad7b0f39d8766978f..24458331bb4e1267b757092333efc4e848556651 100644 (file)
@@ -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 <msp/gltk/dropdown.h>
 #include <msp/gltk/entry.h>
-#include <libmarklin/train.h>
+#include <libr2c2/train.h>
 #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<const Marklin::VehicleType *> add_vehicles;
+       std::vector<const R2C2::VehicleType *> add_vehicles;
        std::set<unsigned> 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
index df336d577197763080a68fca2360f97fc52c6d52..f282b4e07487c6ad24f479bc02a8de7fb39b0ff5 100644 (file)
@@ -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 <msp/gl/tests.h>
 #include <msp/gltk/button.h>
 #include <msp/gltk/image.h>
-#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),
index a452a71912cca03e0bde0a946301e12d489cac1d..c7ba7b90c30da5b05e546aa384369f901b5eacd3 100644 (file)
@@ -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 <msp/gl/texture2d.h>
 #include <msp/gltk/panel.h>
 #include <msp/gltk/toggle.h>
-#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 (file)
index 553159c..0000000
+++ /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_dist<brake_dist+margin)
-       {
-               blocked = true;
-               next_ctrl->set_control("speed", 0);
-       }
-       else if((!approach && rsv_dist<brake_dist*1.3+approach_margin) || (blocked && rsv_dist>brake_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 (file)
index 462a114..0000000
+++ /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 <sigc++/trackable.h>
-#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 (file)
index cac3b32..0000000
+++ /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 <msp/strings/utils.h>
-#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<string> sparts = split(s, '-');
-       for(vector<string>::iterator i=sparts.begin(); i!=sparts.end(); ++i)
-       {
-               if(i->empty())
-                       throw InvalidParameterValue("Malformed article number");
-
-               unsigned nondigit = i->size();
-               for(unsigned j=0; j<i->size(); ++j)
-                       if(!isdigit((*i)[j]))
-                       {
-                               nondigit = j;
-                               break;
-                       }
-
-               if(!nondigit || nondigit<i->size()-1)
-                       throw InvalidParameterValue("Malformed article number");
-
-               Part part;
-               part.number = lexical_cast<unsigned>(i->substr(0, nondigit));
-               part.letter = nondigit<i->size() ? (*i)[nondigit] : 0;
-               parts.push_back(part);
-       }
-}
-
-string ArticleNumber::str() const
-{
-       string result;
-       for(vector<Part>::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<other.parts;
-}
-
-
-bool ArticleNumber::Part::operator<(const Part &other) const
-{
-       if(number!=other.number)
-               return number<other.number;
-       return letter<other.letter;
-}
-
-
-void operator>>(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 (file)
index 0aa6498..0000000
+++ /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 <string>
-#include <vector>
-#include <msp/strings/lexicalcast.h>
-
-namespace Marklin {
-
-class ArticleNumber
-{
-private:
-       struct Part
-       {
-               unsigned number;
-               char letter;
-
-               bool operator<(const Part &) const;
-       };
-
-       std::vector<Part> 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 (file)
index e8e367f..0000000
+++ /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 <algorithm>
-#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<Track *> queue;
-       queue.push_back(&start);
-
-       while(!queue.empty())
-       {
-               Track *track = queue.front();
-               queue.erase(queue.begin());
-
-               const vector<Track *> &links = track->get_links();
-               for(unsigned i=0; i<links.size(); ++i)
-                       if(links[i] && !tracks.count(links[i]))
-                       {
-                               if(links[i]->get_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<endpoints.size(); ++i)
-       {
-               unsigned path = 1<<i;
-               endpoints[i].paths |= path;
-               find_paths(TrackIter(endpoints[i].track, endpoints[i].track_ep), path);
-       }
-
-       layout.add_block(*this);
-}
-
-Block::~Block()
-{
-       set<Track *> trks = tracks;
-       tracks.clear();
-       for(set<Track *>::iterator i=trks.begin(); i!=trks.end(); ++i)
-               (*i)->set_block(0);
-
-       for(vector<Endpoint>::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(); ++i)
-               if(endpoints[i].link==&other)
-                       return i;
-
-       return -1;
-}
-
-float Block::get_path_length(unsigned entry, const Route *route) const
-{
-       if(entry>=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<Endpoint>::iterator i=endpoints.begin(); i!=endpoints.end(); ++i)
-       {
-               if(i->link)
-                       continue;
-
-               for(vector<Endpoint>::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<Endpoint>::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<<i))
-               {
-                       TrackIter next = track.next(i);
-                       if(!next)
-                               continue;
-                       else if(has_track(*next))
-                               find_paths(track.next(i), path);
-                       else
-                       {
-                               next = next.flip();
-                               for(vector<Endpoint>::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(id2<id1)
-                       swap(id1, id2);
-               id = (id1<<16)|id2;
-       }
-       else if(endpoints.size()==1)
-       {
-               unsigned id1 = endpoints[0].link ? endpoints[0].link->get_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 (file)
index 41f9040..0000000
+++ /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 <list>
-#include <set>
-#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<Track *> tracks;
-       std::vector<Endpoint> 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<Track *> &get_tracks() const { return tracks; }
-       bool has_track(Track &) const;
-       const std::vector<Endpoint> &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 (file)
index 245f963..0000000
+++ /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 <msp/core/except.h>
-#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<Block::Endpoint> &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; i<eps.size(); ++i)
-                       if(eps[i].track==t_exit.track() && eps[i].track_ep==t_exit.entry())
-                               return i;
-
-               t_iter = t_exit.flip();
-       }
-
-       return -1;
-}
-
-BlockIter BlockIter::next(const Route *route) const
-{
-       if(!_block)
-               return BlockIter();
-
-       int exit = get_exit(route);
-       if(exit<0)
-               return BlockIter();
-
-       BlockIter result;
-       result._block = _block->get_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 (file)
index c86a4e5..0000000
+++ /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 (file)
index 82dde18..0000000
+++ /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 <msp/core/refptr.h>
-#include <msp/datafile/parser.h>
-#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<Catalogue>(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<void (Loader::*)(unsigned)>(&Loader::track));
-       add("track", static_cast<void (Loader::*)(ArticleNumber)>(&Loader::track));
-       add("vehicle", static_cast<void (Loader::*)(unsigned)>(&Loader::vehicle));
-       add("vehicle", static_cast<void (Loader::*)(ArticleNumber)>(&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<TrackType> 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<VehicleType> 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 (file)
index a436994..0000000
+++ /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 <map>
-#include <msp/datafile/loader.h>
-#include "articlenumber.h"
-#include "layout.h"
-#include "profile.h"
-
-namespace Marklin {
-
-class TrackType;
-class VehicleType;
-
-class Catalogue
-{
-public:
-       class Loader: public Msp::DataFile::BasicLoader<Catalogue>
-       {
-       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<ArticleNumber, TrackType *> TrackMap;
-       typedef std::map<ArticleNumber, VehicleType *> VehicleMap;
-
-       sigc::signal<void, const TrackType &> signal_track_added;
-       sigc::signal<void, const VehicleType &> 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 (file)
index 8d7be31..0000000
+++ /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 <cmath>
-#include <msp/core/except.h>
-#include "controller.h"
-
-using namespace std;
-using namespace Msp;
-
-namespace Marklin {
-
-void Controller::Control::set(float v)
-{
-       if(v<min_value)
-               v = min_value;
-       else if(v>max_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<m)
-               throw InvalidParameterValue("Max value must be greater than min value");
-
-       Controller::Control tc;
-       tc.name = n;
-       tc.type = DISCRETE;
-       tc.min_value = m;
-       tc.max_value = m+floor((x-m)/s)*s;
-       tc.step = s;
-       tc.value = m;
-
-       return tc;
-}
-
-Controller::Control Controller::Control::continuous(const string &n, float m, float x)
-{
-       if(x<m)
-               throw InvalidParameterValue("Max value must be greater than min value");
-
-       Controller::Control tc;
-       tc.name = n;
-       tc.type = CONTINUOUS;
-       tc.min_value = m;
-       tc.max_value = x;
-       tc.step = 0;
-       tc.value = m;
-
-       return tc;
-}
-
-} // namespace Marklin
diff --git a/source/libmarklin/controller.h b/source/libmarklin/controller.h
deleted file mode 100644 (file)
index ac5128b..0000000
+++ /dev/null
@@ -1,75 +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_CONTROLLER_H_
-#define LIBMARKLIN_CONTROLLER_H_
-
-#include <string>
-#include <sigc++/signal.h>
-#include <msp/time/timedelta.h>
-
-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<void, const Control &> 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 (file)
index 3bec54e..0000000
+++ /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 <msp/core/except.h>
-#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 (file)
index f8d8f9c..0000000
+++ /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 <string>
-#include <sigc++/signal.h>
-
-namespace Marklin {
-
-class Driver
-{
-public:
-       sigc::signal<void, bool> signal_power;
-       sigc::signal<void, bool> signal_halt;
-       sigc::signal<void, unsigned, unsigned, bool> signal_loco_speed;
-       sigc::signal<void, unsigned, unsigned, bool> signal_loco_function;
-       sigc::signal<void, unsigned, bool> signal_turnout;
-       sigc::signal<void, unsigned, bool> 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 (file)
index da6c5c9..0000000
+++ /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<unsigned, bool>::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<unsigned, bool>::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 (file)
index 7485fa5..0000000
+++ /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 <map>
-#include "driver.h"
-
-namespace Marklin {
-
-class Dummy: public Driver
-{
-private:
-       struct LocoState
-       {
-               unsigned speed;
-               bool reverse;
-       };
-
-       bool power;
-       std::map<unsigned, bool> turnouts;
-       std::map<unsigned, LocoState> locos;
-       std::map<unsigned, bool> 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 (file)
index 674a6b9..0000000
+++ /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 <cmath>
-#include <vector>
-
-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 (file)
index 1dc2e70..0000000
+++ /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 <fcntl.h>
-#include <termios.h>
-#include <sys/poll.h>
-#include <msp/io/print.h>
-#include <msp/time/units.h>
-#include <msp/time/utils.h>
-#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<unsigned, Locomotive>::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(speed<loco.speed && (speed&1))
-               {
-                       loco.pending_half_step = 1;
-                       speed &= ~1;
-               }
-               else
-                       loco.pending_half_step = 0;
-               loco.half_step_delay = Time::TimeStamp();
-
-               loco_command(addr, (speed+1)/2, loco.reverse, loco.funcs|0x100);
-       }
-       else
-       {
-               if(speed>14)
-                       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<<func;
-       else
-               loco.funcs &= ~(1<<func);
-       loco_command(addr, loco.speed, loco.reverse, loco.funcs);
-       signal_loco_function.emit(addr, func, state);
-}
-
-void Intellibox::add_turnout(unsigned addr)
-{
-       if(!turnouts.count(addr))
-       {
-               turnouts[addr];
-
-               unsigned char data[2];
-               data[0] = addr&0xFF;
-               data[1] = (addr>>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<unsigned, Turnout>::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<unsigned, Sensor>::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<unsigned, Locomotive>::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<unsigned, Turnout>::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<unsigned, Sensor>::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<CommandSlot>::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<count; ++i)
-               {
-                       unsigned char data[2];
-                       read_all(data, 2);
-
-                       unsigned addr = data[0]+((data[1]&7)<<8);
-                       Turnout &turnout = turnouts[addr];
-                       turnout.state = (data[1]&0x80)!=0;
-                       turnout.pending = turnout.state;
-                       signal_turnout.emit(addr, turnout.state);
-               }
-       }
-       else if(cmd==CMD_EVENT_SENSOR)
-       {
-               while(1)
-               {
-                       unsigned char mod;
-                       read_all(&mod, 1);
-                       if(!mod)
-                               break;
-
-                       unsigned char data[2];
-                       read_all(data, 2);
-                       for(unsigned i=0; i<16; ++i)
-                       {
-                               unsigned addr = mod*16+i-15;
-                               bool state = (data[i/8]>>(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<<i))
-                                               signal_loco_function.emit(addr, i, loco.funcs&(1<<i));
-                       }
-               }
-               else
-                       error(cmd, err);
-       }
-       else
-       {
-               unsigned expected_bytes = 0;
-               if(cmd==CMD_FUNC_STATUS)
-                       expected_bytes = 1;
-               if(cmd==CMD_TURNOUT_GROUP_STATUS)
-                       expected_bytes = 2;
-               if(cmd==CMD_LOK_CONFIG)
-                       expected_bytes = 4;
-
-               Error err;
-               read_status(&err);
-
-               if(err==ERR_NO_ERROR)
-               {
-                       unsigned char data[8];
-                       read_all(data, expected_bytes);
-               }
-               else
-                       error(cmd, err);
-       }
-}
-
-unsigned Intellibox::read_all(unsigned char *buf, unsigned len)
-{
-       unsigned pos = 0;
-       while(pos<len)
-               pos += read(serial_fd, buf+pos, len-pos);
-
-       return pos;
-}
-
-unsigned Intellibox::read_status(Error *err)
-{
-       unsigned char c;
-       unsigned ret = read_all(&c, 1);
-       *err = static_cast<Error>(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 (file)
index 6d061a6..0000000
+++ /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 <map>
-#include <msp/time/timestamp.h>
-#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<unsigned, Locomotive> locos;
-       std::map<unsigned, Turnout> turnouts;
-       std::map<unsigned, Sensor> sensors;
-       bool update_sensors;
-       std::list<CommandSlot> 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 (file)
index 5f590db..0000000
+++ /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 <algorithm>
-#include <msp/core/refptr.h>
-#include <msp/datafile/parser.h>
-#include <msp/datafile/writer.h>
-#include <msp/io/print.h>
-#include <msp/time/utils.h>
-#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<unsigned> used_ids;
-       for(set<Track *>::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<Block *>::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<Track *> used_tracks;
-       for(set<Block *>::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
-       {
-               const set<Track *> &btracks = (*i)->get_tracks();
-               used_tracks.insert(btracks.begin(), btracks.end());
-       }
-
-       for(set<Track *>::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<Block *>::iterator i=blocks.begin(); i!=blocks.end(); ++i)
-               for(set<Block *>::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<Block *> del_blocks;
-
-       del_blocks.insert(&track.get_block());
-
-       const vector<Track *> &links = track.get_links();
-       for(vector<Track *>::const_iterator i=links.begin(); i!=links.end(); ++i)
-               if(*i)
-                       del_blocks.insert(&(*i)->get_block());
-
-       for(set<Block *>::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<Route *>::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<Route *>::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<unsigned, Train *>::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<unsigned, Train *>::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<Track *>::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<Route *>::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<unsigned, Train *>::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<Block *>::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<Layout>(l),
-       new_tracks(false)
-{
-       add("base",  &Layout::base);
-       add("route", static_cast<void (Loader::*)()>(&Loader::route));
-       add("route", static_cast<void (Loader::*)(const string &)>(&Loader::route));
-       add("track", static_cast<void (Loader::*)(unsigned)>(&Loader::track));
-       add("track", static_cast<void (Loader::*)(ArticleNumber)>(&Loader::track));
-       add("train", static_cast<void (Loader::*)(unsigned, unsigned, const std::string &)>(&Loader::train));
-       add("train", static_cast<void (Loader::*)(ArticleNumber, unsigned, const std::string &)>(&Loader::train));
-}
-
-void Layout::Loader::finish()
-{
-       for(set<Track *>::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<Track *>::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 (file)
index 2fc761a..0000000
+++ /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 <set>
-#include <sigc++/sigc++.h>
-#include <msp/datafile/loader.h>
-#include <msp/time/timestamp.h>
-
-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<Layout>
-       {
-       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<void, Track &> signal_track_added;
-       sigc::signal<void, Track &> signal_track_removed;
-       sigc::signal<void, Route &> signal_route_added;
-       sigc::signal<void, Route &> signal_route_removed;
-       sigc::signal<void, Train &> signal_train_added;
-       sigc::signal<void, Train &> signal_train_removed;
-       sigc::signal<void, Vehicle &> signal_vehicle_added;
-       sigc::signal<void, Vehicle &> signal_vehicle_removed;
-       sigc::signal<void, Block &, Train *> signal_block_reserved;
-       sigc::signal<void, const std::string &> signal_emergency;
-
-private:
-       Catalogue &catalogue;
-       Driver *driver;
-       std::string base;
-       std::set<Track *> tracks;
-       std::set<Route *> routes;
-       std::set<Block *> blocks;
-       std::map<unsigned, Train *> trains;
-       std::set<Vehicle *> 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<Track *> &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<Block *> &get_blocks() const { return blocks; }
-       void create_blocks();
-       void create_blocks(Track &);
-       void remove_block(Block &);
-
-       void add_route(Route &);
-       const std::set<Route *> &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<unsigned, Train *> &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 (file)
index 7b9dce5..0000000
+++ /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 <cmath>
-#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<Profile>(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 (file)
index b1082e8..0000000
+++ /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 <vector>
-#include <msp/datafile/objectloader.h>
-#include "geometry.h"
-
-namespace Marklin {
-
-class Profile
-{
-public:
-       class Loader: public Msp::DataFile::ObjectLoader<Profile>
-       {
-       public:
-               Loader(Profile &);
-       private:
-               void point(float, float);
-       };
-
-private:
-       std::vector<Point> 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 (file)
index 79886d2..0000000
+++ /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 <queue>
-#include <msp/strings/formatter.h>
-#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<Track *, unsigned> 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<Track *> &tracks;
-
-       TrackInSet(const set<Track *> &t): tracks(t) { }
-
-       bool operator()(Track &t) const { return tracks.count(&t); }
-};
-
-template<typename Pred>
-list<Track *> dijkstra(const TrackIter &from, const Pred &goal)
-{
-       map<Key, Node> track_nodes;
-       priority_queue<Node> 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<<i))
-                       {
-                               TrackIter next = lowest.track.next(i);
-                               if(!next)
-                                       continue;
-
-                               if(track_nodes.count(Key(next.track(), next.entry())))
-                                       continue;
-
-                               nodes.push(Node(next, ref, lowest.track->get_type().get_path_length(i)));
-                       }
-       }
-
-       list<Track *> result;
-       for(Node *node=final; node; node=node->prev)
-               result.push_front(&*node->track);
-
-       return result;
-}
-
-template<typename Pred>
-Route *create_route(const TrackIter &from, const Pred &goal)
-{
-       list<Track *> tracks = dijkstra(from, goal);
-
-       if(tracks.empty())
-               return 0;
-
-       Route *route = new Route(from->get_layout());
-       for(list<Track *>::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<unsigned, int>::iterator i = turnouts.find(addr);
-       if(i==turnouts.end())
-               throw KeyError("Turnout is not in this route");
-       if(i->second>=0 && path!=static_cast<unsigned>(i->second))
-               throw InvalidState("Setting conflicts with route");
-       i->second = path;
-}
-
-void Route::update_turnouts()
-{
-       set<unsigned> found;
-       for(set<Track *>::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
-               if(unsigned tid = (*i)->get_turnout_id())
-               {
-                       found.insert(tid);
-
-                       const vector<TrackType::Endpoint> &endpoints = (*i)->get_type().get_endpoints();
-                       const vector<Track *> &links = (*i)->get_links();
-
-                       // Build a combined path mask from linked endpoints
-                       unsigned mask = (*i)->get_type().get_paths();
-                       for(unsigned j=0; j<endpoints.size(); ++j)
-                       {
-                               if(!tracks.count(links[j]))
-                                       continue;
-
-                               if(unsigned tid2 = links[j]->get_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<<p)))
-                                       {
-                                               // The linked track is a turnout and has a path which is incompatible with this endpoint
-                                               mask &= ~endpoints[j].paths;
-                                               continue;
-                                       }
-                               }
-                               mask &= endpoints[j].paths;
-                       }
-
-                       if(mask && !(mask&(mask-1)))
-                       {
-                               // Exactly one possible choice, set the path accordingly
-                               unsigned path = 0;
-                               for(; (mask && !(mask&1)); mask>>=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<unsigned, int>::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<unsigned, int>::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<unsigned, int>::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<Track *> &trks)
-{
-       set<Track *> pending;
-       for(set<Track *>::const_iterator i=trks.begin(); i!=trks.end(); ++i)
-               if(!tracks.count(*i))
-                       pending.insert(*i);
-
-       while(!pending.empty())
-       {
-               bool found = false;
-               for(set<Track *>::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<DataFile::Statement> &st) const
-{
-       st.push_back((DataFile::Statement("name"), name));
-       for(map<unsigned, int>::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<Track *> &links = trk.get_links();
-       for(vector<Track *>::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<<path))
-                                       result |= 2;
-                       }
-                       else
-                       {
-                               // Linked to a turnout with no path set - check other linked tracks 
-                               const vector<Track *> &tlinks = (*i)->get_links();
-                               unsigned count = 0;
-                               for(unsigned j=0; j<tlinks.size(); ++j)
-                                       if(tracks.count(tlinks[j]))
-                                       {
-                                               unsigned tid2 = tlinks[j]->get_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<<path)))
-                                                               continue;
-                                               }
-
-                                               ++count;
-
-                                               const TrackType::Endpoint &ep2 = (*i)->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<Track *> &to)
-{
-       return create_route(from, TrackInSet(to));
-}
-
-
-Route::Loader::Loader(Route &r):
-       DataFile::BasicLoader<Route>(r)
-{
-       add("name",    &Route::name);
-       add("turnout", &Loader::turnout);
-}
-
-void Route::Loader::finish()
-{
-       const set<Track *> &ltracks = obj.layout.get_tracks();
-       for(set<Track *>::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<<j->second;
-               const vector<TrackType::Endpoint> &eps = (*i)->get_type().get_endpoints();
-               for(unsigned k=0; k<eps.size(); ++k)
-                       if(eps[k].paths&path_mask)
-                       {
-                               Track *link = (*i)->get_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 (file)
index 0b03637..0000000
+++ /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 <map>
-#include <set>
-#include <string>
-#include <sigc++/trackable.h>
-#include <msp/datafile/loader.h>
-
-namespace Marklin {
-
-class Layout;
-class Track;
-class TrackIter;
-
-class Route: public sigc::trackable
-{
-public:
-       typedef std::map<unsigned, int> TurnoutMap;
-
-       class Loader: public Msp::DataFile::BasicLoader<Route>
-       {
-       private:
-               TurnoutMap turnouts;
-
-       public:
-               Loader(Route &);
-       private:
-               virtual void finish();
-               void turnout(unsigned, unsigned);
-       };
-
-       sigc::signal<void, const std::string &> signal_name_changed;
-
-private:
-       Layout &layout;
-       std::string name;
-       bool temporary;
-       std::set<Track *> 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<unsigned, int> &get_turnouts() const { return turnouts; }
-       void add_track(Track &);
-       void add_tracks(const std::set<Track *> &);
-       void add_track_chain(Track &, unsigned, const TurnoutMap &);
-       const std::set<Track *> &get_tracks() const { return tracks; }
-       bool has_track(Track &) const;
-       void save(std::list<Msp::DataFile::Statement> &) 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<Track *> &);
-};
-
-} // namespace Marklin
-
-#endif
diff --git a/source/libmarklin/simplecontroller.cpp b/source/libmarklin/simplecontroller.cpp
deleted file mode 100644 (file)
index 5744188..0000000
+++ /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 <msp/core/except.h>
-#include <msp/time/units.h>
-#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(speed<target_speed.value)
-       {
-               speed += secs*accel;
-               if(speed>target_speed.value)
-                       speed = target_speed.value;
-       }
-       else if(speed>target_speed.value)
-       {
-               speed -= secs*accel;
-               if(speed<target_speed.value)
-                       speed = target_speed.value;
-       }
-}
-
-} // namespace Marklin
diff --git a/source/libmarklin/simplecontroller.h b/source/libmarklin/simplecontroller.h
deleted file mode 100644 (file)
index 9b0df26..0000000
+++ /dev/null
@@ -1,39 +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_SIMPLECONTROLLER_H_
-#define LIBMARKLIN_SIMPLECONTROLLER_H_
-
-#include <string>
-#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 (file)
index a699fc8..0000000
+++ /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 <msp/strings/formatter.h>
-#include <msp/time/units.h>
-#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<string>(0)).get_tracks().begin()))
-                               set_enabled(false);
-                       break;
-               case TRAVEL:
-                       pending_block = &parse_location(row.get_param<string>(0));
-                       pending_train = &train;
-                       executing = false;
-                       break;
-               case WAIT_TIME:
-                       wait_timeout = t+row.get_param<unsigned>(0)*Time::sec;
-                       executing = false;
-                       break;
-               case WAIT_TRAIN:
-                       pending_train = &train.get_layout().get_train(row.get_param<unsigned>(0));
-                       pending_block = &parse_location(row.get_param<string>(1));
-                       executing = false;
-                       break;
-               case ARRIVE:
-                       executing = false;
-                       break;
-               case SPEED:
-                       train.set_control("speed", row.get_param<unsigned>(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<string>(0))))
-                               set_enabled(false);
-                       break;
-               }
-
-               if(executing)
-                       current_row = (current_row+1)%rows.size();
-       }
-}
-
-void Timetable::save(list<DataFile::Statement> &st) const
-{
-       for(vector<Row>::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<unsigned>(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<typename T>
-Timetable::Row::Row(RowType t, const T &p):
-       type(t)
-{
-       params.push_back(p);
-}
-
-template<typename T>
-const T &Timetable::Row::get_param(unsigned i) const
-{
-       if(i>=params.size())
-               throw InvalidParameterValue("Parameter index out of range");
-       return params[i].value<T>();
-}
-
-string Timetable::Row::str() const
-{
-       switch(type)
-       {
-       case GOTO:
-               return "set route to "+get_param<string>(0);
-       case TRAVEL:
-               return "travel to "+get_param<string>(0);
-       case WAIT_TIME:
-               return format("wait for %d seconds", get_param<unsigned>(0));
-       case WAIT_TRAIN:
-               return format("wait for train %d at %s", get_param<unsigned>(0), get_param<string>(1));
-       case ARRIVE:
-               return "travel until arrival";
-       case SPEED:
-               return format("set speed %d km/h", get_param<unsigned>(0));
-       case REVERSE:
-               return "reverse";
-       case ROUTE:
-               return "set route "+get_param<string>(0);
-       default:
-               return "invalid row";
-       }
-}
-
-DataFile::Statement Timetable::Row::save() const
-{
-       switch(type)
-       {
-       case GOTO:
-               return DataFile::Statement("goto"), get_param<string>(0);
-       case TRAVEL:
-               return DataFile::Statement("travel"), get_param<string>(0);
-       case WAIT_TIME:
-               return DataFile::Statement("wait"), get_param<unsigned>(0);
-       case WAIT_TRAIN:
-               return DataFile::Statement("wait_train"), get_param<unsigned>(0), get_param<string>(1);
-       case ARRIVE:
-               return DataFile::Statement("arrive");
-       case SPEED:
-               return DataFile::Statement("speed"), get_param<unsigned>(0);
-       case REVERSE:
-               return DataFile::Statement("reverse");
-       case ROUTE:
-               return DataFile::Statement("route"), get_param<string>(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.size() && isdigit(s[nondigit]))
-                               ++nondigit;
-                       return Row(WAIT_TIME, lexical_cast<unsigned>(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<unsigned>(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.size() && (isdigit(s[nondigit]) || s[nondigit]=='-'))
-                       ++nondigit;
-               return Row(SPEED, lexical_cast<unsigned>(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<Timetable>(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 (file)
index b4f9cc1..0000000
+++ /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 <string>
-#include <vector>
-#include <sigc++/trackable.h>
-#include <msp/datafile/objectloader.h>
-#include <msp/time/timestamp.h>
-
-namespace Marklin {
-
-class Block;
-class Train;
-
-class Timetable: public sigc::trackable
-{
-public:
-       class Loader: public Msp::DataFile::ObjectLoader<Timetable>
-       {
-       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<Msp::Variant> params;
-
-               Row(RowType);
-
-               template<typename T>
-               Row(RowType, const T &);
-
-               template<typename T>
-               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<Row> 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<Msp::DataFile::Statement> &) 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 (file)
index fbe3f0a..0000000
+++ /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 <cmath>
-#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<<p)))
-               throw InvalidParameterValue("Invalid path");
-
-       layout.get_driver().set_turnout(turnout_id, p&1);
-       if(type.is_double_address())
-               layout.get_driver().set_turnout(turnout_id+1, p&2);
-       else if(type.get_n_paths()>2)
-               active_path = (active_path&1) | (p&2);
-}
-
-int Track::get_endpoint_by_link(Track &other) const
-{
-       for(unsigned i=0; i<links.size(); ++i)
-               if(links[i]==&other)
-                       return i;
-
-       return -1;
-}
-
-Point Track::get_endpoint_position(unsigned epi) const
-{
-       const vector<TrackType::Endpoint> &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<TrackType::Endpoint> &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<TrackType::Endpoint> &eps = type.get_endpoints();
-       const vector<TrackType::Endpoint> &other_eps = other.get_type().get_endpoints();
-
-       for(unsigned i=0; i<eps.size(); ++i)
-       {
-               Point epp = get_endpoint_position(i);
-
-               for(unsigned j=0; j<other_eps.size(); ++j)
-               {
-                       if(other.get_link(j))
-                               continue;
-
-                       Point epp2 = other.get_endpoint_position(j);
-                       float dx = epp2.x-epp.x;
-                       float dy = epp2.y-epp.y;
-                       float dz = epp2.z-epp.z;
-                       if(dx*dx+dy*dy<limit && dz*dz<limit)
-                       {
-                               if(!link || (!flex && !other.get_flex()))
-                               {
-                                       set_rotation(other.rot+other_eps[j].dir-eps[i].dir+M_PI);
-                                       Point p(epp2.x-(eps[i].pos.x*cos(rot)-eps[i].pos.y*sin(rot)),
-                                               epp2.y-(eps[i].pos.y*cos(rot)+eps[i].pos.x*sin(rot)),
-                                               epp2.z);
-                                       if(eps.size()==2 && i==1)
-                                               p.z -= slope;
-                                       set_position(p);
-                               }
-
-                               if(link)
-                               {
-                                       if(links[i])
-                                               break_link(*links[i]);
-                                       links[i] = &other;
-                                       other.links[j] = this;
-                                       layout.create_blocks(*this);
-                               }
-
-                               return true;
-                       }
-               }
-       }
-
-       return false;
-}
-
-bool Track::snap(Point &pt, float &d) const
-{
-       const vector<TrackType::Endpoint> &eps = type.get_endpoints();
-
-       for(unsigned i=0; i<eps.size(); ++i)
-       {
-               Point epp = get_endpoint_position(i);
-               float dx = pt.x-epp.x;
-               float dy = pt.y-epp.y;
-               if(dx*dx+dy*dy<1e-4)
-               {
-                       pt = epp;
-                       d = rot+eps[i].dir;
-                       return true;
-               }
-       }
-
-       return false;
-}
-
-void Track::break_link(Track &trk)
-{
-       for(vector<Track *>::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<Track *>::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<DataFile::Statement> &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<Track>(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 (file)
index f065cb6..0000000
+++ /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 <list>
-#include <set>
-#include <sigc++/trackable.h>
-#include <msp/datafile/loader.h>
-#include "geometry.h"
-
-namespace Marklin {
-
-class Block;
-class Layout;
-class TrackType;
-
-class Track: public sigc::trackable
-{
-public:
-       class Loader: public Msp::DataFile::BasicLoader<Track>
-       {
-       public:
-               Loader(Track &);
-       private:
-               void position(float, float, float);
-               void sensor_id(unsigned);
-               void turnout_id(unsigned);
-       };
-
-       sigc::signal<void, unsigned> 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<Track *> 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<Track *> &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<Msp::DataFile::Statement> &) 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 (file)
index b980228..0000000
+++ /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 <algorithm>
-#include <msp/core/except.h>
-#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<TrackType::Endpoint> &eps = _track->get_type().get_endpoints();
-       
-       // Find an endpoint that's connected to the entry and has the requested path
-       for(unsigned i=0; i<eps.size(); ++i)
-               if(i!=_entry && (eps[i].paths&(1<<path)) && (eps[i].paths&eps[_entry].paths))
-                       return i;
-
-       return -1;
-}
-
-TrackIter TrackIter::next() const
-{
-       if(!_track)
-               return TrackIter();
-
-       return next(_track->get_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<TrackList> 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 (file)
index e2f1d85..0000000
+++ /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 <set>
-#include <msp/core/refptr.h>
-#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<Track *> TrackList;
-
-       Msp::RefPtr<TrackList> _visited;
-       TrackList::iterator _last;
-       bool _looped;
-
-public:
-       TrackLoopIter();
-       TrackLoopIter(Track *, unsigned);
-       TrackLoopIter(const TrackIter &);
-private:
-       TrackLoopIter(const TrackIter &, Msp::RefPtr<TrackList>, 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 (file)
index 37c5f97..0000000
+++ /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 <cmath>
-#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; i<n_eps; ++i)
-       {
-               TrackPoint p1 = get_point(i ? get_length() : 0);
-               for(unsigned j=0; j<n_other_eps; ++j)
-               {
-                       TrackPoint p2 = other.get_point(j ? other.get_length() : 0);
-
-                       float dx = p2.pos.x-p1.pos.x;
-                       float dy = p2.pos.y-p1.pos.y;
-
-                       float da = p2.dir-p1.dir+M_PI*((i+j+1)%2);
-                       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)
-                       {
-                               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<TrackPart>(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 (file)
index 13e0f38..0000000
+++ /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 <msp/datafile/loader.h>
-#include "geometry.h"
-
-namespace Marklin {
-
-class TrackPart
-{
-public:
-       class Loader: public Msp::DataFile::BasicLoader<TrackPart>
-       {
-       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 (file)
index 9f2979b..0000000
+++ /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 <cmath>
-#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<TrackPart>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
-               if(p<0 || i->get_path()==static_cast<unsigned>(p))
-                       len += i->get_length();
-       return len;
-}
-
-unsigned TrackType::get_paths() const
-{
-       unsigned mask = 0;
-       for(vector<TrackPart>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
-               mask |= 1<<i->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<TrackPart>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
-       {
-               if((endpoints[epi].paths&(1<<path)) && i->get_path()!=path)
-                       continue;
-
-               unsigned n_part_eps = (i->is_dead_end() ? 1 : 2);
-               for(unsigned j=0; j<n_part_eps; ++j)
-               {
-                       TrackPoint p = i->get_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<TrackPart>::iterator i=parts.begin(); i!=parts.end(); ++i)
-       {
-               for(vector<TrackPart>::iterator j=i; ++j!=parts.end();)
-                       i->check_link(*j);
-
-               unsigned n_part_eps = (i->is_dead_end() ? 1 : 2);
-               for(unsigned j=0; j<n_part_eps; ++j)
-                       if(!i->get_link(j))
-                       {
-                               TrackPoint p = i->get_point(j ? i->get_length() : 0);
-                               if(j==0)
-                                       p.dir += M_PI;
-
-                               bool found = false;
-                               for(vector<Endpoint>::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<<i->get_path();
-                                               found = true;
-                                               break;
-                                       }
-                               }
-
-                               if(!found)
-                                       endpoints.push_back(Endpoint(p.pos.x, p.pos.y, p.dir, 1<<i->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<TrackType>(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 (file)
index d13ea28..0000000
+++ /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 <msp/datafile/loader.h>
-#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<TrackType>
-       {
-       public:
-               Loader(TrackType &);
-       private:
-               virtual void finish();
-               void part();
-               void position(float, float, float);
-       };
-
-private:
-       ArticleNumber art_nr;
-       std::string description;
-       std::vector<TrackPart> parts;
-       std::vector<Endpoint> 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<TrackPart> &get_parts() const { return parts; }
-       const std::vector<Endpoint> &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 (file)
index 859d3da..0000000
+++ /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 <cmath>
-#include <msp/strings/formatter.h>
-#include <msp/time/units.h>
-#include <msp/time/utils.h>
-#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<Track *> &tracks = layout.get_tracks();
-       for(set<Track *>::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<Vehicle *>::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(i<vehicles.size())
-               vehicles[i-1]->attach_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<RouteRef>::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<<i)) && i!=route_path)
-                               {
-                                       path = i;
-                                       break;
-                               }
-
-                       entry = track.entry();
-                       break;
-               }
-
-               track = track.next(route->route->get_path(*track));
-
-               if(!track || track.looped())
-                       return false;
-       }
-
-       TrackIter track = TrackIter(&from, entry).next(path);
-       if(!track)
-               return false;
-
-       set<Track *> tracks;
-       for(list<RouteRef>::iterator i=routes.begin(); i!=routes.end(); ++i)
-               tracks.insert(i->route->get_tracks().begin(), i->route->get_tracks().end());
-       RefPtr<Route> 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<RouteRef>::iterator end = routes.end();
-       while(1)
-       {
-               for(list<RouteRef>::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<Vehicle *>::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)<controller->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<DataFile::Statement> &st) const
-{
-       st.push_back((DataFile::Statement("name"), name));
-
-       st.push_back((DataFile::Statement("priority"), priority));
-
-       for(vector<Vehicle *>::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; i<real_speed.size(); ++i)
-               if(real_speed[i].weight)
-                       st.push_back((DataFile::Statement("real_speed"), i, real_speed[i].speed, real_speed[i].weight));
-
-       if(!blocks.empty() && cur_blocks_end!=blocks.begin())
-       {
-               BlockList blks(blocks.begin(), BlockList::const_iterator(cur_blocks_end));
-               if(reverse)
-                       reverse_blocks(blks);
-
-               BlockIter prev = blks.front().flip();
-               st.push_back((DataFile::Statement("block_hint"), prev->get_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<RouteRef>::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<<func;
-               else
-                       functions &= ~(1<<func);
-
-               signal_function_changed.emit(func, state);
-       }
-}
-
-void Train::sensor_event(unsigned addr, bool state)
-{
-       if(state)
-       {
-               // Find the first sensor block from our reserved blocks that isn't this sensor
-               BlockList::iterator end;
-               unsigned result = 0;
-               for(end=cur_blocks_end; end!=blocks.end(); ++end)
-                       if((*end)->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<BlockIter>::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<RouteRef>::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<BlockIter>::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<unsigned>(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_prio<priority)
-                       {
-                               /* Ask a lesser priority train going to the same direction to free
-                               the block for us */
-                               if(other_train->free_block(*block))
-                                       reserved = block->reserve(this);
-                       }
-                       else if(other_train!=yielding_to && (other_prio<priority || (other_prio==priority && entry_conflict)))
-                       {
-                               /* A lesser priority train is coming at us, we must ask it to free
-                               enough blocks to get clear of it to avoid a potential deadlock */
-                               blocking_train = other_train;
-                               contested_blocks.clear();
-                               contested_blocks.push_back(block);
-                               continue;
-                       }
-                       else if(divert_track && (entry_conflict || exit_conflict))
-                               // We are blocked, but there's a diversion possibility
-                               try_divert = true;
-
-                       if(!reserved)
-                       {
-                               pending_block = &*block;
-                               break;
-                       }
-               }
-
-               if(block->get_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<BlockIter>::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<BlockIter>::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<real_speed.size(); ++high)
-               if(real_speed[high].weight)
-                       break;
-
-       if(real_speed[high].weight)
-       {
-               if(real_speed[low].weight)
-               {
-                       float f = float(i-low)/(high-low);
-                       return real_speed[low].speed*(1-f)+real_speed[high].speed*f;
-               }
-               else
-                       return real_speed[high].speed*float(i)/high;
-       }
-       else if(real_speed[low].weight)
-               return real_speed[low].speed*float(i)/low;
-       else
-               return 0;
-}
-
-unsigned Train::find_speed_step(float real) const
-{
-       if(real_speed.size()<=1)
-               return 0;
-       if(real<=real_speed[1].speed*0.5)
-               return 0;
-
-       unsigned low = 0;
-       unsigned high = 0;
-       unsigned last = 0;
-       for(unsigned i=0; (!high && i<real_speed.size()); ++i)
-               if(real_speed[i].weight)
-               {
-                       last = i;
-                       if(real_speed[i].speed<real)
-                               low = i;
-                       else
-                               high = i;
-               }
-       if(!high)
-       {
-               unsigned limit = real_speed.size()/5;
-               if(!low)
-               {
-                       if(real)
-                               return limit;
-                       else
-                               return 0;
-               }
-               return min(min(static_cast<unsigned>(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<unsigned>(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<int>(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<RouteRef>::iterator &iter, Track &track)
-{
-       while(iter!=routes.end() && !iter->route->has_track(track))
-               ++iter;
-       if(iter==routes.end())
-               return false;
-
-       list<RouteRef>::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<Track *> tracks;
-       for(BlockList::iterator i=blocks.begin(); i!=blocks.end(); ++i)
-       {
-               const set<Track *> &btracks = (*i)->get_tracks();
-               for(set<Track *>::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<RouteRef>::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<route_len*1.2;
-}
-
-
-Train::RouteRef::RouteRef(const Route *r, unsigned d):
-       route(r),
-       diversion(d)
-{ }
-
-
-Train::RealSpeed::RealSpeed():
-       speed(0),
-       weight(0)
-{ }
-
-void Train::RealSpeed::add(float s, float w)
-{
-       speed = (speed*weight+s*w)/(weight+w);
-       weight = min(weight+w, 300.0f);
-}
-
-
-Train::Loader::Loader(Train &t):
-       DataFile::BasicLoader<Train>(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 (file)
index a13c422..0000000
+++ /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 <sigc++/signal.h>
-#include <sigc++/trackable.h>
-#include <msp/time/timestamp.h>
-#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<Train>
-       {
-       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<void, const std::string &> signal_name_changed;
-       sigc::signal<void, const std::string &, float> signal_control_changed;
-       sigc::signal<void, unsigned, bool> signal_function_changed;
-       sigc::signal<void, const Route *> signal_route_changed;
-       sigc::signal<void> signal_arrived;
-       sigc::signal<void, const std::string &> 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<BlockIter> BlockList;
-
-       Layout &layout;
-       const VehicleType &loco_type;
-       unsigned address;
-       std::string protocol;
-       std::string name;
-       int priority;
-       const Train *yielding_to;
-       std::vector<Vehicle *> 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<RouteRef> routes;
-       bool end_of_route;
-       std::string status;
-
-       Msp::Time::TimeStamp last_entry_time;
-       float travel_dist;
-       bool pure_speed;
-       std::vector<RealSpeed> 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<Msp::DataFile::Statement> &) 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<RouteRef>::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 (file)
index b54b531..0000000
+++ /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 <cmath>
-#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<VehicleType::Axle> &axles = type.get_axles();
-       const vector<VehicleType::Bogie> &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<VehicleType::Axle> &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<VehicleType::Axle> &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(dist<tdist-margin || dist>tdist+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 (file)
index 75ae859..0000000
+++ /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<float> 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 (file)
index 5c14cba..0000000
+++ /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<VehicleType>(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<Axle>(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<Bogie>(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 (file)
index 7844825..0000000
+++ /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 <msp/datafile/objectloader.h>
-#include "articlenumber.h"
-
-namespace Marklin {
-
-class VehicleType
-{
-public:
-       class Loader: public Msp::DataFile::ObjectLoader<VehicleType>
-       {
-       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<Axle>
-               {
-               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<Bogie>
-               {
-               public:
-                       Loader(Bogie &);
-               private:
-                       void axle();
-                       void position(float);
-               };
-
-               float position;
-               std::vector<Axle> axles;
-               std::string object;
-               bool rotate_object;
-
-               Bogie();
-       };
-
-private:
-       ArticleNumber art_nr;
-       std::string name;
-       bool locomotive;
-       std::map<unsigned, std::string> functions;
-       float length;
-       float width;
-       float height;
-       std::vector<Axle> axles;
-       std::vector<Bogie> 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<unsigned, std::string> &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<Axle> &get_axles() const { return axles; }
-       const std::vector<Bogie> &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 (file)
index 0000000..c2f16e3
--- /dev/null
@@ -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_dist<brake_dist+margin)
+       {
+               blocked = true;
+               next_ctrl->set_control("speed", 0);
+       }
+       else if((!approach && rsv_dist<brake_dist*1.3+approach_margin) || (blocked && rsv_dist>brake_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 (file)
index 0000000..0d84218
--- /dev/null
@@ -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 <sigc++/trackable.h>
+#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 (file)
index 0000000..45e526c
--- /dev/null
@@ -0,0 +1,90 @@
+/* $Id$
+
+This file is part of R²C²
+Copyright © 2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <msp/strings/utils.h>
+#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<string> sparts = split(s, '-');
+       for(vector<string>::iterator i=sparts.begin(); i!=sparts.end(); ++i)
+       {
+               if(i->empty())
+                       throw InvalidParameterValue("Malformed article number");
+
+               unsigned nondigit = i->size();
+               for(unsigned j=0; j<i->size(); ++j)
+                       if(!isdigit((*i)[j]))
+                       {
+                               nondigit = j;
+                               break;
+                       }
+
+               if(!nondigit || nondigit<i->size()-1)
+                       throw InvalidParameterValue("Malformed article number");
+
+               Part part;
+               part.number = lexical_cast<unsigned>(i->substr(0, nondigit));
+               part.letter = nondigit<i->size() ? (*i)[nondigit] : 0;
+               parts.push_back(part);
+       }
+}
+
+string ArticleNumber::str() const
+{
+       string result;
+       for(vector<Part>::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<other.parts;
+}
+
+
+bool ArticleNumber::Part::operator<(const Part &other) const
+{
+       if(number!=other.number)
+               return number<other.number;
+       return letter<other.letter;
+}
+
+
+void operator>>(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 (file)
index 0000000..cf69c42
--- /dev/null
@@ -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 <string>
+#include <vector>
+#include <msp/strings/lexicalcast.h>
+
+namespace R2C2 {
+
+class ArticleNumber
+{
+private:
+       struct Part
+       {
+               unsigned number;
+               char letter;
+
+               bool operator<(const Part &) const;
+       };
+
+       std::vector<Part> 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 (file)
index 0000000..ca404de
--- /dev/null
@@ -0,0 +1,222 @@
+/* $Id$
+
+This file is part of R²C²
+Copyright © 2006-2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <algorithm>
+#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<Track *> queue;
+       queue.push_back(&start);
+
+       while(!queue.empty())
+       {
+               Track *track = queue.front();
+               queue.erase(queue.begin());
+
+               const vector<Track *> &links = track->get_links();
+               for(unsigned i=0; i<links.size(); ++i)
+                       if(links[i] && !tracks.count(links[i]))
+                       {
+                               if(links[i]->get_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<endpoints.size(); ++i)
+       {
+               unsigned path = 1<<i;
+               endpoints[i].paths |= path;
+               find_paths(TrackIter(endpoints[i].track, endpoints[i].track_ep), path);
+       }
+
+       layout.add_block(*this);
+}
+
+Block::~Block()
+{
+       set<Track *> trks = tracks;
+       tracks.clear();
+       for(set<Track *>::iterator i=trks.begin(); i!=trks.end(); ++i)
+               (*i)->set_block(0);
+
+       for(vector<Endpoint>::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(); ++i)
+               if(endpoints[i].link==&other)
+                       return i;
+
+       return -1;
+}
+
+float Block::get_path_length(unsigned entry, const Route *route) const
+{
+       if(entry>=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<Endpoint>::iterator i=endpoints.begin(); i!=endpoints.end(); ++i)
+       {
+               if(i->link)
+                       continue;
+
+               for(vector<Endpoint>::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<Endpoint>::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<<i))
+               {
+                       TrackIter next = track.next(i);
+                       if(!next)
+                               continue;
+                       else if(has_track(*next))
+                               find_paths(track.next(i), path);
+                       else
+                       {
+                               next = next.flip();
+                               for(vector<Endpoint>::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(id2<id1)
+                       swap(id1, id2);
+               id = (id1<<16)|id2;
+       }
+       else if(endpoints.size()==1)
+       {
+               unsigned id1 = endpoints[0].link ? endpoints[0].link->get_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 (file)
index 0000000..e13e58b
--- /dev/null
@@ -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 <list>
+#include <set>
+#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<Track *> tracks;
+       std::vector<Endpoint> 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<Track *> &get_tracks() const { return tracks; }
+       bool has_track(Track &) const;
+       const std::vector<Endpoint> &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 (file)
index 0000000..db052ac
--- /dev/null
@@ -0,0 +1,125 @@
+/* $Id$
+
+This file is part of R²C²
+Copyright © 2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <msp/core/except.h>
+#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<Block::Endpoint> &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; i<eps.size(); ++i)
+                       if(eps[i].track==t_exit.track() && eps[i].track_ep==t_exit.entry())
+                               return i;
+
+               t_iter = t_exit.flip();
+       }
+
+       return -1;
+}
+
+BlockIter BlockIter::next(const Route *route) const
+{
+       if(!_block)
+               return BlockIter();
+
+       int exit = get_exit(route);
+       if(exit<0)
+               return BlockIter();
+
+       BlockIter result;
+       result._block = _block->get_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 (file)
index 0000000..5c235a5
--- /dev/null
@@ -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 (file)
index 0000000..838b15b
--- /dev/null
@@ -0,0 +1,147 @@
+/* $Id$
+
+This file is part of R²C²
+Copyright © 2006-2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <msp/core/refptr.h>
+#include <msp/datafile/parser.h>
+#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<Catalogue>(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<void (Loader::*)(unsigned)>(&Loader::track));
+       add("track", static_cast<void (Loader::*)(ArticleNumber)>(&Loader::track));
+       add("vehicle", static_cast<void (Loader::*)(unsigned)>(&Loader::vehicle));
+       add("vehicle", static_cast<void (Loader::*)(ArticleNumber)>(&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<TrackType> 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<VehicleType> 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 (file)
index 0000000..c8b006a
--- /dev/null
@@ -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 <map>
+#include <msp/datafile/loader.h>
+#include "articlenumber.h"
+#include "layout.h"
+#include "profile.h"
+
+namespace R2C2 {
+
+class TrackType;
+class VehicleType;
+
+class Catalogue
+{
+public:
+       class Loader: public Msp::DataFile::BasicLoader<Catalogue>
+       {
+       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<ArticleNumber, TrackType *> TrackMap;
+       typedef std::map<ArticleNumber, VehicleType *> VehicleMap;
+
+       sigc::signal<void, const TrackType &> signal_track_added;
+       sigc::signal<void, const VehicleType &> 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 (file)
index 0000000..480abc2
--- /dev/null
@@ -0,0 +1,76 @@
+/* $Id$
+
+This file is part of R²C²
+Copyright © 2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <cmath>
+#include <msp/core/except.h>
+#include "controller.h"
+
+using namespace std;
+using namespace Msp;
+
+namespace R2C2 {
+
+void Controller::Control::set(float v)
+{
+       if(v<min_value)
+               v = min_value;
+       else if(v>max_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<m)
+               throw InvalidParameterValue("Max value must be greater than min value");
+
+       Controller::Control tc;
+       tc.name = n;
+       tc.type = DISCRETE;
+       tc.min_value = m;
+       tc.max_value = m+floor((x-m)/s)*s;
+       tc.step = s;
+       tc.value = m;
+
+       return tc;
+}
+
+Controller::Control Controller::Control::continuous(const string &n, float m, float x)
+{
+       if(x<m)
+               throw InvalidParameterValue("Max value must be greater than min value");
+
+       Controller::Control tc;
+       tc.name = n;
+       tc.type = CONTINUOUS;
+       tc.min_value = m;
+       tc.max_value = x;
+       tc.step = 0;
+       tc.value = m;
+
+       return tc;
+}
+
+} // namespace R2C2
diff --git a/source/libr2c2/controller.h b/source/libr2c2/controller.h
new file mode 100644 (file)
index 0000000..6cabade
--- /dev/null
@@ -0,0 +1,75 @@
+/* $Id$
+
+This file is part of R²C²
+Copyright © 2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#ifndef LIBR2C2_CONTROLLER_H_
+#define LIBR2C2_CONTROLLER_H_
+
+#include <string>
+#include <sigc++/signal.h>
+#include <msp/time/timedelta.h>
+
+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<void, const Control &> 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 (file)
index 0000000..ea903af
--- /dev/null
@@ -0,0 +1,34 @@
+/* $Id$
+
+This file is part of R²C²
+Copyright © 2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <msp/core/except.h>
+#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 (file)
index 0000000..d9d1127
--- /dev/null
@@ -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 <string>
+#include <sigc++/signal.h>
+
+namespace R2C2 {
+
+class Driver
+{
+public:
+       sigc::signal<void, bool> signal_power;
+       sigc::signal<void, bool> signal_halt;
+       sigc::signal<void, unsigned, unsigned, bool> signal_loco_speed;
+       sigc::signal<void, unsigned, unsigned, bool> signal_loco_function;
+       sigc::signal<void, unsigned, bool> signal_turnout;
+       sigc::signal<void, unsigned, bool> 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 (file)
index 0000000..814dce4
--- /dev/null
@@ -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<unsigned, bool>::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<unsigned, bool>::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 (file)
index 0000000..5357bbd
--- /dev/null
@@ -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 <map>
+#include "driver.h"
+
+namespace R2C2 {
+
+class Dummy: public Driver
+{
+private:
+       struct LocoState
+       {
+               unsigned speed;
+               bool reverse;
+       };
+
+       bool power;
+       std::map<unsigned, bool> turnouts;
+       std::map<unsigned, LocoState> locos;
+       std::map<unsigned, bool> 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 (file)
index 0000000..48bbd49
--- /dev/null
@@ -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 <cmath>
+#include <vector>
+
+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 (file)
index 0000000..9ac448e
--- /dev/null
@@ -0,0 +1,706 @@
+/* $Id$
+
+This file is part of R²C²
+Copyright © 2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <fcntl.h>
+#include <termios.h>
+#include <sys/poll.h>
+#include <msp/io/print.h>
+#include <msp/time/units.h>
+#include <msp/time/utils.h>
+#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<unsigned, Locomotive>::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(speed<loco.speed && (speed&1))
+               {
+                       loco.pending_half_step = 1;
+                       speed &= ~1;
+               }
+               else
+                       loco.pending_half_step = 0;
+               loco.half_step_delay = Time::TimeStamp();
+
+               loco_command(addr, (speed+1)/2, loco.reverse, loco.funcs|0x100);
+       }
+       else
+       {
+               if(speed>14)
+                       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<<func;
+       else
+               loco.funcs &= ~(1<<func);
+       loco_command(addr, loco.speed, loco.reverse, loco.funcs);
+       signal_loco_function.emit(addr, func, state);
+}
+
+void Intellibox::add_turnout(unsigned addr)
+{
+       if(!turnouts.count(addr))
+       {
+               turnouts[addr];
+
+               unsigned char data[2];
+               data[0] = addr&0xFF;
+               data[1] = (addr>>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<unsigned, Turnout>::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<unsigned, Sensor>::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<unsigned, Locomotive>::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<unsigned, Turnout>::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<unsigned, Sensor>::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<CommandSlot>::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<count; ++i)
+               {
+                       unsigned char data[2];
+                       read_all(data, 2);
+
+                       unsigned addr = data[0]+((data[1]&7)<<8);
+                       Turnout &turnout = turnouts[addr];
+                       turnout.state = (data[1]&0x80)!=0;
+                       turnout.pending = turnout.state;
+                       signal_turnout.emit(addr, turnout.state);
+               }
+       }
+       else if(cmd==CMD_EVENT_SENSOR)
+       {
+               while(1)
+               {
+                       unsigned char mod;
+                       read_all(&mod, 1);
+                       if(!mod)
+                               break;
+
+                       unsigned char data[2];
+                       read_all(data, 2);
+                       for(unsigned i=0; i<16; ++i)
+                       {
+                               unsigned addr = mod*16+i-15;
+                               bool state = (data[i/8]>>(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<<i))
+                                               signal_loco_function.emit(addr, i, loco.funcs&(1<<i));
+                       }
+               }
+               else
+                       error(cmd, err);
+       }
+       else
+       {
+               unsigned expected_bytes = 0;
+               if(cmd==CMD_FUNC_STATUS)
+                       expected_bytes = 1;
+               if(cmd==CMD_TURNOUT_GROUP_STATUS)
+                       expected_bytes = 2;
+               if(cmd==CMD_LOK_CONFIG)
+                       expected_bytes = 4;
+
+               Error err;
+               read_status(&err);
+
+               if(err==ERR_NO_ERROR)
+               {
+                       unsigned char data[8];
+                       read_all(data, expected_bytes);
+               }
+               else
+                       error(cmd, err);
+       }
+}
+
+unsigned Intellibox::read_all(unsigned char *buf, unsigned len)
+{
+       unsigned pos = 0;
+       while(pos<len)
+               pos += read(serial_fd, buf+pos, len-pos);
+
+       return pos;
+}
+
+unsigned Intellibox::read_status(Error *err)
+{
+       unsigned char c;
+       unsigned ret = read_all(&c, 1);
+       *err = static_cast<Error>(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 (file)
index 0000000..8655bfc
--- /dev/null
@@ -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 <map>
+#include <msp/time/timestamp.h>
+#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<unsigned, Locomotive> locos;
+       std::map<unsigned, Turnout> turnouts;
+       std::map<unsigned, Sensor> sensors;
+       bool update_sensors;
+       std::list<CommandSlot> 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 (file)
index 0000000..1c0d4cf
--- /dev/null
@@ -0,0 +1,351 @@
+/* $Id$
+
+This file is part of R²C²
+Copyright © 2006-2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <algorithm>
+#include <msp/core/refptr.h>
+#include <msp/datafile/parser.h>
+#include <msp/datafile/writer.h>
+#include <msp/io/print.h>
+#include <msp/time/utils.h>
+#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<unsigned> used_ids;
+       for(set<Track *>::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<Block *>::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<Track *> used_tracks;
+       for(set<Block *>::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
+       {
+               const set<Track *> &btracks = (*i)->get_tracks();
+               used_tracks.insert(btracks.begin(), btracks.end());
+       }
+
+       for(set<Track *>::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<Block *>::iterator i=blocks.begin(); i!=blocks.end(); ++i)
+               for(set<Block *>::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<Block *> del_blocks;
+
+       del_blocks.insert(&track.get_block());
+
+       const vector<Track *> &links = track.get_links();
+       for(vector<Track *>::const_iterator i=links.begin(); i!=links.end(); ++i)
+               if(*i)
+                       del_blocks.insert(&(*i)->get_block());
+
+       for(set<Block *>::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<Route *>::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<Route *>::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<unsigned, Train *>::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<unsigned, Train *>::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<Track *>::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<Route *>::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<unsigned, Train *>::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<Block *>::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<Layout>(l),
+       new_tracks(false)
+{
+       add("base",  &Layout::base);
+       add("route", static_cast<void (Loader::*)()>(&Loader::route));
+       add("route", static_cast<void (Loader::*)(const string &)>(&Loader::route));
+       add("track", static_cast<void (Loader::*)(unsigned)>(&Loader::track));
+       add("track", static_cast<void (Loader::*)(ArticleNumber)>(&Loader::track));
+       add("train", static_cast<void (Loader::*)(unsigned, unsigned, const std::string &)>(&Loader::train));
+       add("train", static_cast<void (Loader::*)(ArticleNumber, unsigned, const std::string &)>(&Loader::train));
+}
+
+void Layout::Loader::finish()
+{
+       for(set<Track *>::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<Track *>::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 (file)
index 0000000..86db658
--- /dev/null
@@ -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 <set>
+#include <sigc++/sigc++.h>
+#include <msp/datafile/loader.h>
+#include <msp/time/timestamp.h>
+
+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<Layout>
+       {
+       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<void, Track &> signal_track_added;
+       sigc::signal<void, Track &> signal_track_removed;
+       sigc::signal<void, Route &> signal_route_added;
+       sigc::signal<void, Route &> signal_route_removed;
+       sigc::signal<void, Train &> signal_train_added;
+       sigc::signal<void, Train &> signal_train_removed;
+       sigc::signal<void, Vehicle &> signal_vehicle_added;
+       sigc::signal<void, Vehicle &> signal_vehicle_removed;
+       sigc::signal<void, Block &, Train *> signal_block_reserved;
+       sigc::signal<void, const std::string &> signal_emergency;
+
+private:
+       Catalogue &catalogue;
+       Driver *driver;
+       std::string base;
+       std::set<Track *> tracks;
+       std::set<Route *> routes;
+       std::set<Block *> blocks;
+       std::map<unsigned, Train *> trains;
+       std::set<Vehicle *> 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<Track *> &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<Block *> &get_blocks() const { return blocks; }
+       void create_blocks();
+       void create_blocks(Track &);
+       void remove_block(Block &);
+
+       void add_route(Route &);
+       const std::set<Route *> &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<unsigned, Train *> &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 (file)
index 0000000..b44ee36
--- /dev/null
@@ -0,0 +1,62 @@
+/* $Id$
+
+This file is part of R²C²
+Copyright © 2010 Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <cmath>
+#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<Profile>(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 (file)
index 0000000..00132e9
--- /dev/null
@@ -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 <vector>
+#include <msp/datafile/objectloader.h>
+#include "geometry.h"
+
+namespace R2C2 {
+
+class Profile
+{
+public:
+       class Loader: public Msp::DataFile::ObjectLoader<Profile>
+       {
+       public:
+               Loader(Profile &);
+       private:
+               void point(float, float);
+       };
+
+private:
+       std::vector<Point> 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 (file)
index 0000000..4f7e778
--- /dev/null
@@ -0,0 +1,455 @@
+/* $Id$
+
+This file is part of R²C²
+Copyright © 2007-2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <queue>
+#include <msp/strings/formatter.h>
+#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<Track *, unsigned> 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<Track *> &tracks;
+
+       TrackInSet(const set<Track *> &t): tracks(t) { }
+
+       bool operator()(Track &t) const { return tracks.count(&t); }
+};
+
+template<typename Pred>
+list<Track *> dijkstra(const TrackIter &from, const Pred &goal)
+{
+       map<Key, Node> track_nodes;
+       priority_queue<Node> 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<<i))
+                       {
+                               TrackIter next = lowest.track.next(i);
+                               if(!next)
+                                       continue;
+
+                               if(track_nodes.count(Key(next.track(), next.entry())))
+                                       continue;
+
+                               nodes.push(Node(next, ref, lowest.track->get_type().get_path_length(i)));
+                       }
+       }
+
+       list<Track *> result;
+       for(Node *node=final; node; node=node->prev)
+               result.push_front(&*node->track);
+
+       return result;
+}
+
+template<typename Pred>
+Route *create_route(const TrackIter &from, const Pred &goal)
+{
+       list<Track *> tracks = dijkstra(from, goal);
+
+       if(tracks.empty())
+               return 0;
+
+       Route *route = new Route(from->get_layout());
+       for(list<Track *>::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<unsigned, int>::iterator i = turnouts.find(addr);
+       if(i==turnouts.end())
+               throw KeyError("Turnout is not in this route");
+       if(i->second>=0 && path!=static_cast<unsigned>(i->second))
+               throw InvalidState("Setting conflicts with route");
+       i->second = path;
+}
+
+void Route::update_turnouts()
+{
+       set<unsigned> found;
+       for(set<Track *>::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
+               if(unsigned tid = (*i)->get_turnout_id())
+               {
+                       found.insert(tid);
+
+                       const vector<TrackType::Endpoint> &endpoints = (*i)->get_type().get_endpoints();
+                       const vector<Track *> &links = (*i)->get_links();
+
+                       // Build a combined path mask from linked endpoints
+                       unsigned mask = (*i)->get_type().get_paths();
+                       for(unsigned j=0; j<endpoints.size(); ++j)
+                       {
+                               if(!tracks.count(links[j]))
+                                       continue;
+
+                               if(unsigned tid2 = links[j]->get_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<<p)))
+                                       {
+                                               // The linked track is a turnout and has a path which is incompatible with this endpoint
+                                               mask &= ~endpoints[j].paths;
+                                               continue;
+                                       }
+                               }
+                               mask &= endpoints[j].paths;
+                       }
+
+                       if(mask && !(mask&(mask-1)))
+                       {
+                               // Exactly one possible choice, set the path accordingly
+                               unsigned path = 0;
+                               for(; (mask && !(mask&1)); mask>>=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<unsigned, int>::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<unsigned, int>::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<unsigned, int>::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<Track *> &trks)
+{
+       set<Track *> pending;
+       for(set<Track *>::const_iterator i=trks.begin(); i!=trks.end(); ++i)
+               if(!tracks.count(*i))
+                       pending.insert(*i);
+
+       while(!pending.empty())
+       {
+               bool found = false;
+               for(set<Track *>::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<DataFile::Statement> &st) const
+{
+       st.push_back((DataFile::Statement("name"), name));
+       for(map<unsigned, int>::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<Track *> &links = trk.get_links();
+       for(vector<Track *>::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<<path))
+                                       result |= 2;
+                       }
+                       else
+                       {
+                               // Linked to a turnout with no path set - check other linked tracks 
+                               const vector<Track *> &tlinks = (*i)->get_links();
+                               unsigned count = 0;
+                               for(unsigned j=0; j<tlinks.size(); ++j)
+                                       if(tracks.count(tlinks[j]))
+                                       {
+                                               unsigned tid2 = tlinks[j]->get_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<<path)))
+                                                               continue;
+                                               }
+
+                                               ++count;
+
+                                               const TrackType::Endpoint &ep2 = (*i)->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<Track *> &to)
+{
+       return create_route(from, TrackInSet(to));
+}
+
+
+Route::Loader::Loader(Route &r):
+       DataFile::BasicLoader<Route>(r)
+{
+       add("name",    &Route::name);
+       add("turnout", &Loader::turnout);
+}
+
+void Route::Loader::finish()
+{
+       const set<Track *> &ltracks = obj.layout.get_tracks();
+       for(set<Track *>::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<<j->second;
+               const vector<TrackType::Endpoint> &eps = (*i)->get_type().get_endpoints();
+               for(unsigned k=0; k<eps.size(); ++k)
+                       if(eps[k].paths&path_mask)
+                       {
+                               Track *link = (*i)->get_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 (file)
index 0000000..86a0f61
--- /dev/null
@@ -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 <map>
+#include <set>
+#include <string>
+#include <sigc++/trackable.h>
+#include <msp/datafile/loader.h>
+
+namespace R2C2 {
+
+class Layout;
+class Track;
+class TrackIter;
+
+class Route: public sigc::trackable
+{
+public:
+       typedef std::map<unsigned, int> TurnoutMap;
+
+       class Loader: public Msp::DataFile::BasicLoader<Route>
+       {
+       private:
+               TurnoutMap turnouts;
+
+       public:
+               Loader(Route &);
+       private:
+               virtual void finish();
+               void turnout(unsigned, unsigned);
+       };
+
+       sigc::signal<void, const std::string &> signal_name_changed;
+
+private:
+       Layout &layout;
+       std::string name;
+       bool temporary;
+       std::set<Track *> 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<unsigned, int> &get_turnouts() const { return turnouts; }
+       void add_track(Track &);
+       void add_tracks(const std::set<Track *> &);
+       void add_track_chain(Track &, unsigned, const TurnoutMap &);
+       const std::set<Track *> &get_tracks() const { return tracks; }
+       bool has_track(Track &) const;
+       void save(std::list<Msp::DataFile::Statement> &) 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<Track *> &);
+};
+
+} // namespace R2C2
+
+#endif
diff --git a/source/libr2c2/simplecontroller.cpp b/source/libr2c2/simplecontroller.cpp
new file mode 100644 (file)
index 0000000..7f8b336
--- /dev/null
@@ -0,0 +1,74 @@
+/* $Id$
+
+This file is part of R²C²
+Copyright © 2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <msp/core/except.h>
+#include <msp/time/units.h>
+#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(speed<target_speed.value)
+       {
+               speed += secs*accel;
+               if(speed>target_speed.value)
+                       speed = target_speed.value;
+       }
+       else if(speed>target_speed.value)
+       {
+               speed -= secs*accel;
+               if(speed<target_speed.value)
+                       speed = target_speed.value;
+       }
+}
+
+} // namespace R2C2
diff --git a/source/libr2c2/simplecontroller.h b/source/libr2c2/simplecontroller.h
new file mode 100644 (file)
index 0000000..140f13d
--- /dev/null
@@ -0,0 +1,39 @@
+/* $Id$
+
+This file is part of R²C²
+Copyright © 2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#ifndef LIBR2C2_SIMPLECONTROLLER_H_
+#define LIBR2C2_SIMPLECONTROLLER_H_
+
+#include <string>
+#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 (file)
index 0000000..bc8ebe6
--- /dev/null
@@ -0,0 +1,337 @@
+/* $Id$
+
+This file is part of R²C²
+Copyright © 2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <msp/strings/formatter.h>
+#include <msp/time/units.h>
+#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<string>(0)).get_tracks().begin()))
+                               set_enabled(false);
+                       break;
+               case TRAVEL:
+                       pending_block = &parse_location(row.get_param<string>(0));
+                       pending_train = &train;
+                       executing = false;
+                       break;
+               case WAIT_TIME:
+                       wait_timeout = t+row.get_param<unsigned>(0)*Time::sec;
+                       executing = false;
+                       break;
+               case WAIT_TRAIN:
+                       pending_train = &train.get_layout().get_train(row.get_param<unsigned>(0));
+                       pending_block = &parse_location(row.get_param<string>(1));
+                       executing = false;
+                       break;
+               case ARRIVE:
+                       executing = false;
+                       break;
+               case SPEED:
+                       train.set_control("speed", row.get_param<unsigned>(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<string>(0))))
+                               set_enabled(false);
+                       break;
+               }
+
+               if(executing)
+                       current_row = (current_row+1)%rows.size();
+       }
+}
+
+void Timetable::save(list<DataFile::Statement> &st) const
+{
+       for(vector<Row>::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<unsigned>(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<typename T>
+Timetable::Row::Row(RowType t, const T &p):
+       type(t)
+{
+       params.push_back(p);
+}
+
+template<typename T>
+const T &Timetable::Row::get_param(unsigned i) const
+{
+       if(i>=params.size())
+               throw InvalidParameterValue("Parameter index out of range");
+       return params[i].value<T>();
+}
+
+string Timetable::Row::str() const
+{
+       switch(type)
+       {
+       case GOTO:
+               return "set route to "+get_param<string>(0);
+       case TRAVEL:
+               return "travel to "+get_param<string>(0);
+       case WAIT_TIME:
+               return format("wait for %d seconds", get_param<unsigned>(0));
+       case WAIT_TRAIN:
+               return format("wait for train %d at %s", get_param<unsigned>(0), get_param<string>(1));
+       case ARRIVE:
+               return "travel until arrival";
+       case SPEED:
+               return format("set speed %d km/h", get_param<unsigned>(0));
+       case REVERSE:
+               return "reverse";
+       case ROUTE:
+               return "set route "+get_param<string>(0);
+       default:
+               return "invalid row";
+       }
+}
+
+DataFile::Statement Timetable::Row::save() const
+{
+       switch(type)
+       {
+       case GOTO:
+               return DataFile::Statement("goto"), get_param<string>(0);
+       case TRAVEL:
+               return DataFile::Statement("travel"), get_param<string>(0);
+       case WAIT_TIME:
+               return DataFile::Statement("wait"), get_param<unsigned>(0);
+       case WAIT_TRAIN:
+               return DataFile::Statement("wait_train"), get_param<unsigned>(0), get_param<string>(1);
+       case ARRIVE:
+               return DataFile::Statement("arrive");
+       case SPEED:
+               return DataFile::Statement("speed"), get_param<unsigned>(0);
+       case REVERSE:
+               return DataFile::Statement("reverse");
+       case ROUTE:
+               return DataFile::Statement("route"), get_param<string>(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.size() && isdigit(s[nondigit]))
+                               ++nondigit;
+                       return Row(WAIT_TIME, lexical_cast<unsigned>(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<unsigned>(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.size() && (isdigit(s[nondigit]) || s[nondigit]=='-'))
+                       ++nondigit;
+               return Row(SPEED, lexical_cast<unsigned>(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<Timetable>(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 (file)
index 0000000..9cfda68
--- /dev/null
@@ -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 <string>
+#include <vector>
+#include <sigc++/trackable.h>
+#include <msp/datafile/objectloader.h>
+#include <msp/time/timestamp.h>
+
+namespace R2C2 {
+
+class Block;
+class Train;
+
+class Timetable: public sigc::trackable
+{
+public:
+       class Loader: public Msp::DataFile::ObjectLoader<Timetable>
+       {
+       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<Msp::Variant> params;
+
+               Row(RowType);
+
+               template<typename T>
+               Row(RowType, const T &);
+
+               template<typename T>
+               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<Row> 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<Msp::DataFile::Statement> &) 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 (file)
index 0000000..0592731
--- /dev/null
@@ -0,0 +1,392 @@
+/* $Id$
+
+This file is part of R²C²
+Copyright © 2006-2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <cmath>
+#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<<p)))
+               throw InvalidParameterValue("Invalid path");
+
+       layout.get_driver().set_turnout(turnout_id, p&1);
+       if(type.is_double_address())
+               layout.get_driver().set_turnout(turnout_id+1, p&2);
+       else if(type.get_n_paths()>2)
+               active_path = (active_path&1) | (p&2);
+}
+
+int Track::get_endpoint_by_link(Track &other) const
+{
+       for(unsigned i=0; i<links.size(); ++i)
+               if(links[i]==&other)
+                       return i;
+
+       return -1;
+}
+
+Point Track::get_endpoint_position(unsigned epi) const
+{
+       const vector<TrackType::Endpoint> &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<TrackType::Endpoint> &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<TrackType::Endpoint> &eps = type.get_endpoints();
+       const vector<TrackType::Endpoint> &other_eps = other.get_type().get_endpoints();
+
+       for(unsigned i=0; i<eps.size(); ++i)
+       {
+               Point epp = get_endpoint_position(i);
+
+               for(unsigned j=0; j<other_eps.size(); ++j)
+               {
+                       if(other.get_link(j))
+                               continue;
+
+                       Point epp2 = other.get_endpoint_position(j);
+                       float dx = epp2.x-epp.x;
+                       float dy = epp2.y-epp.y;
+                       float dz = epp2.z-epp.z;
+                       if(dx*dx+dy*dy<limit && dz*dz<limit)
+                       {
+                               if(!link || (!flex && !other.get_flex()))
+                               {
+                                       set_rotation(other.rot+other_eps[j].dir-eps[i].dir+M_PI);
+                                       Point p(epp2.x-(eps[i].pos.x*cos(rot)-eps[i].pos.y*sin(rot)),
+                                               epp2.y-(eps[i].pos.y*cos(rot)+eps[i].pos.x*sin(rot)),
+                                               epp2.z);
+                                       if(eps.size()==2 && i==1)
+                                               p.z -= slope;
+                                       set_position(p);
+                               }
+
+                               if(link)
+                               {
+                                       if(links[i])
+                                               break_link(*links[i]);
+                                       links[i] = &other;
+                                       other.links[j] = this;
+                                       layout.create_blocks(*this);
+                               }
+
+                               return true;
+                       }
+               }
+       }
+
+       return false;
+}
+
+bool Track::snap(Point &pt, float &d) const
+{
+       const vector<TrackType::Endpoint> &eps = type.get_endpoints();
+
+       for(unsigned i=0; i<eps.size(); ++i)
+       {
+               Point epp = get_endpoint_position(i);
+               float dx = pt.x-epp.x;
+               float dy = pt.y-epp.y;
+               if(dx*dx+dy*dy<1e-4)
+               {
+                       pt = epp;
+                       d = rot+eps[i].dir;
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+void Track::break_link(Track &trk)
+{
+       for(vector<Track *>::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<Track *>::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<DataFile::Statement> &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<Track>(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 (file)
index 0000000..95f9023
--- /dev/null
@@ -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 <list>
+#include <set>
+#include <sigc++/trackable.h>
+#include <msp/datafile/loader.h>
+#include "geometry.h"
+
+namespace R2C2 {
+
+class Block;
+class Layout;
+class TrackType;
+
+class Track: public sigc::trackable
+{
+public:
+       class Loader: public Msp::DataFile::BasicLoader<Track>
+       {
+       public:
+               Loader(Track &);
+       private:
+               void position(float, float, float);
+               void sensor_id(unsigned);
+               void turnout_id(unsigned);
+       };
+
+       sigc::signal<void, unsigned> 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<Track *> 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<Track *> &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<Msp::DataFile::Statement> &) 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 (file)
index 0000000..3c6295b
--- /dev/null
@@ -0,0 +1,171 @@
+/* $Id$
+
+This file is part of R²C²
+Copyright © 2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <algorithm>
+#include <msp/core/except.h>
+#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<TrackType::Endpoint> &eps = _track->get_type().get_endpoints();
+       
+       // Find an endpoint that's connected to the entry and has the requested path
+       for(unsigned i=0; i<eps.size(); ++i)
+               if(i!=_entry && (eps[i].paths&(1<<path)) && (eps[i].paths&eps[_entry].paths))
+                       return i;
+
+       return -1;
+}
+
+TrackIter TrackIter::next() const
+{
+       if(!_track)
+               return TrackIter();
+
+       return next(_track->get_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<TrackList> 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 (file)
index 0000000..1dce02a
--- /dev/null
@@ -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 <set>
+#include <msp/core/refptr.h>
+#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<Track *> TrackList;
+
+       Msp::RefPtr<TrackList> _visited;
+       TrackList::iterator _last;
+       bool _looped;
+
+public:
+       TrackLoopIter();
+       TrackLoopIter(Track *, unsigned);
+       TrackLoopIter(const TrackIter &);
+private:
+       TrackLoopIter(const TrackIter &, Msp::RefPtr<TrackList>, 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 (file)
index 0000000..af2cf37
--- /dev/null
@@ -0,0 +1,127 @@
+/* $Id$
+
+This file is part of R²C²
+Copyright © 2006-2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <cmath>
+#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; i<n_eps; ++i)
+       {
+               TrackPoint p1 = get_point(i ? get_length() : 0);
+               for(unsigned j=0; j<n_other_eps; ++j)
+               {
+                       TrackPoint p2 = other.get_point(j ? other.get_length() : 0);
+
+                       float dx = p2.pos.x-p1.pos.x;
+                       float dy = p2.pos.y-p1.pos.y;
+
+                       float da = p2.dir-p1.dir+M_PI*((i+j+1)%2);
+                       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)
+                       {
+                               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<TrackPart>(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 (file)
index 0000000..0a07b4d
--- /dev/null
@@ -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 <msp/datafile/loader.h>
+#include "geometry.h"
+
+namespace R2C2 {
+
+class TrackPart
+{
+public:
+       class Loader: public Msp::DataFile::BasicLoader<TrackPart>
+       {
+       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 (file)
index 0000000..4ac0967
--- /dev/null
@@ -0,0 +1,194 @@
+/* $Id$
+
+This file is part of R²C²
+Copyright © 2006-2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <cmath>
+#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<TrackPart>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
+               if(p<0 || i->get_path()==static_cast<unsigned>(p))
+                       len += i->get_length();
+       return len;
+}
+
+unsigned TrackType::get_paths() const
+{
+       unsigned mask = 0;
+       for(vector<TrackPart>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
+               mask |= 1<<i->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<TrackPart>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
+       {
+               if((endpoints[epi].paths&(1<<path)) && i->get_path()!=path)
+                       continue;
+
+               unsigned n_part_eps = (i->is_dead_end() ? 1 : 2);
+               for(unsigned j=0; j<n_part_eps; ++j)
+               {
+                       TrackPoint p = i->get_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<TrackPart>::iterator i=parts.begin(); i!=parts.end(); ++i)
+       {
+               for(vector<TrackPart>::iterator j=i; ++j!=parts.end();)
+                       i->check_link(*j);
+
+               unsigned n_part_eps = (i->is_dead_end() ? 1 : 2);
+               for(unsigned j=0; j<n_part_eps; ++j)
+                       if(!i->get_link(j))
+                       {
+                               TrackPoint p = i->get_point(j ? i->get_length() : 0);
+                               if(j==0)
+                                       p.dir += M_PI;
+
+                               bool found = false;
+                               for(vector<Endpoint>::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<<i->get_path();
+                                               found = true;
+                                               break;
+                                       }
+                               }
+
+                               if(!found)
+                                       endpoints.push_back(Endpoint(p.pos.x, p.pos.y, p.dir, 1<<i->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<TrackType>(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 (file)
index 0000000..d38f1b2
--- /dev/null
@@ -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 <msp/datafile/loader.h>
+#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<TrackType>
+       {
+       public:
+               Loader(TrackType &);
+       private:
+               virtual void finish();
+               void part();
+               void position(float, float, float);
+       };
+
+private:
+       ArticleNumber art_nr;
+       std::string description;
+       std::vector<TrackPart> parts;
+       std::vector<Endpoint> 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<TrackPart> &get_parts() const { return parts; }
+       const std::vector<Endpoint> &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 (file)
index 0000000..dd7139f
--- /dev/null
@@ -0,0 +1,1420 @@
+/* $Id$
+
+This file is part of R²C²
+Copyright © 2006-2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <cmath>
+#include <msp/strings/formatter.h>
+#include <msp/time/units.h>
+#include <msp/time/utils.h>
+#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<Track *> &tracks = layout.get_tracks();
+       for(set<Track *>::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<Vehicle *>::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(i<vehicles.size())
+               vehicles[i-1]->attach_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<RouteRef>::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<<i)) && i!=route_path)
+                               {
+                                       path = i;
+                                       break;
+                               }
+
+                       entry = track.entry();
+                       break;
+               }
+
+               track = track.next(route->route->get_path(*track));
+
+               if(!track || track.looped())
+                       return false;
+       }
+
+       TrackIter track = TrackIter(&from, entry).next(path);
+       if(!track)
+               return false;
+
+       set<Track *> tracks;
+       for(list<RouteRef>::iterator i=routes.begin(); i!=routes.end(); ++i)
+               tracks.insert(i->route->get_tracks().begin(), i->route->get_tracks().end());
+       RefPtr<Route> 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<RouteRef>::iterator end = routes.end();
+       while(1)
+       {
+               for(list<RouteRef>::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<Vehicle *>::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)<controller->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<DataFile::Statement> &st) const
+{
+       st.push_back((DataFile::Statement("name"), name));
+
+       st.push_back((DataFile::Statement("priority"), priority));
+
+       for(vector<Vehicle *>::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; i<real_speed.size(); ++i)
+               if(real_speed[i].weight)
+                       st.push_back((DataFile::Statement("real_speed"), i, real_speed[i].speed, real_speed[i].weight));
+
+       if(!blocks.empty() && cur_blocks_end!=blocks.begin())
+       {
+               BlockList blks(blocks.begin(), BlockList::const_iterator(cur_blocks_end));
+               if(reverse)
+                       reverse_blocks(blks);
+
+               BlockIter prev = blks.front().flip();
+               st.push_back((DataFile::Statement("block_hint"), prev->get_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<RouteRef>::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<<func;
+               else
+                       functions &= ~(1<<func);
+
+               signal_function_changed.emit(func, state);
+       }
+}
+
+void Train::sensor_event(unsigned addr, bool state)
+{
+       if(state)
+       {
+               // Find the first sensor block from our reserved blocks that isn't this sensor
+               BlockList::iterator end;
+               unsigned result = 0;
+               for(end=cur_blocks_end; end!=blocks.end(); ++end)
+                       if((*end)->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<BlockIter>::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<RouteRef>::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<BlockIter>::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<unsigned>(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_prio<priority)
+                       {
+                               /* Ask a lesser priority train going to the same direction to free
+                               the block for us */
+                               if(other_train->free_block(*block))
+                                       reserved = block->reserve(this);
+                       }
+                       else if(other_train!=yielding_to && (other_prio<priority || (other_prio==priority && entry_conflict)))
+                       {
+                               /* A lesser priority train is coming at us, we must ask it to free
+                               enough blocks to get clear of it to avoid a potential deadlock */
+                               blocking_train = other_train;
+                               contested_blocks.clear();
+                               contested_blocks.push_back(block);
+                               continue;
+                       }
+                       else if(divert_track && (entry_conflict || exit_conflict))
+                               // We are blocked, but there's a diversion possibility
+                               try_divert = true;
+
+                       if(!reserved)
+                       {
+                               pending_block = &*block;
+                               break;
+                       }
+               }
+
+               if(block->get_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<BlockIter>::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<BlockIter>::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<real_speed.size(); ++high)
+               if(real_speed[high].weight)
+                       break;
+
+       if(real_speed[high].weight)
+       {
+               if(real_speed[low].weight)
+               {
+                       float f = float(i-low)/(high-low);
+                       return real_speed[low].speed*(1-f)+real_speed[high].speed*f;
+               }
+               else
+                       return real_speed[high].speed*float(i)/high;
+       }
+       else if(real_speed[low].weight)
+               return real_speed[low].speed*float(i)/low;
+       else
+               return 0;
+}
+
+unsigned Train::find_speed_step(float real) const
+{
+       if(real_speed.size()<=1)
+               return 0;
+       if(real<=real_speed[1].speed*0.5)
+               return 0;
+
+       unsigned low = 0;
+       unsigned high = 0;
+       unsigned last = 0;
+       for(unsigned i=0; (!high && i<real_speed.size()); ++i)
+               if(real_speed[i].weight)
+               {
+                       last = i;
+                       if(real_speed[i].speed<real)
+                               low = i;
+                       else
+                               high = i;
+               }
+       if(!high)
+       {
+               unsigned limit = real_speed.size()/5;
+               if(!low)
+               {
+                       if(real)
+                               return limit;
+                       else
+                               return 0;
+               }
+               return min(min(static_cast<unsigned>(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<unsigned>(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<int>(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<RouteRef>::iterator &iter, Track &track)
+{
+       while(iter!=routes.end() && !iter->route->has_track(track))
+               ++iter;
+       if(iter==routes.end())
+               return false;
+
+       list<RouteRef>::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<Track *> tracks;
+       for(BlockList::iterator i=blocks.begin(); i!=blocks.end(); ++i)
+       {
+               const set<Track *> &btracks = (*i)->get_tracks();
+               for(set<Track *>::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<RouteRef>::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<route_len*1.2;
+}
+
+
+Train::RouteRef::RouteRef(const Route *r, unsigned d):
+       route(r),
+       diversion(d)
+{ }
+
+
+Train::RealSpeed::RealSpeed():
+       speed(0),
+       weight(0)
+{ }
+
+void Train::RealSpeed::add(float s, float w)
+{
+       speed = (speed*weight+s*w)/(weight+w);
+       weight = min(weight+w, 300.0f);
+}
+
+
+Train::Loader::Loader(Train &t):
+       DataFile::BasicLoader<Train>(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 (file)
index 0000000..99575bf
--- /dev/null
@@ -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 <sigc++/signal.h>
+#include <sigc++/trackable.h>
+#include <msp/time/timestamp.h>
+#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<Train>
+       {
+       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<void, const std::string &> signal_name_changed;
+       sigc::signal<void, const std::string &, float> signal_control_changed;
+       sigc::signal<void, unsigned, bool> signal_function_changed;
+       sigc::signal<void, const Route *> signal_route_changed;
+       sigc::signal<void> signal_arrived;
+       sigc::signal<void, const std::string &> 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<BlockIter> BlockList;
+
+       Layout &layout;
+       const VehicleType &loco_type;
+       unsigned address;
+       std::string protocol;
+       std::string name;
+       int priority;
+       const Train *yielding_to;
+       std::vector<Vehicle *> 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<RouteRef> routes;
+       bool end_of_route;
+       std::string status;
+
+       Msp::Time::TimeStamp last_entry_time;
+       float travel_dist;
+       bool pure_speed;
+       std::vector<RealSpeed> 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<Msp::DataFile::Statement> &) 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<RouteRef>::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 (file)
index 0000000..e0a5c96
--- /dev/null
@@ -0,0 +1,364 @@
+/* $Id$
+
+This file is part of R²C²
+Copyright © 2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <cmath>
+#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<VehicleType::Axle> &axles = type.get_axles();
+       const vector<VehicleType::Bogie> &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<VehicleType::Axle> &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<VehicleType::Axle> &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(dist<tdist-margin || dist>tdist+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 (file)
index 0000000..ec33ede
--- /dev/null
@@ -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<float> 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 (file)
index 0000000..3d695f8
--- /dev/null
@@ -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<VehicleType>(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<Axle>(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<Bogie>(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 (file)
index 0000000..b97fb92
--- /dev/null
@@ -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 <msp/datafile/objectloader.h>
+#include "articlenumber.h"
+
+namespace R2C2 {
+
+class VehicleType
+{
+public:
+       class Loader: public Msp::DataFile::ObjectLoader<VehicleType>
+       {
+       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<Axle>
+               {
+               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<Bogie>
+               {
+               public:
+                       Loader(Bogie &);
+               private:
+                       void axle();
+                       void position(float);
+               };
+
+               float position;
+               std::vector<Axle> axles;
+               std::string object;
+               bool rotate_object;
+
+               Bogie();
+       };
+
+private:
+       ArticleNumber art_nr;
+       std::string name;
+       bool locomotive;
+       std::map<unsigned, std::string> functions;
+       float length;
+       float width;
+       float height;
+       std::vector<Axle> axles;
+       std::vector<Bogie> 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<unsigned, std::string> &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<Axle> &get_axles() const { return axles; }
+       const std::vector<Bogie> &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
index 50db7df6d817bdcbb738e4182262de9df2fd275f..d418b8cad92c719d7d0a5f0cb217b8ee6ba89fea 100644 (file)
@@ -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
index 2ab8722f1eb8f24dca84c2e223904b30295ee327..02295dfa32690aeb9a2d2610269fd4132ce83254 100644 (file)
@@ -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 <msp/io/eventdispatcher.h>
 #include <msp/net/communicator.h>
-#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<TrainInfoPacket>,
        Msp::Net::PacketReceiver<TrainFunctionPacket>,
@@ -64,6 +64,6 @@ private:
        virtual void receive(const ErrorPacket &);
 };
 
-} // namespace Marklin
+} // namespace R2C2
 
 #endif
index bb08941b49b1235d0e9529e57304e7126ded99b2..8001b8c1baa721beab957a34459e843d3c063219 100644 (file)
@@ -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 <string>
 
-namespace Marklin {
+namespace R2C2 {
 
 struct TrainInfoPacket
 {
@@ -54,6 +54,6 @@ struct ErrorPacket
        std::string message;
 };
 
-} // namespace Marklin
+} // namespace R2C2
 
 #endif
index 623eadb334eff2b89666c085333fb63af516be9c..cfbc0fdc2a1eac66c53205ef8475468129f33a60 100644 (file)
@@ -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>() (&ErrorPacket::message);
 }
 
-} // namespace Marklin
+} // namespace R2C2
index 176fdad9e70cc12e62b71963383864bf646954df..7ed85fe5030e2e60a15a0a5ad05e98bf8bc1ef82 100644 (file)
@@ -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 <msp/net/protocol.h>
 
-namespace Marklin {
+namespace R2C2 {
 
 class Protocol: public Msp::Net::Protocol
 {
@@ -18,6 +18,6 @@ public:
        Protocol();
 };
 
-} // namespace Marklin
+} // namespace R2C2
 
 #endif
index 2bf641297309ad2e3a5ba304f6502af00fbc6fad..404faa94a6fa83826f46403fd7ff08110d1d231d 100644 (file)
@@ -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 <msp/net/inet.h>
-#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
index 056b0dd089d0c5b2b285136167834f8f81c0947a..ced08aac06eb2df544a9dd8e741cf6cdcfc75e2f 100644 (file)
@@ -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 <msp/io/eventdispatcher.h>
 #include <msp/net/communicator.h>
 #include <msp/net/streamsocket.h>
 #include <msp/net/streamlistensocket.h>
-#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
index 4b6c8e86e1233955d3d4d04b19b6e1d27c522670..df9367e2062366140c166e5c5fd43de4b8e75b5f 100644 (file)
@@ -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
index 3de4f7d38303bc067f55f4a83a1e070f01ccc07a..bffa8a24fbdff372130c822d6abaf363f7e7cf0b 100644 (file)
@@ -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 <sigc++/signal.h>
-#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
index a193b2bf599ef87507fa9aedc037c4572c7a3c10..830a06d05a2f3fc07eb624718629c45772a1f5aa 100644 (file)
@@ -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())
index 6d6be3377aa1f1cc71ffb2b4407c88335f0ee03e..0d6d413d2e2db93ff38a6874a1cbfba1c9f34797 100644 (file)
@@ -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
index b170edc5ff8e4df910fae410f32543b525d61069..cfe0c10fea9f609e8969acc9c8137dcedce3f655 100644 (file)
@@ -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)
index e1464e36331f4bd8923d141644a146ce3eeb7ea8..816d2a091f44bed6307fd1f69e70b6c5aa4eae28 100644 (file)
@@ -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<unsigned, Gtk::CheckButton *> 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 &);
index 4b94034f0354d9c535ff3016b8617bbc7e5c78c3..e812a9931a5ea42f934c3df56e803328a045cf9c 100644 (file)
@@ -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> Serial::reg;
 
index e03bb50d08c5e95bfc132d93957894b72067261c..b40a0b9136221746e1d2bd8f8fbdfc850356d3f4 100644 (file)
@@ -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();
index 2b8f5bf00abd7249768b37f5526f2b1cbd87ec79..8390a264bad8acccfdf4ed1f32b0297c750c2a71 100644 (file)
@@ -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 <msp/datafile/loader.h>
 #include <msp/datafile/parser.h>
 #include <msp/io/print.h>
-#include "libmarklin/articlenumber.h"
+#include "libr2c2/articlenumber.h"
 
 using namespace std;
 using namespace Msp;
-using namespace Marklin;
+using namespace R2C2;
 
 class ShoppingList: public Application
 {