All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ca.bc.gov.open.cpf.plugins.geometryvalidation.GeometryValidatorPlugin Maven / Gradle / Ivy

The newest version!
/*
 * Copyright © 2008-2016, Province of British Columbia
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package ca.bc.gov.open.cpf.plugins.geometryvalidation;

import ca.bc.gov.open.cpf.plugin.api.BusinessApplicationPlugin;
import ca.bc.gov.open.cpf.plugin.api.RequestParameter;
import ca.bc.gov.open.cpf.plugin.api.Required;
import ca.bc.gov.open.cpf.plugin.api.ResultAttribute;

import com.revolsys.geometry.cs.GeographicCoordinateSystem;
import com.revolsys.geometry.model.Geometry;
import com.revolsys.geometry.model.GeometryFactory;
import com.revolsys.geometry.model.Point;
import com.revolsys.geometry.operation.valid.GeometryValidationError;
import com.revolsys.geometry.operation.valid.IsValidOp;
import com.revolsys.geometry.precision.MinimumClearance;

/**
 * The GeometryValidatorPlugin converts the geometry to the requested coordinate
 * system and precision model. It then checks to see if the geometry
 * {@link Geometry#isSimple()}, {@link Geometry#isValid()}, and calculates the
 * {@link MinimumClearance#getDistance()}.
 *
 * @author Paul Austin 
 */
@BusinessApplicationPlugin(name = "GeometryValidator",
    description = "The Geometry Validator takes your input geometry and determines if it is simple, valid, and robust. It will also compute the geometry's minimum clearance. The Validator converts your geometry to a coordinate system of your choice then applies a precision model before analysing it. The definition of terms such as simple, valid, robust, and minimum clearance can be found in the detailed service description.",
    descriptionUrl = "http://www.data.gov.bc.ca/dbc/geo/geomark/index.page",
    numRequestsPerWorker = 100, instantModePermission = "permitAll")
public class GeometryValidatorPlugin {
  /** The geometry to validate. */
  private Geometry geometry;

  /** The flag indicating if the converted geometry was isSimple. */
  private boolean isSimple;

  /**
   * The number of coordinate axis to use for the converted geometry (2 for x, 7
   * and 3 for x, y, z).
   */
  private int resultNumAxis;

  /** The scale factor used to round the x, y coordinates. */
  private double resultScaleFactorXy;

  /** The scale factor used to round the z coordinate. */
  private double resultScaleFactorZ;

  /** The EPSG coordinate system id to convert the geometry to. */
  private int resultSrid;

  /** The flag indicating if the converted geometry was valid. */
  private boolean isValid;

  /** The minimum clearance required for the geometry to still be valid. */
  private double minimumClearance;

  /** The flag indicating if the geometry minimum clearance is robust. */
  private boolean isRobust = true;

  /** The description of any geometry validation errors. */
  private String validationError;

  /** The point location of the first geometry validation error. */
  private Point validationLocation;

  /**
   * Perform the geometry conversion and geometry validation.
   */
  public void execute() {
    if (this.geometry == null) {
      throw new IllegalArgumentException("Geometry cannot be null");
    } else {
      final GeometryFactory sourceGeometryFactory = this.geometry.getGeometryFactory();
      if (this.resultSrid == 0) {
        this.resultSrid = sourceGeometryFactory.getCoordinateSystemId();
      }
      if (this.resultNumAxis == 0) {
        this.resultNumAxis = sourceGeometryFactory.getAxisCount();
      }
      if (this.resultScaleFactorXy == 0) {
        this.resultScaleFactorXy = sourceGeometryFactory.getScaleXY();
      }
      if (this.resultScaleFactorZ == 0) {
        this.resultScaleFactorZ = sourceGeometryFactory.getScaleZ();
      }
      final GeometryFactory geometryFactory = GeometryFactory.fixed(this.resultSrid,
        this.resultNumAxis, this.resultScaleFactorXy, this.resultScaleFactorXy,
        this.resultScaleFactorZ);
      this.geometry = geometryFactory.geometry(this.geometry);

      final IsValidOp validOp = new IsValidOp(this.geometry);
      this.isValid = validOp.isValid();
      if (this.isValid) {
        this.validationError = null;
        this.validationLocation = null;
      } else {
        final GeometryValidationError topologyError = validOp.getValidationError();
        this.validationError = topologyError.getMessage();
        final Point point = topologyError.getErrorPoint();
        this.validationLocation = geometryFactory.point(point);
      }
      this.isSimple = this.geometry.isSimple();

      this.minimumClearance = MinimumClearance.getDistance(this.geometry);

      double clearanceScaleFactor;
      double clearanceTolerance;
      if (this.resultScaleFactorXy == 0) {
        if (geometryFactory.getCoordinateSystem() instanceof GeographicCoordinateSystem) {
          clearanceTolerance = .1;
          clearanceScaleFactor = 10000000;
        } else {
          clearanceTolerance = 0.001;
          clearanceScaleFactor = 1000;
        }
      } else {
        clearanceTolerance = 1 / this.resultScaleFactorXy;
        clearanceScaleFactor = this.resultScaleFactorXy;
      }
      if (Double.compare(this.minimumClearance, clearanceTolerance) < 0) {
        this.isRobust = false;
      }

      if (this.minimumClearance >= clearanceTolerance) {
        this.minimumClearance = Math.ceil(this.minimumClearance * clearanceScaleFactor)
          / clearanceScaleFactor;
      }
      if (Double.isNaN(this.minimumClearance) || Double.isInfinite(this.minimumClearance)
        || this.minimumClearance > 999999999) {
        this.minimumClearance = 999999999;
      }
    }
  }

  /**
   * Get the geometry to validate that has been converted to the required
   * coordinate system and precision model.
   *
   * @return The geometry to validate that has been converted to the required
   *         coordinate system and precision model.
   */
  @ResultAttribute(index = 0)
  public Geometry getGeometry() {
    return this.geometry;
  }

  /**
   * Get the minimum clearance required for the geometry to still be valid.
   *
   * @return The minimum clearance required for the geometry to still be valid.
   */
  @ResultAttribute(index = 6,
      description = "The minimum clearance required for the geometry to still be valid.")
  public double getMinimumClearance() {
    return this.minimumClearance;
  }

  /**
   * Get the description of any geometry validation errors.
   *
   * @return The description of any geometry validation errors.
   */
  @ResultAttribute(index = 3,
      description = "The description of the first geometry validation error.")
  public String getValidationError() {
    return this.validationError;
  }

  /**
   * Get the point location of the first geometry validation error.
   *
   * @return The point location of the first geometry validation error.
   */
  @ResultAttribute(index = 4,
      description = "The point location of the first geometry validation error.")
  public Point getValidationLocation() {
    return this.validationLocation;
  }

  /**
   * Get the flag indicating if the geometry minimum clearance is robust.
   *
   * @return The flag indicating if the geometry minimum clearance is robust.
   */
  @ResultAttribute(index = 5,
      description = "Flag indicating if the geometry minimum clearance is robust.")
  public boolean isIsRobust() {
    return this.isRobust;
  }

  /**
   * Get the flag indicating if the converted geometry was isSimple.
   *
   * @return The flag indicating if the converted geometry was isSimple.
   */
  @ResultAttribute(index = 1,
      description = "Flag indicating if the converted geometry was isSimple.")
  public boolean isIsSimple() {
    return this.isSimple;
  }

  /**
   * Get the flag indicating if the converted geometry was valid.
   *
   * @return The flag indicating if the converted geometry was valid.
   */
  @ResultAttribute(index = 2, description = "Flag indicating if the converted geometry was valid.")
  public boolean isIsValid() {
    return this.isValid;
  }

  /**
   * Set the geometry to validate.
   *
   * @param geometry The geometry to validate.
   */
  @Required
  @RequestParameter(
      description = "The geometry to validate. For single and instant requests enter a WKT encoded geometry or a Geomark URL.")
  public void setGeometry(final Geometry geometry) {
    this.geometry = geometry;
  }

  /**
   * Get the number of coordinate axis to use for the converted geometry (2 for
   * x, 7 and 3 for x, y, z).
   *
   * @param resultNumAxis The number of coordinate axis to use for the converted
   *          geometry (2 for x, 7 and 3 for x, y, z).
   */
  public void setResultNumAxis(final int resultNumAxis) {
    this.resultNumAxis = resultNumAxis;
  }

  /**
   * Get the scale factor used to round the x, y coordinates.
   *
   * @param resultScaleXy The scale factor used to round the x, y coordinates.
   */
  public void setResultScaleFactorXy(final double resultScaleXy) {
    this.resultScaleFactorXy = resultScaleXy;
  }

  /**
   * Get the scale factor used to round the z coordinates.
   *
   * @param resultScaleZ The scale factor used to round the z coordinates.
   */
  public void setResultScaleFactorZ(final double resultScaleZ) {
    this.resultScaleFactorZ = resultScaleZ;
  }

  /**
   * Set the EPSG coordinate system id to convert the geometry to.
   *
   * @param resultSrid The EPSG coordinate system id to convert the geometry to.
   */
  public void setResultSrid(final int resultSrid) {
    this.resultSrid = resultSrid;
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy