//   @Override
    public void add(int i, double[] P1, double[] P2, double[] Q)
    {
        //     assert P1 == p1;
        //   assert P2 == p2;

        for (int f = 0; f < distfunc.getComplexity(); f++)
        {
            FacetList fl = sortedfacets[f];

            FacetListElement fle = new FacetListElement();
            fle.index  = i;
            fle.slope  = fl.slope;
            fle.height = distfunc.getFacetDistance(VectorUtil.subtract(p1, Q), fl.facet);

            while (fl.getSize() > 0 && fl.getFirst().height <= fle.height)
            {
                fl.removeFirst();
            }
            fl.addFirst(fle);
        }
    }
    private double findMinimumTrimmedProcedure()
    {
        FacetListElement[] upperenvelope = new FacetListElement[distfunc.getComplexity()];

        FacetListElement first = sortedfacets[0].getLast();

        upperenvelope[0] = first;
        double[] intersectPreviousAt = new double[distfunc.getComplexity()];
        intersectPreviousAt[0] = 0;
        int n = 1;

        for (int i = 1; i < distfunc.getComplexity(); i++)
        {
            FacetList        fl  = sortedfacets[i];
            FacetListElement fle = fl.getLast();


            upperenvelope[n]       = fle;
            intersectPreviousAt[n] = findIntersection(upperenvelope[n - 1], fle);
            n++;

            if (double.IsInfinity(intersectPreviousAt[n - 1]) || double.IsNaN(intersectPreviousAt[n - 1]))
            {
                // NB: can only occur with the first previous one (slopes are unique in UE)
                if (upperenvelope[n - 1].height > upperenvelope[n - 2].height)
                {
                    // toss previous
                    upperenvelope[n - 2] = upperenvelope[n - 1];
                    if (n > 2)
                    {
                        intersectPreviousAt[n - 2] = findIntersection(upperenvelope[n - 3], fle);
                    }
                    else
                    {
                        // nothing to intersect
                    }
                    n--;
                }
                else
                {
                    // toss this one
                    n--;
                }
            }

            while (n > 1 && intersectPreviousAt[n - 1] < intersectPreviousAt[n - 2])
            {
                // [n-2] not on upper envelope
                upperenvelope[n - 2] = upperenvelope[n - 1];
                if (n == 2)
                {
                    // intersectPreviousAt[n-2] = 0; // doesn't change
                }
                else
                {
                    intersectPreviousAt[n - 2] = findIntersection(upperenvelope[n - 3], fle);
                }
                n--;
            }

            if (intersectPreviousAt[n - 1] > 1)
            {
//                assert n > 1;
                n--;
            }
            else if (n > 1 && upperenvelope[n - 2].slope > 0)
            {
                n--;
            }
        }

        double min;

        if (upperenvelope[n - 1].slope > 0)
        {
            if (n > 1)
            {
                // get height at intersection with previous
                min = upperenvelope[n - 1].slope * intersectPreviousAt[n - 1] + upperenvelope[n - 1].height;
            }
            else
            {
                // get height at 0
                min = upperenvelope[n - 1].height;
            }
        }
        else
        {
            // get height at 1
            min = upperenvelope[n - 1].slope + upperenvelope[n - 1].height;
        }

        return(min);
    }
    private double findIntersection(FacetListElement fle1, FacetListElement fle2)
    {
        double xint = (fle2.height - fle1.height) / (fle1.slope - fle2.slope);

        return(xint);
    }
    private double findMinimumFullProcedure()
    {
        FacetListElement[] upperenvelope = new FacetListElement[distfunc.getComplexity()];

        FacetListElement first = sortedfacets[0].getLast();

        upperenvelope[0] = first;
        double[] intersectPreviousAt = new double[distfunc.getComplexity()];
        intersectPreviousAt[0] = double.NegativeInfinity;
        int n = 1;

        for (int i = 1; i < distfunc.getComplexity(); i++)
        {
            FacetList        fl  = sortedfacets[i];
            FacetListElement fle = fl.getLast();


            upperenvelope[n]       = fle;
            intersectPreviousAt[n] = findIntersection(upperenvelope[n - 1], fle);
            n++;

            if (double.IsInfinity(intersectPreviousAt[n - 1]) || double.IsNaN(intersectPreviousAt[n - 1]))
            {
                // NB: can only occur with the first previous one (slopes are unique in UE)
                if (upperenvelope[n - 1].height > upperenvelope[n - 2].height)
                {
                    upperenvelope[n - 2] = upperenvelope[n - 1];
                    if (n > 2)
                    {
                        intersectPreviousAt[n - 2] = findIntersection(upperenvelope[n - 3], fle);
                    }
                    else
                    {
                    }
                    n--;
                }
                else
                {
                    n--;
                }
            }

            while (n > 1 && intersectPreviousAt[n - 1] < intersectPreviousAt[n - 2])
            {
                upperenvelope[n - 2]       = upperenvelope[n - 1];
                intersectPreviousAt[n - 2] = findIntersection(upperenvelope[n - 3], fle);

                n--;
            }
        }
        // minimum given by first point with positve slop
        int min_index = -1;

        for (int i = 0; i < n; i++)
        {
            if (upperenvelope[i].slope > 0)
            {
                min_index = i;
                break;
            }
        }

        double min;

        if (intersectPreviousAt[min_index] < 0)
        {
            while (min_index < n - 1 && intersectPreviousAt[min_index + 1] < 0)
            {
                min_index++;
            }
            min = upperenvelope[min_index].height;
        }
        else if (intersectPreviousAt[min_index] > 1)
        {
            while (min_index > 0 && intersectPreviousAt[min_index] > 1)
            {
                min_index--;
            }
            min = upperenvelope[min_index].slope + upperenvelope[min_index].height;
        }
        else
        {
            min = upperenvelope[min_index].slope * intersectPreviousAt[min_index] + upperenvelope[min_index].height;
        }

        return(min);
    }