Blender  V2.93
ViewMapBuilder.cpp
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
22 #include <algorithm>
23 #include <memory>
24 #include <sstream>
25 #include <stdexcept>
26 
27 #include "FRS_freestyle.h"
28 
29 #include "BoxGrid.h"
30 #include "CulledOccluderSource.h"
32 #include "OccluderSource.h"
33 #include "SphericalGrid.h"
34 #include "ViewMapBuilder.h"
35 
36 #include "../geometry/GeomUtils.h"
37 #include "../geometry/GridHelpers.h"
38 
39 #include "../winged_edge/WFillGrid.h"
40 
41 #include "BKE_global.h"
42 
43 namespace Freestyle {
44 
45 // XXX Grmll... G is used as template's typename parameter :/
46 static const Global &_global = G;
47 
48 #define LOGGING 0
49 
50 using namespace std;
51 
52 template<typename G, typename I>
53 static void findOccludee(FEdge *fe,
54  G & /*grid*/,
55  I &occluders,
56  real epsilon,
57  WFace **oaWFace,
58  Vec3r &u,
59  Vec3r &A,
60  Vec3r &origin,
61  Vec3r &edgeDir,
62  vector<WVertex *> &faceVertices)
63 {
64  WFace *face = nullptr;
65  if (fe->isSmooth()) {
66  FEdgeSmooth *fes = dynamic_cast<FEdgeSmooth *>(fe);
67  face = (WFace *)fes->face();
68  }
69  WFace *oface;
70  bool skipFace;
71 
73 
74  *oaWFace = nullptr;
75  if (((fe)->getNature() & Nature::SILHOUETTE) || ((fe)->getNature() & Nature::BORDER)) {
76  // we cast a ray from A in the same direction but looking behind
77  Vec3r v(-u[0], -u[1], -u[2]);
78  bool noIntersection = true;
79  real mint = FLT_MAX;
80 
81  for (occluders.initAfterTarget(); occluders.validAfterTarget(); occluders.nextOccludee()) {
82 #if LOGGING
84  cout << "\t\tEvaluating intersection for occludee " << occluders.getWFace() << " and ray "
85  << A << " * " << u << endl;
86  }
87 #endif
88  oface = occluders.getWFace();
89  Polygon3r *p = occluders.getCameraSpacePolygon();
90  real d = -((p->getVertices())[0] * p->getNormal());
91  real t, t_u, t_v;
92 
93  if (nullptr != face) {
94  skipFace = false;
95 
96  if (face == oface) {
97  continue;
98  }
99 
100  if (faceVertices.empty()) {
101  continue;
102  }
103 
104  for (vector<WVertex *>::iterator fv = faceVertices.begin(), fvend = faceVertices.end();
105  fv != fvend;
106  ++fv) {
107  if ((*fv)->isBoundary()) {
108  continue;
109  }
110  WVertex::incoming_edge_iterator iebegin = (*fv)->incoming_edges_begin();
111  WVertex::incoming_edge_iterator ieend = (*fv)->incoming_edges_end();
112  for (ie = iebegin; ie != ieend; ++ie) {
113  if ((*ie) == nullptr) {
114  continue;
115  }
116 
117  WFace *sface = (*ie)->GetbFace();
118  if (sface == oface) {
119  skipFace = true;
120  break;
121  }
122  }
123  if (skipFace) {
124  break;
125  }
126  }
127  if (skipFace) {
128  continue;
129  }
130  }
131  else {
132  // check whether the edge and the polygon plane are coincident:
133  //-------------------------------------------------------------
134  // first let us compute the plane equation.
135  if (GeomUtils::COINCIDENT ==
136  GeomUtils::intersectRayPlane(origin, edgeDir, p->getNormal(), d, t, epsilon)) {
137 #if LOGGING
139  cout << "\t\tRejecting occluder for target coincidence." << endl;
140  }
141 #endif
142  continue;
143  }
144  }
145 
146  if (p->rayIntersect(A, v, t, t_u, t_v)) {
147 #if LOGGING
149  cout << "\t\tRay " << A << " * " << v << " intersects at time " << t << endl;
150  cout << "\t\t(v * normal) == " << (v * p->getNormal()) << " for normal "
151  << p->getNormal() << endl;
152  }
153 #endif
154  if (fabs(v * p->getNormal()) > 0.0001) {
155  if ((t > 0.0) /* && (t<1.0) */) {
156  if (t < mint) {
157  *oaWFace = oface;
158  mint = t;
159  noIntersection = false;
160  fe->setOccludeeIntersection(Vec3r(A + t * v));
161 #if LOGGING
163  cout << "\t\tIs occludee" << endl;
164  }
165 #endif
166  }
167  }
168  }
169 
170  occluders.reportDepth(A, v, t);
171  }
172  }
173 
174  if (noIntersection) {
175  *oaWFace = nullptr;
176  }
177  }
178 }
179 
180 template<typename G, typename I>
181 static void findOccludee(FEdge *fe, G &grid, real epsilon, ViewEdge * /*ve*/, WFace **oaFace)
182 {
183  Vec3r A;
184  Vec3r edgeDir;
185  Vec3r origin;
186  A = Vec3r(((fe)->vertexA()->point3D() + (fe)->vertexB()->point3D()) / 2.0);
187  edgeDir = Vec3r((fe)->vertexB()->point3D() - (fe)->vertexA()->point3D());
188  edgeDir.normalize();
189  origin = Vec3r((fe)->vertexA()->point3D());
190  Vec3r u;
191  if (grid.orthographicProjection()) {
192  u = Vec3r(0.0, 0.0, grid.viewpoint().z() - A.z());
193  }
194  else {
195  u = Vec3r(grid.viewpoint() - A);
196  }
197  u.normalize();
198 
199  vector<WVertex *> faceVertices;
200 
201  WFace *face = nullptr;
202  if (fe->isSmooth()) {
203  FEdgeSmooth *fes = dynamic_cast<FEdgeSmooth *>(fe);
204  face = (WFace *)fes->face();
205  }
206 
207  if (face) {
208  face->RetrieveVertexList(faceVertices);
209  }
210 
211  I occluders(grid, A, epsilon);
212  findOccludee<G, I>(fe, grid, occluders, epsilon, oaFace, u, A, origin, edgeDir, faceVertices);
213 }
214 
215 // computeVisibility takes a pointer to foundOccluders, instead of using a reference,
216 // so that computeVeryFastVisibility can skip the AddOccluders step with minimal overhead.
217 template<typename G, typename I>
218 static int computeVisibility(ViewMap *viewMap,
219  FEdge *fe,
220  G &grid,
221  real epsilon,
222  ViewEdge * /*ve*/,
223  WFace **oaWFace,
224  set<ViewShape *> *foundOccluders)
225 {
226  int qi = 0;
227 
228  Vec3r center;
229  Vec3r edgeDir;
230  Vec3r origin;
231 
232  center = fe->center3d();
233  edgeDir = Vec3r(fe->vertexB()->point3D() - fe->vertexA()->point3D());
234  edgeDir.normalize();
235  origin = Vec3r(fe->vertexA()->point3D());
236 
237  Vec3r vp;
238  if (grid.orthographicProjection()) {
239  vp = Vec3r(center.x(), center.y(), grid.viewpoint().z());
240  }
241  else {
242  vp = Vec3r(grid.viewpoint());
243  }
244  Vec3r u(vp - center);
245  real raylength = u.norm();
246  u.normalize();
247 
248  WFace *face = nullptr;
249  if (fe->isSmooth()) {
250  FEdgeSmooth *fes = dynamic_cast<FEdgeSmooth *>(fe);
251  face = (WFace *)fes->face();
252  }
253  vector<WVertex *> faceVertices;
255 
256  WFace *oface;
257  bool skipFace;
258 
259  if (face) {
260  face->RetrieveVertexList(faceVertices);
261  }
262 
263  I occluders(grid, center, epsilon);
264 
265  for (occluders.initBeforeTarget(); occluders.validBeforeTarget(); occluders.nextOccluder()) {
266  // If we're dealing with an exact silhouette, check whether we must take care of this occluder
267  // of not. (Indeed, we don't consider the occluders that share at least one vertex with the
268  // face containing this edge).
269  //-----------
270  oface = occluders.getWFace();
271  Polygon3r *p = occluders.getCameraSpacePolygon();
272  real t, t_u, t_v;
273 #if LOGGING
275  cout << "\t\tEvaluating intersection for occluder " << (p->getVertices())[0]
276  << (p->getVertices())[1] << (p->getVertices())[2] << endl
277  << "\t\t\tand ray " << vp << " * " << u << " (center " << center << ")" << endl;
278  }
279 #endif
280 
281 #if LOGGING
282  Vec3r v(vp - center);
283  real rl = v.norm();
284  v.normalize();
285  vector<Vec3r> points;
286  // Iterate over vertices, storing projections in points
287  for (vector<WOEdge *>::const_iterator woe = oface->getEdgeList().begin(),
288  woend = oface->getEdgeList().end();
289  woe != woend;
290  woe++) {
291  points.push_back(Vec3r((*woe)->GetaVertex()->GetVertex()));
292  }
293  Polygon3r p1(points, oface->GetNormal());
294  Vec3r v1((p1.getVertices())[0]);
295  real d = -(v1 * p->getNormal());
297  cout << "\t\tp: " << (p->getVertices())[0] << (p->getVertices())[1] << (p->getVertices())[2]
298  << ", norm: " << p->getNormal() << endl;
299  cout << "\t\tp1: " << (p1.getVertices())[0] << (p1.getVertices())[1] << (p1.getVertices())[2]
300  << ", norm: " << p1.getNormal() << endl;
301  }
302 #else
303  real d = -((p->getVertices())[0] * p->getNormal());
304 #endif
305 
306  if (face) {
307 #if LOGGING
309  cout << "\t\tDetermining face adjacency...";
310  }
311 #endif
312  skipFace = false;
313 
314  if (face == oface) {
315 #if LOGGING
317  cout << " Rejecting occluder for face concurrency." << endl;
318  }
319 #endif
320  continue;
321  }
322 
323  for (vector<WVertex *>::iterator fv = faceVertices.begin(), fvend = faceVertices.end();
324  fv != fvend;
325  ++fv) {
326  if ((*fv)->isBoundary()) {
327  continue;
328  }
329 
330  WVertex::incoming_edge_iterator iebegin = (*fv)->incoming_edges_begin();
331  WVertex::incoming_edge_iterator ieend = (*fv)->incoming_edges_end();
332  for (ie = iebegin; ie != ieend; ++ie) {
333  if ((*ie) == nullptr) {
334  continue;
335  }
336 
337  WFace *sface = (*ie)->GetbFace();
338  // WFace *sfacea = (*ie)->GetaFace();
339  // if ((sface == oface) || (sfacea == oface))
340  if (sface == oface) {
341  skipFace = true;
342  break;
343  }
344  }
345  if (skipFace) {
346  break;
347  }
348  }
349  if (skipFace) {
350 #if LOGGING
352  cout << " Rejecting occluder for face adjacency." << endl;
353  }
354 #endif
355  continue;
356  }
357  }
358  else {
359  // check whether the edge and the polygon plane are coincident:
360  //-------------------------------------------------------------
361  // first let us compute the plane equation.
362  if (GeomUtils::COINCIDENT ==
363  GeomUtils::intersectRayPlane(origin, edgeDir, p->getNormal(), d, t, epsilon)) {
364 #if LOGGING
366  cout << "\t\tRejecting occluder for target coincidence." << endl;
367  }
368 #endif
369  continue;
370  }
371  }
372 
373 #if LOGGING
375  real x;
376  if (p1.rayIntersect(center, v, x, t_u, t_v)) {
377  cout << "\t\tRay should intersect at time " << (rl - x) << ". Center: " << center
378  << ", V: " << v << ", RL: " << rl << ", T:" << x << endl;
379  }
380  else {
381  cout << "\t\tRay should not intersect. Center: " << center << ", V: " << v
382  << ", RL: " << rl << endl;
383  }
384  }
385 #endif
386 
387  if (p->rayIntersect(center, u, t, t_u, t_v)) {
388 #if LOGGING
390  cout << "\t\tRay " << center << " * " << u << " intersects at time " << t
391  << " (raylength is " << raylength << ")" << endl;
392  cout << "\t\t(u * normal) == " << (u * p->getNormal()) << " for normal " << p->getNormal()
393  << endl;
394  }
395 #endif
396  if (fabs(u * p->getNormal()) > 0.0001) {
397  if ((t > 0.0) && (t < raylength)) {
398 #if LOGGING
400  cout << "\t\tIs occluder" << endl;
401  }
402 #endif
403  if (foundOccluders != nullptr) {
404  ViewShape *vshape = viewMap->viewShape(oface->GetVertex(0)->shape()->GetId());
405  foundOccluders->insert(vshape);
406  }
407  ++qi;
408 
409  if (!grid.enableQI()) {
410  break;
411  }
412  }
413 
414  occluders.reportDepth(center, u, t);
415  }
416  }
417  }
418 
419  // Find occludee
420  findOccludee<G, I>(
421  fe, grid, occluders, epsilon, oaWFace, u, center, origin, edgeDir, faceVertices);
422 
423  return qi;
424 }
425 
426 // computeCumulativeVisibility returns the lowest x such that the majority of FEdges have QI <= x
427 //
428 // This was probably the original intention of the "normal" algorithm on which
429 // computeDetailedVisibility is based. But because the "normal" algorithm chooses the most popular
430 // QI, without considering any other values, a ViewEdge with FEdges having QIs of 0, 21, 22, 23, 24
431 // and 25 will end up having a total QI of 0, even though most of the FEdges are heavily occluded.
432 // computeCumulativeVisibility will treat this case as a QI of 22 because 3 out of 6 occluders have
433 // QI <= 22.
434 
435 template<typename G, typename I>
436 static void computeCumulativeVisibility(ViewMap *ioViewMap,
437  G &grid,
438  real epsilon,
439  RenderMonitor *iRenderMonitor)
440 {
441  vector<ViewEdge *> &vedges = ioViewMap->ViewEdges();
442 
443  FEdge *fe, *festart;
444  int nSamples = 0;
445  vector<WFace *> wFaces;
446  WFace *wFace = nullptr;
447  unsigned cnt = 0;
448  unsigned cntStep = (unsigned)ceil(0.01f * vedges.size());
449  unsigned tmpQI = 0;
450  unsigned qiClasses[256];
451  unsigned maxIndex, maxCard;
452  unsigned qiMajority;
453  for (vector<ViewEdge *>::iterator ve = vedges.begin(), veend = vedges.end(); ve != veend; ve++) {
454  if (iRenderMonitor) {
455  if (iRenderMonitor->testBreak()) {
456  break;
457  }
458  if (cnt % cntStep == 0) {
459  stringstream ss;
460  ss << "Freestyle: Visibility computations " << (100 * cnt / vedges.size()) << "%";
461  iRenderMonitor->setInfo(ss.str());
462  iRenderMonitor->progress((float)cnt / vedges.size());
463  }
464  cnt++;
465  }
466 #if LOGGING
468  cout << "Processing ViewEdge " << (*ve)->getId() << endl;
469  }
470 #endif
471  // Find an edge to test
472  if (!(*ve)->isInImage()) {
473  // This view edge has been proscenium culled
474  (*ve)->setQI(255);
475  (*ve)->setaShape(nullptr);
476 #if LOGGING
478  cout << "\tCulled." << endl;
479  }
480 #endif
481  continue;
482  }
483 
484  // Test edge
485  festart = (*ve)->fedgeA();
486  fe = (*ve)->fedgeA();
487  qiMajority = 0;
488  do {
489  if (fe != nullptr && fe->isInImage()) {
490  qiMajority++;
491  }
492  fe = fe->nextEdge();
493  } while (fe && fe != festart);
494 
495  if (qiMajority == 0) {
496  // There are no occludable FEdges on this ViewEdge
497  // This should be impossible.
499  cout << "View Edge in viewport without occludable FEdges: " << (*ve)->getId() << endl;
500  }
501  // We can recover from this error:
502  // Treat this edge as fully visible with no occludee
503  (*ve)->setQI(0);
504  (*ve)->setaShape(nullptr);
505  continue;
506  }
507 
508  ++qiMajority;
509  qiMajority >>= 1;
510 
511 #if LOGGING
513  cout << "\tqiMajority: " << qiMajority << endl;
514  }
515 #endif
516 
517  tmpQI = 0;
518  maxIndex = 0;
519  maxCard = 0;
520  nSamples = 0;
521  memset(qiClasses, 0, 256 * sizeof(*qiClasses));
522  set<ViewShape *> foundOccluders;
523 
524  fe = (*ve)->fedgeA();
525  do {
526  if (!fe || !fe->isInImage()) {
527  fe = fe->nextEdge();
528  continue;
529  }
530  if ((maxCard < qiMajority)) {
531  // ARB: change &wFace to wFace and use reference in called function
532  tmpQI = computeVisibility<G, I>(
533  ioViewMap, fe, grid, epsilon, *ve, &wFace, &foundOccluders);
534 #if LOGGING
536  cout << "\tFEdge: visibility " << tmpQI << endl;
537  }
538 #endif
539 
540  // ARB: This is an error condition, not an alert condition.
541  // Some sort of recovery or abort is necessary.
542  if (tmpQI >= 256) {
543  cerr << "Warning: too many occluding levels" << endl;
544  // ARB: Wild guess: instead of aborting or corrupting memory, treat as tmpQI == 255
545  tmpQI = 255;
546  }
547 
548  if (++qiClasses[tmpQI] > maxCard) {
549  maxCard = qiClasses[tmpQI];
550  maxIndex = tmpQI;
551  }
552  }
553  else {
554  // ARB: FindOccludee is redundant if ComputeRayCastingVisibility has been called
555  // ARB: change &wFace to wFace and use reference in called function
556  findOccludee<G, I>(fe, grid, epsilon, *ve, &wFace);
557 #if LOGGING
559  cout << "\tFEdge: occludee only (" << (wFace != NULL ? "found" : "not found") << ")"
560  << endl;
561  }
562 #endif
563  }
564 
565  // Store test results
566  if (wFace) {
567  vector<Vec3r> vertices;
568  for (int i = 0, numEdges = wFace->numberOfEdges(); i < numEdges; ++i) {
569  vertices.emplace_back(wFace->GetVertex(i)->GetVertex());
570  }
571  Polygon3r poly(vertices, wFace->GetNormal());
572  poly.userdata = (void *)wFace;
573  fe->setaFace(poly);
574  wFaces.push_back(wFace);
575  fe->setOccludeeEmpty(false);
576 #if LOGGING
578  cout << "\tFound occludee" << endl;
579  }
580 #endif
581  }
582  else {
583  fe->setOccludeeEmpty(true);
584  }
585 
586  ++nSamples;
587  fe = fe->nextEdge();
588  } while ((maxCard < qiMajority) && (fe) && (fe != festart));
589 
590 #if LOGGING
592  cout << "\tFinished with " << nSamples << " samples, maxCard = " << maxCard << endl;
593  }
594 #endif
595 
596  // ViewEdge
597  // qi --
598  // Find the minimum value that is >= the majority of the QI
599  for (unsigned count = 0, i = 0; i < 256; ++i) {
600  count += qiClasses[i];
601  if (count >= qiMajority) {
602  (*ve)->setQI(i);
603  break;
604  }
605  }
606  // occluders --
607  // I would rather not have to go through the effort of creating this set and then copying out
608  // its contents. Is there a reason why ViewEdge::_Occluders cannot be converted to a set<>?
609  for (set<ViewShape *>::iterator o = foundOccluders.begin(), oend = foundOccluders.end();
610  o != oend;
611  ++o) {
612  (*ve)->AddOccluder((*o));
613  }
614 #if LOGGING
616  cout << "\tConclusion: QI = " << maxIndex << ", " << (*ve)->occluders_size() << " occluders."
617  << endl;
618  }
619 #else
620  (void)maxIndex;
621 #endif
622  // occludee --
623  if (!wFaces.empty()) {
624  if (wFaces.size() <= (float)nSamples / 2.0f) {
625  (*ve)->setaShape(nullptr);
626  }
627  else {
628  ViewShape *vshape = ioViewMap->viewShape(
629  (*wFaces.begin())->GetVertex(0)->shape()->GetId());
630  (*ve)->setaShape(vshape);
631  }
632  }
633 
634  wFaces.clear();
635  }
636  if (iRenderMonitor && !vedges.empty()) {
637  stringstream ss;
638  ss << "Freestyle: Visibility computations " << (100 * cnt / vedges.size()) << "%";
639  iRenderMonitor->setInfo(ss.str());
640  iRenderMonitor->progress((float)cnt / vedges.size());
641  }
642 }
643 
644 template<typename G, typename I>
645 static void computeDetailedVisibility(ViewMap *ioViewMap,
646  G &grid,
647  real epsilon,
648  RenderMonitor *iRenderMonitor)
649 {
650  vector<ViewEdge *> &vedges = ioViewMap->ViewEdges();
651 
652  FEdge *fe, *festart;
653  int nSamples = 0;
654  vector<WFace *> wFaces;
655  WFace *wFace = nullptr;
656  unsigned tmpQI = 0;
657  unsigned qiClasses[256];
658  unsigned maxIndex, maxCard;
659  unsigned qiMajority;
660  for (vector<ViewEdge *>::iterator ve = vedges.begin(), veend = vedges.end(); ve != veend; ve++) {
661  if (iRenderMonitor && iRenderMonitor->testBreak()) {
662  break;
663  }
664 #if LOGGING
666  cout << "Processing ViewEdge " << (*ve)->getId() << endl;
667  }
668 #endif
669  // Find an edge to test
670  if (!(*ve)->isInImage()) {
671  // This view edge has been proscenium culled
672  (*ve)->setQI(255);
673  (*ve)->setaShape(nullptr);
674 #if LOGGING
676  cout << "\tCulled." << endl;
677  }
678 #endif
679  continue;
680  }
681 
682  // Test edge
683  festart = (*ve)->fedgeA();
684  fe = (*ve)->fedgeA();
685  qiMajority = 0;
686  do {
687  if (fe != nullptr && fe->isInImage()) {
688  qiMajority++;
689  }
690  fe = fe->nextEdge();
691  } while (fe && fe != festart);
692 
693  if (qiMajority == 0) {
694  // There are no occludable FEdges on this ViewEdge
695  // This should be impossible.
697  cout << "View Edge in viewport without occludable FEdges: " << (*ve)->getId() << endl;
698  }
699  // We can recover from this error:
700  // Treat this edge as fully visible with no occludee
701  (*ve)->setQI(0);
702  (*ve)->setaShape(nullptr);
703  continue;
704  }
705 
706  ++qiMajority;
707  qiMajority >>= 1;
708 
709 #if LOGGING
711  cout << "\tqiMajority: " << qiMajority << endl;
712  }
713 #endif
714 
715  tmpQI = 0;
716  maxIndex = 0;
717  maxCard = 0;
718  nSamples = 0;
719  memset(qiClasses, 0, 256 * sizeof(*qiClasses));
720  set<ViewShape *> foundOccluders;
721 
722  fe = (*ve)->fedgeA();
723  do {
724  if (fe == nullptr || !fe->isInImage()) {
725  fe = fe->nextEdge();
726  continue;
727  }
728  if ((maxCard < qiMajority)) {
729  // ARB: change &wFace to wFace and use reference in called function
730  tmpQI = computeVisibility<G, I>(
731  ioViewMap, fe, grid, epsilon, *ve, &wFace, &foundOccluders);
732 #if LOGGING
734  cout << "\tFEdge: visibility " << tmpQI << endl;
735  }
736 #endif
737 
738  // ARB: This is an error condition, not an alert condition.
739  // Some sort of recovery or abort is necessary.
740  if (tmpQI >= 256) {
741  cerr << "Warning: too many occluding levels" << endl;
742  // ARB: Wild guess: instead of aborting or corrupting memory, treat as tmpQI == 255
743  tmpQI = 255;
744  }
745 
746  if (++qiClasses[tmpQI] > maxCard) {
747  maxCard = qiClasses[tmpQI];
748  maxIndex = tmpQI;
749  }
750  }
751  else {
752  // ARB: FindOccludee is redundant if ComputeRayCastingVisibility has been called
753  // ARB: change &wFace to wFace and use reference in called function
754  findOccludee<G, I>(fe, grid, epsilon, *ve, &wFace);
755 #if LOGGING
757  cout << "\tFEdge: occludee only (" << (wFace != NULL ? "found" : "not found") << ")"
758  << endl;
759  }
760 #endif
761  }
762 
763  // Store test results
764  if (wFace) {
765  vector<Vec3r> vertices;
766  for (int i = 0, numEdges = wFace->numberOfEdges(); i < numEdges; ++i) {
767  vertices.emplace_back(wFace->GetVertex(i)->GetVertex());
768  }
769  Polygon3r poly(vertices, wFace->GetNormal());
770  poly.userdata = (void *)wFace;
771  fe->setaFace(poly);
772  wFaces.push_back(wFace);
773  fe->setOccludeeEmpty(false);
774 #if LOGGING
776  cout << "\tFound occludee" << endl;
777  }
778 #endif
779  }
780  else {
781  fe->setOccludeeEmpty(true);
782  }
783 
784  ++nSamples;
785  fe = fe->nextEdge();
786  } while ((maxCard < qiMajority) && (fe) && (fe != festart));
787 
788 #if LOGGING
790  cout << "\tFinished with " << nSamples << " samples, maxCard = " << maxCard << endl;
791  }
792 #endif
793 
794  // ViewEdge
795  // qi --
796  (*ve)->setQI(maxIndex);
797  // occluders --
798  // I would rather not have to go through the effort of creating this this set and then copying
799  // out its contents. Is there a reason why ViewEdge::_Occluders cannot be converted to a set<>?
800  for (set<ViewShape *>::iterator o = foundOccluders.begin(), oend = foundOccluders.end();
801  o != oend;
802  ++o) {
803  (*ve)->AddOccluder((*o));
804  }
805 #if LOGGING
807  cout << "\tConclusion: QI = " << maxIndex << ", " << (*ve)->occluders_size() << " occluders."
808  << endl;
809  }
810 #endif
811  // occludee --
812  if (!wFaces.empty()) {
813  if (wFaces.size() <= (float)nSamples / 2.0f) {
814  (*ve)->setaShape(nullptr);
815  }
816  else {
817  ViewShape *vshape = ioViewMap->viewShape(
818  (*wFaces.begin())->GetVertex(0)->shape()->GetId());
819  (*ve)->setaShape(vshape);
820  }
821  }
822 
823  wFaces.clear();
824  }
825 }
826 
827 template<typename G, typename I>
828 static void computeFastVisibility(ViewMap *ioViewMap, G &grid, real epsilon)
829 {
830  vector<ViewEdge *> &vedges = ioViewMap->ViewEdges();
831 
832  FEdge *fe, *festart;
833  unsigned nSamples = 0;
834  vector<WFace *> wFaces;
835  WFace *wFace = nullptr;
836  unsigned tmpQI = 0;
837  unsigned qiClasses[256];
838  unsigned maxIndex, maxCard;
839  unsigned qiMajority;
840  bool even_test;
841  for (vector<ViewEdge *>::iterator ve = vedges.begin(), veend = vedges.end(); ve != veend; ve++) {
842  // Find an edge to test
843  if (!(*ve)->isInImage()) {
844  // This view edge has been proscenium culled
845  (*ve)->setQI(255);
846  (*ve)->setaShape(nullptr);
847  continue;
848  }
849 
850  // Test edge
851  festart = (*ve)->fedgeA();
852  fe = (*ve)->fedgeA();
853 
854  even_test = true;
855  qiMajority = 0;
856  do {
857  if (even_test && fe && fe->isInImage()) {
858  qiMajority++;
859  even_test = !even_test;
860  }
861  fe = fe->nextEdge();
862  } while (fe && fe != festart);
863 
864  if (qiMajority == 0) {
865  // There are no occludable FEdges on this ViewEdge
866  // This should be impossible.
868  cout << "View Edge in viewport without occludable FEdges: " << (*ve)->getId() << endl;
869  }
870  // We can recover from this error:
871  // Treat this edge as fully visible with no occludee
872  (*ve)->setQI(0);
873  (*ve)->setaShape(nullptr);
874  continue;
875  }
876 
877  ++qiMajority;
878  qiMajority >>= 1;
879 
880  even_test = true;
881  maxIndex = 0;
882  maxCard = 0;
883  nSamples = 0;
884  memset(qiClasses, 0, 256 * sizeof(*qiClasses));
885  set<ViewShape *> foundOccluders;
886 
887  fe = (*ve)->fedgeA();
888  do {
889  if (!fe || !fe->isInImage()) {
890  fe = fe->nextEdge();
891  continue;
892  }
893  if (even_test) {
894  if ((maxCard < qiMajority)) {
895  // ARB: change &wFace to wFace and use reference in called function
896  tmpQI = computeVisibility<G, I>(
897  ioViewMap, fe, grid, epsilon, *ve, &wFace, &foundOccluders);
898 
899  // ARB: This is an error condition, not an alert condition.
900  // Some sort of recovery or abort is necessary.
901  if (tmpQI >= 256) {
902  cerr << "Warning: too many occluding levels" << endl;
903  // ARB: Wild guess: instead of aborting or corrupting memory, treat as tmpQI == 255
904  tmpQI = 255;
905  }
906 
907  if (++qiClasses[tmpQI] > maxCard) {
908  maxCard = qiClasses[tmpQI];
909  maxIndex = tmpQI;
910  }
911  }
912  else {
913  // ARB: FindOccludee is redundant if ComputeRayCastingVisibility has been called
914  // ARB: change &wFace to wFace and use reference in called function
915  findOccludee<G, I>(fe, grid, epsilon, *ve, &wFace);
916  }
917 
918  if (wFace) {
919  vector<Vec3r> vertices;
920  for (int i = 0, numEdges = wFace->numberOfEdges(); i < numEdges; ++i) {
921  vertices.emplace_back(wFace->GetVertex(i)->GetVertex());
922  }
923  Polygon3r poly(vertices, wFace->GetNormal());
924  poly.userdata = (void *)wFace;
925  fe->setaFace(poly);
926  wFaces.push_back(wFace);
927  }
928  ++nSamples;
929  }
930 
931  even_test = !even_test;
932  fe = fe->nextEdge();
933  } while ((maxCard < qiMajority) && (fe) && (fe != festart));
934 
935  // qi --
936  (*ve)->setQI(maxIndex);
937 
938  // occluders --
939  for (set<ViewShape *>::iterator o = foundOccluders.begin(), oend = foundOccluders.end();
940  o != oend;
941  ++o) {
942  (*ve)->AddOccluder((*o));
943  }
944 
945  // occludee --
946  if (!wFaces.empty()) {
947  if (wFaces.size() < nSamples / 2) {
948  (*ve)->setaShape(nullptr);
949  }
950  else {
951  ViewShape *vshape = ioViewMap->viewShape(
952  (*wFaces.begin())->GetVertex(0)->shape()->GetId());
953  (*ve)->setaShape(vshape);
954  }
955  }
956 
957  wFaces.clear();
958  }
959 }
960 
961 template<typename G, typename I>
962 static void computeVeryFastVisibility(ViewMap *ioViewMap, G &grid, real epsilon)
963 {
964  vector<ViewEdge *> &vedges = ioViewMap->ViewEdges();
965 
966  FEdge *fe;
967  unsigned qi = 0;
968  WFace *wFace = nullptr;
969 
970  for (vector<ViewEdge *>::iterator ve = vedges.begin(), veend = vedges.end(); ve != veend; ve++) {
971  // Find an edge to test
972  if (!(*ve)->isInImage()) {
973  // This view edge has been proscenium culled
974  (*ve)->setQI(255);
975  (*ve)->setaShape(nullptr);
976  continue;
977  }
978  fe = (*ve)->fedgeA();
979  // Find a FEdge inside the occluder proscenium to test for visibility
980  FEdge *festart = fe;
981  while (fe && !fe->isInImage() && fe != festart) {
982  fe = fe->nextEdge();
983  }
984 
985  // Test edge
986  if (!fe || !fe->isInImage()) {
987  // There are no occludable FEdges on this ViewEdge
988  // This should be impossible.
990  cout << "View Edge in viewport without occludable FEdges: " << (*ve)->getId() << endl;
991  }
992  // We can recover from this error:
993  // Treat this edge as fully visible with no occludee
994  qi = 0;
995  wFace = nullptr;
996  }
997  else {
998  qi = computeVisibility<G, I>(ioViewMap, fe, grid, epsilon, *ve, &wFace, NULL);
999  }
1000 
1001  // Store test results
1002  if (wFace) {
1003  vector<Vec3r> vertices;
1004  for (int i = 0, numEdges = wFace->numberOfEdges(); i < numEdges; ++i) {
1005  vertices.emplace_back(wFace->GetVertex(i)->GetVertex());
1006  }
1007  Polygon3r poly(vertices, wFace->GetNormal());
1008  poly.userdata = (void *)wFace;
1009  fe->setaFace(poly); // This works because setaFace *copies* the polygon
1010  ViewShape *vshape = ioViewMap->viewShape(wFace->GetVertex(0)->shape()->GetId());
1011  (*ve)->setaShape(vshape);
1012  }
1013  else {
1014  (*ve)->setaShape(nullptr);
1015  }
1016  (*ve)->setQI(qi);
1017  }
1018 }
1019 
1020 void ViewMapBuilder::BuildGrid(WingedEdge &we, const BBox<Vec3r> &bbox, unsigned int sceneNumFaces)
1021 {
1022  _Grid->clear();
1023  Vec3r size;
1024  for (unsigned int i = 0; i < 3; i++) {
1025  size[i] = fabs(bbox.getMax()[i] - bbox.getMin()[i]);
1026  // let make the grid 1/10 bigger to avoid numerical errors while computing triangles/cells
1027  // intersections.
1028  size[i] += size[i] / 10.0;
1029  if (size[i] == 0) {
1031  cout << "Warning: the bbox size is 0 in dimension " << i << endl;
1032  }
1033  }
1034  }
1035  _Grid->configure(Vec3r(bbox.getMin() - size / 20.0), size, sceneNumFaces);
1036 
1037  // Fill in the grid:
1038  WFillGrid fillGridRenderer(_Grid, &we);
1039  fillGridRenderer.fillGrid();
1040 
1041  // DEBUG
1042  _Grid->displayDebug();
1043 }
1044 
1046  visibility_algo iAlgo,
1047  real epsilon,
1048  const BBox<Vec3r> &bbox,
1049  unsigned int sceneNumFaces)
1050 {
1051  _ViewMap = new ViewMap;
1052  _currentId = 1;
1053  _currentFId = 0;
1054  _currentSVertexId = 0;
1055 
1056  // Builds initial view edges
1057  computeInitialViewEdges(we);
1058 
1059  // Detects cusps
1060  computeCusps(_ViewMap);
1061 
1062  // Compute intersections
1063  ComputeIntersections(_ViewMap, sweep_line, epsilon);
1064 
1065  // Compute visibility
1066  ComputeEdgesVisibility(_ViewMap, we, bbox, sceneNumFaces, iAlgo, epsilon);
1067 
1068  return _ViewMap;
1069 }
1070 
1071 static inline real distance2D(const Vec3r &point, const real origin[2])
1072 {
1073  return ::hypot((point[0] - origin[0]), (point[1] - origin[1]));
1074 }
1075 
1076 static inline bool crossesProscenium(real proscenium[4], FEdge *fe)
1077 {
1078  Vec2r min(proscenium[0], proscenium[2]);
1079  Vec2r max(proscenium[1], proscenium[3]);
1080  Vec2r A(fe->vertexA()->getProjectedX(), fe->vertexA()->getProjectedY());
1081  Vec2r B(fe->vertexB()->getProjectedX(), fe->vertexB()->getProjectedY());
1082 
1084 }
1085 
1086 static inline bool insideProscenium(const real proscenium[4], const Vec3r &point)
1087 {
1088  return !(point[0] < proscenium[0] || point[0] > proscenium[1] || point[1] < proscenium[2] ||
1089  point[1] > proscenium[3]);
1090 }
1091 
1093  real viewProscenium[4],
1094  real occluderProscenium[4],
1095  bool extensiveFEdgeSearch)
1096 {
1097  // Cull view edges by marking them as non-displayable.
1098  // This avoids the complications of trying to delete edges from the ViewMap.
1099 
1100  // Non-displayable view edges will be skipped over during visibility calculation.
1101 
1102  // View edges will be culled according to their position w.r.t. the viewport proscenium (viewport
1103  // + 5% border, or some such).
1104 
1105  // Get proscenium boundary for culling
1106  GridHelpers::getDefaultViewProscenium(viewProscenium);
1107  real prosceniumOrigin[2];
1108  prosceniumOrigin[0] = (viewProscenium[1] - viewProscenium[0]) / 2.0;
1109  prosceniumOrigin[1] = (viewProscenium[3] - viewProscenium[2]) / 2.0;
1111  cout << "Proscenium culling:" << endl;
1112  cout << "Proscenium: [" << viewProscenium[0] << ", " << viewProscenium[1] << ", "
1113  << viewProscenium[2] << ", " << viewProscenium[3] << "]" << endl;
1114  cout << "Origin: [" << prosceniumOrigin[0] << ", " << prosceniumOrigin[1] << "]" << endl;
1115  }
1116 
1117  // A separate occluder proscenium will also be maintained, starting out the same as the viewport
1118  // proscenium, and expanding as necessary so that it encompasses the center point of at least one
1119  // feature edge in each retained view edge. The occluder proscenium will be used later to cull
1120  // occluding triangles before they are inserted into the Grid. The occluder proscenium starts out
1121  // the same size as the view proscenium
1122  GridHelpers::getDefaultViewProscenium(occluderProscenium);
1123 
1124  // N.B. Freestyle is inconsistent in its use of ViewMap::viewedges_container and
1125  // vector<ViewEdge*>::iterator. Probably all occurrences of vector<ViewEdge*>::iterator should be
1126  // replaced ViewMap::viewedges_container throughout the code. For each view edge
1127  ViewMap::viewedges_container::iterator ve, veend;
1128 
1129  for (ve = ioViewMap->ViewEdges().begin(), veend = ioViewMap->ViewEdges().end(); ve != veend;
1130  ve++) {
1131  // Overview:
1132  // Search for a visible feature edge
1133  // If none: mark view edge as non-displayable
1134  // Otherwise:
1135  // Find a feature edge with center point inside occluder proscenium.
1136  // If none exists, find the feature edge with center point closest to viewport origin.
1137  // Expand occluder proscenium to enclose center point.
1138 
1139  // For each feature edge, while bestOccluderTarget not found and view edge not visible
1140  bool bestOccluderTargetFound = false;
1141  FEdge *bestOccluderTarget = nullptr;
1142  real bestOccluderDistance = 0.0;
1143  FEdge *festart = (*ve)->fedgeA();
1144  FEdge *fe = festart;
1145  // All ViewEdges start culled
1146  (*ve)->setIsInImage(false);
1147 
1148  // For simple visibility calculation: mark a feature edge that is known to have a center point
1149  // inside the occluder proscenium. Cull all other feature edges.
1150  do {
1151  // All FEdges start culled
1152  fe->setIsInImage(false);
1153 
1154  // Look for the visible edge that can most easily be included in the occluder proscenium.
1155  if (!bestOccluderTargetFound) {
1156  // If center point is inside occluder proscenium,
1157  if (insideProscenium(occluderProscenium, fe->center2d())) {
1158  // Use this feature edge for visibility deterimination
1159  fe->setIsInImage(true);
1160  // Mark bestOccluderTarget as found
1161  bestOccluderTargetFound = true;
1162  bestOccluderTarget = fe;
1163  }
1164  else {
1165  real d = distance2D(fe->center2d(), prosceniumOrigin);
1166  // If center point is closer to viewport origin than current target
1167  if (bestOccluderTarget == nullptr || d < bestOccluderDistance) {
1168  // Then store as bestOccluderTarget
1169  bestOccluderDistance = d;
1170  bestOccluderTarget = fe;
1171  }
1172  }
1173  }
1174 
1175  // If feature edge crosses the view proscenium
1176  if (!(*ve)->isInImage() && crossesProscenium(viewProscenium, fe)) {
1177  // Then the view edge will be included in the image
1178  (*ve)->setIsInImage(true);
1179  }
1180  fe = fe->nextEdge();
1181  } while (fe && fe != festart && !(bestOccluderTargetFound && (*ve)->isInImage()));
1182 
1183  // Either we have run out of FEdges, or we already have the one edge we need to determine
1184  // visibility Cull all remaining edges.
1185  while (fe && fe != festart) {
1186  fe->setIsInImage(false);
1187  fe = fe->nextEdge();
1188  }
1189 
1190  // If bestOccluderTarget was not found inside the occluder proscenium, we need to expand the
1191  // occluder proscenium to include it.
1192  if ((*ve)->isInImage() && bestOccluderTarget != nullptr && !bestOccluderTargetFound) {
1193  // Expand occluder proscenium to enclose bestOccluderTarget
1194  Vec3r point = bestOccluderTarget->center2d();
1195  if (point[0] < occluderProscenium[0]) {
1196  occluderProscenium[0] = point[0];
1197  }
1198  else if (point[0] > occluderProscenium[1]) {
1199  occluderProscenium[1] = point[0];
1200  }
1201  if (point[1] < occluderProscenium[2]) {
1202  occluderProscenium[2] = point[1];
1203  }
1204  else if (point[1] > occluderProscenium[3]) {
1205  occluderProscenium[3] = point[1];
1206  }
1207  // Use bestOccluderTarget for visibility determination
1208  bestOccluderTarget->setIsInImage(true);
1209  }
1210  }
1211 
1212  // We are done calculating the occluder proscenium.
1213  // Expand the occluder proscenium by an epsilon to avoid rounding errors.
1214  const real epsilon = 1.0e-6;
1215  occluderProscenium[0] -= epsilon;
1216  occluderProscenium[1] += epsilon;
1217  occluderProscenium[2] -= epsilon;
1218  occluderProscenium[3] += epsilon;
1219 
1220  // For "Normal" or "Fast" style visibility computation only:
1221 
1222  // For more detailed visibility calculation, make a second pass through the view map, marking all
1223  // feature edges with center points inside the final occluder proscenium. All of these feature
1224  // edges can be considered during visibility calculation.
1225 
1226  // So far we have only found one FEdge per ViewEdge. The "Normal" and "Fast" styles of
1227  // visibility computation want to consider many FEdges for each ViewEdge. Here we re-scan the
1228  // view map to find any usable FEdges that we skipped on the first pass, or that have become
1229  // usable because the occluder proscenium has been expanded since the edge was visited on the
1230  // first pass.
1231  if (extensiveFEdgeSearch) {
1232  // For each view edge,
1233  for (ve = ioViewMap->ViewEdges().begin(), veend = ioViewMap->ViewEdges().end(); ve != veend;
1234  ve++) {
1235  if (!(*ve)->isInImage()) {
1236  continue;
1237  }
1238  // For each feature edge,
1239  FEdge *festart = (*ve)->fedgeA();
1240  FEdge *fe = festart;
1241  do {
1242  // If not (already) visible and center point inside occluder proscenium,
1243  if (!fe->isInImage() && insideProscenium(occluderProscenium, fe->center2d())) {
1244  // Use the feature edge for visibility determination
1245  fe->setIsInImage(true);
1246  }
1247  fe = fe->nextEdge();
1248  } while (fe && fe != festart);
1249  }
1250  }
1251 }
1252 
1254 {
1255  vector<WShape *> wshapes = we.getWShapes();
1256  SShape *psShape;
1257 
1258  for (vector<WShape *>::const_iterator it = wshapes.begin(); it != wshapes.end(); it++) {
1259  if (_pRenderMonitor && _pRenderMonitor->testBreak()) {
1260  break;
1261  }
1262 
1263  // create the embedding
1264  psShape = new SShape;
1265  psShape->setId((*it)->GetId());
1266  psShape->setName((*it)->getName());
1267  psShape->setLibraryPath((*it)->getLibraryPath());
1268  psShape->setFrsMaterials((*it)->frs_materials()); // FIXME
1269 
1270  // create the view shape
1271  ViewShape *vshape = new ViewShape(psShape);
1272  // add this view shape to the view map:
1273  _ViewMap->AddViewShape(vshape);
1274 
1275  // we want to number the view edges in a unique way for the while scene.
1276  _pViewEdgeBuilder->setCurrentViewId(_currentId);
1277  // we want to number the feature edges in a unique way for the while scene.
1278  _pViewEdgeBuilder->setCurrentFId(_currentFId);
1279  // we want to number the SVertex in a unique way for the while scene.
1280  _pViewEdgeBuilder->setCurrentSVertexId(_currentFId);
1281  _pViewEdgeBuilder->BuildViewEdges(dynamic_cast<WXShape *>(*it),
1282  vshape,
1283  _ViewMap->ViewEdges(),
1284  _ViewMap->ViewVertices(),
1285  _ViewMap->FEdges(),
1286  _ViewMap->SVertices());
1287 
1288  _currentId = _pViewEdgeBuilder->currentViewId() + 1;
1289  _currentFId = _pViewEdgeBuilder->currentFId() + 1;
1290  _currentSVertexId = _pViewEdgeBuilder->currentSVertexId() + 1;
1291 
1292  psShape->ComputeBBox();
1293  }
1294 }
1295 
1297 {
1298  vector<ViewVertex *> newVVertices;
1299  vector<ViewEdge *> newVEdges;
1300  ViewMap::viewedges_container &vedges = ioViewMap->ViewEdges();
1301  ViewMap::viewedges_container::iterator ve = vedges.begin(), veend = vedges.end();
1302  for (; ve != veend; ++ve) {
1303  if (_pRenderMonitor && _pRenderMonitor->testBreak()) {
1304  break;
1305  }
1306  if ((!((*ve)->getNature() & Nature::SILHOUETTE)) || (!((*ve)->fedgeA()->isSmooth()))) {
1307  continue;
1308  }
1309  FEdge *fe = (*ve)->fedgeA();
1310  FEdge *fefirst = fe;
1311  bool first = true;
1312  bool positive = true;
1313  do {
1314  FEdgeSmooth *fes = dynamic_cast<FEdgeSmooth *>(fe);
1315  Vec3r A((fes)->vertexA()->point3d());
1316  Vec3r B((fes)->vertexB()->point3d());
1317  Vec3r AB(B - A);
1318  AB.normalize();
1319  Vec3r m((A + B) / 2.0);
1320  Vec3r crossP(AB ^ (fes)->normal());
1321  crossP.normalize();
1322  Vec3r viewvector;
1323  if (_orthographicProjection) {
1324  viewvector = Vec3r(0.0, 0.0, m.z() - _viewpoint.z());
1325  }
1326  else {
1327  viewvector = Vec3r(m - _viewpoint);
1328  }
1329  viewvector.normalize();
1330  if (first) {
1331  if (((crossP) * (viewvector)) > 0) {
1332  positive = true;
1333  }
1334  else {
1335  positive = false;
1336  }
1337  first = false;
1338  }
1339  // If we're in a positive part, we need a stronger negative value to change
1340  NonTVertex *cusp = nullptr;
1341  if (positive) {
1342  if (((crossP) * (viewvector)) < -0.1) {
1343  // state changes
1344  positive = false;
1345  // creates and insert cusp
1346  cusp = dynamic_cast<NonTVertex *>(
1347  ioViewMap->InsertViewVertex(fes->vertexA(), newVEdges));
1348  if (cusp) {
1349  cusp->setNature(cusp->getNature() | Nature::CUSP);
1350  }
1351  }
1352  }
1353  else {
1354  // If we're in a negative part, we need a stronger negative value to change
1355  if (((crossP) * (viewvector)) > 0.1) {
1356  positive = true;
1357  cusp = dynamic_cast<NonTVertex *>(
1358  ioViewMap->InsertViewVertex(fes->vertexA(), newVEdges));
1359  if (cusp) {
1360  cusp->setNature(cusp->getNature() | Nature::CUSP);
1361  }
1362  }
1363  }
1364  fe = fe->nextEdge();
1365  } while (fe && fe != fefirst);
1366  }
1367  for (ve = newVEdges.begin(), veend = newVEdges.end(); ve != veend; ++ve) {
1368  (*ve)->viewShape()->AddEdge(*ve);
1369  vedges.push_back(*ve);
1370  }
1371 }
1372 
1374  WingedEdge &we,
1375  const BBox<Vec3r> &bbox,
1376  real epsilon,
1377  bool cull,
1378  GridDensityProviderFactory &factory)
1379 {
1381  AutoPtr<OccluderSource> source;
1382 
1383  if (_orthographicProjection) {
1384  transform = std::make_unique<BoxGrid::Transform>();
1385  }
1386  else {
1387  transform = std::make_unique<SphericalGrid::Transform>();
1388  }
1389 
1390  if (cull) {
1391  source = std::make_unique<CulledOccluderSource>(*transform, we, *ioViewMap, true);
1392  }
1393  else {
1394  source = std::make_unique<OccluderSource>(*transform, we);
1395  }
1396 
1397  AutoPtr<GridDensityProvider> density(factory.newGridDensityProvider(*source, bbox, *transform));
1398 
1399  if (_orthographicProjection) {
1400  BoxGrid grid(*source, *density, ioViewMap, _viewpoint, _EnableQI);
1401  computeCumulativeVisibility<BoxGrid, BoxGrid::Iterator>(
1402  ioViewMap, grid, epsilon, _pRenderMonitor);
1403  }
1404  else {
1405  SphericalGrid grid(*source, *density, ioViewMap, _viewpoint, _EnableQI);
1406  computeCumulativeVisibility<SphericalGrid, SphericalGrid::Iterator>(
1407  ioViewMap, grid, epsilon, _pRenderMonitor);
1408  }
1409 }
1410 
1412  WingedEdge &we,
1413  const BBox<Vec3r> &bbox,
1414  real epsilon,
1415  bool cull,
1416  GridDensityProviderFactory &factory)
1417 {
1419  AutoPtr<OccluderSource> source;
1420 
1421  if (_orthographicProjection) {
1422  transform = std::make_unique<BoxGrid::Transform>();
1423  }
1424  else {
1425  transform = std::make_unique<SphericalGrid::Transform>();
1426  }
1427 
1428  if (cull) {
1429  source = std::make_unique<CulledOccluderSource>(*transform, we, *ioViewMap, true);
1430  }
1431  else {
1432  source = std::make_unique<OccluderSource>(*transform, we);
1433  }
1434 
1435  AutoPtr<GridDensityProvider> density(factory.newGridDensityProvider(*source, bbox, *transform));
1436 
1437  if (_orthographicProjection) {
1438  BoxGrid grid(*source, *density, ioViewMap, _viewpoint, _EnableQI);
1439  computeDetailedVisibility<BoxGrid, BoxGrid::Iterator>(
1440  ioViewMap, grid, epsilon, _pRenderMonitor);
1441  }
1442  else {
1443  SphericalGrid grid(*source, *density, ioViewMap, _viewpoint, _EnableQI);
1444  computeDetailedVisibility<SphericalGrid, SphericalGrid::Iterator>(
1445  ioViewMap, grid, epsilon, _pRenderMonitor);
1446  }
1447 }
1448 
1450  WingedEdge &we,
1451  const BBox<Vec3r> &bbox,
1452  unsigned int sceneNumFaces,
1453  visibility_algo iAlgo,
1454  real epsilon)
1455 {
1456 #if 0
1457  iAlgo = ray_casting; // for testing algorithms equivalence
1458 #endif
1459  switch (iAlgo) {
1460  case ray_casting:
1462  cout << "Using ordinary ray casting" << endl;
1463  }
1464  BuildGrid(we, bbox, sceneNumFaces);
1465  ComputeRayCastingVisibility(ioViewMap, epsilon);
1466  break;
1467  case ray_casting_fast:
1469  cout << "Using fast ray casting" << endl;
1470  }
1471  BuildGrid(we, bbox, sceneNumFaces);
1472  ComputeFastRayCastingVisibility(ioViewMap, epsilon);
1473  break;
1474  case ray_casting_very_fast:
1476  cout << "Using very fast ray casting" << endl;
1477  }
1478  BuildGrid(we, bbox, sceneNumFaces);
1479  ComputeVeryFastRayCastingVisibility(ioViewMap, epsilon);
1480  break;
1481  case ray_casting_culled_adaptive_traditional:
1483  cout << "Using culled adaptive grid with heuristic density and traditional QI calculation"
1484  << endl;
1485  }
1486  try {
1487  HeuristicGridDensityProviderFactory factory(0.5f, sceneNumFaces);
1488  ComputeDetailedVisibility(ioViewMap, we, bbox, epsilon, true, factory);
1489  }
1490  catch (...) {
1491  // Last resort catch to make sure RAII semantics hold for OptimizedGrid. Can be replaced
1492  // with try...catch block around main() if the program as a whole is converted to RAII
1493 
1494  // This is the little-mentioned caveat of RAII: RAII does not work unless destructors are
1495  // always called, but destructors are only called if all exceptions are caught (or
1496  // std::terminate() is replaced).
1497 
1498  // We don't actually handle the exception here, so re-throw it now that our destructors
1499  // have had a chance to run.
1500  throw;
1501  }
1502  break;
1503  case ray_casting_adaptive_traditional:
1505  cout
1506  << "Using unculled adaptive grid with heuristic density and traditional QI calculation"
1507  << endl;
1508  }
1509  try {
1510  HeuristicGridDensityProviderFactory factory(0.5f, sceneNumFaces);
1511  ComputeDetailedVisibility(ioViewMap, we, bbox, epsilon, false, factory);
1512  }
1513  catch (...) {
1514  throw;
1515  }
1516  break;
1517  case ray_casting_culled_adaptive_cumulative:
1519  cout << "Using culled adaptive grid with heuristic density and cumulative QI calculation"
1520  << endl;
1521  }
1522  try {
1523  HeuristicGridDensityProviderFactory factory(0.5f, sceneNumFaces);
1524  ComputeCumulativeVisibility(ioViewMap, we, bbox, epsilon, true, factory);
1525  }
1526  catch (...) {
1527  throw;
1528  }
1529  break;
1530  case ray_casting_adaptive_cumulative:
1532  cout << "Using unculled adaptive grid with heuristic density and cumulative QI calculation"
1533  << endl;
1534  }
1535  try {
1536  HeuristicGridDensityProviderFactory factory(0.5f, sceneNumFaces);
1537  ComputeCumulativeVisibility(ioViewMap, we, bbox, epsilon, false, factory);
1538  }
1539  catch (...) {
1540  throw;
1541  }
1542  break;
1543  default:
1544  break;
1545  }
1546 }
1547 
1548 static const unsigned gProgressBarMaxSteps = 10;
1549 static const unsigned gProgressBarMinSize = 2000;
1550 
1552 {
1553  vector<ViewEdge *> &vedges = ioViewMap->ViewEdges();
1554  bool progressBarDisplay = false;
1555  unsigned progressBarStep = 0;
1556  unsigned vEdgesSize = vedges.size();
1557  unsigned fEdgesSize = ioViewMap->FEdges().size();
1558 
1559  if (_pProgressBar != nullptr && fEdgesSize > gProgressBarMinSize) {
1560  unsigned progressBarSteps = min(gProgressBarMaxSteps, vEdgesSize);
1561  progressBarStep = vEdgesSize / progressBarSteps;
1562  _pProgressBar->reset();
1563  _pProgressBar->setLabelText("Computing Ray casting Visibility");
1564  _pProgressBar->setTotalSteps(progressBarSteps);
1565  _pProgressBar->setProgress(0);
1566  progressBarDisplay = true;
1567  }
1568 
1569  unsigned counter = progressBarStep;
1570  FEdge *fe, *festart;
1571  int nSamples = 0;
1572  vector<Polygon3r *> aFaces;
1573  Polygon3r *aFace = nullptr;
1574  unsigned tmpQI = 0;
1575  unsigned qiClasses[256];
1576  unsigned maxIndex, maxCard;
1577  unsigned qiMajority;
1578  static unsigned timestamp = 1;
1579  for (vector<ViewEdge *>::iterator ve = vedges.begin(), veend = vedges.end(); ve != veend; ve++) {
1580  if (_pRenderMonitor && _pRenderMonitor->testBreak()) {
1581  break;
1582  }
1583 #if LOGGING
1585  cout << "Processing ViewEdge " << (*ve)->getId() << endl;
1586  }
1587 #endif
1588  festart = (*ve)->fedgeA();
1589  fe = (*ve)->fedgeA();
1590  qiMajority = 1;
1591  do {
1592  qiMajority++;
1593  fe = fe->nextEdge();
1594  } while (fe && fe != festart);
1595  qiMajority >>= 1;
1596 #if LOGGING
1598  cout << "\tqiMajority: " << qiMajority << endl;
1599  }
1600 #endif
1601 
1602  tmpQI = 0;
1603  maxIndex = 0;
1604  maxCard = 0;
1605  nSamples = 0;
1606  fe = (*ve)->fedgeA();
1607  memset(qiClasses, 0, 256 * sizeof(*qiClasses));
1608  set<ViewShape *> occluders;
1609  do {
1610  if ((maxCard < qiMajority)) {
1611  tmpQI = ComputeRayCastingVisibility(fe, _Grid, epsilon, occluders, &aFace, timestamp++);
1612 
1613 #if LOGGING
1615  cout << "\tFEdge: visibility " << tmpQI << endl;
1616  }
1617 #endif
1618  // ARB: This is an error condition, not an alert condition.
1619  // Some sort of recovery or abort is necessary.
1620  if (tmpQI >= 256) {
1621  cerr << "Warning: too many occluding levels" << endl;
1622  // ARB: Wild guess: instead of aborting or corrupting memory, treat as tmpQI == 255
1623  tmpQI = 255;
1624  }
1625 
1626  if (++qiClasses[tmpQI] > maxCard) {
1627  maxCard = qiClasses[tmpQI];
1628  maxIndex = tmpQI;
1629  }
1630  }
1631  else {
1632  // ARB: FindOccludee is redundant if ComputeRayCastingVisibility has been called
1633  FindOccludee(fe, _Grid, epsilon, &aFace, timestamp++);
1634 #if LOGGING
1636  cout << "\tFEdge: occludee only (" << (aFace != NULL ? "found" : "not found") << ")"
1637  << endl;
1638  }
1639 #endif
1640  }
1641 
1642  if (aFace) {
1643  fe->setaFace(*aFace);
1644  aFaces.push_back(aFace);
1645  fe->setOccludeeEmpty(false);
1646 #if LOGGING
1648  cout << "\tFound occludee" << endl;
1649  }
1650 #endif
1651  }
1652  else {
1653  // ARB: We are arbitrarily using the last observed value for occludee (almost always the
1654  // value observed
1655  // for the edge before festart). Is that meaningful?
1656  // ...in fact, _occludeeEmpty seems to be unused.
1657  fe->setOccludeeEmpty(true);
1658  }
1659 
1660  ++nSamples;
1661  fe = fe->nextEdge();
1662  } while ((maxCard < qiMajority) && (fe) && (fe != festart));
1663 #if LOGGING
1665  cout << "\tFinished with " << nSamples << " samples, maxCard = " << maxCard << endl;
1666  }
1667 #endif
1668 
1669  // ViewEdge
1670  // qi --
1671  (*ve)->setQI(maxIndex);
1672  // occluders --
1673  for (set<ViewShape *>::iterator o = occluders.begin(), oend = occluders.end(); o != oend;
1674  ++o) {
1675  (*ve)->AddOccluder((*o));
1676  }
1677 #if LOGGING
1679  cout << "\tConclusion: QI = " << maxIndex << ", " << (*ve)->occluders_size() << " occluders."
1680  << endl;
1681  }
1682 #endif
1683  // occludee --
1684  if (!aFaces.empty()) {
1685  if (aFaces.size() <= (float)nSamples / 2.0f) {
1686  (*ve)->setaShape(nullptr);
1687  }
1688  else {
1689  vector<Polygon3r *>::iterator p = aFaces.begin();
1690  WFace *wface = (WFace *)((*p)->userdata);
1691  ViewShape *vshape = ioViewMap->viewShape(wface->GetVertex(0)->shape()->GetId());
1692  ++p;
1693  (*ve)->setaShape(vshape);
1694  }
1695  }
1696 
1697  if (progressBarDisplay) {
1698  counter--;
1699  if (counter <= 0) {
1700  counter = progressBarStep;
1701  _pProgressBar->setProgress(_pProgressBar->getProgress() + 1);
1702  }
1703  }
1704  aFaces.clear();
1705  }
1706 }
1707 
1709 {
1710  vector<ViewEdge *> &vedges = ioViewMap->ViewEdges();
1711  bool progressBarDisplay = false;
1712  unsigned progressBarStep = 0;
1713  unsigned vEdgesSize = vedges.size();
1714  unsigned fEdgesSize = ioViewMap->FEdges().size();
1715 
1716  if (_pProgressBar != nullptr && fEdgesSize > gProgressBarMinSize) {
1717  unsigned progressBarSteps = min(gProgressBarMaxSteps, vEdgesSize);
1718  progressBarStep = vEdgesSize / progressBarSteps;
1719  _pProgressBar->reset();
1720  _pProgressBar->setLabelText("Computing Ray casting Visibility");
1721  _pProgressBar->setTotalSteps(progressBarSteps);
1722  _pProgressBar->setProgress(0);
1723  progressBarDisplay = true;
1724  }
1725 
1726  unsigned counter = progressBarStep;
1727  FEdge *fe, *festart;
1728  unsigned nSamples = 0;
1729  vector<Polygon3r *> aFaces;
1730  Polygon3r *aFace = nullptr;
1731  unsigned tmpQI = 0;
1732  unsigned qiClasses[256];
1733  unsigned maxIndex, maxCard;
1734  unsigned qiMajority;
1735  static unsigned timestamp = 1;
1736  bool even_test;
1737  for (vector<ViewEdge *>::iterator ve = vedges.begin(), veend = vedges.end(); ve != veend; ve++) {
1738  if (_pRenderMonitor && _pRenderMonitor->testBreak()) {
1739  break;
1740  }
1741 
1742  festart = (*ve)->fedgeA();
1743  fe = (*ve)->fedgeA();
1744  qiMajority = 1;
1745  do {
1746  qiMajority++;
1747  fe = fe->nextEdge();
1748  } while (fe && fe != festart);
1749  if (qiMajority >= 4) {
1750  qiMajority >>= 2;
1751  }
1752  else {
1753  qiMajority = 1;
1754  }
1755 
1756  set<ViewShape *> occluders;
1757 
1758  even_test = true;
1759  maxIndex = 0;
1760  maxCard = 0;
1761  nSamples = 0;
1762  memset(qiClasses, 0, 256 * sizeof(*qiClasses));
1763  fe = (*ve)->fedgeA();
1764  do {
1765  if (even_test) {
1766  if ((maxCard < qiMajority)) {
1767  tmpQI = ComputeRayCastingVisibility(fe, _Grid, epsilon, occluders, &aFace, timestamp++);
1768 
1769  // ARB: This is an error condition, not an alert condition.
1770  // Some sort of recovery or abort is necessary.
1771  if (tmpQI >= 256) {
1772  cerr << "Warning: too many occluding levels" << endl;
1773  // ARB: Wild guess: instead of aborting or corrupting memory, treat as tmpQI == 255
1774  tmpQI = 255;
1775  }
1776 
1777  if (++qiClasses[tmpQI] > maxCard) {
1778  maxCard = qiClasses[tmpQI];
1779  maxIndex = tmpQI;
1780  }
1781  }
1782  else {
1783  // ARB: FindOccludee is redundant if ComputeRayCastingVisibility has been called
1784  FindOccludee(fe, _Grid, epsilon, &aFace, timestamp++);
1785  }
1786 
1787  if (aFace) {
1788  fe->setaFace(*aFace);
1789  aFaces.push_back(aFace);
1790  }
1791  ++nSamples;
1792  even_test = false;
1793  }
1794  else {
1795  even_test = true;
1796  }
1797  fe = fe->nextEdge();
1798  } while ((maxCard < qiMajority) && (fe) && (fe != festart));
1799 
1800  (*ve)->setQI(maxIndex);
1801 
1802  if (!aFaces.empty()) {
1803  if (aFaces.size() < nSamples / 2) {
1804  (*ve)->setaShape(nullptr);
1805  }
1806  else {
1807  vector<Polygon3r *>::iterator p = aFaces.begin();
1808  WFace *wface = (WFace *)((*p)->userdata);
1809  ViewShape *vshape = ioViewMap->viewShape(wface->GetVertex(0)->shape()->GetId());
1810  ++p;
1811 #if 0
1812  for (; p != pend; ++p) {
1813  WFace *f = (WFace *)((*p)->userdata);
1814  ViewShape *vs = ioViewMap->viewShape(f->GetVertex(0)->shape()->GetId());
1815  if (vs != vshape) {
1816  sameShape = false;
1817  break;
1818  }
1819  }
1820  if (sameShape)
1821 #endif
1822  {
1823  (*ve)->setaShape(vshape);
1824  }
1825  }
1826  }
1827 
1828  //(*ve)->setaFace(aFace);
1829 
1830  if (progressBarDisplay) {
1831  counter--;
1832  if (counter <= 0) {
1833  counter = progressBarStep;
1834  _pProgressBar->setProgress(_pProgressBar->getProgress() + 1);
1835  }
1836  }
1837  aFaces.clear();
1838  }
1839 }
1840 
1842 {
1843  vector<ViewEdge *> &vedges = ioViewMap->ViewEdges();
1844  bool progressBarDisplay = false;
1845  unsigned progressBarStep = 0;
1846  unsigned vEdgesSize = vedges.size();
1847  unsigned fEdgesSize = ioViewMap->FEdges().size();
1848 
1849  if (_pProgressBar != nullptr && fEdgesSize > gProgressBarMinSize) {
1850  unsigned progressBarSteps = min(gProgressBarMaxSteps, vEdgesSize);
1851  progressBarStep = vEdgesSize / progressBarSteps;
1852  _pProgressBar->reset();
1853  _pProgressBar->setLabelText("Computing Ray casting Visibility");
1854  _pProgressBar->setTotalSteps(progressBarSteps);
1855  _pProgressBar->setProgress(0);
1856  progressBarDisplay = true;
1857  }
1858 
1859  unsigned counter = progressBarStep;
1860  FEdge *fe;
1861  unsigned qi = 0;
1862  Polygon3r *aFace = nullptr;
1863  static unsigned timestamp = 1;
1864  for (vector<ViewEdge *>::iterator ve = vedges.begin(), veend = vedges.end(); ve != veend; ve++) {
1865  if (_pRenderMonitor && _pRenderMonitor->testBreak()) {
1866  break;
1867  }
1868 
1869  set<ViewShape *> occluders;
1870 
1871  fe = (*ve)->fedgeA();
1872  qi = ComputeRayCastingVisibility(fe, _Grid, epsilon, occluders, &aFace, timestamp++);
1873  if (aFace) {
1874  fe->setaFace(*aFace);
1875  WFace *wface = (WFace *)(aFace->userdata);
1876  ViewShape *vshape = ioViewMap->viewShape(wface->GetVertex(0)->shape()->GetId());
1877  (*ve)->setaShape(vshape);
1878  }
1879  else {
1880  (*ve)->setaShape(nullptr);
1881  }
1882 
1883  (*ve)->setQI(qi);
1884 
1885  if (progressBarDisplay) {
1886  counter--;
1887  if (counter <= 0) {
1888  counter = progressBarStep;
1889  _pProgressBar->setProgress(_pProgressBar->getProgress() + 1);
1890  }
1891  }
1892  }
1893 }
1894 
1896  Grid *iGrid,
1897  real epsilon,
1898  Polygon3r **oaPolygon,
1899  unsigned timestamp,
1900  Vec3r &u,
1901  Vec3r &A,
1902  Vec3r &origin,
1903  Vec3r &edgeDir,
1904  vector<WVertex *> &faceVertices)
1905 {
1906  WFace *face = nullptr;
1907  if (fe->isSmooth()) {
1908  FEdgeSmooth *fes = dynamic_cast<FEdgeSmooth *>(fe);
1909  face = (WFace *)fes->face();
1910  }
1911  OccludersSet occluders;
1912  WFace *oface;
1913  bool skipFace;
1914 
1916  OccludersSet::iterator p, pend;
1917 
1918  *oaPolygon = nullptr;
1919  if (((fe)->getNature() & Nature::SILHOUETTE) || ((fe)->getNature() & Nature::BORDER)) {
1920  occluders.clear();
1921  // we cast a ray from A in the same direction but looking behind
1922  Vec3r v(-u[0], -u[1], -u[2]);
1923  iGrid->castInfiniteRay(A, v, occluders, timestamp);
1924 
1925  bool noIntersection = true;
1926  real mint = FLT_MAX;
1927  // we met some occluders, let us fill the aShape field with the first intersected occluder
1928  for (p = occluders.begin(), pend = occluders.end(); p != pend; p++) {
1929  // check whether the edge and the polygon plane are coincident:
1930  //-------------------------------------------------------------
1931  // first let us compute the plane equation.
1932  oface = (WFace *)(*p)->userdata;
1933  Vec3r v1(((*p)->getVertices())[0]);
1934  Vec3r normal((*p)->getNormal());
1935  real d = -(v1 * normal);
1936  real t, t_u, t_v;
1937 
1938  if (face) {
1939  skipFace = false;
1940 
1941  if (face == oface) {
1942  continue;
1943  }
1944 
1945  if (faceVertices.empty()) {
1946  continue;
1947  }
1948 
1949  for (vector<WVertex *>::iterator fv = faceVertices.begin(), fvend = faceVertices.end();
1950  fv != fvend;
1951  ++fv) {
1952  if ((*fv)->isBoundary()) {
1953  continue;
1954  }
1955  WVertex::incoming_edge_iterator iebegin = (*fv)->incoming_edges_begin();
1956  WVertex::incoming_edge_iterator ieend = (*fv)->incoming_edges_end();
1957  for (ie = iebegin; ie != ieend; ++ie) {
1958  if ((*ie) == nullptr) {
1959  continue;
1960  }
1961 
1962  WFace *sface = (*ie)->GetbFace();
1963  if (sface == oface) {
1964  skipFace = true;
1965  break;
1966  }
1967  }
1968  if (skipFace) {
1969  break;
1970  }
1971  }
1972  if (skipFace) {
1973  continue;
1974  }
1975  }
1976  else {
1977  if (GeomUtils::COINCIDENT ==
1978  GeomUtils::intersectRayPlane(origin, edgeDir, normal, d, t, epsilon)) {
1979  continue;
1980  }
1981  }
1982  if ((*p)->rayIntersect(A, v, t, t_u, t_v)) {
1983  if (fabs(v * normal) > 0.0001) {
1984  if (t > 0.0) { // && t < 1.0) {
1985  if (t < mint) {
1986  *oaPolygon = (*p);
1987  mint = t;
1988  noIntersection = false;
1989  fe->setOccludeeIntersection(Vec3r(A + t * v));
1990  }
1991  }
1992  }
1993  }
1994  }
1995 
1996  if (noIntersection) {
1997  *oaPolygon = nullptr;
1998  }
1999  }
2000 }
2001 
2003  FEdge *fe, Grid *iGrid, real epsilon, Polygon3r **oaPolygon, unsigned timestamp)
2004 {
2005  OccludersSet occluders;
2006 
2007  Vec3r A;
2008  Vec3r edgeDir;
2009  Vec3r origin;
2010  A = Vec3r(((fe)->vertexA()->point3D() + (fe)->vertexB()->point3D()) / 2.0);
2011  edgeDir = Vec3r((fe)->vertexB()->point3D() - (fe)->vertexA()->point3D());
2012  edgeDir.normalize();
2013  origin = Vec3r((fe)->vertexA()->point3D());
2014  Vec3r u;
2015  if (_orthographicProjection) {
2016  u = Vec3r(0.0, 0.0, _viewpoint.z() - A.z());
2017  }
2018  else {
2019  u = Vec3r(_viewpoint - A);
2020  }
2021  u.normalize();
2022  if (A < iGrid->getOrigin()) {
2023  cerr << "Warning: point is out of the grid for fedge " << fe->getId().getFirst() << "-"
2024  << fe->getId().getSecond() << endl;
2025  }
2026 
2027  vector<WVertex *> faceVertices;
2028 
2029  WFace *face = nullptr;
2030  if (fe->isSmooth()) {
2031  FEdgeSmooth *fes = dynamic_cast<FEdgeSmooth *>(fe);
2032  face = (WFace *)fes->face();
2033  }
2034  if (face) {
2035  face->RetrieveVertexList(faceVertices);
2036  }
2037 
2038  return FindOccludee(
2039  fe, iGrid, epsilon, oaPolygon, timestamp, u, A, origin, edgeDir, faceVertices);
2040 }
2041 
2043  Grid *iGrid,
2044  real epsilon,
2045  set<ViewShape *> &oOccluders,
2046  Polygon3r **oaPolygon,
2047  unsigned timestamp)
2048 {
2049  OccludersSet occluders;
2050  int qi = 0;
2051 
2052  Vec3r center;
2053  Vec3r edgeDir;
2054  Vec3r origin;
2055 
2056  center = fe->center3d();
2057  edgeDir = Vec3r(fe->vertexB()->point3D() - fe->vertexA()->point3D());
2058  edgeDir.normalize();
2059  origin = Vec3r(fe->vertexA()->point3D());
2060  // Is the edge outside the view frustum ?
2061  Vec3r gridOrigin(iGrid->getOrigin());
2062  Vec3r gridExtremity(iGrid->getOrigin() + iGrid->gridSize());
2063 
2064  if ((center.x() < gridOrigin.x()) || (center.y() < gridOrigin.y()) ||
2065  (center.z() < gridOrigin.z()) || (center.x() > gridExtremity.x()) ||
2066  (center.y() > gridExtremity.y()) || (center.z() > gridExtremity.z())) {
2067  cerr << "Warning: point is out of the grid for fedge " << fe->getId() << endl;
2068  // return 0;
2069  }
2070 
2071 #if 0
2072  Vec3r A(fe->vertexA()->point2d());
2073  Vec3r B(fe->vertexB()->point2d());
2074  int viewport[4];
2076  if ((A.x() < viewport[0]) || (A.x() > viewport[2]) || (A.y() < viewport[1]) ||
2077  (A.y() > viewport[3]) || (B.x() < viewport[0]) || (B.x() > viewport[2]) ||
2078  (B.y() < viewport[1]) || (B.y() > viewport[3])) {
2079  cerr << "Warning: point is out of the grid for fedge " << fe->getId() << endl;
2080  //return 0;
2081  }
2082 #endif
2083 
2084  Vec3r vp;
2085  if (_orthographicProjection) {
2086  vp = Vec3r(center.x(), center.y(), _viewpoint.z());
2087  }
2088  else {
2089  vp = Vec3r(_viewpoint);
2090  }
2091  Vec3r u(vp - center);
2092  real raylength = u.norm();
2093  u.normalize();
2094 #if 0
2096  cout << "grid origin " << iGrid->getOrigin().x() << "," << iGrid->getOrigin().y() << ","
2097  << iGrid->getOrigin().z() << endl;
2098  cout << "center " << center.x() << "," << center.y() << "," << center.z() << endl;
2099  }
2100 #endif
2101 
2102  iGrid->castRay(center, vp, occluders, timestamp);
2103 
2104  WFace *face = nullptr;
2105  if (fe->isSmooth()) {
2106  FEdgeSmooth *fes = dynamic_cast<FEdgeSmooth *>(fe);
2107  face = (WFace *)fes->face();
2108  }
2109  vector<WVertex *> faceVertices;
2111 
2112  WFace *oface;
2113  bool skipFace;
2114  OccludersSet::iterator p, pend;
2115  if (face) {
2116  face->RetrieveVertexList(faceVertices);
2117  }
2118 
2119  for (p = occluders.begin(), pend = occluders.end(); p != pend; p++) {
2120  // If we're dealing with an exact silhouette, check whether we must take care of this occluder
2121  // of not. (Indeed, we don't consider the occluders that share at least one vertex with the
2122  // face containing this edge).
2123  //-----------
2124  oface = (WFace *)(*p)->userdata;
2125 #if LOGGING
2127  cout << "\t\tEvaluating intersection for occluder " << ((*p)->getVertices())[0]
2128  << ((*p)->getVertices())[1] << ((*p)->getVertices())[2] << endl
2129  << "\t\t\tand ray " << vp << " * " << u << " (center " << center << ")" << endl;
2130  }
2131 #endif
2132  Vec3r v1(((*p)->getVertices())[0]);
2133  Vec3r normal((*p)->getNormal());
2134  real d = -(v1 * normal);
2135  real t, t_u, t_v;
2136 
2137 #if LOGGING
2139  cout << "\t\tp: " << ((*p)->getVertices())[0] << ((*p)->getVertices())[1]
2140  << ((*p)->getVertices())[2] << ", norm: " << (*p)->getNormal() << endl;
2141  }
2142 #endif
2143 
2144  if (face) {
2145 #if LOGGING
2147  cout << "\t\tDetermining face adjacency...";
2148  }
2149 #endif
2150  skipFace = false;
2151 
2152  if (face == oface) {
2153 #if LOGGING
2155  cout << " Rejecting occluder for face concurrency." << endl;
2156  }
2157 #endif
2158  continue;
2159  }
2160 
2161  for (vector<WVertex *>::iterator fv = faceVertices.begin(), fvend = faceVertices.end();
2162  fv != fvend;
2163  ++fv) {
2164  if ((*fv)->isBoundary()) {
2165  continue;
2166  }
2167 
2168  WVertex::incoming_edge_iterator iebegin = (*fv)->incoming_edges_begin();
2169  WVertex::incoming_edge_iterator ieend = (*fv)->incoming_edges_end();
2170  for (ie = iebegin; ie != ieend; ++ie) {
2171  if ((*ie) == nullptr) {
2172  continue;
2173  }
2174 
2175  WFace *sface = (*ie)->GetbFace();
2176  // WFace *sfacea = (*ie)->GetaFace();
2177  // if ((sface == oface) || (sfacea == oface)) {
2178  if (sface == oface) {
2179  skipFace = true;
2180  break;
2181  }
2182  }
2183  if (skipFace) {
2184  break;
2185  }
2186  }
2187  if (skipFace) {
2188 #if LOGGING
2190  cout << " Rejecting occluder for face adjacency." << endl;
2191  }
2192 #endif
2193  continue;
2194  }
2195  }
2196  else {
2197  // check whether the edge and the polygon plane are coincident:
2198  //-------------------------------------------------------------
2199  // first let us compute the plane equation.
2200 
2201  if (GeomUtils::COINCIDENT ==
2202  GeomUtils::intersectRayPlane(origin, edgeDir, normal, d, t, epsilon)) {
2203 #if LOGGING
2205  cout << "\t\tRejecting occluder for target coincidence." << endl;
2206  }
2207 #endif
2208  continue;
2209  }
2210  }
2211 
2212  if ((*p)->rayIntersect(center, u, t, t_u, t_v)) {
2213 #if LOGGING
2215  cout << "\t\tRay " << vp << " * " << u << " intersects at time " << t << " (raylength is "
2216  << raylength << ")" << endl;
2217  cout << "\t\t(u * normal) == " << (u * normal) << " for normal " << normal << endl;
2218  }
2219 #endif
2220  if (fabs(u * normal) > 0.0001) {
2221  if ((t > 0.0) && (t < raylength)) {
2222 #if LOGGING
2224  cout << "\t\tIs occluder" << endl;
2225  }
2226 #endif
2227  WFace *f = (WFace *)((*p)->userdata);
2228  ViewShape *vshape = _ViewMap->viewShape(f->GetVertex(0)->shape()->GetId());
2229  oOccluders.insert(vshape);
2230  ++qi;
2231  if (!_EnableQI) {
2232  break;
2233  }
2234  }
2235  }
2236  }
2237  }
2238 
2239  // Find occludee
2240  FindOccludee(fe, iGrid, epsilon, oaPolygon, timestamp, u, center, origin, edgeDir, faceVertices);
2241 
2242  return qi;
2243 }
2244 
2246  intersection_algo iAlgo,
2247  real epsilon)
2248 {
2249  switch (iAlgo) {
2250  case sweep_line:
2251  ComputeSweepLineIntersections(ioViewMap, epsilon);
2252  break;
2253  default:
2254  break;
2255  }
2256 #if 0
2258  ViewMap::viewvertices_container &vvertices = ioViewMap->ViewVertices();
2259  for (ViewMap::viewvertices_container::iterator vv = vvertices.begin(), vvend = vvertices.end();
2260  vv != vvend;
2261  ++vv) {
2262  if ((*vv)->getNature() == Nature::T_VERTEX) {
2263  TVertex *tvertex = (TVertex *)(*vv);
2264  cout << "TVertex " << tvertex->getId() << " has :" << endl;
2265  cout << "FrontEdgeA: " << tvertex->frontEdgeA().first << endl;
2266  cout << "FrontEdgeB: " << tvertex->frontEdgeB().first << endl;
2267  cout << "BackEdgeA: " << tvertex->backEdgeA().first << endl;
2268  cout << "BackEdgeB: " << tvertex->backEdgeB().first << endl << endl;
2269  }
2270  }
2271  }
2272 #endif
2273 }
2274 
2277 
2279  {
2280  epsilon = eps;
2281  }
2282 
2284  {
2285  Vec3r A = x->point2D();
2286  Vec3r B = y->point2D();
2287  for (unsigned int i = 0; i < 3; i++) {
2288  if ((fabs(A[i] - B[i])) < epsilon) {
2289  continue;
2290  }
2291  if (A[i] < B[i]) {
2292  return true;
2293  }
2294  if (A[i] > B[i]) {
2295  return false;
2296  }
2297  }
2298  return false;
2299  }
2300 };
2301 
2304 
2307 
2309  {
2310  edge = iEdge;
2311  }
2312 
2314  {
2315  real tx = x->getParameter(edge);
2316  real ty = y->getParameter(edge);
2317  if (tx > ty) {
2318  return true;
2319  }
2320  return false;
2321  }
2322 };
2323 
2324 struct silhouette_binary_rule : public binary_rule<segment, segment> {
2325  bool operator()(segment &s1, segment &s2) override
2326  {
2327  FEdge *f1 = s1.edge();
2328  FEdge *f2 = s2.edge();
2329 
2330  if ((!(((f1)->getNature() & Nature::SILHOUETTE) || ((f1)->getNature() & Nature::BORDER))) &&
2331  (!(((f2)->getNature() & Nature::SILHOUETTE) || ((f2)->getNature() & Nature::BORDER)))) {
2332  return false;
2333  }
2334 
2335  return true;
2336  }
2337 };
2338 
2340 {
2341  vector<SVertex *> &svertices = ioViewMap->SVertices();
2342  bool progressBarDisplay = false;
2343  unsigned sVerticesSize = svertices.size();
2344  unsigned fEdgesSize = ioViewMap->FEdges().size();
2345 #if 0
2347  ViewMap::fedges_container &fedges = ioViewMap->FEdges();
2348  for (ViewMap::fedges_container::const_iterator f = fedges.begin(), end = fedges.end();
2349  f != end;
2350  ++f) {
2351  cout << (*f)->aMaterialIndex() << "-" << (*f)->bMaterialIndex() << endl;
2352  }
2353  }
2354 #endif
2355  unsigned progressBarStep = 0;
2356 
2357  if (_pProgressBar != nullptr && fEdgesSize > gProgressBarMinSize) {
2358  unsigned progressBarSteps = min(gProgressBarMaxSteps, sVerticesSize);
2359  progressBarStep = sVerticesSize / progressBarSteps;
2360  _pProgressBar->reset();
2361  _pProgressBar->setLabelText("Computing Sweep Line Intersections");
2362  _pProgressBar->setTotalSteps(progressBarSteps);
2363  _pProgressBar->setProgress(0);
2364  progressBarDisplay = true;
2365  }
2366 
2367  unsigned counter = progressBarStep;
2368 
2369  sort(svertices.begin(), svertices.end(), less_SVertex2D(epsilon));
2370 
2372 
2373  vector<FEdge *> &ioEdges = ioViewMap->FEdges();
2374 
2375  vector<segment *> segments;
2376 
2377  vector<FEdge *>::iterator fe, fend;
2378 
2379  for (fe = ioEdges.begin(), fend = ioEdges.end(); fe != fend; fe++) {
2380  segment *s = new segment((*fe), (*fe)->vertexA()->point2D(), (*fe)->vertexB()->point2D());
2381  (*fe)->userdata = s;
2382  segments.push_back(s);
2383  }
2384 
2385  vector<segment *> vsegments;
2386  for (vector<SVertex *>::iterator sv = svertices.begin(), svend = svertices.end(); sv != svend;
2387  sv++) {
2388  if (_pRenderMonitor && _pRenderMonitor->testBreak()) {
2389  break;
2390  }
2391 
2392  const vector<FEdge *> &vedges = (*sv)->fedges();
2393 
2394  for (vector<FEdge *>::const_iterator sve = vedges.begin(), sveend = vedges.end();
2395  sve != sveend;
2396  sve++) {
2397  vsegments.push_back((segment *)((*sve)->userdata));
2398  }
2399 
2400  Vec3r evt((*sv)->point2D());
2402  SL.process(evt, vsegments, sbr, epsilon);
2403 
2404  if (progressBarDisplay) {
2405  counter--;
2406  if (counter <= 0) {
2407  counter = progressBarStep;
2408  _pProgressBar->setProgress(_pProgressBar->getProgress() + 1);
2409  }
2410  }
2411  vsegments.clear();
2412  }
2413 
2414  if (_pRenderMonitor && _pRenderMonitor->testBreak()) {
2415  // delete segments
2416  if (!segments.empty()) {
2417  vector<segment *>::iterator s, send;
2418  for (s = segments.begin(), send = segments.end(); s != send; s++) {
2419  delete *s;
2420  }
2421  }
2422  return;
2423  }
2424 
2425  // reset userdata:
2426  for (fe = ioEdges.begin(), fend = ioEdges.end(); fe != fend; fe++) {
2427  (*fe)->userdata = nullptr;
2428  }
2429 
2430  // list containing the new edges resulting from splitting operations.
2431  vector<FEdge *> newEdges;
2432 
2433  // retrieve the intersected edges:
2434  vector<segment *> &iedges = SL.intersectedEdges();
2435  // retrieve the intersections:
2436  vector<intersection *> &intersections = SL.intersections();
2437 
2438  int id = 0;
2439  // create a view vertex for each intersection and linked this one with the intersection object
2440  vector<intersection *>::iterator i, iend;
2441  for (i = intersections.begin(), iend = intersections.end(); i != iend; i++) {
2442  FEdge *fA = (*i)->EdgeA->edge();
2443  FEdge *fB = (*i)->EdgeB->edge();
2444 
2445  Vec3r A1 = fA->vertexA()->point3D();
2446  Vec3r A2 = fA->vertexB()->point3D();
2447  Vec3r B1 = fB->vertexA()->point3D();
2448  Vec3r B2 = fB->vertexB()->point3D();
2449 
2450  Vec3r a1 = fA->vertexA()->point2D();
2451  Vec3r a2 = fA->vertexB()->point2D();
2452  Vec3r b1 = fB->vertexA()->point2D();
2453  Vec3r b2 = fB->vertexB()->point2D();
2454 
2455  real ta = (*i)->tA;
2456  real tb = (*i)->tB;
2457 
2458  if ((ta < -epsilon) || (ta > 1 + epsilon)) {
2459  cerr << "Warning: 2D intersection out of range for edge " << fA->vertexA()->getId() << " - "
2460  << fA->vertexB()->getId() << endl;
2461  }
2462 
2463  if ((tb < -epsilon) || (tb > 1 + epsilon)) {
2464  cerr << "Warning: 2D intersection out of range for edge " << fB->vertexA()->getId() << " - "
2465  << fB->vertexB()->getId() << endl;
2466  }
2467 
2470 
2471  if ((Ta < -epsilon) || (Ta > 1 + epsilon)) {
2472  cerr << "Warning: 3D intersection out of range for edge " << fA->vertexA()->getId() << " - "
2473  << fA->vertexB()->getId() << endl;
2474  }
2475 
2476  if ((Tb < -epsilon) || (Tb > 1 + epsilon)) {
2477  cerr << "Warning: 3D intersection out of range for edge " << fB->vertexA()->getId() << " - "
2478  << fB->vertexB()->getId() << endl;
2479  }
2480 
2481 #if 0
2483  if ((Ta < -epsilon) || (Ta > 1 + epsilon) || (Tb < -epsilon) || (Tb > 1 + epsilon)) {
2484  printf("ta %.12e\n", ta);
2485  printf("tb %.12e\n", tb);
2486  printf("a1 %e, %e -- a2 %e, %e\n", a1[0], a1[1], a2[0], a2[1]);
2487  printf("b1 %e, %e -- b2 %e, %e\n", b1[0], b1[1], b2[0], b2[1]);
2488  //printf("line([%e, %e], [%e, %e]);\n", a1[0], a2[0], a1[1], a2[1]);
2489  //printf("line([%e, %e], [%e, %e]);\n", b1[0], b2[0], b1[1], b2[1]);
2490  if ((Ta < -epsilon) || (Ta > 1 + epsilon)) {
2491  printf("Ta %.12e\n", Ta);
2492  }
2493  if ((Tb < -epsilon) || (Tb > 1 + epsilon)) {
2494  printf("Tb %.12e\n", Tb);
2495  }
2496  printf("A1 %e, %e, %e -- A2 %e, %e, %e\n", A1[0], A1[1], A1[2], A2[0], A2[1], A2[2]);
2497  printf("B1 %e, %e, %e -- B2 %e, %e, %e\n", B1[0], B1[1], B1[2], B2[0], B2[1], B2[2]);
2498  }
2499  }
2500 #endif
2501 
2502  TVertex *tvertex = ioViewMap->CreateTVertex(Vec3r(A1 + Ta * (A2 - A1)),
2503  Vec3r(a1 + ta * (a2 - a1)),
2504  fA,
2505  Vec3r(B1 + Tb * (B2 - B1)),
2506  Vec3r(b1 + tb * (b2 - b1)),
2507  fB,
2508  id);
2509 
2510  (*i)->userdata = tvertex;
2511  ++id;
2512  }
2513 
2514  progressBarStep = 0;
2515 
2516  if (progressBarDisplay) {
2517  unsigned iEdgesSize = iedges.size();
2518  unsigned progressBarSteps = min(gProgressBarMaxSteps, iEdgesSize);
2519  progressBarStep = iEdgesSize / progressBarSteps;
2520  _pProgressBar->reset();
2521  _pProgressBar->setLabelText("Splitting intersected edges");
2522  _pProgressBar->setTotalSteps(progressBarSteps);
2523  _pProgressBar->setProgress(0);
2524  }
2525 
2526  counter = progressBarStep;
2527 
2528  vector<TVertex *> edgeVVertices;
2529  vector<ViewEdge *> newVEdges;
2530  vector<segment *>::iterator s, send;
2531  for (s = iedges.begin(), send = iedges.end(); s != send; s++) {
2532  edgeVVertices.clear();
2533  newEdges.clear();
2534  newVEdges.clear();
2535 
2536  FEdge *fedge = (*s)->edge();
2537  ViewEdge *vEdge = fedge->viewedge();
2538  ViewShape *shape = vEdge->viewShape();
2539 
2540  vector<intersection *> &eIntersections = (*s)->intersections();
2541  // we first need to sort these intersections from farther to closer to A
2542  sort(eIntersections.begin(), eIntersections.end(), less_Intersection(*s));
2543  for (i = eIntersections.begin(), iend = eIntersections.end(); i != iend; i++) {
2544  edgeVVertices.push_back((TVertex *)(*i)->userdata);
2545  }
2546 
2547  shape->SplitEdge(fedge, edgeVVertices, ioViewMap->FEdges(), ioViewMap->ViewEdges());
2548 
2549  if (progressBarDisplay) {
2550  counter--;
2551  if (counter <= 0) {
2552  counter = progressBarStep;
2553  _pProgressBar->setProgress(_pProgressBar->getProgress() + 1);
2554  }
2555  }
2556  }
2557 
2558  // reset userdata:
2559  for (fe = ioEdges.begin(), fend = ioEdges.end(); fe != fend; fe++) {
2560  (*fe)->userdata = nullptr;
2561  }
2562 
2563  // delete segments
2564  if (!segments.empty()) {
2565  for (s = segments.begin(), send = segments.end(); s != send; s++) {
2566  delete *s;
2567  }
2568  }
2569 }
2570 
2571 } /* namespace Freestyle */
typedef float(TangentPoint)[2]
@ G_DEBUG_FREESTYLE
Definition: BKE_global.h:140
Class to define a cell grid surrounding the projected image of a scene.
Class to define a cell grid surrounding the projected image of a scene.
NSNotificationCenter * center
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble t
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
Class to define a cell grid surrounding the projected image of a scene.
Class to define a cell grid surrounding the projected image of a scene.
#define A2
Definition: RandGen.cpp:38
#define A1
Definition: RandGen.cpp:37
Class to define a cell grid surrounding the projected image of a scene.
#define LOGGING
Class to build silhouette edges from a Winged-Edge structure.
ATTR_WARN_UNUSED_RESULT const BMVert * v
#define A
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
void sort(btMatrix3x3 &U, btVector3 &sigma, btMatrix3x3 &V, int t)
Helper function of 3X3 SVD for sorting singular values.
SIMD_FORCE_INLINE btVector3 & getOrigin()
Return the origin vector translation.
Definition: btTransform.h:113
const Point & getMax() const
Definition: BBox.h:86
const Point & getMin() const
Definition: BBox.h:81
void * face() const
Definition: Silhouette.h:1354
virtual Id getId() const
Definition: Silhouette.h:497
void setOccludeeEmpty(bool iempty)
Definition: Silhouette.h:812
Vec3r center2d()
Definition: Silhouette.h:682
int occluders_size() const
Definition: Silhouette.cpp:273
SVertex * vertexA()
Definition: Silhouette.h:611
ViewEdge * viewedge() const
Definition: Silhouette.h:672
bool isInImage() const
Definition: Silhouette.h:725
SVertex * vertexB()
Definition: Silhouette.h:617
Vec3r center3d()
Definition: Silhouette.h:677
void setIsInImage(bool iFlag)
Definition: Silhouette.h:825
bool isSmooth() const
Definition: Silhouette.h:720
void setaFace(Polygon3r &iFace)
Definition: Silhouette.h:802
FEdge * nextEdge()
Definition: Silhouette.h:637
void setOccludeeIntersection(const Vec3r &iPoint)
Definition: Silhouette.h:807
bool rayIntersect(const Vec3r &orig, const Vec3r &dir, real &t, real &u, real &v, real epsilon=M_EPSILON) const
Definition: Polygon.h:209
const vector< Point > & getVertices() const
Definition: Polygon.h:81
unsigned getId() const
Definition: Polygon.h:109
virtual AutoPtr< GridDensityProvider > newGridDensityProvider(OccluderSource &source, const real proscenium[4])=0
Vec3r gridSize() const
Definition: Grid.h:340
const Vec3r & getOrigin() const
Definition: Grid.h:335
void castInfiniteRay(const Vec3r &orig, const Vec3r &dir, OccludersSet &occluders, unsigned timestamp)
Definition: Grid.cpp:307
void castRay(const Vec3r &orig, const Vec3r &end, OccludersSet &occluders, unsigned timestamp)
Definition: Grid.cpp:297
id_type getFirst() const
Definition: Id.h:76
id_type getSecond() const
Definition: Id.h:82
void setInfo(string info)
Definition: RenderMonitor.h:43
void setId(Id id)
Definition: Silhouette.h:1921
void setFrsMaterials(const vector< FrsMaterial > &iMaterials)
Definition: Silhouette.h:1939
void setLibraryPath(const string &path)
Definition: Silhouette.h:1933
void setName(const string &name)
Definition: Silhouette.h:1927
const Vec3r & point2d() const
Definition: Silhouette.h:409
const Vec3r & point3D() const
Definition: Silhouette.h:237
virtual Id getId() const
Definition: Silhouette.h:131
const Vec3r & point2D() const
Definition: Silhouette.h:242
virtual real getProjectedY() const
Definition: Silhouette.h:110
virtual real getProjectedX() const
Definition: Silhouette.h:104
static real ImageToWorldParameter(FEdge *fe, real t)
static void retrieveViewport(int viewport[4])
vector< Intersection< Segment< T, Point > > * > & intersections()
Definition: SweepLine.h:332
void process(Point &p, vector< Segment< T, Point > * > &segments, binary_rule< Segment< T, Point >, Segment< T, Point >> &binrule, real epsilon=M_EPSILON)
Definition: SweepLine.h:228
vector< Segment< T, Point > * > & intersectedEdges()
Definition: SweepLine.h:327
directedViewEdge & frontEdgeB()
Definition: ViewMap.h:548
directedViewEdge & frontEdgeA()
Definition: ViewMap.h:543
directedViewEdge & backEdgeB()
Definition: ViewMap.h:558
directedViewEdge & backEdgeA()
Definition: ViewMap.h:553
virtual Id getId() const
Definition: ViewMap.h:455
value_type x() const
Definition: VecMat.h:532
value_type z() const
Definition: VecMat.h:552
value_type y() const
Definition: VecMat.h:542
value_type norm() const
Definition: VecMat.h:109
Vec< T, N > & normalize()
Definition: VecMat.h:119
ViewShape * viewShape()
Definition: ViewMap.h:1101
void ComputeFastRayCastingVisibility(ViewMap *ioViewMap, real epsilon=1.0e-6)
void ComputeCumulativeVisibility(ViewMap *ioViewMap, WingedEdge &we, const BBox< Vec3r > &bbox, real epsilon, bool cull, GridDensityProviderFactory &factory)
void ComputeEdgesVisibility(ViewMap *ioViewMap, WingedEdge &we, const BBox< Vec3r > &bbox, unsigned int sceneNumFaces, visibility_algo iAlgo=ray_casting, real epsilon=1.0e-6)
void FindOccludee(FEdge *fe, Grid *iGrid, real epsilon, Polygon3r **oaPolygon, unsigned timestamp)
void CullViewEdges(ViewMap *ioViewMap, real viewProscenium[4], real occluderProscenium[4], bool extensiveFEdgeSearch=true)
void computeInitialViewEdges(WingedEdge &)
void ComputeRayCastingVisibility(ViewMap *ioViewMap, real epsilon=1.0e-6)
void BuildGrid(WingedEdge &we, const BBox< Vec3r > &bbox, unsigned int sceneNumFaces)
void computeCusps(ViewMap *ioViewMap)
ViewMap * BuildViewMap(WingedEdge &we, visibility_algo iAlgo, real epsilon, const BBox< Vec3r > &bbox, unsigned int sceneNumFaces)
void ComputeIntersections(ViewMap *ioViewMap, intersection_algo iAlgo=sweep_line, real epsilon=1.0e-06)
void ComputeSweepLineIntersections(ViewMap *ioViewMap, real epsilon=1.0e-6)
void ComputeVeryFastRayCastingVisibility(ViewMap *ioViewMap, real epsilon=1.0e-6)
void ComputeDetailedVisibility(ViewMap *ioViewMap, WingedEdge &we, const BBox< Vec3r > &bbox, real epsilon, bool cull, GridDensityProviderFactory &factory)
vector< FEdge * > fedges_container
Definition: ViewMap.h:66
ViewShape * viewShape(unsigned id)
Definition: ViewMap.cpp:90
vector< ViewVertex * > viewvertices_container
Definition: ViewMap.h:63
vector< ViewEdge * > viewedges_container
Definition: ViewMap.h:62
TVertex * CreateTVertex(const Vec3r &iA3D, const Vec3r &iA2D, FEdge *iFEdgeA, const Vec3r &iB3D, const Vec3r &iB2D, FEdge *iFEdgeB, const Id &id)
Definition: ViewMap.cpp:143
svertices_container & SVertices()
Definition: ViewMap.h:135
viewvertices_container & ViewVertices()
Definition: ViewMap.h:123
fedges_container & FEdges()
Definition: ViewMap.h:129
ViewVertex * InsertViewVertex(SVertex *iVertex, vector< ViewEdge * > &newViewEdges)
Definition: ViewMap.cpp:186
viewedges_container & ViewEdges()
Definition: ViewMap.h:117
void SplitEdge(FEdge *fe, const vector< TVertex * > &iViewVertices, vector< FEdge * > &ioNewEdges, vector< ViewEdge * > &ioNewViewEdges)
Definition: ViewMap.h:1650
virtual Nature::VertexNature getNature() const
Definition: ViewMap.h:331
void setNature(Nature::VertexNature iNature)
Definition: ViewMap.h:338
void * userdata
Definition: WEdge.h:750
int numberOfEdges() const
Definition: WEdge.h:926
Vec3f & GetNormal()
Definition: WEdge.h:775
WVertex * GetVertex(unsigned int index)
Definition: WEdge.h:798
const vector< WOEdge * > & getEdgeList()
Definition: WEdge.h:765
void RetrieveVertexList(vector< WVertex * > &oVertices)
Definition: WEdge.h:825
unsigned GetId()
Definition: WEdge.h:1107
Vec3f & GetVertex()
Definition: WEdge.h:87
WShape * shape() const
Definition: WEdge.h:102
vector< WShape * > & getWShapes()
Definition: WEdge.h:1369
IconTextureDrawCall normal
int count
#define B
bool intersect2dSeg2dArea(const Vec2r &min, const Vec2r &max, const Vec2r &A, const Vec2r &B)
Definition: GeomUtils.cpp:29
intersection_test intersectRayPlane(const Vec3r &orig, const Vec3r &dir, const Vec3r &norm, const real d, real &t, const real epsilon)
Definition: GeomUtils.cpp:512
VecMat::Vec3< real > Vec3r
Definition: Geom.h:42
void getDefaultViewProscenium(real viewProscenium[4])
Definition: GridHelpers.cpp:26
static const EdgeNature BORDER
Definition: Nature.h:52
static const VertexNature T_VERTEX
Definition: Nature.h:42
static const VertexNature CUSP
Definition: Nature.h:44
static const EdgeNature SILHOUETTE
Definition: Nature.h:50
inherits from class Rep
Definition: AppCanvas.cpp:32
static void computeDetailedVisibility(ViewMap *ioViewMap, G &grid, real epsilon, RenderMonitor *iRenderMonitor)
static void computeFastVisibility(ViewMap *ioViewMap, G &grid, real epsilon)
static real distance2D(const Vec3r &point, const real origin[2])
static double B1(double u)
Definition: FitCurve.cpp:318
static unsigned x[3]
Definition: RandGen.cpp:87
static const Global & _global
static const unsigned gProgressBarMinSize
static const unsigned gProgressBarMaxSteps
static bool insideProscenium(const real proscenium[4], const Vec3r &point)
static void computeCumulativeVisibility(ViewMap *ioViewMap, G &grid, real epsilon, RenderMonitor *iRenderMonitor)
Segment< FEdge *, Vec3r > segment
static int computeVisibility(ViewMap *viewMap, FEdge *fe, G &grid, real epsilon, ViewEdge *, WFace **oaWFace, set< ViewShape * > *foundOccluders)
vector< Polygon3r * > OccludersSet
Definition: Grid.h:47
static void findOccludee(FEdge *fe, G &, I &occluders, real epsilon, WFace **oaWFace, Vec3r &u, Vec3r &A, Vec3r &origin, Vec3r &edgeDir, vector< WVertex * > &faceVertices)
static double B2(double u)
Definition: FitCurve.cpp:324
static bool crossesProscenium(real proscenium[4], FEdge *fe)
static void computeVeryFastVisibility(ViewMap *ioViewMap, G &grid, real epsilon)
double real
Definition: Precision.h:26
INLINE Rall1d< T, V, S > hypot(const Rall1d< T, V, S > &y, const Rall1d< T, V, S > &x)
Definition: rall1d.h:383
static double epsilon
#define I
const btScalar eps
Definition: poly34.cpp:11
#define min(a, b)
Definition: sort.c:51
bool operator()(intersection *x, intersection *y)
bool operator()(SVertex *x, SVertex *y)
bool operator()(segment &s1, segment &s2) override
int debug
Definition: BKE_global.h:97
float max
ccl_device_inline float2 fabs(const float2 &a)
ccl_device_inline float3 ceil(const float3 &a)
#define G(x, y, z)