1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
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
13 the Free Software Foundation, either version 3 of the License, or
14 (at your 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, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "extendedFeatureEdgeMesh.H"
27 #include "triSurface.H"
30 #include "meshTools.H"
31 #include "linePointRef.H"
32 #include "ListListOps.H"
35 #include "unitConversion.H"
37 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
39 defineTypeNameAndDebug(Foam::extendedFeatureEdgeMesh, 0);
41 Foam::scalar Foam::extendedFeatureEdgeMesh::cosNormalAngleTol_ =
42 Foam::cos(degToRad(0.1));
45 Foam::label Foam::extendedFeatureEdgeMesh::convexStart_ = 0;
48 Foam::label Foam::extendedFeatureEdgeMesh::externalStart_ = 0;
51 Foam::label Foam::extendedFeatureEdgeMesh::nPointTypes = 4;
54 Foam::label Foam::extendedFeatureEdgeMesh::nEdgeTypes = 5;
57 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
59 Foam::extendedFeatureEdgeMesh::extendedFeatureEdgeMesh(const IOobject& io)
62 edgeMesh(pointField(0), edgeList(0)),
73 featurePointNormals_(0),
80 io.readOpt() == IOobject::MUST_READ
81 || io.readOpt() == IOobject::MUST_READ_IF_MODIFIED
82 || (io.readOpt() == IOobject::READ_IF_PRESENT && headerOk())
85 if (readOpt() == IOobject::MUST_READ_IF_MODIFIED)
89 "extendedFeatureEdgeMesh::extendedFeatureEdgeMesh"
91 ) << "Specified IOobject::MUST_READ_IF_MODIFIED but class"
92 << " does not support automatic rereading."
96 Istream& is = readStream(typeName);
108 >> featurePointNormals_
114 // Calculate edgeDirections
116 const edgeList& eds(edges());
118 const pointField& pts(points());
120 edgeDirections_.setSize(eds.size());
124 edgeDirections_[eI] = eds[eI].vec(pts);
127 edgeDirections_ /= mag(edgeDirections_);
133 Pout<< "extendedFeatureEdgeMesh::extendedFeatureEdgeMesh :"
134 << " constructed from IOobject :"
135 << " points:" << points().size()
136 << " edges:" << edges().size()
142 Foam::extendedFeatureEdgeMesh::extendedFeatureEdgeMesh
145 const extendedFeatureEdgeMesh& fem
150 concaveStart_(fem.concaveStart()),
151 mixedStart_(fem.mixedStart()),
152 nonFeatureStart_(fem.nonFeatureStart()),
153 internalStart_(fem.internalStart()),
154 flatStart_(fem.flatStart()),
155 openStart_(fem.openStart()),
156 multipleStart_(fem.multipleStart()),
157 normals_(fem.normals()),
158 edgeDirections_(fem.edgeDirections()),
159 edgeNormals_(fem.edgeNormals()),
160 featurePointNormals_(fem.featurePointNormals()),
161 regionEdges_(fem.regionEdges()),
167 Foam::extendedFeatureEdgeMesh::extendedFeatureEdgeMesh
170 const Xfer<pointField>& pointLst,
171 const Xfer<edgeList>& edgeLst
175 edgeMesh(pointLst, edgeLst),
186 featurePointNormals_(0),
193 Foam::extendedFeatureEdgeMesh::extendedFeatureEdgeMesh
195 const surfaceFeatures& sFeat,
196 const objectRegistry& obr,
197 const fileName& sFeatFileName
205 obr.time().constant(),
206 "extendedFeatureEdgeMesh",
212 edgeMesh(pointField(0), edgeList(0)),
215 nonFeatureStart_(-1),
223 featurePointNormals_(0),
228 // Extract and reorder the data from surfaceFeatures
230 // References to the surfaceFeatures data
231 const triSurface& surf(sFeat.surface());
232 const pointField& sFeatLocalPts(surf.localPoints());
233 const edgeList& sFeatEds(surf.edges());
235 // Filling the extendedFeatureEdgeMesh with the raw geometrical data.
237 label nFeatEds = sFeat.featureEdges().size();
239 DynamicList<point> tmpPts;
240 edgeList eds(nFeatEds);
241 DynamicList<vector> norms;
242 vectorField edgeDirections(nFeatEds);
243 labelListList edgeNormals(nFeatEds);
244 DynamicList<label> regionEdges;
246 // Mapping between old and new indices, there is entry in the map for each
247 // of sFeatLocalPts, -1 means that this point hasn't been used (yet), >= 0
248 // corresponds to the index
249 labelList pointMap(sFeatLocalPts.size(), -1);
251 // Noting when the normal of a face has been used so not to duplicate
252 labelList faceMap(surf.size(), -1);
254 // Collecting the status of edge for subsequent sorting
255 List<edgeStatus> edStatus(nFeatEds, NONE);
257 forAll(sFeat.featurePoints(), i)
259 label sFPI = sFeat.featurePoints()[i];
261 tmpPts.append(sFeatLocalPts[sFPI]);
263 pointMap[sFPI] = tmpPts.size() - 1;
266 // All feature points have been added
267 nonFeatureStart_ = tmpPts.size();
269 forAll(sFeat.featureEdges(), i)
271 label sFEI = sFeat.featureEdges()[i];
273 const edge& fE(sFeatEds[sFEI]);
275 // Check to see if the points have been already used
276 if (pointMap[fE.start()] == -1)
278 tmpPts.append(sFeatLocalPts[fE.start()]);
280 pointMap[fE.start()] = tmpPts.size() - 1;
283 eds[i].start() = pointMap[fE.start()];
285 if (pointMap[fE.end()] == -1)
287 tmpPts.append(sFeatLocalPts[fE.end()]);
289 pointMap[fE.end()] = tmpPts.size() - 1;
292 eds[i].end() = pointMap[fE.end()];
294 // Pick up the faces adjacent to the feature edge
295 const labelList& eFaces = surf.edgeFaces()[sFEI];
297 edgeNormals[i].setSize(eFaces.size());
301 label eFI = eFaces[j];
303 // Check to see if the points have been already used
304 if (faceMap[eFI] == -1)
306 norms.append(surf.faceNormals()[eFI]);
308 faceMap[eFI] = norms.size() - 1;
311 edgeNormals[i][j] = faceMap[eFI];
314 vector fC0tofC1(vector::zero);
316 if (eFaces.size() == 2)
319 surf[eFaces[1]].centre(surf.points())
320 - surf[eFaces[0]].centre(surf.points());
323 edStatus[i] = classifyEdge(norms, edgeNormals[i], fC0tofC1);
325 edgeDirections[i] = fE.vec(sFeatLocalPts);
327 if (i < sFeat.nRegionEdges())
329 regionEdges.append(i);
333 // Reorder the edges by classification
335 List<DynamicList<label> > allEds(nEdgeTypes);
337 DynamicList<label>& externalEds(allEds[0]);
338 DynamicList<label>& internalEds(allEds[1]);
339 DynamicList<label>& flatEds(allEds[2]);
340 DynamicList<label>& openEds(allEds[3]);
341 DynamicList<label>& multipleEds(allEds[4]);
345 edgeStatus eStat = edStatus[i];
347 if (eStat == EXTERNAL)
349 externalEds.append(i);
351 else if (eStat == INTERNAL)
353 internalEds.append(i);
355 else if (eStat == FLAT)
359 else if (eStat == OPEN)
363 else if (eStat == MULTIPLE)
365 multipleEds.append(i);
367 else if (eStat == NONE)
371 "Foam::extendedFeatureEdgeMesh::extendedFeatureEdgeMesh"
373 " const surfaceFeatures& sFeat,"
374 " const objectRegistry& obr,"
375 " const fileName& sFeatFileName"
378 << nl << "classifyEdge returned NONE on edge "
380 << ". There is a problem with definition of this edge."
381 << nl << abort(FatalError);
385 internalStart_ = externalEds.size();
386 flatStart_ = internalStart_ + internalEds.size();
387 openStart_ = flatStart_ + flatEds.size();
388 multipleStart_ = openStart_ + openEds.size();
392 ListListOps::combine<labelList>
395 accessOp<labelList>()
399 edMap = invert(edMap.size(), edMap);
401 inplaceReorder(edMap, eds);
402 inplaceReorder(edMap, edStatus);
403 inplaceReorder(edMap, edgeDirections);
404 inplaceReorder(edMap, edgeNormals);
405 inplaceRenumber(edMap, regionEdges);
407 pointField pts(tmpPts);
409 // Initialise the edgeMesh
410 edgeMesh::operator=(edgeMesh(pts, eds));
412 // Initialise sorted edge related data
413 edgeDirections_ = edgeDirections/mag(edgeDirections);
414 edgeNormals_ = edgeNormals;
415 regionEdges_ = regionEdges;
417 // Normals are all now found and indirectly addressed, can also be stored
418 normals_ = vectorField(norms);
420 // Reorder the feature points by classification
422 List<DynamicList<label> > allPts(3);
424 DynamicList<label>& convexPts(allPts[0]);
425 DynamicList<label>& concavePts(allPts[1]);
426 DynamicList<label>& mixedPts(allPts[2]);
428 for (label i = 0; i < nonFeatureStart_; i++)
430 pointStatus ptStatus = classifyFeaturePoint(i);
432 if (ptStatus == CONVEX)
436 else if (ptStatus == CONCAVE)
438 concavePts.append(i);
440 else if (ptStatus == MIXED)
444 else if (ptStatus == NONFEATURE)
448 "Foam::extendedFeatureEdgeMesh::extendedFeatureEdgeMesh"
450 " const surfaceFeatures& sFeat,"
451 " const objectRegistry& obr,"
452 " const fileName& sFeatFileName"
455 << nl << "classifyFeaturePoint returned NONFEATURE on point at "
457 << ". There is a problem with definition of this feature point."
458 << nl << abort(FatalError);
462 concaveStart_ = convexPts.size();
463 mixedStart_ = concaveStart_ + concavePts.size();
467 ListListOps::combine<labelList>
470 accessOp<labelList>()
474 ftPtMap = invert(ftPtMap.size(), ftPtMap);
476 // Creating the ptMap from the ftPtMap with identity values up to the size
477 // of pts to create an oldToNew map for inplaceReorder
479 labelList ptMap(identity(pts.size()));
483 ptMap[i] = ftPtMap[i];
486 inplaceReorder(ptMap, pts);
490 inplaceRenumber(ptMap, eds[i]);
493 // Reinitialise the edgeMesh with sorted feature points and
495 edgeMesh::operator=(edgeMesh(pts, eds));
497 // Generate the featurePointNormals
499 labelListList featurePointNormals(nonFeatureStart_);
501 for (label i = 0; i < nonFeatureStart_; i++)
503 DynamicList<label> tmpFtPtNorms;
505 const labelList& ptEds = pointEdges()[i];
509 const labelList& ptEdNorms(edgeNormals[ptEds[j]]);
513 if (findIndex(tmpFtPtNorms, ptEdNorms[k]) == -1)
515 bool addNormal = true;
517 // Check that the normal direction is unique at this feature
518 forAll(tmpFtPtNorms, q)
522 (normals_[ptEdNorms[k]] & normals_[tmpFtPtNorms[q]])
526 // Parallel to an existing normal, do not add
535 tmpFtPtNorms.append(ptEdNorms[k]);
541 featurePointNormals[i] = tmpFtPtNorms;
544 featurePointNormals_ = featurePointNormals;
548 Foam::extendedFeatureEdgeMesh::extendedFeatureEdgeMesh
551 const pointField& pts,
555 label nonFeatureStart,
560 const vectorField& normals,
561 const vectorField& edgeDirections,
562 const labelListList& edgeNormals,
563 const labelListList& featurePointNormals,
564 const labelList& regionEdges
569 concaveStart_(concaveStart),
570 mixedStart_(mixedStart),
571 nonFeatureStart_(nonFeatureStart),
572 internalStart_(internalStart),
573 flatStart_(flatStart),
574 openStart_(openStart),
575 multipleStart_(multipleStart),
577 edgeDirections_(edgeDirections),
578 edgeNormals_(edgeNormals),
579 featurePointNormals_(featurePointNormals),
580 regionEdges_(regionEdges),
586 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
588 Foam::extendedFeatureEdgeMesh::~extendedFeatureEdgeMesh()
592 // * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
594 Foam::extendedFeatureEdgeMesh::pointStatus
595 Foam::extendedFeatureEdgeMesh::classifyFeaturePoint
600 labelList ptEds(pointEdges()[ptI]);
602 label nPtEds = ptEds.size();
608 // There are no edges attached to the point, this is a problem
614 edgeStatus edStat = getEdgeStatus(ptEds[i]);
616 if (edStat == EXTERNAL)
620 else if (edStat == INTERNAL)
626 if (nExternal == nPtEds)
630 else if (nInternal == nPtEds)
641 Foam::extendedFeatureEdgeMesh::edgeStatus
642 Foam::extendedFeatureEdgeMesh::classifyEdge
644 const List<vector>& norms,
645 const labelList& edNorms,
646 const vector& fC0tofC1
649 label nEdNorms = edNorms.size();
655 else if (nEdNorms == 2)
657 const vector n0(norms[edNorms[0]]);
658 const vector n1(norms[edNorms[1]]);
660 if ((n0 & n1) > cosNormalAngleTol_)
664 else if ((fC0tofC1 & n0) > 0.0)
673 else if (nEdNorms > 2)
679 // There is a problem - the edge has no normals
685 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
687 void Foam::extendedFeatureEdgeMesh::nearestFeatureEdge
690 scalar searchDistSqr,
694 info = edgeTree().findNearest
702 void Foam::extendedFeatureEdgeMesh::nearestFeatureEdge
704 const pointField& samples,
705 const scalarField& searchDistSqr,
706 List<pointIndexHit>& info
709 info.setSize(samples.size());
723 void Foam::extendedFeatureEdgeMesh::nearestFeatureEdgeByType
726 const scalarField& searchDistSqr,
727 List<pointIndexHit>& info
730 const PtrList<indexedOctree<treeDataEdge> >& edgeTrees = edgeTreesByType();
732 info.setSize(edgeTrees.size());
734 labelList sliceStarts(edgeTrees.size());
736 sliceStarts[0] = externalStart_;
737 sliceStarts[1] = internalStart_;
738 sliceStarts[2] = flatStart_;
739 sliceStarts[3] = openStart_;
740 sliceStarts[4] = multipleStart_;
744 info[i] = edgeTrees[i].findNearest
750 // The index returned by the indexedOctree is local to the slice of
751 // edges it was supplied with, return the index to the value in the
752 // complete edge list
754 info[i].setIndex(info[i].index() + sliceStarts[i]);
759 const Foam::indexedOctree<Foam::treeDataEdge>&
760 Foam::extendedFeatureEdgeMesh::edgeTree() const
762 if (edgeTree_.empty())
764 Random rndGen(17301893);
766 // Slightly extended bb. Slightly off-centred just so on symmetric
767 // geometry there are less face/edge aligned items.
770 treeBoundBox(points()).extend(rndGen, 1E-4)
773 bb.min() -= point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
774 bb.max() += point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
776 labelList allEdges(identity(edges().size()));
780 new indexedOctree<treeDataEdge>
787 allEdges // selected edges
801 const Foam::PtrList<Foam::indexedOctree<Foam::treeDataEdge> >&
802 Foam::extendedFeatureEdgeMesh::edgeTreesByType() const
804 if (edgeTreesByType_.size() == 0)
806 edgeTreesByType_.setSize(nEdgeTypes);
808 Random rndGen(872141);
810 // Slightly extended bb. Slightly off-centred just so on symmetric
811 // geometry there are less face/edge aligned items.
814 treeBoundBox(points()).extend(rndGen, 1E-4)
817 bb.min() -= point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
818 bb.max() += point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
820 labelListList sliceEdges(nEdgeTypes);
824 identity(internalStart_ - externalStart_) + externalStart_;
827 sliceEdges[1] = identity(flatStart_ - internalStart_) + internalStart_;
830 sliceEdges[2] = identity(openStart_ - flatStart_) + flatStart_;
833 sliceEdges[3] = identity(multipleStart_ - openStart_) + openStart_;
837 identity(edges().size() - multipleStart_) + multipleStart_;
839 forAll(edgeTreesByType_, i)
844 new indexedOctree<treeDataEdge>
851 sliceEdges[i] // selected edges
862 return edgeTreesByType_;
866 void Foam::extendedFeatureEdgeMesh::writeObj
868 const fileName& prefix
871 Pout<< nl << "Writing extendedFeatureEdgeMesh components to " << prefix
876 edgeMesh::write(prefix + "_edgeMesh.obj");
878 OFstream convexFtPtStr(prefix + "_convexFeaturePts.obj");
879 Pout<< "Writing convex feature points to " << convexFtPtStr.name() << endl;
881 for(label i = 0; i < concaveStart_; i++)
883 meshTools::writeOBJ(convexFtPtStr, points()[i]);
886 OFstream concaveFtPtStr(prefix + "_concaveFeaturePts.obj");
887 Pout<< "Writing concave feature points to "
888 << concaveFtPtStr.name() << endl;
890 for(label i = concaveStart_; i < mixedStart_; i++)
892 meshTools::writeOBJ(concaveFtPtStr, points()[i]);
895 OFstream mixedFtPtStr(prefix + "_mixedFeaturePts.obj");
896 Pout<< "Writing mixed feature points to " << mixedFtPtStr.name() << endl;
898 for(label i = mixedStart_; i < nonFeatureStart_; i++)
900 meshTools::writeOBJ(mixedFtPtStr, points()[i]);
903 OFstream mixedFtPtStructureStr(prefix + "_mixedFeaturePtsStructure.obj");
904 Pout<< "Writing mixed feature point structure to "
905 << mixedFtPtStructureStr.name() << endl;
908 for(label i = mixedStart_; i < nonFeatureStart_; i++)
910 const labelList& ptEds = pointEdges()[i];
914 const edge& e = edges()[ptEds[j]];
916 meshTools::writeOBJ(mixedFtPtStructureStr, points()[e[0]]); verti++;
917 meshTools::writeOBJ(mixedFtPtStructureStr, points()[e[1]]); verti++;
918 mixedFtPtStructureStr << "l " << verti-1 << ' ' << verti << endl;
922 OFstream externalStr(prefix + "_externalEdges.obj");
923 Pout<< "Writing external edges to " << externalStr.name() << endl;
926 for (label i = externalStart_; i < internalStart_; i++)
928 const edge& e = edges()[i];
930 meshTools::writeOBJ(externalStr, points()[e[0]]); verti++;
931 meshTools::writeOBJ(externalStr, points()[e[1]]); verti++;
932 externalStr << "l " << verti-1 << ' ' << verti << endl;
935 OFstream internalStr(prefix + "_internalEdges.obj");
936 Pout<< "Writing internal edges to " << internalStr.name() << endl;
939 for (label i = internalStart_; i < flatStart_; i++)
941 const edge& e = edges()[i];
943 meshTools::writeOBJ(internalStr, points()[e[0]]); verti++;
944 meshTools::writeOBJ(internalStr, points()[e[1]]); verti++;
945 internalStr << "l " << verti-1 << ' ' << verti << endl;
948 OFstream flatStr(prefix + "_flatEdges.obj");
949 Pout<< "Writing flat edges to " << flatStr.name() << endl;
952 for (label i = flatStart_; i < openStart_; i++)
954 const edge& e = edges()[i];
956 meshTools::writeOBJ(flatStr, points()[e[0]]); verti++;
957 meshTools::writeOBJ(flatStr, points()[e[1]]); verti++;
958 flatStr << "l " << verti-1 << ' ' << verti << endl;
961 OFstream openStr(prefix + "_openEdges.obj");
962 Pout<< "Writing open edges to " << openStr.name() << endl;
965 for (label i = openStart_; i < multipleStart_; i++)
967 const edge& e = edges()[i];
969 meshTools::writeOBJ(openStr, points()[e[0]]); verti++;
970 meshTools::writeOBJ(openStr, points()[e[1]]); verti++;
971 openStr << "l " << verti-1 << ' ' << verti << endl;
974 OFstream multipleStr(prefix + "_multipleEdges.obj");
975 Pout<< "Writing multiple edges to " << multipleStr.name() << endl;
978 for (label i = multipleStart_; i < edges().size(); i++)
980 const edge& e = edges()[i];
982 meshTools::writeOBJ(multipleStr, points()[e[0]]); verti++;
983 meshTools::writeOBJ(multipleStr, points()[e[1]]); verti++;
984 multipleStr << "l " << verti-1 << ' ' << verti << endl;
987 OFstream regionStr(prefix + "_regionEdges.obj");
988 Pout<< "Writing region edges to " << regionStr.name() << endl;
991 forAll(regionEdges_, i)
993 const edge& e = edges()[regionEdges_[i]];
995 meshTools::writeOBJ(regionStr, points()[e[0]]); verti++;
996 meshTools::writeOBJ(regionStr, points()[e[1]]); verti++;
997 regionStr << "l " << verti-1 << ' ' << verti << endl;
1002 bool Foam::extendedFeatureEdgeMesh::writeData(Ostream& os) const
1004 os << "// points, edges, concaveStart, mixedStart, nonFeatureStart, " << nl
1005 << "// internalStart, flatStart, openStart, multipleStart, " << nl
1006 << "// normals, edgeNormals, featurePointNormals, regionEdges" << nl
1009 os << points() << nl
1011 << concaveStart_ << token::SPACE
1012 << mixedStart_ << token::SPACE
1013 << nonFeatureStart_ << token::SPACE
1014 << internalStart_ << token::SPACE
1015 << flatStart_ << token::SPACE
1016 << openStart_ << token::SPACE
1017 << multipleStart_ << nl
1019 << edgeNormals_ << nl
1020 << featurePointNormals_ << nl
1028 // ************************************************************************* //