MeshedSurface.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2016 OpenFOAM Foundation
9  Copyright (C) 2016-2022 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "MeshedSurface.H"
30 #include "UnsortedMeshedSurface.H"
31 #include "MeshedSurfaceProxy.H"
32 #include "mergePoints.H"
33 #include "Time.H"
34 #include "ListOps.H"
35 #include "polyBoundaryMesh.H"
36 #include "polyMesh.H"
37 #include "surfMesh.H"
38 #include "primitivePatch.H"
39 #include "faceTraits.H"
41 
42 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
43 
44 template<class Face>
46 {
47  return wordHashSet(*fileExtensionConstructorTablePtr_);
48 }
49 
50 
51 template<class Face>
53 {
54  return wordHashSet(*writefileExtensionMemberFunctionTablePtr_);
55 }
56 
57 
58 template<class Face>
60 (
61  const word& fileType,
62  bool verbose
63 )
64 {
65  return fileFormats::surfaceFormatsCore::checkSupport
66  (
67  readTypes() | FriendType::readTypes(),
68  fileType,
69  verbose,
70  "reading"
71  );
72 }
73 
74 
75 template<class Face>
77 (
78  const word& fileType,
79  bool verbose
80 )
81 {
82  return fileFormats::surfaceFormatsCore::checkSupport
83  (
84  writeTypes() | ProxyType::writeTypes(),
85  fileType,
86  verbose,
87  "writing"
88  );
89 }
90 
91 
92 template<class Face>
94 (
95  const fileName& name,
96  bool verbose
97 )
98 {
99  const word ext =
100  (
101  name.has_ext("gz")
102  ? name.stem().ext()
103  : name.ext()
104  );
106  return canReadType(ext, verbose);
107 }
108 
109 
110 template<class Face>
112 (
113  const fileName& name,
114  const MeshedSurface<Face>& surf,
115  IOstreamOption streamOpt,
116  const dictionary& options
117 )
118 {
119  write(name, name.ext(), surf, streamOpt, options);
120 }
121 
122 
123 template<class Face>
125 (
126  const fileName& name,
127  const word& fileType,
128  const MeshedSurface<Face>& surf,
129  IOstreamOption streamOpt,
130  const dictionary& options
131 )
132 {
133  if (fileType.empty())
134  {
135  // Handle empty/missing type
136 
137  const word ext(name.ext());
138 
139  if (ext.empty())
140  {
142  << "Cannot determine format from filename" << nl
143  << " " << name << nl
144  << exit(FatalError);
145  }
146 
147  write(name, ext, surf, streamOpt, options);
148  return;
149  }
150 
151 
152  DebugInFunction << "Writing to " << name << nl;
153 
154  auto* mfuncPtr = writefileExtensionMemberFunctionTable(fileType);
155 
156  if (!mfuncPtr)
157  {
158  // Delegate to proxy if possible
159  const wordHashSet delegate(ProxyType::writeTypes());
160 
161  if (!delegate.found(fileType))
162  {
164  << "Unknown write format " << fileType << nl << nl
165  << "Valid types:" << nl
166  << flatOutput((delegate | writeTypes()).sortedToc()) << nl
167  << exit(FatalError);
168  }
169 
170  MeshedSurfaceProxy<Face>(surf).write
171  (
172  name, fileType, streamOpt, options
173  );
174  }
175  else
176  {
177  mfuncPtr(name, surf, streamOpt, options);
178  }
179 }
180 
181 
182 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
183 
184 template<class Face>
186 :
187  MeshReference(List<Face>(), pointField()),
188  faceIds_(),
189  zones_()
190 {}
191 
192 
193 template<class Face>
195 (
196  const MeshedSurface<Face>& surf
197 )
198 :
199  MeshReference(surf.surfFaces(), surf.points()),
200  faceIds_(surf.faceIds_),
201  zones_(surf.zones_)
202 {}
203 
204 
205 template<class Face>
207 (
208  const UnsortedMeshedSurface<Face>& surf
209 )
210 :
211  MeshReference(List<Face>(), surf.points()), // Copy points only
212  faceIds_(),
213  zones_()
214 {
216  this->storedZones() = surf.sortedZones(faceMap);
217 
218  // Faces, in the sorted order
219  const List<Face>& origFaces = surf;
220  {
221  List<Face> newFaces(origFaces.size());
222 
223  forAll(newFaces, facei)
224  {
225  newFaces[faceMap[facei]] = origFaces[facei];
226  }
227 
228  this->storedFaces().transfer(newFaces);
229  }
230 
231  // FaceIds, in the sorted order
232  const labelList& origIds = surf.faceIds();
233 
234  if (origIds.size() == origFaces.size())
235  {
236  labelList newFaceIds(origIds.size());
237 
238  forAll(newFaceIds, facei)
239  {
240  newFaceIds[faceMap[facei]] = origIds[facei];
241  }
242 
243  this->storedFaceIds().transfer(newFaceIds);
244  }
245 }
246 
247 
248 template<class Face>
250 (
251  MeshedSurface<Face>&& surf
252 )
253 :
254  MeshedSurface<Face>()
255 {
256  transfer(surf);
257 }
258 
259 
260 template<class Face>
262 (
264 )
265 :
266  MeshedSurface<Face>()
267 {
268  transfer(surf);
269 }
270 
271 
272 template<class Face>
274 (
275  const pointField& pointLst,
276  const UList<Face>& faceLst,
277  const UList<surfZone>& zoneLst
278 )
279 :
280  MeshReference(faceLst, pointLst), // Copy construct
281  faceIds_(),
282  zones_(zoneLst)
283 {
284  this->checkZones(false); // Non-verbose fix zones
285 }
286 
287 
288 template<class Face>
290 (
291  pointField&& pointLst,
292  List<Face>&& faceLst,
293  const UList<surfZone>& zoneLst
294 )
295 :
296  MeshReference(faceLst, pointLst, true), // Move construct
297  faceIds_(),
298  zones_(zoneLst)
299 {
300  this->checkZones(false); // Non-verbose fix zones
301 }
302 
303 
304 template<class Face>
306 (
307  const pointField& pointLst,
308  const UList<Face>& faceLst,
309  const labelUList& zoneSizes,
310  const UList<word>& zoneNames
311 )
312 :
313  MeshReference(faceLst, pointLst), // Copy construct
314  faceIds_(),
315  zones_()
316 {
317  if (zoneSizes.size())
318  {
319  if (zoneNames.size())
320  {
321  addZones(zoneSizes, zoneNames);
322  }
323  else
324  {
325  addZones(zoneSizes);
326  }
327  }
328 }
329 
330 
331 template<class Face>
333 (
334  pointField&& pointLst,
335  List<Face>&& faceLst,
336  const labelUList& zoneSizes,
337  const UList<word>& zoneNames
338 )
339 :
340  MeshReference(faceLst, pointLst, true), // Move construct
341  faceIds_(),
342  zones_()
343 {
344  if (zoneSizes.size())
345  {
346  if (zoneNames.size())
347  {
348  addZones(zoneSizes, zoneNames);
349  }
350  else
351  {
352  addZones(zoneSizes);
353  }
354  }
355 }
356 
357 
358 template<class Face>
360 :
361  MeshedSurface<Face>()
362 {
363  // Need same face type as surfMesh
364  MeshedSurface<face> surf
365  (
366  mesh.points(),
367  mesh.faces(),
368  mesh.surfZones()
369  );
371  this->transcribe(surf);
372 }
373 
374 
375 template<class Face>
377 (
378  const polyBoundaryMesh& bMesh,
379  const bool useGlobalPoints
380 )
381 :
382  MeshedSurface<Face>()
383 {
384  const polyMesh& mesh = bMesh.mesh();
385  const polyPatchList& bPatches = bMesh;
386 
387  // Get a single patch for all boundaries
388  primitivePatch allBoundary
389  (
391  (
392  mesh.faces(),
393  mesh.nBoundaryFaces(),
394  mesh.nInternalFaces()
395  ),
396  mesh.points()
397  );
398 
399  // use global/local points:
400  const pointField& bPoints =
401  (
402  useGlobalPoints ? mesh.points() : allBoundary.localPoints()
403  );
404 
405  // global/local face addressing:
406  const List<Face>& bFaces =
407  (
408  useGlobalPoints ? allBoundary : allBoundary.localFaces()
409  );
410 
411 
412  // create zone list
413  surfZoneList newZones(bPatches.size());
414 
415  label startFacei = 0;
416  label nZone = 0;
417  for (const polyPatch& p : bPatches)
418  {
419  if (p.size())
420  {
421  newZones[nZone] = surfZone
422  (
423  p.name(),
424  p.size(),
425  startFacei,
426  nZone
427  );
428 
429  ++nZone;
430  startFacei += p.size();
431  }
432  }
433 
434  newZones.setSize(nZone);
435 
436  // Face type as per polyBoundaryMesh
437  MeshedSurface<face> surf(bPoints, bFaces, newZones);
439  this->transcribe(surf);
440 }
441 
442 
443 template<class Face>
445 (
446  const fileName& name,
447  const word& fileType
448 )
449 :
451 {
452  read(name, fileType);
453 }
454 
455 
456 template<class Face>
458 :
460 {
461  read(name);
462 }
463 
464 
465 template<class Face>
467 :
468  MeshedSurface<Face>()
469 {
470  read(is);
471 }
472 
473 
474 template<class Face>
476 (
477  const Time& runTime
478 )
479 :
480  MeshedSurface<Face>(runTime, word::null)
481 {}
482 
483 
484 template<class Face>
486 (
487  const Time& runTime,
488  const word& surfName
489 )
490 :
491  MeshedSurface<Face>()
492 {
493  surfMesh mesh
494  (
495  IOobject
496  (
497  "dummyName",
498  runTime.timeName(),
499  runTime,
500  IOobjectOption::MUST_READ,
501  IOobjectOption::NO_WRITE,
502  IOobjectOption::NO_REGISTER
503  ),
504  surfName
505  );
506 
507  // The geometry components, returned via autoPtr
509  (
510  std::move(*(mesh.releaseGeom()))
511  );
513  this->transcribe(surf);
514 }
515 
516 
517 template<class Face>
519 (
520  const IOobject& io,
521  const dictionary& dict,
522  const bool isGlobal
523 )
524 :
525  MeshedSurface<Face>()
526 {
527  fileName fName
528  (
529  fileFormats::surfaceFormatsCore::checkFile(io, dict, isGlobal)
530  );
531 
532  this->read(fName, dict.getOrDefault<word>("fileType", word::null));
533 
534  this->scalePoints(dict.getOrDefault<scalar>("scale", 0));
535 }
536 
537 
538 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
539 
540 template<class Face>
542 {
543  clear();
544 }
545 
546 
547 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
548 
549 template<class Face>
551 (
552  const labelUList& faceMapNewToOld
553 )
554 {
555  if (faceMapNewToOld.empty())
556  {
557  return;
558  }
559 
560  surfZoneList& zones = storedZones();
561 
562  if (zones.size() == 1)
563  {
564  // Single zone case is trivial
565  zones[0].size() = faceMapNewToOld.size();
566  return;
567  }
568 
569  // Recalculate the zone start/size
570  label newFacei = 0;
571  label origEndi = 0;
572 
573  for (surfZone& zone : zones)
574  {
575  // Adjust zone start
576  zone.start() = newFacei;
577  origEndi += zone.size();
578 
579  for (label facei = newFacei; facei < faceMapNewToOld.size(); ++facei)
580  {
581  if (faceMapNewToOld[facei] < origEndi)
582  {
583  ++newFacei;
584  }
585  else
586  {
587  break;
588  }
589  }
590 
591  // Adjust zone size
592  zone.size() = newFacei - zone.start();
593  }
594 }
595 
596 
597 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
598 
599 template<class Face>
601 {
602  MeshReference::clearOut(); // Topology changes
603 
604  storedPoints().clear();
605  storedFaces().clear();
606  storedFaceIds().clear();
607  storedZones().clear();
608 }
609 
610 
611 template<class Face>
613 {
614  MeshReference::clearGeom(); // Changes areas, normals etc.
615 
616  // Adapt for new point positions
617  MeshReference::movePoints(newPoints);
619  // Copy new points
620  storedPoints() = newPoints;
621 }
622 
623 
624 template<class Face>
625 void Foam::MeshedSurface<Face>::scalePoints(const scalar scaleFactor)
626 {
627  // Avoid bad or no scaling
628  if (scaleFactor > SMALL && !equal(scaleFactor, 1))
629  {
630  // Remove all geometry dependent data
631  this->clearTopology();
632 
633  // Adapt for new point positions
634  MeshReference::movePoints(pointField());
635 
636  this->storedPoints() *= scaleFactor;
637  }
638 }
639 
640 
641 // Remove badly degenerate faces, double faces.
642 template<class Face>
643 void Foam::MeshedSurface<Face>::cleanup(const bool verbose)
644 {
645  // Merge points (already done for STL, TRI)
646  stitchFaces(SMALL, verbose);
648  checkFaces(verbose);
649  this->checkTopology(verbose);
650 }
651 
652 
653 template<class Face>
655 {
656  this->clearOut(); // Topology changes
657 
658  // Remove unused points while walking and renumbering faces
659  // in visit order - walk order as per localFaces()
660 
661  labelList oldToCompact(this->points().size(), -1);
662  DynamicList<label> compactPointMap(oldToCompact.size());
663 
664  for (auto& f : this->storedFaces())
665  {
666  for (label& pointi : f)
667  {
668  label compacti = oldToCompact[pointi];
669  if (compacti == -1)
670  {
671  compacti = compactPointMap.size();
672  oldToCompact[pointi] = compacti;
673  compactPointMap.append(pointi);
674  }
675  pointi = compacti;
676  }
677  }
678 
679  pointField newPoints
680  (
681  UIndirectList<point>(this->points(), compactPointMap)
682  );
683 
684  this->swapPoints(newPoints);
685 
686  if (notNull(pointMap))
687  {
688  pointMap.transfer(compactPointMap);
689  }
690 }
691 
692 
693 template<class Face>
695 (
696  const scalar tol,
697  const bool verbose
698 )
699 {
700  pointField& ps = this->storedPoints();
701 
702  // Merge points (inplace)
703  labelList pointMap;
704  label nChanged = Foam::inplaceMergePoints(ps, tol, verbose, pointMap);
705 
706  if (!nChanged)
707  {
708  return false;
709  }
710 
711  if (verbose)
712  {
713  InfoInFunction<< "Renumbering all faces" << endl;
714  }
715 
716  List<Face>& faceLst = this->storedFaces();
717 
718  labelList faceMap(faceLst.size(), -1);
719 
720  // Reset the point labels to the unique points array
721  label newFacei = 0;
722  forAll(faceLst, facei)
723  {
724  Face& f = faceLst[facei];
725  for (label& vert : f)
726  {
727  vert = pointMap[vert];
728  }
729 
730  // For extra safety: collapse face as well
731  if (f.collapse() >= 3)
732  {
733  if (newFacei != facei)
734  {
735  faceLst[newFacei] = f;
736  }
737  faceMap[newFacei] = facei;
738  ++newFacei;
739  }
740  else if (verbose)
741  {
742  Pout<< "MeshedSurface::stitchFaces : "
743  << "Removing collapsed face " << facei << endl
744  << " vertices :" << f << endl;
745  }
746  }
747  pointMap.clear();
748 
749  if (newFacei != faceLst.size())
750  {
751  if (verbose)
752  {
753  Pout<< "MeshedSurface::stitchFaces : "
754  << "Removed " << faceLst.size() - newFacei
755  << " faces" << endl;
756  }
757  faceMap.resize(newFacei);
758  faceLst.resize(newFacei);
759 
760  // The faceMap is a newToOld mapping and only removes elements
761  if (faceIds_.size())
762  {
763  forAll(faceMap, facei)
764  {
765  faceIds_[facei] = faceIds_[faceMap[facei]];
766  }
767 
768  faceIds_.resize(newFacei);
769  }
770 
771  remapFaces(faceMap);
772  }
773  faceMap.clear();
774 
775  // Topology can change when points are merged, etc
776  MeshReference::clearOut();
777 
778  return true;
779 }
780 
781 
782 // Remove badly degenerate faces and double faces.
783 template<class Face>
785 (
786  const bool verbose
787 )
788 {
789  bool changed = false;
790  List<Face>& faceLst = this->storedFaces();
791 
792  labelList faceMap(faceLst.size());
793 
794  label newFacei = 0;
795  const label maxPointi = this->points().size();
796 
797  // Detect badly labelled faces and mark degenerate faces
798  forAll(faceLst, facei)
799  {
800  Face& f = faceLst[facei];
801 
802  // Avoid degenerate faces
803  if (f.collapse() >= 3)
804  {
805  for (const label vert : f)
806  {
807  if (vert < 0 || vert >= maxPointi)
808  {
810  << "face " << f
811  << " uses point indices outside point range 0.."
812  << (maxPointi-1)
813  << exit(FatalError);
814  }
815  }
816 
817  faceMap[facei] = facei;
818  ++newFacei;
819  }
820  else
821  {
822  // Mark as bad face
823  faceMap[facei] = -1;
824 
825  changed = true;
826  if (verbose)
827  {
829  << "face[" << facei << "] = " << f
830  << " does not have three unique vertices" << endl;
831  }
832  }
833  }
834 
835  // Detect doubled faces
836  // do not touch the faces
837  const labelListList& fFaces = this->faceFaces();
838  newFacei = 0;
839  forAll(faceLst, facei)
840  {
841  // Skip already collapsed faces
842  if (faceMap[facei] < 0)
843  {
844  continue;
845  }
846 
847  const Face& f = faceLst[facei];
848 
849  // Duplicate face check
850  bool okay = true;
851  const labelList& neighbours = fFaces[facei];
852 
853  // Check if faceNeighbours use same points as this face.
854  // Note: discards normal information - sides of baffle are merged.
855  for (const label neiFacei : neighbours)
856  {
857  if (neiFacei <= facei || faceMap[neiFacei] < 0)
858  {
859  // lower numbered faces already checked
860  // skip neighbours that are themselves collapsed
861  continue;
862  }
863 
864  const Face& nei = faceLst[neiFacei];
865 
866  if (f == nei)
867  {
868  okay = false;
869 
870  if (verbose)
871  {
873  << "faces share the same vertices:" << nl
874  << " face[" << facei << "] : " << f << nl
875  << " face[" << neiFacei << "] : " << nei << endl;
876  // printFace(Warning, " ", f, points());
877  // printFace(Warning, " ", nei, points());
878  }
879 
880  break;
881  }
882  }
883 
884  if (okay)
885  {
886  faceMap[facei] = facei;
887  ++newFacei;
888  }
889  else
890  {
891  faceMap[facei] = -1;
892  }
893  }
894 
895 
896  // Until now, faceMap is an identity for good faces and -1 for bad faces
897 
898  // Phase 1: pack
899  // Done to keep numbering constant in phase 1
900 
901  if (changed || newFacei < faceLst.size())
902  {
903  changed = true;
904 
905  if (verbose)
906  {
908  << "Removed " << faceLst.size() - newFacei
909  << " illegal faces." << endl;
910  }
911 
912  // Compress the face list
913  newFacei = 0;
914  forAll(faceLst, facei)
915  {
916  if (faceMap[facei] >= 0)
917  {
918  if (newFacei != facei)
919  {
920  faceLst[newFacei] = std::move(faceLst[facei]);
921  }
922  faceMap[newFacei] = facei;
923  ++newFacei;
924  }
925  }
926 
927  faceMap.resize(newFacei);
928  faceLst.resize(newFacei);
929 
930  // The faceMap is a newToOld mapping and only removes elements
931  if (faceIds_.size())
932  {
933  forAll(faceMap, facei)
934  {
935  faceIds_[facei] = faceIds_[faceMap[facei]];
936  }
937 
938  faceIds_.resize(newFacei);
939  }
940 
941  remapFaces(faceMap);
942  }
943  faceMap.clear();
944 
945  // Topology can change because of renumbering
946  MeshReference::clearOut();
947  return changed;
948 }
949 
950 
951 template<class Face>
952 Foam::label Foam::MeshedSurface<Face>::nTriangles() const
953 {
955  {
956  return MeshReference::size();
957  }
958 
959  return nTriangles
960  (
961  const_cast<labelList&>(labelList::null())
962  );
963 }
964 
965 
966 template<class Face>
968 (
970 ) const
971 {
972  label nTri = 0;
973  const List<Face>& faceLst = surfFaces();
974 
975  // Count triangles needed
976  for (const auto& f : faceLst)
977  {
978  nTri += f.nTriangles();
979  }
980 
981  // Nothing to do
982  if (nTri <= faceLst.size())
983  {
984  if (notNull(faceMap))
985  {
986  faceMap.clear();
987  }
988  }
989  else if (notNull(faceMap))
990  {
991  // Face map requested
992  faceMap.resize(nTri);
993 
994  nTri = 0;
995  forAll(faceLst, facei)
996  {
997  label n = faceLst[facei].nTriangles();
998  while (n-- > 0)
999  {
1000  faceMap[nTri++] = facei;
1001  }
1002  }
1003 
1004  faceMap.resize(nTri);
1005  }
1006 
1007  return nTri;
1008 }
1009 
1010 
1011 template<class Face>
1013 {
1014  if (faceTraits<Face>::isTri())
1015  {
1016  // Inplace triangulation of triFace/labelledTri surface = no-op
1017  return 0;
1018  }
1019  else
1020  {
1021  return triangulate
1022  (
1023  const_cast<labelList&>(labelList::null())
1024  );
1025  }
1026 }
1027 
1028 
1029 template<class Face>
1031 (
1032  labelList& faceMapOut
1033 )
1034 {
1035  labelList dummyFaceMap;
1036 
1037  labelList& faceMap =
1038  (
1039  notNull(faceMapOut)
1040  ? faceMapOut
1041  : dummyFaceMap
1042  );
1043 
1044  if (faceTraits<Face>::isTri())
1045  {
1046  // Inplace triangulation of triFace/labelledTri surface = no-op
1047  faceMap.clear();
1048  return 0;
1049  }
1050 
1051  label nTri = 0;
1052  label maxTri = 0; // the maximum number of triangles for any single face
1053  List<Face>& faceLst = this->storedFaces();
1054 
1055  // How many triangles will be needed
1056  for (const auto& f : faceLst)
1057  {
1058  const label n = f.nTriangles();
1059  if (maxTri < n)
1060  {
1061  maxTri = n;
1062  }
1063  nTri += n;
1064  }
1065 
1066  // Nothing to do
1067  if (nTri <= faceLst.size())
1068  {
1069  faceMap.clear();
1070  return 0;
1071  }
1072 
1073  this->storedFaceIds().clear(); // Invalid or misleading
1074 
1075  List<Face> newFaces(nTri);
1076  faceMap.resize(nTri);
1077 
1078  if (this->points().empty())
1079  {
1080  // triangulate without points
1081  // simple face triangulation around f[0]
1082  nTri = 0;
1083  forAll(faceLst, facei)
1084  {
1085  const Face& f = faceLst[facei];
1086 
1087  for (label fp = 1; fp < f.size() - 1; ++fp)
1088  {
1089  const label fp1 = f.fcIndex(fp);
1090 
1091  newFaces[nTri] = Face{f[0], f[fp], f[fp1]};
1092  faceMap[nTri] = facei;
1093  ++nTri;
1094  }
1095  }
1096  }
1097  else
1098  {
1099  // triangulate with points
1100  List<face> tmpTri(maxTri);
1101 
1102  nTri = 0;
1103  forAll(faceLst, facei)
1104  {
1105  // 'face' not '<Face>'
1106  const face& f = faceLst[facei];
1107 
1108  label nTmp = 0;
1109  f.triangles(this->points(), nTmp, tmpTri);
1110  for (label triI = 0; triI < nTmp; triI++)
1111  {
1112  newFaces[nTri] = Face
1113  (
1114  static_cast<labelUList&>(tmpTri[triI])
1115  );
1116  faceMap[nTri] = facei;
1117  ++nTri;
1118  }
1119  }
1120  }
1121 
1122  // The number of *additional* faces
1123  nTri -= faceLst.size();
1124 
1125  faceLst.transfer(newFaces);
1126  remapFaces(faceMap);
1127 
1128  // Topology can change because of renumbering
1129  MeshReference::clearOut();
1130 
1131  return nTri;
1132 }
1133 
1134 
1135 template<class Face>
1138 (
1139  const labelList& pointMap,
1140  const labelList& faceMap
1141 ) const
1142 {
1143  const pointField& locPoints = this->localPoints();
1144  const List<Face>& locFaces = this->localFaces();
1145 
1146  // Subset of points (compact)
1147  pointField newPoints(UIndirectList<point>(locPoints, pointMap));
1148 
1149  // Inverse point mapping - same as ListOps invert() without checks
1150  labelList oldToNew(locPoints.size(), -1);
1151  forAll(pointMap, pointi)
1152  {
1153  oldToNew[pointMap[pointi]] = pointi;
1154  }
1155 
1156  // Subset of faces
1157  List<Face> newFaces(UIndirectList<Face>(locFaces, faceMap));
1158 
1159  // Renumber face node labels
1160  for (auto& f : newFaces)
1161  {
1162  for (label& vert : f)
1163  {
1164  vert = oldToNew[vert];
1165  }
1166  }
1167  oldToNew.clear();
1168 
1169  // Deep copy of zones, leave start/size intact!!
1170  surfZoneList newZones(zones_);
1171 
1172  // Recalculate the zone start/size
1173  label newFacei = 0;
1174  label origEndi = 0;
1175 
1176  for (surfZone& zone : newZones)
1177  {
1178  // The old zone ending
1179  origEndi += zone.size();
1180 
1181  // The new zone start
1182  zone.start() = newFacei;
1183 
1184  for (label facei = newFacei; facei < faceMap.size(); ++facei)
1185  {
1186  if (faceMap[facei] < origEndi)
1187  {
1188  ++newFacei;
1189  }
1190  else
1191  {
1192  break;
1193  }
1194  }
1195 
1196  // The new zone size
1197  zone.size() = newFacei - zone.start();
1198  }
1199 
1200 
1201  // Subset of faceIds. Can be empty.
1202  labelList newFaceIds;
1203  if (faceIds_.size())
1204  {
1205  newFaceIds = labelUIndList(faceIds_, faceMap);
1206  }
1207 
1208  // Construct the sub-surface
1209  MeshedSurface<Face> newSurf;
1210  newSurf.storedFaces().transfer(newFaces);
1211  newSurf.storedPoints().transfer(newPoints);
1212  newSurf.storedZones().transfer(newZones);
1213  newSurf.storedFaceIds().transfer(newFaceIds);
1214 
1215  return newSurf;
1216 }
1217 
1218 
1219 template<class Face>
1222 (
1223  const UList<bool>& include,
1224  labelList& pointMap,
1226 ) const
1227 {
1228  this->subsetMeshMap(include, pointMap, faceMap);
1229  return this->subsetMeshImpl(pointMap, faceMap);
1230 }
1231 
1232 
1233 template<class Face>
1236 (
1237  const bitSet& include,
1238  labelList& pointMap,
1240 ) const
1241 {
1242  this->subsetMeshMap(include, pointMap, faceMap);
1243  return this->subsetMeshImpl(pointMap, faceMap);
1244 }
1245 
1246 
1247 template<class Face>
1250 (
1251  const UList<bool>& include
1252 ) const
1253 {
1254  labelList pointMap, faceMap;
1255  return this->subsetMesh(include, pointMap, faceMap);
1256 }
1257 
1258 
1259 template<class Face>
1262 (
1263  const bitSet& include
1264 ) const
1265 {
1266  labelList pointMap, faceMap;
1267  return this->subsetMesh(include, pointMap, faceMap);
1268 }
1269 
1270 
1271 template<class Face>
1273 (
1274  const wordRes& includeNames,
1275  const wordRes& excludeNames
1276 ) const
1277 {
1278  bitSet include(this->size());
1279 
1280  for
1281  (
1282  const label zonei
1283  : fileFormats::surfaceFormatsCore::getSelectedPatches
1284  (
1285  zones_,
1286  includeNames,
1287  excludeNames
1288  )
1289  )
1290  {
1291  include.set(zones_[zonei].range());
1292  }
1294  return this->subsetMesh(include);
1295 }
1296 
1297 
1298 template<class Face>
1300 (
1301  MeshedSurface<Face>& surf
1302 )
1303 {
1304  if (this == &surf)
1305  {
1306  return; // Self-swap is a no-op
1307  }
1308 
1309  MeshReference::clearOut(); // Topology changes
1310  surf.clearOut(); // Topology changes
1311 
1312  this->storedPoints().swap(surf.storedPoints());
1313  this->storedFaces().swap(surf.storedFaces());
1314  this->storedZones().swap(surf.storedZones());
1315  this->storedFaceIds().swap(surf.storedFaceIds());
1316 }
1317 
1318 
1319 template<class Face>
1321 (
1322  pointField& pointLst,
1323  List<Face>& faceLst
1324 )
1325 {
1326  MeshReference::clearOut(); // Topology changes
1327 
1328  this->storedPoints().transfer(pointLst);
1329  this->storedFaces().transfer(faceLst);
1330  this->storedZones().clear();
1331  this->storedFaceIds().clear(); // Likely to be invalid
1332 }
1333 
1334 
1335 template<class Face>
1337 (
1338  MeshedSurface<Face>& surf
1339 )
1340 {
1341  if (this == &surf)
1342  {
1343  return; // Self-assigment is a no-op
1344  }
1345 
1346  MeshReference::clearOut(); // Topology changes
1347 
1348  this->storedPoints().transfer(surf.storedPoints());
1349  this->storedFaces().transfer(surf.storedFaces());
1350  this->storedZones().transfer(surf.storedZones());
1351  this->storedFaceIds().transfer(surf.storedFaceIds());
1353  surf.clear();
1354 }
1355 
1356 
1357 template<class Face>
1359 (
1361 )
1362 {
1363  // Clear everything
1364  this->clear();
1365 
1367  surfZoneList zoneLst = surf.sortedZones(faceMap);
1368 
1369  List<Face>& faceLst = surf.storedFaces();
1370 
1371  if (zoneLst.size() > 1)
1372  {
1373  // Unknown if we really need to sort the faces
1374  List<Face> sortedFaces(faceMap.size());
1375 
1376  forAll(faceMap, facei)
1377  {
1378  sortedFaces[faceMap[facei]].transfer(faceLst[facei]);
1379  }
1380 
1381  faceLst.swap(sortedFaces); // Replace with sorted faces
1382  }
1383 
1384  MeshedSurface<Face> newSurf
1385  (
1386  std::move(surf.storedPoints()),
1387  std::move(faceLst),
1388  zoneLst
1389  );
1390 
1391  surf.clear();
1393  this->swap(newSurf);
1394 }
1395 
1396 
1397 template<class Face>
1400 {
1401  return autoPtr<MeshedSurface<Face>>::New(std::move(*this));
1402 }
1403 
1404 
1405 template<class Face>
1407 {
1408  MeshReference::clearOut(); // Topology changes
1409 
1410  this->storedFaceIds().clear(); // Likely to be invalid
1411 
1412  this->storedFaces().swap(faces);
1413 
1414  this->checkZones(false); // Non-verbose fix zones
1415 }
1416 
1417 
1418 template<class Face>
1420 {
1421  // Adapt for new point positions
1422  MeshReference::movePoints(points);
1423 
1424  this->storedPoints().swap(points);
1425 }
1426 
1427 
1428 template<class Face>
1430 {
1431  this->clear();
1432  transfer(*New(name));
1433  return true;
1434 }
1435 
1436 
1437 template<class Face>
1439 (
1440  const fileName& name,
1441  const word& fileType
1442 )
1443 {
1444  this->clear();
1445  transfer(*New(name, fileType));
1446  return true;
1447 }
1448 
1449 
1450 template<class Face>
1452 (
1453  const Time& t,
1454  const word& surfName
1455 ) const
1456 {
1457  MeshedSurfaceProxy<Face>(*this).write(t, surfName);
1458 }
1459 
1460 
1461 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
1462 
1463 template<class Face>
1465 {
1466  if (this == &surf)
1467  {
1468  return; // Self-assignment is a no-op
1469  }
1470 
1471  // Clear everything
1472  this->clear();
1473 
1474  this->storedPoints() = surf.points();
1475  this->storedFaces() = surf.surfFaces();
1476  this->storedFaceIds() = surf.faceIds();
1477  this->storedZones() = surf.surfZones();
1478 }
1479 
1480 
1481 template<class Face>
1483 {
1484  transfer(surf);
1485 }
1486 
1487 
1488 template<class Face>
1490 {
1491  return MeshedSurfaceProxy<Face>
1492  (
1493  this->points(),
1494  this->surfFaces(),
1495  this->surfZones(),
1496  labelUList::null(), // faceMap = none
1497  this->faceIds()
1498  );
1499 }
1500 
1501 
1502 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1503 
1504 #include "MeshedSurfaceZones.C"
1505 #include "MeshedSurfaceIO.C"
1506 #include "MeshedSurfaceNew.C"
1507 
1508 // ************************************************************************* //
A surface geometry mesh, in which the surface zone information is conveyed by the &#39;zoneId&#39; associated...
Definition: MeshedSurface.H:76
virtual void clear()
Clear all storage.
void swap(UList< T > &list) noexcept
Swap content with another UList of the same type in constant time.
Definition: UListI.H:505
dictionary dict
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
virtual void compactPoints(labelList &pointMap=const_cast< labelList &>(labelList::null()))
Remove unused points and renumber faces in local visit order.
virtual void scalePoints(const scalar scaleFactor)
Scale points. A non-positive factor is ignored.
void set(const bitSet &bitset)
Set specified bits from another bitset.
Definition: bitSetI.H:504
A class for handling file names.
Definition: fileName.H:72
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
virtual ~MeshedSurface()
Destructor.
autoPtr< MeshedSurface< Face > > releaseGeom()
Release (clear) geometry and return for reuse.
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:160
void transfer(List< T > &list)
Transfer the contents of the argument List into this list and annul the argument list.
Definition: List.C:326
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: BitOps.H:56
A surface geometry mesh with zone information, not to be confused with the similarly named surfaceMes...
static bool canRead(const fileName &name, bool verbose=false)
Can we read this file format?
Definition: MeshedSurface.C:87
An Istream is an abstract base class for all input systems (streams, files, token lists etc)...
Definition: Istream.H:57
A surface zone on a MeshedSurface.
Definition: surfZone.H:52
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
bool empty() const noexcept
True if List is empty (ie, size() is zero)
Definition: UList.H:666
label checkTopology(const polyMesh &mesh, const bool allTopology, const bool allGeometry, autoPtr< surfaceWriter > &surfWriter, autoPtr< coordSetWriter > &setWriter, const bool writeBadEdges=false)
static wordHashSet writeTypes()
Known writable file-types, without friends or proxies.
Definition: MeshedSurface.C:45
UIndirectList< label > labelUIndList
UIndirectList of labels.
Definition: IndirectList.H:65
virtual void clear()
Clear all storage.
engineTime & runTime
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
tmp< DimensionedField< TypeR, GeoMesh > > New(const tmp< DimensionedField< TypeR, GeoMesh >> &tf1, const word &name, const dimensionSet &dimensions, const bool initCopy=false)
Global function forwards to reuseTmpDimensionedField::New.
A simple container for options an IOstream can normally have.
label checkZones(const polyMesh &mesh, const ZoneMesh< Zone, polyMesh > &zones, topoSet &set)
List< labelList > labelListList
List of labelList.
Definition: labelList.H:38
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:69
bool equal(const Matrix< Form1, Type > &A, const Matrix< Form2, Type > &B, const bool verbose=false, const label maxDiffs=10, const scalar relTol=1e-5, const scalar absTol=1e-8)
Compare matrix elements for absolute or relative equality.
Definition: MatrixTools.C:27
surfZoneList & storedZones()
Non-const access to the zones.
Macros for easy insertion into run-time selection tables.
scalar range
UList< label > labelUList
A UList of labels.
Definition: UList.H:78
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
Various functions to operate on Lists.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
static void write(const fileName &name, const MeshedSurfaceProxy &surf, IOstreamOption streamOpt=IOstreamOption(), const dictionary &options=dictionary::null)
Write to file, select based on its extension.
word ext() const
Return file name extension (part after last .)
Definition: wordI.H:171
void swapPoints(pointField &points)
Swap the stored points.
Traits class for faces.
Definition: faceTraits.H:44
void write(vtk::formatter &fmt, const Type &val, const label n=1)
Component-wise write of a value (N times)
A list of faces which address into the list of points.
A List obtained as a section of another List.
Definition: SubList.H:50
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
dynamicFvMesh & mesh
static wordHashSet readTypes()
Known readable file-types, without friends or proxies.
Definition: MeshedSurface.C:38
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
const pointField & points
bool has_ext() const
Various checks for extensions.
Definition: stringI.H:43
List< Face > & storedFaces()
Non-const access to the faces.
A class for handling words, derived from Foam::string.
Definition: word.H:63
#define DebugInFunction
Report an information message using Foam::Info.
label size() const noexcept
The number of entries in the list.
Definition: UPtrListI.H:106
void swap(MeshedSurface< Face > &surf)
Swap contents.
pointField & storedPoints()
Non-const access to global points.
virtual void cleanup(const bool verbose)
Remove invalid faces.
virtual label triangulate()
Triangulate in-place, returning the number of triangles added.
virtual void movePoints(const pointField &newPoints)
Move points.
A List of wordRe with additional matching capabilities.
Definition: wordRes.H:53
MeshedSurface subsetMesh(const UList< bool > &include, labelList &pointMap, labelList &faceMap) const
Return a new surface subsetted on the selected faces.
void operator=(const MeshedSurface< Face > &surf)
Copy assignment.
patchWriters clear()
HashSet< word, Hash< word > > wordHashSet
A HashSet of words, uses string hasher.
Definition: HashSet.H:73
const Field< point_type > & points() const noexcept
Return reference to global points.
labelList & storedFaceIds()
Non-const access to face ids.
label inplaceMergePoints(PointList &points, const scalar mergeTol, const bool verbose, labelList &pointToUnique)
Inplace merge points, preserving the original point order. All points closer/equal mergeTol are to be...
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO...
const labelList & faceIds() const
Return const access to faces ids.
A surface mesh consisting of general polygon faces that has IO capabilities and a registry for storin...
Definition: surfMesh.H:59
const List< Face > & surfFaces() const
Return const access to the faces.
void read(Istream &, label &val, const dictionary &)
In-place read with dictionary lookup.
static bool canWriteType(const word &fileType, bool verbose=false)
Can we write this file format? Also checks proxy types.
Definition: MeshedSurface.C:70
A proxy for writing MeshedSurface, UnsortedMeshedSurface and surfMesh to various file formats...
Definition: MeshedSurface.H:75
Geometric merging of points. See below.
labelList f(nPoints)
surfZoneList sortedZones(labelList &faceMap) const
Sort faces according to zoneIds.
virtual label nTriangles() const
Count number of triangles.
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:59
#define WarningInFunction
Report a warning using Foam::Warning.
static bool canReadType(const word &fileType, bool verbose=false)
Can we read this file format? Also checks friend types.
Definition: MeshedSurface.C:53
virtual bool checkFaces(const bool verbose=false)
A list of pointers to objects of type <T>, with allocation/deallocation management of the pointers...
Definition: List.H:55
List< surfZone > surfZoneList
List of surfZone.
Definition: surfZoneList.H:32
void transfer(pointField &pointLst, List< Face > &faceLst)
Transfer the components.
virtual void remapFaces(const labelUList &faceMapNewToOld)
Set new zones from faceMap.
List< label > sortedToc(const UList< bool > &bools)
Return the (sorted) values corresponding to &#39;true&#39; entries.
Definition: BitOps.C:195
void swapFaces(List< Face > &faces)
Swap the stored faces. Use with caution.
label n
Pointer management similar to std::unique_ptr, with some additional methods and type checking...
Definition: HashPtrTable.H:48
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:74
List< label > labelList
A List of labels.
Definition: List.H:62
volScalarField & p
IOobject io("surfaceFilmProperties", mesh.time().constant(), mesh, IOobject::READ_IF_PRESENT, IOobject::NO_WRITE, IOobject::NO_REGISTER)
const surfZoneList & surfZones() const
Const access to the surface zones.
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:69
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:172
PrimitivePatch< List< face >, const pointField > bMesh
Holder of faceList and points. (v.s. e.g. primitivePatch which references points) ...
Definition: bMesh.H:39
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
bool notNull(const T *ptr)
True if ptr is not a pointer (of type T) to the nullObject.
Definition: nullObject.H:246
MeshedSurface()
Default construct, an empty surface.
virtual bool stitchFaces(const scalar tol=SMALL, const bool verbose=false)
FlatOutput::OutputAdaptor< Container, Delimiters > flatOutput(const Container &obj, Delimiters delim)
Global flatOutput() function with specified output delimiters.
Definition: FlatOutput.H:225
#define InfoInFunction
Report an information message using Foam::Info.