title: how to find perpendicular projection of point on a surface in python
body: <p>I have a bunch of points in 3d space (x,y and z) and want to find their perpendicular projection on a surface in python. My surface is created by four points using the following function:</p>
  <pre><code>PRECISION = 1e-8    # Arbitrary zero for real-world purposes
  def plane_from_points(points):
      centroid = np.mean(points, axis=0)
      _, eigenvalues, eigenvectors = np.linalg.svd(points - centroid)
      if eigenvalues[1] &lt; PRECISION:
          raise ValueError(&quot;Points are aligned, can't define a plane&quot;)
      normal = eigenvectors[2]
      d = -np.dot(centroid, normal)
      plane = np.append(normal, d)
      thickness = eigenvalues[2]
      return plane, thickness
  </code></pre>
  <p>These are my input points stored as list for creating the surface:</p>
  <pre><code>surface_maker=[np.array([[44., 5., 25.],
                          [44., 25., 25.],
                          [59., 5., 75.],
                          [59., 25., 75.]])]
  </code></pre>
  <p>I want to ind the perpedicular projection of the following points in the created surface:</p>
  <pre><code>projection_point=[np.array([[49.9,  5., 65.],
                          [48., 17., 69.],
                          [47., 25., 71.9],
                          [60., 5., 39.],
                          [55., 15., 42.1],
                          [57., 25., 40.1]])]
  </code></pre>
  <p>I tried the following code to do so, but it is giving me the horizontal projection while i want to find the perpendilar projection:</p>
  <pre><code>pls=[]
  for i in surface_maker:
      i=i.tolist()
      pl, thickness= plane_from_points(i)
      pls.append(pl)
  point_on_surf=[]
  n_iter=1
  for i in range (n_iter):
      a, b, c, d = pls[i][0], pls[i][1], pls[i][2], pls[i][3]
      def fun(row):
          row[0] = -(d + b * row[1] + c * row[2]) / a # calculates new x
          return row[0], row[1], row[2] # new x and old y and z
      to_be_projected=[copy.copy(projection_point[i])]
      new_points = np.asarray(list(map(fun, [x for point in to_be_projected for x in point])))
      point_on_surf.append(new_points)
  </code></pre>
  <p>In  fig I visualized what I want. I just used different colurs for points to make the figure more readable. For the upper thre point I showed arrows to visualize the projection. My code is giving me the points which are at the end of red arrows but I want to find the projection point that are perpendicular to the surface. In fact, my code is only calculating a new x for the <code>projection_point</code>. In the fig green arrows show the direction I want. I want to do so for all the points existing in <code>projection_point</code>.
  In advance, I do appreciate any help.</p>
  <p><a href="https://i.stack.imgur.com/0sObh.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/0sObh.jpg" alt="enter image description here" /></a></p>