PLaSK library
Loading...
Searching...
No Matches
triangular2d.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__TRIANGULAR2D_H
15#define PLASK__TRIANGULAR2D_H
16
17#include "mesh.hpp"
18#include "interpolation.hpp"
19#include "boundary.hpp"
20#include "../geometry/path.hpp"
21#include <array>
22#include <unordered_map>
23
24#include <boost/geometry/index/rtree.hpp>
25#include "../vector/boost_geometry.hpp"
26#include <boost/geometry/geometries/box.hpp>
27
28#include <boost/functional/hash.hpp>
29
30namespace plask {
31
32struct PLASK_API TriangularMesh2D: public MeshD<2> {
33
35
38
39 using MeshD<2>::LocalCoords;
40 typedef std::vector<LocalCoords> LocalCoordsVec;
41 typedef LocalCoordsVec::const_iterator const_iterator;
43
45
46 typedef std::array<std::size_t, 3> TriangleNodeIndexes;
47
48 std::vector< TriangleNodeIndexes > elementNodes;
49
55 const TriangularMesh2D& mesh; // for getting access to the nodes
56
57 Element(const TriangularMesh2D& mesh, TriangleNodeIndexes triangleNodes)
58 : triangleNodes(triangleNodes), mesh(mesh) {}
59
65 std::size_t getNodeIndex(std::size_t index) const noexcept {
66 assert(index < 3);
67 return triangleNodes[index];
68 }
69
75 const LocalCoords& getNode(std::size_t index) const noexcept {
76 return mesh.nodes[getNodeIndex(index)];
77 }
78
83 std::array<LocalCoords, 3> getNodes() const {
84 return { getNode(0), getNode(1), getNode(2) };
85 }
86
92 return (getNode(0)+getNode(1)+getNode(2)) / 3.0;
93 }
94
99 double getArea() const noexcept {
100 // formula comes from http://www.mathguru.com/level2/application-of-coordinate-geometry-2007101600011139.aspx
101 const LocalCoords A = getNode(0);
102 const LocalCoords B = getNode(1);
103 const LocalCoords C = getNode(2);
104 return abs( (A.c0 - C.c0) * (B.c1 - A.c1)
105 - (A.c0 - B.c0) * (C.c1 - A.c1) ) / 2.0;
106 }
107
113 Vec<3, double> barycentric(Vec<2, double> p) const;
114
120 bool contains(Vec<2, double> p) const {
121 auto b = barycentric(p);
122 return b.c0 >= 0 && b.c1 >= 0 && b.c2 >= 0;
123 }
124
129 Box2D getBoundingBox() const;
130 };
131
139
140 explicit Elements(const TriangularMesh2D& mesh): mesh(mesh) {}
141
142 Element at(std::size_t index) const {
143 if (index >= mesh.elementNodes.size())
144 throw OutOfBoundsException("triangularMesh2D::Elements::at", "index", index, 0, mesh.elementNodes.size()-1);
145 return Element(mesh, mesh.elementNodes[index]);
146 }
147
148 Element operator[](std::size_t index) const {
149 return Element(mesh, mesh.elementNodes[index]);
150 }
151
156 std::size_t size() const { return mesh.getElementsCount(); }
157
158 bool empty() const { return mesh.getElementsCount() == 0; }
159
162
164 const_iterator begin() const { return const_iterator(this, 0); }
165
167 const_iterator end() const { return const_iterator(this, this->size()); }
168 };
169
170 Elements getElements() const { return Elements(*this); }
171 Elements elements() const { return Elements(*this); }
172
173 Element getElement(std::size_t elementIndex) const {
174 return Element(*this, elementNodes[elementIndex]);
175 };
176
177 Element element(std::size_t elementIndex) const {
178 return Element(*this, elementNodes[elementIndex]);
179 };
180
185 std::size_t getElementsCount() const {
186 return elementNodes.size();
187 }
188
193 std::map<LocalCoords, std::size_t> indexOfNode;
195
200 explicit Builder(TriangularMesh2D& mesh);
201
211 explicit Builder(TriangularMesh2D& mesh, std::size_t predicted_number_of_elements, std::size_t predicted_number_of_nodes);
212
221 explicit Builder(TriangularMesh2D& mesh, std::size_t predicted_number_of_elements)
222 : Builder(mesh, predicted_number_of_elements, predicted_number_of_elements*3) {}
223
225 ~Builder();
226
232 Builder& add(LocalCoords p1, LocalCoords p2, LocalCoords p3);
233
239 Builder& add(const Element& e) { return add(e.getNode(0), e.getNode(1), e.getNode(2)); }
240
246 Builder& add(const std::array<LocalCoords, 3>& points) { return add(points[0], points[1], points[2]); }
247
248 private:
249
255 std::size_t addNode(LocalCoords node);
256 };
257
258 class ElementMesh;
259
265
270 typedef boost::geometry::model::box<Vec<2>> Box;
271
272 typedef boost::geometry::index::rtree<
273 std::pair<Box, std::size_t>,
274 boost::geometry::index::quadratic<16> //??
276
278
280
281 ElementIndex(const TriangularMesh2D& mesh);
282
283 static constexpr std::size_t INDEX_NOT_FOUND = std::numeric_limits<std::size_t>::max();
284
290 std::size_t getIndex(Vec<2, double> p) const;
291
297 optional<Element> getElement(Vec<2, double> p) const;
298 };
299
300 // ------------------ Mesh and MeshD<2> interfaces: ------------------
301 LocalCoords at(std::size_t index) const override {
302 assert(index < nodes.size());
303 return nodes[index];
304 }
305
306 std::size_t size() const override {
307 return nodes.size();
308 }
309
310 bool empty() const override {
311 return nodes.empty();
312 }
313
314 // ---- Faster iterators used when exact type of mesh is known; they hide polymorphic iterators of parent class ----
315 const_iterator begin() const { return nodes.begin(); }
316 const_iterator end() const { return nodes.end(); }
317
318 // ----------------------- Masked meshes -----------------------
319
321 typedef std::function<bool(const Element&)> Predicate;
322
329 TriangularMesh2D masked(const Predicate& predicate) const;
330
339 return masked([&](const Element& el) { return materialPredicate(geom.getMaterial(el.getMidpoint())); });
340 }
341
352 return masked([&](const Element& el) { return (geom.getMaterial(el.getMidpoint())->kind() & materialKinds) != 0; });
353 }
354
359 void writeXML(XMLElement& object) const override;
360
366 static TriangularMesh2D read(XMLReader& reader);
367
368
369 // ------------------ Boundaries: -----------------------
370
371 template <typename Predicate>
372 static Boundary getBoundary(Predicate predicate) {
374 }
375
377 typedef std::pair<std::size_t, std::size_t> Segment;
378
380 typedef std::unordered_map<TriangularMesh2D::Segment, std::size_t, boost::hash<Segment>> SegmentsCounts;
381
386 SegmentsCounts countSegments() const;
387
393 SegmentsCounts countSegmentsIn(const Box2D& box) const;
394
400 SegmentsCounts countSegmentsIn(const std::vector<Box2D>& boxes) const;
401
409 SegmentsCounts countSegmentsIn(const GeometryD<2>& geometry, const GeometryObject& object, const PathHints* path = nullptr) const;
410
411private:
412
414 static void countSegmentsOf(SegmentsCounts& counter, const Element& el);
415
422 static std::set<std::size_t> allBoundaryNodes(const SegmentsCounts& segmentsCount);
423
424 template <typename T> // we can't use std::grater as it use >, and we have < only
425 struct greater: public std::function<bool(T, T)> {
426 bool operator()(const T& first, const T& second) const { return second < first; }
427 };
428
437 template<int SEG_DIR, template<class> class Compare>
438 std::set<std::size_t> dirBoundaryNodes(const SegmentsCounts& segmentsCount) const;
439
440 enum class BoundaryDir { LEFT, RIGHT, BOTTOM, TOP, ALL };
441
442 template<BoundaryDir boundaryDir, typename std::enable_if<boundaryDir != BoundaryDir::ALL && int(boundaryDir)%2==0, int>::type = 0>
443 std::set<std::size_t> boundaryNodes(const SegmentsCounts& segmentsCount) const {
444 return dirBoundaryNodes<int(boundaryDir) / 2, greater>(segmentsCount);
445 }
446
447 template<BoundaryDir boundaryDir, typename std::enable_if<boundaryDir != BoundaryDir::ALL && int(boundaryDir)%2==1, int>::type = 0>
448 std::set<std::size_t> boundaryNodes(const SegmentsCounts& segmentsCount) const {
449 return dirBoundaryNodes<int(boundaryDir) / 2, std::less>(segmentsCount);
450 }
451
453 std::set<std::size_t> boundaryNodes(const SegmentsCounts& segmentsCount) const {
454 return allBoundaryNodes(segmentsCount);
455 }
456
457public:
458
464 return Boundary( [](const TriangularMesh2D& mesh, const shared_ptr<const GeometryD<2>>&) {
465 return BoundaryNodeSet(new StdSetBoundaryImpl(allBoundaryNodes(mesh.countSegments())));
466 } );
467 }
468
473 static Boundary getRightBoundary();
474
479 static Boundary getTopBoundary();
480
485 static Boundary getLeftBoundary();
486
491 static Boundary getBottomBoundary();
492
499 return Boundary( [box](const TriangularMesh2D& mesh, const shared_ptr<const GeometryD<2>>&) {
500 return BoundaryNodeSet(new StdSetBoundaryImpl(allBoundaryNodes(mesh.countSegmentsIn(box))));
501 } );
502 }
503
509 static Boundary getRightOfBoundary(const Box2D& box);
510
516 static Boundary getLeftOfBoundary(const Box2D& box);
517
523 static Boundary getTopOfBoundary(const Box2D& box);
524
530 static Boundary getBottomOfBoundary(const Box2D& box);
531
537 static Boundary getAllBoundaryIn(const std::vector<Box2D>& boxes) {
538 return Boundary( [boxes](const TriangularMesh2D& mesh, const shared_ptr<const GeometryD<2>>&) {
539 return BoundaryNodeSet(new StdSetBoundaryImpl(allBoundaryNodes(mesh.countSegmentsIn(boxes))));
540 } );
541 }
542
548 static Boundary getRightOfBoundary(const std::vector<Box2D>& boxes);
549
555 static Boundary getLeftOfBoundary(const std::vector<Box2D>& boxes);
556
562 static Boundary getTopOfBoundary(const std::vector<Box2D>& boxes);
563
569 static Boundary getBottomOfBoundary(const std::vector<Box2D>& boxes);
570
577 return Boundary( [=](const TriangularMesh2D& mesh, const shared_ptr<const GeometryD<2>>& geom) {
578 return BoundaryNodeSet(new StdSetBoundaryImpl(allBoundaryNodes(mesh.countSegmentsIn(*geom, *object))));
579 } );
580 }
581
587 static Boundary getRightOfBoundary(shared_ptr<const GeometryObject> object);
588
595 static Boundary getLeftOfBoundary(shared_ptr<const GeometryObject> object);
596
602 static Boundary getTopOfBoundary(shared_ptr<const GeometryObject> object);
603
609 static Boundary getBottomOfBoundary(shared_ptr<const GeometryObject> object);
610
618 return Boundary( [=](const TriangularMesh2D& mesh, const shared_ptr<const GeometryD<2>>& geom) {
619 return BoundaryNodeSet(new StdSetBoundaryImpl(allBoundaryNodes(mesh.countSegmentsIn(*geom, *object, &path))));
620 } );
621 }
622
630 return path ? getAllBoundaryIn(object, *path) : getAllBoundaryIn(object);
631 }
632
639 static Boundary getRightOfBoundary(shared_ptr<const GeometryObject> object, const PathHints& path);
640
648 return path ? getRightOfBoundary(object, *path) : getRightOfBoundary(object);
649 }
650
657 static Boundary getLeftOfBoundary(shared_ptr<const GeometryObject> object, const PathHints& path);
658
666 return path ? getLeftOfBoundary(object, *path) : getLeftOfBoundary(object);
667 }
668
675 static Boundary getTopOfBoundary(shared_ptr<const GeometryObject> object, const PathHints& path);
676
684 return path ? getTopOfBoundary(object, *path) : getTopOfBoundary(object);
685 }
686
693 static Boundary getBottomOfBoundary(shared_ptr<const GeometryObject> object, const PathHints& path);
694
702 return path ? getBottomOfBoundary(object, *path) : getBottomOfBoundary(object);
703 }
704
705 static Boundary getBoundary(const std::string &boundary_desc);
706
707 static Boundary getBoundary(XMLReader &boundary_desc, Manager &manager);
708
709};
710
711template <>
713
714template <>
716
717extern template PLASK_API std::set<std::size_t> TriangularMesh2D::boundaryNodes<TriangularMesh2D::BoundaryDir::TOP>(const TriangularMesh2D::SegmentsCounts& segmentsCount) const;
718extern template PLASK_API std::set<std::size_t> TriangularMesh2D::boundaryNodes<TriangularMesh2D::BoundaryDir::LEFT>(const TriangularMesh2D::SegmentsCounts& segmentsCount) const;
719extern template PLASK_API std::set<std::size_t> TriangularMesh2D::boundaryNodes<TriangularMesh2D::BoundaryDir::RIGHT>(const TriangularMesh2D::SegmentsCounts& segmentsCount) const;
720extern template PLASK_API std::set<std::size_t> TriangularMesh2D::boundaryNodes<TriangularMesh2D::BoundaryDir::BOTTOM>(const TriangularMesh2D::SegmentsCounts& segmentsCount) const;
721
722
724
726 const TriangularMesh2D* originalMesh;
727
728 public:
729 ElementMesh(const TriangularMesh2D* originalMesh): originalMesh(originalMesh) {}
730
731 LocalCoords at(std::size_t index) const override {
732 return originalMesh->element(index).getMidpoint();
733 }
734
735 std::size_t size() const override {
736 return originalMesh->getElementsCount();
737 }
738
739 const TriangularMesh2D& getOriginalMesh() const { return *originalMesh; }
740
741protected:
742
743 bool hasSameNodes(const MeshD<2> &to_compare) const override;
744};
745
746
747// ------------------ Nearest Neighbor interpolation ---------------------
748
755
757
758 TriangularMesh2DGetterForRtree(const TriangularMesh2D* src_mesh): src_mesh(src_mesh) {}
759
760 result_type operator()(std::size_t index) const {
761 return src_mesh->at(index);
762 }
763};
764
766typedef boost::geometry::index::rtree<
767 std::size_t,
768 boost::geometry::index::quadratic<16>, //??
769 TriangularMesh2DGetterForRtree
770 >
772
773template <typename DstT, typename SrcT>
775{
777
779 const shared_ptr<const TriangularMesh2D>& src_mesh,
780 const DataVector<const SrcT>& src_vec,
781 const shared_ptr<const MeshD<2>>& dst_mesh,
782 const InterpolationFlags& flags);
783
784 DstT at(std::size_t index) const override;
785};
786
787template <typename SrcT, typename DstT>
789 static LazyData<DstT> interpolate(const shared_ptr<const TriangularMesh2D>& src_mesh,
790 const DataVector<const SrcT>& src_vec,
791 const shared_ptr<const MeshD<2>>& dst_mesh,
792 const InterpolationFlags& flags)
793 {
794 if (src_mesh->empty()) throw BadMesh("interpolate", "source mesh empty");
796 typename std::remove_const<SrcT>::type>
797 (src_mesh, src_vec, dst_mesh, flags);
798 }
799
800};
801
812
813
814// ------------------ Barycentric / Linear interpolation ---------------------
815
816template <typename DstT, typename SrcT>
817struct PLASK_API BarycentricTriangularMesh2DLazyDataImpl: public InterpolatedLazyDataImpl<DstT, TriangularMesh2D, const SrcT>
818{
820
822 const shared_ptr<const TriangularMesh2D>& src_mesh,
823 const DataVector<const SrcT>& src_vec,
824 const shared_ptr<const MeshD<2>>& dst_mesh,
825 const InterpolationFlags& flags);
826
827 DstT at(std::size_t index) const override;
828};
829
830template <typename SrcT, typename DstT>
832 static LazyData<DstT> interpolate(const shared_ptr<const TriangularMesh2D>& src_mesh,
833 const DataVector<const SrcT>& src_vec,
834 const shared_ptr<const MeshD<2>>& dst_mesh,
835 const InterpolationFlags& flags)
836 {
837 if (src_mesh->empty()) throw BadMesh("interpolate", "source mesh empty");
839 typename std::remove_const<SrcT>::type>
840 (src_mesh, src_vec, dst_mesh, flags);
841 }
842
843};
844
855
856
857// ------------------ Element mesh Nearest Neighbor interpolation ---------------------
858
859template <typename DstT, typename SrcT>
860struct PLASK_API NearestNeighborElementTriangularMesh2DLazyDataImpl: public InterpolatedLazyDataImpl<DstT, TriangularMesh2D::ElementMesh, const SrcT>
861{
863
865 const shared_ptr<const TriangularMesh2D::ElementMesh>& src_mesh,
866 const DataVector<const SrcT>& src_vec,
867 const shared_ptr<const MeshD<2>>& dst_mesh,
868 const InterpolationFlags& flags);
869
870 DstT at(std::size_t index) const override;
871};
872
873template <typename SrcT, typename DstT>
875 static LazyData<DstT> interpolate(const shared_ptr<const TriangularMesh2D::ElementMesh>& src_mesh,
876 const DataVector<const SrcT>& src_vec,
877 const shared_ptr<const MeshD<2>>& dst_mesh,
878 const InterpolationFlags& flags)
879 {
880 if (src_mesh->empty()) throw BadMesh("interpolate", "source mesh empty");
882 typename std::remove_const<SrcT>::type>
883 (src_mesh, src_vec, dst_mesh, flags);
884 }
885
886};
887
898
899} // namespace plask
900
901#endif // PLASK__TRIANGULAR2D_H