Back to draw-VTK

'draw'-VTK interface:
object elevation_grid


Once you have opened a Maxima session, load package draw and then set global variable draw_renderer to vtk:

load("draw") $
draw_renderer: 'vtk $

To read the documentation on object elevation_grid, write the following sentence:

describe(elevation_grid) $

A random matrix:

m: apply(matrix, makelist(makelist(random(1.0),k,1,10),i,1,10)) $

draw3d(
  color = white,
  elevation_grid(m, 0, 0, 10, 10)) $
vtkeleva1

Local option wired_surface on an elevation_grid object:

m: apply(
        matrix,
        makelist(makelist(random(1.0),k,1,10),i,1,10)) $

draw3d(
    enhanced3d    = true,
    wired_surface = true,
    elevation_grid(m,0,0,3,2)) $
wired3

Modules:

m: apply(
      matrix,
      makelist(makelist(mod(k,i),k,1,20),i,1,20)) $

draw3d(
  enhanced3d = true,
  elevation_grid(m, 0, 0, 20, 20)) $
vtkeleva2

An artificial landscape. The simulation may take a while, be patient:

terrain_generator(m) :=
    block([terra: float(zeromatrix(m,m)), iter:100, x, y, slope],
        for k:1 thru iter do(
            [x, y]: 1 + [random(m), random(m)],
            slope: tan(random(180.0)),
            for i:1 thru m do
                for j:1 thru m do
                    if i < slope * (j-x) + y
                        then terra[i,j]: terra[i,j] + iter/k
                        else terra[i,j]: terra[i,j] - iter/k  ) ,
        terra / iter) $

terreno: terrain_generator(100)$

draw3d(
  enhanced3d = true,
  palette    = gray,
  elevation_grid(terreno, 0, 0, 10, 10)) $
vtkeleva3

Lena. We read a list of 40000 gray levels and transform it in a square matrix of order 200:

m1: read_list("lena.txt")$

lena: apply(matrix, makelist(makelist(m1[j],j,k*200+1, k*200+200),k,0,199)) $

draw3d(
  palette    = gray,
  enhanced3d = true,
  elevation_grid(lena/10.0,1,1,100,100)) $
vtkeleva4

2D Fast Fourier Transform. Contributed by Edward G. Montague (thanks):

/* Load FFT package */
load(fft)$

N:128$
M:128$

/* 2d  fft
   input array a2
   output array b2 */
fft2(a2,b2):=
    block(
        local(i,j,n,m,ab),
        ab: arrayinfo(a2),
        n: ab[3][1],
        m: ab[3][2],
        n: n+1,
        m: m+1,
        array(b1, float, n-1),
        fillarray(b1, [0.0]),
        for j:0 thru m-1 do (
            for i:0 thru n-1 do
                b1[i]: a2[i,j],
            bb: listarray(b1),
            cc: fft(bb),
            for i:0 thru n-1 do 
                b2[i,j]: cc[i+1]),
        kill(b1,cc,i,j),
        array(b1,float,m-1),
        fillarray(b1,[0.0]),
        for i:0 thru n-1 do (
            for j:0 thru m-1 do
                b1[j]: b2[i,j],
            bb: listarray(b1),
            cc: fft(bb),
            for j:0 thru m-1 do
                b2[i,j]:cc[j+1]),
        b2 )$

/* Exchange 2d array values for centered spectrum .
   Input array   b2
   Output array  c2*/
vxchg(b2,c2) :=
    block(
        local(i,j,n,m,i1,j1,ab),
        ab: arrayinfo(b2),
        n: ab[3][1],
        m: ab[3][2],
        n: n+1,
        m: m+1,
        array(b1,float,m-1),
        array(x2,float,m-1),
        fillarray(b1,[0.0]),
        fillarray(x2,[0.0]),
        xb: listarray(x2),
        for i:0 thru n-1 do (
            for j:0 thru m-1 do
                b1[j]: b2[i,j],
            bb: listarray(b1),
            for j:1 thru m/2 do (
                i1: j+(m/2),
                xb[j]: bb[i1],
                xb[i1]: bb[j]),
            for j:0 thru m-1 do
                c2[i,j]:xb[j+1]),
        kill(b1,bb,cc,x2,xb,i,j),
        array(b1,float,n-1),
        fillarray(b1,[0.0]),
        array(x2,float,n-1),
        fillarray(x2,[0.0]),
        xb: listarray(x2),
        for j:0 thru m-1 do(
            for i:0 thru n-1 do
                b1[i]:c2[i,j],
            bb:listarray(b1),
            for i:1 thru n/2 do (
                j1: i+(n/2),
                xb[i]: bb[j1],
                xb[j1]: bb[i] ),
            for i:0 thru n-1 do
                c2[i,j]:xb[i+1]),
        c2 )$

/* Dimension arrays and generate data */
array(a2,float,N-1,M-1)$
array(b2,float,N-1,M-1)$
array(c2,float,N-1,M-1)$
fillarray(a2,[0.0])$
fillarray(b2,[0.0])$
fillarray(c2,[0.0])$
for j:0 thru (M/4)-1 do
    for i:0 thru (N/8)-1 do
        a2[i,j]: 1 $

/* Generate 2d matrix from 2d array .
   Input  array   a2
   Output matrix  Mat1 */
Mat1: genmatrix(a2,N-1,M-1)$

/* 2d  fft
   Input array   a2
   Output array  b2 */
b2: fft2(a2,b2)$

/* Absolute value of 2d array b2.
   Input array  b2
   Output array b2 */
for i:0 thru N-1 do
  for j:0 thru M-1 do
      b2[i,j]: abs(b2[i,j]) $

/* Exchange values.
   Input array   b2
   Output array  c2 */
c2: vxchg(b2,c2)$

/* Generate 2d matrix from 2d array.
   Input  array  c2
   Output matrix Mat2 */
Mat2: genmatrix(c2,N-1,M-1)$

/* Draw the two matrices */
set_draw_defaults(
        enhanced3d = [log(10000*z+1)/log(10001), x, y, z],
        palette    = [4,-10,17])$
draw(
    dimensions = [800, 400],
    columns    = 1,
    
    /* Draw 2d matrix , Mat1, with logarithmic colouring.
       This is the 2d function data. */
    gr3d(elevation_grid(Mat1, 0, 0, 10, 10)),
    
    /* Draw 2d matrix, Mat2, with logarithmic colouring.
       This is the centered spectrum */
    gr3d(elevation_grid(100*Mat2, 0, 0, 10, 10)) )$
vtkeleva5

Isolines on an elevation_grid surface.

m: matrix(
    [ 0.0, 0.0, 9.5,21.0, 10.5, 0.0, 0.0, 0.0, 0.0, 0.0],
    [ 0.0, 2.1, 2.1, 0.0, 52.5,10.5, 6.3, 0.0, 0.0, 0.0],
    [ 0.0, 2.1, 9.5,10.5, 63.0,21.0,27.3,10.5, 0.0,21.0],
    [ 0.0, 0.0, 9.5,42.0, 94.5,52.5,33.6,21.0,31.5,10.5],
    [21.0,52.5, 6.0,94.5,115.5,73.5,67.2,63.0,21.0, 0.0],
    [10.5,42.0,42.0,52.5, 73.5,84.0,42.0,42.0,10.5, 0.0],
    [ 0.0, 0.0,10.5,31.5, 21.0,42.0,54.6,63.0,31.5, 0.0],
    [ 0.0, 0.0, 0.0, 0.0,  0.0, 0.0,23.1,42.0,31.5,10.5],
    [ 5.3, 3.0, 0.0, 0.0,  0.0, 0.0, 6.3,10.5, 0.0, 0.0],
    [18.2,16.4, 0.0, 0.0,  0.0, 0.0, 6.3,10.5, 0.0, 0.0]) $

draw3d(
  enhanced3d = [z,x,y,z],
  isolines   = [x-y*z,x,y,z],
  line_width = 3,
  elevation_grid(m,1,1,100,100)) $
iso11

Another example of an elevation_grid surface. This time, we read a list of 8100 heights and transform it in a square matrix of order 90.

m2: read_list("terrain.txt")$

terr: apply(matrix, makelist(makelist(m2[j],j,k*90+1, k*90+90),k,0,89)) $

draw3d(
  enhanced3d = [z,x,y,z],
  isolines   = [z,x,y,z],
  line_width = 2,
  elevation_grid(terr,1,1,100,100)) $
iso12

The Mandelbrot set as an elevation grid. A kind contribution from Edward Montague.

MandelB(c,niter):=block([n:0,z:0],
  while ((abs(z) < 4) and (n < niter)) do (
      z:z*z+c,
      z:expand(z),
      n:n+1 ),
  n )$

compile(MandelB)$

nd:200$

x1:-2.5$
y1:-1.5$
x2:1.5$
y2:1.5$
dx:(x2-x1)/nd$
dy:(y2-y1)/nd$

declare(u,complex)$
declare(niter,integer)$
declare(i,integer)$
declare(j,integer)$
declare(m,integer)$
a1:zeromatrix(nd+1,nd+1)$

niter:80$

j:1$
for y:y1 thru y2 step dy do(
  i:1,
  for x:x1 thru x2 step dx do (
        c:x+%i*y,
        m:MandelB(c,niter),
        a1[i,j]:m,
        i:i+1 ),
  j:j+1 )$

load("draw") $
draw_renderer: 'vtk $

draw3d(
  enhanced3d = true,
  elevation_grid(a1*0.4, 1, 1, nd, nd)) $
mandelbrot

This is another example of a 3D fractal, a contribution by Tomio Arisaka. This example also shows how to integrate a user defined Lisp function stored in an external file, mandelbrot-julia.lisp, into a Maxima session. The Javascript code for the interactive visualization is based on the ThreeJS library.

The elevation-grid object is exported to the ply format by means of the terminal option.

load("./mandelbrot-julia.lisp") $

/* example of Julia set */
scale : 120.0 $
iteration : 40 $
[x0, y0] : [0.3090169943749475, -0.535233134659635] $
[x1, x2, y1, y2] : [-1.2, 1.2, -1.4, 1.4] $
width : abs (x2 - x1);
hight : abs (y2 - y1);
size_x : round (width * scale);
size_y : round (hight * scale);
ma1 : zeromatrix (size_y, size_x) $
?julia\-set1 (ma1, iteration, x0, y0, x1, x2, y1, y2);

draw3d(
  terminal   = ply,
  enhanced3d = true,
  palette    = [10, 17, 10],
  elevation_grid(ma1*float(1/(iteration*2*2)), x1, y1, width, hight)) $

The necessary Javascript code looks as follows:

<div id="ThreeJS"></div>

<script>
var container, scene, camera, renderer, controls, sky;

init();
animate();

function init() {

    scene = new THREE.Scene();
    var width  = screen.width;
        height = screen.height;

    camera = new THREE.PerspectiveCamera(50, width / height, 1, 20000);
    camera.position.set(2,2,2);
    scene.add(camera);

    renderer = new THREE.WebGLRenderer();
    renderer.setSize(width, height);

    container = document.getElementById( 'ThreeJS' );
    container.appendChild( renderer.domElement );

    controls = new THREE.TrackballControls(camera, renderer.domElement);
    controls.rotateSpeed = 5.0;

    var light = new THREE.PointLight(0xffffff);
    light.position.set(100,250,100);
    scene.add(light);

    var light = new THREE.PointLight(0xffffff);
    light.position.set(-200,-150,-300);
    scene.add(light);

    var skyBoxGeometry = new THREE.CubeGeometry( 10000, 10000, 10000 );
    var skyBoxMaterial = new THREE.MeshBasicMaterial({color: 0xccccff,
                                                      side: THREE.BackSide});
    sky = new THREE.Mesh( skyBoxGeometry, skyBoxMaterial );
    scene.add(sky);

    var loader = new THREE.PLYLoader();
    loader.load( 'maxima_out.ply',
                 function ( geometry ) {
		    geometry.computeFaceNormals();
		    var material = new THREE.MeshPhongMaterial( {
						color: 0xff5533, 
						specular: 0x111111,
						shininess: 200,
						side: THREE.DoubleSide } );
		    var mesh = new THREE.Mesh( geometry, material );
		    mesh.position.set( 0, 0, 0 );
		    mesh.rotation.set( 0, - Math.PI / 2, 0 );
		    mesh.castShadow = true;
		    mesh.receiveShadow = true;
		    scene.add( mesh ); } ); }

function animate() {
   requestAnimationFrame(animate);
   renderer.render(scene, camera);
   controls.update(); }

</script>

May take a little while to read the 3.7MB file. Please, be patient.


© 2011-2018, TecnoStats.