-1

Hope doing well. I have two numpy array, both are some points in the space. Using python, I want to firstly find the surface passing the first data set (surface_maker) and then find the x,y and z of the projection adjacent opoints of the second array (contact_maker) on the created surface. surface_maker always created planar surfaces. For projection, I only want a vertical going from adjacent point toward the surface. In reality I have lots of points in both sets but I copies a simple case here:

surface_maker=np.array([[50., 15., 46.04750574],
                        [50., 5., 45.56400925],
                        [44.83018398, 5., 25.],
                        [44.76296902, 15., 25.],
                        [50., 25., 45.56400925],
                        [44.83018398, 25., 25.],
                        [59.8336792, 5., 75.],
                        [59.71483707, 15., 75.],
                        [59.8336792, 25., 75.]])
contact_maker=np.array([[10.,  5., 70.00014782],
                        [10., 15., 70.00018358],
                        [10., 25., 70.0001955 ],
                        [30.,  5., 69.99981105],
                        [30., 15., 69.99982297],
                        [30., 25., 69.99985874],
                        [70., 5., 50.00000298],
                        [70., 15., 50.00002682],
                        [70., 25., 50.00005066],
                        [90., 5., 49.99996871],
                        [90., 15., 49.99999255],
                        [90., 25., 50.00001788]])

I have tried several solutions like 1, 2 and so on. But I was successful to solve my issue. For me it is important to have the location of projection as x, y and z. The figure also shows what I want (as it shows, I need only location six adjacent point of the contact_maker projected on the surface created by surface_maker):

enter image description here

In advance, I truely appreciate any help.

Ali_d
  • 1,089
  • 9
  • 24

2 Answers2

2

We can build plane using any three non-collinear points from the first set.

Let points are A, B, C. At first calculate vectors

AB = B - A  (ab.x = b.x - a.x and so on)
AC = C - A

Now calculate normal vector using cross product

N = AB x AC

If N is zero vector, then points are collinear and we need to choose another triplet

(I'm sure that numpy contains ready-to-use functions for all these vector operations)

Now we have three components of the plane equation (normal components)

N.x * x +  N.y * y + N.z * z + D = 0

To get the fourth component D, just substitute A point into this equation

D = - (N.x * A.x +  Ny * A.y + Nz * A.z)

Seems that you projection is along OX axis. In this case for any point Q we can easily find projection onto plane solving

N.x * x +  N.y * Q.y + N.z * Q.z + D = 0
x = -(N.y * Q.y + N.z * Q.z + D) / N.x

for unknown x, whilst y and z coordinates of projection are equal to Q.y and Q.z

import numpy as np

S = np.array([[50., 15., 46.04750574], [50., 5., 45.56400925], [44.83018398, 5., 25.]])
AB = S[1] - S[0]
AC = S[2] - S[0]
N = np.cross(AB, AC)
D = - (N[0] * S[0][0] +  N[1] * S[0][1] + N[2] * S[0][2])
Q = np.array([10.,  5., 70.00014782])
x = -(N[1] * Q[1] + N[2] * Q[2] + D) / N[0]
print(x,Q[1],Q[2])

>>> 56.143273867965505 5.0 70.00014782
MBo
  • 77,366
  • 5
  • 53
  • 86
  • Dear @MBo, I do appreciate your informative hints. Do you know any way to translate your method to python? I am a biginner in python. – Ali_d Nov 13 '20 at 09:48
  • @Ali_d I am not familiar with numpy, so just googled `numpy cross product` and made a sketch for one of your points - literal imlementation of my descritpion above (don't forget to check for zeros and so on) – MBo Nov 13 '20 at 10:09
  • Thanks for your example. I do appreciate it. I am using this results with another application. I that application I am using only four corners of my `surface_maker` to creat a surface. I need this projection in that application. Can I make my surface using four corners? Because I want to mimic the exact surface. Sorry for this issue. It came right now to my mind. You asked me about it and I said all the points. – Ali_d Nov 13 '20 at 10:22
  • 1
    Using three points is enough to define a plane. Fourth corner cannot help better – MBo Nov 13 '20 at 10:32
  • I mean can I connect the corners as lines and make the four connected lines a surface? The other application is doing the same. It connects points and make surfaces by connected points. Is it pissible here? Exactly like my four red lines in the figure I uploaded. – Ali_d Nov 13 '20 at 10:36
  • 1
    Yes, you can connect the corners - for drawing purposes, but to calculate coordinates, you need plane equation. And I gave very simple method to find this equation. – MBo Nov 13 '20 at 10:46
  • Aha, you mean I cannot mimic what the software is doing? It is called gmsh. It connects points and then gives me a surface created by four connected lines. – Ali_d Nov 13 '20 at 10:48
1

I understand you need to solve two problems:

  • Find the plane that fits a collection of points
  • Project a second collection of points onto that plane along a specific direction

The second problem has been fully addressed in another answer, so I'm contributing a more generic approach to the first problem.

It's true that when you positively know that all your points lie on a plane, you may just select three non-aligned ones and calculate the plane. But your points may come from real measurements with some noise, and you may wish to find the plane that best fists your points.

The following function solves the general problem of finding the plane that best fits a collection of points. See the explanations in the comments:

import numpy as np
PRECISION = 1e-8    # Arbitrary zero for real-world purposes

def plane_from_points(points):
    # The adjusted plane crosses the centroid of the point collection
    centroid = np.mean(points, axis=0)

    # Use SVD to calculate the principal axes of the point collection
    # (eigenvectors) and their relative size (eigenvalues)
    _, values, vectors = np.linalg.svd(points - centroid)

    # Each singular value is paired with its vector and they are sorted from
    # largest to smallest value.
    # The adjusted plane plane must contain the eigenvectors corresponding to
    # the two largest eigenvalues. If only one eigenvector is different
    # from zero, then points are aligned and they don't define a plane.
    if values[1] < PRECISION:
        raise ValueError("Points are aligned, can't define a plane")

    # So the plane normal is the eigenvector with the smallest eigenvalue
    normal = vectors[2]

    # Calculate the coefficients (a,b,c,d) of the plane's equation ax+by+cz+d=0.
    # The first three coefficients are given by the normal, and the fourth
    # one (d) is the plane's signed distance to the origin of coordinates
    d = -np.dot(centroid, normal)
    plane = np.append(normal, d)

    # If the smallest eigenvector is close to zero, the collection of
    # points is perfectly flat. The larger the eigenvector, the less flat.
    # You may wish to know this.
    thickness = values[2]

    return plane, thickness

You can check this:

>>> surface_maker=np.array([[50., 15., 46.04750574], [50., 5., 45.56400925], [44.83018398, 5., 25.], [44.76296902, 15., 25.], [50., 25., 45.56400925], [44.83018398, 25., 25.], [59.8336792, 5., 75.], [59.71483707, 15., 75.], [59.8336792, 25., 75.]])
>>> plane, thickness = plane_from_points(surface_maker)
>>> print(plane)
[-0.95725318  0.          0.28925136 35.2806339 ]
>>> print(thickness)
1.3825669490602308

So, in fact, your point distribution is not flat (thickness clearly different from zero), and you can't just select three arbitrary points to solve your problem.

aerobiomat
  • 2,883
  • 1
  • 16
  • 19
  • Dear @aerobiomat, I do appreciate your solution. Sorry for my late response. I saw it late. What happens if I use your method for only four corners rather than all points? Should I have still the thickness or it must be zero when I use four corners? Again, sorry for my late feedback. – Ali_d Nov 15 '20 at 17:41
  • 1
    It seems a bit of an overkill to use this method with very few points, but it will work with any number of points (it will raise ValueError with less than 3 points or with aligned points). With four points it will also give you a "thickness" value. However, selecting only a few points from the original collection will produce results with higher variability. But if you want to use only four points you can calculate the plane using three points and then check the distance from the fourth one to the plane to ensure they all lie on the plane. – aerobiomat Nov 16 '20 at 09:43
  • Dear @aerobiomat, I do appreciate your help. Your solution is giving me the equation of the plane and I only need to replace the y and of adjacent points on the equation of generated plane to find the projection. – Ali_d Nov 16 '20 at 10:26