I'm facing a really peculiar problem with my code,
I am unable to push elements into a list.
I'm trying to implement a scan fill algorithm.
I want the list of points that I have plotted on the screen so that I can check if a scan line intersects with them.
In my Screen::plot_pixel function I push the Point into the plotted_points list.
But when I iterate through the list, it's empty.(I'm iterating in shape.cpp using a friend function)
I tried using a set too but to no avail. I have attached the console output I get too.
plot_pixel gets called multiple times, I verified this by adding a print statement there but the points refuse to get pushed in.
Here's all my code, point.h
#ifndef POINT_H
#define POINT_H
class Point
{
float x_coordinate,y_coordinate;
public:
Point(){}
Point(float x, float y):x_coordinate(x),y_coordinate(y){}
float get_x() const{return x_coordinate;}
float get_y() const {return y_coordinate;}
bool operator==(const Point rhs)const
{
if( ((int)x_coordinate == (int)rhs.get_x()) && ((int)y_coordinate == (int)rhs.get_y()) )
return true;
else return false;
}
bool operator<(const Point rhs)const
{
if((int)x_coordinate < (int)rhs.get_x())
return true;
else return false;
}
};
#endif
screen.h
#ifndef SCREEN_H
#define SCREEN_H
#include<graphics.h>
#include "point.h"
#include<list>
class Shape;
class Screen
{
private:
int max_x,max_y,grid_size;
int delta_x,delta_y;
int origin_x,origin_y;
public:
std::list<Point> plotted_points;
// Default Constructor to Initialize the screen with the grid
Screen(int, int, int);
//Method prototypes
void plot_pixel(int,int,int);
void dda_line(Point p1, Point p2);
int get_max_x(){return max_x;}
int get_max_y(){ return max_y;}
friend void draw_shape(Screen,Shape);
friend void fill_shape(Screen,Shape);
};
#endif
screen.cpp
#include "screen.h"
void Screen::plot_pixel(int xcoord,int ycoord,int col=WHITE)
{
int l,t,r,b;
l = origin_x + xcoord * delta_x;
r = l + delta_x;
b = origin_y - ycoord * delta_y;
t = b - delta_y;
setcolor(col);
bar(l,t,r,b);
setcolor(WHITE);
Point *tmp = new Point(xcoord,ycoord);
//the culprit code
plotted_points.push_back(*tmp);
delete tmp;
}
void Screen::dda_line(Point p1, Point p2)
{
.....
plot_pixel(x,y,0);
}
shape.h
#ifndef SHAPE_H
#define SHAPE_H
#include<list>
#include<iostream>
#include "point.h;
class Screen;
class Shape
{
list<Point> figure;
public:
Shape(list<Point> s);
friend void draw_shape(Screen,Shape);
friend void fill_shape(Screen,Shape);
};
#endif
shape.cpp
#include "shape.h"
#include "screen.h"
Shape::Shape(list<Point> s):figure(s){}
void fill_shape(Screen scr, Shape sh)
{
list<Point>::iterator pit,vit;
//HERE's Where I try iterating over the list and get nothing
//to check if the plotted points and vertices are listed correctly
cout<<"Plotted Points :\n";
for( pit = scr.plotted_points.begin();pit != scr.plotted_points.end();pit++)
{
cout<<pit->get_x()<<" "<<pit->get_y()<<endl;
}
cout<<"Vertices :\n";
for( vit = sh.figure.begin();vit != sh.figure.end();vit++)
{
cout<<vit->get_x()<<" "<<vit->get_y()<<endl;
}
}
and finally my driver
#include "screen.h"
#include "shape.h"
using namespace std;
int main()
{
Screen s(641,641,32);
Point p1(-10,-10),p2(-10,10),p3(10,10),p4(10,-10);
list<Point> rectangle_points;
//to construct the rectangle
rectangle_points.push_back(p1);
rectangle_points.push_back(p2);
rectangle_points.push_back(p3);
rectangle_points.push_back(p4);
Shape rectangle(rectangle_points);
draw_shape(s,rectangle);
fill_shape(s,rectangle);
getch();
return 0;
}
Here's the output
Plotted Points :
Vertices :
-10 -10
-10 10
10 10
10 -10
You are passing the Screen object s into your functions, but they take the Screen object by value. They therefore take a copy of the object which they then modify. Your original Screen "s" is unchanged after the call to draw_shape().
You should probably modify them so they take a reference to a Screen object, such as:
void draw_shape(Screen& scr, Shape shp)
Related
I have taken sample code from ch9 Open Closed Principle in Agile Software Development, as below, which is supposed to sort shapes by precedence in the order given by the table typeOrderTable in the code below. Well, I did have to add a main and test code but pretty much copied the book code. But the output shows it is not sorting as per the table. And if I try to debug the code, the code path does not enter the Shape::Precedes function.
How can I fix this?
Code:
#include <typeinfo>
#include <string>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Shape {
public:
virtual void Draw() const = 0;
bool Precedes(const Shape& s) const;
bool operator<(const Shape& s) const {
return Precedes(s);
}
private:
static const char* typeOrderTable[];
};
bool Shape::Precedes(const Shape& s) const {
const char* thisType = typeid(*this).name();
const char* argType = typeid(s).name();
bool done{ false };
int thisOrd{ -1 };
int argOrd{ -1 };
for (int i = 0; !done; ++i) {
const char* tableEntry = typeOrderTable[i];
if (tableEntry != 0) {
if (strcmp(tableEntry, thisType) == 0)
thisOrd = i;
if (strcmp(tableEntry, argType) == 0)
argOrd = i;
if (argOrd >= 0 && thisOrd >= 0)
done = true;
}
else done = true;
}
return thisOrd < argOrd;
}
class Square : public Shape {
public:
virtual void Draw() const {
cout << "square\n";
}
};
class Circle : public Shape {
public:
virtual void Draw() const {
cout << "circle\n";
}
};
class Rectangle : public Shape {
public:
virtual void Draw() const {
std::cout << "rectangle\n";
}
};
const char* Shape::typeOrderTable[] = {
typeid(Circle).name(),
typeid(Rectangle).name(),
typeid(Square).name(),
0
};
void DrawAllShapes(vector<Shape*> shapes) {
vector<Shape*> orderedList = shapes;
sort(orderedList.begin(), orderedList.end());
for (auto shape : orderedList) {
shape->Draw();
}
}
int main() {
Shape* circle = new Circle();
Shape* square = new Square();
Shape* rectangle = new Rectangle();
Shape* rectangle2 = new Rectangle();
vector<Shape*> shapes{ rectangle, square, circle, rectangle2 };
DrawAllShapes(shapes);
/* should print:
circle
rectangle
rectangle
square
but instead prints:
rectangle
square
rectangle
circle
ie unsorted - actually it is random in the output
*/
}
You need to change your call to std::sort(...) to use a comparator. The way you have it, it is pointers to shapes being sorted not shapes so the operator< defined for shapes will not be called, instead the numeric values of the pointers will be compared.
One way to fix this is to sort like this
sort(orderedList.begin(), orderedList.end(),
[](Shape* s1, Shape* s2) { return s1->Precedes(*s2); }
);
providing a lambda taking Shape*'s to do the actual comparing.
Multiple markers at this line
- candidates are:
- no matching function for call to
'Coordinate::Coordinate()'
I am getting this error in the constructor of my class and I don't understand why. Here is the code involved:
RadialScan header
#ifndef RADIALSCAN_H_
#define RADIALSCAN_H_
#include "EasyBMP/EasyBMP.h"
#include <vector>
#include "Coordinate.h"
using namespace std;
class RadialScan {
vector<int> distanceTimeSeries;
vector<Coordinate> timeSeries;
BMP image;
Coordinate center;
Coordinate getNextPoint(Coordinate c);
bool isBlack(Coordinate c);
void computeTimeSeries();
public:
RadialScan(char* filename);
vector<int> getDistances();
vector<Coordinate> getCoordinates();
};
#endif
RadialScan class (all the methods are implemented, but the error is in the constructor and that's the code I'm providing):
#include "RadialScan.h"
RadialScan::RadialScan(char* filename){
image.ReadFromFile(filename);
int centerX = image.TellWidth()/2;
int centerY = image.TellHeight()/2;
center = Coordinate(centerX, centerY);
}
...
The error seems to be in the constructor. If I remove the constructor everything seems to compile correctly. If I delete the code inside the constructor I'm still getting the error. I don't understand why it keeps asking me for the Coordinate::Coordinate() constructor even when I don't have a coordinate object defined in the RadialScan(char* filename) constructor.
Additionally, these are the files for the Coordinate class:
header:
#ifndef COORDINATE_H_
#define COORDINATE_H_
class Coordinate {
int x;
int y;
public:
Coordinate(int x, int y);
void setX(int oneX);
void setY(int oneY);
int getX();
int getY();
double getMagnitude();
Coordinate operator-(const Coordinate&);
bool operator==(const Coordinate&);
Coordinate operator=(const Coordinate&);
};
#endif
cpp class:
#include "Coordinate.h"
#include <math.h>
Coordinate::Coordinate(int oneX, int oneY) {
x = oneX;
y = oneY;
}
//Setters
void Coordinate::setX(int oneX) {
x = oneX;
}
void Coordinate::setY(int oneY) {
y = oneY;
}
//Getters
int Coordinate::getX() {
return x;
}
int Coordinate::getY() {
return y;
}
double Coordinate::getMagnitude() {
return sqrt(x * x + y * y);
}
Coordinate Coordinate::operator-(const Coordinate& p) {
return Coordinate(x - p.x, y - p.y);
}
bool Coordinate::operator==(const Coordinate& p) {
return x == p.x && y == p.y;
}
Coordinate Coordinate::operator=(const Coordinate& p) {
return Coordinate(p.x, p.y);
}
Your constructor must look like
RadialScan::RadialScan(char* filename) : center (0, 0) {
image.ReadFromFile(filename);
int centerX = image.TellWidth()/2;
int centerY = image.TellHeight()/2;
center = Coordinate(centerX, centerY);
}
this because you did not implement default constructor and you can not create center object by default, so the only way is to call explicity Coordinate constructor with some default values.
No warnings, no errors. Compile fine, but in the bottom of update function, the following lines make crash the program:
(*m_mousePosition).setX(event.motion.x);
(*m_mousePosition).setY(event.motion.y);
This is the complete code:
#include <SDL2/SDL.h>
#include <vector>
#include "Vector2D.h"
using namespace std;
#ifndef INPUTHANDLER_H
#define INPUTHANDLER_H
enum mouse_buttons{
LEFT = 0,
MIDDLE = 1,
RIGHT = 2
};
class InputHandler{
public:
static InputHandler* Instance(){
if(s_pInstance==0){
s_pInstance= new InputHandler();
}
return s_pInstance;
}
void update(){
if(event.type == SDL_MOUSEBUTTONDOWN){
if(event.button.button == SDL_BUTTON_LEFT){
m_mouseButtonStates[LEFT]=true;
}
if(event.button.button == SDL_BUTTON_MIDDLE){
m_mouseButtonStates[MIDDLE]=true;
}
if(event.button.button == SDL_BUTTON_RIGHT){
m_mouseButtonStates[RIGHT]=true;
}
}
if(event.type == SDL_MOUSEBUTTONUP){
if(event.button.button == SDL_BUTTON_LEFT){
m_mouseButtonStates[LEFT]=false;
}
if(event.button.button == SDL_BUTTON_MIDDLE){
m_mouseButtonStates[MIDDLE]=false;
}
if(event.button.button == SDL_BUTTON_RIGHT){
m_mouseButtonStates[RIGHT]=false;
}
}
if(event.type == SDL_MOUSEMOTION){
(*m_mousePosition).setX(event.motion.x);
(*m_mousePosition).setY(event.motion.y);
}
}
SDL_Event* getEvent(){
return &event;
}
void clear();
bool getMouseButtonStates(int buttonNumber){
return m_mouseButtonStates[buttonNumber];
}
Vector2D* getMousePosition(){
return m_mousePosition;
}
private:
SDL_Event event;
vector<bool> m_mouseButtonStates;
Vector2D* m_mousePosition;
InputHandler(){
for(int i=0; i<3; i++){
m_mouseButtonStates.push_back(false);
}
}
~InputHandler(){}
static InputHandler* s_pInstance;
};
typedef InputHandler TheInputHandler;
#endif /* INPUTHANDLER_H */
Maybe its a problem whit pointers, but I don't know, I can't solve
==============================NEW EDIT======================================
Now I don't use pointers, but I must initialize the Vector2D whit two parametres. I put it in the InputHandler constructor:
InputHandler::InputHandler():m_position(0,0){
for(int i=0; i<3; i++){
m_mouseButtonStates.push_back(false);
}
}
And give me the following error:
InputHandler.cpp:12:30: error: member initializer 'm_position' does not name a non-static data member or base class
InputHandler::InputHandler():m_position(0,0){
^~~~~~~~~~~~~~~
The definition of Vector2D class:
#include<math.h>
using namespace std;
#ifndef VECTOR2D_H
#define VECTOR2D_H
class Vector2D {
public:
Vector2D(float x, float y):m_x(x), m_y(y){}
float getX(){return m_x;}
float getY(){return m_y;}
void setX(float x){m_x=x;}
void setY(float y){m_y=y;}
float length(){return sqrt(m_x*m_x + m_y*m_y);}
private:
float m_x;
float m_y;
};
#endif /* VECTOR2D_H */
yes, the problem is "pointers" as you put it.
m_mousePosition is declared but you never assign anything to it so it is NULL/garbage.
you probably dont need to use pointers here.
In my test program I have two points, and I want to find distance between them with my distancefrom. But I get answer 0.
Why does it give 0?
How can I fix it?
Point<2> v1;
// this should have {0.0, 0.0}
Point<2> v3 { list{2.0,3.0} };
float f = v1.distanceFrom(v3);
cout << f << endl;
I have a point.h file.
#ifndef POINT_H
#define POINT_H
#include <iostream>
#include <list>
#include <sstream>
#include <string>
using std::stringstream;
#include <cmath>
using namespace std;
template<unsigned short n>
class Point {
public:
list <float> coords = {0.0};
Point <n>() = default;
Point <n>(list<float> coords){
if (coords.size()!=n) {
throw string ("Vale koordinaatide arv");
}
this-> coords=coords;
}
string toString(){
string sone;
ostringstream ss;
sone.append("(");
auto it3= coords.begin();
while ((it3) != coords.end()){
ss << (*it3);
sone.append(ss.str());
ss.str("");
sone.append(",");
++it3;
}
sone.pop_back();
sone.append(")");
return sone;
}
float distanceFrom (Point <n> v){
float s=0;
list<float> coords;
auto it1= coords.begin();
auto it2= v.coords.begin();
while ((it1) != coords.end()){
s+=(*it1 -*it2)*(*it1-*it2);
it1++;
it2++;
}
return sqrt(s);
}
friend std::ostream& operator <<(std::ostream& out, const Point<n>& v)
{
out << "("<<"Test"<<")";
return out;
}
};
#endif
First, your coords list does not know you want its size to be n. Its size after default initialization like the following is 1:
list <float> coords = {0.0};
The proper way to construct it would be:
list <float> coords = list <float> (n, 0.0);
Second, you allocate a new coords inside the function distanceFrom:
list<float> coords;
This shadows the real coords of the point which you in fact want to use. Remove that line, and you will be fine.
#include<iostream>
#include<cstdlib>
#include<cmath>
using namespace std;
class pointDistance{
int x, y;
public:
pointDistance (int a, int b){
x =a;
y =b;
}
void pointShow(){
cout<<"The Point is ("<<x<<","<<y<<")"<<endl;
}
friend void Distance(pointDistance , pointDistance);
};
//formula of distance between two points:
//d =((x1^2 - x2^2) + (y1^2 - y2^2))^1/2
void Distance(pointDistance o1, pointDistance o2)
{
// pointDistance o3;
int d1,d2;
d1 = (o1.x -o2.x)*(o1.x -o2.x);
d2 = (o1.y - o2.y)*(o1.y - o2.y);
cout<<"So the distance between two point is "<< sqrt(d1+d2)<<endl;
}
int main(){
pointDistance one(4,5);
one.pointShow();
pointDistance two(0,6);
two.pointShow();
Distance(one, two);
return 0;
}
I'm using a class 'triangle' which is expressed as a vector of type 'vertex', 'vertex' being a structure consisting of an x and y value. I have a member function in 'triangle' that is supposed to return the area using heron's formula. Everything works fine until I try to output the area in the main function. Here is my code
vertex.h file
#ifndef VERTEX_H
#define VERTEX_H
#include <iostream>
struct vertex
{
double x, y;
vertex(double ix = 0.0, double iy = 0.0)
{
x = ix;
y = iy;
}
};
#endif // VERTEX_H
triangle.h file
#ifndef TRIANGLE_H
#define TRIANGLE_H
#include <iostream>
#include <vector>
#include "vertex.h"
class triangle
{
public:
triangle(vertex iv0 = vertex(), vertex iv1 = vertex(), vertex iv2 = vertex());
// pre:
// post: empty triangle
triangle(const triangle & source);
// pre:
// post: triangle created and initialized to given triangle source
vertex operator[](size_t i) const;
// pre: 0 <= i < 3
// post: return vertex i in this triangle
double area() const;
//pre:
//post: returns area of triangle
private:
std::vector<vertex> v;
};
std::ostream & operator << (std::ostream & os, const triangle & p);
std::istream & operator >> (std::istream & is, triangle & p);
#endif // TRIANGLE.H
triangle.cpp file
#include <cassert>
#include <vector>
#include <math.h>
#include "triangle.h"
triangle::triangle(vertex iv0, vertex iv1, vertex iv2) : v(3)
{
v[0] = iv0;
v[1] = iv1;
v[2] = iv2;
}
triangle::triangle(const triangle &p)
{
v = p.v;
}
vertex triangle::operator[] (std::size_t i) const
{
assert(i < v.size());
return v[i];
}
double triangle::area() const
{
double a, b, c;
double s;
a = sqrt(pow((v[0].x-v[1].x), 2)+pow((v[0].y-v[1].y), 2));
b = sqrt(pow((v[1].x-v[2].x), 2)+pow((v[1].y-v[2].y), 2));
c = sqrt(pow((v[2].x-v[0].x), 2)+pow((v[2].y-v[0].y), 2));
s = (a+b+c)/2;
return sqrt(s*(s-a)*(s-b)*(s-c));
}
//PROBLEM IS HERE^
//(used distance formula to find side lengths a, b, and c)
main function
#include <iostream>
#include "triangle.h"
using namespace std;
int main()
{
triangle t;
t[0] = vertex(2,3);
t[1] = vertex(5,4);
t[2] = vertex(3,7);
cout << t << endl;
cout << t.area() << endl;
cout << t.operator [](2) << endl;
return 0;
}
Since you are initialising your triangle using operator[], you need to make a non-const version of that function that returns a reference. Generally you return a const reference from the const version too, rather than by value:
const vertex& triangle::operator[] (std::size_t i) const
{
assert(i < v.size());
return v[i];
}
vertex& triangle::operator[] (std::size_t i)
{
assert(i < v.size());
return v[i];
}
Your compiler really shouldn't have let you get away with the code you posted. Modifying an rvalue should be an error, or at the very least a warning. Make sure you compile with warnings turned on, and read them!
The issue has to do with how you are initializing the triangle object. Try initializing it this way:
int main()
{
triangle t (vertex(2,3), vertex(5,4), vertex(3,7));
cout << t.area() << endl;
return 0;
}
Another less ideal solution would be to make "v" a public member and then assign the values this way:
triangle t;
t.v[0] = vertex(2,3);
t.v[1] = vertex(5,4);
t.v[2] = vertex(3,7);