org.hortonmachine.gears.libs.monitor.IHMProgressMonitor - java examples

Here are the examples of the java api org.hortonmachine.gears.libs.monitor.IHMProgressMonitor taken from open source projects. By voting up you can indicate which examples are most useful and appropriate.

76 Examples 7

19 View Complete Implementation : IUHDiffusionSurface.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
/**
 * @author Silvia Franceschi (www.hydrologis.com)
 * @author Andrea Antonello (www.hydrologis.com)
 */
public clreplaced IUHDiffusionSurface {

    private double[][] ampi_diffusion = null;

    private double[][] ampi = null;

    private double diffusionparameter = 0f;

    private double vc = 0f;

    private double delta = 0f;

    private double xres = 0f;

    private double yres = 0f;

    private double npixel = 0f;

    private final IHMProgressMonitor pm;

    /**
     * @param out
     */
    public IUHDiffusionSurface(double[][] _ampi, ParameterBox fixedParameters, IHMProgressMonitor pm) {
        ampi = _ampi;
        this.pm = pm;
        delta = fixedParameters.getDelta();
        double threshold = 5000f;
        ampi_diffusion = new double[(int) (ampi.length + threshold / delta)][ampi[0].length];
        for (int i = 0; i < ampi.length; i++) {
            ampi_diffusion[i][0] = ampi[i][0];
        }
        for (int i = 1; i < threshold / delta; i++) {
            ampi_diffusion[ampi.length - 1 + i][0] = ampi[ampi.length - 1][0] + i * delta;
        }
        diffusionparameter = fixedParameters.getDiffusionparameter();
        vc = fixedParameters.getVc();
        xres = fixedParameters.getXres();
        yres = fixedParameters.getYres();
        npixel = fixedParameters.getNpixel();
    }

    public double[][] calculateIUH() {
        double replaced = 0f;
        double t = 0;
        double integral = 0;
        /*
         * next part calculates the convolution between the aplitude function and the diffusion
         * equation
         */
        ConvolutionDiffusionWidth diffIntegral = new ConvolutionDiffusionWidth(0.0, ampi_diffusion[ampi_diffusion.length - 1][0], IntegralConstants.diffusionmaxsteps, IntegralConstants.diffusionaccurancy, ampi, diffusionparameter, t);
        pm.beginTask("Calculating diffusion...", ampi_diffusion.length - 1);
        for (int i = 0; i < ampi_diffusion.length - 1; i++) {
            t = ampi_diffusion[i + 1][0];
            diffIntegral.updateTime((int) t);
            integral = diffIntegral.integrate();
            ampi_diffusion[i + 1][1] = integral;
            replaced += integral * delta / (xres * yres * npixel * vc);
            ampi_diffusion[i + 1][2] = replaced;
            pm.worked(1);
        }
        pm.done();
        return ampi_diffusion;
    }
}

19 View Complete Implementation : IUHDiffusion.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
/**
 * @author Andrea Antonello - www.hydrologis.com
 * @author Silvia Franceschi - www.hydrologis.com
 */
public clreplaced IUHDiffusion implements IUHCalculator {

    private double[][] totalampidiffusion = null;

    private double tpmax = 0f;

    private double tstarmax = 0f;

    private double[][] ampisubsurface = null;

    private double[][] ampidiffsurface = null;

    private final IHMProgressMonitor pm;

    /**
     * @param effectsBox
     * @param fixedParams
     * @param pm
     */
    public IUHDiffusion(EffectsBox effectsBox, ParameterBox fixedParams, IHMProgressMonitor pm) {
        this.pm = pm;
        double n_idf = fixedParams.getN_idf();
        double area = fixedParams.getArea();
        double timestep = fixedParams.getTimestep();
        double delta_sup = fixedParams.getDelta();
        double delta_sub = fixedParams.getDelta_sub();
        double vc = fixedParams.getVc();
        double prov = 0f;
        double dt = 0f;
        double tstar = 0f;
        double error = 100f;
        double area_tot = 0f;
        double area_sub = 0f;
        double[][] ampi_super = effectsBox.getAmpi();
        IUHDiffusionSurface iuhDiffSurface = new IUHDiffusionSurface(ampi_super, fixedParams, pm);
        ampidiffsurface = iuhDiffSurface.calculateIUH();
        if (effectsBox.ampi_subExists()) {
            area_sub = fixedParams.getArea_sub();
            double[][] ampi_help_sub = effectsBox.getAmpi_sub();
            IUHSubSurface iuhSubSurface = new IUHSubSurface(ampi_help_sub, fixedParams, pm);
            ampisubsurface = iuhSubSurface.calculateIUH();
        }
        double tcorr = ampidiffsurface[ampidiffsurface.length - 1][0];
        totalampidiffusion = calculateTotalDiffusion(ampidiffsurface, ampisubsurface, delta_sup, delta_sub, vc, tcorr, area_sub, area);
        /*
         * next calculates the maximum rain time
         */
        if (effectsBox.ampi_subExists()) {
            area_tot = area_sub + area;
        } else {
            area_tot = area;
        }
        /*
         * Skip the tpmax calculation if real rainfall data
         */
        if (effectsBox.rainDataExists()) {
            tpmax = 0f;
            return;
        }
        int index = 0;
        int threshold = (int) (tcorr / 100);
        pm.beginTask("IUH Diffusion...", (int) tcorr);
        for (int tp = 1; tp <= tcorr; tp += timestep) {
            if (index > threshold) {
                index = 0;
            } else {
                index++;
            }
            dt = ModelsEngine.henderson(totalampidiffusion, tp);
            tstar = tp + dt;
            if (tstar < tcorr) {
                prov = n_idf - 1 + (tp * (double) ModelsEngine.width_interpolate(totalampidiffusion, tstar, 0, 1) / (area_tot * ((double) ModelsEngine.width_interpolate(totalampidiffusion, tstar, 0, 2) - (double) ModelsEngine.width_interpolate(totalampidiffusion, dt, 0, 2))));
                if (Math.abs(prov) < error) {
                    tpmax = tp;
                    tstarmax = tpmax + dt;
                    error = Math.abs(prov);
                }
            }
            pm.worked((int) timestep);
        }
        pm.done();
    }

    /**
     * Calculate the total IUH by summing the superficial and the subsuperficial IUH
     *
     * @param ampidiffsurface
     * @param ampidiffsubsurface
     * @return
     */
    private double[][] calculateTotalDiffusion(double[][] ampidiffsurface, double[][] ampisubsurface, double delta_sup, double delta_sub, double vc, double tcorr, double area_sub, double area_super) {
        double[][] totaldiff = null;
        if (ampisubsurface == null) {
            totaldiff = new double[ampidiffsurface.length][3];
            totaldiff = ampidiffsurface;
        } else {
            /*
             * calculate how many rows are in ampi_sub after ampi_sup has finished
             */
            int rowinampisubwhereampisupfinishes = 0;
            for (int i = 0; i < ampisubsurface.length; i++) {
                if (ampisubsurface[i][0] >= ampidiffsurface[ampidiffsurface.length - 1][0]) {
                    rowinampisubwhereampisupfinishes = i;
                    break;
                }
            }
            int totallength = ampidiffsurface.length + ampisubsurface.length - rowinampisubwhereampisupfinishes;
            totaldiff = new double[totallength][3];
            double intsub = 0f;
            double intsup = 0f;
            for (int i = 0; i < ampidiffsurface.length; i++) {
                totaldiff[i][0] = ampidiffsurface[i][0];
                intsub = (double) ModelsEngine.width_interpolate(ampisubsurface, ampidiffsurface[i][0], 0, 1);
                intsup = ampidiffsurface[i][1];
                if (isNovalue(intsub)) {
                    pm.errorMessage("Found undefined interpolated value for subsuperficial. Not summing it. Index: " + i);
                    totaldiff[i][1] = intsup;
                } else {
                    totaldiff[i][1] = intsup + intsub;
                }
            }
            for (int i = ampidiffsurface.length, j = rowinampisubwhereampisupfinishes; i < totallength; i++, j++) {
                totaldiff[i][0] = ampisubsurface[j][0];
                totaldiff[i][1] = ampisubsurface[j][1];
            }
            /*
             * calculation of the third column = replacedulated The normalization occurs by means of the
             * superficial delta in the first part of the hydrogram, i.e. until the superficial
             * contributes, after that the delta is the one of the subsuperficial.
             */
            double replaced = 0f;
            for (int i = 0; i < ampidiffsurface.length; i++) {
                replaced = replaced + (totaldiff[i][1] * delta_sup) / ((area_super + area_sub) * vc);
                totaldiff[i][2] = replaced;
            }
            for (int i = ampidiffsurface.length, j = rowinampisubwhereampisupfinishes; i < totallength; i++, j++) {
                replaced = replaced + (totaldiff[i][1] * delta_sub) / ((area_super + area_sub) * vc);
                totaldiff[i][2] = replaced;
            }
        }
        return totaldiff;
    }

    /*
     * (non-Javadoc)
     * @see bsh.commands.h.peakflow.iuh.IUHCalculator#calculateIUH()
     */
    public double[][] calculateIUH() {
        return totalampidiffusion;
    }

    /*
     * (non-Javadoc)
     * @see bsh.commands.h.peakflow.iuh.IUHCalculator#getTpMax()
     */
    public double getTpMax() {
        return tpmax;
    }

    /*
     * (non-Javadoc)
     * @see bsh.commands.h.peakflow.iuh.IUHCalculator#getTstarMax()
     */
    public double getTstarMax() {
        return tstarmax;
    }

    public double[][] getIUHSuperficial() {
        return ampidiffsurface;
    }

    public double[][] getIUHSubsuperficial() {
        return ampisubsurface;
    }
}

19 View Complete Implementation : RungeKuttaFelberg.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
/**
 * An implementation of the Runge-Kutta-Felberg algorithm for solving non-linear ordinary
 * differential equations. It uses a time step control algorithm to avoid numerical errors while
 * solving the equations
 *
 * @author Ricardo Mantilla
 */
public clreplaced RungeKuttaFelberg {

    private DuffyModel duffy;

    /**
     * An array containing the value of the function that was last calculated by the RKF algoritm
     */
    private double[] finalCond;

    private double epsilon;

    private double basicTimeStepInMinutes = 10. / 60.;

    // private double[] a = {0., 1. / 5., 3. / 10., 3. / 5., 1., 7. / 8.};
    private double[][] b = { { 0. }, { 1. / 5. }, { 3. / 40., 9. / 40. }, { 3. / 10., -9. / 10., 6. / 5. }, { -11. / 54., 5. / 2., -70. / 27., 35. / 27. }, { 1631. / 55296., 175. / 512., 575. / 13824., 44275. / 110592., 253. / 4096. } };

    private double[] c = { 37. / 378., 0., 250. / 621., 125. / 594., 0., 512. / 1771. };

    private double[] cStar = { 2825. / 27648., 0., 18575. / 48384., 13525. / 55296., 277. / 14336., 1. / 4. };

    private final boolean doLog;

    private boolean isAtFinalSubtimestep = true;

    private IHMProgressMonitor outputStream;

    /**
     * Creates new RKF
     *
     * @param fu The differential equation to solve described by a {@link IBasicFunction}
     * @param eps The value error allowed by the step forward algorithm
     * @param basTs The step size
     * @param doLog
     */
    public RungeKuttaFelberg(DuffyModel fu, double eps, double basTs, IHMProgressMonitor out, boolean doLog) {
        duffy = fu;
        epsilon = eps;
        basicTimeStepInMinutes = basTs;
        this.outputStream = out;
        this.doLog = doLog;
    }

    /**
     * Returns the value of the function described by differential equations in the next time step
     *
     * @param currentTimeInMinutes The current time
     * @param initialConditions The value of the initial condition
     * @param timeStepInMinutes The desired step size
     * @param finalize A boolean indicating in the timeStep provided is final or if it needs to be
     *        refined
     * @param currentSolution
     * @param rainArray
     * @param etpArray
     */
    private void step(double currentTimeInMinutes, double[] initialConditions, double timeStepInMinutes, boolean finalize, CurrentTimestepSolution currentSolution, double[] rainArray, double[] etpArray) {
        double[] carrier = new double[initialConditions.length];
        double[] k0 = duffy.eval(currentTimeInMinutes, initialConditions, rainArray, etpArray, false);
        for (int i = 0; i < initialConditions.length; i++) carrier[i] = Math.max(0, initialConditions[i] + timeStepInMinutes * b[1][0] * k0[i]);
        double[] k1 = duffy.eval(currentTimeInMinutes, carrier, rainArray, etpArray, false);
        for (int i = 0; i < initialConditions.length; i++) carrier[i] = Math.max(0, initialConditions[i] + timeStepInMinutes * (b[2][0] * k0[i] + b[2][1] * k1[i]));
        double[] k2 = duffy.eval(currentTimeInMinutes, carrier, rainArray, etpArray, false);
        for (int i = 0; i < initialConditions.length; i++) carrier[i] = Math.max(0, initialConditions[i] + timeStepInMinutes * (b[3][0] * k0[i] + b[3][1] * k1[i] + b[3][2] * k2[i]));
        double[] k3 = duffy.eval(currentTimeInMinutes, carrier, rainArray, etpArray, false);
        for (int i = 0; i < initialConditions.length; i++) carrier[i] = Math.max(0, initialConditions[i] + timeStepInMinutes * (b[4][0] * k0[i] + b[4][1] * k1[i] + b[4][2] * k2[i] + b[4][3] * k3[i]));
        double[] k4 = duffy.eval(currentTimeInMinutes, carrier, rainArray, etpArray, false);
        for (int i = 0; i < initialConditions.length; i++) carrier[i] = Math.max(0, initialConditions[i] + timeStepInMinutes * (b[5][0] * k0[i] + b[5][1] * k1[i] + b[5][2] * k2[i] + b[5][3] * k3[i] + b[5][4] * k4[i]));
        double[] k5 = duffy.eval(currentTimeInMinutes, carrier, rainArray, etpArray, isAtFinalSubtimestep);
        double[] newY = new double[initialConditions.length];
        for (int i = 0; i < initialConditions.length; i++) {
            newY[i] = initialConditions[i] + timeStepInMinutes * (c[0] * k0[i] + c[1] * k1[i] + c[2] * k2[i] + c[3] * k3[i] + c[4] * k4[i] + c[5] * k5[i]);
            newY[i] = Math.max(0, newY[i]);
            if (Double.isInfinite(newY[i]) || newY[i] != newY[i]) {
                throw new ModelsIllegalargumentException("An error occurred during the integration procedure.", this);
            }
        }
        double[] newYstar = new double[initialConditions.length];
        for (int i = 0; i < initialConditions.length; i++) {
            newYstar[i] = initialConditions[i] + timeStepInMinutes * (cStar[0] * k0[i] + cStar[1] * k1[i] + cStar[2] * k2[i] + cStar[3] * k3[i] + cStar[4] * k4[i] + cStar[5] * k5[i]);
            newYstar[i] = Math.max(0, newYstar[i]);
            if (Double.isInfinite(newYstar[i]) || newYstar[i] != newYstar[i]) {
                throw new ModelsIllegalargumentException("An error occurred during the integration procedure.", this);
            }
        }
        double delta = 0;
        for (int i = 0; i < initialConditions.length; i++) {
            if ((newY[i] + newYstar[i]) > 0)
                delta = Math.max(delta, Math.abs(2 * (newY[i] - newYstar[i]) / (newY[i] + newYstar[i])));
        }
        double newTimeStepInMinutes = timeStepInMinutes;
        if (finalize) {
            currentSolution.newTimeStepInMinutes = newTimeStepInMinutes;
            currentSolution.solution = newY;
        } else {
            double factor;
            if (delta != 0.0) {
                factor = epsilon / delta;
                if (factor >= 1)
                    newTimeStepInMinutes = timeStepInMinutes * Math.pow(factor, 0.15);
                else
                    newTimeStepInMinutes = timeStepInMinutes * Math.pow(factor, 0.25);
            } else {
                factor = 1e8;
                newTimeStepInMinutes = timeStepInMinutes * Math.pow(factor, 0.15);
                finalize = true;
            }
            // System.out.println(" --> "+timeStep+" "+epsilon+" "+Delta+" "+factor+"
            // "+newTimeStep+" ("+java.util.Calendar.getInstance().getTime()+")");
            step(currentTimeInMinutes, initialConditions, newTimeStepInMinutes, true, currentSolution, rainArray, etpArray);
        }
    }

    public void printDate(double minutes) {
        double millis = minutes * 1000d * 60d;
        System.out.println(new DateTime((long) millis).toString(HMConstants.utcDateFormatterYYYYMMDDHHMM));
    }

    /**
     * Writes (in ascii format) to a specified file the values of the function described by
     * differential equations in the the intermidia steps requested to go from the Initial to the
     * Final time. This method is very specific for solving equations of flow in a network. It
     * prints output for the flow component at all locations.
     *
     * @param intervalStartTimeInMinutes The initial time of the solution
     * @param intervalEndTimeInMinutes The final time of the solution
     * @param timeStepInMinutes How often the values are desired
     * @param initialConditions The value of the initial condition
     * @param etpArray
     */
    @SuppressWarnings("nls")
    public void solve(DateTime currentTimstamp, int modelTimestepInMinutes, double internalTimestepInMinutes, double[] initialConditions, double[] rainArray, double[] etpArray) throws IOException {
        isAtFinalSubtimestep = false;
        double intervalStartTimeInMinutes = currentTimstamp.getMillis() / 1000d / 60d;
        double intervalEndTimeInMinutes = intervalStartTimeInMinutes + modelTimestepInMinutes;
        // the running time inside the interval
        double currentTimeInMinutes = intervalStartTimeInMinutes;
        // the end time inside the interval
        double targetTimeInMinutes = intervalStartTimeInMinutes;
        // the object holding the iterated solution and internal timestep
        CurrentTimestepSolution currentSolution = new CurrentTimestepSolution();
        while (currentTimeInMinutes < intervalEndTimeInMinutes) {
            /*
             * split the user set time interval into smaller intervals of time timeStepInMinutes.
             */
            targetTimeInMinutes = currentTimeInMinutes + internalTimestepInMinutes;
            while (currentTimeInMinutes < targetTimeInMinutes) {
                /*
                 * inside step the intervals of time timeStepInMinutes are splitted again in
                 * intervals that begin with basicTimeStepInMinutes and are changed while iteration.
                 */
                step(currentTimeInMinutes, initialConditions, basicTimeStepInMinutes, false, currentSolution, rainArray, etpArray);
                if (currentTimeInMinutes + currentSolution.newTimeStepInMinutes > targetTimeInMinutes) {
                    break;
                }
                basicTimeStepInMinutes = currentSolution.newTimeStepInMinutes;
                currentTimeInMinutes += basicTimeStepInMinutes;
                currentSolution.newTimeStepInMinutes = currentTimeInMinutes;
                initialConditions = currentSolution.solution;
                for (int i = 0; i < initialConditions.length; i++) {
                    if (initialConditions[i] != initialConditions[i]) {
                        throw new ModelsIllegalargumentException("Problems occure during the integration procedure.", this.getClreplaced().getSimpleName());
                    }
                }
            }
            if (Math.abs(targetTimeInMinutes - intervalEndTimeInMinutes) < .0000001) {
                break;
            }
            step(currentTimeInMinutes, initialConditions, targetTimeInMinutes - currentTimeInMinutes, true, currentSolution, rainArray, etpArray);
            if (currentTimeInMinutes + currentSolution.newTimeStepInMinutes >= intervalEndTimeInMinutes) {
                break;
            }
            if (initialConditions[0] < 1e-3) {
                System.out.println("Discharge in outlet less than the threshold.");
                break;
            }
            basicTimeStepInMinutes = currentSolution.newTimeStepInMinutes;
            currentTimeInMinutes += basicTimeStepInMinutes;
            currentSolution.newTimeStepInMinutes = currentTimeInMinutes;
            initialConditions = currentSolution.solution;
            for (int i = 0; i < initialConditions.length; i++) {
                if (initialConditions[i] != initialConditions[i]) {
                    throw new ModelsIllegalargumentException("Problems occure during the integration procedure.", this.getClreplaced().getSimpleName());
                }
            }
            if (doLog) {
                outputStream.message("->  " + new DateTime((long) (currentTimeInMinutes * 60.0 * 1000.0)).toString(OmsAdige.adigeFormatter) + " / " + new DateTime((long) (intervalEndTimeInMinutes * 60. * 1000.)).toString(OmsAdige.adigeFormatter) + " Outlet Duffy Discharge: " + initialConditions[0]);
            }
        // int hillslopeNum = rainArray.length;
        // for( int i = 0; i < hillslopeNum; i++ ) {
        // System.out.println(i + " Discharge " + initialConditions[i] + " qsub "
        // + initialConditions[i + hillslopeNum] + " S1 "
        // + initialConditions[i + 2 * hillslopeNum] + " S2 "
        // + initialConditions[i + 3 * hillslopeNum] + " rain " + rainArray[i]);
        // System.out.println("----------------------");
        // }
        // double avg = 0.0;
        // for( int i = 0; i < rainArray.length; i++ ) {
        // avg = avg + rainArray[i];
        // }
        // avg = avg / rainArray.length;
        // System.out.println("Outlet Discharge " + initialConditions[0] + " qsub "
        // + initialConditions[hillslopeNum] + " S1 "
        // + initialConditions[2 * hillslopeNum] + " S2 "
        // + initialConditions[3 * hillslopeNum] + " rain " + avg);
        }
        isAtFinalSubtimestep = true;
        // 
        if (NumericsUtilities.dEq(currentTimeInMinutes, intervalEndTimeInMinutes) && initialConditions[0] > 1e-3) {
            step(currentTimeInMinutes, initialConditions, intervalEndTimeInMinutes - currentTimeInMinutes - 1. / 60., true, currentSolution, rainArray, etpArray);
            basicTimeStepInMinutes = currentSolution.newTimeStepInMinutes;
            currentTimeInMinutes += basicTimeStepInMinutes;
            currentSolution.newTimeStepInMinutes = currentTimeInMinutes;
            initialConditions = currentSolution.solution;
            for (int i = 0; i < initialConditions.length; i++) {
                if (initialConditions[i] != initialConditions[i]) {
                    throw new ModelsIllegalargumentException("Problems occure during the integration procedure.", this.getClreplaced().getSimpleName());
                }
            }
            double sum = 0;
            for (double d : rainArray) {
                sum = sum + d;
            }
            sum = sum / rainArray.length;
            int hillslopeNum = rainArray.length;
            double currentDischarge = initialConditions[0] + initialConditions[hillslopeNum];
            outputStream.message("->  " + new DateTime((long) (currentTimeInMinutes * 60.0 * 1000.0)).toString(OmsAdige.adigeFormatter) + " / " + new DateTime((long) (intervalEndTimeInMinutes * 60. * 1000.)).toString(OmsAdige.adigeFormatter) + " " + currentDischarge + " with avg rain: " + sum);
        } else {
            outputStream.errorMessage("WARNING, UNEXPECTED");
        }
        finalCond = initialConditions;
    }

    public double[] getFinalCond() {
        return finalCond;
    }
}

19 View Complete Implementation : QuickSortAlgorithmObjects.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
/**
 * Sorting of a double array with an array of objects following.
 *
 * @author Andrea Antonello (www.hydrologis.com)
 */
public clreplaced QuickSortAlgorithmObjects {

    private double[] valuesToSort;

    private int number;

    private Object[] valuesToFollow;

    private IHMProgressMonitor monitor = new LogProgressMonitor();

    public QuickSortAlgorithmObjects(IHMProgressMonitor monitor) {
        if (monitor != null)
            this.monitor = monitor;
    }

    /**
     * Sorts an array of values and moves with the sort a second array.
     *
     * @param values the array to sort.
     * @param valuesToFollow the array that should be sorted following the
     *              indexes of the first array. Can be null.
     */
    public void sort(double[] values, Object[] valuesToFollow) {
        this.valuesToSort = values;
        this.valuesToFollow = valuesToFollow;
        number = values.length;
        monitor.beginTask("Sorting...", -1);
        monitor.worked(1);
        quicksort(0, number - 1);
        monitor.done();
    }

    private void quicksort(int low, int high) {
        int i = low, j = high;
        // Get the pivot element from the middle of the list
        double pivot = valuesToSort[(low + high) >>> 1];
        // Divide into two lists
        while (i <= j) {
            // If the current value from the left list is smaller then the pivot
            // element then get the next element from the left list
            while (valuesToSort[i] < pivot || (isNovalue(valuesToSort[i]) && !isNovalue(pivot))) {
                i++;
            }
            // If the current value from the right list is larger then the pivot
            // element then get the next element from the right list
            while (valuesToSort[j] > pivot || (!isNovalue(valuesToSort[j]) && isNovalue(pivot))) {
                j--;
            }
            // If we have found a values in the left list which is larger then
            // the pivot element and if we have found a value in the right list
            // which is smaller then the pivot element then we exchange the
            // values.
            // As we are done we can increase i and j
            if (i <= j) {
                exchange(i, j);
                i++;
                j--;
            }
        }
        // Recursion
        if (low < j)
            quicksort(low, j);
        if (i < high)
            quicksort(i, high);
    }

    private void exchange(int i, int j) {
        double temp = valuesToSort[i];
        valuesToSort[i] = valuesToSort[j];
        valuesToSort[j] = temp;
        if (valuesToFollow != null) {
            Object tempFollow = valuesToFollow[i];
            valuesToFollow[i] = valuesToFollow[j];
            valuesToFollow[j] = tempFollow;
        }
    }
}

19 View Complete Implementation : QuickSortAlgorithm.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
public clreplaced QuickSortAlgorithm {

    private double[] valuesToSortDouble;

    private float[] valuesToSortFloat;

    private int number;

    private double[] valuesToFollowDouble;

    private float[] valuesToFollowFloat;

    private int[] valuesToFollowInt;

    private IHMProgressMonitor monitor = new LogProgressMonitor();

    public QuickSortAlgorithm(IHMProgressMonitor monitor) {
        if (monitor != null)
            this.monitor = monitor;
    }

    /**
     * Sorts an array of double values and moves with the sort a second array.
     *
     * @param values the array to sort.
     * @param valuesToFollow the array that should be sorted following the
     *              indexes of the first array. Can be null.
     */
    public void sort(double[] values, double[] valuesToFollow) {
        this.valuesToSortDouble = values;
        this.valuesToFollowDouble = valuesToFollow;
        number = values.length;
        monitor.beginTask("Sorting...", -1);
        monitor.worked(1);
        quicksort(0, number - 1);
        monitor.done();
    }

    /**
     * Sorts an array of float values and moves with the sort a second array.
     *
     * @param values the array to sort.
     * @param valuesToFollow the array that should be sorted following the
     *              indexes of the first array. Can be null.
     */
    public void sort(float[] values, float[] valuesToFollow) {
        this.valuesToSortFloat = values;
        this.valuesToFollowFloat = valuesToFollow;
        number = values.length;
        monitor.beginTask("Sorting...", -1);
        monitor.worked(1);
        quicksortFloat(0, number - 1);
        monitor.done();
    }

    public void sort(double[] values, int[] valuesToFollow) {
        this.valuesToSortDouble = values;
        this.valuesToFollowInt = valuesToFollow;
        number = values.length;
        monitor.beginTask("Sorting...", -1);
        monitor.worked(1);
        quicksortInt(0, number - 1);
        monitor.done();
    }

    private void quicksort(int low, int high) {
        int i = low, j = high;
        // Get the pivot element from the middle of the list
        double pivot = valuesToSortDouble[(low + high) >>> 1];
        // Divide into two lists
        while (i <= j) {
            // If the current value from the left list is smaller then the pivot
            // element then get the next element from the left list
            while (valuesToSortDouble[i] < pivot || (isNovalue(valuesToSortDouble[i]) && !isNovalue(pivot))) {
                i++;
            }
            // If the current value from the right list is larger then the pivot
            // element then get the next element from the right list
            while (valuesToSortDouble[j] > pivot || (!isNovalue(valuesToSortDouble[j]) && isNovalue(pivot))) {
                j--;
            }
            // If we have found a values in the left list which is larger then
            // the pivot element and if we have found a value in the right list
            // which is smaller then the pivot element then we exchange the
            // values.
            // As we are done we can increase i and j
            if (i <= j) {
                exchange(i, j);
                i++;
                j--;
            }
        }
        // Recursion
        if (low < j)
            quicksort(low, j);
        if (i < high)
            quicksort(i, high);
    }

    private void quicksortFloat(int low, int high) {
        int i = low, j = high;
        // Get the pivot element from the middle of the list
        double pivot = valuesToSortFloat[(low + high) >>> 1];
        // Divide into two lists
        while (i <= j) {
            // If the current value from the left list is smaller then the pivot
            // element then get the next element from the left list
            while (valuesToSortFloat[i] < pivot || (isNovalue(valuesToSortFloat[i]) && !isNovalue(pivot))) {
                i++;
            }
            // If the current value from the right list is larger then the pivot
            // element then get the next element from the right list
            while (valuesToSortFloat[j] > pivot || (!isNovalue(valuesToSortFloat[j]) && isNovalue(pivot))) {
                j--;
            }
            // If we have found a values in the left list which is larger then
            // the pivot element and if we have found a value in the right list
            // which is smaller then the pivot element then we exchange the
            // values.
            // As we are done we can increase i and j
            if (i <= j) {
                exchangeFloat(i, j);
                i++;
                j--;
            }
        }
        // Recursion
        if (low < j)
            quicksortFloat(low, j);
        if (i < high)
            quicksortFloat(i, high);
    }

    private void quicksortInt(int low, int high) {
        int i = low, j = high;
        // Get the pivot element from the middle of the list
        double pivot = valuesToSortDouble[(low + high) >>> 1];
        // Divide into two lists
        while (i <= j) {
            // If the current value from the left list is smaller then the pivot
            // element then get the next element from the left list
            while (valuesToSortDouble[i] < pivot || (isNovalue(valuesToSortDouble[i]) && !isNovalue(pivot))) {
                i++;
            }
            // If the current value from the right list is larger then the pivot
            // element then get the next element from the right list
            while (valuesToSortDouble[j] > pivot || (!isNovalue(valuesToSortDouble[j]) && isNovalue(pivot))) {
                j--;
            }
            // If we have found a values in the left list which is larger then
            // the pivot element and if we have found a value in the right list
            // which is smaller then the pivot element then we exchange the
            // values.
            // As we are done we can increase i and j
            if (i <= j) {
                exchangeDoubleInt(i, j);
                i++;
                j--;
            }
        }
        // Recursion
        if (low < j)
            quicksortInt(low, j);
        if (i < high)
            quicksortInt(i, high);
    }

    private void exchange(int i, int j) {
        double temp = valuesToSortDouble[i];
        valuesToSortDouble[i] = valuesToSortDouble[j];
        valuesToSortDouble[j] = temp;
        if (valuesToFollowDouble != null) {
            double tempFollow = valuesToFollowDouble[i];
            valuesToFollowDouble[i] = valuesToFollowDouble[j];
            valuesToFollowDouble[j] = tempFollow;
        }
    }

    private void exchangeFloat(int i, int j) {
        float temp = valuesToSortFloat[i];
        valuesToSortFloat[i] = valuesToSortFloat[j];
        valuesToSortFloat[j] = temp;
        if (valuesToFollowFloat != null) {
            float tempFollow = valuesToFollowFloat[i];
            valuesToFollowFloat[i] = valuesToFollowFloat[j];
            valuesToFollowFloat[j] = tempFollow;
        }
    }

    private void exchangeDoubleInt(int i, int j) {
        double temp = valuesToSortDouble[i];
        valuesToSortDouble[i] = valuesToSortDouble[j];
        valuesToSortDouble[j] = temp;
        if (valuesToFollowInt != null) {
            int tempFollow = valuesToFollowInt[i];
            valuesToFollowInt[i] = valuesToFollowInt[j];
            valuesToFollowInt[j] = tempFollow;
        }
    }
}

19 View Complete Implementation : IUHSubSurface.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
/**
 * @author Silvia Franceschi (www.hydrologis.com)
 * @author Andrea Antonello (www.hydrologis.com)
 * @author Silvano Pisoni
 */
public clreplaced IUHSubSurface {

    private double[][] ampi_sub = null;

    private double[][] ampi_help = null;

    private double vc = 0f;

    private double delta_sub = 0f;

    private double xres = 0f;

    private double yres = 0f;

    private double npixel_sub = 0f;

    private double resid_time = 0f;

    private final IHMProgressMonitor pm;

    public IUHSubSurface(double[][] _ampi, ParameterBox fixedParameters, IHMProgressMonitor pm) {
        ampi_help = _ampi;
        this.pm = pm;
        ampi_sub = new double[ampi_help.length][ampi_help[0].length];
        for (int i = 0; i < ampi_help.length; i++) {
            ampi_sub[i][0] = ampi_help[i][0];
        }
        vc = fixedParameters.getVc();
        delta_sub = fixedParameters.getDelta_sub();
        xres = fixedParameters.getXres();
        yres = fixedParameters.getYres();
        npixel_sub = fixedParameters.getNpixel_sub();
        resid_time = fixedParameters.getResid_time();
    }

    public double[][] calculateIUH() {
        double replaced = 0f;
        double t = 0;
        double integral = 0;
        /*
         * next part calculates the convolution between the aplitude function and the exponential
         * equation
         */
        pm.beginTask("Calculating subsurface IUH...", ampi_help.length - 1);
        for (int i = 0; i < ampi_help.length - 1; i++) {
            t = ampi_sub[i + 1][0];
            double upperintegrationlimit = ampi_sub[ampi_sub.length - 1][0];
            ConvolutionExponentialPeakflow expIntegral = new ConvolutionExponentialPeakflow(0.0, upperintegrationlimit, 20, 0.00001, ampi_help, resid_time, t);
            integral = expIntegral.integrate();
            ampi_sub[i + 1][1] = integral;
            /*
             * if (isScs) { replaced += integral delta_sub / (xres yres npixel_sub vc / vcvv); } else {
             */
            replaced += integral * delta_sub / (xres * yres * npixel_sub * vc);
            ampi_sub[i + 1][2] = replaced;
            pm.worked(1);
        }
        pm.done();
        return ampi_sub;
    }
}

19 View Complete Implementation : HillSlopeDuffy.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
public Geometry getGeometry(List<PfafstetterNumber> limit, IHMProgressMonitor pm, boolean doMonitor) {
    return hillSlope.getGeometry(limit, pm, doMonitor);
}

18 View Complete Implementation : JGrassRasterMapReader.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
/**
 * Creates a {@link JGrreplacedRasterMapReader} following the builder pattern.
 *
 * <p>
 * This clreplaced makes it easier to create a reader for GRreplaced rasters.
 * </p>
 *
 * @author Andrea Antonello (www.hydrologis.com)
 * @since 1.1.0
 */
public clreplaced JGrreplacedRasterMapReader {

    /**
     * Builder to create {@link JGrreplacedRasterMapReader} through the path
     * of the Map.
     *
     * <p>Required parameters are:
     * <ul>
     * <li>the region to read</li>
     * <li>the path to the map</li>
     * </ul>
     * </p>
     * <p>Optional parameters are:
     * <ul>
     * <li>the number to use internally instead of the map novalues</li>
     * <li>the raster map type to read (ex. {@link GrreplacedLegacyConstans#GRreplacedBINARYRASTERMAP})</li>
     * <li>a monitor object</li>
     * </ul>
     * </p>
     */
    public static clreplaced BuilderFromMapPath {

        // required parameters
        private final String mapPath;

        private final Window readWindow;

        // optional parameters
        private double novalue = GrreplacedLegacyConstans.defaultNovalue;

        private String maptype = GrreplacedLegacyConstans.GRreplacedBINARYRASTERMAP;

        private IHMProgressMonitor monitor = new LogProgressMonitor();

        /**
         * Constructor for the {@link BuilderFromGeoresource} with the required parameters.
         *
         * @param readWindow the active region to read from.
         * @param resource the {@link IGeoResource}.
         */
        public BuilderFromMapPath(Window readWindow, String mapPath) {
            this.readWindow = readWindow;
            this.mapPath = mapPath;
        }

        /**
         * Sets the optional novalue.
         *
         * @param novalue the novalue to be used.
         * @return the builder object to allow chaining.
         */
        public BuilderFromMapPath novalue(double novalue) {
            this.novalue = novalue;
            return this;
        }

        /**
         * Sets the optional maptype value.
         *
         * @param maptype the maptype to be used.
         * @return the builder object to allow chaining.
         */
        public BuilderFromMapPath maptype(String maptype) {
            this.maptype = maptype;
            return this;
        }

        /**
         * Sets the optional monitor object.
         *
         * @param monitor the monitor to be used.
         * @return the builder object to allow chaining.
         */
        public BuilderFromMapPath monitor(IHMProgressMonitor monitor) {
            this.monitor = monitor;
            return this;
        }

        /**
         * Builds the {@link JGrreplacedRasterMapReader}.
         *
         * @return the JGrreplacedRasterMapReader with the supplied parameters.
         */
        public JGrreplacedRasterMapReader build() {
            return new JGrreplacedRasterMapReader(this);
        }
    }

    /**
     * Builder to create {@link JGrreplacedRasterMapReader} through the path
     * of the Location and the name of Mapset and Map.
     *
     * <p>Required parameters are:
     * <ul>
     * <li>the region to read</li>
     * <li>the path to the Location</li>
     * <li>the name of the mapset</li>
     * <li>the name of the map</li>
     * </ul>
     * </p>
     * <p>Optional parameters are:
     * <ul>
     * <li>the number to use internally instead of the map novalues</li>
     * <li>the raster map type to read (ex. {@link GrreplacedLegacyConstans#GRreplacedBINARYRASTERMAP})</li>
     * <li>a monitor object</li>
     * </ul>
     * </p>
     */
    public static clreplaced BuilderFromPathAndNames {

        // required parameters
        private Window readWindow = null;

        private String mapName = null;

        private String mapsetName = null;

        private String locationPath = null;

        // optional parameters
        private double novalue = GrreplacedLegacyConstans.defaultNovalue;

        private String maptype = GrreplacedLegacyConstans.GRreplacedBINARYRASTERMAP;

        private IHMProgressMonitor monitor = new LogProgressMonitor();

        /**
         * Constructor for the {@link BuilderFromGeoresource} with the required paraeters.
         *
         * @param readWindow the active region to read from.
         * @param resource the {@link IGeoResource}.
         */
        public BuilderFromPathAndNames(Window readWindow, String mapName, String mapsetName, String locationPath) {
            this.readWindow = readWindow;
            this.mapName = mapName;
            this.mapsetName = mapsetName;
            this.locationPath = locationPath;
        }

        /**
         * Sets the optional novalue.
         *
         * @param novalue the novalue to be used.
         * @return the builder object to allow chaining.
         */
        public BuilderFromPathAndNames novalue(double novalue) {
            this.novalue = novalue;
            return this;
        }

        /**
         * Sets the optional maptype value.
         *
         * @param maptype the maptype to be used.
         * @return the builder object to allow chaining.
         */
        public BuilderFromPathAndNames maptype(String maptype) {
            this.maptype = maptype;
            return this;
        }

        /**
         * Sets the optional monitor object.
         *
         * @param monitor the monitor to be used.
         * @return the builder object to allow chaining.
         */
        public BuilderFromPathAndNames monitor(IHMProgressMonitor monitor) {
            this.monitor = monitor;
            return this;
        }

        /**
         * Builds the {@link JGrreplacedRasterMapReader}.
         *
         * @return the JGrreplacedRasterMapReader with the supplied parameters.
         */
        public JGrreplacedRasterMapReader build() {
            return new JGrreplacedRasterMapReader(this);
        }
    }

    private MapReader reader = null;

    private IHMProgressMonitor monitor = null;

    private String mapName = null;

    private String mapsetName = null;

    private String locationPath = null;

    private boolean hasMoreData = false;

    private String mapPath;

    private String fullMapPath = null;

    /**
     * Creates a jgrreplaced raster map reader through a builder.
     *
     * @param builder the builder.
     */
    private JGrreplacedRasterMapReader(BuilderFromPathAndNames builder) {
        this.monitor = builder.monitor;
        this.mapName = builder.mapName;
        this.mapsetName = builder.mapsetName;
        this.locationPath = builder.locationPath;
        reader = MapIOFactory.createGrreplacedRasterMapReader(builder.maptype);
        reader.setParameter("novalue", (new Double(builder.novalue)));
        reader.setDataWindow(builder.readWindow);
        reader.setOutputDataObject(new double[0][0]);
        fullMapPath = locationPath + File.separator + mapsetName + File.separator + GrreplacedLegacyConstans.CELL + File.separator + mapName;
    }

    /**
     * Creates a jgrreplaced raster map reader through a builder.
     *
     * @param builder the builder.
     */
    private JGrreplacedRasterMapReader(BuilderFromMapPath builder) {
        this.monitor = builder.monitor;
        this.mapPath = builder.mapPath;
        reader = MapIOFactory.createGrreplacedRasterMapReader(builder.maptype);
        reader.setParameter("novalue", (new Double(builder.novalue)));
        reader.setDataWindow(builder.readWindow);
        reader.setOutputDataObject(new double[0][0]);
        fullMapPath = mapPath;
    }

    /**
     * <p>
     * Opens the raster map and does some first checking
     * </p>
     *
     * @return true if everything went alright
     */
    public boolean open() {
        boolean ok;
        if (mapPath != null) {
            ok = reader.open(mapPath);
        } else if (locationPath != null && mapsetName != null && mapName != null) {
            ok = reader.open(mapName, locationPath, mapsetName);
        } else {
            return false;
        }
        return ok;
    }

    /**
     * @return true if more data are available
     */
    public boolean hasMoreData() throws IOException {
        try {
            if (reader.hasMoreData(monitor)) {
                hasMoreData = true;
            }
            return hasMoreData;
        } catch (Exception e) {
            e.printStackTrace();
            throw new IOException(e.getLocalizedMessage());
        }
    }

    /**
     * @return a next unit of data from the reader
     */
    public RasterData getNextData() {
        if (hasMoreData) {
            return new JGrreplacedRasterData((double[][]) reader.getNextData());
        }
        return null;
    }

    /**
     * This replacedures a range only after the data were read at least once
     *
     * @return the range
     */
    public double[] getRange() {
        return reader.getRange();
    }

    /**
     * @return the reader that takes care of the raster reading.
     */
    public MapReader getReader() {
        return reader;
    }

    /**
     * close the reader
     */
    public void close() {
        if (reader != null) {
            reader.close();
        }
    }

    public String getFullMapPath() {
        return fullMapPath;
    }
}

18 View Complete Implementation : JGrassRasterMapWriter.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
/**
 * <p>
 * Facility to write JGrreplaced maps
 * </p>
 *
 * @author Andrea Antonello - www.hydrologis.com
 * @since 1.1.0
 */
public clreplaced JGrreplacedRasterMapWriter {

    private MapWriter writer = null;

    private IHMProgressMonitor monitor = new LogProgressMonitor();

    private String mapName = null;

    private String mapsetName = null;

    private String locationPath = null;

    private String mapPath;

    private String fullMapPath = null;

    /**
     * <p>
     * Creates a jgrreplaced raster map writer with some default values
     * </p>
     * <p>
     * <b>NOTE:</b> This doesn't need a working udig environment to run. It just uses paths.
     * Thought also for batch usage.
     * </p>
     *
     * @param writeWindow the region to read
     * @param mapName the name of the map
     * @param mapsetName the name of the mapset
     * @param locationPath the path to the location
     * @param _novalue the value to write as novalue
     * @param mapType the raster map type to read (ex. {@link GrreplacedLegacyConstans#GRreplacedBINARYRASTERMAP})
     * @param monitor a monitor object (if no monitro present, {@link NullProgressMonitor} can be
     *        used)
     */
    public JGrreplacedRasterMapWriter(Window writeWindow, String mapName, String mapsetName, String locationPath, Object novalue, String mapType, IHMProgressMonitor monitor) {
        this.monitor = monitor;
        this.mapName = mapName;
        this.mapsetName = mapsetName;
        this.locationPath = locationPath;
        writer = MapIOFactory.createGrreplacedRasterMapWriter(mapType);
        writer.setDataWindow(writeWindow);
        writer.setParameter("novalue", novalue);
        // write data to
        writer.setOutputDataObject(new Double(2));
        writer.setHistoryComment("Created by JGrreplaced in " + new Date().toString());
        fullMapPath = locationPath + File.separator + mapsetName + File.separator + GrreplacedLegacyConstans.CELL + File.separator + mapName;
    }

    /**
     * <p>
     * Creates a jgrreplaced raster map writer with some default values
     * </p>
     * <p>
     * <b>NOTE:</b> This doesn't need a working udig environment to run. It just uses paths.
     * Thought also for batch usage.
     * </p>
     *
     * @param writeWindow the region to read
     * @param mapName the name of the map
     * @param mapsetName the name of the mapset
     * @param locationPath the path to the location
     * @param _novalue the value to write as novalue
     * @param mapType the raster map type to read (ex. {@link GrreplacedLegacyConstans#GRreplacedBINARYRASTERMAP})
     * @param monitor a monitor object (if no monitro present, {@link NullProgressMonitor} can be
     *        used)
     */
    public JGrreplacedRasterMapWriter(Window writeWindow, String mapPath, Object novalue, String mapType, IHMProgressMonitor monitor) {
        this.monitor = monitor;
        this.mapPath = mapPath;
        writer = MapIOFactory.createGrreplacedRasterMapWriter(mapType);
        writer.setDataWindow(writeWindow);
        writer.setParameter("novalue", novalue);
        // write data to
        writer.setOutputDataObject(new Double(2));
        writer.setHistoryComment("Created by JGrreplaced in " + new Date().toString());
        fullMapPath = mapPath;
    }

    /**
     * <p>
     * Creates a jgrreplaced raster map writer with some default values
     * </p>
     * <p>
     * <b>NOTE:</b> This doesn't need a working udig environment to run. It just uses paths.
     * Thought also for batch usage.
     * </p>
     *
     * @param writeWindow the region to read
     * @param mapName the name of the map
     * @param mapsetName the name of the mapset
     * @param locationPath the path to the location
     * @param _novalue the value to write as novalue
     * @param monitor a monitor object (if no monitro present, {@link NullProgressMonitor} can be
     *        used)
     */
    public JGrreplacedRasterMapWriter(Window writeWindow, String mapName, String mapsetName, String locationPath, Object novalue, IHMProgressMonitor monitor) {
        this(writeWindow, mapName, mapsetName, locationPath, novalue, GrreplacedLegacyConstans.GRreplacedBINARYRASTERMAP, monitor);
    }

    /**
     * <p>
     * Creates a jgrreplaced raster map writer with some default values
     * </p>
     * <p>
     * <b>NOTE:</b> This doesn't need a working udig environment to run. It just uses paths.
     * Thought also for batch usage.
     * </p>
     *
     * @param writeWindow the region to read
     * @param mapName the name of the map
     * @param mapsetName the name of the mapset
     * @param locationPath the path to the location
     * @param mapType the raster map type to read (ex. {@link GrreplacedLegacyConstans#GRreplacedBINARYRASTERMAP})
     * @param monitor a monitor object (if no monitro present, {@link NullProgressMonitor} can be
     *        used)
     */
    public JGrreplacedRasterMapWriter(Window writeWindow, String mapName, String mapsetName, String locationPath, String mapType, IHMProgressMonitor monitor) {
        this(writeWindow, mapName, mapsetName, locationPath, GrreplacedLegacyConstans.defaultNovalue, mapType, monitor);
    }

    /**
     * <p>
     * Creates a jgrreplaced raster map reader with some default values (data are read as double values,
     * novalue is default {@link GrreplacedLegacyConstans#defaultNovalue}).
     * </p>
     * <p>
     * <b>NOTE:</b> This doesn't need a working udig environment to run. It just uses paths.
     * Thought also for batch usage.
     * </p>
     *
     * @param writeWindow the region to read
     * @param mapName the name of the map
     * @param mapsetName the name of the mapset
     * @param locationPath the path to the location
     * @param monitor a monitor object (if no monitro present, {@link NullProgressMonitor} can be
     *        used)
     */
    public JGrreplacedRasterMapWriter(Window writeWindow, String mapName, String mapsetName, String locationPath, IHMProgressMonitor monitor) {
        this(writeWindow, mapName, mapsetName, locationPath, GrreplacedLegacyConstans.defaultNovalue, GrreplacedLegacyConstans.GRreplacedBINARYRASTERMAP, monitor);
    }

    /**
     * <p>
     * Opens the raster map and does some first checking
     * </p>
     *
     * @return true if everything went alright
     */
    public boolean open() throws RasterWritingFailureException {
        boolean ok;
        if (mapPath != null) {
            ok = writer.open(mapPath);
        } else if (locationPath != null && mapsetName != null && mapName != null) {
            ok = writer.open(mapName, locationPath, mapsetName);
        } else {
            return false;
        }
        return ok;
    }

    /**
     * <p>
     * Write the rasterData to disk.
     * </p>
     *
     * @param rasterData
     * @return true if everything went well
     * @throws Exception
     */
    public boolean write(RasterData rasterData) throws RasterWritingFailureException {
        try {
            return writer.write(rasterData);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RasterWritingFailureException(e.getLocalizedMessage());
        }
    }

    public void close() {
        writer.close();
    }

    public String getFullMapPath() {
        return fullMapPath;
    }

    public void cloneColorTableFromReader(JGrreplacedRasterMapReader jgReader) throws IOException {
        // start
        String readerMapPath = jgReader.getFullMapPath();
        String tmpMapName = new File(readerMapPath).getName();
        File mapsetFile = new File(readerMapPath).getParentFile().getParentFile();
        String colorFilePath = mapsetFile.getAbsolutePath() + File.separator + GrreplacedLegacyConstans.COLR + File.separator + tmpMapName;
        // destination
        String destMapName = new File(fullMapPath).getName();
        File destMapsetFile = new File(fullMapPath).getParentFile().getParentFile();
        String destColorFilePath = destMapsetFile.getAbsolutePath() + File.separator + GrreplacedLegacyConstans.COLR + File.separator + destMapName;
        // copy it over
        FileUtilities.copyFile(colorFilePath, destColorFilePath);
    }

    public void cloneCategoriesFromReader(JGrreplacedRasterMapReader jgReader) throws IOException {
        // start
        String readerMapPath = jgReader.getFullMapPath();
        String tmpMapName = new File(readerMapPath).getName();
        File mapsetFile = new File(readerMapPath).getParentFile().getParentFile();
        String catsFilePath = mapsetFile.getAbsolutePath() + File.separator + GrreplacedLegacyConstans.CATS + File.separator + tmpMapName;
        // destination
        String destMapName = new File(fullMapPath).getName();
        File destMapsetFile = new File(fullMapPath).getParentFile().getParentFile();
        String destCatsFilePath = destMapsetFile.getAbsolutePath() + File.separator + GrreplacedLegacyConstans.CATS + File.separator + destMapName;
        // copy it over
        FileUtilities.copyFile(catsFilePath, destCatsFilePath);
    }
}

18 View Complete Implementation : OmsShapefileFeatureWriter.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
public static void writeShapefile(String path, SimpleFeatureCollection featureCollection, IHMProgressMonitor pm) throws IOException {
    OmsShapefileFeatureWriter writer = new OmsShapefileFeatureWriter();
    if (pm != null) {
        writer.pm = pm;
    }
    writer.file = path;
    writer.geodata = featureCollection;
    writer.writeFeatureCollection();
}

18 View Complete Implementation : OmsShapefileFeatureWriter.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
public static void writeEmptyShapefile(String path, SimpleFeatureType schema, IHMProgressMonitor pm) throws IOException {
    OmsShapefileFeatureWriter writer = new OmsShapefileFeatureWriter();
    if (pm != null) {
        writer.pm = pm;
    }
    writer.file = path;
    writer.pType = schema;
    writer.writeFeatureCollection();
}

18 View Complete Implementation : StatisticJeff.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
/**
 * @author Andrea Antonello (www.hydrologis.com)
 */
public clreplaced StatisticJeff {

    private ParameterBox fixedParams = null;

    private double tpmax = 0f;

    private final IHMProgressMonitor pm;

    /**
     * @param fixedParameters
     * @param tp_max
     * @param pm
     */
    public StatisticJeff(ParameterBox fixedParameters, double tp_max, IHMProgressMonitor pm) {
        fixedParams = fixedParameters;
        tpmax = tp_max;
        this.pm = pm;
    }

    public double[][] calculateJeff() {
        pm.message("Calculating Jeff...");
        double n_idf = fixedParams.getN_idf();
        double a_idf = fixedParams.getA_idf();
        /*
         * multiplied by 1/3600 1/(1000*3600) gives us Jeff in m/s
         */
        double J = a_idf * Math.pow(tpmax / 3600.0, n_idf - 1) / (1000.0 * 3600.0);
        double h = a_idf * Math.pow(tpmax / 3600.0, n_idf) / 1000.0;
        double[][] result = new double[1][2];
        result[0][0] = J;
        result[0][1] = h;
        return result;
    }
}

18 View Complete Implementation : ThreadedRunnable.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
/**
 * Mulreplacedhreading util clreplaced.
 *
 * @author Andrea Antonello (www.hydrologis.com)
 */
public clreplaced ThreadedRunnable<E> {

    private ExecutorService fixedThreadPool;

    private ConcurrentLinkedQueue<E> queue = new ConcurrentLinkedQueue<E>();

    private IHMProgressMonitor pm;

    public ThreadedRunnable(int numThreads, IHMProgressMonitor pm) {
        this.pm = pm;
        fixedThreadPool = Executors.newFixedThreadPool(numThreads);
    }

    public void executeRunnable(Runnable runner) {
        fixedThreadPool.execute(runner);
    }

    public void waitAndClose() {
        try {
            fixedThreadPool.shutdown();
            fixedThreadPool.awaitTermination(30, TimeUnit.DAYS);
            fixedThreadPool.shutdownNow();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (pm != null) {
            pm.done();
        }
    }

    public void addToQueue(E item) {
        queue.add(item);
    }

    public ConcurrentLinkedQueue<E> getQueue() {
        return queue;
    }

    public void setWorkLoad(String task, int workLoad) {
        if (pm != null) {
            if (task == null) {
                task = "Processing...";
            }
            pm.beginTask(task, workLoad);
        }
    }

    public synchronized void worked(int process) {
        if (pm != null)
            pm.worked(process);
    }
}

18 View Complete Implementation : OpenstreetmapImageCreator.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
public clreplaced OpenstreetmapImageCreator {

    private static final String EPSG_MERCATOR = "EPSG:3857";

    private String inServiceUrl;

    private int zoomLevel;

    private ReferencedEnvelope mercatorBounds;

    private IHMProgressMonitor pm;

    private File outFile;

    /**
     * @param inServiceUrl The OSM tile service to use (XXX, YYY, ZZZ will be subsreplaceduted by tile indexes and zoom level).
     * @param zoomLevel The zoom level to use.
     * @param inBounds The area to consider in 3875.
     * @param pm The progress monitor.
     * @return the image.
     * @throws Exception
     */
    public OpenstreetmapImageCreator(String inServiceUrl, int zoomLevel, ReferencedEnvelope mercatorBounds, File outFile, IHMProgressMonitor pm) {
        this.inServiceUrl = inServiceUrl;
        this.zoomLevel = zoomLevel;
        this.mercatorBounds = mercatorBounds;
        this.outFile = outFile;
        this.pm = pm;
    }

    public void generate() throws Exception {
        CoordinateReferenceSystem mercatorCrs = CrsUtilities.getCrsFromEpsg(EPSG_MERCATOR, null);
        CoordinateReferenceSystem latLongCrs = DefaultGeographicCRS.WGS84;
        ReferencedEnvelope llBounds = mercatorBounds.transform(latLongCrs, true);
        double w = llBounds.getMinX();
        double e = llBounds.getMaxX();
        double s = llBounds.getMinY();
        double n = llBounds.getMaxY();
        int[] ulTileNumber = getTileXY(n, w, zoomLevel);
        int[] lrTileNumber = getTileXY(s, e, zoomLevel);
        int startXTile = ulTileNumber[0];
        int startYTile = ulTileNumber[1];
        int endXTile = lrTileNumber[0];
        int endYTile = lrTileNumber[1];
        BoundingBox bbUL = tile2boundingBox(startXTile, startYTile, zoomLevel);
        double imageW = bbUL.west;
        double imageN = bbUL.north;
        BoundingBox bbLR = tile2boundingBox(endXTile, endYTile, zoomLevel);
        double imageS = bbLR.south;
        double imageE = bbLR.east;
        int tileCols = endXTile - startXTile + 1;
        int tileRows = endYTile - startYTile + 1;
        int tileSize = 256;
        int height = tileRows * tileSize;
        int width = tileCols * tileSize;
        BufferedImage outImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = (Graphics2D) outImage.getGraphics();
        pm.beginTask("Generating tiles at zoom level: " + zoomLevel + " with tiles: " + tileCols + "x" + tileRows, (endXTile - startXTile + 1));
        int runningX = 0;
        for (int x = startXTile; x <= endXTile; x++) {
            int runningY = 0;
            for (int y = startYTile; y <= endYTile; y++) {
                // int[] tmsNUms = getTileXY(y, x, zoomLevel);
                String tmp = inServiceUrl.replaceFirst("ZZZ", String.valueOf(zoomLevel));
                tmp = tmp.replaceFirst("XXX", String.valueOf(x));
                tmp = tmp.replaceFirst("YYY", String.valueOf(y));
                URL url = new URL(tmp);
                try {
                    BufferedImage tileImage = ImageIO.read(url);
                    g2d.drawImage(tileImage, null, runningX, runningY);
                } catch (Exception ex) {
                    pm.errorMessage("Unable to get image: " + tmp);
                }
                runningY += tileSize;
            }
            runningX += tileSize;
            pm.worked(1);
        }
        pm.done();
        g2d.dispose();
        String nameL = outFile.getName().toLowerCase();
        if (nameL.endsWith("png")) {
            ImageIO.write(outImage, "png", outFile);
        } else if (nameL.endsWith("jpg")) {
            ImageIO.write(outImage, "jpg", outFile);
        } else if (nameL.endsWith("tiff")) {
            ImageIO.write(outImage, "tiff", outFile);
        }
        MathTransform transform = CRS.findMathTransform(latLongCrs, mercatorCrs);
        Coordinate llES = new Coordinate(imageE, imageS);
        Coordinate llWN = new Coordinate(imageW, imageN);
        Coordinate osmES = JTS.transform(llES, null, transform);
        Coordinate osmWN = JTS.transform(llWN, null, transform);
        // create tfw
        double dx = (osmES.x - osmWN.x) / width;
        double dy = (osmWN.y - osmES.y) / height;
        StringBuilder sb = new StringBuilder();
        sb.append(dx).append("\n");
        sb.append("0.00000000").append("\n");
        sb.append("0.00000000").append("\n");
        sb.append(-dy).append("\n");
        sb.append(osmWN.x).append("\n");
        sb.append(osmWN.y).append("\n");
        String fileName = FileUtilities.getNameWithoutExtention(outFile);
        File folder = outFile.getParentFile();
        File tfwFile = new File(folder, fileName + ".tfw");
        FileUtilities.writeFile(sb.toString(), tfwFile);
        // create prj
        File prjFile = new File(folder, fileName + ".prj");
        FileUtilities.writeFile(mercatorCrs.toWKT(), prjFile);
    }

    private static int[] getTileXY(final double lat, final double lon, final int zoom) {
        int xtile = (int) Math.floor((lon + 180) / 360 * (1 << zoom));
        int ytile = (int) Math.floor((1 - Math.log(Math.tan(Math.toRadians(lat)) + 1 / Math.cos(Math.toRadians(lat))) / Math.PI) / 2 * (1 << zoom));
        if (xtile < 0)
            xtile = 0;
        if (xtile >= (1 << zoom))
            xtile = ((1 << zoom) - 1);
        if (ytile < 0)
            ytile = 0;
        if (ytile >= (1 << zoom))
            ytile = ((1 << zoom) - 1);
        return new int[] { xtile, ytile };
    }

    private clreplaced BoundingBox {

        double north;

        double south;

        double east;

        double west;
    }

    private BoundingBox tile2boundingBox(final int x, final int y, final int zoom) {
        BoundingBox bb = new BoundingBox();
        bb.north = tile2lat(y, zoom);
        bb.south = tile2lat(y + 1, zoom);
        bb.west = tile2lon(x, zoom);
        bb.east = tile2lon(x + 1, zoom);
        return bb;
    }

    private static double tile2lon(int x, int z) {
        return x / Math.pow(2.0, z) * 360.0 - 180.0;
    }

    private static double tile2lat(int y, int z) {
        double n = Math.PI - (2.0 * Math.PI * y) / Math.pow(2.0, z);
        return Math.toDegrees(Math.atan(Math.sinh(n)));
    }

    public static void main(String[] args) throws Exception {
        String outFile = "/home/hydrologis/Dropbox/hydrologis/lavori/2015_05_bim_sarcamincio/shape_3857/image_output/osm15.png";
        String bounds = "/home/hydrologis/Dropbox/hydrologis/lavori/2015_05_bim_sarcamincio/shape_3857/area.shp";
        String inServiceUrl = "http://a.tile.opencyclemap.org/cycle/ZZZ/XXX/YYY.png";
        // String inServiceUrl = "http://a.tile.openstreetmap.org/ZZZ/XXX/YYY.png";
        ReferencedEnvelope env = OmsVectorReader.readVector(bounds).getBounds();
        OpenstreetmapImageCreator c = new OpenstreetmapImageCreator(inServiceUrl, 15, env, new File(outFile), new LogProgressMonitor());
        c.generate();
    }
}

18 View Complete Implementation : Utility.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
/**
 * Verify if there is a key of a FeatureCollections.
 *
 * @param key
 * @throws IllegalArgumentException
 *             if the key is null.
 */
private static void verifyFeatureKey(String key, String searchedField, IHMProgressMonitor pm) {
    if (key == null) {
        if (pm != null) {
            pm.errorMessage(msg.message("trentoP.error.featureKey") + searchedField);
        }
        throw new IllegalArgumentException(msg.message("trentoP.error.featureKey") + searchedField);
    }
}

18 View Complete Implementation : LogConsoleController.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
public clreplaced LogConsoleController extends LogConsoleView {

    private IHMProgressMonitor pm = null;

    private String processName;

    private PrintStream logAreaPrintStream;

    public LogConsoleController(final IHMProgressMonitor pm) {
        if (pm != null)
            this.pm = pm;
        init();
    }

    private void init() {
        clearButton.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                // clears the text area
                try {
                    logArea.getDoreplacedent().remove(0, logArea.getDoreplacedent().getLength());
                } catch (BadLocationException ex) {
                    ex.printStackTrace();
                }
            }
        });
        clearButton.setIcon(ImageCache.getInstance().getImage(ImageCache.TRASH));
        copyButton.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                GuiUtilities.copyToClipboard(logArea.getText());
            }
        });
        copyButton.setIcon(ImageCache.getInstance().getImage(ImageCache.COPY));
        stopButton.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                if (pm != null)
                    pm.setCanceled(true);
                stopButton.setEnabled(false);
            }
        });
        stopButton.setIcon(ImageCache.getInstance().getImage(ImageCache.PROGRESS_STOP));
        logAreaPrintStream = new PrintStream(new CustomOutputStream(logArea));
        if (pm == null) {
            pm = new PrintStreamProgressMonitor(logAreaPrintStream, logAreaPrintStream);
        }
        // re-replacedigns standard output stream and error output stream
        System.setOut(logAreaPrintStream);
        System.setErr(logAreaPrintStream);
        setPreferredSize(new Dimension(480, 320));
        addComponentListener(new ComponentListener() {

            public void componentShown(ComponentEvent e) {
            }

            public void componentResized(ComponentEvent e) {
            }

            public void componentMoved(ComponentEvent e) {
            }

            public void componentHidden(ComponentEvent e) {
                stopLogging();
            }
        });
    }

    public PrintStream getLogAreaPrintStream() {
        return logAreaPrintStream;
    }

    public void beginProcess(String name) {
        processName = name;
        System.out.println("Process " + name + " started at: " + new DateTime().toString(HMConstants.dateTimeFormatterYYYYMMDDHHMMSS) + "\n\n");
    }

    public void finishProcess() {
        System.out.println("\n\nProcess " + processName + " stopped at: " + new DateTime().toString(HMConstants.dateTimeFormatterYYYYMMDDHHMMSS));
        stopButton.setEnabled(false);
    }

    public void stopLogging() {
        System.setOut(System.out);
        System.setErr(System.err);
    }

    public JComponent asJComponent() {
        return this;
    }

    public IHMProgressMonitor getProgressMonitor() {
        return pm;
    }
}

18 View Complete Implementation : Offtakes.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
/**
 * Utility clreplaced for handling of Offtakes mappings and data retrival.
 *
 * @author Andrea Antonello (www.hydrologis.com)
 */
public clreplaced Offtakes implements IDischargeContributor {

    private final HashMap<String, Integer> offtakes_pfaff2idMap;

    private HashMap<Integer, double[]> offtakes_id2valuesQMap;

    private final IHMProgressMonitor out;

    private String pNum;

    /**
     * Constructor.
     *
     * @param offtakes_pfaff2idMap {@link HashMap map} of pfafstetter numbers versus
     *                      offtakes points id.
     * @param out {@link PrintStream} for warning handling.
     */
    public Offtakes(HashMap<String, Integer> offtakes_pfaff2idMap, IHMProgressMonitor out) {
        this.offtakes_pfaff2idMap = offtakes_pfaff2idMap;
        this.out = out;
    }

    public Double getDischarge(String pNum) {
        this.pNum = pNum;
        Integer damId = offtakes_pfaff2idMap.get(pNum);
        if (damId != null) {
            double[] discharges = offtakes_id2valuesQMap.get(damId);
            return discharges[0];
        }
        return HMConstants.doubleNovalue;
    }

    public void setCurrentData(HashMap<Integer, double[]> currentDataMap) {
        offtakes_id2valuesQMap = currentDataMap;
    }

    public double mergeWithDischarge(double contributorDischarge, double inputDischarge) {
        if (inputDischarge >= contributorDischarge) {
            return inputDischarge - contributorDischarge;
        } else {
            out.errorMessage(MessageFormat.format("WARNING: offtake discharge at {0} is greater than the river discharge. Offtake discharge set to 0 to continue.", pNum));
            return inputDischarge;
        }
    }
}

17 View Complete Implementation : GeopackageTilesProducer.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
public clreplaced GeopackageTilesProducer implements ITilesProducer {

    private IHMProgressMonitor pm;

    private int minZoom;

    private int maxZoom;

    private int tileSize;

    private CoordinateReferenceSystem mercatorCrs;

    private ImageGenerator imageGen;

    private PreparedGeometry limitsGeom3857;

    public GeopackageTilesProducer(IHMProgressMonitor pm, String filePath, boolean isRaster, int minZoom, int maxZoom, int tileSize, PreparedGeometry limitsGeom3857) throws Exception {
        this.pm = pm;
        this.minZoom = minZoom;
        this.maxZoom = maxZoom;
        this.tileSize = tileSize;
        this.limitsGeom3857 = limitsGeom3857;
        mercatorCrs = CrsUtilities.getCrsFromEpsg("EPSG:" + GeopackageCommonDb.MERCATOR_SRID, null);
        imageGen = new ImageGenerator(pm, mercatorCrs);
        if (isRaster) {
            imageGen.addCoveragePath(filePath);
        } else {
            imageGen.addFeaturePath(filePath, null);
        }
        imageGen.setLayers();
    }

    @Override
    public int getMinZoom() {
        return minZoom;
    }

    @Override
    public int getMaxZoom() {
        return maxZoom;
    }

    @Override
    public boolean cancelled() {
        return pm.isCanceled();
    }

    @Override
    public int getTileSize() {
        return tileSize;
    }

    @Override
    public byte[] getTileData(Envelope tileBounds3857) {
        try {
            if (limitsGeom3857 != null) {
                Polygon envPoly = GeometryUtilities.createPolygonFromEnvelope(tileBounds3857);
                if (!limitsGeom3857.intersects(envPoly)) {
                    return null;
                }
            }
            BufferedImage dumpImage = imageGen.getImageWithCheck(new ReferencedEnvelope(tileBounds3857, mercatorCrs), tileSize, tileSize, 0.0, null);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(dumpImage, "png", baos);
            return baos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public void startWorkingOnZoomLevel(int zoomLevel, int workCount) {
        pm.beginTask("Working on zoom level " + zoomLevel, workCount);
    }

    @Override
    public void worked() {
        pm.worked(1);
    }

    @Override
    public void done() {
        pm.done();
    }

    @Override
    public Envelope areaConstraint() {
        if (limitsGeom3857 != null) {
            return limitsGeom3857.getGeometry().getEnvelopeInternal();
        }
        return null;
    }
}

17 View Complete Implementation : OmsGeopaparazzi4Converter.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
private void simpleNotesToShapefile(IHMConnection connection, File outputFolderFile, IHMProgressMonitor pm) throws Exception {
    File outputShapeFile = new File(outputFolderFile, "notes_simple.shp");
    SimpleFeatureCollection newCollection = simpleNotes2featurecollection(connection, pm);
    dumpVector(newCollection, outputShapeFile.getAbsolutePath());
}

17 View Complete Implementation : OmsGeopaparazzi4Converter.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
private void mediaToShapeFile(IHMConnection connection, File mediaFolderFile, IHMProgressMonitor pm) throws Exception {
    SimpleFeatureCollection newCollection = media2FeatureCollection(connection, mediaFolderFile, pm);
    File outputPointsShapeFile = new File(mediaFolderFile.getParentFile(), "mediapoints.shp");
    dumpVector(newCollection, outputPointsShapeFile.getAbsolutePath());
}

17 View Complete Implementation : HMModel.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
/**
 * Check on the progress monitor to see if the process was stopped.
 *
 * <p>Modules can use that internally to exit, if necessary.</p>
 *
 * @param pm the {@link IHMProgressMonitor progress monitor}.
 * @return true if the process was stopped.
 * @deprecated use directly the pm.isCanceled() or {@link #checkCancel()} instead.
 */
protected boolean isCanceled(IHMProgressMonitor pm) {
    if (pm.isCanceled()) {
        pm.done();
        return true;
    }
    return false;
}

17 View Complete Implementation : DuffyModel.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
/**
 * The duffy model.
 *
 * This clreplaced implements the set of non-linear ordinary differential equations
 * used to simulate flows along the river network. The function is writen as a
 * {@link IBasicFunction.util.ordDiffEqSolver.BasicFunction} that is used by the
 * {@link hydroScalingAPI.util.ordDiffEqSolver.RungeKuttaFelberg}
 *
 * @author Peter Furey
 * @author Andrea Antonello (www.hydrologis.com)
 * @author Silvia Franceschi (www.hydrologis.com)
 */
public clreplaced DuffyModel {

    private double qd, qs, Q_trib, Qs_trib;

    // public double pcoe;
    private double satsurf, mst, qdh, qds, inf, re, qe1, qe2;

    // 0.1Km2
    private double THRESHOLD_AREA = 500000;

    /*
     * HydroloGIS addons
     */
    public static final int ROUTING_CHEZY_NONEXPL = 2;

    public static final int ROUTING_CHEZY = 3;

    public static final int ROUTING_MANNING = 4;

    private static final double MSTMAX = 1;

    private int routingType = ROUTING_CHEZY;

    private List<IHillSlope> orderedHillslopes = null;

    private boolean doLog = false;

    private final IHMProgressMonitor pm;

    private boolean doPrint = false;

    private List<IDischargeContributor> dischargeContributorList = new ArrayList<IDischargeContributor>();

    private HashMap<Integer, ADischargeDistributor> hillslopeId2DischargeDistributor;

    /**
     * Duffy model function.
     *
     * @param linksList
     *            the list of all the network links, expressed through their
     *            OmsPfafstetter numbers
     * @param closureHillslope
     *            the most downstream hillslope in the replacedyzed basin
     * @param routingType
     *            the type of routing to be used
     * @param pm
     * @param deltaTinMinutes
     * @param doLog
     */
    public DuffyModel(List<IHillSlope> orderedHillslopes, int routingType, IHMProgressMonitor pm, boolean doLog) {
        this.orderedHillslopes = orderedHillslopes;
        this.routingType = routingType;
        this.pm = pm;
        this.doLog = doLog;
    }

    /**
     * Duffy function evaluation.
     * @param input
     *            initial condition values for every link. The structure is:
     *            <br>
     *            <ul>
     *            <li>link1 initial discharge</li>
     *            <li>link2 initial discharge</li>
     *            <li>link3 initial discharge</li>
     *            <li>...</li>
     *            <li>linkn initial discharge</li>
     *            <li>link1 subsurface and baseflow</li>
     *            <li>link2 subsurface and baseflow</li>
     *            <li>...</li>
     *            <li>linkn subsurface and baseflow</li>
     *            <li>link1 water storage in non saturated zone of the hillslope</li>
     *            <li>link2 water storage in non saturated zone of the hillslope</li>
     *            <li>...</li>
     *            <li>linkn water storage in non saturated zone of the hillslope</li>
     *            <li>link1 water storage in saturated zone of the hillslope</li>
     *            <li>link2 water storage in saturated zone of the hillslope</li>
     *            <li>...</li>
     *            <li>linkn water storage in saturated zone of the hillslope</li>
     *            </ul>
     * @param rainArray
     *            the array of precipitation (in mm/h) for each hillslope
     *            centroid (to be ordered in a consistent way with the
     *            linksList)
     * @param etpArray
     * @param timeinMinutes
     *            the time
     *
     * @return
     */
    public double[] eval(double currentTimeInMinutes, double[] input, double[] rainArray, double[] etpArray, boolean isAtFinalSubtimestep) {
        // the input's length is twice the number of links... the first half
        // corresponds to links
        // discharge and the second to hillslopes storage
        // System.out.println(input.length);
        // define the month
        long currentTimeInMillis = (long) (currentTimeInMinutes * 60.0 * 1000.0);
        // linksConectionStruct.headsArray.length;
        int linksNum = orderedHillslopes.size();
        // double mstold = 0.0;
        double[] output = new double[input.length];
        for (int i = linksNum - 1; i >= 0; i--) {
            // start from the last pieces
            HillSlopeDuffy currentHillslope = (HillSlopeDuffy) orderedHillslopes.get(i);
            Parameters parameters = currentHillslope.getParameters();
            /*
             * NOTE: Initial conditions are ... input[i] for link discharge
             * input[i+nLi] for link base flow input[i+2*nLi] for unsaturated
             * hillslope S1 input[i+3*nLi] for saturated hillslope S2 . input[]
             * is updated for each time step in DiffEqSolver.RKF .
             */
            // input precipitation is in mm/h
            double prec_mphr = rainArray[i] / 1000.0;
            double area_m2 = currentHillslope.getHillslopeArea();
            // automatically in m2 from the features
            /*
             * Added some check for phisic consistency of the parameters
             */
            // if (input[i + 3 * linksNum] != input[i + 3 * linksNum]) {
            // System.out.println();
            // }
            double minsupdischarge = parameters.getqqsupmin() * currentHillslope.getUpstreamArea(null) / 1E6;
            if (input[i] < minsupdischarge) {
                input[i] = minsupdischarge;
            // System.out
            // .println(
            // "Current superficial discharge is less than the minimum value, setted to it for the basin "
            // + currentHillslope.getHillslopeId());
            }
            double minsubdischarge = parameters.getqqsubmin() * currentHillslope.getUpstreamArea(null) / 1E6;
            if (input[i + linksNum] < minsubdischarge) {
                input[i + linksNum] = minsubdischarge;
            // System.out
            // .println(
            // "Current subsuperficial discharge is less than the minimum value, setted to it for the basin "
            // + currentHillslope.getHillslopeId());
            }
            if (input[i + 2 * linksNum] < parameters.getS1residual()) {
                input[i + 2 * linksNum] = parameters.getS1residual();
            // System.out
            // .println(
            // "Current S1 parameter is less than the minimum value, setted to it for the basin "
            // + currentHillslope.getHillslopeId());
            }
            if (input[i + 3 * linksNum] < parameters.getS2residual()) {
                input[i + 3 * linksNum] = parameters.getS2residual();
            // System.out
            // .println(
            // "Current S2 parameter is less than the minimum value, setted to it for the basin "
            // + currentHillslope.getHillslopeId());
            }
            /* HILLSLOPE FLUX CONDITIONS */
            // dimless
            satsurf = parameters.getS2Param() * (input[i + 3 * linksNum]);
            // double areasat = satsurf * area_m2;
            // dimless
            mst = (input[i + 2 * linksNum]) / (parameters.getS2max() - (input[i + 3 * linksNum]));
            if (Double.isInfinite(mst)) {
                mst = MSTMAX;
            }
            // if ((mst - mstold) > 0.01) {
            // System.out.println("mst " + mst + "mstold " + mstold);
            // mstold = mst;
            // }
            // Ku = hillSlopesInfo.Ks(currentHillslope)
            // * (Math.pow(mst, hillSlopesInfo.MstExp(currentHillslope))); //
            // mphr
            /* HILLSLOPE S1-SURFACE FLUX VALUES */
            if (prec_mphr < parameters.getKs()) {
                // m3phr
                inf = (1.0 - satsurf) * area_m2 * prec_mphr;
                // m3phr
                qdh = 0.0;
            } else {
                // m3phr
                inf = (1.0 - satsurf) * area_m2 * parameters.getKs();
                // m3phr
                qdh = (1.0 - satsurf) * area_m2 * (prec_mphr - parameters.getKs());
            }
            Double eTrate = parameters.getETrate();
            if (etpArray != null) {
                qe1 = etpArray[i];
            } else {
                if (input[i + 2 * linksNum] > parameters.getS1residual()) {
                    // m3phr
                    qe1 = eTrate * area_m2 * (1.0 - satsurf) * mst;
                } else {
                    qe1 = 0.0;
                }
            }
            /* HILLSLOPE S1-S2 FLUX VALUE */
            // re = 1100.0
            // * (input[i + 2 * linksNum] / parameters.getS2max())
            // + 300.0
            // * ((input[i + 2 * linksNum] / parameters.getS2max()) + 5)
            // * Math.pow((input[i + 3 * linksNum] / parameters.getS2max()),
            // 2.0);
            // m3phr
            re = parameters.getKs() * area_m2 * (1.0 - satsurf) * (Math.pow(mst, parameters.getMstExp()));
            /* HILLSLOPE S2-SURFACE FLUX VALUES */
            // m3phr
            qds = satsurf * area_m2 * prec_mphr;
            if (etpArray != null) {
                qe2 = etpArray[i];
            } else {
                // m3phr,
                qe2 = eTrate * area_m2 * satsurf;
            }
            // m3phr
            qs = parameters.getRecParam() * (input[i + 3 * linksNum]);
            /* HILLSLOPE DIRECT RUNOFF (TOTAL) FLUXES */
            // System.out.println("qdh = " + qdh);
            // System.out.println("qds = " + qds);
            // m3phr
            qd = qdh + qds;
            if (Double.isNaN(qs) || Double.isNaN(qd)) {
                if (Double.isNaN(qs)) {
                    throw new ModelsIllegalargumentException("Subsuperficial discharge for the hillslope " + currentHillslope.getHillslopeId() + " " + i + " is NaN", this.getClreplaced().getSimpleName(), pm);
                } else {
                    throw new ModelsIllegalargumentException("Timestep " + currentTimeInMinutes + "Superficial discharge for the hillslope " + currentHillslope.getHillslopeId() + " " + i + " is NaN" + "\nValue of qdh " + qdh + "\nValue of qds " + qds + "\nPrecipitation " + prec_mphr + "\nSatsurf " + satsurf, this.getClreplaced().getSimpleName(), pm);
                }
            }
            if (isAtFinalSubtimestep) {
                pm.message("timeinmin = " + currentTimeInMinutes + "\tbacino: " + i + "\tqdh = " + qdh + "\tqds = " + qds + "\tre = " + re + "\tqs = " + qs + "\tmst = " + mst + "\tinf = " + inf + "\tqe1 = " + qe1 + "\tqe2 = " + qe2);
            }
            /*
             * if the area is > 0.1 km2, we consider the delay effect
             * of the hillslope.
             */
            if (area_m2 > THRESHOLD_AREA) {
                // distribute the discharge
                int hillslopeId = currentHillslope.getHillslopeId();
                ADischargeDistributor dischargeDistributor = hillslopeId2DischargeDistributor.get(hillslopeId);
                qs = dischargeDistributor.calculateSubsuperficialDischarge(qs, satsurf, currentTimeInMillis);
                qd = dischargeDistributor.calculateSuperficialDischarge(qd, satsurf, currentTimeInMillis);
            }
            /* LINK FLUX ( Q ) */
            /*
             * Below, i=link#, j=id of connecting links, Array[i][j]=link# for
             * connecting link
             */
            /* LINK FLUX ( Q SUBSURFACE, BASE FLOW ) */
            /*
             * Below, i=link#, j=id of connecting links, Array[i][j]=link# for
             * connecting link
             */
            Q_trib = 0.0D;
            Qs_trib = 0.0D;
            List<IHillSlope> connectedUpstreamHillSlopes = currentHillslope.getConnectedUpstreamElements();
            if (connectedUpstreamHillSlopes != null) {
                for (IHillSlope hillSlope : connectedUpstreamHillSlopes) {
                    PfafstetterNumber pNum = hillSlope.getPfafstetterNumber();
                    int index = orderedHillslopes.indexOf(hillSlope);
                    boolean doCalculate = true;
                    for (IDischargeContributor dContributor : dischargeContributorList) {
                        Double contributedDischarge = dContributor.getDischarge(pNum.toString());
                        contributedDischarge = dContributor.mergeWithDischarge(contributedDischarge, input[index]);
                        if (!isNovalue(contributedDischarge)) {
                            if (doLog && doPrint) {
                                pm.message("----> For hillslope " + currentHillslope.getPfafstetterNumber() + " using hydrometer/dams data in pfafstetter: " + pNum.toString() + "(meaning added " + contributedDischarge + " instead of " + input[index] + ")");
                            }
                            // input[index] / (input[index] +
                            double dischargeRatio = 0.3;
                            // input[index + linksNum]);
                            // units m^3/s
                            Q_trib = dischargeRatio * contributedDischarge;
                            // units m^3/s
                            Qs_trib = contributedDischarge - Q_trib;
                            doCalculate = false;
                        }
                    }
                    if (doCalculate) {
                        // at the same position we can query the input array
                        // units m^3/s
                        Q_trib += input[index];
                        // units m^3/s
                        Qs_trib += input[index + linksNum];
                    }
                }
            }
            double K_Q = AdigeUtilities.doRouting(input[i], currentHillslope, routingType);
            /*
             * if (i == 62) { System.out.println(" WD ratio ="+
             * linksHydraulicInfo.Width(i)/flowdepth); System.out.println("
             * Mannings v (m/s) =" +
             * (Math.pow(hydrad,2./3.)*Math.pow(linksHydraulicInfo.Slope(i),1/2.)/mannings_n) );
             * System.out.println(" K_Q =" +
             * (Math.pow(hydrad,2./3.)*Math.pow(linksHydraulicInfo.Slope(i),1/2.)/mannings_n)
             * *Math.pow(linksHydraulicInfo.Length(i),-1) ); }
             */
            if (input[i] == 0.0D)
                K_Q = 1e-10;
            if (Double.isNaN(qs) || Double.isNaN(qd)) {
                // $NON-NLS-1$ //$NON-NLS-2$
                pm.errorMessage("Problems in basin: " + currentHillslope.getHillslopeId() + " " + i);
                if (area_m2 < THRESHOLD_AREA) {
                    qd = 0.0;
                    qs = 0.0;
                    inf = 0.0;
                    qe1 = 0.0;
                    qe2 = 0.0;
                    re = 0.0;
                    System.out.println("All the contributes are set to zero.");
                }
            }
            /* OUTPUT */
            if (area_m2 > THRESHOLD_AREA) {
                // LINK dQ/dt; big () term is m^3/s, 60*K_Q is 1/min
                output[i] = 60.0D * K_Q * ((1.0D / 3600.) * qd + Q_trib - input[i]);
                // 60.0 * K_Q * (Q_trib - input[i]) + (1.0 / 3600.0) * qd / deltaTinMinutes;
                // LINK dQs/dt -> (m^3/s)/min
                output[i + linksNum] = 60.0 * K_Q * (Qs_trib - input[i + linksNum]) + 60.0 * K_Q * (1.0 / 3600.) * (qs);
                // HILLSLOPE dS1/dt -> m3/min
                output[i + (2 * linksNum)] = (1.0 / 60.0) * (inf - re - qe1);
                // HILLSLOPE dS2/dt -> m3/min
                output[i + (3 * linksNum)] = (1.0 / 60.0) * (re - qs - qe2);
            } else {
                output[i] = 60.0D * K_Q * ((1.0D / 3600.) * qd + Q_trib - input[i]);
                output[i + linksNum] = 60.0D * K_Q * ((1.0D / 3600.) * (qs) + Qs_trib - input[i + linksNum]);
                output[i + (2 * linksNum)] = (1.0D / 60.0) * (inf - re - qe1);
                if (output[i + (2 * linksNum)] != output[i + (2 * linksNum)] || output[i + (2 * linksNum)] == 0.0) {
                    throw new ModelsIllegalargumentException("Invalid value of S1, please check the parameters." + output[i + (2 * linksNum)], this, pm);
                }
                output[i + (3 * linksNum)] = (1.0D / 60.0) * (re - qs - qe2);
            }
            if (output[i + (3 * linksNum)] != output[i + (3 * linksNum)] || output[i + (2 * linksNum)] == 0.) {
                throw new ModelsIllegalargumentException("Invalid value of S2, please check the parameters.", this.getClreplaced().getSimpleName(), pm);
            }
        }
        doPrint = false;
        return output;
    }

    public void addDischargeContributor(IDischargeContributor dischargeContributor) {
        dischargeContributorList.add(dischargeContributor);
    }

    public void addDischargeDistributor(HashMap<Integer, ADischargeDistributor> hillslopeId2DischargeDistributor) {
        this.hillslopeId2DischargeDistributor = hillslopeId2DischargeDistributor;
    }
}

17 View Complete Implementation : HymodAdigeEngine.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
/**
 * The Hymod engine for the {@link OmsAdige} framework.
 *
 * @author Andrea Antonello (www.hydrologis.com)
 * @author Silvia Franceschi (www.hydrologis.com)
 * @author Giuseppe Formetta
 */
public clreplaced HymodAdigeEngine implements IAdigeEngine {

    private final HymodInputs hymodInputs;

    private final List<IHillSlope> orderedHillslopes;

    // private double[] initialConditions;
    private double[] xSlow = null;

    private double[] xLoss = null;

    private double[][] xQuick = null;

    private final HashMap<Integer, double[]> outDischarge;

    private final HashMap<Integer, double[]> outSubDischarge;

    private final HashMap<Integer, double[]> outDischargeInternal;

    private final HashMap<Integer, Integer> index2Basinid;

    private List<IDischargeContributor> dischargeContributorList = new ArrayList<IDischargeContributor>();

    private final boolean doPrint;

    private final boolean doLog;

    private final IHMProgressMonitor pm;

    private final List<String> pfaffsList;

    private double[] coeffs;

    int conta = 0;

    public HymodAdigeEngine(HymodInputs hymodInputs, List<IHillSlope> orderedHillslopes, HashMap<Integer, Integer> index2Basinid, HashMap<Integer, double[]> outDischarge, HashMap<Integer, double[]> outSubDischarge, List<String> pfaffsList, boolean doLog, boolean doPrint, IHMProgressMonitor pm) {
        this.hymodInputs = hymodInputs;
        this.orderedHillslopes = orderedHillslopes;
        this.index2Basinid = index2Basinid;
        this.outDischarge = outDischarge;
        this.outSubDischarge = outSubDischarge;
        this.pfaffsList = pfaffsList;
        this.doLog = doLog;
        this.doPrint = doPrint;
        this.pm = pm;
        outDischargeInternal = new HashMap<Integer, double[]>();
    }

    public void addDischargeContributor(IDischargeContributor dischargeContributor) {
        dischargeContributorList.add(dischargeContributor);
    }

    public HashMap<Integer, double[]> getDischarge() {
        return outDischarge;
    }

    public HashMap<Integer, double[]> getSubDischarge() {
        return outSubDischarge;
    }

    public double[] solve(DateTime currentTimstamp, int tTimestep, double internalTimestepInMinutes, double[] initialConditions, double[] rainArray, double[] etpArray) throws IOException {
        if (initialConditions != null) {
            for (int i = orderedHillslopes.size() - 1; i >= 0; i--) {
                xLoss[i] = initialConditions[i];
                xSlow[i] = initialConditions[i + orderedHillslopes.size()];
                xQuick[0][i] = initialConditions[i + 2 * orderedHillslopes.size()];
                xQuick[1][i] = initialConditions[i + 3 * orderedHillslopes.size()];
                xQuick[2][i] = initialConditions[i + 4 * orderedHillslopes.size()];
            }
        }
        if (initialConditions == null) {
            xSlow = new double[orderedHillslopes.size()];
            coeffs = new double[orderedHillslopes.size()];
            xQuick = new double[3][orderedHillslopes.size()];
            xLoss = new double[orderedHillslopes.size()];
            initialConditions = new double[orderedHillslopes.size() * 5];
            for (int i = orderedHillslopes.size() - 1; i >= 0; i--) {
                IHillSlope hillSlope = orderedHillslopes.get(i);
                double areaKm2 = hillSlope.getHillslopeArea() / 1E6;
                // System.out.println(areaKm2);
                coeffs[i] = (Math.pow(10, 9)) * tTimestep * 60 / (areaKm2 * (Math.pow(10, 12)));
                xSlow[i] = 0 * hymodInputs.pQ0 * coeffs[i] / hymodInputs.pRs;
            }
        }
        for (int i = orderedHillslopes.size() - 1; i >= 0; i--) {
            IHillSlope hillSlope = orderedHillslopes.get(i);
            // /////////////FISSATO PER CHECK///////////////
            // hymodInputs.pAlpha=0.323;
            // hymodInputs.pCmax=999.0;
            // hymodInputs.pB=0.515;
            // hymodInputs.pRq=0.135;
            // hymodInputs.pRs=0.0091;
            // /////////////FISSATO PER CHECK///////////////
            double rain = rainArray[i];
            double etp = etpArray[i];
            // funziona
            // if (rain == -999 || etp ==-999) {
            // rain=0;etp=0;
            // }
            // modificato
            // System.out.println("rain= "+rain+" etp= "+etp);
            // if (isNovalue(rain) || isNovalue(etp)) {
            // rain=0;
            // etp=0;
            // }
            // 
            // 
            // /*
            // * sum together the discharge contributed by the current
            // * hillslope plus the contributions coming from upstream
            // */
            // 
            // PfafstetterNumber pfaf = hillSlope.getPfafstetterNumber();
            // if (pfaffsList.contains(pfaf.toString())) {
            // outDischarge.put(basinId, new double[] { -999 });
            // outSubDischarge.put(basinId, new double[] { -999 });
            // }
            // 
            // outDischargeInternal.put(basinId,
            // new double[] { -999 });
            // System.out.println(basinId+" rain= "+rain+" etp="+etp+ "outDischargeInternal="+
            // outDischargeInternal.get(basinId));
            // // if (i == 2) {
            // // //
            // // System.out.println(conta+" basinDischarge"+(-999)
            // // +" xloss="+xLoss[i]);
            // // conta++;
            // // }
            // } else {
            double[] out_excess = excess(xLoss[i], rain, etp);
            double UT1 = out_excess[0];
            double UT2 = out_excess[1];
            xLoss[i] = out_excess[2];
            double UQ = hymodInputs.pAlpha * UT2 + UT1;
            double US = (1.0 - hymodInputs.pAlpha) * UT2;
            double inflow = US;
            double[] out_linres1 = linres(xSlow[i], inflow, hymodInputs.pRs, 1);
            xSlow[i] = out_linres1[0];
            double outflow1 = out_linres1[1];
            double QS = outflow1;
            inflow = UQ;
            double outflow2 = 0;
            for (int k = 0; k < 3; k++) {
                double[] out_linres2 = linres(xQuick[k][i], inflow, hymodInputs.pRq, 1);
                xQuick[k][i] = out_linres2[0];
                outflow2 = out_linres2[1];
                inflow = outflow2;
            }
            Integer basinId = index2Basinid.get(i);
            double basinDischarge = (QS + outflow2) / coeffs[i];
            double basinSubDischarge = QS / coeffs[i];
            double allContributionsDischarge = handleContributors(hillSlope, basinDischarge);
            /*
             * sum together the discharge contributed by the current
             * hillslope plus the contributions coming from upstream
             */
            basinDischarge = basinDischarge + allContributionsDischarge;
            PfafstetterNumber pfaf = hillSlope.getPfafstetterNumber();
            if (pfaffsList.contains(pfaf.toString())) {
                outDischarge.put(basinId, new double[] { basinDischarge });
                outSubDischarge.put(basinId, new double[] { basinSubDischarge });
            }
            initialConditions[i] = xLoss[i];
            initialConditions[i + orderedHillslopes.size()] = xSlow[i];
            initialConditions[i + 2 * orderedHillslopes.size()] = xQuick[0][i];
            initialConditions[i + 3 * orderedHillslopes.size()] = xQuick[1][i];
            initialConditions[i + 4 * orderedHillslopes.size()] = xQuick[2][i];
            outDischargeInternal.put(basinId, new double[] { basinDischarge });
        // System.out.println(basinId+" rain= "+rain+" etp="+etp+ "outDischargeInternal="+
        // outDischargeInternal.get(basinId));
        // if (i == 61) {
        // System.out.println("rain= "+rain+" etp= "+etp+" basinId= "+basinId+
        // " basinDischarge"+basinDischarge+" allcontributions= "+allContributionsDischarge+" xloss= "+xLoss[i]);
        // }
        // if (i == 61) {
        // //
        // System.out.println(conta+"rain= "+rain+" etp= "+etp+" basinDischarge"+(basinDischarge-allContributionsDischarge)
        // +" xloss="+xLoss[i]);
        // conta++;
        // }
        // }
        }
        // System.out.println("out=" + outDischarge.get(basinId)[0] + " x_slow="
        // + xSlow[0] + "rain=" + rainArray[0] + " etp="
        // + etpArray[0]);
        return initialConditions;
    }

    private double handleContributors(IHillSlope hillSlope, final double basinDischarge) {
        double summedContributions = 0;
        List<IHillSlope> connectedUpstreamHillSlopes = hillSlope.getConnectedUpstreamElements();
        if (connectedUpstreamHillSlopes != null) {
            for (IHillSlope tmpHillSlope : connectedUpstreamHillSlopes) {
                PfafstetterNumber pNum = tmpHillSlope.getPfafstetterNumber();
                int hillslopeId = tmpHillSlope.getHillslopeId();
                /*
                 * get the inflow from upstream basins
                 */
                double upstreamDischarge = outDischargeInternal.get(hillslopeId)[0];
                /*
                 * handle the contributors
                 */
                for (IDischargeContributor dContributor : dischargeContributorList) {
                    Double contributedDischarge = dContributor.getDischarge(pNum.toString());
                    if (!isNovalue(contributedDischarge)) {
                        if (doLog && doPrint) {
                            pm.message("----> For hillslope " + hillSlope.getPfafstetterNumber() + " using hydrometer/dams data in pfafstetter: " + pNum.toString() + "(meaning added " + contributedDischarge + " instead of " + upstreamDischarge + ")");
                        }
                        /*
                         * here the contributor will give its contribution,
                         * which depends on the type of contributor. For example
                         * a Hydrometer will completely subsreplacedute the
                         * calculated discharge of the current hillslope
                         * (tmpHillSlope) with the measure supplied by the
                         * Hydrometer.
                         */
                        // funziona
                        // if (contributedDischarge != -9999) {
                        // upstreamDischarge = dContributor
                        // .mergeWithDischarge(contributedDischarge,
                        // upstreamDischarge);
                        // }
                        // modificato
                        if (!isNovalue(contributedDischarge)) {
                            upstreamDischarge = dContributor.mergeWithDischarge(contributedDischarge, upstreamDischarge);
                        }
                    }
                }
                double routedDischarge = doRouting(upstreamDischarge, basinDischarge, tmpHillSlope);
                summedContributions = summedContributions + routedDischarge;
            }
        }
        return summedContributions;
    }

    // TODO make this real
    private double doRouting(double discharge, final double basinDischarge, IHillSlope hillslope) {
        // 
        // double K_Q = AdigeUtilities.doRouting(discharge, hillslope, 2);
        return discharge;
    }

    private double[] excess(double x_losss, double Pval, double PETval) {
        double[] o_exces = new double[3];
        double pB = hymodInputs.pB;
        double pCmax = hymodInputs.pCmax;
        double xn_prev = x_losss;
        double coeff1 = ((1.0 - ((pB + 1.0) * (xn_prev) / pCmax)));
        // if(Math.abs(coeff1)<1E-10){coeff1=0;}
        double exp = 1.0 / (pB + 1.0);
        double ct_prev = pCmax * (1.0 - pow(coeff1, exp));
        double UT1 = max((Pval - pCmax + ct_prev), 0.0);
        Pval = Pval - UT1;
        double dummy = min(((ct_prev + Pval) / pCmax), 1.0);
        double coeff2 = (1.0 - dummy);
        double exp2 = (pB + 1.0);
        double xn = (pCmax / (pB + 1.0)) * (1.0 - (pow(coeff2, exp2)));
        double UT2 = max(Pval - (xn - xn_prev), 0);
        double evap = min(xn, PETval);
        xn = xn - evap;
        o_exces[0] = UT1;
        o_exces[1] = UT2;
        o_exces[2] = xn;
        if (xn != xn || UT1 != UT1 || UT2 != UT2) {
            System.out.println("FERMATI");
        }
        return o_exces;
    }

    private double[] linres(double x_sloww, double infloww, double RR, double dt) {
        double[] o_linres = new double[2];
        double x_sloww_prev = x_sloww;
        double x_slow_new = (infloww * dt) + x_sloww_prev * (1 - RR * dt);
        double outfloww = x_slow_new * RR;
        o_linres[0] = x_slow_new;
        o_linres[1] = outfloww;
        return o_linres;
    }
}

17 View Complete Implementation : QStatistic.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
/**
 * @author Silvia Franceschi (www.hydrologis.com)
 * @author Andrea Antonello (www.hydrologis.com)
 * @author Silvano Pisoni
 */
public clreplaced QStatistic implements DischargeCalculator {

    private ParameterBox fixedParams = null;

    private IUHCalculator iuhC = null;

    private double tpmax = 0f;

    private double J = 0f;

    private double h = 0f;

    private double[][] ampidiff = null;

    private final IHMProgressMonitor pm;

    double[][] volumeCheck = null;

    /**
     * This clreplaced calculates maximum discharge and discharge.
     *
     * @param fixedParameters - set of initial parameters
     * @param iuhC - abstraction of the iuh calculator
     * @param jeffC - abstraction of the jeff calculator
     * @param pm
     */
    public QStatistic(ParameterBox fixedParameters, IUHCalculator iuhC, StatisticJeff jeffC, IHMProgressMonitor pm) {
        this.fixedParams = fixedParameters;
        this.iuhC = iuhC;
        this.pm = pm;
        double[][] jeff = jeffC.calculateJeff();
        J = jeff[0][0];
        h = jeff[0][1];
        tpmax = iuhC.getTpMax();
        ampidiff = iuhC.calculateIUH();
    }

    public double calculateQmax() {
        double area_super = fixedParams.getArea();
        double area_sub = fixedParams.getArea_sub();
        double area_tot = 0f;
        /* if (effectsBox.containsKey("ampi_sub")) */
        if (area_sub != 0) {
            area_tot = area_sub + area_super;
        } else {
            area_tot = area_super;
        }
        double qmax = (double) (J * area_tot * (ModelsEngine.width_interpolate(ampidiff, iuhC.getTstarMax(), 0, 2) - ModelsEngine.width_interpolate(ampidiff, iuhC.getTstarMax() - tpmax, 0, 2)));
        return qmax;
    }

    public double[][] calculateQ() {
        double timestep = fixedParams.getTimestep();
        double area_super = fixedParams.getArea();
        double area_sub = fixedParams.getArea_sub();
        double area_tot = 0f;
        double tcorr = ampidiff[ampidiff.length - 1][0];
        double[][] Q = new double[(int) Math.floor((tcorr + tpmax) / timestep) + 1][4];
        volumeCheck = new double[(int) Math.floor((tcorr + tpmax) / timestep) + 1][2];
        if (area_sub != -9999.0) {
            area_tot = area_sub + area_super;
        } else {
            area_tot = area_super;
        }
        /*
         * calculate the discharge for t < tcorr
         */
        int j = 0;
        pm.beginTask("Calculating discharge for t < tcorr...", (int) tcorr);
        for (int t = 1; t < tcorr; t += timestep) {
            j = (int) Math.floor((t) / timestep);
            if (t <= tpmax) {
                Q[j][0] = t;
                Q[j][1] = (double) (J * area_tot * ModelsEngine.width_interpolate(ampidiff, t, 0, 2));
                Q[j][2] = Q[j - 1][2] + Q[j][1];
                Q[j][3] = h;
            } else {
                Q[j][0] = t;
                Q[j][1] = (double) (J * area_tot * (ModelsEngine.width_interpolate(ampidiff, t, 0, 2) - ModelsEngine.width_interpolate(ampidiff, t - tpmax, 0, 2)));
                Q[j][2] = Q[j - 1][2] + Q[j][1];
                Q[j][3] = 0.0;
            }
            double diffJ = (area_tot * J - Q[j][2]) * timestep;
            volumeCheck[j][0] = Q[j][0];
            volumeCheck[j][1] = diffJ;
            pm.worked((int) timestep);
        }
        pm.done();
        /*
         * calculate the discharge for t > tcorr
         */
        pm.beginTask("Calculating discharge for t > tcorr...", (int) tpmax);
        for (double t = tcorr; t < (tcorr + tpmax); t += timestep) {
            j = (int) Math.floor(((int) t) / timestep);
            Q[j][0] = t;
            Q[j][1] = (double) (J * area_tot * (ampidiff[ampidiff.length - 1][2] - ModelsEngine.width_interpolate(ampidiff, t - tpmax, 0, 2)));
            Q[j][2] = Q[j - 1][2] + Q[j][1];
            Q[j][3] = 0.0;
            double diffJ = (area_tot * J - Q[j][2]) * timestep;
            volumeCheck[j][0] = Q[j][0];
            volumeCheck[j][1] = diffJ;
            pm.worked((int) timestep);
        }
        pm.done();
        /*
         * calculate the volumes
         */
        // double vol = Q[Q.length - 2][2] * timestep;
        // double vol2 = (double) (area_tot * h / 1000);
        return Q;
    }

    public double[][] getVolumeCheck() {
        return volumeCheck;
    }

    /*
     * (non-Javadoc)
     * @see bsh.commands.h.peakflow.discharge.DischargeCalculator#getTpMax()
     */
    public double getTpMax() {
        return tpmax;
    }
}

17 View Complete Implementation : Utility.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
/**
 * Calculate the magnitudo of the several drainage area.
 *
 * <p>
 * It begin from the first state, where the magnitudo is setted to 1, and
 * then it follow the path of the water until the outlet.
 * </p>
 * <p>
 * During this process the magnitudo of each through areas is incremented of
 * 1 units. This operation is done for every state, so any path of the water
 * are replacedized, from the state where she is intercept until the outlet.
 * <p>
 * </p>
 *
 * @param magnitudo is the array where the magnitudo is stored.
 * @param whereDrain array which contains where a pipe drains.
 * @param pm the progerss monitor.
 * @throw IllegalArgumentException if the water through a number of state
 *        which is greater than the state in the network.
 */
public static void pipeMagnitude(double[] magnitude, double[] whereDrain, IHMProgressMonitor pm) {
    int count = 0;
    /* whereDrain Contiene gli indici degli stati riceventi. */
    /* magnitude Contiene la magnitude dei vari stati. */
    int length = magnitude.length;
    /* Per ogni stato */
    for (int i = 0; i < length; i++) {
        count = 0;
        /* la magnitude viene posta pari a 1 */
        magnitude[i]++;
        int k = i;
        /*
             * Si segue il percorso dell'acqua e si incrementa di 1 la mgnitude
             * di tutti gli stati attraversati prima di raggiungere l'uscita
             */
        while (whereDrain[k] != Constants.OUT_INDEX_PIPE && count < length) {
            k = (int) whereDrain[k];
            magnitude[k]++;
            count++;
        }
        if (count > length) {
            pm.errorMessage(msg.message("trentoP.error.pipe"));
            throw new IllegalArgumentException(msg.message("trentoP.error.pipe"));
        }
    }
}

17 View Complete Implementation : Utility.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
/**
 * Verify the schema.
 *
 * <p>
 * Verify if the FeatureCollection contains all the needed fields.
 * </p>
 * @param schema is yhe type for the project mode.
 * @param pm
 * @return true if there is the percentage of the area.
 */
public static boolean verifyProjectType(SimpleFeatureType schema, IHMProgressMonitor pm) {
    String searchedField = PipesTrentoP.ID.getAttributeName();
    verifyFeatureKey(findAttributeName(schema, searchedField), searchedField, pm);
    searchedField = PipesTrentoP.DRAIN_AREA.getAttributeName();
    verifyFeatureKey(findAttributeName(schema, searchedField), searchedField, pm);
    searchedField = PipesTrentoP.INITIAL_ELEVATION.getAttributeName();
    verifyFeatureKey(findAttributeName(schema, searchedField), searchedField, pm);
    searchedField = PipesTrentoP.FINAL_ELEVATION.getAttributeName();
    verifyFeatureKey(findAttributeName(schema, searchedField), searchedField, pm);
    searchedField = PipesTrentoP.RUNOFF_COEFFICIENT.getAttributeName();
    verifyFeatureKey(findAttributeName(schema, searchedField), searchedField, pm);
    searchedField = PipesTrentoP.KS.getAttributeName();
    verifyFeatureKey(findAttributeName(schema, searchedField), searchedField, pm);
    searchedField = PipesTrentoP.MINIMUM_PIPE_SLOPE.getAttributeName();
    verifyFeatureKey(findAttributeName(schema, searchedField), searchedField, pm);
    searchedField = PipesTrentoP.AVERAGE_RESIDENCE_TIME.getAttributeName();
    verifyFeatureKey(findAttributeName(schema, searchedField), searchedField, pm);
    searchedField = PipesTrentoP.PIPE_SECTION_TYPE.getAttributeName();
    verifyFeatureKey(findAttributeName(schema, searchedField), searchedField, pm);
    searchedField = PipesTrentoP.AVERAGE_SLOPE.getAttributeName();
    verifyFeatureKey(findAttributeName(schema, searchedField), searchedField, pm);
    searchedField = PipesTrentoP.PER_AREA.getAttributeName();
    String attributeName = findAttributeName(schema, searchedField);
    if (attributeName != null) {
        return true;
    }
    return false;
}

17 View Complete Implementation : Utility.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
/**
 * Verify the schema.
 *
 * <p>
 * Verify if the FeatureCollection contains all the needed fields.
 * </p>
 * @param schema is yhe type for the calibration mode.
 * @param pm
 * @return true if there is the percentage of the area.
 */
public static boolean verifyCalibrationType(SimpleFeatureType schema, IHMProgressMonitor pm) {
    String searchedField = PipesTrentoP.ID.getAttributeName();
    verifyFeatureKey(findAttributeName(schema, searchedField), searchedField, pm);
    searchedField = PipesTrentoP.DRAIN_AREA.getAttributeName();
    verifyFeatureKey(findAttributeName(schema, searchedField), searchedField, pm);
    searchedField = PipesTrentoP.INITIAL_ELEVATION.getAttributeName();
    verifyFeatureKey(findAttributeName(schema, searchedField), searchedField, pm);
    searchedField = PipesTrentoP.FINAL_ELEVATION.getAttributeName();
    verifyFeatureKey(findAttributeName(schema, searchedField), searchedField, pm);
    searchedField = PipesTrentoP.RUNOFF_COEFFICIENT.getAttributeName();
    verifyFeatureKey(findAttributeName(schema, searchedField), searchedField, pm);
    searchedField = PipesTrentoP.KS.getAttributeName();
    verifyFeatureKey(findAttributeName(schema, searchedField), searchedField, pm);
    searchedField = PipesTrentoP.DIAMETER.getAttributeName();
    verifyFeatureKey(findAttributeName(schema, searchedField), searchedField, pm);
    searchedField = PipesTrentoP.AVERAGE_SLOPE.getAttributeName();
    verifyFeatureKey(findAttributeName(schema, searchedField), searchedField, pm);
    searchedField = PipesTrentoP.AVERAGE_RESIDENCE_TIME.getAttributeName();
    verifyFeatureKey(findAttributeName(schema, searchedField), searchedField, pm);
    searchedField = PipesTrentoP.PER_AREA.getAttributeName();
    String attributeName = findAttributeName(schema, searchedField);
    if (attributeName != null) {
        return true;
    }
    return false;
}

16 View Complete Implementation : OmsMorpher.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
/**
 * Morphologically closes an input raster by a given kernel.
 *
 * @param inWR the input raster.
 * @param regionMap the {@link RegionMap}.
 * @param outWR the raster to modify.
 * @param kernelArray the kernel to use.
 * @param binary if <code>true</code>, binary mode is used.
 */
public static void close(WritableRaster inWR, RegionMap regionMap, WritableRaster outWR, int[] kernelArray, boolean binary, IHMProgressMonitor pm) {
    dilate(inWR, regionMap, outWR, kernelArray, binary, pm);
    inWR.setDataElements(0, 0, outWR);
    clearRaster(regionMap, outWR);
    erode(inWR, regionMap, outWR, kernelArray, pm);
}

16 View Complete Implementation : SpatialDbsImportUtils.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
/**
 * Import a shapefile into a table.
 *
 * @param db the database to use.
 * @param shapeFile the shapefile to import.
 * @param tableName the name of the table to import to.
 * @param limit if > 0, a limit to the imported features is applied.
 * @param pm the progress monitor.
 * @return <code>false</code>, is an error occurred.
 * @throws Exception
 */
public static boolean importShapefile(ASpatialDb db, File shapeFile, String tableName, int limit, IHMProgressMonitor pm) throws Exception {
    FileDataStore store = FileDataStoreFinder.getDataStore(shapeFile);
    SimpleFeatureSource featureSource = store.getFeatureSource();
    SimpleFeatureCollection features = featureSource.getFeatures();
    return importFeatureCollection(db, features, tableName, limit, pm);
}

16 View Complete Implementation : RootFindingFunctions.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
/**
 * Evaluate the root of a function.
 *
 * <p>
 *
 * Use the bisection method. note that to use before to use this method it's
 * necessary to have a special function object which is defined by the
 * interface {@link Function}.
 *
 * <ol>
 * <li>Implements the bisection method an return the solution with a
 * particular accuracy.
 * <li>return an error if the function doesn't converge to the solution in
 * JMAX loop.
 * </ol>
 *
 * @param function is the function examined.
 * @param bottomLimit bottom left value of the x.
 * @param upperLimit upper right value of the x.
 * @param accuracy accuracy to use in the evaluation.
 * @param maxIterationNumber maximum number of iteration.
 * @throws ArithmeticException if the method haven't achieve the solution in
 *         jMax steeps.
 *
 * @return the solution of the equation.
 */
public static double bisectionRootFinding(ISingleArgmentFunction function, double bottomLimit, double upperLimit, double accuracy, double maxIterationNumber, IHMProgressMonitor pm) {
    /* Numero di iterazioni eseguite col metodo delle bisezioni */
    long j;
    /* Ampiezza dell'intervallo di ricerca della radice */
    double dx;
    /*
         * Funzione di cui si cerca la radice valutata in corrispondenza
         * dell'estremo inferiore, fisso.
         */
    double f;
    /*
         * Funzione di cui si cerca la radice valutata in corrispondenza
         * dell'estremo superiore mobile.
         */
    double fmid;
    /*
         * Estremo superiore mobile dell'intervallo in cui si cercano le radici
         * cercate.
         */
    double xmid;
    /* La radice calcolata con la precisione richiesta */
    double rtb;
    /*
         * chiamata alla funzione di cui si cerca la radice,nell'estremo
         * inferiore.
         */
    f = function.getValue(bottomLimit);
    /*
         * chiamata alla funzione di cui si cerca la radice nell'estremo
         * superiore del bracketing.
         */
    fmid = function.getValue(upperLimit);
    /* verifica se il bracketing della radice e corretto */
    if (f * fmid >= 0) {
        pm.errorMessage(msg.message("trentoP.error.braketed"));
        throw new ArithmeticException(msg.message("trentoP.error.braketed"));
    }
    if (f < 0) {
        dx = upperLimit - bottomLimit;
        rtb = bottomLimit;
    } else {
        dx = bottomLimit - upperLimit;
        rtb = upperLimit;
    }
    /*
         * se f< 0, mantengo il primo estremo fisso in x1, e sposto il secondo
         * estremo a sisnitra finche la f in tale punto non e minore di 0.
         * Altrimenti fisso il secondo estremo e muovo il primo estremo a destra
         * finche la f diventa negativa.
         */
    for (j = 1; j <= maxIterationNumber; j++) {
        fmid = function.getValue(xmid = rtb + (dx *= 0.5));
        /*
             * quando la f cambia segno rispetto all'estremo di riferimento, il
             * valore corrente dell'estremo mobile e la radice cercata
             */
        if (fmid <= 0)
            rtb = xmid;
        /*
             * resreplaceduisci la rdice se l'intervallo di ricerca e minore della
             * tolleranza prefissata, oppure se f=0
             */
        if (Math.abs(dx) < accuracy || fmid == 0)
            return rtb;
    }
    /*
         * Se il numero delle bisezioni supera il numero mreplacedimo ammesso (40),
         * senza arrivare a una convergenza dei risultati, il programma da
         * errore
         */
    pm.errorMessage(msg.message("trentoP.error.bisection"));
    throw new ArithmeticException(msg.message("trentoP.error.bisection"));
}

16 View Complete Implementation : QReal.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
/**
 * @author Silvia franceschi (www.hydrologis.com)
 * @author Andrea Antonello (www.hydrologis.com)
 */
public clreplaced QReal implements DischargeCalculator {

    private RealJeff jeffC = null;

    private Map<DateTime, Double> jeff = null;

    private double[][] ampi = null;

    private double tpmax = 0f;

    private ParameterBox fixedParams = null;

    private double[][] Qtot = null;

    private final IHMProgressMonitor pm;

    double[][] volumeCheck = null;

    /**
     * Calculate the discharge with rainfall data
     */
    public QReal(ParameterBox fixedParameters, IUHCalculator iuhC, RealJeff jeffC, IHMProgressMonitor pm) {
        this.jeffC = jeffC;
        this.fixedParams = fixedParameters;
        this.pm = pm;
        jeff = jeffC.calculateJeff();
        ampi = iuhC.calculateIUH();
    }

    /**
     * Calculate the discharge with rainfall data.
     */
    // public QReal( ParameterBox fixedParameters, double[][] iuhdata, double[][] jeffdata ) {
    // fixedParams = fixedParameters;
    // 
    // jeff = jeffdata;
    // ampi = iuhdata;
    // 
    // System.out.println("AAAAAAAAAAAAAAAAAAAAAAAAAAAAA: ampilength " + ampi[ampi.length - 1][0]);
    // }
    /*
     * (non-Javadoc)
     * @see bsh.commands.h.peakflow.core.discharge.DischargeCalculator#calculateQ()
     */
    public double[][] calculateQ() {
        double timestep = fixedParams.getTimestep();
        double area_super = fixedParams.getArea();
        double area_sub = fixedParams.getArea_sub();
        double area_tot = 0f;
        double raintimestep = jeffC.getRain_timestep();
        DateTime firstDate = jeffC.getFirstDate();
        /*
         * The maximum rain time has no sense with the real precipitations. In this case it will use
         * the rain timestep for tp.
         */
        double tcorr = ampi[ampi.length - 1][0];
        tpmax = (double) raintimestep;
        int rainLength = jeff.size();
        double[][] totalQshiftMatrix = new double[rainLength][(int) (Math.floor((tcorr + tpmax) / timestep) + 1 + rainLength * raintimestep / timestep)];
        double[][] Q = new double[(int) Math.floor((tcorr + tpmax) / timestep) + 1][3];
        volumeCheck = new double[(int) Math.floor((tcorr + tpmax) / timestep) + 1][2];
        if (area_sub != -9999.0) {
            area_tot = area_sub + area_super;
        } else {
            area_tot = area_super;
        }
        Set<DateTime> dates = jeff.keySet();
        pm.beginTask("Calculating discharge...", dates.size());
        int i = 0;
        for (DateTime dateTime : dates) {
            double J = jeff.get(dateTime);
            /*
             * calculate the discharge for t < tcorr
             */
            int j = 0;
            for (int t = 1; t < tcorr; t += timestep) {
                j = (int) Math.floor((t) / timestep);
                if (t <= tpmax) {
                    Q[j][0] = t;
                    double widthInterpolate = ModelsEngine.width_interpolate(ampi, t, 0, 2);
                    Q[j][1] = (double) (J * area_tot * widthInterpolate);
                    Q[j][2] = Q[j - 1][2] + Q[j][1];
                } else {
                    Q[j][0] = t;
                    Q[j][1] = (double) (J * area_tot * (ModelsEngine.width_interpolate(ampi, t, 0, 2) - ModelsEngine.width_interpolate(ampi, t - tpmax, 0, 2)));
                    Q[j][2] = Q[j - 1][2] + Q[j][1];
                }
                double diffJ = (area_tot * J - Q[j][2]) * timestep;
                volumeCheck[j][0] = Q[j][0];
                volumeCheck[j][1] = diffJ;
            }
            /*
             * calculate the discharge for t > tcorr
             */
            for (double t = tcorr; t < (tcorr + tpmax); t += timestep) {
                j = (int) Math.floor(((int) t) / timestep);
                Q[j][0] = t;
                Q[j][1] = (double) (J * area_tot * (ampi[ampi.length - 1][2] - ModelsEngine.width_interpolate(ampi, t - tpmax, 0, 2)));
                Q[j][2] = Q[j - 1][2] + Q[j][1];
                double diffJ = (area_tot * J - Q[j][2]) * timestep;
                volumeCheck[j][0] = Q[j][0];
                volumeCheck[j][1] = diffJ;
            }
            /*
             * calculate the volumes
             */
            // double vol = Q[Q.length - 2][2] * timestep;
            // double vol2 = (double) (area_tot * J * raintimestep);
            /*
             * calculate zero padding before first value Note that jeff contains already the
             * progressive time of the rainfile.
             */
            int totalshiftmatrixindex = 0;
            int initalshiftmatrixindex = 0;
            // FIXME time in ???
            Duration duration = new Duration(firstDate, dateTime);
            long intervalSeconds = duration.getStandardSeconds();
            int paddingnumber = (int) (intervalSeconds / timestep);
            for (int m = 0; m < paddingnumber; m++) {
                totalQshiftMatrix[i][m] = 0;
                totalshiftmatrixindex++;
            }
            initalshiftmatrixindex = totalshiftmatrixindex;
            for (int k = initalshiftmatrixindex; k < Q.length + initalshiftmatrixindex; k++) {
                totalQshiftMatrix[i][k] = Q[k - initalshiftmatrixindex][1];
                totalshiftmatrixindex++;
            }
            for (int k = Q.length + totalshiftmatrixindex; k < totalQshiftMatrix[0].length; k++) {
                totalQshiftMatrix[i][k] = 0;
            }
            i++;
            pm.worked(1);
        }
        pm.done();
        /*
         * sum the discharge contributes
         */
        Qtot = new double[totalQshiftMatrix[0].length][2];
        double tottime = 0f;
        for (int k = 0; k < Qtot.length; k++) {
            double sum = 0f;
            for (int j = 0; j < totalQshiftMatrix.length; j++) {
                sum = sum + totalQshiftMatrix[j][k];
            }
            tottime = tottime + timestep;
            Qtot[k][1] = sum;
            Qtot[k][0] = tottime;
        }
        double total_vol = 0f;
        for (int k = 0; k < Qtot.length; k++) {
            total_vol = total_vol + Qtot[k][1];
        }
        double total_rain = 0.0;
        for (DateTime dateTime : dates) {
            double J = jeff.get(dateTime);
            total_rain = total_rain + J;
        }
        total_rain = total_rain * area_tot * raintimestep;
        return Qtot;
    }

    public double[][] getVolumeCheck() {
        return volumeCheck;
    }

    /*
     * (non-Javadoc)
     * @see bsh.commands.h.peakflow.core.discharge.DischargeCalculator#calculateQmax()
     */
    public double calculateQmax() {
        if (Qtot == null) {
            calculateQ();
        }
        double qmax = 0f;
        for (int i = 0; i < Qtot.length; i++) {
            if (Qtot[i][1] > qmax)
                qmax = Qtot[i][1];
        }
        return qmax;
    }

    /*
     * (non-Javadoc)
     * @see bsh.commands.h.peakflow.core.discharge.DischargeCalculator#getTpMax()
     */
    public double getTpMax() {
        return tpmax;
    }
}

16 View Complete Implementation : NetworkCalibration.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
/**
 * Clreplaced which contains methods to verify a sewer network.
 *
 * <p>
 *
 * It contains a geosewere method which verify the net..
 *
 * </p>
 *
 * @author Daniele Andreis, Riccardo Rigon, David Tamanini
 */
public clreplaced NetworkCalibration implements Network {

    /**
     * The initial time, it's the initial time whre to start to search the tp max.
     * <p>
     * It's fixed to 15 minutes.
     *
     * </p>
     */
    public static final Integer INITIAL_TIME = 15;

    DateTime first = null;

    /*
     * Time step.
     */
    private Integer dt;

    /*
     * Monitor.
     */
    private final IHMProgressMonitor pm;

    /*
     *
     */
    private final HortonMessageHandler msg = HortonMessageHandler.getInstance();

    /*
     * Rain data.
     */
    private double[][] rainData;

    /*
     * The input rain.
     */
    private final HashMap<DateTime, double[]> inRain;

    /*
     * Flag to exit if a pipe is full.
     */
    boolean isFill = false;

    /*
     * Dati relativi alla rete
     */
    private final Pipe[] networkPipes;

    /*
     * celerita-.
     */
    private final double celerityfactor1;

    /*
     * The time of fill degree..
     */
    private double[][] lastTimeDischarge;

    /*
     * The time of fill degree..
     */
    private double[][] lastTimeFillDegree;

    /*
     * The end time of the simulation.
     */
    private final int tMax;

    /*
     * A string where to put the warning messages.
     */
    private final StringBuilder strBuilder;

    /*
     * The fill degree for each pipe and for each time.
     */
    private HashMap<DateTime, HashMap<Integer, double[]>> fillDegree;

    /*
     * The discharg for each pipe and for each time.
     */
    private HashMap<DateTime, HashMap<Integer, double[]>> discharge;

    /*
     * A flag that indicate to the program if search or not the maximum rain time.
     */
    private final boolean foundMaxrainTime;

    /*
     * The upper limit time range. It is used to search the tpMax. The range to search the tpMax is [IITIAL_TIME, tpMaxCalibration].
     */
    private final Integer tpMaxCalibration;

    /*
     * The rain time that give the maximum discharge.
     */
    private int tpMax;

    /*
     * Is the number of data rain to use.
     */
    private int nTime;

    /*
     * True if there is an infinite loop.
     */
    private boolean infiniteLoop = false;

    /*
     * Max number of iteration to search the solution.
     */
    private final static int MAX_NUMBER_ITERATION = 1000;

    /**
     * Builder for the Calibration clreplaced.
     */
    public static clreplaced Builder {

        // Mandatory parameters.
        /*
         * Progress monitor.
         */
        private final IHMProgressMonitor pm;

        /*
         * time step.
         */
        private final Integer dt;

        /*
         * Builder that contains the warning messages.
         */
        private final StringBuilder strBuilder;

        /*
         * The fillDegree for each pipe and for each time.
         */
        private final HashMap<DateTime, HashMap<Integer, double[]>> fillDegree;

        /*
         * The discharg for each pipe and for each time.
         */
        private final HashMap<DateTime, HashMap<Integer, double[]>> discharge;

        /*
         * Dati di pioggia.
         */
        private final HashMap<DateTime, double[]> inRain;

        /*
         * Dati relativi alla rete
         */
        private final Pipe[] networkPipe;

        /*
         * Flag to indicate if search or not the tpMax.
         */
        private final boolean foundMaxrainTime;

        /*
         * Maximum time of calibration.
         */
        private final Integer tpMaxCalibration;

        // optional parameter.
        /*
         * Celerity.
         */
        private double celerityfactor1 = DEFAULT_CELERITY_FACTOR;

        /*
         *  max number of time step.
         */
        private int tMax = (int) DEFAULT_TMAX;

        /**
         * Initialize the object with the needed parameters
         *
         * @param pm
         * @param msg
         * @param networkPipe the array of pipes.
         * @param dt time step.
         * @param inRain the rain data.
         * @param outDischarge the output, discharge.
         * @param outFillDegreethe output, fill degree.
         * @param strBuilder a string used to store the warnings.
         */
        public Builder(IHMProgressMonitor pm, Pipe[] networkPipe, Integer dt, HashMap<DateTime, double[]> inRain, HashMap<DateTime, HashMap<Integer, double[]>> outDischarge, HashMap<DateTime, HashMap<Integer, double[]>> outFillDegree, StringBuilder strBuilder, Integer tpMaxCalibration, boolean foundTpMax) {
            this.pm = pm;
            this.networkPipe = networkPipe;
            this.inRain = inRain;
            this.dt = dt;
            this.discharge = outDischarge;
            this.fillDegree = outFillDegree;
            this.strBuilder = strBuilder;
            this.foundMaxrainTime = foundTpMax;
            if (tpMaxCalibration != null) {
                this.tpMaxCalibration = tpMaxCalibration;
            } else {
                this.tpMaxCalibration = tMax;
            }
        }

        /**
         * Set the max celerity factor.
         *
         * @param max
         *            celerityFactor.
         */
        public Builder celerityFactor(double celerityFactor) {
            this.celerityfactor1 = celerityFactor;
            return this;
        }

        /**
         * Set the max number of time step.
         *
         * @param tMax
         *            .
         */
        public Builder tMax(int tMax) {
            this.tMax = tMax;
            return this;
        }

        /**
         * Create a NetworkCalibration Object.
         *
         * @return
         */
        public NetworkCalibration build() {
            return new NetworkCalibration(this);
        }
    }

    /**
     * Set the parameter throughout the Builder,
     */
    private NetworkCalibration(Builder builder) {
        this.dt = builder.dt;
        this.pm = builder.pm;
        this.celerityfactor1 = builder.celerityfactor1;
        this.discharge = builder.discharge;
        this.fillDegree = builder.fillDegree;
        this.tMax = builder.tMax;
        this.strBuilder = builder.strBuilder;
        this.tpMaxCalibration = builder.tpMaxCalibration;
        this.foundMaxrainTime = builder.foundMaxrainTime;
        if (builder.networkPipe != null) {
            this.networkPipes = builder.networkPipe;
        } else {
            pm.errorMessage(msg.message("trentoP.error.network"));
            throw new IllegalArgumentException("trentoP.error.network");
        }
        if (builder.inRain != null) {
            this.inRain = builder.inRain;
            // create the rains array from the input.
            Set<Entry<DateTime, double[]>> rainSet = inRain.entrySet();
            DateTime second = null;
            int l = rainSet.size();
            rainData = new double[l][2];
            int index = 0;
            for (Entry<DateTime, double[]> rainRecord : rainSet) {
                DateTime dateTime = rainRecord.getKey();
                double[] values = rainRecord.getValue();
                if (first == null) {
                    first = dateTime;
                } else if (second == null && dt == null) {
                    second = dateTime;
                }
                rainData[index][0] = index + 1;
                rainData[index][1] = values[0];
                index++;
            }
            // Evaluate the time step, if it isn't preplaceded as a parameter,as a difference between two
            // time.
            if (dt == null) {
                dt = abs(second.getMinuteOfDay() - first.getMinuteOfDay());
            }
            // if the input has the date in a wrong order.
            if (dt <= 0) {
                pm.errorMessage(msg.message("trentoP.error.t"));
                throw new IllegalArgumentException(msg.message("trentoP.error.t"));
            }
            double tMaxApproximate = ModelsEngine.approximate2Multiple(tMax, dt);
            // initialize the output.
            nTime = (int) (tMaxApproximate / dt);
            lastTimeDischarge = createMatrix();
            lastTimeFillDegree = createMatrix();
        } else {
            pm.errorMessage(msg.message("trentoP.error.rainData "));
            throw new IllegalArgumentException(msg.message("trentoP.error.rainData"));
        }
    }

    /**
     * Return the rain time.
     *
     * @return the rain time which give the maximum discharge.
     */
    public int getTpMax() {
        return tpMax;
    }

    /*
     * Create the matrix which contains the result.
     */
    private double[][] createMatrix() {
        double time = 0;
        double tmin = 0;
        tmin = rainData[0][0];
        time = tmin;
        double[][] matrix = new double[nTime][networkPipes.length + 1];
        for (int i = 0; i < nTime; ++i) {
            matrix[i][0] = time;
            time += dt;
        }
        return matrix;
    }

    /**
     * verify of the no-head pipes.
     *
     * <p>
     * It evaluate the discharge.
     * </p>
     *
     * @param k  ID of the pipe where evaluate the discharge.
     * @param cDelays delay matrix (for the evalutation of the flow wave).
     * @param net matrix that contains value of the network.
     * @return
     */
    private double internalPipeVerify(int k, double[] cDelays, double[][] net, double[][] timeDischarge, double[][] timeFillDegree, int tp) {
        int num;
        double localdelay, olddelay, qMax, B, known, theta, u;
        double[][] qPartial;
        qPartial = new double[timeDischarge.length][timeDischarge[0].length];
        calculateDelays(k, cDelays, net);
        // First attempt local delay [min]
        localdelay = 1;
        double accuracy = networkPipes[0].getAccuracy();
        int jMax = networkPipes[0].getjMax();
        double minG = networkPipes[0].getMinG();
        double maxtheta = networkPipes[0].getMaxTheta();
        double tolerance = networkPipes[0].getTolerance();
        int count = 0;
        do {
            olddelay = localdelay;
            qMax = 0;
            // Updates delays
            for (int i = 0; i < net.length; i++) {
                net[i][2] += localdelay;
            }
            ;
            for (int j = 0; j < net.length; ++j) {
                num = (int) net[j][0];
                getHydrograph(num, qPartial, olddelay, net[j][2], tp);
            }
            getHydrograph(k, qPartial, olddelay, 0, tp);
            qMax = ModelsEngine.sumDoublematrixColumns(k, qPartial, timeDischarge, 0, qPartial[0].length - 1, pm);
            if (qMax <= 1)
                qMax = 1;
            // Resets delays
            for (int i = 0; i < net.length; i++) {
                net[i][2] -= localdelay;
            }
            calculateFillDegree(k, timeDischarge, timeFillDegree);
            B = qMax / (CUBICMETER2LITER * networkPipes[k].getKs() * sqrt(networkPipes[k].verifyPipeSlope / METER2CM));
            known = (B * TWO_THIRTEENOVERTHREE) / pow(networkPipes[k].diameterToVerify / METER2CM, EIGHTOVERTHREE);
            theta = Utility.thisBisection(maxtheta, known, TWOOVERTHREE, minG, accuracy, jMax, pm, strBuilder);
            // Average velocity in pipe [ m / s ]
            u = qMax * 80 / (pow(networkPipes[k].diameterToVerify, 2) * (theta - sin(theta)));
            localdelay = networkPipes[k].getLenght() / (celerityfactor1 * u * MINUTE2SEC);
            count++;
            // verify if it's an infiniteloop.
            if (count > MAX_NUMBER_ITERATION) {
                infiniteLoop = true;
                throw new ArithmeticException();
            }
        } while (abs(localdelay - olddelay) / olddelay >= tolerance);
        cDelays[k] = localdelay;
        return qMax;
    }

    private void calculateFillDegree(int k, double[][] timeDischarge, double[][] timeFillDegree) {
        double accuracy = networkPipes[0].getAccuracy();
        int jMax = networkPipes[0].getjMax();
        double minG = networkPipes[0].getMinG();
        double maxtheta = networkPipes[0].getMaxTheta();
        double initialFillValue = angleToFillDegree(maxtheta) + 0.1;
        for (int i = 0; i < timeDischarge.length; i++) {
            // set it over the max value so if the bisection fails(because it's over the max) it's
            // setted
            timeFillDegree[i][k] = initialFillValue;
            double q = timeDischarge[i][k];
            if (q > NumericsUtilities.machineFEpsilon()) {
                double B = q / (CUBICMETER2LITER * networkPipes[k].getKs() * sqrt(networkPipes[k].verifyPipeSlope / METER2CM));
                double known = (B * TWO_THIRTEENOVERTHREE) / pow(networkPipes[k].diameterToVerify / METER2CM, EIGHTOVERTHREE);
                double theta = Utility.thisBisection(maxtheta, known, TWOOVERTHREE, minG, accuracy, jMax, pm, strBuilder);
                timeFillDegree[i][k] = angleToFillDegree(theta);
            } else {
                timeFillDegree[i][k] = 0.0;
            }
        }
    }

    /**
     * Calcola il ritardo della tubazione k.
     *
     * @param k indice della tubazione.
     * @param cDelays matrice dei ritardi.
     * @param net  matrice che contiene la sottorete.
     */
    private void calculateDelays(int k, double[] cDelays, double[][] net) {
        double t;
        int ind, r = 1;
        for (int j = 0; j < net.length; ++j) {
            t = 0;
            r = 1;
            ind = (int) net[j][0];
            /*
             * Area k is not included in delays
             */
            while (networkPipes[ind].getIndexPipeWhereDrain() != k) {
                ind = networkPipes[ind].getIndexPipeWhereDrain();
                t += cDelays[ind];
                r++;
            }
            if (r > networkPipes.length) {
                pm.errorMessage(msg.message("trentoP.error.incorrectmatrix"));
                throw new ArithmeticException(msg.message("trentoP.error.incorrectmatrix"));
            }
            net[j][2] = t;
        }
    }

    /**
     * Resreplaceduisce l'idrogramma.
     *
     * @param k tratto di tubazione.
     * @param Qpartial matrice delle portate temporanee necessarie per costriure 'idrogramma.
     * @param localdelay  ritardo della tubazione k.
     * @param delay ritardo temporale.
     */
    private double getHydrograph(int k, double[][] Qpartial, double localdelay, double delay, int tp) {
        double Qmax = 0;
        double tmin = rainData[0][0];
        /* [min] */
        int j = 0;
        double t = tmin;
        double Q;
        double rain;
        int maxRain = 0;
        if (tMax == tpMaxCalibration) {
            maxRain = rainData.length;
        } else {
            maxRain = tp / dt;
        }
        double tMaxApproximate = ModelsEngine.approximate2Multiple(tMax, dt);
        for (t = tmin, j = 0; t <= tMaxApproximate; t += dt, ++j) {
            Q = 0;
            for (int i = 0; i <= maxRain - 1; ++i) {
                // [ l / s ]
                rain = rainData[i][1] * networkPipes[k].getDrainArea() * networkPipes[k].getRunoffCoefficient() * HAOVERH_TO_METEROVERS;
                if (t <= i * dt) {
                    Q += 0;
                } else if (t <= (i + 1) * dt) {
                    Q += rain * pFunction(k, t - i * dt, localdelay, delay);
                } else {
                    Q += rain * (pFunction(k, t - i * dt, localdelay, delay) - pFunction(k, t - (i + 1) * dt, localdelay, delay));
                }
            }
            Qpartial[j][k] = Q;
            if (Q >= Qmax) {
                Qmax = Q;
            }
        }
        return Qmax;
    }

    /**
     * Verify of the head pipes.
     *
     * <p>
     * It evaluate the discharge.
     * </p>
     *
     * @param k
     *            ID of the pipe where evaluate the discharge.
     * @param cDelays
     *            delay matrix (for the evalutation of the flow wave).
     */
    private double headPipeVerify(int k, double[] cDelays, double[][] timeDischarge, double[][] timeFillDegree, int tp) {
        double olddelay = 0;
        double qMax = 0;
        double B = 0;
        double known = 0;
        double theta = 0;
        double u = 0;
        /* First attempt local delay [min] */
        double localdelay = 1;
        double accuracy = networkPipes[0].getAccuracy();
        int jMax = networkPipes[0].getjMax();
        double minG = networkPipes[0].getMinG();
        double maxtheta = networkPipes[0].getMaxTheta();
        double tolerance = networkPipes[0].getTolerance();
        int count = 0;
        do {
            olddelay = localdelay;
            qMax = getHydrograph(k, timeDischarge, olddelay, 0, tp);
            if (qMax <= 1) {
                qMax = 1;
            }
            calculateFillDegree(k, timeDischarge, timeFillDegree);
            B = qMax / (CUBICMETER2LITER * networkPipes[k].getKs() * Math.sqrt(networkPipes[k].verifyPipeSlope / METER2CM));
            known = (B * TWO_THIRTEENOVERTHREE) / Math.pow(networkPipes[k].diameterToVerify / METER2CM, EIGHTOVERTHREE);
            theta = Utility.thisBisection(maxtheta, known, TWOOVERTHREE, minG, accuracy, jMax, pm, strBuilder);
            double tmp1 = 0;
            double tmp2 = 0;
            if (k - 1 >= 0) {
                tmp1 = networkPipes[k].diameterToVerify;
                tmp2 = networkPipes[k].getLenght();
            }
            // Average velocity in pipe [ m / s ]
            u = qMax * 80 / (Math.pow(tmp1, 2) * (theta - Math.sin(theta)));
            localdelay = tmp2 / (celerityfactor1 * u * MINUTE2SEC);
            count++;
            if (count > MAX_NUMBER_ITERATION) {
                infiniteLoop = true;
                throw new ArithmeticException();
            }
        } while (Math.abs(localdelay - olddelay) / olddelay >= tolerance);
        cDelays[k] = localdelay;
        return qMax;
    }

    /**
     * resreplaceduisce la funzione p.
     *
     * @param k tratto di tubazione esaminata.
     * @param ttempo esaminato.
     * @param localdelay ritardo nella tubazione k.
     * @param delay ritardo totale.
     * @return il valore della funxione p
     */
    private double pFunction(int k, double t, double localdelay, double delay) {
        double P = 0;
        if (t < 0) {
            pm.errorMessage(msg.message("trentoP.error.negativeP"));
            throw new ArithmeticException(msg.message("trentoP.error.negativeP"));
        }
        if (t < delay) {
            P = 0;
        } else if (t <= (delay + localdelay)) {
            P = (t - delay) / localdelay + networkPipes[k].k / localdelay * (Math.exp(-(t - delay) / networkPipes[k].k) - 1);
        } else {
            P = 1 + networkPipes[k].k / localdelay * Math.exp(-(t - delay) / networkPipes[k].k) * (1 - Math.exp(localdelay / networkPipes[k].k));
        }
        return P;
    }

    /**
     *  Estimate the discharge for each time and for each pipes.
     *
     * <p>
     * It can work with a single rain time step (if there is an actual rain) or search the maximum rain time, if the rain is unknown and
     * the rain data are builtthroghout the rain possibility curve.
     * </p>
     *  <p>
     *  It work throgout 2 loop:
     *  <ol>
     *  *
     *  <li>The first on the head pipes.
     *  <li>The second on the pipes which are internal.
     *
     *  </ol>
     *  </p>
     */
    @Override
    public void geoSewer() throws Exception {
        if (!foundMaxrainTime) {
            evaluateDischarge(lastTimeDischarge, lastTimeFillDegree, tpMaxCalibration);
        } else {
            /*
             *  start to evaluate the discharge from 15 minutes,evaluate the nearsted value to 15 minutes.
             */
            int minTime = (int) ModelsEngine.approximate2Multiple(INITIAL_TIME, dt);
            double qMax = 0;
            for (int i = minTime; i < tpMaxCalibration; i = i + dt) {
                tpMax = i;
                double[][] timeDischarge = createMatrix();
                double[][] timeFillDegree = createMatrix();
                double q = evaluateDischarge(timeDischarge, timeFillDegree, i);
                if (q > qMax) {
                    qMax = q;
                    lastTimeDischarge = timeDischarge;
                    lastTimeFillDegree = timeFillDegree;
                } else if (q < qMax) {
                    break;
                }
                if (isFill) {
                    break;
                }
            }
        }
        getNetData();
    }

    /*
     * Fill the two output HashMap.
     */
    private void getNetData() {
        int nTime = lastTimeDischarge.length;
        int length = lastTimeDischarge[0].length;
        HashMap<Integer, double[]> tmpHMDis = new LinkedHashMap<Integer, double[]>();
        HashMap<Integer, double[]> tmpHMFill = new LinkedHashMap<Integer, double[]>();
        // order the outpt.
        int netLength = networkPipes.length;
        double[] one = new double[netLength];
        double[] two = new double[netLength];
        for (int i = 0; i < netLength; i++) {
            one[i] = i;
            two[i] = networkPipes[i].getId();
        }
        QuickSortAlgorithm sort = new QuickSortAlgorithm(pm);
        sort.sort(two, one);
        for (int i = 0; i < length - 1; i++) {
            int index = (int) one[i];
            tmpHMDis.put(networkPipes[index].getId(), new double[] { lastTimeDischarge[0][index] });
            tmpHMFill.put(networkPipes[index].getId(), new double[] { lastTimeFillDegree[0][index] });
        }
        discharge.put(first, tmpHMDis);
        fillDegree.put(first, tmpHMFill);
        DateTime tmp = first;
        for (int i = 1; i < nTime; ++i) {
            tmp = tmp.plusMinutes(dt);
            tmpHMDis = new LinkedHashMap<Integer, double[]>();
            tmpHMFill = new LinkedHashMap<Integer, double[]>();
            for (int j = 0; j < length - 1; j++) {
                int index = (int) one[j];
                tmpHMDis.put(networkPipes[index].getId(), new double[] { lastTimeDischarge[i][index] });
                tmpHMFill.put(networkPipes[index].getId(), new double[] { lastTimeFillDegree[i][index] });
            }
            discharge.put(tmp, tmpHMDis);
            fillDegree.put(tmp, tmpHMFill);
        }
    }

    /**
     * Compila la mantrice net con tutte i dati del sottobacino con chiusura nel
     * tratto che si sta replacedizzando, e resreplaceduisce la sua superfice
     *
     * @param k tratto replacedizzato del sottobacino chiuso in l.
     * @param l chiusura del bacino.
     * @param one indice dei versanti.
     * @param net sottobacino che si chiude in l.
     */
    private double scanNetwork(int k, int l, double[] one, double[][] net) {
        int ind;
        /*
         * t Ritardo acreplacedulato dall'onda prima di raggiungere il tratto si sta
         * dimensionando.
         */
        double t;
        /*
         * Distanza percorsa dall'acqua dall'area dove e' caduta per raggiungere
         * l'ingresso del tratto che si sta dimensionando.
         */
        double length;
        /*
         * Superfice del sottobacino con chiusura nel tratto che si sta
         * replacedizzando.
         */
        double totalarea = 0;
        int r = 0;
        int i = 0;
        /*
         * In one gli stati sono in ordine di magmitude crescente. Per ogni
         * stato di magnitude inferiore a quella del tratto l che si sta
         * progettando.
         */
        for (int j = 0; j < k; j++) {
            /* La portata e valutata all'uscita di ciascun tratto */
            t = 0;
            /*
             * ID dello lo stato di magnitude inferiore a quello del tratto che
             * si sta progettando.
             */
            i = (int) one[j];
            ind = i;
            // la lunghezza del tubo precedentemente progettato
            length = networkPipes[ind].getLenght();
            // seguo il percorso dell'acqua finch� non si incontra l'uscita.
            while (networkPipes[ind].getIdPipeWhereDrain() != OUT_ID_PIPE) {
                // lo stato dove drena a sua volta.
                ind = networkPipes[ind].getIndexPipeWhereDrain();
                /*
                 * se lo stato drena direttamente in quello che si sta
                 * progettando
                 */
                if (ind == l) {
                    /*
                     * ID dello stato che drena in l, piu o meno direttamente.
                     */
                    net[r][0] = i;
                    /*
                     * lunghezza del percorsa dall'acqua prima di raggiungere lo
                     * stato l che si sta progettando
                     */
                    net[r][1] = length + networkPipes[l].getLenght();
                    /*
                     * Ritardo acreplacedulato dall'onda di piena formatasi in uno
                     * degli stati a monte, prima di raggiungere il tratto l che
                     * si sta progettando
                     */
                    net[r][2] = t;
                    /*
                     * area di tutti gli stati a monte che direttamente o
                     * indirettamente drenano in l
                     */
                    totalarea += networkPipes[i].getDrainArea();
                    r++;
                    break;
                }
            }
            /*
             * viene incrementato solo se l'area drena in l quindi non puo'
             * superare net->nrh
             */
            if (r > net.length)
                break;
        }
        // area degli stati a monte che drenano in l, l compreso
        totalarea += networkPipes[l].getDrainArea();
        return totalarea;
    }

    private double evaluateDischarge(double[][] timeDischarge, double[][] timeFillDegree, int tp) {
        /* l Tratto che si sta progettando. */
        int l;
        /*
         * matrice che per ciascun area non di testa, contiene i dati geometrici
         * degli stati a monte, che direttamente o indirettamente, drenano in
         * esso
         */
        double[][] net;
        /*
         * contiene la magnitude dei vari stati.
         */
        double[] magnitude = new double[networkPipes.length];
        /*
         * vettore che contiene l'indice dei versanti.
         */
        double[] one = new double[networkPipes.length];
        /*
         * vettore che contiene gli stati riceventi, compresa almeno un'uscita
         */
        double[] two = new double[networkPipes.length];
        /*
         *Max discharge at this iteration; 
         */
        double qMax = 0;
        // initialize the discharge array
        for (int i = 0; i < networkPipes.length; i++) {
            /* Indice degli stati */
            one[i] = i;
            /* Indice degli stati riceventi, compresa almeno un'uscita */
            two[i] = networkPipes[i].getIndexPipeWhereDrain();
        }
        /* Calcola la magnitude di ciascun stato */
        Utility.pipeMagnitude(magnitude, two, pm);
        /*
                                                  * Calcola la magnitude di
                                                  * ciascun stato
                                                  */
        /* al vettore two vengono replacedegnati gli elementi di magnitude */
        for (int i = 0; i < two.length; i++) /*
                                              * al vettore two vengono replacedegnati
                                              * gli elementi di magnitude
                                              */
        {
            two[i] = magnitude[i];
        }
        /*
         * Ordina gli elementi del vettore magnitude in ordine crescente, e
         * posiziona nello stesso ordine gli elementi di one
         */
        QuickSortAlgorithm t = new QuickSortAlgorithm(pm);
        t.sort(magnitude, one);
        int k = 0;
        // tratto che si sta replacedizzando o progettando
        l = (int) one[k];
        pm.beginTask(msg.message("trentoP.begin"), networkPipes.length - 1);
        isFill = false;
        double[] cDelays = new double[networkPipes.length];
        double maxFill = angleToFillDegree(networkPipes[k].getMaxTheta());
        while (magnitude[k] == 1) {
            try {
                double q = headPipeVerify(l, cDelays, timeDischarge, timeFillDegree, tp);
                if (q > qMax) {
                    qMax = q;
                }
                // Preplacedo allo stato successivo
                k++;
                if (k < magnitude.length) {
                    /*
                     * Il prossimo tratto da progettare, ovviamente se avra
                     * magnitude=1
                     */
                    l = (int) one[k];
                } else {
                    break;
                }
                pm.worked(1);
            } catch (ArithmeticException e) {
                if (infiniteLoop) {
                    strBuilder.append(msg.message("trentoP.error.infiniteLoop"));
                } else {
                    NumberFormat formatter = new DecimalFormat("#.###");
                    String limit = formatter.format(maxFill);
                    strBuilder.append(" ");
                    // $NON-NLS-2$
                    strBuilder.append(msg.message("trentoP.warning.emptydegree"));
                    strBuilder.append(limit);
                    strBuilder.append(" ");
                    strBuilder.append(msg.message("trentoP.warning.emptydegree2"));
                    strBuilder.append(networkPipes[l - 1].getId());
                    strBuilder.append(" ");
                    strBuilder.append("tp " + tp);
                    strBuilder.append("\n");
                    isFill = true;
                }
                break;
            }
        }
        /*
         * ----- INIZIO CICLO WHILE PER LA PROGETTAZIONE DELLE AREE NON DI TESTA
         * -----
         * 
         * Magnitude > 1 AREE NON DI TESTA
         */
        if (!isFill) {
            while (k < magnitude.length) {
                try {
                    net = new double[(int) (magnitude[k] - 1)][9];
                    scanNetwork(k, l, one, net);
                    double q = internalPipeVerify(l, cDelays, net, timeDischarge, timeFillDegree, tp);
                    if (q > qMax) {
                        qMax = q;
                    }
                    /* Preplacedo allo stato successivo */
                    k++;
                    /* se non sono arrivato alla fine */
                    if (k < magnitude.length) {
                        /* Prossimo stato da progettare */
                        l = (int) one[k];
                    } else {
                        break;
                    }
                    pm.worked(1);
                } catch (ArithmeticException e) {
                    // if there is an infinite loop.
                    if (infiniteLoop) {
                        strBuilder.append(msg.message("trentoP.error.infiniteLoop"));
                    } else {
                        // if a pipe is fill.
                        // $NON-NLS-2$
                        strBuilder.append(msg.message("trentoP.warning.emptydegree"));
                        strBuilder.append(maxFill);
                        strBuilder.append(" ");
                        strBuilder.append(msg.message("trentoP.warning.emptydegree2"));
                        strBuilder.append(networkPipes[l].getId());
                        strBuilder.append(" ");
                        strBuilder.append("tp " + tp);
                        strBuilder.append("\n");
                        isFill = true;
                    }
                    break;
                }
            }
        }
        return qMax;
    }
}

16 View Complete Implementation : OmsTrentoP.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
/**
 * Verify if the network is consistent.
 *
 * <p>
 * <ol>
 * <li>Verify that the <i>ID</i> of a pipe is a value less than the number
 * of pipe.
 * <li>Verify that the pipe where, the current pipe drain, have an <i>ID</i>
 * less than the number of pipes.
 * <li>Verify that there is an <b>outlet<b> in the net.
 * </ol>
 * </p>
 *
 * @param networkPipes
 *            the array which rappresent the net.
 * @param pm
 *            the progerss monitor.
 * @throws IllegalArgumentException
 *             if the net is unconsistent.
 */
public void verifyNet(Pipe[] networkPipes, IHMProgressMonitor pm) {
    /*
         * serve per verificare che ci sia almeno un'uscita. True= esiste
         * un'uscita
         */
    boolean isOut = false;
    if (networkPipes != null) {
        /* VERIFICA DATI GEOMETRICI DELLA RETE */
        // Per ogni stato
        int length = networkPipes.length;
        int kj;
        for (int i = 0; i < length; i++) {
            // verifica che la rete abbia almeno un-uscita.
            if (networkPipes[i].getIdPipeWhereDrain() == 0) {
                isOut = true;
            }
            /*
                 * Controlla che non ci siano errori nei dati geometrici della
                 * rete, numero ID pipe in cui drena i >del numero consenreplacedo
                 * (la numerazione va da 1 a length
                 */
            if (networkPipes[i].getIndexPipeWhereDrain() > length) {
                pm.errorMessage(msg.message("trentoP.error.pipe"));
                throw new IllegalArgumentException(msg.message("trentoP.error.pipe"));
            }
            /*
                 * Da quanto si puo leggere nel file di input fossolo.geo in
                 * Fluide Turtle, ogni stato o sottobacino e contraddistinto da
                 * un numero crescente che va da 1 a n=numero di stati; n e
                 * anche pari a data->nrh. Inoltre si apprende che la prima
                 * colonna della matrice in fossolo.geo riporta l'elenco degli
                 * stati, mentre la seconda colonna ci dice dove ciascun stato
                 * va a drenare.(NON E AMMESSO CHE LO STESSO STATO DRENI SU PIU
                 * DI UNO!!) Questa if serve per verificare che non siano
                 * presenti condotte non dichiarate, ovvero piu realisticamente
                 * che non ci sia un'errore di numerazione o batreplacedura. In altri
                 * termini lo stato replacedizzato non puo drenare in uno stato al
                 * di fuori di quelli esplicitamente dichiarati o dell'uscita,
                 * contradistinta con ID 0
                 */
            kj = i;
            /*
                 * Terra conto degli stati attraversati dall'acqua che inizia a
                 * scorrere a partire dallo stato replacedizzato
                 */
            int count = 0;
            /*
                 * Seguo il percorso dell'acqua a partire dallo stato corrente
                 */
            while (networkPipes[kj].getIdPipeWhereDrain() != 0) {
                kj = networkPipes[kj].getIndexPipeWhereDrain();
                /*
                     * L'acqua non puo finire in uno stato che con sia tra
                     * quelli esplicitamente definiti, in altre parole il
                     * percorso dell'acqua non puo essere al di fuori
                     * dell'inseme dei dercorsi possibili
                     */
                if (kj > length) {
                    pm.errorMessage(msg.message("trentoP.error.drainPipe") + kj);
                    throw new IllegalArgumentException(msg.message("trentoP.error.drainPipe") + kj);
                }
                count++;
                if (count > length) {
                    pm.errorMessage(msg.message("trentoP.error.pipe"));
                    throw new IllegalArgumentException(msg.message("trentoP.error.pipe"));
                }
            /*
                     * La variabile count mi consente di uscire dal ciclo while,
                     * nel caso non ci fosse [kj][2]=0, ossia un'uscita. Infatti
                     * partendo da uno stato qualsiasi il numero degli stati
                     * attraversati prima di raggiungere l'uscita non puo essere
                     * superiore al numero degli stati effettivamente presenti.
                     * Quando questo accade vuol dire che l'acqua e in un loop
                     * chiuso
                     */
            }
        }
        /*
             * Non si e trovato neanche un uscita, quindi Trento_p da errore di
             * esecuzione, perchè almeno una colonna deve essere l'uscita
             */
        if (isOut == false) {
            pm.errorMessage(msg.message("trentoP.error.noout"));
            throw new IllegalArgumentException(msg.message("trentoP.error.noout"));
        }
    } else {
        throw new IllegalArgumentException(msg.message("trentoP.error.incorrectmatrix"));
    }
}

16 View Complete Implementation : DatabaseViewer.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
public boolean viewSpatialQueryResult3D(String replacedle, String sqlText, IHMProgressMonitor pm) {
    boolean hasError = false;
    if (sqlText.trim().length() == 0) {
        return false;
    }
    try {
        if (toolsPanelController == null) {
            openNww();
        }
        pm.beginTask("Run query: " + sqlText, IHMProgressMonitor.UNKNOWN);
        DefaultFeatureCollection fc = DbsHelper.runRawSqlToFeatureCollection(replacedle, currentConnectedDatabase, sqlText, null);
        ReprojectingFeatureCollection rfc = new ReprojectingFeatureCollection(fc, NwwUtilities.GPS_CRS);
        if (toolsPanelController != null) {
            if (replacedle == null) {
                replacedle = "QueryLayer";
            }
            toolsPanelController.loadFeatureCollection(null, replacedle, null, rfc, null);
            addQueryToHistoryCombo(sqlText);
        }
    } catch (Exception e1) {
        String localizedMessage = e1.getLocalizedMessage();
        hasError = true;
        e1.printStackTrace();
        pm.errorMessage("An error occurred: " + localizedMessage);
    } finally {
        pm.done();
    }
    return hasError;
}

16 View Complete Implementation : OmsGeopaparazzi4Converter.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
private static BuilderAndCollectionPair getBuilderAndCollectionPair(IHMProgressMonitor pm, HashMap<String, BuilderAndCollectionPair> forms2PropertiesMap, String sectionName, Set<Entry<String, String>> entrySet, LinkedHashMap<String, String> typesMap, TreeMap<String, Integer> namesMap, String uniqueSectionName) {
    BuilderAndCollectionPair builderAndCollectionPair = forms2PropertiesMap.get(uniqueSectionName);
    if (builderAndCollectionPair == null) {
        SimpleFeatureTypeBuilder b = new SimpleFeatureTypeBuilder();
        // $NON-NLS-1$
        b.setName(sectionName);
        b.setCRS(DefaultGeographicCRS.WGS84);
        // $NON-NLS-1$
        b.add("the_geom", Point.clreplaced);
        // $NON-NLS-1$
        b.add(tsFN, String.clreplaced);
        // $NON-NLS-1$
        b.add(altimFN, Double.clreplaced);
        // $NON-NLS-1$
        b.add(dirtyFN, Integer.clreplaced);
        for (Entry<String, String> entry : entrySet) {
            String key = entry.getKey();
            String typeStr = typesMap.get(key);
            key = key.replaceAll("\\s+", "_");
            if (key.length() > 10) {
                pm.errorMessage("Need to trim key: " + key);
                key = key.substring(0, 10);
            }
            Integer nCount = namesMap.get(key);
            if (nCount == null) {
                nCount = 1;
                namesMap.put(key, 1);
            } else {
                nCount++;
                namesMap.put(key, nCount);
                if (nCount < 10) {
                    key = key.substring(0, key.length() - 1) + nCount;
                } else {
                    key = key.substring(0, key.length() - 2) + nCount;
                }
            }
            Clreplaced<?> clazz = String.clreplaced;
            if (Utilities.isStringType(typeStr)) {
                // redundant just to show that one can check
                clazz = String.clreplaced;
            } else if (Utilities.isIntegerType(typeStr)) {
                clazz = Integer.clreplaced;
            } else if (Utilities.isDoubleType(typeStr)) {
                clazz = Double.clreplaced;
            }
            b.add(key, clazz);
        }
        SimpleFeatureType featureType = b.buildFeatureType();
        SimpleFeatureBuilder builder = new SimpleFeatureBuilder(featureType);
        DefaultFeatureCollection newCollection = new DefaultFeatureCollection();
        builderAndCollectionPair = new BuilderAndCollectionPair();
        builderAndCollectionPair.builder = builder;
        builderAndCollectionPair.collection = newCollection;
        forms2PropertiesMap.put(uniqueSectionName, builderAndCollectionPair);
    }
    return builderAndCollectionPair;
}

16 View Complete Implementation : HMModel.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
/**
 * Superclreplaced for modules.
 *
 * @author Andrea Antonello (www.hydrologis.com)
 */
public clreplaced HMModel {

    private static boolean doLogging = false;

    static {
        // remove nasty error message if jai has no native backbone
        // JAI.getDefaultInstance().setImagingListener(new ImagingListener(){
        // @Override
        // public boolean errorOccurred( String message, Throwable thrown, Object where, boolean
        // isRetryable )
        // throws RuntimeException {
        // if (thrown != null) {
        // String localizedMessage = thrown.getLocalizedMessage();
        // if (localizedMessage != null //
        // && !localizedMessage.equals("com/sun/medialib/mlib/Image") //
        // && !localizedMessage.equals("IOException occurs when create the socket.") //
        // ) {
        // System.err.println(message);
        // thrown.printStackTrace(System.err);
        // }
        // }
        // return true;
        // }
        // });
        if (!doLogging) {
            // remove many messages from below libs that go out in the console
            Logger l0 = Logger.getLogger("");
            Handler[] handlers = l0.getHandlers();
            for (Handler handler : handlers) {
                l0.removeHandler(handler);
            }
        }
    }

    @// 
    Description(// 
    en = PROGRESS_MONITOR_EN, // 
    it = PROGRESS_MONITOR_EN)
    @In
    public IHMProgressMonitor pm = new LogProgressMonitor();

    /**
     * The default geometry factory.
     */
    public GeometryFactory gf = new GeometryFactory();

    /**
     * Get the default number of threads.
     *
     * <p>At the moment this gives the number of processors.</p>
     *
     * @return the default number of threads.
     */
    public static int getDefaultThreadsNum() {
        int availableProcessors = Runtime.getRuntime().availableProcessors();
        return availableProcessors;
    }

    /**
     * Variable that defines if time is still available or run out.
     *
     * <p>
     * This variable should be set by modules that "lead" the time
     * chain:<br>
     * <ul>
     *      <li><b>true</b>, when the simulation starts</li>
     *      <li><b>false</b>, when the simulation should end, regardless for which
     *          reason (data finished, end date reached...)
     *      </li>
     * </ul>
     * </p>
     */
    // TODO check this out???? @Out
    @UI(HMConstants.ITERATOR_UI_HINT)
    @In
    @Out
    public boolean doProcess = false;

    /**
     * A switch that can enable module resetting.
     *
     * <p>
     * This variable might be useful in the case in which
     * NON-timedependent modules at a certain point should anyways
     * re-read or re-process the data. For example in the case in which
     * a map was already calculated but at a certain point should
     * be recalculated.
     * </p>
     */
    public boolean doReset = false;

    /**
     * Check on the progress monitor to see if the process was stopped.
     *
     * <p>Modules can use that internally to exit, if necessary.</p>
     *
     * @param pm the {@link IHMProgressMonitor progress monitor}.
     * @return true if the process was stopped.
     * @deprecated use directly the pm.isCanceled() or {@link #checkCancel()} instead.
     */
    protected boolean isCanceled(IHMProgressMonitor pm) {
        if (pm.isCanceled()) {
            pm.done();
            return true;
        }
        return false;
    }

    /**
     * Check if the process has been canceled.
     *
     * <p>If canceled a ModelsUserCancelException will be thrown.</p>
     */
    public void checkCancel() {
        if (pm != null && pm.isCanceled()) {
            throw new ModelsUserCancelException();
        }
    }

    // public Map<String, Object> execute( Map<String, Object> input, ProgressListener monitor )
    // throws ProcessException {
    // // the geotools monitor is wrapped into the internal progress monitor
    // GeotoolsProgressMonitorAdapter pm = new GeotoolsProgressMonitorAdapter(monitor);
    // input.put("pm", pm); //$NON-NLS-1$
    // // set the inputs to the model
    // ComponentAccess.setInputData(input, this, null);
    // 
    // // trigger execution of the module
    // ComponentAccess.callAnnotated(this, Initialize.clreplaced, true);
    // ComponentAccess.callAnnotated(this, Execute.clreplaced, false);
    // ComponentAccess.callAnnotated(this, Finalize.clreplaced, true);
    // 
    // // get the results
    // ComponentAccess cA = new ComponentAccess(this);
    // Collection<Access> outputs = cA.outputs();
    // 
    // // and put them into the output map
    // HashMap<String, Object> outputMap = new HashMap<String, Object>();
    // for( Access access : outputs ) {
    // try {
    // String fieldName = access.getField().getName();
    // Object fieldValue = access.getFieldValue();
    // outputMap.put(fieldName, fieldValue);
    // } catch (Exception e) {
    // throw new ProcessException(e.getLocalizedMessage());
    // }
    // }
    // return outputMap;
    // }
    /**
     * Utility method to concatenate conditions with or.
     *
     * <p>
     * This can be useful for readability (in case of negation).
     * </p>
     *
     * @param statements a list of statements.
     * @return the final boolean from the or concatenation.
     */
    protected boolean concatOr(boolean... statements) {
        boolean isTrue = statements[0];
        for (int i = 1; i < statements.length; i++) {
            isTrue = isTrue || statements[i];
        }
        return isTrue;
    }

    /**
     * Checks if the preplaceded objects are all != null and if one is null, throws Exception.
     *
     * @param objects the objects to check.
     */
    protected void checkNull(Object... objects) {
        for (Object object : objects) {
            if (object == null) {
                throw new ModelsIllegalargumentException("Mandatory input argument is missing. Check your syntax...", this.getClreplaced().getSimpleName(), pm);
            }
        }
    }

    /**
     * Checks if preplaceded path strings exist on the filesystem. If not, an Exception is thrown.
     *
     * @param existingFilePath one or more file paths that need to exist.
     */
    protected void checkFileExists(String... existingFilePath) {
        StringBuilder sb = null;
        for (String filePath : existingFilePath) {
            File file = new File(filePath);
            if (!file.exists()) {
                if (sb == null) {
                    sb = new StringBuilder();
                    sb.append("The following file doesn't seem to exist: ");
                }
                sb.append("\n\t").append(file.getAbsolutePath());
            }
        }
        if (sb != null)
            throw new ModelsIllegalargumentException(sb.toString(), this.getClreplaced().getSimpleName(), pm);
    }

    /**
     * Checks if a preplaceded path contains the workingfolder constant. If yes it is set to null.
     *
     * @param filePath the path to check.
     * @return the path or null.
     */
    protected String checkWorkingFolderInPath(String filePath) {
        if (filePath.contains(HMConstants.WORKINGFOLDER)) {
            return null;
        }
        return filePath;
    }

    /**
     * Fast default reading of raster from definition.
     *
     * <p>If the source format is not supported, and {@link Exception} is thrown.</p>
     * <p>If the source is <code>null</code>, null will be returned.</p>
     *
     * @param source the definition for the raster source.
     * @return the read {@link GridCoverage2D}.
     * @throws Exception
     */
    public GridCoverage2D getRaster(String source) throws Exception {
        if (source == null || source.trim().length() == 0)
            return null;
        OmsRasterReader reader = new OmsRasterReader();
        reader.pm = pm;
        reader.file = source;
        reader.process();
        GridCoverage2D geodata = reader.outRaster;
        return geodata;
    }

    /**
     * Fast default reading of vector from definition.
     *
     * <p>If the source format is not supported, and {@link Exception} is thrown.</p>
     * <p>If the source is <code>null</code>, null will be returned.</p>
     *
     * @param source the definition to the vector source.
     * @return the read {@link GridCoverage2D}.
     * @throws Exception
     */
    public SimpleFeatureCollection getVector(String source) throws Exception {
        if (source == null || source.trim().length() == 0)
            return null;
        OmsVectorReader reader = new OmsVectorReader();
        reader.pm = pm;
        reader.file = source;
        reader.process();
        SimpleFeatureCollection fc = reader.outVector;
        return fc;
    }

    /**
     * Fast default writing of raster to source.
     *
     * <p>Mind that if either raster or source are <code>null</code>, the method will
     * return without warning.</p>
     *
     * @param raster the {@link GridCoverage2D} to write.
     * @param source the source to which to write to.
     * @throws Exception
     */
    public void dumpRaster(GridCoverage2D raster, String source) throws Exception {
        if (raster == null || source == null)
            return;
        OmsRasterWriter writer = new OmsRasterWriter();
        writer.pm = pm;
        writer.inRaster = raster;
        writer.file = source;
        writer.process();
    }

    /**
     * Fast default writing of vector to source.
     *
     * <p>Mind that if either vector or source are <code>null</code>, the method will
     * return without warning.</p>
     *
     * @param vector the {@link SimpleFeatureCollection} to write.
     * @param source the source to which to write to.
     * @throws Exception
     */
    public void dumpVector(SimpleFeatureCollection vector, String source) throws Exception {
        if (vector == null || source == null)
            return;
        OmsVectorWriter writer = new OmsVectorWriter();
        writer.pm = pm;
        writer.file = source;
        writer.inVector = vector;
        writer.process();
    }

    public void help() throws Exception {
        String help = ModelsSupporter.generateHelp(this);
        pm.message(help);
    }

    public void template() throws Exception {
        String help = ModelsSupporter.generateTemplate(this);
        pm.message(help);
    }
}

16 View Complete Implementation : OmsMorpher.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
/**
 * Morphologically opens an input raster by a given kernel.
 *
 * @param inWR the input raster.
 * @param regionMap the {@link RegionMap}.
 * @param outWR the raster to modify.
 * @param kernelArray the kernel to use.
 * @param binary if <code>true</code>, binary mode is used.
 */
public static void open(WritableRaster inWR, RegionMap regionMap, WritableRaster outWR, int[] kernelArray, boolean binary, IHMProgressMonitor pm) {
    erode(inWR, regionMap, outWR, kernelArray, pm);
    inWR.setDataElements(0, 0, outWR);
    clearRaster(regionMap, outWR);
    dilate(inWR, regionMap, outWR, kernelArray, binary, pm);
}

15 View Complete Implementation : ImageGenerator.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
/**
 * An utility clreplaced for simple image map generation.
 *
 * <p>A sample usage could be the overlay of vector layers.
 * <pre>
 * ImageGenerator imgGen = new ImageGenerator();
 * imgGen.addFeaturePath(reticolo, null);
 * imgGen.setLayers();
 * imgGen.dumpPngImage(imagePath, bounds, 300, 300, 100);
 * </pre>
 *
 * @author Andrea Antonello (www.hydrologis.com)
 * @since 0.7.3
 */
public clreplaced ImageGenerator {

    public boolean doLegacyGrreplaced = false;

    private String wmsURL = null;

    private List<String> featurePaths = new ArrayList<String>();

    private List<String> featureFilter = new ArrayList<String>();

    private List<String> coveragePaths = new ArrayList<String>();

    private List<GridGeometry2D> coverageRegions = new ArrayList<GridGeometry2D>();

    // private AffineTransform worldToScreen;
    // private AffineTransform screenToWorld;
    private StyleFactory sf;

    private IHMProgressMonitor monitor = new DummyProgressMonitor();

    private List<Layer> layers = new ArrayList<Layer>();

    private List<Layer> synchronizedLayers = null;

    private MapContent content;

    private StreamingRenderer renderer;

    private File shapesFile;

    private CoordinateReferenceSystem forceCrs;

    public ImageGenerator(IHMProgressMonitor monitor, CoordinateReferenceSystem forceCrs) {
        this.forceCrs = forceCrs;
        if (monitor != null)
            this.monitor = monitor;
        sf = CommonFactoryFinder.getStyleFactory(null);
    }

    public void setDoLegacyGrreplaced(boolean doLegacyGrreplaced) {
        this.doLegacyGrreplaced = doLegacyGrreplaced;
    }

    /**
     * Add a new coverage file path.
     *
     * <p>The order will be considered. First paths are drawn first.</p>
     *
     * @param coveragePath the path to add.
     */
    public void addCoveragePath(String coveragePath) {
        if (!coveragePaths.contains(coveragePath)) {
            coveragePaths.add(coveragePath);
        }
    }

    /**
     * Add a coverage read region (this has to have same index as addCoveragePath.
     *
     * @param coverageRegion the region to read.
     */
    public void addCoverageRegion(GridGeometry2D coverageRegion) {
        if (!coverageRegions.contains(coverageRegion)) {
            coverageRegions.add(coverageRegion);
        }
    }

    /**
     * Set a WMS service to handle as raster layer.
     *
     * @param wmsURL the WMS url and layer name in the format: http://wmsurl#layername
     */
    public void setWMS(String wmsURL) {
        this.wmsURL = wmsURL;
    }

    /**
     * Add a new feature file path.
     *
     * <p>The order will be considered. First paths are drawn first.</p>
     *
     * @param featurePath the path to add.
     */
    public void addFeaturePath(String featurePath, String filter) {
        if (!featurePaths.contains(featurePath)) {
            featurePaths.add(featurePath);
            if (filter == null) {
                filter = "";
            }
            featureFilter.add(filter);
        }
    }

    /**
     * Method to add a file that contains a list of shapes/texts to add.
     *
     * <p><b>This is applied on top of the final image. Positions are in pixel.</b>
     * </p>
     * </p>
     * <p>
     * Supported are:</br>
     * <ul>
     *  <li>text;x;y;mytext;colorrgba;size</li>
     * <li>box;x;y;w;h;strokewidth;fillrgba;strokergba</li>
     * <li>roundedbox;x;y;w;h;round;strokewidth;fillrgba;strokergba</li>
     *  <li>...</li>
     * </ul>
     * </p>
     */
    public void addShapesPath(String shapesPath) {
        this.shapesFile = new File(shapesPath);
    }

    // private void setTransforms( final ReferencedEnvelope envelope, int width, int height ) {
    // 
    // double envWidth = envelope.getWidth();
    // double envHeight = envelope.getHeight();
    // double envValue = envWidth;
    // if (envHeight > envWidth) {
    // envValue = envHeight;
    // }
    // 
    // double xscale = width / envValue;
    // double yscale = height / envValue;
    // 
    // double median0 = envelope.getMedian(0);
    // double xoff = median0 * xscale - width / 2.0;
    // double median1 = envelope.getMedian(1);
    // double yoff = median1 * yscale + height / 2.0;
    // 
    // worldToScreen = new AffineTransform(xscale, 0, 0, -yscale, -xoff, yoff);
    // }
    /**
     * Set the layers that have to be drawn.
     *
     * <p><b>This has to be called before the drawing process.</p>
     * @return the max envelope of the data.
     * @throws Exception
     */
    public ReferencedEnvelope setLayers() throws Exception {
        ReferencedEnvelope maxExtent = null;
        // wms first
        if (wmsURL != null) {
            String[] split = wmsURL.split("#");
            WebMapServer server = new WebMapServer(new URL(split[0]));
            org.geotools.data.ows.Layer wmsLayer = getWMSLayer(server, split[1]);
            WMSLayer layer = new WMSLayer(server, wmsLayer);
            layers.add(layer);
            ReferencedEnvelope originalEnvelope = layer.getBounds();
            if (originalEnvelope != null) {
                if (maxExtent == null) {
                    maxExtent = new ReferencedEnvelope(originalEnvelope.getCoordinateReferenceSystem());
                }
                expandToIncludeEnvelope(maxExtent, originalEnvelope);
            }
        }
        // coverages
        monitor.beginTask("Reading raster maps...", coveragePaths.size());
        for (int r = 0; r < coveragePaths.size(); r++) {
            String coveragePath = coveragePaths.get(r);
            GridGeometry2D region = null;
            if (coverageRegions != null && coverageRegions.size() == coveragePaths.size()) {
                region = coverageRegions.get(r);
            }
            File file = new File(coveragePath);
            GridCoverage2D raster = null;
            AbstractGridCoverage2DReader reader = null;
            try {
                try {
                    // first try a format that gives back a reader
                    AbstractGridFormat format = GridFormatFinder.findFormat(file);
                    reader = format.getReader(file);
                    if (reader instanceof GrreplacedCoverageReader) {
                        reader = null;
                    }
                } catch (Exception e1) {
                // ignore and try others
                }
                if (reader == null) {
                    if (region == null) {
                        raster = OmsRasterReader.readRaster(coveragePath);
                    } else {
                        RegionMap regionMap = CoverageUtilities.gridGeometry2RegionParamsMap(region);
                        double n = regionMap.getNorth();
                        double s = regionMap.getSouth();
                        double w = regionMap.getWest();
                        double e = regionMap.getEast();
                        double xres = regionMap.getXres();
                        double yres = regionMap.getYres();
                        OmsRasterReader rreader = new OmsRasterReader();
                        rreader.file = coveragePath;
                        rreader.pNorth = n;
                        rreader.pSouth = s;
                        rreader.pWest = w;
                        rreader.pEast = e;
                        rreader.pXres = xres;
                        rreader.pYres = yres;
                        rreader.doLegacyGrreplaced = doLegacyGrreplaced;
                        rreader.process();
                        raster = rreader.outRaster;
                    }
                }
            // if (crs == null) {
            // crs = raster.getCoordinateReferenceSystem();
            // }
            } catch (Exception e) {
                monitor.errorMessage(e.getLocalizedMessage());
                monitor.errorMessage("Trying to find other coverage source...");
                // try with available readers
                try {
                    AbstractGridFormat format = GridFormatFinder.findFormat(file);
                    reader = format.getReader(file);
                // if (crs == null) {
                // crs = reader.getCrs();
                // }
                } catch (Exception ex) {
                    throw ex;
                }
            }
            File styleFile = FileUtilities.subsreplaceduteExtention(file, "sld");
            Style style;
            if (styleFile.exists()) {
                style = SldUtilities.getStyleFromFile(styleFile);
            } else {
                style = SldUtilities.getStyleFromRasterFile(styleFile);
            }
            if (raster != null) {
                GridCoverageLayer layer = new GridCoverageLayer(raster, style);
                layers.add(layer);
                org.opengis.geometry.Envelope envelope = raster.getEnvelope();
                if (maxExtent == null) {
                    maxExtent = new ReferencedEnvelope(envelope.getCoordinateReferenceSystem());
                }
                expandToIncludeEnvelope(maxExtent, envelope);
            }
            if (reader != null) {
                GridReaderLayer layer = new GridReaderLayer(reader, style);
                // SimpleFeatureSource featureSource = layer.getFeatureSource();
                layers.add(layer);
                org.opengis.geometry.Envelope envelope = reader.getOriginalEnvelope();
                if (maxExtent == null) {
                    maxExtent = new ReferencedEnvelope(envelope.getCoordinateReferenceSystem());
                }
                expandToIncludeEnvelope(maxExtent, envelope);
            }
            monitor.worked(1);
        }
        monitor.done();
        monitor.beginTask("Reading vector maps...", featurePaths.size());
        for (int i = 0; i < featurePaths.size(); i++) {
            String featurePath = featurePaths.get(i);
            String filter = featureFilter.get(i);
            FileDataStore store = FileDataStoreFinder.getDataStore(new File(featurePath));
            SimpleFeatureSource featureSource = store.getFeatureSource();
            SimpleFeatureCollection featureCollection;
            if (filter.length() == 0) {
                featureCollection = featureSource.getFeatures();
            } else {
                featureCollection = featureSource.getFeatures(ECQL.toFilter(filter));
            }
            // if (crs == null) {
            // crs = featureSource.getSchema().getCoordinateReferenceSystem();
            // }
            File styleFile = FileUtilities.subsreplaceduteExtention(new File(featurePath), "sld");
            Style style;
            if (styleFile.exists()) {
                style = SldUtilities.getStyleFromFile(styleFile);
            } else {
                style = SLD.createSimpleStyle(featureSource.getSchema());
            }
            FeatureLayer layer = new FeatureLayer(featureCollection, style);
            layers.add(layer);
            if (maxExtent == null) {
                maxExtent = new ReferencedEnvelope(featureCollection.getSchema().getCoordinateReferenceSystem());
            }
            expandToIncludeEnvelope(maxExtent, featureCollection.getBounds());
            monitor.worked(1);
        }
        synchronizedLayers = Collections.synchronizedList(layers);
        monitor.done();
        return maxExtent;
    }

    private void expandToIncludeEnvelope(ReferencedEnvelope maxExtent, org.opengis.geometry.Envelope envelope) {
        ReferencedEnvelope tmpExtent = new ReferencedEnvelope(envelope.getCoordinateReferenceSystem());
        DirectPosition ll = envelope.getLowerCorner();
        double[] coordinate = ll.getCoordinate();
        tmpExtent.expandToInclude(new Coordinate(coordinate[0], coordinate[1]));
        DirectPosition ur = envelope.getUpperCorner();
        coordinate = ur.getCoordinate();
        tmpExtent.expandToInclude(new Coordinate(coordinate[0], coordinate[1]));
        try {
            ReferencedEnvelope transformed = tmpExtent.transform(maxExtent.getCoordinateReferenceSystem(), true);
            maxExtent.expandToInclude(transformed);
        } catch (TransformException | FactoryException e) {
            e.printStackTrace();
        }
    }

    private org.geotools.data.ows.Layer getWMSLayer(WebMapServer server, String layerName) {
        for (org.geotools.data.ows.Layer layer : server.getCapabilities().getLayerList()) {
            if (layerName.equals(layer.getName())) {
                return layer;
            }
        }
        throw new IllegalArgumentException("Could not find layer " + layerName);
    }

    private synchronized void checkMapContent() {
        if (content == null) {
            content = new MapContent();
            content.setreplacedle("dump");
            for (Layer layer : layers) {
                content.addLayer(layer);
            }
            renderer = new StreamingRenderer();
            renderer.setMapContent(content);
        }
    }

    /**
     * Draw the map on an image.
     *
     * @param bounds the area of interest.
     * @param imageWidth the width of the image to produce.
     * @param imageHeight the height of the image to produce.
     * @param buffer the buffer to add around the map bounds in map units.
     * @return the image.
     */
    public BufferedImage drawImage(ReferencedEnvelope ref, int imageWidth, int imageHeight, double buffer) {
        checkMapContent();
        if (buffer > 0.0)
            ref.expandBy(buffer, buffer);
        Rectangle2D refRect = new Rectangle2D.Double(ref.getMinX(), ref.getMinY(), ref.getWidth(), ref.getHeight());
        Rectangle2D imageRect = new Rectangle2D.Double(0, 0, imageWidth, imageHeight);
        GeometryUtilities.scaleToRatio(imageRect, refRect, false);
        ReferencedEnvelope newRef = new ReferencedEnvelope(refRect, ref.getCoordinateReferenceSystem());
        Rectangle imageBounds = new Rectangle(0, 0, imageWidth, imageHeight);
        BufferedImage dumpImage = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = dumpImage.createGraphics();
        g2d.fillRect(0, 0, imageWidth, imageHeight);
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        synchronized (renderer) {
            renderer.paint(g2d, imageBounds, newRef);
        }
        return dumpImage;
    }

    public void drawImage(Graphics2D g2d, ReferencedEnvelope ref, int imageWidth, int imageHeight, double buffer) {
        checkMapContent();
        if (buffer > 0.0)
            ref.expandBy(buffer, buffer);
        Rectangle2D refRect = new Rectangle2D.Double(ref.getMinX(), ref.getMinY(), ref.getWidth(), ref.getHeight());
        Rectangle2D imageRect = new Rectangle2D.Double(0, 0, imageWidth, imageHeight);
        GeometryUtilities.scaleToRatio(imageRect, refRect, false);
        ReferencedEnvelope newRef = new ReferencedEnvelope(refRect, ref.getCoordinateReferenceSystem());
        Rectangle imageBounds = new Rectangle(0, 0, imageWidth, imageHeight);
        Color white = Color.white;
        g2d.setColor(new Color(white.getRed(), white.getGreen(), white.getBlue(), 0));
        g2d.fillRect(0, 0, imageWidth, imageHeight);
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        synchronized (renderer) {
            content.getViewport().setBounds(newRef);
            renderer.paint(g2d, imageBounds, newRef);
        }
    }

    /**
     * Draw the map on an image creating a new MapContent.
     *
     * @param bounds the area of interest.
     * @param imageWidth the width of the image to produce.
     * @param imageHeight the height of the image to produce.
     * @param buffer the buffer to add around the map bounds in map units.
     * @return the image.
     */
    public BufferedImage drawImageWithNewMapContent(ReferencedEnvelope ref, int imageWidth, int imageHeight, double buffer) {
        MapContent content = new MapContent();
        content.setreplacedle("dump");
        if (forceCrs != null) {
            content.getViewport().setCoordinateReferenceSystem(forceCrs);
            content.getViewport().setBounds(ref);
        }
        synchronized (synchronizedLayers) {
            for (Layer layer : synchronizedLayers) {
                content.addLayer(layer);
            }
        }
        StreamingRenderer renderer = new StreamingRenderer();
        renderer.setMapContent(content);
        if (buffer > 0.0) {
            ref = new ReferencedEnvelope(ref);
            ref.expandBy(buffer, buffer);
        }
        double envW = ref.getWidth();
        double envH = ref.getHeight();
        if (envW < envH) {
            double newEnvW = envH * (double) imageWidth / (double) imageHeight;
            double delta = newEnvW - envW;
            ref.expandBy(delta / 2, 0);
        } else {
            double newEnvH = envW * (double) imageHeight / (double) imageWidth;
            double delta = newEnvH - envH;
            ref.expandBy(0, delta / 2.0);
        }
        Rectangle imageBounds = new Rectangle(0, 0, imageWidth, imageHeight);
        BufferedImage dumpImage = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = dumpImage.createGraphics();
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        renderer.paint(g2d, imageBounds, ref);
        return dumpImage;
    }

    public void dispose() {
        if (content != null)
            content.dispose();
    }

    /**
     * Writes an image of maps drawn to a png file.
     *
     * @param imagePath the path to which to write the image.
     * @param bounds the area of interest.
     * @param imageWidth the width of the image to produce.
     * @param imageHeight the height of the image to produce.
     * @param buffer the buffer to add around the map bounds in map units.
     * @param rgbCheck an rgb tripled. If not <code>null</code> and the image generated is
     *                  composed only of that color, then the tile is not generated.
     *                  This can be useful to avoid generation of empty tiles.
     * @throws IOException
     */
    public void dumpPngImage(String imagePath, ReferencedEnvelope bounds, int imageWidth, int imageHeight, double buffer, int[] rgbCheck) throws IOException {
        BufferedImage dumpImage = drawImageWithNewMapContent(bounds, imageWidth, imageHeight, buffer);
        boolean dumpIt = true;
        if (rgbCheck != null)
            dumpIt = !isAllOfCheckColor(rgbCheck, dumpImage);
        if (dumpIt)
            // $NON-NLS-1$
            ImageIO.write(dumpImage, "png", new File(imagePath));
    }

    /**
     * Writes an image of maps drawn to a jpg file.
     *
     * @param imagePath the path to which to write the image.
     * @param bounds the area of interest.
     * @param imageWidth the width of the image to produce.
     * @param imageHeight the height of the image to produce.
     * @param buffer the buffer to add around the map bounds in map units.
     * @param rgbCheck an rgb tripled. If not <code>null</code> and the image generated is
     *                  composed only of that color, then the tile is not generated.
     *                  This can be useful to avoid generation of empty tiles.
     * @throws IOException
     */
    public void dumpJpgImage(String imagePath, ReferencedEnvelope bounds, int imageWidth, int imageHeight, double buffer, int[] rgbCheck) throws IOException {
        BufferedImage dumpImage = drawImageWithNewMapContent(bounds, imageWidth, imageHeight, buffer);
        boolean dumpIt = true;
        if (rgbCheck != null)
            dumpIt = !isAllOfCheckColor(rgbCheck, dumpImage);
        if (dumpIt)
            ImageIO.write(dumpImage, "jpg", new File(imagePath));
    }

    /**
     * Draw the map on an image.
     *
     * @param bounds the area of interest.
     * @param imageWidth the width of the image to produce.
     * @param imageHeight the height of the image to produce.
     * @param buffer the buffer to add around the map bounds in map units.
     * @param rgbCheck an rgb tripled. If not <code>null</code> and the image generated is
     *                  composed only of that color, then the tile is not generated.
     *                  This can be useful to avoid generation of empty tiles.
     * @throws IOException
     */
    public BufferedImage getImageWithCheck(ReferencedEnvelope bounds, int imageWidth, int imageHeight, double buffer, int[] rgbCheck) throws IOException {
        BufferedImage dumpImage = drawImageWithNewMapContent(bounds, imageWidth, imageHeight, buffer);
        boolean dumpIt = true;
        if (rgbCheck != null)
            dumpIt = !isAllOfCheckColor(rgbCheck, dumpImage);
        if (dumpIt) {
            return dumpImage;
        } else {
            return null;
        }
    }

    private boolean isAllOfCheckColor(int[] rgbCheck, BufferedImage dumpImage) {
        WritableRaster raster = dumpImage.getRaster();
        for (int i = 0; i < raster.getWidth(); i++) {
            for (int j = 0; j < raster.getHeight(); j++) {
                int[] value = raster.getPixel(i, j, (int[]) null);
                if (value[0] != rgbCheck[0] || value[1] != rgbCheck[1] || value[2] != rgbCheck[2]) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * Create an image for a given paper size and scale.
     *
     * @param imagePath the path to which to write the image.
     * @param bounds the area of interest. In this case only the center is considered. The bounds
     *              are recalculated based in paper size and scale.
     * @param scale the scale wanted for the map.
     * @param paperFormat the paper format to use.
     * @param dpi the wanted dpi. If <code>null</code>, 72dpi is used as default.
     * @param legend an optional legend {@link BufferedImage image}.
     * @param legendX the X position of the legend in the final image.
     * @param legendY the Y position of the legend in the final image.
     * @param scalePrefix if not <code>null</code>, this string will be added before the scale definition.
     *                      If <code>null</code>, no scale definition will be added.
     * @param scaleSize a size for the scale.
     * @param scaleX the X position of the scale in the final image.
     * @param scaleY the X position of the scale in the final image.
     * @throws Exception
     * @since 0.7.6
     */
    public void dumpPngImageForScaleAndPaper(String imagePath, ReferencedEnvelope bounds, double scale, EPaperFormat paperFormat, Double dpi, BufferedImage legend, int legendX, int legendY, String scalePrefix, float scaleSize, int scaleX, int scaleY) throws Exception {
        if (dpi == null) {
            dpi = 72.0;
        }
        // we use the bounds top find the center
        Coordinate centre = bounds.centre();
        double boundsXExtension = paperFormat.width() / 1000.0 * scale;
        double boundsYExtension = paperFormat.height() / 1000.0 * scale;
        Coordinate ll = new Coordinate(centre.x - boundsXExtension / 2.0, centre.y - boundsYExtension / 2.0);
        Coordinate ur = new Coordinate(centre.x + boundsXExtension / 2.0, centre.y + boundsYExtension / 2.0);
        Envelope tmpEnv = new Envelope(ll, ur);
        bounds = new ReferencedEnvelope(tmpEnv, bounds.getCoordinateReferenceSystem());
        int imageWidth = (int) (paperFormat.width() / 25.4 * dpi);
        int imageHeight = (int) (paperFormat.height() / 25.4 * dpi);
        BufferedImage dumpImage = drawImage(bounds, imageWidth, imageHeight, 0);
        Graphics2D graphics = (Graphics2D) dumpImage.getGraphics();
        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        if (shapesFile != null && shapesFile.exists()) {
            applyShapes(graphics);
        }
        if (legend != null) {
            graphics.drawImage(legend, null, legendX, legendY);
        }
        if (scalePrefix != null) {
            Font scaleFont = graphics.getFont().deriveFont(scaleSize);
            graphics.setFont(scaleFont);
            FontMetrics fontMetrics = graphics.getFontMetrics(scaleFont);
            String scaleString = scalePrefix + "1:" + (int) scale;
            Rectangle2D stringBounds = fontMetrics.getStringBounds(scaleString, graphics);
            double width = stringBounds.getWidth();
            double height = stringBounds.getHeight();
            graphics.setColor(Color.white);
            double border = 5;
            graphics.fillRect((int) scaleX, (int) (scaleY - height + 2 * border), (int) (width + 3 * border), (int) (height + 2 * border));
            graphics.setColor(Color.black);
            graphics.drawString(scaleString, (int) scaleX + 5, (int) scaleY);
        }
        ImageIO.write(dumpImage, "png", new File(imagePath));
    }

    /**
     * Create an image for a given paper size and scale.
     *
     * @param imagePath the path to which to write the image.
     * @param bounds the area of interest. In this case only the center is considered. The bounds
     *              are recalculated based in paper size and scale.
     * @param scale the scale wanted for the map.
     * @param paperFormat the paper format to use.
     * @param dpi the wanted dpi. If <code>null</code>, 72dpi is used as default.
     * @param legend an optional legend {@link BufferedImage image}.
     * @param legendX the X position of the legend in the final image.
     * @param legendY the Y position of the legend in the final image.
     * @param scalePrefix if not <code>null</code>, this string will be added before the scale definition.
     *                      If <code>null</code>, no scale definition will be added.
     * @param scaleSize a size for the scale.
     * @param scaleX the X position of the scale in the final image.
     * @param scaleY the X position of the scale in the final image.
     * @throws Exception
     * @since 0.7.6
     */
    public void dump2Graphics2D(Graphics2D graphics2d, ReferencedEnvelope bounds, double scale, EPaperFormat paperFormat, Double dpi, BufferedImage legend, int legendX, int legendY, String scalePrefix, float scaleSize, int scaleX, int scaleY) throws Exception {
        if (dpi == null) {
            dpi = 72.0;
        }
        // we use the bounds top find the center
        Coordinate centre = bounds.centre();
        double boundsXExtension = paperFormat.width() / 1000.0 * scale;
        double boundsYExtension = paperFormat.height() / 1000.0 * scale;
        Coordinate ll = new Coordinate(centre.x - boundsXExtension / 2.0, centre.y - boundsYExtension / 2.0);
        Coordinate ur = new Coordinate(centre.x + boundsXExtension / 2.0, centre.y + boundsYExtension / 2.0);
        Envelope tmpEnv = new Envelope(ll, ur);
        // tmpEnv.expandBy(1000);
        bounds = new ReferencedEnvelope(tmpEnv, bounds.getCoordinateReferenceSystem());
        int imageWidth = (int) (paperFormat.width() / 25.4 * dpi);
        int imageHeight = (int) (paperFormat.height() / 25.4 * dpi);
        drawImage(graphics2d, bounds, imageWidth, imageHeight, 0);
        graphics2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        if (shapesFile != null && shapesFile.exists()) {
            applyShapes(graphics2d);
        }
        if (legend != null) {
            graphics2d.drawImage(legend, null, legendX, legendY);
        }
        if (scalePrefix != null) {
            Font scaleFont = graphics2d.getFont().deriveFont(scaleSize);
            graphics2d.setFont(scaleFont);
            FontMetrics fontMetrics = graphics2d.getFontMetrics(scaleFont);
            String scaleString = scalePrefix + "1:" + (int) scale;
            Rectangle2D stringBounds = fontMetrics.getStringBounds(scaleString, graphics2d);
            double width = stringBounds.getWidth();
            double height = stringBounds.getHeight();
            graphics2d.setColor(Color.white);
            double border = 5;
            graphics2d.fillRect((int) scaleX, (int) (scaleY - height + 2 * border), (int) (width + 3 * border), (int) (height + 2 * border));
            graphics2d.setColor(Color.black);
            graphics2d.drawString(scaleString, (int) scaleX + 5, (int) scaleY);
        }
    }

    private void applyShapes(Graphics2D graphics) throws Exception {
        Stream<String> lines = // 
        Files.lines(Paths.get(shapesFile.toURI())).distinct().filter(l -> l.trim().length() != 0);
        lines.forEach(l -> {
            if (l.startsWith("text")) {
                // text;x;y;mytext;colorrgba;size
                String[] split = l.split(";");
                int x = Integer.parseInt(split[1]);
                int y = Integer.parseInt(split[2]);
                String msg = split[3];
                Color color = ColorUtilities.colorFromRbgString(split[4]);
                int size = Integer.parseInt(split[5]);
                graphics.setColor(color);
                graphics.setFont(new Font("Arial", Font.PLAIN, size));
                graphics.drawString(msg, x, y);
            } else if (l.startsWith("box")) {
                // box;x;y;w;h;strokewidth;fillrgba;strokergba
                String[] split = l.split(";");
                int x = Integer.parseInt(split[1]);
                int y = Integer.parseInt(split[2]);
                int w = Integer.parseInt(split[3]);
                int h = Integer.parseInt(split[4]);
                int strokeWidth = Integer.parseInt(split[5]);
                Color colorFill = ColorUtilities.colorFromRbgString(split[6]);
                Color colorStroke = ColorUtilities.colorFromRbgString(split[7]);
                graphics.setColor(colorFill);
                graphics.fillRect(x, y, w, h);
                BasicStroke stroke = new BasicStroke(strokeWidth);
                graphics.setStroke(stroke);
                graphics.setColor(colorStroke);
                graphics.drawRect(x, y, w, h);
            } else if (l.startsWith("roundedbox")) {
                // roundedbox;x;y;w;h;round;strokewidth;fillrgba;strokergba
                String[] split = l.split(";");
                int x = Integer.parseInt(split[1]);
                int y = Integer.parseInt(split[2]);
                int w = Integer.parseInt(split[3]);
                int h = Integer.parseInt(split[4]);
                int round = Integer.parseInt(split[5]);
                int strokeWidth = Integer.parseInt(split[6]);
                Color colorFill = ColorUtilities.colorFromRbgString(split[7]);
                Color colorStroke = ColorUtilities.colorFromRbgString(split[8]);
                graphics.setColor(colorFill);
                graphics.fillRoundRect(x, y, w, h, round, round);
                BasicStroke stroke = new BasicStroke(strokeWidth);
                graphics.setStroke(stroke);
                graphics.setColor(colorStroke);
                graphics.drawRoundRect(x, y, w, h, round, round);
            }
        });
    }
}

15 View Complete Implementation : Utility.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
/**
 * Bracketing.
 *
 * <p>
 * It does the bracketing and then search the root of some function (fill
 * degree, if it's used a commercial diameters):
 * <ol>
 * <li>At first, does the bracketig, in order to search the roots with the
 * bisection method.
 * <li>Call the rtbis function, to evalutate the GSM function root.
 * <li>Return the fill degree, from rtbis.
 * </ol>
 * </p>
 *
 * @param sup upper extrem value of the research.
 * @param known is a constant, evaluated in the main of the program.
 * @param twooverthree, constant.
 * @param minG fill degree.
 * @param accuracy.
 * @param jMax maximum number of iteration.
 * @param pm progress monitor
 * @param strWarnings a StringBuilder where to put the warning messages.
 * @return the fill degree
 */
public static double thisBisection(double sup, double known, double twooverthree, double minG, double accuracy, double jMax, IHMProgressMonitor pm, StringBuilder strWarnings) {
    double thetai = 0;
    /* Ampiezza dell'intervallo per il bracketing */
    double delta;
    /*
         * Estremo inferiore da considerare nella ricerca del angolo di
         * riempimento che si ottiene adottando il diametro commerciale, anziche
         * quello calcolato
         */
    double lowerLimit = 0;
    /*
         * Estremo superiore da adottare nella ricerca dell'angolo formato dalla
         * sezione bagnata, relativa al diametro commerciale
         */
    double upperLimit;
    /* ampiezza dell'intervallo per effettuare il bracketing */
    delta = sup / 10;
    /*
         * e una funzione che mi calcola l'estremo superiore da usare nella
         * ricerca del'angolo di riempimento con metodo di bisezione
         */
    MinimumFillDegreeFunction gsmFunction = new MinimumFillDegreeFunction();
    gsmFunction.setParameters(known, twooverthree, minG);
    upperLimit = gsmFunction.getValue(sup);
    int i;
    /*
         * questo ciclo for mi consente di decrementare l'angolo theta di delta,
         * mi fermo solo quando trovo l'estremo inferiore per un bracketing
         * corretto
         */
    for (i = 0; i < 10; i++) {
        thetai = sup - (i + 1) * delta;
        lowerLimit = gsmFunction.getValue(thetai);
        /* Ho trovato due punti in cui la funzione replacedume segno opposto */
        {
            if (upperLimit * lowerLimit < 0)
                break;
        }
    }
    /*
         * Il bracketing non ha avuto successo, resreplaceduisco il riempimento
         * minimo.
         */
    if (i == 11 && lowerLimit * upperLimit > 0) {
        strWarnings.append(msg.message("trentoP.warning.minimumDepth"));
        return minG;
    }
    /*
         * chiamata alla funzione rtbis(), che restiuira la radice cercata con
         * la precisione richiesta.
         */
    gsmFunction.setParameters(known, twooverthree, minG);
    if (Math.abs(thetai) <= NumericsUtilities.machineFEpsilon()) {
        thetai = 0.0;
    }
    return RootFindingFunctions.bisectionRootFinding(gsmFunction, thetai, thetai + delta, accuracy, jMax, pm);
}

15 View Complete Implementation : TinHandler.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
/**
 * A helper clreplaced for tin handling.
 *
 * @author Andrea Antonello (www.hydrologis.com)
 */
@SuppressWarnings("nls")
public clreplaced TinHandler {

    public static final double POINTENVELOPE_EXPAND = 0.1;

    /**
     * The list of coordinates that will be used at the next tin generation.
     */
    private List<Coordinate> tinCoordinateList = new ArrayList<Coordinate>();

    /**
     * The list of coordinates that are left out as non ground points at each filtering.
     */
    private List<Coordinate> leftOverCoordinateList = new ArrayList<Coordinate>();

    /**
     * The geometries of the last calculated tin.
     */
    private Geometry[] tinGeometries = null;

    private GeometryFactory gf = GeometryUtilities.gf();

    private final IHMProgressMonitor pm;

    private boolean didInitialize = false;

    private boolean isFirstStatsCalculation = true;

    private final CoordinateReferenceSystem crs;

    private final double distanceThreshold;

    private final int threadsNum;

    private double calculatedAngleThreshold;

    private double calculatedDistanceThreshold;

    private final ReadWriteLock monitor = new ReentrantReadWriteLock();

    private final Double maxEdgeLength;

    private double maxEdgeLengthThreshold;

    private final double angleThreshold;

    /**
     * Constructor.
     *
     * @param pm the monitor.
     * @param crs the crs to use for feature creation.
     * @param distanceThreshold the fixed maximum distance threshold to use.
     * @param maxEdgeLength the max edge length for the longest edge of a triangle (if larger, it is ignored)
     * @param threadsNum the number of threads to use for parallel operations.
     */
    public TinHandler(IHMProgressMonitor pm, CoordinateReferenceSystem crs, double angleThreshold, double distanceThreshold, Double maxEdgeLength, int threadsNum) {
        this.pm = pm;
        this.crs = crs;
        this.angleThreshold = angleThreshold;
        this.distanceThreshold = distanceThreshold;
        this.maxEdgeLength = maxEdgeLength;
        this.threadsNum = threadsNum;
    }

    /**
     * Sets the initial coordinates to start with.
     *
     * <p>Generates the tin on the first set of coordinates and adds the
     * coordinates to the {@link #tinCoordinateList} for future use.</p>
     *
     * <p><b>Note that it is mandatory to call this method to initialize.</b></p>
     *
     * @param coordinateList the initial list of coordinates.
     */
    public void setStartCoordinates(List<Coordinate> coordinateList) {
        generateTin(coordinateList);
        for (int i = 0; i < tinGeometries.length; i++) {
            Coordinate[] coordinates = tinGeometries[i].getCoordinates();
            if (!tinCoordinateList.contains(coordinates[0])) {
                tinCoordinateList.add(coordinates[0]);
            }
            if (!tinCoordinateList.contains(coordinates[1])) {
                tinCoordinateList.add(coordinates[1]);
            }
            if (!tinCoordinateList.contains(coordinates[2])) {
                tinCoordinateList.add(coordinates[2]);
            }
        }
        didInitialize = true;
    }

    /**
     * Get the triangles of the current active tin.
     *
     * @return the array of polygons.
     */
    public Geometry[] getTriangles() {
        checkTinGeometries();
        return tinGeometries;
    }

    /**
     * Returns the current size of the {@link #tinCoordinateList} representing teh current ground points.
     *
     * @return the size of the tin coords list.
     */
    public int getCurrentGroundPointsNum() {
        return tinCoordinateList.size();
    }

    /**
     * Returns the size of the points currently defined as being non-ground.
     *
     * @return the size of the non ground points list.
     */
    public int getCurrentNonGroundPointsNum() {
        synchronized (leftOverCoordinateList) {
            return leftOverCoordinateList.size();
        }
    }

    /**
     * Filter data on thresholds of all available data on the tin.
     *
     * <p><b>Note: At the first run of this method, only thresholds are calculated.</b></p>
     *
     * @param lasHandler the las data handler of all data.
     * @throws Exception
     */
    public void filterOnAllData(final ALasDataManager lasHandler) throws Exception {
        final ConcurrentSkipListSet<Double> angleSet = new ConcurrentSkipListSet<Double>();
        final ConcurrentSkipListSet<Double> distanceSet = new ConcurrentSkipListSet<Double>();
        if (isFirstStatsCalculation) {
            pm.beginTask("Calculating initial statistics...", tinGeometries.length);
        } else {
            pm.beginTask("Filtering all data on seeds tin...", tinGeometries.length);
        }
        try {
            final List<Coordinate> newTotalLeftOverCoordinateList = new ArrayList<Coordinate>();
            if (threadsNum > 1) {
                // mulreplacedhreaded
                ThreadedRunnable tRun = new ThreadedRunnable(threadsNum, null);
                for (final Geometry tinGeom : tinGeometries) {
                    tRun.executeRunnable(new Runnable() {

                        public void run() {
                            List<Coordinate> leftOverList = runFilterOnAllData(lasHandler, angleSet, distanceSet, tinGeom);
                            synchronized (newTotalLeftOverCoordinateList) {
                                newTotalLeftOverCoordinateList.addAll(leftOverList);
                            }
                        }
                    });
                }
                tRun.waitAndClose();
            } else {
                for (final Geometry tinGeom : tinGeometries) {
                    List<Coordinate> leftOverList = runFilterOnAllData(lasHandler, angleSet, distanceSet, tinGeom);
                    newTotalLeftOverCoordinateList.addAll(leftOverList);
                }
            }
            pm.done();
            leftOverCoordinateList.clear();
            leftOverCoordinateList.addAll(newTotalLeftOverCoordinateList);
            /*
             * now recalculate the thresholds
             */
            if (angleSet.size() > 1) {
                calculatedAngleThreshold = getMedianFromSet(angleSet);
                pm.message("Calculated angle threshold: " + calculatedAngleThreshold + " (range: " + angleSet.first() + " to " + angleSet.last() + ")");
            } else if (angleSet.size() == 0) {
                return;
            } else {
                calculatedAngleThreshold = angleSet.first();
                pm.message("Single angle left: " + calculatedAngleThreshold);
            }
            if (distanceSet.size() > 1) {
                calculatedDistanceThreshold = getMedianFromSet(distanceSet);
                pm.message("Calculated distance threshold: " + calculatedDistanceThreshold + " (range: " + distanceSet.first() + " to " + distanceSet.last() + ")");
            } else if (distanceSet.size() == 0) {
                return;
            } else {
                calculatedDistanceThreshold = distanceSet.first();
                pm.message("Single distance left: " + calculatedDistanceThreshold);
            }
            if (isFirstStatsCalculation) {
                isFirstStatsCalculation = false;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private List<Coordinate> runFilterOnAllData(final ALasDataManager lasHandler, final ConcurrentSkipListSet<Double> angleSet, final ConcurrentSkipListSet<Double> distanceSet, final Geometry tinGeom) {
        final List<Coordinate> newTotalLeftOverCoordinateList = new ArrayList<Coordinate>();
        try {
            Coordinate[] tinCoords = tinGeom.getCoordinates();
            Coordinate triangleCentroid = getTriangleCentroid(tinCoords[0], tinCoords[1], tinCoords[2]);
            List<LasRecord> pointsInGeom = lasHandler.getPointsInGeometry(tinGeom, false);
            /*
             * now sort the points in the triangle in distance order
             * from the triangle centroid, nearest first
             */
            TreeSet<Coordinate> centroidNearestSet = new TreeSet<Coordinate>(new PointsToCoordinateComparator(triangleCentroid));
            for (LasRecord pointInGeom : pointsInGeom) {
                Coordinate c = new Coordinate(pointInGeom.x, pointInGeom.y, pointInGeom.z);
                if (c.equals(tinCoords[0]) || c.equals(tinCoords[1]) || c.equals(tinCoords[2])) {
                    // the seed point was reread
                    continue;
                }
                centroidNearestSet.add(c);
            }
            // find first possible ground coordinate
            boolean foundOne = false;
            for (Coordinate c : centroidNearestSet) {
                if (foundOne && !isFirstStatsCalculation) {
                    if (!newTotalLeftOverCoordinateList.contains(c))
                        newTotalLeftOverCoordinateList.add(c);
                } else {
                    /*
                     * find the nearest node and distance
                     */
                    Coordinate[] nodes = getOrderedNodes(c, tinCoords[0], tinCoords[1], tinCoords[2]);
                    double nearestDistance = distance3d(nodes[0], c, null);
                    if (!isFirstStatsCalculation) {
                        /*
                         * if we are here, we are doing filtering and calc of thresholds 
                         * for the next round only on the kept data.
                         */
                        if (nearestDistance > calculatedDistanceThreshold) {
                            if (!newTotalLeftOverCoordinateList.contains(c))
                                newTotalLeftOverCoordinateList.add(c);
                            continue;
                        }
                    }
                    /*
                     * calculate the angle between the facet normal and the line
                     * connecting the point and the nearest facet node.
                     */
                    double angle = getAngleBetweenLinePlane(c, nodes[0], nodes[1], nodes[2]);
                    if (Double.isNaN(angle)) {
                        pm.errorMessage("Found NaN angle, set to 0...");
                        angle = 0.0;
                    }
                    if (!isFirstStatsCalculation) {
                        if (angle > calculatedAngleThreshold) {
                            if (!newTotalLeftOverCoordinateList.contains(c))
                                newTotalLeftOverCoordinateList.add(c);
                            continue;
                        } else {
                            // add it to the next tin
                            synchronized (tinCoordinateList) {
                                if (!tinCoordinateList.contains(c)) {
                                    tinCoordinateList.add(c);
                                    foundOne = true;
                                    angleSet.add(angle);
                                    distanceSet.add(nearestDistance);
                                }
                            }
                        }
                    } else {
                        angleSet.add(angle);
                        distanceSet.add(nearestDistance);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        pm.worked(1);
        return newTotalLeftOverCoordinateList;
    }

    public void filterOnLeftOverData() {
        if (isFirstStatsCalculation) {
            throw new IllegalArgumentException("The first round needs to be filtered on all data.");
        }
        pm.beginTask("Creating points indexes...", leftOverCoordinateList.size());
        final STRtree leftOverCoordinatesTree = new STRtree(leftOverCoordinateList.size());
        for (Coordinate c : leftOverCoordinateList) {
            leftOverCoordinatesTree.insert(new Envelope(c), c);
        }
        pm.done();
        if (maxEdgeLength != null) {
            maxEdgeLengthThreshold = maxEdgeLength;
        }
        Geometry[] triangles = getTriangles();
        final ConcurrentSkipListSet<Double> angleSet = new ConcurrentSkipListSet<Double>();
        final ConcurrentSkipListSet<Double> distanceSet = new ConcurrentSkipListSet<Double>();
        final List<Coordinate> newTotalLeftOverCoordinateList = new ArrayList<Coordinate>();
        pm.beginTask("Filtering leftover coordinates on previous tin...", triangles.length);
        if (threadsNum > 1) {
            ThreadedRunnable tRun = new ThreadedRunnable(threadsNum, null);
            for (int i = 0; i < triangles.length; i++) {
                final Geometry triangle = triangles[i];
                tRun.executeRunnable(new Runnable() {

                    public void run() {
                        if (maxEdgeLength != null && triangle.getLength() < maxEdgeLengthThreshold * 3.0) {
                            return;
                        }
                        List<Coordinate> leftOverList = runfilterOnLeftOverData(leftOverCoordinatesTree, angleSet, distanceSet, triangle);
                        synchronized (newTotalLeftOverCoordinateList) {
                            newTotalLeftOverCoordinateList.addAll(leftOverList);
                        }
                    }
                });
            }
            tRun.waitAndClose();
        } else {
            for (int i = 0; i < triangles.length; i++) {
                Geometry triangle = triangles[i];
                List<Coordinate> leftOverList = runfilterOnLeftOverData(leftOverCoordinatesTree, angleSet, distanceSet, triangle);
                newTotalLeftOverCoordinateList.addAll(leftOverList);
            }
        }
        pm.done();
        leftOverCoordinateList.clear();
        leftOverCoordinateList.addAll(newTotalLeftOverCoordinateList);
        /*
         * now recalculate the thresholds
         */
        if (angleSet.size() > 1) {
            calculatedAngleThreshold = getMedianFromSet(angleSet);
            pm.message("Calculated angle threshold: " + calculatedAngleThreshold + " (range: " + angleSet.first() + " to " + angleSet.last() + ")");
        } else if (angleSet.size() == 0) {
            return;
        } else {
            calculatedAngleThreshold = angleSet.first();
            pm.message("Single angle left: " + calculatedAngleThreshold);
        }
        if (distanceSet.size() > 1) {
            calculatedDistanceThreshold = getMedianFromSet(distanceSet);
            pm.message("Calculated distance threshold: " + calculatedDistanceThreshold + " (range: " + distanceSet.first() + " to " + distanceSet.last() + ")");
        } else if (distanceSet.size() == 0) {
            return;
        } else {
            calculatedDistanceThreshold = distanceSet.first();
            pm.message("Single distance left: " + calculatedDistanceThreshold);
        }
        if (calculatedDistanceThreshold < distanceThreshold) {
            calculatedDistanceThreshold = distanceThreshold;
            pm.message("Corrected calculated distance threshold to be: " + calculatedDistanceThreshold);
        }
    }

    @SuppressWarnings("rawtypes")
    private List<Coordinate> runfilterOnLeftOverData(final STRtree leftOverCoordsTree, final ConcurrentSkipListSet<Double> angleSet, final ConcurrentSkipListSet<Double> distanceSet, final Geometry triangle) {
        List<Coordinate> newLeftOverCoordinateList = new ArrayList<Coordinate>();
        Coordinate[] tinCoords = triangle.getCoordinates();
        Coordinate triangleCentroid = getTriangleCentroid(tinCoords[0], tinCoords[1], tinCoords[2]);
        // get left coords around triangle
        List triangleCoordinates = null;
        monitor.readLock().lock();
        try {
            triangleCoordinates = leftOverCoordsTree.query(triangle.getEnvelopeInternal());
        } finally {
            monitor.readLock().unlock();
        }
        /*
         * now sort the points in the triangle in distance order
         * from the triangle centroid, nearest first
         */
        TreeSet<Coordinate> centroidNearestSet = new TreeSet<Coordinate>(new PointsToCoordinateComparator(triangleCentroid));
        for (Object coordinateObj : triangleCoordinates) {
            Coordinate c = (Coordinate) coordinateObj;
            if (c.equals(tinCoords[0]) || c.equals(tinCoords[1]) || c.equals(tinCoords[2])) {
                // the seed point was reread
                continue;
            }
            int loc = SimplePointInAreaLocator.locate(c, triangle);
            if (loc == Location.INTERIOR) {
                centroidNearestSet.add(c);
            }
        }
        // find first possible ground coordinate
        boolean foundOne = false;
        for (Coordinate c : centroidNearestSet) {
            if (foundOne && !isFirstStatsCalculation) {
                if (!newLeftOverCoordinateList.contains(c))
                    newLeftOverCoordinateList.add(c);
            } else {
                /*
                 * find the nearest node and distance
                 */
                Coordinate[] nodes = getOrderedNodes(c, tinCoords[0], tinCoords[1], tinCoords[2]);
                double nearestDistance = distance3d(nodes[0], c, null);
                /*
                 * if we are here, we are doing filtering and calc of thresholds 
                 * for the next round only on the kept data.
                 */
                if (nearestDistance > calculatedDistanceThreshold) {
                    if (!newLeftOverCoordinateList.contains(c))
                        newLeftOverCoordinateList.add(c);
                    continue;
                }
                /*
                 * calculate the angle between the facet normal and the line
                 * connecting the point and the nearest facet node.
                 */
                double angle = getAngleBetweenLinePlane(c, nodes[0], nodes[1], nodes[2]);
                if (Double.isNaN(angle)) {
                    pm.errorMessage("Found NaN angle, set to 0...");
                    angle = 0.0;
                }
                if (angle > calculatedAngleThreshold && angle > angleThreshold) {
                    // TODO
                    if (!newLeftOverCoordinateList.contains(c))
                        newLeftOverCoordinateList.add(c);
                    continue;
                } else {
                    // add it to the next tin
                    synchronized (tinCoordinateList) {
                        if (!tinCoordinateList.contains(c)) {
                            tinCoordinateList.add(c);
                            foundOne = true;
                            angleSet.add(angle);
                            distanceSet.add(nearestDistance);
                        }
                    }
                }
            }
        }
        pm.worked(1);
        return newLeftOverCoordinateList;
    }

    public void finalCleanup(final double pFinalCleanupDist) {
        if (isFirstStatsCalculation) {
            throw new IllegalArgumentException("The first round needs to be filtered on all data.");
        }
        pm.beginTask("Creating points indexes...", leftOverCoordinateList.size());
        final STRtree leftOverCoordinatesTree = new STRtree(leftOverCoordinateList.size());
        for (Coordinate c : leftOverCoordinateList) {
            leftOverCoordinatesTree.insert(new Envelope(c), c);
        }
        pm.done();
        final AtomicInteger removedCount = new AtomicInteger();
        Geometry[] triangles = getTriangles();
        final List<Coordinate> newLeftOverCoordinateList = new ArrayList<Coordinate>();
        pm.beginTask("Final cleanup through triangle to point distance filter...", triangles.length);
        ThreadedRunnable tRun = new ThreadedRunnable(threadsNum, null);
        for (int i = 0; i < triangles.length; i++) {
            final Geometry triangle = triangles[i];
            tRun.executeRunnable(new Runnable() {

                public void run() {
                    runFinalFilter(leftOverCoordinatesTree, newLeftOverCoordinateList, triangle, pFinalCleanupDist, removedCount);
                }
            });
        }
        tRun.waitAndClose();
        pm.done();
        pm.message("Final points removed from non ground: " + removedCount.get());
        pm.message("Final points left as non ground: " + newLeftOverCoordinateList.size());
        leftOverCoordinateList.clear();
        leftOverCoordinateList.addAll(newLeftOverCoordinateList);
    }

    private void runFinalFilter(final STRtree leftOverCoordsTree, List<Coordinate> newLeftOverCoordinateList, final Geometry triangle, double pFinalCleanupDist, AtomicInteger removedCount) {
        Coordinate[] tinCoords = triangle.getCoordinates();
        // get left coords around triangle
        List triangleCoordinates = null;
        monitor.readLock().lock();
        try {
            triangleCoordinates = leftOverCoordsTree.query(triangle.getEnvelopeInternal());
        } finally {
            monitor.readLock().unlock();
        }
        /*
         * now sort the points in the triangle in distance order
         * from the triangle centroid, nearest first
         */
        int count = 0;
        for (Object coordinateObj : triangleCoordinates) {
            Coordinate c = (Coordinate) coordinateObj;
            int loc = SimplePointInAreaLocator.locate(c, triangle);
            if (loc == Location.INTERIOR) {
                Coordinate c1 = new Coordinate(c.x, c.y, 1E6);
                Coordinate c2 = new Coordinate(c.x, c.y, -1E6);
                Coordinate intersection = getLineWithPlaneIntersection(c1, c2, tinCoords[0], tinCoords[1], tinCoords[2]);
                double distance = distance3d(intersection, c, null);
                if (distance > pFinalCleanupDist) {
                    count++;
                    synchronized (newLeftOverCoordinateList) {
                        newLeftOverCoordinateList.add(c);
                    }
                }
            }
        }
        removedCount.addAndGet(count);
        pm.worked(1);
    }

    public void resetTin() {
        tinGeometries = null;
    }

    /**
     * Generate a tin from a given coords list. The internal tin geoms array is set from the result.
     *
     * @param coordinateList the coords to use for the tin generation.
     */
    private void generateTin(List<Coordinate> coordinateList) {
        pm.beginTask("Generate tin...", -1);
        DelaunayTriangulationBuilder b = new DelaunayTriangulationBuilder();
        b.setSites(coordinateList);
        Geometry tinTriangles = b.getTriangles(gf);
        tinGeometries = new Geometry[tinTriangles.getNumGeometries()];
        for (int i = 0; i < tinTriangles.getNumGeometries(); i++) {
            tinGeometries[i] = tinTriangles.getGeometryN(i);
        }
        pm.done();
    }

    /**
     * Generate a spatial index on the tin geometries.
     */
    public STRtree generateTinIndex(Double maxEdgeLength) {
        double maxEdge = maxEdgeLength != null ? maxEdgeLength : 0.0;
        pm.beginTask("Creating tin indexes...", tinGeometries.length);
        final STRtree tinTree = new STRtree(tinGeometries.length);
        for (Geometry geometry : tinGeometries) {
            if (maxEdgeLength != null) {
                Coordinate[] coordinates = geometry.getCoordinates();
                double maxLength = distance3d(coordinates[0], coordinates[1], null);
                double tmpLength = distance3d(coordinates[1], coordinates[2], null);
                if (tmpLength > maxLength) {
                    maxLength = tmpLength;
                }
                tmpLength = distance3d(coordinates[2], coordinates[0], null);
                if (tmpLength > maxLength) {
                    maxLength = tmpLength;
                }
                // triangles below a certain edge length are not adapted
                if (maxLength < maxEdge) {
                    continue;
                }
            }
            tinTree.insert(geometry.getEnvelopeInternal(), geometry);
        }
        pm.done();
        return tinTree;
    }

    /**
     * Checks if the tin is done. If not, it generates it with the available {@link #tinCoordinateList}.
     */
    private void checkTinGeometries() {
        if (!didInitialize) {
            throw new IllegalArgumentException("Not initialized properly. Did you call setStartCoordinates?");
        }
        if (tinGeometries == null) {
            generateTin(tinCoordinateList);
        }
    }

    /**
     * Order coordinates to have the first coordinate in the array as the nearest to a given
     * coordinate 'c'. The second and third are not ordered, but randomly added.
     *
     * @param c
     * @param coordinate1
     * @param coordinate2
     * @param coordinate3
     * @return
     */
    private Coordinate[] getOrderedNodes(Coordinate c, Coordinate coordinate1, Coordinate coordinate2, Coordinate coordinate3) {
        double d = distance3d(c, coordinate1, null);
        Coordinate nearest = coordinate1;
        Coordinate c2 = coordinate2;
        Coordinate c3 = coordinate3;
        double d2 = distance3d(c, coordinate2, null);
        if (d2 < d) {
            nearest = coordinate2;
            d = d2;
            c2 = coordinate1;
            c3 = coordinate3;
        }
        double d3 = distance3d(c, coordinate3, null);
        if (d3 < d) {
            nearest = coordinate3;
            c2 = coordinate1;
            c3 = coordinate2;
        }
        return new Coordinate[] { nearest, c2, c3 };
    }

    private double getMedianFromSet(final ConcurrentSkipListSet<Double> set) {
        double threshold = 0;
        int halfNum = set.size() / 2;
        int count = 0;
        for (double value : set) {
            if (count == halfNum) {
                threshold = value;
                break;
            }
            count++;
        }
        return threshold;
    }

    private double getAverageFromSet(final ConcurrentSkipListSet<Double> set) {
        double sum = 0;
        int count = 0;
        for (double value : set) {
            sum = sum + value;
            count++;
        }
        return sum / count;
    }

    private double getCenterFromSet(final ConcurrentSkipListSet<Double> set) {
        return (set.last() - set.first()) / 2;
    }

    /**
     * Create a {@link SimpleFeatureCollection FeatureCollection} from the current tin triangles
     * with information about the vertexes elevation.
     *
     * @return the feature collection of the tin.
     */
    public SimpleFeatureCollection toFeatureCollection() {
        checkTinGeometries();
        SimpleFeatureTypeBuilder b = new SimpleFeatureTypeBuilder();
        b.setName("triangle");
        b.setCRS(crs);
        DefaultFeatureCollection newCollection = new DefaultFeatureCollection();
        b.add("the_geom", Polygon.clreplaced);
        b.add("elev0", Double.clreplaced);
        b.add("elev1", Double.clreplaced);
        b.add("elev2", Double.clreplaced);
        SimpleFeatureType type = b.buildFeatureType();
        SimpleFeatureBuilder builder = new SimpleFeatureBuilder(type);
        for (Geometry g : tinGeometries) {
            Coordinate[] coordinates = g.getCoordinates();
            Object[] values;
            int windingRule = GeometryUtilities.getTriangleWindingRule(coordinates[0], coordinates[1], coordinates[2]);
            if (windingRule > 0) {
                // need to reverse the triangle
                values = new Object[] { g, coordinates[0].z, coordinates[2].z, coordinates[1].z };
            } else {
                values = new Object[] { g, coordinates[0].z, coordinates[1].z, coordinates[2].z };
            }
            builder.addAll(values);
            SimpleFeature feature = builder.buildFeature(null);
            newCollection.add(feature);
        }
        return newCollection;
    }

    public SimpleFeatureCollection toFeatureCollectionOthers() {
        SimpleFeatureTypeBuilder b = new SimpleFeatureTypeBuilder();
        b.setName("points");
        b.setCRS(crs);
        DefaultFeatureCollection newCollection = new DefaultFeatureCollection();
        b.add("the_geom", Point.clreplaced);
        b.add("elev", Double.clreplaced);
        SimpleFeatureType type = b.buildFeatureType();
        SimpleFeatureBuilder builder = new SimpleFeatureBuilder(type);
        for (Coordinate c : leftOverCoordinateList) {
            Object[] values = new Object[] { gf.createPoint(c), c.z };
            builder.addAll(values);
            SimpleFeature feature = builder.buildFeature(null);
            newCollection.add(feature);
        }
        return newCollection;
    }

    public SimpleFeatureCollection toFeatureCollectionTinPoints() {
        SimpleFeatureTypeBuilder b = new SimpleFeatureTypeBuilder();
        b.setName("points");
        b.setCRS(crs);
        DefaultFeatureCollection newCollection = new DefaultFeatureCollection();
        b.add("the_geom", Point.clreplaced);
        b.add("elev", Double.clreplaced);
        SimpleFeatureType type = b.buildFeatureType();
        SimpleFeatureBuilder builder = new SimpleFeatureBuilder(type);
        for (Coordinate c : tinCoordinateList) {
            Object[] values = new Object[] { gf.createPoint(c), c.z };
            builder.addAll(values);
            SimpleFeature feature = builder.buildFeature(null);
            newCollection.add(feature);
        }
        return newCollection;
    }

    public double[] getMinMaxElev() {
        double min = Double.POSITIVE_INFINITY;
        double max = Double.NEGATIVE_INFINITY;
        for (Coordinate coordinate : tinCoordinateList) {
            max = Math.max(max, coordinate.z);
            min = Math.min(min, coordinate.z);
        }
        return new double[] { min, max };
    }
    // private AtomicInteger count = new AtomicInteger();
    // private void dumpPointsInGeom( Geometry tinGeom, List<LasRecord> pointsInGeom,
    // List<Coordinate> addedPoints )
    // throws IOException {
    // String path = "/home/moovida/dati_unibz/outshape/tinfilter/triangles/";
    // int i = count.getAndIncrement();
    // {
    // SimpleFeatureTypeBuilder b = new SimpleFeatureTypeBuilder();
    // b.setName("t" + i);
    // b.setCRS(crs);
    // 
    // DefaultFeatureCollection newCollection = new DefaultFeatureCollection();
    // b.add("the_geom", Polygon.clreplaced);
    // b.add("elev1", Double.clreplaced);
    // b.add("elev2", Double.clreplaced);
    // b.add("elev3", Double.clreplaced);
    // SimpleFeatureType type = b.buildFeatureType();
    // SimpleFeatureBuilder builder = new SimpleFeatureBuilder(type);
    // Coordinate[] coordinates = tinGeom.getCoordinates();
    // Object[] values = new Object[]{tinGeom, coordinates[0].z, coordinates[1].z,
    // coordinates[2].z};
    // builder.addAll(values);
    // SimpleFeature feature = builder.buildFeature(null);
    // newCollection.add(feature);
    // 
    // OmsVectorWriter.writeVector(path + "t" + i + ".shp", newCollection);
    // }
    // {
    // SimpleFeatureTypeBuilder b = new SimpleFeatureTypeBuilder();
    // b.setName("p" + i);
    // b.setCRS(crs);
    // 
    // DefaultFeatureCollection newCollection = new DefaultFeatureCollection();
    // b.add("the_geom", Point.clreplaced);
    // b.add("elev", Double.clreplaced);
    // SimpleFeatureType type = b.buildFeatureType();
    // SimpleFeatureBuilder builder = new SimpleFeatureBuilder(type);
    // 
    // for( LasRecord lasRecord : pointsInGeom ) {
    // Point point = gf.createPoint(new Coordinate(lasRecord.x, lasRecord.y, lasRecord.z));
    // Object[] values = new Object[]{point, lasRecord.z};
    // builder.addAll(values);
    // SimpleFeature feature = builder.buildFeature(null);
    // newCollection.add(feature);
    // }
    // 
    // OmsVectorWriter.writeVector(path + "p" + i + ".shp", newCollection);
    // }
    // {
    // SimpleFeatureTypeBuilder b = new SimpleFeatureTypeBuilder();
    // b.setName("a" + i);
    // b.setCRS(crs);
    // 
    // DefaultFeatureCollection newCollection = new DefaultFeatureCollection();
    // b.add("the_geom", Point.clreplaced);
    // b.add("elev", Double.clreplaced);
    // SimpleFeatureType type = b.buildFeatureType();
    // SimpleFeatureBuilder builder = new SimpleFeatureBuilder(type);
    // 
    // for( Coordinate coord : addedPoints ) {
    // Point point = gf.createPoint(coord);
    // Object[] values = new Object[]{point, coord.z};
    // builder.addAll(values);
    // SimpleFeature feature = builder.buildFeature(null);
    // newCollection.add(feature);
    // }
    // 
    // OmsVectorWriter.writeVector(path + "a" + i + ".shp", newCollection);
    // }
    // }
}

14 View Complete Implementation : DatabaseViewer.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
public boolean viewSpatialQueryResult(String tableName, String sqlText, IHMProgressMonitor pm, boolean isTableQuery) {
    boolean hasError = false;
    if (sqlText.trim().length() == 0) {
        return false;
    }
    try {
        pm.beginTask("Run query: " + sqlText, IHMProgressMonitor.UNKNOWN);
        DefaultFeatureCollection fc = DbsHelper.runRawSqlToFeatureCollection(tableName, currentConnectedDatabase, sqlText, null);
        ReprojectingFeatureCollection rfc = new ReprojectingFeatureCollection(fc, NwwUtilities.GPS_CRS);
        Style[] styles = null;
        if (isTableQuery && tableName != null) {
            // try to get some style
            if (currentConnectedDatabase.getType() == EDb.GEOPACKAGE) {
                String sldString = ((GeopackageCommonDb) currentConnectedDatabase).getSldString(tableName);
                if (sldString != null) {
                    Style style = SldUtilities.getStyleFromSldString(sldString);
                    styles = new Style[] { style };
                }
            }
        }
        showInMapFrame(true, new SimpleFeatureCollection[] { rfc }, styles);
        addQueryToHistoryCombo(sqlText);
    } catch (Exception e1) {
        String localizedMessage = e1.getLocalizedMessage();
        hasError = true;
        pm.errorMessage("An error occurred: " + localizedMessage);
    } finally {
        pm.done();
    }
    return hasError;
}

14 View Complete Implementation : OmsGeopaparazzi4Converter.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
private void complexNotesToShapefile(IHMConnection connection, File outputFolderFile, IHMProgressMonitor pm) throws Exception {
    HashMap<String, SimpleFeatureCollection> name2CollectionMap = complexNotes2featurecollections(connection, pm);
    pm.beginTask("Writing layers to shapefile...", name2CollectionMap.size());
    Set<Entry<String, SimpleFeatureCollection>> entrySet2 = name2CollectionMap.entrySet();
    for (Entry<String, SimpleFeatureCollection> entry : entrySet2) {
        String name = entry.getKey();
        int lastUnderscore = name.lastIndexOf('_');
        name = name.substring(0, lastUnderscore);
        SimpleFeatureCollection collection = entry.getValue();
        String fileName = "notes_" + name + ".shp";
        fileName = FileUtilities.getSafeFileName(fileName);
        File outFile = new File(outputFolderFile, fileName);
        if (outFile.exists()) {
            File[] listFiles = outputFolderFile.listFiles();
            List<String> fileNames = new ArrayList<>();
            for (File file : listFiles) {
                fileNames.add(FileUtilities.getNameWithoutExtention(file));
            }
            String shpName = FileUtilities.getNameWithoutExtention(outFile);
            String safeShpName = StringUtilities.checkSameName(fileNames, shpName);
            outFile = new File(outputFolderFile, safeShpName + ".shp");
        }
        dumpVector(collection, outFile.getAbsolutePath());
        pm.worked(1);
    }
    pm.done();
}

13 View Complete Implementation : OmsGeopaparazzi4Converter.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
public static SimpleFeatureCollection media2IdBasedFeatureCollection(IHMConnection connection, IHMProgressMonitor pm) throws Exception, IOException, FileNotFoundException {
    try {
        GeometryFactory gf = GeometryUtilities.gf();
        /*
             * create the points fc
             */
        DefaultFeatureCollection newCollection = new DefaultFeatureCollection();
        SimpleFeatureType featureType = GeopaparazziUtilities.getMediaFeaturetype();
        List<Image> imagesList = DaoImages.getImagesList(connection);
        pm.beginTask("Importing media...", imagesList.size());
        for (Image image : imagesList) {
            Point point = gf.createPoint(new Coordinate(image.getLon(), image.getLat()));
            long ts = image.getTs();
            String dateTimeString = ETimeUtilities.INSTANCE.TIME_FORMATTER_LOCAL.format(new Date(ts));
            Object[] values = new Object[] { point, image.getAltim(), dateTimeString, image.getAzim(), image.getImageDataId() };
            SimpleFeatureBuilder builder = new SimpleFeatureBuilder(featureType);
            builder.addAll(values);
            SimpleFeature feature = builder.buildFeature(null);
            newCollection.add(feature);
            pm.worked(1);
        }
        return newCollection;
    } finally {
        pm.done();
    }
}

13 View Complete Implementation : OmsGeopaparazzi4Converter.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
/**
 * Convert the simple notes to a featurecollection.
 *
 * @param connection the db connection.
 * @param pm the monitor.
 * @return the extracted collection.
 * @throws Exception
 */
public static SimpleFeatureCollection simpleNotes2featurecollection(IHMConnection connection, IHMProgressMonitor pm) throws Exception {
    SimpleFeatureType featureType = GeopaparazziUtilities.getSimpleNotesfeatureType();
    String sql = // 
    "select " + latFN + // 
    "," + lonFN + // 
    "," + altimFN + // 
    "," + tsFN + // 
    "," + textFN + // 
    "," + descFN + // 
    "," + dirtyFN + // 
    "," + formFN + // 
    " from " + TABLE_NOTES + " where " + formFN + " is null or " + formFN + " = ''";
    SimpleFeatureBuilder builder = new SimpleFeatureBuilder(featureType);
    pm.beginTask("Processing notes...", -1);
    SimpleFeatureCollection newCollection = new DefaultFeatureCollection();
    try (IHMStatement statement = connection.createStatement();
        IHMResultSet rs = statement.executeQuery(sql)) {
        while (rs.next()) {
            String form = rs.getString(formFN);
            if (form != null && form.trim().length() != 0) {
                continue;
            }
            double lat = rs.getDouble(latFN);
            double lon = rs.getDouble(lonFN);
            double altim = rs.getDouble(altimFN);
            long ts = rs.getLong(tsFN);
            String dateTimeString = ETimeUtilities.INSTANCE.TIME_FORMATTER_LOCAL.format(new Date(ts));
            String text = rs.getString(textFN);
            String descr = rs.getString(descFN);
            if (descr == null)
                descr = EMPTY_STRING;
            int isDirty = rs.getInt(dirtyFN);
            if (lat == 0 || lon == 0) {
                continue;
            }
            // and then create the features
            Coordinate c = new Coordinate(lon, lat);
            Point point = gf.createPoint(c);
            Object[] values = new Object[] { point, text, descr, dateTimeString, altim, isDirty };
            builder.addAll(values);
            SimpleFeature feature = builder.buildFeature(null);
            ((DefaultFeatureCollection) newCollection).add(feature);
        }
    }
    return newCollection;
}

13 View Complete Implementation : CoupledFieldsMoments.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
public double[][] process(RenderedImage map1RI, RenderedImage map2RI, int pBins, int pFirst, int pLast, IHMProgressMonitor pm, int binmode) {
    if (map2RI == null) {
        map2RI = map1RI;
    }
    GearsMessageHandler msg = GearsMessageHandler.getInstance();
    pm.message(msg.message("cb.vectorize"));
    double[] U = vectorizeDoubleMatrix(map1RI);
    double[] T = null;
    QuickSortAlgorithm t = new QuickSortAlgorithm(pm);
    if (map2RI == null) {
        T = U;
        t.sort(U, (double[]) null);
    } else {
        T = vectorizeDoubleMatrix(map2RI);
        t.sort(U, T);
    }
    SplitVectors theSplit = new SplitVectors();
    int num_max = 1000;
    /*
         * if (bintype == 1) {
         */
    pm.message(msg.message("cb.splitvector"));
    split2realvectors(U, T, theSplit, pBins, num_max, pm);
    /*
         * } else { delta = FluidUtils.exponentialsplit2realvectors(U, T,
         * theSplit, N, num_max, base); }
         */
    pm.message(msg.message("cb.creatematrix"));
    double[][] outCb = new double[theSplit.splitIndex.length][pLast - pFirst + 3];
    // kept for future expansion
    binmode = 1;
    if (// always true for now, other modes not implemented yet
    binmode == 1) {
        for (int h = 0; h < theSplit.splitIndex.length; h++) {
            outCb[h][0] = calculateNthMoment(theSplit.splitValues1[h], (int) theSplit.splitIndex[h], 0.0, 1.0, pm);
            outCb[h][1] = theSplit.splitIndex[h];
            outCb[h][2] = calculateNthMoment(theSplit.splitValues2[h], (int) theSplit.splitIndex[h], 0.0, 1.0, pm);
            if (pFirst == 1)
                pFirst++;
            for (int k = pFirst; k <= pLast; k++) {
                outCb[h][k - pFirst + 3] = calculateNthMoment(theSplit.splitValues2[h], (int) theSplit.splitIndex[h], outCb[h][1], (double) k, pm);
            }
        }
    }
    // else if (binmode == 2) // why is this exactly the same as the mode
    // // 'H' ???
    // {
    // for( int h = 0; h < theSplit.splittedindex.length; h++ ) {
    // moments[h][0] =
    // FluidUtils.double_n_moment(theSplit.splittedvalues1[h],
    // (int) theSplit.splittedindex[h], 0.0, 1.0);
    // moments[h][1] =
    // FluidUtils.double_n_moment(theSplit.splittedvalues2[h],
    // (int) theSplit.splittedindex[h], 0.0, 1.0);
    // 
    // if (firstmoment == 1)
    // firstmoment++;
    // for( int k = firstmoment; k <= secondmoment; k++ ) {
    // moments[h][k - firstmoment + 2] = FluidUtils.double_n_moment(
    // theSplit.splittedvalues2[h], (int) theSplit.splittedindex[h],
    // moments[h][k - firstmoment + 1], (double) k);
    // }
    // }
    // }
    return outCb;
}

12 View Complete Implementation : GeopaparazziController.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
/**
 * The spatialtoolbox view controller.
 *
 * @author Andrea Antonello (www.hydrologis.com)
 */
public abstract clreplaced GeopaparazziController extends GeopaparazziView implements IOnCloseListener {

    private static final String RED_HEXA = "#FF0000";

    private static final long serialVersionUID = 1L;

    protected HashMap<String, String> prefsMap = new HashMap<>();

    protected GuiBridgeHandler guiBridge;

    protected IHMProgressMonitor pm = new LogProgressMonitor();

    private List<ProjectInfo> projectInfos = new ArrayList<>();

    protected ProjectInfo currentSelectedProject = null;

    protected Image currentSelectedImage = null;

    protected GpsLog currentSelectedGpsLog = null;

    protected Note currentSelectedNote = null;

    private Dimension preferredButtonSize = new Dimension(30, 30);

    private JTextPane _infoArea;

    private RenderableLayer geopapDataLayer;

    private NwwPanel wwjPanel;

    private ProjectInfo currentLoadedProject;

    @SuppressWarnings({ "unchecked", "rawtypes" })
    public GeopaparazziController(GuiBridgeHandler guiBridge) {
        this.guiBridge = guiBridge;
        setPreferredSize(new Dimension(900, 600));
        HashMap<String, String> prefsMapTmp = guiBridge.getGeopaparazziProjectViewerPreferencesMap();
        if (prefsMapTmp != null) {
            prefsMap = (HashMap) prefsMapTmp;
        }
        init();
    }

    @SuppressWarnings({ "serial" })
    private void init() {
        _infoArea = new JTextPane();
        // _infoArea.setDoreplacedent(new SqlDoreplacedent());
        _infoArea.setContentType("text/html");
        _infoArea.setEditable(false);
        _infoScroll.setViewportView(_infoArea);
        // _infoScroll.setMinimumSize(new Dimension(10, 200));
        _chartHolder.setLayout(new BorderLayout());
        _loadFolderButton.setIcon(ImageCache.getInstance().getImage(ImageCache.REFRESH));
        _loadFolderButton.setText("");
        _loadFolderButton.setPreferredSize(preferredButtonSize);
        _loadFolderButton.addActionListener(e -> {
            final File geopaparazziFolder = new File(_projectsFolderTextfield.getText());
            if (!geopaparazziFolder.exists()) {
                GuiUtilities.showWarningMessage(this, null, "The projects folder doesn't exist.");
                return;
            }
            File[] projectFiles = GeopaparazziUtilities.getGeopaparazziFiles(geopaparazziFolder);
            try {
                projectInfos = readProjectInfos(projectFiles);
                layoutTree(projectInfos, false);
                _filterTextfield.setText("");
            } catch (Exception e1) {
                Logger.INSTANCE.insertError("", "error", e1);
            }
        });
        _projectsFolderBrowseButton.setPreferredSize(preferredButtonSize);
        _projectsFolderBrowseButton.addActionListener(e -> {
            File[] openFiles = guiBridge.showOpenDirectoryDialog("Open projects folder", PreferencesHandler.getLastFile());
            if (openFiles != null && openFiles.length > 0) {
                try {
                    PreferencesHandler.setLastPath(openFiles[0].getAbsolutePath());
                } catch (Exception e1) {
                    Logger.INSTANCE.insertError("", "ERROR", e1);
                }
            } else {
                return;
            }
            _projectsFolderTextfield.setText(openFiles[0].getAbsolutePath());
        });
        String lastSavedPath = prefsMap.get(GuiBridgeHandler.LAST_GP_PROJECTS_PATH);
        _projectsFolderTextfield.setText(lastSavedPath);
        _filterTextfield.addKeyListener(new KeyAdapter() {

            @Override
            public void keyReleased(KeyEvent e) {
                String filterText = _filterTextfield.getText().toLowerCase();
                final List<ProjectInfo> filtered = new ArrayList<ProjectInfo>();
                if (filterText == null) {
                    filtered.addAll(projectInfos);
                } else {
                    for (ProjectInfo projectInfo : projectInfos) {
                        if (projectInfo.fileName.toLowerCase().contains(filterText) || projectInfo.metadata.toLowerCase().contains(filterText)) {
                            filtered.add(projectInfo);
                        }
                    }
                }
                layoutTree(filtered, false);
            }
        });
        addComponentListener(new ComponentListener() {

            public void componentShown(ComponentEvent e) {
            }

            public void componentResized(ComponentEvent e) {
            }

            public void componentMoved(ComponentEvent e) {
            }

            public void componentHidden(ComponentEvent e) {
                onClose();
            }
        });
        try {
            _databaseTreeView.setMinimumSize(new Dimension(300, 200));
            addJtreeDragNDrop();
            addJtreeContextMenu();
            _databaseTree.setRootVisible(false);
            _databaseTree.setCellRenderer(new DefaultTreeCellRenderer() {

                @Override
                public java.awt.Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
                    super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
                    if (value instanceof ProjectInfo) {
                        setIcon(ImageCache.getInstance().getImage(ImageCache.DATABASE));
                    } else if (value instanceof Image) {
                        setIcon(ImageCache.getInstance().getImage(ImageCache.DBIMAGE));
                    } else if (value instanceof GpsLog) {
                        setIcon(ImageCache.getInstance().getImage(ImageCache.GEOM_LINE));
                    } else if (value instanceof Note) {
                        setIcon(ImageCache.getInstance().getImage(ImageCache.NOTE));
                    }
                    return this;
                }
            });
            _databaseTree.addTreeSelectionListener(new TreeSelectionListener() {

                public void valueChanged(TreeSelectionEvent evt) {
                    TreePath[] paths = evt.getPaths();
                    currentSelectedProject = null;
                    currentSelectedImage = null;
                    currentSelectedNote = null;
                    currentSelectedGpsLog = null;
                    _chartHolder.removeAll();
                    if (paths.length > 0) {
                        Object selectedItem = paths[0].getLastPathComponent();
                        if (selectedItem instanceof ProjectInfo) {
                            currentSelectedProject = (ProjectInfo) selectedItem;
                            selectProjectInfo(currentSelectedProject);
                            Logger.INSTANCE.insertDebug("", "Selected project: " + currentSelectedProject.fileName);
                        }
                        if (selectedItem instanceof Image) {
                            currentSelectedImage = (Image) selectedItem;
                            currentSelectedProject = getProjectForImage(currentSelectedImage);
                            selectImage(currentSelectedImage);
                            Logger.INSTANCE.insertDebug("", "Selected image: " + currentSelectedImage.getName() + " of project " + currentSelectedProject.fileName);
                        }
                        if (selectedItem instanceof GpsLog) {
                            currentSelectedGpsLog = (GpsLog) selectedItem;
                            currentSelectedProject = getProjectForGpsLog(currentSelectedGpsLog);
                            selectGpsLog(currentSelectedGpsLog);
                            Logger.INSTANCE.insertDebug("", "Selected gpslog: " + currentSelectedGpsLog.text + " of project " + currentSelectedProject.fileName);
                        }
                        if (selectedItem instanceof Note) {
                            currentSelectedNote = (Note) selectedItem;
                            currentSelectedProject = getProjectForNote(currentSelectedNote);
                            selectNote(currentSelectedNote);
                            Logger.INSTANCE.insertDebug("", "Selected note: " + currentSelectedNote.simpleText + " of project " + currentSelectedProject.fileName);
                        }
                    }
                }
            });
            _databaseTree.setVisible(false);
        } catch (Exception e1) {
            Logger.INSTANCE.insertError("", "Error", e1);
        }
        layoutTree(null, false);
        Component wwjPanelComponent = null;
        try {
            wwjPanelComponent = NwwPanel.createNwwPanel(true);
        } catch (UnsatisfiedLinkError e1) {
        // ignore
        }
        if (wwjPanelComponent instanceof NwwPanel) {
            _nwwHolder.setLayout(new BorderLayout());
            _nwwHolder.add(wwjPanelComponent, BorderLayout.CENTER);
            wwjPanel = (NwwPanel) wwjPanelComponent;
            wwjPanel.addOsmLayer();
            geopapDataLayer = new RenderableLayer();
            wwjPanel.addLayer(geopapDataLayer);
        } else {
            _nwwHolderFrame.setVisible(false);
            _chartHolderFrame.setVisible(false);
            setPreferredSize(new Dimension(400, 600));
        }
    }

    private List<ProjectInfo> readProjectInfos(File[] projectFiles) throws Exception {
        List<ProjectInfo> infoList = new ArrayList<ProjectInfo>();
        for (File geopapDatabaseFile : projectFiles) {
            try (SqliteDb db = new SqliteDb()) {
                db.open(geopapDatabaseFile.getAbsolutePath());
                ProjectInfo resInfo = db.execOnConnection(connection -> {
                    String projectInfo = GeopaparazziUtilities.getProjectInfo(connection, true);
                    ProjectInfo info = new ProjectInfo();
                    info.databaseFile = geopapDatabaseFile;
                    info.fileName = geopapDatabaseFile.getName();
                    info.metadata = projectInfo;
                    List<org.hortonmachine.gears.io.geopaparazzi.geopap4.Image> imagesList = DaoImages.getImagesList(connection);
                    info.images = imagesList.toArray(new org.hortonmachine.gears.io.geopaparazzi.geopap4.Image[0]);
                    List<Note> notesList = DaoNotes.getNotesList(connection, null);
                    info.notes = notesList;
                    List<GpsLog> logsList = DaoGpsLog.getLogsList(connection);
                    info.logs = logsList;
                    return info;
                });
                infoList.add(resInfo);
            }
        }
        return infoList;
    }

    private ProjectInfo getProjectForImage(Image currentSelectedImage) {
        boolean doBreak = false;
        ProjectInfo selectedProject = null;
        for (ProjectInfo projectInfo : projectInfos) {
            for (org.hortonmachine.gears.io.geopaparazzi.geopap4.Image tmpImage : projectInfo.images) {
                if (tmpImage.equals(currentSelectedImage)) {
                    selectedProject = projectInfo;
                    doBreak = true;
                    break;
                }
            }
            if (doBreak) {
                break;
            }
        }
        return selectedProject;
    }

    private ProjectInfo getProjectForGpsLog(GpsLog currentSelectedGpsLog) {
        ProjectInfo selectedProject = null;
        for (ProjectInfo projectInfo : projectInfos) {
            if (projectInfo.logs.contains(currentSelectedGpsLog)) {
                selectedProject = projectInfo;
                break;
            }
        }
        return selectedProject;
    }

    private ProjectInfo getProjectForNote(Note currentSelectedNote) {
        ProjectInfo selectedProject = null;
        for (ProjectInfo projectInfo : projectInfos) {
            if (projectInfo.notes.contains(currentSelectedNote)) {
                selectedProject = projectInfo;
                break;
            }
        }
        return selectedProject;
    }

    private void addJtreeDragNDrop() {
        _databaseTree.setDragEnabled(true);
        _databaseTree.setTransferHandler(new TransferHandler(null) {

            public int getSourceActions(JComponent c) {
                return COPY;
            }

            protected Transferable createTransferable(JComponent c) {
                if (c instanceof JTree) {
                    if (currentSelectedImage != null) {
                        return new StringSelection(currentSelectedImage.getName());
                    } else if (currentSelectedGpsLog != null) {
                        return new StringSelection(currentSelectedGpsLog.text);
                    }
                }
                return new StringSelection("");
            }
        });
    }

    private void addJtreeContextMenu() {
        JPopupMenu popupMenu = new JPopupMenu();
        popupMenu.setBorder(new BevelBorder(BevelBorder.RAISED));
        popupMenu.addPopupMenuListener(new PopupMenuListener() {

            @Override
            public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
                if (currentSelectedImage != null) {
                    Logger.INSTANCE.insertDebug("", "PopupMenuEvent on image: " + currentSelectedImage.getName());
                    List<Action> tableActions = makeImageAction(currentSelectedImage);
                    if (tableActions != null)
                        for (Action action : tableActions) {
                            if (action != null) {
                                JMenuItem item = new JMenuItem(action);
                                popupMenu.add(item);
                                item.setHorizontalTextPosition(JMenuItem.RIGHT);
                            } else {
                                popupMenu.add(new JSeparator());
                            }
                        }
                } else if (currentSelectedGpsLog != null) {
                    Logger.INSTANCE.insertDebug("", "PopupMenuEvent on log: " + currentSelectedGpsLog.text);
                    List<Action> logActions = makeGpsLogActions(currentSelectedGpsLog);
                    if (logActions != null)
                        for (Action action : logActions) {
                            if (action != null) {
                                JMenuItem item = new JMenuItem(action);
                                popupMenu.add(item);
                                item.setHorizontalTextPosition(JMenuItem.RIGHT);
                            } else {
                                popupMenu.add(new JSeparator());
                            }
                        }
                } else if (currentSelectedNote != null) {
                    Logger.INSTANCE.insertDebug("", "PopupMenuEvent on note: " + currentSelectedNote.simpleText);
                    List<Action> notesActions = makeNotesActions(currentSelectedNote);
                    if (notesActions != null)
                        for (Action action : notesActions) {
                            if (action != null) {
                                JMenuItem item = new JMenuItem(action);
                                popupMenu.add(item);
                                item.setHorizontalTextPosition(JMenuItem.RIGHT);
                            } else {
                                popupMenu.add(new JSeparator());
                            }
                        }
                } else if (currentSelectedProject != null) {
                    Logger.INSTANCE.insertDebug("", "PopupMenuEvent on project: " + currentSelectedProject.fileName);
                    List<Action> dbActions = makeProjectAction(currentSelectedProject);
                    if (dbActions != null)
                        for (Action action : dbActions) {
                            if (action != null) {
                                JMenuItem item = new JMenuItem(action);
                                popupMenu.add(item);
                                item.setHorizontalTextPosition(JMenuItem.RIGHT);
                            } else {
                                popupMenu.add(new JSeparator());
                            }
                        }
                }
                Logger.INSTANCE.insertDebug("", "PopupMenuEvent with no available object to load menu from");
            }

            @Override
            public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
                popupMenu.removeAll();
            }

            @Override
            public void popupMenuCanceled(PopupMenuEvent e) {
                popupMenu.removeAll();
            }
        });
        _databaseTree.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseClicked(MouseEvent e) {
                if (SwingUtilities.isRightMouseButton(e)) {
                    int row = _databaseTree.getClosestRowForLocation(e.getX(), e.getY());
                    _databaseTree.setSelectionRow(row);
                    popupMenu.show(e.getComponent(), e.getX(), e.getY());
                }
            }
        });
    }

    private void layoutTree(List<ProjectInfo> projectInfos, boolean expandNodes) {
        if (projectInfos != null) {
            _databaseTree.setVisible(true);
        } else {
            projectInfos = new ArrayList<>();
            _databaseTree.setVisible(false);
        }
        ObjectTreeModel model = new ObjectTreeModel();
        model.setRoot(projectInfos);
        _databaseTree.setModel(model);
        if (expandNodes) {
            _databaseTree.expandRow(0);
        // _databaseTree.expandRow(1);
        }
    // expandAllNodes(_databaseTree, 0, 2);
    }

    private void expandAllNodes(JTree tree, int startingIndex, int rowCount) {
        for (int i = startingIndex; i < rowCount; ++i) {
            tree.expandRow(i);
        }
        if (tree.getRowCount() != rowCount) {
            expandAllNodes(tree, rowCount, tree.getRowCount());
        }
    }

    clreplaced ObjectTreeModel implements TreeModel {

        private List<ProjectInfo> root;

        private EventListenerList listenerList = new EventListenerList();

        /**
         * Constructs an empty tree.
         */
        public ObjectTreeModel() {
            root = null;
        }

        /**
         * Sets the root to a given variable.
         * @param v the variable that is being described by this tree
         */
        public void setRoot(List<ProjectInfo> v) {
            List<ProjectInfo> oldRoot = v;
            root = v;
            fireTreeStructureChanged(oldRoot);
        }

        public Object getRoot() {
            return root;
        }

        @SuppressWarnings("rawtypes")
        public int getChildCount(Object parent) {
            if (parent instanceof ProjectInfo) {
                ProjectInfo projectInfo = (ProjectInfo) parent;
                int childCount = projectInfo.images.length + projectInfo.logs.size() + projectInfo.notes.size();
                return childCount;
            } else if (parent instanceof Image) {
                return 0;
            } else if (parent instanceof GpsLog) {
                return 0;
            } else if (parent instanceof Note) {
                return 0;
            } else if (parent instanceof List) {
                List list = (List) parent;
                return list.size();
            }
            return 0;
        }

        @SuppressWarnings("rawtypes")
        public Object getChild(Object parent, int index) {
            if (parent instanceof ProjectInfo) {
                ProjectInfo projectInfo = (ProjectInfo) parent;
                int imagesCount = projectInfo.images.length;
                int logsCount = projectInfo.logs.size();
                if (index > imagesCount + logsCount - 1) {
                    return projectInfo.notes.get(index - imagesCount - logsCount);
                } else if (index > imagesCount - 1) {
                    return projectInfo.logs.get(index - imagesCount);
                } else {
                    return projectInfo.images[index];
                }
            } else if (parent instanceof List) {
                List list = (List) parent;
                Object item = list.get(index);
                return item;
            }
            return null;
        }

        public int getIndexOfChild(Object parent, Object child) {
            int n = getChildCount(parent);
            for (int i = 0; i < n; i++) if (getChild(parent, i).equals(child))
                return i;
            return -1;
        }

        public boolean isLeaf(Object node) {
            return getChildCount(node) == 0;
        }

        public void valueForPathChanged(TreePath path, Object newValue) {
        }

        public void addTreeModelListener(TreeModelListener l) {
            listenerList.add(TreeModelListener.clreplaced, l);
        }

        public void removeTreeModelListener(TreeModelListener l) {
            listenerList.remove(TreeModelListener.clreplaced, l);
        }

        protected void fireTreeStructureChanged(Object oldRoot) {
            TreeModelEvent event = new TreeModelEvent(this, new Object[] { oldRoot });
            EventListener[] listeners = listenerList.getListeners(TreeModelListener.clreplaced);
            for (int i = 0; i < listeners.length; i++) ((TreeModelListener) listeners[i]).treeStructureChanged(event);
        }
    }

    public JComponent asJComponent() {
        return this;
    }

    public void onClose() {
        try {
            String lastPath = _projectsFolderTextfield.getText();
            File file = new File(lastPath);
            if (file.exists() && file.isDirectory()) {
                prefsMap.put(GuiBridgeHandler.LAST_GP_PROJECTS_PATH, lastPath);
                guiBridge.setGeopaparazziProjectViewerPreferencesMap(prefsMap);
            }
        } catch (Exception e) {
            Logger.INSTANCE.insertError("", "Error", e);
        }
    }

    protected void setDbTreereplacedle(String replacedle) {
        Border databaseTreeViewBorder = _databaseTreeView.getBorder();
        if (databaseTreeViewBorder instanceof replacedledBorder) {
            replacedledBorder tBorder = (replacedledBorder) databaseTreeViewBorder;
            tBorder.setreplacedle(replacedle);
        }
    }

    private void selectProjectInfo(ProjectInfo selectedProject) {
        try {
            String replacedleName = selectedProject.fileName;
            replacedleName = replacedleName.replace('_', ' ').replaceFirst("\\.gpap", "");
            String text = replacedleName + "<br/><br/>" + selectedProject.metadata;
            _infoArea.setText(text);
        } catch (Exception e) {
            Logger.INSTANCE.insertError("", "error", e);
        }
    }

    private void selectImage(org.hortonmachine.gears.io.geopaparazzi.geopap4.Image selectedImage) {
        try {
            checkLoadedProject();
            String dateTimeString = ETimeUtilities.INSTANCE.TIME_FORMATTER_LOCAL.format(new Date(selectedImage.getTs()));
            String picInfo = // 
            "<b>Image:</b> " + GeopaparazziUtilities.escapeHTML(selectedImage.getName()) + "<br/>" + "<b>Timestamp:</b> " + dateTimeString + // 
            "<br/>" + "<b>Azimuth:</b> " + (int) selectedImage.getAzim() + // 
            " deg<br/>" + "<b>Altim:</b> " + (int) selectedImage.getAltim() + " m<br/>";
            _infoArea.setText(picInfo);
            if (wwjPanel != null)
                wwjPanel.goTo(selectedImage.getLon(), selectedImage.getLat(), 1000.0, null, false);
        } catch (Exception e) {
            Logger.INSTANCE.insertError("", "error", e);
            setNoProjectLabel();
        }
    }

    private void checkLoadedProject() throws Exception {
        if (currentLoadedProject == null || currentLoadedProject != currentSelectedProject) {
            loadProjectData(currentSelectedProject, false);
        }
    }

    private void selectNote(Note selectedNote) {
        try {
            checkLoadedProject();
            String dateTimeString = ETimeUtilities.INSTANCE.TIME_FORMATTER_LOCAL.format(new Date(selectedNote.timeStamp));
            String picInfo = // 
            "<b>Text:</b> " + GeopaparazziUtilities.escapeHTML(selectedNote.simpleText) + "<br/>" + "<b>Description:</b> " + GeopaparazziUtilities.escapeHTML(selectedNote.description) + // 
            "<br/>" + "<b>Timestamp:</b> " + dateTimeString + // 
            "<br/>" + "<b>Altim:</b> " + (int) selectedNote.altim + " m<br/>";
            _infoArea.setText(picInfo);
            if (wwjPanel != null)
                wwjPanel.goTo(selectedNote.lon, selectedNote.lat, 1000.0, null, false);
        } catch (Exception e) {
            Logger.INSTANCE.insertError("", "error", e);
            setNoProjectLabel();
        }
    }

    private void selectGpsLog(GpsLog selectedLog) {
        try {
            checkLoadedProject();
            String startDateTimeString = ETimeUtilities.INSTANCE.TIME_FORMATTER_LOCAL.format(new Date(selectedLog.startTime));
            String endDateTimeString = ETimeUtilities.INSTANCE.TIME_FORMATTER_LOCAL.format(new Date(selectedLog.endTime));
            String picInfo = // 
            "<b>Gps log:</b> " + GeopaparazziUtilities.escapeHTML(selectedLog.text) + "<br/>" + "<b>Start time:</b> " + startDateTimeString + // 
            "<br/>" + "<b>End time:</b> " + endDateTimeString + "<br/>";
            _infoArea.setText(picInfo);
            loadGpsLogChart(selectedLog, currentSelectedProject.databaseFile);
            Envelope env = null;
            for (GpsPoint gpsPoint : selectedLog.points) {
                if (env == null) {
                    env = new Envelope(new Coordinate(gpsPoint.lon, gpsPoint.lat));
                } else {
                    env.expandToInclude(gpsPoint.lon, gpsPoint.lat);
                }
            }
            env.expandBy(0.01);
            Sector sector = NwwUtilities.envelope2Sector(new ReferencedEnvelope(env, NwwUtilities.GPS_CRS));
            if (wwjPanel != null)
                wwjPanel.goTo(sector, false);
        } catch (Exception e) {
            Logger.INSTANCE.insertError("", "error", e);
            setNoProjectLabel();
        }
    }

    private void setNoProjectLabel() {
        _infoArea.setText("<h1>No project selected</h1>");
    // Label noModuleLabel = new Label(projectViewComposite, SWT.NONE);
    // noModuleLabel.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
    // noModuleLabel.setData(RWT.MARKUP_ENABLED, Boolean.TRUE);
    // noModuleLabel.setText("<span style='font:bold 26px Arial;'>" + NO_MODULE_SELECTED +
    // "</span>");
    // return noModuleLabel;
    }

    private void loadGpsLogChart(GpsLog log, File dbFile) throws Exception {
        try (SqliteDb db = new SqliteDb()) {
            db.open(dbFile.getAbsolutePath());
            db.execOnConnection(connection -> {
                log.points.clear();
                DaoGpsLog.collectDataForLog(connection, log);
                String logName = log.text;
                int size = log.points.size();
                List<Coordinate> coords = new ArrayList<>();
                double runningDistance = 0;
                for (int i = 0; i < size - 1; i++) {
                    GpsPoint p1 = log.points.get(i);
                    GpsPoint p2 = log.points.get(i + 1);
                    double lon1 = p1.lon;
                    double lat1 = p1.lat;
                    double altim1 = p1.altim;
                    double lon2 = p2.lon;
                    double lat2 = p2.lat;
                    double altim2 = p2.altim;
                    double distance = NwwUtilities.computeDistance(lat1, lon1, lat2, lon2);
                    runningDistance += distance;
                    if (i == 0) {
                        coords.add(new Coordinate(0.0, altim1));
                    }
                    coords.add(new Coordinate(runningDistance, altim2));
                }
                LineString lineString = GeometryUtilities.gf().createLineString(coords.toArray(new Coordinate[0]));
                int lookAhead = 20;
                if (lookAhead > coords.size()) {
                    lookAhead = 3;
                }
                double slide = 1;
                FeatureSlidingAverage fsaElev = new FeatureSlidingAverage(lineString);
                List<Coordinate> smoothedElev = fsaElev.smooth(lookAhead, false, slide);
                if (smoothedElev == null) {
                    smoothedElev = coords;
                }
                double[] xProfile = new double[smoothedElev.size()];
                double[] yProfile = new double[smoothedElev.size()];
                for (int i = 0; i < xProfile.length; i++) {
                    Coordinate c = smoothedElev.get(i);
                    xProfile[i] = c.x;
                    yProfile[i] = c.y;
                }
                Scatter scatterProfile = new Scatter("Profile " + logName);
                scatterProfile.addSeries("profile", xProfile, yProfile);
                scatterProfile.setShowLines(Arrays.asList(true));
                String colorQuery = // 
                "select " + GpsLogsPropertiesTableFields.COLUMN_PROPERTIES_COLOR.getFieldName() + " from " + TABLE_GPSLOG_PROPERTIES + // 
                " where " + GpsLogsPropertiesTableFields.COLUMN_LOGID.getFieldName() + " = " + log.id;
                String colorStr = RED_HEXA;
                try (IHMStatement newStatement = connection.createStatement();
                    IHMResultSet result = newStatement.executeQuery(colorQuery)) {
                    newStatement.setQueryTimeout(30);
                    if (result.next()) {
                        colorStr = result.getString(1);
                        if (colorStr.equalsIgnoreCase("red")) {
                            colorStr = RED_HEXA;
                        }
                    }
                    if (colorStr == null || colorStr.length() == 0) {
                        colorStr = RED_HEXA;
                    }
                }
                Color color = Color.RED;
                try {
                    color = Color.decode(colorStr);
                } catch (Exception e) {
                // ignore Logger.INSTANCE.insertError("","Could not convert color: " + colorStr,
                // e);
                }
                scatterProfile.setColors(new Color[] { color });
                scatterProfile.setXLabel("progressive distance [m]");
                scatterProfile.setYLabel("elevation [m]");
                JFreeChart chart = scatterProfile.getChart();
                ChartPanel chartPanel = new ChartPanel(chart, true);
                _chartHolder.add(chartPanel, BorderLayout.CENTER);
                return null;
            });
        }
    }

    /**
     * Extract data from the db and add them to the map view.
     *
     * @param projectTemplate
     * @return
     * @throws Exception
     */
    public void loadProjectData(ProjectInfo currentSelectedProject, boolean zoomTo) throws Exception {
        if (geopapDataLayer != null)
            geopapDataLayer.removeAllRenderables();
        Envelope bounds = new Envelope();
        File dbFile = currentSelectedProject.databaseFile;
        try (Connection connection = DriverManager.getConnection("jdbc:sqlite:" + dbFile.getAbsolutePath())) {
            // NOTES
            List<String[]> noteDataList = GeopaparazziUtilities.getNotesText(connection);
            StringBuilder sb = new StringBuilder();
            sb.append("\n\n// GP NOTES\n");
            int index = 0;
            PointPlacemarkAttributes notesAttributes = new PointPlacemarkAttributes();
            // notesAttributes.setLabelMaterial(mFillMaterial);
            // notesAttributes.setLineMaterial(mFillMaterial);
            // notesAttributes.setUsePointAsDefaultImage(true);
            notesAttributes.setImage(ImageCache.getInstance().getBufferedImage(ImageCache.NOTE));
            notesAttributes.setLabelMaterial(new Material(Color.BLACK));
            // notesAttributes.setScale(mMarkerSize);
            for (String[] noteData : noteDataList) {
                // [lon, lat, altim, dateTimeString, text, descr]
                double lon = Double.parseDouble(noteData[0]);
                double lat = Double.parseDouble(noteData[1]);
                String altim = noteData[2];
                String date = noteData[3];
                String text = noteData[4];
                String descr = noteData[5];
                PointPlacemark marker = new PointPlacemark(Position.fromDegrees(lat, lon, 0));
                marker.setAlreplacedudeMode(WorldWind.CLAMP_TO_GROUND);
                marker.setLabelText(text + " (" + date + ")");
                marker.setAttributes(notesAttributes);
                if (geopapDataLayer != null)
                    geopapDataLayer.addRenderable(marker);
                bounds.expandToInclude(lon, lat);
            }
            /*
             * IMAGES
             */
            PointPlacemarkAttributes imageAttributes = new PointPlacemarkAttributes();
            imageAttributes.setImage(ImageCache.getInstance().getBufferedImage(ImageCache.DBIMAGE));
            imageAttributes.setLabelMaterial(new Material(Color.GRAY));
            for (org.hortonmachine.gears.io.geopaparazzi.geopap4.Image image : currentSelectedProject.images) {
                double lon = image.getLon();
                double lat = image.getLat();
                PointPlacemark marker = new PointPlacemark(Position.fromDegrees(lat, lon, 0));
                marker.setAlreplacedudeMode(WorldWind.CLAMP_TO_GROUND);
                marker.setLabelText(image.getName());
                marker.setAttributes(imageAttributes);
                if (geopapDataLayer != null)
                    geopapDataLayer.addRenderable(marker);
                bounds.expandToInclude(lon, lat);
            }
            try (Statement statement = connection.createStatement()) {
                // set timeout to 30 sec.
                statement.setQueryTimeout(30);
                String sql = // 
                "select " + GpsLogsTableFields.COLUMN_ID.getFieldName() + // 
                "," + GpsLogsTableFields.COLUMN_LOG_STARTTS.getFieldName() + // 
                "," + GpsLogsTableFields.COLUMN_LOG_ENDTS.getFieldName() + // 
                "," + // 
                GpsLogsTableFields.COLUMN_LOG_TEXT.getFieldName() + " from " + // 
                TABLE_GPSLOGS;
                boolean useGpsElev = _useGpsElevationsCheckbox.isSelected();
                int alreplacedudeMode = WorldWind.CLAMP_TO_GROUND;
                if (useGpsElev) {
                    alreplacedudeMode = WorldWind.ABSOLUTE;
                }
                // first get the logs
                ResultSet rs = statement.executeQuery(sql);
                while (rs.next()) {
                    long id = rs.getLong(1);
                    long startDateTime = rs.getLong(2);
                    String startDateTimeString = ETimeUtilities.INSTANCE.TIME_FORMATTER_LOCAL.format(new Date(startDateTime));
                    long endDateTime = rs.getLong(3);
                    String endDateTimeString = ETimeUtilities.INSTANCE.TIME_FORMATTER_LOCAL.format(new Date(endDateTime));
                    String text = rs.getString(4);
                    // points
                    String query = // 
                    "select " + GpsLogsDataTableFields.COLUMN_DATA_LAT.getFieldName() + "," + GpsLogsDataTableFields.COLUMN_DATA_LON.getFieldName() + "," + GpsLogsDataTableFields.COLUMN_DATA_ALTIM.getFieldName() + "," + // 
                    GpsLogsDataTableFields.COLUMN_DATA_TS.getFieldName() + " from " + TABLE_GPSLOG_DATA + // 
                    " where " + GpsLogsDataTableFields.COLUMN_LOGID.getFieldName() + " = " + id + " order by " + GpsLogsDataTableFields.COLUMN_DATA_TS.getFieldName();
                    List<Position> verticesList = new ArrayList<>();
                    try (Statement newStatement = connection.createStatement()) {
                        newStatement.setQueryTimeout(30);
                        ResultSet result = newStatement.executeQuery(query);
                        while (result.next()) {
                            double lat = result.getDouble(1);
                            double lon = result.getDouble(2);
                            double elev = 0.0;
                            if (useGpsElev)
                                elev = result.getDouble(3);
                            Position pos = Position.fromDegrees(lat, lon, elev);
                            verticesList.add(pos);
                            bounds.expandToInclude(lon, lat);
                        }
                    }
                    // color
                    String colorQuery = // 
                    "select " + GpsLogsPropertiesTableFields.COLUMN_PROPERTIES_COLOR.getFieldName() + "," + GpsLogsPropertiesTableFields.COLUMN_PROPERTIES_WIDTH.getFieldName() + " from " + TABLE_GPSLOG_PROPERTIES + // 
                    " where " + GpsLogsPropertiesTableFields.COLUMN_LOGID.getFieldName() + " = " + id;
                    String colorStr = RED_HEXA;
                    int lineWidth = 3;
                    try (Statement newStatement = connection.createStatement()) {
                        newStatement.setQueryTimeout(30);
                        ResultSet result = newStatement.executeQuery(colorQuery);
                        if (result.next()) {
                            colorStr = result.getString(1);
                            lineWidth = result.getInt(2);
                            if (colorStr.equalsIgnoreCase("red")) {
                                colorStr = RED_HEXA;
                            }
                        }
                        if (colorStr == null || colorStr.length() == 0) {
                            colorStr = RED_HEXA;
                        }
                    }
                    Color color = Color.RED;
                    try {
                        color = Color.decode(colorStr);
                    } catch (Exception e) {
                    // ignore Logger.INSTANCE.insertError("","Could not convert color: " +
                    // colorStr, e);
                    }
                    BasicShapeAttributes lineAttributes = new BasicShapeAttributes();
                    lineAttributes.setOutlineMaterial(new Material(color));
                    lineAttributes.setOutlineWidth(lineWidth);
                    Path path = new Path(verticesList);
                    path.setAlreplacedudeMode(alreplacedudeMode);
                    path.setFollowTerrain(true);
                    path.setAttributes(lineAttributes);
                    if (geopapDataLayer != null)
                        geopapDataLayer.addRenderable(path);
                }
            }
        }
        if (zoomTo) {
            bounds.expandBy(0.001);
            Sector sector = NwwUtilities.envelope2Sector(new ReferencedEnvelope(bounds, NwwUtilities.GPS_CRS));
            if (wwjPanel != null)
                wwjPanel.goTo(sector, false);
        }
        currentLoadedProject = currentSelectedProject;
    }

    protected void editProjectData(ProjectInfo project) throws Exception {
        LinkedHashMap<String, String> metadataMap = new LinkedHashMap<>();
        try (SqliteDb db = new SqliteDb()) {
            db.open(currentSelectedProject.databaseFile.getAbsolutePath());
            db.execOnConnection(connection -> {
                String sql = // 
                "select " + MetadataTableFields.COLUMN_KEY.getFieldName() + ", " + MetadataTableFields.COLUMN_VALUE.getFieldName() + " from " + TABLE_METADATA;
                try (IHMStatement statement = connection.createStatement();
                    IHMResultSet rs = statement.executeQuery(sql)) {
                    // set timeout to 30 sec.
                    statement.setQueryTimeout(30);
                    while (rs.next()) {
                        String key = rs.getString(MetadataTableFields.COLUMN_KEY.getFieldName());
                        String value = rs.getString(MetadataTableFields.COLUMN_VALUE.getFieldName());
                        if (!key.endsWith("ts")) {
                            // timestamps can't be changed
                            metadataMap.put(key, value);
                        }
                    }
                }
                String replacedle = "Edit Project Info";
                String[] labels = metadataMap.keySet().toArray(new String[0]);
                String[] defaultValues = metadataMap.values().toArray(new String[0]);
                String[] result = GuiUtilities.showMultiInputDialog(this, replacedle, labels, defaultValues, null);
                if (result != null) {
                    try (IHMStatement statement = connection.createStatement()) {
                        // set timeout to 30 sec.
                        statement.setQueryTimeout(30);
                        for (int i = 0; i < labels.length; i++) {
                            String key = labels[i];
                            String textData = result[i];
                            if (textData == null) {
                                textData = "";
                            }
                            textData = ASpatialDb.escapeSql(textData);
                            String query = "update " + TABLE_METADATA + " set value='" + textData + "'  where key='" + key + "';";
                            statement.executeUpdate(query);
                        }
                    }
                    String projectInfo = GeopaparazziUtilities.getProjectInfo(connection, true);
                    currentSelectedProject.metadata = projectInfo;
                    selectProjectInfo(currentSelectedProject);
                }
                return null;
            });
        }
    }

    protected abstract List<Action> makeGpsLogActions(final GpsLog selectedLog);

    protected abstract List<Action> makeNotesActions(final Note selectedNote);

    protected abstract List<Action> makeProjectAction(final ProjectInfo project);

    protected abstract List<Action> makeImageAction(final Image selectedImage);
}

12 View Complete Implementation : OmsGeopaparazzi4Converter.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
public static SimpleFeatureCollection media2FeatureCollection(IHMConnection connection, File mediaFolderFile, IHMProgressMonitor pm) throws Exception, IOException, FileNotFoundException {
    DefaultFeatureCollection newCollection = new DefaultFeatureCollection();
    try {
        GeometryFactory gf = GeometryUtilities.gf();
        /*
             * create the points shapefile
             */
        newCollection = new DefaultFeatureCollection();
        SimpleFeatureTypeBuilder b = new SimpleFeatureTypeBuilder();
        b.setName("geopaparazzimediapoints");
        b.setCRS(DefaultGeographicCRS.WGS84);
        b.add("the_geom", Point.clreplaced);
        String altimFN = ImageTableFields.COLUMN_ALTIM.getFieldName();
        String tsFN = ImageTableFields.COLUMN_TS.getFieldName();
        String azimFN = ImageTableFields.COLUMN_AZIM.getFieldName();
        String imageNameFN = ImageTableFields.COLUMN_TEXT.getFieldName();
        b.add(altimFN, String.clreplaced);
        b.add(tsFN, String.clreplaced);
        b.add(azimFN, Double.clreplaced);
        b.add(imageNameFN, String.clreplaced);
        SimpleFeatureType featureType = b.buildFeatureType();
        List<Image> imagesList = DaoImages.getImagesList(connection);
        pm.beginTask("Importing media...", imagesList.size());
        for (Image image : imagesList) {
            File newImageFile = new File(mediaFolderFile, image.getName());
            byte[] imageData = DaoImages.getImageData(connection, image.getImageDataId());
            try (OutputStream outStream = new FileOutputStream(newImageFile)) {
                outStream.write(imageData);
            }
            Point point = gf.createPoint(new Coordinate(image.getLon(), image.getLat()));
            long ts = image.getTs();
            String dateTimeString = ETimeUtilities.INSTANCE.TIME_FORMATTER_LOCAL.format(new Date(ts));
            String imageRelativePath = mediaFolderFile.getName() + "/" + image.getName();
            Object[] values = new Object[] { point, image.getAltim(), dateTimeString, image.getAzim(), imageRelativePath };
            SimpleFeatureBuilder builder = new SimpleFeatureBuilder(featureType);
            builder.addAll(values);
            SimpleFeature feature = builder.buildFeature(null);
            newCollection.add(feature);
            pm.worked(1);
        }
    } finally {
        pm.done();
    }
    return newCollection;
}

12 View Complete Implementation : OmsGeopaparazzi4Converter.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
/**
 * Convert the logs to a featurecollection.
 *
 * @param pm the monitor.
 * @param logsList the list of logs as gathered from {@link #getGpsLogsList(IHMConnection)}.
 * @return the extracted collection.
 * @throws Exception
 */
public static DefaultFeatureCollection getLogLinesFeatureCollection(IHMProgressMonitor pm, List<GpsLog> logsList) {
    GeometryFactory gf = GeometryUtilities.gf();
    SimpleFeatureType featureType = GeopaparazziUtilities.getGpsLogLinesFeatureType();
    pm.beginTask("Import gps to lines...", logsList.size());
    DefaultFeatureCollection newCollection = new DefaultFeatureCollection();
    for (GpsLog log : logsList) {
        List<GpsPoint> points = log.points;
        List<Coordinate> coordList = new ArrayList<>();
        String startDate = ETimeUtilities.INSTANCE.TIME_FORMATTER_LOCAL.format(new Date(log.startTime));
        String endDate = ETimeUtilities.INSTANCE.TIME_FORMATTER_LOCAL.format(new Date(log.endTime));
        for (GpsPoint gpsPoint : points) {
            Coordinate c = new Coordinate(gpsPoint.lon, gpsPoint.lat);
            coordList.add(c);
        }
        Coordinate[] coordArray = coordList.toArray(new Coordinate[coordList.size()]);
        if (coordArray.length < 2) {
            continue;
        }
        LineString lineString = gf.createLineString(coordArray);
        MultiLineString multiLineString = gf.createMultiLineString(new LineString[] { lineString });
        SimpleFeatureBuilder builder = new SimpleFeatureBuilder(featureType);
        Object[] values = new Object[] { multiLineString, startDate, endDate, log.text };
        builder.addAll(values);
        SimpleFeature feature = builder.buildFeature(null);
        newCollection.add(feature);
        pm.worked(1);
    }
    pm.done();
    return newCollection;
}

12 View Complete Implementation : LasUtils.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
/**
 * Smooths a set of las points through the IDW method.
 *
 * <p>Note that the values in the original data are changed.
 *
 * @param lasPoints the list of points to smooth.
 * @param useGround if <code>true</code>, the ground elev is smoothed instead of the z.
 * @param idwBuffer the buffer around the points to consider for smoothing.
 * @param pm the monitor.
 */
@SuppressWarnings("unchecked")
public static void smoothIDW(List<LasRecord> lasPoints, boolean useGround, double idwBuffer, IHMProgressMonitor pm) {
    List<Coordinate> coordinatesList = new ArrayList<Coordinate>();
    if (useGround) {
        for (LasRecord dot : lasPoints) {
            Coordinate c = new Coordinate(dot.x, dot.y, dot.groundElevation);
            coordinatesList.add(c);
        }
    } else {
        for (LasRecord dot : lasPoints) {
            Coordinate c = new Coordinate(dot.x, dot.y, dot.z);
            coordinatesList.add(c);
        }
    }
    // make triangles tree
    STRtree pointsTree = new STRtree(coordinatesList.size());
    pm.beginTask("Make points tree...", coordinatesList.size());
    for (Coordinate coord : coordinatesList) {
        pointsTree.insert(new Envelope(coord), coord);
        pm.worked(1);
    }
    pm.done();
    pm.beginTask("Interpolate...", coordinatesList.size());
    for (int i = 0; i < coordinatesList.size(); i++) {
        Coordinate coord = coordinatesList.get(i);
        Envelope env = new Envelope(coord);
        env.expandBy(idwBuffer);
        List<Coordinate> nearPoints = pointsTree.query(env);
        double avg = 0;
        for (Coordinate coordinate : nearPoints) {
            avg += coordinate.z;
        }
        avg = avg / nearPoints.size();
        LasRecord lasRecord = lasPoints.get(i);
        if (useGround) {
            lasRecord.groundElevation = avg;
        } else {
            lasRecord.z = avg;
        }
        pm.worked(1);
    }
    pm.done();
}

11 View Complete Implementation : OmsGrassLegacyReader.java
Copyright GNU General Public License v3.0
Author : TheHortonMachine
/**
 * Get a single value in a position of the raster.
 *
 * <p>This opens and closes the raster every time it is called. Bad performance on many calls.
 *
 * @param window the grid on which to base on (if <code>null</code>, the active region is picked).
 * @param coordinate the coordinate in which the value is read.
 * @param filePath the path to the map.
 * @param pm the progress monitor or null.
 * @return the value read in the given coordinate.
 * @throws Exception
 */
public static double getValueAt(Window window, Coordinate coordinate, String filePath, IHMProgressMonitor pm) throws Exception {
    JGrreplacedMapEnvironment mapEnvironment = new JGrreplacedMapEnvironment(new File(filePath));
    if (window == null) {
        JGrreplacedRegion jgr = mapEnvironment.getActiveRegion();
        window = new Window(jgr.getWest(), jgr.getEast(), jgr.getSouth(), jgr.getNorth(), jgr.getWEResolution(), jgr.getNSResolution());
    }
    Window rectangleAroundPoint = GrreplacedLegacyUtilities.getRectangleAroundPoint(window, coordinate.x, coordinate.y);
    OmsGrreplacedLegacyReader reader = new OmsGrreplacedLegacyReader();
    reader.file = filePath;
    reader.inWindow = rectangleAroundPoint;
    if (pm != null)
        reader.pm = pm;
    reader.readCoverage();
    double[][] data = reader.geodata;
    if (data.length != 1 || data[0].length != 1) {
        throw new IllegalAccessException("Wrong region extracted for picking a single point.");
    }
    return data[0][0];
}