PLaSK library

Loading...
Searching...
No Matches
leaf.cpp
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#include "leaf.hpp"
15#include "cuboid.hpp"
16
17#define PLASK_BLOCK2D_NAME ("block" PLASK_GEOMETRY_TYPE_NAME_SUFFIX_2D)
18#define PLASK_BLOCK3D_NAME ("block" PLASK_GEOMETRY_TYPE_NAME_SUFFIX_3D)
19
20 namespace plask {
21
22 template <int dim>
23 XMLWriter::Element& GeometryObjectLeaf<dim>::SolidMaterial::writeXML(XMLWriter::Element& dest_xml_object, const AxisNames&) const {
24 return material ? dest_xml_object.attr(GeometryReader::XML_MATERIAL_ATTR, material->str()) : dest_xml_object;
25}
26
27 template <int dim>
28 XMLWriter::Element& GeometryObjectLeaf<dim>::GradientMaterial::writeXML(XMLWriter::Element& dest_xml_object,
29 const AxisNames&) const {
30 if (!materialFactory) return dest_xml_object;
31 return dest_xml_object.attr(GeometryReader::XML_MATERIAL_BOTTOM_ATTR, (*materialFactory)(0.0)->str())
32 .attr(GeometryReader::XML_MATERIAL_TOP_ATTR, (*materialFactory)(1.0)->str());
33}
34
35 template <int dim> GeometryReader& GeometryObjectLeaf<dim>::readMaterial(GeometryReader& src) {
36 auto top_attr = src.source.getAttribute(GeometryReader::XML_MATERIAL_TOP_ATTR);
37 auto bottom_attr = src.source.getAttribute(GeometryReader::XML_MATERIAL_BOTTOM_ATTR);
38 if (!top_attr && !bottom_attr) {
39 if (src.source.hasAttribute(GeometryReader::XML_MATERIAL_GRADING_ATTR))
40 src.source.throwException(
41 format("'{}' attribute allowed only for layers with graded material", GeometryReader::XML_MATERIAL_GRADING_ATTR));
42 if (src.materialsAreRequired) {
43 this->setMaterialFast(src.getMaterial(src.source.requireAttribute(GeometryReader::XML_MATERIAL_ATTR)));
44 } else if (plask::optional<std::string> matstr = src.source.getAttribute(GeometryReader::XML_MATERIAL_ATTR))
45 this->setMaterialFast(src.getMaterial(*matstr));
46 } else {
47 double shape = src.source.getAttribute<double>(GeometryReader::XML_MATERIAL_GRADING_ATTR, 1.);
48 if (!src.manager.draft) {
49 if (!top_attr || !bottom_attr)
50 src.source.throwException(format("If '{0}' or '{1}' attribute is given, the other one is also required",
51 GeometryReader::XML_MATERIAL_TOP_ATTR,
52 GeometryReader::XML_MATERIAL_BOTTOM_ATTR));
53 this->setMaterialTopBottomCompositionFast(src.getMixedCompositionFactory(*top_attr, *bottom_attr, shape));
54 } else {
55 if (!top_attr || !bottom_attr)
56 src.manager.pushError(XMLException(src.source,
57 format("If '{0}' or '{1}' attribute is given, the other one is also required",
58 GeometryReader::XML_MATERIAL_TOP_ATTR,
59 GeometryReader::XML_MATERIAL_BOTTOM_ATTR)));
60 this->setMaterialDraftTopBottomCompositionFast(src.getMixedCompositionFactory(*top_attr, *bottom_attr, shape));
61 }
62 }
63 return src;
64}
65
66 template <int dim> GeometryObject::Type GeometryObjectLeaf<dim>::getType() const { return GeometryObject::TYPE_LEAF; }
67
68 template <int dim>
69 shared_ptr<Material> GeometryObjectLeaf<dim>::getMaterial(const typename GeometryObjectLeaf<dim>::DVec& p) const {
70 return this->contains(p) ? materialProvider->getMaterial(*this, p) : shared_ptr<Material>();
71}
72
73/*void GeometryObjectLeaf::getLeafsInfoToVec(std::vector<std::tuple<shared_ptr<const GeometryObject>,
74 GeometryObjectLeaf::Box, GeometryObjectLeaf::DVec> > &dest, const PathHints *path) const { dest.push_back(
75 std::tuple<shared_ptr<const GeometryObject>, Box, DVec>(this->shared_from_this(), this->getBoundingBox(),
76 Primitive<dim>::ZERO_VEC) );
77}*/
78
79 template <int dim>
80 void GeometryObjectLeaf<dim>::getBoundingBoxesToVec(const GeometryObject::Predicate& predicate,
81 std::vector<typename GeometryObjectLeaf<dim>::Box>& dest,
82 const PathHints*) const {
83 if (predicate(*this)) dest.push_back(this->getBoundingBox());
84}
85
86 template <int dim>
87 void GeometryObjectLeaf<dim>::getObjectsToVec(const GeometryObject::Predicate& predicate,
88 std::vector<shared_ptr<const GeometryObject>>& dest,
89 const PathHints* /*path*/) const {
90 if (predicate(*this)) dest.push_back(this->shared_from_this());
91}
92
93 template <int dim>
94 void GeometryObjectLeaf<dim>::getPositionsToVec(const GeometryObject::Predicate& predicate,
95 std::vector<typename GeometryObjectLeaf::DVec>& dest,
96 const PathHints*) const {
97 if (predicate(*this)) dest.push_back(Primitive<dim>::ZERO_VEC);
98}
99
100 template <int dim> bool GeometryObjectLeaf<dim>::hasInSubtree(const GeometryObject& el) const { return &el == this; }
101
102 template <int dim> GeometryObject::Subtree GeometryObjectLeaf<dim>::getPathsTo(const GeometryObject& el, const PathHints*) const {
103 return GeometryObject::Subtree(&el == this ? this->shared_from_this() : shared_ptr<const GeometryObject>());
104}
105
106 template <int dim>
107 GeometryObject::Subtree GeometryObjectLeaf<dim>::getPathsAt(const typename GeometryObjectLeaf<dim>::DVec& point, bool) const {
108 return GeometryObject::Subtree(this->contains(point) ? this->shared_from_this() : shared_ptr<const GeometryObject>());
109}
110
111 template <int dim> shared_ptr<GeometryObject> GeometryObjectLeaf<dim>::getChildNo(std::size_t) const {
112 throw OutOfBoundsException("geometryObjectLeaf::getChildNo", "child_no");
113}
114
115 template <int dim>
116 shared_ptr<const GeometryObject> GeometryObjectLeaf<dim>::changedVersion(const GeometryObject::Changer& changer,
117 Vec<3, double>* translation) const {
118 shared_ptr<GeometryObject> result(const_pointer_cast<GeometryObject>(this->shared_from_this()));
119 changer.apply(result, translation);
120 return result;
121}
122
123 template <int dim>
124 shared_ptr<GeometryObject> GeometryObjectLeaf<dim>::deepCopy(
125 std::map<const GeometryObject*, shared_ptr<GeometryObject>>& copied) const {
126 auto found = copied.find(this);
127 if (found != copied.end()) return found->second;
128 shared_ptr<GeometryObject> result = this->shallowCopy();
129 copied[this] = result;
130 return result;
131}
132
133 template struct PLASK_API GeometryObjectLeaf<2>;
134 template struct PLASK_API GeometryObjectLeaf<3>;
135
136 shared_ptr<GeometryObject> read_block2D(GeometryReader& reader) {
137 shared_ptr<Block<2>> block(new Block<2>());
138 details::setupBlock2D3D(reader, *block);
139 return block;
140}
141
142// shared_ptr<GeometryObject> read_block3D(GeometryReader& reader) {
143// shared_ptr<Block<3>> block(new Block<3>());
144// block->size.lon() = details::readAlternativeAttrs(reader, "d" + reader.getAxisLongName(), "length");
145// details::setupBlock2D3D(reader, *block);
146// return block;
147// }
148
149 template <> void Block<2>::writeXMLAttr(XMLWriter::Element& dest_xml_object, const AxisNames& axes) const {
150 GeometryObjectLeaf<2>::writeXMLAttr(dest_xml_object, axes);
151 materialProvider->writeXML(dest_xml_object, axes)
152 .attr("d" + axes.getNameForTran(), size.tran())
153 .attr("d" + axes.getNameForVert(), size.vert());
154}
155
156 template <> void Block<3>::writeXMLAttr(XMLWriter::Element& dest_xml_object, const AxisNames& axes) const {
157 GeometryObjectLeaf<3>::writeXMLAttr(dest_xml_object, axes);
158 materialProvider->writeXML(dest_xml_object, axes)
159 .attr("d" + axes.getNameForLong(), size.lon())
160 .attr("d" + axes.getNameForTran(), size.tran())
161 .attr("d" + axes.getNameForVert(), size.vert());
162}
163
164 template <int dim> const char* Block<dim>::NAME = dim == 2 ? PLASK_BLOCK2D_NAME : PLASK_BLOCK3D_NAME;
165
166 template <int dim> std::string Block<dim>::getTypeName() const { return NAME; }
167
168 template <int dim> typename Block<dim>::Box Block<dim>::getBoundingBox() const {
169 return Block<dim>::Box(Primitive<dim>::ZERO_VEC, size);
170}
171
172 template <int dim> bool Block<dim>::contains(const typename Block<dim>::DVec& p) const {
173 return this->getBoundingBox().contains(p);
174}
175
176 template <int dim>
177 void Block<dim>::addPointsAlongToSet(std::set<double>& points,
178 Primitive<3>::Direction direction,
179 unsigned max_steps,
180 double min_step_size) const {
181 assert(int(direction) >= 3 - dim && int(direction) <= 3);
182 if (this->materialProvider->isUniform(direction)) {
183 points.insert(0);
184 points.insert(size[size_t(direction) - (3 - dim)]);
185 } else {
186 if (this->max_steps) max_steps = this->max_steps;
187 if (this->min_step_size) min_step_size = this->min_step_size;
188 double length = size[size_t(direction) - (3 - dim)];
189 unsigned steps = min(unsigned(length / min_step_size), max_steps);
190 double step = length / steps;
191 for (unsigned i = 0; i <= steps; ++i) points.insert(i * step);
192 }
193}
194
195 template <>
196 void Block<2>::addLineSegmentsToSet(std::set<typename GeometryObjectD<2>::LineSegment>& segments,
197 unsigned max_steps,
198 double min_step_size) const {
199 typedef typename GeometryObjectD<2>::LineSegment Segment;
200 std::vector<double> pts0, pts1;
201 {
202 std::set<double> ps;
203 addPointsAlongToSet(ps, Primitive<3>::Direction(Primitive<3>::DIRECTION_TRAN), max_steps, min_step_size);
204 pts0.reserve(ps.size());
205 pts0.insert(pts0.end(), ps.begin(), ps.end());
206 }
207 {
208 std::set<double> ps;
209 addPointsAlongToSet(ps, Primitive<3>::Direction(Primitive<3>::DIRECTION_VERT), max_steps, min_step_size);
210 pts1.reserve(ps.size());
211 pts1.insert(pts1.end(), ps.begin(), ps.end());
212 }
213 for (size_t i1 = 0; i1 < pts1.size(); ++i1) {
214 double p1 = pts1[i1];
215 for (size_t i0 = 1; i0 < pts0.size(); ++i0) segments.insert(Segment(DVec(pts0[i0 - 1], p1), DVec(pts0[i0], p1)));
216 }
217 for (size_t i0 = 0; i0 < pts0.size(); ++i0) {
218 double p0 = pts0[i0];
219 for (size_t i1 = 1; i1 < pts1.size(); ++i1) segments.insert(Segment(DVec(p0, pts1[i1 - 1]), DVec(p0, pts1[i1])));
220 }
221}
222
223 template <>
224 void Block<3>::addLineSegmentsToSet(std::set<typename GeometryObjectD<3>::LineSegment>& segments,
225 unsigned max_steps,
226 double min_step_size) const {
227 typedef typename GeometryObjectD<3>::LineSegment Segment;
228 std::vector<double> pts0, pts1, pts2;
229 {
230 std::set<double> ps;
231 addPointsAlongToSet(ps, Primitive<3>::Direction(Primitive<3>::DIRECTION_LONG), max_steps, min_step_size);
232 pts0.reserve(ps.size());
233 pts0.insert(pts0.end(), ps.begin(), ps.end());
234 }
235 {
236 std::set<double> ps;
237 addPointsAlongToSet(ps, Primitive<3>::Direction(Primitive<3>::DIRECTION_TRAN), max_steps, min_step_size);
238 pts1.reserve(ps.size());
239 pts1.insert(pts1.end(), ps.begin(), ps.end());
240 }
241 {
242 std::set<double> ps;
243 addPointsAlongToSet(ps, Primitive<3>::Direction(Primitive<3>::DIRECTION_VERT), max_steps, min_step_size);
244 pts2.reserve(ps.size());
245 pts2.insert(pts2.end(), ps.begin(), ps.end());
246 }
247 for (size_t i2 = 0; i2 < pts2.size(); ++i2) {
248 double p2 = pts1[i2];
249 for (size_t i1 = 0; i1 < pts1.size(); ++i1) {
250 double p1 = pts1[i1];
251 for (size_t i0 = 1; i0 < pts0.size(); ++i0)
252 segments.insert(Segment(DVec(pts0[i0 - 1], p1, p2), DVec(pts0[i0], p1, p2)));
253 }
254 for (size_t i0 = 0; i0 < pts0.size(); ++i0) {
255 double p0 = pts0[i0];
256 for (size_t i1 = 1; i1 < pts1.size(); ++i1)
257 segments.insert(Segment(DVec(p0, pts1[i1 - 1], p2), DVec(p0, pts1[i1], p2)));
258 }
259 }
260 for (size_t i1 = 0; i1 < pts1.size(); ++i1) {
261 double p1 = pts1[i1];
262 for (size_t i0 = 0; i0 < pts0.size(); ++i0) {
263 double p0 = pts0[i0];
264 for (size_t i2 = 1; i2 < pts2.size(); ++i2)
265 segments.insert(Segment(DVec(p0, p1, pts2[i2 - 1]), DVec(p0, p1, pts2[i2])));
266 }
267 }
268}
269
270 template struct PLASK_API Block<2>;
271 template struct PLASK_API Block<3>;
272
273 static GeometryReader::RegisterObjectReader block2D_reader(PLASK_BLOCK2D_NAME, read_block2D);
274 static GeometryReader::RegisterObjectReader rectangle_reader("rectangle", read_block2D);
275 static GeometryReader::RegisterObjectReader block3D_reader(PLASK_BLOCK3D_NAME, read_cuboid);
276
277 namespace detail {
278
279 template <int dim> struct MakeBlockVisitor : public boost::static_visitor<shared_ptr<Block<dim>>> {
280 Vec<dim> size;
281 bool draft;
282
283 MakeBlockVisitor(const Vec<dim>& size, bool draft): size(size), draft(draft) {}
284
285 shared_ptr<Block<dim>> operator()(const shared_ptr<Material>& material) const {
286 return plask::make_shared<Block<dim>>(size, material);
287 }
288
289 shared_ptr<Block<dim>> operator()(const shared_ptr<MaterialsDB::MixedCompositionFactory>& material_factory) const {
290 if (!draft)
291 return plask::make_shared<Block<dim>>(size, material_factory);
292 else {
293 auto result = plask::make_shared<Block<dim>>(size);
294 result->setMaterialDraftTopBottomCompositionFast(material_factory);
295 return result;
296 }
297 }
298};
299
300} // namespace detail
301
302 shared_ptr<GeometryObject> changeToBlock(const SolidOrGradientMaterial& material,
303 const shared_ptr<const GeometryObject>& to_change,
304 Vec<3, double>& translation, bool draft) {
305 if (to_change->getDimensionsCount() == 3) {
306 shared_ptr<const GeometryObjectD<3>> el = static_pointer_cast<const GeometryObjectD<3>>(to_change);
307 Box3D bb = el->getBoundingBox();
308 translation = bb.lower;
309 return boost::apply_visitor(detail::MakeBlockVisitor<3>(bb.size(), draft), material);
310 } else { // to_change->getDimensionsCount() == 3
311 shared_ptr<const GeometryObjectD<2>> el = static_pointer_cast<const GeometryObjectD<2>>(to_change);
312 Box2D bb = el->getBoundingBox();
313 translation = vec<3, double>(bb.lower);
314 return boost::apply_visitor(detail::MakeBlockVisitor<2>(bb.size(), draft), material);
315 }
316}
317
318} // namespace plask