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(List<Face>(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(List<Face>(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& pbm,
379  const bool useGlobalPoints
380 )
381 :
382  MeshedSurface<Face>()
383 {
384  const polyMesh& mesh = pbm.mesh();
385 
386  // create zone list
387  surfZoneList newZones(pbm.size());
388 
389  label startFacei = 0;
390  label nZone = 0;
391  for (const polyPatch& p : pbm)
392  {
393  if (p.size())
394  {
395  newZones[nZone] = surfZone
396  (
397  p.name(),
398  p.size(),
399  startFacei,
400  nZone
401  );
402 
403  ++nZone;
404  startFacei += p.size();
405  }
406  }
407 
408  newZones.setSize(nZone);
409 
410  // Get a single patch for all boundaries
411  primitivePatch allBoundary(pbm.faces(), mesh.points());
412 
413  // Face type as per polyBoundaryMesh
414  MeshedSurface<face> surf;
415 
416  if (useGlobalPoints)
417  {
418  // use global points, global face addressing
419  surf = MeshedSurface<face>(mesh.points(), allBoundary, newZones);
420  }
421  else
422  {
423  // use local points, local face addressing
424  surf = MeshedSurface<face>
425  (
426  allBoundary.localPoints(),
427  allBoundary.localFaces(),
428  newZones
429  );
430  }
432  this->transcribe(surf);
433 }
434 
435 
436 template<class Face>
438 (
439  const fileName& name,
440  const word& fileType
441 )
442 :
444 {
445  read(name, fileType);
446 }
447 
448 
449 template<class Face>
451 :
453 {
454  read(name);
455 }
456 
457 
458 template<class Face>
460 :
461  MeshedSurface<Face>()
462 {
463  read(is);
464 }
465 
466 
467 template<class Face>
469 (
470  const Time& runTime
471 )
472 :
473  MeshedSurface<Face>(runTime, word::null)
474 {}
475 
476 
477 template<class Face>
479 (
480  const Time& runTime,
481  const word& surfName
482 )
483 :
484  MeshedSurface<Face>()
485 {
486  surfMesh mesh
487  (
488  IOobject
489  (
490  "dummyName",
491  runTime.timeName(),
492  runTime,
493  IOobjectOption::MUST_READ,
494  IOobjectOption::NO_WRITE,
495  IOobjectOption::NO_REGISTER
496  ),
497  surfName
498  );
499 
500  // The geometry components, returned via autoPtr
502  (
503  std::move(*(mesh.releaseGeom()))
504  );
506  this->transcribe(surf);
507 }
508 
509 
510 template<class Face>
512 (
513  const IOobject& io,
514  const dictionary& dict,
515  const bool isGlobal
516 )
517 :
518  MeshedSurface<Face>()
519 {
520  fileName fName
521  (
522  fileFormats::surfaceFormatsCore::checkFile(io, dict, isGlobal)
523  );
524 
525  this->read(fName, dict.getOrDefault<word>("fileType", word::null));
526 
527  this->scalePoints(dict.getOrDefault<scalar>("scale", 0));
528 }
529 
530 
531 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
532 
533 template<class Face>
535 {
536  clear();
537 }
538 
539 
540 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
541 
542 template<class Face>
544 (
545  const labelUList& faceMapNewToOld
546 )
547 {
548  if (faceMapNewToOld.empty())
549  {
550  return;
551  }
552 
553  surfZoneList& zones = storedZones();
554 
555  if (zones.size() == 1)
556  {
557  // Single zone case is trivial
558  zones[0].size() = faceMapNewToOld.size();
559  return;
560  }
561 
562  // Recalculate the zone start/size
563  label newFacei = 0;
564  label origEndi = 0;
565 
566  for (surfZone& zone : zones)
567  {
568  // Adjust zone start
569  zone.start() = newFacei;
570  origEndi += zone.size();
571 
572  for (label facei = newFacei; facei < faceMapNewToOld.size(); ++facei)
573  {
574  if (faceMapNewToOld[facei] < origEndi)
575  {
576  ++newFacei;
577  }
578  else
579  {
580  break;
581  }
582  }
583 
584  // Adjust zone size
585  zone.size() = newFacei - zone.start();
586  }
587 }
588 
589 
590 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
591 
592 template<class Face>
594 {
595  MeshReference::clearOut(); // Topology changes
596 
597  storedPoints().clear();
598  storedFaces().clear();
599  storedFaceIds().clear();
600  storedZones().clear();
601 }
602 
603 
604 template<class Face>
606 {
607  MeshReference::clearGeom(); // Changes areas, normals etc.
608 
609  // Adapt for new point positions
610  MeshReference::movePoints(newPoints);
612  // Copy new points
613  storedPoints() = newPoints;
614 }
615 
616 
617 template<class Face>
618 void Foam::MeshedSurface<Face>::scalePoints(const scalar scaleFactor)
619 {
620  // Avoid bad or no scaling
621  if (scaleFactor > SMALL && !equal(scaleFactor, 1))
622  {
623  // Remove all geometry dependent data
624  this->clearTopology();
625 
626  // Adapt for new point positions
627  MeshReference::movePoints(pointField());
628 
629  this->storedPoints() *= scaleFactor;
630  }
631 }
632 
633 
634 // Remove badly degenerate faces, double faces.
635 template<class Face>
636 void Foam::MeshedSurface<Face>::cleanup(const bool verbose)
637 {
638  // Merge points (already done for STL, TRI)
639  stitchFaces(SMALL, verbose);
641  checkFaces(verbose);
642  this->checkTopology(verbose);
643 }
644 
645 
646 template<class Face>
648 {
649  this->clearOut(); // Topology changes
650 
651  // Remove unused points while walking and renumbering faces
652  // in visit order - walk order as per localFaces()
653 
654  labelList oldToCompact(this->points().size(), -1);
655  DynamicList<label> compactPointMap(oldToCompact.size());
656 
657  for (auto& f : this->storedFaces())
658  {
659  for (label& pointi : f)
660  {
661  label compacti = oldToCompact[pointi];
662  if (compacti == -1)
663  {
664  compacti = compactPointMap.size();
665  oldToCompact[pointi] = compacti;
666  compactPointMap.append(pointi);
667  }
668  pointi = compacti;
669  }
670  }
671 
672  pointField newPoints
673  (
674  UIndirectList<point>(this->points(), compactPointMap)
675  );
676 
677  this->swapPoints(newPoints);
678 
679  if (notNull(pointMap))
680  {
681  pointMap.transfer(compactPointMap);
682  }
683 }
684 
685 
686 template<class Face>
688 (
689  const scalar tol,
690  const bool verbose
691 )
692 {
693  pointField& ps = this->storedPoints();
694 
695  // Merge points (inplace)
696  labelList pointMap;
697  label nChanged = Foam::inplaceMergePoints(ps, tol, verbose, pointMap);
698 
699  if (!nChanged)
700  {
701  return false;
702  }
703 
704  if (verbose)
705  {
706  InfoInFunction<< "Renumbering all faces" << endl;
707  }
708 
709  List<Face>& faceLst = this->storedFaces();
710 
711  labelList faceMap(faceLst.size(), -1);
712 
713  // Reset the point labels to the unique points array
714  label newFacei = 0;
715  forAll(faceLst, facei)
716  {
717  Face& f = faceLst[facei];
718  for (label& vert : f)
719  {
720  vert = pointMap[vert];
721  }
722 
723  // For extra safety: collapse face as well
724  if (f.collapse() >= 3)
725  {
726  if (newFacei != facei)
727  {
728  faceLst[newFacei] = f;
729  }
730  faceMap[newFacei] = facei;
731  ++newFacei;
732  }
733  else if (verbose)
734  {
735  Pout<< "MeshedSurface::stitchFaces : "
736  << "Removing collapsed face " << facei << endl
737  << " vertices :" << f << endl;
738  }
739  }
740  pointMap.clear();
741 
742  if (newFacei != faceLst.size())
743  {
744  if (verbose)
745  {
746  Pout<< "MeshedSurface::stitchFaces : "
747  << "Removed " << faceLst.size() - newFacei
748  << " faces" << endl;
749  }
750  faceMap.resize(newFacei);
751  faceLst.resize(newFacei);
752 
753  // The faceMap is a newToOld mapping and only removes elements
754  if (faceIds_.size())
755  {
756  forAll(faceMap, facei)
757  {
758  faceIds_[facei] = faceIds_[faceMap[facei]];
759  }
760 
761  faceIds_.resize(newFacei);
762  }
763 
764  remapFaces(faceMap);
765  }
766  faceMap.clear();
767 
768  // Topology can change when points are merged, etc
769  MeshReference::clearOut();
770 
771  return true;
772 }
773 
774 
775 // Remove badly degenerate faces and double faces.
776 template<class Face>
778 (
779  const bool verbose
780 )
781 {
782  bool changed = false;
783  List<Face>& faceLst = this->storedFaces();
784 
785  labelList faceMap(faceLst.size());
786 
787  label newFacei = 0;
788  const label maxPointi = this->points().size();
789 
790  // Detect badly labelled faces and mark degenerate faces
791  forAll(faceLst, facei)
792  {
793  Face& f = faceLst[facei];
794 
795  // Avoid degenerate faces
796  if (f.collapse() >= 3)
797  {
798  for (const label vert : f)
799  {
800  if (vert < 0 || vert >= maxPointi)
801  {
803  << "face " << f
804  << " uses point indices outside point range 0.."
805  << (maxPointi-1)
806  << exit(FatalError);
807  }
808  }
809 
810  faceMap[facei] = facei;
811  ++newFacei;
812  }
813  else
814  {
815  // Mark as bad face
816  faceMap[facei] = -1;
817 
818  changed = true;
819  if (verbose)
820  {
822  << "face[" << facei << "] = " << f
823  << " does not have three unique vertices" << endl;
824  }
825  }
826  }
827 
828  // Detect doubled faces
829  // do not touch the faces
830  const labelListList& fFaces = this->faceFaces();
831  newFacei = 0;
832  forAll(faceLst, facei)
833  {
834  // Skip already collapsed faces
835  if (faceMap[facei] < 0)
836  {
837  continue;
838  }
839 
840  const Face& f = faceLst[facei];
841 
842  // Duplicate face check
843  bool okay = true;
844  const labelList& neighbours = fFaces[facei];
845 
846  // Check if faceNeighbours use same points as this face.
847  // Note: discards normal information - sides of baffle are merged.
848  for (const label neiFacei : neighbours)
849  {
850  if (neiFacei <= facei || faceMap[neiFacei] < 0)
851  {
852  // lower numbered faces already checked
853  // skip neighbours that are themselves collapsed
854  continue;
855  }
856 
857  const Face& nei = faceLst[neiFacei];
858 
859  if (f == nei)
860  {
861  okay = false;
862 
863  if (verbose)
864  {
866  << "faces share the same vertices:" << nl
867  << " face[" << facei << "] : " << f << nl
868  << " face[" << neiFacei << "] : " << nei << endl;
869  // printFace(Warning, " ", f, points());
870  // printFace(Warning, " ", nei, points());
871  }
872 
873  break;
874  }
875  }
876 
877  if (okay)
878  {
879  faceMap[facei] = facei;
880  ++newFacei;
881  }
882  else
883  {
884  faceMap[facei] = -1;
885  }
886  }
887 
888 
889  // Until now, faceMap is an identity for good faces and -1 for bad faces
890 
891  // Phase 1: pack
892  // Done to keep numbering constant in phase 1
893 
894  if (changed || newFacei < faceLst.size())
895  {
896  changed = true;
897 
898  if (verbose)
899  {
901  << "Removed " << faceLst.size() - newFacei
902  << " illegal faces." << endl;
903  }
904 
905  // Compress the face list
906  newFacei = 0;
907  forAll(faceLst, facei)
908  {
909  if (faceMap[facei] >= 0)
910  {
911  if (newFacei != facei)
912  {
913  faceLst[newFacei] = std::move(faceLst[facei]);
914  }
915  faceMap[newFacei] = facei;
916  ++newFacei;
917  }
918  }
919 
920  faceMap.resize(newFacei);
921  faceLst.resize(newFacei);
922 
923  // The faceMap is a newToOld mapping and only removes elements
924  if (faceIds_.size())
925  {
926  forAll(faceMap, facei)
927  {
928  faceIds_[facei] = faceIds_[faceMap[facei]];
929  }
930 
931  faceIds_.resize(newFacei);
932  }
933 
934  remapFaces(faceMap);
935  }
936  faceMap.clear();
937 
938  // Topology can change because of renumbering
939  MeshReference::clearOut();
940  return changed;
941 }
942 
943 
944 template<class Face>
945 Foam::label Foam::MeshedSurface<Face>::nTriangles() const
946 {
947  if constexpr (faceTraits<Face>::isTri())
948  {
949  return MeshReference::size();
950  }
951  else
952  {
953  return nTriangles
954  (
955  const_cast<labelList&>(labelList::null())
956  );
957  }
958 }
959 
960 
961 template<class Face>
963 (
965 ) const
966 {
967  label nTri = 0;
968  const List<Face>& faceLst = surfFaces();
969 
970  // Count triangles needed
971  for (const auto& f : faceLst)
972  {
973  nTri += f.nTriangles();
974  }
975 
976  // Nothing to do
977  if (nTri <= faceLst.size())
978  {
979  if (notNull(faceMap))
980  {
981  faceMap.clear();
982  }
983  }
984  else if (notNull(faceMap))
985  {
986  // Face map requested
987  faceMap.resize(nTri);
988 
989  nTri = 0;
990  forAll(faceLst, facei)
991  {
992  label n = faceLst[facei].nTriangles();
993  while (n-- > 0)
994  {
995  faceMap[nTri++] = facei;
996  }
997  }
998 
999  faceMap.resize(nTri);
1000  }
1001 
1002  return nTri;
1003 }
1004 
1005 
1006 template<class Face>
1008 {
1009  if constexpr (faceTraits<Face>::isTri())
1010  {
1011  // Inplace triangulation of triFace/labelledTri surface = no-op
1012  return 0;
1013  }
1014  else
1015  {
1016  return triangulate
1017  (
1018  const_cast<labelList&>(labelList::null())
1019  );
1020  }
1021 }
1022 
1023 
1024 template<class Face>
1026 (
1027  labelList& faceMapOut
1028 )
1029 {
1030  labelList dummyFaceMap;
1031 
1032  labelList& faceMap =
1033  (
1034  notNull(faceMapOut)
1035  ? faceMapOut
1036  : dummyFaceMap
1037  );
1038 
1039  if (faceTraits<Face>::isTri())
1040  {
1041  // Inplace triangulation of triFace/labelledTri surface = no-op
1042  faceMap.clear();
1043  return 0;
1044  }
1045 
1046  label nTri = 0;
1047  label maxTri = 0; // the maximum number of triangles for any single face
1048  List<Face>& faceLst = this->storedFaces();
1049 
1050  // How many triangles will be needed
1051  for (const auto& f : faceLst)
1052  {
1053  const label n = f.nTriangles();
1054  if (maxTri < n)
1055  {
1056  maxTri = n;
1057  }
1058  nTri += n;
1059  }
1060 
1061  // Nothing to do
1062  if (nTri <= faceLst.size())
1063  {
1064  faceMap.clear();
1065  return 0;
1066  }
1067 
1068  this->storedFaceIds().clear(); // Invalid or misleading
1069 
1070  List<Face> newFaces(nTri);
1071  faceMap.resize(nTri);
1072 
1073  if (this->points().empty())
1074  {
1075  // triangulate without points
1076  // simple face triangulation around f[0]
1077  nTri = 0;
1078  forAll(faceLst, facei)
1079  {
1080  const Face& f = faceLst[facei];
1081 
1082  for (label fp = 1; fp < f.size() - 1; ++fp)
1083  {
1084  const label fp1 = f.fcIndex(fp);
1085 
1086  newFaces[nTri] = Face{f[0], f[fp], f[fp1]};
1087  faceMap[nTri] = facei;
1088  ++nTri;
1089  }
1090  }
1091  }
1092  else
1093  {
1094  // triangulate with points
1095  List<face> tmpTri(maxTri);
1096 
1097  nTri = 0;
1098  forAll(faceLst, facei)
1099  {
1100  // 'face' not '<Face>'
1101  const face& f = faceLst[facei];
1102 
1103  label nTmp = 0;
1104  f.triangles(this->points(), nTmp, tmpTri);
1105  for (label triI = 0; triI < nTmp; triI++)
1106  {
1107  newFaces[nTri] = Face
1108  (
1109  static_cast<labelUList&>(tmpTri[triI])
1110  );
1111  faceMap[nTri] = facei;
1112  ++nTri;
1113  }
1114  }
1115  }
1116 
1117  // The number of *additional* faces
1118  nTri -= faceLst.size();
1119 
1120  faceLst.transfer(newFaces);
1121  remapFaces(faceMap);
1122 
1123  // Topology can change because of renumbering
1124  MeshReference::clearOut();
1125 
1126  return nTri;
1127 }
1128 
1129 
1130 template<class Face>
1133 (
1134  const labelList& pointMap,
1135  const labelList& faceMap
1136 ) const
1137 {
1138  const pointField& locPoints = this->localPoints();
1139  const List<Face>& locFaces = this->localFaces();
1140 
1141  // Subset of points (compact)
1142  pointField newPoints(UIndirectList<point>(locPoints, pointMap));
1143 
1144  // Inverse point mapping - same as ListOps invert() without checks
1145  labelList oldToNew(locPoints.size(), -1);
1146  forAll(pointMap, pointi)
1147  {
1148  oldToNew[pointMap[pointi]] = pointi;
1149  }
1150 
1151  // Subset of faces
1152  List<Face> newFaces(UIndirectList<Face>(locFaces, faceMap));
1153 
1154  // Renumber face node labels
1155  for (auto& f : newFaces)
1156  {
1157  for (label& vert : f)
1158  {
1159  vert = oldToNew[vert];
1160  }
1161  }
1162  oldToNew.clear();
1163 
1164  // Deep copy of zones, leave start/size intact!!
1165  surfZoneList newZones(zones_);
1166 
1167  // Recalculate the zone start/size
1168  label newFacei = 0;
1169  label origEndi = 0;
1170 
1171  for (surfZone& zone : newZones)
1172  {
1173  // The old zone ending
1174  origEndi += zone.size();
1175 
1176  // The new zone start
1177  zone.start() = newFacei;
1178 
1179  for (label facei = newFacei; facei < faceMap.size(); ++facei)
1180  {
1181  if (faceMap[facei] < origEndi)
1182  {
1183  ++newFacei;
1184  }
1185  else
1186  {
1187  break;
1188  }
1189  }
1190 
1191  // The new zone size
1192  zone.size() = newFacei - zone.start();
1193  }
1194 
1195 
1196  // Subset of faceIds. Can be empty.
1197  labelList newFaceIds;
1198  if (faceIds_.size())
1199  {
1200  newFaceIds = labelUIndList(faceIds_, faceMap);
1201  }
1202 
1203  // Construct the sub-surface
1204  MeshedSurface<Face> newSurf;
1205  newSurf.storedFaces().transfer(newFaces);
1206  newSurf.storedPoints().transfer(newPoints);
1207  newSurf.storedZones().transfer(newZones);
1208  newSurf.storedFaceIds().transfer(newFaceIds);
1209 
1210  return newSurf;
1211 }
1212 
1213 
1214 template<class Face>
1217 (
1218  const UList<bool>& include,
1219  labelList& pointMap,
1221 ) const
1222 {
1223  this->subsetMeshMap(include, pointMap, faceMap);
1224  return this->subsetMeshImpl(pointMap, faceMap);
1225 }
1226 
1227 
1228 template<class Face>
1231 (
1232  const bitSet& include,
1233  labelList& pointMap,
1235 ) const
1236 {
1237  this->subsetMeshMap(include, pointMap, faceMap);
1238  return this->subsetMeshImpl(pointMap, faceMap);
1239 }
1240 
1241 
1242 template<class Face>
1245 (
1246  const UList<bool>& include
1247 ) const
1248 {
1249  labelList pointMap, faceMap;
1250  return this->subsetMesh(include, pointMap, faceMap);
1251 }
1252 
1253 
1254 template<class Face>
1257 (
1258  const bitSet& include
1259 ) const
1260 {
1261  labelList pointMap, faceMap;
1262  return this->subsetMesh(include, pointMap, faceMap);
1263 }
1264 
1265 
1266 template<class Face>
1268 (
1269  const wordRes& includeNames,
1270  const wordRes& excludeNames
1271 ) const
1272 {
1273  bitSet include(this->size());
1274 
1275  for
1276  (
1277  const label zonei
1278  : fileFormats::surfaceFormatsCore::getSelectedPatches
1279  (
1280  zones_,
1281  includeNames,
1282  excludeNames
1283  )
1284  )
1285  {
1286  include.set(zones_[zonei].range());
1287  }
1289  return this->subsetMesh(include);
1290 }
1291 
1292 
1293 template<class Face>
1295 (
1296  MeshedSurface<Face>& surf
1297 )
1298 {
1299  if (this == &surf)
1300  {
1301  return; // Self-swap is a no-op
1302  }
1303 
1304  MeshReference::clearOut(); // Topology changes
1305  surf.clearOut(); // Topology changes
1306 
1307  this->storedPoints().swap(surf.storedPoints());
1308  this->storedFaces().swap(surf.storedFaces());
1309  this->storedZones().swap(surf.storedZones());
1310  this->storedFaceIds().swap(surf.storedFaceIds());
1311 }
1312 
1313 
1314 template<class Face>
1316 (
1317  pointField& pointLst,
1318  List<Face>& faceLst
1319 )
1320 {
1321  MeshReference::clearOut(); // Topology changes
1322 
1323  this->storedPoints().transfer(pointLst);
1324  this->storedFaces().transfer(faceLst);
1325  this->storedZones().clear();
1326  this->storedFaceIds().clear(); // Likely to be invalid
1327 }
1328 
1329 
1330 template<class Face>
1332 (
1333  MeshedSurface<Face>& surf
1334 )
1335 {
1336  if (this == &surf)
1337  {
1338  return; // Self-assigment is a no-op
1339  }
1340 
1341  MeshReference::clearOut(); // Topology changes
1342 
1343  this->storedPoints().transfer(surf.storedPoints());
1344  this->storedFaces().transfer(surf.storedFaces());
1345  this->storedZones().transfer(surf.storedZones());
1346  this->storedFaceIds().transfer(surf.storedFaceIds());
1348  surf.clear();
1349 }
1350 
1351 
1352 template<class Face>
1354 (
1356 )
1357 {
1358  // Clear everything
1359  this->clear();
1360 
1362  surfZoneList zoneLst = surf.sortedZones(faceMap);
1363 
1364  List<Face>& faceLst = surf.storedFaces();
1365 
1366  if (zoneLst.size() > 1)
1367  {
1368  // Unknown if we really need to sort the faces
1369  List<Face> sortedFaces(faceMap.size());
1370 
1371  forAll(faceMap, facei)
1372  {
1373  sortedFaces[faceMap[facei]].transfer(faceLst[facei]);
1374  }
1375 
1376  faceLst.swap(sortedFaces); // Replace with sorted faces
1377  }
1378 
1379  MeshedSurface<Face> newSurf
1380  (
1381  std::move(surf.storedPoints()),
1382  std::move(faceLst),
1383  zoneLst
1384  );
1385 
1386  surf.clear();
1388  this->swap(newSurf);
1389 }
1390 
1391 
1392 template<class Face>
1395 {
1396  return autoPtr<MeshedSurface<Face>>::New(std::move(*this));
1397 }
1398 
1399 
1400 template<class Face>
1402 {
1403  MeshReference::clearOut(); // Topology changes
1404 
1405  this->storedFaceIds().clear(); // Likely to be invalid
1406 
1407  this->storedFaces().swap(faces);
1408 
1409  this->checkZones(false); // Non-verbose fix zones
1410 }
1411 
1412 
1413 template<class Face>
1415 {
1416  // Adapt for new point positions
1417  MeshReference::movePoints(points);
1418 
1419  this->storedPoints().swap(points);
1420 }
1421 
1422 
1423 template<class Face>
1425 {
1426  this->clear();
1427  transfer(*New(name));
1428  return true;
1429 }
1430 
1431 
1432 template<class Face>
1434 (
1435  const fileName& name,
1436  const word& fileType
1437 )
1438 {
1439  this->clear();
1440  transfer(*New(name, fileType));
1441  return true;
1442 }
1443 
1444 
1445 template<class Face>
1447 (
1448  const Time& t,
1449  const word& surfName
1450 ) const
1451 {
1452  MeshedSurfaceProxy<Face>(*this).write(t, surfName);
1453 }
1454 
1455 
1456 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
1457 
1458 template<class Face>
1460 {
1461  if (this == &surf)
1462  {
1463  return; // Self-assignment is a no-op
1464  }
1465 
1466  // Clear everything
1467  this->clear();
1468 
1469  this->storedPoints() = surf.points();
1470  this->storedFaces() = surf.surfFaces();
1471  this->storedFaceIds() = surf.faceIds();
1472  this->storedZones() = surf.surfZones();
1473 }
1474 
1475 
1476 template<class Face>
1478 {
1479  transfer(surf);
1480 }
1481 
1482 
1483 template<class Face>
1485 {
1486  return MeshedSurfaceProxy<Face>
1487  (
1488  this->points(),
1489  this->surfFaces(),
1490  this->surfZones(),
1491  labelUList::null(), // faceMap = none
1492  this->faceIds()
1493  );
1494 }
1495 
1496 
1497 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1498 
1499 #include "MeshedSurfaceZones.C"
1500 #include "MeshedSurfaceIO.C"
1501 #include "MeshedSurfaceNew.C"
1502 
1503 // ************************************************************************* //
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:517
const polyBoundaryMesh & pbm
dictionary dict
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:119
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:502
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:153
void transfer(List< T > &list)
Transfer the contents of the argument List into this list and annul the argument list.
Definition: List.C:347
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:130
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:652
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:702
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:518
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:68
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:76
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:400
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.
void swapPoints(pointField &points)
Swap the stored points.
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
const pointField & points
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.
void swap(MeshedSurface< Face > &surf)
Swap contents.
pointField & storedPoints()
Non-const access to global points.
const auto & io
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.
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 registered IO, a reference to the associated polyMesh...
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:62
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)
auto & name
PrimitivePatch< SubList< face >, const pointField & > primitivePatch
A PrimitivePatch with a SubList addressing for the faces, const reference for the point field...
surfZoneList sortedZones(labelList &faceMap) const
Sort faces according to zoneIds.
virtual label nTriangles() const
Count number of triangles.
Traits class for faces.
Definition: faceTraits.H:44
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:58
#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)
bool notNull(const T *ptr) noexcept
True if ptr is not a pointer (of type T) to the nullObject.
Definition: nullObject.H:267
surface1 clear()
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:200
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:76
List< label > labelList
A List of labels.
Definition: List.H:61
volScalarField & p
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
void write(vtk::formatter &fmt, const Type &val, const label n=1)
Component-wise write of a value (N times)
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:188
bool equal(const UList< Type1 > &a, const UList< Type2 > &b)
Test for list equality with different but compatible data types. Eg, int32 and int64.
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
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:217
#define InfoInFunction
Report an information message using Foam::Info.