1
+ animateFrames();
2
+ function animateFrames()
3
+ animFilename = ' Around_the_Word.gif' ; % Output file name
4
+ firstFrame = true ;
5
+ framesPerSecond = 24 ;
6
+ delayTime = 1 / framesPerSecond ;
7
+
8
+ % Create the gif
9
+ for frame = 1 : 48
10
+ drawframe(frame );
11
+ fig = gcf();
12
+ fig.Units = ' pixels' ;
13
+ fig .Position(3 : 4 ) = [300 ,300 ];
14
+ im = getframe(fig );
15
+ [A ,map ] = rgb2ind(im .cdata ,256 );
16
+
17
+ if firstFrame
18
+ firstFrame = false ;
19
+ imwrite(A ,map ,animFilename , ' LoopCount' , Inf , ' DelayTime' , delayTime );
20
+ else
21
+ imwrite(A ,map ,animFilename , ' WriteMode' , ' append' , ' DelayTime' , delayTime );
22
+ end
23
+ end
24
+ end
25
+ function drawframe(f )
26
+ % Rotation
27
+ rx= f / 48 * pi ;
28
+
29
+ % Shorteners
30
+ q= @triangulation ;
31
+ j= @polyshape ;
32
+ K= ' KeepCollinearPoints' ;
33
+
34
+ % Transforms
35
+ persistent WX EX
36
+
37
+ if f == 1
38
+ %% WORD SHAPE
39
+ % Basic idea - draw a word using a text object in a wide
40
+ % figure, screen-cap it, then contourit.
41
+ f= figure(' Color' ,' w' ,' Vis' ,' of' ,' Pos' ,[ 100 100 3000 300 ]);
42
+ ax= axes(f ,' Vis' ,' off' );
43
+ t= text(ax ,15 ,15 ,' MATLAB' ,' Units' ,' pixel' ,...
44
+ ' FontSize' ,30 ,' FontWeight' ,' bold' ,' FontUnits' ,' Pix' ,...
45
+ ' VerticalA' ,' baseline' );
46
+ F= getframe(ax ,t .Extent );
47
+ close(f )
48
+ V= contourc(double(flipud(F .cdata(: ,: ,1 ))),[50 50 ])' ;
49
+ % Convert contour matrix into polyshape verts
50
+ idx= 1 ;
51
+ while idx < size(V ,1 )
52
+ n= V(idx ,2 );
53
+ V(idx ,: )=nan ;
54
+ idx= idx + 1 + n ;
55
+ end
56
+ % Center and scale to unit height
57
+ V= (V - min(V ))/max(V ,[],' all' );
58
+ % Convert to polyshape so we get a clean triangulation
59
+ W1= j(V(2 : end ,: ),K ,true );
60
+ W1= XP(W1 .polybuffer(.006 ));
61
+
62
+ %% Create the WordSphere
63
+
64
+ % Constants
65
+ R1= 1.3 ; % radius of inner/outer part of sphere.
66
+ R2= 1.5 ;
67
+ SP= .8 ; % Span of the word
68
+
69
+ T= q(W1 );
70
+
71
+ % Aspects of the triangulation.
72
+ V= T .Points ; % Get improved V
73
+ F= T .ConnectivityList ;
74
+ E= T .freeBoundary ;
75
+
76
+ % Constants for this shape when computing connecting edges
77
+ R= 1 : size(E ,1 ); % All the boundary edges.
78
+ L2= size(V ,1 ); % Layer 2 starts here.
79
+
80
+ % New triangulation faces
81
+ NF= [F ; F + L2 ; % top and bottom
82
+ E(R ,[2 1 2 ])+[0 0 L2 ]; % edges connecting top/bottom
83
+ E(R ,[1 1 2 ])+[0 L2 L2 ];
84
+ ];
85
+
86
+ x= max(V );
87
+ T= V(: ,1 )/x(1 )*SP ; % Stretch around part of theta
88
+
89
+ zV= (V(: ,2 )-x(2 )/2 );
90
+ P= zV *.2 / R1 / max(zV );
91
+
92
+ %% Cheap Earth (do this before patches due to newplot)
93
+ axes(CreateFcn = ' earthmap' );
94
+ EX= hgtransform ;
95
+ set(findobj(' type' ,' surface' ),' parent' ,EX );
96
+
97
+ %% Word Sphere (or 2 half spheres)
98
+ WX= hgtransform ;
99
+ for o= [0 1 ]
100
+ V2= [cospi(T + o ).*cospi(P ),sinpi(T + o ).*cospi(P ),sinpi(P )];
101
+
102
+ WT= q(NF ,[V2 .*[R1 R1 1 ]
103
+ V2 .*[R2 R2 1 ]]);
104
+
105
+ patch(WX ,' Vertices' ,WT .Points ,' Faces' ,WT .ConnectivityList ,...
106
+ ' FaceC' ,' #0076a8' ,' FaceA' ,1 ,' FaceL' ,' n' ,...
107
+ ' FaceVertexCData' ,[T ;T ],...
108
+ ' EdgeC' ,' n' );
109
+
110
+ patch(WX ,' Vertices' ,WT .Points ,' Faces' ,WT .featureEdges(pi / 4.5 ),...
111
+ ' FaceVertexCData' ,[],' FaceC' ,' none' ,' EdgeC' ,' #fff00f' ,' LineW' ,1 );
112
+ end
113
+ clim(clim );
114
+
115
+ % Prettify
116
+ set(gcf ,' Color' ,' k' );
117
+ daspect([1 1 1 ]);
118
+ view([220 5 ])
119
+ axis([-1.5 1.5 - 1.5 1.5 - 1.1 1.1 ],' off' )
120
+ camzoom(1.7 )
121
+ end
122
+
123
+ WX.Matrix= makehgtform(' zrotate' ,-rx + pi / 3 );
124
+ EX.Matrix= makehgtform(' zrotate' ,rx * 2 );
125
+
126
+ %% HELPER FCNS
127
+ % The below fcns add verticies into a polyshape so that the resolution along
128
+ % long edges is high enough so we can bend those edges around the sphere.
129
+ function ps = XP(psIn )
130
+ % Make all long straight edges in the polyshape be made of many short
131
+ % segments.
132
+
133
+ % Get the regions
134
+ r= regions(psIn );
135
+ % New polyshape should keep all the extra pts we'll be adding.
136
+ ps= j();
137
+ % Loop over all the regions
138
+
139
+ for i= 1 : numel(r )
140
+ [x ,y ]=boundary(r(i ),1 ); % Exclude all the holes in this region
141
+ ps= union(ps ,XE(x ,y ),K ,true );
142
+ end
143
+
144
+ % Get the holes in those regions
145
+ h= holes(psIn );
146
+
147
+ % Loop over all the holes
148
+ for i= 1 : numel(h )
149
+ [x ,y ]=boundary(h(i ),1 );
150
+ ps= subtract(ps ,XE(x ,y ),K ,true );
151
+ end
152
+ end
153
+
154
+ function ps = XE(x ,y )
155
+ % Expand the edges for one polyregion
156
+ if x(end )==x(1 ) && y(end )==y(1 )
157
+ inp= [x y ];
158
+ else
159
+ inp= [x(end ) y(end )% This is a loop, re-add the end
160
+ x y ];
161
+ end
162
+
163
+ P= [];
164
+ for i= 2 : size(inp ,1 )
165
+ d= norm(inp(i - 1 ,: )-inp(i ,: ));% distance between adjacent pts
166
+ n= max(2 ,floor(150 * d ));% n pts to increase it to
167
+ if n == 2
168
+ P= [P % #ok
169
+ inp(i - 1 ,: )];
170
+ else
171
+ % disp expand
172
+ xe= linspace(inp(i - 1 ,1 ),inp(i ,1 ),n )' ; % interp
173
+ ye= linspace(inp(i - 1 ,2 ),inp(i ,2 ),n )' ;
174
+ % Add all but last pt to avoid dups
175
+ P= [P ;% #ok
176
+ xe(1 : end - 1 ) ye(1 : end - 1 )];
177
+ end
178
+ end
179
+
180
+ ps= j(P ,K ,true );
181
+ end
182
+
183
+ end
184
+
185
+
186
+
187
+
188
+
0 commit comments