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

com.hazelcast.shaded.org.locationtech.jts.geom.IntersectionMatrix Maven / Gradle / Ivy

There is a newer version: 5.5.0
Show newest version
/*
 * Copyright (c) 2016 Vivid Solutions.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * and Eclipse Distribution License v. 1.0 which accompanies this distribution.
 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v20.html
 * and the Eclipse Distribution License is available at
 *
 * http://www.eclipse.org/org/documents/edl-v10.php.
 */
package com.hazelcast.shaded.org.locationtech.jts.geom;

/**
 * Models a Dimensionally Extended Nine-Intersection Model (DE-9IM) matrix. 
 * DE-9IM matrix values (such as "212FF1FF2")
 * specify the topological relationship between two {@link Geometry}s. 
 * This class can also represent matrix patterns (such as "T*T******")
 * which are used for matching instances of DE-9IM matrices.
 * 

* DE-9IM matrices are 3x3 matrices with integer entries. * The matrix indices {0,1,2} represent the topological locations * that occur in a geometry (Interior, Boundary, Exterior). * These are provided by the constants * {@link Location#INTERIOR}, {@link Location#BOUNDARY}, and {@link Location#EXTERIOR}. *

* When used to specify the topological relationship between two geometries, * the matrix entries represent the possible dimensions of each intersection: * {@link Dimension#A} = 2, {@link Dimension#L} = 1, {@link Dimension#P} = 0 and {@link Dimension#FALSE} = -1. * When used to represent a matrix pattern entries can have the additional values * {@link Dimension#TRUE} {"T") and {@link Dimension#DONTCARE} ("*"). *

* For a description of the DE-9IM and the spatial predicates derived from it, * see the following references: *

*

* Methods are provided to: *

    *
  • set and query the elements of the matrix in a convenient fashion *
  • convert to and from the standard string representation (specified in * SFS Section 2.1.13.2). *
  • test if a matrix matches a given pattern string. *
  • test if a matrix (possibly with geometry dimensions) matches a standard named spatial predicate *
* *@version 1.7 */ public class IntersectionMatrix implements Cloneable { /** * Internal representation of this IntersectionMatrix. */ private int[][] matrix; /** * Creates an IntersectionMatrix with FALSE * dimension values. */ public IntersectionMatrix() { matrix = new int[3][3]; setAll(Dimension.FALSE); } /** * Creates an IntersectionMatrix with the given dimension * symbols. * *@param elements a String of nine dimension symbols in row major order */ public IntersectionMatrix(String elements) { this(); set(elements); } /** * Creates an IntersectionMatrix with the same elements as * other. * *@param other an IntersectionMatrix to copy */ public IntersectionMatrix(IntersectionMatrix other) { this(); matrix[Location.INTERIOR][Location.INTERIOR] = other.matrix[Location.INTERIOR][Location.INTERIOR]; matrix[Location.INTERIOR][Location.BOUNDARY] = other.matrix[Location.INTERIOR][Location.BOUNDARY]; matrix[Location.INTERIOR][Location.EXTERIOR] = other.matrix[Location.INTERIOR][Location.EXTERIOR]; matrix[Location.BOUNDARY][Location.INTERIOR] = other.matrix[Location.BOUNDARY][Location.INTERIOR]; matrix[Location.BOUNDARY][Location.BOUNDARY] = other.matrix[Location.BOUNDARY][Location.BOUNDARY]; matrix[Location.BOUNDARY][Location.EXTERIOR] = other.matrix[Location.BOUNDARY][Location.EXTERIOR]; matrix[Location.EXTERIOR][Location.INTERIOR] = other.matrix[Location.EXTERIOR][Location.INTERIOR]; matrix[Location.EXTERIOR][Location.BOUNDARY] = other.matrix[Location.EXTERIOR][Location.BOUNDARY]; matrix[Location.EXTERIOR][Location.EXTERIOR] = other.matrix[Location.EXTERIOR][Location.EXTERIOR]; } /** * Adds one matrix to another. * Addition is defined by taking the maximum dimension value of each position * in the summand matrices. * * @param im the matrix to add */ public void add(IntersectionMatrix im) { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { setAtLeast(i, j, im.get(i, j)); } } } /** * Tests if the dimension value matches TRUE * (i.e. has value 0, 1, 2 or TRUE). * *@param actualDimensionValue a number that can be stored in the IntersectionMatrix * . Possible values are {TRUE, FALSE, DONTCARE, 0, 1, 2}. *@return true if the dimension value matches TRUE */ public static boolean isTrue(int actualDimensionValue) { if (actualDimensionValue >= 0 || actualDimensionValue == Dimension.TRUE) { return true; } return false; } /** * Tests if the dimension value satisfies the dimension symbol. * *@param actualDimensionValue a number that can be stored in the IntersectionMatrix * . Possible values are {TRUE, FALSE, DONTCARE, 0, 1, 2}. *@param requiredDimensionSymbol a character used in the string * representation of an IntersectionMatrix. Possible values * are {T, F, * , 0, 1, 2}. *@return true if the dimension symbol matches * the dimension value */ public static boolean matches(int actualDimensionValue, char requiredDimensionSymbol) { if (requiredDimensionSymbol == Dimension.SYM_DONTCARE) { return true; } if (requiredDimensionSymbol == Dimension.SYM_TRUE && (actualDimensionValue >= 0 || actualDimensionValue == Dimension.TRUE)) { return true; } if (requiredDimensionSymbol == Dimension.SYM_FALSE && actualDimensionValue == Dimension.FALSE) { return true; } if (requiredDimensionSymbol == Dimension.SYM_P && actualDimensionValue == Dimension.P) { return true; } if (requiredDimensionSymbol == Dimension.SYM_L && actualDimensionValue == Dimension.L) { return true; } if (requiredDimensionSymbol == Dimension.SYM_A && actualDimensionValue == Dimension.A) { return true; } return false; } /** * Tests if each of the actual dimension symbols in a matrix string satisfies the * corresponding required dimension symbol in a pattern string. * *@param actualDimensionSymbols nine dimension symbols to validate. * Possible values are {T, F, * , 0, 1, 2}. *@param requiredDimensionSymbols nine dimension symbols to validate * against. Possible values are {T, F, * , 0, 1, 2}. *@return true if each of the required dimension * symbols encompass the corresponding actual dimension symbol */ public static boolean matches(String actualDimensionSymbols, String requiredDimensionSymbols) { IntersectionMatrix m = new IntersectionMatrix(actualDimensionSymbols); return m.matches(requiredDimensionSymbols); } /** * Changes the value of one of this IntersectionMatrixs * elements. * *@param row the row of this IntersectionMatrix, * indicating the interior, boundary or exterior of the first Geometry *@param column the column of this IntersectionMatrix, * indicating the interior, boundary or exterior of the second Geometry *@param dimensionValue the new value of the element */ public void set(int row, int column, int dimensionValue) { matrix[row][column] = dimensionValue; } /** * Changes the elements of this IntersectionMatrix to the * dimension symbols in dimensionSymbols. * *@param dimensionSymbols nine dimension symbols to which to set this IntersectionMatrix * s elements. Possible values are {T, F, * , 0, 1, 2} */ public void set(String dimensionSymbols) { for (int i = 0; i < dimensionSymbols.length(); i++) { int row = i / 3; int col = i % 3; matrix[row][col] = Dimension.toDimensionValue(dimensionSymbols.charAt(i)); } } /** * Changes the specified element to minimumDimensionValue if the * element is less. * *@param row the row of this IntersectionMatrix * , indicating the interior, boundary or exterior of the first Geometry *@param column the column of this IntersectionMatrix * , indicating the interior, boundary or exterior of the second Geometry *@param minimumDimensionValue the dimension value with which to compare the * element. The order of dimension values from least to greatest is * {DONTCARE, TRUE, FALSE, 0, 1, 2}. */ public void setAtLeast(int row, int column, int minimumDimensionValue) { if (matrix[row][column] < minimumDimensionValue) { matrix[row][column] = minimumDimensionValue; } } /** * If row >= 0 and column >= 0, changes the specified element to minimumDimensionValue * if the element is less. Does nothing if row <0 or column < 0. * *@param row the row of this IntersectionMatrix * , indicating the interior, boundary or exterior of the first Geometry *@param column the column of this IntersectionMatrix * , indicating the interior, boundary or exterior of the second Geometry *@param minimumDimensionValue the dimension value with which to compare the * element. The order of dimension values from least to greatest is * {DONTCARE, TRUE, FALSE, 0, 1, 2}. */ public void setAtLeastIfValid(int row, int column, int minimumDimensionValue) { if (row >= 0 && column >= 0) { setAtLeast(row, column, minimumDimensionValue); } } /** * For each element in this IntersectionMatrix, changes the * element to the corresponding minimum dimension symbol if the element is * less. * *@param minimumDimensionSymbols nine dimension symbols with which to * compare the elements of this IntersectionMatrix. The * order of dimension values from least to greatest is {DONTCARE, TRUE, FALSE, 0, 1, 2} * . */ public void setAtLeast(String minimumDimensionSymbols) { for (int i = 0; i < minimumDimensionSymbols.length(); i++) { int row = i / 3; int col = i % 3; setAtLeast(row, col, Dimension.toDimensionValue(minimumDimensionSymbols.charAt(i))); } } /** * Changes the elements of this IntersectionMatrix to dimensionValue * . * *@param dimensionValue the dimension value to which to set this IntersectionMatrix * s elements. Possible values {TRUE, FALSE, DONTCARE, 0, 1, 2} * . */ public void setAll(int dimensionValue) { for (int ai = 0; ai < 3; ai++) { for (int bi = 0; bi < 3; bi++) { matrix[ai][bi] = dimensionValue; } } } /** * Returns the value of one of this matrix * entries. * The value of the provided index is one of the * values from the {@link Location} class. * The value returned is a constant * from the {@link Dimension} class. * *@param row the row of this IntersectionMatrix, indicating * the interior, boundary or exterior of the first Geometry *@param column the column of this IntersectionMatrix, * indicating the interior, boundary or exterior of the second Geometry *@return the dimension value at the given matrix position. */ public int get(int row, int column) { return matrix[row][column]; } /** * Tests if this matrix matches [FF*FF****]. * *@return true if the two Geometrys related by * this matrix are disjoint */ public boolean isDisjoint() { return matrix[Location.INTERIOR][Location.INTERIOR] == Dimension.FALSE && matrix[Location.INTERIOR][Location.BOUNDARY] == Dimension.FALSE && matrix[Location.BOUNDARY][Location.INTERIOR] == Dimension.FALSE && matrix[Location.BOUNDARY][Location.BOUNDARY] == Dimension.FALSE; } /** * Tests if isDisjoint returns false. * *@return true if the two Geometrys related by * this matrix intersect */ public boolean isIntersects() { return ! isDisjoint(); } /** * Tests if this matrix matches * [FT*******], [F**T*****] or [F***T****]. * *@param dimensionOfGeometryA the dimension of the first Geometry *@param dimensionOfGeometryB the dimension of the second Geometry *@return true if the two Geometry * s related by this matrix touch; Returns false * if both Geometrys are points. */ public boolean isTouches(int dimensionOfGeometryA, int dimensionOfGeometryB) { if (dimensionOfGeometryA > dimensionOfGeometryB) { //no need to get transpose because pattern matrix is symmetrical return isTouches(dimensionOfGeometryB, dimensionOfGeometryA); } if ((dimensionOfGeometryA == Dimension.A && dimensionOfGeometryB == Dimension.A) || (dimensionOfGeometryA == Dimension.L && dimensionOfGeometryB == Dimension.L) || (dimensionOfGeometryA == Dimension.L && dimensionOfGeometryB == Dimension.A) || (dimensionOfGeometryA == Dimension.P && dimensionOfGeometryB == Dimension.A) || (dimensionOfGeometryA == Dimension.P && dimensionOfGeometryB == Dimension.L)) { return matrix[Location.INTERIOR][Location.INTERIOR] == Dimension.FALSE && (isTrue(matrix[Location.INTERIOR][Location.BOUNDARY]) || isTrue(matrix[Location.BOUNDARY][Location.INTERIOR]) || isTrue(matrix[Location.BOUNDARY][Location.BOUNDARY])); } return false; } /** * Tests whether this geometry crosses the * specified geometry. *

* The crosses predicate has the following equivalent definitions: *

    *
  • The geometries have some but not all interior points in common. *
  • The DE-9IM Intersection Matrix for the two geometries matches *
      *
    • [T*T******] (for P/L, P/A, and L/A situations) *
    • [T*****T**] (for L/P, L/A, and A/L situations) *
    • [0********] (for L/L situations) *
    *
* For any other combination of dimensions this predicate returns false. *

* The SFS defined this predicate only for P/L, P/A, L/L, and L/A situations. * JTS extends the definition to apply to L/P, A/P and A/L situations as well. * This makes the relation symmetric. * *@param dimensionOfGeometryA the dimension of the first Geometry *@param dimensionOfGeometryB the dimension of the second Geometry *@return true if the two Geometrys * related by this matrix cross. */ public boolean isCrosses(int dimensionOfGeometryA, int dimensionOfGeometryB) { if ((dimensionOfGeometryA == Dimension.P && dimensionOfGeometryB == Dimension.L) || (dimensionOfGeometryA == Dimension.P && dimensionOfGeometryB == Dimension.A) || (dimensionOfGeometryA == Dimension.L && dimensionOfGeometryB == Dimension.A)) { return isTrue(matrix[Location.INTERIOR][Location.INTERIOR]) && isTrue(matrix[Location.INTERIOR][Location.EXTERIOR]); } if ((dimensionOfGeometryA == Dimension.L && dimensionOfGeometryB == Dimension.P) || (dimensionOfGeometryA == Dimension.A && dimensionOfGeometryB == Dimension.P) || (dimensionOfGeometryA == Dimension.A && dimensionOfGeometryB == Dimension.L)) { return isTrue(matrix[Location.INTERIOR][Location.INTERIOR]) && isTrue(matrix[Location.EXTERIOR][Location.INTERIOR]); } if (dimensionOfGeometryA == Dimension.L && dimensionOfGeometryB == Dimension.L) { return matrix[Location.INTERIOR][Location.INTERIOR] == 0; } return false; } /** * Tests whether this matrix matches [T*F**F***]. * *@return true if the first Geometry is within * the second */ public boolean isWithin() { return isTrue(matrix[Location.INTERIOR][Location.INTERIOR]) && matrix[Location.INTERIOR][Location.EXTERIOR] == Dimension.FALSE && matrix[Location.BOUNDARY][Location.EXTERIOR] == Dimension.FALSE; } /** * Tests whether this matrix matches [T*****FF*[. * *@return true if the first Geometry contains the * second */ public boolean isContains() { return isTrue(matrix[Location.INTERIOR][Location.INTERIOR]) && matrix[Location.EXTERIOR][Location.INTERIOR] == Dimension.FALSE && matrix[Location.EXTERIOR][Location.BOUNDARY] == Dimension.FALSE; } /** * Tests if this matrix matches * [T*****FF*] * or [*T****FF*] * or [***T**FF*] * or [****T*FF*] * *@return true if the first Geometry covers the * second */ public boolean isCovers() { boolean hasPointInCommon = isTrue(matrix[Location.INTERIOR][Location.INTERIOR]) || isTrue(matrix[Location.INTERIOR][Location.BOUNDARY]) || isTrue(matrix[Location.BOUNDARY][Location.INTERIOR]) || isTrue(matrix[Location.BOUNDARY][Location.BOUNDARY]); return hasPointInCommon && matrix[Location.EXTERIOR][Location.INTERIOR] == Dimension.FALSE && matrix[Location.EXTERIOR][Location.BOUNDARY] == Dimension.FALSE; } /** *Tests if this matrix matches * [T*F**F***] * or [*TF**F***] * or [**FT*F***] * or [**F*TF***] * *@return true if the first Geometry * is covered by the second */ public boolean isCoveredBy() { boolean hasPointInCommon = isTrue(matrix[Location.INTERIOR][Location.INTERIOR]) || isTrue(matrix[Location.INTERIOR][Location.BOUNDARY]) || isTrue(matrix[Location.BOUNDARY][Location.INTERIOR]) || isTrue(matrix[Location.BOUNDARY][Location.BOUNDARY]); return hasPointInCommon && matrix[Location.INTERIOR][Location.EXTERIOR] == Dimension.FALSE && matrix[Location.BOUNDARY][Location.EXTERIOR] == Dimension.FALSE; } /** * Tests whether the argument dimensions are equal and * this matrix matches the pattern [T*F**FFF*]. *

* Note: This pattern differs from the one stated in * Simple feature access - Part 1: Common architecture. * That document states the pattern as [TFFFTFFFT]. This would * specify that * two identical POINTs are not equal, which is not desirable behaviour. * The pattern used here has been corrected to compute equality in this situation. * *@param dimensionOfGeometryA the dimension of the first Geometry *@param dimensionOfGeometryB the dimension of the second Geometry *@return true if the two Geometrys * related by this matrix are equal; the * Geometrys must have the same dimension to be equal */ public boolean isEquals(int dimensionOfGeometryA, int dimensionOfGeometryB) { if (dimensionOfGeometryA != dimensionOfGeometryB) { return false; } return isTrue(matrix[Location.INTERIOR][Location.INTERIOR]) && matrix[Location.INTERIOR][Location.EXTERIOR] == Dimension.FALSE && matrix[Location.BOUNDARY][Location.EXTERIOR] == Dimension.FALSE && matrix[Location.EXTERIOR][Location.INTERIOR] == Dimension.FALSE && matrix[Location.EXTERIOR][Location.BOUNDARY] == Dimension.FALSE; } /** * Tests if this matrix matches *

    *
  • [T*T***T**] (for two points or two surfaces) *
  • [1*T***T**] (for two curves) *
. * *@param dimensionOfGeometryA the dimension of the first Geometry *@param dimensionOfGeometryB the dimension of the second Geometry *@return true if the two Geometrys * related by this matrix overlap. For this * function to return true, the Geometrys must * be two points, two curves or two surfaces. */ public boolean isOverlaps(int dimensionOfGeometryA, int dimensionOfGeometryB) { if ((dimensionOfGeometryA == Dimension.P && dimensionOfGeometryB == Dimension.P) || (dimensionOfGeometryA == Dimension.A && dimensionOfGeometryB == Dimension.A)) { return isTrue(matrix[Location.INTERIOR][Location.INTERIOR]) && isTrue(matrix[Location.INTERIOR][Location.EXTERIOR]) && isTrue(matrix[Location.EXTERIOR][Location.INTERIOR]); } if (dimensionOfGeometryA == Dimension.L && dimensionOfGeometryB == Dimension.L) { return matrix[Location.INTERIOR][Location.INTERIOR] == 1 && isTrue(matrix[Location.INTERIOR][Location.EXTERIOR]) && isTrue(matrix[Location.EXTERIOR][Location.INTERIOR]); } return false; } /** * Tests whether this matrix matches the given matrix pattern. * *@param pattern A pattern containing nine dimension symbols with which to * compare the entries of this matrix. Possible * symbol values are {T, F, * , 0, 1, 2}. *@return true if this matrix matches the pattern */ public boolean matches(String pattern) { if (pattern.length() != 9) { throw new IllegalArgumentException("Should be length 9: " + pattern); } for (int ai = 0; ai < 3; ai++) { for (int bi = 0; bi < 3; bi++) { if (!matches(matrix[ai][bi], pattern.charAt(3 * ai + bi))) { return false; } } } return true; } /** * Transposes this IntersectionMatrix. * *@return this IntersectionMatrix as a convenience */ public IntersectionMatrix transpose() { int temp = matrix[1][0]; matrix[1][0] = matrix[0][1]; matrix[0][1] = temp; temp = matrix[2][0]; matrix[2][0] = matrix[0][2]; matrix[0][2] = temp; temp = matrix[2][1]; matrix[2][1] = matrix[1][2]; matrix[1][2] = temp; return this; } /** * Returns a nine-character String representation of this IntersectionMatrix * . * *@return the nine dimension symbols of this IntersectionMatrix * in row-major order. */ public String toString() { StringBuilder builder = new StringBuilder("123456789"); for (int ai = 0; ai < 3; ai++) { for (int bi = 0; bi < 3; bi++) { builder.setCharAt(3 * ai + bi, Dimension.toDimensionSymbol(matrix[ai][bi])); } } return builder.toString(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy