PLaSK library
Loading...
Searching...
No Matches
clip.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 "clip.hpp"
15
16#include "../manager.hpp"
17#include "reader.hpp"
18
19#include <limits>
20
21#define PLASK_CLIP2D_NAME ("clip" PLASK_GEOMETRY_TYPE_NAME_SUFFIX_2D)
22#define PLASK_CLIP3D_NAME ("clip" PLASK_GEOMETRY_TYPE_NAME_SUFFIX_3D)
23
24namespace plask {
25
26template <int dim> const char* Clip<dim>::NAME = dim == 2 ? PLASK_CLIP2D_NAME : PLASK_CLIP3D_NAME;
27
28template <int dim> shared_ptr<Material> Clip<dim>::getMaterial(const typename Clip<dim>::DVec& p) const {
29 return (this->hasChild() && clipBox.contains(p)) ? this->_child->getMaterial(p) : shared_ptr<Material>();
30}
31
32template <int dim> bool Clip<dim>::contains(const typename Clip<dim>::DVec& p) const {
33 return this->hasChild() && clipBox.contains(p) && this->_child->contains(p);
34}
35
36template <int dim>
38 if (this->hasChild() && clipBox.contains(point))
39 return GeometryObject::Subtree::extendIfNotEmpty(this, this->_child->getPathsAt(point, all));
40 else
42}
43
44template <int dim>
46 return child_bbox.intersection(clipBox);
47}
48
49template <int dim>
51 std::vector<DVec>& dest,
52 const PathHints* path) const {
53 this->_getNotChangedPositionsToVec(this, predicate, dest, path);
54}
55
56template <int dim> shared_ptr<GeometryObject> Clip<dim>::shallowCopy() const { return copyShallow(); }
57
58template <int dim>
59void Clip<dim>::addPointsAlongToSet(std::set<double>& points,
61 unsigned max_steps,
62 double min_step_size) const {
63 if (this->_child) {
64 std::set<double> child_points;
65 this->_child->addPointsAlongToSet(child_points, direction, this->max_steps ? this->max_steps : max_steps,
66 this->min_step_size ? this->min_step_size : min_step_size);
67 auto bbox = this->getBoundingBox();
68 points.insert(bbox.lower[int(direction) - (3 - dim)]);
69 for (double p : child_points) {
70 if (clipBox.lower[int(direction) - (3 - dim)] <= p && p <= clipBox.upper[int(direction) - (3 - dim)])
71 points.insert(p);
72 }
73 points.insert(bbox.upper[int(direction) - (3 - dim)]);
74 }
75}
76
77template <int dim>
79 unsigned max_steps,
80 double min_step_size) const {
81 if (this->_child) {
82 std::set<typename GeometryObjectD<dim>::LineSegment> child_segments;
83 this->_child->addLineSegmentsToSet(child_segments, this->max_steps ? this->max_steps : max_steps,
84 this->min_step_size ? this->min_step_size : min_step_size);
85 for (const auto& s : child_segments) {
86 bool in0 = clipBox.contains(s.p0()), in1 = clipBox.contains(s.p1());
87 if (in0 && in1)
88 segments.insert(s);
89 else
90 addClippedSegment(segments, s.p0(), s.p1());
91 }
92 }
93}
94
95inline static void limitT(double& t0, double& t1, double tl[], double th[], int n, int x = -1) {
96 t0 = 0.;
97 t1 = 1.;
98 for (size_t i = 0; i < n; ++i) {
99 if (i == x) continue;
100 double l = tl[i], h = th[i];
101 if (l > h) std::swap(l, h);
102 if (l > t0) t0 = l;
103 if (h < t1) t1 = h;
104 }
105 if (t0 > 1.) t0 = 1.;
106 if (t1 < 0.) t1 = 0.;
107}
108
109template <int dim>
110void Clip<dim>::addClippedSegment(std::set<typename GeometryObjectD<dim>::LineSegment>& segments,
111 DVec p0,
112 DVec p1) const {
113 DVec dp = p1 - p0;
114 double tl[2], tu[2];
115 for (size_t i = 0; i < 2; ++i) {
116 if (dp[i] == 0) {
117 if (clipBox.lower[i] <= p0[i] && p0[0] <= clipBox.upper[i]) {
118 tl[i] = 0.;
119 tu[i] = 1.;
120 } else {
121 tl[i] = tu[i] = 0.5;
122 }
123 } else {
124 tl[i] = (clipBox.lower[i] - p0[i]) / dp[i];
125 tu[i] = (clipBox.upper[i] - p0[i]) / dp[i];
126 }
127 }
128 for (size_t i = 0; i <= dim; ++i) {
129 double t0, t1;
130 limitT(t0, t1, tl, tu, dim, i);
131 if (t1 <= t0) continue;
132 DVec q0 = p0 + dp * t0, q1 = p0 + dp * t1;
133 if (i != dim) {
134 if (dp[i] == 0.) {
135 if (p0[i] < clipBox.lower[i]) {
136 q0[i] = q1[i] = clipBox.lower[i];
137 if (q0 != q1) segments.insert(typename GeometryObjectD<dim>::LineSegment(q0, q1));
138 } else if (p0[i] > clipBox.upper[i]) {
139 q0[i] = q1[i] = clipBox.upper[i];
140 if (q0 != q1) segments.insert(typename GeometryObjectD<dim>::LineSegment(q0, q1));
141 }
142 } else {
143 DVec q0l = (q0[i] <= clipBox.lower[i]) ? q0 : p0 + dp * clamp(tl[i], t0, t1),
144 q1l = (q1[i] <= clipBox.lower[i]) ? q1 : p0 + dp * clamp(tl[i], t0, t1);
145 q0l[i] = q1l[i] = clipBox.lower[i];
146 if (q0l != q1l) segments.insert(typename GeometryObjectD<dim>::LineSegment(q0l, q1l));
147 DVec q0u = (q0[i] >= clipBox.upper[i]) ? q0 : p0 + dp * clamp(tu[i], t0, t1),
148 q1u = (q1[i] >= clipBox.upper[i]) ? q1 : p0 + dp * clamp(tu[i], t0, t1);
149 q0u[i] = q1u[i] = clipBox.upper[i];
150 if (q0u != q1u) segments.insert(typename GeometryObjectD<dim>::LineSegment(q0u, q1u));
151 }
152 } else {
153 if (q0 != q1) segments.insert(typename GeometryObjectD<dim>::LineSegment(q0, q1));
154 }
155 }
156}
157
158template <typename ClipBoxType>
159inline static void writeClip2D3D(XMLWriter::Element& dest_xml_object, const ClipBoxType& clipBox) {
160 if (clipBox.left() > -std::numeric_limits<double>::infinity()) dest_xml_object.attr("left", clipBox.left());
161 if (clipBox.right() < std::numeric_limits<double>::infinity()) dest_xml_object.attr("right", clipBox.right());
162 if (clipBox.bottom() > -std::numeric_limits<double>::infinity()) dest_xml_object.attr("bottom", clipBox.bottom());
163 if (clipBox.top() < std::numeric_limits<double>::infinity()) dest_xml_object.attr("top", clipBox.top());
164}
165
168 writeClip2D3D(dest_xml_object, clipBox);
169}
170
173 writeClip2D3D(dest_xml_object, clipBox);
174 if (clipBox.back() > -std::numeric_limits<double>::infinity()) dest_xml_object.attr("back", clipBox.back());
175 if (clipBox.front() < std::numeric_limits<double>::infinity()) dest_xml_object.attr("front", clipBox.front());
176}
177
178template <typename ClipType> inline static void setupClip2D3D(GeometryReader& reader, ClipType& clip) {
179 clip.clipBox.left() = reader.source.getAttribute<double>("left", -std::numeric_limits<double>::infinity());
180 clip.clipBox.right() = reader.source.getAttribute<double>("right", std::numeric_limits<double>::infinity());
181 clip.clipBox.top() = reader.source.getAttribute<double>("top", std::numeric_limits<double>::infinity());
182 clip.clipBox.bottom() = reader.source.getAttribute<double>("bottom", -std::numeric_limits<double>::infinity());
183 clip.setChild(reader.readExactlyOneChild<typename ClipType::ChildType>());
184}
185
192
196 clip->clipBox.back() = reader.source.getAttribute<double>("back", -std::numeric_limits<double>::infinity());
197 clip->clipBox.front() = reader.source.getAttribute<double>("front", std::numeric_limits<double>::infinity());
198 setupClip2D3D(reader, *clip);
199 return clip;
200}
201
202static GeometryReader::RegisterObjectReader Clip2D_reader(PLASK_CLIP2D_NAME, read_Clip2D);
203static GeometryReader::RegisterObjectReader Clip3D_reader(PLASK_CLIP3D_NAME, read_Clip3D);
204
205template struct PLASK_API Clip<2>;
206template struct PLASK_API Clip<3>;
207
208} // namespace plask