@@ -411,6 +411,72 @@ def _construct_hull(points, left, right, convex_set):
411
411
_construct_hull (candidate_points , extreme_point , right , convex_set )
412
412
413
413
414
+ def convex_hull_melkman (points ):
415
+ """
416
+ Constructs the convex hull of a set of 2D points using the melkman algorithm.
417
+ The algorithm works by iteratively inserting points of a simple polygonal chain
418
+ (meaning that no line segments between two consecutive points cross each other).
419
+ Sorting the points yields such a polygonal chain.
420
+
421
+ Runtime: O(n log n) - O(n) if points are already sorted in the input
422
+
423
+ Parameters
424
+ ---------
425
+ points: array-like of object of Points, lists or tuples.
426
+ The set of 2d points for which the convex-hull is needed
427
+
428
+ Returns
429
+ ------
430
+ convex_set: list, the convex-hull of points sorted in non-decreasing order.
431
+
432
+ See Also
433
+ --------
434
+
435
+ Examples
436
+ ---------
437
+ >>> convex_hull_melkman([[0, 0], [1, 0], [10, 1]])
438
+ [(0.0, 0.0), (1.0, 0.0), (10.0, 1.0)]
439
+ >>> convex_hull_melkman([[0, 0], [1, 0], [10, 0]])
440
+ [(0.0, 0.0), (10.0, 0.0)]
441
+ >>> convex_hull_melkman([[-1, 1],[-1, -1], [0, 0], [0.5, 0.5], [1, -1], [1, 1],
442
+ ... [-0.75, 1]])
443
+ [(-1.0, -1.0), (-1.0, 1.0), (1.0, -1.0), (1.0, 1.0)]
444
+ >>> convex_hull_melkman([(0, 3), (2, 2), (1, 1), (2, 1), (3, 0), (0, 0), (3, 3),
445
+ ... (2, -1), (2, -4), (1, -3)])
446
+ [(0.0, 0.0), (0.0, 3.0), (1.0, -3.0), (2.0, -4.0), (3.0, 0.0), (3.0, 3.0)]
447
+ """
448
+ points = sorted (_validate_input (points ))
449
+ n = len (points )
450
+
451
+ convex_hull = points [:2 ]
452
+ for i in range (2 , n ):
453
+ det = _det (convex_hull [1 ], convex_hull [0 ], points [i ])
454
+ if det > 0 :
455
+ convex_hull .insert (0 , points [i ])
456
+ break
457
+ elif det < 0 :
458
+ convex_hull .append (points [i ])
459
+ break
460
+ else :
461
+ convex_hull [1 ] = points [i ]
462
+ i += 1
463
+
464
+ for i in range (i , n ):
465
+ if (_det (convex_hull [0 ], convex_hull [- 1 ], points [i ]) > 0
466
+ and _det (convex_hull [- 1 ], convex_hull [0 ], points [1 ]) < 0 ):
467
+ # The point lies within the convex hull
468
+ continue
469
+
470
+ convex_hull .insert (0 , points [i ])
471
+ convex_hull .append (points [i ])
472
+ while _det (convex_hull [0 ], convex_hull [1 ], convex_hull [2 ]) >= 0 :
473
+ del convex_hull [1 ]
474
+ while _det (convex_hull [- 1 ], convex_hull [- 2 ], convex_hull [- 3 ]) <= 0 :
475
+ del convex_hull [- 2 ]
476
+
477
+ # `convex_hull` is contains the convex hull in circular order
478
+ return sorted (convex_hull [1 :] if len (convex_hull ) > 3 else convex_hull )
479
+
414
480
def main ():
415
481
points = [
416
482
(0 , 3 ),
@@ -426,10 +492,14 @@ def main():
426
492
]
427
493
# the convex set of points is
428
494
# [(0, 0), (0, 3), (1, -3), (2, -4), (3, 0), (3, 3)]
429
- results_recursive = convex_hull_recursive (points )
430
495
results_bf = convex_hull_bf (points )
496
+
497
+ results_recursive = convex_hull_recursive (points )
431
498
assert results_bf == results_recursive
432
499
500
+ results_melkman = convex_hull_melkman (points )
501
+ assert results_bf == results_melkman
502
+
433
503
print (results_bf )
434
504
435
505
0 commit comments