-
Notifications
You must be signed in to change notification settings - Fork 372
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
Add GEOSDensify to CAPI #391
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
7960e9f
Add GEOSDensify to CAPI
brendan-ward 51c6e77
Fix geometry variable name
brendan-ward 64ccc7c
Remove guard for null geometry and associated test
brendan-ward 9429ff3
Move empty check to Densifier; reduce test boilerplate
brendan-ward e5dad0d
Ensure densify results in segments <= tolerance
brendan-ward File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,214 @@ | ||
// | ||
// Test Suite for C-API GEOSBuffer and GEOSBufferWithStyle | ||
|
||
#include <tut/tut.hpp> | ||
// geos | ||
#include <geos_c.h> | ||
|
||
#include "capi_test_utils.h" | ||
|
||
|
||
namespace tut { | ||
// | ||
// Test Group | ||
// | ||
|
||
// Common data used in test cases. | ||
struct test_capigeosdensify_data : public capitest::utility { | ||
GEOSGeometry* geom1_; | ||
GEOSGeometry* geom2_; | ||
GEOSWKTWriter* w_; | ||
char* wkt_; | ||
|
||
test_capigeosdensify_data() | ||
: geom1_(nullptr), geom2_(nullptr), w_(nullptr) | ||
{ | ||
initGEOS(notice, notice); | ||
w_ = GEOSWKTWriter_create(); | ||
GEOSWKTWriter_setTrim(w_, 1); | ||
} | ||
|
||
~test_capigeosdensify_data() | ||
{ | ||
GEOSGeom_destroy(geom1_); | ||
GEOSGeom_destroy(geom2_); | ||
GEOSWKTWriter_destroy(w_); | ||
geom1_ = nullptr; | ||
geom2_ = nullptr; | ||
wkt_ = nullptr; | ||
finishGEOS(); | ||
} | ||
|
||
}; | ||
|
||
typedef test_group<test_capigeosdensify_data> group; | ||
typedef group::object object; | ||
|
||
group test_capigeosdensify_group("capi::GEOSDensify"); | ||
|
||
// | ||
// Test Cases | ||
// | ||
|
||
// Densify with a tolerance slightly larger than length of all edges. | ||
// Result should match inputs. | ||
template<> | ||
template<> | ||
void object::test<1>() | ||
{ | ||
geom1_ = GEOSGeomFromWKT("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (1 1, 1 2, 2 2, 2 1, 1 1))"); | ||
ensure(geom1_ != nullptr); | ||
GEOSSetSRID(geom1_, 3857); | ||
|
||
geom2_ = GEOSDensify(geom1_, 10.0); | ||
|
||
ensure("result not null", geom2_ != nullptr); | ||
ensure_geometry_equals(geom2_, geom1_); | ||
ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom2_), 3857); | ||
} | ||
|
||
|
||
// Densify with a tolerance that evenly subdivides all outer and inner edges. | ||
template<> | ||
template<> | ||
void object::test<2>() | ||
{ | ||
geom1_ = GEOSGeomFromWKT("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (1 1, 1 7, 7 7, 7 1, 1 1))"); | ||
ensure(geom1_ != nullptr); | ||
GEOSSetSRID(geom1_, 3857); | ||
|
||
geom2_ = GEOSDensify(geom1_, 5.0); | ||
|
||
ensure("result not null", geom2_ != nullptr); | ||
ensure_geometry_equals( | ||
geom2_, | ||
"POLYGON ((0 0, 5 0, 10 0, 10 5, 10 10, 5 10, 0 10, 0 5, 0 0), (1 1, 1 4, 1 7, 4 7, 7 7, 7 4, 7 1, 4 1, 1 1))"); | ||
|
||
ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom2_), 3857); | ||
} | ||
|
||
// Densify a LINESTRING | ||
template<> | ||
template<> | ||
void object::test<3>() | ||
{ | ||
geom1_ = GEOSGeomFromWKT("LINESTRING (0 0, 0 6 )"); | ||
ensure(geom1_ != nullptr); | ||
GEOSSetSRID(geom1_, 3857); | ||
|
||
geom2_ = GEOSDensify(geom1_, 3); | ||
|
||
ensure("result not null", geom2_ != nullptr); | ||
ensure_geometry_equals( | ||
geom2_, | ||
"LINESTRING (0 0, 0 3, 0 6)"); | ||
|
||
ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom2_), 3857); | ||
} | ||
|
||
// Ensure that tolerance results in the right number of subdivisions | ||
// ceil(6 / 2.9999999) = 3 new segments; 2 new vertices | ||
template<> | ||
template<> | ||
void object::test<4>() | ||
{ | ||
geom1_ = GEOSGeomFromWKT("LINESTRING (0 0, 0 6 )"); | ||
ensure(geom1_ != nullptr); | ||
GEOSSetSRID(geom1_, 3857); | ||
|
||
geom2_ = GEOSDensify(geom1_, 2.9999999); | ||
|
||
ensure("result not null", geom2_ != nullptr); | ||
ensure_geometry_equals( | ||
geom2_, | ||
"LINESTRING (0 0, 0 2, 0 4, 0 6)"); | ||
|
||
ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom2_), 3857); | ||
} | ||
|
||
|
||
// Densify a LINEARRING | ||
template<> | ||
template<> | ||
void object::test<5>() | ||
{ | ||
geom1_ = GEOSGeomFromWKT("LINEARRING (0 0, 0 6, 6 6, 0 0)"); | ||
ensure(geom1_ != nullptr); | ||
GEOSSetSRID(geom1_, 3857); | ||
|
||
geom2_ = GEOSDensify(geom1_, 3.0); | ||
|
||
ensure("result not null", geom2_ != nullptr); | ||
ensure_geometry_equals( | ||
geom2_, | ||
"LINEARRING (0 0, 0 3, 0 6, 3 6, 6 6, 4 4, 2 2, 0 0)"); | ||
ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom2_), 3857); | ||
} | ||
|
||
// Densify a POINT | ||
// Results should match inputs | ||
template<> | ||
template<> | ||
void object::test<6>() | ||
{ | ||
geom1_ = GEOSGeomFromWKT("POINT (0 0)"); | ||
ensure(geom1_ != nullptr); | ||
GEOSSetSRID(geom1_, 3857); | ||
|
||
geom2_ = GEOSDensify(geom1_, 3.0); | ||
|
||
ensure("result not null", geom2_ != nullptr); | ||
ensure_geometry_equals(geom2_, geom1_); | ||
ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom2_), 3857); | ||
} | ||
|
||
// Densify a MULTIPOINT | ||
// Results should match inputs | ||
template<> | ||
template<> | ||
void object::test<7>() | ||
{ | ||
geom1_ = GEOSGeomFromWKT("MULTIPOINT ((0 0), (10 10))"); | ||
ensure(geom1_ != nullptr); | ||
GEOSSetSRID(geom1_, 3857); | ||
|
||
geom2_ = GEOSDensify(geom1_, 3.0); | ||
|
||
ensure("result not null", geom2_ != nullptr); | ||
ensure_geometry_equals(geom2_, geom1_); | ||
ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom2_), 3857); | ||
} | ||
|
||
// Densify an empty polygon | ||
// Results should match inputs | ||
template<> | ||
template<> | ||
void object::test<8>() | ||
{ | ||
geom1_ = GEOSGeomFromWKT("POLYGON EMPTY"); | ||
ensure(geom1_ != nullptr); | ||
|
||
geom2_ = GEOSDensify(geom1_, 3.0); | ||
|
||
ensure("result not null", geom2_ != nullptr); | ||
ensure_geometry_equals(geom2_, geom1_); | ||
} | ||
|
||
// Densify with an invalid tolerances should fail | ||
// Note: this raises "IllegalArgumentException: Tolerance must be positive: | ||
template<> | ||
template<> | ||
void object::test<9>() | ||
{ | ||
geom1_ = GEOSGeomFromWKT("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))"); | ||
ensure(geom1_ != nullptr); | ||
|
||
geom2_ = GEOSDensify(geom1_, 0.0); | ||
ensure(geom2_ == nullptr); | ||
|
||
geom2_ = GEOSDensify(geom1_, -1.0); | ||
ensure(geom2_ == nullptr); | ||
} | ||
|
||
} // namespace tut | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure would be nice to reduce the amount of code for tests like this (not just here, for all GEOS unit tests).
Any ideas, @dbaston ? Perhaps some more helper functions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I were writing it I would drop lines 77 and 82, but overall it seems pretty reasonable to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have a problem with those lines per se (although if they are redundant would be good to remove them). The real problem is how many lines of code are repeated in each test. The only information content is the input WKT, the densify tolerance, and the result WKT.
In JTS I factor out the boilerplate into a separate function which is called by each test. One thing this supports nicely is that if the test logic needs to be modified or enhanced (say with an extra test on a specific aspect of the result) it can be done in one place only. (In other words, the standard reason for refactoring :)
I'm just not sure if the tut templated approach supports that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It turns out that factoring out the test common code into a support function is very doable. See
GEOSMinimumClearanceTest.cpp
for an example.@brendan-ward how do you feel about making this improvement?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, some of the tests do something like
doDensifierTest
. I actually find those harder to work with, mostly because our test framework has no way to run an individual test. So if you want to debug a test and the test code itself is in a common function, you have to comment out all of the remaining tests.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it's a balance. I've found having support functions tucked away in another file makes things more painful, but having them in the actual Test file is a-OK. Also, we can run individual tests (not assertions) with
./bin/test_geos_unit geos::io::WKBReader 6
so having more numbered chunks is often preferable to a long list of assertions, or a loop over a data array (my nemesis).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How am I only learning this now? 🤦
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I only found it out a couple months ago! I was like... "what if I add the number..."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Also, the numbers don't have to be sequential)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Of course. My experience makes me less inclined to write something today the way I wrote the minimum clearance tests 5 years ago. Your experience seems to pull you in the other direction. That's fine.