diff --git a/common/src/history/position.mjs b/common/src/history/position.mjs index 4c1af60..3bf2fe8 100644 --- a/common/src/history/position.mjs +++ b/common/src/history/position.mjs @@ -19,7 +19,7 @@ import Objects from "../module/objects.mjs" import Latex from "../module/latex.mjs" import * as MathLib from "../math/index.mjs" -import { escapeHTML } from "../utils.mjs" +import { escapeHTML } from "../utils/index.mjs" import { Action } from "./common.mjs" /** diff --git a/common/src/index.mjs b/common/src/index.mjs index c19e2fe..9b5684c 100644 --- a/common/src/index.mjs +++ b/common/src/index.mjs @@ -18,10 +18,11 @@ import js from "./lib/polyfills/js.mjs" -import * as Modules from "./module/index.mjs" +export * as Utils from "./utils/index.mjs" + import * as ObjsAutoload from "./objs/autoload.mjs" +export * as Modules from "./module/index.mjs" export * as MathLib from "./math/index.mjs" export * as HistoryLib from "./history/index.mjs" export * as Parsing from "./parsing/index.mjs" -export * as Utils from "./utils.mjs" diff --git a/common/src/math/expression.mjs b/common/src/math/expression.mjs index 5701ac6..7c7170b 100644 --- a/common/src/math/expression.mjs +++ b/common/src/math/expression.mjs @@ -17,11 +17,11 @@ */ -import * as Utils from "../utils.mjs" +import * as Utils from "../utils/index.mjs" +import { ExprEvalExpression } from "../lib/expr-eval/expression.mjs" import Latex from "../module/latex.mjs" import ExprParser from "../module/expreval.mjs" import Objects from "../module/objects.mjs" -import { ExprEvalExpression } from "../lib/expr-eval/expression.mjs" const NUMBER_MATCHER = /^\d*\.\d+(e[+-]\d+)?$/ diff --git a/common/src/math/sequence.mjs b/common/src/math/sequence.mjs index 5394237..b295708 100644 --- a/common/src/math/sequence.mjs +++ b/common/src/math/sequence.mjs @@ -17,7 +17,7 @@ */ import * as Expr from "./expression.mjs" -import * as Utils from "../utils.mjs" +import * as Utils from "../utils/index.mjs" import Latex from "../module/latex.mjs" import Objects from "../module/objects.mjs" import ExprParser from "../module/expreval.mjs" diff --git a/common/src/module/canvas.mjs b/common/src/module/canvas.mjs index 5736cfc..dcc3f33 100644 --- a/common/src/module/canvas.mjs +++ b/common/src/module/canvas.mjs @@ -18,7 +18,7 @@ import { Module } from "./common.mjs" import { CanvasInterface, DialogInterface } from "./interface.mjs" -import { textsup } from "../utils.mjs" +import { textsup } from "../utils/index.mjs" import { Expression } from "../math/index.mjs" import Latex from "./latex.mjs" import Objects from "./objects.mjs" diff --git a/common/src/module/latex.mjs b/common/src/module/latex.mjs index 65ce689..3b48ebc 100644 --- a/common/src/module/latex.mjs +++ b/common/src/module/latex.mjs @@ -97,6 +97,7 @@ class LatexAPI extends Module { * true if latex has been enabled by the user, false otherwise. */ this.enabled = false + this.promises = new Set() } /** @@ -139,9 +140,12 @@ class LatexAPI extends Module { if(!this.initialized) throw new Error("Attempting requestAsyncRender before initialize!") let render if(this.#latex.supportsAsyncRender) { - console.trace() this.emit(new AsyncRenderStartedEvent(markup, fontSize, color)) - render = await this.#latex.renderAsync(markup, fontSize, color) + // Storing promise so that it does not get dereferenced. + const promise = this.#latex.renderAsync(markup, fontSize, color) + this.promises.add(promise) + render = await promise + this.promises.delete(promise) this.emit(new AsyncRenderFinishedEvent(markup, fontSize, color)) } else { render = this.#latex.renderSync(markup, fontSize, color) diff --git a/common/src/module/objects.mjs b/common/src/module/objects.mjs index 23801be..979dba4 100644 --- a/common/src/module/objects.mjs +++ b/common/src/module/objects.mjs @@ -17,7 +17,7 @@ */ import { Module } from "./common.mjs" -import { textsub } from "../utils.mjs" +import { textsub } from "../utils/index.mjs" class ObjectsAPI extends Module { diff --git a/common/src/objs/common.mjs b/common/src/objs/common.mjs index 1534a9a..380ac5d 100644 --- a/common/src/objs/common.mjs +++ b/common/src/objs/common.mjs @@ -16,9 +16,9 @@ * along with this program. If not, see . */ -import { getRandomColor } from "../utils.mjs" import Objects from "../module/objects.mjs" import Latex from "../module/latex.mjs" +import { getRandomColor } from "../utils/index.mjs" import { ensureTypeSafety, serializesByPropertyType } from "../parameters.mjs" // This file contains the default data to be imported from all other objects diff --git a/common/src/objs/function.mjs b/common/src/objs/function.mjs index b056cc3..70d0b69 100644 --- a/common/src/objs/function.mjs +++ b/common/src/objs/function.mjs @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -import { textsub } from "../utils.mjs" +import { textsub } from "../utils/index.mjs" import Objects from "../module/objects.mjs" import { ExecutableObject } from "./common.mjs" import { parseDomain, Expression, SpecialDomain } from "../math/index.mjs" diff --git a/common/src/utils.mjs b/common/src/utils/expression.mjs similarity index 72% rename from common/src/utils.mjs rename to common/src/utils/expression.mjs index 5c51f62..ef20b27 100644 --- a/common/src/utils.mjs +++ b/common/src/utils/expression.mjs @@ -16,151 +16,7 @@ * along with this program. If not, see . */ -// Add string methods -/** - * Replaces latin characters with their uppercase versions. - * @return {string} - */ -String.prototype.toLatinUppercase = function() { - return this.replace(/[a-z]/g, function(match) { - return match.toUpperCase() - }) -} - -/** - * Removes the first and last character of a string - * Used to remove enclosing characters like quotes, parentheses, brackets... - * @note Does NOT check for their existence ahead of time. - * @return {string} - */ -String.prototype.removeEnclosure = function() { - return this.substring(1, this.length - 1) -} - -/** - * Rounds to a certain number of decimal places. - * From https://stackoverflow.com/a/48764436 - * - * @param {number} decimalPlaces - * @return {number} - */ -Number.prototype.toDecimalPrecision = function(decimalPlaces = 0) { - const p = Math.pow(10, decimalPlaces) - const n = (this * p) * (1 + Number.EPSILON) - return Math.round(n) / p -} - -const CHARACTER_TO_POWER = new Map([ - ["-", "⁻"], - ["+", "⁺"], - ["=", "⁼"], - [" ", " "], - ["(", "⁽"], - [")", "⁾"], - ["0", "⁰"], - ["1", "¹"], - ["2", "²"], - ["3", "³"], - ["4", "⁴"], - ["5", "⁵"], - ["6", "⁶"], - ["7", "⁷"], - ["8", "⁸"], - ["9", "⁹"], - ["a", "ᵃ"], - ["b", "ᵇ"], - ["c", "ᶜ"], - ["d", "ᵈ"], - ["e", "ᵉ"], - ["f", "ᶠ"], - ["g", "ᵍ"], - ["h", "ʰ"], - ["i", "ⁱ"], - ["j", "ʲ"], - ["k", "ᵏ"], - ["l", "ˡ"], - ["m", "ᵐ"], - ["n", "ⁿ"], - ["o", "ᵒ"], - ["p", "ᵖ"], - ["r", "ʳ"], - ["s", "ˢ"], - ["t", "ᵗ"], - ["u", "ᵘ"], - ["v", "ᵛ"], - ["w", "ʷ"], - ["x", "ˣ"], - ["y", "ʸ"], - ["z", "ᶻ"] -]) - -const CHARACTER_TO_INDICE = new Map([ - ["-", "₋"], - ["+", "₊"], - ["=", "₌"], - ["(", "₍"], - [")", "₎"], - [" ", " "], - ["0", "₀"], - ["1", "₁"], - ["2", "₂"], - ["3", "₃"], - ["4", "₄"], - ["5", "₅"], - ["6", "₆"], - ["7", "₇"], - ["8", "₈"], - ["9", "₉"], - ["a", "ₐ"], - ["e", "ₑ"], - ["h", "ₕ"], - ["i", "ᵢ"], - ["j", "ⱼ"], - ["k", "ₖ"], - ["l", "ₗ"], - ["m", "ₘ"], - ["n", "ₙ"], - ["o", "ₒ"], - ["p", "ₚ"], - ["r", "ᵣ"], - ["s", "ₛ"], - ["t", "ₜ"], - ["u", "ᵤ"], - ["v", "ᵥ"], - ["x", "ₓ"] -]) - -const EXPONENTS = [ - "⁰", "¹", "²", "³", "⁴", "⁵", "⁶", "⁷", "⁸", "⁹" -] - -const EXPONENTS_REG = new RegExp("([" + EXPONENTS.join("") + "]+)", "g") - -/** - * Put a text in sup position - * @param {string} text - * @return {string} - */ -export function textsup(text) { - let ret = "" - text = text.toString() - for(let letter of text) - ret += CHARACTER_TO_POWER.has(letter) ? CHARACTER_TO_POWER.get(letter) : letter - return ret -} - -/** - * Put a text in sub position - * @param {string} text - * @return {string} - */ -export function textsub(text) { - let ret = "" - text = text.toString() - for(let letter of text) - ret += CHARACTER_TO_INDICE.has(letter) ? CHARACTER_TO_INDICE.get(letter) : letter - return ret -} +import { textsub, textsup } from "./subsup.mjs" /** * Simplifies (mathematically) a mathematical expression. @@ -400,35 +256,3 @@ export function parseName(str, removeUnallowed = true) { return str } - -/** - * Creates a randomized color string. - * @returns {string} - */ -export function getRandomColor() { - let clrs = "0123456789ABCDEF" - let color = "#" - for(let i = 0; i < 6; i++) { - color += clrs[Math.floor(Math.random() * (16 - 5 * (i % 2 === 0)))] - } - return color -} - -/** - * Escapes text to html entities. - * @param {string} str - * @returns {string} - */ -export function escapeHTML(str) { - return str.replace(/&/g, "&").replace(//g, ">") -} - - -/** - * Parses exponents and replaces them with expression values - * @param {string} expression - The expression to replace in. - * @return {string} The parsed expression - */ -export function exponentsToExpression(expression) { - return expression.replace(EXPONENTS_REG, (m, exp) => "^" + exp.split("").map((x) => EXPONENTS.indexOf(x)).join("")) -} diff --git a/common/src/utils/index.mjs b/common/src/utils/index.mjs new file mode 100644 index 0000000..02adfd6 --- /dev/null +++ b/common/src/utils/index.mjs @@ -0,0 +1,22 @@ +/** + * LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions. + * Copyright (C) 2021-2024 Ad5001 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +export * from "./prototype.mjs" +export * from "./subsup.mjs" +export * from "./expression.mjs" +export * from "./other.mjs" diff --git a/common/src/utils/other.mjs b/common/src/utils/other.mjs new file mode 100644 index 0000000..bcafd6b --- /dev/null +++ b/common/src/utils/other.mjs @@ -0,0 +1,41 @@ +/** + * LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions. + * Copyright (C) 2021-2024 Ad5001 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + + +/** + * Creates a randomized color string. + * @returns {string} + */ +export function getRandomColor() { + let clrs = "0123456789ABCDEF" + let color = "#" + for(let i = 0; i < 6; i++) { + color += clrs[Math.floor(Math.random() * (16 - 5 * (i % 2 === 0)))] + } + return color +} + +/** + * Escapes text to html entities. + * @param {string} str + * @returns {string} + */ +export function escapeHTML(str) { + return str.replace(/&/g, "&").replace(//g, ">") +} diff --git a/common/src/utils/prototype.mjs b/common/src/utils/prototype.mjs new file mode 100644 index 0000000..cb2cc15 --- /dev/null +++ b/common/src/utils/prototype.mjs @@ -0,0 +1,51 @@ +/** + * LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions. + * Copyright (C) 2021-2024 Ad5001 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +// Add string methods +/** + * Replaces latin characters with their uppercase versions. + * @return {string} + */ +String.prototype.toLatinUppercase = function() { + return this.replace(/[a-z]/g, function(match) { + return match.toUpperCase() + }) +} + +/** + * Removes the first and last character of a string + * Used to remove enclosing characters like quotes, parentheses, brackets... + * @note Does NOT check for their existence ahead of time. + * @return {string} + */ +String.prototype.removeEnclosure = function() { + return this.substring(1, this.length - 1) +} + +/** + * Rounds to a certain number of decimal places. + * From https://stackoverflow.com/a/48764436 + * + * @param {number} decimalPlaces + * @return {number} + */ +Number.prototype.toDecimalPrecision = function(decimalPlaces = 0) { + const p = Math.pow(10, decimalPlaces) + const n = (this * p) * (1 + Number.EPSILON) + return Math.round(n) / p +} diff --git a/common/src/utils/subsup.mjs b/common/src/utils/subsup.mjs new file mode 100644 index 0000000..ff6ed50 --- /dev/null +++ b/common/src/utils/subsup.mjs @@ -0,0 +1,140 @@ +/** + * LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions. + * Copyright (C) 2021-2024 Ad5001 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +const CHARACTER_TO_POWER = new Map([ + ["-", "⁻"], + ["+", "⁺"], + ["=", "⁼"], + [" ", " "], + ["(", "⁽"], + [")", "⁾"], + ["0", "⁰"], + ["1", "¹"], + ["2", "²"], + ["3", "³"], + ["4", "⁴"], + ["5", "⁵"], + ["6", "⁶"], + ["7", "⁷"], + ["8", "⁸"], + ["9", "⁹"], + ["a", "ᵃ"], + ["b", "ᵇ"], + ["c", "ᶜ"], + ["d", "ᵈ"], + ["e", "ᵉ"], + ["f", "ᶠ"], + ["g", "ᵍ"], + ["h", "ʰ"], + ["i", "ⁱ"], + ["j", "ʲ"], + ["k", "ᵏ"], + ["l", "ˡ"], + ["m", "ᵐ"], + ["n", "ⁿ"], + ["o", "ᵒ"], + ["p", "ᵖ"], + ["r", "ʳ"], + ["s", "ˢ"], + ["t", "ᵗ"], + ["u", "ᵘ"], + ["v", "ᵛ"], + ["w", "ʷ"], + ["x", "ˣ"], + ["y", "ʸ"], + ["z", "ᶻ"] +]) + +const CHARACTER_TO_INDICE = new Map([ + ["-", "₋"], + ["+", "₊"], + ["=", "₌"], + ["(", "₍"], + [")", "₎"], + [" ", " "], + ["0", "₀"], + ["1", "₁"], + ["2", "₂"], + ["3", "₃"], + ["4", "₄"], + ["5", "₅"], + ["6", "₆"], + ["7", "₇"], + ["8", "₈"], + ["9", "₉"], + ["a", "ₐ"], + ["e", "ₑ"], + ["h", "ₕ"], + ["i", "ᵢ"], + ["j", "ⱼ"], + ["k", "ₖ"], + ["l", "ₗ"], + ["m", "ₘ"], + ["n", "ₙ"], + ["o", "ₒ"], + ["p", "ₚ"], + ["r", "ᵣ"], + ["s", "ₛ"], + ["t", "ₜ"], + ["u", "ᵤ"], + ["v", "ᵥ"], + ["x", "ₓ"] +]) + +const EXPONENTS = [ + "⁰", "¹", "²", "³", "⁴", "⁵", "⁶", "⁷", "⁸", "⁹" +] + +const EXPONENTS_REG = new RegExp("([" + EXPONENTS.join("") + "]+)", "g") + +/** + * Put a text in sup position + * @param {string} text + * @return {string} + */ +export function textsup(text) { + let ret = "" + text = text.toString() + for(let letter of text) + ret += CHARACTER_TO_POWER.has(letter) ? CHARACTER_TO_POWER.get(letter) : letter + return ret +} + +/** + * Put a text in sub position + * @param {string} text + * @return {string} + */ +export function textsub(text) { + let ret = "" + text = text.toString() + for(let letter of text) + ret += CHARACTER_TO_INDICE.has(letter) ? CHARACTER_TO_INDICE.get(letter) : letter + return ret +} + + +/** + * Parses exponents and replaces them with expression values + * @param {string} expression - The expression to replace in. + * @return {string} The parsed expression + */ +export function exponentsToExpression(expression) { + return expression.replace(EXPONENTS_REG, (m, exp) => "^" + exp.split("").map((x) => EXPONENTS.indexOf(x)).join("")) +} + diff --git a/common/test/basics/utils.mjs b/common/test/basics/utils.mjs index aab2cf5..42adead 100644 --- a/common/test/basics/utils.mjs +++ b/common/test/basics/utils.mjs @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -import { textsup, textsub, parseName, getRandomColor, escapeHTML, exponentsToExpression } from "../../src/utils.mjs" +import { textsup, textsub, parseName, getRandomColor, escapeHTML, exponentsToExpression } from "../../src/utils/index.mjs" import { describe, it } from "mocha" diff --git a/common/test/math/expression.mjs b/common/test/math/expression.mjs index a0ee113..0c15f9c 100644 --- a/common/test/math/expression.mjs +++ b/common/test/math/expression.mjs @@ -178,4 +178,4 @@ describe("Math/Expression", function() { expect(() => executeExpression("x+n")).to.throw("Undefined variable n.") }) }) -}) \ No newline at end of file +}) diff --git a/runtime-pyside6/LogarithmPlotter/logarithmplotter.py b/runtime-pyside6/LogarithmPlotter/logarithmplotter.py index c4c16b9..8940e56 100644 --- a/runtime-pyside6/LogarithmPlotter/logarithmplotter.py +++ b/runtime-pyside6/LogarithmPlotter/logarithmplotter.py @@ -21,9 +21,10 @@ from platform import system as os_name, release as OS_RELEASE from sys import path as sys_path from sys import argv, exit from tempfile import TemporaryDirectory +from math import ceil from time import time -from PySide6.QtCore import QTranslator, QLocale +from PySide6.QtCore import QTranslator, QLocale, QThreadPool, QThread from PySide6.QtGui import QIcon from PySide6.QtQml import QQmlApplicationEngine from PySide6.QtQuickControls2 import QQuickStyle @@ -162,7 +163,11 @@ def run(): dep_time = time() print("Loaded dependencies in " + str((dep_time - start_time) * 1000) + "ms.") - + + # Maxing thread count to half the computer's thread count to avoid maxing CPU + # with too many threads (and also leaving some for rendering). + QThreadPool.globalInstance().setMaxThreadCount(int(ceil(QThread.idealThreadCount() / 2))) + register_icon_directories() app = create_qapp() translator = install_translation(app) diff --git a/runtime-pyside6/LogarithmPlotter/util/promise.py b/runtime-pyside6/LogarithmPlotter/util/promise.py index c917660..f4f21c2 100644 --- a/runtime-pyside6/LogarithmPlotter/util/promise.py +++ b/runtime-pyside6/LogarithmPlotter/util/promise.py @@ -22,6 +22,8 @@ from PySide6.QtQml import QJSValue from LogarithmPlotter.util.js import PyJSValue +NO_RETURN = [None, QJSValue.SpecialValue.UndefinedValue] + def check_callable(function: Callable|QJSValue) -> Callable|None: """ @@ -153,13 +155,12 @@ class PyPromise(QObject): @Slot(QObject) def _fulfill(self, data): self._state = "fulfilled" - no_return = [None, QJSValue.SpecialValue.UndefinedValue] print("Finished", self._runner.args) for i in range(len(self._fulfills)): try: result = self._fulfills[i](data) result = result.qjs_value if isinstance(result, PyJSValue) else result - data = result if result not in no_return else data # Forward data. + data = result if result not in NO_RETURN else data # Forward data. except Exception as e: self._reject(repr(e), start_at=i) break @@ -168,8 +169,7 @@ class PyPromise(QObject): @Slot(str) def _reject(self, error, start_at=0): self._state = "rejected" - no_return = [None, QJSValue.SpecialValue.UndefinedValue] for i in range(start_at, len(self._rejects)): result = self._rejects[i](error) result = result.qjs_value if isinstance(result, PyJSValue) else result - error = result if result not in no_return else error # Forward data. + error = result if result not in NO_RETURN else error # Forward data.