Skip to content

Instantly share code, notes, and snippets.

@nraynaud
Created October 14, 2013 09:05
Show Gist options
  • Save nraynaud/6972980 to your computer and use it in GitHub Desktop.
Save nraynaud/6972980 to your computer and use it in GitHub Desktop.
Testing clipper algo change.
//instrumented by nraynaud for testing purpose
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 5.0.2 *
* Date : 30 December 2012 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2012 *
* *
* License: *
* Use, modification & distribution is subject to Boost Software License Ver 1. *
* http://www.boost.org/LICENSE_1_0.txt *
* *
* Attributions: *
* The code in this library is an extension of Bala Vatti's clipping algorithm: *
* "A generic solution to polygon clipping" *
* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. *
* http://portal.acm.org/citation.cfm?id=129906 *
* *
* Computer graphics and geometric modeling: implementation and algorithms *
* By Max K. Agoston *
* Springer; 1 edition (January 4, 2005) *
* http://books.google.com/books?q=vatti+clipping+agoston *
* *
* See also: *
* "Polygon Offsetting by Computing Winding Numbers" *
* Paper no. DETC2005-85513 pp. 565-575 *
* ASME 2005 International Design Engineering Technical Conferences *
* and Computers and Information in Engineering Conference (IDETC/CIE2005) *
* September 24�28, 2005 , Long Beach, California, USA *
* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf *
* *
*******************************************************************************/
/*******************************************************************************
* *
* Author : Timo *
* Version : 5.0.2.2 *
* Date : 11 September 2013 *
* *
* This is a translation of the C# Clipper library to Javascript. *
* Int128 struct of C# is implemented using JSBN of Tom Wu. *
* Because Javascript lacks support for 64-bit integers, the space *
* is a little more restricted than in C# version. *
* *
* C# version has support for coordinate space: *
* +-4611686018427387903 ( sqrt(2^127 -1)/2 ) *
* while Javascript version has support for space: *
* +-4503599627370495 ( sqrt(2^106 -1)/2 ) *
* *
* Tom Wu's JSBN proved to be the fastest big integer library: *
* http://jsperf.com/big-integer-library-test *
* *
* This class can be made simpler when (if ever) 64-bit integer support comes. *
* *
*******************************************************************************/
/*******************************************************************************
* *
* Basic JavaScript BN library - subset useful for RSA encryption. *
* http://www-cs-students.stanford.edu/~tjw/jsbn/ *
* Copyright (c) 2005 Tom Wu *
* All Rights Reserved. *
* See "LICENSE" for details: *
* http://www-cs-students.stanford.edu/~tjw/jsbn/LICENSE *
* *
*******************************************************************************/
(function () {
// "use strict";
// Browser test to speedup performance critical functions
var nav = navigator.userAgent.toString().toLowerCase();
var browser = {};
if (nav.indexOf("chrome") != -1 && nav.indexOf("chromium") == -1) browser.chrome = 1; else browser.chrome = 0;
if (nav.indexOf("chromium") != -1) browser.chromium = 1; else browser.chromium = 0;
if (nav.indexOf("safari") != -1 && nav.indexOf("chrome") == -1 && nav.indexOf("chromium") == -1) browser.safari = 1; else browser.safari = 0;
if (nav.indexOf("firefox") != -1) browser.firefox = 1; else browser.firefox = 0;
if (nav.indexOf("firefox/17") != -1) browser.firefox17 = 1; else browser.firefox17 = 0;
if (nav.indexOf("firefox/15") != -1) browser.firefox15 = 1; else browser.firefox15 = 0;
if (nav.indexOf("firefox/3") != -1) browser.firefox3 = 1; else browser.firefox3 = 0;
if (nav.indexOf("opera") != -1) browser.opera = 1; else browser.opera = 0;
if (nav.indexOf("msie 10") != -1) browser.msie10 = 1; else browser.msie10 = 0;
if (nav.indexOf("msie 9") != -1) browser.msie9 = 1; else browser.msie9 = 0;
if (nav.indexOf("msie 8") != -1) browser.msie8 = 1; else browser.msie8 = 0;
if (nav.indexOf("msie 7") != -1) browser.msie7 = 1; else browser.msie7 = 0;
if (nav.indexOf("msie ") != -1) browser.msie = 1; else browser.msie = 0;
var ClipperLib = {};
ClipperLib.biginteger_used = null;
// Bits per digit
var dbits;
// JavaScript engine analysis
var canary = 0xdeadbeefcafe;
var j_lm = ((canary & 0xffffff) == 0xefcafe);
// (public) Constructor
function Int128(a, b, c) {
// This test variable can be removed,
// but at least for performance tests it is useful piece of knowledge
// This is the only ClipperLib related variable in Int128 library
ClipperLib.biginteger_used = 1;
if (a != null) if ("number" == typeof a) {
this.fromString(Math.floor(a)
.toString(), 10); //this.fromNumber(a,b,c);
}
else if (b == null && "string" != typeof a) this.fromString(a, 256);
else {
if (a.indexOf(".") != -1) a = a.substring(0, a.indexOf("."));
this.fromString(a, b);
}
}
// return new, unset Int128
function nbi() {
return new Int128(null);
}
// am: Compute w_j += (x*this_i), propagate carries,
// c is initial carry, returns final carry.
// c < 3*dvalue, x < 2*dvalue, this_i < dvalue
// We need to select the fastest one that works in this environment.
// am1: use a single mult and divide to get the high bits,
// max digit bits should be 26 because
// max internal value = 2*dvalue^2-2*dvalue (< 2^53)
function am1(i, x, w, j, c, n) {
while (--n >= 0) {
var v = x * this[i++] + w[j] + c;
c = Math.floor(v / 0x4000000);
w[j++] = v & 0x3ffffff;
}
return c;
}
// am2 avoids a big mult-and-extract completely.
// Max digit bits should be <= 30 because we do bitwise ops
// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)
function am2(i, x, w, j, c, n) {
var xl = x & 0x7fff,
xh = x >> 15;
while (--n >= 0) {
var l = this[i] & 0x7fff;
var h = this[i++] >> 15;
var m = xh * l + h * xl;
l = xl * l + ((m & 0x7fff) << 15) + w[j] + (c & 0x3fffffff);
c = (l >>> 30) + (m >>> 15) + xh * h + (c >>> 30);
w[j++] = l & 0x3fffffff;
}
return c;
}
// Alternately, set max digit bits to 28 since some
// browsers slow down when dealing with 32-bit numbers.
function am3(i, x, w, j, c, n) {
var xl = x & 0x3fff,
xh = x >> 14;
while (--n >= 0) {
var l = this[i] & 0x3fff;
var h = this[i++] >> 14;
var m = xh * l + h * xl;
l = xl * l + ((m & 0x3fff) << 14) + w[j] + c;
c = (l >> 28) + (m >> 14) + xh * h;
w[j++] = l & 0xfffffff;
}
return c;
}
if (j_lm && (navigator.appName == "Microsoft Internet Explorer")) {
Int128.prototype.am = am2;
dbits = 30;
}
else if (j_lm && (navigator.appName != "Netscape")) {
Int128.prototype.am = am1;
dbits = 26;
}
else { // Mozilla/Netscape seems to prefer am3
Int128.prototype.am = am3;
dbits = 28;
}
Int128.prototype.DB = dbits;
Int128.prototype.DM = ((1 << dbits) - 1);
Int128.prototype.DV = (1 << dbits);
var BI_FP = 52;
Int128.prototype.FV = Math.pow(2, BI_FP);
Int128.prototype.F1 = BI_FP - dbits;
Int128.prototype.F2 = 2 * dbits - BI_FP;
// Digit conversions
var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
var BI_RC = [];
var rr, vv;
rr = "0".charCodeAt(0);
for (vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv;
rr = "a".charCodeAt(0);
for (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
rr = "A".charCodeAt(0);
for (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
function int2char(n) {
return BI_RM.charAt(n);
}
function intAt(s, i) {
var c = BI_RC[s.charCodeAt(i)];
return (c == null) ? -1 : c;
}
// (protected) copy this to r
function bnpCopyTo(r) {
for (var i = this.t - 1; i >= 0; --i) r[i] = this[i];
r.t = this.t;
r.s = this.s;
}
// (protected) set from integer value x, -DV <= x < DV
function bnpFromInt(x) {
this.t = 1;
this.s = (x < 0) ? -1 : 0;
if (x > 0) this[0] = x;
else if (x < -1) this[0] = x + this.DV;
else this.t = 0;
}
// return bigint initialized to value
function nbv(i) {
var r = nbi();
r.fromInt(i);
return r;
}
// (protected) set from string and radix
function bnpFromString(s, b) {
var k;
if (b == 16) k = 4;
else if (b == 8) k = 3;
else if (b == 256) k = 8; // byte array
else if (b == 2) k = 1;
else if (b == 32) k = 5;
else if (b == 4) k = 2;
else {
this.fromRadix(s, b);
return;
}
this.t = 0;
this.s = 0;
var i = s.length,
mi = false,
sh = 0;
while (--i >= 0) {
var x = (k == 8) ? s[i] & 0xff : intAt(s, i);
if (x < 0) {
if (s.charAt(i) == "-") mi = true;
continue;
}
mi = false;
if (sh == 0) this[this.t++] = x;
else if (sh + k > this.DB) {
this[this.t - 1] |= (x & ((1 << (this.DB - sh)) - 1)) << sh;
this[this.t++] = (x >> (this.DB - sh));
}
else this[this.t - 1] |= x << sh;
sh += k;
if (sh >= this.DB) sh -= this.DB;
}
if (k == 8 && (s[0] & 0x80) != 0) {
this.s = -1;
if (sh > 0) this[this.t - 1] |= ((1 << (this.DB - sh)) - 1) << sh;
}
this.clamp();
if (mi) Int128.ZERO.subTo(this, this);
}
// (protected) clamp off excess high words
function bnpClamp() {
var c = this.s & this.DM;
while (this.t > 0 && this[this.t - 1] == c)--this.t;
}
// (public) return string representation in given radix
function bnToString(b) {
if (this.s < 0) return "-" + this.negate()
.toString(b);
var k;
if (b == 16) k = 4;
else if (b == 8) k = 3;
else if (b == 2) k = 1;
else if (b == 32) k = 5;
else if (b == 4) k = 2;
else return this.toRadix(b);
var km = (1 << k) - 1,
d, m = false,
r = "",
i = this.t;
var p = this.DB - (i * this.DB) % k;
if (i-- > 0) {
if (p < this.DB && (d = this[i] >> p) > 0) {
m = true;
r = int2char(d);
}
while (i >= 0) {
if (p < k) {
d = (this[i] & ((1 << p) - 1)) << (k - p);
d |= this[--i] >> (p += this.DB - k);
}
else {
d = (this[i] >> (p -= k)) & km;
if (p <= 0) {
p += this.DB;
--i;
}
}
if (d > 0) m = true;
if (m) r += int2char(d);
}
}
return m ? r : "0";
}
// (public) -this
function bnNegate() {
var r = nbi();
Int128.ZERO.subTo(this, r);
return r;
}
// (public) |this|
function bnAbs() {
return (this.s < 0) ? this.negate() : this;
}
// (public) return + if this > a, - if this < a, 0 if equal
function bnCompareTo(a) {
var r = this.s - a.s;
if (r != 0) return r;
var i = this.t;
r = i - a.t;
if (r != 0) return (this.s < 0) ? -r : r;
while (--i >= 0) if ((r = this[i] - a[i]) != 0) return r;
return 0;
}
// returns bit length of the integer x
function nbits(x) {
var r = 1,
t;
if ((t = x >>> 16) != 0) {
x = t;
r += 16;
}
if ((t = x >> 8) != 0) {
x = t;
r += 8;
}
if ((t = x >> 4) != 0) {
x = t;
r += 4;
}
if ((t = x >> 2) != 0) {
x = t;
r += 2;
}
if ((t = x >> 1) != 0) {
x = t;
r += 1;
}
return r;
}
// (public) return the number of bits in "this"
function bnBitLength() {
if (this.t <= 0) return 0;
return this.DB * (this.t - 1) + nbits(this[this.t - 1] ^ (this.s & this.DM));
}
// (protected) r = this << n*DB
function bnpDLShiftTo(n, r) {
var i;
for (i = this.t - 1; i >= 0; --i) r[i + n] = this[i];
for (i = n - 1; i >= 0; --i) r[i] = 0;
r.t = this.t + n;
r.s = this.s;
}
// (protected) r = this >> n*DB
function bnpDRShiftTo(n, r) {
for (var i = n; i < this.t; ++i) r[i - n] = this[i];
r.t = Math.max(this.t - n, 0);
r.s = this.s;
}
// (protected) r = this << n
function bnpLShiftTo(n, r) {
var bs = n % this.DB;
var cbs = this.DB - bs;
var bm = (1 << cbs) - 1;
var ds = Math.floor(n / this.DB),
c = (this.s << bs) & this.DM,
i;
for (i = this.t - 1; i >= 0; --i) {
r[i + ds + 1] = (this[i] >> cbs) | c;
c = (this[i] & bm) << bs;
}
for (i = ds - 1; i >= 0; --i) r[i] = 0;
r[ds] = c;
r.t = this.t + ds + 1;
r.s = this.s;
r.clamp();
}
// (protected) r = this >> n
function bnpRShiftTo(n, r) {
r.s = this.s;
var ds = Math.floor(n / this.DB);
if (ds >= this.t) {
r.t = 0;
return;
}
var bs = n % this.DB;
var cbs = this.DB - bs;
var bm = (1 << bs) - 1;
r[0] = this[ds] >> bs;
for (var i = ds + 1; i < this.t; ++i) {
r[i - ds - 1] |= (this[i] & bm) << cbs;
r[i - ds] = this[i] >> bs;
}
if (bs > 0) r[this.t - ds - 1] |= (this.s & bm) << cbs;
r.t = this.t - ds;
r.clamp();
}
// (protected) r = this - a
function bnpSubTo(a, r) {
var i = 0,
c = 0,
m = Math.min(a.t, this.t);
while (i < m) {
c += this[i] - a[i];
r[i++] = c & this.DM;
c >>= this.DB;
}
if (a.t < this.t) {
c -= a.s;
while (i < this.t) {
c += this[i];
r[i++] = c & this.DM;
c >>= this.DB;
}
c += this.s;
}
else {
c += this.s;
while (i < a.t) {
c -= a[i];
r[i++] = c & this.DM;
c >>= this.DB;
}
c -= a.s;
}
r.s = (c < 0) ? -1 : 0;
if (c < -1) r[i++] = this.DV + c;
else if (c > 0) r[i++] = c;
r.t = i;
r.clamp();
}
// (protected) r = this * a, r != this,a (HAC 14.12)
// "this" should be the larger one if appropriate.
function bnpMultiplyTo(a, r) {
var x = this.abs(),
y = a.abs();
var i = x.t;
r.t = i + y.t;
while (--i >= 0) r[i] = 0;
for (i = 0; i < y.t; ++i) r[i + x.t] = x.am(0, y[i], r, i, 0, x.t);
r.s = 0;
r.clamp();
if (this.s != a.s) Int128.ZERO.subTo(r, r);
}
// (protected) r = this^2, r != this (HAC 14.16)
function bnpSquareTo(r) {
var x = this.abs();
var i = r.t = 2 * x.t;
while (--i >= 0) r[i] = 0;
for (i = 0; i < x.t - 1; ++i) {
var c = x.am(i, x[i], r, 2 * i, 0, 1);
if ((r[i + x.t] += x.am(i + 1, 2 * x[i], r, 2 * i + 1, c, x.t - i - 1)) >= x.DV) {
r[i + x.t] -= x.DV;
r[i + x.t + 1] = 1;
}
}
if (r.t > 0) r[r.t - 1] += x.am(i, x[i], r, 2 * i, 0, 1);
r.s = 0;
r.clamp();
}
// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)
// r != q, this != m. q or r may be null.
function bnpDivRemTo(m, q, r) {
var pm = m.abs();
if (pm.t <= 0) return;
var pt = this.abs();
if (pt.t < pm.t) {
if (q != null) q.fromInt(0);
if (r != null) this.copyTo(r);
return;
}
if (r == null) r = nbi();
var y = nbi(),
ts = this.s,
ms = m.s;
var nsh = this.DB - nbits(pm[pm.t - 1]); // normalize modulus
if (nsh > 0) {
pm.lShiftTo(nsh, y);
pt.lShiftTo(nsh, r);
}
else {
pm.copyTo(y);
pt.copyTo(r);
}
var ys = y.t;
var y0 = y[ys - 1];
if (y0 == 0) return;
var yt = y0 * (1 << this.F1) + ((ys > 1) ? y[ys - 2] >> this.F2 : 0);
var d1 = this.FV / yt,
d2 = (1 << this.F1) / yt,
e = 1 << this.F2;
var i = r.t,
j = i - ys,
t = (q == null) ? nbi() : q;
y.dlShiftTo(j, t);
if (r.compareTo(t) >= 0) {
r[r.t++] = 1;
r.subTo(t, r);
}
Int128.ONE.dlShiftTo(ys, t);
t.subTo(y, y); // "negative" y so we can replace sub with am later
while (y.t < ys) y[y.t++] = 0;
while (--j >= 0) {
// Estimate quotient digit
var qd = (r[--i] == y0) ? this.DM : Math.floor(r[i] * d1 + (r[i - 1] + e) * d2);
if ((r[i] += y.am(0, qd, r, j, 0, ys)) < qd) { // Try it out
y.dlShiftTo(j, t);
r.subTo(t, r);
while (r[i] < --qd) r.subTo(t, r);
}
}
if (q != null) {
r.drShiftTo(ys, q);
if (ts != ms) Int128.ZERO.subTo(q, q);
}
r.t = ys;
r.clamp();
if (nsh > 0) r.rShiftTo(nsh, r); // Denormalize remainder
if (ts < 0) Int128.ZERO.subTo(r, r);
}
// (public) this mod a
function bnMod(a) {
var r = nbi();
this.abs()
.divRemTo(a, null, r);
if (this.s < 0 && r.compareTo(Int128.ZERO) > 0) a.subTo(r, r);
return r;
}
// Modular reduction using "classic" algorithm
function Classic(m) {
this.m = m;
}
function cConvert(x) {
if (x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
else return x;
}
function cRevert(x) {
return x;
}
function cReduce(x) {
x.divRemTo(this.m, null, x);
}
function cMulTo(x, y, r) {
x.multiplyTo(y, r);
this.reduce(r);
}
function cSqrTo(x, r) {
x.squareTo(r);
this.reduce(r);
}
Classic.prototype.convert = cConvert;
Classic.prototype.revert = cRevert;
Classic.prototype.reduce = cReduce;
Classic.prototype.mulTo = cMulTo;
Classic.prototype.sqrTo = cSqrTo;
// (protected) return "-1/this % 2^DB"; useful for Mont. reduction
// justification:
// xy == 1 (mod m)
// xy = 1+km
// xy(2-xy) = (1+km)(1-km)
// x[y(2-xy)] = 1-k^2m^2
// x[y(2-xy)] == 1 (mod m^2)
// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
// should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
// JS multiply "overflows" differently from C/C++, so care is needed here.
function bnpInvDigit() {
if (this.t < 1) return 0;
var x = this[0];
if ((x & 1) == 0) return 0;
var y = x & 3; // y == 1/x mod 2^2
y = (y * (2 - (x & 0xf) * y)) & 0xf; // y == 1/x mod 2^4
y = (y * (2 - (x & 0xff) * y)) & 0xff; // y == 1/x mod 2^8
y = (y * (2 - (((x & 0xffff) * y) & 0xffff))) & 0xffff; // y == 1/x mod 2^16
// last step - calculate inverse mod DV directly;
// assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
y = (y * (2 - x * y % this.DV)) % this.DV; // y == 1/x mod 2^dbits
// we really want the negative inverse, and -DV < y < DV
return (y > 0) ? this.DV - y : -y;
}
// Montgomery reduction
function Montgomery(m) {
this.m = m;
this.mp = m.invDigit();
this.mpl = this.mp & 0x7fff;
this.mph = this.mp >> 15;
this.um = (1 << (m.DB - 15)) - 1;
this.mt2 = 2 * m.t;
}
// xR mod m
function montConvert(x) {
var r = nbi();
x.abs()
.dlShiftTo(this.m.t, r);
r.divRemTo(this.m, null, r);
if (x.s < 0 && r.compareTo(Int128.ZERO) > 0) this.m.subTo(r, r);
return r;
}
// x/R mod m
function montRevert(x) {
var r = nbi();
x.copyTo(r);
this.reduce(r);
return r;
}
// x = x/R mod m (HAC 14.32)
function montReduce(x) {
while (x.t <= this.mt2) // pad x so am has enough room later
x[x.t++] = 0;
for (var i = 0; i < this.m.t; ++i) {
// faster way of calculating u0 = x[i]*mp mod DV
var j = x[i] & 0x7fff;
var u0 = (j * this.mpl + (((j * this.mph + (x[i] >> 15) * this.mpl) & this.um) << 15)) & x.DM;
// use am to combine the multiply-shift-add into one call
j = i + this.m.t;
x[j] += this.m.am(0, u0, x, i, 0, this.m.t);
// propagate carry
while (x[j] >= x.DV) {
x[j] -= x.DV;
x[++j]++;
}
}
x.clamp();
x.drShiftTo(this.m.t, x);
if (x.compareTo(this.m) >= 0) x.subTo(this.m, x);
}
// r = "x^2/R mod m"; x != r
function montSqrTo(x, r) {
x.squareTo(r);
this.reduce(r);
}
// r = "xy/R mod m"; x,y != r
function montMulTo(x, y, r) {
x.multiplyTo(y, r);
this.reduce(r);
}
Montgomery.prototype.convert = montConvert;
Montgomery.prototype.revert = montRevert;
Montgomery.prototype.reduce = montReduce;
Montgomery.prototype.mulTo = montMulTo;
Montgomery.prototype.sqrTo = montSqrTo;
// (protected) true iff this is even
function bnpIsEven() {
return ((this.t > 0) ? (this[0] & 1) : this.s) == 0;
}
// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
function bnpExp(e, z) {
if (e > 0xffffffff || e < 1) return Int128.ONE;
var r = nbi(),
r2 = nbi(),
g = z.convert(this),
i = nbits(e) - 1;
g.copyTo(r);
while (--i >= 0) {
z.sqrTo(r, r2);
if ((e & (1 << i)) > 0) z.mulTo(r2, g, r);
else {
var t = r;
r = r2;
r2 = t;
}
}
return z.revert(r);
}
// (public) this^e % m, 0 <= e < 2^32
function bnModPowInt(e, m) {
var z;
if (e < 256 || m.isEven()) z = new Classic(m);
else z = new Montgomery(m);
return this.exp(e, z);
}
// protected
Int128.prototype.copyTo = bnpCopyTo;
Int128.prototype.fromInt = bnpFromInt;
Int128.prototype.fromString = bnpFromString;
Int128.prototype.clamp = bnpClamp;
Int128.prototype.dlShiftTo = bnpDLShiftTo;
Int128.prototype.drShiftTo = bnpDRShiftTo;
Int128.prototype.lShiftTo = bnpLShiftTo;
Int128.prototype.rShiftTo = bnpRShiftTo;
Int128.prototype.subTo = bnpSubTo;
Int128.prototype.multiplyTo = bnpMultiplyTo;
Int128.prototype.squareTo = bnpSquareTo;
Int128.prototype.divRemTo = bnpDivRemTo;
Int128.prototype.invDigit = bnpInvDigit;
Int128.prototype.isEven = bnpIsEven;
Int128.prototype.exp = bnpExp;
// public
Int128.prototype.toString = bnToString;
Int128.prototype.negate = bnNegate;
Int128.prototype.abs = bnAbs;
Int128.prototype.compareTo = bnCompareTo;
Int128.prototype.bitLength = bnBitLength;
Int128.prototype.mod = bnMod;
Int128.prototype.modPowInt = bnModPowInt;
// "constants"
Int128.ZERO = nbv(0);
Int128.ONE = nbv(1);
// Copyright (c) 2005-2009 Tom Wu
// All Rights Reserved.
// See "LICENSE" for details.
// Extended JavaScript BN functions, required for RSA private ops.
// Version 1.1: new Int128("0", 10) returns "proper" zero
// Version 1.2: square() API, isProbablePrime fix
// (public)
function bnClone() {
var r = nbi();
this.copyTo(r);
return r;
}
// (public) return value as integer
function bnIntValue() {
if (this.s < 0) {
if (this.t == 1) return this[0] - this.DV;
else if (this.t == 0) return -1;
}
else if (this.t == 1) return this[0];
else if (this.t == 0) return 0;
// assumes 16 < DB < 32
return ((this[1] & ((1 << (32 - this.DB)) - 1)) << this.DB) | this[0];
}
// (public) return value as byte
function bnByteValue() {
return (this.t == 0) ? this.s : (this[0] << 24) >> 24;
}
// (public) return value as short (assumes DB>=16)
function bnShortValue() {
return (this.t == 0) ? this.s : (this[0] << 16) >> 16;
}
// (protected) return x s.t. r^x < DV
function bnpChunkSize(r) {
return Math.floor(Math.LN2 * this.DB / Math.log(r));
}
// (public) 0 if this == 0, 1 if this > 0
function bnSigNum() {
if (this.s < 0) return -1;
else if (this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0;
else return 1;
}
// (protected) convert to radix string
function bnpToRadix(b) {
if (b == null) b = 10;
if (this.signum() == 0 || b < 2 || b > 36) return "0";
var cs = this.chunkSize(b);
var a = Math.pow(b, cs);
var d = nbv(a),
y = nbi(),
z = nbi(),
r = "";
this.divRemTo(d, y, z);
while (y.signum() > 0) {
r = (a + z.intValue())
.toString(b)
.substr(1) + r;
y.divRemTo(d, y, z);
}
return z.intValue()
.toString(b) + r;
}
// (protected) convert from radix string
function bnpFromRadix(s, b) {
this.fromInt(0);
if (b == null) b = 10;
var cs = this.chunkSize(b);
var d = Math.pow(b, cs),
mi = false,
j = 0,
w = 0;
for (var i = 0; i < s.length; ++i) {
var x = intAt(s, i);
if (x < 0) {
if (s.charAt(i) == "-" && this.signum() == 0) mi = true;
continue;
}
w = b * w + x;
if (++j >= cs) {
this.dMultiply(d);
this.dAddOffset(w, 0);
j = 0;
w = 0;
}
}
if (j > 0) {
this.dMultiply(Math.pow(b, j));
this.dAddOffset(w, 0);
}
if (mi) Int128.ZERO.subTo(this, this);
}
// (protected) alternate constructor
function bnpFromNumber(a, b, c) {
if ("number" == typeof b) {
// new Int128(int,int,RNG)
if (a < 2) this.fromInt(1);
else {
this.fromNumber(a, c);
if (!this.testBit(a - 1)) // force MSB set
this.bitwiseTo(Int128.ONE.shiftLeft(a - 1), op_or, this);
if (this.isEven()) this.dAddOffset(1, 0); // force odd
while (!this.isProbablePrime(b)) {
this.dAddOffset(2, 0);
if (this.bitLength() > a) this.subTo(Int128.ONE.shiftLeft(a - 1), this);
}
}
}
else {
// new Int128(int,RNG)
var x = [],
t = a & 7;
x.length = (a >> 3) + 1;
b.nextBytes(x);
if (t > 0) x[0] &= ((1 << t) - 1);
else x[0] = 0;
this.fromString(x, 256);
}
}
// (public) convert to bigendian byte array
function bnToByteArray() {
var i = this.t,
r = [];
r[0] = this.s;
var p = this.DB - (i * this.DB) % 8,
d, k = 0;
if (i-- > 0) {
if (p < this.DB && (d = this[i] >> p) != (this.s & this.DM) >> p) r[k++] = d | (this.s << (this.DB - p));
while (i >= 0) {
if (p < 8) {
d = (this[i] & ((1 << p) - 1)) << (8 - p);
d |= this[--i] >> (p += this.DB - 8);
}
else {
d = (this[i] >> (p -= 8)) & 0xff;
if (p <= 0) {
p += this.DB;
--i;
}
}
if ((d & 0x80) != 0) d |= -256;
if (k == 0 && (this.s & 0x80) != (d & 0x80))++k;
if (k > 0 || d != this.s) r[k++] = d;
}
}
return r;
}
function bnEquals(a) {
return (this.compareTo(a) == 0);
}
function bnMin(a) {
return (this.compareTo(a) < 0) ? this : a;
}
function bnMax(a) {
return (this.compareTo(a) > 0) ? this : a;
}
// (protected) r = this op a (bitwise)
function bnpBitwiseTo(a, op, r) {
var i, f, m = Math.min(a.t, this.t);
for (i = 0; i < m; ++i) r[i] = op(this[i], a[i]);
if (a.t < this.t) {
f = a.s & this.DM;
for (i = m; i < this.t; ++i) r[i] = op(this[i], f);
r.t = this.t;
}
else {
f = this.s & this.DM;
for (i = m; i < a.t; ++i) r[i] = op(f, a[i]);
r.t = a.t;
}
r.s = op(this.s, a.s);
r.clamp();
}
// (public) this & a
function op_and(x, y) {
return x & y;
}
function bnAnd(a) {
var r = nbi();
this.bitwiseTo(a, op_and, r);
return r;
}
// (public) this | a
function op_or(x, y) {
return x | y;
}
function bnOr(a) {
var r = nbi();
this.bitwiseTo(a, op_or, r);
return r;
}
// (public) this ^ a
function op_xor(x, y) {
return x ^ y;
}
function bnXor(a) {
var r = nbi();
this.bitwiseTo(a, op_xor, r);
return r;
}
// (public) this & ~a
function op_andnot(x, y) {
return x & ~y;
}
function bnAndNot(a) {
var r = nbi();
this.bitwiseTo(a, op_andnot, r);
return r;
}
// (public) ~this
function bnNot() {
var r = nbi();
for (var i = 0; i < this.t; ++i) r[i] = this.DM & ~this[i];
r.t = this.t;
r.s = ~this.s;
return r;
}
// (public) this << n
function bnShiftLeft(n) {
var r = nbi();
if (n < 0) this.rShiftTo(-n, r);
else this.lShiftTo(n, r);
return r;
}
// (public) this >> n
function bnShiftRight(n) {
var r = nbi();
if (n < 0) this.lShiftTo(-n, r);
else this.rShiftTo(n, r);
return r;
}
// return index of lowest 1-bit in x, x < 2^31
function lbit(x) {
if (x == 0) return -1;
var r = 0;
if ((x & 0xffff) == 0) {
x >>= 16;
r += 16;
}
if ((x & 0xff) == 0) {
x >>= 8;
r += 8;
}
if ((x & 0xf) == 0) {
x >>= 4;
r += 4;
}
if ((x & 3) == 0) {
x >>= 2;
r += 2;
}
if ((x & 1) == 0)++r;
return r;
}
// (public) returns index of lowest 1-bit (or -1 if none)
function bnGetLowestSetBit() {
for (var i = 0; i < this.t; ++i)
if (this[i] != 0) return i * this.DB + lbit(this[i]);
if (this.s < 0) return this.t * this.DB;
return -1;
}
// return number of 1 bits in x
function cbit(x) {
var r = 0;
while (x != 0) {
x &= x - 1;
++r;
}
return r;
}
// (public) return number of set bits
function bnBitCount() {
var r = 0,
x = this.s & this.DM;
for (var i = 0; i < this.t; ++i) r += cbit(this[i] ^ x);
return r;
}
// (public) true iff nth bit is set
function bnTestBit(n) {
var j = Math.floor(n / this.DB);
if (j >= this.t) return (this.s != 0);
return ((this[j] & (1 << (n % this.DB))) != 0);
}
// (protected) this op (1<<n)
function bnpChangeBit(n, op) {
var r = Int128.ONE.shiftLeft(n);
this.bitwiseTo(r, op, r);
return r;
}
// (public) this | (1<<n)
function bnSetBit(n) {
return this.changeBit(n, op_or);
}
// (public) this & ~(1<<n)
function bnClearBit(n) {
return this.changeBit(n, op_andnot);
}
// (public) this ^ (1<<n)
function bnFlipBit(n) {
return this.changeBit(n, op_xor);
}
// (protected) r = this + a
function bnpAddTo(a, r) {
var i = 0,
c = 0,
m = Math.min(a.t, this.t);
while (i < m) {
c += this[i] + a[i];
r[i++] = c & this.DM;
c >>= this.DB;
}
if (a.t < this.t) {
c += a.s;
while (i < this.t) {
c += this[i];
r[i++] = c & this.DM;
c >>= this.DB;
}
c += this.s;
}
else {
c += this.s;
while (i < a.t) {
c += a[i];
r[i++] = c & this.DM;
c >>= this.DB;
}
c += a.s;
}
r.s = (c < 0) ? -1 : 0;
if (c > 0) r[i++] = c;
else if (c < -1) r[i++] = this.DV + c;
r.t = i;
r.clamp();
}
// (public) this + a
function bnAdd(a) {
var r = nbi();
this.addTo(a, r);
return r;
}
// (public) this - a
function bnSubtract(a) {
var r = nbi();
this.subTo(a, r);
return r;
}
// (public) this * a
function bnMultiply(a) {
var r = nbi();
this.multiplyTo(a, r);
return r;
}
// (public) this^2
function bnSquare() {
var r = nbi();
this.squareTo(r);
return r;
}
// (public) this / a
function bnDivide(a) {
var r = nbi();
this.divRemTo(a, r, null);
return r;
}
// (public) this % a
function bnRemainder(a) {
var r = nbi();
this.divRemTo(a, null, r);
return r;
}
// (public) [this/a,this%a]
function bnDivideAndRemainder(a) {
var q = nbi(),
r = nbi();
this.divRemTo(a, q, r);
return new Array(q, r);
}
// (protected) this *= n, this >= 0, 1 < n < DV
function bnpDMultiply(n) {
this[this.t] = this.am(0, n - 1, this, 0, 0, this.t);
++this.t;
this.clamp();
}
// (protected) this += n << w words, this >= 0
function bnpDAddOffset(n, w) {
if (n == 0) return;
while (this.t <= w) this[this.t++] = 0;
this[w] += n;
while (this[w] >= this.DV) {
this[w] -= this.DV;
if (++w >= this.t) this[this.t++] = 0;
++this[w];
}
}
// A "null" reducer
function NullExp() {
}
function nNop(x) {
return x;
}
function nMulTo(x, y, r) {
x.multiplyTo(y, r);
}
function nSqrTo(x, r) {
x.squareTo(r);
}
NullExp.prototype.convert = nNop;
NullExp.prototype.revert = nNop;
NullExp.prototype.mulTo = nMulTo;
NullExp.prototype.sqrTo = nSqrTo;
// (public) this^e
function bnPow(e) {
return this.exp(e, new NullExp());
}
// (protected) r = lower n words of "this * a", a.t <= n
// "this" should be the larger one if appropriate.
function bnpMultiplyLowerTo(a, n, r) {
var i = Math.min(this.t + a.t, n);
r.s = 0; // assumes a,this >= 0
r.t = i;
while (i > 0) r[--i] = 0;
var j;
for (j = r.t - this.t; i < j; ++i) r[i + this.t] = this.am(0, a[i], r, i, 0, this.t);
for (j = Math.min(a.t, n); i < j; ++i) this.am(0, a[i], r, i, 0, n - i);
r.clamp();
}
// (protected) r = "this * a" without lower n words, n > 0
// "this" should be the larger one if appropriate.
function bnpMultiplyUpperTo(a, n, r) {
--n;
var i = r.t = this.t + a.t - n;
r.s = 0; // assumes a,this >= 0
while (--i >= 0) r[i] = 0;
for (i = Math.max(n - this.t, 0); i < a.t; ++i)
r[this.t + i - n] = this.am(n - i, a[i], r, 0, 0, this.t + i - n);
r.clamp();
r.drShiftTo(1, r);
}
// Barrett modular reduction
function Barrett(m) {
// setup Barrett
this.r2 = nbi();
this.q3 = nbi();
Int128.ONE.dlShiftTo(2 * m.t, this.r2);
this.mu = this.r2.divide(m);
this.m = m;
}
function barrettConvert(x) {
if (x.s < 0 || x.t > 2 * this.m.t) return x.mod(this.m);
else if (x.compareTo(this.m) < 0) return x;
else {
var r = nbi();
x.copyTo(r);
this.reduce(r);
return r;
}
}
function barrettRevert(x) {
return x;
}
// x = x mod m (HAC 14.42)
function barrettReduce(x) {
x.drShiftTo(this.m.t - 1, this.r2);
if (x.t > this.m.t + 1) {
x.t = this.m.t + 1;
x.clamp();
}
this.mu.multiplyUpperTo(this.r2, this.m.t + 1, this.q3);
this.m.multiplyLowerTo(this.q3, this.m.t + 1, this.r2);
while (x.compareTo(this.r2) < 0) x.dAddOffset(1, this.m.t + 1);
x.subTo(this.r2, x);
while (x.compareTo(this.m) >= 0) x.subTo(this.m, x);
}
// r = x^2 mod m; x != r
function barrettSqrTo(x, r) {
x.squareTo(r);
this.reduce(r);
}
// r = x*y mod m; x,y != r
function barrettMulTo(x, y, r) {
x.multiplyTo(y, r);
this.reduce(r);
}
Barrett.prototype.convert = barrettConvert;
Barrett.prototype.revert = barrettRevert;
Barrett.prototype.reduce = barrettReduce;
Barrett.prototype.mulTo = barrettMulTo;
Barrett.prototype.sqrTo = barrettSqrTo;
// (public) this^e % m (HAC 14.85)
function bnModPow(e, m) {
var i = e.bitLength(),
k, r = nbv(1),
z;
if (i <= 0) return r;
else if (i < 18) k = 1;
else if (i < 48) k = 3;
else if (i < 144) k = 4;
else if (i < 768) k = 5;
else k = 6;
if (i < 8) z = new Classic(m);
else if (m.isEven()) z = new Barrett(m);
else z = new Montgomery(m);
// precomputation
var g = [],
n = 3,
k1 = k - 1,
km = (1 << k) - 1;
g[1] = z.convert(this);
if (k > 1) {
var g2 = nbi();
z.sqrTo(g[1], g2);
while (n <= km) {
g[n] = nbi();
z.mulTo(g2, g[n - 2], g[n]);
n += 2;
}
}
var j = e.t - 1,
w, is1 = true,
r2 = nbi(),
t;
i = nbits(e[j]) - 1;
while (j >= 0) {
if (i >= k1) w = (e[j] >> (i - k1)) & km;
else {
w = (e[j] & ((1 << (i + 1)) - 1)) << (k1 - i);
if (j > 0) w |= e[j - 1] >> (this.DB + i - k1);
}
n = k;
while ((w & 1) == 0) {
w >>= 1;
--n;
}
if ((i -= n) < 0) {
i += this.DB;
--j;
}
if (is1) { // ret == 1, don't bother squaring or multiplying it
g[w].copyTo(r);
is1 = false;
}
else {
while (n > 1) {
z.sqrTo(r, r2);
z.sqrTo(r2, r);
n -= 2;
}
if (n > 0) z.sqrTo(r, r2);
else {
t = r;
r = r2;
r2 = t;
}
z.mulTo(r2, g[w], r);
}
while (j >= 0 && (e[j] & (1 << i)) == 0) {
z.sqrTo(r, r2);
t = r;
r = r2;
r2 = t;
if (--i < 0) {
i = this.DB - 1;
--j;
}
}
}
return z.revert(r);
}
// (public) gcd(this,a) (HAC 14.54)
function bnGCD(a) {
var x = (this.s < 0) ? this.negate() : this.clone();
var y = (a.s < 0) ? a.negate() : a.clone();
if (x.compareTo(y) < 0) {
var t = x;
x = y;
y = t;
}
var i = x.getLowestSetBit(),
g = y.getLowestSetBit();
if (g < 0) return x;
if (i < g) g = i;
if (g > 0) {
x.rShiftTo(g, x);
y.rShiftTo(g, y);
}
while (x.signum() > 0) {
if ((i = x.getLowestSetBit()) > 0) x.rShiftTo(i, x);
if ((i = y.getLowestSetBit()) > 0) y.rShiftTo(i, y);
if (x.compareTo(y) >= 0) {
x.subTo(y, x);
x.rShiftTo(1, x);
}
else {
y.subTo(x, y);
y.rShiftTo(1, y);
}
}
if (g > 0) y.lShiftTo(g, y);
return y;
}
// (protected) this % n, n < 2^26
function bnpModInt(n) {
if (n <= 0) return 0;
var d = this.DV % n,
r = (this.s < 0) ? n - 1 : 0;
if (this.t > 0) if (d == 0) r = this[0] % n;
else for (var i = this.t - 1; i >= 0; --i) r = (d * r + this[i]) % n;
return r;
}
// (public) 1/this % m (HAC 14.61)
function bnModInverse(m) {
var ac = m.isEven();
if ((this.isEven() && ac) || m.signum() == 0) return Int128.ZERO;
var u = m.clone(),
v = this.clone();
var a = nbv(1),
b = nbv(0),
c = nbv(0),
d = nbv(1);
while (u.signum() != 0) {
while (u.isEven()) {
u.rShiftTo(1, u);
if (ac) {
if (!a.isEven() || !b.isEven()) {
a.addTo(this, a);
b.subTo(m, b);
}
a.rShiftTo(1, a);
}
else if (!b.isEven()) b.subTo(m, b);
b.rShiftTo(1, b);
}
while (v.isEven()) {
v.rShiftTo(1, v);
if (ac) {
if (!c.isEven() || !d.isEven()) {
c.addTo(this, c);
d.subTo(m, d);
}
c.rShiftTo(1, c);
}
else if (!d.isEven()) d.subTo(m, d);
d.rShiftTo(1, d);
}
if (u.compareTo(v) >= 0) {
u.subTo(v, u);
if (ac) a.subTo(c, a);
b.subTo(d, b);
}
else {
v.subTo(u, v);
if (ac) c.subTo(a, c);
d.subTo(b, d);
}
}
if (v.compareTo(Int128.ONE) != 0) return Int128.ZERO;
if (d.compareTo(m) >= 0) return d.subtract(m);
if (d.signum() < 0) d.addTo(m, d);
else return d;
if (d.signum() < 0) return d.add(m);
else return d;
}
var lowprimes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997];
var lplim = (1 << 26) / lowprimes[lowprimes.length - 1];
// (public) test primality with certainty >= 1-.5^t
function bnIsProbablePrime(t) {
var i, x = this.abs();
if (x.t == 1 && x[0] <= lowprimes[lowprimes.length - 1]) {
for (i = 0; i < lowprimes.length; ++i)
if (x[0] == lowprimes[i]) return true;
return false;
}
if (x.isEven()) return false;
i = 1;
while (i < lowprimes.length) {
var m = lowprimes[i],
j = i + 1;
while (j < lowprimes.length && m < lplim) m *= lowprimes[j++];
m = x.modInt(m);
while (i < j) if (m % lowprimes[i++] == 0) return false;
}
return x.millerRabin(t);
}
// (protected) true if probably prime (HAC 4.24, Miller-Rabin)
function bnpMillerRabin(t) {
var n1 = this.subtract(Int128.ONE);
var k = n1.getLowestSetBit();
if (k <= 0) return false;
var r = n1.shiftRight(k);
t = (t + 1) >> 1;
if (t > lowprimes.length) t = lowprimes.length;
var a = nbi();
for (var i = 0; i < t; ++i) {
//Pick bases at random, instead of starting at 2
a.fromInt(lowprimes[Math.floor(Math.random() * lowprimes.length)]);
var y = a.modPow(r, this);
if (y.compareTo(Int128.ONE) != 0 && y.compareTo(n1) != 0) {
var j = 1;
while (j++ < k && y.compareTo(n1) != 0) {
y = y.modPowInt(2, this);
if (y.compareTo(Int128.ONE) == 0) return false;
}
if (y.compareTo(n1) != 0) return false;
}
}
return true;
}
// protected
Int128.prototype.chunkSize = bnpChunkSize;
Int128.prototype.toRadix = bnpToRadix;
Int128.prototype.fromRadix = bnpFromRadix;
Int128.prototype.fromNumber = bnpFromNumber;
Int128.prototype.bitwiseTo = bnpBitwiseTo;
Int128.prototype.changeBit = bnpChangeBit;
Int128.prototype.addTo = bnpAddTo;
Int128.prototype.dMultiply = bnpDMultiply;
Int128.prototype.dAddOffset = bnpDAddOffset;
Int128.prototype.multiplyLowerTo = bnpMultiplyLowerTo;
Int128.prototype.multiplyUpperTo = bnpMultiplyUpperTo;
Int128.prototype.modInt = bnpModInt;
Int128.prototype.millerRabin = bnpMillerRabin;
// public
Int128.prototype.clone = bnClone;
Int128.prototype.intValue = bnIntValue;
Int128.prototype.byteValue = bnByteValue;
Int128.prototype.shortValue = bnShortValue;
Int128.prototype.signum = bnSigNum;
Int128.prototype.toByteArray = bnToByteArray;
Int128.prototype.equals = bnEquals;
Int128.prototype.min = bnMin;
Int128.prototype.max = bnMax;
Int128.prototype.and = bnAnd;
Int128.prototype.or = bnOr;
Int128.prototype.xor = bnXor;
Int128.prototype.andNot = bnAndNot;
Int128.prototype.not = bnNot;
Int128.prototype.shiftLeft = bnShiftLeft;
Int128.prototype.shiftRight = bnShiftRight;
Int128.prototype.getLowestSetBit = bnGetLowestSetBit;
Int128.prototype.bitCount = bnBitCount;
Int128.prototype.testBit = bnTestBit;
Int128.prototype.setBit = bnSetBit;
Int128.prototype.clearBit = bnClearBit;
Int128.prototype.flipBit = bnFlipBit;
Int128.prototype.add = bnAdd;
Int128.prototype.subtract = bnSubtract;
Int128.prototype.multiply = bnMultiply;
Int128.prototype.divide = bnDivide;
Int128.prototype.remainder = bnRemainder;
Int128.prototype.divideAndRemainder = bnDivideAndRemainder;
Int128.prototype.modPow = bnModPow;
Int128.prototype.modInverse = bnModInverse;
Int128.prototype.pow = bnPow;
Int128.prototype.gcd = bnGCD;
Int128.prototype.isProbablePrime = bnIsProbablePrime;
// JSBN-specific extension
Int128.prototype.square = bnSquare;
// end of Int128 section
/*
// Uncomment the following two lines if you want to use Int128 outside ClipperLib
if (typeof(document) !== "undefined") window.Int128 = Int128;
else self.Int128 = Int128;
*/
// Here starts the actual Clipper library:
ClipperLib.Math_Abs_Int64 = ClipperLib.Math_Abs_Int32 = ClipperLib.Math_Abs_Double = function (a) {
return Math.abs(a);
};
ClipperLib.Math_Max_Int32_Int32 = function (a, b) {
return Math.max(a, b);
};
/*
-----------------------------------
cast_32 speedtest: http://jsperf.com/truncate-float-to-integer/2
-----------------------------------
*/
if (browser.msie || browser.opera || browser.safari) ClipperLib.Cast_Int32 = function (a) {
return a | 0;
};
else ClipperLib.Cast_Int32 = function (a) { // eg. browser.chrome || browser.chromium || browser.firefox
return ~~a;
};
/*
--------------------------
cast_64 speedtests: http://jsperf.com/truncate-float-to-integer
Chrome: bitwise_not_floor
Firefox17: toInteger (typeof test)
IE9: bitwise_or_floor
IE7 and IE8: to_parseint
Chromium: to_floor_or_ceil
Firefox3: to_floor_or_ceil
Firefox15: to_floor_or_ceil
Opera: to_floor_or_ceil
Safari: to_floor_or_ceil
--------------------------
*/
if (browser.chrome) ClipperLib.Cast_Int64 = function (a) {
if (a < -2147483648 || a > 2147483647)
return a < 0 ? Math.ceil(a) : Math.floor(a);
else return ~~a;
};
else if (browser.firefox && typeof(Number.toInteger) == "function") ClipperLib.Cast_Int64 = function (a) {
return Number.toInteger(a);
};
else if (browser.msie7 || browser.msie8) ClipperLib.Cast_Int64 = function (a) {
return parseInt(a, 10);
};
else if (browser.msie) ClipperLib.Cast_Int64 = function (a) {
if (a < -2147483648 || a > 2147483647)
return a < 0 ? Math.ceil(a) : Math.floor(a);
return a | 0;
};
// eg. browser.chromium || browser.firefox || browser.opera || browser.safari
else ClipperLib.Cast_Int64 = function (a) {
return a < 0 ? Math.ceil(a) : Math.floor(a);
};
ClipperLib.Clear = function (a) {
a.length = 0;
};
ClipperLib.MaxSteps = 222; // How many steps at maximum in arc in BuildArc() function
ClipperLib.PI = 3.141592653589793;
ClipperLib.PI2 = 2 * 3.141592653589793;
ClipperLib.IntPoint = function () {
var a = arguments;
if (a.length == 1) {
this.X = a[0].X;
this.Y = a[0].Y;
}
if (a.length == 2) {
this.X = a[0];
this.Y = a[1];
}
};
ClipperLib.IntRect = function () {
var a = arguments;
if (a.length == 4) // function (l, t, r, b)
{
var l = a[0],
t = a[1],
r = a[2],
b = a[3];
this.left = l;
this.top = t;
this.right = r;
this.bottom = b;
}
else {
this.left = 0;
this.top = 0;
this.right = 0;
this.bottom = 0;
}
};
ClipperLib.Polygon = function () {
return [];
};
ClipperLib.Polygons = function () {
return []; // Was previously [[]], but caused problems when pushed
};
ClipperLib.ExPolygons = function () {
var a = [];
a.exPolygons = true; // this is needed to make "overloading" possible in Execute
return a;
}
ClipperLib.ExPolygon = function () {
this.outer = null;
this.holes = null;
};
ClipperLib.ClipType = {
ctIntersection: 0,
ctUnion: 1,
ctDifference: 2,
ctXor: 3
};
ClipperLib.PolyType = {
ptSubject: 0,
ptClip: 1
};
ClipperLib.PolyFillType = {
pftEvenOdd: 0,
pftNonZero: 1,
pftPositive: 2,
pftNegative: 3
};
ClipperLib.JoinType = {
jtSquare: 0,
jtRound: 1,
jtMiter: 2
};
ClipperLib.EdgeSide = {
esLeft: 1,
esRight: 2
};
ClipperLib.Protects = {
ipNone: 0,
ipLeft: 1,
ipRight: 2,
ipBoth: 3
};
ClipperLib.Direction = {
dRightToLeft: 0,
dLeftToRight: 1
};
ClipperLib.TEdge = function () {
this.xbot = 0;
this.ybot = 0;
this.xcurr = 0;
this.ycurr = 0;
this.xtop = 0;
this.ytop = 0;
this.dx = 0;
this.deltaX = 0;
this.deltaY = 0;
this.tmpX = 0;
this.polyType = ClipperLib.PolyType.ptSubject;
this.side = null; //= ClipperLib.EdgeSide.esNeither;
this.windDelta = 0;
this.windCnt = 0;
this.windCnt2 = 0;
this.outIdx = 0;
this.next = null;
this.prev = null;
this.nextInLML = null;
this.nextInAEL = null;
this.prevInAEL = null;
this.nextInSEL = null;
this.prevInSEL = null;
};
ClipperLib.IntersectNode = function () {
this.edge1 = null;
this.edge2 = null;
this.pt = null;
this.next = null;
};
ClipperLib.LocalMinima = function () {
this.Y = 0;
this.leftBound = null;
this.rightBound = null;
this.next = null;
};
ClipperLib.Scanbeam = function () {
this.Y = 0;
this.next = null;
};
ClipperLib.OutRec = function () {
this.idx = 0;
this.isHole = false;
this.FirstLeft = null;
this.AppendLink = null;
this.pts = null;
this.bottomPt = null;
};
ClipperLib.OutPt = function () {
this.idx = 0;
this.pt = null;
this.next = null;
this.prev = null;
};
ClipperLib.JoinRec = function () {
this.pt1a = null;
this.pt1b = null;
this.poly1Idx = 0;
this.pt2a = null;
this.pt2b = null;
this.poly2Idx = 0;
};
ClipperLib.HorzJoinRec = function () {
this.edge = null;
this.savedIdx = 0;
};
ClipperLib.ClipperBase = function () {
this.m_MinimaList = null;
this.m_CurrentLM = null;
this.m_edges = [
[]
]; // 2-dimensional array
this.m_UseFullRange = false;
};
// Ranges are in original C# too high for Javascript (in current state 2012 December):
// protected const double horizontal = -3.4E+38;
// internal const Int64 loRange = 0x3FFFFFFF; // = 1073741823 = sqrt(2^63 -1)/2
// internal const Int64 hiRange = 0x3FFFFFFFFFFFFFFFL; // = 4611686018427387903 = sqrt(2^127 -1)/2
// So had to adjust them to more suitable:
ClipperLib.ClipperBase.horizontal = -9007199254740992; //-2^53
ClipperLib.ClipperBase.loRange = 47453132; // sqrt(2^53 -1)/2
ClipperLib.ClipperBase.hiRange = 4503599627370495; // sqrt(2^106 -1)/2
// If JS some day supports truly 64-bit integers, then these ranges can be as in C#
// and biginteger library can be more simpler (as then 128bit can be represented as two 64bit numbers)
ClipperLib.ClipperBase.PointsEqual = function (pt1, pt2) {
return (pt1.X == pt2.X && pt1.Y == pt2.Y);
};
ClipperLib.ClipperBase.prototype.PointIsVertex = function (pt, pp) {
var pp2 = pp;
do {
if (ClipperLib.ClipperBase.PointsEqual(pp2.pt, pt)) return true;
pp2 = pp2.next;
}
while (pp2 != pp);
return false;
};
ClipperLib.ClipperBase.prototype.PointInPolygon = function (pt, pp, UseFulllongRange) {
var pp2 = pp;
var result = false;
if (UseFulllongRange) {
do {
if ((((pp2.pt.Y <= pt.Y) && (pt.Y < pp2.prev.pt.Y)) || ((pp2.prev.pt.Y <= pt.Y) && (pt.Y < pp2.pt.Y))) && new Int128(pt.X - pp2.pt.X)
.compareTo(
new Int128(pp2.prev.pt.X - pp2.pt.X)
.multiply(new Int128(pt.Y - pp2.pt.Y))
.divide(
new Int128(pp2.prev.pt.Y - pp2.pt.Y))) < 0) result = !result;
pp2 = pp2.next;
}
while (pp2 != pp);
}
else {
do {
if ((((pp2.pt.Y <= pt.Y) && (pt.Y < pp2.prev.pt.Y)) || ((pp2.prev.pt.Y <= pt.Y) && (pt.Y < pp2.pt.Y))) && (pt.X - pp2.pt.X < (pp2.prev.pt.X - pp2.pt.X) * (pt.Y - pp2.pt.Y) / (pp2.prev.pt.Y - pp2.pt.Y))) result = !result;
pp2 = pp2.next;
}
while (pp2 != pp);
}
return result;
};
ClipperLib.ClipperBase.prototype.SlopesEqual = ClipperLib.ClipperBase.SlopesEqual = function () {
var a = arguments;
var e1, e2, pt1, pt2, pt3, pt4, UseFullRange;
if (a.length == 3) // function (e1, e2, UseFullRange)
{
e1 = a[0], e2 = a[1], UseFullRange = a[2];
if (UseFullRange) return new Int128(e1.deltaY)
.multiply(new Int128(e2.deltaX))
.toString() == new Int128(e1.deltaX)
.multiply(new Int128(e2.deltaY))
.toString();
else return (e1.deltaY) * (e2.deltaX) == (e1.deltaX) * (e2.deltaY);
}
else if (a.length == 4) // function (pt1, pt2, pt3, UseFullRange)
{
pt1 = a[0], pt2 = a[1], pt3 = a[2], UseFullRange = a[3];
if (UseFullRange) return new Int128(pt1.Y - pt2.Y)
.multiply(new Int128(pt2.X - pt3.X))
.toString() == new Int128(pt1.X - pt2.X)
.multiply(new Int128(pt2.Y - pt3.Y))
.toString();
else return (pt1.Y - pt2.Y) * (pt2.X - pt3.X) - (pt1.X - pt2.X) * (pt2.Y - pt3.Y) == 0;
}
else if (a.length == 5) // function (pt1, pt2, pt3, pt4, UseFullRange)
{
pt1 = a[0], pt2 = a[1], pt3 = a[2], pt4 = a[3], UseFullRange = a[4];
if (UseFullRange) return new Int128(pt1.Y - pt2.Y)
.multiply(new Int128(pt3.X - pt4.X))
.toString() == new Int128(pt1.X - pt2.X)
.multiply(new Int128(pt3.Y - pt4.Y))
.toString();
else return (pt1.Y - pt2.Y) * (pt3.X - pt4.X) - (pt1.X - pt2.X) * (pt3.Y - pt4.Y) == 0;
}
};
ClipperLib.ClipperBase.prototype.Clear = function () {
this.DisposeLocalMinimaList();
for (var i = 0; i < this.m_edges.length; ++i) {
for (var j = 0; j < this.m_edges[i].length; ++j)
this.m_edges[i][j] = null;
ClipperLib.Clear(this.m_edges[i]);
}
ClipperLib.Clear(this.m_edges);
this.m_UseFullRange = false;
};
ClipperLib.ClipperBase.prototype.DisposeLocalMinimaList = function () {
while (this.m_MinimaList != null) {
var tmpLm = this.m_MinimaList.next;
this.m_MinimaList = null;
this.m_MinimaList = tmpLm;
}
this.m_CurrentLM = null;
};
ClipperLib.ClipperBase.prototype.AddPolygons = function (ppg, polyType) {
var result = false;
var res = false;
if (!(ppg instanceof Array)) return result;
for (var i = 0; i < ppg.length; ++i) {
res = this.AddPolygon(ppg[i], polyType, true);
if (res && res != "exceed") result = true;
else if (res == "exceed") break;
}
if (res == "exceed") ClipperLib.Error("Coordinate exceeds range bounds in AddPolygons().");
return result;
};
ClipperLib.ClipperBase.prototype.AddPolygon = function (pg, polyType, multiple) {
if (!(pg instanceof Array)) return false;
var len = pg.length;
if (len < 3) return false;
var p = new ClipperLib.Polygon();
p.push(new ClipperLib.IntPoint(pg[0].X, pg[0].Y));
var j = 0;
var i;
var exceed = false;
for (i = 1; i < len; ++i) {
var maxVal;
if (this.m_UseFullRange) maxVal = ClipperLib.ClipperBase.hiRange;
else maxVal = ClipperLib.ClipperBase.loRange;
if (ClipperLib.Math_Abs_Int64(pg[i].X) > maxVal || ClipperLib.Math_Abs_Int64(pg[i].Y) > maxVal) {
if (ClipperLib.Math_Abs_Int64(pg[i].X) > ClipperLib.ClipperBase.hiRange || ClipperLib.Math_Abs_Int64(pg[i].Y) > ClipperLib.ClipperBase.hiRange) {
if (typeof(multiple) != "undefined") return "exceed";
exceed = true;
break;
}
maxVal = ClipperLib.ClipperBase.hiRange;
this.m_UseFullRange = true;
}
if (ClipperLib.ClipperBase.PointsEqual(p[j], pg[i])) continue;
else if (j > 0 && this.SlopesEqual(p[j - 1], p[j], pg[i], this.m_UseFullRange)) {
if (ClipperLib.ClipperBase.PointsEqual(p[j - 1], pg[i])) j--;
}
else j++;
if (j < p.length) p[j] = pg[i];
else p.push(new ClipperLib.IntPoint(pg[i].X, pg[i].Y));
}
if (exceed && typeof(multiple) == "undefined")
ClipperLib.Error("Coordinate exceeds range bounds in AddPolygon()");
if (j < 2) return false;
len = j + 1;
while (len > 2) {
if (ClipperLib.ClipperBase.PointsEqual(p[j], p[0])) j--;
else if (ClipperLib.ClipperBase.PointsEqual(p[0], p[1]) || this.SlopesEqual(p[j], p[0], p[1], this.m_UseFullRange)) p[0] = p[j--];
else if (this.SlopesEqual(p[j - 1], p[j], p[0], this.m_UseFullRange)) j--;
else if (this.SlopesEqual(p[0], p[1], p[2], this.m_UseFullRange)) {
for (i = 2; i <= j; ++i)
p[i - 1] = p[i];
j--;
}
else break;
len--;
}
if (len < 3) return false;
var edges = [];
for (i = 0; i < len; i++)
edges.push(new ClipperLib.TEdge());
this.m_edges.push(edges);
edges[0].xcurr = p[0].X;
edges[0].ycurr = p[0].Y;
this.InitEdge(edges[len - 1], edges[0], edges[len - 2], p[len - 1], polyType);
for (i = len - 2; i > 0; --i)
this.InitEdge(edges[i], edges[i + 1], edges[i - 1], p[i], polyType);
this.InitEdge(edges[0], edges[1], edges[len - 1], p[0], polyType);
var e = edges[0];
var eHighest = e;
do {
e.xcurr = e.xbot;
e.ycurr = e.ybot;
if (e.ytop < eHighest.ytop) eHighest = e;
e = e.next;
}
while (e != edges[0]);
if (eHighest.windDelta > 0) eHighest = eHighest.next;
if (eHighest.dx == ClipperLib.ClipperBase.horizontal) eHighest = eHighest.next;
e = eHighest;
do {
e = this.AddBoundsToLML(e);
}
while (e != eHighest);
return true;
};
ClipperLib.ClipperBase.prototype.InitEdge = function (e, eNext, ePrev, pt, polyType) {
e.next = eNext;
e.prev = ePrev;
e.xcurr = pt.X;
e.ycurr = pt.Y;
if (e.ycurr >= e.next.ycurr) {
e.xbot = e.xcurr;
e.ybot = e.ycurr;
e.xtop = e.next.xcurr;
e.ytop = e.next.ycurr;
e.windDelta = 1;
}
else {
e.xtop = e.xcurr;
e.ytop = e.ycurr;
e.xbot = e.next.xcurr;
e.ybot = e.next.ycurr;
e.windDelta = -1;
}
this.SetDx(e);
e.polyType = polyType;
e.outIdx = -1;
};
ClipperLib.ClipperBase.prototype.SetDx = function (e) {
e.deltaX = (e.xtop - e.xbot);
e.deltaY = (e.ytop - e.ybot);
if (e.deltaY == 0) e.dx = ClipperLib.ClipperBase.horizontal;
else e.dx = (e.deltaX) / (e.deltaY);
};
ClipperLib.ClipperBase.prototype.AddBoundsToLML = function (e) {
e.nextInLML = null;
e = e.next;
for (; ;) {
if (e.dx == ClipperLib.ClipperBase.horizontal) {
if (e.next.ytop < e.ytop && e.next.xbot > e.prev.xbot) break;
if (e.xtop != e.prev.xbot) this.SwapX(e);
e.nextInLML = e.prev;
}
else if (e.ycurr == e.prev.ycurr) break;
else e.nextInLML = e.prev;
e = e.next;
}
var newLm = new ClipperLib.LocalMinima();
newLm.next = null;
newLm.Y = e.prev.ybot;
if (e.dx == ClipperLib.ClipperBase.horizontal) {
if (e.xbot != e.prev.xbot) this.SwapX(e);
newLm.leftBound = e.prev;
newLm.rightBound = e;
}
else if (e.dx < e.prev.dx) {
newLm.leftBound = e.prev;
newLm.rightBound = e;
}
else {
newLm.leftBound = e;
newLm.rightBound = e.prev;
}
newLm.leftBound.side = ClipperLib.EdgeSide.esLeft;
newLm.rightBound.side = ClipperLib.EdgeSide.esRight;
this.InsertLocalMinima(newLm);
for (; ;) {
if (e.next.ytop == e.ytop && e.next.dx != ClipperLib.ClipperBase.horizontal) break;
e.nextInLML = e.next;
e = e.next;
if (e.dx == ClipperLib.ClipperBase.horizontal && e.xbot != e.prev.xtop) this.SwapX(e);
}
return e.next;
};
ClipperLib.ClipperBase.prototype.InsertLocalMinima = function (newLm) {
if (this.m_MinimaList == null) {
this.m_MinimaList = newLm;
}
else if (newLm.Y >= this.m_MinimaList.Y) {
newLm.next = this.m_MinimaList;
this.m_MinimaList = newLm;
}
else {
var tmpLm = this.m_MinimaList;
while (tmpLm.next != null && (newLm.Y < tmpLm.next.Y))
tmpLm = tmpLm.next;
newLm.next = tmpLm.next;
tmpLm.next = newLm;
}
};
ClipperLib.ClipperBase.prototype.PopLocalMinima = function () {
if (this.m_CurrentLM == null) return;
this.m_CurrentLM = this.m_CurrentLM.next;
};
ClipperLib.ClipperBase.prototype.SwapX = function (e) {
e.xcurr = e.xtop;
e.xtop = e.xbot;
e.xbot = e.xcurr;
};
ClipperLib.ClipperBase.prototype.Reset = function () {
this.m_CurrentLM = this.m_MinimaList;
var lm = this.m_MinimaList;
while (lm != null) {
var e = lm.leftBound;
while (e != null) {
e.xcurr = e.xbot;
e.ycurr = e.ybot;
e.side = ClipperLib.EdgeSide.esLeft;
e.outIdx = -1;
e = e.nextInLML;
}
e = lm.rightBound;
while (e != null) {
e.xcurr = e.xbot;
e.ycurr = e.ybot;
e.side = ClipperLib.EdgeSide.esRight;
e.outIdx = -1;
e = e.nextInLML;
}
lm = lm.next;
}
return;
};
ClipperLib.ClipperBase.prototype.GetBounds = function () {
var result = new ClipperLib.IntRect();
var lm = this.m_MinimaList;
if (lm == null) return result;
result.left = lm.leftBound.xbot;
result.top = lm.leftBound.ybot;
result.right = lm.leftBound.xbot;
result.bottom = lm.leftBound.ybot;
while (lm != null) {
if (lm.leftBound.ybot > result.bottom) result.bottom = lm.leftBound.ybot;
var e = lm.leftBound;
for (; ;) {
var bottomE = e;
while (e.nextInLML != null) {
if (e.xbot < result.left) result.left = e.xbot;
if (e.xbot > result.right) result.right = e.xbot;
e = e.nextInLML;
}
if (e.xbot < result.left) result.left = e.xbot;
if (e.xbot > result.right) result.right = e.xbot;
if (e.xtop < result.left) result.left = e.xtop;
if (e.xtop > result.right) result.right = e.xtop;
if (e.ytop < result.top) result.top = e.ytop;
if (bottomE == lm.leftBound) e = lm.rightBound;
else break;
}
lm = lm.next;
}
return result;
};
ClipperLib.Clipper = function () {
this.m_PolyOuts = null;
this.m_ClipType = ClipperLib.ClipType.ctIntersection;
this.m_Scanbeam = null;
this.m_ActiveEdges = null;
this.m_SortedEdges = null;
this.m_IntersectNodes = null;
this.m_ExecuteLocked = false;
this.m_ClipFillType = ClipperLib.PolyFillType.pftEvenOdd;
this.m_SubjFillType = ClipperLib.PolyFillType.pftEvenOdd;
this.m_Joins = null;
this.m_HorizJoins = null;
this.m_ReverseOutput = false;
this.m_UsingExPolygons = false;
ClipperLib.ClipperBase.call(this);
this.m_Scanbeam = null;
this.m_ActiveEdges = null;
this.m_SortedEdges = null;
this.m_IntersectNodes = null;
this.m_ExecuteLocked = false;
this.m_PolyOuts = [];
this.m_Joins = [];
this.m_HorizJoins = [];
this.m_ReverseOutput = false;
this.m_UsingExPolygons = false;
};
ClipperLib.Clipper.prototype.Clear = function () {
if (this.m_edges.length == 0) return;
this.DisposeAllPolyPts();
ClipperLib.ClipperBase.prototype.Clear.call(this);
};
ClipperLib.Clipper.prototype.DisposeScanbeamList = function () {
while (this.m_Scanbeam != null) {
var sb2 = this.m_Scanbeam.next;
this.m_Scanbeam = null;
this.m_Scanbeam = sb2;
}
};
ClipperLib.Clipper.prototype.Reset = function () {
ClipperLib.ClipperBase.prototype.Reset.call(this);
this.m_Scanbeam = null;
this.m_ActiveEdges = null;
this.m_SortedEdges = null;
this.DisposeAllPolyPts();
var lm = this.m_MinimaList;
while (lm != null) {
this.InsertScanbeam(lm.Y);
this.InsertScanbeam(lm.leftBound.ytop);
lm = lm.next;
}
};
ClipperLib.Clipper.prototype.get_ReverseSolution = function () {
return this.m_ReverseOutput;
};
ClipperLib.Clipper.prototype.set_ReverseSolution = function (value) {
this.m_ReverseOutput = value;
};
ClipperLib.Clipper.prototype.InsertScanbeam = function (Y) {
var newSb;
if (this.m_Scanbeam == null) {
this.m_Scanbeam = new ClipperLib.Scanbeam();
this.m_Scanbeam.next = null;
this.m_Scanbeam.Y = Y;
}
else if (Y > this.m_Scanbeam.Y) {
newSb = new ClipperLib.Scanbeam();
newSb.Y = Y;
newSb.next = this.m_Scanbeam;
this.m_Scanbeam = newSb;
}
else {
var sb2 = this.m_Scanbeam;
while (sb2.next != null && (Y <= sb2.next.Y))
sb2 = sb2.next;
if (Y == sb2.Y) return;
newSb = new ClipperLib.Scanbeam();
newSb.Y = Y;
newSb.next = sb2.next;
sb2.next = newSb;
}
};
ClipperLib.Clipper.prototype.Execute = function (clipType, solution, subjFillType, clipFillType) {
var succeeded;
if (arguments.length == 2) {
subjFillType = ClipperLib.PolyFillType.pftEvenOdd;
clipFillType = ClipperLib.PolyFillType.pftEvenOdd;
}
if (typeof(solution.exPolygons) == "undefined") // hacky way to test if solution is not exPolygons
{
if (this.m_ExecuteLocked) return false;
this.m_ExecuteLocked = true;
ClipperLib.Clear(solution);
this.m_SubjFillType = subjFillType;
this.m_ClipFillType = clipFillType;
this.m_ClipType = clipType;
this.m_UsingExPolygons = false;
succeeded = this.ExecuteInternal();
if (succeeded) {
this.BuildResult(solution);
}
this.m_ExecuteLocked = false;
return succeeded;
}
else {
if (this.m_ExecuteLocked) return false;
this.m_ExecuteLocked = true;
ClipperLib.Clear(solution);
this.m_SubjFillType = subjFillType;
this.m_ClipFillType = clipFillType;
this.m_ClipType = clipType;
this.m_UsingExPolygons = true;
succeeded = this.ExecuteInternal();
if (succeeded) {
this.BuildResultEx(solution);
}
this.m_ExecuteLocked = false;
return succeeded;
}
};
ClipperLib.Clipper.prototype.PolySort = function (or1, or2) {
if (or1 == or2) return 0;
else if (or1.pts == null || or2.pts == null) {
if ((or1.pts == null) != (or2.pts == null)) {
return or1.pts == null ? 1 : -1;
}
else return 0;
}
var i1, i2;
if (or1.isHole) i1 = or1.FirstLeft.idx;
else i1 = or1.idx;
if (or2.isHole) i2 = or2.FirstLeft.idx;
else i2 = or2.idx;
var result = i1 - i2;
if (result == 0 && (or1.isHole != or2.isHole)) {
return or1.isHole ? 1 : -1;
}
return result;
};
ClipperLib.Clipper.prototype.FindAppendLinkEnd = function (outRec) {
while (outRec.AppendLink != null)
outRec = outRec.AppendLink;
return outRec;
};
ClipperLib.Clipper.prototype.FixHoleLinkage = function (outRec) {
var tmp;
if (outRec.bottomPt != null) tmp = this.m_PolyOuts[outRec.bottomPt.idx].FirstLeft;
else tmp = outRec.FirstLeft;
if (outRec == tmp) ClipperLib.Error("HoleLinkage error");
if (tmp != null) {
if (tmp.AppendLink != null) tmp = this.FindAppendLinkEnd(tmp);
if (tmp == outRec) tmp = null;
else if (tmp.isHole) {
this.FixHoleLinkage(tmp);
tmp = tmp.FirstLeft;
}
}
outRec.FirstLeft = tmp;
if (tmp == null) outRec.isHole = false;
outRec.AppendLink = null;
};
ClipperLib.Clipper.prototype.ExecuteInternal = function () {
var succeeded;
try {
this.Reset();
if (this.m_CurrentLM == null) return true;
var botY = this.PopScanbeam();
do {
this.InsertLocalMinimaIntoAEL(botY);
ClipperLib.Clear(this.m_HorizJoins);
this.ProcessHorizontals();
var topY = this.PopScanbeam();
succeeded = this.ProcessIntersections(botY, topY);
if (!succeeded) break;
this.ProcessEdgesAtTopOfScanbeam(topY);
botY = topY;
}
while (this.m_Scanbeam != null);
}
catch ($$e1) {
succeeded = false;
}
if (succeeded) {
var outRec;
for (var i = 0; i < this.m_PolyOuts.length; i++) {
outRec = this.m_PolyOuts[i];
if (outRec.pts == null) continue;
this.FixupOutPolygon(outRec);
if (outRec.pts == null) continue;
if (outRec.isHole && this.m_UsingExPolygons) this.FixHoleLinkage(outRec);
if ((outRec.isHole ^ this.m_ReverseOutput) == (this.Area(outRec, this.m_UseFullRange) > 0))
this.ReversePolyPtLinks(outRec.pts);
}
this.JoinCommonEdges();
if (this.m_UsingExPolygons) this.m_PolyOuts.sort(this.PolySort);
}
ClipperLib.Clear(this.m_Joins);
ClipperLib.Clear(this.m_HorizJoins);
return succeeded;
};
ClipperLib.Clipper.prototype.PopScanbeam = function () {
var Y = this.m_Scanbeam.Y;
var sb2 = this.m_Scanbeam;
this.m_Scanbeam = this.m_Scanbeam.next;
sb2 = null;
return Y;
};
ClipperLib.Clipper.prototype.DisposeAllPolyPts = function () {
for (var i = 0; i < this.m_PolyOuts.length; ++i)
this.DisposeOutRec(i);
ClipperLib.Clear(this.m_PolyOuts);
};
ClipperLib.Clipper.prototype.DisposeOutRec = function (index) {
var outRec = this.m_PolyOuts[index];
if (outRec.pts != null) this.DisposeOutPts(outRec.pts);
outRec = null;
this.m_PolyOuts[index] = null;
};
ClipperLib.Clipper.prototype.DisposeOutPts = function (pp) {
if (pp == null) return;
var tmpPp = null;
pp.prev.next = null;
while (pp != null) {
tmpPp = pp;
pp = pp.next;
tmpPp = null;
}
};
ClipperLib.Clipper.prototype.AddJoin = function (e1, e2, e1OutIdx, e2OutIdx) {
var jr = new ClipperLib.JoinRec();
if (e1OutIdx >= 0) jr.poly1Idx = e1OutIdx;
else jr.poly1Idx = e1.outIdx;
jr.pt1a = new ClipperLib.IntPoint(e1.xcurr, e1.ycurr);
jr.pt1b = new ClipperLib.IntPoint(e1.xtop, e1.ytop);
if (e2OutIdx >= 0) jr.poly2Idx = e2OutIdx;
else jr.poly2Idx = e2.outIdx;
jr.pt2a = new ClipperLib.IntPoint(e2.xcurr, e2.ycurr);
jr.pt2b = new ClipperLib.IntPoint(e2.xtop, e2.ytop);
this.m_Joins.push(jr);
};
ClipperLib.Clipper.prototype.AddHorzJoin = function (e, idx) {
var hj = new ClipperLib.HorzJoinRec();
hj.edge = e;
hj.savedIdx = idx;
this.m_HorizJoins.push(hj);
};
ClipperLib.Clipper.prototype.InsertLocalMinimaIntoAEL = function (botY) {
var pt, pt2;
while (this.m_CurrentLM != null && (this.m_CurrentLM.Y == botY)) {
var lb = this.m_CurrentLM.leftBound;
var rb = this.m_CurrentLM.rightBound;
this.InsertEdgeIntoAEL(lb);
this.InsertScanbeam(lb.ytop);
this.InsertEdgeIntoAEL(rb);
if (this.IsEvenOddFillType(lb)) {
lb.windDelta = 1;
rb.windDelta = 1;
}
else {
rb.windDelta = -lb.windDelta;
}
this.SetWindingCount(lb);
rb.windCnt = lb.windCnt;
rb.windCnt2 = lb.windCnt2;
if (rb.dx == ClipperLib.ClipperBase.horizontal) {
this.AddEdgeToSEL(rb);
this.InsertScanbeam(rb.nextInLML.ytop);
}
else this.InsertScanbeam(rb.ytop);
if (this.IsContributing(lb)) this.AddLocalMinPoly(lb, rb, new ClipperLib.IntPoint(lb.xcurr, this.m_CurrentLM.Y));
if (rb.outIdx >= 0) {
if (rb.dx == ClipperLib.ClipperBase.horizontal) {
for (var i = 0; i < this.m_HorizJoins.length; i++) {
pt = new ClipperLib.IntPoint(), pt2 = new ClipperLib.IntPoint();
var hj = this.m_HorizJoins[i];
if ((function () {
pt = {
Value: pt
};
pt2 = {
Value: pt2
};
var $res = this.GetOverlapSegment(new ClipperLib.IntPoint(hj.edge.xbot, hj.edge.ybot),
new ClipperLib.IntPoint(hj.edge.xtop, hj.edge.ytop),
new ClipperLib.IntPoint(rb.xbot, rb.ybot),
new ClipperLib.IntPoint(rb.xtop, rb.ytop),
pt, pt2);
pt = pt.Value;
pt2 = pt2.Value;
return $res;
})
.call(this)) this.AddJoin(hj.edge, rb, hj.savedIdx, -1);
}
}
}
if (lb.nextInAEL != rb) {
if (rb.outIdx >= 0 && rb.prevInAEL.outIdx >= 0 && this.SlopesEqual(rb.prevInAEL, rb, this.m_UseFullRange)) this.AddJoin(rb, rb.prevInAEL, -1, -1);
var e = lb.nextInAEL;
pt = new ClipperLib.IntPoint(lb.xcurr, lb.ycurr);
while (e != rb) {
if (e == null) ClipperLib.Error("InsertLocalMinimaIntoAEL: missing rightbound!");
this.IntersectEdges(rb, e, pt, ClipperLib.Protects.ipNone);
e = e.nextInAEL;
}
}
this.PopLocalMinima();
}
};
ClipperLib.Clipper.prototype.InsertEdgeIntoAEL = function (edge) {
edge.prevInAEL = null;
edge.nextInAEL = null;
if (this.m_ActiveEdges == null) {
this.m_ActiveEdges = edge;
}
else if (this.E2InsertsBeforeE1(this.m_ActiveEdges, edge)) {
edge.nextInAEL = this.m_ActiveEdges;
this.m_ActiveEdges.prevInAEL = edge;
this.m_ActiveEdges = edge;
}
else {
var e = this.m_ActiveEdges;
while (e.nextInAEL != null && !this.E2InsertsBeforeE1(e.nextInAEL, edge))
e = e.nextInAEL;
edge.nextInAEL = e.nextInAEL;
if (e.nextInAEL != null) e.nextInAEL.prevInAEL = edge;
edge.prevInAEL = e;
e.nextInAEL = edge;
}
};
ClipperLib.Clipper.prototype.E2InsertsBeforeE1 = function (e1, e2) {
return e2.xcurr == e1.xcurr ? e2.dx > e1.dx : e2.xcurr < e1.xcurr;
};
ClipperLib.Clipper.prototype.IsEvenOddFillType = function (edge) {
if (edge.polyType == ClipperLib.PolyType.ptSubject) return this.m_SubjFillType == ClipperLib.PolyFillType.pftEvenOdd;
else return this.m_ClipFillType == ClipperLib.PolyFillType.pftEvenOdd;
};
ClipperLib.Clipper.prototype.IsEvenOddAltFillType = function (edge) {
if (edge.polyType == ClipperLib.PolyType.ptSubject) return this.m_ClipFillType == ClipperLib.PolyFillType.pftEvenOdd;
else return this.m_SubjFillType == ClipperLib.PolyFillType.pftEvenOdd;
};
ClipperLib.Clipper.prototype.IsContributing = function (edge) {
var pft, pft2;
if (edge.polyType == ClipperLib.PolyType.ptSubject) {
pft = this.m_SubjFillType;
pft2 = this.m_ClipFillType;
}
else {
pft = this.m_ClipFillType;
pft2 = this.m_SubjFillType;
}
switch (pft) {
case ClipperLib.PolyFillType.pftEvenOdd:
case ClipperLib.PolyFillType.pftNonZero:
if (ClipperLib.Math_Abs_Int32(edge.windCnt) != 1) return false;
break;
case ClipperLib.PolyFillType.pftPositive:
if (edge.windCnt != 1) return false;
break;
default:
if (edge.windCnt != -1) return false;
break;
}
switch (this.m_ClipType) {
case ClipperLib.ClipType.ctIntersection:
switch (pft2) {
case ClipperLib.PolyFillType.pftEvenOdd:
case ClipperLib.PolyFillType.pftNonZero:
return (edge.windCnt2 != 0);
case ClipperLib.PolyFillType.pftPositive:
return (edge.windCnt2 > 0);
default:
return (edge.windCnt2 < 0);
}
break;
case ClipperLib.ClipType.ctUnion:
switch (pft2) {
case ClipperLib.PolyFillType.pftEvenOdd:
case ClipperLib.PolyFillType.pftNonZero:
return (edge.windCnt2 == 0);
case ClipperLib.PolyFillType.pftPositive:
return (edge.windCnt2 <= 0);
default:
return (edge.windCnt2 >= 0);
}
break;
case ClipperLib.ClipType.ctDifference:
if (edge.polyType == ClipperLib.PolyType.ptSubject) switch (pft2) {
case ClipperLib.PolyFillType.pftEvenOdd:
case ClipperLib.PolyFillType.pftNonZero:
return (edge.windCnt2 == 0);
case ClipperLib.PolyFillType.pftPositive:
return (edge.windCnt2 <= 0);
default:
return (edge.windCnt2 >= 0);
}
else switch (pft2) {
case ClipperLib.PolyFillType.pftEvenOdd:
case ClipperLib.PolyFillType.pftNonZero:
return (edge.windCnt2 != 0);
case ClipperLib.PolyFillType.pftPositive:
return (edge.windCnt2 > 0);
default:
return (edge.windCnt2 < 0);
}
}
return true;
};
ClipperLib.Clipper.prototype.SetWindingCount = function (edge) {
var e = edge.prevInAEL;
while (e != null && e.polyType != edge.polyType)
e = e.prevInAEL;
if (e == null) {
edge.windCnt = edge.windDelta;
edge.windCnt2 = 0;
e = this.m_ActiveEdges;
}
else if (this.IsEvenOddFillType(edge)) {
edge.windCnt = 1;
edge.windCnt2 = e.windCnt2;
e = e.nextInAEL;
}
else {
if (e.windCnt * e.windDelta < 0) {
if (ClipperLib.Math_Abs_Int32(e.windCnt) > 1) {
if (e.windDelta * edge.windDelta < 0) edge.windCnt = e.windCnt;
else edge.windCnt = e.windCnt + edge.windDelta;
}
else edge.windCnt = e.windCnt + e.windDelta + edge.windDelta;
}
else {
if (ClipperLib.Math_Abs_Int32(e.windCnt) > 1 && e.windDelta * edge.windDelta < 0) edge.windCnt = e.windCnt;
else if (e.windCnt + edge.windDelta == 0) edge.windCnt = e.windCnt;
else edge.windCnt = e.windCnt + edge.windDelta;
}
edge.windCnt2 = e.windCnt2;
e = e.nextInAEL;
}
if (this.IsEvenOddAltFillType(edge)) {
while (e != edge) {
edge.windCnt2 = (edge.windCnt2 == 0) ? 1 : 0;
e = e.nextInAEL;
}
}
else {
while (e != edge) {
edge.windCnt2 += e.windDelta;
e = e.nextInAEL;
}
}
};
ClipperLib.Clipper.prototype.AddEdgeToSEL = function (edge) {
if (this.m_SortedEdges == null) {
this.m_SortedEdges = edge;
edge.prevInSEL = null;
edge.nextInSEL = null;
}
else {
edge.nextInSEL = this.m_SortedEdges;
edge.prevInSEL = null;
this.m_SortedEdges.prevInSEL = edge;
this.m_SortedEdges = edge;
}
};
ClipperLib.Clipper.prototype.CopyAELToSEL = function () {
var e = this.m_ActiveEdges;
this.m_SortedEdges = e;
if (this.m_ActiveEdges == null) return;
this.m_SortedEdges.prevInSEL = null;
e = e.nextInAEL;
while (e != null) {
e.prevInSEL = e.prevInAEL;
e.prevInSEL.nextInSEL = e;
e.nextInSEL = null;
e = e.nextInAEL;
}
};
ClipperLib.Clipper.prototype.SwapPositionsInAEL = function (edge1, edge2) {
var next, prev;
if (edge1.nextInAEL == null && edge1.prevInAEL == null) return;
if (edge2.nextInAEL == null && edge2.prevInAEL == null) return;
if (edge1.nextInAEL == edge2) {
next = edge2.nextInAEL;
if (next != null) next.prevInAEL = edge1;
prev = edge1.prevInAEL;
if (prev != null) prev.nextInAEL = edge2;
edge2.prevInAEL = prev;
edge2.nextInAEL = edge1;
edge1.prevInAEL = edge2;
edge1.nextInAEL = next;
}
else if (edge2.nextInAEL == edge1) {
next = edge1.nextInAEL;
if (next != null) next.prevInAEL = edge2;
prev = edge2.prevInAEL;
if (prev != null) prev.nextInAEL = edge1;
edge1.prevInAEL = prev;
edge1.nextInAEL = edge2;
edge2.prevInAEL = edge1;
edge2.nextInAEL = next;
}
else {
next = edge1.nextInAEL;
prev = edge1.prevInAEL;
edge1.nextInAEL = edge2.nextInAEL;
if (edge1.nextInAEL != null) edge1.nextInAEL.prevInAEL = edge1;
edge1.prevInAEL = edge2.prevInAEL;
if (edge1.prevInAEL != null) edge1.prevInAEL.nextInAEL = edge1;
edge2.nextInAEL = next;
if (edge2.nextInAEL != null) edge2.nextInAEL.prevInAEL = edge2;
edge2.prevInAEL = prev;
if (edge2.prevInAEL != null) edge2.prevInAEL.nextInAEL = edge2;
}
if (edge1.prevInAEL == null) this.m_ActiveEdges = edge1;
else if (edge2.prevInAEL == null) this.m_ActiveEdges = edge2;
};
ClipperLib.Clipper.prototype.SwapPositionsInSEL = function (edge1, edge2) {
var next, prev;
if (edge1.nextInSEL == null && edge1.prevInSEL == null) return;
if (edge2.nextInSEL == null && edge2.prevInSEL == null) return;
if (edge1.nextInSEL == edge2) {
next = edge2.nextInSEL;
if (next != null) next.prevInSEL = edge1;
prev = edge1.prevInSEL;
if (prev != null) prev.nextInSEL = edge2;
edge2.prevInSEL = prev;
edge2.nextInSEL = edge1;
edge1.prevInSEL = edge2;
edge1.nextInSEL = next;
}
else if (edge2.nextInSEL == edge1) {
next = edge1.nextInSEL;
if (next != null) next.prevInSEL = edge2;
prev = edge2.prevInSEL;
if (prev != null) prev.nextInSEL = edge1;
edge1.prevInSEL = prev;
edge1.nextInSEL = edge2;
edge2.prevInSEL = edge1;
edge2.nextInSEL = next;
}
else {
next = edge1.nextInSEL;
prev = edge1.prevInSEL;
edge1.nextInSEL = edge2.nextInSEL;
if (edge1.nextInSEL != null) edge1.nextInSEL.prevInSEL = edge1;
edge1.prevInSEL = edge2.prevInSEL;
if (edge1.prevInSEL != null) edge1.prevInSEL.nextInSEL = edge1;
edge2.nextInSEL = next;
if (edge2.nextInSEL != null) edge2.nextInSEL.prevInSEL = edge2;
edge2.prevInSEL = prev;
if (edge2.prevInSEL != null) edge2.prevInSEL.nextInSEL = edge2;
}
if (edge1.prevInSEL == null) this.m_SortedEdges = edge1;
else if (edge2.prevInSEL == null) this.m_SortedEdges = edge2;
};
ClipperLib.Clipper.prototype.AddLocalMaxPoly = function (e1, e2, pt) {
this.AddOutPt(e1, pt);
if (e1.outIdx == e2.outIdx) {
e1.outIdx = -1;
e2.outIdx = -1;
}
else if (e1.outIdx < e2.outIdx) this.AppendPolygon(e1, e2);
else this.AppendPolygon(e2, e1);
};
ClipperLib.Clipper.prototype.AddLocalMinPoly = function (e1, e2, pt) {
var e, prevE;
if (e2.dx == ClipperLib.ClipperBase.horizontal || (e1.dx > e2.dx)) {
this.AddOutPt(e1, pt);
e2.outIdx = e1.outIdx;
e1.side = ClipperLib.EdgeSide.esLeft;
e2.side = ClipperLib.EdgeSide.esRight;
e = e1;
if (e.prevInAEL == e2) prevE = e2.prevInAEL;
else prevE = e.prevInAEL;
}
else {
this.AddOutPt(e2, pt);
e1.outIdx = e2.outIdx;
e1.side = ClipperLib.EdgeSide.esRight;
e2.side = ClipperLib.EdgeSide.esLeft;
e = e2;
if (e.prevInAEL == e1) prevE = e1.prevInAEL;
else prevE = e.prevInAEL;
}
if (prevE != null && prevE.outIdx >= 0 && (ClipperLib.Clipper.TopX(prevE, pt.Y) == ClipperLib.Clipper.TopX(e, pt.Y)) && this.SlopesEqual(e, prevE, this.m_UseFullRange)) this.AddJoin(e, prevE, -1, -1);
};
ClipperLib.Clipper.prototype.CreateOutRec = function () {
var result = new ClipperLib.OutRec();
result.idx = -1;
result.isHole = false;
result.FirstLeft = null;
result.AppendLink = null;
result.pts = null;
result.bottomPt = null;
return result;
};
ClipperLib.Clipper.prototype.AddOutPt = function (e, pt) {
var outRec, op;
var ToFront = (e.side == ClipperLib.EdgeSide.esLeft);
if (e.outIdx < 0) {
outRec = this.CreateOutRec();
this.m_PolyOuts.push(outRec);
outRec.idx = this.m_PolyOuts.length - 1;
e.outIdx = outRec.idx;
op = new ClipperLib.OutPt();
outRec.pts = op;
outRec.bottomPt = op;
op.pt = pt;
op.idx = outRec.idx;
op.next = op;
op.prev = op;
this.SetHoleState(e, outRec);
}
else {
outRec = this.m_PolyOuts[e.outIdx];
op = outRec.pts;
var op2;
if (ToFront && ClipperLib.ClipperBase.PointsEqual(pt, op.pt) || (!ToFront && ClipperLib.ClipperBase.PointsEqual(pt, op.prev.pt))) return;
op2 = new ClipperLib.OutPt();
op2.pt = pt;
op2.idx = outRec.idx;
if (op2.pt.Y == outRec.bottomPt.pt.Y && op2.pt.X < outRec.bottomPt.pt.X) outRec.bottomPt = op2;
op2.next = op;
op2.prev = op.prev;
op2.prev.next = op2;
op.prev = op2;
if (ToFront) outRec.pts = op2;
}
};
ClipperLib.Clipper.prototype.SwapPoints = function (pt1, pt2) {
var tmp = pt1.Value;
pt1.Value = pt2.Value;
pt2.Value = tmp;
};
ClipperLib.Clipper.prototype.GetOverlapSegment = function (pt1a, pt1b, pt2a, pt2b, pt1, pt2) {
if (ClipperLib.Math_Abs_Int64(pt1a.X - pt1b.X) > ClipperLib.Math_Abs_Int64(pt1a.Y - pt1b.Y)) {
if (pt1a.X > pt1b.X)
(function () {
pt1a = {
Value: pt1a
};
pt1b = {
Value: pt1b
};
var $res = this.SwapPoints(pt1a, pt1b);
pt1a = pt1a.Value;
pt1b = pt1b.Value;
return $res;
})
.call(this);
if (pt2a.X > pt2b.X)
(function () {
pt2a = {
Value: pt2a
};
pt2b = {
Value: pt2b
};
var $res = this.SwapPoints(pt2a, pt2b);
pt2a = pt2a.Value;
pt2b = pt2b.Value;
return $res;
})
.call(this);
if (pt1a.X > pt2a.X) pt1.Value = pt1a;
else pt1.Value = pt2a;
if (pt1b.X < pt2b.X) pt2.Value = pt1b;
else pt2.Value = pt2b;
return pt1.Value.X < pt2.Value.X;
}
else {
if (pt1a.Y < pt1b.Y)
(function () {
pt1a = {
Value: pt1a
};
pt1b = {
Value: pt1b
};
var $res = this.SwapPoints(pt1a, pt1b);
pt1a = pt1a.Value;
pt1b = pt1b.Value;
return $res;
})
.call(this);
if (pt2a.Y < pt2b.Y)
(function () {
pt2a = {
Value: pt2a
};
pt2b = {
Value: pt2b
};
var $res = this.SwapPoints(pt2a, pt2b);
pt2a = pt2a.Value;
pt2b = pt2b.Value;
return $res;
})
.call(this);
if (pt1a.Y < pt2a.Y) pt1.Value = pt1a;
else pt1.Value = pt2a;
if (pt1b.Y > pt2b.Y) pt2.Value = pt1b;
else pt2.Value = pt2b;
return pt1.Value.Y > pt2.Value.Y;
}
};
ClipperLib.Clipper.prototype.FindSegment = function (pp, UseFullInt64Range, pt1, pt2) {
if (pp.Value == null) return false;
var pp2 = pp.Value;
var pt1a = new ClipperLib.IntPoint(pt1.Value);
var pt2a = new ClipperLib.IntPoint(pt2.Value);
do {
// Timo's comment: for some reason calling SlopesEqual() below uses big integers
// So although coordinates are low (eg. 900), big integers are sometimes used.
// => Fixed according to changes in original Clipper ver 5.1.2 (25 February 2013)
if (this.SlopesEqual(pt1a, pt2a, pp.Value.pt, pp.Value.prev.pt, UseFullInt64Range) && this.SlopesEqual(pt1a, pt2a, pp.Value.pt, UseFullInt64Range) && this.GetOverlapSegment(pt1a, pt2a, pp.Value.pt, pp.Value.prev.pt, pt1, pt2)) return true;
pp.Value = pp.Value.next;
}
while (pp.Value != pp2);
return false;
};
ClipperLib.Clipper.prototype.Pt3IsBetweenPt1AndPt2 = function (pt1, pt2, pt3) {
if (ClipperLib.ClipperBase.PointsEqual(pt1, pt3) || ClipperLib.ClipperBase.PointsEqual(pt2, pt3)) return true;
else if (pt1.X != pt2.X) return (pt1.X < pt3.X) == (pt3.X < pt2.X);
else return (pt1.Y < pt3.Y) == (pt3.Y < pt2.Y);
};
ClipperLib.Clipper.prototype.InsertPolyPtBetween = function (p1, p2, pt) {
var result = new ClipperLib.OutPt();
result.pt = pt;
if (p2 == p1.next) {
p1.next = result;
p2.prev = result;
result.next = p2;
result.prev = p1;
}
else {
p2.next = result;
p1.prev = result;
result.next = p1;
result.prev = p2;
}
return result;
};
ClipperLib.Clipper.prototype.SetHoleState = function (e, outRec) {
var isHole = false;
var e2 = e.prevInAEL;
while (e2 != null) {
if (e2.outIdx >= 0) {
isHole = !isHole;
if (outRec.FirstLeft == null) outRec.FirstLeft = this.m_PolyOuts[e2.outIdx];
}
e2 = e2.prevInAEL;
}
if (isHole) outRec.isHole = true;
};
ClipperLib.Clipper.prototype.GetDx = function (pt1, pt2) {
if (pt1.Y == pt2.Y) return ClipperLib.ClipperBase.horizontal;
else return (pt2.X - pt1.X) / (pt2.Y - pt1.Y);
};
ClipperLib.Clipper.prototype.FirstIsBottomPt = function (btmPt1, btmPt2) {
var p = btmPt1.prev;
while (ClipperLib.ClipperBase.PointsEqual(p.pt, btmPt1.pt) && (p != btmPt1))
p = p.prev;
var dx1p = ClipperLib.Math_Abs_Double(this.GetDx(btmPt1.pt, p.pt));
p = btmPt1.next;
while (ClipperLib.ClipperBase.PointsEqual(p.pt, btmPt1.pt) && (p != btmPt1))
p = p.next;
var dx1n = ClipperLib.Math_Abs_Double(this.GetDx(btmPt1.pt, p.pt));
p = btmPt2.prev;
while (ClipperLib.ClipperBase.PointsEqual(p.pt, btmPt2.pt) && (p != btmPt2))
p = p.prev;
var dx2p = ClipperLib.Math_Abs_Double(this.GetDx(btmPt2.pt, p.pt));
p = btmPt2.next;
while (ClipperLib.ClipperBase.PointsEqual(p.pt, btmPt2.pt) && (p != btmPt2))
p = p.next;
var dx2n = ClipperLib.Math_Abs_Double(this.GetDx(btmPt2.pt, p.pt));
return (dx1p >= dx2p && dx1p >= dx2n) || (dx1n >= dx2p && dx1n >= dx2n);
};
ClipperLib.Clipper.prototype.GetBottomPt = function (pp) {
var dups = null;
var p = pp.next;
while (p != pp) {
if (p.pt.Y > pp.pt.Y) {
pp = p;
dups = null;
}
else if (p.pt.Y == pp.pt.Y && p.pt.X <= pp.pt.X) {
if (p.pt.X < pp.pt.X) {
dups = null;
pp = p;
}
else {
if (p.next != pp && p.prev != pp) dups = p;
}
}
p = p.next;
}
if (dups != null) {
while (dups != p) {
if (!this.FirstIsBottomPt(p, dups)) pp = dups;
dups = dups.next;
while (!ClipperLib.ClipperBase.PointsEqual(dups.pt, pp.pt))
dups = dups.next;
}
}
return pp;
};
ClipperLib.Clipper.prototype.GetLowermostRec = function (outRec1, outRec2) {
var bPt1 = outRec1.bottomPt;
var bPt2 = outRec2.bottomPt;
if (bPt1.pt.Y > bPt2.pt.Y) return outRec1;
else if (bPt1.pt.Y < bPt2.pt.Y) return outRec2;
else if (bPt1.pt.X < bPt2.pt.X) return outRec1;
else if (bPt1.pt.X > bPt2.pt.X) return outRec2;
else if (bPt1.next == bPt1) return outRec2;
else if (bPt2.next == bPt2) return outRec1;
else if (this.FirstIsBottomPt(bPt1, bPt2)) return outRec1;
else return outRec2;
};
ClipperLib.Clipper.prototype.Param1RightOfParam2 = function (outRec1, outRec2) {
do {
outRec1 = outRec1.FirstLeft;
if (outRec1 == outRec2) return true;
}
while (outRec1 != null);
return false;
};
ClipperLib.Clipper.prototype.AppendPolygon = function (e1, e2) {
var outRec1 = this.m_PolyOuts[e1.outIdx];
var outRec2 = this.m_PolyOuts[e2.outIdx];
var holeStateRec;
if (this.Param1RightOfParam2(outRec1, outRec2)) holeStateRec = outRec2;
else if (this.Param1RightOfParam2(outRec2, outRec1)) holeStateRec = outRec1;
else holeStateRec = this.GetLowermostRec(outRec1, outRec2);
var p1_lft = outRec1.pts;
var p1_rt = p1_lft.prev;
var p2_lft = outRec2.pts;
var p2_rt = p2_lft.prev;
var side;
var i;
if (e1.side == ClipperLib.EdgeSide.esLeft) {
if (e2.side == ClipperLib.EdgeSide.esLeft) {
this.ReversePolyPtLinks(p2_lft);
p2_lft.next = p1_lft;
p1_lft.prev = p2_lft;
p1_rt.next = p2_rt;
p2_rt.prev = p1_rt;
outRec1.pts = p2_rt;
}
else {
p2_rt.next = p1_lft;
p1_lft.prev = p2_rt;
p2_lft.prev = p1_rt;
p1_rt.next = p2_lft;
outRec1.pts = p2_lft;
}
side = ClipperLib.EdgeSide.esLeft;
}
else {
if (e2.side == ClipperLib.EdgeSide.esRight) {
this.ReversePolyPtLinks(p2_lft);
p1_rt.next = p2_rt;
p2_rt.prev = p1_rt;
p2_lft.next = p1_lft;
p1_lft.prev = p2_lft;
}
else {
p1_rt.next = p2_lft;
p2_lft.prev = p1_rt;
p1_lft.prev = p2_rt;
p2_rt.next = p1_lft;
}
side = ClipperLib.EdgeSide.esRight;
}
if (holeStateRec == outRec2) {
outRec1.bottomPt = outRec2.bottomPt;
outRec1.bottomPt.idx = outRec1.idx;
if (outRec2.FirstLeft != outRec1) outRec1.FirstLeft = outRec2.FirstLeft;
outRec1.isHole = outRec2.isHole;
}
outRec2.pts = null;
outRec2.bottomPt = null;
outRec2.AppendLink = outRec1;
var OKIdx = e1.outIdx;
var ObsoleteIdx = e2.outIdx;
e1.outIdx = -1;
e2.outIdx = -1;
var e = this.m_ActiveEdges;
while (e != null) {
if (e.outIdx == ObsoleteIdx) {
e.outIdx = OKIdx;
e.side = side;
break;
}
e = e.nextInAEL;
}
for (i = 0; i < this.m_Joins.length; ++i) {
if (this.m_Joins[i].poly1Idx == ObsoleteIdx) this.m_Joins[i].poly1Idx = OKIdx;
if (this.m_Joins[i].poly2Idx == ObsoleteIdx) this.m_Joins[i].poly2Idx = OKIdx;
}
for (i = 0; i < this.m_HorizJoins.length; ++i) {
if (this.m_HorizJoins[i].savedIdx == ObsoleteIdx) this.m_HorizJoins[i].savedIdx = OKIdx;
}
};
ClipperLib.Clipper.prototype.ReversePolyPtLinks = function (pp) {
if (pp == null) return;
var pp1;
var pp2;
pp1 = pp;
do {
pp2 = pp1.next;
pp1.next = pp1.prev;
pp1.prev = pp2;
pp1 = pp2;
}
while (pp1 != pp);
};
ClipperLib.Clipper.SwapSides = function (edge1, edge2) {
var side = edge1.side;
edge1.side = edge2.side;
edge2.side = side;
};
ClipperLib.Clipper.SwapPolyIndexes = function (edge1, edge2) {
var outIdx = edge1.outIdx;
edge1.outIdx = edge2.outIdx;
edge2.outIdx = outIdx;
};
ClipperLib.Clipper.prototype.DoEdge1 = function (edge1, edge2, pt) {
this.AddOutPt(edge1, pt);
ClipperLib.Clipper.SwapSides(edge1, edge2);
ClipperLib.Clipper.SwapPolyIndexes(edge1, edge2);
};
ClipperLib.Clipper.prototype.DoEdge2 = function (edge1, edge2, pt) {
this.AddOutPt(edge2, pt);
ClipperLib.Clipper.SwapSides(edge1, edge2);
ClipperLib.Clipper.SwapPolyIndexes(edge1, edge2);
};
ClipperLib.Clipper.prototype.DoBothEdges = function (edge1, edge2, pt) {
this.AddOutPt(edge1, pt);
this.AddOutPt(edge2, pt);
ClipperLib.Clipper.SwapSides(edge1, edge2);
ClipperLib.Clipper.SwapPolyIndexes(edge1, edge2);
};
ClipperLib.Clipper.prototype.IntersectEdges = function (e1, e2, pt, protects) {
var e1stops = (ClipperLib.Protects.ipLeft & protects) == 0 && e1.nextInLML == null && e1.xtop == pt.X && e1.ytop == pt.Y;
var e2stops = (ClipperLib.Protects.ipRight & protects) == 0 && e2.nextInLML == null && e2.xtop == pt.X && e2.ytop == pt.Y;
var e1Contributing = (e1.outIdx >= 0);
var e2contributing = (e2.outIdx >= 0);
if (e1.polyType == e2.polyType) {
if (this.IsEvenOddFillType(e1)) {
var oldE1WindCnt = e1.windCnt;
e1.windCnt = e2.windCnt;
e2.windCnt = oldE1WindCnt;
}
else {
if (e1.windCnt + e2.windDelta == 0) e1.windCnt = -e1.windCnt;
else e1.windCnt += e2.windDelta;
if (e2.windCnt - e1.windDelta == 0) e2.windCnt = -e2.windCnt;
else e2.windCnt -= e1.windDelta;
}
}
else {
if (!this.IsEvenOddFillType(e2)) e1.windCnt2 += e2.windDelta;
else e1.windCnt2 = (e1.windCnt2 == 0) ? 1 : 0;
if (!this.IsEvenOddFillType(e1)) e2.windCnt2 -= e1.windDelta;
else e2.windCnt2 = (e2.windCnt2 == 0) ? 1 : 0;
}
var e1FillType, e2FillType, e1FillType2, e2FillType2;
if (e1.polyType == ClipperLib.PolyType.ptSubject) {
e1FillType = this.m_SubjFillType;
e1FillType2 = this.m_ClipFillType;
}
else {
e1FillType = this.m_ClipFillType;
e1FillType2 = this.m_SubjFillType;
}
if (e2.polyType == ClipperLib.PolyType.ptSubject) {
e2FillType = this.m_SubjFillType;
e2FillType2 = this.m_ClipFillType;
}
else {
e2FillType = this.m_ClipFillType;
e2FillType2 = this.m_SubjFillType;
}
var e1Wc, e2Wc;
switch (e1FillType) {
case ClipperLib.PolyFillType.pftPositive:
e1Wc = e1.windCnt;
break;
case ClipperLib.PolyFillType.pftNegative:
e1Wc = -e1.windCnt;
break;
default:
e1Wc = ClipperLib.Math_Abs_Int32(e1.windCnt);
break;
}
switch (e2FillType) {
case ClipperLib.PolyFillType.pftPositive:
e2Wc = e2.windCnt;
break;
case ClipperLib.PolyFillType.pftNegative:
e2Wc = -e2.windCnt;
break;
default:
e2Wc = ClipperLib.Math_Abs_Int32(e2.windCnt);
break;
}
if (e1Contributing && e2contributing) {
if (e1stops || e2stops || (e1Wc != 0 && e1Wc != 1) || (e2Wc != 0 && e2Wc != 1) || (e1.polyType != e2.polyType && this.m_ClipType != ClipperLib.ClipType.ctXor)) this.AddLocalMaxPoly(e1, e2, pt);
else this.DoBothEdges(e1, e2, pt);
}
else if (e1Contributing) {
if ((e2Wc == 0 || e2Wc == 1) && (this.m_ClipType != ClipperLib.ClipType.ctIntersection || e2.polyType == ClipperLib.PolyType.ptSubject || (e2.windCnt2 != 0))) this.DoEdge1(e1, e2, pt);
}
else if (e2contributing) {
if ((e1Wc == 0 || e1Wc == 1) && (this.m_ClipType != ClipperLib.ClipType.ctIntersection || e1.polyType == ClipperLib.PolyType.ptSubject || (e1.windCnt2 != 0))) this.DoEdge2(e1, e2, pt);
}
else if ((e1Wc == 0 || e1Wc == 1) && (e2Wc == 0 || e2Wc == 1) && !e1stops && !e2stops) {
var e1Wc2, e2Wc2;
switch (e1FillType2) {
case ClipperLib.PolyFillType.pftPositive:
e1Wc2 = e1.windCnt2;
break;
case ClipperLib.PolyFillType.pftNegative:
e1Wc2 = -e1.windCnt2;
break;
default:
e1Wc2 = ClipperLib.Math_Abs_Int32(e1.windCnt2);
break;
}
switch (e2FillType2) {
case ClipperLib.PolyFillType.pftPositive:
e2Wc2 = e2.windCnt2;
break;
case ClipperLib.PolyFillType.pftNegative:
e2Wc2 = -e2.windCnt2;
break;
default:
e2Wc2 = ClipperLib.Math_Abs_Int32(e2.windCnt2);
break;
}
if (e1.polyType != e2.polyType) this.AddLocalMinPoly(e1, e2, pt);
else if (e1Wc == 1 && e2Wc == 1) switch (this.m_ClipType) {
case ClipperLib.ClipType.ctIntersection:
if (e1Wc2 > 0 && e2Wc2 > 0) this.AddLocalMinPoly(e1, e2, pt);
break;
case ClipperLib.ClipType.ctUnion:
if (e1Wc2 <= 0 && e2Wc2 <= 0) this.AddLocalMinPoly(e1, e2, pt);
break;
case ClipperLib.ClipType.ctDifference:
if (((e1.polyType == ClipperLib.PolyType.ptClip) && (e1Wc2 > 0) && (e2Wc2 > 0)) || ((e1.polyType == ClipperLib.PolyType.ptSubject) && (e1Wc2 <= 0) && (e2Wc2 <= 0))) this.AddLocalMinPoly(e1, e2, pt);
break;
case ClipperLib.ClipType.ctXor:
this.AddLocalMinPoly(e1, e2, pt);
break;
}
else ClipperLib.Clipper.SwapSides(e1, e2);
}
if ((e1stops != e2stops) && ((e1stops && (e1.outIdx >= 0)) || (e2stops && (e2.outIdx >= 0)))) {
ClipperLib.Clipper.SwapSides(e1, e2);
ClipperLib.Clipper.SwapPolyIndexes(e1, e2);
}
if (e1stops) this.DeleteFromAEL(e1);
if (e2stops) this.DeleteFromAEL(e2);
};
ClipperLib.Clipper.prototype.DeleteFromAEL = function (e) {
var AelPrev = e.prevInAEL;
var AelNext = e.nextInAEL;
if (AelPrev == null && AelNext == null && (e != this.m_ActiveEdges)) return;
if (AelPrev != null) AelPrev.nextInAEL = AelNext;
else this.m_ActiveEdges = AelNext;
if (AelNext != null) AelNext.prevInAEL = AelPrev;
e.nextInAEL = null;
e.prevInAEL = null;
};
ClipperLib.Clipper.prototype.DeleteFromSEL = function (e) {
var SelPrev = e.prevInSEL;
var SelNext = e.nextInSEL;
if (SelPrev == null && SelNext == null && (e != this.m_SortedEdges)) return;
if (SelPrev != null) SelPrev.nextInSEL = SelNext;
else this.m_SortedEdges = SelNext;
if (SelNext != null) SelNext.prevInSEL = SelPrev;
e.nextInSEL = null;
e.prevInSEL = null;
};
ClipperLib.Clipper.prototype.UpdateEdgeIntoAEL = function (e) {
if (e.Value.nextInLML == null) ClipperLib.Error("UpdateEdgeIntoAEL: invalid call");
var AelPrev = e.Value.prevInAEL;
var AelNext = e.Value.nextInAEL;
e.Value.nextInLML.outIdx = e.Value.outIdx;
if (AelPrev != null) AelPrev.nextInAEL = e.Value.nextInLML;
else this.m_ActiveEdges = e.Value.nextInLML;
if (AelNext != null) AelNext.prevInAEL = e.Value.nextInLML;
e.Value.nextInLML.side = e.Value.side;
e.Value.nextInLML.windDelta = e.Value.windDelta;
e.Value.nextInLML.windCnt = e.Value.windCnt;
e.Value.nextInLML.windCnt2 = e.Value.windCnt2;
e.Value = e.Value.nextInLML;
e.Value.prevInAEL = AelPrev;
e.Value.nextInAEL = AelNext;
if (e.Value.dx != ClipperLib.ClipperBase.horizontal) this.InsertScanbeam(e.Value.ytop);
};
ClipperLib.Clipper.prototype.ProcessHorizontals = function () {
var horzEdge = this.m_SortedEdges;
while (horzEdge != null) {
this.DeleteFromSEL(horzEdge);
this.ProcessHorizontal(horzEdge);
horzEdge = this.m_SortedEdges;
}
};
ClipperLib.Clipper.prototype.ProcessHorizontal = function (horzEdge) {
var Direction;
var horzLeft, horzRight;
if (horzEdge.xcurr < horzEdge.xtop) {
horzLeft = horzEdge.xcurr;
horzRight = horzEdge.xtop;
Direction = ClipperLib.Direction.dLeftToRight;
}
else {
horzLeft = horzEdge.xtop;
horzRight = horzEdge.xcurr;
Direction = ClipperLib.Direction.dRightToLeft;
}
var eMaxPair;
if (horzEdge.nextInLML != null) eMaxPair = null;
else eMaxPair = this.GetMaximaPair(horzEdge);
var e = this.GetNextInAEL(horzEdge, Direction);
while (e != null) {
var eNext = this.GetNextInAEL(e, Direction);
if (eMaxPair != null || ((Direction == ClipperLib.Direction.dLeftToRight) && (e.xcurr <= horzRight)) || ((Direction == ClipperLib.Direction.dRightToLeft) && (e.xcurr >= horzLeft))) {
if (e.xcurr == horzEdge.xtop && eMaxPair == null) {
if (this.SlopesEqual(e, horzEdge.nextInLML, this.m_UseFullRange)) {
if (horzEdge.outIdx >= 0 && e.outIdx >= 0) this.AddJoin(horzEdge.nextInLML, e, horzEdge.outIdx, -1);
break;
}
else if (e.dx < horzEdge.nextInLML.dx) break;
}
if (e == eMaxPair) {
if (Direction == ClipperLib.Direction.dLeftToRight) this.IntersectEdges(horzEdge, e, new ClipperLib.IntPoint(e.xcurr, horzEdge.ycurr), 0);
else this.IntersectEdges(e, horzEdge, new ClipperLib.IntPoint(e.xcurr, horzEdge.ycurr), 0);
if (eMaxPair.outIdx >= 0) ClipperLib.Error("ProcessHorizontal error");
return;
}
else if (e.dx == ClipperLib.ClipperBase.horizontal && !this.IsMinima(e) && !(e.xcurr > e.xtop)) {
if (Direction == ClipperLib.Direction.dLeftToRight) this.IntersectEdges(horzEdge, e, new ClipperLib.IntPoint(e.xcurr, horzEdge.ycurr), (this.IsTopHorz(horzEdge, e.xcurr)) ? ClipperLib.Protects.ipLeft : ClipperLib.Protects.ipBoth);
else this.IntersectEdges(e, horzEdge, new ClipperLib.IntPoint(e.xcurr, horzEdge.ycurr), (this.IsTopHorz(horzEdge, e.xcurr)) ? ClipperLib.Protects.ipRight : ClipperLib.Protects.ipBoth);
}
else if (Direction == ClipperLib.Direction.dLeftToRight) {
this.IntersectEdges(horzEdge, e, new ClipperLib.IntPoint(e.xcurr, horzEdge.ycurr), (this.IsTopHorz(horzEdge, e.xcurr)) ? ClipperLib.Protects.ipLeft : ClipperLib.Protects.ipBoth);
}
else {
this.IntersectEdges(e, horzEdge, new ClipperLib.IntPoint(e.xcurr, horzEdge.ycurr), (this.IsTopHorz(horzEdge, e.xcurr)) ? ClipperLib.Protects.ipRight : ClipperLib.Protects.ipBoth);
}
this.SwapPositionsInAEL(horzEdge, e);
}
else if ((Direction == ClipperLib.Direction.dLeftToRight && e.xcurr > horzRight && horzEdge.nextInSEL == null) || (Direction == ClipperLib.Direction.dRightToLeft && e.xcurr < horzLeft && horzEdge.nextInSEL == null)) break;
e = eNext;
}
if (horzEdge.nextInLML != null) {
if (horzEdge.outIdx >= 0) this.AddOutPt(horzEdge, new ClipperLib.IntPoint(horzEdge.xtop, horzEdge.ytop));
(function () {
horzEdge = {
Value: horzEdge
};
var $res = this.UpdateEdgeIntoAEL(horzEdge);
horzEdge = horzEdge.Value;
return $res;
})
.call(this);
}
else {
if (horzEdge.outIdx >= 0) this.IntersectEdges(horzEdge, eMaxPair, new ClipperLib.IntPoint(horzEdge.xtop, horzEdge.ycurr), ClipperLib.Protects.ipBoth);
this.DeleteFromAEL(eMaxPair);
this.DeleteFromAEL(horzEdge);
}
};
ClipperLib.Clipper.prototype.IsTopHorz = function (horzEdge, XPos) {
var e = this.m_SortedEdges;
while (e != null) {
if ((XPos >= Math.min(e.xcurr, e.xtop)) && (XPos <= Math.max(e.xcurr, e.xtop))) return false;
e = e.nextInSEL;
}
return true;
};
ClipperLib.Clipper.prototype.GetNextInAEL = function (e, Direction) {
return Direction == ClipperLib.Direction.dLeftToRight ? e.nextInAEL : e.prevInAEL;
};
ClipperLib.Clipper.prototype.IsMinima = function (e) {
return e != null && (e.prev.nextInLML != e) && (e.next.nextInLML != e);
};
ClipperLib.Clipper.prototype.IsMaxima = function (e, Y) {
return (e != null && e.ytop == Y && e.nextInLML == null);
};
ClipperLib.Clipper.prototype.IsIntermediate = function (e, Y) {
return (e.ytop == Y && e.nextInLML != null);
};
ClipperLib.Clipper.prototype.GetMaximaPair = function (e) {
if (!this.IsMaxima(e.next, e.ytop) || (e.next.xtop != e.xtop)) return e.prev;
else return e.next;
};
ClipperLib.Clipper.prototype.ProcessIntersections = function (botY, topY) {
if (this.m_ActiveEdges == null) return true;
try {
if (this.alternateAlgo)
this.BuildIntersectList2(botY, topY);
else
this.BuildIntersectList2(botY, topY);
if (this.m_IntersectNodes == null) return true;
if (this.FixupIntersections()) this.ProcessIntersectList();
else return false;
}
catch ($$e2) {
this.m_SortedEdges = null;
this.DisposeIntersectNodes();
ClipperLib.Error("ProcessIntersections error");
}
return true;
};
ClipperLib.Clipper.prototype.BuildIntersectList2 = function (botY, topY) {
if (this.m_ActiveEdges == null) return;
var e = this.m_ActiveEdges;
e.tmpX = ClipperLib.Clipper.TopX(e, topY);
this.m_SortedEdges = e;
this.m_SortedEdges.prevInSEL = null;
e = e.nextInAEL;
while (e != null) {
e.prevInSEL = e.prevInAEL;
e.prevInSEL.nextInSEL = e;
e.nextInSEL = null;
e.tmpX = ClipperLib.Clipper.TopX(e, topY);
e = e.nextInAEL;
}
var isModified = true;
var intersectArray = [];
while (isModified && this.m_SortedEdges != null) {
isModified = false;
e = this.m_SortedEdges;
while (e.nextInSEL != null) {
var eNext = e.nextInSEL;
var pt = new ClipperLib.IntPoint();
if (e.tmpX > eNext.tmpX && (function () {
pt = {
Value: pt
};
var $res = this.IntersectPoint(e, eNext, pt);
pt = pt.Value;
return $res;
})
.call(this)) {
if (pt.Y > botY) {
pt.Y = botY;
pt.X = ClipperLib.Clipper.TopX(e, pt.Y);
}
this.SwapPositionsInSEL(e, eNext);
intersectArray.push(this.CreateIntersectNode(e, eNext, pt));
isModified = true;
}
else e = eNext;
}
if (e.prevInSEL != null) e.prevInSEL.nextInSEL = null;
else break;
}
this.AddBulkIntersectNodes(intersectArray);
this.m_SortedEdges = null;
};
ClipperLib.Clipper.prototype.AddBulkIntersectNodes = function (intersectArray) {
intersectArray.sort(function (a, b) {
return ClipperLib.Clipper.prototype.ProcessParam1BeforeParam2(a, b) ? -1 : 1;
});
var startNode = this.m_IntersectNodes;
for (var i = 0; i < intersectArray.length; i++) {
var newNode = intersectArray[i];
if (this.m_IntersectNodes == null) this.m_IntersectNodes = newNode;
else if (this.ProcessParam1BeforeParam2(newNode, this.m_IntersectNodes)) {
newNode.next = this.m_IntersectNodes;
this.m_IntersectNodes = newNode;
}
else {
var iNode = startNode;
while (iNode.next != null && this.ProcessParam1BeforeParam2(iNode.next, newNode))
iNode = iNode.next;
newNode.next = iNode.next;
iNode.next = newNode;
}
startNode = newNode;
}
}
ClipperLib.Clipper.prototype.CreateIntersectNode = function (e1, e2, pt) {
var newNode = new ClipperLib.IntersectNode();
newNode.edge1 = e1;
newNode.edge2 = e2;
newNode.pt = pt;
newNode.next = null;
return newNode;
}
ClipperLib.Clipper.prototype.BuildIntersectList = function (botY, topY) {
if (this.m_ActiveEdges == null) return;
var e = this.m_ActiveEdges;
e.tmpX = ClipperLib.Clipper.TopX(e, topY);
this.m_SortedEdges = e;
this.m_SortedEdges.prevInSEL = null;
e = e.nextInAEL;
while (e != null) {
e.prevInSEL = e.prevInAEL;
e.prevInSEL.nextInSEL = e;
e.nextInSEL = null;
e.tmpX = ClipperLib.Clipper.TopX(e, topY);
e = e.nextInAEL;
}
var isModified = true;
while (isModified && this.m_SortedEdges != null) {
isModified = false;
e = this.m_SortedEdges;
while (e.nextInSEL != null) {
var eNext = e.nextInSEL;
var pt = new ClipperLib.IntPoint();
if (e.tmpX > eNext.tmpX && (function () {
pt = {
Value: pt
};
var $res = this.IntersectPoint(e, eNext, pt);
pt = pt.Value;
return $res;
})
.call(this)) {
if (pt.Y > botY) {
pt.Y = botY;
pt.X = ClipperLib.Clipper.TopX(e, pt.Y);
}
this.AddIntersectNode(e, eNext, pt);
this.SwapPositionsInSEL(e, eNext);
isModified = true;
}
else e = eNext;
}
if (e.prevInSEL != null) e.prevInSEL.nextInSEL = null;
else break;
}
this.m_SortedEdges = null;
};
ClipperLib.Clipper.prototype.FixupIntersections = function () {
if (this.m_IntersectNodes.next == null) return true;
this.CopyAELToSEL();
var int1 = this.m_IntersectNodes;
var int2 = this.m_IntersectNodes.next;
while (int2 != null) {
var e1 = int1.edge1;
var e2;
if (e1.prevInSEL == int1.edge2) e2 = e1.prevInSEL;
else if (e1.nextInSEL == int1.edge2) e2 = e1.nextInSEL;
else {
while (int2 != null) {
if (int2.edge1.nextInSEL == int2.edge2 || int2.edge1.prevInSEL == int2.edge2) break;
else int2 = int2.next;
}
if (int2 == null) return false;
this.SwapIntersectNodes(int1, int2);
e1 = int1.edge1;
e2 = int1.edge2;
}
this.SwapPositionsInSEL(e1, e2);
int1 = int1.next;
int2 = int1.next;
}
this.m_SortedEdges = null;
return (int1.edge1.prevInSEL == int1.edge2 || int1.edge1.nextInSEL == int1.edge2);
};
ClipperLib.Clipper.prototype.ProcessIntersectList = function () {
while (this.m_IntersectNodes != null) {
var iNode = this.m_IntersectNodes.next;
this.IntersectEdges(this.m_IntersectNodes.edge1, this.m_IntersectNodes.edge2, this.m_IntersectNodes.pt, ClipperLib.Protects.ipBoth);
this.SwapPositionsInAEL(this.m_IntersectNodes.edge1, this.m_IntersectNodes.edge2);
this.m_IntersectNodes = null;
this.m_IntersectNodes = iNode;
}
};
/*
--------------------------------
Round speedtest: http://jsperf.com/fastest-round
--------------------------------
*/
var R1 = function (a) {
return a < 0 ? Math.ceil(a - 0.5) : Math.round(a)
};
var R2 = function (a) {
return a < 0 ? Math.ceil(a - 0.5) : Math.floor(a + 0.5)
};
var R3 = function (a) {
return a < 0 ? -Math.round(Math.abs(a)) : Math.round(a)
};
var R4 = function (a) {
if (a < 0) {
a -= 0.5;
return a < -2147483648 ? Math.ceil(a) : a | 0;
} else {
a += 0.5;
return a > 2147483647 ? Math.floor(a) : a | 0;
}
};
if (browser.msie) ClipperLib.Clipper.Round = R1;
else if (browser.chromium) ClipperLib.Clipper.Round = R3;
else if (browser.safari) ClipperLib.Clipper.Round = R4;
else ClipperLib.Clipper.Round = R2; // eg. browser.chrome || browser.firefox || browser.opera
ClipperLib.Clipper.TopX = function (edge, currentY) {
if (currentY == edge.ytop) return edge.xtop;
return edge.xbot + ClipperLib.Clipper.Round(edge.dx * (currentY - edge.ybot));
};
ClipperLib.Clipper.prototype.AddIntersectNode = function (e1, e2, pt) {
var newNode = new ClipperLib.IntersectNode();
newNode.edge1 = e1;
newNode.edge2 = e2;
newNode.pt = pt;
newNode.next = null;
if (this.m_IntersectNodes == null) this.m_IntersectNodes = newNode;
else if (this.ProcessParam1BeforeParam2(newNode, this.m_IntersectNodes)) {
newNode.next = this.m_IntersectNodes;
this.m_IntersectNodes = newNode;
}
else {
var iNode = this.m_IntersectNodes;
while (iNode.next != null && this.ProcessParam1BeforeParam2(iNode.next, newNode))
iNode = iNode.next;
newNode.next = iNode.next;
iNode.next = newNode;
}
};
ClipperLib.Clipper.prototype.ProcessParam1BeforeParam2 = function (node1, node2) {
var result;
if (node1.pt.Y == node2.pt.Y) {
if (node1.edge1 == node2.edge1 || node1.edge2 == node2.edge1) {
result = node2.pt.X > node1.pt.X;
return node2.edge1.dx > 0 ? !result : result;
}
else if (node1.edge1 == node2.edge2 || node1.edge2 == node2.edge2) {
result = node2.pt.X > node1.pt.X;
return node2.edge2.dx > 0 ? !result : result;
}
else return node2.pt.X > node1.pt.X;
}
else return node1.pt.Y > node2.pt.Y;
};
ClipperLib.Clipper.prototype.SwapIntersectNodes = function (int1, int2) {
var e1 = int1.edge1;
var e2 = int1.edge2;
var p = int1.pt;
int1.edge1 = int2.edge1;
int1.edge2 = int2.edge2;
int1.pt = int2.pt;
int2.edge1 = e1;
int2.edge2 = e2;
int2.pt = p;
};
ClipperLib.Clipper.prototype.IntersectPoint = function (edge1, edge2, ip) {
var b1, b2;
if (this.SlopesEqual(edge1, edge2, this.m_UseFullRange)) return false;
else if (edge1.dx == 0) {
ip.Value.X = edge1.xbot;
if (edge2.dx == ClipperLib.ClipperBase.horizontal) {
ip.Value.Y = edge2.ybot;
}
else {
b2 = edge2.ybot - (edge2.xbot / edge2.dx);
ip.Value.Y = ClipperLib.Clipper.Round(ip.Value.X / edge2.dx + b2);
}
}
else if (edge2.dx == 0) {
ip.Value.X = edge2.xbot;
if (edge1.dx == ClipperLib.ClipperBase.horizontal) {
ip.Value.Y = edge1.ybot;
}
else {
b1 = edge1.ybot - (edge1.xbot / edge1.dx);
ip.Value.Y = ClipperLib.Clipper.Round(ip.Value.X / edge1.dx + b1);
}
}
else {
b1 = edge1.xbot - edge1.ybot * edge1.dx;
b2 = edge2.xbot - edge2.ybot * edge2.dx;
var q = (b2 - b1) / (edge1.dx - edge2.dx);
ip.Value.Y = ClipperLib.Clipper.Round(q);
if (ClipperLib.Math_Abs_Double(edge1.dx) < ClipperLib.Math_Abs_Double(edge2.dx)) ip.Value.X = ClipperLib.Clipper.Round(edge1.dx * q + b1);
else ip.Value.X = ClipperLib.Clipper.Round(edge2.dx * q + b2);
}
if (ip.Value.Y < edge1.ytop || ip.Value.Y < edge2.ytop) {
if (edge1.ytop > edge2.ytop) {
ip.Value.X = edge1.xtop;
ip.Value.Y = edge1.ytop;
return ClipperLib.Clipper.TopX(edge2, edge1.ytop) < edge1.xtop;
}
else {
ip.Value.X = edge2.xtop;
ip.Value.Y = edge2.ytop;
return ClipperLib.Clipper.TopX(edge1, edge2.ytop) > edge2.xtop;
}
}
else return true;
};
ClipperLib.Clipper.prototype.DisposeIntersectNodes = function () {
while (this.m_IntersectNodes != null) {
var iNode = this.m_IntersectNodes.next;
this.m_IntersectNodes = null;
this.m_IntersectNodes = iNode;
}
};
ClipperLib.Clipper.prototype.ProcessEdgesAtTopOfScanbeam = function (topY) {
var e = this.m_ActiveEdges;
var ePrev;
while (e != null) {
if (this.IsMaxima(e, topY) && this.GetMaximaPair(e)
.dx != ClipperLib.ClipperBase.horizontal) {
ePrev = e.prevInAEL;
this.DoMaxima(e, topY);
if (ePrev == null) e = this.m_ActiveEdges;
else e = ePrev.nextInAEL;
}
else {
if (this.IsIntermediate(e, topY) && e.nextInLML.dx == ClipperLib.ClipperBase.horizontal) {
if (e.outIdx >= 0) {
this.AddOutPt(e, new ClipperLib.IntPoint(e.xtop, e.ytop));
for (var i = 0; i < this.m_HorizJoins.length; ++i) {
var pt = new ClipperLib.IntPoint(),
pt2 = new ClipperLib.IntPoint();
var hj = this.m_HorizJoins[i];
if ((function () {
pt = {
Value: pt
};
pt2 = {
Value: pt2
};
var $res = this.GetOverlapSegment(new ClipperLib.IntPoint(hj.edge.xbot, hj.edge.ybot),
new ClipperLib.IntPoint(hj.edge.xtop, hj.edge.ytop),
new ClipperLib.IntPoint(e.nextInLML.xbot, e.nextInLML.ybot),
new ClipperLib.IntPoint(e.nextInLML.xtop, e.nextInLML.ytop), pt, pt2);
pt = pt.Value;
pt2 = pt2.Value;
return $res;
})
.call(this)) this.AddJoin(hj.edge, e.nextInLML, hj.savedIdx, e.outIdx);
}
this.AddHorzJoin(e.nextInLML, e.outIdx);
}
(function () {
e = {
Value: e
};
var $res = this.UpdateEdgeIntoAEL(e);
e = e.Value;
return $res;
})
.call(this);
this.AddEdgeToSEL(e);
}
else {
e.xcurr = ClipperLib.Clipper.TopX(e, topY);
e.ycurr = topY;
}
e = e.nextInAEL;
}
}
this.ProcessHorizontals();
e = this.m_ActiveEdges;
while (e != null) {
if (this.IsIntermediate(e, topY)) {
if (e.outIdx >= 0) this.AddOutPt(e, new ClipperLib.IntPoint(e.xtop, e.ytop));
(function () {
e = {
Value: e
};
var $res = this.UpdateEdgeIntoAEL(e);
e = e.Value;
return $res;
})
.call(this);
ePrev = e.prevInAEL;
var eNext = e.nextInAEL;
if (ePrev != null && ePrev.xcurr == e.xbot && ePrev.ycurr == e.ybot && e.outIdx >= 0 && ePrev.outIdx >= 0 && ePrev.ycurr > ePrev.ytop && this.SlopesEqual(e, ePrev, this.m_UseFullRange)) {
this.AddOutPt(ePrev, new ClipperLib.IntPoint(e.xbot, e.ybot));
this.AddJoin(e, ePrev, -1, -1);
}
else if (eNext != null && eNext.xcurr == e.xbot && eNext.ycurr == e.ybot && e.outIdx >= 0 && eNext.outIdx >= 0 && eNext.ycurr > eNext.ytop && this.SlopesEqual(e, eNext, this.m_UseFullRange)) {
this.AddOutPt(eNext, new ClipperLib.IntPoint(e.xbot, e.ybot));
this.AddJoin(e, eNext, -1, -1);
}
}
e = e.nextInAEL;
}
};
ClipperLib.Clipper.prototype.DoMaxima = function (e, topY) {
var eMaxPair = this.GetMaximaPair(e);
var X = e.xtop;
var eNext = e.nextInAEL;
while (eNext != eMaxPair) {
if (eNext == null) ClipperLib.Error("DoMaxima error");
this.IntersectEdges(e, eNext, new ClipperLib.IntPoint(X, topY), ClipperLib.Protects.ipBoth);
eNext = eNext.nextInAEL;
}
if (e.outIdx < 0 && eMaxPair.outIdx < 0) {
this.DeleteFromAEL(e);
this.DeleteFromAEL(eMaxPair);
}
else if (e.outIdx >= 0 && eMaxPair.outIdx >= 0) {
this.IntersectEdges(e, eMaxPair, new ClipperLib.IntPoint(X, topY), ClipperLib.Protects.ipNone);
}
else ClipperLib.Error("DoMaxima error");
};
ClipperLib.Clipper.ReversePolygons = function (polys) {
var len = polys.length,
poly;
for (var i = 0; i < len; i++) {
if (polys[i] instanceof Array) polys[i].reverse();
}
};
ClipperLib.Clipper.Orientation = function (poly) {
return this.Area(poly) >= 0;
};
ClipperLib.Clipper.prototype.PointCount = function (pts) {
if (pts == null) return 0;
var result = 0;
var p = pts;
do {
result++;
p = p.next;
}
while (p != pts);
return result;
};
ClipperLib.Clipper.prototype.BuildResult = function (polyg) {
ClipperLib.Clear(polyg);
var outRec, len = this.m_PolyOuts.length;
for (var i = 0; i < len; i++) {
outRec = this.m_PolyOuts[i];
if (outRec.pts == null) continue;
var p = outRec.pts;
var cnt = this.PointCount(p);
if (cnt < 3) continue;
var pg = new ClipperLib.Polygon(cnt);
for (var j = 0; j < cnt; j++) {
//pg.push(p.pt);
pg.push(new ClipperLib.IntPoint(p.pt.X, p.pt.Y)); // Have to create new point, because the point can be a reference to other point
p = p.prev;
}
polyg.push(pg);
}
};
ClipperLib.Clipper.prototype.BuildResultEx = function (polyg) {
ClipperLib.Clear(polyg);
var i = 0;
while (i < this.m_PolyOuts.length) {
var outRec = this.m_PolyOuts[i++];
if (outRec.pts == null) break;
var p = outRec.pts;
var cnt = this.PointCount(p);
if (cnt < 3) continue;
var epg = new ClipperLib.ExPolygon();
epg.outer = new ClipperLib.Polygon();
epg.holes = new ClipperLib.Polygons();
for (var j = 0; j < cnt; j++) {
//epg.outer.push(p.pt);
epg.outer.push(new ClipperLib.IntPoint(p.pt.X, p.pt.Y)); // Have to create new point, because the point can be a reference to other point
p = p.prev;
}
while (i < this.m_PolyOuts.length) {
outRec = this.m_PolyOuts[i];
if (outRec.pts == null || !outRec.isHole) break;
var pg = new ClipperLib.Polygon();
p = outRec.pts;
do {
//pg.push(p.pt);
pg.push(new ClipperLib.IntPoint(p.pt.X, p.pt.Y)); // Have to create new point, because the point can be a reference to other point
p = p.prev;
}
while (p != outRec.pts);
epg.holes.push(pg);
i++;
}
polyg.push(epg);
}
};
ClipperLib.Clipper.prototype.FixupOutPolygon = function (outRec) {
var lastOK = null;
outRec.pts = outRec.bottomPt;
var pp = outRec.bottomPt;
for (; ;) {
if (pp.prev == pp || pp.prev == pp.next) {
this.DisposeOutPts(pp);
outRec.pts = null;
outRec.bottomPt = null;
return;
}
if (ClipperLib.ClipperBase.PointsEqual(pp.pt, pp.next.pt) || this.SlopesEqual(pp.prev.pt, pp.pt, pp.next.pt, this.m_UseFullRange)) {
lastOK = null;
var tmp = pp;
if (pp == outRec.bottomPt) outRec.bottomPt = null;
pp.prev.next = pp.next;
pp.next.prev = pp.prev;
pp = pp.prev;
tmp = null;
}
else if (pp == lastOK) break;
else {
if (lastOK == null) lastOK = pp;
pp = pp.next;
}
}
if (outRec.bottomPt == null) {
outRec.bottomPt = this.GetBottomPt(pp);
outRec.bottomPt.idx = outRec.idx;
outRec.pts = outRec.bottomPt;
}
};
ClipperLib.Clipper.prototype.JoinPoints = function (j, p1, p2) {
p1.Value = null;
p2.Value = null;
var outRec1 = this.m_PolyOuts[j.poly1Idx];
var outRec2 = this.m_PolyOuts[j.poly2Idx];
if (outRec1 == null || outRec2 == null) return false;
var pp1a = outRec1.pts;
var pp2a = outRec2.pts;
var pt1 = j.pt2a,
pt2 = j.pt2b;
var pt3 = j.pt1a,
pt4 = j.pt1b;
if (!(function () {
pp1a = {
Value: pp1a
};
pt1 = {
Value: pt1
};
pt2 = {
Value: pt2
};
var $res = this.FindSegment(pp1a, this.m_UseFullRange, pt1, pt2);
pp1a = pp1a.Value;
pt1 = pt1.Value;
pt2 = pt2.Value;
return $res;
})
.call(this)) return false;
if (outRec1 == outRec2) {
pp2a = pp1a.next;
if (!(function () {
pp2a = {
Value: pp2a
};
pt3 = {
Value: pt3
};
pt4 = {
Value: pt4
};
var $res = this.FindSegment(pp2a, this.m_UseFullRange, pt3, pt4);
pp2a = pp2a.Value;
pt3 = pt3.Value;
pt4 = pt4.Value;
return $res;
})
.call(this) || (pp2a == pp1a)) return false;
}
else if (!(function () {
pp2a = {
Value: pp2a
};
pt3 = {
Value: pt3
};
pt4 = {
Value: pt4
};
var $res = this.FindSegment(pp2a, this.m_UseFullRange, pt3, pt4);
pp2a = pp2a.Value;
pt3 = pt3.Value;
pt4 = pt4.Value;
return $res;
})
.call(this)) return false;
if (!(function () {
pt1 = {
Value: pt1
};
pt2 = {
Value: pt2
};
var $res = this.GetOverlapSegment(pt1.Value, pt2.Value, pt3, pt4, pt1, pt2);
pt1 = pt1.Value;
pt2 = pt2.Value;
return $res;
})
.call(this)) {
return false;
}
var p3, p4, prev = pp1a.prev;
if (ClipperLib.ClipperBase.PointsEqual(pp1a.pt, pt1)) p1.Value = pp1a;
else if (ClipperLib.ClipperBase.PointsEqual(prev.pt, pt1)) p1.Value = prev;
else p1.Value = this.InsertPolyPtBetween(pp1a, prev, pt1);
if (ClipperLib.ClipperBase.PointsEqual(pp1a.pt, pt2)) p2.Value = pp1a;
else if (ClipperLib.ClipperBase.PointsEqual(prev.pt, pt2)) p2.Value = prev;
else if ((p1.Value == pp1a) || (p1.Value == prev)) p2.Value = this.InsertPolyPtBetween(pp1a, prev, pt2);
else if (this.Pt3IsBetweenPt1AndPt2(pp1a.pt, p1.Value.pt, pt2)) p2.Value = this.InsertPolyPtBetween(pp1a, p1.Value, pt2);
else p2.Value = this.InsertPolyPtBetween(p1.Value, prev, pt2);
prev = pp2a.prev;
if (ClipperLib.ClipperBase.PointsEqual(pp2a.pt, pt1)) p3 = pp2a;
else if (ClipperLib.ClipperBase.PointsEqual(prev.pt, pt1)) p3 = prev;
else p3 = this.InsertPolyPtBetween(pp2a, prev, pt1);
if (ClipperLib.ClipperBase.PointsEqual(pp2a.pt, pt2)) p4 = pp2a;
else if (ClipperLib.ClipperBase.PointsEqual(prev.pt, pt2)) p4 = prev;
else if ((p3 == pp2a) || (p3 == prev)) p4 = this.InsertPolyPtBetween(pp2a, prev, pt2);
else if (this.Pt3IsBetweenPt1AndPt2(pp2a.pt, p3.pt, pt2)) p4 = this.InsertPolyPtBetween(pp2a, p3, pt2);
else p4 = this.InsertPolyPtBetween(p3, prev, pt2);
if (p1.Value.next == p2.Value && p3.prev == p4) {
p1.Value.next = p3;
p3.prev = p1.Value;
p2.Value.prev = p4;
p4.next = p2.Value;
return true;
}
else if (p1.Value.prev == p2.Value && p3.next == p4) {
p1.Value.prev = p3;
p3.next = p1.Value;
p2.Value.next = p4;
p4.prev = p2.Value;
return true;
}
else return false;
};
ClipperLib.Clipper.prototype.FixupJoinRecs = function (j, pt, startIdx) {
for (var k = startIdx; k < this.m_Joins.length; k++) {
var j2 = this.m_Joins[k];
if (j2.poly1Idx == j.poly1Idx && this.PointIsVertex(j2.pt1a, pt)) j2.poly1Idx = j.poly2Idx;
if (j2.poly2Idx == j.poly1Idx && this.PointIsVertex(j2.pt2a, pt)) j2.poly2Idx = j.poly2Idx;
}
};
ClipperLib.Clipper.prototype.JoinCommonEdges = function () {
var k, orec;
for (var i = 0; i < this.m_Joins.length; i++) {
var j = this.m_Joins[i];
var p1, p2;
if (!(function () {
p1 = {
Value: p1
};
p2 = {
Value: p2
};
var $res = this.JoinPoints(j, p1, p2);
p1 = p1.Value;
p2 = p2.Value;
return $res;
})
.call(this)) continue;
var outRec1 = this.m_PolyOuts[j.poly1Idx];
var outRec2 = this.m_PolyOuts[j.poly2Idx];
if (outRec1 == outRec2) {
outRec1.pts = this.GetBottomPt(p1);
outRec1.bottomPt = outRec1.pts;
outRec1.bottomPt.idx = outRec1.idx;
outRec2 = this.CreateOutRec();
this.m_PolyOuts.push(outRec2);
outRec2.idx = this.m_PolyOuts.length - 1;
j.poly2Idx = outRec2.idx;
outRec2.pts = this.GetBottomPt(p2);
outRec2.bottomPt = outRec2.pts;
outRec2.bottomPt.idx = outRec2.idx;
if (this.PointInPolygon(outRec2.pts.pt, outRec1.pts, this.m_UseFullRange)) {
outRec2.isHole = !outRec1.isHole;
outRec2.FirstLeft = outRec1;
this.FixupJoinRecs(j, p2, i + 1);
this.FixupOutPolygon(outRec1);
this.FixupOutPolygon(outRec2);
if ((outRec2.isHole ^ this.m_ReverseOutput) == (this.Area(outRec2, this.m_UseFullRange) > 0))
this.ReversePolyPtLinks(outRec2.pts);
}
else if (this.PointInPolygon(outRec1.pts.pt, outRec2.pts, this.m_UseFullRange)) {
outRec2.isHole = outRec1.isHole;
outRec1.isHole = !outRec2.isHole;
outRec2.FirstLeft = outRec1.FirstLeft;
outRec1.FirstLeft = outRec2;
this.FixupJoinRecs(j, p2, i + 1);
this.FixupOutPolygon(outRec1);
this.FixupOutPolygon(outRec2);
if ((outRec1.isHole ^ this.m_ReverseOutput) == (this.Area(outRec1, this.m_UseFullRange) > 0))
this.ReversePolyPtLinks(outRec1.pts);
if (this.m_UsingExPolygons && outRec1.isHole) for (k = 0; k < this.m_PolyOuts.length; ++k) {
orec = this.m_PolyOuts[k];
if (orec.isHole && orec.bottomPt != null && orec.FirstLeft == outRec1) orec.FirstLeft = outRec2;
}
}
else {
outRec2.isHole = outRec1.isHole;
outRec2.FirstLeft = outRec1.FirstLeft;
this.FixupJoinRecs(j, p2, i + 1);
this.FixupOutPolygon(outRec1);
this.FixupOutPolygon(outRec2);
if (this.m_UsingExPolygons && outRec2.pts != null) for (k = 0; k < this.m_PolyOuts.length; ++k) {
orec = this.m_PolyOuts[k];
if (orec.isHole && orec.bottomPt != null && orec.FirstLeft == outRec1 && this.PointInPolygon(orec.bottomPt.pt, outRec2.pts, this.m_UseFullRange)) orec.FirstLeft = outRec2;
}
}
}
else {
if (this.m_UsingExPolygons) for (k = 0; k < this.m_PolyOuts.length; ++k)
if (this.m_PolyOuts[k].isHole && this.m_PolyOuts[k].bottomPt != null && this.m_PolyOuts[k].FirstLeft == outRec2) this.m_PolyOuts[k].FirstLeft = outRec1;
this.FixupOutPolygon(outRec1);
if (outRec1.pts != null) {
outRec1.isHole = this.Area(outRec1, this.m_UseFullRange) < 0;
if (outRec1.isHole && outRec1.FirstLeft == null) outRec1.FirstLeft = outRec2.FirstLeft;
}
var OKIdx = outRec1.idx;
var ObsoleteIdx = outRec2.idx;
outRec2.pts = null;
outRec2.bottomPt = null;
outRec2.AppendLink = outRec1;
for (k = i + 1; k < this.m_Joins.length; k++) {
var j2 = this.m_Joins[k];
if (j2.poly1Idx == ObsoleteIdx) j2.poly1Idx = OKIdx;
if (j2.poly2Idx == ObsoleteIdx) j2.poly2Idx = OKIdx;
}
}
}
};
ClipperLib.Clipper.FullRangeNeeded = function (pts) {
var result = false;
for (var i = 0; i < pts.length; i++) {
if (ClipperLib.Math_Abs_Int64(pts[i].X) > ClipperLib.ClipperBase.hiRange || ClipperLib.Math_Abs_Int64(pts[i].Y) > ClipperLib.ClipperBase.hiRange)
ClipperLib.Error("Coordinate exceeds range bounds in FullRangeNeeded().");
else if (ClipperLib.Math_Abs_Int64(pts[i].X) > ClipperLib.ClipperBase.loRange || ClipperLib.Math_Abs_Int64(pts[i].Y) > ClipperLib.ClipperBase.loRange) {
result = true;
}
}
return result;
};
ClipperLib.Clipper.prototype.Area = ClipperLib.Clipper.Area = function () {
var arg = arguments;
var i, a;
if (arg.length == 1) // function ( poly )
{
var poly = arg[0];
var highI = poly.length - 1;
if (highI < 2) return 0;
if (ClipperLib.Clipper.FullRangeNeeded(poly)) {
a = new Int128(poly[highI].X + poly[0].X).multiply(new Int128(poly[0].Y - poly[highI].Y));
for (i = 1; i <= highI; ++i)
a = a.add(new Int128(poly[i - 1].X + poly[i].X).multiply(new Int128(poly[i].Y - poly[i - 1].Y)));
return parseFloat(a.toString()) / 2;
}
else {
var area = (poly[highI].X + poly[0].X) * (poly[0].Y - poly[highI].Y);
for (i = 1; i <= highI; ++i)
area += (poly[i - 1].X + poly[i].X) * (poly[i].Y - poly[i - 1].Y);
return area / 2;
}
}
else if (arg.length == 2) // function (outRec, UseFull64BitRange)
{
var outRec = arg[0];
var UseFull64BitRange = arg[1];
var op = outRec.pts;
if (op == null) return 0;
if (UseFull64BitRange) {
a = new Int128(Int128.ZERO);
do {
a = a.add(new Int128(op.pt.X + op.prev.pt.X).multiply(new Int128(op.prev.pt.Y - op.pt.Y)));
op = op.next;
} while (op != outRec.pts);
return parseFloat(a.toString()) / 2; // This could be something faster!
}
else {
a = 0;
do {
a = a + (op.pt.X + op.prev.pt.X) * (op.prev.pt.Y - op.pt.Y);
op = op.next;
}
while (op != outRec.pts);
return a / 2;
}
}
};
ClipperLib.Clipper.BuildArc = function (pt, a1, a2, r) {
var steps = Math.sqrt(ClipperLib.Math_Abs_Double(r)) * ClipperLib.Math_Abs_Double(a2 - a1);
steps = steps / 4; // to avoid overload
// If you want to make steps independent of scaling factor (scale have to be set),
// the following line does the trick:
// steps = steps / Math.sqrt(scale) * 2;
// If you want that changing scale factor has some influence to steps, uncomment also the following line:
// It may be desirable, that bigger precision ( = bigger scaling factor) needs more steps.
// steps += Math.pow(scale, 0.2);
if (steps < 6) steps = 6;
if (steps > ClipperLib.MaxSteps) steps = ClipperLib.MaxSteps; // to avoid overload
// if (steps > 1048576) steps = 1048576; // 0x100000
// if (steps > ClipperLib.MaxSteps) steps = ClipperLib.MaxSteps; // 0x100000
// Had to change 1048576 to lower value, because when coordinates are near or above lorange, program starts hanging
// Adjust this value to meet your needs, maybe 10 is enough for most purposes
var n = ClipperLib.Cast_Int32(steps);
var result = new ClipperLib.Polygon();
var da = (a2 - a1) / (n - 1);
var a = a1;
for (var i = 0; i < n; ++i) {
result.push(new ClipperLib.IntPoint(pt.X + ClipperLib.Clipper.Round(Math.cos(a) * r), pt.Y + ClipperLib.Clipper.Round(Math.sin(a) * r)));
a += da;
}
return result;
};
ClipperLib.Clipper.GetUnitNormal = function (pt1, pt2) {
var dx = (pt2.X - pt1.X);
var dy = (pt2.Y - pt1.Y);
if ((dx == 0) && (dy == 0)) return new ClipperLib.Clipper.DoublePoint(0, 0);
var f = 1 / Math.sqrt(dx * dx + dy * dy);
dx *= f;
dy *= f;
return new ClipperLib.Clipper.DoublePoint(dy, -dx);
};
ClipperLib.Clipper.prototype.OffsetPolygons = function (poly, delta, jointype, MiterLimit, AutoFix) {
var a = arguments;
if (a.length == 4) AutoFix = true;
else if (a.length == 3) {
MiterLimit = 2;
AutoFix = true;
}
else if (a.length == 2) {
jointype = ClipperLib.JoinType.jtSquare;
MiterLimit = 2;
AutoFix = true;
}
if (isNaN(delta)) ClipperLib.Error("Delta is not a number");
else if (isNaN(MiterLimit)) ClipperLib.Error("MiterLimit is not a number");
var result = {};
new ClipperLib.Clipper.PolyOffsetBuilder(poly, result, delta, jointype, MiterLimit, AutoFix);
if (result.Value) result = result.Value;
else result = [
[]
];
return result;
};
ClipperLib.Clipper.prototype.SimplifyPolygon = function (poly, fillType) {
var result = new ClipperLib.Polygons();
var c = new ClipperLib.Clipper();
if (c.AddPolygon(poly, ClipperLib.PolyType.ptSubject))
c.Execute(ClipperLib.ClipType.ctUnion, result, fillType, fillType);
return result;
};
ClipperLib.Clipper.prototype.SimplifyPolygons = function (polys, fillType) {
var result = new ClipperLib.Polygons();
var c = new ClipperLib.Clipper();
if (c.AddPolygons(polys, ClipperLib.PolyType.ptSubject))
c.Execute(ClipperLib.ClipType.ctUnion, result, fillType, fillType);
return result;
};
var ce = ClipperLib.Clipper;
var ce2 = ClipperLib.ClipperBase;
var p;
if (typeof (Object.getOwnPropertyNames) == 'undefined') {
for (p in ce2.prototype)
if (typeof (ce.prototype[p]) == 'undefined' || ce.prototype[p] == Object.prototype[p]) ce.prototype[p] = ce2.prototype[p];
for (p in ce2)
if (typeof (ce[p]) == 'undefined') ce[p] = ce2[p];
ce.$baseCtor = ce2;
}
else {
var props = Object.getOwnPropertyNames(ce2.prototype);
for (var i = 0; i < props.length; i++)
if (typeof (Object.getOwnPropertyDescriptor(ce.prototype, props[i])) == 'undefined') Object.defineProperty(ce.prototype, props[i], Object.getOwnPropertyDescriptor(ce2.prototype, props[i]));
for (p in ce2)
if (typeof (ce[p]) == 'undefined') ce[p] = ce2[p];
ce.$baseCtor = ce2;
}
ClipperLib.Clipper.DoublePoint = function (x, y) {
this.X = x;
this.Y = y;
};
ClipperLib.Clipper.PolyOffsetBuilder = function (pts, solution, delta, jointype, MiterLimit, AutoFix) {
this.pts = null; // Polygons
this.currentPoly = null; // Polygon
this.normals = null;
this.delta = 0;
this.m_R = 0;
this.m_i = 0;
this.m_j = 0;
this.m_k = 0;
this.botPt = null; // This is "this." because it is ref in original c# code
if (delta == 0) {
solution.Value = pts;
return;
}
this.pts = pts;
this.delta = delta;
var i, j;
//AutoFix - fixes polygon orientation if necessary and removes
//duplicate vertices. Can be set false when you're sure that polygon
//orientation is correct and that there are no duplicate vertices.
if (AutoFix) {
var Len = this.pts.length,
botI = 0;
while (botI < Len && this.pts[botI].length == 0) botI++;
if (botI == Len) {
//solution.Value = new ClipperLib.Polygons();
return;
}
//botPt: used to find the lowermost (in inverted Y-axis) & leftmost point
//This point (on pts[botI]) must be on an outer polygon ring and if
//its orientation is false (counterclockwise) then assume all polygons
//need reversing ...
this.botPt = this.pts[botI][0]; // This is ported with different logic than other C# refs
// adding botPt to object's property it's accessible through object's
// methods
// => All other ref's are now ported using rather complex object.Value
// technique, which seems to work.
for (i = botI; i < Len; ++i) {
if (this.UpdateBotPt(this.pts[i][0])) botI = i;
for (j = this.pts[i].length - 1; j > 0; j--) {
if (ClipperLib.ClipperBase.PointsEqual(this.pts[i][j], this.pts[i][j - 1])) {
this.pts[i].splice(j, 1);
}
else if (this.UpdateBotPt(this.pts[i][j])) botI = i;
}
}
if (!ClipperLib.Clipper.Orientation(this.pts[botI])) ClipperLib.Clipper.ReversePolygons(this.pts);
}
if (MiterLimit <= 1) MiterLimit = 1;
var RMin = 2 / (MiterLimit * MiterLimit);
this.normals = [];
var deltaSq = delta * delta;
solution.Value = new ClipperLib.Polygons();
//ClipperLib.Clear(solution.Value);
var len;
for (this.m_i = 0; this.m_i < this.pts.length; this.m_i++) {
len = this.pts[this.m_i].length;
if (len > 1 && this.pts[this.m_i][0].X == this.pts[this.m_i][len - 1].X &&
this.pts[this.m_i][0].Y == this.pts[this.m_i][len - 1].Y) {
len--;
}
if (len == 0 || (len < 3 && delta <= 0)) {
continue;
}
else if (len == 1) {
var arc;
arc = ClipperLib.Clipper.BuildArc(this.pts[this.m_i][len - 1], 0, ClipperLib.PI2, delta);
solution.Value.push(arc);
continue;
}
//build normals ...
ClipperLib.Clear(this.normals);
for (j = 0; j < len - 1; ++j)
this.normals.push(ClipperLib.Clipper.GetUnitNormal(this.pts[this.m_i][j], this.pts[this.m_i][j + 1]));
this.normals.push(ClipperLib.Clipper.GetUnitNormal(this.pts[this.m_i][len - 1], this.pts[this.m_i][0]));
this.currentPoly = new ClipperLib.Polygon();
this.m_k = len - 1;
for (this.m_j = 0; this.m_j < len; ++this.m_j) {
switch (jointype) {
case ClipperLib.JoinType.jtMiter:
this.m_R = 1 + (this.normals[this.m_j].X * this.normals[this.m_k].X + this.normals[this.m_j].Y * this.normals[this.m_k].Y);
if (this.m_R >= RMin) this.DoMiter();
else this.DoSquare(MiterLimit);
break;
case ClipperLib.JoinType.jtRound:
this.DoRound();
break;
case ClipperLib.JoinType.jtSquare:
this.DoSquare(1);
break;
}
this.m_k = this.m_j;
}
solution.Value.push(this.currentPoly);
}
//finally, clean up untidy corners ...
var clpr = new ClipperLib.Clipper();
clpr.AddPolygons(solution.Value, ClipperLib.PolyType.ptSubject);
if (delta > 0) {
clpr.Execute(ClipperLib.ClipType.ctUnion, solution.Value, ClipperLib.PolyFillType.pftPositive, ClipperLib.PolyFillType.pftPositive);
}
else {
var r = clpr.GetBounds();
var outer = new ClipperLib.Polygon();
outer.push(new ClipperLib.IntPoint(r.left - 10, r.bottom + 10));
outer.push(new ClipperLib.IntPoint(r.right + 10, r.bottom + 10));
outer.push(new ClipperLib.IntPoint(r.right + 10, r.top - 10));
outer.push(new ClipperLib.IntPoint(r.left - 10, r.top - 10));
clpr.AddPolygon(outer, ClipperLib.PolyType.ptSubject);
clpr.Execute(ClipperLib.ClipType.ctUnion, solution.Value, ClipperLib.PolyFillType.pftNegative, ClipperLib.PolyFillType.pftNegative);
if (solution.Value.length > 0) {
solution.Value.splice(0, 1);
for (i = 0; i < solution.Value.length; i++)
solution.Value[i].reverse();
}
}
};
//ClipperLib.Clipper.PolyOffsetBuilder.buffLength = 128;
ClipperLib.Clipper.PolyOffsetBuilder.prototype.UpdateBotPt = function (pt) {
if (pt.Y > this.botPt.Y || (pt.Y == this.botPt.Y && pt.X < this.botPt.X)) {
this.botPt = pt;
return true;
}
else return false;
};
ClipperLib.Clipper.PolyOffsetBuilder.prototype.AddPoint = function (pt) {
this.currentPoly.push(pt);
};
ClipperLib.Clipper.PolyOffsetBuilder.prototype.DoSquare = function (mul) {
var pt1 = new ClipperLib.IntPoint(ClipperLib.Cast_Int64(ClipperLib.Clipper.Round(this.pts[this.m_i][this.m_j].X + this.normals[this.m_k].X * this.delta)),
ClipperLib.Cast_Int64(ClipperLib.Clipper.Round(this.pts[this.m_i][this.m_j].Y + this.normals[this.m_k].Y * this.delta)));
var pt2 = new ClipperLib.IntPoint(ClipperLib.Cast_Int64(ClipperLib.Clipper.Round(this.pts[this.m_i][this.m_j].X + this.normals[this.m_j].X * this.delta)),
ClipperLib.Cast_Int64(ClipperLib.Clipper.Round(this.pts[this.m_i][this.m_j].Y + this.normals[this.m_j].Y * this.delta)));
if ((this.normals[this.m_k].X * this.normals[this.m_j].Y - this.normals[this.m_j].X * this.normals[this.m_k].Y) * this.delta >= 0) {
var a1 = Math.atan2(this.normals[this.m_k].Y, this.normals[this.m_k].X);
var a2 = Math.atan2(-this.normals[this.m_j].Y, -this.normals[this.m_j].X);
a1 = Math.abs(a2 - a1);
if (a1 > ClipperLib.PI) a1 = ClipperLib.PI2 - a1;
var dx = Math.tan((ClipperLib.PI - a1) / 4) * Math.abs(this.delta * mul);
pt1 = new ClipperLib.IntPoint(ClipperLib.Cast_Int64((pt1.X - this.normals[this.m_k].Y * dx)),
ClipperLib.Cast_Int64((pt1.Y + this.normals[this.m_k].X * dx)));
this.AddPoint(pt1);
pt2 = new ClipperLib.IntPoint(ClipperLib.Cast_Int64((pt2.X + this.normals[this.m_j].Y * dx)),
ClipperLib.Cast_Int64((pt2.Y - this.normals[this.m_j].X * dx)));
this.AddPoint(pt2);
}
else {
this.AddPoint(pt1);
this.AddPoint(this.pts[this.m_i][this.m_j]);
this.AddPoint(pt2);
}
};
ClipperLib.Clipper.PolyOffsetBuilder.prototype.DoMiter = function () {
if ((this.normals[this.m_k].X * this.normals[this.m_j].Y - this.normals[this.m_j].X * this.normals[this.m_k].Y) * this.delta >= 0) {
var q = this.delta / this.m_R;
this.AddPoint(new ClipperLib.IntPoint(
ClipperLib.Cast_Int64(
ClipperLib.Clipper.Round(this.pts[this.m_i][this.m_j].X + (this.normals[this.m_k].X + this.normals[this.m_j].X) * q)),
ClipperLib.Cast_Int64(
ClipperLib.Clipper.Round(this.pts[this.m_i][this.m_j].Y + (this.normals[this.m_k].Y + this.normals[this.m_j].Y) * q))));
}
else {
var pt1 = new ClipperLib.IntPoint(ClipperLib.Cast_Int64(ClipperLib.Clipper.Round(this.pts[this.m_i][this.m_j].X + this.normals[this.m_k].X * this.delta)),
ClipperLib.Cast_Int64(ClipperLib.Clipper.Round(this.pts[this.m_i][this.m_j].Y + this.normals[this.m_k].Y * this.delta)));
var pt2 = new ClipperLib.IntPoint(ClipperLib.Cast_Int64(ClipperLib.Clipper.Round(this.pts[this.m_i][this.m_j].X + this.normals[this.m_j].X * this.delta)),
ClipperLib.Cast_Int64(ClipperLib.Clipper.Round(this.pts[this.m_i][this.m_j].Y + this.normals[this.m_j].Y * this.delta)));
this.AddPoint(pt1);
this.AddPoint(this.pts[this.m_i][this.m_j]);
this.AddPoint(pt2);
}
};
ClipperLib.Clipper.PolyOffsetBuilder.prototype.DoRound = function () {
var pt1 = new ClipperLib.IntPoint(ClipperLib.Clipper.Round(this.pts[this.m_i][this.m_j].X + this.normals[this.m_k].X * this.delta),
ClipperLib.Clipper.Round(this.pts[this.m_i][this.m_j].Y + this.normals[this.m_k].Y * this.delta));
var pt2 = new ClipperLib.IntPoint(ClipperLib.Clipper.Round(this.pts[this.m_i][this.m_j].X + this.normals[this.m_j].X * this.delta),
ClipperLib.Clipper.Round(this.pts[this.m_i][this.m_j].Y + this.normals[this.m_j].Y * this.delta));
this.AddPoint(pt1);
//round off reflex angles (ie > 180 deg) unless almost flat (ie < 10deg).
//cross product normals < 0 . angle > 180 deg.
//dot product normals == 1 . no angle
if ((this.normals[this.m_k].X * this.normals[this.m_j].Y - this.normals[this.m_j].X * this.normals[this.m_k].Y) * this.delta >= 0) {
if ((this.normals[this.m_j].X * this.normals[this.m_k].X + this.normals[this.m_j].Y * this.normals[this.m_k].Y) < 0.985) {
var a1 = Math.atan2(this.normals[this.m_k].Y, this.normals[this.m_k].X);
var a2 = Math.atan2(this.normals[this.m_j].Y, this.normals[this.m_j].X);
if (this.delta > 0 && a2 < a1) a2 += ClipperLib.PI2;
else if (this.delta < 0 && a2 > a1) a2 -= ClipperLib.PI2;
var arc = ClipperLib.Clipper.BuildArc(this.pts[this.m_i][this.m_j], a1, a2, this.delta);
for (var m = 0; m < arc.length; m++)
this.AddPoint(arc[m]);
}
}
else this.AddPoint(this.pts[this.m_i][this.m_j]);
this.AddPoint(pt2);
};
ClipperLib.Error = function (message) {
try {
throw new Error(message);
}
catch (err) {
alert(err.message);
}
};
// Make deep copy of Polygons or Polygon
// so that also IntPoint objects are cloned and not only referenced
// This should be the fastest way
ClipperLib.Clone = function (polygon) {
if (!(polygon instanceof Array)) return [];
if (polygon.length == 0) return [];
else if (polygon.length == 1 && polygon[0].length == 0) return [
[]
];
var isPolygons = polygon[0] instanceof Array;
if (!isPolygons) polygon = [polygon];
var len = polygon.length, plen, i, j, result;
var results = [];
for (i = 0; i < len; i++) {
plen = polygon[i].length;
result = [];
for (j = 0; j < plen; j++) {
result.push({X: polygon[i][j].X, Y: polygon[i][j].Y});
}
results.push(result);
}
if (!isPolygons) results = results[0];
return results;
};
// Clean() joins vertices that are too near each other
// and causes distortion to offsetted polygons without cleaning
ClipperLib.Clean = function (polygon, delta) {
if (!(polygon instanceof Array)) return [];
var isPolygons = polygon[0] instanceof Array;
var polygon = ClipperLib.Clone(polygon);
if (typeof delta != "number" || delta === null) {
ClipperLib.Error("Delta is not a number in Clean().");
return polygon;
}
if (polygon.length == 0 || (polygon.length == 1 && polygon[0].length == 0) || delta < 0) return polygon;
if (!isPolygons) polygon = [polygon];
var k_length = polygon.length;
var len, poly, result, d, p, j, i;
var results = [];
for (var k = 0; k < k_length; k++) {
poly = polygon[k];
len = poly.length;
if (len == 0) continue;
else if (len < 3) {
result = poly;
results.push(result);
continue;
}
result = poly;
d = delta * delta;
//d = Math.floor(c_delta * c_delta);
p = poly[0];
j = 1;
for (i = 1; i < len; i++) {
if ((poly[i].X - p.X) * (poly[i].X - p.X) +
(poly[i].Y - p.Y) * (poly[i].Y - p.Y) <= d)
continue;
result[j] = poly[i];
p = poly[i];
j++;
}
p = poly[j - 1];
if ((poly[0].X - p.X) * (poly[0].X - p.X) +
(poly[0].Y - p.Y) * (poly[0].Y - p.Y) <= d)
j--;
if (j < len)
result.splice(j, len - j);
if (result.length) results.push(result);
}
if (!isPolygons && results.length) results = results[0];
else if (!isPolygons && results.length == 0) results = [];
else if (isPolygons && results.length == 0) results = [
[]
];
return results;
}
// Removes points that doesn't affect much to the visual appearance.
// If middle point is at or under certain distance (tolerance) of the line between
// start and end point, the middle point is removed.
ClipperLib.Lighten = function (polygon, tolerance) {
if (!(polygon instanceof Array)) return [];
if (typeof tolerance != "number" || tolerance === null) {
ClipperLib.Error("Tolerance is not a number in Lighten().")
return ClipperLib.Clone(polygon);
}
if (polygon.length === 0 || (polygon.length == 1 && polygon[0].length === 0) || tolerance < 0) {
return ClipperLib.Clone(polygon);
}
if (!(polygon[0] instanceof Array)) polygon = [polygon];
var i, j, poly, k, poly2, plen, A, B, P, d, rem, addlast;
var bxax, byay, nL;
var len = polygon.length;
var results = [];
for (i = 0; i < len; i++) {
poly = polygon[i];
for (k = 0; k < 1000000; k++) // could be forever loop, but wiser to restrict max repeat count
{
poly2 = [];
plen = poly.length;
// the first have to added to the end, if first and last are not the same
// this way we ensure that also the actual last point can be removed if needed
if (poly[plen - 1].X != poly[0].X || poly[plen - 1].Y != poly[0].Y) {
addlast = 1;
poly.push({X: poly[0].X, Y: poly[0].Y});
plen = poly.length;
}
else addlast = 0;
rem = []; // Indexes of removed points
for (j = 0; j < plen - 2; j++) {
A = poly[j]; // Start point of line segment
P = poly[j + 1]; // Middle point. This is the one to be removed.
B = poly[j + 2]; // End point of line segment
bxax = B.X - A.X;
byay = B.Y - A.Y;
d = 0;
if (bxax !== 0 || byay !== 0) // To avoid Nan, when A==P && P==B. And to avoid peaks (A==B && A!=P), which have lenght, but not area.
{
nL = Math.sqrt(bxax * bxax + byay * byay);
// d is the perpendicular distance from P to (infinite) line AB.
d = Math.abs((P.X - A.X) * byay - (P.Y - A.Y) * bxax) / nL;
}
if (d <= tolerance) {
rem[j + 1] = 1;
j++; // when removed, transfer the pointer to the next one
}
}
// add all unremoved points to poly2
poly2.push({X: poly[0].X, Y: poly[0].Y});
for (j = 1; j < plen - 1; j++)
if (!rem[j]) poly2.push({X: poly[j].X, Y: poly[j].Y});
poly2.push({X: poly[plen - 1].X, Y: poly[plen - 1].Y});
// if the first point was added to the end, remove it
if (addlast) poly.pop();
// break, if there was not anymore removed points
if (!rem.length) break;
// else continue looping using poly2, to check if there are points to remove
else poly = poly2;
}
plen = poly2.length;
// remove duplicate from end, if needed
if (poly2[plen - 1].X == poly2[0].X && poly2[plen - 1].Y == poly2[0].Y) {
poly2.pop();
}
if (poly2.length > 2) // to avoid two-point-polygons
results.push(poly2);
}
if (!polygon[0] instanceof Array) results = results[0];
if (typeof (results) == "undefined") results = [
[]
];
return results;
}
if (typeof(document) !== "undefined") window.ClipperLib = ClipperLib;
else self['ClipperLib'] = ClipperLib;
})();
<!DOCTYPE html>
<html>
<head>
<script src="clipper_unminified.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script>
/*
* jQuery repeatedclick v1.0.5
* Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
* and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
* Written by: Alexandr Zykov <[email protected]>
*/
if (typeof(jQuery) != "undefined")
jQuery.fn.hold = function (h, j) {
var c = jQuery.extend({duration: 350, speed: 0.85, min: 50}, j);
"undefined" === typeof jQuery.repeatedEvents && (jQuery.repeatedEvents = []);
jQuery.repeatedEvents.push(h);
var k = jQuery.repeatedEvents.length - 1, d, e;
return this.each(function () {
d = function (f, b, a) {
var g = this;
jQuery.repeatedEvents[f].call(g, a);
e = setTimeout(function () {
d.call(g, f, b > c.min ? b * c.speed : b, a)
}, b)
};
jQuery(this).mousedown(function (a) {
d.call(this, k, c.duration, a)
});
var a = function () {
"undefined" !== typeof e && clearInterval(e)
};
jQuery(this).mouseout(a);
jQuery(this).mouseup(a)
})
};
</script>
<script>
/*
* TotalStorage v. 1.1.2
* Copyright (c) 2012 Jared Novack & Upstatement (upstatement.com)
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
* @author Jared Novack/[email protected]
* @url http://upstatement.com/blog/2012/01/jquery-local-storage-done-right-and-easy/
*/
if (typeof(jQuery) != "undefined")
(function (c) {
var e = window.localStorage, f;
f = "undefined" == typeof e || "undefined" == typeof window.JSON ? !1 : !0;
c.totalStorage = function (b, a) {
return c.totalStorage.impl.init(b, a)
};
c.totalStorage.setItem = function (b, a) {
return c.totalStorage.impl.setItem(b, a)
};
c.totalStorage.getItem = function (b) {
return c.totalStorage.impl.getItem(b)
};
c.totalStorage.getAll = function () {
return c.totalStorage.impl.getAll()
};
c.totalStorage.deleteItem = function (b) {
return c.totalStorage.impl.deleteItem(b)
};
c.totalStorage.impl = {init: function (b, a) {
return"undefined" != typeof a ? this.setItem(b, a) : this.getItem(b)
}, setItem: function (b, a) {
if (!f)try {
return c.cookie(b, a), a
} catch (d) {
console.log("Local Storage not supported by this browser. Install the cookie plugin on your site to take advantage of the same functionality. You can get it at https://github.com/carhartl/jquery-cookie")
}
var g = JSON.stringify(a);
e.setItem(b, g);
return this.parseResult(g)
}, getItem: function (b) {
if (!f)try {
return this.parseResult(c.cookie(b))
} catch (a) {
return null
}
return this.parseResult(e.getItem(b))
},
deleteItem: function (b) {
if (!f)try {
return c.cookie(b, null), !0
} catch (a) {
return!1
}
e.removeItem(b);
return!0
}, getAll: function () {
var b = [];
if (f)for (d in e)d.length && b.push({key: d, value: this.parseResult(e.getItem(d))}); else try {
for (var a = document.cookie.split(";"), d = 0; d < a.length; d++) {
var g = a[d].split("=")[0];
b.push({key: g, value: this.parseResult(c.cookie(g))})
}
} catch (h) {
return null
}
return b
}, parseResult: function (b) {
var a;
try {
a = JSON.parse(b), "true" == a && (a = !0), "false" == a && (a = !1), parseFloat(a) == a && "object" != typeof a &&
(a = parseFloat(a))
} catch (c) {
}
return a
}}
})(jQuery);
</script>
<meta charset=utf-8/>
<title>Javascript Clipper Main Demo</title>
<style>
.textarea_hide_buttons {
margin-bottom: 6px;
margin-top: 4px;
}
body {
background-color: #F8F8F8;
}
p {
margin: 0px;
padding: 0px;
}
th {
background-color: #DDDDDD;
font-weight: bold;
padding: 0px;
}
body, th, td, input, legend, fieldset, p, b, button, select, textarea {
font-size: 13px;
font-family: Arial, Helvetica, sans-serif;
}
#p, #_p {
background-color: #ffffff;
border: 2px solid #AAAAAA;
}
.svg_mypath {
stroke: black;
stroke-width: 1;
fill: black;
fill-opacity: 0.3;
}
#p1, #_p1 {
fill: #00009C;
fill-opacity: 0.06;
stroke: #D3D3DA;
stroke-opacity: 1.0;
stroke-width: 0.8;
}
#p2, #_p2 {
fill: #9C0000;
fill-opacity: 0.06;
stroke: #FFA07A;
stroke-opacity: 1.0;
stroke-width: 0.8;
}
#p3, #_p3 {
fill: #80ff9C;
fill-opacity: 0.5;
stroke: #003300;
stroke-opacity: 1.0;
stroke-width: 0.8;
}
#svg_source_textarea {
width: 1215px;
height: 300px;
}
#benchmark_exports_textarea {
width: 1215px;
height: 300px;
}
div#svgcontainer {
margin-right: 2px;
margin-top: 6px;
}
div#benchmark_div_outer {
width: 100%;
}
div#benchmark_div {
width: 100%;
}
#benchmark_fieldset {
width: 367px;
min-width: 367px;
height: 350px;
}
.buttons {
display: inline-block;
padding: 0px;
padding-left: 12px;
padding-right: 12px;
background-color: #666666;
color: white;
border-radius: 10px;
text-align: center;
line-height: 20px;
font-size: 13px;
cursor: pointer;
margin-bottom: 2px;
margin-top: 2px;
font-family: Helvetica, Arial, sans-serif;
white-space: nowrap;
}
LEGEND {
font-weight: bold;
}
FIELDSET {
background-color: #EEEEEE;
/*
border-radius: 4px 4px 7px 7px;
-moz-border-radius: 4px 4px 7px 7px;
-webkit-border-radius: 4px 4px 7px 7px;
*/
border: 2px solid #AAAAAA;
white-space: nowrap;
}
table {
border: 0px;
}
.subpolylinks {
cursor: pointer;
font-size: 13px;
padding: 2px;
}
.subpolylinks:hover {
background-color: #BBBBBB;
}
.subpolylinks_disabled {
font-size: 13px;
padding: 2px;
}
/* To prevent odd text resizing in mobile Safari */
@media only screen and (max-device-width: 480px) {
.body, p, fieldset, td, th {
-webkit-text-size-adjust: 100%
}
}
.polygon_explorer {
text-align: left;
border-collapse: collapse;
white-space: normal;
width: 461px;
}
.polygon_explorer th {
font-weight: bold;
}
.polygon_explorer > tr > th, .polygon_explorer > tr > td,
.polygon_explorer > tbody > tr > th, .polygon_explorer > tbody > tr > td {
border: 1px solid #666666;
padding: 3px 4px 3px 4px;
vertical-align: top;
}
.polygons_fieldset {
border-collapse: collapse;
width: 100%;
}
.polygons_fieldset td {
vertical-align: top;
white-space: nowrap;
padding: 0px;
padding-right: 10px;
}
.polygons_fieldset input[type=radio] {
margin-left: 0px;
}
.random {
border-collapse: collapse;
width: 100%;
}
.random td {
padding: 0px;
padding-right: 10px;
}
.random_inputs {
width: 25px
}
.random th {
padding: 0px;
padding-right:
}
.random th {
background-color: transparent;
}
.random_new_th {
background-color: transparent;
}
.random_new_th button {
margin: 0px;
}
.random button, .random input {
margin-bottom: 0px;
margin-top: 0px;
}
#subj_polygon_count {
margin-bottom: 2px;
}
.filltype_cliptype {
border-collapse: collapse;
}
.filltype_cliptype td {
vertical-align: top;
padding: 0px;
}
.offset_outer {
border-collapse: collapse;
width: 100%;
}
.offset_outer td {
vertical-align: top;
white-space: nowrap;
padding: 0px;
}
.offset_outer input[type=radio] {
margin-left: 0px;
}
.offset_inner input[type=text] {
margin-bottom: 2px;
}
.offset_inner {
border-collapse: collapse;
}
.offset_inner td {
vertical-align: top;
height: 100%;
}
#custom_polygons_fieldset {
display: none;
}
#random_polygons_fieldset {
display: none;
}
#misc_fieldset {
min-height: 81px;
}
.custom_polygon_input {
width: 285px;
height: 15px;
padding: 2px;
line-height: 15px;
}
#polygon_explorer_string_inp {
margin: 0px;
height: 15px;
width: 323px;
padding: 2px;
line-height: 15px;
}
#custom_polygon_inputs {
display: block;
}
#custom_poly_message_box_green {
display: none;
opacity: 0;
position: absolute;
top: 0px;
left: 0px;
height: 0px;
width: 200px;
vertical-align: middle;
text-align: center;
border: 2px solid #106712;
background-color: #A3F1A5;
padding: 8px;
padding-left: 11px;
padding-right: 11px;
border-radius: 6px;
font-size: 16px;
z-index: 2;
}
.custom_polygon_inputs_table {
border-collapse: collapse;
}
#help_builtin_polygon_sets, #help_output_format, #help_custom_polygon {
padding-left: 7px;
padding-right: 7px;
}
/*
#outertable > tbody > tr > td {
border:1px solid red;
}
*/
</style>
</head>
<body>
<table id="outertable" style="margin-bottom:5px">
<tr>
<td id="td0" style="vertical-align:top;width:353px;min-width:353px">
<FIELDSET id="PolygonsFieldset">
<LEGEND title="Builtin polygons">Polygons</LEGEND>
<table class="polygons_fieldset">
<tr>
<td>
<input type="radio" name="polygons" value="0">Arrows
<br>
<input type="radio" name="polygons" value="1">Texts
<br>
<input type="radio" name="polygons" value="2">Rects
<br>
</td>
<td>
<input type="radio" name="polygons" value="3">Same
<br>
<input type="radio" name="polygons" value="4" title="Random rectangles">RandRects
<br>
<input type="radio" name="polygons" value="5" title="Random polygons">Random
<br>
</td>
<td>
<input type="radio" name="polygons" value="6">Star & rect
<br>
<input type="radio" name="polygons" value="7">Spiral
<br>
<input type="radio" name="polygons" value="8">Grid & star
<br>
</td>
<td style="padding-right:0px">
<input type="radio" name="polygons" value="9">Glyph
<br>
<input type="radio" name="polygons" value="10" title="Your own custom polygon sets">Custom
<br>
</td>
</tr>
</table>
</FIELDSET>
<FIELDSET id="custom_polygons_fieldset" style="position:relative">
<LEGEND>Your own custom polygons</LEGEND>
<select name="custom_polygons_select"
id="custom_polygons_select" title="Saved custom polygon sets"></select>
<select name="sample_custom_polygon" id="sample_custom_polygon" title="Get Builtin polygon set">
<option value="">- Builtin -</option>
<option value="0">Arrows</option>
<option value="1">Texts</option>
<option value="2">Rects</option>
<option value="3">Same</option>
<option value="4">RandRects</option>
<option value="5">Random</option>
<option value="6">Star & rect</option>
<option value="7">Spiral</option>
<option value="8">Grid & star</option>
<option value="9">Glyph</option>
</select>
<button id="help_builtin_polygon_sets" title="Get help about Builtin polygon sets">?</button>
<div id="custom_polygon_inputs">
<table class="custom_polygon_inputs_table">
<tr>
<td>
<b title="Here you can type or paste custom subject polygons. Click the '?' button below to get help about string formats.">Subj</b>
</td>
<td>
<textarea class="custom_polygon_input" id="custom_polygon_subj" value=''></textarea>
</td>
</tr>
<tr>
<td>
<b title="Here you can type or paste custom clip polygons. Click the '?' button below to get help about string formats.">Clip</b>
</td>
<td>
<textarea class="custom_polygon_input" id="custom_polygon_clip" value=''></textarea>
</td>
</tr>
</table>
<button id="save_custom_polygon" title="Update polygon set">Save</button>
<button id="add_as_new_custom_polygon" title="Save as a new custom polygon set">Save as new</button>
<button id="remove_custom_polygon" title="Remove selected custom polygon set">Del</button>
<button id="removeall_custom_polygon" title="Remove all custom polygon sets">Del all</button>
<button id="help_custom_polygon" title="Get help about custom polygons">?</button>
</div>
<div id="custom_poly_message_box_green"></div>
</FIELDSET>
<FIELDSET id="random_polygons_fieldset">
<LEGEND>Random polygon settings</LEGEND>
<table class="random">
<thead>
<tr>
<th class="random_new_th">
<button id="generate_random_polygons" title="Generate random polygons">New</button>
</th>
<th>Polygon count</th>
<th style="padding-right:0px">Point count</th>
</tr>
</thead>
<tbody>
<tr>
<td><b>Subject</b>
</td>
<td>
<button id="subj_polygon_count_minus">&nbsp;-&nbsp;</button>
<input class="random_inputs" type="text" id="subj_polygon_count"
value="1">
<button id="subj_polygon_count_plus">&nbsp;+&nbsp;</button>
</td>
<td style="padding-right:0px">
<button id="subj_point_count_minus">&nbsp;-&nbsp;</button>
<input class="random_inputs" type="text" id="subj_point_count"
value="1">
<button id="subj_point_count_plus">&nbsp;+&nbsp;</button>
</td>
</tr>
<tr>
<td><b>Clip</b>
</td>
<td>
<button id="clip_polygon_count_minus">&nbsp;-&nbsp;</button>
<input class="random_inputs" type="text" id="clip_polygon_count"
value="1">
<button id="clip_polygon_count_plus">&nbsp;+&nbsp;</button>
</td>
<td style="padding-right:0px">
<button id="clip_point_count_minus">&nbsp;-&nbsp;</button>
<input class="random_inputs" type="text" id="clip_point_count"
value="1">
<button id="clip_point_count_plus">&nbsp;+&nbsp;</button>
</td>
</tr>
</table>
</FIELDSET>
<table id="filltype_cliptype_table" class="filltype_cliptype" style="width:100%">
<tr>
<td>
<FIELDSET>
<LEGEND>Subject FillType</LEGEND>
<input type="radio" name="subject_fillType" value="0">EvenOdd&nbsp;
<input type="radio" name="subject_fillType" value="1">NonZero
</FIELDSET>
</td>
<td>
<FIELDSET>
<LEGEND>Clip FillType</LEGEND>
<input type="radio" name="clip_fillType" value="0">EvenOdd&nbsp;
<input type="radio" name="clip_fillType" value="1">NonZero
</FIELDSET>
</td>
</tr>
</table>
<FIELDSET id="ClipTypeFieldset">
<LEGEND>Clip type (operation)</LEGEND>
<p>
<input type="radio" name="clipType" value="">No&nbsp;&nbsp;
<input type="radio" name="clipType" value="0">Intersect&nbsp;&nbsp;
<input type="radio" name="clipType" value="1">Union&nbsp;&nbsp;
<input type="radio" name="clipType" value="2">Difference&nbsp;&nbsp;
<input type="radio" name="clipType" value="3" checked>Xor</p>
</FIELDSET>
<FIELDSET id="CleaningFieldset">
<LEGEND>Cleaning and simplifying</LEGEND>
<p>
<b>Clean</b><input type="checkbox" id="clean"
title="Clean. Joins sequential vertices if they are almost coincident. This is needed to prevent polygon breakage when offsetting. Not included in original Clipper, yet. This operation is done before offsetting."
value="1">
<input style="width:28px" type="text" value="" id="cleandelta"
title="Delta. The distance used for Clean. Sequential vertices are joined if they are at or below this distance of each other.">&nbsp;&nbsp;
<b>Simplify</b><input type="checkbox" id="Simplify"
title="Simplify. Convert complex (self-intersecting) polygon to simple ones. Produces multiple polygons, if there are self-intersections. Note! Not work in self-intersections that are too small, you have to remove too-near-vertices using Clean feature. This operation is done before offsetting."
value="1">&nbsp;&nbsp;
<b>Lighten</b><input type="checkbox" id="lighten"
title="Lighten. Removes unnecessary vertices. Not included in original Clipper. This operation is done after offsetting."
value="1">
<input style="width:28px;" type="text" value="" id="lighten_distance"
title="Tolerance. The distance that is used when lightening polygon. Removes middle vertex of three sequential vertices, if the middle vertex is under (or at) this distance of the line between start and end vertex.">
</p>
</FIELDSET>
<FIELDSET id="OffsettingFieldset">
<LEGEND>Offsetting</LEGEND>
<table class="offset_outer">
<tr>
<td style="padding-right:6px;">
<b><span style="display:block;padding-bottom:3px">Polygon</span></b>
<input type="radio" name="offsettable_poly" value="1">Subject
<br>
<input type="radio" name="offsettable_poly" value="2">Clip
<br>
<input type="radio" id="offsettable_poly3" name="offsettable_poly" value="3" checked>Solution
</td>
<td style="padding-right:6px;">
<b><span style="display:block;padding-bottom:3px">JoinType</span></b>
<input type="radio" name="joinType" value="0" checked>Square
<br>
<input type="radio" name="joinType" value="1">Round
<br>
<input type="radio" name="joinType" value="2">Miter
<br>
</td>
<td style="padding-right:0px">
<table class="offset_inner">
<tr>
<td>
<b>Delta</b>
<button id="delta_minus">&nbsp;-&nbsp;</button>
<input type="text" id="delta" value="" style="width:50px">
<button id="delta_plus">&nbsp;+&nbsp;</button>
</td>
</tr>
<tr>
<td><b>MiterLimit</b>
<button id="miterLimit_minus">&nbsp;-&nbsp;</button>
<input type="text" id="miterLimit" value="" style="width:20px">
<button id="miterLimit_plus">&nbsp;+&nbsp;</button>
</td>
</tr>
<tr>
<td style="padding-bottom: 0px; padding-top: 3px;">
<b title="AutoFix">AutoFix</b>
<input type="checkbox" id="AutoFix"
title="AutoFix. Fixes polygon orientation if necessary and removes duplicate vertices. Can be set false when you are sure that polygon orientation is correct and that there are no duplicate vertices."
value="1">
</td>
</tr>
</table>
</td>
</tr>
</table>
</FIELDSET>
<FIELDSET id="ScaleFieldset">
<LEGEND>Scale</LEGEND>
<p style="width:200px;">
<button id="scale_minus">&nbsp;-&nbsp;</button>
<input type="text" id="scale" value="" style="width:80px">
<button id="scale_plus">&nbsp;+&nbsp;</button>
<span id="scaletest"></span>&nbsp; <b>Bigints used:</b>
<span
id="biginteger_used"></span>
</p>
</FIELDSET>
<FIELDSET id="misc_fieldset">
<LEGEND>Misc</LEGEND>
<button id="show_svg_source" title="Show current SVG source in textarea at the bottom of the page">Show SVG source
B
</button>
&nbsp;<b>Bevel</b>
<input type="checkbox" id="bevel"
value="1" title="Uncheck this to speedup drawing">&nbsp;&nbsp;
<b>Explorer</b>
<input type="checkbox" id="sub_poly_links_update"
value="1" title="Enable/disable Polygon Explorer">
<br>
<button id="benchmark1" title="Execute Normal benchmark">Run NB</button>
<button id="benchmark1b" title="Execute Normal benchmark 5x">Run NB 5x</button>
<button id="benchmark2" title="Execute Big Integer benchmark">Run BIB</button>
<button id="benchmark2b" title="Execute Big Integer benchmark 5x">Run BIB 5x</button>
</FIELDSET>
</td>
<td id="td1" style="vertical-align:top;width:506px;">
<div id="svgcontainer"></div>
<FIELDSET id="polygon_explorer_fieldset">
<LEGEND>Polygon explorer</LEGEND>
<div id="polygon_explorer_div" style="padding-left:1px;/*overflow-y:auto;overflow-x:visible;max-height:300px*/">
<table class="polygon_explorer">
<tr>
<td colspan="4" style="padding:0px;white-space:nowrap; border:0px">
<table style="padding:0px;border-collapse:collapse">
<tr>
<td style="padding:0px;vertical-align:middle">
<textarea id="polygon_explorer_string_inp"
title="When you click the numbers below, here comes coordinates of the clicked polygon (or polygons) as string."
value="">Click below to see coordinates here!</textarea>
</td>
<td style="padding:0px;vertical-align:middle">
<select id="output_format" title="Output format" style="width:73px;margin-left:5px">
<option value="0">Clipper</option>
<option value="1">Plain</option>
<option value="2">SVG</option>
</select>&nbsp;&nbsp;<b>Ex</b> <input type="checkbox" id="ExPolygons"
value="1" title="Show solution as ExPolygons">
</td>
</tr>
</table>
</td>
</tr>
<tr>
<th style="white-space:nowrap; width:31px;" title="Polygon type">Type</th>
<th style="white-space:nowrap; width:35px;" title="Count of subpolygons">Polys</th>
<th style="white-space:nowrap; width:40px;"
title="Count of points in all sub polygons. Hover numbers below to see the whole multi-polygon highlighted. Click them to see coordinates as strings and the area of multi-polygon (sum of areas of sub polygons).">
Points
</th>
<th style="white-space:nowrap;"
title="Count of points in sub polygons. Hover numbers below to see sub polygons highlighted. Click to see coordinates as strings and the area of sub polygon."
>Points in subpolygons
</th>
</tr>
<tr>
<td id="subject_box" title="Subject">
<b>Subj</b>
</td>
<td>
<span id="subj_subpolygons"></span>
</td>
<td>
<span id="subj_points_total" class="subpolylinks"
onclick="popup_path(undefined,'1')"
onmouseover="show_path(undefined,'1')" onmouseout="hide_path()"
></span>
</td>
<td>
<span id="subj_points_in_subpolygons"></span>
</td>
</tr>
<tr>
<td id="clip_box" title="Clip">
<b>Clip</b>
</td>
<td>
<span id="clip_subpolygons">
</span>
</td>
<td><span id="clip_points_total" class="subpolylinks"
onclick="popup_path(undefined,'2')"
onmouseover="show_path(undefined,'2')" onmouseout="hide_path()"
></span>
</td>
<td>
<span id="clip_points_in_subpolygons"></span>
</td>
</tr>
<tr>
<td id="solution_box" title="Solution">
<b>Solu</b>
</td>
<td>
<span id="solution_subpolygons"></span>
</td>
<td>
<span id="solution_points_total" class="subpolylinks"
onclick="popup_path(undefined,'3')"
onmouseover="show_path(undefined,'3')" onmouseout="hide_path()"
></span>
</td>
<td>
<span id="solution_points_in_subpolygons">
</span>
</td>
</tr>
<tr>
<td>
<b>Total</b>
</td>
<td>
<b><span id="all_subpolygons"></span></b>
</td>
<td>
<b><span id="points_total"></span></b>
</td>
<td style="padding-bottom:0px;padding-top:0px;text-align:right;white-space:nowrap">
<div id="area" style="padding:0px;display:inline-block;width:90%;text-align:left"
title="Click above numbers to see the area of sub polygons."
>Area: Click above to see polygon area!
</div>
<button id="help_output_format" title="Get help about output format">?</button>
</td>
</tr>
</table>
</div>
</FIELDSET>
</td>
<td id="td2" style="width:353px;vertical-align:top;">
<FIELDSET id="benchmark_fieldset_f" style="min-height:517px">
<LEGEND id="#benchmark_fieldset">Benchmark</LEGEND>
<div id="benchmark_div_outer">
<div id="benchmark_div"></div>
<div id="benchmark_multiple_table_cont"></div>
</div>
</FIELDSET>
</td>
<td id="td3" style="vertical-align:top;">
<div id="svg_source_container2"></div>
</td>
</tr>
</table>
<div id="svg_source_container"></div>
<div id="benchmark_exports_container"></div>
<script>
//var scale = 10000000000000;
var scale = 100;
var global_do_not_round_and_scale = false;
var scale_addition = 100;
var polygons_default = 1;
var joinType = 0;
var miterLimit = 2.0;
var delta = -1;
var AutoFix = true;
var ExPolygons = false;
var SolutionPolygonClicked = false;
var SolutionPolygonString = "";
var Simplify = true;
var clean = true;
var cleandelta_default = 0.1;
var cleandelta = cleandelta_default;
var lighten = true;
var lighten_distance_default = 0.1;
var lighten_distance = lighten_distance_default;
var offsettable_poly = 3;
var clipType = 3;
var subject_fillType = 1;
var clip_fillType = 1;
var ss, cc, sss, cpr, sss2, cpr2, p, ok = 1;
var off_result;
var SVG = {}, p, p1, p2, p3;
var random_subj;
var random_clip;
var rnd_sett_defaults = {};
rnd_sett_defaults.rect = {};
rnd_sett_defaults.norm = {};
rnd_sett_defaults.rect.default = {
clip_polygon_count: 1,
clip_point_count: 4,
subj_polygon_count: 2,
subj_point_count: 8
};
rnd_sett_defaults.rect.min = {
clip_polygon_count: 1,
clip_point_count: 4,
subj_polygon_count: 1,
subj_point_count: 4
};
rnd_sett_defaults.rect.max = {
clip_polygon_count: 100,
clip_point_count: 100,
subj_polygon_count: 100,
subj_point_count: 100
};
rnd_sett_defaults.norm.default = {
clip_polygon_count: 1,
clip_point_count: 3,
subj_polygon_count: 2,
subj_point_count: 8
};
rnd_sett_defaults.norm.min = {
clip_polygon_count: 1,
clip_point_count: 3,
subj_polygon_count: 1,
subj_point_count: 3
};
rnd_sett_defaults.norm.max = {
clip_polygon_count: 100,
clip_point_count: 100,
subj_polygon_count: 100,
subj_point_count: 100
};
rnd_sett_defaults.current = "norm";
var bevel = 0;
var mypath = null;
var scaled_paths = [];
var subj_points_total = 0;
var clip_points_total = 0;
var solution_points_total = 0;
var subj_subpolygons = 0;
var clip_subpolygons = 0;
var solution_subpolygons = 0;
var bench;
var sub_poly_links_update = 1;
var benchmark1_globals = {};
var browserg;
var repeat_times;
var repeat = 0;
var clicked_benchmark_button_id;
var benchmark_exports = "";
var benchmark_running = 0;
var benchmark_automatic_click = 0;
// default_custom_subject_polygon = '[[{"X":90.58,"Y":144.44},{"X":84.83,"Y":141.55},{"X":84.84,"Y":141.56},{"X":79.29,"Y":137.67},{"X":73.79,"Y":132.61},{"X":73.8,"Y":132.62},{"X":67.31,"Y":125.14},{"X":63.22,"Y":119.64},{"X":98.93,"Y":130.63},{"X":98.91,"Y":130.61},{"X":99.02,"Y":130.66},{"X":99.02,"Y":130.65},{"X":97.46,"Y":134.4},{"X":93.93,"Y":139.6},{"X":90.86,"Y":144.22},{"X":90.87,"Y":144.21}]]';
// The Phantom image
var default_custom_subject_polygon = '[[{"X":-29.42,"Y":106.23},{"X":-26.7,"Y":105.45},{"X":-11.55,"Y":101.73},{"X":0.12,"Y":99.72},{"X":9.69,"Y":98.94},{"X":17.63,"Y":99.17},{"X":24.29,"Y":100.23},{"X":23.93,"Y":92.91},{"X":24.08,"Y":81.36},{"X":25.12,"Y":70.62},{"X":26.99,"Y":60.59},{"X":29.66,"Y":51.22},{"X":33.11,"Y":42.43},{"X":37.31,"Y":34.29},{"X":42.16,"Y":26.9},{"X":47.77,"Y":20.05},{"X":53.98,"Y":13.98},{"X":60.82,"Y":8.61},{"X":68.2,"Y":4.01},{"X":76.04,"Y":0.24},{"X":84.37,"Y":-2.73},{"X":92.97,"Y":-4.8},{"X":101.89,"Y":-5.98},{"X":110.88,"Y":-6.23},{"X":120,"Y":-5.53},{"X":128.99,"Y":-3.88},{"X":137.63,"Y":-1.36},{"X":145.94,"Y":2.06},{"X":153.87,"Y":6.32},{"X":161.29,"Y":11.4},{"X":168.03,"Y":17.14},{"X":174.22,"Y":23.66},{"X":179.7,"Y":30.8},{"X":184.49,"Y":38.59},{"X":188.54,"Y":46.95},{"X":191.9,"Y":56.1},{"X":194.44,"Y":65.81},{"X":196.16,"Y":76.18},{"X":197,"Y":87.09},{"X":196.94,"Y":98.79},{"X":195.88,"Y":111.18},{"X":207.51,"Y":112.86},{"X":220.6,"Y":115.46},{"X":233.18,"Y":118.91},{"X":245.2,"Y":123.18},{"X":256.72,"Y":128.26},{"X":267.97,"Y":134.26},{"X":278.87,"Y":141.16},{"X":289.73,"Y":149.16},{"X":300.72,"Y":158.47},{"X":312.07,"Y":169.38},{"X":312.06,"Y":169.37},{"X":336.14,"Y":177.32},{"X":355.16,"Y":183.81},{"X":367.78,"Y":189},{"X":378.1,"Y":194.19},{"X":387.04,"Y":199.69},{"X":395.07,"Y":205.73},{"X":400.6,"Y":210.78},{"X":405.18,"Y":216.34},{"X":409.93,"Y":223.8},{"X":420.35,"Y":243.91},{"X":425.91,"Y":253.51},{"X":431.07,"Y":260.69},{"X":436.35,"Y":266.43},{"X":436.34,"Y":266.42},{"X":443.69,"Y":272.81},{"X":469.07,"Y":291.49},{"X":477.42,"Y":298.56},{"X":483.68,"Y":305.01},{"X":487.79,"Y":310.56},{"X":497.28,"Y":326.73},{"X":502.53,"Y":334.76},{"X":511.53,"Y":345.81},{"X":337.97,"Y":345.86},{"X":315.38,"Y":321.1},{"X":303.25,"Y":308.84},{"X":303.26,"Y":308.85},{"X":292.72,"Y":299.47},{"X":292.69,"Y":299.5},{"X":290.88,"Y":300.26},{"X":290.89,"Y":300.25},{"X":283.26,"Y":304.12},{"X":283.27,"Y":304.11},{"X":275.98,"Y":308.87},{"X":268.76,"Y":314.74},{"X":261.42,"Y":322.02},{"X":261.43,"Y":322.01},{"X":253.55,"Y":331.26},{"X":242.73,"Y":345.84},{"X":-29.42,"Y":345.86}],[{"X":127.69,"Y":269.76},{"X":127.68,"Y":269.77},{"X":133.88,"Y":268.63},{"X":133.87,"Y":268.64},{"X":139.54,"Y":266.65},{"X":139.53,"Y":266.66},{"X":144.66,"Y":263.86},{"X":144.65,"Y":263.87},{"X":149.4,"Y":260.18},{"X":149.39,"Y":260.19},{"X":153.81,"Y":255.5},{"X":158.06,"Y":249.51},{"X":162.29,"Y":241.74},{"X":166.81,"Y":231.1},{"X":166.8,"Y":231.11},{"X":176.87,"Y":202.06},{"X":182.04,"Y":188.77},{"X":182.04,"Y":188.78},{"X":182.02,"Y":188.77},{"X":181.74,"Y":188.64},{"X":181.75,"Y":188.65},{"X":179.85,"Y":188.27},{"X":178.29,"Y":188.8},{"X":178.3,"Y":188.79},{"X":176.74,"Y":190.4},{"X":176.75,"Y":190.39},{"X":173.98,"Y":196.05},{"X":173.14,"Y":196.87},{"X":172.34,"Y":196.57},{"X":171.01,"Y":194.4},{"X":174.86,"Y":188.74},{"X":180.8,"Y":179.01},{"X":185.49,"Y":169.61},{"X":185.48,"Y":169.62},{"X":188.88,"Y":160.79},{"X":188.87,"Y":160.8},{"X":191.15,"Y":152.4},{"X":191.14,"Y":152.41},{"X":192.39,"Y":144.4},{"X":192.38,"Y":144.41},{"X":192.65,"Y":136.76},{"X":192.65,"Y":136.77},{"X":191.95,"Y":129.43},{"X":191.96,"Y":129.44},{"X":190.36,"Y":122.45},{"X":189.2,"Y":126.33},{"X":186.64,"Y":132.72},{"X":183.5,"Y":138.19},{"X":179.85,"Y":142.75},{"X":175.82,"Y":146.34},{"X":171.49,"Y":149.01},{"X":166.88,"Y":150.79},{"X":162.01,"Y":151.66},{"X":157.07,"Y":151.61},{"X":152.08,"Y":150.61},{"X":147.07,"Y":148.62},{"X":142.21,"Y":145.63},{"X":137.56,"Y":141.62},{"X":133.27,"Y":136.62},{"X":129.46,"Y":130.68},{"X":129.03,"Y":130.72},{"X":129.04,"Y":130.71},{"X":124.06,"Y":131.87},{"X":124.07,"Y":131.86},{"X":119.96,"Y":133.69},{"X":116.46,"Y":136.26},{"X":116.47,"Y":136.25},{"X":113.27,"Y":139.82},{"X":107.23,"Y":149.32},{"X":104.14,"Y":153.18},{"X":101,"Y":155.72},{"X":97.49,"Y":157.4},{"X":93.11,"Y":158.38},{"X":88.02,"Y":158.61},{"X":83.43,"Y":157.91},{"X":79.22,"Y":156.35},{"X":75,"Y":153.77},{"X":70.26,"Y":149.63},{"X":60.57,"Y":138.77},{"X":54.38,"Y":132.43},{"X":54.39,"Y":132.44},{"X":49.11,"Y":128.26},{"X":43.79,"Y":125.19},{"X":43.54,"Y":126.2},{"X":43.55,"Y":126.19},{"X":43.13,"Y":133.69},{"X":43.13,"Y":133.68},{"X":43.66,"Y":140.71},{"X":43.65,"Y":140.7},{"X":45.09,"Y":147.46},{"X":45.08,"Y":147.45},{"X":47.49,"Y":154.24},{"X":47.48,"Y":154.23},{"X":51.23,"Y":161.76},{"X":63.98,"Y":182.09},{"X":67.55,"Y":189.18},{"X":69.73,"Y":195.4},{"X":70.92,"Y":201.58},{"X":71.16,"Y":207.87},{"X":70.43,"Y":214.58},{"X":68.63,"Y":221.85},{"X":68.56,"Y":221.68},{"X":68.68,"Y":203.83},{"X":68.68,"Y":203.84},{"X":68.16,"Y":197.1},{"X":68.17,"Y":197.11},{"X":67.05,"Y":192.75},{"X":67.06,"Y":192.76},{"X":65.5,"Y":189.85},{"X":65.51,"Y":189.86},{"X":63.49,"Y":187.86},{"X":60.94,"Y":186.59},{"X":60.95,"Y":186.6},{"X":57.55,"Y":186.01},{"X":57.78,"Y":189.41},{"X":57.77,"Y":189.4},{"X":59.32,"Y":201.46},{"X":59.31,"Y":201.45},{"X":61.68,"Y":212.76},{"X":61.67,"Y":212.75},{"X":64.76,"Y":223.11},{"X":64.75,"Y":223.1},{"X":68.47,"Y":232.45},{"X":72.73,"Y":240.71},{"X":77.44,"Y":247.84},{"X":82.45,"Y":253.81},{"X":82.44,"Y":253.8},{"X":87.82,"Y":258.8},{"X":93.45,"Y":262.8},{"X":93.44,"Y":262.79},{"X":99.44,"Y":265.89},{"X":99.43,"Y":265.88},{"X":105.67,"Y":268.07},{"X":105.66,"Y":268.06},{"X":112.58,"Y":269.42},{"X":112.57,"Y":269.41},{"X":120.65,"Y":270.08}],[{"X":121.49,"Y":240.71},{"X":118.05,"Y":239.68},{"X":115.54,"Y":238.06},{"X":113.86,"Y":235.97},{"X":112.96,"Y":233.43},{"X":112.86,"Y":230.29},{"X":112.9,"Y":230.33},{"X":114.24,"Y":231.32},{"X":114.23,"Y":231.31},{"X":117.3,"Y":232.52},{"X":117.29,"Y":232.51},{"X":122.05,"Y":233.17},{"X":132.1,"Y":233.03},{"X":140.49,"Y":233.06},{"X":139.8,"Y":234.49},{"X":137.79,"Y":236.7},{"X":134.63,"Y":238.72},{"X":130.41,"Y":240.25},{"X":125.83,"Y":240.94}],[{"X":90.76,"Y":219.11},{"X":91.11,"Y":218.28},{"X":92.59,"Y":216.41},{"X":95.22,"Y":214.69},{"X":99.6,"Y":213.14},{"X":106.53,"Y":211.9},{"X":117,"Y":211.2},{"X":143.09,"Y":211.3},{"X":151.49,"Y":210.93},{"X":151.31,"Y":211.49},{"X":149.72,"Y":213.46},{"X":147.43,"Y":214.88},{"X":143.97,"Y":215.82},{"X":138.58,"Y":216.09},{"X":117.5,"Y":214.37},{"X":117.51,"Y":214.38},{"X":108.81,"Y":214.35},{"X":101.81,"Y":215.22},{"X":101.82,"Y":215.21},{"X":95.89,"Y":216.85},{"X":95.9,"Y":216.84},{"X":90.72,"Y":219.22}],[{"X":131.9,"Y":198.38},{"X":131.72,"Y":195.25},{"X":132.38,"Y":192.96},{"X":133.78,"Y":191.21},{"X":136.84,"Y":189.34},{"X":140.91,"Y":187.09},{"X":142.52,"Y":185.35},{"X":143.3,"Y":183.24},{"X":143.3,"Y":183.25},{"X":143.22,"Y":183.13},{"X":141.54,"Y":180.12},{"X":139.65,"Y":174.9},{"X":138.32,"Y":168.14},{"X":137.62,"Y":158.87},{"X":137.76,"Y":144.77},{"X":142.77,"Y":159.79},{"X":145.49,"Y":170.4},{"X":146.69,"Y":178.4},{"X":146.78,"Y":184.55},{"X":146.02,"Y":189.28},{"X":144.58,"Y":192.89},{"X":142.54,"Y":195.66},{"X":139.94,"Y":197.69},{"X":136.5,"Y":199.14},{"X":132.22,"Y":199.86}],[{"X":108.17,"Y":188.43},{"X":106.35,"Y":187.41},{"X":105.13,"Y":185.72},{"X":104.56,"Y":183.25},{"X":104.61,"Y":183.31},{"X":104.81,"Y":183.53},{"X":104.8,"Y":183.52},{"X":106.39,"Y":184.64},{"X":106.38,"Y":184.63},{"X":108.44,"Y":184.92},{"X":114,"Y":183.64},{"X":116.83,"Y":183.49},{"X":119.09,"Y":184.26},{"X":121.14,"Y":185.99},{"X":120.5,"Y":186.31},{"X":114.98,"Y":188.22},{"X":110.98,"Y":188.8}],[{"X":163.89,"Y":141.31},{"X":166.4,"Y":137.22},{"X":174.87,"Y":127.72},{"X":177.63,"Y":123.62},{"X":179.28,"Y":119.59},{"X":179.28,"Y":119.6},{"X":179.24,"Y":119.6},{"X":179.25,"Y":119.59},{"X":176.7,"Y":119.79},{"X":176.71,"Y":119.78},{"X":170.65,"Y":120.87},{"X":170.66,"Y":120.86},{"X":164.55,"Y":122.95},{"X":164.56,"Y":122.94},{"X":148.93,"Y":130.62},{"X":148.93,"Y":130.61},{"X":149.21,"Y":132.61},{"X":149.2,"Y":132.6},{"X":150.57,"Y":136.41},{"X":152.55,"Y":139.41},{"X":152.54,"Y":139.4},{"X":155.11,"Y":141.71},{"X":155.1,"Y":141.7},{"X":158.43,"Y":143.41},{"X":158.42,"Y":143.4},{"X":162.62,"Y":144.5}],[{"X":90.87,"Y":144.21},{"X":90.86,"Y":144.22},{"X":93.93,"Y":139.6},{"X":97.47,"Y":134.4},{"X":99.02,"Y":130.65},{"X":99.02,"Y":130.66},{"X":98.92,"Y":130.62},{"X":98.93,"Y":130.63},{"X":63.23,"Y":119.65},{"X":67.31,"Y":125.14},{"X":73.8,"Y":132.62},{"X":73.79,"Y":132.61},{"X":79.3,"Y":137.68},{"X":84.84,"Y":141.56},{"X":84.83,"Y":141.55},{"X":90.59,"Y":144.44}],[{"X":128.47,"Y":127.41},{"X":128.46,"Y":127.42},{"X":134.55,"Y":125.73},{"X":134.54,"Y":125.74},{"X":141.57,"Y":122.7},{"X":141.56,"Y":122.71},{"X":154.9,"Y":115.21},{"X":164.19,"Y":110.32},{"X":171.16,"Y":107.57},{"X":177.57,"Y":106},{"X":183.83,"Y":105.4},{"X":190.12,"Y":105.74},{"X":182.19,"Y":101.42},{"X":182.2,"Y":101.43},{"X":175.96,"Y":98.85},{"X":175.97,"Y":98.86},{"X":170.13,"Y":97.45},{"X":170.14,"Y":97.46},{"X":164,"Y":96.98},{"X":157.13,"Y":97.46},{"X":157.08,"Y":97.55},{"X":156.47,"Y":98.59},{"X":153.09,"Y":103.35},{"X":149.58,"Y":106.83},{"X":145.83,"Y":109.3},{"X":141.79,"Y":110.89},{"X":137.21,"Y":111.67},{"X":131.97,"Y":111.55},{"X":125.78,"Y":110.38},{"X":117.8,"Y":107.78},{"X":92.32,"Y":96.78},{"X":92.33,"Y":96.79},{"X":83.94,"Y":93.95},{"X":83.95,"Y":93.96},{"X":77.47,"Y":92.65},{"X":77.48,"Y":92.66},{"X":72.09,"Y":92.45},{"X":67.49,"Y":93.16},{"X":67.5,"Y":93.15},{"X":63.28,"Y":94.72},{"X":63.29,"Y":94.71},{"X":59.49,"Y":97.13},{"X":55.9,"Y":100.53},{"X":55.91,"Y":100.52},{"X":52.52,"Y":105.09},{"X":49.25,"Y":111.18},{"X":52.77,"Y":110.06},{"X":58.91,"Y":108.7},{"X":64.9,"Y":108.31},{"X":70.86,"Y":108.86},{"X":77.27,"Y":110.42},{"X":84.53,"Y":113.27},{"X":105.04,"Y":123.87},{"X":105.03,"Y":123.86},{"X":111.74,"Y":126.51},{"X":111.73,"Y":126.5},{"X":117.29,"Y":127.77},{"X":117.28,"Y":127.76},{"X":122.82,"Y":128.06}]]';
// The Phantom Scull Ring
var default_custom_clip_polygon = '[[{"X":385.77,"Y":166.95},{"X":386.68,"Y":182.21},{"X":386.15,"Y":187.13},{"X":384.96,"Y":190.99},{"X":382.95,"Y":194.32},{"X":379.91,"Y":197.42},{"X":375.8,"Y":200.17},{"X":370.59,"Y":202.47},{"X":364.37,"Y":204.13},{"X":357.67,"Y":204.95},{"X":350.93,"Y":204.85},{"X":344.71,"Y":203.87},{"X":339.59,"Y":202.19},{"X":335.52,"Y":199.95},{"X":332.61,"Y":197.37},{"X":330.67,"Y":194.53},{"X":329.62,"Y":191.41},{"X":329.4,"Y":187.83},{"X":330.02,"Y":183.99},{"X":331.34,"Y":181.14},{"X":333.27,"Y":179.05},{"X":336.11,"Y":177.4},{"X":340.71,"Y":176.05},{"X":352.22,"Y":173.98},{"X":356.3,"Y":172.51},{"X":361.25,"Y":169.4},{"X":370.03,"Y":163.12},{"X":373.94,"Y":161.22},{"X":377.01,"Y":160.6},{"X":379.53,"Y":160.94},{"X":381.9,"Y":162.19},{"X":384.3,"Y":164.67},{"X":385.77,"Y":166.93},{"X":385.77,"Y":166.95}],[{"X":270.77,"Y":163.84},{"X":273.88,"Y":163.4},{"X":276.36,"Y":163.91},{"X":280.12,"Y":166.08},{"X":285.42,"Y":169.2},{"X":291.02,"Y":171.33},{"X":299.79,"Y":173.33},{"X":307.68,"Y":175.13},{"X":311.52,"Y":176.78},{"X":314.01,"Y":178.71},{"X":315.73,"Y":181.15},{"X":316.83,"Y":184.41},{"X":317.2,"Y":188.89},{"X":316.7,"Y":192.44},{"X":315.33,"Y":195.6},{"X":313.05,"Y":198.56},{"X":309.77,"Y":201.19},{"X":305.39,"Y":203.45},{"X":299.95,"Y":205.12},{"X":293.7,"Y":205.99},{"X":287.12,"Y":205.96},{"X":280.75,"Y":205},{"X":275.02,"Y":203.24},{"X":270.05,"Y":200.77},{"X":266.08,"Y":197.81},{"X":263.1,"Y":194.47},{"X":260.95,"Y":190.7},{"X":259.68,"Y":186.54},{"X":259.29,"Y":181.92},{"X":259.86,"Y":176.86},{"X":261.36,"Y":171.68},{"X":263.13,"Y":168.56},{"X":265.48,"Y":166.25},{"X":268.64,"Y":164.55},{"X":270.77,"Y":163.84},{"X":270.77,"Y":163.84}],[{"X":303.94,"Y":227.57},{"X":303.74,"Y":222.63},{"X":304.44,"Y":218.35},{"X":305.94,"Y":214.59},{"X":308.24,"Y":211.27},{"X":311.35,"Y":208.46},{"X":315.13,"Y":206.32},{"X":319.55,"Y":204.91},{"X":324.31,"Y":204.37},{"X":329.09,"Y":204.77},{"X":333.4,"Y":206.03},{"X":337.08,"Y":208.03},{"X":339.99,"Y":210.61},{"X":342.11,"Y":213.69},{"X":343.43,"Y":217.19},{"X":343.94,"Y":221.2},{"X":343.59,"Y":225.38},{"X":342.53,"Y":228.01},{"X":340.69,"Y":230.17},{"X":337.79,"Y":232.02},{"X":333.81,"Y":233.34},{"X":328.46,"Y":234.03},{"X":322.02,"Y":233.83},{"X":315.23,"Y":232.68},{"X":309.37,"Y":230.81},{"X":305.39,"Y":228.73},{"X":303.99,"Y":227.61},{"X":303.94,"Y":227.57}],[{"X":421.16,"Y":64.34},{"X":421.16,"Y":64.45},{"X":422.7,"Y":96.81},{"X":424.28,"Y":149.29},{"X":425.26,"Y":216.18},{"X":425.57,"Y":327.02},{"X":220.65,"Y":327.02},{"X":220.41,"Y":312.05},{"X":219.69,"Y":230.46},{"X":219.9,"Y":144.66},{"X":221.01,"Y":65.92},{"X":233.74,"Y":65.34},{"X":264.63,"Y":64.78},{"X":325.38,"Y":65.31},{"X":363.93,"Y":65.31},{"X":393.46,"Y":64.48},{"X":420.05,"Y":62.8},{"X":420.8,"Y":62.92},{"X":421.16,"Y":64.34}],[{"X":404.57,"Y":215.13},{"X":404.58,"Y":215.08},{"X":405.83,"Y":205.87},{"X":406.55,"Y":194.49},{"X":406.3,"Y":183.7},{"X":405.16,"Y":173.57},{"X":403.17,"Y":164.03},{"X":400.34,"Y":155.01},{"X":396.73,"Y":146.61},{"X":392.34,"Y":138.76},{"X":387.23,"Y":131.54},{"X":381.47,"Y":125.02},{"X":375.05,"Y":119.16},{"X":368.04,"Y":114.01},{"X":360.39,"Y":109.58},{"X":352.3,"Y":105.99},{"X":343.88,"Y":103.28},{"X":335.22,"Y":101.47},{"X":326.42,"Y":100.59},{"X":317.57,"Y":100.64},{"X":308.77,"Y":101.63},{"X":300.3,"Y":103.53},{"X":292.06,"Y":106.33},{"X":284.32,"Y":109.94},{"X":277.01,"Y":114.36},{"X":270.11,"Y":119.65},{"X":263.83,"Y":125.67},{"X":258.83,"Y":131.66},{"X":253.44,"Y":139.77},{"X":248.35,"Y":149.13},{"X":244.11,"Y":158.88},{"X":241,"Y":168.28},{"X":239,"Y":177.21},{"X":238.09,"Y":185.4},{"X":238.17,"Y":192.9},{"X":239.13,"Y":199.57},{"X":240.91,"Y":205.61},{"X":243.45,"Y":211.04},{"X":246.09,"Y":214.67},{"X":249.63,"Y":217.9},{"X":254.56,"Y":221.04},{"X":270.07,"Y":228.23},{"X":275.76,"Y":231.57},{"X":279.77,"Y":234.93},{"X":282.82,"Y":238.64},{"X":285.08,"Y":242.87},{"X":286.61,"Y":247.72},{"X":287.31,"Y":253.67},{"X":287.19,"Y":274.82},{"X":287.8,"Y":281.39},{"X":288.94,"Y":285.57},{"X":290.57,"Y":288.43},{"X":292.56,"Y":290.24},{"X":295.1,"Y":291.3},{"X":295.83,"Y":283.75},{"X":296,"Y":265.6},{"X":296.31,"Y":250.76},{"X":297.29,"Y":241.67},{"X":299.29,"Y":240.75},{"X":303.08,"Y":239.94},{"X":307.26,"Y":240},{"X":307.66,"Y":242.7},{"X":309.02,"Y":256.43},{"X":310.57,"Y":291.19},{"X":311.49,"Y":291.54},{"X":314.95,"Y":293.31},{"X":316.6,"Y":294.82},{"X":316.6,"Y":295.52},{"X":315.35,"Y":295.94},{"X":315.99,"Y":296.02},{"X":317.2,"Y":295.47},{"X":318.2,"Y":293.99},{"X":319.04,"Y":290.81},{"X":319.39,"Y":284.37},{"X":318.41,"Y":262.35},{"X":318.37,"Y":251.85},{"X":319.08,"Y":245.75},{"X":320.27,"Y":242.05},{"X":321.29,"Y":240.77},{"X":323.08,"Y":240.08},{"X":328.27,"Y":240},{"X":329.31,"Y":244.13},{"X":330.19,"Y":252.03},{"X":330.63,"Y":273.92},{"X":331.25,"Y":284.25},{"X":332.33,"Y":289.99},{"X":333.7,"Y":293.31},{"X":335.26,"Y":295.12},{"X":337.01,"Y":295.94},{"X":337.81,"Y":294.94},{"X":339.33,"Y":291.52},{"X":340.32,"Y":286.68},{"X":340.61,"Y":279.64},{"X":339.38,"Y":260.18},{"X":339.31,"Y":251.49},{"X":340.05,"Y":245.84},{"X":341.39,"Y":241.87},{"X":342.36,"Y":240.75},{"X":344.31,"Y":240.04},{"X":351.49,"Y":240},{"X":351.67,"Y":240.9},{"X":352.45,"Y":248.35},{"X":352.58,"Y":274.14},{"X":353.27,"Y":282.2},{"X":354.5,"Y":287.31},{"X":356.13,"Y":290.68},{"X":358.13,"Y":292.86},{"X":359.27,"Y":289.89},{"X":360.62,"Y":284.2},{"X":361.32,"Y":276.58},{"X":361.16,"Y":258.89},{"X":361.45,"Y":247.8},{"X":365.47,"Y":242.21},{"X":370.89,"Y":236.4},{"X":377.72,"Y":230.54},{"X":385.94,"Y":224.78},{"X":395.31,"Y":219.41},{"X":404.57,"Y":215.13}]]';
var output_format = 1;
var ClipperLib_MaxSteps_original; // this hold the original ClipperLib.MaxSteps value
// during benchmarks, ClipperLib.MaxSteps is set to 10
// to make benchmarks comparable
var ismousedown = false; // Not yet in use
var bench_glob = [];
var bench_elapsed_time = 0;
window.onerror = function (message, url, linenumber) {
console.log("JavaScript error: " + message + " on line " + linenumber + " for " + url);
}
window.onload = function () {
"use strict";
if (typeof (jQuery) == "undefined") alert("Failed to load jQuery. Please reload the page. If this fails repeatedly, please check the path of the jQuery library or use an own copy of jQuery.");
else if (typeof (Raphael) == "undefined") alert("Failed to load Raphael. Please reload the page. If this fails repeatedly, please check the path of the Raphael library or use an own copy of Raphael.");
else if (typeof (ClipperLib) == "undefined") alert("Failed to load ClipperLib. Please check that ClipperLib is loaded correctly.");
else {
ClipperLib_MaxSteps_original = ClipperLib.MaxSteps;
browserg = get_browser();
bench = new benchmark("bench");
p = SVG.create();
main();
}
}
function get_browser() {
var nav = navigator.userAgent.toString().toLowerCase();
var browser = {};
if (nav.indexOf("chrome") != -1 && nav.indexOf("chromium") == -1) browser.chrome = 1;
else browser.chrome = 0;
if (nav.indexOf("chromium") != -1) browser.chromium = 1;
else browser.chromium = 0;
if (nav.indexOf("safari") != -1 && nav.indexOf("chrome") == -1 && nav.indexOf("chromium") == -1) browser.safari = 1;
else browser.safari = 0;
if (nav.indexOf("firefox") != -1) browser.firefox = 1;
else browser.firefox = 0;
if (nav.indexOf("firefox/17") != -1) browser.firefox17 = 1;
else browser.firefox17 = 0;
if (nav.indexOf("firefox/15") != -1) browser.firefox15 = 1;
else browser.firefox15 = 0;
if (nav.indexOf("firefox/3") != -1) browser.firefox3 = 1;
else browser.firefox3 = 0;
if (nav.indexOf("opera") != -1) browser.opera = 1;
else browser.opera = 0;
if (nav.indexOf("msie 10") != -1) browser.msie10 = 1;
else browser.msie10 = 0;
if (nav.indexOf("msie 9") != -1) browser.msie9 = 1;
else browser.msie9 = 0;
if (nav.indexOf("msie 8") != -1) browser.msie8 = 1;
else browser.msie8 = 0;
if (nav.indexOf("msie 7") != -1) browser.msie7 = 1;
else browser.msie7 = 0;
if (nav.indexOf("msie ") != -1) browser.msie = 1;
else browser.msie = 0;
for (var i in browser) {
if (browser[i] === 1 && !i.match(/[0-9]/)) browser["browser"] = i;
}
browser.version = $.browser.version;
return browser;
}
// Helper tool to piece together Raphael's paths into strings again
Array.prototype.flatten || (Array.prototype.flatten = function () {
return this.reduce(function (a, b) {
return a.concat('function' === typeof b.flatten ? b.flatten() : b);
}, []);
});
/* Normalizes inputted polygon string
Input can be JSON-stringified version of the following:
- Array of arrays of points [[{"X":10,"Y":10},{"X":10,"Y":10},{"X":10,"Y":10}][{"X":10,"Y":10},{"X":10,"Y":10},{"X":10,"Y":10}]]
- Array of points [{"X":10,"Y":10},{"X":10,"Y":10},{"X":10,"Y":10}]
- The aboves in lowercase
- Array of x,y-coordinates eg. [0, 10, 20, 30, 40, 50] or [0 10 20 30 40 50] or [0 10, 20 30, 40 50];
- The above without []
- SVG path string with commands MLVHZ and mlvhz
Returns normalized Clipper Polygons object stringified or false in failure
*/
function normalize_clipper_poly(polystr, quiet) {
if (typeof (polystr) != "string") return false;
polystr = polystr.trim();
var np, txt;
if (polystr.substr(0, 1).toUpperCase() === "M") {
np = svgpath_to_clipper_polygons(polystr);
if (np === false) {
txt = "Unable to parse SVG path string.\n";
txt += "Click OK to continue.\n";
if (!quiet) alert(txt);
return false;
}
else return JSON.stringify(np);
}
polystr = polystr.replace(/[\s,]+/g, ",");
if (polystr.substr(0, 1) !== "[") polystr = "[" + polystr;
if (polystr.substr(-1, 1) !== "]") polystr = polystr + "]";
try {
var poly = JSON.parse(polystr);
}
catch (err) {
txt = "Unable to parse polygon string.\n";
txt += "Error: " + err.message + "\n";
txt += "Click OK to continue.\n";
if (!quiet) alert(txt);
return false;
}
// if only points without "X" and "Y"
var temp_n = [], i;
if (isArray(poly) && poly.length && typeof (poly[0]) == "number") {
var len = poly.length;
for (i = 0; i < len; i = i + 2) {
temp_n.push({
X: poly[i],
Y: poly[i + 1]
});
}
poly = temp_n;
}
// if an array of array of points without "X" and "Y"
var temp_n2 = [], i, j, len, len2;
if (isArray(poly) && poly.length && isArray(poly[0]) && typeof(poly[0][0]) != "undefined" &&
typeof(poly[0][0].X) == "undefined" &&
typeof(poly[0][0].x) == "undefined") {
len2 = poly.length;
for (j = 0; j < len2; j++) {
temp_n = [];
len = poly[j].length;
for (i = 0; i < len; i = i + 2) {
temp_n.push({
X: poly[j][i],
Y: poly[j][i + 1]
});
}
temp_n2.push(temp_n);
}
poly = temp_n2;
}
// if not array of arrays, convert to array of arrays
if (isArray(poly) && poly.length > 0 && !isArray(poly[0])) poly = [poly];
var pp, n = [
[]
],
m, pm, x, y;
np = [
[]
];
for (i = 0, m = poly.length; i < m; i++) {
np[i] = [];
for (j = 0, pm = poly[i].length; j < pm; j++) {
pp = {};
y = null;
x = null;
if (typeof (poly[i][j].X) != "undefined" && !isNaN(Number(poly[i][j].X))) x = Number(poly[i][j].X);
else if (typeof (poly[i][j].x) != "undefined" && !isNaN(Number(poly[i][j].x))) x = Number(poly[i][j].x);
if (typeof (poly[i][j].Y) != "undefined" && !isNaN(Number(poly[i][j].Y))) y = Number(poly[i][j].Y);
else if (typeof (poly[i][j].y) != "undefined" && !isNaN(Number(poly[i][j].y))) y = Number(poly[i][j].y);
if (y !== null && x !== null) {
pp.X = x;
pp.Y = y;
np[i].push(pp);
}
else {
txt = "Unable to parse polygon string.\n";
txt += "Error: Coordinates are not in a right form.\n";
txt += "Click OK to continue.\n";
if (!quiet) alert(txt);
return false;
}
;
}
}
return JSON.stringify(np);
}
// helper function for normalize_clipper_poly()
function svgpath_to_clipper_polygons(d) {
var arr;
d = d.trim();
arr = Raphael.parsePathString(d); // str to array
arr = Raphael._pathToAbsolute(arr); // mahvstcsqz -> uppercase
var str = arr.flatten().join(" ");
var paths = str.replace(/M/g, '|M').split("|");
var k, polygons_arr = [],
polygon_arr = [];
for (k = 0; k < paths.length; k++) {
if (paths[k].trim() === "") continue;
arr = Raphael.parsePathString(paths[k].trim());
polygon_arr = [];
var i = 0,
j, m = arr.length,
letter = "",
x = 0,
y = 0,
pt = {},
subpath_start = {};
subpath_start.x = "";
subpath_start.y = "";
for (; i < m; i++) {
letter = arr[i][0].toUpperCase();
if (letter != "M" && letter != "L" && letter != "Z") continue;
if (letter != "Z") {
for (j = 1; j < arr[i].length; j = j + 2) {
if (letter == "V") y = arr[i][j];
else if (letter == "H") x = arr[i][j];
else {
x = arr[i][j];
y = arr[i][j + 1];
}
pt = {};
pt.X = null;
pt.Y = null;
if (typeof (x) != "undefined" && !isNaN(Number(x))) pt.X = Number(x);
if (typeof (y) != "undefined" && !isNaN(Number(y))) pt.Y = Number(y);
if (pt.X !== null && pt.Y !== null) {
polygon_arr.push(pt);
}
else {
return false;
}
}
}
if ((letter != "Z" && subpath_start.x === "") || letter == "M") {
subpath_start.x = x;
subpath_start.y = y;
}
if (letter == "Z") {
x = subpath_start.x;
y = subpath_start.y;
}
}
polygons_arr.push(polygon_arr);
}
return polygons_arr;
}
function format_output(polystr, ExPolygonsOrNot) {
var txt, returnAsExPolygons = false;
if (typeof(polystr) != "string" || polystr === "") return "";
if (ExPolygonsOrNot == "ExPolygons" && ExPolygons) returnAsExPolygons = true;
try {
var poly = JSON.parse(polystr);
}
catch (err) {
txt = "Unable to parse polygon for output.\n";
txt += "Error: " + err.message + "\n";
txt += "Click OK to continue.\n";
alert(txt);
return "";
}
var i, j, m, n, newpolystr = "";
if (output_format === 0) // Clipper
{
//return polystr;
}
else if (output_format == 1) // Plain
{
m = poly.length;
for (i = 0; i < m; i++) {
newpolystr += "[";
n = poly[i].length;
for (j = 0; j < n; j++) {
newpolystr += poly[i][j].X + "," + poly[i][j].Y;
if (j !== n - 1) newpolystr += ", ";
}
newpolystr += "]";
if (i !== m - 1) newpolystr += ",";
}
//return "[" + newpolystr + "]";
polystr = "[" + newpolystr + "]";
}
else if (output_format == 2) // SVG
{
m = poly.length;
for (i = 0; i < m; i++) {
n = poly[i].length;
for (j = 0; j < n; j++) {
if (j === 0) newpolystr += "M";
else newpolystr += "L";
newpolystr += poly[i][j].X + "," + poly[i][j].Y;
if (j !== n - 1) newpolystr += " ";
}
newpolystr += "Z";
if (i !== m - 1) newpolystr += " ";
}
if (newpolystr.trim() == "Z") newpolystr = "";
//return newpolystr;
polystr = newpolystr;
}
if (!returnAsExPolygons) return polystr;
else {
if (!cpr) cpr = new ClipperLib.Clipper();
else cpr.Clear();
cpr.AddPolygons(poly, ClipperLib.PolyType.ptSubject);
sss = new ClipperLib.ExPolygons();
cpr.Execute(clipType, sss, subject_fillType, clip_fillType);
polystr = JSON.stringify(sss);
return polystr;
}
/*
else if (output_format == 3) // ExPolygons
{
m = poly.length;
for(i = 0; i < m; i++)
{
newpolystr += "[";
n = poly[i].length;
for(j = 0; j < n; j++)
{
newpolystr += poly[i][j].X + "," + poly[i][j].Y;
if (j !== n - 1) newpolystr += ", ";
}
newpolystr += "]";
if (i !== m - 1) newpolystr += ",";
}
return "[" + newpolystr + "]";
}
*/
}
;
function get_gb_and_arrow() {
var gb_poly = '[[{"X":189,"Y":154},{"X":192,"Y":155},{"X":193,"Y":154},{"X":194,"Y":151},{"X":194,"Y":150},{"X":196,"Y":151},{"X":199,"Y":151},{"X":200,"Y":150},{"X":203,"Y":149},{"X":204,"Y":149},{"X":205,"Y":149},{"X":206,"Y":149},{"X":209,"Y":150},{"X":211,"Y":149},{"X":212,"Y":149},{"X":212,"Y":152},{"X":212,"Y":155},{"X":213,"Y":156},{"X":213,"Y":156},{"X":213,"Y":159},{"X":214,"Y":159},{"X":216,"Y":161},{"X":216,"Y":161},{"X":216,"Y":163},{"X":217,"Y":163},{"X":218,"Y":166},{"X":218,"Y":166},{"X":217,"Y":163},{"X":217,"Y":162},{"X":218,"Y":162},{"X":218,"Y":163},{"X":220,"Y":165},{"X":218,"Y":167},{"X":218,"Y":167},{"X":215,"Y":168},{"X":214,"Y":170},{"X":214,"Y":171},{"X":215,"Y":170},{"X":217,"Y":168},{"X":220,"Y":168},{"X":221,"Y":168},{"X":222,"Y":170},{"X":223,"Y":172},{"X":223,"Y":174},{"X":224,"Y":176},{"X":223,"Y":178},{"X":223,"Y":179},{"X":223,"Y":179},{"X":223,"Y":180},{"X":222,"Y":180},{"X":222,"Y":180},{"X":221,"Y":178},{"X":222,"Y":177},{"X":222,"Y":174},{"X":221,"Y":174},{"X":220,"Y":172},{"X":218,"Y":172},{"X":218,"Y":174},{"X":220,"Y":174},{"X":218,"Y":174},{"X":220,"Y":176},{"X":220,"Y":178},{"X":217,"Y":180},{"X":221,"Y":179},{"X":221,"Y":180},{"X":222,"Y":181},{"X":221,"Y":182},{"X":218,"Y":183},{"X":218,"Y":183},{"X":217,"Y":182},{"X":214,"Y":184},{"X":214,"Y":187},{"X":214,"Y":189},{"X":211,"Y":191},{"X":210,"Y":191},{"X":210,"Y":190},{"X":209,"Y":189},{"X":207,"Y":189},{"X":206,"Y":189},{"X":207,"Y":189},{"X":209,"Y":191},{"X":209,"Y":191},{"X":210,"Y":191},{"X":207,"Y":192},{"X":205,"Y":191},{"X":204,"Y":191},{"X":204,"Y":191},{"X":204,"Y":192},{"X":204,"Y":194},{"X":204,"Y":195},{"X":206,"Y":195},{"X":206,"Y":198},{"X":206,"Y":199},{"X":206,"Y":200},{"X":206,"Y":202},{"X":206,"Y":203},{"X":210,"Y":206},{"X":209,"Y":207},{"X":207,"Y":211},{"X":209,"Y":212},{"X":210,"Y":212},{"X":210,"Y":213},{"X":207,"Y":212},{"X":207,"Y":213},{"X":206,"Y":213},{"X":207,"Y":215},{"X":209,"Y":216},{"X":209,"Y":218},{"X":210,"Y":222},{"X":209,"Y":226},{"X":211,"Y":226},{"X":209,"Y":231},{"X":207,"Y":232},{"X":206,"Y":234},{"X":205,"Y":237},{"X":205,"Y":240},{"X":202,"Y":246},{"X":201,"Y":247},{"X":200,"Y":247},{"X":200,"Y":247},{"X":200,"Y":248},{"X":201,"Y":249},{"X":201,"Y":248},{"X":201,"Y":250},{"X":202,"Y":251},{"X":201,"Y":254},{"X":200,"Y":254},{"X":201,"Y":253},{"X":199,"Y":254},{"X":199,"Y":253},{"X":199,"Y":253},{"X":196,"Y":254},{"X":194,"Y":251},{"X":192,"Y":253},{"X":193,"Y":251},{"X":192,"Y":251},{"X":192,"Y":251},{"X":191,"Y":251},{"X":192,"Y":253},{"X":191,"Y":253},{"X":190,"Y":254},{"X":189,"Y":255},{"X":189,"Y":255},{"X":190,"Y":254},{"X":190,"Y":253},{"X":190,"Y":251},{"X":189,"Y":251},{"X":189,"Y":249},{"X":189,"Y":251},{"X":189,"Y":253},{"X":189,"Y":253},{"X":188,"Y":255},{"X":185,"Y":254},{"X":187,"Y":253},{"X":185,"Y":253},{"X":185,"Y":253},{"X":185,"Y":254},{"X":184,"Y":254},{"X":183,"Y":254},{"X":179,"Y":254},{"X":177,"Y":255},{"X":177,"Y":255},{"X":176,"Y":255},{"X":174,"Y":255},{"X":176,"Y":256},{"X":177,"Y":257},{"X":176,"Y":257},{"X":176,"Y":258},{"X":172,"Y":258},{"X":172,"Y":260},{"X":171,"Y":260},{"X":170,"Y":260},{"X":169,"Y":259},{"X":169,"Y":260},{"X":168,"Y":260},{"X":169,"Y":261},{"X":167,"Y":262},{"X":166,"Y":264},{"X":166,"Y":264},{"X":162,"Y":265},{"X":161,"Y":264},{"X":161,"Y":264},{"X":162,"Y":262},{"X":163,"Y":261},{"X":160,"Y":262},{"X":158,"Y":261},{"X":158,"Y":262},{"X":159,"Y":262},{"X":160,"Y":264},{"X":160,"Y":265},{"X":160,"Y":265},{"X":158,"Y":267},{"X":157,"Y":267},{"X":156,"Y":267},{"X":155,"Y":267},{"X":155,"Y":267},{"X":154,"Y":268},{"X":154,"Y":270},{"X":154,"Y":269},{"X":151,"Y":269},{"X":150,"Y":272},{"X":149,"Y":272},{"X":149,"Y":270},{"X":147,"Y":270},{"X":147,"Y":272},{"X":146,"Y":272},{"X":146,"Y":272},{"X":144,"Y":270},{"X":143,"Y":272},{"X":141,"Y":270},{"X":141,"Y":272},{"X":140,"Y":272},{"X":140,"Y":271},{"X":140,"Y":273},{"X":139,"Y":273},{"X":139,"Y":273},{"X":139,"Y":273},{"X":138,"Y":272},{"X":138,"Y":273},{"X":137,"Y":273},{"X":137,"Y":273},{"X":136,"Y":272},{"X":137,"Y":270},{"X":136,"Y":269},{"X":136,"Y":270},{"X":135,"Y":270},{"X":134,"Y":270},{"X":134,"Y":272},{"X":133,"Y":272},{"X":133,"Y":272},{"X":132,"Y":272},{"X":132,"Y":270},{"X":129,"Y":272},{"X":130,"Y":272},{"X":128,"Y":272},{"X":128,"Y":271},{"X":127,"Y":272},{"X":127,"Y":271},{"X":127,"Y":271},{"X":129,"Y":269},{"X":132,"Y":269},{"X":134,"Y":267},{"X":134,"Y":267},{"X":128,"Y":269},{"X":127,"Y":269},{"X":128,"Y":268},{"X":129,"Y":267},{"X":136,"Y":266},{"X":136,"Y":266},{"X":136,"Y":265},{"X":136,"Y":265},{"X":135,"Y":264},{"X":135,"Y":262},{"X":135,"Y":264},{"X":134,"Y":266},{"X":126,"Y":266},{"X":126,"Y":267},{"X":124,"Y":267},{"X":123,"Y":267},{"X":122,"Y":267},{"X":122,"Y":267},{"X":122,"Y":267},{"X":122,"Y":266},{"X":123,"Y":267},{"X":123,"Y":266},{"X":123,"Y":265},{"X":123,"Y":265},{"X":125,"Y":265},{"X":126,"Y":264},{"X":125,"Y":264},{"X":125,"Y":262},{"X":127,"Y":261},{"X":127,"Y":262},{"X":127,"Y":261},{"X":129,"Y":261},{"X":128,"Y":261},{"X":130,"Y":259},{"X":133,"Y":259},{"X":134,"Y":259},{"X":132,"Y":259},{"X":129,"Y":260},{"X":128,"Y":260},{"X":127,"Y":260},{"X":127,"Y":260},{"X":122,"Y":262},{"X":122,"Y":261},{"X":121,"Y":261},{"X":121,"Y":260},{"X":122,"Y":259},{"X":121,"Y":258},{"X":119,"Y":259},{"X":118,"Y":260},{"X":118,"Y":258},{"X":117,"Y":258},{"X":117,"Y":256},{"X":119,"Y":256},{"X":121,"Y":256},{"X":119,"Y":255},{"X":119,"Y":255},{"X":121,"Y":254},{"X":121,"Y":254},{"X":126,"Y":251},{"X":127,"Y":250},{"X":127,"Y":251},{"X":127,"Y":251},{"X":128,"Y":249},{"X":129,"Y":249},{"X":132,"Y":249},{"X":128,"Y":248},{"X":127,"Y":248},{"X":127,"Y":249},{"X":126,"Y":248},{"X":123,"Y":249},{"X":122,"Y":248},{"X":121,"Y":248},{"X":119,"Y":248},{"X":121,"Y":249},{"X":121,"Y":249},{"X":118,"Y":248},{"X":119,"Y":249},{"X":117,"Y":249},{"X":116,"Y":248},{"X":116,"Y":248},{"X":116,"Y":247},{"X":117,"Y":247},{"X":116,"Y":246},{"X":117,"Y":246},{"X":117,"Y":247},{"X":118,"Y":247},{"X":118,"Y":245},{"X":119,"Y":245},{"X":121,"Y":244},{"X":123,"Y":244},{"X":123,"Y":245},{"X":125,"Y":246},{"X":126,"Y":244},{"X":125,"Y":243},{"X":126,"Y":242},{"X":126,"Y":244},{"X":127,"Y":246},{"X":129,"Y":246},{"X":129,"Y":246},{"X":129,"Y":246},{"X":132,"Y":246},{"X":132,"Y":245},{"X":128,"Y":245},{"X":128,"Y":243},{"X":129,"Y":244},{"X":129,"Y":243},{"X":130,"Y":240},{"X":128,"Y":239},{"X":128,"Y":239},{"X":133,"Y":238},{"X":134,"Y":237},{"X":135,"Y":238},{"X":135,"Y":237},{"X":134,"Y":237},{"X":134,"Y":237},{"X":135,"Y":235},{"X":136,"Y":235},{"X":138,"Y":236},{"X":138,"Y":235},{"X":141,"Y":236},{"X":147,"Y":234},{"X":147,"Y":235},{"X":148,"Y":235},{"X":149,"Y":234},{"X":151,"Y":234},{"X":151,"Y":234},{"X":154,"Y":234},{"X":150,"Y":233},{"X":149,"Y":233},{"X":149,"Y":232},{"X":148,"Y":231},{"X":147,"Y":231},{"X":147,"Y":232},{"X":144,"Y":235},{"X":143,"Y":234},{"X":141,"Y":236},{"X":140,"Y":235},{"X":141,"Y":234},{"X":139,"Y":234},{"X":137,"Y":234},{"X":137,"Y":233},{"X":136,"Y":232},{"X":137,"Y":234},{"X":134,"Y":234},{"X":134,"Y":235},{"X":129,"Y":234},{"X":128,"Y":234},{"X":132,"Y":234},{"X":135,"Y":231},{"X":136,"Y":229},{"X":138,"Y":229},{"X":138,"Y":227},{"X":139,"Y":226},{"X":139,"Y":224},{"X":141,"Y":223},{"X":140,"Y":223},{"X":138,"Y":223},{"X":138,"Y":223},{"X":139,"Y":222},{"X":143,"Y":217},{"X":146,"Y":217},{"X":147,"Y":217},{"X":147,"Y":217},{"X":149,"Y":217},{"X":147,"Y":217},{"X":149,"Y":217},{"X":149,"Y":217},{"X":150,"Y":217},{"X":150,"Y":217},{"X":150,"Y":216},{"X":151,"Y":215},{"X":150,"Y":215},{"X":149,"Y":215},{"X":149,"Y":214},{"X":150,"Y":213},{"X":150,"Y":213},{"X":150,"Y":212},{"X":148,"Y":212},{"X":146,"Y":213},{"X":139,"Y":213},{"X":138,"Y":213},{"X":138,"Y":211},{"X":138,"Y":211},{"X":137,"Y":213},{"X":137,"Y":213},{"X":137,"Y":212},{"X":137,"Y":211},{"X":137,"Y":210},{"X":137,"Y":210},{"X":138,"Y":210},{"X":137,"Y":209},{"X":137,"Y":210},{"X":137,"Y":209},{"X":137,"Y":209},{"X":137,"Y":209},{"X":137,"Y":209},{"X":136,"Y":210},{"X":135,"Y":210},{"X":134,"Y":209},{"X":133,"Y":209},{"X":133,"Y":207},{"X":133,"Y":207},{"X":135,"Y":206},{"X":135,"Y":206},{"X":135,"Y":206},{"X":135,"Y":206},{"X":133,"Y":206},{"X":133,"Y":206},{"X":133,"Y":206},{"X":133,"Y":206},{"X":132,"Y":206},{"X":132,"Y":207},{"X":129,"Y":206},{"X":128,"Y":205},{"X":127,"Y":206},{"X":127,"Y":205},{"X":126,"Y":205},{"X":127,"Y":203},{"X":129,"Y":204},{"X":128,"Y":203},{"X":128,"Y":202},{"X":127,"Y":201},{"X":126,"Y":201},{"X":128,"Y":201},{"X":128,"Y":200},{"X":132,"Y":201},{"X":129,"Y":198},{"X":134,"Y":198},{"X":134,"Y":196},{"X":134,"Y":194},{"X":136,"Y":193},{"X":138,"Y":194},{"X":139,"Y":193},{"X":138,"Y":193},{"X":139,"Y":192},{"X":138,"Y":192},{"X":139,"Y":191},{"X":139,"Y":191},{"X":139,"Y":190},{"X":136,"Y":190},{"X":135,"Y":190},{"X":134,"Y":190},{"X":134,"Y":190},{"X":134,"Y":188},{"X":136,"Y":189},{"X":136,"Y":189},{"X":136,"Y":189},{"X":136,"Y":187},{"X":136,"Y":187},{"X":136,"Y":188},{"X":136,"Y":187},{"X":136,"Y":187},{"X":135,"Y":184},{"X":135,"Y":183},{"X":136,"Y":183},{"X":135,"Y":183},{"X":136,"Y":182},{"X":135,"Y":182},{"X":135,"Y":183},{"X":134,"Y":182},{"X":134,"Y":182},{"X":134,"Y":182},{"X":135,"Y":181},{"X":134,"Y":181},{"X":135,"Y":180},{"X":134,"Y":180},{"X":135,"Y":179},{"X":135,"Y":179},{"X":133,"Y":178},{"X":133,"Y":179},{"X":133,"Y":179},{"X":133,"Y":180},{"X":132,"Y":180},{"X":132,"Y":180},{"X":132,"Y":181},{"X":132,"Y":182},{"X":130,"Y":182},{"X":132,"Y":178},{"X":132,"Y":178},{"X":130,"Y":177},{"X":132,"Y":177},{"X":132,"Y":177},{"X":134,"Y":174},{"X":134,"Y":177},{"X":135,"Y":178},{"X":135,"Y":179},{"X":134,"Y":178},{"X":134,"Y":178},{"X":136,"Y":179},{"X":136,"Y":177},{"X":136,"Y":178},{"X":136,"Y":177},{"X":136,"Y":177},{"X":136,"Y":176},{"X":136,"Y":174},{"X":138,"Y":176},{"X":143,"Y":176},{"X":144,"Y":178},{"X":146,"Y":177},{"X":147,"Y":177},{"X":147,"Y":178},{"X":148,"Y":179},{"X":148,"Y":179},{"X":148,"Y":180},{"X":148,"Y":180},{"X":149,"Y":181},{"X":149,"Y":181},{"X":151,"Y":178},{"X":154,"Y":178},{"X":156,"Y":180},{"X":157,"Y":179},{"X":157,"Y":179},{"X":158,"Y":180},{"X":160,"Y":181},{"X":161,"Y":181},{"X":160,"Y":180},{"X":160,"Y":180},{"X":161,"Y":179},{"X":162,"Y":179},{"X":161,"Y":178},{"X":161,"Y":178},{"X":162,"Y":178},{"X":162,"Y":178},{"X":161,"Y":177},{"X":160,"Y":178},{"X":159,"Y":177},{"X":161,"Y":176},{"X":161,"Y":174},{"X":161,"Y":174},{"X":163,"Y":174},{"X":162,"Y":173},{"X":163,"Y":172},{"X":163,"Y":173},{"X":167,"Y":173},{"X":168,"Y":171},{"X":168,"Y":170},{"X":170,"Y":168},{"X":170,"Y":168},{"X":171,"Y":168},{"X":170,"Y":168},{"X":168,"Y":168},{"X":167,"Y":168},{"X":167,"Y":168},{"X":167,"Y":168},{"X":166,"Y":168},{"X":163,"Y":170},{"X":163,"Y":168},{"X":166,"Y":168},{"X":166,"Y":168},{"X":163,"Y":168},{"X":163,"Y":168},{"X":161,"Y":168},{"X":160,"Y":168},{"X":157,"Y":166},{"X":158,"Y":165},{"X":157,"Y":165},{"X":158,"Y":165},{"X":158,"Y":163},{"X":160,"Y":162},{"X":165,"Y":163},{"X":163,"Y":162},{"X":162,"Y":162},{"X":163,"Y":162},{"X":166,"Y":163},{"X":162,"Y":160},{"X":163,"Y":160},{"X":167,"Y":160},{"X":166,"Y":159},{"X":166,"Y":159},{"X":167,"Y":159},{"X":168,"Y":159},{"X":167,"Y":159},{"X":166,"Y":158},{"X":166,"Y":159},{"X":165,"Y":158},{"X":165,"Y":156},{"X":167,"Y":156},{"X":166,"Y":156},{"X":165,"Y":154},{"X":166,"Y":154},{"X":166,"Y":152},{"X":167,"Y":154},{"X":167,"Y":152},{"X":168,"Y":152},{"X":168,"Y":152},{"X":168,"Y":152},{"X":168,"Y":151},{"X":169,"Y":150},{"X":171,"Y":150},{"X":171,"Y":150},{"X":171,"Y":150},{"X":171,"Y":151},{"X":172,"Y":150},{"X":174,"Y":150},{"X":174,"Y":148},{"X":174,"Y":147},{"X":176,"Y":148},{"X":176,"Y":149},{"X":177,"Y":149},{"X":177,"Y":150},{"X":177,"Y":150},{"X":178,"Y":150},{"X":177,"Y":150},{"X":178,"Y":150},{"X":178,"Y":150},{"X":178,"Y":149},{"X":177,"Y":149},{"X":177,"Y":147},{"X":178,"Y":147},{"X":178,"Y":147},{"X":178,"Y":150},{"X":179,"Y":150},{"X":180,"Y":151},{"X":180,"Y":152},{"X":181,"Y":151},{"X":180,"Y":148},{"X":180,"Y":150},{"X":180,"Y":149},{"X":180,"Y":148},{"X":179,"Y":148},{"X":179,"Y":147},{"X":180,"Y":147},{"X":181,"Y":146},{"X":182,"Y":147},{"X":182,"Y":149},{"X":183,"Y":151},{"X":183,"Y":151},{"X":183,"Y":152},{"X":181,"Y":155},{"X":182,"Y":155},{"X":182,"Y":155},{"X":181,"Y":155},{"X":180,"Y":157},{"X":182,"Y":155},{"X":184,"Y":154},{"X":184,"Y":154},{"X":184,"Y":151},{"X":183,"Y":148},{"X":184,"Y":148},{"X":183,"Y":147},{"X":184,"Y":147},{"X":184,"Y":147},{"X":184,"Y":147},{"X":187,"Y":146},{"X":187,"Y":146},{"X":187,"Y":147},{"X":189,"Y":147},{"X":187,"Y":146},{"X":187,"Y":145},{"X":187,"Y":145},{"X":187,"Y":144},{"X":185,"Y":144},{"X":185,"Y":144},{"X":189,"Y":144},{"X":190,"Y":145},{"X":191,"Y":146},{"X":195,"Y":148},{"X":195,"Y":149},{"X":191,"Y":151}],[{"X":236,"Y":34},{"X":237,"Y":35},{"X":238,"Y":35},{"X":239,"Y":35},{"X":239,"Y":36},{"X":240,"Y":35},{"X":239,"Y":35},{"X":239,"Y":35},{"X":240,"Y":36},{"X":242,"Y":37},{"X":242,"Y":37},{"X":240,"Y":40},{"X":242,"Y":38},{"X":242,"Y":37},{"X":243,"Y":37},{"X":243,"Y":36},{"X":245,"Y":36},{"X":246,"Y":37},{"X":247,"Y":38},{"X":246,"Y":40},{"X":247,"Y":37},{"X":249,"Y":37},{"X":250,"Y":38},{"X":250,"Y":38},{"X":250,"Y":37},{"X":251,"Y":37},{"X":251,"Y":36},{"X":253,"Y":37},{"X":254,"Y":36},{"X":254,"Y":36},{"X":256,"Y":36},{"X":257,"Y":36},{"X":260,"Y":36},{"X":262,"Y":36},{"X":262,"Y":36},{"X":262,"Y":36},{"X":264,"Y":35},{"X":266,"Y":36},{"X":266,"Y":35},{"X":265,"Y":34},{"X":266,"Y":33},{"X":266,"Y":34},{"X":269,"Y":34},{"X":269,"Y":35},{"X":271,"Y":34},{"X":271,"Y":35},{"X":270,"Y":38},{"X":270,"Y":39},{"X":271,"Y":39},{"X":270,"Y":44},{"X":269,"Y":44},{"X":268,"Y":46},{"X":266,"Y":47},{"X":264,"Y":51},{"X":258,"Y":53},{"X":257,"Y":55},{"X":256,"Y":56},{"X":254,"Y":58},{"X":254,"Y":60},{"X":253,"Y":60},{"X":251,"Y":61},{"X":250,"Y":61},{"X":250,"Y":62},{"X":253,"Y":62},{"X":254,"Y":61},{"X":255,"Y":61},{"X":255,"Y":62},{"X":256,"Y":62},{"X":257,"Y":60},{"X":258,"Y":61},{"X":256,"Y":63},{"X":254,"Y":66},{"X":254,"Y":66},{"X":254,"Y":66},{"X":253,"Y":66},{"X":250,"Y":67},{"X":248,"Y":66},{"X":248,"Y":68},{"X":246,"Y":69},{"X":246,"Y":70},{"X":249,"Y":67},{"X":253,"Y":67},{"X":253,"Y":66},{"X":254,"Y":67},{"X":251,"Y":69},{"X":251,"Y":69},{"X":251,"Y":70},{"X":250,"Y":71},{"X":250,"Y":72},{"X":249,"Y":71},{"X":249,"Y":72},{"X":249,"Y":73},{"X":250,"Y":73},{"X":250,"Y":73},{"X":250,"Y":73},{"X":253,"Y":71},{"X":253,"Y":70},{"X":253,"Y":69},{"X":256,"Y":69},{"X":260,"Y":68},{"X":262,"Y":68},{"X":264,"Y":66},{"X":266,"Y":64},{"X":271,"Y":68},{"X":275,"Y":66},{"X":276,"Y":67},{"X":277,"Y":67},{"X":283,"Y":68},{"X":284,"Y":68},{"X":286,"Y":67},{"X":287,"Y":68},{"X":289,"Y":67},{"X":291,"Y":67},{"X":291,"Y":68},{"X":292,"Y":67},{"X":293,"Y":68},{"X":293,"Y":69},{"X":293,"Y":70},{"X":294,"Y":73},{"X":294,"Y":73},{"X":294,"Y":74},{"X":295,"Y":74},{"X":290,"Y":81},{"X":289,"Y":84},{"X":290,"Y":86},{"X":287,"Y":91},{"X":287,"Y":93},{"X":286,"Y":96},{"X":283,"Y":97},{"X":283,"Y":97},{"X":283,"Y":101},{"X":283,"Y":101},{"X":281,"Y":102},{"X":282,"Y":103},{"X":281,"Y":105},{"X":278,"Y":107},{"X":277,"Y":108},{"X":276,"Y":108},{"X":275,"Y":108},{"X":273,"Y":108},{"X":272,"Y":108},{"X":271,"Y":108},{"X":267,"Y":111},{"X":266,"Y":112},{"X":267,"Y":112},{"X":268,"Y":111},{"X":275,"Y":108},{"X":276,"Y":110},{"X":276,"Y":111},{"X":276,"Y":112},{"X":276,"Y":112},{"X":277,"Y":113},{"X":279,"Y":113},{"X":280,"Y":116},{"X":278,"Y":117},{"X":276,"Y":117},{"X":273,"Y":117},{"X":272,"Y":117},{"X":269,"Y":121},{"X":269,"Y":122},{"X":267,"Y":123},{"X":265,"Y":124},{"X":261,"Y":123},{"X":258,"Y":123},{"X":258,"Y":124},{"X":259,"Y":124},{"X":262,"Y":124},{"X":265,"Y":125},{"X":266,"Y":124},{"X":267,"Y":125},{"X":269,"Y":125},{"X":270,"Y":126},{"X":271,"Y":126},{"X":272,"Y":125},{"X":273,"Y":125},{"X":275,"Y":124},{"X":275,"Y":123},{"X":276,"Y":122},{"X":279,"Y":122},{"X":280,"Y":124},{"X":280,"Y":124},{"X":282,"Y":124},{"X":286,"Y":127},{"X":289,"Y":127},{"X":289,"Y":127},{"X":290,"Y":129},{"X":292,"Y":133},{"X":294,"Y":136},{"X":295,"Y":136},{"X":295,"Y":137},{"X":295,"Y":137},{"X":295,"Y":138},{"X":298,"Y":138},{"X":298,"Y":138},{"X":299,"Y":140},{"X":300,"Y":141},{"X":300,"Y":144},{"X":299,"Y":146},{"X":300,"Y":147},{"X":300,"Y":149},{"X":301,"Y":152},{"X":301,"Y":154},{"X":303,"Y":158},{"X":304,"Y":160},{"X":304,"Y":161},{"X":306,"Y":166},{"X":306,"Y":168},{"X":309,"Y":169},{"X":308,"Y":169},{"X":309,"Y":170},{"X":309,"Y":172},{"X":309,"Y":172},{"X":309,"Y":172},{"X":309,"Y":171},{"X":312,"Y":172},{"X":315,"Y":173},{"X":319,"Y":176},{"X":321,"Y":176},{"X":322,"Y":177},{"X":322,"Y":178},{"X":323,"Y":180},{"X":325,"Y":182},{"X":326,"Y":183},{"X":327,"Y":187},{"X":331,"Y":188},{"X":328,"Y":189},{"X":327,"Y":191},{"X":330,"Y":195},{"X":333,"Y":200},{"X":335,"Y":204},{"X":335,"Y":206},{"X":335,"Y":206},{"X":335,"Y":205},{"X":335,"Y":204},{"X":333,"Y":204},{"X":333,"Y":204},{"X":332,"Y":204},{"X":330,"Y":204},{"X":327,"Y":201},{"X":326,"Y":201},{"X":324,"Y":202},{"X":322,"Y":203},{"X":320,"Y":202},{"X":319,"Y":203},{"X":319,"Y":203},{"X":321,"Y":203},{"X":322,"Y":203},{"X":323,"Y":203},{"X":326,"Y":202},{"X":327,"Y":203},{"X":328,"Y":204},{"X":332,"Y":206},{"X":333,"Y":206},{"X":333,"Y":207},{"X":334,"Y":210},{"X":336,"Y":210},{"X":336,"Y":211},{"X":337,"Y":212},{"X":339,"Y":217},{"X":341,"Y":220},{"X":339,"Y":222},{"X":336,"Y":225},{"X":335,"Y":229},{"X":334,"Y":229},{"X":334,"Y":229},{"X":335,"Y":229},{"X":336,"Y":229},{"X":336,"Y":231},{"X":338,"Y":233},{"X":341,"Y":232},{"X":342,"Y":234},{"X":342,"Y":233},{"X":342,"Y":232},{"X":343,"Y":227},{"X":344,"Y":226},{"X":346,"Y":226},{"X":347,"Y":226},{"X":350,"Y":226},{"X":352,"Y":226},{"X":352,"Y":226},{"X":353,"Y":226},{"X":354,"Y":226},{"X":353,"Y":225},{"X":354,"Y":225},{"X":355,"Y":225},{"X":356,"Y":226},{"X":360,"Y":226},{"X":363,"Y":229},{"X":368,"Y":233},{"X":368,"Y":233},{"X":370,"Y":236},{"X":370,"Y":238},{"X":370,"Y":240},{"X":370,"Y":243},{"X":370,"Y":245},{"X":368,"Y":249},{"X":368,"Y":251},{"X":368,"Y":255},{"X":365,"Y":257},{"X":364,"Y":261},{"X":361,"Y":259},{"X":361,"Y":260},{"X":359,"Y":260},{"X":358,"Y":260},{"X":363,"Y":260},{"X":360,"Y":264},{"X":361,"Y":264},{"X":361,"Y":262},{"X":363,"Y":264},{"X":363,"Y":264},{"X":360,"Y":266},{"X":358,"Y":267},{"X":357,"Y":266},{"X":356,"Y":266},{"X":355,"Y":266},{"X":354,"Y":267},{"X":353,"Y":268},{"X":350,"Y":268},{"X":352,"Y":269},{"X":352,"Y":269},{"X":354,"Y":267},{"X":355,"Y":268},{"X":355,"Y":269},{"X":355,"Y":272},{"X":354,"Y":272},{"X":353,"Y":272},{"X":354,"Y":272},{"X":354,"Y":272},{"X":354,"Y":272},{"X":355,"Y":272},{"X":356,"Y":272},{"X":353,"Y":276},{"X":349,"Y":276},{"X":348,"Y":277},{"X":346,"Y":277},{"X":345,"Y":277},{"X":344,"Y":278},{"X":345,"Y":278},{"X":346,"Y":277},{"X":347,"Y":277},{"X":350,"Y":277},{"X":352,"Y":278},{"X":350,"Y":279},{"X":349,"Y":279},{"X":348,"Y":279},{"X":347,"Y":279},{"X":348,"Y":280},{"X":349,"Y":280},{"X":350,"Y":280},{"X":350,"Y":280},{"X":350,"Y":279},{"X":352,"Y":280},{"X":352,"Y":279},{"X":352,"Y":278},{"X":355,"Y":279},{"X":356,"Y":281},{"X":355,"Y":281},{"X":353,"Y":281},{"X":355,"Y":281},{"X":361,"Y":280},{"X":367,"Y":279},{"X":366,"Y":281},{"X":365,"Y":282},{"X":366,"Y":284},{"X":366,"Y":288},{"X":365,"Y":289},{"X":363,"Y":290},{"X":361,"Y":290},{"X":360,"Y":291},{"X":358,"Y":292},{"X":357,"Y":293},{"X":357,"Y":295},{"X":354,"Y":295},{"X":352,"Y":297},{"X":350,"Y":298},{"X":344,"Y":300},{"X":343,"Y":302},{"X":342,"Y":303},{"X":337,"Y":302},{"X":333,"Y":300},{"X":322,"Y":302},{"X":322,"Y":303},{"X":321,"Y":302},{"X":321,"Y":304},{"X":320,"Y":304},{"X":317,"Y":302},{"X":319,"Y":302},{"X":317,"Y":301},{"X":317,"Y":301},{"X":316,"Y":301},{"X":315,"Y":301},{"X":316,"Y":301},{"X":317,"Y":302},{"X":314,"Y":302},{"X":315,"Y":302},{"X":315,"Y":301},{"X":314,"Y":301},{"X":314,"Y":303},{"X":313,"Y":303},{"X":313,"Y":303},{"X":313,"Y":301},{"X":313,"Y":300},{"X":311,"Y":301},{"X":312,"Y":302},{"X":312,"Y":303},{"X":309,"Y":301},{"X":308,"Y":299},{"X":305,"Y":298},{"X":305,"Y":299},{"X":306,"Y":299},{"X":309,"Y":302},{"X":308,"Y":303},{"X":305,"Y":303},{"X":304,"Y":304},{"X":301,"Y":304},{"X":299,"Y":304},{"X":300,"Y":304},{"X":300,"Y":304},{"X":298,"Y":304},{"X":297,"Y":304},{"X":295,"Y":306},{"X":295,"Y":304},{"X":293,"Y":304},{"X":292,"Y":306},{"X":293,"Y":305},{"X":293,"Y":306},{"X":295,"Y":306},{"X":295,"Y":308},{"X":295,"Y":308},{"X":295,"Y":309},{"X":294,"Y":310},{"X":293,"Y":310},{"X":292,"Y":310},{"X":290,"Y":309},{"X":284,"Y":309},{"X":284,"Y":309},{"X":283,"Y":310},{"X":284,"Y":311},{"X":283,"Y":312},{"X":283,"Y":311},{"X":280,"Y":308},{"X":277,"Y":305},{"X":275,"Y":305},{"X":272,"Y":306},{"X":270,"Y":306},{"X":268,"Y":306},{"X":265,"Y":310},{"X":264,"Y":309},{"X":262,"Y":306},{"X":262,"Y":310},{"X":261,"Y":312},{"X":261,"Y":314},{"X":260,"Y":315},{"X":260,"Y":316},{"X":261,"Y":317},{"X":261,"Y":317},{"X":260,"Y":317},{"X":259,"Y":319},{"X":259,"Y":319},{"X":258,"Y":320},{"X":258,"Y":321},{"X":258,"Y":322},{"X":256,"Y":323},{"X":255,"Y":322},{"X":255,"Y":322},{"X":254,"Y":322},{"X":253,"Y":320},{"X":251,"Y":319},{"X":249,"Y":319},{"X":247,"Y":319},{"X":247,"Y":317},{"X":246,"Y":317},{"X":246,"Y":317},{"X":247,"Y":317},{"X":246,"Y":319},{"X":245,"Y":319},{"X":244,"Y":317},{"X":243,"Y":317},{"X":240,"Y":317},{"X":239,"Y":319},{"X":236,"Y":319},{"X":235,"Y":319},{"X":235,"Y":317},{"X":234,"Y":319},{"X":233,"Y":322},{"X":231,"Y":321},{"X":229,"Y":322},{"X":228,"Y":322},{"X":228,"Y":324},{"X":227,"Y":324},{"X":228,"Y":324},{"X":227,"Y":324},{"X":227,"Y":321},{"X":227,"Y":321},{"X":226,"Y":322},{"X":227,"Y":323},{"X":226,"Y":324},{"X":227,"Y":324},{"X":226,"Y":324},{"X":226,"Y":325},{"X":225,"Y":325},{"X":226,"Y":326},{"X":226,"Y":327},{"X":226,"Y":328},{"X":224,"Y":328},{"X":224,"Y":331},{"X":223,"Y":328},{"X":222,"Y":326},{"X":221,"Y":326},{"X":217,"Y":324},{"X":216,"Y":324},{"X":216,"Y":325},{"X":215,"Y":326},{"X":213,"Y":327},{"X":212,"Y":326},{"X":213,"Y":325},{"X":212,"Y":323},{"X":213,"Y":324},{"X":216,"Y":321},{"X":218,"Y":322},{"X":220,"Y":321},{"X":221,"Y":321},{"X":222,"Y":320},{"X":223,"Y":317},{"X":225,"Y":316},{"X":225,"Y":315},{"X":227,"Y":315},{"X":228,"Y":313},{"X":227,"Y":312},{"X":228,"Y":311},{"X":228,"Y":311},{"X":229,"Y":310},{"X":229,"Y":310},{"X":231,"Y":309},{"X":234,"Y":309},{"X":234,"Y":306},{"X":235,"Y":305},{"X":236,"Y":304},{"X":238,"Y":303},{"X":238,"Y":299},{"X":239,"Y":295},{"X":240,"Y":295},{"X":243,"Y":295},{"X":244,"Y":295},{"X":246,"Y":294},{"X":247,"Y":293},{"X":245,"Y":291},{"X":246,"Y":291},{"X":246,"Y":290},{"X":246,"Y":290},{"X":255,"Y":288},{"X":259,"Y":288},{"X":260,"Y":288},{"X":262,"Y":289},{"X":264,"Y":290},{"X":266,"Y":290},{"X":268,"Y":289},{"X":270,"Y":289},{"X":271,"Y":288},{"X":271,"Y":288},{"X":271,"Y":286},{"X":272,"Y":286},{"X":272,"Y":282},{"X":275,"Y":281},{"X":277,"Y":279},{"X":278,"Y":279},{"X":283,"Y":271},{"X":284,"Y":270},{"X":284,"Y":269},{"X":284,"Y":270},{"X":283,"Y":270},{"X":278,"Y":276},{"X":275,"Y":277},{"X":272,"Y":278},{"X":272,"Y":278},{"X":272,"Y":278},{"X":271,"Y":278},{"X":269,"Y":279},{"X":269,"Y":280},{"X":268,"Y":280},{"X":268,"Y":281},{"X":267,"Y":282},{"X":264,"Y":282},{"X":260,"Y":281},{"X":258,"Y":279},{"X":257,"Y":279},{"X":255,"Y":278},{"X":254,"Y":275},{"X":250,"Y":275},{"X":250,"Y":275},{"X":250,"Y":277},{"X":247,"Y":277},{"X":247,"Y":277},{"X":246,"Y":278},{"X":244,"Y":277},{"X":244,"Y":276},{"X":245,"Y":275},{"X":246,"Y":275},{"X":246,"Y":275},{"X":248,"Y":275},{"X":249,"Y":273},{"X":249,"Y":272},{"X":248,"Y":273},{"X":247,"Y":272},{"X":244,"Y":272},{"X":244,"Y":272},{"X":243,"Y":271},{"X":243,"Y":270},{"X":244,"Y":271},{"X":243,"Y":269},{"X":243,"Y":268},{"X":243,"Y":269},{"X":242,"Y":269},{"X":242,"Y":270},{"X":237,"Y":270},{"X":236,"Y":272},{"X":235,"Y":272},{"X":234,"Y":273},{"X":233,"Y":275},{"X":231,"Y":275},{"X":228,"Y":273},{"X":228,"Y":272},{"X":227,"Y":272},{"X":227,"Y":272},{"X":228,"Y":272},{"X":228,"Y":272},{"X":228,"Y":272},{"X":229,"Y":272},{"X":233,"Y":271},{"X":229,"Y":270},{"X":226,"Y":270},{"X":226,"Y":272},{"X":225,"Y":270},{"X":224,"Y":269},{"X":225,"Y":269},{"X":226,"Y":268},{"X":227,"Y":268},{"X":227,"Y":266},{"X":225,"Y":266},{"X":223,"Y":265},{"X":223,"Y":262},{"X":225,"Y":264},{"X":225,"Y":262},{"X":227,"Y":261},{"X":227,"Y":260},{"X":229,"Y":261},{"X":231,"Y":261},{"X":232,"Y":261},{"X":232,"Y":260},{"X":233,"Y":261},{"X":234,"Y":260},{"X":234,"Y":259},{"X":235,"Y":259},{"X":236,"Y":257},{"X":236,"Y":257},{"X":236,"Y":256},{"X":240,"Y":256},{"X":243,"Y":254},{"X":244,"Y":254},{"X":246,"Y":253},{"X":248,"Y":250},{"X":249,"Y":248},{"X":250,"Y":244},{"X":251,"Y":243},{"X":253,"Y":242},{"X":250,"Y":242},{"X":248,"Y":240},{"X":250,"Y":237},{"X":251,"Y":235},{"X":250,"Y":236},{"X":249,"Y":235},{"X":248,"Y":235},{"X":248,"Y":234},{"X":249,"Y":232},{"X":248,"Y":231},{"X":243,"Y":231},{"X":242,"Y":232},{"X":242,"Y":233},{"X":242,"Y":234},{"X":240,"Y":235},{"X":238,"Y":233},{"X":238,"Y":234},{"X":236,"Y":233},{"X":236,"Y":234},{"X":236,"Y":233},{"X":236,"Y":232},{"X":238,"Y":231},{"X":240,"Y":229},{"X":244,"Y":226},{"X":244,"Y":223},{"X":245,"Y":223},{"X":245,"Y":223},{"X":248,"Y":220},{"X":249,"Y":218},{"X":250,"Y":218},{"X":254,"Y":217},{"X":255,"Y":217},{"X":254,"Y":216},{"X":256,"Y":216},{"X":257,"Y":217},{"X":259,"Y":217},{"X":265,"Y":215},{"X":266,"Y":215},{"X":266,"Y":216},{"X":270,"Y":220},{"X":270,"Y":217},{"X":268,"Y":214},{"X":268,"Y":214},{"X":271,"Y":212},{"X":271,"Y":213},{"X":273,"Y":216},{"X":276,"Y":217},{"X":277,"Y":217},{"X":278,"Y":216},{"X":277,"Y":216},{"X":275,"Y":216},{"X":272,"Y":213},{"X":270,"Y":210},{"X":272,"Y":204},{"X":276,"Y":202},{"X":271,"Y":202},{"X":270,"Y":199},{"X":271,"Y":195},{"X":275,"Y":194},{"X":275,"Y":195},{"X":276,"Y":193},{"X":275,"Y":193},{"X":275,"Y":193},{"X":275,"Y":193},{"X":273,"Y":192},{"X":275,"Y":190},{"X":276,"Y":190},{"X":276,"Y":189},{"X":276,"Y":187},{"X":276,"Y":185},{"X":275,"Y":185},{"X":273,"Y":188},{"X":272,"Y":188},{"X":271,"Y":185},{"X":270,"Y":189},{"X":269,"Y":191},{"X":269,"Y":191},{"X":267,"Y":189},{"X":267,"Y":188},{"X":267,"Y":188},{"X":268,"Y":188},{"X":268,"Y":183},{"X":267,"Y":187},{"X":266,"Y":187},{"X":264,"Y":183},{"X":264,"Y":181},{"X":259,"Y":176},{"X":260,"Y":172},{"X":261,"Y":170},{"X":262,"Y":168},{"X":264,"Y":167},{"X":264,"Y":166},{"X":265,"Y":163},{"X":266,"Y":162},{"X":266,"Y":163},{"X":267,"Y":163},{"X":267,"Y":162},{"X":267,"Y":162},{"X":267,"Y":161},{"X":268,"Y":160},{"X":270,"Y":161},{"X":271,"Y":161},{"X":271,"Y":160},{"X":270,"Y":160},{"X":270,"Y":160},{"X":271,"Y":160},{"X":271,"Y":159},{"X":269,"Y":159},{"X":267,"Y":160},{"X":264,"Y":160},{"X":264,"Y":160},{"X":262,"Y":160},{"X":261,"Y":160},{"X":261,"Y":160},{"X":261,"Y":160},{"X":261,"Y":163},{"X":260,"Y":163},{"X":258,"Y":162},{"X":257,"Y":163},{"X":256,"Y":162},{"X":256,"Y":163},{"X":256,"Y":162},{"X":256,"Y":162},{"X":255,"Y":163},{"X":256,"Y":165},{"X":253,"Y":167},{"X":251,"Y":167},{"X":251,"Y":165},{"X":250,"Y":166},{"X":249,"Y":166},{"X":248,"Y":165},{"X":248,"Y":162},{"X":247,"Y":165},{"X":246,"Y":162},{"X":245,"Y":162},{"X":244,"Y":161},{"X":244,"Y":162},{"X":244,"Y":162},{"X":244,"Y":165},{"X":246,"Y":165},{"X":245,"Y":166},{"X":246,"Y":169},{"X":245,"Y":169},{"X":242,"Y":169},{"X":240,"Y":166},{"X":237,"Y":165},{"X":236,"Y":162},{"X":236,"Y":162},{"X":234,"Y":163},{"X":233,"Y":165},{"X":234,"Y":169},{"X":235,"Y":169},{"X":235,"Y":169},{"X":236,"Y":170},{"X":235,"Y":170},{"X":234,"Y":169},{"X":234,"Y":168},{"X":229,"Y":162},{"X":228,"Y":160},{"X":229,"Y":158},{"X":231,"Y":158},{"X":232,"Y":158},{"X":232,"Y":160},{"X":233,"Y":162},{"X":233,"Y":161},{"X":232,"Y":158},{"X":232,"Y":157},{"X":233,"Y":154},{"X":236,"Y":150},{"X":236,"Y":147},{"X":237,"Y":146},{"X":238,"Y":144},{"X":240,"Y":144},{"X":240,"Y":141},{"X":239,"Y":140},{"X":239,"Y":140},{"X":239,"Y":139},{"X":239,"Y":138},{"X":237,"Y":137},{"X":237,"Y":136},{"X":235,"Y":134},{"X":236,"Y":133},{"X":236,"Y":130},{"X":235,"Y":127},{"X":236,"Y":126},{"X":237,"Y":125},{"X":238,"Y":127},{"X":243,"Y":127},{"X":240,"Y":125},{"X":238,"Y":124},{"X":237,"Y":122},{"X":237,"Y":124},{"X":238,"Y":124},{"X":237,"Y":124},{"X":236,"Y":124},{"X":236,"Y":122},{"X":237,"Y":121},{"X":236,"Y":121},{"X":236,"Y":119},{"X":236,"Y":119},{"X":235,"Y":121},{"X":236,"Y":122},{"X":236,"Y":124},{"X":235,"Y":124},{"X":235,"Y":124},{"X":234,"Y":128},{"X":233,"Y":128},{"X":233,"Y":126},{"X":232,"Y":124},{"X":232,"Y":127},{"X":229,"Y":126},{"X":229,"Y":124},{"X":229,"Y":124},{"X":229,"Y":127},{"X":228,"Y":127},{"X":229,"Y":129},{"X":227,"Y":128},{"X":226,"Y":127},{"X":227,"Y":124},{"X":228,"Y":122},{"X":229,"Y":121},{"X":229,"Y":119},{"X":233,"Y":118},{"X":233,"Y":117},{"X":235,"Y":115},{"X":234,"Y":116},{"X":233,"Y":116},{"X":232,"Y":118},{"X":228,"Y":119},{"X":226,"Y":124},{"X":225,"Y":124},{"X":225,"Y":124},{"X":225,"Y":125},{"X":225,"Y":126},{"X":225,"Y":128},{"X":227,"Y":130},{"X":227,"Y":132},{"X":226,"Y":133},{"X":225,"Y":134},{"X":224,"Y":136},{"X":224,"Y":137},{"X":224,"Y":138},{"X":224,"Y":138},{"X":224,"Y":139},{"X":222,"Y":144},{"X":222,"Y":144},{"X":222,"Y":144},{"X":223,"Y":145},{"X":222,"Y":147},{"X":220,"Y":148},{"X":217,"Y":147},{"X":217,"Y":144},{"X":220,"Y":144},{"X":220,"Y":139},{"X":220,"Y":138},{"X":221,"Y":136},{"X":221,"Y":135},{"X":224,"Y":129},{"X":222,"Y":132},{"X":221,"Y":130},{"X":221,"Y":129},{"X":223,"Y":126},{"X":221,"Y":127},{"X":221,"Y":126},{"X":223,"Y":122},{"X":222,"Y":123},{"X":221,"Y":126},{"X":220,"Y":126},{"X":221,"Y":124},{"X":222,"Y":123},{"X":222,"Y":122},{"X":223,"Y":121},{"X":224,"Y":121},{"X":223,"Y":119},{"X":224,"Y":117},{"X":223,"Y":119},{"X":222,"Y":119},{"X":223,"Y":117},{"X":223,"Y":115},{"X":223,"Y":112},{"X":224,"Y":112},{"X":225,"Y":108},{"X":229,"Y":108},{"X":227,"Y":107},{"X":226,"Y":107},{"X":226,"Y":107},{"X":226,"Y":107},{"X":225,"Y":107},{"X":226,"Y":106},{"X":227,"Y":106},{"X":228,"Y":105},{"X":229,"Y":105},{"X":227,"Y":105},{"X":226,"Y":105},{"X":227,"Y":102},{"X":228,"Y":102},{"X":228,"Y":102},{"X":229,"Y":101},{"X":232,"Y":101},{"X":233,"Y":101},{"X":232,"Y":101},{"X":229,"Y":101},{"X":233,"Y":95},{"X":231,"Y":97},{"X":229,"Y":97},{"X":228,"Y":100},{"X":227,"Y":101},{"X":227,"Y":101},{"X":225,"Y":103},{"X":224,"Y":105},{"X":221,"Y":106},{"X":221,"Y":106},{"X":220,"Y":105},{"X":220,"Y":105},{"X":217,"Y":104},{"X":215,"Y":103},{"X":215,"Y":102},{"X":216,"Y":101},{"X":217,"Y":101},{"X":221,"Y":100},{"X":222,"Y":101},{"X":224,"Y":101},{"X":222,"Y":101},{"X":220,"Y":100},{"X":218,"Y":101},{"X":217,"Y":100},{"X":212,"Y":100},{"X":211,"Y":99},{"X":213,"Y":97},{"X":215,"Y":97},{"X":216,"Y":96},{"X":217,"Y":97},{"X":218,"Y":97},{"X":218,"Y":96},{"X":218,"Y":97},{"X":220,"Y":96},{"X":220,"Y":96},{"X":218,"Y":95},{"X":218,"Y":94},{"X":221,"Y":94},{"X":221,"Y":94},{"X":222,"Y":94},{"X":222,"Y":94},{"X":221,"Y":94},{"X":221,"Y":94},{"X":221,"Y":93},{"X":217,"Y":92},{"X":218,"Y":93},{"X":220,"Y":93},{"X":218,"Y":92},{"X":220,"Y":90},{"X":221,"Y":89},{"X":221,"Y":90},{"X":222,"Y":91},{"X":225,"Y":90},{"X":223,"Y":90},{"X":222,"Y":90},{"X":222,"Y":89},{"X":222,"Y":88},{"X":221,"Y":88},{"X":221,"Y":86},{"X":222,"Y":85},{"X":223,"Y":85},{"X":225,"Y":88},{"X":226,"Y":86},{"X":224,"Y":86},{"X":224,"Y":85},{"X":223,"Y":83},{"X":222,"Y":83},{"X":223,"Y":83},{"X":223,"Y":82},{"X":223,"Y":81},{"X":223,"Y":80},{"X":225,"Y":80},{"X":225,"Y":80},{"X":227,"Y":82},{"X":227,"Y":81},{"X":226,"Y":81},{"X":225,"Y":80},{"X":222,"Y":80},{"X":222,"Y":80},{"X":223,"Y":78},{"X":225,"Y":77},{"X":226,"Y":74},{"X":225,"Y":77},{"X":224,"Y":78},{"X":223,"Y":77},{"X":224,"Y":77},{"X":224,"Y":75},{"X":221,"Y":78},{"X":220,"Y":78},{"X":220,"Y":75},{"X":221,"Y":75},{"X":220,"Y":75},{"X":221,"Y":74},{"X":220,"Y":74},{"X":220,"Y":72},{"X":221,"Y":70},{"X":221,"Y":70},{"X":222,"Y":71},{"X":222,"Y":70},{"X":223,"Y":72},{"X":223,"Y":72},{"X":224,"Y":72},{"X":225,"Y":71},{"X":224,"Y":71},{"X":223,"Y":70},{"X":223,"Y":70},{"X":223,"Y":70},{"X":222,"Y":69},{"X":222,"Y":68},{"X":221,"Y":68},{"X":221,"Y":64},{"X":223,"Y":64},{"X":223,"Y":64},{"X":222,"Y":64},{"X":221,"Y":63},{"X":221,"Y":62},{"X":221,"Y":60},{"X":223,"Y":60},{"X":223,"Y":60},{"X":223,"Y":62},{"X":224,"Y":63},{"X":224,"Y":62},{"X":225,"Y":62},{"X":225,"Y":60},{"X":224,"Y":60},{"X":224,"Y":58},{"X":225,"Y":58},{"X":225,"Y":58},{"X":225,"Y":60},{"X":227,"Y":60},{"X":227,"Y":58},{"X":232,"Y":60},{"X":232,"Y":60},{"X":228,"Y":58},{"X":228,"Y":57},{"X":228,"Y":57},{"X":229,"Y":59},{"X":232,"Y":58},{"X":233,"Y":60},{"X":234,"Y":61},{"X":234,"Y":60},{"X":232,"Y":58},{"X":233,"Y":58},{"X":233,"Y":58},{"X":231,"Y":56},{"X":229,"Y":55},{"X":228,"Y":53},{"X":228,"Y":53},{"X":227,"Y":52},{"X":227,"Y":51},{"X":229,"Y":52},{"X":229,"Y":52},{"X":232,"Y":52},{"X":232,"Y":52},{"X":231,"Y":51},{"X":232,"Y":51},{"X":231,"Y":50},{"X":232,"Y":50},{"X":231,"Y":50},{"X":231,"Y":50},{"X":229,"Y":49},{"X":229,"Y":49},{"X":228,"Y":47},{"X":228,"Y":46},{"X":231,"Y":48},{"X":233,"Y":47},{"X":233,"Y":48},{"X":234,"Y":47},{"X":237,"Y":48},{"X":236,"Y":47},{"X":237,"Y":47},{"X":235,"Y":47},{"X":234,"Y":46},{"X":234,"Y":45},{"X":234,"Y":45},{"X":233,"Y":45},{"X":234,"Y":41},{"X":236,"Y":42},{"X":235,"Y":41},{"X":235,"Y":41},{"X":235,"Y":41},{"X":235,"Y":40},{"X":236,"Y":40},{"X":237,"Y":40},{"X":236,"Y":39},{"X":234,"Y":38},{"X":234,"Y":38},{"X":236,"Y":37}]]';
var arrow_poly = '[[{"X":246,"Y":146},{"X":313,"Y":146},{"X":290,"Y":168},{"X":335,"Y":191},{"X":290,"Y":235},{"X":268,"Y":191},{"X":246,"Y":213}],[{"X":246,"Y":57},{"X":268,"Y":79},{"X":290,"Y":35},{"X":335,"Y":79},{"X":290,"Y":102},{"X":313,"Y":124},{"X":246,"Y":124}],[{"X":224,"Y":146},{"X":224,"Y":213},{"X":201,"Y":191},{"X":179,"Y":235},{"X":134,"Y":191},{"X":179,"Y":168},{"X":157,"Y":146}],[{"X":179,"Y":102},{"X":134,"Y":79},{"X":179,"Y":35},{"X":201,"Y":79},{"X":224,"Y":57},{"X":224,"Y":124},{"X":157,"Y":124}]]';
return {
"ss": deserialize_clipper_poly(gb_poly),
"cc": deserialize_clipper_poly(arrow_poly)
}
}
function get_text_polys() {
var text_polygon = '[[{"X":"28.18","Y":"205.95"},{"X":"28.18","Y":"105.07"},{"X":"48.27","Y":"105.07"},{"X":"48.28","Y":"110.23"},{"X":"54.15","Y":"107.22"},{"X":"59.69","Y":"105.39"},{"X":"65.04","Y":"104.66"},{"X":"72.07","Y":"105.08"},{"X":"78.09","Y":"106.31"},{"X":"81.57","Y":"107.68"},{"X":"84.84","Y":"110.05"},{"X":"88.03","Y":"113.63"},{"X":"90.87","Y":"118.22"},{"X":"92.71","Y":"123.12"},{"X":"94.06","Y":"129.73"},{"X":"94.70","Y":"138.25"},{"X":"94.41","Y":"147.24"},{"X":"93.31","Y":"155.42"},{"X":"91.66","Y":"161.49"},{"X":"89.46","Y":"166.25"},{"X":"86.67","Y":"170.32"},{"X":"83.75","Y":"173.13"},{"X":"80.65","Y":"174.92"},{"X":"75.51","Y":"176.56"},{"X":"69.28","Y":"177.50"},{"X":"63.74","Y":"177.55"},{"X":"57.05","Y":"176.72"},{"X":"51.42","Y":"175.15"},{"X":"48.27","Y":"173.79"},{"X":"48.27","Y":"205.95"},{"X":"48.27","Y":"205.95"},{"X":"28.18","Y":"205.95"}],[{"X":"48.28","Y":"120.42"},{"X":"48.38","Y":"164.32"},{"X":"52.31","Y":"166.53"},{"X":"56.14","Y":"167.74"},{"X":"61.35","Y":"168.35"},{"X":"65.96","Y":"167.83"},{"X":"69.49","Y":"166.59"},{"X":"72.20","Y":"164.73"},{"X":"74.29","Y":"162.19"},{"X":"76.19","Y":"157.95"},{"X":"77.71","Y":"152.00"},{"X":"78.63","Y":"144.11"},{"X":"78.66","Y":"136.61"},{"X":"77.89","Y":"129.16"},{"X":"76.59","Y":"124.08"},{"X":"74.84","Y":"120.60"},{"X":"72.55","Y":"118.04"},{"X":"69.77","Y":"116.28"},{"X":"65.91","Y":"115.07"},{"X":"60.69","Y":"114.57"},{"X":"56.85","Y":"115.18"},{"X":"53.10","Y":"116.68"},{"X":"48.91","Y":"119.57"},{"X":"48.28","Y":"120.39"},{"X":"48.28","Y":"120.42"}],[{"X":"132.15","Y":"104.65"},{"X":"139.94","Y":"105.10"},{"X":"146.11","Y":"106.30"},{"X":"151.03","Y":"108.11"},{"X":"155.15","Y":"110.57"},{"X":"158.60","Y":"113.67"},{"X":"161.35","Y":"117.41"},{"X":"163.45","Y":"121.89"},{"X":"165.10","Y":"127.80"},{"X":"166.07","Y":"135.09"},{"X":"166.22","Y":"143.93"},{"X":"165.51","Y":"151.69"},{"X":"164.06","Y":"158.12"},{"X":"162.01","Y":"163.28"},{"X":"159.40","Y":"167.47"},{"X":"156.32","Y":"170.74"},{"X":"152.52","Y":"173.40"},{"X":"147.87","Y":"175.49"},{"X":"142.07","Y":"176.99"},{"X":"134.92","Y":"177.77"},{"X":"127.42","Y":"177.67"},{"X":"120.74","Y":"176.71"},{"X":"115.29","Y":"175.07"},{"X":"110.74","Y":"172.78"},{"X":"106.95","Y":"169.86"},{"X":"103.92","Y":"166.34"},{"X":"101.48","Y":"162.04"},{"X":"99.57","Y":"156.68"},{"X":"98.29","Y":"150.05"},{"X":"97.78","Y":"141.98"},{"X":"98.18","Y":"134.19"},{"X":"99.36","Y":"127.55"},{"X":"101.22","Y":"122.01"},{"X":"103.68","Y":"117.38"},{"X":"106.77","Y":"113.52"},{"X":"110.41","Y":"110.41"},{"X":"114.84","Y":"107.89"},{"X":"120.07","Y":"106.06"},{"X":"126.27","Y":"104.95"},{"X":"132.11","Y":"104.65"},{"X":"132.15","Y":"104.65"}],[{"X":"117.86","Y":"140.93"},{"X":"118.75","Y":"153.65"},{"X":"119.63","Y":"158.05"},{"X":"121.31","Y":"161.73"},{"X":"123.57","Y":"164.71"},{"X":"126.01","Y":"166.43"},{"X":"129.14","Y":"167.44"},{"X":"133.32","Y":"167.70"},{"X":"137.17","Y":"167.11"},{"X":"140.03","Y":"165.83"},{"X":"142.14","Y":"163.92"},{"X":"143.62","Y":"161.33"},{"X":"145.05","Y":"155.97"},{"X":"145.97","Y":"148.23"},{"X":"146.12","Y":"137.89"},{"X":"145.44","Y":"129.22"},{"X":"144.13","Y":"122.91"},{"X":"142.80","Y":"119.58"},{"X":"140.91","Y":"117.26"},{"X":"138.39","Y":"115.66"},{"X":"135.07","Y":"114.75"},{"X":"131.03","Y":"114.64"},{"X":"127.21","Y":"115.38"},{"X":"124.25","Y":"116.82"},{"X":"122.07","Y":"118.86"},{"X":"120.53","Y":"121.59"},{"X":"119.03","Y":"126.93"},{"X":"118.09","Y":"134.21"},{"X":"117.86","Y":"140.81"},{"X":"117.86","Y":"140.93"}],[{"X":"172.03","Y":"177.00"},{"X":"172.03","Y":"76.33"},{"X":"191.91","Y":"76.33"},{"X":"191.91","Y":"177.00"},{"X":"191.91","Y":"177.00"},{"X":"172.03","Y":"177.00"}],[{"X":"224.60","Y":"196.88"},{"X":"221.39","Y":"198.11"},{"X":"215.61","Y":"199.00"},{"X":"208.60","Y":"199.21"},{"X":"204.09","Y":"190.40"},{"X":"211.28","Y":"190.55"},{"X":"214.82","Y":"189.98"},{"X":"217.84","Y":"188.66"},{"X":"220.35","Y":"186.54"},{"X":"222.45","Y":"183.44"},{"X":"224.33","Y":"178.55"},{"X":"225.80","Y":"173.86"},{"X":"195.43","Y":"105.07"},{"X":"215.95","Y":"105.07"},{"X":"235.40","Y":"149.04"},{"X":"252.44","Y":"105.07"},{"X":"265.17","Y":"105.14"},{"X":"233.73","Y":"186.25"},{"X":"231.07","Y":"190.77"},{"X":"228.03","Y":"194.27"},{"X":"224.70","Y":"196.82"},{"X":"224.60","Y":"196.88"}],[{"X":"292.60","Y":"192.98"},{"X":"298.73","Y":"192.56"},{"X":"303.08","Y":"191.46"},{"X":"305.98","Y":"189.91"},{"X":"307.86","Y":"187.98"},{"X":"308.96","Y":"185.54"},{"X":"309.26","Y":"183.06"},{"X":"309.20","Y":"173.81"},{"X":"304.04","Y":"175.83"},{"X":"298.03","Y":"177.13"},{"X":"291.00","Y":"177.63"},{"X":"284.29","Y":"177.05"},{"X":"278.60","Y":"175.70"},{"X":"274.88","Y":"174.11"},{"X":"271.82","Y":"171.71"},{"X":"268.90","Y":"168.11"},{"X":"266.25","Y":"163.24"},{"X":"264.52","Y":"157.97"},{"X":"263.31","Y":"150.88"},{"X":"262.81","Y":"141.60"},{"X":"263.34","Y":"132.62"},{"X":"264.61","Y":"125.23"},{"X":"266.40","Y":"119.67"},{"X":"268.74","Y":"115.31"},{"X":"271.95","Y":"111.17"},{"X":"275.11","Y":"108.42"},{"X":"278.30","Y":"106.76"},{"X":"283.81","Y":"105.35"},{"X":"290.52","Y":"104.67"},{"X":"295.16","Y":"104.90"},{"X":"299.98","Y":"105.99"},{"X":"306.08","Y":"108.50"},{"X":"309.26","Y":"110.23"},{"X":"309.26","Y":"105.06"},{"X":"329.35","Y":"105.06"},{"X":"329.23","Y":"182.37"},{"X":"328.37","Y":"186.78"},{"X":"326.76","Y":"190.49"},{"X":"324.35","Y":"193.73"},{"X":"321.15","Y":"196.44"},{"X":"316.95","Y":"198.74"},{"X":"311.55","Y":"200.55"},{"X":"304.61","Y":"201.78"},{"X":"296.23","Y":"202.25"},{"X":"286.50","Y":"201.75"},{"X":"279.10","Y":"200.55"},{"X":"271.33","Y":"198.26"},{"X":"269.50","Y":"197.28"},{"X":"268.04","Y":"186.11"},{"X":"273.14","Y":"188.62"},{"X":"280.19","Y":"191.16"},{"X":"286.81","Y":"192.48"},{"X":"292.48","Y":"192.97"},{"X":"292.60","Y":"192.98"}],[{"X":"309.26","Y":"120.42"},{"X":"308.13","Y":"119.26"},{"X":"303.52","Y":"116.46"},{"X":"299.14","Y":"114.93"},{"X":"296.63","Y":"114.57"},{"X":"291.87","Y":"115.12"},{"X":"288.19","Y":"116.39"},{"X":"285.33","Y":"118.31"},{"X":"282.99","Y":"121.03"},{"X":"281.19","Y":"124.65"},{"X":"279.81","Y":"130.01"},{"X":"278.92","Y":"137.91"},{"X":"278.88","Y":"145.11"},{"X":"279.69","Y":"152.40"},{"X":"281.18","Y":"158.05"},{"X":"283.08","Y":"162.12"},{"X":"285.18","Y":"164.65"},{"X":"287.89","Y":"166.53"},{"X":"291.41","Y":"167.79"},{"X":"296.02","Y":"168.34"},{"X":"301.23","Y":"167.79"},{"X":"305.10","Y":"166.63"},{"X":"309.03","Y":"164.44"},{"X":"309.26","Y":"164.24"},{"X":"309.26","Y":"164.24"},{"X":"309.26","Y":"120.42"}],[{"X":"369.84","Y":"104.65"},{"X":"377.62","Y":"105.10"},{"X":"383.80","Y":"106.30"},{"X":"388.72","Y":"108.11"},{"X":"392.84","Y":"110.56"},{"X":"396.29","Y":"113.67"},{"X":"399.04","Y":"117.41"},{"X":"401.13","Y":"121.89"},{"X":"402.78","Y":"127.80"},{"X":"403.75","Y":"135.08"},{"X":"403.90","Y":"143.93"},{"X":"403.19","Y":"151.69"},{"X":"401.74","Y":"158.12"},{"X":"399.70","Y":"163.28"},{"X":"397.08","Y":"167.47"},{"X":"394.00","Y":"170.74"},{"X":"390.20","Y":"173.40"},{"X":"385.55","Y":"175.49"},{"X":"379.75","Y":"176.99"},{"X":"372.60","Y":"177.77"},{"X":"365.11","Y":"177.67"},{"X":"358.43","Y":"176.71"},{"X":"352.98","Y":"175.07"},{"X":"348.43","Y":"172.78"},{"X":"344.63","Y":"169.86"},{"X":"341.60","Y":"166.34"},{"X":"339.16","Y":"162.04"},{"X":"337.26","Y":"156.68"},{"X":"335.98","Y":"150.05"},{"X":"335.46","Y":"141.97"},{"X":"335.86","Y":"134.19"},{"X":"337.04","Y":"127.55"},{"X":"338.90","Y":"122.01"},{"X":"341.37","Y":"117.38"},{"X":"344.45","Y":"113.52"},{"X":"348.10","Y":"110.41"},{"X":"352.52","Y":"107.89"},{"X":"357.76","Y":"106.06"},{"X":"363.95","Y":"104.95"},{"X":"369.79","Y":"104.65"},{"X":"369.84","Y":"104.65"}],[{"X":"355.55","Y":"140.93"},{"X":"356.44","Y":"153.65"},{"X":"357.32","Y":"158.05"},{"X":"358.99","Y":"161.73"},{"X":"361.25","Y":"164.71"},{"X":"363.70","Y":"166.43"},{"X":"366.83","Y":"167.44"},{"X":"371.01","Y":"167.70"},{"X":"374.86","Y":"167.11"},{"X":"377.72","Y":"165.83"},{"X":"379.82","Y":"163.92"},{"X":"381.31","Y":"161.33"},{"X":"382.74","Y":"155.97"},{"X":"383.65","Y":"148.23"},{"X":"383.81","Y":"137.89"},{"X":"383.12","Y":"129.22"},{"X":"381.82","Y":"122.91"},{"X":"380.48","Y":"119.58"},{"X":"378.60","Y":"117.26"},{"X":"376.07","Y":"115.66"},{"X":"372.76","Y":"114.75"},{"X":"368.72","Y":"114.64"},{"X":"364.90","Y":"115.38"},{"X":"361.94","Y":"116.82"},{"X":"359.76","Y":"118.86"},{"X":"358.22","Y":"121.60"},{"X":"356.71","Y":"126.93"},{"X":"355.77","Y":"134.21"},{"X":"355.55","Y":"140.81"},{"X":"355.55","Y":"140.93"}],[{"X":"471.82","Y":"121.68"},{"X":"471.82","Y":"177.00"},{"X":"456.69","Y":"177.00"},{"X":"456.58","Y":"122.81"},{"X":"455.77","Y":"120.25"},{"X":"454.20","Y":"118.25"},{"X":"451.80","Y":"116.74"},{"X":"448.06","Y":"115.65"},{"X":"442.84","Y":"115.25"},{"X":"438.30","Y":"116.22"},{"X":"435.19","Y":"117.70"},{"X":"432.97","Y":"119.70"},{"X":"430.36","Y":"123.35"},{"X":"429.69","Y":"124.95"},{"X":"429.69","Y":"177.00"},{"X":"409.38","Y":"177.00"},{"X":"409.38","Y":"105.07"},{"X":"429.69","Y":"105.07"},{"X":"429.70","Y":"110.91"},{"X":"434.67","Y":"107.84"},{"X":"440.16","Y":"105.83"},{"X":"445.62","Y":"104.85"},{"X":"452.21","Y":"104.70"},{"X":"457.71","Y":"105.40"},{"X":"461.98","Y":"106.78"},{"X":"465.33","Y":"108.76"},{"X":"468.28","Y":"111.73"},{"X":"470.35","Y":"115.03"},{"X":"471.52","Y":"118.58"},{"X":"471.82","Y":"121.56"},{"X":"471.82","Y":"121.68"}]]';
var text_clipping = '[[{"X":"115.54","Y":"216.41"},{"X":"113.01","Y":"217.26"},{"X":"105.79","Y":"218.58"},{"X":"96.36","Y":"219.18"},{"X":"88.73","Y":"218.69"},{"X":"82.86","Y":"217.48"},{"X":"78.40","Y":"215.73"},{"X":"74.91","Y":"213.42"},{"X":"72.12","Y":"210.49"},{"X":"69.88","Y":"206.77"},{"X":"68.13","Y":"201.83"},{"X":"66.93","Y":"195.19"},{"X":"66.45","Y":"186.51"},{"X":"67.03","Y":"179.19"},{"X":"68.36","Y":"173.03"},{"X":"70.25","Y":"168.30"},{"X":"72.58","Y":"164.82"},{"X":"75.62","Y":"161.94"},{"X":"79.35","Y":"159.71"},{"X":"84.02","Y":"158.09"},{"X":"89.93","Y":"157.11"},{"X":"96.97","Y":"156.93"},{"X":"105.18","Y":"157.69"},{"X":"114.58","Y":"159.65"},{"X":"116.44","Y":"168.59"},{"X":"110.93","Y":"166.65"},{"X":"105.50","Y":"165.51"},{"X":"98.32","Y":"165.06"},{"X":"94.16","Y":"165.58"},{"X":"90.96","Y":"166.82"},{"X":"88.62","Y":"168.68"},{"X":"86.96","Y":"171.17"},{"X":"85.31","Y":"175.67"},{"X":"84.32","Y":"181.28"},{"X":"84.15","Y":"188.62"},{"X":"84.83","Y":"196.53"},{"X":"86.18","Y":"202.53"},{"X":"87.64","Y":"205.97"},{"X":"89.52","Y":"208.29"},{"X":"92.02","Y":"209.92"},{"X":"95.18","Y":"210.85"},{"X":"99.07","Y":"210.96"},{"X":"105.48","Y":"210.28"},{"X":"111.84","Y":"208.54"},{"X":"116.32","Y":"206.45"},{"X":"116.62","Y":"206.17"},{"X":"115.55","Y":"216.31"},{"X":"115.54","Y":"216.41"}],[{"X":"120.11","Y":"219.00"},{"X":"120.11","Y":"132.31"},{"X":"137.23","Y":"132.31"},{"X":"137.23","Y":"219.00"},{"X":"137.23","Y":"219.00"},{"X":"120.11","Y":"219.00"}],[{"X":"153.34","Y":"132.13"},{"X":"156.60","Y":"132.56"},{"X":"159.17","Y":"133.77"},{"X":"161.19","Y":"135.77"},{"X":"162.61","Y":"138.40"},{"X":"163.19","Y":"141.48"},{"X":"162.87","Y":"144.75"},{"X":"161.71","Y":"147.51"},{"X":"159.79","Y":"149.80"},{"X":"157.51","Y":"151.22"},{"X":"154.46","Y":"151.96"},{"X":"151.02","Y":"151.84"},{"X":"148.34","Y":"150.92"},{"X":"146.08","Y":"149.20"},{"X":"144.28","Y":"146.63"},{"X":"143.38","Y":"143.78"},{"X":"143.37","Y":"140.64"},{"X":"144.20","Y":"137.77"},{"X":"145.94","Y":"135.15"},{"X":"148.14","Y":"133.37"},{"X":"150.80","Y":"132.38"},{"X":"153.33","Y":"132.13"},{"X":"153.34","Y":"132.13"}],[{"X":"144.58","Y":"219.00"},{"X":"144.58","Y":"157.06"},{"X":"161.88","Y":"157.06"},{"X":"161.88","Y":"219.00"},{"X":"161.88","Y":"219.00"},{"X":"144.58","Y":"219.00"}],[{"X":"168.78","Y":"243.93"},{"X":"168.78","Y":"157.06"},{"X":"186.09","Y":"157.06"},{"X":"186.19","Y":"161.44"},{"X":"191.55","Y":"158.75"},{"X":"196.41","Y":"157.22"},{"X":"201.17","Y":"156.70"},{"X":"207.60","Y":"157.21"},{"X":"212.99","Y":"158.51"},{"X":"216.03","Y":"160.11"},{"X":"219.02","Y":"162.82"},{"X":"222.00","Y":"166.95"},{"X":"223.86","Y":"171.04"},{"X":"225.25","Y":"176.56"},{"X":"226.01","Y":"184.02"},{"X":"225.94","Y":"191.67"},{"X":"225.03","Y":"199.56"},{"X":"223.55","Y":"205.37"},{"X":"221.48","Y":"209.86"},{"X":"218.90","Y":"213.53"},{"X":"216.12","Y":"216.03"},{"X":"213.05","Y":"217.58"},{"X":"207.99","Y":"218.94"},{"X":"201.87","Y":"219.54"},{"X":"195.30","Y":"219.05"},{"X":"189.90","Y":"217.79"},{"X":"186.09","Y":"216.23"},{"X":"186.09","Y":"243.93"},{"X":"186.09","Y":"243.93"},{"X":"168.78","Y":"243.93"}],[{"X":"186.09","Y":"170.27"},{"X":"186.13","Y":"208.05"},{"X":"189.79","Y":"210.09"},{"X":"193.53","Y":"211.16"},{"X":"197.86","Y":"211.53"},{"X":"201.86","Y":"210.97"},{"X":"204.91","Y":"209.73"},{"X":"207.25","Y":"207.87"},{"X":"209.01","Y":"205.27"},{"X":"210.72","Y":"200.64"},{"X":"211.90","Y":"194.30"},{"X":"212.32","Y":"186.82"},{"X":"211.80","Y":"179.19"},{"X":"210.69","Y":"174.07"},{"X":"209.11","Y":"170.68"},{"X":"207.06","Y":"168.30"},{"X":"204.40","Y":"166.63"},{"X":"200.81","Y":"165.59"},{"X":"196.18","Y":"165.25"},{"X":"192.24","Y":"166.16"},{"X":"188.91","Y":"167.87"},{"X":"186.21","Y":"169.99"},{"X":"186.09","Y":"170.26"},{"X":"186.09","Y":"170.27"}],[{"X":"231.09","Y":"243.93"},{"X":"231.09","Y":"157.06"},{"X":"248.39","Y":"157.06"},{"X":"248.50","Y":"161.44"},{"X":"253.86","Y":"158.75"},{"X":"258.72","Y":"157.22"},{"X":"263.48","Y":"156.70"},{"X":"269.91","Y":"157.21"},{"X":"275.30","Y":"158.51"},{"X":"278.34","Y":"160.11"},{"X":"281.33","Y":"162.82"},{"X":"284.31","Y":"166.96"},{"X":"286.17","Y":"171.04"},{"X":"287.56","Y":"176.57"},{"X":"288.32","Y":"184.02"},{"X":"288.25","Y":"191.67"},{"X":"287.34","Y":"199.56"},{"X":"285.86","Y":"205.37"},{"X":"283.79","Y":"209.86"},{"X":"281.21","Y":"213.53"},{"X":"278.43","Y":"216.04"},{"X":"275.35","Y":"217.58"},{"X":"270.29","Y":"218.94"},{"X":"264.18","Y":"219.54"},{"X":"257.60","Y":"219.05"},{"X":"252.21","Y":"217.78"},{"X":"248.40","Y":"216.23"},{"X":"248.40","Y":"243.93"},{"X":"248.40","Y":"243.93"},{"X":"231.09","Y":"243.93"}],[{"X":"248.39","Y":"170.27"},{"X":"248.44","Y":"208.05"},{"X":"252.10","Y":"210.09"},{"X":"255.84","Y":"211.16"},{"X":"260.17","Y":"211.53"},{"X":"264.17","Y":"210.97"},{"X":"267.22","Y":"209.73"},{"X":"269.56","Y":"207.87"},{"X":"271.32","Y":"205.27"},{"X":"273.03","Y":"200.64"},{"X":"274.21","Y":"194.30"},{"X":"274.63","Y":"186.82"},{"X":"274.12","Y":"179.19"},{"X":"273.00","Y":"174.07"},{"X":"271.42","Y":"170.68"},{"X":"269.38","Y":"168.30"},{"X":"266.72","Y":"166.64"},{"X":"263.12","Y":"165.59"},{"X":"258.49","Y":"165.25"},{"X":"254.56","Y":"166.16"},{"X":"251.23","Y":"167.86"},{"X":"248.52","Y":"169.99"},{"X":"248.40","Y":"170.26"},{"X":"248.39","Y":"170.27"}],[{"X":"302.11","Y":"132.13"},{"X":"305.37","Y":"132.56"},{"X":"307.93","Y":"133.77"},{"X":"309.95","Y":"135.77"},{"X":"311.37","Y":"138.40"},{"X":"311.95","Y":"141.48"},{"X":"311.63","Y":"144.75"},{"X":"310.47","Y":"147.51"},{"X":"308.56","Y":"149.80"},{"X":"306.27","Y":"151.22"},{"X":"303.22","Y":"151.96"},{"X":"299.79","Y":"151.84"},{"X":"297.10","Y":"150.92"},{"X":"294.85","Y":"149.20"},{"X":"293.04","Y":"146.63"},{"X":"292.14","Y":"143.78"},{"X":"292.13","Y":"140.64"},{"X":"292.97","Y":"137.77"},{"X":"294.71","Y":"135.15"},{"X":"296.90","Y":"133.37"},{"X":"299.56","Y":"132.38"},{"X":"302.10","Y":"132.13"},{"X":"302.11","Y":"132.13"}],[{"X":"293.34","Y":"219.00"},{"X":"293.34","Y":"157.06"},{"X":"310.65","Y":"157.06"},{"X":"310.65","Y":"219.00"},{"X":"310.65","Y":"219.00"},{"X":"293.34","Y":"219.00"}],[{"X":"371.24","Y":"171.37"},{"X":"371.24","Y":"219.00"},{"X":"358.21","Y":"219.00"},{"X":"358.11","Y":"172.27"},{"X":"357.35","Y":"170.01"},{"X":"355.81","Y":"168.19"},{"X":"353.32","Y":"166.83"},{"X":"349.52","Y":"165.99"},{"X":"345.63","Y":"165.91"},{"X":"341.71","Y":"166.90"},{"X":"339.11","Y":"168.36"},{"X":"336.70","Y":"171.02"},{"X":"335.06","Y":"173.87"},{"X":"334.96","Y":"219.00"},{"X":"317.48","Y":"219.00"},{"X":"317.48","Y":"157.06"},{"X":"334.96","Y":"157.06"},{"X":"335.01","Y":"162.07"},{"X":"339.49","Y":"159.34"},{"X":"344.58","Y":"157.56"},{"X":"349.77","Y":"156.78"},{"X":"355.76","Y":"156.84"},{"X":"360.47","Y":"157.70"},{"X":"364.07","Y":"159.18"},{"X":"366.81","Y":"161.26"},{"X":"369.25","Y":"164.29"},{"X":"370.67","Y":"167.42"},{"X":"371.23","Y":"170.82"},{"X":"371.24","Y":"171.27"},{"X":"371.24","Y":"171.37"}],[{"X":"401.90","Y":"232.76"},{"X":"407.58","Y":"232.33"},{"X":"411.33","Y":"231.29"},{"X":"413.88","Y":"229.75"},{"X":"415.39","Y":"227.89"},{"X":"416.16","Y":"225.48"},{"X":"416.21","Y":"216.25"},{"X":"411.46","Y":"218.08"},{"X":"405.72","Y":"219.22"},{"X":"399.44","Y":"219.51"},{"X":"393.19","Y":"218.76"},{"X":"388.30","Y":"217.32"},{"X":"385.44","Y":"215.70"},{"X":"382.67","Y":"212.97"},{"X":"380.07","Y":"208.95"},{"X":"378.24","Y":"204.52"},{"X":"376.93","Y":"198.51"},{"X":"376.28","Y":"190.44"},{"X":"376.52","Y":"182.65"},{"X":"377.58","Y":"175.38"},{"X":"379.16","Y":"170.07"},{"X":"381.22","Y":"166.08"},{"X":"384.14","Y":"162.28"},{"X":"387.11","Y":"159.77"},{"X":"390.08","Y":"158.35"},{"X":"395.48","Y":"157.12"},{"X":"401.76","Y":"156.70"},{"X":"406.66","Y":"157.40"},{"X":"412.02","Y":"159.31"},{"X":"416.24","Y":"161.51"},{"X":"416.24","Y":"157.06"},{"X":"433.55","Y":"157.06"},{"X":"433.43","Y":"223.84"},{"X":"432.54","Y":"227.93"},{"X":"430.90","Y":"231.30"},{"X":"428.49","Y":"234.16"},{"X":"425.23","Y":"236.55"},{"X":"420.86","Y":"238.51"},{"X":"415.19","Y":"239.93"},{"X":"407.89","Y":"240.69"},{"X":"399.04","Y":"240.53"},{"X":"391.61","Y":"239.58"},{"X":"384.09","Y":"237.51"},{"X":"382.01","Y":"236.48"},{"X":"380.74","Y":"226.84"},{"X":"385.59","Y":"229.19"},{"X":"391.82","Y":"231.36"},{"X":"398.16","Y":"232.49"},{"X":"401.75","Y":"232.75"},{"X":"401.90","Y":"232.76"}],[{"X":"416.25","Y":"170.27"},{"X":"414.97","Y":"169.05"},{"X":"410.96","Y":"166.71"},{"X":"406.83","Y":"165.39"},{"X":"404.44","Y":"165.28"},{"X":"400.31","Y":"165.96"},{"X":"397.15","Y":"167.34"},{"X":"394.75","Y":"169.35"},{"X":"392.82","Y":"172.20"},{"X":"391.40","Y":"176.14"},{"X":"390.35","Y":"182.50"},{"X":"390.04","Y":"190.14"},{"X":"390.67","Y":"197.15"},{"X":"391.97","Y":"202.39"},{"X":"393.71","Y":"206.20"},{"X":"395.76","Y":"208.58"},{"X":"398.42","Y":"210.25"},{"X":"401.86","Y":"211.27"},{"X":"406.04","Y":"211.51"},{"X":"410.92","Y":"210.69"},{"X":"414.49","Y":"209.16"},{"X":"416.25","Y":"208.01"},{"X":"416.25","Y":"170.27"},{"X":"416.25","Y":"170.27"}]]';
return {
"ss": deserialize_clipper_poly(text_polygon),
"cc": deserialize_clipper_poly(text_clipping)
};
}
function get_rectangle_polys() {
var rectangle1 = '[[{"X":155,"Y":61.67},{"X":155,"Y":212.7},{"X":288.98,"Y":212.7},{"X":288.98,"Y":61.67},{"X":173.01999999999998,"Y":61.67},{"X":155,"Y":61.67}],[{"X":274.37,"Y":190.77},{"X":171.24,"Y":190.77},{"X":171.24,"Y":81.16},{"X":274.37,"Y":81.16},{"X":274.37,"Y":81.16},{"X":274.37,"Y":190.77}]]';
var rectangle2 = '[[{"X":217.69,"Y":126.14},{"X":217.69,"Y":277.17},{"X":351.66999999999996,"Y":277.17},{"X":351.66999999999996,"Y":126.14},{"X":253.71,"Y":126.14},{"X":217.69,"Y":126.14}],[{"X":337.05,"Y":255.25},{"X":233.93,"Y":255.25},{"X":233.93,"Y":145.63},{"X":337.05,"Y":145.63},{"X":337.05,"Y":145.63},{"X":337.05,"Y":255.25}]]';
return {
"ss": deserialize_clipper_poly(rectangle1),
"cc": deserialize_clipper_poly(rectangle2)
};
}
function get_same_self_intersecting_polys() {
var rectangle1 = '[[{"X":172,"Y":90},{"X":222,"Y":90},{"X":222,"Y":240},{"X":322,"Y":240},{"X":322,"Y":140},{"X":172,"Y":140}]]';
var rectangle2 = '[[{"X":172,"Y":90},{"X":222,"Y":90},{"X":222,"Y":240},{"X":322,"Y":240},{"X":322,"Y":140},{"X":172,"Y":140}]]';
return {
"ss": deserialize_clipper_poly(rectangle1),
"cc": deserialize_clipper_poly(rectangle2)
};
}
function get_star_and_rect() {
var star = '[[{"X":147.47,"Y":312.74},{"X":247.07,"Y":33.510000000000005},{"X":337.66,"Y":312.04},{"X":86.36,"Y":122.7},{"X":404.07,"Y":123.57},{"X":148.11,"Y":312.27},{"X":147.47,"Y":312.74}]]';
var rectangle1 = '[[{"X":336.36,"Y":261.38},{"X":155.25,"Y":260.49},{"X":155.25,"Y":84.06},{"X":336.36,"Y":84.06},{"X":336.36,"Y":261.38},{"X":336.36,"Y":261.38}]]';
return {
"ss": deserialize_clipper_poly(star),
"cc": deserialize_clipper_poly(rectangle1)
};
}
function get_spiral_and_rects() {
var spiral = '[[{"X":222.02,"Y":294.08},{"X":202.56,"Y":292.96},{"X":183.69,"Y":289.52},{"X":165.670002,"Y":283.86},{"X":148.5,"Y":275.99},{"X":132.45999999999998,"Y":266.02},{"X":117.8,"Y":254.11},{"X":104.75,"Y":240.45},{"X":93.72,"Y":225.49},{"X":84.85,"Y":209.5},{"X":78.12,"Y":192.5},{"X":73.73,"Y":175.06},{"X":71.6,"Y":156.89},{"X":71.83,"Y":139.51},{"X":74.33,"Y":123.52},{"X":79.1,"Y":108.05},{"X":86.16,"Y":93.15},{"X":95.270001,"Y":79.41},{"X":106.41,"Y":66.85},{"X":119.19,"Y":55.97},{"X":133.6,"Y":46.79},{"X":149.15,"Y":39.7},{"X":165.51999999999998,"Y":34.82},{"X":182.41,"Y":32.2300004},{"X":199.5,"Y":31.97},{"X":214.94,"Y":34.03},{"X":229.61,"Y":38.33},{"X":243.45,"Y":44.81},{"X":256.13,"Y":53.36},{"X":267.330004,"Y":63.75},{"X":276.63,"Y":75.5},{"X":283.960004,"Y":88.57},{"X":289.03,"Y":102.35},{"X":291.840003,"Y":116.77},{"X":292.340003,"Y":131.44},{"X":290.53999999999996,"Y":144.5},{"X":286.49,"Y":157.05},{"X":280.16999999999996,"Y":168.96},{"X":271.9,"Y":179.61},{"X":261.710004,"Y":188.89},{"X":250.1,"Y":196.31},{"X":237.4,"Y":201.68},{"X":223.99,"Y":204.85},{"X":209.93,"Y":205.76},{"X":197.13,"Y":204.33},{"X":185.11,"Y":200.63},{"X":173.99,"Y":194.74},{"X":164.19,"Y":186.85},{"X":156.22,"Y":177.51},{"X":150.18,"Y":166.82},{"X":146.41,"Y":155.44},{"X":144.89,"Y":143.56},{"X":145.63,"Y":132.5},{"X":148.59,"Y":122.14},{"X":153.8,"Y":112.36},{"X":160.93,"Y":103.88},{"X":169.89,"Y":96.86},{"X":180.09,"Y":91.81},{"X":191.1,"Y":88.95},{"X":202.47,"Y":88.37},{"X":212.8,"Y":90.1},{"X":222.22,"Y":93.95},{"X":230.55,"Y":99.81},{"X":237.37,"Y":107.36},{"X":242.28,"Y":116.28},{"X":244.92,"Y":125.8},{"X":245.3,"Y":135.670002},{"X":243.42,"Y":144.44},{"X":239.27,"Y":152.74},{"X":233.18,"Y":159.73},{"X":225.31,"Y":165.19},{"X":216.34,"Y":168.54},{"X":206.82,"Y":169.6},{"X":198.23,"Y":168.4},{"X":190.26,"Y":164.97},{"X":183.5,"Y":159.55},{"X":178.57999999999998,"Y":152.77},{"X":175.66,"Y":144.92},{"X":175,"Y":136.87},{"X":176.64,"Y":132.74},{"X":180.14,"Y":130},{"X":184.55,"Y":129.420002},{"X":188.66,"Y":131.13},{"X":191.34,"Y":134.670002},{"X":192.98,"Y":143.46},{"X":196.15,"Y":148.15},{"X":201.12,"Y":151.43},{"X":206.97,"Y":152.6},{"X":214.06,"Y":151.54},{"X":220.43,"Y":148.24},{"X":225.15,"Y":143.26},{"X":227.84,"Y":137.26},{"X":228.34,"Y":130.41},{"X":226.58,"Y":122.84},{"X":222.68,"Y":116.12},{"X":216.8,"Y":110.59},{"X":209.61,"Y":106.92},{"X":201.39,"Y":105.35},{"X":191.84,"Y":106.08},{"X":182.76,"Y":109.12},{"X":174.94,"Y":114.11},{"X":168.57999999999998,"Y":120.86},{"X":164.26,"Y":128.730002},{"X":162.09,"Y":137.44},{"X":162.230002,"Y":147.31},{"X":164.64,"Y":157.2},{"X":169.35,"Y":166.56},{"X":176.03,"Y":174.64},{"X":184.51999999999998,"Y":181.28},{"X":194.25,"Y":185.91},{"X":204.75,"Y":188.36},{"X":216.73,"Y":188.57},{"X":228.83,"Y":186.5},{"X":240.34,"Y":182.2},{"X":250.83,"Y":175.81},{"X":259.9,"Y":167.54},{"X":267.03,"Y":157.91},{"X":272.02,"Y":147.35},{"X":274.830004,"Y":136.01},{"X":275.340003,"Y":123.74},{"X":273.580004,"Y":110.68},{"X":269.580004,"Y":98.12},{"X":263.3,"Y":86.19},{"X":255.05,"Y":75.52},{"X":244.91,"Y":66.18},{"X":233.35,"Y":58.67},{"X":220.7,"Y":53.21},{"X":207.02,"Y":49.86},{"X":192.67,"Y":48.8},{"X":176.82999999999998,"Y":50},{"X":161.34,"Y":53.51},{"X":146.540002,"Y":59.27},{"X":132.76,"Y":67.17},{"X":120.53999999999999,"Y":76.85},{"X":109.92,"Y":88.25},{"X":101.32,"Y":100.89},{"X":94.75999999999999,"Y":114.7},{"X":90.52,"Y":129.07},{"X":88.57,"Y":143.93},{"X":88.92,"Y":160.71},{"X":91.63,"Y":177.58},{"X":96.66,"Y":193.91},{"X":103.9,"Y":209.38},{"X":113.37,"Y":223.97},{"X":124.72,"Y":237.14},{"X":137.93,"Y":248.89},{"X":152.59,"Y":258.78999999999996},{"X":168.44,"Y":266.65},{"X":185.18,"Y":272.34},{"X":202.83,"Y":275.85},{"X":221.07,"Y":277.07},{"X":241.43,"Y":276},{"X":261.24,"Y":272.63},{"X":280.52,"Y":266.98},{"X":299,"Y":259.12},{"X":316.43,"Y":249.14},{"X":332.56,"Y":237.17},{"X":346.94,"Y":223.57},{"X":359.59,"Y":208.35},{"X":370.15,"Y":191.97},{"X":378.51,"Y":174.7},{"X":384.69,"Y":156.54},{"X":388.59,"Y":137.75},{"X":390.64,"Y":115.98},{"X":393.21,"Y":112.35},{"X":397.26,"Y":110.5},{"X":401.4,"Y":110.83},{"X":405.08,"Y":113.33},{"X":407,"Y":117.34},{"X":406.15,"Y":134.39},{"X":402.81,"Y":154.2},{"X":397.18,"Y":173.48},{"X":389.22,"Y":192.25},{"X":379.12,"Y":209.96},{"X":366.88,"Y":226.64},{"X":352.8,"Y":241.8},{"X":336.88,"Y":255.47},{"X":319.51,"Y":267.26},{"X":300.93,"Y":277.02},{"X":281.38,"Y":284.66},{"X":260.81,"Y":290.13},{"X":239.75,"Y":293.26},{"X":222.07,"Y":294.08},{"X":222.02,"Y":294.08}]]';
var rectangle1 = '[[{"X":210.91,"Y":210.89},{"X":107.65,"Y":210.65},{"X":107.65,"Y":27.58},{"X":210.91,"Y":27.75},{"X":210.91,"Y":36.45},{"X":210.91,"Y":210.89}],[{"X":304.24,"Y":323.13},{"X":210.91,"Y":322.86},{"X":210.91,"Y":70.9},{"X":304.24,"Y":70.91},{"X":304.24,"Y":148.61},{"X":304.24,"Y":323.13}],[{"X":407.5,"Y":254.59},{"X":304.24,"Y":254.35},{"X":304.24,"Y":71.28},{"X":407.5,"Y":71.28},{"X":407.5,"Y":71.28},{"X":407.5,"Y":254.59}]]';
return {
"ss": deserialize_clipper_poly(spiral),
"cc": deserialize_clipper_poly(rectangle1)
};
}
function get_rounded_grid_and_star() {
var rounded_grid = '[[{"X":346.2,"Y":66.31},{"X":332.04,"Y":53.81},{"X":316.43,"Y":43.18},{"X":299.87,"Y":34.73995},{"X":282.39,"Y":28.44},{"X":263.95,"Y":24.33},{"X":245.15,"Y":22.56002},{"X":226.27,"Y":23.13},{"X":207.6,"Y":26.04},{"X":189.74,"Y":31.18},{"X":172.6702,"Y":38.53},{"X":156.65,"Y":47.95},{"X":141.69,"Y":59.49},{"X":128.2902,"Y":72.8},{"X":116.65,"Y":87.67},{"X":107.11,"Y":103.62},{"X":99.64,"Y":120.65},{"X":94.37,"Y":138.47},{"X":91.33,"Y":157.11},{"X":90.63,"Y":175.99},{"X":92.2599,"Y":194.8},{"X":96.2401,"Y":213.27},{"X":102.42,"Y":230.8},{"X":110.74,"Y":247.42},{"X":121.26,"Y":263.1},{"X":133.6702,"Y":277.35},{"X":147.74,"Y":289.95},{"X":163.2698,"Y":300.69},{"X":179.77,"Y":309.25},{"X":197.21,"Y":315.68},{"X":215.62,"Y":319.92},{"X":234.41,"Y":321.81},{"X":253.29,"Y":321.38},{"X":271.98,"Y":318.6},{"X":289.87,"Y":313.58},{"X":307,"Y":306.36},{"X":323.09,"Y":297.05},{"X":338.12,"Y":285.62},{"X":351.62,"Y":272.4},{"X":363.37,"Y":257.61},{"X":373.02,"Y":241.73},{"X":380.61,"Y":224.76},{"X":386,"Y":206.97},{"X":389.18,"Y":188.35},{"X":390.01,"Y":169.48},{"X":388.5,"Y":150.65},{"X":384.65,"Y":132.16},{"X":378.61,"Y":114.59},{"X":370.4,"Y":97.91},{"X":359.99,"Y":82.15},{"X":347.69,"Y":67.82},{"X":346.21,"Y":66.32},{"X":346.2,"Y":66.31}],[{"X":375.03,"Y":172.21},{"X":373.83,"Y":190.15},{"X":370.54,"Y":206.57},{"X":362.32,"Y":203.86},{"X":365.47,"Y":187.07},{"X":366.32,"Y":169.7},{"X":364.79,"Y":152.38},{"X":360.96,"Y":135.73},{"X":354.9,"Y":119.76},{"X":346.72,"Y":104.76},{"X":336.39,"Y":90.77},{"X":324.26,"Y":78.32},{"X":320.42,"Y":74.77},{"X":325.57,"Y":67.97},{"X":338.69,"Y":80.27},{"X":350.08,"Y":94.19},{"X":359.52,"Y":109.5},{"X":366.74,"Y":125.65},{"X":371.75,"Y":142.61},{"X":374.49,"Y":160.09},{"X":375.03,"Y":172.07},{"X":375.03,"Y":172.21}],[{"X":129.2698,"Y":172.21},{"X":130.44,"Y":156.06},{"X":133.9598,"Y":140.26},{"X":139.75,"Y":125.15},{"X":147.69,"Y":111.05},{"X":157.6,"Y":98.25},{"X":169.15,"Y":87.09},{"X":174.15,"Y":94.2},{"X":163.0798,"Y":105.17},{"X":153.78,"Y":117.67},{"X":146.4802,"Y":131.44},{"X":141.37,"Y":146.17},{"X":138.57,"Y":161.5},{"X":138.13,"Y":177.08},{"X":140.05,"Y":192.54},{"X":140.87,"Y":196.58},{"X":132.61,"Y":199.24},{"X":129.82,"Y":183.3},{"X":129.2698,"Y":172.22},{"X":129.2698,"Y":172.21}],[{"X":327.6,"Y":172.21},{"X":326.42,"Y":186.54},{"X":325.15,"Y":191.85},{"X":317.08,"Y":189.04},{"X":318.84,"Y":175.67},{"X":318.28,"Y":162.2},{"X":315.43,"Y":149.02},{"X":310.34,"Y":136.54},{"X":303.19,"Y":125.11},{"X":293.99,"Y":114.85},{"X":292.48,"Y":113.21},{"X":297.61,"Y":106.36},{"X":307.64,"Y":116.67},{"X":315.86,"Y":128.4802},{"X":322.02,"Y":141.48},{"X":325.96,"Y":155.31},{"X":327.56,"Y":169.6},{"X":327.6,"Y":172},{"X":327.6,"Y":172.21}],[{"X":153.0198,"Y":172.21},{"X":154.19,"Y":157.87},{"X":157.7098,"Y":143.92},{"X":163.49,"Y":130.75},{"X":171.35,"Y":118.7},{"X":181.07,"Y":108.1},{"X":183.26,"Y":106.49},{"X":188.11,"Y":113.5},{"X":178.65,"Y":123.52},{"X":171.2098,"Y":134.7698},{"X":165.8,"Y":147.12},{"X":162.61,"Y":160.22},{"X":161.7098,"Y":173.67},{"X":163.13,"Y":187.08},{"X":163.36,"Y":189.28},{"X":155.22,"Y":191.74},{"X":153.18,"Y":177.51},{"X":153.0198,"Y":172.41},{"X":153.0198,"Y":172.21}],[{"X":303.92,"Y":172.21},{"X":302.73,"Y":184.43},{"X":294.39,"Y":181.76},{"X":295.2104,"Y":170.41},{"X":293.6597,"Y":159.14},{"X":289.8,"Y":148.43},{"X":283.81,"Y":138.76},{"X":278.44,"Y":132.51},{"X":283.57,"Y":125.63},{"X":291.73,"Y":134.82},{"X":297.98,"Y":145.39},{"X":302.07,"Y":156.97},{"X":303.84,"Y":169.12},{"X":303.92,"Y":172.12},{"X":303.92,"Y":172.21}],[{"X":200.38,"Y":172.21},{"X":201.53,"Y":162.7},{"X":204.93,"Y":153.75},{"X":210.37,"Y":145.87},{"X":211.36,"Y":145.15},{"X":216.39,"Y":152.18},{"X":211.93,"Y":159.27},{"X":209.51,"Y":167.29},{"X":209.16,"Y":174.43},{"X":200.68,"Y":177.07},{"X":200.38,"Y":172.28},{"X":200.38,"Y":172.21}],[{"X":279.9196,"Y":177.17},{"X":271.4,"Y":174.36},{"X":270.87,"Y":166.01},{"X":268.12,"Y":158.1},{"X":264.19,"Y":152.1},{"X":269.5,"Y":145.05},{"X":275.1597,"Y":152.78},{"X":278.81,"Y":161.64},{"X":280.22,"Y":171.11},{"X":279.93,"Y":177.09},{"X":279.9196,"Y":177.17}],[{"X":251.65,"Y":183.77},{"X":247.81,"Y":186.59},{"X":247.94,"Y":182.57},{"X":251.37,"Y":183.68},{"X":251.65,"Y":183.77}],[{"X":252.45,"Y":168.26},{"X":254.89,"Y":165.21},{"X":256.24,"Y":169.49},{"X":252.54,"Y":168.29},{"X":252.45,"Y":168.26}],[{"X":240.31,"Y":159.45},{"X":238.03,"Y":156.14},{"X":242.64,"Y":156.24},{"X":240.35,"Y":159.39},{"X":240.31,"Y":159.45}],[{"X":228.17,"Y":168.26},{"X":224.41,"Y":169.28},{"X":225.81,"Y":165.03},{"X":228.11,"Y":168.18},{"X":228.17,"Y":168.26}],[{"X":232.81,"Y":182.52},{"X":232.69,"Y":186.53},{"X":229.1,"Y":183.73},{"X":232.52,"Y":182.62},{"X":232.81,"Y":182.52}],[{"X":247.81,"Y":202.54},{"X":255.59,"Y":199.43},{"X":262.26,"Y":194.37},{"X":266.99,"Y":188.75},{"X":275.13,"Y":191.69},{"X":269.4604,"Y":199.41},{"X":262.13,"Y":205.57},{"X":253.54,"Y":209.81},{"X":247.81,"Y":211.35},{"X":247.81,"Y":211.35},{"X":247.81,"Y":202.54}],[{"X":252.07,"Y":143.27},{"X":243.96,"Y":141.17},{"X":235.59,"Y":141.32},{"X":228.44,"Y":143.14},{"X":223.38,"Y":136.11},{"X":232.48,"Y":133.12},{"X":242.03,"Y":132.38},{"X":251.47,"Y":133.94},{"X":257.2,"Y":136.21},{"X":252.09,"Y":143.25},{"X":252.07,"Y":143.27}],[{"X":213.83,"Y":188.68},{"X":219.16,"Y":195.14},{"X":226,"Y":199.96},{"X":232.81,"Y":202.54},{"X":232.71,"Y":211.33},{"X":223.6,"Y":208.4},{"X":215.45,"Y":203.37},{"X":208.72,"Y":196.55},{"X":205.5,"Y":191.38},{"X":213.77,"Y":188.7},{"X":213.83,"Y":188.68}],[{"X":232.81,"Y":226.54},{"X":232.63,"Y":235.34},{"X":220.63,"Y":232.69},{"X":209.38,"Y":227.76},{"X":199.29,"Y":220.77},{"X":190.72,"Y":211.98},{"X":183.98,"Y":201.71},{"X":182.64,"Y":198.8},{"X":190.9,"Y":196.16},{"X":196.92,"Y":205.81},{"X":204.8,"Y":214.02},{"X":214.19,"Y":220.45},{"X":224.71,"Y":224.8},{"X":232.61,"Y":226.52},{"X":232.81,"Y":226.54}],[{"X":247.81,"Y":226.54},{"X":258.86,"Y":223.83},{"X":269.11,"Y":218.89},{"X":278.13,"Y":211.95},{"X":285.53,"Y":203.31},{"X":289.8,"Y":196.15},{"X":298.05,"Y":198.84},{"X":291.8403,"Y":209.44},{"X":283.7104,"Y":218.65},{"X":273.98,"Y":226.14},{"X":262.99,"Y":231.62},{"X":251.15,"Y":234.87},{"X":247.81,"Y":235.36},{"X":247.81,"Y":235.36},{"X":247.81,"Y":226.54}],[{"X":266.2,"Y":123.84},{"X":255.67,"Y":119.53},{"X":244.47,"Y":117.5},{"X":233.1,"Y":117.82},{"X":222.03,"Y":120.47},{"X":214.38,"Y":123.79},{"X":209.48,"Y":116.59},{"X":220.74,"Y":111.68},{"X":232.73,"Y":109.05},{"X":245.01,"Y":108.77},{"X":257.11,"Y":110.86},{"X":268.5804,"Y":115.25},{"X":271.2896,"Y":116.84},{"X":266.35,"Y":123.63},{"X":266.2,"Y":123.84}],[{"X":202.29,"Y":132.6702},{"X":194.93,"Y":141.35},{"X":189.51,"Y":151.35},{"X":186.28,"Y":162.26},{"X":185.4,"Y":173.61},{"X":186.15,"Y":181.89},{"X":177.9,"Y":184.53},{"X":176.7,"Y":172.31},{"X":177.86,"Y":160.08},{"X":181.36,"Y":148.31},{"X":187.07,"Y":137.44},{"X":194.76,"Y":127.86},{"X":197.29,"Y":125.8},{"X":202.24,"Y":132.6},{"X":202.29,"Y":132.6702}],[{"X":168.2,"Y":203.48},{"X":174.63,"Y":215.34},{"X":182.98,"Y":225.92},{"X":193.01,"Y":234.94},{"X":204.42,"Y":242.12},{"X":216.89,"Y":247.24},{"X":230.06,"Y":250.14},{"X":232.81,"Y":250.45},{"X":232.66,"Y":259.23},{"X":218.49,"Y":256.8},{"X":204.91,"Y":252.05},{"X":192.3,"Y":245.13},{"X":180.99,"Y":236.24},{"X":171.2902,"Y":225.63},{"X":163.44,"Y":213.57},{"X":160.07,"Y":206.12},{"X":168.06,"Y":203.53},{"X":168.2,"Y":203.48}],[{"X":247.81,"Y":250.45},{"X":261.07,"Y":248.02},{"X":273.72,"Y":243.35},{"X":285.37,"Y":236.57},{"X":295.7104,"Y":227.91},{"X":304.42,"Y":217.62},{"X":311.26,"Y":206},{"X":312.63,"Y":203.56},{"X":320.65,"Y":206.36},{"X":313.94,"Y":219.08},{"X":305.24,"Y":230.53},{"X":294.7896,"Y":240.41},{"X":282.86,"Y":248.46},{"X":269.78,"Y":254.44},{"X":255.89,"Y":258.1696},{"X":247.81,"Y":259.24},{"X":247.81,"Y":259.24},{"X":247.81,"Y":250.45}],[{"X":280.24,"Y":104.53},{"X":268.0903,"Y":98.68},{"X":255.12,"Y":95},{"X":241.71,"Y":93.61},{"X":228.26,"Y":94.52},{"X":215.16,"Y":97.73},{"X":202.81,"Y":103.15},{"X":200.26,"Y":104.37},{"X":195.31,"Y":97.37},{"X":208.19,"Y":90.97},{"X":221.96,"Y":86.79},{"X":236.22,"Y":84.94},{"X":250.6,"Y":85.45},{"X":264.69,"Y":88.31},{"X":278.12,"Y":93.47},{"X":285.3304,"Y":97.52},{"X":280.4,"Y":104.31},{"X":280.24,"Y":104.53}],[{"X":240.31,"Y":69.85},{"X":224.77,"Y":71.03},{"X":209.88,"Y":74.47},{"X":195.4,"Y":80.25},{"X":186.27,"Y":85.13},{"X":181.44,"Y":78.15},{"X":195.74,"Y":70.57},{"X":211,"Y":65.16},{"X":226.88,"Y":62.04},{"X":243.04,"Y":61.27},{"X":259.15,"Y":62.84},{"X":274.86,"Y":66.7401},{"X":289.8304,"Y":72.9},{"X":299.23,"Y":78.4},{"X":294.06,"Y":85.16},{"X":280.23,"Y":77.97},{"X":265.47,"Y":72.98},{"X":250.12,"Y":70.31},{"X":240.53,"Y":69.85},{"X":240.31,"Y":69.85}],[{"X":145.5798,"Y":210.82},{"X":152.56,"Y":224.76},{"X":161.57,"Y":237.47},{"X":172.4,"Y":248.69},{"X":184.79,"Y":258.14},{"X":198.47,"Y":265.6},{"X":213.13,"Y":270.89},{"X":228.42,"Y":273.88},{"X":232.81,"Y":274.29},{"X":232.64,"Y":282.91},{"X":216.62,"Y":280.63},{"X":201.1,"Y":276.03},{"X":186.42,"Y":269.2},{"X":172.89,"Y":260.32},{"X":160.7902,"Y":249.58},{"X":150.36,"Y":237.2},{"X":141.8298,"Y":223.44},{"X":137.4202,"Y":213.47},{"X":145.41,"Y":210.88},{"X":145.5798,"Y":210.82}],[{"X":247.81,"Y":274.29},{"X":263.22,"Y":271.97},{"X":277.81,"Y":267.44},{"X":291.82,"Y":260.61},{"X":304.63,"Y":251.73},{"X":315.96,"Y":241.02},{"X":325.54,"Y":228.73},{"X":333.15,"Y":215.13},{"X":335.12,"Y":210.85},{"X":343.34,"Y":213.56},{"X":336.21,"Y":228.09},{"X":327.03,"Y":241.42},{"X":316.03,"Y":253.29},{"X":303.43,"Y":263.45},{"X":289.49,"Y":271.68},{"X":274.5,"Y":277.79},{"X":258.78,"Y":281.63},{"X":247.81,"Y":282.92},{"X":247.81,"Y":282.92},{"X":247.81,"Y":274.29}],[{"X":339.67,"Y":196.56},{"X":342.21,"Y":181.18},{"X":342.39,"Y":165.6},{"X":340.21,"Y":150.16},{"X":335.7,"Y":135.25},{"X":328.96,"Y":121.19},{"X":320.17,"Y":108.32},{"X":309.54,"Y":96.93},{"X":306.51,"Y":93.91},{"X":311.67,"Y":87.25},{"X":323.27,"Y":98.54},{"X":333.13,"Y":111.37},{"X":341.03,"Y":125.5},{"X":346.77,"Y":140.63},{"X":350.23,"Y":156.45},{"X":351.35,"Y":172.59},{"X":350.12,"Y":188.73},{"X":347.95,"Y":199.24},{"X":339.68,"Y":196.56},{"X":339.67,"Y":196.56}],[{"X":313.32,"Y":59.03},{"X":307.96,"Y":65.9601},{"X":292.9604,"Y":57.76},{"X":277,"Y":51.68},{"X":260.35,"Y":47.83},{"X":243.33,"Y":46.27},{"X":225.96,"Y":47.04},{"X":209.16,"Y":50.13},{"X":192.93,"Y":55.47},{"X":177.58,"Y":62.97},{"X":172.2698,"Y":65.87},{"X":167.5,"Y":58.9},{"X":182.96,"Y":50.31},{"X":199.42,"Y":43.83},{"X":216.59,"Y":39.58},{"X":234.17,"Y":37.62005},{"X":252.15,"Y":38},{"X":269.63,"Y":40.7},{"X":286.6,"Y":45.68},{"X":302.76,"Y":52.86},{"X":313.12,"Y":58.91},{"X":313.32,"Y":59.03}],[{"X":155.18,"Y":67.87},{"X":160.1,"Y":75.1},{"X":147.49,"Y":87.07},{"X":136.63,"Y":100.65},{"X":127.73,"Y":115.58},{"X":121.08,"Y":131.32},{"X":116.64,"Y":147.82},{"X":114.48,"Y":164.77},{"X":114.66,"Y":182.16},{"X":117.15,"Y":199.06},{"X":118.19,"Y":203.94},{"X":110.01,"Y":206.46},{"X":106.64,"Y":189.1},{"X":105.59,"Y":171.14},{"X":106.92,"Y":153.21},{"X":110.56,"Y":135.9},{"X":116.45,"Y":119.22},{"X":124.48,"Y":103.46},{"X":134.7,"Y":88.66},{"X":146.78,"Y":75.33},{"X":155.07,"Y":67.9601},{"X":155.18,"Y":67.87}],[{"X":114.68,"Y":220.85},{"X":123.06,"Y":218.44},{"X":130.4202,"Y":233.86},{"X":139.99,"Y":248.38},{"X":151.45,"Y":261.4604},{"X":164.59,"Y":272.84},{"X":179.16,"Y":282.33},{"X":194.62,"Y":289.61},{"X":210.92,"Y":294.71},{"X":227.77,"Y":297.55},{"X":232.81,"Y":297.95},{"X":232.52,"Y":306.7},{"X":214.97,"Y":304.53},{"X":197.86,"Y":300.07},{"X":181.48,"Y":293.39},{"X":166.12,"Y":284.61},{"X":151.82,"Y":273.7},{"X":139.0798,"Y":261.01},{"X":128.14,"Y":246.73},{"X":119.31,"Y":231.41},{"X":114.72,"Y":220.97},{"X":114.68,"Y":220.85}],[{"X":247.81,"Y":306.71},{"X":248.04,"Y":297.93},{"X":264.99,"Y":295.74},{"X":281.48,"Y":291.27},{"X":297.2,"Y":284.59},{"X":311.88,"Y":275.84},{"X":325.47,"Y":264.99},{"X":337.44,"Y":252.39},{"X":347.59,"Y":238.27},{"X":355.57,"Y":223.16},{"X":357.93,"Y":218.25},{"X":365.83,"Y":221.11},{"X":358.32,"Y":237.13},{"X":348.6,"Y":252.26},{"X":336.95,"Y":265.97},{"X":323.6,"Y":278.02},{"X":308.77,"Y":288.19},{"X":292.99,"Y":296.19},{"X":276.3,"Y":302.04},{"X":258.98,"Y":305.63},{"X":247.94,"Y":306.71},{"X":247.81,"Y":306.71}]]';
var star = '[[{"X":240.31,"Y":12.26},{"X":292.45,"Y":117.59},{"X":408.23,"Y":134.69},{"X":324.43,"Y":216.63},{"X":344.16,"Y":332.1},{"X":240.06,"Y":277.63},{"X":136.4,"Y":332},{"X":155.99,"Y":216.19},{"X":72.33,"Y":134.4202},{"X":188.37,"Y":117.5},{"X":240.28,"Y":12.30999},{"X":240.31,"Y":12.26}]]';
return {
"ss": deserialize_clipper_poly(rounded_grid),
"cc": deserialize_clipper_poly(star)
};
}
function get_glyph_and_grid() {
var glyph = '[[{"X":105.65,"Y":51.37},{"X":105.65,"Y":295.26},{"X":395.09,"Y":295.26},{"X":395.01,"Y":51.37},{"X":108.51,"Y":51.37},{"X":105.65,"Y":51.37}],[{"X":380.09,"Y":89.4799},{"X":349.33,"Y":89.4799},{"X":349.33,"Y":66.37},{"X":380.09,"Y":66.37},{"X":380.09,"Y":66.37},{"X":380.09,"Y":89.4799}],[{"X":257.87,"Y":127.7},{"X":257.87,"Y":104.48},{"X":288.63,"Y":104.48},{"X":288.44,"Y":127.7},{"X":283.0396,"Y":127.7},{"X":257.87,"Y":127.7}],[{"X":288.63,"Y":142.7},{"X":288.63,"Y":165.81},{"X":257.87,"Y":165.81},{"X":257.87,"Y":142.7},{"X":257.87,"Y":142.7},{"X":288.63,"Y":142.7}],[{"X":242.87,"Y":127.7},{"X":212.11,"Y":127.7},{"X":212.11,"Y":104.48},{"X":242.87,"Y":104.48},{"X":242.87,"Y":104.48},{"X":242.87,"Y":127.7}],[{"X":242.87,"Y":142.7},{"X":242.87,"Y":165.81},{"X":212.11,"Y":165.81},{"X":212.11,"Y":142.7},{"X":212.11,"Y":142.7},{"X":242.87,"Y":142.7}],[{"X":197.11,"Y":165.81},{"X":166.41,"Y":165.81},{"X":166.41,"Y":142.7},{"X":197.11,"Y":142.7},{"X":197.11,"Y":142.7},{"X":197.11,"Y":165.81}],[{"X":197.11,"Y":180.81},{"X":197.11,"Y":203.92},{"X":166.41,"Y":203.92},{"X":166.41,"Y":180.81},{"X":166.41,"Y":180.81},{"X":197.11,"Y":180.81}],[{"X":212.11,"Y":180.81},{"X":242.87,"Y":180.81},{"X":242.87,"Y":203.92},{"X":212.11,"Y":203.92},{"X":212.11,"Y":203.92},{"X":212.11,"Y":180.81}],[{"X":242.87,"Y":218.92},{"X":242.87,"Y":242.14},{"X":212.11,"Y":242.14},{"X":212.11,"Y":218.92},{"X":212.11,"Y":218.92},{"X":242.87,"Y":218.92}],[{"X":257.87,"Y":218.92},{"X":288.63,"Y":218.92},{"X":288.63,"Y":242.14},{"X":257.87,"Y":242.14},{"X":257.87,"Y":242.14},{"X":257.87,"Y":218.92}],[{"X":257.87,"Y":203.92},{"X":257.87,"Y":180.81},{"X":288.63,"Y":180.81},{"X":288.63,"Y":203.92},{"X":288.63,"Y":203.92},{"X":257.87,"Y":203.92}],[{"X":303.63,"Y":180.81},{"X":334.33004,"Y":180.81},{"X":334.33004,"Y":203.92},{"X":303.63,"Y":203.92},{"X":303.63,"Y":203.92},{"X":303.63,"Y":180.81}],[{"X":303.63,"Y":165.81},{"X":303.63,"Y":142.7},{"X":334.33004,"Y":142.7},{"X":334.33004,"Y":165.81},{"X":334.33004,"Y":165.81},{"X":303.63,"Y":165.81}],[{"X":303.63,"Y":127.7},{"X":303.63,"Y":104.48},{"X":334.33004,"Y":104.48},{"X":334.07,"Y":127.7},{"X":328.6696,"Y":127.7},{"X":303.63,"Y":127.7}],[{"X":303.63,"Y":89.4799},{"X":303.63,"Y":66.37},{"X":334.33004,"Y":66.37},{"X":334.15,"Y":89.4799},{"X":316.15,"Y":89.4799},{"X":303.63,"Y":89.4799}],[{"X":288.63,"Y":89.4799},{"X":257.87,"Y":89.4799},{"X":257.87,"Y":66.37},{"X":288.63,"Y":66.37},{"X":288.63,"Y":89.4799},{"X":288.63,"Y":89.4799}],[{"X":242.87,"Y":89.4799},{"X":212.11,"Y":89.4799},{"X":212.11,"Y":66.37},{"X":242.87,"Y":66.37},{"X":242.87,"Y":66.37},{"X":242.87,"Y":89.4799}],[{"X":197.11,"Y":89.4799},{"X":166.41,"Y":89.4799},{"X":166.41,"Y":66.37},{"X":197.11,"Y":66.37},{"X":197.11,"Y":66.37},{"X":197.11,"Y":89.4799}],[{"X":197.11,"Y":104.48},{"X":196.93,"Y":127.7},{"X":166.41,"Y":127.7},{"X":166.41,"Y":104.48},{"X":166.41,"Y":104.48},{"X":197.11,"Y":104.48}],[{"X":151.41,"Y":127.7},{"X":120.65,"Y":127.7},{"X":120.65,"Y":104.48},{"X":151.41,"Y":104.48},{"X":151.41,"Y":104.48},{"X":151.41,"Y":127.7}],[{"X":151.41,"Y":142.7},{"X":151.41,"Y":165.81},{"X":120.65,"Y":165.81},{"X":120.65,"Y":142.7},{"X":120.65,"Y":142.7},{"X":151.41,"Y":142.7}],[{"X":151.41,"Y":180.81},{"X":151.41,"Y":203.92},{"X":120.65,"Y":203.92},{"X":120.65,"Y":180.81},{"X":120.65,"Y":180.81},{"X":151.41,"Y":180.81}],[{"X":151.41,"Y":218.92},{"X":151.41,"Y":242.14},{"X":120.65,"Y":242.14},{"X":120.65,"Y":218.92},{"X":120.65,"Y":218.92},{"X":151.41,"Y":218.92}],[{"X":166.41,"Y":218.92},{"X":197.11,"Y":218.92},{"X":197.11,"Y":242.14},{"X":166.41,"Y":242.14},{"X":166.41,"Y":242.14},{"X":166.41,"Y":218.92}],[{"X":197.11,"Y":257.14},{"X":197.11,"Y":280.26},{"X":166.41,"Y":280.26},{"X":166.41,"Y":257.14},{"X":166.41,"Y":257.14},{"X":197.11,"Y":257.14}],[{"X":212.11,"Y":257.14},{"X":242.87,"Y":257.14},{"X":242.87,"Y":280.26},{"X":212.11,"Y":280.26},{"X":212.11,"Y":280.26},{"X":212.11,"Y":257.14}],[{"X":257.87,"Y":257.14},{"X":288.63,"Y":257.14},{"X":288.63,"Y":280.26},{"X":257.87,"Y":280.26},{"X":257.87,"Y":280.26},{"X":257.87,"Y":257.14}],[{"X":303.63,"Y":257.14},{"X":334.33004,"Y":257.14},{"X":334.33004,"Y":280.26},{"X":303.63,"Y":280.26},{"X":303.63,"Y":280.26},{"X":303.63,"Y":257.14}],[{"X":303.63,"Y":242.14},{"X":303.63,"Y":218.92},{"X":334.33004,"Y":218.92},{"X":334.33004,"Y":242.14},{"X":334.33004,"Y":242.14},{"X":303.63,"Y":242.14}],[{"X":349.33,"Y":218.92},{"X":380.09,"Y":218.92},{"X":380.09,"Y":242.14},{"X":349.33,"Y":242.14},{"X":349.33,"Y":242.14},{"X":349.33,"Y":218.92}],[{"X":349.33,"Y":203.92},{"X":349.33,"Y":180.81},{"X":380.09,"Y":180.81},{"X":380.09,"Y":203.92},{"X":380.09,"Y":203.92},{"X":349.33,"Y":203.92}],[{"X":349.33,"Y":165.81},{"X":349.33,"Y":142.7},{"X":380.09,"Y":142.7},{"X":380.09,"Y":165.81},{"X":380.09,"Y":165.81},{"X":349.33,"Y":165.81}],[{"X":349.33,"Y":127.7},{"X":349.33,"Y":104.48},{"X":380.09,"Y":104.48},{"X":379.9,"Y":127.7},{"X":374.5,"Y":127.7},{"X":349.33,"Y":127.7}],[{"X":151.41,"Y":66.37},{"X":151.12,"Y":89.4799},{"X":120.65,"Y":89.4799},{"X":120.65,"Y":66.37},{"X":120.65,"Y":66.37},{"X":151.41,"Y":66.37}],[{"X":120.65,"Y":257.14},{"X":151.41,"Y":257.14},{"X":151.41,"Y":280.26},{"X":120.65,"Y":280.26},{"X":120.65,"Y":280.26},{"X":120.65,"Y":257.14}],[{"X":349.33,"Y":280.26},{"X":349.33,"Y":257.14},{"X":380.09,"Y":257.14},{"X":380.09,"Y":280.26},{"X":380.09,"Y":280.26},{"X":349.33,"Y":280.26}]]';
var grid = '[[{"X":305.08004,"Y":241.97},{"X":306,"Y":251.51},{"X":308.18,"Y":256.4},{"X":311.72,"Y":259.09003},{"X":317.31,"Y":260.01},{"X":324.71004,"Y":259.01},{"X":332.45,"Y":255.86},{"X":335.57,"Y":257.5396},{"X":337.6,"Y":260.44},{"X":336.94,"Y":262.33004},{"X":328.27,"Y":268.74},{"X":317.9,"Y":273.4196},{"X":307.94,"Y":275.49},{"X":296.26,"Y":275.23},{"X":286.64,"Y":272.99},{"X":279.7896,"Y":269.31},{"X":274.14,"Y":263.55},{"X":271.6597,"Y":260.21004},{"X":269.2,"Y":261.06},{"X":254.83,"Y":268.51},{"X":242.11,"Y":272.97},{"X":227.59,"Y":275.23},{"X":209.91,"Y":275.48},{"X":197.47,"Y":273.63},{"X":187.91,"Y":270.13},{"X":180.48002,"Y":265.09003},{"X":175.32,"Y":258.88},{"X":172.2098,"Y":251.44},{"X":171.1,"Y":242.23},{"X":172.24,"Y":233.63},{"X":175.49,"Y":226.24},{"X":181,"Y":219.54},{"X":189.42002,"Y":213.3},{"X":201.36,"Y":207.73},{"X":217.23,"Y":203.25},{"X":238.28,"Y":200.1},{"X":265.24,"Y":198.78},{"X":269.37,"Y":198.47},{"X":269.98,"Y":182.93},{"X":268.74,"Y":171.32},{"X":266.05,"Y":163.7098},{"X":261.58004,"Y":157.72},{"X":255.24,"Y":153.24},{"X":247.06,"Y":150.3298},{"X":235.44,"Y":149.13},{"X":224.71,"Y":150.05},{"X":215.91,"Y":153},{"X":210.23002,"Y":156.86},{"X":207.64,"Y":160.85},{"X":207.19,"Y":165.28},{"X":209.34,"Y":169.86},{"X":212.0198,"Y":174.15},{"X":212.14,"Y":177.99},{"X":209.8,"Y":181.78},{"X":204.22,"Y":185.79},{"X":197.62,"Y":187.68},{"X":188.65,"Y":187.43},{"X":182.41,"Y":185.39},{"X":178.45,"Y":181.77},{"X":176.2098,"Y":176.9},{"X":176.03,"Y":170.64},{"X":178.2,"Y":164.13},{"X":183.09,"Y":157.7},{"X":191.04002,"Y":151.36},{"X":202.01,"Y":145.8298},{"X":216.09,"Y":141.57},{"X":232.08,"Y":139.24},{"X":250.07,"Y":139.18},{"X":266.13,"Y":141.23002},{"X":279.05,"Y":145.06},{"X":289.1597,"Y":150.3},{"X":295.9196,"Y":156.19},{"X":300.73,"Y":163.41},{"X":303.85,"Y":172.47},{"X":305.07,"Y":183.78},{"X":305.07,"Y":241.97},{"X":305.08004,"Y":241.97}],[{"X":243.99,"Y":64.95},{"X":255.92,"Y":66.07},{"X":266.21004,"Y":69.28},{"X":274.98,"Y":74.44},{"X":280.65,"Y":80.19},{"X":284.03,"Y":86.85},{"X":285.26,"Y":94.52001},{"X":284.28,"Y":102.84},{"X":281.24,"Y":109.66},{"X":276.0396,"Y":115.43},{"X":267.89,"Y":120.46},{"X":257.68,"Y":123.93},{"X":245.79,"Y":125.33},{"X":232.93,"Y":124.53},{"X":222.21,"Y":121.74},{"X":213.14,"Y":117.11},{"X":207.36,"Y":111.92},{"X":203.7,"Y":105.75},{"X":201.94,"Y":98.18},{"X":202.34,"Y":90.12},{"X":204.86,"Y":83.4},{"X":210.01,"Y":76.81},{"X":217.49,"Y":71.33},{"X":227.17,"Y":67.31},{"X":238.35,"Y":65.2},{"X":243.75,"Y":64.95},{"X":243.99,"Y":64.95}],[{"X":269.99,"Y":212.88},{"X":269.48,"Y":208.76},{"X":266.59003,"Y":208.36},{"X":245.76,"Y":210.86},{"X":230.95,"Y":214.67},{"X":220.9,"Y":219.34},{"X":213.82,"Y":224.85},{"X":209.69,"Y":230.71},{"X":207.92002,"Y":237.03},{"X":208.4,"Y":244.49},{"X":210.86,"Y":250.57},{"X":215.2,"Y":255.08},{"X":221.69,"Y":258.13},{"X":230.57,"Y":259.43},{"X":242.52,"Y":258.58004},{"X":255.27,"Y":255.23},{"X":266.07,"Y":250.04},{"X":269.34003,"Y":247.02},{"X":269.99,"Y":244.81},{"X":269.99,"Y":212.88},{"X":269.99,"Y":212.88}],[{"X":243.63,"Y":73.34},{"X":235.93,"Y":74.4},{"X":230.07,"Y":77.36},{"X":225.65,"Y":82.21001},{"X":223.05,"Y":88.57},{"X":222.41,"Y":96.92},{"X":223.94,"Y":104.53},{"X":227.23,"Y":110.22},{"X":231.99,"Y":114.29},{"X":238.44,"Y":116.65},{"X":246.81,"Y":116.94},{"X":253.73,"Y":115.1},{"X":258.87,"Y":111.5},{"X":262.63,"Y":106.12},{"X":264.65,"Y":98.93},{"X":264.59003,"Y":90.25},{"X":262.47,"Y":83.41},{"X":258.6597,"Y":78.43},{"X":253.37,"Y":75.08},{"X":246.08,"Y":73.43},{"X":243.68,"Y":73.34},{"X":243.63,"Y":73.34}]]';
return {
"ss": deserialize_clipper_poly(glyph),
"cc": deserialize_clipper_poly(grid)
};
}
function get_custom_poly() {
var selected_value = $("#custom_polygons_select").val();
var arr = $.totalStorage('custom_polygons');
if (selected_value !== "") {
//selected_value = parseInt(selected_value,10);
return {
"ss": deserialize_clipper_poly(arr[selected_value].subj),
"cc": deserialize_clipper_poly(arr[selected_value].clip)
};
}
//else return { "ss": '[[{"X":0,"Y":0},{"X":1,"Y":1}]]', "cc": '[[{"X":0,"Y":0},{"X":1,"Y":1}]]' };
else return {
"ss": deserialize_clipper_poly(default_custom_subject_polygon),
"cc": deserialize_clipper_poly(default_custom_clip_polygon)
};
}
function get_random_polys(which, polygon) {
var point_count, polygon_count;
if (which == "subj") {
point_count = rnd_sett.subj_point_count;
polygon_count = rnd_sett.subj_polygon_count;
}
else if (which == "clip") {
point_count = rnd_sett.clip_point_count;
polygon_count = rnd_sett.clip_polygon_count;
}
if (arguments.length === 1) polygon = parseInt($('input[type="radio"][name="polygons"]:checked').val(), 10);
if (polygon != 4 && polygon != 5) return new ClipperLib.Polygons();
var svg = $("#p");
var margin = 10;
rnd_sett.rand_min_x = 0 + margin;
rnd_sett.rand_max_x = parseFloat(svg.attr("width"), 10) - margin;
rnd_sett.rand_min_y = 0 + margin;
rnd_sett.rand_max_y = parseFloat(svg.attr("height"), 10) - margin;
var i, j, pp, np = new ClipperLib.Polygons(),
prev_x = null,
prev_y = null,
horiz_or_vertic = null,
prev_horiz_or_vertic = null;
for (i = 0; i < polygon_count; i++) {
np[i] = new ClipperLib.Polygon();
for (j = 0; j < point_count; j++) {
pp = new ClipperLib.IntPoint();
if (polygon == 4) {
horiz_or_vertic = rnd("int", 0, 1); // 0 = horiz, 1 = vertic
if (prev_horiz_or_vertic === horiz_or_vertic) {
if (horiz_or_vertic === 0) horiz_or_vertic = 1;
else if (horiz_or_vertic === 1) horiz_or_vertic = 0;
else horiz_or_vertic = 0;
}
if (horiz_or_vertic === 0) // horiz => y remains same
{
pp.X = round(rnd("float", rnd_sett.rand_min_x, rnd_sett.rand_max_x));
if (prev_y == null) pp.Y = round(rnd("float", rnd_sett.rand_min_y, rnd_sett.rand_max_y));
else pp.Y = prev_y;
prev_x = pp.X;
prev_y = pp.Y;
prev_horiz_or_vertic = horiz_or_vertic;
}
else // vertic => x remains same
{
pp.Y = round(rnd("float", rnd_sett.rand_min_y, rnd_sett.rand_max_y));
if (prev_x == null) pp.X = round(rnd("float", rnd_sett.rand_min_x, rnd_sett.rand_max_x));
else pp.X = prev_x;
prev_x = pp.X;
prev_y = pp.Y;
prev_horiz_or_vertic = horiz_or_vertic;
}
// last point fix
if (j == point_count - 1 && point_count !== 1) {
if (horiz_or_vertic === 0) // horiz => y remains same
{
pp.X = np[i][0].X;
}
else // vertic => x remains same
{
pp.Y = np[i][0].Y;
}
np[i].push(pp);
}
else np[i].push(pp);
}
else if (polygon == 5) {
pp.X = round(rnd("float", rnd_sett.rand_min_x, rnd_sett.rand_max_x));
pp.Y = round(rnd("float", rnd_sett.rand_min_y, rnd_sett.rand_max_y));
np[i].push(pp);
}
}
prev_x = null;
prev_y = null;
horiz_or_vertic = null;
prev_horiz_or_vertic = null;
}
rnd_sett.scale = scale;
return np;
}
function scale_again_random_poly(poly) {
var i, j;
for (i = 0; i < poly.length; i++) {
for (j = 0; j < poly[i].length; j++) {
poly[i][j].X = round(poly[i][j].X / rnd_sett.scale);
poly[i][j].Y = round(poly[i][j].Y / rnd_sett.scale);
}
}
return poly;
}
function rnd(intfloat, Amin, Amax) {
var num;
if (intfloat == "float") num = (Amin + (Amax - Amin) * Math.random()).toFixed(2);
else if (intfloat == "int") num = Math.floor(Amin + (1 + Amax - Amin) * Math.random());
return num;
}
function get_rect_poly() {
var rect_poly = '[[{"X":100,"Y":100},{"X":200,"Y":100},{"X":200,"Y":200},{"X":100,"Y":200},{"X":100,"Y":100}]]';
rect_poly = '[[{"X":100,"Y":100},{"X":100,"Y":100},{"X":200,"Y":100},{"X":200,"Y":200},{"X":100,"Y":200},{"X":100,"Y":100}]]';
return deserialize_clipper_poly(rect_poly);
}
function round(a) {
if (global_do_not_round_and_scale) return a;
else
return Math.floor(a * scale);
}
window.lsk = 0;
function deserialize_clipper_poly(polystr) {
window.lsk++;
var poly = JSON.parse(polystr);
var i, j, pp, n = [
[]
], m, pm;
var np = new ClipperLib.Polygons();
for (i = 0, m = poly.length; i < m; i++) {
np[i] = new ClipperLib.Polygon();
for (j = 0, pm = poly[i].length; j < pm; j++) {
pp = new ClipperLib.IntPoint();
if (!isNaN(Number(poly[i][j].X)) && !isNaN(Number(poly[i][j].Y))) {
pp.X = round(Number(poly[i][j].X));
pp.Y = round(Number(poly[i][j].Y));
if (benchmark_running) {
if (pp.X > bench.max_point_x) bench.max_point_x = pp.X;
if (pp.Y > bench.max_point_y) bench.max_point_y = pp.Y;
if (pp.X < bench.min_point_x) bench.min_point_x = pp.X;
if (pp.Y < bench.min_point_y) bench.min_point_y = pp.Y;
if (typeof (bench.points["L" + pp.X]) == "undefined") bench.points["L" + pp.X] = scale + ":" + pp.X + ":" + poly[i][j].X;
if (typeof (bench.points["L" + pp.Y]) == "undefined") bench.points["L" + pp.Y] = scale + ":" + pp.Y + ":" + poly[i][j].Y;
}
np[i].push(pp);
}
else return n;
}
}
return np;
}
(function () {
"use strict";
SVG.create = function () {
p = Raphael("svgcontainer", 500, 350);
p.canvas.setAttribute("id", "p");
var str = "<filter id='innerbewel' x0='-50%' y0='-50%' width='200%' height='200%' >";
str += "<feGaussianBlur in='SourceAlpha' stdDeviation='2' result='blur'/>";
str += "<feOffset dy='3' dx='3'/>";
str += "<feComposite in2='SourceAlpha' operator='arithmetic'";
str += " k2='-1' k3='1' result='hlDiff'/>";
str += "<feFlood flood-color='white' flood-opacity='0.8'/>"; // changed to 1.0 for speed
str += "<feComposite in2='hlDiff' operator='in'/>";
str += "<feComposite in2='SourceGraphic' operator='over' result='withGlow'/>";
str += "<feOffset in='blur' dy='-3' dx='-3'/>";
str += "<feComposite in2='SourceAlpha' operator='arithmetic'";
str += " k2='-1' k3='1' result='shadowDiff'/>";
str += "<feFlood flood-color='black' flood-opacity='0.5'/>"; // changed to 1.0 for speed
str += "<feComposite in2='shadowDiff' operator='in'/>";
str += "<feComposite in2='withGlow' operator='over'/>";
str += "</filter>";
var markers = '';
// Markers to show start, mid and end points of path
markers += '<marker id="StartMarker" viewBox="0 0 10 10" refX="0" refY="5" markerUnits="strokeWidth" markerWidth="10" markerHeight="10" stroke="red" stroke-width="1" fill="none" orient="auto">';
markers += '<path d="M0,5L10,5M5,0L10,5M5,10L10,5">';
markers += '</marker>';
markers += '<marker id="MidMarker" stroke-opacity="1.0" viewBox="-1 -1 12 12" refX="5" refY="5" markerWidth="4" markerHeight="4" stroke="red" stroke-width="1" fill="yellow" stroke-opacity="0.5" fill-opacity="0.5" orient="0" markerUnits="strokeWidth">';
markers += '<circle cx="5" cy="5" r="5"></circle>';
markers += '</marker>';
markers += '<marker id="EndMarker" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="8" stroke="blue" stroke-width="1" fill="none" orient="auto">';
markers += '<rect x="0" y="0" width="10" height="10"></rect>';
markers += '</marker>';
// This second invisible marker is needed to avoid noisy after images in Chrome:
markers += '<marker id="StartMarker2" viewBox="0 0 10 10" refX="0" refY="5" markerUnits="strokeWidth" markerWidth="10" markerHeight="10" stroke="none" fill="none" orient="auto">';
markers += '<path d="M0,5L10,5M5,0L10,5M5,10L10,5">';
markers += '</marker>';
markers += '<marker id="MidMarker2" stroke-opacity="1.0" viewBox="-1 -1 12 12" refX="5" refY="5" markerWidth="4" markerHeight="4" stroke="none" fill="none" orient="0" markerUnits="strokeWidth">';
markers += '<circle cx="5" cy="5" r="5"></circle>';
markers += '</marker>';
markers += '<marker id="EndMarker2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="8" stroke="none" fill="none" orient="auto">';
markers += '<rect x="0" y="0" width="10" height="10"></rect>';
markers += '</marker>';
$("body").append("<svg id='dummy' style='display:none'><defs>" + str + markers + "</defs></svg>");
$("#p defs").append($("#innerbewel"));
$("#p defs").append($("#dummy marker"));
$("#dummy").remove();
return p;
};
SVG.addpaths = function (a, b, c, a1, b1) {
if (a) {
subj_subpolygons = a.length;
a = this.polys2path(a, "1");
if (sub_poly_links_update) {
if (typeof(subj_subpolygons) == "undefined") subj_subpolygons = 0;
$("#subj_subpolygons").html(subj_subpolygons);
$("#subj_points_in_subpolygons").html(this.sub_poly_links);
$("#subj_points_total").html(this.total.toString());
subj_points_total = this.total;
}
}
if (b) {
clip_subpolygons = b.length;
b = this.polys2path(b, "2");
if (sub_poly_links_update) {
if (typeof(clip_subpolygons) == "undefined") clip_subpolygons = 0;
$("#clip_subpolygons").html(clip_subpolygons);
$("#clip_points_in_subpolygons").html(this.sub_poly_links);
$("#clip_points_total").html(this.total.toString());
clip_points_total = this.total;
}
}
if (typeof(c) != "undefined" && typeof(c.length) != "undefined") solution_subpolygons = c.length;
else solution_subpolygons = 0;
if (c) {
c = this.polys2path(c, "3");
if (sub_poly_links_update) {
$("#solution_subpolygons").html(solution_subpolygons);
$("#solution_points_in_subpolygons").html(this.sub_poly_links);
$("#solution_points_total").html(this.total.toString());
solution_points_total = this.total;
}
}
if (sub_poly_links_update) {
$("#points_total").html((subj_points_total + clip_points_total + solution_points_total).toString());
if (isNaN(subj_subpolygons)) subj_subpolygons = 0;
else if (isNaN(clip_subpolygons)) clip_subpolygons = 0;
else if (isNaN(solution_subpolygons)) solution_subpolygons = 0;
$("#all_subpolygons").html(subj_subpolygons + clip_subpolygons + solution_subpolygons);
}
if (a) p1 = p.path(a);
if (b) p2 = p.path(b);
if (c) p3 = p.path(c);
if (a) p1.node.setAttribute("id", "p1");
if (b) p2.node.setAttribute("id", "p2");
if (c) p3.node.setAttribute("id", "p3");
if (c && bevel) $("#p3").attr("filter", "url(#innerbewel)");
else if (c && !bevel) $("#p3").removeAttr("filter");
if (a) $("#p1").removeAttr("fill stroke");
if (b) $("#p2").removeAttr("fill stroke");
if (c) $("#p3").removeAttr("fill stroke");
var PolyFillType = {
pftEvenOdd: 0,
pftNonZero: 1,
pftPositive: 2,
pftNegative: 3
};
if (a) {
if (a1 == PolyFillType.pftEvenOdd) $("#p1").attr("fill-rule", "evenodd");
else $("#p1").attr("fill-rule", "nonzero");
}
if (b) {
if (b1 == PolyFillType.pftEvenOdd) $("#p2").attr("fill-rule", "evenodd");
else $("#p2").attr("fill-rule", "nonzero");
}
// p.setViewBox(bbox.x, bbox.y, bbox.width, bbox.height, true);
// p.setSize(bbox.width, bbox.height);
};
SVG.sub_poly_counts = null;
SVG.sub_poly_links = null;
SVG.total = null;
SVG.polys2path = function (a, fr) {
scaled_paths[fr] = [];
var path = "",
i, j, link, d;
this.sub_poly_counts = [];
this.sub_poly_links = "";
this.total = 0;
if (!scale) scale = 1;
var a_length = a.length;
var a_i_length;
var classi = "subpolylinks";
for (i = 0; i < a_length; i++) {
this.sub_poly_counts.push(a[i].length);
d = "";
a_i_length = a[i].length;
for (j = 0; j < a_i_length; j++) {
this.total++;
if (j == 0) {
d += "M";
}
else {
d += "L";
}
d += (a[i][j].X / scale) + ", " + (a[i][j].Y / scale);
}
d += "Z";
path += d;
if (sub_poly_links_update) {
if (d.trim() == "Z") d = "";
scaled_paths[fr].push(d);
if (benchmark_running) classi = "subpolylinks_disabled";
link = '<span class="' + classi + '" onclick="popup_path(' + i + ',' + fr + ')" onmouseover="show_path(' + i + ',' + fr + ')" onmouseout="hide_path()" >' + a_i_length + '</span>, ';
this.sub_poly_links += link;
}
}
if (sub_poly_links_update) this.sub_poly_links = this.sub_poly_links.substring(0, this.sub_poly_links.length - 2);
if (path.trim() == "Z") path = "";
if (benchmark_running) $(".subpolylinks").removeClass("subpolylinks subpolylinks_disabled").addClass("subpolylinks_disabled");
else $(".subpolylinks_disabled").removeClass("subpolylinks subpolylinks_disabled").addClass("subpolylinks");
return path;
}
window.SVG = SVG;
})()
function toint(a) {
a = parseInt(a, 10);
return a;
}
// Englarges mypath ( = black partially transparent path)
// when clicked
function popup_path(i, fr) {
if (benchmark_running) return false;
if (typeof(i) == "undefined") d = scaled_paths[fr].join(" ");
else d = scaled_paths[fr][i];
var points_string = normalize_clipper_poly(d, true); // quiet
var area;
SolutionPolygonClicked = false;
SolutionPolygonString = "";
if (points_string !== false) {
if (typeof(i) == "undefined") // which means that "Points" column is clicked
{
if (fr == 3) {
$("#polygon_explorer_string_inp").val(format_output(points_string, "ExPolygons"));
SolutionPolygonClicked = true;
SolutionPolygonString = points_string;
}
else {
$("#polygon_explorer_string_inp").val(format_output(points_string));
}
var scaled_paths_length = scaled_paths.length;
var points_str;
area = 0;
for (var j = 0; j < scaled_paths_length; j++) {
points_str = normalize_clipper_poly(scaled_paths[fr][j], true);
if (points_str !== false) {
var polygon = JSON.parse(points_str.replace(/^\[\[/, "[").replace(/\]\]$/, "]"));
area += ClipperLib.Clipper.Area(polygon);
}
}
$("#area").html("Area: " + area);
}
else {
$("#polygon_explorer_string_inp").val(format_output(points_string).replace(/^\[\[/, "[").replace(/\]\]$/, "]"));
area = ClipperLib.Clipper.Area(JSON.parse(points_string.replace(/^\[\[/, "[").replace(/\]\]$/, "]")));
$("#area").html("Area: " + area);
}
}
else {
$("#polygon_explorer_string_inp").val("Some error occurred when parsing polygon points!");
}
$(mypath.node).removeAttr('fill stroke').attr('class', 'svg_mypath');
$(mypath.node).attr('fill-rule', $('#p' + fr).attr('fill-rule'));
$(mypath.node).attr('vector-effect', 'non-scaling-stroke'); // This is not supported in IE 9 and IE10 pre!
var bb = mypath.node.getBBox();
var svg_w = toint($('#p').attr('width'));
var svg_h = toint($('#p').attr('height'));
var x_scale = (svg_w - 20) / bb.width;
var y_scale = (svg_h - 20) / bb.height;
var scal = Math.min(x_scale, y_scale);
var x_trans = -(bb.x + bb.width / 2) + svg_w / 2;
var y_trans = -(bb.y + bb.height / 2) + svg_h / 2;
$('#StartMarker')[0].setAttribute('markerWidth', 10 / scal * 2);
$('#StartMarker')[0].setAttribute('markerHeight', 10 / scal * 2);
$('#MidMarker')[0].setAttribute('markerWidth', 4 / scal * 2);
$('#MidMarker')[0].setAttribute('markerHeight', 4 / scal * 2);
$('#EndMarker')[0].setAttribute('markerWidth', 4 / scal * 2);
$('#EndMarker')[0].setAttribute('markerHeight', 4 / scal * 2);
mypath.animate({
'transform': 't' + x_trans + ' ' + y_trans + 's' + scal + ' ' + scal
}, 500, function () {
$(mypath.node).attr({
'marker-start': 'url(#StartMarker)',
'marker-mid': 'url(#MidMarker)',
'marker-end': 'url(#EndMarker)'
});
});
}
// Shows mypath ( = black partially transparent path)
// when hovered
function show_path(i, fr) {
if (benchmark_running) return false;
var d;
if (typeof(i) == "undefined")
d = scaled_paths[fr].join(" ");
else
d = scaled_paths[fr][i];
mypath = p.path(d);
$(mypath.node).removeAttr('fill stroke').attr('class', 'svg_mypath');
$(mypath.node).attr('fill-rule', $('#p' + fr).attr('fill-rule'));
$(mypath.node).attr('vector-effect', 'non-scaling-stroke');
}
// Hides mypath ( = black partially transparent path)
function hide_path() {
if (mypath == null) return;
$(mypath.node).attr({
'marker-start': 'url(#StartMarker2)',
'marker-mid': 'url(#MidMarker2)',
'marker-end': 'url(#EndMarker2)'
});
if ($(mypath.node).attr('transform')) mypath.animate({
'transform': 's1 1'
}, 500, function () {
this.animate({
'opacity': '0'
}, 500, function () {
this.remove();
});
});
else mypath.animate({
'opacity': '0'
}, 300, function () {
this.remove();
});
}
function set_default_custom_polygon() {
var subj = default_custom_subject_polygon;
var clip = default_custom_clip_polygon;
var def_obj = {
"subj": subj,
"clip": clip
};
var arr = $.totalStorage('custom_polygons');
if (typeof (arr) == "undefined" || arr === null || !isArray(arr) || arr.length == 0) arr = [];
arr[0] = def_obj;
$.totalStorage('custom_polygons', arr);
}
function update_custom_polygons_select() {
var arr = $.totalStorage('custom_polygons');
var selected_value = $("#custom_polygons_select").val();
if (!selected_value && selected_value + "" !== "0") selected_value = 0;
$("#custom_polygons_select option").remove();
var arr_length = 0;
if (isArray(arr)) arr_length = arr.length;
var selected_txt, i;
if (arr_length > 0)
for (i = 0; i < arr_length; i++) {
selected_txt = "";
if (i == selected_value) selected_txt = "selected";
if (arr[i] !== null) $("#custom_polygons_select").append('<option ' + selected_txt + ' value="' + i + '">Poly ' + i + '</option>');
}
else set_default_custom_polygon();
if ($("#custom_polygons_select option").length === 0) set_default_custom_polygon();
// If previously selected value is removed, select the next one
if (arr_length > 0)
if (arr[selected_value] === null) {
for (i = parseInt(selected_value, 10); i < arr_length; i++) {
if (arr[i] !== null) {
$('#custom_polygons_select').val(i);
break;
}
}
}
$('#custom_polygons_select').change();
}
function show_alert(e, obj, txt) {
var x = e.pageX - obj.offsetLeft + $(obj).width() / 2;
var y = e.pageY - obj.offsetTop;
$("#custom_poly_message_box_green")
.stop()
.css({
height: '0px',
opacity: '0',
left: x + 1,
top: y - 1,
width: '0px',
display: 'block'
})
.html("")
.animate({
left: (x + 200),
top: (y - 40),
height: '40px',
width: '200px',
opacity: '0.9'
}, 300, function () {
$(this).html(txt).animate({
opacity: '0.9'
}, 1200, function () {
$(this).animate({
opacity: 0
}, 600, function () {
$(this).css("display", "none");
})
})
});
}
function update_fieldset_heights() {
$("#misc_fieldset").css("min-height", "").css("height", "");
$("#polygon_explorer_fieldset").css("min-height", "").css("height", "");
$("#benchmark_fieldset_f").css("min-height", "").css("height", "");
var td_heights = [];
td_heights.push($("#td0").innerHeight());
td_heights.push($("#td1").innerHeight());
td_heights.push($("#td2").innerHeight());
td_heights.push($("#td3").innerHeight());
var max_td_height = Array_max(td_heights);
var max_index;
var children_heights;
var children_heights_arr = [];
for (var i = 0; i < td_heights.length; i++) {
children_heights = 0;
if (td_heights != max_td_height || 1 == 1) {
$("#td" + i).children().each(function () {
if ($(this).css("display") != "none") {
children_heights += $(this).outerHeight(true);
//console.log(this.type + ":" + $(this).attr("id") + ":" + $(this).outerHeight(true) + ":" + $(this).outerWidth(true));
}
else {
//console.log("----- NOT COUNTED:"+this.type + ":" + $(this).attr("id") + ":" + $(this).outerHeight(true) + ":" + $(this).outerWidth(true));
}
});
}
children_heights_arr.push(children_heights);
//console.log("-------------");
}
var misc_fieldset_height = $("#misc_fieldset").height();
var polygon_explorer_fieldset_height = $("#polygon_explorer_fieldset").height();
var benchmark_fieldset_f_height = $("#benchmark_fieldset_f").height();
misc_fieldset_height += (max_td_height - children_heights_arr[0]);
polygon_explorer_fieldset_height += (max_td_height - children_heights_arr[1]);
benchmark_fieldset_f_height += (max_td_height - children_heights_arr[2]);
$("#misc_fieldset").css("min-height", misc_fieldset_height + "px");
$("#polygon_explorer_fieldset").css("min-height", polygon_explorer_fieldset_height + "px");
$("#benchmark_fieldset_f").css("min-height", benchmark_fieldset_f_height + "px");
}
function resize() {
myresize();
}
function myresize() {
var freeheight = $(window).height();
var polygon_explorer_div_max_height = freeheight - 360;
if (polygon_explorer_div_max_height < 170) polygon_explorer_div_max_height = 170;
// This causes problems when resizing polygon explorer textarea, so have to comment:
//$("#polygon_explorer_div").css("max-height", polygon_explorer_div_max_height +"px");
}
// ADDITIONAL SVG WINDOW STARTS
window.update_enlarged_SVG = false;
window.update_enlarged_SVG_source = false;
window.svg_source_place = "svg_source_container";
function svg_source_enlarge() {
var source = $("#svg_source_textarea").val().replace(/ id=\"/g, ' id="_');
$("#enlarged_svg").html(source);
var original_height = $("#_p").attr("height");
var original_width = $("#_p").attr("width");
// get bbox of all children of svg
$("body").append('<div id="dummy" style="display:block;visibility:hidden"><svg><g id="g123"></g></svg></div>');
$("#g123").append($("#_p").children().clone());
$("#dummy").html($("#dummy").html());
var bb = $("#g123")[0].getBBox();
var g_width = bb.width + 10;
var g_height = bb.height + 10;
var g_x = bb.x - 5;
var g_y = bb.y - 5;
$("#dummy").remove();
/*
$("body").append('<img id="width_img" width="100%" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7">');
var window_width = parseInt(window.getComputedStyle($("#width_img")[0],null).getPropertyValue("width"));
$("#width_img").remove();
*/
$("#_p").attr("viewBox", g_x + " " + g_y + " " + g_width + " " + g_height);
$("#enlarged_svg").html($("#enlarged_svg").html());
$("#enlarged_svg").css("display", "block");
if (svg_source_place == "svg_source_container") // at the bottom
{
$("#_p").attr("width", window_width);
$("#_p").attr("height", parseInt((window_width / original_width) * original_height));
$("#_p1,#_p2,#_p3").css("stroke-width", 0.8 * (original_width / window_width));
}
else // at the right
{
$("#_p").attr("height", window_height);
$("#_p").attr("width", parseInt((window_height / original_height) * original_width));
$("#_p1,#_p2,#_p3").css("stroke-width", 0.8 * (original_height / window_height));
}
$("#svg_source_textarea").css("display", "none");
if (benchmark_running) var disabled = "disabled";
else disabled = "";
$("#svg_source_enlarge_button").html('<button ' + disabled + ' class="textarea_hide_buttons" onClick="show_svg_source_f()" title="Show SVG source">Show SVG source</button>');
update_enlarged_SVG_source = true;
update_enlarged_SVG = true;
}
function show_svg_source_f() {
$("#svg_source_textarea").css("display", "block");
show_svg_source_click("non_click");
$("#enlarged_svg").html("");
if (benchmark_running) var disabled = "disabled";
else disabled = "";
$("#svg_source_enlarge_button").html('<button ' + disabled + ' class="textarea_hide_buttons" onClick="svg_source_enlarge()" title="Show SVG">Show SVG</button>');
update_enlarged_SVG_source = true;
update_enlarged_SVG = false;
}
window_height = $(document).height() * 0.9;
window_width = $(document).width() * 0.9;
function show_svg_source_click(non_click) {
update_enlarged_SVG_source = true;
if (!update_enlarged_SVG) update_enlarged_SVG = false;
if (non_click !== "non_click") {
if ($("#show_svg_source").html() == "Show SVG source B") {
$("#show_svg_source").html("Show SVG source R");
$("#show_svg_source").attr("title", "Show current SVG source in textarea at the right side of the page");
svg_source_place = "svg_source_container";
$("#svg_source_container2").html("");
}
else {
$("#show_svg_source").html("Show SVG source B");
$("#show_svg_source").attr("title", "Show current SVG source in textarea at the bottom of the page");
svg_source_place = "svg_source_container2";
$("#svg_source_container").html("");
}
var textarea_str = '<div id="svg_source_textarea_div">';
textarea_str += '<button class="textarea_hide_buttons" onClick="$(\'#svg_source_textarea_div\').remove();update_enlarged_SVG_source=false;update_enlarged_SVG=false" title="Hide SVG source">Hide</button>';
if (benchmark_running) var disabled = "disabled";
else disabled = "";
textarea_str += '<span id="svg_source_enlarge_button"><button ' + disabled + ' class="textarea_hide_buttons" onClick="svg_source_enlarge()" title="Show SVG">Show SVG</button></span><br>';
textarea_str += '<div style="display:none" id="enlarged_svg"></div>';
textarea_str += '<textarea id="svg_source_textarea"></textarea>';
textarea_str += '</div>';
$("#" + svg_source_place).append(textarea_str);
}
var svg_source = $("#svgcontainer").html().replace(/\>/g, ">\n");
$("#svg_source_textarea").val(svg_source);
}
// ADDITIONAL SVG WINDOW ENDS
// BENCHMARKING STARTS
function benchmark2(i) {
var start_time = new Date().getTime();
var obj = bench_glob[i];
$("#clean").removeAttr('checked');
clean = false;
$("#lighten").removeAttr('checked');
lighten = false;
joinType = obj.joinType;
$('input[type="radio"][name="joinType"][value="' + joinType + '"]').attr('checked', 'checked');
offsettable_poly = obj.offsettable_poly;
$('input[type="radio"][name="offsettable_poly"][value="' + offsettable_poly + '"]').attr('checked', 'checked');
delta = obj.delta;
$('#delta').val(delta);
miterLimit = obj.miterLimit;
$('#miterLimit').val(miterLimit);
AutoFix = obj.AutoFix;
if (AutoFix) $('#AutoFix').attr('checked', 'checked');
else $('#AutoFix').removeAttr('checked');
ExPolygons = obj.ExPolygons;
if (ExPolygons) $('#ExPolygons').attr('checked', 'checked');
else $('#ExPolygons').removeAttr('checked');
Simplify = obj.Simplify;
if (Simplify) $('#Simplify').attr('checked', 'checked');
else $('#Simplify').removeAttr('Simplify');
subject_fillType = obj.subject_fillType;
$("input[name='subject_fillType'][value='" + subject_fillType + "']").attr("checked", "checked");
clip_fillType = obj.clip_fillType;
$("input[name='clip_fillType'][value='" + clip_fillType + "']").attr("checked", "checked");
clipType = obj.clipType;
$("input[name='clipType'][value='" + clipType + "']").attr("checked", "checked");
scale = obj.scale;
$('#scale').val(scale);
if (obj.polygon_id == 4 || obj.polygon_id == 5) rnd_sett = obj.rnd_sett;
$('input[type="radio"][name="polygons"][value="' + obj.polygon_id + '"]').attr('checked', 'checked').trigger("change");
obj = null;
window.last_completed_bench = i;
var end_time = new Date().getTime();
var time = end_time - start_time;
bench_glob[i].measured_time = time;
bench_elapsed_time += time;
bench_glob[i].elapsed_time = bench_elapsed_time;
// update next timeouts
for (var lsk = i + 1; lsk < bench_glob.length; lsk++) {
clearTimeout(bench_glob[lsk].setTimeout);
bench_glob[lsk].setTimeout = setTimeout("benchmark2(" + (lsk) + ")",
bench_glob[lsk].elapsed_time + lsk * bench_glob[lsk].time);
}
var results = '';
var elapsed_time = end_time - bench.list[0].start;
results += Math.floor((i + 1) / bench_glob.length * 100) + " % (";
results += (elapsed_time / 1000).toFixed(1) + " s) of ";
results += "benchmark " + (repeat + 1) + " / " + repeat_times + ". ";
results += "Remaining: ";
results += Math.floor((((elapsed_time / (i + 1)) * (bench_glob.length - i + 1)) / 1000)) + " s.";
$("#benchmark_multiple_status").html(results);
$("#benchmark_multiple_status").css("display", "table-cell");
if (i == 0) {
var multiple_runs_table = bench.print_multiple_runs();
if ($("#benchmark_multiple_table").length) $("#benchmark_multiple_table").remove();
$("#benchmark_multiple_table_cont").append(multiple_runs_table);
}
else if (i == bench_glob.length - 1) {
if (!$("#benchmark_exports_textarea").length) {
var textarea_str = '<div id="benchmark_exports_textarea_div">';
textarea_str += '<button class="textarea_hide_buttons" onClick="$(\'#benchmark_exports_textarea_div\').remove()" title="Hide Benchmark exports">Hide</button><br>';
textarea_str += '<textarea id="benchmark_exports_textarea"></textarea>';
textarea_str += '</div>';
$("#benchmark_exports_container").append(textarea_str);
}
if (benchmark_exports.indexOf("max_point_x") == -1) {
benchmark_exports += "bench.max_point_x:" + bench.max_point_x + "\n";
benchmark_exports += "bench.max_point_y:" + bench.max_point_y + "\n";
benchmark_exports += "bench.min_point_x:" + bench.min_point_x + "\n";
benchmark_exports += "bench.min_point_y:" + bench.min_point_y + "\n";
}
benchmark_exports += bench.totals + ";" + browserg.browser + ";" + browserg.version + "\n";
$("#benchmark_exports_textarea").val(benchmark_exports);
bench.totals_arr_multiple.push(bench.totals_arr[0]);
var multiple_runs_table = bench.print_multiple_runs();
if ($("#benchmark_multiple_table").length) $("#benchmark_multiple_table").remove();
$("#benchmark_multiple_table_cont").append(multiple_runs_table);
repeat++;
if (repeat < repeat_times) {
benchmark_automatic_click = 1;
$("#" + clicked_benchmark_button_id).trigger("click");
}
else {
bench_glob.length = 0;
repeat = 0;
benchmark_running = 0;
ClipperLib.MaxSteps = ClipperLib_MaxSteps_original;
$("#" + clicked_benchmark_button_id).html($("#" + clicked_benchmark_button_id).html().replace("Stop", "Run"));
$("#" + clicked_benchmark_button_id).attr("title", $("#" + clicked_benchmark_button_id).attr("title").replace("Stop", "Execute"));
$("button,input,select").removeAttr('disabled');
$('#sub_poly_links_update').trigger("change");
}
}
}
(function (window) {
var benchmark = function (varname) {
if (typeof (varname) == "string") this.varname = varname;
else this.varname = "";
this.list = [];
this.cats = [];
this.cats.arr = [];
this.type = "benchmark";
this.includeSVG = true;
this.totals = "";
this.totals_arr = [];
this.totals_arr_multiple = [];
this.max_point_x = Number.NEGATIVE_INFINITY;
this.min_point_x = Number.POSITIVE_INFINITY;
this.max_point_y = Number.NEGATIVE_INFINITY;
this.min_point_y = Number.POSITIVE_INFINITY;
this.points = [];
};
// returns index
// cat = category, which name belongs to
// name = code region name or function, which is measured
benchmark.prototype.start = function (cat, name) {
if (cat == "") return;
if (name == "") return;
var b = {};
b.start = new Date().getTime();
b.name = name;
b.cat = cat;
this.list.push(b);
return this.list.length - 1;
}
benchmark.prototype.end = function (index) {
this.list[index].end = new Date().getTime();
this.list[index].time = this.list[index].end - this.list[index].start;
var this_list_cat = this.list[index].cat;
var this_list_cat_counts = this_list_cat + "_counts";
var this_list_cat_time_sum = this_list_cat + "_time_sum"
if (typeof (this.cats[this_list_cat_counts]) == "undefined") this.cats.arr.push(this_list_cat);
if (typeof (this.cats[this_list_cat_time_sum]) == "undefined") this.cats[this_list_cat_time_sum] = 0;
if (typeof (this.cats[this_list_cat_counts]) == "undefined") this.cats[this_list_cat_counts] = 0;
this.cats[this_list_cat_time_sum] += this.list[index].time;
this.cats[this_list_cat_counts]++;
if (typeof (bench_glob) != "undefined" && bench_glob.length > 0) {
this.list[index].bench_glob_index = window.last_completed_bench;
}
}
benchmark.prototype.clear = function () {
this.list = [];
this.cats = [];
this.cats.arr = [];
this.includeSVG = true;
return true;
}
benchmark.prototype.print = function (all) {
var tbl = '<style>';
tbl += '.bench {width:317px;border-collapse:collapse;white-space:nowrap;}';
tbl += '.bench td, .bench th{font-size:12px;text-align:left;border:1px solid #444444; padding:2px}';
tbl += '.bench th{background-color:#DDDDDD;}';
tbl += '.bench tfoot td{background-color:#DDDDDD;}';
tbl += '.bench_foot{font-weight:bold;}';
tbl += '</style>';
tbl += '<table class="bench"><thead><tr>';
tbl += '<th>Num</th>';
tbl += '<th>Name</th>';
tbl += '<th>Category</th>';
tbl += '<th>Time</th>';
tbl += '</tr></thead>';
tbl += '<tbody>';
var time, totaltime = 0,
i, m;
if (this.list && this.list.length) {
m = this.list.length;
// print all
var start_index = 0;
if (!all) {
if (bench_glob.length) start_index = m - 3;
else start_index = m - 16;
if (start_index < 0) start_index = 0;
}
for (i = start_index; i < m; i++) {
time = (this.list[i].time);
tbl += '<tr><td>';
tbl += (i + 1);
tbl += '</td><td>';
tbl += this.list[i].name;
tbl += '</td><td>';
tbl += this.list[i].cat;
tbl += '</td><td>';
tbl += time;
tbl += '</td></tr>';
}
}
tbl += '</tbody>';
tbl += '</table>';
var tbl2 = "";
tbl2 += '<table style="margin-top:10px;margin-bottom:10px" class="bench"><thead><tr>';
tbl2 += '<th>Num</th>';
tbl2 += '<th>Category</th>';
tbl2 += '<th>Calls</th>';
tbl2 += '<th>Sum</th>';
tbl2 += '<th>Avg</th>';
tbl2 += '</tr></thead>';
tbl2 += '<tbody>';
m = this.cats.arr.length;
var item;
this.totals = "";
this.totals_arr = [];
var totals_arr_item = [];
var counts_sum = 0,
cat_time_sum = 0,
cat_time_avg = 0,
this_list_i_cat,
this_list_i_cat_time_sum, this_list_i_cat_counts;
if (m > 0) for (i = 0; i < m; i++) {
tbl2 += '<tr><td>';
item = (i + 1);
tbl2 += item;
tbl2 += '</td><td>';
this_list_i_cat = this.cats.arr[i];
item = this_list_i_cat;
tbl2 += item;
tbl2 += '</td><td>';
this_list_i_cat_counts = this.cats[this_list_i_cat + "_counts"];
item = this_list_i_cat_counts;
tbl2 += item;
counts_sum += this_list_i_cat_counts;
tbl2 += '</td><td>';
this_list_i_cat_time_sum = this.cats[this_list_i_cat + "_time_sum"];
item = this_list_i_cat_time_sum;
tbl2 += item;
cat_time_sum += this_list_i_cat_time_sum;
tbl2 += '</td><td>';
item = (this_list_i_cat_time_sum / this_list_i_cat_counts).toFixed(4);
tbl2 += item;
tbl2 += '</td></tr>';
}
tbl2 += '</tbody>';
if (m > 0) {
tbl2 += '<tfoot><tr><td class="bench_foot" colspan="2">Total</td>';
item = (counts_sum);
totals_arr_item.push(item);
this.totals += item + ";";
tbl2 += '<td>' + item + '</td>';
item = (cat_time_sum);
totals_arr_item.push(item);
this.totals += item + ";";
tbl2 += '<td>' + item + '</td>';
item = (cat_time_sum / counts_sum).toFixed(4);
totals_arr_item.push(item);
this.totals += item;
tbl2 += '<td style="padding: 4px; background-color: hsl(125, 73%, 80%); border: 3px solid black; font-weight: bold; font-size: 16px;">' + item + '</td>';
tbl2 += '</tr>';
tbl2 += '</tfoot>';
}
tbl2 += '</table>';
this.totals_arr.push(totals_arr_item);
tbl += tbl2;
if (benchmark_running) var disabled = "disabled";
else disabled = "";
tbl += '<button ' + disabled + ' onClick="try { ' + this.varname + '.clear();$(\'#benchmark_div\').html(' + this.varname + '.print()); return true; } catch (e) {return false}">Clear Benchmarks</button>';
tbl += '<button ' + disabled + ' onClick="try { $(\'#benchmark_div\').html(' + this.varname + '.print(1)); } catch (e) {return false}">Show all</button>';
return tbl;
}
benchmark.prototype.print_multiple_runs = function (str) {
var tbl2 = "";
tbl2 += '<table id="benchmark_multiple_table" style="margin-top:10px;margin-bottom:10px" class="bench"><thead><tr>';
tbl2 += '<th>Num</th>';
tbl2 += '<th>Calls</th>';
tbl2 += '<th>Sum</th>';
tbl2 += '<th>Avg</th>';
tbl2 += '</tr></thead>';
tbl2 += '<tbody>';
var item, counts_sum = 0,
time_sum = 0;
var times_array = [];
for (var i = 0, m = this.totals_arr_multiple.length; i < m; i++) {
times_array.push(this.totals_arr_multiple[i][1]);
}
var max = Array_max(times_array);
var min = Array_min(times_array);
var range = max - min;
var average = getAverageFromNumArr(times_array, 4);
var stdev = getStandardDeviation(times_array, 4);
var minus_range = min - average;
var plus_range = max - average;
for (var i = 0, m = this.totals_arr_multiple.length; i < m; i++) {
tbl2 += '<tr><td>';
item = (i + 1);
tbl2 += item;
tbl2 += '</td><td>';
item = this.totals_arr_multiple[i][0];
tbl2 += item;
tbl2 += '</td><td>';
item = this.totals_arr_multiple[i][1];
tbl2 += item;
time_sum += item;
tbl2 += '</td><td>';
item = this.totals_arr_multiple[i][2];
tbl2 += item;
tbl2 += '</td></tr>';
}
tbl2 += '<tr><td colspan="4" id="benchmark_multiple_status" style="display:none"></td></tr>';
if (!isNaN(average)) {
tbl2 += '<tr><td colspan="4">';
tbl2 += '<b>Average:</b> ' + average + " ms<br>";
tbl2 += '<b>Min:</b> ' + min + " ms<br>";
tbl2 += '<b>Max:</b> ' + max + " ms<br>";
tbl2 += '<b>Range:</b> ' + range.toFixed(4) + " ms<br>";
tbl2 += '<b>Minus-Range:</b> ' + minus_range.toFixed(4) + " ms<br>";
tbl2 += '<b>Plus-Range:</b> ' + plus_range.toFixed(4) + " ms<br>";
tbl2 += '<b>Stdev:</b> ' + stdev + " ms<br>";
tbl2 += '<b>Range/Average %:</b> ' + (range / average * 100).toFixed(4) + "<br>";
tbl2 += '<b>Minus-Range/Average %:</b> ' + (minus_range / average * 100).toFixed(4) + "<br>";
tbl2 += '<b>Plus-Range/Average %:</b> ' + (plus_range / average * 100).toFixed(4) + "<br>";
tbl2 += '<b>Stdev/Average %:</b> ' + (stdev / average * 100).toFixed(4) + "<br>";
tbl2 += '</td></tr>';
}
tbl2 += '</tbody>';
return tbl2;
}
window.benchmark = benchmark;
})(window);
// Programmer: Larry Battle
// Date: Mar 06, 2011
// Purpose: Calculate standard deviation, variance, and average among an array of numbers.
function isArray(obj) {
return Object.prototype.toString.call(obj) === "[object Array]";
}
;
function getNumWithSetDec(num, numOfDec) {
var pow10s = Math.pow(10, numOfDec || 0);
return (numOfDec) ? Math.round(pow10s * num) / pow10s : num;
}
;
function getAverageFromNumArr(numArr, numOfDec) {
if (!isArray(numArr)) {
return false;
}
var i = numArr.length,
sum = 0;
while (i--) {
sum += numArr[i];
}
return getNumWithSetDec((sum / numArr.length), numOfDec);
}
;
function getVariance(numArr, numOfDec) {
if (!isArray(numArr)) {
return false;
}
var avg = getAverageFromNumArr(numArr, numOfDec),
i = numArr.length,
v = 0;
while (i--) {
v += Math.pow((numArr[i] - avg), 2);
}
v /= numArr.length;
return getNumWithSetDec(v, numOfDec);
}
;
function getStandardDeviation(numArr, numOfDec) {
if (!isArray(numArr)) {
return false;
}
var stdDev = Math.sqrt(getVariance(numArr, numOfDec));
return getNumWithSetDec(stdDev, numOfDec);
}
;
function Array_max(array) {
return Math.max.apply(Math, array);
}
;
function Array_min(array) {
return Math.min.apply(Math, array);
}
;
// BENCHMARKING ENDS
function colorize_boxes_like_in_svg() {
var bg_color = $("#p").css("background-color");
bg_color = new RGBColor(bg_color);
var fill_color, stroke_color, fill_opacity, stroke_opacity, box;
for (var i = 1; i <= 3; i++) {
fill_color = $("#p" + i).css("fill");
fill_color = new RGBColor(fill_color);
fill_opacity = $("#p" + i).css("fill-opacity");
fill_color = fill_color.flattenRGBA(fill_opacity, bg_color);
stroke_color = $("#p" + i).css("stroke");
stroke_color = new RGBColor(stroke_color);
stroke_opacity = $("#p" + i).css("stroke-opacity");
stroke_color = stroke_color.flattenRGBA(stroke_opacity, bg_color);
if (i == 1) box = "#subject_box";
else if (i == 2) box = "#clip_box";
else if (i == 3) box = "#solution_box";
$(box).css("background-color", fill_color);
}
}
// The following class exists only for transferring color values from SVG to html table
// It could be got without this, but wanted to try this.
// May be I remove this and make precalculated values
/**
* A class to parse color values
* @author Stoyan Stefanov <[email protected]>
* @link http://www.phpied.com/rgb-color-parser-in-javascript/
* @license Use it if you like it
*/
function RGBColor(color_string) {
if (typeof(color_string) == "undefined") color_string = "";
this.ok = false;
// strip any leading #
if (color_string.charAt(0) == '#') { // remove # if any
color_string = color_string.substr(1, 6);
}
color_string = color_string.replace(/ /g, '');
color_string = color_string.toLowerCase();
// before getting into regexps, try simple matches
// and overwrite the input
var simple_colors = { aliceblue: 'f0f8ff', antiquewhite: 'faebd7', aqua: '00ffff', aquamarine: '7fffd4', azure: 'f0ffff', beige: 'f5f5dc', bisque: 'ffe4c4', black: '000000', blanchedalmond: 'ffebcd', blue: '0000ff', blueviolet: '8a2be2', brown: 'a52a2a', burlywood: 'deb887', cadetblue: '5f9ea0', chartreuse: '7fff00', chocolate: 'd2691e', coral: 'ff7f50', cornflowerblue: '6495ed', cornsilk: 'fff8dc', crimson: 'dc143c', cyan: '00ffff', darkblue: '00008b', darkcyan: '008b8b', darkgoldenrod: 'b8860b', darkgray: 'a9a9a9', darkgreen: '006400', darkkhaki: 'bdb76b', darkmagenta: '8b008b', darkolivegreen: '556b2f', darkorange: 'ff8c00', darkorchid: '9932cc', darkred: '8b0000', darksalmon: 'e9967a', darkseagreen: '8fbc8f', darkslateblue: '483d8b', darkslategray: '2f4f4f', darkturquoise: '00ced1', darkviolet: '9400d3', deeppink: 'ff1493', deepskyblue: '00bfff', dimgray: '696969', dodgerblue: '1e90ff', feldspar: 'd19275', firebrick: 'b22222', floralwhite: 'fffaf0', forestgreen: '228b22', fuchsia: 'ff00ff', gainsboro: 'dcdcdc', ghostwhite: 'f8f8ff', gold: 'ffd700', goldenrod: 'daa520', gray: '808080', green: '008000', greenyellow: 'adff2f', honeydew: 'f0fff0', hotpink: 'ff69b4', indianred: 'cd5c5c', indigo: '4b0082', ivory: 'fffff0', khaki: 'f0e68c', lavender: 'e6e6fa', lavenderblush: 'fff0f5', lawngreen: '7cfc00', lemonchiffon: 'fffacd', lightblue: 'add8e6', lightcoral: 'f08080', lightcyan: 'e0ffff', lightgoldenrodyellow: 'fafad2', lightgrey: 'd3d3d3', lightgreen: '90ee90', lightpink: 'ffb6c1', lightsalmon: 'ffa07a', lightseagreen: '20b2aa', lightskyblue: '87cefa', lightslateblue: '8470ff', lightslategray: '778899', lightsteelblue: 'b0c4de', lightyellow: 'ffffe0', lime: '00ff00', limegreen: '32cd32', linen: 'faf0e6', magenta: 'ff00ff', maroon: '800000', mediumaquamarine: '66cdaa', mediumblue: '0000cd', mediumorchid: 'ba55d3', mediumpurple: '9370d8', mediumseagreen: '3cb371', mediumslateblue: '7b68ee', mediumspringgreen: '00fa9a', mediumturquoise: '48d1cc', mediumvioletred: 'c71585', midnightblue: '191970', mintcream: 'f5fffa', mistyrose: 'ffe4e1', moccasin: 'ffe4b5', navajowhite: 'ffdead', navy: '000080', oldlace: 'fdf5e6', olive: '808000', olivedrab: '6b8e23', orange: 'ffa500', orangered: 'ff4500', orchid: 'da70d6', palegoldenrod: 'eee8aa', palegreen: '98fb98', paleturquoise: 'afeeee', palevioletred: 'd87093', papayawhip: 'ffefd5', peachpuff: 'ffdab9', peru: 'cd853f', pink: 'ffc0cb', plum: 'dda0dd', powderblue: 'b0e0e6', purple: '800080', red: 'ff0000', rosybrown: 'bc8f8f', royalblue: '4169e1', saddlebrown: '8b4513', salmon: 'fa8072', sandybrown: 'f4a460', seagreen: '2e8b57', seashell: 'fff5ee', sienna: 'a0522d', silver: 'c0c0c0', skyblue: '87ceeb', slateblue: '6a5acd', slategray: '708090', snow: 'fffafa', springgreen: '00ff7f', steelblue: '4682b4', tan: 'd2b48c', teal: '008080', thistle: 'd8bfd8', tomato: 'ff6347', turquoise: '40e0d0', violet: 'ee82ee', violetred: 'd02090', wheat: 'f5deb3', white: 'ffffff', whitesmoke: 'f5f5f5', yellow: 'ffff00', yellowgreen: '9acd32' };
for (var key in simple_colors) {
if (color_string == key) {
color_string = simple_colors[key];
}
}
// emd of simple type-in colors
// array of color definition objects
var color_defs = [
{
re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,
example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'],
process: function (bits) {
return [
parseInt(bits[1], 10),
parseInt(bits[2], 10),
parseInt(bits[3], 10)];
}
},
{
re: /^(\w{2})(\w{2})(\w{2})$/,
example: ['#00ff00', '336699'],
process: function (bits) {
return [
parseInt(bits[1], 16),
parseInt(bits[2], 16),
parseInt(bits[3], 16)];
}
},
{
re: /^(\w{1})(\w{1})(\w{1})$/,
example: ['#fb0', 'f0f'],
process: function (bits) {
return [
parseInt(bits[1] + bits[1], 16),
parseInt(bits[2] + bits[2], 16),
parseInt(bits[3] + bits[3], 16)];
}
}
];
// search through the definitions to find a match
for (var i = 0; i < color_defs.length; i++) {
var re = color_defs[i].re;
var processor = color_defs[i].process;
var bits = re.exec(color_string);
if (bits) {
channels = processor(bits);
this.r = channels[0];
this.g = channels[1];
this.b = channels[2];
this.ok = true;
}
}
// validate/cleanup values
this.r = (this.r < 0 || isNaN(this.r)) ? 0 : ((this.r > 255) ? 255 : this.r);
this.g = (this.g < 0 || isNaN(this.g)) ? 0 : ((this.g > 255) ? 255 : this.g);
this.b = (this.b < 0 || isNaN(this.b)) ? 0 : ((this.b > 255) ? 255 : this.b);
// some getters
this.toRGB = function () {
return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')';
};
this.toHex = function () {
var r = this.r.toString(16);
var g = this.g.toString(16);
var b = this.b.toString(16);
if (r.length == 1) r = '0' + r;
if (g.length == 1) g = '0' + g;
if (b.length == 1) b = '0' + b;
return '#' + r + g + b;
};
this.flattenRGBA = function (a, bg) {
var alpha = 1 - parseFloat(a);
this.r = Math.round((a * (this.r / 255) + (alpha * (bg.r / 255))) * 255);
this.g = Math.round((a * (this.g / 255) + (alpha * (bg.g / 255))) * 255);
this.b = Math.round((a * (this.b / 255) + (alpha * (bg.b / 255))) * 255);
return this.toHex();
};
}
// Not used, because using mouse and repeated events is better
function offset_key(e) {
return;
if (e.which == 38) {
make_offset(1);
}
else if (e.which == 40) {
make_offset(-1);
}
e.stopPropagation();
e.preventDefault();
}
function round_to(num, dec) {
if (typeof (num) == "undefined" || typeof (dec) == "undefined" || isNaN(dec)) {
alert("Cannot round other than number");
return false;
}
else return Math.round(num * Math.pow(10, dec)) / Math.pow(10, dec);
}
function update_enlarged_SVG_if_needed() {
if (update_enlarged_SVG) {
show_svg_source_click("non_click");
svg_source_enlarge();
}
else if (update_enlarged_SVG_source && !update_enlarged_SVG) {
show_svg_source_click("non_click");
}
}
function to_printable(a) {
return a.toFixed(1);
}
function get_polys(scale_again) {
var polygon = parseInt($('input[type="radio"][name="polygons"]:checked').val(), 10);
var polys;
if (polygon === 0) {
polys = get_gb_and_arrow();
ss = polys.ss;
cc = polys.cc;
}
else if (polygon == 1) {
polys = get_text_polys();
ss = polys.ss;
cc = polys.cc;
}
else if (polygon == 2) {
polys = get_rectangle_polys();
ss = polys.ss;
cc = polys.cc;
}
else if (polygon == 3) {
polys = get_same_self_intersecting_polys();
ss = polys.ss;
cc = polys.cc;
}
else if (polygon == 6) {
polys = get_star_and_rect();
ss = polys.ss;
cc = polys.cc;
}
else if (polygon == 7) {
polys = get_spiral_and_rects();
ss = polys.ss;
cc = polys.cc;
}
else if (polygon == 8) {
polys = get_rounded_grid_and_star();
ss = polys.ss;
cc = polys.cc;
}
else if (polygon == 9) {
polys = get_glyph_and_grid();
ss = polys.ss;
cc = polys.cc;
}
else if (polygon == 10) {
polys = get_custom_poly();
ss = polys.ss;
cc = polys.cc;
}
else if (polygon == 4 || polygon == 5) {
if (!random_subj) random_subj = get_random_polys("subj");
if (!random_clip) random_clip = get_random_polys("clip");
if (scale_again) {
random_subj = scale_again_random_poly(random_subj);
random_clip = scale_again_random_poly(random_clip);
ss = random_subj;
cc = random_clip;
rnd_sett.scale = scale;
}
else {
ss = random_subj;
cc = random_clip;
}
}
sss = [
[]
];
}
// Main function which setups defaults
// and attach events
// and finally draw the default svg image
function main() {
// formats internal representation of polygons to
// specified output format and prints them on input fields
$("#output_format").change(function () {
var selected_val = parseInt($(this).val(), 10);
output_format = selected_val;
if ($("#custom_polygons_fieldset").css("display") != "none") {
var subj = $("#custom_polygon_subj").val();
var clip = $("#custom_polygon_clip").val();
subj = normalize_clipper_poly(subj, true); // quiet
clip = normalize_clipper_poly(clip, true); // quiet
if (subj !== false && clip !== false) {
$("#custom_polygon_subj").val(format_output(subj));
$("#custom_polygon_clip").val(format_output(clip));
}
}
var polygon_explorer_string = $("#polygon_explorer_string_inp").val();
polygon_explorer_string = normalize_clipper_poly(polygon_explorer_string, true); // quiet
if (polygon_explorer_string !== false) {
$("#polygon_explorer_string_inp").val(format_output(polygon_explorer_string));
}
});
$("#sample_custom_polygon").change(function () {
var polygon = parseInt($(this).val(), 10);
var polys;
global_do_not_round_and_scale = true;
var subj = "",
clip = "";
if (polygon === "") {
subj = "";
clip = "";
}
else if (polygon === 0) {
polys = get_gb_and_arrow();
subj = polys.ss;
clip = polys.cc;
}
else if (polygon == 1) {
polys = get_text_polys();
subj = polys.ss;
clip = polys.cc;
}
else if (polygon == 2) {
polys = get_rectangle_polys();
subj = polys.ss;
clip = polys.cc;
}
else if (polygon == 3) {
polys = get_same_self_intersecting_polys();
subj = polys.ss;
clip = polys.cc;
}
else if (polygon == 4 || polygon == 5) {
subj = get_random_polys("subj", polygon);
clip = get_random_polys("clip", polygon);
}
else if (polygon == 6) {
polys = get_star_and_rect();
subj = polys.ss;
clip = polys.cc;
}
else if (polygon == 7) {
polys = get_spiral_and_rects();
subj = polys.ss;
clip = polys.cc;
}
else if (polygon == 8) {
polys = get_rounded_grid_and_star();
subj = polys.ss;
clip = polys.cc;
}
else if (polygon == 9) {
polys = get_glyph_and_grid();
subj = polys.ss;
clip = polys.cc;
}
else if (polygon == 10) {
polys = get_custom_poly();
subj = polys.ss;
clip = polys.cc;
}
global_do_not_round_and_scale = false;
if (subj != "") subj = JSON.stringify(subj);
if (clip != "") clip = JSON.stringify(clip);
$("#custom_polygon_subj").val(format_output(subj));
$("#custom_polygon_clip").val(format_output(clip));
});
$("#help_custom_polygon").click(function () {
var txt = "";
txt += 'A) You can add your own custom polygons in several formats:\n\n';
txt += '1) The program uses as an inner default the following format: JSON-stringified array of arrays of point objects eg. [[{"X":100,"Y":100},{"X":200,"Y":100},{"X":200,"Y":200},{"X":100,"Y":200}],[{"X":110,"Y":110},{"X":210,"Y":110},{"X":210,"Y":210},{"X":110,"Y":210}]]. This format allows to input sub polygons. Each sub polygon is an array of point objects. This format makes it easy to transfer polygons to other programs that use Clipper library and is suitable for storing polygons in database.\n\n';
txt += '2) JSON-stringified array of point objects eg. [{"X":100,"Y":100},{"X":200,"Y":100},{"X":200,"Y":200},{"X":100,"Y":200}]. This format doesn\'t allow to input sub polygons.\n\n';
txt += '3) JSON-stringified array of arrays of coordinates without "X" and "Y" eg. [[100,100,200,100,200,200,100,200],[110,110,210,110,210,210,110,210]]. This format allows to input sub polygons. Each sub polygon is an array of coordinates so that each x coordinate is followed by an y coordinate. This format makes it easy to transfer polygons to other programs that use Clipper library and is suitable for storing polygons in database.\n\n';
txt += '4) JSON-stringified array of x and y coordinates eg. [100,100,200,100,200,200,100,200] or [100 100 200 100 200 200 100 200] or [100 100,200 100,200 200,100 200] or the same without []:s. This format doesn\'t allow to input sub polygons.\n\n';
txt += '5) SVG path strings with commands MLVHZ or mlvhz eg. M100,100 L200,100 L200,200 L100,200Z M110,110 L210,110 L210,210 L110,210Z. This format allows to input sub polygons. Each subpolygon starts with M (moveto) command.\n\n';
txt += '\n';
txt += 'B) Custom polygons are saved in browser\'s Local Storage, so they should be tolerant for page reload and browser crashes.\n';
txt += '\n';
alert(txt);
});
$("#help_builtin_polygon_sets").click(function () {
var txt = '';
txt += 'Builtin polygon sets\n\n';
txt += 'You can add builtin polygon sets into Subj and Clip input fields to edit copies of them.\n\n';
txt += 'Note! Before saving, nothing happens. After saving, the SVG window is also updated.';
alert(txt);
});
$("#help_output_format").click(function () {
var txt = '';
txt += 'Output format\n\n';
txt += 'To change the polygon coordinate output format please use the above dropdown. The available formats are:\n\n';
txt += '- Clipper: [[{"X":100,"Y":100},{"X":200,"Y":200}]]\n\n';
txt += '- Plain: [[100,100,200,200]]\n\n';
txt += '- SVG: M100,100L200,200Z\n\n';
txt += 'There are two places where this has effect: 1) the above text box 2) the Subj and Clip text boxes in Custom Polygon fieldset.';
alert(txt);
});
$("#remove_custom_polygon").click(function () {
var selected_value = $("#custom_polygons_select").val();
if (selected_value + "" === "0") {
alert("Cannot remove the default polygon.");
}
else if (selected_value) {
if (confirm("Remove custom polygon " + selected_value + "?")) {
var arr = $.totalStorage('custom_polygons');
arr[selected_value] = null;
$.totalStorage('custom_polygons', arr);
update_custom_polygons_select();
}
}
else alert("Nothing removable.");
});
$("#removeall_custom_polygon").click(function () {
var count = $("#custom_polygons_select option").length;
if (count > 1) {
if (confirm("Remove all " + (count - 1) + " custom polygons?")) {
$.totalStorage('custom_polygons', []);
set_default_custom_polygon();
update_custom_polygons_select();
}
}
else alert("Nothing removable.");
});
$("#save_custom_polygon").click(function (e) {
var subj = $("#custom_polygon_subj").val();
var clip = $("#custom_polygon_clip").val();
subj = normalize_clipper_poly(subj);
clip = normalize_clipper_poly(clip);
if (subj === false || clip === false) return false;
if (typeof ($.totalStorage('custom_polygons')) == "undefined" || $.totalStorage('custom_polygons') === null) {
set_default_custom_polygon();
}
var polygon_set = {};
polygon_set.subj = subj;
polygon_set.clip = clip;
var arr2 = $.totalStorage('custom_polygons');
var selected_value = $("#custom_polygons_select").val();
if (selected_value + "" !== "0" && selected_value) {
arr2[selected_value] = polygon_set;
$.totalStorage('custom_polygons', arr2);
update_custom_polygons_select();
show_alert(e, this, "Polygon " + (selected_value) + " updated!");
}
else if (selected_value + "" === "0") {
alert("The default custom polygon cannot be overwrited. If you want to modify it, save it first as a new.");
}
else alert("Polygon update failed!");
});
$("#add_as_new_custom_polygon").click(function (e) {
var subj = $("#custom_polygon_subj").val();
var clip = $("#custom_polygon_clip").val();
subj = normalize_clipper_poly(subj);
clip = normalize_clipper_poly(clip);
if (subj === false || clip === false) return false;
if (typeof ($.totalStorage('custom_polygons')) == "undefined" || $.totalStorage('custom_polygons') === null) {
set_default_custom_polygon();
}
var polygon_set = {};
polygon_set.subj = subj;
polygon_set.clip = clip;
var arr2 = $.totalStorage('custom_polygons');
arr2.push(polygon_set);
$.totalStorage('custom_polygons', arr2);
update_custom_polygons_select();
$('#custom_polygons_select').val(arr2.length - 1).change();
show_alert(e, this, "New polygon " + (arr2.length - 1) + " added!");
});
$("#custom_polygons_select").change(function () {
var selected_value = $("#custom_polygons_select").val();
if (!selected_value && selected_value + "" !== "0") selected_value = 0;
var arr = $.totalStorage('custom_polygons');
if (isArray(arr) && arr.length && typeof (arr[selected_value]) != "undefined") {
$("#custom_polygon_subj").val(format_output(arr[selected_value].subj));
$("#custom_polygon_clip").val(format_output(arr[selected_value].clip));
make_clip();
}
});
$("input[type='radio'][name='polygons']").change(function (e) {
var val = parseInt($(this).val(), 10);
if (val == 10) {
$("#random_polygons_fieldset").css("display", "none");
$("#custom_polygons_fieldset").css("display", "block");
set_default_custom_polygon();
update_custom_polygons_select();
update_fieldset_heights();
$("#custom_polygons_select").change();
make_clip();
return;
}
else $("#custom_polygons_fieldset").css("display", "none");
if (val == 4 || val == 5) {
$("#random_polygons_fieldset").css("display", "block");
if (val == 4) rnd_sett_defaults.current = "rect";
else rnd_sett_defaults.current = "norm";
// Test for ranges
if (rnd_sett.clip_point_count < rnd_sett_defaults[rnd_sett_defaults.current].min.clip_point_count) rnd_sett.clip_point_count = rnd_sett_defaults[rnd_sett_defaults.current].min.clip_point_count;
if (rnd_sett.clip_point_count > rnd_sett_defaults[rnd_sett_defaults.current].max.clip_point_count) rnd_sett.clip_point_count = rnd_sett_defaults[rnd_sett_defaults.current].max.clip_point_count;
$('#clip_point_count').val(rnd_sett.clip_point_count);
if (rnd_sett.clip_polygon_count < rnd_sett_defaults[rnd_sett_defaults.current].min.clip_polygon_count) rnd_sett.clip_polygon_count = rnd_sett_defaults[rnd_sett_defaults.current].min.clip_polygon_count;
if (rnd_sett.clip_polygon_count > rnd_sett_defaults[rnd_sett_defaults.current].max.clip_polygon_count) rnd_sett.clip_polygon_count = rnd_sett_defaults[rnd_sett_defaults.current].max.clip_polygon_count;
$('#clip_polygon_count').val(rnd_sett.clip_polygon_count);
if (rnd_sett.subj_point_count < rnd_sett_defaults[rnd_sett_defaults.current].min.subj_point_count) rnd_sett.subj_point_count = rnd_sett_defaults[rnd_sett_defaults.current].min.subj_point_count;
if (rnd_sett.subj_point_count > rnd_sett_defaults[rnd_sett_defaults.current].max.subj_point_count) rnd_sett.subj_point_count = rnd_sett_defaults[rnd_sett_defaults.current].max.subj_point_count;
$('#subj_point_count').val(rnd_sett.subj_point_count);
if (rnd_sett.subj_polygon_count < rnd_sett_defaults[rnd_sett_defaults.current].min.subj_polygon_count) rnd_sett.subj_polygon_count = rnd_sett_defaults[rnd_sett_defaults.current].min.subj_polygon_count;
if (rnd_sett.subj_polygon_count > rnd_sett_defaults[rnd_sett_defaults.current].max.subj_polygon_count) rnd_sett.subj_polygon_count = rnd_sett_defaults[rnd_sett_defaults.current].max.subj_polygon_count;
$('#subj_polygon_count').val(rnd_sett.subj_polygon_count);
random_subj = get_random_polys("subj", val);
random_clip = get_random_polys("clip", val);
}
else $("#random_polygons_fieldset").css("display", "none");
make_clip();
update_fieldset_heights();
});
$('#generate_random_polygons').hold(function (e) {
random_subj = get_random_polys("subj");
random_clip = get_random_polys("clip");
make_clip();
}, {
duration: 300,
speed: 0,
min: 150
});
$("input[name='clipType']").change(function () {
if ($('input[type="radio"][name="clipType"][value=""]').is(":checked")) {
$('input[type="radio"][name="offsettable_poly"][value="1"]').attr('checked', 'checked');
offsettable_poly = 1;
}
else {
$("#offsettable_poly3").attr('checked', 'checked');
offsettable_poly = 3;
}
clipType = $('input[type="radio"][name="clipType"]:checked').val();
if (clipType !== "") clipType = parseInt(clipType, 10);
make_clip();
});
$("input[name='subject_fillType']").change(function () {
subject_fillType = parseInt(this.value, 10);
make_clip();
});
$("input[name='clip_fillType']").change(function () {
clip_fillType = parseInt(this.value, 10);
make_clip();
});
$("input[name='offsettable_poly']").change(function () {
offsettable_poly = parseInt(this.value, 10);
// When offsettable poly is set to Subject or Clip, then boolean operations are not done.
// To show this to user, set clipType to "No"
if (offsettable_poly == 1 || offsettable_poly == 2) {
$('input[type="radio"][name="clipType"][value=""]').attr('checked', 'checked');
clipType = "";
}
make_clip();
});
$('#scale_minus').hold(function () {
var scale_orig = $('#scale').val();
if (scale_orig && !isNaN(scale_orig) && parseInt(scale_orig, 10).toString() !== "0") scale = parseFloat(scale_orig);
scale = scale - scale_addition;
scale = Math.round(scale / scale_addition) * scale_addition;
if (scale <= 0) scale = 1.0;
$('#scale').val(to_printable(scale));
$('#scale').trigger('change');
}, {
duration: 300,
speed: 0,
min: 150
});
$('#scale').change(function () {
if (this.value && !isNaN(this.value) && parseInt(this.value, 10).toString() !== "0") {
scale = parseFloat(this.value);
get_polys(true);
sss = cc;
make_clip();
}
else alert("Scale has to be a number");
});
$('#scale_plus').hold(function () {
var scale_orig = $('#scale').val();
if (scale_orig && !isNaN(scale_orig) && parseInt(scale_orig, 10).toString() !== "0") scale = parseFloat(scale_orig);
scale = scale + scale_addition;
scale = Math.round(scale / scale_addition) * scale_addition;
$('#scale').val(to_printable(scale));
$('#scale').trigger('change');
}, {
duration: 300,
speed: 0,
min: 150
});
$('#delta_minus').hold(function () {
var delta_orig = $('#delta').val();
if (!isNaN(delta_orig)) delta = parseFloat(delta_orig);
delta = delta - 1;
make_clip();
}, {
duration: 300,
speed: 0,
min: 150
});
$('#delta').change(function (e) {
var delta_orig = $('#delta').val();
if (!isNaN(delta_orig)) delta = parseFloat(delta_orig);
make_clip();
});
$('#delta_plus').hold(function () {
var delta_orig = $('#delta').val();
if (!isNaN(delta_orig)) delta = parseFloat(delta_orig);
delta = delta + 1;
make_clip();
}, {
duration: 300,
speed: 0,
min: 150
});
$("input[name='joinType']").change(function () {
joinType = parseInt(this.value, 10);
//make_offset();
make_clip();
});
$('#miterLimit_minus').hold(function () {
var miterLimit_orig = $('#miterLimit').val();
if (!isNaN(miterLimit_orig)) miterLimit = parseFloat(miterLimit_orig);
miterLimit = miterLimit - 0.1;
if (miterLimit < 1.0) miterLimit = 1.0;
make_clip();
}, {
duration: 300,
speed: 0,
min: 150
});
$("#miterLimit").change(function () {
miterLimit = parseFloat(this.value);
make_clip();
});
$("#cleandelta").change(function () {
var cleandelta_orig = $(this).val();
var this_value = parseFloat(this.value);
if (!isNaN(this_value)) cleandelta = this_value;
//else cleandelta = cleandelta_orig;
make_clip();
});
$("#lighten_distance").change(function () {
var lighten_distance_orig = $(this).val();
var this_value = parseFloat(this.value);
if (!isNaN(this_value)) lighten_distance = this_value;
//else lighten_distance = lighten_distance_orig;
make_clip();
});
$('#miterLimit_plus').hold(function () {
var miterLimit_orig = $('#miterLimit').val();
if (!isNaN(miterLimit_orig)) miterLimit = parseFloat(miterLimit_orig);
miterLimit = miterLimit + 0.1;
if (miterLimit < 1.0) miterLimit = 1.0;
make_clip();
}, {
duration: 300,
speed: 0,
min: 150
});
$("#AutoFix").change(function () {
if ($(this).attr('checked')) AutoFix = true;
else AutoFix = false;
make_clip();
});
$("#ExPolygons").change(function () {
if ($(this).attr('checked')) ExPolygons = true;
else ExPolygons = false;
if (SolutionPolygonClicked) $("#polygon_explorer_string_inp").val(format_output(SolutionPolygonString, "ExPolygons"));
//make_clip();
});
$("#Simplify").change(function () {
if ($(this).attr('checked')) Simplify = true;
else Simplify = false;
make_clip();
});
$("#clean").change(function () {
if ($(this).attr('checked')) {
if ($("#cleandelta").val() + "".trim() == "") {
cleandelta = cleandelta_default;
$("#cleandelta").val(cleandelta);
}
clean = true;
}
else {
clean = false;
}
make_clip();
});
$("#lighten").change(function () {
if ($(this).attr('checked')) lighten = true;
else lighten = false;
make_clip();
});
$("#lighten").change(function () {
if ($(this).attr('checked')) {
if ($("#lighten_distance").val() + "".trim() == "") {
lighten_distance = lighten_distance_default;
$("#lighten_distance").val(lighten_distance);
}
lighten = true;
}
else {
lighten = false;
}
make_clip();
});
$('#subj_polygon_count_minus').hold(function () {
var subj_polygon_count_orig = $('#subj_polygon_count').val();
if (!isNaN(subj_polygon_count_orig)) rnd_sett.subj_polygon_count = parseFloat(subj_polygon_count_orig);
rnd_sett.subj_polygon_count = rnd_sett.subj_polygon_count - 1;
if (rnd_sett.subj_polygon_count < rnd_sett_defaults[rnd_sett_defaults.current].min.subj_polygon_count) rnd_sett.subj_polygon_count = rnd_sett_defaults[rnd_sett_defaults.current].min.subj_polygon_count;
$('#subj_polygon_count').val(rnd_sett.subj_polygon_count);
random_subj = get_random_polys("subj");
random_clip = get_random_polys("clip");
make_clip();
}, {
duration: 300,
speed: 0,
min: 150
});
$('#subj_polygon_count').change(function (e) {
var subj_polygon_count_orig = $('#subj_polygon_count').val();
if (!isNaN(subj_polygon_count_orig)) rnd_sett.subj_polygon_count = parseFloat(subj_polygon_count_orig);
if (rnd_sett.subj_polygon_count < rnd_sett_defaults[rnd_sett_defaults.current].min.subj_polygon_count) rnd_sett.subj_polygon_count = rnd_sett_defaults[rnd_sett_defaults.current].min.subj_polygon_count;
if (rnd_sett.subj_polygon_count > rnd_sett_defaults[rnd_sett_defaults.current].max.subj_polygon_count) rnd_sett.subj_polygon_count = rnd_sett_defaults[rnd_sett_defaults.current].max.subj_polygon_count;
$('#subj_polygon_count').val(rnd_sett.subj_polygon_count);
random_subj = get_random_polys("subj");
random_clip = get_random_polys("clip");
make_clip();
});
$('#subj_polygon_count_plus').hold(function () {
var subj_polygon_count_orig = $('#subj_polygon_count').val();
if (!isNaN(subj_polygon_count_orig)) rnd_sett.subj_polygon_count = parseFloat(subj_polygon_count_orig);
rnd_sett.subj_polygon_count = rnd_sett.subj_polygon_count + 1;
if (rnd_sett.subj_polygon_count > rnd_sett_defaults[rnd_sett_defaults.current].max.subj_polygon_count) rnd_sett.subj_polygon_count = rnd_sett_defaults[rnd_sett_defaults.current].max.subj_polygon_count;
$('#subj_polygon_count').val(rnd_sett.subj_polygon_count);
random_subj = get_random_polys("subj");
random_clip = get_random_polys("clip");
make_clip();
}, {
duration: 300,
speed: 0,
min: 150
});
$('#subj_point_count_minus').hold(function () {
var subj_point_count_orig = $('#subj_point_count').val();
if (!isNaN(subj_point_count_orig)) rnd_sett.subj_point_count = parseFloat(subj_point_count_orig);
rnd_sett.subj_point_count = rnd_sett.subj_point_count - 1;
if (rnd_sett.subj_point_count < rnd_sett_defaults[rnd_sett_defaults.current].min.subj_point_count) rnd_sett.subj_point_count = rnd_sett_defaults[rnd_sett_defaults.current].min.subj_point_count;
$('#subj_point_count').val(rnd_sett.subj_point_count);
random_subj = get_random_polys("subj");
random_clip = get_random_polys("clip");
make_clip();
}, {
duration: 300,
speed: 0,
min: 150
});
$('#subj_point_count').change(function (e) {
var subj_point_count_orig = $('#subj_point_count').val();
if (!isNaN(subj_point_count_orig)) rnd_sett.subj_point_count = parseFloat(subj_point_count_orig);
if (rnd_sett.subj_point_count < rnd_sett_defaults[rnd_sett_defaults.current].min.subj_point_count) rnd_sett.subj_point_count = rnd_sett_defaults[rnd_sett_defaults.current].min.subj_point_count;
if (rnd_sett.subj_point_count > rnd_sett_defaults[rnd_sett_defaults.current].max.subj_point_count) rnd_sett.subj_point_count = rnd_sett_defaults[rnd_sett_defaults.current].max.subj_point_count;
$('#subj_point_count').val(rnd_sett.subj_point_count);
random_subj = get_random_polys("subj");
random_clip = get_random_polys("clip");
make_clip();
});
$('#subj_point_count_plus').hold(function () {
var subj_point_count_orig = $('#subj_point_count').val();
if (!isNaN(subj_point_count_orig)) rnd_sett.subj_point_count = parseFloat(subj_point_count_orig);
rnd_sett.subj_point_count = rnd_sett.subj_point_count + 1;
if (rnd_sett.subj_point_count > rnd_sett_defaults[rnd_sett_defaults.current].max.subj_point_count) rnd_sett.subj_point_count = rnd_sett_defaults[rnd_sett_defaults.current].max.subj_point_count;
$('#subj_point_count').val(rnd_sett.subj_point_count);
random_subj = get_random_polys("subj");
random_clip = get_random_polys("clip");
make_clip();
}, {
duration: 300,
speed: 0,
min: 150
});
$('#clip_polygon_count_minus').hold(function () {
var clip_polygon_count_orig = $('#clip_polygon_count').val();
if (!isNaN(clip_polygon_count_orig)) rnd_sett.clip_polygon_count = parseFloat(clip_polygon_count_orig);
rnd_sett.clip_polygon_count = rnd_sett.clip_polygon_count - 1;
if (rnd_sett.clip_polygon_count < rnd_sett_defaults[rnd_sett_defaults.current].min.clip_polygon_count) rnd_sett.clip_polygon_count = rnd_sett_defaults[rnd_sett_defaults.current].min.clip_polygon_count;
$('#clip_polygon_count').val(rnd_sett.clip_polygon_count);
random_subj = get_random_polys("subj");
random_clip = get_random_polys("clip");
make_clip();
}, {
duration: 300,
speed: 0,
min: 150
});
$('#clip_polygon_count').change(function (e) {
var clip_polygon_count_orig = $('#clip_polygon_count').val();
if (!isNaN(clip_polygon_count_orig)) rnd_sett.clip_polygon_count = parseFloat(clip_polygon_count_orig);
if (rnd_sett.clip_polygon_count < rnd_sett_defaults[rnd_sett_defaults.current].min.clip_polygon_count) rnd_sett.clip_polygon_count = rnd_sett_defaults[rnd_sett_defaults.current].min.clip_polygon_count;
if (rnd_sett.clip_polygon_count > rnd_sett_defaults[rnd_sett_defaults.current].max.clip_polygon_count) rnd_sett.clip_polygon_count = rnd_sett_defaults[rnd_sett_defaults.current].max.clip_polygon_count;
$('#clip_polygon_count').val(rnd_sett.clip_polygon_count);
random_subj = get_random_polys("subj");
random_clip = get_random_polys("clip");
make_clip();
});
$('#clip_polygon_count_plus').hold(function () {
var clip_polygon_count_orig = $('#clip_polygon_count').val();
if (!isNaN(clip_polygon_count_orig)) rnd_sett.clip_polygon_count = parseFloat(clip_polygon_count_orig);
rnd_sett.clip_polygon_count = rnd_sett.clip_polygon_count + 1;
if (rnd_sett.clip_polygon_count > rnd_sett_defaults[rnd_sett_defaults.current].max.clip_polygon_count) rnd_sett.clip_polygon_count = rnd_sett_defaults[rnd_sett_defaults.current].max.clip_polygon_count;
$('#clip_polygon_count').val(rnd_sett.clip_polygon_count);
random_subj = get_random_polys("subj");
random_clip = get_random_polys("clip");
make_clip();
}, {
duration: 300,
speed: 0,
min: 150
});
$('#clip_point_count_minus').hold(function () {
var clip_point_count_orig = $('#clip_point_count').val();
if (!isNaN(clip_point_count_orig)) rnd_sett.clip_point_count = parseFloat(clip_point_count_orig);
rnd_sett.clip_point_count = rnd_sett.clip_point_count - 1;
if (rnd_sett.clip_point_count < rnd_sett_defaults[rnd_sett_defaults.current].min.clip_point_count) rnd_sett.clip_point_count = rnd_sett_defaults[rnd_sett_defaults.current].min.clip_point_count;
$('#clip_point_count').val(rnd_sett.clip_point_count);
random_subj = get_random_polys("subj");
random_clip = get_random_polys("clip");
make_clip();
}, {
duration: 300,
speed: 0,
min: 150
});
$('#clip_point_count').change(function (e) {
var clip_point_count_orig = $('#clip_point_count').val();
if (!isNaN(clip_point_count_orig)) rnd_sett.clip_point_count = parseFloat(clip_point_count_orig);
if (rnd_sett.clip_point_count < rnd_sett_defaults[rnd_sett_defaults.current].min.clip_point_count) rnd_sett.clip_point_count = rnd_sett_defaults[rnd_sett_defaults.current].min.clip_point_count;
if (rnd_sett.clip_point_count > rnd_sett_defaults[rnd_sett_defaults.current].max.clip_point_count) rnd_sett.clip_point_count = rnd_sett_defaults[rnd_sett_defaults.current].max.clip_point_count;
$('#clip_point_count').val(rnd_sett.clip_point_count);
random_subj = get_random_polys("subj");
random_clip = get_random_polys("clip");
make_clip();
});
$('#clip_point_count_plus').hold(function () {
var clip_point_count_orig = $('#clip_point_count').val();
if (!isNaN(clip_point_count_orig)) rnd_sett.clip_point_count = parseFloat(clip_point_count_orig);
rnd_sett.clip_point_count = rnd_sett.clip_point_count + 1;
if (rnd_sett.clip_point_count > rnd_sett_defaults[rnd_sett_defaults.current].max.clip_point_count) rnd_sett.clip_point_count = rnd_sett_defaults[rnd_sett_defaults.current].max.clip_point_count;
$('#clip_point_count').val(rnd_sett.clip_point_count);
random_subj = get_random_polys("subj");
random_clip = get_random_polys("clip");
make_clip();
}, {
duration: 300,
speed: 0,
min: 150
});
$("#bevel").change(function () {
if ($(this).attr('checked')) {
bevel = true;
$("#p3").attr("filter", "url(#innerbewel)");
}
else {
bevel = false;
$("#p3").removeAttr("filter");
}
update_enlarged_SVG_if_needed();
});
$("#show_svg_source").click(show_svg_source_click);
$('#sub_poly_links_update').change(function () {
if ($(this).is(':checked')) {
sub_poly_links_update = 1;
if (!p) p = SVG.create();
if (p1) p1.remove();
if (p2) p2.remove();
if (p3) p3.remove();
SVG.addpaths(ss, cc, off_result, subject_fillType, clip_fillType);
}
else {
sub_poly_links_update = 0;
$("#subj_subpolygons, #subj_points_in_subpolygons, #subj_points_total, #clip_subpolygons, #clip_points_in_subpolygons, #clip_points_total, #solution_subpolygons, #solution_points_in_subpolygons, #solution_points_total, #points_total, #all_subpolygons").html("");
}
});
$("#output_format").val(output_format);
myresize();
$("document").mousedown(function () {
ismousedown = true;
});
$("document").mouseup(function () {
ismousedown = false;
});
$("#benchmark1,#benchmark2,#benchmark1b,#benchmark2b").click(function () {
clicked_benchmark_button_id = $(this).attr("id");
if (benchmark_running && !benchmark_automatic_click) {
for (var lsk = 0; lsk < bench_glob.length; lsk++) {
clearTimeout(bench_glob[lsk].setTimeout);
}
bench_glob.length = 0;
repeat = 0;
benchmark_running = 0;
ClipperLib.MaxSteps = ClipperLib_MaxSteps_original;
$("#" + clicked_benchmark_button_id).html($("#" + clicked_benchmark_button_id).html().replace("Stop", "Run"));
$("#" + clicked_benchmark_button_id).attr("title", $("#" + clicked_benchmark_button_id).attr("title").replace("Stop", "Execute"));
$("button,input,select").removeAttr('disabled');
$('#sub_poly_links_update').trigger("change");
return;
}
else {
// disable buttons that are not allowed to click when running
$("button,input,select").attr('disabled', 'disabled');
$("#benchmark1,#benchmark2,#benchmark1b,#benchmark2b").each(function () {
var $this = $(this);
if ($this.attr("id") != clicked_benchmark_button_id) $this.attr('disabled', 'disabled');
else $this.removeAttr('disabled');
});
}
benchmark_automatic_click = 0;
benchmark_running = 1;
ClipperLib.MaxSteps = 10;
$("#" + clicked_benchmark_button_id).html($("#" + clicked_benchmark_button_id).html().replace("Run", "Stop"));
$("#" + clicked_benchmark_button_id).attr("title", $("#" + clicked_benchmark_button_id).attr("title").replace("Execute", "Stop"));
bench.clear();
bench.includeSVG = false;
var scaleLocal;
var polygon_id;
var deltaLocal, clipTypeLocal, offsettable_polyLocal_start, offsettable_polyLocal_end;
var offsettable_polyLocal, joinTypeLocal, miterLimitLocal, miterLimitLocal_start, miterLimitLocal_end;
var fillTypeLocal, fillTypeLocal_start, fillTypeLocal_end;
var timeout_time = 0;
var timeout_time_addition = 100;
window.last_completed_bench = "";
bench_glob.length = 0;
timeout_time = 0;
timeout_time_addition = 0;
latest_time = 10;
window.last_completed_bench = "";
var count;
var deltaLocals = [-5, 0, 10, 30];
var deltaLocal_i, m;
var this_id = $(this).attr("id");
if (this_id == "benchmark1b" || this_id == "benchmark2b") repeat_times = 5;
else repeat_times = 1;
for (count = 0; count < 2; count++) {
if (this_id == "benchmark1" || this_id == "benchmark1b") {
scaleLocal = 100;
if (count === 1) continue;
}
else if (this_id == "benchmark2" || this_id == "benchmark2b") {
scaleLocal = 100000000;
if (count === 1) continue;
}
for (polygon_id = 0; polygon_id < 10; polygon_id++) {
if (!(polygon_id == 0 || polygon_id == 1 || polygon_id == 7 || polygon_id == 8 || polygon_id == 9)) continue;
if (polygon_id == 4 || polygon_id == 5) {
fillTypeLocal_start = 0;
fillTypeLocal_end = 1;
}
else {
fillTypeLocal_start = 1;
fillTypeLocal_end = 1
}
for (fillTypeLocal = fillTypeLocal_start; fillTypeLocal < fillTypeLocal_end + 1; fillTypeLocal++) {
for (clipTypeLocal = 0; clipTypeLocal < 5; clipTypeLocal++) {
if (clipTypeLocal === 0) {
offsettable_polyLocal_start = 1;
offsettable_polyLocal_end = 2;
}
else {
offsettable_polyLocal_start = 3;
offsettable_polyLocal_end = 3;
}
for (offsettable_polyLocal = offsettable_polyLocal_start; offsettable_polyLocal < offsettable_polyLocal_end + 1; offsettable_polyLocal++) {
if (polygon_id === 0 && offsettable_polyLocal == 2) continue;
for (joinTypeLocal = 0; joinTypeLocal < 3; joinTypeLocal++) {
for (deltaLocal_i = 0, m = deltaLocals.length; deltaLocal_i < m; deltaLocal_i++) {
deltaLocal = deltaLocals[deltaLocal_i];
if (joinTypeLocal == 2 && deltaLocal !== 0) {
miterLimitLocal_start = 1;
miterLimitLocal_end = 6;
}
else {
miterLimitLocal_start = 1;
miterLimitLocal_end = 1
}
for (miterLimitLocal = miterLimitLocal_start; miterLimitLocal < miterLimitLocal_end + 1; miterLimitLocal += 2) {
bench_glob[bench_glob.length] = {
polygon_id: polygon_id,
joinType: joinTypeLocal, // 0,1
offsettable_poly: offsettable_polyLocal, // 1,2,3
delta: deltaLocal, // -10 - 10
miterLimit: miterLimitLocal, // 1 - 5
AutoFix: true, // false, true
ExPolygons: false, // false, true
Simplify: false, // false, true
subject_fillType: fillTypeLocal, // 0,1
clip_fillType: fillTypeLocal, //0, 1
clipType: (clipTypeLocal === 0) ? "" : clipTypeLocal - 1, // "",0,1,2,3
scale: scaleLocal, // 100, 100 000, 1000 000 000
rnd_sett: {
clip_polygon_count: 4,
clip_point_count: 4,
subj_polygon_count: 4,
subj_point_count: 4
}
};
timeout_time += timeout_time_addition;
bench_glob[bench_glob.length - 1].setTimeout = setTimeout("benchmark2(" + (bench_glob.length - 1) + ")", timeout_time);
bench_glob[bench_glob.length - 1].timeout_time = timeout_time;
}
}
}
}
}
}
}
}
});
$('#scale').val(to_printable(scale));
$('#delta').val(to_printable(delta));
$('#miterLimit').val(to_printable(miterLimit));
if (AutoFix) $('#AutoFix').attr('checked', 'checked');
else $('#AutoFix').removeAttr('checked');
if (ExPolygons) $('#ExPolygons').attr('checked', 'checked');
else $('#ExPolygons').removeAttr('checked');
if (Simplify) $('#Simplify').attr('checked', 'checked');
else $('#Simplify').removeAttr('checked');
if (clean) $('#clean').attr('checked', 'checked');
else $('#clean').removeAttr('checked');
$("#cleandelta").val(cleandelta_default);
if (lighten) $('#lighten').attr('checked', 'checked');
else $('#lighten').removeAttr('checked');
$('#lighten_distance').val(lighten_distance_default);
$('input[type="radio"][name="subject_fillType"][value="' + subject_fillType + '"]').attr('checked', 'checked');
$('input[type="radio"][name="clip_fillType"][value="' + clip_fillType + '"]').attr('checked', 'checked');
$('input[type="radio"][name="polygons"][value="' + polygons_default + '"]').attr('checked', 'checked').change();
var polygon = parseInt(polygons_default, 10);
if (polygon == 4) rnd_sett = rnd_sett_defaults.rects.default;
else rnd_sett = rnd_sett_defaults.norm.default;
$('input[type="radio"][name="offsettable_poly"][value="' + offsettable_poly + '"]').attr('checked', 'checked');
$('#subj_polygon_count').val(rnd_sett.subj_polygon_count);
$('#subj_point_count').val(rnd_sett.subj_point_count);
$('#clip_polygon_count').val(rnd_sett.clip_polygon_count);
$('#clip_point_count').val(rnd_sett.clip_point_count);
if (bevel) $('#bevel').attr('checked', 'checked');
else $('#bevel').removeAttr('checked');
if (sub_poly_links_update) $('#sub_poly_links_update').attr('checked', 'checked');
else $('#sub_poly_links_update').removeAttr('checked');
make_clip();
colorize_boxes_like_in_svg();
} // main()
function make_offset() {
// --------------------------------
// SELECT OFSETTABLE POLYGON STARTS
// --------------------------------
var off_poly, off_poly1, off_poly2, off_poly3;
offsettable_poly = parseInt($('input[type="radio"][name="offsettable_poly"]:checked').val(), 10);
if (offsettable_poly == 1) {
off_poly = ClipperLib.Clone(ss);
}
else if (offsettable_poly == 2) {
off_poly = ClipperLib.Clone(cc);
}
else if (offsettable_poly == 3) {
off_poly = sss;
}
if (typeof(off_poly) == "undefined" || !(sss instanceof Array)) off_poly = [
[]
];
// ------------------------------
// SELECT OFSETTABLE POLYGON ENDS
// ------------------------------
if (ClipperLib.biginteger_used === null) ClipperLib.biginteger_used = 0;
// -------------
// CLEAN STARTS
// -------------
if (clean) {
off_poly = ClipperLib.Clean(off_poly, cleandelta * scale);
}
//if (isArray(off_poly) && off_poly.length)
//console.log(JSON.stringify(off_poly[0]));
// -------------
// CLEAN ENDS
// -------------
// ---------------
// SIMPLIFY STARTS
// ---------------
// Must simplify before offsetting, to get offsetting right in certain cases.
// Other operations (boolean ones) doesn't need this.
// This is needed when offsetting polygons that has selfintersecting parts ( eg. 5-point star needs this )
if (Simplify) {
// Simplifying is only needed when offsetting original polys, because
// results of boolean operations are already simplified.
// Note! if clip polygon is the same as subject polygon
// then it seems that simplifying is needed also for result of boolean operation (ie. solution).
if (offsettable_poly == 1) // subj
{
off_poly = cpr.SimplifyPolygons(off_poly, subject_fillType);
}
if (offsettable_poly == 2) // clip
{
off_poly = cpr.SimplifyPolygons(off_poly, clip_fillType);
}
if (offsettable_poly == 3) // solution
{
off_poly = cpr.SimplifyPolygons(off_poly, clip_fillType);
if (subject_fillType !== clip_fillType) {
console.log("Subject filltype and Clip filltype are different. We used Clip filltype in SimplifyPolygons().");
}
}
}
// -------------
// SIMPLIFY ENDS
// -------------
// ------------------------------
// ACTUAL OFFSET OPERATION STARTS
// ------------------------------
if (delta) {
for (var i = 0; i < 10; i++) {
cpr.Clear();
cpr.alternateAlgo = false;
var param_delta = round_to(delta * scale, 3);
var param_miterLimit = round_to(miterLimit, 3);
var B0 = bench.start("Offset", "Offset(" + param_delta + ", " + joinType + ", " + param_miterLimit + ", " + AutoFix + ")");
off_result = cpr.OffsetPolygons(off_poly, param_delta, joinType, param_miterLimit, AutoFix);
bench.end(B0);
cpr.Clear();
cpr.alternateAlgo = true;
var param_delta = round_to(delta * scale, 3);
var param_miterLimit = round_to(miterLimit, 3);
var B0 = bench.start("Offset bulk insert", "Offset(" + param_delta + ", " + joinType + ", " + param_miterLimit + ", " + AutoFix + ")");
off_result = cpr.OffsetPolygons(off_poly, param_delta, joinType, param_miterLimit, AutoFix);
bench.end(B0);
}
}
else {
off_result = off_poly;
}
// ----------------------------
// ACTUAL OFFSET OPERATION ENDS
// ------------------------------
// ----------------------------
// LIGHTENING STARTS
// ------------------------------
if (lighten) {
off_result = ClipperLib.Lighten(off_result, lighten_distance * scale);
// Because lighten may produce self-intersections,
// must Simplify to be sure that result is free of them,
// but only if user wants
if (Simplify) {
off_result = cpr.SimplifyPolygons(off_result, subject_fillType);
}
}
// ----------------------------
// LIGHTENING ENDS
// ------------------------------
// --------------------------------
// SVG UPDATE STARTS
// --------------------------------
if (!p) p = SVG.create();
if (p1) p1.remove();
if (p2) p2.remove();
if (p3) p3.remove();
if (bench.includeSVG) var B3 = bench.start("SVG", "addpaths(ss, cc, off_result, " + subject_fillType + ", " + clip_fillType + ")");
SVG.addpaths(ss, cc, off_result, subject_fillType, clip_fillType);
if (bench.includeSVG) bench.end(B3);
// --------------------------------
// SVG UPDATE ENDS
// --------------------------------
// --------------------------------
// UPDATE BIGINTEGERS TOGGLE STARTS
// --------------------------------
if (ClipperLib.biginteger_used !== null) {
if (ClipperLib.biginteger_used) $("#biginteger_used").html("true");
else $("#biginteger_used").html("false");
}
else $("#biginteger_used").html("unknown");
ClipperLib.biginteger_used = null;
// ------------------------------
// UPDATE BIGINTEGERS TOGGLE ENDS
// ------------------------------
// UPDATE DELTA TO FORM
$('#delta').val(to_printable(delta));
// UPDATE MITERLIMIT TO FORM
$('#miterLimit').val(to_printable(miterLimit));
// PRINT BENCHMARKS
$("#benchmark_div").html(bench.print());
update_enlarged_SVG_if_needed();
update_fieldset_heights();
}
function make_clip() {
ClipperLib.biginteger_used = null;
if (!cpr) {
cpr = new ClipperLib.Clipper();
}
else cpr.Clear();
if (!cpr2) {
cpr2 = new ClipperLib.Clipper();
}
else cpr2.Clear();
get_polys();
if (clipType !== "" && offsettable_poly == 3) {
for (var i = 0; i < 10; i++) {
cpr.Clear()
cpr.AddPolygons(ss, ClipperLib.PolyType.ptSubject);
cpr.AddPolygons(cc, ClipperLib.PolyType.ptClip);
sss = new ClipperLib.Polygons();
cpr.alternateAlgo = false;
var B1 = bench.start("Boolean", "Execute(" + clipType + ", sss, " + subject_fillType + ", " + clip_fillType + ")");
cpr.Execute(clipType, sss, subject_fillType, clip_fillType);
bench.end(B1);
cpr2.Clear();
cpr2.AddPolygons(ss, ClipperLib.PolyType.ptSubject);
cpr2.AddPolygons(cc, ClipperLib.PolyType.ptClip);
sss2 = new ClipperLib.Polygons();
cpr2.alternateAlgo = true;
var B2 = bench.start("Boolean bulk insert", "Execute(" + clipType + ", sss2, " + subject_fillType + ", " + clip_fillType + ")");
cpr2.Execute(clipType, sss2, subject_fillType, clip_fillType);
bench.end(B2);
}
}
make_offset();
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment