regions

JTS Topology Suite

To work with spatial objects we use HelperJTS. According to Vivid Solutions, JTS Topology Suite (JTS) is an API providing 2D spatial object model and fundamental geometric functions. It implements the geometry model defined in the OpenGIS Consortium Simple Features Specification for SQL. Functions provided include:

  • Unordered List Item spatial predicates (based on the DE-9IM model)
  • overlay functions (intersection, difference, union, symmetric difference)
  • buffer
  • convex hull
  • area and distance functions topological validity checking

and It has the following design goals:

  • JTS conforms to the Simple Features Specification for SQL published by the Open GIS Consortium
  • JTS provides a complete, consistent, robust implementation of fundamental 2D spatial algorithms
  • JTS is fast enough for production use
  • JTS is written in 100% pure JavaTM
  • JTS is open source (under the LGPL license)

However, to be viable afford even millions of checks per minute, we perform some optimizations, but basic functions remain the same.

Some summary information is available:

  • getArea() - Returns the area of this Geometry. Area returned in the same units as the coordinates (be careful of lat/lon data!)
  • getCentroid() - Computes the centroid of this Geometry.
  • getEnvelope() - Returns this Geometrys bounding box.
  • getEnvelopeInternal() - tReturns the minimum and maximum x and y values in this Geometry , or a null Envelope if this Geometry is empty.
  • getInteriorPoint() - Computes an interior point of this Geometry.
  • getDimension() - Returns the dimension of this Geometry. The dimension of the class implementing this interface, whether or not this object is the empty geometry

Geometry relationships are represented by the following functions returning true or false:

  • disjoint(Geometry) - Returns true if this geometry is disjoint to the specified geometry.
  • touches(Geometry) - Returns true if this geometry touches the specified geometry.
  • intersects(Geometry) - Returns true if this geometry intersects the specified geometry.
  • crosses(Geometry) - Returns true if this geometry crosses the specified geometry.
  • within(Geometry) - Returns true if this geometry is within the specified geometry.
  • contains(Geometry) - Returns true if this geometry contains the specified geometry.
  • overlaps(Geometry) - Returns true if this geometry overlaps the specified geometry.
  • covers(Geometry) - Returns true if this geometry covers the specified geometry.
  • coveredBy(Geometry) - Returns true if this geometry is covered by the specified geometry.
  • relate(Geometry, String) - Returns true if the elements in the DE-9IM IntersectionMatrix for the two Geometrys match the elements in intersectionPattern.
  • relate(Geometry) Returns the DE-9IM IntersectionMatrix for the two Geometrys..

To actually determine a shape based on two geometry:

  • intersection(Geometry) - Computes a Geometry representing the points shared by this Geometry and other.
  • union(Geometry) - Computes a Geometry representing all the points in this Geometry and other.
  • difference(Geometry) - Computes a Geometry representing the points making up this Geometry that do not make up other.
  • symDifference(Geometry) - Returns a set combining the points in this Geometry not in other, and the points in other not in this Geometry.

Some of the most helpful functions are:

  • distance(Geometry) - Returns the minimum distance between this Geometry and the Geometry g
  • buffer(double) -Computes a buffer area around this geometry having the given width.
  • union() - Computes a Geometry representing all the points in this Geometry and other.

The three most difficult methods are here :

  • equals(Object) - Returns true if this geometry is equal to the specified geometry
  • equals(Geometry) - checks if the geometry is the same shape
  • equalsExact(Geometry) - Returns true if the two Geometrys are exactly equal, up to a specified distance tolerance.

There are some book keeping methods to help discovery how the geometry was constructed:

  • getGeometryFactory() - Gets the factory which contains the context in which this geometry was created.
  • getPreceisionModel()
  • toText() - the WKT representation of the Geometry
  • getGeometryType() - factory method called (ie “point”, “linestring”, etc..)

A couple of methods are there to store your developer information:

  • getSRID() - stores the “spatial reference id”, used as an external key when working with databases
  • getUserData() - intended to be used by developers, a best practice is to store a java.util.Map. GeoTools will occasionally use this field to store a “srsName” or full CoordianteReferenceSystem.

The code below is based on this two polygons. Its coordinates can be viewed in GerarPoligonoA and GerarPoligonoB methods.

The operations results of the main methods follows in the table below:

AB BA
Equals F F
Disjoint F F
Intersects T T
Touches F F
Crosses F F
Within F F
Contains F F
Overlaps T T
Polygon.java
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
 
import ContextNetGeo.CtxCoordinate;
import ContextNetGeo.Polygon;
 
public class Execute {
 
  /**
   * @param args
   * @throws Exception
   */
 
  public static void main(String[] args) throws Exception {
    Polygon polygonA = GerarPoligonoA();
    Polygon polygonB = GerarPoligonoB();
    testeOperacoes(polygonA, polygonB);
    System.out.println("\nCalculando média do tempo de consulta no poligono sem cache...");
    testeCache(false, polygonA, polygonB);
    polygonA = GerarPoligonoA();
    polygonB = GerarPoligonoB();
    System.out.println("\nCalculando média do tempo de consulta no poligono com cache...");
    testeCache(true, polygonA, polygonB);
 
  }
 
  private static void testeCache(boolean isCached, Polygon polygonA, Polygon polygonB) throws Exception {
    long startTime = System.currentTimeMillis();
    long iterations = 0;
    //Random rdn = new Random();
    polygonA.setCache(isCached, 15000);
    List<CtxCoordinate> listaPontos = gerarPontosAleatorios(1000000);
    polygonA.setCache(isCached, 15000);
    polygonB.setCache(isCached, 15000);
    while (System.currentTimeMillis() - startTime < 30000) {
      // Incrementa a quantidade de iterações feitas dentro de 5 segundos.
      iterations++;
      for (CtxCoordinate ctxCoordinate : listaPontos) {
        polygonA.isPointWithin(ctxCoordinate);
 
        // Incrementa a quantidade de iterações feitas dentro de 5 segundos.
        iterations++;
      }
    }
    long finishTime = System.currentTimeMillis() - startTime;
    // Calcula a média de tempo de cada iteração.
    float media = (float) finishTime / iterations;
 
    if (isCached)
      System.out.println("Média do tempo para consultas aleatórias com cache (ms):" + media);
    else
      System.out.println("Média do tempo para consultas aleatórias sem cache (ms):" + media);
 
    System.out.println("Quantidade de Iterações: " + iterations);
  }
 
  private static List<CtxCoordinate> gerarPontosAleatorios(int quantidade) {
 
    ArrayList<CtxCoordinate> list = new ArrayList<CtxCoordinate>(quantidade);
    Random rdn = new Random();
    for (int i = 0; i < 50; i++) {
      list.add(new CtxCoordinate(rdn.nextInt(100), rdn.nextInt(700)));
    }
 
    return list;
  }
 
  private static void testeOperacoes(Polygon polygonA, Polygon polygonB) {
    System.out.println("AB");
    System.out.println("Equals    : " + polygonA.GetData().equals(polygonB.GetData()));
    System.out.println("disjoint  : " + polygonA.GetData().disjoint(polygonB.GetData()));
    System.out.println("intersects: " + polygonA.GetData().intersects(polygonB.GetData()));
    System.out.println("touches   : " + polygonA.GetData().touches(polygonB.GetData()));
    System.out.println("crosses   : " + polygonA.GetData().crosses(polygonB.GetData()));
    System.out.println("within    : " + polygonA.GetData().within(polygonB.GetData()));
    System.out.println("contains  : " + polygonA.GetData().contains(polygonB.GetData()));
    System.out.println("overlaps  : " + polygonA.GetData().overlaps(polygonB.GetData()));
 
    System.out.println("\n");
    System.out.println("BA");
    System.out.println("Equals    : " + polygonB.GetData().equals(polygonA.GetData()));
    System.out.println("disjoint  : " + polygonB.GetData().disjoint(polygonA.GetData()));
    System.out.println("intersects: " + polygonB.GetData().intersects(polygonA.GetData()));
    System.out.println("touches   : " + polygonB.GetData().touches(polygonA.GetData()));
    System.out.println("crosses   : " + polygonB.GetData().crosses(polygonA.GetData()));
    System.out.println("within    : " + polygonB.GetData().within(polygonA.GetData()));
    System.out.println("contains  : " + polygonB.GetData().contains(polygonA.GetData()));
    System.out.println("overlaps  : " + polygonB.GetData().overlaps(polygonA.GetData()));
  }
 
  private static Polygon GerarPoligonoA() {
    // Poligono 1 - Externa
    ArrayList<CtxCoordinate> listaCoordenadasMaster = new ArrayList<CtxCoordinate>();
 
    listaCoordenadasMaster.add(new CtxCoordinate(30, 260));
    listaCoordenadasMaster.add(new CtxCoordinate(130, 350));
    listaCoordenadasMaster.add(new CtxCoordinate(250, 330));
    listaCoordenadasMaster.add(new CtxCoordinate(320, 180));
    listaCoordenadasMaster.add(new CtxCoordinate(250, 50));
    listaCoordenadasMaster.add(new CtxCoordinate(70, 60));
    listaCoordenadasMaster.add(new CtxCoordinate(30, 260));
 
    // Poligono 1 - Interna
    ArrayList<CtxCoordinate> listaCoordenadasEscravo = new ArrayList<CtxCoordinate>();
    listaCoordenadasEscravo.add(new CtxCoordinate(140, 260));
    listaCoordenadasEscravo.add(new CtxCoordinate(110, 150));
    listaCoordenadasEscravo.add(new CtxCoordinate(230, 210));
    listaCoordenadasEscravo.add(new CtxCoordinate(140, 210));
    listaCoordenadasEscravo.add(new CtxCoordinate(140, 260));
 
    return new Polygon(listaCoordenadasMaster, listaCoordenadasEscravo);
  }
 
  private static Polygon GerarPoligonoB() {
    // Poligono 1 - Externa
    ArrayList<CtxCoordinate> listaCoordenadasMaster = new ArrayList<CtxCoordinate>();
    listaCoordenadasMaster.add(new CtxCoordinate(210, 390));
    listaCoordenadasMaster.add(new CtxCoordinate(180, 290));
    listaCoordenadasMaster.add(new CtxCoordinate(170, 210));
    listaCoordenadasMaster.add(new CtxCoordinate(190, 140));
    listaCoordenadasMaster.add(new CtxCoordinate(360, 60));
    listaCoordenadasMaster.add(new CtxCoordinate(470, 220));
    listaCoordenadasMaster.add(new CtxCoordinate(440, 390));
    listaCoordenadasMaster.add(new CtxCoordinate(210, 390));
 
    // Poligono 1 - Interna
    ArrayList<CtxCoordinate> listaCoordenadasEscravo = new ArrayList<CtxCoordinate>();
    listaCoordenadasEscravo.add(new CtxCoordinate(340, 310));
    listaCoordenadasEscravo.add(new CtxCoordinate(250, 260));
    listaCoordenadasEscravo.add(new CtxCoordinate(270, 140));
    listaCoordenadasEscravo.add(new CtxCoordinate(360, 130));
    listaCoordenadasEscravo.add(new CtxCoordinate(390, 230));
    listaCoordenadasEscravo.add(new CtxCoordinate(340, 310));
 
    return new Polygon(listaCoordenadasMaster, listaCoordenadasEscravo);
  }
}
  • regions.txt
  • Last modified: 2017/07/21 03:08
  • (external edit)