diff --git a/LICENSE.md b/LICENSE.md index a9530c3..2fb2e74 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -630,8 +630,8 @@ attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. - LogarithmPlotter - Create graphs with logarithm scales. - Copyright (C) 2021 Ad5001 + + Copyright (C) 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 @@ -652,7 +652,7 @@ mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: - LogarithmPlotter Copyright (C) 2021 Ad5001 + Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. @@ -673,4 +673,3 @@ library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . - diff --git a/LogarithmPlotter/__init__.py b/LogarithmPlotter/__init__.py index 9a008ad..69c5368 100644 --- a/LogarithmPlotter/__init__.py +++ b/LogarithmPlotter/__init__.py @@ -17,7 +17,7 @@ """ from shutil import which -__VERSION__ = "0.1.9" +__VERSION__ = "0.2.0" is_release = False diff --git a/LogarithmPlotter/i18n/lp_de.ts b/LogarithmPlotter/i18n/lp_de.ts index d6d6ee9..27f5bca 100644 --- a/LogarithmPlotter/i18n/lp_de.ts +++ b/LogarithmPlotter/i18n/lp_de.ts @@ -5,7 +5,7 @@ About - + About LogarithmPlotter Über LogarithmPlotter @@ -33,112 +33,117 @@ AppMenuBar - + &File &Datei - + &Load... &Laden… - + &Save &Speichern - + Save &As... Speichern &Unter… - + &Quit &Ausfahrt - + &Edit &Bearbeiten - + &Undo &Lösen - + &Redo &Wiederherstellen - + &Copy plot Grafik &Kopieren - + &Create &Erstellen - + &Settings &Einstellungen - + Check for updates on startup Beim Starten auf Updates prüfen - + Reset redo stack automaticly Wiederherstellen-Stapel automatisch zurücksetzen - + + Enable LaTeX rendering + + + + &Help &Hilfe - + &Source code &Quellcode - + &Report a bug Fehler &Melden - + &User manual &Benutzerhandbuch - + &Changelog &Changelog - + &Help translating! &Hilfe beim Übersetzen! - + &About &Übrigens - + Save unsaved changes? Änderungen speichern? - + This plot contains unsaved changes. By doing this, all unsaved data will be lost. Continue? Diese Grafik enthält ungespeicherte Änderungen. Dadurch gehen alle ungespeicherten Daten verloren. Fortfahren? @@ -211,44 +216,49 @@ GreetScreen - + Welcome to LogarithmPlotter Willkommen bei LogarithmPlotter - + Version %1 Version %1 - + Take a few seconds to configure LogarithmPlotter. These settings can be changed at any time from the "Settings" menu. Nehmen Sie sich ein paar Sekunden Zeit, um LogarithmPlotter zu konfigurieren. Diese Einstellungen können jederzeit über das Menü "Einstellungen" geändert werden. - + Check for updates on startup (requires online connectivity) Beim Start nach Updates suchen (Online-Verbindung erforderlich) - + Reset redo stack when a new action is added to history Redo-Stapel zurücksetzen, wenn eine neue Aktion zur Historie hinzugefügt wird - + + Enable LaTeX rendering + + + + User manual Benutzerhandbuch - + Changelog Changelog - + Done Schließen @@ -279,7 +289,7 @@ Diese Einstellungen können jederzeit über das Menü "Einstellungen" ListSetting - + + Add Entry + Neuer Eintrag @@ -507,12 +517,12 @@ Diese Einstellungen können jederzeit über das Menü "Einstellungen" changelog - + Could not fetch changelog: Server error {}. Changelog konnte nicht geholt werden: Server-Fehler {}. - + Could not fetch update: {}. Changelog konnte nicht geholt werden: {}. @@ -529,32 +539,37 @@ Diese Einstellungen können jederzeit über das Menü "Einstellungen" comment - + Ex: R+* (ℝ⁺*), N (ℕ), Z-* (ℤ⁻*), ]0;1[, {3;4;5} Beispiel: R+* (ℝ⁺*), N (ℕ), Z-* (ℤ-*), ]0;1[, {3;4;5} - + The following parameters are used when the definition domain is a non-continuous set. (Ex: ℕ, ℤ, sets like {0;3}...) Die folgenden Parameter werden verwendet, wenn der Definitionsbereich eine nicht kontinuierliche Menge ist. (Beispiel: ℕ, ℤ, Mengen wie {0;3}...) - + Note: Specify the probability for each value. Hinweis: Geben Sie die Wahrscheinlichkeit für jeden Wert an. - + Note: Use %1[n] to refer to %1ₙ, %1[n+1] for %1ₙ₊₁... Hinweis: Verwenden Sie %1[n], um sich auf %1ₙ zu beziehen, %1[n+1] für %1ₙ₊₁… + + + If you have latex enabled, you can use use latex markup in between $$ to create equations. + + control - + %1: %1: @@ -594,12 +609,12 @@ Diese Einstellungen können jederzeit über das Menü "Einstellungen" function - + Function Funktion - + Functions Funktionen @@ -607,22 +622,24 @@ Diese Einstellungen können jederzeit über das Menü "Einstellungen" gainbode - + Bode Magnitude Bode-Magnitude - + Bode Magnitudes Bode-Magnituden - + + low-pass Tiefpass - + + high-pass Hochpass @@ -654,6 +671,38 @@ Diese Einstellungen können jederzeit über das Menü "Einstellungen" Der Name von %1 %2 wurde in %3 geändert. + + latex + + + No Latex installation found. +If you already have a latex distribution installed, make sure it's installed on your path. +Otherwise, you can download a Latex distribution like TeX Live at https://tug.org/texlive/. + + + + + DVIPNG was not found. Make sure you include it from your Latex distribution. + + + + + An exception occured within the creation of the latex formula. +Process '{}' ended with a non-zero return code {}: + +{} +Please make sure your latex installation is correct and report a bug if so. + + + + + An exception occured within the creation of the latex formula. +Process '{}' took too long to finish: +{} +Please make sure your latex installation is correct and report a bug if so. + + + name @@ -781,12 +830,12 @@ Diese Einstellungen können jederzeit über das Menü "Einstellungen" phasebode - + Bode Phase Bode-Phase - + Bode Phases Bode-Phasen @@ -794,12 +843,12 @@ Diese Einstellungen können jederzeit über das Menü "Einstellungen" point - + Point Punkt - + Points Punkte @@ -807,153 +856,158 @@ Diese Einstellungen können jederzeit über das Menü "Einstellungen" prop - + expression Ausdruck - + definitionDomain Definitionsbereich - + destinationDomain Reichweite - - - - - - - - - - + + + + + + + + + + labelPosition Position des Etiketts - + displayMode Anzeigemodus - - - - - - - + + + + + + + labelX X-Position des Etiketts - - + + drawPoints Unentschiedene Punkte - - + + drawDashedLines Gestrichelte Linien anzeigen - - + + om_0 ω₀ - + pass Pass - + gain Größenordnung - + omGraduation Teilung auf ω zeigen - + phase Phase - + unit Einheit - - - + + + x X - - + + y Y - + pointStyle Punkt-Stil - + probabilities Wahrscheinlichkeiten - + text Inhalt - + + disableLatex + + + + targetElement Zielobjekt - + approximate Ungefähren Wert anzeigen - + rounding Rundung - + displayStyle Stil - + targetValuePosition Wertposition des Ziels - + defaultExpression Standardausdruck - + baseValues Initialisierungswerte @@ -965,12 +1019,12 @@ Diese Einstellungen können jederzeit über das Menü "Einstellungen" repartition - + Repartition Verteilungsfunktion - + Repartition functions Verteilungsfunktionen @@ -978,12 +1032,12 @@ Diese Einstellungen können jederzeit über das Menü "Einstellungen" sequence - + Sequence Folge - + Sequences Folgen @@ -991,8 +1045,8 @@ Diese Einstellungen können jederzeit über das Menü "Einstellungen" sommegainsbode - + Bode Magnitudes Sum Bode-Magnituden Summe @@ -1000,8 +1054,8 @@ Diese Einstellungen können jederzeit über das Menü "Einstellungen" sommephasesbode - + Bode Phases Sum Bode-Phasen Summe @@ -1009,12 +1063,12 @@ Diese Einstellungen können jederzeit über das Menü "Einstellungen" text - + Text Text - + Texts Texte @@ -1022,22 +1076,22 @@ Diese Einstellungen können jederzeit über das Menü "Einstellungen" update - + An update for LogarithPlotter (v{}) is available. Ein Aktualisierung für LogarithmPlotter (v{}) ist verfügbar. - + No update available. Keine Aktualisierung verfügbar. - + Could not fetch update information: Server error {}. Es konnten keine Aktualisierungsinformationen abgerufen werden: Server-Fehler {}. - + Could not fetch update information: {}. Es konnten keine Aktualisierungsinformationen abgerufen werden:{}. @@ -1060,12 +1114,12 @@ Diese Einstellungen können jederzeit über das Menü "Einstellungen" xcursor - + X Cursor X Zeiger - + X Cursors X Zeiger diff --git a/LogarithmPlotter/i18n/lp_en.ts b/LogarithmPlotter/i18n/lp_en.ts index c721ac3..e7e90ae 100644 --- a/LogarithmPlotter/i18n/lp_en.ts +++ b/LogarithmPlotter/i18n/lp_en.ts @@ -5,7 +5,7 @@ About - + About LogarithmPlotter About LogarithmPlotter @@ -33,112 +33,117 @@ AppMenuBar - + &File &File - + &Load... &Open… - + &Save &Save - + Save &As... Save &As… - + &Quit &Quit - + &Edit &Edit - + &Undo &Undo - + &Redo &Redo - + &Copy plot &Copy plot - + &Create &Create - + &Settings &Settings - + Check for updates on startup Check for updates on startup - + Reset redo stack automaticly Reset redo stack automatically - + + Enable LaTeX rendering + + + + &Help &Help - + &Source code &Source code - + &Report a bug &Report a bug - + &User manual &User manual - + &Changelog &Changelog - + &Help translating! &Help translating! - + &About &About - + Save unsaved changes? Save unsaved changes? - + This plot contains unsaved changes. By doing this, all unsaved data will be lost. Continue? This plot contains unsaved changes. By doing this, all unsaved data will be lost. Continue? @@ -211,44 +216,49 @@ GreetScreen - + Welcome to LogarithmPlotter Welcome to LogarithmPlotter - + Version %1 Version %1 - + Take a few seconds to configure LogarithmPlotter. These settings can be changed at any time from the "Settings" menu. Take a few seconds to configure LogarithmPlotter. These settings can be changed at any time from the "Settings" menu. - + Check for updates on startup (requires online connectivity) Check for updates on startup (requires online connectivity) - + Reset redo stack when a new action is added to history Reset redo stack when a new action is added to history - + + Enable LaTeX rendering + + + + User manual User manual - + Changelog Changelog - + Done Done @@ -279,7 +289,7 @@ These settings can be changed at any time from the "Settings" menu. ListSetting - + + Add Entry + Add Entry @@ -507,12 +517,12 @@ These settings can be changed at any time from the "Settings" menu. changelog - + Could not fetch changelog: Server error {}. Could not fetch changelog: Server error {}. - + Could not fetch update: {}. Could not fetch changelog: {}. @@ -529,32 +539,37 @@ These settings can be changed at any time from the "Settings" menu. comment - + Ex: R+* (ℝ⁺*), N (ℕ), Z-* (ℤ⁻*), ]0;1[, {3;4;5} Ex: R+* (ℝ⁺*), N (ℕ), Z-* (ℤ⁻*), ]0;1[, {3;4;5} - + The following parameters are used when the definition domain is a non-continuous set. (Ex: ℕ, ℤ, sets like {0;3}...) The following parameters are used when the domain is a non-continuous set. (Ex: ℕ, ℤ, sets like {0;3}…) - + Note: Specify the probability for each value. Note: Specify the probability for each value. - + Note: Use %1[n] to refer to %1ₙ, %1[n+1] for %1ₙ₊₁... Note: Use %1[n] to refer to %1ₙ, %1[n+1] for %1ₙ₊₁… + + + If you have latex enabled, you can use use latex markup in between $$ to create equations. + + control - + %1: %1: @@ -594,12 +609,12 @@ These settings can be changed at any time from the "Settings" menu. function - + Function Function - + Functions Functions @@ -607,22 +622,24 @@ These settings can be changed at any time from the "Settings" menu. gainbode - + Bode Magnitude Bode Magnitude - + Bode Magnitudes Bode Magnitudes - + + low-pass low-pass - + + high-pass high-pass @@ -654,6 +671,47 @@ These settings can be changed at any time from the "Settings" menu.Name of %1 %2 changed to %3. + + latex + + + No Latex installation found. +If you already have a latex distribution installed, make sure it's installed on your path. +Otherwise, you can download a Latex distribution like TeX Live at https://tug.org/texlive/. + No Latex installation found. +If you already have a latex distribution installed, make sure it's installed on your path. +Otherwise, you can download a Latex distribution like TeX Live at https://tug.org/texlive/. + + + + DVIPNG was not found. Make sure you include it from your Latex distribution. + DVIPNG was not found. Make sure you include it from your Latex distribution. + + + + An exception occured within the creation of the latex formula. +Process '{}' ended with a non-zero return code {}: + +{} +Please make sure your latex installation is correct and report a bug if so. + An exception occurred within the creation of the latex formula. +Process '{}' ended with a non-zero return code {}: + +{} +Please make sure your latex installation is correct and report a bug if so. + + + + An exception occured within the creation of the latex formula. +Process '{}' took too long to finish: +{} +Please make sure your latex installation is correct and report a bug if so. + An exception occurred within the creation of the latex formula. +Process '{}' took too long to finish: +{} +Please make sure your latex installation is correct and report a bug if so. + + name @@ -781,12 +839,12 @@ These settings can be changed at any time from the "Settings" menu. phasebode - + Bode Phase Bode Phase - + Bode Phases Bode Phases @@ -794,12 +852,12 @@ These settings can be changed at any time from the "Settings" menu. point - + Point Point - + Points Points @@ -807,153 +865,158 @@ These settings can be changed at any time from the "Settings" menu. prop - + expression Expression - + definitionDomain Domain - + destinationDomain Range - - - - - - - - - - + + + + + + + + + + labelPosition Label position - + displayMode Display mode - - - - - - - + + + + + + + labelX Label's X position - - + + drawPoints Show points - - + + drawDashedLines Show dashed lines - - + + om_0 ω₀ - + pass Pass - + gain Magnitude gain - + omGraduation Show graduation on ω₀ - + phase Phase - + unit Unit to use - - - + + + x X - - + + y Y - + pointStyle Point style - + probabilities Probabilities list - + text Content - + + disableLatex + Disable latex rendering for this text + + + targetElement Object to target - + approximate Show approximate value - + rounding Rounding - + displayStyle Display style - + targetValuePosition Target's value position - + defaultExpression Default expression - + baseValues Initialisation values @@ -965,12 +1028,12 @@ These settings can be changed at any time from the "Settings" menu. repartition - + Repartition Distribution - + Repartition functions Distribution functions @@ -978,12 +1041,12 @@ These settings can be changed at any time from the "Settings" menu. sequence - + Sequence Sequence - + Sequences Sequences @@ -991,8 +1054,8 @@ These settings can be changed at any time from the "Settings" menu. sommegainsbode - + Bode Magnitudes Sum Bode Magnitudes Sum @@ -1000,8 +1063,8 @@ These settings can be changed at any time from the "Settings" menu. sommephasesbode - + Bode Phases Sum Bode Phases Sum @@ -1009,12 +1072,12 @@ These settings can be changed at any time from the "Settings" menu. text - + Text Text - + Texts Texts @@ -1022,22 +1085,22 @@ These settings can be changed at any time from the "Settings" menu. update - + An update for LogarithPlotter (v{}) is available. An update for LogarithmPlotter (v{}) is available. - + No update available. No update available. - + Could not fetch update information: Server error {}. Could not fetch update information: Server error {}. - + Could not fetch update information: {}. Could not fetch update information: {}. @@ -1060,12 +1123,12 @@ These settings can be changed at any time from the "Settings" menu. xcursor - + X Cursor X Cursor - + X Cursors X Cursors diff --git a/LogarithmPlotter/i18n/lp_es.ts b/LogarithmPlotter/i18n/lp_es.ts index 16c53ff..d17ef46 100644 --- a/LogarithmPlotter/i18n/lp_es.ts +++ b/LogarithmPlotter/i18n/lp_es.ts @@ -5,7 +5,7 @@ About - + About LogarithmPlotter Sobre LogarithmPlotter @@ -33,112 +33,117 @@ AppMenuBar - + &File &Archivo - + &Load... &Abrir… - + &Save &Guardar - + Save &As... Guardar &como… - + &Quit &Salida - + &Edit &Editar - + &Undo &Cancelar - + &Redo &Reiniciar - + &Copy plot &Copiar el gráfico - + &Create &Crear - + &Settings &Ajustes - + Check for updates on startup - + Reset redo stack automaticly - - - &Help - - - &Source code - - - - - &Report a bug - - - - - &User manual + Enable LaTeX rendering + &Help + + + + + &Source code + + + + + &Report a bug + + + + + &User manual + + + + &Changelog - + &Help translating! - + &About - + Save unsaved changes? - + This plot contains unsaved changes. By doing this, all unsaved data will be lost. Continue? @@ -211,43 +216,48 @@ GreetScreen - + Welcome to LogarithmPlotter - + Version %1 - + Take a few seconds to configure LogarithmPlotter. These settings can be changed at any time from the "Settings" menu. - + Check for updates on startup (requires online connectivity) - + Reset redo stack when a new action is added to history - - User manual - - - - - Changelog + + Enable LaTeX rendering + User manual + + + + + Changelog + + + + Done @@ -278,7 +288,7 @@ These settings can be changed at any time from the "Settings" menu. ListSetting - + + Add Entry @@ -506,12 +516,12 @@ These settings can be changed at any time from the "Settings" menu. changelog - + Could not fetch changelog: Server error {}. - + Could not fetch update: {}. @@ -528,32 +538,37 @@ These settings can be changed at any time from the "Settings" menu. comment - + Ex: R+* (ℝ⁺*), N (ℕ), Z-* (ℤ⁻*), ]0;1[, {3;4;5} - + The following parameters are used when the definition domain is a non-continuous set. (Ex: ℕ, ℤ, sets like {0;3}...) - + Note: Specify the probability for each value. - + Note: Use %1[n] to refer to %1ₙ, %1[n+1] for %1ₙ₊₁... + + + If you have latex enabled, you can use use latex markup in between $$ to create equations. + + control - + %1: @@ -593,12 +608,12 @@ These settings can be changed at any time from the "Settings" menu. function - + Function - + Functions @@ -606,26 +621,60 @@ These settings can be changed at any time from the "Settings" menu. gainbode - + Bode Magnitude - + Bode Magnitudes - + + low-pass - + + high-pass + + latex + + + No Latex installation found. +If you already have a latex distribution installed, make sure it's installed on your path. +Otherwise, you can download a Latex distribution like TeX Live at https://tug.org/texlive/. + + + + + DVIPNG was not found. Make sure you include it from your Latex distribution. + + + + + An exception occured within the creation of the latex formula. +Process '{}' ended with a non-zero return code {}: + +{} +Please make sure your latex installation is correct and report a bug if so. + + + + + An exception occured within the creation of the latex formula. +Process '{}' took too long to finish: +{} +Please make sure your latex installation is correct and report a bug if so. + + + name @@ -753,12 +802,12 @@ These settings can be changed at any time from the "Settings" menu. phasebode - + Bode Phase - + Bode Phases @@ -766,12 +815,12 @@ These settings can be changed at any time from the "Settings" menu. point - + Point - + Points @@ -779,153 +828,158 @@ These settings can be changed at any time from the "Settings" menu. prop - + expression - + definitionDomain - + destinationDomain - - - - - - - - - - + + + + + + + + + + labelPosition - + displayMode - - - - - - - + + + + + + + labelX - - + + drawPoints - - + + drawDashedLines - - + + om_0 - + pass - + gain - + omGraduation - + phase - + unit - - - + + + x - - + + y - + pointStyle - + probabilities - + text - + + disableLatex + + + + targetElement - + approximate - + rounding - + displayStyle - + targetValuePosition - + defaultExpression - + baseValues @@ -933,12 +987,12 @@ These settings can be changed at any time from the "Settings" menu. repartition - + Repartition - + Repartition functions @@ -946,12 +1000,12 @@ These settings can be changed at any time from the "Settings" menu. sequence - + Sequence - + Sequences @@ -959,8 +1013,8 @@ These settings can be changed at any time from the "Settings" menu. sommegainsbode - + Bode Magnitudes Sum @@ -968,8 +1022,8 @@ These settings can be changed at any time from the "Settings" menu. sommephasesbode - + Bode Phases Sum @@ -977,12 +1031,12 @@ These settings can be changed at any time from the "Settings" menu. text - + Text - + Texts @@ -990,22 +1044,22 @@ These settings can be changed at any time from the "Settings" menu. update - + An update for LogarithPlotter (v{}) is available. - + No update available. - + Could not fetch update information: Server error {}. - + Could not fetch update information: {}. @@ -1028,12 +1082,12 @@ These settings can be changed at any time from the "Settings" menu. xcursor - + X Cursor - + X Cursors diff --git a/LogarithmPlotter/i18n/lp_fr.ts b/LogarithmPlotter/i18n/lp_fr.ts index 2fb1234..32830c4 100644 --- a/LogarithmPlotter/i18n/lp_fr.ts +++ b/LogarithmPlotter/i18n/lp_fr.ts @@ -5,7 +5,7 @@ About - + About LogarithmPlotter À propos de LogarithmPlotter @@ -33,113 +33,118 @@ AppMenuBar - + &File &Fichier - + &Load... &Ouvrir… - + &Save &Sauvegarder - + Save &As... Sauvegarde &Sous… - + &Quit &Quitter - + &Edit &Édition - + &Undo &Annuler - + &Redo &Rétablir - + &Copy plot &Copier le graphe - + &Create &Créer - + &Settings &Paramètres - + Check for updates on startup Vérifier la présence de mise à jour au démarrage - + Reset redo stack automaticly Légèrement long, et pas forcément très compréhensible. Réinitialiser la pile d'action "Rétablir" automatiquement - + + Enable LaTeX rendering + + + + &Help &Aide - + &Source code &Code source - + &Report a bug &Rapport de bug - + &User manual Manuel d'&utilisation - + &Changelog &Historique des modifications - + &Help translating! &Aider à la traduction ! - + &About &À propos - + Save unsaved changes? Sauvegarder les modifications ? - + This plot contains unsaved changes. By doing this, all unsaved data will be lost. Continue? Ce graphe contient des modifications non sauvegardées. En faisant cela, toutes les données non sauvegardées seront perdues. Continuer ? @@ -213,34 +218,39 @@ GreetScreen - + Welcome to LogarithmPlotter Bienvenue sur LogarithmPlotter - + Version %1 Version %1 - + Take a few seconds to configure LogarithmPlotter. These settings can be changed at any time from the "Settings" menu. Prenez quelques secondes pour configurer LogarithmPlotter. Ces paramètres peuvent être modifiés à tout moment à partir du menu "Paramètres". - + + Enable LaTeX rendering + + + + User manual Manuel d'utilisation - + Changelog Historique des modifications - + Done Fermer @@ -251,12 +261,12 @@ These settings can always be changed at any time from the "Settings" m These settings can always be changed at any time from the "Settings" menu. - + Check for updates on startup (requires online connectivity) Vérifier les mises à jour au démarrage (nécessite d'être connecté à internet) - + Reset redo stack when a new action is added to history Réinitialiser la pile d'action "Rétablir" lorsqu'une nouvelle action est ajoutée à l'historique @@ -287,7 +297,7 @@ These settings can always be changed at any time from the "Settings" m ListSetting - + + Add Entry + Nouvelle entrée @@ -515,12 +525,12 @@ These settings can always be changed at any time from the "Settings" m changelog - + Could not fetch changelog: Server error {}. Impossible de récupérer l'historique des modifications : Erreur de serveur {}. - + Could not fetch update: {}. Impossible de récupérer l'historique des modifications : {}. @@ -537,33 +547,38 @@ These settings can always be changed at any time from the "Settings" m comment - + Ex: R+* (ℝ⁺*), N (ℕ), Z-* (ℤ⁻*), ]0;1[, {3;4;5} Par exemple : R+* (ℝ⁺*), N (ℕ), Z-* (ℤ⁻*), ]0;1[, {3;4;5} - + The following parameters are used when the definition domain is a non-continuous set. (Ex: ℕ, ℤ, sets like {0;3}...) Les paramètres suivants sont utilisés lorsque le domaine de définition est un ensemble non-continu. (Ex : ℕ, ℤ, des ensembles comme {0;3}…) - + Note: Specify the probability for each value. Note : Spécifiez la probabilité pour chaque valeur. - + Note: Use %1[n] to refer to %1ₙ, %1[n+1] for %1ₙ₊₁... Note : Utilisez %1[n] pour faire référence à %1ₙ, %1[n+1] pour %1ₙ₊₁... Note : Utilisez %1[n] pour faire référence à %1ₙ, %1[n+1] pour %1ₙ₊₁… + + + If you have latex enabled, you can use use latex markup in between $$ to create equations. + + control - + %1: %1 : @@ -603,12 +618,12 @@ These settings can always be changed at any time from the "Settings" m function - + Function Fonction - + Functions Fonctions @@ -616,22 +631,24 @@ These settings can always be changed at any time from the "Settings" m gainbode - + Bode Magnitude Gain de Bode - + Bode Magnitudes Gains de Bode - + + low-pass passe-bas - + + high-pass passe-haut @@ -663,6 +680,47 @@ These settings can always be changed at any time from the "Settings" m Le nom de %1 %2 a été changé en %3. + + latex + + + No Latex installation found. +If you already have a latex distribution installed, make sure it's installed on your path. +Otherwise, you can download a Latex distribution like TeX Live at https://tug.org/texlive/. + Aucune installation de Latex trouvée. +Si vous avez déjà installé une distribution Latex, assurez-vous qu'elle est installée sur votre PATH. +Sinon, vous pouvez télécharger une distribution Latex comme TeX Live à l'adresse https://tug.org/texlive/. + + + + DVIPNG was not found. Make sure you include it from your Latex distribution. + DVIPNG n'a pas été trouvé. Assurez-vous de l'inclure dans votre distribution Latex. + + + + An exception occured within the creation of the latex formula. +Process '{}' ended with a non-zero return code {}: + +{} +Please make sure your latex installation is correct and report a bug if so. + Une exception s'est produite lors de la création de la formule latex. +Le processus '{}' s'est terminé par un code de retour non nul {} : + +{} +Vérifiez que votre installation de latex est correcte et signalez un bogue si c'est le cas. + + + + An exception occured within the creation of the latex formula. +Process '{}' took too long to finish: +{} +Please make sure your latex installation is correct and report a bug if so. + Une exception s'est produite lors de la création de la formule latex. +Le processus '{}' a mis trop de temps à se terminer : +{} +Vérifiez que votre installation de latex est correcte et signalez un bogue si c'est le cas. + + name @@ -790,12 +848,12 @@ These settings can always be changed at any time from the "Settings" m phasebode - + Bode Phase Phase de Bode - + Bode Phases Phases de Bode @@ -803,12 +861,12 @@ These settings can always be changed at any time from the "Settings" m point - + Point Point - + Points Points @@ -816,153 +874,158 @@ These settings can always be changed at any time from the "Settings" m prop - + expression Expression - + definitionDomain Domaine de définition - + destinationDomain Portée - - - - - - - - - - + + + + + + + + + + labelPosition Position de l'étiquette - + displayMode Mode d'affichage - - - - - - - + + + + + + + labelX Position en X de l'étiquette - - + + drawPoints Afficher les points - - + + drawDashedLines Afficher les pointillés - - + + om_0 ω₀ - + pass Passe - + gain Gain - + omGraduation Afficher la graduation sur ω₀ - + phase Phase - + unit Unité de la phase - - - + + + x X - - + + y Y - + pointStyle Style du point - + probabilities Liste de probabilités - + text Contenu - + + disableLatex + Désactiver le rendu latex pour ce texte + + + targetElement Objet à cibler - + approximate Afficher la valeur approximative - + rounding Arrondi - + displayStyle Style d'affichage - + targetValuePosition Position de la valeur de la cible - + defaultExpression Expression - + baseValues Valeurs d'initialisation @@ -974,12 +1037,12 @@ These settings can always be changed at any time from the "Settings" m repartition - + Repartition Répartition - + Repartition functions Fonctions de répartition @@ -987,12 +1050,12 @@ These settings can always be changed at any time from the "Settings" m sequence - + Sequence Suite - + Sequences Suites @@ -1000,8 +1063,8 @@ These settings can always be changed at any time from the "Settings" m sommegainsbode - + Bode Magnitudes Sum Sommes des gains de Bode @@ -1009,8 +1072,8 @@ These settings can always be changed at any time from the "Settings" m sommephasesbode - + Bode Phases Sum Somme des phases de Bode @@ -1018,12 +1081,12 @@ These settings can always be changed at any time from the "Settings" m text - + Text Texte - + Texts Textes @@ -1031,22 +1094,22 @@ These settings can always be changed at any time from the "Settings" m update - + An update for LogarithPlotter (v{}) is available. Une mise à jour de LogarithmPlotter (v{}) est disponible. - + No update available. À jour. - + Could not fetch update information: Server error {}. Impossible de récupérer les informations de mise à jour. Erreur du serveur {}. - + Could not fetch update information: {}. Impossible de récupérer les informations de mise à jour. {}. @@ -1069,12 +1132,12 @@ These settings can always be changed at any time from the "Settings" m xcursor - + X Cursor Curseur X - + X Cursors Curseurs X diff --git a/LogarithmPlotter/i18n/lp_hu.ts b/LogarithmPlotter/i18n/lp_hu.ts index 43a5bad..91ba500 100644 --- a/LogarithmPlotter/i18n/lp_hu.ts +++ b/LogarithmPlotter/i18n/lp_hu.ts @@ -5,7 +5,7 @@ About - + About LogarithmPlotter LogarithmPlotter névjegye @@ -33,112 +33,117 @@ AppMenuBar - + &File &Fájl - + &Load... &Betöltés… - + &Save &Mentés - + Save &As... Me&ntés másként… - + &Quit &Kilépés - + &Edit S&zerkesztés - + &Undo &Visszavonás - + &Redo &Ismétlés - + &Copy plot Ábra má&solása - + &Create &Létrehozás - + &Settings &Beállítások - + Check for updates on startup Frissítések keresése indításkor - + Reset redo stack automaticly Ismétlési verem önműködő visszaállítása - - - &Help - &Súgó - - &Source code - &Forráskód - - - - &Report a bug - &Hiba bejelentése - - - - &User manual + Enable LaTeX rendering + &Help + &Súgó + + + + &Source code + &Forráskód + + + + &Report a bug + &Hiba bejelentése + + + + &User manual + + + + &Changelog &Változásnapló - + &Help translating! &Segítség a fordításban! - + &About &Névjegy - + Save unsaved changes? Menti a változtatásokat? - + This plot contains unsaved changes. By doing this, all unsaved data will be lost. Continue? Ez az ábra nem mentett változtatásokat tartalmaz. Ezzel az összes nem mentett adat elveszik. Folytatja? @@ -211,44 +216,49 @@ GreetScreen - + Welcome to LogarithmPlotter Isten hozott a LogarithmPlotter! - + Version %1 %1 verzió - + Take a few seconds to configure LogarithmPlotter. These settings can be changed at any time from the "Settings" menu. Szánjon néhány másodpercet a LogarithmPlotter beállításához. Ezek a beállítások bármikor módosíthatók a „Beállítások” menüben. - + Check for updates on startup (requires online connectivity) Frissítések keresése indításkor (online kapcsolat szükséges) - + Reset redo stack when a new action is added to history Ismétlési verem alaphelyzet visszaállítása, ha új műveletet adnak az előzményekhez - + + Enable LaTeX rendering + + + + User manual - + Changelog Változásnapló - + Done Kész @@ -279,7 +289,7 @@ Ezek a beállítások bármikor módosíthatók a „Beállítások” menüben. ListSetting - + + Add Entry + Bejegyzés hozzáadása @@ -507,12 +517,12 @@ Ezek a beállítások bármikor módosíthatók a „Beállítások” menüben. changelog - + Could not fetch changelog: Server error {}. Nem sikerült lekérni a változásnaplót: Kiszolgálóhiba: {}. - + Could not fetch update: {}. Nem sikerült lekérni a változásnaplót: {}. @@ -529,32 +539,37 @@ Ezek a beállítások bármikor módosíthatók a „Beállítások” menüben. comment - + Ex: R+* (ℝ⁺*), N (ℕ), Z-* (ℤ⁻*), ]0;1[, {3;4;5} Példák: R+* (ℝ⁺*), N (ℕ), Z-* (ℤ⁻*), ]0;1[, {3;4;5} - + The following parameters are used when the definition domain is a non-continuous set. (Ex: ℕ, ℤ, sets like {0;3}...) A következő paraméterek használatosak, ha a tartomány nem folytonos halmaz. (Példák: ℕ, ℤ, olyan halmazok, mint a {0;3}…) - + Note: Specify the probability for each value. Megjegyzés: Adja meg az egyes értékek valószínűségét. - + Note: Use %1[n] to refer to %1ₙ, %1[n+1] for %1ₙ₊₁... Megjegyzés: A(z) %1[n] használatával hivatkozhat erre: %1ₙ, a(z) %1[n+1] használatával hivatkozhat erre: %1ₙ₊₁, … + + + If you have latex enabled, you can use use latex markup in between $$ to create equations. + + control - + %1: %1: @@ -594,12 +609,12 @@ Ezek a beállítások bármikor módosíthatók a „Beállítások” menüben. function - + Function Függvény - + Functions Függvények @@ -607,22 +622,24 @@ Ezek a beállítások bármikor módosíthatók a „Beállítások” menüben. gainbode - + Bode Magnitude Bode-nagyságrend - + Bode Magnitudes Bode-nagyságrendek - + + low-pass aluláteresztő - + + high-pass felüláteresztő @@ -650,6 +667,38 @@ Ezek a beállítások bármikor módosíthatók a „Beállítások” menüben. %1 %2 rejtve. + + latex + + + No Latex installation found. +If you already have a latex distribution installed, make sure it's installed on your path. +Otherwise, you can download a Latex distribution like TeX Live at https://tug.org/texlive/. + + + + + DVIPNG was not found. Make sure you include it from your Latex distribution. + + + + + An exception occured within the creation of the latex formula. +Process '{}' ended with a non-zero return code {}: + +{} +Please make sure your latex installation is correct and report a bug if so. + + + + + An exception occured within the creation of the latex formula. +Process '{}' took too long to finish: +{} +Please make sure your latex installation is correct and report a bug if so. + + + name @@ -777,12 +826,12 @@ Ezek a beállítások bármikor módosíthatók a „Beállítások” menüben. phasebode - + Bode Phase Bode-fázis - + Bode Phases Bode-fázisok @@ -790,12 +839,12 @@ Ezek a beállítások bármikor módosíthatók a „Beállítások” menüben. point - + Point Pont - + Points Pontok @@ -803,153 +852,158 @@ Ezek a beállítások bármikor módosíthatók a „Beállítások” menüben. prop - + expression Kifejezés - + definitionDomain Abszcissza tartomány - + destinationDomain Ordináta tartomány - - - - - - - - - - + + + + + + + + + + labelPosition Címke helyzete - + displayMode Megjelenítési mód - - - - - - - + + + + + + + labelX Címke X helyzete - - + + drawPoints Pontok megjelenítése - - + + drawDashedLines Szaggatott vonalak megjelenítése - - + + om_0 ω₀ - + pass Áteresztő - + gain Nagyságrend nyeresége - + omGraduation ω₀ érettségi megjelenítése - + phase Fázis - + unit Egység használata - - - + + + x X - - + + y Y - + pointStyle Pontstílus - + probabilities Valószínűségek listája - + text Tartalom - + + disableLatex + + + + targetElement Tárgycél - + approximate Hozzávetőleges érték megjelenítése - + rounding Kerekítés - + displayStyle Megjelenítési stílus - + targetValuePosition Cél értékpozíciója - + defaultExpression Alapértelmezett kifejezés - + baseValues Kezdeményezési értékek @@ -957,12 +1011,12 @@ Ezek a beállítások bármikor módosíthatók a „Beállítások” menüben. repartition - + Repartition Elosztás - + Repartition functions Elosztási függvények @@ -970,12 +1024,12 @@ Ezek a beállítások bármikor módosíthatók a „Beállítások” menüben. sequence - + Sequence Sorozat - + Sequences Sorozatok @@ -983,8 +1037,8 @@ Ezek a beállítások bármikor módosíthatók a „Beállítások” menüben. sommegainsbode - + Bode Magnitudes Sum Bode-nagyságrendek összege @@ -992,8 +1046,8 @@ Ezek a beállítások bármikor módosíthatók a „Beállítások” menüben. sommephasesbode - + Bode Phases Sum Bode-fázisok összege @@ -1001,12 +1055,12 @@ Ezek a beállítások bármikor módosíthatók a „Beállítások” menüben. text - + Text Szöveg - + Texts Szövegek @@ -1014,22 +1068,22 @@ Ezek a beállítások bármikor módosíthatók a „Beállítások” menüben. update - + An update for LogarithPlotter (v{}) is available. Elérhető a Logaritmus-ábrázoló ({} verzió) frissítése. - + No update available. Nincs telepíthető frissítés. - + Could not fetch update information: Server error {}. Nem sikerült lekérni a frissítési adatokat: Kiszolgálóhiba: {}. - + Could not fetch update information: {}. Nem sikerült lekérni a frissítési adatokat: {}. @@ -1052,12 +1106,12 @@ Ezek a beállítások bármikor módosíthatók a „Beállítások” menüben. xcursor - + X Cursor X kurzor - + X Cursors X kurzorok diff --git a/LogarithmPlotter/i18n/lp_nb_NO.ts b/LogarithmPlotter/i18n/lp_nb_NO.ts index 898785b..85ade3d 100644 --- a/LogarithmPlotter/i18n/lp_nb_NO.ts +++ b/LogarithmPlotter/i18n/lp_nb_NO.ts @@ -5,7 +5,7 @@ About - + About LogarithmPlotter Om @@ -33,112 +33,117 @@ AppMenuBar - + &File &Fil - + &Load... &Last inn … - + &Save &Lagre - + Save &As... Lagre &som … - + &Quit &Avslutt - + &Edit &Rediger - + &Undo &Angre - + &Redo &Gjenta - + &Copy plot &Kopier plott - + &Create &Opprett - + &Settings &Innstillinger - + Check for updates on startup Se etter nye versjoner ved programstart - + Reset redo stack automaticly Tilbakestill angrehistorikk automatisk - - - &Help - &Hjelp - - &Source code - - - - - &Report a bug - - - - - &User manual + Enable LaTeX rendering + &Help + &Hjelp + + + + &Source code + + + + + &Report a bug + + + + + &User manual + + + + &Changelog - + &Help translating! - + &About &Om - + Save unsaved changes? - + This plot contains unsaved changes. By doing this, all unsaved data will be lost. Continue? @@ -211,44 +216,49 @@ GreetScreen - + Welcome to LogarithmPlotter Velkommen til LogarithmPlotter - + Version %1 Versjon %1 - + Take a few seconds to configure LogarithmPlotter. These settings can be changed at any time from the "Settings" menu. Sett opp LogarithmPlotter. Disse innstillingene kan endres når som helst fra «Innstillinger»-menyen. - + Check for updates on startup (requires online connectivity) Se etter nye versjoner ved programstart. (Krever tilkobling til Internett.) - + Reset redo stack when a new action is added to history Tilbakesitll angrehistorikk når en ny handling legges til - - User manual - - - - - Changelog + + Enable LaTeX rendering + User manual + + + + + Changelog + + + + Done @@ -279,7 +289,7 @@ Disse innstillingene kan endres når som helst fra «Innstillinger»-menyen. ListSetting - + + Add Entry @@ -507,12 +517,12 @@ Disse innstillingene kan endres når som helst fra «Innstillinger»-menyen. changelog - + Could not fetch changelog: Server error {}. - + Could not fetch update: {}. @@ -529,32 +539,37 @@ Disse innstillingene kan endres når som helst fra «Innstillinger»-menyen. comment - + Ex: R+* (ℝ⁺*), N (ℕ), Z-* (ℤ⁻*), ]0;1[, {3;4;5} - + The following parameters are used when the definition domain is a non-continuous set. (Ex: ℕ, ℤ, sets like {0;3}...) - + Note: Specify the probability for each value. - + Note: Use %1[n] to refer to %1ₙ, %1[n+1] for %1ₙ₊₁... + + + If you have latex enabled, you can use use latex markup in between $$ to create equations. + + control - + %1: @@ -594,12 +609,12 @@ Disse innstillingene kan endres når som helst fra «Innstillinger»-menyen. function - + Function Funksjon - + Functions Funksjoner @@ -607,22 +622,24 @@ Disse innstillingene kan endres når som helst fra «Innstillinger»-menyen. gainbode - + Bode Magnitude Bode-magnitude - + Bode Magnitudes Bode-magnituder - + + low-pass lavpass - + + high-pass høypass @@ -650,6 +667,38 @@ Disse innstillingene kan endres når som helst fra «Innstillinger»-menyen.%1 %2 skjult. + + latex + + + No Latex installation found. +If you already have a latex distribution installed, make sure it's installed on your path. +Otherwise, you can download a Latex distribution like TeX Live at https://tug.org/texlive/. + + + + + DVIPNG was not found. Make sure you include it from your Latex distribution. + + + + + An exception occured within the creation of the latex formula. +Process '{}' ended with a non-zero return code {}: + +{} +Please make sure your latex installation is correct and report a bug if so. + + + + + An exception occured within the creation of the latex formula. +Process '{}' took too long to finish: +{} +Please make sure your latex installation is correct and report a bug if so. + + + name @@ -777,12 +826,12 @@ Disse innstillingene kan endres når som helst fra «Innstillinger»-menyen. phasebode - + Bode Phase Bode-fase - + Bode Phases Bode-faser @@ -790,12 +839,12 @@ Disse innstillingene kan endres når som helst fra «Innstillinger»-menyen. point - + Point Punkt - + Points Punkter @@ -803,153 +852,158 @@ Disse innstillingene kan endres når som helst fra «Innstillinger»-menyen. prop - + expression - + definitionDomain - + destinationDomain - - - - - - - - - - + + + + + + + + + + labelPosition - + displayMode - - - - - - - + + + + + + + labelX - - + + drawPoints - - + + drawDashedLines - - + + om_0 - + pass - + gain - + omGraduation - + phase - + unit - - - + + + x - - + + y - + pointStyle - + probabilities - + text - + + disableLatex + + + + targetElement - + approximate - + rounding - + displayStyle - + targetValuePosition - + defaultExpression - + baseValues @@ -957,12 +1011,12 @@ Disse innstillingene kan endres når som helst fra «Innstillinger»-menyen. repartition - + Repartition Distribusjon - + Repartition functions Distribusjonsfunksjoner @@ -970,12 +1024,12 @@ Disse innstillingene kan endres når som helst fra «Innstillinger»-menyen. sequence - + Sequence Følge - + Sequences Følger @@ -983,8 +1037,8 @@ Disse innstillingene kan endres når som helst fra «Innstillinger»-menyen. sommegainsbode - + Bode Magnitudes Sum Bode-magnitudesum @@ -992,8 +1046,8 @@ Disse innstillingene kan endres når som helst fra «Innstillinger»-menyen. sommephasesbode - + Bode Phases Sum Bode-fasesum @@ -1001,12 +1055,12 @@ Disse innstillingene kan endres når som helst fra «Innstillinger»-menyen. text - + Text Tekst - + Texts Tekster @@ -1014,22 +1068,22 @@ Disse innstillingene kan endres når som helst fra «Innstillinger»-menyen. update - + An update for LogarithPlotter (v{}) is available. En ny versjon av LogartimePlotter (v{}) er tilgjengelig - + No update available. Ingen nye versjoner. - + Could not fetch update information: Server error {}. Fant ikke ut om det er noen nye versjoner. Tjenerfeil {}. - + Could not fetch update information: {}. Kunne ikke hente info om hvorvidt det er nye versjoner: {}. @@ -1052,12 +1106,12 @@ Disse innstillingene kan endres når som helst fra «Innstillinger»-menyen. xcursor - + X Cursor X-peker - + X Cursors X-pekere diff --git a/LogarithmPlotter/i18n/lp_template.ts b/LogarithmPlotter/i18n/lp_template.ts index d3888b9..aacd4e5 100644 --- a/LogarithmPlotter/i18n/lp_template.ts +++ b/LogarithmPlotter/i18n/lp_template.ts @@ -5,7 +5,7 @@ About - + About LogarithmPlotter @@ -33,112 +33,117 @@ AppMenuBar - + &File - + &Load... - + &Save - + Save &As... - + &Quit - + &Edit - + &Undo - + &Redo - + &Copy plot - + &Create - + &Settings - + Check for updates on startup - + Reset redo stack automaticly - - - &Help - - - &Source code - - - - - &Report a bug - - - - - &User manual + Enable LaTeX rendering + &Help + + + + + &Source code + + + + + &Report a bug + + + + + &User manual + + + + &Changelog - + &Help translating! - + &About - + Save unsaved changes? - + This plot contains unsaved changes. By doing this, all unsaved data will be lost. Continue? @@ -211,43 +216,48 @@ GreetScreen - + Welcome to LogarithmPlotter - + Version %1 - + Take a few seconds to configure LogarithmPlotter. These settings can be changed at any time from the "Settings" menu. - + Check for updates on startup (requires online connectivity) - + Reset redo stack when a new action is added to history - - User manual - - - - - Changelog + + Enable LaTeX rendering + User manual + + + + + Changelog + + + + Done @@ -278,7 +288,7 @@ These settings can be changed at any time from the "Settings" menu. ListSetting - + + Add Entry @@ -506,12 +516,12 @@ These settings can be changed at any time from the "Settings" menu. changelog - + Could not fetch changelog: Server error {}. - + Could not fetch update: {}. @@ -528,32 +538,37 @@ These settings can be changed at any time from the "Settings" menu. comment - + Ex: R+* (ℝ⁺*), N (ℕ), Z-* (ℤ⁻*), ]0;1[, {3;4;5} - + The following parameters are used when the definition domain is a non-continuous set. (Ex: ℕ, ℤ, sets like {0;3}...) - + Note: Specify the probability for each value. - + Note: Use %1[n] to refer to %1ₙ, %1[n+1] for %1ₙ₊₁... + + + If you have latex enabled, you can use use latex markup in between $$ to create equations. + + control - + %1: @@ -593,12 +608,12 @@ These settings can be changed at any time from the "Settings" menu. function - + Function - + Functions @@ -606,26 +621,60 @@ These settings can be changed at any time from the "Settings" menu. gainbode - + Bode Magnitude - + Bode Magnitudes - + + low-pass - + + high-pass + + latex + + + No Latex installation found. +If you already have a latex distribution installed, make sure it's installed on your path. +Otherwise, you can download a Latex distribution like TeX Live at https://tug.org/texlive/. + + + + + DVIPNG was not found. Make sure you include it from your Latex distribution. + + + + + An exception occured within the creation of the latex formula. +Process '{}' ended with a non-zero return code {}: + +{} +Please make sure your latex installation is correct and report a bug if so. + + + + + An exception occured within the creation of the latex formula. +Process '{}' took too long to finish: +{} +Please make sure your latex installation is correct and report a bug if so. + + + name @@ -753,12 +802,12 @@ These settings can be changed at any time from the "Settings" menu. phasebode - + Bode Phase - + Bode Phases @@ -766,12 +815,12 @@ These settings can be changed at any time from the "Settings" menu. point - + Point - + Points @@ -779,153 +828,158 @@ These settings can be changed at any time from the "Settings" menu. prop - + expression - + definitionDomain - + destinationDomain - - - - - - - - - - + + + + + + + + + + labelPosition - + displayMode - - - - - - - + + + + + + + labelX - - + + drawPoints - - + + drawDashedLines - - + + om_0 - + pass - + gain - + omGraduation - + phase - + unit - - - + + + x - - + + y - + pointStyle - + probabilities - + text - + + disableLatex + + + + targetElement - + approximate - + rounding - + displayStyle - + targetValuePosition - + defaultExpression - + baseValues @@ -933,12 +987,12 @@ These settings can be changed at any time from the "Settings" menu. repartition - + Repartition - + Repartition functions @@ -946,12 +1000,12 @@ These settings can be changed at any time from the "Settings" menu. sequence - + Sequence - + Sequences @@ -959,8 +1013,8 @@ These settings can be changed at any time from the "Settings" menu. sommegainsbode - + Bode Magnitudes Sum @@ -968,8 +1022,8 @@ These settings can be changed at any time from the "Settings" menu. sommephasesbode - + Bode Phases Sum @@ -977,12 +1031,12 @@ These settings can be changed at any time from the "Settings" menu. text - + Text - + Texts @@ -990,22 +1044,22 @@ These settings can be changed at any time from the "Settings" menu. update - + An update for LogarithPlotter (v{}) is available. - + No update available. - + Could not fetch update information: Server error {}. - + Could not fetch update information: {}. @@ -1028,12 +1082,12 @@ These settings can be changed at any time from the "Settings" menu. xcursor - + X Cursor - + X Cursors diff --git a/LogarithmPlotter/logarithmplotter.py b/LogarithmPlotter/logarithmplotter.py index 53b29e0..70073ef 100644 --- a/LogarithmPlotter/logarithmplotter.py +++ b/LogarithmPlotter/logarithmplotter.py @@ -18,17 +18,18 @@ from time import time -start_time = time() - from PySide2.QtWidgets import QApplication from PySide2.QtQml import QQmlApplicationEngine -from PySide2.QtCore import QTranslator, QLocale +from PySide2.QtCore import Qt, QTranslator, QLocale from PySide2.QtGui import QIcon from tempfile import TemporaryDirectory from os import getcwd, chdir, environ, path, remove, close from platform import release as os_release from sys import platform, argv, version as sys_version, exit +from sys import path as sys_path + +start_time = time() # Create the temporary directory for saving copied screenshots and latex files tempdir = TemporaryDirectory() @@ -37,7 +38,6 @@ pwd = getcwd() chdir(path.dirname(path.realpath(__file__))) -from sys import path as sys_path if path.realpath(path.join(getcwd(), "..")) not in sys_path: sys_path.append(path.realpath(path.join(getcwd(), ".."))) @@ -46,6 +46,7 @@ from LogarithmPlotter import __VERSION__ from LogarithmPlotter.util import config, native from LogarithmPlotter.util.update import check_for_updates from LogarithmPlotter.util.helper import Helper +from LogarithmPlotter.util.latex import Latex config.init() @@ -84,6 +85,7 @@ def run(): icon_fallbacks.append(path.realpath(path.join(base_icon_path, "settings", "custom"))) QIcon.setFallbackSearchPaths(icon_fallbacks); + QApplication.setAttribute(Qt.AA_EnableHighDpiScaling) app = QApplication(argv) app.setApplicationName("LogarithmPlotter") app.setOrganizationName("Ad5001") @@ -107,7 +109,9 @@ def run(): engine = QQmlApplicationEngine() global tmpfile helper = Helper(pwd, tmpfile) + latex = Latex(tempdir) engine.rootContext().setContextProperty("Helper", helper) + engine.rootContext().setContextProperty("Latex", latex) engine.rootContext().setContextProperty("TestBuild", "--test-build" in argv) engine.rootContext().setContextProperty("StartTime", dep_time) @@ -131,6 +135,8 @@ def run(): if platform == "darwin": macOSFileOpenHandler.init_graphics(engine.rootObjects()[0]) + latex.check_latex_install() + # Check for updates if config.getSetting("check_for_updates"): check_for_updates(__VERSION__, engine.rootObjects()[0]) diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/AppMenuBar.qml b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/AppMenuBar.qml index c7aa7bb..31d9b7b 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/AppMenuBar.qml +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/AppMenuBar.qml @@ -22,6 +22,8 @@ import QtQuick.Dialogs 1.3 import eu.ad5001.MixedMenu 1.1 import "js/objects.js" as Objects import "js/historylib.js" as HistoryLib +import "js/math/latex.js" as Latex + /*! \qmltype AppMenuBar @@ -139,6 +141,21 @@ MenuBar { onTriggered: Helper.setSettingBool("reset_redo_stack", checked) icon.name: 'timeline' } + + Action { + id: enableLatexSetting + text: qsTr("Enable LaTeX rendering") + checkable: true + checked: Helper.getSettingBool("enable_latex") + onTriggered: { + Helper.setSettingBool("enable_latex", checked) + Latex.enabled = checked + drawCanvas.requestPaint() + } + icon.name: 'Expression' + + Component.onCompleted: Latex.enabled = checked + } } Menu { diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/History/History.qml b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/History/History.qml index 99fc4cb..e6caf9d 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/History/History.qml +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/History/History.qml @@ -124,14 +124,16 @@ Item { } /*! - \qmlmethod void History::undo() + \qmlmethod void History::undo(bool updateObjectList = true) Undoes the historylib.Action at the top of the undo stack and pushes it to the top of the redo stack. + By default, will update the graph and the object list. This behavior can be disabled by setting the \c updateObjectList to false. */ - function undo() { + function undo(updateObjectList = true) { if(undoStack.length > 0) { var action = undoStack.pop() action.undo() - objectLists.update() + if(updateObjectList) + objectLists.update() redoStack.push(action) undoCount--; redoCount++; @@ -140,14 +142,16 @@ Item { } /*! - \qmlmethod void History::redo() + \qmlmethod void History::redo(bool updateObjectList = true) Redoes the historylib.Action at the top of the redo stack and pushes it to the top of the undo stack. + By default, will update the graph and the object list. This behavior can be disabled by setting the \c updateObjectList to false. */ - function redo() { + function redo(updateObjectList = true) { if(redoStack.length > 0) { var action = redoStack.pop() action.redo() - objectLists.update() + if(updateObjectList) + objectLists.update() undoStack.push(action) undoCount++; redoCount--; @@ -186,7 +190,7 @@ Item { property int toUndoCount: 0 onTriggered: { if(toUndoCount > 0) { - historyObj.undo() + historyObj.undo(toUndoCount % 4 == 1) // Only redraw once every 4 changes. toUndoCount--; } else { running = false; @@ -200,7 +204,7 @@ Item { property int toRedoCount: 0 onTriggered: { if(toRedoCount > 0) { - historyObj.redo() + historyObj.redo(toRedoCount % 4 == 1) // Only redraw once every 4 changes. toRedoCount--; } else { running = false; diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/LogGraphCanvas.qml b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/LogGraphCanvas.qml index f140007..e35950a 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/LogGraphCanvas.qml +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/LogGraphCanvas.qml @@ -157,26 +157,48 @@ Canvas { */ property int drawMaxX: Math.ceil(Math.max(Math.abs(xmin), Math.abs(px2x(canvasSize.width)))/xaxisstep1) + /*! + \qmlproperty var LogGraphCanvas::imageLoaders + Dictionary of format {image: [callback.image data]} containing data for defered image loading. + */ + property var imageLoaders: {} + /*! + \qmlproperty var LogGraphCanvas::ctx + Cache for the 2D context so that it may be used asynchronously. + */ + property var ctx - onPaint: { + Component.onCompleted: imageLoaders = {} + + onPaint: function(rect) { //console.log('Redrawing') - var ctx = getContext("2d"); - reset(ctx) - drawGrille(ctx) - drawAxises(ctx) - ctx.lineWidth = linewidth - for(var objType in Objects.currentObjects) { - for(var obj of Objects.currentObjects[objType]){ - ctx.strokeStyle = obj.color - ctx.fillStyle = obj.color - if(obj.visible) obj.draw(canvas, ctx) + if(rect.width == canvas.width) { // Redraw full canvas + ctx = getContext("2d"); + reset(ctx) + drawGrille(ctx) + drawAxises(ctx) + drawLabels(ctx) + ctx.lineWidth = linewidth + for(var objType in Objects.currentObjects) { + for(var obj of Objects.currentObjects[objType]){ + ctx.strokeStyle = obj.color + ctx.fillStyle = obj.color + if(obj.visible) obj.draw(canvas, ctx) + } } + ctx.lineWidth = 1 } - ctx.lineWidth = 1 - drawLabels(ctx) - } + onImageLoaded: { + Object.keys(imageLoaders).forEach((key) => { + if(isImageLoaded(key)) { + // Calling callback + imageLoaders[key][0](canvas, ctx, imageLoaders[key][1]) + delete imageLoaders[key] + } + }) + } /*! \qmlmethod void LogGraphCanvas::reset(var ctx) @@ -186,7 +208,7 @@ Canvas { // Reset ctx.fillStyle = "#FFFFFF" ctx.strokeStyle = "#000000" - ctx.font = `${canvas.textsize-2}px sans-serif` + ctx.font = `${canvas.textsize}px sans-serif` ctx.fillRect(0,0,width,height) } @@ -243,12 +265,12 @@ Canvas { var axisxpx = y2px(0) // Y coordinate of X axis // Labels ctx.fillStyle = "#000000" - ctx.font = `${canvas.textsize+2}px sans-serif` + ctx.font = `${canvas.textsize}px sans-serif` ctx.fillText(ylabel, axisypx+10, 24) var textSize = ctx.measureText(xlabel).width ctx.fillText(xlabel, canvasSize.width-14-textSize, axisxpx-5) // Axis graduation labels - ctx.font = `${canvas.textsize-2}px sans-serif` + ctx.font = `${canvas.textsize-4}px sans-serif` var txtMinus = ctx.measureText('-').width if(showxgrad) { @@ -314,16 +336,30 @@ Canvas { } } + /*! + \qmlmethod void LogGraphCanvas::drawVisibleImage(var ctx, var image, double x, double y) + Draws an \c image onto the canvas using 2D \c ctx. + \note The \c x, \c y \c width and \c height properties here are relative to the canvas, not the plot. + */ + function drawVisibleImage(ctx, image, x, y, width, height) { + //console.log("Drawing image", isImageLoaded(image), isImageError(image)) + markDirty(Qt.rect(x, y, width, height)); + ctx.drawImage(image, x, y, width, height) + /*if(true || (x > 0 && x < canvasSize.width && y > 0 && y < canvasSize.height)) { + }*/ + } + /*! \qmlmethod var LogGraphCanvas::measureText(var ctx, string text) Measures the wicth and height of a multiline \c text that would be drawn onto the canvas using 2D \c ctx. Return format: dictionary {"width": width, "height": height} */ function measureText(ctx, text) { - var theight = 0 - var twidth = 0 + let theight = 0 + let twidth = 0 + let defaultHeight = ctx.measureText("M").width // Approximate but good enough! text.split("\n").forEach(function(txt, i){ - theight += canvas.textsize + theight += defaultHeight if(ctx.measureText(txt).width > twidth) twidth = ctx.measureText(txt).width }) return {'width': twidth, 'height': theight} @@ -415,4 +451,25 @@ Canvas { } ctx.stroke(); } + + /*! + \qmlmethod var LogGraphCanvas::renderLatexImage(string ltxText, color) + Renders latex markup \c ltxText to an image and loads it. Returns a dictionary with three values: source, width and height. + */ + function renderLatexImage(ltxText, color, callback) { + let [ltxSrc, ltxWidth, ltxHeight] = Latex.render(ltxText, textsize, color).split(",") + let imgData = { + "source": ltxSrc, + "width": parseFloat(ltxWidth), + "height": parseFloat(ltxHeight) + }; + if(!isImageLoaded(ltxSrc) && !isImageLoading(ltxSrc)){ + // Wait until the image is loaded to callback. + loadImage(ltxSrc) + imageLoaders[ltxSrc] = [callback, imgData] + } else { + // Callback directly + callback(canvas, ctx, imgData) + } + } } diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Popup/GreetScreen.qml b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Popup/GreetScreen.qml index e99cd17..15c1587 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Popup/GreetScreen.qml +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Popup/GreetScreen.qml @@ -18,6 +18,7 @@ import QtQuick 2.12 import QtQuick.Controls 2.12 +import "../js/math/latex.js" as Latex /*! \qmltype GreetScreen @@ -101,7 +102,7 @@ Popup { text: qsTr('Check for updates on startup (requires online connectivity)') onClicked: { Helper.setSettingBool("check_for_updates", checked) - checkForUpdatesMenuSetting.checked = checked + //checkForUpdatesMenuSetting.checked = checked } } @@ -113,7 +114,20 @@ Popup { text: qsTr('Reset redo stack when a new action is added to history') onClicked: { Helper.setSettingBool("reset_redo_stack", checked) - resetRedoStackMenuSetting.checked = checked + //resetRedoStackMenuSetting.checked = checked + } + } + + CheckBox { + id: enableLatexSetting + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: resetRedoStackSetting.bottom + checked: Helper.getSettingBool("enable_latex") + text: qsTr('Enable LaTeX rendering') + onClicked: { + Helper.setSettingBool("enable_latex", checked) + Latex.enabled = checked + drawCanvas.requestPaint() } } diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Setting/LatexExpression.qml b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Setting/LatexExpression.qml new file mode 100644 index 0000000..bc8897c --- /dev/null +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Setting/LatexExpression.qml @@ -0,0 +1,28 @@ +/** + * LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions. + * Copyright (C) 2022 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 . + */ + + +import QtQuick 2.12 +import QtQuick.Controls 2.12 + +Image { + id: expr + property string expression + + src: Latex.render(expression).split(',')[0] +} diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Setting/ListSetting.qml b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Setting/ListSetting.qml index 718181f..c71fddd 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Setting/ListSetting.qml +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Setting/ListSetting.qml @@ -1,3 +1,21 @@ +/** + * LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions. + * Copyright (C) 2022 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 . + */ + import QtQuick 2.12 import QtQuick.Controls 2.12 import QtQml.Models 2.12 diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Setting/TextSetting.qml b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Setting/TextSetting.qml index 739f7d8..d9239c8 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Setting/TextSetting.qml +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Setting/TextSetting.qml @@ -83,7 +83,7 @@ Item { id: iconLabel anchors.top: parent.top anchors.topMargin: icon == "" ? 0 : 3 - source: control.visible ? "../icons/" + control.icon : "" + source: control.visible && icon != "" ? "../icons/" + control.icon : "" width: height height: icon == "" || !visible ? 0 : 24 color: sysPalette.windowText diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Settings.qml b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Settings.qml index 2115b6b..6bde410 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Settings.qml +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Settings.qml @@ -99,7 +99,7 @@ ScrollView { Font size of the text that will be drawn into the canvas, provided from settings. \sa Settings */ - property double textsize: 14 + property double textsize: 18 /*! \qmlproperty bool Settings::logscalex true if the canvas should be in logarithmic mode, false otherwise. diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/domain.js b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/domain.js index cdf9902..48c23cf 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/domain.js +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/domain.js @@ -152,10 +152,15 @@ class Domain { * Represents an empty set. */ class EmptySet extends Domain { + constructor() { + super() + this.displayName = "∅" + this.latexMarkup = "\\emptyset" + } includes(x) { return false } - toString() { return "∅" } + toString() { return this.displayName } union(domain) { return domain } @@ -177,6 +182,7 @@ class Range extends Domain { this.openBegin = openBegin this.openEnd = openEnd this.displayName = (openBegin ? "]" : "[") + begin.toString() + ";" + end.toString() + (openEnd ? "[" : "]") + this.latexMarkup = `\\mathopen${openBegin ? "]" : "["}${this.begin.latexMarkup};${this.end.latexMarkup}\\mathclose${openEnd ? "[" : "]"}` } includes(x) { @@ -292,6 +298,8 @@ class DomainSet extends SpecialDomain { } this.executedValues.sort((a,b) => a-b) this.values = this.executedValues.map(val => newVals[val]) + this.displayName = "{" + this.values.join(";") + "}" + this.latexMarkup = `\\{${this.values.join(";")}\\}` } includes(x) { @@ -325,7 +333,7 @@ class DomainSet extends SpecialDomain { } toString() { - return "{" + this.values.join(";") + "}" + return this.displayName } union(domain) { @@ -397,6 +405,8 @@ class UnionDomain extends Domain { super() this.dom1 = dom1 this.dom2 = dom2 + this.displayName = this.dom1.toString() + " ∪ " + this.dom2.toString() + this.latexMarkup = `${dom1.latexMarkup}\\cup${dom2.latexMarkup}` } includes(x) { @@ -404,7 +414,7 @@ class UnionDomain extends Domain { } toString() { - return this.dom1.toString() + " ∪ " + this.dom2.toString() + return this.displayName } union(domain) { @@ -441,6 +451,8 @@ class IntersectionDomain extends Domain { super() this.dom1 = dom1 this.dom2 = dom2 + this.displayName = dom1.toString() + " ∩ " + dom2.toString() + this.latexMarkup = `${dom1.latexMarkup}\\cap${dom2.latexMarkup}` } includes(x) { @@ -448,7 +460,7 @@ class IntersectionDomain extends Domain { } toString() { - return this.dom1.toString() + " ∩ " + this.dom2.toString() + return this.displayName } union(domain) { @@ -484,6 +496,8 @@ class MinusDomain extends Domain { super() this.dom1 = dom1 this.dom2 = dom2 + this.displayName = dom1.toString() + "∖" + dom2.toString() + this.latexMarkup = `${dom1.latexMarkup}\\setminus${dom2.latexMarkup}` } includes(x) { @@ -491,7 +505,7 @@ class MinusDomain extends Domain { } toString() { - return this.dom1.toString() + "∖" + this.dom2.toString() + return this.displayName } static import(frm) { @@ -505,33 +519,45 @@ class MinusDomain extends Domain { Domain.RE = new MinusDomain("R", "{0}") Domain.RE.displayName = "ℝ*" +Domain.RE.latexMarkup = "\\mathbb{R}^{*}" Domain.R = new Range(-Infinity,Infinity,true,true) Domain.R.displayName = "ℝ" +Domain.R.latexMarkup = "\\mathbb{R}" Domain.RP = new Range(0,Infinity,true,false) Domain.RP.displayName = "ℝ⁺" +Domain.RP.latexMarkup = "\\mathbb{R}^{+}" Domain.RM = new Range(-Infinity,0,true,false) Domain.RM.displayName = "ℝ⁻" +Domain.RM.latexMarkup = "\\mathbb{R}^{-}" Domain.RPE = new Range(0,Infinity,true,true) Domain.RPE.displayName = "ℝ⁺*" +Domain.RPE.latexMarkup = "\\mathbb{R}^{+*}" Domain.RME = new Range(-Infinity,0,true,true) Domain.RME.displayName = "ℝ⁻*" +Domain.RME.latexMarkup = "\\mathbb{R}^{+*}" Domain.N = new SpecialDomain('ℕ', x => x%1==0 && x >= 0, x => Math.max(Math.floor(x)+1, 0), x => Math.max(Math.ceil(x)-1, 0)) +Domain.N.latexMarkup = "\\mathbb{N}" Domain.NE = new SpecialDomain('ℕ*', x => x%1==0 && x > 0, x => Math.max(Math.floor(x)+1, 1), x => Math.max(Math.ceil(x)-1, 1)) +Domain.NE.latexMarkup = "\\mathbb{N}^{*}" Domain.Z = new SpecialDomain('ℤ', x => x%1==0, x => Math.floor(x)+1, x => Math.ceil(x)-1) +Domain.Z.latexMarkup = "\\mathbb{Z}" Domain.ZE = new SpecialDomain('ℤ*', x => x%1==0 && x != 0, x => Math.floor(x)+1 == 0 ? Math.floor(x)+2 : Math.floor(x)+1, x => Math.ceil(x)-1 == 0 ? Math.ceil(x)-2 : Math.ceil(x)-1) +Domain.ZE.latexMarkup = "\\mathbb{Z}^{*}" Domain.ZM = new SpecialDomain('ℤ⁻', x => x%1==0 && x <= 0, x => Math.min(Math.floor(x)+1, 0), x => Math.min(Math.ceil(x)-1, 0)) +Domain.ZM.latexMarkup = "\\mathbb{Z}^{-}" Domain.ZME = new SpecialDomain('ℤ⁻*', x => x%1==0 && x < 0, x => Math.min(Math.floor(x)+1, -1), x => Math.min(Math.ceil(x)-1, -1)) +Domain.ZME.latexMarkup = "\\mathbb{Z}^{-*}" Domain.NLog = new SpecialDomain('ℕˡᵒᵍ', x => x/Math.pow(10, x.toString().length-1) % 1 == 0 && x > 0, function(x) { @@ -542,6 +568,7 @@ Domain.NLog = new SpecialDomain('ℕˡᵒᵍ', var x10pow = Math.pow(10, x.toString().length-1) return Math.max(1, (Math.ceil(x/x10pow)-1)*x10pow) }) +Domain.NLog.latexMarkup = "\\mathbb{N}^{log}" var refedDomains = [] diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/expression.js b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/expression.js index ed2bee9..58c4528 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/expression.js +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/expression.js @@ -31,7 +31,7 @@ class Expression { this.calc = C.parser.parse(expr).simplify() this.cached = this.isConstant() this.cachedValue = this.cached ? this.calc.evaluate(C.evalVariables) : null - this.latexMarkup = Latex.expressionToLatex(this.calc.tokens) + this.latexMarkup = Latex.expression(this.calc.tokens) } isConstant() { diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/latex.js b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/latex.js index d7620fc..4c57b07 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/latex.js +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/latex.js @@ -20,6 +20,12 @@ .import "../expr-eval.js" as ExprEval + +/** + * true if latex has been enabled by the user, false otherwise. + */ +var enabled = false + /** * Puts element within parenthesis. * @@ -32,23 +38,99 @@ function par(elem) { /** * Checks if the element contains at least one of the elements of - * the string array contents , and returns the parenthesis version if so. + * the string array contents, but not at the first position of the string, + * and returns the parenthesis version if so. * * @param {string} elem - element to put within parenthesis. * @param {Array} contents - Array of elements to put within parenthesis. * @returns {string} */ function parif(elem, contents) { - return contents.some(x => elem.toString().includes(x)) ? par(elem) : elem + elem = elem.toString() + if(elem[0] != "(" && elem[elem.length-1] != ")" && contents.some(x => elem.indexOf(x) > 0)) + return par(elem) + if(elem[0] == "(" && elem[elem.length-1] == ")") + return elem.substr(1, elem.length-2) + return elem +} + + +/** + * Creates a latex expression for a function. + * + * @param {string} f - Function to convert + * @param {Array} args - Arguments of the function + * @returns {string} + */ +function functionToLatex(f, args) { + switch(f) { + case "derivative": + return '\\frac{d' + args[0].substr(1, args[0].length-2).replace(new RegExp(args[1].substr(1, args[1].length-2), 'g'), 'x') + '}{dx}'; + break; + case "integral": + return '\\int\\limits_{' + args[0] + '}^{' + args[1] + '}' + args[2].substr(1, args[2].length-2) + ' d' + args[3].substr(1, args[3].length-2); + break; + case "sqrt": + return '\\sqrt\\left(' + args.join(', ') + '\\right)'; + break; + case "abs": + return '\\left|' + args.join(', ') + '\\right|'; + break; + case "floor": + return '\\left\\lfloor' + args.join(', ') + '\\right\\rfloor'; + break; + case "ceil": + return '\\left\\lceil' + args.join(', ') + '\\right\\rceil'; + break; + default: + return '\\mathrm{' + f + '}\\left(' + args.join(', ') + '\\right)'; + break; + } +} + + +/** + * Creates a latex variable from a variable. + * + * @param {string} vari - variable to convert + * @returns {string} + */ +function variable(vari) { + let unicodechars = ["α","β","γ","δ","ε","ζ","η", + "π","θ","κ","λ","μ","ξ","ρ", + "ς","σ","τ","φ","χ","ψ","ω", + "Γ","Δ","Θ","Λ","Ξ","Π","Σ", + "Φ","Ψ","Ω","ₐ","ₑ","ₒ","ₓ", + "ₕ","ₖ","ₗ","ₘ","ₙ","ₚ","ₛ", + "ₜ","¹","²","³","⁴","⁵","⁶", + "⁷","⁸","⁹","⁰","₁","₂","₃", + "₄","₅","₆","₇","₈","₉","₀", + "pi"] + let equivalchars = ["\\alpha","\\beta","\\gamma","\\delta","\\epsilon","\\zeta","\\eta", + "\\pi","\\theta","\\kappa","\\lambda","\\mu","\\xi","\\rho", + "\\sigma","\\sigma","\\tau","\\phi","\\chi","\\psi","\\omega", + "\\Gamma","\\Delta","\\Theta","\\Lambda","\\Xi","\\Pi","\\Sigma", + "\\Phy","\\Psi","\\Omega","{}_{a}","{}_{e}","{}_{o}","{}_{x}", + "{}_{h}","{}_{k}","{}_{l}","{}_{m}","{}_{n}","{}_{p}","{}_{s}", + "{}_{t}","{}^{1}","{}^{2}","{}^{3}","{}^{4}","{}^{5}","{}^{6}", + "{}^{7}","{}^{8}","{}^{9}","{}^{0}","{}_{1}","{}_{2}","{}_{3}", + "{}_{4}","{}_{5}","{}_{6}","{}_{7}","{}_{8}","{}_{9}","{}_{0}", + "\\pi"] + for(let i = 0; i < unicodechars.length; i++) { + //console.log(vari, unicodechars[i], equivalchars[i]); + if(vari.includes(unicodechars[i])) + vari = vari.replace(new RegExp(unicodechars[i], 'g'), equivalchars[i]) + } + return vari; } /** - * This function converts expr-eval tokens to a latex string. + * Converts expr-eval tokens to a latex string. * * @param {Array} tokens - expr-eval tokens list * @returns {string} */ -function expressionToLatex(tokens) { +function expression(tokens) { var nstack = []; var n1, n2, n3; var f, args, argCount; @@ -73,7 +155,7 @@ function expressionToLatex(tokens) { switch(f) { case '-': case '+': - nstack.push(n1 + this.ope + n2); + nstack.push(n1 + f + n2); break; case '||': case 'or': @@ -81,10 +163,13 @@ function expressionToLatex(tokens) { case 'and': case '==': case '!=': - nstack.push(par(n1) + this.ope + par(n2)); + nstack.push(par(n1) + f + par(n2)); break; case '*': - nstack.push(parif(n1,['+','-']) + " \\times " + parif(n2,['+','-'])); + if(n2 == "\\pi" || n2 == "e" || n2 == "x" || n2 == "n") + nstack.push(parif(n1,['+','-']) + n2) + else + nstack.push(parif(n1,['+','-']) + " \\times " + parif(n2,['+','-'])); break; case '/': nstack.push("\\frac{" + n1 + "}{" + n2 + "}"); @@ -115,10 +200,7 @@ function expressionToLatex(tokens) { break; case ExprEval.IVAR: case ExprEval.IVARNAME: - if(item.value == "pi") - nstack.push("π") - else - nstack.push(item.value); + nstack.push(variable(item.value.toString())); break; case ExprEval.IOP1: // Unary operator n1 = nstack.pop(); @@ -144,20 +226,7 @@ function expressionToLatex(tokens) { } f = nstack.pop(); // Handling various functions - if(f == "derivative") - nstack.push('\\frac{d' + args[0].substr(1, args[0].length-2).replace(new RegExp(by, 'g'), 'x') + '}{dx}'); - else if(f == "integral") - nstack.push('\\int\\limits^{' + args[0] + '}_{' + args[1] + '}' + args[2].substr(1, args[2].length-2) + ' d' + args[3]); - else if(f == "sqrt") - nstack.push('\\sqrt\\left(' + args.join(', ') + '\\right)'); - else if(f == "abs") - nstack.push('\\left|' + args.join(', ') + '\\right|'); - else if(f == "floor") - nstack.push('\\left\\lfloor' + args.join(', ') + '\\right\\rfloor'); - else if(f == "ceil") - nstack.push('\\left\\lceil' + args.join(', ') + '\\right\\rceil'); - else - nstack.push('\\mathrm{' + f + '}\\left(' + args.join(', ') + '\\right)'); + nstack.push(functionToLatex(f, args)) break; case ExprEval.IFUNDEF: nstack.push(par(n1 + '(' + args.join(', ') + ') = ' + n2)); @@ -175,7 +244,7 @@ function expressionToLatex(tokens) { nstack.push('[' + args.join(', ') + ']'); break; case ExprEval.IEXPR: - nstack.push('(' + expressionToLatex(item.value) + ')'); + nstack.push('(' + expression(item.value) + ')'); break; case ExprEval.IENDSTATEMENT: break; @@ -185,11 +254,7 @@ function expressionToLatex(tokens) { } } if (nstack.length > 1) { - if (toJS) { - nstack = [ nstack.join(',') ]; - } else { - nstack = [ nstack.join(';') ]; - } + nstack = [ nstack.join(';') ] } return String(nstack[0]); } diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/sequence.js b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/sequence.js index 7988949..cdee74c 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/sequence.js +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/sequence.js @@ -21,6 +21,8 @@ .import "common.js" as C .import "expression.js" as Expr .import "../utils.js" as Utils +.import "../math/latex.js" as Latex + /** * Represents mathematical object for sequences. @@ -32,9 +34,13 @@ class Sequence extends Expr.Expression { this.name = name this.baseValues = baseValues this.calcValues = Object.assign({}, baseValues) + this.latexValues = Object.assign({}, baseValues) for(var n in this.calcValues) - if(['string', 'number'].includes(typeof this.calcValues[n])) - this.calcValues[n] = parser.parse(this.calcValues[n].toString()).simplify().evaluate(C.evalVariables) + if(['string', 'number'].includes(typeof this.calcValues[n])) { + let parsed = C.parser.parse(this.calcValues[n].toString()).simplify() + this.latexValues[n] = Latex.expression(parsed.tokens) + this.calcValues[n] = parsed.evaluate(C.evalVariables) + } this.valuePlus = parseInt(valuePlus) } @@ -58,11 +64,11 @@ class Sequence extends Expr.Expression { cache(n = 1) { var str = Utils.simplifyExpression(this.calc.substitute('n', n-this.valuePlus).toString()) - var expr = parser.parse(str).simplify() + var expr = C.parser.parse(str).simplify() var l = {'n': n-this.valuePlus} // Just in case, add n (for custom functions) l[this.name] = this.calcValues - currentVars = Object.assign(l, C.evalVariables) - this.calcValues[n] = expr.evaluate(currentVars) + C.currentVars = Object.assign(l, C.evalVariables) + this.calcValues[n] = expr.evaluate(C.currentVars) } toString(forceSign=false) { @@ -75,4 +81,15 @@ class Sequence extends Expr.Expression { ).join('; ') return ret } + + toLatexString(forceSign=false) { + var str = this.latexMarkup + if(str[0] != '-' && forceSign) str = '+' + str + var subtxt = '_{n' + (this.valuePlus == 0 ? '' : '+' + this.valuePlus) + '}' + var ret = `\\begin{array}{l}${Latex.variable(this.name)}${subtxt} = ${str}${this.latexValues.length == 0 ? '' : "\n"}\\\\` + ret += Object.keys(this.latexValues).map( + n => `${this.name}_{${n}} = ${this.latexValues[n]}` + ).join('; ') + "\\end{array}" + return ret + } } diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/common.js b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/common.js index 8eb3036..3864b2f 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/common.js +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/common.js @@ -20,10 +20,16 @@ .import "../utils.js" as Utils .import "../objects.js" as Objects +.import "../math/latex.js" as Latex // This file contains the default data to be imported from all other objects - +/** + * Creates a new name for an object, based on the \c allowedLetters. + * If variables with each of the allowedLetters is created, a subscript + * number is added to the name. + * @return {string} New unused name for a new object. + */ function getNewName(allowedLetters) { // Allows to get a new name, based on the allowed letters, // as well as adding a sub number when needs be. @@ -38,33 +44,70 @@ function getNewName(allowedLetters) { return ret } +/** + * Class to extend for every type of object that + * can be drawn on the canvas. + */ class DrawableObject { - // Class to extend for every type of object that - // can be drawn on the canvas. - - // Base name of the object. Needs to be constant over time. + /** + * Base name of the object. Needs to be constant over time. + * @return {string} Type of the object. + */ static type(){return 'Unknown'} - // (Potentially translated) name of the object to be shown to the user. + /** + * Translated name of the object to be shown to the user. + * @return {string} + */ static displayType(){return 'Unknown'} - // Label used for the list on the ObjectsList sidebar. + /** + * Translated name of the object in plural form to be shown to the user. + * @return {string} + */ static displayTypeMultiple(){return 'Unknowns'} - // Whether this object can be created by the user - // or are instantiated by other objects. + /** + * True if this object can be created by the user, false if it can only + * be instantiated by other objects + * @return {bool} + */ static createable() {return true} - // Properties are set with key as property name and - // value as it's type name (e.g 'Expression', 'string'...), - // an Enum for enumerations, an ObjectType for DrawableObjects - // with a specific type, a List instance for lists, a - // Dictionary instance for dictionaries... - // Used for property modifier in the sidebar. + + /** + * List of properties used in the Object Editor. + * + * Properties are set with key as property name and + * value as it's type name (e.g 'Expression', 'string'...), + * an Enum for enumerations, an ObjectType for DrawableObjects + * with a specific type, a List instance for lists, a + * Dictionary instance for dictionaries... + * + * If the property is to be translated, the key should be passed + * through the QT_TRANSLATE_NOOP macro in that form: + * [QT_TRANSLATE_NOOP('prop','key')] + * Enums that are translated should be indexed in parameters.js and + * then be linked directly here. + * + * @return {Dictionary} + */ static properties() {return {}} - // Whether the object can be executed (instance of ExecutableObject) + /** + * True if this object can be executed, so that an y value might be computed + * for an x value. Only ExecutableObjects have that property set to true. + * @return {bool} + */ static executable() {return false} + /** + * Base constructor for the object. + * @param {string} name - Name of the object + * @param {bool} visible - true if the object is visible, false otherwise. + * @param {color} color - Color of the object (can be string or QColor) + * @param {Enum} labelContent - One of 'null', 'name' or 'name + value' describing the content of the label. + * @constructor() + */ constructor(name, visible = true, color = null, labelContent = 'name + value') { if(color == null) color = Utils.getRandomColor() this.type = 'Unknown' @@ -75,15 +118,40 @@ class DrawableObject { this.requiredBy = [] } + /** + * Serilizes the object in an array that can be JSON serialized. + * These parameters will be re-entered in the constructor when restored. + * @return {array} + */ export() { // Should return what will be inputed as arguments when a file is loaded (serializable form) return [this.name, this.visible, this.color.toString(), this.labelContent] } + /** + * String representing the object that will be displayed to the user. + * It allows for 2 lines and translated text, but it shouldn't be too long. + * @return {string} + */ getReadableString() { return `${this.name} = Unknown` } + /** + * Latex markuped version of the readable string. + * Every non latin character should be passed as latex symbols and formulas + * should be in latex form. + * See ../latex.js for helper methods. + * @return {string} + */ + getLatexString() { + return this.getReadableString() + } + + /** + * Readable string content of the label depending on the value of the \c latexContent. + * @return {string} + */ getLabel() { switch(this.labelContent) { case 'name': @@ -96,12 +164,37 @@ class DrawableObject { } } + /** + * Latex markup string content of the label depending on the value of the \c latexContent. + * Every non latin character should be passed as latex symbols and formulas + * should be in latex form. + * See ../latex.js for helper methods. + * @return {string} + */ + getLatexLabel() { + switch(this.labelContent) { + case 'name': + return Latex.variable(this.name) + case 'name + value': + return this.getLatexString() + case 'null': + return '' + + } + } + + /** + * Callback method when one of the properties of the object is updated. + */ update() { for(var req of this.requiredBy) { req.update() } } + /** + * Callback method when the object is about to get deleted. + */ delete() { for(var toRemove of this.requiredBy) { toRemove.delete() @@ -109,28 +202,166 @@ class DrawableObject { } } + /** + * Abstract method. Draw the object onto the \c canvas with the 2D context \c ctx. + * @param {Canvas} canvas + * @param {Context2D} ctx + */ draw(canvas, ctx) {} + /** + * Applicates a \c drawFunction with two position arguments depending on + * both the \c posX and \c posY of where the label should be displayed, + * and the \c labelPosition which declares the label should be displayed + * relatively to that position. + * + * @param {string|Enum} labelPosition - Position of the label relative to the marked position + * @param {number} offset - Margin between the position and the object to be drawn + * @param {Dictionary} size - Size of the label item, containing two properties, "width" and "height" + * @param {number} posX - Component of the marked position on the x-axis + * @param {number} posY - Component of the marked position on the y-axis + * @param {function} drawFunction - Function with two arguments (x, y) that will be called to draw the label + */ + drawPositionDivergence(labelPosition, offset, size, posX, posY, drawFunction) { + switch(labelPosition) { + case 'center': + drawFunction(posX-size.width/2, posY-size.height/2) + break; + case 'top': + case 'above': + drawFunction(posX-size.width/2, posY-size.height-offset) + break; + case 'bottom': + case 'below': + drawFunction(posX-size.width/2, posY+offset) + break; + case 'left': + drawFunction(posX-size.width-offset, posY-size.height/2) + break; + case 'right': + drawFunction(posX+offset, posY-size.height/2) + break; + case 'top-left': + case 'above-left': + drawFunction(posX-size.width, posY-size.height-offset) + break; + case 'top-right': + case 'above-right': + drawFunction(posX+offset, posY-size.height-offset) + break; + case 'bottom-left': + case 'below-left': + drawFunction(posX-size.width-offset, posY+offset) + break; + case 'bottom-right': + case 'below-right': + drawFunction(posX+offset, posY+offset) + break; + } + } + + /** + * Automaticly draw text (by default the label of the object on the \c canvas with + * the 2D context \c ctx depending on user settings. + * This method takes into account both the \c posX and \c posY of where the label + * should be displayed, including the \c labelPosition relative to it. + * The text is get both through the \c getLatexFunction and \c getTextFunction + * depending on whether to use latex. + * Then, it's displayed using the \c drawFunctionLatex (x,y,imageData) and + * \c drawFunctionText (x,y,text) depending on whether to use latex. + * + * @param {Canvas} canvas + * @param {Context2D} ctx + * @param {string|Enum} labelPosition - Position of the label relative to the marked position + * @param {number} posX - Component of the marked position on the x-axis + * @param {number} posY - Component of the marked position on the y-axis + * @param {bool} forceText - Force the rendering of the label as text + * @param {function|null} getLatexFunction - Function (no argument) to get the latex markup to be displayed + * @param {function|null} getTextFunction - Function (no argument) to get the text to be displayed + * @param {function|null} drawFunctionLatex - Function (x,y,imageData) to display the latex image + * @param {function|null} drawFunctionText - Function (x,y,text,textSize) to display the text + */ + drawLabel(canvas, ctx, labelPosition, posX, posY, forceText = false, + getLatexFunction = null, getTextFunction = null, drawFunctionLatex = null, drawFunctionText = null) { + // Default functions + if(getLatexFunction == null) + getLatexFunction = this.getLatexLabel.bind(this) + if(getTextFunction == null) + getTextFunction = this.getLabel.bind(this) + if(drawFunctionLatex == null) + drawFunctionLatex = (x,y,ltxImg) => canvas.drawVisibleImage(ctx, ltxImg.source, x, y, ltxImg.width, ltxImg.height) + if(drawFunctionText == null) + drawFunctionText = (x,y,text,textSize) => canvas.drawVisibleText(ctx, text, x, y+textSize.height) // Positioned from left bottom + // Drawing the label + let offset + if(!forceText && Latex.enabled) { // TODO: Check for user setting with Latex. + // With latex + let drawLblCb = function(canvas, ctx, ltxImg) { + this.drawPositionDivergence(labelPosition, 8+ctx.lineWidth/2, ltxImg, posX, posY, (x,y) => drawFunctionLatex(x,y,ltxImg)) + } + let ltxLabel = getLatexFunction(); + if(ltxLabel != "") + canvas.renderLatexImage(ltxLabel, this.color, drawLblCb.bind(this)) + } else { + // Without latex + let text = getTextFunction() + ctx.font = `${canvas.textsize}px sans-serif` + let textSize = canvas.measureText(ctx, text) + this.drawPositionDivergence(labelPosition, 8+ctx.lineWidth/2, textSize, posX, posY, (x,y) => drawFunctionText(x,y,text,textSize)) + } + } + toString() { return this.name; } } +/** + * Class to be extended for every object on which + * an y for a x can be computed with the execute function. + * If a value cannot be found during execute, it will + * return null. However, theses same x values will + * return false when passed to canExecute. + */ class ExecutableObject extends DrawableObject { - // Class to be extended for every class upon which we - // calculate an y for a x with the execute function. - // If a value cannot be found during execute, it should - // return null. However, theses values should - // return false when passed to canExecute. + /** + * Returns the corresponding y value for an x value. + * If the object isn't defined on the given x, then + * this function will return null. + * + * @param {number} x + * @returns {number|null} + */ execute(x = 1) {return 0} + /** + * Returns false if the object isn't defined on the given x, true otherwise. + * + * @param {number} x + * @returns {bool} + */ canExecute(x = 1) {return true} - // Simplify returns the simplified string of the expression. + /** + * Returns the simplified expression string for a given x. + * + * @param {number} x + * @returns {bool} + */ simplify(x = 1) {return '0'} - // Whether the object can be executed (instance of ExecutableObject) + + /** + * True if this object can be executed, so that an y value might be computed + * for an x value. Only ExecutableObjects have that property set to true. + * @return {bool} + */ static executable() {return true} } + +/** + * Registers the object \c obj in the object list. + * @param {DrawableObject} obj - Object to be registered. + */ function registerObject(obj) { // Registers an object to be used in LogarithmPlotter. // This function is called from autoload.js diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/function.js b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/function.js index 9b474a2..44dc1f4 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/function.js +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/function.js @@ -22,24 +22,13 @@ .import "../utils.js" as Utils .import "../mathlib.js" as MathLib .import "../parameters.js" as P +.import "../math/latex.js" as Latex class Function extends Common.ExecutableObject { static type(){return 'Function'} static displayType(){return qsTr('Function')} static displayTypeMultiple(){return qsTr('Functions')} - /*static properties() {return { - 'expression': 'Expression', - 'definitionDomain': 'Domain', - 'destinationDomain': 'Domain', - 'comment1': 'Ex: R+* (ℝ⁺*), N (ℕ), Z-* (ℤ⁻*), ]0;1[, {3;4;5}', - 'labelPosition': P.Enum.Position, - 'displayMode': new P.Enum('application', 'function'), - 'labelX': 'number', - 'comment2': 'The following parameters are used when the definition domain is a non-continuous set. (Ex: ℕ, ℤ, sets like {0;3}...)', - 'drawPoints': 'boolean', - 'drawDashedLines': 'boolean' - }}*/ static properties() {return { [QT_TRANSLATE_NOOP('prop','expression')]: 'Expression', [QT_TRANSLATE_NOOP('prop','definitionDomain')]: 'Domain', @@ -87,6 +76,15 @@ class Function extends Common.ExecutableObject { } } + getLatexString() { + if(this.displayMode == 'application') { + return `${Latex.variable(this.name)}:\\begin{array}{llll}${this.definitionDomain.latexMarkup}\\textrm{ } & \\rightarrow & \\textrm{ }${this.destinationDomain.latexMarkup}\\\\ + x\\textrm{ } & \\mapsto & \\textrm{ }${this.expression.latexMarkup}\\end{array}` + } else { + return `\\begin{array}{l}${Latex.variable(this.name)}(x) = ${this.expression.latexMarkup}\\\\ D_{${this.name}} = ${this.definitionDomain.latexMarkup}\\end{array}` + } + } + export() { return [this.name, this.visible, this.color.toString(), this.labelContent, this.expression.toEditableString(), this.definitionDomain.toString(), this.destinationDomain.toString(), @@ -112,43 +110,13 @@ class Function extends Common.ExecutableObject { draw(canvas, ctx) { Function.drawFunction(canvas, ctx, this.expression, this.definitionDomain, this.destinationDomain, this.drawPoints, this.drawDashedLines) // Label - var text = this.getLabel() - ctx.font = `${canvas.textsize}px sans-serif` - var textSize = canvas.measureText(ctx, text) - var posX = canvas.x2px(this.labelX) - var posY = canvas.y2px(this.execute(this.labelX)) - switch(this.labelPosition) { - case 'above': - canvas.drawVisibleText(ctx, text, posX-textSize.width/2, posY-textSize.height) - break; - case 'below': - canvas.drawVisibleText(ctx, text, posX-textSize.width/2, posY+textSize.height) - break; - case 'left': - canvas.drawVisibleText(ctx, text, posX-textSize.width, posY-textSize.height/2) - break; - case 'right': - canvas.drawVisibleText(ctx, text, posX, posY-textSize.height/2) - break; - case 'above-left': - canvas.drawVisibleText(ctx, text, posX-textSize.width, posY-textSize.height) - break; - case 'above-right': - canvas.drawVisibleText(ctx, text, posX, posY-textSize.height) - break; - case 'below-left': - canvas.drawVisibleText(ctx, text, posX-textSize.width, posY+textSize.height) - break; - case 'below-right': - canvas.drawVisibleText(ctx, text, posX, posY+textSize.height) - break; - } + this.drawLabel(canvas, ctx, this.labelPosition, canvas.x2px(this.labelX), canvas.y2px(this.execute(this.labelX))) } static drawFunction(canvas, ctx, expr, definitionDomain, destinationDomain, drawPoints = true, drawDash = true) { // Reusable in other objects. - // Drawing small traits every 2px - var pxprecision = 0.2 + // Drawing small traits every 0.2px + var pxprecision = 1 var previousX = canvas.px2x(0) var previousY; if(definitionDomain instanceof MathLib.SpecialDomain && definitionDomain.moveSupported) { diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/gainbode.js b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/gainbode.js index 8d0543c..ff8236c 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/gainbode.js +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/gainbode.js @@ -25,19 +25,13 @@ .import "../mathlib.js" as MathLib .import "../historylib.js" as HistoryLib .import "../parameters.js" as P +.import "../math/latex.js" as Latex + class GainBode extends Common.ExecutableObject { static type(){return 'Gain Bode'} static displayType(){return qsTr('Bode Magnitude')} static displayTypeMultiple(){return qsTr('Bode Magnitudes')} - /*static properties() {return { - 'om_0': new P.ObjectType('Point'), - 'pass': new P.Enum('high', 'low'), - 'gain': 'Expression', - 'labelPosition': new P.Enum('above', 'below', 'left', 'right', 'above-left', 'above-right', 'below-left', 'below-right'), - 'labelX': 'number', - 'omGraduation': 'boolean' - }}*/ static properties() {return { [QT_TRANSLATE_NOOP('prop','om_0')]: new P.ObjectType('Point'), [QT_TRANSLATE_NOOP('prop','pass')]: P.Enum.BodePass, @@ -81,6 +75,14 @@ class GainBode extends Common.ExecutableObject { return `${this.name}: ${pass}; ${this.om_0.name} = ${this.om_0.x}\n ${' '.repeat(this.name.length)}${this.gain.toString(true)} dB/dec` } + getLatexString() { + let pass = this.pass == "low" ? qsTr("low-pass") : qsTr("high-pass"); + return `\\mathrm{${Latex.variable(this.name)}:}\\begin{array}{l} + \\textsf{${pass}};${Latex.variable(this.om_0.name)} = ${this.om_0.x.latexMarkup} \\\\ + ${this.gain.latexMarkup}\\textsf{ dB/dec} + \\end{array}` + } + export() { return [this.name, this.visible, this.color.toString(), this.labelContent, this.om_0.name, this.pass.toString(), this.gain.toEditableString(), this.labelPosition, this.labelX, this.omGraduation] @@ -131,38 +133,9 @@ class GainBode extends Common.ExecutableObject { var dashPxSize = 10 for(var i = 0; i < canvas.canvasSize.height && this.omGraduation; i += dashPxSize*2) canvas.drawLine(ctx, xpos, i, xpos, i+dashPxSize) + // Label - var text = this.getLabel() - ctx.font = `${canvas.textsize}px sans-serif` - var textSize = canvas.measureText(ctx, text) - var posX = canvas.x2px(this.labelX) - var posY = canvas.y2px(this.execute(this.labelX)) - switch(this.labelPosition) { - case 'above': - canvas.drawVisibleText(ctx, text, posX-textSize.width/2, posY-textSize.height) - break; - case 'below': - canvas.drawVisibleText(ctx, text, posX-textSize.width/2, posY+textSize.height) - break; - case 'left': - canvas.drawVisibleText(ctx, text, posX-textSize.width, posY-textSize.height/2) - break; - case 'right': - canvas.drawVisibleText(ctx, text, posX, posY-textSize.height/2) - break; - case 'above-left': - canvas.drawVisibleText(ctx, text, posX-textSize.width, posY-textSize.height) - break; - case 'above-right': - canvas.drawVisibleText(ctx, text, posX, posY-textSize.height) - break; - case 'below-left': - canvas.drawVisibleText(ctx, text, posX-textSize.width, posY+textSize.height) - break; - case 'below-right': - canvas.drawVisibleText(ctx, text, posX, posY+textSize.height) - break; - } + this.drawLabel(canvas, ctx, this.labelPosition, canvas.x2px(this.labelX), canvas.y2px(this.execute(this.labelX))) } update() { diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/phasebode.js b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/phasebode.js index fa75ec5..e3d7be0 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/phasebode.js +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/phasebode.js @@ -23,19 +23,13 @@ .import "../mathlib.js" as MathLib .import "../historylib.js" as HistoryLib .import "../parameters.js" as P +.import "../math/latex.js" as Latex class PhaseBode extends Common.ExecutableObject { static type(){return 'Phase Bode'} static displayType(){return qsTr('Bode Phase')} static displayTypeMultiple(){return qsTr('Bode Phases')} - /*static properties() {return { - 'om_0': new P.ObjectType('Point'), - 'phase': 'Expression', - 'unit': new P.Enum('°', 'deg', 'rad'), - 'labelPosition': new P.Enum('above', 'below', 'left', 'right', 'above-left', 'above-right', 'below-left', 'below-right'), - 'labelX': 'number' - }}*/ static properties() {return { [QT_TRANSLATE_NOOP('prop','om_0')]: new P.ObjectType('Point'), [QT_TRANSLATE_NOOP('prop','phase')]: 'Expression', @@ -61,7 +55,7 @@ class PhaseBode extends Common.ExecutableObject { om_0.name = Common.getNewName('ω') om_0.color = this.color om_0.labelContent = 'name' - om_0.labelPosition = this.phase.execute() >= 0 ? 'bottom' : 'top' + om_0.labelPosition = this.phase.execute() >= 0 ? 'above' : 'below' HistoryLib.history.addToHistory(new HistoryLib.CreateNewObject(om_0.name, 'Point', om_0.export())) labelPosition = 'below' } @@ -82,6 +76,10 @@ class PhaseBode extends Common.ExecutableObject { return `${this.name}: ${this.phase.toString(true)}${this.unit} at ${this.om_0.name} = ${this.om_0.x}` } + getLatexString() { + return `${Latex.variable(this.name)}: ${this.phase.latexMarkup}\\textsf{${this.unit} at }${Latex.variable(this.om_0.name)} = ${this.om_0.x.latexMarkup}` + } + execute(x=1) { if(typeof x == 'string') x = MathLib.executeExpression(x) if(x < this.om_0.x) { @@ -120,37 +118,7 @@ class PhaseBode extends Common.ExecutableObject { canvas.drawLine(ctx, Math.max(0, baseX), augmtY, canvas.canvasSize.width, augmtY) // Label - var text = this.getLabel() - ctx.font = `${canvas.textsize}px sans-serif` - var textSize = canvas.measureText(ctx, text) - var posX = canvas.x2px(this.labelX) - var posY = canvas.y2px(this.execute(this.labelX)) - switch(this.labelPosition) { - case 'above': - canvas.drawVisibleText(ctx, text, posX-textSize.width/2, posY-textSize.height) - break; - case 'below': - canvas.drawVisibleText(ctx, text, posX-textSize.width/2, posY+textSize.height) - break; - case 'left': - canvas.drawVisibleText(ctx, text, posX-textSize.width, posY-textSize.height/2) - break; - case 'right': - canvas.drawVisibleText(ctx, text, posX, posY-textSize.height/2) - break; - case 'above-left': - canvas.drawVisibleText(ctx, text, posX-textSize.width, posY-textSize.height) - break; - case 'above-right': - canvas.drawVisibleText(ctx, text, posX, posY-textSize.height) - break; - case 'below-left': - canvas.drawVisibleText(ctx, text, posX-textSize.width, posY+textSize.height) - break; - case 'below-right': - canvas.drawVisibleText(ctx, text, posX, posY+textSize.height) - break; - } + this.drawLabel(canvas, ctx, this.labelPosition, canvas.x2px(this.labelX), canvas.y2px(this.execute(this.labelX))) } update() { diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/point.js b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/point.js index e0b9c58..66ba301 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/point.js +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/point.js @@ -21,6 +21,7 @@ .import "common.js" as Common .import "../mathlib.js" as MathLib .import "../parameters.js" as P +.import "../math/latex.js" as Latex class Point extends Common.DrawableObject { @@ -28,12 +29,6 @@ class Point extends Common.DrawableObject { static displayType(){return qsTr('Point')} static displayTypeMultiple(){return qsTr('Points')} - /*static properties() {return { - 'x': 'Expression', - 'y': 'Expression', - 'labelPosition': new P.Enum('above', 'below', 'left', 'right', 'above-left', 'above-right', 'below-left', 'below-right'), - 'pointStyle': new P.Enum('●', '✕', '+'), - }}*/ static properties() {return { [QT_TRANSLATE_NOOP('prop','x')]: 'Expression', [QT_TRANSLATE_NOOP('prop','y')]: 'Expression', @@ -58,6 +53,10 @@ class Point extends Common.DrawableObject { return `${this.name} = (${this.x}, ${this.y})` } + getLatexString() { + return `${Latex.variable(this.name)} = \\left(${this.x.latexMarkup}, ${this.y.latexMarkup}\\right)` + } + export() { return [this.name, this.visible, this.color.toString(), this.labelContent, this.x.toEditableString(), this.y.toEditableString(), this.labelPosition, this.pointStyle] } @@ -80,41 +79,6 @@ class Point extends Common.DrawableObject { ctx.fillRect(canvasX-1, canvasY-pointSize/2, 2, pointSize) break; } - var text = this.getLabel() - ctx.font = `${canvas.textsize}px sans-serif` - var textSize = ctx.measureText(text).width - switch(this.labelPosition) { - case 'top': - case 'above': - canvas.drawVisibleText(ctx, text, canvasX-textSize/2, canvasY-16) - break; - case 'bottom': - case 'below': - canvas.drawVisibleText(ctx, text, canvasX-textSize/2, canvasY+16) - break; - case 'left': - canvas.drawVisibleText(ctx, text, canvasX-textSize-10, canvasY+4) - break; - case 'right': - canvas.drawVisibleText(ctx, text, canvasX+10, canvasY+4) - break; - case 'top-left': - case 'above-left': - canvas.drawVisibleText(ctx, text, canvasX-textSize-10, canvasY-16) - break; - case 'top-right': - case 'above-right': - canvas.drawVisibleText(ctx, text, canvasX+10, canvasY-16) - break; - case 'bottom-left': - case 'below-left': - canvas.drawVisibleText(ctx, text, canvasX-textSize-10, canvasY+16) - break; - case 'bottom-right': - case 'below-right': - canvas.drawVisibleText(ctx, text, canvasX+10, canvasY+16) - break; - - } + this.drawLabel(canvas, ctx, this.labelPosition, canvasX, canvasY) } } diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/repartition.js b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/repartition.js index 341a2a8..da8c4e1 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/repartition.js +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/repartition.js @@ -20,6 +20,8 @@ .import "common.js" as Common .import "../parameters.js" as P +.import "../math/latex.js" as Latex + class RepartitionFunction extends Common.ExecutableObject { static type(){return 'Repartition'} @@ -66,6 +68,12 @@ class RepartitionFunction extends Common.ExecutableObject { return `F_${this.name}(x) = P(${this.name} ≤ x)\n` + keys.map(idx => `P(${this.name}=${idx})=${this.probabilities[idx]}`).join("; ") } + getLatexString() { + let keys = Object.keys(this.probabilities).sort((a,b) => a-b); + let varName = Latex.variable(this.name) + return `\\begin{array}{l}F_{${varName}}(x) = P(${varName} \\le x)\\\\` + keys.map(idx => `P(${varName}=${idx})=${this.probabilities[idx]}`).join("; ") + '\\end{array}' + } + execute(x = 1) { var ret = 0; Object.keys(this.probabilities).sort((a,b) => a-b).forEach(idx => { @@ -145,37 +153,7 @@ class RepartitionFunction extends Common.ExecutableObject { } // Label - var text = this.getLabel() - ctx.font = `${canvas.textsize}px sans-serif` - var textSize = canvas.measureText(ctx, text) - var posX = canvas.x2px(this.labelX) - var posY = canvas.y2px(this.execute(this.labelX)) - switch(this.labelPosition) { - case 'above': - canvas.drawVisibleText(ctx, text, posX-textSize.width/2, posY-textSize.height) - break; - case 'below': - canvas.drawVisibleText(ctx, text, posX-textSize.width/2, posY+textSize.height) - break; - case 'left': - canvas.drawVisibleText(ctx, text, posX-textSize.width, posY-textSize.height/2) - break; - case 'right': - canvas.drawVisibleText(ctx, text, posX, posY-textSize.height/2) - break; - case 'above-left': - canvas.drawVisibleText(ctx, text, posX-textSize.width, posY-textSize.height) - break; - case 'above-right': - canvas.drawVisibleText(ctx, text, posX, posY-textSize.height) - break; - case 'below-left': - canvas.drawVisibleText(ctx, text, posX-textSize.width, posY+textSize.height) - break; - case 'below-right': - canvas.drawVisibleText(ctx, text, posX, posY+textSize.height) - break; - } + this.drawLabel(canvas, ctx, this.labelPosition, canvas.x2px(this.labelX), canvas.y2px(this.execute(this.labelX))) } } diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/sequence.js b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/sequence.js index 0e8989c..484b7a4 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/sequence.js +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/sequence.js @@ -22,6 +22,7 @@ .import "function.js" as F .import "../mathlib.js" as MathLib .import "../parameters.js" as P +.import "../math/latex.js" as Latex class Sequence extends Common.ExecutableObject { @@ -76,11 +77,14 @@ class Sequence extends Common.ExecutableObject { ) } - getReadableString() { return this.sequence.toString() } + getLatexString() { + return this.sequence.toLatexString() + } + execute(x = 1) { if(x % 1 == 0) return this.sequence.execute(x) @@ -103,7 +107,17 @@ class Sequence extends Common.ExecutableObject { return this.getReadableString() case 'null': return '' - + } + } + + getLatexLabel() { + switch(this.labelContent) { + case 'name': + return `(${Latex.variable(this.name)}_n)` + case 'name + value': + return this.getLatexString() + case 'null': + return '' } } @@ -111,37 +125,7 @@ class Sequence extends Common.ExecutableObject { F.Function.drawFunction(canvas, ctx, this.sequence, canvas.logscalex ? MathLib.Domain.NE : MathLib.Domain.N, MathLib.Domain.R, this.drawPoints, this.drawDashedLines) // Label - var text = this.getLabel() - ctx.font = `${canvas.textsize}px sans-serif` - var textSize = canvas.measureText(ctx, text) - var posX = canvas.x2px(this.labelX) - var posY = canvas.y2px(this.execute(this.labelX)) - switch(this.labelPosition) { - case 'above': - canvas.drawVisibleText(ctx, text, posX-textSize.width/2, posY-textSize.height) - break; - case 'below': - canvas.drawVisibleText(ctx, text, posX-textSize.width/2, posY+textSize.height) - break; - case 'left': - canvas.drawVisibleText(ctx, text, posX-textSize.width, posY-textSize.height/2) - break; - case 'right': - canvas.drawVisibleText(ctx, text, posX, posY-textSize.height/2) - break; - case 'above-left': - canvas.drawVisibleText(ctx, text, posX-textSize.width, posY-textSize.height) - break; - case 'above-right': - canvas.drawVisibleText(ctx, text, posX, posY-textSize.height) - break; - case 'below-left': - canvas.drawVisibleText(ctx, text, posX-textSize.width, posY+textSize.height) - break; - case 'below-right': - canvas.drawVisibleText(ctx, text, posX, posY+textSize.height) - break; - } + this.drawLabel(canvas, ctx, this.labelPosition, canvas.x2px(this.labelX), canvas.y2px(this.execute(this.labelX))) } } diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/sommegainsbode.js b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/sommegainsbode.js index 20c17ba..8f5854c 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/sommegainsbode.js +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/sommegainsbode.js @@ -23,6 +23,7 @@ .import "../objects.js" as Objects .import "../mathlib.js" as MathLib .import "../parameters.js" as P +.import "../math/latex.js" as Latex class SommeGainsBode extends Common.DrawableObject { @@ -30,10 +31,6 @@ class SommeGainsBode extends Common.DrawableObject { static displayType(){return qsTr('Bode Magnitudes Sum')} static displayTypeMultiple(){return qsTr('Bode Magnitudes Sum')} static createable() {return false} - /*static properties() {return { - 'labelPosition': new P.Enum('above', 'below', 'left', 'right', 'above-left', 'above-right', 'below-left', 'below-right'), - 'labelX': 'number' - }}*/ static properties() {return { [QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Position, [QT_TRANSLATE_NOOP('prop','labelX')]: 'number', @@ -56,6 +53,10 @@ class SommeGainsBode extends Common.DrawableObject { return `${this.name} = ${Objects.getObjectsName('Gain Bode').join(' + ')}` } + getLatexString() { + return `${Latex.variable(this.name)} = ${Objects.getObjectsName('Gain Bode').map(Latex.variable).join(' + ')}` + } + execute(x = 0) { for(var [dbfn, inDrawDom] of this.cachedParts) { if(inDrawDom.includes(x)) { @@ -136,37 +137,7 @@ class SommeGainsBode extends Common.DrawableObject { F.Function.drawFunction(canvas, ctx, dbfn, inDrawDom, MathLib.Domain.R) if(inDrawDom.includes(this.labelX)) { // Label - var text = this.getLabel() - ctx.font = `${canvas.textsize}px sans-serif` - var textSize = canvas.measureText(ctx, text) - var posX = canvas.x2px(this.labelX) - var posY = canvas.y2px(dbfn.execute(this.labelX)) - switch(this.labelPosition) { - case 'above': - canvas.drawVisibleText(ctx, text, posX-textSize.width/2, posY-textSize.height) - break; - case 'below': - canvas.drawVisibleText(ctx, text, posX-textSize.width/2, posY+textSize.height) - break; - case 'left': - canvas.drawVisibleText(ctx, text, posX-textSize.width, posY-textSize.height/2) - break; - case 'right': - canvas.drawVisibleText(ctx, text, posX, posY-textSize.height/2) - break; - case 'above-left': - canvas.drawVisibleText(ctx, text, posX-textSize.width, posY-textSize.height) - break; - case 'above-right': - canvas.drawVisibleText(ctx, text, posX, posY-textSize.height) - break; - case 'below-left': - canvas.drawVisibleText(ctx, text, posX-textSize.width, posY+textSize.height) - break; - case 'below-right': - canvas.drawVisibleText(ctx, text, posX, posY+textSize.height) - break; - } + this.drawLabel(canvas, ctx, this.labelPosition, canvas.x2px(this.labelX), canvas.y2px(this.execute(this.labelX))) } } } diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/sommephasesbode.js b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/sommephasesbode.js index 98a5fcc..bfa6c4b 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/sommephasesbode.js +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/sommephasesbode.js @@ -22,6 +22,7 @@ .import "../objects.js" as Objects .import "../mathlib.js" as MathLib .import "../parameters.js" as P +.import "../math/latex.js" as Latex class SommePhasesBode extends Common.ExecutableObject { @@ -55,6 +56,10 @@ class SommePhasesBode extends Common.ExecutableObject { return `${this.name} = ${Objects.getObjectsName('Phase Bode').join(' + ')}` } + getLatexString() { + return `${Latex.variable(this.name)} = ${Objects.getObjectsName('Phase Bode').map(Latex.variable).join(' + ')}` + } + execute(x=1) { if(typeof x == 'string') x = MathLib.executeExpression(x) for(var i = 0; i < this.om0xList.length-1; i++) { @@ -122,37 +127,7 @@ class SommePhasesBode extends Common.ExecutableObject { } // Label - var text = this.getLabel() - ctx.font = `${canvas.textsize}px sans-serif` - var textSize = canvas.measureText(ctx, text) - var posX = canvas.x2px(this.labelX) - var posY = canvas.y2px(this.execute(this.labelX)) - switch(this.labelPosition) { - case 'above': - canvas.drawVisibleText(ctx, text, posX-textSize.width/2, posY-textSize.height) - break; - case 'below': - canvas.drawVisibleText(ctx, text, posX-textSize.width/2, posY+textSize.height) - break; - case 'left': - canvas.drawVisibleText(ctx, text, posX-textSize.width, posY-textSize.height/2) - break; - case 'right': - canvas.drawVisibleText(ctx, text, posX, posY-textSize.height/2) - break; - case 'above-left': - canvas.drawVisibleText(ctx, text, posX-textSize.width, posY-textSize.height) - break; - case 'above-right': - canvas.drawVisibleText(ctx, text, posX, posY-textSize.height) - break; - case 'below-left': - canvas.drawVisibleText(ctx, text, posX-textSize.width, posY+textSize.height) - break; - case 'below-right': - canvas.drawVisibleText(ctx, text, posX, posY+textSize.height) - break; - } + this.drawLabel(canvas, ctx, this.labelPosition, canvas.x2px(this.labelX), canvas.y2px(this.execute(this.labelX))) } } diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/text.js b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/text.js index 92d27f5..a46e840 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/text.js +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/text.js @@ -21,6 +21,8 @@ .import "common.js" as Common .import "../mathlib.js" as MathLib .import "../parameters.js" as P +.import "../math/latex.js" as Latex + class Text extends Common.DrawableObject { @@ -37,11 +39,16 @@ class Text extends Common.DrawableObject { [QT_TRANSLATE_NOOP('prop','x')]: 'Expression', [QT_TRANSLATE_NOOP('prop','y')]: 'Expression', [QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Positioning, - [QT_TRANSLATE_NOOP('prop','text')]: 'string' + [QT_TRANSLATE_NOOP('prop','text')]: 'string', + 'comment1': QT_TRANSLATE_NOOP( + 'comment', + 'If you have latex enabled, you can use use latex markup in between $$ to create equations.' + ), + [QT_TRANSLATE_NOOP('prop','disableLatex')]: 'boolean' }} constructor(name = null, visible = true, color = null, labelContent = 'null', - x = 1, y = 0, labelPosition = 'center', text = 'New text') { + x = 1, y = 0, labelPosition = 'center', text = 'New text', disableLatex = false) { if(name == null) name = Common.getNewName('t') super(name, visible, color, labelContent) this.type = 'Point' @@ -51,50 +58,45 @@ class Text extends Common.DrawableObject { this.y = y this.labelPosition = labelPosition this.text = text + this.disableLatex = disableLatex } getReadableString() { return `${this.name} = "${this.text}"` } + latexMarkupText() { + let txt = Latex.variable(this.text) + let i + for(i = 0; txt.includes('$$'); i++) + if(i & 0x01) // Every odd number + txt = txt.replace('$$', '\\textsf{') + else + txt = txt.replace('$$', '}') + if(i & 0x01) // Finished by a } + txt += "{" + return txt + } + + getLatexString() { + return `${Latex.variable(this.name)} = "\\textsf{${this.latexMarkupText()}}"` + } + export() { return [this.name, this.visible, this.color.toString(), this.labelContent, this.x.toEditableString(), this.y.toEditableString(), this.labelPosition, this.text] } + getLabel() { + return this.text + } + + getLatexLabel() { + return `\\textsf{${this.latexMarkupText()}}` + } + draw(canvas, ctx) { - var [canvasX, canvasY] = [canvas.x2px(this.x.execute()), canvas.y2px(this.y.execute())] - ctx.font = `${canvas.textsize}px sans-serif` - var textSize = ctx.measureText(this.text).width - switch(this.labelPosition) { - case 'center': - canvas.drawVisibleText(ctx, this.text, canvasX-textSize/2, canvasY+4) - break; - case 'top': - canvas.drawVisibleText(ctx, this.text, canvasX-textSize/2, canvasY-16) - break; - case 'bottom': - canvas.drawVisibleText(ctx, this.text, canvasX-textSize/2, canvasY+16) - break; - case 'left': - canvas.drawVisibleText(ctx, this.text, canvasX-textSize-5, canvasY+4) - break; - case 'right': - canvas.drawVisibleText(ctx, this.text, canvasX+5, canvasY+4) - break; - case 'top-left': - canvas.drawVisibleText(ctx, this.text, canvasX-textSize-5, canvasY-16) - break; - case 'top-right': - canvas.drawVisibleText(ctx, this.text, canvasX+5, canvasY-16) - break; - case 'bottom-left': - canvas.drawVisibleText(ctx, this.text, canvasX-textSize-5, canvasY+16) - break; - case 'bottom-right': - canvas.drawVisibleText(ctx, this.text, canvasX+5, canvasY+16) - break; - - } + let yOffset = this.disableLatex ? canvas.textsize-4 : 0 + this.drawLabel(canvas, ctx, this.labelPosition, canvas.x2px(this.x.execute()), canvas.y2px(this.y.execute())+yOffset, this.disableLatex) } } diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/xcursor.js b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/xcursor.js index e81c1a3..52c989f 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/xcursor.js +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/xcursor.js @@ -22,27 +22,14 @@ .import "../objects.js" as Objects .import "../mathlib.js" as MathLib .import "../parameters.js" as P +.import "../math/latex.js" as Latex + class XCursor extends Common.DrawableObject { static type(){return 'X Cursor'} static displayType(){return qsTr('X Cursor')} static displayTypeMultiple(){return qsTr('X Cursors')} - /*static properties() { - return { - 'x': 'Expression', - 'targetElement': new P.ObjectType('ExecutableObject'), - 'labelPosition': new P.Enum('left', 'right'), - 'approximate': 'boolean', - 'rounding': 'number', - 'displayStyle': new P.Enum( - '— — — — — — —', - '⸺⸺⸺⸺⸺⸺', - '• • • • • • • • • •' - ), - 'targetValuePosition' : new P.Enum('Next to target', 'With label', 'Hidden') - } - }*/ static properties() {return { [QT_TRANSLATE_NOOP('prop','x')]: 'Expression', [QT_TRANSLATE_NOOP('prop','targetElement')]: new P.ObjectType('ExecutableObject'), @@ -87,6 +74,13 @@ class XCursor extends Common.DrawableObject { return `${this.name} = ${this.x.toString()}\n${this.getTargetValueLabel()}` } + getLatexString() { + if(this.targetElement == null) return `${Latex.variable(this.name)} = ${this.x.latexMarkup}` + return `\\begin{array}{l} + ${Latex.variable(this.name)} = ${this.x.latexMarkup} \\\\ + ${this.getTargetValueLatexLabel()}` + } + getTargetValueLabel() { var t = this.targetElement var approx = '' @@ -98,6 +92,18 @@ class XCursor extends Common.DrawableObject { (this.approximate ? ' ≈ ' + approx : '') } + getTargetValueLatexLabel() { + var t = this.targetElement + var approx = '' + if(this.approximate) { + approx = t.execute(this.x.execute()) + approx = approx.toPrecision(this.rounding + Math.round(approx).toString().length) + } + let simpl = t.simplify(this.x.toEditableString()) + return `${Latex.variable(t.name)}(${Latex.variable(this.name)}) = ${simpl.tokens ? Latex.expression(simpl.tokens) : simpl}` + + (this.approximate ? ' \\simeq ' + approx : '') + } + getLabel() { switch(this.labelContent) { case 'name': @@ -118,8 +124,28 @@ class XCursor extends Common.DrawableObject { } } + getLatexLabel() { + switch(this.labelContent) { + case 'name': + return Latex.variable(this.name) + break; + case 'name + value': + switch(this.targetValuePosition) { + case 'Next to target': + case 'Hidden': + return `${Latex.variable(this.name)} = ${this.x.latexMarkup}` + break; + case 'With label': + return this.getLatexString() + break; + } + case 'null': + return '' + } + } + draw(canvas, ctx) { - var xpos = canvas.x2px(this.x.execute()) + let xpos = canvas.x2px(this.x.execute()) switch(this.displayStyle) { case '— — — — — — —': var dashPxSize = 10 @@ -139,52 +165,18 @@ class XCursor extends Common.DrawableObject { break; } - // Label - var text = this.getLabel() - ctx.font = `${canvas.textsize}px sans-serif` - var textSize = canvas.measureText(ctx, text) - - switch(this.labelPosition) { - case 'left': - case 'above-left': - case 'below-left': - case 'below': - case 'above': - canvas.drawVisibleText(ctx, text, xpos-textSize.width-5, textSize.height+5) - break; - case 'right': - case 'above-right': - case 'below-right': - canvas.drawVisibleText(ctx, text, xpos+5, textSize.height+5) - break; - } + // Drawing label at the top of the canvas. + this.drawLabel(canvas, ctx, this.labelPosition, xpos, 0, false, null, null, + (x,y,ltxImg) => canvas.drawVisibleImage(ctx, ltxImg.source, x, 5, ltxImg.width, ltxImg.height), + (x,y,text,textSize) => canvas.drawVisibleText(ctx, text, x, textSize.height+5)) + // Drawing label at the position of the target element. if(this.targetValuePosition == 'Next to target' && this.targetElement != null) { - var text = this.getTargetValueLabel() - var textSize = canvas.measureText(ctx, text) - var ypox = canvas.y2px(this.targetElement.execute(this.x.execute())) - switch(this.labelPosition) { - case 'left': - case 'below': - case 'above': - canvas.drawVisibleText(ctx, text, xpos-textSize.width-5, ypox+textSize.height) - break; - case 'above-left': - canvas.drawVisibleText(ctx, text, xpos-textSize.width-5, ypox+textSize.height+12) - break; - case 'below-left': - canvas.drawVisibleText(ctx, text, xpos-textSize.width-5, ypox+textSize.height-12) - break; - case 'right': - canvas.drawVisibleText(ctx, text, xpos+5, ypox+textSize.height) - break; - case 'above-right': - canvas.drawVisibleText(ctx, text, xpos+5, ypox+textSize.height+12) - break; - case 'below-right': - canvas.drawVisibleText(ctx, text, xpos+5, ypox+textSize.height-12) - break; - } + let ypos = canvas.y2px(this.targetElement.execute(this.x.execute())) + this.drawLabel(canvas, ctx, this.labelPosition, xpos, ypos, false, + this.getTargetValueLatexLabel.bind(this), this.getTargetValueLabel.bind(this), + (x,y,ltxImg) => canvas.drawVisibleImage(ctx, ltxImg.source, x, y, ltxImg.width, ltxImg.height), + (x,y,text,textSize) => canvas.drawVisibleText(ctx, text, x, y+textSize.height)) } } } diff --git a/LogarithmPlotter/util/config.py b/LogarithmPlotter/util/config.py index ce59163..ecaa214 100644 --- a/LogarithmPlotter/util/config.py +++ b/LogarithmPlotter/util/config.py @@ -26,6 +26,7 @@ DEFAULT_SETTINGS = { "check_for_updates": True, "reset_redo_stack": True, "last_install_greet": "0", + "enable_latex": True } # Create config directory diff --git a/LogarithmPlotter/util/latex.py b/LogarithmPlotter/util/latex.py new file mode 100644 index 0000000..0ce5b91 --- /dev/null +++ b/LogarithmPlotter/util/latex.py @@ -0,0 +1,192 @@ +""" + * LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions. + * Copyright (C) 2022 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 . +""" + +from PySide2.QtCore import QObject, Slot, Property, QCoreApplication +from PySide2.QtGui import QImage, QColor +from PySide2.QtWidgets import QApplication, QMessageBox + +from os import path, remove +from string import Template +from tempfile import TemporaryDirectory +from subprocess import Popen, TimeoutExpired, PIPE +from platform import system +from shutil import which +from sys import argv + +""" +Searches for a valid Latex and DVIPNG (http://savannah.nongnu.org/projects/dvipng/) +installation and collects the binary path in the DVIPNG_PATH variable. +If not found, it will send an alert to the user. +""" +LATEX_PATH = which('latex') +DVIPNG_PATH = which('dvipng') +#subprocess.run(["ls", "-l", "/dev/null"], capture_output=True) + +DEFAULT_LATEX_DOC = Template(r""" +\documentclass[]{minimal} +\usepackage[utf8]{inputenc} +\usepackage{calligra} +\usepackage{amsfonts} + +\title{} +\author{} + +\begin{document} + +$$$$ $markup $$$$ + +\end{document} +""") + +class Latex(QObject): + """ + Base class to convert Latex equations into PNG images with custom font color and size. + It doesn't have any python dependency, but requires a working latex installation and + dvipng to be installed on the system. + """ + def __init__(self, tempdir: TemporaryDirectory): + QObject.__init__(self) + self.tempdir = tempdir + + def check_latex_install(self): + """ + Checks if the current latex installation is valid. + """ + if LATEX_PATH is None: + print("No Latex installation found.") + if "--test-build" not in argv: + QMessageBox.warning(None, "LogarithmPlotter - Latex setup", QCoreApplication.translate("latex", "No Latex installation found.\nIf you already have a latex distribution installed, make sure it's installed on your path.\nOtherwise, you can download a Latex distribution like TeX Live at https://tug.org/texlive/.")) + elif DVIPNG_PATH is None: + print("DVIPNG not found.") + if "--test-build" not in argv: + QMessageBox.warning(None, "LogarithmPlotter - Latex setup", QCoreApplication.translate("latex", "DVIPNG was not found. Make sure you include it from your Latex distribution.")) + + @Property(bool) + def latexSupported(self): + return LATEX_PATH is not None and DVIPNG_PATH is not None + + @Slot(str, float, QColor, result=str) + def render(self, latex_markup: str, font_size: float, color: QColor = True) -> str: + """ + Renders a latex string into a png file. + """ + markup_hash = hash(latex_markup) + export_path = path.join(self.tempdir.name, f'{markup_hash}_{font_size}_{color.rgb()}') + if self.latexSupported and not path.exists(export_path + ".png"): + print("Rendering", latex_markup, export_path) + # Generating file + try: + latex_path = path.join(self.tempdir.name, str(markup_hash)) + # If the formula is just recolored or the font is just changed, no need to recreate the DVI. + if not path.exists(latex_path + ".dvi"): + self.create_latex_doc(latex_path, latex_markup) + self.convert_latex_to_dvi(latex_path) + self.cleanup(latex_path) + self.convert_dvi_to_png(latex_path, export_path, font_size, color) + except Exception as e: # One of the processes failed. A message will be sent every time. + raise e + img = QImage(export_path + ".png"); + # Small hack, not very optimized since we load the image twice, but you can't pass a QImage to QML and expect it to be loaded + return f'{export_path}.png,{img.width()},{img.height()}' + + def create_latex_doc(self, export_path: str, latex_markup: str): + """ + Creates a temporary latex document with base file_hash as file name and a given expression markup latex_markup. + """ + ltx_path = export_path + ".tex" + f = open(export_path + ".tex", 'w') + f.write(DEFAULT_LATEX_DOC.substitute(markup = latex_markup)) + f.close() + + def convert_latex_to_dvi(self, export_path: str): + """ + Converts a DVI file to a PNG file. + """ + self.run([ + LATEX_PATH, + export_path + ".tex" + ]) + + + def convert_dvi_to_png(self, dvi_path: str, export_path: str, font_size: float, color: QColor): + """ + Converts a DVI file to a PNG file. + Documentation: https://linux.die.net/man/1/dvipng + """ + fg = color.convertTo(QColor.Rgb) + fg = f'rgb {fg.redF()} {fg.greenF()} {fg.blueF()}' + depth = int(font_size * 72.27 / 100) * 10 + self.run([ + DVIPNG_PATH, + '-T', 'tight', # Make sure image borders are as tight around the equation as possible to avoid blank space. + '--truecolor', # Make sure it's rendered in 24 bit colors. + '-D',f'{depth}', # Depth of the image + '-bg', 'Transparent', # Transparent background + '-fg',f'{fg}', # Foreground of the wanted color. + f'{dvi_path}.dvi', # Input file + '-o',f'{export_path}.png', # Output file + ]) + + def run(self, process: list): + """ + Runs a subprocess and handles exceptions and messages them to the user. + """ + proc = Popen(process, stdout=PIPE, stderr=PIPE, cwd=self.tempdir.name) + try: + out, err = proc.communicate(timeout=2) # 2 seconds is already FAR too long. + if proc.returncode != 0: + # Process errored + QMessageBox.warning(None, "LogarithmPlotter - Latex", + QCoreApplication.translate("latex", "An exception occured within the creation of the latex formula.\nProcess '{}' ended with a non-zero return code {}:\n\n{}\nPlease make sure your latex installation is correct and report a bug if so.") + .format(" ".join(process), proc.returncode, str(out, 'utf8')+"\n"+str(err,'utf8'))) + raise Exception(" ".join(process) + " process exited with return code " + str(proc.returncode) + ":\n" + str(out, 'utf8')+"\n"+str(err,'utf8')) + except TimeoutExpired as e: + # Process timed out + proc.kill() + out, err = proc.communicate() + QMessageBox.warning(None, "LogarithmPlotter - Latex", + QCoreApplication.translate("latex", "An exception occured within the creation of the latex formula.\nProcess '{}' took too long to finish:\n{}\nPlease make sure your latex installation is correct and report a bug if so.") + .format(" ".join(process), str(out, 'utf8')+"\n"+str(err,'utf8'))) + raise Exception(" ".join(process) + " process timed out:\n" + str(out, 'utf8')+"\n"+str(err,'utf8')) + + def cleanup(self, export_path): + """ + Removes auxiliary, logs and Tex temporary files. + """ + for i in [".tex", ".aux", ".log"]: + remove(export_path + i) + + + @Slot(str, float, QColor, result=str) + def render_legacy(self, latexstring, font_size, color = True): + exprpath = path.join(self.tempdir.name, f'{hash(latexstring)}_{font_size}_{color.rgb()}.png') + print("Rendering", latexstring, exprpath) + if not path.exists(exprpath): + fg = color.convertTo(QColor.Rgb) + fg = f'rgb {fg.redF()} {fg.greenF()} {fg.blueF()}' + preview('$${' + latexstring + '}$$', viewer='file', filename=exprpath, dvioptions=[ + "-T", "tight", + "-z", "0", + "--truecolor", + f"-D {int(font_size * 72.27 / 100) * 10}", # See https://linux.die.net/man/1/dvipng#-D for convertion + "-bg", "Transparent", + "-fg", fg], + euler=False) + img = QImage(exprpath); + # Small hack, not very optimized since we load the image twice, but you can't pass a QImage to QML and expect it to be loaded + return f'{exprpath},{img.width()},{img.height()}' diff --git a/ci/drone.yml b/ci/drone.yml index 0eb4b7a..d699291 100644 --- a/ci/drone.yml +++ b/ci/drone.yml @@ -14,6 +14,7 @@ steps: - name: Linux test image: ad5001/ubuntu-pyside2-xvfb:hirsute-5.15.2 commands: + - apt install -y texlive-latex-base dvipng - xvfb-run python3 run.py --test-build --no-check-for-updates - xvfb-run python3 run.py --test-build --no-check-for-updates ./ci/test1.lpf - xvfb-run python3 run.py --test-build --no-check-for-updates ./ci/test2.lpf diff --git a/ci/test1.lpf b/ci/test1.lpf index 7785158..eb766f5 100644 --- a/ci/test1.lpf +++ b/ci/test1.lpf @@ -1 +1 @@ -LPFv1{"xzoom":100,"yzoom":485,"xmin":-1,"ymax":1,"xaxisstep":"1","yaxisstep":"0.1","xaxislabel":"ω (rad/s)","yaxislabel":"G (dB)","logscalex":false,"linewidth":2,"showxgrad":true,"showygrad":true,"textsize":22,"history":[[["EditedProperty",["h","Function","labelX",3,2.5,false]],["EditedProperty",["h","Function","labelPosition","above-left","above",false]],["EditedProperty",["h","Function","labelPosition","above","left",false]],["EditedProperty",["h","Function","labelX",2.5,2,false]],["EditedProperty",["h","Function","labelX",2,2.2,false]],["EditedProperty",["h","Function","labelX",2.2,9,false]]],[]],"width":1908,"height":1005,"objects":{"Sequence":[["u",true,"#ff5500","name + value",true,true,{"1":"cos(u[n])"},{"0":"-1"},"above-left",8]],"Function":[["f",true,"#2b156d","name + value","integral((x + 1), x, \"cos (t)\", \"t\")","ℝ⁺*","ℝ","application","left",7,true,true],["g",true,"#ac539c","name + value","0.739083","ℝ","ℝ","application","below",-1,true,false],["h",true,"#00aa00","name + value","derivative(\"cos t\", \"t\", x)","ℤ","ℝ","application","left",9,true,true]],"Repartition":[["X",true,"#1E1EAF","name",true,true,{"0":"0.2","1":"0.1","2":"0.2"},"above",2.5]],"Point":[["A",true,"#060759","name + value","4","(-0.5)","top","●"]]},"type":"logplotv1"} \ No newline at end of file +LPFv1{"xzoom":100,"yzoom":485,"xmin":-1,"ymax":1,"xaxisstep":"1","yaxisstep":"0.1","xaxislabel":"ω (rad/s)","yaxislabel":"G (dB)","logscalex":false,"linewidth":2,"showxgrad":true,"showygrad":true,"textsize":22,"history":[[["EditedProperty",["h","Function","labelX",3,2.5,false]],["EditedProperty",["h","Function","labelPosition","above-left","above",false]],["EditedProperty",["h","Function","labelPosition","above","left",false]],["EditedProperty",["h","Function","labelX",2.5,2,false]],["EditedProperty",["h","Function","labelX",2,2.2,false]],["EditedProperty",["h","Function","labelX",2.2,9,false]],["EditedProperty",["f","Function","labelPosition","left","above-left",false]],["EditedProperty",["f","Function","labelX",7,7.4,false]],["EditedProperty",["A","Point","y","(-0.5)","(-0.6)",true]],["EditedProperty",["X","Repartition","labelX",2.5,5,false]],["EditedProperty",["u","Sequence","labelPosition","above-left","below-right",false]],["EditedProperty",["u","Sequence","labelPosition","below-right","below-left",false]],["EditedProperty",["u","Sequence","labelX",8,6,false]],["EditedProperty",["u","Sequence","baseValues",{"0":"-1"},{"0":"-1"},false]],["EditedProperty",["u","Sequence","labelX",6,7,false]],["EditedProperty",["u","Sequence","labelPosition","below-left","above-right",false]]],[]],"width":1908,"height":1005,"objects":{"Sequence":[["u",true,"#ff5500","name + value",true,true,{"1":"cos(u[n])"},{"0":"-1"},"above-right",7]],"Function":[["f",true,"#2b156d","name + value","integral((x + 1), x, \"cos (t)\", \"t\")","ℝ⁺*","ℝ","application","above-left",7.4,true,true],["g",true,"#ac539c","null","0.739083","ℝ","ℝ","application","below",-1,true,false],["h",true,"#00aa00","name + value","derivative(\"cos t\", \"t\", x)","ℤ","ℝ","application","left",9,true,true]],"Repartition":[["X",true,"#1E1EAF","name + value",true,true,{"0":"0.2","1":"0.1","2":"0.2"},"above",5]],"Point":[["A",true,"#060759","name + value","4","(-0.6)","top","●"]]},"type":"logplotv1"} \ No newline at end of file diff --git a/ci/test2.lpf b/ci/test2.lpf index f443606..c9470d4 100644 --- a/ci/test2.lpf +++ b/ci/test2.lpf @@ -1 +1 @@ -LPFv1{"xzoom":300,"yzoom":22,"xmin":0.5,"ymax":22,"xaxisstep":"4","yaxisstep":"4","xaxislabel":"","yaxislabel":"","logscalex":true,"linewidth":2,"showxgrad":true,"showygrad":true,"textsize":14,"history":[[["CreateNewObject",["g","Function",["g",true,"#697F4E","name + value","x","ℝ⁺*","ℝ","application","above",1,true,true]]],["EditedProperty",["g","Function","expression","x","(x ^ 3)",true]],["CreateNewObject",["h","Function",["h",true,"#0CA920","name + value","x","ℝ⁺*","ℝ","application","above",1,true,true]]],["EditedProperty",["h","Function","expression","x","Integrate(\"x^3\", x)",true]],["EditedProperty",["h","Function","expression","Integrate(\"x^3\", x)","integral(0, x, \"t^3\", \"t\")",true]],["EditedProperty",["h","Function","expression","integral(0, x, \"t^3\", \"t\")","integral(0, x, \"t^3\", \"t\")",true]],["EditedProperty",["g","Function","labelX",1,2,false]],["EditedProperty",["g","Function","displayMode","application","function",false]],["EditedProperty",["g","Function","labelPosition","above","above-left",false]],["EditedProperty",["g","Function","labelX",2,1.5,false]],["EditedProperty",["g","Function","labelPosition","above-left","above",false]],["EditedProperty",["h","Function","expression","integral(0, x, \"t^3\", \"t\")","integral((x + 1), x, \"t^3\", \"t\")",true]],["EditedProperty",["h","Function","expression","integral((x + 1), x, \"t^3\", \"t\")","integral(x, (x + 1), \"t^3\", \"t\")",true]],["EditedProperty",["h","Function","expression","integral(x, (x + 1), \"t^3\", \"t\")","integral(0, (x + 1), \"t^3\", \"t\")",true]],["EditedProperty",["h","Function","expression","integral(0, (x + 1), \"t^3\", \"t\")","integral(0, x, \"t^3\", \"t\")",true]],["EditedProperty",["h","Function","expression","integral(0, x, \"t^3\", \"t\")","integral(0, (x + 0), \"t^3\", \"t\")",true]],["EditedProperty",["h","Function","expression","integral(0, (x + 0), \"t^3\", \"t\")","integral(1, x, \"t^3\", \"t\")",true]],["EditedProperty",["h","Function","expression","integral(1, x, \"t^3\", \"t\")","integral(x, 0, \"t^3\", \"t\")",true]],["EditedProperty",["h","Function","expression","integral(x, 0, \"t^3\", \"t\")","integral(x, (x + 1), \"t^3\", \"t\")",true]],["EditedProperty",["h","Function","expression","integral(x, (x + 1), \"t^3\", \"t\")","integral(x, 1, \"t^3\", \"t\")",true]],["EditedProperty",["h","Function","expression","integral(x, 1, \"t^3\", \"t\")","integral(0, x, \"t^3\", \"t\")",true]],["EditedProperty",["h","Function","displayMode","application","function",false]],["EditedProperty",["h","Function","displayMode","function","application",false]],["EditedProperty",["h","Function","labelX",1,2,false]],["EditedProperty",["h","Function","labelPosition","above","below",false]],["EditedProperty",["h","Function","labelPosition","below","below-right",false]],["EditedProperty",["h","Function","expression","integral(0, x, \"t^3\", \"t\")","integral(0, (x - 1), \"t^3\", \"t\")",true]],["EditedProperty",["h","Function","expression","integral(0, (x - 1), \"t^3\", \"t\")","integral(0, (x - 0), \"t^3\", \"t\")",true]],["EditedProperty",["h","Function","expression","integral(0, (x - 0), \"t^3\", \"t\")","integral(0, (x + 0.01), \"t^3\", \"t\")",true]]],[]],"width":1027,"height":594,"objects":{"Function":[["f",true,"#8F6027","name + value","derivative(\"t^3\", \"t\", x)","ℝ⁺*","ℝ","application","above-left",2,true,true],["g",true,"#697F4E","name + value","(x ^ 3)","ℝ⁺*","ℝ","function","above",1.5,true,true],["h",true,"#0CA920","name + value","integral(0, (x + 0.01), \"t^3\", \"t\")","ℝ⁺*","ℝ","application","below-right",2,true,true]]},"type":"logplotv1"} \ No newline at end of file +LPFv1{"xzoom":300,"yzoom":22,"xmin":0.5,"ymax":22,"xaxisstep":"4","yaxisstep":"4","xaxislabel":"","yaxislabel":"","logscalex":true,"linewidth":2,"showxgrad":true,"showygrad":true,"textsize":20,"history":[[["CreateNewObject",["g","Function",["g",true,"#697F4E","name + value","x","ℝ⁺*","ℝ","application","above",1,true,true]]],["EditedProperty",["g","Function","expression","x","(x ^ 3)",true]],["CreateNewObject",["h","Function",["h",true,"#0CA920","name + value","x","ℝ⁺*","ℝ","application","above",1,true,true]]],["EditedProperty",["h","Function","expression","x","Integrate(\"x^3\", x)",true]],["EditedProperty",["h","Function","expression","Integrate(\"x^3\", x)","integral(0, x, \"t^3\", \"t\")",true]],["EditedProperty",["h","Function","expression","integral(0, x, \"t^3\", \"t\")","integral(0, x, \"t^3\", \"t\")",true]],["EditedProperty",["g","Function","labelX",1,2,false]],["EditedProperty",["g","Function","displayMode","application","function",false]],["EditedProperty",["g","Function","labelPosition","above","above-left",false]],["EditedProperty",["g","Function","labelX",2,1.5,false]],["EditedProperty",["g","Function","labelPosition","above-left","above",false]],["EditedProperty",["h","Function","expression","integral(0, x, \"t^3\", \"t\")","integral((x + 1), x, \"t^3\", \"t\")",true]],["EditedProperty",["h","Function","expression","integral((x + 1), x, \"t^3\", \"t\")","integral(x, (x + 1), \"t^3\", \"t\")",true]],["EditedProperty",["h","Function","expression","integral(x, (x + 1), \"t^3\", \"t\")","integral(0, (x + 1), \"t^3\", \"t\")",true]],["EditedProperty",["h","Function","expression","integral(0, (x + 1), \"t^3\", \"t\")","integral(0, x, \"t^3\", \"t\")",true]],["EditedProperty",["h","Function","expression","integral(0, x, \"t^3\", \"t\")","integral(0, (x + 0), \"t^3\", \"t\")",true]],["EditedProperty",["h","Function","expression","integral(0, (x + 0), \"t^3\", \"t\")","integral(1, x, \"t^3\", \"t\")",true]],["EditedProperty",["h","Function","expression","integral(1, x, \"t^3\", \"t\")","integral(x, 0, \"t^3\", \"t\")",true]],["EditedProperty",["h","Function","expression","integral(x, 0, \"t^3\", \"t\")","integral(x, (x + 1), \"t^3\", \"t\")",true]],["EditedProperty",["h","Function","expression","integral(x, (x + 1), \"t^3\", \"t\")","integral(x, 1, \"t^3\", \"t\")",true]],["EditedProperty",["h","Function","expression","integral(x, 1, \"t^3\", \"t\")","integral(0, x, \"t^3\", \"t\")",true]],["EditedProperty",["h","Function","displayMode","application","function",false]],["EditedProperty",["h","Function","displayMode","function","application",false]],["EditedProperty",["h","Function","labelX",1,2,false]],["EditedProperty",["h","Function","labelPosition","above","below",false]],["EditedProperty",["h","Function","labelPosition","below","below-right",false]],["EditedProperty",["h","Function","expression","integral(0, x, \"t^3\", \"t\")","integral(0, (x - 1), \"t^3\", \"t\")",true]],["EditedProperty",["h","Function","expression","integral(0, (x - 1), \"t^3\", \"t\")","integral(0, (x - 0), \"t^3\", \"t\")",true]],["EditedProperty",["h","Function","expression","integral(0, (x - 0), \"t^3\", \"t\")","integral(0, (x + 0.01), \"t^3\", \"t\")",true]]],[]],"width":1027,"height":594,"objects":{"Function":[["f",true,"#8F6027","name + value","derivative(\"t^3\", \"t\", x)","ℝ⁺*","ℝ","application","above-left",2,true,true],["g",true,"#697F4E","name + value","(x ^ 3)","ℝ⁺*","ℝ","function","above",1.5,true,true],["h",true,"#0CA920","name + value","integral(0, (x + 0.01), \"t^3\", \"t\")","ℝ⁺*","ℝ","application","below-right",2,true,true]]},"type":"logplotv1"} \ No newline at end of file diff --git a/linux/debian/control b/linux/debian/control index a4fe523..1f05813 100644 --- a/linux/debian/control +++ b/linux/debian/control @@ -1,9 +1,9 @@ Package: logarithmplotter Source: logarithmplotter -Version: 0.1.9 +Version: 0.2.0 Architecture: all Maintainer: Ad5001 -Depends: python3, python3-pip, qml-module-qtquick-controls2 (>= 5.12.0), qml-module-qtmultimedia (>= 5.12.0), qml-module-qtgraphicaleffects (>= 5.12.0), qml-module-qtquick2 (>= 5.12.0), qml-module-qtqml-models2 (>= 5.12.0), qml-module-qtquick-controls (>= 5.12.0), python3-pyside2.qtcore (>= 5.12.0), python3-pyside2.qtqml (>= 5.12.0), python3-pyside2.qtgui (>= 5.12.0), python3-pyside2.qtquick (>= 5.12.0), python3-pyside2.qtwidgets (>= 5.12.0), python3-pyside2.qtmultimedia (>= 5.12.0), python3-pyside2.qtnetwork (>= 5.12.0), python3-sympy +Depends: python3, python3-pip, qml-module-qtquick-controls2 (>= 5.12.0), qml-module-qtmultimedia (>= 5.12.0), qml-module-qtgraphicaleffects (>= 5.12.0), qml-module-qtquick2 (>= 5.12.0), qml-module-qtqml-models2 (>= 5.12.0), qml-module-qtquick-controls (>= 5.12.0), python3-pyside2.qtcore (>= 5.12.0), python3-pyside2.qtqml (>= 5.12.0), python3-pyside2.qtgui (>= 5.12.0), python3-pyside2.qtquick (>= 5.12.0), python3-pyside2.qtwidgets (>= 5.12.0), python3-pyside2.qtmultimedia (>= 5.12.0), python3-pyside2.qtnetwork (>= 5.12.0), texlive-latex-base, dvipng Build-Depends: debhelper (>=11~), dh-python, dpkg-dev (>= 1.16.1~), python-setuptools, python3-all-dev (>=3.6) Section: science diff --git a/linux/debian/depends b/linux/debian/depends index 725059d..53dcda3 100644 --- a/linux/debian/depends +++ b/linux/debian/depends @@ -1 +1 @@ -python3-pip, qml-module-qtquick-controls2 (>= 5.12.0), qml-module-qtmultimedia (>= 5.12.0), qml-module-qtgraphicaleffects (>= 5.12.0), qml-module-qtquick2 (>= 5.12.0), qml-module-qtqml-models2 (>= 5.12.0), qml-module-qtquick-controls (>= 5.12.0), python3-pyside2.qtcore (>= 5.12.0), python3-pyside2.qtqml (>= 5.12.0), python3-pyside2.qtgui (>= 5.12.0), python3-pyside2.qtquick (>= 5.12.0), python3-pyside2.qtwidgets (>= 5.12.0), python3-pyside2.qtmultimedia (>= 5.12.0), python3-pyside2.qtnetwork (>= 5.12.0), python3-sympy +python3-pip, qml-module-qtquick-controls2 (>= 5.12.0), qml-module-qtmultimedia (>= 5.12.0), qml-module-qtgraphicaleffects (>= 5.12.0), qml-module-qtquick2 (>= 5.12.0), qml-module-qtqml-models2 (>= 5.12.0), qml-module-qtquick-controls (>= 5.12.0), python3-pyside2.qtcore (>= 5.12.0), python3-pyside2.qtqml (>= 5.12.0), python3-pyside2.qtgui (>= 5.12.0), python3-pyside2.qtquick (>= 5.12.0), python3-pyside2.qtwidgets (>= 5.12.0), python3-pyside2.qtmultimedia (>= 5.12.0), python3-pyside2.qtnetwork (>= 5.12.0), texlive-latex-base, dvipng diff --git a/linux/snapcraft/launcher/launch-logarithmplotter b/linux/snapcraft/launcher/launch-logarithmplotter index 55fc9b4..7f8b61e 100755 --- a/linux/snapcraft/launcher/launch-logarithmplotter +++ b/linux/snapcraft/launcher/launch-logarithmplotter @@ -8,7 +8,24 @@ set \ -o pipefail # GTK theme integration (we have Qt fetch the GTK theme mirroring the host Qt theme...) +# Currently broken with portals #export QT_QPA_PLATFORMTHEME=kde -# Finally run the next part of the command chain -${@} --no-check-for-updates +# Check if the last parameter is a file, and if so, add the argument "--no-checks-for-updates" BEFORE it. + +length=$(($#-1)) + +echo "Len: $length" + +if [ $length -gt 0 ]; then + last="${@:$#}" # last parameter + args=("${@:1:$length}") # all parameters except the last + + if [ -f "$last" ]; then + ${args} --no-check-for-updates "$last" + else + ${@} --no-check-for-updates + fi +else + ${@} --no-check-for-updates +fi diff --git a/scripts/package-macosx.sh b/scripts/package-macosx.sh index c61cfcf..070a164 100644 --- a/scripts/package-macosx.sh +++ b/scripts/package-macosx.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash cd "$(dirname "$(readlink -f "$0" || realpath "$0")")/.." -VERSION=0.1.9 +VERSION=0.2.0 title="LogarithmPlotter v${VERSION} Setup" finalDMGName="LogarithmPlotter-v${VERSION}-setup.dmg" applicationName=LogarithmPlotter diff --git a/setup.py b/setup.py index b7817bf..e3fb347 100644 --- a/setup.py +++ b/setup.py @@ -127,7 +127,7 @@ if sys.platform == 'linux': os.remove(os.environ["PREFIX"] + '/icons/hicolor/scalable/apps/logplotter.svg') setuptools.setup( - install_requires=([] if "FLATPAK_INSTALL" in os.environ else ["PySide2", "sympy"]), + install_requires=([] if "FLATPAK_INSTALL" in os.environ else ["PySide2"]), python_requires='>=3.8', name='logarithmplotter', @@ -145,7 +145,7 @@ setuptools.setup( classifiers=CLASSIFIERS, zip_safe=False, - packages=["LogarithmPlotter"], + packages=["LogarithmPlotter", "LogarithmPlotter.util"], package_data={ 'LogarithmPlotter':package_data(), diff --git a/snapcraft.yaml b/snapcraft.yaml index 49ba0e7..9124698 100644 --- a/snapcraft.yaml +++ b/snapcraft.yaml @@ -1,6 +1,6 @@ name: logarithmplotter title: LogarithmPlotter -version: '0.1.9' +version: '0.2.0' summary: 2D logarithmic-scaled plotter software to create asymptotic Bode plots confinement: strict base: core20 @@ -79,6 +79,9 @@ parts: source: . stage-packages: - breeze-icon-theme + # Latex dependencies + - texlive-latex-base + - dvipng # Additional dependencies - libxcomposite1 - libxcursor1 @@ -131,7 +134,7 @@ parts: - libxcb-render-util0 - libdouble-conversion3 - libpcre2-16-0 - snapcraft-preload: # Fixes error related to multiprocessing on python. + snapcraft-preload: source: https://github.com/sergiusens/snapcraft-preload.git plugin: cmake cmake-parameters: @@ -142,6 +145,11 @@ parts: - g++-multilib stage-packages: - lib32stdc++6 + changelog: + source: . + plugin: dump + organize: + CHANGELOG.md: lib/python3.8/site-packages/LogarithmPlotter/CHANGELOG.md apps: logarithmplotter: diff --git a/win/installer.nsi b/win/installer.nsi index 6b67417..1d2c260 100644 --- a/win/installer.nsi +++ b/win/installer.nsi @@ -11,7 +11,7 @@ Unicode True !define PROG_ID "LogarithmPlotter.File.1" !define DEV_NAME "Ad5001" !define WEBSITE "https://apps.ad5001.eu/logarithmplotter" -!define VERSION_SHORT "0.1.9" +!define VERSION_SHORT "0.2.0" !define APP_VERSION "${VERSION_SHORT}.0" !define COPYRIGHT "Ad5001 (c) 2022" !define DESCRIPTION "Create graphs with logarithm scales."