autoSnapDriverFeature.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-2015 OpenFOAM Foundation
6  \\/ M anipulation | Copyright (C) 2015 OpenCFD Ltd.
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 \*---------------------------------------------------------------------------*/
25 
26 #include "autoSnapDriver.H"
27 #include "polyTopoChange.H"
28 #include "syncTools.H"
29 #include "fvMesh.H"
30 #include "OBJstream.H"
31 #include "motionSmoother.H"
32 #include "refinementSurfaces.H"
33 #include "refinementFeatures.H"
34 #include "unitConversion.H"
35 #include "plane.H"
36 #include "featureEdgeMesh.H"
37 #include "treeDataPoint.H"
38 #include "indexedOctree.H"
39 #include "snapParameters.H"
40 #include "PatchTools.H"
41 #include "pyramidPointFaceRef.H"
42 #include "localPointRegion.H"
43 
44 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
45 
46 namespace Foam
47 {
48  template<class T>
50  {
51  public:
52 
53  void operator()(List<T>& x, const List<T>& y) const
54  {
55  label sz = x.size();
56  x.setSize(sz+y.size());
57  forAll(y, i)
58  {
59  x[sz++] = y[i];
60  }
61  }
62  };
63 }
64 
65 
66 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
67 
69 (
70  const scalar featureCos,
71  const indirectPrimitivePatch& pp,
72  const PackedBoolList& isFeatureEdge,
73  const label pointI
74 ) const
75 {
76  const pointField& points = pp.localPoints();
77  const edgeList& edges = pp.edges();
78  const labelList& pEdges = pp.pointEdges()[pointI];
79 
80  label nFeatEdges = 0;
81 
82  forAll(pEdges, i)
83  {
84  if (isFeatureEdge[pEdges[i]])
85  {
86  nFeatEdges++;
87 
88  for (label j = i+1; j < pEdges.size(); j++)
89  {
90  if (isFeatureEdge[pEdges[j]])
91  {
92  const edge& eI = edges[pEdges[i]];
93  const edge& eJ = edges[pEdges[j]];
94 
95  const point& p = points[pointI];
96  const point& pI = points[eI.otherVertex(pointI)];
97  const point& pJ = points[eJ.otherVertex(pointI)];
98 
99  vector vI = p-pI;
100  scalar vIMag = mag(vI);
101 
102  vector vJ = pJ-p;
103  scalar vJMag = mag(vJ);
104 
105  if
106  (
107  vIMag > SMALL
108  && vJMag > SMALL
109  && ((vI/vIMag & vJ/vJMag) < featureCos)
110  )
111  {
112  return true;
113  }
114  }
115  }
116  }
117  }
118 
119  if (nFeatEdges == 1)
120  {
121  // End of feature-edge string
122  return true;
123  }
124 
125  return false;
126 }
127 
128 
130 (
131  const PackedBoolList& isPatchMasterEdge,
132  const indirectPrimitivePatch& pp,
133  const labelList& meshEdges,
134  const List<pointConstraint>& constraints,
135  vectorField& disp
136 ) const
137 {
138  const fvMesh& mesh = meshRefiner_.mesh();
139 
140  for (label avgIter = 0; avgIter < 20; avgIter++)
141  {
142  // Calculate average displacement of neighbours
143  // - unconstrained (i.e. surface) points use average of all
144  // neighbouring points
145  // - from testing it has been observed that it is not beneficial
146  // to have edge constrained points use average of all edge or point
147  // constrained neighbours since they're already attracted to
148  // the nearest point on the feature.
149  // Having them attract to point-constrained neighbours does not
150  // make sense either since there is usually just one of them so
151  // it severely distorts it.
152  // - same for feature points. They are already attracted to the
153  // nearest feature point.
154 
155  vectorField dispSum(pp.nPoints(), vector::zero);
156  labelList dispCount(pp.nPoints(), 0);
157 
158  const labelListList& pointEdges = pp.pointEdges();
159  const edgeList& edges = pp.edges();
160 
161  forAll(pointEdges, pointI)
162  {
163  const labelList& pEdges = pointEdges[pointI];
164 
165  label nConstraints = constraints[pointI].first();
166 
167  if (nConstraints <= 1)
168  {
169  forAll(pEdges, i)
170  {
171  label edgeI = pEdges[i];
172 
173  if (isPatchMasterEdge[edgeI])
174  {
175  label nbrPointI = edges[edgeI].otherVertex(pointI);
176  if (constraints[nbrPointI].first() >= nConstraints)
177  {
178  dispSum[pointI] += disp[nbrPointI];
179  dispCount[pointI]++;
180  }
181  }
182  }
183  }
184  }
185 
186  syncTools::syncPointList
187  (
188  mesh,
189  pp.meshPoints(),
190  dispSum,
191  plusEqOp<point>(),
192  vector::zero,
194  );
195  syncTools::syncPointList
196  (
197  mesh,
198  pp.meshPoints(),
199  dispCount,
200  plusEqOp<label>(),
201  label(0),
203  );
204 
205  // Constraints
206  forAll(constraints, pointI)
207  {
208  if (dispCount[pointI] > 0)
209  {
210  // Mix my displacement with neighbours' displacement
211  disp[pointI] =
212  0.5
213  *(disp[pointI] + dispSum[pointI]/dispCount[pointI]);
214  }
215  }
216  }
217 }
218 
219 
221 (
222  const label iter,
223  const indirectPrimitivePatch& pp,
224  const scalarField& faceSnapDist,
225  vectorField& faceDisp,
226  vectorField& faceSurfaceNormal,
227  labelList& faceSurfaceGlobalRegion
228  //vectorField& faceRotation
229 ) const
230 {
231  const fvMesh& mesh = meshRefiner_.mesh();
232  const refinementSurfaces& surfaces = meshRefiner_.surfaces();
233 
234  // Displacement and orientation per pp face.
235  faceDisp.setSize(pp.size());
236  faceDisp = vector::zero;
237  faceSurfaceNormal.setSize(pp.size());
238  faceSurfaceNormal = vector::zero;
239  faceSurfaceGlobalRegion.setSize(pp.size());
240  faceSurfaceGlobalRegion = -1;
241 
242  // Divide surfaces into zoned and unzoned
243  const labelList zonedSurfaces =
244  surfaceZonesInfo::getNamedSurfaces(surfaces.surfZones());
245  const labelList unzonedSurfaces =
246  surfaceZonesInfo::getUnnamedSurfaces(surfaces.surfZones());
247 
248  // Per pp face the current surface snapped to
249  labelList snapSurf(pp.size(), -1);
250 
251 
252  // Do zoned surfaces
253  // ~~~~~~~~~~~~~~~~~
254  // Zoned faces only attract to corresponding surface
255 
256  // Extract faces per zone
257  const PtrList<surfaceZonesInfo>& surfZones = surfaces.surfZones();
258 
259  forAll(zonedSurfaces, i)
260  {
261  label zoneSurfI = zonedSurfaces[i];
262 
263  const word& faceZoneName = surfZones[zoneSurfI].faceZoneName();
264 
265  // Get indices of faces on pp that are also in zone
266  label zoneI = mesh.faceZones().findZoneID(faceZoneName);
267  if (zoneI == -1)
268  {
270  << "Problem. Cannot find zone " << faceZoneName
271  << exit(FatalError);
272  }
273  const faceZone& fZone = mesh.faceZones()[zoneI];
274  PackedBoolList isZonedFace(mesh.nFaces());
275  forAll(fZone, i)
276  {
277  isZonedFace[fZone[i]] = 1;
278  }
279 
280  DynamicList<label> ppFaces(fZone.size());
281  DynamicList<label> meshFaces(fZone.size());
282  forAll(pp.addressing(), i)
283  {
284  if (isZonedFace[pp.addressing()[i]])
285  {
286  snapSurf[i] = zoneSurfI;
287  ppFaces.append(i);
288  meshFaces.append(pp.addressing()[i]);
289  }
290  }
291 
292  //Pout<< "For faceZone " << fZone.name()
293  // << " found " << ppFaces.size() << " out of " << pp.size()
294  // << endl;
295 
296  pointField fc
297  (
299  (
300  IndirectList<face>(mesh.faces(), meshFaces),
301  mesh.points()
302  ).faceCentres()
303  );
304 
305  List<pointIndexHit> hitInfo;
306  labelList hitSurface;
307  labelList hitRegion;
308  vectorField hitNormal;
309  surfaces.findNearestRegion
310  (
311  labelList(1, zoneSurfI),
312  fc,
313  sqr(faceSnapDist),// sqr of attract dist
314  hitSurface,
315  hitInfo,
316  hitRegion,
317  hitNormal
318  );
319 
320  forAll(hitInfo, hitI)
321  {
322  if (hitInfo[hitI].hit())
323  {
324  label faceI = ppFaces[hitI];
325  faceDisp[faceI] = hitInfo[hitI].hitPoint() - fc[hitI];
326  faceSurfaceNormal[faceI] = hitNormal[hitI];
327  faceSurfaceGlobalRegion[faceI] = surfaces.globalRegion
328  (
329  hitSurface[hitI],
330  hitRegion[hitI]
331  );
332  }
333  else
334  {
336  << "Did not find surface near face centre " << fc[hitI]
337  << endl;
338  }
339  }
340  }
341 
342 
343  // Do unzoned surfaces
344  // ~~~~~~~~~~~~~~~~~~~
345  // Unzoned faces attract to any unzoned surface
346 
347  DynamicList<label> ppFaces(pp.size());
348  DynamicList<label> meshFaces(pp.size());
349  forAll(pp.addressing(), i)
350  {
351  if (snapSurf[i] == -1)
352  {
353  ppFaces.append(i);
354  meshFaces.append(pp.addressing()[i]);
355  }
356  }
357  //Pout<< "Found " << ppFaces.size() << " unzoned faces out of "
358  // << pp.size() << endl;
359 
360  pointField fc
361  (
363  (
364  IndirectList<face>(mesh.faces(), meshFaces),
365  mesh.points()
366  ).faceCentres()
367  );
368 
369  List<pointIndexHit> hitInfo;
370  labelList hitSurface;
371  labelList hitRegion;
372  vectorField hitNormal;
373  surfaces.findNearestRegion
374  (
375  unzonedSurfaces,
376  fc,
377  sqr(faceSnapDist),// sqr of attract dist
378  hitSurface,
379  hitInfo,
380  hitRegion,
381  hitNormal
382  );
383 
384  forAll(hitInfo, hitI)
385  {
386  if (hitInfo[hitI].hit())
387  {
388  label faceI = ppFaces[hitI];
389  faceDisp[faceI] = hitInfo[hitI].hitPoint() - fc[hitI];
390  faceSurfaceNormal[faceI] = hitNormal[hitI];
391  faceSurfaceGlobalRegion[faceI] = surfaces.globalRegion
392  (
393  hitSurface[hitI],
394  hitRegion[hitI]
395  );
396  }
397  else
398  {
400  << "Did not find surface near face centre " << fc[hitI]
401  << endl;
402  }
403  }
404 
405 
408  //
410  //faceRotation.setSize(pp.size());
411  //faceRotation = vector::zero;
412  //
413  //forAll(faceRotation, faceI)
414  //{
415  // // Note: extend to >180 degrees checking
416  // faceRotation[faceI] =
417  // pp.faceNormals()[faceI]
418  // ^ faceSurfaceNormal[faceI];
419  //}
420  //
421  //if (debug&meshRefinement::ATTRACTION)
422  //{
423  // dumpMove
424  // (
425  // mesh.time().path()
426  // / "faceDisp_" + name(iter) + ".obj",
427  // pp.faceCentres(),
428  // pp.faceCentres() + faceDisp
429  // );
430  // dumpMove
431  // (
432  // mesh.time().path()
433  // / "faceRotation_" + name(iter) + ".obj",
434  // pp.faceCentres(),
435  // pp.faceCentres() + faceRotation
436  // );
437  //}
438 }
439 
440 
441 // Collect (possibly remote) per point data of all surrounding faces
442 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
443 // - faceSurfaceNormal
444 // - faceDisp
445 // - faceCentres&faceNormal
447 (
448  const label iter,
449  const indirectPrimitivePatch& pp,
450 
451  const vectorField& faceDisp,
452  const vectorField& faceSurfaceNormal,
453  const labelList& faceSurfaceGlobalRegion,
454 
455  List<List<point> >& pointFaceSurfNormals,
456  List<List<point> >& pointFaceDisp,
457  List<List<point> >& pointFaceCentres,
458  List<labelList>& pointFacePatchID
459 ) const
460 {
461  const fvMesh& mesh = meshRefiner_.mesh();
462 
463  const PackedBoolList isMasterFace(syncTools::getMasterFaces(mesh));
464 
465 
466  // For now just get all surrounding face data. Expensive - should just
467  // store and sync data on coupled points only
468  // (see e.g PatchToolsNormals.C)
469 
470  pointFaceSurfNormals.setSize(pp.nPoints());
471  pointFaceDisp.setSize(pp.nPoints());
472  pointFaceCentres.setSize(pp.nPoints());
473  pointFacePatchID.setSize(pp.nPoints());
474 
475  // Fill local data
476  forAll(pp.pointFaces(), pointI)
477  {
478  const labelList& pFaces = pp.pointFaces()[pointI];
479 
480  // Count valid face normals
481  label nFaces = 0;
482  forAll(pFaces, i)
483  {
484  label faceI = pFaces[i];
485  if (isMasterFace[faceI] && faceSurfaceGlobalRegion[faceI] != -1)
486  {
487  nFaces++;
488  }
489  }
490 
491 
492  List<point>& pNormals = pointFaceSurfNormals[pointI];
493  pNormals.setSize(nFaces);
494  List<point>& pDisp = pointFaceDisp[pointI];
495  pDisp.setSize(nFaces);
496  List<point>& pFc = pointFaceCentres[pointI];
497  pFc.setSize(nFaces);
498  labelList& pFid = pointFacePatchID[pointI];
499  pFid.setSize(nFaces);
500 
501  nFaces = 0;
502  forAll(pFaces, i)
503  {
504  label faceI = pFaces[i];
505  label globalRegionI = faceSurfaceGlobalRegion[faceI];
506 
507  if (isMasterFace[faceI] && globalRegionI != -1)
508  {
509  pNormals[nFaces] = faceSurfaceNormal[faceI];
510  pDisp[nFaces] = faceDisp[faceI];
511  pFc[nFaces] = pp.faceCentres()[faceI];
512  pFid[nFaces] = globalToMasterPatch_[globalRegionI];
513  nFaces++;
514  }
515  }
516  }
517 
518 
519  // Collect additionally 'normal' boundary faces for boundaryPoints of pp
520  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
521  // points on the boundary of pp should pick up non-pp normals
522  // as well for the feature-reconstruction to behave correctly.
523  // (the movement is already constrained outside correctly so it
524  // is only that the unconstrained attraction vector is calculated
525  // correctly)
526  {
527  const polyBoundaryMesh& pbm = mesh.boundaryMesh();
528  labelList patchID(pbm.patchID());
529 
530  // Unmark all non-coupled boundary faces
531  forAll(pbm, patchI)
532  {
533  const polyPatch& pp = pbm[patchI];
534 
535  if (pp.coupled() || isA<emptyPolyPatch>(pp))
536  {
537  forAll(pp, i)
538  {
539  label meshFaceI = pp.start()+i;
540  patchID[meshFaceI-mesh.nInternalFaces()] = -1;
541  }
542  }
543  }
544 
545  // Remove any meshed faces
546  forAll(pp.addressing(), i)
547  {
548  label meshFaceI = pp.addressing()[i];
549  patchID[meshFaceI-mesh.nInternalFaces()] = -1;
550  }
551 
552 
553 
554  // See if edge of pp uses any non-meshed boundary faces. If so add the
555  // boundary face as additional constraint. Note that we account for
556  // both 'real' boundary edges and boundary edge of baffles
557 
558  const labelList bafflePair
559  (
560  localPointRegion::findDuplicateFaces(mesh, pp.addressing())
561  );
562 
563 
564  // Mark all points on 'boundary' edges
565  PackedBoolList isBoundaryPoint(pp.nPoints());
566 
567  const labelListList& edgeFaces = pp.edgeFaces();
568  const edgeList& edges = pp.edges();
569 
570  forAll(edgeFaces, edgeI)
571  {
572  const edge& e = edges[edgeI];
573  const labelList& eFaces = edgeFaces[edgeI];
574 
575  if (eFaces.size() == 1)
576  {
577  // 'real' boundary edge
578  isBoundaryPoint[e[0]] = true;
579  isBoundaryPoint[e[1]] = true;
580  }
581  else if (eFaces.size() == 2 && bafflePair[eFaces[0]] == eFaces[1])
582  {
583  // 'baffle' boundary edge
584  isBoundaryPoint[e[0]] = true;
585  isBoundaryPoint[e[1]] = true;
586  }
587  }
588 
589 
590  // Construct labelList equivalent of meshPointMap
591  labelList meshToPatchPoint(mesh.nPoints(), -1);
592  forAll(pp.meshPoints(), pointI)
593  {
594  meshToPatchPoint[pp.meshPoints()[pointI]] = pointI;
595  }
596 
597  forAll(patchID, bFaceI)
598  {
599  label patchI = patchID[bFaceI];
600 
601  if (patchI != -1)
602  {
603  label faceI = mesh.nInternalFaces()+bFaceI;
604  const face& f = mesh.faces()[faceI];
605 
606  forAll(f, fp)
607  {
608  label pointI = meshToPatchPoint[f[fp]];
609 
610  if (pointI != -1 && isBoundaryPoint[pointI])
611  {
612  List<point>& pNormals = pointFaceSurfNormals[pointI];
613  List<point>& pDisp = pointFaceDisp[pointI];
614  List<point>& pFc = pointFaceCentres[pointI];
615  labelList& pFid = pointFacePatchID[pointI];
616 
617  const point& pt = mesh.points()[f[fp]];
618  vector fn = mesh.faceAreas()[faceI];
619 
620  pNormals.append(fn/mag(fn));
621  pDisp.append(mesh.faceCentres()[faceI]-pt);
622  pFc.append(mesh.faceCentres()[faceI]);
623  pFid.append(patchI);
624  }
625  }
626  }
627  }
628  }
629 
630  syncTools::syncPointList
631  (
632  mesh,
633  pp.meshPoints(),
634  pointFaceSurfNormals,
636  List<point>(),
638  );
639  syncTools::syncPointList
640  (
641  mesh,
642  pp.meshPoints(),
643  pointFaceDisp,
645  List<point>(),
647  );
648  syncTools::syncPointList
649  (
650  mesh,
651  pp.meshPoints(),
652  pointFaceCentres,
654  List<point>(),
656  );
657  syncTools::syncPointList
658  (
659  mesh,
660  pp.meshPoints(),
661  pointFacePatchID,
663  List<label>()
664  );
665 
666 
667  // Sort the data according to the face centres. This is only so we get
668  // consistent behaviour serial and parallel.
669  labelList visitOrder;
670  forAll(pointFaceDisp, pointI)
671  {
672  List<point>& pNormals = pointFaceSurfNormals[pointI];
673  List<point>& pDisp = pointFaceDisp[pointI];
674  List<point>& pFc = pointFaceCentres[pointI];
675  labelList& pFid = pointFacePatchID[pointI];
676 
677  sortedOrder(mag(pFc)(), visitOrder);
678 
679  pNormals = List<point>(pNormals, visitOrder);
680  pDisp = List<point>(pDisp, visitOrder);
681  pFc = List<point>(pFc, visitOrder);
682  pFid = UIndirectList<label>(pFid, visitOrder)();
683  }
684 }
685 
686 
687 // Gets passed in offset to nearest point on feature edge. Calculates
688 // if the point has a different number of faces on either side of the feature
689 // and if so attracts the point to that non-dominant plane.
691 (
692  const DynamicList<point>& surfacePoints,
693  const DynamicList<label>& surfaceCounts,
694  const point& edgePt,
695  const vector& edgeNormal, // normalised normal
696  const point& pt,
697 
698  vector& edgeOffset // offset from pt to point on edge
699 ) const
700 {
701  // Tangential component along edge
702  scalar tang = ((pt-edgePt)&edgeNormal);
703 
704  labelList order;
705  Foam::sortedOrder(surfaceCounts, order);
706 
707  if (order[0] < order[1])
708  {
709  // There is a non-dominant plane. Use the point on the plane to
710  // attract to.
711  vector attractD = surfacePoints[order[0]]-edgePt;
712  // Tangential component along edge
713  scalar tang2 = (attractD&edgeNormal);
714  // Normal component
715  attractD -= tang2*edgeNormal;
716  // Calculate fraction of normal distances
717  scalar magAttractD = mag(attractD);
718  scalar fraction = magAttractD/(magAttractD+mag(edgeOffset));
719 
720  point linePt =
721  edgePt
722  + ((1.0-fraction)*tang2 + fraction*tang)*edgeNormal;
723  edgeOffset = linePt-pt;
724  }
725 }
726 
727 
729 (
730  const point& pt,
731  const labelList& patchIDs,
732  const List<point>& faceCentres
733 ) const
734 {
735  // Determine if multiple patchIDs
736  if (patchIDs.size())
737  {
738  label patch0 = patchIDs[0];
739 
740  for (label i = 1; i < patchIDs.size(); i++)
741  {
742  if (patchIDs[i] != patch0)
743  {
744  return pointIndexHit(true, pt, labelMax);
745  }
746  }
747  }
748  return pointIndexHit(false, vector::zero, labelMax);
749 }
750 
751 
753 (
754  const scalar featureCos,
755  const vector& n,
756  const DynamicList<vector>& surfaceNormals
757 ) const
758 {
759  label index = -1;
760 
761  forAll(surfaceNormals, j)
762  {
763  scalar cosAngle = (n&surfaceNormals[j]);
764 
765  if
766  (
767  (cosAngle >= featureCos)
768  || (cosAngle < (-1+0.001)) // triangle baffles
769  )
770  {
771  index = j;
772  break;
773  }
774  }
775  return index;
776 }
777 
778 
779 // Detect multiple patches. Returns pointIndexHit:
780 // - false, index=-1 : single patch
781 // - true , index=0 : multiple patches but on different normals planes
782 // (so geometric feature edge is also a region edge)
783 // - true , index=1 : multiple patches on same normals plane i.e. flat region
784 // edge
786 (
787  const point& pt,
788  const labelList& patchIDs,
789  const DynamicList<vector>& surfaceNormals,
790  const labelList& faceToNormalBin
791 ) const
792 {
793  if (patchIDs.empty())
794  {
795  return pointIndexHit(false, pt, -1);
796  }
797 
798  // Detect single patch situation (to avoid allocation)
799  label patch0 = patchIDs[0];
800 
801  for (label i = 1; i < patchIDs.size(); i++)
802  {
803  if (patchIDs[i] != patch0)
804  {
805  patch0 = -1;
806  break;
807  }
808  }
809 
810  if (patch0 >= 0)
811  {
812  // Single patch
813  return pointIndexHit(false, pt, -1);
814  }
815  else
816  {
817  if (surfaceNormals.size() == 1)
818  {
819  // Same normals plane, flat region edge.
820  return pointIndexHit(true, pt, 1);
821  }
822  else
823  {
824  // Detect per normals bin
825  labelList normalToPatch(surfaceNormals.size(), -1);
826  forAll(faceToNormalBin, i)
827  {
828  if (faceToNormalBin[i] != -1)
829  {
830  label& patch = normalToPatch[faceToNormalBin[i]];
831  if (patch == -1)
832  {
833  // First occurence
834  patch = patchIDs[i];
835  }
836  else if (patch == -2)
837  {
838  // Already marked as being on multiple patches
839  }
840  else if (patch != patchIDs[i])
841  {
842  // Mark as being on multiple patches
843  patch = -2;
844  }
845  }
846  }
847 
848  forAll(normalToPatch, normalI)
849  {
850  if (normalToPatch[normalI] == -2)
851  {
852  // Multiple patches on same normals plane, flat region
853  // edge
854  return pointIndexHit(true, pt, 1);
855  }
856  }
857 
858  // All patches on either side of geometric feature anyway
859  return pointIndexHit(true, pt, 0);
860  }
861  }
862 }
863 
864 
866 (
867  const indirectPrimitivePatch& pp,
868  const PackedBoolList& isPatchMasterPoint,
869  const List<pointConstraint>& patchConstraints
870 ) const
871 {
872  label nMasterPoints = 0;
873  label nPlanar = 0;
874  label nEdge = 0;
875  label nPoint = 0;
876 
877  forAll(patchConstraints, pointI)
878  {
879  if (isPatchMasterPoint[pointI])
880  {
881  nMasterPoints++;
882 
883  if (patchConstraints[pointI].first() == 1)
884  {
885  nPlanar++;
886  }
887  else if (patchConstraints[pointI].first() == 2)
888  {
889  nEdge++;
890  }
891  else if (patchConstraints[pointI].first() == 3)
892  {
893  nPoint++;
894  }
895  }
896  }
897 
898  reduce(nMasterPoints, sumOp<label>());
899  reduce(nPlanar, sumOp<label>());
900  reduce(nEdge, sumOp<label>());
901  reduce(nPoint, sumOp<label>());
902  Info<< "total master points :" << nMasterPoints
903  << " of which attracted to :" << nl
904  << " feature point : " << nPoint << nl
905  << " feature edge : " << nEdge << nl
906  << " nearest surface : " << nPlanar << nl
907  << " rest : " << nMasterPoints-nPoint-nEdge-nPlanar
908  << nl
909  << endl;
910 }
911 
912 
914 (
915  const label iter,
916  const scalar featureCos,
917 
918  const indirectPrimitivePatch& pp,
919  const scalarField& snapDist,
920  const vectorField& nearestDisp,
921  const label pointI,
922 
923  const List<List<point> >& pointFaceSurfNormals,
924  const List<List<point> >& pointFaceDisp,
925  const List<List<point> >& pointFaceCentres,
926  const labelListList& pointFacePatchID,
927 
928  DynamicList<point>& surfacePoints,
929  DynamicList<vector>& surfaceNormals,
930  labelList& faceToNormalBin,
931 
932  vector& patchAttraction,
933  pointConstraint& patchConstraint
934 ) const
935 {
936  patchAttraction = vector::zero;
937  patchConstraint = pointConstraint();
938 
939  const List<point>& pfSurfNormals = pointFaceSurfNormals[pointI];
940  const List<point>& pfDisp = pointFaceDisp[pointI];
941  const List<point>& pfCentres = pointFaceCentres[pointI];
942 
943  // Bin according to surface normal
944  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
945 
946  //- Bins of differing normals:
947  // - one normal : flat(tish) surface
948  // - two normals : geometric feature edge
949  // - three normals: geometric feature point
950  // - four normals : too complex a feature
951  surfacePoints.clear();
952  surfaceNormals.clear();
953 
954  //- From face to above normals bin
955  faceToNormalBin.setSize(pfDisp.size());
956  faceToNormalBin = -1;
957 
958  forAll(pfSurfNormals, i)
959  {
960  const point& fc = pfCentres[i];
961  const vector& fSNormal = pfSurfNormals[i];
962  const vector& fDisp = pfDisp[i];
963 
964  // What to do with very far attraction? For now just ignore the face
965  if (magSqr(fDisp) < sqr(snapDist[pointI]) && mag(fSNormal) > VSMALL)
966  {
967  const point pt = fc + fDisp;
968 
969  // Do we already have surface normal?
970  faceToNormalBin[i] = findNormal
971  (
972  featureCos,
973  fSNormal,
974  surfaceNormals
975  );
976 
977  if (faceToNormalBin[i] != -1)
978  {
979  // Same normal
980  }
981  else
982  {
983  // Now check if the planes go through the same edge or point
984 
985  if (surfacePoints.size() <= 1)
986  {
987  surfacePoints.append(pt);
988  faceToNormalBin[i] = surfaceNormals.size();
989  surfaceNormals.append(fSNormal);
990  }
991  else if (surfacePoints.size() == 2)
992  {
993  plane pl0(surfacePoints[0], surfaceNormals[0]);
994  plane pl1(surfacePoints[1], surfaceNormals[1]);
995  plane::ray r(pl0.planeIntersect(pl1));
996  vector featureNormal = r.dir() / mag(r.dir());
997 
998  if (mag(fSNormal&featureNormal) >= 0.001)
999  {
1000  // Definitely makes a feature point
1001  surfacePoints.append(pt);
1002  faceToNormalBin[i] = surfaceNormals.size();
1003  surfaceNormals.append(fSNormal);
1004  }
1005  }
1006  else if (surfacePoints.size() == 3)
1007  {
1008  // Have already feature point. See if this new plane is
1009  // the same point or not.
1010  plane pl0(surfacePoints[0], surfaceNormals[0]);
1011  plane pl1(surfacePoints[1], surfaceNormals[1]);
1012  plane pl2(surfacePoints[2], surfaceNormals[2]);
1013  point p012(pl0.planePlaneIntersect(pl1, pl2));
1014 
1015  plane::ray r(pl0.planeIntersect(pl1));
1016  vector featureNormal = r.dir() / mag(r.dir());
1017  if (mag(fSNormal&featureNormal) >= 0.001)
1018  {
1019  plane pl3(pt, fSNormal);
1020  point p013(pl0.planePlaneIntersect(pl1, pl3));
1021 
1022  if (mag(p012-p013) > snapDist[pointI])
1023  {
1024  // Different feature point
1025  surfacePoints.append(pt);
1026  faceToNormalBin[i] = surfaceNormals.size();
1027  surfaceNormals.append(fSNormal);
1028  }
1029  }
1030  }
1031  }
1032  }
1033  }
1034 
1035 
1036  const point& pt = pp.localPoints()[pointI];
1037 
1038  // Check the number of directions
1039  if (surfaceNormals.size() == 1)
1040  {
1041  // Normal distance to plane
1042  vector d =
1043  ((surfacePoints[0]-pt) & surfaceNormals[0])
1044  *surfaceNormals[0];
1045 
1046  // Trim to snap distance
1047  if (magSqr(d) > sqr(snapDist[pointI]))
1048  {
1049  d *= Foam::sqrt(sqr(snapDist[pointI])/magSqr(d));
1050  }
1051 
1052  patchAttraction = d;
1053 
1054  // Store constraints
1055  patchConstraint.applyConstraint(surfaceNormals[0]);
1056  }
1057  else if (surfaceNormals.size() == 2)
1058  {
1059  plane pl0(surfacePoints[0], surfaceNormals[0]);
1060  plane pl1(surfacePoints[1], surfaceNormals[1]);
1061  plane::ray r(pl0.planeIntersect(pl1));
1062  vector n = r.dir() / mag(r.dir());
1063 
1064  // Get nearest point on infinite ray
1065  vector d = r.refPoint()-pt;
1066  d -= (d&n)*n;
1067 
1068  // Trim to snap distance
1069  if (magSqr(d) > sqr(snapDist[pointI]))
1070  {
1071  d *= Foam::sqrt(sqr(snapDist[pointI])/magSqr(d));
1072  }
1073 
1074  patchAttraction = d;
1075 
1076  // Store constraints
1077  patchConstraint.applyConstraint(surfaceNormals[0]);
1078  patchConstraint.applyConstraint(surfaceNormals[1]);
1079  }
1080  else if (surfaceNormals.size() == 3)
1081  {
1082  // Calculate point from the faces.
1083  plane pl0(surfacePoints[0], surfaceNormals[0]);
1084  plane pl1(surfacePoints[1], surfaceNormals[1]);
1085  plane pl2(surfacePoints[2], surfaceNormals[2]);
1086  point cornerPt(pl0.planePlaneIntersect(pl1, pl2));
1087  vector d = cornerPt - pt;
1088 
1089  // Trim to snap distance
1090  if (magSqr(d) > sqr(snapDist[pointI]))
1091  {
1092  d *= Foam::sqrt(sqr(snapDist[pointI])/magSqr(d));
1093  }
1094 
1095  patchAttraction = d;
1096 
1097  // Store constraints
1098  patchConstraint.applyConstraint(surfaceNormals[0]);
1099  patchConstraint.applyConstraint(surfaceNormals[1]);
1100  patchConstraint.applyConstraint(surfaceNormals[2]);
1101  }
1102 }
1103 
1104 
1105 // Special version that calculates attraction in one go
1108  const label iter,
1109  const scalar featureCos,
1110 
1111  const indirectPrimitivePatch& pp,
1112  const scalarField& snapDist,
1113  const vectorField& nearestDisp,
1114 
1115  const List<List<point> >& pointFaceSurfNormals,
1116  const List<List<point> >& pointFaceDisp,
1117  const List<List<point> >& pointFaceCentres,
1118  const labelListList& pointFacePatchID,
1119 
1120  vectorField& patchAttraction,
1121  List<pointConstraint>& patchConstraints
1122 ) const
1123 {
1124  autoPtr<OBJstream> feStr;
1125  autoPtr<OBJstream> fpStr;
1126  if (debug&meshRefinement::ATTRACTION)
1127  {
1128  feStr.reset
1129  (
1130  new OBJstream
1131  (
1132  meshRefiner_.mesh().time().path()
1133  / "implicitFeatureEdge_" + name(iter) + ".obj"
1134  )
1135  );
1136  Info<< "Dumping implicit feature-edge direction to "
1137  << feStr().name() << endl;
1138 
1139  fpStr.reset
1140  (
1141  new OBJstream
1142  (
1143  meshRefiner_.mesh().time().path()
1144  / "implicitFeaturePoint_" + name(iter) + ".obj"
1145  )
1146  );
1147  Info<< "Dumping implicit feature-point direction to "
1148  << fpStr().name() << endl;
1149  }
1150 
1151 
1152  DynamicList<point> surfacePoints(4);
1153  DynamicList<vector> surfaceNormals(4);
1154  labelList faceToNormalBin;
1155 
1156  forAll(pp.localPoints(), pointI)
1157  {
1158  vector attraction = vector::zero;
1159  pointConstraint constraint;
1160 
1161  featureAttractionUsingReconstruction
1162  (
1163  iter,
1164  featureCos,
1165 
1166  pp,
1167  snapDist,
1168  nearestDisp,
1169 
1170  pointI,
1171 
1172  pointFaceSurfNormals,
1173  pointFaceDisp,
1174  pointFaceCentres,
1175  pointFacePatchID,
1176 
1177  surfacePoints,
1178  surfaceNormals,
1179  faceToNormalBin,
1180 
1181  attraction,
1182  constraint
1183  );
1184 
1185  if
1186  (
1187  (constraint.first() > patchConstraints[pointI].first())
1188  || (
1189  (constraint.first() == patchConstraints[pointI].first())
1190  && (magSqr(attraction) < magSqr(patchAttraction[pointI]))
1191  )
1192  )
1193  {
1194  patchAttraction[pointI] = attraction;
1195  patchConstraints[pointI] = constraint;
1196 
1197  const point& pt = pp.localPoints()[pointI];
1198 
1199  if (patchConstraints[pointI].first() == 2 && feStr.valid())
1200  {
1201  feStr().write(linePointRef(pt, pt+patchAttraction[pointI]));
1202  }
1203  else if (patchConstraints[pointI].first() == 3 && fpStr.valid())
1204  {
1205  fpStr().write(linePointRef(pt, pt+patchAttraction[pointI]));
1206  }
1207  }
1208  }
1209 }
1210 
1211 
1214  const label iter,
1215  const scalar featureCos,
1216 
1217  const indirectPrimitivePatch& pp,
1218  const scalarField& snapDist,
1219 
1220  const vectorField& rawPatchAttraction,
1221  const List<pointConstraint>& rawPatchConstraints,
1222 
1223  vectorField& patchAttraction,
1224  List<pointConstraint>& patchConstraints
1225 ) const
1226 {
1227  // Snap edges to feature edges
1228  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
1229  // Walk existing edges and snap remaining ones (that are marked as
1230  // feature edges in rawPatchConstraints)
1231 
1232  // What this does is fill in any faces where not all points
1233  // on the face are being attracted:
1234  /*
1235  +
1236  / \
1237  / \
1238  ---+ +---
1239  \ /
1240  \ /
1241  +
1242  */
1243  // so the top and bottom will never get attracted since the nearest
1244  // back from the feature edge will always be one of the left or right
1245  // points since the face is diamond like. So here we walk the feature edges
1246  // and add any non-attracted points.
1247 
1248 
1249  while (true)
1250  {
1251  label nChanged = 0;
1252 
1253  const labelListList& pointEdges = pp.pointEdges();
1254  forAll(pointEdges, pointI)
1255  {
1256  if (patchConstraints[pointI].first() == 2)
1257  {
1258  const point& pt = pp.localPoints()[pointI];
1259  const labelList& pEdges = pointEdges[pointI];
1260  const vector& featVec = patchConstraints[pointI].second();
1261 
1262  // Detect whether there are edges in both directions.
1263  // (direction along the feature edge that is)
1264  bool hasPos = false;
1265  bool hasNeg = false;
1266 
1267  forAll(pEdges, pEdgeI)
1268  {
1269  const edge& e = pp.edges()[pEdges[pEdgeI]];
1270  label nbrPointI = e.otherVertex(pointI);
1271 
1272  if (patchConstraints[nbrPointI].first() > 1)
1273  {
1274  const point& nbrPt = pp.localPoints()[nbrPointI];
1275  const point featPt =
1276  nbrPt + patchAttraction[nbrPointI];
1277  const scalar cosAngle = (featVec & (featPt-pt));
1278 
1279  if (cosAngle > 0)
1280  {
1281  hasPos = true;
1282  }
1283  else
1284  {
1285  hasNeg = true;
1286  }
1287  }
1288  }
1289 
1290  if (!hasPos || !hasNeg)
1291  {
1292  //Pout<< "**Detected feature string end at "
1293  // << pp.localPoints()[pointI] << endl;
1294 
1295  // No string. Assign best choice on either side
1296  label bestPosPointI = -1;
1297  scalar minPosDistSqr = GREAT;
1298  label bestNegPointI = -1;
1299  scalar minNegDistSqr = GREAT;
1300 
1301  forAll(pEdges, pEdgeI)
1302  {
1303  const edge& e = pp.edges()[pEdges[pEdgeI]];
1304  label nbrPointI = e.otherVertex(pointI);
1305 
1306  if
1307  (
1308  patchConstraints[nbrPointI].first() <= 1
1309  && rawPatchConstraints[nbrPointI].first() > 1
1310  )
1311  {
1312  const vector& nbrFeatVec =
1313  rawPatchConstraints[pointI].second();
1314 
1315  if (mag(featVec&nbrFeatVec) > featureCos)
1316  {
1317  // nbrPointI attracted to sameish feature
1318  // Note: also check on position.
1319 
1320  scalar d2 = magSqr
1321  (
1322  rawPatchAttraction[nbrPointI]
1323  );
1324 
1325  const point featPt =
1326  pp.localPoints()[nbrPointI]
1327  + rawPatchAttraction[nbrPointI];
1328  const scalar cosAngle =
1329  (featVec & (featPt-pt));
1330 
1331  if (cosAngle > 0)
1332  {
1333  if (!hasPos && d2 < minPosDistSqr)
1334  {
1335  minPosDistSqr = d2;
1336  bestPosPointI = nbrPointI;
1337  }
1338  }
1339  else
1340  {
1341  if (!hasNeg && d2 < minNegDistSqr)
1342  {
1343  minNegDistSqr = d2;
1344  bestNegPointI = nbrPointI;
1345  }
1346  }
1347  }
1348  }
1349  }
1350 
1351  if (bestPosPointI != -1)
1352  {
1353  // Use reconstructed-feature attraction. Use only
1354  // part of it since not sure...
1355  //const point& bestPt =
1356  // pp.localPoints()[bestPosPointI];
1357  //Pout<< "**Overriding point " << bestPt
1358  // << " on reconstructed feature edge at "
1359  // << rawPatchAttraction[bestPosPointI]+bestPt
1360  // << " to attracted-to-feature-edge." << endl;
1361  patchAttraction[bestPosPointI] =
1362  0.5*rawPatchAttraction[bestPosPointI];
1363  patchConstraints[bestPosPointI] =
1364  rawPatchConstraints[bestPosPointI];
1365 
1366  nChanged++;
1367  }
1368  if (bestNegPointI != -1)
1369  {
1370  // Use reconstructed-feature attraction. Use only
1371  // part of it since not sure...
1372  //const point& bestPt =
1373  // pp.localPoints()[bestNegPointI];
1374  //Pout<< "**Overriding point " << bestPt
1375  // << " on reconstructed feature edge at "
1376  // << rawPatchAttraction[bestNegPointI]+bestPt
1377  // << " to attracted-to-feature-edge." << endl;
1378  patchAttraction[bestNegPointI] =
1379  0.5*rawPatchAttraction[bestNegPointI];
1380  patchConstraints[bestNegPointI] =
1381  rawPatchConstraints[bestNegPointI];
1382 
1383  nChanged++;
1384  }
1385  }
1386  }
1387  }
1388 
1389 
1390  reduce(nChanged, sumOp<label>());
1391  Info<< "Stringing feature edges : changed " << nChanged << " points"
1392  << endl;
1393  if (nChanged == 0)
1394  {
1395  break;
1396  }
1397  }
1398 }
1399 
1400 
1403  const label iter,
1404  const scalar featureCos,
1405 
1406  const indirectPrimitivePatch& pp,
1407  const scalarField& snapDist,
1408 
1409  const List<List<point> >& pointFaceCentres,
1410  const labelListList& pointFacePatchID,
1411 
1412  const vectorField& rawPatchAttraction,
1413  const List<pointConstraint>& rawPatchConstraints,
1414 
1415  vectorField& patchAttraction,
1416  List<pointConstraint>& patchConstraints
1417 ) const
1418 {
1419  autoPtr<OBJstream> multiPatchStr;
1420  if (debug&meshRefinement::ATTRACTION)
1421  {
1422  multiPatchStr.reset
1423  (
1424  new OBJstream
1425  (
1426  meshRefiner_.mesh().time().path()
1427  / "multiPatch_" + name(iter) + ".obj"
1428  )
1429  );
1430  Info<< "Dumping removed constraints due to same-face"
1431  << " multi-patch points to "
1432  << multiPatchStr().name() << endl;
1433  }
1434 
1435 
1436  // 1. Mark points on multiple patches
1437  PackedBoolList isMultiPatchPoint(pp.size());
1438 
1439  forAll(pointFacePatchID, pointI)
1440  {
1441  pointIndexHit multiPatchPt = findMultiPatchPoint
1442  (
1443  pp.localPoints()[pointI],
1444  pointFacePatchID[pointI],
1445  pointFaceCentres[pointI]
1446  );
1447  isMultiPatchPoint[pointI] = multiPatchPt.hit();
1448  }
1449 
1450  // 2. Make sure multi-patch points are also attracted
1451  forAll(isMultiPatchPoint, pointI)
1452  {
1453  if (isMultiPatchPoint[pointI])
1454  {
1455  if
1456  (
1457  patchConstraints[pointI].first() <= 1
1458  && rawPatchConstraints[pointI].first() > 1
1459  )
1460  {
1461  patchAttraction[pointI] = rawPatchAttraction[pointI];
1462  patchConstraints[pointI] = rawPatchConstraints[pointI];
1463 
1464  //if (multiPatchStr.valid())
1465  //{
1466  // Pout<< "Adding constraint on multiPatchPoint:"
1467  // << pp.localPoints()[pointI]
1468  // << " constraint:" << patchConstraints[pointI]
1469  // << " attraction:" << patchAttraction[pointI]
1470  // << endl;
1471  //}
1472  }
1473  }
1474  }
1475 
1476  // Up to here it is all parallel ok.
1477 
1478 
1479  // 3. Knock out any attraction on faces with multi-patch points
1480  label nChanged = 0;
1481  forAll(pp.localFaces(), faceI)
1482  {
1483  const face& f = pp.localFaces()[faceI];
1484 
1485  label nMultiPatchPoints = 0;
1486  forAll(f, fp)
1487  {
1488  label pointI = f[fp];
1489  if
1490  (
1491  isMultiPatchPoint[pointI]
1492  && patchConstraints[pointI].first() > 1
1493  )
1494  {
1495  nMultiPatchPoints++;
1496  }
1497  }
1498 
1499  if (nMultiPatchPoints > 0)
1500  {
1501  forAll(f, fp)
1502  {
1503  label pointI = f[fp];
1504  if
1505  (
1506  !isMultiPatchPoint[pointI]
1507  && patchConstraints[pointI].first() > 1
1508  )
1509  {
1510  //Pout<< "Knocking out constraint"
1511  // << " on non-multiPatchPoint:"
1512  // << pp.localPoints()[pointI] << endl;
1513  patchAttraction[pointI] = vector::zero;
1514  patchConstraints[pointI] = pointConstraint();
1515  nChanged++;
1516 
1517  if (multiPatchStr.valid())
1518  {
1519  multiPatchStr().write(pp.localPoints()[pointI]);
1520  }
1521  }
1522  }
1523  }
1524  }
1525 
1526  reduce(nChanged, sumOp<label>());
1527  Info<< "Removing constraints near multi-patch points : changed "
1528  << nChanged << " points" << endl;
1529 }
1530 
1531 
1534  const indirectPrimitivePatch& pp,
1535  const vectorField& patchAttraction,
1536  const List<pointConstraint>& patchConstraints,
1537  const label faceI
1538 ) const
1539 {
1540  const face& f = pp.localFaces()[faceI];
1541  // For now just detect any attraction. Improve this to look at
1542  // actual attraction position and orientation
1543 
1544  labelPair attractIndices(-1, -1);
1545 
1546  if (f.size() >= 4)
1547  {
1548  for (label startFp = 0; startFp < f.size()-2; startFp++)
1549  {
1550  label minFp = f.rcIndex(startFp);
1551 
1552  for
1553  (
1554  label endFp = f.fcIndex(f.fcIndex(startFp));
1555  endFp < f.size() && endFp != minFp;
1556  endFp++
1557  )
1558  {
1559  if
1560  (
1561  patchConstraints[f[startFp]].first() >= 2
1562  && patchConstraints[f[endFp]].first() >= 2
1563  )
1564  {
1565  attractIndices = labelPair(startFp, endFp);
1566  break;
1567  }
1568  }
1569  }
1570  }
1571  return attractIndices;
1572 }
1573 
1574 
1577  const scalar featureCos,
1578  const point& p0,
1579  const pointConstraint& pc0,
1580  const point& p1,
1581  const pointConstraint& pc1
1582 ) const
1583 {
1584  vector d(p1-p0);
1585  scalar magD = mag(d);
1586  if (magD < VSMALL)
1587  {
1588  // Two diagonal points already colocated?
1589  return false;
1590  }
1591  else
1592  {
1593  d /= magD;
1594 
1595  // Is diagonal d aligned with at least one of the feature
1596  // edges?
1597 
1598  if (pc0.first() == 2 && mag(d & pc0.second()) > featureCos)
1599  {
1600  return true;
1601  }
1602  else if (pc1.first() == 2 && mag(d & pc1.second()) > featureCos)
1603  {
1604  return true;
1605  }
1606  else
1607  {
1608  return false;
1609  }
1610  }
1611 }
1612 
1613 
1614 // Is situation very concave
1617  const point& c0,
1618  const vector& area0,
1619  const point& c1,
1620  const vector& area1,
1621  const scalar concaveCos
1622 ) const
1623 {
1624  vector n0 = area0;
1625  scalar magN0 = mag(n0);
1626  if (magN0 < VSMALL)
1627  {
1628  // Zero area face. What to return? For now disable splitting.
1629  return true;
1630  }
1631  n0 /= magN0;
1632 
1633  // Distance from c1 to plane of face0
1634  scalar d = (c1-c0)&n0;
1635 
1636  if (d <= 0)
1637  {
1638  // Convex (face1 centre on 'inside' of face0)
1639  return false;
1640  }
1641  else
1642  {
1643  // Is a bit or very concave?
1644  vector n1 = area1;
1645  scalar magN1 = mag(n1);
1646  if (magN1 < VSMALL)
1647  {
1648  // Zero area face. See above
1649  return true;
1650  }
1651  n1 /= magN1;
1652 
1653  if ((n0&n1) < concaveCos)
1654  {
1655  return true;
1656  }
1657  else
1658  {
1659  return false;
1660  }
1661  }
1662 }
1663 
1664 
1667  const scalar featureCos,
1668  const scalar concaveCos,
1669  const scalar minAreaRatio,
1670  const indirectPrimitivePatch& pp,
1671  const vectorField& patchAttr,
1672  const List<pointConstraint>& patchConstraints,
1673  const vectorField& nearestAttr,
1674  const vectorField& nearestNormal,
1675  const label faceI,
1676 
1677  DynamicField<point>& points0,
1678  DynamicField<point>& points1
1679 ) const
1680 {
1681  const face& localF = pp.localFaces()[faceI];
1682 
1683  labelPair attractIndices(-1, -1);
1684 
1685  if (localF.size() >= 4)
1686  {
1687  const pointField& localPts = pp.localPoints();
1688 
1692  //const polyMesh& mesh = meshRefiner_.mesh();
1693  //label meshFaceI = pp.addressing()[faceI];
1694  //const face& meshF = mesh.faces()[meshFaceI];
1695  //label cellI = mesh.faceOwner()[meshFaceI];
1696  //const labelList& cPoints = mesh.cellPoints(cellI);
1697  //
1698  //point cc(mesh.points()[meshF[0]]);
1699  //for (label i = 1; i < meshF.size(); i++)
1700  //{
1701  // cc += mesh.points()[meshF[i]]+patchAttr[localF[i]];
1702  //}
1703  //forAll(cPoints, i)
1704  //{
1705  // label pointI = cPoints[i];
1706  // if (findIndex(meshF, pointI) == -1)
1707  // {
1708  // cc += mesh.points()[pointI];
1709  // }
1710  //}
1711  //cc /= cPoints.size();
1713  //
1714  //const scalar vol = pyrVol(pp, patchAttr, localF, cc);
1715  //const scalar area = localF.mag(localPts);
1716 
1717 
1718 
1719  // Try all diagonal cuts
1720  // ~~~~~~~~~~~~~~~~~~~~~
1721 
1722  face f0(3);
1723  face f1(3);
1724 
1725  for (label startFp = 0; startFp < localF.size()-2; startFp++)
1726  {
1727  label minFp = localF.rcIndex(startFp);
1728 
1729  for
1730  (
1731  label endFp = localF.fcIndex(localF.fcIndex(startFp));
1732  endFp < localF.size() && endFp != minFp;
1733  endFp++
1734  )
1735  {
1736  label startPtI = localF[startFp];
1737  label endPtI = localF[endFp];
1738 
1739  const pointConstraint& startPc = patchConstraints[startPtI];
1740  const pointConstraint& endPc = patchConstraints[endPtI];
1741 
1742  if (startPc.first() >= 2 && endPc.first() >= 2)
1743  {
1744  if (startPc.first() == 2 || endPc.first() == 2)
1745  {
1746  // Check if
1747  // - sameish feature edge normal
1748  // - diagonal aligned with feature edge normal
1749  point start = localPts[startPtI]+patchAttr[startPtI];
1750  point end = localPts[endPtI]+patchAttr[endPtI];
1751 
1752  if
1753  (
1754  !isSplitAlignedWithFeature
1755  (
1756  featureCos,
1757  start,
1758  startPc,
1759  end,
1760  endPc
1761  )
1762  )
1763  {
1764  // Attract to different features. No need to
1765  // introduce split
1766  continue;
1767  }
1768  }
1769 
1770 
1771 
1772  // Form two faces
1773  // ~~~~~~~~~~~~~~
1774  // Predict position of faces. End points of the faces
1775  // attract to the feature
1776  // and all the other points just attract to the nearest
1777 
1778  // face0
1779 
1780  f0.setSize(endFp-startFp+1);
1781  label i0 = 0;
1782  for (label fp = startFp; fp <= endFp; fp++)
1783  {
1784  f0[i0++] = localF[fp];
1785  }
1786 
1787  // Get compact face and points
1788  const face compact0(identity(f0.size()));
1789  points0.clear();
1790  points0.append(localPts[f0[0]] + patchAttr[f0[0]]);
1791  for (label fp=1; fp < f0.size()-1; fp++)
1792  {
1793  label pI = f0[fp];
1794  points0.append(localPts[pI] + nearestAttr[pI]);
1795  }
1796  points0.append
1797  (
1798  localPts[f0.last()] + patchAttr[f0.last()]
1799  );
1800 
1801 
1802  // face1
1803 
1804  f1.setSize(localF.size()+2-f0.size());
1805  label i1 = 0;
1806  for
1807  (
1808  label fp = endFp;
1809  fp != startFp;
1810  fp = localF.fcIndex(fp)
1811  )
1812  {
1813  f1[i1++] = localF[fp];
1814  }
1815  f1[i1++] = localF[startFp];
1816 
1817 
1818  // Get compact face and points
1819  const face compact1(identity(f1.size()));
1820  points1.clear();
1821  points1.append(localPts[f1[0]] + patchAttr[f1[0]]);
1822  for (label fp=1; fp < f1.size()-1; fp++)
1823  {
1824  label pI = f1[fp];
1825  points1.append(localPts[pI] + nearestAttr[pI]);
1826  }
1827  points1.append
1828  (
1829  localPts[f1.last()] + patchAttr[f1.last()]
1830  );
1831 
1832 
1833 
1834  // Avoid splitting concave faces
1835  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1836 
1837  if
1838  (
1839  isConcave
1840  (
1841  compact0.centre(points0),
1842  compact0.normal(points0),
1843  compact1.centre(points1),
1844  compact1.normal(points1),
1845  concaveCos
1846  )
1847  )
1848  {
1850  //Pout<< "# f0:" << f0 << endl;
1851  //forAll(p, i)
1852  //{
1853  // meshTools::writeOBJ(Pout, points0[i]);
1854  //}
1855  //Pout<< "# f1:" << f1 << endl;
1856  //forAll(p, i)
1857  //{
1858  // meshTools::writeOBJ(Pout, points1[i]);
1859  //}
1860  }
1861  else
1862  {
1863  // Existing areas
1864  const scalar area0 = f0.mag(localPts);
1865  const scalar area1 = f1.mag(localPts);
1866 
1867  if
1868  (
1869  area0/area1 >= minAreaRatio
1870  && area1/area0 >= minAreaRatio
1871  )
1872  {
1873  attractIndices = labelPair(startFp, endFp);
1874  }
1875  }
1876  }
1877  }
1878  }
1879  }
1880  return attractIndices;
1881 }
1882 
1883 
1886  const scalar featureCos,
1887  const scalar concaveCos,
1888  const scalar minAreaRatio,
1889 
1890  const indirectPrimitivePatch& pp,
1891  const vectorField& nearestAttraction,
1892  const vectorField& nearestNormal,
1893 
1894  vectorField& patchAttraction,
1895  List<pointConstraint>& patchConstraints,
1896  DynamicList<label>& splitFaces,
1897  DynamicList<labelPair>& splits
1898 ) const
1899 {
1900  const labelList& bFaces = pp.addressing();
1901 
1902  splitFaces.clear();
1903  splitFaces.setCapacity(bFaces.size());
1904  splits.clear();
1905  splits.setCapacity(bFaces.size());
1906 
1907 
1908  // Work arrays for storing points of face
1909  DynamicField<point> facePoints0;
1910  DynamicField<point> facePoints1;
1911 
1912  forAll(bFaces, faceI)
1913  {
1914  const labelPair split
1915  (
1916  findDiagonalAttraction
1917  (
1918  featureCos,
1919  concaveCos,
1920  minAreaRatio,
1921 
1922  pp,
1923  patchAttraction,
1924  patchConstraints,
1925 
1926  nearestAttraction,
1927  nearestNormal,
1928  faceI,
1929 
1930  facePoints0,
1931  facePoints1
1932  )
1933  );
1934 
1935  if (split != labelPair(-1, -1))
1936  {
1937  splitFaces.append(bFaces[faceI]);
1938  splits.append(split);
1939 
1940  const face& f = pp.localFaces()[faceI];
1941 
1942  // Knock out other attractions on face
1943  forAll(f, fp)
1944  {
1945  // Knock out any other constraints
1946  if
1947  (
1948  fp != split[0]
1949  && fp != split[1]
1950  && patchConstraints[f[fp]].first() >= 2
1951  )
1952  {
1953  patchConstraints[f[fp]] = pointConstraint
1954  (
1956  (
1957  1,
1958  nearestNormal[f[fp]]
1959  )
1960  );
1961  patchAttraction[f[fp]] = nearestAttraction[f[fp]];
1962  }
1963  }
1964  }
1965  }
1966 }
1967 
1968 
1971  const label iter,
1972  const scalar featureCos,
1973 
1974  const indirectPrimitivePatch& pp,
1975 
1976  vectorField& patchAttraction,
1977  List<pointConstraint>& patchConstraints
1978 ) const
1979 {
1980  forAll(pp.localFaces(), faceI)
1981  {
1982  const face& f = pp.localFaces()[faceI];
1983 
1984  labelPair diag = findDiagonalAttraction
1985  (
1986  pp,
1987  patchAttraction,
1988  patchConstraints,
1989  faceI
1990  );
1991 
1992  if (diag[0] != -1 && diag[1] != -1)
1993  {
1994  // Found two diagonal points that being attracted.
1995  // For now just attract my one to the average of those.
1996  const label i0 = f[diag[0]];
1997  const point pt0 =
1998  pp.localPoints()[i0]+patchAttraction[i0];
1999  const label i1 = f[diag[1]];
2000  const point pt1 =
2001  pp.localPoints()[i1]+patchAttraction[i1];
2002  const point mid = 0.5*(pt0+pt1);
2003 
2004  const scalar cosAngle = mag
2005  (
2006  patchConstraints[i0].second()
2007  & patchConstraints[i1].second()
2008  );
2009 
2010  //Pout<< "Found diagonal attraction at indices:"
2011  // << diag[0]
2012  // << " and " << diag[1]
2013  // << " with cosAngle:" << cosAngle
2014  // << " mid:" << mid << endl;
2015 
2016  if (cosAngle > featureCos)
2017  {
2018  // The two feature edges are roughly in the same direction.
2019  // Add the nearest of the other points in the face as
2020  // attractor
2021  label minFp = -1;
2022  scalar minDistSqr = GREAT;
2023  forAll(f, fp)
2024  {
2025  label pointI = f[fp];
2026  if (patchConstraints[pointI].first() <= 1)
2027  {
2028  const point& pt = pp.localPoints()[pointI];
2029  scalar distSqr = magSqr(mid-pt);
2030  if (distSqr < minDistSqr)
2031  {
2032  distSqr = minDistSqr;
2033  minFp = fp;
2034  }
2035  }
2036  }
2037  if (minFp != -1)
2038  {
2039  label minPointI = f[minFp];
2040  patchAttraction[minPointI] =
2041  mid-pp.localPoints()[minPointI];
2042  patchConstraints[minPointI] = patchConstraints[f[diag[0]]];
2043  }
2044  }
2045  else
2046  {
2047  //Pout<< "Diagonal attractors at" << nl
2048  // << " pt0:" << pt0
2049  // << " constraint:"
2050  // << patchConstraints[i0].second() << nl
2051  // << " pt1:" << pt1
2052  // << " constraint:"
2053  // << patchConstraints[i1].second() << nl
2054  // << " make too large an angle:"
2055  // << mag
2056  // (
2057  // patchConstraints[i0].second()
2058  // & patchConstraints[i1].second()
2059  // )
2060  // << endl;
2061  }
2062  }
2063  }
2064 }
2065 
2066 
2070  const bool isRegionEdge,
2071 
2072  const indirectPrimitivePatch& pp,
2073  const scalarField& snapDist,
2074  const label pointI,
2075  const point& estimatedPt,
2076 
2077  List<List<DynamicList<point> > >& edgeAttractors,
2078  List<List<DynamicList<pointConstraint> > >& edgeConstraints,
2079  vectorField& patchAttraction,
2080  List<pointConstraint>& patchConstraints
2081 ) const
2082 {
2083  const refinementFeatures& features = meshRefiner_.features();
2084 
2085  labelList nearEdgeFeat;
2086  List<pointIndexHit> nearEdgeInfo;
2087  vectorField nearNormal;
2088 
2089  if (isRegionEdge)
2090  {
2091  features.findNearestRegionEdge
2092  (
2093  pointField(1, estimatedPt),
2094  scalarField(1, sqr(snapDist[pointI])),
2095  nearEdgeFeat,
2096  nearEdgeInfo,
2097  nearNormal
2098  );
2099  }
2100  else
2101  {
2102  features.findNearestEdge
2103  (
2104  pointField(1, estimatedPt),
2105  scalarField(1, sqr(snapDist[pointI])),
2106  nearEdgeFeat,
2107  nearEdgeInfo,
2108  nearNormal
2109  );
2110  }
2111 
2112  const pointIndexHit& nearInfo = nearEdgeInfo[0];
2113  label featI = nearEdgeFeat[0];
2114 
2115  if (nearInfo.hit())
2116  {
2117  // So we have a point on the feature edge. Use this
2118  // instead of our estimate from planes.
2119  edgeAttractors[featI][nearInfo.index()].append
2120  (
2121  nearInfo.hitPoint()
2122  );
2123  pointConstraint c(Tuple2<label, vector>(2, nearNormal[0]));
2124  edgeConstraints[featI][nearInfo.index()].append(c);
2125 
2126  // Store for later use
2127  patchAttraction[pointI] = nearInfo.hitPoint()-pp.localPoints()[pointI];
2128  patchConstraints[pointI] = c;
2129  }
2130  return Tuple2<label, pointIndexHit>(featI, nearInfo);
2131 }
2132 
2133 
2137  const bool isRegionPoint,
2138 
2139  const indirectPrimitivePatch& pp,
2140  const scalarField& snapDist,
2141  const label pointI,
2142  const point& estimatedPt,
2143 
2144  // Feature-point to pp point
2145  List<labelList>& pointAttractor,
2147  // Feature-edge to pp point
2148  List<List<DynamicList<point> > >& edgeAttractors,
2149  List<List<DynamicList<pointConstraint> > >& edgeConstraints,
2150  // pp point to nearest feature
2151  vectorField& patchAttraction,
2152  List<pointConstraint>& patchConstraints
2153 ) const
2154 {
2155  const refinementFeatures& features = meshRefiner_.features();
2156 
2157  // Search for for featurePoints only! This ignores any non-feature points.
2158 
2159  labelList nearFeat;
2161  features.findNearestPoint
2162  (
2163  pointField(1, estimatedPt),
2164  scalarField(1, sqr(snapDist[pointI])),
2165  nearFeat,
2166  nearInfo
2167  );
2168 
2169  label featI = nearFeat[0];
2170 
2171  if (featI != -1)
2172  {
2173  const point& pt = pp.localPoints()[pointI];
2174 
2175  label featPointI = nearInfo[0].index();
2176  const point& featPt = nearInfo[0].hitPoint();
2177  scalar distSqr = magSqr(featPt-pt);
2178 
2179  // Check if already attracted
2180  label oldPointI = pointAttractor[featI][featPointI];
2181 
2182  if (oldPointI != -1)
2183  {
2184  // Check distance
2185  if (distSqr >= magSqr(featPt-pp.localPoints()[oldPointI]))
2186  {
2187  // oldPointI nearest. Keep.
2188  featI = -1;
2189  featPointI = -1;
2190  }
2191  else
2192  {
2193  // Current pointI nearer.
2194  pointAttractor[featI][featPointI] = pointI;
2195  pointConstraints[featI][featPointI].first() = 3;
2196  pointConstraints[featI][featPointI].second() = vector::zero;
2197 
2198  // Store for later use
2199  patchAttraction[pointI] = featPt-pt;
2200  patchConstraints[pointI] = pointConstraints[featI][featPointI];
2201 
2202  // Reset oldPointI to nearest on feature edge
2203  patchAttraction[oldPointI] = vector::zero;
2204  patchConstraints[oldPointI] = pointConstraint();
2205 
2206  findNearFeatureEdge
2207  (
2208  isRegionPoint, // search region edges only
2209 
2210  pp,
2211  snapDist,
2212  oldPointI,
2213  pp.localPoints()[oldPointI],
2214 
2215  edgeAttractors,
2216  edgeConstraints,
2217  patchAttraction,
2218  patchConstraints
2219  );
2220  }
2221  }
2222  else
2223  {
2224  // Current pointI nearer.
2225  pointAttractor[featI][featPointI] = pointI;
2226  pointConstraints[featI][featPointI].first() = 3;
2227  pointConstraints[featI][featPointI].second() = vector::zero;
2228 
2229  // Store for later use
2230  patchAttraction[pointI] = featPt-pt;
2231  patchConstraints[pointI] = pointConstraints[featI][featPointI];
2232  }
2233  }
2234 
2235  return Tuple2<label, pointIndexHit>(featI, nearInfo[0]);
2236 }
2237 
2238 
2239 // Determines for every pp point - that is on multiple faces that form
2240 // a feature - the nearest feature edge/point.
2243  const label iter,
2244  const scalar featureCos,
2245  const bool multiRegionFeatureSnap,
2246 
2247  const indirectPrimitivePatch& pp,
2248  const scalarField& snapDist,
2249  const vectorField& nearestDisp,
2250 
2251  const List<List<point> >& pointFaceSurfNormals,
2252  const List<List<point> >& pointFaceDisp,
2253  const List<List<point> >& pointFaceCentres,
2254  const labelListList& pointFacePatchID,
2255 
2256  // Feature-point to pp point
2257  List<labelList>& pointAttractor,
2259  // Feature-edge to pp point
2260  List<List<DynamicList<point> > >& edgeAttractors,
2261  List<List<DynamicList<pointConstraint> > >& edgeConstraints,
2262  // pp point to nearest feature
2263  vectorField& patchAttraction,
2264  List<pointConstraint>& patchConstraints
2265 ) const
2266 {
2267  autoPtr<OBJstream> featureEdgeStr;
2268  autoPtr<OBJstream> missedEdgeStr;
2269  autoPtr<OBJstream> featurePointStr;
2270  autoPtr<OBJstream> missedMP0Str;
2271  autoPtr<OBJstream> missedMP1Str;
2272 
2273  if (debug&meshRefinement::ATTRACTION)
2274  {
2275  featureEdgeStr.reset
2276  (
2277  new OBJstream
2278  (
2279  meshRefiner_.mesh().time().path()
2280  / "featureEdge_" + name(iter) + ".obj"
2281  )
2282  );
2283  Info<< "Dumping feature-edge sampling to "
2284  << featureEdgeStr().name() << endl;
2285 
2286  missedEdgeStr.reset
2287  (
2288  new OBJstream
2289  (
2290  meshRefiner_.mesh().time().path()
2291  / "missedFeatureEdge_" + name(iter) + ".obj"
2292  )
2293  );
2294  Info<< "Dumping feature-edges that are too far away to "
2295  << missedEdgeStr().name() << endl;
2296 
2297  featurePointStr.reset
2298  (
2299  new OBJstream
2300  (
2301  meshRefiner_.mesh().time().path()
2302  / "featurePoint_" + name(iter) + ".obj"
2303  )
2304  );
2305  Info<< "Dumping feature-point sampling to "
2306  << featurePointStr().name() << endl;
2307 
2308  missedMP0Str.reset
2309  (
2310  new OBJstream
2311  (
2312  meshRefiner_.mesh().time().path()
2313  / "missedFeatureEdgeFromMPEdge_" + name(iter) + ".obj"
2314  )
2315  );
2316  Info<< "Dumping region-edges that are too far away to "
2317  << missedMP0Str().name() << endl;
2318 
2319  missedMP1Str.reset
2320  (
2321  new OBJstream
2322  (
2323  meshRefiner_.mesh().time().path()
2324  / "missedFeatureEdgeFromMPPoint_" + name(iter) + ".obj"
2325  )
2326  );
2327  Info<< "Dumping region-points that are too far away to "
2328  << missedMP1Str().name() << endl;
2329  }
2330 
2331 
2332  DynamicList<point> surfacePoints(4);
2333  DynamicList<vector> surfaceNormals(4);
2334  labelList faceToNormalBin;
2335 
2336  forAll(pp.localPoints(), pointI)
2337  {
2338  const point& pt = pp.localPoints()[pointI];
2339 
2340 
2341  // Determine the geometric planes the point is (approximately) on.
2342  // This is returned as a
2343  // - attraction vector
2344  // - and a constraint
2345  // (1: attract to surface, constraint is normal of plane
2346  // 2: attract to feature line, constraint is feature line direction
2347  // 3: attract to feature point, constraint is zero)
2348 
2349  vector attraction = vector::zero;
2350  pointConstraint constraint;
2351 
2352  featureAttractionUsingReconstruction
2353  (
2354  iter,
2355  featureCos,
2356 
2357  pp,
2358  snapDist,
2359  nearestDisp,
2360 
2361  pointI,
2362 
2363  pointFaceSurfNormals,
2364  pointFaceDisp,
2365  pointFaceCentres,
2366  pointFacePatchID,
2367 
2368  surfacePoints,
2369  surfaceNormals,
2370  faceToNormalBin,
2371 
2372  attraction,
2373  constraint
2374  );
2375 
2376  // Now combine the reconstruction with the current state of the
2377  // point. The logic is quite complicated:
2378  // - the new constraint (from reconstruction) will only win if
2379  // - the constraint is higher (feature-point wins from feature-edge
2380  // etc.)
2381  // - or the constraint is the same but the attraction distance is less
2382  //
2383  // - then this will be combined with explicit searching on the
2384  // features and optionally the analysis of the patches using the
2385  // point. This analysis can do three thing:
2386  // - the point is not on multiple patches
2387  // - the point is on multiple patches but these are also
2388  // different planes (so the region feature is also a geometric
2389  // feature)
2390  // - the point is on multiple patches some of which are on
2391  // the same plane. This is the problem one - do we assume it is
2392  // an additional constraint (feat edge upgraded to region point,
2393  // see below)?
2394  //
2395  // Reconstruction MultiRegionFeatureSnap Attraction
2396  // ------- ---------------------- -----------
2397  // surface false surface
2398  // surface true region edge
2399  // feat edge false feat edge
2400  // feat edge true and no planar regions feat edge
2401  // feat edge true and yes planar regions region point
2402  // feat point false feat point
2403  // feat point true region point
2404 
2405 
2406  if
2407  (
2408  (constraint.first() > patchConstraints[pointI].first())
2409  || (
2410  (constraint.first() == patchConstraints[pointI].first())
2411  && (magSqr(attraction) < magSqr(patchAttraction[pointI]))
2412  )
2413  )
2414  {
2415  patchAttraction[pointI] = attraction;
2416  patchConstraints[pointI] = constraint;
2417 
2418  // Check the number of directions
2419  if (patchConstraints[pointI].first() == 1)
2420  {
2421  // Flat surface. Check for different patchIDs
2422  if (multiRegionFeatureSnap)
2423  {
2424  const point estimatedPt(pt + nearestDisp[pointI]);
2425  pointIndexHit multiPatchPt
2426  (
2427  findMultiPatchPoint
2428  (
2429  estimatedPt,
2430  pointFacePatchID[pointI],
2431  surfaceNormals,
2432  faceToNormalBin
2433  )
2434  );
2435 
2436  if (multiPatchPt.hit())
2437  {
2438  // Behave like when having two surface normals so
2439  // attract to nearest feature edge (with a guess for
2440  // the multipatch point as starting point)
2442  findNearFeatureEdge
2443  (
2444  true, // isRegionEdge
2445  pp,
2446  snapDist,
2447  pointI,
2448  multiPatchPt.hitPoint(), // estimatedPt
2449 
2450  edgeAttractors,
2451  edgeConstraints,
2452 
2453  patchAttraction,
2454  patchConstraints
2455  );
2456 
2457  const pointIndexHit& info = nearInfo.second();
2458  if (info.hit())
2459  {
2460  // Dump
2461  if (featureEdgeStr.valid())
2462  {
2463  featureEdgeStr().write
2464  (
2465  linePointRef(pt, info.hitPoint())
2466  );
2467  }
2468  }
2469  else
2470  {
2471  if (missedEdgeStr.valid())
2472  {
2473  missedEdgeStr().write
2474  (
2475  linePointRef(pt, multiPatchPt.hitPoint())
2476  );
2477  }
2478  }
2479  }
2480  }
2481  }
2482  else if (patchConstraints[pointI].first() == 2)
2483  {
2484  // Mark point on the nearest feature edge. Note that we
2485  // only search within the surrounding since the plane
2486  // reconstruction might find a feature where there isn't one.
2487  const point estimatedPt(pt + patchAttraction[pointI]);
2488 
2490 
2491  // Geometric feature edge. Check for different patchIDs
2492  bool hasSnapped = false;
2493  if (multiRegionFeatureSnap)
2494  {
2495  pointIndexHit multiPatchPt
2496  (
2497  findMultiPatchPoint
2498  (
2499  estimatedPt,
2500  pointFacePatchID[pointI],
2501  surfaceNormals,
2502  faceToNormalBin
2503  )
2504  );
2505  if (multiPatchPt.hit())
2506  {
2507  if (multiPatchPt.index() == 0)
2508  {
2509  // Region edge is also a geometric feature edge
2510  nearInfo = findNearFeatureEdge
2511  (
2512  true, // isRegionEdge
2513  pp,
2514  snapDist,
2515  pointI,
2516  estimatedPt,
2517 
2518  edgeAttractors,
2519  edgeConstraints,
2520 
2521  patchAttraction,
2522  patchConstraints
2523  );
2524  hasSnapped = true;
2525 
2526  // Debug: dump missed feature point
2527  if
2528  (
2529  missedMP0Str.valid()
2530  && !nearInfo.second().hit()
2531  )
2532  {
2533  missedMP0Str().write
2534  (
2535  linePointRef(pt, estimatedPt)
2536  );
2537  }
2538  }
2539  else
2540  {
2541  // One of planes of feature contains multiple
2542  // regions. We assume (contentious!) that the
2543  // separation between
2544  // the regions is not aligned with the geometric
2545  // feature so is an additional constraint on the
2546  // point -> is region-feature-point.
2547  nearInfo = findNearFeaturePoint
2548  (
2549  true, // isRegionPoint
2550  pp,
2551  snapDist,
2552  pointI,
2553  estimatedPt,
2554 
2555  // Feature-point to pp point
2556  pointAttractor,
2558  // Feature-edge to pp point
2559  edgeAttractors,
2560  edgeConstraints,
2561  // pp point to nearest feature
2562  patchAttraction,
2563  patchConstraints
2564  );
2565  hasSnapped = true;
2566 
2567  // More contentious: if we don't find
2568  // a near feature point we will never find the
2569  // attraction to a feature edge either since
2570  // the edgeAttractors/edgeConstraints do not get
2571  // filled and we're using reverse attraction
2572  // Note that we're in multiRegionFeatureSnap which
2573  // where findMultiPatchPoint can decide the
2574  // wrong thing. So: if failed finding a near
2575  // feature point try for a feature edge
2576  if (!nearInfo.second().hit())
2577  {
2578  nearInfo = findNearFeatureEdge
2579  (
2580  true, // isRegionEdge
2581  pp,
2582  snapDist,
2583  pointI,
2584  estimatedPt,
2585 
2586  // Feature-edge to pp point
2587  edgeAttractors,
2588  edgeConstraints,
2589  // pp point to nearest feature
2590  patchAttraction,
2591  patchConstraints
2592  );
2593  }
2594 
2595  // Debug: dump missed feature point
2596  if
2597  (
2598  missedMP1Str.valid()
2599  && !nearInfo.second().hit()
2600  )
2601  {
2602  missedMP1Str().write
2603  (
2604  linePointRef(pt, estimatedPt)
2605  );
2606  }
2607  }
2608  }
2609  }
2610 
2611  if (!hasSnapped)
2612  {
2613  // Determine nearest point on feature edge. Store
2614  // constraint
2615  // (calculated from feature edge, alternative would be to
2616  // use constraint calculated from both surfaceNormals)
2617  nearInfo = findNearFeatureEdge
2618  (
2619  false, // isRegionPoint
2620  pp,
2621  snapDist,
2622  pointI,
2623  estimatedPt,
2624 
2625  edgeAttractors,
2626  edgeConstraints,
2627 
2628  patchAttraction,
2629  patchConstraints
2630  );
2631  hasSnapped = true;
2632  }
2633 
2634  // Dump to obj
2635  const pointIndexHit& info = nearInfo.second();
2636  if (info.hit())
2637  {
2638  if
2639  (
2640  patchConstraints[pointI].first() == 3
2641  && featurePointStr.valid()
2642  )
2643  {
2644  featurePointStr().write
2645  (
2646  linePointRef(pt, info.hitPoint())
2647  );
2648  }
2649  else if
2650  (
2651  patchConstraints[pointI].first() == 2
2652  && featureEdgeStr.valid()
2653  )
2654  {
2655  featureEdgeStr().write
2656  (
2657  linePointRef(pt, info.hitPoint())
2658  );
2659  }
2660  }
2661  else
2662  {
2663  if (missedEdgeStr.valid())
2664  {
2665  missedEdgeStr().write
2666  (
2667  linePointRef(pt, estimatedPt)
2668  );
2669  }
2670  }
2671  }
2672  else if (patchConstraints[pointI].first() == 3)
2673  {
2674  // Mark point on the nearest feature point.
2675  const point estimatedPt(pt + patchAttraction[pointI]);
2676 
2678 
2679  if (multiRegionFeatureSnap)
2680  {
2681  pointIndexHit multiPatchPt
2682  (
2683  findMultiPatchPoint
2684  (
2685  estimatedPt,
2686  pointFacePatchID[pointI],
2687  surfaceNormals,
2688  faceToNormalBin
2689  )
2690  );
2691  if (multiPatchPt.hit())
2692  {
2693  // Multiple regions
2694  nearInfo = findNearFeaturePoint
2695  (
2696  true, // isRegionPoint
2697  pp,
2698  snapDist,
2699  pointI,
2700  estimatedPt,
2701 
2702  // Feature-point to pp point
2703  pointAttractor,
2705  // Feature-edge to pp point
2706  edgeAttractors,
2707  edgeConstraints,
2708  // pp point to nearest feature
2709  patchAttraction,
2710  patchConstraints
2711  );
2712  }
2713  else
2714  {
2715  nearInfo = findNearFeaturePoint
2716  (
2717  false, // isRegionPoint
2718  pp,
2719  snapDist,
2720  pointI,
2721  estimatedPt,
2722 
2723  // Feature-point to pp point
2724  pointAttractor,
2726  // Feature-edge to pp point
2727  edgeAttractors,
2728  edgeConstraints,
2729  // pp point to nearest feature
2730  patchAttraction,
2731  patchConstraints
2732  );
2733  }
2734  }
2735  else
2736  {
2737  // No multi-patch snapping
2738  nearInfo = findNearFeaturePoint
2739  (
2740  false, // isRegionPoint
2741  pp,
2742  snapDist,
2743  pointI,
2744  estimatedPt,
2745 
2746  // Feature-point to pp point
2747  pointAttractor,
2749  // Feature-edge to pp point
2750  edgeAttractors,
2751  edgeConstraints,
2752  // pp point to nearest feature
2753  patchAttraction,
2754  patchConstraints
2755  );
2756  }
2757 
2758  const pointIndexHit& info = nearInfo.second();
2759  if (info.hit() && featurePointStr.valid())
2760  {
2761  featurePointStr().write
2762  (
2763  linePointRef(pt, info.hitPoint())
2764  );
2765  }
2766  }
2767  }
2768  }
2769 }
2770 
2771 
2772 // Baffle handling
2773 // ~~~~~~~~~~~~~~~
2774 // Override pointAttractor, edgeAttractor, patchAttration etc. to
2775 // implement 'baffle' handling.
2776 // Baffle: the mesh pp point originates from a loose standing
2777 // baffle.
2778 // Sampling the surface with the surrounding face-centres only picks up
2779 // a single triangle normal so above determineFeatures will not have
2780 // detected anything. So explicitly pick up feature edges on the pp
2781 // (after duplicating points & smoothing so will already have been
2782 // expanded) and match these to the features.
2785  const label iter,
2786  const bool baffleFeaturePoints,
2787  const scalar featureCos,
2788 
2789  const indirectPrimitivePatch& pp,
2790  const scalarField& snapDist,
2791 
2792  // Feature-point to pp point
2793  List<labelList>& pointAttractor,
2795  // Feature-edge to pp point
2796  List<List<DynamicList<point> > >& edgeAttractors,
2797  List<List<DynamicList<pointConstraint> > >& edgeConstraints,
2798  // pp point to nearest feature
2799  vectorField& patchAttraction,
2800  List<pointConstraint>& patchConstraints
2801 ) const
2802 {
2803  const fvMesh& mesh = meshRefiner_.mesh();
2804  const refinementFeatures& features = meshRefiner_.features();
2805 
2806  // Calculate edge-faces
2807  List<List<point> > edgeFaceNormals(pp.nEdges());
2808 
2809  // Fill local data
2810  forAll(pp.edgeFaces(), edgeI)
2811  {
2812  const labelList& eFaces = pp.edgeFaces()[edgeI];
2813  List<point>& eFc = edgeFaceNormals[edgeI];
2814  eFc.setSize(eFaces.size());
2815  forAll(eFaces, i)
2816  {
2817  label faceI = eFaces[i];
2818  eFc[i] = pp.faceNormals()[faceI];
2819  }
2820  }
2821 
2822  {
2823  // Precalculate mesh edges for pp.edges.
2824  const labelList meshEdges
2825  (
2826  pp.meshEdges(mesh.edges(), mesh.pointEdges())
2827  );
2828  syncTools::syncEdgeList
2829  (
2830  mesh,
2831  meshEdges,
2832  edgeFaceNormals,
2834  List<point>(),
2836  );
2837  }
2838 
2839  // Detect baffle edges. Assume initial mesh will have 0,90 or 180
2840  // (baffle) degree angles so smoothing should make 0,90
2841  // to be less than 90. Choose reasonable value
2842  const scalar baffleFeatureCos = Foam::cos(degToRad(110));
2843 
2844 
2845  autoPtr<OBJstream> baffleEdgeStr;
2846  if (debug&meshRefinement::ATTRACTION)
2847  {
2848  baffleEdgeStr.reset
2849  (
2850  new OBJstream
2851  (
2852  meshRefiner_.mesh().time().path()
2853  / "baffleEdge_" + name(iter) + ".obj"
2854  )
2855  );
2856  Info<< nl << "Dumping baffle-edges to "
2857  << baffleEdgeStr().name() << endl;
2858  }
2859 
2860 
2861  // Is edge on baffle
2862  PackedBoolList isBaffleEdge(pp.nEdges());
2863  label nBaffleEdges = 0;
2864  // Is point on
2865  // 0 : baffle-edge (0)
2866  // 1 : baffle-feature-point (1)
2867  // -1 : rest
2868  labelList pointStatus(pp.nPoints(), -1);
2869 
2870  forAll(edgeFaceNormals, edgeI)
2871  {
2872  const List<point>& efn = edgeFaceNormals[edgeI];
2873 
2874  if (efn.size() == 2 && (efn[0]&efn[1]) < baffleFeatureCos)
2875  {
2876  isBaffleEdge[edgeI] = true;
2877  nBaffleEdges++;
2878  const edge& e = pp.edges()[edgeI];
2879  pointStatus[e[0]] = 0;
2880  pointStatus[e[1]] = 0;
2881 
2882  if (baffleEdgeStr.valid())
2883  {
2884  const point& p0 = pp.localPoints()[e[0]];
2885  const point& p1 = pp.localPoints()[e[1]];
2886  baffleEdgeStr().write(linePointRef(p0, p1));
2887  }
2888  }
2889  }
2890 
2891  reduce(nBaffleEdges, sumOp<label>());
2892 
2893  Info<< "Detected " << nBaffleEdges
2894  << " baffle edges out of "
2895  << returnReduce(pp.nEdges(), sumOp<label>())
2896  << " edges." << endl;
2897 
2898 
2899  //- Baffle edges will be too ragged to sensibly determine feature points
2900  //forAll(pp.pointEdges(), pointI)
2901  //{
2902  // if
2903  // (
2904  // isFeaturePoint
2905  // (
2906  // featureCos,
2907  // pp,
2908  // isBaffleEdge,
2909  // pointI
2910  // )
2911  // )
2912  // {
2913  // //Pout<< "Detected feature point:" << pp.localPoints()[pointI]
2914  // // << endl;
2915  // //-TEMPORARILY DISABLED:
2916  // //pointStatus[pointI] = 1;
2917  // }
2918  //}
2919 
2920 
2921  label nBafflePoints = 0;
2922  forAll(pointStatus, pointI)
2923  {
2924  if (pointStatus[pointI] != -1)
2925  {
2926  nBafflePoints++;
2927  }
2928  }
2929  reduce(nBafflePoints, sumOp<label>());
2930 
2931 
2932  label nPointAttract = 0;
2933  label nEdgeAttract = 0;
2934 
2935  forAll(pointStatus, pointI)
2936  {
2937  const point& pt = pp.localPoints()[pointI];
2938 
2939  if (pointStatus[pointI] == 0) // baffle edge
2940  {
2941  // 1: attract to near feature edge first
2942 
2943  Tuple2<label, pointIndexHit> nearInfo = findNearFeatureEdge
2944  (
2945  false, // isRegionPoint?
2946  pp,
2947  snapDist,
2948  pointI,
2949  pt,
2950 
2951  edgeAttractors,
2952  edgeConstraints,
2953  patchAttraction,
2954  patchConstraints
2955  );
2956 
2957 
2958  //- MEJ:
2959  // 2: optionally override with nearest feature point.
2960  // On baffles we don't have enough normals to construct a feature
2961  // point so assume all feature edges are close to feature points
2962  if (nearInfo.second().hit())
2963  {
2964  nEdgeAttract++;
2965 
2966  if (baffleFeaturePoints)
2967  {
2968  nearInfo = findNearFeaturePoint
2969  (
2970  false, // isRegionPoint,
2971 
2972  pp,
2973  snapDist,
2974  pointI,
2975  pt, // estimatedPt,
2976 
2977  // Feature-point to pp point
2978  pointAttractor,
2980  // Feature-edge to pp point
2981  edgeAttractors,
2982  edgeConstraints,
2983  // pp point to nearest feature
2984  patchAttraction,
2985  patchConstraints
2986  );
2987 
2988  if (nearInfo.first() != -1)
2989  {
2990  nEdgeAttract--;
2991  nPointAttract++;
2992  }
2993  }
2994  }
2995  }
2996  else if (pointStatus[pointI] == 1) // baffle point
2997  {
2998  labelList nearFeat;
3000  features.findNearestPoint
3001  (
3002  pointField(1, pt),
3003  scalarField(1, sqr(snapDist[pointI])),
3004  nearFeat,
3005  nearInfo
3006  );
3007 
3008  label featI = nearFeat[0];
3009 
3010  if (featI != -1)
3011  {
3012  nPointAttract++;
3013 
3014  label featPointI = nearInfo[0].index();
3015  const point& featPt = nearInfo[0].hitPoint();
3016  scalar distSqr = magSqr(featPt-pt);
3017 
3018  // Check if already attracted
3019  label oldPointI = pointAttractor[featI][featPointI];
3020 
3021  if
3022  (
3023  oldPointI == -1
3024  || (
3025  distSqr
3026  < magSqr(featPt-pp.localPoints()[oldPointI])
3027  )
3028  )
3029  {
3030  pointAttractor[featI][featPointI] = pointI;
3031  pointConstraints[featI][featPointI].first() = 3;
3032  pointConstraints[featI][featPointI].second() =
3033  vector::zero;
3034 
3035  // Store for later use
3036  patchAttraction[pointI] = featPt-pt;
3037  patchConstraints[pointI] =
3038  pointConstraints[featI][featPointI];
3039 
3040  if (oldPointI != -1)
3041  {
3042  // The current point is closer so wins. Reset
3043  // the old point to attract to nearest edge
3044  // instead.
3045  findNearFeatureEdge
3046  (
3047  false, // isRegionPoint
3048  pp,
3049  snapDist,
3050  oldPointI,
3051  pp.localPoints()[oldPointI],
3052 
3053  edgeAttractors,
3054  edgeConstraints,
3055  patchAttraction,
3056  patchConstraints
3057  );
3058  }
3059  }
3060  else
3061  {
3062  // Make it fall through to check below
3063  featI = -1;
3064  }
3065  }
3066 
3067  // Not found a feature point or another point is already
3068  // closer to that feature
3069  if (featI == -1)
3070  {
3071  //Pout<< "*** Falling back to finding nearest feature"
3072  // << " edge"
3073  // << " for baffle-feature-point " << pt
3074  // << endl;
3075 
3076  Tuple2<label, pointIndexHit> nearInfo = findNearFeatureEdge
3077  (
3078  false, // isRegionPoint
3079  pp,
3080  snapDist,
3081  pointI,
3082  pt, // starting point
3083 
3084  edgeAttractors,
3085  edgeConstraints,
3086  patchAttraction,
3087  patchConstraints
3088  );
3089 
3090  if (nearInfo.first() != -1)
3091  {
3092  nEdgeAttract++;
3093  }
3094  }
3095  }
3096  }
3097 
3098  reduce(nPointAttract, sumOp<label>());
3099  reduce(nEdgeAttract, sumOp<label>());
3100 
3101  Info<< "Baffle points : " << nBafflePoints
3102  << " of which attracted to :" << nl
3103  << " feature point : " << nPointAttract << nl
3104  << " feature edge : " << nEdgeAttract << nl
3105  << " rest : " << nBafflePoints-nPointAttract-nEdgeAttract
3106  << nl
3107  << endl;
3108 }
3109 
3110 
3113  const label iter,
3114 
3115  const indirectPrimitivePatch& pp,
3116  const scalarField& snapDist,
3117 
3118  // Feature-point to pp point
3119  const List<labelList>& pointAttractor,
3121  // Feature-edge to pp point
3122  const List<List<DynamicList<point> > >& edgeAttractors,
3123  const List<List<DynamicList<pointConstraint> > >& edgeConstraints,
3124 
3125  const vectorField& rawPatchAttraction,
3126  const List<pointConstraint>& rawPatchConstraints,
3127 
3128  // pp point to nearest feature
3129  vectorField& patchAttraction,
3130  List<pointConstraint>& patchConstraints
3131 ) const
3132 {
3133  const refinementFeatures& features = meshRefiner_.features();
3134 
3135  // Find nearest mesh point to feature edge
3136  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3137  // Reverse lookup : go through all edgeAttractors and find the
3138  // nearest point on pp
3139 
3140  // Get search domain and extend it a bit
3141  treeBoundBox bb(pp.localPoints());
3142  {
3143  // Random number generator. Bit dodgy since not exactly random ;-)
3144  Random rndGen(65431);
3145 
3146  // Slightly extended bb. Slightly off-centred just so on symmetric
3147  // geometry there are less face/edge aligned items.
3148  bb = bb.extend(rndGen, 1e-4);
3149  bb.min() -= point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
3150  bb.max() += point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
3151  }
3152 
3153  // Collect candidate points for attraction
3154  DynamicList<label> attractPoints(pp.nPoints());
3155  {
3156  const fvMesh& mesh = meshRefiner_.mesh();
3157 
3158  boolList isFeatureEdgeOrPoint(pp.nPoints(), false);
3159  label nFeats = 0;
3160  forAll(rawPatchConstraints, pointI)
3161  {
3162  if (rawPatchConstraints[pointI].first() >= 2)
3163  {
3164  isFeatureEdgeOrPoint[pointI] = true;
3165  nFeats++;
3166  }
3167  }
3168 
3169  Info<< "Initially selected " << returnReduce(nFeats, sumOp<label>())
3170  << " mesh points out of "
3171  << returnReduce(pp.nPoints(), sumOp<label>())
3172  << " for reverse attraction." << endl;
3173 
3174  // Make sure is synchronised (note: check if constraint is already
3175  // synced in which case this is not needed here)
3176  syncTools::syncPointList
3177  (
3178  mesh,
3179  pp.meshPoints(),
3180  isFeatureEdgeOrPoint,
3181  orEqOp<bool>(), // combine op
3182  false
3183  );
3184 
3185  for (label nGrow = 0; nGrow < 1; nGrow++)
3186  {
3187  boolList newIsFeatureEdgeOrPoint(isFeatureEdgeOrPoint);
3188 
3189  forAll(pp.localFaces(), faceI)
3190  {
3191  const face& f = pp.localFaces()[faceI];
3192 
3193  forAll(f, fp)
3194  {
3195  if (isFeatureEdgeOrPoint[f[fp]])
3196  {
3197  // Mark all points on face
3198  forAll(f, fp)
3199  {
3200  newIsFeatureEdgeOrPoint[f[fp]] = true;
3201  }
3202  break;
3203  }
3204  }
3205  }
3206 
3207  isFeatureEdgeOrPoint = newIsFeatureEdgeOrPoint;
3208 
3209  syncTools::syncPointList
3210  (
3211  mesh,
3212  pp.meshPoints(),
3213  isFeatureEdgeOrPoint,
3214  orEqOp<bool>(), // combine op
3215  false
3216  );
3217  }
3218 
3219 
3220  // Collect attractPoints
3221  forAll(isFeatureEdgeOrPoint, pointI)
3222  {
3223  if (isFeatureEdgeOrPoint[pointI])
3224  {
3225  attractPoints.append(pointI);
3226  }
3227  }
3228 
3229  Info<< "Selected "
3230  << returnReduce(attractPoints.size(), sumOp<label>())
3231  << " mesh points out of "
3232  << returnReduce(pp.nPoints(), sumOp<label>())
3233  << " for reverse attraction." << endl;
3234  }
3235 
3236 
3238  (
3239  treeDataPoint(pp.localPoints(), attractPoints),
3240  bb, // overall search domain
3241  8, // maxLevel
3242  10, // leafsize
3243  3.0 // duplicity
3244  );
3245 
3246  // Per mesh point the point on nearest feature edge.
3247  patchAttraction.setSize(pp.nPoints());
3248  patchAttraction = vector::zero;
3249  patchConstraints.setSize(pp.nPoints());
3250  patchConstraints = pointConstraint();
3251 
3252  forAll(edgeAttractors, featI)
3253  {
3254  const List<DynamicList<point> >& edgeAttr = edgeAttractors[featI];
3255  const List<DynamicList<pointConstraint> >& edgeConstr =
3256  edgeConstraints[featI];
3257 
3258  forAll(edgeAttr, featEdgeI)
3259  {
3260  const DynamicList<point>& attr = edgeAttr[featEdgeI];
3261  forAll(attr, i)
3262  {
3263  // Find nearest pp point
3264  const point& featPt = attr[i];
3266  (
3267  featPt,
3268  sqr(GREAT)
3269  );
3270 
3271  if (nearInfo.hit())
3272  {
3273  label pointI =
3274  ppTree.shapes().pointLabels()[nearInfo.index()];
3275  const point attraction = featPt-pp.localPoints()[pointI];
3276 
3277  // Check if this point is already being attracted. If so
3278  // override it only if nearer.
3279  if
3280  (
3281  patchConstraints[pointI].first() <= 1
3282  || magSqr(attraction) < magSqr(patchAttraction[pointI])
3283  )
3284  {
3285  patchAttraction[pointI] = attraction;
3286  patchConstraints[pointI] = edgeConstr[featEdgeI][i];
3287  }
3288  }
3289  else
3290  {
3292  << "Did not find pp point near " << featPt
3293  << endl;
3294  }
3295  }
3296  }
3297  }
3298 
3299 
3300  // Different procs might have different patchAttraction,patchConstraints
3301  // however these only contain geometric information, no topology
3302  // so as long as we synchronise after overriding with feature points
3303  // there is no problem, just possibly a small error.
3304 
3305 
3306  // Find nearest mesh point to feature point
3307  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3308  // (overrides attraction to feature edge)
3309  forAll(pointAttractor, featI)
3310  {
3311  const labelList& pointAttr = pointAttractor[featI];
3312  const List<pointConstraint>& pointConstr = pointConstraints[featI];
3313 
3314  forAll(pointAttr, featPointI)
3315  {
3316  if (pointAttr[featPointI] != -1)
3317  {
3318  const point& featPt = features[featI].points()
3319  [
3320  featPointI
3321  ];
3322 
3323  // Find nearest pp point
3325  (
3326  featPt,
3327  sqr(GREAT)
3328  );
3329 
3330  if (nearInfo.hit())
3331  {
3332  label pointI =
3333  ppTree.shapes().pointLabels()[nearInfo.index()];
3334 
3335  const point& pt = pp.localPoints()[pointI];
3336  const point attraction = featPt-pt;
3337 
3338  // - already attracted to feature edge : point always wins
3339  // - already attracted to feature point: nearest wins
3340 
3341  if (patchConstraints[pointI].first() <= 1)
3342  {
3343  patchAttraction[pointI] = attraction;
3344  patchConstraints[pointI] = pointConstr[featPointI];
3345  }
3346  else if (patchConstraints[pointI].first() == 2)
3347  {
3348  patchAttraction[pointI] = attraction;
3349  patchConstraints[pointI] = pointConstr[featPointI];
3350  }
3351  else if (patchConstraints[pointI].first() == 3)
3352  {
3353  // Only if nearer
3354  if
3355  (
3356  magSqr(attraction)
3357  < magSqr(patchAttraction[pointI])
3358  )
3359  {
3360  patchAttraction[pointI] = attraction;
3361  patchConstraints[pointI] =
3362  pointConstr[featPointI];
3363  }
3364  }
3365  }
3366  }
3367  }
3368  }
3369 }
3370 
3371 
3374  const label iter,
3375  const bool multiRegionFeatureSnap,
3376 
3377  const bool detectBaffles,
3378  const bool baffleFeaturePoints,
3379 
3380  const bool releasePoints,
3381  const bool stringFeatures,
3382  const bool avoidDiagonal,
3383 
3384  const scalar featureCos,
3385 
3386  const indirectPrimitivePatch& pp,
3387  const scalarField& snapDist,
3388  const vectorField& nearestDisp,
3389  const vectorField& nearestNormal,
3390 
3391  const List<List<point> >& pointFaceSurfNormals,
3392  const List<List<point> >& pointFaceDisp,
3393  const List<List<point> >& pointFaceCentres,
3394  const labelListList& pointFacePatchID,
3395 
3396  vectorField& patchAttraction,
3397  List<pointConstraint>& patchConstraints
3398 ) const
3399 {
3400  const refinementFeatures& features = meshRefiner_.features();
3401  const fvMesh& mesh = meshRefiner_.mesh();
3402 
3403  const PackedBoolList isPatchMasterPoint
3404  (
3405  meshRefinement::getMasterPoints
3406  (
3407  mesh,
3408  pp.meshPoints()
3409  )
3410  );
3411 
3412 
3413  // Collect ordered attractions on feature edges
3414  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3415 
3416  // Per feature, per feature-edge a list of attraction points and their
3417  // originating vertex.
3418  List<List<DynamicList<point> > > edgeAttractors(features.size());
3419  List<List<DynamicList<pointConstraint> > > edgeConstraints
3420  (
3421  features.size()
3422  );
3423  forAll(features, featI)
3424  {
3425  label nFeatEdges = features[featI].edges().size();
3426  edgeAttractors[featI].setSize(nFeatEdges);
3427  edgeConstraints[featI].setSize(nFeatEdges);
3428  }
3429 
3430  // Per feature, per feature-point the pp point that is attracted to it.
3431  // This list is only used to subset the feature-points that are actually
3432  // used.
3433  List<labelList> pointAttractor(features.size());
3435  forAll(features, featI)
3436  {
3437  label nFeatPoints = features[featI].points().size();
3438  pointAttractor[featI].setSize(nFeatPoints, -1);
3439  pointConstraints[featI].setSize(nFeatPoints);
3440  }
3441 
3442  // Reverse: from pp point to nearest feature
3443  vectorField rawPatchAttraction(pp.nPoints(), vector::zero);
3444  List<pointConstraint> rawPatchConstraints(pp.nPoints());
3445 
3446  determineFeatures
3447  (
3448  iter,
3449  featureCos,
3450  multiRegionFeatureSnap,
3451 
3452  pp,
3453  snapDist, // per point max distance and nearest surface
3454  nearestDisp,
3455 
3456  pointFaceSurfNormals, // per face nearest surface
3457  pointFaceDisp,
3458  pointFaceCentres,
3459  pointFacePatchID,
3460 
3461  // Feature-point to pp point
3462  pointAttractor,
3464  // Feature-edge to pp point
3465  edgeAttractors,
3466  edgeConstraints,
3467  // pp point to nearest feature
3468  rawPatchAttraction,
3469  rawPatchConstraints
3470  );
3471 
3472  // Print a bit about the attraction from patch point to feature
3473  if (debug)
3474  {
3475  Info<< "Raw geometric feature analysis : ";
3476  writeStats(pp, isPatchMasterPoint, rawPatchConstraints);
3477  }
3478 
3479  // Baffle handling
3480  // ~~~~~~~~~~~~~~~
3481  // Override pointAttractor, edgeAttractor, rawPatchAttration etc. to
3482  // implement 'baffle' handling.
3483  // Baffle: the mesh pp point originates from a loose standing
3484  // baffle.
3485  // Sampling the surface with the surrounding face-centres only picks up
3486  // a single triangle normal so above determineFeatures will not have
3487  // detected anything. So explicitly pick up feature edges on the pp
3488  // (after duplicating points & smoothing so will already have been
3489  // expanded) and match these to the features.
3490  if (detectBaffles)
3491  {
3492  determineBaffleFeatures
3493  (
3494  iter,
3495  baffleFeaturePoints,
3496  featureCos,
3497 
3498  pp,
3499  snapDist,
3500 
3501  // Feature-point to pp point
3502  pointAttractor,
3504  // Feature-edge to pp point
3505  edgeAttractors,
3506  edgeConstraints,
3507  // pp point to nearest feature
3508  rawPatchAttraction,
3509  rawPatchConstraints
3510  );
3511  }
3512 
3513  // Print a bit about the attraction from patch point to feature
3514  if (debug)
3515  {
3516  Info<< "After baffle feature analysis : ";
3517  writeStats(pp, isPatchMasterPoint, rawPatchConstraints);
3518  }
3519 
3520 
3521  // Reverse lookup: Find nearest mesh point to feature edge
3522  // ~~~~~~~~~~~~~~~~----------------~~~~~~~~~~~~~~~~~~~~~~~
3523  // go through all edgeAttractors and find the nearest point on pp
3524 
3525  reverseAttractMeshPoints
3526  (
3527  iter,
3528 
3529  pp,
3530  snapDist,
3531 
3532  // Feature-point to pp point
3533  pointAttractor,
3535  // Feature-edge to pp point
3536  edgeAttractors,
3537  edgeConstraints,
3538 
3539  // Estimated feature point
3540  rawPatchAttraction,
3541  rawPatchConstraints,
3542 
3543  // pp point to nearest feature
3544  patchAttraction,
3545  patchConstraints
3546  );
3547 
3548  // Print a bit about the attraction from patch point to feature
3549  if (debug)
3550  {
3551  Info<< "Reverse attract feature analysis : ";
3552  writeStats(pp, isPatchMasterPoint, patchConstraints);
3553  }
3554 
3555  // Dump
3556  if (debug&meshRefinement::ATTRACTION)
3557  {
3558  OBJstream featureEdgeStr
3559  (
3560  meshRefiner_.mesh().time().path()
3561  / "edgeAttractors_" + name(iter) + ".obj"
3562  );
3563  Info<< "Dumping feature-edge attraction to "
3564  << featureEdgeStr.name() << endl;
3565 
3566  OBJstream featurePointStr
3567  (
3568  meshRefiner_.mesh().time().path()
3569  / "pointAttractors_" + name(iter) + ".obj"
3570  );
3571  Info<< "Dumping feature-point attraction to "
3572  << featurePointStr.name() << endl;
3573 
3574  forAll(patchConstraints, pointI)
3575  {
3576  const point& pt = pp.localPoints()[pointI];
3577  const vector& attr = patchAttraction[pointI];
3578 
3579  if (patchConstraints[pointI].first() == 2)
3580  {
3581  featureEdgeStr.write(linePointRef(pt, pt+attr));
3582  }
3583  else if (patchConstraints[pointI].first() == 3)
3584  {
3585  featurePointStr.write(linePointRef(pt, pt+attr));
3586  }
3587  }
3588  }
3589 
3590 
3591  //MEJ: any faces that have multi-patch points only keep the
3592  // multi-patch
3593  // points. The other points on the face will be dragged along
3594  // (hopefully)
3595  if (releasePoints)
3596  {
3597  releasePointsNextToMultiPatch
3598  (
3599  iter,
3600  featureCos,
3601 
3602  pp,
3603  snapDist,
3604 
3605  pointFaceCentres,
3606  pointFacePatchID,
3607 
3608  rawPatchAttraction,
3609  rawPatchConstraints,
3610 
3611  patchAttraction,
3612  patchConstraints
3613  );
3614  }
3615 
3616 
3617  // Snap edges to feature edges
3618  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
3619  // Walk existing edges and snap remaining ones (that are marked as
3620  // feature edges in rawPatchConstraints)
3621  if (stringFeatures)
3622  {
3623  stringFeatureEdges
3624  (
3625  iter,
3626  featureCos,
3627 
3628  pp,
3629  snapDist,
3630 
3631  rawPatchAttraction,
3632  rawPatchConstraints,
3633 
3634  patchAttraction,
3635  patchConstraints
3636  );
3637  }
3638 
3639 
3640  // Avoid diagonal attraction
3641  // ~~~~~~~~~~~~~~~~~~~~~~~~~
3642  // Attract one of the non-diagonal points.
3643  if (avoidDiagonal)
3644  {
3645  avoidDiagonalAttraction
3646  (
3647  iter,
3648  featureCos,
3649  pp,
3650  patchAttraction,
3651  patchConstraints
3652  );
3653  }
3654 
3655 
3656  if (debug&meshRefinement::ATTRACTION)
3657  {
3658  dumpMove
3659  (
3660  meshRefiner_.mesh().time().path()
3661  / "patchAttraction_" + name(iter) + ".obj",
3662  pp.localPoints(),
3663  pp.localPoints() + patchAttraction
3664  );
3665  }
3666 }
3667 
3668 
3669 // Correct for squeezing of face
3672  const label iter,
3673  const scalar featureCos,
3674 
3675  const indirectPrimitivePatch& pp,
3676  const scalarField& snapDist,
3677  const vectorField& nearestAttraction,
3678 
3679  vectorField& patchAttraction,
3680  List<pointConstraint>& patchConstraints
3681 ) const
3682 {
3683  autoPtr<OBJstream> strPtr;
3684  if (debug&meshRefinement::ATTRACTION)
3685  {
3686  strPtr.reset
3687  (
3688  new OBJstream
3689  (
3690  meshRefiner_.mesh().time().path()
3691  / "faceSqueeze_" + name(iter) + ".obj"
3692  )
3693  );
3694  Info<< "Dumping faceSqueeze corrections to "
3695  << strPtr().name() << endl;
3696  }
3697 
3699  face singleF;
3700  forAll(pp.localFaces(), faceI)
3701  {
3702  const face& f = pp.localFaces()[faceI];
3703 
3704  if (f.size() != points.size())
3705  {
3706  points.setSize(f.size());
3707  singleF.setSize(f.size());
3708  for (label i = 0; i < f.size(); i++)
3709  {
3710  singleF[i] = i;
3711  }
3712  }
3713  label nConstraints = 0;
3714  forAll(f, fp)
3715  {
3716  label pointI = f[fp];
3717  const point& pt = pp.localPoints()[pointI];
3718 
3719  if (patchConstraints[pointI].first() > 1)
3720  {
3721  points[fp] = pt + patchAttraction[pointI];
3722  nConstraints++;
3723  }
3724  else
3725  {
3726  points[fp] = pt;
3727  }
3728  }
3729 
3730  if (nConstraints == f.size())
3731  {
3732  if (f.size() == 3)
3733  {
3734  // Triangle: knock out attraction altogether
3735 
3736  // For now keep the points on the longest edge
3737  label maxFp = -1;
3738  scalar maxS = -1;
3739  forAll(f, fp)
3740  {
3741  const point& pt = pp.localPoints()[f[fp]];
3742  const point& nextPt = pp.localPoints()[f.nextLabel(fp)];
3743 
3744  scalar s = magSqr(pt-nextPt);
3745  if (s > maxS)
3746  {
3747  maxS = s;
3748  maxFp = fp;
3749  }
3750  }
3751  if (maxFp != -1)
3752  {
3753  label pointI = f.prevLabel(maxFp);
3754 
3755  // Reset attraction on pointI to nearest
3756 
3757  const point& pt = pp.localPoints()[pointI];
3758 
3759  //Pout<< "** on triangle " << pp.faceCentres()[faceI]
3760  // << " knocking out attraction to " << pointI
3761  // << " at:" << pt
3762  // << endl;
3763 
3764  patchAttraction[pointI] = nearestAttraction[pointI];
3765 
3766  if (strPtr.valid())
3767  {
3768  strPtr().write
3769  (
3770  linePointRef(pt, pt+patchAttraction[pointI])
3771  );
3772  }
3773  }
3774  }
3775  else
3776  {
3777  scalar oldArea = f.mag(pp.localPoints());
3778  scalar newArea = singleF.mag(points);
3779  if (newArea < 0.1*oldArea)
3780  {
3781  // For now remove the point with largest distance
3782  label maxFp = -1;
3783  scalar maxS = -1;
3784  forAll(f, fp)
3785  {
3786  scalar s = magSqr(patchAttraction[f[fp]]);
3787  if (s > maxS)
3788  {
3789  maxS = s;
3790  maxFp = fp;
3791  }
3792  }
3793  if (maxFp != -1)
3794  {
3795  label pointI = f[maxFp];
3796  // Lower attraction on pointI
3797  patchAttraction[pointI] *= 0.5;
3798  }
3799  }
3800  }
3801  }
3802  }
3803 }
3804 
3805 
3808  const snapParameters& snapParams,
3809  const bool alignMeshEdges,
3810  const label iter,
3811  const scalar featureCos,
3812  const scalar featureAttract,
3813  const scalarField& snapDist,
3814  const vectorField& nearestDisp,
3815  const vectorField& nearestNormal,
3816  motionSmoother& meshMover,
3817  vectorField& patchAttraction,
3818  List<pointConstraint>& patchConstraints,
3819 
3820  DynamicList<label>& splitFaces,
3821  DynamicList<labelPair>& splits
3822 
3823 ) const
3824 {
3825  const Switch implicitFeatureAttraction = snapParams.implicitFeatureSnap();
3826  const Switch explicitFeatureAttraction = snapParams.explicitFeatureSnap();
3827  const Switch multiRegionFeatureSnap = snapParams.multiRegionFeatureSnap();
3828 
3829  Info<< "Overriding displacement on features :" << nl
3830  << " implicit features : " << implicitFeatureAttraction << nl
3831  << " explicit features : " << explicitFeatureAttraction << nl
3832  << " multi-patch features : " << multiRegionFeatureSnap << nl
3833  << endl;
3834 
3835 
3836  const indirectPrimitivePatch& pp = meshMover.patch();
3837  const pointField& localPoints = pp.localPoints();
3838  const fvMesh& mesh = meshRefiner_.mesh();
3839 
3840 
3841  //const PackedBoolList isMasterPoint(syncTools::getMasterPoints(mesh));
3842  const PackedBoolList isPatchMasterPoint
3843  (
3844  meshRefinement::getMasterPoints
3845  (
3846  mesh,
3847  pp.meshPoints()
3848  )
3849  );
3850 
3851  // Per point, per surrounding face:
3852  // - faceSurfaceNormal
3853  // - faceDisp
3854  // - faceCentres
3855  List<List<point> > pointFaceSurfNormals;
3856  List<List<point> > pointFaceDisp;
3857  List<List<point> > pointFaceCentres;
3858  List<labelList> pointFacePatchID;
3859 
3860  {
3861  // Calculate attraction distance per face (from the attraction distance
3862  // per point)
3863  scalarField faceSnapDist(pp.size(), -GREAT);
3864  forAll(pp.localFaces(), faceI)
3865  {
3866  const face& f = pp.localFaces()[faceI];
3867  forAll(f, fp)
3868  {
3869  faceSnapDist[faceI] = max(faceSnapDist[faceI], snapDist[f[fp]]);
3870  }
3871  }
3872 
3873 
3874  // Displacement and orientation per pp face
3875  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3876 
3877  // vector from point on surface back to face centre
3878  vectorField faceDisp(pp.size(), vector::zero);
3879  // normal of surface at point on surface
3880  vectorField faceSurfaceNormal(pp.size(), vector::zero);
3881  labelList faceSurfaceGlobalRegion(pp.size(), -1);
3882  //vectorField faceRotation(pp.size(), vector::zero);
3883 
3884  calcNearestFace
3885  (
3886  iter,
3887  pp,
3888  faceSnapDist,
3889  faceDisp,
3890  faceSurfaceNormal,
3891  faceSurfaceGlobalRegion
3892  //faceRotation
3893  );
3894 
3895 
3896  // Collect (possibly remote) per point data of all surrounding faces
3897  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3898  // - faceSurfaceNormal
3899  // - faceDisp
3900  // - faceCentres
3901  calcNearestFacePointProperties
3902  (
3903  iter,
3904  pp,
3905 
3906  faceDisp,
3907  faceSurfaceNormal,
3908  faceSurfaceGlobalRegion,
3909 
3910  pointFaceSurfNormals,
3911  pointFaceDisp,
3912  pointFaceCentres,
3913  pointFacePatchID
3914  );
3915  }
3916 
3917 
3918  // Start off with nearest point on surface
3919  vectorField patchDisp = nearestDisp;
3920 
3921 
3922  // Main calculation
3923  // ~~~~~~~~~~~~~~~~
3924  // This is the main intelligence which calculates per point the vector to
3925  // attract it to the nearest surface. There are lots of possibilities
3926  // here.
3927 
3928  // Nearest feature
3929  patchAttraction.setSize(localPoints.size());
3930  patchAttraction = vector::zero;
3931  // Constraints at feature
3932  patchConstraints.setSize(localPoints.size());
3933  patchConstraints = pointConstraint();
3934 
3935  if (implicitFeatureAttraction)
3936  {
3937  // Sample faces around each point and see if nearest surface normal
3938  // differs. Reconstruct a feature edge/point if possible and snap to
3939  // it.
3940  featureAttractionUsingReconstruction
3941  (
3942  iter,
3943  featureCos,
3944 
3945  pp,
3946  snapDist,
3947  nearestDisp,
3948 
3949  pointFaceSurfNormals,
3950  pointFaceDisp,
3951  pointFaceCentres,
3952  pointFacePatchID,
3953 
3954  patchAttraction,
3955  patchConstraints
3956  );
3957  }
3958 
3959  if (explicitFeatureAttraction)
3960  {
3961  // Only do fancy stuff if alignMeshEdges
3962  bool releasePoints = false;
3963  bool stringFeatures = false;
3964  bool avoidDiagonal = false;
3965  if (alignMeshEdges)
3966  {
3967  releasePoints = snapParams.releasePoints();
3968  stringFeatures = snapParams.stringFeatures();
3969  avoidDiagonal = snapParams.avoidDiagonal();
3970  }
3971 
3972 
3973  // Sample faces around each point and see if nearest surface normal
3974  // differs. For those find the nearest real feature edge/point and
3975  // store the correspondence. Then loop over feature edge/point
3976  // and attract those nearest mesh point. (the first phase just is
3977  // a subsetting of candidate points, the second makes sure that only
3978  // one mesh point gets attracted per feature)
3979  featureAttractionUsingFeatureEdges
3980  (
3981  iter,
3982  multiRegionFeatureSnap,
3983 
3984  snapParams.detectBaffles(),
3985  snapParams.baffleFeaturePoints(), // all points on baffle edges
3986  // are attracted to feature pts
3987 
3988  releasePoints,
3989  stringFeatures,
3990  avoidDiagonal,
3991 
3992  featureCos,
3993 
3994  pp,
3995  snapDist,
3996  nearestDisp,
3997  nearestNormal,
3998 
3999  pointFaceSurfNormals,
4000  pointFaceDisp,
4001  pointFaceCentres,
4002  pointFacePatchID,
4003 
4004  patchAttraction,
4005  patchConstraints
4006  );
4007  }
4008 
4009  if (!alignMeshEdges)
4010  {
4011  const scalar concaveCos = Foam::cos
4012  (
4013  degToRad(snapParams.concaveAngle())
4014  );
4015  const scalar minAreaRatio = snapParams.minAreaRatio();
4016 
4017  Info<< "Experimental: introducing face splits to avoid rotating"
4018  << " mesh edges. Splitting faces when" << nl
4019  << indent << "- angle not concave by more than "
4020  << snapParams.concaveAngle() << " degrees" << nl
4021  << indent << "- resulting triangles of similar area "
4022  << " (ratio within " << minAreaRatio << ")" << nl
4023  << endl;
4024 
4025  splitDiagonals
4026  (
4027  featureCos,
4028  concaveCos,
4029  minAreaRatio,
4030  pp,
4031 
4032  nearestDisp,
4033  nearestNormal,
4034 
4035  patchAttraction,
4036  patchConstraints,
4037  splitFaces,
4038  splits
4039  );
4040 
4041  if (debug)
4042  {
4043  Info<< "Diagonal attraction feature correction : ";
4044  writeStats(pp, isPatchMasterPoint, patchConstraints);
4045  }
4046  }
4047 
4048 
4049  preventFaceSqueeze
4050  (
4051  iter,
4052  featureCos,
4053 
4054  pp,
4055  snapDist,
4056  nearestDisp,
4057 
4058  patchAttraction,
4059  patchConstraints
4060  );
4061 
4062  {
4063  vector avgPatchDisp = meshRefinement::gAverage
4064  (
4065  isPatchMasterPoint,
4066  patchDisp
4067  );
4068  vector avgPatchAttr = meshRefinement::gAverage
4069  (
4070  isPatchMasterPoint,
4071  patchAttraction
4072  );
4073 
4074  Info<< "Attraction:" << endl
4075  << " linear : max:" << gMaxMagSqr(patchDisp)
4076  << " avg:" << avgPatchDisp << endl
4077  << " feature : max:" << gMaxMagSqr(patchAttraction)
4078  << " avg:" << avgPatchAttr << endl;
4079  }
4080 
4081  // So now we have:
4082  // - patchDisp : point movement to go to nearest point on surface
4083  // (either direct or through interpolation of
4084  // face nearest)
4085  // - patchAttraction : direct attraction to features
4086  // - patchConstraints : type of features
4087 
4088  // Use any combination of patchDisp and direct feature attraction.
4089 
4090 
4091  // Mix with direct feature attraction
4092  forAll(patchConstraints, pointI)
4093  {
4094  if (patchConstraints[pointI].first() > 1)
4095  {
4096  patchDisp[pointI] =
4097  (1.0-featureAttract)*patchDisp[pointI]
4098  + featureAttract*patchAttraction[pointI];
4099  }
4100  }
4101 
4102 
4103 
4104  // Count
4105  {
4106  Info<< "Feature analysis : ";
4107  writeStats(pp, isPatchMasterPoint, patchConstraints);
4108  }
4109 
4110 
4111  // Now we have the displacement per patch point to move onto the surface
4112  // Split into tangential and normal direction.
4113  // - start off with all non-constrained points following the constrained
4114  // ones since point normals not relevant.
4115  // - finish with only tangential component smoothed.
4116  // Note: tangential is most
4117  // likely to come purely from face-centre snapping, not face rotation.
4118  // Note: could use the constraints here (constraintTransformation())
4119  // but this is not necessarily accurate and we're smoothing to
4120  // get out of problems.
4121 
4122  if (featureAttract < 1-0.001)
4123  {
4124  //const PackedBoolList isMasterEdge(syncTools::getMasterEdges(mesh));
4125  const labelList meshEdges
4126  (
4127  pp.meshEdges(mesh.edges(), mesh.pointEdges())
4128  );
4129  const PackedBoolList isPatchMasterEdge
4130  (
4131  meshRefinement::getMasterEdges
4132  (
4133  mesh,
4134  meshEdges
4135  )
4136  );
4137 
4138  const vectorField pointNormals
4139  (
4140  PatchTools::pointNormals
4141  (
4142  mesh,
4143  pp
4144  )
4145  );
4146 
4147  // 1. Smoothed all displacement
4148  vectorField smoothedPatchDisp = patchDisp;
4149  smoothAndConstrain
4150  (
4151  isPatchMasterEdge,
4152  pp,
4153  meshEdges,
4154  patchConstraints,
4155  smoothedPatchDisp
4156  );
4157 
4158 
4159  // 2. Smoothed tangential component
4160  vectorField tangPatchDisp = patchDisp;
4161  tangPatchDisp -= (pointNormals & patchDisp) * pointNormals;
4162  smoothAndConstrain
4163  (
4164  isPatchMasterEdge,
4165  pp,
4166  meshEdges,
4167  patchConstraints,
4168  tangPatchDisp
4169  );
4170 
4171  // Re-add normal component
4172  tangPatchDisp += (pointNormals & patchDisp) * pointNormals;
4173 
4174  if (debug&meshRefinement::ATTRACTION)
4175  {
4176  dumpMove
4177  (
4178  mesh.time().path()
4179  / "tangPatchDispConstrained_" + name(iter) + ".obj",
4180  pp.localPoints(),
4181  pp.localPoints() + tangPatchDisp
4182  );
4183  }
4184 
4185  patchDisp =
4186  (1.0-featureAttract)*smoothedPatchDisp
4187  + featureAttract*tangPatchDisp;
4188  }
4189 
4190 
4191  const scalar relax = featureAttract;
4192  patchDisp *= relax;
4193 
4194 
4195  // Points on zones in one domain but only present as point on other
4196  // will not do condition 2 on all. Sync explicitly.
4197  syncTools::syncPointList
4198  (
4199  mesh,
4200  pp.meshPoints(),
4201  patchDisp,
4202  minMagSqrEqOp<point>(), // combine op
4203  vector(GREAT, GREAT, GREAT) // null value (note: cant use VGREAT)
4204  );
4205 
4206  return patchDisp;
4207 }
4208 
4209 
4210 // ************************************************************************* //
Foam::DynamicField::clear
void clear()
Clear the addressed list, i.e. set the size to zero.
Definition: DynamicFieldI.H:277
Foam::snapParameters::avoidDiagonal
Switch avoidDiagonal() const
Definition: snapParameters.H:213
Foam::snapParameters::minAreaRatio
scalar minAreaRatio() const
Definition: snapParameters.H:231
Foam::snapParameters::detectBaffles
Switch detectBaffles() const
Definition: snapParameters.H:193
Foam::face::normal
vector normal(const pointField &) const
Vector normal; magnitude is equal to area of face.
Definition: face.C:552
Foam::pointField
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
Foam::Random
Simple random number generator.
Definition: Random.H:49
Foam::PackedBoolList
A bit-packed bool list.
Definition: PackedBoolList.H:63
Foam::PrimitivePatch::pointFaces
const labelListList & pointFaces() const
Return point-face addressing.
Definition: PrimitivePatchTemplate.C:352
Foam::Switch
A simple wrapper around bool so that it can be read as a word: true/false, on/off,...
Definition: Switch.H:60
Foam::PointIndexHit::index
label index() const
Return index.
Definition: PointIndexHit.H:111
relax
p relax()
Foam::PrimitivePatch::edgeFaces
const labelListList & edgeFaces() const
Return edge-face addressing.
Definition: PrimitivePatchTemplate.C:292
p
p
Definition: pEqn.H:62
Foam::word
A class for handling words, derived from string.
Definition: word.H:59
Foam::autoSnapDriver::isConcave
bool isConcave(const point &c0, const vector &area0, const point &c1, const vector &area1, const scalar concaveCos) const
Definition: autoSnapDriverFeature.C:1616
Foam::labelList
List< label > labelList
A List of labels.
Definition: labelList.H:56
Foam::boundBox::max
const point & max() const
Maximum describing the bounding box.
Definition: boundBoxI.H:60
Foam::returnReduce
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
Definition: PstreamReduceOps.H:86
Foam::OBJstream
OFstream which keeps track of vertices.
Definition: OBJstream.H:53
Foam::face::mag
scalar mag(const pointField &) const
Magnitude of face area.
Definition: faceI.H:97
Foam::polyBoundaryMesh
Foam::polyBoundaryMesh.
Definition: polyBoundaryMesh.H:60
Foam::PrimitivePatch::edges
const edgeList & edges() const
Return list of edges, address into LOCAL point list.
Definition: PrimitivePatchTemplate.C:212
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:406
Foam::autoSnapDriver::determineFeatures
void determineFeatures(const label iter, const scalar featureCos, const bool multiRegionFeatureSnap, const indirectPrimitivePatch &, const scalarField &snapDist, const vectorField &nearestDisp, const List< List< point > > &pointFaceSurfNormals, const List< List< point > > &pointFaceDisp, const List< List< point > > &pointFaceCentres, const labelListList &pointFacePatchID, List< labelList > &pointAttractor, List< List< pointConstraint > > &pointConstraints, List< List< DynamicList< point > > > &edgeAttractors, List< List< DynamicList< pointConstraint > > > &edgeConstraints, vectorField &patchAttraction, List< pointConstraint > &patchConstraints) const
Determine geometric features and attraction to equivalent.
Definition: autoSnapDriverFeature.C:2242
Foam::DynamicList< label >
Foam::gAverage
Type gAverage(const FieldField< Field, Type > &f)
Definition: FieldFieldFunctions.C:571
Foam::diag
void diag(pointPatchField< vector > &, const pointPatchField< tensor > &)
Definition: pointPatchFieldFunctions.H:262
Foam::Tuple2::second
const Type2 & second() const
Return second.
Definition: Tuple2.H:106
Foam::refinementFeatures::findNearestPoint
void findNearestPoint(const pointField &samples, const scalarField &nearestDistSqr, labelList &nearFeature, List< pointIndexHit > &nearInfo) const
Find nearest feature point. Sets.
Definition: refinementFeatures.C:699
Foam::plane::ray::dir
const vector & dir() const
Definition: plane.H:92
Foam::OBJstream::write
virtual Ostream & write(const char)
Write character.
Definition: OBJstream.C:82
Foam::refinementSurfaces::surfaces
const labelList & surfaces() const
Definition: refinementSurfaces.H:157
Foam::PrimitivePatch::localPoints
const Field< PointType > & localPoints() const
Return pointField of points in patch.
Definition: PrimitivePatchTemplate.C:432
Foam::motionSmootherAlgo::patch
const indirectPrimitivePatch & patch() const
Reference to patch.
Definition: motionSmootherAlgo.C:395
Foam::labelMax
static const label labelMax
Definition: label.H:62
Foam::PrimitivePatch::nEdges
label nEdges() const
Return number of edges in patch.
Definition: PrimitivePatchTemplate.H:299
Foam::treeBoundBox
Standard boundBox + extra functionality for use in octree.
Definition: treeBoundBox.H:75
Foam::polyPatch::coupled
virtual bool coupled() const
Return true if this patch is geometrically coupled (i.e. faces and.
Definition: polyPatch.H:322
motionSmoother.H
polyTopoChange.H
Foam::Tuple2::first
const Type1 & first() const
Return first.
Definition: Tuple2.H:94
indexedOctree.H
localPointRegion.H
Foam::face::centre
point centre(const pointField &) const
Centre point of face.
Definition: face.C:488
Foam::PrimitivePatch::meshEdges
labelList meshEdges(const edgeList &allEdges, const labelListList &cellEdges, const labelList &faceCells) const
Return labels of patch edges in the global edge list using.
Definition: PrimitivePatchMeshEdges.C:41
Foam::edge
An edge is a list of two point labels. The functionality it provides supports the discretisation on a...
Definition: edge.H:58
Foam::PointIndexHit::hit
bool hit() const
Is there a hit.
Definition: PointIndexHit.H:105
Foam::pointConstraint
Accumulates point constraints through successive applications of the applyConstraint function.
Definition: pointConstraint.H:56
unitConversion.H
Unit conversion functions.
Foam::indexedOctree::shapes
const Type & shapes() const
Reference to shape.
Definition: indexedOctree.H:449
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
Foam::autoSnapDriver::smoothAndConstrain
void smoothAndConstrain(const PackedBoolList &isMasterEdge, const indirectPrimitivePatch &pp, const labelList &meshEdges, const List< pointConstraint > &constraints, vectorField &disp) const
Definition: autoSnapDriverFeature.C:130
Foam::autoSnapDriver::calcNearestFacePointProperties
void calcNearestFacePointProperties(const label iter, const indirectPrimitivePatch &pp, const vectorField &faceDisp, const vectorField &faceSurfaceNormal, const labelList &faceSurfaceRegion, List< List< point > > &pointFaceSurfNormals, List< List< point > > &pointFaceDisp, List< List< point > > &pointFaceCentres, List< labelList > &pointFacePatchID) const
Definition: autoSnapDriverFeature.C:447
refinementFeatures.H
Foam::mag
dimensioned< scalar > mag(const dimensioned< Type > &)
Foam::mapDistribute::transformPosition
Default transformation behaviour for position.
Definition: mapDistribute.H:249
Foam::autoSnapDriver::findNormal
label findNormal(const scalar featureCos, const vector &faceSurfaceNormal, const DynamicList< vector > &surfaceNormals) const
Return index of similar normal.
Definition: autoSnapDriverFeature.C:753
Foam::autoSnapDriver::isSplitAlignedWithFeature
bool isSplitAlignedWithFeature(const scalar featureCos, const point &newPt0, const pointConstraint &pc0, const point &newPt1, const pointConstraint &pc1) const
Definition: autoSnapDriverFeature.C:1576
syncTools.H
Foam::autoSnapDriver::avoidDiagonalAttraction
void avoidDiagonalAttraction(const label iter, const scalar featureCos, const indirectPrimitivePatch &pp, vectorField &patchAttraction, List< pointConstraint > &patchConstraints) const
Avoid attraction across face diagonal since would.
Definition: autoSnapDriverFeature.C:1970
Foam::autoSnapDriver::findDiagonalAttraction
labelPair findDiagonalAttraction(const indirectPrimitivePatch &pp, const vectorField &patchAttraction, const List< pointConstraint > &patchConstraints, const label faceI) const
Detect any diagonal attraction. Returns indices in face.
Definition: autoSnapDriverFeature.C:1533
Foam::treeDataPoint
Holds (reference to) pointField. Encapsulation of data needed for octree searches....
Definition: treeDataPoint.H:59
Foam::snapParameters::baffleFeaturePoints
Switch baffleFeaturePoints() const
Definition: snapParameters.H:198
Foam::gMaxMagSqr
Type gMaxMagSqr(const UList< Type > &f, const label comm)
Definition: FieldFunctions.C:544
Foam::nearInfo
Tuple2< scalar, label > nearInfo
Private class for finding nearest.
Definition: sampledTriSurfaceMesh.C:64
Foam::plane
Geometric class that creates a 2D plane and can return the intersection point between a line and the ...
Definition: plane.H:60
pFaces
Info<< "Finished reading KIVA file"<< endl;cellShapeList cellShapes(nPoints);labelList cellZoning(nPoints, -1);const cellModel &hex=*(cellModeller::lookup("hex"));labelList hexLabels(8);label activeCells=0;labelList pointMap(nPoints);forAll(pointMap, i){ pointMap[i]=i;}for(label i=0;i< nPoints;i++){ if(f[i] > 0.0) { hexLabels[0]=i;hexLabels[1]=i1tab[i];hexLabels[2]=i3tab[i1tab[i]];hexLabels[3]=i3tab[i];hexLabels[4]=i8tab[i];hexLabels[5]=i1tab[i8tab[i]];hexLabels[6]=i3tab[i1tab[i8tab[i]]];hexLabels[7]=i3tab[i8tab[i]];cellShapes[activeCells]=cellShape(hex, hexLabels);edgeList edges=cellShapes[activeCells].edges();forAll(edges, ei) { if(edges[ei].mag(points)< SMALL) { label start=pointMap[edges[ei].start()];while(start !=pointMap[start]) { start=pointMap[start];} label end=pointMap[edges[ei].end()];while(end !=pointMap[end]) { end=pointMap[end];} label minLabel=min(start, end);pointMap[start]=pointMap[end]=minLabel;} } cellZoning[activeCells]=idreg[i];activeCells++;}}cellShapes.setSize(activeCells);cellZoning.setSize(activeCells);forAll(cellShapes, celli){ cellShape &cs=cellShapes[celli];forAll(cs, i) { cs[i]=pointMap[cs[i]];} cs.collapse();}label bcIDs[11]={-1, 0, 2, 4, -1, 5, -1, 6, 7, 8, 9};const label nBCs=12;const word *kivaPatchTypes[nBCs]={ &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &symmetryPolyPatch::typeName, &wedgePolyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &symmetryPolyPatch::typeName, &oldCyclicPolyPatch::typeName};enum patchTypeNames{ PISTON, VALVE, LINER, CYLINDERHEAD, AXIS, WEDGE, INFLOW, OUTFLOW, PRESIN, PRESOUT, SYMMETRYPLANE, CYCLIC};const char *kivaPatchNames[nBCs]={ "piston", "valve", "liner", "cylinderHead", "axis", "wedge", "inflow", "outflow", "presin", "presout", "symmetryPlane", "cyclic"};List< SLList< face > > pFaces[nBCs]
Definition: readKivaGrid.H:235
Foam::DynamicField
Dynamically sized Field.
Definition: DynamicField.H:49
Foam::autoSnapDriver::findMultiPatchPoint
pointIndexHit findMultiPatchPoint(const point &pt, const labelList &patchIDs, const List< point > &faceCentres) const
Return hit if on multiple points.
Definition: autoSnapDriverFeature.C:729
Foam::snapParameters::explicitFeatureSnap
Switch explicitFeatureSnap() const
Definition: snapParameters.H:178
Foam::snapParameters::implicitFeatureSnap
Switch implicitFeatureSnap() const
Definition: snapParameters.H:183
Foam::snapParameters::releasePoints
Switch releasePoints() const
Definition: snapParameters.H:203
n
label n
Definition: TABSMDCalcMethod2.H:31
Foam::sortedOrder
void sortedOrder(const UList< T > &, labelList &order)
Generate the (stable) sort order for the list.
Definition: ListOpsTemplates.C:179
Foam::polyBoundaryMesh::patchID
const labelList & patchID() const
Per boundary face label the patch index.
Definition: polyBoundaryMesh.C:399
Foam::autoSnapDriver::writeStats
void writeStats(const indirectPrimitivePatch &pp, const PackedBoolList &isMasterPoint, const List< pointConstraint > &patchConstraints) const
Write some stats about constraints.
Definition: autoSnapDriverFeature.C:866
Foam::snapParameters
Simple container to keep together snap specific information.
Definition: snapParameters.H:50
Foam::autoSnapDriver::splitDiagonals
void splitDiagonals(const scalar featureCos, const scalar concaveCos, const scalar minAreaFraction, const indirectPrimitivePatch &pp, const vectorField &nearestAttraction, const vectorField &nearestNormal, vectorField &patchAttraction, List< pointConstraint > &patchConstraints, DynamicList< label > &splitFaces, DynamicList< labelPair > &splits) const
Do all logic on whether to add face cut to diagonal.
Definition: autoSnapDriverFeature.C:1885
Foam::refinementSurfaces::surfZones
const PtrList< surfaceZonesInfo > & surfZones() const
Definition: refinementSurfaces.H:168
Foam::reduce
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
Definition: PstreamReduceOps.H:43
Foam::PointIndexHit
This class describes the interaction of (usually) a face and a point. It carries the info of a succes...
Definition: PointIndexHit.H:53
Foam::constant::physicoChemical::c1
const dimensionedScalar c1
First radiation constant: default SI units: [W/m2].
Foam::label
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
Foam::Field
Pre-declare SubField and related Field type.
Definition: Field.H:57
treeDataPoint.H
plane.H
Foam::faceZone
A subset of mesh faces organised as a primitive patch.
Definition: faceZone.H:64
Foam::treeBoundBox::extend
treeBoundBox extend(Random &, const scalar s) const
Return slightly wider bounding box.
Definition: treeBoundBoxI.H:317
Foam::List::append
void append(const T &)
Append an element at the end of the list.
Foam::nl
static const char nl
Definition: Ostream.H:260
Foam::Info
messageStream Info
Foam::PointIndexHit::hitPoint
const Point & hitPoint() const
Return hit point.
Definition: PointIndexHit.H:117
Foam::autoSnapDriver::reverseAttractMeshPoints
void reverseAttractMeshPoints(const label iter, const indirectPrimitivePatch &pp, const scalarField &snapDist, const List< labelList > &pointAttractor, const List< List< pointConstraint > > &pointConstraints, const List< List< DynamicList< point > > > &edgeAttractors, const List< List< DynamicList< pointConstraint > > > &, const vectorField &rawPatchAttraction, const List< pointConstraint > &rawPatchConstraints, vectorField &patchAttraction, List< pointConstraint > &patchConstraints) const
Definition: autoSnapDriverFeature.C:3112
Foam::polyPatch
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:66
refinementSurfaces.H
Foam::PrimitivePatch::pointEdges
const labelListList & pointEdges() const
Return point-edge addressing.
Definition: PrimitivePatchTemplate.C:332
Foam::DynamicList::clear
void clear()
Clear the addressed list, i.e. set the size to zero.
Definition: DynamicListI.H:242
Foam::snapParameters::stringFeatures
Switch stringFeatures() const
Definition: snapParameters.H:208
Foam::DynamicList::setCapacity
void setCapacity(const label)
Alter the size of the underlying storage.
Definition: DynamicListI.H:109
Foam::DynamicField::append
DynamicField< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Foam::IndirectList
A List with indirect addressing.
Definition: IndirectList.H:102
Foam::indexedOctree
Non-pointer based hierarchical recursive searching.
Definition: treeDataTriSurface.H:47
f1
scalar f1
Definition: createFields.H:28
Foam::PtrList
A templated 1D list of pointers to objects of type <T>, where the size of the array is known and used...
Definition: List.H:61
Foam::motionSmoother
Given a displacement moves the mesh by scaling the displacement back until there are no more mesh err...
Definition: motionSmoother.H:89
Foam::boundBox::min
const point & min() const
Minimum describing the bounding box.
Definition: boundBoxI.H:54
Foam::orEqOp
Definition: ops.H:82
Foam::autoSnapDriver::findNearFeaturePoint
Tuple2< label, pointIndexHit > findNearFeaturePoint(const bool isRegionEdge, const indirectPrimitivePatch &pp, const scalarField &snapDist, const label pointI, const point &estimatedPt, List< labelList > &pointAttractor, List< List< pointConstraint > > &pointConstraints, List< List< DynamicList< point > > > &edgeAttractors, List< List< DynamicList< pointConstraint > > > &edgeConstraints, vectorField &patchAttraction, List< pointConstraint > &patchConstraints) const
Find nearest feature point (within searchDist).
Definition: autoSnapDriverFeature.C:2136
Foam::snapParameters::concaveAngle
scalar concaveAngle() const
Definition: snapParameters.H:226
Foam::identity
labelList identity(const label len)
Create identity map (map[i] == i) of given length.
Definition: ListOps.C:104
Foam::PrimitivePatch::nPoints
label nPoints() const
Return number of points supporting patch faces.
Definition: PrimitivePatchTemplate.H:293
Foam::FatalError
error FatalError
Foam::refinementSurfaces::globalRegion
label globalRegion(const label surfI, const label regionI) const
From surface and region on surface to global region.
Definition: refinementSurfaces.H:230
mesh
dynamicFvMesh & mesh
Definition: createDynamicFvMesh.H:18
Foam::plusEqOp
Definition: ops.H:71
Foam::fvMesh
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:78
fvMesh.H
Foam
Namespace for OpenFOAM.
Definition: combustionModel.C:30
Foam::plane::ray
A direction and a reference point.
Definition: plane.H:73
Foam::indent
Ostream & indent(Ostream &os)
Indent stream.
Definition: Ostream.H:221
s
gmvFile<< "tracers "<< particles.size()<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().x()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().y()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
Foam::polyPatch::start
label start() const
Return start label of this patch in the polyMesh face list.
Definition: polyPatch.H:312
Foam::DynamicList::append
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
Foam::pointConstraint::applyConstraint
void applyConstraint(const vector &cd)
Apply and accumulate the effect of the given constraint direction.
Definition: pointConstraintI.H:48
Foam::mapDistribute::transform
Default transformation behaviour.
Definition: mapDistribute.H:196
autoSnapDriver.H
Foam::refinementSurfaces::findNearestRegion
void findNearestRegion(const labelList &surfacesToTest, const pointField &samples, const scalarField &nearestDistSqr, labelList &hitSurface, labelList &hitRegion) const
Find nearest point on surfaces. Return surface and region on.
Definition: refinementSurfaces.C:1463
Foam::pointConstraints
Application of (multi-)patch point contraints.
Definition: pointConstraints.H:62
Foam::max
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
Foam::autoSnapDriver::featureAttractionUsingFeatureEdges
void featureAttractionUsingFeatureEdges(const label iter, const bool multiRegionFeatureSnap, const bool detectBaffles, const bool baffleFeaturePoints, const bool releasePoints, const bool stringFeatures, const bool avoidDiagonal, const scalar featureCos, const indirectPrimitivePatch &pp, const scalarField &snapDist, const vectorField &nearestDisp, const vectorField &nearestNormal, const List< List< point > > &pointFaceSurfNormals, const List< List< point > > &pointFaceDisp, const List< List< point > > &pointFaceCentres, const labelListList &pointFacePatchID, vectorField &patchAttraction, List< pointConstraint > &patchConstraints) const
Definition: autoSnapDriverFeature.C:3373
Foam::autoSnapDriver::determineBaffleFeatures
void determineBaffleFeatures(const label iter, const bool baffleFeaturePoints, const scalar featureCos, const indirectPrimitivePatch &pp, const scalarField &snapDist, List< labelList > &pointAttractor, List< List< pointConstraint > > &pointConstraints, List< List< DynamicList< point > > > &edgeAttractors, List< List< DynamicList< pointConstraint > > > &edgeConstraints, vectorField &patchAttraction, List< pointConstraint > &patchConstraints) const
Determine features originating from bafles and.
Definition: autoSnapDriverFeature.C:2784
Foam::List::setSize
void setSize(const label)
Reset size of List.
Foam::autoPtr
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: PtrList.H:117
Foam::linePointRef
line< point, const point & > linePointRef
Line using referred points.
Definition: linePointRef.H:45
Foam::autoSnapDriver::findNearFeatureEdge
Tuple2< label, pointIndexHit > findNearFeatureEdge(const bool isRegionEdge, const indirectPrimitivePatch &pp, const scalarField &snapDist, const label pointI, const point &estimatedPt, List< List< DynamicList< point > > > &, List< List< DynamicList< pointConstraint > > > &, vectorField &, List< pointConstraint > &) const
Find point on nearest feature edge (within searchDist).
Definition: autoSnapDriverFeature.C:2069
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:318
Foam::plane::planeIntersect
ray planeIntersect(const plane &) const
Return the cutting line between this plane and another.
Definition: plane.C:337
Foam::sqr
dimensionedSymmTensor sqr(const dimensionedVector &dv)
Definition: dimensionedSymmTensor.C:49
Foam::pointIndexHit
PointIndexHit< point > pointIndexHit
Definition: pointIndexHit.H:42
Foam::refinementFeatures::findNearestRegionEdge
void findNearestRegionEdge(const pointField &samples, const scalarField &nearestDistSqr, labelList &nearFeature, List< pointIndexHit > &nearInfo, vectorField &nearNormal) const
Find nearest point on nearest region edge. Sets.
Definition: refinementFeatures.C:584
Foam::sumOp
Definition: ops.H:162
Foam::Pair
An ordered pair of two objects of type <T> with first() and second() elements.
Definition: contiguous.H:49
Foam::autoSnapDriver::correctAttraction
void correctAttraction(const DynamicList< point > &surfacePoints, const DynamicList< label > &surfaceCounts, const point &edgePt, const vector &edgeNormal, const point &pt, vector &edgeOffset) const
Definition: autoSnapDriverFeature.C:691
Foam::PrimitivePatch::faceNormals
const Field< PointType > & faceNormals() const
Return face normals for patch.
Definition: PrimitivePatchTemplate.C:520
Foam::autoSnapDriver::featureAttractionUsingReconstruction
void featureAttractionUsingReconstruction(const label iter, const scalar featureCos, const indirectPrimitivePatch &pp, const scalarField &snapDist, const vectorField &nearestDisp, const label pointI, const List< List< point > > &pointFaceSurfNormals, const List< List< point > > &pointFaceDisp, const List< List< point > > &pointFaceCentres, const labelListList &pointFacePatchID, DynamicList< point > &surfacePoints, DynamicList< vector > &surfaceNormals, labelList &faceToNormalBin, vector &patchAttraction, pointConstraint &patchConstraint) const
Determine attraction and constraints for single point.
Definition: autoSnapDriverFeature.C:914
Foam::refinementFeatures
Encapsulates queries for features.
Definition: refinementFeatures.H:51
f
labelList f(nPoints)
Foam::Vector< scalar >
Foam::List< T >
Foam::sqrt
dimensionedScalar sqrt(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:142
Foam::autoSnapDriver::calcNearestFace
void calcNearestFace(const label iter, const indirectPrimitivePatch &pp, const scalarField &faceSnapDist, vectorField &faceDisp, vectorField &faceSurfaceNormal, labelList &faceSurfaceRegion) const
Definition: autoSnapDriverFeature.C:221
scalarField
volScalarField scalarField(fieldObject, mesh)
Foam::PrimitivePatch::faceCentres
const Field< PointType > & faceCentres() const
Return face centres for patch.
Definition: PrimitivePatchTemplate.C:500
Foam::autoPtr::valid
bool valid() const
Return true if the autoPtr valid (ie, the pointer is set).
Definition: autoPtrI.H:83
Foam::autoSnapDriver::stringFeatureEdges
void stringFeatureEdges(const label iter, const scalar featureCos, const indirectPrimitivePatch &pp, const scalarField &snapDist, const vectorField &rawPatchAttraction, const List< pointConstraint > &rawPatchConstraints, vectorField &patchAttraction, List< pointConstraint > &patchConstraints) const
For any reverse (so from feature back to mesh) attraction:
Definition: autoSnapDriverFeature.C:1213
points
const pointField & points
Definition: gmvOutputHeader.H:1
Foam::constant::electromagnetic::e
const dimensionedScalar e
Elementary charge.
Definition: doubleFloat.H:94
Foam::autoSnapDriver::calcNearestSurfaceFeature
vectorField calcNearestSurfaceFeature(const snapParameters &snapParams, const bool alignMeshEdges, const label iter, const scalar featureCos, const scalar featureAttract, const scalarField &snapDist, const vectorField &nearestDisp, const vectorField &nearestNormal, motionSmoother &meshMover, vectorField &patchAttraction, List< pointConstraint > &patchConstraints, DynamicList< label > &splitFaces, DynamicList< labelPair > &splits) const
Top level feature attraction routine. Gets given.
Definition: autoSnapDriverFeature.C:3807
Foam::PtrList::size
label size() const
Return the number of elements in the PtrList.
Definition: PtrListI.H:32
Foam::plane::ray::refPoint
const point & refPoint() const
Definition: plane.H:87
x
x
Definition: LISASMDCalcMethod2.H:52
snapParameters.H
Foam::constant::universal::c
const dimensionedScalar c
Speed of light in a vacuum.
Foam::autoPtr::reset
void reset(T *=0)
If object pointer already set, delete object and set to given.
Definition: autoPtrI.H:114
Foam::PrimitivePatch::localFaces
const List< Face > & localFaces() const
Return patch faces addressing into local point list.
Definition: PrimitivePatchTemplate.C:372
Foam::UIndirectList
A List with indirect addressing.
Definition: fvMatrix.H:106
Foam::indexedOctree::findNearest
void findNearest(const label nodeI, const linePointRef &ln, treeBoundBox &tightest, label &nearestShapeI, point &linePoint, point &nearestPoint, const FindNearestOp &fnOp) const
Find nearest point to line.
Definition: indexedOctree.C:590
Foam::face
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:75
Foam::listPlusEqOp::operator()
void operator()(List< T > &x, const List< T > &y) const
Definition: autoSnapDriverFeature.C:53
Foam::minMagSqrEqOp
Definition: ops.H:79
Foam::autoSnapDriver::isFeaturePoint
bool isFeaturePoint(const scalar featureCos, const indirectPrimitivePatch &pp, const PackedBoolList &isFeatureEdge, const label pointI) const
Is point on two feature edges that make a largish angle?
Definition: autoSnapDriverFeature.C:69
Foam::OFstream::name
const fileName & name() const
Return the name of the stream.
Definition: OFstream.H:118
Foam::autoSnapDriver::releasePointsNextToMultiPatch
void releasePointsNextToMultiPatch(const label iter, const scalar featureCos, const indirectPrimitivePatch &pp, const scalarField &snapDist, const List< List< point > > &pointFaceCentres, const labelListList &pointFacePatchID, const vectorField &rawPatchAttraction, const List< pointConstraint > &rawPatchConstraints, vectorField &patchAttraction, List< pointConstraint > &patchConstraints) const
Remove constraints of points next to multi-patch points.
Definition: autoSnapDriverFeature.C:1402
Foam::List::size
void size(const label)
Override size to be inconsistent with allocated storage.
featureEdgeMesh.H
Foam::Tuple2< label, vector >
Foam::point
vector point
Point is a vector.
Definition: point.H:41
Foam::autoSnapDriver::preventFaceSqueeze
void preventFaceSqueeze(const label iter, const scalar featureCos, const indirectPrimitivePatch &pp, const scalarField &snapDist, const vectorField &nearestAttraction, vectorField &patchAttraction, List< pointConstraint > &patchConstraints) const
Definition: autoSnapDriverFeature.C:3671
Foam::PrimitivePatch::meshPoints
const labelList & meshPoints() const
Return labelList of mesh points in patch.
Definition: PrimitivePatchTemplate.C:392
Foam::refinementSurfaces
Container for data on surfaces used for surface-driven refinement. Contains all the data about the le...
Definition: refinementSurfaces.H:60
Foam::edge::otherVertex
label otherVertex(const label a) const
Given one vertex, return the other.
Definition: edgeI.H:103
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:259
pyramidPointFaceRef.H
Foam::refinementFeatures::findNearestEdge
void findNearestEdge(const pointField &samples, const scalarField &nearestDistSqr, labelList &nearFeature, List< pointIndexHit > &nearInfo, vectorField &nearNormal) const
Find nearest point on nearest feature edge. Sets.
Definition: refinementFeatures.C:525
Foam::labelPair
Pair< label > labelPair
Label pair.
Definition: labelPair.H:48
Foam::magSqr
dimensioned< scalar > magSqr(const dimensioned< Type > &)
rndGen
cachedRandom rndGen(label(0), -1)
writeStats
void writeStats(const extendedFeatureEdgeMesh &fem, Ostream &os)
Definition: surfaceFeatureExtract.C:902
Foam::listPlusEqOp
Definition: autoSnapDriverFeature.C:49
OBJstream.H
Foam::plane::planePlaneIntersect
point planePlaneIntersect(const plane &, const plane &) const
Return the cutting point between this plane and two other planes.
Definition: plane.C:406
Foam::name
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
Foam::snapParameters::multiRegionFeatureSnap
Switch multiRegionFeatureSnap() const
Definition: snapParameters.H:188
y
scalar y
Definition: LISASMDCalcMethod1.H:14
Foam::PrimitivePatch
A list of faces which address into the list of points.
Definition: PrimitivePatchTemplate.H:88
Foam::degToRad
scalar degToRad(const scalar deg)
Conversion from degrees to radians.
Definition: unitConversion.H:45
Foam::cos
dimensionedScalar cos(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:256