Why I can't access data from array of objects? - c++

I have a problem with my code, every time I use my arrays (vTab or eTab) of an object inside of cube:3D_obj it returns me pointer ID or nan. Well just for context here's the whole code, but those arrays are only the problem because the code is running fine.
For debugging purposes, I wrote cout's in some places. Also, I tried to init vTab[] as new vertice[8], but the same results.
I came up with one problem, that I might have to init verticle object outside of functions but i don't know actually how to handle it.
If you need to know this project have to represent simple 3D figures as data with classes/objects
Two vertices make an edge, edges make figures, etc.
IDE: I use Visual Studio on Windows
#define pi 3.14159265359
#define eps 0.0001
#include <iostream>
#include <math.h>
using namespace std;
double aprox(double x, double y) {
return round(10000 * x) / 10000;
}
class vertice {
double x;
double y;
double z;
friend ostream& operator<< (ostream& c, vertice& orig);
public:
vertice() {//init funciton
x = y = z = 0;
}
vertice(double ix, double iy, double iz) {//init function
x = ix;
y = iy;
z = iz;
}
vertice& operator- (vertice& orig) {
vertice temp = *this;
temp.x -= orig.x;
temp.y -= orig.y;
temp.z -= orig.z;
return temp;
}
vertice& operator+ (vertice& orig) {
vertice temp = *this;
temp.x += orig.x;
temp.y += orig.y;
temp.z += orig.z;
return temp;
}
void position(double ix, double iy, double iz) { //change the position of the vertice
x = ix;
y = iy;
z = iz;
}
void position(double ix) {
x = ix;
}
void rotate(double ax, double ay, double az, vertice anchorPoint = vertice(0, 0, 0)) { //rotate in 3D (angle) axis using anchor point
vertice tempVertice = *this - anchorPoint;
double cosX = cos(ax * pi / 180), cosY = cos(ay * pi / 180), cosZ = cos(az * pi / 180), sinX = sin(ax * pi / 180), sinY = sin(ay * pi / 180), sinZ = sin(az * pi / 180);
//rotate X
y = aprox(tempVertice.y * cosX - tempVertice.z * sinX, eps);
z = aprox(tempVertice.z * cosX + tempVertice.y * sinX, eps);
tempVertice = *this;
//rotate Y
x = aprox(tempVertice.x * cosY - tempVertice.z * sinY, eps);
z = aprox(tempVertice.z * cosY + tempVertice.x * sinY, eps);
tempVertice = *this;
//rotate Z
x = aprox(tempVertice.x * cosZ - tempVertice.y * sinZ, eps);
y = aprox(tempVertice.y * cosZ + tempVertice.x * sinZ, eps);
//tempVertice = *this;
*this = *this + anchorPoint;
}
//~vertice() {};
};
ostream& operator<< (ostream& c, vertice& orig) { //using << operator to stream data from vertice
cout << "x= " << orig.x << " | y= " << orig.y << " | z= " << orig.z;
return c;
}
class edge {
friend ostream& operator<< (ostream& c, edge& orig);
public:
vertice* v1;
vertice* v2;
edge() {
v1 = new vertice();
v2 = new vertice();
}
edge(vertice iv1, vertice iv2) {
v1 = &iv1;
v2 = &iv2;
}
};
ostream& operator<< (ostream& c, edge& orig) { //printing edges as two vertex
cout << "Edge: \n* " << *orig.v1 << "\n* " << *orig.v2 << endl;
return c;
}
class obj_3D {
vertice position;
vertice anchorPoint;
//material type; //not using
public:
void Draw() {}
//~obj_3D() {};
};
class cube : public obj_3D {
double a;
edge eTab[12];
vertice vTab[8];
public:
cube(double ia) { //creating vertices, edges according to object properaties.
a = ia;
double Ph = aprox(asin(sqrt(2) / 2), eps), Alph = aprox(asin(3 * sqrt(2) / 3), eps);
double TPh = 0, TAlph = 0;
double R = a * sqrt(2) / 2;
for (int i = 0; i < 8; i++) { //initializing vertices
vTab[i] = vertice();
vTab[i].position(R);
vTab[i].rotate(Ph + TPh, Alph+ TAlph, 0);
if (i == 3) {
TPh = 0;
TAlph = 180;
}
else TPh += 90;
cout << vTab[i] << endl; //for debuging purp.
}
for (int i = 0; i < 10; i++) { //initializing edges
if (i < 4) {
eTab[i] = edge(vTab[i], vTab[(i + 1) % 4]);
eTab[i + 4] = edge(vTab[i], vTab[i + 4]);
cout << eTab[i] << eTab[i + 4] << endl;
}
else {
eTab[i + 4] = edge(vTab[i], vTab[((i + 1) % 4) + 4]);
cout << eTab[i + 4] << endl;
}
}
}
void print() {
cout << "Cube: \n";
for (int i = 0; i < 12; i++) {
edge temp = eTab[i];
cout << i+1 << ". " << temp << endl;
}
}
};
int main() {
/*vertice a = vertice();
vertice b = vertice(4.2, 1.3, 2.2);
cout << b;
b = b + a;
b = b - a;
b.rotate(90, 90, 90);
cout << endl << a;
edge e1 = edge(a, b);
cout << endl << e1;*/
//vertice b = vertice();
//cout << b;
cube c1 = cube(4);
//c1.print();
}
I really will appreciate your help because I really am stuck here and don't know what to do...

Related

How to draw a 45x45 grid with SDL

I am trying to make a grid of 45x45 in SDL but I am not so sure how to do it. Should I use SDL_RenderDrawLine? If so how should I use it inside my void ParticleManager::renderGrid(SDL_Renderer* renderer) function?
#include <iostream>
#include <vector>
#include <string>
#include <cassert>
#include <SDL.h>
#include "Constants.h"
#include "ParticleManager.h"
using namespace std;
Particle::Particle(double _x, double _y) :
x(_x), y(_y),
vx(0.f), vy(0.f),
fx(0.f), fy(0.f),
rho(0.f), p(0.f)
{
}
ParticleManager::ParticleManager()
{
ax = 0;
ay = GRAVITY;
renderMode = "particles";
}
void ParticleManager::init(unsigned long n)
{
cout << "Init with " << n << " particles" << endl;
particles.clear();
particles.reserve(n);
while (particles.size() < n) {
double x = rand() / (double)(RAND_MAX)*SCREEN_WIDTH;
double y = rand() / (double)(RAND_MAX)*SCREEN_HEIGHT;
double centerDist = sqrt(
pow(x - SCREEN_WIDTH / 2.0, 2) +
pow(y - SCREEN_HEIGHT / 2.0, 2));
if (centerDist < fmin(SCREEN_WIDTH, SCREEN_HEIGHT) * 0.25)
particles.push_back(Particle(x, y));
}
}
void ParticleManager::addBlock(double center_x, double center_y)
{
for (int i = 0; i <= 4; i++) {
for (int j = 0; j <= 4; j++) {
double x = center_x + (j - 2) * SCREEN_WIDTH * 0.04f + (rand() / (double)(RAND_MAX)) * H;
double y = center_y + (i - 2) * SCREEN_HEIGHT * 0.04f + (rand() / (double)(RAND_MAX)) * H;
if (x >= 0 && x < SCREEN_WIDTH && y >= 0 && y < SCREEN_HEIGHT)
particles.push_back(Particle(x, y));
}
}
cout << particles.size() << " particles" << endl;
}
void ParticleManager::addOne(double x, double y)
{
particles.push_back(Particle(x, y));
cout << particles.size() << " particles" << endl;
}
void ParticleManager::setGravity(int direction)
{
switch (direction) {
case DOWN:
ax = 0;
ay = +GRAVITY;
break;
case UP:
ax = 0;
ay = -GRAVITY;
break;
case RIGHT:
ax = +GRAVITY;
ay = 0;
break;
default:
ax = -GRAVITY;
ay = 0;
}
}
void ParticleManager::explode() {
for (auto& p : particles) {
p.vx = rand() / (double)RAND_MAX * 10000 - 5000;
p.vy = rand() / (double)RAND_MAX * 10000 - 5000;
}
}
void ParticleManager::integrate(double dt)
{
for (auto& p : particles)
{
// forward Euler integration
if (p.rho != 0 && p.fx == p.fx && p.fy == p.fy) {
p.vx += dt * p.fx / p.rho;
p.vy += dt * p.fy / p.rho;
}
p.x += dt * p.vx;
p.y += dt * p.vy;
// enforce boundary conditions
if (p.x - PARTICLE_RADIUS < 0.0f)
{
p.vx *= BOUND_DAMPING;
p.x = PARTICLE_RADIUS;
}
if (p.x + PARTICLE_RADIUS > SCREEN_WIDTH)
{
p.vx *= BOUND_DAMPING;
p.x = SCREEN_WIDTH - PARTICLE_RADIUS;
}
if (p.y - PARTICLE_RADIUS < 0.0f)
{
p.vy *= BOUND_DAMPING;
p.y = PARTICLE_RADIUS;
}
if (p.y + PARTICLE_RADIUS > SCREEN_HEIGHT)
{
p.vy *= BOUND_DAMPING;
p.y = SCREEN_HEIGHT - PARTICLE_RADIUS;
}
}
}
void ParticleManager::computeDensityPressure()
{
// for each particles
for (auto& pi : particles)
{
pi.rho = 0.f;
// Find all the particles that contribute to the
// pressure / density
for (auto& pj : particles)
{
double distance = sqrt(
pow(pj.x - pi.x, 2) +
pow(pj.y - pi.y, 2));
if (distance < H)
{
// this computation is symmetric
pi.rho += MASS * POLY6 * pow(pow(H, 2) - pow(distance, 2), 3.f);
}
}
pi.p = GAS_CONST * (pi.rho - REST_DENS);
}
}
void ParticleManager::computeForces()
{
// For each particle
for (auto& pi : particles) {
double pressure_x = 0.f;
double pressure_y = 0.f;
double viscosity_x = 0.f;
double viscosity_y = 0.f;
// Calculate the sum of the viscosity and pressure forces
// applied by the other particles
for (auto& pj : particles) {
if (&pi == &pj)
continue;
double r = sqrt(
pow(pj.x - pi.x, 2) +
pow(pj.y - pi.y, 2));
if (r < H) {
// compute pressure force contribution
double fpress = MASS * (pi.p + pj.p) / (2.0 * pj.rho) * SPIKY_GRAD * pow(H - r, 2.0);
pressure_x += (pi.x - pj.x) / r * fpress;
pressure_y += (pi.y - pj.y) / r * fpress;
// compute viscosity force contribution
viscosity_x += VISC * MASS * (pj.vx - pi.vx) / pj.rho * VISC_LAP * (H - r);
viscosity_y += VISC * MASS * (pj.vy - pi.vy) / pj.rho * VISC_LAP * (H - r);
}
}
pi.fx = pressure_x + viscosity_x + ax * pi.rho;
pi.fy = pressure_y + viscosity_y + ay * pi.rho;
}
}
void ParticleManager::update(unsigned long dt)
{
// TODO: calculate the grid here
computeDensityPressure();
computeForces();
integrate(dt / 10000.0f);
}
void ParticleManager::renderParticles(SDL_Renderer* renderer) {
SDL_SetRenderDrawColor(renderer, 230, 120, 0, 100);
SDL_Rect r;
// Draw particles
for (long unsigned int i = 0; i < particles.size(); i++) {
r.x = (int)(particles[i].x - PARTICLE_RADIUS);
r.y = (int)(particles[i].y - PARTICLE_RADIUS);
r.w = (int)(PARTICLE_RADIUS * 2);
r.h = (int)(PARTICLE_RADIUS * 2);
SDL_RenderFillRect(renderer, &r);
}
}
void ParticleManager::renderGrid(SDL_Renderer* renderer) {
// TODO: Draw the lines that form the grid
cout << "Affichage de la grile (TODO)" << endl;
}
void ParticleManager::renderCells(SDL_Renderer* renderer) {
// TODO: Draw the boxes in different colors to
// represent the number of particles in each cell
//
// Use the calculation:
// int alpha = nb_particles * 255/5;
// if (alpha> 255) alpha = 255;
// SDL_SetRenderDrawColor (renderer, 0, 0, 255, alpha);
//
// To assign the color to the cell
cout << "Affichage des cellules (TODO)" << endl;
}
void ParticleManager::render(SDL_Renderer* renderer)
{
if (renderMode.find("particle") != string::npos)
renderParticles(renderer);
if (renderMode.find("grid") != string::npos) {
renderCells(renderer);
renderGrid(renderer);
}
}
The end result should look like this:

C++: Variable 'DiscreteGBM::S0' is uninitialized. Always initialize a member variable (type.6)

I have an error message C++: Variable 'DiscreteGBM::S0' is uninitialized. Always initialize a member variable (type.6). This message is repeated a few times with names of different member variables.
Can someone kind teach me how to initialize please? The header file cannot be changed. Only allowed changing of cpp file. However for cpp file, main function cannot be changed.
This first code is for header file. This is not allowed to be changed
class DiscreteGBM
{
protected:
double r; // risk free interest rate
double S0; // stock price at time 0
double sigma; // volatility
double delta; // length of time steps
int numberSteps; // total number of time steps;
// start time is 0, end time is numberSteps*delta
public:
DiscreteGBM() {}
void SetRiskFreeRate(double r1); // set r to r1
void SetInitialStockPrice(double s); // set S0 to s
void SetVolatility(double s); // set sigma to s
void SetTimeStepSize(double d); // set delta to d
void SetNumberSteps(int n); // set numberSteps to n
vector<double> PricePath() const; // compute price path S_0,...,S_T (where T=delta*n)
// according to formula (1) in the instructions,
// and return the vector (S_0,...,S_T)
};
// class for simulation of European call and put options
class EuropeanOption : public DiscreteGBM
{
protected:
bool callPut; // callPut =0 if object is call option, callPut=1 if it's a put option
double strike; // strike price of option
public:
EuropeanOption() {}
void SetCallPut(bool c); // set callPut to c
void SetStrike(double s); // set strike to s
double Payoff(double S_T) const; // return payoff of option according to
// formulas (2) and (3) of the instructions;
// S_T is the stock price at maturity
double BlackScholesPrice() const; // return Black Scholes price of the option
// according to formulas (4) and (6) of the instructions
double MonteCarloPrice(int numberScenarios=10000) const;
// execute algorithm Monte Carlo pricing given
// in instructions
};
CPP file below
#include "Functions.h"
#include "PricingSimulation.h"
void DiscreteGBM::SetRiskFreeRate(double r1) {
r = r1;
}
void DiscreteGBM::SetInitialStockPrice(double s) {
S0 = s;
}
void DiscreteGBM::SetVolatility(double s) {
sigma = s;
}
void DiscreteGBM::SetTimeStepSize(double d) {
delta = d;
}
void DiscreteGBM::SetNumberSteps(int n) {
numberSteps = n;
}
vector<double> DiscreteGBM::PricePath() const {
vector<double> stock;
vector<double> rnorm;
rnorm = randn(numberSteps);
stock[0] = S0;
for (int i = 1; i <= numberSteps; i++) {
stock[i] = stock[i - 1] * exp((r - 0.5 * sigma * sigma) * delta + sigma * sqrt(delta) * rnorm[i]);
}
return stock;
}
void EuropeanOption::SetCallPut(bool c) {
callPut = c;
}
void EuropeanOption::SetStrike(double s) {
strike = s;
}
double EuropeanOption::Payoff(double S_T) const {
double value;
if (callPut == 0)
if ((S_T - strike) > 0)
value = S_T - strike;
else
value = 0;
else
if ((strike - S_T) > 0)
value = strike - S_T;
else
value = 0;
return value;
}
double EuropeanOption::BlackScholesPrice() const {
double value2, d1, d2;
d1 = (1 / (sigma * sqrt(numberSteps * delta)) * (log(S0 / strike) + (r + sigma * sigma / 2) * numberSteps * delta));
d2 = d1 - sigma * sqrt(numberSteps * delta);
if (callPut == 0)
value2 = normcdf(d1) * S0 - normcdf(d2) * strike * exp(-r * numberSteps * delta);
else
value2 = -normcdf(-d1) * S0 + normcdf(-d2) * strike * exp(-r * numberSteps * delta);
return value2;
}
double EuropeanOption::MonteCarloPrice(int numberScenarios = 10000) const {
int N = numberScenarios;
double sum;
double T = numberSteps * delta;
vector <double> A;
double O;
for (int i = 1; i <= N; i++) {
A = PricePath();
O = A[numberSteps];
sum += O;
}
double average = sum / N;
return exp(-r * T) * average;
}
int main()
{
SetSeed();
EuropeanOption Test;
for (double r = -0.1; r <= 0.1; r += 0.05)
for (double sigma = 0.1; sigma <= 1; sigma += 0.3)
for (int c = 0; c <= 1; c++)
{
Test.SetRiskFreeRate(r);
Test.SetInitialStockPrice(100);
Test.SetVolatility(sigma);
Test.SetNumberSteps(100);
Test.SetTimeStepSize(0.1);
Test.SetStrike(130);
Test.SetCallPut(c);
cout << "r = " << r << ", sigma = " << sigma;
cout << ", c = " << c << ": ";
cout << Test.BlackScholesPrice() << " , ";
cout << Test.MonteCarloPrice() << endl;
}
system("pause");
}

How to find coefficients of polynomial equation?

Given two points in the x, y plane:
x, f(x)
1, 3
2, 5
I can interpolate them using Lagrange and find f(1.5), which result in 4. Thinking a little I managed to find a way to discover the coefficients of the equation:
void l1Coefficients(const vector<double> &x, const vector<double> &y) {
double a0 = y[0]/(x[0]-x[1]);
double a1 = y[1]/(x[1]-x[0]);
double b0 = (-x[1]*y[0])/(x[0]-x[1]);
double b1 = (-x[0]*y[1])/(x[1]-x[0]);
double a = a0 + a1;
double b = b0 + b1;
cout << "P1(x) = " << a << "x +" << b << endl;
}
That gives me P1(x) = 2x +1.
Thinking a little more I was able to extend that to 2nd order equations. So, given the points:
1, 1
2, 4
3, 9
I found the equation P2(x) = 1x^2 +0x +0 with the following:
void l2Coefficients(const vector<double> &x, const vector<double> &y) {
double a0 = y[0] / ((x[0]-x[1])*(x[0]-x[2]));
double a1 = y[1] / ((x[1]-x[0])*(x[1]-x[2]));
double a2 = y[2] / ((x[2]-x[0])*(x[2]-x[1]));
double b0 = -(x[1]+x[2])*y[0] / ((x[0]-x[1])*(x[0]-x[2]));
double b1 = -(x[0]+x[2])*y[1] / ((x[1]-x[0])*(x[1]-x[2]));
double b2 = -(x[0]+x[1])*y[2] / ((x[2]-x[0])*(x[2]-x[1]));
double c0 = (x[1]*x[2])*y[0] / ((x[0]-x[1])*(x[0]-x[2]));
double c1 = (x[0]*x[2])*y[1] / ((x[1]-x[0])*(x[1]-x[2]));
double c2 = (x[0]*x[1])*y[2] / ((x[2]-x[0])*(x[2]-x[1]));
double a = a0 + a1 + a2;
double b = b0 + b1 + b2;
double c = c0 + c1 + c2;
cout << "P2(x) = " << a << "x^2 +" << b << "x +" << c << endl;
}
Working hard I actually was able to find the coefficients for equations of order up to 4th.
How to find the coefficients of order n equations? Where
Pn(x) = c_2x^2 + c_1x^1 + c_0x^0 + ...
It's a simple linear algebra problem.
We have a set of N samples of the form xk -> f(xk) and we know the general form of function f(x), which is:
f(x) = c0x0 + c1x1 + ... + cN-1xN-1
We want to find the coefficients c0 ... cN-1. To achieve that, we build a system of N equations of the form:
c0xk0 + c1xk1 + ... + cN-1xkN-1 = f(xk)
where k is the sample number. Since xk and f(xk) are constants rather than variables, we have a linear system of equations.
Expressed in terms of linear algebra, we have to solve:
Ac = b
where A is a Vandermonde matrix of powers of x and b is a vector of f(xk) values.
To solve such a system, you need a linear algebra library, such as Eigen. See here for example code.
The only thing that can go wrong with such an approach is the system of linear equations being under-determined, which will happen if your N samples can be fit with with a polynomial of degree less than N-1. In such a case you can still solve this system with Moore-Penrose pseudo inverse like this:
c = pinv(A)*b
Unfortunately, Eigen doesn't have a pinv() implementation, though it's pretty easy to code it by yourself in terms of Singular Value Decomposition (SVD).
I created a naive implementation of the matrix solution:
#include <iostream>
#include <vector>
#include <stdexcept>
class Matrix
{
private:
class RowIterator
{
public:
RowIterator(Matrix* mat, int rowNum) :_mat(mat), _rowNum(rowNum) {}
double& operator[] (int colNum) { return _mat->_data[_rowNum*_mat->_sizeX + colNum]; }
private:
Matrix* _mat;
int _rowNum;
};
int _sizeY, _sizeX;
std::vector<double> _data;
public:
Matrix(int sizeY, int sizeX) : _sizeY(sizeY), _sizeX(sizeX), _data(_sizeY*_sizeX){}
Matrix(std::vector<std::vector<double> > initList) : _sizeY(initList.size()), _sizeX(_sizeY>0 ? initList.begin()->size() : 0), _data()
{
_data.reserve(_sizeY*_sizeX);
for (const std::vector<double>& list : initList)
{
_data.insert(_data.end(), list.begin(), list.end());
}
}
RowIterator operator[] (int rowNum) { return RowIterator(this, rowNum); }
int getSize() { return _sizeX*_sizeY; }
int getSizeX() { return _sizeX; }
int getSizeY() { return _sizeY; }
Matrix reduce(int rowNum, int colNum)
{
Matrix mat(_sizeY-1, _sizeX-1);
int rowRem = 0;
for (int y = 0; y < _sizeY; y++)
{
if (rowNum == y)
{
rowRem = 1;
continue;
}
int colRem = 0;
for (int x = 0; x < _sizeX; x++)
{
if (colNum == x)
{
colRem = 1;
continue;
}
mat[y - rowRem][x - colRem] = (*this)[y][x];
}
}
return mat;
}
Matrix replaceCol(int colNum, std::vector<double> newCol)
{
Matrix mat = *this;
for (int y = 0; y < _sizeY; y++)
{
mat[y][colNum] = newCol[y];
}
return mat;
}
};
double solveMatrix(Matrix mat)
{
if (mat.getSizeX() != mat.getSizeY()) throw std::invalid_argument("Not square matrix");
if (mat.getSize() > 1)
{
double sum = 0.0;
int sign = 1;
for (int x = 0; x < mat.getSizeX(); x++)
{
sum += sign * mat[0][x] * solveMatrix(mat.reduce(0, x));
sign = -sign;
}
return sum;
}
return mat[0][0];
}
std::vector<double> solveEq(std::vector< std::pair<double, double> > points)
{
std::vector<std::vector<double> > xes(points.size());
for (int i = 0; i<points.size(); i++)
{
xes[i].push_back(1);
for (int j = 1; j<points.size(); j++)
{
xes[i].push_back(xes[i].back() * points[i].first);
}
}
Matrix mat(xes);
std::vector<double> ys(points.size());
for (int i = 0; i < points.size(); i++)
{
ys[i] = points[i].second;
}
double w = solveMatrix(mat);
std::vector<double> result(points.size(), 0.0);
if(w!=0)
for (int i = 0; i < ys.size(); i++)
{
result[i] = solveMatrix(mat.replaceCol(i, ys));
result[i] /= w;
}
return result;
}
void printCoe(std::vector<double> coe)
{
std::cout << "f(x)=";
bool notFirstSign = false;
for (int i = coe.size() - 1; i >= 0; i--)
{
if (coe[i] != 0.0)
{
if (coe[i] >= 0.0 && notFirstSign)
std::cout << "+";
notFirstSign = true;
if (coe[i] != 1.0)
if (coe[i] == -1.0)
std::cout << "-";
else
std::cout << coe[i];
if (i == 1)
std::cout << "x";
if (i>1)
std::cout << "x^" << i;
}
}
std::cout << std::endl;
}
int main()
{
std::vector< std::pair<double, double> > points1 = { {3,31}, {6,94}, {4,48}, {0,4} };
std::vector<double> coe = solveEq(points1);
printCoe(coe);
std::vector< std::pair<double, double> > points2 = { { 0,0 },{ 1,-1 },{ 2,-16 },{ 3,-81 },{ 4,-256 } };
printCoe(solveEq(points2));
printCoe(solveEq({ { 0,0 },{ 1,1 },{ 2,8 },{ 3,27 } }));
std::cin.ignore();
return 0;
}

How do I calculate angles to create vector offsets to define parallel paths?

I have reference paths that are defined by a series of points. Given a starting point and additional points in a given direction, I need to effectively split the path created by the points into two distinct paths (directional) in a manner that allows me to draw and work with the two paths independently. The following screenshot shows 8 path examples. The "starting point" is the one with the white circle on it. If you orient yourself from the starting point towards the next point, then the path suggested by the red circles always should be to the "right" of the path defined by the given points.
In the screen, paths 2, 3, 5, 6, and 7 are correct. In paths 1, 4, and 8, essentially when the path starts on the right and moves left, then the position of the parallel path points are correct, but they are swapped in some instance (green where red should be, etc).
I'm somehow misusing atan2() (I think) to get the proper angle and or calculate the positions. For the first and last points, I'm calculating the angle to the adjacent point and the drawing the red and green path points at 90 degree offsets from that angle. For the points in the middle of the path, I'm looking at the angle to the previous point and the angle to the next point and placing the points in a manner that bisects the angles.
How do I properly calculate these angles to get the red and green parallel path points on the proper side of the reference line?
The problem likely is in TestLine::calculateParallelPoints().
I used openFrameworks 0.90 for this. Here's the code:
ofApp.h
#pragma once
#include "ofMain.h"
#include "TestLine.h"
class ofApp : public ofBaseApp{
public:
void setup();
void update();
void draw();
int sectors_wide;
int sectors_tall;
vector<TestLine> testLines;
};
ofApp.cpp
#include "ofApp.h"
//--------------------------------------------------------------
void ofApp::setup(){
ofSetBackgroundColorHex(0x000000);
sectors_wide = 4;
sectors_tall = 2;
TestLine t1 = TestLine(0,0,sectors_wide,sectors_tall);
t1.raw_points.push_back(ofPoint(0.9,0.5));
t1.raw_points.push_back(ofPoint(0.8,0.6));
t1.raw_points.push_back(ofPoint(0.7,0.4));
t1.raw_points.push_back(ofPoint(0.6,0.6));
t1.raw_points.push_back(ofPoint(0.5,0.4));
t1.raw_points.push_back(ofPoint(0.4,0.4));
t1.raw_points.push_back(ofPoint(0.3,0.5));
testLines.push_back(t1);
TestLine t2 = TestLine(1,0,sectors_wide,sectors_tall);
t2.raw_points.push_back(ofPoint(0.3,0.5)); //
t2.raw_points.push_back(ofPoint(0.4,0.4));
t2.raw_points.push_back(ofPoint(0.5,0.4));
t2.raw_points.push_back(ofPoint(0.6,0.6));
t2.raw_points.push_back(ofPoint(0.7,0.4));
t2.raw_points.push_back(ofPoint(0.8,0.6));
t2.raw_points.push_back(ofPoint(0.9,0.5));
testLines.push_back(t2);
TestLine t3 = TestLine(2,0,sectors_wide,sectors_tall);
t3.raw_points.push_back(ofPoint(0.1,0.2));
t3.raw_points.push_back(ofPoint(0.7,0.4));
t3.raw_points.push_back(ofPoint(0.4,0.45));
t3.raw_points.push_back(ofPoint(0.6,0.5));
t3.raw_points.push_back(ofPoint(0.9,0.9));
testLines.push_back(t3);
TestLine t4 = TestLine(3,0,sectors_wide,sectors_tall);
t4.raw_points.push_back(ofPoint(0.5,0.5));
t4.raw_points.push_back(ofPoint(0.9,0.5));
t4.raw_points.push_back(ofPoint(0.5,0.1));
t4.raw_points.push_back(ofPoint(0.1,0.1));
t4.raw_points.push_back(ofPoint(0.1,0.8));
t4.raw_points.push_back(ofPoint(0.8,0.6));
testLines.push_back(t4);
TestLine t5 = TestLine(0,1,sectors_wide,sectors_tall);
t5.raw_points.push_back(ofPoint(0.4,0.4));
t5.raw_points.push_back(ofPoint(0.6,0.5));
t5.raw_points.push_back(ofPoint(0.8,0.4));
testLines.push_back(t5);
TestLine t6 = TestLine(1,1,sectors_wide,sectors_tall);
t6.raw_points.push_back(ofPoint(0.7,0.1));
t6.raw_points.push_back(ofPoint(0.2,0.3));
t6.raw_points.push_back(ofPoint(0.7,0.5));
testLines.push_back(t6);
TestLine t7 = TestLine(2,1,sectors_wide,sectors_tall);
t7.raw_points.push_back(ofPoint(0.2,0.1));
t7.raw_points.push_back(ofPoint(0.7,0.3));
t7.raw_points.push_back(ofPoint(0.2,0.5));
testLines.push_back(t7);
TestLine t8 = TestLine(3,1,sectors_wide,sectors_tall);
t8.raw_points.push_back(ofPoint(0.8,0.5));
t8.raw_points.push_back(ofPoint(0.6,0.4));
t8.raw_points.push_back(ofPoint(0.4,0.5));
testLines.push_back(t8);
// Convert raw points to real points in the grid space
for (int i = 0; i < testLines.size(); i++) {
testLines[i].processRawPoints();
testLines[i].calculateParallelPoints();
}
}
//--------------------------------------------------------------
void ofApp::update(){
}
//--------------------------------------------------------------
void ofApp::draw(){
ofSetBackgroundColorHex(0x000000);
ofSetColor(255, 255, 255);
for (int i = 0; i < testLines.size(); i++) {
testLines[i].displayTestLine();
}
}
TestLine.h
#include "ofMain.h"
class TestLine {
public:
TestLine(float _x, float _y, int _sec_wide, int _sec_tall);
void displayTestLine();
void calculateParallelPoints();
void processRawPoints();
float x_coord;
float y_coord;
float x_min;
float x_max;
float y_min;
float y_max;
vector<float> angles;
vector<ofPoint> raw_points;
vector<ofPoint> points;
vector<ofPoint> forward_points;
vector<ofPoint> reverse_points;
ofPolyline line;
ofPolyline forward_line;
ofPolyline reverse_line;
};
TestLine.cpp
#include "TestLine.h"
TestLine::TestLine(float _x, float _y, int _sec_wide, int _sec_tall){
x_coord = _x;
y_coord = _y;
int w = ofGetWindowWidth();
int h = ofGetWindowHeight();
float allowed_w = (float)w / _sec_wide;
float allowed_h = (float)h / _sec_tall;
x_min = x_coord * allowed_w;
x_max = x_min + allowed_w;
y_min = y_coord * allowed_h;
y_max = y_min + allowed_h;
}
void TestLine::calculateParallelPoints(){
for (int i = 0; i < points.size(); i++) {
if (i == 0) {
ofVec2f v2 = points[i];
ofVec2f v1 = points[i+1];
float angle = ofRadToDeg(atan2(v1.y - v2.y, v1.x - v2.x));
angles.push_back(angle);
cout << "Start: " << angle << endl;
}
if (i > 0 && i < points.size() - 1) {
ofVec2f v1 = points[i];
ofVec2f v2 = points[i-1];
float back_angle = ofRadToDeg(atan2(v1.y - v2.y, v1.x - v2.x));
v2 = points[i];
v1 = points[i+1];
float front_angle = ofRadToDeg(atan2(v1.y - v2.y, v1.x - v2.x));
float final_angle = (back_angle + front_angle) / 2;
cout << "BACK ANGLE: " << back_angle << ", FRONT ANGLE: " << front_angle << ", FINAL ANGLE: " << final_angle << endl;
float prev_x = points[i-1].x;
float prev_y = points[i-1].y;
float this_x = points[i].x;
float this_y = points[i].y;
float next_x = points[i+1].x;
float next_y = points[i+1].y;
angles.push_back(final_angle);
}
if (i == points.size() - 1) {
ofVec2f v1 = points[i];
ofVec2f v2 = points[i-1];
float angle = ofRadToDeg(atan2(v1.y - v2.y, v1.x - v2.x));
angles.push_back(angle);
cout << "End: " << angle << endl;
}
line.addVertex(points[i]);
}
// Now using the points and the angles to calculate the forward and reverse points
for (int i = 0; i < points.size(); i++) {
float forward_angle = angles[i] + 90;
float reverse_angle = angles[i] - 90;
// cout << forward_angle << ", " << reverse_angle << endl;
float forward_x = points[i].x + cos(ofDegToRad(forward_angle)) * 8;
float forward_y = points[i].y + sin(ofDegToRad(forward_angle)) * 8;
forward_points.push_back(ofPoint(forward_x, forward_y));
float reverse_x = points[i].x + cos(ofDegToRad(reverse_angle)) * 8;
float reverse_y = points[i].y + sin(ofDegToRad(reverse_angle)) * 8;
reverse_points.push_back(ofPoint(reverse_x, reverse_y));
}
}
void TestLine::processRawPoints(){
for (int i = 0; i < raw_points.size(); i++) {
float newx = ofMap(raw_points[i].x, 0, 1, x_min, x_max);
float newy = ofMap(raw_points[i].y, 0, 1, y_min, y_max);
points.push_back(ofPoint(newx,newy));
}
}
void TestLine::displayTestLine(){
ofSetColor(128,128,128);
line.draw();
ofSetColor(255, 255, 255);
ofDrawCircle(points[0].x, points[0].y, 3);
ofSetColor(255, 0, 0);
for (int i = 0; i < forward_points.size(); i++) {
ofDrawCircle(forward_points[i].x, forward_points[i].y, 2);
}
ofSetColor(0, 255, 0);
for (int i = 0; i < reverse_points.size(); i++) {
ofDrawCircle(reverse_points[i].x, reverse_points[i].y, 2);
}
}
I ended up handling this with several conditional statements, though I feel there's probably a better way to handle it with trig. Here's the amended TestLine.cpp file.
TestLine.cpp
#include "TestLine.h"
TestLine::TestLine(float _x, float _y, int _sec_wide, int _sec_tall){
x_coord = _x;
y_coord = _y;
int w = ofGetWindowWidth();
int h = ofGetWindowHeight();
float allowed_w = (float)w / _sec_wide;
float allowed_h = (float)h / _sec_tall;
x_min = x_coord * allowed_w;
x_max = x_min + allowed_w;
y_min = y_coord * allowed_h;
y_max = y_min + allowed_h;
}
void TestLine::calculateParallelPoints(){
for (int i = 0; i < points.size(); i++) {
if (i == 0) {
ofVec2f v2 = points[i];
ofVec2f v1 = points[i+1];
float angle = ofRadToDeg(atan2(v1.y - v2.y, v1.x - v2.x));
angles.push_back(angle);
cout << endl;
cout << "Start: " << angle << endl;
}
if (i > 0 && i < points.size() - 1) {
ofVec2f v1 = points[i];
ofVec2f v2 = points[i-1];
float back_angle = ofRadToDeg(atan2(v1.y - v2.y, v1.x - v2.x));
v2 = points[i];
v1 = points[i+1];
float front_angle = ofRadToDeg(atan2(v1.y - v2.y, v1.x - v2.x));
float final_angle = (back_angle + front_angle) / 2; // back_angle + front_angle
float prev_x = points[i-1].x;
float prev_y = points[i-1].y;
float this_x = points[i].x;
float this_y = points[i].y;
float next_x = points[i+1].x;
float next_y = points[i+1].y;
// Here is the addition that addressed the problem.
if ((prev_x > this_x && prev_y <= this_y && next_x < this_x && next_y < this_y) ||
(prev_x > this_x && prev_y > this_y && next_x < this_x && next_y >= this_y)) {
final_angle += 180;
}
cout << "BACK ANGLE: " << back_angle << ", FRONT ANGLE: " << front_angle << ", FINAL ANGLE: " << final_angle << endl;
angles.push_back(final_angle);
}
if (i == points.size() - 1) {
ofVec2f v1 = points[i];
ofVec2f v2 = points[i-1];
float angle = ofRadToDeg(atan2(v1.y - v2.y, v1.x - v2.x));
angles.push_back(angle);
cout << "End: " << angle << endl << endl;
}
line.addVertex(points[i]);
}
// Now using the points and the angles to calculate the forward and reverse points
for (int i = 0; i < points.size(); i++) {
float forward_angle = angles[i] + 90;
float reverse_angle = angles[i] - 90;
// cout << forward_angle << ", " << reverse_angle << endl;
float forward_x = points[i].x + cos(ofDegToRad(forward_angle)) * 8;
float forward_y = points[i].y + sin(ofDegToRad(forward_angle)) * 8;
forward_points.push_back(ofPoint(forward_x, forward_y));
float reverse_x = points[i].x + cos(ofDegToRad(reverse_angle)) * 8;
float reverse_y = points[i].y + sin(ofDegToRad(reverse_angle)) * 8;
reverse_points.push_back(ofPoint(reverse_x, reverse_y));
}
}
void TestLine::processRawPoints(){
for (int i = 0; i < raw_points.size(); i++) {
float newx = ofMap(raw_points[i].x, 0, 1, x_min, x_max);
float newy = ofMap(raw_points[i].y, 0, 1, y_min, y_max);
points.push_back(ofPoint(newx,newy));
}
}
void TestLine::displayTestLine(){
ofSetColor(128,128,128);
line.draw();
ofSetColor(255, 255, 255);
ofDrawCircle(points[0].x, points[0].y, 3);
ofSetColor(255, 0, 0);
for (int i = 0; i < forward_points.size(); i++) {
ofDrawCircle(forward_points[i].x, forward_points[i].y, 2);
}
ofSetColor(0, 255, 0);
for (int i = 0; i < reverse_points.size(); i++) {
ofDrawCircle(reverse_points[i].x, reverse_points[i].y, 2);
}
}

No matching function for call to class

/*
* File: ShapeTwoD.h
* Author: Administrator
*
* Created on October 30, 2012, 12:05 AM
*/
#ifndef SHAPETWOD_H
#define SHAPETWOD_H
#include <string>
#include <math.h>
using namespace std;
struct Point {
int x, y;
};
class ShapeTwoD {
public:
ShapeTwoD(string shapename, bool containsWS);
string getName();
bool getContainsWarpSpace();
string toString();
virtual double computeArea();
virtual bool isPointInShape(Point P, Point* V, int n);
virtual bool isPointOnShape(Point A, Point B, Point C, int slope, int intercept, int left, int top, int right, int bottom, int dx, int dy);
void setName(string shapename);
void setContainsWarpSpace(bool containsWS);
private:
string name;
bool containsWarpSpace;
};
class Cross : public ShapeTwoD {
public:
Cross(string shapename = "Cross", bool containsWS, int vertices = 12, Point ordinates[]):ShapeTwoD(shapename, containsWS){}
int getVert();
void setVert(int vertices);
Point getOrd();
void setOrd(Point ordinates[]);
virtual double computeArea(Point A[], int vertices);
private:
int vert;
Point ord[];
};
class Rectangle : public ShapeTwoD {
public:
Rectangle(string shapename = "Rectangle", bool containsWS, int vertices = 4, Point ordinates[]):ShapeTwoD(shapename, containsWS){}
int getVert();
void setVert(int vertices);
Point getOrd();
void setOrd(Point ordinates[]);
virtual double computeArea(Point A, Point B);
private:
int vert;
Point ord[];
};
class Square : public ShapeTwoD {
public:
Square(string shapename = "Square", bool containsWS, int vertices = 4, Point ordinates[]):ShapeTwoD(shapename, containsWS){}
int getVert();
void setVert(int vertices);
Point getOrd();
void setOrd(Point ordinates[]);
virtual double computeArea(Point A, Point B);
private:
int vert;
Point ord[];
};
#endif /* SHAPETWOD_H */
/*
* File: ShapeTwoD.cpp
* Author: Administrator
*
* Created on October 30, 2012, 12:05 AM
*/
#include "ShapeTwoD.h"
#include <sstream>
ShapeTwoD::ShapeTwoD(string shapename, bool containsWS) {
name = shapename;
containsWarpSpace = containsWS;
}
string ShapeTwoD::getName() {
return name;
}
void ShapeTwoD::setName(string shapename) {
name = shapename;
};
bool ShapeTwoD::getContainsWarpSpace() {
return containsWarpSpace;
}
void ShapeTwoD::setContainsWarpSpace(bool containsWS) {
containsWarpSpace = containsWS;
}
string cvtBool(bool b) {
stringstream ss;
ss << b;
return ss.str();
}
string ShapeTwoD::toString() {
return "Name:\t" + name + "\nSpecial Type:\t" + cvtBool(containsWarpSpace) + "\n";
}
// Formulas gotten from http://www.mathopenref.com/coordpolygonarea.html
// http://softsurfer.com/Archive/algorithm_0103/algorithm_0103.htm
int pointsInShape;
int pointsOnShape;
double ShapeTwoD::computeArea() {
// Based on Pick's Thorem
double area = pointsInShape + (pointsOnShape / 2) - 1;
return area;
}
float isLeft(Point P0, Point P1, Point P2) {
return ((P1.x - P0.x) * (P2.y - P0.y) - (P2.x - P0.x) * (P1.y - P0.y));
}
bool ShapeTwoD::isPointInShape(Point P, Point* V, int n) {
// Input: P = a point,
// V[] = vertex points of a polygon V[n+1] with V[n]=V[0]
int wn = 0; // the winding number counter
// loop through all edges of the polygon
for (int i = 0; i < n; i++) { // edge from V[i] to V[i+1]
if (V[i].y <= P.y) { // start y <= P.y
if (V[i + 1].y > P.y) // an upward crossing
if (isLeft(V[i], V[i + 1], P) > 0) // P left of edge
++wn; // have a valid up intersect
} else { // start y > P.y (no test needed)
if (V[i + 1].y <= P.y) // a downward crossing
if (isLeft(V[i], V[i + 1], P) < 0) // P right of edge
--wn; // have a valid down intersect
}
}
pointsInShape += wn;
return true;
}
bool ShapeTwoD::isPointOnShape(Point A, Point B, Point C, int slope, int intercept, int left, int top, int right, int bottom, int dx, int dy) {
// Linear equation
dx = B.x - A.x;
dy = B.y - A.y;
slope = dy / dx;
intercept = y1 - slope * A.x;
if (A.x < B.x) {
left = A.x;
right = B.x;
} else {
left = B.x;
right = A.x;
}
if (A.y < B.y) {
top = A.y;
bottom = B.y;
} else {
top = B.y;
bottom = A.y;
}
if (slope * C.x + intercept > (C.y - 0.01) && slope * C.x + intercept < (C.y + 0.01)) {
if (C.x >= left && C.x <= right && C.y >= top && C.y <= bottom) {
pointsOnShape++;
return true;
}
}
}
Cross::Cross(string shapename, bool containsWS, int vertices = 12, Point ordinates[]):ShapeTwoD(shapename, containsWS) {
vert = vertices;
ord[] = ordinates[];
}
int Cross::getVert() {
return vert;
}
void Cross::setVert(int vertices) {
vert = vertices;
}
Point Cross::getOrd() {
return ord[];
}
void Cross::setOrd(Point ordinates[]) {
ord[] = ordinates[];
}
double Cross::computeArea(Point A[], int vertices) {
/* If you know the coordinates of the vertices of a polygon, this algorithm can be used to find the area.
* Parameters
* X, Y Arrays of the x and y coordinates of the vertices, traced in a clockwise direction, starting at any vertex. If you trace them counterclockwise, the result will be correct but have a negative sign.
* numPoints The number of vertices
* Returns the area of the polygon
*/
double area = 0;
int j = vertices - 1; // The last vertex is the 'previous' one to the first
for (int i = 0; i < vertices; i++) {
area = (area + (A[j].x + A[i].x) * (A[j].y - A[i].y))/2;
j = i;
}
return area;
}
Rectangle::Rectangle(string shapename, bool containsWS, int vertices = 4, Point ordinates[]):ShapeTwoD(shapename, containsWS) {
vert = vertices;
ord[] = ordinates[];
}
int Rectangle::getVert() {
return vert;
}
void Rectangle::setVert(int vertices) {
vert = vertices;
}
void Rectangle::getOrd() {
return ord[];
}
void Rectangle::setOrd(Point ordinates[]) {
ord[] = ordinates[];
}
double Rectangle::computeArea(Point A, Point B, Point C) {
double length = sqrt(pow((A.x - B.x), 2) + pow((A.y - B.y), 2));
double width = sqrt(pow((B.x - C.x), 2) + pow((B.y - C.y), 2));
double area = length * width;
return area;
}
Square::Square(string shapename, bool containsWS, int vertices, Point ordinates[]):ShapeTwoD(shapename, containsWS) {
vert = vertices;
ord[] = ordinates[];
}
int Square::getVert() {
return vert;
}
void Square::setVert(int vertices) {
vert = vertices;
}
void Square::getOrd() {
return ord[];
}
void Square::setOrd(Point ordinates[]) {
ord[] = ordinates[];
}
double Square::computeArea(Point A, Point B) {
double length = sqrt(pow((A.x - B.x), 2) + pow((A.y - B.y), 2));
double area = pow(length, 2);
return area;
}
/*
* File: Assn2.cpp
* Author: Administrator
*
* Created on October 29, 2012, 11:58 PM
*/
#include "ShapeTwoD.h"
#include <iostream>
#include <math.h>
#include <string>
#include <vector>
using namespace std;
// Global declarations
void menu(), option1(), option2(), option3(), option4();
int choice, vert;
string shape, special;
double area;
bool containsWS;
vector<ShapeTwoD> stdv;
int main() {
cout << "Welcome to Assn2 program!\n\n";
// When user enters 5 as input, the program quits
while (choice != 5) {
menu();
/* switch evaluates expression and checks if it is equivalent to constant1,
* if it is, it executes group of statements 1 until it finds the break statement.
* When it finds this break statement the program jumps to the end of the switch selective structure.
* If expression was not equal to constant1 it will be checked against constant2.
* If it is equal to this, it will execute group of statements 2 until a break keyword is found,
* and then will jump to the end of the switch selective structure.
*/
switch (choice) {
case 1:
option1();
break;
case 2:
option2();
break;
case 3:
option3();
break;
case 4:
option4();
break;
}
}
}
void menu() {
cout << "1) Input sensor data\n";
cout << "2) Compute area (for all records)\n";
cout << "3) Print shapes report\n";
cout << "4) Sort shape data\n";
cout << "5) Quit\n\n";
cout << "Please enter your choice: ";
cin >> choice;
cout << "\n";
}
void option1() {
cout << "[ Input sensor data ]\n";
cout << "Please enter name of Shape (Cross, Rectangle or Square): ";
cin >> shape;
cout << "Please enter Special type (NS or WS): ";
cin >> special;
if (special == "WS") {
containsWS = true;
}
else {
containsWS = false;
}
if (shape == "Cross") {
vert = 12;
for (int v = 0; v < vert; v++) {
Point ordinates[v];
cout << "Please enter x-ordinate of pt. " << (v+1) << ":";
cin >> ordinates[v].x;
cout << "Please enter y-ordinate of pt. " << (v+1) << ":";
cin >> ordinates[v].y;
Cross cross(shape, containsWS, vert, ordinates[v]);
stdv.push_back(cross);
}
}
if (shape == "Rectangle") {
vert = 4;
for (int v = 0; v < vert; v++) {
Point ordinates[v];
cout << "Please enter x-ordinate of pt. " << (v+1) << ":";
cin >> ordinates[v].x;
cout << "Please enter y-ordinate of pt. " << (v+1) << ":";
cin >> ordinates[v].y;
Rectangle rectangle(shape, containsWS, vert, ordinates[v]);
stdv.push_back(rectangle);
}
}
else {
shape = "Square";
vert = 4;
for (int v = 0; v < vert; v++) {
Point ordinates[v];
cout << "Please enter x-ordinate of pt. " << (v+1) << ":";
cin >> ordinates[v].x;
cout << "Please enter y-ordinate of pt. " << (v+1) << ":";
cin >> ordinates[v].y;
Square square(shape, containsWS, vert, ordinates[v]);
stdv.push_back(square);
}
}
cout << "Record successfully stored. Going back to main menu";
}
void option2() {
if (stdv.size() != 0) {
for (int count = 0; count < stdv.size(); count++) {
area = stdv.at(count).computeArea();
//Debugging purpose
cout << (count+1) << ")" << stdv.at(count).getName() << "\t" << area;
}
cout << "Computation completed! (" << stdv.size() << " records were updated)\n\n";
}
}
Here I'm trying to insert an array of the struct Point into my class constructors (Cross, Rectangle, Square). But it returned me some errors which I don't really get.
Assn2.cpp:113: error: no matching function for call to
`Cross::Cross(std::string&, bool&, int&, Point&)'
ShapeTwoD.h:41: note: candidates are: Cross::Cross(const Cross&)
ShapeTwoD.h:43: note: Cross::Cross(std::string, bool,
int, Point*)
Assn2.cpp:136: error: no matching function for call to
`Rectangle::Rectangle(std::string&, bool&, int&, Point&)
ShapeTwoD.h:56: note: candidates are: Rectangle::Rectangle(const
Rectangle&)
ShapeTwoD.h:58: note: Rectangle::Rectangle(std::string, bool, int,
Point*)
your function declaration won't even compile, the parameter with default value can't be in the front of argument without default value:
Cross(string shapename = "Cross", bool containsWS, int vertices = 12, Point ordinates[])
Rectangle(string shapename = "Rectangle", bool containsWS, int vertices = 4, Point ordinates[]):ShapeTwoD(shapename, containsWS){}
Square(string shapename = "Square", bool containsWS, int vertices = 4, Point ordinates[]):ShapeTwoD(shapename, containsWS){}
you either make all parameters having all default values or change the order, for example below is valid function declaration:
Cross(bool containsWS, Point ordinates[], string shapename = "Cross", int vertices = 12)