GEOS 3.14.0dev
RelatePredicate.h
1/**********************************************************************
2 *
3 * GEOS - Geometry Engine Open Source
4 * http://geos.osgeo.org
5 *
6 * Copyright (c) 2024 Martin Davis
7 * Copyright (C) 2024 Paul Ramsey <pramsey@cleverelephant.ca>
8 *
9 * This is free software; you can redistribute and/or modify it under
10 * the terms of the GNU Lesser General Public Licence as published
11 * by the Free Software Foundation.
12 * See the COPYING file for more information.
13 *
14 **********************************************************************/
15
16#pragma once
17
18#include <geos/geom/Location.h>
19#include <geos/operation/relateng/BasicPredicate.h>
20#include <geos/operation/relateng/IMPatternMatcher.h>
21#include <geos/operation/relateng/IMPredicate.h>
22#include <geos/operation/relateng/RelateGeometry.h>
23#include <geos/geom/Envelope.h>
24#include <geos/export.h>
25
26namespace geos { // geos.
27namespace operation { // geos.operation.
28namespace relateng { // geos.operation.relateng
29
30
31class GEOS_DLL RelatePredicate {
32 using Envelope = geos::geom::Envelope;
34
35public:
36
37/************************************************************************
38 *
39 * Creates a predicate to determine whether two geometries intersect.
40 *
41 * The intersects predicate has the following equivalent definitions:
42 *
43 * * The two geometries have at least one point in common
44 * * The DE-9IM Intersection Matrix for the two geometries matches
45 * at least one of the patterns
46 *
47 * [T********]
48 * [*T*******]
49 * [***T*****]
50 * [****T****]
51 *
52 * disjoint() = false
53 * (intersects is the inverse of disjoint)
54 *
55 * @return the predicate instance
56 *
57 * @see disjoint()
58 */
59class IntersectsPredicate : public BasicPredicate {
60
61public:
62
63 std::string name() const override {
64 return std::string("intersects");
65 }
66
67 bool requireSelfNoding() const override {
68 //-- self-noding is not required to check for a simple interaction
69 return false;
70 }
71
72 bool requireExteriorCheck(bool isSourceA) const override {
73 (void)isSourceA;
74 //-- intersects only requires testing interaction
75 return false;
76 }
77
78 void init(const Envelope& envA, const Envelope& envB) override {
79 require(envA.intersects(envB));
80 }
81
82 void updateDimension(Location locA, Location locB, int dimension) override {
83 (void)dimension;
84 setValueIf(true, isIntersection(locA, locB));
85 }
86
87 void finish() override {
88 //-- if no intersecting locations were found
89 setValue(false);
90 }
91
92};
93
94static std::unique_ptr<BasicPredicate> intersects();
95
96/************************************************************************
97 *
98 * Creates a predicate to determine whether two geometries are disjoint.
99 *
100 * The disjoint predicate has the following equivalent definitions:
101 *
102 * * The two geometries have no point in common
103 * * The DE-9IM Intersection Matrix for the two geometries matches
104 * [FF*FF****]
105 * * intersects() = false
106 * (disjoint is the inverse of intersects)
107 *
108 * @return the predicate instance
109 *
110 * @see intersects()
111 */
112class DisjointPredicate : public BasicPredicate {
113
114 std::string name() const override {
115 return std::string("disjoint");
116 }
117
118 bool requireSelfNoding() const override {
119 //-- self-noding is not required to check for a simple interaction
120 return false;
121 }
122
123 bool requireInteraction() const override {
124 //-- ensure entire matrix is computed
125 return false;
126 }
127
128 bool requireExteriorCheck(bool isSourceA) const override {
129 (void)isSourceA;
130 //-- intersects only requires testing interaction
131 return false;
132 }
133
134 void init(const Envelope& envA, const Envelope& envB) override {
135 setValueIf(true, envA.disjoint(envB));
136 }
137
138 void updateDimension(Location locA, Location locB, int dimension) override {
139 (void)dimension;
140 setValueIf(false, isIntersection(locA, locB));
141 }
142
143 void finish() override {
144 //-- if no intersecting locations were found
145 setValue(true);
146 }
147};
148
149static std::unique_ptr<BasicPredicate> disjoint();
150
151/************************************************************************
152 * Creates a predicate to determine whether a geometry contains another geometry.
153 *
154 * The contains predicate has the following equivalent definitions:
155 *
156 * * Every point of the other geometry is a point of this geometry,
157 * and the interiors of the two geometries have at least one point in common.
158 * * The DE-9IM Intersection Matrix for the two geometries matches
159 * the pattern
160 * [T*****FF*]
161 * * within(B, A) = true
162 * (contains is the converse of within)
163 *
164 * An implication of the definition is that "Geometries do not
165 * contain their boundary". In other words, if a geometry A is a subset of
166 * the points in the boundary of a geometry B, B.contains(A) = false.
167 * (As a concrete example, take A to be a LineString which lies in the boundary of a Polygon B.)
168 * For a predicate with similar behavior but avoiding
169 * this subtle limitation, see covers().
170 *
171 * @return the predicate instance
172 *
173 * @see within()
174 */
175class ContainsPredicate : public IMPredicate {
176
177 std::string name() const override {
178 return std::string("contains");
179 }
180
181 bool requireCovers(bool isSourceA) override {
182 return isSourceA == RelateGeometry::GEOM_A;
183 }
184
185 bool requireExteriorCheck(bool isSourceA) const override {
186 //-- only need to check B against Exterior of A
187 return isSourceA == RelateGeometry::GEOM_B;
188 }
189
190 void init(int _dimA, int _dimB) override {
191 IMPredicate::init(_dimA, _dimB);
192 require(isDimsCompatibleWithCovers(dimA, dimB));
193 }
194
195 void init(const Envelope& envA, const Envelope& envB) override {
196 BasicPredicate::requireCovers(envA, envB);
197 }
198
199 bool isDetermined() const override {
200 return intersectsExteriorOf(RelateGeometry::GEOM_A);
201 }
202
203 bool valueIM() override {
204 return intMatrix.isContains();
205 }
206};
207
208static std::unique_ptr<IMPredicate> contains();
209
210
211
212/************************************************************************
213 * Creates a predicate to determine whether a geometry is within another geometry.
214 *
215 * The within predicate has the following equivalent definitions:
216 *
217 * * Every point of this geometry is a point of the other geometry,
218 * and the interiors of the two geometries have at least one point in common.
219 * * The DE-9IM Intersection Matrix for the two geometries matches
220 * [T*F**F***]
221 * * contains(B, A) = true
222 * (within is the converse of contains())
223 *
224 * An implication of the definition is that
225 * "The boundary of a Geometry is not within the Geometry".
226 * In other words, if a geometry A is a subset of
227 * the points in the boundary of a geometry B, within(B, A) = false
228 * (As a concrete example, take A to be a LineString which lies in the boundary of a Polygon B.)
229 * For a predicate with similar behavior but avoiding
230 * this subtle limitation, see coveredimBy().
231 *
232 * @return the predicate instance
233 *
234 * @see #contains()
235 */
236class WithinPredicate : public IMPredicate {
237
238 std::string name() const override {
239 return std::string("within");
240 }
241
242 bool requireCovers(bool isSourceA) override {
243 return isSourceA == RelateGeometry::GEOM_B;
244 }
245
246 bool requireExteriorCheck(bool isSourceA) const override {
247 //-- only need to check B against Exterior of A
248 return isSourceA == RelateGeometry::GEOM_A;
249 }
250
251 void init(int _dimA, int _dimB) override {
252 IMPredicate::init(_dimA, _dimB);
253 require(isDimsCompatibleWithCovers(dimB, dimA));
254 }
255
256 void init(const Envelope& envA, const Envelope& envB) override {
257 BasicPredicate::requireCovers(envB, envA);
258 }
259
260 bool isDetermined() const override {
261 return intersectsExteriorOf(RelateGeometry::GEOM_B);
262 }
263
264 bool valueIM() override {
265 return intMatrix.isWithin();
266 }
267};
268
269static std::unique_ptr<IMPredicate> within();
270
271
272
273/************************************************************************
274 * Creates a predicate to determine whether a geometry covers another geometry.
275 *
276 * The covers predicate has the following equivalent definitions:
277 *
278 * Every point of the other geometry is a point of this geometry.
279 * The DE-9IM Intersection Matrix for the two geometries matches
280 * at least one of the following patterns:
281 *
282 * * [T*****FF*]
283 * * [*T****FF*]
284 * * [***T**FF*]
285 * * [****T*FF*]
286 *
287 * coveredimBy(b, a) = true
288 * (covers is the converse of coveredimBy())
289 *
290 * If either geometry is empty, the value of this predicate is false.
291 *
292 * This predicate is similar to contains(),
293 * but is more inclusive (i.e. returns true for more cases).
294 * In particular, unlike contains it does not distinguish between
295 * points in the boundary and in the interior of geometries.
296 * For most cases, covers should be used in preference to contains.
297 * As an added benefit, covers is more amenable to optimization,
298 * and hence should be more performant.
299 *
300 * @return the predicate instance
301 *
302 * @see #coveredimBy()
303 */
304class CoversPredicate : public IMPredicate {
305
306 std::string name() const override {
307 return std::string("covers");
308 }
309
310 bool requireCovers(bool isSourceA) override {
311 return isSourceA == RelateGeometry::GEOM_A;
312 }
313
314 bool requireExteriorCheck(bool isSourceA) const override {
315 //-- only need to check B against Exterior of A
316 return isSourceA == RelateGeometry::GEOM_B;
317 }
318
319 void init(int _dimA, int _dimB) override {
320 IMPredicate::init(_dimA, _dimB);
321 require(isDimsCompatibleWithCovers(dimA, dimB));
322 }
323
324 void init(const Envelope& envA, const Envelope& envB) override {
325 BasicPredicate::requireCovers(envA, envB);
326
327 }
328
329 bool isDetermined() const override {
330 return intersectsExteriorOf(RelateGeometry::GEOM_A);
331 }
332
333 bool valueIM() override {
334 return intMatrix.isCovers();
335 }
336};
337
338static std::unique_ptr<IMPredicate> covers();
339
340
341/************************************************************************
342* Creates a predicate to determine whether a geometry is covered
343* by another geometry.
344*
345* The coveredimBy predicate has the following equivalent definitions:
346*
347* Every point of this geometry is a point of the other geometry.
348* The DE-9IM Intersection Matrix for the two geometries matches
349* at least one of the following patterns:
350*
351* [T*F**F***]
352* [*TF**F***]
353* [**FT*F***]
354* [**F*TF***]
355*
356* covers(B, A) = true
357* (coveredimBy is the converse of covers())
358*
359* If either geometry is empty, the value of this predicate is false.
360*
361* This predicate is similar to within(),
362* but is more inclusive (i.e. returns true for more cases).
363*
364* @return the predicate instance
365*
366* @see #covers()
367*/
368class CoveredByPredicate : public IMPredicate {
369
370 std::string name() const override {
371 return std::string("coveredBy");
372 }
373
374 bool requireCovers(bool isSourceA) override {
375 return isSourceA == RelateGeometry::GEOM_B;
376 }
377
378 bool requireExteriorCheck(bool isSourceA) const override {
379 //-- only need to check B against Exterior of A
380 return isSourceA == RelateGeometry::GEOM_A;
381 }
382
383 void init(int _dimA, int _dimB) override {
384 IMPredicate::init(_dimA, _dimB);
385 require(isDimsCompatibleWithCovers(dimB, dimA));
386 }
387
388 void init(const Envelope& envA, const Envelope& envB) override {
389 BasicPredicate::requireCovers(envB, envA);
390 }
391
392 bool isDetermined() const override {
393 return intersectsExteriorOf(RelateGeometry::GEOM_B);
394 }
395
396 bool valueIM() override {
397 return intMatrix.isCoveredBy();
398 }
399
400};
401
402static std::unique_ptr<IMPredicate> coveredBy();
403
404
405/************************************************************************
406* Creates a predicate to determine whether a geometry crosses another geometry.
407*
408* The crosses predicate has the following equivalent definitions:
409*
410* The geometries have some but not all interior points in common.
411* The DE-9IM Intersection Matrix for the two geometries matches
412* one of the following patterns:
413*
414* [T*T******] (for P/L, P/A, and L/A cases)
415* [T*****T**] (for L/P, A/P, and A/L cases)
416* [0********] (for L/L cases)
417*
418*
419* For the A/A and P/P cases this predicate returns false.
420*
421* The SFS defined this predicate only for P/L, P/A, L/L, and L/A cases.
422* To make the relation symmetric
423* JTS extends the definition to apply to L/P, A/P and A/L cases as well.
424*
425* @return the predicate instance
426*/
427
428class CrossesPredicate : public IMPredicate {
429
430 std::string name() const override {
431 return std::string("crosses");
432 }
433
434 void init(int _dimA, int _dimB) override {
435 IMPredicate::init(_dimA, _dimB);
436 bool isBothPointsOrAreas =
437 (dimA == Dimension::P && dimB == Dimension::P) ||
438 (dimA == Dimension::A && dimB == Dimension::A);
439 require(!isBothPointsOrAreas);
440 }
441
442 bool isDetermined() const override {
443 if (dimA == Dimension::L && dimB == Dimension::L) {
444 //-- L/L interaction can only be dim = P
445 if (getDimension(Location::INTERIOR, Location::INTERIOR) > Dimension::P)
446 return true;
447 }
448 else if (dimA < dimB) {
449 if (isIntersects(Location::INTERIOR, Location::INTERIOR) &&
450 isIntersects(Location::INTERIOR, Location::EXTERIOR)) {
451 return true;
452 }
453 }
454 else if (dimA > dimB) {
455 if (isIntersects(Location::INTERIOR, Location::INTERIOR) &&
456 isIntersects(Location::EXTERIOR, Location::INTERIOR)) {
457 return true;
458 }
459 }
460 return false;
461 }
462
463 bool valueIM() override {
464 return intMatrix.isCrosses(dimA, dimB);
465 }
466};
467
468static std::unique_ptr<IMPredicate> crosses();
469
470
471/************************************************************************
472* Creates a predicate to determine whether two geometries are
473* topologically equal.
474*
475* The equals predicate has the following equivalent definitions:
476*
477* The two geometries have at least one point in common,
478* and no point of either geometry lies in the exterior of the other geometry.
479* The DE-9IM Intersection Matrix for the two geometries matches
480* the pattern T*F**FFF*
481*
482* @return the predicate instance
483*/
484class EqualsTopoPredicate : public IMPredicate {
485
486 std::string name() const override {
487 return std::string("equals");
488 }
489
490 bool requireInteraction() const override {
491 //-- allow EMPTY = EMPTY
492 return false;
493 };
494
495 void init(int _dimA, int _dimB) override {
496 IMPredicate::init(_dimA, _dimB);
497 //-- don't require equal dims, because EMPTY = EMPTY for all dims
498 }
499
500 void init(const Envelope& envA, const Envelope& envB) override {
501 //-- handle EMPTY = EMPTY cases
502 setValueIf(true, envA.isNull() && envB.isNull());
503
504 require(envA.equals(&envB));
505 }
506
507 bool isDetermined() const override {
508 bool isEitherExteriorIntersects =
509 isIntersects(Location::INTERIOR, Location::EXTERIOR) ||
510 isIntersects(Location::BOUNDARY, Location::EXTERIOR) ||
511 isIntersects(Location::EXTERIOR, Location::INTERIOR) ||
512 isIntersects(Location::EXTERIOR, Location::BOUNDARY);
513
514 return isEitherExteriorIntersects;
515 }
516
517 bool valueIM() override {
518 return intMatrix.isEquals(dimA, dimB);
519 }
520
521};
522
523static std::unique_ptr<IMPredicate> equalsTopo();
524
525
526/************************************************************************
527 * Creates a predicate to determine whether a geometry overlaps another geometry.
528 *
529 * The overlaps predicate has the following equivalent definitions:
530 *
531 * The geometries have at least one point each not shared by the other
532 * (or equivalently neither covers the other),
533 * they have the same dimension,
534 * and the intersection of the interiors of the two geometries has
535 * the same dimension as the geometries themselves.
536 * The DE-9IM Intersection Matrix for the two geometries matches
537 * [T*T***T**] (for P/P and A/A cases)
538 * or [1*T***T**] (for L/L cases)
539 *
540 * If the geometries are of different dimension this predicate returns false.
541 * This predicate is symmetric.
542 *
543 * @return the predicate instance
544 */
545class OverlapsPredicate : public IMPredicate {
546
547 std::string name() const override {
548 return std::string("overlaps");
549 }
550
551 void init(int _dimA, int _dimB) override {
552 IMPredicate::init(_dimA, _dimB);
553 require(dimA == dimB);
554 }
555
556 bool isDetermined() const override {
557 if (dimA == Dimension::A || dimA == Dimension::P) {
558 if (isIntersects(Location::INTERIOR, Location::INTERIOR) &&
559 isIntersects(Location::INTERIOR, Location::EXTERIOR) &&
560 isIntersects(Location::EXTERIOR, Location::INTERIOR))
561 return true;
562 }
563 if (dimA == Dimension::L) {
564 if (isDimension(Location::INTERIOR, Location::INTERIOR, Dimension::L) &&
565 isIntersects(Location::INTERIOR, Location::EXTERIOR) &&
566 isIntersects(Location::EXTERIOR, Location::INTERIOR))
567 return true;
568 }
569 return false;
570 }
571
572 bool valueIM() override {
573 return intMatrix.isOverlaps(dimA, dimB);
574 }
575};
576
577static std::unique_ptr<IMPredicate> overlaps();
578
579
580
581
582
583/************************************************************************
584* Creates a predicate to determine whether a geometry touches another geometry.
585*
586* The touches predicate has the following equivalent definitions:
587*
588* The geometries have at least one point in common,
589* but their interiors do not intersect.
590* The DE-9IM Intersection Matrix for the two geometries matches
591* at least one of the following patterns
592*
593* [FT*******]
594* [F**T*****]
595* [F***T****]
596*
597*
598* If both geometries have dimension 0, the predicate returns false,
599* since points have only interiors.
600* This predicate is symmetric.
601*
602* @return the predicate instance
603*/
604class TouchesPredicate : public IMPredicate {
605
606 std::string name() const override {
607 return std::string("touches");
608 }
609
610 void init(int _dimA, int _dimB) override {
611 IMPredicate::init(_dimA, _dimB);
612 bool isBothPoints = (dimA == 0 && dimB == 0);
613 require(! isBothPoints);
614 }
615
616 bool isDetermined() const override {
617 bool isInteriorsIntersects = isIntersects(Location::INTERIOR, Location::INTERIOR);
618 return isInteriorsIntersects;
619 }
620
621 bool valueIM() override {
622 return intMatrix.isTouches(dimA, dimB);
623 }
624};
625
626static std::unique_ptr<IMPredicate> touches();
627
636static std::unique_ptr<TopologyPredicate> matches(const std::string& imPattern)
637{
638 return std::unique_ptr<TopologyPredicate>(new IMPatternMatcher(imPattern));
639}
640
641
642
643}; // !RelatePredicate
644
645
646} // namespace geos.operation.relateng
647} // namespace geos.operation
648} // namespace geos
649
An Envelope defines a rectangulare region of the 2D coordinate plane.
Definition Envelope.h:59
Location
Constants representing the location of a point relative to a geometry.
Definition Location.h:32
Basic namespace for all GEOS functionalities.
Definition geos.h:39