```python
import numpy as np
import ipyvolume as ipv
import sympy as sy
from sympy.geometry import Plane as syPlane, Point3D as syPoint3D
import tqdm
```


```python
xyz = np.array((np.random.random(1000), np.random.random(1000), np.random.random(1000)))
```


```python
ipv.clear()
ipv.scatter(*xyz, marker='circle_2d')
ipv.show()
```

Let's see how we can define a thick plane (i.e. two co-planar planes separated by a certain distance) by selecting a point in space and then adding a normal vector and a thickness.

It would be nice if we could get the initial plane-point by clicking on a point in the ipyvolume plot. Let's look into that later.

If the normal vector $\boldsymbol{n}$ is $(a,b,c)$ then a plane in $(x,y,z)$ is parameterized by

$$
ax+by+cz+d=0
$$

You can either find three points $P_i$ in the plane and use the cross product of two differences of points to find a, b, c, because

$$
\boldsymbol{n} = (P_3-P_1) \times (P_2-P_1)
$$

or if you define $\boldsymbol{n}$ yourself, you can just directly find $d$ by plugging in any point in the plane in the previous equation.

Then you can use the edges of your box to define the extreme points of your plane to be plotted.

See e.g. https://stackoverflow.com/a/13473027/1199693


```python
def normalize_vector(n):
    n_size = n[0] * n[0] + n[1] * n[1] + n[2] * n[2]
    n = (n[0]/n_size, n[1]/n_size, n[2]/n_size)
    return n


def plot_plane(p, n):
    """
    Draw a plane.

    p: a point in the plane (x, y, z; any iterable)
    n: the normal vector to the plane (x, y, z; any iterable)
    """
    n = normalize_vector(n)
    
    # find d
    d = -(n[0] * p[0] + n[1] * p[1] + n[2] * p[2])

    # get box limits in two dimensions
    x_lim = (0, 1)
    z_lim = (0, 1)
    x, z = np.meshgrid(x_lim, z_lim)

    # find corresponding y coordinates
    y = -(n[0] * x + n[2] * z + d)/n[1]

    # plot
    ipv.plot_surface(x, y, z)


def thick_plane_points(p, n, thickness):
    """
    Given a point, a normal vector and a thickness, return two points
    along the normal that are `thickness` apart.
    """
    n = normalize_vector(n)
    
    p1 = (p[0] + 0.5 * thickness * n[0],
          p[1] + 0.5 * thickness * n[1],
          p[2] + 0.5 * thickness * n[2])
    p2 = (p[0] - 0.5 * thickness * n[0],
          p[1] - 0.5 * thickness * n[1],
          p[2] - 0.5 * thickness * n[2])
    return p1, p2


def plot_thick_plane(p, n, thickness=0):
    """
    Draw two co-planar planes, separated by a distance `thickness`.

    p: a point in the plane (x, y, z; any iterable)
    n: the normal vector to the plane (x, y, z; any iterable)
    thickness: the distance between the two co-planar planes
    """
    if thickness <= 0:
        plot_plane(point, normal)
    else:
        # find points in the two planes and plot them
        p1, p2 = thick_plane_points(p, n, thickness)
        
        plot_plane(p1, n)
        plot_plane(p2, n)
```


```python
point = (0.5, 0.5, 0.5)
normal = (0, 1, 0)  # make it normalized to one
thickness = 0.1

plot_thick_plane(point, normal, thickness=thickness)
```

Now, we also need to actually filter the points. Let's do that with Sympy.


```python
def filter_points_plane(points_xyz, plane_point, plane_normal, plane_thickness):
    point1, point2 = thick_plane_points(plane_point, plane_normal, plane_thickness)
    plane1 = syPlane(syPoint3D(point1), normal_vector=plane_normal)
    plane2 = syPlane(syPoint3D(point2), normal_vector=plane_normal)
    
    p_filtered = []
    for p_i in tqdm.tqdm(points_xyz.T):
        sy_point_i = syPoint3D(tuple(p_i))
        if plane1.distance(sy_point_i) <= thickness and plane2.distance(sy_point_i) <= thickness:
            p_filtered.append(p_i)
    return p_filtered
```


```python
p_filtered = filter_points_plane(xyz, point, normal, thickness)
```


```python
len(p_filtered)
```


```python
ipv.scatter(*np.array(p_filtered).T, marker='circle_2d', color='blue')
```


```python

```

a599d8f2dc36b7eb3b129b8586b9b35430951f2a
ipynb
Jupyter Notebook
req2.1_filter_plane.ipynb
sundial-pointcloud-geometry/explore
f2aca1b787a5bcc8a187fefdf5048451fca1b2e1
MIT
req2.1_filter_plane.ipynb
sundial-pointcloud-geometry/explore
f2aca1b787a5bcc8a187fefdf5048451fca1b2e1
MIT
req2.1_filter_plane.ipynb
sundial-pointcloud-geometry/explore
f2aca1b787a5bcc8a187fefdf5048451fca1b2e1
MIT
Qwen/Qwen-72B
1. YES
2. YES