I am writing a small utility class that transfor latitude and longitude coordinated into a UTM local system. For this task I am using this source. I created some struct to help me manage the majority of the data, but something is wrong if I pass data in a speciific way. It does work if I clearly re-state the values. See below the example:
zoneconverter.h
#ifndef ZONE_CONVERTER_H
#define ZONE_CONVERTER_H
#include <string>
#include <math.h>
#include <cmath>
#include <ctgmath>
#include <stdlib.h>
#include <stdio.h>
#include <stdexcept>
#define PI 3.14159265358979323846 /* pi */
#define SMaxA 6378137.0 /* semi major axis */
#define SMinA 6356752.314245 /* sdmi minor axis */
#define grid_size 100000.0 /* 100 km grid*/
struct Deg2Rad {
double D2R = PI/180.0;
};
struct Rad2Deg {
double R2D = PI*180.0;
};
// definition of the World Geodetic System 84
struct WGS84_DATA
{
double semi_major_axis_a = 6378137.0; // by definition
double semi_minor_axis_b = 6356752.314245; // by definition
const double flattening = (SMaxA-SMinA)/SMaxA; // by definition
const double first_eccentricity = 0.081891909; // by calculation
double second_eccentricity = 0.0820944377; // by calculation
double angular_velocity_earth = 72.92115e-6; // rad/s
double gravitational_constant = 3986004.418e8; // by definition
};
struct UTM_DATA
{
double point_scale_factor = 0.9996; // by convention
double equatorial_radius = 6378137.0; // meters also semi_major_axis_a
double inverse_flattening = 1/((SMaxA-SMinA)/SMaxA); // by convention
double northen_emisphere = 0.0; // meter
double southern_hemisphere = 10000000.0; // meter
double false_esting = 500000.0; // meter by convention
double first_eccentricity_power2 = 0.081891909*0.081891909;
double first_eccentricity_power4 = 0.081891909*0.081891909*0.081891909*0.081891909;
double first_eccentricity_power6 = 0.081891909*0.081891909*0.081891909*0.081891909*0.081891909*0.081891909;
};
enum UTMidentifierLeter {
X, W, V, U, T, S, R, Q, P, N,
M, L, K, J, H, G, F, E, D, C, Z
};
struct UTM_LETTER_ZONE { UTMidentifierLeter utmLetterZone; };
enum UTMIdentifierZone { NORWAY, SVALBARD };
struct UTM_ZONE { UTMIdentifierZone utmZone; };
class ZONE_converter
{
public:
ZONE_converter();
WGS84_DATA wgs84_data;
UTM_DATA utm_data;
Deg2Rad degreeToRad_reader;
Rad2Deg radToDeg_reader;
void UTM(double lat, double lon, double eastingUtmzone, double northingUtmzone);
char adjustForNorway(double lat);
char adjustForSvalbard(double lat, double lon);
char allOtherZones(double lat);
private:
UTM_LETTER_ZONE letter;
UTM_ZONE zone;
double latitude;
double longitude;
int current_zone;
};
#endif // ZONE_CONVERTER_H
zoneconverter.cpp is as following
#include "zone_converter.h"
ZONE_converter::ZONE_converter(){}
void ZONE_converter::UTM(double lat, double lon, double eastingUtmzone, double northingUtmzone)
{
double m0_a11 = (std::pow(wgs84_data.first_eccentricity, 4)/4);
double m0_a12 = (std::pow(wgs84_data.first_eccentricity, 4)/64);
double m0_a13 = (std::pow(wgs84_data.first_eccentricity, 6))/256;
double m0 = 1 - m0_a11 - 3*m0_a12 - 5*m0_a13;
double m1_a11 = (std::pow(wgs84_data.first_eccentricity, 2))/8;
double m1_a12 = (std::pow(wgs84_data.first_eccentricity, 4))/32;
double m1_a13 = (std::pow(wgs84_data.first_eccentricity, 6))/1024;
double m1 = -(3*m1_a11 + 3*m1_a12 + 45*m1_a13);
double m2_a11 = (std::pow(wgs84_data.first_eccentricity, 4))/256;
double m2_a12 = (std::pow(wgs84_data.first_eccentricity, 6))/1024;
double m2 = 15*m2_a11 + 45*m2_a12;
double m3_a11 = (std::pow(wgs84_data.first_eccentricity, 6))/3072;
double m3 = -35*m3_a11;
// calculation of the central meridian
int centralMeridian = ((lon >= 0.0)
? (static_cast<int>(lon) - (static_cast<int>(lon)) % 6 + 3)
: (static_cast<int>(lon) - (static_cast<int>(lon)) % 6 - 3));
double rlat = degreeToRad_reader.D2R;
double rlon = degreeToRad_reader.D2R;
double rlon0 = centralMeridian*degreeToRad_reader.D2R;
double slat = std::sin(rlat);
double clat = std::cos(rlat);
double tlat = std::tan(rlat);
double fn = (lat > 0) ? utm_data.northen_emisphere : utm_data.southern_hemisphere;
double T = tlat*tlat;
double C = (wgs84_data.first_eccentricity*wgs84_data.first_eccentricity)*clat*clat;
double A = (rlon - rlon0)*clat;
double M = (wgs84_data.semi_major_axis_a)*(m0*rlat + m1*std::sin(2*rlat) + m2*std::sin(4*rlat) + m3*std::sin(6*rlat));
// radius of curvature on the plane of the prime vertical
double Rn = wgs84_data.semi_major_axis_a/(std::sqrt(1 - std::pow((wgs84_data.first_eccentricity), 2)*slat*slat));
// radius of Curvature in the plane os the meridian
double Rc = ((wgs84_data.semi_major_axis_a)*(1 - ((wgs84_data.first_eccentricity)*(wgs84_data.first_eccentricity))))/(1 - ((wgs84_data.first_eccentricity)*(wgs84_data.first_eccentricity))*std::pow(std::sin(rlat), 2));
// computation of the easting-northing coordinate
eastingUtmzone = utm_data.point_scale_factor*Rn*(A + ((1-T+C)*(std::pow(A, 3)/6))+(5-18*T + std::pow(T,2) + 72*C - 58*(std::pow(wgs84_data.second_eccentricity, 2)))*(std::pow(A, 5))/120);
northingUtmzone = utm_data.point_scale_factor*((M - 0.0)+Rn*tlat*(((A*A)/2) + (((std::pow(A, 4))/24)*(5-T+9*C+4*C*C)) + (61 - 58*T + T*T + 600*C - 330*(std::pow(wgs84_data.second_eccentricity, 2))*((std::pow(A, 6))/720))));
(void) Rc;
(void) fn;
return;
}
main.cpp
#include <iostream>
#include "zone_converter.h"
using namespace std;
int main()
{
ZONE_converter convert;
double lat = 26.281742;
double lon = 92.142683;
double eastingUtmzone;
double northingUtmzone;
convert.UTM(lat, lon, eastingUtmzone, northingUtmzone);
std::cout<< lat << lon<< northingUtmzone<< eastingUtmzone<< std::endl;
return 0;
}
But I am trying to understand why if I write the function in the following way accessing the struct I created in header file I get a SIGSEV segmentation error:
void ZONE_converter::UTM(double lat, double lon, double eastingUtmzone, double northingUtmzone)
{
double m0_a11 = (std::pow(wgs84_data.first_eccentricity, 2)/4);
double m0_a12 = (std::pow(wgs84_data.first_eccentricity, 4)/64);
double m0_a13 = (std::pow(wgs84_data.first_eccentricity, 6))/256;
double m0 = 1 - m0_a11 - 3*m0_a12 - 5*m0_a13;
// ... additional operation
}
Can anyone shed light on this matter?
One issue is that you're using uninitialized variables here:
double eastingUtmzone; // uninitialized
double northingUtmzone; // uninitialized
convert.UTM(lat, lon, eastingUtmzone, northingUtmzone);
std::cout<< lat << lon<< northingUtmzone<< eastingUtmzone<< std::endl;
So there are at least two points of failure -- within the convert.UTM that uses these variables, and in the std::cout after the call.
Since utilizing uninitialized variables is undefined behavior, expect anything to happen, where one of those things seemingly is a SIGSEGV occurring.
Related
When initializing a struct using curly braces, it does not seem to work with an array of chars. I can write an equivalent constructor that works below. Is there any syntax so I don't have to write the constructor?
#include <cstdint>
#include <cstring>
using namespace std;
struct NamedLocationData {
uint16_t offset;
char stateName[21];
float lat;
float lon;
uint32_t population;
NamedLocationData(uint16_t offset, const char stateName[21],
float lat, float lon, uint32_t population)
: offset(offset), lat(lat), lon(lon), population(population) {
strncpy(this->stateName, stateName, 21);
}
};
int main() {
uint16_t nameOffset = 0;
char stateName[21] = "New York";
float lat = 40;
float lon = -74;
uint32_t population = 8000000;
#if 0
NamedLocationData temp = NamedLocationData
{
nameOffset, stateName, lat, lon, population
};
#endif
NamedLocationData temp( nameOffset, stateName, lat, lon, population);
}
Default constructors are one of the special member functions. If no constructors are declared in a class, the compiler provides an implicit inline default constructor.
I suggest you change char[] to string so that stateName will be able to get a value.
#include <cstdint>
#include <cstring>
#include <string>
using namespace std;
struct NamedLocationData {
uint16_t offset;
string stateName;
float lat;
float lon;
uint32_t population;
NamedLocationData(uint16_t offset, string stateName,
float lat, float lon, uint32_t population)
: offset(offset), lat(lat), lon(lon), population(population) ,
stateName(stateName){}
};
int main() {
uint16_t nameOffset = 0;
string stateName = "New York";
float lat = 40;
float lon = -74;
uint32_t population = 8000000;
#if 0
NamedLocationData temp = NamedLocationData
{
nameOffset, stateName, lat, lon, population
};
#endif
NamedLocationData temp(nameOffset, stateName, lat, lon, population);
return 0;
}
Result:
So I am trying to implement an integration function from scratch in CPP. I have been stuck on this for 2 days.
I am not sure how to do an integration computation from x to +inf. My plan was to use the sigmoid function as a substitution for the integration which should mathematically work but it didn't work computationally. Formula reference: https://en.wikipedia.org/wiki/Integration_by_substitution#Definite_integrals
My questions are 1). why my method didn't work? 2). Is there a better method/function to be used for the substitution?
Reproducible Code
which can be accessed via https://onlinegdb.com/F3rzIEReA with explanations as comments
#include <iostream>
#include <cmath>
const double PI = 3.14159265358979323846;
using namespace std;
// I have an interface for a real function named RealFunction which
// is used to be fed into the integral function
class RealFunction {
public:
virtual ~RealFunction() {};
virtual double evaluate( double x ) = 0;
};
// integral function that utilises the rectangular rule
double integral( RealFunction& f,
double a,
double b,
int nPoints ) {
double h = (b-a)/nPoints;
double x = a + 0.5*h;
double totalHeight = 0.0;
for (int i=0; i<nPoints; i++) {
double height = f.evaluate(x);
totalHeight+=height;
x+=h;
}
return h*totalHeight;
}
// a probability normal distribution function
class NormPDF : public RealFunction {
public:
NormPDF(double mu, double sigma) :
mu(mu), sigma(sigma){}
NormPDF() :
mu(0.0), sigma(1.0){}
double mu;
double sigma;
double evaluate(double x){
return exp(-0.5*pow((x-mu)/sigma,2.0))/(sigma*sqrt(2*PI));
}
};
// my chosen substitution function - sigmoid function
double sigmoidFunction(double x) {
return 1/(1+exp(-x));
}
// implementing the integral to infinity function with
// the sigmoid function
double integralToInfinity( RealFunction& f,
double x,
int nPoints) {
class SigmoidInfusedFunction : public RealFunction {
public:
SigmoidInfusedFunction(RealFunction& f) :
f(f) {
}
RealFunction &f;
double evaluate(double x) {
// d(sig)/dx = exp(-x) / pow(1+exp(-x),2)
return f.evaluate(sigmoidFunction(x)) * exp(-x) / pow(1+exp(-x),2);
}
};
SigmoidInfusedFunction sigmoidInfusedFunc(f);
return integral(sigmoidInfusedFunc, sigmoidFunction(x), 1, 1000);
}
int main() {
// Test for integrate - result: 0.95004 expected: 0.95 (CORRECT)
NormPDF normPDF;
cout << integral(normPDF, -1.96, 1.96, 1000) << endl;
// Test for infinity - result: 0.0688965 expected: 0.5 (INCORRECT)
cout << integralToInfinity(normPDF, 0, 1000) << endl;
return 0;
}
Hello I am a student learning c++ and I am just starting to learn OOP. The problem is in my MAIN however I am showing all of my files in case it is from another file.
I have written my hpp and cpp file and now I am just working on my main for testing. The class is called Box and when I create an object box1 or box 2 and attempt to access my functions it says there are two few arguments. It says this regardless of whether I put box1.calcVolume(double h, double w, double l) or box1.calcVolume();
So the issue is on the line(s) that say:
double volume2 = box2.calcVolume();
double volume1 = box1.calcVolume();
double surfaceArea1 = box1.calcSurfaceArea();
If anyone can spot something that I missing our may not understand please let me know.
This is the header file:
#pragma once
#include <iostream>
#ifndef BOX_HPP
#define BOX_HPP
class Box
{
private:
double height;
double width;
double length;
public:
void setHeight(double h);
void setWidth(double w);
void setLength(double l);
double calcVolume(double h, double w, double l);
double calcSurfaceArea(double h, double w, double l);
Box();
Box(double height, double width, double length);
};
#endif
This is the CPP file
#include <iostream>
#include "Box.hpp"
Box::Box()
{
setHeight(1);
setWidth(1);
setLength(1);
}
Box::Box(double h, double w, double l)
{
setHeight(h);
setWidth(w);
setLength(l);
}
void Box::setHeight(double h)
{
height = h;
}
void Box::setWidth(double w)
{
width = w;
}
void Box::setLength(double l)
{
length = l;
}
double Box::calcVolume(double h, double w, double l)
{
double volume;
volume = h * w * l;
return volume;
}
double Box::calcSurfaceArea(double h, double w, double l)
{
double surfaceArea;
surfaceArea = 2 * (h*w) + 2 * (h*l) + 2 * (l*w);
return surfaceArea;
}
my BoxMain file:
#include <iostream>
#include "Box.hpp"
using std::cout;
using std::cin;
using std::endl;
int main()
{
Box box1(1.1, 2.4, 3.8);
Box box2;
box2.setHeight(12);
box2.setWidth(22.3);
box2.setLength(2.3);
double volume2 = box2.calcVolume();
double volume1 = box1.calcVolume();
double surfaceArea1 = box1.calcSurfaceArea();
cout << box1.calcVolume(); << endl; //testing different methods
return 0;
}
Your method takes three parameters:
double Box::calcVolume(double h, double w, double l)
{
double volume;
volume = h * w * l;
return volume;
}
So, you would call it like so:
Box b;
double volume = b.calcVolume(1, 2, 3);
But that's not quite right. An instance of Box knows how big it is, because you pass a size to the constructor, which stores the sizes in the fields width, height, and length. You probably want something like this:
double Box::calcVolume()
{
volume = height * width * length;
return volume;
}
You have the code wrong. The dimensions of the box are known during the creation of box object. The length, width and height are already available - updated in the member variables.
Functions calcVolume and calcSurfaceArea should not take arguments but return the computed value. Modified code below:
double Box::calcVolume()
{
return height*width*length;
}
double Box::calcSurfaceArea()
{
return 2*((height*width) + (height*length) + (length*width));
}
Also, remember to modify the .hpp file with the declarations corresponding to the code above.
Declaration in the .hpp file should be
double calcVolume();
double calcSurfaceArea();
I have solved the problem. I removed the arguments in calcVolume and calcSurfaceArea everywhere in my code and it resolved the error.
I am trying to make and ode solver using c++ and numerical methods (euler, heun and runge kutta). first i made and abstract class for ode solving requirements then i made a separate class for each solver inheriting from the ABClass. there is no problem with the code excpet it works only with first order differential equations as dydt = y
however i need to expand it to be able to solve a system of first order differential equations as dydt = x-y & dxdt = y together
here is the header file
#ifndef ABSTRACTODESOLVER_H_INCLUDED
#define ABSTRACTODESOLVER_H_INCLUDED
#include <iostream>
using namespace std;
class AbstractOdeSolver
{
private:
double stepsize;
double initialTime;
double finalTime;
double initialValue;
public:
double (*RHS)(double, double); //pointer to function
void SetStepSize(double h);
void SetIntervalTime(double t0, double t1);
void SetInitialValue(double y0);
void setRHS(double (*pRHS)(double, double)); //set pointer function
double getStepSize(){return stepsize;}
double getInitialTime(){return initialTime;}
double getFinalTime(){return finalTime;}
double getInitialValue(){return initialValue;}
virtual void SolveEquation() = 0;
};
class EulerSolver : public AbstractOdeSolver
{
public:
virtual void SolveEquation();
};
class HeunSolver : public AbstractOdeSolver
{
public:
virtual void SolveEquation();
};
class RungeKuttaSolver : public AbstractOdeSolver
{
public:
virtual void SolveEquation();
};
#endif // ABSTRACTODESOLVER_H_INCLUDED
and this is the source code for one solver:
void EulerSolver::SolveEquation(){
double yNew = 0.0;
double yOld = getInitialValue(); // y0 initial value of Y
double tInit = getInitialTime(); // t0 initial value of T
double tFinal = getFinalTime();
double h = getStepSize();
for (double i = tInit; i <= tFinal; i += h){
yNew = yOld + (h * RHS(tInit,yOld));
yOld = yNew;
tInit += h;
cout << left << setw(5) << tInit << " " << setw(5) << yNew << endl;
}
}
and this is a program:
double Func(double t, double y){
return y;
}
EulerSolver euler1;
euler1.SetIntervalTime(0,0.6);
euler1.SetInitialValue(1);
euler1.SetStepSize(0.1);
euler1.setRHS(Func);
euler1.SolveEquation();
here i am using a function pointer RHS to allow the solver to use the function every time in the iteration, however i need to have more than one function in order to solve higher degree equations and the problem i dont know a way of making two separate functions with related variables (dydt = x-y & dxdt = y) and then having a pointer on each and returning the answer in an array!.
Any ideas will be great.
I'm currently writing the implementation file of a program I'm doing. I included the header file in it which is why you don't see as much as you would usually see
This is the program in which all the functions you see are included in a class called "Body". The member functions are public except for the std::istream which is considered "friend" and the variables are private
I'm trying to understand why I am getting this error:
"passing const Body as 'this' argument of double Body::getX() discards qualifiers"
This error is pointing to my distanceTo function that I wrote. I kind of understand what the error message is saying but I really need the passing argument of distantTo function to be constant. Any way of fixing this?
This is the overall view of my program:
#include "Body.h"
#include <cmath>
#include <vector>
#include <fstream>
Body::Body(std::string _name, double _mass, double _x,
double _y, double _vx, double _vy)
{
name = _name;
mass = _mass;
x = _x;
y = _y;
vx = _vx;
vy = _vy;
}
double Body::getX()
{
return x;
}
double Body::getY()
{
return y;
}
double Body::getVX()
{
return vx;
}
double Body::getVY()
{
return vy;
}
double Body::getMass()
{
return mass;
}
void Body::setX(double _x)
{
x = _x;
}
void Body::setY(double _y)
{
y = _y;
}
void Body::setVX(double _vx)
{
vx = _vx;
}
void Body::setVY(double _vy)
{
vy = _vy;
}
void Body::draw(Canvas &canvas)
{
canvas.DrawCircle(getX(), getY(), 10);
canvas.DrawText(getX()+2, getY(), name);
}
istream &Body::operator>>(std::istream &input, Body &body)
{
input >> body.name >> body.mass >> body.x >> body.y >> body.vx >> body.vy;
return input;
}
double Body::distanceTo(const Body &other)
{
double tx = x-other.getX();
double ty = y-other.getY();
double ans = sqrt(tx*tx + ty *ty);
return ans;
}
double Body::forceX(double G, const Body &body)
{
double d = distanceTo(body);
double d3=d*d*d;
double tx = x - getX();
double dx= sqrt( tx * tx );
double fx = G * ((mass * getMass() * dx) / d3);
return fx;
}
double Body::forceY(double G, const Body &body)
{
double d = distanceTo(body);
double d3=d*d*d;
double ty = y - getX();
double dy= sqrt( ty * ty );
double fy = G * ((mass * getMass() * dy) / d3);
return fy;
}
Private data:
std::string name;
double x, y;
double vx, vy;
double mass;
Make your get member functions constant, nothing changes in these functions and will allow your distance function to work as expected
double getX() const;
double getY() const;
To clarify, as chris pointed out in the comments you cannot call a non-const function with a constant object. You promised the compiler the object would not change what so ever, so you need to provide constant functions to make the compiler happy.