This repository was archived by the owner on Dec 8, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathex2.zig
More file actions
131 lines (111 loc) · 4.46 KB
/
Copy pathex2.zig
File metadata and controls
131 lines (111 loc) · 4.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/// Reads one geometry and does high-performance prepared geometry operations
/// to place random points inside it.
///
/// (the description says "random points", however the example C code is not
/// randomized.)
///
/// Ported from src/geos/examples/capi_prepared.c
const c = @cImport({
@cInclude("zig_handlers.h");
@cInclude("geos_c.h");
});
const std = @import("std");
const handlers = @import("default_handlers");
const ArrayList = std.ArrayList;
const GeneralPurposeAllocator = std.heap.GeneralPurposeAllocator(.{});
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
var gpa = GeneralPurposeAllocator{};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Send notice and error messages to our stdout handler
c.initGEOS(handlers.shimNotice, handlers.shimError);
// Clean up the global context
defer c.finishGEOS();
errdefer c.finishGEOS();
// One concave polygon
const wkt = "POLYGON ((189 115, 200 170, 130 170, 35 242, 156 215, 210 290, 274 256, 360 190, 267 215, 300 50, 200 60, 189 115))";
// Read the WKT into geometry objects
const reader = c.GEOSWKTReader_create();
defer c.GEOSWKTReader_destroy(reader);
const geom = c.GEOSWKTReader_read(reader, wkt);
defer c.GEOSGeom_destroy(geom);
// Check for parse success.
if (geom == null) {
// TODO: parse failure actually results in an unhandled C++ exception (see known issues)
return error.GEOSWKTParseFailure;
}
// Prepare the geometry
const prep_geom = c.GEOSPrepare(geom);
defer c.GEOSPreparedGeom_destroy(prep_geom);
// Read bounds of geometry
var xmin: f64 = 0;
var xmax: f64 = 0;
var ymin: f64 = 0;
var ymax: f64 = 0;
if (c.GEOSGeom_getXMin(geom, &xmin) == 0) {
// geos returns 0 on empty geometry.
return error.GEOSInvalidOperation;
}
if (c.GEOSGeom_getXMax(geom, &xmax) == 0) {
return error.GEOSInvalidOperation;
}
if (c.GEOSGeom_getYMin(geom, &ymin) == 0) {
return error.GEOSInvalidOperation;
}
if (c.GEOSGeom_getYMax(geom, &ymax) == 0) {
return error.GEOSInvalidOperation;
}
// Set up the point generator
// Generate all the points in the bounding box
// of the input polygon.
const steps: u8 = 10;
const xstep: f64 = (xmax - xmin) / @intToFloat(f64, steps);
const ystep: f64 = (ymax - ymin) / @intToFloat(f64, steps);
// Place to hold points to output
// The example C code allocated a [steps*steps] array of pointers.
// Instead, use zig std library ArrayList.
var geoms = ArrayList(?*c.GEOSGeometry).init(allocator);
defer geoms.deinit();
// Test all the points in the polygon bounding box
// and only keep those that intersect the actual polygon.
var i: u8 = 0;
var j: u8 = 0;
while (i < steps) : (i += 1) {
while (j < steps) : (j += 1) {
// Make a point in the point grid
const x = xmin + xstep * @intToFloat(f64, i);
const y = ymin + ystep * @intToFloat(f64, j);
const pt = c.GEOSGeom_createPointFromXY(x, y) orelse return error.GEOSInvalidOperation;
// Check if the point and polygon intersect
if (c.GEOSPreparedIntersects(prep_geom, pt) != '0') {
// Save the ones that do
try geoms.append(pt);
} else {
// Clean up the ones that don't
c.GEOSGeom_destroy(pt);
}
}
}
// Put the successful geoms inside a geometry for WKT output
const result = c.GEOSGeom_createCollection(c.GEOS_MULTIPOINT, geoms.items.ptr, @intCast(c_uint, geoms.items.len));
defer c.GEOSGeom_destroy(result);
// The GEOSGeom_createCollection() only takes ownership of the
// geometries, not the array container, so we can free the container now.
//
// (See defer statement above)
// Convert result to WKT
const writer = c.GEOSWKTWriter_create();
defer c.GEOSWKTWriter_destroy(writer);
// Trim trailing zeros off output
c.GEOSWKTWriter_setTrim(writer, 1);
c.GEOSWKTWriter_setRoundingPrecision(writer, 3);
const wkt_result = c.GEOSWKTWriter_write(writer, result);
defer c.GEOSFree(wkt_result);
// Print answer
try stdout.print("Input Polygon:\n{s}\n\n", .{wkt});
try stdout.print("Output Points:\n{s}\n\n", .{wkt_result});
// | Clean up everything we allocated
// | Clean up the global context
// |-> *see zig defer statements above*
}