| 1 |
|
| 2 |
|
| 3 |
|
| 4 |
|
| 5 |
|
| 6 |
|
| 7 |
|
| 8 |
|
| 9 |
|
| 10 |
|
| 11 |
|
| 12 |
|
| 13 |
|
| 14 |
package org.locationtech.jts.geom; |
| 15 |
|
| 16 |
/** |
| 17 |
* Models a <b>Dimensionally Extended Nine-Intersection Model (DE-9IM)</b> matrix. |
| 18 |
* DE-9IM matrix values (such as "212FF1FF2") |
| 19 |
* specify the topological relationship between two {@link Geometry}s. |
| 20 |
* This class can also represent matrix patterns (such as "T*T******") |
| 21 |
* which are used for matching instances of DE-9IM matrices. |
| 22 |
* <p> |
| 23 |
* DE-9IM matrices are 3x3 matrices with integer entries. |
| 24 |
* The matrix indices {0,1,2} represent the topological locations |
| 25 |
* that occur in a geometry (Interior, Boundary, Exterior). |
| 26 |
* These are provided by the constants |
| 27 |
* {@link Location#INTERIOR}, {@link Location#BOUNDARY}, and {@link Location#EXTERIOR}. |
| 28 |
* <p> |
| 29 |
* When used to specify the topological relationship between two geometries, |
| 30 |
* the matrix entries represent the possible dimensions of each intersection: |
| 31 |
* {@link Dimension#A} = 2, {@link Dimension#L} = 1, {@link Dimension#P} = 0 and {@link Dimension#FALSE} = -1. |
| 32 |
* When used to represent a matrix pattern entries can have the additional values |
| 33 |
* {@link Dimension#TRUE} {"T") and {@link Dimension#DONTCARE} ("*"). |
| 34 |
* <p> |
| 35 |
* For a description of the DE-9IM and the spatial predicates derived from it, |
| 36 |
* see the following references: |
| 37 |
* <ul> |
| 38 |
* <li><i><a href="http://www.opengis.org/techno/specs.htm"> |
| 39 |
* OGC 99-049 OpenGIS Simple Features Specification for SQL</a></i> |
| 40 |
* , Section 2.1.13</li> |
| 41 |
* <li><i><a href="http://portal.opengeospatial.org/files/?artifact_id=25355"> |
| 42 |
* OGC 06-103r4 OpenGIS Implementation Standard for Geographic information - Simple feature access - Part 1: Common architecture</a></i> |
| 43 |
* , Section 6.1.15 (which provides some further details on certain predicate specifications). |
| 44 |
* </li> |
| 45 |
* <li>Wikipedia article on <a href="https://en.wikipedia.org/wiki/DE-9IM">DE-9IM</a></li> |
| 46 |
* </ul> |
| 47 |
* <p> |
| 48 |
* Methods are provided to: |
| 49 |
* <UL> |
| 50 |
* <LI>set and query the elements of the matrix in a convenient fashion |
| 51 |
* <LI>convert to and from the standard string representation (specified in |
| 52 |
* SFS Section 2.1.13.2). |
| 53 |
* <LI>test if a matrix matches a given pattern string. |
| 54 |
* <li>test if a matrix (possibly with geometry dimensions) matches a standard named spatial predicate |
| 55 |
* </UL> |
| 56 |
* |
| 57 |
*@version 1.7 |
| 58 |
*/ |
| 59 |
public class IntersectionMatrix implements Cloneable { |
| 60 |
/** |
| 61 |
* Internal representation of this <code>IntersectionMatrix</code>. |
| 62 |
*/ |
| 63 |
private int[][] matrix; |
| 64 |
|
| 65 |
/** |
| 66 |
* Creates an <code>IntersectionMatrix</code> with <code>FALSE</code> |
| 67 |
* dimension values. |
| 68 |
*/ |
| 69 |
public IntersectionMatrix() { |
| 70 |
matrix = new int[3][3]; |
| 71 |
setAll(Dimension.FALSE); |
| 72 |
} |
| 73 |
|
| 74 |
/** |
| 75 |
* Creates an <code>IntersectionMatrix</code> with the given dimension |
| 76 |
* symbols. |
| 77 |
* |
| 78 |
*@param elements a String of nine dimension symbols in row major order |
| 79 |
*/ |
| 80 |
public IntersectionMatrix(String elements) { |
| 81 |
this(); |
| 82 |
set(elements); |
| 83 |
} |
| 84 |
|
| 85 |
/** |
| 86 |
* Creates an <code>IntersectionMatrix</code> with the same elements as |
| 87 |
* <code>other</code>. |
| 88 |
* |
| 89 |
*@param other an <code>IntersectionMatrix</code> to copy |
| 90 |
*/ |
| 91 |
public IntersectionMatrix(IntersectionMatrix other) { |
| 92 |
this(); |
| 93 |
matrix[Location.INTERIOR][Location.INTERIOR] = other.matrix[Location.INTERIOR][Location.INTERIOR]; |
| 94 |
matrix[Location.INTERIOR][Location.BOUNDARY] = other.matrix[Location.INTERIOR][Location.BOUNDARY]; |
| 95 |
matrix[Location.INTERIOR][Location.EXTERIOR] = other.matrix[Location.INTERIOR][Location.EXTERIOR]; |
| 96 |
matrix[Location.BOUNDARY][Location.INTERIOR] = other.matrix[Location.BOUNDARY][Location.INTERIOR]; |
| 97 |
matrix[Location.BOUNDARY][Location.BOUNDARY] = other.matrix[Location.BOUNDARY][Location.BOUNDARY]; |
| 98 |
matrix[Location.BOUNDARY][Location.EXTERIOR] = other.matrix[Location.BOUNDARY][Location.EXTERIOR]; |
| 99 |
matrix[Location.EXTERIOR][Location.INTERIOR] = other.matrix[Location.EXTERIOR][Location.INTERIOR]; |
| 100 |
matrix[Location.EXTERIOR][Location.BOUNDARY] = other.matrix[Location.EXTERIOR][Location.BOUNDARY]; |
| 101 |
matrix[Location.EXTERIOR][Location.EXTERIOR] = other.matrix[Location.EXTERIOR][Location.EXTERIOR]; |
| 102 |
} |
| 103 |
|
| 104 |
/** |
| 105 |
* Adds one matrix to another. |
| 106 |
* Addition is defined by taking the maximum dimension value of each position |
| 107 |
* in the summand matrices. |
| 108 |
* |
| 109 |
* @param im the matrix to add |
| 110 |
*/ |
| 111 |
public void add(IntersectionMatrix im) |
| 112 |
{ |
| 113 |
for (int i = 0; i < 3; i++) { |
| 114 |
for (int j = 0; j < 3; j++) { |
| 115 |
setAtLeast(i, j, im.get(i, j)); |
| 116 |
} |
| 117 |
} |
| 118 |
} |
| 119 |
|
| 120 |
/** |
| 121 |
* Tests if the dimension value matches <tt>TRUE</tt> |
| 122 |
* (i.e. has value 0, 1, 2 or TRUE). |
| 123 |
* |
| 124 |
*@param actualDimensionValue a number that can be stored in the <code>IntersectionMatrix</code> |
| 125 |
* . Possible values are <code>{TRUE, FALSE, DONTCARE, 0, 1, 2}</code>. |
| 126 |
*@return true if the dimension value matches TRUE |
| 127 |
*/ |
| 128 |
public static boolean isTrue(int actualDimensionValue) { |
| 129 |
if (actualDimensionValue >= 0 || actualDimensionValue == Dimension.TRUE) { |
| 130 |
return true; |
| 131 |
} |
| 132 |
return false; |
| 133 |
} |
| 134 |
|
| 135 |
/** |
| 136 |
* Tests if the dimension value satisfies the dimension symbol. |
| 137 |
* |
| 138 |
*@param actualDimensionValue a number that can be stored in the <code>IntersectionMatrix</code> |
| 139 |
* . Possible values are <code>{TRUE, FALSE, DONTCARE, 0, 1, 2}</code>. |
| 140 |
*@param requiredDimensionSymbol a character used in the string |
| 141 |
* representation of an <code>IntersectionMatrix</code>. Possible values |
| 142 |
* are <code>{T, F, * , 0, 1, 2}</code>. |
| 143 |
*@return true if the dimension symbol matches |
| 144 |
* the dimension value |
| 145 |
*/ |
| 146 |
public static boolean matches(int actualDimensionValue, char requiredDimensionSymbol) { |
| 147 |
if (requiredDimensionSymbol == Dimension.SYM_DONTCARE) { |
| 148 |
return true; |
| 149 |
} |
| 150 |
if (requiredDimensionSymbol == Dimension.SYM_TRUE && (actualDimensionValue >= 0 || actualDimensionValue |
| 151 |
== Dimension.TRUE)) { |
| 152 |
return true; |
| 153 |
} |
| 154 |
if (requiredDimensionSymbol == Dimension.SYM_FALSE && actualDimensionValue == Dimension.FALSE) { |
| 155 |
return true; |
| 156 |
} |
| 157 |
if (requiredDimensionSymbol == Dimension.SYM_P && actualDimensionValue == Dimension.P) { |
| 158 |
return true; |
| 159 |
} |
| 160 |
if (requiredDimensionSymbol == Dimension.SYM_L && actualDimensionValue == Dimension.L) { |
| 161 |
return true; |
| 162 |
} |
| 163 |
if (requiredDimensionSymbol == Dimension.SYM_A && actualDimensionValue == Dimension.A) { |
| 164 |
return true; |
| 165 |
} |
| 166 |
return false; |
| 167 |
} |
| 168 |
|
| 169 |
/** |
| 170 |
* Tests if each of the actual dimension symbols in a matrix string satisfies the |
| 171 |
* corresponding required dimension symbol in a pattern string. |
| 172 |
* |
| 173 |
*@param actualDimensionSymbols nine dimension symbols to validate. |
| 174 |
* Possible values are <code>{T, F, * , 0, 1, 2}</code>. |
| 175 |
*@param requiredDimensionSymbols nine dimension symbols to validate |
| 176 |
* against. Possible values are <code>{T, F, * , 0, 1, 2}</code>. |
| 177 |
*@return true if each of the required dimension |
| 178 |
* symbols encompass the corresponding actual dimension symbol |
| 179 |
*/ |
| 180 |
public static boolean matches(String actualDimensionSymbols, String requiredDimensionSymbols) { |
| 181 |
IntersectionMatrix m = new IntersectionMatrix(actualDimensionSymbols); |
| 182 |
return m.matches(requiredDimensionSymbols); |
| 183 |
} |
| 184 |
|
| 185 |
/** |
| 186 |
* Changes the value of one of this <code>IntersectionMatrix</code>s |
| 187 |
* elements. |
| 188 |
* |
| 189 |
*@param row the row of this <code>IntersectionMatrix</code>, |
| 190 |
* indicating the interior, boundary or exterior of the first <code>Geometry</code> |
| 191 |
*@param column the column of this <code>IntersectionMatrix</code>, |
| 192 |
* indicating the interior, boundary or exterior of the second <code>Geometry</code> |
| 193 |
*@param dimensionValue the new value of the element |
| 194 |
*/ |
| 195 |
public void set(int row, int column, int dimensionValue) { |
| 196 |
matrix[row][column] = dimensionValue; |
| 197 |
} |
| 198 |
|
| 199 |
/** |
| 200 |
* Changes the elements of this <code>IntersectionMatrix</code> to the |
| 201 |
* dimension symbols in <code>dimensionSymbols</code>. |
| 202 |
* |
| 203 |
*@param dimensionSymbols nine dimension symbols to which to set this <code>IntersectionMatrix</code> |
| 204 |
* s elements. Possible values are <code>{T, F, * , 0, 1, 2}</code> |
| 205 |
*/ |
| 206 |
public void set(String dimensionSymbols) { |
| 207 |
for (int i = 0; i < dimensionSymbols.length(); i++) { |
| 208 |
int row = i / 3; |
| 209 |
int col = i % 3; |
| 210 |
matrix[row][col] = Dimension.toDimensionValue(dimensionSymbols.charAt(i)); |
| 211 |
} |
| 212 |
} |
| 213 |
|
| 214 |
/** |
| 215 |
* Changes the specified element to <code>minimumDimensionValue</code> if the |
| 216 |
* element is less. |
| 217 |
* |
| 218 |
*@param row the row of this <code>IntersectionMatrix</code> |
| 219 |
* , indicating the interior, boundary or exterior of the first <code>Geometry</code> |
| 220 |
*@param column the column of this <code>IntersectionMatrix</code> |
| 221 |
* , indicating the interior, boundary or exterior of the second <code>Geometry</code> |
| 222 |
*@param minimumDimensionValue the dimension value with which to compare the |
| 223 |
* element. The order of dimension values from least to greatest is |
| 224 |
* <code>{DONTCARE, TRUE, FALSE, 0, 1, 2}</code>. |
| 225 |
*/ |
| 226 |
public void setAtLeast(int row, int column, int minimumDimensionValue) { |
| 227 |
if (matrix[row][column] < minimumDimensionValue) { |
| 228 |
matrix[row][column] = minimumDimensionValue; |
| 229 |
} |
| 230 |
} |
| 231 |
|
| 232 |
/** |
| 233 |
* If row >= 0 and column >= 0, changes the specified element to <code>minimumDimensionValue</code> |
| 234 |
* if the element is less. Does nothing if row <0 or column < 0. |
| 235 |
* |
| 236 |
*@param row the row of this <code>IntersectionMatrix</code> |
| 237 |
* , indicating the interior, boundary or exterior of the first <code>Geometry</code> |
| 238 |
*@param column the column of this <code>IntersectionMatrix</code> |
| 239 |
* , indicating the interior, boundary or exterior of the second <code>Geometry</code> |
| 240 |
*@param minimumDimensionValue the dimension value with which to compare the |
| 241 |
* element. The order of dimension values from least to greatest is |
| 242 |
* <code>{DONTCARE, TRUE, FALSE, 0, 1, 2}</code>. |
| 243 |
*/ |
| 244 |
public void setAtLeastIfValid(int row, int column, int minimumDimensionValue) { |
| 245 |
if (row >= 0 && column >= 0) { |
| 246 |
setAtLeast(row, column, minimumDimensionValue); |
| 247 |
} |
| 248 |
} |
| 249 |
|
| 250 |
/** |
| 251 |
* For each element in this <code>IntersectionMatrix</code>, changes the |
| 252 |
* element to the corresponding minimum dimension symbol if the element is |
| 253 |
* less. |
| 254 |
* |
| 255 |
*@param minimumDimensionSymbols nine dimension symbols with which to |
| 256 |
* compare the elements of this <code>IntersectionMatrix</code>. The |
| 257 |
* order of dimension values from least to greatest is <code>{DONTCARE, TRUE, FALSE, 0, 1, 2}</code> |
| 258 |
* . |
| 259 |
*/ |
| 260 |
public void setAtLeast(String minimumDimensionSymbols) { |
| 261 |
for (int i = 0; i < minimumDimensionSymbols.length(); i++) { |
| 262 |
int row = i / 3; |
| 263 |
int col = i % 3; |
| 264 |
setAtLeast(row, col, Dimension.toDimensionValue(minimumDimensionSymbols.charAt(i))); |
| 265 |
} |
| 266 |
} |
| 267 |
|
| 268 |
/** |
| 269 |
* Changes the elements of this <code>IntersectionMatrix</code> to <code>dimensionValue</code> |
| 270 |
* . |
| 271 |
* |
| 272 |
*@param dimensionValue the dimension value to which to set this <code>IntersectionMatrix</code> |
| 273 |
* s elements. Possible values <code>{TRUE, FALSE, DONTCARE, 0, 1, 2}</code> |
| 274 |
* . |
| 275 |
*/ |
| 276 |
public void setAll(int dimensionValue) { |
| 277 |
for (int ai = 0; ai < 3; ai++) { |
| 278 |
for (int bi = 0; bi < 3; bi++) { |
| 279 |
matrix[ai][bi] = dimensionValue; |
| 280 |
} |
| 281 |
} |
| 282 |
} |
| 283 |
|
| 284 |
/** |
| 285 |
* Returns the value of one of this matrix |
| 286 |
* entries. |
| 287 |
* The value of the provided index is one of the |
| 288 |
* values from the {@link Location} class. |
| 289 |
* The value returned is a constant |
| 290 |
* from the {@link Dimension} class. |
| 291 |
* |
| 292 |
*@param row the row of this <code>IntersectionMatrix</code>, indicating |
| 293 |
* the interior, boundary or exterior of the first <code>Geometry</code> |
| 294 |
*@param column the column of this <code>IntersectionMatrix</code>, |
| 295 |
* indicating the interior, boundary or exterior of the second <code>Geometry</code> |
| 296 |
*@return the dimension value at the given matrix position. |
| 297 |
*/ |
| 298 |
public int get(int row, int column) { |
| 299 |
return matrix[row][column]; |
| 300 |
} |
| 301 |
|
| 302 |
/** |
| 303 |
* Tests if this matrix matches <code>[FF*FF****]</code>. |
| 304 |
* |
| 305 |
*@return <code>true</code> if the two <code>Geometry</code>s related by |
| 306 |
* this matrix are disjoint |
| 307 |
*/ |
| 308 |
public boolean isDisjoint() { |
| 309 |
return |
| 310 |
matrix[Location.INTERIOR][Location.INTERIOR] == Dimension.FALSE && |
| 311 |
matrix[Location.INTERIOR][Location.BOUNDARY] == Dimension.FALSE && |
| 312 |
matrix[Location.BOUNDARY][Location.INTERIOR] == Dimension.FALSE && |
| 313 |
matrix[Location.BOUNDARY][Location.BOUNDARY] == Dimension.FALSE; |
| 314 |
} |
| 315 |
|
| 316 |
/** |
| 317 |
* Tests if <code>isDisjoint</code> returns false. |
| 318 |
* |
| 319 |
*@return <code>true</code> if the two <code>Geometry</code>s related by |
| 320 |
* this matrix intersect |
| 321 |
*/ |
| 322 |
public boolean isIntersects() { |
| 323 |
return ! isDisjoint(); |
| 324 |
} |
| 325 |
|
| 326 |
/** |
| 327 |
* Tests if this matrix matches |
| 328 |
* <code>[FT*******]</code>, <code>[F**T*****]</code> or <code>[F***T****]</code>. |
| 329 |
* |
| 330 |
*@param dimensionOfGeometryA the dimension of the first <code>Geometry</code> |
| 331 |
*@param dimensionOfGeometryB the dimension of the second <code>Geometry</code> |
| 332 |
*@return <code>true</code> if the two <code>Geometry</code> |
| 333 |
* s related by this matrix touch; Returns false |
| 334 |
* if both <code>Geometry</code>s are points. |
| 335 |
*/ |
| 336 |
public boolean isTouches(int dimensionOfGeometryA, int dimensionOfGeometryB) { |
| 337 |
if (dimensionOfGeometryA > dimensionOfGeometryB) { |
| 338 |
|
| 339 |
return isTouches(dimensionOfGeometryB, dimensionOfGeometryA); |
| 340 |
} |
| 341 |
if ((dimensionOfGeometryA == Dimension.A && dimensionOfGeometryB == Dimension.A) || |
| 342 |
(dimensionOfGeometryA == Dimension.L && dimensionOfGeometryB == Dimension.L) || |
| 343 |
(dimensionOfGeometryA == Dimension.L && dimensionOfGeometryB == Dimension.A) || |
| 344 |
(dimensionOfGeometryA == Dimension.P && dimensionOfGeometryB == Dimension.A) || |
| 345 |
(dimensionOfGeometryA == Dimension.P && dimensionOfGeometryB == Dimension.L)) { |
| 346 |
return matrix[Location.INTERIOR][Location.INTERIOR] == Dimension.FALSE && |
| 347 |
(isTrue(matrix[Location.INTERIOR][Location.BOUNDARY]) |
| 348 |
|| isTrue(matrix[Location.BOUNDARY][Location.INTERIOR]) |
| 349 |
|| isTrue(matrix[Location.BOUNDARY][Location.BOUNDARY])); |
| 350 |
} |
| 351 |
return false; |
| 352 |
} |
| 353 |
|
| 354 |
/** |
| 355 |
* Tests whether this geometry crosses the |
| 356 |
* specified geometry. |
| 357 |
* <p> |
| 358 |
* The <code>crosses</code> predicate has the following equivalent definitions: |
| 359 |
* <ul> |
| 360 |
* <li>The geometries have some but not all interior points in common. |
| 361 |
* <li>The DE-9IM Intersection Matrix for the two geometries matches |
| 362 |
* <ul> |
| 363 |
* <li><code>[T*T******]</code> (for P/L, P/A, and L/A situations) |
| 364 |
* <li><code>[T*****T**]</code> (for L/P, L/A, and A/L situations) |
| 365 |
* <li><code>[0********]</code> (for L/L situations) |
| 366 |
* </ul> |
| 367 |
* </ul> |
| 368 |
* For any other combination of dimensions this predicate returns <code>false</code>. |
| 369 |
* <p> |
| 370 |
* The SFS defined this predicate only for P/L, P/A, L/L, and L/A situations. |
| 371 |
* JTS extends the definition to apply to L/P, A/P and A/L situations as well. |
| 372 |
* This makes the relation symmetric. |
| 373 |
* |
| 374 |
*@param dimensionOfGeometryA the dimension of the first <code>Geometry</code> |
| 375 |
*@param dimensionOfGeometryB the dimension of the second <code>Geometry</code> |
| 376 |
*@return <code>true</code> if the two <code>Geometry</code>s |
| 377 |
* related by this matrix cross. |
| 378 |
*/ |
| 379 |
public boolean isCrosses(int dimensionOfGeometryA, int dimensionOfGeometryB) { |
| 380 |
if ((dimensionOfGeometryA == Dimension.P && dimensionOfGeometryB == Dimension.L) || |
| 381 |
(dimensionOfGeometryA == Dimension.P && dimensionOfGeometryB == Dimension.A) || |
| 382 |
(dimensionOfGeometryA == Dimension.L && dimensionOfGeometryB == Dimension.A)) { |
| 383 |
return isTrue(matrix[Location.INTERIOR][Location.INTERIOR]) && |
| 384 |
isTrue(matrix[Location.INTERIOR][Location.EXTERIOR]); |
| 385 |
} |
| 386 |
if ((dimensionOfGeometryA == Dimension.L && dimensionOfGeometryB == Dimension.P) || |
| 387 |
(dimensionOfGeometryA == Dimension.A && dimensionOfGeometryB == Dimension.P) || |
| 388 |
(dimensionOfGeometryA == Dimension.A && dimensionOfGeometryB == Dimension.L)) { |
| 389 |
return isTrue(matrix[Location.INTERIOR][Location.INTERIOR]) && |
| 390 |
isTrue(matrix[Location.EXTERIOR][Location.INTERIOR]); |
| 391 |
} |
| 392 |
if (dimensionOfGeometryA == Dimension.L && dimensionOfGeometryB == Dimension.L) { |
| 393 |
return matrix[Location.INTERIOR][Location.INTERIOR] == 0; |
| 394 |
} |
| 395 |
return false; |
| 396 |
} |
| 397 |
|
| 398 |
/** |
| 399 |
* Tests whether this matrix matches <code>[T*F**F***]</code>. |
| 400 |
* |
| 401 |
*@return <code>true</code> if the first <code>Geometry</code> is within |
| 402 |
* the second |
| 403 |
*/ |
| 404 |
public boolean isWithin() { |
| 405 |
return isTrue(matrix[Location.INTERIOR][Location.INTERIOR]) && |
| 406 |
matrix[Location.INTERIOR][Location.EXTERIOR] == Dimension.FALSE && |
| 407 |
matrix[Location.BOUNDARY][Location.EXTERIOR] == Dimension.FALSE; |
| 408 |
} |
| 409 |
|
| 410 |
/** |
| 411 |
* Tests whether this matrix matches [T*****FF*[. |
| 412 |
* |
| 413 |
*@return <code>true</code> if the first <code>Geometry</code> contains the |
| 414 |
* second |
| 415 |
*/ |
| 416 |
public boolean isContains() { |
| 417 |
return isTrue(matrix[Location.INTERIOR][Location.INTERIOR]) && |
| 418 |
matrix[Location.EXTERIOR][Location.INTERIOR] == Dimension.FALSE && |
| 419 |
matrix[Location.EXTERIOR][Location.BOUNDARY] == Dimension.FALSE; |
| 420 |
} |
| 421 |
|
| 422 |
/** |
| 423 |
* Tests if this matrix matches |
| 424 |
* <code>[T*****FF*]</code> |
| 425 |
* or <code>[*T****FF*]</code> |
| 426 |
* or <code>[***T**FF*]</code> |
| 427 |
* or <code>[****T*FF*]</code> |
| 428 |
* |
| 429 |
*@return <code>true</code> if the first <code>Geometry</code> covers the |
| 430 |
* second |
| 431 |
*/ |
| 432 |
public boolean isCovers() { |
| 433 |
boolean hasPointInCommon = |
| 434 |
isTrue(matrix[Location.INTERIOR][Location.INTERIOR]) |
| 435 |
|| isTrue(matrix[Location.INTERIOR][Location.BOUNDARY]) |
| 436 |
|| isTrue(matrix[Location.BOUNDARY][Location.INTERIOR]) |
| 437 |
|| isTrue(matrix[Location.BOUNDARY][Location.BOUNDARY]); |
| 438 |
|
| 439 |
return hasPointInCommon && |
| 440 |
matrix[Location.EXTERIOR][Location.INTERIOR] == Dimension.FALSE && |
| 441 |
matrix[Location.EXTERIOR][Location.BOUNDARY] == Dimension.FALSE; |
| 442 |
} |
| 443 |
|
| 444 |
/** |
| 445 |
*Tests if this matrix matches |
| 446 |
* <code>[T*F**F***]</code> |
| 447 |
* or <code>[*TF**F***]</code> |
| 448 |
* or <code>[**FT*F***]</code> |
| 449 |
* or <code>[**F*TF***]</code> |
| 450 |
* |
| 451 |
*@return <code>true</code> if the first <code>Geometry</code> |
| 452 |
* is covered by the second |
| 453 |
*/ |
| 454 |
public boolean isCoveredBy() { |
| 455 |
boolean hasPointInCommon = |
| 456 |
isTrue(matrix[Location.INTERIOR][Location.INTERIOR]) |
| 457 |
|| isTrue(matrix[Location.INTERIOR][Location.BOUNDARY]) |
| 458 |
|| isTrue(matrix[Location.BOUNDARY][Location.INTERIOR]) |
| 459 |
|| isTrue(matrix[Location.BOUNDARY][Location.BOUNDARY]); |
| 460 |
|
| 461 |
return hasPointInCommon && |
| 462 |
matrix[Location.INTERIOR][Location.EXTERIOR] == Dimension.FALSE && |
| 463 |
matrix[Location.BOUNDARY][Location.EXTERIOR] == Dimension.FALSE; |
| 464 |
} |
| 465 |
|
| 466 |
/** |
| 467 |
* Tests whether the argument dimensions are equal and |
| 468 |
* this matrix matches the pattern <tt>[T*F**FFF*]</tt>. |
| 469 |
* <p> |
| 470 |
* <b>Note:</b> This pattern differs from the one stated in |
| 471 |
* <i>Simple feature access - Part 1: Common architecture</i>. |
| 472 |
* That document states the pattern as <tt>[TFFFTFFFT]</tt>. This would |
| 473 |
* specify that |
| 474 |
* two identical <tt>POINT</tt>s are not equal, which is not desirable behaviour. |
| 475 |
* The pattern used here has been corrected to compute equality in this situation. |
| 476 |
* |
| 477 |
*@param dimensionOfGeometryA the dimension of the first <code>Geometry</code> |
| 478 |
*@param dimensionOfGeometryB the dimension of the second <code>Geometry</code> |
| 479 |
*@return <code>true</code> if the two <code>Geometry</code>s |
| 480 |
* related by this matrix are equal; the |
| 481 |
* <code>Geometry</code>s must have the same dimension to be equal |
| 482 |
*/ |
| 483 |
public boolean isEquals(int dimensionOfGeometryA, int dimensionOfGeometryB) { |
| 484 |
if (dimensionOfGeometryA != dimensionOfGeometryB) { |
| 485 |
return false; |
| 486 |
} |
| 487 |
return isTrue(matrix[Location.INTERIOR][Location.INTERIOR]) && |
| 488 |
matrix[Location.INTERIOR][Location.EXTERIOR] == Dimension.FALSE && |
| 489 |
matrix[Location.BOUNDARY][Location.EXTERIOR] == Dimension.FALSE && |
| 490 |
matrix[Location.EXTERIOR][Location.INTERIOR] == Dimension.FALSE && |
| 491 |
matrix[Location.EXTERIOR][Location.BOUNDARY] == Dimension.FALSE; |
| 492 |
} |
| 493 |
|
| 494 |
/** |
| 495 |
* Tests if this matrix matches |
| 496 |
* <UL> |
| 497 |
* <LI><tt>[T*T***T**]</tt> (for two points or two surfaces) |
| 498 |
* <LI><tt>[1*T***T**]</tt> (for two curves) |
| 499 |
* </UL>. |
| 500 |
* |
| 501 |
*@param dimensionOfGeometryA the dimension of the first <code>Geometry</code> |
| 502 |
*@param dimensionOfGeometryB the dimension of the second <code>Geometry</code> |
| 503 |
*@return <code>true</code> if the two <code>Geometry</code>s |
| 504 |
* related by this matrix overlap. For this |
| 505 |
* function to return <code>true</code>, the <code>Geometry</code>s must |
| 506 |
* be two points, two curves or two surfaces. |
| 507 |
*/ |
| 508 |
public boolean isOverlaps(int dimensionOfGeometryA, int dimensionOfGeometryB) { |
| 509 |
if ((dimensionOfGeometryA == Dimension.P && dimensionOfGeometryB == Dimension.P) || |
| 510 |
(dimensionOfGeometryA == Dimension.A && dimensionOfGeometryB == Dimension.A)) { |
| 511 |
return isTrue(matrix[Location.INTERIOR][Location.INTERIOR]) |
| 512 |
&& isTrue(matrix[Location.INTERIOR][Location.EXTERIOR]) |
| 513 |
&& isTrue(matrix[Location.EXTERIOR][Location.INTERIOR]); |
| 514 |
} |
| 515 |
if (dimensionOfGeometryA == Dimension.L && dimensionOfGeometryB == Dimension.L) { |
| 516 |
return matrix[Location.INTERIOR][Location.INTERIOR] == 1 |
| 517 |
&& isTrue(matrix[Location.INTERIOR][Location.EXTERIOR]) |
| 518 |
&& isTrue(matrix[Location.EXTERIOR][Location.INTERIOR]); |
| 519 |
} |
| 520 |
return false; |
| 521 |
} |
| 522 |
|
| 523 |
/** |
| 524 |
* Tests whether this matrix matches the given matrix pattern. |
| 525 |
* |
| 526 |
*@param pattern A pattern containing nine dimension symbols with which to |
| 527 |
* compare the entries of this matrix. Possible |
| 528 |
* symbol values are <code>{T, F, * , 0, 1, 2}</code>. |
| 529 |
*@return <code>true</code> if this matrix matches the pattern |
| 530 |
*/ |
| 531 |
public boolean matches(String pattern) { |
| 532 |
if (pattern.length() != 9) { |
| 533 |
throw new IllegalArgumentException("Should be length 9: " + pattern); |
| 534 |
} |
| 535 |
for (int ai = 0; ai < 3; ai++) { |
| 536 |
for (int bi = 0; bi < 3; bi++) { |
| 537 |
if (!matches(matrix[ai][bi], pattern.charAt(3 * ai + |
| 538 |
bi))) { |
| 539 |
return false; |
| 540 |
} |
| 541 |
} |
| 542 |
} |
| 543 |
return true; |
| 544 |
} |
| 545 |
|
| 546 |
/** |
| 547 |
* Transposes this IntersectionMatrix. |
| 548 |
* |
| 549 |
*@return this <code>IntersectionMatrix</code> as a convenience |
| 550 |
*/ |
| 551 |
public IntersectionMatrix transpose() { |
| 552 |
int temp = matrix[1][0]; |
| 553 |
matrix[1][0] = matrix[0][1]; |
| 554 |
matrix[0][1] = temp; |
| 555 |
temp = matrix[2][0]; |
| 556 |
matrix[2][0] = matrix[0][2]; |
| 557 |
matrix[0][2] = temp; |
| 558 |
temp = matrix[2][1]; |
| 559 |
matrix[2][1] = matrix[1][2]; |
| 560 |
matrix[1][2] = temp; |
| 561 |
return this; |
| 562 |
} |
| 563 |
|
| 564 |
/** |
| 565 |
* Returns a nine-character <code>String</code> representation of this <code>IntersectionMatrix</code> |
| 566 |
* . |
| 567 |
* |
| 568 |
*@return the nine dimension symbols of this <code>IntersectionMatrix</code> |
| 569 |
* in row-major order. |
| 570 |
*/ |
| 571 |
public String toString() { |
| 572 |
StringBuilder builder = new StringBuilder("123456789"); |
| 573 |
for (int ai = 0; ai < 3; ai++) { |
| 574 |
for (int bi = 0; bi < 3; bi++) { |
| 575 |
builder.setCharAt(3 * ai + bi, Dimension.toDimensionSymbol(matrix[ai][bi])); |
| 576 |
} |
| 577 |
} |
| 578 |
return builder.toString(); |
| 579 |
} |
| 580 |
} |
| 581 |
|
| 582 |
|