From 6c5d4065c2483a5ab74bc35242eefa62f4fa660c Mon Sep 17 00:00:00 2001
From: Jonathan Deutsch <jonathan@tumult.com>
Date: Thu, 26 Jul 2018 14:33:39 -0700
Subject: [PATCH] Add removeDuplicatePoints option from polygon-decomp 0.3.0 to
 Bodies.fromVertices()

---
 demo/lib/decomp.js    | 66 ++++++++++++++++++++++++++++++++++++++++---
 src/factory/Bodies.js |  6 +++-
 2 files changed, 67 insertions(+), 5 deletions(-)

diff --git a/demo/lib/decomp.js b/demo/lib/decomp.js
index 6119908..ffd33bd 100644
--- a/demo/lib/decomp.js
+++ b/demo/lib/decomp.js
@@ -4,6 +4,7 @@ module.exports = {
     quickDecomp: polygonQuickDecomp,
     isSimple: polygonIsSimple,
     removeCollinearPoints: polygonRemoveCollinearPoints,
+    removeDuplicatePoints: polygonRemoveDuplicatePoints,
     makeCCW: polygonMakeCCW
 };
 
@@ -179,6 +180,9 @@ function polygonMakeCCW(polygon){
     // reverse poly if clockwise
     if (!isLeft(polygonAt(polygon, br - 1), polygonAt(polygon, br), polygonAt(polygon, br + 1))) {
         polygonReverse(polygon);
+        return true;
+    } else {
+        return false;
     }
 }
 
@@ -243,6 +247,27 @@ function polygonCanSee(polygon, a,b) {
     return true;
 }
 
+/**
+ * Check if two vertices in the polygon can see each other
+ * @method canSee2
+ * @param  {Number} a Vertex index 1
+ * @param  {Number} b Vertex index 2
+ * @return {Boolean}
+ */
+function polygonCanSee2(polygon, a,b) {
+    // for each edge
+    for (var i = 0; i !== polygon.length; ++i) {
+        // ignore incident edges
+        if (i === a || i === b || (i + 1) % polygon.length === a || (i + 1) % polygon.length === b){
+            continue;
+        }
+        if( lineSegmentsIntersect(polygonAt(polygon, a), polygonAt(polygon, b), polygonAt(polygon, i), polygonAt(polygon, i+1)) ){
+            return false;
+        }
+    }
+    return true;
+}
+
 /**
  * Copy the polygon from vertex i to vertex j.
  * @method copy
@@ -526,9 +551,12 @@ function polygonQuickDecomp(polygon, result,reflexVertices,steinerPoints,delta,m
                 }
 
                 for (var j = lowerIndex; j <= upperIndex; ++j) {
-                    if (isLeftOn(polygonAt(poly, i - 1), polygonAt(poly, i), polygonAt(poly, j)) && isRightOn(polygonAt(poly, i + 1), polygonAt(poly, i), polygonAt(poly, j))) {
+                    if (
+                        isLeftOn(polygonAt(poly, i - 1), polygonAt(poly, i), polygonAt(poly, j)) &&
+                        isRightOn(polygonAt(poly, i + 1), polygonAt(poly, i), polygonAt(poly, j))
+                    ) {
                         d = sqdist(polygonAt(poly, i), polygonAt(poly, j));
-                        if (d < closestDist) {
+                        if (d < closestDist && polygonCanSee2(poly, i, j)) {
                             closestDist = d;
                             closestIndex = j % polygon.length;
                         }
@@ -585,6 +613,23 @@ function polygonRemoveCollinearPoints(polygon, precision){
     return num;
 }
 
+/**
+ * Remove duplicate points in the polygon.
+ * @method removeDuplicatePoints
+ * @param  {Number} [precision] The threshold to use when determining whether two points are the same. Use zero for best precision.
+ */
+function polygonRemoveDuplicatePoints(polygon, precision){
+    for(var i=polygon.length-1; i>=1; --i){
+        var pi = polygon[i];
+        for(var j=i-1; j>=0; --j){
+            if(points_eq(pi, polygon[j], precision)){
+                polygon.splice(i,1);
+                continue;
+            }
+        }
+    }
+}
+
 /**
  * Check if two scalars are equal
  * @static
@@ -596,9 +641,22 @@ function polygonRemoveCollinearPoints(polygon, precision){
  */
 function scalar_eq(a,b,precision){
     precision = precision || 0;
-    return Math.abs(a-b) < precision;
+    return Math.abs(a-b) <= precision;
+}
+
+/**
+ * Check if two points are equal
+ * @static
+ * @method points_eq
+ * @param  {Array} a
+ * @param  {Array} b
+ * @param  {Number} [precision]
+ * @return {Boolean}
+ */
+function points_eq(a,b,precision){
+    return scalar_eq(a[0],b[0],precision) && scalar_eq(a[1],b[1],precision);
 }
 
 },{}]},{},[1])
 (1)
-});
+});
\ No newline at end of file
diff --git a/src/factory/Bodies.js b/src/factory/Bodies.js
index d1edd68..9fe191d 100644
--- a/src/factory/Bodies.js
+++ b/src/factory/Bodies.js
@@ -194,9 +194,10 @@ var decomp;
      * @param {bool} [flagInternal=false]
      * @param {number} [removeCollinear=0.01]
      * @param {number} [minimumArea=10]
+     * @param {number} [removeDuplicatePoints=0.1]
      * @return {body}
      */
-    Bodies.fromVertices = function(x, y, vertexSets, options, flagInternal, removeCollinear, minimumArea) {
+    Bodies.fromVertices = function(x, y, vertexSets, options, flagInternal, removeCollinear, minimumArea, removeDuplicatePoints) {
         if (!decomp) {
             decomp = Common._requireGlobal('decomp', 'poly-decomp');
         }
@@ -217,6 +218,7 @@ var decomp;
         flagInternal = typeof flagInternal !== 'undefined' ? flagInternal : false;
         removeCollinear = typeof removeCollinear !== 'undefined' ? removeCollinear : 0.01;
         minimumArea = typeof minimumArea !== 'undefined' ? minimumArea : 10;
+        removeDuplicatePoints = typeof removeDuplicatePoints !== 'undefined' ? removeDuplicatePoints : 0.1;
 
         if (!decomp) {
             Common.warn('Bodies.fromVertices: poly-decomp.js required. Could not decompose vertices. Fallback to convex hull.');
@@ -253,6 +255,8 @@ var decomp;
                 decomp.makeCCW(concave);
                 if (removeCollinear !== false)
                     decomp.removeCollinearPoints(concave, removeCollinear);
+                if (removeDuplicatePoints !== false)
+                    decomp.removeDuplicatePoints(concave, removeDuplicatePoints);
 
                 // use the quick decomposition algorithm (Bayazit)
                 var decomposed = decomp.quickDecomp(concave);