Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to determine if 4 points are on same plane

Tags:

c#

kinect

I'm choosing 4 points from an image outputted by Kinect therefor each point has its (x, y, z) coordinates.

My objective is to determine whether the 4 points fall on the same plane.

This is my function:

    public bool isValidPlane()
    {
        for (int i = 0; i < edgesPoints.Length; i++)
        {
            double absPlaneEquation = Math.Abs(distance -
                (normal.X * edgesPoints[i].X + normal.Y * edgesPoints[i].Y + normal.Z * edgesPoints[i].Z));
            if (absPlaneEquation > 1500) /* 1500 is a tolerance error*/
            {
                return false;
            }
        }
        return true;
    }

The normal is also the normal (a cross product of 2 vectors on the plane, which been previously calculated from 3 out of 4 of the chosen points) to the plane and it's normalized:

    private void calcPlaneNormalVector()
    {
        if (lastEdgeNumber < 3)
        {
            return;
        }
        Vector3D vec1 = new Vector3D(edgesPoints[0], edgesPoints[1]);
        Vector3D vec2 = new Vector3D(edgesPoints[0], edgesPoints[2]);
        vec2 = vec1.crossProduct(vec2);
        double lengthNormal = Math.Sqrt(Math.Pow(vec2.X, 2) + Math.Pow(vec2.Y, 2) + Math.Pow(vec2.Z, 2));
//normalizing:
        normal = new Vector3D((vec2.X / lengthNormal), (vec2.Y / lengthNormal), (vec2.Z / lengthNormal));
        distance = (-1) * (edgesPoints[0].X * normal.X + edgesPoints[0].Y * normal.Y + edgesPoints[0].Z + normal.Z);
    }

Vector3D is a class to represent a vector:

public  class Vector3D
{
    private double x, y, z;

    public Vector3D(Point3D p1, Point3D p2)
    {
        x = p2.X - p1.X;
        y = p2.Y - p1.Y;
        z = p2.Z - p1.Z;
    }
    public Vector3D(double a = 0, double b = 0, double c = 0)
    {
        x = a;
        y = b;
        z = c;
    }

    <get properties for x, y, z >

    public Vector3D crossProduct(Vector3D u)
    {
        double tmpX = 0, tmpY = 0, tmpZ = 0;
        tmpX = y * u.Z - z * u.Y;
        tmpY = z * u.X - x * u.Z;
        tmpZ = x * u.Y - y * u.X;
        return new Vector3D(tmpX, tmpY, tmpZ);
    }
    public double dotProduct(Vector3D u)
    {
        return x * u.X + y * u.Y + z * u.Z;
    }
}

i always get 1300 <= absPlaneEquation <= 1400 even when the 4 points are chosen so that they won't be on the same plane.

What is the best way to detect that the 4 points refer to the same plane?

like image 552
ThunderWiring Avatar asked Aug 24 '16 13:08

ThunderWiring


People also ask

How do you prove that 4 points are on the same plane?

If θ = 0º or 180º, the cross-product will be 0, and all 4 points lie on the same plane. Use the three points to find its equation ( that is find A,B, and C ) , then plug in the 4th point to see if that satisfies then they are all in the same plane.

How do you know if two points are on the same plane?

Put the coordinates of the given points in the equation of plane and store the values in variables P1 and P2. Check the sign of the obtained values: If P1 and P2 have the same parity, then they are on the same side of the plane. If P1 and P2 have different parity then they lie on the opposite sides of the plane.

Can there be 4 points on a plane?

Four points (like the corners of a tetrahedron or a triangular pyramid) will not all be on any plane, though triples of them will form four different planes. Stepping down, two points form a line, and there wil be a fan of planes with this line (like pages of an open book, with the line down the spine of the book).


1 Answers

Once you have the normal vector of a plane, you can evaluate the plane's equation:

normal vector components : [A, B, C]
Plane equation           : A·x + B·y + C·z + D = 0;

Use one of the three points (P1, P2 or P3) used to obtain the normal vector to evaluate D and then simply check that the fourth point (P4) satisfies the equation:

 D = - (A·x1 + B·y1 + C·z1)
 A·x4 + B·y4 + C·z4 - (A·x1 + B·y1 + C·z1) = 0

It is importat to note that you are using floating point arithmetics so you can not test for strict equality. You need to define an acceptable error and check that the fourth points complies with the equation according to such tolerance:

 |A·x4 + B·y4 + C·z4 - (A·x1 + B·y1 + C·z1)| < TOLERANCE

UPDATE: Here's how I'd code the solution to your problem:

public struct Point3D
{
    public double X { get; }
    public double Y { get; }
    public double Z { get; }

    public Point3D(double x, double y, double z)
    {
        X = x;
        Y = y;
        Z = z;
    }
}

public struct Vector3D
{
    public double X { get; }
    public double Y { get; }
    public double Z { get; }
    public double Magnitude => Math.Sqrt(X * X + Y * Y + Z * Z);

    public Vector3D(Point3D p1, Point3D p2)
        : this(p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z)
    {
    }

    public Vector3D(double x, double y, double z)
    {
        X = x;
        Y = y;
        Z = z;
    }

    public static Vector3D CrossProduct(Vector3D left, Vector3D right)
    {
        double tmpX = 0, tmpY = 0, tmpZ = 0;
        tmpX = left.Y * right.Z - left.Z * right.Y;
        tmpY = left.Z * right.X - left.X * right.Z;
        tmpZ = left.X * right.Y - left.Y * right.X;
        return new Vector3D(tmpX, tmpY, tmpZ);
    }

    public static double DotProduct(Vector3D left, Vector3D right)
    {
        return left.X * right.X + left.Y * right.Y + left.Z * right.Z;
    }
}

public struct Plane3D
{
    private const double TOLERANCE = 0.001;

    private readonly double independentTerm;
    public Vector3D Normal { get; }

    public Plane3D(Point3D p1, Point3D p2, Point3D p3)
    {
        Normal = Vector3D.crossProduct(new Vector3D(p1, p2), new Vector3D(p1, p3));

        if (Normal.Magnitude < TOLERANCE)
            throw new ArgumentException("Specified points do not define a valid plane.");

        independentTerm = -(Normal.X * p1.X + Normal.Y * p1.Y + Normal.Z * p1.Z);
    }

    public bool Contains(Point3D p) => Math.Abs(Normal.X * p.X + Normal.Y * p.Y + Normal.Z * p.Z + independentTerm) < TOLERANCE;
}

Things to note:

  1. I've changed Point3D and Vector3D to structs. This largely depends on how you will use the objects but, at first glance, value types seem a better fit.
  2. I've made the value types immutable. Mutable value types are not a good idea; again, this wouldn't be an issue if you implement them as classes although I'd still advise creating immutable types whenever possible. In this case, doing so is very cheap.
  3. You have the concept of plane, well then, create a type to represent one.
  4. I've changed the vector operators to static methods. This could be down to personal taste.
  5. I've implemented the TOLERANCE const inside Plane. There is probably much better places where to define it, its simply there for convenience.
  6. I've tweeked you naming slightly; public members should start with a capital letter.
like image 91
InBetween Avatar answered Oct 01 '22 09:10

InBetween