view gnv-artifacts/src/main/java/de/intevation/gnv/utils/WKTUtils.java @ 522:c896282c2601

Issue 156 solved. Added width, height and points as parameter to svg and pdf output mode. Width and height have an effact on the width and height of the export, points is a boolean property which enables/disables the drawing of data points. gnv-artifacts/trunk@616 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Ingo Weinzierl <ingo.weinzierl@intevation.de>
date Mon, 25 Jan 2010 09:18:31 +0000
parents 4e347624ee7c
children 0563389138bb
line wrap: on
line source
package de.intevation.gnv.utils;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;

import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader;

import de.intevation.gnv.artifacts.ressource.RessourceFactory;

import de.intevation.gnv.geobackend.base.Result;

import de.intevation.gnv.geobackend.base.query.QueryExecutor;
import de.intevation.gnv.geobackend.base.query.QueryExecutorFactory;

import de.intevation.gnv.geobackend.base.query.exception.QueryException;

import de.intevation.gnv.math.LinearFunction;

import java.text.MessageFormat;
import java.text.NumberFormat;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;

import org.apache.commons.math.FunctionEvaluationException;

import org.apache.commons.math.optimization.OptimizationException;

import org.apache.commons.math.optimization.fitting.CurveFitter;

import org.apache.commons.math.optimization.general.GaussNewtonOptimizer;

import org.apache.log4j.Logger;

public abstract class WKTUtils {

    private static Logger log = Logger.getLogger(WKTUtils.class);

    public static final double NAUTICAL_MILE = 1852.216d;
    public static final double KILOMETER     = 1000d;

    public static final String I_NAME = "MEDIAN.MESHPOINT.IPOSITION";
    public static final String J_NAME = "MEDIAN.MESHPOINT.JPOSITION";

    public static final String TRUE_EXPRESSION = "FEATUREID=FEATUREID";

    public static final String[] COORDINATE_OUT_FORMAT = {
        "coordinate.template.northeast",
        "coordinate.template.southeast",
        "coordinate.template.northwest",
        "coordinate.template.southwest"
    };

    public static final String DEFAULT_COORDINATE_TEMPLATE =
        "{0}\u00b0N {1}'' {2}\u00b0E {3}''";

    public static boolean different(Result a, Result b, int [] indices) {
        for (int i = 0; i < indices.length; ++i) {
            String oa = a.getString(indices[i]);
            String ob = b.getString(indices[i]);

            if (oa == null && ob == null)  {
                continue;
            }

            if (oa == null || ob == null) {
                return true;
            }

            if (!oa.equals(ob)) {
                return true;
            }
        }
        return false;
    }

    public static Coordinate toCoordinate(String shape) {
        try {
            return shape != null
                ? ((Point)(new WKTReader().read(shape))).getCoordinate()
                : null;
        }
        catch (ParseException pe) {
            log.error(pe);
        }
		catch (ClassCastException cce) {
			log.error("cannot read WKT point", cce);
		}
        return null;
    }

    public static Polygon toPolygon(String shape) {
        try {
            return (Polygon)new WKTReader().read(shape);
        }
        catch (ParseException pe) {
            log.error(pe);
        }
		catch (ClassCastException cce) {
			log.error("cannot read WKT polygon", cce);
		}
        return null;
    }

    public static final double toKM(double distance) {
        return (distance * NAUTICAL_MILE) / KILOMETER;
    }


    public static String toWKT(Coordinate coordinate) {
        StringBuilder sb = new StringBuilder("POINT(");
        sb.append(coordinate.x)
          .append(' ')
          .append(coordinate.y)
          .append(')');
        return sb.toString();
    }

    public static final String indexBox(
        java.awt.Point a, 
        java.awt.Point b,
        String         iName,
        String         jName
    ) {
        int minI = Math.min(a.x, b.x) - 1;
        int maxI = Math.max(a.x, b.x) + 1;
        int minJ = Math.min(a.y, b.y) - 1;
        int maxJ = Math.max(a.y, b.y) + 1;
        StringBuilder sb = new StringBuilder("(")
                          .append(iName).append(" >= ").append(minI)
          .append(" AND ").append(iName).append(" <= ").append(maxI)
          .append(" AND ").append(jName).append(" >= ").append(minJ)
          .append(" AND ").append(jName).append(" <= ").append(maxJ)
          .append(')');
        return sb.toString();
    }

    public static final String diagonalBox(List<java.awt.Point> points) {

        if (points.get(0) != null && points.get(2) != null) {
            return indexBox(
                points.get(0), points.get(2),
                I_NAME,
                J_NAME);
        }

        if (points.get(1) != null && points.get(3) != null) {
            return indexBox(
                points.get(1), points.get(3),
                I_NAME,
                J_NAME);
        }

        return null;
    }

    public static String worldEnvelopeCoordinatesToIndex(
         Coordinate []       coords,
         String              meshid,
         String              ijkQueryID
    )
    throws QueryException
    {
        List<java.awt.Point> points =
            new ArrayList<java.awt.Point>(coords.length);

        ArrayList<Object []> missingPoints =
            new ArrayList<Object []>();

        createIJKPoints(coords, meshid, ijkQueryID, points, missingPoints);
        
        String additionWhere = null;

        if (missingPoints.size() == coords.length) {
            log.debug("cannot create index buffer");
        }
        else {
            additionWhere = diagonalBox(points);

            if (additionWhere == null) {
                // 3 Points are missing or are on one side of the envelope
                boolean remainsMissingPoints = calculateIJ4MissingPoints(
                    coords, points, missingPoints);

                if (!remainsMissingPoints) {
                    additionWhere = diagonalBox(points);
                }
            }
        }

        return additionWhere != null
            ? additionWhere
            : TRUE_EXPRESSION;
    }

    public static String worldCoordinatesToIndex(
		Coordinate []       coords,
        Collection<Result>  result,
		String              meshid,
        String              ijkQueryID
    )
	throws QueryException
    {
        List<java.awt.Point> points = new ArrayList<java.awt.Point>(coords.length);

        ArrayList<Object []> missingPoints = new ArrayList<Object []>();

        createIJKPoints(coords, meshid, ijkQueryID, points, missingPoints);
        
        String additionWhere = TRUE_EXPRESSION;

        if (missingPoints.size() == coords.length) {
            log.debug("cannot create index buffer");
        }
        else { // generate index filter
            boolean remainsMissingPoints = calculateIJ4MissingPoints(
                coords, points, missingPoints);

            if (!remainsMissingPoints) {
                // TODO: Make Tablenames and Columns Configurable
                IndexBuffer ib = new IndexBuffer(
                    points, 
                    I_NAME, 
                    J_NAME );
                additionWhere = ib.toWhereClause();
                log.debug("Additional Where Clause = "+additionWhere);
            }
        } // if generate index filter

        return additionWhere;
    }


    /**
     * @param coords
     * @param points
     * @param missingPoints
     * @return
     */
    private static boolean calculateIJ4MissingPoints(
        Coordinate []        coords,
        List<java.awt.Point> points,
        ArrayList<Object[]>  missingPoints
    ) {
        boolean remainsMissingPoints = !missingPoints.isEmpty();

        if (remainsMissingPoints) {
            // try to guess the missing (i, j)
            CurveFitter iFitter = new CurveFitter(new GaussNewtonOptimizer(true));
            CurveFitter jFitter = new CurveFitter(new GaussNewtonOptimizer(true));

            for (int i = 0, N = points.size(); i < N; ++i) {
                java.awt.Point p = (java.awt.Point)points.get(i);
                if (p != null) {
                    Coordinate coord = coords[i];
                    iFitter.addObservedPoint(coord.x, p.x);
                    jFitter.addObservedPoint(coord.y, p.y);
                }
            }
            try {
                // XXX: Assumption: (i, j) are created by componentwise linear function.
                // This is surely not correct because (x, y) are in a ellipsoid projection.
                // TODO: use ellipsoid functions and fit with Levenberg Marquardt.
                double [] iParams = iFitter.fit(
                    LinearFunction.INSTANCE, new double [] { 1d, 1d });

                double [] jParams = jFitter.fit(
                    LinearFunction.INSTANCE, new double [] { 1d, 1d });

                for (int i = missingPoints.size()-1; i >= 0; --i) {
                    Object [] a = (Object [])missingPoints.get(i);
                    Coordinate coord = (Coordinate)a[1];
                    int pi = (int)Math.round(iParams[0]*coord.x + iParams[1]);
                    int pj = (int)Math.round(jParams[0]*coord.y + jParams[1]);
                    points.set(
                        ((Integer)a[0]).intValue(),
                        new java.awt.Point(pi, pj));
                }

                remainsMissingPoints = false; // we filled the gaps
            }
            catch (FunctionEvaluationException fee) {
                log.error(fee);
            }
            catch (OptimizationException oe) {
                log.error(oe);
            }
        }
        return remainsMissingPoints;
    }


    /**
     * @param coords
     * @param meshid
     * @param ijkQueryID
     * @param points
     * @param missingPoints
     * @throws QueryException
     */
    private static void createIJKPoints(
        Coordinate[]         coords,
        String               meshid,
        String               ijkQueryID,
        List<java.awt.Point> points,
        ArrayList<Object []> missingPoints
    )
    throws QueryException 
    {
        boolean debug = log.isDebugEnabled();

        QueryExecutor queryExecutor = QueryExecutorFactory
            .getInstance()
            .getQueryExecutor();
        
        for (int i = 0; i < coords.length; i++) {

            String wkt = toWKT(coords[i]);

            Collection<Result> result = queryExecutor.executeQuery(
                ijkQueryID,
                new String [] {meshid, wkt});

            if (!result.isEmpty()) {
                Result resultValue = result.iterator().next();
                int iPos = resultValue.getInteger(1);
                int jPos = resultValue.getInteger(0);
                if (debug) {
                    log.debug("Found Pos "+iPos+"/"+jPos +" for "+wkt);
                }
                points.add(i, new java.awt.Point(iPos,jPos));
            }
            else {
                if (debug) {
                    log.debug("No i/j Pos found for "+wkt);
                }
                missingPoints.add(new Object [] { Integer.valueOf(i), coords[i] });
                points.add(i, null);
                // Special Case no i,j found for Coordinate
            }
        }
    }

	public static Coordinate [] toCoordinates(String wkt) {
		try {
			LineString ls = (LineString)new WKTReader().read(wkt);
			return ls.getCoordinates();
		}
		catch (ParseException pe) {
			log.error("cannot read WKT line string", pe);
		}
		catch (ClassCastException cce) {
			log.error("cannot read WKT line string", cce);
		}
		return null;
	}

    public static String toText(String wkt) {
        return toText(Locale.getDefault(), wkt);
    }

    public static String toText(Locale locale, String wkt) {
        String formattedCoordinate = null;
        try {
            Point p = (Point)new WKTReader().read(wkt);
            double lat = p.getY();
            double lon =p.getX();

            int choice = 0;

            if (lat <0 ) {
                choice += 1;
                lat=-lat;
            }

            if (lon <0 ) {
                choice += 2;
                lon=-lon;
            }

            RessourceFactory factory = RessourceFactory.getInstance();
            String template = factory.getRessource(
                locale,
                COORDINATE_OUT_FORMAT[choice],
                DEFAULT_COORDINATE_TEMPLATE
            );

            NumberFormat minFormatter = NumberFormat.getInstance(locale);
            minFormatter.setMaximumFractionDigits(3);
            minFormatter.setMinimumFractionDigits(3);

            String minLat = minFormatter.format(60.*(lat-((int)lat)));
            String minLon = minFormatter.format(60.*(lon-((int)lon)));

            NumberFormat degFormatter = NumberFormat.getInstance(locale);
            degFormatter.setMinimumIntegerDigits(2);

            String formLat = degFormatter.format((int)lat);
            String formLon = degFormatter.format((int)lon);

            MessageFormat formatter = new MessageFormat(template);

            Object[] args = {
                formLat, minLat,
                formLon, minLon
            };

            return formatter.format(args);

        }
        catch (ParseException e) {
            log.warn(e,e);
        }

        return null;
    }
}

http://dive4elements.wald.intevation.org