Orthogonal variables code duplication problem - c++

I've started refactoring some legacy code recently and came across two functions for drawing a coordinate grid, the problem is that these functions differ only in orthogonal variables they treat, something like that
void DrawScaleX(HDC dc, int step, int x0, int x1, int y0, int y1)
{
for(int x = x0; x < x1; x += step)
{
MoveToEx(dc, x, y0, NULL);
LineTo(dc, x, y1);
}
}
void DrawScaleY(HDC dc, int step, int x0, int x1, int y0, int y1)
{
for(int y = y0; y < y1; y += step)
{
MoveToEx(dc, x0, y, NULL);
LineTo(dc, x1, y);
}
}
So if I decide to add some fancy stuff, like antialiasing or merely change drawing pencil or whatever I'll have to put the same code in both of them and it's code duplication and it's bad we all know why.
My question is how would you rewrite these two functions into a single one to avoid this problem?

Why you just do not extract the body of the for cycle into a separate function? Then you can do the funny stuff in the extracted function.
void DrawScaleX(HDC dc, int step, int x0, int x1, int y0, int y1)
{
for(int x = x0; x < x1; x += step)
{
DrawScale(dc, x, y0, x, y1);
}
}
void DrawScaleY(HDC dc, int step, int x0, int x1, int y0, int y1)
{
for(int y = y0; y < y1; y += step)
{
DrawScale(dc, x0, y, x1, y);
}
}
private void DrawScale(HDC dc, int x0, int y0, int x1, int y1)
{
//Add funny stuff here
MoveToEx(dc, x0, y0, NULL);
LineTo(dc, x1, y1);
//Add funny stuff here
}

Drawing a line is simply joining two points, and drawing a scaling incrementing (x0,y0) and(x1,y1) in a particular direction, through X, and/or through Y.
This boils down to, in the scale case, which direction(s) stepping occurs (maybe both directions for fun).
template< int XIncrement, YIncrement >
struct DrawScale
{
void operator()(HDC dc, int step, int x0, int x1, int y0, int y1)
{
const int deltaX = XIncrement*step;
const int deltaY = YIncrement*step;
const int ymax = y1;
const int xmax = x1;
while( x0 < xmax && y0 < ymax )
{
MoveToEx(dc, x0, y0, NULL);
LineTo(dc, x1, y1);
x0 += deltaX;
x1 += deltaX;
y0 += deltaY;
y1 += deltaY;
}
}
};
typedef DrawScale< 1, 0 > DrawScaleX;
typedef DrawScale< 0, 1 > DrawScaleY;
The template will do its job: at compile time the compiler will remove all the null statements i.e. deltaX or deltaY is 0 regarding which function is called and half of the code goes away in each functor.
You can add you anti-alias, pencil stuff inside this uniq function and get the code properly generated generated by the compiler.
This is cut and paste on steroids ;-)
-- ppi

Here is my own solution
class CoordGenerator
{
public:
CoordGenerator(int _from, int _to, int _step)
:from(_from), to(_to), step(_step), pos(_from){}
virtual POINT GetPoint00() const = 0;
virtual POINT GetPoint01() const = 0;
bool Next()
{
if(pos > step) return false;
pos += step;
}
protected:
int from;
int to;
int step;
int pos;
};
class GenX: public CoordGenerator
{
public:
GenX(int x0, int x1, int step, int _y0, int _y1)
:CoordGenerator(x0, x1, step),y0(_y0), y1(_y1){}
virtual POINT GetPoint00() const
{
const POINT p = {pos, y0};
return p;
}
virtual POINT GetPoint01() const
{
const POINT p = {pos, y1};
return p;
}
private:
int y0;
int y1;
};
class GenY: public CoordGenerator
{
public:
GenY(int y0, int y1, int step, int _x0, int _x1)
:CoordGenerator(y0, y1, step),x0(_x0), x1(_x1){}
virtual POINT GetPoint00() const
{
const POINT p = {x0, pos};
return p;
}
virtual POINT GetPoint01() const
{
const POINT p = {x1, pos};
return p;
}
private:
int x1;
int x0;
};
void DrawScale(HDC dc, CoordGenerator* g)
{
do
{
POINT p = g->GetPoint00();
MoveToEx(dc, p.x, p.y, 0);
p = g->GetPoint01();
LineTo(dc, p.x, p.y);
}while(g->Next());
}
But I it seems to me too complicated for such a tiny problem, so I'm looking forward to still see your solutions.

Well, an obvious "solution" would be to make a single function and add one extra parameter (of enum-like type). And then do an if() or switch() inside, and perform the appropriate actions. Because hey, the functionality of the functions is different, so you have to do those different actions somewhere.
However, this adds runtime complexity (check things at runtime) in a place that could be just better checked at compile time.
I don't understand what's the problem in adding extra parameters in the future in both (or more functions). It goes like this:
add more parameters to all functions
compile your code, it won't compile in a bunch of places because it does not pass new parameters.
fix all places that call those functions by passing new parameters.
profit! :)
If it's C++, of course you could make the function be a template, and instead adding an extra parameter, you add a template parameter, and then specialize template implementations to do different things. But this is just obfuscating the point, in my opinion. Code becomes harder to understand, and the process of extending it with more parameters is still exactly the same:
add extra parameters
compile code, it won't compile in a bunch of places
fix all places that call that function
So you've won nothing, but made code harder to understand. Not a worthy goal, IMO.

I think I'd move:
MoveToEx(dc, x0, y, NULL);
LineTo(dc, x1, y);
into their own function DrawLine(x0,y0,x0,y0), which you can call from each of the existing functions.
Then there's one place to add extra drawing effects?

A little templates... :)
void DrawLine(HDC dc, int x0, int y0, int x0, int x1)
{
// anti-aliasing stuff
MoveToEx(dc, x0, y0, NULL);
LineTo(dc, x1, y1);
}
struct DrawBinderX
{
DrawBinderX(int y0, int y1) : y0_(y0), y1_(y1) {}
void operator()(HDC dc, int i)
{
DrawLine(dc, i, y0_, i, y1_);
}
private:
int y0_;
int y1_;
};
struct DrawBinderY
{
DrawBinderX(int x0, int x1) : x0_(x0), x1_(x1) {}
void operator()(HDC dc, int i)
{
DrawLine(dc, x0_, i, x1_, i);
}
private:
int x0_;
int x1_;
};
template< class Drawer >
void DrawScale(Drawer drawer, HDC dc, int from, int to, int step)
{
for (int i = from; i < to; i += step)
{
drawer(dc, i);
}
}
void DrawScaleX(HDC dc, int step, int x0, int x1, int y0, int y1)
{
DrawBindexX drawer(y0, y1);
DrawScale(drawer, dc, x0, x1, step);
}
void DrawScaleY(HDC dc, int step, int x0, int x1, int y0, int y1)
{
DrawBindexY drawer( x0, x1 );
DrawScale(drawer, dc, y0, y1, step);
}

Related

elegant template overloading solution?

In c++11 I have functions
double f(double x1);
double f(double x1, double x2);
double f(double x1, double x2, double x3);
double h(double x);
I also have functions
double g(std::vector<double> y, double x1);
double g(std::vector<double> y, double x1, double x2);
double g(std::vector<double> y, double x1, double x2, double x3);
The implementation of g is something like
double g(std::vector<double> y, double x1, double x2, double x3)
{
double ans = 0.0;
for(g : y)
{
ans = h(g) * f(x1, x2, x3);
}
return ans;
}
Is there an elegant (templated) way of doing this instead of writing g 3 times with overloaded arguments?
template<typename... Ts>
double g(std::vector<double> v, Ts&&...ts ) {
double ret = 1;
for(auto x:v){
ret *= h(x)*f(ts...);
}
return ret;
}
if you want to restrict the ts to be doubles beyond calling f, it needs more work. Otherwise, the above is enough.
(Note the resriction work gets prettier in C++1y with concepts lite: in C++11 I vote to skip the restriction of Ts to doubles, and just rely on f only taking doubles.)

Polygon intersection with Boost::geometry severe performance deterioration

I have a particle system and I am using boost::geometry to approximate my elliptical particles as polygons and then use the intersection function of the library to find the overlap area. I am calculating an "inner" and "outer" ellipse(polygon) area to assign a "potential" for each particle-particle interaction.
My potential function is this:
double Potential(Cell* current, Cell* next)
{
double areaRep, areaAtt;
double distance = Distance(current,next);
double A1 = current->getLength();
double B1 = A1/2.0;
double theta1 = current->getTheta(); //*180.0/M_PI
double x1 = current->getCurrX();
double y1 = current->getCurrY();
double A2 = next->getLength();
double B2 = A2/2.0;
double theta2 = next->getTheta();
double x2 = next->getCurrX();
double y2 = next->getCurrY();
polygon_2d poly1, poly2, poly3, poly4;
double lamda1, lamda2;
lamda1 = 0.0005; lamda2 = 0.00001;
if(distance < 2.0*1.5*A1) {
ellipse2poly(theta1, A1, B1, x1, y1, &poly1);
ellipse2poly(theta2, A2, B2, x2, y2, &poly2);
areaRep = getOverlapingAreaPoly(poly1,poly2);
ellipse2poly(theta1, 1.5*A1, 1.5*B1, x1, y1, &poly3);
ellipse2poly(theta2, 1.5*A2, 1.5*B2, x2, y2, &poly4);
areaAtt = getOverlapingAreaPoly(poly3, poly4);
return (lamda1*areaRep - lamda2*areaAtt);
}
else
return 0.0;
}
The "polygonizing" function is:
int ellipse2poly(double theta, double A1, double B1, double H1, double K1, polygon_2d *po)
{
using namespace boost::geometry;
polygon_2d poly;
const int n = 20;
double angle = theta; // cell orientation
double a = A1; // Long semi-axis length
double b = B1; // short semi-axis length
double xc = H1; // current X position
double yc = K1; // current Y position
if(!n)
{
std::cout << "error ellipse(): n should be >0\n" <<std::endl;
return 0;
}
double t = 0;
int i = 0;
double coor[2*n+1][2];
double x, y;
double step = M_PI/(double)n;
double sinphi = sin(angle);
double cosphi = cos(angle);
for(i=0; i<2*n+1; i++)
{
x = xc + a*cos(t)*cosphi - b*sin(t)*sinphi;
y = yc + a*cos(t)*sinphi + b*sin(t)*cosphi;
coor[i][0] = x;
coor[i][1] = y;
t += step;
}
assign_points(poly, coor);
correct(poly);
*po = poly;
return 1;
}
And the returned area is:
double getOverlapingAreaPoly(polygon_2d poly, polygon_2d poly2)
{
point_2d cent; //centre of overlaping area
double overAreaPoly = 0.0;
typedef std::vector<polygon_2d > polygon_list;
polygon_list v;
intersection(poly,poly2,v);
for (polygon_list::const_iterator it = v.begin(); it != v.end(); ++it)
{
centroid(*it, cent);
overAreaPoly = area(*it);
}
return overAreaPoly;
}
The function is called for every cell (particle) as long as it is not for the same one. Previously, using another method, one iteration of my algorithm would take approximately 43 ms for one iteration for 100 particles. Now it takes approximately 1 min(!!!), so I guess I have done something horribly wrong!
I have tested this only in MSVC2012 under win7 64bit. I will report back for Linux Mint with Qt 4.7.4.
EDIT:
I have tested on Linux Mint with Qt 4.7.4 and it is running very reasonably; maybe 90-100 ms per iteration which is fine. I don't know what is wrong in win7...
I have actually fixed it. I started a new project in Visual Studio and copied all source and header files, recompiled and everything runs smoothly now. I guess radically changing code and adding / subtracting stuff must have some impact...

How to pass member functions to composition's member that takes function pointers?

I have the below class that yields this error for the lines I commented: Description Invalid arguments 'Candidates are:
Eigen::Matrix Forward_Euler(double ()(double), double ()(double), double (*)(double))' I'm getting confused when trying to search for a solution.
The signature for Forward Euler is:
Eigen::MatrixXd Forward_Euler(double (*f)(double), double (*gleft)(double), double (*gright)(double))
And my class is:
class C
{
protected:
A x;
B y;
double a;
double b;
Eigen::MatrixXd u;
public:
double f(double x)
{
return a;
}
double gleft(double tau)
{
return b
}
double gright(double tau)
{
return a*b;
}
FD_Euro_Put(): x(), y(), a(0), b(0){}
FD_Euro_Put(char y1, double y2, double y3, double y4, double x2,
double x3, double x4, double x5, double x6, double x7):
x(x1, x2, x3, x4, x5, x6, x7)
{
double Xleft = x1*x2;
double Xright = x1*x3;
double Tauf = x1*x1;
double NN = floor((x1/x2);
a = x1*x2 - 0.5;
b = x1*x2 + 0.5;
pde = HeatPDE(y1, NN, Xleft, Xright, Tauf, Alpha); //begin problem area
u.resize(pde.N+1, pde.M+1);
if(fdtype == 'f')
u = pde.Forward_Euler(&f, &gleft, &gright);
else if(fdtype == 'b')
u = pde.Backward_Euler(&f, &gleft, &gright);
else if(fdtype == 'c')
u = pde.Crank_Nicolson(&f, &gleft, &gright); //end problem area
else
cout << "Incorrect choice for finite difference type!" << endl;
}
Member function pointers and function pointers are not the same thing. Member function pointers have a much more difficult job and need to deal with things like virtual functions and the this pointer.
But look at the functions in your class! They are not really object functions because they use nothing from the object. You can either move them out of the class or make them static functions of the class. If you do either of those things you can use them as function pointers.
I think you have to use a class template and static functions. You can provide the arguments as template arguments.

Acessing protected members of composition class

I have the below class that has two custom objects as member variables. I get errors with the bold section. What is the proper way to access protected members of the composition classes? I get 'within this context' errors the f, gleft, and gright functions and when I try to resize u.
class C
{
protected:
A x;
B y;
double a;
double b;
Eigen::MatrixXd u;
public:
double f(double x)
{
return x;
}
double gleft(double tau)
{
return tau
}
double gright(double tau)
{
return 0;
}
FD_Euro_Put(): x(), y(), a(0), b(0){}
FD_Euro_Put(char y1, double y2, double y3, double y4, double x2,
double x3, double x4, double x5, double x6, double x7):
x(x1, x2, x3, x4, x5, x6, x7)
{
double Xleft = x1*x2;
double Xright = x1*x3;
double Tauf = x1*x1;
double NN = floor((x1/x2);
a = x1*x2 - 0.5;
b = x1*x2 + 0.5;
pde = HeatPDE(y1, NN, Xleft, Xright, Tauf, Alpha); //begin problem area
u.resize(pde.N+1, pde.M+1);
if(fdtype == 'f')
u = pde.Forward_Euler(&f, &gleft, &gright);
else if(fdtype == 'b')
u = pde.Backward_Euler(&f, &gleft, &gright);
else if(fdtype == 'c')
u = pde.Crank_Nicolson(&f, &gleft, &gright); //end problem area
else
cout << "Incorrect choice for finite difference type!" << endl;
}
You can't access protected members of a class unless it explicitly lists you as a friend or you inherit from that class.
A hack would be to wrap that class in your own class which gives getters for those members.
But from a logical standpoint, if those members aren't public, you probably shouldn't need access to them anyway.

Unknown bug affecting Graham's algorithm for finding convex hull

I have programmed the Graham's algorithm but it still gives me the wrong points for the convex hull. I need help. Think I have a bug in my sign function but dunno what it is.
#include <cstdio>
#include <algorithm>
#include <math.h>
#define pb push_back
#define mp make_pair
#include <vector>
using namespace std;
vector <pair<double, double> > st;
pair<double, double> p[1000];
double x, y;
int f(pair <double,double> a, pair<double, double> b)
{
double x1 = x - a.first, x2 = x - b.first;
double y1 = y - a.second, y2 = y - b.second;
return ((x1*y2-y1*x2) < 0);
}
void setlast(double &x1, double &y1, double &x2, double &y2)
{
x2 = st[st.size()-1].first;
y2 = st[st.size()-1].second;
x1 = st[st.size()-2].first;
y1 = st[st.size()-2].second;
}
sign improved I use doubles
double sign(double x1,double y1, double x2,double y2, double y3,double x3)
{
double xx1 = x2 - x1, xx2 = x3 - x1;
double yy1 = y2 - y1, yy2 = y3 - y1;
return (xx1*yy2-yy1*xx2);
}
int main()
{
int n;
x = 0x3f3f3f3f;
y = 0x3f3f3f3f;
scanf("%d", &n);
for(int i = 0; i < n; i++)
{
scanf("%lf %lf", &p[i].first, &p[i].second);
if(p[i].first <= x && p[i].second <= y)
x = p[i].first,
y = p[i].second;
}
sort(p, p + n, f);
p[n].first = x;
p[n].second = y;
st.pb(mp(p[0].first, p[0].second));
st.pb(mp(p[1].first, p[1].second));
double x1, x2, x3, y1, y2, y3;
here I iterate through all vectors and try to determine the points of convex hull
for(int i = 2; i < n; i++)
{
x3 = p[i].first;
y3 = p[i].second;
setlast(x1,y1,x2,y2);
while(1)
if(sign(x1,y1,x2,y2,x3,y3) < 0)
{
st.pb(mp(x3, y3));
break;
}
else
st.pop_back(),
setlast(x1, y1, x2, y2);
}
here printing the convex hull
for(int i = 0; i < st.size(); i++)
printf("%lf %lf\n", st[i].first, st[i].second);
return 0
}
My question, why does int f(pair<int, int>, pair<int, int>) take pair<int, int> instead of pair<double, double>?
Also, why isn't it named something informative like compare_blah?
Lastly, why doesn't it return bool instead of an int? Either works of course, but it will be clearer that this is intended simply as a comparison function if you return a bool. And making your program clear to people who read it should be your primary goal. Getting it to do what it's supposed to is a secondary goal. After all, it doing what it's supposed to is only a transitory state of affairs. Eventually someone will want it to do something else.
The pair<int, int> thing could be your problem right there. You are doing several implicit type conversions in that function between int and double and losing information left and right. I doubt that's what you intended.
If you would use a typedef for your pair like typedef pair<double, double> point2d_t and then use point2d_t everywhere you could protect yourself from mistakes like that and make your program clearer in the bargain.
I'm not familiar enough with Graham's algorithm to evaluate your use of abs inside of f, though it's quite possible the person who commented on this is correct.