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 {
948  {
949  return MeshReference::size();
950  }
951 
952  return nTriangles
953  (
954  const_cast<labelList&>(labelList::null())
955  );
956 }
957 
958 
959 template<class Face>
961 (
963 ) const
964 {
965  label nTri = 0;
966  const List<Face>& faceLst = surfFaces();
967 
968  // Count triangles needed
969  for (const auto& f : faceLst)
970  {
971  nTri += f.nTriangles();
972  }
973 
974  // Nothing to do
975  if (nTri <= faceLst.size())
976  {
977  if (notNull(faceMap))
978  {
979  faceMap.clear();
980  }
981  }
982  else if (notNull(faceMap))
983  {
984  // Face map requested
985  faceMap.resize(nTri);
986 
987  nTri = 0;
988  forAll(faceLst, facei)
989  {
990  label n = faceLst[facei].nTriangles();
991  while (n-- > 0)
992  {
993  faceMap[nTri++] = facei;
994  }
995  }
996 
997  faceMap.resize(nTri);
998  }
999 
1000  return nTri;
1001 }
1002 
1003 
1004 template<class Face>
1006 {
1007  if (faceTraits<Face>::isTri())
1008  {
1009  // Inplace triangulation of triFace/labelledTri surface = no-op
1010  return 0;
1011  }
1012  else
1013  {
1014  return triangulate
1015  (
1016  const_cast<labelList&>(labelList::null())
1017  );
1018  }
1019 }
1020 
1021 
1022 template<class Face>
1024 (
1025  labelList& faceMapOut
1026 )
1027 {
1028  labelList dummyFaceMap;
1029 
1030  labelList& faceMap =
1031  (
1032  notNull(faceMapOut)
1033  ? faceMapOut
1034  : dummyFaceMap
1035  );
1036 
1037  if (faceTraits<Face>::isTri())
1038  {
1039  // Inplace triangulation of triFace/labelledTri surface = no-op
1040  faceMap.clear();
1041  return 0;
1042  }
1043 
1044  label nTri = 0;
1045  label maxTri = 0; // the maximum number of triangles for any single face
1046  List<Face>& faceLst = this->storedFaces();
1047 
1048  // How many triangles will be needed
1049  for (const auto& f : faceLst)
1050  {
1051  const label n = f.nTriangles();
1052  if (maxTri < n)
1053  {
1054  maxTri = n;
1055  }
1056  nTri += n;
1057  }
1058 
1059  // Nothing to do
1060  if (nTri <= faceLst.size())
1061  {
1062  faceMap.clear();
1063  return 0;
1064  }
1065 
1066  this->storedFaceIds().clear(); // Invalid or misleading
1067 
1068  List<Face> newFaces(nTri);
1069  faceMap.resize(nTri);
1070 
1071  if (this->points().empty())
1072  {
1073  // triangulate without points
1074  // simple face triangulation around f[0]
1075  nTri = 0;
1076  forAll(faceLst, facei)
1077  {
1078  const Face& f = faceLst[facei];
1079 
1080  for (label fp = 1; fp < f.size() - 1; ++fp)
1081  {
1082  const label fp1 = f.fcIndex(fp);
1083 
1084  newFaces[nTri] = Face{f[0], f[fp], f[fp1]};
1085  faceMap[nTri] = facei;
1086  ++nTri;
1087  }
1088  }
1089  }
1090  else
1091  {
1092  // triangulate with points
1093  List<face> tmpTri(maxTri);
1094 
1095  nTri = 0;
1096  forAll(faceLst, facei)
1097  {
1098  // 'face' not '<Face>'
1099  const face& f = faceLst[facei];
1100 
1101  label nTmp = 0;
1102  f.triangles(this->points(), nTmp, tmpTri);
1103  for (label triI = 0; triI < nTmp; triI++)
1104  {
1105  newFaces[nTri] = Face
1106  (
1107  static_cast<labelUList&>(tmpTri[triI])
1108  );
1109  faceMap[nTri] = facei;
1110  ++nTri;
1111  }
1112  }
1113  }
1114 
1115  // The number of *additional* faces
1116  nTri -= faceLst.size();
1117 
1118  faceLst.transfer(newFaces);
1119  remapFaces(faceMap);
1120 
1121  // Topology can change because of renumbering
1122  MeshReference::clearOut();
1123 
1124  return nTri;
1125 }
1126 
1127 
1128 template<class Face>
1131 (
1132  const labelList& pointMap,
1133  const labelList& faceMap
1134 ) const
1135 {
1136  const pointField& locPoints = this->localPoints();
1137  const List<Face>& locFaces = this->localFaces();
1138 
1139  // Subset of points (compact)
1140  pointField newPoints(UIndirectList<point>(locPoints, pointMap));
1141 
1142  // Inverse point mapping - same as ListOps invert() without checks
1143  labelList oldToNew(locPoints.size(), -1);
1144  forAll(pointMap, pointi)
1145  {
1146  oldToNew[pointMap[pointi]] = pointi;
1147  }
1148 
1149  // Subset of faces
1150  List<Face> newFaces(UIndirectList<Face>(locFaces, faceMap));
1151 
1152  // Renumber face node labels
1153  for (auto& f : newFaces)
1154  {
1155  for (label& vert : f)
1156  {
1157  vert = oldToNew[vert];
1158  }
1159  }
1160  oldToNew.clear();
1161 
1162  // Deep copy of zones, leave start/size intact!!
1163  surfZoneList newZones(zones_);
1164 
1165  // Recalculate the zone start/size
1166  label newFacei = 0;
1167  label origEndi = 0;
1168 
1169  for (surfZone& zone : newZones)
1170  {
1171  // The old zone ending
1172  origEndi += zone.size();
1173 
1174  // The new zone start
1175  zone.start() = newFacei;
1176 
1177  for (label facei = newFacei; facei < faceMap.size(); ++facei)
1178  {
1179  if (faceMap[facei] < origEndi)
1180  {
1181  ++newFacei;
1182  }
1183  else
1184  {
1185  break;
1186  }
1187  }
1188 
1189  // The new zone size
1190  zone.size() = newFacei - zone.start();
1191  }
1192 
1193 
1194  // Subset of faceIds. Can be empty.
1195  labelList newFaceIds;
1196  if (faceIds_.size())
1197  {
1198  newFaceIds = labelUIndList(faceIds_, faceMap);
1199  }
1200 
1201  // Construct the sub-surface
1202  MeshedSurface<Face> newSurf;
1203  newSurf.storedFaces().transfer(newFaces);
1204  newSurf.storedPoints().transfer(newPoints);
1205  newSurf.storedZones().transfer(newZones);
1206  newSurf.storedFaceIds().transfer(newFaceIds);
1207 
1208  return newSurf;
1209 }
1210 
1211 
1212 template<class Face>
1215 (
1216  const UList<bool>& include,
1217  labelList& pointMap,
1219 ) const
1220 {
1221  this->subsetMeshMap(include, pointMap, faceMap);
1222  return this->subsetMeshImpl(pointMap, faceMap);
1223 }
1224 
1225 
1226 template<class Face>
1229 (
1230  const bitSet& include,
1231  labelList& pointMap,
1233 ) const
1234 {
1235  this->subsetMeshMap(include, pointMap, faceMap);
1236  return this->subsetMeshImpl(pointMap, faceMap);
1237 }
1238 
1239 
1240 template<class Face>
1243 (
1244  const UList<bool>& include
1245 ) const
1246 {
1247  labelList pointMap, faceMap;
1248  return this->subsetMesh(include, pointMap, faceMap);
1249 }
1250 
1251 
1252 template<class Face>
1255 (
1256  const bitSet& include
1257 ) const
1258 {
1259  labelList pointMap, faceMap;
1260  return this->subsetMesh(include, pointMap, faceMap);
1261 }
1262 
1263 
1264 template<class Face>
1266 (
1267  const wordRes& includeNames,
1268  const wordRes& excludeNames
1269 ) const
1270 {
1271  bitSet include(this->size());
1272 
1273  for
1274  (
1275  const label zonei
1276  : fileFormats::surfaceFormatsCore::getSelectedPatches
1277  (
1278  zones_,
1279  includeNames,
1280  excludeNames
1281  )
1282  )
1283  {
1284  include.set(zones_[zonei].range());
1285  }
1287  return this->subsetMesh(include);
1288 }
1289 
1290 
1291 template<class Face>
1293 (
1294  MeshedSurface<Face>& surf
1295 )
1296 {
1297  if (this == &surf)
1298  {
1299  return; // Self-swap is a no-op
1300  }
1301 
1302  MeshReference::clearOut(); // Topology changes
1303  surf.clearOut(); // Topology changes
1304 
1305  this->storedPoints().swap(surf.storedPoints());
1306  this->storedFaces().swap(surf.storedFaces());
1307  this->storedZones().swap(surf.storedZones());
1308  this->storedFaceIds().swap(surf.storedFaceIds());
1309 }
1310 
1311 
1312 template<class Face>
1314 (
1315  pointField& pointLst,
1316  List<Face>& faceLst
1317 )
1318 {
1319  MeshReference::clearOut(); // Topology changes
1320 
1321  this->storedPoints().transfer(pointLst);
1322  this->storedFaces().transfer(faceLst);
1323  this->storedZones().clear();
1324  this->storedFaceIds().clear(); // Likely to be invalid
1325 }
1326 
1327 
1328 template<class Face>
1330 (
1331  MeshedSurface<Face>& surf
1332 )
1333 {
1334  if (this == &surf)
1335  {
1336  return; // Self-assigment is a no-op
1337  }
1338 
1339  MeshReference::clearOut(); // Topology changes
1340 
1341  this->storedPoints().transfer(surf.storedPoints());
1342  this->storedFaces().transfer(surf.storedFaces());
1343  this->storedZones().transfer(surf.storedZones());
1344  this->storedFaceIds().transfer(surf.storedFaceIds());
1346  surf.clear();
1347 }
1348 
1349 
1350 template<class Face>
1352 (
1354 )
1355 {
1356  // Clear everything
1357  this->clear();
1358 
1360  surfZoneList zoneLst = surf.sortedZones(faceMap);
1361 
1362  List<Face>& faceLst = surf.storedFaces();
1363 
1364  if (zoneLst.size() > 1)
1365  {
1366  // Unknown if we really need to sort the faces
1367  List<Face> sortedFaces(faceMap.size());
1368 
1369  forAll(faceMap, facei)
1370  {
1371  sortedFaces[faceMap[facei]].transfer(faceLst[facei]);
1372  }
1373 
1374  faceLst.swap(sortedFaces); // Replace with sorted faces
1375  }
1376 
1377  MeshedSurface<Face> newSurf
1378  (
1379  std::move(surf.storedPoints()),
1380  std::move(faceLst),
1381  zoneLst
1382  );
1383 
1384  surf.clear();
1386  this->swap(newSurf);
1387 }
1388 
1389 
1390 template<class Face>
1393 {
1394  return autoPtr<MeshedSurface<Face>>::New(std::move(*this));
1395 }
1396 
1397 
1398 template<class Face>
1400 {
1401  MeshReference::clearOut(); // Topology changes
1402 
1403  this->storedFaceIds().clear(); // Likely to be invalid
1404 
1405  this->storedFaces().swap(faces);
1406 
1407  this->checkZones(false); // Non-verbose fix zones
1408 }
1409 
1410 
1411 template<class Face>
1413 {
1414  // Adapt for new point positions
1415  MeshReference::movePoints(points);
1416 
1417  this->storedPoints().swap(points);
1418 }
1419 
1420 
1421 template<class Face>
1423 {
1424  this->clear();
1425  transfer(*New(name));
1426  return true;
1427 }
1428 
1429 
1430 template<class Face>
1432 (
1433  const fileName& name,
1434  const word& fileType
1435 )
1436 {
1437  this->clear();
1438  transfer(*New(name, fileType));
1439  return true;
1440 }
1441 
1442 
1443 template<class Face>
1445 (
1446  const Time& t,
1447  const word& surfName
1448 ) const
1449 {
1450  MeshedSurfaceProxy<Face>(*this).write(t, surfName);
1451 }
1452 
1453 
1454 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
1455 
1456 template<class Face>
1458 {
1459  if (this == &surf)
1460  {
1461  return; // Self-assignment is a no-op
1462  }
1463 
1464  // Clear everything
1465  this->clear();
1466 
1467  this->storedPoints() = surf.points();
1468  this->storedFaces() = surf.surfFaces();
1469  this->storedFaceIds() = surf.faceIds();
1470  this->storedZones() = surf.surfZones();
1471 }
1472 
1473 
1474 template<class Face>
1476 {
1477  transfer(surf);
1478 }
1479 
1480 
1481 template<class Face>
1483 {
1484  return MeshedSurfaceProxy<Face>
1485  (
1486  this->points(),
1487  this->surfFaces(),
1488  this->surfZones(),
1489  labelUList::null(), // faceMap = none
1490  this->faceIds()
1491  );
1492 }
1493 
1494 
1495 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1496 
1497 #include "MeshedSurfaceZones.C"
1498 #include "MeshedSurfaceIO.C"
1499 #include "MeshedSurfaceNew.C"
1500 
1501 // ************************************************************************* //
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:499
const polyBoundaryMesh & pbm
dictionary dict
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
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:498
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:150
void transfer(List< T > &list)
Transfer the contents of the argument List into this list and annul the argument list.
Definition: List.C:337
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:600
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:697
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:529
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
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:286
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)
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.
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.
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)
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.
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)
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: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:75
List< label > labelList
A List of labels.
Definition: List.H:61
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:180
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:225
#define InfoInFunction
Report an information message using Foam::Info.