@@ -297,7 +297,7 @@ bool MergableRoadDetector::HaveSameDirection(const NodeID intersection_node,
297297
298298 // many roads only do short parallel segments. To get a good impression of how `parallel` two
299299 // roads are, we look 100 meters down the road (wich can be quite short for very broad roads).
300- const double constexpr distance_to_extract = 100 ;
300+ const double constexpr distance_to_extract = 150 ;
301301
302302 std::tie (distance_traversed_to_the_left, coordinates_to_the_left) =
303303 getCoordinatesAlongWay (lhs.eid , distance_to_extract);
@@ -317,6 +317,36 @@ bool MergableRoadDetector::HaveSameDirection(const NodeID intersection_node,
317317
318318 const auto connect_again = (coordinates_to_the_left.back () == coordinates_to_the_right.back ());
319319
320+ // Tuning parameter to detect and don't merge roads close to circular shapes
321+ // if the area to squared circumference ratio is between the lower bound and 1/(4π)
322+ // that correspond to isoperimetric inequality 4πA ≤ L² or lower bound ≤ A/L² ≤ 1/(4π).
323+ // The lower bound must be larger enough to allow merging of square-shaped intersections
324+ // with A/L² = 1/16 or 78.6%
325+ // The condition suppresses roads merging for intersections like
326+ // . .
327+ // . .
328+ // ---- ----
329+ // . .
330+ // . .
331+ // but will allow roads merging for intersections like
332+ // -------
333+ // / \
334+ // ---- ----
335+ // \ /
336+ // -------
337+ const auto constexpr CIRCULAR_POLYGON_ISOPERIMETRIC_LOWER_BOUND = 0.85 / (4 * M_PI);
338+ if (connect_again && coordinates_to_the_left.front () == coordinates_to_the_left.back ())
339+ { // if the left and right roads connect again and are closed polygons ...
340+ const auto area = util::coordinate_calculation::computeArea (coordinates_to_the_left);
341+ const auto perimeter = distance_traversed_to_the_left;
342+ const auto area_to_squared_perimeter_ratio = std::abs (area) / (perimeter * perimeter);
343+
344+ // then don't merge roads if A/L² is greater than the lower bound
345+ BOOST_ASSERT (area_to_squared_perimeter_ratio <= 1 . / (4 * M_PI));
346+ if (area_to_squared_perimeter_ratio >= CIRCULAR_POLYGON_ISOPERIMETRIC_LOWER_BOUND)
347+ return false ;
348+ }
349+
320350 // sampling to correctly weight longer segments in regression calculations
321351 const auto constexpr SAMPLE_INTERVAL = 5 ;
322352 coordinates_to_the_left = coordinate_extractor.SampleCoordinates (
0 commit comments