Bembel
 
Loading...
Searching...
No Matches
GeometryIGS.hpp
1// This file is part of Bembel, the higher order C++ boundary element library.
2//
3// Copyright (C) 2024 see <http://www.bembel.eu>
4//
5// It was written as part of a cooperation of J. Doelz, H. Harbrecht, S. Kurz,
6// M. Multerer, S. Schoeps, and F. Wolf at Technische Universitaet Darmstadt,
7// Universitaet Basel, and Universita della Svizzera italiana, Lugano. This
8// source code is subject to the GNU General Public License version 3 and
9// provided WITHOUT ANY WARRANTY, see <http://www.bembel.eu> for further
10// information.
11
12#ifndef BEMBEL_SRC_GEOMETRY_GEOMETRYIGS_HPP_
13#define BEMBEL_SRC_GEOMETRY_GEOMETRYIGS_HPP_
14
15namespace Bembel {
16
25std::vector<Patch> LoadGeometryFileIGS(const std::string& file_name) noexcept {
26 std::ifstream file;
27 std::vector<int> patch_lines;
28 file.open(file_name);
29 if (!file) {
30 std::cerr << "File " << file_name << " doesn't exist!";
31 exit(1);
32 }
33 std::string row;
34 getline(file, row);
35
36 if (row[72] != 'S') {
37 std::cerr << "Format of the file not supported! I assume that character 72 "
38 "denotes the section";
39 exit(1);
40 }
41 // character 72 denotes the section and the information starts in Section D
42 while (row[72] != 'D') {
43 getline(file, row);
44 assert(!file.eof() && "End of file should not be found here!");
45 }
46
47 // collect two lines info of each patch from Directory section
48 while (row[72] != 'P') {
49 std::stringstream iss;
50 std::string word;
51 std::vector<int> info1, info2;
52 iss.str(row);
53 while (iss >> word) {
54 info1.push_back(std::stoi(word));
55 }
56 assert(info1[0] == 128 && "Entry type must be NURBS surface!");
57 // this info1 in not going to be used further
58
59 getline(file, row);
60 iss.clear();
61 iss.str(row);
62 while (iss >> word) {
63 info2.push_back(std::stoi(word));
64 }
65 getline(file, row);
66 // This entry denotes how many lines correspond to a patch
67 patch_lines.push_back(info2[3]);
68 assert(!file.eof() && "End of file should not be found here!");
69 }
70
71 // main loop over patches
72 std::vector<Patch> out;
73 out.reserve(patch_lines.size());
74 const int number_of_patches = patch_lines.size();
75 for (auto i = 0; i < number_of_patches; ++i) {
76 std::stringstream iss;
77 std::string word;
78 std::vector<double> data;
79 for (auto j = 0; j < patch_lines[i]; ++j) {
80 // characters 0 to 63 contain data
81 std::string raw_data = row.substr(0, 64);
82 raw_data.erase(std::remove(raw_data.begin(), raw_data.end(), ' '),
83 raw_data.end());
84
85 iss.str(raw_data);
86 while (std::getline(iss, word, ',')) {
87 data.push_back(atof(word.c_str()));
88 }
89 iss.clear();
90
91 getline(file, row);
92 }
93
94 const int K1 = data[1];
95 const int K2 = data[2];
96 const int M1 = data[3];
97 const int M2 = data[4];
98
99 const int N1 = 1 + K1 - M1;
100 const int N2 = 1 + K2 - M2;
101 const int A = N1 + 2 * M1;
102 const int B = N2 + 2 * M2;
103 const int C = (1 + K1) * (1 + K2);
104
105 // The data of the first entries is read and not needed any more
106 data.erase(data.begin(), data.begin() + 10);
107
108 // the + 1 is necessary because the construct excludes the last iterator
109 std::vector<double> tempknt1(data.begin(), data.begin() + A + 1);
110 std::vector<double> tempknt2(data.begin() + A + 1,
111 data.begin() + A + B + 2);
112
113 const int M = K2 + 1;
114 const int N = K1 + 1;
115
116 Eigen::MatrixXd weights(M, N);
117 auto it_weights = data.begin() + A + B + 2;
118 for (auto entry = it_weights; entry != it_weights + C; ++entry) {
119 int index = entry - it_weights;
120 weights((int)index / N, index % N) = *entry;
121 }
122
123 Eigen::MatrixXd x_coordinates(M, N);
124 Eigen::MatrixXd y_coordinates(M, N);
125 Eigen::MatrixXd z_coordinates(M, N);
126 auto it_points = data.begin() + A + B + C + 2;
127 for (auto entry = it_points; entry != it_points + 3 * C; entry += 3) {
128 int index = (int)(entry - it_points) / 3;
129 x_coordinates((int)index / N, index % N) = *entry;
130 y_coordinates((int)index / N, index % N) = *(entry + 1);
131 z_coordinates((int)index / N, index % N) = *(entry + 2);
132 }
133
134 // we need to transfer to homogeneous coordinates
135 x_coordinates = x_coordinates.cwiseProduct(weights);
136 y_coordinates = y_coordinates.cwiseProduct(weights);
137 z_coordinates = z_coordinates.cwiseProduct(weights);
138
139 std::vector<Eigen::MatrixXd> tmp = {x_coordinates, y_coordinates,
141
144 out.push_back(tempPatch);
145 }
146 file.close();
147 return out;
148}
149
158void writeSection(std::string file_name,
159 const std::vector<std::string>& section,
160 const char section_char) {
161 std::ofstream file(file_name, std::ios::app);
162 for (auto it = section.begin(); it != section.end(); ++it) {
163 const int index = std::distance(section.begin(), it);
164 file << std::left << std::setw(72) << *it << section_char << std::right
165 << std::setw(7) << index + 1 << "\n";
166 }
167 file.close();
168 return;
169}
170
182 const std::vector<std::string>& section,
183 const int patch_idx, const int start_count) {
184 std::ofstream file(file_name, std::ios::app);
186 for (auto it = section.begin(); it != section.end(); ++it) {
187 file << std::left << std::setw(64) << *it
188 << std::right << std::setw(8) << patch_idx << "P"
189 << std::right << std::setw(7) << last_line << "\n";
190 ++last_line;
191 }
192 file.close();
193 return last_line;
194}
195
205std::vector<std::string> makeSection(std::vector<std::string> data,
206 const int linewidth = 72) {
207 std::vector<std::string> out;
208 out.reserve(data.size());
209
210 std::string line = "";
211 const int number_of_entries = data.size();
212 for (auto i = 0; i < number_of_entries; ++i) {
213 std::string item = data[i];
214 if (i < number_of_entries - 1)
215 item += ",";
216 else
217 item += ";";
218
219 const int line_length = line.length() + item.length();
220 if (line_length > linewidth) {
221 out.push_back(line);
222 line = "";
223 }
224 line += item;
225 }
226 out.push_back(line);
227 return out;
228}
229
236void writeIGSHeader(std::string file_name) {
237 std::vector<std::string> section(4);
238 section[0] = "";
239 section[1] = "IGES obtained from Bembel.";
240 section[2] = "See <http://www.bembel.eu>";
241 section[3] = "";
242
244 return;
245}
246
253std::string double_to_string(double d, const int precision) {
254 std::ostringstream stm;
255 stm << std::setprecision(precision) << d;
256 return stm.str();
257}
258
266 std::vector<std::string> out(24);
267 std::time_t now = std::time(nullptr);
268
269 std::tm* localTime = std::localtime(&now);
270 char dateString[11]; // "YYYY-MM-DD\0"
271 std::strftime(dateString, sizeof(dateString), "%Y-%m-%d", localTime);
272 // Parameter Deliminator Character
273 out[0] = "1H,";
274 // Record Delimiter Character
275 out[1] = "1H;";
276 // Product ID from Sender
277 out[2] = "Bembel";
278 // File Name
279 out[3] = file_name;
280 // System ID
281 out[4] = "Bembel";
282 // Pre-processor Version
283 out[5] = "writeIGSFile";
284 // Number of Bits for Integers
285 out[6] = "32";
286 // Single Precision Magnitude
287 out[7] = "75";
288 // Single Precision Significance
289 out[8] = "6";
290 // Double Precision Magnitude
291 out[9] = "75";
292 // Double Precision Significance
293 out[10] = "15";
294 // Product ID for Receiver
295 out[11] = "Nurbs from Bembel";
296 // Model Space Scale
297 out[12] = "1.0";
298 // Unit Flag (6 = metres)
299 out[13] = "6";
300 // Units (metres = "M")
301 out[14] = "M";
302 // Maximum Number of Line Weights
303 out[15] = "1000";
304 // Size of Maximum Line Width
305 out[16] = "1.0";
306 // Date and Time of file generation
307 out[17] = dateString;
308 // Minimum User-intended Resolution
309 out[18] = "0.000001";
310 // Approximate Maximum Coordinate
311 out[19] = "10000.0";
312 // Name of Author
313 out[20] = "Maximilian Nolte";
314 // Author's Organization
315 out[21] = "CEM - TU Darmstadt";
316 // IGES Version Number (3 = IGES version 2.0)
317 out[22] = "3";
318 // Drafting Standard Code (0 = no standard)
319 out[23] = "0";
320
321 std::vector<std::string> section = makeSection(out);
322
324 return section.size();
325}
326
336int writeDirectory(std::string file_name, std::vector<int> start_idx,
337 std::vector<int> number_of_lines) {
338 assert(start_idx.size() == number_of_lines.size());
339
340 std::ofstream fid(file_name, std::ios::app);
341 int tot_number_of_lines = 0;
342 const int number_of_patches = start_idx.size();
343 for (auto i = 0; i < number_of_patches; ++i) {
344 fid << std::setw(8) << "128"
345 << std::setw(8) << start_idx[i]
346 << std::setw(8) << 0
347 << std::setw(8) << 0
348 << std::setw(8) << 0
349 << std::setw(8) << 0
350 << std::setw(8) << 0
351 << std::setw(8) << 0
352 << std::setw(8) << 0
353 << "D"
354 << std::setw(7) << (i + 1) * 2 - 1<< "\n";
355
356 fid << std::setw(8) << "128"
357 << std::setw(8) << 0
358 << std::setw(8) << 0
359 << std::setw(8) << number_of_lines[i]
360 << std::setw(8) << 0
361 << std::setw(8) << " "
362 << std::setw(8) << " "
363 << std::setw(8) << " "
364 << std::setw(8) << 0
365 << "D"
366 << std::setw(7) << (i + 1) * 2 << "\n";
367
369 }
370 return tot_number_of_lines;
371}
372
385std::vector<std::string> writePatchData(const Patch& patch,
386 const int precision) {
387 const int degree_x = patch.polynomial_degree_x_;
388 const int degree_y = patch.polynomial_degree_y_;
389
390 assert(patch.unique_knots_x_.size() == 2 &&
391 "We can not handle internal knots");
392 assert(patch.unique_knots_y_.size() == 2 &&
393 "We can not handle internal knots");
394
395 std::vector<double> knots_x(2 * degree_x, 0);
396 for (auto i = 0; i <= degree_x; ++i) knots_x[degree_x + i] = 1;
397 std::vector<double> knots_y(2 * degree_y, 0);
398 for (auto i = 0; i <= degree_y; ++i) knots_y[degree_y + i] = 1;
399
400 const std::array<double, 2> span_x = {0, 1};
401 const std::array<double, 2> span_y = {0, 1};
402
403 const int number_of_points_x = knots_x.size() - degree_x;
404 const int number_of_points_y = knots_y.size() - degree_y;
405
406 const int size = patch.data_.size() / 4;
407 std::vector<double> weights(size);
408 std::vector<double> coordinates_x(size);
409 std::vector<double> coordinates_y(size);
410 std::vector<double> coordinates_z(size);
411 // transform from wx, wy, wz to x, y, z
412 // further more switch row major and column major
413 for (auto i = 0; i < size; ++i) {
414 const int rowIndex = i % number_of_points_y;
415 const int colIndex = i / number_of_points_y;
416
417 // Calculate the index for the corresponding element in row-major order
418 const int j = rowIndex * number_of_points_x + colIndex;
419
420 double weight = patch.data_[i * 4 + 3];
421 weights[j] = weight;
422 coordinates_x[j] = patch.data_[i * 4] / weight;
423 coordinates_y[j] = patch.data_[i * 4 + 1] / weight;
424 coordinates_z[j] = patch.data_[i * 4 + 2] / weight;
425 }
426
427 const int number_of_data_entries = 16;
428 const int size_data =
429 number_of_data_entries + 4 * size + knots_x.size() + knots_y.size();
430 std::vector<std::string> patch_data(size_data);
431
432 patch_data[0] = "128";
433 patch_data[1] = std::to_string(number_of_points_x - 1);
434 patch_data[2] = std::to_string(number_of_points_y - 1);
435 patch_data[3] = std::to_string(degree_x - 1);
436 patch_data[4] = std::to_string(degree_y - 1);
437 patch_data[5] = "0";
438 patch_data[6] = "0";
439 patch_data[7] = "0";
440 patch_data[8] = "0";
441 patch_data[9] = "0";
442
443 for (auto i = 0; i < knots_x.size(); ++i) {
444 patch_data[10 + i] = double_to_string(knots_x[i], precision);
445 }
446
447 const int idx_knots_y = 10 + knots_x.size();
448 for (auto i = 0; i < knots_y.size(); ++i) {
450 }
451
452 const int idx_weights = 10 + knots_x.size() + knots_y.size();
453 for (auto i = 0; i < size; ++i) {
455
456 patch_data[idx_weights + size + i * 3] =
457 double_to_string(coordinates_x[i], precision);
458 patch_data[idx_weights + size + i * 3 + 1] =
459 double_to_string(coordinates_y[i], precision);
460 patch_data[idx_weights + size + i * 3 + 2] =
461 double_to_string(coordinates_z[i], precision);
462 }
463 patch_data[idx_weights + 4 * size] = std::to_string(span_x[0]);
464 patch_data[idx_weights + 4 * size + 1] = std::to_string(span_x[1]);
465 patch_data[idx_weights + 4 * size + 2] = std::to_string(span_y[0]);
466 patch_data[idx_weights + 4 * size + 3] = std::to_string(span_y[1]);
467 patch_data[idx_weights + 4 * size + 4] = "0";
468 patch_data[idx_weights + 4 * size + 5] = "0";
469
470 return patch_data;
471}
472
481void writeIGSFile(const std::vector<Patch>& geometry, std::string file_name,
482 const int precision = 6) {
483 std::ofstream out(file_name);
484 out.close();
487
488 const int number_of_patches = geometry.size();
489 std::vector<int> start_idx(number_of_patches);
490 std::vector<int> end_idx(number_of_patches);
491 std::vector<std::vector<std::string>> patch_sections(number_of_patches);
492 int start_line = 1;
493 for (auto i = 0; i < number_of_patches; ++i) {
494 const std::vector<std::string> patch_data =
495 writePatchData(geometry[i], precision);
497
499 start_line += patch_sections[i].size();
500 end_idx[i] = patch_sections[i].size();
501 }
503
504 int first_line = 1;
505 int size_parameter = 0;
506 for (auto it = patch_sections.begin(); it != patch_sections.end(); ++it) {
507 const int i = std::distance(patch_sections.begin(), it);
508 const int last_idx =
511 size_parameter += (*it).size();
512 }
513
514 // Terminate Section
515 std::stringstream last_section;
516 last_section << std::setw(7) << 4 << "S"
517 << std::setw(7) << size_global << "G"
518 << std::setw(7) << size_directory << "D"
519 << std::setw(7) << size_parameter << "P";
520
521
522 std::ofstream file(file_name, std::ios::app);
523 file << std::left << std::setw(72) << last_section.str()
524 << "T"
525 << std::right << std::setw(7) << 1 << "\n";
526 file.close();
527
528 return;
529}
530} // namespace Bembel
531#endif // BEMBEL_SRC_GEOMETRY_GEOMETRYIGS_HPP_
handles a single patch
Definition Patch.hpp:20
void init_Patch(const std::vector< Eigen::Matrix< double, -1, -1 > > &xyzw, const std::vector< double > &x_knots, const std::vector< double > &y_knots)
init
Definition Patch.hpp:63
int writeDirectory(std::string file_name, std::vector< int > start_idx, std::vector< int > number_of_lines)
Write the IGES Directory section into the given file.
std::vector< std::string > writePatchData(const Patch &patch, const int precision)
This Function writes the patch from Bembel into a vector which can be written into an IGES file.
int writeParameterSection(std::string file_name, const std::vector< std::string > &section, const int patch_idx, const int start_count)
This function writes a the parameter section of the IGES file.
void writeIGSHeader(std::string file_name)
Write the IGES header into the given file.
void writeSection(std::string file_name, const std::vector< std::string > &section, const char section_char)
This function writes a given section to the specified file.
std::vector< std::string > makeSection(std::vector< std::string > data, const int linewidth=72)
Transform a vector of Data in a vector of lines with a specific length.
std::vector< Patch > LoadGeometryFileIGS(const std::string &file_name) noexcept
loads geometry from IGES file. Note that the direction of the normals must be consistent.
void writeIGSFile(const std::vector< Patch > &geometry, std::string file_name, const int precision=6)
Writes Geometry into an IGES file format.
int writeGlobalSection(std::string file_name)
Write the IGES Global section into the given file.
Routines for the evalutation of pointwise errors.
std::string double_to_string(double d, const int precision)
Convert a double to a string with given precision.
constexpr int getFunctionSpaceOutputDimension()