G-coordinatorで3Dプリント（造形関数）

# 関数を用いた造形

G-coordinatorを用いて造形を行う際に，重要な関数について述べていきます．
造形入門編において，簡単な円柱を造形するためのコードの解説は既に行なっています．
今回は，この円柱に，インフィルをつけたり，オフセットしたりする方法について解説します．

![](https://gcoordinator.readthedocs.io/ja/latest/_images/cylinder_wall.png)


前回までの単純な円柱コードを以下に示します．

```python
import numpy as np
import gcoordinator as gc

full_object=[]
for height in range(100):
    arg = np.linspace(0, 2*np.pi, 100)
    x = 10 * np.cos(arg)
    y = 10 * np.sin(arg)
    z = np.full_like(arg, (height+1) * 0.2)
    wall = gc.Path(x, y, z)
    full_object.append(wall)

gc.gui_export(full_object)
```

内容としては，x, y, z座標列を作成して，それらを元にPathと呼ばれるオブジェクトを作成し，印刷順番に，full_objectというリストにそれらを格納することで造形を行なっていました．


# Pathの変形
gc.Transformクラスの中に，入力されたパスを変形させる関数がまとまっています．

## オフセット
壁を一層ではなく，2層3層に増やしたいとします．この時，以下のようにoffset関数を呼び出します

```diff_python
... 略

    wall = gc.Path(x, y, z)
    full_object.append(wall)
+   outer_wall = gc.Transform.offset(wall, 0.4)
+   full_object.append(outer_wall)

... 略
```

こうすることで，ノズルの直径0.4mm分だけ外側にオフセットしたパスが印刷されます．
オフセットの値をプラスで指定すると，外側に，マイナスで指定すると内側にオフセットされます．

![スクリーンショット 2024-06-21 14.58.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3126722/73c57ff4-be75-4f53-7ae1-3b6122e03479.png)

offset関数の引数はPathで，返り値もPathです．帰ってきたouter_wallをさらにoffsetすることも可能です．

```diff_python
... 略

    wall = gc.Path(x, y, z)
    full_object.append(wall)
    outer_wall = gc.Transform.offset(wall, 0.4)
    full_object.append(outer_wall)
+   outer_wall_2 = gc.Transform.offset(outer_wall, 0.4)
+   full_object.append(outer_wall_2)

... 略
```

![スクリーンショット 2024-06-21 15.04.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3126722/809c2627-00e7-d043-1608-e445914f2e80.png)

また，返り値がPathオブジェクトであるから，一番外側のパスのみ，印刷設定を変えたいというときには以下のようにすればいいです．


```diff_python
... 略

    wall = gc.Path(x, y, z)
    full_object.append(wall)
    outer_wall = gc.Transform.offset(wall, 0.4)
    full_object.append(outer_wall)
    outer_wall_2 = gc.Transform.offset(outer_wall, 0.4)
    full_object.append(outer_wall_2)
+   outer_wall_2.print_speed = 3000

... 略
```
このようにすれば，一番外側の壁を印刷する時の印刷速度を直接指定することができます．



# その他のTransformクラスの関数
```python
gc.Transform.move(wall, x=10) # wallをx方向に10移動させたPathを返す
gc.Transform.rotate_xy(wall, np.pi/4) # wallを原点中心にπ/4(45度)回転させたPathを返す
gc.Transform.stretch(wall, x_stretch_ratio=2) # x方向に2倍に引き伸ばしたPathを返す
```


# インフィルの生成
G-coordinatorの目玉とも言えるインフィル生成に関して解説します．


```diff_python
... 略

    wall = gc.Path(x, y, z)
    full_object.append(wall)
+   infill = gc.gyroid_infill(wall, infill_distance=4)
+   full_object.append(infill)

... 略
```

実装自体は非常にシンプルで，gyroid_infillという関数にwallと，インフィルの間隔を入力することでその内部を埋めるパスを得ることができます．

![スクリーンショット 2024-06-21 15.28.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3126722/2857bcf9-ede3-6aa8-dcb5-28e0eaa90cc6.png)

:::note warn 
gc.gyroid_infill関数，gc.line_infill関数からの返り値は厳密にはPathクラスのオブジェクトではなく，PathListクラスのオブジェクトです．とある層において，インフィルは，複数のパスが集まって一塊のインフィルとなっているためです．しかし，G-coordinator内で，ユーザはPathListのオブジェクトもPathクラスのオブジェクトとほとんど同じように扱うことができるため，その違いをユーザが意識する必要なほとんどありません．
:::

 現在，G-coordinatorでは，上で示したgyroid_infillと，line_infillをサポートしています．
 line_infillの使用においても，gyroid_infillとほとんど同じです．

```diff_python
... 略

    wall = gc.Path(x, y, z)
    full_object.append(wall)
+   infill = gc.line_infill(wall, infill_distance=4)
+   full_object.append(infill)

... 略
```

![スクリーンショット 2024-06-21 15.44.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3126722/5e94862d-d02b-b0fa-3fcf-7a6f72c69b0f.png)

互い違いに格子のようにインフィルを生成したい時は，一層ごとにインフィルの角度を変えることで可能です．


```diff_python
for height in range(100):
    ... 略
    wall = gc.Path(x, y, z)
    full_object.append(wall)
+   infill = gc.line_infill(wall, infill_distance=4, angle=np.pi/4 + np.pi/2*height)
    full_object.append(infill)

... 略
```

![スクリーンショット 2024-06-21 15.48.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3126722/a7b7152f-32a3-3127-de01-eb63609c194a.png)

height の値が1ずつ増えるため，インフィルの角度が最初はπ/4, 次が3π/4, 次が5π/4
になり，互い違いのインフィルを実装できます．

## インフィルの印刷設定
インフィルも，他のパスと同じように印刷設定を調整することが可能です．
印刷設定の記事でも述べたように，基本は左のパラメータツリーの値が採用されますが，エディタで個別に調整することでできます．

注意点としては，印刷パスのリスト（full_object）に追加する前に，印刷設定を指定する必要があります．
```diff_python
... 略

    wall = gc.Path(x, y, z)
    full_object.append(wall)
    infill = gc.gyroid_infill(wall, infill_distance=4)
+   infill.print_spedd = 3000
    full_object.append(infill)

... 略
```

# インフィルに穴を開けたい
パスの内側にインフィルを生成するにあたり，この部分にはインフィルを生成したくないということもよくあります．（穴を開けたい時など）

その時には，少し工夫が必要です．


![スクリーンショット 2024-06-21 16.05.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3126722/2297c6e9-8bbb-815f-b9ed-7c42e99c32b3.png)


```diff_python
import math
import numpy as np
import gcoordinator as gc

LAYER = 100

full_object=[]
for height in range(LAYER):
    arg = np.linspace(0, 2*np.pi, 100)
    x = 10 * np.cos(arg)
    y = 10 * np.sin(arg)
    z = np.full_like(arg, (height+1) * 0.2)
    wall = gc.Path(x, y, z)
    full_object.append(wall)
+   inner_wall = gc.Transform.offset(wall, -5)
+   full_object.append(inner_wall)
+   walls = gc.PathList([wall, inner_wall])
+   infill = gc.gyroid_infill(walls, infill_distance=4)
+   full_object.append(infill)
gc.gui_export(full_object)

```
まず，外側のwallを作成します．
次に，穴のPathを生成します．今回は，5mm内側にオフセットしたパスを穴としました．
これらのwall, innner_wallの二つをリストにしたものを元にPathListクラスを生成します．PathListは複数のPathが一塊になったものと思ってください．今だと，wallとinner_wallが一塊として認識されるイメージです．
そのwallsというPathListをインフィルの入力とすれば，関数の中でよしなに計算して，内側の穴にはインフィルを生成しないようにしてれます，