PLaSK library

Loading...
Searching...
No Matches
container.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__GEOMETRY_CONTAINER_H
15#define PLASK__GEOMETRY_CONTAINER_H
16
21#include <algorithm>
22#include <cmath> //fmod
23#include <vector>
24#include "../utils/metaprog.hpp"
25
26#include "../manager.hpp"
27#include "../utils/string.hpp"
28#include "align.hpp"
29#include "path.hpp"
30#include "reader.hpp"
31
32 namespace plask {
33
41 template <int dim> struct PLASK_API GeometryObjectContainer : public GeometryObjectD<dim> {
43 typedef typename GeometryObjectContainer<dim>::DVec DVec;
44
46 typedef typename GeometryObjectContainer<dim>::Box Box;
47
49 typedef GeometryObjectD<dim> ChildType;
50
52 typedef Translation<dim> TranslationT;
53
55 typedef std::vector<shared_ptr<TranslationT>> TranslationVector;
56
57 protected:
58 TranslationVector children;
59
68 virtual void writeXMLChildAttr(XMLWriter::Element& dest_xml_child_tag,
69 std::size_t child_index,
70 const AxisNames& axes) const;
71
79 virtual shared_ptr<GeometryObject> changedVersionForChildren(
80 std::vector<std::pair<shared_ptr<ChildType>, Vec<3, double>>>& children_after_change,
81 Vec<3, double>* recomended_translation) const = 0;
82
83 public:
90 virtual void writeXML(XMLWriter::Element& parent_xml_object,
91 GeometryObject::WriteXMLCallback& write_cb,
92 AxisNames axes) const override;
93
94 // TODO container should reduce number of generated event from child if have 2 or more same children, for each
95 // children should be connected once
96
98 ~GeometryObjectContainer() {
99 for (auto& c : children) disconnectOnChildChanged(*c);
100 }
101
103 virtual void onChildChanged(const GeometryObject::Event& evt);
104
106 void connectOnChildChanged(Translation<dim>& child);
107
109 void disconnectOnChildChanged(Translation<dim>& child);
110
115 const TranslationVector& getChildrenVector() const { return children; }
116
118 GeometryObject::Type getType() const override { return GeometryObject::TYPE_CONTAINER; }
119
120 bool contains(const DVec& p) const override;
121
122 // TODO to use (impl. is good) or remove
123 /*virtual bool intersects(const Box& area) const {
124 for (auto child: children) if (child->intersects(area)) return true;
125 return false;
126 }*/
127
128 Box getBoundingBox() const override;
129
134 shared_ptr<Material> getMaterial(const DVec& p) const override;
135
136 /*virtual void getLeafsInfoToVec(std::vector< std::tuple<shared_ptr<const GeometryObject>, Box, DVec> >& dest, const
137 PathHints* path = 0) const { if (path) { auto c = path->getTranslationChildren<dim>(*this); if (!c.empty()) { for
138 (auto child: c) child->getLeafsInfoToVec(dest, path); return;
139 }
140 }
141 for (auto child: children) child->getLeafsInfoToVec(dest, path);
142 }*/
143
144 void getBoundingBoxesToVec(const GeometryObject::Predicate& predicate,
145 std::vector<Box>& dest,
146 const PathHints* path = 0) const override;
147
148 void getObjectsToVec(const GeometryObject::Predicate& predicate,
149 std::vector<shared_ptr<const GeometryObject>>& dest,
150 const PathHints* path = 0) const override;
151
152 /*virtual void getLeafsToVec(std::vector< shared_ptr<const GeometryObject> >& dest) const {
153 for (auto child: children) child->getLeafsToVec(dest);
154 }*/
155
156 virtual void getPositionsToVec(const GeometryObject::Predicate& predicate,
157 std::vector<DVec>& dest,
158 const PathHints* path = 0) const override;
159
160 // void extractToVec(const GeometryObject::Predicate &predicate, std::vector< shared_ptr<const GeometryObjectD<dim>
161 // > >& dest, const PathHints *path) const;
162
163 /*virtual std::vector< std::tuple<shared_ptr<const GeometryObject>, DVec> > getLeafsWithTranslations() const {
164 std::vector< std::tuple<shared_ptr<const GeometryObject>, DVec> > result;
165 for (auto child: children) {
166 std::vector< std::tuple<shared_ptr<const GeometryObject>, DVec> > child_leafs_tran =
167 child->getLeafsWithTranslations(); result.insert(result.end(), child_leafs_tran.begin(), child_leafs_tran.end());
168 }
169 return result;
170 }*/
171
172 bool hasInSubtree(const GeometryObject& el) const override;
173
174 template <typename ChildIter>
175 GeometryObject::Subtree findPathsFromChildTo(ChildIter childBegin,
176 ChildIter childEnd,
177 const GeometryObject& el,
178 const PathHints* path = 0) const {
179 GeometryObject::Subtree result;
180 for (auto child_iter = childBegin; child_iter != childEnd; ++child_iter) {
181 GeometryObject::Subtree child_path = (*child_iter)->getPathsTo(el, path);
182 if (!child_path.empty()) result.children.push_back(std::move(child_path));
183 }
184 if (!result.children.empty()) result.object = this->shared_from_this();
185 return result;
186 }
187
188 GeometryObject::Subtree getPathsTo(const GeometryObject& el, const PathHints* path = 0) const override;
189
190 GeometryObject::Subtree getPathsAt(const DVec& point, bool all = false) const override;
191
192 std::size_t getChildrenCount() const override;
193
194 shared_ptr<GeometryObject> getChildNo(std::size_t child_no) const override;
195
201 std::size_t getChildIndex(const shared_ptr<ChildType>& el, const PathHints* path = 0) const;
202
208 std::size_t getChildIndex(const shared_ptr<ChildType>& el, const PathHints& path) const {
209 return getChildIndex(el, &path);
210 }
211
212 /*virtual shared_ptr<TranslationT> getTranslationOfRealChildAt(std::size_t child_no) const {
213 this->ensureIsValidChildNr(child_no);
214 return children[child_no];
215 }*/
216
217 virtual shared_ptr<const GeometryObject> changedVersion(const GeometryObject::Changer& changer,
218 Vec<3, double>* translation = 0) const override;
219
228 virtual bool removeIfTUnsafe(const std::function<bool(const shared_ptr<TranslationT>& c)>& predicate);
229
235 bool removeIfT(const std::function<bool(const shared_ptr<TranslationT>& c)>& predicate);
236
243 bool removeIf(const std::function<bool(const shared_ptr<ChildType>& c)>& predicate) {
244 return removeIfT(
245 [&](const shared_ptr<const TranslationT>& c) { return c->getChild() && predicate(c->getChild()); });
246 }
247
253 bool removeT(shared_ptr<const TranslationT> el) {
254 return removeIfT([&el](const shared_ptr<const TranslationT>& c) { return c == el; });
255 }
256
262 bool remove(shared_ptr<const ChildType> el) {
263 return removeIf([&el](const shared_ptr<const ChildType>& c) { return c == el; });
264 }
265
271 bool remove(const PathHints& hints) {
272 auto cset = hints.getChildren(*this);
273 return removeIfT([&](const shared_ptr<TranslationT>& t) {
274 return cset.find(static_pointer_cast<GeometryObject>(t)) != cset.end();
275 });
276 }
277
285 void removeAtUnsafe(std::size_t index) override;
286
288 void clear() {
289 removeIfT([](const shared_ptr<ChildType>&) { return true; });
290 }
291
299 template <typename UnaryFunction> void forEachChild(UnaryFunction fun, const PathHints* path = nullptr) const {
300 if (path) {
301 auto c = path->getTranslationChildren<dim>(*this);
302 if (!c.empty()) {
303 for (auto child : c) fun(*child);
304 return;
305 }
306 }
307 for (auto child : children) fun(*child);
308 }
309
310 void addPointsAlongToSet(std::set<double>& points,
311 Primitive<3>::Direction direction,
312 unsigned max_steps,
313 double min_step_size) const override;
314
315 void addLineSegmentsToSet(std::set<typename GeometryObjectD<dim>::LineSegment>& segments,
316 unsigned max_steps,
317 double min_step_size) const override;
318};
319
320 PLASK_API_EXTERN_TEMPLATE_STRUCT(GeometryObjectContainer<2>)
321 PLASK_API_EXTERN_TEMPLATE_STRUCT(GeometryObjectContainer<3>)
322
323
332 template <typename ChildParamF, typename WithoutChildParamF>
333 inline void read_children(GeometryReader& reader,
334 ChildParamF child_param_read,
335 WithoutChildParamF without_child_param_read) {
336 while (reader.source.requireTagOrEnd()) {
337 if (reader.source.getNodeName() == "item") {
338 plask::optional<std::string> paths_str = reader.source.getAttribute("path");
339 PathHints::Hint hint = child_param_read(); // this calls readExactlyOneChild
340 if (paths_str) {
341 auto paths = splitEscIterator(*paths_str, ',');
342 for (std::string path : paths) {
343 std::replace(path.begin(), path.end(), '-', '_');
344 BadId::throwIfBad("path", path);
345 reader.manager.pathHints[path].addHint(hint);
346 }
347 }
348 } else {
349 without_child_param_read();
350 }
351 }
352}
353
361 template <typename ParentType, typename ChildAlignerType> struct WithAligners : public ParentType {
362 typedef ChildAlignerType ChildAligner;
363 typedef typename ParentType::TranslationT TranslationT;
364
365 protected:
366 using ParentType::children;
367
368 std::vector<ChildAligner> aligners;
369
371 PathHints::Hint _insertUnsafe(const std::size_t pos, shared_ptr<TranslationT> to_insert, ChildAligner aligner) {
372 this->ensureIsValidInsertPosition(pos, "insertUnsafe");
373 this->children.insert(children.begin() + pos, to_insert);
374 aligners.insert(aligners.begin() + pos, aligner);
375 this->connectOnChildChanged(*to_insert);
376 this->fireChildrenInserted(pos, pos + 1);
377 return PathHints::Hint(this->shared_from_this(), to_insert);
378 }
379
380 PathHints::Hint _insert(const std::size_t pos, shared_ptr<TranslationT> to_insert, ChildAligner aligner) {
381 if (to_insert) this->ensureCanHaveAsChild(*to_insert);
382 return _insertUnsafe(pos, to_insert, aligner);
383 }
384
385 PathHints::Hint _addUnsafe(shared_ptr<TranslationT> to_add, ChildAligner aligner) {
386 this->children.push_back(to_add);
387 aligners.push_back(aligner);
388 this->connectOnChildChanged(*to_add);
389 this->fireChildrenInserted(children.size() - 1, children.size());
390 return PathHints::Hint(this->shared_from_this(), to_add);
391 }
392
393 /*PathHints::Hint _add(shared_ptr<TranslationT> to_add, ChildAligner aligner) {
394 if (to_add) this->ensureCanHaveAsChild(*to_add);
395 this->_addUnsafe(to_add, aligner);
396 return PathHints::Hint(this->shared_from_this(), to_add);
397 }*/
398
399 ChildAligner getAlignerFor(shared_ptr<const TranslationT> child) {
400 auto it = std::find(children.begin(), children.end(), child);
401 return it != children.end() ? aligners[it - children.begin()] : ChildAligner();
402 }
403
404 ChildAligner getAlignerFor(TranslationT& child) {
405 auto it = std::find(children.begin(), children.end(),
406 static_pointer_cast<const TranslationT>(child.shared_from_this()));
407 return it != children.end() ? aligners[it - children.begin()] : ChildAligner();
408 }
409
410 void align(shared_ptr<TranslationT> child) {
411 auto it = std::find(children.begin(), children.end(), child);
412 if (it != children.end()) aligners[it - children.begin()].align(*child);
413 }
414
415 void align(TranslationT* child) { align(static_pointer_cast<TranslationT>(child->shared_from_this())); }
416
417 void align(TranslationT& child) { align(static_pointer_cast<TranslationT>(child.shared_from_this())); }
418
419 public:
421 // using ParentType::ParentType;//this is fine but not implemented in GCC 4.7
422 template <typename... Args> WithAligners(Args&&... args) : ParentType(std::forward<Args>(args)...) {}
423
425 void onChildChanged(const GeometryObject::Event& evt) override {
426 if (evt.isResize()) align(const_cast<TranslationT*>(evt.source<TranslationT>()));
427 ParentType::onChildChanged(evt);
428 }
429
430 bool removeIfTUnsafe(const std::function<bool(const shared_ptr<TranslationT>& c)>& predicate) override {
431 auto dst = this->children.begin();
432 auto al_dst = aligners.begin();
433 auto al_src = aligners.begin();
434 for (auto i : children) {
435 if (predicate(i)) this->disconnectOnChildChanged(*i);
436 else {
437 *dst++ = i;
438 *al_dst++ = std::move(*al_src);
439 }
440 ++al_src;
441 }
442 if (dst != children.end()) {
443 children.erase(dst, children.end());
444 aligners.erase(al_dst, aligners.end());
445 return true;
446 } else
447 return false;
448 }
449
450 void removeAtUnsafe(std::size_t index) override {
451 ParentType::removeAtUnsafe(index);
452 aligners.erase(aligners.begin() + index);
453 }
454
455 void writeXMLChildAttr(XMLWriter::Element& dest_xml_child_tag,
456 std::size_t child_index,
457 const AxisNames& axes) const override {
458 aligners[child_index].writeToXML(dest_xml_child_tag, axes);
459 }
460
466 void move(std::size_t index, ChildAligner aligner) {
467 this->ensureIsValidChildNr(index, "move", "index");
468 aligners[index] = aligner;
469 aligners[index].align(*children[index]);
470 this->fireChildrenChanged(); // or children[child_no]->fireChanged();??
471 }
472
478 void move(shared_ptr<const TranslationT> child, ChildAligner aligner) {
479 auto it = std::find(children.begin(), children.end(), child);
480 if (it != children.end()) move(it - children.begin(), aligner);
481 }
482
488 void move(const TranslationT& child, ChildAligner aligner) {
489 move(static_pointer_cast<const TranslationT>(child.shared_from_this()), aligner);
490 }
491
495 const std::vector<ChildAligner>& getAligners() const {
496 return aligners;
497 }
498};
499
500} // namespace plask
501
502#endif // PLASK__GEOMETRY_CONTAINER_H