Best container for coordinates - c++

I'm currently trying to pick up coordinates from a txt file in use of xlib and I've been wondering what's the best container to use for such an endeavor? I was thinking multidimensional arrays since my program is going to work with triangles and a shortest path algorithm I also wanted to ask how best to fill said container using the scan function too, the plan is to use use nested loops in order to fill it up.
EDIT: The txt file that I'm planning on using is a list of triangle coordinates to draw using the xlib function, Then by placing points on the interface, to find the shortest path from a user-defined spot to another, with the triangles serving as obstacles.
int main(int argc,char *argv[])
{
int A,B;
int Trig[A][B];
FILE * pFile;
// First need to scan the file. Need to check if there's a file to look into first.
std::string pFilename = argv[1];
if (pFilename == ""){
cout << "Needs a Filename";
}
pFile = fopen(atoi(pFilename),"r");
// scanf(pFile,"%1s (%d,%d) (%d,%d) (%d,%d)",);
return 0;
}

If those are 2D coordinates, std::pair would be a great choice.
#include <utility>
int main()
{
std::pair<int, int> intCoordinates(5, 3);
std::cout << "x: " << intCoordinates.first;
std::cout << "y: " << intCoordinates.second << "\n";
// -- hocus pocus, array of pairs, use it as normal C array
std::pair<int, int> arr[5];
}
Of course you can change the type of variables.
It can be <double, double> or even <double, int> if you want, that's completely up to you.
More informations: http://www.cplusplus.com/reference/utility/pair/pair/
In this or any other cases, Point struct would do the job:
struct Point {
int x, y;
Point(int a, int b) { this->x = a; this->y = b; }
};
int main()
{
Point p(2,3);
// ...
}
We probably cannot give your more advices unless you bring us more informations about your code.

I faced the same issue recently and found that post. I started using pair as suggested here but at the end it wasn't that easy to use and to maintain so I created my own Struct with some utilities operators.
.hpp
struct Coordinates
{
std::size_t x;
std::size_t y;
Coordinates(std::size_t x, std::size_t y);
void add(std::size_t x, std::size_t y);
Coordinates operator+=(const Coordinates &coordinate);
Coordinates operator+(Coordinates coordinate);
};
.cpp
Coordinates::Coordinates(std::size_t x, std::size_t y) : x(x), y(y)
{
}
void Coordinates::add(std::size_t xAdd, std::size_t yAdd)
{
x += xAdd;
y += yAdd;
}
Coordinates Coordinates::operator+=(const Coordinates &coordinate)
{
add(coordinate.x, coordinate.y);
return *this;
}
Coordinates Coordinates::operator+(Coordinates coordinate)
{
return coordinate += *this;
}
Here is what you can do:
Coordinates myPoint(4, 7);
myPoint += Coordinates(2, 3); // myPoint now contains x = 6 and y = 10
You can also access fields x and y by doing yourPoint.x or yourPoint.y.

Related

I'm getting a conversion error in my C++ solution for TSP

I am attempting to solve TSP in C++ with a multidimensional array and am receiving an error message about type conversion.
I've gotten rusty on C++ having not used it in a few years, so to relearn I decided to try a few Travelling Salesman solutions. The first I'm using uses a multidimensional array to store the points, which are being assigned randomly. That part worked fine, so I moved on to the distance formula. I created a helper function for the basic distance formula that takes 2 arrays as its input which functions fine on its own, then created a function to find the total distance of a full array of cities. It takes in an array of doubles and an integer that represents the total number of cities, then iterates through the array finding the distance for each point and adding them together.
Here's the variable declaration and random point assignment
int numCities = 10;
double cities[numCities][2];
//Creates random(unseeded) points
for(int i = 0; i < numCities; i++){
for(int j = 0; j < 2; j++){
cities[i][j] = (rand() % 100) + 1;
}
}
Here's the line being used to call the function
cout << distTotal(cities, numCities) << endl;
And here's the function and helper function
//basic distance formula
double cityDist(double cityA[], double cityB[]){
return sqrt(pow((cityB[0]-cityA[0]), 2.0)+
pow((cityB[1]-cityA[1]), 2.0));
}
//calculate total distance of group of cities
double distTotal(double* points[], int num){
double total = 0;
for(int i = 0; i < num-1; i++){
total=total+cityDist(points[i], points[i+1]);
}
return total;
}
So ideally this should be giving me the total distance between all the points in the base order given here. However, I'm currently getting the following error:
error: cannot convert 'double (*)[2]' to 'double**' for argument '1' to 'double distTotal(double**, int)'
If I remember correctly, this could have to do with pointers, but I honestly don't remember enough about C++ pointers to know how to fix it.
Any help is appreciated, thanks
Your declaration should be double* points as C-arrays decay into pointers. If doing c++ you might consider using std::vector<double>& as an input instead.
Edit: if you end up using c-arrays you will have to allocate them on the heap and free the resources.
int numCities = 10;
double cities[numCities][2];
Instead of having an anonymous pair of doubles containing the x and y position of each city, create a class/struct for it. It'll make it easier to expand your solution later. If you'd like to store the name of the city with its position for example:
struct position_t {
double x;
double y;
};
struct city_t {
position_t position;
std::string name;
};
Then, instead of having a fixed number of cities in an array, consider using a vector which can grow and shrink dynamically during runtime:
std::vector<city_t> cities;
With some helper functions added:
#include <cmath>
#include <iostream>
#include <string>
#include <string_view>
#include <vector>
struct position_t {
position_t(double X, double Y) : x(X), y(Y) {}
double dist(const position_t& other) const {
return std::sqrt(std::pow(x - other.x, 2.) + std::pow(y - other.y, 2.));
}
// a function to print the position
friend std::ostream& operator<<(std::ostream&, const position_t&);
double x;
double y;
};
std::ostream& operator<<(std::ostream& os, const position_t& p) {
return os << '{' << p.x << ',' << p.y << '}';
}
struct city_t {
city_t(const position_t& p, const std::string_view& n) : position(p), name(n) {}
double dist(const city_t& other) const {
// this distance function just calls the function in the position_t
return position.dist(other.position);
}
// a function to print the values of the city
friend std::ostream& operator<<(std::ostream&, const city_t&);
position_t position;
std::string name;
};
std::ostream& operator<<(std::ostream& os, const city_t& c) {
return os << c.position << ' ' << c.name;
}
int main() {
std::vector<city_t> cities = {{{10., 20.}, "Ankeborg"},
{{11., 12.}, "Gothenburg"}};
for(const auto& c : cities) {
std::cout << c << "\n";
}
std::cout << "distance: " << cities[0].dist(cities[1]) << "\n";
}
Output:
{10,20} Ankeborg
{11,12} Gothenburg
distance: 8.06226

Segmentation Fault encountered while implementation of DFS using STL in C++

Debugging of segmentation fault is one of the key issues I am facing as beginner in C++. I had tried to implement Depth First Search in Directed Graphs using C++ STL in the following lines of code (based on Steven Skienna's Algorithm Design Manual) :
#include <iostream>
#include <list>
#include <cstdio>
using namespace std;
#define TREE 0 /* tree edge */
#define BACK 1 /* back edge */
#define CROSS 2 /* cross edge */
#define FORWARD 3 /* forward edge */
class Graph
{
int V; //no of vertices
int time;
list <int> *adj; //Pointer to an array containeing the adjacency list
public:
Graph(int V); //A constructor
int entry_time[] ,exit_time[] , parent[] ;
bool processed[] , discovered[] ;
void addEdge(int v , int w ) ; // a function to add an edge to graph
void DFS(int v); // print DFS transversal of the complete graph
void initializeGraph () ; // a function used by DFS
void process_edge(int x , int y);
void process_vertex_early(int x);
void process_vertex_late(int x);
int edge_classification(int x , int y);
};
Graph::Graph(int V)
{
this->V = V;
adj = new list<int>[V]; // dynamic allocation of V lists to an array named adj
}
void Graph::addEdge(int v, int w )
{
adj[v].push_back(w); //Add w to v's list
}
void Graph::initializeGraph ()
{
time = 0;
for (int j=0;j<V;j++)
{
processed[j]=discovered[j] = false;
parent[j]=-1;
}
// Recur for all the vertices adjacent to this vertex
}
void Graph::DFS(int v)
{
process_vertex_early(v);
list <int>::iterator i ;
for (i=(adj[v].begin());i!=adj[v].end();++i)
{ cout << *i ;
if (discovered[*i]==false)
{
parent[*i] = v ;
process_edge(v,*i);
DFS(*i);
}
else if (processed[*i]==false)
process_edge(v,*i);
}
process_vertex_late(v);
}
void Graph::process_vertex_early(int v)
{
discovered[v] = true;
time = time +1 ;
entry_time[v] = time ;
printf("discovered vertex %d at time %d\n",v, entry_time[v]);
}
void Graph::process_vertex_late(int v)
{
time = time + 1 ;
exit_time[v] = time;
processed[v] = true;
//printf("processed vertex %d at time %d\n",v, exit_time[v]);
}
int Graph::edge_classification (int x , int y )
{
if (parent[y]==x) return (TREE);
if (discovered[y] && !processed[y]) return (BACK);
//cout << " Warning : self loop " << x << y ;
}
void Graph::process_edge(int x , int y)
{
int type ;
type = edge_classification(x,y);
//if (type== BACK) cout << "Back Edge" << x << " -> " << y << endl;
//else if (type== TREE) cout << "Tree Edge" << x << " -> " << y << endl;
//else cout << " Not in the type " ;
}
int main()
{
Graph g(4);
g.initializeGraph();
g.addEdge(0,1);
g.addEdge(0,2);
g.addEdge(1,2);
g.addEdge(2,0);
g.addEdge(2,3);
g.addEdge(3,1);
cout << " Following is a DFS transversal \n " ;
g.DFS(0);
return 0;
}
Segmentation Fault occurs after the search operation reaches a depth of one or two. I had tried applying Breadth First Search using a similar syntax which worked . Please help me in debugging this code . Thanks .
Step one is to read all compiler warnings (and compile with warnings switched on).
For example:
int entry_time[] ,exit_time[] , parent[] ;
These arrays are defined with no size - but you are putting data in them. This means you are writing outside the array boundaries which cause Undefined Behavior (such as the crashing and double-frees you are seeing). Either allocate space for these arrays like you do for adj, or use another container (such as vector) which you can resize as needed.
Also edge_classification doesn't always return a value - your compiler should have warned you about this.
Edit: More about std::vector
You can't declare your arrays to be as entry_time[V] because the value of V isn't known at compile time. You could have many different Graph objects with different sizes.
If you change your arrays to std::vector you can then allocate their size in the Graph constructor and let the std::vector class worry about allocating and freeing memory.
For example:
In the class declare entry_time as a std:vector:
std::vector<int> entry_time;
In the constructor, set the size of the entry_time vector.
entry_time.resize(V);
Note that you can use V here as a parameter to resize as this is at run-time so it now has a value.
std::vector has a normal array-like accessor, so you can assign values into the entries of the vector as you would an array. For example, your existing code will still work:
entry_time[v] = time ;

Should I be attempting to return an array, or is there a better solution?

A problem set for people learning C++ is
Write a short program to simulate a ball being dropped off of a tower. To start, the user should be asked for the initial height of the tower in meters. Assume normal gravity (9.8 m/s2), and that the ball has no initial velocity. Have the program output the height of the ball above the ground after 0, 1, 2, 3, 4, and 5 seconds. The ball should not go underneath the ground (height 0).
Before starting C++ I had a reasonable, but primarily self taught, knowledge of Java. So looking at the problem it seems like it ought to be split into
input class
output class
calculations class
Physical constants class (recommended by the question setter)
controller ('main') class
The input class would ask the user for a starting height, which would be passed to the controller. The controller would give this and a number of seconds (5) to the calculations class, which would create an array of results and return this to the controller. The controller would hand the array of results to the output class that would print them to the console.
I will put the actual code at the bottom, but it's possibly not needed.
You can probably already see the problem, attempting to return an array. I'm not asking how to get round that problem, there is a workaround here and here. I'm asking, is the problem a result of bad design? Should my program be structured differently, for performance, maintenance or style reasons, such that I would not be attempting to return an array like object?
Here is the code (which works apart from trying to return arrays);
main.cpp
/*
* Just the main class, call other classes and passes variables around
*/
#include <iostream>
#include "dropSim.h"
using namespace std;
int main()
{
double height = getHeight();
int seconds = 5;
double* results = calculateResults(height, seconds);
outputResults(results);
return 0;
}
getHeight.cpp
/*
* Asks the user for a height from which to start the experiment
* SI units
*/
#include <iostream>
using namespace std;
double getHeight()
{
cout << "What height should the experiment start at; ";
double height;
cin >> height;
return height;
}
calculateResults.cpp
/*
* given the initial height and the physical constants, the position of the ball
* is calculated at integer number seconds, beginning at 0
*/
#include "constants.h"
#include <cmath>
#include <iostream>
using namespace std;
double getPosition(double height, double time);
double* calculateResults(double height, int seconds)
{
double positions[seconds + 1];
for(int t = 0; t < seconds + 1; t++)
{
positions[t] = getPosition(height, t);
}
return positions;
}
double getPosition(double height, double time)
{
double position = height - 0.5*constants::gravity*pow(static_cast<double>(time), 2);
if( position < 0) position = 0;
//Commented code is for testing
//cout << position << endl;
return position;
}
outputResults.cpp
/*
* Takes the array of results and prints them in an appropriate format
*/
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
void outputResults(double* results){
string outputText = "";
//The commented code is to test the output method
//Which is working
//double results1[] = {1,2,3,4,5};
//int numResults = sizeof(results1)/sizeof(results1[0]);
int numResults = sizeof(results)/sizeof(results[0]);
//cout << numResults; //= 0 ... Oh
for(int t = 0; t < numResults; t++)
{
ostringstream line;
line << "After " << t << " seconds the height of the object is " << results[t] << "\r";
outputText.append(line.str());
}
cout << outputText;
}
And finally a couple of headers;
dropSim.h
/*
* dropSim.h
*/
#ifndef DROPSIM_H_
#define DROPSIM_H_
double getHeight();
double* calculateResults(double height, int seconds);
void outputResults(double* results);
#endif /* DROPSIM_H_ */
constants.h
/*
* Contains physical constants relevant to simulation.
* SI units
*/
#ifndef CONSTANTS_H_
#define CONSTANTS_H_
namespace constants
{
const double gravity(9.81);
}
#endif /* CONSTANTS_H_ */
I would say that you're over-engineering a big solution to a little problem, but to answer your specific question:
Should my program be structured differently, for performance, maintenance or style reasons, such that I would not be attempting to return an array like object?
Returning an array-like object is fine. But that doesn't mean returning an array, nor does it mean allocating raw memory with new.
And it's not restricted to return values either. When you're starting out with C++, it's probably best to just forget that it has built-in arrays at all. Most of the time, you should be using either std::vector or std::array (or another linear collection such as std::deque).
Built-in arrays should normally be viewed as a special-purpose item, included primarily for compatibility with C, not for everyday use.
It may, however, be worth considering writing your computation in the same style as the algorithms in the standard library. This would mean writing the code to receive an iterator to a destination, and writing its output to wherever that iterator designates.
I'd probably package the height and time together as a set of input parameters, and have a function that generates output based on those:
struct params {
double height;
int seconds;
};
template <class OutIt>
void calc_pos(params const &p, OutIt output) {
for (int i=0; i<p.seconds; i++) {
*output = get_position(p.height, i);
++output;
}
}
This works somewhat more clearly along with the rest of the standard library:
std::vector<double> results;
calc_pos(inputs, std::back_inserter(results));
You can go a few steps further if you like--the standard library has quite a bit to help with a great deal of this. Your calc_pos does little more than invoke another function repeatedly with successive values for the time. You could (for example) use std::iota to generate the successive times, then use std::transform to generate outputs:
std::vector<int> times(6);
std::iota(times.begin(), times.end(), 0);
std::vector<double> distances;
std::transform(times.begin(), times.end(), compute_distance);
This computes the distances as the distance dropped after a given period of time rather than the height above the ground, but given an initial height, computing the difference between the two is quite trivial:
double initial_height = 5;
std::vector<double> heights;
std::transform(distances.begin(), distances.end(),
std::back_inserter(heights),
[=](double v) { return max(initial_height-v, 0); });
At least for now, this doesn't attempt to calculate the ball bouncing when it hits the ground--it just assumes the ball immediately stops when it hits the ground.
You should get rid of self-allocated double * and use std::vector<double> instead. It's not difficult to learn and a basic step in modern C++
This is how I would solve the problem:
#include <cmath>
#include <iostream>
#include <iomanip>
using std::cin;
using std::cout;
using std::endl;
using std::sqrt;
using std::fixed;
using std::setprecision;
using std::max;
using std::setw;
static const double g = 9.81;
class Calculator {
public:
Calculator(double inh) : h(inh)
{
}
void DoWork() const {
double tmax = sqrt(h / ( g / 2));
for (double t=0.0; t<tmax; t+=1.0) {
GenerateOutput(t);
}
GenerateOutput(tmax);
}
private:
void GenerateOutput(double t) const {
double x = g * t * t / 2;
double hremaining = max(h - x, 0.0);
cout << fixed << setprecision(2) << setw(10) << t;
cout << setw(10) << hremaining << endl;
}
double h;
};
int main() {
double h(0.0);
cout << "Enter height in meters: ";
cin >> h;
if (h > 0.0) {
const Calculator calc(h);
calc.DoWork();
} else {
return 1;
}
return 0;
}

Trouble while writing an resiseable vector with std::vector

i'm a Brazilian beginner in c++ coding (apologize my poor knowledge in both things). I'm trying to write an .txt output file containing the positions of pixels i click with the mouse. I'm making use of opencv library, so thats a functional part of the code:
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <vector>
#include <fstream>
using namespace std;
using namespace cv;
//declaration of vector and counter
int i = 1;
std::vector<int>vet_x(i);
std::vector<int>vet_y(i);
//the callback function
void CallBackFunc(int event, int x, int y, int flags, void* userdata)
{
if (event == EVENT_LBUTTONDOWN)
{
vet_x.resize(i);
vet_y.resize(i);
vet_x[i] = x;
vet_y[i] = y;
i++;
cout << "Left button of the mouse is clicked - position (" << x << ", " << y << ")" << endl;
}
}
int main(int argc, char** argv)
{
Mat img = imread("lena.jpg");
//Create a window
namedWindow("Mouse Track Test", 1);
//set the callback function for mouse event
setMouseCallback("Mouse Track Test", CallBackFunc, NULL);
//show the image
imshow("Mouse Track Test", img);
// Wait until user press some key
waitKey(0);
//the writing begins after the press of the key
ofstream myfile;
myfile.open("points.txt");
for (int j = 1; j <= vet_x.size(); j++)
{
cout << vet_x[j] << "," << vet_y[j] << endl;
myfile << vet_x[j] << "," << vet_y[j] << endl;
}
myfile.close();
return 0;
}
The problem is: the file write only the last clicked position!
But if i turn the "vet_x.reserve(1024);" line, it works well, but only for the y coordinates...
So, what is my mistake?
C++ array indexing is 0-based. Thus when you resize a vector v to size 1, and assign to v[1], you're assigning to a non-existing item. This is Undefined Behavior.
To catch this kind of out-of-bounds indexing you can use the at method, which guarantees an exception. I.e., writing v.at(i) instead of v[i].
However, you should simply use the push_back member function to add items to a vector. I.e., v.push_back( x ), where x is the value that you want to add. It can also be a good idea to use a single vector of 2D points, instead of one vector for x and one vector for y.
vet_x.resize(i);
vet_y.resize(i);
vet_x[i]=x;
vet_y[i]=y;
You are assigning elements out of range, which is an undefined behavior. After resize(i) the last valid index is i-1. std::vector operator [] never insert elements in the container.
Rather just do
vet_x.push_back(x);
vet_y.push_back(y);
Your method of adding variables into vectors is wrong. I suggest this:
struct Point
{
int x, y;
Point(int sx, int sy)
:x(sx),y(sy)
{
}
};
std::vector<Point> clickedPositions;
//the callback function
void CallBackFunc(int event, int x, int y, int flags, void* userdata)
{
if ( event == EVENT_LBUTTONDOWN )
{
clickedPositions.push_back(Point(x,y));
}
}
and while writing it into the file:
for(int j=0; j<clickedPositions.size(); j++)
{
myfile << clickedPositions[j].x < <","<< clickedPositions[j].y <<endl;
}

My code doesn't work with std::map and sf::Vector2i

I am trying to make a pathfinding system for the SFML, but I am stuck because of a compilation error. This error occurs when I try to add an element to my std::map . Here is the header code:
#include <SFML/Graphics.hpp>
#include <list>
#include <map>
class Node {
public:
float cout_g, cout_h, cout_f;
sf::Vector2i parent;
};
class Pathfinding
{
public:
Pathfinding(sf::Vector2i);
std::list<sf::Vector2i> searchPath(sf::Vector2i endpoint,sf::Vector2i startpoint);
private:
std::map<sf::Vector2i,Node> closedList;
std::map<sf::Vector2i,Node> openList;
};
And here is the source code:
#include "Pathfinding.h"
Pathfinding::Pathfinding(sf::Vector2i coords)
{
}
std::list<sf::Vector2i> Pathfinding::searchPath(sf::Vector2i endpoint, sf::Vector2i startpoint)
{
Node startNode;
startNode.parent.x = 0;
startNode.parent.y = 0;
openList[startpoint] = startNode;
std::list<sf::Vector2i> list;
return list;
}
And here is the game loop:
#include "Pathfinding.h"
int main()
{
sf::RenderWindow window(sf::VideoMode(800,600),"A* Test");
Pathfinding pathfinder(sf::Vector2i(800,600));
while(window.isOpen())
{
sf::Event event;
while(window.pollEvent(event))
{
if(event.type == sf::Event::Closed) window.close();
}
std::list<sf::Vector2i> path = pathfinder.searchPath(sf::Vector2i(3,3),sf::Vector2i(45,55));
window.clear(sf::Color::White);
window.display();
}
return 0;
}
This code isn't functionnal at all, I reduced it to the minimum for the debugging.
I really don't understand the error code it is giving: http://pastebin.com/mBVALHML (I am posting it on Pastebin because it is really long). The only thing I understand in this error is the problem comes from this line:
openList[startpoint] = startNode;
I also tried to compile with SFML 2.1 and 2.2, but it didn't worked. So do you know why I am getting this error, and maybe how to fix it ?
Thanks a lot :)
sf::Vector2<T> has no operator< but in order to use it as a key in a std::map it needs such an operator.
You somehow have two options, without the need to modify Vector2.hpp: One complex and one easy but not so wanted way.
Easy
Simply make the maps from a fixed size, e.g.
/*some function-head-thing*/(sf::Vector2u size)
{
for(unsigned int y = 0U; y < size.y; ++y)
for(unsigned int x = 0U; x < size.x; ++x)
map[x + y * size.x] = /*some init value*/
}
In order to access the elements in the map you always need to know the size but it stays simple: map[x + y * size.x].
Complex
As the operator== is defined for sf::Vector2<T> you simply need to add a std::hash specified for sf::Vector2<T> and then you can replace the map with an std::unordered_map.
Maybe something like this:
namespace std
{
template <class T>
struct hash<sf::Vector2<T>>
{
std::size_t operator()(const sf::Vector2<T>& v) const
{
using std::hash;
// Compute individual hash values for first
// and second. Combine them using the Boost-func
std::size_t tmp0 = hash<T>()(v.x);
std::size_t tmp1 = hash<T>()(v.y);
tmp0 ^= tmp1 + 0x9e3779b9 + (tmp0 << 6) + (tmp0 >> 2);
}
};
}
But be careful if you want to use sf::Vector2f! Better add a static_assert to restrict the usage of T, it should not be floating point as the operator== might not give expected results, no matter if fuzzy-compare or not.
Otherwise
Add some operator< in the Vector2.hpp and Vector2.inl, however you need it.