org.kalypso.kalypsosimulationmodel.core.terrainmodel.ASCTerrainElevationModel.java Source code

Java tutorial

Introduction

Here is the source code for org.kalypso.kalypsosimulationmodel.core.terrainmodel.ASCTerrainElevationModel.java

Source

/*----------------    FILE HEADER KALYPSO ------------------------------------------
 *
 *  This file is part of kalypso.
 *  Copyright (C) 2004 by:
 *
 *  Technical University Hamburg-Harburg (TUHH)
 *  Institute of River and coastal engineering
 *  Denickestrae 22
 *  21073 Hamburg, Germany
 *  http://www.tuhh.de/wb
 *
 *  and
 *
 *  Bjoernsen Consulting Engineers (BCE)
 *  Maria Trost 3
 *  56070 Koblenz, Germany
 *  http://www.bjoernsen.de
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *  Contact:
 *
 *  E-Mail:
 *  belger@bjoernsen.de
 *  schlienger@bjoernsen.de
 *  v.doemming@tuhh.de
 *
 *  ---------------------------------------------------------------------------*/
package org.kalypso.kalypsosimulationmodel.core.terrainmodel;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;

import org.apache.commons.io.IOUtils;
import org.eclipse.core.runtime.IProgressMonitor;
import org.kalypso.contribs.eclipse.ui.progress.ProgressUtilities;
import org.kalypso.contribs.java.lang.NumberUtils;
import org.kalypsodeegree.KalypsoDeegreePlugin;
import org.kalypsodeegree.model.elevation.IElevationModel;
import org.kalypsodeegree.model.geometry.GM_Envelope;
import org.kalypsodeegree.model.geometry.GM_Point;
import org.kalypsodeegree.model.geometry.GM_Position;
import org.kalypsodeegree.model.geometry.GM_AbstractSurfacePatch;
import org.kalypsodeegree.model.geometry.GM_Triangle;
import org.kalypsodeegree.model.geometry.ISurfacePatchVisitable;
import org.kalypsodeegree.model.geometry.ISurfacePatchVisitor;
import org.kalypsodeegree_impl.model.geometry.GeometryFactory;

/**
 * An elevation provider base on ASC file
 *
 * @author Madanagopal
 * @author Patrice Congo
 *
 */
public class ASCTerrainElevationModel implements IElevationModel, ISurfacePatchVisitable<GM_AbstractSurfacePatch> {
    private static final int PROPORTIONAL_FACTOR = 160;

    private static final int MIN_FINE = 4;

    /**
     * The envelope of the region of interest
     */
    private double cellSize;

    private double elevations[][];

    private int N_COLS;

    private int N_ROWS;

    private double xllcorner;

    private double yllcorner;

    private double minElevation;

    private double maxElevation;

    /**
     * The maximal envelop for the elevation
     */
    private GM_Envelope maxEnvelope;

    // FIXME: this is nonsense, we should use the crs configured at our containing NativeTerrainModelWrapper and transform
    // our data into that crs
    private final String crs = KalypsoDeegreePlugin.getDefault().getCoordinateSystem();

    /**
     * Create an elevation provider based on the given asc file, in the specified region of interest. if the
     * regionInterest is null the file elevation information is computed and therefore available
     *
     * @param ascFile
     *          the asc file containing the native terrain model
     * @param regionOfInterest
     *          the {@link GM_Envelope} of region of interest
     * @throws IllegalArgumentException
     *           if asc file is null or is a directory or does not exist or is not accesible (cannot be read)
     *
     */
    public ASCTerrainElevationModel(final URL ascFileURL) throws IllegalArgumentException, IOException {
        parse(ascFileURL.openStream());
    }

    @Override
    public void dispose() {
    }

    private void parse(final InputStream inputStream) {
        BufferedReader br = null;
        try {
            br = new BufferedReader(new InputStreamReader(inputStream));
            final String[] data = new String[6];
            String line;
            // reading header data
            for (int i = 0; i < 6; i++) {
                line = br.readLine();
                final int index = line.indexOf(" "); //$NON-NLS-1$
                final String subString = line.substring(index);
                data[i] = subString.trim();
            }
            N_COLS = Integer.parseInt(data[0]);
            N_ROWS = Integer.parseInt(data[1]);
            xllcorner = NumberUtils.parseDouble(data[2]);
            yllcorner = NumberUtils.parseDouble(data[3]);
            cellSize = NumberUtils.parseDouble(data[4]);
            final double noDataValue = NumberUtils.parseDouble(data[5]);
            double currentValue;

            elevations = new double[N_ROWS][N_COLS];
            minElevation = Double.MAX_VALUE;
            maxElevation = -Double.MAX_VALUE;

            String[] strRow;
            for (int y = N_ROWS - 1; y >= 0; y--) {
                strRow = br.readLine().trim().split(" "); //$NON-NLS-1$
                for (int x = 0; x < N_COLS; x++) {
                    currentValue = NumberUtils.parseDouble(strRow[x]);
                    if (currentValue != noDataValue) {
                        elevations[y][x] = currentValue;

                        if (minElevation > currentValue) {
                            minElevation = currentValue;
                        }

                        if (maxElevation < currentValue) {
                            maxElevation = currentValue;
                        }
                    } else {
                        elevations[y][x] = Double.NaN;
                    }

                }
            }
            maxEnvelope = makeMaxEnvelope();
        } catch (final NumberFormatException e) {
            e.printStackTrace();
        } catch (final IOException e) {
            e.printStackTrace();
        } finally {
            IOUtils.closeQuietly(br);
        }
    }

    private final GM_Envelope makeMaxEnvelope() {
        final GM_Position posMin = GeometryFactory.createGM_Position(xllcorner, yllcorner);
        final GM_Position posMax = GeometryFactory.createGM_Position(xllcorner + cellSize * N_COLS,
                yllcorner + cellSize * N_ROWS);
        return GeometryFactory.createGM_Envelope(posMin, posMax, crs);
    }

    /**
     * @see org.kalypso.kalypsosimulationmodel.core.terrainmodel.IElevationProvider#getElevation(org.kalypsodeegree.model.geometry.GM_Point)
     */
    @Override
    public double getElevation(final GM_Point location) {
        final int col = (int) Math.floor((location.getX() - xllcorner) / cellSize);
        final int row = (int) Math.floor((location.getY() - yllcorner) / cellSize);
        if (col < N_COLS && row < N_ROWS && col >= 0 && row >= 0)
            return elevations[row][col];

        return Double.NaN;
    }

    /**
     * @see org.kalypsodeegree.model.geometry.ISurfacePatchVisitable#acceptSurfacePatches(org.kalypsodeegree.model.geometry.GM_Envelope,
     *      org.kalypsodeegree.model.geometry.ISurfacePatchVisitor, org.eclipse.core.runtime.IProgressMonitor)
     *
     * Extended for better performance. according to the zoom factor only each (n) cell of the grid will be visited,
     * after getting close enough will refine the representation of model.
     */
    @Override
    public void acceptSurfacePatches(final GM_Envelope envToVisit,
            final ISurfacePatchVisitor<GM_AbstractSurfacePatch> surfacePatchVisitor,
            final IProgressMonitor monitor) {
        // FIXME: painting a grid with the triangle stuff is NOT appropriate! -> makes never sense, because a grid cell has
        // only onse single value; so splitting up
        // into triangle parts according to color classes is slow and makes absolutely no sense!

        final int iProportional = (int) (Math.min(envToVisit.getHeight(), envToVisit.getWidth())
                / (cellSize * PROPORTIONAL_FACTOR));
        final int iShift = (Math.max(MIN_FINE, iProportional));
        double dShiftMonitor = iShift;
        boolean lBoolDoFine = false;
        if (iProportional < MIN_FINE / 2) {
            lBoolDoFine = true;
            dShiftMonitor = (double) MIN_FINE / (MIN_FINE + 1);
        }
        final GM_Envelope env = GMRectanglesClip.getIntersectionEnv(maxEnvelope, envToVisit);
        final double xmin = env.getMin().getX();
        final int col = (int) Math.floor((xmin - xllcorner) / cellSize);
        final double ymin = env.getMin().getY();
        int row = (int) Math.floor((ymin - yllcorner) / cellSize);
        if (row < 0)
            row = 0;

        final int totalWork = (int) (Math.floor(env.getWidth() / cellSize) / dShiftMonitor);
        if (col < N_COLS && row < N_ROWS && col >= 0 && row >= 0) {
            monitor.beginTask("", totalWork); //$NON-NLS-1$

            final int N_COL_ENV = (int) Math.floor(env.getWidth() / cellSize);
            final int N_ROW_ENV = (int) Math.floor(env.getHeight() / cellSize);
            // iteration for rough representation with adaptive walking through the grid. iShift variable defines the step size of walking
            for (int i = 0; i < N_ROW_ENV; i += iShift) {
                for (int j = 0; j < N_COL_ENV; j += iShift) {
                    final double x = xmin + j * cellSize;
                    final double xPlusCellSize = x + cellSize * iShift;
                    final double y = ymin + i * cellSize;
                    final double yPlusCellSize = y + cellSize * iShift;
                    final double z = elevations[row + i][col + j];

                    final GM_Position pos0 = GeometryFactory.createGM_Position(x, y, z);
                    final GM_Position pos1 = GeometryFactory.createGM_Position(xPlusCellSize, y, z);
                    final GM_Position pos2 = GeometryFactory.createGM_Position(xPlusCellSize, yPlusCellSize, z);
                    final GM_Position pos3 = GeometryFactory.createGM_Position(x, yPlusCellSize, z);

                    try {
                        final GM_AbstractSurfacePatch patch = GeometryFactory.createGM_PolygonPatch(
                                new GM_Position[] { pos0, pos1, pos2, pos3, pos0 }, null, crs);
                        surfacePatchVisitor.visit(patch);
                    } catch (final Throwable e) {
                        e.printStackTrace();
                    }
                }
                if (monitor.isCanceled()) {
                    monitor.worked(totalWork);
                    monitor.done();
                    return;
                }
                ProgressUtilities.worked(monitor, 1);
            }
            // the refinement iteration, visits all the points of the given grid in actual envelope.
            if (lBoolDoFine) {
                for (int i = 0; i < N_ROW_ENV; i++) {
                    for (int j = 0; j < N_COL_ENV; j++) {
                        final double x = xmin + j * cellSize;
                        final double xPlusCellSize = x + cellSize;
                        final double y = ymin + i * cellSize;
                        final double yPlusCellSize = y + cellSize;
                        final double z = elevations[row + i][col + j];

                        final GM_Position pos0 = GeometryFactory.createGM_Position(x, y, z);
                        final GM_Position pos1 = GeometryFactory.createGM_Position(xPlusCellSize, y, z);
                        final GM_Position pos2 = GeometryFactory.createGM_Position(xPlusCellSize, yPlusCellSize, z);
                        final GM_Position pos3 = GeometryFactory.createGM_Position(x, yPlusCellSize, z);

                        final GM_Triangle patch1 = GeometryFactory
                                .createGM_Triangle(new GM_Position[] { pos0, pos1, pos3 }, crs);
                        final GM_Triangle patch2 = GeometryFactory
                                .createGM_Triangle(new GM_Position[] { pos1, pos2, pos3 }, crs);

                        try {
                            surfacePatchVisitor.visit(patch1);
                            surfacePatchVisitor.visit(patch2);
                        } catch (final Throwable e) {
                            e.printStackTrace();
                        }
                    }
                    if (monitor.isCanceled()) {
                        monitor.worked(totalWork);
                        monitor.done();
                        return;
                    }
                    ProgressUtilities.worked(monitor, 1);
                }
            }
        }
        return;
    }

    @Override
    public GM_Envelope getBoundingBox() {
        return maxEnvelope;
    }

    public double getCellSize() {
        return cellSize;
    }

    @Override
    public double getMaxElevation() {
        return (maxElevation == -Double.MAX_VALUE) ? Double.NaN : maxElevation;
    }

    @Override
    public double getMinElevation() {
        return (minElevation == Double.MAX_VALUE) ? Double.NaN : minElevation;
    }
}