Jump to content

  • Log In with Google      Sign In   
  • Create Account


taby

Member Since 10 Feb 2005
Offline Last Active May 11 2014 11:18 AM
***--

#5152594 Four pillars of object oriented programming

Posted by taby on 09 May 2014 - 02:36 PM

I reimplemented the polymorphism example to take into account multiple types, like Glass_Knife suggested (I think):

 

#include <iostream>
using std::cout;
using std::endl;


// Base class with virtual member function
class A
{
public:
    virtual void talk(void)
    {
        cout << "Class A" << endl;
    }
};
 
class B: public A
{
public:
    void talk(void)
    {
        cout << "Class B" << endl;
    }
};

int main(void)
{
    A a;
    B b;

    A *a_ptr = &a;
    a_ptr->talk();

    a_ptr = &b;
    a_ptr->talk();

    // Also see function overloading as an example of polymorphism
    // ie:
    // int add(int a, int b) { return a + b }
    // float add(float a, float b) { return a + b }
    //
    // Also see templates
    // ie:
    // STL containers

    return 0;
}



#5152593 Four pillars of object oriented programming

Posted by taby on 09 May 2014 - 02:23 PM

If it seems that no one can agree what the "four pillars of OOP" are, perhaps you should take that as a sign that the idea of "four pillars" is bullshit.

 

LOL, perhaps that's true. :)




#5152555 Four pillars of object oriented programming

Posted by taby on 09 May 2014 - 10:32 AM

What are the four pillars of object oriented programming, with regards to C++? I've googled and googled this subject, and there are different answers depending on which site you visit. What is your impression as to what the four pillars are? I've given my impression below, in the form of code snippets. Are these snippets the correct way to think of the four pillars?

 

Simple class / object:

#include <iostream>
using std::cout;
using std::endl;


class A
{
public:
    A(void)
    {
        value1 = 123;
    }

    int value1;
};


int main(void)
{
    A a;
    cout << a.value1 << endl;

    return 0;
}

Pillar 1 encapsulation:

#include <iostream>
using std::cout;
using std::endl;


class A
{
public:
    A(void)
    {
        value1 = 123;
    }

// Encapsulating the member variable by making it protected from code
// that exists outside of the class    
protected:
    int value1;

public:
    int getvalue1(void)
    {
        return value1;
    }

    void setvalue1(const int value)
    {
        value1 = value;
    }
};


int main(void)
{
    A a;
    cout << a.getvalue1() << endl;

    return 0;
}

Pillar 2 inheritence:

#include <iostream>

using std::cout;
using std::endl;


// Base class
class A
{
public:
    A(void)
    {
        value1 = 123;
    }

protected:
    int value1;

public:
    int getvalue1(void)
    {
        return value1;
    }

    void setvalue1(const int value)
    {
        value1 = value;
    }
};


// Inheriting class
class B: public A
{
public:
    B(void)
    {
        value2 = 456;
    }

protected:
    int value2;

public:
    int getvalue2(void)
    {
        return value2;
    }

    void setvalue2(const int value)
    {
        value2 = value;
    }
};


int main(void)
{
    B b;
    cout << b.getvalue1() << ' ' << b.getvalue2() << endl;

    return 0;
}

Pillar 3 abstraction (abstract class):

#include <iostream>
using std::cout;
using std::endl;


// Abstract base class (cannot be instantiated due to pure virtual member function)
class A
{
public:
    virtual void talk(void) = 0;
};

// Inheriting class must implement pure virtual function talk()
class B: public A 
{
public:
    void talk(void)
    {
        cout << "Class B" << endl;
    }
};


int main(void)
{
    B b;
    b.talk();

    return 0;
}

Pillar 4 polymorphism:

#include <iostream>
using std::cout;
using std::endl;


// Abstract base class (cannot be instantiated due to pure virtual member function)
class A
{
public:
    virtual void talk(void) = 0;
};

// Inheriting class must implement pure virtual function
class B: public A 
{
public:
    void talk(void)
    {
        cout << "Class B" << endl;
    }
};

// Inheriting class must implement pure virtual function
class C: public A 
{
public:
    void talk(void)
    {
        cout << "Class C" << endl;
    }
};


int main(void)
{
    B b;
    b.talk();

    C c;
    c.talk();

    // Also see general function overloading as an example of polymorphism
    // ie:
    // int add(int a, int b) { return a + b }
    // float add(float a, float b) { return a + b }
    //
    // Also see templates
    // ie:
    // STL containers

    return 0;
}



#5057804 A C++ code to smooth (and fix cracks in) meshes generated by the standard, or...

Posted by taby on 29 April 2013 - 11:12 AM

Another simple smoothing algorithm to try is where the scale is multiplied by a factor related to each vertex's angle deficit (curvature), ie.:

 

vertex[i] += displacement[i]*scale*((2pi - total_angle[i])/(2pi)).

 

This should smooth out spikes and pits, but leave ridges, valleys and flat regions relatively untouched -- which seems ideal for the task at hand.

 

Not sure what the algorithm's called, nor how much it would differ from the curvature normal weighting, but will try later today.

 

Update:  implemented as suggested, it doesn't work entirely as expected, but will try other things related to it.




#5055841 A C++ code to smooth (and fix cracks in) meshes generated by the standard, or...

Posted by taby on 22 April 2013 - 03:00 PM

In the past, some people have asked for code or help with applying a smoothing algorithm to the meshes they get from the Marching Cubes algorithm (see: 'Polygonising a scalar field' by P. Bourke).

 

I've attached some sample C++ code to perform Taubin smoothing (see: 'Geometric Signal Processing on Polygonal Meshes' by G. Taubin and 'Implicit Fairing of Irregular Meshes using Diffusion and Curvature Flow' by M. Desbrun, et al.) on a Stereo Lithography (STL) file. The code assumes that the mesh is closed -- Attached File  mc_smooth2.zip   8.27KB   154 downloads

 

The code also eliminates the cracks in the mesh that are unfailingly generated by the standard, original Marching Cubes algorithm (Google for 'marching cubes cracks' to see that it is a common problem).

 

The cracks must be eliminated before smoothing occurs, otherwise the cracks will become holes, and the mesh will be ruined.

 

Attached is a sample mesh (including cracks) -- Attached File  fractal.zip   826.28KB   89 downloads

 

Here is an image of the sample mesh as generated by Marching Cubes, rendered using flat shading -- very blocky:

1_raw_flat_shaded.png

 

Here is an image of the cracks highlighted in red, rendered using flat shading:

3_raw_cracks.png

 

Here is an image of the sample mesh after 10 iterations of Taubin smoothing, rendered using flat shading -- the cracks have now become holes, thanks to the smoothing. This is bad:

4_taubin_smoothed_holes.png

 

Here is an image of the vertex pairs (highlighted in blue, and connected by green lines) that should have been merged -- in order to fix the cracks -- before the smoothing was applied, rendered using flat shading:

5_taubin_smoothed_merge_vertices.png

 

Here is an image of the crackless mesh after 10 iterations of Taubin smoothing, rendered using flat shading -- no holes, looks less blocky:

6_taubin_smoothed_flat_shaded.png

 

Here is an image of the crackless mesh after 10 iterations of Taubin smoothing, rendered using Gouraud shading -- no holes, looks much less blocky:

7_taubin_smoothed_gouraud_shaded.png

 

Good luck.

 

P.S. The sample mesh is an isosurface of the escape value (where isovalue = 4.0) for the quaternion Julia set generated by Z' = Z^2 + C where C = {0.3, 0.5, 0.4, 0.2} and the maximum number of iterations is 8. (see: 'Quaternion Julia Fractals' by P. Bourke). The code to generate this mesh can be found at: http://code.google.com/p/qjs-isosurface/downloads/detail?name=qjs-isosurface-v2.0.2.1.zip




#4991827 Problem getting correct orbits of planets

Posted by taby on 19 October 2012 - 11:06 AM

I may have to look up tangential velocity then


Calculating the tangential velocity based on orbit parameters like distance/eccentricity:
http://www.gamedev.n...58#entry3961958

Periapsis velocity:
v = sqrt((G*M/a)*(1 + e)/(1 - e)).

The planet Mercury's semi-major axis a = 57909176e3 metres, and has an orbit eccentricity e = 0.20563069:
v = sqrt((6.6742e-11 * 1.988435e30 / 57909176e3) * (1 + 0.20563069) / (1 - 0.20563069)),
v = 58976.3015.

That's very close to the maximum orbit speed of Mercury, as 58980 m/s on wikipedia.org.

(Note, 1.988435e30 == Sun's mass)

Oppositely, for the apoapsis velocity:
v = sqrt((G*M/a)*(1 - e)/(1 + e)),
v = 38858.47.

For a circular orbit, the eccentricity is 0.

These calculations help you find the length of the tangential velocity vector. As for finding the direction of the tangential velocity vector, the cross product operation will help you (if your orbit plane is nice and aligned with the coordinate system, it's very straightforward).


#4967397 Cycled (infinite) maps

Posted by taby on 08 August 2012 - 08:42 AM

It's only an analogy because there's no embedding space in which to step out into, which is to say it's not wholly an analogy.


#4954654 Extending a normalized vector?(3d)

Posted by taby on 01 July 2012 - 03:13 PM

Ok, again, where C is the camera position, and N is the unit look-at vector...

It's the same thing in 3D. If you want your vector to be 2 or 3 times longer, then multiply all of the vector's components by 2 or 3.

To draw your unit length red line:
Start at C and end at C + N.

To draw a longer line that includes the blue:
Start at C and end at C + N*3.

As for determining 2 or 3, or whatever the factor is... that's application dependent, and it's really your call. Best of luck.

I notice that the function call drawLine(fromAllCharacters, vector3); basically treats vector3 as a position, when it's a displacement (ie. a direction times a length). Not sure what you're trying to achieve here, since it isn't at all like what I tried to show you in the first two examples. Note how I end the line segment at C + N*d (ie. a position plus a displacement is a position), not at N*d (ie. a displacement plus nothing is a displacement). These line segment drawing functions deal in positions, not displacements.

A vector V = <V.x, V.y, V.z>, or displacement, is essentially a 1D line segment (or arrow, if you prefer) that always starts at the origin's position O = <0, 0, 0> and extends to the position <O.x + V.x, O.y + V.y, O.z + V.z>. The vector is an extended object.

A position P = <P.x, P.y, P.z> is essentially a 0D point that "starts and ends" at <P.x, P.y, P.z>. The position is not an extended object.

Both objects are defined using three components, and you can even make these components equal in value by setting P = V, but in the end they are not the same kind of object. A displacement is an extended object, a position is not. The start and end points of a line segment are not extended objects.


#4950479 Macroscopic timing of pass-by-reference vs pass-by-value for const double, lo...

Posted by taby on 18 June 2012 - 09:49 PM

Oh, I know that macroscopic timing really pisses people off, but it was undeniably fair and accurate enough to get the general idea: pass-by-reference is not worth it for double and long unsigned int, and um, MSVC++ sucks balls. Of course, the functions given here are not the only functions in all of existence.

gcc on Ubuntu runs the float test much faster by default. The switch -ffast-math had some effect, though slight. The average per test fluctuated quite dramatically, making it unclear as to which pass method was faster, so running many tests and gathering the many averages would give a bigger picture.

The timer code:
#include <time.h>
struct timespec start_time;

float get_curr_time(void)
{
	struct timespec end_time; // better as static?
	clock_gettime(CLOCK_REALTIME, &end_time);

	struct timespec diff; // better as static?

	if(end_time.tv_nsec - start_time.tv_nsec < 0)
	{
		diff.tv_sec = end_time.tv_sec - start_time.tv_sec - 1;
		diff.tv_nsec = 1000000000 + end_time.tv_nsec - start_time.tv_nsec; // 1,000,000,000 nanoseconds = 1 second
	}
	else
	{
		diff.tv_sec = end_time.tv_sec - start_time.tv_sec;
		diff.tv_nsec = end_time.tv_nsec - start_time.tv_nsec;
	}

	return static_cast<float>(diff.tv_sec) + static_cast<float>(diff.tv_nsec) / 1000000000.0f; // 1,000,000,000 nanoseconds = 1 second
}

...

int main(void)
{
	clock_gettime(CLOCK_REALTIME, &start_time);

	...

	start_ref = get_curr_time();

	for(size_t j = 0; j < iterations; j++)
		out = (*fptr_ref)(in);

	end_ref  = get_curr_time();

	...




#4949359 Numerical integration methods

Posted by taby on 14 June 2012 - 05:38 PM

I think I made these codes up from the example that Gaffer had given. The Gaffer example is a great resource, but it was a bit too object-oriented for me, and I had to pare it down to understand it better. If anyone has any other integration methods that they'd like to share, I'd be very grateful, and I can put them in the same format. Maybe someone could make a sticky thread about integration, I dunno. Maybe there already is.

I'm also kind of putting this here so that I can find it easier later. Is there a way to make notes for myself on gamedev.net, that can be formatted nicely like in these forum posts?

// Euler integration
inline void proceed_Euler(body &b, const double &dt)
{
	b.velocity += acceleration(b.position, b.velocity)*dt;
	b.position += b.velocity*dt;
}

// Runge-Kutta order 2
inline void proceed_RK2(body &b, const double &dt)
{
	vector_3 k1_velocity = b.velocity;
	vector_3 k1_acceleration = acceleration(b.position, k1_velocity);

	vector_3 k2_velocity = b.velocity + k1_acceleration*dt*0.5;
	vector_3 k2_acceleration = acceleration(b.position + k1_velocity*dt*0.5, k2_velocity);

	b.velocity += k2_acceleration*dt;
	b.position += k2_velocity*dt;
}

// Runge-Kutta order 4
inline void proceed_RK4(body &b, const double &dt)
{
	static const double one_sixth = 1.0/6.0;

	vector_3 k1_velocity = b.velocity;
	vector_3 k1_acceleration = acceleration(b.position, k1_velocity);

	vector_3 k2_velocity = b.velocity + k1_acceleration*dt*0.5;
	vector_3 k2_acceleration = acceleration(b.position + k1_velocity*dt*0.5, k2_velocity);

	vector_3 k3_velocity = b.velocity + k2_acceleration*dt*0.5;
	vector_3 k3_acceleration = acceleration(b.position + k2_velocity*dt*0.5, k3_velocity);

	vector_3 k4_velocity = b.velocity + k3_acceleration*dt;
	vector_3 k4_acceleration = acceleration(b.position + k3_velocity*dt, k4_velocity);

	b.velocity += (k1_acceleration + (k2_acceleration + k3_acceleration)*2.0 + k4_acceleration)*one_sixth*dt;
	b.position += (k1_velocity + (k2_velocity + k3_velocity)*2.0 + k4_velocity)*one_sixth*dt;
}

Here's some code testing it against the code that Gaffer gave out:
// Simple RK4 integration framework
// Copyright (c) 2004, Glenn Fiedler
// http://www.gaffer.org/articles

#include <iostream>
using std::cout;
using std::endl;

#include <cmath>

// My adaptation
class vector_3
{
public:
    double x, y, z;

    vector_3(const double &src_x = 0, const double &src_y = 0, const double &src_z = 0)
    {
        x = src_x;
        y = src_y;
        z = src_z;
    }

    vector_3 operator+(const vector_3 &rhs)
    {
        return vector_3(x + rhs.x, y + rhs.y, z + rhs.z);
    }

    vector_3 operator*(const double &rhs)
    {
        return vector_3(x*rhs, y*rhs, z*rhs);
    }

    vector_3& operator+=(const vector_3 &rhs)
    {
        x += rhs.x; y += rhs.y; z += rhs.z;
        return *this;
    }
};

class body
{
public:
    vector_3 position, velocity;
};

vector_3 acceleration(vector_3 const &pos, vector_3 const &vel)
{
    const double k = 10;
    const double b = 1;
    return -k*pos.x - b*vel.x;
}

// Euler integration
inline void proceed_Euler(body &b, const double &dt)
{
    b.velocity += acceleration(b.position, b.velocity)*dt;
    b.position += b.velocity*dt;
}

// Runge-Kutta order 2
inline void proceed_RK2(body &b, const double &dt)
{
    vector_3 k1_velocity = b.velocity;
    vector_3 k1_acceleration = acceleration(b.position, k1_velocity);

    vector_3 k2_velocity = b.velocity + k1_acceleration*dt*0.5;
    vector_3 k2_acceleration = acceleration(b.position + k1_velocity*dt*0.5, k2_velocity);

    b.velocity += k2_acceleration*dt;
    b.position += k2_velocity*dt;
}

// Runge-Kutta order 4
inline void proceed_RK4(body &b, const double &dt)
{
    static const double one_sixth = 1.0/6.0;

    vector_3 k1_velocity = b.velocity;
    vector_3 k1_acceleration = acceleration(b.position, k1_velocity);

    vector_3 k2_velocity = b.velocity + k1_acceleration*dt*0.5;
    vector_3 k2_acceleration = acceleration(b.position + k1_velocity*dt*0.5, k2_velocity);

    vector_3 k3_velocity = b.velocity + k2_acceleration*dt*0.5;
    vector_3 k3_acceleration = acceleration(b.position + k2_velocity*dt*0.5, k3_velocity);

    vector_3 k4_velocity = b.velocity + k3_acceleration*dt;
    vector_3 k4_acceleration = acceleration(b.position + k3_velocity*dt, k4_velocity);

    b.velocity += (k1_acceleration + (k2_acceleration + k3_acceleration)*2.0 + k4_acceleration)*one_sixth*dt;
    b.position += (k1_velocity + (k2_velocity + k3_velocity)*2.0 + k4_velocity)*one_sixth*dt;
}
// My adaptation


// Slightly modified Gaffer code
struct State
{
    double x;
    double v;
};

struct Derivative
{
    double dx;
    double dv;
};

double acceleration(const State &state)
{
    const double k = 10;
    const double b = 1;
    return - k*state.x - b*state.v;
}

Derivative evaluate(const State &initial)
{
    Derivative output;
    output.dx = initial.v;
    output.dv = acceleration(initial);
    return output;
}

Derivative evaluate(const State &initial, double dt, const Derivative &d)
{
    State state;
    state.x = initial.x + d.dx*dt;
    state.v = initial.v + d.dv*dt;
    Derivative output;
    output.dx = state.v;
    output.dv = acceleration(state);
    return output;
}

void integrate(State &state, double dt)
{
    Derivative a = evaluate(state);
    Derivative b = evaluate(state, dt*0.5, a);
    Derivative c = evaluate(state, dt*0.5, b);
    Derivative d = evaluate(state, dt, c);

    const double dxdt = 1.0/6.0 * (a.dx + 2.0*(b.dx + c.dx) + d.dx);
    const double dvdt = 1.0/6.0 * (a.dv + 2.0*(b.dv + c.dv) + d.dv);

    state.x = state.x + dxdt*dt;
    state.v = state.v + dvdt*dt;
}
// Slightly modified Gaffer code
struct Method
{
    char const* name;
    void (*integrator)(body &b, const double &dt);
    body b;
};

int main()
{
    // Gaffer
    State state;
    state.x = 100;
    state.v = 0;

    // My adaptation

    body b;
    b.position.x = state.x;
    b.velocity.x = 0;

    Method methods[] = {
        { "RK4  ", proceed_RK4, b },
        { "RK2  ", proceed_RK2, b },
        { "Euler", proceed_Euler, b}
    };

    double t = 0;
    double dt = 0.1;


    cout << "Name | ( position, velocity )"<<endl;
    while (fabs(state.x)>0.001 || fabs(state.v)>0.001)
    {
        integrate(state, dt);

        //proceed_Euler(b, dt);
        //proceed_RK2(b, dt);
        //proceed_RK4(b, dt);

        for(int i = 0; i < sizeof(methods)/sizeof(Method); ++i) {
            methods[i].integrator(methods[i].b, dt);
            cout << methods[i].name << " (" << fabs(state.x - methods[i].b.position.x) << ", " << fabs(state.v - methods[i].b.velocity.x) << ")" << endl;
        }

        t += dt;
    }

    return 0;
}



#4947270 Using partial derivatives to light circular waves

Posted by taby on 07 June 2012 - 09:43 PM

I realize this. I'm merely using the basic sample that comes with the D3D SDK to compare. It still looks like crap, but at least it's isotropic crap.


#4947268 AABB/Plane intersection volume

Posted by taby on 07 June 2012 - 09:40 PM

Some links to give you some ideas.

http://stackoverflow.com/questions/1406029/how-to-calculate-the-volume-of-a-3d-mesh-object-the-surface-of-which-is-made-up
http://www.math.uchicago.edu/~may/VIGRE/VIGRE2007/REUPapers/FINALAPP/Peng.pdf
http://mathworld.wolfram.com/Capsule.html
http://mathworld.wolfram.com/SphericalCap.html
http://mathworld.wolfram.com/SphericalSegment.html
http://mathworld.wolfram.com/CylindricalSegment.html
http://mathworld.wolfram.com/HorizontalCylindricalSegment.html
http://mathworld.wolfram.com/CylindricalWedge.html


#4946907 I must be doing something wrong (slow development)

Posted by taby on 06 June 2012 - 06:33 PM

With regard to productivity, Patrick deWitt (winner of the 2011 Canadian Governor General's Award for English language fiction for his totally awesome book The Sisters Brothers) gave out a really great tip during the 2011 Scotiabank Giller Prize awards telecast. It was something along the lines of: Turn off your Internet connection at 8am and don't turn it back on until 5pm.

IMHO, that's just genius advice.


#4946522 need help with data oriented design

Posted by taby on 05 June 2012 - 11:33 AM

Have you ever studied the first three normal forms of relational database design? They will help you to clearly see the one-to-one, one-to-many, and many-to-many relationships that exist in all kinds of systems. I recommend it, even if you never plan on writing a single line of SQL in your life, because -- as zen and vague as it may sound -- everything is connected.

http://w3schools.in/...e-Normalization


#4945669 Question About Directory

Posted by taby on 02 June 2012 - 04:31 PM

If you're using C++ then why not use the string class (aka basic_string<char>)?

string location;

#ifdef _DEBUG
location = "foo";
#else
location = "bar";
#endif

location += filename;

Also, the VC is giving you a warning, not an error. Either ignore it or disable it using a pragma. Microsoft means well, but their recommended solution is utter garbage. So, why not use string? For the record, you should probably use wstring when handling file and directory names in general, but string may be fine in your specific case.

Look into the string's c_str() function to see how it interfaces with C-style functions. It returns a pointer, but don't return this pointer. Return the string, or pass it in as a reference so temporary duplicates are avoided.




PARTNERS