Skip to content

Commit

Permalink
convexHullPolygon (#432)
Browse files Browse the repository at this point in the history
## Changes
* `ConvexHullMesh` is broken in Wolfram Language 12.2. It seems that only 1D examples evaluate, 2D and 3D example return unevaluated even if using examples from the documentation.
* This PR adds a replacement for that function, `convexHullPolygon`.

## Comments
* `WolframModelPlot` is completely broken without this function, so this is a critical PR.
* Another PR fixing `WolframModelPlot` is coming shortly.
* There are lots of tests, they are randomly generated, and visually verified.

## Examples
* This is a helper function to verify the polygon:
```wl
testPolygon[pts_] := 
 Show[Graphics[({Opacity[0.4], Line[#], Opacity[0.1], Polygon[#]} &)@
    First@SetReplace`PackageScope`convexHullPolygon[pts]], 
  Graphics[Point[pts]]]
```
* Try it for a 5-points example:
```wl
In[] := testPolygon[{{9, 6}, {8, 7}, {6, 7}, {5, 8}, {8, 2}}]
```
![image](https://user-images.githubusercontent.com/1479325/95256943-2e454c80-07e9-11eb-9f42-73ce596d093d.png)

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/maxitg/setreplace/432)
<!-- Reviewable:end -->
  • Loading branch information
maxitg authored Oct 7, 2020
1 parent 958c46b commit 06bffec
Show file tree
Hide file tree
Showing 2 changed files with 881 additions and 0 deletions.
39 changes: 39 additions & 0 deletions Kernel/convexHullPolygon.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
Package["SetReplace`"]

PackageScope["convexHullPolygon"]

(* Graham scan algorithm, https://en.wikipedia.org/wiki/Graham_scan *)

polarAngle = ArcTan @@ # &;

peekNextToTop[stack_] := With[{
top = stack["Pop"],
nextToTop = stack["Peek"]},
stack["Push", top];
nextToTop
]

(* Returns a positive value for counterclockwise direction, negative for clockwise, and zero otherwise *)
rotationDirection[pt1_, pt2_, pt3_] :=
(pt2[[1]] - pt1[[1]]) (pt3[[2]] - pt2[[2]]) - (pt2[[2]] - pt1[[2]]) (pt3[[1]] - pt2[[1]])

convexHullPolygon[points_] := Module[{
(* Sort is broken for symbolic values in Wolfram Language 12.2 *)
numericPoints = N[points],
stack = CreateDataStructure["Stack"],
center, centeredPoints, counterClockwisePoints, deduplicatedPoints},
(* find a bottommost point, if multiple, find the leftmost one *)
center = First[MinimalBy[MinimalBy[numericPoints, Last], First]];
centeredPoints = # - center & /@ DeleteCases[numericPoints, center, {1}];
counterClockwisePoints = SortBy[centeredPoints, polarAngle];
(* if there are multiple points with the same polar angle, pick the farthest *)
deduplicatedPoints = Values[First /@ MaximalBy[Norm] /@ GroupBy[counterClockwisePoints, polarAngle]];

Scan[(
(* pop the last point from the stack if we turn clockwise to reach this point *)
While[stack["Length"] > 1 && rotationDirection[peekNextToTop[stack], stack["Peek"], #] <= 0, stack["Pop"]];
stack["Push", #]
) &, deduplicatedPoints];

Polygon[Join[{center}, # + center & /@ Normal[stack]]]
]
Loading

0 comments on commit 06bffec

Please sign in to comment.