com.atolcd.pentaho.di.trans.steps.gisrelate.GisRelate.java Source code

Java tutorial

Introduction

Here is the source code for com.atolcd.pentaho.di.trans.steps.gisrelate.GisRelate.java

Source

package com.atolcd.pentaho.di.trans.steps.gisrelate;

/*
 * #%L
 * Pentaho Data Integrator GIS Plugin
 * %%
 * Copyright (C) 2015 Atol CD
 * %%
 * This program 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 3 of the
 * License, or (at your option) any later version.
 * 
 * This program 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 General Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * <http://www.gnu.org/licenses/lgpl-3.0.html>.
 * #L%
 */

import org.apache.commons.lang.ArrayUtils;
import org.pentaho.di.core.Const;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.core.row.RowDataUtil;
import org.pentaho.di.core.row.RowMetaInterface;
import org.pentaho.di.core.row.value.GeometryInterface;
import org.pentaho.di.trans.Trans;
import org.pentaho.di.trans.TransMeta;
import org.pentaho.di.trans.step.BaseStep;
import org.pentaho.di.trans.step.StepDataInterface;
import org.pentaho.di.trans.step.StepInterface;
import org.pentaho.di.trans.step.StepMeta;
import org.pentaho.di.trans.step.StepMetaInterface;

import com.atolcd.pentaho.di.core.row.value.ValueMetaGeometry;
import com.atolcd.pentaho.di.gis.utils.GeometryUtils;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;

public class GisRelate extends BaseStep implements StepInterface {

    private static GeometryFactory geometryFactory = new GeometryFactory();

    private GisRelateData data;
    private GisRelateMeta meta;

    private String operator;

    private Integer firstGeometryFieldIndex;
    private Integer secondGeometryFieldIndex;
    private Integer distanceFieldIndex;
    private Double distanceValue;

    private String returnType;
    private Integer outputFieldIndex;

    private boolean withDistance;
    private Class<?> resultType;
    private GeometryInterface firstGeometryInterface;
    private GeometryInterface secondGeometryInterface;

    private Object getRelateResult(Object[] row) throws KettleException {

        Geometry firstGeometry = ((GeometryInterface) firstGeometryInterface)
                .getGeometry(row[firstGeometryFieldIndex]);
        Geometry secondGeometry = ((GeometryInterface) secondGeometryInterface)
                .getGeometry(row[secondGeometryFieldIndex]);

        if (!GeometryUtils.isNullOrEmptyGeometry(firstGeometry)
                && !GeometryUtils.isNullOrEmptyGeometry(secondGeometry)) {

            Double distance = null;

            if (withDistance) {

                if (distanceFieldIndex != null) {

                    distance = getInputRowMeta().getNumber(row, distanceFieldIndex);

                    if (distance == null) {
                        throw new KettleException("Distance can not be null");
                    }

                } else {
                    distance = distanceValue;
                }

            }

            return process(operator, firstGeometry, secondGeometry, distance);

        }

        return null;

    }

    public GisRelate(StepMeta s, StepDataInterface stepDataInterface, int c, TransMeta t, Trans dis) {
        super(s, stepDataInterface, c, t, dis);
    }

    public boolean processRow(StepMetaInterface smi, StepDataInterface sdi) throws KettleException {
        meta = (GisRelateMeta) smi;
        data = (GisRelateData) sdi;

        Object result;

        Object[] r = getRow();

        if (r == null) {

            setOutputDone();
            return false;

        }

        if (first) {

            first = false;
            data.outputRowMeta = (RowMetaInterface) getInputRowMeta().clone();
            meta.getFields(data.outputRowMeta, getStepname(), null, null, this);

            operator = meta.getOperator();
            returnType = meta.getReturnType();

            // Rcupration des indexes des colonnes contenant les gomrtries
            // d'entre
            firstGeometryFieldIndex = getInputRowMeta().indexOfValue(meta.getFirstGeometryFieldName());
            secondGeometryFieldIndex = getInputRowMeta().indexOfValue(meta.getSecondGeometryFieldName());
            firstGeometryInterface = (GeometryInterface) getInputRowMeta().getValueMeta(firstGeometryFieldIndex);
            secondGeometryInterface = (GeometryInterface) getInputRowMeta().getValueMeta(secondGeometryFieldIndex);
            // Besoin de distance
            if (ArrayUtils.contains(meta.getWithDistanceOperators(), operator)) {

                withDistance = true;
                if (meta.isDynamicDistance()) {
                    distanceFieldIndex = getInputRowMeta().indexOfValue(meta.getDistanceFieldName());
                } else {

                    try {
                        distanceValue = Double.parseDouble(environmentSubstitute(meta.getDistanceValue()));
                    } catch (Exception e) {
                        throw new KettleException("Distance is not valid");
                    }
                }

            } else {
                withDistance = false;
            }

            // En fonction du type de rsultat
            if (ArrayUtils.contains(meta.getBoolResultOperators(), operator)) {
                resultType = Boolean.class;
            } else if (ArrayUtils.contains(meta.getNumericResultOperators(), operator)) {
                resultType = Double.class;
            }

            // Rcupration de l'index de la colonne contenant le rsultat
            outputFieldIndex = data.outputRowMeta.indexOfValue(meta.getOutputFieldName());

            logBasic("Initialized successfully");

        }

        Object[] outputRow = null;
        result = getRelateResult(r);

        if (resultType.equals(Boolean.class)) {

            if (returnType.equalsIgnoreCase("ALL")) {

                outputRow = RowDataUtil.resizeArray(r, r.length + 1);
                outputRow[outputFieldIndex] = (Boolean) result;
                putRow(data.outputRowMeta, outputRow);

            } else {

                if (String.valueOf((Boolean) result).equalsIgnoreCase(returnType)) {
                    putRow(data.outputRowMeta, r);
                }

            }

        } else if (resultType.equals(Double.class)) {

            outputRow = RowDataUtil.resizeArray(r, r.length + 1);
            outputRow[outputFieldIndex] = (Double) result;
            putRow(data.outputRowMeta, outputRow);

        }

        incrementLinesInput();

        if (checkFeedback(getLinesRead())) {
            logBasic("Linenr " + getLinesRead());
        }

        return true;
    }

    public boolean init(StepMetaInterface smi, StepDataInterface sdi) {
        meta = (GisRelateMeta) smi;
        data = (GisRelateData) sdi;
        return super.init(smi, sdi);
    }

    public void dispose(StepMetaInterface smi, StepDataInterface sdi) {
        meta = (GisRelateMeta) smi;
        data = (GisRelateData) sdi;

        super.dispose(smi, sdi);
    }

    public void run() {
        logBasic("Starting to run...");
        try {
            while (processRow(meta, data) && !isStopped())
                ;
        } catch (Exception e) {
            logError("Unexpected error : " + e.toString());
            logError(Const.getStackTracker(e));
            setErrors(1);
            stopAll();
        } finally {
            dispose(meta, data);
            logBasic("Finished, processing " + getLinesRead() + " rows");
            markStop();
        }
    }

    private Object process(String operator, Geometry inGeometryA, Geometry inGeometryB, Double distance)
            throws KettleException {

        Object result = false;

        if (GeometryUtils.getSrid(inGeometryA).compareTo(GeometryUtils.getSrid(inGeometryB)) == 0) {

            if (operator.equalsIgnoreCase("CONTAINS")) {
                result = inGeometryA.contains(inGeometryB);

            } else if (operator.equalsIgnoreCase("COVERED_BY")) {
                result = inGeometryA.coveredBy(inGeometryB);

            } else if (operator.equalsIgnoreCase("COVERS")) {
                result = inGeometryA.covers(inGeometryB);

            } else if (operator.equalsIgnoreCase("CROSSES")) {
                result = inGeometryA.crosses(inGeometryB);

            } else if (operator.equalsIgnoreCase("DISJOINT")) {
                result = inGeometryA.disjoint(inGeometryB);

            } else if (operator.equalsIgnoreCase("EQUALS")) {
                result = inGeometryA.equals(inGeometryB);

            } else if (operator.equalsIgnoreCase("EQUALS_EXACT")) {
                result = inGeometryA.equalsExact(inGeometryB);

            } else if (operator.equalsIgnoreCase("INTERSECTS")) {
                result = inGeometryA.intersects(inGeometryB);

            } else if (operator.equalsIgnoreCase("WITHIN")) {
                result = inGeometryA.within(inGeometryB);

            } else if (operator.equalsIgnoreCase("IS_WITHIN_DISTANCE")) {

                distance = Math.abs(distance);
                result = inGeometryA.isWithinDistance(inGeometryB, distance);

            } else if (operator.equalsIgnoreCase("IS_NOT_WITHIN_DISTANCE")) {

                distance = Math.abs(distance);
                result = !inGeometryA.isWithinDistance(inGeometryB, distance);

            } else if (operator.equalsIgnoreCase("OVERLAPS")) {
                result = inGeometryA.overlaps(inGeometryB);

            } else if (operator.equalsIgnoreCase("TOUCHES")) {
                result = inGeometryA.touches(inGeometryB);

            } else if (operator.equalsIgnoreCase("DISTANCE_MIN")) {
                result = inGeometryA.distance(inGeometryB);

            } else if (operator.equalsIgnoreCase("DISTANCE_MAX")) {

                Double maxDistance = inGeometryA.distance(inGeometryB);
                Geometry geometry = geometryFactory
                        .createGeometryCollection(new Geometry[] { inGeometryA, inGeometryB });
                Coordinate[] coords = geometry.convexHull().getCoordinates();

                for (Coordinate aCoordinate : coords) {

                    for (Coordinate bCoordinate : coords) {

                        double currenDistance = geometryFactory.createPoint(aCoordinate)
                                .distance(geometryFactory.createPoint(bCoordinate));
                        if (currenDistance > maxDistance) {
                            maxDistance = currenDistance;
                        }

                    }

                }

                result = maxDistance;

            } else {
                throw new IllegalArgumentException("Function \"" + operator + "\" is not allowed");
            }

        } else {
            throw new KettleException("Unauthorized mixed srids : " + GeometryUtils.getSrid(inGeometryA) + " with "
                    + GeometryUtils.getSrid(inGeometryB));
        }

        return result;

    }

}