├── CMakeLists.txt
├── Docs
├── MatlabBridgeDesign.pptx
├── logo
│ ├── MatlabBridgeLogo.png
│ ├── MatlabBridgeLogo.xcf
│ ├── MatlabBridgeLogo_128x128.png
│ ├── MatlabModuleGenerator.xcf
│ └── description.txt
└── tutorial
│ ├── MatlabBridgeTutorial.pdf
│ └── MatlabBridgeTutorial.ppt
├── Examples
├── FillAroundSeeds
│ ├── FillAroundSeeds.bat
│ ├── FillAroundSeeds.m
│ └── FillAroundSeeds.xml
├── LandmarkRegistration
│ ├── LandmarkRegistration.bat
│ ├── LandmarkRegistration.m
│ ├── LandmarkRegistration.xml
│ └── absor.m
├── MatlabBridgeParameterPassingTest
│ ├── MatlabBridgeParameterPassingTest.bat
│ ├── MatlabBridgeParameterPassingTest.m
│ └── MatlabBridgeParameterPassingTest.xml
└── MeshScale
│ ├── MeshScale.bat
│ ├── MeshScale.m
│ └── MeshScale.xml
├── MatlabBridge.png
├── MatlabCommander
├── CMakeLists.txt
├── MatlabCommander.cxx
├── MatlabCommander.xml
└── commandserver
│ ├── cli_argsread.m
│ ├── cli_argswrite.m
│ ├── cli_commandserver.m
│ ├── cli_geometryread.m
│ ├── cli_geometrywrite.m
│ ├── cli_imageread.m
│ ├── cli_imagewrite.m
│ ├── cli_lineartransformread.m
│ ├── cli_lineartransformwrite.m
│ ├── cli_measurementread.m
│ ├── cli_measurementwrite.m
│ ├── cli_pointfileread.m
│ ├── cli_pointfilewrite.m
│ ├── cli_pointvectordecode.m
│ ├── cli_stringvectordecode.m
│ ├── cli_transformread.m
│ ├── cli_transformwrite.m
│ ├── cli_version.m.in
│ ├── fcsvwrite.m
│ ├── nrrdaddmetafield.m
│ ├── nrrdread.m
│ ├── nrrdwrite.m
│ ├── read_ply.m
│ ├── stlread.m
│ ├── stlwrite.m
│ └── write_ply.m
├── MatlabModuleGenerator
├── CMakeLists.txt
├── Logic
│ ├── CMakeLists.txt
│ ├── vtkSlicerMatlabModuleGeneratorLogic.cxx
│ └── vtkSlicerMatlabModuleGeneratorLogic.h
├── Resources
│ ├── Icons
│ │ └── MatlabModuleGenerator.png
│ ├── Templates
│ │ ├── MatlabModuleTemplate
│ │ ├── MatlabModuleTemplate.bat
│ │ ├── MatlabModuleTemplate.m
│ │ └── MatlabModuleTemplate.xml
│ ├── UI
│ │ └── qSlicerMatlabModuleGeneratorModuleWidget.ui
│ └── qSlicerMatlabModuleGeneratorModule.qrc
├── Testing
│ ├── CMakeLists.txt
│ └── Cxx
│ │ └── CMakeLists.txt
├── qSlicerMatlabModuleGeneratorModule.cxx
├── qSlicerMatlabModuleGeneratorModule.h
├── qSlicerMatlabModuleGeneratorModuleWidget.cxx
└── qSlicerMatlabModuleGeneratorModuleWidget.h
└── README.md
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.5)
2 |
3 | project(MatlabBridge)
4 |
5 | #-----------------------------------------------------------------------------
6 | OPTION(MATLABBRIDGE_ENABLE_MATLAB_TESTING "Enable using of Matlab for testing. Turn this option requires Matlab to be installed on this computer." OFF)
7 |
8 | # ------------------------------------------------------------------------
9 | set(MATLABBRIDGE_VERSION_MAJOR "0")
10 | set(MATLABBRIDGE_VERSION_MINOR "14")
11 | set(MATLABBRIDGE_VERSION_PATCH "0")
12 | set(MATLABBRIDGE_VERSION ${MATLABBRIDGE_VERSION_MAJOR}.${MATLABBRIDGE_VERSION_MINOR}.${MATLABBRIDGE_VERSION_PATCH})
13 |
14 | #-----------------------------------------------------------------------------
15 | set(EXTENSION_HOMEPAGE "https://www.slicer.org/slicerWiki/index.php/Documentation/Nightly/Extensions/MatlabBridge")
16 | set(EXTENSION_CATEGORY "Developer Tools")
17 | set(EXTENSION_CONTRIBUTORS "Andras Lasso (PerkLab, Queen's University), Jean-Christophe Fillion-Robin (Kitware), Kevin Wang (Radiation Medicine Program, Princess Margaret Hospital, University Health Network Toronto)")
18 | set(EXTENSION_DESCRIPTION "The Matlab Bridge extension allows running Matlab scripts as command-line interface (CLI) modules directly from 3D Slicer. The only prerequisites for running Matlab scripts are having this extension and Matlab installed on the 3D Slicer computer (building of 3D Slicer, MEX files, etc. is not needed). Extension version: ${MATLABBRIDGE_VERSION}.")
19 | set(EXTENSION_ICONURL "https://www.slicer.org/slicerWiki/images/e/e8/MatlabBridgeLogo.png")
20 | set(EXTENSION_SCREENSHOTURLS "https://www.slicer.org/slicerWiki/images/2/2f/MatlabBridgeScreenshot1.png https://www.slicer.org/slicerWiki/images/1/16/MatlabBridgeScreenshot2.png https://www.slicer.org/slicerWiki/images/b/b9/MatlabBridgeScreenshot3.png")
21 | set(EXTENSION_DEPENDS SlicerOpenIGTLink)
22 |
23 | #-----------------------------------------------------------------------------
24 | find_package(Slicer REQUIRED)
25 | include(${Slicer_USE_FILE})
26 |
27 | #-----------------------------------------------------------------------------
28 | add_subdirectory(MatlabCommander)
29 | add_subdirectory(MatlabModuleGenerator )
30 |
31 | #-----------------------------------------------------------------------------
32 | include(${Slicer_EXTENSION_GENERATE_CONFIG})
33 | include(${Slicer_EXTENSION_CPACK})
34 |
--------------------------------------------------------------------------------
/Docs/MatlabBridgeDesign.pptx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PerkLab/SlicerMatlabBridge/e9b297dbb6248be91a44013a85e21ff0fd8d13fd/Docs/MatlabBridgeDesign.pptx
--------------------------------------------------------------------------------
/Docs/logo/MatlabBridgeLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PerkLab/SlicerMatlabBridge/e9b297dbb6248be91a44013a85e21ff0fd8d13fd/Docs/logo/MatlabBridgeLogo.png
--------------------------------------------------------------------------------
/Docs/logo/MatlabBridgeLogo.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PerkLab/SlicerMatlabBridge/e9b297dbb6248be91a44013a85e21ff0fd8d13fd/Docs/logo/MatlabBridgeLogo.xcf
--------------------------------------------------------------------------------
/Docs/logo/MatlabBridgeLogo_128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PerkLab/SlicerMatlabBridge/e9b297dbb6248be91a44013a85e21ff0fd8d13fd/Docs/logo/MatlabBridgeLogo_128x128.png
--------------------------------------------------------------------------------
/Docs/logo/MatlabModuleGenerator.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PerkLab/SlicerMatlabBridge/e9b297dbb6248be91a44013a85e21ff0fd8d13fd/Docs/logo/MatlabModuleGenerator.xcf
--------------------------------------------------------------------------------
/Docs/logo/description.txt:
--------------------------------------------------------------------------------
1 | Image source: http://commons.wikimedia.org/wiki/File:Matlab_Logo.png
--------------------------------------------------------------------------------
/Docs/tutorial/MatlabBridgeTutorial.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PerkLab/SlicerMatlabBridge/e9b297dbb6248be91a44013a85e21ff0fd8d13fd/Docs/tutorial/MatlabBridgeTutorial.pdf
--------------------------------------------------------------------------------
/Docs/tutorial/MatlabBridgeTutorial.ppt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PerkLab/SlicerMatlabBridge/e9b297dbb6248be91a44013a85e21ff0fd8d13fd/Docs/tutorial/MatlabBridgeTutorial.ppt
--------------------------------------------------------------------------------
/Examples/FillAroundSeeds/FillAroundSeeds.bat:
--------------------------------------------------------------------------------
1 | @set MODULE_NAME=FillAroundSeeds
2 | @rem MatlabBridge proxy version: 1.0
3 |
4 | @echo off
5 | if not "%~1"=="--xml" goto :launch_module
6 |
7 | :print_xml
8 | rem Print CLI descriptor XML
9 | type %MODULE_NAME%.xml
10 | rem Return with success
11 | exit /b 0
12 |
13 | :launch_module
14 | rem Print error messages if any of the required environment variables are not set
15 | if not defined SLICER_MATLAB_COMMANDER_PATH echo ERROR: SLICER_MATLAB_COMMANDER_PATH environment variable is not defined. Make sure you installed the MatlabBridge extension.
16 | if not defined SLICER_MATLAB_COMMAND_SERVER_SCRIPT_PATH echo ERROR: SLICER_MATLAB_COMMAND_SERVER_SCRIPT_PATH environment variable is not defined. Make sure you installed the MatlabBridge extension.
17 | if not defined SLICER_MATLAB_EXECUTABLE_PATH echo ERROR: SLICER_MATLAB_EXECUTABLE_PATH environment variable is not defined. Make sure you installed the MatlabBridge extension and set the path to the Matlab executable.
18 | rem Make the .bat file location to be the working directory (that's where the MatlabCommander.exe is)
19 | pushd "%~dp0"
20 | rem Forward parameters to the Matlab CLI
21 | "%SLICER_HOME%/Slicer.exe" --launcher-no-splash --launch %SLICER_MATLAB_COMMANDER_PATH% --call-matlab-function %MODULE_NAME% %*
22 | if errorlevel 1 exit /b 1
23 | rem Return with success
24 | exit /b 0
25 |
--------------------------------------------------------------------------------
/Examples/FillAroundSeeds/FillAroundSeeds.m:
--------------------------------------------------------------------------------
1 | function outputParams=FillAroundSeeds(inputParams)
2 | % Example function for filling the image with a selected intensity around the chosen seed points
3 | %
4 | % Parameters:
5 | % inputParams.seed: seed locations
6 | % inputParams.radius: radius around the seed for filling (in mm)
7 | % inputParams.fillvalue: pixel value to fill
8 | % inputParams.unnamed{1}: input image filename
9 | % inputParams.unnamed{2}: output image filename (value is 0 if below threshold, 100 if above threshold)
10 | %
11 |
12 | img=cli_imageread(inputParams.inputvolume);
13 |
14 | seeds_LPS=cli_pointvectordecode(inputParams.seed);
15 | [seedDim seedCount]=size(seeds_LPS);
16 | radius_LPS=[inputParams.radius inputParams.radius inputParams.radius 0]';
17 | radius_IJK=abs(round(img.ijkToLpsTransform\radius_LPS));
18 | for seedIndex=1:seedCount
19 | seed_IJK=round(img.ijkToLpsTransform\[seeds_LPS(:,seedIndex); 1]);
20 | img.pixelData(seed_IJK(1)-radius_IJK(1):seed_IJK(1)+radius_IJK(1),seed_IJK(2)-radius_IJK(2):seed_IJK(2)+radius_IJK(2),seed_IJK(3)-radius_IJK(3):seed_IJK(3)+radius_IJK(3))=ones(radius_IJK(1)*2+1,radius_IJK(2)*2+1,radius_IJK(3)*2+1)*inputParams.fillvalue;
21 | end
22 |
23 | cli_imagewrite(inputParams.outputvolume, img);
24 |
--------------------------------------------------------------------------------
/Examples/FillAroundSeeds/FillAroundSeeds.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Matlab
4 | FillAroundSeeds
5 |
6 | 0.0.0.1
7 | http://www.slicer.org/slicerWiki/index.php/Documentation/Nightly/Extensions/MatlabBridge
8 |
9 | Andras Lasso (PerkLab)
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | seed
18 | 0,0,0
19 |
20 |
21 |
22 |
23 | fillvalue
24 | 500
25 |
26 | -1000
27 | 1000
28 | 5
29 |
30 |
31 |
32 |
33 |
34 | radius
35 | 5
36 |
37 | 0.5
38 | 50
39 | 0.5
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | inputvolume
50 | input
51 |
52 |
53 |
54 |
55 | outputvolume
56 | output
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/Examples/LandmarkRegistration/LandmarkRegistration.bat:
--------------------------------------------------------------------------------
1 | @set MODULE_NAME=LandmarkRegistration
2 | @rem MatlabBridge proxy version: 1.0
3 |
4 | @echo off
5 | if not "%~1"=="--xml" goto :launch_module
6 |
7 | :print_xml
8 | rem Print CLI descriptor XML
9 | type %MODULE_NAME%.xml
10 | rem Return with success
11 | exit /b 0
12 |
13 | :launch_module
14 | rem Print error messages if any of the required environment variables are not set
15 | if not defined SLICER_MATLAB_COMMANDER_PATH echo ERROR: SLICER_MATLAB_COMMANDER_PATH environment variable is not defined. Make sure you installed the MatlabBridge extension.
16 | if not defined SLICER_MATLAB_COMMAND_SERVER_SCRIPT_PATH echo ERROR: SLICER_MATLAB_COMMAND_SERVER_SCRIPT_PATH environment variable is not defined. Make sure you installed the MatlabBridge extension.
17 | if not defined SLICER_MATLAB_EXECUTABLE_PATH echo ERROR: SLICER_MATLAB_EXECUTABLE_PATH environment variable is not defined. Make sure you installed the MatlabBridge extension and set the path to the Matlab executable.
18 | rem Make the .bat file location to be the working directory (that's where the MatlabCommander.exe is)
19 | pushd "%~dp0"
20 | rem Forward parameters to the Matlab CLI
21 | "%SLICER_HOME%/Slicer.exe" --launcher-no-splash --launch %SLICER_MATLAB_COMMANDER_PATH% --call-matlab-function %MODULE_NAME% %*
22 | if errorlevel 1 exit /b 1
23 | rem Return with success
24 | exit /b 0
25 |
--------------------------------------------------------------------------------
/Examples/LandmarkRegistration/LandmarkRegistration.m:
--------------------------------------------------------------------------------
1 | function outputParams=LandmarkRegistration(inputParams)
2 | % Example function that computes a rigid similarity transform between two sets of points
3 |
4 | fixedPoints=cli_pointvectordecode(inputParams.fixedpoints);
5 | movingPoints=cli_pointvectordecode(inputParams.movingpoints);
6 | doScale=isfield(inputParams,'enablescaling');
7 |
8 | [regParams,Bfit,ErrorStats]=absor(fixedPoints,movingPoints,'doScale',doScale);
9 |
10 | outputParams.lsqerror=ErrorStats.errlsq;
11 | outputParams.maxerror=ErrorStats.errmax;
12 |
13 | cli_lineartransformwrite(inputParams.movingtofixedtransform,regParams.M);
14 |
--------------------------------------------------------------------------------
/Examples/LandmarkRegistration/LandmarkRegistration.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Matlab
4 | Landmark Registration
5 |
6 | 0.0.0.1
7 | http://www.slicer.org/slicerWiki/index.php/Documentation/Nightly/Extensions/MatlabBridge
8 |
9 | Andras Lasso (PerkLab)
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | fixedpoints
18 | 0,0,0
19 |
20 |
21 |
22 |
23 | movingpoints
24 | 0,0,0
25 |
26 |
27 |
28 |
29 | enablescaling
30 | true
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | movingtofixedtransform
40 | output
41 |
42 |
43 |
44 |
45 | lsqerror
46 | output
47 |
48 |
49 |
50 |
51 |
52 | maxerror
53 | output
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/Examples/LandmarkRegistration/absor.m:
--------------------------------------------------------------------------------
1 | function [regParams,Bfit,ErrorStats]=absor(A,B,varargin)
2 | %ABSOR - a tool for solving the absolute orientation problem using Horn's
3 | %quaternion-based method, that is, for finding the rotation, translation, and
4 | %optionally also the scaling, that best maps one collection of point coordinates
5 | %to another in a least squares sense. The function works for both 2D and 3D
6 | %coordinates, and also gives the option of weighting the coordinates non-uniformly.
7 | %The code avoids for-loops to maximize speed.
8 | %
9 | %DESCRIPTION:
10 | %
11 | %As input data, one has
12 | %
13 | % A: a 2xN or 3xN matrix whos columns are the coordinates of N source points.
14 | % B: a 2xN or 3xN matrix whos columns are the coordinates of N target points.
15 | %
16 | %The syntax
17 | %
18 | % [regParams,Bfit,ErrorStats]=absor(A,B)
19 | %
20 | %solves the unweighted/unscaled registration problem
21 | %
22 | % min. sum_i ||R*A(:,i) + t - B(:,i)||^2
23 | %
24 | %for unknown rotation matrix R and unknown translation vector t.
25 | %
26 | %This is a special case of the more general problem
27 | %
28 | % min. sum_i w(i)*||s*R*A(:,i) + t - B(:,i)||^2
29 | %
30 | %where s>=0 is an unknown global scale factor to be estimated along with R and t
31 | %and w is a user-supplied length N vector of weights. One can include either
32 | %s or w or both in the problem formulation using the syntax,
33 | %
34 | % [regParams,Bfit,ErrorStats]=absor(A,B,'param1',value1,'param2',value2,...)
35 | %
36 | %with parameter/value pair options
37 | %
38 | % 'doScale' - Boolean flag. If TRUE, the global scale factor, s, is included.
39 | % Default=FALSE.
40 | %
41 | % 'weights' - the length N-vector of weights, w. Default, no weighting.
42 | %
43 | %
44 | %
45 | %out:
46 | %
47 | %
48 | % regParams: structure output with estimated registration parameters,
49 | %
50 | % regParams.R: The estimated rotation matrix, R
51 | % regParams.t: The estimated translation vector, t
52 | % regParams.s: The estimated scale factor (set to 1 if doScale=false).
53 | % regParams.M: Homogenous coordinate transform matrix [s*R,t;[0 0 ... 1]].
54 | %
55 | % For 3D problems, the structure includes
56 | %
57 | % regParams.q: A unit quaternion [q0 qx qy qz] corresponding to R and
58 | % signed to satisfy max(q)=max(abs(q))>0
59 | %
60 | % For 2D problems, it includes
61 | %
62 | % regParams.theta: the counter-clockwise rotation angle about the
63 | % 2D origin
64 | %
65 | %
66 | % Bfit: The rotation, translation, and scaling (as applicable) of A that
67 | % best matches B.
68 | %
69 | %
70 | % ErrorStats: structure output with error statistics. In particular,
71 | % defining err(i)=sqrt(w(i))*norm( Bfit(:,i)-B(:,i) ),
72 | % it contains
73 | %
74 | % ErrorStats.errlsq = norm(err)
75 | % ErrorStats.errmax = max(err)
76 | %
77 | %
78 | %
79 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
80 | % Author: Matt Jacobson
81 | % Copyright, Xoran Technologies, Inc. http://www.xorantech.com
82 |
83 |
84 | %%Input option processing and set up
85 |
86 | options.doScale = 0;
87 | options.weights = [];
88 |
89 | for ii=1:2:length(varargin)
90 | param=varargin{ii};
91 | val=varargin{ii+1};
92 | if strcmpi(param,'doScale'),
93 | options.doScale=val;
94 | elseif strcmpi(param,'weights')
95 | options.weights=val;
96 | else
97 | error(['Option ''' param ''' not recognized']);
98 | end
99 | end
100 |
101 | doScale = options.doScale;
102 | weights = options.weights;
103 |
104 |
105 |
106 | if ~isempty(which('bsxfun'))
107 | matmvec=@(M,v) bsxfun(@minus,M,v); %matrix-minus-vector
108 | mattvec=@(M,v) bsxfun(@times,M,v); %matrix-minus-vector
109 | else
110 | matmvec=@matmvecHandle;
111 | mattvec=@mattvecHandle;
112 | end
113 |
114 |
115 | dimension=size(A,1);
116 |
117 | if dimension~=size(B,1),
118 | error 'The number of points to be registered must be the same'
119 | end
120 |
121 |
122 | %%Centering/weighting of input data
123 |
124 |
125 | if isempty(weights)
126 |
127 | sumwts=1;
128 |
129 | lc=mean(A,2); rc=mean(B,2); %Centroids
130 | left = matmvec(A,lc); %Center coordinates at centroids
131 | right = matmvec(B,rc);
132 |
133 | else
134 |
135 | sumwts=sum(weights);
136 |
137 | weights=full(weights)/sumwts;
138 | weights=weights(:);
139 | sqrtwts=sqrt(weights.');
140 |
141 |
142 | lc=A*weights; rc=B*weights; %weighted centroids
143 |
144 | left = matmvec(A,lc);
145 | left = mattvec(left,sqrtwts);
146 | right = matmvec(B,rc);
147 | right = mattvec(right,sqrtwts);
148 |
149 | end
150 |
151 | M=left*right.';
152 |
153 |
154 | %%Compute rotation matrix
155 |
156 | switch dimension
157 |
158 | case 2
159 |
160 |
161 | Nxx=M(1)+M(4); Nyx=M(3)-M(2);
162 |
163 | N=[Nxx Nyx;...
164 | Nyx -Nxx];
165 |
166 | [V,D]=eig(N);
167 |
168 | [trash,emax]=max(real( diag(D) )); emax=emax(1);
169 |
170 | q=V(:,emax); %Gets eigenvector corresponding to maximum eigenvalue
171 | q=real(q); %Get rid of imaginary part caused by numerical error
172 |
173 |
174 | q=q*sign(q(2)+(q(2)>=0)); %Sign ambiguity
175 | q=q./norm(q);
176 |
177 | R11=q(1)^2-q(2)^2;
178 | R21=prod(q)*2;
179 |
180 | R=[R11 -R21;R21 R11]; %map to orthogonal matrix
181 |
182 |
183 |
184 |
185 | case 3
186 |
187 | [Sxx,Syx,Szx, Sxy,Syy,Szy, Sxz,Syz,Szz]=dealr(M(:));
188 |
189 | N=[(Sxx+Syy+Szz) (Syz-Szy) (Szx-Sxz) (Sxy-Syx);...
190 | (Syz-Szy) (Sxx-Syy-Szz) (Sxy+Syx) (Szx+Sxz);...
191 | (Szx-Sxz) (Sxy+Syx) (-Sxx+Syy-Szz) (Syz+Szy);...
192 | (Sxy-Syx) (Szx+Sxz) (Syz+Szy) (-Sxx-Syy+Szz)];
193 |
194 | [V,D]=eig(N);
195 |
196 | [trash,emax]=max(real( diag(D) )); emax=emax(1);
197 |
198 | q=V(:,emax); %Gets eigenvector corresponding to maximum eigenvalue
199 | q=real(q); %Get rid of imaginary part caused by numerical error
200 |
201 | [trash,ii]=max(abs(q)); sgn=sign(q(ii(1)));
202 | q=q*sgn; %Sign ambiguity
203 |
204 | %map to orthogonal matrix
205 |
206 | quat=q(:);
207 | nrm=norm(quat);
208 | if ~nrm
209 | 'Quaternion distribution is 0'
210 | end
211 |
212 | quat=quat./norm(quat);
213 |
214 | q0=quat(1);
215 | qx=quat(2);
216 | qy=quat(3);
217 | qz=quat(4);
218 | v =quat(2:4);
219 |
220 |
221 | Z=[q0 -qz qy;...
222 | qz q0 -qx;...
223 | -qy qx q0 ];
224 |
225 | R=v*v.' + Z^2;
226 |
227 | otherwise
228 | error 'Points must be either 2D or 3D'
229 |
230 | end
231 |
232 | %%
233 |
234 | if doScale
235 |
236 | summ = @(M) sum(M(:));
237 |
238 | sss=summ( right.*(R*left))/summ(left.^2);
239 | t=rc-R*(lc*sss);
240 |
241 |
242 | else
243 |
244 | sss=1;
245 | t=rc-R*lc;
246 |
247 |
248 | end
249 |
250 |
251 | regParams.R=R;
252 | regParams.t=t;
253 | regParams.s=sss;
254 |
255 |
256 | if dimension==2
257 |
258 | regParams.M=[sss*R,t;[0 0 1]];
259 | regParams.theta=atan2(q(2),q(1))*360/pi;
260 |
261 | else%dimension=3
262 |
263 | regParams.M=[sss*R,t;[0 0 0 1]];
264 | regParams.q=q/norm(q);
265 |
266 | end
267 |
268 | if nargout>1
269 |
270 | Bfit=matmvec((sss*R)*A,-t);
271 |
272 | end
273 |
274 | if nargout>2
275 |
276 | l2norm = @(M,dim) sqrt(sum(M.^2,dim));
277 |
278 | err=l2norm(Bfit-B,1);
279 |
280 | if ~isempty(weights), err=err.*sqrtwts; end
281 |
282 | ErrorStats.errlsq=norm(err)*sqrt(sumwts); %unnormalize the weights
283 | ErrorStats.errmax=max(err);
284 |
285 |
286 | end
287 |
288 |
289 |
290 |
291 | function M=matmvecHandle(M,v)
292 | %Matrix-minus-vector
293 |
294 | for ii=1:size(M,1)
295 | M(ii,:)=M(ii,:)-v(ii);
296 | end
297 |
298 | function M=mattvecHandle(M,v)
299 | %Matrix-times-vector
300 |
301 | for ii=1:size(M,1)
302 | M(ii,:)=M(ii,:).*v;
303 | end
304 |
305 | function varargout=dealr(v)
306 |
307 | varargout=num2cell(v);
308 |
309 |
310 |
311 |
312 | %Copyright (c) 2009, Matt Jacobson, Xoran Technologies, Inc. http://www.xorantech.com
313 | %All rights reserved.
314 | %
315 | %Redistribution and use in source and binary forms, with or without
316 | %modification, are permitted provided that the following conditions are
317 | %met:
318 | %
319 | % * Redistributions of source code must retain the above copyright
320 | % notice, this list of conditions and the following disclaimer.
321 | % * Redistributions in binary form must reproduce the above copyright
322 | % notice, this list of conditions and the following disclaimer in
323 | % the documentation and/or other materials provided with the distribution
324 | %
325 | %THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
326 | %AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
327 | %IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
328 | %ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
329 | %LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
330 | %CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
331 | %SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
332 | %INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
333 | %CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
334 | %ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
335 | %POSSIBILITY OF SUCH DAMAGE.
336 |
--------------------------------------------------------------------------------
/Examples/MatlabBridgeParameterPassingTest/MatlabBridgeParameterPassingTest.bat:
--------------------------------------------------------------------------------
1 | @set MODULE_NAME=MatlabBridgeParameterPassingTest
2 | @rem MatlabBridge proxy version: 1.0
3 |
4 | @echo off
5 | if not "%~1"=="--xml" goto :launch_module
6 |
7 | :print_xml
8 | rem Print CLI descriptor XML
9 | type %MODULE_NAME%.xml
10 | rem Return with success
11 | exit /b 0
12 |
13 | :launch_module
14 | rem Print error messages if any of the required environment variables are not set
15 | if not defined SLICER_MATLAB_COMMANDER_PATH echo ERROR: SLICER_MATLAB_COMMANDER_PATH environment variable is not defined. Make sure you installed the MatlabBridge extension.
16 | if not defined SLICER_MATLAB_COMMAND_SERVER_SCRIPT_PATH echo ERROR: SLICER_MATLAB_COMMAND_SERVER_SCRIPT_PATH environment variable is not defined. Make sure you installed the MatlabBridge extension.
17 | if not defined SLICER_MATLAB_EXECUTABLE_PATH echo ERROR: SLICER_MATLAB_EXECUTABLE_PATH environment variable is not defined. Make sure you installed the MatlabBridge extension and set the path to the Matlab executable.
18 | rem Make the .bat file location to be the working directory (that's where the MatlabCommander.exe is)
19 | pushd "%~dp0"
20 | rem Forward parameters to the Matlab CLI
21 | "%SLICER_HOME%/Slicer.exe" --launcher-no-splash --launch %SLICER_MATLAB_COMMANDER_PATH% --call-matlab-function %MODULE_NAME% %*
22 | if errorlevel 1 exit /b 1
23 | rem Return with success
24 | exit /b 0
25 |
--------------------------------------------------------------------------------
/Examples/MatlabBridgeParameterPassingTest/MatlabBridgeParameterPassingTest.m:
--------------------------------------------------------------------------------
1 | function outputParams=MatlabBridgeParameterPassingTest(inputParams)
2 | % Example function that returns the minimum and maximum voxel value in a volume
3 | % and performs thresholding operation on the volume.
4 | %
5 | % Parameters:
6 | % inputParams.threshold: threshold value
7 | % inputParams.unnamed{1}: input image filename
8 | % inputParams.unnamed{2}: output image filename (value is 0 if below threshold, 100 if above threshold)
9 | % outputParams.min: image minimum value
10 | % outputParams.max: image maximum value
11 | % etc.
12 | %
13 |
14 | % Read inputs
15 | integerValue=inputParams.integer
16 | doubleValue=inputParams.double
17 | floatVectorValue=inputParams.f
18 | stringVectorValue=cli_stringvectordecode(inputParams.string_vector)
19 | stringEnumerationValue=inputParams.enumeration
20 | boolean1Value=isfield(inputParams,'boolean1')
21 | boolean2Value=isfield(inputParams,'boolean2')
22 | boolean3Value=isfield(inputParams,'boolean3')
23 | filenameValue=inputParams.file1
24 | filenameListValue=cli_stringvectordecode(inputParams.files)
25 | directoryValue=cli_stringvectordecode(inputParams.directory1)
26 | imageValue=cli_imageread(inputParams.image1)
27 | transformValue=cli_lineartransformread(inputParams.transform1)
28 | regionValue=cli_pointvectordecode(inputParams.region);
29 | seedValue=inputParams.seed
30 | inputMeasurementFilenameValue=cli_measurementread(inputParams.inputFA)
31 | unnamedInputImageValue=cli_imageread(inputParams.unnamed{1});
32 | surfaceMeshValue = cli_geometryread(inputParams.model1);
33 |
34 | % Do some simple processing
35 |
36 | [regionDim regionCount]=size(regionValue);
37 | fillValue = 10;
38 | for regionIndex=1:regionCount
39 | center_IJK=round(imageValue.ijkToLpsTransform\[regionValue(1:3,regionIndex); 1])
40 | radius_IJK=abs(round(imageValue.ijkToLpsTransform\[regionValue(4:6,regionIndex); 0]))
41 | imageValue.pixelData(center_IJK(1)-radius_IJK(1):center_IJK(1)+radius_IJK(1),center_IJK(2)-radius_IJK(2):center_IJK(2)+radius_IJK(2),center_IJK(3)-radius_IJK(3):center_IJK(3)+radius_IJK(3))=ones(radius_IJK(1)*2+1,radius_IJK(2)*2+1,radius_IJK(3)*2+1)*fillValue;
42 | end
43 |
44 | scaleFactor = 1.2; % enlarge by 20%
45 | surfaceMeshValue.vertices = surfaceMeshValue.vertices * diag([scaleFactor scaleFactor scaleFactor]);
46 |
47 | % Write outputs
48 | outputParams.anintegerreturn=integerValue*10;
49 | outputParams.abooleanreturn=boolean1Value && boolean2Value && boolean3Value;
50 | outputParams.afloatreturn=123.456;
51 | outputParams.adoublereturn=246.81012;
52 | outputParams.astringreturn=['the input was ' stringEnumerationValue];
53 | outputParams.anintegervectorreturn=floatVectorValue*2;
54 | outputParams.astringchoicereturn=stringEnumerationValue;
55 |
56 | cli_imagewrite(inputParams.image2, imageValue); % Write the input image on the output unchanged
57 | cli_lineartransformwrite(inputParams.transform2,transformValue); % Write the input transform on the output unchanged
58 | cli_imagewrite(inputParams.unnamed{2},unnamedInputImageValue); % Write the input image on the output unchanged
59 | cli_measurementwrite(inputParams.outputFA, [inputMeasurementFilenameValue; 1 2 0.2; 2 4 0.3; 3 5 0.2]); % Write the input image on the output with a few extra numbers added
60 | cli_geometrywrite(inputParams.model2, surfaceMeshValue); % Write the input surface mesh on the output unchanged
61 |
--------------------------------------------------------------------------------
/Examples/MatlabBridgeParameterPassingTest/MatlabBridgeParameterPassingTest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Matlab
4 | MatlabBridge parameter passing test
5 |
6 | 0.1.0.$Revision: 21227 $(alpha)
7 | http://wiki.slicer.org/slicerWiki/index.php/Documentation/4.2/Modules/ExecutionModelTour
8 |
9 | Daniel Blezek (GE), Bill Lorensen (GE)
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | integer
18 | 30
19 |
20 |
21 |
22 |
23 | double
24 | 30
25 |
26 | 0
27 | 1.e3
28 | 10
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | f
39 | 1.3,2,-14
40 |
41 |
42 |
43 |
44 | string_vector
45 | foo,bar,foobar
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | enumeration
55 | Bill
56 | Ron
57 | Eric
58 | Bill
59 | Ross
60 | Steve
61 | Will
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 | boolean1
71 | true
72 |
73 |
74 |
75 |
76 | boolean2
77 | false
78 |
79 |
80 |
81 |
82 | boolean3
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 | file1
92 | input
93 |
94 |
95 |
96 |
97 | files
98 | input
99 |
100 |
101 |
102 |
103 | directory1
104 | input
105 |
106 |
107 |
108 |
109 | image1
110 | input
111 |
112 |
113 |
114 |
115 | image2
116 | output
117 |
118 |
119 |
120 |
121 | model1
122 | input
123 |
124 |
125 |
126 |
127 | model2
128 | output
129 |
130 |
131 |
132 |
133 | transform1
134 | input
135 |
136 |
137 |
138 |
139 | transform2
140 | output
141 |
142 |
143 |
144 |
145 | seed
146 | 0,0,0
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 | index0
156 | 0
157 | input
158 |
159 |
160 |
161 |
162 | index1
163 | 1
164 | output
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 | region
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 | inputFA
181 | input
182 |
183 |
184 |
185 |
186 | outputFA
187 | output
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 | anintegerreturn
196 | output
197 | 5
198 |
199 |
200 |
201 |
202 | abooleanreturn
203 | output
204 | false
205 |
206 |
207 |
208 |
209 | afloatreturn
210 | output
211 | 7.0
212 |
213 |
214 |
215 |
216 | adoublereturn
217 | output
218 | 14.0
219 |
220 |
221 |
222 |
223 | astringreturn
224 | output
225 | Hello
226 |
227 |
228 |
229 |
230 | anintegervectorreturn
231 | output
232 | 1,2,3
233 |
234 |
235 |
236 |
237 | astringchoicereturn
238 | output
239 | Bill
240 | Ron
241 | Eric
242 | Bill
243 | Ross
244 | Steve
245 | Will
246 |
247 |
248 |
249 |
--------------------------------------------------------------------------------
/Examples/MeshScale/MeshScale.bat:
--------------------------------------------------------------------------------
1 | @set MODULE_NAME=MeshScale
2 | @rem MatlabBridge proxy version: 1.0
3 |
4 | @echo off
5 | if not "%~1"=="--xml" goto :launch_module
6 |
7 | :print_xml
8 | rem Print CLI descriptor XML
9 | type %MODULE_NAME%.xml
10 | rem Return with success
11 | exit /b 0
12 |
13 | :launch_module
14 | rem Print error messages if any of the required environment variables are not set
15 | if not defined SLICER_MATLAB_COMMANDER_PATH echo ERROR: SLICER_MATLAB_COMMANDER_PATH environment variable is not defined. Make sure you installed the MatlabBridge extension.
16 | if not defined SLICER_MATLAB_COMMAND_SERVER_SCRIPT_PATH echo ERROR: SLICER_MATLAB_COMMAND_SERVER_SCRIPT_PATH environment variable is not defined. Make sure you installed the MatlabBridge extension.
17 | if not defined SLICER_MATLAB_EXECUTABLE_PATH echo ERROR: SLICER_MATLAB_EXECUTABLE_PATH environment variable is not defined. Make sure you installed the MatlabBridge extension and set the path to the Matlab executable.
18 | rem Make the .bat file location to be the working directory (that's where the MatlabCommander.exe is)
19 | pushd "%~dp0"
20 | rem Forward parameters to the Matlab CLI
21 | "%SLICER_HOME%/Slicer.exe" --launcher-no-splash --launch %SLICER_MATLAB_COMMANDER_PATH% --call-matlab-function %MODULE_NAME% %*
22 | if errorlevel 1 exit /b 1
23 | rem Return with success
24 | exit /b 0
25 |
--------------------------------------------------------------------------------
/Examples/MeshScale/MeshScale.m:
--------------------------------------------------------------------------------
1 | function outputParams=MeshScale(inputParams)
2 | % Example function that changes scales of a surface mesh
3 |
4 | mesh = cli_geometryread(inputParams.inputmesh);
5 |
6 | mesh.vertices = mesh.vertices * diag([inputParams.scalex inputParams.scaley inputParams.scalez]);
7 |
8 | cli_geometrywrite(inputParams.outputmesh, mesh);
9 |
--------------------------------------------------------------------------------
/Examples/MeshScale/MeshScale.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Matlab
4 | Change model scale
5 |
6 | 0.0.0.1
7 | http://www.slicer.org/slicerWiki/index.php/Documentation/Nightly/Extensions/MatlabBridge
8 |
9 | Andras Lasso (PerkLab)
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | inputmesh
18 | input
19 |
20 |
21 |
22 |
23 | scalex
24 | 1.5
25 |
26 | 0.1
27 | 10
28 | 0.1
29 |
30 |
31 |
32 |
33 |
34 | scaley
35 | 1.0
36 |
37 | 0.1
38 | 10
39 | 0.1
40 |
41 |
42 |
43 |
44 |
45 | scalez
46 | 0.8
47 |
48 | 0.1
49 | 10
50 | 0.1
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | outputmesh
61 | output
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/MatlabBridge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PerkLab/SlicerMatlabBridge/e9b297dbb6248be91a44013a85e21ff0fd8d13fd/MatlabBridge.png
--------------------------------------------------------------------------------
/MatlabCommander/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | #-----------------------------------------------------------------------------
2 | set(MODULE_NAME MatlabCommander)
3 |
4 | find_package(OpenIGTLink REQUIRED)
5 |
6 | include(${OpenIGTLink_USE_FILE})
7 |
8 | #-----------------------------------------------------------------------------
9 | set(MODULE_INCLUDE_DIRECTORIES
10 | ${OpenIGTLink_INCLUDE_DIRS}
11 | )
12 |
13 | set(MODULE_SRCS
14 | )
15 |
16 | set(MODULE_TARGET_LIBRARIES
17 | ${ITK_LIBRARIES}
18 | OpenIGTLink
19 | )
20 |
21 | #-----------------------------------------------------------------------------
22 | SEMMacroBuildCLI(
23 | NAME ${MODULE_NAME}
24 | TARGET_LIBRARIES ${MODULE_TARGET_LIBRARIES}
25 | INCLUDE_DIRECTORIES ${MODULE_INCLUDE_DIRECTORIES}
26 | ADDITIONAL_SRCS ${MODULE_SRCS}
27 | RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${Slicer_CLIMODULES_BIN_DIR}"
28 | LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${Slicer_CLIMODULES_LIB_DIR}"
29 | ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${Slicer_CLIMODULES_LIB_DIR}"
30 | #EXECUTABLE_ONLY
31 | )
32 |
33 | #-----------------------------------------------------------------------------
34 | if(BUILD_TESTING)
35 | #add_subdirectory(Testing)
36 | endif()
37 |
38 | #-----------------------------------------------------------------------------
39 |
40 | # Copy (and install) al cli_*.m script files
41 |
42 | file(GLOB SCRIPT_FILES
43 | RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/commandserver"
44 | "${CMAKE_CURRENT_SOURCE_DIR}/commandserver/*.m"
45 | )
46 |
47 | foreach(SCRIPT_FILE ${SCRIPT_FILES})
48 | configure_file(
49 | ${CMAKE_CURRENT_SOURCE_DIR}/commandserver/${SCRIPT_FILE}
50 | ${CMAKE_BINARY_DIR}/${Slicer_CLIMODULES_BIN_DIR}/commandserver/${SCRIPT_FILE}
51 | COPYONLY)
52 | install(
53 | FILES ${CMAKE_BINARY_DIR}/${Slicer_CLIMODULES_BIN_DIR}/commandserver/${SCRIPT_FILE}
54 | DESTINATION ${Slicer_INSTALL_CLIMODULES_BIN_DIR}/commandserver COMPONENT Runtime)
55 | endforeach()
56 |
57 | # Create (and install) version info function
58 |
59 | configure_file(
60 | ${CMAKE_CURRENT_SOURCE_DIR}/commandserver/cli_version.m.in
61 | ${CMAKE_BINARY_DIR}/${Slicer_CLIMODULES_BIN_DIR}/commandserver/cli_version.m)
62 | install(
63 | FILES ${CMAKE_BINARY_DIR}/${Slicer_CLIMODULES_BIN_DIR}/commandserver/cli_version.m
64 | DESTINATION ${Slicer_INSTALL_CLIMODULES_BIN_DIR}/commandserver COMPONENT Runtime)
65 |
--------------------------------------------------------------------------------
/MatlabCommander/MatlabCommander.cxx:
--------------------------------------------------------------------------------
1 | #include "MatlabCommanderCLP.h"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #include "igtlOSUtil.h"
9 | #include "igtlStringMessage.h"
10 | #include "igtlClientSocket.h"
11 |
12 | #include "vtksys/SystemTools.hxx"
13 | #include "vtksys/Process.h"
14 |
15 | const std::string CALL_MATLAB_FUNCTION_ARG="--call-matlab-function";
16 | const std::string EXIT_MATLAB_ARG="--exit-matlab";
17 | const std::string MATLAB_DEFAULT_HOST="127.0.0.1";
18 | const int MATLAB_DEFAULT_PORT=4100;
19 |
20 | const int MAX_MATLAB_STARTUP_TIME_SEC=60; // maximum time allowed for Matlab to start
21 |
22 | // If the Matlab function response string starts with this string then it means
23 | // the function execution failed
24 | const std::string RESPONSE_ERROR_PREFIX="ERROR:";
25 |
26 | enum ExecuteMatlabCommandStatus
27 | {
28 | COMMAND_STATUS_FAILED=0,
29 | COMMAND_STATUS_SUCCESS=1
30 | };
31 |
32 | std::string ReceiveString(igtl::Socket * socket, igtl::MessageHeader::Pointer& header)
33 | {
34 | // Create a message buffer to receive transform data
35 | igtl::StringMessage::Pointer stringMsg;
36 | stringMsg = igtl::StringMessage::New();
37 | stringMsg->SetMessageHeader(header);
38 | stringMsg->AllocatePack();
39 |
40 | // Receive transform data from the socket
41 | bool receiveTimedOut = false;
42 | int received=socket->Receive(stringMsg->GetPackBodyPointer(), stringMsg->GetPackBodySize(), receiveTimedOut);
43 | if (received!=stringMsg->GetPackBodySize())
44 | {
45 | std::cerr << "WARNING: failed to receive complete message body" << std::endl;
46 | }
47 | if (receiveTimedOut)
48 | {
49 | std::cerr << "WARNING: receiving timed out" << std::endl;
50 | }
51 |
52 | // Deserialize the transform data
53 | // If you want to skip CRC check, call Unpack() without argument.
54 | int c = stringMsg->Unpack();
55 |
56 | if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK
57 | {
58 | return stringMsg->GetString();
59 | }
60 |
61 | // error
62 | return "";
63 | }
64 |
65 | void SetReturnValues(const std::string &returnParameterFile,const char* reply, bool completed)
66 | {
67 | // Write out the return parameters in "name = value" form
68 | std::ofstream rts;
69 | rts.open(returnParameterFile.c_str() );
70 | rts << "reply = " << reply << std::endl;
71 | rts << "completed = " << (completed?"true":"false") << std::endl;
72 | rts.close();
73 | }
74 |
75 | // Returns true if execution is successful. Matlab start may take an additional minute after this function returns.
76 | bool StartMatlabServer()
77 | {
78 | const char* matlabExecutablePath=getenv("SLICER_MATLAB_EXECUTABLE_PATH");
79 | const char* matlabCommandServerScriptPath=getenv("SLICER_MATLAB_COMMAND_SERVER_SCRIPT_PATH");
80 |
81 | if ( matlabExecutablePath == NULL )
82 | {
83 | std::cerr << "ERROR: The SLICER_MATLAB_EXECUTABLE_PATH environment variable is not set. Cannot start the Matlab command server." << std::endl;
84 | return false;
85 | }
86 | if ( matlabCommandServerScriptPath == NULL )
87 | {
88 | std::cerr << "ERROR: The SLICER_MATLAB_COMMAND_SERVER_SCRIPT_PATH environment variable is not set. Cannot start the Matlab command server." << std::endl;
89 | return false;
90 | }
91 |
92 | if ( !vtksys::SystemTools::FileExists( matlabExecutablePath, true) )
93 | {
94 | std::cerr << "ERROR: Unable to find Matlab executable defined in the SLICER_MATLAB_EXECUTABLE_PATH environment variable: "
95 | << matlabExecutablePath << std::endl;
96 | return false;
97 | }
98 |
99 | bool success = true;
100 | try
101 | {
102 | std::vector command;
103 | command.clear();
104 |
105 | // Compose Matlab launching command
106 | std::cout << "Starting Matlab server: " << matlabExecutablePath;
107 | command.push_back(matlabExecutablePath);
108 |
109 | // start in minimized, with text console only
110 | std::cout << " -automation";
111 | command.push_back("-automation");
112 |
113 | // script directory (-sd) option does not work with the automation option, so need to use the run command to specify full script path
114 |
115 | // run script after startup
116 | #if defined( _WIN32 ) && !defined(__CYGWIN__)
117 | // Windows requires parameter and script name as two separate arguments
118 | std::string startupCommand1=std::string("-r");
119 | std::cout << " " << startupCommand1;
120 | command.push_back(startupCommand1.c_str());
121 | std::string startupCommand2=std::string("\"run('")+matlabCommandServerScriptPath+"');\"";
122 | std::cout << " " << startupCommand2;
123 | command.push_back(startupCommand2.c_str());
124 | #else
125 | // Linux/Mac OS X requires parameter and script name as one argument
126 | std::string startupCommand=std::string("-r \"run('")+matlabCommandServerScriptPath+"');\"";
127 | std::cout << " " << startupCommand;
128 | command.push_back(startupCommand.c_str());
129 | #endif
130 |
131 | // The array must end with a NULL pointer.
132 | std::cout << std::endl;
133 | command.push_back(0);
134 |
135 | // Create new process
136 | vtksysProcess* gp = vtksysProcess_New();
137 |
138 | // Set command
139 | vtksysProcess_SetCommand(gp, &*command.begin());
140 |
141 | // Hide window
142 | vtksysProcess_SetOption(gp,vtksysProcess_Option_HideWindow, 1);
143 |
144 | #if defined( _WIN32 ) && !defined(__CYGWIN__)
145 | // No need to redirect process output on Windows
146 | #else
147 | // Need to redirect the outputs to dev/null on Linux and Mac OS X,
148 | // otherwise Matlab terminates right after it is started
149 | vtksysProcess_SetPipeFile(gp, vtksysProcess_Pipe_STDOUT, "/dev/null");
150 | vtksysProcess_SetPipeFile(gp, vtksysProcess_Pipe_STDERR, "/dev/null");
151 | #endif
152 |
153 | // Start a detached process, because we don't want to block the MatlabCommander if the started Matlab process does not exit
154 | // (usually the Matlab process exits within a few seconds, but on some configurations it does not)
155 | vtksysProcess_SetOption(gp, vtksysProcess_Option_Detach, 1);
156 |
157 | // Run the application
158 | vtksysProcess_Execute(gp);
159 |
160 | // Release the application and let it run in the background
161 | vtksysProcess_Disown(gp);
162 |
163 | switch (vtksysProcess_GetState(gp))
164 | {
165 | case vtksysProcess_State_Disowned:
166 | // This is the success case
167 | std::cout << "Successfully detached from the started Matlab process" <ConnectToServer(hostname.c_str(), port);
220 | if (connectErrorCode!=0)
221 | {
222 | // Maybe Matlab server has not been started, try to start it
223 | if (StartMatlabServer())
224 | {
225 | // process start requested, try to connect
226 | for (int retryAttempts=0; retryAttemptsConnectToServer(hostname.c_str(), port);
229 | if (connectErrorCode==0)
230 | {
231 | // success
232 | break;
233 | }
234 | // Failed to connect, wait some more and retry
235 | vtksys::SystemTools::Delay(1000); // msec
236 | std::cerr << "Waiting for Matlab startup ... " << retryAttempts << "sec" << std::endl;
237 | }
238 | }
239 | else
240 | {
241 | std::cerr << "ERROR: Failed to start Matlab process" << std::endl;
242 | }
243 | }
244 | if (connectErrorCode != 0)
245 | {
246 | reply="ERROR: Cannot connect to the server";
247 | return COMMAND_STATUS_FAILED;
248 | }
249 |
250 | //------------------------------------------------------------
251 | // Send command
252 | igtl::StringMessage::Pointer stringMsg;
253 | stringMsg = igtl::StringMessage::New();
254 | stringMsg->SetDeviceName("CMD");
255 | std::cout << "Sending string: " << cmd << std::endl;
256 | stringMsg->SetString(cmd.c_str());
257 | stringMsg->Pack();
258 | socket->SetSendTimeout(5000); // timeout in msec
259 | if (!socket->Send(stringMsg->GetPackPointer(), stringMsg->GetPackSize()))
260 | {
261 | // Failed to send the message
262 | std::cerr << "Failed to send message to Matlab process" << std::endl;
263 | socket->CloseSocket();
264 | return COMMAND_STATUS_FAILED;
265 | }
266 |
267 | //------------------------------------------------------------
268 | // Receive reply
269 | // Create a message buffer to receive header
270 | igtl::MessageHeader::Pointer headerMsg;
271 | headerMsg = igtl::MessageHeader::New();
272 | // Initialize receive buffer
273 | headerMsg->InitPack();
274 | // Receive generic header from the socket
275 | if (receiveTimeoutMsec>0)
276 | {
277 | socket->SetReceiveTimeout(receiveTimeoutMsec); // timeout in msec
278 | }
279 |
280 | bool receiveTimedOut = false;
281 | int receivedBytes = socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), receiveTimedOut);
282 | if (receivedBytes == 0)
283 | {
284 | reply="No reply";
285 | socket->CloseSocket();
286 | return COMMAND_STATUS_FAILED;
287 | }
288 | if (receivedBytes != headerMsg->GetPackSize() || receiveTimedOut)
289 | {
290 | reply = "Bad reply";
291 | socket->CloseSocket();
292 | return COMMAND_STATUS_FAILED;
293 | }
294 | // Deserialize the header
295 | headerMsg->Unpack();
296 | if (strcmp(headerMsg->GetDeviceType(), "STRING") != 0)
297 | {
298 | reply = std::string("Receiving unsupported message type: ") + headerMsg->GetDeviceType();
299 | socket->Skip(headerMsg->GetBodySizeToRead(), 0);
300 | socket->CloseSocket();
301 | return COMMAND_STATUS_FAILED;
302 | }
303 | // Get the reply string
304 | reply=ReceiveString(socket, headerMsg);
305 |
306 | //------------------------------------------------------------
307 | // Close connection
308 | socket->CloseSocket();
309 |
310 | return COMMAND_STATUS_SUCCESS;
311 | }
312 |
313 | int ExitMatlab()
314 | {
315 | igtl::ClientSocket::Pointer socket = igtl::ClientSocket::New();
316 | int connectErrorCode = socket->ConnectToServer(MATLAB_DEFAULT_HOST.c_str(), MATLAB_DEFAULT_PORT);
317 | if (connectErrorCode!=0)
318 | {
319 | // The server has not been started, nothing to do
320 | std::cout << "Matlab process is already stopped" << std::endl;
321 | return EXIT_SUCCESS;
322 | }
323 |
324 | std::string cmd = "exit";
325 |
326 | //------------------------------------------------------------
327 | // Send command
328 | igtl::StringMessage::Pointer stringMsg;
329 | stringMsg = igtl::StringMessage::New();
330 | stringMsg->SetDeviceName("CMD");
331 | std::cout << "Sending string: " << cmd << std::endl;
332 | stringMsg->SetString(cmd.c_str());
333 | stringMsg->Pack();
334 | socket->SetSendTimeout(5000); // timeout in msec
335 | if (!socket->Send(stringMsg->GetPackPointer(), stringMsg->GetPackSize()))
336 | {
337 | // Failed to send the message
338 | std::cerr << "Failed to send message to Matlab process" << std::endl;
339 | socket->CloseSocket();
340 | return COMMAND_STATUS_FAILED;
341 | }
342 |
343 | // Close connection
344 | socket->CloseSocket();
345 |
346 | std::cout << "Matlab process exit requested" << std::endl;
347 | return EXIT_SUCCESS;
348 | }
349 |
350 |
351 | int CallMatlabFunction(int argc, char * argv [])
352 | {
353 | // Search for the --returnparameterfile argument. If it is present then arguments shall be returned.
354 | const std::string returnParameterFileArgName="--returnparameterfile";
355 | std::string returnParameterFileArgValue;
356 | for (int argvIndex=3; argvIndex=argc)
362 | {
363 | std::cerr << "ERROR: --returnparameterfile value is not defined" << std::endl;
364 | break;
365 | }
366 | returnParameterFileArgValue=argv[argvIndex+1];
367 | if ( returnParameterFileArgValue.at(0) == '"' )
368 | {
369 | // this is a quoted string => remove the quotes (Matlab uses different quotes anyway)
370 | returnParameterFileArgValue.erase( 0, 1 ); // erase the first character
371 | returnParameterFileArgValue.erase( returnParameterFileArgValue.size() - 1 ); // erase the last character
372 | }
373 | break;
374 | }
375 | }
376 |
377 | std::string cmd;
378 |
379 | // Change directory to the current working directory (where the Matlab function .m file is located)
380 | cmd += "cd('"+vtksys::SystemTools::GetCurrentWorkingDirectory()+"'); ";
381 |
382 | // No return value:
383 | // myfunction( cli_argsread({"--paramName1","paramValue1",...}) );
384 | // With return value:
385 | // cli_argswrite( myfunction( cli_argsread({"--paramName1","paramValue1",...}) ) );
386 |
387 | if (!returnParameterFileArgValue.empty())
388 | {
389 | // with return value
390 | cmd+="cli_argswrite('"+returnParameterFileArgValue+"',";
391 | }
392 | std::string functionName=argv[2];
393 | cmd+=functionName+"(cli_argsread({";
394 |
395 | for (int argvIndex=3; argvIndex remove the quotes (Matlab uses different quotes anyway)
401 | arg.erase( 0, 1 ); // erase the first character
402 | arg.erase( arg.size() - 1 ); // erase the last character
403 | }
404 | cmd+=std::string("'")+arg+"'";
405 | if (argvIndex+1RESPONSE_ERROR_PREFIX.size() && reply.compare(0,RESPONSE_ERROR_PREFIX.size(),RESPONSE_ERROR_PREFIX)==0)
431 | {
432 | // the response starts with "ERROR:", so the execution failed
433 | std::cerr << "Failed to execute Matlab function: " << functionName << ", received the following error message: " << std::endl;
434 | std::cerr << reply << std::endl;
435 | return EXIT_FAILURE;
436 | }
437 |
438 | std::cout << reply << std::endl;
439 | return EXIT_SUCCESS;
440 | }
441 |
442 |
443 | int CallStandardCli(int argc, char * argv [])
444 | {
445 | PARSE_ARGS;
446 |
447 | if (!cmd.empty())
448 | {
449 | // Execute command
450 | ExecuteMatlabCommandStatus status=ExecuteMatlabCommand(hostname, port, cmd, reply);
451 | if (status==COMMAND_STATUS_SUCCESS)
452 | {
453 | std::cout << reply << std::endl;
454 | completed=true;
455 | }
456 | else
457 | {
458 | std::cerr << reply << std::endl;
459 | completed=false;
460 | }
461 |
462 | // Remove newline characters, as it would confuse the return parameter file
463 | std::replace( reply.begin(), reply.end(), '\r', ' ');
464 | std::replace( reply.begin(), reply.end(), '\n', ' ');
465 | }
466 | else
467 | {
468 | // Empty command, for example when we just want to exit Matlab
469 | reply.clear();
470 | completed = true;
471 | }
472 |
473 | SetReturnValues(returnParameterFile,reply.c_str(),completed);
474 |
475 | // Exit Matlab
476 | if (exitmatlab == true)
477 | {
478 | return ExitMatlab();
479 | }
480 |
481 | return EXIT_SUCCESS; // always return with EXIT_SUCCESS, otherwise Slicer ignores the return values and we cannot show the reply on the module GUI
482 | }
483 |
484 | int main (int argc, char * argv [])
485 | {
486 | if (argc>2 && CALL_MATLAB_FUNCTION_ARG.compare(argv[1])==0)
487 | {
488 | // MatlabCommander is called with arguments: --call-matlab-function function_name parameter1 parameter2 ...
489 | return CallMatlabFunction(argc, argv);
490 | }
491 | else if (argc==2 && EXIT_MATLAB_ARG.compare(argv[1])==0)
492 | {
493 | // MatlabCommander is called with arguments: --exit-matlab
494 | return ExitMatlab();
495 | }
496 | else
497 | {
498 | // MatlabCommander is called as a standard CLI modul
499 | return CallStandardCli(argc, argv);
500 | }
501 | }
502 |
--------------------------------------------------------------------------------
/MatlabCommander/MatlabCommander.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Developer Tools.Matlab
4 | Matlab Commander
5 |
6 | 0.8
7 | http://www.slicer.org/slicerWiki/index.php/Documentation/Nightly/Extensions/MatlabBridge
8 | Slicer license
9 | Andras Lasso (PerkLab, Queen's University), Jean-Christophe Fillion-Robin (Kitware), Kevin Wang (Radiation Medicine Program, Princess Margaret Hospital, University Health Network Toronto)
10 |
11 |
12 |
13 | Matlab command input
14 |
15 | cmd
16 |
17 | input
18 |
19 |
20 | -c
21 | --command
22 |
23 |
24 |
25 |
26 | Matlab command output
27 |
28 | reply
29 |
30 | output
31 |
32 |
33 |
34 |
35 | completed
36 |
37 | output
38 | false
39 |
40 |
41 |
42 |
43 |
44 | Options for specifying the Matlab command server's network address
45 |
46 | hostname
47 |
48 | 127.0.0.1
49 |
50 | --host
51 |
52 |
53 | port
54 |
55 |
56 | 4100
57 | --port
58 |
59 |
60 | exitmatlab
61 |
62 |
63 | False
64 | --q
65 | --exitmatlab
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/MatlabCommander/commandserver/cli_argsread.m:
--------------------------------------------------------------------------------
1 | function params=cli_argsread(args)
2 | % Retrieve parameters in a structure from a list of command-line arguments
3 | % The output structure contains all the named arguments (field name is the command-line argument name)
4 | % and an "unnamed" argument containing the list of unnamed arguments in a cell.
5 |
6 | args=fixupArgumentList(args);
7 |
8 | params={};
9 | params.unnamed={};
10 |
11 | curArgName='';
12 | curArgValue='';
13 | for curArgIndex=1:length(args)
14 | if (regexp(args{curArgIndex},'^-[-]?[a-zA-Z]')==1)
15 | % This is an argument name (as it starts with - or -- followed by letters)
16 | % There may be an argument name without a value (flag parameter) or value
17 | % without a name (unnamed parameter) => save it before we start
18 | % processing the new argument
19 | params=saveParam(params,curArgName,curArgValue);
20 | curArgName='';
21 | curArgValue='';
22 | % Save the new argument name (but don't store it yet, it may be
23 | % followed by an argument value)
24 | % Strip the - or -- from the argument name
25 | [tokens matches]=regexp(args{curArgIndex},'^-[-]?([^-]+)','tokens','match');
26 | curArgName=tokens{1}{1};
27 | else
28 | % This is an argument value
29 | curArgValue=getValueFromString(args{curArgIndex});
30 | % We have a pair of argument name and value => save it
31 | params=saveParam(params,curArgName,curArgValue);
32 | curArgName='';
33 | curArgValue='';
34 | end
35 | end
36 |
37 | % If there is an argument that has not yet stored, store it
38 | params=saveParam(params,curArgName,curArgValue);
39 |
40 | end
41 |
42 | %% Helper functions
43 |
44 | % Fixing up the parameter list
45 | % Fiducial point name and value is stored in one argument:
46 | % '--somefiducial 12.3,14.6, 18.7'
47 | % Detect this case and convert it to
48 | % '--somefiducial' '12.3,14.6, 18.7'
49 | function updatedArgs=fixupArgumentList(originalArgs)
50 | updatedArgs={};
51 | for curArgIndex=1:length(originalArgs)
52 | if (regexp(originalArgs{curArgIndex},'^-[-]?[a-zA-Z].*[ ].+')==1)
53 | % Detected a space in an argument name, e.g., '--somefiducial 12.3,14.6,18.7'
54 | [matchedTokens matchedString]=regexp(originalArgs{curArgIndex},'^(-[-]?[a-zA-Z]+[^ ]*)[ ](.+)','tokens','match');
55 | argName=matchedTokens{1}{1}; % '--somefiducial'
56 | argValue=matchedTokens{1}{2}; % '12.3,14.6,18.7'
57 | % Insert the split argName and argValue in the argument list
58 | updatedArgs=[updatedArgs {argName} {argValue}];
59 | else
60 | updatedArgs=[updatedArgs {originalArgs{curArgIndex}}];
61 | end
62 | end
63 | end
64 |
65 | function paramValue=getValueFromString(paramString)
66 | % Store numerical values as numbers (to don't require the user to call str2num to get a numerical parameter from a string)
67 | [paramValue paramCount paramError]=sscanf(paramString,'%f,'); % reads one or more comma-separated floating point values
68 | if (isempty(paramError))
69 | % No error, so it was a number or vector of numbers
70 | return;
71 | end
72 | % There was an error, so we interpret this value as a string
73 | paramValue=paramString;
74 | end
75 |
76 | function updatedParams=saveParam(originalParams,curArgName,curArgValue)
77 | updatedParams=originalParams;
78 | if (isempty(curArgName))
79 | if (~isempty(curArgValue))
80 | updatedParams.unnamed{length(updatedParams.unnamed)+1}=curArgValue;
81 | end
82 | else
83 | if (isfield(updatedParams, curArgName))
84 | % This field exists already, so add the value
85 | updatedParams.(curArgName)=[updatedParams.(curArgName) {curArgValue}];
86 | else
87 | updatedParams.(curArgName)=curArgValue;
88 | end
89 | end
90 | end
91 |
--------------------------------------------------------------------------------
/MatlabCommander/commandserver/cli_argswrite.m:
--------------------------------------------------------------------------------
1 | function argswrite(returnParameterFilename, args)
2 | % Write return values specified in the args structure to the return parameter text file
3 |
4 | % open file for writing text file (create new)
5 | fid=fopen(returnParameterFilename, 'wt+');
6 | assert(fid > 0, ['Could not open output file:' returnParameterFilename]);
7 |
8 | argsCellArr = struct2cell(args);
9 |
10 | % Get string names for each field in the meta data
11 | fields = fieldnames(args);
12 |
13 | % Print the header data to the output file
14 | for i=1:numel(fields)
15 | fprintf(fid,fields{i});
16 | fprintf(fid,' = ');
17 | % Print as a row vector (scalar vectors are not written correctly if they are stored in a column vector)
18 | [valueRows valueColumns]=size(argsCellArr{i});
19 | if (valueRows==1)
20 | value=argsCellArr{i};
21 | else
22 | value=argsCellArr{i}';
23 | end
24 | fprintf(fid,num2str(value));
25 | fprintf(fid,'\n');
26 | end
27 |
28 | fclose(fid);
29 |
--------------------------------------------------------------------------------
/MatlabCommander/commandserver/cli_commandserver.m:
--------------------------------------------------------------------------------
1 | % OpenIGTLink server that executes the received string commands
2 | function cli_commandserver(port)
3 |
4 | global OPENIGTLINK_SERVER_SOCKET
5 |
6 | import java.net.Socket
7 | import java.io.*
8 | import java.net.ServerSocket
9 |
10 | % Add current directory to the path so that all cli_* functions will be available even when the current working directory is changed
11 | addpath(pwd);
12 |
13 | serverSocketInfo.port=4100;
14 | serverSocketInfo.timeout=1000;
15 |
16 | if (nargin>0)
17 | serverSocketInfo.port=port;
18 | end
19 |
20 | disp(['Starting OpenIGTLink command server at port ' num2str(serverSocketInfo.port)]);
21 |
22 | % Open a TCP Server Port
23 | if (exist('OPENIGTLINK_SERVER_SOCKET','var'))
24 | if (not(isempty(OPENIGTLINK_SERVER_SOCKET)))
25 | % Socket has not been closed last time
26 | disp('Socket has not been closed properly last time. Closing it now.');
27 | OPENIGTLINK_SERVER_SOCKET.close;
28 | OPENIGTLINK_SERVER_SOCKET=[];
29 | end
30 | end
31 |
32 | try
33 | serverSocketInfo.socket = ServerSocket(serverSocketInfo.port);
34 | OPENIGTLINK_SERVER_SOCKET=serverSocketInfo.socket;
35 | catch
36 | error('Failed to open server port. Make sure the port is not open already or blocked by firewall.');
37 | end
38 | serverSocketInfo.socket.setSoTimeout(serverSocketInfo.timeout);
39 |
40 | disp('Waiting for client connections...');
41 |
42 | % Handle client connections
43 | while(true)
44 |
45 | % Wait for client connection
46 | drawNowCounter=0;
47 | while(true),
48 | try
49 | clientSocketInfo.socket = serverSocketInfo.socket.accept;
50 | break;
51 | catch
52 | end
53 | if (drawNowCounter>10)
54 | drawnow
55 | drawNowCounter=0;
56 | end;
57 | drawNowCounter=drawNowCounter+1;
58 | pause(0.5);
59 | end
60 |
61 | % Client connected
62 | disp('Client connected')
63 | % Rehash forces re-reading of all Matlab functions from files
64 | rehash
65 |
66 | clientSocketInfo.remoteHost = char(clientSocketInfo.socket.getInetAddress);
67 | clientSocketInfo.outputStream = clientSocketInfo.socket.getOutputStream;
68 | clientSocketInfo.inputStream = clientSocketInfo.socket.getInputStream;
69 | clientSocketInfo.messageHeaderReceiveTimeoutSec=5;
70 | clientSocketInfo.messageBodyReceiveTimeoutSec=25;
71 |
72 | % Read command
73 | receivedMsg=ReadOpenIGTLinkStringMessage(clientSocketInfo);
74 | if(~isempty(receivedMsg) && ~isempty(receivedMsg.string))
75 | dataType=deblank(char(receivedMsg.dataTypeName));
76 | deviceName=deblank(char(receivedMsg.deviceName));
77 | cmd=deblank(char(receivedMsg.string));
78 | replyDeviceName='ACK';
79 | if (~strcmp(dataType,'STRING'))
80 | response=['ERROR: Expected STRING data type, received data type: [',dataType,']'];
81 | elseif (length(deviceName)<3 || ~strcmp(deviceName(1:3),'CMD'))
82 | response=['ERROR: Expected device name starting with CMD. Received device name: [',deviceName,']'];
83 | elseif (isempty(cmd))
84 | response='ERROR: Received empty command string';
85 | else
86 | % Reply device name for CMD is ACQ, for CMD_someuid is ACK_someuid
87 | replyDeviceName=deviceName;
88 | replyDeviceName(1:3)='ACK';
89 | try
90 | disp([' Execute command: ',cmd]);
91 | response=evalc(cmd);
92 | if (isempty(response))
93 | % Replace empty response by OK to indicate success
94 | response='OK';
95 | end
96 | disp(' Command execution completed successfully');
97 | catch ME
98 | response=['ERROR: Command execution failed. ',ME.getReport('extended','hyperlinks','off')];
99 | end
100 | end
101 | else
102 | response='ERROR: Error while receiving the command';
103 | end
104 |
105 | % Send reply
106 | responseStr=num2str(response);
107 | disp([' Response (sent to device ',replyDeviceName,'): ', responseStr]);
108 | WriteOpenIGTLinkStringMessage(clientSocketInfo, responseStr, replyDeviceName);
109 |
110 | % Close connection
111 | clientSocketInfo.socket.close;
112 | clientSocketInfo.socket=[];
113 | disp('Client connection closed');
114 |
115 | end
116 |
117 | % Close server socket
118 | serverSocketInfo.socket.close;
119 | serverSocketInfo.socket=[];
120 |
121 | end
122 |
123 | function msg=ReadOpenIGTLinkStringMessage(clientSocket)
124 | msg=ReadOpenIGTLinkMessage(clientSocket);
125 | if (length(msg.body)<5)
126 | disp('Error: STRING message received with incomplete contents')
127 | msg.string='';
128 | return
129 | end
130 | strMsgEncoding=convertFromUint8VectorToUint16(msg.body(1:2));
131 | if (strMsgEncoding~=3)
132 | disp(['Warning: STRING message received with unknown encoding ',num2str(strMsgEncoding)])
133 | end
134 | strMsgLength=convertFromUint8VectorToUint16(msg.body(3:4));
135 | msg.string=char(msg.body(5:4+strMsgLength));
136 | end
137 |
138 | function msg=ReadOpenIGTLinkMessage(clientSocket)
139 | openIGTLinkHeaderLength=58;
140 | headerData=ReadWithTimeout(clientSocket, openIGTLinkHeaderLength, clientSocket.messageHeaderReceiveTimeoutSec);
141 | if (length(headerData)==openIGTLinkHeaderLength)
142 | msg=ParseOpenIGTLinkMessageHeader(headerData);
143 | msg.body=ReadWithTimeout(clientSocket, msg.bodySize, clientSocket.messageBodyReceiveTimeoutSec);
144 | else
145 | error('ERROR: Timeout while waiting receiving OpenIGTLink message header')
146 | end
147 | end
148 |
149 | function result=WriteOpenIGTLinkStringMessage(clientSocket, msgString, deviceName)
150 | msg.dataTypeName='STRING';
151 | msg.deviceName=deviceName;
152 | msg.timestamp=0;
153 | msgString=[uint8(msgString) uint8(0)]; % Convert string to uint8 vector and add terminator character
154 | msg.body=[convertFromUint16ToUint8Vector(3),convertFromUint16ToUint8Vector(length(msgString)),msgString];
155 | result=WriteOpenIGTLinkMessage(clientSocket, msg);
156 | end
157 |
158 | % Returns 1 if successful, 0 if failed
159 | function result=WriteOpenIGTLinkMessage(clientSocket, msg)
160 | import java.net.Socket
161 | import java.io.*
162 | import java.net.ServerSocket
163 | % Add constant fields values
164 | msg.versionNumber=1;
165 | msg.bodySize=length(msg.body);
166 | msg.bodyCrc=0; % TODO: compute this
167 | % Pack message
168 | data=[];
169 | data=[data, convertFromUint16ToUint8Vector(msg.versionNumber)];
170 | data=[data, padString(msg.dataTypeName,12)];
171 | data=[data, padString(msg.deviceName,20)];
172 | data=[data, convertFromInt64ToUint8Vector(msg.timestamp)];
173 | data=[data, convertFromInt64ToUint8Vector(msg.bodySize)];
174 | data=[data, convertFromInt64ToUint8Vector(msg.bodyCrc)];
175 | data=[data, uint8(msg.body)];
176 | result=1;
177 | try
178 | DataOutputStream(clientSocket.outputStream).write(uint8(data),0,length(data));
179 | catch ME
180 | disp(ME.message)
181 | result=0;
182 | end
183 | try
184 | DataOutputStream(clientSocket.outputStream).flush;
185 | catch ME
186 | disp(ME.message)
187 | result=0;
188 | end
189 | if (result==0)
190 | disp('Sending OpenIGTLink message failed');
191 | end
192 | end
193 |
194 | function data=ReadWithTimeout(clientSocket, requestedDataLength, timeoutSec)
195 | import java.net.Socket
196 | import java.io.*
197 | import java.net.ServerSocket
198 |
199 | % preallocate to improve performance
200 | data=zeros(1,requestedDataLength,'uint8');
201 | signedDataByte=int8(0);
202 | bytesRead=0;
203 | while(bytesRead0)
214 | % starting to read message header
215 | tstart=tic;
216 | end
217 | for i = bytesRead+1:bytesRead+bytesToRead
218 | signedDataByte = DataInputStream(clientSocket.inputStream).readByte;
219 | if signedDataByte>=0
220 | data(i) = signedDataByte;
221 | else
222 | data(i) = typecast(int8(signedDataByte),'uint8');
223 | end
224 | end
225 | bytesRead=bytesRead+bytesToRead;
226 | if (bytesRead>0 && bytesReadtimeoutSec)
230 | % timeout, it should not happen
231 | % remove the unnecessary preallocated elements
232 | data=data(1:bytesRead);
233 | break
234 | end
235 | end
236 | end
237 | end
238 |
239 | %% Parse OpenIGTLink messag header
240 | % http://openigtlink.org/protocols/v2_header.html
241 | function parsedMsg=ParseOpenIGTLinkMessageHeader(rawMsg)
242 | parsedMsg.versionNumber=convertFromUint8VectorToUint16(rawMsg(1:2));
243 | parsedMsg.dataTypeName=char(rawMsg(3:14));
244 | parsedMsg.deviceName=char(rawMsg(15:34));
245 | parsedMsg.timestamp=convertFromUint8VectorToInt64(rawMsg(35:42));
246 | parsedMsg.bodySize=convertFromUint8VectorToInt64(rawMsg(43:50));
247 | parsedMsg.bodyCrc=convertFromUint8VectorToInt64(rawMsg(51:58));
248 | end
249 |
250 | function result=convertFromUint8VectorToUint16(uint8Vector)
251 | result=int32(uint8Vector(1))*256+int32(uint8Vector(2));
252 | end
253 |
254 | function result=convertFromUint8VectorToInt64(uint8Vector)
255 | multipliers = [256^7 256^6 256^5 256^4 256^3 256^2 256^1 1];
256 | % Matlab R2009 and earlier versions don't support int64 arithmetics.
257 | int64arithmeticsSupported=~isempty(find(strcmp(methods('int64'),'mtimes')));
258 | if int64arithmeticsSupported
259 | % Full 64-bit arithmetics
260 | result = sum(int64(uint8Vector).*int64(multipliers));
261 | else
262 | % Fall back to floating point arithmetics: compute result with floating
263 | % point type and convert the end result to int64
264 | % (it should be precise enough for realistic file sizes)
265 | result = int64(sum(double(uint8Vector).*multipliers));
266 | end
267 | end
268 |
269 | function selectedByte=getNthByte(multibyte, n)
270 | selectedByte=uint8(mod(floor(multibyte/256^n),256));
271 | end
272 |
273 | function result=convertFromUint16ToUint8Vector(uint16Value)
274 | result=[getNthByte(uint16Value,1) getNthByte(uint16Value,0)];
275 | end
276 |
277 | function result=convertFromInt64ToUint8Vector(int64Value)
278 | result=zeros(1,8,'uint8');
279 | result(1)=getNthByte(int64Value,7);
280 | result(2)=getNthByte(int64Value,6);
281 | result(3)=getNthByte(int64Value,5);
282 | result(4)=getNthByte(int64Value,4);
283 | result(5)=getNthByte(int64Value,3);
284 | result(6)=getNthByte(int64Value,2);
285 | result(7)=getNthByte(int64Value,1);
286 | result(8)=getNthByte(int64Value,0);
287 | end
288 |
289 | function paddedStr=padString(str,strLen)
290 | paddedStr=str(1:min(length(str),strLen));
291 | paddingLength=strLen-length(paddedStr);
292 | if (paddingLength>0)
293 | paddedStr=[paddedStr,zeros(1,paddingLength,'uint8')];
294 | end
295 | end
296 |
--------------------------------------------------------------------------------
/MatlabCommander/commandserver/cli_geometryread.m:
--------------------------------------------------------------------------------
1 | function geometry = cli_geometryread(filename)
2 | %cli_geometryread Read geometry for the command-line interface module from file (in PLY or STL format) into LPS coordinate system
3 | %
4 | % geometry = cli_geometryread(filename) reads the mesh
5 | %
6 | % geometry.vertices contains the vertices for all triangles in LPS coordinate system [3*n x 3].
7 | % geometry.faces contains the vertex lists defining each triangle face [n x 3].
8 | %
9 | % Current limitations/caveats:
10 | % * Only triangle mesh geometry is supported.
11 | %
12 | % Example:
13 | % g=cli_geometryread('SimpleGeom.stl');
14 | % patch(g, 'FaceColor', 'red');
15 | %
16 |
17 | [pathstr,name,ext] = fileparts(filename);
18 | if (strcmpi(ext,'.stl'))
19 | [v, f, n, c, stltitle] = stlread(filename);
20 | else
21 | [v, f] = read_ply(filename);
22 | end
23 |
24 | geometry.vertices = v;
25 | geometry.faces = f;
26 |
27 | % Slicer writes mesh points in RAS coordinate system by default, convert to LPS now
28 | geometry.vertices(:,1:2) = -1*geometry.vertices(:,1:2)
29 |
--------------------------------------------------------------------------------
/MatlabCommander/commandserver/cli_geometrywrite.m:
--------------------------------------------------------------------------------
1 | function cli_geometrywrite(outputFilename, geometry)
2 | % Function for writing mesh data to PLY or STL file
3 | %
4 | % geometry.vertices contains the vertices for all triangles in LPS coordinate system [3*n x 3].
5 | % geometry.faces contains the vertex lists defining each triangle face [n x 3].
6 | %
7 | % Current limitations/caveats:
8 | % * Only triangle mesh geometry is supported.
9 |
10 | % Slicer expects mesh points in RAS coordinate system by default, convert from LPS now
11 | geometry.vertices(:,1:2) = -1*geometry.vertices(:,1:2)
12 |
13 | [pathstr,name,ext] = fileparts(outputFilename);
14 | if (strcmpi(ext,'.stl'))
15 | stlwrite(outputFilename, geometry);
16 | else
17 | write_ply(geometry.vertices, geometry.faces, outputFilename);
18 | end
19 |
--------------------------------------------------------------------------------
/MatlabCommander/commandserver/cli_imageread.m:
--------------------------------------------------------------------------------
1 | function img = cli_imageread(filename)
2 | %cli_imageread Read images for the command-line interface module from file (in NRRD format, see http://teem.sourceforge.net/nrrd/format.html)
3 | % img = cli_imageread(filename) reads the image volume and associated metadata
4 | %
5 | % See detailed description of the img structure in nrrdread.m
6 | %
7 |
8 | img = nrrdread(filename);
9 |
--------------------------------------------------------------------------------
/MatlabCommander/commandserver/cli_imagewrite.m:
--------------------------------------------------------------------------------
1 | function cli_imagewrite(outputFilename, img)
2 | % Function for writing pixel and meta data struct to a NRRD file
3 | %
4 | % See detailed description of the input data format description in nrrdwrite.m
5 | %
6 |
7 | nrrdwrite(outputFilename, img);
8 |
--------------------------------------------------------------------------------
/MatlabCommander/commandserver/cli_lineartransformread.m:
--------------------------------------------------------------------------------
1 | function transform = cli_lineartransformread(filename, transformType)
2 | %cli_transformread Read a single 4x4 linear transformation matrix from an "Insight Transform File V1.0" text file
3 | %
4 | % By default the output transform is in LPS anatomical coordinate sytem and
5 | % defined according to ITK ("image processing") convention.
6 | % If transformType is set to 'slicer' then the output transform is in RAS
7 | % coordinate system and defined according to Slicer ("computer graphics")
8 | % convention.
9 | % See more details at: http://www.slicer.org/slicerWiki/index.php/Documentation/4.2/FAQ#The_registration_transform_file_saved_by_Slicer_does_not_seem_to_match_what_is_shown
10 | %
11 |
12 | if nargin < 2
13 | transformType = 'itk';
14 | end
15 |
16 | allTransforms=cli_transformread(filename);
17 |
18 | assert(length(allTransforms)==1, 'The transform file should contain exactly one transform');
19 | assert(strcmpi(allTransforms{1}.Transform,'AffineTransform_double_3_3'), 'The transform file should contain an AffineTransform_double_3_3 transform');
20 |
21 | params=str2num(allTransforms{1}.Parameters);
22 |
23 | transform_lps=[[reshape(params(1:9),3,3)' params(10:12)']; 0 0 0 1];
24 |
25 | if (strcmpi(transformType,'itk'))
26 | transform=transform_lps;
27 | elseif (strcmpi(transformType, 'slicer'))
28 | lps2ras=diag([-1 -1 1 1]);
29 | ras2lps=diag([-1 -1 1 1]);
30 | transform=lps2ras*inv(transform_lps)*ras2lps;
31 | else
32 | error('Unknown transformType: %s',transformType);
33 | end
34 |
--------------------------------------------------------------------------------
/MatlabCommander/commandserver/cli_lineartransformwrite.m:
--------------------------------------------------------------------------------
1 | function cli_lineartransformwrite(outputfilename, transformMatrix, transformType)
2 | %cli_transformwrite Write a single 4x4 linear transformation matrix to an "Insight Transform File V1.0" text file
3 | %
4 | % By default the output transform is in LPS anatomical coordinate sytem and
5 | % defined according to ITK ("image processing") convention.
6 | % If transformType is set to 'slicer' then the output transform is in RAS
7 | % coordinate system and defined according to Slicer ("computer graphics")
8 | % convention.
9 | % See more details at: http://www.slicer.org/slicerWiki/index.php/Documentation/4.2/FAQ#The_registration_transform_file_saved_by_Slicer_does_not_seem_to_match_what_is_shown
10 | %
11 |
12 | if nargin < 3
13 | transformType = 'itk';
14 | end
15 |
16 | assert(isequal(size(transformMatrix),[4 4]), 'transformMatrix size must be 4x4');
17 |
18 | if (strcmpi(transformType,'itk'))
19 | transform_lps=transformMatrix;
20 | elseif (strcmpi(transformType, 'slicer'))
21 | lps2ras=diag([-1 -1 1 1]);
22 | ras2lps=diag([-1 -1 1 1]);
23 | transform_lps=ras2lps*inv(transformMatrix)*lps2ras;
24 | else
25 | error('Unknown transformType: %s',transformType);
26 | end
27 |
28 | allTransforms{1}.Transform='AffineTransform_double_3_3';
29 | allTransforms{1}.Parameters=[reshape(transform_lps(1:3,1:3)',1,9) transform_lps(1:3,4)'];
30 | allTransforms{1}.FixedParameters=[0 0 0];
31 |
32 | cli_transformwrite(outputfilename, allTransforms);
33 |
--------------------------------------------------------------------------------
/MatlabCommander/commandserver/cli_measurementread.m:
--------------------------------------------------------------------------------
1 | function measurement = cli_measurementread(filename)
2 | %cli_measurementread Read measurement table from Slicer measurement CSV file
3 | %
4 |
5 | % Sample file contents:
6 | %
7 | % # measurement file C:/Users/someuser/AppData/Local/Temp/FBGA_vtkMRMLDoubleArrayNodeB.csv
8 | % # columns = x,y,yerr
9 | % 2.0,4.0,0.002
10 | % 5.2,1.5,0.001
11 | % 5.1,2.5,0.005
12 | %
13 |
14 | try
15 | measurement=csvread(filename,2);
16 | catch ME
17 | % failed with and without an output, the command must be invalid
18 | disp(['Could not retrieve any measurement values from: ' filename]);
19 | measurement=[];
20 | end
21 |
--------------------------------------------------------------------------------
/MatlabCommander/commandserver/cli_measurementwrite.m:
--------------------------------------------------------------------------------
1 | function cli_measurementwrite(outputfilename, measurements)
2 | %cli_measurementwrite Write a list of measurements to a "Insight Transform File V1.0" text file
3 | %
4 |
5 | % Sample file contents:
6 | %
7 | % # measurement file C:/Users/someuser/AppData/Local/Temp/FBGA_vtkMRMLDoubleArrayNodeB.csv
8 | % # columns = x,y,yerr
9 | % 2.0,4.0,0.002
10 | % 5.2,1.5,0.001
11 | % 5.1,2.5,0.005
12 | %
13 |
14 | [rows columns] = size(measurements);
15 | assert(rows>0, 'The measurement matrix is empty');
16 | assert(columns==3, 'The measurement matrix must have 3 columns');
17 |
18 | % Write header
19 | fid=fopen(outputfilename, 'w');
20 | assert(fid > 0, 'Could not open file %s', outputfilename);
21 | fprintf(fid,'# measurement file %s\n', outputfilename);
22 | fprintf(fid,'# columns = x,y,yerr\n');
23 | fclose(fid);
24 |
25 | dlmwrite(outputfilename,measurements,'-append','delimiter',',');
26 |
--------------------------------------------------------------------------------
/MatlabCommander/commandserver/cli_pointfileread.m:
--------------------------------------------------------------------------------
1 | function points = cli_pointfileread(filename)
2 | % Read image markups from a Slicer fcsv file
3 | % points = cli_pointfileread(filename) reads the image volume and associated metadata
4 | %
5 | % points.position: point positions (Nx3)
6 | % points.orientation: point orientations as quaternion (Nx4)
7 | % points.id: point identifiers
8 | % points.visibility: non-zero if point is visible
9 | % points.selected: non-zero if point is selected
10 | % points.locked: non-zero if point is protected from editing by the user
11 | % points.label: displayed label string
12 | % points.description: description of the point
13 | % points.associatedNodeID: ID od te node where the point was marked on
14 | %
15 | % points.headerVersion: first header line
16 | % points.headerCoordinateSystem: second header line
17 | % points.headerColumns: third header line
18 | %
19 | % Sample file contents:
20 | %
21 | % # Markups fiducial file version = 4.7
22 | % # CoordinateSystem = 1
23 | % # columns = id,x,y,z,ow,ox,oy,oz,vis,sel,lock,label,desc,associatedNodeID
24 | % vtkMRMLMarkupsFiducialNode_122,-31.27,-28.3827,40.0248,0,0,0,1,1,0,0,,,
25 | % vtkMRMLMarkupsFiducialNode_123,-30.7427,-28.8846,40.7103,0,0,0,1,1,0,0,,,
26 | % vtkMRMLMarkupsFiducialNode_124,-30.2028,-29.4316,41.3501,0,0,0,1,1,0,0,,,
27 | % vtkMRMLMarkupsFiducialNode_125,-29.6359,-30.022,41.9246,0,0,0,1,1,0,0,,,
28 | %
29 |
30 | points = {}
31 |
32 | fid = fopen(filename, 'r');
33 | assert(fid > 0, 'Could not open file.');
34 | cleaner = onCleanup(@() fclose(fid));
35 |
36 | % Ignore the first 3 lines, they are just headers
37 | % (it may be useful to parse these lines in the future to improve robustnes
38 | % and compatibility)
39 | points.headerVersion = fgetl(fid);
40 | points.headerCoordinateSystem = fgetl(fid);
41 | points.headerColumns = fgetl(fid);
42 |
43 | columns = textscan(fid, '%s %f%f%f %f%f%f%f %d%d%d %s %s %s','delimiter',',')
44 |
45 | points.id = columns{1}
46 | points.position = [columns{2}, columns{3}, columns{4}]
47 | points.orientation = [columns{5}, columns{6}, columns{7}, columns{8}]
48 | points.visibility = columns{9}
49 | points.selected = columns{10}
50 | points.locked = columns{11}
51 | points.label = columns{12}
52 | points.description = columns{13}
53 | points.associatedNodeID = columns{14}
54 |
--------------------------------------------------------------------------------
/MatlabCommander/commandserver/cli_pointfilewrite.m:
--------------------------------------------------------------------------------
1 | function cli_pointfilewrite(outputfilename, points)
2 | %cli_measurementwrite Write a list of measurements to a Slicer fcsv text file
3 | %
4 | % See more details at cli_pointfileread
5 | %
6 | % Sample file contents:
7 | %
8 | % # Markups fiducial file version = 4.7
9 | % # CoordinateSystem = 1
10 | % # columns = id,x,y,z,ow,ox,oy,oz,vis,sel,lock,label,desc,associatedNodeID
11 | % vtkMRMLMarkupsFiducialNode_122,-31.27,-28.3827,40.0248,0,0,0,1,1,0,0,,,
12 | % vtkMRMLMarkupsFiducialNode_123,-30.7427,-28.8846,40.7103,0,0,0,1,1,0,0,,,
13 | % vtkMRMLMarkupsFiducialNode_124,-30.2028,-29.4316,41.3501,0,0,0,1,1,0,0,,,
14 | % vtkMRMLMarkupsFiducialNode_125,-29.6359,-30.022,41.9246,0,0,0,1,1,0,0,,,
15 | %
16 |
17 | % Write header
18 | fid=fopen(outputfilename, 'w');
19 | assert(fid > 0, 'Could not open file %s', outputfilename);
20 | fprintf(fid,'%s\n', points.headerVersion);
21 | fprintf(fid,'%s\n', points.headerCoordinateSystem);
22 | fprintf(fid,'%s\n', points.headerColumns);
23 | numOfPoints = size(points.position,1);
24 | for k = 1:numOfPoints
25 | % Retrieve optional properties
26 | label = '';
27 | if k <= size(points.label,1)
28 | label = points.label(k);
29 | end
30 | description = '';
31 | if k <= size(points.description,1)
32 | description = points.description(k);
33 | end
34 | associatedNodeID = '';
35 | if k <= size(points.associatedNodeID,1)
36 | associatedNodeID = points.associatedNodeID(k);
37 | end
38 | % Write to file
39 | fprintf(fid,'%s,%g,%g,%g,%g,%g,%g,%g,%d,%d,%d,%s,%s,%s\n',...
40 | points.id(k,:),...
41 | points.position(k,1), points.position(k,2), points.position(k,3),...
42 | points.orientation(k,1), points.orientation(k,2), points.orientation(k,3), points.orientation(k,4),...
43 | points.visibility(k), points.selected(k), points.locked(k),...
44 | label, description, associatedNodeID);
45 | end
46 | fclose(fid);
47 |
--------------------------------------------------------------------------------
/MatlabCommander/commandserver/cli_pointvectordecode.m:
--------------------------------------------------------------------------------
1 | function points=cli_pointvectordecode(paramValue)
2 | % Creates a [3xN] matrix with the point positions in LPS coordinate system
3 |
4 | if (iscell(paramValue))
5 | points=cell2mat(paramValue);
6 | else
7 | % Single fiducial point, it's not stored in a cell
8 | points=paramValue;
9 | end
10 |
11 | % Point coordinates are provided by Slicer in RAS coordinate system
12 | % Multiply the first two components by -1 to obtain points in LPS coordinate system
13 | points(1:2,:)=-1*points(1:2,:);
14 |
--------------------------------------------------------------------------------
/MatlabCommander/commandserver/cli_stringvectordecode.m:
--------------------------------------------------------------------------------
1 | function stringlist=cli_stringvectordecode(paramValue)
2 | % Creates a string cell array from the string-vector parameter value
3 | % (which is a comma-separated string).
4 | % More recent Matlab versions can return the value simply by using the
5 | % strsplit function.
6 |
7 | stringcellarray=regexp(paramValue,'([^,]*)','tokens')
8 | stringlist=cat(2,stringcellarray{:})
9 |
--------------------------------------------------------------------------------
/MatlabCommander/commandserver/cli_transformread.m:
--------------------------------------------------------------------------------
1 | function transforms = cli_transformread(filename)
2 | %cli_transformread Read transforms from a "Insight Transform File V1.0" text file
3 | %
4 | % The output is a cell that contains a structure for each transform in
5 | % the file.
6 | % The structure contains the properties of each transform (typically
7 | % Transform, Parameters, and FixedParameters field).
8 | %
9 |
10 | fid = fopen(filename, 'rt');
11 | assert(fid > 0, 'Could not open file.');
12 | cleaner = onCleanup(@() fclose(fid));
13 |
14 | % Transform files are expected to start with a specific first line
15 | expectedFirstLine='#Insight Transform File V1.0';
16 | theLine = fgetl(fid);
17 | assert(strcmpi(theLine,expectedFirstLine), 'The first line of the transform file expected to be #Insight Transform File V1.0')
18 |
19 | % The contents of a linear transform file:
20 | %
21 | % #Insight Transform File V1.0
22 | % #Transform 0
23 | % Transform: AffineTransform_double_3_3
24 | % Parameters: 0.9961969233988567 0.05233595624294384 -0.0696608749212155 -0.041992154494529144 0.9889109407697044 0.14244932497869228 0.07634362299210169 -0.13898236906210146 0.9873477362704213 6.995316014085823 -9.993983402051885 0.021204305831741033
25 | % FixedParameters: 0 0 0
26 | %
27 |
28 | transforms = {};
29 | latestTransform={};
30 |
31 | % Parse the file a line at a time.
32 | while (~feof(fid))
33 | theLine = fgetl(fid);
34 | if (isempty(theLine))
35 | % End of the header.
36 | break;
37 | end
38 | if (isequal(theLine(1), '#'))
39 | % Comment line.
40 | continue;
41 | end
42 |
43 | % "fieldname:= value" or "fieldname: value" or "fieldname:value"
44 | parsedLine = regexp(theLine, ':=?\s*', 'split','once');
45 |
46 | assert(numel(parsedLine) == 2, 'Parsing error')
47 |
48 | field = parsedLine{1};
49 | value = parsedLine{2};
50 |
51 | if (strcmpi(field,'Transform'))
52 | % This is a new transform
53 | if (isfield(latestTransform,'Transform'))
54 | % We already have some transform info, so save it
55 | transforms{length(transforms)+1}=latestTransform;
56 | latestTransform={};
57 | end
58 | latestTransform.Transform=value;
59 | else
60 | % This is a new field for the latest transform
61 | latestTransform.(field)=value;
62 | end
63 | end
64 |
65 | % Save the latestTransform
66 | if (isfield(latestTransform,'Transform'))
67 | % We already have some transform info, so save it
68 | transforms{length(transforms)+1}=latestTransform;
69 | end
70 |
--------------------------------------------------------------------------------
/MatlabCommander/commandserver/cli_transformwrite.m:
--------------------------------------------------------------------------------
1 | function cli_transformwrite(outputfilename, transforms)
2 | %cli_transformwrite Write transforms to a "Insight Transform File V1.0" text file
3 | %
4 |
5 | % Open file for writing
6 | fid=fopen(outputfilename, 'w');
7 |
8 | assert(fid > 0, 'Could not open file %s', outputfilename);
9 | cleaner = onCleanup(@() fclose(fid));
10 |
11 | fprintf(fid,'#Insight Transform File V1.0\n');
12 |
13 | for transformIndex=1:length(transforms)
14 | % Get string names for each field in transform descriptor
15 | fields = fieldnames(transforms{transformIndex});
16 | metaDataCellArr = struct2cell(transforms{transformIndex});
17 | for i=1:numel(fields)
18 | fprintf(fid,fields{i});
19 | writeDataByType(fid,metaDataCellArr{i});
20 | end
21 | end
22 |
23 | fprintf(fid,'\n');
24 |
25 | %fclose(fid);
26 |
27 | function writeDataByType(fid, data)
28 | % Function that writes the header data to file based on the type of data
29 | % params: - fid of file to write to
30 | % - data from header to write
31 | if ischar(data)
32 | fprintf(fid,': %s\n',data);
33 | else
34 | fprintf(fid,': ');
35 | fprintf(fid,'%d ',data);
36 | fprintf(fid,'\n');
37 | end
38 |
--------------------------------------------------------------------------------
/MatlabCommander/commandserver/cli_version.m.in:
--------------------------------------------------------------------------------
1 | function [major minor patch]=cli_version()
2 | % Returns MatlabBridge module version
3 |
4 | major = @MATLABBRIDGE_VERSION_MAJOR@
5 | minor = @MATLABBRIDGE_VERSION_MINOR@
6 | patch = @MATLABBRIDGE_VERSION_PATCH@
7 |
--------------------------------------------------------------------------------
/MatlabCommander/commandserver/fcsvwrite.m:
--------------------------------------------------------------------------------
1 | function fcsvwrite(outputfilename, position, id, visibile, selected, locked, label, description, orientation)
2 | %fcsvwrite Write a list of fiducial markups to Slicer fcsv file
3 | %
4 |
5 | % Sample file contents:
6 | %
7 | % # Markups fiducial file version = 4.5
8 | % # CoordinateSystem = 0
9 | % # columns = id,x,y,z,ow,ox,oy,oz,vis,sel,lock,label,desc,associatedNodeID
10 | % vtkMRMLMarkupsFiducialNode_0,-2.49926,8.41401,78.7389,0,0,0,1,1,1,0,F-1,,vtkMRMLModelNode5
11 | % vtkMRMLMarkupsFiducialNode_1,-7.29697,13.0602,74.4859,0,0,0,1,1,1,0,F-2,,vtkMRMLModelNode5
12 | % vtkMRMLMarkupsFiducialNode_2,-5.4786,10.4094,76.1044,0,0,0,1,1,1,0,F-3,,vtkMRMLModelNode5
13 | %
14 |
15 | [rows columns] = size(position);
16 | if rows>0
17 | assert(columns==3, 'Position matrix must have 3 columns');
18 | end
19 |
20 | if nargin < 3
21 | id = strtrim(cellstr(num2str([1:rows]'))');
22 | end
23 | if nargin < 4
24 | visible = ones(rows,1);
25 | end
26 | if nargin < 5
27 | selected = ones(rows,1);
28 | end
29 | if nargin < 6
30 | locked = zeros(rows,1);
31 | end
32 | if nargin < 7
33 | label = cell(rows,1);
34 | end
35 | if nargin < 8
36 | description = cell(rows,1);
37 | end
38 | if nargin < 9
39 | orientation = [zeros(rows,3) ones(rows,1)];
40 | else
41 | [orientationRows orientationColumns] = size(orientation)
42 | assert(orientationRows==rows, 'Orientation matrix must the same number of rows as the position matrix');
43 | assert(orientationColumns==4, 'Orientation matrix must have 4 columns');
44 | end
45 |
46 | associatedNodeID = ''; % use just a constant empty associated node ID for all points
47 |
48 | % Write header
49 | fid=fopen(outputfilename, 'w');
50 | assert(fid > 0, 'Could not open file %s', outputfilename);
51 | fprintf(fid,'# Markups fiducial file version = 4.5\n');
52 | fprintf(fid,'# CoordinateSystem = 0\n');
53 | fprintf(fid,'# columns = id,x,y,z,ow,ox,oy,oz,vis,sel,lock,label,desc,associatedNodeID\n');
54 | for rowIndex=1:rows
55 | fprintf(fid,'%s,%f,%f,%f,%f,%f,%f,%f,%d,%d,%d,%s,%s,%s\n',char(id(rowIndex)),
56 | position(rowIndex,1),position(rowIndex,2),position(rowIndex,3),
57 | orientation(rowIndex,1),orientation(rowIndex,2),orientation(rowIndex,3),orientation(rowIndex,4),
58 | visible(rowIndex),selected(rowIndex),locked(rowIndex),
59 | char(label(rowIndex)),char(description(rowIndex)),associatedNodeID);
60 | end
61 | fclose(fid);
62 |
--------------------------------------------------------------------------------
/MatlabCommander/commandserver/nrrdaddmetafield.m:
--------------------------------------------------------------------------------
1 | function img = nrrdaddmetafield(img, fullFieldName, fieldValue)
2 | % Add a metadata field to an image
3 | %
4 | % Example:
5 | %
6 | % img = nrrdaddmetafield(img, 'MultiVolume.DICOM.EchoTime', 1.348);
7 |
8 | fieldName=regexprep(fullFieldName,'\W','_');
9 | if ~strcmp(fieldName,fullFieldName)
10 | img.metaDataFieldNames.(fieldName) = fullFieldName;
11 | end
12 | img.metaData.(fieldName) = fieldValue;
13 |
--------------------------------------------------------------------------------
/MatlabCommander/commandserver/nrrdread.m:
--------------------------------------------------------------------------------
1 | function img = nrrdread(filename)
2 | % Read image and metadata from a NRRD file (see http://teem.sourceforge.net/nrrd/format.html)
3 | % img = cli_imageread(filename) reads the image volume and associated metadata
4 | %
5 | % img.pixelData: pixel data array
6 | % img.ijkToLpsTransform: pixel (IJK) to physical (LPS, assuming 'space' is 'left-posterior-superior')
7 | % coordinate system transformation, the origin of the IJK coordinate system is (1,1,1) to match Matlab matrix indexing
8 | % img.metaData: contains all the descriptive information in the image header
9 | % img.metaDataFieldNames: Contains full names of metadata fields that cannot be used as Matlab field names because they contains
10 | % special characters (space, dot, etc). Special characters in field names are replaced by underscore by default when the NRRD
11 | % file is read. Full field names are used when writing the image to NRRD file.
12 | %
13 | % Supports reading of 3D and 4D volumes.
14 | %
15 | % Current limitations/caveats:
16 | % * Block datatype is not supported.
17 | % * Only tested with "gzip" and "raw" file encodings.
18 | %
19 | % Partly based on the nrrdread.m function with copyright 2012 The MathWorks, Inc.
20 |
21 | fid = fopen(filename, 'rb');
22 | assert(fid > 0, 'Could not open file.');
23 | cleaner = onCleanup(@() fclose(fid));
24 |
25 | % NRRD files must start with the NRRD word and a version number
26 | theLine = fgetl(fid);
27 | assert(numel(theLine) >= 4, 'Bad signature in file.')
28 | assert(isequal(theLine(1:4), 'NRRD'), 'Bad signature in file.')
29 |
30 | % The general format of a NRRD file (with attached header) is:
31 | %
32 | % NRRD000X
33 | % :
34 | % :
35 | % #
36 | % ...
37 | % :
38 | % :=
39 | % :=
40 | % :=
41 | % #
42 | %
43 | % ...
44 |
45 | img.metaData = {};
46 | img.metaDataFieldNames = {};
47 | % Parse the file a line at a time.
48 | while (true)
49 |
50 | theLine = fgetl(fid);
51 |
52 | if (isempty(theLine) || feof(fid))
53 | % End of the header.
54 | break;
55 | end
56 |
57 | if (isequal(theLine(1), '#'))
58 | % Comment line.
59 | continue;
60 | end
61 |
62 | % "fieldname:= value" or "fieldname: value" or "fieldname:value"
63 | parsedLine = regexp(theLine, ':=?\s*', 'split','once');
64 |
65 | assert(numel(parsedLine) == 2, 'Parsing error')
66 |
67 | field = parsedLine{1};
68 | value = parsedLine{2};
69 |
70 | % Cannot use special characters in field names, so replace them by underscore
71 | % and store the original field name in img.metaDataFieldNames so that it can be
72 | % restored when writing the data.
73 | fieldName=regexprep(field,'\W','_');
74 | if ~strcmp(fieldName,field)
75 | img.metaDataFieldNames.(fieldName) = field;
76 | end
77 |
78 | img.metaData(1).(fieldName) = value;
79 |
80 | end
81 |
82 | datatype = getDatatype(img.metaData.type);
83 |
84 | % Get the size of the data.
85 | assert(isfield(img.metaData, 'sizes') && ...
86 | isfield(img.metaData, 'dimension') && ...
87 | isfield(img.metaData, 'encoding'), ...
88 | 'Missing required metadata fields (sizes, dimension, or encoding).')
89 |
90 | dims = sscanf(img.metaData.sizes, '%d');
91 | ndims = sscanf(img.metaData.dimension, '%d');
92 | assert(numel(dims) == ndims);
93 |
94 | data = readData(fid, img.metaData, datatype);
95 | if isfield(img.metaData, 'endian')
96 | data = adjustEndian(data, img.metaData);
97 | end
98 |
99 | img.pixelData = reshape(data, dims');
100 |
101 | % For convenience, compute the transformation matrix between physical and pixel coordinates
102 | switch (ndims)
103 | case {3}
104 | axes_directions=reshape(sscanf(img.metaData.space_directions,'(%f,%f,%f) (%f,%f,%f) (%f,%f,%f)'),3,3);
105 | case {4}
106 | axes_directions=reshape(sscanf(img.metaData.space_directions,'none (%f,%f,%f) (%f,%f,%f) (%f,%f,%f)'),3,3);
107 | otherwise
108 | assert(false, 'Unsupported pixel data dimension')
109 | end
110 | axes_origin=sscanf(img.metaData.space_origin,'(%f,%f,%f)');
111 | ijkZeroBasedToLpsTransform=[[axes_directions, axes_origin]; [0 0 0 1]];
112 | ijkOneBasedToIjkZeroBasedTransform=[[eye(3), [-1;-1;-1] ]; [0 0 0 1]];
113 | ijkOneBasedToLpsTransform=ijkZeroBasedToLpsTransform*ijkOneBasedToIjkZeroBasedTransform;
114 | % Use the one-based IJK transform (origin is at [1,1,1])
115 | img.ijkToLpsTransform=ijkOneBasedToLpsTransform;
116 |
117 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
118 | function datatype = getDatatype(metaType)
119 | % Determine the datatype
120 | switch (metaType)
121 | case {'signed char', 'int8', 'int8_t'}
122 | datatype = 'int8';
123 | case {'uchar', 'unsigned char', 'uint8', 'uint8_t'}
124 | datatype = 'uint8';
125 | case {'short', 'short int', 'signed short', 'signed short int', ...
126 | 'int16', 'int16_t'}
127 | datatype = 'int16';
128 | case {'ushort', 'unsigned short', 'unsigned short int', 'uint16', ...
129 | 'uint16_t'}
130 | datatype = 'uint16';
131 | case {'int', 'signed int', 'int32', 'int32_t'}
132 | datatype = 'int32';
133 | case {'uint', 'unsigned int', 'uint32', 'uint32_t'}
134 | datatype = 'uint32';
135 | case {'longlong', 'long long', 'long long int', 'signed long long', ...
136 | 'signed long long int', 'int64', 'int64_t'}
137 | datatype = 'int64';
138 | case {'ulonglong', 'unsigned long long', 'unsigned long long int', ...
139 | 'uint64', 'uint64_t'}
140 | datatype = 'uint64';
141 | case {'float'}
142 | datatype = 'single';
143 | case {'double'}
144 | datatype = 'double';
145 | otherwise
146 | assert(false, 'Unknown datatype')
147 | end
148 |
149 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
150 | function data = readData(fidIn, meta, datatype)
151 |
152 | switch (meta.encoding)
153 | case {'raw'}
154 | data = fread(fidIn, inf, [datatype '=>' datatype]);
155 | case {'gzip', 'gz'}
156 | compressedData = fread(fidIn, inf, 'uchar=>uint8');
157 | try
158 | data = zlib_decompress(compressedData,datatype);
159 | catch noMemory
160 | error('Not enough Java heap space (it can be increased in Matlab preferences)');
161 | return;
162 | end
163 | case {'txt', 'text', 'ascii'}
164 | data = fscanf(fidIn, '%f');
165 | data = cast(data, datatype);
166 | otherwise
167 | assert(false, 'Unsupported encoding')
168 | end
169 |
170 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
171 | function data = adjustEndian(data, meta)
172 | % For ignoring unused parameters dummy variables (dummy1 and dummy2) are
173 | % used instead of ~ to maintain compatibility with Matlab R2009b version
174 | [dummy1,dummy2,endian] = computer();
175 | needToSwap = (isequal(endian, 'B') && isequal(lower(meta.endian), 'little')) || ...
176 | (isequal(endian, 'L') && isequal(lower(meta.endian), 'big'));
177 | if (needToSwap)
178 | data = swapbytes(data);
179 | end
180 |
181 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
182 | function M = zlib_decompress(Z,DataType)
183 | % Function for decompressing pixel data
184 | % Z: pixel data to decompress (from uchar to uint8)
185 | % DataType: data type of the volume
186 | % Returns: decompressed pixel data
187 | % Examples:
188 | % pixelData = zlib_decompress(Z,int32);
189 |
190 | import com.mathworks.mlwidgets.io.InterruptibleStreamCopier
191 | a=java.io.ByteArrayInputStream(Z);
192 | b=java.util.zip.GZIPInputStream(a);
193 | isc = InterruptibleStreamCopier.getInterruptibleStreamCopier;
194 | c = java.io.ByteArrayOutputStream;
195 | isc.copyStream(b,c);
196 | M=typecast(c.toByteArray,DataType);
197 |
--------------------------------------------------------------------------------
/MatlabCommander/commandserver/nrrdwrite.m:
--------------------------------------------------------------------------------
1 | function nrrdwrite(outputFilename, img)
2 | % Write image and metadata to a NRRD file (see http://teem.sourceforge.net/nrrd/format.html)
3 | % img.pixelData: pixel data array
4 | % img.ijkToLpsTransform: pixel (IJK) to physical (LPS, assuming 'space' is 'left-posterior-superior')
5 | % coordinate system transformation, the origin of the IJK coordinate system is (1,1,1) to match Matlab matrix indexing
6 | % img.metaData: Contains all the descriptive information in the image header. The following fields are ignored:
7 | % sizes: computed to match size of img.pixelData
8 | % type: computed to match type of img.pixelData
9 | % kinds: computed to match dimension of img.pixelData
10 | % dimension: computed to match dimension of img.pixelData
11 | % space_directions: ignored if img.ijkToLpsTransform is defined
12 | % space_origin: ignored if img.ijkToLpsTransform is defined
13 | % img.metaData: Contains the list of full NRRD field names for each
14 | % metaData field name. All fields should be listed here that have a
15 | % special character in their name (such as dot or space).
16 | % img.metaDataFieldNames: Contains full names of metadata fields that cannot be used as Matlab field names because they contains
17 | % special characters (space, dot, etc). Full field names are used for determining the field name to be used in the NRRD file
18 | % from the Matlab metadata field name.
19 | %
20 | % Supports writing of 3D and 4D volumes.
21 | % 2D pixelData is written as single-slice 3D volume.
22 | %
23 | % Examples:
24 | %
25 | % 1. Using output from nrrdread:
26 | %
27 | % img = nrrdread('testData\MRHeadRot.nrrd')
28 | % nrrdwrite('testOutput.nrrd', img)
29 | %
30 | % 2. Creating volume from scratch - minimal example
31 | %
32 | % [x,y,z] = meshgrid([-10:10],[-12:15],[-8:6]);
33 | % img.pixelData = x/3+y/4+z/2;
34 | %
35 | % nrrdwrite('testOutput.nrrd', img);
36 | %
37 | % 3. Creating volume from scratch
38 | %
39 | % % Set pixel data
40 | % [x,y,z] = meshgrid([-10:10],[-12:15],[-8:6]);
41 | % img.pixelData = x/3+y/4+z/2;
42 | %
43 | % % Define origin, spacing, axis directions by a homogeneous transformation matrix:
44 | % img.ijkToLpsTransform = [ 1.2 0 0 10; 0 1.2 0 12; 0 0 3.0 -22; 0 0 0 1];
45 | %
46 | % % Enable compression
47 | % img.metaData.encoding='gzip';
48 | %
49 | % nrrdwrite('testOutput.nrrd', img);
50 | %
51 |
52 | % Open file for writing
53 | fid=fopen(outputFilename, 'w');
54 | if(fid<=0)
55 | fprintf('Could not open file: %s\n', outputFilename);
56 | end
57 |
58 | standardFieldNames = { 'type', 'dimension', 'space', 'sizes', 'space directions', 'kinds', 'endian', 'encoding', 'space origin', 'measurement frame' };
59 |
60 | fprintf(fid,'NRRD0005\n');
61 | fprintf(fid,'# Complete NRRD file format specification at:\n');
62 | fprintf(fid,'# http://teem.sourceforge.net/nrrd/format.html\n');
63 |
64 | % Create/override mandatory fields
65 |
66 | img.metaData.type = getMetaType(class(img.pixelData));
67 |
68 | if ~isfield(img.metaData,'space')
69 | img.metaData.space = 'left-posterior-superior';
70 | end
71 |
72 | img.metaData.dimension = length(size(img.pixelData)); % ndim is not defined for int16 arrays
73 |
74 | % 2D image is be written as single-slice 3D volume
75 | if img.metaData.dimension == 2
76 | img.metaData.dimension = 3;
77 | img.metaData.sizes=num2str([size(img.pixelData), 1]);
78 | else
79 | img.metaData.sizes=num2str(size(img.pixelData));
80 | end
81 |
82 | if isfield(img,'ijkToLpsTransform')
83 | % Write zero-based IJK transform (origin is at [0,0,0]) to the image header
84 | ijkOneBasedToLpsTransform=img.ijkToLpsTransform;
85 | ijkOneBasedToIjkZeroBasedTransform=[[eye(3), [-1;-1;-1] ]; [0 0 0 1]];
86 | ijkZeroBasedToLpsTransform=ijkOneBasedToLpsTransform*inv(ijkOneBasedToIjkZeroBasedTransform);
87 | axes_origin=ijkZeroBasedToLpsTransform(1:3,4);
88 | img.metaData.space_origin=sprintf('(%f,%f,%f)',reshape(axes_origin,1,3));
89 | axes_directions=ijkZeroBasedToLpsTransform(1:3,1:3);
90 | switch (img.metaData.dimension)
91 | case {3}
92 | img.metaData.space_directions=sprintf('(%f,%f,%f) (%f,%f,%f) (%f,%f,%f)',reshape(axes_directions,1,9));
93 | case {4}
94 | img.metaData.space_directions=sprintf('none (%f,%f,%f) (%f,%f,%f) (%f,%f,%f)',reshape(axes_directions,1,9));
95 | otherwise
96 | assert(false, 'Unsupported pixel data dimension')
97 | end
98 | end
99 |
100 | if ~isfield(img.metaData,'space_directions')
101 | switch (img.metaData.dimension)
102 | case {3}
103 | img.metaData.space_directions = '(1,0,0) (0,1,0) (0,0,1)';
104 | case {4}
105 | img.metaData.space_directions = 'none (1,0,0) (0,1,0) (0,0,1)';
106 | otherwise
107 | assert(false, 'Unsupported pixel data dimension')
108 | end
109 | end
110 |
111 | switch (img.metaData.dimension)
112 | case {3}
113 | img.metaData.kinds='domain domain domain';
114 | case {4}
115 | img.metaData.kinds='list domain domain domain';
116 | % Add a custom field to make the volume load into 3D Slicer as a MultiVolume
117 | img = nrrdaddmetafield(img,'MultiVolume.NumberOfFrames',size(img.pixelData,4));
118 | otherwise
119 | assert(false, 'Unsupported pixel data dimension')
120 | end
121 |
122 | if ~isfield(img.metaData,'endian')
123 | img.metaData.endian='little';
124 | end
125 |
126 | if ~isfield(img.metaData,'encoding')
127 | img.metaData.encoding='raw';
128 | end
129 |
130 | % Make sure that standard field names that contain special
131 | % characters have their full field names defined.
132 | for k=1:length(standardFieldNames)
133 | fullFieldName=standardFieldNames{k};
134 | fieldName=regexprep(fullFieldName,'\W','_');
135 | if ~strcmp(fieldName,fullFieldName)
136 | img.metaDataFieldNames.(fieldName)=fullFieldName;
137 | end
138 | end
139 |
140 | % Print the header data to the output file
141 | metaDataCellArr = struct2cell(img.metaData);
142 | fields = fieldnames(img.metaData);
143 | for i=1:numel(fields)
144 | writeFieldName(fid, fields{i}, img.metaDataFieldNames, standardFieldNames);
145 | writeDataByType(fid,metaDataCellArr{i});
146 | end
147 |
148 | fprintf(fid,'\n');
149 |
150 | % Write pixel data
151 | switch (img.metaData.encoding)
152 | case {'raw'}
153 | fwrite(fid, img.pixelData, class(img.pixelData));
154 | case {'gzip', 'gz'}
155 | try
156 | compressedPixelData = zlib_compress(img.pixelData, class(img.pixelData));
157 | catch noMemory
158 | disp('Not enough Java heap space (it can be increased in Matlab preferences)');
159 | return;
160 | end
161 | fwrite(fid, compressedPixelData, class(compressedPixelData));
162 | otherwise
163 | assert(false, 'Unsupported encoding')
164 | end
165 |
166 | fclose('all');
167 |
168 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
169 | function writeFieldName(fid, fieldName, fullFieldNames, standardFieldNames)
170 | % If full field name is listed in img.metaDataFieldNames then use that
171 | % instead of the Matlab field name.
172 | if isfield(fullFieldNames,fieldName)
173 | fullFieldName = fullFieldNames.(fieldName);
174 | else
175 | fullFieldName = fieldName;
176 | end
177 |
178 | isStandardFieldName = ~isempty(find(strcmp(fullFieldName, standardFieldNames), 1));
179 | if isStandardFieldName
180 | % Standard field names are separated by :
181 | fprintf(fid,'%s: ',fullFieldName);
182 | else
183 | % Custom field names are separated by :=
184 | fprintf(fid,'%s:= ',fullFieldName);
185 | end
186 |
187 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
188 | function writeDataByType(fid, data)
189 | % Function that writes the header data to file based on the type of data
190 | % params: - fid of file to write to
191 | % - data from header to write
192 | if ischar(data)
193 | fprintf(fid,'%s\n',data);
194 | else
195 | fprintf(fid,'%d ',data);
196 | fprintf(fid,'\n');
197 | end
198 |
199 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
200 | function metaType = getMetaType(matlabType)
201 | % Determine the metadata type from the Matlab type
202 | switch (matlabType)
203 | case {'int8'}
204 | metaType = 'int8';
205 | case {'uint8'}
206 | metaType = 'uint8';
207 | case {'int16'}
208 | metaType = 'int16';
209 | case {'uint16'}
210 | metaType = 'uint16';
211 | case {'int32'}
212 | metaType = 'int32';
213 | case {'uint32'}
214 | metaType = 'uint32';
215 | case {'int64'}
216 | metaType = 'int64';
217 | case {'uint64'}
218 | metaType = 'uint64';
219 | case {'single'}
220 | metaType = 'float';
221 | case {'double'}
222 | metaType = 'double';
223 | otherwise
224 | assert(false, 'Unsupported Matlab data type')
225 | end
226 |
227 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
228 | function compressedPixelData = zlib_compress(pixelData,DataType)
229 | % Function for compressing pixel data
230 | % pixelData: pixel data to be compressed
231 | % DataType: data type of volume
232 | % Returns: compressed data
233 | % Examples:
234 | % compressedPixelData = zlib_compress(pixelData,int32)
235 |
236 | cn = strmatch(DataType,{'double','single','logical','char','int8','uint8',...
237 | 'int16','uint16','int32','uint32','int64','uint64'});
238 |
239 | if cn == 3 || cn == 4
240 | pixelData=uint8(pixelData);
241 | end
242 | pixelData=typecast(pixelData(:),'uint8');
243 | a=java.io.ByteArrayOutputStream();
244 | b=java.util.zip.GZIPOutputStream(a);
245 | b.write(pixelData);
246 | b.close;
247 | compressedPixelData=typecast(a.toByteArray,'uint8');
248 | a.close;
249 |
--------------------------------------------------------------------------------
/MatlabCommander/commandserver/read_ply.m:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PerkLab/SlicerMatlabBridge/e9b297dbb6248be91a44013a85e21ff0fd8d13fd/MatlabCommander/commandserver/read_ply.m
--------------------------------------------------------------------------------
/MatlabCommander/commandserver/stlread.m:
--------------------------------------------------------------------------------
1 | function [v, f, n, c, stltitle] = stlread(filename, verbose)
2 | % This function reads an STL file in binary format into vertex and face
3 | % matrices v and f.
4 | %
5 | % USAGE: [v, f, n, c, stltitle] = stlread(filename, verbose);
6 | %
7 | % verbose is an optional logical argument for displaying some loading
8 | % information (default is false).
9 | %
10 | % v contains the vertices for all triangles [3*n x 3].
11 | % f contains the vertex lists defining each triangle face [n x 3].
12 | % n contains the normals for each triangle face [n x 3].
13 | % c is optional and contains color rgb data in 5 bits [n x 3].
14 | % if C is not specified, the item is determined to be of uniform temp
15 | % if color is specified, a max and min temp are specified and blue is
16 | % used to range the temperature from min to max in 32 steps
17 | % Valid - (15) - 1 color is used, 0 color is not used
18 | % Red - (10:14) - 0:31 - Reserved
19 | % Green - (5:9) - 0:31 - Reserved
20 | % Blue - (0:4) - 0:31 - Used for temperature scaling
21 |
22 | % stltitle contains the title of the specified stl file [1 x 80].
23 | %
24 | % To see plot the 3D surface use:
25 | % patch('Faces',f,'Vertices',v,'FaceVertexCData',c);
26 | % or
27 | % plot3(v(:,1),v(:,2),v(:,3),'.');
28 | %
29 | % Duplicate vertices can be removed using:
30 | % [v, f]=patchslim(v, f);
31 | %
32 | % ===================================================
33 | %
34 | % For more information see:
35 | % http://www.esmonde-white.com/home/diversions/matlab-program-for-loading-stl-files
36 | %
37 | % Based on code originally written by:
38 | % Doron Harlev
39 | % and combined with some code by:
40 | % Eric C. Johnson, 11-Dec-2008
41 | % Copyright 1999-2008 The MathWorks, Inc.
42 | %
43 | % Re-written and optimized by Francis Esmonde-White, May 2010.
44 | %
45 | % ===================================================
46 | % Minor Bugfix.
47 | % Bug in color algorithm fixed by William Grant Lohsen, May 2012.
48 | %
49 | % NOTE: Color implementation is compatible with VisCAM and SolidView
50 | % From Wikipedia:
51 | % The VisCAM and SolidView software packages use the two 'attribute byte count'
52 | % bytes at the end of every triangle to store a 15 bit RGB colour:
53 | % bit 0 to 4 are the intensity level for blue (0 to 31)
54 | % bits 5 to 9 are the intensity level for green (0 to 31)
55 | % bits 10 to 14 are the intensity level for red (0 to 31)
56 | % bit 15 is 1 if the colour is valid
57 | % bit 15 is 0 if the colour is not valid (as with normal STL files)
58 | %
59 |
60 | use_color=(nargout>=4);
61 |
62 | fid=fopen(filename, 'r'); %Open the file, assumes STL Binary format.
63 | if fid == -1
64 | error('File could not be opened, check name or path.')
65 | end
66 |
67 | if ~exist('verbose','var')
68 | verbose = false;
69 | end
70 |
71 | ftitle=fread(fid,80,'uchar=>schar'); % Read file title
72 | numFaces=fread(fid,1,'int32'); % Read number of Faces
73 |
74 | T = fread(fid,inf,'uint8=>uint8'); % read the remaining values
75 | fclose(fid);
76 |
77 | stltitle = char(ftitle');
78 |
79 | if verbose
80 | fprintf('\nTitle: %s\n', stltitle);
81 | fprintf('Number of Faces: %d\n', numFaces);
82 | disp('Please wait...');
83 | end
84 |
85 | % Each facet is 50 bytes
86 | % - Three single precision values specifying the face normal vector
87 | % - Three single precision values specifying the first vertex (XYZ)
88 | % - Three single precision values specifying the second vertex (XYZ)
89 | % - Three single precision values specifying the third vertex (XYZ)
90 | % - Two color bytes (possibly zeroed)
91 |
92 | % 3 dimensions x 4 bytes x 4 vertices = 48 bytes for triangle vertices
93 | % 2 bytes = color (if color is specified)
94 |
95 | trilist = 1:48;
96 |
97 | ind = reshape(repmat(50*(0:(numFaces-1)),[48,1]),[1,48*numFaces])+repmat(trilist,[1,numFaces]);
98 | Tri = reshape(typecast(T(ind),'single'),[3,4,numFaces]);
99 |
100 | n=squeeze(Tri(:,1,:))';
101 | n=double(n);
102 |
103 | v=Tri(:,2:4,:);
104 | v = reshape(v,[3,3*numFaces]);
105 | v = double(v)';
106 |
107 | f = reshape(1:3*numFaces,[3,numFaces])';
108 |
109 | if use_color
110 | c0 = typecast(T(49:50),'uint16');
111 | if (bitget(c0(1),16)==1)
112 | trilist = 49:50;
113 | ind = reshape(repmat(50*(0:(numFaces-1)),[2,1]),[1,2*numFaces])+repmat(trilist,[1,numFaces]);
114 | c0 = reshape(typecast(T(ind),'uint16'),[1,numFaces]);
115 |
116 | %modified by WGL
117 | r=bitshift(bitand(2^15-1, c0),-10);
118 | g=bitshift(bitand(2^10-1, c0),-5);
119 | b=bitand(2^5-1, c0);
120 | %end modification
121 | c=[r; g; b]';
122 |
123 | else
124 | c = zeros(numFaces,3);
125 | end
126 | end
127 |
128 | if verbose
129 | disp('Done!');
130 | end
--------------------------------------------------------------------------------
/MatlabCommander/commandserver/stlwrite.m:
--------------------------------------------------------------------------------
1 | function stlwrite(filename, varargin)
2 | %STLWRITE Write STL file from patch or surface data.
3 | %
4 | % STLWRITE(FILE, FV) writes a stereolithography (STL) file to FILE for a
5 | % triangulated patch defined by FV (a structure with fields 'vertices'
6 | % and 'faces').
7 | %
8 | % STLWRITE(FILE, FACES, VERTICES) takes faces and vertices separately,
9 | % rather than in an FV struct
10 | %
11 | % STLWRITE(FILE, X, Y, Z) creates an STL file from surface data in X, Y,
12 | % and Z. STLWRITE triangulates this gridded data into a triangulated
13 | % surface using triangulation options specified below. X, Y and Z can be
14 | % two-dimensional arrays with the same size. If X and Y are vectors with
15 | % length equal to SIZE(Z,2) and SIZE(Z,1), respectively, they are passed
16 | % through MESHGRID to create gridded data. If X or Y are scalar values,
17 | % they are used to specify the X and Y spacing between grid points.
18 | %
19 | % STLWRITE(...,'PropertyName',VALUE,'PropertyName',VALUE,...) writes an
20 | % STL file using the following property values:
21 | %
22 | % MODE - File is written using 'binary' (default) or 'ascii'.
23 | %
24 | % TITLE - Header text (max 80 chars) written to the STL file.
25 | %
26 | % TRIANGULATION - When used with gridded data, TRIANGULATION is either:
27 | % 'delaunay' - (default) Delaunay triangulation of X, Y
28 | % 'f' - Forward slash division of grid quads
29 | % 'b' - Back slash division of quadrilaterals
30 | % 'x' - Cross division of quadrilaterals
31 | % Note that 'f', 'b', or 't' triangulations now use an
32 | % inbuilt version of FEX entry 28327, "mesh2tri".
33 | %
34 | % FACECOLOR - Single colour (1-by-3) or one-colour-per-face (N-by-3)
35 | % vector of RGB colours, for face/vertex input. RGB range
36 | % is 5 bits (0:31), stored in VisCAM/SolidView format
37 | % (http://en.wikipedia.org/wiki/STL_(file_format)#Color_in_binary_STL)
38 | %
39 | % Example 1:
40 | % % Write binary STL from face/vertex data
41 | % tmpvol = zeros(20,20,20); % Empty voxel volume
42 | % tmpvol(8:12,8:12,5:15) = 1; % Turn some voxels on
43 | % fv = isosurface(tmpvol, 0.99); % Create the patch object
44 | % stlwrite('test.stl',fv) % Save to binary .stl
45 | %
46 | % Example 2:
47 | % % Write ascii STL from gridded data
48 | % [X,Y] = deal(1:40); % Create grid reference
49 | % Z = peaks(40); % Create grid height
50 | % stlwrite('test.stl',X,Y,Z,'mode','ascii')
51 |
52 | % Original idea adapted from surf2stl by Bill McDonald. Huge speed
53 | % improvements implemented by Oliver Woodford. Non-Delaunay triangulation
54 | % of quadrilateral surface courtesy of Kevin Moerman. FaceColor
55 | % implementation by Grant Lohsen.
56 | %
57 | % Author: Sven Holcombe, 11-24-11
58 |
59 |
60 | % Check valid filename path
61 | path = fileparts(filename);
62 | if ~isempty(path) && ~exist(path,'dir')
63 | error('Directory "%s" does not exist.',path);
64 | end
65 |
66 | % Get faces, vertices, and user-defined options for writing
67 | [faces, vertices, options] = parseInputs(varargin{:});
68 | asciiMode = strcmp( options.mode ,'ascii');
69 |
70 | % Create the facets
71 | facets = single(vertices');
72 | facets = reshape(facets(:,faces'), 3, 3, []);
73 |
74 | % Compute their normals
75 | V1 = squeeze(facets(:,2,:) - facets(:,1,:));
76 | V2 = squeeze(facets(:,3,:) - facets(:,1,:));
77 | normals = V1([2 3 1],:) .* V2([3 1 2],:) - V2([2 3 1],:) .* V1([3 1 2],:);
78 | clear V1 V2
79 | normals = bsxfun(@times, normals, 1 ./ sqrt(sum(normals .* normals, 1)));
80 | facets = cat(2, reshape(normals, 3, 1, []), facets);
81 | clear normals
82 |
83 | % Open the file for writing
84 | permissions = {'w','wb+'};
85 | fid = fopen(filename, permissions{asciiMode+1});
86 | if (fid == -1)
87 | error('stlwrite:cannotWriteFile', 'Unable to write to %s', filename);
88 | end
89 |
90 | % Write the file contents
91 | if asciiMode
92 | % Write HEADER
93 | fprintf(fid,'solid %s\r\n',options.title);
94 | % Write DATA
95 | fprintf(fid,[...
96 | 'facet normal %.7E %.7E %.7E\r\n' ...
97 | 'outer loop\r\n' ...
98 | 'vertex %.7E %.7E %.7E\r\n' ...
99 | 'vertex %.7E %.7E %.7E\r\n' ...
100 | 'vertex %.7E %.7E %.7E\r\n' ...
101 | 'endloop\r\n' ...
102 | 'endfacet\r\n'], facets);
103 | % Write FOOTER
104 | fprintf(fid,'endsolid %s\r\n',options.title);
105 |
106 | else % BINARY
107 | % Write HEADER
108 | fprintf(fid, '%-80s', options.title); % Title
109 | fwrite(fid, size(facets, 3), 'uint32'); % Number of facets
110 | % Write DATA
111 | % Add one uint16(0) to the end of each facet using a typecasting trick
112 | facets = reshape(typecast(facets(:), 'uint16'), 12*2, []);
113 | % Set the last bit to 0 (default) or supplied RGB
114 | facets(end+1,:) = options.facecolor;
115 | fwrite(fid, facets, 'uint16');
116 | end
117 |
118 | % Close the file
119 | fclose(fid);
120 | fprintf('Wrote %d facets\n',size(facets, 3));
121 |
122 |
123 | %% Input handling subfunctions
124 | function [faces, vertices, options] = parseInputs(varargin)
125 | % Determine input type
126 | if isstruct(varargin{1}) % stlwrite('file', FVstruct, ...)
127 | if ~all(isfield(varargin{1},{'vertices','faces'}))
128 | error( 'Variable p must be a faces/vertices structure' );
129 | end
130 | faces = varargin{1}.faces;
131 | vertices = varargin{1}.vertices;
132 | options = parseOptions(varargin{2:end});
133 |
134 | elseif isnumeric(varargin{1})
135 | firstNumInput = cellfun(@isnumeric,varargin);
136 | firstNumInput(find(~firstNumInput,1):end) = 0; % Only consider numerical input PRIOR to the first non-numeric
137 | numericInputCnt = nnz(firstNumInput);
138 |
139 | options = parseOptions(varargin{numericInputCnt+1:end});
140 | switch numericInputCnt
141 | case 3 % stlwrite('file', X, Y, Z, ...)
142 | % Extract the matrix Z
143 | Z = varargin{3};
144 |
145 | % Convert scalar XY to vectors
146 | ZsizeXY = fliplr(size(Z));
147 | for i = 1:2
148 | if isscalar(varargin{i})
149 | varargin{i} = (0:ZsizeXY(i)-1) * varargin{i};
150 | end
151 | end
152 |
153 | % Extract X and Y
154 | if isequal(size(Z), size(varargin{1}), size(varargin{2}))
155 | % X,Y,Z were all provided as matrices
156 | [X,Y] = varargin{1:2};
157 | elseif numel(varargin{1})==ZsizeXY(1) && numel(varargin{2})==ZsizeXY(2)
158 | % Convert vector XY to meshgrid
159 | [X,Y] = meshgrid(varargin{1}, varargin{2});
160 | else
161 | error('stlwrite:badinput', 'Unable to resolve X and Y variables');
162 | end
163 |
164 | % Convert to faces/vertices
165 | if strcmp(options.triangulation,'delaunay')
166 | faces = delaunay(X,Y);
167 | vertices = [X(:) Y(:) Z(:)];
168 | else
169 | if ~exist('mesh2tri','file')
170 | error('stlwrite:missing', '"mesh2tri" is required to convert X,Y,Z matrices to STL. It can be downloaded from:\n%s\n',...
171 | 'http://www.mathworks.com/matlabcentral/fileexchange/28327')
172 | end
173 | [faces, vertices] = mesh2tri(X, Y, Z, options.triangulation);
174 | end
175 |
176 | case 2 % stlwrite('file', FACES, VERTICES, ...)
177 | faces = varargin{1};
178 | vertices = varargin{2};
179 |
180 | otherwise
181 | error('stlwrite:badinput', 'Unable to resolve input types.');
182 | end
183 | end
184 |
185 | if ~isempty(options.facecolor) % Handle colour preparation
186 | facecolor = uint16(options.facecolor);
187 | %Set the Valid Color bit (bit 15)
188 | c0 = bitshift(ones(size(faces,1),1,'uint16'),15);
189 | %Red color (10:15), Blue color (5:9), Green color (0:4)
190 | c0 = bitor(bitshift(bitand(2^6-1, facecolor(:,1)),10),c0);
191 | c0 = bitor(bitshift(bitand(2^11-1, facecolor(:,2)),5),c0);
192 | c0 = bitor(bitand(2^6-1, facecolor(:,3)),c0);
193 | options.facecolor = c0;
194 | else
195 | options.facecolor = 0;
196 | end
197 |
198 | function options = parseOptions(varargin)
199 | IP = inputParser;
200 | IP.addParamValue('mode', 'binary', @ischar)
201 | IP.addParamValue('title', sprintf('Created by stlwrite.m %s',datestr(now)), @ischar);
202 | IP.addParamValue('triangulation', 'delaunay', @ischar);
203 | IP.addParamValue('facecolor',[], @isnumeric)
204 | IP.parse(varargin{:});
205 | options = IP.Results;
206 |
207 | function [F,V]=mesh2tri(X,Y,Z,tri_type)
208 | % function [F,V]=mesh2tri(X,Y,Z,tri_type)
209 | %
210 | % Available from http://www.mathworks.com/matlabcentral/fileexchange/28327
211 | % Included here for convenience. Many thanks to Kevin Mattheus Moerman
212 | % kevinmoerman@hotmail.com
213 | % 15/07/2010
214 | %------------------------------------------------------------------------
215 |
216 | [J,I]=meshgrid(1:1:size(X,2)-1,1:1:size(X,1)-1);
217 |
218 | switch tri_type
219 | case 'f'%Forward slash
220 | TRI_I=[I(:),I(:)+1,I(:)+1; I(:),I(:),I(:)+1];
221 | TRI_J=[J(:),J(:)+1,J(:); J(:),J(:)+1,J(:)+1];
222 | F = sub2ind(size(X),TRI_I,TRI_J);
223 | case 'b'%Back slash
224 | TRI_I=[I(:),I(:)+1,I(:); I(:)+1,I(:)+1,I(:)];
225 | TRI_J=[J(:)+1,J(:),J(:); J(:)+1,J(:),J(:)+1];
226 | F = sub2ind(size(X),TRI_I,TRI_J);
227 | case 'x'%Cross
228 | TRI_I=[I(:)+1,I(:); I(:)+1,I(:)+1; I(:),I(:)+1; I(:),I(:)];
229 | TRI_J=[J(:),J(:); J(:)+1,J(:); J(:)+1,J(:)+1; J(:),J(:)+1];
230 | IND=((numel(X)+1):numel(X)+prod(size(X)-1))';
231 | F = sub2ind(size(X),TRI_I,TRI_J);
232 | F(:,3)=repmat(IND,[4,1]);
233 | Fe_I=[I(:),I(:)+1,I(:)+1,I(:)]; Fe_J=[J(:),J(:),J(:)+1,J(:)+1];
234 | Fe = sub2ind(size(X),Fe_I,Fe_J);
235 | Xe=mean(X(Fe),2); Ye=mean(Y(Fe),2); Ze=mean(Z(Fe),2);
236 | X=[X(:);Xe(:)]; Y=[Y(:);Ye(:)]; Z=[Z(:);Ze(:)];
237 | end
238 |
239 | V=[X(:),Y(:),Z(:)];
--------------------------------------------------------------------------------
/MatlabCommander/commandserver/write_ply.m:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PerkLab/SlicerMatlabBridge/e9b297dbb6248be91a44013a85e21ff0fd8d13fd/MatlabCommander/commandserver/write_ply.m
--------------------------------------------------------------------------------
/MatlabModuleGenerator/CMakeLists.txt:
--------------------------------------------------------------------------------
1 |
2 | #-----------------------------------------------------------------------------
3 | set(MODULE_NAME MatlabModuleGenerator)
4 | set(MODULE_TITLE "Matlab Module Generator")
5 |
6 | string(TOUPPER ${MODULE_NAME} MODULE_NAME_UPPER)
7 |
8 | #-----------------------------------------------------------------------------
9 | add_subdirectory(Logic)
10 |
11 | #-----------------------------------------------------------------------------
12 | set(MODULE_EXPORT_DIRECTIVE "Q_SLICER_QTMODULES_${MODULE_NAME_UPPER}_EXPORT")
13 |
14 | # Current_{source,binary} and Slicer_{Libs,Base} already included
15 | set(MODULE_INCLUDE_DIRECTORIES
16 | ${CMAKE_CURRENT_SOURCE_DIR}/Logic
17 | ${CMAKE_CURRENT_BINARY_DIR}/Logic
18 | )
19 |
20 | set(MODULE_SRCS
21 | qSlicer${MODULE_NAME}Module.cxx
22 | qSlicer${MODULE_NAME}Module.h
23 | qSlicer${MODULE_NAME}ModuleWidget.cxx
24 | qSlicer${MODULE_NAME}ModuleWidget.h
25 | )
26 |
27 | set(MODULE_MOC_SRCS
28 | qSlicer${MODULE_NAME}Module.h
29 | qSlicer${MODULE_NAME}ModuleWidget.h
30 | )
31 |
32 | set(MODULE_UI_SRCS
33 | Resources/UI/qSlicer${MODULE_NAME}ModuleWidget.ui
34 | )
35 |
36 | set(MODULE_TARGET_LIBRARIES
37 | vtkSlicer${MODULE_NAME}ModuleLogic
38 | )
39 |
40 | set(MODULE_RESOURCES
41 | Resources/qSlicer${MODULE_NAME}Module.qrc
42 | )
43 |
44 | #-----------------------------------------------------------------------------
45 | slicerMacroBuildQtModule(
46 | NAME ${MODULE_NAME}
47 | TITLE ${MODULE_TITLE}
48 | EXPORT_DIRECTIVE ${MODULE_EXPORT_DIRECTIVE}
49 | INCLUDE_DIRECTORIES ${MODULE_INCLUDE_DIRECTORIES}
50 | SRCS ${MODULE_SRCS}
51 | MOC_SRCS ${MODULE_MOC_SRCS}
52 | UI_SRCS ${MODULE_UI_SRCS}
53 | TARGET_LIBRARIES ${MODULE_TARGET_LIBRARIES}
54 | RESOURCES ${MODULE_RESOURCES}
55 | WITH_GENERIC_TESTS
56 | )
57 |
58 | #-----------------------------------------------------------------------------
59 | if(BUILD_TESTING)
60 | add_subdirectory(Testing)
61 | endif()
62 |
63 | #-----------------------------------------------------------------------------
64 | set(TEMPLATE_FILES
65 | MatlabModuleTemplate.m
66 | MatlabModuleTemplate.xml
67 | )
68 |
69 | IF (WIN32)
70 | set(TEMPLATE_FILES ${TEMPLATE_FILES} MatlabModuleTemplate.bat)
71 | ELSE()
72 | set(TEMPLATE_FILES ${TEMPLATE_FILES} MatlabModuleTemplate)
73 | ENDIF()
74 |
75 | foreach(TEMPLATE_FILE ${TEMPLATE_FILES})
76 | configure_file(
77 | ${CMAKE_CURRENT_SOURCE_DIR}/Resources/Templates/${TEMPLATE_FILE}
78 | ${CMAKE_BINARY_DIR}/${Slicer_QTLOADABLEMODULES_SHARE_DIR}/${MODULE_NAME}/${TEMPLATE_FILE}
79 | COPYONLY)
80 | install(
81 | FILES ${CMAKE_BINARY_DIR}/${Slicer_QTLOADABLEMODULES_SHARE_DIR}/${MODULE_NAME}/${TEMPLATE_FILE}
82 | DESTINATION ${Slicer_INSTALL_QTLOADABLEMODULES_SHARE_DIR}/${MODULE_NAME} COMPONENT Runtime)
83 | endforeach()
84 |
--------------------------------------------------------------------------------
/MatlabModuleGenerator/Logic/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | project(vtkSlicer${MODULE_NAME}ModuleLogic)
2 |
3 | set(KIT ${PROJECT_NAME})
4 |
5 | set(${KIT}_EXPORT_DIRECTIVE "VTK_SLICER_${MODULE_NAME_UPPER}_MODULE_LOGIC_EXPORT")
6 |
7 | set(${KIT}_INCLUDE_DIRECTORIES
8 | )
9 |
10 | set(${KIT}_SRCS
11 | vtkSlicer${MODULE_NAME}Logic.cxx
12 | vtkSlicer${MODULE_NAME}Logic.h
13 | )
14 |
15 | set(${KIT}_TARGET_LIBRARIES
16 | ${ITK_LIBRARIES}
17 | )
18 |
19 | #-----------------------------------------------------------------------------
20 | SlicerMacroBuildModuleLogic(
21 | NAME ${KIT}
22 | EXPORT_DIRECTIVE ${${KIT}_EXPORT_DIRECTIVE}
23 | INCLUDE_DIRECTORIES ${${KIT}_INCLUDE_DIRECTORIES}
24 | SRCS ${${KIT}_SRCS}
25 | TARGET_LIBRARIES ${${KIT}_TARGET_LIBRARIES}
26 | )
27 |
--------------------------------------------------------------------------------
/MatlabModuleGenerator/Logic/vtkSlicerMatlabModuleGeneratorLogic.cxx:
--------------------------------------------------------------------------------
1 | /*==============================================================================
2 |
3 | Program: 3D Slicer
4 |
5 | Portions (c) Copyright Brigham and Women's Hospital (BWH) All Rights Reserved.
6 |
7 | See COPYRIGHT.txt
8 | or http://www.slicer.org/copyright/copyright.txt for details.
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 |
16 | ==============================================================================*/
17 |
18 | // MatlabModuleGenerator Logic includes
19 | #include "vtkSlicerMatlabModuleGeneratorLogic.h"
20 |
21 | // MRML includes
22 | #include "vtkMRMLScene.h"
23 |
24 | // VTK includes
25 | #include
26 | #include
27 | #include
28 | #include
29 |
30 | // STD includes
31 | #include
32 | #include // for std::remove
33 |
34 | // Slicer includes
35 | #include "vtkSlicerConfigure.h" // For Slicer_CLIMODULES_SUBDIR
36 |
37 | static const std::string TEMPLATE_NAME="MatlabModuleTemplate";
38 | /* Define case insensitive string compare for all supported platforms. */
39 | #if defined( _WIN32 ) && !defined(__CYGWIN__)
40 | static const std::string MODULE_PROXY_TEMPLATE_EXTENSION=".bat";
41 | static const std::string MATLAB_COMMANDER_EXECUTABLE_NAME="MatlabCommander.exe";
42 | #else
43 | static const std::string MODULE_PROXY_TEMPLATE_EXTENSION="";
44 | static const std::string MATLAB_COMMANDER_EXECUTABLE_NAME="MatlabCommander";
45 | #include
46 | #endif
47 | static const std::string MODULE_SCRIPT_TEMPLATE_EXTENSION=".m";
48 | static const std::string MODULE_DEFINITION_TEMPLATE_EXTENSION=".xml";
49 |
50 |
51 | //----------------------------------------------------------------------------
52 | vtkStandardNewMacro(vtkSlicerMatlabModuleGeneratorLogic);
53 |
54 | //----------------------------------------------------------------------------
55 | vtkSlicerMatlabModuleGeneratorLogic::vtkSlicerMatlabModuleGeneratorLogic()
56 | {
57 | }
58 |
59 | //----------------------------------------------------------------------------
60 | vtkSlicerMatlabModuleGeneratorLogic::~vtkSlicerMatlabModuleGeneratorLogic()
61 | {
62 | }
63 |
64 | //----------------------------------------------------------------------------
65 | void vtkSlicerMatlabModuleGeneratorLogic::PrintSelf(ostream& os, vtkIndent indent)
66 | {
67 | this->Superclass::PrintSelf(os, indent);
68 | }
69 |
70 | //---------------------------------------------------------------------------
71 | void vtkSlicerMatlabModuleGeneratorLogic::SetMRMLSceneInternal(vtkMRMLScene * newScene)
72 | {
73 | vtkNew events;
74 | events->InsertNextValue(vtkMRMLScene::NodeAddedEvent);
75 | events->InsertNextValue(vtkMRMLScene::NodeRemovedEvent);
76 | events->InsertNextValue(vtkMRMLScene::EndBatchProcessEvent);
77 | this->SetAndObserveMRMLSceneEventsInternal(newScene, events.GetPointer());
78 | }
79 |
80 | //-----------------------------------------------------------------------------
81 | void vtkSlicerMatlabModuleGeneratorLogic::RegisterNodes()
82 | {
83 | assert(this->GetMRMLScene() != 0);
84 | }
85 |
86 | //---------------------------------------------------------------------------
87 | void vtkSlicerMatlabModuleGeneratorLogic::UpdateFromMRMLScene()
88 | {
89 | assert(this->GetMRMLScene() != 0);
90 | }
91 |
92 | //---------------------------------------------------------------------------
93 | void vtkSlicerMatlabModuleGeneratorLogic
94 | ::OnMRMLSceneNodeAdded(vtkMRMLNode* vtkNotUsed(node))
95 | {
96 | }
97 |
98 | //---------------------------------------------------------------------------
99 | void vtkSlicerMatlabModuleGeneratorLogic
100 | ::OnMRMLSceneNodeRemoved(vtkMRMLNode* vtkNotUsed(node))
101 | {
102 | }
103 |
104 | //---------------------------------------------------------------------------
105 | const char* vtkSlicerMatlabModuleGeneratorLogic
106 | ::GetMatlabModuleDirectory()
107 | {
108 | // Find out where the generated Matlab modules are
109 | std::string dir=this->GetModuleShareDirectory()+"/../../../../../MatlabModules";
110 | this->MatlabModuleDirectory=vtksys::SystemTools::CollapseFullPath(dir.c_str());
111 | return this->MatlabModuleDirectory.c_str();
112 | }
113 |
114 | //---------------------------------------------------------------------------
115 | const char* vtkSlicerMatlabModuleGeneratorLogic
116 | ::GetMatlabCommandServerDirectory()
117 | {
118 | // Find out where the commandserver Matlab files are
119 | std::string dir=this->GetModuleShareDirectory()+"/../../../../"+Slicer_CLIMODULES_BIN_DIR+"/commandserver";
120 | this->MatlabCommandServerDirectory=vtksys::SystemTools::CollapseFullPath(dir.c_str());
121 | return this->MatlabCommandServerDirectory.c_str();
122 | }
123 |
124 | //---------------------------------------------------------------------------
125 | const char* vtkSlicerMatlabModuleGeneratorLogic
126 | ::GetMatlabCommanderPath()
127 | {
128 | // Find out where the MatlabCommander CLI is
129 | // Retrieve the bin directory from the known path of the share directory
130 | std::string climodulesDir=this->GetModuleShareDirectory()+"/../../../../"+Slicer_CLIMODULES_BIN_DIR;
131 | climodulesDir=vtksys::SystemTools::CollapseFullPath(climodulesDir.c_str());
132 | this->MatlabCommanderPath=climodulesDir+"/"+MATLAB_COMMANDER_EXECUTABLE_NAME;
133 | #if defined( _WIN32 ) && !defined(__CYGWIN__)
134 | if (!vtksys::SystemTools::FileExists(this->MatlabCommanderPath.c_str(),true))
135 | {
136 | // The executable does not exist at the expected location, so probably it is a Windows build tree
137 | // where executables are in the Debug or Release subdirectory
138 | #ifdef _DEBUG
139 | this->MatlabCommanderPath=climodulesDir+"/Debug/"+MATLAB_COMMANDER_EXECUTABLE_NAME;
140 | #else
141 | this->MatlabCommanderPath=climodulesDir+"/Release/"+MATLAB_COMMANDER_EXECUTABLE_NAME;
142 | #endif
143 | }
144 | #endif
145 | return this->MatlabCommanderPath.c_str();
146 | }
147 |
148 | //---------------------------------------------------------------------------
149 | const char* vtkSlicerMatlabModuleGeneratorLogic
150 | ::GenerateModule(const char* inputModuleName, vtkStdString& interfaceDefinitionFilename, vtkStdString& matlabFunctionFilename)
151 | {
152 | this->GenerateModuleResult.clear();
153 | interfaceDefinitionFilename.clear();
154 | matlabFunctionFilename.clear();
155 |
156 | std::string fullModuleName=inputModuleName; // module name, including spaces
157 | std::string moduleNameNoSpaces=inputModuleName; // module name without spaces
158 | moduleNameNoSpaces.erase(std::remove(moduleNameNoSpaces.begin(), moduleNameNoSpaces.end(), ' '), moduleNameNoSpaces.end());
159 |
160 | vtkStdString result;
161 | bool success=true;
162 |
163 | std::string targetDir=GetMatlabModuleDirectory();
164 |
165 | if (! vtksys::SystemTools::MakeDirectory(targetDir.c_str()))
166 | {
167 | this->GenerateModuleResult+="ERROR: Unable to create Matlab module directory '"+targetDir+"'\n";
168 | success=false;
169 | }
170 |
171 | // Matlab .m file
172 |
173 | matlabFunctionFilename = targetDir+"/"+moduleNameNoSpaces+MODULE_SCRIPT_TEMPLATE_EXTENSION;
174 | if (!CreateFileFromTemplate(this->GetModuleShareDirectory()+"/"+TEMPLATE_NAME+MODULE_SCRIPT_TEMPLATE_EXTENSION,
175 | matlabFunctionFilename, TEMPLATE_NAME, moduleNameNoSpaces, result))
176 | {
177 | success=false;
178 | matlabFunctionFilename.clear();
179 | }
180 | this->GenerateModuleResult+=result+"\n";
181 |
182 | // Module description .xml file
183 | interfaceDefinitionFilename = targetDir+"/"+moduleNameNoSpaces+MODULE_DEFINITION_TEMPLATE_EXTENSION;
184 | if (!CreateFileFromTemplate(this->GetModuleShareDirectory()+"/"+TEMPLATE_NAME+MODULE_DEFINITION_TEMPLATE_EXTENSION,
185 | interfaceDefinitionFilename, TEMPLATE_NAME, fullModuleName, result))
186 | {
187 | success=false;
188 | interfaceDefinitionFilename.clear();
189 | }
190 | this->GenerateModuleResult+=result+"\n";
191 |
192 | // Proxy .bat or .sh file
193 | std::string proxyTargetFilePath=targetDir+"/"+moduleNameNoSpaces+MODULE_PROXY_TEMPLATE_EXTENSION;
194 | if (!CreateFileFromTemplate(this->GetModuleShareDirectory()+"/"+TEMPLATE_NAME+MODULE_PROXY_TEMPLATE_EXTENSION,
195 | proxyTargetFilePath, TEMPLATE_NAME, moduleNameNoSpaces, result))
196 | {
197 | success=false;
198 | }
199 | else
200 | {
201 | #if defined( _WIN32 ) && !defined(__CYGWIN__)
202 | // no need to change file attributes to make the proxy executable
203 | #else
204 | mode_t mode=S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH;
205 | vtksys::SystemTools::GetPermissions(proxyTargetFilePath.c_str(), mode);
206 | mode |= S_IXUSR|S_IXGRP|S_IXOTH; // set executable permission for user, group, and others
207 | if (!vtksys::SystemTools::SetPermissions(proxyTargetFilePath.c_str(),mode))
208 | {
209 | result+=" Failed to set the file permission to allow execution - Slicer may not discover this module until the file permission is set allow execution.";
210 | }
211 | #endif
212 | }
213 | this->GenerateModuleResult+=result+"\n";
214 |
215 | if (success)
216 | {
217 | this->GenerateModuleResult+="\nModule generation was successful.\nEdit the module descriptor .xml and the .m file then restart Slicer.";
218 | }
219 | else
220 | {
221 | this->GenerateModuleResult+="\nModule generation failed";
222 | }
223 | return this->GenerateModuleResult.c_str();
224 | }
225 |
226 | //---------------------------------------------------------------------------
227 | bool vtkSlicerMatlabModuleGeneratorLogic
228 | ::CreateFileFromTemplate(const vtkStdString& templateFilename, const vtkStdString& targetFilename, const vtkStdString& originalString, const vtkStdString& modifiedString, vtkStdString &result)
229 | {
230 | result.clear();
231 |
232 | if (vtksys::SystemTools::FileExists(targetFilename.c_str(),true))
233 | {
234 | // Prevent accidental overwriting of existing valuable file with auto-generated file
235 | result="Cannot create file, it already exists:\n "+targetFilename;
236 | return false;
237 | }
238 |
239 | // Open input file
240 | fstream templateFile;
241 | templateFile.open(templateFilename.c_str(), fstream::in);
242 | if (!templateFile.is_open())
243 | {
244 | result="Template file not found:\n "+templateFilename;
245 | return false;
246 | }
247 |
248 | // Open output file
249 | std::ofstream targetFile;
250 | targetFile.open(targetFilename.c_str() );
251 | if (!targetFile.is_open())
252 | {
253 | result="Target file cannot be opened for writing:\n "+targetFilename;
254 | templateFile.close();
255 | return false;
256 | }
257 |
258 | // Copy line-by-line while replacing the original string with the modified string
259 | for (std::string line; std::getline(templateFile, line); )
260 | {
261 | if (line.length()>0 && originalString.length())
262 | {
263 | // search and replace
264 | size_t idx = 0;
265 | for (;;)
266 | {
267 | idx = line.find( originalString, idx);
268 | if (idx == std::string::npos) break;
269 | line.replace( idx, originalString.length(), modifiedString);
270 | idx += modifiedString.length();
271 | }
272 | }
273 | targetFile << line << std::endl;
274 | }
275 |
276 | // Close input and output files
277 | templateFile.close();
278 | targetFile.close();
279 |
280 | result="File created:\n "+targetFilename;
281 | return true;
282 | }
283 |
284 | //---------------------------------------------------------------------------
285 | void vtkSlicerMatlabModuleGeneratorLogic
286 | ::SetMatlabExecutablePath(const char* matlabExePath)
287 | {
288 | this->MatlabExecutablePath = (matlabExePath==NULL)?"":matlabExePath;
289 |
290 | std::string matlabEnvVar=std::string("SLICER_MATLAB_EXECUTABLE_PATH=")+this->MatlabExecutablePath;
291 | vtksys::SystemTools::PutEnv(matlabEnvVar.c_str());
292 | }
293 |
294 |
295 | //---------------------------------------------------------------------------
296 | const char* vtkSlicerMatlabModuleGeneratorLogic
297 | ::GetMatlabExecutablePath()
298 | {
299 | return this->MatlabExecutablePath.c_str();
300 | }
301 |
--------------------------------------------------------------------------------
/MatlabModuleGenerator/Logic/vtkSlicerMatlabModuleGeneratorLogic.h:
--------------------------------------------------------------------------------
1 | /*==============================================================================
2 |
3 | Program: 3D Slicer
4 |
5 | Portions (c) Copyright Brigham and Women's Hospital (BWH) All Rights Reserved.
6 |
7 | See COPYRIGHT.txt
8 | or http://www.slicer.org/copyright/copyright.txt for details.
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 |
16 | ==============================================================================*/
17 |
18 | // .NAME vtkSlicerMatlabModuleGeneratorLogic - slicer logic class for volumes manipulation
19 | // .SECTION Description
20 | // This class manages the logic associated with reading, saving,
21 | // and changing propertied of the volumes
22 |
23 |
24 | #ifndef __vtkSlicerMatlabModuleGeneratorLogic_h
25 | #define __vtkSlicerMatlabModuleGeneratorLogic_h
26 |
27 | // Slicer includes
28 | #include "vtkSlicerModuleLogic.h"
29 |
30 | // MRML includes
31 |
32 | // STD includes
33 | #include
34 |
35 | #include "vtkSlicerMatlabModuleGeneratorModuleLogicExport.h"
36 |
37 |
38 | /// \ingroup Slicer_QtModules_ExtensionTemplate
39 | class VTK_SLICER_MATLABMODULEGENERATOR_MODULE_LOGIC_EXPORT vtkSlicerMatlabModuleGeneratorLogic :
40 | public vtkSlicerModuleLogic
41 | {
42 | public:
43 |
44 | static vtkSlicerMatlabModuleGeneratorLogic *New();
45 | vtkTypeMacro(vtkSlicerMatlabModuleGeneratorLogic, vtkSlicerModuleLogic);
46 | void PrintSelf(ostream& os, vtkIndent indent);
47 |
48 | /// Get the directory where the generated Matlab script (and corresponding proxy shell script and XML description) files are stored
49 | /// Typically: Extensions-NNN/MatlabModules
50 | const char* GetMatlabModuleDirectory();
51 |
52 | /// Get the directory where the cli_commandserver.m and other cli_*.m helper files are stored
53 | /// Typically: Extensions-NNN/MatlabBridge/lib/Slicer-4.2/cli-modules/commandserver
54 | const char* GetMatlabCommandServerDirectory();
55 |
56 | /// Get the path to the MatlabCommander CLI executable
57 | /// Typically: Extensions-NNN/MatlabBridge/lib/Slicer-4.2/cli-modules/MatlabCommander.exe)
58 | const char* GetMatlabCommanderPath();
59 |
60 | /// Get path to Matlab.exe
61 | const char* GetMatlabExecutablePath();
62 |
63 | /// Set path to Matlab.exe
64 | void SetMatlabExecutablePath(const char* matlabExePath);
65 |
66 | /// Generates and installs a Matlab module and returns the status
67 | const char* GenerateModule(const char* moduleName, vtkStdString& interfaceDefinitionFilename, vtkStdString& matlabFunctionFilename);
68 |
69 | protected:
70 | vtkSlicerMatlabModuleGeneratorLogic();
71 | virtual ~vtkSlicerMatlabModuleGeneratorLogic();
72 |
73 | virtual void SetMRMLSceneInternal(vtkMRMLScene* newScene);
74 | /// Register MRML Node classes to Scene. Gets called automatically when the MRMLScene is attached to this logic class.
75 | virtual void RegisterNodes();
76 | virtual void UpdateFromMRMLScene();
77 | virtual void OnMRMLSceneNodeAdded(vtkMRMLNode* node);
78 | virtual void OnMRMLSceneNodeRemoved(vtkMRMLNode* node);
79 |
80 | /// return true if successful
81 | bool CreateFileFromTemplate(const vtkStdString& templateFilename, const vtkStdString& targetFilename, const vtkStdString& originalString, const vtkStdString& modifiedString, vtkStdString &result);
82 |
83 | private:
84 |
85 | std::string MatlabModuleDirectory;
86 | std::string MatlabCommandServerDirectory;
87 | std::string MatlabCommanderPath;
88 | std::string MatlabExecutablePath;
89 | std::string GenerateModuleResult;
90 |
91 | vtkSlicerMatlabModuleGeneratorLogic(const vtkSlicerMatlabModuleGeneratorLogic&); // Not implemented
92 | void operator=(const vtkSlicerMatlabModuleGeneratorLogic&); // Not implemented
93 | };
94 |
95 | #endif
96 |
--------------------------------------------------------------------------------
/MatlabModuleGenerator/Resources/Icons/MatlabModuleGenerator.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PerkLab/SlicerMatlabBridge/e9b297dbb6248be91a44013a85e21ff0fd8d13fd/MatlabModuleGenerator/Resources/Icons/MatlabModuleGenerator.png
--------------------------------------------------------------------------------
/MatlabModuleGenerator/Resources/Templates/MatlabModuleTemplate:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # If this proxy is called with the --xml parameter then just return the module decriptor XML file,
3 | # otherwise run the associated Matlab script.
4 | # MatlabBridge proxy version: 1.1
5 |
6 | MODULE_NAME="MatlabModuleTemplate"
7 |
8 | if [ $1 = "--xml" ]; then
9 | cat $MODULE_NAME.xml
10 | exit 0
11 | fi
12 |
13 | # Make this proxy file location to be the working directory (this is where the .m file is located; in Matlab the current directory will be changed to this directory)
14 | cd "$( dirname "$0" )"
15 |
16 | # Forward parameters to the Matlab CLI
17 | if [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then
18 | # Linux: use Slicer launcher
19 | "$SLICER_HOME/Slicer" --launcher-no-splash --launch "$SLICER_MATLAB_COMMANDER_PATH" --call-matlab-function $MODULE_NAME $*
20 | exit $?
21 | else
22 | # Mac OS X: there is no launcher, so run the commander directly
23 | "$SLICER_MATLAB_COMMANDER_PATH" --call-matlab-function $MODULE_NAME $*
24 | exit $?
25 | fi
26 |
--------------------------------------------------------------------------------
/MatlabModuleGenerator/Resources/Templates/MatlabModuleTemplate.bat:
--------------------------------------------------------------------------------
1 | @set MODULE_NAME=MatlabModuleTemplate
2 | @rem MatlabBridge proxy version: 1.0
3 |
4 | @echo off
5 | if not "%~1"=="--xml" goto :launch_module
6 |
7 | :print_xml
8 | rem Print CLI descriptor XML
9 | type %MODULE_NAME%.xml
10 | rem Return with success
11 | exit /b 0
12 |
13 | :launch_module
14 | rem Print error messages if any of the required environment variables are not set
15 | if not defined SLICER_MATLAB_COMMANDER_PATH echo ERROR: SLICER_MATLAB_COMMANDER_PATH environment variable is not defined. Make sure you installed the MatlabBridge extension.
16 | if not defined SLICER_MATLAB_COMMAND_SERVER_SCRIPT_PATH echo ERROR: SLICER_MATLAB_COMMAND_SERVER_SCRIPT_PATH environment variable is not defined. Make sure you installed the MatlabBridge extension.
17 | if not defined SLICER_MATLAB_EXECUTABLE_PATH echo ERROR: SLICER_MATLAB_EXECUTABLE_PATH environment variable is not defined. Make sure you installed the MatlabBridge extension and set the path to the Matlab executable.
18 | rem Make the .bat file location to be the working directory (this is where the .m file is located; in Matlab the current directory will be changed to this directory)
19 | pushd "%~dp0"
20 | rem Forward parameters to the Matlab CLI
21 | "%SLICER_HOME%/Slicer.exe" --launcher-no-splash --launch "%SLICER_MATLAB_COMMANDER_PATH%" --call-matlab-function %MODULE_NAME% %*
22 | if errorlevel 1 exit /b 1
23 | rem Return with success
24 | exit /b 0
25 |
--------------------------------------------------------------------------------
/MatlabModuleGenerator/Resources/Templates/MatlabModuleTemplate.m:
--------------------------------------------------------------------------------
1 | function outputParams=MatlabModuleTemplate(inputParams)
2 | % Example function that returns the minimum and maximum voxel value in a volume
3 | % and performs thresholding operation on the volume.
4 | %
5 | % Parameters:
6 | % inputParams.threshold: threshold value
7 | % inputParams.inputvolume: input image filename
8 | % inputParams.outputvolume: output image filename, result of the processing
9 | % outputParams.min: image minimum value
10 | % outputParams.max: image maximum value
11 | %
12 |
13 | img=cli_imageread(inputParams.inputvolume);
14 |
15 | outputParams.min=min(min(min(img.pixelData)));
16 | outputParams.max=max(max(max(img.pixelData)));
17 |
18 | img.pixelData=(double(img.pixelData)>inputParams.threshold)*100;
19 |
20 | cli_imagewrite(inputParams.outputvolume, img);
21 |
22 | %% Help for reading/writing parameters
23 | %
24 | % Reading input parameters
25 | %
26 | % integer, integer-vector, float, float-vector, double, double-vector, string, string-enumeration, file:
27 | % value=inputParams.name;
28 | % string-vector:
29 | % value=cli_stringvectordecode(inputParams.name);
30 | % point-vector:
31 | % value=cli_pointvectordecode(inputParams.name);
32 | % boolean:
33 | % value=isfield(inputParams,'name');
34 | % image:
35 | % value=cli_imageread(inputParams.name);
36 | % transform:
37 | % value=cli_lineartransformread(inputParams.name);
38 | % or (for generic transforms):
39 | % value=cli_transformread(inputParams.name);
40 | % pointfile:
41 | % points=cli_pointfileread(inputParams.name);
42 | % [pointDim pointCount]=size(points.position);
43 | % Difference between pointfile and point is that pointfile can transfer point properties, such as visibility and
44 | % selected state and works faster and more reliably if there are many points.
45 | % point:
46 | % values_LPS=cli_pointvectordecode(inputParams.name);
47 | % [pointDim pointCount]=size(values_LPS);
48 | % region:
49 | % values=cli_pointvectordecode(inputParams.name);
50 | % [regionDim regionCount]=size(values_LPS);
51 | % center_LPS=[values(1:3,regionIndex); 1];
52 | % radius_LPS=abs([values(4:6,regionIndex); 1]);
53 | % measurement:
54 | % value=cli_measurementread(inputParams.name);
55 | % geometry:
56 | % value=cli_geometryread(inputParams.name);
57 | % Important: in the CLI definition file the following attribute shall be added to the geometry element: fileExtensions=".ply"
58 | % See https://github.com/PerkLab/SlicerMatlabBridge/tree/master/Examples/MeshScale for a complete example.
59 | %
60 | % Notes:
61 | % - Input and file (image, transform, measurement, geometry) parameter names are defined by the element in the XML file
62 | % - Output parameter names are defined by the element in the XML file
63 | % - For retrieving index-th unnamed parameter use inputParams.unnamed{index+1} instead of inputParams.name
64 | %
65 | %
66 | % Writing output parameters
67 | %
68 | % integer, integer-vector, float, float-vector, double, double-vector, string, string-enumeration, file:
69 | % outputParams.name=value;
70 | % image:
71 | % cli_imagewrite(inputParams.name, value);
72 | % transform:
73 | % cli_lineartransformwrite(inputParams.name, value);
74 | % or (for generic transforms):
75 | % cli_transformwrite(inputParams.name, value);
76 | % measurement:
77 | % cli_measurementwrite(inputParams.name, value);
78 | % pointfile:
79 | % cli_pointfilewrite(inputParams.name, points);
80 | % geometry:
81 | % cli_geometrywrite(inputParams.name, value);
82 | % Important: in the CLI definition file the following attribute shall be added to the geometry element: fileExtensions=".stl"
83 | % See https://github.com/PerkLab/SlicerMatlabBridge/tree/master/Examples/MeshScale for a complete example.
84 | %
85 |
--------------------------------------------------------------------------------
/MatlabModuleGenerator/Resources/Templates/MatlabModuleTemplate.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Matlab
4 | MatlabModuleTemplate
5 |
6 | 0.0.0.1
7 | http://www.slicer.org/slicerWiki/index.php/Documentation/Nightly/Extensions/MatlabBridge
8 |
9 | Andras Lasso (PerkLab)
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | threshold
18 | 50
19 |
20 | -2000
21 | 5000
22 | 5
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | inputvolume
33 | input
34 |
35 |
36 |
37 |
38 | outputvolume
39 | output
40 |
41 |
42 |
43 |
44 | Matlab command output
45 |
46 |
47 |
48 | min
49 | output
50 |
51 |
52 |
53 |
54 |
55 | max
56 | output
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/MatlabModuleGenerator/Resources/UI/qSlicerMatlabModuleGeneratorModuleWidget.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | qSlicerMatlabModuleGeneratorModuleWidget
4 |
5 |
6 |
7 | 0
8 | 0
9 | 525
10 | 503
11 |
12 |
13 |
14 | Form
15 |
16 |
17 | -
18 |
19 |
20 | Matlab configuration
21 |
22 |
23 |
-
24 |
25 |
26 | Matlab executable
27 |
28 |
29 |
30 | -
31 |
32 |
33 | -
34 |
35 |
36 | Exit Matlab on Application Exit
37 |
38 |
39 |
40 | -
41 |
42 |
43 | Matlab script directory
44 |
45 |
46 | lineEdit_MatlabScriptDirectory
47 |
48 |
49 |
50 | -
51 |
52 |
53 | true
54 |
55 |
56 |
57 | true
58 |
59 |
60 |
61 | false
62 |
63 |
64 | true
65 |
66 |
67 |
68 |
69 |
70 |
71 | -
72 |
73 |
74 | Matlab module generation
75 |
76 |
77 | QFrame::NoFrame
78 |
79 |
80 |
-
81 |
82 |
83 | Module name
84 |
85 |
86 | lineEdit_GeneratorModuleName
87 |
88 |
89 |
90 | -
91 |
92 |
93 | -
94 |
95 |
96 | Generate module
97 |
98 |
99 |
100 | -
101 |
102 |
103 | -
104 |
105 |
106 | 0
107 |
108 |
-
109 |
110 |
111 | false
112 |
113 |
114 | Edit interface definition
115 |
116 |
117 |
118 | -
119 |
120 |
121 | false
122 |
123 |
124 | Edit Matlab function
125 |
126 |
127 |
128 | -
129 |
130 |
131 | Restart application
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 | -
141 |
142 |
143 | Qt::Vertical
144 |
145 |
146 |
147 | 0
148 | 0
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 | qSlicerWidget
158 | QWidget
159 |
160 | 1
161 |
162 |
163 | ctkCollapsibleButton
164 | QWidget
165 |
166 | 1
167 |
168 |
169 | ctkPathLineEdit
170 | QWidget
171 |
172 |
173 |
174 |
175 |
176 |
177 |
--------------------------------------------------------------------------------
/MatlabModuleGenerator/Resources/qSlicerMatlabModuleGeneratorModule.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | Icons/MatlabModuleGenerator.png
4 |
5 |
6 |
--------------------------------------------------------------------------------
/MatlabModuleGenerator/Testing/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_subdirectory(Cxx)
2 |
--------------------------------------------------------------------------------
/MatlabModuleGenerator/Testing/Cxx/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | set(KIT qSlicer${MODULE_NAME}Module)
2 |
3 | #-----------------------------------------------------------------------------
4 | set(KIT_TEST_SRCS
5 | #qSlicer${MODULE_NAME}ModuleTest.cxx
6 | )
7 |
8 | #-----------------------------------------------------------------------------
9 | slicerMacroConfigureModuleCxxTestDriver(
10 | NAME ${KIT}
11 | SOURCES ${KIT_TEST_SRCS}
12 | WITH_VTK_DEBUG_LEAKS_CHECK
13 | )
14 |
15 | #-----------------------------------------------------------------------------
16 | #simple_test(qSlicer${MODULE_NAME}ModuleTest)
17 |
--------------------------------------------------------------------------------
/MatlabModuleGenerator/qSlicerMatlabModuleGeneratorModule.cxx:
--------------------------------------------------------------------------------
1 | /*==============================================================================
2 |
3 | Program: 3D Slicer
4 |
5 | Portions (c) Copyright Brigham and Women's Hospital (BWH) All Rights Reserved.
6 |
7 | See COPYRIGHT.txt
8 | or http://www.slicer.org/copyright/copyright.txt for details.
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 |
16 | ==============================================================================*/
17 |
18 | // Qt includes
19 | #include
20 | #include
21 | #include
22 |
23 | // VTK includes
24 | #include "vtksys/SystemTools.hxx"
25 |
26 | // SlicerQt includes
27 | #include
28 |
29 | // MatlabModuleGenerator Logic includes
30 | #include
31 |
32 | // MatlabModuleGenerator includes
33 | #include "qSlicerMatlabModuleGeneratorModule.h"
34 | #include "qSlicerMatlabModuleGeneratorModuleWidget.h"
35 |
36 | const std::string MATLAB_COMMAND_SERVER_SCRIPT_NAME="cli_commandserver.m";
37 |
38 | #if defined( _WIN32 ) && !defined(__CYGWIN__)
39 | // Windows
40 | static const std::string DEFAULT_MATLAB_PROCESS_PATH="matlab.exe";
41 | #elif defined(__APPLE__)
42 | // Mac OS X
43 | static const std::string DEFAULT_MATLAB_PROCESS_PATH="/Applications/MATLAB_XXXXX.app/bin/matlab";
44 | #else
45 | // Linux
46 | static const std::string DEFAULT_MATLAB_PROCESS_PATH="/usr/local/bin/matlab";
47 | #endif
48 |
49 | //-----------------------------------------------------------------------------
50 |
51 | #if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
52 | #include
53 | Q_EXPORT_PLUGIN2(qSlicerMatlabModuleGeneratorModule, qSlicerMatlabModuleGeneratorModule);
54 | #endif
55 |
56 | //-----------------------------------------------------------------------------
57 | /// \ingroup Slicer_QtModules_ExtensionTemplate
58 | class qSlicerMatlabModuleGeneratorModulePrivate
59 | {
60 | public:
61 | qSlicerMatlabModuleGeneratorModulePrivate();
62 | };
63 |
64 | //-----------------------------------------------------------------------------
65 | // qSlicerMatlabModuleGeneratorModulePrivate methods
66 |
67 | //-----------------------------------------------------------------------------
68 | qSlicerMatlabModuleGeneratorModulePrivate
69 | ::qSlicerMatlabModuleGeneratorModulePrivate()
70 | {
71 | }
72 |
73 | //-----------------------------------------------------------------------------
74 | // qSlicerMatlabModuleGeneratorModule methods
75 |
76 | //-----------------------------------------------------------------------------
77 | qSlicerMatlabModuleGeneratorModule
78 | ::qSlicerMatlabModuleGeneratorModule(QObject* _parent)
79 | : Superclass(_parent)
80 | , d_ptr(new qSlicerMatlabModuleGeneratorModulePrivate)
81 | {
82 | }
83 |
84 | //-----------------------------------------------------------------------------
85 | qSlicerMatlabModuleGeneratorModule::~qSlicerMatlabModuleGeneratorModule()
86 | {
87 | }
88 |
89 | //-----------------------------------------------------------------------------
90 | QString qSlicerMatlabModuleGeneratorModule::helpText()const
91 | {
92 | return "The MatlabModuleGenerator module is used for generating a skeleton Matlab module that the user can further customize to implement the intended functionality. The module also allows the user to specify the location of the Matlab executable.";
93 | }
94 |
95 | //-----------------------------------------------------------------------------
96 | QString qSlicerMatlabModuleGeneratorModule::acknowledgementText()const
97 | {
98 | return "This work is part of the SparKit project, funded by An Applied Cancer Research Unit of Cancer Care Ontario with funds provided by the Ministry of Health and Long-Term Care and the Ontario Consortium for Adaptive Interventions in Radiation Oncology (OCAIRO) to provide free, open-source toolset for radiotherapy and related image-guided interventions.";
99 | }
100 |
101 | //-----------------------------------------------------------------------------
102 | QStringList qSlicerMatlabModuleGeneratorModule::contributors()const
103 | {
104 | QStringList moduleContributors;
105 | moduleContributors << QString("Andras Lasso (PerkLab, Queen's University)");
106 | moduleContributors << QString("Jean-Christophe Fillion-Robin (Kitware)");
107 | moduleContributors << QString("Kevin Wang (Radiation Medicine Program, Princess Margaret Hospital, University Health Network Toronto)");
108 | return moduleContributors;
109 | }
110 |
111 | //-----------------------------------------------------------------------------
112 | QIcon qSlicerMatlabModuleGeneratorModule::icon()const
113 | {
114 | return QIcon(":/Icons/MatlabModuleGenerator.png");
115 | }
116 |
117 | //-----------------------------------------------------------------------------
118 | QStringList qSlicerMatlabModuleGeneratorModule::categories() const
119 | {
120 | return QStringList() << "Developer Tools.Matlab";
121 | }
122 |
123 | //-----------------------------------------------------------------------------
124 | QStringList qSlicerMatlabModuleGeneratorModule::dependencies() const
125 | {
126 | return QStringList();
127 | }
128 |
129 | QString qSlicerMatlabModuleGeneratorModule::getMatlabExecutablePath() const
130 | {
131 | // 1. Slicer.ini application settings
132 | // If the Matlab path is defined in the Slicer settings then use that
133 | QSettings settings;
134 | QString matlabExecutablePath = settings.value("Matlab/MatlabExecutablePath","").toString();
135 | if (!matlabExecutablePath.isEmpty())
136 | {
137 | QFileInfo checkFile(matlabExecutablePath);
138 | if (checkFile.exists() && checkFile.isFile())
139 | {
140 | qDebug("Matlab executable found in Slicer settings: %s", qPrintable(matlabExecutablePath));
141 | return matlabExecutablePath;
142 | }
143 | qDebug("Matlab executable is defined in Slicer settings (%s), but the file is not found.", qPrintable(matlabExecutablePath));
144 | }
145 |
146 | // 2. SLICER_MATLAB_EXECUTABLE_PATH environment variable
147 | // If the Matlab path is defined in an environment variable then use that
148 | const char* matlabExePathEnvValue=getenv("SLICER_MATLAB_EXECUTABLE_PATH");
149 | if (matlabExePathEnvValue && strlen(matlabExePathEnvValue)>0)
150 | {
151 | qDebug("Matlab executable found in environment at %s", qPrintable(matlabExePathEnvValue));
152 | return QString(matlabExePathEnvValue);
153 | }
154 |
155 | // 3. App Paths
156 | #if defined( _WIN32 ) && !defined(__CYGWIN__)
157 | QSettings matlabExePathRegistryKey("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\matlab.exe",QSettings::NativeFormat);
158 | QString matlabExePathWin=matlabExePathRegistryKey.value(".", NULL).toString(); // "." reads the (Default) value
159 | if (!matlabExePathWin.isEmpty())
160 | {
161 | qDebug("Matlab executable found on system at %s", qPrintable(matlabExePathWin));
162 | return matlabExePathWin;
163 | }
164 | #elif defined(__APPLE__)
165 | QString appPath("/Applications");
166 | QDir appDir(appPath);
167 | QStringList nameFilter("MATLAB*.app");
168 | QStringList matlabAppPaths = appDir.entryList(nameFilter);
169 | if(!matlabAppPaths.isEmpty())
170 | {
171 | QString matlabAppPath = matlabAppPaths.at(0); //take the first one found
172 | QString matlabExePathMac = appPath + "/" + matlabAppPath + "/bin/matlab";
173 | QFileInfo matlabExeFileMac(matlabExePathMac);
174 | if (matlabExeFileMac.exists() && matlabExeFileMac.isFile())
175 | {
176 | qDebug() << "Matlab executable found on system at : " << matlabExePathMac;
177 | return matlabExePathMac;
178 | }
179 | }
180 | #else
181 | std::vector hints;
182 | std::string matlabExePathUnix = vtksys::SystemTools::FindProgram("matlab", hints, false); // false: search system path
183 | if (!matlabExePathUnix.empty())
184 | {
185 | qDebug("Matlab executable found on system at %s", qPrintable(matlabExePathUnix.c_str()));
186 | return QString(matlabExePathUnix.c_str());
187 | }
188 | #endif
189 |
190 | // 4. Hardcoded default string
191 | qDebug("MatlabExecutablePath not found, default path used: %s", qPrintable(DEFAULT_MATLAB_PROCESS_PATH.c_str()));
192 | return QString(DEFAULT_MATLAB_PROCESS_PATH.c_str());
193 | }
194 |
195 | //-----------------------------------------------------------------------------
196 | void qSlicerMatlabModuleGeneratorModule::setup()
197 | {
198 | this->Superclass::setup();
199 |
200 | qSlicerApplication * app = qSlicerApplication::application();
201 | if (!app)
202 | {
203 | qCritical() << "Fail to initalize qSlicerMatlabModuleGeneratorModule module: application is invalid";
204 | return;
205 | }
206 | vtkSlicerMatlabModuleGeneratorLogic* moduleGeneratorLogic= vtkSlicerMatlabModuleGeneratorLogic::SafeDownCast(this->logic());
207 | if (moduleGeneratorLogic == 0)
208 | {
209 | qCritical() << "Fail to initalize qSlicerMatlabModuleGeneratorModule module: logic is invalid";
210 | return;
211 | }
212 |
213 | //Uncomment this to allow some time to attach the debugger
214 | //vtksys::SystemTools::Delay(10000);
215 |
216 | // Get Matlab executable path and store in the logic
217 | QString matlabExecutablePath = getMatlabExecutablePath();
218 | moduleGeneratorLogic->SetMatlabExecutablePath(matlabExecutablePath.toLatin1());
219 |
220 | // Append Matlab module path to the additional paths
221 | QStringList additionalPaths = app->revisionUserSettings()->value("Modules/AdditionalPaths").toStringList();
222 | QString pathToAppend=moduleGeneratorLogic->GetMatlabModuleDirectory();
223 | QDir dirToCheck(pathToAppend);
224 | bool isPathToAppendAlreadyInAdditionalPaths=false;
225 | foreach(const QString& path, additionalPaths)
226 | {
227 | if (dirToCheck == QDir(path))
228 | {
229 | isPathToAppendAlreadyInAdditionalPaths=true;
230 | break;
231 | }
232 | }
233 | if (!isPathToAppendAlreadyInAdditionalPaths)
234 | {
235 | additionalPaths << pathToAppend;
236 | app->revisionUserSettings()->setValue("Modules/AdditionalPaths",additionalPaths);
237 | }
238 |
239 | // Set Matlab executable and commandserver script paths in environment variables
240 | // for MatlabCommander CLI module
241 | // Ideally, the app->setEnvironmentVariable method should be used, but somehow app->setEnvironmentVariable
242 | // causes failure in the sample data volume (and probably in other modules, too, as Python cannot find the "os" symbol)
243 | std::string matlabEnvVar=std::string("SLICER_MATLAB_EXECUTABLE_PATH=")+std::string(matlabExecutablePath.toLatin1());
244 | vtksys::SystemTools::PutEnv(matlabEnvVar.c_str());
245 | std::string scriptEnvVar=std::string("SLICER_MATLAB_COMMAND_SERVER_SCRIPT_PATH=")+moduleGeneratorLogic->GetMatlabCommandServerDirectory()+"/"+MATLAB_COMMAND_SERVER_SCRIPT_NAME;
246 | vtksys::SystemTools::PutEnv(scriptEnvVar.c_str());
247 | std::string commanderEnvVar=std::string("SLICER_MATLAB_COMMANDER_PATH=")+moduleGeneratorLogic->GetMatlabCommanderPath();
248 | vtksys::SystemTools::PutEnv(commanderEnvVar.c_str());
249 | }
250 |
251 | //-----------------------------------------------------------------------------
252 | qSlicerAbstractModuleRepresentation * qSlicerMatlabModuleGeneratorModule
253 | ::createWidgetRepresentation()
254 | {
255 | return new qSlicerMatlabModuleGeneratorModuleWidget;
256 | }
257 |
258 | //-----------------------------------------------------------------------------
259 | vtkMRMLAbstractLogic* qSlicerMatlabModuleGeneratorModule::createLogic()
260 | {
261 | return vtkSlicerMatlabModuleGeneratorLogic::New();
262 | }
263 |
--------------------------------------------------------------------------------
/MatlabModuleGenerator/qSlicerMatlabModuleGeneratorModule.h:
--------------------------------------------------------------------------------
1 | /*==============================================================================
2 |
3 | Program: 3D Slicer
4 |
5 | Portions (c) Copyright Brigham and Women's Hospital (BWH) All Rights Reserved.
6 |
7 | See COPYRIGHT.txt
8 | or http://www.slicer.org/copyright/copyright.txt for details.
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 |
16 | ==============================================================================*/
17 |
18 | #ifndef __qSlicerMatlabModuleGeneratorModule_h
19 | #define __qSlicerMatlabModuleGeneratorModule_h
20 |
21 | // SlicerQt includes
22 | #include "qSlicerLoadableModule.h"
23 |
24 | #include "qSlicerMatlabModuleGeneratorModuleExport.h"
25 |
26 | class qSlicerMatlabModuleGeneratorModulePrivate;
27 |
28 | /// \ingroup Slicer_QtModules_ExtensionTemplate
29 | class Q_SLICER_QTMODULES_MATLABMODULEGENERATOR_EXPORT
30 | qSlicerMatlabModuleGeneratorModule
31 | : public qSlicerLoadableModule
32 | {
33 | Q_OBJECT
34 | #ifdef Slicer_HAVE_QT5
35 | Q_PLUGIN_METADATA(IID "org.slicer.modules.loadable.qSlicerLoadableModule/1.0");
36 | #endif
37 | Q_INTERFACES(qSlicerLoadableModule);
38 |
39 | public:
40 |
41 | typedef qSlicerLoadableModule Superclass;
42 | explicit qSlicerMatlabModuleGeneratorModule(QObject *parent=0);
43 | virtual ~qSlicerMatlabModuleGeneratorModule();
44 |
45 | qSlicerGetTitleMacro(QTMODULE_TITLE);
46 |
47 | virtual QString helpText()const;
48 | virtual QString acknowledgementText()const;
49 | virtual QStringList contributors()const;
50 |
51 | virtual QIcon icon()const;
52 |
53 | virtual QStringList categories()const;
54 | virtual QStringList dependencies() const;
55 |
56 | protected:
57 |
58 | /// Get location of the Matlab executable.
59 | /// Search order:
60 | /// \li Slicer.ini application settings
61 | /// \li SLICER_MATLAB_EXECUTABLE_PATH environment variable
62 | /// \li Path or App Paths
63 | /// \li Hardcoded default location
64 | QString getMatlabExecutablePath() const;
65 |
66 | /// Initialize the module. Register the volumes reader/writer
67 | virtual void setup();
68 |
69 | /// Create and return the widget representation associated to this module
70 | virtual qSlicerAbstractModuleRepresentation * createWidgetRepresentation();
71 |
72 | /// Create and return the logic associated to this module
73 | virtual vtkMRMLAbstractLogic* createLogic();
74 |
75 | protected:
76 | QScopedPointer d_ptr;
77 |
78 | private:
79 | Q_DECLARE_PRIVATE(qSlicerMatlabModuleGeneratorModule);
80 | Q_DISABLE_COPY(qSlicerMatlabModuleGeneratorModule);
81 |
82 | };
83 |
84 | #endif
85 |
--------------------------------------------------------------------------------
/MatlabModuleGenerator/qSlicerMatlabModuleGeneratorModuleWidget.cxx:
--------------------------------------------------------------------------------
1 | /*==============================================================================
2 |
3 | Program: 3D Slicer
4 |
5 | Portions (c) Copyright Brigham and Women's Hospital (BWH) All Rights Reserved.
6 |
7 | See COPYRIGHT.txt
8 | or http://www.slicer.org/copyright/copyright.txt for details.
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 |
16 | ==============================================================================*/
17 |
18 | // Qt includes
19 | #include
20 | #include
21 | #include
22 | #include
23 |
24 | // VTK includes
25 | #include
26 |
27 | // SlicerQt includes
28 | #include "qSlicerMatlabModuleGeneratorModuleWidget.h"
29 | #include "ui_qSlicerMatlabModuleGeneratorModuleWidget.h"
30 | #include "qSlicerApplication.h"
31 | #include "qSlicerModuleManager.h"
32 | #include "qSlicerAbstractCoreModule.h"
33 | #include
34 |
35 | // Module includes
36 | #include "vtkSlicerMatlabModuleGeneratorLogic.h"
37 |
38 |
39 | //-----------------------------------------------------------------------------
40 | /// \ingroup Slicer_QtModules_ExtensionTemplate
41 | class qSlicerMatlabModuleGeneratorModuleWidgetPrivate: public Ui_qSlicerMatlabModuleGeneratorModuleWidget
42 | {
43 | Q_DECLARE_PUBLIC(qSlicerMatlabModuleGeneratorModuleWidget);
44 | protected:
45 | qSlicerMatlabModuleGeneratorModuleWidget* const q_ptr;
46 | vtkStdString lastInterfaceDefinitionFilename;
47 | vtkStdString lastMatlabFunctionFilename;
48 | public:
49 | qSlicerMatlabModuleGeneratorModuleWidgetPrivate(qSlicerMatlabModuleGeneratorModuleWidget& object);
50 | vtkSlicerMatlabModuleGeneratorLogic* logic() const;
51 | };
52 |
53 | //-----------------------------------------------------------------------------
54 | // qSlicerMatlabModuleGeneratorModuleWidgetPrivate methods
55 |
56 | //-----------------------------------------------------------------------------
57 | qSlicerMatlabModuleGeneratorModuleWidgetPrivate::qSlicerMatlabModuleGeneratorModuleWidgetPrivate(qSlicerMatlabModuleGeneratorModuleWidget& object)
58 | : q_ptr(&object)
59 | {
60 | }
61 |
62 | //-----------------------------------------------------------------------------
63 | vtkSlicerMatlabModuleGeneratorLogic*
64 | qSlicerMatlabModuleGeneratorModuleWidgetPrivate::logic() const
65 | {
66 | Q_Q(const qSlicerMatlabModuleGeneratorModuleWidget);
67 | return vtkSlicerMatlabModuleGeneratorLogic::SafeDownCast(q->logic());
68 | }
69 |
70 | //-----------------------------------------------------------------------------
71 | // qSlicerMatlabModuleGeneratorModuleWidget methods
72 |
73 | //-----------------------------------------------------------------------------
74 | qSlicerMatlabModuleGeneratorModuleWidget::qSlicerMatlabModuleGeneratorModuleWidget(QWidget* _parent)
75 | : Superclass( _parent )
76 | , d_ptr( new qSlicerMatlabModuleGeneratorModuleWidgetPrivate(*this) )
77 | {
78 | }
79 |
80 | //-----------------------------------------------------------------------------
81 | qSlicerMatlabModuleGeneratorModuleWidget::~qSlicerMatlabModuleGeneratorModuleWidget()
82 | {
83 | }
84 |
85 | //-----------------------------------------------------------------------------
86 | void qSlicerMatlabModuleGeneratorModuleWidget::setup()
87 | {
88 | Q_D(qSlicerMatlabModuleGeneratorModuleWidget);
89 | d->setupUi(this);
90 | this->Superclass::setup();
91 |
92 | // Determine the value of Matlab/ExitMatlab in QSettings
93 | // and set checkbox_ExitMatlab accordingly
94 | QSettings settings;
95 | if (settings.contains("Matlab/ExitMatlabOnApplicationExit"))
96 | {
97 | bool exitMatlab = settings.value("Matlab/ExitMatlabOnApplicationExit").toBool();
98 | d->checkBox_ExitMatlab->setChecked(exitMatlab);
99 | }
100 | else
101 | {
102 | d->checkBox_ExitMatlab->setChecked(true);
103 | settings.setValue("Matlab/ExitMatlabOnApplicationExit",true);
104 | }
105 |
106 | connect( QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(applicationAboutToQuit()) );
107 |
108 | connect( d->lineEdit_MatlabExecutablePath, SIGNAL(currentPathChanged(QString)), this, SLOT(matlabExecutablePathChanged(QString)) );
109 | connect( d->checkBox_ExitMatlab, SIGNAL(stateChanged(int)), this, SLOT(exitMatlabChanged(int)) );
110 |
111 | connect( d->pushButton_GenerateModule, SIGNAL(clicked()), this, SLOT(generateModuleClicked()) );
112 |
113 | connect( d->pushButton_EditInterfaceDefinition, SIGNAL(clicked()), this, SLOT(editInterfaceDefinitionClicked()) );
114 | connect( d->pushButton_EditMatlabFunction, SIGNAL(clicked()), this, SLOT(editMatlabFunctionClicked()) );
115 | connect( d->pushButton_RestartApplication, SIGNAL(clicked()), this, SLOT(restartApplicationClicked()) );
116 |
117 | d->lineEdit_MatlabExecutablePath->setCurrentPath(d->logic()->GetMatlabExecutablePath());
118 | d->lineEdit_MatlabScriptDirectory->setText(d->logic()->GetMatlabModuleDirectory());
119 | }
120 |
121 | //-----------------------------------------------------------------------------
122 | void qSlicerMatlabModuleGeneratorModuleWidget::applicationAboutToQuit()
123 | {
124 | bool exitMatlab = true;
125 | QSettings settings;
126 | if (settings.contains("Matlab/ExitMatlabOnApplicationExit"))
127 | {
128 | exitMatlab = settings.value("Matlab/ExitMatlabOnApplicationExit").toBool();
129 | }
130 | if (exitMatlab)
131 | {
132 | qDebug("Shutting down Matlab");
133 | qSlicerModuleManager* moduleManager = qSlicerApplication::application()->moduleManager();
134 | qSlicerAbstractCoreModule* matlabCommanderModule = moduleManager->module("MatlabCommander");
135 | if (matlabCommanderModule)
136 | {
137 | vtkSlicerCLIModuleLogic* matlabCommanderLogic = vtkSlicerCLIModuleLogic::SafeDownCast(matlabCommanderModule->logic());
138 | vtkMRMLCommandLineModuleNode* cmdNode = matlabCommanderLogic->CreateNodeInScene();
139 | cmdNode->SetParameterAsBool("exitmatlab", true);
140 | matlabCommanderLogic->ApplyAndWait(cmdNode);
141 | }
142 | else
143 | {
144 | qWarning("MatlabCommander module is not found");
145 | }
146 | }
147 | }
148 |
149 | //-----------------------------------------------------------------------------
150 | void qSlicerMatlabModuleGeneratorModuleWidget::matlabExecutablePathChanged(QString path)
151 | {
152 | Q_D(qSlicerMatlabModuleGeneratorModuleWidget);
153 |
154 | QSettings settings;
155 | settings.setValue("Matlab/MatlabExecutablePath",path);
156 |
157 | d->logic()->SetMatlabExecutablePath(path.toLatin1());
158 | }
159 |
160 | //-----------------------------------------------------------------------------
161 | void qSlicerMatlabModuleGeneratorModuleWidget::exitMatlabChanged(int state)
162 | {
163 | Q_D(qSlicerMatlabModuleGeneratorModuleWidget);
164 | QSettings settings;
165 | settings.setValue("Matlab/ExitMatlabOnApplicationExit",state==Qt::Checked);
166 | }
167 |
168 | //-----------------------------------------------------------------------------
169 | void qSlicerMatlabModuleGeneratorModuleWidget::generateModuleClicked()
170 | {
171 | Q_D(qSlicerMatlabModuleGeneratorModuleWidget);
172 | QString moduleName=d->lineEdit_GeneratorModuleName->text();
173 | vtkStdString result=d->logic()->GenerateModule(moduleName.toLatin1(), d->lastInterfaceDefinitionFilename, d->lastMatlabFunctionFilename);
174 | d->textEdit_GeneratorResults->setText(QString(result));
175 |
176 | d->pushButton_EditInterfaceDefinition->setEnabled(!d->lastInterfaceDefinitionFilename.empty());
177 | d->pushButton_EditMatlabFunction->setEnabled(!d->lastMatlabFunctionFilename.empty());
178 | }
179 |
180 | //-----------------------------------------------------------------------------
181 | void qSlicerMatlabModuleGeneratorModuleWidget::editInterfaceDefinitionClicked()
182 | {
183 | Q_D(qSlicerMatlabModuleGeneratorModuleWidget);
184 | QString filename = QString::fromLatin1("file:///")+QString::fromLatin1(d->lastInterfaceDefinitionFilename);
185 | QDesktopServices::openUrl(QUrl(filename, QUrl::TolerantMode));
186 | }
187 |
188 | //-----------------------------------------------------------------------------
189 | void qSlicerMatlabModuleGeneratorModuleWidget::editMatlabFunctionClicked()
190 | {
191 | Q_D(qSlicerMatlabModuleGeneratorModuleWidget);
192 | QString filename = QString::fromLatin1("file:///")+QString::fromLatin1(d->lastMatlabFunctionFilename);
193 | QDesktopServices::openUrl(QUrl(filename, QUrl::TolerantMode));
194 | }
195 |
196 | //-----------------------------------------------------------------------------
197 | void qSlicerMatlabModuleGeneratorModuleWidget::restartApplicationClicked()
198 | {
199 | Q_D(qSlicerMatlabModuleGeneratorModuleWidget);
200 | qSlicerApplication::application()->confirmRestart();
201 | }
202 |
--------------------------------------------------------------------------------
/MatlabModuleGenerator/qSlicerMatlabModuleGeneratorModuleWidget.h:
--------------------------------------------------------------------------------
1 | /*==============================================================================
2 |
3 | Program: 3D Slicer
4 |
5 | Portions (c) Copyright Brigham and Women's Hospital (BWH) All Rights Reserved.
6 |
7 | See COPYRIGHT.txt
8 | or http://www.slicer.org/copyright/copyright.txt for details.
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 |
16 | ==============================================================================*/
17 |
18 | #ifndef __qSlicerMatlabModuleGeneratorModuleWidget_h
19 | #define __qSlicerMatlabModuleGeneratorModuleWidget_h
20 |
21 | // SlicerQt includes
22 | #include "qSlicerAbstractModuleWidget.h"
23 |
24 | #include "qSlicerMatlabModuleGeneratorModuleExport.h"
25 |
26 | class qSlicerMatlabModuleGeneratorModuleWidgetPrivate;
27 | class vtkMRMLNode;
28 |
29 | /// \ingroup Slicer_QtModules_ExtensionTemplate
30 | class Q_SLICER_QTMODULES_MATLABMODULEGENERATOR_EXPORT qSlicerMatlabModuleGeneratorModuleWidget :
31 | public qSlicerAbstractModuleWidget
32 | {
33 | Q_OBJECT
34 |
35 | public:
36 |
37 | typedef qSlicerAbstractModuleWidget Superclass;
38 | qSlicerMatlabModuleGeneratorModuleWidget(QWidget *parent=0);
39 | virtual ~qSlicerMatlabModuleGeneratorModuleWidget();
40 |
41 | public slots:
42 |
43 | protected slots:
44 |
45 | void applicationAboutToQuit();
46 |
47 | void matlabExecutablePathChanged(QString path);
48 | void exitMatlabChanged(int state);
49 | void generateModuleClicked();
50 |
51 | void editInterfaceDefinitionClicked();
52 | void editMatlabFunctionClicked();
53 | void restartApplicationClicked();
54 |
55 | protected:
56 | QScopedPointer d_ptr;
57 |
58 | virtual void setup();
59 |
60 | private:
61 | Q_DECLARE_PRIVATE(qSlicerMatlabModuleGeneratorModuleWidget);
62 | Q_DISABLE_COPY(qSlicerMatlabModuleGeneratorModuleWidget);
63 | };
64 |
65 | #endif
66 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # SlicerMatlabBridge
3 | MatlabBridge extension for 3D Slicer
4 |
5 | More information: https://www.slicer.org/wiki/Documentation/Nightly/Extensions/MatlabBridge
6 |
--------------------------------------------------------------------------------