public static float getHeight(Vector3 point, planeData pd)
    {
        Vector3 diff   = point - pd.point;
        float   height = Vector3.Dot(diff, pd.normal.normalized);

        return(height);
    }
    static void findInliers(planeData pd, Vector3[] points, out int[] inlierIdxArray, out int[] outlierIdxArray)
    {
        List <int> inlierList  = new List <int>();
        List <int> outlierList = new List <int>();


        for (int i = 0; i < points.Length; i++)
        {
            float dist = Vector3.Dot((points[i] - pd.point), pd.normal);
            if (Mathf.Abs(dist) < inlierThreshold)
            {
                inlierList.Add(i);
            }

            if (Mathf.Abs(dist) > outlierThreshold)
            {
                outlierList.Add(i);
            }
        }



        inlierIdxArray  = inlierList.ToArray();
        outlierIdxArray = outlierList.ToArray();
    }
    static void estimatePlane(Vector3[] points, int[] idx_array, out planeData pd)
    {
        pd = new planeData();
        Vector3[] point_array = new Vector3[idx_array.Length];
        for (int pp = 0; pp < point_array.Length; pp++)
        {
            point_array[pp] = points[idx_array[pp]];
            //Debug.Log("point array of pp: " + point_array[pp]);
        }
        Vector3 p0 = point_array[0];



        pd.point = p0;

        //estimate normal:
        Mat A = new Mat(idx_array.Length, 3, CvType.CV_64F, new Scalar(0.0));

        for (int pp = 0; pp < idx_array.Length; pp++)
        {
            A.put(pp, 0, (point_array[pp].x - p0.x));
            A.put(pp, 1, (point_array[pp].y - p0.y));
            A.put(pp, 2, (point_array[pp].z - p0.z));
        }


        Mat S  = new Mat();
        Mat U  = new Mat();
        Mat Vt = new Mat();

        Core.SVDecomp(A, S, U, Vt, 4);

        //Debug.Log("A: " + A.dump());
        //Debug.Log("U: " + U.dump());
        //Debug.Log("S: " + S.dump());
        //Debug.Log("Vt: " + Vt.dump());

        double Nx = Vt.get(2, 0)[0];
        double Ny = Vt.get(2, 1)[0];
        double Nz = Vt.get(2, 2)[0];

        pd.normal = new Vector3((float)Nx, (float)Ny, (float)Nz);
    }
    public static void identify_biggest_plane(Vector3[] points, out planeData pd, out int[] insideIdx, out int[] remainingIdx)
    {
        List <Vector3> remainingList = new List <Vector3>();


        pd = new planeData();

        List <planeData> planeIterationList       = new List <planeData>();
        List <int>       inlierCountIterationList = new List <int>();


        System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
        for (int iter = 0; iter < ransac_iterations; iter++)
        {
            int[] idx_array = getThree(points.Length);
            //find the plane:

            sw.Reset();
            sw.Start();
            estimatePlane(points, idx_array, out pd);
            sw.Stop();

            //Debug.Log("idx array: " + idx_array[0] + " " + idx_array[1] + " " + idx_array[2]);
            //Debug.Log("plane: " + pd.normal + " point " + pd.point);



            //Debug.Log("Time to estimate plane with: " + points.Length + " " + sw.ElapsedMilliseconds + " ms");
            //find the inliers:
            int[] inlier_idx;
            int[] outlier_idx;
            sw.Reset();
            sw.Start();
            findInliers(pd, points, out inlier_idx, out outlier_idx);
            sw.Stop();
            //Debug.Log("Time to find inliers: " + inlier_idx.Length + " " + sw.ElapsedMilliseconds + " ms");
            //recalculate the plane:
            //estimatePlane(points, inlier_idx, out pd);

            planeIterationList.Add(pd);
            inlierCountIterationList.Add(inlier_idx.Length);
        }


        //select best plane:
        int best_idx   = 0;
        int best_count = inlierCountIterationList[0];

        for (int i = 0; i < planeIterationList.Count; i++)
        {
            if (inlierCountIterationList[i] > best_count)
            {
                best_idx   = i;
                best_count = inlierCountIterationList[i];
            }
        }


        //print out the best inlier iteration list:
        string output = "";

        for (int i = 0; i < inlierCountIterationList.Count; i++)
        {
            output += "plane " + i + ": " + inlierCountIterationList[i] + "\n";
        }
        //Debug.Log(output);



        planeData bestPlane = planeIterationList[best_idx];

        pd = bestPlane;


        int[] inlier_idx_array;
        int[] outlier_idx_array;
        findInliers(bestPlane, points, out inlier_idx_array, out outlier_idx_array);
        insideIdx    = inlier_idx_array;
        remainingIdx = outlier_idx_array;

        //Debug.Log("best plane is: " + best_idx + " new inliers: " + inlier_idx_array.Length);


        Vector3 inlierCentroid = new Vector3(0.0f, 0.0f, 0.0f);

        //insidePoints = new Vector3[inlier_idx_array.Length];
        for (int rr = 0; rr < inlier_idx_array.Length; rr++)
        {
            //insidePoints[rr] = points[inlier_idx_array[rr]];
            inlierCentroid = inlierCentroid + points[inlier_idx_array[rr]];
        }
        inlierCentroid    = inlierCentroid / inlier_idx_array.Length;
        pd.inlierCentroid = inlierCentroid;
        best_num_inliers  = inlier_idx_array.Length;

        /*
         * remainingPoints = new Vector3[outlier_idx_array.Length];
         * for (int rr = 0; rr < remainingPoints.Length; rr++)
         * {
         *  remainingPoints[rr] = points[outlier_idx_array[rr]];
         * }
         */
    }