Slashdot Mirror


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?"

10 of 81 comments (clear)

  1. Graph3 by The+MAZZTer · · Score: 1, Informative

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

  2. You sure you want to do the math? by perlionex · · Score: 3, Informative

    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:

  3. 2D contouring by jmac880n · · Score: 4, Informative

    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:

    • Computing Contours by Successive Solution of Quintic Polynomial Equations
      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!!!

    1. Re:2D contouring by jmac880n · · Score: 2, Informative

      Pardon me, I'd like to make a correction. Good 2D contour plotting from scattered point data is not easy. For contour plotting from a regular grid, the marching squares algorithm is simple, easy to implement, and works pretty well. Run it several times with different reference values to get all the contours you want.

      Uhhh... I said good 2D contouring is hard. Marching squares is by NO stretch of the imagination good, even with regular data. Easy, yes. Good, no.

      It has discontinuities. Good contouring will have smoothness at least to the 2nd derivative. TRICP uses fifth order equations to fit the derivatives on all sides of the triangulation so that the resulting curves are smooth at all points. As I pointed out, triangulation is trivial with regular gridded data.

      And subsampling using cubic interpolation will not help the discontinuities that appear with marching squares. Unless you use an algorithm that fits the derivatives at the region boundaries, you will get noticable jagged lines.

  4. Basic Rundown by The+boojum · · Score: 4, Informative

    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.

    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" /> <!-- First line to draw -->
        <path d="M px1 py1 L px2 py2" fill="none" stroke="black" stroke-width="1" /> <!-- Second line to draw -->
        <path d="M px1 py1 L px2 py2" fill="none" stroke="black" stroke-width="1" /> <!-- Third line to draw, etc... -->
    </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.

  5. Shouldn't be too tough... by ClassMyAss · · Score: 2, Informative

    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!

  6. Read a book by jlarocco · · Score: 4, Informative

    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.

    1. Re:Read a book by sglow · · Score: 2, Informative

      Here's the best book on the subject that I've come across.

      Mathematical Elements for Computer Graphics
      http://www.nar-associates.com/nar-publishing/mecg2 nd.htm

  7. Re:R-project by infolib · · Score: 2, Informative

    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.
  8. Marching cubes by Hillman · · Score: 2, Informative

    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