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