John Ratcliff's Code Suppository

A place where I insert my code into the anus of the Internet.

 

Saturday, June 13, 2009

Apparently I'm not Charles Bloom



Yesterday I posted a rant out of frustration at a frequent number of emails I get from people on the Internet. I often get asked questions by people, who from the content of their question, clearly don't know how to program in C++ hardly at all. It's difficult to figure out how to respond to that sort of thing.

Here's the deal. I'm a nice guy. It's not just a put on, or an act, or a pose, or anything like that. I'm genuinely a nice person. I really like to help people out, not just in programming, but in life in general. I also really like to teach and I absolutely don't mind people asking me programming questions.

All that said, there are certain types of questions, like those that indicate you don't know how to program at all, that completely leave me at a loss.

After I posted my rant yesterday an Anonymous (yep you heard it, anonymous) person left a comment chastising me for being so rude and obnoxious to people who just wanted to learn from a professional software developer.

Well, anonymous comments on my blog are yet another one of my pet peeves that often make me launch off on a rant. Seriously, if you ever really want me to answer a question, don't leave an Anonymous comment! Take a moment and enter an email address so I can respond to you directly.

Nevertheless, the guy who left the comment was right. It is inappropriate and out of character for me to curse out beginner programmers who simply want to learn something.

I edited yesterday's post, removed the F-bombs and personal insults, but left the basic tone and content the same. With this post I would like to apologize. I do encourage people, even beginners, to learn from my code snippets. To be frank, that is often whey I write them! Especially 'FloatMath' which is an amazing repository for various and sundry math functions.

So, feel free to ask me questions and I promise I won't be insulting. However, if you are such a beginner that you can't understand some very basic and simple things about C++ programming, I have to be honest, there isn't much I can tell you until you bone up on your skills. And, if that is the case, I will try to say so politely instead of going off on a rant.

I like to rant, just like Charles Bloom does, but I don't like the repercussions. The things I wrote on my blog yesterday I would never say to someone's face. Thus the weird dichotomy of Internet communications.

Once again I apologize to anyone who might have been offended by my post. I genuinely want to help programmers, even beginner programmers, solve their problems. My main motivation in this site, besides simply sharing useful code with developers who have shared useful code with me (such as Charles Bloom one of the most generous open source developers out there) is to educate.

If you are disappointed that I backed off my rant, then I strongly recommend you subscribe to a news feed of Charles Bloom's website as I'm sure you will find your daily dose of rank ranting over there.

Friday, June 12, 2009

Holy Crap??? My very own Charles Bloomesque Rant



( The snippet form of the best fit plane code can be found here. It supports both single and double precision floating point numbers and even has an example 'main' in it for the truly technically challenged)

bestfit.h
bestfit.cpp)

(Note: The following rant has been edited from it's original by the author.)

Holy crap. I pride myself on being able to provide source code which is extremely (and I mean *extremely*) easy for people to adopt and use.

That is why I put everything in 'snippet' form; and by that I mean one header, one CPP, with no external dependencies of any kind. I provide code that is not dependent on special templates or data types.

The one piece of code that people come to this site for a lot, is the code snippet I provided for computing a best fit plane.

Now, I didn't even actually write this code myself. David Eberly did on his Magic Software site. I love David Eberly to death, he provides more amazing free source code to the community than nearly anyone else. That said, David does commit the horrific crime of providing code that can *only* be used within the context of his personal suite of template/type libraries. It is virtually impossible to just extract one useful math routine out of his code base without having to adopt every vector, matrix, quaternion, template, and every other dependency all of his code requires.

In fact it took me the better part of the day to convert his 'best fit plane' routine into code snippet form.

Now, it simply amazes me how many questions I get from people who can't understand how to use my code-snippet version!??!

I have even had a number of people email me with the question "I don't get it, where is 'main'?".

Really? Seriously?

This is one tiny isolated routine, one snippet of code. Drop it into your own program, call it, and be done.

If you don't know how to even use a code snippet in the first place, you might not be at the right web site...

So, hey, maybe I'm wrong here.....

So let's check back.

Here is the only thing the header file contains for the best fit plane code snippet:

----------------------------------------------------------

bool fm_computeBestFitPlane(size_t vcount, // number of input data points
const float *points, // starting address of points array.
size_t vstride, // stride between input points.
const float *weights, // *optional point weighting values.
size_t wstride, // weight stride for each vertex.
float plane[4]);

-----------------------------------------------------------------

So...what's the problem? What is there not to understand? I can understand not understaning the 'weighting' part, because I didn't really explain that. But, the rest, really!???

Ok, now in baby steps.....

Let's say you have a set of 3D data points. Woops....just realized I might be talking past my audience.

3D means 'three dimensional' as in representing a location in three dimensional space, typically represented as the notation X, Y, and Z.

Each point in space is three floating points numbers.

Example: float this_is_a_point_in_space[3] = { 3, 4, 5 };

Got that?

Understand?

Ok, now let's represent 2 points in space.....

float this_is_two_points_in_space[6] = { 3, 4, 5, 8, 1, 4 };

Now, lots of people don't use just a float array to represent their points. They often use data structures.

They might have a structure like:

struct Point
{
float x;
float y;
float z;
};

Thus, they might represent two ponts as:

Point this_is_two_points[2];

Get it? Follow me?

And...sometimes...people have structures that contain data in addition to just the points!

For example:

struct Vertex
{
Point position;
int color;
};

Follow me?

You can represent your points in a variety of ways *in your code* but one thing is always common. A point, in 3 space, is three floating point numbers in the order of X, Y, Z.

Thus... in my routine, you pass the address of the x component of your first point and the stride (stride is the distance between the first X and the next X in bytes).

The return value is a plane. What do I mean by that?

There are four components to a plane equation typically expressed as A,B,C, and D.

Now, my routine returns the results of the plane equation as four floating point numbers representing A,B,C, and D.

What follows are several examples of how you can call my mysterious and cryptic code:

--------------------------------------------------------------------------------

float points[9] = { 3, 4, 2, 8, 1, 4, -4, 4, 3 }; // float array with 3 data points in the form of x,y,z

float plane[4]; // will contain the computed plane equation result

fm_computeBestFitPlane(3, // we have 3 data points.
points, // the address of the X component of the first data point.
sizeof(float)*3, // The stride (distance in bytes) between one point and the next.
NULL, // pass a null pointer for weights
0, // pass a zero for weight stride.
plane); // the address of the plane equation to store the result.

-------------------------------------------------

Ok, now here is an example presuming your code has data types such as 'Vertex' and 'Plane'.

Vertex vertices[3];
Plane p;

fm_computeBestFitPlane(number_of_points,
&mVertices.mPoint.x,
sizeof(Vertex),
0,
0,
&p.A); // the address to store the plane equation results in the form A,B,C,D

-------------------------------------------------------------------

On a final note, the field for weights is an optional set of weighting values corresponding with each vertex. They are unitless and simply serve as relative weighting components.

If you want the plane fitting code to weigh some vertices more strongly than others, then you would pass a larger weight value at that index location.

Since the weighting thing is entirely optional I won't bother to explain it further. Personally, I think it is self-evident.

Look, to adopt a number of these code snippets requires a minimum technical knowledge about programming in C++