[76e9f4]: / tool_funcs / applyTorsionToVTPBoneGeom.m

Download this file

300 lines (242 with data), 10.0 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
%-------------------------------------------------------------------------%
% Copyright (c) 2021 Modenese L. %
% Author: Luca Modenese, 2021 %
% email: l.modenese@imperial.ac.uk %
% ----------------------------------------------------------------------- %
% function to deform the vtp bone geometries according to the specified
% torsional profile.
function osimModel = applyTorsionToVTPBoneGeom(osimModel, bone_to_deform, torsionAxis, torsion_angle_func_rad, torsion_doc_string, OSGeometry_folder)
% assign by default OpenSim 3.1 folder
if nargin<6
[~, osim_version_string] = getOpenSimVersion();
OSGeometry_folder = ['C:\OpenSim ',osim_version_string,'\Geometry'];
end
disp('--------------------------');
disp(' ADJUSTING VTP GEOMETRIES ');
disp('--------------------------');
% get VTP files for bone of interest
disp(['Geometry folder: ', OSGeometry_folder])
disp(['VTP files attached to ', bone_to_deform,':']);
vtpNameSet = getBodyVTPFileNames(osimModel, bone_to_deform);
% converting the axis in the index used later
[RotMat, axis_ind] = getAxisRotMat(torsionAxis);
for n_vtp = 1:size(vtpNameSet,2)
% current geometry
curr_vtp = vtpNameSet{n_vtp};
% print vtp file
disp(['* ', curr_vtp]);
% vtp files with path
vtp_file = fullfile(OSGeometry_folder,curr_vtp);
% reads the original vtp file
disp(' - reading VTP file');
[ normals, points] = readVTPfile_v2(vtp_file);
% 2021 version
% [P, C, N] = readVTPfile(vtp_file, 0);
% boneTriObj = triangulation(C, P(:,1), P(:,2), P(:,3));
% OBJfile = fullfile(OSGeometry_folder, [curr_vtp(1:end-4), deformed_vtp_suffix,'.obj']);
% writeOBJfile(boneTriObj, OBJfile);
% Deforms points and normals
disp(' - applying torsion to points and normals');
% initialize (required for multiple vtp vones)
% thanks to Axel Koussou!
new_points=[];
new_normals=[];
for n = 1:size(points,1)
% compute torsion matrix
TorsRotMat = RotMat(torsion_angle_func_rad(points(n,axis_ind)));
% New points and axis
new_points(n,:) = (TorsRotMat*points(n,:)')';
new_normals(n,:) = (TorsRotMat*normals(n,:)')';
end
% writes the deformed geometry
deformed_vtp_suffix = ['_Torsion',upper(torsionAxis),torsion_doc_string];
disp(' - writing deformed VTP file');
writeDeformedVTPGeometry(vtp_file, new_normals, new_points, deformed_vtp_suffix)
end
% assign to model
osimModel = assignDeformedVTPFileNamesToBody(osimModel, bone_to_deform, deformed_vtp_suffix);
end
function vtpNameSet = getBodyVTPFileNames(aOsimModel, aBodyName)
import org.opensim.modeling.*
% check if body is included in the model
if aOsimModel.getBodySet().getIndex(aBodyName)<0
error('The specified segment is not included in the OpenSim model')
end
% OpenSim 3.3
if getOpenSimVersion()<4.0
% gets GeometrySet, where the display properties are located
bodyGeometrySet = aOsimModel.getBodySet().get(aBodyName).getDisplayer().getGeometrySet();
% Gets the element of the geometrySet
N_vtp = bodyGeometrySet.getSize();
% Loops and saved the names of the VTP geometry files
for n_vtp = 0:N_vtp-1
cur_geom = bodyGeometrySet.get(n_vtp);
vtpNameSet(n_vtp+1) = {char(cur_geom.getGeometryFile())}; %#ok<AGROW>
end
else
body = aOsimModel.getBodySet().get(aBodyName);
% get number of meshes
N_vtp = body.getPropertyByName('attached_geometry').size();
for n_vtp = 0:N_vtp-1 % here no -1
cur_geom = body.get_attached_geometry(n_vtp);
% transform to Mesh
currentMesh = Mesh.safeDownCast(cur_geom);
% extract file
vtpNameSet(n_vtp+1) = {char(currentMesh.get_mesh_file())}; %#ok<AGROW>
end
end
end
% function to read normals and points contained in a vtp file.
% points and normal define the geometry of the bone (assuming that topology
% doesn't change).
function [normals, points] = readVTPfile_v2(vtp_file)
% open vtp file
fid = fopen(vtp_file);
% check on the file: is it open?
if fid == -1; error('VTPfile not loaded'); end
% initialization
n_norm = 1;
n_p=1;
while ~feof(fid) % goes though the entire file
% gets a line
tline = fgetl(fid);
% checks if there are three floating nr in a row (can be a normal or a
% point)
if ~isempty(sscanf(tline,'%f %f %f\n'))
% it gets the vector as double
data = sscanf(tline,'%f %f %f\n');
% it si a normal if norm is close to one.
% the code assumes that normals are listed before points.
if (abs(norm(data)-1)<0.000001) && n_p==1
% stores the normal
normals(n_norm,:) = data;
n_norm = n_norm+1;
% otherwise is a point
elseif n_p<n_norm
% stores the point
points(n_p,:) = data;
n_p = n_p+1;
else
% if not point or normal than exit for loop, This avoids to go
% through topology.
break
end
end
end
% close files
fclose all;
end
% this function updates the normals and points of a vtp file with some new
% normals and points given as input
% writes the deformed file in the same folder where the original vtp is
% locates
function writeDeformedVTPGeometry(vtp_file,new_normals,new_points,deformed_vtp_suffix)
% Opens original VTP file
fid = fopen(vtp_file);
[path, name, ~] = fileparts(vtp_file);
% Opens a VTP files to write the deformed geometry
deformed_vtp_file = fullfile(path, [name,deformed_vtp_suffix,'.vtp']);
fidDef = fopen(deformed_vtp_file,'w+');
% Throws exception if there are problems with the files
if fid == -1; error('Vtp file not loaded'); end
if fidDef == -1; error('Vtp deformed file not loaded'); end
% initializations
n_norm = 1;
n_p=1;
% goes though the entire file
while ~feof(fid)
% initialization of the writing format
format = '';
% gets a line
tline = fgetl(fid);
% scans the file until it finds 3 double in a row. They can be a
% normal, a point or topology.
if ~isempty(sscanf(tline,'%f %f %f\n'))
% gets the floating numbers
data = sscanf(tline,'%f %f %f\n');
% They are normals if the norm is numerically zero and their index
% is minor/equal to the first dimension of the given matrix
if (abs(norm(data)-1)<0.000001) && n_norm<=length(new_normals)
% substitution of the original values with the deformed one
tline = new_normals(n_norm,:);
% appropriate format for the normals
format = '\t\t\t%-6.6f %-6.6f %-6.6f\r\n';
n_norm = n_norm+1;
end
% if the vector has norm>1 and given points are not finished then
% treat the vector as a point
if (n_p<=length(new_points))&& (abs(norm(data)-1)>=0.000001)
% update the point coordinates
tline = new_points(n_p,:);
% same format as before
format = '\t\t\t%-6.6f %-6.6f %-6.6f\r\n';
n_p = n_p+1;
end
% if not point or normal the vector value just goes through and
% format is not updated
end
if strcmp(format,'')
% format used to copy the line of the original file as it is.
format = '%s\r\n';
end
% just write the line (updated or not)
fprintf(fidDef,format,tline);
end
% close files
fclose all;
% informs the user of the new geometry
disp([' - saved as ''', deformed_vtp_file, ''' in geometry folder.']);
end
%-------------------------------------------------------------------------%
% Copyright (c) 2021 Modenese L. %
% Author: Luca Modenese, 2020 %
% email: l.modenese@imperial.ac.uk %
% ----------------------------------------------------------------------- %
function [aOsimModel,newVTPNames] = assignDeformedVTPFileNamesToBody(aOsimModel, aBodyName, suffix)
import org.opensim.modeling.*
% check if body is included in the model
if aOsimModel.getBodySet().getIndex(aBodyName)<0
error('The specified segment is not included in the OpenSim model')
end
% OpenSim 3.3
if getOpenSimVersion()<4.0
% gets GeometrySet, where the display properties are located
bodyGeometrySet = aOsimModel.getBodySet().get(aBodyName).getDisplayer().getGeometrySet();
% Gets the element of the geometrySet
N_vtp = bodyGeometrySet.getSize();
% Loops and updates the names of the VTP geometry files
for n_vtp = 0:N_vtp-1
cur_geom = bodyGeometrySet.get(n_vtp);
% original name
origName = char(cur_geom.getGeometryFile());
% update the vtp file name
updVTPName = [origName(1:end-4),suffix,'.vtp'];
% sets new file name for Geometry
cur_geom.setGeometryFile(updVTPName);
% stores name
newVTPNames(n_vtp+1) = {updVTPName};
% clear
clear origName newName
end
else
body = aOsimModel.getBodySet().get(aBodyName);
% get number of meshes
N_vtp = body.getPropertyByName('attached_geometry').size();
% Loops and updates the names of the VTP geometry files
for n_vtp = 0:N_vtp-1
cur_geom = body.get_attached_geometry(n_vtp);
% transform to Mesh
currentMesh = Mesh.safeDownCast(cur_geom);
% original name
origName = char(currentMesh.get_mesh_file());
% update the vtp file name
updVTPName = [origName(1:end-4),suffix,'.vtp'];
% sets new file name for Geometry
currentMesh.set_mesh_file(updVTPName);
% stores name
newVTPNames(n_vtp+1) = {updVTPName};
% clear
clear origName newName
end
end
end