1 // Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
2 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License.
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 // See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org
20 // File : SMESH_Pattern.hxx
21 // Created : Mon Aug 2 10:30:00 2004
22 // Author : Edward AGAPOV (eap)
24 #include "SMESH_Pattern.hxx"
26 #include <BRepTools.hxx>
27 #include <BRepTools_WireExplorer.hxx>
28 #include <BRep_Tool.hxx>
29 #include <Bnd_Box.hxx>
30 #include <Bnd_Box2d.hxx>
32 #include <Extrema_GenExtPS.hxx>
33 #include <Extrema_POnSurf.hxx>
34 #include <Geom2d_Curve.hxx>
35 #include <GeomAdaptor_Surface.hxx>
36 #include <Geom_Curve.hxx>
37 #include <Geom_Surface.hxx>
38 #include <IntAna2d_AnaIntersection.hxx>
39 #include <TopAbs_ShapeEnum.hxx>
41 #include <TopLoc_Location.hxx>
43 #include <TopoDS_Edge.hxx>
44 #include <TopoDS_Face.hxx>
45 #include <TopoDS_Iterator.hxx>
46 #include <TopoDS_Shell.hxx>
47 #include <TopoDS_Vertex.hxx>
48 #include <TopoDS_Wire.hxx>
50 #include <gp_Lin2d.hxx>
51 #include <gp_Pnt2d.hxx>
52 #include <gp_Trsf.hxx>
56 #include "SMDS_EdgePosition.hxx"
57 #include "SMDS_FacePosition.hxx"
58 #include "SMDS_MeshElement.hxx"
59 #include "SMDS_MeshFace.hxx"
60 #include "SMDS_MeshNode.hxx"
61 #include "SMESHDS_Group.hxx"
62 #include "SMESHDS_Mesh.hxx"
63 #include "SMESHDS_SubMesh.hxx"
64 #include "SMESH_Block.hxx"
65 #include "SMESH_Mesh.hxx"
66 #include "SMESH_MeshEditor.hxx"
67 #include "SMESH_subMesh.hxx"
69 #include "utilities.h"
73 typedef map< const SMDS_MeshElement*, int > TNodePointIDMap;
75 //=======================================================================
76 //function : SMESH_Pattern
78 //=======================================================================
80 SMESH_Pattern::SMESH_Pattern ()
83 //=======================================================================
86 //=======================================================================
88 static inline int getInt( const char * theSring )
90 if ( *theSring < '0' || *theSring > '9' )
94 int val = strtol( theSring, &ptr, 10 );
95 if ( ptr == theSring ||
96 // there must not be neither '.' nor ',' nor 'E' ...
97 (*ptr != ' ' && *ptr != '\n' && *ptr != '\0'))
103 //=======================================================================
104 //function : getDouble
106 //=======================================================================
108 static inline double getDouble( const char * theSring )
111 return strtod( theSring, &ptr );
114 //=======================================================================
115 //function : readLine
116 //purpose : Put token starting positions in theFields until '\n' or '\0'
117 // Return the number of the found tokens
118 //=======================================================================
120 static int readLine (list <const char*> & theFields,
121 const char* & theLineBeg,
122 const bool theClearFields )
124 if ( theClearFields )
129 /* switch ( symbol ) { */
130 /* case white-space: */
131 /* look for a non-space symbol; */
132 /* case string-end: */
135 /* case comment beginning: */
136 /* skip all till a line-end; */
138 /* put its position in theFields, skip till a white-space;*/
144 bool stopReading = false;
147 bool isNumber = false;
148 switch ( *theLineBeg )
150 case ' ': // white space
155 case '\n': // a line ends
156 stopReading = ( nbRead > 0 );
161 while ( *theLineBeg != '\n' && *theLineBeg != '\0' );
165 case '\0': // file ends
168 case '-': // real number
173 isNumber = isNumber || ( *theLineBeg >= '0' && *theLineBeg <= '9' );
175 theFields.push_back( theLineBeg );
178 while (*theLineBeg != ' ' &&
179 *theLineBeg != '\n' &&
180 *theLineBeg != '\0');
184 return 0; // incorrect file format
190 } while ( !stopReading );
195 //=======================================================================
197 //purpose : Load a pattern from <theFile>
198 //=======================================================================
200 bool SMESH_Pattern::Load (const char* theFileContents)
202 MESSAGE("Load( file ) ");
206 // ! This is a comment
207 // NB_POINTS ! 1 integer - the number of points in the pattern.
208 // X1 Y1 [Z1] ! 2 or 3 reals - nodes coordinates within 2D or 3D domain:
209 // X2 Y2 [Z2] ! the pattern dimention is defined by the number of coordinates
211 // [ ID1 ID2 ... IDn ] ! Indices of key-points for a 2D pattern (only).
212 // ! elements description goes after all
213 // ID1 ID2 ... IDn ! 2-4 or 4-8 integers - nodal connectivity of a 2D or 3D element.
218 const char* lineBeg = theFileContents;
219 list <const char*> fields;
220 const bool clearFields = true;
222 // NB_POINTS ! 1 integer - the number of points in the pattern.
224 if ( readLine( fields, lineBeg, clearFields ) != 1 ) {
225 MESSAGE("Error reading NB_POINTS");
226 return setErrorCode( ERR_READ_NB_POINTS );
228 int nbPoints = getInt( fields.front() );
230 // X1 Y1 [Z1] ! 2 or 3 reals - nodes coordinates within 2D or 3D domain:
232 // read the first point coordinates to define pattern dimention
233 int dim = readLine( fields, lineBeg, clearFields );
239 MESSAGE("Error reading points: wrong nb of coordinates");
240 return setErrorCode( ERR_READ_POINT_COORDS );
242 if ( nbPoints <= dim ) {
243 MESSAGE(" Too few points ");
244 return setErrorCode( ERR_READ_TOO_FEW_POINTS );
247 // read the rest points
249 for ( iPoint = 1; iPoint < nbPoints; iPoint++ )
250 if ( readLine( fields, lineBeg, !clearFields ) != dim ) {
251 MESSAGE("Error reading points : wrong nb of coordinates ");
252 return setErrorCode( ERR_READ_POINT_COORDS );
254 // store point coordinates
255 myPoints.resize( nbPoints );
256 list <const char*>::iterator fIt = fields.begin();
257 for ( iPoint = 0; iPoint < nbPoints; iPoint++ )
259 TPoint & p = myPoints[ iPoint ];
260 for ( int iCoord = 1; iCoord <= dim; iCoord++, fIt++ )
262 double coord = getDouble( *fIt );
263 if ( !myIs2D && ( coord < 0.0 || coord > 1.0 )) {
264 MESSAGE("Error reading 3D points, value should be in [0,1]: " << coord);
266 return setErrorCode( ERR_READ_3D_COORD );
268 p.myInitXYZ.SetCoord( iCoord, coord );
270 p.myInitUV.SetCoord( iCoord, coord );
274 // [ ID1 ID2 ... IDn ] ! Indices of key-points for a 2D pattern (only).
277 if ( readLine( fields, lineBeg, clearFields ) == 0 ) {
278 MESSAGE("Error: missing key-points");
280 return setErrorCode( ERR_READ_NO_KEYPOINT );
283 for ( fIt = fields.begin(); fIt != fields.end(); fIt++ )
285 int pointIndex = getInt( *fIt );
286 if ( pointIndex >= nbPoints || pointIndex < 0 ) {
287 MESSAGE("Error: invalid point index " << pointIndex );
289 return setErrorCode( ERR_READ_BAD_INDEX );
291 if ( idSet.insert( pointIndex ).second ) // unique?
292 myKeyPointIDs.push_back( pointIndex );
296 // ID1 ID2 ... IDn ! 2-4 or 4-8 integers - nodal connectivity of a 2D or 3D element.
298 while ( readLine( fields, lineBeg, clearFields ))
300 myElemPointIDs.push_back( list< int >() );
301 list< int >& elemPoints = myElemPointIDs.back();
302 for ( fIt = fields.begin(); fIt != fields.end(); fIt++ )
304 int pointIndex = getInt( *fIt );
305 if ( pointIndex >= nbPoints || pointIndex < 0 ) {
306 MESSAGE("Error: invalid point index " << pointIndex );
308 return setErrorCode( ERR_READ_BAD_INDEX );
310 elemPoints.push_back( pointIndex );
312 // check the nb of nodes in element
314 switch ( elemPoints.size() ) {
315 case 3: if ( !myIs2D ) Ok = false; break;
319 case 8: if ( myIs2D ) Ok = false; break;
323 MESSAGE("Error: wrong nb of nodes in element " << elemPoints.size() );
325 return setErrorCode( ERR_READ_ELEM_POINTS );
328 if ( myElemPointIDs.empty() ) {
329 MESSAGE("Error: no elements");
331 return setErrorCode( ERR_READ_NO_ELEMS );
334 findBoundaryPoints(); // sort key-points
336 return setErrorCode( ERR_OK );
339 //=======================================================================
341 //purpose : Save the loaded pattern into the file <theFileName>
342 //=======================================================================
344 bool SMESH_Pattern::Save (ostream& theFile)
346 MESSAGE(" ::Save(file) " );
348 MESSAGE(" Pattern not loaded ");
349 return setErrorCode( ERR_SAVE_NOT_LOADED );
352 theFile << "!!! SALOME Mesh Pattern file" << endl;
353 theFile << "!!!" << endl;
354 theFile << "!!! Nb of points:" << endl;
355 theFile << myPoints.size() << endl;
359 // theFile.width( 8 );
360 // theFile.setf(ios::fixed);// use 123.45 floating notation
361 // theFile.setf(ios::right);
362 // theFile.flags( theFile.flags() & ~ios::showpoint); // do not show trailing zeros
363 // theFile.setf(ios::showpoint); // do not show trailing zeros
364 vector< TPoint >::const_iterator pVecIt = myPoints.begin();
365 for ( int i = 0; pVecIt != myPoints.end(); pVecIt++, i++ ) {
366 const gp_XYZ & xyz = (*pVecIt).myInitXYZ;
367 theFile << " " << setw( width ) << xyz.X() << " " << setw( width ) << xyz.Y();
368 if ( !myIs2D ) theFile << " " << setw( width ) << xyz.Z();
369 theFile << " !- " << i << endl; // point id to ease reading by a human being
373 theFile << "!!! Indices of " << myKeyPointIDs.size() << " key-points:" << endl;
374 list< int >::const_iterator kpIt = myKeyPointIDs.begin();
375 for ( ; kpIt != myKeyPointIDs.end(); kpIt++ )
376 theFile << " " << *kpIt;
377 if ( !myKeyPointIDs.empty() )
381 theFile << "!!! Indices of points of " << myElemPointIDs.size() << " elements:" << endl;
382 list<list< int > >::const_iterator epIt = myElemPointIDs.begin();
383 for ( ; epIt != myElemPointIDs.end(); epIt++ )
385 const list< int > & elemPoints = *epIt;
386 list< int >::const_iterator iIt = elemPoints.begin();
387 for ( ; iIt != elemPoints.end(); iIt++ )
388 theFile << " " << *iIt;
394 return setErrorCode( ERR_OK );
397 //=======================================================================
398 //function : sortBySize
399 //purpose : sort theListOfList by size
400 //=======================================================================
402 template<typename T> struct TSizeCmp {
403 bool operator ()( const list < T > & l1, const list < T > & l2 )
404 const { return l1.size() < l2.size(); }
407 template<typename T> void sortBySize( list< list < T > > & theListOfList )
409 if ( theListOfList.size() > 2 ) {
410 TSizeCmp< T > SizeCmp;
411 theListOfList.sort( SizeCmp );
415 //=======================================================================
416 //function : getOrderedEdges
417 //purpose : return nb wires and a list of oredered edges
418 //=======================================================================
420 static int getOrderedEdges (const TopoDS_Face& theFace,
421 const TopoDS_Vertex& theFirstVertex,
422 list< TopoDS_Edge >& theEdges,
423 list< int > & theNbVertexInWires)
425 // put wires in a list, so that an outer wire comes first
426 list<TopoDS_Wire> aWireList;
427 TopoDS_Wire anOuterWire = BRepTools::OuterWire( theFace );
428 aWireList.push_back( anOuterWire );
429 for ( TopoDS_Iterator wIt (theFace); wIt.More(); wIt.Next() )
430 if ( !anOuterWire.IsSame( wIt.Value() ))
431 aWireList.push_back( TopoDS::Wire( wIt.Value() ));
433 // loop on edges of wires
434 theNbVertexInWires.clear();
435 list<TopoDS_Wire>::iterator wlIt = aWireList.begin();
436 for ( ; wlIt != aWireList.end(); wlIt++ )
439 BRepTools_WireExplorer wExp( *wlIt, theFace );
440 for ( iE = 0; wExp.More(); wExp.Next(), iE++ )
442 TopoDS_Edge edge = wExp.Current();
443 edge = TopoDS::Edge( edge.Oriented( wExp.Orientation() ));
444 theEdges.push_back( edge );
446 theNbVertexInWires.push_back( iE );
448 if ( wlIt == aWireList.begin() && theEdges.size() > 1 ) { // the outer wire
449 // orient closed edges
450 list< TopoDS_Edge >::iterator eIt, eIt2;
451 for ( eIt = theEdges.begin(); eIt != theEdges.end(); eIt++ )
453 TopoDS_Edge& edge = *eIt;
454 if ( TopExp::FirstVertex( edge ).IsSame( TopExp::LastVertex( edge ) ))
457 bool isNext = ( eIt2 == theEdges.begin() );
458 TopoDS_Edge edge2 = isNext ? *(++eIt2) : *(--eIt2);
460 Handle(Geom2d_Curve) c1 = BRep_Tool::CurveOnSurface( edge, theFace, f1,l1 );
461 Handle(Geom2d_Curve) c2 = BRep_Tool::CurveOnSurface( edge2, theFace, f2,l2 );
462 gp_Pnt2d pf = c1->Value( edge.Orientation() == TopAbs_FORWARD ? f1 : l1 );
463 gp_Pnt2d pl = c1->Value( edge.Orientation() == TopAbs_FORWARD ? l1 : f1 );
464 bool isFirst = ( edge2.Orientation() == TopAbs_FORWARD ? isNext : !isNext );
465 gp_Pnt2d p2 = c2->Value( isFirst ? f2 : l2 );
466 isFirst = ( p2.SquareDistance( pf ) < p2.SquareDistance( pl ));
467 if ( isNext ? isFirst : !isFirst )
471 // rotate theEdges until it begins from theFirstVertex
472 if ( ! theFirstVertex.IsNull() )
473 while ( !theFirstVertex.IsSame( TopExp::FirstVertex( theEdges.front(), true )))
475 theEdges.splice(theEdges.end(), theEdges,
476 theEdges.begin(), ++ theEdges.begin());
477 if ( iE++ > theNbVertexInWires.back() )
478 break; // break infinite loop
483 return aWireList.size();
486 //=======================================================================
489 //=======================================================================
491 static gp_XY project (const SMDS_MeshNode* theNode,
492 Extrema_GenExtPS & theProjectorPS)
494 gp_Pnt P( theNode->X(), theNode->Y(), theNode->Z() );
495 theProjectorPS.Perform( P );
496 if ( !theProjectorPS.IsDone() ) {
497 MESSAGE( "SMESH_Pattern: point projection FAILED");
500 double u, v, minVal = DBL_MAX;
501 for ( int i = theProjectorPS.NbExt(); i > 0; i-- )
502 if ( theProjectorPS.Value( i ) < minVal ) {
503 minVal = theProjectorPS.Value( i );
504 theProjectorPS.Point( i ).Parameter( u, v );
506 return gp_XY( u, v );
509 //=======================================================================
510 //function : isMeshBoundToShape
511 //purpose : return true if all 2d elements are bound to shape
512 //=======================================================================
514 static bool isMeshBoundToShape(SMESH_Mesh* theMesh)
516 // check faces binding
517 SMESHDS_Mesh * aMeshDS = theMesh->GetMeshDS();
518 SMESHDS_SubMesh * aMainSubMesh = aMeshDS->MeshElements( aMeshDS->ShapeToMesh() );
519 if ( aMeshDS->NbFaces() != aMainSubMesh->NbElements() )
522 // check face nodes binding
523 SMDS_FaceIteratorPtr fIt = aMeshDS->facesIterator();
524 while ( fIt->more() )
526 SMDS_ElemIteratorPtr nIt = fIt->next()->nodesIterator();
527 while ( nIt->more() )
529 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nIt->next() );
530 SMDS_PositionPtr pos = node->GetPosition();
531 if ( !pos || !pos->GetShapeId() )
538 //=======================================================================
540 //purpose : Create a pattern from the mesh built on <theFace>.
541 // <theProject>==true makes override nodes positions
542 // on <theFace> computed by mesher
543 //=======================================================================
545 bool SMESH_Pattern::Load (SMESH_Mesh* theMesh,
546 const TopoDS_Face& theFace,
549 MESSAGE(" ::Load(face) " );
553 SMESHDS_Mesh * aMeshDS = theMesh->GetMeshDS();
554 SMESHDS_SubMesh * fSubMesh = aMeshDS->MeshElements( theFace );
556 int nbNodes = ( !fSubMesh ? 0 : fSubMesh->NbNodes() );
557 int nbElems = ( !fSubMesh ? 0 : fSubMesh->NbElements() );
558 if ( nbElems == 0 && aMeshDS->NbFaces() == 0 )
560 MESSAGE( "No elements bound to the face");
561 return setErrorCode( ERR_LOAD_EMPTY_SUBMESH );
564 TopoDS_Face face = TopoDS::Face( theFace.Oriented( TopAbs_FORWARD ));
566 // check that face is not closed
568 list<TopoDS_Edge> eList;
569 getOrderedEdges( face, bidon, eList, myNbKeyPntInBoundary );
570 list<TopoDS_Edge>::iterator elIt = eList.begin();
571 for ( ; elIt != eList.end() ; elIt++ )
572 if ( BRep_Tool::IsClosed( *elIt , face ))
573 return setErrorCode( ERR_LOADF_CLOSED_FACE );
576 Extrema_GenExtPS projector;
577 GeomAdaptor_Surface aSurface( BRep_Tool::Surface( face ));
578 if ( theProject || nbElems == 0 )
579 projector.Initialize( aSurface, 20,20, 1e-5,1e-5 );
582 TNodePointIDMap nodePointIDMap;
584 if ( nbElems == 0 || (theProject &&
585 theMesh->IsMainShape( face ) &&
586 !isMeshBoundToShape( theMesh )))
588 MESSAGE("Project the whole mesh");
589 // ---------------------------------------------------------------
590 // The case where the whole mesh is projected to theFace
591 // ---------------------------------------------------------------
593 // put nodes of all faces in the nodePointIDMap and fill myElemPointIDs
594 SMDS_FaceIteratorPtr fIt = aMeshDS->facesIterator();
595 while ( fIt->more() )
597 myElemPointIDs.push_back( list< int >() );
598 list< int >& elemPoints = myElemPointIDs.back();
599 SMDS_ElemIteratorPtr nIt = fIt->next()->nodesIterator();
600 while ( nIt->more() )
602 const SMDS_MeshElement* node = nIt->next();
603 TNodePointIDMap::iterator nIdIt = nodePointIDMap.find( node );
604 if ( nIdIt == nodePointIDMap.end() )
606 elemPoints.push_back( iPoint );
607 nodePointIDMap.insert( make_pair( node, iPoint++ ));
610 elemPoints.push_back( (*nIdIt).second );
613 myPoints.resize( iPoint );
615 // project all nodes of 2d elements to theFace
616 TNodePointIDMap::iterator nIdIt = nodePointIDMap.begin();
617 for ( ; nIdIt != nodePointIDMap.end(); nIdIt++ )
619 const SMDS_MeshNode* node =
620 static_cast<const SMDS_MeshNode*>( (*nIdIt).first );
621 TPoint * p = & myPoints[ (*nIdIt).second ];
622 p->myInitUV = project( node, projector );
623 p->myInitXYZ.SetCoord( p->myInitUV.X(), p->myInitUV.Y(), 0 );
625 // find key-points: the points most close to UV of vertices
626 TopExp_Explorer vExp( face, TopAbs_VERTEX );
627 set<int> foundIndices;
628 for ( ; vExp.More(); vExp.Next() ) {
629 const TopoDS_Vertex v = TopoDS::Vertex( vExp.Current() );
630 gp_Pnt2d uv = BRep_Tool::Parameters( v, face );
631 double minDist = DBL_MAX;
633 vector< TPoint >::const_iterator pVecIt = myPoints.begin();
634 for ( iPoint = 0; pVecIt != myPoints.end(); pVecIt++, iPoint++ ) {
635 double dist = uv.SquareDistance( (*pVecIt).myInitUV );
636 if ( dist < minDist ) {
641 if ( foundIndices.insert( index ).second ) // unique?
642 myKeyPointIDs.push_back( index );
644 myIsBoundaryPointsFound = false;
649 // ---------------------------------------------------------------------
650 // The case where a pattern is being made from the mesh built by mesher
651 // ---------------------------------------------------------------------
653 // Load shapes in the consequent order and count nb of points
656 for ( elIt = eList.begin(); elIt != eList.end(); elIt++ ) {
657 myShapeIDMap.Add( TopExp::FirstVertex( *elIt, true ));
658 SMESHDS_SubMesh * eSubMesh = aMeshDS->MeshElements( *elIt );
660 nbNodes += eSubMesh->NbNodes() + 1;
663 for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
664 myShapeIDMap.Add( *elIt );
666 myShapeIDMap.Add( face );
668 myPoints.resize( nbNodes );
670 // Load U of points on edges
672 for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
674 TopoDS_Edge & edge = *elIt;
675 list< TPoint* > & ePoints = getShapePoints( edge );
677 Handle(Geom2d_Curve) C2d;
679 C2d = BRep_Tool::CurveOnSurface( edge, face, f, l );
680 bool isForward = ( edge.Orientation() == TopAbs_FORWARD );
682 // the forward key-point
683 TopoDS_Shape v = TopExp::FirstVertex( edge, true );
684 list< TPoint* > & vPoint = getShapePoints( v );
685 if ( vPoint.empty() )
687 SMESHDS_SubMesh * vSubMesh = aMeshDS->MeshElements( v );
688 if ( vSubMesh && vSubMesh->NbNodes() ) {
689 myKeyPointIDs.push_back( iPoint );
690 SMDS_NodeIteratorPtr nIt = vSubMesh->GetNodes();
691 const SMDS_MeshNode* node = nIt->next();
692 nodePointIDMap.insert( make_pair( node, iPoint ));
694 TPoint* keyPoint = &myPoints[ iPoint++ ];
695 vPoint.push_back( keyPoint );
697 keyPoint->myInitUV = project( node, projector );
699 keyPoint->myInitUV = C2d->Value( isForward ? f : l ).XY();
700 keyPoint->myInitXYZ.SetCoord (keyPoint->myInitUV.X(), keyPoint->myInitUV.Y(), 0);
703 if ( !vPoint.empty() )
704 ePoints.push_back( vPoint.front() );
707 SMESHDS_SubMesh * eSubMesh = aMeshDS->MeshElements( edge );
708 if ( eSubMesh && eSubMesh->NbNodes() )
710 // loop on nodes of an edge: sort them by param on edge
711 typedef map < double, const SMDS_MeshNode* > TParamNodeMap;
712 TParamNodeMap paramNodeMap;
713 SMDS_NodeIteratorPtr nIt = eSubMesh->GetNodes();
714 while ( nIt->more() )
716 const SMDS_MeshNode* node =
717 static_cast<const SMDS_MeshNode*>( nIt->next() );
718 const SMDS_EdgePosition* epos =
719 static_cast<const SMDS_EdgePosition*>(node->GetPosition().get());
720 double u = epos->GetUParameter();
721 paramNodeMap.insert( TParamNodeMap::value_type( u, node ));
723 // put U in [0,1] so that the first key-point has U==0
725 TParamNodeMap::iterator unIt = paramNodeMap.begin();
726 TParamNodeMap::reverse_iterator unRIt = paramNodeMap.rbegin();
727 while ( unIt != paramNodeMap.end() )
729 TPoint* p = & myPoints[ iPoint ];
730 ePoints.push_back( p );
731 const SMDS_MeshNode* node = isForward ? (*unIt).second : (*unRIt).second;
732 nodePointIDMap.insert ( make_pair( node, iPoint ));
735 p->myInitUV = project( node, projector );
737 double u = isForward ? (*unIt).first : (*unRIt).first;
738 p->myInitU = isForward ? (( u - f ) / du ) : ( 1.0 - ( u - f ) / du );
739 p->myInitUV = C2d->Value( u ).XY();
741 p->myInitXYZ.SetCoord( p->myInitUV.X(), p->myInitUV.Y(), 0 );
746 // the reverse key-point
747 v = TopExp::LastVertex( edge, true ).Reversed();
748 list< TPoint* > & vPoint2 = getShapePoints( v );
749 if ( vPoint2.empty() )
751 SMESHDS_SubMesh * vSubMesh = aMeshDS->MeshElements( v );
752 if ( vSubMesh && vSubMesh->NbNodes() ) {
753 myKeyPointIDs.push_back( iPoint );
754 SMDS_NodeIteratorPtr nIt = vSubMesh->GetNodes();
755 const SMDS_MeshNode* node = nIt->next();
756 nodePointIDMap.insert( make_pair( node, iPoint ));
758 TPoint* keyPoint = &myPoints[ iPoint++ ];
759 vPoint2.push_back( keyPoint );
761 keyPoint->myInitUV = project( node, projector );
763 keyPoint->myInitUV = C2d->Value( isForward ? l : f ).XY();
764 keyPoint->myInitXYZ.SetCoord( keyPoint->myInitUV.X(), keyPoint->myInitUV.Y(), 0 );
767 if ( !vPoint2.empty() )
768 ePoints.push_back( vPoint2.front() );
770 // compute U of edge-points
773 double totalDist = 0;
774 list< TPoint* >::iterator pIt = ePoints.begin();
775 TPoint* prevP = *pIt;
776 prevP->myInitU = totalDist;
777 for ( pIt++; pIt != ePoints.end(); pIt++ ) {
779 totalDist += ( p->myInitUV - prevP->myInitUV ).Modulus();
780 p->myInitU = totalDist;
783 if ( totalDist > DBL_MIN)
784 for ( pIt = ePoints.begin(); pIt != ePoints.end(); pIt++ ) {
786 p->myInitU /= totalDist;
789 } // loop on edges of a wire
791 // Load in-face points and elements
793 if ( fSubMesh && fSubMesh->NbElements() )
795 list< TPoint* > & fPoints = getShapePoints( face );
796 SMDS_NodeIteratorPtr nIt = fSubMesh->GetNodes();
797 while ( nIt->more() )
799 const SMDS_MeshNode* node =
800 static_cast<const SMDS_MeshNode*>( nIt->next() );
801 nodePointIDMap.insert( make_pair( node, iPoint ));
802 TPoint* p = &myPoints[ iPoint++ ];
803 fPoints.push_back( p );
805 p->myInitUV = project( node, projector );
807 const SMDS_FacePosition* pos =
808 static_cast<const SMDS_FacePosition*>(node->GetPosition().get());
809 p->myInitUV.SetCoord( pos->GetUParameter(), pos->GetVParameter() );
811 p->myInitXYZ.SetCoord( p->myInitUV.X(), p->myInitUV.Y(), 0 );
814 SMDS_ElemIteratorPtr elemIt = fSubMesh->GetElements();
815 while ( elemIt->more() ) {
816 SMDS_ElemIteratorPtr nIt = elemIt->next()->nodesIterator();
817 myElemPointIDs.push_back( list< int >() );
818 list< int >& elemPoints = myElemPointIDs.back();
819 while ( nIt->more() )
820 elemPoints.push_back( nodePointIDMap[ nIt->next() ]);
824 myIsBoundaryPointsFound = true;
827 // Assure that U range is proportional to V range
830 vector< TPoint >::iterator pVecIt = myPoints.begin();
831 for ( ; pVecIt != myPoints.end(); pVecIt++ )
832 bndBox.Add( gp_Pnt2d( (*pVecIt).myInitUV ));
833 double minU, minV, maxU, maxV;
834 bndBox.Get( minU, minV, maxU, maxV );
835 double dU = maxU - minU, dV = maxV - minV;
836 if ( dU <= DBL_MIN || dV <= DBL_MIN ) {
838 return setErrorCode( ERR_LOADF_NARROW_FACE );
840 double ratio = dU / dV, maxratio = 3, scale;
842 if ( ratio > maxratio ) {
843 scale = ratio / maxratio;
846 else if ( ratio < 1./maxratio ) {
847 scale = maxratio / ratio;
852 for ( pVecIt = myPoints.begin(); pVecIt != myPoints.end(); pVecIt++ ) {
853 TPoint & p = *pVecIt;
854 p.myInitUV.SetCoord( iCoord, p.myInitUV.Coord( iCoord ) * scale );
855 p.myInitXYZ.SetCoord( p.myInitUV.X(), p.myInitUV.Y(), 0 );
858 if ( myElemPointIDs.empty() ) {
859 MESSAGE( "No elements bound to the face");
860 return setErrorCode( ERR_LOAD_EMPTY_SUBMESH );
863 return setErrorCode( ERR_OK );
866 //=======================================================================
867 //function : computeUVOnEdge
868 //purpose : compute coordinates of points on theEdge
869 //=======================================================================
871 void SMESH_Pattern::computeUVOnEdge (const TopoDS_Edge& theEdge,
872 const list< TPoint* > & ePoints )
874 bool isForward = ( theEdge.Orientation() == TopAbs_FORWARD );
876 Handle(Geom2d_Curve) C2d =
877 BRep_Tool::CurveOnSurface( theEdge, TopoDS::Face( myShape ), f, l );
879 ePoints.back()->myInitU = 1.0;
880 list< TPoint* >::const_iterator pIt = ePoints.begin();
881 for ( pIt++; pIt != ePoints.end(); pIt++ )
883 TPoint* point = *pIt;
885 double du = ( isForward ? point->myInitU : 1 - point->myInitU );
886 point->myU = ( f * ( 1 - du ) + l * du );
888 point->myUV = C2d->Value( point->myU ).XY();
892 //=======================================================================
893 //function : intersectIsolines
895 //=======================================================================
897 static bool intersectIsolines(const gp_XY& uv11, const gp_XY& uv12, const double r1,
898 const gp_XY& uv21, const gp_XY& uv22, const double r2,
902 gp_XY loc1 = uv11 * ( 1 - r1 ) + uv12 * r1;
903 gp_XY loc2 = uv21 * ( 1 - r2 ) + uv22 * r2;
904 resUV = 0.5 * ( loc1 + loc2 );
905 isDeformed = ( loc1 - loc2 ).SquareModulus() > 1e-8;
906 // double len1 = ( uv11 - uv12 ).Modulus();
907 // double len2 = ( uv21 - uv22 ).Modulus();
908 // resUV = loc1 * len2 / ( len1 + len2 ) + loc2 * len1 / ( len1 + len2 );
912 // gp_Lin2d line1( uv11, uv12 - uv11 );
913 // gp_Lin2d line2( uv21, uv22 - uv21 );
914 // double angle = Abs( line1.Angle( line2 ) );
916 // IntAna2d_AnaIntersection inter;
917 // inter.Perform( line1.Normal( loc1 ), line2.Normal( loc2 ) );
918 // if ( inter.IsDone() && inter.NbPoints() == 1 )
920 // gp_Pnt2d interUV = inter.Point(1).Value();
921 // resUV += interUV.XY();
922 // inter.Perform( line1, line2 );
923 // interUV = inter.Point(1).Value();
924 // resUV += interUV.XY();
931 //=======================================================================
932 //function : compUVByIsoIntersection
934 //=======================================================================
936 bool SMESH_Pattern::compUVByIsoIntersection (const list< list< TPoint* > >& theBndPoints,
937 const gp_XY& theInitUV,
939 bool & theIsDeformed )
941 // compute UV by intersection of 2 iso lines
942 //gp_Lin2d isoLine[2];
943 gp_XY uv1[2], uv2[2];
945 const double zero = DBL_MIN;
946 for ( int iIso = 0; iIso < 2; iIso++ )
948 // to build an iso line:
949 // find 2 pairs of consequent edge-points such that the range of their
950 // initial parameters encloses the in-face point initial parameter
951 gp_XY UV[2], initUV[2];
952 int nbUV = 0, iCoord = iIso + 1;
953 double initParam = theInitUV.Coord( iCoord );
955 list< list< TPoint* > >::const_iterator bndIt = theBndPoints.begin();
956 for ( ; bndIt != theBndPoints.end(); bndIt++ )
958 const list< TPoint* > & bndPoints = * bndIt;
959 TPoint* prevP = bndPoints.back(); // this is the first point
960 list< TPoint* >::const_iterator pIt = bndPoints.begin();
961 bool coincPrev = false;
962 // loop on the edge-points
963 for ( ; pIt != bndPoints.end(); pIt++ )
965 double paramDiff = initParam - (*pIt)->myInitUV.Coord( iCoord );
966 double prevParamDiff = initParam - prevP->myInitUV.Coord( iCoord );
967 double sumOfDiff = Abs(prevParamDiff) + Abs(paramDiff);
968 if (!coincPrev && // ignore if initParam coincides with prev point param
969 sumOfDiff > zero && // ignore if both points coincide with initParam
970 prevParamDiff * paramDiff <= zero )
972 // find UV in parametric space of theFace
973 double r = Abs(prevParamDiff) / sumOfDiff;
974 gp_XY uvInit = (*pIt)->myInitUV * r + prevP->myInitUV * ( 1 - r );
977 // throw away uv most distant from <theInitUV>
978 gp_XY vec0 = initUV[0] - theInitUV;
979 gp_XY vec1 = initUV[1] - theInitUV;
980 gp_XY vec = uvInit - theInitUV;
981 bool isBetween = ( vec0 * vec1 < 0 ); // is theInitUV between initUV[0] and initUV[1]
982 double dist0 = vec0.SquareModulus();
983 double dist1 = vec1.SquareModulus();
984 double dist = vec .SquareModulus();
985 if ( !isBetween || dist < dist0 || dist < dist1 ) {
986 i = ( dist0 < dist1 ? 1 : 0 );
987 if ( isBetween && vec.Dot( i ? vec1 : vec0 ) < 0 )
988 i = 3; // theInitUV must remain between
992 initUV[ i ] = uvInit;
993 UV[ i ] = (*pIt)->myUV * r + prevP->myUV * ( 1 - r );
995 coincPrev = ( Abs(paramDiff) <= zero );
1002 if ( nbUV < 2 || (UV[0]-UV[1]).SquareModulus() <= DBL_MIN*DBL_MIN ) {
1003 MESSAGE(" consequent edge-points not found, nb UV found: " << nbUV <<
1004 ", for point: " << theInitUV.X() <<" " << theInitUV.Y() );
1005 return setErrorCode( ERR_APPLF_BAD_TOPOLOGY );
1007 // an iso line should be normal to UV[0] - UV[1] direction
1008 // and be located at the same relative distance as from initial ends
1009 //gp_Lin2d iso( UV[0], UV[0] - UV[1] );
1011 (initUV[0]-theInitUV).Modulus() / (initUV[0]-initUV[1]).Modulus();
1012 //gp_Pnt2d isoLoc = UV[0] * ( 1 - r ) + UV[1] * r;
1013 //isoLine[ iIso ] = iso.Normal( isoLoc );
1014 uv1[ iIso ] = UV[0];
1015 uv2[ iIso ] = UV[1];
1018 if ( !intersectIsolines( uv1[0], uv2[0], ratio[0],
1019 uv1[1], uv2[1], ratio[1], theUV, theIsDeformed )) {
1020 MESSAGE(" Cant intersect isolines for a point "<<theInitUV.X()<<", "<<theInitUV.Y());
1021 return setErrorCode( ERR_APPLF_BAD_TOPOLOGY );
1028 // ==========================================================
1029 // structure representing a node of a grid of iso-poly-lines
1030 // ==========================================================
1037 gp_Dir2d myDir[2]; // boundary tangent dir for boundary nodes, iso dir for internal ones
1038 TIsoNode* myNext[4]; // order: (iDir=0,isForward=0), (1,0), (0,1), (1,1)
1039 TIsoNode* myBndNodes[4]; // order: (iDir=0,i=0), (1,0), (0,1), (1,1)
1040 TIsoNode(double initU, double initV):
1041 myInitUV( initU, initV ), myUV( 1e100, 1e100 ), myIsMovable(true)
1042 { myNext[0] = myNext[1] = myNext[2] = myNext[3] = 0; }
1043 bool IsUVComputed() const
1044 { return myUV.X() != 1e100; }
1045 bool IsMovable() const
1046 { return myIsMovable && myNext[0] && myNext[1] && myNext[2] && myNext[3]; }
1047 void SetNotMovable()
1048 { myIsMovable = false; }
1049 void SetBoundaryNode(TIsoNode* node, int iDir, int i)
1050 { myBndNodes[ iDir + i * 2 ] = node; }
1051 TIsoNode* GetBoundaryNode(int iDir, int i)
1052 { return myBndNodes[ iDir + i * 2 ]; }
1053 void SetNext(TIsoNode* node, int iDir, int isForward)
1054 { myNext[ iDir + isForward * 2 ] = node; }
1055 TIsoNode* GetNext(int iDir, int isForward)
1056 { return myNext[ iDir + isForward * 2 ]; }
1059 //=======================================================================
1060 //function : getNextNode
1062 //=======================================================================
1064 static inline TIsoNode* getNextNode(const TIsoNode* node, int dir )
1066 TIsoNode* n = node->myNext[ dir ];
1067 if ( n && !n->IsUVComputed()/* && node->IsMovable()*/ ) {
1068 n = 0;//node->myBndNodes[ dir ];
1069 // MESSAGE("getNextNode: use bnd for node "<<
1070 // node->myInitUV.X()<<" "<<node->myInitUV.Y());
1074 //=======================================================================
1075 //function : checkQuads
1076 //purpose : check if newUV destortes quadrangles around node,
1077 // and if ( crit == FIX_OLD ) fix newUV in this case
1078 //=======================================================================
1080 enum { CHECK_NEW_IN, CHECK_NEW_OK, FIX_OLD };
1082 static bool checkQuads (const TIsoNode* node,
1084 const bool reversed,
1085 const int crit = FIX_OLD,
1086 double fixSize = 0.)
1088 gp_XY oldUV = node->myUV, oldUVFixed[4], oldUVImpr[4];
1089 int nbOldFix = 0, nbOldImpr = 0;
1090 double newBadRate = 0, oldBadRate = 0;
1091 bool newIsOk = true, newIsIn = true, oldIsIn = true, oldIsOk = true;
1092 int i, dir1 = 0, dir2 = 3;
1093 for ( ; dir1 < 4; dir1++, dir2++ ) // loop on 4 quadrangles around <node>
1095 if ( dir2 > 3 ) dir2 = 0;
1097 // walking counterclockwise around a quad,
1098 // nodes are in the order: node, n[0], n[1], n[2]
1099 n[0] = getNextNode( node, dir1 );
1100 n[2] = getNextNode( node, dir2 );
1101 if ( !n[0] || !n[2] ) continue;
1102 n[1] = getNextNode( n[0], dir2 );
1103 if ( !n[1] ) n[1] = getNextNode( n[2], dir1 );
1104 bool isTriangle = ( !n[1] );
1106 TIsoNode* tmp = n[0]; n[0] = n[2]; n[2] = tmp;
1108 // if ( fixSize != 0 ) {
1109 // cout<<"NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<" UV: "<<node->myUV.X()<<" "<<node->myUV.Y()<<endl;
1110 // cout<<"\t0: "<<n[0]->myInitUV.X()<<" "<<n[0]->myInitUV.Y()<<" UV: "<<n[0]->myUV.X()<<" "<<n[0]->myUV.Y()<<endl;
1111 // cout<<"\t1: "<<n[1]->myInitUV.X()<<" "<<n[1]->myInitUV.Y()<<" UV: "<<n[1]->myUV.X()<<" "<<n[1]->myUV.Y()<<endl;
1112 // cout<<"\t2: "<<n[2]->myInitUV.X()<<" "<<n[2]->myInitUV.Y()<<" UV: "<<n[2]->myUV.X()<<" "<<n[2]->myUV.Y()<<endl;
1114 // check if a quadrangle is degenerated
1116 ((( n[0]->myUV - n[1]->myUV ).SquareModulus() <= DBL_MIN ) ||
1117 (( n[2]->myUV - n[1]->myUV ).SquareModulus() <= DBL_MIN )))
1120 ( n[0]->myUV - n[2]->myUV ).SquareModulus() <= DBL_MIN )
1123 // find min size of the diagonal node-n[1]
1124 double minDiag = fixSize;
1125 if ( minDiag == 0. ) {
1126 double maxLen2 = ( node->myUV - n[0]->myUV ).SquareModulus();
1127 if ( !isTriangle ) {
1128 maxLen2 = Max( maxLen2, ( n[0]->myUV - n[1]->myUV ).SquareModulus() );
1129 maxLen2 = Max( maxLen2, ( n[1]->myUV - n[2]->myUV ).SquareModulus() );
1131 maxLen2 = Max( maxLen2, ( n[2]->myUV - node->myUV ).SquareModulus() );
1132 minDiag = sqrt( maxLen2 ) * PI / 60.; // ~ maxLen * Sin( 3 deg )
1135 // check if newUV is behind 3 dirs: n[0]-n[1], n[1]-n[2] and n[0]-n[2]
1136 // ( behind means "to the right of")
1138 // 1. newUV is not behind 01 and 12 dirs
1139 // 2. or newUV is not behind 02 dir and n[2] is convex
1140 bool newIn[3] = { true, true, true }, newOk[3] = { true, true, true };
1141 bool wasIn[3] = { true, true, true }, wasOk[3] = { true, true, true };
1142 gp_Vec2d moveVec[3], outVec[3];
1143 for ( i = isTriangle ? 2 : 0; i < 3; i++ )
1145 bool isDiag = ( i == 2 );
1146 if ( isDiag && newOk[0] && newOk[1] && !isTriangle )
1150 sideDir = gp_Vec2d( n[0]->myUV, n[2]->myUV );
1152 sideDir = gp_Vec2d( n[i]->myUV, n[i+1]->myUV );
1154 gp_Vec2d outDir( sideDir.Y(), -sideDir.X() ); // to the right
1156 gp_Vec2d newDir( n[i]->myUV, newUV );
1157 gp_Vec2d oldDir( n[i]->myUV, oldUV );
1159 if ( newIsOk ) newOk[i] = ( outDir * newDir < -minDiag );
1160 if ( newIsIn ) newIn[i] = ( outDir * newDir < 0 );
1161 if ( crit == FIX_OLD ) {
1162 wasIn[i] = ( outDir * oldDir < 0 );
1163 wasOk[i] = ( outDir * oldDir < -minDiag );
1165 newBadRate += outDir * newDir;
1167 oldBadRate += outDir * oldDir;
1170 double oldDist = - outDir * oldDir;//, l2 = outDir * newDir;
1171 // double r = ( l1 - minDiag ) / ( l1 + l2 );
1172 // moveVec[i] = r * gp_Vec2d( node->myUV, newUV );
1173 moveVec[i] = ( oldDist - minDiag ) * outDir;
1178 // check if n[2] is convex
1181 convex = ( outVec[0] * gp_Vec2d( n[1]->myUV, n[2]->myUV ) < 0 );
1183 bool isNewOk = ( newOk[0] && newOk[1] ) || ( newOk[2] && convex );
1184 bool isNewIn = ( newIn[0] && newIn[1] ) || ( newIn[2] && convex );
1185 newIsOk = ( newIsOk && isNewOk );
1186 newIsIn = ( newIsIn && isNewIn );
1188 if ( crit != FIX_OLD ) {
1189 if ( crit == CHECK_NEW_OK && !newIsOk ) break;
1190 if ( crit == CHECK_NEW_IN && !newIsIn ) break;
1194 bool isOldIn = ( wasIn[0] && wasIn[1] ) || ( wasIn[2] && convex );
1195 bool isOldOk = ( wasOk[0] && wasOk[1] ) || ( wasOk[2] && convex );
1196 oldIsIn = ( oldIsIn && isOldIn );
1197 oldIsOk = ( oldIsOk && isOldIn );
1200 if ( !isOldIn ) { // node is outside a quadrangle
1201 // move newUV inside a quadrangle
1202 //MESSAGE("Quad "<< dir1 << " WAS IN " << wasIn[0]<<" "<<wasIn[1]<<" "<<wasIn[2]);
1203 // node and newUV are outside: push newUV inside
1205 if ( convex || isTriangle ) {
1206 uv = 0.5 * ( n[0]->myUV + n[2]->myUV ) - minDiag * outVec[2].XY();
1209 gp_Vec2d out = outVec[0].Normalized() + outVec[1].Normalized();
1210 double outSize = out.Magnitude();
1211 if ( outSize > DBL_MIN )
1214 out.SetCoord( -outVec[1].Y(), outVec[1].X() );
1215 uv = n[1]->myUV - minDiag * out.XY();
1217 oldUVFixed[ nbOldFix++ ] = uv;
1218 //node->myUV = newUV;
1220 else if ( !isOldOk ) {
1221 // try to fix old UV: move node inside as less as possible
1222 //MESSAGE("Quad "<< dir1 << " old is BAD, try to fix old, minDiag: "<< minDiag);
1223 gp_XY uv1, uv2 = node->myUV;
1224 for ( i = isTriangle ? 2 : 0; i < 3; i++ ) // mark not computed vectors
1226 moveVec[ i ].SetCoord( 1, 2e100); // not use this vector
1227 while ( !isOldOk ) {
1228 // find the least moveVec
1230 double minMove2 = 1e100;
1231 for ( i = isTriangle ? 2 : 0; i < 3; i++ )
1233 if ( moveVec[i].Coord(1) < 1e100 ) {
1234 double move2 = moveVec[i].SquareMagnitude();
1235 if ( move2 < minMove2 ) {
1244 // move node to newUV
1245 uv1 = node->myUV + moveVec[ iMin ].XY();
1246 uv2 += moveVec[ iMin ].XY();
1247 moveVec[ iMin ].SetCoord( 1, 2e100); // not use this vector more
1248 // check if uv1 is ok
1249 for ( i = isTriangle ? 2 : 0; i < 3; i++ )
1250 wasOk[i] = ( outVec[i] * gp_Vec2d( n[i]->myUV, uv1 ) < -minDiag );
1251 isOldOk = ( wasOk[0] && wasOk[1] ) || ( wasOk[2] && convex );
1253 oldUVImpr[ nbOldImpr++ ] = uv1;
1255 // check if uv2 is ok
1256 for ( i = isTriangle ? 2 : 0; i < 3; i++ )
1257 wasOk[i] = ( outVec[i] * gp_Vec2d( n[i]->myUV, uv2 ) < -minDiag );
1258 isOldOk = ( wasOk[0] && wasOk[1] ) || ( wasOk[2] && convex );
1260 oldUVImpr[ nbOldImpr++ ] = uv2;
1265 } // loop on 4 quadrangles around <node>
1267 if ( crit == CHECK_NEW_OK )
1269 if ( crit == CHECK_NEW_IN )
1278 if ( oldIsIn && nbOldImpr ) {
1279 // MESSAGE(" Try to improve UV, init: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<
1280 // " uv: "<<oldUV.X()<<" "<<oldUV.Y() );
1281 gp_XY uv = oldUVImpr[ 0 ];
1282 for ( int i = 1; i < nbOldImpr; i++ )
1283 uv += oldUVImpr[ i ];
1285 if ( checkQuads( node, uv, reversed, CHECK_NEW_OK )) {
1290 //MESSAGE(" Cant improve UV, uv: "<<uv.X()<<" "<<uv.Y());
1293 if ( !oldIsIn && nbOldFix ) {
1294 // MESSAGE(" Try to fix UV, init: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<
1295 // " uv: "<<oldUV.X()<<" "<<oldUV.Y() );
1296 gp_XY uv = oldUVFixed[ 0 ];
1297 for ( int i = 1; i < nbOldFix; i++ )
1298 uv += oldUVFixed[ i ];
1300 if ( checkQuads( node, uv, reversed, CHECK_NEW_IN )) {
1305 //MESSAGE(" Cant fix UV, uv: "<<uv.X()<<" "<<uv.Y());
1308 if ( newIsIn && oldIsIn )
1309 newUV = ( newBadRate < oldBadRate ) ? newUV : oldUV;
1310 else if ( !newIsIn )
1317 //=======================================================================
1318 //function : compUVByElasticIsolines
1319 //purpose : compute UV as nodes of iso-poly-lines consisting of
1320 // segments keeping relative size as in the pattern
1321 //=======================================================================
1322 //#define DEB_COMPUVBYELASTICISOLINES
1323 bool SMESH_Pattern::
1324 compUVByElasticIsolines(const list< list< TPoint* > >& theBndPoints,
1325 const list< TPoint* >& thePntToCompute)
1327 //cout << "============================== KEY POINTS =============================="<<endl;
1328 // list< int >::iterator kpIt = myKeyPointIDs.begin();
1329 // for ( ; kpIt != myKeyPointIDs.end(); kpIt++ ) {
1330 // TPoint& p = myPoints[ *kpIt ];
1331 // cout << "INIT: " << p.myInitUV.X() << " " << p.myInitUV.Y() <<
1332 // " UV: " << p.myUV.X() << " " << p.myUV.Y() << endl;
1334 //cout << "=============================="<<endl;
1336 // Define parameters of iso-grid nodes in U and V dir
1338 set< double > paramSet[ 2 ];
1339 list< list< TPoint* > >::const_iterator pListIt;
1340 list< TPoint* >::const_iterator pIt;
1341 for ( pListIt = theBndPoints.begin(); pListIt != theBndPoints.end(); pListIt++ ) {
1342 const list< TPoint* > & pList = * pListIt;
1343 for ( pIt = pList.begin(); pIt != pList.end(); pIt++ ) {
1344 paramSet[0].insert( (*pIt)->myInitUV.X() );
1345 paramSet[1].insert( (*pIt)->myInitUV.Y() );
1348 for ( pIt = thePntToCompute.begin(); pIt != thePntToCompute.end(); pIt++ ) {
1349 paramSet[0].insert( (*pIt)->myInitUV.X() );
1350 paramSet[1].insert( (*pIt)->myInitUV.Y() );
1352 // unite close parameters and split too long segments
1355 for ( iDir = 0; iDir < 2; iDir++ )
1357 set< double > & params = paramSet[ iDir ];
1358 double range = ( *params.rbegin() - *params.begin() );
1359 double toler = range / 1e6;
1360 tol[ iDir ] = toler;
1361 // double maxSegment = range / params.size() / 2.;
1363 // set< double >::iterator parIt = params.begin();
1364 // double prevPar = *parIt;
1365 // for ( parIt++; parIt != params.end(); parIt++ )
1367 // double segLen = (*parIt) - prevPar;
1368 // if ( segLen < toler )
1369 // ;//params.erase( prevPar ); // unite
1370 // else if ( segLen > maxSegment )
1371 // params.insert( prevPar + 0.5 * segLen ); // split
1372 // prevPar = (*parIt);
1376 // Make nodes of a grid of iso-poly-lines
1378 list < TIsoNode > nodes;
1379 typedef list < TIsoNode *> TIsoLine;
1380 map < double, TIsoLine > isoMap[ 2 ];
1382 set< double > & params0 = paramSet[ 0 ];
1383 set< double >::iterator par0It = params0.begin();
1384 for ( ; par0It != params0.end(); par0It++ )
1386 TIsoLine & isoLine0 = isoMap[0][ *par0It ]; // vertical isoline with const U
1387 set< double > & params1 = paramSet[ 1 ];
1388 set< double >::iterator par1It = params1.begin();
1389 for ( ; par1It != params1.end(); par1It++ )
1391 nodes.push_back( TIsoNode( *par0It, *par1It ) );
1392 isoLine0.push_back( & nodes.back() );
1393 isoMap[1][ *par1It ].push_back( & nodes.back() );
1397 // Compute intersections of boundaries with iso-lines:
1398 // only boundary nodes will have computed UV so far
1401 list< list< TPoint* > >::const_iterator bndIt = theBndPoints.begin();
1402 list< TIsoNode* > bndNodes; // nodes corresponding to outer theBndPoints
1403 for ( ; bndIt != theBndPoints.end(); bndIt++ )
1405 const list< TPoint* > & bndPoints = * bndIt;
1406 TPoint* prevP = bndPoints.back(); // this is the first point
1407 list< TPoint* >::const_iterator pIt = bndPoints.begin();
1408 // loop on the edge-points
1409 for ( ; pIt != bndPoints.end(); pIt++ )
1411 TPoint* point = *pIt;
1412 for ( iDir = 0; iDir < 2; iDir++ )
1414 const int iCoord = iDir + 1;
1415 const int iOtherCoord = 2 - iDir;
1416 double par1 = prevP->myInitUV.Coord( iCoord );
1417 double par2 = point->myInitUV.Coord( iCoord );
1418 double parDif = par2 - par1;
1419 if ( Abs( parDif ) <= DBL_MIN )
1421 // find iso-lines intersecting a bounadry
1422 double toler = tol[ 1 - iDir ];
1423 double minPar = Min ( par1, par2 );
1424 double maxPar = Max ( par1, par2 );
1425 map < double, TIsoLine >& isos = isoMap[ iDir ];
1426 map < double, TIsoLine >::iterator isoIt = isos.begin();
1427 for ( ; isoIt != isos.end(); isoIt++ )
1429 double isoParam = (*isoIt).first;
1430 if ( isoParam < minPar || isoParam > maxPar )
1432 double r = ( isoParam - par1 ) / parDif;
1433 gp_XY uv = ( 1 - r ) * prevP->myUV + r * point->myUV;
1434 gp_XY initUV = ( 1 - r ) * prevP->myInitUV + r * point->myInitUV;
1435 double otherPar = initUV.Coord( iOtherCoord ); // along isoline
1436 // find existing node with otherPar or insert a new one
1437 TIsoLine & isoLine = (*isoIt).second;
1439 TIsoLine::iterator nIt = isoLine.begin();
1440 for ( ; nIt != isoLine.end(); nIt++ ) {
1441 nodePar = (*nIt)->myInitUV.Coord( iOtherCoord );
1442 if ( nodePar >= otherPar )
1446 if ( Abs( nodePar - otherPar ) <= toler )
1447 node = ( nIt == isoLine.end() ) ? isoLine.back() : (*nIt);
1449 nodes.push_back( TIsoNode( initUV.X(), initUV.Y() ) );
1450 node = & nodes.back();
1451 isoLine.insert( nIt, node );
1453 node->SetNotMovable();
1455 uvBnd.Add( gp_Pnt2d( uv ));
1456 // cout << "bnd: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<" UV: "<<node->myUV.X()<<" "<<node->myUV.Y()<<endl;
1458 gp_XY tgt( point->myUV - prevP->myUV );
1459 if ( ::IsEqual( r, 1. ))
1460 node->myDir[ 0 ] = tgt;
1461 else if ( ::IsEqual( r, 0. ))
1462 node->myDir[ 1 ] = tgt;
1464 node->myDir[ 1 ] = node->myDir[ 0 ] = tgt;
1465 // keep boundary nodes corresponding to boundary points
1466 if ( bndIt == theBndPoints.begin() && ::IsEqual( r, 1. ))
1467 if ( bndNodes.empty() || bndNodes.back() != node )
1468 bndNodes.push_back( node );
1469 } // loop on isolines
1470 } // loop on 2 directions
1472 } // loop on boundary points
1473 } // loop on boundaries
1475 // Define orientation
1477 // find the point with the least X
1478 double leastX = DBL_MAX;
1479 TIsoNode * leftNode;
1480 list < TIsoNode >::iterator nodeIt = nodes.begin();
1481 for ( ; nodeIt != nodes.end(); nodeIt++ ) {
1482 TIsoNode & node = *nodeIt;
1483 if ( node.IsUVComputed() && node.myUV.X() < leastX ) {
1484 leastX = node.myUV.X();
1487 // if ( node.IsUVComputed() ) {
1488 // cout << "bndNode INIT: " << node.myInitUV.X()<<" "<<node.myInitUV.Y()<<" UV: "<<
1489 // node.myUV.X()<<" "<<node.myUV.Y()<<endl<<
1490 // " dir0: "<<node.myDir[0].X()<<" "<<node.myDir[0].Y() <<
1491 // " dir1: "<<node.myDir[1].X()<<" "<<node.myDir[1].Y() << endl;
1494 bool reversed = ( leftNode->myDir[0].Y() + leftNode->myDir[1].Y() > 0 );
1495 //SCRUTE( reversed );
1497 // Prepare internal nodes:
1499 // 2. compute ratios
1500 // 3. find boundary nodes for each node
1501 // 4. remove nodes out of the boundary
1502 for ( iDir = 0; iDir < 2; iDir++ )
1504 const int iCoord = 2 - iDir; // coord changing along an isoline
1505 map < double, TIsoLine >& isos = isoMap[ iDir ];
1506 map < double, TIsoLine >::iterator isoIt = isos.begin();
1507 for ( ; isoIt != isos.end(); isoIt++ )
1509 TIsoLine & isoLine = (*isoIt).second;
1510 bool firstCompNodeFound = false;
1511 TIsoLine::iterator lastCompNodePos, nPrevIt, nIt, nNextIt, nIt2;
1512 nPrevIt = nIt = nNextIt = isoLine.begin();
1514 nNextIt++; nNextIt++;
1515 while ( nIt != isoLine.end() )
1517 // 1. connect prev - cur
1518 TIsoNode* node = *nIt, * prevNode = *nPrevIt;
1519 if ( !firstCompNodeFound && prevNode->IsUVComputed() ) {
1520 firstCompNodeFound = true;
1521 lastCompNodePos = nPrevIt;
1523 if ( firstCompNodeFound ) {
1524 node->SetNext( prevNode, iDir, 0 );
1525 prevNode->SetNext( node, iDir, 1 );
1528 if ( nNextIt != isoLine.end() ) {
1529 double par1 = prevNode->myInitUV.Coord( iCoord );
1530 double par2 = node->myInitUV.Coord( iCoord );
1531 double par3 = (*nNextIt)->myInitUV.Coord( iCoord );
1532 node->myRatio[ iDir ] = ( par2 - par1 ) / ( par3 - par1 );
1534 // 3. find boundary nodes
1535 if ( node->IsUVComputed() )
1536 lastCompNodePos = nIt;
1537 else if ( firstCompNodeFound && nNextIt != isoLine.end() ) {
1538 TIsoNode* bndNode1 = *lastCompNodePos, *bndNode2 = 0;
1539 for ( nIt2 = nNextIt; nIt2 != isoLine.end(); nIt2++ )
1540 if ( (*nIt2)->IsUVComputed() )
1542 if ( nIt2 != isoLine.end() ) {
1544 node->SetBoundaryNode( bndNode1, iDir, 0 );
1545 node->SetBoundaryNode( bndNode2, iDir, 1 );
1546 // cout << "--------------------------------------------------"<<endl;
1547 // cout << "bndNode1: " << bndNode1->myUV.X()<<" "<<bndNode1->myUV.Y()<<endl<<
1548 // " dir0: "<<bndNode1->myDir[0].X()<<" "<<bndNode1->myDir[0].Y() <<
1549 // " dir1: "<<bndNode1->myDir[1].X()<<" "<<bndNode1->myDir[1].Y() << endl;
1550 // cout << "bndNode2: " << bndNode2->myUV.X()<<" "<<bndNode2->myUV.Y()<<endl<<
1551 // " dir0: "<<bndNode2->myDir[0].X()<<" "<<bndNode2->myDir[0].Y() <<
1552 // " dir1: "<<bndNode2->myDir[1].X()<<" "<<bndNode2->myDir[1].Y() << endl;
1556 if ( nNextIt != isoLine.end() ) nNextIt++;
1557 // 4. remove nodes out of the boundary
1558 if ( !firstCompNodeFound )
1559 isoLine.pop_front();
1560 } // loop on isoLine nodes
1562 // remove nodes after the boundary
1563 // for ( nIt = ++lastCompNodePos; nIt != isoLine.end(); nIt++ )
1564 // (*nIt)->SetNotMovable();
1565 isoLine.erase( ++lastCompNodePos, isoLine.end() );
1566 } // loop on isolines
1567 } // loop on 2 directions
1569 // Compute local isoline direction for internal nodes
1572 map < double, TIsoLine >& isos = isoMap[ 0 ]; // vertical isolines with const U
1573 map < double, TIsoLine >::iterator isoIt = isos.begin();
1574 for ( ; isoIt != isos.end(); isoIt++ )
1576 TIsoLine & isoLine = (*isoIt).second;
1577 TIsoLine::iterator nIt = isoLine.begin();
1578 for ( ; nIt != isoLine.end(); nIt++ )
1580 TIsoNode* node = *nIt;
1581 if ( node->IsUVComputed() || !node->IsMovable() )
1583 gp_Vec2d aTgt[2], aNorm[2];
1586 for ( iDir = 0; iDir < 2; iDir++ )
1588 TIsoNode* bndNode1 = node->GetBoundaryNode( iDir, 0 );
1589 TIsoNode* bndNode2 = node->GetBoundaryNode( iDir, 1 );
1590 if ( !bndNode1 || !bndNode2 ) {
1594 const int iCoord = 2 - iDir; // coord changing along an isoline
1595 double par1 = bndNode1->myInitUV.Coord( iCoord );
1596 double par2 = node->myInitUV.Coord( iCoord );
1597 double par3 = bndNode2->myInitUV.Coord( iCoord );
1598 ratio[ iDir ] = ( par2 - par1 ) / ( par3 - par1 );
1600 gp_Vec2d tgt1( bndNode1->myDir[0].XY() + bndNode1->myDir[1].XY() );
1601 gp_Vec2d tgt2( bndNode2->myDir[0].XY() + bndNode2->myDir[1].XY() );
1602 if ( bool( iDir ) == reversed ) tgt2.Reverse(); // along perpend. isoline
1603 else tgt1.Reverse();
1604 //cout<<" tgt: " << tgt1.X()<<" "<<tgt1.Y()<<" | "<< tgt2.X()<<" "<<tgt2.Y()<<endl;
1606 if ( ratio[ iDir ] < 0.5 )
1607 aNorm[ iDir ] = gp_Vec2d( -tgt1.Y(), tgt1.X() ); // rotate tgt to the left
1609 aNorm[ iDir ] = gp_Vec2d( -tgt2.Y(), tgt2.X() );
1611 aNorm[ iDir ].Reverse(); // along iDir isoline
1613 double angle = tgt1.Angle( tgt2 ); // [-PI, PI]
1614 // maybe angle is more than |PI|
1615 if ( Abs( angle ) > PI / 2. ) {
1616 // check direction of the last but one perpendicular isoline
1617 TIsoNode* prevNode = bndNode2->GetNext( iDir, 0 );
1618 bndNode1 = prevNode->GetBoundaryNode( 1 - iDir, 0 );
1619 bndNode2 = prevNode->GetBoundaryNode( 1 - iDir, 1 );
1620 gp_Vec2d isoDir( bndNode1->myUV, bndNode2->myUV );
1621 if ( isoDir * tgt2 < 0 )
1623 double angle2 = tgt1.Angle( isoDir );
1624 //cout << " isoDir: "<< isoDir.X() <<" "<<isoDir.Y() << " ANGLE: "<< angle << " "<<angle2<<endl;
1625 if (angle2 * angle < 0 && // check the sign of an angle close to PI
1626 Abs ( Abs ( angle ) - PI ) <= PI / 180. ) {
1627 //MESSAGE("REVERSE ANGLE");
1630 if ( Abs( angle2 ) > Abs( angle ) ||
1631 ( angle2 * angle < 0 && Abs( angle2 ) > Abs( angle - angle2 ))) {
1632 //MESSAGE("Add PI");
1633 // cout << "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
1634 // cout <<"ISO: " << isoParam << " " << (*iso2It).first << endl;
1635 // cout << "bndNode1: " << bndNode1->myUV.X()<<" "<<bndNode1->myUV.Y()<< endl;
1636 // cout << "bndNode2: " << bndNode2->myUV.X()<<" "<<bndNode2->myUV.Y()<<endl;
1637 // cout <<" tgt: " << tgt1.X()<<" "<<tgt1.Y()<<" "<< tgt2.X()<<" "<<tgt2.Y()<<endl;
1638 angle += ( angle < 0 ) ? 2. * PI : -2. * PI;
1641 aTgt[ iDir ] = tgt1.Rotated( angle * ratio[ iDir ] ).XY();
1645 for ( iDir = 0; iDir < 2; iDir++ )
1647 aTgt[iDir].Normalize();
1648 aNorm[1-iDir].Normalize();
1649 double r = Abs ( ratio[iDir] - 0.5 ) * 2.0; // [0,1] - distance from the middle
1652 node->myDir[iDir] = //aTgt[iDir];
1653 aNorm[1-iDir] * r + aTgt[iDir] * ( 1. - r );
1655 // cout << "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
1656 // cout <<" tgt: " << tgt1.X()<<" "<<tgt1.Y()<<" - "<< tgt2.X()<<" "<<tgt2.Y()<<endl;
1657 // cout << " isoDir: "<< node->myDir[0].X() <<" "<<node->myDir[0].Y()<<" | "
1658 // << node->myDir[1].X() <<" "<<node->myDir[1].Y()<<endl;
1660 } // loop on iso nodes
1661 } // loop on isolines
1663 // Find nodes to start computing UV from
1665 list< TIsoNode* > startNodes;
1666 list< TIsoNode* >::iterator nIt = bndNodes.end();
1667 TIsoNode* node = *(--nIt);
1668 TIsoNode* prevNode = *(--nIt);
1669 for ( nIt = bndNodes.begin(); nIt != bndNodes.end(); nIt++ )
1671 TIsoNode* nextNode = *nIt;
1672 gp_Vec2d initTgt1( prevNode->myInitUV, node->myInitUV );
1673 gp_Vec2d initTgt2( node->myInitUV, nextNode->myInitUV );
1674 double initAngle = initTgt1.Angle( initTgt2 );
1675 double angle = node->myDir[0].Angle( node->myDir[1] );
1676 if ( reversed ) angle = -angle;
1677 if ( initAngle > angle && initAngle - angle > PI / 2.1 ) {
1678 // find a close internal node
1679 TIsoNode* nClose = 0;
1680 list< TIsoNode* > testNodes;
1681 testNodes.push_back( node );
1682 list< TIsoNode* >::iterator it = testNodes.begin();
1683 for ( ; !nClose && it != testNodes.end(); it++ )
1685 for (int i = 0; i < 4; i++ )
1687 nClose = (*it)->myNext[ i ];
1689 if ( !nClose->IsUVComputed() )
1692 testNodes.push_back( nClose );
1698 startNodes.push_back( nClose );
1699 // cout << "START: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<" UV: "<<
1700 // node->myUV.X()<<" "<<node->myUV.Y()<<endl<<
1701 // "initAngle: " << initAngle << " angle: " << angle << endl;
1702 // cout <<" init tgt: " << initTgt1.X()<<" "<<initTgt1.Y()<<" | "<< initTgt2.X()<<" "<<initTgt2.Y()<<endl;
1703 // cout << " tgt: "<< node->myDir[ 0 ].X() <<" "<<node->myDir[ 0 ].Y()<<" | "<<
1704 // node->myDir[ 1 ].X() <<" "<<node->myDir[ 1 ].Y()<<endl;
1705 // cout << "CLOSE: "<<nClose->myInitUV.X()<<" "<<nClose->myInitUV.Y()<<endl;
1711 // Compute starting UV of internal nodes
1713 list < TIsoNode* > internNodes;
1714 bool needIteration = true;
1715 if ( startNodes.empty() ) {
1716 MESSAGE( " Starting UV by compUVByIsoIntersection()");
1717 needIteration = false;
1718 map < double, TIsoLine >& isos = isoMap[ 0 ];
1719 map < double, TIsoLine >::iterator isoIt = isos.begin();
1720 for ( ; isoIt != isos.end(); isoIt++ )
1722 TIsoLine & isoLine = (*isoIt).second;
1723 TIsoLine::iterator nIt = isoLine.begin();
1724 for ( ; !needIteration && nIt != isoLine.end(); nIt++ )
1726 TIsoNode* node = *nIt;
1727 if ( !node->IsUVComputed() && node->IsMovable() ) {
1728 internNodes.push_back( node );
1730 if ( !compUVByIsoIntersection(theBndPoints, node->myInitUV,
1731 node->myUV, needIteration ))
1732 node->myUV = node->myInitUV;
1736 if ( needIteration )
1737 for ( nIt = bndNodes.begin(); nIt != bndNodes.end(); nIt++ )
1739 TIsoNode* node = *nIt, *nClose = 0;
1740 list< TIsoNode* > testNodes;
1741 testNodes.push_back( node );
1742 list< TIsoNode* >::iterator it = testNodes.begin();
1743 for ( ; !nClose && it != testNodes.end(); it++ )
1745 for (int i = 0; i < 4; i++ )
1747 nClose = (*it)->myNext[ i ];
1749 if ( !nClose->IsUVComputed() && nClose->IsMovable() )
1752 testNodes.push_back( nClose );
1758 startNodes.push_back( nClose );
1762 double aMin[2], aMax[2], step[2];
1763 uvBnd.Get( aMin[0], aMin[1], aMax[0], aMax[1] );
1764 double minUvSize = Min ( aMax[0]-aMin[0], aMax[1]-aMin[1] );
1765 step[0] = minUvSize / paramSet[ 0 ].size() / 10;
1766 step[1] = minUvSize / paramSet[ 1 ].size() / 10;
1767 //cout << "STEPS: " << step[0] << " " << step[1]<< endl;
1769 for ( nIt = startNodes.begin(); nIt != startNodes.end(); nIt++ )
1771 TIsoNode* prevN[2], *node = *nIt;
1772 if ( node->IsUVComputed() || !node->IsMovable() )
1774 gp_XY newUV( 0, 0 ), sumDir( 0, 0 );
1775 int nbComp = 0, nbPrev = 0;
1776 for ( iDir = 0; iDir < 2; iDir++ )
1778 TIsoNode* prevNode1 = 0, *prevNode2 = 0;
1779 TIsoNode* n = node->GetNext( iDir, 0 );
1780 if ( n->IsUVComputed() )
1783 startNodes.push_back( n );
1784 n = node->GetNext( iDir, 1 );
1785 if ( n->IsUVComputed() )
1788 startNodes.push_back( n );
1790 prevNode1 = prevNode2;
1793 if ( prevNode1 ) nbPrev++;
1794 if ( prevNode2 ) nbPrev++;
1797 double prevPar = prevNode1->myInitUV.Coord( 2 - iDir );
1798 double par = node->myInitUV.Coord( 2 - iDir );
1799 bool isEnd = ( prevPar > par );
1800 // dir = node->myDir[ 1 - iDir ].XY() * ( isEnd ? -1. : 1. );
1801 //cout << "__________"<<endl<< "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
1802 TIsoNode* bndNode = node->GetBoundaryNode( iDir, isEnd );
1803 gp_XY tgt( bndNode->myDir[0].XY() + bndNode->myDir[1].XY() );
1804 dir.SetCoord( 1, tgt.Y() * ( reversed ? 1 : -1 ));
1805 dir.SetCoord( 2, tgt.X() * ( reversed ? -1 : 1 ));
1806 //cout << "bndNode UV: " << bndNode->myUV.X()<<" "<<bndNode->myUV.Y()<< endl;
1807 // cout << " tgt: "<< bndNode->myDir[ 0 ].X() <<" "<<bndNode->myDir[ 0 ].Y()<<" | "<<
1808 // bndNode->myDir[ 1 ].X() <<" "<<bndNode->myDir[ 1 ].Y()<<endl;
1809 //cout << "prevNode UV: " << prevNode1->myUV.X()<<" "<<prevNode1->myUV.Y()<<
1810 //" par: " << prevPar << endl;
1811 // cout <<" tgt: " << tgt.X()<<" "<<tgt.Y()<<endl;
1812 //cout << " DIR: "<< dir.X() <<" "<<dir.Y()<<endl;
1814 //cout << "____2next______"<<endl<< "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
1815 gp_XY & uv1 = prevNode1->myUV;
1816 gp_XY & uv2 = prevNode2->myUV;
1817 // dir = ( uv2 - uv1 );
1818 // double len = dir.Modulus();
1819 // if ( len > DBL_MIN )
1820 // dir /= len * 0.5;
1821 double r = node->myRatio[ iDir ];
1822 newUV += uv1 * ( 1 - r ) + uv2 * r;
1825 newUV += prevNode1->myUV + dir * step[ iDir ];
1828 prevN[ iDir ] = prevNode1;
1834 //cout << "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
1836 // check if a quadrangle is not distorted
1838 //int crit = ( nbPrev == 4 ) ? FIX_OLD : CHECK_NEW_IN;
1839 if ( !checkQuads( node, newUV, reversed, FIX_OLD, step[0] + step[1] )) {
1840 //cout <<" newUV: " << node->myUV.X() << " "<<node->myUV.Y() << " nbPrev: "<<nbPrev<< endl;
1841 // cout << "_FIX_INIT_ fixedUV: " << newUV.X() << " "<<newUV.Y() << endl;
1845 internNodes.push_back( node );
1850 static int maxNbIter = 100;
1851 #ifdef DEB_COMPUVBYELASTICISOLINES
1853 bool useNbMoveNode = 0;
1854 static int maxNbNodeMove = 100;
1857 if ( !useNbMoveNode )
1858 maxNbIter = ( maxNbIter < 0 ) ? 100 : -1;
1863 if ( !needIteration) break;
1864 #ifdef DEB_COMPUVBYELASTICISOLINES
1865 if ( nbIter >= maxNbIter ) break;
1868 list < TIsoNode* >::iterator nIt = internNodes.begin();
1869 for ( ; nIt != internNodes.end(); nIt++ ) {
1870 #ifdef DEB_COMPUVBYELASTICISOLINES
1872 cout << nbNodeMove <<" =================================================="<<endl;
1874 TIsoNode * node = *nIt;
1878 for ( iDir = 0; iDir < 2; iDir++ )
1880 gp_XY & uv1 = node->GetNext( iDir, 0 )->myUV;
1881 gp_XY & uv2 = node->GetNext( iDir, 1 )->myUV;
1882 double r = node->myRatio[ iDir ];
1883 loc[ iDir ] = uv1 * ( 1 - r ) + uv2 * r;
1884 // line[ iDir ].SetLocation( loc[ iDir ] );
1885 // line[ iDir ].SetDirection( node->myDir[ iDir ] );
1888 double locR[2] = { 0, 0 };
1889 for ( iDir = 0; iDir < 2; iDir++ )
1891 const int iCoord = 2 - iDir; // coord changing along an isoline
1892 TIsoNode* bndNode1 = node->GetBoundaryNode( iDir, 0 );
1893 TIsoNode* bndNode2 = node->GetBoundaryNode( iDir, 1 );
1894 double par1 = bndNode1->myInitUV.Coord( iCoord );
1895 double par2 = node->myInitUV.Coord( iCoord );
1896 double par3 = bndNode2->myInitUV.Coord( iCoord );
1897 double r = ( par2 - par1 ) / ( par3 - par1 );
1898 r = Abs ( r - 0.5 ) * 2.0; // [0,1] - distance from the middle
1899 locR[ iDir ] = ( 1 - r * r ) * 0.25;
1901 //locR[0] = locR[1] = 0.25;
1902 // intersect the 2 lines and move a node
1903 //IntAna2d_AnaIntersection inter( line[0], line[1] );
1904 if ( /*inter.IsDone() && inter.NbPoints() ==*/ 1 )
1906 // double intR = 1 - locR[0] - locR[1];
1907 // gp_XY newUV = inter.Point(1).Value().XY();
1908 // if ( !checkQuads( node, newUV, reversed, CHECK_NEW_IN ))
1909 // newUV = ( locR[0] * loc[0] + locR[1] * loc[1] ) / ( 1 - intR );
1911 // newUV = intR * newUV + locR[0] * loc[0] + locR[1] * loc[1];
1912 gp_XY newUV = 0.5 * ( loc[0] + loc[1] );
1913 // avoid parallel isolines intersection
1914 checkQuads( node, newUV, reversed );
1916 maxMove = Max( maxMove, ( newUV - node->myUV ).SquareModulus());
1918 } // intersection found
1919 #ifdef DEB_COMPUVBYELASTICISOLINES
1920 if (useNbMoveNode && ++nbNodeMove >= maxNbNodeMove ) break;
1922 } // loop on internal nodes
1923 #ifdef DEB_COMPUVBYELASTICISOLINES
1924 if (useNbMoveNode && nbNodeMove >= maxNbNodeMove ) break;
1926 } while ( maxMove > 1e-8 && nbIter++ < maxNbIter );
1928 MESSAGE( "compUVByElasticIsolines(): Nb iterations " << nbIter << " dist: " << sqrt( maxMove ));
1930 if ( nbIter >= maxNbIter && sqrt(maxMove) > minUvSize * 0.05 ) {
1931 MESSAGE( "compUVByElasticIsolines() failed: "<<sqrt(maxMove)<<">"<<minUvSize * 0.05);
1932 #ifndef DEB_COMPUVBYELASTICISOLINES
1937 // Set computed UV to points
1939 for ( pIt = thePntToCompute.begin(); pIt != thePntToCompute.end(); pIt++ ) {
1940 TPoint* point = *pIt;
1941 //gp_XY oldUV = point->myUV;
1942 double minDist = DBL_MAX;
1943 list < TIsoNode >::iterator nIt = nodes.begin();
1944 for ( ; nIt != nodes.end(); nIt++ ) {
1945 double dist = ( (*nIt).myInitUV - point->myInitUV ).SquareModulus();
1946 if ( dist < minDist ) {
1948 point->myUV = (*nIt).myUV;
1958 //=======================================================================
1959 //function : setFirstEdge
1960 //purpose : choose the best first edge of theWire; return the summary distance
1961 // between point UV computed by isolines intersection and
1962 // eventual UV got from edge p-curves
1963 //=======================================================================
1965 //#define DBG_SETFIRSTEDGE
1966 double SMESH_Pattern::setFirstEdge (list< TopoDS_Edge > & theWire, int theFirstEdgeID)
1968 int iE, nbEdges = theWire.size();
1972 // Transform UVs computed by iso to fit bnd box of a wire
1974 // max nb of points on an edge
1976 int eID = theFirstEdgeID;
1977 for ( iE = 0; iE < nbEdges; iE++ )
1978 maxNbPnt = Max ( maxNbPnt, getShapePoints( eID++ ).size() );
1980 // compute bnd boxes
1981 TopoDS_Face face = TopoDS::Face( myShape );
1982 Bnd_Box2d bndBox, eBndBox;
1983 eID = theFirstEdgeID;
1984 list< TopoDS_Edge >::iterator eIt;
1985 list< TPoint* >::iterator pIt;
1986 for ( eIt = theWire.begin(); eIt != theWire.end(); eIt++ )
1988 // UV by isos stored in TPoint.myXYZ
1989 list< TPoint* > & ePoints = getShapePoints( eID++ );
1990 for ( pIt = ePoints.begin(); pIt != ePoints.end(); pIt++ ) {
1992 bndBox.Add( gp_Pnt2d( p->myXYZ.X(), p->myXYZ.Y() ));
1994 // UV by an edge p-curve
1996 Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface( *eIt, face, f, l );
1997 double dU = ( l - f ) / ( maxNbPnt - 1 );
1998 for ( int i = 0; i < maxNbPnt; i++ )
1999 eBndBox.Add( C2d->Value( f + i * dU ));
2002 // transform UVs by isos
2003 double minPar[2], maxPar[2], eMinPar[2], eMaxPar[2];
2004 bndBox.Get( minPar[0], minPar[1], maxPar[0], maxPar[1] );
2005 eBndBox.Get( eMinPar[0], eMinPar[1], eMaxPar[0], eMaxPar[1] );
2006 #ifdef DBG_SETFIRSTEDGE
2007 cout << "EDGES: X: " << eMinPar[0] << " - " << eMaxPar[0] << " Y: "
2008 << eMinPar[1] << " - " << eMaxPar[1] << endl;
2010 for ( int iC = 1, i = 0; i < 2; iC++, i++ ) // loop on 2 coordinates
2012 double dMin = eMinPar[i] - minPar[i];
2013 double dMax = eMaxPar[i] - maxPar[i];
2014 double dPar = maxPar[i] - minPar[i];
2015 eID = theFirstEdgeID;
2016 for ( iE = 0; iE < nbEdges; iE++ ) // loop on edges of a boundary
2018 list< TPoint* > & ePoints = getShapePoints( eID++ );
2019 for ( pIt = ++ePoints.begin(); pIt != ePoints.end(); pIt++ ) // loop on edge points
2021 double par = (*pIt)->myXYZ.Coord( iC );
2022 double r = ( par - minPar[i] ) / dPar;
2023 par += ( 1 - r ) * dMin + r * dMax;
2024 (*pIt)->myXYZ.SetCoord( iC, par );
2030 double minDist = DBL_MAX;
2031 for ( iE = 0 ; iE < nbEdges; iE++ )
2033 #ifdef DBG_SETFIRSTEDGE
2034 cout << " VARIANT " << iE << endl;
2036 // evaluate the distance between UV computed by the 2 methods:
2037 // by isos intersection ( myXYZ ) and by edge p-curves ( myUV )
2039 int eID = theFirstEdgeID;
2040 for ( eIt = theWire.begin(); eIt != theWire.end(); eIt++ )
2042 list< TPoint* > & ePoints = getShapePoints( eID++ );
2043 computeUVOnEdge( *eIt, ePoints );
2044 for ( pIt = ++ePoints.begin(); pIt != ePoints.end(); pIt++ ) {
2046 dist += ( p->myUV - gp_XY( p->myXYZ.X(), p->myXYZ.Y() )).SquareModulus();
2047 #ifdef DBG_SETFIRSTEDGE
2048 cout << " ISO : ( " << p->myXYZ.X() << ", "<< p->myXYZ.Y() << " ) PCURVE : ( " <<
2049 p->myUV.X() << ", " << p->myUV.Y() << ") " << endl;
2053 #ifdef DBG_SETFIRSTEDGE
2054 cout << "dist -- " << dist << endl;
2056 if ( dist < minDist ) {
2058 eBest = theWire.front();
2060 // check variant with another first edge
2061 theWire.splice( theWire.begin(), theWire, --theWire.end(), theWire.end() );
2063 // put the best first edge to the theWire front
2064 if ( eBest != theWire.front() ) {
2065 eIt = find ( theWire.begin(), theWire.end(), eBest );
2066 theWire.splice( theWire.begin(), theWire, eIt, theWire.end() );
2072 //=======================================================================
2073 //function : sortSameSizeWires
2074 //purpose : sort wires in theWireList from theFromWire until theToWire,
2075 // the wires are set in the order to correspond to the order
2076 // of boundaries; after sorting, edges in the wires are put
2077 // in a good order, point UVs on edges are computed and points
2078 // are appended to theEdgesPointsList
2079 //=======================================================================
2081 bool SMESH_Pattern::sortSameSizeWires (TListOfEdgesList & theWireList,
2082 const TListOfEdgesList::iterator& theFromWire,
2083 const TListOfEdgesList::iterator& theToWire,
2084 const int theFirstEdgeID,
2085 list< list< TPoint* > >& theEdgesPointsList )
2087 TopoDS_Face F = TopoDS::Face( myShape );
2088 int iW, nbWires = 0;
2089 TListOfEdgesList::iterator wlIt = theFromWire;
2090 while ( wlIt++ != theToWire )
2093 // Recompute key-point UVs by isolines intersection,
2094 // compute CG of key-points for each wire and bnd boxes of GCs
2097 gp_XY orig( gp::Origin2d().XY() );
2098 vector< gp_XY > vGcVec( nbWires, orig ), gcVec( nbWires, orig );
2099 Bnd_Box2d bndBox, vBndBox;
2100 int eID = theFirstEdgeID;
2101 list< TopoDS_Edge >::iterator eIt;
2102 for ( iW = 0, wlIt = theFromWire; wlIt != theToWire; wlIt++, iW++ )
2104 list< TopoDS_Edge > & wire = *wlIt;
2105 for ( eIt = wire.begin(); eIt != wire.end(); eIt++ )
2107 list< TPoint* > & ePoints = getShapePoints( eID++ );
2108 TPoint* p = ePoints.front();
2109 if ( !compUVByIsoIntersection( theEdgesPointsList, p->myInitUV, p->myUV, aBool )) {
2110 MESSAGE("cant sortSameSizeWires()");
2113 gcVec[iW] += p->myUV;
2114 bndBox.Add( gp_Pnt2d( p->myUV ));
2115 TopoDS_Vertex V = TopExp::FirstVertex( *eIt, true );
2116 gp_Pnt2d vXY = BRep_Tool::Parameters( V, F );
2117 vGcVec[iW] += vXY.XY();
2119 // keep the computed UV to compare against by setFirstEdge()
2120 p->myXYZ.SetCoord( p->myUV.X(), p->myUV.Y(), 0. );
2122 gcVec[iW] /= nbWires;
2123 vGcVec[iW] /= nbWires;
2124 // cout << " Wire " << iW << " iso: " << gcVec[iW].X() << " " << gcVec[iW].Y() << endl <<
2125 // " \t vertex: " << vGcVec[iW].X() << " " << vGcVec[iW].Y() << endl;
2128 // Transform GCs computed by isos to fit in bnd box of GCs by vertices
2130 double minPar[2], maxPar[2], vMinPar[2], vMaxPar[2];
2131 bndBox.Get( minPar[0], minPar[1], maxPar[0], maxPar[1] );
2132 vBndBox.Get( vMinPar[0], vMinPar[1], vMaxPar[0], vMaxPar[1] );
2133 for ( int iC = 1, i = 0; i < 2; iC++, i++ ) // loop on 2 coordinates
2135 double dMin = vMinPar[i] - minPar[i];
2136 double dMax = vMaxPar[i] - maxPar[i];
2137 double dPar = maxPar[i] - minPar[i];
2138 if ( Abs( dPar ) <= DBL_MIN )
2140 for ( iW = 0; iW < nbWires; iW++ ) { // loop on GCs of wires
2141 double par = gcVec[iW].Coord( iC );
2142 double r = ( par - minPar[i] ) / dPar;
2143 par += ( 1 - r ) * dMin + r * dMax;
2144 gcVec[iW].SetCoord( iC, par );
2148 // Define boundary - wire correspondence by GC closeness
2150 TListOfEdgesList tmpWList;
2151 tmpWList.splice( tmpWList.end(), theWireList, theFromWire, theToWire );
2152 typedef map< int, TListOfEdgesList::iterator > TIntWirePosMap;
2153 TIntWirePosMap bndIndWirePosMap;
2154 vector< bool > bndFound( nbWires, false );
2155 for ( iW = 0, wlIt = tmpWList.begin(); iW < nbWires; iW++, wlIt++ )
2157 // cout << " TRSF Wire " << iW << " iso: " << gcVec[iW].X() << " " << gcVec[iW].Y() << endl <<
2158 // " \t vertex: " << vGcVec[iW].X() << " " << vGcVec[iW].Y() << endl;
2159 double minDist = DBL_MAX;
2160 gp_XY & wGc = vGcVec[ iW ];
2162 for ( int iB = 0; iB < nbWires; iB++ ) {
2163 if ( bndFound[ iB ] ) continue;
2164 double dist = ( wGc - gcVec[ iB ] ).SquareModulus();
2165 if ( dist < minDist ) {
2170 bndFound[ bIndex ] = true;
2171 bndIndWirePosMap.insert( TIntWirePosMap::value_type( bIndex, wlIt ));
2176 TIntWirePosMap::iterator bIndWPosIt = bndIndWirePosMap.begin();
2177 eID = theFirstEdgeID;
2178 for ( ; bIndWPosIt != bndIndWirePosMap.end(); bIndWPosIt++ )
2180 TListOfEdgesList::iterator wirePos = (*bIndWPosIt).second;
2181 list < TopoDS_Edge > & wire = ( *wirePos );
2183 // choose the best first edge of a wire
2184 setFirstEdge( wire, eID );
2186 // compute eventual UV and fill theEdgesPointsList
2187 theEdgesPointsList.push_back( list< TPoint* >() );
2188 list< TPoint* > & edgesPoints = theEdgesPointsList.back();
2189 for ( eIt = wire.begin(); eIt != wire.end(); eIt++ )
2191 list< TPoint* > & ePoints = getShapePoints( eID++ );
2192 computeUVOnEdge( *eIt, ePoints );
2193 edgesPoints.insert( edgesPoints.end(), ePoints.begin(), (--ePoints.end()));
2195 // put wire back to theWireList
2197 theWireList.splice( theToWire, tmpWList, wlIt, wirePos );
2203 //=======================================================================
2205 //purpose : Compute nodes coordinates applying
2206 // the loaded pattern to <theFace>. The first key-point
2207 // will be mapped into <theVertexOnKeyPoint1>
2208 //=======================================================================
2210 bool SMESH_Pattern::Apply (const TopoDS_Face& theFace,
2211 const TopoDS_Vertex& theVertexOnKeyPoint1,
2212 const bool theReverse)
2214 MESSAGE(" ::Apply(face) " );
2215 TopoDS_Face face = theReverse ? TopoDS::Face( theFace.Reversed() ) : theFace;
2216 if ( !setShapeToMesh( face ))
2219 // find points on edges, it fills myNbKeyPntInBoundary
2220 if ( !findBoundaryPoints() )
2223 // Define the edges order so that the first edge starts at
2224 // theVertexOnKeyPoint1
2226 list< TopoDS_Edge > eList;
2227 list< int > nbVertexInWires;
2228 int nbWires = getOrderedEdges( face, theVertexOnKeyPoint1, eList, nbVertexInWires);
2229 if ( !theVertexOnKeyPoint1.IsSame( TopExp::FirstVertex( eList.front(), true )))
2231 MESSAGE( " theVertexOnKeyPoint1 not found in the outer wire ");
2232 return setErrorCode( ERR_APPLF_BAD_VERTEX );
2234 // check nb wires and edges
2235 list< int > l1 = myNbKeyPntInBoundary, l2 = nbVertexInWires;
2236 l1.sort(); l2.sort();
2239 MESSAGE( "Wrong nb vertices in wires" );
2240 return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
2243 // here shapes get IDs, for the outer wire IDs are OK
2244 list<TopoDS_Edge>::iterator elIt = eList.begin();
2245 for ( ; elIt != eList.end(); elIt++ ) {
2246 myShapeIDMap.Add( TopExp::FirstVertex( *elIt, true ));
2247 if ( BRep_Tool::IsClosed( *elIt, theFace ) )
2248 myShapeIDMap.Add( TopExp::LastVertex( *elIt, true ));
2250 int nbVertices = myShapeIDMap.Extent();
2252 for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
2253 myShapeIDMap.Add( *elIt );
2255 myShapeIDMap.Add( face );
2257 if ( myShapeIDToPointsMap.size() != myShapeIDMap.Extent()/* + nbSeamShapes*/ ) {
2258 MESSAGE( myShapeIDToPointsMap.size() <<" != " << myShapeIDMap.Extent());
2259 return setErrorCode( ERR_APPLF_INTERNAL_EEROR );
2262 // points on edges to be used for UV computation of in-face points
2263 list< list< TPoint* > > edgesPointsList;
2264 edgesPointsList.push_back( list< TPoint* >() );
2265 list< TPoint* > * edgesPoints = & edgesPointsList.back();
2266 list< TPoint* >::iterator pIt;
2268 // compute UV of points on the outer wire
2269 int iE, nbEdgesInOuterWire = nbVertexInWires.front();
2270 for (iE = 0, elIt = eList.begin();
2271 iE < nbEdgesInOuterWire && elIt != eList.end();
2274 list< TPoint* > & ePoints = getShapePoints( *elIt );
2276 computeUVOnEdge( *elIt, ePoints );
2277 // collect on-edge points (excluding the last one)
2278 edgesPoints->insert( edgesPoints->end(), ePoints.begin(), --ePoints.end());
2281 // If there are several wires, define the order of edges of inner wires:
2282 // compute UV of inner edge-points using 2 methods: the one for in-face points
2283 // and the one for on-edge points and then choose the best edge order
2284 // by the best correspondance of the 2 results
2287 // compute UV of inner edge-points using the method for in-face points
2288 // and devide eList into a list of separate wires
2290 list< list< TopoDS_Edge > > wireList;
2291 list<TopoDS_Edge>::iterator eIt = elIt;
2292 list<int>::iterator nbEIt = nbVertexInWires.begin();
2293 for ( nbEIt++; nbEIt != nbVertexInWires.end(); nbEIt++ )
2295 int nbEdges = *nbEIt;
2296 wireList.push_back( list< TopoDS_Edge >() );
2297 list< TopoDS_Edge > & wire = wireList.back();
2298 for ( iE = 0 ; iE < nbEdges; eIt++, iE++ )
2300 list< TPoint* > & ePoints = getShapePoints( *eIt );
2301 pIt = ePoints.begin();
2302 for ( pIt++; pIt != ePoints.end(); pIt++ ) {
2304 if ( !compUVByIsoIntersection( edgesPointsList, p->myInitUV, p->myUV, aBool )) {
2305 MESSAGE("cant Apply(face)");
2308 // keep the computed UV to compare against by setFirstEdge()
2309 p->myXYZ.SetCoord( p->myUV.X(), p->myUV.Y(), 0. );
2311 wire.push_back( *eIt );
2314 // remove inner edges from eList
2315 eList.erase( elIt, eList.end() );
2317 // sort wireList by nb edges in a wire
2318 sortBySize< TopoDS_Edge > ( wireList );
2320 // an ID of the first edge of a boundary
2321 int id1 = nbVertices + nbEdgesInOuterWire + 1;
2322 // if ( nbSeamShapes > 0 )
2323 // id1 += 2; // 2 vertices more
2325 // find points - edge correspondence for wires of unique size,
2326 // edge order within a wire should be defined only
2328 list< list< TopoDS_Edge > >::iterator wlIt = wireList.begin();
2329 while ( wlIt != wireList.end() )
2331 list< TopoDS_Edge >& wire = (*wlIt);
2332 int nbEdges = wire.size();
2334 if ( wlIt == wireList.end() || (*wlIt).size() != nbEdges ) // a unique size wire
2336 // choose the best first edge of a wire
2337 setFirstEdge( wire, id1 );
2339 // compute eventual UV and collect on-edge points
2340 edgesPointsList.push_back( list< TPoint* >() );
2341 edgesPoints = & edgesPointsList.back();
2343 for ( eIt = wire.begin(); eIt != wire.end(); eIt++ )
2345 list< TPoint* > & ePoints = getShapePoints( eID++ );
2346 computeUVOnEdge( *eIt, ePoints );
2347 edgesPoints->insert( edgesPoints->end(), ePoints.begin(), (--ePoints.end()));
2353 // find boundary - wire correspondence for several wires of same size
2355 id1 = nbVertices + nbEdgesInOuterWire + 1;
2356 wlIt = wireList.begin();
2357 while ( wlIt != wireList.end() )
2359 int nbSameSize = 0, nbEdges = (*wlIt).size();
2360 list< list< TopoDS_Edge > >::iterator wlIt2 = wlIt;
2362 while ( wlIt2 != wireList.end() && (*wlIt2).size() == nbEdges ) { // a same size wire
2366 if ( nbSameSize > 0 )
2367 if (!sortSameSizeWires(wireList, wlIt, wlIt2, id1, edgesPointsList))
2370 id1 += nbEdges * ( nbSameSize + 1 );
2373 // add well-ordered edges to eList
2375 for ( wlIt = wireList.begin(); wlIt != wireList.end(); wlIt++ )
2377 list< TopoDS_Edge >& wire = (*wlIt);
2378 eList.splice( eList.end(), wire, wire.begin(), wire.end() );
2381 // re-fill myShapeIDMap - all shapes get good IDs
2383 myShapeIDMap.Clear();
2384 for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
2385 myShapeIDMap.Add( TopExp::FirstVertex( *elIt, true ));
2386 for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
2387 myShapeIDMap.Add( *elIt );
2388 myShapeIDMap.Add( face );
2390 } // there are inner wires
2392 // Compute XYZ of on-edge points
2394 TopLoc_Location loc;
2395 for ( iE = nbVertices + 1, elIt = eList.begin(); elIt != eList.end(); elIt++ )
2398 Handle(Geom_Curve) C3d = BRep_Tool::Curve( *elIt, loc, f, l );
2399 const gp_Trsf & aTrsf = loc.Transformation();
2400 list< TPoint* > & ePoints = getShapePoints( iE++ );
2401 pIt = ePoints.begin();
2402 for ( pIt++; pIt != ePoints.end(); pIt++ )
2404 TPoint* point = *pIt;
2405 point->myXYZ = C3d->Value( point->myU );
2406 if ( !loc.IsIdentity() )
2407 aTrsf.Transforms( point->myXYZ.ChangeCoord() );
2411 // Compute UV and XYZ of in-face points
2413 // try to use a simple algo
2414 list< TPoint* > & fPoints = getShapePoints( face );
2415 bool isDeformed = false;
2416 for ( pIt = fPoints.begin(); !isDeformed && pIt != fPoints.end(); pIt++ )
2417 if ( !compUVByIsoIntersection( edgesPointsList, (*pIt)->myInitUV,
2418 (*pIt)->myUV, isDeformed )) {
2419 MESSAGE("cant Apply(face)");
2422 // try to use a complex algo if it is a difficult case
2423 if ( isDeformed && !compUVByElasticIsolines( edgesPointsList, fPoints ))
2425 for ( ; pIt != fPoints.end(); pIt++ ) // continue with the simple algo
2426 if ( !compUVByIsoIntersection( edgesPointsList, (*pIt)->myInitUV,
2427 (*pIt)->myUV, isDeformed )) {
2428 MESSAGE("cant Apply(face)");
2433 Handle(Geom_Surface) aSurface = BRep_Tool::Surface( face, loc );
2434 const gp_Trsf & aTrsf = loc.Transformation();
2435 for ( pIt = fPoints.begin(); pIt != fPoints.end(); pIt++ )
2437 TPoint * point = *pIt;
2438 point->myXYZ = aSurface->Value( point->myUV.X(), point->myUV.Y() );
2439 if ( !loc.IsIdentity() )
2440 aTrsf.Transforms( point->myXYZ.ChangeCoord() );
2443 myIsComputed = true;
2445 return setErrorCode( ERR_OK );
2448 //=======================================================================
2450 //purpose : Compute nodes coordinates applying
2451 // the loaded pattern to <theFace>. The first key-point
2452 // will be mapped into <theNodeIndexOnKeyPoint1>-th node
2453 //=======================================================================
2455 bool SMESH_Pattern::Apply (const SMDS_MeshFace* theFace,
2456 const int theNodeIndexOnKeyPoint1,
2457 const bool theReverse)
2459 MESSAGE(" ::Apply(MeshFace) " );
2461 if ( !IsLoaded() ) {
2462 MESSAGE( "Pattern not loaded" );
2463 return setErrorCode( ERR_APPL_NOT_LOADED );
2466 // check nb of nodes
2467 if (theFace->NbNodes() != myNbKeyPntInBoundary.front() ) {
2468 MESSAGE( myKeyPointIDs.size() << " != " << theFace->NbNodes() );
2469 return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
2472 // find points on edges, it fills myNbKeyPntInBoundary
2473 if ( !findBoundaryPoints() )
2476 // check that there are no holes in a pattern
2477 if (myNbKeyPntInBoundary.size() > 1 ) {
2478 return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
2481 // Define the nodes order
2483 list< const SMDS_MeshNode* > nodes;
2484 list< const SMDS_MeshNode* >::iterator n = nodes.end();
2485 SMDS_ElemIteratorPtr noIt = theFace->nodesIterator();
2487 while ( noIt->more() ) {
2488 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( noIt->next() );
2489 nodes.push_back( node );
2490 if ( iSub++ == theNodeIndexOnKeyPoint1 )
2493 if ( n != nodes.end() ) {
2495 if ( n != --nodes.end() )
2496 nodes.splice( nodes.begin(), nodes, ++n, nodes.end() );
2499 else if ( n != nodes.begin() )
2500 nodes.splice( nodes.end(), nodes, nodes.begin(), n );
2502 list< gp_XYZ > xyzList;
2503 myOrderedNodes.resize( theFace->NbNodes() );
2504 for ( iSub = 0, n = nodes.begin(); n != nodes.end(); ++n ) {
2505 xyzList.push_back( gp_XYZ( (*n)->X(), (*n)->Y(), (*n)->Z() ));
2506 myOrderedNodes[ iSub++] = *n;
2509 // Define a face plane
2511 list< gp_XYZ >::iterator xyzIt = xyzList.begin();
2512 gp_Pnt P ( *xyzIt++ );
2513 gp_Vec Vx( P, *xyzIt++ ), N;
2515 N = Vx ^ gp_Vec( P, *xyzIt++ );
2516 } while ( N.SquareMagnitude() <= DBL_MIN && xyzIt != xyzList.end() );
2517 if ( N.SquareMagnitude() <= DBL_MIN )
2518 return setErrorCode( ERR_APPLF_BAD_FACE_GEOM );
2519 gp_Ax2 pos( P, N, Vx );
2521 // Compute UV of key-points on a plane
2522 for ( xyzIt = xyzList.begin(), iSub = 1; xyzIt != xyzList.end(); xyzIt++, iSub++ )
2524 gp_Vec vec ( pos.Location(), *xyzIt );
2525 TPoint* p = getShapePoints( iSub ).front();
2526 p->myUV.SetX( vec * pos.XDirection() );
2527 p->myUV.SetY( vec * pos.YDirection() );
2531 // points on edges to be used for UV computation of in-face points
2532 list< list< TPoint* > > edgesPointsList;
2533 edgesPointsList.push_back( list< TPoint* >() );
2534 list< TPoint* > * edgesPoints = & edgesPointsList.back();
2535 list< TPoint* >::iterator pIt;
2537 // compute UV and XYZ of points on edges
2539 for ( xyzIt = xyzList.begin(); xyzIt != xyzList.end(); iSub++ )
2541 gp_XYZ& xyz1 = *xyzIt++;
2542 gp_XYZ& xyz2 = ( xyzIt != xyzList.end() ) ? *xyzIt : xyzList.front();
2544 list< TPoint* > & ePoints = getShapePoints( iSub );
2545 ePoints.back()->myInitU = 1.0;
2546 list< TPoint* >::const_iterator pIt = ++ePoints.begin();
2547 while ( *pIt != ePoints.back() )
2550 p->myXYZ = xyz1 * ( 1 - p->myInitU ) + xyz2 * p->myInitU;
2551 gp_Vec vec ( pos.Location(), p->myXYZ );
2552 p->myUV.SetX( vec * pos.XDirection() );
2553 p->myUV.SetY( vec * pos.YDirection() );
2555 // collect on-edge points (excluding the last one)
2556 edgesPoints->insert( edgesPoints->end(), ePoints.begin(), --ePoints.end());
2559 // Compute UV and XYZ of in-face points
2561 // try to use a simple algo to compute UV
2562 list< TPoint* > & fPoints = getShapePoints( iSub );
2563 bool isDeformed = false;
2564 for ( pIt = fPoints.begin(); !isDeformed && pIt != fPoints.end(); pIt++ )
2565 if ( !compUVByIsoIntersection( edgesPointsList, (*pIt)->myInitUV,
2566 (*pIt)->myUV, isDeformed )) {
2567 MESSAGE("cant Apply(face)");
2570 // try to use a complex algo if it is a difficult case
2571 if ( isDeformed && !compUVByElasticIsolines( edgesPointsList, fPoints ))
2573 for ( ; pIt != fPoints.end(); pIt++ ) // continue with the simple algo
2574 if ( !compUVByIsoIntersection( edgesPointsList, (*pIt)->myInitUV,
2575 (*pIt)->myUV, isDeformed )) {
2576 MESSAGE("cant Apply(face)");
2581 for ( pIt = fPoints.begin(); pIt != fPoints.end(); pIt++ )
2583 (*pIt)->myXYZ = ElSLib::PlaneValue( (*pIt)->myUV.X(), (*pIt)->myUV.Y(), pos );
2586 myIsComputed = true;
2588 return setErrorCode( ERR_OK );
2591 //=======================================================================
2592 //function : undefinedXYZ
2594 //=======================================================================
2596 static const gp_XYZ& undefinedXYZ()
2598 static gp_XYZ xyz( 1.e100, 0., 0. );
2602 //=======================================================================
2603 //function : isDefined
2605 //=======================================================================
2607 inline static bool isDefined(const gp_XYZ& theXYZ)
2609 return theXYZ.X() < 1.e100;
2612 //=======================================================================
2613 //function : mergePoints
2614 //purpose : Look for coincident points between myXYZs indexed with
2615 // list<int> of each element of xyzIndGroups. Coincident indices
2616 // are merged in myElemXYZIDs.
2617 //=======================================================================
2619 void SMESH_Pattern::mergePoints (map<TNodeSet, list<list<int> > >& indGroups,
2620 map< int, list< list< int >* > > & reverseConnectivity)
2622 map< TNodeSet, list< list< int > > >::iterator indListIt;
2623 for ( indListIt = indGroups.begin(); indListIt != indGroups.end(); indListIt++ )
2625 list<list< int > > groups = indListIt->second;
2626 if ( groups.size() < 2 )
2629 // const TNodeSet & nodes = indListIt->first;
2630 // TNodeSet::const_iterator n = nodes.begin();
2631 // for ( ; n != nodes.end(); n++ )
2636 list< int >& indices = groups.front();
2637 list< int >::iterator ind, ind1, ind2;
2638 for ( ind = indices.begin(); ind != indices.end(); ind++ )
2639 box.Add( gp_Pnt( myXYZ[ *ind ]));
2640 double x, y, z, X, Y, Z;
2641 box.Get( x, y, z, X, Y, Z );
2642 gp_Pnt p( x, y, z ), P( X, Y, Z );
2643 double tol2 = 1.e-4 * p.SquareDistance( P );
2645 // compare points, replace indices
2647 list< list< int > >::iterator grpIt1, grpIt2;
2648 for ( grpIt1 = groups.begin(); grpIt1 != groups.end(); grpIt1++ )
2650 list< int >& indices1 = *grpIt1;
2652 for ( grpIt2++; grpIt2 != groups.end(); grpIt2++ )
2654 list< int >& indices2 = *grpIt2;
2655 for ( ind1 = indices1.begin(); ind1 != indices1.end(); ind1++ )
2657 gp_XYZ& p1 = myXYZ[ *ind1 ];
2658 ind2 = indices2.begin();
2659 while ( ind2 != indices2.end() )
2661 gp_XYZ& p2 = myXYZ[ *ind2 ];
2662 //MESSAGE("COMP: " << *ind1 << " " << *ind2 << " X: " << p2.X() << " tol2: " << tol2);
2663 if ( ( p1 - p2 ).SquareModulus() <= tol2 )
2665 ASSERT( reverseConnectivity.find( *ind2 ) != reverseConnectivity.end() );
2666 list< list< int >* > & elemXYZIDsList = reverseConnectivity[ *ind2 ];
2667 list< list< int >* >::iterator elemXYZIDs = elemXYZIDsList.begin();
2668 for ( ; elemXYZIDs != elemXYZIDsList.end(); elemXYZIDs++ )
2670 ind = find( (*elemXYZIDs)->begin(), (*elemXYZIDs)->end(), *ind2 );
2671 //MESSAGE( " Replace " << *ind << " with " << *ind1 );
2672 myXYZ[ *ind ] = undefinedXYZ();
2675 ind2 = indices2.erase( ind2 );
2686 //=======================================================================
2688 //purpose : Compute nodes coordinates applying
2689 // the loaded pattern to <theFaces>. The first key-point
2690 // will be mapped into <theNodeIndexOnKeyPoint1>-th node
2691 //=======================================================================
2693 bool SMESH_Pattern::Apply (std::set<const SMDS_MeshFace*> theFaces,
2694 const int theNodeIndexOnKeyPoint1,
2695 const bool theReverse)
2697 MESSAGE(" ::Apply(set<MeshFace>) " );
2699 if ( !IsLoaded() ) {
2700 MESSAGE( "Pattern not loaded" );
2701 return setErrorCode( ERR_APPL_NOT_LOADED );
2704 // find points on edges, it fills myNbKeyPntInBoundary
2705 if ( !findBoundaryPoints() )
2708 // check that there are no holes in a pattern
2709 if (myNbKeyPntInBoundary.size() > 1 ) {
2710 return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
2714 myElemXYZIDs.clear();
2715 myXYZIdToNodeMap.clear();
2718 myXYZ.resize( myPoints.size() * theFaces.size(), undefinedXYZ() );
2719 myElements.reserve( theFaces.size() );
2721 // to find point index
2722 map< TPoint*, int > pointIndex;
2723 for ( int i = 0; i < myPoints.size(); i++ )
2724 pointIndex.insert( make_pair( & myPoints[ i ], i ));
2726 // to merge nodes on edges of the elements being refined
2727 typedef set<const SMDS_MeshNode*> TLink;
2728 map< TLink, list< list< int > > > linkPointIndListMap;
2729 map< int, list< list< int >* > > reverseConnectivity;
2731 int ind1 = 0; // lowest point index for a face
2733 // apply to each face in theFaces set
2734 set<const SMDS_MeshFace*>::iterator face = theFaces.begin();
2735 for ( ; face != theFaces.end(); ++face )
2737 if ( !Apply( *face, theNodeIndexOnKeyPoint1, theReverse )) {
2738 MESSAGE( "Failed on " << *face );
2741 myElements.push_back( *face );
2743 // store computed points belonging to elements
2744 list< list< int > >::iterator ll = myElemPointIDs.begin();
2745 for ( ; ll != myElemPointIDs.end(); ++ll )
2747 myElemXYZIDs.push_back();
2748 list< int >& xyzIds = myElemXYZIDs.back();
2749 list< int >& pIds = *ll;
2750 for ( list<int>::iterator id = pIds.begin(); id != pIds.end(); id++ ) {
2751 int pIndex = *id + ind1;
2752 xyzIds.push_back( pIndex );
2753 myXYZ[ pIndex ] = myPoints[ *id ].myXYZ.XYZ();
2754 reverseConnectivity[ pIndex ].push_back( & xyzIds );
2757 // put points on links to linkPointIndListMap
2758 int nbNodes = (*face)->NbNodes(), eID = nbNodes + 1;
2759 for ( int i = 0; i < nbNodes; i++ )
2761 const SMDS_MeshNode* n1 = myOrderedNodes[ i ];
2762 const SMDS_MeshNode* n2 = myOrderedNodes[ i + 1 == nbNodes ? 0 : i + 1 ];
2763 // make a link of node pointers
2767 // add the link to the map
2768 list< list< int > >& groups = linkPointIndListMap[ link ];
2770 list< int >& indList = groups.back();
2771 list< TPoint* > & linkPoints = getShapePoints( eID++ );
2772 list< TPoint* >::iterator p = linkPoints.begin();
2773 // map the first link point to n1
2774 myXYZIdToNodeMap[ pointIndex[ *p ] + ind1 ] = n1;
2775 // add points to the map excluding the end points
2776 for ( p++; *p != linkPoints.back(); p++ )
2777 indList.push_back( pointIndex[ *p ] + ind1 );
2779 ind1 += myPoints.size();
2782 mergePoints( linkPointIndListMap, reverseConnectivity );
2784 return !myElemXYZIDs.empty();
2787 //=======================================================================
2789 //purpose : Compute nodes coordinates applying
2790 // the loaded pattern to <theVolumes>. The (0,0,0) key-point
2791 // will be mapped into <theNode000Index>-th node. The
2792 // (0,0,1) key-point will be mapped into <theNode000Index>-th
2794 //=======================================================================
2796 bool SMESH_Pattern::Apply (std::set<const SMDS_MeshVolume*> theVolumes,
2797 const int theNode000Index,
2798 const int theNode001Index)
2800 MESSAGE(" ::Apply(set<MeshVolumes>) " );
2802 if ( !IsLoaded() ) {
2803 MESSAGE( "Pattern not loaded" );
2804 return setErrorCode( ERR_APPL_NOT_LOADED );
2807 // bind ID to points
2808 if ( !findBoundaryPoints() )
2811 // check that there are no holes in a pattern
2812 if (myNbKeyPntInBoundary.size() > 1 ) {
2813 return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
2817 myElemXYZIDs.clear();
2818 myXYZIdToNodeMap.clear();
2821 myXYZ.resize( myPoints.size() * theVolumes.size(), undefinedXYZ() );
2822 myElements.reserve( theVolumes.size() );
2824 // to find point index
2825 map< TPoint*, int > pointIndex;
2826 for ( int i = 0; i < myPoints.size(); i++ )
2827 pointIndex.insert( make_pair( & myPoints[ i ], i ));
2829 // to merge nodes on edges and faces of the elements being refined
2830 map< TNodeSet, list< list< int > > > subPointIndListMap;
2831 map< int, list< list< int >* > > reverseConnectivity;
2833 int ind1 = 0; // lowest point index for an element
2835 // apply to each element in theVolumes set
2836 set<const SMDS_MeshVolume*>::iterator vol = theVolumes.begin();
2837 for ( ; vol != theVolumes.end(); ++vol )
2839 if ( !Apply( *vol, theNode000Index, theNode001Index )) {
2840 MESSAGE( "Failed on " << *vol );
2843 myElements.push_back( *vol );
2845 // store computed points belonging to elements
2846 list< list< int > >::iterator ll = myElemPointIDs.begin();
2847 for ( ; ll != myElemPointIDs.end(); ++ll )
2849 myElemXYZIDs.push_back();
2850 list< int >& xyzIds = myElemXYZIDs.back();
2851 list< int >& pIds = *ll;
2852 for ( list<int>::iterator id = pIds.begin(); id != pIds.end(); id++ ) {
2853 int pIndex = *id + ind1;
2854 xyzIds.push_back( pIndex );
2855 myXYZ[ pIndex ] = myPoints[ *id ].myXYZ.XYZ();
2856 reverseConnectivity[ pIndex ].push_back( & xyzIds );
2859 // put points on edges and faces to subPointIndListMap
2860 for ( int Id = SMESH_Block::ID_V000; Id <= SMESH_Block::ID_F1yz; Id++ )
2862 // make a set of sub-points
2864 vector< int > subIDs;
2865 if ( SMESH_Block::IsVertexID( Id )) {
2866 // use nodes of refined volumes for merge
2868 else if ( SMESH_Block::IsEdgeID( Id )) {
2869 SMESH_Block::GetEdgeVertexIDs( Id, subIDs );
2870 subNodes.insert( myOrderedNodes[ subIDs.front() - 1 ]);
2871 subNodes.insert( myOrderedNodes[ subIDs.back() - 1 ]);
2874 SMESH_Block::GetFaceEdgesIDs( Id, subIDs );
2875 int e1 = subIDs[ 0 ], e2 = subIDs[ 1 ];
2876 SMESH_Block::GetEdgeVertexIDs( e1, subIDs );
2877 subNodes.insert( myOrderedNodes[ subIDs.front() - 1 ]);
2878 subNodes.insert( myOrderedNodes[ subIDs.back() - 1 ]);
2879 SMESH_Block::GetEdgeVertexIDs( e2, subIDs );
2880 subNodes.insert( myOrderedNodes[ subIDs.front() - 1 ]);
2881 subNodes.insert( myOrderedNodes[ subIDs.back() - 1 ]);
2883 list< list< int > >& groups = subPointIndListMap[ subNodes ];
2885 list< int >& indList = groups.back();
2887 list< TPoint* > & points = getShapePoints( Id );
2888 list< TPoint* >::iterator p = points.begin();
2889 if ( subNodes.empty() ) // vertex case
2890 myXYZIdToNodeMap[ pointIndex[ *p ] + ind1 ] = myOrderedNodes[ Id - 1 ];
2892 for ( ; p != points.end(); p++ )
2893 indList.push_back( pointIndex[ *p ] + ind1 );
2895 ind1 += myPoints.size();
2898 mergePoints( subPointIndListMap, reverseConnectivity );
2900 return !myElemXYZIDs.empty();
2903 //=======================================================================
2905 //purpose : Create a pattern from the mesh built on <theBlock>
2906 //=======================================================================
2908 bool SMESH_Pattern::Load (SMESH_Mesh* theMesh,
2909 const TopoDS_Shell& theBlock)
2911 MESSAGE(" ::Load(volume) " );
2914 SMESHDS_Mesh * aMeshDS = theMesh->GetMeshDS();
2916 // load shapes in myShapeIDMap
2918 TopoDS_Vertex v1, v2;
2919 if ( !block.LoadBlockShapes( theBlock, v1, v2, myShapeIDMap ))
2920 return setErrorCode( ERR_LOADV_BAD_SHAPE );
2923 int nbNodes = 0, shapeID;
2924 for ( shapeID = 1; shapeID <= myShapeIDMap.Extent(); shapeID++ )
2926 const TopoDS_Shape& S = myShapeIDMap( shapeID );
2927 SMESHDS_SubMesh * aSubMesh = aMeshDS->MeshElements( S );
2929 nbNodes += aSubMesh->NbNodes();
2931 myPoints.resize( nbNodes );
2933 // load U of points on edges
2934 TNodePointIDMap nodePointIDMap;
2936 for ( shapeID = 1; shapeID <= myShapeIDMap.Extent(); shapeID++ )
2938 const TopoDS_Shape& S = myShapeIDMap( shapeID );
2939 list< TPoint* > & shapePoints = getShapePoints( shapeID );
2940 SMESHDS_SubMesh * aSubMesh = aMeshDS->MeshElements( S );
2941 if ( ! aSubMesh ) continue;
2942 SMDS_NodeIteratorPtr nIt = aSubMesh->GetNodes();
2943 if ( !nIt->more() ) continue;
2945 // store a node and a point
2946 while ( nIt->more() ) {
2947 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nIt->next() );
2948 nodePointIDMap.insert( make_pair( node, iPoint ));
2949 if ( block.IsVertexID( shapeID ))
2950 myKeyPointIDs.push_back( iPoint );
2951 TPoint* p = & myPoints[ iPoint++ ];
2952 shapePoints.push_back( p );
2953 p->myXYZ.SetCoord( node->X(), node->Y(), node->Z() );
2954 p->myInitXYZ.SetCoord( 0,0,0 );
2956 list< TPoint* >::iterator pIt = shapePoints.begin();
2959 switch ( S.ShapeType() )
2964 for ( ; pIt != shapePoints.end(); pIt++ ) {
2965 double * coef = block.GetShapeCoef( shapeID );
2966 for ( int iCoord = 1; iCoord <= 3; iCoord++ )
2967 if ( coef[ iCoord - 1] > 0 )
2968 (*pIt)->myInitXYZ.SetCoord( iCoord, 1. );
2970 if ( S.ShapeType() == TopAbs_VERTEX )
2973 const TopoDS_Edge& edge = TopoDS::Edge( S );
2975 BRep_Tool::Range( edge, f, l );
2976 int iCoord = SMESH_Block::GetCoordIndOnEdge( shapeID );
2977 bool isForward = SMESH_Block::IsForwardEdge( edge, myShapeIDMap );
2978 pIt = shapePoints.begin();
2979 nIt = aSubMesh->GetNodes();
2980 for ( ; nIt->more(); pIt++ )
2982 const SMDS_MeshNode* node =
2983 static_cast<const SMDS_MeshNode*>( nIt->next() );
2984 const SMDS_EdgePosition* epos =
2985 static_cast<const SMDS_EdgePosition*>(node->GetPosition().get());
2986 double u = ( epos->GetUParameter() - f ) / ( l - f );
2987 (*pIt)->myInitXYZ.SetCoord( iCoord, isForward ? u : 1 - u );
2992 for ( ; pIt != shapePoints.end(); pIt++ )
2994 if ( !block.ComputeParameters( (*pIt)->myXYZ, (*pIt)->myInitXYZ, shapeID )) {
2995 MESSAGE( "!block.ComputeParameters()" );
2996 return setErrorCode( ERR_LOADV_COMPUTE_PARAMS );
3000 } // loop on block sub-shapes
3004 SMESHDS_SubMesh * aSubMesh = aMeshDS->MeshElements( theBlock );
3007 SMDS_ElemIteratorPtr elemIt = aSubMesh->GetElements();
3008 while ( elemIt->more() ) {
3009 SMDS_ElemIteratorPtr nIt = elemIt->next()->nodesIterator();
3010 myElemPointIDs.push_back( list< int >() );
3011 list< int >& elemPoints = myElemPointIDs.back();
3012 while ( nIt->more() )
3013 elemPoints.push_back( nodePointIDMap[ nIt->next() ]);
3017 myIsBoundaryPointsFound = true;
3019 return setErrorCode( ERR_OK );
3022 //=======================================================================
3024 //purpose : Compute nodes coordinates applying
3025 // the loaded pattern to <theBlock>. The (0,0,0) key-point
3026 // will be mapped into <theVertex000>. The (0,0,1)
3027 // fifth key-point will be mapped into <theVertex001>.
3028 //=======================================================================
3030 bool SMESH_Pattern::Apply (const TopoDS_Shell& theBlock,
3031 const TopoDS_Vertex& theVertex000,
3032 const TopoDS_Vertex& theVertex001)
3034 MESSAGE(" ::Apply(volume) " );
3036 if (!findBoundaryPoints() || // bind ID to points
3037 !setShapeToMesh( theBlock )) // check theBlock is a suitable shape
3040 SMESH_Block block; // bind ID to shape
3041 if (!block.LoadBlockShapes( theBlock, theVertex000, theVertex001, myShapeIDMap ))
3042 return setErrorCode( ERR_APPLV_BAD_SHAPE );
3044 // compute XYZ of points on shapes
3046 for ( int shapeID = 1; shapeID <= myShapeIDMap.Extent(); shapeID++ )
3048 list< TPoint* > & shapePoints = getShapePoints( shapeID );
3049 list< TPoint* >::iterator pIt = shapePoints.begin();
3050 const TopoDS_Shape& S = myShapeIDMap( shapeID );
3051 switch ( S.ShapeType() )
3053 case TopAbs_VERTEX: {
3055 for ( ; pIt != shapePoints.end(); pIt++ )
3056 block.VertexPoint( shapeID, (*pIt)->myXYZ.ChangeCoord() );
3061 for ( ; pIt != shapePoints.end(); pIt++ )
3062 block.EdgePoint( shapeID, (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
3067 for ( ; pIt != shapePoints.end(); pIt++ )
3068 block.FacePoint( shapeID, (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
3072 for ( ; pIt != shapePoints.end(); pIt++ )
3073 block.ShellPoint( (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
3075 } // loop on block sub-shapes
3077 myIsComputed = true;
3079 return setErrorCode( ERR_OK );
3082 //=======================================================================
3084 //purpose : Compute nodes coordinates applying
3085 // the loaded pattern to <theVolume>. The (0,0,0) key-point
3086 // will be mapped into <theNode000Index>-th node. The
3087 // (0,0,1) key-point will be mapped into <theNode000Index>-th
3089 //=======================================================================
3091 bool SMESH_Pattern::Apply (const SMDS_MeshVolume* theVolume,
3092 const int theNode000Index,
3093 const int theNode001Index)
3095 MESSAGE(" ::Apply(MeshVolume) " );
3097 if (!findBoundaryPoints()) // bind ID to points
3100 SMESH_Block block; // bind ID to shape
3101 if (!block.LoadMeshBlock( theVolume, theNode000Index, theNode001Index, myOrderedNodes ))
3102 return setErrorCode( ERR_APPLV_BAD_SHAPE );
3103 // compute XYZ of points on shapes
3105 for ( int ID = SMESH_Block::ID_V000; ID <= SMESH_Block::ID_Shell; ID++ )
3107 list< TPoint* > & shapePoints = getShapePoints( ID );
3108 list< TPoint* >::iterator pIt = shapePoints.begin();
3110 if ( block.IsVertexID( ID ))
3111 for ( ; pIt != shapePoints.end(); pIt++ ) {
3112 block.VertexPoint( ID, (*pIt)->myXYZ.ChangeCoord() );
3114 else if ( block.IsEdgeID( ID ))
3115 for ( ; pIt != shapePoints.end(); pIt++ ) {
3116 block.EdgePoint( ID, (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
3118 else if ( block.IsFaceID( ID ))
3119 for ( ; pIt != shapePoints.end(); pIt++ ) {
3120 block.FacePoint( ID, (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
3123 for ( ; pIt != shapePoints.end(); pIt++ )
3124 block.ShellPoint( (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
3125 } // loop on block sub-shapes
3127 myIsComputed = true;
3129 return setErrorCode( ERR_OK );
3132 //=======================================================================
3133 //function : MakeMesh
3134 //purpose : Create nodes and elements in <theMesh> using nodes
3135 // coordinates computed by either of Apply...() methods
3136 //=======================================================================
3138 bool SMESH_Pattern::MakeMesh(SMESH_Mesh* theMesh)
3140 MESSAGE(" ::MakeMesh() " );
3141 if ( !myIsComputed )
3142 return setErrorCode( ERR_MAKEM_NOT_COMPUTED );
3144 SMESHDS_Mesh* aMeshDS = theMesh->GetMeshDS();
3145 SMESH_MeshEditor editor( theMesh );
3147 // clear elements and nodes existing on myShape
3149 if ( !myShape.IsNull() )
3151 SMESH_subMesh * aSubMesh = theMesh->GetSubMeshContaining( myShape );
3152 SMESHDS_SubMesh * aSubMeshDS = aMeshDS->MeshElements( myShape );
3154 aSubMesh->ComputeStateEngine( SMESH_subMesh::CLEAN );
3155 else if ( aSubMeshDS )
3157 SMDS_ElemIteratorPtr eIt = aSubMeshDS->GetElements();
3158 while ( eIt->more() )
3159 aMeshDS->RemoveElement( eIt->next() );
3160 SMDS_NodeIteratorPtr nIt = aSubMeshDS->GetNodes();
3161 while ( nIt->more() )
3162 aMeshDS->RemoveNode( static_cast<const SMDS_MeshNode*>( nIt->next() ));
3166 bool onMeshElements = ( !myElements.empty() );
3168 // loop on sub-shapes of myShape: create nodes and build point-node map
3170 vector< const SMDS_MeshNode* > nodesVector;
3171 map< TPoint*, const SMDS_MeshNode* > pointNodeMap;
3172 if ( onMeshElements )
3174 nodesVector.resize( myXYZ.size() );
3175 for ( int i = 0; i < myXYZ.size(); ++i ) {
3176 map< int, const SMDS_MeshNode*>::iterator idNode = myXYZIdToNodeMap.find( i );
3177 if ( idNode != myXYZIdToNodeMap.end() )
3178 nodesVector[ i ] = idNode->second;
3179 else if ( isDefined( myXYZ[ i ] ))
3180 nodesVector[ i ] = aMeshDS->AddNode (myXYZ[ i ].X(),
3187 map< int, list< TPoint* > >::iterator idPointIt = myShapeIDToPointsMap.begin();
3188 for ( ; idPointIt != myShapeIDToPointsMap.end(); idPointIt++ )
3191 SMESHDS_SubMesh * subMeshDS = 0;
3192 if ( !myShapeIDMap.IsEmpty() ) {
3193 S = myShapeIDMap( idPointIt->first );
3194 subMeshDS = aMeshDS->MeshElements( S );
3196 list< TPoint* > & points = idPointIt->second;
3197 list< TPoint* >::iterator pIt = points.begin();
3198 for ( ; pIt != points.end(); pIt++ )
3200 TPoint* point = *pIt;
3201 if ( pointNodeMap.find( point ) != pointNodeMap.end() )
3203 SMDS_MeshNode* node = aMeshDS->AddNode (point->myXYZ.X(),
3206 pointNodeMap.insert( make_pair( point, node ));
3208 switch ( S.ShapeType() ) {
3209 case TopAbs_VERTEX: {
3210 aMeshDS->SetNodeOnVertex( node, TopoDS::Vertex( S ));
3214 aMeshDS->SetNodeOnEdge( node, TopoDS::Edge( S ));
3215 SMDS_EdgePosition* epos =
3216 dynamic_cast<SMDS_EdgePosition *>(node->GetPosition().get());
3217 epos->SetUParameter( point->myU );
3221 aMeshDS->SetNodeOnFace( node, TopoDS::Face( S ));
3222 SMDS_FacePosition* pos =
3223 dynamic_cast<SMDS_FacePosition *>(node->GetPosition().get());
3224 pos->SetUParameter( point->myUV.X() );
3225 pos->SetVParameter( point->myUV.Y() );
3229 aMeshDS->SetNodeInVolume( node, TopoDS::Shell( S ));
3238 // shapes and groups myElements are on
3239 vector< int > shapeIDs;
3240 vector< list< SMESHDS_Group* > > groups;
3241 if ( onMeshElements )
3243 shapeIDs.resize( myElements.size() );
3244 groups.resize( myElements.size() );
3245 const set<SMESHDS_GroupBase*>& allGroups = aMeshDS->GetGroups();
3246 set<SMESHDS_GroupBase*>::const_iterator grIt;
3247 for ( int i = 0; i < myElements.size(); i++ )
3249 shapeIDs[ i ] = editor.FindShape( myElements[ i ] );
3250 for ( grIt = allGroups.begin(); grIt != allGroups.end(); grIt++ ) {
3251 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
3252 if ( group && group->SMDSGroup().Contains( myElements[ i ] ))
3253 groups[ i ].push_back( group );
3257 int nbElems = myElemPointIDs.size(); // nb elements in a pattern
3259 list<list< int > >::iterator epIt, epEnd;
3260 if ( onMeshElements ) {
3261 epIt = myElemXYZIDs.begin();
3262 epEnd = myElemXYZIDs.end();
3265 epIt = myElemPointIDs.begin();
3266 epEnd = myElemPointIDs.end();
3268 for ( int iElem = 0; epIt != epEnd; epIt++, iElem++ )
3270 list< int > & elemPoints = *epIt;
3272 const SMDS_MeshNode* nodes[ 8 ];
3273 list< int >::iterator iIt = elemPoints.begin();
3275 for ( nbNodes = 0; iIt != elemPoints.end(); iIt++ ) {
3276 if ( onMeshElements )
3277 nodes[ nbNodes++ ] = nodesVector[ *iIt ];
3279 nodes[ nbNodes++ ] = pointNodeMap[ & myPoints[ *iIt ]];
3282 const SMDS_MeshElement* elem = 0;
3284 switch ( nbNodes ) {
3286 elem = aMeshDS->AddFace( nodes[0], nodes[1], nodes[2] ); break;
3288 elem = aMeshDS->AddFace( nodes[0], nodes[1], nodes[2], nodes[3] ); break;
3290 ASSERT( nbNodes < 8 );
3294 switch ( nbNodes ) {
3296 elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3] ); break;
3298 elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3],
3301 elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3],
3302 nodes[4], nodes[5] ); break;
3304 elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3],
3305 nodes[4], nodes[5], nodes[6], nodes[7] ); break;
3307 ASSERT( nbNodes < 8 );
3310 // set element on a shape
3311 if ( elem && onMeshElements ) // applied to mesh elements
3313 int elemIndex = iElem / nbElems;
3314 int shapeID = shapeIDs[ elemIndex ];
3315 if ( shapeID > 0 ) {
3316 aMeshDS->SetMeshElementOnShape( elem, shapeID );
3317 // set nodes on a shape
3318 TopoDS_Shape S = aMeshDS->IndexToShape( shapeID );
3319 if ( S.ShapeType() == TopAbs_SOLID ) {
3320 TopoDS_Iterator shellIt( S );
3321 if ( shellIt.More() )
3322 shapeID = aMeshDS->ShapeToIndex( shellIt.Value() );
3324 SMDS_ElemIteratorPtr noIt = elem->nodesIterator();
3325 while ( noIt->more() ) {
3326 SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>
3327 ( static_cast<const SMDS_MeshNode*>( noIt->next() ));
3328 if ( !node->GetPosition() || !node->GetPosition()->GetShapeId() ) {
3329 if ( S.ShapeType() == TopAbs_FACE )
3330 aMeshDS->SetNodeOnFace( node, shapeID );
3332 aMeshDS->SetNodeInVolume( node, shapeID );
3336 // add elem in groups
3337 list< SMESHDS_Group* >::iterator g = groups[ elemIndex ].begin();
3338 for ( ; g != groups[ elemIndex ].end(); ++g )
3339 (*g)->SMDSGroup().Add( elem );
3341 if ( elem && !myShape.IsNull() ) // applied to shape
3342 aMeshDS->SetMeshElementOnShape( elem, myShape );
3345 // make that SMESH_subMesh::_computeState = COMPUTE_OK
3346 // so that operations with hypotheses will erase the mesh being built
3348 SMESH_subMesh * subMesh;
3349 if ( !myShape.IsNull() ) {
3350 subMesh = theMesh->GetSubMeshContaining( myShape );
3352 subMesh->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
3354 if ( onMeshElements ) {
3355 list< int > elemIDs;
3356 for ( int i = 0; i < myElements.size(); i++ )
3358 int shapeID = shapeIDs[ i ];
3359 if ( shapeID > 0 ) {
3360 TopoDS_Shape S = aMeshDS->IndexToShape( shapeID );
3361 subMesh = theMesh->GetSubMeshContaining( S );
3363 subMesh->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
3365 elemIDs.push_back( myElements[ i ]->GetID() );
3367 // remove refined elements
3368 editor.Remove( elemIDs, false );
3371 return setErrorCode( ERR_OK );
3375 //=======================================================================
3376 //function : arrangeBoundaries
3377 //purpose : if there are several wires, arrange boundaryPoints so that
3378 // the outer wire goes first and fix inner wires orientation
3379 // update myKeyPointIDs to correspond to the order of key-points
3380 // in boundaries; sort internal boundaries by the nb of key-points
3381 //=======================================================================
3383 void SMESH_Pattern::arrangeBoundaries (list< list< TPoint* > >& boundaryList)
3385 typedef list< list< TPoint* > >::iterator TListOfListIt;
3386 TListOfListIt bndIt;
3387 list< TPoint* >::iterator pIt;
3389 int nbBoundaries = boundaryList.size();
3390 if ( nbBoundaries > 1 )
3392 // sort boundaries by nb of key-points
3393 if ( nbBoundaries > 2 )
3395 // move boundaries in tmp list
3396 list< list< TPoint* > > tmpList;
3397 tmpList.splice( tmpList.begin(), boundaryList, boundaryList.begin(), boundaryList.end());
3398 // make a map nb-key-points to boundary-position-in-tmpList,
3399 // boundary-positions get ordered in it
3400 typedef map< int, TListOfListIt > TNbKpBndPosMap;
3401 TNbKpBndPosMap nbKpBndPosMap;
3402 bndIt = tmpList.begin();
3403 list< int >::iterator nbKpIt = myNbKeyPntInBoundary.begin();
3404 for ( ; nbKpIt != myNbKeyPntInBoundary.end(); nbKpIt++, bndIt++ ) {
3405 int nb = *nbKpIt * nbBoundaries;
3406 while ( nbKpBndPosMap.find ( nb ) != nbKpBndPosMap.end() )
3408 nbKpBndPosMap.insert( TNbKpBndPosMap::value_type( nb, bndIt ));
3410 // move boundaries back to boundaryList
3411 TNbKpBndPosMap::iterator nbKpBndPosIt = nbKpBndPosMap.begin();
3412 for ( ; nbKpBndPosIt != nbKpBndPosMap.end(); nbKpBndPosIt++ ) {
3413 TListOfListIt & bndPos2 = (*nbKpBndPosIt).second;
3414 TListOfListIt bndPos1 = bndPos2++;
3415 boundaryList.splice( boundaryList.end(), tmpList, bndPos1, bndPos2 );
3419 // Look for the outer boundary: the one with the point with the least X
3420 double leastX = DBL_MAX;
3421 TListOfListIt outerBndPos;
3422 for ( bndIt = boundaryList.begin(); bndIt != boundaryList.end(); bndIt++ )
3424 list< TPoint* >& boundary = (*bndIt);
3425 for ( pIt = boundary.begin(); pIt != boundary.end(); pIt++)
3427 TPoint* point = *pIt;
3428 if ( point->myInitXYZ.X() < leastX ) {
3429 leastX = point->myInitXYZ.X();
3430 outerBndPos = bndIt;
3435 if ( outerBndPos != boundaryList.begin() )
3436 boundaryList.splice( boundaryList.begin(), boundaryList, outerBndPos, ++outerBndPos );
3438 } // if nbBoundaries > 1
3440 // Check boundaries orientation and re-fill myKeyPointIDs
3442 set< TPoint* > keyPointSet;
3443 list< int >::iterator kpIt = myKeyPointIDs.begin();
3444 for ( ; kpIt != myKeyPointIDs.end(); kpIt++ )
3445 keyPointSet.insert( & myPoints[ *kpIt ]);
3446 myKeyPointIDs.clear();
3448 // update myNbKeyPntInBoundary also
3449 list< int >::iterator nbKpIt = myNbKeyPntInBoundary.begin();
3451 for ( bndIt = boundaryList.begin(); bndIt != boundaryList.end(); bndIt++, nbKpIt++ )
3453 // find the point with the least X
3454 double leastX = DBL_MAX;
3455 list< TPoint* >::iterator xpIt;
3456 list< TPoint* >& boundary = (*bndIt);
3457 for ( pIt = boundary.begin(); pIt != boundary.end(); pIt++)
3459 TPoint* point = *pIt;
3460 if ( point->myInitXYZ.X() < leastX ) {
3461 leastX = point->myInitXYZ.X();
3465 // find points next to the point with the least X
3466 TPoint* p = *xpIt, *pPrev, *pNext;
3467 if ( p == boundary.front() )
3468 pPrev = *(++boundary.rbegin());
3474 if ( p == boundary.back() )
3475 pNext = *(++boundary.begin());
3480 // vectors of boundary direction near <p>
3481 gp_Vec2d v1( pPrev->myInitUV, p->myInitUV ), v2( p->myInitUV, pNext->myInitUV );
3482 double sqMag1 = v1.SquareMagnitude(), sqMag2 = v2.SquareMagnitude();
3483 if ( sqMag1 > DBL_MIN && sqMag2 > DBL_MIN ) {
3484 double yPrev = v1.Y() / sqrt( sqMag1 );
3485 double yNext = v2.Y() / sqrt( sqMag2 );
3486 double sumY = yPrev + yNext;
3488 if ( bndIt == boundaryList.begin() ) // outer boundary
3496 // Put key-point IDs of a well-oriented boundary in myKeyPointIDs
3497 (*nbKpIt) = 0; // count nb of key-points again
3498 pIt = boundary.begin();
3499 for ( ; pIt != boundary.end(); pIt++)
3501 TPoint* point = *pIt;
3502 if ( keyPointSet.find( point ) == keyPointSet.end() )
3504 // find an index of a keypoint
3506 vector< TPoint >::const_iterator pVecIt = myPoints.begin();
3507 for ( ; pVecIt != myPoints.end(); pVecIt++, index++ )
3508 if ( &(*pVecIt) == point )
3510 myKeyPointIDs.push_back( index );
3513 myKeyPointIDs.pop_back(); // remove the first key-point from the back
3516 } // loop on a list of boundaries
3518 ASSERT( myKeyPointIDs.size() == keyPointSet.size() );
3521 //=======================================================================
3522 //function : findBoundaryPoints
3523 //purpose : if loaded from file, find points to map on edges and faces and
3524 // compute their parameters
3525 //=======================================================================
3527 bool SMESH_Pattern::findBoundaryPoints()
3529 if ( myIsBoundaryPointsFound ) return true;
3531 MESSAGE(" findBoundaryPoints() ");
3535 set< TPoint* > pointsInElems;
3537 // Find free links of elements:
3538 // put links of all elements in a set and remove links encountered twice
3540 typedef pair< TPoint*, TPoint*> TLink;
3541 set< TLink > linkSet;
3542 list<list< int > >::iterator epIt = myElemPointIDs.begin();
3543 for ( ; epIt != myElemPointIDs.end(); epIt++ )
3545 list< int > & elemPoints = *epIt;
3546 list< int >::iterator pIt = elemPoints.begin();
3547 int prevP = elemPoints.back();
3548 for ( ; pIt != elemPoints.end(); pIt++ ) {
3549 TPoint* p1 = & myPoints[ prevP ];
3550 TPoint* p2 = & myPoints[ *pIt ];
3551 TLink link(( p1 < p2 ? p1 : p2 ), ( p1 < p2 ? p2 : p1 ));
3552 ASSERT( link.first != link.second );
3553 pair<set< TLink >::iterator,bool> itUniq = linkSet.insert( link );
3554 if ( !itUniq.second )
3555 linkSet.erase( itUniq.first );
3558 pointsInElems.insert( p1 );
3561 // Now linkSet contains only free links,
3562 // find the points order that they have in boundaries
3564 // 1. make a map of key-points
3565 set< TPoint* > keyPointSet;
3566 list< int >::iterator kpIt = myKeyPointIDs.begin();
3567 for ( ; kpIt != myKeyPointIDs.end(); kpIt++ )
3568 keyPointSet.insert( & myPoints[ *kpIt ]);
3570 // 2. chain up boundary points
3571 list< list< TPoint* > > boundaryList;
3572 boundaryList.push_back( list< TPoint* >() );
3573 list< TPoint* > * boundary = & boundaryList.back();
3575 TPoint *point1, *point2, *keypoint1;
3576 kpIt = myKeyPointIDs.begin();
3577 point1 = keypoint1 = & myPoints[ *kpIt++ ];
3578 // loop on free links: look for the next point
3580 set< TLink >::iterator lIt = linkSet.begin();
3581 while ( lIt != linkSet.end() )
3583 if ( (*lIt).first == point1 )
3584 point2 = (*lIt).second;
3585 else if ( (*lIt).second == point1 )
3586 point2 = (*lIt).first;
3591 linkSet.erase( lIt );
3592 lIt = linkSet.begin();
3594 if ( keyPointSet.find( point2 ) == keyPointSet.end() ) // not a key-point
3596 boundary->push_back( point2 );
3598 else // a key-point found
3600 keyPointSet.erase( point2 ); // keyPointSet contains not found key-points only
3602 if ( point2 != keypoint1 ) // its not the boundary end
3604 boundary->push_back( point2 );
3606 else // the boundary end reached
3608 boundary->push_front( keypoint1 );
3609 boundary->push_back( keypoint1 );
3610 myNbKeyPntInBoundary.push_back( iKeyPoint );
3611 if ( keyPointSet.empty() )
3612 break; // all boundaries containing key-points are found
3614 // prepare to search for the next boundary
3615 boundaryList.push_back( list< TPoint* >() );
3616 boundary = & boundaryList.back();
3617 point2 = keypoint1 = (*keyPointSet.begin());
3621 } // loop on the free links set
3623 if ( boundary->empty() ) {
3624 MESSAGE(" a separate key-point");
3625 return setErrorCode( ERR_READ_BAD_KEY_POINT );
3628 // if there are several wires, arrange boundaryPoints so that
3629 // the outer wire goes first and fix inner wires orientation;
3630 // sort myKeyPointIDs to correspond to the order of key-points
3632 arrangeBoundaries( boundaryList );
3634 // Find correspondence shape ID - points,
3635 // compute points parameter on edge
3637 keyPointSet.clear();
3638 for ( kpIt = myKeyPointIDs.begin(); kpIt != myKeyPointIDs.end(); kpIt++ )
3639 keyPointSet.insert( & myPoints[ *kpIt ]);
3641 set< TPoint* > edgePointSet; // to find in-face points
3642 int vertexID = 1; // the first index in TopTools_IndexedMapOfShape
3643 int edgeID = myKeyPointIDs.size() + 1;
3645 list< list< TPoint* > >::iterator bndIt = boundaryList.begin();
3646 for ( ; bndIt != boundaryList.end(); bndIt++ )
3648 boundary = & (*bndIt);
3649 double edgeLength = 0;
3650 list< TPoint* >::iterator pIt = boundary->begin();
3651 getShapePoints( edgeID ).push_back( *pIt );
3652 getShapePoints( vertexID++ ).push_back( *pIt );
3653 for ( pIt++; pIt != boundary->end(); pIt++)
3655 list< TPoint* > & edgePoints = getShapePoints( edgeID );
3656 TPoint* prevP = edgePoints.empty() ? 0 : edgePoints.back();
3657 TPoint* point = *pIt;
3658 edgePointSet.insert( point );
3659 if ( keyPointSet.find( point ) == keyPointSet.end() ) // inside-edge point
3661 edgePoints.push_back( point );
3662 edgeLength += ( point->myInitUV - prevP->myInitUV ).Modulus();
3663 point->myInitU = edgeLength;
3667 // treat points on the edge which ends up: compute U [0,1]
3668 edgePoints.push_back( point );
3669 if ( edgePoints.size() > 2 ) {
3670 edgeLength += ( point->myInitUV - prevP->myInitUV ).Modulus();
3671 list< TPoint* >::iterator epIt = edgePoints.begin();
3672 for ( ; epIt != edgePoints.end(); epIt++ )
3673 (*epIt)->myInitU /= edgeLength;
3675 // begin the next edge treatment
3678 if ( point != boundary->front() ) { // not the first key-point again
3679 getShapePoints( edgeID ).push_back( point );
3680 getShapePoints( vertexID++ ).push_back( point );
3686 // find in-face points
3687 list< TPoint* > & facePoints = getShapePoints( edgeID );
3688 vector< TPoint >::iterator pVecIt = myPoints.begin();
3689 for ( ; pVecIt != myPoints.end(); pVecIt++ ) {
3690 TPoint* point = &(*pVecIt);
3691 if ( edgePointSet.find( point ) == edgePointSet.end() &&
3692 pointsInElems.find( point ) != pointsInElems.end())
3693 facePoints.push_back( point );
3700 // bind points to shapes according to point parameters
3701 vector< TPoint >::iterator pVecIt = myPoints.begin();
3702 for ( int i = 0; pVecIt != myPoints.end(); pVecIt++, i++ ) {
3703 TPoint* point = &(*pVecIt);
3704 int shapeID = SMESH_Block::GetShapeIDByParams( point->myInitXYZ );
3705 getShapePoints( shapeID ).push_back( point );
3706 // detect key-points
3707 if ( SMESH_Block::IsVertexID( shapeID ))
3708 myKeyPointIDs.push_back( i );
3712 myIsBoundaryPointsFound = true;
3713 return myIsBoundaryPointsFound;
3716 //=======================================================================
3718 //purpose : clear fields
3719 //=======================================================================
3721 void SMESH_Pattern::Clear()
3723 myIsComputed = myIsBoundaryPointsFound = false;
3726 myKeyPointIDs.clear();
3727 myElemPointIDs.clear();
3728 myShapeIDToPointsMap.clear();
3729 myShapeIDMap.Clear();
3731 myNbKeyPntInBoundary.clear();
3734 //=======================================================================
3735 //function : setShapeToMesh
3736 //purpose : set a shape to be meshed. Return True if meshing is possible
3737 //=======================================================================
3739 bool SMESH_Pattern::setShapeToMesh(const TopoDS_Shape& theShape)
3741 if ( !IsLoaded() ) {
3742 MESSAGE( "Pattern not loaded" );
3743 return setErrorCode( ERR_APPL_NOT_LOADED );
3746 TopAbs_ShapeEnum aType = theShape.ShapeType();
3747 bool dimOk = ( myIs2D ? aType == TopAbs_FACE : aType == TopAbs_SHELL );
3749 MESSAGE( "Pattern dimention mismatch" );
3750 return setErrorCode( ERR_APPL_BAD_DIMENTION );
3753 // check if a face is closed
3754 int nbNodeOnSeamEdge = 0;
3756 TopoDS_Face face = TopoDS::Face( theShape );
3757 TopExp_Explorer eExp( theShape, TopAbs_EDGE );
3758 for ( ; eExp.More() && nbNodeOnSeamEdge == 0; eExp.Next() )
3759 if ( BRep_Tool::IsClosed( TopoDS::Edge( eExp.Current() ), face ))
3760 nbNodeOnSeamEdge = 2;
3763 // check nb of vertices
3764 TopTools_IndexedMapOfShape vMap;
3765 TopExp::MapShapes( theShape, TopAbs_VERTEX, vMap );
3766 if ( vMap.Extent() + nbNodeOnSeamEdge != myKeyPointIDs.size() ) {
3767 MESSAGE( myKeyPointIDs.size() << " != " << vMap.Extent() );
3768 return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
3771 myShapeIDMap.Clear();
3776 //=======================================================================
3777 //function : GetMappedPoints
3778 //purpose : Return nodes coordinates computed by Apply() method
3779 //=======================================================================
3781 bool SMESH_Pattern::GetMappedPoints ( list< const gp_XYZ * > & thePoints ) const
3784 if ( !myIsComputed )
3787 if ( myElements.empty() ) { // applied to shape
3788 vector< TPoint >::const_iterator pVecIt = myPoints.begin();
3789 for ( ; pVecIt != myPoints.end(); pVecIt++ )
3790 thePoints.push_back( & (*pVecIt).myXYZ.XYZ() );
3792 else { // applied to mesh elements
3793 const gp_XYZ * definedXYZ = & myPoints[ myKeyPointIDs.front() ].myXYZ.XYZ();
3794 vector<gp_XYZ>::const_iterator xyz = myXYZ.begin();
3795 for ( ; xyz != myXYZ.end(); ++xyz )
3796 if ( !isDefined( *xyz ))
3797 thePoints.push_back( definedXYZ );
3799 thePoints.push_back( & (*xyz) );
3801 return !thePoints.empty();
3805 //=======================================================================
3806 //function : GetPoints
3807 //purpose : Return nodes coordinates of the pattern
3808 //=======================================================================
3810 bool SMESH_Pattern::GetPoints ( list< const gp_XYZ * > & thePoints ) const
3817 vector< TPoint >::const_iterator pVecIt = myPoints.begin();
3818 for ( ; pVecIt != myPoints.end(); pVecIt++ )
3819 thePoints.push_back( & (*pVecIt).myInitXYZ );
3821 return ( thePoints.size() > 0 );
3824 //=======================================================================
3825 //function : getShapePoints
3826 //purpose : return list of points located on theShape
3827 //=======================================================================
3829 list< SMESH_Pattern::TPoint* > &
3830 SMESH_Pattern::getShapePoints(const TopoDS_Shape& theShape)
3833 if ( !myShapeIDMap.Contains( theShape ))
3834 aShapeID = myShapeIDMap.Add( theShape );
3836 aShapeID = myShapeIDMap.FindIndex( theShape );
3838 return myShapeIDToPointsMap[ aShapeID ];
3841 //=======================================================================
3842 //function : getShapePoints
3843 //purpose : return list of points located on the shape
3844 //=======================================================================
3846 list< SMESH_Pattern::TPoint* > & SMESH_Pattern::getShapePoints(const int theShapeID)
3848 return myShapeIDToPointsMap[ theShapeID ];
3851 //=======================================================================
3852 //function : DumpPoints
3854 //=======================================================================
3856 void SMESH_Pattern::DumpPoints() const
3859 vector< TPoint >::const_iterator pVecIt = myPoints.begin();
3860 for ( int i = 0; pVecIt != myPoints.end(); pVecIt++, i++ )
3861 cout << i << ": " << *pVecIt;
3865 //=======================================================================
3866 //function : TPoint()
3868 //=======================================================================
3870 SMESH_Pattern::TPoint::TPoint()
3873 myInitXYZ.SetCoord(0,0,0);
3874 myInitUV.SetCoord(0.,0.);
3876 myXYZ.SetCoord(0,0,0);
3877 myUV.SetCoord(0.,0.);
3882 //=======================================================================
3883 //function : operator <<
3885 //=======================================================================
3887 ostream & operator <<(ostream & OS, const SMESH_Pattern::TPoint& p)
3889 gp_XYZ xyz = p.myInitXYZ;
3890 OS << "\tinit( xyz( " << xyz.X() << " " << xyz.Y() << " " << xyz.Z() << " )";
3891 gp_XY xy = p.myInitUV;
3892 OS << " uv( " << xy.X() << " " << xy.Y() << " )";
3893 double u = p.myInitU;
3894 OS << " u( " << u << " )) " << &p << endl;
3895 xyz = p.myXYZ.XYZ();
3896 OS << "\t ( xyz( " << xyz.X() << " " << xyz.Y() << " " << xyz.Z() << " )";
3898 OS << " uv( " << xy.X() << " " << xy.Y() << " )";
3900 OS << " u( " << u << " ))" << endl;