-
Notifications
You must be signed in to change notification settings - Fork 226
Fix/start turns #769
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
Fix/start turns #769
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -507,6 +507,46 @@ inline void discard_interior_exterior_turns(Turns& turns, Clusters& clusters) | |
| } | ||
| } | ||
|
|
||
| template<typename Turns, typename Clusters> | ||
| inline void discard_start_turns(Turns& turns, Clusters& clusters) | ||
| { | ||
| for (auto& nv : clusters) | ||
| { | ||
| cluster_info& cinfo = nv.second; | ||
| auto& indices = cinfo.turn_indices; | ||
| std::size_t start_count{0}; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Out of curiosity, why not
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Habit, it the office we're preferring the new uniform initialization. What do you think?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I used to be very keen in preferring the uniform initialization heavily and everywhere, until I read the abseil guidelines and tips, in particular https://abseil.io/tips/88
It's a pity the uniform initialization is not corner-case free improvement to C++.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In this particular case I'd use This is not a case when an object of a class is created by passing some abstract which may describe something like number of elements. From the same reason I'd probably initialize the vector like the one below. In other words to express that the initializer list on the right represents the vector or that it is the vector (just like with This works right? ;) And then for all other things I don't have an opinion. I'd probably use the old parentheses. But maybe that's just because it's what I'm familiar with. Maybe with the exception of avoiding double parentheses to deal with the most vexing parse. So I guess I could also express this as a conservative stance where old initialization is used when possible as it was in the past and new brackets only for new features.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Interesting visions, thanks. |
||
| for (signed_size_type index : indices) | ||
| { | ||
| auto const& turn = turns[index]; | ||
| if (turn.method == method_start) | ||
| { | ||
| start_count++; | ||
| } | ||
| } | ||
| if (start_count == 0 && start_count == indices.size()) | ||
| { | ||
| // There are no start turns, or all turns in the cluster are start turns. | ||
| continue; | ||
| } | ||
|
|
||
| // Discard the start turns and simultaneously erase them from the indices | ||
| for (auto it = indices.begin(); it != indices.end();) | ||
| { | ||
| auto& turn = turns[*it]; | ||
| if (turn.method == method_start) | ||
| { | ||
| turn.discarded = true; | ||
| turn.cluster_id = -1; | ||
| it = indices.erase(it); | ||
| } | ||
| else | ||
| { | ||
| ++it; | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| template <typename Geometry0, typename Geometry1> | ||
| inline segment_identifier get_preceding_segment_id(segment_identifier const& id, | ||
| Geometry0 const& geometry0, Geometry1 const& geometry1) | ||
|
|
@@ -700,6 +740,8 @@ inline bool handle_colocations(Turns& turns, Clusters& clusters, | |
| // on turns which are discarded afterwards | ||
| set_colocation<OverlayType>(turns, clusters); | ||
|
|
||
| discard_start_turns(turns, clusters); | ||
|
|
||
| if (BOOST_GEOMETRY_CONDITION(target_operation == operation_intersection)) | ||
| { | ||
| discard_interior_exterior_turns | ||
|
|
@@ -783,7 +825,7 @@ inline bool fill_sbs(Sbs& sbs, Point& turn_point, | |
| { | ||
| signed_size_type turn_index = *sit; | ||
| turn_type const& turn = turns[turn_index]; | ||
| if (first ) | ||
| if (first) | ||
| { | ||
| turn_point = turn.point; | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -292,6 +292,52 @@ static std::string const rt_v3 | |
| static std::string const rt_v4 | ||
| = "MULTIPOLYGON(((5 4,5 5,6 5,6 4,5 4)),((7 1,6 1,7 2,7 1)),((7 1,8 1,8 0,7 0,7 1)),((6 1,5 1,5 2,6 1)))"; | ||
|
|
||
| // From 2020 runs of robustness test recursive_polygons_buffer, without rescaling | ||
| // For the same problem there can be multiple cases, but details differ | ||
|
|
||
| // Cases missing a turn, or needing a start turn | ||
| static std::string const nores_mt_1 | ||
| = "MULTIPOLYGON(((4 8,4 9,5 9,4 8)),((3 6,3 7,4 6,3 6)))"; | ||
|
|
||
| static std::string const nores_mt_2 | ||
| = "MULTIPOLYGON(((5 3,6 4,6 3,5 3)),((4 4,3 4,4 5,5 5,4 4)),((4 5,3 5,3 6,4 5)))"; | ||
|
|
||
| static std::string const nores_mt_3 | ||
| = "MULTIPOLYGON(((7 4,7 5,8 5,8 4,7 4)),((2 6,2 7,3 6,2 6)),((3 10,4 10,4 9,4 8,3 8,3 10)))"; | ||
|
|
||
| static std::string const nores_mt_4 | ||
| = "MULTIPOLYGON(((6 8,6 9,7 9,6 8)),((1 5,1 6,2 6,1 5)),((7 7,8 8,8 7,7 7)),((0 3,0 4,1 3,0 3)))"; | ||
|
|
||
| static std::string const nores_mt_5 | ||
| = "MULTIPOLYGON(((4 3,4 4,5 4,5 3,4 3)),((3 1,3 2,4 1,3 1)),((1 6,2 7,2 6,1 6)),((3 6,4 5,3 4,3 6)))"; | ||
|
|
||
| static std::string const nores_mt_6 | ||
| = "MULTIPOLYGON(((5 7,5 6,4 6,4 5,4 4,3 4,3 6,3 7,5 7)))"; | ||
|
|
||
| // Cases generating an extra turn, and/or a cluster not yet handled correctly | ||
| static std::string const nores_et_1 | ||
| = "MULTIPOLYGON(((5 7,5 8,6 8,5 7)),((5 4,5 5,6 4,5 4)),((3 6,4 7,4 6,3 6)))"; | ||
|
|
||
| static std::string const nores_et_2 | ||
| = "MULTIPOLYGON(((4 2,5 3,5 2,4 2)),((6 3,6 4,7 4,7 3,6 3)),((7 2,8 3,8 2,7 2)),((4 4,4 5,5 5,5 4,4 4)))"; | ||
|
|
||
| static std::string const nores_et_3 | ||
| = "MULTIPOLYGON(((3 1,3 2,4 2,4 1,3 1)),((5 4,5 3,4 3,5 4)),((5 3,6 2,5 2,5 3)),((8 1,7 1,6 1,7 2,7 3,7.5 2.5,8 3,8 1)))"; | ||
|
|
||
| static std::string const nores_et_4 | ||
| = "MULTIPOLYGON(((4 7,4 8,5 8,5 7,4 7)),((3 5,3 6,4 5,3 5)),((1 6,2 7,2 6,1 6)))"; | ||
|
|
||
| static std::string const nores_et_5 | ||
| = "MULTIPOLYGON(((3 2,3 3,4 3,4 2,3 2)),((0 3,0 4,1 3,0 3)),((2 2,2 1,1 1,2 2)))"; | ||
|
|
||
|
|
||
| // Cases having wrong next turn information, somehow, taking the "i" (intersection), | ||
| // which is wrong for buffer (it should take the "u" like union) | ||
| static std::string const nores_wn_1 | ||
| = "MULTIPOLYGON(((8 3,8 4,9 4,9 3,8 3)),((9 5,9 6,10 5,9 5)),((8 8,9 9,9 8,8 8)),((8 8,8 7,7 7,8 8)))"; | ||
| static std::string const nores_wn_2 | ||
| = "MULTIPOLYGON(((9 5,9 6,10 5,9 5)),((8 8,8 7,7 7,7 8,8 8)),((8 8,9 9,9 8,8 8)))"; | ||
|
|
||
|
|
||
| static std::string const neighbouring | ||
| = "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0)),((10 10,10 20,20 20,20 10,10 10)))"; | ||
|
|
@@ -498,6 +544,23 @@ void test_all() | |
| test_one<multi_polygon_type, polygon_type>("rt_v3", rt_v3, join_round32, end_flat, 22.9158, 1.0); | ||
| test_one<multi_polygon_type, polygon_type>("rt_v4", rt_v4, join_round32, end_flat, 23.4146, 1.0); | ||
|
|
||
| test_one<multi_polygon_type, polygon_type>("nores_mt_1", nores_mt_1, join_round32, end_flat, 13.4113, 1.0); | ||
| test_one<multi_polygon_type, polygon_type>("nores_mt_2", nores_mt_2, join_round32, end_flat, 17.5265, 1.0); | ||
| test_one<multi_polygon_type, polygon_type>("nores_mt_3", nores_mt_3, join_round32, end_flat, 25.6091, 1.0); | ||
| test_one<multi_polygon_type, polygon_type>("nores_mt_4", nores_mt_4, join_round32, end_flat, 26.0946, 1.0); | ||
| test_one<multi_polygon_type, polygon_type>("nores_mt_5", nores_mt_5, join_round32, end_flat, 26.4375, 1.0); | ||
| test_one<multi_polygon_type, polygon_type>("nores_mt_6", nores_mt_6, join_round32, end_flat, 16.9018, 1.0); | ||
|
|
||
| #if defined(BOOST_GEOMETRY_USE_RESCALING) || defined(BOOST_GEOMETRY_TEST_FAILURES) | ||
| test_one<multi_polygon_type, polygon_type>("nores_et_1", nores_et_1, join_round32, end_flat, 18.9866, 1.0); | ||
| test_one<multi_polygon_type, polygon_type>("nores_et_2", nores_et_2, join_round32, end_flat, 23.8389, 1.0); | ||
| test_one<multi_polygon_type, polygon_type>("nores_et_3", nores_et_3, join_round32, end_flat, 26.9030, 1.0); | ||
| test_one<multi_polygon_type, polygon_type>("nores_et_4", nores_et_4, join_round32, end_flat, 19.9626, 1.0); | ||
| test_one<multi_polygon_type, polygon_type>("nores_et_5", nores_et_5, join_round32, end_flat, 19.9615, 1.0); | ||
| test_one<multi_polygon_type, polygon_type>("nores_wn_1", nores_wn_1, join_round32, end_flat, 23.7659, 1.0); | ||
| test_one<multi_polygon_type, polygon_type>("nores_wn_2", nores_wn_2, join_round32, end_flat, 18.2669, 1.0); | ||
| #endif | ||
|
|
||
| test_one<multi_polygon_type, polygon_type>("neighbouring_small", | ||
| neighbouring, | ||
| join_round32, end_round32, 128.0, -1.0); | ||
|
|
@@ -541,7 +604,7 @@ int test_main(int, char* []) | |
| #endif | ||
|
|
||
| #if defined(BOOST_GEOMETRY_TEST_FAILURES) | ||
| BoostGeometryWriteExpectedFailures(1, 1, 2, 3); | ||
| BoostGeometryWriteExpectedFailures(1, 14, 2, 11); | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because it's related to precision, for float these changes were not necessary. |
||
| #endif | ||
|
|
||
| return 0; | ||
|
|
||
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.
This code is relatively simple now, I first had more conditions but they were not relevant in the end.
But I might find cases where some behaviour should be fine-tuned.