# Geometric Coding

EusLisp have a solid library for geometric calculation. The explanation below is for irteusgl and afterwards (including roseus).

## 3D Viewer

3D Viewer can be launched with

``````(make-irtviewer)
`````` This viewer can be accessed by the global variable `*irtviewer*`. The view angle can be changed by dragging around the center. The left and bottom sides are used to adjust the view point. The right and top sides are used to zoom in and out. It differs from most 3D software, so please be aware of the above.

The viewer can be updated by clicking it or using `:draw-objects`, which is particularly necessary for loop animations. Updating the objects usually do not cause the viewer to get updated.

``````(send *irtviewer* :draw-objects)
``````

The following is used to allow mouse interruption during loop animation.

``````(x::window-main-one)
``````

## Basic solids

The following create a cube with border 100 mm

``````(setq *cube* (make-cube 100 100 100))
``````

which is send to the viewer by

``````(objects (list *cube*))
`````` Color can be changed with `:set-color`.

``````(send *cube* :set-color :red)
``````

The following change the cube's position and pose.

``````(send *cube* :translate (float-vector 0 0 50))
(send *cube* :rotate (/ pi 4.0) :z)
``````

`float-vector` is a function to create a vector. Differently from lists, vectors can only store elements of the same type.

When the viewer is clicked or `draw-objects` gets called, the viewer is updated. Similarly, `make-cylinder`, `make-cone` and other functions are provided. Details are given in Basic body functions (Japanese).

## Vector operations

Simple operations can be performed with `v+`, `v-`, `v.` and `v*`. For summing more than two vectors, `v++` is used.

``````(setq *v0* (float-vector 1 2 3)
*v1* (float-vector 4 5 6))
(print (v+ *v0* *v1*))
(print (v- *v0* *v1*))
(print (v. *v0* *v1*))  ;; Inner product
(print (v* *v0* *v1*))  ;; Outer product
``````

`scale` is used to multiply by a scalar.

``````(scale 10.0 *v0*)
``````

Vector elements can be accessed with `elt`. List operations such as `nth` and `car` cannot be used.

Objects created with `float-vector` are represented with `#f()`, which can also be used to access immediate values. However, it is not recommended to change elements of vectors created with `#f()`.

## Coordinate system

Next, try this:

``````(send *cube* :coords)
``````

It should return something like the following object.

``````#<coordinates #X6890ff8  0.0 0.0 50.0 / 0.785 0.0 0.0>
``````

This is a `coordinate` object, which can be transformed by homogeneous coordinate transformations like the above `:translate` and `:rotate`.

To copy such objects, `:copy-coords` is used.

``````(send *cube* :copy-coords)
``````

To make new coordinates, `make-coords` is used.

``````(setq *co* (make-coords))
``````

Translation is made with `:translate`.

``````(send *co* :translate (float-vector 10 20 30))
``````

The easiest way to change the coordinate attitude is to `:rotate` around an axis.

``````(send *co* :rotate (/ pi 4.0) :z)
``````

The above rotates 4/PI rad (45 deg) around the z axis. (`deg2rad` and `rad2deg` can be used for conversion between radian and degree)

It is also possible to visualize coordinates.

``````(objects (list *cube* *co*))
`````` ### Vector transformations using coordinates

It is possible to transform a vector into a certain coordinate system with the following:

``````(setq *vec* (float-vector 100 0 50))
(send *co* :transform-vector *vec*)
``````

Here, the result is the vector equivalent to `*vec*` with origin in `*co*`.

``````#f(80.7107 90.7107 80.0)
``````

### Coordinate transformations using other coordinates

For example:

``````(setq *co2* (make-coords))
(send *co2* :translate (float-vector 100 0 0))
(send *co2* :rotate pi :x)
(send *co* :transform *co2*)
``````

The result is the coordinate equivalent to `*co2*` with origin in `*co*`. This value is also stored in `*co*`.

``````#<coordinates #X68a8e38  80.711 90.711 30.0 / 0.785 6.163e-33 3.142>
``````

Until now we only dealt with single coordinate systems. By using `cascaded-coords`, it is possible to express linked coordinate systems. That is, when the parent coordinate is moved, child coordinate systems move the same way. Instead of `make-coords`, `make-cascoords` is used.

``````(setq *casco* (make-cascoords))
(setq *casco2* (make-cascoords :pos (float-vector 100 0 0) :parent *casco*))
``````

In the above, `*casco*` and `*casoco2*` are created and linked. It is also possible to link already created coordinates with `:assoc`.

In the following, translating the parent `*casco*` also causes `casco2*` to be moved the same way.

``````(send *casco* :translate (float-vector 0 0 100))
;; #<cascaded-coords #X690b528  0.0 0.0 100.0 / 0.0 0.0 0.0>
*casco2*
;; #<cascaded-coords #X6a0ece8  100.0 0.0 100.0 / 0.0 0.0 0.0>
``````

Instead, try to move the child coordinate:

``````(send *casco2* :translate (float-vector 0 100 0))
;; #<cascaded-coords #X6a0ece8  100.0 100.0 100.0 / 0.0 0.0 0.0>
``````

In this case, `*casco*` does not move.

``````*casco*
;; #<cascaded-coords #X690b528  0.0 0.0 100.0 / 0.0 0.0 0.0>
``````

Bodies can be linked with `:assoc`, similarly to coordinates.

``````(setq *stick* (make-cylinder 10 100))
(send *stick* :set-color :red)
(setq *body* (make-cube 50 100 50))
(send *body* :translate (float-vector 0 0 100))
(send *body* :set-color :yellow)
(send *stick* :assoc *body*)
(objects (list *body* *stick*))
`````` Both objects are displayed. If we try to move `*stick*`, both objects get moved.

``````(send *stick* :translate (float-vector 0 0 100))
(send *irtviewer* :draw-objects)  ;; Update viewer
`````` However, the coordinates of `*body*` seem to be unchanged:

``````(send *body* :coords)
;; #<coordinates #X6b3d9f8  0.0 0.0 100.0 / 0.0 0.0 0.0>
``````

This is because `:coords` returns the coordinates relative to the parent, which remain unaltered. To get the global coordinates, `:worldcoords` is used.

``````(send *body* :worldcoords)
;; #<coordinates #X6a93e88  0.0 0.0 200.0 / 0.0 0.0 0.0>
``````

Global coordinates can be copied with `:copy-worldcoords`.

``````(send *body* :copy-worldcoords)
``````