1 // Copyright (C) 2007-2013 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
22 // File : StdMeshers_Adaptive1D.cxx
25 #include "StdMeshers_Adaptive1D.hxx"
27 #include "SMESH_Gen.hxx"
28 #include "SMESH_Mesh.hxx"
29 #include "SMESH_MesherHelper.hxx"
30 #include "SMESH_Octree.hxx"
31 #include "SMESH_subMesh.hxx"
32 #include "SMESH_HypoFilter.hxx"
34 #include <Utils_SALOME_Exception.hxx>
36 #include <BRepAdaptor_Curve.hxx>
37 #include <BRepAdaptor_Surface.hxx>
38 #include <BRepMesh_IncrementalMesh.hxx>
39 #include <BRep_Tool.hxx>
40 #include <Bnd_B3d.hxx>
41 #include <GCPnts_AbscissaPoint.hxx>
42 #include <GeomAdaptor_Curve.hxx>
43 #include <Geom_Curve.hxx>
44 #include <Poly_Array1OfTriangle.hxx>
45 #include <Poly_Triangulation.hxx>
46 #include <TColgp_Array1OfPnt.hxx>
48 #include <TopExp_Explorer.hxx>
49 #include <TopLoc_Location.hxx>
50 #include <TopTools_IndexedMapOfShape.hxx>
52 #include <TopoDS_Edge.hxx>
53 #include <TopoDS_Face.hxx>
54 #include <TopoDS_Vertex.hxx>
64 namespace // internal utils
66 //================================================================================
68 * \brief Working data of an EDGE
77 ProbePnt( gp_Pnt p, double u, double sz=1e100 ): myP( p ), myU( u ), mySegSize( sz ) {}
79 BRepAdaptor_Curve myC3d;
81 list< ProbePnt > myPoints;
83 typedef list< ProbePnt >::iterator TPntIter;
84 void AddPoint( TPntIter where, double u )
86 myPoints.insert( where, ProbePnt( myC3d.Value( u ), u ));
88 const ProbePnt& First() const { return myPoints.front(); }
89 const ProbePnt& Last() const { return myPoints.back(); }
90 const TopoDS_Edge& Edge() const { return myC3d.Edge(); }
93 //================================================================================
95 * \brief Bnd_B3d with access to its center and half-size
97 struct BBox : public Bnd_B3d
99 gp_XYZ Center() const { return gp_XYZ( myCenter[0], myCenter[1], myCenter[2] ); }
100 gp_XYZ HSize() const { return gp_XYZ( myHSize[0], myHSize[1], myHSize[2] ); }
101 double Size() const { return 2 * myHSize[0]; }
103 //================================================================================
105 * \brief Octree of local segment size
107 class SegSizeTree : public SMESH_Octree
109 double mySegSize; // segment size
111 // structure holding some common parameters of SegSizeTree
112 struct _CommonData : public SMESH_TreeLimit
114 double myGrading, myMinSize, myMaxSize;
116 _CommonData* getData() const { return (_CommonData*) myLimit; }
118 SegSizeTree(double size): SMESH_Octree(), mySegSize(size)
122 void allocateChildren()
124 myChildren = new SMESH_Octree::TBaseTree*[nbChildren()];
125 for ( int i = 0; i < nbChildren(); ++i )
126 myChildren[i] = NULL;
128 virtual box_type* buildRootBox() { return 0; }
129 virtual SegSizeTree* newChild() const { return 0; }
130 virtual void buildChildrenData() {}
134 SegSizeTree( Bnd_B3d & bb, double grading, double mixSize, double maxSize);
135 void SetSize( const gp_Pnt& p, double size );
136 double SetSize( const gp_Pnt& p1, const gp_Pnt& p2 );
137 double GetSize( const gp_Pnt& p ) const;
138 const BBox* GetBox() const { return (BBox*) getBox(); }
139 double GetMinSize() { return getData()->myMinSize; }
141 //================================================================================
143 * \brief Data of triangle used to locate it in an octree and to find distance
149 // data for DistToProjection()
150 gp_XYZ myN0, myEdge1, myEdge2, myNorm, myPVec;
151 double myInvDet, myMaxSize2;
153 void Init( const gp_Pnt& n1, const gp_Pnt& n2, const gp_Pnt& n3 );
154 bool DistToProjection( const gp_Pnt& p, double& dist ) const;
156 //================================================================================
158 * \brief Element data held by ElementBndBoxTree + algorithm computing a distance
159 * from a point to element
161 class ElementBndBoxTree;
162 struct ElemTreeData : public SMESH_TreeLimit
164 virtual const Bnd_B3d* GetBox(int elemID) const = 0;
166 struct TriaTreeData : public ElemTreeData
168 vector< Triangle > myTrias;
170 double myTriasDeflection;
171 const ElementBndBoxTree* myTree;
172 const Poly_Array1OfTriangle* myPolyTrias;
173 const TColgp_Array1OfPnt* myNodes;
176 TriaTreeData( const TopoDS_Face& face, ElementBndBoxTree* triaTree );
177 ~TriaTreeData() { if ( myOwnNodes ) delete myNodes; myNodes = NULL; }
178 virtual const Bnd_B3d* GetBox(int elemID) const { return &myTrias[elemID].myBox; }
179 void SetSizeByTrias( SegSizeTree& sizeTree, double deflection ) const;
180 double GetMinDistInSphere(const gp_Pnt& p,
182 const bool projectedOnly,
183 const gp_Pnt* avoidP=0) const;
185 //================================================================================
187 * \brief Octree of triangles or segments
189 class ElementBndBoxTree : public SMESH_Octree
192 ElementBndBoxTree(const TopoDS_Face& face);
193 void GetElementsInSphere( const gp_XYZ& center,
194 const double radius, std::set<int> & foundElemIDs) const;
195 ElemTreeData* GetElemData() const { return (ElemTreeData*) myLimit; }
196 TriaTreeData* GetTriaData() const { return (TriaTreeData*) myLimit; }
199 ElementBndBoxTree() {}
200 SMESH_Octree* newChild() const { return new ElementBndBoxTree; }
201 void buildChildrenData();
202 Bnd_B3d* buildRootBox();
204 vector< int > _elementIDs;
206 //================================================================================
208 * \brief BRepMesh_IncrementalMesh with access to its protected Bnd_Box
210 struct IncrementalMesh : public BRepMesh_IncrementalMesh
212 IncrementalMesh(const TopoDS_Shape& shape,
213 const Standard_Real deflection,
214 const bool relative):
215 BRepMesh_IncrementalMesh( shape, deflection, relative )
218 Bnd_B3d GetBox() const
220 Standard_Real TXmin, TYmin, TZmin, TXmax, TYmax, TZmax;
221 myBox.Get(TXmin, TYmin, TZmin, TXmax, TYmax, TZmax);
223 bb.Add( gp_XYZ( TXmin, TYmin, TZmin ));
224 bb.Add( gp_XYZ( TXmax, TYmax, TZmax ));
229 //================================================================================
231 * \brief Initialize TriaTreeData
233 //================================================================================
235 TriaTreeData::TriaTreeData( const TopoDS_Face& face, ElementBndBoxTree* triaTree )
236 : myTree(NULL), myPolyTrias(NULL), myNodes(NULL), myOwnNodes(false), myTriasDeflection(0)
239 Handle(Poly_Triangulation) tr = BRep_Tool::Triangulation( face, loc );
242 myFaceTol = SMESH_MesherHelper::MaxTolerance( face );
244 myNodes = & tr->Nodes();
245 myPolyTrias = & tr->Triangles();
246 myTriasDeflection = tr->Deflection();
247 if ( !loc.IsIdentity() ) // transform nodes if necessary
249 TColgp_Array1OfPnt* trsfNodes = new TColgp_Array1OfPnt( myNodes->Lower(), myNodes->Upper() );
250 trsfNodes->Assign( *myNodes );
253 const gp_Trsf& trsf = loc;
254 for ( int i = trsfNodes->Lower(); i <= trsfNodes->Upper(); ++i )
255 trsfNodes->ChangeValue(i).Transform( trsf );
257 myTrias.resize( myPolyTrias->Length() );
258 Standard_Integer n1,n2,n3;
259 for ( int i = 1; i <= myPolyTrias->Upper(); ++i )
261 myPolyTrias->Value( i ).Get( n1,n2,n3 );
262 myTrias[ i-1 ].Init( myNodes->Value( n1 ),
263 myNodes->Value( n2 ),
264 myNodes->Value( n3 ));
266 // TODO: mark triangles with nodes on VERTEXes to
267 // less frequently compare with avoidPnt in GetMinDistInSphere()
269 // Handle(Poly_PolygonOnTriangulation) polygon =
270 // BRep_Tool::PolygonOnTriangulation( edge, tr, loc );
271 // if ( polygon.IsNull() /*|| !pologon.HasParameters()*/ )
273 // Handle(TColStd_Array1OfInteger) nodeIDs = polygon->Nodes();
276 //================================================================================
278 * \brief Set size of segments by size of triangles
280 //================================================================================
282 void TriaTreeData::SetSizeByTrias( SegSizeTree& sizeTree, double deflection ) const
284 if ( myTriasDeflection <= std::numeric_limits<double>::min() )
286 const double factor = deflection / myTriasDeflection;
288 Standard_Integer n1,n2,n3;
291 for ( int i = 1; i <= myPolyTrias->Upper(); ++i )
293 // compute minimal altitude of a triangle
294 myPolyTrias->Value( i ).Get( n1,n2,n3 );
295 p[0] = myNodes->Value( n1 );
296 p[1] = myNodes->Value( n2 );
297 p[2] = myNodes->Value( n3 );
299 a[0] = p[0].Distance( p[1] );
300 a[1] = p[1].Distance( p[2] );
301 a[2] = p[2].Distance( p[3] );
302 double maxSide = Max( a[0], Max( a[1], a[2] ));
303 double s = 0.5 * ( a[0] + a[1] + a[2] );
304 double area = sqrt( s * (s - a[0]) * (s - a[1]) * (s - a[2]));
305 double sz = 2 * area / maxSide; // minimal altitude
306 for ( int j = 0; j < 3; ++j )
308 int nb = 2 * int( a[j] / sz + 0.5 );
309 for ( int k = 1; k <= nb; ++k )
311 double r = double( k ) / nb;
312 sizeTree.SetSize( r * p[j].XYZ() + ( 1-r ) * p[j+1].XYZ(), sz * factor );
315 sizeTree.SetSize(( p[0].XYZ() + p[1].XYZ() + p[2].XYZ()) / 3., sz * factor );
316 //cout << "SetSizeByTrias, i="<< i << " " << sz * factor << endl;
319 //================================================================================
321 * \brief Return minimal distance from a given point to a trinangle but not more
322 * distant than a given radius. Triangles with a node at avoidPnt are ignored.
325 //================================================================================
327 double TriaTreeData::GetMinDistInSphere(const gp_Pnt& p,
329 const bool projectedOnly,
330 const gp_Pnt* avoidPnt) const
332 double minDist2 = 1e100;
333 const double tol2 = myFaceTol * myFaceTol;
335 std::set<int> foundElemIDs;
336 myTree->GetElementsInSphere( p.XYZ(), radius, foundElemIDs );
338 std::set<int>::iterator id = foundElemIDs.begin();
339 Standard_Integer n[ 3 ];
340 for ( ; id != foundElemIDs.end(); ++id )
342 double d, minD2 = minDist2;
343 bool avoidTria = false;
344 myPolyTrias->Value( *id+1 ).Get( n[0],n[1],n[2] );
345 for ( int i = 0; i < 3; ++i )
347 const gp_Pnt& pn = myNodes->Value(n[i]);
348 if ( avoidTria = ( avoidPnt && pn.SquareDistance(*avoidPnt) <= tol2 ))
350 if ( !projectedOnly )
351 minD2 = Min( minD2, pn.SquareDistance( p ));
355 const Triangle& t = myTrias[ *id ];
356 if ( minD2 < t.myMaxSize2 && t.DistToProjection( p, d ))
357 minD2 = Min( minD2, d*d );
358 minDist2 = Min( minDist2, minD2 );
361 return sqrt( minDist2 );
363 //================================================================================
365 * \brief Prepare Triangle data
367 //================================================================================
369 void Triangle::Init( const gp_Pnt& p1, const gp_Pnt& p2, const gp_Pnt& p3 )
375 myEdge1 = p2.XYZ() - myN0;
376 myEdge2 = p3.XYZ() - myN0;
377 myNorm = myEdge1 ^ myEdge2;
378 double normSize = myNorm.Modulus();
379 if ( normSize > std::numeric_limits<double>::min() )
382 myPVec = myNorm ^ myEdge2;
383 myInvDet = 1. / ( myEdge1 * myPVec );
389 myMaxSize2 = Max( p2.SquareDistance( p3 ),
390 Max( myEdge2.SquareModulus(), myEdge1.SquareModulus() ));
392 //================================================================================
394 * \brief Compute distance from a point to the triangle. Return false if the point
395 * is not projected inside the triangle
397 //================================================================================
399 bool Triangle::DistToProjection( const gp_Pnt& p, double& dist ) const
402 return false; // degenerated triangle
404 /* distance from n0 to the point */
405 gp_XYZ tvec = p.XYZ() - myN0;
407 /* calculate U parameter and test bounds */
408 double u = ( tvec * myPVec ) * myInvDet;
409 if (u < 0.0 || u > 1.0)
410 return false; // projected outside the triangle
412 /* calculate V parameter and test bounds */
413 gp_XYZ qvec = tvec ^ myEdge1;
414 double v = ( myNorm * qvec) * myInvDet;
415 if ( v < 0.0 || u + v > 1.0 )
416 return false; // projected outside the triangle
418 dist = ( myEdge2 * qvec ) * myInvDet;
422 //================================================================================
424 * \brief Consturct ElementBndBoxTree of Poly_Triangulation of a FACE
426 //================================================================================
428 ElementBndBoxTree::ElementBndBoxTree(const TopoDS_Face& face)
431 TriaTreeData* data = new TriaTreeData( face, this );
432 data->myMaxLevel = 5;
435 if ( !data->myTrias.empty() )
437 for ( size_t i = 0; i < data->myTrias.size(); ++i )
438 _elementIDs.push_back( i );
443 //================================================================================
445 * \brief Return the maximal box
447 //================================================================================
449 Bnd_B3d* ElementBndBoxTree::buildRootBox()
451 Bnd_B3d* box = new Bnd_B3d;
452 ElemTreeData* data = GetElemData();
453 for ( int i = 0; i < _elementIDs.size(); ++i )
454 box->Add( *data->GetBox( _elementIDs[i] ));
458 //================================================================================
460 * \brief Redistrubute element boxes among children
462 //================================================================================
464 void ElementBndBoxTree::buildChildrenData()
466 ElemTreeData* data = GetElemData();
467 for ( int i = 0; i < _elementIDs.size(); ++i )
469 const Bnd_B3d* elemBox = data->GetBox( _elementIDs[i] );
470 for (int j = 0; j < 8; j++)
471 if ( !elemBox->IsOut( *myChildren[j]->getBox() ))
472 ((ElementBndBoxTree*)myChildren[j])->_elementIDs.push_back( _elementIDs[i] );
474 SMESHUtils::FreeVector( _elementIDs ); // = _elements.clear() + free memory
476 const int theMaxNbElemsInLeaf = 7;
478 for (int j = 0; j < 8; j++)
480 ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j] );
481 if ( child->_elementIDs.size() <= theMaxNbElemsInLeaf )
482 child->myIsLeaf = true;
485 //================================================================================
487 * \brief Return elements from leaves intersecting the sphere
489 //================================================================================
491 void ElementBndBoxTree::GetElementsInSphere( const gp_XYZ& center,
493 std::set<int> & foundElemIDs) const
495 if ( const box_type* box = getBox() )
497 if ( box->IsOut( center, radius ))
502 ElemTreeData* data = GetElemData();
503 for ( int i = 0; i < _elementIDs.size(); ++i )
504 if ( !data->GetBox( _elementIDs[i] )->IsOut( center, radius ))
505 foundElemIDs.insert( _elementIDs[i] );
509 for (int i = 0; i < 8; i++)
510 ((ElementBndBoxTree*) myChildren[i])->GetElementsInSphere( center, radius, foundElemIDs );
515 //================================================================================
517 * \brief Constructor of SegSizeTree
518 * \param [in,out] bb - bounding box enclosing all EDGEs to discretize
519 * \param [in] grading - factor to get max size of the neighbour segment by
520 * size of a current one.
522 //================================================================================
524 SegSizeTree::SegSizeTree( Bnd_B3d & bb, double grading, double minSize, double maxSize )
525 : SMESH_Octree( new _CommonData() )
527 // make cube myBox from the box bb
528 gp_XYZ pmin = bb.CornerMin(), pmax = bb.CornerMax();
529 double maxBoxHSize = 0.5 * Max( pmax.X()-pmin.X(), Max( pmax.Y()-pmin.Y(), pmax.Z()-pmin.Z() ));
531 bb.SetHSize( gp_XYZ( maxBoxHSize, maxBoxHSize, maxBoxHSize ));
532 myBox = new box_type( bb );
534 mySegSize = Min( 2 * maxBoxHSize, maxSize );
536 getData()->myGrading = grading;
537 getData()->myMinSize = Max( minSize, 2*maxBoxHSize / 1.e6 );
538 getData()->myMaxSize = maxSize;
542 //================================================================================
544 * \brief Set segment size at a given point
546 //================================================================================
548 void SegSizeTree::SetSize( const gp_Pnt& p, double size )
550 // check if the point is out of the largest cube
551 SegSizeTree* root = this;
552 while ( root->myFather )
553 root = (SegSizeTree*) root->myFather;
554 if ( root->getBox()->IsOut( p.XYZ() ))
557 // keep size whthin the valid range
558 size = Max( size, getData()->myMinSize );
559 //size = Min( size, getData()->myMaxSize );
561 // find an existing leaf at the point
562 SegSizeTree* leaf = (SegSizeTree*) root;
566 iChild = SMESH_Octree::getChildIndex( p.X(), p.Y(), p.Z(), leaf->GetBox()->Center() );
567 if ( leaf->myChildren[ iChild ] )
568 leaf = (SegSizeTree*) leaf->myChildren[ iChild ];
572 // don't increase the current size
573 if ( leaf->mySegSize <= 1.1 * size )
576 // split the found leaf until its box size is less than the given size
577 const double rootSize = root->GetBox()->Size();
578 while ( leaf->GetBox()->Size() > size )
580 const BBox* bb = leaf->GetBox();
581 iChild = SMESH_Octree::getChildIndex( p.X(), p.Y(), p.Z(), bb->Center() );
582 SegSizeTree* newLeaf = new SegSizeTree( bb->Size() / 2 );
583 leaf->myChildren[iChild] = newLeaf;
584 newLeaf->myFather = leaf;
585 newLeaf->myLimit = leaf->myLimit;
586 newLeaf->myLevel = leaf->myLevel + 1;
587 newLeaf->myBox = leaf->newChildBox( iChild );
588 newLeaf->myBox->Enlarge( rootSize * 1e-10 );
589 //newLeaf->myIsLeaf = ( newLeaf->mySegSize <= size );
592 leaf->mySegSize = size;
594 // propagate increased size out from the leaf
595 double boxSize = leaf->GetBox()->Size();
596 double sizeInc = size + boxSize * getData()->myGrading;
597 for ( int iDir = 1; iDir <= 3; ++iDir )
600 outPnt.SetCoord( iDir, p.Coord( iDir ) + boxSize );
601 SetSize( outPnt, sizeInc );
602 outPnt.SetCoord( iDir, p.Coord( iDir ) - boxSize );
603 SetSize( outPnt, sizeInc );
606 //================================================================================
608 * \brief Set size of a segment given by two end points
610 //================================================================================
612 double SegSizeTree::SetSize( const gp_Pnt& p1, const gp_Pnt& p2 )
614 const double size = p1.Distance( p2 );
615 gp_XYZ p = 0.5 * ( p1.XYZ() + p2.XYZ() );
619 //cout << "SetSize " << p1.Distance( p2 ) << " at " << p.X() <<", "<< p.Y()<<", "<<p.Z()<< endl;
623 //================================================================================
625 * \brief Return segment size at a point
627 //================================================================================
629 double SegSizeTree::GetSize( const gp_Pnt& p ) const
631 const SegSizeTree* leaf = this;
634 int iChild = SMESH_Octree::getChildIndex( p.X(), p.Y(), p.Z(), leaf->GetBox()->Center() );
635 if ( leaf->myChildren[ iChild ] )
636 leaf = (SegSizeTree*) leaf->myChildren[ iChild ];
638 return leaf->mySegSize;
640 return mySegSize; // just to return anything
643 //================================================================================
645 * \brief Evaluate curve deflection between two points
646 * \param theCurve - the curve
647 * \param theU1 - the parameter of the first point
648 * \param theU2 - the parameter of the second point
649 * \retval double - square deflection value
651 //================================================================================
653 double deflection2(const BRepAdaptor_Curve & theCurve,
657 // line between theU1 and theU2
658 gp_Pnt p1 = theCurve.Value( theU1 ), p2 = theCurve.Value( theU2 );
659 gp_Lin segment( p1, gp_Vec( p1, p2 ));
661 // evaluate square distance of theCurve from the segment
662 Standard_Real dist2 = 0;
664 const double step = ( theU2 - theU1 ) / nbPnt;
665 while (( theU1 += step ) < theU2 )
666 dist2 = Max( dist2, segment.SquareDistance( theCurve.Value( theU1 )));
673 //=======================================================================
674 //function : StdMeshers_Adaptive1D
675 //purpose : Constructor
676 StdMeshers_Adaptive1D::StdMeshers_Adaptive1D(int hypId,
679 :SMESH_Hypothesis(hypId, studyId, gen)
685 _name = "Adaptive1D";
686 _param_algo_dim = 1; // is used by SMESH_Regular_1D
688 //=======================================================================
689 //function : ~StdMeshers_Adaptive1D
690 //purpose : Destructor
691 StdMeshers_Adaptive1D::~StdMeshers_Adaptive1D()
693 delete myAlgo; myAlgo = NULL;
695 //=======================================================================
696 //function : SetDeflection
698 void StdMeshers_Adaptive1D::SetDeflection(double value)
699 throw(SALOME_Exception)
701 if (value <= std::numeric_limits<double>::min() )
702 throw SALOME_Exception("Deflection must be greater that zero");
703 if (myDeflection != value)
705 myDeflection = value;
706 NotifySubMeshesHypothesisModification();
709 //=======================================================================
710 //function : SetMinSize
711 //purpose : Sets minimal allowed segment length
712 void StdMeshers_Adaptive1D::SetMinSize(double minSize)
713 throw(SALOME_Exception)
715 if (minSize <= std::numeric_limits<double>::min() )
716 throw SALOME_Exception("Min size must be greater that zero");
718 if (myMinSize != minSize )
721 NotifySubMeshesHypothesisModification();
724 //=======================================================================
725 //function : SetMaxSize
726 //purpose : Sets maximal allowed segment length
727 void StdMeshers_Adaptive1D::SetMaxSize(double maxSize)
728 throw(SALOME_Exception)
730 if (maxSize <= std::numeric_limits<double>::min() )
731 throw SALOME_Exception("Max size must be greater that zero");
733 if (myMaxSize != maxSize )
736 NotifySubMeshesHypothesisModification();
739 //=======================================================================
741 //purpose : Persistence
742 ostream & StdMeshers_Adaptive1D::SaveTo(ostream & save)
744 save << myMinSize << " " << myMaxSize << " " << myDeflection;
745 save << " " << -1 << " " << -1; // preview addition of parameters
748 //=======================================================================
749 //function : LoadFrom
750 //purpose : Persistence
751 istream & StdMeshers_Adaptive1D::LoadFrom(istream & load)
754 bool isOK = (load >> myMinSize >> myMaxSize >> myDeflection >> dummyParam >> dummyParam);
756 load.clear(ios::badbit | load.rdstate());
759 //=======================================================================
760 //function : SetParametersByMesh
761 //purpose : Initialize parameters by the mesh built on the geometry
762 //param theMesh - the built mesh
763 //param theShape - the geometry of interest
764 //retval bool - true if parameter values have been successfully defined
765 bool StdMeshers_Adaptive1D::SetParametersByMesh(const SMESH_Mesh* theMesh,
766 const TopoDS_Shape& theShape)
768 if ( !theMesh || theShape.IsNull() )
772 TopTools_IndexedMapOfShape edgeMap;
773 TopExp::MapShapes( theShape, TopAbs_EDGE, edgeMap );
775 SMESH_MesherHelper helper( (SMESH_Mesh&) *theMesh );
776 double minSz2 = 1e100, maxSz2 = 0, sz2, maxDefl2 = 0;
777 for ( int iE = 1; iE <= edgeMap.Extent(); ++iE )
779 const TopoDS_Edge& edge = TopoDS::Edge( edgeMap( iE ));
780 SMESHDS_SubMesh* smDS = theMesh->GetMeshDS()->MeshElements( edge );
781 if ( !smDS ) continue;
784 helper.SetSubShape( edge );
785 BRepAdaptor_Curve curve( edge );
787 SMDS_ElemIteratorPtr segIt = smDS->GetElements();
788 while ( segIt->more() )
790 const SMDS_MeshElement* seg = segIt->next();
791 const SMDS_MeshNode* n1 = seg->GetNode(0);
792 const SMDS_MeshNode* n2 = seg->GetNode(1);
793 sz2 = SMESH_TNodeXYZ( n1 ).SquareDistance( n2 );
794 minSz2 = Min( minSz2, sz2 );
795 maxSz2 = Max( maxSz2, sz2 );
796 if ( curve.GetType() != GeomAbs_Line )
798 double u1 = helper.GetNodeU( edge, n1, n2 );
799 double u2 = helper.GetNodeU( edge, n2, n1 );
800 maxDefl2 = Max( maxDefl2, deflection2( curve, u1, u2 ));
806 myMinSize = sqrt( minSz2 );
807 myMaxSize = sqrt( maxSz2 );
809 myDeflection = maxDefl2;
814 //=======================================================================
815 //function : SetParametersByDefaults
816 //purpose : Initialize my parameter values by default parameters.
817 //retval : bool - true if parameter values have been successfully defined
818 bool StdMeshers_Adaptive1D::SetParametersByDefaults(const TDefaults& dflts,
819 const SMESH_Mesh* /*theMesh*/)
821 myMinSize = dflts._elemLength / 100;
822 myMaxSize = dflts._elemLength * 2;
823 myDeflection = myMinSize / 10;
827 //=======================================================================
829 //purpose : Returns an algorithm that works using this hypothesis
830 //=======================================================================
832 StdMeshers_AdaptiveAlgo_1D* StdMeshers_Adaptive1D::GetAlgo() const
836 StdMeshers_AdaptiveAlgo_1D* newAlgo =
837 new StdMeshers_AdaptiveAlgo_1D( _gen->GetANewId(), _studyId, _gen );
838 newAlgo->SetHypothesis( this );
840 ((StdMeshers_Adaptive1D*) this)->myAlgo = newAlgo;
845 //================================================================================
849 //================================================================================
851 StdMeshers_AdaptiveAlgo_1D::StdMeshers_AdaptiveAlgo_1D(int hypId,
854 : StdMeshers_Regular_1D( hypId, studyId, gen ),
857 _name = "AdaptiveAlgo_1D";
860 //================================================================================
862 * \brief Sets the hypothesis
864 //================================================================================
866 void StdMeshers_AdaptiveAlgo_1D::SetHypothesis( const StdMeshers_Adaptive1D* hyp )
871 //================================================================================
873 * \brief Creates segments on all given EDGEs
875 //================================================================================
877 bool StdMeshers_AdaptiveAlgo_1D::Compute(SMESH_Mesh & theMesh,
878 const TopoDS_Shape & theShape,
884 if ( myHyp->GetMinSize() > myHyp->GetMaxSize() )
885 return error( "Bad parameters: min size > max size" );
887 SMESH_MesherHelper helper( theMesh );
888 const double grading = 0.7;
890 TopTools_IndexedMapOfShape edgeMap, faceMap;
891 TopExp::MapShapes( theShape, TopAbs_EDGE, edgeMap );
892 TopExp::MapShapes( theMesh.GetShapeToMesh(), TopAbs_FACE, faceMap );
894 // Triangulate the shape with the given deflection ?????????
897 IncrementalMesh im( theMesh.GetShapeToMesh(), myHyp->GetDeflection(), /*Relatif=*/false);
902 // holder of segment size at each point
903 SegSizeTree sizeTree( box, grading, myHyp->GetMinSize(), myHyp->GetMaxSize() );
905 // minimal segment size that sizeTree can store with reasonable tree height
906 const double minSize = Max( myHyp->GetMinSize(), 1.1 * sizeTree.GetMinSize() );
909 // working data of EDGEs
910 vector< EdgeData > edges;
912 // sort EDGEs by length
913 multimap< double, TopoDS_Edge > edgeOfLength;
914 for ( int iE = 1; iE <= edgeMap.Extent(); ++iE )
916 const TopoDS_Edge & edge = TopoDS::Edge( edgeMap( iE ));
917 if ( !SMESH_Algo::isDegenerated( edge) )
918 edgeOfLength.insert( make_pair( EdgeLength( edge ), edge ));
920 edges.resize( edgeOfLength.size() );
921 multimap< double, TopoDS_Edge >::const_iterator len2edge = edgeOfLength.begin();
922 for ( int iE = 0; len2edge != edgeOfLength.end(); ++len2edge, ++iE )
924 const TopoDS_Edge & edge = len2edge->second;
925 EdgeData& eData = edges[ iE ];
926 eData.myC3d.Initialize( edge );
927 eData.myLength = EdgeLength( edge );
928 eData.AddPoint( eData.myPoints.end(), eData.myC3d.FirstParameter() );
929 eData.AddPoint( eData.myPoints.end(), eData.myC3d.LastParameter() );
933 // Take into account size of already existing segments
934 SMDS_EdgeIteratorPtr segIterator = theMesh.GetMeshDS()->edgesIterator();
935 while ( segIterator->more() )
937 const SMDS_MeshElement* seg = segIterator->next();
938 sizeTree.SetSize( SMESH_TNodeXYZ( seg->GetNode( 0 )), SMESH_TNodeXYZ( seg->GetNode( 1 )));
941 // Set size of segments according to the deflection
943 StdMeshers_Regular_1D::_hypType = DEFLECTION;
944 StdMeshers_Regular_1D::_value[ DEFLECTION_IND ] = myHyp->GetDeflection();
946 list< double > params;
947 for ( int iE = 0; iE < edges.size(); ++iE )
949 EdgeData& eData = edges[ iE ];
950 //cout << "E " << theMesh.GetMeshDS()->ShapeToIndex( eData.Edge() ) << endl;
952 double f = eData.First().myU, l = eData.Last().myU;
953 if ( !computeInternalParameters( theMesh, eData.myC3d, eData.myLength, f,l, params, false, false ))
955 if ( params.size() <= 1 && helper.IsClosedEdge( eData.Edge() ) ) // 2 segments on a circle
958 for ( int i = 1; i < 6; ++i )
959 params.push_back(( l - f ) * i/6. );
961 EdgeData::TPntIter where = --eData.myPoints.end();
962 list< double >::const_iterator param = params.begin();
963 for ( ; param != params.end(); ++param )
964 eData.AddPoint( where, *param );
966 EdgeData::TPntIter pIt2 = eData.myPoints.begin(), pIt1 = pIt2++;
967 for ( ; pIt2 != eData.myPoints.end(); ++pIt1, ++pIt2 )
968 sizeTree.SetSize( (*pIt1).myP, (*pIt2).myP );
971 // Limit size of segments according to distance to closest FACE
973 for ( int iF = 1; iF <= faceMap.Extent(); ++iF )
975 const TopoDS_Face & face = TopoDS::Face( faceMap( iF ));
976 // cout << "FACE " << iF << "/" << faceMap.Extent()
977 // << " id-" << theMesh.GetMeshDS()->ShapeToIndex( face ) << endl;
979 ElementBndBoxTree triaTree( face ); // tree of FACE triangulation
980 TriaTreeData* triaSearcher = triaTree.GetTriaData();
982 if ( BRepAdaptor_Surface( face ).GetType() != GeomAbs_Plane )
983 triaSearcher->SetSizeByTrias( sizeTree, myHyp->GetDeflection() );
985 for ( int iE = 0; iE < edges.size(); ++iE )
987 EdgeData& eData = edges[ iE ];
989 // check if the face is in topological contact with the edge
990 bool isAdjFace = ( helper.IsSubShape( helper.IthVertex( 0, eData.Edge()), face ) ||
991 helper.IsSubShape( helper.IthVertex( 1, eData.Edge()), face ));
993 bool sizeDecreased = true;
994 for (int iLoop = 0; sizeDecreased; ++iLoop ) //repeat until segment size along the edge becomes stable
996 // get points to check distance to the face
997 EdgeData::TPntIter pIt2 = eData.myPoints.begin(), pIt1 = pIt2++;
998 pIt1->mySegSize = sizeTree.GetSize( pIt1->myP );
999 for ( ; pIt2 != eData.myPoints.end(); )
1001 pIt2->mySegSize = sizeTree.GetSize( pIt2->myP );
1002 double curSize = Min( pIt1->mySegSize, pIt2->mySegSize );
1003 if ( pIt1->myP.Distance( pIt2->myP ) > curSize )
1005 double midU = 0.5*( pIt1->myU + pIt2->myU );
1006 gp_Pnt midP = eData.myC3d.Value( midU );
1007 double midSz = sizeTree.GetSize( midP );
1008 pIt2 = eData.myPoints.insert( pIt2, EdgeData::ProbePnt( midP, midU, midSz ));
1015 // check if the face is more distant than a half of the current segment size,
1016 // if not, segment size is decreased
1017 sizeDecreased = false;
1018 const gp_Pnt* avoidPnt = & eData.First().myP;
1019 for ( pIt1 = eData.myPoints.begin(); pIt1 != eData.myPoints.end(); )
1022 triaSearcher->GetMinDistInSphere( pIt1->myP, pIt1->mySegSize, isAdjFace, avoidPnt );
1023 double allowedSize = Max( minSize, distToFace*( 1. + grading ));
1024 if ( 1.1 * allowedSize < pIt1->mySegSize )
1026 sizeDecreased = true;
1027 sizeTree.SetSize( pIt1->myP, allowedSize );
1028 // cout << "E " << theMesh.GetMeshDS()->ShapeToIndex( eData.Edge() )
1029 // << "\t SetSize " << allowedSize << " at "
1030 // << pIt1->myP.X() <<", "<< pIt1->myP.Y()<<", "<<pIt1->myP.Z() << endl;
1032 if ( --pIt2 != eData.myPoints.end() && pIt2->mySegSize > allowedSize )
1033 sizeTree.SetSize( eData.myC3d.Value( 0.6*pIt2->myU + 0.4*pIt1->myU ), allowedSize );
1035 if ( ++pIt2 != eData.myPoints.end() && pIt2->mySegSize > allowedSize )
1036 sizeTree.SetSize( eData.myC3d.Value( 0.6*pIt2->myU + 0.4*pIt1->myU ), allowedSize );
1037 pIt1->mySegSize = allowedSize;
1040 if ( & (*pIt1) == & eData.Last() )
1041 avoidPnt = & eData.Last().myP;
1048 cout << "Infinite loop in StdMeshers_AdaptiveAlgo_1D::Compute()" << endl;
1050 sizeDecreased = false;
1054 } // while ( sizeDecreased )
1057 *theProgress = 0.3 + 0.3 * iF / double( faceMap.Extent() );
1058 if ( _computeCanceled )
1061 } // loop on faceMap
1066 SMESH_HypoFilter quadHyp( SMESH_HypoFilter::HasName( "QuadraticMesh" ));
1067 _quadraticMesh = theMesh.GetHypothesis( edges[0].Edge(), quadHyp, /*andAncestors=*/true );
1068 helper.SetIsQuadratic( _quadraticMesh );
1070 for ( int iE = 0; iE < edges.size(); ++iE )
1072 EdgeData& eData = edges[ iE ];
1074 // estimate roughly min segement size on the EDGE
1075 double edgeMinSize = myHyp->GetMaxSize();
1076 EdgeData::TPntIter pIt1 = eData.myPoints.begin();
1077 for ( ; pIt1 != eData.myPoints.end(); ++pIt1 )
1078 edgeMinSize = Min( edgeMinSize, sizeTree.GetSize( pIt1->myP ));
1080 const double f = eData.myC3d.FirstParameter(), l = eData.myC3d.LastParameter();
1081 const double parLen = l - f;
1082 const int nbDivSeg = 5;
1083 int nbDiv = int ( eData.myLength / edgeMinSize * nbDivSeg );
1085 // compute nb of segments
1086 vector< double > nbSegs;
1087 bool toRecompute = true;
1088 double maxSegSize = 0;
1089 //cout << "E " << theMesh.GetMeshDS()->ShapeToIndex( eData.Edge() ) << endl;
1090 while ( toRecompute ) // recompute if segment size at some point is less than edgeMinSize/nbDivSeg
1092 nbSegs.resize( nbDiv + 1 );
1094 toRecompute = false;
1096 gp_Pnt p1 = eData.First().myP, p2, pDiv = p1;
1097 for ( size_t i = 1, segCount = 1; i < nbSegs.size(); ++i )
1099 p2 = eData.myC3d.Value( f + parLen * i / nbDiv );
1100 double locSize = Min( sizeTree.GetSize( p2 ), myHyp->GetMaxSize() );
1101 double nb = p1.Distance( p2 ) / locSize;
1102 // if ( nbSegs.size() < 30 )
1103 // cout << "locSize " << locSize << " nb " << nb << endl;
1107 edgeMinSize = locSize;
1108 nbDiv = int ( eData.myLength / edgeMinSize * nbDivSeg );
1111 nbSegs[i] = nbSegs[i-1] + nb;
1113 if ( nbSegs[i] >= segCount )
1115 maxSegSize = Max( maxSegSize, pDiv.Distance( p2 ));
1122 // compute parameters of nodes
1123 int nbSegFinal = int(floor(nbSegs.back()+0.5));
1124 double fact = nbSegFinal / nbSegs.back();
1125 if ( maxSegSize / fact > myHyp->GetMaxSize() )
1126 fact = ++nbSegFinal / nbSegs.back();
1127 //cout << "nbSegs.back() " << nbSegs.back() << " nbSegFinal " << nbSegFinal << endl;
1129 for ( int i = 0, segCount = 1; segCount < nbSegFinal; ++segCount )
1131 while ( nbSegs[i] * fact < segCount )
1134 params.push_back( f + parLen * i / nbDiv );
1138 // get nodes on VERTEXes
1139 TopoDS_Vertex vf = helper.IthVertex( 0, eData.Edge(), false );
1140 TopoDS_Vertex vl = helper.IthVertex( 1, eData.Edge(), false );
1141 theMesh.GetSubMesh( vf )->ComputeStateEngine( SMESH_subMesh::COMPUTE );
1142 theMesh.GetSubMesh( vl )->ComputeStateEngine( SMESH_subMesh::COMPUTE );
1143 const SMDS_MeshNode * nf = VertexNode( vf, theMesh.GetMeshDS() );
1144 const SMDS_MeshNode * nl = VertexNode( vl, theMesh.GetMeshDS() );
1146 return error("No node on vertex");
1149 helper.SetSubShape( eData.Edge() );
1150 helper.SetElementsOnShape( true );
1152 const SMDS_MeshNode *n1 = nf, *n2;
1153 list< double >::const_iterator u = params.begin();
1154 for ( ; u != params.end(); ++u, n1 = n2 )
1156 gp_Pnt p2 = eData.myC3d.Value( *u );
1157 n2 = helper.AddNode( p2.X(), p2.Y(), p2.Z(), ID, *u );
1158 helper.AddEdge( n1, n2, ID, /*force3d=*/false );
1160 helper.AddEdge( n1, nl, ID, /*force3d=*/false );
1162 *theProgress = 0.6 + 0.4 * iE / double( edges.size() );
1163 if ( _computeCanceled )
1171 //================================================================================
1173 * \brief Creates segments on all given EDGEs
1175 //================================================================================
1177 bool StdMeshers_AdaptiveAlgo_1D::Evaluate(SMESH_Mesh & theMesh,
1178 const TopoDS_Shape & theShape,
1179 MapShapeNbElems& theResMap)
1181 // initialize fields of inherited StdMeshers_Regular_1D
1182 StdMeshers_Regular_1D::_hypType = DEFLECTION;
1183 StdMeshers_Regular_1D::_value[ DEFLECTION_IND ] = myHyp->GetDeflection();
1185 TopExp_Explorer edExp( theShape, TopAbs_EDGE );
1187 for ( ; edExp.More(); edExp.Next() )
1189 const TopoDS_Edge & edge = TopoDS::Edge( edExp.Current() );
1190 StdMeshers_Regular_1D::Evaluate( theMesh, theShape, theResMap );