UNPKG

@mathboard-ai/math

Version:

Excalidraw math functions for MathBoard

1,812 lines (1,771 loc) 49.4 kB
var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __esm = (fn, res) => function __init() { return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; }; var __commonJS = (cb, mod) => function __require() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); // <define:import.meta.env> var init_define_import_meta_env = __esm({ "<define:import.meta.env>"() { } }); // ../../node_modules/es6-promise-pool/es6-promise-pool.js var require_es6_promise_pool = __commonJS({ "../../node_modules/es6-promise-pool/es6-promise-pool.js"(exports, module) { init_define_import_meta_env(); (function(root, factory) { if (typeof define === "function" && define.amd) { define([], factory); } else if (typeof exports === "object") { module.exports = factory(); } else { root.PromisePool = factory(); root.promisePool = root.PromisePool; } })(exports, function() { "use strict"; var EventTarget = function() { this._listeners = {}; }; EventTarget.prototype.addEventListener = function(type, listener) { this._listeners[type] = this._listeners[type] || []; if (this._listeners[type].indexOf(listener) < 0) { this._listeners[type].push(listener); } }; EventTarget.prototype.removeEventListener = function(type, listener) { if (this._listeners[type]) { var p = this._listeners[type].indexOf(listener); if (p >= 0) { this._listeners[type].splice(p, 1); } } }; EventTarget.prototype.dispatchEvent = function(evt) { if (this._listeners[evt.type] && this._listeners[evt.type].length) { var listeners = this._listeners[evt.type].slice(); for (var i = 0, l = listeners.length; i < l; ++i) { listeners[i].call(this, evt); } } }; var isGenerator = function(func) { return typeof func.constructor === "function" && func.constructor.name === "GeneratorFunction"; }; var functionToIterator = function(func) { return { next: function() { var promise = func(); return promise ? { value: promise } : { done: true }; } }; }; var promiseToIterator = function(promise) { var called = false; return { next: function() { if (called) { return { done: true }; } called = true; return { value: promise }; } }; }; var toIterator = function(obj, Promise2) { var type = typeof obj; if (type === "object") { if (typeof obj.next === "function") { return obj; } if (typeof obj.then === "function") { return promiseToIterator(obj); } } if (type === "function") { return isGenerator(obj) ? obj() : functionToIterator(obj); } return promiseToIterator(Promise2.resolve(obj)); }; var PromisePoolEvent = function(target, type, data) { this.target = target; this.type = type; this.data = data; }; var PromisePool = function(source, concurrency, options) { EventTarget.call(this); if (typeof concurrency !== "number" || Math.floor(concurrency) !== concurrency || concurrency < 1) { throw new Error("Invalid concurrency"); } this._concurrency = concurrency; this._options = options || {}; this._options.promise = this._options.promise || Promise; this._iterator = toIterator(source, this._options.promise); this._done = false; this._size = 0; this._promise = null; this._callbacks = null; }; PromisePool.prototype = new EventTarget(); PromisePool.prototype.constructor = PromisePool; PromisePool.prototype.concurrency = function(value) { if (typeof value !== "undefined") { this._concurrency = value; if (this.active()) { this._proceed(); } } return this._concurrency; }; PromisePool.prototype.size = function() { return this._size; }; PromisePool.prototype.active = function() { return !!this._promise; }; PromisePool.prototype.promise = function() { return this._promise; }; PromisePool.prototype.start = function() { var that = this; var Promise2 = this._options.promise; this._promise = new Promise2(function(resolve, reject) { that._callbacks = { reject, resolve }; that._proceed(); }); return this._promise; }; PromisePool.prototype._fireEvent = function(type, data) { this.dispatchEvent(new PromisePoolEvent(this, type, data)); }; PromisePool.prototype._settle = function(error) { if (error) { this._callbacks.reject(error); } else { this._callbacks.resolve(); } this._promise = null; this._callbacks = null; }; PromisePool.prototype._onPooledPromiseFulfilled = function(promise, result) { this._size--; if (this.active()) { this._fireEvent("fulfilled", { promise, result }); this._proceed(); } }; PromisePool.prototype._onPooledPromiseRejected = function(promise, error) { this._size--; if (this.active()) { this._fireEvent("rejected", { promise, error }); this._settle(error || new Error("Unknown error")); } }; PromisePool.prototype._trackPromise = function(promise) { var that = this; promise.then(function(result) { that._onPooledPromiseFulfilled(promise, result); }, function(error) { that._onPooledPromiseRejected(promise, error); })["catch"](function(err) { that._settle(new Error("Promise processing failed: " + err)); }); }; PromisePool.prototype._proceed = function() { if (!this._done) { var result = { done: false }; while (this._size < this._concurrency && !(result = this._iterator.next()).done) { this._size++; this._trackPromise(result.value); } this._done = result === null || !!result.done; } if (this._done && this._size === 0) { this._settle(); } }; PromisePool.PromisePoolEvent = PromisePoolEvent; PromisePool.PromisePool = PromisePool; return PromisePool; }); } }); // ../../node_modules/@braintree/sanitize-url/dist/index.js var require_dist = __commonJS({ "../../node_modules/@braintree/sanitize-url/dist/index.js"(exports) { "use strict"; init_define_import_meta_env(); Object.defineProperty(exports, "__esModule", { value: true }); exports.sanitizeUrl = void 0; var invalidProtocolRegex = /^([^\w]*)(javascript|data|vbscript)/im; var htmlEntitiesRegex = /&#(\w+)(^\w|;)?/g; var htmlCtrlEntityRegex = /&(newline|tab);/gi; var ctrlCharactersRegex = /[\u0000-\u001F\u007F-\u009F\u2000-\u200D\uFEFF]/gim; var urlSchemeRegex = /^.+(:|&colon;)/gim; var relativeFirstCharacters = [".", "/"]; function isRelativeUrlWithoutProtocol(url) { return relativeFirstCharacters.indexOf(url[0]) > -1; } function decodeHtmlCharacters(str) { return str.replace(htmlEntitiesRegex, function(match, dec) { return String.fromCharCode(dec); }); } function sanitizeUrl2(url) { var sanitizedUrl = decodeHtmlCharacters(url || "").replace(htmlCtrlEntityRegex, "").replace(ctrlCharactersRegex, "").trim(); if (!sanitizedUrl) { return "about:blank"; } if (isRelativeUrlWithoutProtocol(sanitizedUrl)) { return sanitizedUrl; } var urlSchemeParseResults = sanitizedUrl.match(urlSchemeRegex); if (!urlSchemeParseResults) { return sanitizedUrl; } var urlScheme = urlSchemeParseResults[0]; if (invalidProtocolRegex.test(urlScheme)) { return "about:blank"; } return sanitizedUrl; } exports.sanitizeUrl = sanitizeUrl2; } }); // src/index.ts init_define_import_meta_env(); // src/angle.ts init_define_import_meta_env(); // src/utils.ts init_define_import_meta_env(); var PRECISION = 1e-4; var clamp = (value, min, max) => { return Math.min(Math.max(value, min), max); }; var round = (value, precision, func = "round") => { const multiplier = Math.pow(10, precision); return Math[func]((value + Number.EPSILON) * multiplier) / multiplier; }; var roundToStep = (value, step, func = "round") => { const factor = 1 / step; return Math[func](value * factor) / factor; }; var average = (a, b) => (a + b) / 2; var isFiniteNumber = (value) => { return typeof value === "number" && Number.isFinite(value); }; var isCloseTo = (a, b, precision = PRECISION) => Math.abs(a - b) < precision; // src/angle.ts var normalizeRadians = (angle) => angle < 0 ? angle % (2 * Math.PI) + 2 * Math.PI : angle % (2 * Math.PI); var cartesian2Polar = ([ x, y ]) => [ Math.hypot(x, y), normalizeRadians(Math.atan2(y, x)) ]; function degreesToRadians(degrees) { return degrees * Math.PI / 180; } function radiansToDegrees(degrees) { return degrees * 180 / Math.PI; } function isRightAngleRads(rads) { return Math.abs(Math.sin(2 * rads)) < PRECISION; } function radiansBetweenAngles(a, min, max) { a = normalizeRadians(a); min = normalizeRadians(min); max = normalizeRadians(max); if (min < max) { return a >= min && a <= max; } return a >= min || a <= max; } function radiansDifference(a, b) { a = normalizeRadians(a); b = normalizeRadians(b); let diff = a - b; if (diff < -Math.PI) { diff = diff + 2 * Math.PI; } else if (diff > Math.PI) { diff = diff - 2 * Math.PI; } return Math.abs(diff); } // src/curve.ts init_define_import_meta_env(); // src/point.ts init_define_import_meta_env(); // src/vector.ts init_define_import_meta_env(); function vector(x, y, originX = 0, originY = 0) { return [x - originX, y - originY]; } function vectorFromPoint(p, origin = [0, 0], threshold, defaultValue = [0, 1]) { const vec = vector(p[0] - origin[0], p[1] - origin[1]); if (threshold && vectorMagnitudeSq(vec) < threshold * threshold) { return defaultValue; } return vec; } function vectorCross(a, b) { return a[0] * b[1] - b[0] * a[1]; } function vectorDot(a, b) { return a[0] * b[0] + a[1] * b[1]; } function isVector(v) { return Array.isArray(v) && v.length === 2 && typeof v[0] === "number" && !isNaN(v[0]) && typeof v[1] === "number" && !isNaN(v[1]); } function vectorAdd(a, b) { return [a[0] + b[0], a[1] + b[1]]; } function vectorSubtract(start, end) { return [start[0] - end[0], start[1] - end[1]]; } function vectorScale(v, scalar) { return vector(v[0] * scalar, v[1] * scalar); } function vectorMagnitudeSq(v) { return v[0] * v[0] + v[1] * v[1]; } function vectorMagnitude(v) { return Math.sqrt(vectorMagnitudeSq(v)); } var vectorNormalize = (v) => { const m = vectorMagnitude(v); if (m === 0) { return vector(0, 0); } return vector(v[0] / m, v[1] / m); }; var vectorNormal = (v) => vector(v[1], -v[0]); // src/point.ts function pointFrom(x, y) { return [x, y]; } function pointFromArray(numberArray) { return numberArray.length === 2 ? pointFrom(numberArray[0], numberArray[1]) : void 0; } function pointFromPair(pair) { return pair; } function pointFromVector(v, offset = pointFrom(0, 0)) { return pointFrom(offset[0] + v[0], offset[1] + v[1]); } function isPoint(p) { return Array.isArray(p) && p.length === 2 && typeof p[0] === "number" && !isNaN(p[0]) && typeof p[1] === "number" && !isNaN(p[1]); } function pointsEqual(a, b, tolerance = PRECISION) { const abs = Math.abs; return abs(a[0] - b[0]) < tolerance && abs(a[1] - b[1]) < tolerance; } function pointRotateRads([x, y], [cx, cy], angle) { return pointFrom( (x - cx) * Math.cos(angle) - (y - cy) * Math.sin(angle) + cx, (x - cx) * Math.sin(angle) + (y - cy) * Math.cos(angle) + cy ); } function pointRotateDegs(point, center, angle) { return pointRotateRads(point, center, degreesToRadians(angle)); } function pointTranslate(p, v = [0, 0]) { return pointFrom(p[0] + v[0], p[1] + v[1]); } function pointCenter(a, b) { return pointFrom((a[0] + b[0]) / 2, (a[1] + b[1]) / 2); } function pointDistance(a, b) { return Math.hypot(b[0] - a[0], b[1] - a[1]); } function pointDistanceSq(a, b) { const xDiff = b[0] - a[0]; const yDiff = b[1] - a[1]; return xDiff * xDiff + yDiff * yDiff; } var pointScaleFromOrigin = (p, mid, multiplier) => pointTranslate(mid, vectorScale(vectorFromPoint(p, mid), multiplier)); var isPointWithinBounds = (p, q, r) => { return q[0] <= Math.max(p[0], r[0]) && q[0] >= Math.min(p[0], r[0]) && q[1] <= Math.max(p[1], r[1]) && q[1] >= Math.min(p[1], r[1]); }; // src/constants.ts init_define_import_meta_env(); var LegendreGaussN24TValues = [ -0.06405689286260563, 0.06405689286260563, -0.1911188674736163, 0.1911188674736163, -0.3150426796961634, 0.3150426796961634, -0.4337935076260451, 0.4337935076260451, -0.5454214713888396, 0.5454214713888396, -0.6480936519369755, 0.6480936519369755, -0.7401241915785544, 0.7401241915785544, -0.820001985973903, 0.820001985973903, -0.8864155270044011, 0.8864155270044011, -0.9382745520027328, 0.9382745520027328, -0.9747285559713095, 0.9747285559713095, -0.9951872199970213, 0.9951872199970213 ]; var LegendreGaussN24CValues = [ 0.12793819534675216, 0.12793819534675216, 0.1258374563468283, 0.1258374563468283, 0.12167047292780339, 0.12167047292780339, 0.1155056680537256, 0.1155056680537256, 0.10744427011596563, 0.10744427011596563, 0.09761865210411388, 0.09761865210411388, 0.08619016153195327, 0.08619016153195327, 0.0733464814110803, 0.0733464814110803, 0.05929858491543678, 0.05929858491543678, 0.04427743881741981, 0.04427743881741981, 0.028531388628933663, 0.028531388628933663, 0.0123412297999872, 0.0123412297999872 ]; // src/curve.ts function curve(a, b, c, d) { return [a, b, c, d]; } function gradient(f, t0, s0, delta = 1e-6) { return [ (f(t0 + delta, s0) - f(t0 - delta, s0)) / (2 * delta), (f(t0, s0 + delta) - f(t0, s0 - delta)) / (2 * delta) ]; } function solve(f, t0, s0, tolerance = 1e-3, iterLimit = 10) { let error = Infinity; let iter = 0; while (error >= tolerance) { if (iter >= iterLimit) { return null; } const y0 = f(t0, s0); const jacobian = [ gradient((t, s) => f(t, s)[0], t0, s0), gradient((t, s) => f(t, s)[1], t0, s0) ]; const b = [[-y0[0]], [-y0[1]]]; const det = jacobian[0][0] * jacobian[1][1] - jacobian[0][1] * jacobian[1][0]; if (det === 0) { return null; } const iJ = [ [jacobian[1][1] / det, -jacobian[0][1] / det], [-jacobian[1][0] / det, jacobian[0][0] / det] ]; const h = [ [iJ[0][0] * b[0][0] + iJ[0][1] * b[1][0]], [iJ[1][0] * b[0][0] + iJ[1][1] * b[1][0]] ]; t0 = t0 + h[0][0]; s0 = s0 + h[1][0]; const [tErr, sErr] = f(t0, s0); error = Math.max(Math.abs(tErr), Math.abs(sErr)); iter += 1; } return [t0, s0]; } var bezierEquation = (c, t) => pointFrom( (1 - t) ** 3 * c[0][0] + 3 * (1 - t) ** 2 * t * c[1][0] + 3 * (1 - t) * t ** 2 * c[2][0] + t ** 3 * c[3][0], (1 - t) ** 3 * c[0][1] + 3 * (1 - t) ** 2 * t * c[1][1] + 3 * (1 - t) * t ** 2 * c[2][1] + t ** 3 * c[3][1] ); function curveIntersectLineSegment(c, l) { const line2 = (s) => pointFrom( l[0][0] + s * (l[1][0] - l[0][0]), l[0][1] + s * (l[1][1] - l[0][1]) ); const initial_guesses = [ [0.5, 0], [0.2, 0], [0.8, 0] ]; const calculate = ([t0, s0]) => { const solution2 = solve( (t2, s2) => { const bezier_point = bezierEquation(c, t2); const line_point = line2(s2); return [ bezier_point[0] - line_point[0], bezier_point[1] - line_point[1] ]; }, t0, s0 ); if (!solution2) { return null; } const [t, s] = solution2; if (t < 0 || t > 1 || s < 0 || s > 1) { return null; } return bezierEquation(c, t); }; let solution = calculate(initial_guesses[0]); if (solution) { return [solution]; } solution = calculate(initial_guesses[1]); if (solution) { return [solution]; } solution = calculate(initial_guesses[2]); if (solution) { return [solution]; } return []; } function curveClosestPoint(c, p, tolerance = 1e-3) { const localMinimum = (min, max, f, e = tolerance) => { let m = min; let n = max; let k; while (n - m > e) { k = (n + m) / 2; if (f(k - e) < f(k + e)) { n = k; } else { m = k; } } return k; }; const maxSteps = 30; let closestStep = 0; for (let min = Infinity, step = 0; step < maxSteps; step++) { const d = pointDistance(p, bezierEquation(c, step / maxSteps)); if (d < min) { min = d; closestStep = step; } } const t0 = Math.max((closestStep - 1) / maxSteps, 0); const t1 = Math.min((closestStep + 1) / maxSteps, 1); const solution = localMinimum( t0, t1, (t) => pointDistance(p, bezierEquation(c, t)) ); if (!solution) { return null; } return bezierEquation(c, solution); } function curvePointDistance(c, p) { const closest = curveClosestPoint(c, p); if (!closest) { return 0; } return pointDistance(p, closest); } function isCurve(v) { return Array.isArray(v) && v.length === 4 && isPoint(v[0]) && isPoint(v[1]) && isPoint(v[2]) && isPoint(v[3]); } function curveTangent([p0, p1, p2, p3], t) { return vector( -3 * (1 - t) * (1 - t) * p0[0] + 3 * (1 - t) * (1 - t) * p1[0] - 6 * t * (1 - t) * p1[0] - 3 * t * t * p2[0] + 6 * t * (1 - t) * p2[0] + 3 * t * t * p3[0], -3 * (1 - t) * (1 - t) * p0[1] + 3 * (1 - t) * (1 - t) * p1[1] - 6 * t * (1 - t) * p1[1] - 3 * t * t * p2[1] + 6 * t * (1 - t) * p2[1] + 3 * t * t * p3[1] ); } function curveCatmullRomQuadraticApproxPoints(points, tension = 0.5) { if (points.length < 2) { return; } const pointSets = []; for (let i = 0; i < points.length - 1; i++) { const p0 = points[i - 1 < 0 ? 0 : i - 1]; const p1 = points[i]; const p2 = points[i + 1 >= points.length ? points.length - 1 : i + 1]; const cpX = p1[0] + (p2[0] - p0[0]) * tension / 2; const cpY = p1[1] + (p2[1] - p0[1]) * tension / 2; pointSets.push([ pointFrom(cpX, cpY), pointFrom(p2[0], p2[1]) ]); } return pointSets; } function curveCatmullRomCubicApproxPoints(points, tension = 0.5) { if (points.length < 2) { return; } const pointSets = []; for (let i = 0; i < points.length - 1; i++) { const p0 = points[i - 1 < 0 ? 0 : i - 1]; const p1 = points[i]; const p2 = points[i + 1 >= points.length ? points.length - 1 : i + 1]; const p3 = points[i + 2 >= points.length ? points.length - 1 : i + 2]; const tangent1 = [(p2[0] - p0[0]) * tension, (p2[1] - p0[1]) * tension]; const tangent2 = [(p3[0] - p1[0]) * tension, (p3[1] - p1[1]) * tension]; const cp1x = p1[0] + tangent1[0] / 3; const cp1y = p1[1] + tangent1[1] / 3; const cp2x = p2[0] - tangent2[0] / 3; const cp2y = p2[1] - tangent2[1] / 3; pointSets.push( curve( pointFrom(p1[0], p1[1]), pointFrom(cp1x, cp1y), pointFrom(cp2x, cp2y), pointFrom(p2[0], p2[1]) ) ); } return pointSets; } function curveOffsetPoints([p0, p1, p2, p3], offset, steps = 50) { const offsetPoints = []; for (let i = 0; i <= steps; i++) { const t = i / steps; const c = curve(p0, p1, p2, p3); const point = bezierEquation(c, t); const tangent = vectorNormalize(curveTangent(c, t)); const normal = vectorNormal(tangent); offsetPoints.push(pointFromVector(vectorScale(normal, offset), point)); } return offsetPoints; } function offsetPointsForQuadraticBezier(p0, p1, p2, offsetDist, steps = 50) { const offsetPoints = []; for (let i = 0; i <= steps; i++) { const t = i / steps; const t1 = 1 - t; const point = pointFrom( t1 * t1 * p0[0] + 2 * t1 * t * p1[0] + t * t * p2[0], t1 * t1 * p0[1] + 2 * t1 * t * p1[1] + t * t * p2[1] ); const tangentX = 2 * (1 - t) * (p1[0] - p0[0]) + 2 * t * (p2[0] - p1[0]); const tangentY = 2 * (1 - t) * (p1[1] - p0[1]) + 2 * t * (p2[1] - p1[1]); const tangent = vectorNormalize(vector(tangentX, tangentY)); const normal = vectorNormal(tangent); offsetPoints.push(pointFromVector(vectorScale(normal, offsetDist), point)); } return offsetPoints; } function curveLength(c) { const z2 = 0.5; let sum = 0; for (let i = 0; i < 24; i++) { const t = z2 * LegendreGaussN24TValues[i] + z2; const derivativeVector = curveTangent(c, t); const magnitude = Math.sqrt( derivativeVector[0] * derivativeVector[0] + derivativeVector[1] * derivativeVector[1] ); sum += LegendreGaussN24CValues[i] * magnitude; } return z2 * sum; } function curveLengthAtParameter(c, t) { if (t <= 0) { return 0; } if (t >= 1) { return curveLength(c); } const z1 = t / 2; const z2 = t / 2; let sum = 0; for (let i = 0; i < 24; i++) { const parameter = z1 * LegendreGaussN24TValues[i] + z2; const derivativeVector = curveTangent(c, parameter); const magnitude = Math.sqrt( derivativeVector[0] * derivativeVector[0] + derivativeVector[1] * derivativeVector[1] ); sum += LegendreGaussN24CValues[i] * magnitude; } return z1 * sum; } function curvePointAtLength(c, percent) { if (percent <= 0) { return bezierEquation(c, 0); } if (percent >= 1) { return bezierEquation(c, 1); } const totalLength = curveLength(c); const targetLength = totalLength * percent; let tMin = 0; let tMax = 1; let t = percent; let currentLength = 0; const tolerance = totalLength * 1e-4; const maxIterations = 20; for (let iteration = 0; iteration < maxIterations; iteration++) { currentLength = curveLengthAtParameter(c, t); const error = Math.abs(currentLength - targetLength); if (error < tolerance) { break; } if (currentLength < targetLength) { tMin = t; } else { tMax = t; } t = (tMin + tMax) / 2; } return bezierEquation(c, t); } // src/ellipse.ts init_define_import_meta_env(); function ellipse(center, halfWidth, halfHeight) { return { center, halfWidth, halfHeight }; } var ellipseIncludesPoint = (p, ellipse2) => { const { center, halfWidth, halfHeight } = ellipse2; const normalizedX = (p[0] - center[0]) / halfWidth; const normalizedY = (p[1] - center[1]) / halfHeight; return normalizedX * normalizedX + normalizedY * normalizedY <= 1; }; var ellipseTouchesPoint = (point, ellipse2, threshold = PRECISION) => { return ellipseDistanceFromPoint(point, ellipse2) <= threshold; }; var ellipseDistanceFromPoint = (p, ellipse2) => { const { halfWidth, halfHeight, center } = ellipse2; const a = halfWidth; const b = halfHeight; const translatedPoint = vectorAdd( vectorFromPoint(p), vectorScale(vectorFromPoint(center), -1) ); const px = Math.abs(translatedPoint[0]); const py = Math.abs(translatedPoint[1]); let tx = 0.707; let ty = 0.707; for (let i = 0; i < 3; i++) { const x = a * tx; const y = b * ty; const ex = (a * a - b * b) * tx ** 3 / a; const ey = (b * b - a * a) * ty ** 3 / b; const rx = x - ex; const ry = y - ey; const qx = px - ex; const qy = py - ey; const r = Math.hypot(ry, rx); const q = Math.hypot(qy, qx); tx = Math.min(1, Math.max(0, (qx * r / q + ex) / a)); ty = Math.min(1, Math.max(0, (qy * r / q + ey) / b)); const t = Math.hypot(ty, tx); tx /= t; ty /= t; } const [minX, minY] = [ a * tx * Math.sign(translatedPoint[0]), b * ty * Math.sign(translatedPoint[1]) ]; return pointDistance(pointFromVector(translatedPoint), pointFrom(minX, minY)); }; function ellipseSegmentInterceptPoints(e, s) { const rx = e.halfWidth; const ry = e.halfHeight; const dir = vectorFromPoint(s[1], s[0]); const diff = vector(s[0][0] - e.center[0], s[0][1] - e.center[1]); const mDir = vector(dir[0] / (rx * rx), dir[1] / (ry * ry)); const mDiff = vector(diff[0] / (rx * rx), diff[1] / (ry * ry)); const a = vectorDot(dir, mDir); const b = vectorDot(dir, mDiff); const c = vectorDot(diff, mDiff) - 1; const d = b * b - a * c; const intersections = []; if (d > 0) { const t_a = (-b - Math.sqrt(d)) / a; const t_b = (-b + Math.sqrt(d)) / a; if (0 <= t_a && t_a <= 1) { intersections.push( pointFrom( s[0][0] + (s[1][0] - s[0][0]) * t_a, s[0][1] + (s[1][1] - s[0][1]) * t_a ) ); } if (0 <= t_b && t_b <= 1) { intersections.push( pointFrom( s[0][0] + (s[1][0] - s[0][0]) * t_b, s[0][1] + (s[1][1] - s[0][1]) * t_b ) ); } } else if (d === 0) { const t = -b / a; if (0 <= t && t <= 1) { intersections.push( pointFrom( s[0][0] + (s[1][0] - s[0][0]) * t, s[0][1] + (s[1][1] - s[0][1]) * t ) ); } } return intersections; } function ellipseLineIntersectionPoints({ center, halfWidth, halfHeight }, [g, h]) { const [cx, cy] = center; const x1 = g[0] - cx; const y1 = g[1] - cy; const x2 = h[0] - cx; const y2 = h[1] - cy; const a = Math.pow(x2 - x1, 2) / Math.pow(halfWidth, 2) + Math.pow(y2 - y1, 2) / Math.pow(halfHeight, 2); const b = 2 * (x1 * (x2 - x1) / Math.pow(halfWidth, 2) + y1 * (y2 - y1) / Math.pow(halfHeight, 2)); const c = Math.pow(x1, 2) / Math.pow(halfWidth, 2) + Math.pow(y1, 2) / Math.pow(halfHeight, 2) - 1; const t1 = (-b + Math.sqrt(Math.pow(b, 2) - 4 * a * c)) / (2 * a); const t2 = (-b - Math.sqrt(Math.pow(b, 2) - 4 * a * c)) / (2 * a); const candidates = [ pointFrom(x1 + t1 * (x2 - x1) + cx, y1 + t1 * (y2 - y1) + cy), pointFrom(x1 + t2 * (x2 - x1) + cx, y1 + t2 * (y2 - y1) + cy) ].filter((p) => !isNaN(p[0]) && !isNaN(p[1])); if (candidates.length === 2 && pointsEqual(candidates[0], candidates[1])) { return [candidates[0]]; } return candidates; } // src/line.ts init_define_import_meta_env(); function line(a, b) { return [a, b]; } function linesIntersectAt(a, b) { const A1 = a[1][1] - a[0][1]; const B1 = a[0][0] - a[1][0]; const A2 = b[1][1] - b[0][1]; const B2 = b[0][0] - b[1][0]; const D = A1 * B2 - A2 * B1; if (D !== 0) { const C1 = A1 * a[0][0] + B1 * a[0][1]; const C2 = A2 * b[0][0] + B2 * b[0][1]; return pointFrom((C1 * B2 - C2 * B1) / D, (A1 * C2 - A2 * C1) / D); } return null; } // src/polygon.ts init_define_import_meta_env(); // src/segment.ts init_define_import_meta_env(); function lineSegment(a, b) { return [a, b]; } var isLineSegment = (segment) => Array.isArray(segment) && segment.length === 2 && isPoint(segment[0]) && isPoint(segment[0]); var lineSegmentRotate = (l, angle, origin) => { return lineSegment( pointRotateRads(l[0], origin || pointCenter(l[0], l[1]), angle), pointRotateRads(l[1], origin || pointCenter(l[0], l[1]), angle) ); }; var segmentsIntersectAt = (a, b) => { const a0 = vectorFromPoint(a[0]); const a1 = vectorFromPoint(a[1]); const b0 = vectorFromPoint(b[0]); const b1 = vectorFromPoint(b[1]); const r = vectorSubtract(a1, a0); const s = vectorSubtract(b1, b0); const denominator = vectorCross(r, s); if (denominator === 0) { return null; } const i = vectorSubtract(vectorFromPoint(b[0]), vectorFromPoint(a[0])); const u = vectorCross(i, r) / denominator; const t = vectorCross(i, s) / denominator; if (u === 0) { return null; } const p = vectorAdd(a0, vectorScale(r, t)); if (t >= 0 && t < 1 && u >= 0 && u < 1) { return pointFromVector(p); } return null; }; var pointOnLineSegment = (point, line2, threshold = PRECISION) => { const distance = distanceToLineSegment(point, line2); if (distance === 0) { return true; } return distance < threshold; }; var distanceToLineSegment = (point, line2) => { const [x, y] = point; const [[x1, y1], [x2, y2]] = line2; const A = x - x1; const B = y - y1; const C = x2 - x1; const D = y2 - y1; const dot = A * C + B * D; const len_sq = C * C + D * D; let param = -1; if (len_sq !== 0) { param = dot / len_sq; } let xx; let yy; if (param < 0) { xx = x1; yy = y1; } else if (param > 1) { xx = x2; yy = y2; } else { xx = x1 + param * C; yy = y1 + param * D; } const dx = x - xx; const dy = y - yy; return Math.sqrt(dx * dx + dy * dy); }; function lineSegmentIntersectionPoints(l, s, threshold) { const candidate = linesIntersectAt(line(l[0], l[1]), line(s[0], s[1])); if (!candidate || !pointOnLineSegment(candidate, s, threshold) || !pointOnLineSegment(candidate, l, threshold)) { return null; } return candidate; } function lineSegmentsDistance(s1, s2) { if (lineSegmentIntersectionPoints(s1, s2)) { return 0; } return Math.min( distanceToLineSegment(s1[0], s2), distanceToLineSegment(s1[1], s2), distanceToLineSegment(s2[0], s1), distanceToLineSegment(s2[1], s1) ); } // src/polygon.ts function polygon(...points) { return polygonClose(points); } function polygonFromPoints(points) { return polygonClose(points); } var polygonIncludesPoint = (point, polygon2) => { const x = point[0]; const y = point[1]; let inside = false; for (let i = 0, j = polygon2.length - 1; i < polygon2.length; j = i++) { const xi = polygon2[i][0]; const yi = polygon2[i][1]; const xj = polygon2[j][0]; const yj = polygon2[j][1]; if ((yi > y && yj <= y || yi <= y && yj > y) && x < (xj - xi) * (y - yi) / (yj - yi) + xi) { inside = !inside; } } return inside; }; var polygonIncludesPointNonZero = (point, polygon2) => { const [x, y] = point; let windingNumber = 0; for (let i = 0; i < polygon2.length; i++) { const j = (i + 1) % polygon2.length; const [xi, yi] = polygon2[i]; const [xj, yj] = polygon2[j]; if (yi <= y) { if (yj > y) { if ((xj - xi) * (y - yi) - (x - xi) * (yj - yi) > 0) { windingNumber++; } } } else if (yj <= y) { if ((xj - xi) * (y - yi) - (x - xi) * (yj - yi) < 0) { windingNumber--; } } } return windingNumber !== 0; }; var pointOnPolygon = (p, poly, threshold = PRECISION) => { let on = false; for (let i = 0, l = poly.length - 1; i < l; i++) { if (pointOnLineSegment(p, lineSegment(poly[i], poly[i + 1]), threshold)) { on = true; break; } } return on; }; function polygonClose(polygon2) { return polygonIsClosed(polygon2) ? polygon2 : [...polygon2, polygon2[0]]; } function polygonIsClosed(polygon2) { return pointsEqual(polygon2[0], polygon2[polygon2.length - 1]); } // src/range.ts init_define_import_meta_env(); // ../common/src/index.ts init_define_import_meta_env(); // ../common/src/binary-heap.ts init_define_import_meta_env(); // ../common/src/colors.ts init_define_import_meta_env(); // ../../node_modules/open-color/open-color.json var open_color_default = { white: "#ffffff", black: "#000000", gray: [ "#f8f9fa", "#f1f3f5", "#e9ecef", "#dee2e6", "#ced4da", "#adb5bd", "#868e96", "#495057", "#343a40", "#212529" ], red: [ "#fff5f5", "#ffe3e3", "#ffc9c9", "#ffa8a8", "#ff8787", "#ff6b6b", "#fa5252", "#f03e3e", "#e03131", "#c92a2a" ], pink: [ "#fff0f6", "#ffdeeb", "#fcc2d7", "#faa2c1", "#f783ac", "#f06595", "#e64980", "#d6336c", "#c2255c", "#a61e4d" ], grape: [ "#f8f0fc", "#f3d9fa", "#eebefa", "#e599f7", "#da77f2", "#cc5de8", "#be4bdb", "#ae3ec9", "#9c36b5", "#862e9c" ], violet: [ "#f3f0ff", "#e5dbff", "#d0bfff", "#b197fc", "#9775fa", "#845ef7", "#7950f2", "#7048e8", "#6741d9", "#5f3dc4" ], indigo: [ "#edf2ff", "#dbe4ff", "#bac8ff", "#91a7ff", "#748ffc", "#5c7cfa", "#4c6ef5", "#4263eb", "#3b5bdb", "#364fc7" ], blue: [ "#e7f5ff", "#d0ebff", "#a5d8ff", "#74c0fc", "#4dabf7", "#339af0", "#228be6", "#1c7ed6", "#1971c2", "#1864ab" ], cyan: [ "#e3fafc", "#c5f6fa", "#99e9f2", "#66d9e8", "#3bc9db", "#22b8cf", "#15aabf", "#1098ad", "#0c8599", "#0b7285" ], teal: [ "#e6fcf5", "#c3fae8", "#96f2d7", "#63e6be", "#38d9a9", "#20c997", "#12b886", "#0ca678", "#099268", "#087f5b" ], green: [ "#ebfbee", "#d3f9d8", "#b2f2bb", "#8ce99a", "#69db7c", "#51cf66", "#40c057", "#37b24d", "#2f9e44", "#2b8a3e" ], lime: [ "#f4fce3", "#e9fac8", "#d8f5a2", "#c0eb75", "#a9e34b", "#94d82d", "#82c91e", "#74b816", "#66a80f", "#5c940d" ], yellow: [ "#fff9db", "#fff3bf", "#ffec99", "#ffe066", "#ffd43b", "#fcc419", "#fab005", "#f59f00", "#f08c00", "#e67700" ], orange: [ "#fff4e6", "#ffe8cc", "#ffd8a8", "#ffc078", "#ffa94d", "#ff922b", "#fd7e14", "#f76707", "#e8590c", "#d9480f" ] }; // ../common/src/colors.ts var pick = (source, keys) => { return keys.reduce((acc, key) => { if (key in source) { acc[key] = source[key]; } return acc; }, {}); }; var DEFAULT_ELEMENT_STROKE_COLOR_INDEX = 4; var DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX = 1; var ELEMENTS_PALETTE_SHADE_INDEXES = [0, 2, 4, 6, 8]; var getSpecificColorShades = (color, indexArr) => { return indexArr.map((index) => open_color_default[color][index]); }; var COLOR_PALETTE = { transparent: "transparent", black: "#1e1e1e", white: "#ffffff", // open-colors gray: getSpecificColorShades("gray", ELEMENTS_PALETTE_SHADE_INDEXES), red: getSpecificColorShades("red", ELEMENTS_PALETTE_SHADE_INDEXES), pink: getSpecificColorShades("pink", ELEMENTS_PALETTE_SHADE_INDEXES), grape: getSpecificColorShades("grape", ELEMENTS_PALETTE_SHADE_INDEXES), violet: getSpecificColorShades("violet", ELEMENTS_PALETTE_SHADE_INDEXES), blue: getSpecificColorShades("blue", ELEMENTS_PALETTE_SHADE_INDEXES), cyan: getSpecificColorShades("cyan", ELEMENTS_PALETTE_SHADE_INDEXES), teal: getSpecificColorShades("teal", ELEMENTS_PALETTE_SHADE_INDEXES), green: getSpecificColorShades("green", ELEMENTS_PALETTE_SHADE_INDEXES), yellow: getSpecificColorShades("yellow", ELEMENTS_PALETTE_SHADE_INDEXES), orange: getSpecificColorShades("orange", ELEMENTS_PALETTE_SHADE_INDEXES), // radix bronze shades 3,5,7,9,11 bronze: ["#f8f1ee", "#eaddd7", "#d2bab0", "#a18072", "#846358"] }; var COMMON_ELEMENT_SHADES = pick(COLOR_PALETTE, [ "cyan", "blue", "violet", "grape", "pink", "green", "teal", "yellow", "orange", "red" ]); var DEFAULT_ELEMENT_STROKE_PICKS = [ COLOR_PALETTE.black, COLOR_PALETTE.red[DEFAULT_ELEMENT_STROKE_COLOR_INDEX], COLOR_PALETTE.green[DEFAULT_ELEMENT_STROKE_COLOR_INDEX], COLOR_PALETTE.blue[DEFAULT_ELEMENT_STROKE_COLOR_INDEX], COLOR_PALETTE.yellow[DEFAULT_ELEMENT_STROKE_COLOR_INDEX] ]; var DEFAULT_ELEMENT_BACKGROUND_PICKS = [ COLOR_PALETTE.transparent, COLOR_PALETTE.red[DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX], COLOR_PALETTE.green[DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX], COLOR_PALETTE.blue[DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX], COLOR_PALETTE.yellow[DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX] ]; var DEFAULT_CANVAS_BACKGROUND_PICKS = [ COLOR_PALETTE.white, // radix slate2 "#f8f9fa", // radix blue2 "#f5faff", // radix yellow2 "#fffce8", // radix bronze2 "#fdf8f6" ]; var DEFAULT_ELEMENT_STROKE_COLOR_PALETTE = { // 1st row transparent: COLOR_PALETTE.transparent, white: COLOR_PALETTE.white, gray: COLOR_PALETTE.gray, black: COLOR_PALETTE.black, bronze: COLOR_PALETTE.bronze, // rest ...COMMON_ELEMENT_SHADES }; var DEFAULT_ELEMENT_BACKGROUND_COLOR_PALETTE = { transparent: COLOR_PALETTE.transparent, white: COLOR_PALETTE.white, gray: COLOR_PALETTE.gray, black: COLOR_PALETTE.black, bronze: COLOR_PALETTE.bronze, ...COMMON_ELEMENT_SHADES }; // ../common/src/constants.ts init_define_import_meta_env(); var isDarwin = /Mac|iPod|iPhone|iPad/.test(navigator.platform); var isWindows = /^Win/.test(navigator.platform); var isAndroid = /\b(android)\b/i.test(navigator.userAgent); var isFirefox = typeof window !== "undefined" && "netscape" in window && navigator.userAgent.indexOf("rv:") > 1 && navigator.userAgent.indexOf("Gecko") > 1; var isChrome = navigator.userAgent.indexOf("Chrome") !== -1; var isSafari = !isChrome && navigator.userAgent.indexOf("Safari") !== -1; var isIOS = /iPad|iPhone/i.test(navigator.platform) || // iPadOS 13+ navigator.userAgent.includes("Mac") && "ontouchend" in document; var isMobile = isIOS || /android|webos|ipod|blackberry|iemobile|opera mini/i.test( navigator.userAgent ) || /android|ios|ipod|blackberry|windows phone/i.test(navigator.platform); var supportsResizeObserver = typeof window !== "undefined" && "ResizeObserver" in window; var SHIFT_LOCKING_ANGLE = Math.PI / 12; var CJK_HAND_DRAWN_FALLBACK_FONT = "Xiaolai"; var WINDOWS_EMOJI_FALLBACK_FONT = "Segoe UI Emoji"; var FONT_FAMILY = { Virgil: 1, Helvetica: 2, Cascadia: 3, // leave 4 unused as it was historically used for Assistant (which we don't use anymore) or custom font (Obsidian) Excalifont: 5, Nunito: 6, "Lilita One": 7, "Comic Shanns": 8, "Liberation Sans": 9, Assistant: 10 }; var SANS_SERIF_GENERIC_FONT = "sans-serif"; var MONOSPACE_GENERIC_FONT = "monospace"; var FONT_FAMILY_GENERIC_FALLBACKS = { [SANS_SERIF_GENERIC_FONT]: 998, [MONOSPACE_GENERIC_FONT]: 999 }; var FONT_FAMILY_FALLBACKS = { [CJK_HAND_DRAWN_FALLBACK_FONT]: 100, ...FONT_FAMILY_GENERIC_FALLBACKS, [WINDOWS_EMOJI_FALLBACK_FONT]: 1e3 }; var DEFAULT_FONT_FAMILY = FONT_FAMILY.Excalifont; var DEFAULT_TRANSFORM_HANDLE_SPACING = 2; var SIDE_RESIZING_THRESHOLD = 2 * DEFAULT_TRANSFORM_HANDLE_SPACING; var EPSILON = 1e-5; var DEFAULT_COLLISION_THRESHOLD = 2 * SIDE_RESIZING_THRESHOLD - EPSILON; var IMAGE_MIME_TYPES = { svg: "image/svg+xml", png: "image/png", jpg: "image/jpeg", gif: "image/gif", webp: "image/webp", bmp: "image/bmp", ico: "image/x-icon", avif: "image/avif", jfif: "image/jfif" }; var STRING_MIME_TYPES = { text: "text/plain", html: "text/html", json: "application/json", // excalidraw data excalidraw: "application/vnd.excalidraw+json", excalidrawlib: "application/vnd.excalidrawlib+json" }; var MIME_TYPES = { ...STRING_MIME_TYPES, // image-encoded excalidraw data "excalidraw.svg": "image/svg+xml", "excalidraw.png": "image/png", // binary binary: "application/octet-stream", // image ...IMAGE_MIME_TYPES }; var ALLOWED_PASTE_MIME_TYPES = [ MIME_TYPES.text, MIME_TYPES.html, ...Object.values(IMAGE_MIME_TYPES) ]; var MQ_MAX_MOBILE = 599; var MQ_MIN_TABLET = MQ_MAX_MOBILE + 1; var MAX_ALLOWED_FILE_BYTES = 4 * 1024 * 1024; var ROUGHNESS = { architect: 0, artist: 1, cartoonist: 2 }; var DEFAULT_ELEMENT_PROPS = { strokeColor: COLOR_PALETTE.black, backgroundColor: COLOR_PALETTE.transparent, fillStyle: "solid", strokeWidth: 2, strokeStyle: "solid", roughness: ROUGHNESS.artist, opacity: 100, locked: false }; var ORIG_ID = Symbol.for("__test__originalId__"); // ../common/src/font-metadata.ts init_define_import_meta_env(); var FONT_METADATA = { [FONT_FAMILY.Excalifont]: { metrics: { unitsPerEm: 1e3, ascender: 886, descender: -374, lineHeight: 1.25 } }, [FONT_FAMILY.Nunito]: { metrics: { unitsPerEm: 1e3, ascender: 1011, descender: -353, lineHeight: 1.25 } }, [FONT_FAMILY["Lilita One"]]: { metrics: { unitsPerEm: 1e3, ascender: 923, descender: -220, lineHeight: 1.15 } }, [FONT_FAMILY["Comic Shanns"]]: { metrics: { unitsPerEm: 1e3, ascender: 750, descender: -250, lineHeight: 1.25 } }, [FONT_FAMILY.Virgil]: { metrics: { unitsPerEm: 1e3, ascender: 886, descender: -374, lineHeight: 1.25 }, deprecated: true }, [FONT_FAMILY.Helvetica]: { metrics: { unitsPerEm: 2048, ascender: 1577, descender: -471, lineHeight: 1.15 }, deprecated: true, local: true }, [FONT_FAMILY.Cascadia]: { metrics: { unitsPerEm: 2048, ascender: 1900, descender: -480, lineHeight: 1.2 }, deprecated: true }, [FONT_FAMILY["Liberation Sans"]]: { metrics: { unitsPerEm: 2048, ascender: 1854, descender: -434, lineHeight: 1.15 }, private: true }, [FONT_FAMILY.Assistant]: { metrics: { unitsPerEm: 2048, ascender: 1021, descender: -287, lineHeight: 1.25 }, private: true }, [FONT_FAMILY_FALLBACKS.Xiaolai]: { metrics: { unitsPerEm: 1e3, ascender: 880, descender: -144, lineHeight: 1.25 }, fallback: true }, [FONT_FAMILY_FALLBACKS["Segoe UI Emoji"]]: { metrics: { // reusing Excalifont metrics unitsPerEm: 1e3, ascender: 886, descender: -374, lineHeight: 1.25 }, local: true, fallback: true } }; // ../common/src/queue.ts init_define_import_meta_env(); // ../common/src/keys.ts init_define_import_meta_env(); var CODES = { EQUAL: "Equal", MINUS: "Minus", NUM_ADD: "NumpadAdd", NUM_SUBTRACT: "NumpadSubtract", NUM_ZERO: "Numpad0", BRACKET_RIGHT: "BracketRight", BRACKET_LEFT: "BracketLeft", ONE: "Digit1", TWO: "Digit2", THREE: "Digit3", NINE: "Digit9", QUOTE: "Quote", ZERO: "Digit0", SLASH: "Slash", C: "KeyC", D: "KeyD", H: "KeyH", V: "KeyV", Z: "KeyZ", Y: "KeyY", R: "KeyR", S: "KeyS" }; var KEYS = { ARROW_DOWN: "ArrowDown", ARROW_LEFT: "ArrowLeft", ARROW_RIGHT: "ArrowRight", ARROW_UP: "ArrowUp", PAGE_UP: "PageUp", PAGE_DOWN: "PageDown", BACKSPACE: "Backspace", ALT: "Alt", CTRL_OR_CMD: isDarwin ? "metaKey" : "ctrlKey", DELETE: "Delete", ENTER: "Enter", ESCAPE: "Escape", QUESTION_MARK: "?", SPACE: " ", TAB: "Tab", CHEVRON_LEFT: "<", CHEVRON_RIGHT: ">", PERIOD: ".", COMMA: ",", SUBTRACT: "-", SLASH: "/", A: "a", C: "c", D: "d", E: "e", F: "f", G: "g", H: "h", I: "i", L: "l", O: "o", P: "p", Q: "q", R: "r", S: "s", T: "t", V: "v", X: "x", Y: "y", Z: "z", K: "k", W: "w", 0: "0", 1: "1", 2: "2", 3: "3", 4: "4", 5: "5", 6: "6", 7: "7", 8: "8", 9: "9" }; var KeyCodeMap = /* @__PURE__ */ new Map([ [KEYS.Z, CODES.Z], [KEYS.Y, CODES.Y] ]); // ../common/src/points.ts init_define_import_meta_env(); // ../common/src/promise-pool.ts init_define_import_meta_env(); var import_es6_promise_pool = __toESM(require_es6_promise_pool(), 1); // ../common/src/random.ts init_define_import_meta_env(); // ../../node_modules/roughjs/bin/math.js init_define_import_meta_env(); var Random = class { constructor(seed) { this.seed = seed; } next() { if (this.seed) { return (2 ** 31 - 1 & (this.seed = Math.imul(48271, this.seed))) / 2 ** 31; } else { return Math.random(); } } }; // ../common/src/utils.ts init_define_import_meta_env(); var RS_LTR_CHARS = "A-Za-z\xC0-\xD6\xD8-\xF6\xF8-\u02B8\u0300-\u0590\u0800-\u1FFF\u2C00-\uFB1C\uFDFE-\uFE6F\uFEFD-\uFFFF"; var RS_RTL_CHARS = "\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC"; var RE_RTL_CHECK = new RegExp(`^[^${RS_LTR_CHARS}]*[${RS_RTL_CHARS}]`); var toBrandedType = (value) => { return value; }; // ../common/src/random.ts var random = new Random(Date.now()); // ../common/src/url.ts init_define_import_meta_env(); var import_sanitize_url = __toESM(require_dist(), 1); // ../common/src/emitter.ts init_define_import_meta_env(); // src/range.ts function rangeInclusive(start, end) { return toBrandedType([start, end]); } function rangeInclusiveFromPair(pair) { return toBrandedType(pair); } var rangesOverlap = ([a0, a1], [b0, b1]) => { if (a0 <= b0) { return a1 >= b0; } if (a0 >= b0) { return b1 >= a0; } return false; }; var rangeIntersection = ([a0, a1], [b0, b1]) => { const rangeStart = Math.max(a0, b0); const rangeEnd = Math.min(a1, b1); if (rangeStart <= rangeEnd) { return toBrandedType([rangeStart, rangeEnd]); } return null; }; var rangeIncludesValue = (value, [min, max]) => { return value >= min && value <= max; }; // src/rectangle.ts init_define_import_meta_env(); function rectangle(topLeft, bottomRight) { return [topLeft, bottomRight]; } function rectangleFromNumberSequence(minX, minY, maxX, maxY) { return rectangle(pointFrom(minX, minY), pointFrom(maxX, maxY)); } function rectangleIntersectLineSegment(r, l) { return [ lineSegment(r[0], pointFrom(r[1][0], r[0][1])), lineSegment(pointFrom(r[1][0], r[0][1]), r[1]), lineSegment(r[1], pointFrom(r[0][0], r[1][1])), lineSegment(pointFrom(r[0][0], r[1][1]), r[0]) ].map((s) => lineSegmentIntersectionPoints(l, s)).filter((i) => !!i); } function rectangleIntersectRectangle(rectangle1, rectangle2) { const [[minX1, minY1], [maxX1, maxY1]] = rectangle1; const [[minX2, minY2], [maxX2, maxY2]] = rectangle2; return minX1 < maxX2 && maxX1 > minX2 && minY1 < maxY2 && maxY1 > minY2; } // src/triangle.ts init_define_import_meta_env(); function triangleIncludesPoint([a, b, c], p) { const triangleSign = (p1, p2, p3) => (p1[0] - p3[0]) * (p2[1] - p3[1]) - (p2[0] - p3[0]) * (p1[1] - p3[1]); const d1 = triangleSign(p, a, b); const d2 = triangleSign(p, b, c); const d3 = triangleSign(p, c, a); const has_neg = d1 < 0 || d2 < 0 || d3 < 0; const has_pos = d1 > 0 || d2 > 0 || d3 > 0; return !(has_neg && has_pos); } // src/types.ts init_define_import_meta_env(); export { PRECISION, average, bezierEquation, cartesian2Polar, clamp, curve, curveCatmullRomCubicApproxPoints, curveCatmullRomQuadraticApproxPoints, curveClosestPoint, curveIntersectLineSegment, curveLength, curveLengthAtParameter, curveOffsetPoints, curvePointAtLength, curvePointDistance, curveTangent, degreesToRadians, distanceToLineSegment, ellipse, ellipseDistanceFromPoint, ellipseIncludesPoint, ellipseLineIntersectionPoints, ellipseSegmentInterceptPoints, ellipseTouchesPoint, isCloseTo, isCurve, isFiniteNumber, isLineSegment, isPoint, isPointWithinBounds, isRightAngleRads, isVector, line, lineSegment, lineSegmentIntersectionPoints, lineSegmentRotate, lineSegmentsDistance, linesIntersectAt, normalizeRadians, offsetPointsForQuadraticBezier, pointCenter, pointDistance, pointDistanceSq, pointFrom, pointFromArray, pointFromPair, pointFromVector, pointOnLineSegment, pointOnPolygon, pointRotateDegs, pointRotateRads, pointScaleFromOrigin, pointTranslate, pointsEqual, polygon, polygonFromPoints, polygonIncludesPoint, polygonIncludesPointNonZero, radiansBetweenAngles, radiansDifference, radiansToDegrees, rangeIncludesValue, rangeInclusive, rangeInclusiveFromPair, rangeIntersection, rangesOverlap, rectangle, rectangleFromNumberSequence, rectangleIntersectLineSegment, rectangleIntersectRectangle, round, roundToStep, segmentsIntersectAt, triangleIncludesPoint, vector, vectorAdd, vectorCross, vectorDot, vectorFromPoint, vectorMagnitude, vectorMagnitudeSq, vectorNormal, vectorNormalize, vectorScale, vectorSubtract }; //# sourceMappingURL=index.js.map