Search code examples
pythonopenglpoint-clouds

How to get diagonal line of a cube in a point cloud?


I have a point cloud of a cube. I created it with random(), so all x,y,z points are between 0 and 1. I created the cube like that.

import numpy as np
import open3d
import random

listPoints = []

for i in range(10000):
    x = random.random()
    y = random.random()
    z = random.random()
    listPoints.append([x,y,z])

arrayPoints = np.asarray(listPoints) 

point_cloud = open3d.PointCloud()
point_cloud.points = open3d.Vector3dVector(arrayPoints)
open3d.draw_geometries([point_cloud])

Cube

Now I want to get the points on the diagonal line. I now how to get points perpendicular to a point. I need to multiply some values depanding on degrees but I couldn't figure out how to do it. The code I use to get perpendicular to middle of the cube: (Y is 0.5 so I keep it static and check all points that has 0.5 Y value)

listPoints2 = []

minimumY = 0.5 - 0.02
maximumY = 0.5 + 0.02

for i in range(10000):
    if(listPoints[i][1] < maximumY and listPoints[i][1] > minimumY):
        listPoints2.append([listPoints[i][0],listPoints[i][1],listPoints[i][2]])

arrayPoints2 = np.asarray(listPoints2) 

point_cloud2 = open3d.PointCloud()
point_cloud2.points = open3d.Vector3dVector(arrayPoints2)
open3d.draw_geometries([point_cloud2])

Cube

My final output with perpendicular points. I want it to be angled like diagonal line.

Cube

With what should I multiply my values to get diagonal line?


Solution

  • what you need is to compute perpendicular distance of a point to axis see:

    From that you just test all points to be close enough to each of the 4 diagonals of cube. In C++ (sorry not a Python coder) it looks like this:

    //---------------------------------------------------------------------------
    const int n=10000;  // points
    const int n3=n+n+n; // points*dimensions
    double pnt[n3];     // points x,y,z ...
    DWORD  col[n];      // colors rgba, ...
    //---------------------------------------------------------------------------
    double distance_point_axis(double *p,double *p0,double *dp)
        {
        int i;
        double l,d,q[3];
        for (i=0;i<3;i++) q[i]=p[i]-p0[i];                  // q = p-p0
        for (l=0.0,i=0;i<3;i++) l+=dp[i]*dp[i];             // l = |dp|^2
        for (d=0.0,i=0;i<3;i++) d+=q[i]*dp[i];              // d = dot(q,dp)
        if (l<1e-10) d=0.0; else d/=l;                      // d = dot(q,dp)/|dp|^2
        for (i=0;i<3;i++) q[i]-=dp[i]*d;                    // q=q-dp*dot(q,dp)/|dp|^2
        for (l=0.0,i=0;i<3;i++) l+=q[i]*q[i]; l=sqrt(l);    // l = |q|
        return l;
        }
    //---------------------------------------------------------------------------
    void pnt_init()
        {
        Randomize();
        int i,i3,j;
        double r=0.1;  // radius of diagonals cylinders
        double diag[4*6]=
            {
            // p0        dp
            0.0,0.0,0.0, +1.0,+1.0,+1.0, // diagonal 1
            0.0,1.0,0.0, +1.0,-1.0,+1.0, // diagonal 2
            1.0,0.0,0.0, -1.0,+1.0,+1.0, // diagonal 3
            1.0,1.0,0.0, -1.0,-1.0,+1.0, // diagonal 4
            };
        // compute some uniformly random points <0,1>
        for (i3=0;i3<n3;i3++) pnt[i3]=Random();
        // compute color
        for (i=0,i3=0;i<n;i++,i3+=3)
            {
            // graysh
            col[i]=0x00303030;
            // diagonals
            j=0;
            if (distance_point_axis(pnt+i3,diag+j+0,diag+j+3)<r) col[i]|=0x00FF0000; j+=6;
            if (distance_point_axis(pnt+i3,diag+j+0,diag+j+3)<r) col[i]|=0x0000FF00; j+=6;
            if (distance_point_axis(pnt+i3,diag+j+0,diag+j+3)<r) col[i]|=0x000000FF; j+=6;
            if (distance_point_axis(pnt+i3,diag+j+0,diag+j+3)<r) col[i]|=0x00FF00FF; j+=6;
            }
        }
    //---------------------------------------------------------------------------
    void gl_draw()
        {
        int i,i3;
        static double ang=0.0; ang+=2.5; if (ang>360.0) ang-=360.0;
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
        glEnable(GL_DEPTH_TEST);
        glDisable(GL_TEXTURE_2D);
    
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glTranslatef(-0.5,-0.5,-5.0);
        glRotatef(ang,0.5,0.5,0.5);
    
        // render points froma list
        glBegin(GL_POINTS);
        for (i=0,i3=0;i<n;i++,i3+=3)
            {
            glColor4ubv((BYTE*)(col+i));
            glVertex3dv(pnt+i3);
            }
        glEnd();
    
    //  glFlush();
        glFinish();
        SwapBuffers(hdc);
        }
    //---------------------------------------------------------------------------
    

    So I declared 4 axes diag[4*6] (starting point and direction vector) and just set color of each point that is near to predefined RGB color...

    Here preview:

    preview

    And GIF animation:

    animation

    In case you want something simpler then main diagonal of your cube is

    x = y = z
    

    so simply test

    fabs(x-y)+fabs(x-z)+fabs(y-z) <= 1e-2
    

    for each point ... the other diagonals are just mirrors so just substitute mirrored coordinate with 1-coordinate