unstructured_two_d_mesh_geometry_base.cc
Go to the documentation of this file.
1// LIC// ====================================================================
2// LIC// This file forms part of oomph-lib, the object-oriented,
3// LIC// multi-physics finite-element library, available
4// LIC// at http://www.oomph-lib.org.
5// LIC//
6// LIC// Copyright (C) 2006-2025 Matthias Heil and Andrew Hazel
7// LIC//
8// LIC// This library is free software; you can redistribute it and/or
9// LIC// modify it under the terms of the GNU Lesser General Public
10// LIC// License as published by the Free Software Foundation; either
11// LIC// version 2.1 of the License, or (at your option) any later version.
12// LIC//
13// LIC// This library is distributed in the hope that it will be useful,
14// LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16// LIC// Lesser General Public License for more details.
17// LIC//
18// LIC// You should have received a copy of the GNU Lesser General Public
19// LIC// License along with this library; if not, write to the Free Software
20// LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21// LIC// 02110-1301 USA.
22// LIC//
23// LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
24// LIC//
25// LIC//====================================================================
26
28
29
30///////////////////////////////////////////////////////////////////////
31///////////////////////////////////////////////////////////////////////
32///////////////////////////////////////////////////////////////////////
33
34namespace oomph
35{
36#ifdef OOMPH_HAS_TRIANGLE_LIB
37
38 //==================================================================
39 /// Helper namespace for triangle meshes
40 //==================================================================
41 namespace TriangleHelper
42 {
43 /// Clear TriangulateIO structure
45 const bool& clear_hole_data)
46 {
47 // Clear the point,attribute and marker list
48 free(triangulate_io.pointlist);
49 free(triangulate_io.pointattributelist);
50 free(triangulate_io.pointmarkerlist);
51 triangulate_io.numberofpoints = 0;
52 triangulate_io.numberofpointattributes = 0;
53
54 // Clear the triangle, attribute,neighbor and area list
55 free(triangulate_io.trianglelist);
56 free(triangulate_io.triangleattributelist);
57 free(triangulate_io.trianglearealist);
58 free(triangulate_io.neighborlist);
59 triangulate_io.numberoftriangles = 0;
60 triangulate_io.numberofcorners = 0;
61 triangulate_io.numberoftriangleattributes = 0;
62
63 // Clear the segment and marker list
64 free(triangulate_io.segmentlist);
65 free(triangulate_io.segmentmarkerlist);
66 triangulate_io.numberofsegments = 0;
67
68 // Clear hole list
69 if (clear_hole_data) free(triangulate_io.holelist);
70 triangulate_io.numberofholes = 0;
71
72 // Clear region list
74 {
75 free(triangulate_io.regionlist);
76 }
77 triangulate_io.numberofregions = 0;
78
79 // Clear edge, marker and norm list
80 free(triangulate_io.edgelist);
81 free(triangulate_io.edgemarkerlist);
82 free(triangulate_io.normlist);
83 triangulate_io.numberofedges = 0;
84
85 // Now null it all out again
87 }
88
89
90 /// Initialise TriangulateIO structure
92 {
93 // Initialize the point list
94 triangle_io.pointlist = (double*)NULL;
95 triangle_io.pointattributelist = (double*)NULL;
96 triangle_io.pointmarkerlist = (int*)NULL;
97 triangle_io.numberofpoints = 0;
98 triangle_io.numberofpointattributes = 0;
99
100 // Initialize the triangle list
101 triangle_io.trianglelist = (int*)NULL;
102 triangle_io.triangleattributelist = (double*)NULL;
103 triangle_io.trianglearealist = (double*)NULL;
104 triangle_io.neighborlist = (int*)NULL;
105 triangle_io.numberoftriangles = 0;
106 triangle_io.numberofcorners = 0;
107 triangle_io.numberoftriangleattributes = 0;
108
109 // Initialize the segment list
110 triangle_io.segmentlist = (int*)NULL;
111 triangle_io.segmentmarkerlist = (int*)NULL;
112 triangle_io.numberofsegments = 0;
113
114 // Initialise hole list
115 triangle_io.holelist = (double*)NULL;
116 triangle_io.numberofholes = 0;
117
118 // Initialize region list
119 triangle_io.regionlist = (double*)NULL;
120 triangle_io.numberofregions = 0;
121
122 // Initialize edge list
123 triangle_io.edgelist = (int*)NULL;
124 triangle_io.edgemarkerlist = (int*)NULL;
125 triangle_io.normlist = (double*)NULL;
126 triangle_io.numberofedges = 0;
127 }
128
129
130 /// Make (partial) deep copy of TriangulateIO object. We only copy
131 /// those items we need within oomph-lib's adaptation procedures.
132 /// Warnings are issued if triangulate_io contains data that is not
133 /// not copied, unless quiet=true;
135 TriangulateIO& triangle_io, const bool& quiet)
136 {
137 // Create the struct
139
140 // Initialise
142
143 // Point data
144 triangle_out.numberofpoints = triangle_io.numberofpoints;
145 triangle_out.pointlist =
146 (double*)malloc(triangle_out.numberofpoints * 2 * sizeof(double));
147 for (int j = 0; j < triangle_out.numberofpoints * 2; j++)
148 {
149 triangle_out.pointlist[j] = triangle_io.pointlist[j];
150 }
151
152 triangle_out.pointmarkerlist =
153 (int*)malloc(triangle_out.numberofpoints * sizeof(int));
154 for (int j = 0; j < triangle_out.numberofpoints; j++)
155 {
156 triangle_out.pointmarkerlist[j] = triangle_io.pointmarkerlist[j];
157 }
158
159 // Warn about laziness...
160 if (!quiet)
161 {
162 if ((triangle_io.pointattributelist != 0) ||
163 (triangle_io.numberofpointattributes != 0))
164 {
166 "Point attributes are not currently copied across",
167 "TriangleHelper::deep_copy_of_triangulateio_representation",
169 }
170 }
171
172
173 // Triangle data
174 triangle_out.numberoftriangles = triangle_io.numberoftriangles;
175 triangle_out.trianglelist =
176 (int*)malloc(triangle_out.numberoftriangles * 3 * sizeof(int));
177 for (int j = 0; j < triangle_out.numberoftriangles * 3; j++)
178 {
179 triangle_out.trianglelist[j] = triangle_io.trianglelist[j];
180 }
181
182
183 // Copy over the triangle attribute data
184 triangle_out.numberoftriangleattributes =
185 triangle_io.numberoftriangleattributes;
186 triangle_out.triangleattributelist = (double*)malloc(
187 triangle_out.numberoftriangles *
188 triangle_out.numberoftriangleattributes * sizeof(double));
189 for (int j = 0; j < (triangle_out.numberoftriangles *
190 triangle_out.numberoftriangleattributes);
191 ++j)
192 {
193 triangle_out.triangleattributelist[j] =
194 triangle_io.triangleattributelist[j];
195 }
196
197
198 // Warn about laziness...
199 if (!quiet)
200 {
201 /* if ((triangle_io.triangleattributelist!=0)||
202 (triangle_io.numberoftriangleattributes!=0))
203 {
204 OomphLibWarning(
205 "Triangle attributes are not currently copied across",
206 "TriangleHelper::deep_copy_of_triangulateio_representation",
207 OOMPH_EXCEPTION_LOCATION);
208 }*/
209
210 if ((triangle_io.trianglearealist != 0))
211 {
213 "Triangle areas are not currently copied across",
214 "TriangleHelper::deep_copy_of_triangulateio_representation",
216 }
217
218 if ((triangle_io.neighborlist != 0))
219 {
221 "Triangle neighbours are not currently copied across",
222 "TriangleHelper::deep_copy_of_triangulateio_representation",
224 }
225 }
226
227
228 triangle_out.numberofcorners = triangle_io.numberofcorners;
229
230 // Segment data
231 triangle_out.numberofsegments = triangle_io.numberofsegments;
232 triangle_out.segmentlist =
233 (int*)malloc(triangle_out.numberofsegments * 2 * sizeof(int));
234 for (int j = 0; j < triangle_out.numberofsegments * 2; j++)
235 {
236 triangle_out.segmentlist[j] = triangle_io.segmentlist[j];
237 }
238 triangle_out.segmentmarkerlist =
239 (int*)malloc(triangle_out.numberofsegments * sizeof(int));
240 for (int j = 0; j < triangle_out.numberofsegments; j++)
241 {
242 triangle_out.segmentmarkerlist[j] = triangle_io.segmentmarkerlist[j];
243 }
244
245
246 // Region data
247 triangle_out.numberofregions = triangle_io.numberofregions;
248 triangle_out.regionlist =
249 (double*)malloc(triangle_out.numberofregions * 4 * sizeof(double));
250 for (int j = 0; j < triangle_out.numberofregions * 4; ++j)
251 {
252 triangle_out.regionlist[j] = triangle_io.regionlist[j];
253 }
254
255 // Hole data
256 triangle_out.numberofholes = triangle_io.numberofholes;
257 triangle_out.holelist =
258 (double*)malloc(triangle_out.numberofholes * 2 * sizeof(double));
259 for (int j = 0; j < triangle_out.numberofholes * 2; j++)
260 {
261 triangle_out.holelist[j] = triangle_io.holelist[j];
262 }
263
264
265 // Warn about laziness...
266 if (!quiet)
267 {
268 /* if ((triangle_io.regionlist!=0)||
269 (triangle_io.numberofregions!=0))
270 {
271 OomphLibWarning(
272 "Regions are not currently copied across",
273 "TriangleHelper::deep_copy_of_triangulateio_representation",
274 OOMPH_EXCEPTION_LOCATION);
275 }*/
276
277 if ((triangle_io.edgelist != 0) || (triangle_io.numberofedges != 0))
278 {
280 "Edges are not currently copied across",
281 "TriangleHelper::deep_copy_of_triangulateio_representation",
283 }
284
285 if ((triangle_io.edgemarkerlist != 0))
286 {
288 "Edge markers are not currently copied across",
289 "TriangleHelper::deep_copy_of_triangulateio_representation",
291 }
292
293 if ((triangle_io.normlist != 0))
294 {
296 "Normals are not currently copied across",
297 "TriangleHelper::deep_copy_of_triangulateio_representation",
299 }
300 }
301
302 // Give it back!
303 return triangle_out;
304 }
305
306 /// Write the triangulateio data to disk as a poly file,
307 /// mainly used for debugging
309 std::ostream& poly_file)
310 {
311 // Up the precision dramatiacally
312 poly_file.precision(20);
313
314 // Output the number of points and their attributes
315 // Store the number of attributes
316 const int n_attr = triangle_io.numberofpointattributes;
317 poly_file << triangle_io.numberofpoints << " " << 2 << " " << n_attr
318 << " ";
319 // Determine whether there are point markers
320 bool point_markers = true;
321 if (triangle_io.pointmarkerlist == NULL)
322 {
323 point_markers = false;
324 }
325 // Indicate this in the file
326 poly_file << point_markers << "\n";
327
328 // Now output the point data
329 poly_file << "#Points\n";
330 for (int n = 0; n < triangle_io.numberofpoints; ++n)
331 {
332 // Output the point number and x and y coordinates
333 poly_file << n + 1 << " " << triangle_io.pointlist[2 * n] << " "
334 << triangle_io.pointlist[2 * n + 1] << " ";
335 // Output any attributes
336 for (int i = 0; i < n_attr; ++i)
337 {
338 poly_file << triangle_io.pointattributelist[n_attr * n + i] << " ";
339 }
340 // Output the boundary marker
341 if (point_markers)
342 {
343 poly_file << triangle_io.pointmarkerlist[n] << " ";
344 }
345 poly_file << "\n";
346 }
347
348 // Now move onto the segments
349 poly_file << "#Lines\n";
350 poly_file << triangle_io.numberofsegments << " ";
351 // Determine whether there are segment markers
352 bool seg_markers = true;
353 if (triangle_io.segmentmarkerlist == NULL)
354 {
355 seg_markers = false;
356 }
357 // Output this info in the file
358 poly_file << seg_markers << "\n";
359
360 // Now output the segment data
361 for (int n = 0; n < triangle_io.numberofsegments; ++n)
362 {
363 poly_file << n + 1 << " " << triangle_io.segmentlist[2 * n] << " "
364 << triangle_io.segmentlist[2 * n + 1] << " ";
365 // If there is a boundary marker output
366 if (seg_markers)
367 {
368 poly_file << triangle_io.segmentmarkerlist[n] << " ";
369 }
370 poly_file << "\n";
371 }
372
373 // Now output the number of holes
374 poly_file << "#No holes\n";
375 poly_file << triangle_io.numberofholes << "\n";
376 // Output the hole data
377 for (int h = 0; h < triangle_io.numberofholes; ++h)
378 {
379 poly_file << h + 1 << " " << triangle_io.holelist[2 * h] << " "
380 << triangle_io.holelist[2 * h + 1] << "\n";
381 }
382
383 // Now output the number of regions
384 poly_file << "#Assignment of attributes to regions\n";
385 poly_file << triangle_io.numberofregions << "\n";
386
387 // Loop over the regions
388 for (int r = 0; r < triangle_io.numberofregions; ++r)
389 {
390 poly_file << r + 1 << " ";
391 for (unsigned i = 0; i < 4; i++)
392 {
393 poly_file << triangle_io.regionlist[4 * r + i] << " ";
394 }
395 poly_file << "\n";
396 }
397 }
398
399
400 /// Create a triangulateio data file from ele node and poly
401 /// files. This is used if the mesh is generated by using Triangle
402 /// externally. The triangulateio structure is required to dump the mesh
403 /// topology for restarts.
405 const std::string& node_file_name,
406 const std::string& element_file_name,
407 const std::string& poly_file_name,
409 bool& use_attributes)
410 {
411 // Initialise the TriangulateIO data structure
413
414 // Process element file
415 std::ifstream element_file(element_file_name.c_str(), std::ios_base::in);
416
417 // Check that the file actually opened correctly
418 if (!element_file.is_open())
419 {
420 std::string error_msg("Failed to open element file: ");
421 error_msg += "\"" + element_file_name + "\".";
422 throw OomphLibError(
424 }
425
426 // Read in the number of elements
427 element_file >> triangle_io.numberoftriangles;
428 const unsigned n_element =
429 static_cast<unsigned>(triangle_io.numberoftriangles);
430
431 // Read in the number of nodes per element
432 element_file >> triangle_io.numberofcorners;
433 const unsigned n_local_node =
434 static_cast<unsigned>(triangle_io.numberofcorners);
435
436 // Read in the element attributes
437 element_file >> triangle_io.numberoftriangleattributes;
438 const unsigned n_attributes =
439 static_cast<unsigned>(triangle_io.numberoftriangleattributes);
440
441 // Allocate storage in the data structure
442 triangle_io.trianglelist =
443 (int*)malloc(triangle_io.numberoftriangles *
444 triangle_io.numberofcorners * sizeof(int));
445
446 if (n_attributes > 0)
447 {
448 triangle_io.triangleattributelist = (double*)malloc(
449 triangle_io.numberoftriangles *
450 triangle_io.numberoftriangleattributes * sizeof(double));
451 }
452
453 // Dummy storage
455
456 // Initialise counter
457 unsigned counter = 0;
458 unsigned counter2 = 0;
459
460 // Read global node numbers for all elements
461 for (unsigned e = 0; e < n_element; e++)
462 {
464 for (unsigned j = 0; j < n_local_node; j++)
465 {
466 element_file >> triangle_io.trianglelist[counter];
467 ++counter;
468 }
469 for (unsigned j = 0; j < n_attributes; j++)
470 {
471 element_file >> triangle_io.triangleattributelist[counter2];
472 ++counter2;
473 }
474 }
475 // Close the element file
476 element_file.close();
477
478 // Process node file
479 // -----------------
480 std::ifstream node_file(node_file_name.c_str(), std::ios_base::in);
481
482 // Check that the file actually opened correctly
483 if (!node_file.is_open())
484 {
485 std::string error_msg("Failed to open node file: ");
486 error_msg += "\"" + node_file_name + "\".";
487 throw OomphLibError(
489 }
490
491 // Read number of nodes
492 node_file >> triangle_io.numberofpoints;
493 unsigned n_node = static_cast<unsigned>(triangle_io.numberofpoints);
494
495 // Spatial dimension of nodes
496 unsigned dimension;
498
499#ifdef PARANOID
500 if (dimension != 2)
501 {
502 throw OomphLibError("The dimension must be 2\n",
505 }
506#endif
507
508 // Flag for attributes
509 node_file >> triangle_io.numberofpointattributes;
510 unsigned n_point_attributes =
511 static_cast<unsigned>(triangle_io.numberofpointattributes);
512
513 // Flag for boundary markers
514 unsigned boundary_markers_flag;
516
517 // Allocate storage
518 triangle_io.pointlist =
519 (double*)malloc(triangle_io.numberofpoints * 2 * sizeof(double));
520 triangle_io.pointattributelist =
521 (double*)malloc(triangle_io.numberofpoints *
522 triangle_io.numberofpointattributes * sizeof(double));
524 {
525 triangle_io.pointmarkerlist =
526 (int*)malloc(triangle_io.numberofpoints * sizeof(int));
527 }
528
529 // Dummy for node number
530 unsigned dummy_node_number;
531
532 // Reset counter
533 counter = 0;
534 // Load in nodal posititions, point attributes
535 // and boundary markers
536 for (unsigned i = 0; i < n_node; i++)
537 {
539 node_file >> triangle_io.pointlist[2 * i];
540 node_file >> triangle_io.pointlist[2 * i + 1];
541 for (unsigned j = 0; j < n_point_attributes; ++j)
542 {
543 node_file >> triangle_io.pointattributelist[counter];
544 ++counter;
545 }
547 {
548 node_file >> triangle_io.pointmarkerlist[i];
549 }
550 }
551 node_file.close();
552
553
554 // Process poly file to extract edges
555 //-----------------------------------
556
557 // Open poly file
558 std::ifstream poly_file(poly_file_name.c_str(), std::ios_base::in);
559
560 // Check that the file actually opened correctly
561 if (!poly_file.is_open())
562 {
563 std::string error_msg("Failed to open poly file: ");
564 error_msg += "\"" + poly_file_name + "\".";
565 throw OomphLibError(
567 }
568
569 // Number of nodes in poly file --- these will be ignore
570 unsigned n_node_poly;
572
573 // Dimension
575
576 // Attribute flag
577 unsigned attribute_flag;
579
580 // Boundary markers flag
582
583
584 // Ignore node information: Note: No, we can't extract the
585 // actual nodes themselves from here!
586 unsigned dummy;
587 for (unsigned i = 0; i < n_node_poly; i++)
588 {
589 // Read in (and discard) node number and x and y coordinates
590 poly_file >> dummy;
591 poly_file >> dummy;
592 poly_file >> dummy;
593 // read in the attributes
594 for (unsigned j = 0; j < attribute_flag; ++j)
595 {
596 poly_file >> dummy;
597 }
598 // read in the boundary marker
599 if (boundary_markers_flag == 1)
600 {
601 poly_file >> dummy;
602 }
603 }
604
605 // Now extract the segment information
606 //------------------------------------
607
608 // Number of segments
609 poly_file >> triangle_io.numberofsegments;
610 unsigned n_segment = static_cast<unsigned>(triangle_io.numberofsegments);
611
612 // Boundary marker flag
614
615 // Allocate storage
616 triangle_io.segmentlist =
617 (int*)malloc(triangle_io.numberofsegments * 2 * sizeof(int));
619 {
620 triangle_io.segmentmarkerlist =
621 (int*)malloc(triangle_io.numberofsegments * sizeof(int));
622 }
623
624 // Dummy for global segment number
625 unsigned dummy_segment_number;
626
627 // Extract information for each segment
628 for (unsigned i = 0; i < n_segment; i++)
629 {
631 poly_file >> triangle_io.segmentlist[2 * i];
632 poly_file >> triangle_io.segmentlist[2 * i + 1];
634 {
635 poly_file >> triangle_io.segmentmarkerlist[i];
636 }
637 }
638
639 // Extract hole center information
640 poly_file >> triangle_io.numberofholes;
641 unsigned n_hole = static_cast<unsigned>(triangle_io.numberofholes);
642
643 // Allocate memory
644 triangle_io.holelist =
645 (double*)malloc(triangle_io.numberofholes * 2 * sizeof(double));
646
647
648 // Dummy for hole number
649 unsigned dummy_hole;
650 // Loop over the holes to get centre coords
651 for (unsigned ihole = 0; ihole < n_hole; ihole++)
652 {
653 // Read the centre value
655 poly_file >> triangle_io.holelist[2 * ihole];
656 poly_file >> triangle_io.holelist[2 * ihole + 1];
657 }
658
659 // Extract regions information
660 poly_file >> triangle_io.numberofregions;
661 unsigned n_regions = static_cast<unsigned>(triangle_io.numberofregions);
662
663 // Allocate memory
664 triangle_io.regionlist =
665 (double*)malloc(triangle_io.numberofregions * 4 * sizeof(double));
666
667 // Check for using regions
668 if (n_regions > 0)
669 {
670 use_attributes = true;
671 }
672
673 // Dummy for regions number
674 unsigned dummy_region;
675
676 // Loop over the regions to get their coords
677 for (unsigned iregion = 0; iregion < n_regions; iregion++)
678 {
679 // Read the regions coordinates
681 poly_file >> triangle_io.regionlist[4 * iregion];
682 poly_file >> triangle_io.regionlist[4 * iregion + 1];
683 poly_file >> triangle_io.regionlist[4 * iregion + 2];
684 triangle_io.regionlist[4 * iregion + 3] = 0.0;
685
686 // Skip the rest of the line, there is no need to read the size of
687 // the elements in the region since that value is no longer used
688 poly_file.ignore(80, '\n');
689
690 // Verify if not using the default region number (zero)
691 if (triangle_io.regionlist[4 * iregion + 2] == 0)
692 {
693 std::ostringstream error_message;
694 error_message
695 << "Please use another region id different from zero.\n"
696 << "It is internally used as the default region number.\n";
697 throw OomphLibError(error_message.str(),
700 }
701 }
702
703 poly_file.close();
704 }
705
706
707 /// Write all the triangulateio data to disk in a dump file
708 /// that can then be used to restart simulations
710 {
711 // Dump the triangles first
712 dump_file << triangle_io.numberoftriangles
713 << " # number of elements in TriangulateIO" << std::endl;
714
715 dump_file << triangle_io.numberofcorners
716 << " # number of nodes in each triangle" << std::endl;
717
718 dump_file << triangle_io.numberoftriangleattributes
719 << " # number of triangle attributes" << std::endl;
720
721 // Loop over and dump the triangle information
722 const int n_element = triangle_io.numberoftriangles;
723 const int n_local_node = triangle_io.numberofcorners;
724 const int n_attribute = triangle_io.numberoftriangleattributes;
725 unsigned counter = 0, counter2 = 0;
726 for (int e = 0; e < n_element; ++e)
727 {
728 // Dump the corners
729 dump_file << e << " # element number " << std::endl;
730 for (int n = 0; n < n_local_node; ++n)
731 {
732 dump_file << triangle_io.trianglelist[counter] << std::endl;
733 ++counter;
734 }
735 // Dump the attributes
736 dump_file << n_attribute << " # number of attributes" << std::endl;
737 for (int n = 0; n < n_attribute; ++n)
738 {
739 dump_file << triangle_io.triangleattributelist[counter2] << std::endl;
740 ++counter2;
741 }
742 }
743
744
745 // Dump the points (nodes) next
746 dump_file << triangle_io.numberofpoints
747 << " # number of points in TriangulateIO" << std::endl;
748 dump_file << triangle_io.numberofpointattributes
749 << " # number of point attributes" << std::endl;
750 // Test whether there are point markers
751 bool point_marker_flag = true;
752 if (triangle_io.pointmarkerlist == NULL)
753 {
754 point_marker_flag = false;
755 }
756 dump_file << point_marker_flag << " # point marker flag" << std::endl;
757
758
759 // Now output the point data
760 const int n_nodes = triangle_io.numberofpoints;
761 const int n_point_attributes = triangle_io.numberofpointattributes;
762 counter = 0;
763 counter2 = 0;
764 for (int n = 0; n < n_nodes; ++n)
765 {
766 dump_file << n << " # point number " << std::endl;
767 for (int i = 0; i < 2; ++i)
768 {
769 dump_file << triangle_io.pointlist[counter] << std::endl;
770 ++counter;
771 }
772 dump_file << n_point_attributes << " # number of point attributes "
773 << std::endl;
774 // Output any attributes
775 for (int i = 0; i < n_point_attributes; ++i)
776 {
777 dump_file << triangle_io.pointattributelist[counter2] << std::endl;
778 ++counter2;
779 }
780 dump_file << point_marker_flag << " # point marker flag " << std::endl;
781 // Output the boundary marker
783 {
784 dump_file << triangle_io.pointmarkerlist[n] << std::endl;
785 }
786 }
787
788 // Now move onto the segments
789 dump_file << triangle_io.numberofsegments
790 << " # Number of segments in TriangulateIO " << std::endl;
791
792 // Determine whether there are segment markers
793 bool seg_marker_flag = true;
794 if (triangle_io.segmentmarkerlist == NULL)
795 {
796 seg_marker_flag = false;
797 }
798 // Output this info in the file
799 dump_file << seg_marker_flag << " # segment marker flag " << std::endl;
800
801 const int n_segments = triangle_io.numberofsegments;
802 counter = 0;
803 // Now output the segment data
804 for (int n = 0; n < n_segments; ++n)
805 {
806 dump_file << n << " # segment number " << std::endl;
807 for (int i = 0; i < 2; ++i)
808 {
809 dump_file << triangle_io.segmentlist[counter] << std::endl;
810 ++counter;
811 }
812
813 // If there is a boundary marker output
814 dump_file << seg_marker_flag << " # segment marker flag " << std::endl;
815 if (seg_marker_flag)
816 {
817 dump_file << triangle_io.segmentmarkerlist[n] << std::endl;
818 }
819 }
820
821 // Now output the number of holes
822 dump_file << triangle_io.numberofholes << " # number of holes "
823 << std::endl;
824 const int n_hole = triangle_io.numberofholes;
825 // Output the hole data
826 for (int h = 0; h < n_hole; ++h)
827 {
828 dump_file << h << " # hole number " << std::endl;
829 dump_file << triangle_io.holelist[2 * h] << std::endl;
830 dump_file << triangle_io.holelist[2 * h + 1] << std::endl;
831 }
832
833 // Now output the number of regions
834 dump_file << triangle_io.numberofregions << " # number of regions "
835 << std::endl;
836
837 const int n_region = triangle_io.numberofregions;
838 // Loop over the regions
839 counter = 0;
840 for (int r = 0; r < n_region; ++r)
841 {
842 dump_file << r << " # region number " << std::endl;
843 for (unsigned i = 0; i < 4; i++)
844 {
845 dump_file << triangle_io.regionlist[counter] << std::endl;
846 ++counter;
847 }
848 }
849 }
850
851 /// Read the triangulateio data from a dump file on
852 /// disk, which can then be used to restart simulations
855 {
856 // String for reading
857 std::string input_string;
858
859 // Initialise the triangulate data structure
861
862 // Read the first line up to termination sign
863 getline(restart_file, input_string, '#');
864 // Ignore the rest of the line
865 restart_file.ignore(80, '\n');
866 // Convert the number
867 triangle_io.numberoftriangles = atoi(input_string.c_str());
868
869 // Read the next line up to termination sign
870 getline(restart_file, input_string, '#');
871 // Ignore the rest of the line
872 restart_file.ignore(80, '\n');
873 // Convert the number
874 triangle_io.numberofcorners = atoi(input_string.c_str());
875
876 // Read the next line up to termination sign
877 getline(restart_file, input_string, '#');
878 // Ignore the rest of the line
879 restart_file.ignore(80, '\n');
880 // Convert the number
881 triangle_io.numberoftriangleattributes = atoi(input_string.c_str());
882
883 // Convert numbers into register variables
884 const int n_element = triangle_io.numberoftriangles;
885 const int n_local_node = triangle_io.numberofcorners;
886 const int n_attribute = triangle_io.numberoftriangleattributes;
887
888 // Allocate storage in the data structure
889 triangle_io.trianglelist =
890 (int*)malloc(triangle_io.numberoftriangles *
891 triangle_io.numberofcorners * sizeof(int));
892
893 if (n_attribute > 0)
894 {
895 triangle_io.triangleattributelist = (double*)malloc(
896 triangle_io.numberoftriangles *
897 triangle_io.numberoftriangleattributes * sizeof(double));
898 }
899
900 // Loop over elements and load in data
901 unsigned counter = 0, counter2 = 0;
902 for (int e = 0; e < n_element; ++e)
903 {
904 // Read the next line and ignore it
905 getline(restart_file, input_string);
906 for (int n = 0; n < n_local_node; ++n)
907 {
908 getline(restart_file, input_string);
909 triangle_io.trianglelist[counter] = atoi(input_string.c_str());
910 ++counter;
911 }
912 // Read the attributes
913 getline(restart_file, input_string);
914 for (int n = 0; n < n_attribute; ++n)
915 {
916 getline(restart_file, input_string);
917 triangle_io.triangleattributelist[counter2] =
918 atof(input_string.c_str());
919 ++counter2;
920 }
921 }
922
923
924 // Read the points (nodes) next up to termination string
925 getline(restart_file, input_string, '#');
926 // ignore the rest
927 restart_file.ignore(80, '\n');
928 triangle_io.numberofpoints = atoi(input_string.c_str());
929
930 // Read the point attributes next up to termination string
931 getline(restart_file, input_string, '#');
932 // ignore the rest
933 restart_file.ignore(80, '\n');
934 triangle_io.numberofpointattributes = atoi(input_string.c_str());
935
936 // Read whether there are point markers
937 getline(restart_file, input_string, '#');
938 // ignore the rest
939 restart_file.ignore(80, '\n');
940 int point_marker_flag = atoi(input_string.c_str());
941
942 // Allocate storage
943 triangle_io.pointlist =
944 (double*)malloc(triangle_io.numberofpoints * 2 * sizeof(double));
945 triangle_io.pointattributelist =
946 (double*)malloc(triangle_io.numberofpoints *
947 triangle_io.numberofpointattributes * sizeof(double));
949 {
950 triangle_io.pointmarkerlist =
951 (int*)malloc(triangle_io.numberofpoints * sizeof(int));
952 }
953
954
955 // Now read the point data
956 const int n_nodes = triangle_io.numberofpoints;
957 const int n_point_attributes = triangle_io.numberofpointattributes;
958 counter = 0;
959 counter2 = 0;
960 for (int n = 0; n < n_nodes; ++n)
961 {
962 // Ignore the first line
963 getline(restart_file, input_string);
964 // Get the positions
965 for (int i = 0; i < 2; ++i)
966 {
967 getline(restart_file, input_string);
968 triangle_io.pointlist[counter] = atof(input_string.c_str());
969 ++counter;
970 }
971
972 // Ignore the next line about point attributes
973 getline(restart_file, input_string);
974
975 // Read any attributes
976 for (int i = 0; i < n_point_attributes; ++i)
977 {
978 getline(restart_file, input_string);
979 triangle_io.pointattributelist[counter2] = atof(input_string.c_str());
980 ++counter2;
981 }
982
983 // Ignore the next line
984 getline(restart_file, input_string);
985 // Output the boundary marker
987 {
988 getline(restart_file, input_string);
989 triangle_io.pointmarkerlist[n] = atoi(input_string.c_str());
990 }
991 }
992
993 // Next read the segments
994 getline(restart_file, input_string, '#');
995 restart_file.ignore(80, '\n');
996 triangle_io.numberofsegments = atoi(input_string.c_str());
997
998 // Determine whether there are segment markers
999 getline(restart_file, input_string, '#');
1000 // ignore the rest
1001 restart_file.ignore(80, '\n');
1002 int seg_marker_flag = atoi(input_string.c_str());
1003
1004 // Allocate storage
1005 triangle_io.segmentlist =
1006 (int*)malloc(triangle_io.numberofsegments * 2 * sizeof(int));
1007 if (seg_marker_flag)
1008 {
1009 triangle_io.segmentmarkerlist =
1010 (int*)malloc(triangle_io.numberofsegments * sizeof(int));
1011 }
1012
1013 const int n_segments = triangle_io.numberofsegments;
1014 counter = 0;
1015 // Now output the segment data
1016 for (int n = 0; n < n_segments; ++n)
1017 {
1018 getline(restart_file, input_string);
1019 // get input
1020 for (int i = 0; i < 2; ++i)
1021 {
1022 getline(restart_file, input_string);
1023 triangle_io.segmentlist[counter] = atoi(input_string.c_str());
1024 ++counter;
1025 }
1026
1027 // Ignore the next line
1028 getline(restart_file, input_string);
1029 if (seg_marker_flag)
1030 {
1031 getline(restart_file, input_string);
1032 triangle_io.segmentmarkerlist[n] = atoi(input_string.c_str());
1033 }
1034 }
1035
1036 // Now read the holes
1037 getline(restart_file, input_string, '#');
1038 restart_file.ignore(80, '\n');
1039 triangle_io.numberofholes = atoi(input_string.c_str());
1040
1041 // Allocate memory
1042 triangle_io.holelist =
1043 (double*)malloc(triangle_io.numberofholes * 2 * sizeof(double));
1044
1045 const int n_hole = triangle_io.numberofholes;
1046 // Output the hole data
1047 for (int h = 0; h < n_hole; ++h)
1048 {
1049 // Ignore the first line
1050 getline(restart_file, input_string);
1051 // get the centre
1052 getline(restart_file, input_string);
1053 triangle_io.holelist[2 * h] = atof(input_string.c_str());
1054 getline(restart_file, input_string);
1055 triangle_io.holelist[2 * h + 1] = atof(input_string.c_str());
1056 }
1057
1058 // Now read the number of regions
1059 getline(restart_file, input_string, '#');
1060 restart_file.ignore(80, '\n');
1061 triangle_io.numberofregions = atoi(input_string.c_str());
1062
1063 const int n_region = triangle_io.numberofregions;
1064
1065 // Allocate memory
1066 triangle_io.regionlist =
1067 (double*)malloc(triangle_io.numberofregions * 4 * sizeof(double));
1068
1069 // Loop over the regions
1070 counter = 0;
1071 for (int r = 0; r < n_region; ++r)
1072 {
1073 getline(restart_file, input_string);
1074 for (unsigned i = 0; i < 4; i++)
1075 {
1076 getline(restart_file, input_string);
1077 triangle_io.regionlist[counter] = atof(input_string.c_str());
1078 ++counter;
1079 }
1080 }
1081 }
1082 } // namespace TriangleHelper
1083
1084#endif
1085
1086
1087 ////////////////////////////////////////////////////////////////////
1088 ////////////////////////////////////////////////////////////////////
1089 ////////////////////////////////////////////////////////////////////
1090
1091
1092 /// Namespace that allows the specification of a tolerance
1093 /// between vertices at the ends of polylines that are supposed
1094 /// to be at the same position.
1095 namespace ToleranceForVertexMismatchInPolygons
1096 {
1097 /// Acceptable discrepancy for mismatch in vertex coordinates.
1098 /// In paranoid mode, the code will die if the beginning/end of
1099 /// two adjacent polylines differ by more than that. If the
1100 /// discrepancy is smaller (but nonzero) one of the vertex coordinates
1101 /// get adjusted to match perfectly; without paranoia the vertex
1102 /// coordinates are taken as they come...
1103 double Tolerable_error = 1.0e-14;
1104
1105 } // namespace ToleranceForVertexMismatchInPolygons
1106
1107
1108 ////////////////////////////////////////////////////////////////////
1109 ////////////////////////////////////////////////////////////////////
1110 ////////////////////////////////////////////////////////////////////
1111
1112
1113 // =======================================================================
1114 // Connects the initial vertex of the curve section to a desired
1115 /// target polyline by specifying the vertex number. There is a checking
1116 /// which verifies that the initial vertex is close enough to the
1117 /// destination vertex on the target polyline by no more than the specified
1118 /// tolerance
1119 // =======================================================================
1121 TriangleMeshPolyLine* polyline_pt,
1122 const unsigned& vertex_number,
1123 const double& tolerance_for_connection)
1124 {
1125#ifdef PARANOID
1126 unsigned n_vertices = polyline_pt->nvertex();
1127
1128 if (n_vertices <= vertex_number)
1129 {
1130 std::ostringstream error_stream;
1131 error_stream << "The vertex number you provided (" << vertex_number
1132 << ") is greater\n than the number of vertices ("
1133 << n_vertices << "in the specified TriangleMeshPolyLine.\n"
1134 << "Remember that the vertex index starts at 0" << std::endl
1135 << "Source boundary (" << boundary_id()
1136 << ") wants to connect "
1137 << "to destination boundary (" << polyline_pt->boundary_id()
1138 << ")" << std::endl;
1139 throw OomphLibError(
1141 }
1142
1143 // Verify if there is really a match point in the specified
1144 // connection values
1147
1148 this->initial_vertex_coordinate(v_src);
1149 v_dst = polyline_pt->vertex_coordinate(vertex_number);
1150
1151 double error = sqrt((v_src[0] - v_dst[0]) * (v_src[0] - v_dst[0]) +
1152 (v_src[1] - v_dst[1]) * (v_src[1] - v_dst[1]));
1153
1155 {
1156 std::ostringstream error_stream;
1157 error_stream << "The associated vertices for the connection"
1158 << "\nare not close enough. Their respective values are:\n"
1159 << "Source boundary id:(" << this->boundary_id() << ")\n"
1160 << "Source vertex x:(" << v_src[0] << ") y:(" << v_src[1]
1161 << ")\n"
1162 << "Destination boundary id:(" << polyline_pt->boundary_id()
1163 << ")"
1164 << "\nAssociated vertex x:(" << v_dst[0] << ") y:("
1165 << v_dst[1] << ")"
1166 << "\nThe corresponding distance is: (" << error
1167 << ") but the "
1168 << "allowed\ntolerance is: (" << tolerance_for_connection
1169 << ")" << std::endl;
1170 throw OomphLibError(
1172 }
1173
1174#endif
1175
1178 Initial_vertex_connected_n_vertex = vertex_number;
1180 }
1181
1182 // =======================================================================
1183 // Connects the final vertex of the curve section to a desired
1184 /// target polyline by specifying the vertex number. There is a checking
1185 /// which verifies that the final vertex is close enough to the
1186 /// destination vertex on the target polyline by no more than the specified
1187 /// tolerance
1188 // =======================================================================
1190 TriangleMeshPolyLine* polyline_pt,
1191 const unsigned& vertex_number,
1192 const double& tolerance_for_connection)
1193 {
1194#ifdef PARANOID
1195 unsigned n_vertices = polyline_pt->nvertex();
1196
1197 if (n_vertices <= vertex_number)
1198 {
1199 std::ostringstream error_stream;
1200 error_stream << "The vertex number you provided (" << vertex_number
1201 << ") is greater\n than the number of vertices ("
1202 << n_vertices << "in the specified TriangleMeshPolyLine.\n"
1203 << "Remember that the vertex index starts at 0" << std::endl
1204 << "Source boundary (" << boundary_id()
1205 << ") wants to connect "
1206 << "to destination boundary (" << polyline_pt->boundary_id()
1207 << ")" << std::endl;
1208 throw OomphLibError(
1210 }
1211
1212 // Verify if there is really a match point in the specified
1213 // connection values
1216
1217 this->final_vertex_coordinate(v_src);
1218 v_dst = polyline_pt->vertex_coordinate(vertex_number);
1219
1220 double error = sqrt((v_src[0] - v_dst[0]) * (v_src[0] - v_dst[0]) +
1221 (v_src[1] - v_dst[1]) * (v_src[1] - v_dst[1]));
1222
1224 {
1225 std::ostringstream error_stream;
1226 error_stream << "The associated vertices for the connection"
1227 << "\nare not close enough. Their respective values are:\n"
1228 << "Source boundary id:(" << this->boundary_id() << ")\n"
1229 << "Source vertex x:(" << v_src[0] << ") y:(" << v_src[1]
1230 << ")\n"
1231 << "Destination boundary id:(" << polyline_pt->boundary_id()
1232 << ")"
1233 << "\nAssociated vertex x:(" << v_dst[0] << ") y:("
1234 << v_dst[1] << ")"
1235 << "\nThe corresponding distance is: (" << error
1236 << ") but the "
1237 << "allowed\ntolerance is: (" << tolerance_for_connection
1238 << ")" << std::endl;
1239 throw OomphLibError(
1241 }
1242
1243#endif
1244
1247 Final_vertex_connected_n_vertex = vertex_number;
1249 }
1250
1251 // =======================================================================
1252 // Connects the initial vertex of the curve section to a desired
1253 /// target curviline by specifying the s value (intrinsic value on the
1254 /// geometric object of the curviline) where to connect on the target
1255 /// curviline. There is a checking which verifies that the initial vertex
1256 /// and the coordinates on the given s value are close enough by no more
1257 /// than the given tolerance
1258 // =======================================================================
1261 const double& s_value,
1262 const double& tolerance_for_connection)
1263 {
1264#ifdef PARANOID
1265 double z_initial = curviline_pt->zeta_start();
1266 double z_final = curviline_pt->zeta_end();
1267 double z_max = std::max(z_initial, z_final);
1268 double z_min = std::min(z_initial, z_final);
1269 if (s_value < z_min || z_max < s_value)
1270 {
1271 std::ostringstream error_stream;
1272 error_stream << "The s value you provided for connection (" << s_value
1273 << ") is out\nof the limits of the specified "
1274 << "TriangleMeshCurviLine.\nThe limits are [" << z_initial
1275 << ", " << z_final << "]" << std::endl
1276 << "Source boundary (" << boundary_id()
1277 << ") wants to connect "
1278 << "to destination boundary (" << curviline_pt->boundary_id()
1279 << ")" << std::endl;
1280 throw OomphLibError(
1282 }
1283
1284 // Verify if there is really a match point in the specified
1285 // connection values
1288 Vector<double> z(1);
1289
1290 this->initial_vertex_coordinate(v_src);
1291 z[0] = s_value;
1292 curviline_pt->geom_object_pt()->position(z, v_dst);
1293 double error = sqrt((v_src[0] - v_dst[0]) * (v_src[0] - v_dst[0]) +
1294 (v_src[1] - v_dst[1]) * (v_src[1] - v_dst[1]));
1296 {
1297 std::ostringstream error_stream;
1299 << "The associated vertex for the provided connection s value\n"
1300 << "are not close enough. Their respective values are:\n"
1301 << "Source boundary id:(" << this->boundary_id() << ")\n"
1302 << "Source vertex x:(" << v_src[0] << ") y:(" << v_src[1] << ")\n"
1303 << "Destination boundary id:(" << curviline_pt->boundary_id() << ")"
1304 << "\nDestination s value (" << s_value << ")\n"
1305 << "Associated vertex x:(" << v_dst[0] << ") y:(" << v_dst[1] << ")"
1306 << "\nThe corresponding distance is: (" << error << ") but the "
1307 << "allowed\ntolerance is: (" << tolerance_for_connection << ")"
1308 << std::endl;
1309 throw OomphLibError(
1311 }
1312
1313#endif
1314
1319
1320 // We are still not able to compute the vertex number but we can
1321 // at least store the corresponding s value
1322 // The corresponding vertex will be computed when the curviline be
1323 // changed into a polyline
1326
1327 curviline_pt->add_connection_point(s_value, tolerance_for_connection);
1328 }
1329
1330 // =======================================================================
1331 // Connects the final vertex of the curve section to a desired
1332 /// target curviline by specifying the s value (intrinsic value on the
1333 /// geometric object of the curviline) where to connect on the target
1334 /// curviline. There is a checking which verifies that the final vertex
1335 /// and the coordinates on the given s value are close enough by no more
1336 /// than the given tolerance
1337 // =======================================================================
1340 const double& s_value,
1341 const double& tolerance_for_connection)
1342 {
1343#ifdef PARANOID
1344 double z_initial = curviline_pt->zeta_start();
1345 double z_final = curviline_pt->zeta_end();
1346 double z_max = std::max(z_initial, z_final);
1347 double z_min = std::min(z_initial, z_final);
1348 if (s_value < z_min || z_max < s_value)
1349 {
1350 std::ostringstream error_stream;
1351 error_stream << "The s value you provided for connection (" << s_value
1352 << ") is out\nof the limits of the specified "
1353 << "TriangleMeshCurviLine.\nThe limits are [" << z_initial
1354 << ", " << z_final << "]" << std::endl
1355 << "Source boundary (" << boundary_id()
1356 << ") wants to connect "
1357 << "to destination boundary (" << curviline_pt->boundary_id()
1358 << ")" << std::endl;
1359 throw OomphLibError(
1361 }
1362
1363 // Verify if there is really a match point in the specified
1364 // connection values
1367 Vector<double> z(1);
1368
1369 this->final_vertex_coordinate(v_src);
1370 z[0] = s_value;
1371 curviline_pt->geom_object_pt()->position(z, v_dst);
1372
1373 double error = sqrt((v_src[0] - v_dst[0]) * (v_src[0] - v_dst[0]) +
1374 (v_src[1] - v_dst[1]) * (v_src[1] - v_dst[1]));
1375
1377 {
1378 std::ostringstream error_stream;
1380 << "The associated vertex for the provided connection s value\n"
1381 << "are not close enough. Their respective values are:\n"
1382 << "Source boundary id:(" << this->boundary_id() << ")\n"
1383 << "Source vertex x:(" << v_src[0] << ") y:(" << v_src[1] << ")\n"
1384 << "Destination boundary id:(" << curviline_pt->boundary_id() << ")"
1385 << "\nDestination s value (" << s_value << ")\n"
1386 << "Associated vertex x:(" << v_dst[0] << ") y:(" << v_dst[1] << ")"
1387 << "\nThe corresponding distance is: (" << error << ") but the "
1388 << "allowed\ntolerance is: (" << tolerance_for_connection << ")"
1389 << std::endl;
1390 throw OomphLibError(
1392 }
1393
1394#endif
1395
1399 Final_vertex_connected_n_chunk = curviline_pt->boundary_chunk();
1400
1401 // We are still not able to compute the vertex number but we can
1402 // at least store the corresponding s value.
1403 // The corresponding vertex will be computed when the curviline be
1404 // transformed into a polyline
1407
1408 curviline_pt->add_connection_point(s_value, tolerance_for_connection);
1409 }
1410
1411
1412 ///////////////////////////////////////////////////////////////////////
1413 ///////////////////////////////////////////////////////////////////////
1414 //////////////////////////////////////////////////////////////////////
1415
1416
1417 //=====================================================================
1418 /// Class defining a closed curve for the Triangle mesh generation
1419 //=====================================================================
1421 const Vector<TriangleMeshCurveSection*>& curve_section_pt,
1423 const bool& is_internal_point_fixed)
1424 : TriangleMeshCurve(curve_section_pt),
1425 Internal_point_pt(internal_point_pt),
1426 Is_internal_point_fixed(is_internal_point_fixed)
1427 {
1428 // Matching of curve sections i.e. the last vertex of the i curve
1429 // section should match with the first vertex of the i+1 curve
1430 // section
1431
1432 // Total number of boundaries
1433 const unsigned n_boundaries = Curve_section_pt.size();
1434
1435 // Need at least two
1436 if (n_boundaries < 2)
1437 {
1438 std::ostringstream error_stream;
1439 error_stream << "Sorry -- I'm afraid we insist that a closed curve is\n"
1440 << "specified by at least two separate CurveSections.\n"
1441 << "You've only specified (" << n_boundaries << ")"
1442 << std::endl;
1443 throw OomphLibError(
1445 }
1446
1447 // Check last point of each boundary bit coincides with first point
1448 // on next one
1449 for (unsigned i = 0; i < n_boundaries - 1; i++)
1450 {
1451 // Auxiliary vertex for storing the vertex values of contiguous curves
1452 Vector<double> v1(2);
1453
1454 // This is for getting the final coordinates of the i curve section
1455 curve_section_pt[i]->final_vertex_coordinate(v1);
1456
1457 // Auxiliary vertex for storing the vertex values of contiguous curves
1458 Vector<double> v2(2);
1459
1460 // This is for the start coordinates of the i+1 curve section
1461 curve_section_pt[i + 1]->initial_vertex_coordinate(v2);
1462
1463 // Work out error
1464 double error = sqrt(pow(v1[0] - v2[0], 2) + pow(v1[1] - v2[1], 2));
1465
1467 {
1468 std::ostringstream error_stream;
1470 << "The start and end points of curve section boundary parts\n"
1471 << i << " and " << i + 1
1472 << " don't match when judged with the tolerance of "
1474 << " which\nis specified in the namespace variable\n"
1475 << "ToleranceForVertexMismatchInPolygons::Tolerable_error.\n\n"
1476 << "These are the vertices coordinates:\n"
1477 << "Curve section (" << i << ") final vertex: (" << v1[0] << ", "
1478 << v1[1] << ")\n"
1479 << "Curve section (" << i + 1 << ") initial vertex: (" << v2[0]
1480 << ", " << v2[1] << ")\n"
1481 << "The distance between the vertices is (" << error << ")\n"
1482 << "Feel free to adjust this or to recompile the code without\n"
1483 << "paranoia if you think this is OK...\n"
1484 << std::endl;
1485 throw OomphLibError(
1487 }
1488 else
1489 {
1490 // Aligns (only implemented for polylines)
1492 dynamic_cast<TriangleMeshPolyLine*>(Curve_section_pt[i]);
1494 dynamic_cast<TriangleMeshPolyLine*>(Curve_section_pt[i + 1]);
1495
1496 // Was it able to do the cast?
1498 {
1499 unsigned last_vertex = current_polyline->nvertex() - 1;
1500 next_polyline->vertex_coordinate(0) =
1501 current_polyline->vertex_coordinate(last_vertex);
1502 }
1503 }
1504
1505 } // For n_boundaries - 1
1506
1507 // Check wrap around
1508 // Auxiliary vertex for storing the vertex values of contiguous curves
1509 Vector<double> v1(2);
1510
1511 // This is for getting the first coordinates of the first curve section
1512 Curve_section_pt[0]->initial_vertex_coordinate(v1);
1513
1514 // Auxiliary vertex for storing the vertex values of contiguous curves
1515 Vector<double> v2(2);
1516
1517 // This is for getting the last coordinates of the last curve section
1518 Curve_section_pt[n_boundaries - 1]->final_vertex_coordinate(v2);
1519
1520 double error = sqrt(pow(v2[0] - v1[0], 2) + pow(v2[1] - v1[1], 2));
1521
1523 {
1524 std::ostringstream error_stream;
1526 << "The start and end points of the first and last curve segment\n"
1527 << "boundary parts don't match when judged \nwith the tolerance of "
1529 << " which is specified in the namespace \nvariable "
1530 << "ToleranceForVertexMismatchInPolygons::Tolerable_error.\n\n"
1531 << "Feel free to adjust this or to recompile the code without\n"
1532 << "paranoia if you think this is OK...\n"
1533 << std::endl;
1534 throw OomphLibError(
1536 }
1537 else
1538 {
1539 // Aligns (only implemented for polylines)
1541 dynamic_cast<TriangleMeshPolyLine*>(Curve_section_pt[0]);
1544
1545 // Was it able to do the cast?
1547 {
1548 unsigned last_vertex = last_polyline->nvertex() - 1;
1549 first_polyline->vertex_coordinate(0) =
1550 last_polyline->vertex_coordinate(last_vertex);
1551 }
1552 }
1553 }
1554
1555
1556 /////////////////////////////////////////////////////////////////////
1557 /////////////////////////////////////////////////////////////////////
1558 /////////////////////////////////////////////////////////////////////
1559
1560
1561 //=========================================================================
1562 /// Constructor: Specify vector of pointers to TriangleMeshCurveSection
1563 /// that define the boundary of the segments of the polygon.
1564 /// Each TriangleMeshCurveSection has its own boundary ID and can contain
1565 /// multiple (straight-line) segments. For consistency across the
1566 /// various uses of this class, we insist that the closed boundary
1567 /// is represented by at least two separate TriangleMeshCurveSection
1568 /// whose joint vertices must be specified in both.
1569 /// (This is to allow the setup of unique boundary coordinate(s)
1570 /// around the polygon.) This may seem slightly annoying
1571 /// in cases where a polygon really only represents a single
1572 /// boundary, but...
1573 /// Note: The specified vector of pointers must consist of only
1574 /// TriangleMeshPolyLine elements. There is a checking on the PARANOID
1575 /// mode for this constraint
1576 //=========================================================================
1578 const Vector<TriangleMeshCurveSection*>& boundary_polyline_pt,
1580 const bool& is_internal_point_fixed)
1581 : TriangleMeshCurve(boundary_polyline_pt),
1583 boundary_polyline_pt, internal_point_pt, is_internal_point_fixed),
1584 Enable_redistribution_of_segments_between_polylines(false),
1585 Can_update_configuration(false),
1586 Polygon_fixed(false)
1587 {
1588 // Get the number of polylines
1589 const unsigned n_bound = boundary_polyline_pt.size();
1590
1591 // Check that all the constituent TriangleMeshCurveSection are
1592 // instance of TriangleMeshPolyLine
1593 for (unsigned p = 0; p < n_bound; p++)
1594 {
1596 dynamic_cast<TriangleMeshPolyLine*>(boundary_polyline_pt[p]);
1597 if (tmp_polyline_pt == 0)
1598 {
1599 std::ostringstream error_stream;
1600 error_stream << "The (" << p << ") TriangleMeshCurveSection is not a "
1601 << "TriangleMeshPolyLine.\nThe TriangleMeshPolygon object"
1602 << "is constituent of only TriangleMeshPolyLine objects.\n"
1603 << "Verify that all the constituent elements of the "
1604 << "TriangleMeshPolygon\nare instantiated as "
1605 << "TriangleMeshPolyLines." << std::endl;
1606 throw OomphLibError(
1608 }
1609 }
1610
1611 // Check that the polylines are contiguous
1612 bool contiguous = true;
1613 unsigned i_offensive = 0;
1614
1615 // Need at least two
1616 if (n_bound < 2)
1617 {
1618 std::ostringstream error_stream;
1620 << "Sorry -- I'm afraid we insist that a closed curve is\n"
1621 << "specified by at least two separate TriangleMeshPolyLines.\n"
1622 << "You've only specified (" << n_bound << ")" << std::endl;
1623 throw OomphLibError(error_stream.str(),
1624 "TriangleMeshPolygon::TriangleMeshPolygon()",
1626 } // if (n_bound<2)
1627
1628 // Does the last node of the polyline connect to the first one of the
1629 // next one (only up the last but one!)
1630 for (unsigned i = 0; i < n_bound - 1; i++)
1631 {
1632 // Get vector last vertex in current polyline
1633 unsigned last_vertex = (polyline_pt(i)->nvertex()) - 1;
1635
1636 // Get vector to first vertex in next polyline
1638
1639 // Work out error
1640 double error = sqrt(pow(v1[0] - v2[0], 2) + pow(v1[1] - v2[1], 2));
1641
1642 // Is error accetable?
1644 {
1645 contiguous = false;
1646 i_offensive = i;
1647 break;
1648 }
1649 // Align
1650 else
1651 {
1654 }
1655 }
1656
1657 // Does the last one connect to the first one?
1658
1659 // Get vector last vertex last polyline
1660 unsigned last_vertex = (polyline_pt(n_bound - 1)->nvertex()) - 1;
1663
1664 // Get vector first vertex first polyline
1666 double error = sqrt(pow(v1[0] - v2[0], 2) + pow(v1[1] - v2[1], 2));
1667
1669 {
1670 contiguous = false;
1671 i_offensive = n_bound - 1;
1672 }
1673 else
1674 {
1677 }
1678
1679 if (!contiguous)
1680 {
1681 std::ostringstream error_stream;
1683 << "The polylines specified \n"
1684 << "should define a closed geometry, i.e. the first/last vertex of\n"
1685 << "adjacent polylines should match.\n\n"
1686 << "Your polyline number " << i_offensive
1687 << " has no contiguous neighbour, when judged \nwith the tolerance of "
1689 << " which is specified in the namespace \nvariable "
1690 << "ToleranceForVertexMismatchInPolygons::Tolerable_error.\n\n"
1691 << "Feel free to adjust this or to recompile the code without\n"
1692 << "paranoia if you think this is OK...\n"
1693 << std::endl;
1694 throw OomphLibError(error_stream.str(),
1695 "TriangleMeshPolygon::TriangleMeshPolygon()",
1697 }
1698
1699 // Check if internal point is actually located in bounding polygon
1700 // Reference: http://paulbourke.net/geometry/insidepoly/
1701
1702 // Only checked if there is an internal hole
1703 if (!Internal_point_pt.empty())
1704 {
1705 // Vertex coordinates
1707
1708 // Total number of vertices
1709 unsigned nvertex = 0;
1710
1711 // Storage for first/last point on polyline for contiguousness check
1714
1715 // Get vertices
1716 unsigned npolyline = boundary_polyline_pt.size();
1717 for (unsigned i = 0; i < npolyline; i++)
1718 {
1719 // Number of vertices
1720 unsigned nvert = boundary_polyline_pt[i]->nvertex();
1721 for (unsigned j = 0; j < nvert; j++)
1722 {
1723 // Check contiguousness
1724 if ((i > 1) && (j == 0))
1725 {
1727 double dist = sqrt(pow(first_vertex[0] - last_vertex[0], 2) +
1728 pow(first_vertex[1] - last_vertex[1], 2));
1730 {
1731 std::ostringstream error_stream;
1733 << "The start and end points of polylines " << i << " and "
1734 << i + 1 << " don't match when judged\n"
1735 << "with the tolerance ("
1737 << ") which is specified in the namespace \nvariable "
1738 << "ToleranceForVertexMismatchInPolygons::"
1739 << "Tolerable_error.\n\n"
1740 << "Feel free to adjust this or to recompile the "
1741 << "code without\n"
1742 << "paranoia if you think this is OK...\n"
1743 << std::endl;
1744 throw OomphLibError(error_stream.str(),
1745 "TriangleMeshPolygon::TriangleMeshPolygon()",
1747 }
1748 }
1749 // Get vertex (ignore end point)
1750 if (j < nvert - 1)
1751 {
1752 polygon_vertex.push_back(polyline_pt(i)->vertex_coordinate(j));
1753 }
1754 // Prepare for check of contiguousness
1755 else
1756 {
1758 }
1759 }
1760 }
1761
1762 // Total number of vertices
1763 nvertex = polygon_vertex.size();
1764
1765 // Counter for number of intersections
1766 unsigned intersect_counter = 0;
1767
1768 // Get first vertex
1770 for (unsigned i = 1; i <= nvertex; i++)
1771 {
1772 // Get second vertex by wrap-around
1773 Vector<double> p2 = polygon_vertex[i % nvertex];
1774
1775 if (Internal_point_pt[1] > std::min(p1[1], p2[1]))
1776 {
1777 if (Internal_point_pt[1] <= std::max(p1[1], p2[1]))
1778 {
1779 if (Internal_point_pt[0] <= std::max(p1[0], p2[0]))
1780 {
1781 if (p1[1] != p2[1])
1782 {
1783 double xintersect = (Internal_point_pt[1] - p1[1]) *
1784 (p2[0] - p1[0]) / (p2[1] - p1[1]) +
1785 p1[0];
1786 if ((p1[0] == p2[0]) || (Internal_point_pt[0] <= xintersect))
1787 {
1789 }
1790 }
1791 }
1792 }
1793 }
1794 p1 = p2;
1795 }
1796
1797 // Even number of intersections: outside
1798 if (intersect_counter % 2 == 0)
1799 {
1800 std::ostringstream error_stream;
1802 << "The internal point at " << Internal_point_pt[0] << " "
1803 << Internal_point_pt[1]
1804 << " isn't in the polygon that describes the internal closed "
1805 << "curve!\nPolygon vertices are at: \n";
1806 for (unsigned i = 0; i < nvertex; i++)
1807 {
1808 error_stream << polygon_vertex[i][0] << " " << polygon_vertex[i][1]
1809 << "\n";
1810 }
1812 << "This may be because the internal point is defined by a\n"
1813 << "GeomObject that has deformed so much that it's \n"
1814 << "swept over the (initial) internal point.\n"
1815 << "If so, you should update the position of the internal point. \n"
1816 << "This could be done automatically by generating \n"
1817 << "an internal mesh inside the polygon and using one\n"
1818 << "of its internal nodes as the internal point. Actually not \n"
1819 << "why triangle doesn't do that automatically....\n";
1820 throw OomphLibError(error_stream.str(),
1821 "TriangleMeshPolygon::TriangleMeshPolygon()",
1823 }
1824 }
1825 }
1826
1827
1828 /////////////////////////////////////////////////////////////////////
1829 /////////////////////////////////////////////////////////////////////
1830 /////////////////////////////////////////////////////////////////////
1831
1832
1833 //=====================================================================
1834 /// Class defining an open curve for the Triangle mesh generation
1835 //=====================================================================
1837 const Vector<TriangleMeshCurveSection*>& curve_section_pt)
1838 : TriangleMeshCurve(curve_section_pt)
1839 {
1840 // Matching of curve sections i.e. the last vertex of
1841 // the i curve section should match with the first
1842 // vertex of the i+1 curve section
1843
1844 // Total number of boundaries
1845 unsigned n_boundaries = Curve_section_pt.size();
1846
1847 // Check last point of each boundary bit coincides with first point
1848 // on next one
1849 for (unsigned i = 0; i < n_boundaries - 1; i++)
1850 {
1851 // Auxiliary vertex for storing the vertex values of contiguous curves
1852 Vector<double> v1(2);
1853 Vector<double> v2(2);
1854
1855 // This is for getting the final coordinates of the i curve section
1856 Curve_section_pt[i]->final_vertex_coordinate(v1);
1857
1858 // This is for the start coordinates of the i+1 curve section
1859 Curve_section_pt[i + 1]->initial_vertex_coordinate(v2);
1860
1861 // Work out error
1862 double error = sqrt(pow(v1[0] - v2[0], 2) + pow(v1[1] - v2[1], 2));
1864 {
1865 std::ostringstream error_stream;
1867 << "The start and end points of curve section boundary parts " << i
1868 << " and " << i + 1
1869 << " don't match when judged \nwith the tolerance of "
1871 << " which is specified in the namespace \nvariable "
1872 << "ToleranceForVertexMismatchInPolygons::Tolerable_error.\n\n"
1873 << "Feel free to adjust this or to recompile the code without\n"
1874 << "paranoia if you think this is OK...\n"
1875 << std::endl;
1876 throw OomphLibError(
1878 }
1879 else
1880 {
1881 // Aligns (only implemented for polylines)
1883 dynamic_cast<TriangleMeshPolyLine*>(Curve_section_pt[i]);
1885 dynamic_cast<TriangleMeshPolyLine*>(Curve_section_pt[i + 1]);
1886
1888 {
1889 unsigned last_vertex = current_polyline->nvertex() - 1;
1890 next_polyline->vertex_coordinate(0) =
1891 current_polyline->vertex_coordinate(last_vertex);
1892 }
1893 }
1894
1895 } // For n_boundaries - 1
1896 }
1897
1898#ifdef OOMPH_HAS_TRIANGLE_LIB
1899
1900 //======================================================================
1901 /// Create TriangulateIO object from outer boundaries, internal
1902 /// boundaries, and open curves. Add the holes and regions
1903 /// information as well
1904 //======================================================================
1909 Vector<Vector<double>>& extra_holes_coordinates,
1910 std::map<unsigned, Vector<double>>& regions_coordinates,
1911 std::map<unsigned, double>& regions_areas,
1913 {
1914 // These are the general stages of the algorithm
1915 // --------------------------------------------------------------------
1916 // 1) Create the boundary connections structure, every entry states
1917 // if the initial or final vertex is connected to other vertex
1918 // --------------------------------------------------------------------
1919 // 2) Create the structure for base vertices, the base vertices are
1920 // those that are not connected
1921 // --------------------------------------------------------------------
1922 // 3) Assign a unique id to each vertex in the polylines (creates a
1923 // look up scheme used to create the segments)
1924 // --------------------------------------------------------------------
1925 // 4) Create the segments using the unique id of the vertices and
1926 // assign a segment id to each segment (the one from the
1927 // polyline-boundary)
1928 // ------------------------------------------------------------------
1929 // 5) Fill the triangulateio containers with the collected
1930 // information
1931 // --------------------------------------------------------------
1932
1933 // ------------------------------------------------------------------
1934 // 1st- stage
1935
1936 // 1) Create the boundary connections structure for the outer
1937 // boundaries, internal boundaries and open curves
1938
1939 // Store the number of vertices on each boundary (which is
1940 // represented by a polyline -- for quick access--). We may have
1941 // more than one polyline with the same boundary id, that is why we
1942 // need a vector to represent the set of polylines associated to a
1943 // boundary (the chunks). The mentioned case is quite common when
1944 // working in parallel, when a boundary may be split because of the
1945 // distribution strategy
1946 std::map<unsigned, std::map<unsigned, unsigned>> boundary_chunk_n_vertices;
1947
1948 // Note: For each polyline, we only consider (v-1) vertices since
1949 // the first vertex of the p-th polyline (when p > 1) is the same as
1950 // the last vertex of the (p-1)-th polyline (when p > 1). KEEP THIS
1951 // ---ALWAYS--- IN MIND WHEN REVIEWING THE CODE
1952
1953 // The connections matrix
1954
1955 // Stores the vertex_connection_info:
1956 // - is_connected
1957 // - boundary_id_to_connect
1958 // - boundary_chunk_to_connect
1959 // - vertex_number_to_connect
1960 // of the initial and final vertex of each polyline
1961 // -----------------------
1962 // (boundary, chunk#, vertex (initial[0] or final[1])) ->
1963 // vertex_connection_info
1964 // -----------------------
1965 // map[x][][] = boundary_id
1966 // map[][x][] = chunk_id
1967 // Vector[][][x] = vertex#, only initial or final (that is why only
1968 // two indexes)
1969 std::map<unsigned, std::map<unsigned, Vector<vertex_connection_info>>>
1971
1972 // Initialize the base vertex structure (every vertex is a not base
1973 // vertex by default)
1974
1975 // The data structure that stores the base vertex information
1976 // Stores the base_vertex_info:
1977 // - done
1978 // - base_vertex
1979 // - boundary_id
1980 // - boundary_chunk
1981 // - vertex_number
1982 // of the initial and final vertex of each polyline
1983 // -----------------------
1984 // (boundary, chunk#, vertex (initial[0] or final[1])) -> base_vertex_info
1985 // -----------------------
1986 // map[x][][] = boundary_id
1987 // map[][x][] = chunk_id
1988 // Vector[][][x] = vertex#, only initial or final (that is why only
1989 // two indexes)
1990 std::map<unsigned, std::map<unsigned, Vector<base_vertex_info>>>
1992
1993 // Get the number of outer polygons
1994 const unsigned n_outer_polygons = outer_polygons_pt.size();
1995
1996 for (unsigned i = 0; i < n_outer_polygons; i++)
1997 {
1998 // The number of polylines in the current polygon
1999 const unsigned n_polylines = outer_polygons_pt[i]->npolyline();
2000
2001 for (unsigned p = 0; p < n_polylines; p++)
2002 {
2003 // Get a pointer to the current polyline
2005 outer_polygons_pt[i]->polyline_pt(p);
2006
2007 // Get the boundary id of the current polyline
2008 const unsigned bound_id = tmp_polyline_pt->boundary_id();
2009
2010 // The number of vertices in the current polyline
2011 const unsigned n_vertices = tmp_polyline_pt->nvertex();
2012
2013 // Get the chunk number associated with this boundary
2014 const unsigned bound_chunk = tmp_polyline_pt->boundary_chunk();
2015
2016 // Store the number of vertices of the polyline in the global
2017 // storage
2019
2020 // Get the next polyline (or the initial polyline)
2022
2023 // Is there next polyline
2024 if (p < n_polylines - 1)
2025 {
2026 // Set the next polyline
2027 next_polyline_pt = outer_polygons_pt[i]->polyline_pt(p + 1);
2028 }
2029 else
2030 {
2031 // The next polyline is the initial polyline
2032 next_polyline_pt = outer_polygons_pt[i]->polyline_pt(0);
2033 }
2034
2035 // Add the information to the connections matrix
2038
2039 // Initialise the base vertices structure for the current
2040 // polyline
2042
2043 } // for (p < n_polylines)
2044
2045 } // for (i < n_outer_polygons)
2046
2047 // Get the number of internal polygons
2049
2050 for (unsigned i = 0; i < n_internal_polygons; i++)
2051 {
2052 // The number of polylines in the current polygon
2053 const unsigned n_polylines = internal_polygons_pt[i]->npolyline();
2054
2055 for (unsigned p = 0; p < n_polylines; p++)
2056 {
2057 // Get a pointer to the current polyline
2059 internal_polygons_pt[i]->polyline_pt(p);
2060
2061 // Get the boundary id of the current polyline
2062 const unsigned bound_id = tmp_polyline_pt->boundary_id();
2063
2064 // The number of vertices in the current polyline
2065 const unsigned n_vertices = tmp_polyline_pt->nvertex();
2066
2067 // Get the chunk number associated with this boundary
2068 const unsigned bound_chunk = tmp_polyline_pt->boundary_chunk();
2069
2070 // Store the number of vertices of the polyline in the global
2071 // storage
2073
2074 // Get the next polyline (or the initial polyline)
2076
2077 // Is there next polyline
2078 if (p < n_polylines - 1)
2079 {
2080 // Set the next polyline
2081 next_polyline_pt = internal_polygons_pt[i]->polyline_pt(p + 1);
2082 }
2083 else
2084 {
2085 // The next polyline is the initial polyline
2086 next_polyline_pt = internal_polygons_pt[i]->polyline_pt(0);
2087 }
2088
2089 // Add the information to the connections matrix
2092
2093 // Initialise the base vertices structure for the current
2094 // polyline
2096
2097 } // for (p < n_polylines)
2098
2099 } // for (i < n_internal_polygons)
2100
2101 // Get the number of open curves
2102 const unsigned n_open_curves = open_curves_pt.size();
2103
2104 for (unsigned i = 0; i < n_open_curves; i++)
2105 {
2106 // The number of polylines in the current polygon
2107 const unsigned n_polylines = open_curves_pt[i]->ncurve_section();
2108
2109 for (unsigned p = 0; p < n_polylines; p++)
2110 {
2111 // Get a pointer to the current polyline
2113 open_curves_pt[i]->polyline_pt(p);
2114
2115 // Get the boundary id of the current polyline
2116 const unsigned bound_id = tmp_polyline_pt->boundary_id();
2117
2118 // The number of vertices in the current polyline
2119 const unsigned n_vertices = tmp_polyline_pt->nvertex();
2120
2121 // Get the chunk number associated with this boundary
2122 const unsigned bound_chunk = tmp_polyline_pt->boundary_chunk();
2123
2124 // Store the number of vertices of the polyline in the global
2125 // storage
2127
2128 // Get the next polyline (or the initial polyline)
2130
2131 // Is there next polyline
2132 if (p < n_polylines - 1)
2133 {
2134 // Set the next polyline
2135 next_polyline_pt = open_curves_pt[i]->polyline_pt(p + 1);
2136 }
2137 else
2138 {
2139 // If we are in the last polyline of the open curve there is
2140 // no actual next polyline
2141 }
2142
2143 // Add the information to the connections matrix
2146
2147 // Initialise the base vertices structure for the current
2148 // polyline
2150
2151 } // for (p < n_polylines)
2152
2153 } // for (i < n_open_curves)
2154
2155 // ------------------------------------------------------------------
2156
2157 // ------------------------------------------------------------------
2158 // 2) Create the structure for base vertices, the base vertices are
2159 // those that are not connected
2160 // ------------------------------------------------------------------
2161
2162 // Loop over the polylines in the outer polygons and indentify the
2163 // base vertices
2164 for (unsigned i = 0; i < n_outer_polygons; i++)
2165 {
2166 // The number of polylines in the current polygon
2167 const unsigned n_polylines = outer_polygons_pt[i]->npolyline();
2168
2169 for (unsigned p = 0; p < n_polylines; p++)
2170 {
2171 // Get a pointer to the current polyline
2173 outer_polygons_pt[i]->polyline_pt(p);
2174
2175 // Identify the base vertices in the current polyline
2180
2181 } // for (p < n_polylines)
2182
2183 } // for (i < n_outer_polygons)
2184
2185 // Loop over the polylines in the internal polygons and indentify the
2186 // base vertices
2187 for (unsigned i = 0; i < n_internal_polygons; i++)
2188 {
2189 // The number of polylines in the current polygon
2190 const unsigned n_polylines = internal_polygons_pt[i]->npolyline();
2191
2192 for (unsigned p = 0; p < n_polylines; p++)
2193 {
2194 // Get a pointer to the current polyline
2196 internal_polygons_pt[i]->polyline_pt(p);
2197
2198 // Identify the base vertices in the current polyline
2203
2204 } // for (p < n_polylines)
2205
2206 } // for (i < n_internal_polygons)
2207
2208 // Loop over the polylines in the open curves and indentify the base
2209 // vertices
2210 for (unsigned i = 0; i < n_open_curves; i++)
2211 {
2212 // The number of polylines in the current polygon
2213 const unsigned n_polylines = open_curves_pt[i]->ncurve_section();
2214
2215 for (unsigned p = 0; p < n_polylines; p++)
2216 {
2217 // Get a pointer to the current polyline
2219 open_curves_pt[i]->polyline_pt(p);
2220
2221 // Identify the base vertices in the current polyline
2226
2227 } // for (p < n_polylines)
2228
2229 } // for (i < n_open_curves)
2230
2231 // ------------------------------------------------------------------
2232
2233 // ------------------------------------------------------------------
2234 // 3) Assign a unique id to each vertex in the polylines (creates a
2235 // look up scheme used to create the segments)
2236 // ------------------------------------------------------------------
2237
2238 // Create the storage for the look-up scheme
2239 // (boundary_local, chunk#, vertex#) -> global_vertex_id
2240 // map[x][][] = boundary
2241 // map[][x][] = chunk_id
2242 // Vector[][][x] = vertex#
2243 std::map<unsigned, std::map<unsigned, Vector<int>>>
2245
2246 // Create an entry in the map for each boundary, then do the same
2247 // for the chunks and finally resize the container (Vector) to store
2248 // the vertices
2249 for (std::map<unsigned, std::map<unsigned, unsigned>>::iterator it =
2252 it++)
2253 {
2254 // Get the boundary id
2255 const unsigned b = (*it).first;
2256
2257 // Now loop over the chunks
2258 for (std::map<unsigned, unsigned>::iterator itt = (*it).second.begin();
2259 itt != (*it).second.end();
2260 itt++)
2261 {
2262 // Get the chunk id
2263 const unsigned c = (*itt).first;
2264
2265 // Get the number of vertices associated with the boundary-chunk
2266 // and resize the container
2267 const unsigned n_vertices = boundary_chunk_n_vertices[b][c];
2268
2269 // Now create storage in the container and resize the vector that
2270 // stores the vertices ids. Initialize the entries to -1
2272
2273 } // Loop over the chunks
2274
2275 } // Loop over the boundaries
2276
2277 // Counter for the numbering of the global vertices
2278 unsigned global_vertex_number = 0;
2279
2280 // Container for the vertices
2282
2283 // Go through all the vertices in the polylines and assign a unique
2284 // id only to the base vertices, any other vertex copy the unique id
2285 // from its base vertex
2286
2287 // The total number of added vertices in the outer polygons
2288 unsigned n_vertices_outer_polygons = 0;
2289
2290 // Start with the outer polygons
2291 for (unsigned i = 0; i < n_outer_polygons; i++)
2292 {
2293 // The number of polylines in the current polygon
2294 const unsigned n_polylines = outer_polygons_pt[i]->npolyline();
2295
2296 for (unsigned p = 0; p < n_polylines; p++)
2297 {
2298 // Get a pointer to the current polyline
2300 outer_polygons_pt[i]->polyline_pt(p);
2301
2302 // Get the boundary id of the current polyline
2303 const unsigned bound_id = tmp_polyline_pt->boundary_id();
2304
2305 // The number of vertices in the current polyline
2306 const unsigned n_vertices = tmp_polyline_pt->nvertex();
2307
2308 // Get the current chunk number of the polyline
2309 const unsigned bnd_chunk = tmp_polyline_pt->boundary_chunk();
2310
2311 // Assign a global vertex id to the initial vertex
2312 // -----------------------------------------------
2313
2314 // Get the base vertex information of the initial vertex
2317
2318#ifdef PARANOID
2319 if (!initial_base_vertex_info.has_base_vertex_assigned)
2320 {
2321 std::ostringstream error_message;
2322 std::string output_string =
2323 "UnstructuredTwoDMeshGeometryBase::build_triangulateio()";
2324 error_message
2325 << "The initial vertex of the current polyline has no base\n"
2326 << "vertex assigned\n"
2327 << "Outer polygon number: (" << i << ")\n\n"
2328 << "Polyline number: (" << p << ")\n"
2329 << "Boundary id: (" << bound_id << ")\n"
2330 << "Boundary chunk: (" << bnd_chunk << ")\n";
2331 throw OomphLibError(
2332 error_message.str(), output_string, OOMPH_EXCEPTION_LOCATION);
2333 } // if (!initial_base_vertex_info.has_base_vertex_assigned)
2334#endif
2335
2336 // The base vertex boundary id
2337 unsigned bvbi = initial_base_vertex_info.boundary_id;
2338 // The base vertex boundary chunkx
2339 unsigned bvbc = initial_base_vertex_info.boundary_chunk;
2340 // The vertex number of the base vertex
2341 unsigned bvvn = initial_base_vertex_info.vertex_number;
2342
2343 // Get the global vertex id of the base vertex
2344 int global_vertex_id =
2346
2347 // Check if the global vertex id has been already assigned
2348 if (global_vertex_id != -1)
2349 {
2350 // If that is the case then copy the global vertex id in the
2351 // current slot
2354 } // if (global_vertex_id != -1)
2355 else
2356 {
2357 // Assign a global vertex id to the base vertex
2360
2361 // ... and copy the value to the initial vertex
2364
2365 // ... increase the counter for the "global_vertex_number"
2367
2368 // Get the vertex
2369 Vector<double> vertex = tmp_polyline_pt->vertex_coordinate(0);
2370
2371 // ... and add it to the global vertex container
2372 global_vertices.push_back(vertex);
2373 }
2374
2375 // Is the initial vertex a base vertex
2376 if (initial_base_vertex_info.is_base_vertex)
2377 {
2378 // Increase the independent vertices counter
2380 }
2381
2382 // ------------------------------------------------------------
2383 // Now loop over the intermediate vertices and assign a unique
2384 // vertex id (all intermediate vertices are base vertices)
2385 for (unsigned v = 1; v < n_vertices - 1; v++)
2386 {
2387 // Get the global vertex id
2390
2391 // Check if the global vertex id has been already assigned.
2392 // We do nothing if it has been already assigned
2393 // (global_vertex_id!=-1).
2394
2395 // If it has not been already assigned (global_vertex_id==-1)
2396 // then set a new global vertex number, and add the vertex to
2397 // the global vertices container
2398 if (global_vertex_id == -1)
2399 {
2400 // Set a value for the global vertex
2403
2404 // ... increase the counter for the "global_vertex_number"
2406
2407 // Add the vertex to the global vertex container
2408 Vector<double> vertex = tmp_polyline_pt->vertex_coordinate(v);
2409 // Add the vertex to the global vertex container
2410 global_vertices.push_back(vertex);
2411
2412 } // if (global_vertex_id == -1)
2413
2414 // Increase the independent vertices counter
2416
2417 } // for (n_vertices-1)
2418
2419 // Assign a global vertex id to the final vertex
2420 // -----------------------------------------------
2421
2422 // Get the base vertex information of the final vertex
2425
2426#ifdef PARANOID
2427 if (!final_base_vertex_info.has_base_vertex_assigned)
2428 {
2429 std::ostringstream error_message;
2430 std::string output_string =
2431 "UnstructuredTwoDMeshGeometryBase::build_triangulateio()";
2432 error_message
2433 << "The final vertex of the current polyline has no base\n"
2434 << "vertex assigned\n"
2435 << "Outer polygon number: (" << i << ")\n\n"
2436 << "Polyline number: (" << p << ")\n"
2437 << "Boundary id: (" << bound_id << ")\n"
2438 << "Boundary chunk: (" << bnd_chunk << ")\n";
2439 throw OomphLibError(
2440 error_message.str(), output_string, OOMPH_EXCEPTION_LOCATION);
2441 } // if (!final_base_vertex_info.has_base_vertex_assigned)
2442#endif
2443
2444 // The base vertex boundary id
2445 bvbi = final_base_vertex_info.boundary_id;
2446 // The base vertex boundary chunkx
2447 bvbc = final_base_vertex_info.boundary_chunk;
2448 // The vertex number of the base vertex
2449 bvvn = final_base_vertex_info.vertex_number;
2450
2451 // Get the global vertex id of the base vertex
2454
2455 // Check if the global vertex id has been already assigned
2456 if (global_vertex_id != -1)
2457 {
2458 // If that is the case then copy the global vertex id in the
2459 // current slot
2461 [n_vertices - 1] =
2463 } // if (global_vertex_id != -1)
2464 else
2465 {
2466 // Assign a global vertex id to the base vertex
2469
2470 // ... and copy the value to the final vertex
2472 [n_vertices - 1] =
2474
2475 // ... increase the counter for the "global_vertex_number"
2477
2478 // Get the vertex
2480 tmp_polyline_pt->vertex_coordinate(n_vertices - 1);
2481
2482 // ... and add it to the global vertex container
2483 global_vertices.push_back(vertex);
2484 }
2485
2486 // Is the final vertex a base vertex
2487 if (final_base_vertex_info.is_base_vertex)
2488 {
2489 // Increase the independent vertices counter
2491 }
2492
2493 } // for (p < n_polylines)
2494
2495 } // for (i < n_outer_polygons)
2496
2497 // The total number of added vertices in the internal polygons
2498 unsigned n_vertices_internal_polygons = 0;
2499
2500 // Do the internal polygons
2501 for (unsigned i = 0; i < n_internal_polygons; i++)
2502 {
2503 // The number of polylines in the current polygon
2504 const unsigned n_polylines = internal_polygons_pt[i]->npolyline();
2505
2506 for (unsigned p = 0; p < n_polylines; p++)
2507 {
2508 // Get a pointer to the current polyline
2510 internal_polygons_pt[i]->polyline_pt(p);
2511
2512 // Get the boundary id of the current polyline
2513 const unsigned bound_id = tmp_polyline_pt->boundary_id();
2514
2515 // The number of vertices in the current polyline
2516 const unsigned n_vertices = tmp_polyline_pt->nvertex();
2517
2518 // Get the current chunk number of the polyline
2519 const unsigned bnd_chunk = tmp_polyline_pt->boundary_chunk();
2520
2521 // Assign a global vertex id to the initial vertex
2522 // -----------------------------------------------
2523
2524 // Get the base vertex information of the initial vertex
2527
2528#ifdef PARANOID
2529 if (!initial_base_vertex_info.has_base_vertex_assigned)
2530 {
2531 std::ostringstream error_message;
2532 std::string output_string =
2533 "UnstructuredTwoDMeshGeometryBase::build_triangulateio()";
2534 error_message
2535 << "The initial vertex of the current polyline has no base\n"
2536 << "vertex assigned\n"
2537 << "Internal polygon number: (" << i << ")\n\n"
2538 << "Polyline number: (" << p << ")\n"
2539 << "Boundary id: (" << bound_id << ")\n"
2540 << "Boundary chunk: (" << bnd_chunk << ")\n";
2541 throw OomphLibError(
2542 error_message.str(), output_string, OOMPH_EXCEPTION_LOCATION);
2543 } // if (!initial_base_vertex_info.has_base_vertex_assigned)
2544#endif
2545
2546 // The base vertex boundary id
2547 unsigned bvbi = initial_base_vertex_info.boundary_id;
2548 // The base vertex boundary chunkx
2549 unsigned bvbc = initial_base_vertex_info.boundary_chunk;
2550 // The vertex number of the base vertex
2551 unsigned bvvn = initial_base_vertex_info.vertex_number;
2552
2553 // Get the global vertex id of the base vertex
2554 int global_vertex_id =
2556
2557 // Check if the global vertex id has been already assigned
2558 if (global_vertex_id != -1)
2559 {
2560 // If that is the case then copy the global vertex id in the
2561 // current slot
2564 } // if (global_vertex_id != -1)
2565 else
2566 {
2567 // Assign a global vertex id to the base vertex
2570
2571 // ... and copy the value to the initial vertex
2574
2575 // ... increase the counter for the "global_vertex_number"
2577
2578 // Get the vertex
2579 Vector<double> vertex = tmp_polyline_pt->vertex_coordinate(0);
2580
2581 // ... and add it to the global vertex container
2582 global_vertices.push_back(vertex);
2583 }
2584
2585 // Is the initial vertex a base vertex
2586 if (initial_base_vertex_info.is_base_vertex)
2587 {
2588 // Increase the independent vertices counter
2590 }
2591
2592 // ------------------------------------------------------------
2593 // Now loop over the intermediate vertices and assign a unique
2594 // vertex id (all intermediate vertices are base vertices)
2595 for (unsigned v = 1; v < n_vertices - 1; v++)
2596 {
2597 // Get the global vertex id
2600
2601 // Check if the global vertex id has been already assigned.
2602 // We do nothing if it has been already assigned
2603 // (global_vertex_id!=-1).
2604
2605 // If it has not been already assigned (global_vertex_id==-1)
2606 // then set a new global vertex number, and add the vertex to
2607 // the global vertices container
2608 if (global_vertex_id == -1)
2609 {
2610 // Set a value for the global vertex
2613
2614 // ... increase the counter for the "global_vertex_number"
2616
2617 // Add the vertex to the global vertex container
2618 Vector<double> vertex = tmp_polyline_pt->vertex_coordinate(v);
2619 // Add the vertex to the global vertex container
2620 global_vertices.push_back(vertex);
2621
2622 } // if (global_vertex_id == -1)
2623
2624 // Increase the independent vertices counter
2626
2627 } // for (n_vertices-1)
2628
2629 // Assign a global vertex id to the final vertex
2630 // -----------------------------------------------
2631
2632 // Get the base vertex information of the final vertex
2635
2636#ifdef PARANOID
2637 if (!final_base_vertex_info.has_base_vertex_assigned)
2638 {
2639 std::ostringstream error_message;
2640 std::string output_string =
2641 "UnstructuredTwoDMeshGeometryBase::build_triangulateio()";
2642 error_message
2643 << "The final vertex of the current polyline has no base\n"
2644 << "vertex assigned\n"
2645 << "Internal polygon number: (" << i << ")\n\n"
2646 << "Polyline number: (" << p << ")\n"
2647 << "Boundary id: (" << bound_id << ")\n"
2648 << "Boundary chunk: (" << bnd_chunk << ")\n";
2649 throw OomphLibError(
2650 error_message.str(), output_string, OOMPH_EXCEPTION_LOCATION);
2651 } // if (!final_base_vertex_info.has_base_vertex_assigned)
2652#endif
2653
2654 // The base vertex boundary id
2655 bvbi = final_base_vertex_info.boundary_id;
2656 // The base vertex boundary chunkx
2657 bvbc = final_base_vertex_info.boundary_chunk;
2658 // The vertex number of the base vertex
2659 bvvn = final_base_vertex_info.vertex_number;
2660
2661 // Get the global vertex id of the base vertex
2664
2665 // Check if the global vertex id has been already assigned
2666 if (global_vertex_id != -1)
2667 {
2668 // If that is the case then copy the global vertex id in the
2669 // current slot
2671 [n_vertices - 1] =
2673 } // if (global_vertex_id != -1)
2674 else
2675 {
2676 // Assign a global vertex id to the base vertex
2679
2680 // ... and copy the value to the final vertex
2682 [n_vertices - 1] =
2684
2685 // ... increase the counter for the "global_vertex_number"
2687
2688 // Get the vertex
2690 tmp_polyline_pt->vertex_coordinate(n_vertices - 1);
2691
2692 // ... and add it to the global vertex container
2693 global_vertices.push_back(vertex);
2694 }
2695
2696 // Is the final vertex a base vertex
2697 if (final_base_vertex_info.is_base_vertex)
2698 {
2699 // Increase the independent vertices counter
2701 }
2702
2703 } // for (p < n_polylines)
2704
2705 } // for (i < n_internal_polygons)
2706
2707 // The total number of added vertices in the open curves
2708 unsigned n_vertices_open_curves = 0;
2709
2710 // Do the open curves
2711 for (unsigned i = 0; i < n_open_curves; i++)
2712 {
2713 // The number of polylines in the current polygon
2714 const unsigned n_polylines = open_curves_pt[i]->ncurve_section();
2715
2716 for (unsigned p = 0; p < n_polylines; p++)
2717 {
2718 // Get a pointer to the current polyline
2720 open_curves_pt[i]->polyline_pt(p);
2721
2722 // Get the boundary id of the current polyline
2723 const unsigned bound_id = tmp_polyline_pt->boundary_id();
2724
2725 // The number of vertices in the current polyline
2726 const unsigned n_vertices = tmp_polyline_pt->nvertex();
2727
2728 // Get the current chunk number of the polyline
2729 const unsigned bnd_chunk = tmp_polyline_pt->boundary_chunk();
2730
2731 // Assign a global vertex id to the initial vertex
2732 // -----------------------------------------------
2733
2734 // Get the base vertex information of the initial vertex
2737
2738#ifdef PARANOID
2739 if (!initial_base_vertex_info.has_base_vertex_assigned)
2740 {
2741 std::ostringstream error_message;
2742 std::string output_string =
2743 "UnstructuredTwoDMeshGeometryBase::build_triangulateio()";
2744 error_message
2745 << "The initial vertex of the current polyline has no base\n"
2746 << "vertex assigned\n"
2747 << "Open curve number: (" << i << ")\n\n"
2748 << "Polyline number: (" << p << ")\n"
2749 << "Boundary id: (" << bound_id << ")\n"
2750 << "Boundary chunk: (" << bnd_chunk << ")\n";
2751 throw OomphLibError(
2752 error_message.str(), output_string, OOMPH_EXCEPTION_LOCATION);
2753 } // if (!initial_base_vertex_info.has_base_vertex_assigned)
2754#endif
2755
2756 // The base vertex boundary id
2757 unsigned bvbi = initial_base_vertex_info.boundary_id;
2758 // The base vertex boundary chunkx
2759 unsigned bvbc = initial_base_vertex_info.boundary_chunk;
2760 // The vertex number of the base vertex
2761 unsigned bvvn = initial_base_vertex_info.vertex_number;
2762
2763 // Get the global vertex id of the base vertex
2764 int global_vertex_id =
2766
2767 // Check if the global vertex id has been already assigned
2768 if (global_vertex_id != -1)
2769 {
2770 // If that is the case then copy the global vertex id in the
2771 // current slot
2774 } // if (global_vertex_id != -1)
2775 else
2776 {
2777 // Assign a global vertex id to the base vertex
2780
2781 // ... and copy the value to the initial vertex
2784
2785 // ... increase the counter for the "global_vertex_number"
2787
2788 // Get the vertex
2789 Vector<double> vertex = tmp_polyline_pt->vertex_coordinate(0);
2790
2791 // ... and add it to the global vertex container
2792 global_vertices.push_back(vertex);
2793 }
2794
2795 // Is the initial vertex a base vertex
2796 if (initial_base_vertex_info.is_base_vertex)
2797 {
2798 // Increase the independent vertices counter
2800 }
2801
2802 // ------------------------------------------------------------
2803 // Now loop over the intermediate vertices and assign a unique
2804 // vertex id (all intermediate vertices are base vertices)
2805 for (unsigned v = 1; v < n_vertices - 1; v++)
2806 {
2807 // Get the global vertex id
2810
2811 // Check if the global vertex id has been already assigned.
2812 // We do nothing if it has been already assigned
2813 // (global_vertex_id!=-1).
2814
2815 // If it has not been already assigned (global_vertex_id==-1)
2816 // then set a new global vertex number, and add the vertex to
2817 // the global vertices container
2818 if (global_vertex_id == -1)
2819 {
2820 // Set a value for the global vertex
2823
2824 // ... increase the counter for the "global_vertex_number"
2826
2827 // Add the vertex to the global vertex container
2828 Vector<double> vertex = tmp_polyline_pt->vertex_coordinate(v);
2829 // Add the vertex to the global vertex container
2830 global_vertices.push_back(vertex);
2831
2832 } // if (global_vertex_id == -1)
2833
2834 // Increase the independent vertices counter
2836
2837 } // for (n_vertices-1)
2838
2839 // Assign a global vertex id to the final vertex
2840 // -----------------------------------------------
2841
2842 // Get the base vertex information of the final vertex
2845
2846#ifdef PARANOID
2847 if (!final_base_vertex_info.has_base_vertex_assigned)
2848 {
2849 std::ostringstream error_message;
2850 std::string output_string =
2851 "UnstructuredTwoDMeshGeometryBase::build_triangulateio()";
2852 error_message
2853 << "The final vertex of the current polyline has no base\n"
2854 << "vertex assigned\n"
2855 << "Open curve number: (" << i << ")\n\n"
2856 << "Polyline number: (" << p << ")\n"
2857 << "Boundary id: (" << bound_id << ")\n"
2858 << "Boundary chunk: (" << bnd_chunk << ")\n";
2859 throw OomphLibError(
2860 error_message.str(), output_string, OOMPH_EXCEPTION_LOCATION);
2861 } // if (!final_base_vertex_info.has_base_vertex_assigned)
2862#endif
2863
2864 // The base vertex boundary id
2865 bvbi = final_base_vertex_info.boundary_id;
2866 // The base vertex boundary chunkx
2867 bvbc = final_base_vertex_info.boundary_chunk;
2868 // The vertex number of the base vertex
2869 bvvn = final_base_vertex_info.vertex_number;
2870
2871 // Get the global vertex id of the base vertex
2874
2875 // Check if the global vertex id has been already assigned
2876 if (global_vertex_id != -1)
2877 {
2878 // If that is the case then copy the global vertex id in the
2879 // current slot
2881 [n_vertices - 1] =
2883 } // if (global_vertex_id != -1)
2884 else
2885 {
2886 // Assign a global vertex id to the base vertex
2889
2890 // ... and copy the value to the final vertex
2892 [n_vertices - 1] =
2894
2895 // ... increase the counter for the "global_vertex_number"
2897
2898 // Get the vertex
2900 tmp_polyline_pt->vertex_coordinate(n_vertices - 1);
2901
2902 // ... and add it to the global vertex container
2903 global_vertices.push_back(vertex);
2904 }
2905
2906 // Is the final vertex a base vertex
2907 if (final_base_vertex_info.is_base_vertex)
2908 {
2909 // Increase the independent vertices counter
2911 }
2912
2913 } // for (p < n_polylines)
2914
2915 } // for (i < n_open_curves)
2916
2917 // We have already assigned a unique id for each vertex in the
2918 // boundaries, and we have collected all the vertices in a container
2919
2920 // Store the global number of vertices. Add the number of vertices
2921 // of all the polygons (outer and internal), and the open curves to
2922 // get the total number of vertices. NB This is the number of NON
2923 // REPEATED vertices, the sum of all the vertices of each individual
2924 // polyline can be computed from the boundary_chunk_nvertices
2925 // container
2929
2930#ifdef PARANOID
2931 // Check that the total number of vertices be equal to the
2932 // pre-computed number of vertices
2933 const unsigned added_global_vertices = global_vertices.size();
2935 {
2936 std::ostringstream error_stream;
2937 std::string output_string =
2938 "UnstructuredTwoDMeshGeometryBase::build_triangulateio()";
2940 << "The number of added vertices to the global vertices container\n"
2941 << "is different from the pre-computed number of vertices\n"
2942 << "Added number of vertices: (" << added_global_vertices << ")\n"
2943 << "Pre-computed number of global vertices: (" << n_global_vertices
2944 << ")\n";
2945 throw OomphLibError(
2947 } // if (added_global_vertices != n_global_vertices)
2948
2949 // Check that the counter for the global number of vertices is the same as
2950 // the pre-computed number of vertices
2952 {
2953 std::ostringstream error_stream;
2954 std::string output_string =
2955 "UnstructuredTwoDMeshGeometryBase::build_triangulateio()";
2957 << "The counter for the global number of vertices is different from\n"
2958 << "the pre-computed number of vertices\n"
2959 << "Global vertices counter: (" << global_vertex_number << ")\n"
2960 << "Pre-computed number of global vertices: (" << n_global_vertices
2961 << ")\n";
2962 throw OomphLibError(
2964 } // if (global_vertex_number != n_global_vertices)
2965#endif
2966
2967
2968 // ------------------------------------------------------------------
2969
2970 // ------------------------------------------------------------------
2971 // 4th- stage
2972 // Create the segments using the unique id of the vertices and
2973 // assign a segment id to each segment (the one from the boundary)
2974
2975 // Create the segment storage, each segment is composed of two
2976 // vertices (the vertices id is obtained from the global vertex ids
2977 // container)
2979
2980 // Assign a segment marked to each segment (the boundary id to which
2981 // the segment belongs)
2983
2984 // Loop over the boundaries again, but know get the global vertex id
2985 // from the container and create the segments
2986
2987 // Start with the outer polygons
2988 for (unsigned i = 0; i < n_outer_polygons; i++)
2989 {
2990 // The number of polylines in the current polygon
2991 const unsigned n_polylines = outer_polygons_pt[i]->npolyline();
2992
2993 // Loop over the polylines
2994 for (unsigned p = 0; p < n_polylines; p++)
2995 {
2996 // Get the boundary id of the current polyline
2997 const unsigned bound_id =
2998 outer_polygons_pt[i]->polyline_pt(p)->boundary_id();
2999
3000 // The number of vertices in the current polyline
3001 const unsigned n_vertices =
3002 outer_polygons_pt[i]->polyline_pt(p)->nvertex();
3003
3004 // Get the current chunk number of the polyline
3005 const unsigned bnd_chunk =
3006 outer_polygons_pt[i]->polyline_pt(p)->boundary_chunk();
3007
3008 // Loop over the vertices in the polyline
3009 for (unsigned v = 1; v < n_vertices; v++)
3010 {
3011 // Get the global vertex id
3012 const int global_vertex_id_v_1 =
3014 [v - 1];
3015
3016#ifdef PARANOID
3017 if (global_vertex_id_v_1 == -1)
3018 {
3019 // Get the current vertex
3021 outer_polygons_pt[i]->polyline_pt(p)->vertex_coordinate(v - 1);
3022 std::ostringstream error_message;
3023 std::string output_string =
3024 "UnstructuredTwoDMeshGeometryBase::build_triangulateio()";
3025 error_message
3026 << "The global vertex number for the current vertex has not\n"
3027 << "been assigned\n."
3028 << "Outer polygon number: (" << i << ")\n\n"
3029 << "Polyline number: (" << p << ")\n"
3030 << "Boundary id: (" << bound_id << ")\n"
3031 << "Boundary chunk: (" << bnd_chunk << ")\n"
3032 << "Vertex[" << v - 1 << "]: (" << current_vertex[0] << ", "
3033 << current_vertex[1] << ")\n";
3034 throw OomphLibError(
3035 error_message.str(), output_string, OOMPH_EXCEPTION_LOCATION);
3036 } // if (global_vertex_id_v_1 == -1)
3037#endif
3038
3039 // Get the global vertex id
3040 const int global_vertex_id_v =
3042
3043#ifdef PARANOID
3044 if (global_vertex_id_v == -1)
3045 {
3046 // Get the current vertex
3048 outer_polygons_pt[i]->polyline_pt(p)->vertex_coordinate(v);
3049 std::ostringstream error_message;
3050 std::string output_string =
3051 "UnstructuredTwoDMeshGeometryBase::build_triangulateio()";
3052 error_message
3053 << "The global vertex number for the current vertex has not\n"
3054 << "been assigned\n."
3055 << "Outer polygon number: (" << i << ")\n\n"
3056 << "Polyline number: (" << p << ")\n"
3057 << "Boundary id: (" << bound_id << ")\n"
3058 << "Boundary chunk: (" << bnd_chunk << ")\n"
3059 << "Vertex[" << v << "]: (" << current_vertex[0] << ", "
3060 << current_vertex[1] << ")\n";
3061 throw OomphLibError(
3062 error_message.str(), output_string, OOMPH_EXCEPTION_LOCATION);
3063 } // if (global_vertex_id_v == -1)
3064#endif
3065
3066 // Add the vertices to the segments container
3071
3072 // ... and associate the segments marker
3074
3075 } // for (v < n_vertices)
3076
3077 } // for (p < n_polylines)
3078
3079 } // for (i < n_outer_polygons)
3080
3081 // Now work the internal polygons
3082 for (unsigned i = 0; i < n_internal_polygons; i++)
3083 {
3084 // The number of polylines in the current polygon
3085 const unsigned n_polylines = internal_polygons_pt[i]->npolyline();
3086
3087 // Loop over the polylines
3088 for (unsigned p = 0; p < n_polylines; p++)
3089 {
3090 // Get the boundary id of the current polyline
3091 const unsigned bound_id =
3092 internal_polygons_pt[i]->polyline_pt(p)->boundary_id();
3093
3094 // The number of vertices in the current polyline
3095 const unsigned n_vertices =
3096 internal_polygons_pt[i]->polyline_pt(p)->nvertex();
3097
3098 // Get the current chunk number of the polyline
3099 const unsigned bnd_chunk =
3100 internal_polygons_pt[i]->polyline_pt(p)->boundary_chunk();
3101
3102 // Loop over the vertices in the polyline
3103 for (unsigned v = 1; v < n_vertices; v++)
3104 {
3105 // Get the global vertex id
3106 const int global_vertex_id_v_1 =
3108 [v - 1];
3109
3110#ifdef PARANOID
3111 if (global_vertex_id_v_1 == -1)
3112 {
3113 // Get the current vertex
3115 internal_polygons_pt[i]->polyline_pt(p)->vertex_coordinate(v - 1);
3116 std::ostringstream error_message;
3117 std::string output_string =
3118 "UnstructuredTwoDMeshGeometryBase::build_triangulateio()";
3119 error_message
3120 << "The global vertex number for the current vertex has not\n"
3121 << "been assigned\n."
3122 << "Internal polygon number: (" << i << ")\n\n"
3123 << "Polyline number: (" << p << ")\n"
3124 << "Boundary id: (" << bound_id << ")\n"
3125 << "Boundary chunk: (" << bnd_chunk << ")\n"
3126 << "Vertex[" << v - 1 << "]: (" << current_vertex[0] << ", "
3127 << current_vertex[1] << ")\n";
3128 throw OomphLibError(
3129 error_message.str(), output_string, OOMPH_EXCEPTION_LOCATION);
3130 } // if (global_vertex_id_v_1 == -1)
3131#endif
3132
3133 // Get the global vertex id
3134 const int global_vertex_id_v =
3136
3137#ifdef PARANOID
3138 if (global_vertex_id_v == -1)
3139 {
3140 // Get the current vertex
3142 internal_polygons_pt[i]->polyline_pt(p)->vertex_coordinate(v);
3143 std::ostringstream error_message;
3144 std::string output_string =
3145 "UnstructuredTwoDMeshGeometryBase::build_triangulateio()";
3146 error_message
3147 << "The global vertex number for the current vertex has not\n"
3148 << "been assigned\n."
3149 << "Internal polygon number: (" << i << ")\n\n"
3150 << "Polyline number: (" << p << ")\n"
3151 << "Boundary id: (" << bound_id << ")\n"
3152 << "Boundary chunk: (" << bnd_chunk << ")\n"
3153 << "Vertex[" << v << "]: (" << current_vertex[0] << ", "
3154 << current_vertex[1] << ")\n";
3155 throw OomphLibError(
3156 error_message.str(), output_string, OOMPH_EXCEPTION_LOCATION);
3157 } // if (global_vertex_id_v == -1)
3158#endif
3159
3160 // Add the vertices to the segments container
3165
3166 // ... and associate the segments marker
3168
3169 } // for (v < n_vertices)
3170
3171 } // for (p < n_polylines)
3172
3173 } // for (i < n_internal_polygons)
3174
3175 // Now do the open curves
3176 for (unsigned i = 0; i < n_open_curves; i++)
3177 {
3178 // The number of polylines in the current polygon
3179 const unsigned n_polylines = open_curves_pt[i]->ncurve_section();
3180
3181 // Loop over the polylines
3182 for (unsigned p = 0; p < n_polylines; p++)
3183 {
3184 // Get the boundary id of the current polyline
3185 const unsigned bound_id =
3186 open_curves_pt[i]->polyline_pt(p)->boundary_id();
3187
3188 // The number of vertices in the current polyline
3189 const unsigned n_vertices =
3190 open_curves_pt[i]->polyline_pt(p)->nvertex();
3191
3192 // Get the current chunk number of the polyline
3193 const unsigned bnd_chunk =
3194 open_curves_pt[i]->polyline_pt(p)->boundary_chunk();
3195
3196 // Loop over the vertices in the polyline
3197 for (unsigned v = 1; v < n_vertices; v++)
3198 {
3199 // Get the global vertex id
3200 const int global_vertex_id_v_1 =
3202 [v - 1];
3203
3204#ifdef PARANOID
3205 if (global_vertex_id_v_1 == -1)
3206 {
3207 // Get the current vertex
3209 open_curves_pt[i]->polyline_pt(p)->vertex_coordinate(v - 1);
3210 std::ostringstream error_message;
3211 std::string output_string =
3212 "UnstructuredTwoDMeshGeometryBase::build_triangulateio()";
3213 error_message
3214 << "The global vertex number for the current vertex has not\n"
3215 << "been assigned\n."
3216 << "Open curve number: (" << i << ")\n\n"
3217 << "Polyline number: (" << p << ")\n"
3218 << "Boundary id: (" << bound_id << ")\n"
3219 << "Boundary chunk: (" << bnd_chunk << ")\n"
3220 << "Vertex[" << v - 1 << "]: (" << current_vertex[0] << ", "
3221 << current_vertex[1] << ")\n";
3222 throw OomphLibError(
3223 error_message.str(), output_string, OOMPH_EXCEPTION_LOCATION);
3224 } // if (global_vertex_id_v_1 == -1)
3225#endif
3226
3227 // Get the global vertex id
3228 const int global_vertex_id_v =
3230
3231#ifdef PARANOID
3232 if (global_vertex_id_v == -1)
3233 {
3234 // Get the current vertex
3236 open_curves_pt[i]->polyline_pt(p)->vertex_coordinate(v);
3237 std::ostringstream error_message;
3238 std::string output_string =
3239 "UnstructuredTwoDMeshGeometryBase::build_triangulateio()";
3240 error_message
3241 << "The global vertex number for the current vertex has not\n"
3242 << "been assigned\n."
3243 << "Open curve number: (" << i << ")\n\n"
3244 << "Polyline number: (" << p << ")\n"
3245 << "Boundary id: (" << bound_id << ")\n"
3246 << "Boundary chunk: (" << bnd_chunk << ")\n"
3247 << "Vertex[" << v << "]: (" << current_vertex[0] << ", "
3248 << current_vertex[1] << ")\n";
3249 throw OomphLibError(
3250 error_message.str(), output_string, OOMPH_EXCEPTION_LOCATION);
3251 } // if (global_vertex_id_v == -1)
3252#endif
3253
3254 // Add the vertices to the segments container
3259
3260 // ... and associate the segments marker
3262
3263 } // for (v < n_vertices)
3264
3265 } // for (p < n_polylines)
3266
3267 } // for (i < n_open_curves)
3268
3269 // ------------------------------------------------------------------
3270 // 5th- stage
3271 // Fill the triangulateio containers with the collected information
3272
3273 // Initialize the triangulateIO structure
3275
3276 // Set the number of vertices
3277 triangulate_io.numberofpoints = n_global_vertices;
3278
3279 // Get the number of segments
3280 const unsigned n_global_segments = global_segments.size();
3281 // Set the number of segments
3282 triangulate_io.numberofsegments = n_global_segments;
3283
3284 // Allocate memory in the triangulateIO structure to store the values
3285 triangulate_io.pointlist =
3286 (double*)malloc(triangulate_io.numberofpoints * 2 * sizeof(double));
3287 triangulate_io.segmentlist =
3288 (int*)malloc(triangulate_io.numberofsegments * 2 * sizeof(int));
3289 triangulate_io.segmentmarkerlist =
3290 (int*)malloc(triangulate_io.numberofsegments * sizeof(int));
3291
3292 // Fill triangulateIO data structure
3293 // ---------------------------------------
3294
3295 // Fill the vertices first
3296 // An external counter
3297 unsigned ii = 0;
3298 for (unsigned i = 0; i < n_global_vertices; i++, ii += 2)
3299 {
3300 triangulate_io.pointlist[ii] = global_vertices[i][0];
3301 triangulate_io.pointlist[ii + 1] = global_vertices[i][1];
3302 } // for (i < n_global_vertices)
3303
3304 // Then fill the segments, and segments markers
3305 // Reset the external counter
3306 ii = 0;
3307 for (unsigned i = 0; i < n_global_segments; i++, ii += 2)
3308 {
3309 // The segment marker should start in 1 (our enumeration started
3310 // in 0, therefore we add one to every entry)
3311 triangulate_io.segmentlist[ii] = global_segments[i][0] + 1;
3312 triangulate_io.segmentlist[ii + 1] = global_segments[i][1] + 1;
3313 // Set the segment marker as the boundary id + 1
3314 triangulate_io.segmentmarkerlist[i] = global_segment_markers[i] + 1;
3315 }
3316
3317 // Store any regions information
3318 // ---------------------------------------
3319
3320 // Get the number of regions
3321 unsigned n_regions = regions_coordinates.size();
3322
3323 // Check if there are regions to include
3324 if (n_regions > 0)
3325 {
3326 triangulate_io.numberofregions = n_regions;
3327 triangulate_io.regionlist =
3328 (double*)malloc(triangulate_io.numberofregions * 4 * sizeof(double));
3329
3330 // Loop over the regions map
3331 unsigned p = 1;
3332 for (std::map<unsigned, Vector<double>>::iterator it_regions =
3333 regions_coordinates.begin();
3334 it_regions != regions_coordinates.end();
3335 it_regions++)
3336 {
3337 // Get the region id
3338 unsigned region_id = (*it_regions).first;
3339 // Set the x-coordinate
3340 triangulate_io.regionlist[4 * p - 4] = ((*it_regions).second)[0];
3341 // Set the y-coordinate
3342 triangulate_io.regionlist[4 * p - 3] = ((*it_regions).second)[1];
3343 // Set the region id
3344 triangulate_io.regionlist[4 * p - 2] = static_cast<double>(region_id);
3345 // This is used to define a target area for the region, zero
3346 // means no target area defined
3347 triangulate_io.regionlist[4 * p - 1] = regions_areas[region_id];
3348 // Increase the auxiliary counter
3349 p++;
3350 } // Loop over the regions map
3351
3352 } // if (n_regions > 0)
3353
3354 // Holes information
3355 // ---------------------------------------
3356
3357 // Get the number of any extra defined holes
3358 const unsigned n_extra_holes = extra_holes_coordinates.size();
3359 // The internal polygon marked as a hole
3361 // Count how many internal polygons are holes
3362 for (unsigned h = 0; h < n_internal_polygons; h++)
3363 {
3364 if (!internal_polygons_pt[h]->internal_point().empty())
3365 {
3367 } // Is internal polygon a hole?
3368 } // for (h < n_internal_polygons)
3369
3370 // Get the number of internal polygons that should be treated as
3371 // holes
3372 const unsigned n_internal_polygons_are_holes =
3374
3375 // Set the number of holes in the triangulateIO structure
3376 triangulate_io.numberofholes =
3378
3379 // Allocate memory for the holes coordinates
3380 triangulate_io.holelist =
3381 (double*)malloc(triangulate_io.numberofholes * 2 * sizeof(double));
3382
3383 // Store the holes coordinates
3384 unsigned count_hole = 0;
3385 // Add first the internal polygons marked as holes
3387 {
3388 const unsigned index_intenal_polygon_is_hole =
3390 triangulate_io.holelist[count_hole] =
3392 ->internal_point()[0];
3393 triangulate_io.holelist[count_hole + 1] =
3395 ->internal_point()[1];
3396 } // for (count_hole < n_internal_polygons_are_holes*2)
3397
3398 // Add the extra holes coordinates
3399 for (unsigned i_eh = 0;
3401 count_hole += 2, i_eh++)
3402 {
3403 triangulate_io.holelist[count_hole] = extra_holes_coordinates[i_eh][0];
3404 triangulate_io.holelist[count_hole + 1] =
3405 extra_holes_coordinates[i_eh][1];
3406 } // for (count_hole < 2*(n_extra_holes + n_internal_polygons_are_holes))
3407
3408 // ------------------------------------------------------------------
3409 }
3410
3411 //========================================================================
3412 /// Helps to add information to the connection matrix of the
3413 /// given polyline
3414 //========================================================================
3416 TriangleMeshPolyLine* polyline_pt,
3417 std::map<unsigned, std::map<unsigned, Vector<vertex_connection_info>>>&
3420 {
3421 // Get the boundary id of the current polyline
3422 const unsigned bound_id = polyline_pt->boundary_id();
3423
3424 // Get the chunk number associated with this boundary
3425 const unsigned bound_chunk = polyline_pt->boundary_chunk();
3426
3427 // Check if the ends of the polyline are connected
3428 const bool connected_init_end = polyline_pt->is_initial_vertex_connected();
3429
3430 // ... check for both connections
3431 const bool connected_final_end = polyline_pt->is_final_vertex_connected();
3432
3433 // Prepare the connection matrix (resize the vector to store the
3434 // initial and final vertices info.)
3436
3437 // The default information for the matrix
3439 default_vertex_connection_info.is_connected = false;
3440 default_vertex_connection_info.boundary_id_to_connect = 0;
3441 default_vertex_connection_info.boundary_chunk_to_connect = 0;
3442 default_vertex_connection_info.vertex_number_to_connect = 0;
3443
3444 // Set the default information for the initial vertex
3447 // Set the default information for the final vertex
3450
3451 // Set the info. for the connection matrix
3453 {
3454 // The boundary id to connect
3455 const unsigned bc = polyline_pt->initial_vertex_connected_bnd_id();
3456
3457 // The vertex number to which is connected
3458 const unsigned vc = polyline_pt->initial_vertex_connected_n_vertex();
3459
3460 // The boundary chunk to which is connected
3461 const unsigned cc = polyline_pt->initial_vertex_connected_n_chunk();
3462
3463 // Set the connection info
3465 // Set as connected
3466 initial_vertex_info.is_connected = true;
3467 // The boundary id to connect
3468 initial_vertex_info.boundary_id_to_connect = bc;
3469 // The chunk number to connect
3470 initial_vertex_info.boundary_chunk_to_connect = cc;
3471 // The vertex number to connect
3472 initial_vertex_info.vertex_number_to_connect = vc;
3473
3474 // Add the connection information to the connection matrix
3476
3477 } // if (connected_init_end)
3478
3480 {
3481 // The boundary id to connect
3482 const unsigned bc = polyline_pt->final_vertex_connected_bnd_id();
3483
3484 // The vertex number to which is connected
3485 const unsigned vc = polyline_pt->final_vertex_connected_n_vertex();
3486
3487 // The boundary chunk to which is connected
3488 const unsigned cc = polyline_pt->final_vertex_connected_n_chunk();
3489
3490 // Set the connection info
3492 // Set as connected
3493 final_vertex_info.is_connected = true;
3494 // The boundary id to connect
3495 final_vertex_info.boundary_id_to_connect = bc;
3496 // The chunk number to connect
3497 final_vertex_info.boundary_chunk_to_connect = cc;
3498 // The vertex number to connect
3499 final_vertex_info.vertex_number_to_connect = vc;
3500
3501 // Add the connection information to the connection matrix
3503
3504 } // if (connected_final_end)
3505 else
3506 {
3507 // If the vertex is not connected but there is a next polyline in
3508 // the polygon (this only applies for polygons, for open curves
3509 // the next polyline is set to null)
3510
3511 if (next_polyline_pt != 0)
3512 {
3513 // Get the info of the next polyline
3514 const unsigned next_bound_id = next_polyline_pt->boundary_id();
3515
3516 // Get the chunk number associated with this boundary
3517 const unsigned next_bound_chunk = next_polyline_pt->boundary_chunk();
3518
3519 // Set the connection info
3521 // Set as connected
3522 final_vertex_info.is_connected = true;
3523 // The boundary id to connect
3524 final_vertex_info.boundary_id_to_connect = next_bound_id;
3525 // The chunk number to connect
3526 final_vertex_info.boundary_chunk_to_connect = next_bound_chunk;
3527 // The vertex number to connect
3528 final_vertex_info.vertex_number_to_connect = 0;
3529
3530 // Add the connection information to the connection matrix
3532
3533 } // if (next_polyline_pt != 0)
3534
3535 } // else if (connected_final_end)
3536 }
3537
3538 //========================================================================
3539 // Initialize the base vertex structure, set every vertex to
3540 // no visited and not being a base vertex
3541 //========================================================================
3543 TriangleMeshPolyLine* polyline_pt,
3544 std::map<unsigned, std::map<unsigned, Vector<base_vertex_info>>>&
3546 {
3547 // Get the boundary id of the current polyline
3548 const unsigned bound_id = polyline_pt->boundary_id();
3549
3550 // Get the chunk number associated with this boundary
3551 const unsigned bound_chunk = polyline_pt->boundary_chunk();
3552
3553 // Create the default data structure
3555 // Set as not done
3556 default_base_vertex_info.has_base_vertex_assigned = false;
3557 // Set as not base vertex
3558 default_base_vertex_info.is_base_vertex = false;
3559 // Set the default base boundary id
3560 default_base_vertex_info.boundary_id = 0;
3561 // Set the default base boundary chunk
3562 default_base_vertex_info.boundary_chunk = 0;
3563 // Set the default base vertex number
3564 default_base_vertex_info.vertex_number = 0;
3565
3566 // Initialize the base vertex info. for the current polyline
3567 // Allocate memory for the initial and final vertex
3569 // Set the initial vertex info.
3571 // Set the final vertex info.
3573 }
3574
3575 //========================================================================
3576 // Helps to identify the base vertex of the given polyline
3577 //========================================================================
3579 TriangleMeshPolyLine* polyline_pt,
3580 std::map<unsigned, std::map<unsigned, Vector<base_vertex_info>>>&
3582 std::map<unsigned, std::map<unsigned, Vector<vertex_connection_info>>>&
3584 std::map<unsigned, std::map<unsigned, unsigned>>& boundary_chunk_nvertices)
3585 {
3586 // Get the general data of the polyline
3587
3588 // Get the boundary id of the current polyline
3589 const unsigned bound_id = polyline_pt->boundary_id();
3590
3591 // The number of vertices in the current polyline
3592 const unsigned n_vertices = polyline_pt->nvertex();
3593
3594 // Get the chunk number associated with this boundary
3595 const unsigned bound_chunk = polyline_pt->boundary_chunk();
3596
3597 // Keep track of the done vertices
3598 std::map<Vector<unsigned>, bool> done;
3599
3600 // Loop over the vertices in the polyline
3601 for (unsigned v = 0; v < n_vertices; v++)
3602 {
3603 // For each vertex find its base vertex
3604
3605 // Flag to state if repeat the search with the new vertex
3606 // reference
3607 bool repeat = false;
3608
3609 // Store the info. of the vertex currently serching for base
3610 // vertex
3611 unsigned ibnd_id = bound_id;
3612 unsigned ibnd_chunk = bound_chunk;
3613 unsigned ivertex_number = v;
3614
3615 // Store the info. of the base vertex of the current vertex
3616 unsigned base_bnd_id = 0;
3617 unsigned base_bnd_chunk = 0;
3618 unsigned base_vertex_number = 0;
3619
3620 // Store all the found references to the vertex
3624
3625 do
3626 {
3627 // Reset the flag
3628 repeat = false;
3629
3630 // Get the number of vertices of the polyline where the current
3631 // reference index lives on
3632 const unsigned i_n_vertices =
3634 // Is the vertex an initial or final vertex on the (ibnd_id,
3635 // ibnd_chunk)
3636 bool is_initial = false;
3637 if (ivertex_number == 0)
3638 {
3639 is_initial = true;
3640 }
3641 bool is_final = false;
3642 if (ivertex_number == i_n_vertices - 1)
3643 {
3644 is_final = true;
3645 }
3646
3647 // Is initial or final?
3648 if (is_initial || is_final)
3649 {
3650 // Stores the base vertex info. of the current vertex
3652
3653 if (is_initial)
3654 {
3655 // Get the base vertex info. of the current vertex
3657 }
3658 else if (is_final)
3659 {
3660 // Get the base vertex info. of the current vertex
3662 }
3663
3664 // Has the vertex assigned a base vertex?
3665 if (!current_vertex_base_info.has_base_vertex_assigned)
3666 {
3667 // Is the current vertex a base vertex?
3668 if (!current_vertex_base_info.is_base_vertex)
3669 {
3670 // Get the connection info. of the vertex
3673
3674 if (is_initial)
3675 {
3677 }
3678 else if (is_final)
3679 {
3681 }
3682
3683 // Get the complete connection information of the vertex
3684
3685 // The new connection info.
3686 const bool current_is_connected =
3687 vertex_connect_info.is_connected;
3688
3689 // Is the current vertex connected to other vertex
3691 {
3692 // The new boundary id to connect
3693 const unsigned iibnd_id =
3694 vertex_connect_info.boundary_id_to_connect;
3695
3696 // The new boundary chunk to connect
3697 const unsigned iibnd_chunk =
3698 vertex_connect_info.boundary_chunk_to_connect;
3699
3700 // The new vertex number to connect
3701 const unsigned iivertex_number =
3702 vertex_connect_info.vertex_number_to_connect;
3703
3704 // Get the number of vertices in the new boundary to connect
3705 const unsigned ii_n_vertices =
3707
3708 // Is the new vertex an initial or final vertex on the
3709 // (iibnd_id, iibnd_chunk)
3710 bool new_is_initial = false;
3711 if (iivertex_number == 0)
3712 {
3713 new_is_initial = true;
3714 }
3715 bool new_is_final = false;
3716 if (iivertex_number == ii_n_vertices - 1)
3717 {
3718 new_is_final = true;
3719 }
3720
3721 // Is new initial or final?
3723 {
3724 // Stores the base vertex info. of the new vertex
3726
3727 if (new_is_initial)
3728 {
3729 // Get the base vertex info. of the current vertex
3732 }
3733 else if (new_is_final)
3734 {
3735 // Get the base vertex info. of the current vertex
3738 }
3739
3740 // Verify if the new vertex has been done
3742 check_done[0] = iibnd_id;
3745 // Has the new vertex been already visited?
3746 if (!done[check_done])
3747 {
3748 // Add the i-reference to the iteration vectors
3749 // since it needs to be assigned the base node when
3750 // it be found
3751 iter_bnd_id.push_back(ibnd_id);
3752 iter_bnd_chunk.push_back(ibnd_chunk);
3754
3756 current_done[0] = ibnd_id;
3759
3760 // Mark the i-th reference of the vertex as done
3761 done[current_done] = true;
3762
3763 // Change the vertex reference and repeat
3764 ibnd_id = iibnd_id;
3767
3768 // Set the flag to repeat the search with the new
3769 // reference of the vertex
3770 repeat = true;
3771
3772 } // if (!done[check_done])
3773 else
3774 {
3775 // We have found a base vertex, we only need to
3776 // decide if it is the current vertex or the new
3777 // vertex
3778
3779 // Add the i-reference to the iteration vectors to
3780 // be assigned the found base vertex
3781 iter_bnd_id.push_back(ibnd_id);
3782 iter_bnd_chunk.push_back(ibnd_chunk);
3784
3785 // Has the new vertex a base vertes assigned
3786 if (!new_vertex_base_info.has_base_vertex_assigned)
3787 {
3788 // The current vertex is a base vertex (we are
3789 // looping over the current and new vertex)
3790
3792 current_done[0] = ibnd_id;
3795
3796 // Mark the i-th reference of the vertex as done
3797 done[current_done] = true;
3798
3799 // Mark the i-th reference of the vertex as base
3800 // vertex
3801 if (is_initial)
3802 {
3803 // Mark the vertex as base vertex
3804 base_vertices[ibnd_id][ibnd_chunk][0].is_base_vertex =
3805 true;
3806 }
3807 else if (is_final)
3808 {
3809 // Mark the vertex as base vertex
3810 base_vertices[ibnd_id][ibnd_chunk][1].is_base_vertex =
3811 true;
3812 }
3813
3814 // Set as base vertex the current vertex info.
3815 // The base boundary id
3817 // The base boundary chunk number
3819 // The base vertex number
3821
3822 } // if (!new_vertex_base_info.is_base_vertex)
3823 else
3824 {
3825 // The new vertex is a base vertex (we are looping
3826 // over the current and new vertex)
3827
3829 current_done[0] = ibnd_id;
3832
3833 // Mark the i-th reference of the vertex as done
3834 done[current_done] = true;
3835
3836 // Set as base vertex the new vertex info.
3837 // The base boundary id
3839 // The base boundary chunk number
3841 // The base vertex number
3843
3844 } // else if (!new_vertex_base_info.is_base_vertex)
3845
3846 } // else if (!new_vertex_base_info.done)
3847
3848 } // if (new_is_initial || new_is_final)
3849 else
3850 {
3851 // Add the i-reference to the iteration vectors since
3852 // it needs to be assigned the just found base vertex
3853 iter_bnd_id.push_back(ibnd_id);
3854 iter_bnd_chunk.push_back(ibnd_chunk);
3856
3858 current_done[0] = ibnd_id;
3861
3862 // Mark the i-th reference of the vertex as done
3863 done[current_done] = true;
3864
3865 // Set as base node the new node info.
3866 // The base boundary id
3868 // The base boundary chunk number
3870 // The base vertex number
3872 } // else if (new_is_initial || new_is_final)
3873
3874 } // if (current_is_connected)
3875 else
3876 {
3877 // The current vertex is a base vertex
3878
3879 // Add the i-reference to the iteration vectors to be
3880 // assigned the found base vertex
3881 iter_bnd_id.push_back(ibnd_id);
3882 iter_bnd_chunk.push_back(ibnd_chunk);
3884
3886 current_done[0] = ibnd_id;
3889
3890 // Mark the i-th reference of the vertex as done
3891 done[current_done] = true;
3892
3893 // Mark the i-th reference of the vertex as base vertex
3894 if (is_initial)
3895 {
3896 // Mark the vertex as base vertex
3897 base_vertices[ibnd_id][ibnd_chunk][0].is_base_vertex = true;
3898 }
3899 else if (is_final)
3900 {
3901 // Mark the vertex as base vertex
3902 base_vertices[ibnd_id][ibnd_chunk][1].is_base_vertex = true;
3903 }
3904
3905 // Set as base vertex the current vertex info.
3906 // The base boundary id
3908 // The base boundary chunk number
3910 // The base vertex number
3912
3913 } // else if (current_is_connected)
3914
3915 } // if (!current_vertex_base_info.is_base_vertex)
3916 else
3917 {
3918 // Copy the base vertex info. and assign it to all the
3919 // found vertex references
3920
3921 // The base boundary id
3923 // The base boundary chunk number
3925 // The base vertex number
3927
3928 } // else if (!current_vertex_base_info.is_base_vertex)
3929
3930 } // if (!current_vertex_base_info.has_base_vertex_assigned)
3931 else
3932 {
3933 // Copy the base vertex info. and assign it to all the found
3934 // vertex references
3935
3936 // The base boundary id
3938 // The base boundary chunk number
3940 // The base vertex number
3942 } // else if (!current_vertex_base_info.has_base_vertex_assigned)
3943
3944 } // if (is_initial || is_final)
3945
3946 } while (repeat);
3947
3948 // Assign the base vertex to all the found references of the
3949 // vertex
3950
3951 // Get the number of found references
3952 const unsigned n_vertex_references = iter_bnd_id.size();
3953 // Loop over the found references and assign the base vertex
3954 for (unsigned r = 0; r < n_vertex_references; r++)
3955 {
3956 // Get the r-th reference of the vertex
3957 const unsigned rbnd_id = iter_bnd_id[r];
3958 const unsigned rbnd_chunk = iter_bnd_chunk[r];
3959 const unsigned rvertex_number = iter_vertex_number[r];
3960
3961 // Get the number of vertices in the r-th boundary r-th boundary
3962 // chunk
3963 const unsigned r_n_vertices =
3965
3966 // Is the r-th vertex an initial or final vertex
3967 bool is_initial = false;
3968 if (rvertex_number == 0)
3969 {
3970 is_initial = true;
3971 }
3972 bool is_final = false;
3973 if (rvertex_number == r_n_vertices - 1)
3974 {
3975 is_final = true;
3976 }
3977
3978 if (is_initial)
3979 {
3980 // Set the base vertex info. of the r-th vertex reference
3981
3982 // Mark the vertex as having assigned a base vertex
3983 base_vertices[rbnd_id][rbnd_chunk][0].has_base_vertex_assigned = true;
3984 // The base boundary id
3985 base_vertices[rbnd_id][rbnd_chunk][0].boundary_id = base_bnd_id;
3986 // The base boundary chunk number
3987 base_vertices[rbnd_id][rbnd_chunk][0].boundary_chunk = base_bnd_chunk;
3988 // The base vertex number
3989 base_vertices[rbnd_id][rbnd_chunk][0].vertex_number =
3991 }
3992 else if (is_final)
3993 {
3994 // Set the base vertex info. of the r-th vertex reference
3995
3996 // Mark the vertex as having assigned a base vertex
3997 base_vertices[rbnd_id][rbnd_chunk][1].has_base_vertex_assigned = true;
3998 // The base boundary id
3999 base_vertices[rbnd_id][rbnd_chunk][1].boundary_id = base_bnd_id;
4000 // The base boundary chunk number
4001 base_vertices[rbnd_id][rbnd_chunk][1].boundary_chunk = base_bnd_chunk;
4002 // The base vertex number
4003 base_vertices[rbnd_id][rbnd_chunk][1].vertex_number =
4005 }
4006
4007 } // for (i < n_vertex_references)
4008
4009 } // for (v < n_vertices)
4010 }
4011
4012#endif
4013
4014
4015 //======================================================================
4016 /// Move the nodes on boundaries with associated Geometric Objects so
4017 /// that they exactly coincide with the geometric object. This requires
4018 /// that the boundary coordinates are set up consistently
4019 //======================================================================
4021 {
4022 // Loop over all boundaries
4023 unsigned n_bound = this->nboundary();
4024 for (unsigned b = 0; b < n_bound; b++)
4025 {
4026 // Find the geometric object
4027 GeomObject* const geom_object_pt = this->boundary_geom_object_pt(b);
4028
4029 // If there is one
4030 if (geom_object_pt != 0)
4031 {
4034 const unsigned n_boundary_node = this->nboundary_node(b);
4035 for (unsigned n = 0; n < n_boundary_node; ++n)
4036 {
4037 // Get the boundary node and coordinates
4038 Node* const nod_pt = this->boundary_node_pt(b, n);
4039 nod_pt->get_coordinates_on_boundary(b, b_coord);
4040
4041 // Get the position and time history according to the underlying
4042 // geometric object, assuming that it has the same timestepper
4043 // as the nodes....
4044 unsigned n_tvalues =
4045 1 + nod_pt->position_time_stepper_pt()->nprev_values();
4046 for (unsigned t = 0; t < n_tvalues; ++t)
4047 {
4048 // Get the position according to the underlying geometric object
4049 geom_object_pt->position(t, b_coord, new_x);
4050
4051 // Move the node
4052 for (unsigned i = 0; i < 2; i++)
4053 {
4054 nod_pt->x(t, i) = new_x[i];
4055 }
4056 }
4057 }
4058 }
4059 }
4060 }
4061
4062 //======================================================================
4063 /// Helper function that checks if a given point is inside a polygon
4064 //======================================================================
4067 {
4068 // Total number of vertices (the first and last vertex should be the same)
4069 const unsigned n_vertex = polygon_vertices.size();
4070
4071 // Check if internal point is actually located in bounding polygon
4072 // Reference: http://paulbourke.net/geometry/insidepoly/
4073
4074 // Counter for number of intersections
4075 unsigned intersect_counter = 0;
4076
4077 // Get first vertex
4079 for (unsigned i = 1; i <= n_vertex; i++)
4080 {
4081 // Get second vertex by wrap-around
4083
4084 if (point[1] > std::min(p1[1], p2[1]))
4085 {
4086 if (point[1] <= std::max(p1[1], p2[1]))
4087 {
4088 if (point[0] <= std::max(p1[0], p2[0]))
4089 {
4090 if (p1[1] != p2[1])
4091 {
4092 double xintersect =
4093 (point[1] - p1[1]) * (p2[0] - p1[0]) / (p2[1] - p1[1]) + p1[0];
4094 if ((p1[0] == p2[0]) || (point[0] <= xintersect))
4095 {
4097 }
4098 }
4099 }
4100 }
4101 }
4102 p1 = p2;
4103 }
4104
4105 // Even number of intersections: outside
4106 if (intersect_counter % 2 == 0)
4107 {
4108 return false;
4109 }
4110 else
4111 {
4112 return true;
4113 }
4114 }
4115
4116 //======================================================================
4117 /// Gets the vertex number on the destination polyline (used /
4118 /// to create the connections among shared boundaries)
4119 //======================================================================
4124 unsigned& vertex_number)
4125 {
4126 // The returning flag indicating that the vertex was found in the
4127 // destination boundary
4128 bool found_vertex_number = false;
4129
4130 // Get the number of vertices in the destination polyline
4131 const unsigned n_vertices = dst_polyline_pt->nvertex();
4132
4133 // Loop over the vertices and return the closest vertex
4134 // to the given vertex coordinates
4135 for (unsigned i = 0; i < n_vertices; i++)
4136 {
4137 // Get the i-vertex on the polyline
4138 Vector<double> current_vertex = dst_polyline_pt->vertex_coordinate(i);
4139
4140 // Compute the distance to the input vertex
4141 double dist = (vertex_coordinates[0] - current_vertex[0]) *
4145 dist = sqrt(dist);
4146
4147 // Have we found the vertex?
4149 {
4150 // Set the vertex index
4151 vertex_number = i;
4152
4153 // Set the flag to found
4154 found_vertex_number = true;
4155
4156 // Break the serching
4157 break;
4158 }
4159 } // for (i < n_vertices)
4160
4161 // Return if the connection was found
4162 return found_vertex_number;
4163 }
4164
4165
4166#ifdef OOMPH_HAS_TRIANGLE_LIB
4167
4168 //======================================================================
4169 /// Helper function to copy the connection information from
4170 /// the input curve(polyline or curviline) to the output polyline
4171 //======================================================================
4175 {
4176 // Is there a connection to the initial vertex
4177 const bool initial_connection =
4178 input_curve_pt->is_initial_vertex_connected();
4179
4180 // Is there a connection to the initial vertex
4181 const bool final_connection = input_curve_pt->is_final_vertex_connected();
4182
4183 // If there are any connection at the ends then copy the information
4185 {
4186 // Get the initial and final vertex from the input polyline
4188 input_curve_pt->initial_vertex_coordinate(input_initial_vertex);
4190 input_curve_pt->final_vertex_coordinate(input_final_vertex);
4191
4192 // Get the initial and final vertex from the output polyline
4194 output_curve_pt->initial_vertex_coordinate(output_initial_vertex);
4196 output_curve_pt->final_vertex_coordinate(output_final_vertex);
4197
4198 // Check if the polyline is in the same order or if it is
4199 // reversed. We need to know to copy the connection information
4200 // correctly
4201
4202 // The flag to state if the copy is in the same order or in
4203 // reversed order
4204 bool copy_reversed = false;
4205
4206 // Start with the initial vertices
4207 double dist_initial =
4213
4214 // Compute the distance of the final vertices
4220
4221 // Get the distace from the input vertices to the output vertices
4222 // in the same order
4223 const double dist = dist_initial + dist_final;
4224
4225 // Compute the distance between the input initial vertex and the
4226 // output final vertex
4227 double dist_initial_rev =
4233
4234 // Compute the distance between the input final vertex and the
4235 // output initial vertex
4236 double dist_final_rev =
4242
4243 // Get the distace from the input to the output vertices in
4244 // reversed order
4245 const double dist_rev = dist_initial_rev + dist_final_rev;
4246
4247 // If the distance is smaller than the reversed distance then the
4248 // order of the vertices is the same
4249 if (dist <= dist_rev)
4250 {
4251 // Do nothing
4252 copy_reversed = false;
4253 }
4254 else if (dist_rev < dist)
4255 {
4256 // The connection information is copied in reversed order
4257 copy_reversed = true;
4258 } // else if (dist_rev < dist)
4259
4260 // Copy the connection information
4261 // ----------------------------------------------------------------
4262 // Copy in reversed order? (copy normal)
4263 if (!copy_reversed)
4264 {
4265 // Initial vertex
4266 if (input_curve_pt->is_initial_vertex_connected())
4267 {
4268 output_curve_pt->set_initial_vertex_connected();
4269
4270 output_curve_pt->initial_vertex_connected_bnd_id() =
4271 input_curve_pt->initial_vertex_connected_bnd_id();
4272
4273 output_curve_pt->initial_vertex_connected_n_chunk() =
4274 input_curve_pt->initial_vertex_connected_n_chunk();
4275
4276 // We need to know if we have to compute the vertex number or
4277 // if we need just to copy it
4278 if (input_curve_pt->is_initial_vertex_connected_to_curviline())
4279 {
4280 double initial_s_connection =
4281 input_curve_pt->initial_s_connection_value();
4282
4283 unsigned bnd_id =
4284 output_curve_pt->initial_vertex_connected_bnd_id();
4285
4286 double s_tolerance = input_curve_pt->tolerance_for_s_connection();
4287
4288 output_curve_pt->initial_vertex_connected_n_vertex() =
4291
4292 // The output polyline is not longer connected to a curviline
4293 // because we will be using the polyline representation of the
4294 // curviline
4295 output_curve_pt->unset_initial_vertex_connected_to_curviline();
4296 }
4297 else
4298 {
4299 output_curve_pt->initial_vertex_connected_n_vertex() =
4300 input_curve_pt->initial_vertex_connected_n_vertex();
4301 }
4302
4303 } // if (input_curve_pt->is_initial_vertex_connected())
4304
4305 // Final vertex
4306 if (input_curve_pt->is_final_vertex_connected())
4307 {
4308 output_curve_pt->set_final_vertex_connected();
4309
4310 output_curve_pt->final_vertex_connected_bnd_id() =
4311 input_curve_pt->final_vertex_connected_bnd_id();
4312
4313 output_curve_pt->final_vertex_connected_n_chunk() =
4314 input_curve_pt->final_vertex_connected_n_chunk();
4315
4316 // We need to know if we have to compute the vertex number or
4317 // if we need just to copy it
4318 if (input_curve_pt->is_final_vertex_connected_to_curviline())
4319 {
4320 double final_s_connection =
4321 input_curve_pt->final_s_connection_value();
4322
4323 unsigned bnd_id = input_curve_pt->final_vertex_connected_bnd_id();
4324
4325 double s_tolerance = input_curve_pt->tolerance_for_s_connection();
4326
4327 output_curve_pt->final_vertex_connected_n_vertex() =
4330
4331 // The output polyline is not longer connected to a curviline
4332 // because we will be using the polyline representation of the
4333 // curviline
4334 output_curve_pt->unset_final_vertex_connected_to_curviline();
4335 }
4336 else
4337 {
4338 output_curve_pt->final_vertex_connected_n_vertex() =
4339 input_curve_pt->final_vertex_connected_n_vertex();
4340 }
4341
4342 } // if (input_curve_pt->is_final_vertex_connected())
4343
4344 } // if (!copy_reversed)
4345 else
4346 {
4347 // Copy the connections in reversed order
4348
4349 // Initial vertex
4350 if (input_curve_pt->is_initial_vertex_connected())
4351 {
4352 output_curve_pt->set_final_vertex_connected();
4353
4354 output_curve_pt->final_vertex_connected_bnd_id() =
4355 input_curve_pt->initial_vertex_connected_bnd_id();
4356
4357 output_curve_pt->final_vertex_connected_n_chunk() =
4358 input_curve_pt->initial_vertex_connected_n_chunk();
4359
4360 // We need to know if we have to compute the vertex number or
4361 // if we need just to copy it
4362 if (input_curve_pt->is_initial_vertex_connected_to_curviline())
4363 {
4364 double initial_s_connection =
4365 input_curve_pt->initial_s_connection_value();
4366
4367 unsigned bnd_id = input_curve_pt->initial_vertex_connected_bnd_id();
4368
4369 double s_tolerance = input_curve_pt->tolerance_for_s_connection();
4370
4371 output_curve_pt->final_vertex_connected_n_vertex() =
4374
4375 // The output polyline is not longer connected to a curviline
4376 // because we will be using the polyline representation of the
4377 // curviline
4378 output_curve_pt->unset_final_vertex_connected_to_curviline();
4379 }
4380 else
4381 {
4382 output_curve_pt->final_vertex_connected_n_vertex() =
4383 input_curve_pt->initial_vertex_connected_n_vertex();
4384 }
4385
4386 } // if (input_curve_pt->is_initial_vertex_connected())
4387
4388 // Final vertex
4389 if (input_curve_pt->is_final_vertex_connected())
4390 {
4391 output_curve_pt->set_initial_vertex_connected();
4392
4393 output_curve_pt->initial_vertex_connected_bnd_id() =
4394 input_curve_pt->final_vertex_connected_bnd_id();
4395
4396 output_curve_pt->initial_vertex_connected_n_chunk() =
4397 input_curve_pt->final_vertex_connected_n_chunk();
4398
4399 // We need to know if we have to compute the vertex number or
4400 // if we need just to copy it
4401 if (input_curve_pt->is_final_vertex_connected_to_curviline())
4402 {
4403 double final_s_connection =
4404 input_curve_pt->final_s_connection_value();
4405
4406 unsigned bnd_id = input_curve_pt->final_vertex_connected_bnd_id();
4407
4408 double s_tolerance = input_curve_pt->tolerance_for_s_connection();
4409
4410 output_curve_pt->initial_vertex_connected_n_vertex() =
4413
4414 // The output polyline is not longer connected to a curviline
4415 // because we will be using the polyline representation of the
4416 // curviline
4417 output_curve_pt->unset_initial_vertex_connected_to_curviline();
4418 }
4419 else
4420 {
4421 output_curve_pt->initial_vertex_connected_n_vertex() =
4422 input_curve_pt->final_vertex_connected_n_vertex();
4423 }
4424 } // if (input_curve_pt->is_final_vertex_connected())
4425 } // else if (!copy_reversed)
4426 } // if (initial_connection || final_connection)
4427 }
4428
4429 //======================================================================
4430 /// Helper function to copy the connection information from
4431 /// the input curve(polyline or curviline) to the output sub-polyline
4432 //======================================================================
4437 {
4438 // Is there a connection to the initial vertex
4439 const bool initial_connection =
4440 input_curve_pt->is_initial_vertex_connected();
4441
4442 // Is there a connection to the initial vertex
4443 const bool final_connection = input_curve_pt->is_final_vertex_connected();
4444
4445 // If there are any connection at the ends then copy the information
4447 {
4448 // Get the initial and final vertex from the input polyline
4450 input_curve_pt->initial_vertex_coordinate(input_initial_vertex);
4452 input_curve_pt->final_vertex_coordinate(input_final_vertex);
4453
4454 // Get the initial and final vertex from the output polyline
4456 output_curve_pt->initial_vertex_coordinate(output_initial_vertex);
4458 output_curve_pt->final_vertex_coordinate(output_final_vertex);
4459
4460 // Check if the polyline is in the same order or if it is
4461 // reversed. We need to know to copy the connection information
4462 // correctly
4463
4464 // The flag to state if the copy is in the same order or in
4465 // reversed order
4466 bool copy_reversed = false;
4467
4468 // Start with the initial vertices
4469 double dist_initial =
4475
4476 // Compute the distance of the final vertices
4482
4483 // Get the distace from the input vertices to the output vertices
4484 // in the same order
4485 const double dist = dist_initial + dist_final;
4486
4487 // Compute the distance between the input initial vertex and the
4488 // output final vertex
4489 double dist_initial_rev =
4495
4496 // Compute the distance between the input final vertex and the
4497 // output initial vertex
4498 double dist_final_rev =
4504
4505 // Get the distace from the input to the output vertices in
4506 // reversed order
4507 const double dist_rev = dist_initial_rev + dist_final_rev;
4508
4509 // If the distance is smaller than the reversed distance then the
4510 // order of the vertices is the same
4511 if (dist <= dist_rev)
4512 {
4513 // Do nothing
4514 copy_reversed = false;
4515 }
4516 else if (dist_rev < dist)
4517 {
4518 // The connection information is copied in reversed order
4519 copy_reversed = true;
4520 } // else if (dist_rev < dist)
4521
4522 // Copy the connection information
4523 // ----------------------------------------------------------------
4524 // Copy in reversed order? (copy normal)
4525 if (!copy_reversed)
4526 {
4527 // Initial vertex. We need to double check that the initial
4528 // vertex of the input curve section correspond with the
4529 // initial vertex of the output sub-polyline. It may be the
4530 // case that this sub-polyline has not the initial vertex
4531 if (input_curve_pt->is_initial_vertex_connected() &&
4532 dist_initial <
4534 {
4535 output_curve_pt->set_initial_vertex_connected();
4536
4537 output_curve_pt->initial_vertex_connected_bnd_id() =
4538 input_curve_pt->initial_vertex_connected_bnd_id();
4539
4540 output_curve_pt->initial_vertex_connected_n_chunk() =
4541 input_curve_pt->initial_vertex_connected_n_chunk();
4542
4543 // We need to know if we have to compute the vertex
4544 // number or if we need just to copy it
4545 if (input_curve_pt->is_initial_vertex_connected_to_curviline())
4546 {
4547 double initial_s_connection =
4548 input_curve_pt->initial_s_connection_value();
4549
4550 unsigned bnd_id =
4551 output_curve_pt->initial_vertex_connected_bnd_id();
4552
4553 double s_tolerance = input_curve_pt->tolerance_for_s_connection();
4554
4555 output_curve_pt->initial_vertex_connected_n_vertex() =
4558
4559 // The output polyline is not longer connected to a
4560 // curviline because we will be using the polyline
4561 // representation of the curviline
4562 output_curve_pt->unset_initial_vertex_connected_to_curviline();
4563 }
4564 else
4565 {
4566 output_curve_pt->initial_vertex_connected_n_vertex() =
4567 input_curve_pt->initial_vertex_connected_n_vertex();
4568 }
4569 } // input_curve_pt->is_initial_vertex_connected() &&
4570 // dist_initial<Tolerance
4571
4572 // Final vertex. We need to double check that the final vertex
4573 // of the input curve section correspond with the final vertex
4574 // of the output sub-polyline. It may be the case that this
4575 // sub-polyline has not the final vertex
4576 if (input_curve_pt->is_final_vertex_connected() &&
4578 {
4579 output_curve_pt->set_final_vertex_connected();
4580
4581 output_curve_pt->final_vertex_connected_bnd_id() =
4582 input_curve_pt->final_vertex_connected_bnd_id();
4583
4584 output_curve_pt->final_vertex_connected_n_chunk() =
4585 input_curve_pt->final_vertex_connected_n_chunk();
4586
4587 // We need to know if we have to compute the vertex number or
4588 // if we need just to copy it
4589 if (input_curve_pt->is_final_vertex_connected_to_curviline())
4590 {
4591 double final_s_connection =
4592 input_curve_pt->final_s_connection_value();
4593
4594 unsigned bnd_id = input_curve_pt->final_vertex_connected_bnd_id();
4595
4596 double s_tolerance = input_curve_pt->tolerance_for_s_connection();
4597
4598 output_curve_pt->final_vertex_connected_n_vertex() =
4601
4602 // The output polyline is not longer connected to a
4603 // curviline because we will be using the polyline
4604 // representation of the curviline
4605 output_curve_pt->unset_final_vertex_connected_to_curviline();
4606 }
4607 else
4608 {
4609 output_curve_pt->final_vertex_connected_n_vertex() =
4610 input_curve_pt->final_vertex_connected_n_vertex();
4611 }
4612 } // input_curve_pt->is_final_vertex_connected() && dist_final<Tolerance
4613 } // if (!copy_reversed)
4614 else
4615 {
4616 // Copy the connections in reversed order
4617
4618 // Initial vertex. We need to double check that the initial
4619 // vertex of the input curve section correspond with the
4620 // initial vertex of the output sub-polyline. It may be the
4621 // case that this sub-polyline has not the initial vertex
4622 if (input_curve_pt->is_initial_vertex_connected() &&
4625 {
4626 output_curve_pt->set_final_vertex_connected();
4627
4628 output_curve_pt->final_vertex_connected_bnd_id() =
4629 input_curve_pt->initial_vertex_connected_bnd_id();
4630
4631 output_curve_pt->final_vertex_connected_n_chunk() =
4632 input_curve_pt->initial_vertex_connected_n_chunk();
4633
4634 // We need to know if we have to compute the vertex number or
4635 // if we need just to copy it
4636 if (input_curve_pt->is_initial_vertex_connected_to_curviline())
4637 {
4638 double initial_s_connection =
4639 input_curve_pt->initial_s_connection_value();
4640
4641 unsigned bnd_id = input_curve_pt->initial_vertex_connected_bnd_id();
4642
4643 double s_tolerance = input_curve_pt->tolerance_for_s_connection();
4644
4645 output_curve_pt->final_vertex_connected_n_vertex() =
4648
4649 // The output polyline is not longer connected to a
4650 // curviline because we will be using the polyline
4651 // representation of the curviline
4652 output_curve_pt->unset_final_vertex_connected_to_curviline();
4653 }
4654 else
4655 {
4656 output_curve_pt->final_vertex_connected_n_vertex() =
4657 input_curve_pt->initial_vertex_connected_n_vertex();
4658 }
4659 } // input_curve_pt->is_final_vertex_connected() && dist_final<Tolerance
4660
4661 // Final vertex. We need to double check that the final vertex
4662 // of the input curve section correspond with the final vertex
4663 // of the output sub-polyline. It may be the case that this
4664 // sub-polyline has not the final vertex
4665 if (input_curve_pt->is_final_vertex_connected() &&
4668 {
4669 output_curve_pt->set_initial_vertex_connected();
4670
4671 output_curve_pt->initial_vertex_connected_bnd_id() =
4672 input_curve_pt->final_vertex_connected_bnd_id();
4673
4674 output_curve_pt->initial_vertex_connected_n_chunk() =
4675 input_curve_pt->final_vertex_connected_n_chunk();
4676
4677 // We need to know if we have to compute the vertex number or
4678 // if we need just to copy it
4679 if (input_curve_pt->is_final_vertex_connected_to_curviline())
4680 {
4681 double final_s_connection =
4682 input_curve_pt->final_s_connection_value();
4683
4684 unsigned bnd_id = input_curve_pt->final_vertex_connected_bnd_id();
4685
4686 double s_tolerance = input_curve_pt->tolerance_for_s_connection();
4687
4688 output_curve_pt->initial_vertex_connected_n_vertex() =
4691
4692 // The output polyline is not longer connected to a
4693 // curviline because we will be using the polyline
4694 // representation of the curviline
4695 output_curve_pt->unset_initial_vertex_connected_to_curviline();
4696 }
4697 else
4698 {
4699 output_curve_pt->initial_vertex_connected_n_vertex() =
4700 input_curve_pt->final_vertex_connected_n_vertex();
4701 }
4702 } // input_curve_pt->is_final_vertex_connected() && dist_final<Tolerance
4703 } // else if (!copy_reversed)
4704 } // if (initial_connection || final_connection)
4705 }
4706
4707
4708 /// Public static flag to suppress warning; defaults to true because
4709 /// it really clutters up the output. It's unlikely to ever be a
4710 /// genuine error...
4711 bool UnstructuredTwoDMeshGeometryBase::
4712 Suppress_warning_about_regions_and_boundaries = true;
4713
4714
4715#endif // OOMPH_HAS_TRIANGLE_LIB
4716
4717
4718} // namespace oomph
e
Definition cfortran.h:571
cstr elem_len * i
Definition cfortran.h:603
char t
Definition cfortran.h:568
void position(const Vector< double > &zeta, Vector< double > &r) const
Return the parametrised position of the FiniteElement in its incarnation as a GeomObject,...
Definition elements.h:2680
double size() const
Calculate the size of the element (length, area, volume,...) in Eulerian computational coordinates....
Definition elements.cc:4320
A geometric object is an object that provides a parametrised description of its shape via the functio...
virtual void position(const Vector< double > &zeta, Vector< double > &r) const =0
Parametrised position on object at current time: r(zeta).
unsigned long nboundary_node(const unsigned &ibound) const
Return number of nodes on a particular boundary.
Definition mesh.h:841
unsigned nboundary() const
Return number of boundaries.
Definition mesh.h:835
Node *& boundary_node_pt(const unsigned &b, const unsigned &n)
Return pointer to node n on boundary b.
Definition mesh.h:497
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
Definition nodes.h:906
An OomphLibError object which should be thrown when an run-time error is encountered....
An OomphLibWarning object which should be created as a temporary object to issue a warning....
TAdvectionDiffusionReactionElement<NREAGENT,DIM,NNODE_1D> elements are isoparametric triangular DIM-d...
Base class defining a closed curve for the Triangle mesh generation.
TriangleMeshClosedCurve(const Vector< TriangleMeshCurveSection * > &curve_section_pt, const Vector< double > &internal_point_pt=Vector< double >(0), const bool &is_internal_point_fixed=false)
Constructor prototype.
Vector< double > Internal_point_pt
Vector of vertex coordinates.
Base class for defining a triangle mesh boundary, this class has the methods that allow to connect th...
bool Initial_vertex_connected_to_curviline
States if the initial vertex is connected to a curviline.
virtual void initial_vertex_coordinate(Vector< double > &vertex)=0
Get first vertex coordinates.
bool Final_vertex_connected
Used for stating if the final end is connected to another boundary.
unsigned Final_vertex_connected_n_vertex
Stores the vertex number used for connection with the final end.
bool Final_vertex_connected_to_curviline
States if the final vertex is connected to a curviline.
double Initial_s_connection_value
Stores the s value used for connecting the initial end with a curviline.
virtual unsigned boundary_id() const =0
Boundary id.
void connect_initial_vertex_to_polyline(TriangleMeshPolyLine *polyline_pt, const unsigned &vertex_number, const double &tolerance_for_connection=1.0e-14)
Connects the initial vertex of the curve section to a desired target polyline by specifying the verte...
double Final_s_connection_value
Stores the s value used for connecting the final end with a curviline.
unsigned Final_vertex_connected_bnd_id
Stores the id to which the initial end is connected.
unsigned Initial_vertex_connected_n_chunk
Stores the chunk number of the boundary to which is connected th initial end.
unsigned initial_vertex_connected_n_vertex() const
Gets the vertex number to which the initial end is connected.
void connect_final_vertex_to_polyline(TriangleMeshPolyLine *polyline_pt, const unsigned &vertex_number, const double &tolerance_for_connection=1.0e-14)
Connects the final vertex of the curve section to a desired target polyline by specifying the vertex ...
unsigned final_vertex_connected_n_chunk() const
Gets the boundary chunk to which the final end is connected.
bool Initial_vertex_connected
Used for stating if the initial end is connected to another boundary.
unsigned final_vertex_connected_n_vertex() const
Sets the vertex number to which the final end is connected.
unsigned Initial_vertex_connected_n_vertex
Stores the vertex number used for connection with the initial end.
bool is_final_vertex_connected() const
Test whether final vertex is connected or not.
double Tolerance_for_s_connection
Tolerance used for connecting the ends to a curviline.
unsigned initial_vertex_connected_bnd_id() const
Gets the id to which the initial end is connected.
virtual void final_vertex_coordinate(Vector< double > &vertex)=0
Get last vertex coordinates.
bool is_initial_vertex_connected() const
Test whether initial vertex is connected or not.
unsigned Final_vertex_connected_n_chunk
Stores the chunk number of the boundary to which is connected th initial end.
void connect_initial_vertex_to_curviline(TriangleMeshCurviLine *curviline_pt, const double &s_value, const double &tolerance_for_connection=1.0e-14)
Connects the initial vertex of the curve section to a desired target curviline by specifying the s va...
unsigned initial_vertex_connected_n_chunk() const
Gets the boundary chunk to which the initial end is connected.
void connect_final_vertex_to_curviline(TriangleMeshCurviLine *curviline_pt, const double &s_value, const double &tolerance_for_connection=1.0e-14)
Connects the final vertex of the curve section to a desired target curviline by specifying the s valu...
unsigned final_vertex_connected_bnd_id() const
Gets the id to which the final end is connected.
unsigned Initial_vertex_connected_bnd_id
Stores the id to which the initial end is connected.
closed curves and open curves. All TriangleMeshCurves are composed of a Vector of TriangleMeshCurveSe...
virtual TriangleMeshCurveSection * curve_section_pt(const unsigned &i) const
Pointer to i-th constituent curve section.
Vector< TriangleMeshCurveSection * > Curve_section_pt
Vector of curve sections.
Class definining a curvilinear triangle mesh boundary in terms of a GeomObject. Curvlinear equivalent...
TriangleMeshOpenCurve(const Vector< TriangleMeshCurveSection * > &curve_section_pt)
Constructor.
Class defining a polyline for use in Triangle Mesh generation.
Vector< double > vertex_coordinate(const unsigned &i) const
Coordinate vector of i-th vertex (const version)
unsigned boundary_chunk() const
Boundary chunk (Used when a boundary is represented by more than one polyline.
unsigned nvertex() const
Number of vertices.
unsigned npolyline() const
Number of constituent polylines.
TriangleMeshPolyLine * polyline_pt(const unsigned &i) const
Pointer to i-th constituent polyline.
TriangleMeshPolygon(const Vector< TriangleMeshCurveSection * > &boundary_polyline_pt, const Vector< double > &internal_point_pt=Vector< double >(0), const bool &is_internal_point_fixed=false)
Constructor: Specify vector of pointers to TriangleMeshCurveSection that define the boundary of the s...
const bool get_connected_vertex_number_on_destination_polyline(TriangleMeshPolyLine *dst_polyline_pt, Vector< double > &vertex_coordinates, unsigned &vertex_number)
Gets the vertex number on the destination polyline (used to create the connections among shared bound...
void snap_nodes_onto_geometric_objects()
Snap the boundary nodes onto any curvilinear boundaries defined by geometric objects.
unsigned get_associated_vertex_to_svalue(double &target_s_value, unsigned &bnd_id)
Get the associated vertex to the given s value by looking to the list of s values created when changi...
void copy_connection_information_to_sub_polylines(TriangleMeshCurveSection *input_curve_pt, TriangleMeshCurveSection *output_curve_pt)
Helper function to copy the connection information from the input curve(polyline or curviline) to the...
void copy_connection_information(TriangleMeshCurveSection *input_curve_pt, TriangleMeshCurveSection *output_curve_pt)
Helper function to copy the connection information from the input curve(polyline or curviline) to the...
void build_triangulateio(Vector< TriangleMeshPolygon * > &outer_polygons_pt, Vector< TriangleMeshPolygon * > &internal_polygons_pt, Vector< TriangleMeshOpenCurve * > &open_curves_pt, Vector< Vector< double > > &extra_holes_coordinates, std::map< unsigned, Vector< double > > &regions_coordinates, std::map< unsigned, double > &regions_areas, TriangulateIO &triangulate_io)
Create TriangulateIO object from outer boundaries, internal boundaries, and open curves....
bool is_point_inside_polygon_helper(Vector< Vector< double > > polygon_vertices, Vector< double > point)
Helper function that checks if a given point is inside a polygon (a set of sorted vertices that conne...
void add_connection_matrix_info_helper(TriangleMeshPolyLine *polyline_pt, std::map< unsigned, std::map< unsigned, Vector< vertex_connection_info > > > &connection_matrix, TriangleMeshPolyLine *next_polyline_pt=0)
Helps to add information to the connection matrix of the given polyline.
void initialise_base_vertex(TriangleMeshPolyLine *polyline_pt, std::map< unsigned, std::map< unsigned, Vector< base_vertex_info > > > &base_vertices)
Initialise the base vertex structure, set every vertex to no visited and not being a base vertex.
std::map< unsigned, GeomObject * > & boundary_geom_object_pt()
Return direct access to the geometric object storage.
void add_base_vertex_info_helper(TriangleMeshPolyLine *polyline_pt, std::map< unsigned, std::map< unsigned, Vector< base_vertex_info > > > &base_vertices, std::map< unsigned, std::map< unsigned, Vector< vertex_connection_info > > > &connection_matrix, std::map< unsigned, std::map< unsigned, unsigned > > &boundary_chunk_nvertices)
Helps to identify the base vertex of the given polyline.
A slight extension to the standard template vector class so that we can include "graceful" array rang...
Definition Vector.h:58
double Tolerable_error
Acceptable discrepancy for mismatch in vertex coordinates. In paranoid mode, the code will die if the...
void create_triangulateio_from_polyfiles(const std::string &node_file_name, const std::string &element_file_name, const std::string &poly_file_name, TriangulateIO &triangle_io, bool &use_attributes)
Create a triangulateio data file from ele node and poly files. This is used if the mesh is generated ...
void dump_triangulateio(TriangulateIO &triangle_io, std::ostream &dump_file)
Write all the triangulateio data to disk in a dump file that can then be used to restart simulations.
void initialise_triangulateio(TriangulateIO &triangle_io)
Initialise TriangulateIO structure.
void read_triangulateio(std::istream &restart_file, TriangulateIO &triangle_io)
Read the triangulateio data from a dump file on disk, which can then be used to restart simulations.
void write_triangulateio_to_polyfile(TriangulateIO &triangle_io, std::ostream &poly_file)
Write the triangulateio data to disk as a poly file, mainly used for debugging.
void clear_triangulateio(TriangulateIO &triangulate_io, const bool &clear_hole_data)
Clear TriangulateIO structure.
TriangulateIO deep_copy_of_triangulateio_representation(TriangulateIO &triangle_io, const bool &quiet)
Make (partial) deep copy of TriangulateIO object. We only copy those items we need within oomph-lib's...
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).
The Triangle data structure, modified from the triangle.h header supplied with triangle 1....
Data structure to store the base vertex info, initial or final vertex in the polylines have an associ...
Data structure filled when the connection matrix is created, for each polyline, there are two vertex_...