PLaSK library
Loading...
Searching...
No Matches
align.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_ALIGN_H
15#define PLASK__GEOMETRY_ALIGN_H
16
21#include "transform.hpp"
22#include <boost/lexical_cast.hpp>
23#include "../utils/xml.hpp"
24#include "../memory.hpp"
25#include "../utils/metaprog.hpp"
26
27namespace plask {
28
29namespace align {
30
35
37template <Direction direction>
39 //static_assert(false, "given 3D direction cannot be converted to 2D direction");
40};
41
42template <>
43struct DirectionTo2D<Primitive<3>::DIRECTION_TRAN> {
44 enum { value = 0 };
45};
46
47template <>
48struct DirectionTo2D<Primitive<3>::DIRECTION_VERT> {
49 enum { value = 1 };
50};
51
52
59template <Direction _direction>
60struct AlignerImpl: public Printable {
61
64
66 double coordinate;
67
73
74 virtual ~AlignerImpl() {}
75
81 virtual double getAlign(double low, double hi) const = 0;
82
87 virtual bool useBounds() const { return true; }
88
96 inline double align(Translation<3>& toAlign, const Box3D& childBoundingBox) const {
97 return toAlign.translation[direction] = this->getAlign(childBoundingBox.lower[direction], childBoundingBox.upper[direction]);
98 }
99
106 virtual double align(Translation<3>& toAlign) const {
107 if (this->useBounds() && toAlign.getChild())
108 return align(toAlign, toAlign.getChild()->getBoundingBox());
109 else
110 return toAlign.translation[direction] = this->getAlign(0.0, 0.0);
111 }
112
118 virtual std::string key(const AxisNames& axis_names) const = 0;
119
125 std::map<std::string,double> asDict(const AxisNames& axis_names) const {
126 std::map<std::string,double> dict;
127 dict[key(axis_names)] = this->coordinate;
128 return dict;
129 }
130
137 dest.attr(key(axis_names), this->coordinate);
138 }
139
140};
141
142template <Direction _direction>
143struct AlignerBase: public HolderRef<AlignerImpl<_direction>> {
144
146
148
151
156 double getCoordinate() const { return this->held->coordinate; }
157
163 double getAlign(double low, double hi) const { return this->held->getAlign(low, hi); }
164
169 bool useBounds() const { return this->held->useBounds(); }
170
179 return this->held->align(toAlign, childBoundingBox);
180 }
181
188 virtual double align(Translation<3>& toAlign) const {
189 return this->held->align(toAlign);
190 }
191
197 virtual std::string key(const AxisNames& axis_names) const { return this->held->key(axis_names); }
198
204 std::map<std::string,double> asDict(const AxisNames& axis_names) const {
205 return this->held->asDict(axis_names);
206 }
207
208
215 this->held->writeToXML(dest, axis_names);
216 }
217
224 friend inline std::ostream& operator<<(std::ostream& out, const AlignerBase<_direction>& to_print) {
225 return out << *to_print.held;
226 }
227
232 std::string str() const { return this->held; }
233
234};
235
236template <Direction... directions> struct Aligner;
237
241template <Direction _direction>
242struct Aligner<_direction>: public AlignerBase<_direction> {
243
244 static const Direction direction = _direction;
245
246 enum { direction2D = DirectionTo2D<_direction>::value };
247
249
250 Aligner<_direction>(AlignerImpl<_direction>* impl): AlignerBase<_direction>(impl) {}
251
252 using AlignerBase<_direction>::align;
253
262 toAlign.translation[direction2D] = this->getAlign(childBoundingBox.lower[direction2D], childBoundingBox.upper[direction2D]);
263 }
264
272 if (this->useBounds() && toAlign.getChild())
273 this->align(toAlign, toAlign.getChild()->getBoundingBox());
274 else
275 toAlign.translation[direction2D] = this->getAlign(0.0, 0.0);
276 }
277
278};
279
280template <>
281struct Aligner<Primitive<3>::DIRECTION_LONG>: public AlignerBase<Primitive<3>::DIRECTION_LONG> {
283 Aligner(AlignerImpl<direction>* impl): AlignerBase<Primitive<3>::DIRECTION_LONG>(impl) {}
284};
285
286namespace details {
287
291template <Direction direction>
292struct PositionAlignerImpl: public AlignerImpl<direction> {
293
294 PositionAlignerImpl(double translation): AlignerImpl<direction>(translation) {}
295
296 double getAlign(double PLASK_UNUSED(low), double PLASK_UNUSED(hi)) const override {
297 return this->coordinate;
298 }
299
300 bool useBounds() const override { return false; }
301
302 void print(std::ostream& out) const override { out << "align object position along axis " << direction << " to " << this->coordinate; }
303
304 std::string key(const AxisNames& axis_names) const override { return axis_names[direction]; }
305};
306
307} // namespace details
308
312template <Direction _direction1, Direction _direction2>
314
315 static_assert(_direction1 < _direction2, "Wrong Aligner template parameters, two different directions are required and first direction must have lower index than second one. Try swapping Aligner template parameters.");
316
319
321
323
326
327 /* Aligner(const Aligner<direction1, direction2>& toCopy)
328 : dir1aligner(toCopy.dir1aligner->clone()), dir2aligner(toCopy.dir2aligner->clone()) {}
329
330 Aligner(const Aligner<direction2, direction1>& toCopy)
331 : dir1aligner(toCopy.dir2aligner->clone()), dir2aligner(toCopy.dir1aligner->clone()) {}
332
333 Aligner(Aligner<direction1, direction2>&& toMove)
334 : dir1aligner(toMove.dir1aligner), dir2aligner(toMove.dir2aligner) {
335 toMove.dir1aligner = 0; toMove.dir2aligner = 0;
336 }
337
338 Aligner(Aligner<direction2, direction1>&& toMove)
339 : dir1aligner(toMove.dir2aligner), dir2aligner(toMove.dir1aligner) {
340 toMove.dir1aligner = 0; toMove.dir2aligner = 0;
341 }*/
342
347 bool useBounds() const { return dir1aligner.useBounds() || dir2aligner.useBounds(); }
348
356 virtual void align(Translation<3>& toAlign, const Box3D& childBoundingBox) const {
357 toAlign.translation[direction1] =
359 toAlign.translation[direction2] =
361 }
362
369 virtual void align(Translation<3>& toAlign) const {
370 if (useBounds() && toAlign.getChild())
371 align(toAlign, toAlign.getChild()->getBoundingBox());
372 else {
373 toAlign.translation[direction1] = dir1aligner.getAlign(0.0, 0.0);
374 toAlign.translation[direction2] = dir2aligner.getAlign(0.0, 0.0);
375 }
376 }
377
384 friend inline std::ostream& operator<<(std::ostream& out, const Aligner<_direction1,_direction2>& to_print) {
385 return out << to_print.dir1aligner << ", " << to_print.dir2aligner;
386 }
387
392 std::string str() const { return boost::lexical_cast<std::string>(*this); }
393
399 virtual std::map<std::string,double> asDict(const AxisNames& axis_names) const {
400 std::map<std::string,double> dict;
401 dict[dir1aligner.key(axis_names)] = dir1aligner.getCoordinate();
402 dict[dir2aligner.key(axis_names)] = dir2aligner.getCoordinate();
403 return dict;
404 }
405
411 virtual void writeToXML(XMLElement& dest, const AxisNames& axis_names) const {
412 dir1aligner.writeToXML(dest, axis_names);
413 dir2aligner.writeToXML(dest, axis_names);
414 }
415
416 bool isNull() { return dir1aligner.isNull() || dir2aligner.isNull(); }
417
418};
419
423template <Direction _direction1, Direction _direction2>
424struct Aligner<_direction1, _direction2>: public AlignerBase2D<_direction1, _direction2> {
425
427
428 Aligner(const Aligner<_direction1>& dir1aligner, const Aligner<_direction2>& dir2aligner)
429 : AlignerBase2D<_direction1, _direction2>(dir1aligner, dir2aligner) {}
430
431};
432
438template <>
439struct Aligner<Primitive<3>::DIRECTION_TRAN, Primitive<3>::DIRECTION_VERT>: public AlignerBase2D<Primitive<3>::DIRECTION_TRAN, Primitive<3>::DIRECTION_VERT> {
440
442
444 : AlignerBase2D<Primitive<3>::DIRECTION_TRAN, Primitive<3>::DIRECTION_VERT>(dir1aligner, dir2aligner) {}
445
447
456 toAlign.translation[0] = this->dir1aligner.getAlign(childBoundingBox.lower[0], childBoundingBox.upper[0]);
457 toAlign.translation[1] = this->dir2aligner.getAlign(childBoundingBox.lower[1], childBoundingBox.upper[1]);
458 }
459
467 if (this->useBounds() && toAlign.getChild())
468 this->align(toAlign, toAlign.getChild()->getBoundingBox());
469 else {
470 toAlign.translation[0] = this->dir1aligner.getAlign(0.0, 0.0);
471 toAlign.translation[1] = this->dir2aligner.getAlign(0.0, 0.0);
472 }
473 }
474
475};
476
478
482template <>
484
488
490
492 : dir1aligner(dir1aligner), dir2aligner(dir2aligner), dir3aligner(dir3aligner) {}
493
498 bool useBounds() const { return dir1aligner.useBounds() || dir2aligner.useBounds() || dir3aligner.useBounds(); }
499
507 virtual void align(Translation<3>& toAlign, const Box3D& childBoundingBox) const {
508 toAlign.translation[0] = dir1aligner.getAlign(childBoundingBox.lower[0], childBoundingBox.upper[0]);
509 toAlign.translation[1] = dir2aligner.getAlign(childBoundingBox.lower[1], childBoundingBox.upper[1]);
510 toAlign.translation[2] = dir3aligner.getAlign(childBoundingBox.lower[2], childBoundingBox.upper[2]);
511 }
512
519 virtual void align(Translation<3>& toAlign) const {
520 if (useBounds() && toAlign.getChild())
521 align(toAlign, toAlign.getChild()->getBoundingBox());
522 else {
523 toAlign.translation[0] = dir1aligner.getAlign(0.0, 0.0);
524 toAlign.translation[1] = dir2aligner.getAlign(0.0, 0.0);
525 toAlign.translation[2] = dir3aligner.getAlign(0.0, 0.0);
526 }
527 }
528
535 friend inline std::ostream& operator<<(std::ostream& out, const Aligner<Primitive<3>::Direction(0), Primitive<3>::Direction(1), Primitive<3>::Direction(2)>& to_print) {
536 return out << to_print.dir1aligner << ", " << to_print.dir2aligner << ", " << to_print.dir3aligner;
537 }
538
543 std::string str() const { return boost::lexical_cast<std::string>(*this); }
544
550 virtual std::map<std::string,double> asDict(const AxisNames& axis_names) const {
551 std::map<std::string,double> dict;
552 dict[dir1aligner.key(axis_names)] = dir1aligner.getCoordinate();
553 dict[dir2aligner.key(axis_names)] = dir2aligner.getCoordinate();
554 dict[dir3aligner.key(axis_names)] = dir3aligner.getCoordinate();
555 return dict;
556 }
557
563 virtual void writeToXML(XMLElement& dest, const AxisNames& axis_names) const {
564 dir1aligner.writeToXML(dest, axis_names);
565 dir2aligner.writeToXML(dest, axis_names);
566 dir3aligner.writeToXML(dest, axis_names);
567 }
568
569 bool isNull() { return dir1aligner.isNull() || dir2aligner.isNull() || dir3aligner.isNull(); }
570
571};
572
573
574
576
578template <int dim> using AlignerD = typename chooseType<dim-2, Aligner2D, Aligner3D>::type;
579
580//two 1D aligners gives 2D aligner
582 return Aligner<Primitive<3>::Direction(0), Primitive<3>::Direction(1)>(dir1aligner, dir2aligner);
583}
584
586 return Aligner<Primitive<3>::Direction(0), Primitive<3>::Direction(1)>(dir2aligner, dir1aligner);
587}
588
590 return Aligner<Primitive<3>::Direction(0), Primitive<3>::Direction(2)>(dir1aligner, dir2aligner);
591}
592
594 return Aligner<Primitive<3>::Direction(0), Primitive<3>::Direction(2)>(dir2aligner, dir1aligner);
595}
596
598 return Aligner<Primitive<3>::Direction(1), Primitive<3>::Direction(2)>(dir1aligner, dir2aligner);
599}
600
602 return Aligner<Primitive<3>::Direction(1), Primitive<3>::Direction(2)>(dir2aligner, dir1aligner);
603}
604
605//1D aligner & 2D aligner = 3D aligner
609
613
615 return Aligner3D(dir02aligner.dir1aligner, dir1aligner, dir02aligner.dir2aligner);
616}
617
619 return dir02aligner & dir1aligner;
620}
621
623 return Aligner3D(dir01aligner.dir1aligner, dir01aligner.dir2aligner, dir2aligner);
624}
625
627 return dir01aligner & dir2aligner;
628}
629
630
631namespace details {
632
633typedef double alignStrategy(double lo, double hi, double coordinate);
634inline double lowToCoordinate(double lo, double /*hi*/, double coordinate) { return coordinate -lo; }
635inline double hiToCoordinate(double /*lo*/, double hi, double coordinate) { return coordinate -hi; }
636inline double centerToCoordinate(double lo, double hi, double coordinate) { return coordinate -(lo+hi)/2.0; }
637
638struct LEFT { static constexpr const char* value = "left"; };
639struct RIGHT { static constexpr const char* value = "right"; };
640struct FRONT { static constexpr const char* value = "front"; };
641struct BACK { static constexpr const char* value = "back"; };
642struct TOP { static constexpr const char* value = "top"; };
643struct BOTTOM { static constexpr const char* value = "bottom"; };
644struct TRAN_CENTER { static constexpr const char* value = "trancenter"; };
645struct LON_CENTER { static constexpr const char* value = "longcenter"; };
646struct VERT_CENTER { static constexpr const char* value = "vertcenter"; };
647
648template <Direction direction, alignStrategy strategy, typename name_tag>
649struct AlignerCustomImpl: public AlignerImpl<direction> {
650
652
653 double getAlign(double low, double hi) const override {
654 return strategy(low, hi, this->coordinate);
655 }
656
657 /*virtual AlignerImpl<direction, strategy, name_tag>* clone() const {
658 return new AlignerImpl<direction, strategy, name_tag>(this->coordinate);
659 }*/
660
661 void print(std::ostream& out) const override { out << "align " << name_tag::value << " to " << this->coordinate; }
662
663 std::string key(const AxisNames& /*axis_names*/) const override { return name_tag::value; }
664};
665
666} // namespace details
667
668// 1D tran. aligners:
674
675// 1D long. aligners:
680
681// 1D vert. aligners:
686
688 return tran(v.tran()) & vert(v.vert());
689}
690
692 return lon(v.lon()) & tran(v.tran()) & vert(v.vert());
693}
694
697
705
706typedef std::function<plask::optional<double>(const std::string& name)> Dictionary;
707
708namespace details {
712}
713
723template <Direction direction>
725
726template <>
729}
730
731template <>
734}
735
736template <>
739}
740
750template <Direction direction>
754
765template <Direction direction>
771
778 plask::optional<double> operator()(const std::string& s) const { return reader.getAttribute<double>(s); }
779};
780
781template <Direction direction>
782inline Aligner<direction> fromXML(const XMLReader& reader, const std::string& axis_name) {
784}
785
786template <Direction direction>
788 return fromXML<direction>(reader, axis_names[direction]);
789}
790
791template <Direction direction>
792inline Aligner<direction> fromXML(const XMLReader& reader, const AxisNames& axis_names, Aligner<direction> default_aligner) {
793 return fromDictionary<direction>(DictionaryFromXML(reader), axis_names, default_aligner);
794}
795
805template <Direction direction1, Direction direction2>
808 if (a1.isNull()) throw Exception("no aligner for axis{0} defined.", direction1);
810 if (a2.isNull()) throw Exception("no aligner for axis{0} defined.", direction2);
812}
813
823template <Direction direction1, Direction direction2>
827
837template <Direction direction1, Direction direction2>
841
851template <Direction direction1, Direction direction2>
855
865template <Direction direction1, Direction direction2, Direction direction3>
868 if (a0.isNull()) throw Exception("no aligner for axis{0} defined.", 0);
870 if (a1.isNull()) throw Exception("no aligner for axis{0} defined.", 1);
872 if (a2.isNull()) throw Exception("no aligner for axis{0} defined.", 2);
873 return Aligner3D(a0, a1, a2);
874}
875
885template <Direction direction1, Direction direction2, Direction direction3>
886inline Aligner3D fromXML(const XMLReader& reader, const AxisNames& axes) {
888}
889
899template <Direction direction1, Direction direction2, Direction direction3>
903
913template <Direction direction1, Direction direction2, Direction direction3>
917
931template <typename TranslationT, typename Aligner1T, typename Aligner2T>
932void align(TranslationT& toAlign, const Aligner1T& aligner1, const Aligner2T& aligner2) {
933 if ((aligner1.useBounds() || aligner2.useBounds()) && toAlign.getChild()) {
934 auto bb = toAlign.getChild()->getBoundingBox();
935 aligner1.align(toAlign, bb);
936 aligner2.align(toAlign, bb);
937 } else {
938 aligner1.align(toAlign);
939 aligner2.align(toAlign);
940 }
941}
942
943} // namespace align
944} // namespace plask
945
946#endif // PLASK__GEOMETRY_ALIGN_H