PLaSK library

Loading...
Searching...
No Matches
rectangular_masked2d.hpp
Go to the documentation of this file.
1/*
2 * This file is part of PLaSK (https://plask.app) by Photonics Group at TUL
3 * Copyright (c) 2022 Lodz University of Technology
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14#ifndef PLASK__RECTANGULAR_MASKED2D_H
15#define PLASK__RECTANGULAR_MASKED2D_H
16
17#include "rectangular_masked_common.hpp"
18
19 namespace plask {
20
28 struct PLASK_API RectangularMaskedMesh2D: public RectangularMaskedMeshBase<2> {
29
31 typedef std::function<bool(const RectangularMesh2D::Element&)> Predicate;
32
33 class PLASK_API Element {
34
35 const RectangularMaskedMesh2D& maskedMesh;
36
37 //std::uint32_t elementNumber; ///< index of element in oryginal mesh
38 std::size_t index0, index1; // probably this form allows to do most operation fastest in average, low indexes of element corner or just element indexes
39
41 mutable std::size_t elementIndex;
42
43 const RectangularMesh<2>& fullMesh() const { return maskedMesh.fullMesh; }
44
45 public:
46
47 enum: std::size_t { UNKNOWN_ELEMENT_INDEX = std::numeric_limits<std::size_t>::max() };
48
49 Element(const RectangularMaskedMesh2D& maskedMesh, std::size_t elementIndex, std::size_t index0, std::size_t index1)
50 : maskedMesh(maskedMesh), index0(index0), index1(index1), elementIndex(elementIndex)
51 {
52 }
53
54 Element(const RectangularMaskedMesh2D& maskedMesh, std::size_t elementIndex, std::size_t elementIndexOfFullMesh)
55 : maskedMesh(maskedMesh), elementIndex(elementIndex)
56 {
57 const std::size_t v = fullMesh().getElementMeshLowIndex(elementIndexOfFullMesh);
58 index0 = fullMesh().index0(v);
59 index1 = fullMesh().index1(v);
60 }
61
62 Element(const RectangularMaskedMesh2D& maskedMesh, std::size_t elementIndex)
63 : Element(maskedMesh, elementIndex, maskedMesh.elementSet.at(elementIndex))
64 {}
65
67 inline std::size_t getIndex0() const { return index0; }
68
70 inline std::size_t getIndex1() const { return index1; }
71
73 inline std::size_t getLowerIndex0() const { return index0; }
74
76 inline std::size_t getLowerIndex1() const { return index1; }
77
79 inline double getLower0() const { return fullMesh().axis[0]->at(index0); }
80
82 inline double getLower1() const { return fullMesh().axis[1]->at(index1); }
83
85 inline std::size_t getUpperIndex0() const { return index0+1; }
86
88 inline std::size_t getUpperIndex1() const { return index1+1; }
89
91 inline double getUpper0() const { return fullMesh().axis[0]->at(getUpperIndex0()); }
92
94 inline double getUpper1() const { return fullMesh().axis[1]->at(getUpperIndex1()); }
95
97 inline double getSize0() const { return getUpper0() - getLower0(); }
98
100 inline double getSize1() const { return getUpper1() - getLower1(); }
101
103 inline Vec<2, double> getSize() const { return getUpUp() - getLoLo(); }
104
106 inline Vec<2, double> getMidpoint() const { return maskedMesh.getElementMidpoint(index0, index1); }
107
109 inline std::size_t getIndex() const {
110 if (elementIndex == UNKNOWN_ELEMENT_INDEX)
111 elementIndex = maskedMesh.getElementIndexFromLowIndexes(getLowerIndex0(), getLowerIndex1());
112 return elementIndex;
113 }
114
116 inline Box2D toBox() const { return maskedMesh.getElementBox(index0, index1); }
117
119 inline double getVolume() const { return getSize0() * getSize1(); }
120
122 inline double getArea() const { return getVolume(); }
123
125 inline std::size_t getLoLoIndex() const { return maskedMesh.index(getLowerIndex0(), getLowerIndex1()); }
126
128 inline std::size_t getLoUpIndex() const { return maskedMesh.index(getLowerIndex0(), getUpperIndex1()); }
129
131 inline std::size_t getUpLoIndex() const { return maskedMesh.index(getUpperIndex0(), getLowerIndex1()); }
132
134 inline std::size_t getUpUpIndex() const { return maskedMesh.index(getUpperIndex0(), getUpperIndex1()); }
135
137 inline Vec<2, double> getLoLo() const { return maskedMesh(getLowerIndex0(), getLowerIndex1()); }
138
140 inline Vec<2, double> getLoUp() const { return maskedMesh(getLowerIndex0(), getUpperIndex1()); }
141
143 inline Vec<2, double> getUpLo() const { return maskedMesh(getUpperIndex0(), getLowerIndex1()); }
144
146 inline Vec<2, double> getUpUp() const { return maskedMesh(getUpperIndex0(), getUpperIndex1()); }
147
148 }; // class Element
149
150 struct PLASK_API Elements: ElementsBase<RectangularMaskedMesh2D> {
151
152 explicit Elements(const RectangularMaskedMesh2D& mesh): ElementsBase(mesh) { mesh.ensureHasElements(); }
153
154 Element operator()(std::size_t i0, std::size_t i1) const { return Element(*maskedMesh, Element::UNKNOWN_ELEMENT_INDEX, i0, i1); }
155
156 }; // struct Elements
157
159 struct PLASK_API ElementMesh: ElementMeshBase<RectangularMaskedMesh2D> {
160
161 explicit ElementMesh(const RectangularMaskedMesh2D* originalMesh): ElementMeshBase<RectangularMaskedMesh2D>(originalMesh) {}
162
169 inline std::size_t index(std::size_t axis0_index, std::size_t axis1_index) const {
170 return originalMesh->elementSet.indexOf(fullMesh.index(axis0_index, axis1_index));
171 }
172
173
174 bool prepareInterpolation(const Vec<2>& point, Vec<2>& wrapped_point, std::size_t& index0_lo, std::size_t& index0_hi, std::size_t& index1_lo, std::size_t& index1_hi,
175 const InterpolationFlags& flags) const {
176 return originalMesh->prepareInterpolation(point, wrapped_point, index0_lo, index0_hi, index1_lo, index1_hi, flags);
177 }
178
179 // Convert to recctangular masked mesh
180 RectangularMaskedMesh2D toMasked() const {
181 return RectangularMaskedMesh2D(fullMesh, originalMesh->elementSet);
182 }
183
184 // Convert to recctangular masked mesh
185 operator RectangularMaskedMesh2D() const {
186 return RectangularMaskedMesh2D(fullMesh, originalMesh->elementSet);
187 }
188
195 template <typename RandomAccessContainer>
196 auto interpolateLinear(const RandomAccessContainer& data, const Vec<2>& point, const InterpolationFlags& flags) const
197 -> typename std::remove_reference<decltype(data[0])>::type {
198 typedef typename std::remove_reference<decltype(data[0])>::type DataT;
199 Vec<2> p;
200 size_t index0, index0_hi, index1, index1_hi;
201
202 if (!prepareInterpolation(point, p, index0, index0_hi, index1, index1_hi, flags))
203 return NaN<decltype(data[0])>();
204
205 Vec<2> pa = fullMesh.at(index0, index1);
206
207 size_t step0 = (p.c0 < pa.c0)?
208 (index0 == 0)? 0 : -1 :
209 (index0_hi == fullMesh.axis[0]->size())? 0 : 1;
210 size_t step1 = (p.c1 < pa.c1)?
211 (index1 == 0)? 0 : -1 :
212 (index1_hi == fullMesh.axis[1]->size())? 0 : 1;
213
214 size_t index_aa = index(index0, index1), index_ab, index_ba, index_bb;
215
216 typename std::remove_const<DataT>::type data_aa = data[index_aa], data_ab, data_ba, data_bb;
217
218 if (step0 == 0 && step1 == 0) {
219 index_ab = index_ba = index_bb = index_aa;
220 data_ab = data_ba = data_bb = data_aa;
221 } else {
222 index_ab = index(index0, index1+step1);
223 index_ba = index(index0+step0, index1);
224 index_bb = index(index0+step0, index1+step1);
225 data_ab = (index_ab != Element::UNKNOWN_ELEMENT_INDEX)? data[index_ab] : data_aa;
226 data_ba = (index_ba != Element::UNKNOWN_ELEMENT_INDEX)? data[index_ba] : data_aa;
227 data_bb = (index_bb != Element::UNKNOWN_ELEMENT_INDEX)? data[index_bb] : data_ab + data_ba - data_aa;
228 }
229
230 Vec<2> pb = fullMesh.at(index0+step0, index1+step1);
231 if (step0 == 0) pb.c0 += 1.;
232 if (step1 == 0) pb.c1 += 1.;
233
234 return flags.postprocess(point,
235 interpolation::bilinear(pa.c0, pb.c0, pa.c1, pb.c1,
236 data_aa, data_ba, data_bb, data_ab, p.c0, p.c1));
237 }
238
245 template <typename RandomAccessContainer>
246 auto interpolateNearestNeighbor(const RandomAccessContainer& data, const Vec<2>& point, const InterpolationFlags& flags) const
247 -> typename std::remove_reference<decltype(data[0])>::type {
248 Vec<2> wrapped_point;
249 std::size_t index0_lo, index0_hi, index1_lo, index1_hi;
250
251 if (!originalMesh->prepareInterpolation(point, wrapped_point, index0_lo, index0_hi, index1_lo, index1_hi, flags))
252 return NaN<decltype(data[0])>();
253
254 return flags.postprocess(point, data[this->index(index0_lo, index1_lo)]);
255 }
256
257 }; // struct ElementMesh
258
262 RectangularMaskedMesh2D() = default;
263
268 void reset(const Predicate& predicate);
269
277 RectangularMaskedMesh2D(const RectangularMesh<2>& fullMesh, const Predicate& predicate, bool clone_axes = false);
278
286 void reset(const RectangularMesh<2>& fullMesh, const Predicate& predicate, bool clone_axes = false);
287
296 RectangularMaskedMesh2D(const RectangularMesh<2>& fullMesh, const GeometryD<2>& geom, const std::function<bool(shared_ptr<const Material>)> materialPredicate, bool clone_axes = false)
297 : RectangularMaskedMesh2D(fullMesh,
298 [&](const RectangularMesh2D::Element& el) { return materialPredicate(geom.getMaterial(el.getMidpoint())); },
299 clone_axes)
300 {
301 }
302
311 void reset(const RectangularMesh<2>& rectangularMesh, const GeometryD<2>& geom, const std::function<bool(shared_ptr<const Material>)> materialPredicate, bool clone_axes = false) {
312 reset(rectangularMesh,
313 [&](const RectangularMesh2D::Element& el) { return materialPredicate(geom.getMaterial(el.getMidpoint())); },
314 clone_axes);
315 }
316
327 RectangularMaskedMesh2D(const RectangularMesh<2>& rectangularMesh, const GeometryD<2>& geom, unsigned materialKinds, bool clone_axes = false)
328 : RectangularMaskedMesh2D(rectangularMesh,
329 [&](const RectangularMesh2D::Element& el) { return (geom.getMaterial(el.getMidpoint())->kind() & materialKinds) != 0; },
330 clone_axes)
331 {
332 }
333
344 void reset(const RectangularMesh<2>& rectangularMesh, const GeometryD<2>& geom, unsigned materialKinds, bool clone_axes = false) {
345 reset(rectangularMesh,
346 [&](const RectangularMesh2D::Element& el) { return (geom.getMaterial(el.getMidpoint())->kind() & materialKinds) != 0; },
347 clone_axes);
348 }
349
358 RectangularMaskedMesh2D(const RectangularMesh<DIM>& rectangularMesh, Set nodeSet, bool clone_axes = false);
359
360 Elements elements() const { return Elements(*this); }
361 Elements getElements() const { return elements(); }
362
363 Element element(std::size_t i0, std::size_t i1) const { ensureHasElements(); return Element(*this, Element::UNKNOWN_ELEMENT_INDEX, i0, i1); }
364 Element getElement(std::size_t i0, std::size_t i1) const { return element(i0, i1); }
365
371 Element element(std::size_t i) const { ensureHasElements(); return Element(*this, i); }
372
378 Element getElement(std::size_t i) const { return element(i); }
379
386 inline std::size_t index(std::size_t axis0_index, std::size_t axis1_index) const {
387 return nodeSet.indexOf(fullMesh.index(axis0_index, axis1_index));
388 }
389
390 using RectangularMaskedMeshBase<2>::index;
391 using RectangularMaskedMeshBase<2>::at;
392
399 inline Vec<2, double> at(std::size_t index0, std::size_t index1) const {
400 return fullMesh.at(index0, index1);
401 }
402
409 inline Vec<2,double> operator()(std::size_t axis0_index, std::size_t axis1_index) const {
410 return fullMesh.operator()(axis0_index, axis1_index);
411 }
412
417 shared_ptr<RectangularMaskedMesh2D::ElementMesh> getElementMesh() const {
418 return make_shared<RectangularMaskedMesh2D::ElementMesh>(this);
419 }
420
421 private:
422
423 void initNodesAndElements(const RectangularMaskedMesh2D::Predicate &predicate);
424
425 bool canBeIncluded(const Vec<2>& point) const {
426 return
427 fullMesh.axis[0]->at(0) - point[0] < MIN_DISTANCE && point[0] - fullMesh.axis[0]->at(fullMesh.axis[0]->size()-1) < MIN_DISTANCE &&
428 fullMesh.axis[1]->at(0) - point[1] < MIN_DISTANCE && point[1] - fullMesh.axis[1]->at(fullMesh.axis[1]->size()-1) < MIN_DISTANCE;
429 }
430
431 public:
440 bool prepareInterpolation(const Vec<2>& point, Vec<2>& wrapped_point,
441 std::size_t& index0_lo, std::size_t& index0_hi,
442 std::size_t& index1_lo, std::size_t& index1_hi,
443 const InterpolationFlags& flags) const;
444
451 template <typename RandomAccessContainer>
452 auto interpolateLinear(const RandomAccessContainer& data, const Vec<2>& point, const InterpolationFlags& flags) const
453 -> typename std::remove_reference<decltype(data[0])>::type
454 {
455 Vec<2> wrapped_point;
456 std::size_t index0_lo, index0_hi, index1_lo, index1_hi;
457
458 if (!prepareInterpolation(point, wrapped_point, index0_lo, index0_hi, index1_lo, index1_hi, flags))
459 return NaN<decltype(data[0])>();
460
461 return flags.postprocess(point,
462 interpolation::bilinear(
463 fullMesh.axis[0]->at(index0_lo), fullMesh.axis[0]->at(index0_hi),
464 fullMesh.axis[1]->at(index1_lo), fullMesh.axis[1]->at(index1_hi),
465 data[index(index0_lo, index1_lo)],
466 data[index(index0_hi, index1_lo)],
467 data[index(index0_hi, index1_hi)],
468 data[index(index0_lo, index1_hi)],
469 wrapped_point.c0, wrapped_point.c1));
470 }
471
478 template <typename RandomAccessContainer>
479 auto interpolateNearestNeighbor(const RandomAccessContainer& data, const Vec<2>& point, const InterpolationFlags& flags) const
480 -> typename std::remove_reference<decltype(data[0])>::type
481 {
482 Vec<2> wrapped_point;
483 std::size_t index0_lo, index0_hi, index1_lo, index1_hi;
484
485 if (!prepareInterpolation(point, wrapped_point, index0_lo, index0_hi, index1_lo, index1_hi, flags))
486 return NaN<decltype(data[0])>();
487
488 return flags.postprocess(point,
489 data[this->index(
490 nearest(wrapped_point.c0, *fullMesh.axis[0], index0_lo, index0_hi),
491 nearest(wrapped_point.c1, *fullMesh.axis[1], index1_lo, index1_hi)
492 )]);
493 }
494
501 std::size_t getElementIndexFromLowIndexes(std::size_t axis0_index, std::size_t axis1_index) const {
502 return ensureHasElements().indexOf(fullMesh.getElementIndexFromLowIndexes(axis0_index, axis1_index));
503 }
504
510 double getElementArea(std::size_t index0, std::size_t index1) const {
511 return fullMesh.getElementArea(index0, index1);
512 }
513
519 Vec<2, double> getElementMidpoint(std::size_t index0, std::size_t index1) const {
520 return fullMesh.getElementMidpoint(index0, index1);
521 }
522
528 Box2D getElementBox(std::size_t index0, std::size_t index1) const {
529 return fullMesh.getElementBox(index0, index1);
530 }
531
532 protected: // boundaries code:
533
534 // Common code for: left, right, bottom, top boundaries:
535 template <int CHANGE_DIR>
536 struct BoundaryIteratorImpl: public plask::BoundaryNodeSetImpl::IteratorImpl {
537
538 const RectangularMaskedMeshBase<2> &mesh;
539
541 Vec<2, std::size_t> index;
542
544 std::size_t endIndex;
545
546 BoundaryIteratorImpl(const RectangularMaskedMeshBase<2>& mesh, Vec<2, std::size_t> index, std::size_t endIndex)
547 : mesh(mesh), index(index), endIndex(endIndex)
548 {
549 // go to the first index existed in order to make dereference possible:
550 while (this->index[CHANGE_DIR] < this->endIndex && mesh.index(this->index) == NOT_INCLUDED)
551 ++this->index[CHANGE_DIR];
552 }
553
554 void increment() override {
555 do {
556 ++index[CHANGE_DIR];
557 } while (index[CHANGE_DIR] < endIndex && mesh.index(index) == NOT_INCLUDED);
558 }
559
560 bool equal(const plask::BoundaryNodeSetImpl::IteratorImpl& other) const override {
561 return index == static_cast<const BoundaryIteratorImpl&>(other).index;
562 }
563
564 std::size_t dereference() const override {
565 return mesh.index(index);
566 }
567
568 std::unique_ptr<plask::BoundaryNodeSetImpl::IteratorImpl> clone() const override {
569 return std::unique_ptr<plask::BoundaryNodeSetImpl::IteratorImpl>(new BoundaryIteratorImpl<CHANGE_DIR>(*this));
570 }
571
572 };
573
574 template <int CHANGE_DIR>
575 struct BoundaryNodeSetImpl: public BoundaryNodeSetWithMeshImpl<RectangularMaskedMeshBase<2>> {
576
577 using typename BoundaryNodeSetWithMeshImpl<RectangularMaskedMeshBase<2>>::const_iterator;
578
580 Vec<2, std::size_t> index;
581
583 std::size_t endIndex;
584
585 BoundaryNodeSetImpl(const RectangularMaskedMeshBase<2>& mesh, Vec<2, std::size_t> index, std::size_t endIndex)
586 : BoundaryNodeSetWithMeshImpl<RectangularMaskedMeshBase<2>>(mesh), index(index), endIndex(endIndex) {}
587
588 BoundaryNodeSetImpl(const RectangularMaskedMeshBase<2>& mesh, std::size_t index0, std::size_t index1, std::size_t endIndex)
589 : BoundaryNodeSetWithMeshImpl<RectangularMaskedMeshBase<2>>(mesh), index(index0, index1), endIndex(endIndex) {}
590
591 bool contains(std::size_t mesh_index) const override {
592 if (mesh_index >= this->mesh.size()) return false;
593 Vec<2, std::size_t> mesh_indexes = this->mesh.indexes(mesh_index);
594 for (int i = 0; i < 2; ++i)
595 if (i == CHANGE_DIR) {
596 if (mesh_indexes[i] < index[i] || mesh_indexes[i] >= endIndex) return false;
597 } else
598 if (mesh_indexes[i] != index[i]) return false;
599 return true;
600 }
601
602 const_iterator begin() const override {
603 return Iterator(new BoundaryIteratorImpl<CHANGE_DIR>(this->mesh, index, endIndex));
604 }
605
606 const_iterator end() const override {
607 Vec<2, std::size_t> index_end = index;
608 index_end[CHANGE_DIR] = endIndex;
609 return Iterator(new BoundaryIteratorImpl<CHANGE_DIR>(this->mesh, index_end, endIndex));
610 }
611 };
612
613 public: // boundaries:
614
615 BoundaryNodeSet createVerticalBoundaryAtLine(std::size_t line_nr_axis0) const override;
616
617 BoundaryNodeSet createVerticalBoundaryAtLine(std::size_t line_nr_axis0, std::size_t indexBegin, std::size_t indexEnd) const override;
618
619 BoundaryNodeSet createVerticalBoundaryNear(double axis0_coord) const override;
620
621 BoundaryNodeSet createVerticalBoundaryNear(double axis0_coord, double from, double to) const override;
622
623 BoundaryNodeSet createLeftBoundary() const override;
624
625 BoundaryNodeSet createRightBoundary() const override;
626
627 BoundaryNodeSet createLeftOfBoundary(const Box2D& box) const override;
628
629 BoundaryNodeSet createRightOfBoundary(const Box2D& box) const override;
630
631 BoundaryNodeSet createBottomOfBoundary(const Box2D& box) const override;
632
633 BoundaryNodeSet createTopOfBoundary(const Box2D& box) const override;
634
635 BoundaryNodeSet createHorizontalBoundaryAtLine(std::size_t line_nr_axis1) const override;
636
637 BoundaryNodeSet createHorizontalBoundaryAtLine(std::size_t line_nr_axis1, std::size_t indexBegin, std::size_t indexEnd) const override;
638
639 BoundaryNodeSet createHorizontalBoundaryNear(double axis1_coord) const override;
640
641 BoundaryNodeSet createHorizontalBoundaryNear(double axis1_coord, double from, double to) const override;
642
643 BoundaryNodeSet createTopBoundary() const override;
644
645 BoundaryNodeSet createBottomBoundary() const override;
646
647};
648
649 template <typename SrcT, typename DstT>
650 struct InterpolationAlgorithm<RectangularMaskedMesh2D, SrcT, DstT, INTERPOLATION_LINEAR> {
651 static LazyData<DstT> interpolate(const shared_ptr<const RectangularMaskedMesh2D>& src_mesh, const DataVector<const SrcT>& src_vec,
652 const shared_ptr<const MeshD<2>>& dst_mesh, const InterpolationFlags& flags) {
653 if (src_mesh->empty()) throw BadMesh("interpolate", "source mesh empty");
654 return new LinearInterpolatedLazyDataImpl<DstT, RectangularMaskedMesh2D, SrcT>(src_mesh, src_vec, dst_mesh, flags);
655 }
656};
657
658 template <typename SrcT, typename DstT>
659 struct InterpolationAlgorithm<RectangularMaskedMesh2D, SrcT, DstT, INTERPOLATION_NEAREST> {
660 static LazyData<DstT> interpolate(const shared_ptr<const RectangularMaskedMesh2D>& src_mesh, const DataVector<const SrcT>& src_vec,
661 const shared_ptr<const MeshD<2>>& dst_mesh, const InterpolationFlags& flags) {
662 if (src_mesh->empty()) throw BadMesh("interpolate", "source mesh empty");
663 return new NearestNeighborInterpolatedLazyDataImpl<DstT, RectangularMaskedMesh2D, SrcT>(src_mesh, src_vec, dst_mesh, flags);
664 }
665};
666
667
668 template <typename SrcT, typename DstT>
669 struct InterpolationAlgorithm<RectangularMaskedMesh2D::ElementMesh, SrcT, DstT, INTERPOLATION_LINEAR> {
670 static LazyData<DstT> interpolate(const shared_ptr<const RectangularMaskedMesh2D::ElementMesh>& src_mesh, const DataVector<const SrcT>& src_vec,
671 const shared_ptr<const MeshD<2>>& dst_mesh, const InterpolationFlags& flags) {
672 if (src_mesh->empty()) throw BadMesh("interpolate", "source mesh empty");
673 return new LinearInterpolatedLazyDataImpl<DstT, RectangularMaskedMesh2D::ElementMesh, SrcT>(src_mesh, src_vec, dst_mesh, flags);
674 }
675};
676
677 template <typename SrcT, typename DstT>
678 struct InterpolationAlgorithm<RectangularMaskedMesh2D::ElementMesh, SrcT, DstT, INTERPOLATION_NEAREST> {
679 static LazyData<DstT> interpolate(const shared_ptr<const RectangularMaskedMesh2D::ElementMesh>& src_mesh, const DataVector<const SrcT>& src_vec,
680 const shared_ptr<const MeshD<2>>& dst_mesh, const InterpolationFlags& flags) {
681 if (src_mesh->empty()) throw BadMesh("interpolate", "source mesh empty");
682 return new NearestNeighborInterpolatedLazyDataImpl<DstT, RectangularMaskedMesh2D::ElementMesh, SrcT>(src_mesh, src_vec, dst_mesh, flags);
683 }
684};
685
686} // namespace plask
687
688#endif // PLASK__RECTANGULAR_MASKED2D_H