diff --git a/CMakeLists.txt b/CMakeLists.txt
index 010a9859..461eac9f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,39 +1,50 @@
cmake_minimum_required(VERSION 3.11.3)
-if(NOT TESTING)
- set(TESTING "notest")
-endif()
+# Set the C++ standard we will use
+set(CMAKE_CXX_STANDARD 17)
-message("TESTING = ${TESTING}")
+# Add the path of the cmake files to the CMAKE_MODULE_PATH
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake)
-set(CMAKE_CXX_STANDARD 17)
-set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
-
-# Use the CMakeLists.txt's parent-directory-name for the project's id/name
-get_filename_component(PROJECT_ID ${CMAKE_CURRENT_SOURCE_DIR} NAME)
-string(REPLACE " " "_" PROJECT_ID ${PROJECT_ID})
-project(${PROJECT_ID})
-
-#
-# Project Output Paths
-#
-set(MAINFOLDER ${PROJECT_SOURCE_DIR})
-set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${MAINFOLDER}/bin")
-set(LIBRARY_OUTPUT_PATH "${MAINFOLDER}/lib")
-
-#
-# Locate Project Prerequisites
-#
+project(OSM_A_star_search)
+
+# Set library output path to /lib
+set(LIBRARY_OUTPUT_PATH "${CMAKE_SOURCE_DIR}/lib")
+
+# Locate project prerequisites
find_package(io2d REQUIRED)
find_package(Cairo)
find_package(GraphicsMagick)
-#
-# Add Build Targets
-#
+# Set IO2D flags
set(IO2D_WITHOUT_SAMPLES 1)
set(IO2D_WITHOUT_TESTS 1)
-add_subdirectory(src)
-add_subdirectory(test)
+
+# Add the pugixml and GoogleTest library subdirectories
add_subdirectory(thirdparty/pugixml)
add_subdirectory(thirdparty/googletest)
+
+# Add project executable
+add_executable(OSM_A_star_search src/main.cpp src/model.cpp src/render.cpp src/route_model.cpp src/route_planner.cpp)
+
+target_link_libraries(OSM_A_star_search
+ PRIVATE io2d::io2d
+ PUBLIC pugixml
+)
+
+# Add the testing executable
+add_executable(test test/utest_rp_a_star_search.cpp src/route_planner.cpp src/model.cpp src/route_model.cpp)
+
+target_link_libraries(test
+ gtest_main
+ pugixml
+)
+
+# Set options for Linux or Microsoft Visual C++
+if( ${CMAKE_SYSTEM_NAME} MATCHES "Linux" )
+ target_link_libraries(OSM_A_star_search PUBLIC pthread)
+endif()
+
+if(MSVC)
+ target_compile_options(OSM_A_star_search PUBLIC /D_SILENCE_CXX17_ALLOCATOR_VOID_DEPRECATION_WARNING /wd4459)
+endif()
diff --git a/README.md b/README.md
index e3d7d281..5cd9cea9 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,8 @@
-# Route Planning Project Starter Code
+# Route Planning Project
-This is the starter code for the Route Planning project. Instructions for each exercise can be found in the `instructions` directory, and unit tests for some exercises in the `test` directory.
+This repo contains the starter code for the Route Planning project.
+
+
## Cloning
@@ -13,6 +15,21 @@ or with SSH:
git clone git@github.com:udacity/CppND-Route-Planning-Project.git --recurse-submodules
```
+## Dependencies for Running Locally
+* cmake >= 3.11.3
+ * All OSes: [click here for installation instructions](https://cmake.org/install/)
+* make >= 4.1 (Linux, Mac), 3.81 (Windows)
+ * Linux: make is installed by default on most Linux distros
+ * Mac: [install Xcode command line tools to get make](https://developer.apple.com/xcode/features/)
+ * Windows: [Click here for installation instructions](http://gnuwin32.sourceforge.net/packages/make.htm)
+* gcc/g++ >= 7.4.0
+ * Linux: gcc / g++ is installed by default on most Linux distros
+ * Mac: same instructions as make - [install Xcode command line tools](https://developer.apple.com/xcode/features/)
+ * Windows: recommend using [MinGW](http://www.mingw.org/)
+* IO2D
+ * Installation instructions for all operating systems can be found [here](https://github.com/cpp-io2d/P0267_RefImpl/blob/master/BUILDING.md)
+ * This library must be built in a place where CMake `find_package` will be able to find it
+
## Compiling and Running
### Compiling
@@ -26,33 +43,19 @@ cmake ..
make
```
### Running
-The executables will be placed in the `bin` directory. From within `build`, you can run the project as follows:
+The executable will be placed in the `build` directory. From within `build`, you can run the project as follows:
+```
+./OSM_A_star_search
+```
+Or to specify a map file:
```
-../bin/ -f ../map.osm
+./OSM_A_star_search -f ../
```
## Testing
-For exercises that have unit tests, the project must be built with the approprate test cpp file. This can be done by passing a string with the `-DTESTING` flag in `cmake`. For example, from the build directory:
+The testing executable is also placed in the `build` directory. From within `build`, you can run the unit tests as follows:
```
-cmake -DTESTING="RouteModel" ..
-make
-```
-Those commands will build the code with the tests for the "Fill Out Route Model" exercise. The tests can then be run from the `build` directory as follows:
+./test
```
-../bin/test
-```
-Exercises with tests will specify which string to pass with `-DTESTING`, but a table is given below with the complete list for reference:
-
-| Exercise Name | `-DTESTING` String Value |
-|-----------------------------|:------------------------:|
-| Fill Out Route Model | "RouteModel" |
-| Fill Out Node Class | "RMNodeClass" |
-| Create RouteModel Nodes | "RMSNodes" |
-| Write the Distance Function | "NodeDist" |
-| Create Road to Node Hashmap | "NodeToRoad" |
-| Write FindNeighbors | "FindNeighbors" |
-| Find the Closest Node | "FindClosest" |
-| Write the A\* Search Stub | "AStarStub" |
-| Finish A\* Search | "AStarSearch" |
diff --git a/instructions/add_user_input.md b/instructions/add_user_input.md
deleted file mode 100644
index 74298581..00000000
--- a/instructions/add_user_input.md
+++ /dev/null
@@ -1 +0,0 @@
-In this exercise, modify `main.cpp` to get floats `start_x`, `start_y`, `end_x`, and `end_y` from the user and pass the inputs to the `RoutePlanner`. Each of these inputs should be in the range 0 to 100.
\ No newline at end of file
diff --git a/instructions/complete_AStarSearch.md b/instructions/complete_AStarSearch.md
deleted file mode 100644
index 6ab9f05d..00000000
--- a/instructions/complete_AStarSearch.md
+++ /dev/null
@@ -1,23 +0,0 @@
-In this exercise, you will complete `AStarSearch()` in `route_planner.cpp` using the `NextNode`, `ConstructFinalPath`, and `AddNeighbors` methods you have written previously.
-
-To complete this exercise:
-1. Delete the current contents of `AStarSearch`.
-2. Use the `NextNode`, `ConstructFinalPath` and `AddNeighbors` methods to implement the pseudocode below in `AStarSearch`:
-
->AStarSearch:
->
->1. Set `start_node->visited` to be `true`.
->
->2. Push `start_node` to the back of `open_list`.
->
->3. Create a pointer `RouteModel::Node *current_node` and initialize the pointer to `nullptr`.
->
->4. **while** the `open_list` size is greater than 0:
->
-> 1. Set the `current_node` pointer to the results of calling `NextNode`.
-> 2. **if** the distance from `current_node` to the `end_node` is 0:
- - Call `ConstructFinalPath` using `current_node` and set `m_Model.path` with the results.
- - Return to exit the A\* search.
->
-> 4. **else** call `AddNeighbors` with the `current_node`./CppND-Route-Planning-Solution -f ../map.osm
-````
diff --git a/instructions/create_RouteModel_Nodes.md b/instructions/create_RouteModel_Nodes.md
deleted file mode 100644
index 4a3b6aa4..00000000
--- a/instructions/create_RouteModel_Nodes.md
+++ /dev/null
@@ -1,6 +0,0 @@
-Now that you have a `RouteModel` class and you have completed the `RouteModel::Node` nested class, you can create `RouteModel` nodes. When the `RouteModel` constructor is called, it calls the `Model` constructor with the open street map data. When this happens, a collection of `Model:Node` objects are created. However, in order to perform the A\* search, you will need to use `RouteModel::Node` objects instead. In this exercise, you will take the vector of `Model:Node` objects and create a vector of `RouteModel::Node` objects from them that will be stored in the `RouteModel`.
-
-
-To complete this exercise:
-
-- Write a `for` loop with a counter to loop over `this->Nodes()`, which is the list of `Model::Node` objects. For each node, use the `RouteModel::Node` constructor to create a new node with index given by the counter, and push the node to the back of `m_Nodes`.
\ No newline at end of file
diff --git a/instructions/fill_RoutePlanner_constructor.md b/instructions/fill_RoutePlanner_constructor.md
deleted file mode 100644
index 1e0f7c5d..00000000
--- a/instructions/fill_RoutePlanner_constructor.md
+++ /dev/null
@@ -1,9 +0,0 @@
-Now that you have filled out the header of the `RoutePlanner` class, you can finish writing the constructor in `route_planner.cpp`. The constructor takes one `RouteModel` reference and four `floats` as arguments. The `RouteModel` reference should have been assigned to the `m_Model` variable in the previous exercise. In this exercise, the floats should be used to construct the `start_node` and `end_node` of your class. Follow the instructions below to do this.
-
-
-To complete this exercise:
-1. Within the body of the constructor:
- 1. Scale the `float`s to percentages by multiplying each `float` by 0.01 and storing the result in the float variable. For example: `start_x *= 0.01;`
- 2. Use the `m_Model.FindClosestNode` method to find the closest nodes to `(start_x, start_y)` and `(end_x, end_y)`. Store pointers to these nodes in the `start_node` and `end_node` class variables.
-
-Note that there are no tests for this exercise. Your code should compile, and this class will be tested in later exercises.
\ No newline at end of file
diff --git a/instructions/fill_out_Node_class.md b/instructions/fill_out_Node_class.md
deleted file mode 100644
index 9dcfee7a..00000000
--- a/instructions/fill_out_Node_class.md
+++ /dev/null
@@ -1,22 +0,0 @@
-The `Model::Node` class that exists in the current code doesn't contain all the data that would be needed to perfom an A\* search. In order to perform a search, it would be ideal for each node to contain at least the following information:
-- The g-value for the node.
-- The h-value for the node.
-- A boolean to indicate if the node has been visited.
-- A pointer to the node's parent.
-
-In this exercise, you will fill out the `RouteModel::Node` class, which will extend the `Model::Node` class so that the data above, along with a few other useful variables, can be included with each node.
-
-
-To complete this exercise:
-1. Add the following public variables to the `RouteModel::Node` class:
- - A `Node` pointer `parent`, which is initialized to a `nullptr`.
- - A `float` `h_value`, which is initialized to the maximum possible: `std::numeric_limits::max()`.
- - A `float` `g_value`, which is initialized to 0.0.
- - A `bool` `visited`, which is initialized to `false`.
- - A vector of `Node` pointers named `neighbors`.
-2. Add the following two constructors for `RouteModel::Node` objects:
- - A default constructor `Node(){}`.
- - A constructor which accepts an `int` index named `idx`, a pointer to a `RouteModel` object named `search_model`, and a `Model::Node` object named `node`. This constructor should use a constructor list to call the `Model::Node` constructor using `node`, and set the two private variables (discussed below) as follows: `parent_model(search_model)` and `index(idx)`.
-3. Add the following private variables to the `RouteModel::Node` class:
- - An `int` `index`.
- - A pointer to a `RouteModel` object named `parent_model`. This variable is important, as it allows each node to access data stored in the parent model that the node belongs to.
\ No newline at end of file
diff --git a/instructions/fill_out_RouteModel_class.md b/instructions/fill_out_RouteModel_class.md
deleted file mode 100644
index e25cb6cc..00000000
--- a/instructions/fill_out_RouteModel_class.md
+++ /dev/null
@@ -1,11 +0,0 @@
-The `Model` class that exists in the current code doesn't contain all the data or methods that will be needed to perfom an A\* search, so we are going to extend that class with a `RouteModel` class. In this exercise, you will fill out the `RouteModel` class in `route_model.h`. In the next exercises, you will also fill out the `RouteModel::Node` class as well.
-
-
-To complete this exercise:
-In `route_model.h`:
-1. Add a public constructor declaration in the `RouteModel` class. This constructor should accept the following argument, which will be the Open Street Map data: `const std::vector &xml`.
-2. Add a private vector of `Node` objects named `m_Nodes`. This will store all of the nodes from the Open Street Map data.
-3. Add a public getter method `SNodes`. This method should have as the return type a reference to a vector of `Nodes`. The method should return `m_Nodes`.
-
-In `route_model.cpp`:
-1. Add a `RouteModel` constructor in `route_model.cpp`. In the `RouteModel` constructor, use a constructor list to call the `Model` constructor with the `xml` variable: `Model(xml)`.
\ No newline at end of file
diff --git a/instructions/fill_out_RoutePlanner_header.md b/instructions/fill_out_RoutePlanner_header.md
deleted file mode 100644
index a245cc67..00000000
--- a/instructions/fill_out_RoutePlanner_header.md
+++ /dev/null
@@ -1,13 +0,0 @@
-You are now read to begin filling out the `RoutePlanner` class, which will contain methods and data to perform the A\* search on the `RouteModel` data. A class stub and empty class constructor have been provided in the `route_planner.h` and `route_planner.cpp` files. In this exercise, you will be starting with the header file `route_planner.h`.
-
-
-To complete this exercise:
-1. Add the following private variables to the `RoutePlanner` class in `route_planer.h`:
- - A `RouteModel` reference `m_Model`. This will refer to the model that you will be performing A\* search on.
- - `RouteModel::Node` pointers `start_node` and `end_node`. These will point to the nodes in the model which are closest to our starting and ending points.
- - A float `distance`. This variable will hold the total distance for the route that A\* search finds from `start_node` to `end_node`.
-2. Add the following public method to the `RoutePlanner` class in `route_planner.h`:
- - A `GetDistance()` method. This is a public getter method for the `distance` variable, and should just return `distance`. This method will later be used to print out the total distance from `main.cpp`.
-3. Use an initializer list in the `RoutePlanner` constructor in `route_planner.cpp` to initialize the `m_Model` variable with the passed `RoutePlanner` reference `model`.
-
-Note that this exercise has no tests associated with it, but there will be tests in future exercises using the `RoutePlanner` class.
\ No newline at end of file
diff --git a/instructions/write_AStarSearch_stub.md b/instructions/write_AStarSearch_stub.md
deleted file mode 100644
index 0ac367b8..00000000
--- a/instructions/write_AStarSearch_stub.md
+++ /dev/null
@@ -1,16 +0,0 @@
-In this exercise, you will modify `route_planner.h`, `route_planner.cpp`, `main.cpp`, and `render.cpp` to add a method `AStarSearch`, which will eventually become the search from `start_node` to `end_node`. In this exercise, you will only implement a basic version that returns a direct path between those two nodes. When you are done with this exercise, running the code should render a map with a direct path between the start and end nodes.
-
-
-To complete this exercise, you can use the following steps:
-1. Add a `AStarSearch` declaration to the `RoutePlanner` class in `route_planner.h`. This method will be called from `main.cpp`, so it must be a public method. `AStarSearch` will use the `start_node` and `end_node` class variables, and it will modify the `m_Model` class variable, so it does not need any arguments, and should have `void` return type.
-2. In `route_planner.cpp` define the `AStarSearch` method. The method should do the following:
- 1. Set the parent of `end_node` to the `start_node`.
- 2. Set `m_Model.path` to the result of calling `ConstructFinalPath` on `end_node`.
-3. In `main.cpp` call `AStarSearch` on the `RoutePlanner` object. This should happen just after the `RoutePlanner` object is defined, but before the `Render render{model}`.
-4. Also in `main.cpp` use the `GetDistance()` method of the `RoutePlanner` object to print the length of the path.
-5. Uncomment the following lines in the `Render::Display` method in `render.cpp`. These lines will include the path in the rendered map:
-```
- // DrawPath(surface);
- // DrawStartPosition(surface);
- // DrawEndPosition(surface);
-```
\ No newline at end of file
diff --git a/instructions/write_AddNeighbors.md b/instructions/write_AddNeighbors.md
deleted file mode 100644
index 5e707b19..00000000
--- a/instructions/write_AddNeighbors.md
+++ /dev/null
@@ -1,16 +0,0 @@
-In this exercise, you will will write a `RoutePlanner::AddNeighbors` method to take each neighbor of the current node in the A\* search, set the neighbor's g-value, h-value, and parent, and add the neighbor to the open list. To do this, you will use the `RouteModel::Node::FindNeighbors()`, and the `CalculateHValue` method that you have written previously.
-
-To complete this exercise:
-1. Modify `route_planner.h` to include a private method declaration for the `AddNeighbors` method. This method should accept a pointer to a `RouteModel::Node` object as the argument, and since the method is just modifying the `RoutePlanner` instance variable `open_list`, the method can have `void` return type.
-2. In `route_planner.cpp` define the `AddNeighbors` method using the `FindNeighbors` and `CalculateHValue` methods. You can use the pseudocode below as a guideline:
-
-> AddNeighbors(RouteModel::Node *current_node)
-> 1. Call `FindNeighbors()` on `current_node` to populate the `current_node`'s `neighbors` vector.
-> 2. For each `neighbor` in the `current_node`'s `neighbors`
-> 1. Set the `neighbor`s `parent` to the `current_node`.
-> 2. Set the `neighbor`'s `g_value` to the sum of the `current_node`'s `g_value` plus the distance from the `curent_node` to the `neighbor`.
-> 3. Set the `neighbor`'s `h_value` using `CalculateHValue`
-> 4. Push the `neighbor` to the back of the `open_list`.
-> 5. Mark the `neighbor` as visited.
-
-This exercise does not have any tests associated with it, but you will be completing A\* search in the next exercise, and the code will be tested with the results of `AStarSearch()`.
\ No newline at end of file
diff --git a/instructions/write_CalculateHValue.md b/instructions/write_CalculateHValue.md
deleted file mode 100644
index 5bce4651..00000000
--- a/instructions/write_CalculateHValue.md
+++ /dev/null
@@ -1,8 +0,0 @@
-In this exercise, you will modify `route_planner.h` and `route_planner.cpp` to add a method `CalculateHValue`, which calculates the h-value for a given node. In this project, h-value will be computed as the distance from the node to the end_node.
-
-
-To write this method, you can use the following steps:
-1. Add a `CalculateHValue` declaration to the `RoutePlanner` class in `route_planner.h`. This method will only be used in the `RoutePlanner` class, so it can be a private method. `CalculateHValue` should accept a `const` pointer to a `RouteModel::Node` object, and it should return a `float`.
-2. In `route_planner.cpp` define the `CalculateHValue` method. The method should return the distance from the passed argument to the `end_node`.
-
-Note that since `CalculateHValue` is private, there will be no tests for this exercise. The code will be tested implicitly through public functions in later tests.
\ No newline at end of file
diff --git a/instructions/write_ConstructFinalPath.md b/instructions/write_ConstructFinalPath.md
deleted file mode 100644
index 7f3f5fb0..00000000
--- a/instructions/write_ConstructFinalPath.md
+++ /dev/null
@@ -1,15 +0,0 @@
-In the next exercise, you will write a method stub for the A\* search. Before that method can be written, you will need a way to reconstruct the final sequence of nodes found from the `start_node` to the `end_node`, so that the A\* search can store the sequence. The final sequence is reconstructed by starting with the last node that was found, and then iteratively traversing to the parent of that node and each previous node in the sequence until the starting node is reached. In this exercise, you will be writting a method `ConstructFinalPath` that takes a `RouteModel::Node` pointer and iteratively moves the sequence of parents, storing each node in the sequence, until the starting node is reached.
-
-
-To complete this exercise, you can use the following steps:
-1. Add a `ConstructFinalPath` declaration to the `RoutePlanner` class in `route_planner.h`. This method will be called from the A\* search within the RoutePlanner class, so it can be a private method. `ConstructFinalPath` should accept the pointer `RouteModel::Node *current_node` as the argument, and it should return a vector of ``RouteModel::Node` objects.
-2. In `route_planner.cpp` define the `ConstructFinalPath` method. The method should do the following:
- 1. Initialize an empty vector `path_found` of `RouteModel::Node` objects and set the class variable `distance` to 0.
- 2. Iterate through the node parents until a node with parent equal to `nullptr` is reached - this will be the start node, which has no parent. Each node in the iteration should be pushed to the `path_found` vector.
- 3. To keep track of the total path distance, in each step of the iteration, add the distance between a node and its parent to the `distance` variable.
- 4. After the loop, scale the `distance` by multiplying by the model's scale: `m_Model.MetricScale()`. This is done since node coordinates are scaled down when they are stored in the model. They must be rescaled to get an accurate distance.
- 5. Return the `path_found`.
-
-Note that the path returned above is in reverse order, with the ending node at the beginning of the vector. This is fine, and is expected by the rendering code.
-
-Note that this exercise has no tests. The `ConstructFinalPath` method will be tested in upcoming exercises as the A\* search methods are implemented.
\ No newline at end of file
diff --git a/instructions/write_CreateNodeToRoadHashmap.md b/instructions/write_CreateNodeToRoadHashmap.md
deleted file mode 100644
index 8caf5b6a..00000000
--- a/instructions/write_CreateNodeToRoadHashmap.md
+++ /dev/null
@@ -1,15 +0,0 @@
-When you begin to write A\* search, you will be searching between two nodes on the map. We would like the search path to follow the roads that the nodes are on, but a given node doesn't have any information about which road it belongs to. To rectify this problem, you will write a function that creates a hashmap of `Node` values to a vector of `Roads` that those nodes belong to.
-
-
-To complete this exercise:
-1. Add a private variable `node_to_road` in the `RouteModel` class in `route_model.h`. This variable should be an `unordered_map` with an `int` key type, and a vector of `const Model::Road *` as the value type.
-2. Add a method declaration `CreateNodeToRoadHashmap` in the `RouteModel` class in `route_model.h`. This method will operate only on the `node_to_road` variable declared above, and only within the `RouteModel` class, so it can be private, it needs no arguments, and can have `void` return type.
-3. Add a method definition `route_model.cpp`
-4. In the body of the method, you will need to do the following:
- 1. Write a loop that iterates through the vector given by calling `Roads()`.
- 2. For each reference `&road` in the vector, check that the type is not a footway: `road.type != Model::Road::Type::Footway`. If the road is not a footway:
- 1. Loop over each `node_idx` in the `way` that the road belongs to: `Ways()[road.way].nodes`.
- 1. If the node index is not in the `node_to_road` hashmap yet, set the value for the `node_idx` key to be an empty vector of `const Model::Road *` objects.
- 2. Push a pointer to the current road in the loop to the back of the vector given by the `node_idx` key in `node_to_road`.
-5. Call `CreateNodeToRoadHashmap()` in the `RouteModel` constructor in `route_model.cpp`.
-6. Lastly, add a public getter function `GetNodeToRoadMap()` in the `RouteModel` class in `route_model.h`. This function should return a reference to the `node_to_road` variable, and it will be primarily used for testing.
\ No newline at end of file
diff --git a/instructions/write_FindClosestNode.md b/instructions/write_FindClosestNode.md
deleted file mode 100644
index 67affd69..00000000
--- a/instructions/write_FindClosestNode.md
+++ /dev/null
@@ -1,15 +0,0 @@
-In the upcoming exercises, you will start working on the `RoutePlanner` class, which will contain methods to perform the A\* search. A `RoutePlanner` class will be initialized starting and ending coordinates provided by the user. These will be input as float values, but in order for the search to be performed, you will need to find the nodes in the `RouteModel` that are closest to the starting and ending coordinates. In this exercise, you will write a method `FindClosestNode` that accepts two `floats` and finds the closest node in your model.
-
-
-To complete this exercise:
-1. Add a public method declaration `FindClosestNode` in the `RouteModel` class in `route_model.h`. This method should accept two floats `x` and `y` as arguments, and should return a reference to a `RouteModel::Node` object.
-2. Add a method definition `route_model.cpp`
-3. In the body of the method, you will need to do the following:
- 1. Create a temporary `Node` with `x` and `y` coordinates given by the method inputs.
- 2. Create a float `min_dist = std::numeric_limits::max()` for the minum distance found in your search.
- 3. Create an `int` variable `closest_idx` to store the index of the closest
- 4. Write a loop that iterates through the vector given by calling `Roads()`.
- 5. For each reference `&road` in the vector, check that the type is not a footway: `road.type != Model::Road::Type::Footway`. If the road is not a footway:
- 1. Loop over each node index in the `way` that the road belongs to: `Ways()[road.way].nodes`.
- 2. Update `closest_idx` and `min_dist`, if needed.
- 6. Return the node from the `SNodes()` vector using the found index.
\ No newline at end of file
diff --git a/instructions/write_FindNeighbor.md b/instructions/write_FindNeighbor.md
deleted file mode 100644
index f3732042..00000000
--- a/instructions/write_FindNeighbor.md
+++ /dev/null
@@ -1,29 +0,0 @@
-In this exercise, modify `route_model.h` and `route_model.cpp` to add a `RouteModel::Node` method `FindNeighbor`. The goal of `FindNeighbor` is to return a pointer to the closest unvisited node from a vector of node indices, where the distance is measured to the current node (`this`).
-
-
-To write this method, you can use the following steps:
-1. Add a `FindNeighbor` declaration to the `RouteModel::Node` class in `route_model.h`. This method will only be used later in another `RouteModel::Node` method to find the closest node in each `Road` containing the current node, so `FindNeighbor` can be a private method. `FindNeighbor` should accept a `vector node_indices` argument and return a pointer to a node: `RouteModel::Node*` type.
-2. In `route_model.cpp` define an empty `FindNeighbor` method. At this step, compile the code using `make` to check that your method declaration and empty method definiton have matching signatures.
-3. Within the `FindNeighbor` method, loop through the `node_indices` vector to find the closest unvisited node. To do this, start with a pointer `Node *closest_node = nullptr`, and then update `closest_node` as you find closer nodes in the loop. The following will be useful:
- - For each index in the loop, you can retrieve the `Node` object with `parent_model->SNodes()[index]`.
- - For each retrieved `Node` in the loop, you should check that the node has not been visted (`!node.visited`) _and_ that the distance to `this` is nonzero. In other words, you want the closest unvisted node that is not the current node.
- - The `RouteModel::Node::distance` method can be used to find the distance between two nodes.
-
-Pseudocode for the exercise is given below:
-
->The FindNeighbor method, given a `vector node_indices`:
->
->1. Create a pointer `Node *closest_node = nullptr`
->2. Declare a temporary Node variable `node`
->
->3. For each `node_index` in `node_indices`
-
-> 1. Set `node` equal to the `parent_model->SNodes()[node_index]`
-> 2. If the distance from `this` to `node` is nonzero, _and_ the `node` has not been visited:
->
-> 1. If the `closest_node` equals `nullptr`, _or_ the distance from `this` to `node` is less than the distance from `this` to `*closest_node`:
-> - Set `closest_node` to point to the address of `parent_model->SNodes()[node_index]`.
->4. Finally, return the `closest_node`.
-
-
-Note that there will be no tests for this method. The method is private, and will be used as a helper function in a public method in the next exercise.
\ No newline at end of file
diff --git a/instructions/write_FindNeighbors.md b/instructions/write_FindNeighbors.md
deleted file mode 100644
index 0a782a23..00000000
--- a/instructions/write_FindNeighbors.md
+++ /dev/null
@@ -1,7 +0,0 @@
-In this exercise, modify `route_model.h` and `route_model.cpp` to add a `RouteModel::Node` method `FindNeighbors`. The goal of `FindNeighbors` is to populate the `neighbors` vector of the current `Node` object (the vector `this->neighbors`). This vector should contain the closest neighbor from each road that `this` belongs to. Since `FindNeighbors` operates on the current `Node` and modifies the `Node` data, it does not need any arguments and can have return type `void`.
-
-To write this method, you can use the following steps:
-1. Add a public `FindNeighbors` declaration to the `RouteModel::Node` class in `route_model.h`. This method will be called from `route_planner.cpp`, so the method needs to be public. `FindNeighbors` should take no arguments and have `void` return type.
-2. In `route_model.cpp` define the `FindNeighbors` method.
-3. With the `FindNeighbors` method, for each road reference `&road` in the vector `parent_model->node_to_road[this->index]`, `FindNeighbors` should use the `FindNeighbor` method to create a pointer of `RouteModel::Node* ` type.
-4. If that pointer is not a `nullptr`, push the pointer to the back of `this->neighbors`.
\ No newline at end of file
diff --git a/instructions/write_NextNode.md b/instructions/write_NextNode.md
deleted file mode 100644
index 3e7e6b57..00000000
--- a/instructions/write_NextNode.md
+++ /dev/null
@@ -1,12 +0,0 @@
-In this exercise, you will will write a `RoutePlanner::NextNode` method which will sort the list of open nodes in the A\* search, return the node with the lowest f-value, and remove the node from the list of open nodes. As you continue to develop your project, it will be easier to store the open list in the class as a vector of pointers to `RouteModel::Node` objects, so you will do that in this exercise as well.
-
-To complete this exercise:
-1. In the `RoutePlanner` class in `route_planner.h`, add a private class member variable `open_list`. The `open_list` should be a vector of `RouteModel::Node` pointers.
-2. Modify `route_planner.h` to include a private function declaration for the `NextNode` method. Since the method is just modifying the `open_list` and returning a pointer to a node, `NextNode` does not need any arguments. The method should return a pointer to a `RouteModel::Node` object.
-3. In `route_planner.cpp` define the `NextNode` method. This method should:
- 1. Sort the `open_list` according to the f-value, which is the sum of a node's h-value and g-value.
- 2. Create a pointer copy of the pointer to the node with the lowest f-value.
- 3. Erase that node pointer from `open_list`.
- 4. Return the pointer copy.
-
-Since the `NextNode` method is private, there will not be any tests for this exercise. You will be able to test that the method is working with your A\* implementation in upcoming exercises.
\ No newline at end of file
diff --git a/instructions/write_distance_function.md b/instructions/write_distance_function.md
deleted file mode 100644
index 9f93846c..00000000
--- a/instructions/write_distance_function.md
+++ /dev/null
@@ -1,5 +0,0 @@
-As you write A\* search, it will be useful to be able to find the distance between two nodes. This will allow the search algorithm to find the closest node to the current node. In this exercise, you will write a utility function that finds the distance between two `RouteModel::Node` objects.
-
-To complete this exercise:
-1. Add a `distance` declaration to the `RouteModel::Node` class. This method should take a `Node` object as the argument, and it should return a `float`. The `distance` method shouldn't change the object being passed, so you can make it a `const` method (add const after the function name).
-2. Return the euclidean distance from the current node to the node passed in. Note that for points $(x_1, y_1)$ and $(x_2, y_2)$, the euclidean distance is given by $\sqrt((x_1 - x_2)^2 + (y_1 - y_2)^2)$.
\ No newline at end of file
diff --git a/map.png b/map.png
new file mode 100644
index 00000000..3f5b0853
Binary files /dev/null and b/map.png differ
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
deleted file mode 100644
index ea9feb11..00000000
--- a/src/CMakeLists.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-#
-# Set the binary executable name
-#
-set(project_BIN ${PROJECT_NAME})
-
-#
-# Find all executables
-#
-file(GLOB project_SRCS *.cpp *.h)
-
-#
-# Add executables to project
-#
-add_executable(${project_BIN} ${project_SRCS})
-
-target_link_libraries(${project_BIN}
- PRIVATE io2d::io2d
- PUBLIC pugixml
-)
-
-#
-# create a library for unit tests
-#
-add_library(route_planner OBJECT route_planner.cpp model.cpp route_model.cpp)
-target_include_directories(route_planner PRIVATE ../thirdparty/pugixml/src)
-
-
-if( ${CMAKE_SYSTEM_NAME} MATCHES "Linux" )
- target_link_libraries(${project_BIN} PUBLIC pthread)
-endif()
-
-if(MSVC)
- target_compile_options(${project_BIN} PUBLIC /D_SILENCE_CXX17_ALLOCATOR_VOID_DEPRECATION_WARNING /wd4459)
-endif()
diff --git a/src/main.cpp b/src/main.cpp
index 957bbe93..8becb63a 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -36,7 +36,9 @@ int main(int argc, const char **argv)
osm_data_file = argv[i];
}
else {
- std::cout << "Usage: [executable] [-f filename.osm]" << std::endl;
+ std::cout << "To specify a map file use the following format: " << std::endl;
+ std::cout << "Usage: [executable] [-f filename.osm]" << std::endl;
+ osm_data_file = "../map.osm";
}
std::vector osm_data;
@@ -50,15 +52,20 @@ int main(int argc, const char **argv)
osm_data = std::move(*data);
}
- // TODO: Declare floats `start_x`, `start_y`, `end_x`, and `end_y` and get
+ // TODO 1: Declare floats `start_x`, `start_y`, `end_x`, and `end_y` and get
// user input for these values using std::cin. Pass the user input to the
- // RoutePlanner object below.
+ // RoutePlanner object below in place of 10, 10, 90, 90.
// Build Model.
RouteModel model{osm_data};
- // Perform search and render results.
+ // Create RoutePlanner object and perform A* search.
RoutePlanner route_planner{model, 10, 10, 90, 90};
+ route_planner.AStarSearch();
+
+ std::cout << "Distance: " << route_planner.GetDistance() << " meters. \n";
+
+ // Render results of search.
Render render{model};
auto display = io2d::output_surface{400, 400, io2d::format::argb32, io2d::scaling::none, io2d::refresh_style::fixed, 30};
diff --git a/src/render.cpp b/src/render.cpp
index a3a55799..25f78dc8 100644
--- a/src/render.cpp
+++ b/src/render.cpp
@@ -27,9 +27,9 @@ void Render::Display( io2d::output_surface &surface )
DrawRailways(surface);
DrawHighways(surface);
DrawBuildings(surface);
- // DrawPath(surface);
- // DrawStartPosition(surface);
- // DrawEndPosition(surface);
+ DrawPath(surface);
+ DrawStartPosition(surface);
+ DrawEndPosition(surface);
}
void Render::DrawPath(io2d::output_surface &surface) const{
@@ -41,13 +41,14 @@ void Render::DrawPath(io2d::output_surface &surface) const{
}
void Render::DrawEndPosition(io2d::output_surface &surface) const{
+ if (m_Model.path.empty()) return;
io2d::render_props aliased{ io2d::antialias::none };
io2d::brush foreBrush{ io2d::rgba_color::red };
auto pb = io2d::path_builder{};
pb.matrix(m_Matrix);
- pb.new_figure({(float) m_Model.path.front().x, (float) m_Model.path.front().y});
+ pb.new_figure({(float) m_Model.path.back().x, (float) m_Model.path.back().y});
float constexpr l_marker = 0.01f;
pb.rel_line({l_marker, 0.f});
pb.rel_line({0.f, l_marker});
@@ -57,17 +58,18 @@ void Render::DrawEndPosition(io2d::output_surface &surface) const{
surface.fill(foreBrush, pb);
surface.stroke(foreBrush, io2d::interpreted_path{pb}, std::nullopt, std::nullopt, std::nullopt, aliased);
-
}
void Render::DrawStartPosition(io2d::output_surface &surface) const{
+ if (m_Model.path.empty()) return;
+
io2d::render_props aliased{ io2d::antialias::none };
io2d::brush foreBrush{ io2d::rgba_color::green };
auto pb = io2d::path_builder{};
pb.matrix(m_Matrix);
- pb.new_figure({(float) m_Model.path.back().x, (float) m_Model.path.back().y});
+ pb.new_figure({(float) m_Model.path.front().x, (float) m_Model.path.front().y});
float constexpr l_marker = 0.01f;
pb.rel_line({l_marker, 0.f});
pb.rel_line({0.f, l_marker});
@@ -77,7 +79,6 @@ void Render::DrawStartPosition(io2d::output_surface &surface) const{
surface.fill(foreBrush, pb);
surface.stroke(foreBrush, io2d::interpreted_path{pb}, std::nullopt, std::nullopt, std::nullopt, aliased);
-
}
void Render::DrawBuildings(io2d::output_surface &surface) const
diff --git a/src/route_model.cpp b/src/route_model.cpp
index fa1e9133..ec6cf1ad 100644
--- a/src/route_model.cpp
+++ b/src/route_model.cpp
@@ -2,5 +2,76 @@
#include
RouteModel::RouteModel(const std::vector &xml) : Model(xml) {
+ // Create RouteModel nodes.
+ int counter = 0;
+ for (Model::Node node : this->Nodes()) {
+ m_Nodes.emplace_back(Node(counter, this, node));
+ counter++;
+ }
+ CreateNodeToRoadHashmap();
+}
+
+void RouteModel::CreateNodeToRoadHashmap() {
+ for (const Model::Road &road : Roads()) {
+ if (road.type != Model::Road::Type::Footway) {
+ for (int node_idx : Ways()[road.way].nodes) {
+ if (node_to_road.find(node_idx) == node_to_road.end()) {
+ node_to_road[node_idx] = std::vector ();
+ }
+ node_to_road[node_idx].push_back(&road);
+ }
+ }
+ }
+}
+
+
+RouteModel::Node *RouteModel::Node::FindNeighbor(std::vector node_indices) {
+ Node *closest_node = nullptr;
+ Node node;
+
+ for (int node_index : node_indices) {
+ node = parent_model->SNodes()[node_index];
+ if (this->distance(node) != 0 && !node.visited) {
+ if (closest_node == nullptr || this->distance(node) < this->distance(*closest_node)) {
+ closest_node = &parent_model->SNodes()[node_index];
+ }
+ }
+ }
+ return closest_node;
+}
+
+
+void RouteModel::Node::FindNeighbors() {
+ for (auto & road : parent_model->node_to_road[this->index]) {
+ RouteModel::Node *new_neighbor = this->FindNeighbor(parent_model->Ways()[road->way].nodes);
+ if (new_neighbor) {
+ this->neighbors.emplace_back(new_neighbor);
+ }
+ }
+}
+
+
+RouteModel::Node &RouteModel::FindClosestNode(float x, float y) {
+ Node input;
+ input.x = x;
+ input.y = y;
+
+ float min_dist = std::numeric_limits::max();
+ float dist;
+ int closest_idx;
+
+ for (const Model::Road &road : Roads()) {
+ if (road.type != Model::Road::Type::Footway) {
+ for (int node_idx : Ways()[road.way].nodes) {
+ dist = input.distance(SNodes()[node_idx]);
+ if (dist < min_dist) {
+ closest_idx = node_idx;
+ min_dist = dist;
+ }
+ }
+ }
+ }
+
+ return SNodes()[closest_idx];
}
\ No newline at end of file
diff --git a/src/route_model.h b/src/route_model.h
index 46e00d45..d2710375 100644
--- a/src/route_model.h
+++ b/src/route_model.h
@@ -1,4 +1,5 @@
-#pragma once
+#ifndef ROUTE_MODEL_H
+#define ROUTE_MODEL_H
#include
#include
@@ -11,22 +12,36 @@ class RouteModel : public Model {
public:
class Node : public Model::Node {
public:
- // Add public Node variables and methods here.
-
+ Node * parent = nullptr;
+ float h_value = std::numeric_limits::max();
+ float g_value = 0.0;
+ bool visited = false;
+ std::vector neighbors;
+
+ void FindNeighbors();
+ float distance(Node other) const {
+ return std::sqrt(std::pow((x - other.x), 2) + std::pow((y - other.y), 2));
+ }
+
Node(){}
Node(int idx, RouteModel * search_model, Model::Node node) : Model::Node(node), parent_model(search_model), index(idx) {}
-
+
private:
- // Add private Node variables and methods here.
int index;
+ Node * FindNeighbor(std::vector node_indices);
RouteModel * parent_model = nullptr;
};
-
- // Add public RouteModel variables and methods here.
- RouteModel(const std::vector &xml);
- std::vector path; // This variable will eventually store the path that is found by the A* search.
+ RouteModel(const std::vector &xml);
+ Node &FindClosestNode(float x, float y);
+ auto &SNodes() { return m_Nodes; }
+ std::vector path;
+
private:
- // Add private RouteModel variables and methods here.
+ void CreateNodeToRoadHashmap();
+ std::unordered_map> node_to_road;
+ std::vector m_Nodes;
};
+
+#endif
diff --git a/src/route_planner.cpp b/src/route_planner.cpp
index c808e0cc..280ca96d 100644
--- a/src/route_planner.cpp
+++ b/src/route_planner.cpp
@@ -2,5 +2,83 @@
#include
RoutePlanner::RoutePlanner(RouteModel &model, float start_x, float start_y, float end_x, float end_y): m_Model(model) {
+ // Convert inputs to percentage:
+ start_x *= 0.01;
+ start_y *= 0.01;
+ end_x *= 0.01;
+ end_y *= 0.01;
+
+ // TODO 2: Use the m_Model.FindClosestNode method to find the closest nodes to the starting and ending coordinates.
+ // Store the nodes you find in the RoutePlanner's start_node and end_node attributes.
+
+}
+
+
+// TODO 3: Implement the CalculateHValue method.
+// Tips:
+// - You can use the distance to the end_node for the h value.
+// - Node objects have a distance method to determine the distance to another node.
+
+float RoutePlanner::CalculateHValue(RouteModel::Node const *node) {
+
+}
+
+
+// TODO 4: Complete the AddNeighbors method to expand the current node by adding all unvisited neighbors to the open list.
+// Tips:
+// - Use the FindNeighbors() method of the current_node to populate current_node.neighbors vector with all the neighbors.
+// - For each node in current_node.neighbors, set the parent, the h_value, the g_value.
+// - Use CalculateHValue below to implement the h-Value calculation.
+// - For each node in current_node.neighbors, add the neighbor to open_list and set the node's visited attribute to true.
+
+void RoutePlanner::AddNeighbors(RouteModel::Node *current_node) {
+
+}
+
+
+// TODO 5: Complete the NextNode method to sort the open list and return the next node.
+// Tips:
+// - Sort the open_list according to the sum of the h value and g value.
+// - Create a pointer to the node in the list with the lowest sum.
+// - Remove that node from the open_list.
+// - Return the pointer.
+
+RouteModel::Node *RoutePlanner::NextNode() {
+
+}
+
+
+// TODO 6: Complete the ConstructFinalPath method to return the final path found from your A* search.
+// Tips:
+// - This method should take the current (final) node as an argument and iteratively follow the
+// chain of parents of nodes until the starting node is found.
+// - For each node in the chain, add the distance from the node to its parent to the distance variable.
+// - The returned vector should be in the correct order: the start node should be the first element
+// of the vector, the end node should be the last element.
+
+std::vector RoutePlanner::ConstructFinalPath(RouteModel::Node *current_node) {
+ // Create path_found vector
+ distance = 0.0f;
+ std::vector path_found;
+
+ // TODO: Implement your solution here.
+
+ distance *= m_Model.MetricScale(); // Multiply the distance by the scale of the map to get meters.
+ return path_found;
}
+
+
+// TODO 7: Write the A* Search algorithm here.
+// Tips:
+// - Use the AddNeighbors method to add all of the neighbors of the current node to the open_list.
+// - Use the NextNode() method to sort the open_list and return the next node.
+// - When the search has reached the end_node, use the ConstructFinalPath method to return the final path that was found.
+// - Store the final path in the m_Model.path attribute before the method exits. This path will then be displayed on the map tile.
+
+void RoutePlanner::AStarSearch() {
+ RouteModel::Node *current_node = nullptr;
+
+ // TODO: Implement your solution here.
+
+}
\ No newline at end of file
diff --git a/src/route_planner.h b/src/route_planner.h
index 4f61abea..8bc68c53 100644
--- a/src/route_planner.h
+++ b/src/route_planner.h
@@ -1,4 +1,5 @@
-#pragma once
+#ifndef ROUTE_PLANNER_H
+#define ROUTE_PLANNER_H
#include
#include
@@ -10,8 +11,23 @@ class RoutePlanner {
public:
RoutePlanner(RouteModel &model, float start_x, float start_y, float end_x, float end_y);
// Add public variables or methods declarations here.
+ float GetDistance() const {return distance;}
+ void AStarSearch();
+
+ // The following methods have been made public so we can test them individually.
+ void AddNeighbors(RouteModel::Node *current_node);
+ float CalculateHValue(RouteModel::Node const *node);
+ std::vector ConstructFinalPath(RouteModel::Node *);
+ RouteModel::Node *NextNode();
private:
// Add private variables or methods declarations here.
+ std::vector open_list;
+ RouteModel::Node *start_node;
+ RouteModel::Node *end_node;
+
+ float distance = 0.0f;
RouteModel &m_Model;
};
+
+#endif
\ No newline at end of file
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
deleted file mode 100644
index be8b81eb..00000000
--- a/test/CMakeLists.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-
-# message("TESTING = ${TESTING}")
-
-# Choose which test .cpp file based on the exercise.
-if(${TESTING} STREQUAL "RouteModel")
- add_executable(test utest_route_model_class.cpp)
-elseif(${TESTING} STREQUAL "RMNodeClass")
- add_executable(test utest_rm_node_class.cpp)
-elseif(${TESTING} STREQUAL "RMSNodes")
- add_executable(test utest_rm_snodes.cpp)
-elseif(${TESTING} STREQUAL "NodeDist")
- add_executable(test utest_rm_node_dist.cpp)
-elseif(${TESTING} STREQUAL "NodeToRoad")
- add_executable(test utest_rm_hashmap.cpp)
-elseif(${TESTING} STREQUAL "FindNeighbors")
- add_executable(test utest_rm_find_neighbors.cpp)
-elseif(${TESTING} STREQUAL "FindClosest")
- add_executable(test utest_rm_find_closest_node.cpp)
-elseif(${TESTING} STREQUAL "AStarStub")
- add_executable(test utest_rp_a_star_stub.cpp)
-elseif(${TESTING} STREQUAL "AStarSearch")
- add_executable(test utest_rp_a_star_search.cpp)
-else()
- # If the user calls CMake with no flags, don't compile any test files.
- add_executable(test)
-endif()
-
-target_link_libraries(test gtest_main route_planner pugixml)
-add_test(NAME test COMMAND test)
-
-unset(TESTING CACHE)
diff --git a/test/utest_rm_find_closest_node.cpp b/test/utest_rm_find_closest_node.cpp
deleted file mode 100644
index 6ce6f8a1..00000000
--- a/test/utest_rm_find_closest_node.cpp
+++ /dev/null
@@ -1,115 +0,0 @@
-#include "gtest/gtest.h"
-#include
-#include
-#include
-#include
-#include "../src/route_model.h"
-#include "../src/route_planner.h"
-
-
-static std::optional> ReadFile(const std::string &path)
-{
- std::ifstream is{path, std::ios::binary | std::ios::ate};
- if( !is )
- return std::nullopt;
-
- auto size = is.tellg();
- std::vector contents(size);
-
- is.seekg(0);
- is.read((char*)contents.data(), size);
-
- if( contents.empty() )
- return std::nullopt;
- return std::move(contents);
-}
-
-std::vector ReadOSMData(const std::string &path) {
- std::vector osm_data;
- auto data = ReadFile(path);
- if( !data ) {
- std::cout << "Failed to read OSM data." << std::endl;
- } else {
- osm_data = std::move(*data);
- }
- return osm_data;
-}
-
-
-class RouteModelTest : public ::testing::Test {
- protected:
- std::string osm_data_file = "../map.osm";
- std::vector osm_data = ReadOSMData(osm_data_file);
- RouteModel model{osm_data};
-};
-
-
-// Test that the path size is zero initially.
-TEST_F(RouteModelTest, RouteModelData) {
- EXPECT_EQ(model.path.size(), 0);
- EXPECT_EQ(model.Nodes().size(), model.SNodes().size());
-}
-
-
-// Test that the RouteModel::Node class is defined correctly.
-TEST_F(RouteModelTest, RouteModelNode) {
- RouteModel::Node test_node = model.SNodes()[1];
- EXPECT_FLOAT_EQ(test_node.x, 1.2646476);
- EXPECT_FLOAT_EQ(test_node.y, 0.23506972);
- EXPECT_EQ(test_node.parent, nullptr);
- EXPECT_FLOAT_EQ(test_node.h_value, std::numeric_limits::max());
- EXPECT_FLOAT_EQ(test_node.g_value, 0.0);
- EXPECT_FLOAT_EQ(test_node.visited, false);
- EXPECT_EQ(test_node.neighbors.size(), 0);
- RouteModel::Node test_node_2 = RouteModel::Node();
-}
-
-// Test the distance function between nodes.
-TEST_F(RouteModelTest, NodeDistance) {
- RouteModel::Node test_node = model.SNodes()[1];
- RouteModel::Node test_node_2 = model.SNodes()[4];
- EXPECT_FLOAT_EQ(test_node.distance(test_node_2), 0.10309877);
-}
-
-// Test the data created by CreateNodeToRoadHashmap.
-TEST_F(RouteModelTest, NodeToRoad) {
- auto node_to_road = model.GetNodeToRoadMap();
- EXPECT_EQ(node_to_road[0].size(), 2);
- EXPECT_EQ(node_to_road[30].size(), 2);
- EXPECT_EQ(node_to_road[90].size(), 2);
- EXPECT_EQ(node_to_road[0][0]->way, 500);
- EXPECT_EQ(node_to_road[30][1]->way, 613);
- EXPECT_EQ(node_to_road[90][1]->way, 475);
-}
-
-// Test the FindNeighbors method.
-TEST_F(RouteModelTest, FindNeighbors) {
- auto test_node = model.SNodes()[0];
- test_node.FindNeighbors();
- EXPECT_EQ(test_node.neighbors.size(), 2);
- EXPECT_FLOAT_EQ(test_node.neighbors[1]->x, 1.3250526);
- EXPECT_FLOAT_EQ(test_node.neighbors[1]->y, 0.41849667);
- test_node.neighbors.clear(); // Clear out neighbors just added.
- test_node = model.SNodes()[100];
- test_node.FindNeighbors();
- EXPECT_EQ(test_node.neighbors.size(), 2);
- EXPECT_FLOAT_EQ(test_node.neighbors[0]->x, 0.77367586);
- EXPECT_FLOAT_EQ(test_node.neighbors[0]->y, 0.52004427);
- test_node.neighbors.clear();
-}
-
-// Test the FindClosestNode method.
-TEST_F(RouteModelTest, FindClosestNode) {
- float x = 0.023456;
- float y = 0.567890;
- auto& test_node = model.FindClosestNode(x, y);
- EXPECT_EQ(&test_node, &model.SNodes()[10155]);
- EXPECT_FLOAT_EQ(test_node.x, 0.030928569);
- EXPECT_FLOAT_EQ(test_node.y, 0.58042318);
- x = 0.555555;
- y = 0.333333;
- auto& test_node_2 = model.FindClosestNode(x, y);
- EXPECT_EQ(&test_node_2, &model.SNodes()[600]);
- EXPECT_FLOAT_EQ(test_node_2.x, 0.58249766);
- EXPECT_FLOAT_EQ(test_node_2.y, 0.34965551);
-}
diff --git a/test/utest_rm_find_neighbors.cpp b/test/utest_rm_find_neighbors.cpp
deleted file mode 100644
index 1597bc7e..00000000
--- a/test/utest_rm_find_neighbors.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-#include "gtest/gtest.h"
-#include
-#include
-#include
-#include
-#include "../src/route_model.h"
-#include "../src/route_planner.h"
-
-
-static std::optional> ReadFile(const std::string &path)
-{
- std::ifstream is{path, std::ios::binary | std::ios::ate};
- if( !is )
- return std::nullopt;
-
- auto size = is.tellg();
- std::vector contents(size);
-
- is.seekg(0);
- is.read((char*)contents.data(), size);
-
- if( contents.empty() )
- return std::nullopt;
- return std::move(contents);
-}
-
-std::vector ReadOSMData(const std::string &path) {
- std::vector osm_data;
- auto data = ReadFile(path);
- if( !data ) {
- std::cout << "Failed to read OSM data." << std::endl;
- } else {
- osm_data = std::move(*data);
- }
- return osm_data;
-}
-
-
-class RouteModelTest : public ::testing::Test {
- protected:
- std::string osm_data_file = "../map.osm";
- std::vector osm_data = ReadOSMData(osm_data_file);
- RouteModel model{osm_data};
-};
-
-
-// Test that the path size is zero initially.
-TEST_F(RouteModelTest, RouteModelData) {
- EXPECT_EQ(model.path.size(), 0);
- EXPECT_EQ(model.Nodes().size(), model.SNodes().size());
-}
-
-
-// Test that the RouteModel::Node class is defined correctly.
-TEST_F(RouteModelTest, RouteModelNode) {
- RouteModel::Node test_node = model.SNodes()[1];
- EXPECT_FLOAT_EQ(test_node.x, 1.2646476);
- EXPECT_FLOAT_EQ(test_node.y, 0.23506972);
- EXPECT_EQ(test_node.parent, nullptr);
- EXPECT_FLOAT_EQ(test_node.h_value, std::numeric_limits::max());
- EXPECT_FLOAT_EQ(test_node.g_value, 0.0);
- EXPECT_FLOAT_EQ(test_node.visited, false);
- EXPECT_EQ(test_node.neighbors.size(), 0);
- RouteModel::Node test_node_2 = RouteModel::Node();
-}
-
-// Test the distance function between nodes.
-TEST_F(RouteModelTest, NodeDistance) {
- RouteModel::Node test_node = model.SNodes()[1];
- RouteModel::Node test_node_2 = model.SNodes()[4];
- EXPECT_FLOAT_EQ(test_node.distance(test_node_2), 0.10309877);
-}
-
-// Test the data created by CreateNodeToRoadHashmap.
-TEST_F(RouteModelTest, NodeToRoad) {
- auto node_to_road = model.GetNodeToRoadMap();
- EXPECT_EQ(node_to_road[0].size(), 2);
- EXPECT_EQ(node_to_road[30].size(), 2);
- EXPECT_EQ(node_to_road[90].size(), 2);
- EXPECT_EQ(node_to_road[0][0]->way, 500);
- EXPECT_EQ(node_to_road[30][1]->way, 613);
- EXPECT_EQ(node_to_road[90][1]->way, 475);
-}
-
-// Test the FindNeighbors method.
-TEST_F(RouteModelTest, FindNeighbors) {
- auto test_node = model.SNodes()[0];
- test_node.FindNeighbors();
- EXPECT_EQ(test_node.neighbors.size(), 2);
- EXPECT_FLOAT_EQ(test_node.neighbors[1]->x, 1.3250526);
- EXPECT_FLOAT_EQ(test_node.neighbors[1]->y, 0.41849667);
- test_node.neighbors.clear(); // Clear out neighbors just added.
- test_node = model.SNodes()[100];
- test_node.FindNeighbors();
- EXPECT_EQ(test_node.neighbors.size(), 2);
- EXPECT_FLOAT_EQ(test_node.neighbors[0]->x, 0.77367586);
- EXPECT_FLOAT_EQ(test_node.neighbors[0]->y, 0.52004427);
- test_node.neighbors.clear();
-}
diff --git a/test/utest_rm_hashmap.cpp b/test/utest_rm_hashmap.cpp
deleted file mode 100644
index d30acac2..00000000
--- a/test/utest_rm_hashmap.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-#include "gtest/gtest.h"
-#include
-#include
-#include
-#include
-#include "../src/route_model.h"
-#include "../src/route_planner.h"
-
-
-static std::optional> ReadFile(const std::string &path)
-{
- std::ifstream is{path, std::ios::binary | std::ios::ate};
- if( !is )
- return std::nullopt;
-
- auto size = is.tellg();
- std::vector contents(size);
-
- is.seekg(0);
- is.read((char*)contents.data(), size);
-
- if( contents.empty() )
- return std::nullopt;
- return std::move(contents);
-}
-
-std::vector ReadOSMData(const std::string &path) {
- std::vector osm_data;
- auto data = ReadFile(path);
- if( !data ) {
- std::cout << "Failed to read OSM data." << std::endl;
- } else {
- osm_data = std::move(*data);
- }
- return osm_data;
-}
-
-
-class RouteModelTest : public ::testing::Test {
- protected:
- std::string osm_data_file = "../map.osm";
- std::vector osm_data = ReadOSMData(osm_data_file);
- RouteModel model{osm_data};
-};
-
-
-// Test that the path size is zero initially.
-TEST_F(RouteModelTest, RouteModelData) {
- EXPECT_EQ(model.path.size(), 0);
- EXPECT_EQ(model.Nodes().size(), model.SNodes().size());
-}
-
-
-// Test that the RouteModel::Node class is defined correctly.
-TEST_F(RouteModelTest, RouteModelNode) {
- RouteModel::Node test_node = model.SNodes()[1];
- EXPECT_FLOAT_EQ(test_node.x, 1.2646476);
- EXPECT_FLOAT_EQ(test_node.y, 0.23506972);
- EXPECT_EQ(test_node.parent, nullptr);
- EXPECT_FLOAT_EQ(test_node.h_value, std::numeric_limits::max());
- EXPECT_FLOAT_EQ(test_node.g_value, 0.0);
- EXPECT_FLOAT_EQ(test_node.visited, false);
- EXPECT_EQ(test_node.neighbors.size(), 0);
- RouteModel::Node test_node_2 = RouteModel::Node();
-}
-
-// Test the distance function between nodes.
-TEST_F(RouteModelTest, NodeDistance) {
- RouteModel::Node test_node = model.SNodes()[1];
- RouteModel::Node test_node_2 = model.SNodes()[4];
- EXPECT_FLOAT_EQ(test_node.distance(test_node_2), 0.10309877);
-}
-
-// Test the data created by CreateNodeToRoadHashmap.
-TEST_F(RouteModelTest, NodeToRoad) {
- auto node_to_road = model.GetNodeToRoadMap();
- EXPECT_EQ(node_to_road[0].size(), 2);
- EXPECT_EQ(node_to_road[30].size(), 2);
- EXPECT_EQ(node_to_road[90].size(), 2);
- EXPECT_EQ(node_to_road[0][0]->way, 500);
- EXPECT_EQ(node_to_road[30][1]->way, 613);
- EXPECT_EQ(node_to_road[90][1]->way, 475);
-}
diff --git a/test/utest_rm_node_class.cpp b/test/utest_rm_node_class.cpp
deleted file mode 100644
index ba718a53..00000000
--- a/test/utest_rm_node_class.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-#include "gtest/gtest.h"
-#include
-#include
-#include
-#include
-#include "../src/route_model.h"
-#include "../src/route_planner.h"
-
-
-static std::optional> ReadFile(const std::string &path)
-{
- std::ifstream is{path, std::ios::binary | std::ios::ate};
- if( !is )
- return std::nullopt;
-
- auto size = is.tellg();
- std::vector contents(size);
-
- is.seekg(0);
- is.read((char*)contents.data(), size);
-
- if( contents.empty() )
- return std::nullopt;
- return std::move(contents);
-}
-
-
-std::vector ReadOSMData(const std::string &path) {
- std::vector osm_data;
- auto data = ReadFile(path);
- if( !data ) {
- std::cout << "Failed to read OSM data." << std::endl;
- } else {
- osm_data = std::move(*data);
- }
- return osm_data;
-}
-
-
-class RouteModelTest : public ::testing::Test {
- protected:
- std::string osm_data_file = "../map.osm";
- std::vector osm_data = ReadOSMData(osm_data_file);
- RouteModel model{osm_data};
-};
-
-
-// Test that the path size is zero initially.
-TEST_F(RouteModelTest, RouteModelData) {
- EXPECT_EQ(model.path.size(), 0);
- EXPECT_EQ(model.Nodes().size(), 10754);
- ASSERT_EQ(model.SNodes().size(), 0);
-}
-
-
-// Test that the RouteModel::Node class is defined correctly.
-TEST_F(RouteModelTest, RouteModelNode) {
- RouteModel* p_model = &model;
- RouteModel::Node test_node = RouteModel::Node(1, p_model, model.Nodes()[1]);
- EXPECT_FLOAT_EQ(test_node.x, 1.2646476);
- EXPECT_FLOAT_EQ(test_node.y, 0.23506972);
- EXPECT_EQ(test_node.parent, nullptr);
- EXPECT_FLOAT_EQ(test_node.h_value, std::numeric_limits::max());
- EXPECT_FLOAT_EQ(test_node.g_value, 0.0);
- EXPECT_FLOAT_EQ(test_node.visited, false);
- EXPECT_EQ(test_node.neighbors.size(), 0);
- RouteModel::Node test_node_2 = RouteModel::Node();
-}
diff --git a/test/utest_rm_node_dist.cpp b/test/utest_rm_node_dist.cpp
deleted file mode 100644
index 70302607..00000000
--- a/test/utest_rm_node_dist.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-#include "gtest/gtest.h"
-#include
-#include
-#include
-#include
-#include "../src/route_model.h"
-#include "../src/route_planner.h"
-
-
-static std::optional> ReadFile(const std::string &path)
-{
- std::ifstream is{path, std::ios::binary | std::ios::ate};
- if( !is )
- return std::nullopt;
-
- auto size = is.tellg();
- std::vector contents(size);
-
- is.seekg(0);
- is.read((char*)contents.data(), size);
-
- if( contents.empty() )
- return std::nullopt;
- return std::move(contents);
-}
-
-std::vector ReadOSMData(const std::string &path) {
- std::vector osm_data;
- auto data = ReadFile(path);
- if( !data ) {
- std::cout << "Failed to read OSM data." << std::endl;
- } else {
- osm_data = std::move(*data);
- }
- return osm_data;
-}
-
-
-class RouteModelTest : public ::testing::Test {
- protected:
- std::string osm_data_file = "../map.osm";
- std::vector osm_data = ReadOSMData(osm_data_file);
- RouteModel model{osm_data};
-};
-
-
-// Test that the path size is zero initially.
-TEST_F(RouteModelTest, RouteModelData) {
- EXPECT_EQ(model.path.size(), 0);
- EXPECT_EQ(model.Nodes().size(), model.SNodes().size());
-}
-
-
-// Test that the RouteModel::Node class is defined correctly.
-TEST_F(RouteModelTest, RouteModelNode) {
- RouteModel::Node test_node = model.SNodes()[1];
- EXPECT_FLOAT_EQ(test_node.x, 1.2646476);
- EXPECT_FLOAT_EQ(test_node.y, 0.23506972);
- EXPECT_EQ(test_node.parent, nullptr);
- EXPECT_FLOAT_EQ(test_node.h_value, std::numeric_limits::max());
- EXPECT_FLOAT_EQ(test_node.g_value, 0.0);
- EXPECT_FLOAT_EQ(test_node.visited, false);
- EXPECT_EQ(test_node.neighbors.size(), 0);
- RouteModel::Node test_node_2 = RouteModel::Node();
-}
-
-// Test the distance function between nodes.
-TEST_F(RouteModelTest, NodeDistance) {
- RouteModel::Node test_node = model.SNodes()[1];
- RouteModel::Node test_node_2 = model.SNodes()[4];
- EXPECT_FLOAT_EQ(test_node.distance(test_node_2), 0.10309877);
-}
diff --git a/test/utest_rm_snodes.cpp b/test/utest_rm_snodes.cpp
deleted file mode 100644
index 4592809a..00000000
--- a/test/utest_rm_snodes.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-#include "gtest/gtest.h"
-#include
-#include
-#include
-#include
-#include "../src/route_model.h"
-#include "../src/route_planner.h"
-
-
-static std::optional> ReadFile(const std::string &path)
-{
- std::ifstream is{path, std::ios::binary | std::ios::ate};
- if( !is )
- return std::nullopt;
-
- auto size = is.tellg();
- std::vector contents(size);
-
- is.seekg(0);
- is.read((char*)contents.data(), size);
-
- if( contents.empty() )
- return std::nullopt;
- return std::move(contents);
-}
-
-
-std::vector ReadOSMData(const std::string &path) {
- std::vector osm_data;
- auto data = ReadFile(path);
- if( !data ) {
- std::cout << "Failed to read OSM data." << std::endl;
- } else {
- osm_data = std::move(*data);
- }
- return osm_data;
-}
-
-
-class RouteModelTest : public ::testing::Test {
- protected:
- std::string osm_data_file = "../map.osm";
- std::vector osm_data = ReadOSMData(osm_data_file);
- RouteModel model{osm_data};
-};
-
-
-// Test that the path size is zero initially.
-TEST_F(RouteModelTest, RouteModelData) {
- EXPECT_EQ(model.path.size(), 0);
- EXPECT_EQ(model.Nodes().size(), model.SNodes().size());
-}
-
-
-// Test that the RouteModel::Node class is defined correctly.
-TEST_F(RouteModelTest, RouteModelNode) {
- RouteModel::Node test_node = model.SNodes()[1];
- EXPECT_FLOAT_EQ(test_node.x, 1.2646476);
- EXPECT_FLOAT_EQ(test_node.y, 0.23506972);
- EXPECT_EQ(test_node.parent, nullptr);
- EXPECT_FLOAT_EQ(test_node.h_value, std::numeric_limits::max());
- EXPECT_FLOAT_EQ(test_node.g_value, 0.0);
- EXPECT_FLOAT_EQ(test_node.visited, false);
- EXPECT_EQ(test_node.neighbors.size(), 0);
- RouteModel::Node test_node_2 = RouteModel::Node();
-}
diff --git a/test/utest_route_model_class.cpp b/test/utest_route_model_class.cpp
deleted file mode 100644
index 04517d09..00000000
--- a/test/utest_route_model_class.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-#include "gtest/gtest.h"
-#include
-#include
-#include
-#include
-#include "../src/route_model.h"
-#include "../src/route_planner.h"
-
-
-static std::optional> ReadFile(const std::string &path)
-{
- std::ifstream is{path, std::ios::binary | std::ios::ate};
- if( !is )
- return std::nullopt;
-
- auto size = is.tellg();
- std::vector contents(size);
-
- is.seekg(0);
- is.read((char*)contents.data(), size);
-
- if( contents.empty() )
- return std::nullopt;
- return std::move(contents);
-}
-
-
-std::vector ReadOSMData(const std::string &path) {
- std::vector osm_data;
- auto data = ReadFile(path);
- if( !data ) {
- std::cout << "Failed to read OSM data." << std::endl;
- } else {
- osm_data = std::move(*data);
- }
- return osm_data;
-}
-
-
-class RouteModelTest : public ::testing::Test {
- protected:
- std::string osm_data_file = "../map.osm";
- std::vector osm_data = ReadOSMData(osm_data_file);
- RouteModel model{osm_data};
-};
-
-
-// Test that the path size is zero initially.
-TEST_F(RouteModelTest, RouteModelData) {
- EXPECT_EQ(model.path.size(), 0);
- EXPECT_EQ(model.Nodes().size(), 10754);
- ASSERT_EQ(model.SNodes().size(), 0);
-}
diff --git a/test/utest_rp_a_star_search.cpp b/test/utest_rp_a_star_search.cpp
index bd7aae09..ba941f48 100644
--- a/test/utest_rp_a_star_search.cpp
+++ b/test/utest_rp_a_star_search.cpp
@@ -35,87 +35,8 @@ std::vector ReadOSMData(const std::string &path) {
return osm_data;
}
-
-class RouteModelTest : public ::testing::Test {
- protected:
- std::string osm_data_file = "../map.osm";
- std::vector osm_data = ReadOSMData(osm_data_file);
- RouteModel model{osm_data};
-};
-
-
-// Test that the path size is zero initially.
-TEST_F(RouteModelTest, RouteModelData) {
- EXPECT_EQ(model.path.size(), 0);
- EXPECT_EQ(model.Nodes().size(), model.SNodes().size());
-}
-
-
-// Test that the RouteModel::Node class is defined correctly.
-TEST_F(RouteModelTest, RouteModelNode) {
- RouteModel::Node test_node = model.SNodes()[1];
- EXPECT_FLOAT_EQ(test_node.x, 1.2646476);
- EXPECT_FLOAT_EQ(test_node.y, 0.23506972);
- EXPECT_EQ(test_node.parent, nullptr);
- EXPECT_FLOAT_EQ(test_node.h_value, std::numeric_limits::max());
- EXPECT_FLOAT_EQ(test_node.g_value, 0.0);
- EXPECT_FLOAT_EQ(test_node.visited, false);
- EXPECT_EQ(test_node.neighbors.size(), 0);
- RouteModel::Node test_node_2 = RouteModel::Node();
-}
-
-// Test the distance function between nodes.
-TEST_F(RouteModelTest, NodeDistance) {
- RouteModel::Node test_node = model.SNodes()[1];
- RouteModel::Node test_node_2 = model.SNodes()[4];
- EXPECT_FLOAT_EQ(test_node.distance(test_node_2), 0.10309877);
-}
-
-// Test the data created by CreateNodeToRoadHashmap.
-TEST_F(RouteModelTest, NodeToRoad) {
- auto node_to_road = model.GetNodeToRoadMap();
- EXPECT_EQ(node_to_road[0].size(), 2);
- EXPECT_EQ(node_to_road[30].size(), 2);
- EXPECT_EQ(node_to_road[90].size(), 2);
- EXPECT_EQ(node_to_road[0][0]->way, 500);
- EXPECT_EQ(node_to_road[30][1]->way, 613);
- EXPECT_EQ(node_to_road[90][1]->way, 475);
-}
-
-// Test the FindNeighbors method.
-TEST_F(RouteModelTest, FindNeighbors) {
- auto test_node = model.SNodes()[0];
- test_node.FindNeighbors();
- EXPECT_EQ(test_node.neighbors.size(), 2);
- EXPECT_FLOAT_EQ(test_node.neighbors[1]->x, 1.3250526);
- EXPECT_FLOAT_EQ(test_node.neighbors[1]->y, 0.41849667);
- test_node.neighbors.clear(); // Clear out neighbors just added.
- test_node = model.SNodes()[100];
- test_node.FindNeighbors();
- EXPECT_EQ(test_node.neighbors.size(), 2);
- EXPECT_FLOAT_EQ(test_node.neighbors[0]->x, 0.77367586);
- EXPECT_FLOAT_EQ(test_node.neighbors[0]->y, 0.52004427);
- test_node.neighbors.clear();
-}
-
-// Test the FindClosestNode method.
-TEST_F(RouteModelTest, FindClosestNode) {
- float x = 0.023456;
- float y = 0.567890;
- auto& test_node = model.FindClosestNode(x, y);
- EXPECT_EQ(&test_node, &model.SNodes()[10155]);
- EXPECT_FLOAT_EQ(test_node.x, 0.030928569);
- EXPECT_FLOAT_EQ(test_node.y, 0.58042318);
- x = 0.555555;
- y = 0.333333;
- auto& test_node_2 = model.FindClosestNode(x, y);
- EXPECT_EQ(&test_node_2, &model.SNodes()[600]);
- EXPECT_FLOAT_EQ(test_node_2.x, 0.58249766);
- EXPECT_FLOAT_EQ(test_node_2.y, 0.34965551);
-}
-
//--------------------------------//
-// Beginning RouteModel Tests.
+// Beginning RoutePlanner Tests.
//--------------------------------//
class RoutePlannerTest : public ::testing::Test {
@@ -132,15 +53,66 @@ class RoutePlannerTest : public ::testing::Test {
float end_y = 0.9;
RouteModel::Node* start_node = &model.FindClosestNode(start_x, start_y);
RouteModel::Node* end_node = &model.FindClosestNode(end_x, end_y);
+
+ // Construct another node in the middle of the map for testing.
+ float mid_x = 0.5;
+ float mid_y = 0.5;
+ RouteModel::Node* mid_node = &model.FindClosestNode(mid_x, mid_y);
};
-// Test the AStarSearch method stub.
-TEST_F(RoutePlannerTest, AStarSearch) {
+// Test the CalculateHValue method.
+TEST_F(RoutePlannerTest, TestCalculateHValue) {
+ EXPECT_FLOAT_EQ(route_planner.CalculateHValue(start_node), 1.1329799);
+ EXPECT_FLOAT_EQ(route_planner.CalculateHValue(end_node), 0.0f);
+ EXPECT_FLOAT_EQ(route_planner.CalculateHValue(mid_node), 0.58903033);
+}
+
+
+
+// Test the AddNeighbors method.
+bool NodesSame(RouteModel::Node* a, RouteModel::Node* b) { return a == b; }
+TEST_F(RoutePlannerTest, TestAddNeighbors) {
+ route_planner.AddNeighbors(start_node);
+
+ // Correct h and g values for the neighbors of start_node.
+ std::vector start_neighbor_g_vals{0.10671431, 0.082997195, 0.051776856, 0.055291083};
+ std::vector start_neighbor_h_vals{1.1828455, 1.0998145, 1.0858033, 1.1831238};
+ auto neighbors = start_node->neighbors;
+ EXPECT_EQ(neighbors.size(), 4);
+
+ // Check results for each neighbor.
+ for (int i = 0; i < neighbors.size(); i++) {
+ EXPECT_PRED2(NodesSame, neighbors[i]->parent, start_node);
+ EXPECT_FLOAT_EQ(neighbors[i]->g_value, start_neighbor_g_vals[i]);
+ EXPECT_FLOAT_EQ(neighbors[i]->h_value, start_neighbor_h_vals[i]);
+ EXPECT_EQ(neighbors[i]->visited, true);
+ }
+}
+
+
+// Test the ConstructFinalPath method.
+TEST_F(RoutePlannerTest, TestConstructFinalPath) {
+ // Construct a path.
+ mid_node->parent = start_node;
+ end_node->parent = mid_node;
+ std::vector path = route_planner.ConstructFinalPath(end_node);
+
+ // Test the path.
+ EXPECT_EQ(path.size(), 3);
+ EXPECT_FLOAT_EQ(start_node->x, path.front().x);
+ EXPECT_FLOAT_EQ(start_node->y, path.front().y);
+ EXPECT_FLOAT_EQ(end_node->x, path.back().x);
+ EXPECT_FLOAT_EQ(end_node->y, path.back().y);
+}
+
+
+// Test the AStarSearch method.
+TEST_F(RoutePlannerTest, TestAStarSearch) {
route_planner.AStarSearch();
EXPECT_EQ(model.path.size(), 33);
- RouteModel::Node path_start = model.path.back();
- RouteModel::Node path_end = model.path.front();
+ RouteModel::Node path_start = model.path.front();
+ RouteModel::Node path_end = model.path.back();
// The start_node and end_node x, y values should be the same as in the path.
EXPECT_FLOAT_EQ(start_node->x, path_start.x);
EXPECT_FLOAT_EQ(start_node->y, path_start.y);
diff --git a/test/utest_rp_a_star_stub.cpp b/test/utest_rp_a_star_stub.cpp
deleted file mode 100644
index 573372dc..00000000
--- a/test/utest_rp_a_star_stub.cpp
+++ /dev/null
@@ -1,150 +0,0 @@
-#include "gtest/gtest.h"
-#include
-#include
-#include
-#include
-#include "../src/route_model.h"
-#include "../src/route_planner.h"
-
-
-static std::optional> ReadFile(const std::string &path)
-{
- std::ifstream is{path, std::ios::binary | std::ios::ate};
- if( !is )
- return std::nullopt;
-
- auto size = is.tellg();
- std::vector contents(size);
-
- is.seekg(0);
- is.read((char*)contents.data(), size);
-
- if( contents.empty() )
- return std::nullopt;
- return std::move(contents);
-}
-
-std::vector ReadOSMData(const std::string &path) {
- std::vector osm_data;
- auto data = ReadFile(path);
- if( !data ) {
- std::cout << "Failed to read OSM data." << std::endl;
- } else {
- osm_data = std::move(*data);
- }
- return osm_data;
-}
-
-
-class RouteModelTest : public ::testing::Test {
- protected:
- std::string osm_data_file = "../map.osm";
- std::vector osm_data = ReadOSMData(osm_data_file);
- RouteModel model{osm_data};
-};
-
-
-// Test that the path size is zero initially.
-TEST_F(RouteModelTest, RouteModelData) {
- EXPECT_EQ(model.path.size(), 0);
- EXPECT_EQ(model.Nodes().size(), model.SNodes().size());
-}
-
-
-// Test that the RouteModel::Node class is defined correctly.
-TEST_F(RouteModelTest, RouteModelNode) {
- RouteModel::Node test_node = model.SNodes()[1];
- EXPECT_FLOAT_EQ(test_node.x, 1.2646476);
- EXPECT_FLOAT_EQ(test_node.y, 0.23506972);
- EXPECT_EQ(test_node.parent, nullptr);
- EXPECT_FLOAT_EQ(test_node.h_value, std::numeric_limits::max());
- EXPECT_FLOAT_EQ(test_node.g_value, 0.0);
- EXPECT_FLOAT_EQ(test_node.visited, false);
- EXPECT_EQ(test_node.neighbors.size(), 0);
- RouteModel::Node test_node_2 = RouteModel::Node();
-}
-
-// Test the distance function between nodes.
-TEST_F(RouteModelTest, NodeDistance) {
- RouteModel::Node test_node = model.SNodes()[1];
- RouteModel::Node test_node_2 = model.SNodes()[4];
- EXPECT_FLOAT_EQ(test_node.distance(test_node_2), 0.10309877);
-}
-
-// Test the data created by CreateNodeToRoadHashmap.
-TEST_F(RouteModelTest, NodeToRoad) {
- auto node_to_road = model.GetNodeToRoadMap();
- EXPECT_EQ(node_to_road[0].size(), 2);
- EXPECT_EQ(node_to_road[30].size(), 2);
- EXPECT_EQ(node_to_road[90].size(), 2);
- EXPECT_EQ(node_to_road[0][0]->way, 500);
- EXPECT_EQ(node_to_road[30][1]->way, 613);
- EXPECT_EQ(node_to_road[90][1]->way, 475);
-}
-
-// Test the FindNeighbors method.
-TEST_F(RouteModelTest, FindNeighbors) {
- auto test_node = model.SNodes()[0];
- test_node.FindNeighbors();
- EXPECT_EQ(test_node.neighbors.size(), 2);
- EXPECT_FLOAT_EQ(test_node.neighbors[1]->x, 1.3250526);
- EXPECT_FLOAT_EQ(test_node.neighbors[1]->y, 0.41849667);
- test_node.neighbors.clear(); // Clear out neighbors just added.
- test_node = model.SNodes()[100];
- test_node.FindNeighbors();
- EXPECT_EQ(test_node.neighbors.size(), 2);
- EXPECT_FLOAT_EQ(test_node.neighbors[0]->x, 0.77367586);
- EXPECT_FLOAT_EQ(test_node.neighbors[0]->y, 0.52004427);
- test_node.neighbors.clear();
-}
-
-// Test the FindClosestNode method.
-TEST_F(RouteModelTest, FindClosestNode) {
- float x = 0.023456;
- float y = 0.567890;
- auto& test_node = model.FindClosestNode(x, y);
- EXPECT_EQ(&test_node, &model.SNodes()[10155]);
- EXPECT_FLOAT_EQ(test_node.x, 0.030928569);
- EXPECT_FLOAT_EQ(test_node.y, 0.58042318);
- x = 0.555555;
- y = 0.333333;
- auto& test_node_2 = model.FindClosestNode(x, y);
- EXPECT_EQ(&test_node_2, &model.SNodes()[600]);
- EXPECT_FLOAT_EQ(test_node_2.x, 0.58249766);
- EXPECT_FLOAT_EQ(test_node_2.y, 0.34965551);
-}
-
-//--------------------------------//
-// Beginning RouteModel Tests.
-//--------------------------------//
-
-class RoutePlannerTest : public ::testing::Test {
- protected:
- std::string osm_data_file = "../map.osm";
- std::vector osm_data = ReadOSMData(osm_data_file);
- RouteModel model{osm_data};
- RoutePlanner route_planner{model, 10, 10, 90, 90};
-
- // Construct start_node and end_node as in the model.
- float start_x = 0.1;
- float start_y = 0.1;
- float end_x = 0.9;
- float end_y = 0.9;
- RouteModel::Node* start_node = &model.FindClosestNode(start_x, start_y);
- RouteModel::Node* end_node = &model.FindClosestNode(end_x, end_y);
-};
-
-
-// Test the AStarSearch method stub.
-TEST_F(RoutePlannerTest, AStarStub) {
- route_planner.AStarSearch();
- EXPECT_EQ(model.path.size(), 2);
- RouteModel::Node path_start = model.path[1];
- RouteModel::Node path_end = model.path[0];
- // The start_node and end_node x, y values should be the same as in the path.
- EXPECT_FLOAT_EQ(start_node->x, path_start.x);
- EXPECT_FLOAT_EQ(start_node->y, path_start.y);
- EXPECT_FLOAT_EQ(end_node->x, path_end.x);
- EXPECT_FLOAT_EQ(end_node->y, path_end.y);
- EXPECT_FLOAT_EQ(route_planner.GetDistance(), 655.7218);
-}