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
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="x-ua-compatible" content="IE=Edge"/>
<title>Self Collision — NvCloth 1.1.5 documentation</title>
<link rel="stylesheet" href="../_static/default.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="../_static/breathe.css" type="text/css" />
<link rel="stylesheet" href="../_static/application.css" type="text/css" />
<link rel="stylesheet" href="../_static/styleguide.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '../',
VERSION: '1.1.5',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="../_static/jquery.js"></script>
<script type="text/javascript" src="../_static/underscore.js"></script>
<script type="text/javascript" src="../_static/doctools.js"></script>
<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<script type="text/javascript" src="../_static/bootstrap.js"></script>
<script type="text/javascript" src="../_static/jquery.cookie.js"></script>
<script type="text/javascript" src="../_static/jquery.storageapi.js"></script>
<link rel="top" title="NvCloth 1.1.5 documentation" href="../index.html" />
<link rel="up" title="Internal collision detection documentation" href="Index.html" />
<link rel="next" title="Inter Collision" href="InterCollision.html" />
<link rel="prev" title="Sphere Capsule collision detection" href="SphereCapsuleCollision.html" />
</head>
<body>
<nav class="navbar navbar-inverse navbar-default">
<div class="row">
<div class="navbar-brand">
<img class="logo" src="../_static/developerzone_gameworks_logo.png" alt="Logo"/>
</div>
<div id="searchbox" style="display: none; float:right; padding-top:4px; padding-right:4px">
<form class="search form-inline" action="../search.html" method="get">
<div class="form-group">
<input type="text" name="q" class="form-control" />
<input type="submit" value="Search" class="btn btn-primary" />
</div>
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
</div>
</nav>
<div class="masthead">
<div class="row">
<ul class="breadcrumb">
<li><a href="../index.html">NvCloth 1.1.5 documentation</a></li>
<li><a href="Index.html" accesskey="U">Internal collision detection documentation</a></li>
</ul>
</div>
</div>
<div class="row">
<div class="col-md-3 bs-sidenav" style="white-space: nowrap; overflow: auto;">
<div class="bs-sidebar">
<div id="sidebar_toc">
<h4>Table Of Contents</h4>
<ul class="current">
<li class="toctree-l1"><a class="reference internal" href="../ReleaseNotes/index.html">Release Notes</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../ReleaseNotes/index.html#id1">1.1.5</a></li>
<li class="toctree-l2"><a class="reference internal" href="../ReleaseNotes/index.html#id2">1.1.4</a></li>
<li class="toctree-l2"><a class="reference internal" href="../ReleaseNotes/index.html#id3">1.1.3</a></li>
<li class="toctree-l2"><a class="reference internal" href="../ReleaseNotes/index.html#id4">1.1.2</a></li>
<li class="toctree-l2"><a class="reference internal" href="../ReleaseNotes/index.html#id5">1.1.1</a></li>
<li class="toctree-l2"><a class="reference internal" href="../ReleaseNotes/index.html#id6">1.1.0</a></li>
<li class="toctree-l2"><a class="reference internal" href="../ReleaseNotes/index.html#id7">1.0.0</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../Compiling/index.html">Compiling</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../Compiling/index.html#windows">Windows</a></li>
<li class="toctree-l2"><a class="reference internal" href="../Compiling/index.html#linux">Linux</a></li>
<li class="toctree-l2"><a class="reference internal" href="../Compiling/index.html#mac">Mac</a></li>
<li class="toctree-l2"><a class="reference internal" href="../Compiling/index.html#ios">iOS</a></li>
<li class="toctree-l2"><a class="reference internal" href="../Compiling/index.html#android">Android</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../Modules/Index.html">Modules</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../Modules/Index.html#nvcloth">NvCloth</a></li>
<li class="toctree-l2"><a class="reference internal" href="../Modules/Index.html#nvcloth-extensions">NvCloth extensions</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../UserGuide/Index.html">User Guide</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../UserGuide/Index.html#setup">Setup</a><ul>
<li class="toctree-l3"><a class="reference internal" href="../UserGuide/Index.html#initializing-the-library">Initializing the Library</a></li>
<li class="toctree-l3"><a class="reference internal" href="../UserGuide/Index.html#factory">Factory</a></li>
<li class="toctree-l3"><a class="reference internal" href="../UserGuide/Index.html#fabric-cloth">Fabric & Cloth</a><ul>
<li class="toctree-l4"><a class="reference internal" href="../UserGuide/Index.html#fabric">Fabric</a></li>
<li class="toctree-l4"><a class="reference internal" href="../UserGuide/Index.html#cloth">Cloth</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="../UserGuide/Index.html#solver">Solver</a></li>
<li class="toctree-l3"><a class="reference internal" href="../UserGuide/Index.html#retrieving-simulation-data">Retrieving simulation data</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="../UserGuide/Index.html#usage">Usage</a><ul>
<li class="toctree-l3"><a class="reference internal" href="../UserGuide/Index.html#common-cloth-properties">Common cloth properties</a></li>
<li class="toctree-l3"><a class="reference internal" href="../UserGuide/Index.html#tethers">Tethers</a></li>
<li class="toctree-l3"><a class="reference internal" href="../UserGuide/Index.html#collision-detection">Collision detection</a></li>
<li class="toctree-l3"><a class="reference internal" href="../UserGuide/Index.html#local-space-simulation">Local space simulation</a></li>
<li class="toctree-l3"><a class="reference internal" href="../UserGuide/Index.html#drag-lift-and-wind">Drag lift and wind</a></li>
<li class="toctree-l3"><a class="reference internal" href="../UserGuide/Index.html#distance-motion-constraints">Distance/Motion constraints</a></li>
<li class="toctree-l3"><a class="reference internal" href="../UserGuide/Index.html#attaching-cloth-to-animated-characters">Attaching cloth to animated characters</a></li>
<li class="toctree-l3"><a class="reference internal" href="../UserGuide/Index.html#unit-scaling">Unit scaling</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="../UserGuide/Index.html#troubleshooting">Troubleshooting</a><ul>
<li class="toctree-l3"><a class="reference internal" href="../UserGuide/Index.html#parts-of-cloth-disappearing-for-single-frame">Parts of cloth disappearing (for single frame)</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../CopyRight/Index.html">NVIDIA Copyright Notice</a></li>
<li class="toctree-l1"><a class="reference internal" href="../Solver/Index.html">Internal solver function/algorithm documentation</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../Solver/Index.html#overview">Overview</a></li>
<li class="toctree-l2"><a class="reference internal" href="../Solver/Index.html#particle-invmass-w-component">Particle invMass w component</a></li>
<li class="toctree-l2"><a class="reference internal" href="../Solver/Index.html#slack">Slack</a></li>
<li class="toctree-l2"><a class="reference internal" href="../Solver/Index.html#log-stiffness">Log Stiffness</a></li>
<li class="toctree-l2"><a class="reference internal" href="../Solver/Index.html#integration">Integration</a></li>
<li class="toctree-l2"><a class="reference internal" href="../Solver/Index.html#wind-simulation">Wind simulation</a></li>
<li class="toctree-l2"><a class="reference internal" href="../Solver/Index.html#distance-constraints">Distance constraints</a></li>
<li class="toctree-l2"><a class="reference internal" href="../Solver/Index.html#tether-constraints">Tether constraints</a></li>
<li class="toctree-l2"><a class="reference internal" href="../Solver/Index.html#edge-constraints">Edge constraints</a></li>
<li class="toctree-l2"><a class="reference internal" href="../Solver/Index.html#separation-constraints">Separation constraints</a></li>
<li class="toctree-l2"><a class="reference internal" href="../Solver/Index.html#fabric-data-structure">Fabric data structure</a></li>
</ul>
</li>
<li class="toctree-l1 current"><a class="reference internal" href="Index.html">Internal collision detection documentation</a><ul class="current">
<li class="toctree-l2 current"><a class="reference internal" href="Index.html#overview-of-the-different-modules">Overview of the different modules</a><ul class="current">
<li class="toctree-l3"><a class="reference internal" href="SphereCapsuleCollision.html">Sphere Capsule collision detection</a><ul>
<li class="toctree-l4"><a class="reference internal" href="SphereCapsuleCollision.html#sphere-capsule-generation">Sphere/ Capsule generation</a></li>
<li class="toctree-l4"><a class="reference internal" href="SphereCapsuleCollision.html#sphere-acceleration-structure">Sphere acceleration structure</a></li>
<li class="toctree-l4"><a class="reference internal" href="SphereCapsuleCollision.html#collideparticles">collideParticles()</a></li>
<li class="toctree-l4"><a class="reference internal" href="SphereCapsuleCollision.html#capsule-collision-detection">Capsule collision detection</a><ul>
<li class="toctree-l5"><a class="reference internal" href="SphereCapsuleCollision.html#cone-collision-detection">Cone collision detection</a></li>
<li class="toctree-l5"><a class="reference internal" href="SphereCapsuleCollision.html#sphere-collision-detection">Sphere collision detection</a></li>
<li class="toctree-l5"><a class="reference internal" href="SphereCapsuleCollision.html#sphere-ccd">Sphere CCD</a></li>
<li class="toctree-l5"><a class="reference internal" href="SphereCapsuleCollision.html#cone-ccd">Cone CCD</a></li>
</ul>
</li>
<li class="toctree-l4"><a class="reference internal" href="SphereCapsuleCollision.html#calculatefrictionimpulse">calculateFrictionImpulse()</a></li>
</ul>
</li>
<li class="toctree-l3 current"><a class="current reference internal" href="">Self Collision</a><ul>
<li class="toctree-l4"><a class="reference internal" href="#overview">Overview</a></li>
<li class="toctree-l4"><a class="reference internal" href="#acceleration-structure">Acceleration structure</a><ul>
<li class="toctree-l5"><a class="reference internal" href="#grid-setup">Grid setup</a></li>
<li class="toctree-l5"><a class="reference internal" href="#particle-sorting">Particle sorting</a></li>
<li class="toctree-l5"><a class="reference internal" href="#key-range-sweep">Key range sweep</a></li>
<li class="toctree-l5"><a class="reference internal" href="#collision-detection-and-response">Collision detection and response</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="InterCollision.html">Inter Collision</a><ul>
<li class="toctree-l4"><a class="reference internal" href="InterCollision.html#overview">Overview</a></li>
<li class="toctree-l4"><a class="reference internal" href="InterCollision.html#broad-phase-collision-detection">Broad phase collision detection</a></li>
<li class="toctree-l4"><a class="reference internal" href="InterCollision.html#acceleration-structure">Acceleration structure</a><ul>
<li class="toctree-l5"><a class="reference internal" href="InterCollision.html#id1">Broad phase collision detection</a></li>
<li class="toctree-l5"><a class="reference internal" href="InterCollision.html#differences-with-self-collision">Differences with self collision</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="Index.html#todo">Todo</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../Cooking/Index.html">Internal cooking documentation</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../Cooking/Index.html#overview-of-the-different-modules">Overview of the different modules</a><ul>
<li class="toctree-l3"><a class="reference internal" href="../Cooking/TripletScheduler.html">TripletScheduler</a><ul>
<li class="toctree-l4"><a class="reference internal" href="../Cooking/TripletScheduler.html#adjacencyquerier">AdjacencyQuerier</a></li>
<li class="toctree-l4"><a class="reference internal" href="../Cooking/TripletScheduler.html#id1">TripletScheduler</a></li>
<li class="toctree-l4"><a class="reference internal" href="../Cooking/TripletScheduler.html#tripletscheduler-simd">TripletScheduler::simd()</a></li>
<li class="toctree-l4"><a class="reference internal" href="../Cooking/TripletScheduler.html#tripletscheduler-warp">TripletScheduler::warp()</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
<h4>Previous topic</h4>
<p class="topless"><a href="SphereCapsuleCollision.html"
title="previous chapter">Sphere Capsule collision detection</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="InterCollision.html"
title="next chapter">Inter Collision</a></p>
<div id="searchbox" style="display: none">
<h4>Quick search</h4>
<form class="search form-inline" action="../search.html" method="get">
<div class="form-group">
<input type="text" name="q" class="form-control" />
<input type="submit" value="Search" class="btn btn-primary" />
</div>
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
<p class="searchtip" style="font-size: 90%">
Enter search terms or a module, class or function name.
</p>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
</div>
</div>
<div class="document col-md-8">
<div class="body">
<div class="section" id="self-collision">
<h1>Self Collision<a class="headerlink" href="#self-collision" title="Permalink to this headline">¶</a></h1>
<div class="section" id="overview">
<h2>Overview<a class="headerlink" href="#overview" title="Permalink to this headline">¶</a></h2>
<p>Self collision tries to keep the cloth from self intersecting.
It does this by keeping the particles a minimum distance away from each other.
This distance can be set using Cloth::setSelfCollisionDistance().</p>
</div>
<div class="section" id="acceleration-structure">
<h2>Acceleration structure<a class="headerlink" href="#acceleration-structure" title="Permalink to this headline">¶</a></h2>
<p>Testing every particle against all other particle is too slow.
Instead an acceleration structure is used to only test nearby particles.</p>
<p>The acceleration structure is a combination of a regular grid and a sweep.
The longest axes of the AABB around all particles is used for the sweep.
The other two axes are divided in a regular grid of 253x253.
For each particle we test against the current and neighboring cells of the grid in which we sweep along the remaining axis.
The whole process will be described in more detail below.</p>
<div class="section" id="grid-setup">
<h3>Grid setup<a class="headerlink" href="#grid-setup" title="Permalink to this headline">¶</a></h3>
<p>The AABB is obtained from ClothData (calculated by SwCollision<T4f>::computeBounds()).
The edge lengths are calculated by subtracting the lower bounds from the upper bounds.
The sweep axis index (0 to 2 for x to z so we can use the array operators) is picked by the largest edge length.
The two hash axes are the remaining axes in arbitrary order.</p>
<img src="../_images/SelfCollisionGrid.svg" /><p>The cell size for the hash axes is picked so that it is not smaller than the collision distance set by the user, and large enough that 253 cells cover the whole edge length.
The sweep axis is divided in 65533 cells.
The first and last cells of each axis are reserved as a sentinel.
The amount of sweep cells that need to be checked to cover the collision distance is given by:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">numSweepCells</span> <span class="o">=</span> <span class="mi">2</span> <span class="o">+</span> <span class="n">gridScale</span> <span class="o">*</span> <span class="n">collisionDistance</span>
</pre></div>
</div>
<p>We calculate the grid scale and grid bias to quickly convert particle coordinates to cell coordinates using \(coordinate \cdot gridScale + gridBias\).
The gridScale is \((cellCount + 1)^{-1}\) and the gridBias is \(-lowerBound \cdot gridScale + 1 \), where \(lowerBound\) is taken from the AABB.</p>
</div>
<div class="section" id="particle-sorting">
<h3>Particle sorting<a class="headerlink" href="#particle-sorting" title="Permalink to this headline">¶</a></h3>
<p>Particles are sorted based on a key which is constructed from the cell coordinates.
The 16 least significant bits are used to store the sweep axis cell coordinate.
The two other bytes are used to store the hash axis cell coordinates (this is the reason for the specific cell count per axis in the grid).</p>
<p>A radix sort with a radix (bin) size of 256 is used, requiring 4 bins to sort the 32-bit keys.</p>
</div>
<div class="section" id="key-range-sweep">
<h3>Key range sweep<a class="headerlink" href="#key-range-sweep" title="Permalink to this headline">¶</a></h3>
<p>Individual particles can be processed now that the acceleration structure is setup.
Only 5 cells are processed for each particle, as we don’t want to detect duplicate pairs.</p>
<img src="../_images/SelfCollisionHashAxisKernel.svg" /><p>Particles can be quickly identified in the acceleration structure by looping though the sorted keys.
Cells cannot be directly accessed as they are variable in size (depending on how many particles a cell contains) and stored in a continuous buffer.</p>
<p>The range of keys that need to be tested against the current particles can be calculated using key offsets.
Key offsets are relative key coordinates for the cells marked in yellow in the above diagram.</p>
<p>The first and last keys in the starting cell is calculated using:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">firstKey</span> <span class="o">=</span> <span class="n">currentParticleKey</span> <span class="o">-</span> <span class="nb">min</span><span class="p">(</span><span class="n">numSweepCells</span><span class="p">,</span> <span class="n">currentParticleKey</span> <span class="o">&</span> <span class="n">bucketMask</span><span class="p">)</span>
<span class="n">lastKey</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="n">currentParticleKey</span> <span class="o">+</span> <span class="n">numSweepCells</span><span class="p">,</span> <span class="n">currentParticleKey</span> <span class="o">|</span> <span class="n">bucketMask</span><span class="p">)</span>
</pre></div>
</div>
<p>The key offsets can be added to these values to obtain the range for the other cells.
Note that numSweepCells is not subtracted for firstKey to ensure no duplicate collisions are detected.
Note that bit operations can be used as the different axes are contained in their own bytes within the key.</p>
<p>Collision detection/response can begin once the first/last keys are known.</p>
<p>Note that the first/last keys from the previous processed particle are reused for optimizations that can be done because the keys are sorted.</p>
</div>
<div class="section" id="collision-detection-and-response">
<h3>Collision detection and response<a class="headerlink" href="#collision-detection-and-response" title="Permalink to this headline">¶</a></h3>
<p>Near phase collision detection can start once two possibly colliding keys are identified.
The pointers to the keys are converted to the particles and the rest particles.</p>
<p>A basic distance check between the particles and the user specified collision distance is done, culling non-colliding particles.</p>
<p>When available the distance is also checked against the rest distance to cull particles that are supposed to be close in the mesh.
This makes it possible to set the collision distance larger than the shortest constraint in the fabric without providing manual collision indices.</p>
<p>Next a position delta is calculated if the particle collision is not culled:</p>
<div class="highlight-python"><pre>diff = p1-p0
ratio = collisionDistance / |diff|
scale = stiffness / (epsilon + w0 + w1)
delta = scale * (diff - diff * ratio
p0 += delta * w0
p1 -= delta * w1</pre>
</div>
<p>TODO: format nicer</p>
</div>
</div>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="col-md-1"></div>
</div>
<div class="masthead">
<div class="row">
<ul class="breadcrumb">
<li><a href="../index.html">NvCloth 1.1.5 documentation</a></li>
<li><a href="Index.html" >Internal collision detection documentation</a></li>
</ul>
</div>
</div>
<footer>
<div class="footer-boilerplate">
<div class="row">
<div class="boilerplate">
Copyright © 2019, NVIDIA Corporation | <a href="http://www.nvidia.com/object/about-nvidia.html" onclick="s_objectID="http://www.nvidia.com/object/about-nvidia.html_1";return this.s_oc?this.s_oc(e):true">About NVIDIA </a> | <a href="http://www.nvidia.com/object/legal_info.html" onclick="s_objectID="http://www.nvidia.com/object/legal_info.html_1";return this.s_oc?this.s_oc(e):true">Legal Information </a> | <a href="http://www.nvidia.com/object/privacy_policy.html" onclick="s_objectID="http://www.nvidia.com/object/privacy_policy.html_1";return this.s_oc?this.s_oc(e):true">Privacy Policy </a>
</div>
</div>
</div>
</div>
</footer>
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
extensions: ["tex2jax.js"],
jax: ["input/TeX", "output/HTML-CSS"],
tex2jax: {
processEscapes: true,
skipTags: ["script","noscript","style","textarea"]
},
"HTML-CSS": { availableFonts: ["TeX"] },
TeX: {
Macros: {
Lrg: ['\\displaystyle{#1}', 1, ""]
}
}
});
</script>
<script type="text/javascript" async
src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-MML-AM_CHTML">
</script>
<script>
var treestatename = 'GWDocsTreeState';
var protocol = location.href.split('/')[0].toLowerCase();
var storage;
if (protocol.substring(0,4) == 'http') {
storage = $.cookieStorage;
storage.setPath('/');
} else {
storage = $.localStorage;
}
if (storage.isEmpty(treestatename)) {
storage.set(treestatename, {});
}
var treestate = storage.get(treestatename);
$.each($("#sidebar_toc ul li"), toc_walker);
function toc_walker(key, value) {
var handleSpan = $("<span></span>")
.addClass("toc_handle").prependTo(value);
handleSpan.attr("id", $(value).closest("div").attr("id") + "." + key);
if($(value).has("ul li").size() > 0) {
var id = handleSpan.attr("id");
if (!(id in treestate)) {
treestate[id] = false;
}
handleSpan.addClass("toc_expanded").click(function() {
$(this).toggleClass("toc_expanded toc_collapsed").siblings("ul").toggle();
treestate[$(this).attr('id')] = $(this).hasClass('toc_expanded');
storage.set(treestatename, treestate);
});
if(!($(this).hasClass('current') || treestate[id])) {
handleSpan.click();
}
if($(this).hasClass('current')) {
treestate[handleSpan.attr('id')] = handleSpan.hasClass('toc_expanded');
storage.set(treestatename, treestate);
}
}
}
</script>
</body>
</html>
|