tg_geometry 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +103 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +21 -0
- data/README.md +385 -0
- data/Rakefile +129 -0
- data/benchmark/_support.rb +115 -0
- data/benchmark/batch_packed_vs_loop.rb +27 -0
- data/benchmark/falcon_concurrency.rb +25 -0
- data/benchmark/flat_vs_rtree.rb +27 -0
- data/benchmark/gvl_threshold.rb +41 -0
- data/benchmark/objectspace_memsize.rb +17 -0
- data/benchmark/parse_throughput.rb +38 -0
- data/benchmark/rss_stability.rb +70 -0
- data/docs/ACTIVE_RECORD.md +26 -0
- data/docs/ARCHITECTURE.md +130 -0
- data/docs/AUTO_STRATEGY.md +15 -0
- data/docs/BENCHMARKING.md +75 -0
- data/docs/CASUAL_EXAMPLE.md +618 -0
- data/docs/CONCURRENCY.md +65 -0
- data/docs/ERROR_HANDLING.md +55 -0
- data/docs/EXPANSION_E_TO_H_STATUS.md +51 -0
- data/docs/FORMAT_COVERAGE.md +23 -0
- data/docs/FULL_TG_API_COVERAGE.md +109 -0
- data/docs/LIMITATIONS.md +61 -0
- data/docs/LOW_LEVEL_GEOMETRY.md +121 -0
- data/docs/MEMORY_OWNERSHIP.md +94 -0
- data/docs/RACTOR.md +40 -0
- data/docs/REGISTRY.md +37 -0
- data/docs/RELEASE_CHECKLIST.md +39 -0
- data/ext/tg_geometry/extconf.rb +91 -0
- data/ext/tg_geometry/tg_geometry_ext.c +3054 -0
- data/ext/tg_geometry/tg_geometry_vendor_rtree.c +1 -0
- data/ext/tg_geometry/tg_geometry_vendor_tg.c +24 -0
- data/ext/tg_geometry/vendor/.vendored +16 -0
- data/ext/tg_geometry/vendor/rtree/LICENSE +20 -0
- data/ext/tg_geometry/vendor/rtree/README.md +202 -0
- data/ext/tg_geometry/vendor/rtree/VERSION +3 -0
- data/ext/tg_geometry/vendor/rtree/rtree.c +840 -0
- data/ext/tg_geometry/vendor/rtree/rtree.h +105 -0
- data/ext/tg_geometry/vendor/tg/LICENSE +19 -0
- data/ext/tg_geometry/vendor/tg/README.md +197 -0
- data/ext/tg_geometry/vendor/tg/VERSION +3 -0
- data/ext/tg_geometry/vendor/tg/tg.c +16010 -0
- data/ext/tg_geometry/vendor/tg/tg.h +359 -0
- data/lib/tg/geometry/active_record_source.rb +57 -0
- data/lib/tg/geometry/registry.rb +119 -0
- data/lib/tg/geometry/version.rb +7 -0
- data/lib/tg/geometry.rb +6 -0
- data/lib/tg_geometry.rb +3 -0
- data/script/vendor_libs.rb +264 -0
- data/spec/block_10_rtree_strategy_spec.rb +82 -0
- data/spec/block_11_rtree_order_spec.rb +53 -0
- data/spec/block_12_batch_packed_spec.rb +55 -0
- data/spec/block_13_error_hardening_spec.rb +65 -0
- data/spec/block_14_memory_gc_hardening_spec.rb +116 -0
- data/spec/block_1_skeleton_spec.rb +45 -0
- data/spec/block_20_concurrency_spec.rb +157 -0
- data/spec/block_20_fuzz_spec.rb +145 -0
- data/spec/block_2_vendor_spec.rb +79 -0
- data/spec/block_3_geom_parse_spec.rb +89 -0
- data/spec/block_4_geom_api_spec.rb +90 -0
- data/spec/block_5_rect_api_spec.rb +96 -0
- data/spec/block_6_index_build_spec.rb +111 -0
- data/spec/block_7_index_owned_geometry_spec.rb +143 -0
- data/spec/block_8_index_borrowed_geometry_spec.rb +106 -0
- data/spec/block_9_flat_query_spec.rb +65 -0
- data/spec/expansion_a_auto_strategy_spec.rb +14 -0
- data/spec/expansion_b_registry_spec.rb +47 -0
- data/spec/expansion_c_active_record_source_spec.rb +42 -0
- data/spec/expansion_d_format_coverage_spec.rb +30 -0
- data/spec/expansion_e_low_level_geometry_spec.rb +82 -0
- data/spec/expansion_i_ractor_spec.rb +25 -0
- data/spec/expansion_j_full_tg_api_coverage_spec.rb +114 -0
- data/spec/spec_helper.rb +15 -0
- metadata +157 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// Copyright 2023 Joshua J Baker. All rights reserved.
|
|
2
|
+
// Use of this source code is governed by an MIT-style
|
|
3
|
+
// license that can be found in the LICENSE file.
|
|
4
|
+
|
|
5
|
+
#ifndef RTREE_H
|
|
6
|
+
#define RTREE_H
|
|
7
|
+
|
|
8
|
+
#include <stdlib.h>
|
|
9
|
+
#include <stdbool.h>
|
|
10
|
+
|
|
11
|
+
// rtree_new returns a new rtree
|
|
12
|
+
//
|
|
13
|
+
// Returns NULL if the system is out of memory.
|
|
14
|
+
struct rtree *rtree_new(void);
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
// rtree_new returns a new rtree using a custom allocator
|
|
18
|
+
//
|
|
19
|
+
// Returns NULL if the system is out of memory.
|
|
20
|
+
struct rtree *rtree_new_with_allocator(void *(*malloc)(size_t), void (*free)(void*));
|
|
21
|
+
|
|
22
|
+
// rtree_free frees an rtree
|
|
23
|
+
void rtree_free(struct rtree *tr);
|
|
24
|
+
|
|
25
|
+
// rtree_clone makes an instant copy of the btree.
|
|
26
|
+
//
|
|
27
|
+
// This operation uses shadowing / copy-on-write.
|
|
28
|
+
struct rtree *rtree_clone(struct rtree *tr);
|
|
29
|
+
|
|
30
|
+
// rtree_set_item_callbacks sets the item clone and free callbacks that will be
|
|
31
|
+
// called internally by the rtree when items are inserted and removed.
|
|
32
|
+
//
|
|
33
|
+
// These callbacks are optional but may be needed by programs that require
|
|
34
|
+
// copy-on-write support by using the rtree_clone function.
|
|
35
|
+
//
|
|
36
|
+
// The clone function should return true if the clone succeeded or false if the
|
|
37
|
+
// system is out of memory.
|
|
38
|
+
void rtree_set_item_callbacks(struct rtree *tr,
|
|
39
|
+
bool (*clone)(const void *item, void **into, void *udata),
|
|
40
|
+
void (*free)(const void *item, void *udata));
|
|
41
|
+
|
|
42
|
+
// rtree_set_udata sets the user-defined data.
|
|
43
|
+
//
|
|
44
|
+
// This should be called once after rtree_new() and is only used for
|
|
45
|
+
// the item callbacks as defined in rtree_set_item_callbacks().
|
|
46
|
+
void rtree_set_udata(struct rtree *tr, void *udata);
|
|
47
|
+
|
|
48
|
+
// rtree_insert inserts an item into the rtree.
|
|
49
|
+
//
|
|
50
|
+
// This operation performs a copy of the data that is pointed to in the second
|
|
51
|
+
// and third arguments. The R-tree expects a rectangle, which is two arrays of
|
|
52
|
+
// doubles. The first N values as the minimum corner of the rect, and the next
|
|
53
|
+
// N values as the maximum corner of the rect, where N is the number of
|
|
54
|
+
// dimensions.
|
|
55
|
+
//
|
|
56
|
+
// When inserting points, the max coordinates is optional (set to NULL).
|
|
57
|
+
//
|
|
58
|
+
// Returns false if the system is out of memory.
|
|
59
|
+
bool rtree_insert(struct rtree *tr, const double *min, const double *max, const void *data);
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
// rtree_search searches the rtree and iterates over each item that intersect
|
|
63
|
+
// the provided rectangle.
|
|
64
|
+
//
|
|
65
|
+
// Returning false from the iter will stop the search.
|
|
66
|
+
void rtree_search(const struct rtree *tr, const double *min, const double *max,
|
|
67
|
+
bool (*iter)(const double *min, const double *max, const void *data, void *udata),
|
|
68
|
+
void *udata);
|
|
69
|
+
|
|
70
|
+
// rtree_scan iterates over every item in the rtree.
|
|
71
|
+
//
|
|
72
|
+
// Returning false from the iter will stop the scan.
|
|
73
|
+
void rtree_scan(const struct rtree *tr,
|
|
74
|
+
bool (*iter)(const double *min, const double *max, const void *data, void *udata),
|
|
75
|
+
void *udata);
|
|
76
|
+
|
|
77
|
+
// rtree_count returns the number of items in the rtree.
|
|
78
|
+
size_t rtree_count(const struct rtree *tr);
|
|
79
|
+
|
|
80
|
+
// rtree_delete deletes an item from the rtree.
|
|
81
|
+
//
|
|
82
|
+
// This searches the tree for an item that is contained within the provided
|
|
83
|
+
// rectangle, and perform a binary comparison of its data to the provided
|
|
84
|
+
// data. The first item that is found is deleted.
|
|
85
|
+
//
|
|
86
|
+
// Returns false if the system is out of memory.
|
|
87
|
+
bool rtree_delete(struct rtree *tr, const double *min, const double *max, const void *data);
|
|
88
|
+
|
|
89
|
+
// rtree_delete_with_comparator deletes an item from the rtree.
|
|
90
|
+
// This searches the tree for an item that is contained within the provided
|
|
91
|
+
// rectangle, and perform a comparison of its data to the provided data using
|
|
92
|
+
// a compare function. The first item that is found is deleted.
|
|
93
|
+
//
|
|
94
|
+
// Returns false if the system is out of memory.
|
|
95
|
+
bool rtree_delete_with_comparator(struct rtree *tr, const double *min,
|
|
96
|
+
const double *max, const void *data,
|
|
97
|
+
int (*compare)(const void *a, const void *b, void *udata),
|
|
98
|
+
void *udata);
|
|
99
|
+
|
|
100
|
+
// rtree_opt_relaxed_atomics activates memory_order_relaxed for all atomic
|
|
101
|
+
// loads. This may increase performance for single-threaded programs.
|
|
102
|
+
// Optionally, define RTREE_NOATOMICS to disbale all atomics.
|
|
103
|
+
void rtree_opt_relaxed_atomics(struct rtree *tr);
|
|
104
|
+
|
|
105
|
+
#endif // RTREE_H
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) 2023 Joshua J Baker
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
|
11
|
+
all copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
19
|
+
THE SOFTWARE.
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="docs/assets/logo.png" width="240" alt="TG">
|
|
3
|
+
</p>
|
|
4
|
+
<p align="center">
|
|
5
|
+
<a href="docs/API.md"><img src="https://img.shields.io/badge/api-reference-blue.svg?style=flat-square" alt="API Reference"></a>
|
|
6
|
+
</p>
|
|
7
|
+
|
|
8
|
+
TG is a geometry library for C that is small, fast, and easy to use.
|
|
9
|
+
It's designed for programs that need real-time geospatial, such as geofencing, monitoring, and streaming analysis.
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- Implements OGC [Simple Features](https://en.wikipedia.org/wiki/Simple_Features) including Point, LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon, GeometryCollection.
|
|
14
|
+
- Optimized [polygon indexing](docs/POLYGON_INDEXING.md) that introduces two new structures.
|
|
15
|
+
- Reads and writes [GeoJSON](https://en.wikipedia.org/wiki/GeoJSON), [WKT](https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry), [WKB](https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry), and [GeoBIN](docs/GEOBIN.md).
|
|
16
|
+
- Provides a purely functional [API](docs/API.md) that is reentrant and thread-safe.
|
|
17
|
+
- Spatial predicates including "intersects", "covers", "touches", "equals", etc.
|
|
18
|
+
- Compiles to Webassembly using Emscripten
|
|
19
|
+
- [Test suite](tests/README.md) with 100% coverage using sanitizers and [Valgrind](https://valgrind.org).
|
|
20
|
+
- Self-contained library that is encapsulated in the single [tg.c](tg.c) source file.
|
|
21
|
+
- Pretty darn good performance. 🚀 <sup>[[benchmarks]](docs/BENCHMARKS.md)</sup>
|
|
22
|
+
|
|
23
|
+
## Goals
|
|
24
|
+
|
|
25
|
+
The main goal of TG is to provide the fastest, most memory efficient geometry library for the purpose of monitoring spatial relationships, specifically operations like point-in-polygon and geometry intersect.
|
|
26
|
+
|
|
27
|
+
It's a non-goal for TG to be a full GIS library. Consider [GEOS](https://libgeos.org) if you need GIS algorithms like generating a convex hull or voronoi diagram. The [tgx](https://github.com/tidwall/tgx) library is available for bridging GEOS and TG geometries, which allows for performing GEOS operations on a TG geometry.
|
|
28
|
+
|
|
29
|
+
## Performance
|
|
30
|
+
|
|
31
|
+
TG uses [entirely new](docs/POLYGON_INDEXING.md) indexing structures that speed up [geometry predicates](docs/API.md#geometry-predicates). It can index more than 10GB per second of point data on modern hardware, while using less than 7% of additional memory, and can perform over 10 million point-in-polygon operations per second, even when using large polygons with over 10K points.
|
|
32
|
+
|
|
33
|
+
The following benchmark provides an example of the parsing, indexing, and point-in-polygon speed of TG vs GEOS when using a large polygon. In this case Brazil, which has 39K points.
|
|
34
|
+
|
|
35
|
+
<pre>
|
|
36
|
+
<b>Brazil ops/sec ns/op points hits built bytes</b>
|
|
37
|
+
tg/none 96,944 10315 39914 3257 46.73 µs 638,720
|
|
38
|
+
tg/natural 10,143,419 99 39914 3257 53.17 µs 681,360
|
|
39
|
+
tg/ystripes 15,174,761 66 39914 3257 884.06 µs 1,059,548
|
|
40
|
+
geos/none 29,708 33661 39914 3257 135.18 µs 958,104
|
|
41
|
+
geos/prepared 7,885,512 127 39914 3257 2059.94 µs 3,055,496
|
|
42
|
+
</pre>
|
|
43
|
+
|
|
44
|
+
- "built": Column showing how much time it took to construct the polygon and index.
|
|
45
|
+
- "bytes": Column showing the final in-memory size of the polygon and index.
|
|
46
|
+
- "none": No indexing was used.
|
|
47
|
+
- "natural": Using TG [Natural](docs/POLYGON_INDEXING.md#natural) indexing
|
|
48
|
+
- "ystripes": Using TG [YStripes](docs/POLYGON_INDEXING.md#ystripes) indexing
|
|
49
|
+
- "prepared": Using a [GEOS](https://libgeos.org) PreparedGeometry
|
|
50
|
+
|
|
51
|
+
See all [benchmarks](docs/BENCHMARKS.md) for more information.
|
|
52
|
+
|
|
53
|
+
## Using
|
|
54
|
+
|
|
55
|
+
Just drop the "tg.c" and "tg.h" files into your project.
|
|
56
|
+
Uses standard C11 so most modern C compilers should work.
|
|
57
|
+
|
|
58
|
+
```sh
|
|
59
|
+
$ cc -c tg.c
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Programmer notes
|
|
63
|
+
|
|
64
|
+
*Check out the complete [API](docs/API.md) for detailed information.*
|
|
65
|
+
|
|
66
|
+
#### Pure functions
|
|
67
|
+
|
|
68
|
+
TG library functions are thread-safe, reentrant, and (mostly) without side
|
|
69
|
+
effects.
|
|
70
|
+
The exception being with the use of malloc by some functions like
|
|
71
|
+
[geometry constructors](docs/API.md#geometry-constructors).
|
|
72
|
+
In those cases, it's the programmer's responsibiilty to check the return value
|
|
73
|
+
before continuing.
|
|
74
|
+
|
|
75
|
+
```c
|
|
76
|
+
struct tg_geom *geom = tg_geom_new_point(-112, 33);
|
|
77
|
+
if (!geom) {
|
|
78
|
+
// System is out of memory.
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
#### Fast cloning
|
|
83
|
+
|
|
84
|
+
The cloning of geometries, as with [tg_geom_clone()](docs/API.md#tg_geom_clone), are
|
|
85
|
+
O(1) operations that use implicit sharing through an atomic reference counter.
|
|
86
|
+
Geometry constructors like [tg_geom_new_polygon()](docs/API.md#tg_geom_new_polygon) will
|
|
87
|
+
use this method under the hood to maintain references of its inputs.
|
|
88
|
+
|
|
89
|
+
While this may only be an implementation detail, it's important for the
|
|
90
|
+
programmer to understand how TG uses memory and object references.
|
|
91
|
+
|
|
92
|
+
For example:
|
|
93
|
+
|
|
94
|
+
```c
|
|
95
|
+
struct tg_geom *geom = tg_geom_new_polygon(exterior, holes, nholes);
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Above, a new geometry "geom" was created and includes a cloned reference to the
|
|
99
|
+
[tg_ring](docs/API.md#tg_ring) "exterior" and all of the holes.
|
|
100
|
+
|
|
101
|
+
Providing `TG_NOATOMICS` to the compiler will disable the use of atomics and
|
|
102
|
+
instead use non-atomic reference counters.
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
cc -DTG_NOATOMICS tg.c ...
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Alternatively, the [tg_geom_copy()](docs/API.md#tg_geom_copy) method is available to perform a deep copy of the
|
|
109
|
+
geometry.
|
|
110
|
+
|
|
111
|
+
#### Avoid memory leaks
|
|
112
|
+
|
|
113
|
+
To avoid memory leaks, call [tg_geom_free()](docs/API.md#tg_geom_free) on geometries
|
|
114
|
+
created from [geometry constructors](docs/API.md#geometry-constructors),
|
|
115
|
+
[geometry parsers](docs/API.md#geometry-parsing), [tg_geom_clone()](docs/API.md#tg_geom_clone), and [tg_geom_copy()](docs/API.md#tg_geom_copy)
|
|
116
|
+
|
|
117
|
+
In other words, for every `tg_geom_new_*()`, `tg_geom_parse_*()`,
|
|
118
|
+
`tg_geom_clone()`, and `tg_geom_copy()` there should be (eventually and exactly)
|
|
119
|
+
one `tg_geom_free()`.
|
|
120
|
+
|
|
121
|
+
#### Upcasting
|
|
122
|
+
|
|
123
|
+
The TG object types [tg_line](docs/API.md#tg_line), [tg_ring](docs/API.md#tg_ring), and
|
|
124
|
+
[tg_poly](docs/API.md#tg_poly) can be safely upcasted to a [tg_geom](docs/API.md#tg_geom) with no
|
|
125
|
+
cost at runtime.
|
|
126
|
+
|
|
127
|
+
```c
|
|
128
|
+
struct tg_geom *geom1 = (struct tg_geom*)line; // Cast tg_line to tg_geom
|
|
129
|
+
struct tg_geom *geom2 = (struct tg_geom*)ring; // Cast tg_ring to tg_geom
|
|
130
|
+
struct tg_geom *geom3 = (struct tg_geom*)poly; // Cast tg_poly to tg_geom
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
This allows for exposing all [tg_geom](docs/API.md#tg_geom) functions to the other
|
|
134
|
+
object types.
|
|
135
|
+
|
|
136
|
+
In addition, the [tg_ring](docs/API.md#tg_ring) type can also cast to a
|
|
137
|
+
[tg_poly](docs/API.md#tg_poly).
|
|
138
|
+
|
|
139
|
+
```c
|
|
140
|
+
struct tg_poly *poly = (struct tg_poly*)ring; // Cast tg_ring to tg_poly
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
*Do not downcast. It's not generally safe to cast from a [tg_geom](docs/API.md#tg_geom) to other
|
|
144
|
+
types.*
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
## Example
|
|
148
|
+
|
|
149
|
+
Create a program that tests if two geometries intersect using [WKT](https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry) as inputs.
|
|
150
|
+
|
|
151
|
+
```c
|
|
152
|
+
#include <stdio.h>
|
|
153
|
+
#include <tg.h>
|
|
154
|
+
|
|
155
|
+
int main(int argc, char **argv) {
|
|
156
|
+
if (argc != 3) {
|
|
157
|
+
fprintf(stderr, "Usage: %s <geom-a> <geom-b>\n", argv[0]);
|
|
158
|
+
return 1;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Parse the input geometries and check for errors.
|
|
162
|
+
struct tg_geom *a = tg_parse_wkt(argv[1]);
|
|
163
|
+
if (tg_geom_error(a)) {
|
|
164
|
+
fprintf(stderr, "%s\n", tg_geom_error(a));
|
|
165
|
+
return 1;
|
|
166
|
+
}
|
|
167
|
+
struct tg_geom *b = tg_parse_wkt(argv[2]);
|
|
168
|
+
if (tg_geom_error(b)) {
|
|
169
|
+
fprintf(stderr, "%s\n", tg_geom_error(b));
|
|
170
|
+
return 1;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Execute the "intersects" predicate to test if both geometries intersect.
|
|
174
|
+
if (tg_geom_intersects(a, b)) {
|
|
175
|
+
printf("yes\n");
|
|
176
|
+
} else {
|
|
177
|
+
printf("no\n");
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Free geometries when done.
|
|
181
|
+
tg_geom_free(a);
|
|
182
|
+
tg_geom_free(b);
|
|
183
|
+
return 0;
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Build and run the example:
|
|
188
|
+
|
|
189
|
+
```sh
|
|
190
|
+
$ cc -I. examples/intersects.c tg.c
|
|
191
|
+
$ ./a.out 'POINT(15 15)' 'POLYGON((10 10,20 10,20 20,10 20,10 10))'
|
|
192
|
+
yes
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## License
|
|
196
|
+
|
|
197
|
+
TG source code is available under the MIT [License](/LICENSE).
|