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
9
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
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.
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
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
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
void castRay(const Vec3r &orig, const Vec3r &end, OccludersSet &occluders, uint timestamp)
Definition Grid.cpp:287
id_type getFirst() const
Definition Id.h:64
id_type getSecond() const
Definition Id.h:70
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
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
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
void SplitEdge(FEdge *fe, const vector< TVertex * > &iViewVertices, vector< FEdge * > &ioNewEdges, vector< ViewEdge * > &ioNewViewEdges)
Definition ViewMap.h:1640
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
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::Vec2< real > Vec2r
Definition Geom.h:24
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
Intersection< segment > intersection
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