//--------------------------------------------------------------------------
// Copyright (C) 2001, 2002  Geoffrey Furnish
// Copyright (C) 2002-2014 Alan W. Irwin
// Copyright (C) 2004  Andrew Ross
//
// This file is part of PLplot.
//
// PLplot is free software; you can redistribute it and/or modify
// it under the terms of the GNU Library General Public License as published by
// the Free Software Foundation; version 2 of the License.
//
// PLplot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public License
// along with PLplot; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
//--------------------------------------------------------------------------

//--------------------------------------------------------------------------
// Implementation of PLplot example 9 in Java.
//--------------------------------------------------------------------------

package plplot.examples;

import plplot.core.*;
import static plplot.core.plplotjavacConstants.*;

import java.lang.Math;

class x09 {
    static final int    XPTS = 35;
    static final int    YPTS = 46;
    static final double XSPA = 2. / ( XPTS - 1 );
    static final double YSPA = 2. / ( YPTS - 1 );

// polar plot data
    static final int PERIMETERPTS = 100;
    static final int RPTS         = 40;
    static final int THETAPTS     = 40;

// potential plot data
    static final int PPERIMETERPTS = 100;
    static final int PRPTS         = 40;
    static final int PTHETAPTS     = 64;
    static final int PNLEVEL       = 20;

    final double     clevel[] = { -1., -.8, -.6, -.4, -.2, 0, .2, .4, .6, .8, 1. };
// Transformation function
    final double     tr[] = { XSPA, 0.0, -1.0, 0.0, YSPA, -1.0 };

    PLStream         pls = new PLStream();

// State data used by f2mnmx
    double fmin, fmax;

// Does a large series of unlabelled and labelled contour plots.

    public static void main( String[] args )
    {
        new x09( args );
    }

    public x09( String[] args )
    {
        int i, j;

        double[][] xg0 = new double[XPTS][YPTS];
        double[][] yg0 = new double[XPTS][YPTS];
        double[][] xg1 = new double[XPTS][YPTS];
        double[][] yg1 = new double[XPTS][YPTS];
        double[][] xg2 = new double[XPTS][YPTS];
        double[][] yg2 = new double[XPTS][YPTS];
        double[][] z   = new double[XPTS][YPTS];
        double[][] w   = new double[XPTS][YPTS];

        double      xx, yy, argx, argy, distort;
        final int[] mark  = { 1500 };
        final int[] space = { 1500 };
        final int[] mark0 = {};
        final int[] space0 = {};

        // Parse and process command line arguments.

        pls.parseopts( args, PL_PARSE_FULL | PL_PARSE_NOPROGRAM );
        // Initialize plplot

        pls.init();

        // Set up function arrays

        for ( i = 0; i < XPTS; i++ )
        {
            xx = (double) ( i - ( XPTS / 2 ) ) / (double) ( XPTS / 2 );
            for ( j = 0; j < YPTS; j++ )
            {
                yy      = (double) ( j - ( YPTS / 2 ) ) / (double) ( YPTS / 2 ) - 1.0;
                z[i][j] = xx * xx - yy * yy;
                w[i][j] = 2 * xx * yy;
            }
        }

        // Set up grids


        for ( i = 0; i < XPTS; i++ )
        {
            for ( j = 0; j < YPTS; j++ )
            {
                // Replacement for mypltr of x09c.c
                xx = tr[0] * i + tr[1] * j + tr[2];
                yy = tr[3] * i + tr[4] * j + tr[5];

                argx    = xx * Math.PI / 2;
                argy    = yy * Math.PI / 2;
                distort = 0.4;

                // Note these are one-dimensional because of arrangement of
                // zeros in the final tr definition above.
                // But I haven't found out yet, how with swig to overload
                // one- and two-dimensional array arguments so for now make
                // xg0 --> yg1 two-dimensional.
                xg0[i][j] = xx;
                yg0[i][j] = yy;
                xg1[i][j] = xx + distort * Math.cos( argx );
                yg1[i][j] = yy - distort * Math.cos( argy );

                xg2[i][j] = xx + distort * Math.cos( argx ) * Math.cos( argy );
                yg2[i][j] = yy - distort * Math.cos( argx ) * Math.cos( argy );
            }
        }


        // Plot using scaled identity transform used to create xg0 and yg0
//	pls.setcontlabelparam(0.006, 0.3, 0.1, 0);
//      pls.env(-1.0, 1.0, -1.0, 1.0, 0, 0);
//      pls.col0(2);
//      pls.cont( z, 1, XPTS, 1, YPTS, clevel, xg0, yg0 );
//      pls.styl(mark, space);
//      pls.col0(3);
//      pls.cont(w, 1, XPTS, 1, YPTS, clevel, xg0, yg0 );
//      pls.styl(mark0, space0);
//      pls.col0(1);
//      pls.lab("X Coordinate", "Y Coordinate", "Streamlines of flow");
//
        pls.setcontlabelformat( 4, 3 );
        pls.setcontlabelparam( 0.006, 0.3, 0.1, 1 );
        pls.env( -1.0, 1.0, -1.0, 1.0, 0, 0 );
        pls.col0( 2 );
        pls.cont( z, 1, XPTS, 1, YPTS, clevel, xg0, yg0 );
        pls.styl( mark, space );
        pls.col0( 3 );
        pls.cont( w, 1, XPTS, 1, YPTS, clevel, xg0, yg0 );
        pls.styl( mark0, space0 );
        pls.col0( 1 );
        pls.lab( "X Coordinate", "Y Coordinate", "Streamlines of flow" );
        pls.setcontlabelparam( 0.006, 0.3, 0.1, 0 );

        // Plot using 1d coordinate transform
        pls.env( -1.0, 1.0, -1.0, 1.0, 0, 0 );
        pls.col0( 2 );
        pls.cont( z, 1, XPTS, 1, YPTS, clevel, xg1, yg1 );
        pls.styl( mark, space );
        pls.col0( 3 );
        pls.cont( w, 1, XPTS, 1, YPTS, clevel, xg1, yg1 );
        pls.styl( mark0, space0 );
        pls.col0( 1 );
        pls.lab( "X Coordinate", "Y Coordinate", "Streamlines of flow" );

//	pls.setcontlabelparam(0.006, 0.3, 0.1, 1);
//      pls.env(-1.0, 1.0, -1.0, 1.0, 0, 0);
//      pls.col0(2);
//      pls.cont(z, 1, XPTS, 1, YPTS, clevel, xg1, yg1 );
//      pls.styl(mark, space);
//      pls.col0(3);
//      pls.cont(w, 1, XPTS, 1, YPTS, clevel, xg1, yg1 );
//      pls.styl(mark0, space0);
//      pls.col0(1);
//      pls.lab("X Coordinate", "Y Coordinate", "Streamlines of flow");
//      pls.setcontlabelparam(0.006, 0.3, 0.1, 0);
//
        // Plot using 2d coordinate transform
        pls.env( -1.0, 1.0, -1.0, 1.0, 0, 0 );
        pls.col0( 2 );
        pls.cont( z, 1, XPTS, 1, YPTS, clevel, xg2, yg2 );
        pls.styl( mark, space );
        pls.col0( 3 );
        pls.cont( w, 1, XPTS, 1, YPTS, clevel, xg2, yg2 );
        pls.styl( mark0, space0 );
        pls.col0( 1 );
        pls.lab( "X Coordinate", "Y Coordinate", "Streamlines of flow" );

//	pls.setcontlabelparam(0.006, 0.3, 0.1, 1);
//      pls.env(-1.0, 1.0, -1.0, 1.0, 0, 0);
//      pls.col0(2);
//      pls.cont(z, 1, XPTS, 1, YPTS, clevel, xg2, yg2 );
//      pls.styl(mark, space);
//      pls.col0(3);
//      pls.cont(w, 1, XPTS, 1, YPTS, clevel, xg2, yg2 );
//      pls.styl(mark0, space0);
//      pls.col0(1);
//      pls.lab("X Coordinate", "Y Coordinate", "Streamlines of flow");
//      pls.setcontlabelparam(0.006, 0.3, 0.1, 0);
//
        polar();
//        pls.setcontlabelparam(0.006, 0.3, 0.1, 1);
//      polar();
//      pls.setcontlabelparam(0.006, 0.3, 0.1, 0);
//
        potential();
//        pls.setcontlabelparam(0.006, 0.3, 0.1, 1);
//      potential();
//      pls.setcontlabelparam(0.006, 0.3, 0.1, 0);
//
        pls.end();
    }

    void polar()
    // polar contour plot example.
    {
        int i, j;
        double[] px   = new double[PERIMETERPTS];
        double[] py   = new double[PERIMETERPTS];
        double[][] xg = new double[RPTS][THETAPTS];
        double[][] yg = new double[RPTS][THETAPTS];
        double[][] z  = new double[RPTS][THETAPTS];
        double t, r, theta;
        double [] lev = new double[10];

        pls.env( -1., 1., -1., 1., 0, -2 );
        pls.col0( 1 );

        // Perimeter
        for ( i = 0; i < PERIMETERPTS; i++ )
        {
            t     = ( 2. * Math.PI / ( PERIMETERPTS - 1 ) ) * i;
            px[i] = Math.cos( t );
            py[i] = Math.sin( t );
        }
        pls.line( px, py );

        // Create data to be contoured.

        for ( i = 0; i < RPTS; i++ )
        {
            r = i / (double) ( RPTS - 1 );
            for ( j = 0; j < THETAPTS; j++ )
            {
                theta    = ( 2. * Math.PI / ( THETAPTS - 1 ) ) * j;
                xg[i][j] = r * Math.cos( theta );
                yg[i][j] = r * Math.sin( theta );
                z[i][j]  = r;
            }
        }

        for ( i = 0; i < 10; i++ )
        {
            lev[i] = 0.05 + 0.10 * i;
        }

        pls.col0( 2 );
        pls.cont( z, 1, RPTS, 1, THETAPTS, lev, xg, yg );
        pls.col0( 1 );
        pls.lab( "", "", "Polar Contour Plot" );
    }

// Compute min and max value of a 2-d array.

    void f2mnmx( double[][] f, int nx, int ny )
    {
        fmax = f[0][0];
        fmin = fmax;

        for ( int i = 0; i < nx; i++ )
            for ( int j = 0; j < ny; j++ )
            {
                if ( f[i][j] < fmin ) fmin = f[i][j];
                if ( f[i][j] > fmax ) fmax = f[i][j];
            }
    }

    final void potential()
    // Shielded potential contour plot example.
    {
        int    i, j;

        double rmax, xmin, xmax, x0, ymin, ymax, y0, zmin, zmax;
        double peps, xpmin, xpmax, ypmin, ypmax;
        double eps, q1, d1, q1i, d1i, q2, d2, q2i, d2i;
        double div1, div1i, div2, div2i;
        double [][] xg = new double[PRPTS][PTHETAPTS];
        double [][] yg = new double[PRPTS][PTHETAPTS];
        double [][] z  = new double[PRPTS][PTHETAPTS];
        int    nlevelneg, nlevelpos;
        double dz, clev;
        double [] clevelneg_store = new double[PNLEVEL];
        double [] clevelpos_store = new double[PNLEVEL];
        int ncollin, ncolbox, ncollab;
        double [] px = new double[PPERIMETERPTS];
        double [] py = new double[PPERIMETERPTS];
        double t, r, theta;

        // Create data to be contoured.

        //java wants r unambiguously initialized for rmax below.
        r = 0.;
        for ( i = 0; i < PRPTS; i++ )
        {
            r = 0.5 + i;
            for ( j = 0; j < PTHETAPTS; j++ )
            {
                theta    = ( 2. * Math.PI / ( PTHETAPTS - 1 ) ) * ( 0.5 + j );
                xg[i][j] = r * Math.cos( theta );
                yg[i][j] = r * Math.sin( theta );
            }
        }

        rmax = r;

        f2mnmx( xg, PRPTS, PTHETAPTS );
        xmin = fmin;
        xmax = fmax;

        f2mnmx( yg, PRPTS, PTHETAPTS );
        ymin = fmin;
        ymax = fmax;

        x0 = ( xmin + xmax ) / 2.;
        y0 = ( ymin + ymax ) / 2.;

        // Expanded limits
        peps  = 0.05;
        xpmin = xmin - Math.abs( xmin ) * peps;
        xpmax = xmax + Math.abs( xmax ) * peps;
        ypmin = ymin - Math.abs( ymin ) * peps;
        ypmax = ymax + Math.abs( ymax ) * peps;

        // Potential inside a conducting cylinder (or sphere) by method of images.
        // Charge 1 is placed at (d1, d1), with image charge at (d2, d2).
        // Charge 2 is placed at (d1, -d1), with image charge at (d2, -d2).
        // Also put in smoothing term at small distances.

        eps = 2.;

        q1 = 1.;
        d1 = rmax / 4.;

        q1i = -q1 * rmax / d1;
        d1i = Math.pow( rmax, 2 ) / d1;

        q2 = -1.;
        d2 = rmax / 4.;

        q2i = -q2 * rmax / d2;
        d2i = Math.pow( rmax, 2 ) / d2;

        for ( i = 0; i < PRPTS; i++ )
        {
            for ( j = 0; j < PTHETAPTS; j++ )
            {
                div1    = Math.sqrt( Math.pow( xg[i][j] - d1, 2 ) + Math.pow( yg[i][j] - d1, 2 ) + Math.pow( eps, 2 ) );
                div1i   = Math.sqrt( Math.pow( xg[i][j] - d1i, 2 ) + Math.pow( yg[i][j] - d1i, 2 ) + Math.pow( eps, 2 ) );
                div2    = Math.sqrt( Math.pow( xg[i][j] - d2, 2 ) + Math.pow( yg[i][j] + d2, 2 ) + Math.pow( eps, 2 ) );
                div2i   = Math.sqrt( Math.pow( xg[i][j] - d2i, 2 ) + Math.pow( yg[i][j] + d2i, 2 ) + Math.pow( eps, 2 ) );
                z[i][j] = q1 / div1 + q1i / div1i + q2 / div2 + q2i / div2i;
            }
        }

        f2mnmx( z, PRPTS, PTHETAPTS );
        zmin = fmin;
        zmax = fmax;

        //	printf("%.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g \n",
        //  q1, d1, q1i, d1i, q2, d2, q2i, d2i);
        //  System.out.println(xmin);
        //  System.out.println(xmax);
        //  System.out.println(ymin);
        //  System.out.println(ymax);
        //  System.out.println(zmin);
        //  System.out.println(zmax);

        // Positive and negative contour levels.
        dz        = ( zmax - zmin ) / PNLEVEL;
        nlevelneg = 0;
        nlevelpos = 0;
        for ( i = 0; i < PNLEVEL; i++ )
        {
            clev = zmin + ( i + 0.5 ) * dz;
            if ( clev <= 0. )
                clevelneg_store[nlevelneg++] = clev;
            else
                clevelpos_store[nlevelpos++] = clev;
        }
        // Colours!
        ncollin = 11;
        ncolbox = 1;
        ncollab = 2;

        // Finally start plotting this page!
        pls.adv( 0 );
        pls.col0( ncolbox );

        pls.vpas( 0.1, 0.9, 0.1, 0.9, 1.0 );
        pls.wind( xpmin, xpmax, ypmin, ypmax );
        pls.box( "", 0., 0, "", 0., 0 );

        pls.col0( ncollin );
        if ( nlevelneg > 0 )
        {
            // Negative contours
            pls.lsty( 2 );
            // The point here is to copy results into an array of the correct size
            // which is essential for the java wrapper of plplot to work correctly.
            double [] clevelneg = new double[nlevelneg];
            System.arraycopy( clevelneg_store, 0, clevelneg, 0, nlevelneg );
            pls.cont( z, 1, PRPTS, 1, PTHETAPTS, clevelneg, xg, yg );
        }

        if ( nlevelpos > 0 )
        {
            // Positive contours
            pls.lsty( 1 );
            double [] clevelpos = new double[nlevelpos];
            // The point here is to copy results into an array of the correct size
            // which is essential for the java wrapper of plplot to work correctly.
            System.arraycopy( clevelpos_store, 0, clevelpos, 0, nlevelpos );
            pls.cont( z, 1, PRPTS, 1, PTHETAPTS, clevelpos, xg, yg );
        }

        // Draw outer boundary
        for ( i = 0; i < PPERIMETERPTS; i++ )
        {
            t     = ( 2. * Math.PI / ( PPERIMETERPTS - 1 ) ) * i;
            px[i] = x0 + rmax * Math.cos( t );
            py[i] = y0 + rmax * Math.sin( t );
        }

        pls.col0( ncolbox );
        pls.line( px, py );

        pls.col0( ncollab );
        pls.lab( "", "", "Shielded potential of charges in a conducting sphere" );
    }
}

//--------------------------------------------------------------------------
//                              End of x09.java
//--------------------------------------------------------------------------
