surfaceAdd.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-2023 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 Application
28  surfaceAdd
29 
30 Group
31  grpSurfaceUtilities
32 
33 Description
34  Add two surfaces. Does geometric merge on points.
35  Does not check for overlapping/intersecting triangles.
36 
37  Keeps patches separate by renumbering.
38 
39 \*---------------------------------------------------------------------------*/
40 
41 #include "argList.H"
42 #include "fileName.H"
43 #include "triSurface.H"
44 #include "Fstream.H"
45 #include "triFace.H"
46 #include "triFaceList.H"
47 
48 using namespace Foam;
49 
50 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
51 
52 
53 int main(int argc, char *argv[])
54 {
56  (
57  "Add two surfaces via a geometric merge on points."
58  " Does not check for overlapping/intersecting triangles."
59  );
60 
62  argList::addArgument("surface1", "The input surface file 1");
63  argList::addArgument("surface2", "The input surface file 2");
64  argList::addArgument("output", "The output surface file");
65 
67  (
68  "points",
69  "file",
70  "Provide additional points"
71  );
73  (
74  "mergeRegions",
75  "Combine regions from both surfaces"
76  );
78  (
79  "scale",
80  "factor",
81  "Geometry scaling factor on input surfaces"
82  );
84 
85  argList args(argc, argv);
86 
87  const auto inFileName1 = args.get<fileName>(1);
88  const auto inFileName2 = args.get<fileName>(2);
89  const auto outFileName = args.get<fileName>(3);
90 
91  const int optVerbose = args.verbose();
92  const bool addPoint = args.found("points");
93  const bool mergeRegions = args.found("mergeRegions");
94 
95  const scalar scaleFactor = args.getOrDefault<scalar>("scale", -1);
96 
97  if (addPoint)
98  {
99  Info<< "Reading a surface and adding points from a file"
100  << "; merging the points and writing the surface to another file"
101  << nl << endl;
102 
103  Info<< "Surface : " << inFileName1<< nl
104  << "Points : " << args.get<fileName>("points") << nl
105  << "Writing : " << outFileName << nl << endl;
106  }
107  else
108  {
109  Info<< "Reading two surfaces"
110  << "; merging points and writing the surface to another file"
111  << nl << endl;
112 
113  if (mergeRegions)
114  {
115  Info<< "Regions from the two files will get merged" << nl
116  << "Do not use this option if you want to keep the regions"
117  << " separate" << nl << endl;
118  }
119  else
120  {
121  Info<< "Regions from the two files will not get merged" << nl
122  << "Regions from " << inFileName2 << " will get offset so"
123  << " as not to overlap with the regions in " << inFileName1
124  << nl << endl;
125  }
126 
127 
128  Info<< "Surface1 : " << inFileName1<< nl
129  << "Surface2 : " << inFileName2<< nl
130  << "Writing : " << outFileName << nl << endl;
131  }
132 
133  if (scaleFactor > 0)
134  {
135  Info<< "Scaling : " << scaleFactor << nl;
136  }
137 
138  const triSurface surface1(inFileName1, scaleFactor);
139  Info<< "Surface1:" << endl;
140  surface1.writeStats(Info);
141  Info<< endl;
142 
143  const pointField& points1 = surface1.points();
144 
145  // Final surface
146  triSurface combinedSurf;
147 
148  if (addPoint)
149  {
150  IFstream pointsFile(args.get<fileName>("points"));
151  const pointField extraPoints(pointsFile);
152 
153  Info<< "Additional Points:" << extraPoints.size() << endl;
154 
155  vectorField pointsAll(points1);
156  label pointi = pointsAll.size();
157  pointsAll.setSize(pointsAll.size() + extraPoints.size());
158 
159  for (const auto& pt : extraPoints)
160  {
161  pointsAll[pointi++] = pt;
162  }
163 
164  combinedSurf = triSurface(surface1, surface1.patches(), pointsAll);
165  }
166  else
167  {
168  const triSurface surface2(inFileName2, scaleFactor);
169  Info<< "Surface2:" << endl;
170  surface2.writeStats(Info);
171  Info<< endl;
172 
173 
174  // Make new storage
175  List<labelledTri> facesAll(surface1.size() + surface2.size());
176 
177  const pointField& points2 = surface2.points();
178 
179  vectorField pointsAll(points1.size() + points2.size());
180 
181 
182  label pointi = 0;
183  // Copy points1 into pointsAll
184  for (const auto& pt : points1)
185  {
186  pointsAll[pointi++] = pt;
187  }
188  // Add surface2 points
189  for (const auto& pt : points2)
190  {
191  pointsAll[pointi++] = pt;
192  }
193 
194 
195  label trianglei = 0;
196 
197  // Determine map for both regions
198  label nNewPatches = 0;
199  labelList patch1Map(surface1.patches().size());
200  labelList patch2Map(surface2.patches().size());
201 
202  if (mergeRegions)
203  {
204  HashTable<label> nameToPatch;
205 
206  forAll(surface1.patches(), i)
207  {
208  const word& name = surface1.patches()[i].name();
209 
210  // Lookup or insert
211  const label combinedi = nameToPatch(name, nameToPatch.size());
212 
213  patch1Map[i] = combinedi;
214  }
215 
216  // Determine map for surface2 regions
217 
218  forAll(surface2.patches(), i)
219  {
220  const word& name = surface2.patches()[i].name();
221 
222  // Lookup or insert
223  const label combinedi = nameToPatch(name, nameToPatch.size());
224 
225  patch2Map[i] = combinedi;
226  }
227 
228  nNewPatches = nameToPatch.size();
229  }
230  else
231  {
232  Info<< "Surface " << inFileName1
233  << " has " << surface1.patches().size()
234  << " regions"
235  << nl
236  << "All region numbers in " << inFileName2 << " will be offset"
237  << " by this amount" << nl << endl;
238 
239  patch1Map = identity(surface1.patches().size());
240  patch2Map = identity(surface2.patches().size(), patch1Map.size());
241 
242  nNewPatches = surface1.patches().size()+surface2.patches().size();
243  }
244 
245 
246  // Copy triangles1 into trianglesAll
247  for (const labelledTri& tri : surface1)
248  {
249  labelledTri& destTri = facesAll[trianglei++];
250 
251  destTri.triFace::operator=(tri);
252  destTri.region() = patch1Map[tri.region()];
253  }
254 
255  // Add (renumbered) surface2 triangles
256  for (const labelledTri& tri : surface2)
257  {
258  labelledTri& destTri = facesAll[trianglei++];
259  destTri[0] = tri[0] + points1.size();
260  destTri[1] = tri[1] + points1.size();
261  destTri[2] = tri[2] + points1.size();
262  destTri.region() = patch2Map[tri.region()];
263  }
264 
265 
266  geometricSurfacePatchList newPatches(nNewPatches);
267  forAll(surface1.patches(), patchi)
268  {
269  newPatches[patch1Map[patchi]] = surface1.patches()[patchi];
270  }
271  forAll(surface2.patches(), patchi)
272  {
273  newPatches[patch2Map[patchi]] = surface2.patches()[patchi];
274  }
275 
276  Info<< "New patches:" << nl;
277  forAll(newPatches, patchi)
278  {
279  Info<< " " << patchi << '\t' << newPatches[patchi].name() << nl;
280  }
281  Info<< endl;
282 
283 
284  // Construct new surface mesh
285  combinedSurf = triSurface(facesAll, newPatches, pointsAll);
286  }
287 
288  // Merge all common points and do some checks
289  combinedSurf.cleanup(optVerbose);
290 
291  Info<< "Merged surface:" << endl;
292 
293  combinedSurf.writeStats(Info);
294 
295  Info<< endl;
296 
297  Info<< "Writing : " << outFileName << endl;
298 
299  // If merging regions also sort
300  combinedSurf.write(outFileName, mergeRegions);
301 
302  Info<< "End\n" << endl;
303 
304  return 0;
305 }
306 
307 
308 // ************************************************************************* //
void cleanup(const bool verbose)
Remove non-valid triangles.
Definition: triSurface.C:648
static void addNote(const string &note)
Add extra notes for the usage information.
Definition: argList.C:462
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
A class for handling file names.
Definition: fileName.H:71
void writeStats(Ostream &os) const
Write some statistics.
Definition: triSurfaceIO.C:348
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:49
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:487
static void addBoolOption(const word &optName, const string &usage="", bool advanced=false)
Add a bool option to validOptions with usage information.
Definition: argList.C:374
static void noParallel()
Remove the parallel options.
Definition: argList.C:584
T getOrDefault(const word &optName, const T &deflt) const
Get a value from the named option if present, or return default.
Definition: argListI.H:300
void write(Ostream &os) const
Write to Ostream in simple OpenFOAM format.
Definition: triSurfaceIO.C:331
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:414
static constexpr label size() noexcept
Return the number of elements in the FixedList.
Definition: FixedList.H:597
label size() const noexcept
The number of elements in table.
Definition: HashTable.H:331
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:52
labelList identity(const label len, label start=0)
Return an identity map of the given length with (map[i] == i)
Definition: labelList.C:31
label region() const noexcept
Return the region index.
Definition: labelledTri.H:171
A class for handling words, derived from Foam::string.
Definition: word.H:63
Extract command arguments and options from the supplied argc and argv parameters. ...
Definition: argList.H:118
static void addOption(const word &optName, const string &param="", const string &usage="", bool advanced=false)
Add an option to validOptions with usage information.
Definition: argList.C:385
A triFace with additional (region) index.
Definition: labelledTri.H:53
static void addVerboseOption(const string &usage="", bool advanced=false)
Enable a &#39;verbose&#39; bool option, with usage information.
Definition: argList.C:520
Input from file stream, using an ISstream.
Definition: IFstream.H:49
T get(const label index) const
Get a value from the argument at index.
Definition: argListI.H:271
static void addArgument(const string &argName, const string &usage="")
Append a (mandatory) argument to validArgs.
Definition: argList.C:351
messageStream Info
Information stream (stdout output on master, null elsewhere)
Triangulated surface description with patch information.
Definition: triSurface.H:71
Foam::argList args(argc, argv)
int verbose() const noexcept
Return the verbose flag.
Definition: argListI.H:121
bool found(const word &optName) const
Return true if the named option is found.
Definition: argListI.H:171
Namespace for OpenFOAM.