PLaSK library
Loading...
Searching...
No Matches
reader.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 "reader.hpp"
15
16#include "../manager.hpp"
17
18namespace plask {
19
20constexpr const char* const GeometryReader::XML_NAME_ATTR;
21constexpr const char* const GeometryReader::XML_MATERIAL_ATTR;
22constexpr const char* const GeometryReader::XML_MATERIAL_TOP_ATTR;
23constexpr const char* const GeometryReader::XML_MATERIAL_BOTTOM_ATTR;
24constexpr const char* const GeometryReader::XML_MATERIAL_GRADING_ATTR;
25
37
51
55 if (!top_attr && !bottom_attr) {
58 format("'{}' attribute allowed only for layers with graded material", GeometryReader::XML_MATERIAL_GRADING_ATTR));
59 try {
61 } catch (const XMLNoAttrException err) {
64 }
65 } else {
67 if (!manager.draft) {
68 if (!top_attr || !bottom_attr)
69 source.throwException(format("If '{0}' or '{1}' attribute is given, the other one is also required",
72 } else {
73 if (!top_attr || !bottom_attr)
75 XMLException(source, format("If '{0}' or '{1}' attribute is given, the other one is also required",
77 return (*getMixedCompositionFactory(*top_attr, *bottom_attr, shape))(0.5);
78 }
79 }
80}
81
82std::map<std::string, GeometryReader::object_read_f*>& GeometryReader::objectReaders() {
83 static std::map<std::string, GeometryReader::object_read_f*> result;
84 return result;
85}
86
87void GeometryReader::registerObjectReader(const std::string& tag_name, object_read_f* reader) {
88 objectReaders()[tag_name] = reader;
89}
90
91std::map<std::string, GeometryReader::changer_read_f>& GeometryReader::changerReaders() {
92 static std::map<std::string, GeometryReader::changer_read_f> result;
93 return result;
94}
95
97 changerReaders()[tag_name] = reader;
98}
99
101
103
105 : reader(reader), old(reader.expectedSuffix) {
107}
108
117
120
121inline bool isAutoName(const std::string& name) { return !name.empty() && name[0] == '#'; }
122
123#define XML_MAX_STEPS_ATTR "steps-num"
124#define XML_MIN_STEP_SIZE_ATTR "steps-dist"
125
127 std::string nodeName = source.getNodeName();
128
129 if (nodeName == "again") {
132 return result;
133 }
134
136 if (name && !isAutoName(*name)) {
137 std::replace(name->begin(), name->end(), '-', '_');
138 BadId::throwIfBad("geometry object", *name);
139 }
140
141 plask::optional<std::string> roles = source.getAttribute("role"); // read roles (tags)
142
143 auto max_steps = source.getAttribute<unsigned long>(XML_MAX_STEPS_ATTR);
144 auto min_step_size = source.getAttribute<double>(XML_MIN_STEP_SIZE_ATTR);
145
146 shared_ptr<GeometryObject> new_object; // new object that will be constructed
147
148 std::deque<std::pair<std::string, shared_ptr<GeometryObject>>> other_names;
149
150 if (nodeName == "copy") {
152 try {
153 if (auto geometry = dynamic_pointer_cast<Geometry2DCartesian>(from))
154 from = geometry->getExtrusion();
155 else if (auto geometry = dynamic_pointer_cast<Geometry2DCylindrical>(from))
156 from = geometry->getRevolution();
157 else if (auto geometry = dynamic_pointer_cast<Geometry3D>(from))
158 from = geometry->getChild();
159 } catch (const NoChildException&) {
160 from.reset();
161 }
162 if (from) {
164 while (source.requireTagOrEnd()) {
165 const std::string operation_name = source.getNodeName();
166 if (operation_name == "replace") {
169 if (op_from) {
171 if (to_name) {
174 } else {
175 if (source.requireTagOrEnd()) {
176 SetExpectedSuffix suffixSetter(*this, op_from->getDimensionsCount());
177 to = readObject();
179 } else {
181 }
182 }
183 if (to)
184 changers.append(new GeometryObject::ReplaceChanger(op_from, to, vec(0.0, 0.0, 0.0)));
185 else
187 } else
189 } else if (operation_name == "toblock") {
193 if (op_from) {
196 changers.append(changer);
197 if (block_name && !isAutoName(*block_name)) {
198 std::replace(block_name->begin(), block_name->end(), '-', '_');
199 BadId::throwIfBad("block replacing object", *block_name);
200 other_names.push_back(std::make_pair(*block_name, changer->to));
201 }
202 if (plask::optional<std::string> block_roles = source.getAttribute("role")) { // if have some roles
203 for (const std::string& c : splitEscIterator(*block_roles, ',')) changer->to->addRole(c);
204 }
205 }
207 } else if (operation_name == "delete") {
211 } else {
212 auto found = changerReaders().find(operation_name);
213 if (found == changerReaders().end())
214 throw Exception("\"{0}\" is not a proper name of copy operation and so it is not allowed in <copy> tag.",
216 changers.append(found->second(*this));
217 }
218 }
219 new_object = const_pointer_cast<GeometryObject>(from->changedVersion(changers));
220 } else {
222 }
223 } else {
224 Manager::SetAxisNames axis_reader(*this); // try set up new axis names, store old, and restore old on end of block
225 auto reader_it = objectReaders().find(nodeName);
226 if (reader_it == objectReaders().end()) {
229 if (reader_it == objectReaders().end()) throw NoSuchGeometryObjectType(nodeName + "[" + expectedSuffix + "]");
230 }
231 new_object = reader_it->second(*this); // and rest (but while reading this subtree, name is not registered yet)
232 }
233
234 if (!new_object) return new_object;
235
237 for (const auto& other : other_names) {
238 registerObjectName(other.first, other.second);
239 }
240
241 if (roles) { // if have some roles
242 new_object->clearRoles(); // in case of copied object: overwrite
243 auto roles_it = splitEscIterator(*roles, ',');
244 for (const std::string& c : roles_it) {
245 new_object->addRole(c);
246 }
247 }
248
249 if (max_steps) new_object->max_steps = *max_steps;
250 if (min_step_size) new_object->min_step_size = *min_step_size;
251
252 return new_object;
253}
254
266
268 Manager::SetAxisNames axis_reader(*this); // try set up new axis names, store old, and restore old on end of block
269 std::string nodeName = source.getNodeName();
271 if (name) {
272 std::replace(name->begin(), name->end(), '-', '_');
273 BadId::throwIfBad("geometry", *name);
274 if (manager.geometrics.find(*name) != manager.geometrics.end())
275 throw XMLDuplicatedElementException(source, "geometry '" + *name + "'");
276 }
277
278 // TODO read subspaces from XML
280
281 if (nodeName == "cartesian2d") {
283 plask::optional<double> l = source.getAttribute<double>("length");
284 shared_ptr<Geometry2DCartesian> cartesian2d = plask::make_shared<Geometry2DCartesian>(); // result with original type
286 result->setEdges([&](const std::string& s) -> plask::optional<std::string> { return source.getAttribute(s); },
288 if (l) {
290 } else {
292 bool require_end = true;
295 child = readObject();
296 } else {
298 require_end = false;
299 }
301 if (child_as_extrusion) {
302 cartesian2d->setExtrusion(child_as_extrusion);
303 } else {
307 }
309 }
310
311 } else if (nodeName == "cylindrical" || nodeName == "cylindrical2d") {
314 result->setEdges([&](const std::string& s) -> plask::optional<std::string> { return source.getAttribute(s); },
317 bool require_end = true;
320 child = readObject();
321 } else {
323 require_end = false;
324 }
328 } else {
332 }
334
335 } else if (nodeName == "cartesian3d") {
338 result->setEdges([&](const std::string& s) -> plask::optional<std::string> { return source.getAttribute(s); },
341
342 } else
343 throw XMLUnexpectedElementException(source, "geometry tag (<cartesian2d>, <cartesian3d>, or <cylindrical>)");
344
345 result->axisNames = getAxisNames();
346
347 if (name) manager.geometrics[*name] = result;
348 return result;
349}
350
352 if (isAutoName(name)) {
353 auto it = autoNamedObjects.find(name);
354 if (it == autoNamedObjects.end()) {
357 }
358 return it->second;
359 } else {
360 try {
361 return manager.requireGeometryObject(name);
362 } catch (const NoSuchGeometryObject& err) {
365 }
366 }
367}
368
370 if (isAutoName(name)) {
371 if (!autoNamedObjects.insert(std::map<std::string, shared_ptr<GeometryObject>>::value_type(name, object)).second)
372 throw NamesConflictException("auto-named geometry object", name);
373 } else { // normal name
374 if (!manager.geometrics.insert(std::map<std::string, shared_ptr<GeometryObject>>::value_type(name, object)).second)
375 throw NamesConflictException("geometry object", name);
376 }
377}
378
379} // namespace plask