prosperon/scripts/base.js

1574 lines
35 KiB
JavaScript
Raw Normal View History

/* It is EMCA6 but without a lot of builtin objects and various functions. There are no:
* Promises and so on (Generators, async)
* WeakMaps and so on (weakset, weakref)
* Typed arrays
* Proxys
* Modules
* Symbols (use closures)
In addition to the removal of a bunch of stuff as seen here.
Access prototypes through __proto__ instead of the long-winded Object.getProtoTypeOf.
*/
2024-03-19 14:39:19 -05:00
2023-12-18 06:45:27 -06:00
/*
2023-10-09 13:03:12 -05:00
Object.getPrototypeOf = undefined;
Object.setPrototypeOf = undefined;
2024-03-14 09:33:15 -05:00
Reflect = undefined
2023-10-09 13:03:12 -05:00
Symbol = undefined;
URIError = undefined;
Proxy = undefined;
Map = undefined;
WeakMap = undefined;
Promise = undefined;
Set = undefined;
WeakSet = undefined;
2023-12-18 06:45:27 -06:00
*/
2023-10-09 13:03:12 -05:00
2024-02-25 17:31:48 -06:00
Number.roman = {
2024-02-19 20:31:26 -06:00
M: 1000,
D: 500,
C: 100,
L: 50,
X: 10,
V: 5,
2024-09-26 11:36:09 -05:00
I: 1,
2024-02-19 20:31:26 -06:00
};
2024-02-25 17:31:48 -06:00
var convert = {};
2024-09-26 11:36:09 -05:00
convert.romanize = function (num) {
2024-02-25 17:31:48 -06:00
if (!+num) return false;
2024-09-26 11:36:09 -05:00
var digits = String(+num).split("");
var key = ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM", "", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC", "", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"];
var roman = "",
i = 3;
while (i--) roman = (key[+digits.pop() + i * 10] || "") + roman;
return Array(+digits.join("") + 1).join("M") + roman;
};
2024-02-19 20:31:26 -06:00
2024-09-26 11:36:09 -05:00
convert.deromanize = function (str) {
2024-02-25 17:31:48 -06:00
var str = str.toUpperCase();
var validator = /^M*(?:D?C{0,3}|C[MD])(?:L?X{0,3}|X[CL])(?:V?I{0,3}|I[XV])$/;
var token = /[MDLV]|C[MD]?|X[CL]?|I[XV]?/g;
2024-09-26 11:36:09 -05:00
var key = {
M: 1000,
CM: 900,
D: 500,
CD: 400,
C: 100,
XC: 90,
L: 50,
XL: 40,
X: 10,
IX: 9,
V: 5,
IV: 4,
I: 1,
};
var num = 0,
m;
2024-02-25 17:31:48 -06:00
if (!(str && validator.test(str))) return false;
2024-09-26 11:36:09 -05:00
while ((m = token.exec(str))) num += key[m[0]];
2024-02-19 20:31:26 -06:00
return num;
2024-09-26 11:36:09 -05:00
};
2024-02-19 20:31:26 -06:00
2024-09-26 11:36:09 -05:00
convert.buf2hex = function (buffer) {
// buffer is an ArrayBuffer
return [...new Uint8Array(buffer)].map(x => x.toString(16).padStart(2, "0")).join(" ");
};
2024-02-09 01:49:52 -06:00
2024-02-25 17:31:48 -06:00
/* Time values are always expressed in terms of real earth-seconds */
Object.assign(time, {
2024-09-26 11:36:09 -05:00
hour2minute() {
return this.hour / this.minute;
},
day2hour() {
return this.day / this.hour;
},
minute2second() {
return this.minute / this.second;
},
week2day() {
return this.week / this.day;
},
});
2024-02-25 17:31:48 -06:00
time.strparse = {
2023-12-09 22:09:15 -06:00
yyyy: "year",
mm: "month",
m: "month",
eee: "yday",
dd: "day",
d: "day",
v: "weekday",
hh: "hour",
h: "hour",
nn: "minute",
n: "minute",
ss: "second",
s: "second",
};
2024-02-25 17:31:48 -06:00
time.doc = {
doc: "Functions for manipulating time.",
second: "Earth-seconds in a second.",
minute: "Seconds in a minute.",
hour: "Seconds in an hour.",
day: "Seconds in a day.",
week: "Seconds in a week.",
weekdays: "Names of the days of the week.",
monthstr: "Full names of the months of the year.",
epoch: "Times are expressed in terms of day 0 at hms 0 of this year.",
now: "Get the time now.",
computer_zone: "Get the time zone of the running computer.",
computer_dst: "Return true if the computer is in daylight savings.",
yearsize: "Given a year, return the number of days in that year.",
monthdays: "Number of days in each month.",
fmt: "Default format for time.",
record: "Given a time, return an object with time fields.",
number: "Return the number representation of a given time.",
2024-09-26 11:36:09 -05:00
text: "Return a text formatted time.",
2023-12-09 22:09:15 -06:00
};
2024-02-25 17:31:48 -06:00
time.second = 1;
time.minute = 60;
time.hour = 3_600;
time.day = 86_400;
time.week = 604_800;
2023-12-09 22:09:15 -06:00
time.weekdays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
2024-09-26 11:36:09 -05:00
time.monthstr = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
2023-12-09 22:09:15 -06:00
2024-02-25 17:31:48 -06:00
time.epoch = 1970;
2024-09-26 11:36:09 -05:00
time.isleap = function (year) {
return this.yearsize(year) === 366;
};
2023-12-09 22:09:15 -06:00
time.isleap.doc = "Return true if the given year is a leapyear.";
2024-09-26 11:36:09 -05:00
time.yearsize = function (y) {
if (y % 4 === 0 && (y % 100 != 0 || y % 400 === 0)) return 366;
2023-12-09 22:09:15 -06:00
return 365;
2024-09-26 11:36:09 -05:00
};
2023-12-09 22:09:15 -06:00
2024-09-26 11:36:09 -05:00
time.timecode = function (t, fps = 24) {
var s = Math.trunc(t);
t -= s;
2024-09-26 11:36:09 -05:00
return `${s}:${Math.trunc(fps * s)}`;
};
2024-09-26 11:36:09 -05:00
time.monthdays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
2023-12-09 22:09:15 -06:00
time.zones = {};
2024-09-26 11:36:09 -05:00
time.zones["-12"] = "IDLW";
time.record = function (num, zone = this.computer_zone()) {
if (typeof num === "object") return num;
else if (typeof num === "number") {
2023-12-09 22:09:15 -06:00
var monthdays = this.monthdays.slice();
var rec = {
second: 0,
minute: 0,
hour: 0,
yday: 0,
year: 0,
2024-09-26 11:36:09 -05:00
zone: 0,
2023-12-09 22:09:15 -06:00
};
rec.zone = zone;
2024-09-26 11:36:09 -05:00
num += zone * this.hour;
2023-12-09 22:09:15 -06:00
var hms = num % this.day;
2024-09-26 11:36:09 -05:00
var day = parseInt(num / this.day);
2023-12-09 22:09:15 -06:00
if (hms < 0) {
hms += this.day;
day--;
}
2024-09-26 11:36:09 -05:00
rec.second = hms % this.minute;
var d1 = Math.floor(hms / this.minute);
2023-12-09 22:09:15 -06:00
rec.minute = d1 % this.minute;
2024-09-26 11:36:09 -05:00
rec.hour = Math.floor(d1 / this.minute);
2023-12-09 22:09:15 -06:00
/* addend%7 is 4 */
2024-09-26 11:36:09 -05:00
rec.weekday = (day + 4503599627370496 + 2) % 7;
2023-12-09 22:09:15 -06:00
var d1 = this.epoch;
2024-09-26 11:36:09 -05:00
if (day >= 0) for (d1 = this.epoch; day >= this.yearsize(d1); d1++) day -= this.yearsize(d1);
else for (d1 = this.epoch; day < 0; d1--) day += this.yearsize(d1 - 1);
2023-12-09 22:09:15 -06:00
rec.year = d1;
2024-09-26 11:36:09 -05:00
if (rec.year <= 0) rec.ce = "BC";
else rec.ce = "AD";
2023-12-09 22:09:15 -06:00
rec.yday = day;
2024-09-26 11:36:09 -05:00
if (this.yearsize(d1) === 366) monthdays[1] = 29;
2023-12-09 22:09:15 -06:00
2024-09-26 11:36:09 -05:00
var d0 = day;
for (d1 = 0; d0 >= monthdays[d1]; d1++) d0 -= monthdays[d1];
2023-12-09 22:09:15 -06:00
monthdays[1] = 28;
rec.day = d0 + 1;
rec.month = d1;
2024-09-26 11:36:09 -05:00
return rec;
2023-12-09 22:09:15 -06:00
}
2024-09-26 11:36:09 -05:00
};
2023-12-09 22:09:15 -06:00
2024-09-26 11:36:09 -05:00
time.number = function (rec) {
if (typeof rec === "number") return rec;
else if (typeof rec === "object") {
2023-12-09 22:09:15 -06:00
var c = 0;
var year = rec.year ? rec.year : 0;
var hour = rec.hour ? rec.hour : 0;
var minute = rec.minute ? rec.minute : 0;
var second = rec.second ? rec.second : 0;
var zone = rec.zone ? rec.zone : 0;
2024-09-26 11:36:09 -05:00
if (year > this.epoch) for (var i = this.epoch; i < year; i++) c += this.day * this.yearsize(i);
2023-12-09 22:09:15 -06:00
else if (year < this.epoch) {
2024-09-26 11:36:09 -05:00
for (var i = this.epoch - 1; i > year; i--) c += this.day * this.yearsize(i);
c += (this.yearsize(year) - yday - 1) * this.day;
c += (this.day2hour() - hour - 1) * this.hour;
c += (this.hour2minute() - minute - 1) * this.minute;
c += this.minute2second() - second;
c += zone * this.hour;
2023-12-09 22:09:15 -06:00
c *= -1;
return c;
}
c += second;
c += minute * this.minute;
c += hour * this.hour;
c += yday * this.day;
c -= zone * this.hour;
return c;
}
2024-09-26 11:36:09 -05:00
};
2023-12-09 22:09:15 -06:00
/* Time formatting
yyyy - year in a 4 digit field
y - as many digits as necessary
mm - month (1-12)
mB - month name
mb - abbreviated month name
dd - day (1-31)
d
c - if the year is <= 0, BC. Otherwise, AD.
hh - hour
h
nn - minutes
n
ss - seconds
s
v - day of the week (0-6)
vB - weekday name
vb - abbreviated weekday name
a - am/pm
z - zone, -12 to +11
*/
time.fmt = "vB mB d h:nn:ss TZz a y c";
/* If num is a number, converts to a rec first. */
2024-09-26 11:36:09 -05:00
time.text = function (num, fmt = this.fmt, zone) {
2023-12-09 22:09:15 -06:00
var rec = num;
2024-09-26 11:36:09 -05:00
if (typeof rec === "number") rec = time.record(num, zone);
2023-12-09 22:09:15 -06:00
zone = rec.zone;
2024-09-26 11:36:09 -05:00
if (fmt.match("a")) {
2023-12-09 22:09:15 -06:00
if (rec.hour >= 13) {
rec.hour -= 12;
2024-09-26 11:36:09 -05:00
fmt = fmt.replaceAll("a", "PM");
} else if (rec.hour === 12) fmt = fmt.replaceAll("a", "PM");
2023-12-09 22:09:15 -06:00
else if (rec.hour === 0) {
rec.hour = 12;
2024-09-26 11:36:09 -05:00
fmt = fmt.replaceAll("a", "AM");
} else fmt = fmt.replaceAll("a", "AM");
2023-12-09 22:09:15 -06:00
}
var year = rec.year > 0 ? rec.year : rec.year - 1;
2024-09-26 11:36:09 -05:00
if (fmt.match("c")) {
2023-12-09 22:09:15 -06:00
if (year < 0) {
year = Math.abs(year);
2024-09-26 11:36:09 -05:00
fmt = fmt.replaceAll("c", "BC");
} else fmt = fmt.replaceAll("c", "AD");
2023-12-09 22:09:15 -06:00
}
2024-09-26 11:36:09 -05:00
fmt = fmt.replaceAll("yyyy", year.toString().padStart(4, "0"));
fmt = fmt.replaceAll("y", year);
fmt = fmt.replaceAll("eee", rec.yday + 1);
fmt = fmt.replaceAll("dd", rec.day.toString().padStart(2, "0"));
fmt = fmt.replaceAll("d", rec.day);
fmt = fmt.replaceAll("hh", rec.hour.toString().padStart(2, "0"));
fmt = fmt.replaceAll("h", rec.hour);
fmt = fmt.replaceAll("nn", rec.minute.toString().padStart(2, "0"));
fmt = fmt.replaceAll("n", rec.minute);
fmt = fmt.replaceAll("ss", rec.second.toString().padStart(2, "0"));
fmt = fmt.replaceAll("s", rec.second);
fmt = fmt.replaceAll("z", zone >= 0 ? "+" + zone : zone);
fmt = fmt.replaceAll(/mm[^bB]/g, rec.month + 1);
fmt = fmt.replaceAll(/m[^bB]/g, rec.month + 1);
fmt = fmt.replaceAll(/v[^bB]/g, rec.weekday);
fmt = fmt.replaceAll("mb", this.monthstr[rec.month].slice(0, 3));
fmt = fmt.replaceAll("mB", this.monthstr[rec.month]);
fmt = fmt.replaceAll("vB", this.weekdays[rec.weekday]);
fmt = fmt.replaceAll("vb", this.weekdays[rec.weekday].slice(0, 3));
2023-12-09 22:09:15 -06:00
return fmt;
2024-09-26 11:36:09 -05:00
};
2023-12-09 22:09:15 -06:00
2024-09-26 11:36:09 -05:00
Object.methods = function (o) {
2023-10-09 13:03:12 -05:00
var m = [];
2024-09-26 11:36:09 -05:00
Object.keys(o).forEach(function (k) {
if (typeof o[k] === "function") m.push(k);
2023-10-09 13:03:12 -05:00
});
return m;
2024-09-26 11:36:09 -05:00
};
2023-11-29 12:40:13 -06:00
Object.methods.doc = "Retun an array of all functions an object has access to.";
2023-10-09 13:03:12 -05:00
2024-09-26 11:36:09 -05:00
Object.dig = function (obj, path, def = {}) {
var pp = path.split(".");
for (var i = 0; i < pp.length - 1; i++) {
obj = obj[pp[i]] = obj[pp[i]] || {};
}
2024-09-26 11:36:09 -05:00
obj[pp[pp.length - 1]] = def;
return def;
2024-09-26 11:36:09 -05:00
};
2024-09-26 11:36:09 -05:00
Object.rkeys = function (o) {
2023-10-09 13:03:12 -05:00
var keys = [];
2024-09-26 11:36:09 -05:00
Object.keys(o).forEach(function (key) {
2023-10-09 13:03:12 -05:00
keys.push(key);
2024-09-26 11:36:09 -05:00
if (Object.isObject(o[key])) keys.push(Object.rkeys(o[key]));
2023-10-09 13:03:12 -05:00
});
return keys;
2024-09-26 11:36:09 -05:00
};
2024-09-26 11:36:09 -05:00
Object.readonly = function (o, name, msg) {
2024-04-10 16:21:46 -05:00
var tmp = {};
var prop = Object.getOwnPropertyDescriptor(o, name);
if (!prop) {
console.error(`Attempted to make property ${name} readonly, but it doesn't exist on ${o}.`);
return;
}
Object.defineProperty(tmp, name, prop);
2024-09-26 11:36:09 -05:00
prop.get = function () {
return tmp[name];
};
prop.set = function () {
console.warn(`Attempted to set readonly property ${name}`);
};
2024-04-10 16:21:46 -05:00
Object.defineProperty(o, name, prop);
2024-09-26 11:36:09 -05:00
};
2024-04-10 16:21:46 -05:00
2024-09-26 11:36:09 -05:00
Object.mixin = function (target, source) {
if (typeof source !== "object") return target;
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
return target;
};
2024-09-26 11:36:09 -05:00
Object.mix = function (...objs) {
var n = {};
2024-09-26 11:36:09 -05:00
for (var o of objs) Object.mixin(n, o);
return n;
2024-09-26 11:36:09 -05:00
};
2024-09-26 11:36:09 -05:00
Object.deepmixin = function (target, source) {
2023-10-11 17:22:41 -05:00
var o = source;
while (o !== Object.prototype) {
Object.mixin(target, o);
o = o.__proto__;
2024-09-26 11:36:09 -05:00
}
};
2023-10-11 17:22:41 -05:00
2024-09-26 11:36:09 -05:00
Object.deepfreeze = function (obj) {
2023-09-21 12:50:39 -05:00
for (var key in obj) {
2024-09-26 11:36:09 -05:00
if (typeof obj[key] === "object") Object.deepfreeze(obj[key]);
2023-09-21 12:50:39 -05:00
}
Object.freeze(obj);
2024-09-26 11:36:09 -05:00
};
2023-09-21 12:50:39 -05:00
/* Goes through each key and overwrites if it's present */
2024-09-26 11:36:09 -05:00
Object.dainty_assign = function (target, source) {
Object.keys(source).forEach(function (k) {
if (typeof source[k] === "function") return;
2023-10-10 17:37:58 -05:00
if (!(k in target)) return;
2024-09-26 11:36:09 -05:00
if (Array.isArray(source[k])) target[k] = deep_copy(source[k]);
else if (Object.isObject(source[k])) Object.dainty_assign(target[k], source[k]);
else target[k] = source[k];
});
2024-09-26 11:36:09 -05:00
};
2024-09-26 11:36:09 -05:00
Object.isObject = function (o) {
return o instanceof Object && !(o instanceof Array);
};
2023-10-04 17:57:37 -05:00
2024-09-26 11:36:09 -05:00
Object.setter_assign = function (target, source) {
for (var key in target) if (Object.isAccessor(target, key) && typeof source[key] !== "undefined") target[key] = source[key];
};
2023-10-04 17:57:37 -05:00
2024-09-26 11:36:09 -05:00
Object.containingKey = function (obj, prop) {
if (typeof obj !== "object") return undefined;
if (!(prop in obj)) return undefined;
2024-09-26 11:36:09 -05:00
var o = obj;
2024-09-26 11:36:09 -05:00
while (o.__proto__ && !Object.hasOwn(o, prop)) o = o.__proto__;
return o;
2024-09-26 11:36:09 -05:00
};
2024-09-26 11:36:09 -05:00
Object.access = function (obj, name) {
var dig = name.split(".");
for (var i of dig) {
obj = obj[i];
if (!obj) return undefined;
}
2024-09-26 11:36:09 -05:00
return obj;
2024-09-26 11:36:09 -05:00
};
2024-09-26 11:36:09 -05:00
Object.isAccessor = function (obj, prop) {
var o = Object.containingKey(obj, prop);
if (!o) return false;
2024-09-26 11:36:09 -05:00
var desc = Object.getOwnPropertyDescriptor(o, prop);
if (!desc) return false;
if (desc.get || desc.set) return true;
return false;
2024-09-26 11:36:09 -05:00
};
2023-09-21 19:51:38 -05:00
2024-09-26 11:36:09 -05:00
Object.mergekey = function (o1, o2, k) {
2023-09-27 09:37:20 -05:00
if (!o2) return;
2024-09-26 11:36:09 -05:00
if (typeof o2[k] === "object") {
if (Array.isArray(o2[k])) o1[k] = deep_copy(o2[k]);
else {
if (!o1[k]) o1[k] = {};
2024-09-26 11:36:09 -05:00
if (typeof o1[k] === "object") Object.merge(o1[k], o2[k]);
else o1[k] = o2[k];
}
2024-09-26 11:36:09 -05:00
} else o1[k] = o2[k];
};
2023-09-21 19:51:38 -05:00
/* Same as merge from Ruby */
/* Adds objs key by key to target */
2024-09-26 11:36:09 -05:00
Object.merge = function (target, ...objs) {
for (var obj of objs) for (var key of Object.keys(obj)) Object.mergekey(target, obj, key);
2023-10-02 17:03:01 -05:00
return target;
2024-09-26 11:36:09 -05:00
};
2023-09-21 19:51:38 -05:00
2024-09-26 11:36:09 -05:00
Object.totalmerge = function (target, ...objs) {
for (var obj of objs) for (var key in obj) Object.mergekey(target, obj, key);
2023-12-27 07:04:18 -06:00
return target;
2024-09-26 11:36:09 -05:00
};
2023-09-21 19:51:38 -05:00
/* Returns a new object with undefined, null, and empty values removed. */
2024-09-26 11:36:09 -05:00
Object.compact = function (obj) {};
2023-09-21 19:51:38 -05:00
2024-09-26 11:36:09 -05:00
Object.totalassign = function (to, from) {
for (var key in from) to[key] = from[key];
};
2023-09-20 13:33:11 -05:00
/* Prototypes out an object and assigns values */
2024-09-26 11:36:09 -05:00
Object.copy = function (proto, ...objs) {
var c = Object.create(proto);
2024-09-26 11:36:09 -05:00
for (var obj of objs) Object.mixin(c, obj);
return c;
2024-09-26 11:36:09 -05:00
};
/* OBJECT DEFININTIONS */
2024-09-26 11:36:09 -05:00
Object.defHidden = function (obj, prop) {
Object.defineProperty(obj, prop, { enumerable: false, writable: true });
};
2024-09-26 11:36:09 -05:00
Object.hide = function (obj, ...props) {
for (var prop of props) {
2024-09-26 11:36:09 -05:00
var p = Object.getOwnPropertyDescriptor(obj, prop);
2024-08-25 06:35:04 -05:00
if (!p) continue;
p.enumerable = false;
Object.defineProperty(obj, prop, p);
2023-10-02 17:03:01 -05:00
}
2024-09-26 11:36:09 -05:00
};
2023-10-02 17:03:01 -05:00
2024-09-26 11:36:09 -05:00
Object.enumerable = function (obj, val, ...props) {
2024-08-25 06:35:04 -05:00
for (var prop of props) {
2024-09-26 11:36:09 -05:00
p = Object.getOwnPropertyDescriptor(obj, prop);
2024-08-25 06:35:04 -05:00
if (!p) continue;
p.enumerable = val;
Object.defineProperty(obj, prop, p);
2024-09-26 11:36:09 -05:00
}
};
2024-08-25 06:35:04 -05:00
2024-09-26 11:36:09 -05:00
Object.unhide = function (obj, ...props) {
2023-10-26 11:48:02 -05:00
for (var prop of props) {
2024-09-26 11:36:09 -05:00
var p = Object.getOwnPropertyDescriptor(obj, prop);
2024-08-25 06:35:04 -05:00
if (!p) continue;
2023-10-26 11:48:02 -05:00
p.enumerable = true;
Object.defineProperty(obj, prop, p);
}
2024-09-26 11:36:09 -05:00
};
2023-10-26 11:48:02 -05:00
2024-09-26 11:36:09 -05:00
Object.defineProperty(Object.prototype, "obscure", {
value: function (name) {
2023-04-29 10:07:58 -05:00
Object.defineProperty(this, name, { enumerable: false });
2024-09-26 11:36:09 -05:00
},
2023-04-29 10:07:58 -05:00
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Object.prototype, "mixin", {
value: function (obj) {
if (typeof obj === "string") obj = use(obj);
if (obj) Object.mixin(this, obj);
},
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Object.prototype, "hasOwn", {
value: function (x) {
return this.hasOwnProperty(x);
},
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Object.prototype, "defn", {
value: function (name, val) {
Object.defineProperty(this, name, {
value: val,
writable: true,
configurable: true,
});
},
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Object.prototype, "nulldef", {
value: function (name, val) {
if (!this.hasOwnProperty(name)) this[name] = val;
2024-09-26 11:36:09 -05:00
},
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Object.prototype, "prop_obj", {
value: function () {
return JSON.parse(JSON.stringify(this));
},
2023-05-27 07:01:17 -05:00
});
/* defc 'define constant'. Defines a value that is not writable. */
2024-09-26 11:36:09 -05:00
Object.defineProperty(Object.prototype, "defc", {
value: function (name, val) {
Object.defineProperty(this, name, {
value: val,
2024-09-26 11:36:09 -05:00
writable: false,
enumerable: true,
configurable: false,
});
2024-09-26 11:36:09 -05:00
},
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Object.prototype, "stick", {
value: function (prop) {
Object.defineProperty(this, prop, { writable: false });
},
2023-05-27 07:01:17 -05:00
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Object.prototype, "harden", {
value: function (prop) {
Object.defineProperty(this, prop, {
writable: false,
configurable: false,
enumerable: false,
});
},
2023-05-27 07:01:17 -05:00
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Object.prototype, "deflock", {
value: function (prop) {
Object.defineProperty(this, prop, { configurable: false });
},
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Object.prototype, "forEach", {
value: function (fn) {
2023-09-29 13:16:59 -05:00
Object.values(this).forEach(fn);
2024-09-26 11:36:09 -05:00
},
});
2024-09-26 11:36:09 -05:00
Object.empty = function (obj) {
2024-02-19 20:31:26 -06:00
return Object.keys(obj).length === 0;
2024-09-26 11:36:09 -05:00
};
2024-09-26 11:36:09 -05:00
Object.defineProperty(Object.prototype, "nth", {
value: function (x) {
if (this.empty || x >= Object.keys(this).length) return null;
return this[Object.keys(this)[x]];
},
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Object.prototype, "filter", {
value: function (fn) {
2023-09-29 13:16:59 -05:00
return Object.values(this).filter(fn);
2024-09-26 11:36:09 -05:00
},
2023-09-29 13:16:59 -05:00
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Object.prototype, "push", {
value: function (val) {
2023-09-29 13:16:59 -05:00
var str = val.toString();
2024-09-26 11:36:09 -05:00
str = str.replaceAll(".", "_");
2023-09-29 13:16:59 -05:00
var n = 1;
var t = str;
2024-09-26 11:36:09 -05:00
while (Object.hasOwn(this, t)) {
2023-09-29 13:16:59 -05:00
t = str + n;
2024-09-26 11:36:09 -05:00
n++;
2023-09-29 13:16:59 -05:00
}
this[t] = val;
return t;
2024-09-26 11:36:09 -05:00
},
2023-09-29 13:16:59 -05:00
});
/* STRING DEFS */
2024-09-26 11:36:09 -05:00
Object.defineProperty(String.prototype, "next", {
value: function (char, from) {
if (!Array.isArray(char)) char = [char];
if (from > this.length - 1) return -1;
else if (!from) from = 0;
var find = this.slice(from).search(char[0]);
2024-09-26 11:36:09 -05:00
if (find === -1) return -1;
else return from + find;
var i = 0;
2024-09-26 11:36:09 -05:00
var c = this.charAt(from + i);
while (!char.includes(c)) {
i++;
2024-09-26 11:36:09 -05:00
if (from + i > this.length - 1) return -1;
c = this.charAt(from + i);
}
2024-09-26 11:36:09 -05:00
return from + i;
},
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(String.prototype, "prev", {
value: function (char, from, count) {
if (from > this.length - 1) return -1;
else if (!from) from = this.length - 1;
if (!count) count = 0;
2024-09-26 11:36:09 -05:00
var find = this.slice(0, from).lastIndexOf(char);
while (count > 1) {
2024-09-26 11:36:09 -05:00
find = this.slice(0, find).lastIndexOf(char);
count--;
}
2024-09-26 11:36:09 -05:00
if (find === -1) return 0;
else return find;
},
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(String.prototype, "shift", {
value: function (n) {
if (n === 0) return this.slice();
2024-09-26 11:36:09 -05:00
if (n > 0) return this.slice(n);
2024-09-26 11:36:09 -05:00
if (n < 0) return this.slice(0, this.length + n);
},
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(String.prototype, "strip_ext", {
value: function () {
return this.tolast(".");
},
2023-09-26 13:34:02 -05:00
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(String.prototype, "ext", {
value: function () {
return this.fromlast(".");
},
2023-09-11 02:46:12 -05:00
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(String.prototype, "set_ext", {
value: function (val) {
return this.strip_ext() + val;
},
2023-10-09 13:03:12 -05:00
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(String.prototype, "folder_same_name", {
value: function () {
var dirs = this.dir().split("/");
return dirs.last() === this.name();
2024-09-26 11:36:09 -05:00
},
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(String.prototype, "up_path", {
value: function () {
var base = this.base();
2024-09-26 11:36:09 -05:00
var dirs = this.dir().split("/");
dirs.pop();
2024-09-26 11:36:09 -05:00
return dirs.join("/") + base;
},
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(String.prototype, "fromlast", {
value: function (val) {
2023-10-09 13:03:12 -05:00
var idx = this.lastIndexOf(val);
if (idx === -1) return "";
2024-09-26 11:36:09 -05:00
return this.slice(idx + 1);
},
2023-09-08 01:26:48 -05:00
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(String.prototype, "tofirst", {
value: function (val) {
2023-10-09 13:03:12 -05:00
var idx = this.indexOf(val);
if (idx === -1) return this.slice();
2024-09-26 11:36:09 -05:00
return this.slice(0, idx);
},
2023-09-08 01:26:48 -05:00
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(String.prototype, "fromfirst", {
value: function (val) {
var idx = this.indexOf(val);
if (idx === -1) return this;
2024-09-26 11:36:09 -05:00
return this.slice(idx + val.length);
},
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(String.prototype, "name", {
value: function () {
var idx = this.indexOf("/");
if (idx === -1) return this.tolast(".");
return this.fromlast("/").tolast(".");
},
2023-10-09 13:03:12 -05:00
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(String.prototype, "set_name", {
value: function (name) {
2024-05-28 13:39:02 -05:00
var dir = this.dir();
2024-08-20 02:17:56 -05:00
return this.dir() + "/" + name + "." + this.ext();
2024-09-26 11:36:09 -05:00
},
2024-05-28 13:39:02 -05:00
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(String.prototype, "base", {
value: function () {
return this.fromlast("/");
},
2023-10-09 13:03:12 -05:00
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(String.prototype, "splice", {
value: function (index, str) {
return this.slice(0, index) + str + this.slice(index);
},
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(String.prototype, "sub", {
value: function (index, str) {
return this.slice(0, index) + str + this.slice(index + str.length);
},
2024-04-30 10:32:27 -05:00
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(String.prototype, "updir", {
value: function () {
if (this.lastIndexOf("/") === this.length - 1) return this.slice(0, this.length - 1);
var dir = (this + "/").dir();
2023-09-26 17:07:51 -05:00
return dir.dir();
2024-09-26 11:36:09 -05:00
},
2023-09-26 17:07:51 -05:00
});
2023-09-08 01:26:48 -05:00
2024-09-26 11:36:09 -05:00
Object.defineProperty(String.prototype, "trimchr", {
value: function (chars) {
return vector.trimchr(this, chars);
2024-09-26 11:36:09 -05:00
},
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(String.prototype, "uc", {
value: function () {
return this.toUpperCase();
},
});
Object.defineProperty(String.prototype, "lc", {
value: function () {
return this.toLowerCase();
},
});
2023-10-09 13:03:12 -05:00
/* ARRAY DEFS */
2024-09-26 11:36:09 -05:00
Object.defineProperty(Array.prototype, "copy", {
value: function () {
var c = [];
2024-09-26 11:36:09 -05:00
this.forEach(function (x, i) {
c[i] = deep_copy(x);
});
2024-09-26 11:36:09 -05:00
return c;
2024-09-26 11:36:09 -05:00
},
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Array.prototype, "forFrom", {
value: function (n, fn) {
2024-07-25 16:14:37 -05:00
for (var i = n; i < this.length; i++) fn(this[i]);
2024-09-26 11:36:09 -05:00
},
2024-07-25 16:14:37 -05:00
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Array.prototype, "forTo", {
value: function (n, fn) {
2024-07-25 16:14:37 -05:00
for (var i = 0; i < n; i++) fn(this[i]);
2024-09-26 11:36:09 -05:00
},
2024-07-25 16:14:37 -05:00
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Array.prototype, "dofilter", {
value: function (fn) {
2024-04-14 14:53:41 -05:00
for (let i = 0; i < this.length; i++) {
if (!fn.call(this, this[i], i, this)) {
this.splice(i, 1);
i--;
2023-10-09 13:03:12 -05:00
}
2024-04-14 14:53:41 -05:00
}
2023-10-09 13:03:12 -05:00
return this;
2024-09-26 11:36:09 -05:00
},
2023-10-09 13:03:12 -05:00
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Array.prototype, "reversed", {
value: function () {
var c = this.slice();
return c.reverse();
2024-09-26 11:36:09 -05:00
},
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Array.prototype, "rotate", {
value: function (a) {
return Vector.rotate(this, a);
2024-09-26 11:36:09 -05:00
},
});
2024-02-25 17:31:48 -06:00
function make_swizz() {
2024-09-26 11:36:09 -05:00
function setelem(n) {
return {
get: function () {
return this[n];
},
set: function (x) {
this[n] = x;
},
};
}
2024-09-26 11:36:09 -05:00
function arrsetelem(str, n) {
Object.defineProperty(Array.prototype, str, setelem(n));
}
2024-09-26 11:36:09 -05:00
var arr_elems = ["x", "y", "z", "w"];
var quat_elems = ["i", "j", "k"];
var color_elems = ["r", "g", "b", "a"];
2024-09-26 11:36:09 -05:00
arr_elems.forEach(function (x, i) {
arrsetelem(x, i);
});
quat_elems.forEach(function (x, i) {
arrsetelem(x, i);
});
color_elems.forEach(function (x, i) {
arrsetelem(x, i);
});
2024-09-26 11:36:09 -05:00
var nums = [0, 1, 2, 3];
2024-09-26 11:36:09 -05:00
var swizz = [];
2024-09-26 11:36:09 -05:00
for (var i of nums) for (var j of nums) swizz.push([i, j]);
2024-09-26 11:36:09 -05:00
swizz.forEach(function (x) {
var str = "";
for (var i of x) str += arr_elems[i];
2024-09-26 11:36:09 -05:00
Object.defineProperty(Array.prototype, str, {
get() {
return [this[x[0]], this[x[1]]];
},
set(j) {
this[x[0]] = j[0];
this[x[1]] = j[1];
},
});
str = "";
for (var i of x) str += color_elems[i];
Object.defineProperty(Array.prototype, str, {
get() {
return [this[x[0]], this[x[1]]];
},
set(j) {
this[x[0]] = j[0];
this[x[1]] = j[1];
},
});
});
2024-09-26 11:36:09 -05:00
swizz = [];
for (var i of nums) for (var j of nums) for (var k of nums) swizz.push([i, j, k]);
2024-09-26 11:36:09 -05:00
swizz.forEach(function (x) {
var str = "";
for (var i of x) str += arr_elems[i];
2024-09-26 11:36:09 -05:00
Object.defineProperty(Array.prototype, str, {
get() {
return [this[x[0]], this[x[1]], this[x[2]]];
},
set(j) {
this[x[0]] = j[0];
this[x[1]] = j[1];
this[x[2]] = j[2];
},
});
2024-09-26 11:36:09 -05:00
str = "";
for (var i of x) str += color_elems[i];
Object.defineProperty(Array.prototype, str, {
get() {
return [this[x[0]], this[x[1]], this[x[2]]];
},
set(j) {
this[x[0]] = j[0];
this[x[1]] = j[1];
this[x[2]] = j[2];
},
});
});
2024-09-26 11:36:09 -05:00
swizz = [];
for (var i of nums) for (var j of nums) for (var k of nums) for (var w of nums) swizz.push([i, j, k, w]);
2024-09-26 11:36:09 -05:00
swizz.forEach(function (x) {
var str = "";
for (var i of x) str += arr_elems[i];
Object.defineProperty(Array.prototype, str, {
2024-09-26 11:36:09 -05:00
get() {
return [this[x[0]], this[x[1]], this[x[2]], this[x[3]]];
},
set(j) {
this[x[0]] = j[0];
this[x[1]] = j[1];
this[x[2]] = j[2];
this[x[3]] = j[3];
},
});
2024-09-26 11:36:09 -05:00
str = "";
for (var i of x) str += color_elems[i];
Object.defineProperty(Array.prototype, str, {
get() {
return [this[x[0]], this[x[1]], this[x[2]], this[x[3]]];
},
set(j) {
this[x[0]] = j[0];
this[x[1]] = j[1];
this[x[2]] = j[2];
this[x[3]] = j[3];
},
});
});
}
2024-02-25 17:31:48 -06:00
make_swizz();
2024-09-26 11:36:09 -05:00
Object.defineProperty(Array.prototype, "normalized", {
value: function () {
return vector.norm(this);
},
2023-12-19 17:28:45 -06:00
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Array.prototype, "newfirst", {
value: function (i) {
var c = this.slice();
if (i >= c.length) return c;
do {
c.push(c.shift());
i--;
} while (i > 0);
return c;
2024-09-26 11:36:09 -05:00
},
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Array.prototype, "doubleup", {
value: function (n) {
var c = [];
2024-09-26 11:36:09 -05:00
this.forEach(function (x) {
for (var i = 0; i < n; i++) c.push(x);
});
2024-09-26 11:36:09 -05:00
return c;
2024-09-26 11:36:09 -05:00
},
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Array.prototype, "mult", {
value: function (arr) {
2023-05-24 20:45:50 -05:00
var c = [];
2024-09-26 11:36:09 -05:00
for (var i = 0; i < this.length; i++) {
c[i] = this[i] * arr[i];
}
2023-05-24 20:45:50 -05:00
return c;
2024-09-26 11:36:09 -05:00
},
});
2023-05-24 20:45:50 -05:00
2024-09-26 11:36:09 -05:00
Object.defineProperty(Array.prototype, "apply", {
value: function (fn) {
this.forEach(function (x) {
x[fn].apply(x);
});
},
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Array.prototype, "sorted", {
value: function () {
2024-04-14 14:53:41 -05:00
return this.toSorted();
2024-09-26 11:36:09 -05:00
},
2024-04-14 14:53:41 -05:00
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Array.prototype, "equal", {
value: function (b) {
if (this.length !== b.length) return false;
if (b == null) return false;
if (this === b) return true;
2024-09-26 11:36:09 -05:00
return JSON.stringify(this.sorted()) === JSON.stringify(b.sorted());
2024-09-26 11:36:09 -05:00
for (var i = 0; i < this.length; i++) {
if (!this[i] === b[i]) return false;
}
return true;
},
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Array.prototype, "mapc", {
value: function (fn) {
return this.map(x => fn(x));
2024-09-26 11:36:09 -05:00
},
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Array.prototype, "mapvec", {
value: function (fn, b) {
return this.map((x, i) => fn(x, b[i]));
},
2023-12-24 09:14:46 -06:00
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Array.prototype, "remove", {
value: function (b) {
var idx = this.indexOf(b);
2024-09-26 11:36:09 -05:00
if (idx === -1) return false;
this.splice(idx, 1);
2024-09-26 11:36:09 -05:00
return true;
},
});
Object.defineProperty(Array.prototype, "set", {
value: function (b) {
if (this.length !== b.length) return;
2024-09-26 11:36:09 -05:00
b.forEach(function (val, i) {
this[i] = val;
}, this);
},
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Array.prototype, "flat", {
value: function () {
return [].concat.apply([], this);
},
});
/* Return true if array contains x */
2024-09-26 11:36:09 -05:00
Object.defineProperty(Array.prototype, "empty", {
get: function () {
return this.length === 0;
},
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Array.prototype, "push_unique", {
value: function (x) {
var inc = !this.includes(x);
if (inc) this.push(x);
return inc;
},
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Array.prototype, "unique", {
value: function () {
var c = [];
2024-09-26 11:36:09 -05:00
this.forEach(function (x) {
c.push_unique(x);
});
return c;
2024-09-26 11:36:09 -05:00
},
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Array.prototype, "unduped", {
value: function () {
return [...new Set(this)];
},
2024-06-26 16:57:17 -05:00
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Array.prototype, "findIndex", {
value: function (fn) {
var idx = -1;
this.every(function (x, i) {
if (fn(x)) {
idx = i;
return false;
}
2024-09-26 11:36:09 -05:00
return true;
});
2024-09-26 11:36:09 -05:00
return idx;
},
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Array.prototype, "find", {
value: function (fn) {
var ret;
2024-09-26 11:36:09 -05:00
this.every(function (x) {
if (fn(x)) {
ret = x;
return false;
}
2024-09-26 11:36:09 -05:00
return true;
});
2024-09-26 11:36:09 -05:00
return ret;
},
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Array.prototype, "search", {
value: function (val) {
for (var i = 0; i < this.length; i++) if (this[i] === val) return i;
2024-06-26 16:57:17 -05:00
return undefined;
2024-09-26 11:36:09 -05:00
},
2024-06-26 16:57:17 -05:00
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Array.prototype, "last", {
value: function () {
return this[this.length - 1];
},
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Array.prototype, "at", {
value: function (x) {
return x < 0 ? this[this.length + x] : this[x];
},
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Array.prototype, "wrapped", {
value: function (x) {
var c = this.slice(0, this.length);
2024-09-26 11:36:09 -05:00
for (var i = 0; i < x; i++) c.push(this[i]);
return c;
2024-09-26 11:36:09 -05:00
},
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Array.prototype, "wrap_idx", {
value: function (x) {
while (x >= this.length) {
x -= this.length;
}
return x;
2024-09-26 11:36:09 -05:00
},
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Array.prototype, "mirrored", {
value: function (x) {
var c = this.slice(0);
if (c.length <= 1) return c;
2024-09-26 11:36:09 -05:00
for (var i = c.length - 2; i >= 0; i--) c.push(c[i]);
return c;
2024-09-26 11:36:09 -05:00
},
});
Math.lerp = vector.lerp;
Math.gcd = vector.gcd;
Math.lcm = vector.lcm;
Math.sum = vector.sum;
Math.mean = vector.mean;
Math.sigma = vector.sigma;
Math.median = vector.median;
2024-09-26 11:36:09 -05:00
Math.variance = function (series) {
var mean = Math.mean(series);
var vnce = 0;
2024-09-26 11:36:09 -05:00
for (var i = 0; i < series.length; i++) vnce += Math.pow(series[i] - mean, 2);
return vnce / series.length;
};
2023-06-05 17:19:43 -05:00
2024-09-26 11:36:09 -05:00
Math.ci = function (series) {
return (3 * Math.sigma(series)) / Math.sqrt(series.length);
};
2023-09-11 02:46:12 -05:00
2024-09-26 11:36:09 -05:00
Math.grab_from_points = function (pos, points, slop) {
2023-11-29 17:31:41 -06:00
var shortest = slop;
var idx = -1;
2024-09-26 11:36:09 -05:00
points.forEach(function (x, i) {
2023-11-29 17:31:41 -06:00
if (Vector.length(pos.sub(x)) < shortest) {
shortest = Vector.length(pos.sub(x));
idx = i;
}
});
return idx;
};
2024-09-26 11:36:09 -05:00
Math.nearest = function (n, incr) {
return Math.round(n / incr) * incr;
};
2023-11-29 17:31:41 -06:00
2024-09-26 11:36:09 -05:00
Math.places = function (n, digits) {
var div = Math.pow(10, digits);
return Math.round(n * div) / div;
};
2023-12-27 10:34:14 -06:00
2024-09-26 11:36:09 -05:00
Number.hex = function (n) {
2023-10-09 13:03:12 -05:00
var s = Math.floor(n).toString(16);
2024-09-26 11:36:09 -05:00
if (s.length === 1) s = "0" + s;
2023-10-09 13:03:12 -05:00
return s.uc();
2024-09-26 11:36:09 -05:00
};
2023-10-09 13:03:12 -05:00
2024-09-26 11:36:09 -05:00
Object.defineProperty(Object.prototype, "lerp", {
value: function (to, t) {
2023-06-05 17:19:43 -05:00
var self = this;
var obj = {};
2024-09-26 11:36:09 -05:00
Object.keys(self).forEach(function (key) {
obj[key] = self[key].lerp(to[key], t);
2023-06-05 17:19:43 -05:00
});
return obj;
2024-09-26 11:36:09 -05:00
},
});
/* MATH EXTENSIONS */
2024-09-26 11:36:09 -05:00
Object.defineProperty(Number.prototype, "lerp", {
value: function (to, t) {
return Math.lerp(this, to, t);
},
2023-06-05 17:19:43 -05:00
});
2024-09-26 11:36:09 -05:00
Object.defineProperty(Number.prototype, "clamp", {
value: function (from, to) {
return Math.clamp(this, from, to);
},
2024-07-16 15:37:07 -05:00
});
Math.clamp = vector.clamp;
Math.random_range = vector.random_range;
2024-09-26 11:36:09 -05:00
Math.rand_int = function (max = 9007199254740991) {
return Math.floor(Math.random() * max);
};
2023-04-28 12:49:18 -05:00
2024-09-26 11:36:09 -05:00
Math.snap = function (val, grid) {
if (!grid || grid === 1) return Math.round(val);
2024-09-26 11:36:09 -05:00
var rem = val % grid;
var d = val - rem;
2024-09-26 11:36:09 -05:00
var i = Math.round(rem / grid) * grid;
return d + i;
};
Math.angledist = vector.angledist;
Math.angledist.doc = "Find the shortest angle between two angles.";
2024-09-26 11:36:09 -05:00
Math.TAU = Math.PI * 2;
Math.deg2rad = function (deg) {
return deg * 0.0174533;
};
Math.rad2deg = function (rad) {
return rad / 0.0174533;
};
Math.turn2rad = function (x) {
return x * Math.TAU;
};
Math.rad2turn = function (x) {
return x / Math.TAU;
};
Math.turn2deg = function (x) {
return x * 360;
};
Math.deg2turn = function (x) {
return x / 360;
};
Math.randomint = function (max) {
return Math.clamp(Math.floor(Math.random() * max), 0, max - 1);
};
Math.variate = vector.variate;
/* BOUNDINGBOXES */
2024-02-25 17:31:48 -06:00
var bbox = {};
2024-09-26 11:36:09 -05:00
bbox.overlap = function (box1, box2) {
return box1.l > box2.l && box1.r < box2.r && box1.t < box2.t && box1.b > box2.b;
return box1.l > box2.r || box1.r < box2.l || box1.t > box2.b || box1.b < box2.t;
};
2024-03-22 09:02:10 -05:00
2024-09-26 11:36:09 -05:00
bbox.fromcwh = function (c, wh) {
return {
2024-09-26 11:36:09 -05:00
t: c.y + wh.y / 2,
b: c.y - wh.y / 2,
l: c.x - wh.x / 2,
r: c.x + wh.x / 2,
};
};
2024-09-26 11:36:09 -05:00
bbox.frompoints = function (points) {
var b = { t: 0, b: 0, l: 0, r: 0 };
points.forEach(function (x) {
if (x.y > b.t) b.t = x.y;
if (x.y < b.b) b.b = x.y;
if (x.x > b.r) b.r = x.x;
if (x.x < b.l) b.l = x.x;
});
return b;
};
2024-09-26 11:36:09 -05:00
bbox.topoints = function (bb) {
2023-06-05 10:32:45 -05:00
return [
2024-09-26 11:36:09 -05:00
[bb.l, bb.t],
[bb.r, bb.t],
[bb.r, bb.b],
[bb.l, bb.b],
2023-06-05 10:32:45 -05:00
];
2024-09-26 11:36:09 -05:00
};
2024-09-26 11:36:09 -05:00
bbox.tocwh = function (bb) {
if (!bb) return undefined;
var cwh = {};
var w = bb.r - bb.l;
var h = bb.t - bb.b;
cwh.wh = [w, h];
2024-09-26 11:36:09 -05:00
cwh.c = [bb.l + w / 2, bb.b + h / 2];
return cwh;
};
2024-09-26 11:36:09 -05:00
bbox.towh = function (bb) {
return [bb.r - bb.l, bb.t - bb.b];
};
2024-09-26 11:36:09 -05:00
bbox.pointin = function (bb, p) {
if (bb.t < p.y || bb.b > p.y || bb.l > p.x || bb.r < p.x) return false;
2023-06-05 10:32:45 -05:00
return true;
2024-09-26 11:36:09 -05:00
};
2023-06-05 10:32:45 -05:00
2024-09-26 11:36:09 -05:00
bbox.zero = function (bb) {
var newbb = Object.assign({}, bb);
2024-07-14 16:09:50 -05:00
newbb.r -= newbb.l;
newbb.t -= newbb.b;
newbb.b = 0;
newbb.l = 0;
return newbb;
2024-09-26 11:36:09 -05:00
};
2024-07-14 16:09:50 -05:00
2024-09-26 11:36:09 -05:00
bbox.move = function (bb, pos) {
2023-06-05 10:32:45 -05:00
var newbb = Object.assign({}, bb);
newbb.t += pos.y;
newbb.b += pos.y;
newbb.l += pos.x;
newbb.r += pos.x;
return newbb;
};
2024-09-26 11:36:09 -05:00
bbox.moveto = function (bb, pos) {
2024-07-14 16:09:50 -05:00
bb = bbox.zero(bb);
return bbox.move(bb, pos);
2024-09-26 11:36:09 -05:00
};
2024-07-14 16:09:50 -05:00
2024-09-26 11:36:09 -05:00
bbox.expand = function (oldbb, x) {
if (!oldbb || !x) return;
var bb = {};
Object.assign(bb, oldbb);
2024-09-26 11:36:09 -05:00
if (bb.t < x.t) bb.t = x.t;
if (bb.r < x.r) bb.r = x.r;
if (bb.b > x.b) bb.b = x.b;
if (bb.l > x.l) bb.l = x.l;
return bb;
};
2024-09-26 11:36:09 -05:00
bbox.blwh = function (bl, wh) {
2023-10-04 17:57:37 -05:00
return {
b: bl.y,
l: bl.x,
r: bl.x + wh.x,
2024-09-26 11:36:09 -05:00
t: bl.y + wh.y,
2023-10-04 17:57:37 -05:00
};
2024-09-26 11:36:09 -05:00
};
2023-10-04 17:57:37 -05:00
bbox.blwh.doc = "Bounding box from (bottom left, width height)";
2024-09-26 11:36:09 -05:00
bbox.fromobjs = function (objs) {
var bb = objs[0].boundingbox;
2024-09-26 11:36:09 -05:00
objs.forEach(function (obj) {
bb = bbox.expand(bb, obj.boundingbox);
});
return bb;
};
/* VECTORS */
2024-03-18 14:27:52 -05:00
var Vector = {};
2024-08-05 15:26:18 -05:00
Vector.length = vector.length;
Vector.norm = vector.norm;
Vector.project = vector.project;
Vector.dot = vector.dot;
2024-09-26 11:36:09 -05:00
Vector.random = function () {
var vec = [Math.random() - 0.5, Math.random() - 0.5];
2024-03-18 14:27:52 -05:00
return Vector.norm(vec);
2024-09-26 11:36:09 -05:00
};
2024-06-25 17:53:15 -05:00
Vector.angle_between = vector.angle_between;
Vector.rotate = vector.rotate;
2024-08-08 13:25:47 -05:00
2024-09-26 11:36:09 -05:00
vector.direction = function (from, to) {
2024-08-08 13:25:47 -05:00
return vector.norm(to.sub(from));
2024-09-26 11:36:09 -05:00
};
Vector.equal = function (v1, v2, tol) {
if (!tol) return v1.equal(v2);
2024-03-18 14:27:52 -05:00
var eql = true;
var c = v1.sub(v2);
2024-09-26 11:36:09 -05:00
c.forEach(function (x) {
2024-03-18 14:27:52 -05:00
if (!eql) return;
2024-09-26 11:36:09 -05:00
if (Math.abs(x) > tol) eql = false;
2024-03-18 14:27:52 -05:00
});
2024-03-18 14:27:52 -05:00
return eql;
2024-09-26 11:36:09 -05:00
};
2023-11-15 16:42:39 -06:00
2024-09-26 11:36:09 -05:00
Vector.reflect = function (vec, plane) {
2024-03-18 14:27:52 -05:00
var p = Vector.norm(plane);
2024-09-26 11:36:09 -05:00
return vec.sub(p.scale(2 * Vector.dot(vec, p)));
};
2023-12-20 17:20:29 -06:00
2024-09-26 11:36:09 -05:00
Vector.reflect_point = function (vec, point) {
return point.add(vec.sub(point).scale(-1));
};
/* POINT ASSISTANCE */
2024-09-26 11:36:09 -05:00
function points2cm(points) {
var x = 0;
var y = 0;
var n = points.length;
2024-09-26 11:36:09 -05:00
points.forEach(function (p) {
x = x + p[0];
y = y + p[1];
});
2024-09-26 11:36:09 -05:00
return [x / n, y / n];
}
Math.sortpointsccw = function (points) {
var cm = points2cm(points);
2024-09-26 11:36:09 -05:00
var cmpoints = points.map(function (x) {
return x.sub(cm);
});
var ccw = cmpoints.sort(function (a, b) {
2024-05-28 13:39:02 -05:00
var aatan = Math.atan2(a.y, a.x);
var batan = Math.atan2(b.y, b.x);
return aatan - batan;
});
2024-09-26 11:36:09 -05:00
return ccw.map(function (x) {
return x.add(cm);
});
};
2024-04-30 10:32:27 -05:00
var yaml = {};
2024-09-26 11:36:09 -05:00
yaml.tojson = function (yaml) {
2024-05-30 17:12:32 -05:00
// Replace key value pairs that are strings with quotation marks around them
2024-04-30 10:32:27 -05:00
yaml = yaml.replace(/(\w+):/g, '"$1":');
2024-05-30 17:12:32 -05:00
yaml = yaml.replace(/: ([\w\.\/]+)/g, ': "$1"'); // TODO: make this more general
2024-09-26 11:36:09 -05:00
2024-04-30 10:32:27 -05:00
yaml = yaml.split("\n");
var cont = {};
var cur = 0;
for (var i = 0; i < yaml.length; i++) {
var line = yaml[i];
var indent = line.search(/\S/);
2024-09-26 11:36:09 -05:00
2024-04-30 10:32:27 -05:00
if (indent > cur) {
if (line[indent] == "-") {
cont[indent] = "array";
2024-09-26 11:36:09 -05:00
yaml[i] = line.sub(indent, "[");
2024-04-30 10:32:27 -05:00
} else {
cont[indent] = "obj";
2024-09-26 11:36:09 -05:00
yaml[i] = line.sub(indent - 1, "{");
2024-04-30 10:32:27 -05:00
}
}
2024-09-26 11:36:09 -05:00
2024-04-30 10:32:27 -05:00
if (indent < cur) {
while (cur > indent) {
2024-09-26 11:36:09 -05:00
if (cont[cur] === "obj") yaml[i - 1] = yaml[i - 1] + "}";
else if (cont[cur] === "array") yaml[i - 1] = yaml[i - 1] + "]";
delete cont[cur];
cur--;
2024-04-30 10:32:27 -05:00
}
}
if (indent === cur) {
2024-09-26 11:36:09 -05:00
if (yaml[i][indent] === "-") yaml[i] = yaml[i].sub(indent, ",");
else yaml[i - 1] = yaml[i - 1] + ",";
2024-04-30 10:32:27 -05:00
}
2024-09-26 11:36:09 -05:00
2024-04-30 10:32:27 -05:00
cur = indent;
}
yaml = "{" + yaml.join("\n") + "}";
2024-09-26 11:36:09 -05:00
yaml = yaml.replace(/\s/g, "");
yaml = yaml.replace(/,}/g, "}");
yaml = yaml.replace(/,]/g, "]");
yaml = yaml.replace(/,"[^"]+"\:,/g, ",");
return yaml;
};
2024-04-30 10:32:27 -05:00
2024-09-26 11:36:09 -05:00
Math.sign = function (n) {
return n >= 0 ? 1 : -1;
};
2024-05-28 13:39:02 -05:00
2024-09-26 19:28:54 -05:00
var lodash = {};
2024-09-26 23:12:30 -05:00
lodash.get = function (obj, path, defValue) {
if (!path) return undefined;
2024-09-26 19:28:54 -05:00
// Check if path is string or array. Regex : ensure that we do not have '.' and brackets.
2024-09-26 23:12:30 -05:00
var pathArray = Array.isArray(path) ? path : path.match(/([^[.\]])+/g);
var result = pathArray.reduce((prevObj, key) => prevObj && prevObj[key], obj);
return result === undefined ? defValue : result;
};
2024-09-26 19:28:54 -05:00
return {
convert,
time,
Vector,
2024-04-30 10:32:27 -05:00
bbox,
2024-09-26 11:36:09 -05:00
yaml,
2024-09-26 23:12:30 -05:00
lodash,
};