2 * This program is free software: you can redistribute it and/or modify
3 * it under the terms of the GNU Lesser General Public License as
4 * published by the Free Software Foundation, either version 3 of the
5 * License, or (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 * @author Bastien Doignies <bastien.doignies@liris.cnrs.fr>
22 * Implementation file for 3D Display
24 * This file is part of the DGtal library.
30 std::vector<std::array<size_t, I>> makeIndices(size_t N) {
31 std::vector<std::array<size_t, I>> indices(N);
33 for (size_t i = 0; i < N; ++i) {
34 for (size_t j = 0; j < I; ++j) {
35 indices[i][j] = j + i * I;
42 std::array<T, 8> getCubeVertices(T center, double size) {
44 center + 0.5 * size * T(-1, -1, -1),
45 center + 0.5 * size * T( 1, -1, -1),
46 center + 0.5 * size * T( 1, 1, -1),
47 center + 0.5 * size * T(-1, 1, -1),
48 center + 0.5 * size * T(-1, -1, 1),
49 center + 0.5 * size * T( 1, -1, 1),
50 center + 0.5 * size * T( 1, 1, 1),
51 center + 0.5 * size * T(-1, 1, 1)
55 template<typename T, typename U>
56 void insertCubeVertices(U& dest, T center, double scale) {
57 auto vertices = getCubeVertices(center, scale);
58 dest.insert(dest.end(), vertices.begin(), vertices.end());
62 std::array<T, 4> getAASquareVertices(T center, int orientation, double size) {
64 case 0: // Normal in x direction
66 center + 0.5 * size * T(0, -1, -1),
67 center + 0.5 * size * T(0, -1, 1),
68 center + 0.5 * size * T(0, 1, 1),
69 center + 0.5 * size * T(0, 1, -1)
71 case 1: // Normal in y direction
73 center + 0.5 * size * T(-1, 0, -1),
74 center + 0.5 * size * T(-1, 0, 1),
75 center + 0.5 * size * T( 1, 0, 1),
76 center + 0.5 * size * T( 1, 0, -1)
78 case 2: // Normal in z direction
81 center + 0.5 * size * T(-1, -1, 0),
82 center + 0.5 * size * T(-1, 1, 0),
83 center + 0.5 * size * T( 1, 1, 0),
84 center + 0.5 * size * T( 1, -1, 0)
89 template<typename U, typename T>
90 void insertAASquare(U& dest, T center, int orientation, double size) {
91 auto vertices = getAASquareVertices(center, orientation, size);
92 dest.insert(dest.end(), vertices.begin(), vertices.end());
96 std::array<T, 8> getPrism(
97 T center, int orientation,
98 double size1, double size2, double shift1, double shift2
100 T dir(0, 0, 0); dir[orientation] = 1;
102 std::array<T, 8> vertices;
103 auto fQuad = getAASquareVertices(center + shift1 * dir, orientation, size1);
104 auto sQuad = getAASquareVertices(center + shift2 * dir, orientation, size2);
106 std::copy(fQuad.begin(), fQuad.end(), vertices.begin());
107 std::copy(sQuad.begin(), sQuad.end(), vertices.begin() + fQuad.size());
111 template<typename T, typename U>
112 void insertPrism(U& dest, T center, int orientation,
113 double scale1, double scale2, double shift1, double shift2) {
114 auto vertices = getPrism(center, orientation, scale1, scale2, shift1, shift2);
115 dest.insert(dest.end(), vertices.begin(), vertices.end());
119 ///////////////////////////////////////////////////////////////////////////
120 ///////////////////////////// GENERAL COMMANDS ////////////////////////////
122 template <typename Space, typename KSpace>
123 void Display3D<Space, KSpace>::clear() {
133 template <typename Space, typename KSpace>
134 void Display3D<Space, KSpace>::setCallback(typename Display3D<Space, KSpace>::Callback* callback) {
135 this->myCallback = callback;
136 if (this->myCallback) {
137 this->myCallback->viewer = this;
138 this->myCallback->OnAttach(this);
142 ///////////////////////////// GENERAL COMMANDS ////////////////////////////
143 ///////////////////////////////////////////////////////////////////////////
145 ///////////////////////////////////////////////////////////////////////////
146 ///////////////////////////// GROUP MANAGEMENT ////////////////////////////
148 template <typename Space, typename KSpace>
149 std::string Display3D<Space, KSpace>::newList(const std::string& name, size_t eSize) {
150 static const std::string token = "{i}";
152 auto it = data.find(name);
153 std::string newName = name;
155 size_t idx = name.find(token);
156 if (it != data.end() || idx != std::string::npos) {
157 std::string prefix = name;
159 if (idx == std::string::npos) {
160 idx = prefix.size() + 1;
161 prefix = prefix + "_" + token;
166 std::string tmpPrefix = prefix;
167 newName = tmpPrefix.replace(idx, token.size(), std::to_string(i));
170 } while (data.find(newName) != data.end());
173 // Insert a new empty container
174 DisplayData<RealPoint> newData;
177 newData.style = currentStyle;
178 newData.elementSize = eSize;
180 myCurrentData = &data.emplace(newName, std::move(newData)).first->second;
181 myCurrentName = newName;
182 // Add to render queue
183 myToRender.push_back(myCurrentName);
184 // Return computed name
188 template <typename Space, typename KSpace>
189 bool Display3D<Space, KSpace>::setCurrentList(const std::string& name) {
190 auto it = data.find(name);
191 if (it == data.end())
194 myCurrentData = &it->second;
195 myCurrentName = name;
199 template <typename Space, typename KSpace>
200 bool Display3D<Space, KSpace>::canCreateNewList(size_t elementSize) const {
201 if (!myCurrentData) return true;
202 if (myCurrentData->elementSize != elementSize) return true;
203 return !allowReuseList;
206 template <typename Space, typename KSpace>
207 std::string Display3D<Space, KSpace>::createOrReuseList(const std::string& name, size_t elementSize) {
208 if (canCreateNewList(elementSize)) {
209 return newList(name, elementSize);
211 return myCurrentName;
214 template <typename Space, typename KSpace>
215 void Display3D<Space, KSpace>::endCurrentGroup() {
216 myCurrentData = nullptr;
220 ///////////////////////////// GROUP MANAGEMENT /////////////////////////////
221 ////////////////////////////////////////////////////////////////////////////
223 ////////////////////////////////////////////////////////////////////////////
224 ////////////////////////////// DRAW MODIFIERS //////////////////////////////
226 template <typename Space, typename KSpace>
227 std::string Display3D<Space, KSpace>::draw(const DGtal::Color& color, const std::string& name) {
233 template <typename Space, typename KSpace>
234 void Display3D<Space, KSpace>::drawColor(const DGtal::Color& color) {
235 currentStyle.color = color;
236 currentStyle.useDefaultColors = false;
239 template <typename Space, typename KSpace>
240 void Display3D<Space, KSpace>::setDefaultColors() {
241 currentStyle.useDefaultColors = true;
244 template <typename Space, typename KSpace>
245 void Display3D<Space, KSpace>::drawAdjacencies(bool toggle) {
246 if (toggle) currentStyle.mode |= DisplayStyle::ADJACENCIES;
247 else currentStyle.mode &= ~DisplayStyle::ADJACENCIES;
250 template <typename Space, typename KSpace>
251 void Display3D<Space, KSpace>::drawAsSimplified(bool toggle) {
252 if (toggle) currentStyle.mode |= DisplayStyle::SIMPLIFIED;
253 else currentStyle.mode &= ~DisplayStyle::SIMPLIFIED;
256 template <typename Space, typename KSpace>
257 void Display3D<Space, KSpace>::drawAsGrid(bool toggle) {
258 if (toggle) currentStyle.mode |= DisplayStyle::GRID;
259 else currentStyle.mode &= ~DisplayStyle::GRID;
262 template <typename Space, typename KSpace>
263 void Display3D<Space, KSpace>::defaultStyle() {
264 currentStyle.mode = DisplayStyle::DEFAULT;
267 template <typename Space, typename KSpace>
268 void Display3D<Space, KSpace>::drawAsPaving() {
269 currentStyle.mode &= ~DisplayStyle::BALLS;
270 currentStyle.mode |= DisplayStyle::PAVING;
273 template <typename Space, typename KSpace>
274 void Display3D<Space, KSpace>::drawAsBalls() {
275 currentStyle.mode &= ~DisplayStyle::PAVING;
276 currentStyle.mode |= DisplayStyle::BALLS;
279 ////////////////////////////// DRAW MODIFIERS //////////////////////////////
280 ////////////////////////////////////////////////////////////////////////////
282 ////////////////////////////////////////////////////////////////////////////
283 ////////////////////////////// DRAW COMMANDS ///////////////////////////////
285 template <typename Space, typename KSpace>
286 template<typename Obj>
287 Display3D<Space, KSpace>& Display3D<Space, KSpace>::operator<<(const Obj& obj) {
292 template <typename Space, typename KSpace>
293 std::string Display3D<Space, KSpace>::draw(const Point& p, const std::string& uname) {
294 return draw(myEmbedder.embed(p), uname);
297 template <typename Space, typename KSpace>
298 std::string Display3D<Space, KSpace>::draw(const RealPoint& rp, const std::string& uname) {
299 std::string name = myCurrentName;
301 if (currentStyle.mode & DisplayStyle::BALLS) {
302 name = createOrReuseBallList(uname);
303 myCurrentData->vertices.push_back(rp);
305 name = createOrReuseCubeList(uname);
306 drawutils::insertCubeVertices(myCurrentData->vertices, rp, myCurrentData->style.width);
311 template <typename Space, typename KSpace>
312 std::string Display3D<Space, KSpace>::draw(const std::pair<RealPoint, RealPoint>& arrow, const std::string& uname) {
313 // Warning, this function draw arrows, not lines !
314 std::string name = createOrReuseBallList(uname);
315 myCurrentData->vertices.push_back(arrow.first);
316 myCurrentData->vectorQuantities[QuantityScale::VERTEX]["value"].push_back(arrow.second);
320 template <typename Space, typename KSpace>
322 std::string Display3D<Space, KSpace>::draw(const std::vector<T>& range, const std::string& uname) {
323 return drawGenericRange(range, uname);
326 template <typename Space, typename KSpace>
327 template<typename A, typename B, typename C>
328 std::string Display3D<Space, KSpace>::draw(const ConstRangeAdapter<A, B, C> range, const std::string& uname) {
329 return drawGenericRange(range, uname);
332 template <typename Space, typename KSpace>
333 template<typename A, typename B, typename C>
334 std::string Display3D<Space, KSpace>::draw(const ConstIteratorAdapter<A, B, C>& adapter, const std::string& uname) {
336 // Use default value of draw
337 return draw(*adapter);
339 return draw(*adapter, uname);
342 template <typename Space, typename KSpace>
343 std::string Display3D<Space, KSpace>::draw(const GridCurve<KSpace>& curve, const std::string& uname) {
344 return draw(curve.getSCellsRange(), uname);
347 template <typename Space, typename KSpace>
348 std::string Display3D<Space, KSpace>::draw(const typename GridCurve<KSpace>::MidPointsRange& range, const std::string& uname) {
349 return drawGenericRange(range, uname);
352 template <typename Space, typename KSpace>
353 std::string Display3D<Space, KSpace>::draw(const typename GridCurve<KSpace>::ArrowsRange& range, const std::string& uname) {
354 return drawGenericRange(range, uname);
357 template <typename Space, typename KSpace>
358 template <DGtal::Dimension emb, DGtal::Dimension amb, typename Algebra, typename Int>
359 std::string Display3D<Space, KSpace>::draw(const DiscreteExteriorCalculus<emb, amb, Algebra, Int>& calc, const std::string& uname) {
360 bool save = allowReuseList;
361 allowReuseList = true;
363 // Maintains multiple names it contains any dimension type
364 std::string list0 = newBallList(uname + "_0d");
365 std::string list1 = newLineList(uname + "_1d");
366 std::string list2_1 = newQuadList(uname + "_2d");
367 std::string list2_2 = newVolumetricList(uname + "_2d_signed");
368 std::string list3 = newCubeList(uname + "_3d");
370 const std::string* const lists[4] = { &list0, &list1, &list2_2, &list3 };
372 for (auto it = calc.begin(); it != calc.end(); ++it) {
373 const auto& cell = it->first;
374 const bool& flip = it->second.flipped;
376 const SCell displayed = calc.myKSpace.signs(cell, flip ? KSpace::NEG : KSpace::POS);
378 const bool xodd = (NumberTraits<typename KSpace::Integer>::castToInt64_t(displayed.preCell().coordinates[0]) & 1);
379 const bool yodd = (NumberTraits<typename KSpace::Integer>::castToInt64_t(displayed.preCell().coordinates[1]) & 1);
380 const bool zodd = (NumberTraits<typename KSpace::Integer>::castToInt64_t(displayed.preCell().coordinates[2]) & 1);
382 const int dim = xodd + yodd + zodd;
384 setCurrentList(*lists[dim]);
385 if ((dim == 2) && (currentStyle.mode & DisplayStyle::SIMPLIFIED))
386 setCurrentList(list2_1);
388 const auto rp = mySCellEmbedder.embed(displayed);
389 drawKCell(*lists[dim], rp, xodd, yodd, zodd, true, displayed.preCell().positive);
392 allowReuseList = save;
394 return list2_2; // Return one of the name
397 template <typename Space, typename KSpace>
398 template <typename Calculus, DGtal::Order order, DGtal::Duality duality>
399 std::string Display3D<Space, KSpace>::draw(const KForm<Calculus, order, duality>& kform, const std::string& uname) {
400 bool save = allowReuseList;
401 allowReuseList = true;
403 // using CSCell = Calculus::SCell;
404 using Scalar = Calculus::Scalar;
406 std::string list0 = newBallList(uname + "_0d");
407 std::string list1 = newLineList(uname + "_1d");
408 std::string list2_1 = newQuadList(uname + "_2d");
409 std::string list2_2 = newVolumetricList(uname + "_2d_signed");
410 std::string list3 = newCubeList(uname + "_3d");
412 const std::string* lists[4] = { &list0, &list1, &list2_2, &list3 };
414 for (typename Calculus::Index i = 0; i < kform.length(); ++i) {
415 const SCell cell = kform.getSCell(i);
416 const Scalar val = kform.myContainer(i);
418 const bool xodd = (NumberTraits<typename KSpace::Integer>::castToInt64_t(cell.preCell().coordinates[0]) & 1);
419 const bool zodd = (NumberTraits<typename KSpace::Integer>::castToInt64_t(cell.preCell().coordinates[2]) & 1);
420 const bool yodd = (NumberTraits<typename KSpace::Integer>::castToInt64_t(cell.preCell().coordinates[1]) & 1);
422 const int dim = xodd + yodd + zodd;
423 if (!std::isfinite(val)) continue;
425 setCurrentList(*lists[dim]);
426 if ((dim == 2) && (currentStyle.mode & DisplayStyle::SIMPLIFIED))
427 setCurrentList(list2_1);
429 // Automatically decide the scalle of the quantity
430 draw(WithQuantity(cell, "value", val));
433 allowReuseList = save;
435 return list2_2; // Return one of the name
439 template <typename Space, typename KSpace>
440 template <typename Calculus, DGtal::Duality dual>
441 std::string Display3D<Space, KSpace>::draw(const VectorField<Calculus, dual>& field, const std::string& uname) {
442 std::string name = newBallList(uname);
444 myCurrentData->style.width = 0.; // Make ball diseapear
445 myCurrentData->vertices.reserve(field.length());
446 myCurrentData->vectorQuantities[QuantityScale::VERTEX]["value"].reserve(field.length());
448 for (typename Calculus::Index i = 0; i < field.length(); ++i) {
449 const auto& origin = mySCellEmbedder.embed(field.getSCell(i));
450 const auto vector = field.getVector(i);
452 if (std::isfinite(vector[0]) && std::isfinite(vector[1]) && std::isfinite(vector[2])) {
453 myCurrentData->vertices.push_back(origin);
454 myCurrentData->vectorQuantities[QuantityScale::VERTEX]["value"].push_back(vector);
462 template <typename Space, typename KSpace>
463 std::string Display3D<Space, KSpace>::draw(const KCell& cell, const std::string& name) {
464 const RealPoint rp = myCellEmbedder.embed(cell);
466 const bool xodd = (NumberTraits<typename KSpace::Integer>::castToInt64_t(cell.preCell().coordinates[0]) & 1);
467 const bool yodd = (NumberTraits<typename KSpace::Integer>::castToInt64_t(cell.preCell().coordinates[1]) & 1);
468 const bool zodd = (NumberTraits<typename KSpace::Integer>::castToInt64_t(cell.preCell().coordinates[2]) & 1);
470 return drawKCell(name, rp, xodd, yodd, zodd, false, false);
473 template <typename Space, typename KSpace>
474 std::string Display3D<Space, KSpace>::draw(const SCell& cell, const std::string& name) {
475 const RealPoint rp = mySCellEmbedder.embed(cell);
477 const bool xodd = (NumberTraits<typename KSpace::Integer>::castToInt64_t(cell.preCell().coordinates[0]) & 1);
478 const bool yodd = (NumberTraits<typename KSpace::Integer>::castToInt64_t(cell.preCell().coordinates[1]) & 1);
479 const bool zodd = (NumberTraits<typename KSpace::Integer>::castToInt64_t(cell.preCell().coordinates[2]) & 1);
481 return drawKCell(name, rp, xodd, yodd, zodd, true, cell.preCell().positive);
484 template <typename Space, typename KSpace>
485 std::string Display3D<Space, KSpace>::draw(const HyperRectDomain<Space>& domain, const std::string& uname) {
489 if (currentStyle.mode & DisplayStyle::GRID) {
490 name = newLineList(uname);
493 for (auto z = domain.myLowerBound[2]; z <= domain.myUpperBound[2]; z++) {
494 for (auto x = domain.myLowerBound[0]; x <= domain.myUpperBound[0]; x++) {
495 DGtal::Z3i::RealPoint rp1 = myEmbedder.embed( DGtal::Z3i::Point(x, domain.myLowerBound[1], z) );
496 DGtal::Z3i::RealPoint rp2 = myEmbedder.embed( DGtal::Z3i::Point(x, domain.myUpperBound[1], z) );
497 myCurrentData->vertices.push_back(rp1);
498 myCurrentData->vertices.push_back(rp2);
501 for (auto y = domain.myLowerBound[1]; y <= domain.myUpperBound[1]; y++) {
502 DGtal::Z3i::RealPoint rp1 = myEmbedder.embed( DGtal::Z3i::Point(domain.myLowerBound[0], y, z) );
503 DGtal::Z3i::RealPoint rp2 = myEmbedder.embed( DGtal::Z3i::Point(domain.myUpperBound[0], y, z) );
504 myCurrentData->vertices.push_back(rp1);
505 myCurrentData->vertices.push_back(rp2);
510 for (auto y = domain.myLowerBound[1]; y <= domain.myUpperBound[1]; y++) {
511 for (auto x = domain.myLowerBound[0]; x <= domain.myUpperBound[0]; x++) {
512 DGtal::Z3i::RealPoint rp1 = myEmbedder.embed( DGtal::Z3i::Point(x, y, domain.myLowerBound[2]) );
513 DGtal::Z3i::RealPoint rp2 = myEmbedder.embed( DGtal::Z3i::Point(x, y, domain.myLowerBound[2]) );
515 myCurrentData->vertices.push_back(rp1);
516 myCurrentData->vertices.push_back(rp2);
518 for (auto z = domain.myLowerBound[2]; z <= domain.myUpperBound[2]; z++) {
519 DGtal::Z3i::RealPoint rp1 = myEmbedder.embed( DGtal::Z3i::Point(domain.myLowerBound[0], y, z) );
520 DGtal::Z3i::RealPoint rp2 = myEmbedder.embed( DGtal::Z3i::Point(domain.myUpperBound[0], y, z) );
522 myCurrentData->vertices.push_back(rp1);
523 myCurrentData->vertices.push_back(rp2);
528 for (auto x = domain.myLowerBound[0]; x <= domain.myUpperBound[0]; x++) {
529 for (auto y = domain.myLowerBound[1]; y <= domain.myUpperBound[1]; y++) {
530 DGtal::Z3i::RealPoint rp1 = myEmbedder.embed( DGtal::Z3i::Point(x, y, domain.myLowerBound[2]) );
531 DGtal::Z3i::RealPoint rp2 = myEmbedder.embed( DGtal::Z3i::Point(x, y, domain.myUpperBound[2]) );
533 myCurrentData->vertices.push_back(rp1);
534 myCurrentData->vertices.push_back(rp2);
536 for (auto z = domain.myLowerBound[2]; z <= domain.myUpperBound[2]; z++) {
537 DGtal::Z3i::RealPoint rp1 = myEmbedder.embed( DGtal::Z3i::Point(x, domain.myLowerBound[1], z) );
538 DGtal::Z3i::RealPoint rp2 = myEmbedder.embed( DGtal::Z3i::Point(x, domain.myLowerBound[1], z) );
540 myCurrentData->vertices.push_back(rp1);
541 myCurrentData->vertices.push_back(rp2);
547 name = drawGenericRange(domain, uname);
548 if (!(currentStyle.mode & DisplayStyle::BALLS))
550 data[name].style.useDefaultColors=false;
551 data[name].style.color.alpha(64);
559 template <typename Space, typename KSpace>
560 template <typename Vec>
561 std::string Display3D<Space, KSpace>::drawPolygon(const std::vector<Vec>& vertices, const std::string& uname) {
562 std::string name = createOrReusePolygonList(uname);
564 std::vector<unsigned> indices;
565 indices.reserve(vertices.size());
567 size_t count = myCurrentData->vertices.size();
568 for (const auto& vert : vertices) {
569 myCurrentData->vertices.push_back(vert);
570 indices.push_back(count++);
572 myCurrentData->indices.push_back(std::move(indices));
576 template <typename Space, typename KSpace>
577 std::string Display3D<Space, KSpace>::drawBall(const RealPoint& c, const std::string& uname) {
578 std::string name = createOrReuseBallList(uname);
579 myCurrentData->vertices.push_back(c);
583 template <typename Space, typename KSpace>
584 std::string Display3D<Space, KSpace>::drawLine(const RealPoint& a, const RealPoint& b, const std::string& uname) {
585 std::string name = createOrReuseLineList(uname);
587 myCurrentData->vertices.push_back(a);
588 myCurrentData->vertices.push_back(b);
592 template <typename Space, typename KSpace>
593 std::string Display3D<Space, KSpace>::drawQuad(const RealPoint& a, const RealPoint& b, const RealPoint& c, const RealPoint& d, const std::string& uname) {
594 // Not a draw specialization as it would be confusing with a drawing call of
595 // an array of points, or other primitives
596 std::string name = createOrReuseQuadList(uname);
598 myCurrentData->vertices.push_back(a);
599 myCurrentData->vertices.push_back(b);
600 myCurrentData->vertices.push_back(c);
601 myCurrentData->vertices.push_back(d);
606 template <typename Space, typename KSpace>
607 template <typename Obj, typename Cont>
608 std::string Display3D<Space, KSpace>::draw(const DigitalSetByAssociativeContainer<Obj, Cont>& set, const std::string& name) {
609 return drawGenericRange(set, name);
612 template <typename Space, typename KSpace>
613 template <typename D, typename T>
614 std::string Display3D<Space, KSpace>::draw(const ImageContainerBySTLVector<D, T>& image, const std::string& name) {
615 return drawImage(name, image);
618 template <typename Space, typename KSpace>
619 template <typename TImageContainer,
624 typename TFunctorVm1>
625 std::string Display3D<Space, KSpace>::draw(const ImageAdapter<TImageContainer, TNewDomain, TFunctorD, TNewValue, TFunctorV, TFunctorVm1>& adapter, const std::string& name) {
626 return drawImageAdaptDom(name, adapter);
629 template <typename Space, typename KSpace>
630 template <typename TImageContainer,
635 std::string Display3D<Space, KSpace>::draw(const ConstImageAdapter<TImageContainer, TNewDomain, TFunctorD, TNewValue, TFunctorV>& adapter, const std::string& name) {
636 return drawImageAdaptDom(name, adapter);
639 template <typename Space, typename KSpace>
640 template <typename Adj, typename Set>
641 std::string Display3D<Space, KSpace>::draw(const DGtal::Object<Adj, Set>& obj, const std::string& uname) {
642 std::string name = drawGenericRange(obj, uname);
644 // Draw adjacency if needed
645 if (currentStyle.mode & DisplayStyle::ADJACENCIES) {
646 newLineList(name + "_adj");
648 for (auto it = obj.begin(); it != obj.end(); ++it) {
649 auto neig = obj.properNeighborhood(*it);
651 const RealPoint p = myEmbedder.embed(*it);
652 for (auto it2 = neig.begin(); it2 != neig.end(); ++it2) {
653 auto p2 = myEmbedder.embed(*it2);
655 myCurrentData->vertices.push_back(p);
656 myCurrentData->vertices.push_back(p2);
664 template <typename Space, typename KSpace>
665 template <typename T, typename Type>
666 std::string Display3D<Space, KSpace>::draw(const WithQuantity<T, Type>& props, const std::string& uname) {
669 name = draw(props.object);
671 name = draw(props.object, uname);
673 QuantityScale sloc = props.scale;
675 // Tries to find an appropriate scale
676 if (sloc == QuantityScale::UNKNOWN)
677 sloc = data[name].getDefaultQuantityLevel(data[name].elementSize);
679 if (sloc == QuantityScale::UNKNOWN) {
680 trace.error() << "Unable to find suitable quantity scale, defaulting to vertex (for: '" << name << "')\n";
681 sloc = QuantityScale::VERTEX;
684 addQuantity(name, props.name, props.values, sloc);
688 template <typename Space, typename KSpace>
689 template <typename Type>
690 void Display3D<Space, KSpace>::addQuantity(const std::string& oName, const std::string& qName, const Type& value, QuantityScale scale) {
691 std::vector<Type> values = {value};
692 addQuantity(oName, qName, values, scale);
695 template <typename Space, typename KSpace>
696 template <typename Type>
697 void Display3D<Space, KSpace>::addQuantity(const std::string& oName, const std::string& qName, const std::vector<Type>& values, QuantityScale scale) {
698 if (scale == QuantityScale::UNKNOWN)
699 scale = data[oName].getDefaultQuantityLevel(data[oName].elementSize);
701 if (scale == QuantityScale::UNKNOWN) {
702 trace.error() << "Unable to find suitable quantity scale, defaulting to vertex (for: '" << oName << "')\n";
703 scale = QuantityScale::VERTEX;
706 if constexpr (std::is_scalar_v<Type>) {
707 auto& loc = data[oName].scalarQuantities[scale][qName];
708 loc.insert(loc.end(), values.begin(), values.end());
710 else if constexpr(std::is_same_v<RealPoint, Type>) {
711 auto& loc = data[oName].vectorQuantities[scale][qName];
712 loc.insert(loc.end(), values.begin(), values.end());
714 else if constexpr(std::is_same_v<Color , Type>) {
715 auto& loc = data[oName].colorQuantities[scale][qName];
716 loc.insert(loc.end(), values.begin(), values.end());
719 trace.error() << "Unknown quantity type (for: '" << oName << "')\n";
724 template <typename Space, typename KSpace>
725 template <typename Pt>
726 std::string Display3D<Space, KSpace>::draw(const Mesh<Pt>& mesh, const std::string& uname) {
727 // A mesh may have quad faces, therefore we render it as a polygonal mesh
728 std::string name = newPolygonList(uname);
730 myCurrentData->vertices.reserve(mesh.nbVertex());
732 myCurrentData->indices.reserve(mesh.nbFaces());
733 myCurrentData->colorQuantities[QuantityScale::FACE]["color"].reserve(mesh.nbFaces());
735 // Can not insert directly vectors because of type mismatch
736 for (auto it = mesh.vertexBegin(); it != mesh.vertexEnd(); ++it) {
737 myCurrentData->vertices.push_back(*it);
739 for (size_t i = 0; i < mesh.nbFaces(); ++i) {
740 const auto& face = mesh.getFace(i);
741 std::vector<unsigned int> fIdx;
742 fIdx.reserve(face.size());
743 for (auto j : face) {
746 myCurrentData->indices.push_back(std::move(fIdx));
747 myCurrentData->colorQuantities[QuantityScale::FACE]["color"].push_back(mesh.getFaceColor(i));
753 template <typename Space, typename KSpace>
754 template <typename It, typename Int, int Con>
755 std::string Display3D<Space, KSpace>::draw(const StandardDSS6Computer<It, Int, Con>& computer, const std::string& uname) {
757 if (currentStyle.mode & DisplayStyle::BALLS) {
758 name = newBallList(uname);
760 for (auto it = computer.begin(); it != computer.end(); ++it) {
761 const auto rp = myEmbedder.embed(*it);
762 myCurrentData->vertices.push_back(rp);
764 } else { // Default mode
765 name = newLineList(uname);
767 auto it = computer.begin();
768 RealPoint a = myEmbedder.embed(*it);
771 for (++it; it != computer.end(); ++it) {
772 b = myEmbedder.embed(*it);
773 myCurrentData->vertices.push_back(a);
774 myCurrentData->vertices.push_back(b);
784 template <typename Space, typename KSpace>
785 template<typename It, typename Int, int Con>
786 std::string Display3D<Space, KSpace>::draw(const Naive3DDSSComputer<It, Int, Con>& computer, const std::string& uname) {
787 std::string name = drawGenericRange(computer, uname);
790 if (currentStyle.mode & DisplayStyle::ADJACENCIES) {
791 newLineList(uname + "_links");
793 auto it = computer.begin();
794 auto prev = myEmbedder(*it);
797 for (; it != computer.end(); ++it) {
798 auto p = myEmbedder(*it);
799 myCurrentData->vertices.push_back(prev);
800 myCurrentData->vertices.push_back(p);
809 template <typename Space, typename KSpace>
810 std::string Display3D<Space, KSpace>::draw(const ClippingPlane& plane, const std::string& uname) {
812 planes.push_back(plane);
813 planes.back().style = currentStyle;
817 template <typename Space, typename KSpace>
818 template <typename T>
819 std::string Display3D<Space, KSpace>::draw(const SphericalAccumulator<T> accumulator, const std::string& uname) {
820 std::string name = newQuadList(uname);
822 typedef typename SphericalAccumulator<T>::Size Size;
823 typedef typename SphericalAccumulator<T>::RealVector Vec;
827 for (auto it = accumulator.begin(); it != accumulator.end(); ++it) {
828 accumulator.binCoordinates(it, i, j);
830 if (accumulator.isValidBin(i, j)) {
831 accumulator.getBinGeometry(i, j, a, b, c, d);
833 myCurrentData->vertices.push_back(a);
834 myCurrentData->vertices.push_back(b);
835 myCurrentData->vertices.push_back(c);
836 myCurrentData->vertices.push_back(d);
837 myCurrentData->scalarQuantities[QuantityScale::FACE]["value"].push_back(accumulator.count(i, j));
844 template <typename Space, typename KSpace>
845 template <typename Range>
846 std::string Display3D<Space, KSpace>::drawGenericRange(const Range& range, const std::string& uname) {
847 bool save = allowReuseList;
850 allowReuseList = true;
852 auto it = range.begin();
854 std::string name = myCurrentName;
858 name = draw(*it, uname);
861 myCurrentData->vertices.reserve(
862 myCurrentData->vertices.size() +
863 myCurrentData->elementSize * std::distance(range.begin(), range.end())
866 for (++it; it != range.end(); ++it) {
871 allowReuseList = save;
875 template <typename Space, typename KSpace>
876 template <typename T>
877 std::string Display3D<Space, KSpace>::drawImage(const std::string& uname, const T& image) {
878 std::string name = newCubeList(uname);
880 size_t total = image.domain().size();
882 auto it = image.domain().begin();
883 auto itend = image.domain().end();
884 constexpr size_t dim = T::Domain::Space::dimension;
886 myCurrentData->vertices.reserve(8 * total);
887 myCurrentData->scalarQuantities[QuantityScale::CELL]["value"].reserve(total);
888 for(; it != itend; ++it) {
890 if constexpr (dim == 3) {
891 rp = myEmbedder.embed(*it);
893 // We accept to draw theses 2D image, do ask to parametrize to also the myEmbedder...
894 rp = myEmbedder.embed(Z3i::Point((*it)[0], (*it)[1], 0));
896 myCurrentData->scalarQuantities[QuantityScale::CELL]["value"].push_back(image(*it));
897 drawutils::insertCubeVertices(myCurrentData->vertices, rp, myCurrentData->style.width);
902 template <typename Space, typename KSpace>
903 template <typename T>
904 std::string Display3D<Space, KSpace>::drawImageAdaptDom(const std::string& uname, const T& image) {
905 std::string name = newCubeList(uname);
907 size_t total = image.domain().size();
909 auto it = image.domain().begin();
910 auto itend = image.domain().end();
911 constexpr size_t dim = T::Domain::Space::dimension;
913 myCurrentData->vertices.reserve(8 * total);
914 myCurrentData->scalarQuantities[QuantityScale::CELL]["value"].reserve(total);
915 for(; it != itend; ++it) {
917 if constexpr (dim == 3) {
918 rp = myEmbedder.embed(*it);
920 // We accept to draw theses 2D image, do ask to parametrize to also the myEmbedder...
921 rp = myEmbedder.embed(image.sourceDomainPoint(Z2i::Point((*it)[0], (*it)[1])));
923 myCurrentData->scalarQuantities[QuantityScale::CELL]["value"].push_back(image(*it));
924 drawutils::insertCubeVertices(myCurrentData->vertices, rp, myCurrentData->style.width);
930 template <typename Space, typename KSpace>
931 std::string Display3D<Space, KSpace>::drawKCell(std::string uname, const RealPoint& rp, bool xodd, bool yodd, bool zodd, bool hasSign, bool sign) {
932 std::string name = myCurrentName;
933 static const std::string TOKEN = "{d}";
934 static const double scale = 0.9;
935 static const double shift = 0.05;
936 static const double smallScale = 0.3;
937 static const double smallShift = 0.15;
938 // For 2D cell, this indicates if the big quad is
939 // inside the cell or outside
940 static const int orientationPermut[3][2] = {
941 {1, 0}, {0, 1}, {1, 0}
944 const unsigned int dim = xodd + yodd + zodd;
946 auto tokenPos = uname.find(TOKEN);
947 if (tokenPos != std::string::npos)
948 uname.replace(uname.find(TOKEN), TOKEN.size(), std::to_string(dim));
952 name = createOrReuseBallList(uname);
953 if (myCurrentData->vertices.size() == 0)
954 myCurrentData->style.width *= scale;
956 myCurrentData->vertices.push_back(rp);
960 name = createOrReuseLineList(uname);
962 const RealPoint newshift(xodd, yodd, zodd);
963 myCurrentData->vertices.push_back(rp - 0.5 * newshift);
964 myCurrentData->vertices.push_back(rp + 0.5 * newshift);
968 const unsigned int orientation = (!xodd ? 0 : (!yodd ? 1 : 2));
969 if (currentStyle.mode & DisplayStyle::SIMPLIFIED || !hasSign) {
970 name = createOrReuseQuadList(uname);
972 const double scale1 = myCurrentData->style.width * scale;
974 drawutils::insertAASquare(myCurrentData->vertices, rp, orientation, scale1);
976 name = createOrReuseVolumetricList(uname);
978 const double scales[2] = {
979 scale * myCurrentData->style.width,
980 smallScale * myCurrentData->style.width
983 // Decide where the big quad goes, in the interior or the exterior
984 // of the cell depending on sign and the orientation
985 int permut = orientationPermut[orientation][sign];
986 double scale1 = scales[ permut];
987 double scale2 = scales[1 - permut];
988 double shift1 = shift;
989 double shift2 = smallShift;
991 drawutils::insertPrism(myCurrentData->vertices, rp, orientation, scale1, scale2, shift1, shift2);
996 name = createOrReuseCubeList(uname);
997 drawutils::insertCubeVertices(myCurrentData->vertices, rp, myCurrentData->style.width);