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