Writing Code for Surface Plots?
MySchizoBuddy asks: "In what ways can you code plots of surface charts using a z(x,y) function or a cloud of points? I'm looking for a tutorial that explains this that doesn't use DirectX or OpenGL libraries (the language I'm using cannot use either framework anyway). How is the 3D mess generated and how can the 2D contour plots be generated as well? I'm assuming once I know that I can also use it to make torus plots as well. Remember, I'm asking for the explanation of the underlying math and an example code that does that. The GNUPlot gallery has some examples that I find helpful, but are there similar examples out there? (Remember, I am writing the plotting code as well)? Can anyone help or point me in the right direction?"
http://www.detachedsolutions.com/graph3/
This is software that does what you need, written for the TI-83 (should work fine on an 84 too). Since it's open source, you can peek at the source code to get an idea of how its 3d rendering works.
Unfortunately, most TI calculator apps are coded in assembly...
I looked at 3D rendering quite a while back (about 15 years ago). Believe me -- you probably don't really want to built this up from scratch.
It sounds like you just need some sample code that doesn't rely on OpenGL or DirectX. To that end, the following (open-source) projects may be useful:
Gan Family Homepage
Good 2D contour plotting is not easy (I know!!!).
If you are not afraid of coding, then the best reference that I know of is:
by Albrecht Preusser, ACM TOMS V10#4
The code (in FORTRAN, unfortunately) is also in TOMS as:
Algorithm 626 TRICP: A Contour Plot Program Triangular Meshes
You can get ACM TOMS (Transaction on Mathematical Software) from any reasonable college library.
This might be a bit of overkill, as it is designed for irregular data sets (versus regular datasets - grids). However, the code can be separated into a separate Delaunay Triangulation step. If you have a grid (or in your case, a function f(x,y)), it is easy to generate fixed triangles.
If anybody knows of a better algorithm, I'm all ears!!!
My advice would be to pick up a decent intro book on graphics. The Foley and Van Dam is a classic, but nearly any good book on the topic tends to have a review of the basic math involved in 3d: linear algebra with 3- or 4-value vectors and 3x3 or 4x4 matrices, the perspective divide, etc. Knowing the basics will help you have a lot better idea of what to do. But for anyone curious about the most basic 3d, here's a simple way to do it that should work decently for simple wireframe plots.
" > /> <!-- First line to draw --> /> <!-- Second line to draw --> /> <!-- Third line to draw, etc... -->
1) Take each 3d point of interest and apply some set of rotations around the X, Y, and Z axis to get the view angle right. You'll probably want to just do one rotation around each axis. e.g.:
x2 = x * cos( z_angle ) + y * sin( z_angle );
y2 = x * -sin( z_angle ) + y * cos( z_angle );
x3 = x2 * cos( y_angle ) + z * sin( y_angle );
z2 = x2 * -sin( y_angle ) + z * cos( y_angle );
y3 = y2 * cos( x_angle ) + z2 * sin( x_angle );
z3 = y2 * -sin( x_angle ) + z2 * cos( x_angle );
At this point, you'll have rotated your original coordinate (x,y,z) by some angle around some axis to get (x3,y3,z3)
(To my fellow graphics geeks: yes, yes, I know full well that matrices and quaternions are better -- I'm trying keep this simple.)
2) Maybe add some distance to the z value, to move ("translate") it away from the "camera" at the origin. You'll need to add enough to make sure that all of your z-values are positive and non-zero before step 3:
z4 = z3 + z_translate
3) Do what's called the "perspective divide" to find the two dimensional coordinate of this point. e.g.:
px = x3 / z4 * scale + center_x;
py = y3 / z4 * scale + center_y;
4) Either plot a point at the (px,py) that you just got, or compute steps 1 and 2 twice for the end points of lines and then use your system's graphics primitives to draw lines between (px1,py1) and (px2,py2). If you're not using a language or a library that can do simple 2d graphics, then I'd suggest writing out a file with the lines in SVG format (and then rasterize to bitmap with a program like Batik, Inkscape, Illustrator, etc.) e.g.:
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd
<svg width="4cm" height="4cm" viewBox="0 0 400 400" xmlns="http://www.w3.org/2000/svg" version="1.1">
<path d="M px1 py1 L px2 py2" fill="none" stroke="black" stroke-width="1"
<path d="M px1 py1 L px2 py2" fill="none" stroke="black" stroke-width="1"
<path d="M px1 py1 L px2 py2" fill="none" stroke="black" stroke-width="1"
</svg>
5) If you want more than wireframe, things will be a lot more complicated. At the very least, you'll need to be able to fill polygons and sort back to front by the z-value after the rotation so that everything gets drawn in the correct order. Z-buffers would be even better.
Well, I hope all that helps. Again, if anyone's really interested, I'd suggest getting a real book on the topic. But I hope this's enough to get the curious started.
I just looked at the GNUPlot page, and regardless of what anyone else says, I don't think it should be too difficult to code at all, at least the grid stuff like near the top of that page. The reason - it's all drawn without perspective, which means a little vector math tells you where to put each point. You might be a bit foolish to try to hand-code something substantial with perspective, but orthogonal projections are straightforward.
Here's what you need to do. First, figure out what a unit in the X, Y, and Z axes corresponds to in screen coordinates. In the examples on the GNUPlot page, I'd estimate that a unit in the X direction is about 10 pixels to the right and 2 pixels down in screen coordinates, or (10, -2). Similarly, a unit in the Y direction is about (3, 3), and a unit in the Z direction is (0, 1). Now, to find the screen location of a point given in 3D, say (x,y,z), we start at the screen coordinate of the origin (wherever you want to put (0,0,0)). To this, we add x times the vector (10, -2), y times the vector (3, 3), and z times the vector (0, 1). For example, the point (10, 3, 6), with an origin at (100, 100), would show up at (100, 100) + (100, -20) + (9, 9) + (0, 6) = (209, 95).
In other words, if we call the unit vectors in the X, Y and Z directions (given in screen coordinates) Xhat, Yhat, and Zhat, then the point (x,y,z) should be plotted at (origin + x*Xhat+y*Yhat+z*Zhat).
I presume that from here you should be able to figure out how to draw the grid lines - just sample a bunch of points, and draw straight lines between neighbors. If you want to fill in the tiles (like the pictures near the bottom of the GNUPlot page), you'll need to be clever about the order you fill them in so that the ones in front are filled last. For this, you can sort the tiles by the appropriate combination of x and y coordinates (in "real" space, not screen space) - in our example, Xhat - 3.333Yhat points straight down, so you would sort by the combination x - 3.333y and draw in that order.
This should at least get you on your way. I'm sure there are subtleties to consider, but hey - it's your project, not mine, so I'll leave it at that!
Hate to disappoint you, but you're probably not going to find a tutorial and code that conveniently meets your requirements. For starters, eliminating OpenGL and D3D is going to remove a large number of tutorials, simply because it doesn't make sense for most people to roll their own rendering code.
Your best bet would be to look through "Computer Graphics: Principles and Practice" by Foley, van Dam, Feiner and Hughes. It covers a large number of topics, in enough detail to get a good idea of how to get started and where to look for more information. Also "Real-Time Rendering" by Tomas Möller and Eric Haines. Despite the name, a large portion of the book is applicable to almost all computer graphics, not just real-time. Also, a book on linear algebra would probably be helpful.
Maybe not
I'm out of mod points, but this is insightful. The R programming language is GPL'ed and works on lin/win/osx (packages for major distros). It is an interpreted language (except for a few internal commands), and so the source code for the several different 3D plotters is included with the program. Some you might have to install yourself, but this can be done by the install.packages command.
You might want to have a quick look at output from different 3D commands (persp, scatterplot3d and wireframe).
The introductory documentation might be a bit confusing - especially since it's often written for and by statisticians, but there's a mailinglist with a huge googleable archive and I've often found that "google:r-project search term" will get me what I need.
Any sufficiently advanced libertarian utopia is indistinguishable from government.
You can use the marching cubes algorithm. You can go from a cloud of points to a 3d object that you can transform like you want. I think they use that in MRI imaging. I used the 2d version (marching squares) to optimize a metablob routine a long time ago.
see: http://www.exaflop.org/docs/marchcubes/index.html