PLaSK library

Loading...
Searching...
No Matches
ellipse.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 "ellipse.hpp"
15#include "../manager.hpp"
16#include "../math.hpp"
17#include "reader.hpp"
18
19#define PLASK_ELLIPSE2D_NAME "ellipse"
20
21 namespace plask {
22
23 const char* Ellipse::NAME = PLASK_ELLIPSE2D_NAME;
24
25std::string Ellipse::getTypeName() const { return NAME; }
26
27 Ellipse::Ellipse(double rx, double ry, const shared_ptr<plask::Material>& material)
28 : GeometryObjectLeaf(material), radius0(std::max(rx, 0.)), radius1(std::max(ry, 0.)) {}
29
30 Ellipse::Ellipse(double rx, double ry, shared_ptr<MaterialsDB::MixedCompositionFactory> materialTopBottom)
31 : GeometryObjectLeaf(materialTopBottom), radius0(std::max(rx, 0.)), radius1(std::max(ry, 0.)) {}
32
33 typename Ellipse::Box Ellipse::getBoundingBox() const { return Ellipse::Box(vec(-radius0, -radius1), vec(radius0, radius1)); }
34
35 bool Ellipse::contains(const typename Ellipse::DVec& p) const {
36 double x = p.c0 / radius0, y = p.c1 / radius1;
37 return x * x + y * y <= 1.;
38}
39
40 void Ellipse::writeXMLAttr(XMLWriter::Element& dest_xml_object, const AxisNames& axes) const {
41 GeometryObjectLeaf::writeXMLAttr(dest_xml_object, axes);
42 this->materialProvider->writeXML(dest_xml_object, axes).attr("radius0", this->radius0).attr("radius1", this->radius1);
43}
44
45 void Ellipse::addPointsAlongToSet(std::set<double>& points,
46 Primitive<3>::Direction direction,
47 unsigned max_steps,
48 double min_step_size) const {
49 assert(int(direction) >= 1 && int(direction) <= 3);
50 double radius = (direction == Primitive<3>::DIRECTION_VERT) ? radius1 : radius0;
51 if (this->max_steps) max_steps = this->max_steps;
52 if (this->min_step_size) min_step_size = this->min_step_size;
53 unsigned steps = min(unsigned(2. * radius / min_step_size), max_steps);
54 double step = 2. * radius / steps;
55 for (unsigned i = 0; i <= steps; ++i) points.insert(i * step - radius);
56}
57
58 void Ellipse::addLineSegmentsToSet(std::set<typename GeometryObjectD<2>::LineSegment>& segments,
59 unsigned max_steps,
60 double min_step_size) const {
61 typedef typename GeometryObjectD<2>::LineSegment Segment;
62 if (this->max_steps) max_steps = this->max_steps;
63 if (this->min_step_size) min_step_size = this->min_step_size;
64 if (materialProvider->isUniform(Primitive<3>::DIRECTION_VERT)) {
65 unsigned steps = min(unsigned(M_PI * min(radius0, radius1) / min_step_size), max_steps);
66 double dphi = M_PI / steps;
67 double x0 = radius0, y0 = 0;
68 for (unsigned i = 1; i <= (steps + 1) / 2; ++i) {
69 double phi = dphi * i;
70 double x1 = radius0 * cos(phi), y1 = radius1 * sin(phi);
71 segments.insert(Segment(DVec(-x0, -y0), DVec(-x1, -y1)));
72 segments.insert(Segment(DVec(x0, -y0), DVec(x1, -y1)));
73 segments.insert(Segment(DVec(-x0, y0), DVec(-x1, y1)));
74 segments.insert(Segment(DVec(x0, y0), DVec(x1, y1)));
75 if (x1 >= 0 && !materialProvider->isUniform(Primitive<3>::DIRECTION_TRAN)) {
76 segments.insert(Segment(DVec(-x1, -y1), DVec(-x1, y1)));
77 segments.insert(Segment(DVec(x1, -y1), DVec(x1, y1)));
78 }
79 x0 = x1;
80 y0 = y1;
81 }
82 } else {
83 // If material is not uniform vertically, we use uniform division in vertical direction
84 unsigned steps = min(unsigned(2. * radius1 / min_step_size), max_steps);
85 double step = 2. * radius1 / steps;
86 double x0 = sqrt(0.5 * step * radius0); // x0 = r sin(φ/2) = r √[(1–cosφ)/2], cosφ = (r-s)/r = 1 – s/r
87 double xr0 = x0 / radius0;
88 double y0 = radius1 * sqrt(1. - xr0 * xr0);
89 segments.insert(Segment(DVec(0., -radius1), DVec(-x0, -y0)));
90 segments.insert(Segment(DVec(0., -radius1), DVec(x0, -y0)));
91 segments.insert(Segment(DVec(0., radius1), DVec(-x0, y0)));
92 segments.insert(Segment(DVec(0., radius1), DVec(x0, y0)));
93 if (!materialProvider->isUniform(Primitive<3>::DIRECTION_TRAN)) {
94 segments.insert(Segment(DVec(-x0, -y0), DVec(-x0, y0)));
95 segments.insert(Segment(DVec(0., -radius1), DVec(0., radius1)));
96 segments.insert(Segment(DVec(x0, -y0), DVec(x0, y0)));
97 }
98 for (unsigned i = 1; i <= (steps + 1) / 2; ++i) {
99 double y1 = radius1 - i * step;
100 double yr1 = y1 / radius1;
101 double x1 = radius0 * sqrt(1. - yr1 * yr1);
102 segments.insert(Segment(DVec(-x1, -y1), DVec(x1, -y1)));
103 segments.insert(Segment(DVec(-x1, y1), DVec(x1, y1)));
104 segments.insert(Segment(DVec(-x0, -y0), DVec(-x1, -y1)));
105 segments.insert(Segment(DVec(x0, -y0), DVec(x1, -y1)));
106 segments.insert(Segment(DVec(-x0, y0), DVec(-x1, y1)));
107 segments.insert(Segment(DVec(x0, y0), DVec(x1, y1)));
108 if (!materialProvider->isUniform(Primitive<3>::DIRECTION_TRAN)) {
109 segments.insert(Segment(DVec(x1, -y1), DVec(x1, y1)));
110 segments.insert(Segment(DVec(-x1, -y1), DVec(-x1, y1)));
111 }
112 x0 = x1;
113 y0 = y1;
114 }
115 }
116}
117
118 shared_ptr<GeometryObject> read_ellipse(GeometryReader& reader) {
119 shared_ptr<Ellipse> ellipse =
120 reader.manager.draft
121 ? plask::make_shared<Ellipse>(reader.source.getAttribute("radius0", 0.0), reader.source.getAttribute("radius1", 0.0))
122 : plask::make_shared<Ellipse>(reader.source.requireAttribute<double>("radius0"),
123 reader.source.requireAttribute<double>("radius1"));
124 ellipse->readMaterial(reader);
125 reader.source.requireTagEnd();
126 return ellipse;
127}
128
129 static GeometryReader::RegisterObjectReader ellipse_reader(PLASK_ELLIPSE2D_NAME, read_ellipse);
130
131} // namespace plask