John Ratcliff's Code Suppository

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

 

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++

9 Comments:

  • At 5:07 PM, Blogger cbloom said…

    lol, well done sir.

    BTW there is one ambiguity in that bestfit.h - what's the sign convention for plane[3] ?

     
  • At 6:30 PM, Blogger John said…

    The sign is the one I usually use in my code. If you don't like it, I strongly recommend you multiply times negative one. :)

     
  • At 7:13 PM, Blogger Shane said…

    Hehe I love a good old coder rant. Keep up the good work :)

     
  • At 3:59 AM, Anonymous Anonymous said…

    John, I've found your source code snippets extremely helpful and I've used it in a number of projects. I know I'm smart enough to figure out how to use it, I don't know if I'd be smart enough to write the code myself. Over time, I've understood more and become more capable.

    It's not hard for me to imagine a beginner who doesn't even know how to use the code, I'm sure with time they would get better too. In fact, I would argue very few beginner programmers understand the concept of 'strides'. I know I didn't when I began.

    Nobody is expects you to answer all your questions, and I think its great that you actually answered, but I think it's a shame you decided to respond in this tone. Especially for someone who is admired and respected so much in the community.

     
  • At 7:52 AM, Anonymous Matt S. said…

    People on the internets tubes run the full extreme from the brightest to the dumbest on earth. To actual coders, your snippets and examples are a delight and always cause for further investigation and thought, please don't be dissuaded from continuing them.

     
  • At 3:53 PM, Blogger Shane said…

    There is no crime in being 'dumb' (I hate that word), but there is against being lazy. It's a habit I've seen develop over the past few years of Internet baby programmers who fire off questions without thinking through problems on their own.

    I think it's lazy programmers John has issue with, not beginners or unintelligent people.

    Keep fighting the good fight John, I think seeing simple, decoupled code is good for Noobs and programmers who write 'template' before everything ;)

     
  • At 5:23 PM, Anonymous Anonymous said…

    Humorous, but adding a comment as simple as
    //stride = sizeof(float)*3 for float array
    would have prevented the confusion. I'd blame this on the code writer, not the confused users.

     
  • At 4:55 PM, Blogger Alexis said…

    This is an old post, yet it's exactly what I have been looking for! A simple reference for best fit plane for a bunch of points, not 10k lines of code for dealing with huge point clouds.

    By the way, I think that if someone can't use your code, they don't really deserve to be helped. This is some of the nicest code to be found on the internet, easily usable right away (though I'll first convert what I need to C).

    Thanks!

     
  • At 5:52 PM, Blogger Alexis said…

    Tiny correction: I know that part is just meant as an example but main() must return int in both C or C++.

    Some compilers may be more accommodating, but gcc and g++ won't touch a "void main()".

     

Post a Comment

<< Home