1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd.
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
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 the
13 Free Software Foundation; either version 2 of the License, or (at your
14 option) any later version.
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
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*---------------------------------------------------------------------------*/
28 #include "triSurface.H"
29 #include "triSurfaceTools.H"
30 #include "triSurfaceSearch.H"
33 #include "surfaceIntersection.H"
34 #include "SortableList.H"
38 // Does face use valid vertices?
39 bool validTri(const triSurface& surf, const label faceI)
41 // Simple check on indices ok.
43 const labelledTri& f = surf[faceI];
47 (f[0] < 0) || (f[0] >= surf.points().size())
48 || (f[1] < 0) || (f[1] >= surf.points().size())
49 || (f[2] < 0) || (f[2] >= surf.points().size())
52 //WarningIn("validTri(const triSurface&, const label)")
53 // << "triangle " << faceI << " vertices " << f
54 // << " uses point indices outside point range 0.."
55 // << surf.points().size()-1 << endl;
60 if ((f[0] == f[1]) || (f[0] == f[2]) || (f[1] == f[2]))
62 //WarningIn("validTri(const triSurface&, const label)")
63 // << "triangle " << faceI
64 // << " uses non-unique vertices " << f
69 // duplicate triangle check
71 const labelList& fFaces = surf.faceFaces()[faceI];
73 // Check if faceNeighbours use same points as this face.
74 // Note: discards normal information - sides of baffle are merged.
77 label nbrFaceI = fFaces[i];
79 if (nbrFaceI <= faceI)
81 // lower numbered faces already checked
85 const labelledTri& nbrF = surf[nbrFaceI];
89 ((f[0] == nbrF[0]) || (f[0] == nbrF[1]) || (f[0] == nbrF[2]))
90 && ((f[1] == nbrF[0]) || (f[1] == nbrF[1]) || (f[1] == nbrF[2]))
91 && ((f[2] == nbrF[0]) || (f[2] == nbrF[1]) || (f[2] == nbrF[2]))
94 //WarningIn("validTri(const triSurface&, const label)")
95 // << "triangle " << faceI << " vertices " << f
96 // << " has the same vertices as triangle " << nbrFaceI
97 // << " vertices " << nbrF
112 const scalarField& vals
115 scalar dist = nBins/(max - min);
117 labelList binCount(nBins, 0);
121 scalar val = vals[i];
125 if (Foam::mag(val - min) < SMALL)
129 else if (val >= max - SMALL)
135 index = label((val - min)*dist);
137 if ((index < 0) || (index >= nBins))
141 "countBins(const scalar, const scalar, const label"
142 ", const scalarField&)"
143 ) << "value " << val << " at index " << i
144 << " outside range " << min << " .. " << max << endl;
163 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
166 int main(int argc, char *argv[])
168 argList::noParallel();
170 argList::validArgs.clear();
171 argList::validArgs.append("surface file");
172 argList::validOptions.insert("noSelfIntersection", "");
173 argList args(argc, argv);
175 bool checkSelfIntersection = !args.options().found("noSelfIntersection");
177 fileName surfFileName(args.additionalArgs()[0]);
178 Pout<< "Reading surface from " << surfFileName << " ..." << nl << endl;
184 triSurface surf(surfFileName);
187 Pout<< "Statistics:" << endl;
188 surf.writeStats(Pout);
196 labelList regionSize(surf.patches().size(), 0);
200 label region = surf[faceI].region();
202 if (region < 0 || region >= regionSize.size())
204 WarningIn(args.executable())
205 << "Triangle " << faceI << " vertices " << surf[faceI]
206 << " has region " << region << " which is outside the range"
207 << " of regions 0.." << surf.patches().size()-1
212 regionSize[region]++;
216 Pout<< "Region\tSize" << nl
217 << "------\t----" << nl;
218 forAll(surf.patches(), patchI)
220 Pout<< surf.patches()[patchI].name() << '\t'
221 << regionSize[patchI] << nl;
231 DynamicList<label> illegalFaces(surf.size()/100 + 1);
235 if (!validTri(surf, faceI))
237 illegalFaces.append(faceI);
241 illegalFaces.shrink();
243 if (illegalFaces.size() > 0)
245 Pout<< "Surface has " << illegalFaces.size()
246 << " illegal triangles." << endl;
248 OFstream str("illegalFaces");
249 Pout<< "Dumping conflicting face labels to " << str.name() << endl
250 << "Paste this into the input for surfaceSubset" << endl;
255 Pout<< "Surface has no illegal triangles." << endl;
266 scalarField triQ(surf.size(), 0);
269 const labelledTri& f = surf[faceI];
271 if (f[0] == f[1] || f[0] == f[2] || f[1] == f[2])
273 //WarningIn(args.executable())
274 // << "Illegal triangle " << faceI << " vertices " << f
275 // << " coords " << f.points(surf.points()) << endl;
286 vector ba(tri.b() - tri.a());
287 ba /= mag(ba) + VSMALL;
289 vector ca(tri.c() - tri.a());
290 ca /= mag(ca) + VSMALL;
292 if (mag(ba&ca) > 1-1E-3)
298 triQ[faceI] = triPointRef
308 labelList binCount = countBins(0, 1, 20, triQ);
310 Pout<< "Triangle quality (equilateral=1, collapsed=0):"
317 scalar dist = (1.0 - 0.0)/20.0;
319 forAll(binCount, binI)
321 Pout<< " " << min << " .. " << min+dist << " : "
322 << 1.0/surf.size() * binCount[binI]
328 label minIndex = findMin(triQ);
329 label maxIndex = findMax(triQ);
331 Pout<< " min " << triQ[minIndex] << " for triangle " << minIndex
333 << " max " << triQ[maxIndex] << " for triangle " << maxIndex
338 if (triQ[minIndex] < SMALL)
340 WarningIn(args.executable()) << "Minimum triangle quality is "
341 << triQ[minIndex] << ". This might give problems in"
342 << " self-intersection testing later on." << endl;
345 // Dump for subsetting
347 DynamicList<label> problemFaces(surf.size()/100+1);
351 if (triQ[faceI] < 1E-11)
353 problemFaces.append(faceI);
356 OFstream str("badFaces");
358 Pout<< "Dumping bad quality faces to " << str.name() << endl
359 << "Paste this into the input for surfaceSubset" << nl
371 const edgeList& edges = surf.edges();
372 const pointField& localPoints = surf.localPoints();
374 scalarField edgeMag(edges.size());
378 edgeMag[edgeI] = edges[edgeI].mag(localPoints);
381 label minEdgeI = findMin(edgeMag);
382 label maxEdgeI = findMax(edgeMag);
384 const edge& minE = edges[minEdgeI];
385 const edge& maxE = edges[maxEdgeI];
388 Pout<< "Edges:" << nl
389 << " min " << edgeMag[minEdgeI] << " for edge " << minEdgeI
390 << " points " << localPoints[minE[0]] << localPoints[minE[1]]
392 << " max " << edgeMag[maxEdgeI] << " for edge " << maxEdgeI
393 << " points " << localPoints[maxE[0]] << localPoints[maxE[1]]
403 const edgeList& edges = surf.edges();
404 const pointField& localPoints = surf.localPoints();
406 const boundBox bb(localPoints);
407 scalar smallDim = 1E-6*mag(bb.max() - bb.min());
409 Pout<< "Checking for points less than 1E-6 of bounding box ("
410 << bb.max() - bb.min() << " meter) apart."
414 SortableList<scalar> sortedMag(mag(localPoints));
418 for (label i = 1; i < sortedMag.size(); i++)
420 label ptI = sortedMag.indices()[i];
422 label prevPtI = sortedMag.indices()[i-1];
424 if (mag(localPoints[ptI] - localPoints[prevPtI]) < smallDim)
426 // Check if neighbours.
427 const labelList& pEdges = surf.pointEdges()[ptI];
433 const edge& e = edges[pEdges[i]];
435 if (e[0] == prevPtI || e[1] == prevPtI)
437 // point1 and point0 are connected through edge.
448 Pout<< " close unconnected points "
449 << ptI << ' ' << localPoints[ptI]
450 << " and " << prevPtI << ' '
451 << localPoints[prevPtI]
453 << mag(localPoints[ptI] - localPoints[prevPtI])
458 Pout<< " small edge between points "
459 << ptI << ' ' << localPoints[ptI]
460 << " and " << prevPtI << ' '
461 << localPoints[prevPtI]
463 << mag(localPoints[ptI] - localPoints[prevPtI])
469 Pout<< "Found " << nClose << " nearby points." << nl
478 DynamicList<label> problemFaces(surf.size()/100 + 1);
480 const labelListList& eFaces = surf.edgeFaces();
482 label nSingleEdges = 0;
483 forAll(eFaces, edgeI)
485 const labelList& myFaces = eFaces[edgeI];
487 if (myFaces.size() == 1)
489 problemFaces.append(myFaces[0]);
495 label nMultEdges = 0;
496 forAll(eFaces, edgeI)
498 const labelList& myFaces = eFaces[edgeI];
500 if (myFaces.size() > 2)
502 forAll(myFaces, myFaceI)
504 problemFaces.append(myFaces[myFaceI]);
510 problemFaces.shrink();
512 if ((nSingleEdges != 0) || (nMultEdges != 0))
514 Pout<< "Surface is not closed since not all edges connected to "
515 << "two faces:" << endl
516 << " connected to one face : " << nSingleEdges << endl
517 << " connected to >2 faces : " << nMultEdges << endl;
519 Pout<< "Conflicting face labels:" << problemFaces.size() << endl;
521 OFstream str("problemFaces");
523 Pout<< "Dumping conflicting face labels to " << str.name() << endl
524 << "Paste this into the input for surfaceSubset" << endl;
530 Pout<< "Surface is closed. All edges connected to two faces." << endl;
536 // Check singly connected domain
537 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
540 label numZones = surf.markZones(boolList(surf.nEdges(), false), faceZone);
542 Pout<< "Number of unconnected parts : " << numZones << endl;
546 Pout<< "Splitting surface into parts ..." << endl << endl;
548 fileName surfFileNameBase(surfFileName.name());
550 for(label zone = 0; zone < numZones; zone++)
552 boolList includeMap(surf.size(), false);
554 forAll(faceZone, faceI)
556 if (faceZone[faceI] == zone)
558 includeMap[faceI] = true;
577 surfFileNameBase.lessExt()
583 Pout<< "writing part " << zone << " size " << subSurf.size()
584 << " to " << subFileName << endl;
586 subSurf.write(subFileName);
597 boolList borderEdge(surf.checkOrientation(false));
600 // Colour all faces into zones using borderEdge
602 labelList normalZone;
603 label numNormalZones = surf.markZones(borderEdge, normalZone);
606 << "Number of zones (connected area with consistent normal) : "
607 << numNormalZones << endl;
609 if (numNormalZones > 1)
611 Pout<< "More than one normal orientation." << endl;
617 // Check self-intersection
618 // ~~~~~~~~~~~~~~~~~~~~~~~
620 if (checkSelfIntersection)
622 Pout<< "Checking self-intersection." << endl;
624 triSurfaceSearch querySurf(surf);
625 surfaceIntersection inter(querySurf);
627 if ((inter.cutEdges().size() == 0) && (inter.cutPoints().size() == 0))
629 Pout<< "Surface is not self-intersecting" << endl;
633 Pout<< "Surface is self-intersecting" << endl;
634 Pout<< "Writing edges of intersection to selfInter.obj" << endl;
636 OFstream intStream("selfInter.obj");
637 forAll(inter.cutPoints(), cutPointI)
639 const point& pt = inter.cutPoints()[cutPointI];
641 intStream << "v " << pt.x() << ' ' << pt.y() << ' ' << pt.z()
644 forAll(inter.cutEdges(), cutEdgeI)
646 const edge& e = inter.cutEdges()[cutEdgeI];
648 intStream << "l " << e.start()+1 << ' ' << e.end()+1 << endl;
655 Pout<< "End\n" << endl;
661 // ************************************************************************* //