PLaSK library
Loading...
Searching...
No Matches
lattice.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 "lattice.hpp"
15#include "../manager.hpp"
16#include "reader.hpp"
17
18// used by lattice
19#include <map>
20#include <set>
21#include <utility>
22
23#define PLASK_ARRANGE2D_NAME ("arrange" PLASK_GEOMETRY_TYPE_NAME_SUFFIX_2D)
24#define PLASK_ARRANGE3D_NAME ("arrange" PLASK_GEOMETRY_TYPE_NAME_SUFFIX_3D)
25#define PLASK_LATTICE_NAME "lattice"
26
27namespace plask {
28
29template <int dim> const char* ArrangeContainer<dim>::NAME = dim == 2 ? PLASK_ARRANGE2D_NAME : PLASK_ARRANGE3D_NAME;
30
31template <int dim>
32std::pair<int, int> ArrangeContainer<dim>::bounds(const typename ArrangeContainer<dim>::DVec& vec) const {
33 if (!this->hasChild() || repeat_count == 0) return std::make_pair(1, 0);
34 auto box = _child->getBoundingBox();
35 int hi = repeat_count - 1, lo = 0;
36 for (int i = 0; i != dim; ++i) {
37 if (translation[i] > 0.) {
38 lo = max(1 + int(std::floor((vec[i] - box.upper[i]) / translation[i])), lo);
39 hi = min(int(std::floor((vec[i] - box.lower[i]) / translation[i])), hi);
40 } else if (translation[i] < 0.) {
41 lo = max(1 + int(std::floor((vec[i] - box.lower[i]) / translation[i])), lo);
42 hi = min(int(std::floor((vec[i] - box.upper[i]) / translation[i])), hi);
43 } else if (vec[i] < box.lower[i] || box.upper[i] < vec[i]) {
44 return std::make_pair(1, 0);
45 }
46 }
47 return std::make_pair(lo, hi);
48}
49
50template <int dim> void ArrangeContainer<dim>::warmOverlaping() const {
51 if (warn_overlapping && this->hasChild()) {
52 Box box = this->_child->getBoundingBox();
53 box -= box.lower;
54 if (box.intersects(box + translation)) writelog(LOG_WARNING, "Arrange: item bboxes overlap");
55 }
56}
57
59 Box bbox;
60 if (!this->hasChild()) {
61 bbox.makeInvalid();
62 } else {
63 Box box = _child->getBoundingBox();
64 for (int i = 0; i != dim; ++i) {
65 if (translation[i] >= 0.) {
66 bbox.lower[i] = box.lower[i];
67 bbox.upper[i] = box.upper[i] + (int(repeat_count) - 1) * translation[i];
68 } else {
69 bbox.lower[i] = box.lower[i] + (int(repeat_count) - 1) * translation[i];
70 bbox.upper[i] = box.upper[i];
71 }
72 }
73 }
74 return bbox;
75}
76
79 return getChild()->getBoundingBox();
80}
81
82template <int dim>
84 std::vector<typename ArrangeContainer<dim>::Box>& dest,
85 const PathHints* path) const {
86 if (predicate(*this)) {
87 dest.push_back(getBoundingBox());
88 return;
89 }
90 if (repeat_count == 0 || !this->hasChild()) return;
91 std::size_t old_size = dest.size();
92 _child->getBoundingBoxesToVec(predicate, dest, path);
93 std::size_t new_size = dest.size();
94 for (unsigned r = 1; r < repeat_count; ++r)
95 for (std::size_t i = old_size; i < new_size; ++i) dest.push_back(dest[i] + translation * r);
96}
97
98template <int dim>
101 const PathHints* path) const {
102 if (predicate(*this)) {
103 dest.push_back(this->shared_from_this());
104 return;
105 }
106 if (repeat_count == 0 || !this->hasChild()) return;
107 std::size_t old_size = dest.size();
108 _child->getObjectsToVec(predicate, dest, path);
109 std::size_t new_size = dest.size();
110 for (unsigned r = 1; r < repeat_count; ++r)
111 for (std::size_t i = old_size; i < new_size; ++i) dest.push_back(dest[i]);
112}
113
114template <int dim>
116 std::vector<typename ArrangeContainer<dim>::DVec>& dest,
117 const PathHints* path) const {
118 if (predicate(*this)) {
120 return;
121 }
122 if (repeat_count == 0 || !this->hasChild()) return;
123 std::size_t old_size = dest.size();
124 _child->getPositionsToVec(predicate, dest, path);
125 std::size_t new_size = dest.size();
126 for (unsigned r = 1; r < repeat_count; ++r)
127 for (std::size_t i = old_size; i < new_size; ++i) dest.push_back(dest[i] + translation * r);
128}
129
130template <int dim> bool ArrangeContainer<dim>::contains(const typename ArrangeContainer<dim>::DVec& p) const {
131 if (!this->hasChild()) return false;
132 auto lohi = bounds(p);
133 for (int i = lohi.second; i >= lohi.first; --i)
134 if (_child->contains(p - i * translation)) return true;
135 return false;
136}
137
138template <int dim>
140 if (!this->hasChild()) return shared_ptr<Material>();
141 auto lohi = bounds(p);
142 for (int i = lohi.second; i >= lohi.first; --i)
143 if (auto material = _child->getMaterial(p - i * translation)) return material;
144 return shared_ptr<Material>();
145}
146
147template <int dim> std::size_t ArrangeContainer<dim>::getChildrenCount() const {
148 return this->hasChild() ? repeat_count : 0;
149}
150
152 if (child_no >= getChildrenCount())
153 throw OutOfBoundsException("getChildNo", "child_no", child_no, 0, getChildrenCount() - 1);
154 return plask::make_shared<Translation<dim>>(_child, child_no * translation);
155}
156
157template <int dim> std::size_t ArrangeContainer<dim>::getRealChildrenCount() const {
159}
160
164
165template <int dim>
167 bool all) const {
168 if (!this->hasChild()) return GeometryObject::Subtree();
170 auto lohi = bounds(point);
171 if (all) {
172 for (int i = lohi.first; i <= lohi.second; --i) {
173 GeometryObject::Subtree child_path = _child->getPathsAt(point - i * translation, true);
174 if (!child_path.empty()) result.children.push_back(std::move(child_path));
175 }
176 } else {
177 for (int i = lohi.second; i >= lohi.first; --i) {
178 GeometryObject::Subtree child_path = _child->getPathsAt(point - i * translation, true);
179 if (!child_path.empty()) {
180 result.children.push_back(std::move(child_path));
181 break;
182 }
183 }
184 }
185 if (!result.children.empty()) result.object = this->shared_from_this();
186 return result;
187}
188
190 return plask::make_shared<ArrangeContainer<dim>>(_child, translation, repeat_count);
191}
192
193template <int dim>
198
199template <int dim>
200void ArrangeContainer<dim>::addPointsAlongToSet(std::set<double>& points,
201 Primitive<3>::Direction direction,
202 unsigned max_steps,
203 double min_step_size) const {
204 if (!this->hasChild()) return;
205 std::set<double> child_points;
206 _child->addPointsAlongToSet(child_points, direction, this->max_steps ? this->max_steps : max_steps,
207 this->min_step_size ? this->min_step_size : min_step_size);
208 for (int i = 0; i < repeat_count; ++i) {
209 double trans = i * translation[int(direction) - (3 - dim)];
210 for (double p : child_points) points.insert(p + trans);
211 }
212}
213
214template <int dim>
216 unsigned max_steps,
217 double min_step_size) const {
218 if (!this->hasChild()) return;
219 std::set<typename GeometryObjectD<dim>::LineSegment> child_segments;
220 _child->addLineSegmentsToSet(child_segments, this->max_steps ? this->max_steps : max_steps,
221 this->min_step_size ? this->min_step_size : min_step_size);
222 for (int i = 0; i < repeat_count; ++i) {
223 DVec trans = i * translation;
224 for (const auto& p : child_segments)
225 segments.insert(typename GeometryObjectD<dim>::LineSegment(p[0] + trans, p[1] + trans));
226 }
227}
228
230 BaseClass::writeXMLAttr(dest_xml_object, axes);
231 if (translation.tran() != 0.) dest_xml_object.attr("d" + axes.getNameForTran(), translation.tran());
232 if (translation.vert() != 0.) dest_xml_object.attr("d" + axes.getNameForVert(), translation.vert());
233 dest_xml_object.attr("count", repeat_count);
234 if (warn_overlapping) dest_xml_object.attr("warning", "false");
235}
236
238 BaseClass::writeXMLAttr(dest_xml_object, axes);
239 if (translation.lon() != 0.) dest_xml_object.attr("d" + axes.getNameForLong(), translation.lon());
240 if (translation.tran() != 0.) dest_xml_object.attr("d" + axes.getNameForTran(), translation.tran());
241 if (translation.vert() != 0.) dest_xml_object.attr("d" + axes.getNameForVert(), translation.vert());
242 dest_xml_object.attr("count", repeat_count);
243 if (warn_overlapping) dest_xml_object.attr("warning", "false");
244}
245
249 vec.tran() = reader.source.getAttribute("d" + reader.getAxisTranName(), 0.);
250 vec.vert() = reader.source.getAttribute("d" + reader.getAxisVertName(), 0.);
251 unsigned repeat = reader.source.requireAttribute<unsigned>("count");
252 bool warn = reader.source.getAttribute("warning", true);
253 auto child = reader.readExactlyOneChild<typename ArrangeContainer<2>::ChildType>();
255}
256
260 vec.lon() = reader.source.getAttribute("d" + reader.getAxisLongName(), 0.);
261 vec.tran() = reader.source.getAttribute("d" + reader.getAxisTranName(), 0.);
262 vec.vert() = reader.source.getAttribute("d" + reader.getAxisVertName(), 0.);
263 unsigned repeat = reader.source.requireAttribute<unsigned>("count");
264 bool warn = reader.source.getAttribute("warning", true);
265 auto child = reader.readExactlyOneChild<typename ArrangeContainer<3>::ChildType>();
267}
268
269static GeometryReader::RegisterObjectReader arrange2d_reader(PLASK_ARRANGE2D_NAME, read_arrange2d);
270static GeometryReader::RegisterObjectReader arrange3d_reader(PLASK_ARRANGE3D_NAME, read_arrange3d);
271
274
275struct YEnds {
276 // map: y -> 2*x, each (x, y) is point where shape begins or ends
277 // odd 2*x are for each points between integer coordinates
278 std::map<int, std::set<int>> coords;
279
280 void add_d(int dbl_x, int y) {
281 std::set<int>& dst = coords[y];
282 auto ins_ans = dst.insert(dbl_x);
283 if (!ins_ans.second) { // element was already included
284 dst.erase(ins_ans.first); // we remove it
285 if (dst.empty()) coords.erase(y);
286 }
287 }
288
289 // void add(int x, int y) { add_d(2*x, y); }
290 void add(Vec<2, int> p) { add_d(2 * p.c0, p.c1); }
291};
292
301 const std::vector<std::vector<Vec<2, int>>>& segments;
302
304
305 std::size_t seg_nr;
306 std::ptrdiff_t point_nr;
307
313 SegmentsIterator(const std::vector<std::vector<Vec<2, int>>>& segments)
314 : segments(segments), seg_nr(0), point_nr(-1) {}
315
320 bool next() {
321 if (seg_nr == segments.size()) return false;
322 ++point_nr;
323 if (point_nr == std::ptrdiff_t(segments[seg_nr].size())) { // end of segment?
324 point_nr = 0; // go to next segment
325 do {
326 ++seg_nr;
327 if (seg_nr == segments.size()) return false;
328 } while (segments[seg_nr].empty()); // loop skips empty segments
329 }
331 second = segments[seg_nr][(point_nr + 1) % segments[seg_nr].size()];
332 return true;
333 }
334};
335
337
339 std::vector<Box>& dest,
340 const PathHints* path) const {
341 if (predicate(*this)) {
342 dest.push_back(getBoundingBox());
343 return;
344 }
345 // hide this->child from predicate, delegate calling to its child
346 container->forEachChild([&](const Translation<3>& child) { child.getBoundingBoxesToVec(predicate, dest, path); },
347 path);
348}
349
352 const PathHints* path) const {
353 if (predicate(*this)) {
354 dest.push_back(this->shared_from_this());
355 return;
356 }
357 // hide this->child from predicate, delegate calling to its child
358 container->forEachChild([&](const Translation<3>& child) { child.getObjectsToVec(predicate, dest, path); }, path);
359}
360
362 std::vector<DVec>& dest,
363 const PathHints* path) const {
364 if (predicate(*this)) {
365 dest.push_back(Primitive<3>::ZERO_VEC);
366 return;
367 }
368 // hide this->child from predicate, delegate calling to its child
369 container->forEachChild([&](const Translation<3>& child) { child.getPositionsToVec(predicate, dest, path); }, path);
370}
371
373 if (this == &el) return this->shared_from_this();
374 GeometryObject::Subtree result = container->getPathsTo(el, path);
375 if (result.object) result.object = this->shared_from_this();
376 return result;
377}
378
380 container->clear();
381
382 std::map<int, std::set<int>>
383 result; // coordinates of all (x, y) points inside the polygon in the map: y -> set of x
384 YEnds ends;
385 SegmentsIterator segment(this->segments);
386 while (segment.next()) {
387 if (segment.first.c1 == segment.second.c1) {
388 std::set<int>& dst = result[segment.first.c1];
389 if (segment.first.c0 > segment.second.c0) std::swap(segment.first.c0, segment.second.c0);
390 for (int x = segment.first.c0; x <= segment.second.c0; ++x)
391 dst.insert(x); // we immediately add all points which lie on side
392 } else {
393 result[segment.first.c1].insert(segment.first.c0); // we immediately add all vertexes
394 result[segment.second.c1].insert(segment.second.c0); // we immediately add all vertexes
395
397 if (segment.first.c1 > segment.second.c1) {
398 low_y = segment.second;
399 hi_y = segment.first;
400 } else {
401 low_y = segment.first;
402 hi_y = segment.second;
403 }
404 int dx = hi_y.c0 - low_y.c0;
405 int dy = hi_y.c1 - low_y.c1; // dy > 0
406 for (int y = low_y.c1 + 1; y < hi_y.c1; ++y) {
407 // x = l/m + low_y.c0
408 int l = dx * (y - low_y.c1);
409 int x = l / dy + low_y.c0;
410 int rem = l % dy;
411 if (rem == 0) { // x,y is exactly on side
412 result[y].insert(x); // so we immediately add it
413 ends.add_d(2 * x, y);
414 } else {
415 // here: real x = x + rem / dy and dy>0
416 ends.add_d(rem > 0 ? 2 * x + 1 : 2 * x - 1, y);
417 }
418 }
419 ends.add(hi_y); // add point with higher y to ends
420 }
421 }
422 for (std::pair<const int, std::set<int>>& line : ends.coords) {
423 assert(line.second.size() % 2 == 0);
424 std::set<int>& dst = result[line.first];
425 for (std::set<int>::iterator dblx_it = line.second.begin(); dblx_it != line.second.end(); ++dblx_it) {
426 // we can exclude ends of the segments as they are already included
427 int beg = (*dblx_it + 1) / 2;
428 ++dblx_it; // this is ok because of line.second has even length
429 int end = (*dblx_it + 1) / 2;
430 // add all points from range [beg, end)
431 while (beg != end) {
432 dst.insert(beg);
433 ++beg;
434 }
435 }
436 }
437
438 for (auto& p : result) { // p is pair: set of x's, and one y
439 for (auto x : p.second) {
440 container->addUnsafe(this->_child, x * vec0 + p.first * vec1);
441 }
442 }
443}
444
445void Lattice::addPointsAlongToSet(std::set<double>& points,
446 Primitive<3>::Direction direction,
447 unsigned max_steps,
448 double min_step_size) const {
449 if (!this->hasChild()) return;
450 container->addPointsAlongToSet(points, direction, this->max_steps ? this->max_steps : max_steps,
451 this->min_step_size ? this->min_step_size : min_step_size);
452}
453
455 unsigned max_steps,
456 double min_step_size) const {
457 if (!this->hasChild()) return;
458 container->addLineSegmentsToSet(segments, this->max_steps ? this->max_steps : max_steps,
459 this->min_step_size ? this->min_step_size : min_step_size);
460}
461
464 if (vec0.lon() != 0.) dest_xml_object.attr("a" + axes.getNameForLong(), vec0.lon());
465 if (vec0.tran() != 0.) dest_xml_object.attr("a" + axes.getNameForTran(), vec0.tran());
466 if (vec0.vert() != 0.) dest_xml_object.attr("a" + axes.getNameForVert(), vec0.vert());
467 if (vec1.lon() != 0.) dest_xml_object.attr("b" + axes.getNameForLong(), vec1.lon());
468 if (vec1.tran() != 0.) dest_xml_object.attr("b" + axes.getNameForTran(), vec1.tran());
469 if (vec1.vert() != 0.) dest_xml_object.attr("b" + axes.getNameForVert(), vec1.vert());
470}
471
472#define LATTICE_XML_SEGMENTS_TAG_NAME "segments"
473
476 const AxisNames& axes) const {
477 { // write <segments>
479 bool first = true;
480 for (const std::vector<Vec<2, int>>& s : segments) {
481 if (!first) segments_tag.writeText(" ^\n");
482 first = false;
483 bool first_point = true;
484 for (Vec<2, int> p : s) {
485 if (!first_point) {
486 segments_tag.writeText("; ");
487 }
488 first_point = false;
489 segments_tag.writeText(p[0]).writeText(' ').writeText(p[1]);
490 }
491 }
492 } // </segments>
493 // write child:
495}
496
497void Lattice::setSegments(std::vector<std::vector<Vec<2, int>>> new_segments) {
498 this->segments = std::move(new_segments);
500}
501
505 result->vec0.lon() = reader.source.getAttribute("a" + reader.getAxisLongName(), 0.);
506 result->vec0.tran() = reader.source.getAttribute("a" + reader.getAxisTranName(), 0.);
507 result->vec0.vert() = reader.source.getAttribute("a" + reader.getAxisVertName(), 0.);
508 result->vec1.lon() = reader.source.getAttribute("b" + reader.getAxisLongName(), 0.);
509 result->vec1.tran() = reader.source.getAttribute("b" + reader.getAxisTranName(), 0.);
510 result->vec1.vert() = reader.source.getAttribute("b" + reader.getAxisVertName(), 0.);
512 std::string segments = reader.source.requireTextInCurrentTag();
513 boost::tokenizer<boost::char_separator<char>> tokens(segments, boost::char_separator<char>(" \t\n\r", ";^"));
514 result->segments.emplace_back();
516 for (const std::string& t : tokens) {
517 if (t == ";" || t == "^") { // end of point or segment
518 if (cords_in_current_point != 2) throw Exception("each point must have two coordinates.");
520 if (t == "^") // end of segment, add new one
521 result->segments.emplace_back();
522 } else { // end of point coordinate
523 if (cords_in_current_point == 2)
524 throw Exception("end of point (\";\") or segment (\"^\") was expected, but got \"{0}\".", t);
525 if (cords_in_current_point == 0) result->segments.back().emplace_back();
526 result->segments.back().back()[cords_in_current_point++] = boost::lexical_cast<int>(t);
527 }
528 }
529 result->setChild(reader.readExactlyOneChild<typename Lattice::ChildType>());
530 result->refillContainer();
531 return result;
532}
533
534static GeometryReader::RegisterObjectReader lattice_reader(PLASK_LATTICE_NAME, read_lattice);
535
536} // namespace plask