[PyVista]調査メモ

## はじめに

PyVistaの調査メモ

https://tkoyama010.github.io/pyvista-docs-dev-ja/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/ba4ca1a1-47d1-b60f-c44b-8cb4856e9618.png)

## 環境

Window10環境で実行しました。

```powershell
PS C:\> python -V
Python 3.9.5
PS C:\> pip list | Select-String "PyVista"

pyvista               0.31.3
pyvistaqt             0.5.0
```

## ウィンドウを開きシリンダーオブジェクトを描画

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/019140f6-151b-4e0b-60c5-2b59d0f3f1d7.png)

```python
import pyvista as pv
import numpy as np

targetImage = [ "image0.png" , "image1.png"]
surf = pv.Cylinder()
tex = pv.numpy_to_texture(targetImage[0])
surf.plot(texture=tex)
```

テクスチャ用の画像

<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/ff3d63d6-9644-040c-8644-8d76a54fbc6a.png">


## シリンダーオブジェクトを画像出力

実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/812fa0ea-7832-8830-3fe8-781ad134b49c.png)

```python:png画像出力
import pyvista as pv
import numpy as np

targetImage = [ "image0.png" , "image1.png" ]
#surf = pv.Cylinder()
surf = pv.Cylinder(np.array([0, 0, 0]), np.array([0, 0, 1]), 1.0, 1.0)
"""
arg1: 座標 Location of the centroid in [x, y, z]
arg2: 向き Direction cylinder points to in [x, y, z]
arg3: 円の大きさ
arg4: 円柱の高さ 
"""
tex = pv.numpy_to_texture(targetImage[1])
plotter = pv.Plotter(off_screen=True)
plotter.add_mesh(surf , texture=tex, point_size=5.0)
plotter.screenshot('output.png')
```

### イメージファイルの読み込み

読み込んだ画像を描画します

参考

https://tkoyama010.github.io/pyvista-docs-dev-ja/examples/00-load/read-image.html

実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/c878d50b-8240-73da-ad9c-4c3e268e5c19.png)

```python
import pyvista as pv

targetImage = [ "image0.png" , "image1.png" ]
mesh = pv.read(targetImage[1])
mesh.plot(rgb=True, cpos="xy")
```

## オブジェクトを2つ配置し画像出力

実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/92bf67db-299d-ca00-5e87-81873a44c23c.png)

```python
import pyvista as pv
import numpy as np
plotter = pv.Plotter(off_screen=True, window_size=(400,400))

obj1 = pv.Cylinder(np.array([0, 0, 0]), np.array([0, 0, 1]), 1.0, 1.0)
plotter.add_mesh(obj1 ,color="green", show_edges=True)

obj2 = pv.Cylinder(np.array([0, 0, 1]), np.array([1, 0, 1]), 0.5, 3.0)
plotter.add_mesh(obj2 ,color="red", show_edges=True)

plotter.screenshot('output.png')
```

## ドーナツ型オブジェクト

参照

https://docs.pyvista.org/utilities/geometric.html

実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/9ac0e79d-6474-ee15-b346-18564ecb29d6.png)

```python:ウィンドウ描画
import pyvista as pv
pv.CylinderStructured(
        center=(0.0, 0.0, 0.0), 
        direction=(1.0, 0.0, 0.0), 
        radius=[2, 2.5], 
        height=3.0
    ).plot(show_edges=True)
```

```python:画像出力
import pyvista as pv
obj = pv.CylinderStructured(
        center=(0.0, 0.0, 0.0), 
        direction=(1.0, 0.0, 0.0), 
        radius=[2, 2.5], 
        height=3.0
    )
plotter = pv.Plotter(off_screen=True, window_size=(400,400))
plotter.add_mesh(obj)
plotter.screenshot('output.png')
```

実行結果（背景透過）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/db8cdd43-889d-0f1d-6eab-6cb54d8bd3f1.png)

```python:画像出力(背景透明)
import pyvista as pv
pv.rcParams['transparent_background'] = True
obj = pv.CylinderStructured(
        center=(0.0, 0.0, 0.0), 
        direction=(1.0, 0.0, 0.0), 
        radius=[2, 2.5], 
        height=3.0
    )
plotter = pv.Plotter(off_screen=True, window_size=(400,400))
plotter.add_mesh(obj)
plotter.screenshot('output.png')
```


## ブール演算

オブジェクトが重なる箇所をマスクする　※勉強中※

参考

https://docs.pyvista.org/examples/01-filter/boolean-operations.html#sphx-glr-examples-01-filter-boolean-operations-py

実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/cc194190-85bc-a3a6-64e0-600364904439.png)


```python
import pyvista as pv
import numpy as np
def make_cube():
    x = np.linspace(-0.5, 0.5, 25)
    grid = pv.StructuredGrid(*np.meshgrid(x, x, x))
    return grid.extract_surface().triangulate()

# Create to example PolyData meshes for boolean operations
sphere = pv.Sphere(radius=0.65, center=(0, 0, 0))

cube = make_cube()
union = sphere.boolean_union(cube)
p = pv.Plotter()
p.add_mesh(union,  opacity=0.5, show_edges=True, color=True)
p.show()
```


**【NG例】オブジェクト同士が重なっていないとエラーになる**

```python:【NG例】
import pyvista as pv
import numpy as np
def make_cube():
    x = np.linspace(-0.5, 0.5, 25)
    grid = pv.StructuredGrid(*np.meshgrid(x, x, x))
    return grid.extract_surface().triangulate()

# Create to example PolyData meshes for boolean operations
sphere = pv.Sphere(radius=0.65, center=(3, 3, 3))

cube = make_cube()
union = sphere.boolean_union(cube)
p = pv.Plotter()
p.add_mesh(union,  opacity=0.5, show_edges=True, color=True)
p.show()
```

エラーメッセージ

```powershell
PS C:\Users\user01\pyvista> python .\booltest.py
2021-08-07 17:38:47.837 (   0.135s) [                ]    vtkPointLocator.cxx:845    ERR| vtkPointLocator (000002DABCA16130): No points to subdivide
ERROR:root:No points to subdivide
2021-08-07 17:38:47.839 (   0.136s) [                ]vtkIntersectionPolyData:2410  WARN| No Intersection between objects
2021-08-07 17:38:47.840 (   0.137s) [                ]vtkDistancePolyDataFilt:82     ERR| vtkDistancePolyDataFilter (000002DAAB083FE0): No points/cells to operate on
ERROR:root:No points/cells to operate on
2021-08-07 17:38:47.840 (   0.138s) [                ]vtkDistancePolyDataFilt:82     ERR| vtkDistancePolyDataFilter (000002DAAB083FE0): No points/cells to operate on
ERROR:root:No points/cells to operate on
Traceback (most recent call last):
  File "C:\Users\user01\pyvista\booltest.py", line 32, in <module>
    p.add_mesh(union,  opacity=0.5, show_edges=True, color=True)
  File "C:\Users\user01\AppData\Local\Programs\Python\Python39\lib\site-packages\pyvista\plotting\plotting.py", line 1480, in add_mesh
    raise ValueError('Empty meshes cannot be plotted. Input mesh has zero points.')
ValueError: Empty meshes cannot be plotted. Input mesh has zero points.
PS C:\Users\user01\pyvista>
```

## ブール演算：検証① → 失敗

ブール演算の前準備として、2つのオブジェクトを重なるように配置する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/4d688ca4-e6f8-6d10-6dd1-b7c79ec1dbc8.png)

```python
import pyvista as pv
pv.rcParams['transparent_background'] = True

obj0 = pv.Cube(
        center=(0.0, 0.0, 0.0), 
        x_length=1.0, 
        y_length=0.1, 
        z_length=1.0, 
        bounds=None
    )
obj2 = pv.Cylinder(
        center=(0.0, -0.05, 0.0), 
        direction=(0.0, 1.0, 0.0),
        radius=0.4, 
        height=0.4
    )

plotter = pv.Plotter(off_screen=False, window_size=(400,400))
plotter.camera.position    = (6.0, 6.0, 6.0)

plotter.add_mesh(obj0 ,color="FFFFFF", show_edges=True)
plotter.add_mesh(obj2 ,color="red", show_edges=True)

plotter.show()
```

これをブール演算するとエラー発生　※原因調査中※


```python:エラーになる
import pyvista as pv
pv.rcParams['transparent_background'] = True

obj0 = pv.Cube(
        center=(0.0, 0.0, 0.0), 
        x_length=1.0, 
        y_length=0.1, 
        z_length=1.0, 
        bounds=None
    )

obj2 = pv.Cylinder(
        center=(0.0, -0.05, 0.0), 
        direction=(0.0, 1.0, 0.0),
        radius=0.4, 
        height=0.4
    )

union = obj2.boolean_union(obj0)

plotter = pv.Plotter(off_screen=False, window_size=(400,400))
plotter.camera.position    = (6.0, 6.0, 6.0)
plotter.add_mesh(union ,color="FFFFFF", show_edges=True)
plotter.show()
```

```powershell
PS C:\Users\user01\python\pyvista> python .\test2.py
2021-08-08 06:29:41.575 (   0.138s) [                ]    vtkPointLocator.cxx:845    ERR| vtkPointLocator (000002BD6BE50CB0): No points to subdivide
ERROR:root:No points to subdivide
2021-08-08 06:29:41.577 (   0.139s) [                ]vtkIntersectionPolyData:2410  WARN| No Intersection between objects
2021-08-08 06:29:41.577 (   0.139s) [                ]vtkDistancePolyDataFilt:82     ERR| vtkDistancePolyDataFilter (000002BD5AD8F060): No points/cells to operate on
ERROR:root:No points/cells to operate on
2021-08-08 06:29:41.578 (   0.140s) [                ]vtkDistancePolyDataFilt:82     ERR| vtkDistancePolyDataFilter (000002BD5AD8F060): No points/cells to operate on
ERROR:root:No points/cells to operate on
Traceback (most recent call last):
  File "C:\Users\user01\python\pyvista\test2.py", line 25, in <module>
    plotter.add_mesh(union ,color="FFFFFF", show_edges=True)
  File "C:\Users\zgw42\AppData\Local\Programs\Python\Python39\lib\site-packages\pyvista\plotting\plotting.py", line 1480, in add_mesh
    raise ValueError('Empty meshes cannot be plotted. Input mesh has zero points.')
ValueError: Empty meshes cannot be plotted. Input mesh has zero points.
PS C:\Users\user01\python\pyvista>
```

（エラー対策わかったら追記します）

## 穴形状のオブジェクトを作ってみる

PyVistaの習得できた範囲で穴形状のオブジェクトを作ってみます。ブール演算は理解できてないので、壁に穴が空いた表現は、透過画像で代用します。中央に透過率100%の円がある画像を用意します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/6bfe6b78-504e-cde2-6882-23253b6fb0bf.png)

実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/0cdf0eeb-3a73-48b7-0636-3309a10988f5.png)


```python
import pyvista as pv

pv.rcParams['transparent_background'] = True
targetImage = [ "image0.png" , "image1.png","image2.png" ]
tex = pv.numpy_to_texture(targetImage[2])

obj0 = pv.Plane(
        center=(0, 0, 0),
        direction=(0, 1, 0),
        i_size=1,
        j_size=1,
        i_resolution=20,
        j_resolution=20
    )
obj1 = pv.CylinderStructured(
        center=(0.0, -0.51, 0.0), 
        direction=(0.0, 1.0, 0.0), 
        radius=[0.3, 0.4], 
        height=1.0
    )

#plotter = pv.Plotter(off_screen=True, window_size=(400,400))
plotter = pv.Plotter(off_screen=False, window_size=(400,400))
plotter.camera.position    = (6.0, 6.0, 6.0)

plotter.add_mesh(obj0 ,color="FFFFFF", show_edges=False , texture=tex)
plotter.add_mesh(obj1 ,color="green", show_edges=True)

#plotter.screenshot('output.png')
plotter.show()
```

---

PyVistaまだまだわかってないです。調査はつづく