From e94e414b93e7c3d5f9930413a4d96810abada7b4 Mon Sep 17 00:00:00 2001 From: Allan CORNET Date: Sun, 15 Oct 2023 10:40:48 +0200 Subject: [PATCH] strjust function + tf display centered --- CHANGELOG.md | 1 + .../control_system/functions/@tf/display.m | 52 +++++++++--- .../control_system/functions/@tf/subsasgn.m | 12 ++- modules/control_system/tests/test_tf.m | 84 +++++++++---------- modules/string/functions/@cell/strjust.m | 35 ++++++++ modules/string/functions/@string/strjust.m | 32 +++++++ modules/string/functions/strjust.m | 83 ++++++++++++++++++ modules/string/help/en_US/xml/strjust.xml | 84 +++++++++++++++++++ modules/string/module.iss | 2 + modules/string/tests/test_strjust.m | 31 +++++++ 10 files changed, 362 insertions(+), 54 deletions(-) create mode 100644 modules/string/functions/@cell/strjust.m create mode 100644 modules/string/functions/@string/strjust.m create mode 100644 modules/string/functions/strjust.m create mode 100644 modules/string/help/en_US/xml/strjust.xml create mode 100644 modules/string/tests/test_strjust.m diff --git a/CHANGELOG.md b/CHANGELOG.md index deb5ac8cd6..1edc628a1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - `cell2mat` Convert cell array of matrices to single matrix. - [#948](http://github.com/Nelson-numerical-software/nelson/issues/948) `blkdiag` Create a block diagonal matrix from 2D matrices of different sizes. - `kron` Kronecker tensor product. +- `strjust` Justify strings. - control system module (part 1): - [#967](http://github.com/Nelson-numerical-software/nelson/issues/967) control system module template. diff --git a/modules/control_system/functions/@tf/display.m b/modules/control_system/functions/@tf/display.m index 6d20dd7b15..9f64a0f5f0 100644 --- a/modules/control_system/functions/@tf/display.m +++ b/modules/control_system/functions/@tf/display.m @@ -44,15 +44,22 @@ function display(varargin) numeratorString = stringPoly(numerators{k, q}, TF.Variable); haveNoNumerator = isempty(numeratorString); denominatorString = stringPoly(denominator{k, q}, TF.Variable); - lengthDiff = length(denominatorString) - length(numeratorString); - if (lengthDiff > 0) - spacesToAdd = repmat(' ', 1, floor(lengthDiff / 2)); - numeratorString = [spacesToAdd, numeratorString]; - end + isOneString = strcmp(denominatorString, ' 1'); + + maxLen = max([length(denominatorString), length(numeratorString)]); + spacesToAdd = repmat(' ', 1, maxLen - length(numeratorString)); + numeratorString = [spacesToAdd, numeratorString]; + spacesToAdd = repmat(' ', 1, maxLen - length(denominatorString)); + denominatorString = [spacesToAdd, denominatorString]; + ce = strjust({numeratorString, denominatorString}, 'center'); + numeratorString = ce{1}; + denominatorString = ce{2}; + numeratorString = deblank(numeratorString); + denominatorString = deblank(denominatorString); dashString = getDashedLine(numeratorString, denominatorString); - + if (m ~= 1) - if (strcmp(denominatorString, ' 1') == true) + if isOneString if ~haveNoNumerator disp([' ',sprintf(_('%d:'), k), ' ', numeratorString]); else @@ -74,8 +81,7 @@ function display(varargin) end end - - if (strcmp(denominatorString, ' 1') == false && ~haveNoNumerator) + if (~isOneString && ~haveNoNumerator) disp([' ', dashString]); disp([' ', denominatorString]); end @@ -101,9 +107,35 @@ function display(varargin) end end %============================================================================= +function [numeratorString, dashString, denominatorString] = uniformizeStrings(numeratorString, dashString, denominatorString) + + str = string({numeratorString, dashString, denominatorString}); + max_length = max(strlength(str)); + + spaces_numeratorString = (max_length - length(numeratorString)); + spaces_dashString = (max_length - length(dashString)); + spaces_denominatorString = (max_length - length(denominatorString)); + + text = strjust({dashString, denominatorString}, 'center'); + dashString = text{1}; + denominatorString = text{2}; + + str{1} = [repmat(' ', 1, spaces_numeratorString), str{1}]; + str{2} = [repmat(' ', 1, spaces_dashString), str{2}]; + str{3} = [repmat(' ', 1, spaces_denominatorString), str{3}]; + + str = strjust(str, 'center'); + numeratorString = deblank(str{1}); + dashString = deblank(str{2}); + denominatorString = deblank(str{3}); +end +%============================================================================= function dash = getDashedLine(numeratorString, denominatorString) dash = ''; - lenDash = max(length(numeratorString), length(denominatorString)) + 1; + lenDash = max(length(numeratorString), length(denominatorString)); + if ~mod(lenDash, 2) + lenDash = lenDash + 1; + end for i = 1:lenDash dash = strcat(dash, '—'); end diff --git a/modules/control_system/functions/@tf/subsasgn.m b/modules/control_system/functions/@tf/subsasgn.m index 6b64dcd904..9ac5bf27f7 100644 --- a/modules/control_system/functions/@tf/subsasgn.m +++ b/modules/control_system/functions/@tf/subsasgn.m @@ -36,13 +36,21 @@ %============================================================================= function objOut = updateNumerator(objIn, value) st = struct(objIn); - st.Numerator = value; + if ~iscell(value) + st.Numerator = {value}; + else + st.Numerator = value; + end objOut = class(st, 'tf'); end %============================================================================= function objOut = updateDenominator(objIn, value) st = struct(objIn); - st.Denominator = value; + if ~iscell(value) + st.Denominator = {value}; + else + st.Denominator = value; + end objOut = class(st, 'tf'); end %============================================================================= diff --git a/modules/control_system/tests/test_tf.m b/modules/control_system/tests/test_tf.m index b5d5725c8b..f9c1246fa5 100644 --- a/modules/control_system/tests/test_tf.m +++ b/modules/control_system/tests/test_tf.m @@ -14,9 +14,9 @@ REF = ' sys = - 2 s - ————————————————— - 4 s^3 + 3 s - 1 + 2 s + ——————————————— + 4 s^3 + 3 s - 1 Continuous-time transfer function. @@ -31,9 +31,9 @@ REF = ' sys = - 2 z - ————————————————— - 4 z^3 + 3 z - 1 + 2 z + ——————————————— + 4 z^3 + 3 z - 1 Sample time: 1.5000 seconds Discrete-time transfer function. @@ -49,14 +49,14 @@ sys = From input 1 to output: - 2 s - ————————————————— - 4 s^3 + 3 s - 1 + 2 s + ——————————————— + 4 s^3 + 3 s - 1 From input 2 to output: - s + 3 - ——————————————— - s^2 + 3 s + 5 + s + 3 + ————————————— + s^2 + 3 s + 5 Continuous-time transfer function. @@ -78,32 +78,32 @@ sys = From input 1 to output: - 1: 1 + 1: 1 - 2: 5 + 2: 5 - 3: 8 + 3: 8 From input 2 to output: - 1: 2 + 1: 2 - 2: 6 + 2: 6 - 3: 9 + 3: 9 From input 3 to output: - 1: 3 + 1: 3 - 2: 7 + 2: 7 - 3: 10 + 3: 10 From input 4 to output: - 1: 4 + 1: 4 - 2: 8 + 2: 8 - 3: 11 + 3: 11 Static gain. @@ -116,11 +116,11 @@ sys = tf(num, den, Ts); sys.Variable = 'z^-1'; R = evalc('display(sys)'); -REF = ' +REF = ' sys = 3 z^-1 + 4 z^-2 - —————————————————— + ————————————————— 3 + z^-1 + 5 z^-2 Sample time: 0.2000 seconds @@ -138,14 +138,14 @@ REF = ' sys = - - 1 + 3 z^-1 - 4 z^-2 - ——————————————————————— - - 1 + 5 z^-1 - 7 z^-2 + - 1 + 3 z^-1 - 4 z^-2 + ————————————————————— + - 1 + 5 z^-1 - 7 z^-2 Sample time: 0.2000 seconds Discrete-time transfer function. -'; +' ; assert_isequal(R, REF); %============================================================================= sys1 = tf([1 -1],[1 1]); @@ -156,14 +156,14 @@ sys = 1: - s - 1 - ———————— - s + 1 + s - 1 + ——————— + s + 1 2: - s + 2 - ——————————————— - s^2 + 4 s + 5 + s + 2 + ————————————— + s^2 + 4 s + 5 Continuous-time transfer function. @@ -178,14 +178,14 @@ sys = From input 1 to output: - s - 1 - ———————— - s + 1 + s - 1 + ——————— + s + 1 From input 2 to output: - s + 2 - ——————————————— - s^2 + 4 s + 5 + s + 2 + ————————————— + s^2 + 4 s + 5 Continuous-time transfer function. diff --git a/modules/string/functions/@cell/strjust.m b/modules/string/functions/@cell/strjust.m new file mode 100644 index 0000000000..6462cc7cfd --- /dev/null +++ b/modules/string/functions/@cell/strjust.m @@ -0,0 +1,35 @@ +%============================================================================= +% Copyright (c) 2016-present Allan CORNET (Nelson) +%============================================================================= +% This file is part of the Nelson. +%============================================================================= +% LICENCE_BLOCK_BEGIN +% SPDX-License-Identifier: LGPL-3.0-or-later +% LICENCE_BLOCK_END +%============================================================================= +function varargout = strjust(varargin) + narginchk(1, 2); + nargoutchk(0, 1); + + if nargin == 1 + justify = 'right'; + else + justify = lower(varargin{2}); + end + mustBeMember(justify, ["left", "right", "center"], 2); + + str = varargin{1}; + if ~iscellstr(str) + error(_('String, cell of chars or characters vector expected.')); + end + result = str; + for k = 1:numel(str) + if ischar(str{k}) + result{k} = strjust(str{k}, justify); + else + error(_('String, cell of chars or characters vector expected.')); + end + end + varargout{1} = result; +end +%============================================================================= diff --git a/modules/string/functions/@string/strjust.m b/modules/string/functions/@string/strjust.m new file mode 100644 index 0000000000..fb0903010c --- /dev/null +++ b/modules/string/functions/@string/strjust.m @@ -0,0 +1,32 @@ +%============================================================================= +% Copyright (c) 2016-present Allan CORNET (Nelson) +%============================================================================= +% This file is part of the Nelson. +%============================================================================= +% LICENCE_BLOCK_BEGIN +% SPDX-License-Identifier: LGPL-3.0-or-later +% LICENCE_BLOCK_END +%============================================================================= +function varargout = strjust(varargin) + narginchk(1, 2); + nargoutchk(0, 1); + + if nargin == 1 + justify = 'right'; + else + justify = lower(varargin{2}); + end + mustBeMember(justify, ["left", "right", "center"], 2); + + str = varargin{1}; + result = str; + for k = 1:numel(str) + if ischar(str{k}) + result{k} = strjust(str{k}, justify); + else + error(_('String, cell of chars or characters vector expected.')); + end + end + varargout{1} = result; +end +%============================================================================= diff --git a/modules/string/functions/strjust.m b/modules/string/functions/strjust.m new file mode 100644 index 0000000000..1374d4253b --- /dev/null +++ b/modules/string/functions/strjust.m @@ -0,0 +1,83 @@ +%============================================================================= +% Copyright (c) 2016-present Allan CORNET (Nelson) +%============================================================================= +% This file is part of the Nelson. +%============================================================================= +% LICENCE_BLOCK_BEGIN +% SPDX-License-Identifier: LGPL-3.0-or-later +% LICENCE_BLOCK_END +%============================================================================= +function varargout = strjust(varargin) + narginchk(1, 2); + nargoutchk(0, 1); + + if nargin == 1 + justify = 'right'; + else + justify = lower(varargin{2}); + end + mustBeMember(justify, ["left", "right", "center"], 2); + + str = varargin{1}; + % Handle empty input + if isempty(str) + varargout{1} = str; + return; + end + + if isnumeric(str) + str = char(str); + end + + % Get the size of the input string + [m, n] = size(str); + + % Initialize justifiedText as a space-filled matrix of the same size + justifiedText = repmat(' ', m, n); + + % Determine the column to add spaces + if (strcmp(justify, 'left') && ~any(str(:, 1) == ' ')) || (strcmp(justify, 'right') && ~any(str(:, n) == ' ')) + varargout{1} = char(str); + return; + end + % Find row and column indices of non-space characters + isChar = (str ~= 0 & str ~= ' '); + [nr, nc] = find(isChar); + + % Determine how to justify the text + if strcmp(justify, 'left') + shift = shiftLeft(isChar); + elseif strcmp(justify, 'right') + shift = shiftRight(isChar); + else + shift = shiftCenter(isChar); + end + + % Calculate input and output positions for character copying + posIn = nr + (nc - 1) * m; + posOut = nr + (nc + shift(nr)' - 1) * m; + % Copy characters to the justifiedText matrix + justifiedText(posOut) = str(posIn); + + varargout{1} = justifiedText; +end +%============================================================================= +function shift = shiftLeft(isChar) + % For left justification, find the leftmost non-space character in each row + [dummy, shift] = max(isChar, [], 2); + shift = 1 - shift; +end +%============================================================================= +function shift = shiftRight(isChar) + % For right justification, find the rightmost non-space character in each row + [dummy, shift] = max(fliplr(isChar), [], 2); + shift = shift - 1; +end +%============================================================================= +function shift = shiftCenter(isChar) + % For center justification, find the middle point between leftmost and rightmost non-space characters + [dummy, shiftBefore] = max(isChar, [], 2); + [dummy, shiftAfter] = max(fliplr(isChar), [], 2); + shift = floor((shiftAfter - shiftBefore) / 2); +end +%============================================================================= diff --git a/modules/string/help/en_US/xml/strjust.xml b/modules/string/help/en_US/xml/strjust.xml new file mode 100644 index 0000000000..4f6d645a03 --- /dev/null +++ b/modules/string/help/en_US/xml/strjust.xml @@ -0,0 +1,84 @@ + + + SAME AS NELSON SOFTWARE + + en_US + strjust + Justify strings + + + J = strjust(str) + J = strjust(str, side) + + + + + + str + characters vector, cell of characters or string array. + + + side + 'left', 'center', 'right' (default). + + + + + + + + J + justified text + + + + +

J = strjust(str, side) returns the text that is justified on the side specified by side.

+
+ + + + + + + + nelson + + + + + + + nelson + + + + + + + + + + blanks + + + + + + 1.0.0 + initial version + + + + + Allan CORNET + +
diff --git a/modules/string/module.iss b/modules/string/module.iss index 0274ddae7f..6ffcbdca77 100644 --- a/modules/string/module.iss +++ b/modules/string/module.iss @@ -17,6 +17,8 @@ Source: {#RootPath}modules\{#MODULE_NAME}\etc\startup.m; DestDir: {app}\modules\ Source: {#RootPath}modules\{#MODULE_NAME}\etc\finish.m; DestDir: {app}\modules\{#MODULE_NAME}\etc\; ;============================================================================== Source: {#RootPath}modules\{#MODULE_NAME}\functions\*.m; DestDir: {app}\modules\{#MODULE_NAME}\functions\; +Source: {#RootPath}modules\{#MODULE_NAME}\functions\@cell\*.m; DestDir: {app}\modules\{#MODULE_NAME}\functions\@cell; +Source: {#RootPath}modules\{#MODULE_NAME}\functions\@string\*.m; DestDir: {app}\modules\{#MODULE_NAME}\functions\@string; ;============================================================================== Source: {#RootPath}modules\{#MODULE_NAME}\help\*.qch; DestDir: {app}\modules\{#MODULE_NAME}\help\; Flags: recursesubdirs;Components: {#COMPONENT_HELP_FILES} and {#COMPONENT_HELP_BROWSER}; ;============================================================================== diff --git a/modules/string/tests/test_strjust.m b/modules/string/tests/test_strjust.m new file mode 100644 index 0000000000..db615582ed --- /dev/null +++ b/modules/string/tests/test_strjust.m @@ -0,0 +1,31 @@ +%============================================================================= +% Copyright (c) 2016-present Allan CORNET (Nelson) +%============================================================================= +% This file is part of the Nelson. +%============================================================================= +% LICENCE_BLOCK_BEGIN +% SPDX-License-Identifier: LGPL-3.0-or-later +% LICENCE_BLOCK_END +%============================================================================= +R = strjust(' s', 'center'); +REF = ' s '; +assert_isequal(R, REF); +%============================================================================= +R = strjust([]); +REF = []; +assert_isequal(R, REF); +%============================================================================= +str = ["Nelson"; "Mir "; "ISS "]; +R = strjust(str, 'right'); +REF = ["Nelson"; " Mir";" ISS"]; +assert_isequal(R, REF); +%============================================================================= +str = {'Nelson'; 'Mir '; 'ISS '}; +R = strjust(str, 'right'); +REF = {'Nelson'; ' Mir';' ISS'}; +assert_isequal(R, REF); +%============================================================================= +R = strjust([69, 77]); +REF = 'EM'; +assert_isequal(R, REF); +%=============================================================================