If you run this program, you'll see that it works fine, but the only problem I have is that my Manhattan Distance is occasionally wrong. My equation seems to be fine, and I don't have a debugger in VS Code, so I am having extreme difficulty diagnosing this problem. My Manhattan Distance calculation seems to be silently breaking whenever it wants to, and it's confusing me.
Source code:
#include <iostream>
#include <fstream>
#include <cstdlib> //For std::exit()
#include <vector>
#include <cmath>
#include <iomanip>
struct dataPoint {
int x1;
int y1;
std::string name;
};
struct queryPoint {
int x2;
int y2;
std::string name;
};
class File
{
public:
File(std::string dataFile, std::string queryFile)
: m_dataFile{ dataFile }, m_queryFile{ queryFile }
{
m_dataPoints.reserve(50);
m_queryPoints.reserve(50);
}
//Constructor to initalize class object.
void errorDataCheck() {
std::ifstream infile;
infile.open(m_dataFile);
if(!infile.is_open()) {
std::cout << "Error: Unable to open the data file\n";
infile.close(); //Close file before exiting to prevent corruption.
std::exit(3);
} //std::exit is okay to use here, since we don't risk corruption.
infile.close();
}
void errorQueryCheck() {
std::ifstream infile;
infile.open(m_queryFile);
if(!infile.is_open()) {
std::cout << "Error: Unable to open the query file\n";
infile.close();
std::exit(3);
}
infile.close();
}
void errorCheck() {
errorDataCheck();
errorQueryCheck();
}
void const readFile() {
std::ifstream dataInfile;
dataInfile.open(m_dataFile);
bool data1{ false };
bool data2{ false };
bool query1{ false };
bool query2{ false };
while( !dataInfile.eof() ) {
dataPoint dataPoint;
dataInfile >> dataPoint.x1;
dataInfile >> dataPoint.y1;
dataInfile >> dataPoint.name;
m_dataPoints.push_back(dataPoint);
}
dataInfile.close();
std::ifstream queryInfile;
queryInfile.open(m_queryFile);
while( !queryInfile.eof() ) {
queryPoint point;
queryInfile >> point.x2;
queryInfile >> point.y2;
queryInfile >> point.name;
if(data1 || data2 || query1 || query2) {
if(data1) std::cout << "Invalid point in data file\n";
if(data2) std::cout << "Invalid point in data file\n";
if(query1) std::cout << "Invalid point in query file\n";
if(query2) std::cout << "Invalid point in query file\n";
std::exit(3);
}
m_queryPoints.push_back(point);
}
queryInfile.close();
}
void sendFile() {
std::ofstream outfile;
for(auto& dataElement : m_dataPoints) {
if(dataElement.name == m_dataPoints[m_dataPoints.size()].name) //Discard final element in vector because it's garbage. Tbh I don't even know how it got there.
break;
std::string fileName{"Distances_" + dataElement.name};
outfile.open(fileName);
outfile << "x1 y1 label\n";
outfile << dataElement.x1 << ' ' << dataElement.y1 << ' ' << dataElement.name << '\n';
outfile << "x2 y2 manDist eucDist label\n";
for(auto& queryElement : m_queryPoints) {
if(queryElement.name == m_queryPoints[m_queryPoints.size()].name)
break;
outfile << queryElement.x2 << ' ' << queryElement.y2 << ' ';
outfile << std::setprecision(4) << abs( (dataElement.x1 - queryElement.x2) + (dataElement.y1 - queryElement.y2) ) << ' ';
outfile << std::setprecision(4) << sqrt( pow(dataElement.x1 - queryElement.x2, 2) + pow(dataElement.y1 - queryElement.y2, 2) ) << ' ';
outfile << queryElement.name << '\n';
}
outfile.close();
}
}
void print() {
for(auto& element : m_dataPoints)
std::cout << element.x1 << ' ' << element.y1 << ' ' << element.name << '\n';
for(auto& element : m_queryPoints)
std::cout << element.x2 << ' ' << element.y2 << ' ' << element.name << '\n';
}
private:
std::string m_dataFile;
std::string m_queryFile;
std::vector<dataPoint> m_dataPoints;
std::vector<queryPoint> m_queryPoints;
};
void errorArgcCheck(int argc)
{
if(argc == 1) {
std::cout << "Usage: ./a.out dataFile queryFile\n";
std::exit(1);
}
else if(argc != 3) {
std::cout << "Error: Incorrect amount of command line arguments\n";
std::exit(1);
}
} //Has to be done outside class before we can initialize object.
int main(int argc, char* argv[])
{
errorArgcCheck(argc); //Check argv[1] and argv[2] for existence before initialize File object.
File files{argv[1], argv[2]}; //Initialize class object with file names and argc
files.errorCheck(); //Computationally expensive to open and close files, but doesn't matter for a 100-200 line program.
files.readFile();
files.sendFile();
files.print();
std::cout << '\n';
return 0;
}
Data file:
-1200 300 Plane_001
-1100 500 Plane_002
-800 200 Plane_003
-400 600 Plane_004
-1100 -100 Plane_005
-800 -400 Plane_006
-500 -600 Plane_007
200 100 Plane_008
300 800 Plane_009
700 100 Plane_010
900 400 Plane_011
400 -600 Plane_012
800 -800 Plane_013
1000 -300 Plane_014
Query File:
-1300 100 SFO
-1200 700 SEA
-900 500 JAC
-600 100 SLC
-200 700 MSP
-200 300 JAC
-1200 -300 LAX
-700 -200 LAS
-300 -100 DEN
-400 -500 PHX
0 -300 DFW
100 500 ORD
300 500 DTW
700 700 EWR
900 700 JFK
900 100 CLT
300 -100 STL
500 -400 ATL
900 -600 MCO
1000 -800 MIA
Desired output for distance_plane_001 file:
x1 y1 label
-1200 300 Plane_001
x2 y2 manDist eucDist label
-1300 100 300 223.6 SFO
-1200 700 400 400 SEA
-900 500 500 360.6 JAC
-600 100 800 632.5 SLC
-200 700 1400 1077 MSP
-200 300 1000 1000 JAC
-1200 -300 600 600 LAX
-700 -200 1000 707.1 LAS
-300 -100 1300 984.9 DEN
-400 -500 1600 1131 PHX
0 -300 1800 1342 DFW
100 500 1500 1315 ORD
300 500 1700 1513 DTW
700 700 2300 1942 EWR
900 700 2500 2138 JFK
900 100 2300 2110 CLT
300 -100 1900 1552 STL
500 -400 2400 1838 ATL
900 -600 3000 2285 MCO
1000 -800 3300 2460 MIA
The program output for plane_001:
x1 y1 label
-1200 300 Plane_001
x2 y2 manDist eucDist label
-1300 100 300 223.6 SFO
-1200 700 400 400 SEA
-900 500 500 360.6 JAC
-600 100 400 632.5 SLC
-200 700 1400 1077 MSP
-200 300 1000 1000 JAC
-1200 -300 600 600 LAX
-700 -200 0 707.1 LAS
-300 -100 500 984.9 DEN
-400 -500 0 1131 PHX
0 -300 600 1342 DFW
100 500 1500 1315 ORD
300 500 1700 1513 DTW
700 700 2300 1942 EWR
900 700 2500 2138 JFK
900 100 1900 2110 CLT
300 -100 1100 1552 STL
500 -400 1000 1838 ATL
900 -600 1200 2285 MCO
1000 -800 1100 2460 MIA