Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EXPERIMENTAL work on prototyping the VT3 vector tile spec revision #611

Open
wants to merge 130 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
130 commits
Select commit Hold shift + click to select a range
23c615e
EXPERIMENTAL support for arbitrary JSON objects as feature attributes
e-n-f Sep 28, 2016
3ed673b
Enforce the constraint against circular references
e-n-f Sep 28, 2016
91d4621
Also handle nested feature attributes in tile-join
e-n-f Sep 29, 2016
37a20a0
Factor out duplicated code
e-n-f Sep 29, 2016
2606fa1
Add new protocol elements to .proto file
e-n-f Sep 29, 2016
98c5581
Use 8 for hashes and 9 for lists, not the other way around
e-n-f Sep 29, 2016
c1889b7
Encode null sub-attributes as an empty message, not as their own type
e-n-f Jun 5, 2017
93005de
Fix duplicate attribute detection for lists and hashes
e-n-f Jun 5, 2017
c2b7d36
Merge branch 'master' into object-attributes
e-n-f Aug 21, 2017
1ca0d00
Fix and test round trip of compound attributes through tile-join
e-n-f Aug 21, 2017
3d65ceb
Add missing #include
e-n-f Aug 31, 2017
4b08302
Another missing #include
e-n-f Sep 1, 2017
6f4ec2a
Merge branch 'master' into object-attributes-merge3
e-n-f Mar 17, 2018
f4517d9
Geobuf doesn't support nested attributes, so don't test that
e-n-f Mar 19, 2018
c64a39c
Merge branch 'master' into object-attributes
e-n-f Mar 19, 2018
e0ab754
Nested attributes do work in Geobuf. Remove coercion to string.
e-n-f Mar 19, 2018
4756be6
Merge branch 'master' into object-attributes
e-n-f Apr 9, 2018
b6f329e
Untested code to read and write proposed new properties format
e-n-f Jul 20, 2018
c619f56
It works (except for tests that depend upon exact tile size)
e-n-f Jul 20, 2018
053d2d1
The tile-join main loop wasn't copying proposed-new-style attributes
e-n-f Jul 20, 2018
e8011c5
Make tile format configurable. Add option to sort values in v2 style.
e-n-f Jul 23, 2018
b7dc84b
Also sort the keys
e-n-f Jul 23, 2018
8722ec0
Add variant that inlines float values
e-n-f Jul 24, 2018
27b9ced
Need 4 bits for type, not just 3
e-n-f Jul 24, 2018
0b8dc68
Merge branch 'master' into object-attributes
e-n-f Aug 14, 2018
04adb8b
Be clear that empty lists and objects are allowed, and are failing
e-n-f Aug 14, 2018
9319f2e
Add a way to represent empty hashes and lists in attributes
e-n-f Aug 14, 2018
935cff2
Merge branch 'master' into blake-properties
e-n-f Aug 14, 2018
aa8d4c1
Update test standards after merge
e-n-f Aug 14, 2018
762b9e9
More tests that come out a little different now
e-n-f Aug 14, 2018
cafe178
The tileset stats test also needs an update
e-n-f Aug 14, 2018
31e4ec6
Merge branch 'object-attributes' into blake-properties
e-n-f Aug 14, 2018
ff1a28b
Fix segfault
e-n-f Aug 14, 2018
900738d
Pass compound objects through the prefilter
e-n-f Aug 14, 2018
e6fb320
Treat compound tagging like any other tagging. Add postfilter test.
e-n-f Aug 14, 2018
f31024d
Merge branch 'object-attributes' into blake-properties
e-n-f Aug 14, 2018
8814021
Move in the direction of supporting lists and hashes again
e-n-f Aug 14, 2018
1252008
Reorganize to get ready for lists and hashes
e-n-f Aug 15, 2018
5aaad25
Write lists and hashes
e-n-f Aug 15, 2018
bfc211a
Closer to encoding and decoding lists and hashes
e-n-f Aug 15, 2018
a5e1153
Decode Blake-style lists and hashes
e-n-f Aug 15, 2018
adc4039
Handle null values (in nested objects)
e-n-f Aug 15, 2018
a35c22e
Fix array bounds reference in tile-join property iteration
e-n-f Aug 15, 2018
3f0cd8b
Pass compound objects through tile-join
e-n-f Aug 15, 2018
76582d0
Fix out-of-bounds array reference
e-n-f Aug 15, 2018
ba583d4
Change tables of integers by reference to be fixed-size
e-n-f Aug 16, 2018
02ba289
Merge branch 'master' into blake-properties
e-n-f Aug 16, 2018
9ae2121
Revised attribute representation to match spec revision
e-n-f Aug 17, 2018
fc351aa
Get rid of the experiment with inlining floats
e-n-f Aug 17, 2018
7fe6bbf
Fix tile-join
e-n-f Aug 17, 2018
7c498ae
Format change means tile sizes changed again
e-n-f Aug 17, 2018
3a588b0
Fix another tile-join crash
e-n-f Aug 17, 2018
a3c52c8
Start trying to preserve additional node dimensions
e-n-f Aug 22, 2018
ee3f353
More plumbing for additional geometry dimensions
e-n-f Aug 22, 2018
dcc4676
Plumb 3D geometry and per-node attributes through serialization
e-n-f Aug 23, 2018
0098322
Add missing header
e-n-f Aug 23, 2018
c43e6d6
Extend the elevation pipeline far enough to write some to the tile
e-n-f Aug 23, 2018
00a74a5
Carry elevations all the way into decoding
e-n-f Aug 23, 2018
58e5e7a
Clip points should have interpolated elevations
e-n-f Aug 23, 2018
79a0422
Don't try to run the elevation test with geobuf, since it won't work
e-n-f Aug 23, 2018
366353a
Fix undefined elevations coming back as 0
e-n-f Aug 23, 2018
12cd5f6
The g++ build does not seem to think that C-style isnan is defined
e-n-f Aug 24, 2018
3fbd899
Fix more g++ complaints about isnan not being defined
e-n-f Aug 24, 2018
68686e8
Carry the per-node attributes into the tile structure
e-n-f Aug 24, 2018
1ddaa92
Work on generalizing to arbitrarily many dimensions
e-n-f Aug 24, 2018
b68c190
Fix elevation inconsistencies
e-n-f Aug 24, 2018
38d2a86
Fix encoding of features with unequal numbers of dimensions
e-n-f Aug 24, 2018
6faf4dc
Some work on decoding per-node attributes
e-n-f Aug 28, 2018
18d1e54
More plumbing for decoding node attributes
e-n-f Aug 28, 2018
749418e
Serialize node attributes into the tile
e-n-f Aug 28, 2018
074ed22
Turn node attribute parsing back on. Fix message number in tile.
e-n-f Aug 28, 2018
8980c4a
Get the first node attribute per feature decoding, at least
e-n-f Aug 28, 2018
8db6f59
Remove dead-end idea for decoding node attributes
e-n-f Aug 28, 2018
a1b651b
Forgot to increment the attribute index after decoding
e-n-f Aug 28, 2018
cf902bf
In output, write node attributes in a parallel array, not in coordinates
e-n-f Aug 29, 2018
09f76cd
Move the per-node attributes from coordinates to a parallel array
e-n-f Aug 30, 2018
86cf0a5
Should keep pre/postfilter from losing node attributes, but not working
e-n-f Aug 30, 2018
b7e56dd
Unify some duplicated code, but it still loses the node attributes
e-n-f Aug 31, 2018
9b3f09b
Renumber types and use a single pool for signed and unsigned ints
e-n-f Sep 4, 2018
de120df
Only the string values are in a sub-object of the layer now.
e-n-f Sep 4, 2018
16e7e0a
Forgot to update the tile size stats test
e-n-f Sep 4, 2018
b4cb2c6
Merge branch 'master' into blake-properties
e-n-f Sep 7, 2018
bd18666
Untested support for string feature IDs
e-n-f Sep 7, 2018
13879d0
Read string IDs at all, and use the right IDs when writing
e-n-f Sep 8, 2018
555e1be
Didn't update this test to include the string ID
e-n-f Sep 8, 2018
afe739c
String IDs are now plain strings instead of references
e-n-f Sep 10, 2018
ec0a54f
Move the string values back to the top level of the layer
e-n-f Sep 12, 2018
b79b9f9
Turn off geobuf versions for tests of vt3 features
e-n-f Sep 12, 2018
7154c06
Stabilize order of features in tile-join output
e-n-f Sep 12, 2018
4bcef2c
Work on reading dimension descriptions
e-n-f Sep 14, 2018
d4f9729
More progress on decoding elevations
e-n-f Sep 14, 2018
801940d
Encode dimensions, but it doesn't work
e-n-f Sep 14, 2018
b64cc84
Fix delta-encoded elevations
e-n-f Sep 14, 2018
0a339b6
Read and write spline knots, but don't try to interpret them yet
e-n-f Sep 17, 2018
fd65a64
Renumber fields to move in the direction of latest spec revisions
e-n-f Sep 27, 2018
e9e84fb
Revise for new definition of Scaling
e-n-f Oct 3, 2018
7d47d3c
Get rid of VT2-style lists and hashes to avoid future confusion
e-n-f Oct 8, 2018
7a84314
Introduce new list and hash container types for geometric attributes
e-n-f Oct 8, 2018
41f64b5
Inching closer to the revised spec for elevations
e-n-f Oct 9, 2018
0774711
I think this brings elevations in line with the spec
e-n-f Oct 9, 2018
e919726
Untested code for decoding delta-encoded lists
e-n-f Oct 9, 2018
9ac4ab2
Use a delta-encoded list
e-n-f Oct 9, 2018
c9a2a00
Turn the node attributes into a list to write them to the tile
e-n-f Oct 10, 2018
bc15ed2
Decode per-node attributes in list form
e-n-f Oct 10, 2018
602508a
Allow null attributes in tiles
e-n-f Oct 10, 2018
bf2ea31
Merge branch 'master' into blake-properties
e-n-f Oct 10, 2018
d3d73d3
Encode and decode zoom/x/y tags in the layer
e-n-f Oct 11, 2018
6315009
Remove some of the cases where objects are stored as stringified JSON
e-n-f Oct 11, 2018
c3d06f8
Only movetos and linetos have elevations, not closepaths
e-n-f Oct 12, 2018
ff1d1f0
Choose an elevation precision based on the zoom level
e-n-f Oct 12, 2018
600e87a
Disentangle list and hash attributes a little further
e-n-f Oct 15, 2018
a7903c4
Build the lists of node attributes as mvt_values without involving JSON
e-n-f Oct 15, 2018
56bf3f4
Elevation deltas are 32-bit, not 64-bit
e-n-f Oct 17, 2018
4ce81bd
Preserve per-node attributes through feature filter pipelines
e-n-f Oct 17, 2018
00f5713
Fix crash, clean up messy leftover code
e-n-f Oct 17, 2018
1b823a6
Preserve per-node attributes through tile-join
e-n-f Oct 17, 2018
af66a8a
Knots are delta-encoded complex values, not a list of doubles
e-n-f Oct 18, 2018
cf81880
Use the right message numbers for splines; additional spline support
e-n-f Oct 18, 2018
cfea072
Decode knots and spline degree to JSON if present
e-n-f Oct 19, 2018
0db0ef9
Include elevation and attribute scaling in tippecanoe-decode output
e-n-f Oct 19, 2018
ca887f5
Use delta-encoding for lists of integers
e-n-f Oct 19, 2018
44c0a6b
Fix a crash risk in parsing JSON coordinate arrays
e-n-f Oct 23, 2018
c4cb8d5
The default tile extent is 4096, not 0
e-n-f Oct 23, 2018
88ef0cd
Merge branch 'master' into blake-properties
e-n-f Oct 24, 2018
4f0a891
Reconcile tests (null attributes, clipping to bounding box)
e-n-f Oct 24, 2018
dd72e67
Add scaffolding for testing Python library. Change layer versions to 3
e-n-f Oct 25, 2018
719b5b8
Script to run tiles through python
e-n-f Oct 26, 2018
4a5aebe
Change representation of null/true/false to match vector-tile-base
e-n-f Oct 31, 2018
f327dd3
Change of representation changed the size of these tiles
e-n-f Oct 31, 2018
18c1c1b
Merge branch 'master' into blake-properties
e-n-f Nov 7, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 59 additions & 37 deletions Makefile

Large diffs are not rendered by default.

68 changes: 67 additions & 1 deletion decode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,16 @@ void do_stats(mvt_tile &tile, size_t size, bool compressed, int z, unsigned x, u
for (size_t i = 0; i < tile.layers.size(); i++) {
state.json_write_string(tile.layers[i].name);

size_t points = 0, lines = 0, polygons = 0;
size_t points = 0, lines = 0, polygons = 0, splines = 0;
for (size_t j = 0; j < tile.layers[i].features.size(); j++) {
if (tile.layers[i].features[j].type == mvt_point) {
points++;
} else if (tile.layers[i].features[j].type == mvt_linestring) {
lines++;
} else if (tile.layers[i].features[j].type == mvt_polygon) {
polygons++;
} else if (tile.layers[i].features[j].type == mvt_spline) {
splines++;
}
}

Expand All @@ -73,9 +75,27 @@ void do_stats(mvt_tile &tile, size_t size, bool compressed, int z, unsigned x, u
state.json_write_string("polygons");
state.json_write_unsigned(polygons);

state.json_write_string("splines");
state.json_write_unsigned(splines);

state.json_write_string("extent");
state.json_write_signed(tile.layers[i].extent);

if (tile.layers[i].zoom >= 0) {
state.json_write_string("zoom");
state.json_write_unsigned(tile.layers[i].zoom);
}

if (tile.layers[i].x >= 0) {
state.json_write_string("x");
state.json_write_unsigned(tile.layers[i].x);
}

if (tile.layers[i].y >= 0) {
state.json_write_string("y");
state.json_write_unsigned(tile.layers[i].y);
}

state.json_end_hash();
}

Expand All @@ -85,6 +105,21 @@ void do_stats(mvt_tile &tile, size_t size, bool compressed, int z, unsigned x, u
state.json_write_newline();
}

void write_scaling(json_writer &state, mvt_scaling const &scaling) {
state.json_write_hash();

state.json_write_string("offset");
state.json_write_unsigned(scaling.offset);

state.json_write_string("multiplier");
state.json_write_number(scaling.multiplier);

state.json_write_string("base");
state.json_write_number(scaling.base);

state.json_end_hash();
}

void handle(std::string message, int z, unsigned x, unsigned y, std::set<std::string> const &to_decode, bool pipeline, bool stats, json_writer &state) {
mvt_tile tile;
bool was_compressed;
Expand Down Expand Up @@ -189,6 +224,37 @@ void handle(std::string message, int z, unsigned x, unsigned y, std::set<std::st
state.json_write_string("extent");
state.json_write_signed(layer.extent);

if (layer.zoom >= 0) {
state.json_write_string("zoom");
state.json_write_unsigned(layer.zoom);
}

if (layer.x >= 0) {
state.json_write_string("x");
state.json_write_unsigned(layer.x);
}

if (layer.y >= 0) {
state.json_write_string("y");
state.json_write_unsigned(layer.y);
}

if (layer.has_elevation_scaling) {
state.json_write_string("elevation_scaling");
write_scaling(state, layer.elevation_scaling);
}

if (layer.attribute_scalings.size() != 0) {
state.json_write_string("attribute_scalings");
state.json_write_array();

for (size_t i = 0; i < layer.attribute_scalings.size(); i++) {
write_scaling(state, layer.attribute_scalings[i]);
}

state.json_end_array();
}

state.json_end_hash();

state.json_write_string("features");
Expand Down
2 changes: 1 addition & 1 deletion geobuf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ serial_val readValue(protozero::pbf_reader &pbf) {
break;

case 6:
sv.type = mvt_string; // stringified JSON
sv.type = mvt_hash; // stringified JSON
sv.s = pbf.get_string();

if (sv.s == "null") {
Expand Down
31 changes: 24 additions & 7 deletions geojson.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ int serialize_geojson_feature(struct serialization_state *sst, json_object *geom
return 0;
}

json_object *attributes = json_hash_get(geometry, "attributes");
if (attributes != NULL && attributes->type != JSON_ARRAY) {
attributes = NULL;
}

int t;
for (t = 0; t < GEOM_TYPES; t++) {
if (strcmp(geometry_type->string, geometry_names[t]) == 0) {
Expand Down Expand Up @@ -100,6 +105,7 @@ int serialize_geojson_feature(struct serialization_state *sst, json_object *geom

bool has_id = false;
unsigned long long id_value = 0;
std::string string_id_value;
if (id != NULL) {
if (id->type == JSON_NUMBER) {
if (id->number >= 0) {
Expand Down Expand Up @@ -159,13 +165,17 @@ int serialize_geojson_feature(struct serialization_state *sst, json_object *geom
}

if (!converted) {
static bool warned_nan = false;
if (id->type == JSON_STRING) {
string_id_value = id->string;
} else {
static bool warned_nan = false;

if (!warned_nan) {
char *s = json_stringify(id);
fprintf(stderr, "Warning: Can't represent non-numeric feature ID %s\n", s);
free(s); // stringify
warned_nan = true;
if (!warned_nan) {
char *s = json_stringify(id);
fprintf(stderr, "Warning: Can't represent non-numeric feature ID %s\n", s);
free(s); // stringify
warned_nan = true;
}
}
}
}
Expand Down Expand Up @@ -210,14 +220,21 @@ int serialize_geojson_feature(struct serialization_state *sst, json_object *geom
}

drawvec dv;
parse_geometry(t, coordinates, dv, VT_MOVETO, sst->fname, sst->line, feature);
parse_geometry(t, coordinates, dv, VT_MOVETO, sst->fname, sst->line, feature, false);

if (attributes != NULL) {
drawvec dv2;
parse_geometry(t, attributes, dv2, VT_MOVETO, sst->fname, sst->line, feature, true);
merge_node_attributes(dv, dv2);
}

serial_feature sf;
sf.layer = layer;
sf.segment = sst->segment;
sf.t = mb_geometry[t];
sf.has_id = has_id;
sf.id = id_value;
sf.string_id = string_id_value;
sf.has_tippecanoe_minzoom = (tippecanoe_minzoom != -1);
sf.tippecanoe_minzoom = tippecanoe_minzoom;
sf.has_tippecanoe_maxzoom = (tippecanoe_maxzoom != -1);
Expand Down
90 changes: 77 additions & 13 deletions geometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#include "options.hpp"

static int pnpoly(drawvec &vert, size_t start, size_t nvert, long long testx, long long testy);
static int clip(double *x0, double *y0, double *x1, double *y1, double xmin, double ymin, double xmax, double ymax);
static int clip(double *x0, double *y0, double *x1, double *y1, double xmin, double ymin, double xmax, double ymax, bool *changed0, bool *changed1, std::vector<double> *el0, std::vector<double> *el1);

drawvec decode_geometry(FILE *meta, std::atomic<long long> *geompos, int z, unsigned tx, unsigned ty, long long *bbox, unsigned initial_x, unsigned initial_y) {
drawvec out;
Expand All @@ -37,10 +37,12 @@ drawvec decode_geometry(FILE *meta, std::atomic<long long> *geompos, int z, unsi
while (1) {
draw d;

if (!deserialize_byte_io(meta, &d.op, geompos)) {
signed char op;
if (!deserialize_byte_io(meta, &op, geompos)) {
fprintf(stderr, "Internal error: Unexpected end of file in geometry\n");
exit(EXIT_FAILURE);
}
d.op = op & VT_CLOSEPATH;
if (d.op == VT_END) {
break;
}
Expand Down Expand Up @@ -77,6 +79,19 @@ drawvec decode_geometry(FILE *meta, std::atomic<long long> *geompos, int z, unsi

d.x = wwx;
d.y = wwy;

if (op & VT_NODE_3D) {
unsigned long long n;
deserialize_ulong_long_io(meta, &n, geompos);

d.elevations.resize(n);
for (size_t i = 0; i < n; i++) {
deserialize_double_io(meta, &d.elevations[i], geompos);
}
}
if (op & VT_NODE_ATTRIB) {
deserialize_string_io(meta, d.attributes, geompos);
}
}

out.push_back(d);
Expand Down Expand Up @@ -665,20 +680,41 @@ drawvec clip_lines(drawvec &geom, long long minx, long long miny, long long maxx
if (i > 0 && (geom[i - 1].op == VT_MOVETO || geom[i - 1].op == VT_LINETO) && geom[i].op == VT_LINETO) {
double x1 = geom[i - 1].x;
double y1 = geom[i - 1].y;
std::vector<double> e1 = geom[i - 1].elevations;

double x2 = geom[i - 0].x;
double y2 = geom[i - 0].y;
std::vector<double> e2 = geom[i - 0].elevations;

int c = clip(&x1, &y1, &x2, &y2, minx, miny, maxx, maxy);
bool changed0 = false, changed1 = false;
int c = clip(&x1, &y1, &x2, &y2, minx, miny, maxx, maxy, &changed0, &changed1, &e1, &e2);

if (c > 1) { // clipped
out.push_back(draw(VT_MOVETO, x1, y1));
out.push_back(draw(VT_LINETO, x2, y2));
out.push_back(draw(VT_MOVETO, geom[i].x, geom[i].y));
if (changed0) {
out.push_back(draw(VT_MOVETO, x1, y1, e1));
} else {
draw d = geom[i - 1];
d.op = VT_MOVETO;
out.push_back(d);
}

if (changed1) {
out.push_back(draw(VT_LINETO, x2, y2, e2));
} else {
draw d = geom[i];
d.op = VT_LINETO;
out.push_back(d);
}

draw d = geom[i];
d.op = VT_MOVETO;
out.push_back(d);
} else if (c == 1) { // unchanged
out.push_back(geom[i]);
} else { // clipped away entirely
out.push_back(draw(VT_MOVETO, geom[i].x, geom[i].y));
draw d = geom[i];
d.op = VT_MOVETO;
out.push_back(d);
}
} else {
out.push_back(geom[i]);
Expand Down Expand Up @@ -778,19 +814,22 @@ drawvec impose_tile_boundaries(drawvec &geom, long long extent) {
if (i > 0 && geom[i].op == VT_LINETO && (geom[i - 1].op == VT_MOVETO || geom[i - 1].op == VT_LINETO)) {
double x1 = geom[i - 1].x;
double y1 = geom[i - 1].y;
std::vector<double> e1 = geom[i - 1].elevations;

double x2 = geom[i - 0].x;
double y2 = geom[i - 0].y;
std::vector<double> e2 = geom[i - 0].elevations;

int c = clip(&x1, &y1, &x2, &y2, 0, 0, extent, extent);
bool changed0 = false, changed1 = false;
int c = clip(&x1, &y1, &x2, &y2, 0, 0, extent, extent, &changed0, &changed1, &e1, &e2);

if (c > 1) { // clipped
if (x1 != geom[i - 1].x || y1 != geom[i - 1].y) {
out.push_back(draw(VT_LINETO, x1, y1));
if (changed0) {
out.push_back(draw(VT_LINETO, x1, y1, e1));
out[out.size() - 1].necessary = 1;
}
if (x2 != geom[i - 0].x || y2 != geom[i - 0].y) {
out.push_back(draw(VT_LINETO, x2, y2));
if (changed1) {
out.push_back(draw(VT_LINETO, x2, y2, e2));
out[out.size() - 1].necessary = 1;
}
}
Expand Down Expand Up @@ -1071,7 +1110,7 @@ static int computeOutCode(double x, double y, double xmin, double ymin, double x
return code;
}

static int clip(double *x0, double *y0, double *x1, double *y1, double xmin, double ymin, double xmax, double ymax) {
static int clip(double *x0, double *y0, double *x1, double *y1, double xmin, double ymin, double xmax, double ymax, bool *changed0, bool *changed1, std::vector<double> *e0, std::vector<double> *e1) {
int outcode0 = computeOutCode(*x0, *y0, xmin, ymin, xmax, ymax);
int outcode1 = computeOutCode(*x1, *y1, xmin, ymin, xmax, ymax);
int accept = 0;
Expand All @@ -1087,6 +1126,7 @@ static int clip(double *x0, double *y0, double *x1, double *y1, double xmin, dou
// failed both tests, so calculate the line segment to clip
// from an outside point to an intersection with clip edge
double x = *x0, y = *y0;
std::vector<double> e = *e0;

// At least one endpoint is outside the clip rectangle; pick it.
int outcodeOut = outcode0 ? outcode0 : outcode1;
Expand All @@ -1096,28 +1136,52 @@ static int clip(double *x0, double *y0, double *x1, double *y1, double xmin, dou
if (outcodeOut & TOP) { // point is above the clip rectangle
x = *x0 + (*x1 - *x0) * (ymax - *y0) / (*y1 - *y0);
y = ymax;

e.resize(0);
for (size_t i = 0; i < e0->size() && i < e1->size(); i++) {
e.push_back((*e0)[i] + ((*e1)[i] - (*e0)[i]) * (ymax - *y0) / (*y1 - *y0));
}
} else if (outcodeOut & BOTTOM) { // point is below the clip rectangle
x = *x0 + (*x1 - *x0) * (ymin - *y0) / (*y1 - *y0);
y = ymin;

e.resize(0);
for (size_t i = 0; i < e0->size() && i < e1->size(); i++) {
e.push_back((*e0)[i] + ((*e1)[i] - (*e0)[i]) * (ymin - *y0) / (*y1 - *y0));
}
} else if (outcodeOut & RIGHT) { // point is to the right of clip rectangle
y = *y0 + (*y1 - *y0) * (xmax - *x0) / (*x1 - *x0);
x = xmax;

e.resize(0);
for (size_t i = 0; i < e0->size() && i < e1->size(); i++) {
e.push_back((*e0)[i] + ((*e1)[i] - (*e0)[i]) * (xmax - *x0) / (*x1 - *x0));
}
} else if (outcodeOut & LEFT) { // point is to the left of clip rectangle
y = *y0 + (*y1 - *y0) * (xmin - *x0) / (*x1 - *x0);
x = xmin;

e.resize(0);
for (size_t i = 0; i < e0->size() && i < e1->size(); i++) {
e.push_back((*e0)[i] + ((*e1)[i] - (*e0)[i]) * (xmin - *x0) / (*x1 - *x0));
}
}

// Now we move outside point to intersection point to clip
// and get ready for next pass.
if (outcodeOut == outcode0) {
*x0 = x;
*y0 = y;
*e0 = e;
outcode0 = computeOutCode(*x0, *y0, xmin, ymin, xmax, ymax);
*changed0 = 1;
changed = 1;
} else {
*x1 = x;
*y1 = y;
*e1 = e;
outcode1 = computeOutCode(*x1, *y1, xmin, ymin, xmax, ymax);
*changed1 = 1;
changed = 1;
}
}
Expand Down
Loading