

public class PickableSchwarzPolygon
{
    public Complex SchwarzPolygon[];

    public PickableSchwarzPolygon()
    {
        SchwarzPolygon = null;
    }


    public void setVertices(double vertices[][ ], Isometry2 I)
    {
        if (vertices == null)
            SchwarzPolygon = null;
        else
        {
            int n = vertices.length;
            SchwarzPolygon = new Complex[n];
            int i;
            for (i = 0; (i) < (n); ++i)
            {
                SchwarzPolygon[i] = I.apply(new Complex(vertices[i][0],vertices[i][1]));
            }
        }
    }


    public void setVerticesFromDoubles(Complex vertices[], Isometry2 I)
    {
        if (vertices == null)
            SchwarzPolygon = null;
        else
        {
            int n = vertices.length;
            SchwarzPolygon = new Complex[n];
            int i;
            for (i = 0; (i) < (n); ++i)
            {
                SchwarzPolygon[i] = I.apply(vertices[i]);
            }
        }
    }





    public boolean pick(
                Complex p,
                Isometry2 return_IsometryThatSendsPointInsideSchwarzPolygon,
                int verbose,
                int return_nFlips[ ])
    {




        Isometry2 curI = Isometry2.identity;
        Complex curP = p;

        if (verbose >= 1)
        {
            System.out.println("    Trying to send point "+curP+" to inside schwarz polygon "+this+"");
        }

        int n = SchwarzPolygon.length;
        double eps = 1e-6;



        if (HyperbolicUtils.pointIsToRightSideOfLinePoincare(
                SchwarzPolygon[2],
                SchwarzPolygon[0],
                SchwarzPolygon[1],
                eps))
        {


            Arrays.reverse(SchwarzPolygon, SchwarzPolygon);
        }

        Isometry2 reflections[] = new Isometry2[n];



        int totalIterations;
        int totalIterationsLimit = 200;
        int nInside = 0;
        int i;
        int totalFlips = 0;
        for (i = 0, totalIterations = 0;
             totalIterations < totalIterationsLimit;
             i = (i+1)%n, totalIterations++)
        {
            if (HyperbolicUtils.pointIsToRightSideOfLinePoincare(
                        curP,
                        SchwarzPolygon[i],
                        SchwarzPolygon[(i+1)%n],
                        eps))
            {
                if (verbose >= 1)
                    System.out.println("            outside side "+i);




                if (reflections[i] == null)
                {
                    reflections[i] = Isometry2.reflectionAcrossLine(
                                        SchwarzPolygon[i],
                                        SchwarzPolygon[(i+1)%n]);
                }
                Isometry2 incI = reflections[i];

                curI = Isometry2.mul(incI, curI);
                curP = incI.apply(curP);

                if (verbose >= 1)
                {
                    System.out.println("        -> "+curP);
                }

                totalFlips++;

                nInside = 0;
            }
            else
            {
                if (verbose >= 3)
                    System.out.println("            inside side "+i);

                if (++nInside == n)
                {



                    if (verbose >= 1)
                    {
                        System.out.println("        got it! (iteration "+totalIterations+")\n");
                    }
                    return_IsometryThatSendsPointInsideSchwarzPolygon.set(curI);
                    if (return_nFlips != null)
                        return_nFlips[0] = totalFlips;
                    return true;
                }
            }
        }
        System.out.println("        ARGH! pick reached "+totalIterations+" iterations");
        return false;
    }

    public String toString()
    {
        String s = "[";
        int i, n = SchwarzPolygon.length;
        for (i = 0; (i) < (n); ++i)
        {
            s = s + "(" + SchwarzPolygon[i].x + "," + SchwarzPolygon[i].y + ")";
            if (i+1 < n)
                s = s + ", ";
        }
        s = s + "]";
        return s;
    }
}
