Polygon class
class Polygon {
 final List<Point> points;
 Polygon(List<Point> points) : points = points.toList(growable: false) {
   if (this.points.length < 3) {
     throw new ArgumentError("Please provide three or more points.");
   }
 }
 //-----------------------------------------------------------------------------------------------
 //-----------------------------------------------------------------------------------------------
 bool isSimple() {
   int length = points.length;
   if (length <= 3) return true;
   for(int i = 0; i < length; i++) {
     Point a1 = points[i];
     Point a2 = points[(i == length - 1) ? 0 : i];
     for(int j = 0; j < length; j++) {
       if ((i - j).abs() < 2) continue;
       if (j == length - 1 && i == 0) continue;
       if (i == length - 1 && j == 0) continue;
       Point b1 = points[j];
       Point b2 = points[(j == length - 1) ? 0 : j];
       if(_getLineIntersection(a1, a2, b1, b2) != null) return false;
     }
   }
   return true;
 }
 //-----------------------------------------------------------------------------------------------
 bool isConvex()  {
   int length = points.length;
   if (length <= 3) return true;
   for(int i = 0; i < length; i++) {
     Point p1 = points[(i + 0) % length];
     Point p2 = points[(i + 1) % length];
     Point p3 = points[(i + 2) % length];
     if(!_convex(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y)) return false;
   }
   return true;
 }
 //-----------------------------------------------------------------------------------------------
 Rectangle getBounds() {
   num maxX = double.NEGATIVE_INFINITY;
   num minX = double.INFINITY;
   num maxY = double.NEGATIVE_INFINITY;
   num minY = double.INFINITY;
   for(int i = 0; i < points.length; i++) {
     Point point = points[i];
     maxX = max(maxX, point.x);
     minX = min(minX, point.x);
     maxY = max(maxY, point.y);
     minY = min(minY, point.y);
   }
   return new Rectangle(minX, minY, maxX - minX, maxY - minY);
 }
 //-----------------------------------------------------------------------------------------------
 List<int> triangulate() {
   int i = 0;
   int al = points.length;
   List<int> result = new List<int>();
   List<int> available = new List<int>();
   for(int p = 0; p < points.length; p++) {
     available.add(p);
   }
   while(al > 3) {
     int i0 = available[(i + 0) % al];
     int i1 = available[(i + 1) % al];
     int i2 = available[(i + 2) % al];
     num ax = points[i0].x;
     num ay = points[i0].y;
     num bx = points[i1].x;
     num by = points[i1].y;
     num cx = points[i2].x;
     num cy = points[i2].y;
     bool earFound = false;
     if(_convex(ax, ay, bx, by, cx, cy)) {
       earFound = true;
       for(int j = 0; j < al; j++) {
         int vi = available[j];
         if(vi == i0 || vi == i1 || vi == i2) continue;
         if(_pointInTriangle(points[vi].x, points[vi].y, ax, ay, bx, by, cx, cy)) {
           earFound = false;
           break;
         }
       }
     }
     if(earFound) {
       result.addAll([i0, i1, i2]);
       available.removeAt((i + 1) % al);
       al--;
       i = 0;
     } else if(i++ > 3 * al) {
       break; // no convex angles :(
     }
   }
   result.addAll([available[0], available[1], available[2]]);
   return result;
 }
 //-----------------------------------------------------------------------------------------------
 bool contains(num px, num py) {
   num ax = 0;
   num ay = 0;
   num bx = points[points.length - 1].x - px;
   num by = points[points.length - 1].y - py;
   int depth = 0;
   for(int i = 0; i < points.length; i++) {
     ax = bx;
     ay = by;
     bx = points[i].x - px;
     by = points[i].y - py;
     if (ay < 0 && by < 0) continue;  // both "up" or both "down"
     if (ay > 0 && by > 0) continue;  // both "up" or both "down"
     if (ax < 0 && bx < 0) continue;  // both points on left
     num lx = ax - ay * (bx - ax) / (by - ay);
     if (lx == 0) return true;        // point on edge
     if (lx > 0) depth++;
   }
   return (depth & 1) == 1;
 }
 //-----------------------------------------------------------------------------------------------
 bool _inRect(Point point, Point a1, Point a2) {
   if  (a1.x == a2.x) return point.y >= min(a1.y, a2.y) && point.y <= max(a1.y, a2.y);
   if  (a1.y == a2.y) return point.x >= min(a1.x, a2.x) && point.x <= max(a1.x, a2.x);
   return
       point.x >= min(a1.x, a2.x) && point.x <= max(a1.x, a2.x) &&
       point.y >= min(a1.y, a2.y) && point.y <= max(a1.y, a2.y);
 }
 //-----------------------------------------------------------------------------------------------
 Point _getLineIntersection(Point a1, Point a2, Point b1, Point b2) {
   num dax = (a1.x - a2.x);
   num dbx = (b1.x - b2.x);
   num day = (a1.y - a2.y);
   num dby = (b1.y - b2.y);
   num den = dax * dby - day * dbx;
   if (den == 0) return null;  // parallel
   num a = (a1.x * a2.y - a1.y * a2.x);
   num b = (b1.x * b2.y - b1.y * b2.x);
   num x = (a * dbx - dax * b ) / den;
   num y = (a * dby - day * b ) / den;
   Point point = new Point(x, y);
   return _inRect(point, a1, a2) && _inRect(point, b1, b2) ? point : null;
 }
 //-----------------------------------------------------------------------------------------------
 bool _convex(num ax, num ay, num bx, num by, num cx, num cy) {
   return (ay - by) * (cx - bx) + (bx - ax) * (cy - by) >= 0;
 }
 //-----------------------------------------------------------------------------------------------
 bool _pointInTriangle (num px, num py, num ax, num ay, num bx, num by, num cx, num cy) {
   num v0x = cx - ax;
   num v0y = cy - ay;
   num v1x = bx - ax;
   num v1y = by - ay;
   num v2x = px - ax;
   num v2y = py - ay;
   num dot00 = v0x * v0x + v0y * v0y;
   num dot01 = v0x * v1x + v0y * v1y;
   num dot02 = v0x * v2x + v0y * v2y;
   num dot11 = v1x * v1x + v1y * v1y;
   num dot12 = v1x * v2x + v1y * v2y;
   num invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
   num u = (dot11 * dot02 - dot01 * dot12) * invDenom;
   num v = (dot00 * dot12 - dot01 * dot02) * invDenom;
   return (u >= 0) && (v >= 0) && (u + v < 1);
 }
}
Constructors
new Polygon(List<Point> points) #
Creates a new Object instance.
Object instances have no meaningful state, and are only useful through their identity. An Object instance is equal to itself only.
docs inherited from Object 
Polygon(List<Point> points) : points = points.toList(growable: false) {
 if (this.points.length < 3) {
   throw new ArgumentError("Please provide three or more points.");
 }
}
Methods
bool contains(num px, num py) #
bool contains(num px, num py) {
 num ax = 0;
 num ay = 0;
 num bx = points[points.length - 1].x - px;
 num by = points[points.length - 1].y - py;
 int depth = 0;
 for(int i = 0; i < points.length; i++) {
   ax = bx;
   ay = by;
   bx = points[i].x - px;
   by = points[i].y - py;
   if (ay < 0 && by < 0) continue;  // both "up" or both "down"
   if (ay > 0 && by > 0) continue;  // both "up" or both "down"
   if (ax < 0 && bx < 0) continue;  // both points on left
   num lx = ax - ay * (bx - ax) / (by - ay);
   if (lx == 0) return true;        // point on edge
   if (lx > 0) depth++;
 }
 return (depth & 1) == 1;
}
Rectangle getBounds() #
Rectangle getBounds() {
 num maxX = double.NEGATIVE_INFINITY;
 num minX = double.INFINITY;
 num maxY = double.NEGATIVE_INFINITY;
 num minY = double.INFINITY;
 for(int i = 0; i < points.length; i++) {
   Point point = points[i];
   maxX = max(maxX, point.x);
   minX = min(minX, point.x);
   maxY = max(maxY, point.y);
   minY = min(minY, point.y);
 }
 return new Rectangle(minX, minY, maxX - minX, maxY - minY);
}
bool isConvex() #
bool isConvex()  {
 int length = points.length;
 if (length <= 3) return true;
 for(int i = 0; i < length; i++) {
   Point p1 = points[(i + 0) % length];
   Point p2 = points[(i + 1) % length];
   Point p3 = points[(i + 2) % length];
   if(!_convex(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y)) return false;
 }
 return true;
}
bool isSimple() #
bool isSimple() {
 int length = points.length;
 if (length <= 3) return true;
 for(int i = 0; i < length; i++) {
   Point a1 = points[i];
   Point a2 = points[(i == length - 1) ? 0 : i];
   for(int j = 0; j < length; j++) {
     if ((i - j).abs() < 2) continue;
     if (j == length - 1 && i == 0) continue;
     if (i == length - 1 && j == 0) continue;
     Point b1 = points[j];
     Point b2 = points[(j == length - 1) ? 0 : j];
     if(_getLineIntersection(a1, a2, b1, b2) != null) return false;
   }
 }
 return true;
}
List<int> triangulate() #
List<int> triangulate() {
 int i = 0;
 int al = points.length;
 List<int> result = new List<int>();
 List<int> available = new List<int>();
 for(int p = 0; p < points.length; p++) {
   available.add(p);
 }
 while(al > 3) {
   int i0 = available[(i + 0) % al];
   int i1 = available[(i + 1) % al];
   int i2 = available[(i + 2) % al];
   num ax = points[i0].x;
   num ay = points[i0].y;
   num bx = points[i1].x;
   num by = points[i1].y;
   num cx = points[i2].x;
   num cy = points[i2].y;
   bool earFound = false;
   if(_convex(ax, ay, bx, by, cx, cy)) {
     earFound = true;
     for(int j = 0; j < al; j++) {
       int vi = available[j];
       if(vi == i0 || vi == i1 || vi == i2) continue;
       if(_pointInTriangle(points[vi].x, points[vi].y, ax, ay, bx, by, cx, cy)) {
         earFound = false;
         break;
       }
     }
   }
   if(earFound) {
     result.addAll([i0, i1, i2]);
     available.removeAt((i + 1) % al);
     al--;
     i = 0;
   } else if(i++ > 3 * al) {
     break; // no convex angles :(
   }
 }
 result.addAll([available[0], available[1], available[2]]);
 return result;
}