Need code for the given functions Have to write these functions only in m1.cpp file double findStreetLength(StreetIdx street_id); double findDistanceBetweenTwoPoints(LatLon point_1, LatLon point_2); double findStreetSegmentLength(StreetSegmentIdx double findStreetSegmentTravelTime(StreetSegmentIdx double findAngleBetweenStreetSegments(StreetSegmentIdx street_segment_id); street_segment_id);
src_street_segment_id, StreetSegmentIdx dst_street_segment_id); void closeMap();/n #include #include "m1.h" #include "Streets DatabaseAPI.h" #include "OSMDatabaseAPI.h" #include "globals.h" // load Map will be called with the name of the file that stores the "layer-2" // map data accessed through Streets DatabaseAPI: the street and intersection // data that is higher-level than the raw OSM data). // This file name will always end in ".streets.bin" and you // can call loadStreets DatabaseBIN with this filename to initialize the // layer 2 (Streets Database) API. // If you need data from the lower level, layer 1, API that provides raw OSM // data (nodes, ways, etc.) you will also need to initialize the layer 1 // OSMDatabaseAPI by calling loadOSMDatabaseBIN. That function needs the // name of the ".osm.bin" file that matches your map -- just change // ".streets" to ".osm" in the map_streets_database_filename to get the proper // name. //Load all structures needed std::unordered_map>> gHashOSMNode; bool loadMap(std::string map_streets_database_filename) { bool load_successful = false; //Indicates whether the map has loaded //successfully } bool load_OSM_successful = false; //Indicates whether the corresponding //BIN file loaded load_successful = loadStreetsDatabaseBIN(map_streets_database_filename); if (!load_successful) { return load_successful; } std:: size_t toReplace = map_streets_database_filename.find(".streets"); if (toReplace!=std::string::npos){ std::string map_OSM_database_filename = map_streets_database_filename; map_OSM_database_filename.replace(toReplace, std::string(".streets").length(), ".osm.bin"); load_OSM_successful = loadOSMDatabaseBIN(map_OSM_database_filename); } if (!load_OSM_successful){ return load_OSM_successful; } std::cout << "loadMap: " << map_streets_database_filename << std::endl; //SHOULD IT BE STREETS OR OSM FOR THIS ONE? // Load your map related data structures here. load_successful = true; //Make sure this is updated to reflect whether //loading the map succeeded or failed return load_successful; //Initialize data structures void initializeOSMnode (){ } } //Get total number of nodes int numOfNodes= getNumberOfNodes(); gHashOSMNode.rehash(numOfNodes); for (int i=0; i < numOfNodes; i++){ //Get the node by the index const OSMNode* node = = getNodeByIndex(i); //Get the nodes OSMid OSMID nodeID= = node->id(); //Get the number of tags for that node int tagCount = getTagCount(node); //Create a vector for the nodes tags (key, value pairs) std::vector> tagVector; //Set the size of the vector tagVector.reserve(tagCount); //Fill up the tag vector with its key and value for (int i=0; i < tagCount; i++){ auto tagPair = getTagPair(node, i); tagVector.push_back(tagPair); } } std::string getOSMNodeTagValue(OSMID OSMid, std::string key){ //First, check if that ID exists within the hash-table for OSMNodes auto it = gHashOSMNode.find(OSMid); if (it!=gHashOSMNode.end()){ } //Sort the tags by key and value std::sort(tagVector.begin(), tagVector.end()); //Load the tag vector into the hash-table corresponding to its OSMid gHashOSMNode[nodelD]=std::move(tagVector); } //Key exists for (const auto& tag : it->second){ if (tag.first == key){ } } else { return tag.second; } return "": 1 //Key does not exist return " //Helper function that normalizes a string std::string normalizeString (const std::string &str){ std::string normalized; for (auto c: str){ if(!std::isspace(static_cast(c))) { normalized+=std::tolower(static_cast(c)); } return normalized; std::vector findS TreetIdsFromPartialStreetName(std::string street_prefix){ std::vector partialNames Vector; //change the string to all lower cases with no spaces std::string normalizedPrefix= normalizeString(street_prefix); if (normalizedPrefix.empty()){ return partialNames Vector; } int numOfStreets = getNumStreets(); for (StreetIdx i=0; i < numOfStreets; i++){ std::string streetName = getStreetName(i); if std::string normalizedStreet = normalizeString(streetName); (normalizedStreet.find(normalizedPrefix)==0){ partialNames Vector.push_back(i); } } return partialNames Vector; } // Returns the length of the OSMWay that has the given OSMID, in meters. // To implement this function you will have to access the OSMDatabaseAPI.h // functions. // Speed Requirement --> high double findWayLength(OSMID way_id) { double totalLength = 0.0; // Get the total number of ways in the database int numWays = getNumberOfWays(); // Iterate over all ways for (int i = 0; i < numWays; ++i) { // Get the current way by index const OSMWay* way = getWayByIndex(i); // Check if the OSMID of the current way matches the way_id we're looking for if (way->id() == way_id) { std::vector wayMemberIDs = getWayMembers(way); for (size_t j = 0; j < wayMemberlDs.size() - 1; ++j) { // Retrieve the OSMNode objects for the two consecutive nodes const OSMNode* node1 = getNodeByIndex(wayMemberlDs[j]); const OSMNode* node2 = getNode ByIndex(wayMemberlDs[j+ 1]); // Get the coordinates of the two nodes LatLon coords1 = getNodeCoords(node 1); LatLon coords2 = getNodeCoords(node2); } // Calculate the distance between the two points double distance = findDistanceBetween TwoPoints(coords1, coords2); // Add the distance to the total length of the way totalLength += distance; } if (isClosed Way(way)) { const OSMNode* lastNode = getNodeByIndex(wayMemberIDs.back()); const OSMNode* firstNode = getNodeByIndex(wayMemberIDs.front()); LatLon lastCoords = getNodeCoords(lastNode); LatLon firstCoords = getNodeCoords(firstNode); totalLength += calculateDistance(lastCoords, firstCoords); } break; // Exit the loop after finding and processing the way } return totalLength; } double findFeatureArea(Featureldx feature_id);/n ECE297 Software Design and Communication ECE297 Milestone 1 Using and Creating Efficient APIs 3 "There is more to life than increasing its speed." -Mahatma Gandhi 4 TA: project management, code style, and git = 3/10 Autotester = 7/10 10/100 1 Objectives This milestone focuses on using and extending an application programming interface (API). We have written a library called libstreetsdatabase that allows you to query geographic information database files for cities. This API consists of two pieces, each provided by a different header file. Streets DatabaseAPI.h provides a higher level interface to structured street and intersection data; you will mostly use functions from this header file. OSMDatabaseAPI.h allows you to query lower level OpenStreetMap data on individual geographic points; you will only need to use this API for two functions in this milestone. Winter 2024 In this milestone you will learn to use the API defined by these header files, and you will implement functions that will be useful for your project; essentially you are creating a new, richer API. To make some of the functions in your new API fast, you will also need to create and load some data structures of your own to allow efficient look-ups. You should make use of the STL container classes such as vectors, maps and/or unordered maps that you recently learned about in the course tutorials to build your data structures quickly. Some of the tests we have released for this milestone test the speed of your new API; based on the results of these tests you can see where you need to optimize for speed. After completing this milestone you should be able to: Total marks = 2 | Create a new API of functions that will be useful in your project. Query the libstreetsdatabase API using functions in the provided header files. Use unit tests to test your code. Use STL data structures such as vectors and maps, and choose appropriate data structures to speed up an API. Page 1 of 25 ECE297 Software Design and Communication 2 Problem Statement Winter 2024 In this milestone you will load a skeleton C++ project in your IDE and put it under revision control. This will be the C++ project on which you implement all of your re- maining ECE297 milestones. You will then start using some of the functions (such as getStreetName) Streets DatabaseAPI.h and OSMDatabaseAPI.h which are located in /cad2/ece297s/public/include/streetsdatabase. These APIs allow you to access the data loaded from large binary files that describe all the streets and intersections in a city and more. You will then be asked to implement your own functions that use this API to provide higher-level functions. For example, you will implement a function that returns the names of the streets that meet at a given intersection. You will test your code using the ece297exercise autotester, and submit it using the ece297submit script. Note that you will be using git throughout the milestone to work effectively with your teammates. ! 3 Walkthrough Even though your ECE297 project is divided up into milestones, all of the milestones are part of one project. You will be creating a mapping application similar to Google/Bing Maps. You will build upon the code you write in milestone 1 as you implement milestone 2, and so on. Your project is divided into milestones, but you will use your solutions to the milestones in all subsequent milestones. This is also why you started off by learning how to use git. To build up your project code efficiently, it is important to keep it under revision control and to commit + push often. This will allow you to divide tasks easily among your team members, keep track of all changes made to your project code, and share the latest working code with your teammates. Note that your grade will depend not only on how well your code works, but also on your TA's assessment of your code style, usage of git, and project management. 1. Code correctness and performance will be automatically graded. 2. Project management will graded by your TA. Have you broken up the milestone into tasks assigned to each team member, and are the task owners, due dates and status tracked on your wiki page? 3. Your TA will also consider how well you use git: are there frequent commits by different team members, with good commit messages? 4. Coding style and commenting will be graded by your TA. Page 2 of 25 ECE297 Software Design and Communication Winter 2024 An effective team project is well-commented and uses revision control (such as git) to effectively divide work and maintain a history of code changes. 3.1 Project Setup To setup the project each team member needs to run ece297init 1 as shown below: 1#The following command will setup the project and git repo 2> ece297init 1 3 #Output trimmed... 4 5 You can now open your mapper project in your chosen IDE at: /homes/v/vaughn/ece297/work/mapper 6 7 #NOTE: the above path will differ based on your username. Listing 1: Setting up the project ece297init 1 will create a git remote repository for all group members under /groups/ ECE297S/cd-XXX/mapper_repo (where XXX is your group number), and commits the initial project files. It then clones a local repository and a working copy under ~/ece297/work/ mapper, which you can open as a Visual Studio Code, NetBeans, CLion or Eclipse project. You will use this project and repository for all the following milestones. 3.2 Code Organization In this milestone you are building a library of higher level (more complex) functions that will be useful in later milestones. To build these higher level functions, you will call lower-level functions we have written for you that provide basic data from the OpenStreetMap database. The organization of these application programming interface (API) layers and of the code is shown in Fig. 1 and Fig. 2, respectively, and is detailed below. libstreetmap/src: This is the library that you will be creating throughout your ECE297 project. It contains "m1.cpp", which includes “m1.h". m1.h defines the interfaces of all the functions you will implement in milestone 1; you cannot change these interfaces and accordingly m1.h is a read-only file (in /cad2/ece297s/public/include/milestones) that you can read but can't modify. You must write the implementation of all the m1.h function interfaces in files in libstreetmap/src; m1.cpp is a possible implementation file but you can create additional or different .cpp and .h files if you prefer. The comments in m1.h also give information about corner cases you should handle and how fast the various functions need to be; the ece297exercise autotester provides the precise speed specification by automatically testing the speed of these functions. • libstreetsdatabase: This library provides the functions for accessing the libstreets- database API that parses and interprets OSM data; it has been written for you. The most im- portant header file is StreetsDatabaseAPI.h, and OSMDatabaseAPI.h is the next most im- portant. These files and the other headers for this library are in /cad2/ece297s/public/include/streetsdataba Page 3 of 25 ECE297 libstreetmap Software Design and Communication m1.h m1.cpp helper.cpp Layer 2: most milestone 1 routines need this ● call functions from Streets DatabaseAPI.h --- toronto_canada.streets.bin loads data from OSMDatabaseAPI.h Your .cpp files go here: can have as many as you like Figure 1: Project API layers. Layer 1: most detail, less processed; one milestone 1 routine needs it toronto_canada.osm.bin Winter 2024 libstreetsdatabase you can read and use them but cannot modify them. An easy way to read these headers is to use VSCode or another IDE to navigate into them. Streets DatabaseAPI.h is made up of several functions, and each function gives you infor- mation about streets or intersections that exist in a cityname.streets.bin file. Data for OSMDatabase API.h is stored in a separate file called cityname.osm.bin. We'll be testing your code with the data files for several cities, including Toronto, New York, and Kyiv. 3.3 Understand StreetsDatabase API.h • main: This folder contains your "main.cpp" file; this is where your program starts executing when you type mapper at the command line. You can call the functions you wrote in libstreetmap from here. We have provided a simple main.cpp file that will simply load and close a map; you don't need to change it for milestone 1. libstreetmap/tests: Most of your testing in this course won't be performed with the mapper executable program that an end user would run. Instead, you will use Unit Tests that directly link to and test your libstreetmap functions. We have written unit tests for all the functions of this milestone; if you wish you can write additional tests and put the code for them in this folder. Fig. 3 shows how a map is represented internally in the libstreetsdatabase. Each Intersection is a graph node and each Street Segment is a graph edge (which connects two Intersection nodes). Note that multiple Street Segments make up one Street - for example, the dotted Street Segments are all part of one Street (College St.). Page 4 of 25 ECE297 mapper - NetBeans IDE 8.1 File Edit View Navigate Source Refactor Run Debug Team Tools Window Help X Fil. mapper lemapper - /cad2/ece297s/de build 9 release alibstreetmap src Cm1.cpp tests Ltester_main.cpp lamain Asrc L main.cpp Makefile mapper test_libstreetmap Software Design and Communication Important Files Cm1.cpp x tester_main.cpp x 2 3 4 Source History 1 #include "ml.h" 5698 7 UnitTest_Release } KA #include "Streets Database API.h" 12 13 } 9 10 void close_map() { 11 Lo Versioning Output Search Results hote bool load_map(std::string /*map_path*/) { //Load your map related data structures here return true; QSearch (Ctrl+1) StreetsDatabaseAPI.h x ml.h x //Clean-up your map related data structures here. Figure 2: Source code folders in NetBeans. 2:32 ▶ Winter 2024 23 INS In the libstreetsdatabase graph, each graph node is an Intersection, and each graph edge (between 2 nodes) is a Street Segment. The provided StreetsDatabaseAPI has an integer id for each of the intersections; from 0 to getNumIntersections ()-1 - which is the total number of intersections. Similarly, each Street Segment has an integer id from 0 to getNumStreet Segments ()-1 and each Street has an integer id from 0 to get NumStreets()-1. Additionally, each Intersection has a name, and each Street has a name. Note that it is possible for two Streets to have the same name; there is more than one Main Street in Greater Toronto for example. Intersection names are formed from the names of the streets that meet at that intersection. Street Segments do not have unique names associated with them. Each Intersection, Street Segment, or Street has a unique integer ID. Only Intersections and Streets have names, and they may not be unique. Listing 2 shows "StreetsDatabaseAPI.h" which contains the libstreetsdatabase API func- tions that you can use to retrieve information about the map-graph of Toronto. All function prototypes are commented; this is the best kind of documentation as it always remains with the code. Study the API and the comments, and try out the different functions to understand what each function does and how it works. Note that in addition to Streets, Street Segments and Intersections, the Streets DatabaseAPI also provides 'Points of Interest' which are simply interesting landmarks, such as Union Station or a Tim Horton's store. Each 'Point of Interest' has a location, name and a type (another string) only. There are also function calls to obtain natural features like the bound- aries of parks and lakes and function calls to obtain the unique OSMid (identifier) for each Page 5 of 25