surfaceSubset.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 | Copyright (C) 2011-2016 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 Application
25  surfaceSubset
26 
27 Description
28  A surface analysis tool which sub-sets the triSurface
29  to choose only a part of interest. Based on subsetMesh.
30 
31 \*---------------------------------------------------------------------------*/
32 
33 #include "triSurface.H"
34 #include "triSurfaceSearch.H"
35 #include "argList.H"
36 #include "OFstream.H"
37 #include "IFstream.H"
38 #include "Switch.H"
39 #include "IOdictionary.H"
40 #include "boundBox.H"
41 #include "indexedOctree.H"
42 #include "treeDataTriSurface.H"
43 #include "Random.H"
44 #include "volumeType.H"
45 #include "plane.H"
46 
47 using namespace Foam;
48 
49 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
50 
51 int main(int argc, char *argv[])
52 {
54  argList::validArgs.append("surfaceSubsetDict");
55  argList::validArgs.append("surfaceFile");
56  argList::validArgs.append("output surfaceFile");
57  argList args(argc, argv);
58 
59  Info<< "Reading dictionary " << args[1] << " ..." << endl;
60  IFstream dictFile(args[1]);
61  dictionary meshSubsetDict(dictFile);
62 
63  Info<< "Reading surface " << args[2] << " ..." << endl;
64  triSurface surf1(args[2]);
65 
66  const fileName outFileName(args[3]);
67 
68 
69  Info<< "Original:" << endl;
70  surf1.writeStats(Info);
71  Info<< endl;
72 
73 
74  labelList markedPoints
75  (
76  meshSubsetDict.lookup("localPoints")
77  );
78 
79  labelList markedEdges
80  (
81  meshSubsetDict.lookup("edges")
82  );
83 
84  labelList markedFaces
85  (
86  meshSubsetDict.lookup("faces")
87  );
88 
89  pointField markedZone
90  (
91  meshSubsetDict.lookup("zone")
92  );
93 
94  if (markedZone.size() && markedZone.size() != 2)
95  {
97  << "zone specification should be two points, min and max of "
98  << "the boundingbox" << endl
99  << "zone:" << markedZone
100  << exit(FatalError);
101  }
102 
103  Switch addFaceNeighbours
104  (
105  meshSubsetDict.lookup("addFaceNeighbours")
106  );
107 
108  const bool invertSelection =
109  meshSubsetDict.lookupOrDefault("invertSelection", false);
110 
111  // Mark the cells for the subset
112 
113  // Faces to subset
114  boolList facesToSubset(surf1.size(), false);
115 
116 
117  //
118  // pick up faces connected to "localPoints"
119  //
120 
121  if (markedPoints.size())
122  {
123  Info<< "Found " << markedPoints.size() << " marked point(s)." << endl;
124 
125  // pick up cells sharing the point
126 
127  forAll(markedPoints, pointi)
128  {
129  if
130  (
131  markedPoints[pointi] < 0
132  || markedPoints[pointi] >= surf1.nPoints()
133  )
134  {
136  << "localPoint label " << markedPoints[pointi]
137  << "out of range."
138  << " The mesh has got "
139  << surf1.nPoints() << " localPoints."
140  << exit(FatalError);
141  }
142 
143  const labelList& curFaces =
144  surf1.pointFaces()[markedPoints[pointi]];
145 
146  forAll(curFaces, i)
147  {
148  facesToSubset[curFaces[i]] = true;
149  }
150  }
151  }
152 
153 
154 
155  //
156  // pick up faces connected to "edges"
157  //
158 
159  if (markedEdges.size())
160  {
161  Info<< "Found " << markedEdges.size() << " marked edge(s)." << endl;
162 
163  // pick up cells sharing the edge
164 
165  forAll(markedEdges, edgeI)
166  {
167  if
168  (
169  markedEdges[edgeI] < 0
170  || markedEdges[edgeI] >= surf1.nEdges()
171  )
172  {
174  << "edge label " << markedEdges[edgeI]
175  << "out of range."
176  << " The mesh has got "
177  << surf1.nEdges() << " edges."
178  << exit(FatalError);
179  }
180 
181  const labelList& curFaces = surf1.edgeFaces()[markedEdges[edgeI]];
182 
183  forAll(curFaces, i)
184  {
185  facesToSubset[curFaces[i]] = true;
186  }
187  }
188  }
189 
190 
191  //
192  // pick up faces with centre inside "zone"
193  //
194 
195  if (markedZone.size() == 2)
196  {
197  const point& min = markedZone[0];
198  const point& max = markedZone[1];
199 
200  Info<< "Using zone min:" << min << " max:" << max << endl;
201 
202  forAll(surf1, facei)
203  {
204  const point centre = surf1[facei].centre(surf1.points());
205 
206  if
207  (
208  (centre.x() >= min.x())
209  && (centre.y() >= min.y())
210  && (centre.z() >= min.z())
211  && (centre.x() <= max.x())
212  && (centre.y() <= max.y())
213  && (centre.z() <= max.z())
214  )
215  {
216  facesToSubset[facei] = true;
217  }
218  }
219  }
220 
221 
222  //
223  // pick up faces on certain side of surface
224  //
225 
226  if (meshSubsetDict.found("surface"))
227  {
228  const dictionary& surfDict = meshSubsetDict.subDict("surface");
229 
230  fileName surfName(surfDict.lookup("name"));
231 
232  Switch outside(surfDict.lookup("outside"));
233 
234  if (outside)
235  {
236  Info<< "Selecting all triangles with centre outside surface "
237  << surfName << endl;
238  }
239  else
240  {
241  Info<< "Selecting all triangles with centre inside surface "
242  << surfName << endl;
243  }
244 
245  // Read surface to select on
246  triSurface selectSurf(surfName);
247 
248  triSurfaceSearch searchSelectSurf
249  (
250  selectSurf,
252  8
253  );
254 
255  const indexedOctree<treeDataTriSurface>& selectTree =
256  searchSelectSurf.tree();
257 
258  // Check if face (centre) is in outside or inside.
259  forAll(facesToSubset, facei)
260  {
261  if (!facesToSubset[facei])
262  {
263  const point fc(surf1[facei].centre(surf1.points()));
264 
265  volumeType t = selectTree.getVolumeType(fc);
266 
267  if
268  (
269  outside
270  ? (t == volumeType::OUTSIDE)
271  : (t == volumeType::INSIDE)
272  )
273  {
274  facesToSubset[facei] = true;
275  }
276  }
277  }
278  }
279 
280 
281  if (meshSubsetDict.found("plane"))
282  {
283  const dictionary& planeDict = meshSubsetDict.subDict("plane");
284 
285  const plane pl(planeDict);
286  const scalar distance(readScalar(planeDict.lookup("distance")));
287  const scalar cosAngle(readScalar(planeDict.lookup("cosAngle")));
288 
289  // Select all triangles that are close to the plane and
290  // whose normal aligns with the plane as well.
291 
292  forAll(surf1.faceCentres(), facei)
293  {
294  const point& fc = surf1.faceCentres()[facei];
295  const point& nf = surf1.faceNormals()[facei];
296 
297  if (pl.distance(fc) < distance && mag(pl.normal() & nf) > cosAngle)
298  {
299  facesToSubset[facei] = true;
300  }
301  }
302  }
303 
304 
305 
306  //
307  // pick up specified "faces"
308  //
309 
310  // Number of additional faces picked up because of addFaceNeighbours
311  label nFaceNeighbours = 0;
312 
313  if (markedFaces.size())
314  {
315  Info<< "Found " << markedFaces.size() << " marked face(s)." << endl;
316 
317  // Check and mark faces to pick up
318  forAll(markedFaces, facei)
319  {
320  if
321  (
322  markedFaces[facei] < 0
323  || markedFaces[facei] >= surf1.size()
324  )
325  {
327  << "Face label " << markedFaces[facei] << "out of range."
328  << " The mesh has got "
329  << surf1.size() << " faces."
330  << exit(FatalError);
331  }
332 
333  // Mark the face
334  facesToSubset[markedFaces[facei]] = true;
335 
336  // mark its neighbours if requested
337  if (addFaceNeighbours)
338  {
339  const labelList& curFaces =
340  surf1.faceFaces()[markedFaces[facei]];
341 
342  forAll(curFaces, i)
343  {
344  label facei = curFaces[i];
345 
346  if (!facesToSubset[facei])
347  {
348  facesToSubset[facei] = true;
349  nFaceNeighbours++;
350  }
351  }
352  }
353  }
354  }
355 
356  if (addFaceNeighbours)
357  {
358  Info<< "Added " << nFaceNeighbours
359  << " faces because of addFaceNeighbours" << endl;
360  }
361 
362 
363  if (invertSelection)
364  {
365  Info<< "Inverting selection." << endl;
366 
367  forAll(facesToSubset, i)
368  {
369  facesToSubset[i] = facesToSubset[i] ? false : true;
370  }
371  }
372 
373 
374  // Create subsetted surface
375  labelList pointMap;
377  triSurface surf2
378  (
379  surf1.subsetMesh(facesToSubset, pointMap, faceMap)
380  );
381 
382  Info<< "Subset:" << endl;
383  surf2.writeStats(Info);
384  Info<< endl;
385 
386  Info<< "Writing surface to " << outFileName << endl;
387 
388  surf2.write(outFileName);
389 
390  return 0;
391 }
392 
393 
394 // ************************************************************************* //
const Cmpt & z() const
Definition: VectorI.H:87
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:428
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
A class for handling file names.
Definition: fileName.H:69
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
const Cmpt & x() const
Definition: VectorI.H:75
error FatalError
A list of keyword definitions, which are a keyword followed by any number of values (e...
Definition: dictionary.H:137
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:319
const dictionary & subDict(const word &) const
Find and return a sub-dictionary.
Definition: dictionary.C:633
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:253
A simple wrapper around bool so that it can be read as a word: true/false, on/off, yes/no, y/n, t/f, or none.
Definition: Switch.H:60
const Vector< Cmpt > & centre(const Foam::List< Vector< Cmpt >> &) const
Return *this (used for point which is a typedef to Vector<scalar>.
Definition: VectorI.H:116
static void noParallel()
Remove the parallel options.
Definition: argList.C:146
static SLList< string > validArgs
A list of valid (mandatory) arguments.
Definition: argList.H:154
scalar distance(const vector &p1, const vector &p2)
Definition: curveTools.C:12
Geometric class that creates a 2D plane and can return the intersection point between a line and the ...
Definition: plane.H:60
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
Helper class to search on triSurface.
Extract command arguments and options from the supplied argc and argv parameters. ...
Definition: argList.H:102
const Cmpt & y() const
Definition: VectorI.H:81
bool readScalar(const char *buf, doubleScalar &s)
Read whole of buf as a scalar. Return true if succesful.
Definition: doubleScalar.H:63
Input from file stream.
Definition: IFstream.H:81
Non-pointer based hierarchical recursive searching.
Definition: treeDataEdge.H:47
messageStream Info
dimensioned< scalar > mag(const dimensioned< Type > &)
virtual Ostream & write(const token &)=0
Write next token to stream.
Triangulated surface description with patch information.
Definition: triSurface.H:65
Foam::argList args(argc, argv)
Namespace for OpenFOAM.
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:451