Skip to content

janm31415/meshscript

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

meshscript

Visualize 3d meshes via scripting in scheme.

Content

Introduction

Meshscript is a scriptable interface for visualizing and editing 3d meshes and point clouds.

Building

First of all, meshscript uses submodules, so don't forget to also call

 git submodule update --init

Next, run CMake to generate a solution file on Windows, a make file on Linux, or an XCode project on MacOs. You can build meshscript without building other external projects (as all necessary dependencies are delivered with the code).

The default multithreading approach uses std::thread. There is however the option to use multithreading via Intel's TBB library. This is an option in CMake: set the JTK_THREADING variable to tbb. You will have to make sure that you have the correct dll files and lib files to link with TBB. You can set the necessary variables TBB_INCLUDE_DIR and TBB_LIBRARIES via CMake.

If you build for a Mac M1 with ARM processor, then set the CMake variables JTK_TARGET and SKIWI_TARGET to arm. Furthermore if you get an error related to XCode's "new build system", then follow the solution on StackOverflow.

Basics

When you run meshscript you'll find yourself in a scheme REPL. I'm using my own skiwi compiler, which is a JIT compiler that translates scheme code to machine code and then executes the code. The scheme compiler is R4RS-compliant and almost R5RS-compliant.

Apart from regular scheme syntax, you can also call meshscript related functions. They are described in more detail in the glossary below. By typing

,external

in the scheme REPL you'll get an overview of all the meshscript related functionality. If you are looking for information on a function that starts with load, you can type

,external load

in the REPL to find all meshscript functions that start with load.

Let's start with an example. Suppose you want to visualize a PLY-file, then the following call

(load-mesh "D:/my_3d_files/rabbit.ply")

will load the mesh. The return value is an integer or id that represents this mesh. If you want to change any properties of the mesh, you'll need this id. Therefore it's probably better to load a mesh as

(define id (load-mesh "D:/my_3d_files/rabbit.ply"))

so that you can query properties of this mesh. For instance

(info id)

shows the number of vertices and triangles and other properties of the mesh. If you want to visualize the mesh, you'll need to call

(view-show!)

to open up the 3D view. The mesh will be displayed. You can hide the view again by closing it with the mouse or by calling

(view-hide!)

in the REPL. If you want to keep the view, but hide your 3D model, you can call

(hide! id)

In this case we've been writing our code directly in the REPL. You can also write your script in a separate file, and then call meshscript with this script file as argument. Meshscript will start, compile the script, run the script, and then start the REPL. All functions or defines from the script will be available in the REPL.

Examples

One bit render of 3D mesh to png

For this example I've used a free model of a Porsche 911 available via the link https://www.thingiverse.com/thing:2946486

; porsche 911 race car: https://www.thingiverse.com/thing:2946486

; load the mesh
(define id (load-mesh "D:/stl/porsche/complete.stl"))

; set view properties
(view-onebit-set! #t)
(view-size-set! 1920 1024)
(view-bg-set! 0 0 0)
(view-shadow-set! #t)

; set coordinate system for the view
(define cs '((0.593359 -0.220264 0.774216 11.876) (0.803842 0.212337 -0.555654 -2.86377) (-0.0420054 0.952049 0.303049 5.89276) (0 0 0 1)))
(view-cs-set! cs)

; show the view window
(view-show!)

; save the view as png image
(view-export "D:/stl/porsche/porsche.png")

Gyroid with marching cubes

(define gyroid_a 1)

(define gyroid 
            (lambda (x y z)
                    (/ (abs
                            (+ (* (sin x) (cos y)) (* (sin y) (cos z)) (* (sin z) (cos x))) )
                       gyroid_a ))) ; implicit function for the gyroid
       
(define bb '((-3.15 3.15) (-3.15 3.15) (-3.15 3.15))) ; bounding box
(define dim `(100 100 100)) ; dimensions

(define id (marching-cubes bb dim 1.0 gyroid)) ; making a mesh with marching cubes

(view-edges-set! #f) ; view properties
(view-show!) ; show the 3d view

68 landmarks for Basel face model

The Basel face model is a morphable model containing shape and color information of 200 subjects. The following script will automatically compute the vertex indices corresponding with the 68 facial landmark points as defined by https://ibug.doc.ic.ac.uk/resources/300-W/.

For this script you need to get the Basel face model (2019) from https://faces.dmi.unibas.ch/bfm/bfm2019.html and the dlib 68 facial landmarks predictor from https://github.com/davisking/dlib-models.

(view-edges-set! #f) ; view render properties
(view-show!) ; load the 3d view

; load the basel face model (https://faces.dmi.unibas.ch/bfm/bfm2019.html)
(define basel (load-morphable-model "D:/basel_face_model/model2019_fullHead.h5"))

; load the dlib 68 face landmarks predictor (https://github.com/davisking/dlib-models)
(define sp (load-shape-predictor "D:/neural_networks/shape_predictor_68_face_landmarks.dat"))

; set the view coordinate system so that the basel face model is aligned nicely
(view-cs-set! '((1 0 0 0.253426) (0 1 0 16.3451) (0 0 1 520.029) (0 0 0 1)))

; get the landmarks
(define landmarks (shape-predict sp (face-detect)))

; compute the corresponding vertex indices of the landmarks
(define indices '())
(let loop ((times 0))
  (if (eq? times (length landmarks))
      indices
      (begin
        (set! indices (append indices (list (view-index (list-ref (list-ref landmarks times) 0) (list-ref (list-ref landmarks times) 1)))))
        (loop (+ times 1))
      )
  )
)

; visualize the face detector and predictor
(view-face-detector-set! #t)
(shape-predictor-link-to-face-detector sp)

; show the indices in the repl
indices

If you're interested in the vertex indices computed automatically, this is the output of the meshscript repl:

ms> compiling primitives library...
ms> compiling string-to-symbol...
ms> compiling apply...
ms> compiling call/cc library...
ms> compiling r5rs library...
ms> compiling modules...
ms> compiling packages.scm...
ms> compiling basel_indices.scm...
(50554 49734 39678 57089 53700 34983 29867 29803 33294 18746 960 5881 24405 20551 10408 27676 14071 48784 56510 47558 41896 51179 21884 12601 18263 27215 26530 38214 38937 38126 37890 46209 42590 33495 27683 16914 44826 43055 55328 44026 31881 52594 14731 26033 24600 11988 7898 19180 31761 31013 30769 38414 9204 23032 28235 14011 2291 33531 41368 54142 45513 38161 58180 12118 1791 26503 33236 38161)

Welcome to meshscript
Type ,? for help.
ms>

Make funny faces

Video on YouTube

For this script you need to get the Basel face model (2019) from https://faces.dmi.unibas.ch/bfm/bfm2019.html.

(import 'srfi-27) ; random number generation

(define sigma-factor 5) ; set to 1 for normal faces, 5 for funny faces

; load the basel face model
(define id (load-morphable-model "D:/_Development/basel_face_model/model2019_fullHead.h5"))

; get the coefficient vector and color coefficient vector
(define coeff (list->vector (morphable-model-coefficients id)))
(define color-coeff (list->vector (morphable-model-color-coefficients id)))

; set a random value at index i in the coefficient vector
(define (set-random-coeff i)
  (let ((r (- (* 2 (random-real)) 1)))    
    (let ((c (* (morphable-model-sigma id i) sigma-factor r)))
      (vector-set! coeff i c)
    )
  )
)

; set a random value at index i in the color coefficient vector
(define (set-random-color-coeff i)
  (let ((r (- (* 2 (random-real)) 1)))    
    (let ((c (* (morphable-model-color-sigma id i) sigma-factor r)))
      (vector-set! color-coeff i c)
    )
  )
)

; loop over all coefficients and set random values
(define (random-face)
  (let loop ((times 0))
    (if (eq? times (morphable-model-coefficients-size id))
        #t
        (begin
          (set-random-coeff times)
          (set-random-color-coeff times)
          (loop (+ times 1))
        )
    )
  )
  (morphable-model-coefficients-set! id (vector->list coeff))
  (morphable-model-color-coefficients-set! id (vector->list color-coeff))
)

(view-edges-set! #f) ; turn of rendering of edges
(view-show!) ; show the 3d view

; render 1000 different arbitrary faces
(let loop ((times 0))
  (if (eq? times 1000)
      #t
      (begin
        (random-face)
        (loop (+ times 1))
      )
  )
)

Map vertex values to colors

This example uses three csv (comma separated value) files with data. These files have the following content:

vertices.csv :

-1, -1,  1
 1, -1,  1
 1,  1,  1
-1,  1,  1
-1, -1, -1
 1, -1, -1
 1,  1, -1
-1,  1, -1

triangles.csv :

0, 1, 2
0, 2, 3
7, 6, 5
7, 5, 4
1, 0, 4
1, 4, 5
2, 1, 5
2, 5, 6
3, 2, 6
3, 6, 7
0, 3, 7
0, 7, 4 

values.csv :

100
-80
76
-25
30
50
0
-60

The following script will load vertices.csv as vertex data, triangles.csv as triangle indices data, and values.csv as values assigned to the corresponding vertex. Next we plot the mesh, and map a color code to the vertex values.

(import 'csv) ; functionality for reading csv files

(define vertices (csv->numbers (read-csv "D:/colorplot/vertices.csv"))) ; load vertices
(define triangles (csv->numbers (read-csv "D:/colorplot/triangles.csv"))) ; load triangles

(define id (make-mesh vertices triangles)) ; make a mesh

(define values (csv->numbers (read-csv "D:/colorplot/values.csv"))) ; load values

(set! values (map car values)) ; unmap the list of lists to a simple list of values

(define (max-list xs)
  (if 
    (equal? (cdr xs) '()) 
            (car xs)
            (max (car xs) (max-list (cdr xs)))))

(define (min-list xs)
  (if 
    (equal? (cdr xs) '()) 
            (car xs)
            (min (car xs) (min-list (cdr xs)))))
            
      
(define minimum (min-list values)) ; compute the minimum value
(define maximum (max-list values)) ; compute the maximum value


(define (rescale x)
  ( / (- x minimum) (- maximum minimum) )
)      
       
       
(define rescaled (map rescale values)) ; rescale all values between 0 and 1
            
(define colors (jet rescaled)) ; map the values to colors

(vertexcolors-set! id colors) ; set the vertex colors

(view-edges-set! #f) ; don't render edges
(view-size-set! 1000 1000) ; increase the view

(view-show!) ; show the view

Compare facial scans

For this script you need to get the dlib 68 facial landmarks predictor from https://github.com/davisking/dlib-models. Furthermore this example uses two scans of myself taken at a different time. Replace jan1.obj and jan2.obj by two facial scans with texture that you have at your disposal.

; load dlib 68 face landmarks shape predictor
(define sp (load-shape-predictor "D:/neural_networks/shape_predictor_68_face_landmarks.dat"))

(define id1 (load-mesh "D:/scans/jan1.obj")) ; the first scan
(define id2 (load-mesh "D:/scans/jan2.obj")) ; the second scan

(cs-rotate! id1 -90 0 0) ; rotate the first scan so that the front faces the camera
(cs-rotate! id2 -90 0 0) ; rotate the second scan so that the front faces the camera

(hide! id1) ; don't render the first scan
(hide! id2) ; don't render the second scan

(view-show!) ; open the 3d view

; zoom out a bit to have the full scan visible
(view-cs-set! '((1 0 0 2.841) (0 1 0 49.722) (0 0 1 770.457) (0 0 0 1)))

(view-edges-set! #f); don't render edges

(show! id1) ; render the first scan

; compute the 68 facial landmarks for the first scan
(define landmarks1 (shape-predict sp (face-detect)))

; compute the corresponding 3d positions of the 68 facial landmarks for the first scan
(define positions1 '())
(let loop ((times 0))
  (if (eq? times (length landmarks1))
      positions1
      (begin
        (set! positions1 (append positions1 (list (view-position (list-ref (list-ref landmarks1 times) 0) (list-ref (list-ref landmarks1 times) 1)))))
        (loop (+ times 1))
      )
  )
)

(hide! id1) ; hide the first scan
(show! id2) ; render the second scan

; compute the 68 facial landmarks for the second scan
(define landmarks2 (shape-predict sp (face-detect)))

; compute the corresponding 3d positions of the 68 facial landmarks for the second scan
(define positions2 '())
(let loop ((times 0))
  (if (eq? times (length landmarks2))
      positions2
      (begin
        (set! positions2 (append positions2 (list (view-position (list-ref (list-ref landmarks2 times) 0) (list-ref (list-ref landmarks2 times) 1)))))
        (loop (+ times 1))
      )
  )
)

; n-point registration of the 68 landmark points of the two scans
(define transformation_npoint (npoint positions1 positions2))
(cs-premultiply! id1 transformation_npoint)

; iterative closest point between the two scans
(define transformation_icp (icp id1 id2 5))
(cs-premultiply! id1 transformation_icp)

(show! id1) ; render the first scan
(hide! id2) ; hide the second scan

(define dm (distance-map id1 id2 #f)) ; compute the distance map between the two scans     

(define (clamp x minimum maximum) ; clamps a value x to the interval [minimum;maximum]
  (if (< x minimum)
     minimum
     (if (> x maximum)
         maximum
         x
     )))
     
(define maximum-distance 10) ; 10 mm

(define (rescale x)
  ( / (clamp x 0 maximum-distance) maximum-distance )
)      

(define rescaled (map rescale dm)) ; rescale all values of the distance map to [0;1]            
(define colors (jet rescaled)) ; map the values to colors

(vertexcolors-set! id1 colors) ; set the vertex colors on the first scan

Convert Obj to Ply

For this example I've downloaded an obj file with texture from https://free3d.com/nl/3d-model/skull-v3--785914.html.

(define id (load-mesh "D:/stl/obj/skull/12140_Skull_v3_L2.obj")) ; load an obj with texture

(view-show!) ; show the 3d view

(view-edges-set! #f) ; don't render the edges

(define vertexclrs (mesh-texture->vertexcolors id)) ; get the colors per vertex from the texture

(vertexcolors-set! id vertexclrs) ; set vertexcolors for this mesh

(save id "D:/stl/obj/skull/skull.ply") ; save as ply with vertex colors

Pointcloud to mesh with Poisson surface reconstruction

(define xsteps 100)
(define ysteps 100)
(define pi 3.1415926535)

(define rad 15)

(define (cylinder1 x y) ; parametric representation of the first cylinder
  (list (* rad (sin x)) (* rad (cos x)) (- y (/ ysteps 2)))
)

(define (cylinder2 x y) ; parametric representation of the second cylinder
  (list (* rad (sin x)) (- y (/ ysteps 2)) (* rad (cos x)))
)

(define (inside-cylinder1 pos) ; returns #t if pos is inside the first cylinder
  (let ((x (list-ref pos 0)) (y (list-ref pos 1)) (z (list-ref pos 2)))
    (let ((r (+ (* x x) (* y y))))
      (if (< r (* rad rad))
          #t
          #f
      )
    )
  )
)

(define (inside-cylinder2 pos) ; returns #t if pos is inside the second cylinder
  (let ((x (list-ref pos 0)) (y (list-ref pos 1)) (z (list-ref pos 2)))
    (let ((r (+ (* x x) (* z z))))
      (if (< r (* rad rad))
          #t
          #f
      )
    )
  )
)

(define vertices '())

(let loop1 ((x 0)) ; loop over the first parameter
  (if (eq? x xsteps)
      vertices
      (begin
        (let loop2 ((y 0)) ; loop over the second parameter
          (if (eq? y ysteps)
              vertices
              (begin
                (let* ((a (/ (* x 2.0 pi) xsteps)) (pos1 (cylinder1 a y)) (pos2 (cylinder2 a y)))
                  (if (not (inside-cylinder2 pos1))  
                    (set! vertices (append vertices (list pos1)))
                  )
                  (if (not (inside-cylinder1 pos2))  
                    (set! vertices (append vertices (list pos2)))
                  )
                )
                (loop2 (+ y 1))      
              )))      
        (loop1 (+ x 1))
      )))

(define id (make-pointcloud vertices)) ; make a pointcloud from the vertices

(pointcloud-normals-estimate! id 10) ; estimate normals for the pointcloud

(define id2 (poisson id 5)) ; poisson surface reconstruction

(view-show!) ; show the 3d view

Parametric representation of Klein's bottle

(define pi 3.1415926535897)

(define (KleinX u v)
  (if (< v pi)         
      (* (- 2.5 (* 1.5 (cos v))) (cos u))
      (if (< v (* 2.0 pi)) 
          (* (- 2.5 (* 1.5 (cos v))) (cos u))
          (if (< v (* 3.0 pi)) 
              (- (* (+ 2.0 (cos u)) (cos v)) 2.0)
              (- (* 2.0 (cos v)) 2.0 (cos u))
          ))))

(define (KleinY u v)
  (if (< v pi)         
      (* (- 2.5 (* 1.5 (cos v))) (sin u))
  
      (if (< v (* 2.0 pi)) 
          (* (- 2.5 (* 1.5 (cos v))) (sin u))
          (if (< v (* 3.0 pi)) 
              (sin u)
              (sin u)
          ))))

(define (KleinZ u v)
  (if (< v pi)         
      (* -2.5 (sin v))
      (if (< v (* 2.0 pi)) 
          (- (* 3.0 v)(* 3.0 pi))
          (if (< v (* 3.0 pi)) 
              (+ (* (+ 2.0 (cos u))(sin v)) (* 3.0 pi))
              (- (* 12.0 pi) (* 3.0 v))
          ))))

(define (KleinBottle u v) ; parametric representation of the Klein bottle
  (list (KleinX u v) (KleinY u v) (KleinZ u v))
)

; the domain as a list: min_u, max_u, step_u, min_v, max_v, step_v
(define domain (list 0.0 (* 2.0 pi) (/ pi 72.0) 0.0 (* 4.0 pi) (/ pi 72.0)))

; generate a mesh from the parametric representation
(define id (parametric KleinBottle domain))

; set a matcap for nice rendering
(define matcap (load-image "D:/my_matcaps/ceramic_lightbulb.png"))
(matcap-set! id matcap)

(view-textured-set! #f) ; don't render the uv domain / texture
(view-edges-set! #f) ; don't render edges

(view-show!) ; show the 3d view    

Compressing STL files by a factor 5

Load any file, and save it to TRC file format, see trico.

(define id (load-mesh "D:/stl/lucy.stl"))
(save id "D:/compressed_files/lucy.trc"))

The following table comes from trico, and shows the compression ratios of the TRC file format. Note that TRC is much faster in compression and decompression than the standard zip algorithm (zdeflate / zinflate). TRC is lossless. The files were taken from the Stanford 3D Scanning Repository.

Model Triangles Vertices Binary STL Binary PLY Binary PLY zipped Trico Compression ratio vs STL Compression ratio vs PLY Compression ratio vs PLY zipped
Stanford Bunny 69451 35947 3392 KB 1291 KB 522 KB 571 KB 5.94 2.26 0.91
Happy Buddha 1087716 543652 53112 KB 20180 KB 10135 KB 9146 KB 5.81 2.21 1.11
Dragon 871414 437645 42550 KB 16192 KB 8129 KB 7274 KB 5.85 2.23 1.12
Armadillo 345944 172974 16892 KB 6757 KB 3794 KB 4059 KB 4.16 1.66 0.93
Lucy 28055742 14027872 1369910 KB 520566 KB 296014 kB 230609 KB 5.94 2.26 1.28
Asian Dragon 7219045 3609600 352493 KB 133949 KB 68541 KB 49896 KB 7.06 2.68 1.37
Vellum manuscript* 4305818 2155617 210246 KB 86241 KB 42783 KB 23465 KB 8.96 3.68 1.82
Thai Statue 10000000 4999996 488282 KB 185548 KB 104048 KB 86165 KB 5.67 2.15 1.21

* the PLY and Trico file contain vertex colors, the STL file does not.

CSG modelling

(define length-square
  (lambda (x y z)
    (+ (* x x) (* y y) (* z z))
  ))

(define sphere-radius-square 1)

(define sphere ; signed distance function for a sphere
  (lambda (x y z)
          (- (length-square x y z) sphere-radius-square)))
             
   
(define cube-radius 0.8)
 
(define cube ; signed distance function for a cube
  (lambda (x y z)
     (let ((xx (- (abs x) cube-radius)) (yy (- (abs y) cube-radius)) (zz (- (abs z) cube-radius)))
       (+ (sqrt (length-square (max xx 0.0) (max yy 0.0) (max zz 0.0))) (min (max xx yy zz) 0.0))
     )))
       
                           
(define bb '((-1.2 1.2) (-1.2 1.2) (-1.2 1.2))) ; the bounding box for marching cubes         
(define dim `(100 100 100)) ; the dimensions for marching cubes

(define sph (marching-cubes bb dim 0.0 sphere)) ; make a sphere with marching cubes

(define cub (marching-cubes bb dim 0.0 cube)) ; make a cube with marching cubes

(define res (difference (list cub sph))) ; compute the difference of the cube and the sphere
(matcap-set! res 3) ; choose matcap nr 3 for rendering

(hide! sph) ; hide the sphere
(hide! cub) ; hide the cube

(view-show!)

Racing car with spoiler

I've taken this example from this OpenSCAD tutorial.

(define d1 30)
(define d2 20)
(define d3 20)
(define d4 10)
(define d5 20)

(define w1 15)
(define w2 45)
(define w3 25)

(define l1 d1)
(define l2 (+ d1 d2))
(define l3 (+ d1 d2 d3))
(define l4 (+ d1 d2 d3 d4))
(define l5 (+ d1 d2 d3 d4 d5))

(define p0 (list 0 (/ w1 2)))
(define p1 (list l1 (/ w1 2)))
(define p2 (list l2 (/ w2 2)))
(define p3 (list l3 (/ w2 2)))
(define p4 (list l4 (/ w3 2)))
(define p5 (list l5 (/ w3 2)))

(define p6 (list l5 (/ w3 -2)))
(define p7 (list l4 (/ w3 -2)))
(define p8 (list l3 (/ w2 -2)))
(define p9 (list l2 (/ w2 -2)))
(define p10 (list l1 (/ w1 -2)))
(define p11 (list 0 (/ w1 -2)))

(define h 14)

(define points (list p0 p1 p2 p3 p4 p5 p6 p7 p8 p9 p10 p11))

(define body (extrude points h))

(define canopy (sphere (/ w2 4) 5))
(scale! canopy ( / (/ (+ d2 d3 d4) 2) (/ w2 4)) 1 1)
(cs-translate! canopy (+ d1 d2 (/ d3 2)) 0 h)

(define axis-length 40)
(define front-axis (cylinder 1 axis-length 128))
(cs-rotate! front-axis 90 0 0)
(define back-axis (duplicate front-axis))
(cs-translate! front-axis (/ d1 2) (/ axis-length 2) (/ h 2))
(cs-translate! back-axis (+ d1 d2 d3 d4 (/ d5 2)) (/ axis-length 2) (/ h 2))

(define front-wheel-width 12)
(define back-wheel-width 15)
(define wheel-radius 10)
(define left-front-wheel (cylinder wheel-radius front-wheel-width 128))
(define right-front-wheel (duplicate left-front-wheel))
(cs-rotate! left-front-wheel 90 0 0)
(cs-rotate! right-front-wheel -90 0 0)

(cs-translate! left-front-wheel (/ d1 2) -10 (/ h 2))
(cs-translate! right-front-wheel (/ d1 2) 10 (/ h 2))

(define left-back-wheel (cylinder wheel-radius back-wheel-width 128))
(define right-back-wheel (duplicate left-back-wheel))
(cs-rotate! left-back-wheel 90 0 0)
(cs-rotate! right-back-wheel -90 0 0)

(cs-translate! left-back-wheel (+ d1 d2 d3 d4 (/ d5 2)) -15 (/ h 2))
(cs-translate! right-back-wheel (+ d1 d2 d3 d4 (/ d5 2)) 15 (/ h 2))

(define (naca-half-thickness x t)
  (* 5 t (+ (* 0.2969 (sqrt x)) (* -0.1260 x) (* -0.3516 (expt x 2)) (* 0.2843 (expt x 3)) (* -0.1015 (expt x 4) )))
)

(define (naca-top-coordinates t n)
  (define coords '())
  (let loop ((x 0))
    (if (> x 1)
        coords
        (begin
          (set! coords (append coords (list (list x (naca-half-thickness x t)))))
          (loop (+ x (/ 1 n)))        
        )))
)

(define (naca-bottom-coordinates t n)
  (define coords '())
  (let loop ((x 1))
    (if (< x 0)
        coords
        (begin
          (set! coords (append coords (list (list x (- 0 (naca-half-thickness x t))))))
          (loop (- x (/ 1 n)))        
        )))
)

(define (naca-coordinates t n)
  (append (naca-top-coordinates t n) (naca-bottom-coordinates t n))
)

(define wing1 (extrude (naca-coordinates 0.12 300) 15))
(scale! wing1 20 20 1)
(define wing2 (duplicate wing1))
(cs-translate! wing1 (+ d1 d2 d3 d4 (/ d5 2)) 10 10)
(cs-translate! wing2 (+ d1 d2 d3 d4 (/ d5 2)) -10 10)

(define wing3 (extrude (naca-coordinates 0.12 300) 60))
(scale! wing3 20 20 1)
(cs-rotate! wing3 90 0 0)
(cs-translate! wing3 (+ d1 d2 d3 d4 (/ d5 2)) 30 25)

(matcap-set! body 3)
(matcap-set! left-front-wheel 3)
(matcap-set! right-front-wheel 3)
(matcap-set! left-back-wheel 3)
(matcap-set! right-back-wheel 3)
(matcap-set! canopy 3)
(matcap-set! wing1 3)
(matcap-set! wing2 3)
(matcap-set! wing3 3)
(matcap-set! front-axis 3)
(matcap-set! back-axis 3)

(view-shadow-set! #t)

(view-show!)

Brandy glass

(define glass-shape
  (lambda (x)
    (let ((a -2.9) (b 1) (c 1) (d 0.3))
      (+ (* a (expt x 3)) (* b (expt x 2)) (* c x) d)
    )
  )
)

(define (glass-coordinates n)
  (define coords '())
  (let loop ((x 0))
    (if (> x 1)
        coords
        (begin
          (set! coords (append coords (list (list x (glass-shape x)))))
          (loop (+ x (/ 1 n)))        
        )))
)


(define pts-list (glass-coordinates 100))

(define id (revolve pts-list 100 #f))

(define im (load-image "D:/matcaps/metal_shiny.png"))
(matcap-set! id im)

(view-show!)

Torus

(define (circle cx cy r n)    
  (define coords '())
  (let loop ((i 0))
    (if (= i n)
        coords
        (begin
          (let* ((ang (/ (* i 2.0 3.1415926535) n)) 
                 (x (+ (* r (cos ang)) cx)) 
                 (y (+ (* r (sin ang)) cy)))
            (set! coords (append coords (list (list x y))))
          )
          (loop (+ i 1))
        )))
)

(define r1 1.5)
(define R1 7.5)

(define circle-pts-1 (circle 0 R1 r1 128))

(define id1 (revolve circle-pts-1 100 #t))

(define r2 2)
(define R2 3)

(define circle-pts-2 (circle 0 R2 r2 8))

(define id2 (revolve circle-pts-2 10 #t))

(view-show!)

Make mesh from boundary

(define (subdivide-point-list lst) ; linear subdivision for a list of 3d points ((x1 y1 z1) (x2 y2 z2) ...)
  (define odd '())
  (define le (length lst))
  (define combine (lambda (f) (lambda (x y) (if (null? x) (quote ()) (f (list (car x) (car y)) ((combine f) (cdr x) (cdr y)))))))
  (let loop ((times 0))
    (if (eq? times le)
        odd
        (begin
          (let ((p0 (list-ref lst times)) (p1 (list-ref lst (modulo (+ times 1) le))))
            (let ((x0 (list-ref p0 0)) (y0 (list-ref p0 1)) (z0 (list-ref p0 2))
                  (x1 (list-ref p1 0)) (y1 (list-ref p1 1)) (z1 (list-ref p1 2)))
              (let ((new-point (list (/ (+ x0 x1) 2.0) (/ (+ y0 y1) 2.0) (/ (+ z0 z1) 2.0))))
                (set! odd (append odd (list new-point)))
              )
            )
          )
          (loop (+ times 1))
        )
    )
  )
  ((combine append) lst odd)  
)


(define helix1 '())

(let loop ((times 0)) ; we make the inner loop for our helix
  (if (eq? times 100)
      helix
      (begin
        (set! helix1 (append helix1 (list (list (cos (/ times 10)) (sin (/ times 10)) (* times 0.02)))))
        (loop (+ times 1))
      )
  )
)

(define helix2 '())

(let loop ((times 100)) ; we make the outer loop for our helix
  (if (eq? times 0)
      helix
      (begin
        (set! helix2 (append helix2 (list (list (* 3 (cos (/ times 10))) (* 3 (sin (/ times 10))) (* times 0.02)))))
        (loop (- times 1))
      )
  )
)

(define helix-list (append helix1 helix2)) ; combine the inner and outer loop of the helix
(set! helix-list (subdivide-point-list helix-list)) ; linear subdivision
(set! helix-list (subdivide-point-list helix-list)) ; linear subdivision


(define id (make-minimal helix-list 8 1000)) ; make a mesh: we create 8 rings of triangles that are faired 1000 times.

(view-show!); show the view

Glossary

Below follows a dump of all the meshscript methods so far.

NAME
	cs
DESCRIPTION
	(cs id) returns the coordinate system for the object
	with tag `id`.

NAME
	cs-apply!
DESCRIPTION
	(cs-apply! id) transforms the vertices of object with
	tag `id` by its coordinate system, and sets its coordinate
	system to the world.

NAME
	cs-rotate!
DESCRIPTION
	(cs-rotate! id x y z) rotates the object with tag `id`
	by `x` degrees over the x-axis, by `y` degrees over
	the y-axis, and by `z` degrees over the z-axis.

NAME
	cs-set!
DESCRIPTION
	(cs-set! id cs) sets a new coordinate system for the
	object with tag `id`. The coordinate system `cs` can
	be given as a vector of size 16 in column major format
	or as a list of lists in row major format.

NAME
	cs-translate!
DESCRIPTION
	(cs-translate! id x y z) translates the object with
	tag `id` by vector (x y z).

NAME
	cs-premultiply!
DESCRIPTION
	(cs-premultiply! id cs) premultiplies the coordinate
	system of the object with tag `id` by the input coordinate
	system. The coordinate system `cs` can be given as
	a vector of size 16 in column major format or as a
	list of lists in row major format.

NAME
	cube
DESCRIPTION
	(cube w h d) makes a cube with dimensions `w` x `h`
	x `d`.

NAME
	cylinder
DESCRIPTION
	(cylinder r h n) makes a cylinder with radius `r` and
	height `h`. The cylinder's side is discretized by 'n'
	ribs.

NAME
	diagnose
DESCRIPTION
	(diagnose id) diagnoses the self intersections of the
	mesh with tag `id`.

NAME
	difference
DESCRIPTION
	(difference (id1 id2 ...) ) computes the difference
	of the meshes or morphable models with tag `id1`, tag
	`id2`, ... in the list (`id` `id2` ...) and returns
	the id of the result.

NAME
	distance-map
DESCRIPTION
	(distance-map id1 id2 bool-signed) returns a list with
	values that represent the distance between objects
	with tag `id1` and `id2`. For each vertex of object
	`id1` there is exactly one distance in the list. The
	distance can be signed or unsigned, depending on the
	boolean value that is given to `bool-signed`.

NAME
	duplicate
DESCRIPTION
	(duplicate id) makes a duplicate of the object with
	tag `id`.

NAME
	ear-right-detect
DESCRIPTION
	(ear-right-detect) runs the ear detector on the current
	view and returns a list of lists of the form ((x y
	w h) ...) where (x y w h) represents a rectangle containing
	the right ear starting in corner (x,y) and with sizes
	(w,h).

NAME
	ear-left-detect
DESCRIPTION
	(ear-left-detect) runs the ear detector on the current
	view and returns a list of lists of the form ((x y
	w h) ...) where (x y w h) represents a rectangle containing
	the left ear starting in corner (x,y) and with sizes
	(w,h).

NAME
	extrude
DESCRIPTION
	(extrude lst h) extrudes a list of 2d points of the
	form ((x0 y0) (x1 y1) ...) with length `h` and returns
	the id of the resulting mesh.

NAME
	face-detect
DESCRIPTION
	(face-detect) runs the face detector on the current
	view and returns a list of lists of the form ((x y
	w h) ...) where (x y w h) represents a rectangle containing
	the face starting in corner (x,y) and with sizes (w,h).

NAME
	fill-hole
DESCRIPTION
	(fill-hole id hole) fills the list of vertex indices
	`hole` for the object with tag `id` and returns the
	result as a new mesh.

NAME
	fill-hole-minimal
DESCRIPTION
	(fill-hole-minimal id hole rings iterations) fills the
	list of vertex indices `hole` for the object with tag
	`id` as a minimal surface, and returns the result as
	a new mesh. The algorithm will create `rings` number
	of rings of triangles and this mesh is faired `iterations`
	times.

NAME
	force-redraw
DESCRIPTION
	(force-redraw) redraws the canvas. This is useful if
	you want to use view-position in your script, as view-position
	uses the data of the last render of the view.

NAME
	hide!
DESCRIPTION
	(hide! id) makes the object with tag `id` invisible.

NAME
	holes
DESCRIPTION
	(holes id) returns a list of lists containing the vertex
	indices that form a hole for the object with tag `id`.

NAME
	icosahedron
DESCRIPTION
	(icosahedron r) makes a icosahedron with radius `r`.

NAME
	icp
DESCRIPTION
	(icp id1 id2 inlier-distance) returns the result of
	the iterative closest point algorithm between objects
	with tag `id1` and `id2`. This result is always a 4x4
	transformation matrix. The iterative closest point
	algorithm will only use correspondences between `id1`
	and `id2` if their distance is smaller than `inlier-distance`.

NAME
	info
DESCRIPTION
	(info id) prints info on the object with tag `id`.

NAME
	intersection
DESCRIPTION
	(intersection (id1 id2 ...)) computes the intersection
	of the meshes or morphable models with tag `id1`, tag
	`id2`, ... in the list (`id` `id2` ...) and returns
	the id of the result.

NAME
	jet
DESCRIPTION
	(jet lst) takes a list `lst` of values between 0 and
	1 and returns a list of lists with (r g b) values.

NAME
	lscm
DESCRIPTION
	(lscm id) takes a mesh with tag `id` as input, and returns
	a new mesh with uv texture map, computed with the least
	squares conformal mapping method.

NAME
	load-mesh
DESCRIPTION
	(load-mesh "stlfile.stl") loads the STL file and returns
	an id. Similarly (load-mesh "objfile.obj") loads an
	OBJ file and returns the id. Other input mesh formats
	that are implemented are PLY, OFF, and TRC.

NAME
	load-morphable-model
DESCRIPTION
	(load-morphable-model "model2019_fullHead.h5") loads
	morphable models following the hdf5 file format as
	used by the Basel Face Model project (https://faces.dmi.unibas.ch/bfm/bfm2019.html).
	The other file format that can be read is meshscripts
	own binary morphable model file format with extension
	SSM.

NAME
	load-pointcloud
DESCRIPTION
	(load-pointcloud "pointcloud.ply") loads the PLY file
	as point cloud and returns an id. Other file formats
	allowed are OBJ, TRC, PTS, or XYZ.

NAME
	load-shape-predictor
DESCRIPTION
	(load-shape-predictor "filename") initializes the shape
	predictor with the data given by "filename" and returns
	the id. This is the dlib shape predictor (http://dlib.net).
	The 68 points facial landmarks predictor data can be
	downloaded from https://github.com/davisking/dlib-models

NAME
	load-image
DESCRIPTION
	(load-image "image.png") loads the PNG file as image
	and returns an id. Other well known image formats can
	also be loaded.

NAME
	make-mesh
DESCRIPTION
	(make-mesh vertices triangles) creates the mesh with
	given `vertices` and `triangles`, and returns the id
	of the created object. `vertices` should be a list
	of lists of the form ((x y z) (x y z) ...) with x,y,z
	floating point values, and `triangles` should be a
	list of lists of the form ((a b c) (d e f) ...) with
	a,b... fixnums referring to the vertex indices.

NAME
	make-minimal
DESCRIPTION
	(make-minimal vertices rings iterations) creates a mesh
	with minimual surface area surrounded by the given
	`vertices`, and returns the id of the created object.
	`vertices` should be a list of lists of the form ((x
	y z) (x y z) ...) with x,y,z floating point values.
	. The algorithm will initially create `rings` number
	of rings of triangles and this mesh is faired `iterations`
	times.

NAME
	make-pointcloud
DESCRIPTION
	(make-pointcloud vertices) creates the pointcloud with
	given `vertices`, and returns the id of the created
	object. `vertices` should be a list of lists of the
	form ((x y z) (x y z) ...) with x,y,z floating point
	values.

NAME
	marching-cubes
DESCRIPTION
	(marching-cubes bb dim isovalue fun) with `bb` representing
	the bounding box of the form ((min_x max_x) (min_y
	max_y) (min_z max_z)), `dim` representing the dimensions
	of the form (width height depth), `isovalue` a flonum
	representing the signed distance requested, and `fun`
	representing the distance functions as a lambda function
	accepting (x y z) values and returning a distance.

NAME
	matcap-set!
DESCRIPTION
	(matcap-set! id matcap-id) changes the matcap of the
	object with tag `id`. The matcap is given by its id
	`matcap-id`. There are 4 hard-coded matcaps with ids
	0, 1, 2, 3. You can also provide an image id as `matcap-id`,
	see load-image.

NAME
	mesh->pointcloud
DESCRIPTION
	(mesh->pointcloud id) converts the mesh with tag `id`
	to a pointcloud.

NAME
	mesh-texture->image
DESCRIPTION
	(mesh-texture->image id) converts the texture of the
	mesh with tag `id` to an image.

NAME
	mesh-texture->vertexcolors
DESCRIPTION
	(mesh-texture->vertexcolors id) will return a list of
	lists of the form ((r g b) (r g b) ... ). Each vertex
	of the object with tag `id` has a corresponding (r
	g b) value. This (r g b) value is obtained from the
	texture of `id`, if available.

NAME
	mesh-texture-set!
DESCRIPTION
	(mesh-texture-set! id tex) sets the image with tag `tex`
	as texture for the mesh with tag `id`,

NAME
	morphable-model-coefficients-size
DESCRIPTION
	(morphable-model-coefficients-size mm_id) returns the
	number of coefficients for the morphable model with
	tag `mm_id`.

NAME
	morphable-model-shape-size
DESCRIPTION
	(morphable-model-shape_size mm_id) returns the shape
	size for the morphable model with tag `mm_id`. This
	is equal to the number of rows in the U matrix, where
	a shape S is represented as S = mu + U*c, with mu the
	average shape, and c the coefficients vector.

NAME
	morphable-model-sigma
DESCRIPTION
	(morphable-model-sigma mm_id idx) returns sigma for
	the morphable model with tag `mm_id` at coefficient
	index `idx`.

NAME
	morphable-model-coefficients
DESCRIPTION
	(morphable-model-coefficients mm_id) returns the list
	of coefficients for the morphable model with tag `mm_id`.

NAME
	morphable-model-basic-shape-coefficients
DESCRIPTION
	(morphable-model-basic-shape-coefficients mm_id idx)
	returns the list of coefficients of the `idx`-th shape
	that was used to generate this morphable model. Not
	all morphable models have this data. For instance the
	Basel shape model does not contain this data.

NAME
	morphable-model-coefficients-set!
DESCRIPTION
	(morphable-model-coefficients-set! mm_id coeff) sets
	the list of coefficients for the morphable model with
	tag `mm_id`. Here `coeff` is a list of coefficient
	values, and its size should equal (morphable-model-coefficients-size
	mm_id).

NAME
	morphable-model->mesh
DESCRIPTION
	(morphable-model->mesh mm_id) converts the morphable
	model with tag `mm_id` to a mesh and returns the new
	id.

NAME
	morphable-model-color-coefficients-size
DESCRIPTION
	(morphable-model-color-coefficients-size mm_id) returns
	the number of color coefficients for the morphable
	model with tag `mm_id`.

NAME
	morphable-model-color-shape-size
DESCRIPTION
	(morphable-model-color-shape_size mm_id) returns the
	shape size for the color part of the morphable model
	with tag `mm_id`. This is equal to the number of rows
	in the U_color matrix, where a the shape colors S_color
	are represented as S_color = mu_color + U_color*c,
	with mu_color the average shape colors, and c the color
	coefficients vector.

NAME
	morphable-model-color-sigma
DESCRIPTION
	(morphable-model-color-sigma mm_id idx) returns sigma
	for the colors of the morphable model with tag `mm_id`
	at color coefficient index `idx`.

NAME
	morphable-model-color-coefficients
DESCRIPTION
	(morphable-model-color-coefficients mm_id) returns the
	list of color coefficients for the morphable model
	with tag `mm_id`.

NAME
	morphable-model-color-basic-shape-coefficients
DESCRIPTION
	(morphable-model-color-basic-shape-coefficients mm_id
	idx) returns the list of color coefficients of the
	`idx`-th color shape that was used to generate this
	morphable model. Not all morphable models have this
	data. For instance the Basel shape model does not contain
	this data.

NAME
	morphable-model-color-coefficients-set!
DESCRIPTION
	(morphable-model-color-coefficients-set! mm_id coeff)
	sets the list of color coefficients for the morphable
	model with tag `mm_id`. Here `coeff` is a list of color
	coefficient values, and its size should equal (morphable-model-color-coefficients-size
	mm_id).

NAME
	morphable-model-fit-indices!
DESCRIPTION
	(morphable-model-fit-indices! mm_id indices positions)

NAME
	morphable-model-fit!
DESCRIPTION
	(morphable-model-fit! mm_id mesh_id)

NAME
	npoint
DESCRIPTION
	(npoint from to) computes the npoint-registration of
	the set of 3d points in `from` to the set of 3d points
	in `to`. The result is a 4x4 transformation matrix.
	Here `from` and `to` are lists of lists of the form
	((x y z) (x y z) ...) and `from` and `to` should have
	the same amount of 3d points.

NAME
	parametric
DESCRIPTION
	(parametric fun domain) returns the id of a new mesh.
	The mesh is created from a lambda function `fun`, where
	`fun` accepts two floating input values (u v) and returns
	a list (x y z). The input variable `domain` is a list
	of the form (min_u max_u step_u min_v max_v step_v)
	describing the uv parameter domain.

NAME
	pointcloud-normals-estimate!
DESCRIPTION
	(pointcloud-normals-estimate! id k) creates vertex normals
	for the pointcloud with tag `id` by taking the `k`
	nearest neighbours of each vertex, fit a least squares
	plane through these points, and use the normal of this
	plane as estimate.

NAME
	poisson
DESCRIPTION
	(poisson pc_id depth) applies Poisson surface reconstruction
	to the pointcloud with tag `pc_id`. This is the screened
	Poisson surface reconstruction algorithm by M. Kazhdan
	and H. Hoppe. You have to provide the parameter `depth`
	which represents the depth of the octree during Poisson
	surface reconstruction.

NAME
	resolve-intersections
DESCRIPTION
	(resolve-intersections id) resolves all self intersections
	of the mesh with tag `id`.

NAME
	revolve
DESCRIPTION
	(revolve lst n closed?) revolves a list of 2d points
	of the form ((x0 y0) (x1 y1) ...). The second parameter
	`n` indicates the number of revolve steps. The third
	parameter `closed?` indicates whether the input list
	is closed or not. Its value should be #t or #f. The
	id of the resulting mesh is returned.

NAME
	save
DESCRIPTION
	(save id "file.ext") writes the object with tag `id`
	to file. The filetype is determined by the extension
	that is given. You can export meshes to STL, PLY, OBJ,
	OFF, or TRC, pointclouds to PLY, OBJ, PTS, XYZ, or
	TRC, morphable models to SSM.

NAME
	scale
DESCRIPTION
	(scale id sx sy sz) scales the vertices of the object
	with tag `id` by vector (`sx`, `sy`, `sz). The resulting
	mesh's id is returned.

NAME
	scale!
DESCRIPTION
	(scale! id sx sy sz) scales the vertices of the object
	with tag `id` by vector (`sx`, `sy`, `sz).

NAME
	shape-predict
DESCRIPTION
	(shape-predict sp_id (x y w h)) or (shape-predict sp_id
	((x y w h) ...)) runs the shape predictor with tag
	`sp_id` on the region defined by (x y w h) or on the
	regions defined by ((x y w h) ...) in the current view
	and returns the coordinates of the landmarks as a list
	of lists. The predictor should be initialized with
	load-shape-predictor.

NAME
	shape-predictor-horizontal-flip-set!
DESCRIPTION
	(shape-predictor-horizontal-flip-set! id #t/#f) toggles
	horizontal flipping of the shape predictor given by
	tag `id`.

NAME
	shape-predictor-link-to-ear-left-detector
DESCRIPTION
	(shape-predictor-link-to-ear-left-detector id) links
	the shape predictor given by tag `id` to the ear left
	detector. The result of this operation is that the
	shape predictor is rendered automatically when the
	left ear detector's automatic rendering is on. You
	can turn on/off automatic rendering of the left ear
	detector with the command (view-ear-left-detector-set!
	#t/#f).

NAME
	shape-predictor-link-to-ear-right-detector
DESCRIPTION
	(shape-predictor-link-to-ear-right-detector id) links
	the shape predictor given by tag `id` to the ear right
	detector. The result of this operation is that the
	shape predictor is rendered automatically when the
	right ear detector's automatic rendering is on. You
	can turn on/off automatic rendering of the right ear
	detector with the command (view-ear-right-detector-set!
	#t/#f).

NAME
	shape-predictor-link-to-face-detector
DESCRIPTION
	(shape-predictor-link-to-face-detector id) links the
	shape predictor given by tag `id` to the face detector.
	The result of this operation is that the shape predictor
	is rendered automatically when the face detector's
	automatic rendering is on. You can turn on/off automatic
	rendering of the face detector with the command (view-face-detector-set!
	#t/#f).

NAME
	shape-predictor-unlink
DESCRIPTION
	(shape-predictor-unlink id) unlinks the shape predictor
	given by tag `id`, see shape-predictor-link-to-face-detector,
	shape-predictor-link-to-ear-right-detector, or shape-predictor-link-to-ear-left-detector.

NAME
	show!
DESCRIPTION
	(show! id) makes the object with tag `id` visible.

NAME
	smooth
DESCRIPTION
	(smooth id iterations lambda mu) smooths the mesh with
	tag `id` `iterations` times with Taubin smoothing parameters
	`lambda` and `mu`. The resulting mesh's id is returned.
	For Laplacian smoothing, choose `lambda` equal to 1
	and `mu` equal to 0. General rule for Taubin smoothing:
	let -`mu` > `lambda` > 0.

NAME
	smooth!
DESCRIPTION
	(smooth! id iterations lambda mu) smooths the mesh with
	tag `id` `iterations` times with Taubin smoothing parameters
	`lambda` and `mu`. For Laplacian smoothing, choose
	`lambda` equal to 1 and `mu` equal to 0. General rule
	for Taubin smoothing: let -`mu` > `lambda` > 0.

NAME
	sphere
DESCRIPTION
	(sphere r sub) makes a sphere with radius `r`. The sphere
	starts from a regular icosahedron, and is then subdivided
	`sub` times.

NAME
	subdivide
DESCRIPTION
	(subdivide id nr) subdivides the mesh with tag `id`
	`nr` times. The resulting mesh's id is returned. 

NAME
	subdivide!
DESCRIPTION
	(subdivide! id nr) subdivides the mesh with tag `id`
	`nr` times.

NAME
	trianglenormals
DESCRIPTION
	(trianglenormals id) returns the triangle normals of
	object with tag `id`. The triangle normals are given
	as a list of lists with (x y z) values.

NAME
	triangles
DESCRIPTION
	(triangles id) returns the triangles of object with
	tag `id` as a list of lists of the form ((v0 v1 v2)
	(v3 v4 v4) ...) where each sublist (v0 v1 v2) contain
	the indices of the vertices that form a triangle. The
	actual vertex positions can be obtained with the command
	(vertices id).

NAME
	triangles->csv
DESCRIPTION
	(triangles->csv id "file.csv") exports the triangles
	of the object with tag `id` to a csv file.

NAME
	triangulate
DESCRIPTION
	(triangulate lst) triangulates a list of 2d points of
	the form ((x0 y0) (x1 y1) ...) and returns the id of
	the resulting mesh.

NAME
	vertexcolors
DESCRIPTION
	(vertexcolors id) returns the vertex colors of object
	with tag `id`. The vertex colors are given as a list
	of lists with (r g b) values.

NAME
	vertexnormals
DESCRIPTION
	(vertexnormals id) returns the vertex normals of object
	with tag `id`. The vertex normals are given as a list
	of lists with (x y z) values.

NAME
	vertexcolors-set!
DESCRIPTION
	(vertexcolors-set! id clrlst) sets vertex colors for
	the object with tag `id`. The vertex colors are given
	as a list of lists with (r g b) values.

NAME
	vertices
DESCRIPTION
	(vertices id) returns the vertices of object with tag
	`id` as a list of lists of the form ((x y z) (x y z)
	...) where each sublist (x y z) is a 3d point representing
	the position of that vertex.

NAME
	union
DESCRIPTION
	(union (id1 id2 ...)) computes the union of the meshes
	or morphable models with tag `id1`, tag `id2`, ...
	in the list (`id` `id2` ...) and returns the id of
	the result.

NAME
	vertices->csv
DESCRIPTION
	(vertices->csv id "file.csv") exports the vertices of
	the object with tag `id` to a csv file.

NAME
	view-bg-set!
DESCRIPTION
	(view-bg-set! r g b) changes the background color to
	(r g b).

NAME
	view-cs
DESCRIPTION
	(view-cs) returns the coordinate system of the view
	camera.

NAME
	view-cs-set!
DESCRIPTION
	(view-cs-set! cs) sets the coordinate system of the
	view camera. The coordinate system `cs` can be given
	as a vector of size 16 in column major format or as
	a list of lists in row major format.

NAME
	view-edges-set!
DESCRIPTION
	(view-edges-set! #t/#f) turns on/off rendering of edges.

NAME
	view-export
DESCRIPTION
	(view-export "image-file.png") exports the current view
	to a png image.

NAME
	view-ear-left-detector-set!
DESCRIPTION
	(view-ear-left-detector-set! #t/#f) turns on/off rendering
	of the left ear detector result.

NAME
	view-ear-right-detector-set!
DESCRIPTION
	(view-ear-right-detector-set! #t/#f) turns on/off rendering
	of the right ear detector result.

NAME
	view-face-detector-set!
DESCRIPTION
	(view-face-detector-set! #t/#f) turns on/off rendering
	of the face detector result.

NAME
	view-hide!
DESCRIPTION
	(view-hide!) hides the 3d view.

NAME
	view-onebit-set!
DESCRIPTION
	(view-onebit-set! #t/#f) turns on/off one-bit rendering.

NAME
	view-position
DESCRIPTION
	(view-position x y) returns the 3d position of the vertex
	in the last render of the 3d view at coordinate (x,y).

NAME
	view-index
DESCRIPTION
	(view-index x y) returns the vertex index of the vertex
	in the last render of the 3d view at coordinate (x,y).

NAME
	view-id
DESCRIPTION
	(view-id x y) returns the id of the object in the last
	render of the 3d view at coordinate (x,y).

NAME
	view-shading-set!
DESCRIPTION
	(view-shading-set! #t/#f) turns on/off lighting.

NAME
	view-shadow-set!
DESCRIPTION
	(view-shadow-set! #t/#f) turns on/off rendering of shadow.

NAME
	view-show!
DESCRIPTION
	(view-show!) shows the 3d view.

NAME
	view-size-set!
DESCRIPTION
	(view-size-set! w h) resizes the plotted image to size
	(w, h).

NAME
	view-textured-set!
DESCRIPTION
	(view-textured-set! #t/#f) turns on/off rendering of
	texture.

NAME
	view-unzoom!
DESCRIPTION
	(view-unzoom!) sets the camera to its initial position.

NAME
	view-vertexcolors-set!
DESCRIPTION
	(view-vertexcolors-set! #t/#f) turns on/off rendering
	of vertex colors.

NAME
	view-wireframe-set!
DESCRIPTION
	(view-wireframe-set! #t/#f) turns on/off rendering of
	wireframe.

NAME
	exit
DESCRIPTION
	(exit) can be used in the input script to end meshscript,
	so the REPL is skipped.

Credits