Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP Let the GMT/MEX toolbox be an optional supplement in the main GMT project #4246

Open
wants to merge 75 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
5f2156a
Initial upload of files and setting of CMake par guesses for building…
PaulWessel Sep 22, 2020
017cb8e
Report what we find for MATLAB lits etc.
PaulWessel Sep 22, 2020
78e63ab
Update CMakeLists.txt
PaulWessel Sep 22, 2020
8a5691b
testing
PaulWessel Sep 23, 2020
8149a02
eliminate cmakelist in gmtmex
PaulWessel Sep 25, 2020
4ebb328
Merge branch 'master' into add-gmtmex-supplement
PaulWessel Apr 3, 2021
4f598d1
Update emx files
PaulWessel Apr 3, 2021
c1ee290
Update ConfigReleaseBuild.cmake
PaulWessel Apr 3, 2021
2b203c5
Consolidate gmtmex as supplement
PaulWessel Apr 3, 2021
65cd6f2
Update gmt.m
PaulWessel Apr 3, 2021
56c694f
Add CMakeLists.txt file for gmtmex
PaulWessel Apr 3, 2021
2bc96a8
Update CMakeLists.txt
PaulWessel Apr 3, 2021
fef3186
Merge branch 'master' into add-gmtmex-supplement
PaulWessel Apr 3, 2021
e81ab9a
Use FindMatlab
PaulWessel Apr 3, 2021
8051bb2
More updates
PaulWessel Apr 3, 2021
93ed770
Finalize
PaulWessel Apr 4, 2021
1657680
Merge branch 'master' into add-gmtmex-supplement
PaulWessel Apr 4, 2021
3197b75
Merge branch 'master' into add-gmtmex-supplement
PaulWessel Apr 4, 2021
6bccb33
Merge branch 'master' into add-gmtmex-supplement
PaulWessel Apr 5, 2021
e119d38
Merge branch 'master' into add-gmtmex-supplement
PaulWessel Apr 7, 2021
99f238c
Update gmtmex.c
PaulWessel Apr 8, 2021
49a83d4
Update gmt_api.c
PaulWessel Apr 8, 2021
cd3a262
Merge branch 'master' into add-gmtmex-supplement
PaulWessel Apr 10, 2021
8165620
Add build script
PaulWessel Apr 10, 2021
c28bc9c
Update gmt_mexbuild.sh
PaulWessel Apr 10, 2021
f4a0f2e
Update build-macos-external-list.sh
PaulWessel Apr 10, 2021
ff80e53
Install gmt_mexbuild.sh
PaulWessel Apr 10, 2021
cca3939
Update gmt_mexbuild.sh
PaulWessel Apr 10, 2021
cc08901
Merge branch 'master' into add-gmtmex-supplement
PaulWessel Apr 16, 2021
fbe05ec
Update gmtmex.c
PaulWessel Apr 17, 2021
da72376
Merge branch 'master' into add-gmtmex-supplement
PaulWessel Apr 29, 2021
de3699a
Fix grdinterpolate KEYS for external use
PaulWessel May 8, 2021
5bd4401
Merge branch 'master' into add-gmtmex-supplement
PaulWessel May 9, 2021
592afa8
Merge branch 'grdinterpolate-keys' into add-gmtmex-supplement
PaulWessel May 9, 2021
6e68ca9
Merge branch 'master' into add-gmtmex-supplement
PaulWessel May 17, 2021
7f3968f
Moving along
PaulWessel May 17, 2021
14efb57
Update CMakeLists.txt
PaulWessel May 17, 2021
7504cd8
Update gmtmex.c
PaulWessel May 17, 2021
e6647a3
Update build-macos-external-list.sh
PaulWessel May 18, 2021
411aae3
Update gmt_mexbuild.sh
PaulWessel May 18, 2021
98732f2
Update gmt_mexbuild.sh
PaulWessel May 18, 2021
fad2ccb
Update gmt_mexbuild.sh
PaulWessel May 18, 2021
a4e33dc
Update gmt_mexbuild.sh
PaulWessel May 18, 2021
c81b42d
Update gmt_mexbuild.sh
PaulWessel May 18, 2021
63f6187
Update gmt_mexbuild.sh
PaulWessel May 18, 2021
d5d800a
Update ConfigDefault.cmake
PaulWessel May 18, 2021
cb2dcb9
Update gmt_mexbuild.sh
PaulWessel May 18, 2021
79a6b61
Try to do both a mex build and just distribute files
PaulWessel May 18, 2021
168b423
Update CMakeLists.txt
PaulWessel May 18, 2021
e2a7345
Update CMakeLists.txt
PaulWessel May 18, 2021
ba293be
Update gmt_mexbuild.sh
PaulWessel May 18, 2021
5634b5c
Update gmt_mexbuild.sh
PaulWessel May 18, 2021
088ae48
Merge branch 'master' into add-gmtmex-supplement
PaulWessel May 18, 2021
e9b91cf
Merge branch 'master' into add-gmtmex-supplement
PaulWessel May 19, 2021
94498be
Merge branch 'master' into add-gmtmex-supplement
PaulWessel May 23, 2021
28a77c6
Merge branch 'master' into add-gmtmex-supplement
PaulWessel Jun 15, 2021
f3c8820
Merge branch 'ternary-key-fix' into add-gmtmex-supplement
PaulWessel Jun 15, 2021
48004d9
Update psternary.c
PaulWessel Jun 15, 2021
662a44b
Merge branch 'master' into add-gmtmex-supplement
PaulWessel Jun 16, 2021
d70a376
let GMT_Encode_Option do its job for psternary
PaulWessel Jun 16, 2021
1a359a5
Merge branch 'mex-ternary-update' into add-gmtmex-supplement
PaulWessel Jun 16, 2021
e9f58b1
Merge branch 'master' into add-gmtmex-supplement
PaulWessel Jan 1, 2022
1f3062b
Merge branch 'master' into add-gmtmex-supplement
PaulWessel Jun 7, 2022
c892c64
Merge branch 'master' into add-gmtmex-supplement
PaulWessel Jul 5, 2022
15aec06
Update gmtmex.c
PaulWessel Jul 5, 2022
5249572
Merge branch 'master' into add-gmtmex-supplement
PaulWessel Jul 7, 2022
e20dbcc
Merge branch 'master' into add-gmtmex-supplement
PaulWessel Jul 14, 2023
5b0898f
Merge branch 'master' into add-gmtmex-supplement
PaulWessel Jul 14, 2023
0da49f6
Merge branch 'master' into add-gmtmex-supplement
PaulWessel Jul 22, 2023
7d3a3f5
Merge branch 'master' into add-gmtmex-supplement
PaulWessel Dec 1, 2023
59c37f9
Update dates and fix typo
PaulWessel Dec 1, 2023
1e70cd3
Merge branch 'master' into add-gmtmex-supplement
PaulWessel Dec 3, 2023
93423e3
Merge branch 'master' into add-gmtmex-supplement
PaulWessel Jan 1, 2024
fb42dc7
copyright year update
PaulWessel Jan 1, 2024
cfee4cc
Merge branch 'master' into add-gmtmex-supplement
PaulWessel Jan 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -174,11 +174,23 @@ else (SUPPL_EXTRA_DIRS)
set (PROTO "none")
endif (SUPPL_EXTRA_DIRS)

if (GMT_INSTALL_MODULE_LINKS)
set (LINKS "yes")
if (SUPPL_EXTRA_DIRS)
set (PROTO ${SUPPL_EXTRA_DIRS})
else (SUPPL_EXTRA_DIRS)
set (PROTO "none")
endif (SUPPL_EXTRA_DIRS)

if (GMT_BUILD_GMTMEX)
set (MATLAB_APP "${MATLAB}")
set (MATLAB_INC "${MEX_INC}")
set (MATLAB_LIB1 "${MEX_LIB}")
set (MATLAB_LIB2 "${MX_LIB}")
else (GMT_INSTALL_MODULE_LINKS)
set (LINKS "no")
endif (GMT_INSTALL_MODULE_LINKS)
set (MATLAB_APP "not used")
set (MATLAB_INC "not used")
set (MATLAB_LIB1 "not used")
set (MATLAB_LIB2 "not used")
endif (GMT_BUILD_GMTMEX)

# Configure header file to pass some of the CMake settings to the source code
configure_file (src/config.h.in src/config.h)
Expand Down Expand Up @@ -231,6 +243,10 @@ message(
"* Build GMT for developers : ${DEVEL}\n"
"* Build proto supplements : ${PROTO}\n"
"* Build module links : ${LINKS}\n"
"* MATLAB Application : ${MATLAB_APP}\n"
"* MATLAB include dir : ${MATLAB_INC}\n"
"* MATLAB MEX library : ${MATLAB_LIB1}\n"
"* MATLAB MX library : ${MATLAB_LIB2}\n"
"* Found Ghostscript (gs) : ${GMT_CONFIG_GS_MESSAGE}\n"
"* Found GraphicsMagick (gm) : ${GMT_CONFIG_GM_MESSAGE}\n"
"* Found ffmpeg : ${GMT_CONFIG_FFMPEG_MESSAGE}\n"
Expand Down
26 changes: 26 additions & 0 deletions cmake/ConfigUserAdvancedTemplate.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@
#set (GMT_EXCLUDE_BLAS TRUE)
#set (GMT_EXCLUDE_ZLIB TRUE)

# Include special gmtmex supplement for the GMT/MEX toolbox [which requires MATLAB]
#set (GMT_BUILD_GMTMEX TRUE)

# ============================================================================
# Advanced configuration begins here. Usually it is not necessary to edit any
# settings below. You should know what you are doing if you do though. Note:
Expand Down Expand Up @@ -247,6 +250,29 @@
# set (CMAKE_C_FLAGS_RELEASE "-ggdb3 -O2 -Wuninitialized") # check uninitialized variables
#endif (HAVE_OPENMP)

#
# Building the GMT/MEX Toolbox
#
# Please export an environmental variable MATLAB that points to your Matlab application

if (GMT_BUILD_GMTMEX)
set (SUPPL_EXTRA_DIRS ${SUPPL_EXTRA_DIRS} gmtmex)
if (APPLE)
set (MATLAB "$ENV{MATLAB}")
set (MEX_EXT "mexmaci64")
set (MATLAB_MEX "maci64")
set (MATLAB_FLAGS="-g")
add_definitions(-DGMT_MATLAB)
#set (MEX_BLD "xcrun clang -undefined error -arch x86_64 -bundle -DGMT_MATLAB ${MATLAB_FLAGS}")
set (MEX_INC "${MATLAB}/extern/include")
set (MEX_LIB "${MATLAB}/bin/${MATLAB_MEX}/libmex.dylib")
set (MX_LIB "${MATLAB}/bin/${MATLAB_MEX}/libmx.dylib")
include_directories (${MEX_INC})
list (APPEND GMT_OPTIONAL_LIBRARIES ${MEX_LIB})
list (APPEND GMT_OPTIONAL_LIBRARIES ${MX_LIB})
endif (APPLE)
endif (GMT_BUILD_GMTMEX)

#
# System specific tweaks
#
Expand Down
37 changes: 37 additions & 0 deletions src/gmtmex/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#
#
# Copyright (c) 1991-2020 by the GMT Team (https://www.generic-mapping-tools.org/team.html)
# See LICENSE.TXT file for copying and redistribution conditions.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; version 3 or 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 Lesser General Public License for more details.
#
# Contact info: www.generic-mapping-tools.org
#-------------------------------------------------------------------------------
#
# CMake settings for supplemental package:
#
# SUPPL_NAME: name of the supplemental package
# SUPPL_HEADERS: header files. Will be installed if BUILD_DEVELOPER is TRUE
# SUPPL_PROGS_SRCS: list of C source codes for supplemental modules
# SUPPL_LIB_SRCS: list of C source codes for supplemental library
# SUPPL_EXAMPLE_FILES: README and other example files
# SUPPL_EXAMPLE_PROGS: Example scripts
#

set (SUPPL_NAME gmtmex)
set (SUPPL_PROGS_SRCS gmtmex.c gmtmex_parser.c)
set (SUPPL_HEADERS gmtmex.h)
set (SUPPL_LIB_SRCS ${SUPPL_PROGS_SRCS})
Copy link
Member

@seisman seisman Sep 22, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may work:

Suggested change
set (SUPPL_PROGS_SRCS gmtmex.c gmtmex_parser.c)
set (SUPPL_HEADERS gmtmex.h)
set (SUPPL_LIB_SRCS ${SUPPL_PROGS_SRCS})
set (SUPPL_HEADERS gmtmex.h)
set (SUPPL_LIB_SRCS gmtmex.c gmtmex_parser.c)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with header and parser. But gmtmex.c is like gmt.c and is to become a stand-alone executable. So perhaps just parser?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gmtmex.c is not a module, so can't be in SUPPL_PROGS_SRCS. Perhaps need to define a new cmake variable, and also update src/CMakeLists to be able to build stand-alone programs.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I will leave it off for now since it is different.

set (SUPPL_EXAMPLE_FILES README.gmtmex)

# install gmt/mex external function interface and driver shell script
install (PROGRAMS gmt.m gmtmex.${MEX_EXT}
DESTINATION ${GMT_BINDIR}
COMPONENT Runtime)
9 changes: 9 additions & 0 deletions src/gmtmex/README.gmtmex
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#
Distributed under the GNU Lesser Public License; see file
LICENSE.TXT in main GMT directory.

GMT 5 Release introduced a full set of Matlab interface functions
for all GMT modules. GMT 6 continued this work, and GMT 6.1 made
some internal changes, necessitating GMTMEX 2.0.0

See documentation for usage.
223 changes: 223 additions & 0 deletions src/gmtmex/gmt.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
function varargout = gmt(cmd, varargin)
% Helper function to call the gmtmex MEX function

if (nargin == 0)
fprintf(sprintf('\n\t\tGMT - The Generic Mapping Tools, Version 6.1 API\n'))
fprintf(sprintf('Copyright 1991-2020 The GMT Team (https://www.generic-mapping-tools.org/team.html\n\n'))

fprintf(sprintf('Usage:\tTo call a GMT module:\n\t output = gmt (''module_name'', ''options'', numeric_input)\n\n'))
fprintf(sprintf(['\tTo create a Grid structure from a 2-D Z array and a 1x9 header vector:\n\t' ...
' G = gmt (''wrapgrid'', Z, head)\n' ...
'\theader is a vector with [x_min x_max, y_min y_max z_min z_max reg x_inc y_inc]\n\n']))
fprintf(sprintf(['\tTo create an Image structure from a 2-D img array and a 1x9 header vector:\n\t' ...
' I = gmt (''wrapimage'', img, header [, cmap])\n' ...
'\theader is a vector with [x_min x_max, y_min y_max z_min z_max reg x_inc y_inc].\n' ...
'\tcmap is an optional color palette structure or a Matlab Mx3 cmap array (not yet).\n\n']))
fprintf(sprintf(['\tTo create a structure for a multi-segment dataset:\n\t' ...
' D = gmt (''wrapseg'', {[1 0; 1 1], [5 5; 56]}, {''Seg1'', ''Seg2''})\n\n']))
fprintf(sprintf(['\tTo create a structure with numeric and text good for use in pstext:\n\t' ...
' R = gmt (''record'', [1 0; 1 1], {''Text1'', ''Text2''})\n\n']))
fprintf(sprintf(['\tTo join two color palette structures:\n\t' ...
' cpt = gmt (''catcpt'', cpt1, cpt2)\n\n']))
fprintf(sprintf(['\tTo merge all data segments from an array of Data structures:\n\t' ...
' all = gmt (''catseg'', segments[, 1])\n\t' ...
'The optional 2nd argument will insert a NaN-record at the start of each segment.\n']))
return
end

if (strcmp(cmd,'wrapgrid') || strcmp(cmd,'wrapimage') || strcmp(cmd,'catcpt') || strncmp(cmd,'catseg',6) || ...
strcmp(cmd,'wrapseg') || strcmp(cmd,'record'))
[varargout{1:nargout}] = feval (cmd, varargin{:});
else
[varargout{1:nargout}] = gmtmex (cmd, varargin{:});
end

% -------------------------------------------------------------------------------------------------
function all = catseg(varargin)
all = catsegment(varargin{:});

function all = catsegment(A, header)
% MERGE Combine all segment arrays to a single array
% all = catsegment (A, opt)
%
% Concatenate all data segment arrays in the structures A
% into a single array. If the optional argument opt is given
% the we start each segment with a NaN record.

n_segments = length(A); n = 0;
[nr, nc] = size (A(1).data); % Get # columns from first segment
for k = 1:n_segments % Count total rows
n = n + length(A(k).data);
end
if nargin == 2 % Need to add a NaN-record per segment
all = zeros (n+n_segments, nc);
else
all = zeros (n, nc);
end
n = 1;
for k = 1:n_segments
[nr, nc] = size (A(k).data);
if nargin == 2 % Add NaN-record
all(n,:) = NaN;
n = n + 1;
end
all(n:(n+nr-1),:) = A(k).data;
n = n + nr;
end

% -------------------------------------------------------------------------------------------------
function cpt = catcpt(cpt1, cpt2)
% Join two CPT1 and CPT2 color palette structures.
% Note, the two palettes must be continuous across its common border. No testing on that is done here.
% NOT COMPLETE. NEEDS THE CPT, MODEL & COMMENT FIELDS

if (nargin ~= 2)
error(' Must provide 2 input arguments.')
elseif (cpt1.depth ~= cpt2.depth)
error(' Cannot join two palettes that have different bit depths.')
end
if (size(cpt1.colormap,1) ~= size(cpt1.range))
% A continuous palette so the join would have one color in excess. We could average
% the top cpt1 color and bottom cpt2 but that would blur the transition.
%cpt.colormap = [cpt1.colormap(1:end-1,:); (cpt1.colormap(end,:)+cpt2.colormap(1,:))/2; cpt2.colormap(2:end,:)];
cpt.colormap = [cpt1.colormap(1:end-1,:); cpt2.colormap];
cpt.alpha = [cpt1.alpha(1:end-1,:); cpt2.alpha];
else
cpt.colormap = [cpt1.colormap; cpt2.colormap];
cpt.alpha = [cpt1.alpha; cpt2.alpha];
end
cpt.range = [cpt1.range; cpt2.range];
cpt.minmax = [cpt1.minmax(1) cpt2.minmax(2)];
cpt.bfn = cpt1.bfn; % Just keep the first one
cpt.depth = cpt1.depth;

% -------------------------------------------------------------------------------------------------
function G = wrapgrid(Z, head)
% Fill the Grid struct used in gmtmex. HEAD is the old 1x9 header vector.

if (nargin ~= 2)
error(' Must provide 2 input arguments.')
elseif (size(Z,1) < 2 || size(Z,2) < 2)
error(' First argument must be a decent 2D array.')
elseif (any(size(head) ~= [1 9]))
error(' Second argument must be a 1x9 header vector.')
end

if (~isa(head, 'double')), head = double(head); end
G.proj4 = '';
G.wkt = '';
G.range = head(1:6);
G.inc = head(8:9);
G.registration = head(7);
G.nodata = NaN;
G.title = '';
G.comment = '';
G.command = '';
G.datatype = 'float32';
G.x = linspace(head(1), head(2), size(Z,2));
G.y = linspace(head(3), head(4), size(Z,1));
G.z = Z;
G.x_unit = '';
G.y_unit = '';
G.z_unit = '';

% -------------------------------------------------------------------------------------------------
function I = wrapimage(img, head, cmap)
% Fill the Image struct used in gmtmex. HEAD is the old 1x9 header vector.

if (nargin < 2)
error(' Must provide at least 2 input arguments.')
end
if (size(img,1) < 2 || size(img,2) < 2)
error(' First argument must be a decent 2D image array.')
elseif (any(size(head) ~= [1 9]))
error(' Second argument must be a 1x9 header vector.')
end

if (~isa(head, 'double')), head = double(head); end
I.proj4 = '';
I.wkt = '';
I.range = head(1:6);
I.inc = head(8:9);
I.nodata = NaN;
I.registration = head(7);
I.title = '';
I.comment = '';
I.command = '';
I.datatype = 'uint8';
I.x = linspace(head(1), head(2), size(img,2));
I.y = linspace(head(3), head(4), size(img,1));
I.image = img;
I.x_unit = '';
I.y_unit = '';
I.z_unit = '';
if (nargin == 3)
if (~isa(cmap, 'struct'))
% TODO: write a function that converts from Mx3 Matlab cmap to color struct used in MEX
error('The third argin (cmap) must be a colormap struct.')
end
I.colormap = cmap;
else
I.colormap = [];
end
if (size(img,3) == 4) % Not obvious that this is the best choice
I.alpha = img(:,:,4);
else
I.alpha = [];
end
I.layout = 'TCBa';

% -------------------------------------------------------------------------------------------------
function D = wrapseg(in, headers, text, comm, proj_s, wkt_s)
% Fill the Dataset struct used in gmtmex.
% IN -> A cell array of matrices where each matrix is a segment.
% HEADERS, TEXT, COMM, PROJ_S & WKT_S are all optional and can either be empty, char strings or cell
% arrays of text with the exact same size of input data IN which must also be a cell array (numeric).
% HEADERS -> multi-segment header info (a cell array of strings o a single text line)
% TEXT -> any text that may follow numeric columns (a cell array of strings or a single text line)
% COMM -> Commentary describing this datase (a text string)
% PROJ_S -> A text string with a PROJ4 projection string
% WKT_S -> A text string with a WKT projection string

if (nargin == 0), error('Wrong number of input arguments'), end
if (~isa(in, 'cell')), error('Only cell arrays of matrices are accepted in first argument'), end
if (~exist('headers', 'var') || isempty(headers)), headers = cell(size(in)); end
if (~exist('text', 'var') || isempty(text)), text = cell(size(in)); end
if (~exist('comm', 'var') || isempty(comm)), comm = cell(size(in)); end
if (~exist('proj_s', 'var') || isempty(proj_s)), proj_s = cell(size(in)); end
if (~exist('wkt_s', 'var') || isempty(wkt_s)), wkt_s = cell(size(in)); end
if (isa(comm, 'char')) % If allocated above this test is false
comment = cell(size(in)); comment{1} = comm;
else
comment = comm;
end
if (isa(proj_s, 'char'))
proj4 = cell(size(in)); proj4{1} = proj_s;
else
proj4 = proj_s;
end
if (isa(wkt_s, 'char'))
wkt = cell(size(in)); wkt{1} = wkt_s;
else
wkt = wkt_s;
end
if (~isequal(size(in), size(headers)) || ~isequal(size(headers), size(text)) || ~isequal(size(text), size(comm)) || ...
~isequal(size(comm), size(proj_s)) || ~isequal(size(proj_s), size(wkt_s)))
error('All cell arrays must be of the same size/shape. Can''t mix row and column cell vectors')
end
D = struct('data',in, 'header',headers, 'text',text, 'comment',comment, 'proj4',proj4, 'wkt',wkt);

% -------------------------------------------------------------------------------------------------
function R = record(data, text)
% Simplifies creating one or more GMT records on the fly
R.data = data;
if (ischar(text))
R.text = text;
else
[n,m] = size(text);
if (n == 1)
R.text = text';
else
R.text = text;
end
end
Loading