-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathicosphere.m
159 lines (159 loc) · 4.78 KB
/
icosphere.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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
function [vv,ff] = icosphere(varargin)
%ICOSPHERE Generate icosphere.
% Create a unit geodesic sphere created by subdividing a regular
% icosahedron with normalised vertices.
%
% [V,F] = ICOSPHERE(N) generates to matrices containing vertex and face
% data so that patch('Faces',F,'Vertices',V) produces a unit icosphere
% with N subdivisions.
%
% FV = ICOSPHERE(N) generates an FV structure for using with patch.
%
% ICOSPHERE(N) and just ICOSPHERE display the icosphere as a patch on the
% current axes and does not return anything.
%
% ICOSPHERE uses N = 3.
%
% ICOSPHERE(AX,...) plots into AX instead of GCA.
%
% See also SPHERE.
%
% Based on C# code by Andres Kahler
% http://blog.andreaskahler.com/2009/06/creating-icosphere-mesh-in-code.html
%
% Wil O.C. Ward 19/03/2015
% University of Nottingham, UK
% Parse possible axes input
if nargin > 2
error('Too many input variables, must be 0, 1 or 2.');
end
[cax,args,nargs] = axescheck(varargin{:});
n = 3; % default number of sub-divisions
if nargs > 0, n = args{1}; end % override based on input
% generate regular unit icosahedron (20 faced polyhedron)
[v,f] = icosahedron(); % size(v) = [12,3]; size(f) = [20,3];
% recursively subdivide triangle faces
for gen = 1:n
f_ = zeros(size(f,1)*4,3);
for i = 1:size(f,1) % for each triangle
tri = f(i,:);
% calculate mid points (add new points to v)
[a,v] = getMidPoint(tri(1),tri(2),v);
[b,v] = getMidPoint(tri(2),tri(3),v);
[c,v] = getMidPoint(tri(3),tri(1),v);
% generate new subdivision triangles
nfc = [tri(1),a,c;
tri(2),b,a;
tri(3),c,b;
a,b,c];
% replace triangle with subdivision
idx = 4*(i-1)+1:4*i;
f_(idx,:) = nfc;
end
f = f_; % update
end
% remove duplicate vertices
[v,b,ix] = unique(v,'rows'); clear b % b dummy / compatibility
% reassign faces to trimmed vertex list and remove any duplicate faces
f = unique(ix(f),'rows');
switch(nargout)
case 0 % no output
cax = newplot(cax); % draw to given axis (or gca)
showSphere(cax,f,v);
case 1 % return fv structure for patch
vv = struct('Vertices',v,'Faces',f,...
'VertexNormals',v,'FaceVertexCData',v(:,3));
case 2 % return vertices and faces
vv = v; ff = f;
otherwise
error('Too many output variables, must be 0, 1 or 2.');
end
end
function [i,v] = getMidPoint(t1,t2,v)
%GETMIDPOINT calculates point between two vertices
% Calculate new vertex in sub-division and normalise to unit length
% then find or add it to v and return index
%
% Wil O.C. Ward 19/03/2015
% University of Nottingham, UK
% get vertice positions
p1 = v(t1,:); p2 = v(t2,:);
% calculate mid point (on unit sphere)
pm = (p1 + p2) ./ 2;
pm = pm./norm(pm);
% add to vertices list, return index
i = size(v,1) + 1;
v = [v;pm];
end
function [v,f] = icosahedron()
%ICOSAHEDRON creates unit regular icosahedron
% Returns 12 vertex and 20 face values.
%
% Wil O.C. Ward 19/03/2015
% University of Nottingham, UK
t = (1+sqrt(5)) / 2;
% create vertices
v = [-1, t, 0; % v1
1, t, 0; % v2
-1,-t, 0; % v3
1,-t, 0; % v4
0,-1, t; % v5
0, 1, t; % v6
0,-1,-t; % v7
0, 1,-t; % v8
t, 0,-1; % v9
t, 0, 1; % v10
-t, 0,-1; % v11
-t, 0, 1];% v12
% normalise vertices to unit size
v = v./norm(v(1,:));
% create faces
f = [ 1,12, 6; % f1
1, 6, 2; % f2
1, 2, 8; % f3
1, 8,11; % f4
1,11,12; % f5
2, 6,10; % f6
6,12, 5; % f7
12,11, 3; % f8
11, 8, 7; % f9
8, 2, 9; % f10
4,10, 5; % f11
4, 5, 3; % f12
4, 3, 7; % f13
4, 7, 9; % f14
4, 9,10; % f15
5,10, 6; % f16
3, 5,12; % f17
7, 3,11; % f18
9, 7, 8; % f19
10, 9, 2];% f20
end
function showSphere(cax,f,v)
%SHOWSPHERE displays icosphere given faces and vertices.
% Displays a patch surface on the axes, cax, and sets the view.
%
% Properties:
% - vertex normals == vertex vectors
% - no backface lighting
% - colour data matches z value of vertex
% - material properties match default SURF
%
% Wil O.C. Ward 19/03/2015
% University of Nottingham, UK
% set some axes properties if not held
if ~ishold(cax)
az = -37.5; el = 30;
view(az,el)
grid
end
% create patch object on cax
patch('Faces',f,'Vertices',v,...
'VertexNormals',v,...
'LineWidth',0.5,'FaceLighting','phong',...
'BackFaceLighting','unlit',...
'AmbientStrength',0.3,'DiffuseStrength',0.6,...
'SpecularExponent',10,'SpecularStrength',0.9,...
'FaceColor','flat','CData',v(:,3),...
'Parent',cax,'Tag','Icosphere');
end