From 208c989c5374746c006bac7ca39579b3a4208f96 Mon Sep 17 00:00:00 2001 From: Matteo Cypriani Date: Fri, 2 Apr 2010 15:49:22 +0200 Subject: [PATCH] [Positioning] Add InputDataReader & TopologyReaderCSV InputDataReader handles all data input, i.e. data needed to prepare computation (topology, calibration measurements, etc.). TopologyReaderCSV reads topology from a CSV file (just Building and Area for the moment). cfg/topo.csv: change format (add building name and reorder coordinates). UserInterface: add data input options. posexcept: add data input exceptions. --- owlps-positioning/Makefile | 14 ++++ owlps-positioning/TODO | 1 + owlps-positioning/cfg/topo.csv | 68 +++++++-------- owlps-positioning/src/inputdatareader.cc | 50 +++++++++++ owlps-positioning/src/inputdatareader.hh | 17 ++++ owlps-positioning/src/owlps-positioning.cc | 5 +- owlps-positioning/src/posexcept.cc | 20 +++++ owlps-positioning/src/posexcept.hh | 26 ++++++ owlps-positioning/src/topologyreadercsv.cc | 60 ++++++++++++++ owlps-positioning/src/topologyreadercsv.hh | 30 +++++++ owlps-positioning/src/userinterface.cc | 22 +++++ owlps-positioning/src/userinterface.hh | 1 + .../tests/inputdatareader_test.hh | 15 ++++ .../tests/topologyreadercsv_test.hh | 83 +++++++++++++++++++ 14 files changed, 376 insertions(+), 36 deletions(-) create mode 100644 owlps-positioning/src/inputdatareader.cc create mode 100644 owlps-positioning/src/inputdatareader.hh create mode 100644 owlps-positioning/src/topologyreadercsv.cc create mode 100644 owlps-positioning/src/topologyreadercsv.hh create mode 100644 owlps-positioning/tests/inputdatareader_test.hh create mode 100644 owlps-positioning/tests/topologyreadercsv_test.hh diff --git a/owlps-positioning/Makefile b/owlps-positioning/Makefile index ca02073..a113c83 100644 --- a/owlps-positioning/Makefile +++ b/owlps-positioning/Makefile @@ -57,6 +57,8 @@ OBJ_LIST = \ realposition.o \ configuration.o \ userinterface.o \ + inputdatareader.o \ + topologyreadercsv.o \ textfilereader.o \ csvfilereader.o \ textfilewriter.o \ @@ -109,8 +111,19 @@ $(OBJ_DIR)/%.o: $(SRC_DIR)/%.cc $(SRC_DIR)/%.hh $(LD) $(LDFLAGS) -o $@ $^ # Dependencies +$(OBJ_DIR)/owlps-positioning.o: \ + $(OBJ_DIR)/userinterface.o \ + $(OBJ_DIR)/inputdatareader.o \ + $(OBJ_DIR)/stock.o \ + $(OBJ_DIR)/positioning.o $(OBJ_DIR)/userinterface.o: \ $(OBJ_DIR)/configuration.o +$(OBJ_DIR)/inputdatareader.o: \ + $(OBJ_DIR)/topologyreadercsv.o \ + $(OBJ_DIR)/configuration.o \ + $(OBJ_DIR)/posexcept.o +$(OBJ_DIR)/topologyreadercsv.o: \ + $(OBJ_DIR)/textfilereader.o $(OBJ_DIR)/referencepoint.o: \ $(OBJ_DIR)/point3d.o $(OBJ_DIR)/waypoint.o: \ @@ -184,6 +197,7 @@ $(OBJ_DIR)/realposition.o: \ $(OBJ_DIR)/calibrationrequest.o \ $(OBJ_DIR)/referencepoint.o $(OBJ_DIR)/positioning.o: \ + $(OBJ_DIR)/inputdatareader.o \ $(OBJ_DIR)/input.o \ $(OBJ_DIR)/realposition.o \ $(OBJ_DIR)/output.o \ diff --git a/owlps-positioning/TODO b/owlps-positioning/TODO index 7512320..21ac4e9 100644 --- a/owlps-positioning/TODO +++ b/owlps-positioning/TODO @@ -1,5 +1,6 @@ - Tests unitaires + ° Finir le test de InputDataReader. ° Finir le test de Input. ° Finir le test de Output. ° Finir le test de Positioning. diff --git a/owlps-positioning/cfg/topo.csv b/owlps-positioning/cfg/topo.csv index 34a362c..2c606d2 100644 --- a/owlps-positioning/cfg/topo.csv +++ b/owlps-positioning/cfg/topo.csv @@ -1,48 +1,48 @@ -# Liste des zones homogènes du bâtiment (pièces). +# Liste des bâtiments et de leurs zones homogènes (pièces). # Chaque ligne définit une zone, de la forme : -# Nom de la pièce;X1;Y1;X2;Y2;Z1;Z2 +# Nom du bâtiment;Nom de la pièce;X1;Y1;X2;Y2;Z1;Z2 ### Rez-de-chaussée ### # -0140;1.00;7.28;6.05;3.70;0.00;2.99 -0130;1.00;10.88;6.05;7.28;0.00;2.99 -0120;1.00;14.48;6.05;10.88;0.00;2.99 -0110;1.00;18.12;6.05;14.48;0.00;2.99 -0100;1.00;21.66;6.05;18.12;0.00;2.99 -0090;1.00;25.32;6.05;21.66;0.00;2.99 -0080;1.00;29.00;6.05;25.32;0.00;2.99 -0070;1.00;32.00;6.05;29.00;0.00;2.99 -WC N0;8.20;5.30;10.00;0.50;0.00;2.99 -0085;8.20;9.00;10.00;5.30;0.00;2.99 -0075;8.20;10.88;10.00;9.00;0.00;2.99 -Palier N0;5.00;3.70;8.20;0.50;0.00;2.99 -Couloir N0 A;6.05;30.00;8.20;3.70;0.00;2.99 -Couloir N0 B;8.20;16.50;10.00;10.88;0.00;2.99 -Couloir N0 C;8.20;24.80;10.00;22.60;0.00;2.99 +Numerica;0140;1.00;7.28;6.05;3.70;0.00;2.99 +Numerica;0130;1.00;10.88;6.05;7.28;0.00;2.99 +Numerica;0120;1.00;14.48;6.05;10.88;0.00;2.99 +Numerica;0110;1.00;18.12;6.05;14.48;0.00;2.99 +Numerica;0100;1.00;21.66;6.05;18.12;0.00;2.99 +Numerica;0090;1.00;25.32;6.05;21.66;0.00;2.99 +Numerica;0080;1.00;29.00;6.05;25.32;0.00;2.99 +Numerica;0070;1.00;32.00;6.05;29.00;0.00;2.99 +Numerica;WC N0;8.20;5.30;10.00;0.50;0.00;2.99 +Numerica;0085;8.20;9.00;10.00;5.30;0.00;2.99 +Numerica;0075;8.20;10.88;10.00;9.00;0.00;2.99 +Numerica;Palier N0;5.00;3.70;8.20;0.50;0.00;2.99 +Numerica;Couloir N0 A;6.05;30.00;8.20;3.70;0.00;2.99 +Numerica;Couloir N0 B;8.20;16.50;10.00;10.88;0.00;2.99 +Numerica;Couloir N0 C;8.20;24.80;10.00;22.60;0.00;2.99 ### Escaliers N0 / N1 ### # # TODO : affiner la hauteur, etc. -Escalier N0-N1 A;8.20;22.60;10.00;16.50;0.00;6.00 -Escalier N0-N1 B1;2.50;2.00;5.00;0.50;0.00;6.00 -Escalier N0-N1 B palier;1.00;3.70;2.50;0.50;1.50;6.00 -Escalier N0-N1 B2;2.50;3.70;5.00;2.00;1.50;6.00 +Numerica;Escalier N0-N1 A;8.20;22.60;10.00;16.50;0.00;6.00 +Numerica;Escalier N0-N1 B1;2.50;2.00;5.00;0.50;0.00;6.00 +Numerica;Escalier N0-N1 B palier;1.00;3.70;2.50;0.50;1.50;6.00 +Numerica;Escalier N0-N1 B2;2.50;3.70;5.00;2.00;1.50;6.00 ### Premier étage ### # -1100;1.00;7.28;6.05;3.70;3.00;6.00 -0190;1.00;10.88;6.05;7.28;3.00;6.00 -0180;1.00;14.48;6.05;10.88;3.00;6.00 -1070;1.00;18.12;6.05;14.48;3.00;6.00 -1060;1.00;25.32;6.05;18.12;3.00;6.00 -1050;1.00;31.40;6.05;25.32;3.00;6.00 -WC N1;8.20;9.00;10.00;0.50;3.00;6.00 -1105;8.20;10.88;10.00;9.00;3.00;6.00 -1095;8.20;29.30;10.00;24.80;3.00;6.00 -Palier N1;5.00;3.70;8.20;0.50;3.00;6.00 -Couloir N1 A;6.05;29.50;8.20;3.70;3.00;6.00 -Couloir N1 B;8.20;16.50;10.00;10.88;3.00;6.00 -Couloir N1 C;8.20;24.80;10.00;22.60;3.00;6.00 +Numerica;1100;1.00;7.28;6.05;3.70;3.00;6.00 +Numerica;0190;1.00;10.88;6.05;7.28;3.00;6.00 +Numerica;0180;1.00;14.48;6.05;10.88;3.00;6.00 +Numerica;1070;1.00;18.12;6.05;14.48;3.00;6.00 +Numerica;1060;1.00;25.32;6.05;18.12;3.00;6.00 +Numerica;1050;1.00;31.40;6.05;25.32;3.00;6.00 +Numerica;WC N1;8.20;9.00;10.00;0.50;3.00;6.00 +Numerica;1105;8.20;10.88;10.00;9.00;3.00;6.00 +Numerica;1095;8.20;29.30;10.00;24.80;3.00;6.00 +Numerica;Palier N1;5.00;3.70;8.20;0.50;3.00;6.00 +Numerica;Couloir N1 A;6.05;29.50;8.20;3.70;3.00;6.00 +Numerica;Couloir N1 B;8.20;16.50;10.00;10.88;3.00;6.00 +Numerica;Couloir N1 C;8.20;24.80;10.00;22.60;3.00;6.00 diff --git a/owlps-positioning/src/inputdatareader.cc b/owlps-positioning/src/inputdatareader.cc new file mode 100644 index 0000000..b1fd91d --- /dev/null +++ b/owlps-positioning/src/inputdatareader.cc @@ -0,0 +1,50 @@ +#include "inputdatareader.hh" +#include "configuration.hh" +#include "posexcept.hh" +#include "topologyreadercsv.hh" + +using namespace std ; + + + +/* *** Constructors *** */ + + +InputDataReader::InputDataReader() +{ + initialise_topology_media() ; +} + + + +/* *** Operations *** */ + + +void InputDataReader::initialise_topology_media() +{ + if (! Configuration::is_configured("data-input.topology-medium")) + return ; + + const vector &media_names = + Configuration::string_vector_value("data-input.topology-medium") ; + + for (vector::const_iterator i = media_names.begin() ; + i != media_names.end() ; ++i) + { + if (*i == "CSV") + initialise_topology_csv() ; + + else + throw topology_input_medium_type_unknown(*i) ; + } +} + + +void InputDataReader::initialise_topology_csv() +{ + if (! Configuration::is_configured("data-input.areas-csv-file")) + throw no_topology_input_csv_file() ; + + TopologyReaderCSV( + Configuration::string_value("data-input.areas-csv-file")) ; +} diff --git a/owlps-positioning/src/inputdatareader.hh b/owlps-positioning/src/inputdatareader.hh new file mode 100644 index 0000000..c94e357 --- /dev/null +++ b/owlps-positioning/src/inputdatareader.hh @@ -0,0 +1,17 @@ +#ifndef _OWLPS_POSITIONING_INPUTDATAREADER_HH_ +#define _OWLPS_POSITIONING_INPUTDATAREADER_HH_ + +/// Read input data using parameters in Configuration +class InputDataReader +{ +protected: + void initialise_topology_media(void) ; + void initialise_topology_csv(void) ; + +public: + InputDataReader(void) ; + + ~InputDataReader(void) {} +} ; + +#endif // _OWLPS_POSITIONING_INPUTDATAREADER_HH_ diff --git a/owlps-positioning/src/owlps-positioning.cc b/owlps-positioning/src/owlps-positioning.cc index a4f23ff..ebd141b 100644 --- a/owlps-positioning/src/owlps-positioning.cc +++ b/owlps-positioning/src/owlps-positioning.cc @@ -1,12 +1,13 @@ #include "userinterface.hh" +#include "inputdatareader.hh" #include "stock.hh" #include "positioning.hh" int main(int argc, char **argv) { - UserInterface *ui = new UserInterface(argc, argv) ; - delete ui ; // We don't need it any more + delete new UserInterface(argc, argv) ; + delete new InputDataReader() ; Positioning positioning ; diff --git a/owlps-positioning/src/posexcept.cc b/owlps-positioning/src/posexcept.cc index 725bfc4..6469bb9 100644 --- a/owlps-positioning/src/posexcept.cc +++ b/owlps-positioning/src/posexcept.cc @@ -24,6 +24,26 @@ element_not_found(const string &_explanation) throw(): +/* *** Data input *** */ + + +topology_input_medium_type_unknown:: +topology_input_medium_type_unknown(const string &medium_name) throw(): + posexcept("The specified topology input medium « "+ medium_name + + " » is unknown!") {} + + +no_topology_input_csv_file::no_topology_input_csv_file() throw(): + posexcept( + "No topologyinput CSV file specified in the configuration!") {} + + +malformed_topology:: +malformed_topology(const string &_explanation) throw(): + posexcept("Error reading the topology:" + _explanation) {} + + + /* *** Input *** */ diff --git a/owlps-positioning/src/posexcept.hh b/owlps-positioning/src/posexcept.hh index d69bca0..b257cca 100644 --- a/owlps-positioning/src/posexcept.hh +++ b/owlps-positioning/src/posexcept.hh @@ -44,6 +44,32 @@ public: +/* *** Data input *** */ + + +class topology_input_medium_type_unknown: public posexcept +{ +public: + topology_input_medium_type_unknown( + const std::string &medium_name) throw() ; +} ; + + +class no_topology_input_csv_file: public posexcept +{ +public: + no_topology_input_csv_file(void) throw() ; +} ; + + +class malformed_topology: public posexcept +{ +public: + malformed_topology(const std::string &_explanation) throw() ; +} ; + + + /* *** Input *** */ diff --git a/owlps-positioning/src/topologyreadercsv.cc b/owlps-positioning/src/topologyreadercsv.cc new file mode 100644 index 0000000..122ba91 --- /dev/null +++ b/owlps-positioning/src/topologyreadercsv.cc @@ -0,0 +1,60 @@ +#include "topologyreadercsv.hh" +#include "posexcept.hh" +#include "stock.hh" +#include "point3d.hh" +#include "area.hh" + +using namespace std ; + + + +/* *** Constructors *** */ + + +TopologyReaderCSV::TopologyReaderCSV(const string &filename): + file(filename) +{ + read_topology() ; +} + + + +/* *** Operations *** */ + + +void TopologyReaderCSV::read_topology() +{ + while (file.next_line()) + process_line() ; +} + + +void TopologyReaderCSV::process_line() +{ + string building_name ; + if (! file.read_field(building_name)) + throw malformed_topology("Cannot read building name!") ; + Building &building = const_cast( + Stock::find_create_building(building_name)) ; + + string name ; + if (! file.read_field(name)) + throw malformed_topology("Cannot read area name!") ; + + Point3D p_min(read_point()) ; + Point3D p_max(read_point()) ; + + Area *area = new Area(&building, name, p_min, p_max) ; + building.add_area(area) ; +} + + +Point3D TopologyReaderCSV::read_point() +{ + float coord[3] ; + for (unsigned int i = 0 ; i < 3 ; ++i) + if (! file.read_field(coord[i])) + throw malformed_topology("Cannot read a whole Point3D!") ; + + return Point3D(coord) ; +} diff --git a/owlps-positioning/src/topologyreadercsv.hh b/owlps-positioning/src/topologyreadercsv.hh new file mode 100644 index 0000000..15eea3a --- /dev/null +++ b/owlps-positioning/src/topologyreadercsv.hh @@ -0,0 +1,30 @@ +#ifndef _OWLPS_POSITIONING_TOPOLOGYREADERCSV_HH_ +#define _OWLPS_POSITIONING_TOPOLOGYREADERCSV_HH_ + +class Point3D ; + +#include "csvfilereader.hh" + +#include + +/// Reads and registers to the Stock an Area list from a CSV file +/** + * CSV format is: + * Building name;Room name;X1;Y1;Z1;X2;Y2;Z2 + */ +class TopologyReaderCSV +{ +protected: + CSVFileReader file ; + + void read_topology(void) ; + void process_line(void) ; + Point3D read_point(void) ; + +public: + TopologyReaderCSV(const std::string &filename) ; + + ~TopologyReaderCSV(void) {} +} ; + +#endif // _OWLPS_POSITIONING_TOPOLOGYREADERCSV_HH_ diff --git a/owlps-positioning/src/userinterface.cc b/owlps-positioning/src/userinterface.cc index 7198378..2a6ad72 100644 --- a/owlps-positioning/src/userinterface.cc +++ b/owlps-positioning/src/userinterface.cc @@ -82,6 +82,7 @@ void UserInterface::fill_cli_options() void UserInterface::fill_file_options() { fill_server_options() ; + fill_data_input_options() ; fill_input_options() ; fill_log_options() ; fill_positioning_options() ; @@ -103,6 +104,27 @@ void UserInterface::fill_server_options() } +void UserInterface::fill_data_input_options() +{ + po::options_description options("Data input options") ; + + options.add_options() + ("data-input.topology-medium,T", po::value< vector >() + ->composing(), + "Medium from which topology (buildings, areas and waypoints) is \ +read. You can specify this option more than once. Allowed: CSV.") + ("data-input.areas-csv-file,A", po::value(), + "CSV file to use for topology input (when \ +data-input.topology-medium = CSV).") + ("data-input.waypoints-csv-file,W", po::value(), + "CSV file to use for waypoints input (when \ +data-input.topology-medium = CSV).") + ; + + file_options->add(options) ; +} + + void UserInterface::fill_input_options() { po::options_description options("Input options") ; diff --git a/owlps-positioning/src/userinterface.hh b/owlps-positioning/src/userinterface.hh index 362be88..3c08067 100644 --- a/owlps-positioning/src/userinterface.hh +++ b/owlps-positioning/src/userinterface.hh @@ -25,6 +25,7 @@ protected: /// the configuration file void fill_file_options(void) ; void fill_server_options(void) ; + void fill_data_input_options(void) ; void fill_input_options(void) ; void fill_log_options(void) ; void fill_positioning_options(void) ; diff --git a/owlps-positioning/tests/inputdatareader_test.hh b/owlps-positioning/tests/inputdatareader_test.hh new file mode 100644 index 0000000..ebbe641 --- /dev/null +++ b/owlps-positioning/tests/inputdatareader_test.hh @@ -0,0 +1,15 @@ +#include + +#include "inputdatareader.hh" + +class InputDataReader_test: public CxxTest::TestSuite +{ +public: + + void test_constructor(void) + { + // TODO: test with a mock Configuration? + InputDataReader inputdatareader1 ; + } + +} ; diff --git a/owlps-positioning/tests/topologyreadercsv_test.hh b/owlps-positioning/tests/topologyreadercsv_test.hh new file mode 100644 index 0000000..4f9c794 --- /dev/null +++ b/owlps-positioning/tests/topologyreadercsv_test.hh @@ -0,0 +1,83 @@ +#include + +#include "topologyreadercsv.hh" + +class TopologyReaderCSV_test: public CxxTest::TestSuite +{ +private: + std::string topology_file_name ; + +public: + + TopologyReaderCSV_test(void): + topology_file_name("/tmp/TopologyReaderCSV_topology_file.csv") + { + Stock::clear() ; + + std::ofstream topology_file(topology_file_name.c_str()) ; + topology_file + << "My building;My room #1;1;2;3;9;8;7\n" + << "My building;Room #2;4;5;6;6;5;4\n" + << "Building #2;My room #1;1;2;3;9;8;7\n" + << "My building;Room #2;4;5;6;6;5;4\n" + << "My building;Room #2;4;5;6;6;5;4\n" ; + topology_file.close() ; + } + + + ~TopologyReaderCSV_test(void) + { + Stock::clear() ; + TestUtil::remove_file(topology_file_name) ; + } + + + static TopologyReaderCSV_test* createSuite(void) + { + return new TopologyReaderCSV_test() ; + } + + + static void destroySuite(TopologyReaderCSV_test *suite) + { + delete suite ; + } + + + void test_topologyreadercsv(void) + { + TS_ASSERT_THROWS_NOTHING( + TopologyReaderCSV toporeader(topology_file_name)) ; + + Building *building1 ; + TS_ASSERT_THROWS_NOTHING( + building1 = const_cast( + &Stock::get_building("My building"))) ; + Building *building2 ; + TS_ASSERT_THROWS_NOTHING( + building2 = const_cast( + &Stock::get_building("Building #2"))) ; + + TS_ASSERT_EQUALS(building1->get_areas().size(), 2u) ; + + Area *area_ptr ; + area_ptr = building1->get_areas().find("My room #1")->second ; + Area area1(building1, "My room #1", + Point3D(1,2,3), Point3D(9,8,7)) ; + assert(area_ptr) ; + TS_ASSERT_EQUALS(*area_ptr, area1) ; + + area_ptr = building1->get_areas().find("Room #2")->second ; + assert(area_ptr) ; + Area area2(building1, "Room #2", + Point3D(4,5,6), Point3D(6,5,4)) ; + TS_ASSERT_EQUALS(*area_ptr, area2) ; + + TS_ASSERT_EQUALS(building2->get_areas().size(), 1u) ; + area1.set_building(building2) ; + area_ptr = building2->get_areas().find("My room #1")->second ; + assert(area_ptr) ; + TS_ASSERT_EQUALS(*area_ptr, area1) ; + } + +} ;