mirror of
https://github.com/JannisX11/blockbench.git
synced 2024-12-03 04:40:46 +08:00
f7f1b53455
Support format "features" inside conditions Fix issue with clicking actions in action control Add mesh UV rotate actions UV size sliders now work for meshes Complete blender keymap
710 lines
18 KiB
JavaScript
710 lines
18 KiB
JavaScript
//Blockbench
|
|
function compareVersions(string1/*new*/, string2/*old*/) {
|
|
// Is string1 newer than string2 ?
|
|
var arr1 = string1.split(/[.-]/);
|
|
var arr2 = string2.split(/[.-]/);
|
|
var i = 0;
|
|
var num1 = 0;
|
|
var num2 = 0;
|
|
while (i < Math.max(arr1.length, arr2.length)) {
|
|
num1 = arr1[i];
|
|
num2 = arr2[i];
|
|
if (num1 == 'beta') num1 = -1;
|
|
if (num2 == 'beta') num2 = -1;
|
|
num1 = parseInt(num1) || 0;
|
|
num2 = parseInt(num2) || 0;
|
|
if (num1 > num2) {
|
|
return true;
|
|
} else if (num1 < num2) {
|
|
return false
|
|
}
|
|
i++;
|
|
}
|
|
return false;
|
|
}
|
|
/**
|
|
*
|
|
* @param {*} condition Input condition. Can be undefined, a boolean, a function or a condition object
|
|
* @param {*} context
|
|
*/
|
|
const Condition = function(condition, context) {
|
|
if (condition !== undefined && condition !== null && condition.condition !== undefined) {
|
|
condition = condition.condition
|
|
}
|
|
if (condition === undefined) {
|
|
return true;
|
|
} else if (typeof condition === 'function') {
|
|
return condition(context)
|
|
} else if (typeof condition === 'object') {
|
|
if (condition.modes instanceof Array && condition.modes.includes(Modes.id) === false) return false;
|
|
if (condition.formats instanceof Array && condition.formats.includes(Format.id) === false) return false;
|
|
if (condition.tools instanceof Array && window.Toolbox && condition.tools.includes(Toolbox.selected.id) === false) return false;
|
|
if (condition.features instanceof Array && Format && condition.features.find(feature => !Format[feature])) return false;
|
|
|
|
if (condition.method instanceof Function) {
|
|
return condition.method(context);
|
|
}
|
|
return true;
|
|
} else {
|
|
return !!condition
|
|
}
|
|
}
|
|
class oneLiner {
|
|
constructor(data) {
|
|
if (data !== undefined) {
|
|
for (var key in data) {
|
|
if (data.hasOwnProperty(key)) {
|
|
this[key] = data[key]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
var templog = console.log
|
|
var asyncLoop = function(o){
|
|
var i=-1;
|
|
var async_loop = function(){
|
|
i++;
|
|
if(i==o.length){o.callback(); return;}
|
|
o.functionToLoop(async_loop, i);
|
|
}
|
|
async_loop();//init
|
|
}
|
|
Date.prototype.getTimestamp = function() {
|
|
var l2 = i => (i.toString().length === 1 ? '0'+i : i);
|
|
return l2(this.getHours()) + ':' + l2(this.getMinutes());
|
|
}
|
|
Object.defineProperty(Event.prototype, 'ctrlOrCmd', {
|
|
get: function() {
|
|
return this.ctrlKey || this.metaKey;
|
|
}
|
|
})
|
|
Object.defineProperty($.Event.prototype, 'ctrlOrCmd', {
|
|
get: function() {
|
|
return this.ctrlKey || this.metaKey;
|
|
}
|
|
})
|
|
|
|
function convertTouchEvent(event) {
|
|
if (event && event.changedTouches && event.changedTouches.length && event.offsetX == undefined) {
|
|
//event.preventDefault();
|
|
event.clientX = event.changedTouches[0].clientX;
|
|
event.clientY = event.changedTouches[0].clientY;
|
|
event.offsetX = event.changedTouches[0].clientX;
|
|
event.offsetY = event.changedTouches[0].clientY;
|
|
|
|
var offset = $(event.target).offset();
|
|
if (offset) {
|
|
event.offsetX -= offset.left;
|
|
event.offsetY -= offset.top;
|
|
}
|
|
}
|
|
return event;
|
|
}
|
|
function addEventListeners(el, events, func, option) {
|
|
events.split(' ').forEach(e => {
|
|
el.addEventListener(e, func, option)
|
|
})
|
|
}
|
|
function removeEventListeners(el, events, func, option) {
|
|
events.split(' ').forEach(e => {
|
|
el.removeEventListener(e, func, option)
|
|
})
|
|
}
|
|
|
|
//Jquery
|
|
$.fn.deepest = function() {
|
|
if (!this.length) return this;
|
|
var opts = []
|
|
this.each((i, node) => {
|
|
var i = 0;
|
|
var obj = $(node)
|
|
while (obj.parent().get(0) instanceof HTMLBodyElement === false) {
|
|
obj = obj.parent()
|
|
i++;
|
|
}
|
|
opts.push({depth: i, o: node})
|
|
})
|
|
opts.sort((a, b) => (a.depth < b.depth));
|
|
return $(opts[0].o)
|
|
}
|
|
|
|
//Math
|
|
function guid() {
|
|
function s4() {
|
|
return Math.floor((1 + Math.random()) * 0x10000)
|
|
.toString(16)
|
|
.substring(1);
|
|
}
|
|
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
|
|
s4() + '-' + s4() + s4() + s4();
|
|
}
|
|
function isUUID(s) {
|
|
return (s.length === 36 && s.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/))
|
|
}
|
|
function bbuid(l) {
|
|
l = l || 1
|
|
let chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
|
var s = '';
|
|
while (l > 0) {
|
|
var n = Math.floor(Math.random()*62)
|
|
if (n > 9) {
|
|
n = chars[n-10]
|
|
}
|
|
s += n
|
|
l--;
|
|
}
|
|
return s;
|
|
}
|
|
Math.radToDeg = function(rad) {
|
|
return rad / Math.PI * 180
|
|
}
|
|
Math.degToRad = function(deg) {
|
|
return Math.PI / (180 /deg)
|
|
}
|
|
Math.roundTo = function(num, digits) {
|
|
var d = Math.pow(10,digits)
|
|
return Math.round(num * d) / d
|
|
}
|
|
Math.lerp = function(a,b,m) {
|
|
return (m-a) / (b-a)
|
|
}
|
|
Math.isBetween = function(number, limit1, limit2) {
|
|
return (number - limit1) * (number - limit2) <= 0
|
|
}
|
|
Math.epsilon = function(a, b, epsilon) {
|
|
return Math.abs(b - a) < epsilon
|
|
}
|
|
Math.trimDeg = function(a) {
|
|
return (a+180*15)%360-180
|
|
}
|
|
Math.isPowerOfTwo = function(x) {
|
|
return (x > 1) && ((x & (x - 1)) == 0);
|
|
}
|
|
Math._numbertype = 'number';
|
|
Math.isNumber = function(x) {
|
|
return typeof x == Math._numbertype;
|
|
}
|
|
Math.randomab = function(a, b) {
|
|
return a + Math.random()*(b-a);
|
|
}
|
|
Math.areMultiples = function(n1, n2) {
|
|
return (
|
|
(n1/n2)%1 === 0 ||
|
|
(n2/n1)%1 === 0
|
|
)
|
|
}
|
|
Math.getNextPower = function(num, min) {
|
|
var i = min ? min : 2
|
|
while (i < num && i < 4000) {
|
|
i *= 2
|
|
}
|
|
return i;
|
|
}
|
|
Math.snapToValues = function(val, snap_points, epsilon = 12) {
|
|
let snaps = snap_points.slice().sort((a, b) => {
|
|
return Math.abs(val-a) - Math.abs(val-b)
|
|
})
|
|
if (Math.abs(snaps[0] - val) < epsilon) {
|
|
return snaps[0]
|
|
} else {
|
|
return val
|
|
}
|
|
}
|
|
function trimFloatNumber(val) {
|
|
if (val == '') return val;
|
|
var string = val.toFixed(4)
|
|
string = string.replace(/0+$/g, '').replace(/\.$/g, '')
|
|
if (string == -0) return 0;
|
|
return string;
|
|
}
|
|
function getAxisLetter(number) {
|
|
switch (number) {
|
|
case 0: return 'x'; break;
|
|
case 1: return 'y'; break;
|
|
case 2: return 'z'; break;
|
|
}
|
|
}
|
|
function getAxisNumber(letter) {
|
|
switch (letter.toLowerCase()) {
|
|
case 'x': return 0; break;
|
|
case 'y': return 1; break;
|
|
case 'z': return 2; break;
|
|
}
|
|
}
|
|
function limitNumber(number, min, max) {
|
|
if (number > max) number = max;
|
|
if (number < min || isNaN(number)) number = min;
|
|
return number;
|
|
}
|
|
function highestInObject(obj, inverse) {
|
|
var n = inverse ? Infinity : -Infinity;
|
|
var result;
|
|
for (var key in obj) {
|
|
if ( (!inverse && obj[key] > n) || (inverse && obj[key] < n) ) {
|
|
n = obj[key];
|
|
result = key;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
Math.clamp = limitNumber;
|
|
function getRectangle(a, b, c, d) {
|
|
var rect = {};
|
|
if (!b && typeof a === 'object') {
|
|
rect = a
|
|
} else if (typeof a === 'object' && a.x) {
|
|
rect.ax = a.x
|
|
rect.ay = a.y
|
|
|
|
rect.bx = b.x
|
|
rect.by = b.y
|
|
} else {
|
|
rect.ax = a
|
|
rect.ay = b
|
|
if (typeof c === 'number' && typeof d === 'number') {
|
|
rect.bx = c
|
|
rect.by = d
|
|
} else {
|
|
rect.bx = a
|
|
rect.by = b
|
|
}
|
|
}
|
|
if (rect.ax > rect.bx) {
|
|
[rect.ax, rect.bx] = [rect.bx, rect.ax]
|
|
}
|
|
if (rect.ay > rect.by) {
|
|
[rect.ay, rect.by] = [rect.by, rect.ay]
|
|
}
|
|
rect.x = rect.bx - rect.ax
|
|
rect.y = rect.by - rect.ay
|
|
return rect;
|
|
}
|
|
function doRectanglesOverlap(rect1, rect2) {
|
|
if (rect1.ax > rect2.bx || rect2.ax > rect1.bx) {
|
|
return false
|
|
}
|
|
if (rect1.ay > rect2.by || rect2.ay > rect1.by) {
|
|
return false
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//Date
|
|
Number.prototype.toDigitString = function(digits) {
|
|
if (!digits) digits = 1;
|
|
var s = this.toString();
|
|
var l = s.length
|
|
for (var i = 0; i < (digits-l); i++) {
|
|
s = '0'+s;
|
|
}
|
|
return s;
|
|
}
|
|
Date.prototype.getDateArray = function() {
|
|
return [
|
|
this.getDate(),
|
|
this.getMonth()+1,
|
|
this.getYear()+1900
|
|
];
|
|
}
|
|
Date.prototype.getDateString = function() {
|
|
var a = this.getDateArray();
|
|
return `${a[0].toDigitString(2)}.${a[1].toDigitString(2)}.${a[2]}`;
|
|
}
|
|
Date.prototype.dayOfYear = function() {
|
|
var start = new Date(this.getFullYear(), 0, 0);
|
|
var diff = this - start;
|
|
var oneDay = 1000 * 60 * 60 * 24;
|
|
return Math.floor(diff / oneDay);
|
|
|
|
}
|
|
|
|
//Array
|
|
Array.prototype.safePush = function(...items) {
|
|
let included = false;
|
|
for (var item of items) {
|
|
if (!this.includes(item)) {
|
|
this.push(item);
|
|
included = true;
|
|
}
|
|
}
|
|
return included;
|
|
}
|
|
Array.prototype.equals = function (array) {
|
|
if (!array)
|
|
return false;
|
|
|
|
if (this.length != array.length)
|
|
return false;
|
|
|
|
for (var i = 0, l=this.length; i < l; i++) {
|
|
if (this[i] instanceof Array && array[i] instanceof Array) {
|
|
if (!this[i].equals(array[i]))
|
|
return false;
|
|
}
|
|
else if (this[i] != array[i]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
Array.prototype.remove = function (...items) {
|
|
items.forEach(item => {
|
|
var index = this.indexOf(item)
|
|
if (index > -1) {
|
|
this.splice(index, 1)
|
|
return index;
|
|
}
|
|
return false;
|
|
})
|
|
}
|
|
Array.prototype.empty = function() {
|
|
this.splice(0, Infinity);
|
|
return this;
|
|
}
|
|
Array.prototype.purge = function() {
|
|
this.splice(0, Infinity);
|
|
return this;
|
|
}
|
|
Array.prototype.replace = function(items) {
|
|
this.splice(0, Infinity, ...items);
|
|
return this;
|
|
}
|
|
Array.prototype.findInArray = function(key, value) {
|
|
for (var i = 0; i < this.length; i++) {
|
|
if (this[i][key] === value) return this[i]
|
|
}
|
|
return false;
|
|
}
|
|
Array.prototype.last = function() {
|
|
return this[this.length-1];
|
|
}
|
|
Array.prototype.positiveItems = function() {
|
|
var x = 0, i = 0;
|
|
while (i < this.length) {
|
|
if (this[i]) x++;
|
|
i++;
|
|
}
|
|
return x;
|
|
}
|
|
Array.prototype.allEqual = function(s) {
|
|
var i = 0;
|
|
while (i < this.length) {
|
|
if (this[i] !== s) {
|
|
return false;
|
|
}
|
|
i++;
|
|
}
|
|
return true;
|
|
}
|
|
Array.prototype.random = function() {
|
|
return this[Math.floor(Math.random()*this.length)]
|
|
}
|
|
Array.prototype.forEachReverse = function(cb) {
|
|
var i = this.length;
|
|
for (var i = this.length-1; i >= 0; i--) {
|
|
cb(this[i], i);
|
|
}
|
|
}
|
|
Array.prototype.overlap = function(arr2) {
|
|
var count = 0;
|
|
for (var item of this) {
|
|
if (arr2.includes(item)) count++;
|
|
}
|
|
return count;
|
|
}
|
|
Array.prototype.toggle = function(item, state = !this.includes(item)) {
|
|
if (state) {
|
|
this.safePush(item);
|
|
} else {
|
|
this.remove(item);
|
|
}
|
|
}
|
|
|
|
//Array Vector
|
|
Array.prototype.V3_set = function(x, y, z) {
|
|
if (x instanceof Array) return this.V3_set(...x);
|
|
if (y === undefined && z === undefined) z = y = x;
|
|
this[0] = parseFloat(x)||0;
|
|
this[1] = parseFloat(y)||0;
|
|
this[2] = parseFloat(z)||0;
|
|
return this;
|
|
}
|
|
Array.prototype.V3_add = function(x, y, z) {
|
|
if (x instanceof Array) return this.V3_add(...x);
|
|
if (x instanceof THREE.Vector3) return this.V3_add(x.x, x.y, x.z);
|
|
this[0] += parseFloat(x)||0;
|
|
this[1] += parseFloat(y)||0;
|
|
this[2] += parseFloat(z)||0;
|
|
return this;
|
|
}
|
|
Array.prototype.V3_subtract = function(x, y, z) {
|
|
if (x instanceof Array) return this.V3_subtract(...x);
|
|
if (x instanceof THREE.Vector3) return this.V3_subtract(x.x, x.y, x.z);
|
|
this[0] -= parseFloat(x)||0;
|
|
this[1] -= parseFloat(y)||0;
|
|
this[2] -= parseFloat(z)||0;
|
|
return this;
|
|
}
|
|
Array.prototype.V3_multiply = function(x, y, z) {
|
|
if (x instanceof Array) return this.V3_multiply(...x);
|
|
if (x instanceof THREE.Vector3) return this.V3_multiply(x.x, x.y, x.z);
|
|
if (y === undefined && z === undefined) z = y = x;
|
|
this[0] *= parseFloat(x)||0;
|
|
this[1] *= parseFloat(y)||0;
|
|
this[2] *= parseFloat(z)||0;
|
|
return this;
|
|
}
|
|
Array.prototype.V3_divide = function(x, y, z) {
|
|
if (x instanceof Array) return this.V3_divide(...x);
|
|
if (x instanceof THREE.Vector3) return this.V3_divide(x.x, x.y, x.z);
|
|
if (y === undefined && z === undefined) z = y = x;
|
|
this[0] /= parseFloat(x)||1;
|
|
this[1] /= parseFloat(y)||1;
|
|
this[2] /= parseFloat(z)||1;
|
|
return this;
|
|
}
|
|
Array.prototype.V3_toThree = function() {
|
|
return new THREE.Vector3(this[0], this[1], this[2]);
|
|
}
|
|
|
|
//Object
|
|
Object.defineProperty(Array.prototype, "equals", {enumerable: false});
|
|
|
|
function omitKeys(obj, keys, dual_level) {
|
|
var dup = {};
|
|
for (key in obj) {
|
|
if (keys.indexOf(key) == -1) {
|
|
if (dual_level === true && typeof obj[key] === 'object') {
|
|
dup[key] = {}
|
|
for (key2 in obj[key]) {
|
|
if (keys.indexOf(key2) == -1) {
|
|
dup[key][key2] = obj[key][key2];
|
|
}
|
|
}
|
|
} else {
|
|
dup[key] = obj[key];
|
|
}
|
|
}
|
|
}
|
|
return dup;
|
|
}
|
|
function get (options, name, defaultValue) {
|
|
return (name in options ? options[name] : defaultValue)
|
|
}
|
|
function getKeyByValue(object, value) {
|
|
return Object.keys(object).find(key => object[key] === value);
|
|
}
|
|
|
|
var Objector = {
|
|
equalKeys: function(obj, ref) {
|
|
for (var key in obj) {
|
|
if (obj.hasOwnProperty(key)) {
|
|
if (!ref.hasOwnProperty(key)) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
for (var key in ref) {
|
|
if (ref.hasOwnProperty(key)) {
|
|
if (!obj.hasOwnProperty(key)) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
},
|
|
keyLength: function(obj) {
|
|
var l = 0;
|
|
for (var key in obj) {
|
|
if (obj.hasOwnProperty(key)) {
|
|
l++;
|
|
}
|
|
}
|
|
return l;
|
|
}
|
|
}
|
|
|
|
var Merge = {
|
|
number: function(obj, source, index) {
|
|
if (source[index] !== undefined) {
|
|
var val = source[index]
|
|
if (typeof val === 'number' && !isNaN(val)) {
|
|
obj[index] = val
|
|
} else {
|
|
val = parseFloat(val)
|
|
if (typeof val === 'number' && !isNaN(val)) {
|
|
obj[index] = val
|
|
}
|
|
}
|
|
}
|
|
},
|
|
string: function(obj, source, index, validate) {
|
|
if (source[index] || typeof source[index] === 'string') {
|
|
var val = source[index]
|
|
if (typeof val !== 'string') val = val.toString();
|
|
if (validate instanceof Function === false || validate(val)) {
|
|
obj[index] = val
|
|
}
|
|
}
|
|
},
|
|
molang: function(obj, source, index) {
|
|
if (['string', 'number'].includes(typeof source[index])) {
|
|
obj[index] = source[index];
|
|
}
|
|
},
|
|
boolean: function(obj, source, index, validate) {
|
|
if (source[index] !== undefined) {
|
|
if (validate instanceof Function === false || validate(source[index])) {
|
|
obj[index] = source[index]
|
|
}
|
|
}
|
|
},
|
|
function: function(obj, source, index, validate) {
|
|
if (typeof source[index] === 'function') {
|
|
if (validate instanceof Function === false || validate(source[index])) {
|
|
obj[index] = source[index]
|
|
}
|
|
}
|
|
},
|
|
arrayVector: function(obj, source, index, validate) {
|
|
if (source[index] instanceof Array) {
|
|
if (validate instanceof Function === false || validate(source[index])) {
|
|
obj[index].V3_set(source[index]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function onVueSetup(func) {
|
|
if (!onVueSetup.funcs) {
|
|
onVueSetup.funcs = []
|
|
}
|
|
onVueSetup.funcs.push(func)
|
|
}
|
|
|
|
//String
|
|
function capitalizeFirstLetter(string) {
|
|
return string.charAt(0).toUpperCase() + string.slice(1);
|
|
}
|
|
function autoStringify(object) {
|
|
return compileJSON(object, {small: settings.minifiedout.value})
|
|
}
|
|
function pluralS(arr) {
|
|
if (arr.length === 1 || arr === 1) {
|
|
return '';
|
|
} else {
|
|
return 's';
|
|
}
|
|
}
|
|
function pathToName(path, extension) {
|
|
var path_array = path.split('/').join('\\').split('\\')
|
|
if (extension === true) {
|
|
return path_array[path_array.length-1]
|
|
} else {
|
|
return path_array[path_array.length-1].replace(/\.\w+$/, '')
|
|
}
|
|
}
|
|
function pathToExtension(path) {
|
|
if (typeof path !== 'string') return '';
|
|
var matches = path.match(/\.\w{2,24}$/)
|
|
if (!matches || !matches.length) return '';
|
|
return matches[0].replace('.', '').toLowerCase()
|
|
}
|
|
Object.defineProperty(String.prototype, 'hashCode', {
|
|
value() {
|
|
var hash = 0, i, chr;
|
|
for (i = 0; i < this.length; i++) {
|
|
chr = this.charCodeAt(i);
|
|
hash = ((hash << 5) - hash) + chr;
|
|
hash |= 0;
|
|
}
|
|
return hash;
|
|
}
|
|
});
|
|
|
|
//Color
|
|
tinycolor.prototype.toInt = function() {
|
|
var rgba = this.toRgb()
|
|
return Jimp.rgbaToInt(rgba.r, rgba.g, rgba.b, rgba.a)
|
|
}
|
|
function getAverageRGB(imgEl, blockSize) {
|
|
|
|
var defaultRGB = {r:0,g:0,b:0}, // for non-supporting envs
|
|
canvas = document.createElement('canvas'),
|
|
context = canvas.getContext && canvas.getContext('2d'),
|
|
data, width, height,
|
|
i = -4,
|
|
length,
|
|
rgb = {r:0,g:0,b:0},
|
|
count = 0;
|
|
|
|
if (!context) {
|
|
return defaultRGB;
|
|
}
|
|
|
|
height = canvas.height = imgEl.naturalHeight || imgEl.offsetHeight || imgEl.height;
|
|
width = canvas.width = imgEl.naturalWidth || imgEl.offsetWidth || imgEl.width;
|
|
|
|
context.drawImage(imgEl, 0, 0);
|
|
|
|
try {
|
|
data = context.getImageData(0, 0, width, height);
|
|
} catch(e) {
|
|
/* security error, img on diff domain */alert('x');
|
|
return defaultRGB;
|
|
}
|
|
|
|
length = data.data.length;
|
|
|
|
if (!blockSize) blockSize = Math.ceil(length/64)
|
|
|
|
while ( (i += blockSize * 4) < length ) {
|
|
if (data.data[i+3] > 0) {
|
|
++count;
|
|
rgb.r += data.data[i];
|
|
rgb.g += data.data[i+1];
|
|
rgb.b += data.data[i+2];
|
|
}
|
|
}
|
|
|
|
// ~~ used to floor values
|
|
rgb.r = ~~(rgb.r/count);
|
|
rgb.g = ~~(rgb.g/count);
|
|
rgb.b = ~~(rgb.b/count);
|
|
|
|
return rgb;
|
|
}
|
|
|
|
function stringifyLargeInt(int) {
|
|
let string = int.toString();
|
|
return string.replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,')
|
|
}
|
|
|
|
|
|
function intersectLines(p1, p2, p3, p4) {
|
|
let s1 = [ p2[0] - p1[0], p2[1] - p1[1] ];
|
|
let s2 = [ p4[0] - p3[0], p4[1] - p3[1] ];
|
|
|
|
let s = (-s1[1] * (p1[0] - p3[0]) + s1[0] * (p1[1] - p3[1])) / (-s2[0] * s1[1] + s1[0] * s2[1]);
|
|
let t = ( s2[0] * (p1[1] - p3[1]) - s2[1] * (p1[0] - p3[0])) / (-s2[0] * s1[1] + s1[0] * s2[1]);
|
|
|
|
return (s >= 0 && s <= 1 && t >= 0 && t <= 1);
|
|
}
|
|
function pointInRectangle(point, rect_start, rect_end) {
|
|
return (point[0] > rect_start[0] && point[0] < rect_end[0] && point[1] > rect_start[1] && point[1] < rect_end[1])
|
|
}
|
|
function lineIntersectsReactangle(p1, p2, rect_start, rect_end) {
|
|
// Check if points inside rect
|
|
if (pointInRectangle(p1, rect_start, rect_end)) return true;
|
|
if (pointInRectangle(p2, rect_start, rect_end)) return true;
|
|
// If points are the same, the line no longer intersect
|
|
if (Math.epsilon(p1[0], p2[0], 0.01) && Math.epsilon(p1[1], p2[1], 0.01)) return false;
|
|
// Intersect all 4 lines of rect
|
|
return intersectLines(p1, p2, [rect_start[0], rect_start[1]], [rect_end[0], rect_start[1]])
|
|
|| intersectLines(p1, p2, [rect_start[0], rect_start[1]], [rect_start[0], rect_end[1]])
|
|
|| intersectLines(p1, p2, [rect_end[0], rect_end[1]], [rect_end[0], rect_start[1]])
|
|
|| intersectLines(p1, p2, [rect_end[0], rect_end[1]], [rect_start[0], rect_end[1]])
|
|
}
|
|
|