-
Notifications
You must be signed in to change notification settings - Fork 0
/
sbfread.m
144 lines (118 loc) · 4.51 KB
/
sbfread.m
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
function [header, data] = sbfread(file)
% SBFREAD Read point cloud in simple binary file format used by CloudCompare.
% ------------------------------------------------------------------------------
% DESCRIPTION/NOTES
% * Format definition: https://www.cloudcompare.org/doc/wiki/index.php?title=SBF
% ------------------------------------------------------------------------------
% INPUT
% 1 [file]
% Path to sbf file.
% ------------------------------------------------------------------------------
% OUTPUT
% 1 [header]
% Structure containing the header metadata from the '.sbf' ascii file.
%
% 2 [data]
% Structure containing the point cloud data from the '.sbf.data' binary file.
% ------------------------------------------------------------------------------
% EXAMPLES
% 1 Read sbf file.
% [header, data] = sbfread('Lion.sbf');
% ------------------------------------------------------------------------------
% ------------------------------------------------------------------------------
arguments
file {mustBeFile}
end
header = readAsciiFile(file);
data = readBinaryFile([file '.data']);
compareDuplicateEntries(header, data);
end
function header = readAsciiFile(file)
% READASCIIFILE Read header metadata from '.sbf' ascii file.
header = struct;
% Open file
fid = fopen(file, 'rt');
if fid == -1
error('Can not read ''%s''!', file);
end
header.file = file;
% Check first line
tline = fgetl(fid);
if ~strcmpi(tline, '[SBF]')
error('''%s'' does not contain ''[SBF]'' on the first line!', file);
end
% Read rest of file into structure
tline = fgetl(fid);
noLine = 2;
while ischar(tline)
tline = strtrim(tline); % remove any leading/trailing spaces
if ~isempty(tline) % skip empty lines
idxEqual = strfind(tline, '=');
if ~isempty(idxEqual)
field = tline(1:idxEqual(1)-1);
if strcmp(field, 'GlobalShift')
globalShiftCell = textscan(tline(idxEqual(1)+1:end), '%f', 'Delimiter', ',');
header.(field) = globalShiftCell{1}';
elseif matches(field, "SF" + digitsPattern) % e.g. SF1
entries = textscan(tline(idxEqual(1)+1:end), '%s', 'Delimiter', ',');
header.(field).name = entries{1}{1};
if numel(entries{1}) > 1 % if the options 'p=' or 's=' are defined
for idxEntry = 2:numel(entries{1})
[attribute, value] = strtok(entries{1}{idxEntry}, '=');
value = value(2:end); % remove '='
if attribute == 's'
header.(field).(attribute) = str2double(value);
else
header.(field).(attribute) = value;
end
end
end
else
header.(field) = str2double(tline(idxEqual(1)+1:end));
end
else
warning('Can not interpret line %d in ''%s''', noLine, file);
end
end
tline = fgetl(fid);
noLine = noLine+1;
end
fclose(fid);
end
function data = readBinaryFile(file)
% READBINARYFILE Read point cloud data from '.sbf.data' binary file.
data = struct;
% Open file
fid = fopen(file, 'r', 'b');
if fid == -1
error('Can not read ''%s''!', file);
end
data.file = file;
% Read header
fseek(fid, 2, 'bof');
data.Points = fread(fid, 1, 'uint64');
data.SFCount = fread(fid, 1, 'integer*2');
data.GlobalShift = fread(fid, [1,3], 'double');
% Read point cloud data
fseek(fid, 64, 'bof');
data.XA = fread(fid, [3+data.SFCount data.Points], 'single');
fclose(fid);
end
function compareDuplicateEntries(header, data)
% COMPAREDUPLICATEENTRIES Compare duplicate entries in header and data structure.
entriesToCompare = ["Points" "SFCount" "GlobalShift"];
for entry = entriesToCompare
if ~isfield(header, entry)
warning('File ''%s'' does not contain the entry ''%s''.', header.file, entry);
continue;
end
if ~isfield(data, entry)
warning('File ''%s'' does not contain the entry ''%s''.', data.file, entry);
continue;
end
if header.(entry) ~= data.(entry)
warning('Values for ''%s'' in header file and data file are not the same.', entry);
end
end
end