Visualization Library 2.0.0-b5

A lightweight C++ OpenGL middleware for 2D/3D graphics

VL     Star     Watch     Fork     Issue

[Download] [Tutorials] [All Classes] [Grouped Classes]
tri_stripper.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2004 Tanguy Fautré.
3 // For conditions of distribution and use,
4 // see copyright notice in tri_stripper.h
5 //
7 // SVN: $Id: tri_stripper.cpp 86 2005-06-08 17:47:27Z gpsnoopy $
9 
10 #include "tri_stripper.h"
11 
13 #include "detail/policy.h"
14 
15 #include <cassert>
16 
17 
18 
19 
20 namespace triangle_stripper {
21 
22  using namespace detail;
23 
24 
25 
26 
28  : m_Triangles(TriIndices.size() / 3), // Silently ignore extra indices if (Indices.size() % 3 != 0)
29  m_StripID(0),
30  m_FirstRun(true)
31 {
32  SetCacheSize();
36 
37  make_connectivity_graph(m_Triangles, TriIndices);
38 }
39 
40 
41 
42 void tri_stripper::Strip(primitive_vector * out_pPrimitivesVector)
43 {
44  assert(out_pPrimitivesVector);
45 
46  if (! m_FirstRun) {
47  unmark_nodes(m_Triangles);
48  ResetStripIDs();
49  m_Cache.reset();
50  m_TriHeap.clear();
51  m_Candidates.clear();
52  m_StripID = 0;
53 
54  m_FirstRun = false;
55  }
56 
57  out_pPrimitivesVector->clear();
58 
59  InitTriHeap();
60 
61  Stripify();
62  AddLeftTriangles();
63 
64  std::swap(m_PrimitivesVector, (* out_pPrimitivesVector));
65 }
66 
67 
68 
69 void tri_stripper::InitTriHeap()
70 {
71  m_TriHeap.reserve(m_Triangles.size());
72 
73  // Set up the triangles priority queue
74  // The lower the number of available neighbour triangles, the higher the priority.
75  for (size_t i = 0; i < m_Triangles.size(); ++i)
76  m_TriHeap.push(m_Triangles[i].out_size());
77 
78  // We're not going to add new elements anymore
79  m_TriHeap.lock();
80 
81  // Remove useless triangles
82  // Note: we had to put all of them into the heap before to ensure coherency of the heap_array object
83  while ((! m_TriHeap.empty()) && (m_TriHeap.top() == 0))
84  m_TriHeap.pop();
85 }
86 
87 
88 
89 void tri_stripper::ResetStripIDs()
90 {
91  for (triangle_graph::node_iterator it = m_Triangles.begin(); it != m_Triangles.end(); ++it)
92  (**it).ResetStripID();
93 }
94 
95 
96 
97 void tri_stripper::Stripify()
98 {
99  while (! m_TriHeap.empty()) {
100 
101  // There is no triangle in the candidates list, refill it with the loneliest triangle
102  const size_t HeapTop = m_TriHeap.position(0);
103  m_Candidates.push_back(HeapTop);
104 
105  while (! m_Candidates.empty()) {
106 
107  // Note: FindBestStrip empties the candidate list, while BuildStrip refills it
108  const strip TriStrip = FindBestStrip();
109 
110  if (TriStrip.Size() >= m_MinStripSize)
111  BuildStrip(TriStrip);
112  }
113 
114  if (! m_TriHeap.removed(HeapTop))
115  m_TriHeap.erase(HeapTop);
116 
117  // Eliminate all the triangles that have now become useless
118  while ((! m_TriHeap.empty()) && (m_TriHeap.top() == 0))
119  m_TriHeap.pop();
120  }
121 }
122 
123 
124 
125 inline strip tri_stripper::FindBestStrip()
126 {
127  // Allow to restore the cache (modified by ExtendTriToStrip) and implicitly reset the cache hit count
128  const cache_simulator CacheBackup = m_Cache;
129 
130  policy Policy(m_MinStripSize, Cache());
131 
132  while (! m_Candidates.empty()) {
133 
134  const size_t Candidate = m_Candidates.back();
135  m_Candidates.pop_back();
136 
137  // Discard useless triangles from the candidate list
138  if ((m_Triangles[Candidate].marked()) || (m_TriHeap[Candidate] == 0))
139  continue;
140 
141  // Try to extend the triangle in the 3 possible forward directions
142  for (size_t i = 0; i < 3; ++i) {
143 
144  const strip Strip = ExtendToStrip(Candidate, triangle_order(i));
145  Policy.Challenge(Strip, m_TriHeap[Strip.Start()], m_Cache.hitcount());
146 
147  m_Cache = CacheBackup;
148  }
149 
150  // Try to extend the triangle in the 6 possible backward directions
151  if (m_BackwardSearch) {
152 
153  for (size_t i = 0; i < 3; ++i) {
154 
155  const strip Strip = BackExtendToStrip(Candidate, triangle_order(i), false);
156  Policy.Challenge(Strip, m_TriHeap[Strip.Start()], m_Cache.hitcount());
157 
158  m_Cache = CacheBackup;
159  }
160 
161  for (size_t i = 0; i < 3; ++i) {
162 
163  const strip Strip = BackExtendToStrip(Candidate, triangle_order(i), true);
164  Policy.Challenge(Strip, m_TriHeap[Strip.Start()], m_Cache.hitcount());
165 
166  m_Cache = CacheBackup;
167  }
168  }
169 
170  }
171 
172  return Policy.BestStrip();
173 }
174 
175 
176 
177 strip tri_stripper::ExtendToStrip(const size_t Start, triangle_order Order)
178 {
179  const triangle_order StartOrder = Order;
180 
181  // Begin a new strip
182  m_Triangles[Start]->SetStripID(++m_StripID);
183  AddTriangle(* m_Triangles[Start], Order, false);
184 
185  size_t Size = 1;
186  bool ClockWise = false;
187 
188  // Loop while we can further extend the strip
189  for (tri_iterator Node = (m_Triangles.begin() + Start);
190  (Node != m_Triangles.end()) && (!Cache() || ((Size + 2) < CacheSize()));
191  ++Size) {
192 
193  const const_link_iterator Link = LinkToNeighbour(Node, ClockWise, Order, false);
194 
195  // Is it the end of the strip?
196  if (Link == Node->out_end()) {
197 
198  Node = m_Triangles.end();
199  --Size;
200 
201  } else {
202 
203  Node = Link->terminal();
204  (* Node)->SetStripID(m_StripID);
205  ClockWise = ! ClockWise;
206 
207  }
208  }
209 
210  return strip(Start, StartOrder, Size);
211 }
212 
213 
214 
215 strip tri_stripper::BackExtendToStrip(size_t Start, triangle_order Order, bool ClockWise)
216 {
217  // Begin a new strip
218  m_Triangles[Start]->SetStripID(++m_StripID);
219  BackAddIndex(LastEdge(* m_Triangles[Start], Order).B());
220  size_t Size = 1;
221 
222  tri_iterator Node;
223 
224  // Loop while we can further extend the strip
225  for (Node = (m_Triangles.begin() + Start);
226  !Cache() || ((Size + 2) < CacheSize());
227  ++Size) {
228 
229  const const_link_iterator Link = BackLinkToNeighbour(Node, ClockWise, Order);
230 
231  // Is it the end of the strip?
232  if (Link == Node->out_end())
233  break;
234 
235  else {
236  Node = Link->terminal();
237  (* Node)->SetStripID(m_StripID);
238  ClockWise = ! ClockWise;
239  }
240  }
241 
242  // We have to start from a counterclockwise triangle.
243  // Simply return an empty strip in the case where the first triangle is clockwise.
244  // Even though we could discard the first triangle and start from the next counterclockwise triangle,
245  // this often leads to more lonely triangles afterward.
246  if (ClockWise)
247  return strip();
248 
249  if (Cache()) {
250  m_Cache.merge(m_BackCache, Size);
251  m_BackCache.reset();
252  }
253 
254  return strip(Node - m_Triangles.begin(), Order, Size);
255 }
256 
257 
258 
259 void tri_stripper::BuildStrip(const strip Strip)
260 {
261  const size_t Start = Strip.Start();
262 
263  bool ClockWise = false;
264  triangle_order Order = Strip.Order();
265 
266  // Create a new strip
267  m_PrimitivesVector.push_back(primitive_group());
268  m_PrimitivesVector.back().Type = TRIANGLE_STRIP;
269  AddTriangle(* m_Triangles[Start], Order, true);
270  MarkTriAsTaken(Start);
271 
272  // Loop while we can further extend the strip
273  tri_iterator Node = (m_Triangles.begin() + Start);
274 
275  for (size_t Size = 1; Size < Strip.Size(); ++Size) {
276 
277  const const_link_iterator Link = LinkToNeighbour(Node, ClockWise, Order, true);
278 
279  assert(Link != Node->out_end());
280 
281  // Go to the next triangle
282  Node = Link->terminal();
283  MarkTriAsTaken(Node - m_Triangles.begin());
284  ClockWise = ! ClockWise;
285  }
286 }
287 
288 
289 
290 inline tri_stripper::const_link_iterator tri_stripper::LinkToNeighbour(const const_tri_iterator Node, const bool ClockWise, triangle_order & Order, const bool NotSimulation)
291 {
292  const triangle_edge Edge = LastEdge(** Node, Order);
293 
294  for (const_link_iterator Link = Node->out_begin(); Link != Node->out_end(); ++Link) {
295 
296  // Get the reference to the possible next triangle
297  const triangle & Tri = ** Link->terminal();
298 
299  // Check whether it's already been used
300  if (NotSimulation || (Tri.StripID() != m_StripID)) {
301 
302  if (! Link->terminal()->marked()) {
303 
304  // Does the current candidate triangle match the required position for the strip?
305 
306  if ((Edge.B() == Tri.A()) && (Edge.A() == Tri.B())) {
307  Order = (ClockWise) ? ABC : BCA;
308  AddIndex(Tri.C(), NotSimulation);
309  return Link;
310  }
311 
312  else if ((Edge.B() == Tri.B()) && (Edge.A() == Tri.C())) {
313  Order = (ClockWise) ? BCA : CAB;
314  AddIndex(Tri.A(), NotSimulation);
315  return Link;
316  }
317 
318  else if ((Edge.B() == Tri.C()) && (Edge.A() == Tri.A())) {
319  Order = (ClockWise) ? CAB : ABC;
320  AddIndex(Tri.B(), NotSimulation);
321  return Link;
322  }
323  }
324  }
325 
326  }
327 
328  return Node->out_end();
329 }
330 
331 
332 
333 inline tri_stripper::const_link_iterator tri_stripper::BackLinkToNeighbour(const_tri_iterator Node, bool ClockWise, triangle_order & Order)
334 {
335  const triangle_edge Edge = FirstEdge(** Node, Order);
336 
337  for (const_link_iterator Link = Node->out_begin(); Link != Node->out_end(); ++Link) {
338 
339  // Get the reference to the possible previous triangle
340  const triangle & Tri = ** Link->terminal();
341 
342  // Check whether it's already been used
343  if ((Tri.StripID() != m_StripID) && ! Link->terminal()->marked()) {
344 
345  // Does the current candidate triangle match the required position for the strip?
346 
347  if ((Edge.B() == Tri.A()) && (Edge.A() == Tri.B())) {
348  Order = (ClockWise) ? CAB : BCA;
349  BackAddIndex(Tri.C());
350  return Link;
351  }
352 
353  else if ((Edge.B() == Tri.B()) && (Edge.A() == Tri.C())) {
354  Order = (ClockWise) ? ABC : CAB;
355  BackAddIndex(Tri.A());
356  return Link;
357  }
358 
359  else if ((Edge.B() == Tri.C()) && (Edge.A() == Tri.A())) {
360  Order = (ClockWise) ? BCA : ABC;
361  BackAddIndex(Tri.B());
362  return Link;
363  }
364  }
365 
366  }
367 
368  return Node->out_end();
369 }
370 
371 
372 
373 void tri_stripper::MarkTriAsTaken(const size_t i)
374 {
375  // typedef triangle_graph::node_iterator tri_node_iter;
376  typedef triangle_graph::out_arc_iterator tri_link_iter;
377 
378  // Mark the triangle node
379  m_Triangles[i].mark();
380 
381  // Remove triangle from priority queue if it isn't yet
382  if (! m_TriHeap.removed(i))
383  m_TriHeap.erase(i);
384 
385  // Adjust the degree of available neighbour triangles
386  for (tri_link_iter Link = m_Triangles[i].out_begin(); Link != m_Triangles[i].out_end(); ++Link) {
387 
388  const size_t j = Link->terminal() - m_Triangles.begin();
389 
390  if ((! m_Triangles[j].marked()) && (! m_TriHeap.removed(j))) {
391  size_t NewDegree = m_TriHeap.peek(j);
392  NewDegree = NewDegree - 1;
393  m_TriHeap.update(j, NewDegree);
394 
395  // Update the candidate list if cache is enabled
396  if (Cache() && (NewDegree > 0))
397  m_Candidates.push_back(j);
398  }
399  }
400 }
401 
402 
403 
404 inline triangle_edge tri_stripper::FirstEdge(const triangle & Triangle, const triangle_order Order)
405 {
406  switch (Order)
407  {
408  case ABC:
409  return triangle_edge(Triangle.A(), Triangle.B());
410 
411  case BCA:
412  return triangle_edge(Triangle.B(), Triangle.C());
413 
414  case CAB:
415  return triangle_edge(Triangle.C(), Triangle.A());
416 
417  default:
418  assert(false);
419  return triangle_edge(0, 0);
420  }
421 }
422 
423 
424 
425 inline triangle_edge tri_stripper::LastEdge(const triangle & Triangle, const triangle_order Order)
426 {
427  switch (Order)
428  {
429  case ABC:
430  return triangle_edge(Triangle.B(), Triangle.C());
431 
432  case BCA:
433  return triangle_edge(Triangle.C(), Triangle.A());
434 
435  case CAB:
436  return triangle_edge(Triangle.A(), Triangle.B());
437 
438  default:
439  assert(false);
440  return triangle_edge(0, 0);
441  }
442 }
443 
444 
445 
446 inline void tri_stripper::AddIndex(const index i, const bool NotSimulation)
447 {
448  if (Cache())
449  m_Cache.push(i, ! NotSimulation);
450 
451  if (NotSimulation)
452  m_PrimitivesVector.back().Indices.push_back(i);
453 }
454 
455 
456 
457 inline void tri_stripper::BackAddIndex(const index i)
458 {
459  if (Cache())
460  m_BackCache.push(i, true);
461 }
462 
463 
464 
465 inline void tri_stripper::AddTriangle(const triangle & Tri, const triangle_order Order, const bool NotSimulation)
466 {
467  switch (Order)
468  {
469  case ABC:
470  AddIndex(Tri.A(), NotSimulation);
471  AddIndex(Tri.B(), NotSimulation);
472  AddIndex(Tri.C(), NotSimulation);
473  break;
474 
475  case BCA:
476  AddIndex(Tri.B(), NotSimulation);
477  AddIndex(Tri.C(), NotSimulation);
478  AddIndex(Tri.A(), NotSimulation);
479  break;
480 
481  case CAB:
482  AddIndex(Tri.C(), NotSimulation);
483  AddIndex(Tri.A(), NotSimulation);
484  AddIndex(Tri.B(), NotSimulation);
485  break;
486  }
487 }
488 
489 
490 
491 inline void tri_stripper::BackAddTriangle(const triangle & Tri, const triangle_order Order)
492 {
493  switch (Order)
494  {
495  case ABC:
496  BackAddIndex(Tri.C());
497  BackAddIndex(Tri.B());
498  BackAddIndex(Tri.A());
499  break;
500 
501  case BCA:
502  BackAddIndex(Tri.A());
503  BackAddIndex(Tri.C());
504  BackAddIndex(Tri.B());
505  break;
506 
507  case CAB:
508  BackAddIndex(Tri.B());
509  BackAddIndex(Tri.A());
510  BackAddIndex(Tri.C());
511  break;
512  }
513 }
514 
515 
516 
517 void tri_stripper::AddLeftTriangles()
518 {
519  // Create the last indices array and fill it with all the triangles that couldn't be stripped
520  primitive_group Primitives;
521  Primitives.Type = TRIANGLES;
522  m_PrimitivesVector.push_back(Primitives);
523  indices & Indices = m_PrimitivesVector.back().Indices;
524 
525  for (size_t i = 0; i < m_Triangles.size(); ++i)
526  if (! m_Triangles[i].marked()) {
527  Indices.push_back(m_Triangles[i]->A());
528  Indices.push_back(m_Triangles[i]->B());
529  Indices.push_back(m_Triangles[i]->C());
530  }
531 
532  // Undo if useless
533  if (Indices.size() == 0)
534  m_PrimitivesVector.pop_back();
535 }
536 
537 
538 
539 inline bool tri_stripper::Cache() const
540 {
541  return (m_Cache.size() != 0);
542 }
543 
544 
545 
546 inline size_t tri_stripper::CacheSize() const
547 {
548  return m_Cache.size();
549 }
550 
551 
552 
553 
554 } // namespace triangle_stripper
void SetPushCacheHits(bool Enabled=true)
Definition: tri_stripper.h:177
void Strip(primitive_vector *out_pPrimitivesVector)
void update(size_t i, const T &Elem)
Definition: heap_array.h:236
void Challenge(strip Strip, size_t Degree, size_t CacheHits)
Definition: policy.cpp:22
png_uint_32 i
Definition: png.h:2640
const T & peek(size_t i) const
Definition: heap_array.h:143
void SetBackwardSearch(bool Enabled=false)
Definition: tri_stripper.h:170
void merge(const cache_simulator &Backward, size_t PossibleOverlap)
size_t position(size_t i) const
Definition: heap_array.h:227
#define true
Definition: ftrandom.c:49
void SetMinStripSize(size_t MinStripSize=2)
Definition: tri_stripper.h:161
void SetCacheSize(size_t CacheSize=10)
Definition: tri_stripper.h:154
void make_connectivity_graph(graph_array< triangle > &Triangles, const indices &Indices)
tri_stripper(const indices &TriIndices)
std::vector< primitive_group > primitive_vector
Definition: public_types.h:36
unsigned int index
Definition: public_types.h:21
triangle_order Order() const
Definition: types.h:82
void push(index i, bool CountCacheHit=false)
GLsizeiptr size
void unmark_nodes(graph_array< nodetype > &G)