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 // check that face is not closed
566 list<TopoDS_Edge> eList;
567 getOrderedEdges( theFace, bidon, eList, myNbKeyPntInBoundary );
568 list<TopoDS_Edge>::iterator elIt = eList.begin();
569 for ( ; elIt != eList.end() ; elIt++ )
570 if ( BRep_Tool::IsClosed( *elIt , theFace ))
571 return setErrorCode( ERR_LOADF_CLOSED_FACE );
574 Extrema_GenExtPS projector;
575 GeomAdaptor_Surface aSurface( BRep_Tool::Surface( theFace ));
576 if ( theProject || nbElems == 0 )
577 projector.Initialize( aSurface, 20,20, 1e-5,1e-5 );
580 TNodePointIDMap nodePointIDMap;
582 if ( nbElems == 0 || (theProject &&
583 theMesh->IsMainShape( theFace ) &&
584 !isMeshBoundToShape( theMesh )))
586 MESSAGE("Project the whole mesh");
587 // ---------------------------------------------------------------
588 // The case where the whole mesh is projected to theFace
589 // ---------------------------------------------------------------
591 // put nodes of all faces in the nodePointIDMap and fill myElemPointIDs
592 SMDS_FaceIteratorPtr fIt = aMeshDS->facesIterator();
593 while ( fIt->more() )
595 myElemPointIDs.push_back( list< int >() );
596 list< int >& elemPoints = myElemPointIDs.back();
597 SMDS_ElemIteratorPtr nIt = fIt->next()->nodesIterator();
598 while ( nIt->more() )
600 const SMDS_MeshElement* node = nIt->next();
601 TNodePointIDMap::iterator nIdIt = nodePointIDMap.find( node );
602 if ( nIdIt == nodePointIDMap.end() )
604 elemPoints.push_back( iPoint );
605 nodePointIDMap.insert( make_pair( node, iPoint++ ));
608 elemPoints.push_back( (*nIdIt).second );
611 myPoints.resize( iPoint );
613 // project all nodes of 2d elements to theFace
614 TNodePointIDMap::iterator nIdIt = nodePointIDMap.begin();
615 for ( ; nIdIt != nodePointIDMap.end(); nIdIt++ )
617 const SMDS_MeshNode* node =
618 static_cast<const SMDS_MeshNode*>( (*nIdIt).first );
619 TPoint * p = & myPoints[ (*nIdIt).second ];
620 p->myInitUV = project( node, projector );
621 p->myInitXYZ.SetCoord( p->myInitUV.X(), p->myInitUV.Y(), 0 );
623 // find key-points: the points most close to UV of vertices
624 TopExp_Explorer vExp( theFace, TopAbs_VERTEX );
625 set<int> foundIndices;
626 for ( ; vExp.More(); vExp.Next() ) {
627 const TopoDS_Vertex v = TopoDS::Vertex( vExp.Current() );
628 gp_Pnt2d uv = BRep_Tool::Parameters( v, theFace );
629 double minDist = DBL_MAX;
631 vector< TPoint >::const_iterator pVecIt = myPoints.begin();
632 for ( iPoint = 0; pVecIt != myPoints.end(); pVecIt++, iPoint++ ) {
633 double dist = uv.SquareDistance( (*pVecIt).myInitUV );
634 if ( dist < minDist ) {
639 if ( foundIndices.insert( index ).second ) // unique?
640 myKeyPointIDs.push_back( index );
642 myIsBoundaryPointsFound = false;
647 // ---------------------------------------------------------------------
648 // The case where a pattern is being made from the mesh built by mesher
649 // ---------------------------------------------------------------------
651 // Load shapes in the consequent order and count nb of points
654 for ( elIt = eList.begin(); elIt != eList.end(); elIt++ ) {
655 myShapeIDMap.Add( TopExp::FirstVertex( *elIt, true ));
656 SMESHDS_SubMesh * eSubMesh = aMeshDS->MeshElements( *elIt );
658 nbNodes += eSubMesh->NbNodes() + 1;
661 for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
662 myShapeIDMap.Add( *elIt );
664 myShapeIDMap.Add( theFace );
666 myPoints.resize( nbNodes );
668 // Load U of points on edges
670 for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
672 TopoDS_Edge & edge = *elIt;
673 list< TPoint* > & ePoints = getShapePoints( edge );
675 Handle(Geom2d_Curve) C2d;
677 C2d = BRep_Tool::CurveOnSurface( edge, theFace, f, l );
678 bool isForward = ( edge.Orientation() == TopAbs_FORWARD );
680 // the forward key-point
681 TopoDS_Shape v = TopExp::FirstVertex( edge, true );
682 list< TPoint* > & vPoint = getShapePoints( v );
683 if ( vPoint.empty() )
685 SMESHDS_SubMesh * vSubMesh = aMeshDS->MeshElements( v );
686 if ( vSubMesh && vSubMesh->NbNodes() ) {
687 myKeyPointIDs.push_back( iPoint );
688 SMDS_NodeIteratorPtr nIt = vSubMesh->GetNodes();
689 const SMDS_MeshNode* node = nIt->next();
690 nodePointIDMap.insert( make_pair( node, iPoint ));
692 TPoint* keyPoint = &myPoints[ iPoint++ ];
693 vPoint.push_back( keyPoint );
695 keyPoint->myInitUV = project( node, projector );
697 keyPoint->myInitUV = C2d->Value( isForward ? f : l ).XY();
698 keyPoint->myInitXYZ.SetCoord (keyPoint->myInitUV.X(), keyPoint->myInitUV.Y(), 0);
701 if ( !vPoint.empty() )
702 ePoints.push_back( vPoint.front() );
705 SMESHDS_SubMesh * eSubMesh = aMeshDS->MeshElements( edge );
706 if ( eSubMesh && eSubMesh->NbNodes() )
708 // loop on nodes of an edge: sort them by param on edge
709 typedef map < double, const SMDS_MeshNode* > TParamNodeMap;
710 TParamNodeMap paramNodeMap;
711 SMDS_NodeIteratorPtr nIt = eSubMesh->GetNodes();
712 while ( nIt->more() )
714 const SMDS_MeshNode* node =
715 static_cast<const SMDS_MeshNode*>( nIt->next() );
716 const SMDS_EdgePosition* epos =
717 static_cast<const SMDS_EdgePosition*>(node->GetPosition().get());
718 double u = epos->GetUParameter();
719 paramNodeMap.insert( TParamNodeMap::value_type( u, node ));
721 // put U in [0,1] so that the first key-point has U==0
723 TParamNodeMap::iterator unIt = paramNodeMap.begin();
724 TParamNodeMap::reverse_iterator unRIt = paramNodeMap.rbegin();
725 while ( unIt != paramNodeMap.end() )
727 TPoint* p = & myPoints[ iPoint ];
728 ePoints.push_back( p );
729 const SMDS_MeshNode* node = isForward ? (*unIt).second : (*unRIt).second;
730 nodePointIDMap.insert ( make_pair( node, iPoint ));
733 p->myInitUV = project( node, projector );
735 double u = isForward ? (*unIt).first : (*unRIt).first;
736 p->myInitU = isForward ? (( u - f ) / du ) : ( 1.0 - ( u - f ) / du );
737 p->myInitUV = C2d->Value( u ).XY();
739 p->myInitXYZ.SetCoord( p->myInitUV.X(), p->myInitUV.Y(), 0 );
744 // the reverse key-point
745 v = TopExp::LastVertex( edge, true ).Reversed();
746 list< TPoint* > & vPoint2 = getShapePoints( v );
747 if ( vPoint2.empty() )
749 SMESHDS_SubMesh * vSubMesh = aMeshDS->MeshElements( v );
750 if ( vSubMesh && vSubMesh->NbNodes() ) {
751 myKeyPointIDs.push_back( iPoint );
752 SMDS_NodeIteratorPtr nIt = vSubMesh->GetNodes();
753 const SMDS_MeshNode* node = nIt->next();
754 nodePointIDMap.insert( make_pair( node, iPoint ));
756 TPoint* keyPoint = &myPoints[ iPoint++ ];
757 vPoint2.push_back( keyPoint );
759 keyPoint->myInitUV = project( node, projector );
761 keyPoint->myInitUV = C2d->Value( isForward ? l : f ).XY();
762 keyPoint->myInitXYZ.SetCoord( keyPoint->myInitUV.X(), keyPoint->myInitUV.Y(), 0 );
765 if ( !vPoint2.empty() )
766 ePoints.push_back( vPoint2.front() );
768 // compute U of edge-points
771 double totalDist = 0;
772 list< TPoint* >::iterator pIt = ePoints.begin();
773 TPoint* prevP = *pIt;
774 prevP->myInitU = totalDist;
775 for ( pIt++; pIt != ePoints.end(); pIt++ ) {
777 totalDist += ( p->myInitUV - prevP->myInitUV ).Modulus();
778 p->myInitU = totalDist;
781 if ( totalDist > DBL_MIN)
782 for ( pIt = ePoints.begin(); pIt != ePoints.end(); pIt++ ) {
784 p->myInitU /= totalDist;
787 } // loop on edges of a wire
789 // Load in-face points and elements
791 if ( fSubMesh && fSubMesh->NbElements() )
793 list< TPoint* > & fPoints = getShapePoints( theFace );
794 SMDS_NodeIteratorPtr nIt = fSubMesh->GetNodes();
795 while ( nIt->more() )
797 const SMDS_MeshNode* node =
798 static_cast<const SMDS_MeshNode*>( nIt->next() );
799 nodePointIDMap.insert( make_pair( node, iPoint ));
800 TPoint* p = &myPoints[ iPoint++ ];
801 fPoints.push_back( p );
803 p->myInitUV = project( node, projector );
805 const SMDS_FacePosition* pos =
806 static_cast<const SMDS_FacePosition*>(node->GetPosition().get());
807 p->myInitUV.SetCoord( pos->GetUParameter(), pos->GetVParameter() );
809 p->myInitXYZ.SetCoord( p->myInitUV.X(), p->myInitUV.Y(), 0 );
812 SMDS_ElemIteratorPtr elemIt = fSubMesh->GetElements();
813 while ( elemIt->more() ) {
814 SMDS_ElemIteratorPtr nIt = elemIt->next()->nodesIterator();
815 myElemPointIDs.push_back( list< int >() );
816 list< int >& elemPoints = myElemPointIDs.back();
817 while ( nIt->more() )
818 elemPoints.push_back( nodePointIDMap[ nIt->next() ]);
822 myIsBoundaryPointsFound = true;
825 // Assure that U range is proportional to V range
828 vector< TPoint >::iterator pVecIt = myPoints.begin();
829 for ( ; pVecIt != myPoints.end(); pVecIt++ )
830 bndBox.Add( gp_Pnt2d( (*pVecIt).myInitUV ));
831 double minU, minV, maxU, maxV;
832 bndBox.Get( minU, minV, maxU, maxV );
833 double dU = maxU - minU, dV = maxV - minV;
834 if ( dU <= DBL_MIN || dV <= DBL_MIN ) {
836 return setErrorCode( ERR_LOADF_NARROW_FACE );
838 double ratio = dU / dV, maxratio = 3, scale;
840 if ( ratio > maxratio ) {
841 scale = ratio / maxratio;
844 else if ( ratio < 1./maxratio ) {
845 scale = maxratio / ratio;
850 for ( pVecIt = myPoints.begin(); pVecIt != myPoints.end(); pVecIt++ ) {
851 TPoint & p = *pVecIt;
852 p.myInitUV.SetCoord( iCoord, p.myInitUV.Coord( iCoord ) * scale );
853 p.myInitXYZ.SetCoord( p.myInitUV.X(), p.myInitUV.Y(), 0 );
856 if ( myElemPointIDs.empty() ) {
857 MESSAGE( "No elements bound to the face");
858 return setErrorCode( ERR_LOAD_EMPTY_SUBMESH );
861 return setErrorCode( ERR_OK );
864 //=======================================================================
865 //function : computeUVOnEdge
866 //purpose : compute coordinates of points on theEdge
867 //=======================================================================
869 void SMESH_Pattern::computeUVOnEdge (const TopoDS_Edge& theEdge,
870 const list< TPoint* > & ePoints )
872 bool isForward = ( theEdge.Orientation() == TopAbs_FORWARD );
874 Handle(Geom2d_Curve) C2d =
875 BRep_Tool::CurveOnSurface( theEdge, TopoDS::Face( myShape ), f, l );
877 ePoints.back()->myInitU = 1.0;
878 list< TPoint* >::const_iterator pIt = ePoints.begin();
879 for ( pIt++; pIt != ePoints.end(); pIt++ )
881 TPoint* point = *pIt;
883 double du = ( isForward ? point->myInitU : 1 - point->myInitU );
884 point->myU = ( f * ( 1 - du ) + l * du );
886 point->myUV = C2d->Value( point->myU ).XY();
890 //=======================================================================
891 //function : intersectIsolines
893 //=======================================================================
895 static bool intersectIsolines(const gp_XY& uv11, const gp_XY& uv12, const double r1,
896 const gp_XY& uv21, const gp_XY& uv22, const double r2,
900 gp_XY loc1 = uv11 * ( 1 - r1 ) + uv12 * r1;
901 gp_XY loc2 = uv21 * ( 1 - r2 ) + uv22 * r2;
902 resUV = 0.5 * ( loc1 + loc2 );
903 isDeformed = ( loc1 - loc2 ).SquareModulus() > 1e-8;
904 // double len1 = ( uv11 - uv12 ).Modulus();
905 // double len2 = ( uv21 - uv22 ).Modulus();
906 // resUV = loc1 * len2 / ( len1 + len2 ) + loc2 * len1 / ( len1 + len2 );
910 // gp_Lin2d line1( uv11, uv12 - uv11 );
911 // gp_Lin2d line2( uv21, uv22 - uv21 );
912 // double angle = Abs( line1.Angle( line2 ) );
914 // IntAna2d_AnaIntersection inter;
915 // inter.Perform( line1.Normal( loc1 ), line2.Normal( loc2 ) );
916 // if ( inter.IsDone() && inter.NbPoints() == 1 )
918 // gp_Pnt2d interUV = inter.Point(1).Value();
919 // resUV += interUV.XY();
920 // inter.Perform( line1, line2 );
921 // interUV = inter.Point(1).Value();
922 // resUV += interUV.XY();
929 //=======================================================================
930 //function : compUVByIsoIntersection
932 //=======================================================================
934 bool SMESH_Pattern::compUVByIsoIntersection (const list< list< TPoint* > >& theBndPoints,
935 const gp_XY& theInitUV,
937 bool & theIsDeformed )
939 // compute UV by intersection of 2 iso lines
940 //gp_Lin2d isoLine[2];
941 gp_XY uv1[2], uv2[2];
943 const double zero = DBL_MIN;
944 for ( int iIso = 0; iIso < 2; iIso++ )
946 // to build an iso line:
947 // find 2 pairs of consequent edge-points such that the range of their
948 // initial parameters encloses the in-face point initial parameter
949 gp_XY UV[2], initUV[2];
950 int nbUV = 0, iCoord = iIso + 1;
951 double initParam = theInitUV.Coord( iCoord );
953 list< list< TPoint* > >::const_iterator bndIt = theBndPoints.begin();
954 for ( ; bndIt != theBndPoints.end(); bndIt++ )
956 const list< TPoint* > & bndPoints = * bndIt;
957 TPoint* prevP = bndPoints.back(); // this is the first point
958 list< TPoint* >::const_iterator pIt = bndPoints.begin();
959 bool coincPrev = false;
960 // loop on the edge-points
961 for ( ; pIt != bndPoints.end(); pIt++ )
963 double paramDiff = initParam - (*pIt)->myInitUV.Coord( iCoord );
964 double prevParamDiff = initParam - prevP->myInitUV.Coord( iCoord );
965 double sumOfDiff = Abs(prevParamDiff) + Abs(paramDiff);
966 if (!coincPrev && // ignore if initParam coincides with prev point param
967 sumOfDiff > zero && // ignore if both points coincide with initParam
968 prevParamDiff * paramDiff <= zero )
970 // find UV in parametric space of theFace
971 double r = Abs(prevParamDiff) / sumOfDiff;
972 gp_XY uvInit = (*pIt)->myInitUV * r + prevP->myInitUV * ( 1 - r );
975 // throw away uv most distant from <theInitUV>
976 gp_XY vec0 = initUV[0] - theInitUV;
977 gp_XY vec1 = initUV[1] - theInitUV;
978 gp_XY vec = uvInit - theInitUV;
979 bool isBetween = ( vec0 * vec1 < 0 ); // is theInitUV between initUV[0] and initUV[1]
980 double dist0 = vec0.SquareModulus();
981 double dist1 = vec1.SquareModulus();
982 double dist = vec .SquareModulus();
983 if ( !isBetween || dist < dist0 || dist < dist1 ) {
984 i = ( dist0 < dist1 ? 1 : 0 );
985 if ( isBetween && vec.Dot( i ? vec1 : vec0 ) < 0 )
986 i = 3; // theInitUV must remain between
990 initUV[ i ] = uvInit;
991 UV[ i ] = (*pIt)->myUV * r + prevP->myUV * ( 1 - r );
993 coincPrev = ( Abs(paramDiff) <= zero );
1000 if ( nbUV < 2 || (UV[0]-UV[1]).SquareModulus() <= DBL_MIN*DBL_MIN ) {
1001 MESSAGE(" consequent edge-points not found, nb UV found: " << nbUV <<
1002 ", for point: " << theInitUV.X() <<" " << theInitUV.Y() );
1003 return setErrorCode( ERR_APPLF_BAD_TOPOLOGY );
1005 // an iso line should be normal to UV[0] - UV[1] direction
1006 // and be located at the same relative distance as from initial ends
1007 //gp_Lin2d iso( UV[0], UV[0] - UV[1] );
1009 (initUV[0]-theInitUV).Modulus() / (initUV[0]-initUV[1]).Modulus();
1010 //gp_Pnt2d isoLoc = UV[0] * ( 1 - r ) + UV[1] * r;
1011 //isoLine[ iIso ] = iso.Normal( isoLoc );
1012 uv1[ iIso ] = UV[0];
1013 uv2[ iIso ] = UV[1];
1016 if ( !intersectIsolines( uv1[0], uv2[0], ratio[0],
1017 uv1[1], uv2[1], ratio[1], theUV, theIsDeformed )) {
1018 MESSAGE(" Cant intersect isolines for a point "<<theInitUV.X()<<", "<<theInitUV.Y());
1019 return setErrorCode( ERR_APPLF_BAD_TOPOLOGY );
1026 // ==========================================================
1027 // structure representing a node of a grid of iso-poly-lines
1028 // ==========================================================
1035 gp_Dir2d myDir[2]; // boundary tangent dir for boundary nodes, iso dir for internal ones
1036 TIsoNode* myNext[4]; // order: (iDir=0,isForward=0), (1,0), (0,1), (1,1)
1037 TIsoNode* myBndNodes[4]; // order: (iDir=0,i=0), (1,0), (0,1), (1,1)
1038 TIsoNode(double initU, double initV):
1039 myInitUV( initU, initV ), myUV( 1e100, 1e100 ), myIsMovable(true)
1040 { myNext[0] = myNext[1] = myNext[2] = myNext[3] = 0; }
1041 bool IsUVComputed() const
1042 { return myUV.X() != 1e100; }
1043 bool IsMovable() const
1044 { return myIsMovable && myNext[0] && myNext[1] && myNext[2] && myNext[3]; }
1045 void SetNotMovable()
1046 { myIsMovable = false; }
1047 void SetBoundaryNode(TIsoNode* node, int iDir, int i)
1048 { myBndNodes[ iDir + i * 2 ] = node; }
1049 TIsoNode* GetBoundaryNode(int iDir, int i)
1050 { return myBndNodes[ iDir + i * 2 ]; }
1051 void SetNext(TIsoNode* node, int iDir, int isForward)
1052 { myNext[ iDir + isForward * 2 ] = node; }
1053 TIsoNode* GetNext(int iDir, int isForward)
1054 { return myNext[ iDir + isForward * 2 ]; }
1057 //=======================================================================
1058 //function : getNextNode
1060 //=======================================================================
1062 static inline TIsoNode* getNextNode(const TIsoNode* node, int dir )
1064 TIsoNode* n = node->myNext[ dir ];
1065 if ( n && !n->IsUVComputed()/* && node->IsMovable()*/ ) {
1066 n = 0;//node->myBndNodes[ dir ];
1067 // MESSAGE("getNextNode: use bnd for node "<<
1068 // node->myInitUV.X()<<" "<<node->myInitUV.Y());
1072 //=======================================================================
1073 //function : checkQuads
1074 //purpose : check if newUV destortes quadrangles around node,
1075 // and if ( crit == FIX_OLD ) fix newUV in this case
1076 //=======================================================================
1078 enum { CHECK_NEW_IN, CHECK_NEW_OK, FIX_OLD };
1080 static bool checkQuads (const TIsoNode* node,
1082 const bool reversed,
1083 const int crit = FIX_OLD,
1084 double fixSize = 0.)
1086 gp_XY oldUV = node->myUV, oldUVFixed[4], oldUVImpr[4];
1087 int nbOldFix = 0, nbOldImpr = 0;
1088 double newBadRate = 0, oldBadRate = 0;
1089 bool newIsOk = true, newIsIn = true, oldIsIn = true, oldIsOk = true;
1090 int i, dir1 = 0, dir2 = 3;
1091 for ( ; dir1 < 4; dir1++, dir2++ ) // loop on 4 quadrangles around <node>
1093 if ( dir2 > 3 ) dir2 = 0;
1095 // walking counterclockwise around a quad,
1096 // nodes are in the order: node, n[0], n[1], n[2]
1097 n[0] = getNextNode( node, dir1 );
1098 n[2] = getNextNode( node, dir2 );
1099 if ( !n[0] || !n[2] ) continue;
1100 n[1] = getNextNode( n[0], dir2 );
1101 if ( !n[1] ) n[1] = getNextNode( n[2], dir1 );
1102 bool isTriangle = ( !n[1] );
1104 TIsoNode* tmp = n[0]; n[0] = n[2]; n[2] = tmp;
1106 // if ( fixSize != 0 ) {
1107 // cout<<"NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<" UV: "<<node->myUV.X()<<" "<<node->myUV.Y()<<endl;
1108 // cout<<"\t0: "<<n[0]->myInitUV.X()<<" "<<n[0]->myInitUV.Y()<<" UV: "<<n[0]->myUV.X()<<" "<<n[0]->myUV.Y()<<endl;
1109 // cout<<"\t1: "<<n[1]->myInitUV.X()<<" "<<n[1]->myInitUV.Y()<<" UV: "<<n[1]->myUV.X()<<" "<<n[1]->myUV.Y()<<endl;
1110 // cout<<"\t2: "<<n[2]->myInitUV.X()<<" "<<n[2]->myInitUV.Y()<<" UV: "<<n[2]->myUV.X()<<" "<<n[2]->myUV.Y()<<endl;
1112 // check if a quadrangle is degenerated
1114 ((( n[0]->myUV - n[1]->myUV ).SquareModulus() <= DBL_MIN ) ||
1115 (( n[2]->myUV - n[1]->myUV ).SquareModulus() <= DBL_MIN )))
1118 ( n[0]->myUV - n[2]->myUV ).SquareModulus() <= DBL_MIN )
1121 // find min size of the diagonal node-n[1]
1122 double minDiag = fixSize;
1123 if ( minDiag == 0. ) {
1124 double maxLen2 = ( node->myUV - n[0]->myUV ).SquareModulus();
1125 if ( !isTriangle ) {
1126 maxLen2 = Max( maxLen2, ( n[0]->myUV - n[1]->myUV ).SquareModulus() );
1127 maxLen2 = Max( maxLen2, ( n[1]->myUV - n[2]->myUV ).SquareModulus() );
1129 maxLen2 = Max( maxLen2, ( n[2]->myUV - node->myUV ).SquareModulus() );
1130 minDiag = sqrt( maxLen2 ) * PI / 60.; // ~ maxLen * Sin( 3 deg )
1133 // check if newUV is behind 3 dirs: n[0]-n[1], n[1]-n[2] and n[0]-n[2]
1134 // ( behind means "to the right of")
1136 // 1. newUV is not behind 01 and 12 dirs
1137 // 2. or newUV is not behind 02 dir and n[2] is convex
1138 bool newIn[3] = { true, true, true }, newOk[3] = { true, true, true };
1139 bool wasIn[3] = { true, true, true }, wasOk[3] = { true, true, true };
1140 gp_Vec2d moveVec[3], outVec[3];
1141 for ( i = isTriangle ? 2 : 0; i < 3; i++ )
1143 bool isDiag = ( i == 2 );
1144 if ( isDiag && newOk[0] && newOk[1] && !isTriangle )
1148 sideDir = gp_Vec2d( n[0]->myUV, n[2]->myUV );
1150 sideDir = gp_Vec2d( n[i]->myUV, n[i+1]->myUV );
1152 gp_Vec2d outDir( sideDir.Y(), -sideDir.X() ); // to the right
1154 gp_Vec2d newDir( n[i]->myUV, newUV );
1155 gp_Vec2d oldDir( n[i]->myUV, oldUV );
1157 if ( newIsOk ) newOk[i] = ( outDir * newDir < -minDiag );
1158 if ( newIsIn ) newIn[i] = ( outDir * newDir < 0 );
1159 if ( crit == FIX_OLD ) {
1160 wasIn[i] = ( outDir * oldDir < 0 );
1161 wasOk[i] = ( outDir * oldDir < -minDiag );
1163 newBadRate += outDir * newDir;
1165 oldBadRate += outDir * oldDir;
1168 double oldDist = - outDir * oldDir;//, l2 = outDir * newDir;
1169 // double r = ( l1 - minDiag ) / ( l1 + l2 );
1170 // moveVec[i] = r * gp_Vec2d( node->myUV, newUV );
1171 moveVec[i] = ( oldDist - minDiag ) * outDir;
1176 // check if n[2] is convex
1179 convex = ( outVec[0] * gp_Vec2d( n[1]->myUV, n[2]->myUV ) < 0 );
1181 bool isNewOk = ( newOk[0] && newOk[1] ) || ( newOk[2] && convex );
1182 bool isNewIn = ( newIn[0] && newIn[1] ) || ( newIn[2] && convex );
1183 newIsOk = ( newIsOk && isNewOk );
1184 newIsIn = ( newIsIn && isNewIn );
1186 if ( crit != FIX_OLD ) {
1187 if ( crit == CHECK_NEW_OK && !newIsOk ) break;
1188 if ( crit == CHECK_NEW_IN && !newIsIn ) break;
1192 bool isOldIn = ( wasIn[0] && wasIn[1] ) || ( wasIn[2] && convex );
1193 bool isOldOk = ( wasOk[0] && wasOk[1] ) || ( wasOk[2] && convex );
1194 oldIsIn = ( oldIsIn && isOldIn );
1195 oldIsOk = ( oldIsOk && isOldIn );
1198 if ( !isOldIn ) { // node is outside a quadrangle
1199 // move newUV inside a quadrangle
1200 //MESSAGE("Quad "<< dir1 << " WAS IN " << wasIn[0]<<" "<<wasIn[1]<<" "<<wasIn[2]);
1201 // node and newUV are outside: push newUV inside
1203 if ( convex || isTriangle ) {
1204 uv = 0.5 * ( n[0]->myUV + n[2]->myUV ) - minDiag * outVec[2].XY();
1207 gp_Vec2d out = outVec[0].Normalized() + outVec[1].Normalized();
1208 double outSize = out.Magnitude();
1209 if ( outSize > DBL_MIN )
1212 out.SetCoord( -outVec[1].Y(), outVec[1].X() );
1213 uv = n[1]->myUV - minDiag * out.XY();
1215 oldUVFixed[ nbOldFix++ ] = uv;
1216 //node->myUV = newUV;
1218 else if ( !isOldOk ) {
1219 // try to fix old UV: move node inside as less as possible
1220 //MESSAGE("Quad "<< dir1 << " old is BAD, try to fix old, minDiag: "<< minDiag);
1221 gp_XY uv1, uv2 = node->myUV;
1222 for ( i = isTriangle ? 2 : 0; i < 3; i++ ) // mark not computed vectors
1224 moveVec[ i ].SetCoord( 1, 2e100); // not use this vector
1225 while ( !isOldOk ) {
1226 // find the least moveVec
1228 double minMove2 = 1e100;
1229 for ( i = isTriangle ? 2 : 0; i < 3; i++ )
1231 if ( moveVec[i].Coord(1) < 1e100 ) {
1232 double move2 = moveVec[i].SquareMagnitude();
1233 if ( move2 < minMove2 ) {
1242 // move node to newUV
1243 uv1 = node->myUV + moveVec[ iMin ].XY();
1244 uv2 += moveVec[ iMin ].XY();
1245 moveVec[ iMin ].SetCoord( 1, 2e100); // not use this vector more
1246 // check if uv1 is ok
1247 for ( i = isTriangle ? 2 : 0; i < 3; i++ )
1248 wasOk[i] = ( outVec[i] * gp_Vec2d( n[i]->myUV, uv1 ) < -minDiag );
1249 isOldOk = ( wasOk[0] && wasOk[1] ) || ( wasOk[2] && convex );
1251 oldUVImpr[ nbOldImpr++ ] = uv1;
1253 // check if uv2 is ok
1254 for ( i = isTriangle ? 2 : 0; i < 3; i++ )
1255 wasOk[i] = ( outVec[i] * gp_Vec2d( n[i]->myUV, uv2 ) < -minDiag );
1256 isOldOk = ( wasOk[0] && wasOk[1] ) || ( wasOk[2] && convex );
1258 oldUVImpr[ nbOldImpr++ ] = uv2;
1263 } // loop on 4 quadrangles around <node>
1265 if ( crit == CHECK_NEW_OK )
1267 if ( crit == CHECK_NEW_IN )
1276 if ( oldIsIn && nbOldImpr ) {
1277 // MESSAGE(" Try to improve UV, init: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<
1278 // " uv: "<<oldUV.X()<<" "<<oldUV.Y() );
1279 gp_XY uv = oldUVImpr[ 0 ];
1280 for ( int i = 1; i < nbOldImpr; i++ )
1281 uv += oldUVImpr[ i ];
1283 if ( checkQuads( node, uv, reversed, CHECK_NEW_OK )) {
1288 //MESSAGE(" Cant improve UV, uv: "<<uv.X()<<" "<<uv.Y());
1291 if ( !oldIsIn && nbOldFix ) {
1292 // MESSAGE(" Try to fix UV, init: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<
1293 // " uv: "<<oldUV.X()<<" "<<oldUV.Y() );
1294 gp_XY uv = oldUVFixed[ 0 ];
1295 for ( int i = 1; i < nbOldFix; i++ )
1296 uv += oldUVFixed[ i ];
1298 if ( checkQuads( node, uv, reversed, CHECK_NEW_IN )) {
1303 //MESSAGE(" Cant fix UV, uv: "<<uv.X()<<" "<<uv.Y());
1306 if ( newIsIn && oldIsIn )
1307 newUV = ( newBadRate < oldBadRate ) ? newUV : oldUV;
1308 else if ( !newIsIn )
1315 //=======================================================================
1316 //function : compUVByElasticIsolines
1317 //purpose : compute UV as nodes of iso-poly-lines consisting of
1318 // segments keeping relative size as in the pattern
1319 //=======================================================================
1320 //#define DEB_COMPUVBYELASTICISOLINES
1321 bool SMESH_Pattern::
1322 compUVByElasticIsolines(const list< list< TPoint* > >& theBndPoints,
1323 const list< TPoint* >& thePntToCompute)
1325 //cout << "============================== KEY POINTS =============================="<<endl;
1326 // list< int >::iterator kpIt = myKeyPointIDs.begin();
1327 // for ( ; kpIt != myKeyPointIDs.end(); kpIt++ ) {
1328 // TPoint& p = myPoints[ *kpIt ];
1329 // cout << "INIT: " << p.myInitUV.X() << " " << p.myInitUV.Y() <<
1330 // " UV: " << p.myUV.X() << " " << p.myUV.Y() << endl;
1332 //cout << "=============================="<<endl;
1334 // Define parameters of iso-grid nodes in U and V dir
1336 set< double > paramSet[ 2 ];
1337 list< list< TPoint* > >::const_iterator pListIt;
1338 list< TPoint* >::const_iterator pIt;
1339 for ( pListIt = theBndPoints.begin(); pListIt != theBndPoints.end(); pListIt++ ) {
1340 const list< TPoint* > & pList = * pListIt;
1341 for ( pIt = pList.begin(); pIt != pList.end(); pIt++ ) {
1342 paramSet[0].insert( (*pIt)->myInitUV.X() );
1343 paramSet[1].insert( (*pIt)->myInitUV.Y() );
1346 for ( pIt = thePntToCompute.begin(); pIt != thePntToCompute.end(); pIt++ ) {
1347 paramSet[0].insert( (*pIt)->myInitUV.X() );
1348 paramSet[1].insert( (*pIt)->myInitUV.Y() );
1350 // unite close parameters and split too long segments
1353 for ( iDir = 0; iDir < 2; iDir++ )
1355 set< double > & params = paramSet[ iDir ];
1356 double range = ( *params.rbegin() - *params.begin() );
1357 double toler = range / 1e6;
1358 tol[ iDir ] = toler;
1359 // double maxSegment = range / params.size() / 2.;
1361 // set< double >::iterator parIt = params.begin();
1362 // double prevPar = *parIt;
1363 // for ( parIt++; parIt != params.end(); parIt++ )
1365 // double segLen = (*parIt) - prevPar;
1366 // if ( segLen < toler )
1367 // ;//params.erase( prevPar ); // unite
1368 // else if ( segLen > maxSegment )
1369 // params.insert( prevPar + 0.5 * segLen ); // split
1370 // prevPar = (*parIt);
1374 // Make nodes of a grid of iso-poly-lines
1376 list < TIsoNode > nodes;
1377 typedef list < TIsoNode *> TIsoLine;
1378 map < double, TIsoLine > isoMap[ 2 ];
1380 set< double > & params0 = paramSet[ 0 ];
1381 set< double >::iterator par0It = params0.begin();
1382 for ( ; par0It != params0.end(); par0It++ )
1384 TIsoLine & isoLine0 = isoMap[0][ *par0It ]; // vertical isoline with const U
1385 set< double > & params1 = paramSet[ 1 ];
1386 set< double >::iterator par1It = params1.begin();
1387 for ( ; par1It != params1.end(); par1It++ )
1389 nodes.push_back( TIsoNode( *par0It, *par1It ) );
1390 isoLine0.push_back( & nodes.back() );
1391 isoMap[1][ *par1It ].push_back( & nodes.back() );
1395 // Compute intersections of boundaries with iso-lines:
1396 // only boundary nodes will have computed UV so far
1399 list< list< TPoint* > >::const_iterator bndIt = theBndPoints.begin();
1400 list< TIsoNode* > bndNodes; // nodes corresponding to outer theBndPoints
1401 for ( ; bndIt != theBndPoints.end(); bndIt++ )
1403 const list< TPoint* > & bndPoints = * bndIt;
1404 TPoint* prevP = bndPoints.back(); // this is the first point
1405 list< TPoint* >::const_iterator pIt = bndPoints.begin();
1406 // loop on the edge-points
1407 for ( ; pIt != bndPoints.end(); pIt++ )
1409 TPoint* point = *pIt;
1410 for ( iDir = 0; iDir < 2; iDir++ )
1412 const int iCoord = iDir + 1;
1413 const int iOtherCoord = 2 - iDir;
1414 double par1 = prevP->myInitUV.Coord( iCoord );
1415 double par2 = point->myInitUV.Coord( iCoord );
1416 double parDif = par2 - par1;
1417 if ( Abs( parDif ) <= DBL_MIN )
1419 // find iso-lines intersecting a bounadry
1420 double toler = tol[ 1 - iDir ];
1421 double minPar = Min ( par1, par2 );
1422 double maxPar = Max ( par1, par2 );
1423 map < double, TIsoLine >& isos = isoMap[ iDir ];
1424 map < double, TIsoLine >::iterator isoIt = isos.begin();
1425 for ( ; isoIt != isos.end(); isoIt++ )
1427 double isoParam = (*isoIt).first;
1428 if ( isoParam < minPar || isoParam > maxPar )
1430 double r = ( isoParam - par1 ) / parDif;
1431 gp_XY uv = ( 1 - r ) * prevP->myUV + r * point->myUV;
1432 gp_XY initUV = ( 1 - r ) * prevP->myInitUV + r * point->myInitUV;
1433 double otherPar = initUV.Coord( iOtherCoord ); // along isoline
1434 // find existing node with otherPar or insert a new one
1435 TIsoLine & isoLine = (*isoIt).second;
1437 TIsoLine::iterator nIt = isoLine.begin();
1438 for ( ; nIt != isoLine.end(); nIt++ ) {
1439 nodePar = (*nIt)->myInitUV.Coord( iOtherCoord );
1440 if ( nodePar >= otherPar )
1444 if ( Abs( nodePar - otherPar ) <= toler )
1445 node = ( nIt == isoLine.end() ) ? isoLine.back() : (*nIt);
1447 nodes.push_back( TIsoNode( initUV.X(), initUV.Y() ) );
1448 node = & nodes.back();
1449 isoLine.insert( nIt, node );
1451 node->SetNotMovable();
1453 uvBnd.Add( gp_Pnt2d( uv ));
1454 // cout << "bnd: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<" UV: "<<node->myUV.X()<<" "<<node->myUV.Y()<<endl;
1456 gp_XY tgt( point->myUV - prevP->myUV );
1457 if ( ::IsEqual( r, 1. ))
1458 node->myDir[ 0 ] = tgt;
1459 else if ( ::IsEqual( r, 0. ))
1460 node->myDir[ 1 ] = tgt;
1462 node->myDir[ 1 ] = node->myDir[ 0 ] = tgt;
1463 // keep boundary nodes corresponding to boundary points
1464 if ( bndIt == theBndPoints.begin() && ::IsEqual( r, 1. ))
1465 if ( bndNodes.empty() || bndNodes.back() != node )
1466 bndNodes.push_back( node );
1467 } // loop on isolines
1468 } // loop on 2 directions
1470 } // loop on boundary points
1471 } // loop on boundaries
1473 // Define orientation
1475 // find the point with the least X
1476 double leastX = DBL_MAX;
1477 TIsoNode * leftNode;
1478 list < TIsoNode >::iterator nodeIt = nodes.begin();
1479 for ( ; nodeIt != nodes.end(); nodeIt++ ) {
1480 TIsoNode & node = *nodeIt;
1481 if ( node.IsUVComputed() && node.myUV.X() < leastX ) {
1482 leastX = node.myUV.X();
1485 // if ( node.IsUVComputed() ) {
1486 // cout << "bndNode INIT: " << node.myInitUV.X()<<" "<<node.myInitUV.Y()<<" UV: "<<
1487 // node.myUV.X()<<" "<<node.myUV.Y()<<endl<<
1488 // " dir0: "<<node.myDir[0].X()<<" "<<node.myDir[0].Y() <<
1489 // " dir1: "<<node.myDir[1].X()<<" "<<node.myDir[1].Y() << endl;
1492 bool reversed = ( leftNode->myDir[0].Y() + leftNode->myDir[1].Y() > 0 );
1493 //SCRUTE( reversed );
1495 // Prepare internal nodes:
1497 // 2. compute ratios
1498 // 3. find boundary nodes for each node
1499 // 4. remove nodes out of the boundary
1500 for ( iDir = 0; iDir < 2; iDir++ )
1502 const int iCoord = 2 - iDir; // coord changing along an isoline
1503 map < double, TIsoLine >& isos = isoMap[ iDir ];
1504 map < double, TIsoLine >::iterator isoIt = isos.begin();
1505 for ( ; isoIt != isos.end(); isoIt++ )
1507 TIsoLine & isoLine = (*isoIt).second;
1508 bool firstCompNodeFound = false;
1509 TIsoLine::iterator lastCompNodePos, nPrevIt, nIt, nNextIt, nIt2;
1510 nPrevIt = nIt = nNextIt = isoLine.begin();
1512 nNextIt++; nNextIt++;
1513 while ( nIt != isoLine.end() )
1515 // 1. connect prev - cur
1516 TIsoNode* node = *nIt, * prevNode = *nPrevIt;
1517 if ( !firstCompNodeFound && prevNode->IsUVComputed() ) {
1518 firstCompNodeFound = true;
1519 lastCompNodePos = nPrevIt;
1521 if ( firstCompNodeFound ) {
1522 node->SetNext( prevNode, iDir, 0 );
1523 prevNode->SetNext( node, iDir, 1 );
1526 if ( nNextIt != isoLine.end() ) {
1527 double par1 = prevNode->myInitUV.Coord( iCoord );
1528 double par2 = node->myInitUV.Coord( iCoord );
1529 double par3 = (*nNextIt)->myInitUV.Coord( iCoord );
1530 node->myRatio[ iDir ] = ( par2 - par1 ) / ( par3 - par1 );
1532 // 3. find boundary nodes
1533 if ( node->IsUVComputed() )
1534 lastCompNodePos = nIt;
1535 else if ( firstCompNodeFound && nNextIt != isoLine.end() ) {
1536 TIsoNode* bndNode1 = *lastCompNodePos, *bndNode2 = 0;
1537 for ( nIt2 = nNextIt; nIt2 != isoLine.end(); nIt2++ )
1538 if ( (*nIt2)->IsUVComputed() )
1540 if ( nIt2 != isoLine.end() ) {
1542 node->SetBoundaryNode( bndNode1, iDir, 0 );
1543 node->SetBoundaryNode( bndNode2, iDir, 1 );
1544 // cout << "--------------------------------------------------"<<endl;
1545 // cout << "bndNode1: " << bndNode1->myUV.X()<<" "<<bndNode1->myUV.Y()<<endl<<
1546 // " dir0: "<<bndNode1->myDir[0].X()<<" "<<bndNode1->myDir[0].Y() <<
1547 // " dir1: "<<bndNode1->myDir[1].X()<<" "<<bndNode1->myDir[1].Y() << endl;
1548 // cout << "bndNode2: " << bndNode2->myUV.X()<<" "<<bndNode2->myUV.Y()<<endl<<
1549 // " dir0: "<<bndNode2->myDir[0].X()<<" "<<bndNode2->myDir[0].Y() <<
1550 // " dir1: "<<bndNode2->myDir[1].X()<<" "<<bndNode2->myDir[1].Y() << endl;
1554 if ( nNextIt != isoLine.end() ) nNextIt++;
1555 // 4. remove nodes out of the boundary
1556 if ( !firstCompNodeFound )
1557 isoLine.pop_front();
1558 } // loop on isoLine nodes
1560 // remove nodes after the boundary
1561 // for ( nIt = ++lastCompNodePos; nIt != isoLine.end(); nIt++ )
1562 // (*nIt)->SetNotMovable();
1563 isoLine.erase( ++lastCompNodePos, isoLine.end() );
1564 } // loop on isolines
1565 } // loop on 2 directions
1567 // Compute local isoline direction for internal nodes
1570 map < double, TIsoLine >& isos = isoMap[ 0 ]; // vertical isolines with const U
1571 map < double, TIsoLine >::iterator isoIt = isos.begin();
1572 for ( ; isoIt != isos.end(); isoIt++ )
1574 TIsoLine & isoLine = (*isoIt).second;
1575 TIsoLine::iterator nIt = isoLine.begin();
1576 for ( ; nIt != isoLine.end(); nIt++ )
1578 TIsoNode* node = *nIt;
1579 if ( node->IsUVComputed() || !node->IsMovable() )
1581 gp_Vec2d aTgt[2], aNorm[2];
1584 for ( iDir = 0; iDir < 2; iDir++ )
1586 TIsoNode* bndNode1 = node->GetBoundaryNode( iDir, 0 );
1587 TIsoNode* bndNode2 = node->GetBoundaryNode( iDir, 1 );
1588 if ( !bndNode1 || !bndNode2 ) {
1592 const int iCoord = 2 - iDir; // coord changing along an isoline
1593 double par1 = bndNode1->myInitUV.Coord( iCoord );
1594 double par2 = node->myInitUV.Coord( iCoord );
1595 double par3 = bndNode2->myInitUV.Coord( iCoord );
1596 ratio[ iDir ] = ( par2 - par1 ) / ( par3 - par1 );
1598 gp_Vec2d tgt1( bndNode1->myDir[0].XY() + bndNode1->myDir[1].XY() );
1599 gp_Vec2d tgt2( bndNode2->myDir[0].XY() + bndNode2->myDir[1].XY() );
1600 if ( bool( iDir ) == reversed ) tgt2.Reverse(); // along perpend. isoline
1601 else tgt1.Reverse();
1602 //cout<<" tgt: " << tgt1.X()<<" "<<tgt1.Y()<<" | "<< tgt2.X()<<" "<<tgt2.Y()<<endl;
1604 if ( ratio[ iDir ] < 0.5 )
1605 aNorm[ iDir ] = gp_Vec2d( -tgt1.Y(), tgt1.X() ); // rotate tgt to the left
1607 aNorm[ iDir ] = gp_Vec2d( -tgt2.Y(), tgt2.X() );
1609 aNorm[ iDir ].Reverse(); // along iDir isoline
1611 double angle = tgt1.Angle( tgt2 ); // [-PI, PI]
1612 // maybe angle is more than |PI|
1613 if ( Abs( angle ) > PI / 2. ) {
1614 // check direction of the last but one perpendicular isoline
1615 TIsoNode* prevNode = bndNode2->GetNext( iDir, 0 );
1616 bndNode1 = prevNode->GetBoundaryNode( 1 - iDir, 0 );
1617 bndNode2 = prevNode->GetBoundaryNode( 1 - iDir, 1 );
1618 gp_Vec2d isoDir( bndNode1->myUV, bndNode2->myUV );
1619 if ( isoDir * tgt2 < 0 )
1621 double angle2 = tgt1.Angle( isoDir );
1622 //cout << " isoDir: "<< isoDir.X() <<" "<<isoDir.Y() << " ANGLE: "<< angle << " "<<angle2<<endl;
1623 if (angle2 * angle < 0 && // check the sign of an angle close to PI
1624 Abs ( Abs ( angle ) - PI ) <= PI / 180. ) {
1625 //MESSAGE("REVERSE ANGLE");
1628 if ( Abs( angle2 ) > Abs( angle ) ||
1629 ( angle2 * angle < 0 && Abs( angle2 ) > Abs( angle - angle2 ))) {
1630 //MESSAGE("Add PI");
1631 // cout << "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
1632 // cout <<"ISO: " << isoParam << " " << (*iso2It).first << endl;
1633 // cout << "bndNode1: " << bndNode1->myUV.X()<<" "<<bndNode1->myUV.Y()<< endl;
1634 // cout << "bndNode2: " << bndNode2->myUV.X()<<" "<<bndNode2->myUV.Y()<<endl;
1635 // cout <<" tgt: " << tgt1.X()<<" "<<tgt1.Y()<<" "<< tgt2.X()<<" "<<tgt2.Y()<<endl;
1636 angle += ( angle < 0 ) ? 2. * PI : -2. * PI;
1639 aTgt[ iDir ] = tgt1.Rotated( angle * ratio[ iDir ] ).XY();
1643 for ( iDir = 0; iDir < 2; iDir++ )
1645 aTgt[iDir].Normalize();
1646 aNorm[1-iDir].Normalize();
1647 double r = Abs ( ratio[iDir] - 0.5 ) * 2.0; // [0,1] - distance from the middle
1650 node->myDir[iDir] = //aTgt[iDir];
1651 aNorm[1-iDir] * r + aTgt[iDir] * ( 1. - r );
1653 // cout << "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
1654 // cout <<" tgt: " << tgt1.X()<<" "<<tgt1.Y()<<" - "<< tgt2.X()<<" "<<tgt2.Y()<<endl;
1655 // cout << " isoDir: "<< node->myDir[0].X() <<" "<<node->myDir[0].Y()<<" | "
1656 // << node->myDir[1].X() <<" "<<node->myDir[1].Y()<<endl;
1658 } // loop on iso nodes
1659 } // loop on isolines
1661 // Find nodes to start computing UV from
1663 list< TIsoNode* > startNodes;
1664 list< TIsoNode* >::iterator nIt = bndNodes.end();
1665 TIsoNode* node = *(--nIt);
1666 TIsoNode* prevNode = *(--nIt);
1667 for ( nIt = bndNodes.begin(); nIt != bndNodes.end(); nIt++ )
1669 TIsoNode* nextNode = *nIt;
1670 gp_Vec2d initTgt1( prevNode->myInitUV, node->myInitUV );
1671 gp_Vec2d initTgt2( node->myInitUV, nextNode->myInitUV );
1672 double initAngle = initTgt1.Angle( initTgt2 );
1673 double angle = node->myDir[0].Angle( node->myDir[1] );
1674 if ( reversed ) angle = -angle;
1675 if ( initAngle > angle && initAngle - angle > PI / 2.1 ) {
1676 // find a close internal node
1677 TIsoNode* nClose = 0;
1678 list< TIsoNode* > testNodes;
1679 testNodes.push_back( node );
1680 list< TIsoNode* >::iterator it = testNodes.begin();
1681 for ( ; !nClose && it != testNodes.end(); it++ )
1683 for (int i = 0; i < 4; i++ )
1685 nClose = (*it)->myNext[ i ];
1687 if ( !nClose->IsUVComputed() )
1690 testNodes.push_back( nClose );
1696 startNodes.push_back( nClose );
1697 // cout << "START: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<" UV: "<<
1698 // node->myUV.X()<<" "<<node->myUV.Y()<<endl<<
1699 // "initAngle: " << initAngle << " angle: " << angle << endl;
1700 // cout <<" init tgt: " << initTgt1.X()<<" "<<initTgt1.Y()<<" | "<< initTgt2.X()<<" "<<initTgt2.Y()<<endl;
1701 // cout << " tgt: "<< node->myDir[ 0 ].X() <<" "<<node->myDir[ 0 ].Y()<<" | "<<
1702 // node->myDir[ 1 ].X() <<" "<<node->myDir[ 1 ].Y()<<endl;
1703 // cout << "CLOSE: "<<nClose->myInitUV.X()<<" "<<nClose->myInitUV.Y()<<endl;
1709 // Compute starting UV of internal nodes
1711 list < TIsoNode* > internNodes;
1712 bool needIteration = true;
1713 if ( startNodes.empty() ) {
1714 MESSAGE( " Starting UV by compUVByIsoIntersection()");
1715 needIteration = false;
1716 map < double, TIsoLine >& isos = isoMap[ 0 ];
1717 map < double, TIsoLine >::iterator isoIt = isos.begin();
1718 for ( ; isoIt != isos.end(); isoIt++ )
1720 TIsoLine & isoLine = (*isoIt).second;
1721 TIsoLine::iterator nIt = isoLine.begin();
1722 for ( ; !needIteration && nIt != isoLine.end(); nIt++ )
1724 TIsoNode* node = *nIt;
1725 if ( !node->IsUVComputed() && node->IsMovable() ) {
1726 internNodes.push_back( node );
1728 if ( !compUVByIsoIntersection(theBndPoints, node->myInitUV,
1729 node->myUV, needIteration ))
1730 node->myUV = node->myInitUV;
1734 if ( needIteration )
1735 for ( nIt = bndNodes.begin(); nIt != bndNodes.end(); nIt++ )
1737 TIsoNode* node = *nIt, *nClose = 0;
1738 list< TIsoNode* > testNodes;
1739 testNodes.push_back( node );
1740 list< TIsoNode* >::iterator it = testNodes.begin();
1741 for ( ; !nClose && it != testNodes.end(); it++ )
1743 for (int i = 0; i < 4; i++ )
1745 nClose = (*it)->myNext[ i ];
1747 if ( !nClose->IsUVComputed() && nClose->IsMovable() )
1750 testNodes.push_back( nClose );
1756 startNodes.push_back( nClose );
1760 double aMin[2], aMax[2], step[2];
1761 uvBnd.Get( aMin[0], aMin[1], aMax[0], aMax[1] );
1762 double minUvSize = Min ( aMax[0]-aMin[0], aMax[1]-aMin[1] );
1763 step[0] = minUvSize / paramSet[ 0 ].size() / 10;
1764 step[1] = minUvSize / paramSet[ 1 ].size() / 10;
1765 //cout << "STEPS: " << step[0] << " " << step[1]<< endl;
1767 for ( nIt = startNodes.begin(); nIt != startNodes.end(); nIt++ )
1769 TIsoNode* prevN[2], *node = *nIt;
1770 if ( node->IsUVComputed() || !node->IsMovable() )
1772 gp_XY newUV( 0, 0 ), sumDir( 0, 0 );
1773 int nbComp = 0, nbPrev = 0;
1774 for ( iDir = 0; iDir < 2; iDir++ )
1776 TIsoNode* prevNode1 = 0, *prevNode2 = 0;
1777 TIsoNode* n = node->GetNext( iDir, 0 );
1778 if ( n->IsUVComputed() )
1781 startNodes.push_back( n );
1782 n = node->GetNext( iDir, 1 );
1783 if ( n->IsUVComputed() )
1786 startNodes.push_back( n );
1788 prevNode1 = prevNode2;
1791 if ( prevNode1 ) nbPrev++;
1792 if ( prevNode2 ) nbPrev++;
1795 double prevPar = prevNode1->myInitUV.Coord( 2 - iDir );
1796 double par = node->myInitUV.Coord( 2 - iDir );
1797 bool isEnd = ( prevPar > par );
1798 // dir = node->myDir[ 1 - iDir ].XY() * ( isEnd ? -1. : 1. );
1799 //cout << "__________"<<endl<< "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
1800 TIsoNode* bndNode = node->GetBoundaryNode( iDir, isEnd );
1801 gp_XY tgt( bndNode->myDir[0].XY() + bndNode->myDir[1].XY() );
1802 dir.SetCoord( 1, tgt.Y() * ( reversed ? 1 : -1 ));
1803 dir.SetCoord( 2, tgt.X() * ( reversed ? -1 : 1 ));
1804 //cout << "bndNode UV: " << bndNode->myUV.X()<<" "<<bndNode->myUV.Y()<< endl;
1805 // cout << " tgt: "<< bndNode->myDir[ 0 ].X() <<" "<<bndNode->myDir[ 0 ].Y()<<" | "<<
1806 // bndNode->myDir[ 1 ].X() <<" "<<bndNode->myDir[ 1 ].Y()<<endl;
1807 //cout << "prevNode UV: " << prevNode1->myUV.X()<<" "<<prevNode1->myUV.Y()<<
1808 //" par: " << prevPar << endl;
1809 // cout <<" tgt: " << tgt.X()<<" "<<tgt.Y()<<endl;
1810 //cout << " DIR: "<< dir.X() <<" "<<dir.Y()<<endl;
1812 //cout << "____2next______"<<endl<< "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
1813 gp_XY & uv1 = prevNode1->myUV;
1814 gp_XY & uv2 = prevNode2->myUV;
1815 // dir = ( uv2 - uv1 );
1816 // double len = dir.Modulus();
1817 // if ( len > DBL_MIN )
1818 // dir /= len * 0.5;
1819 double r = node->myRatio[ iDir ];
1820 newUV += uv1 * ( 1 - r ) + uv2 * r;
1823 newUV += prevNode1->myUV + dir * step[ iDir ];
1826 prevN[ iDir ] = prevNode1;
1832 //cout << "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
1834 // check if a quadrangle is not distorted
1836 //int crit = ( nbPrev == 4 ) ? FIX_OLD : CHECK_NEW_IN;
1837 if ( !checkQuads( node, newUV, reversed, FIX_OLD, step[0] + step[1] )) {
1838 //cout <<" newUV: " << node->myUV.X() << " "<<node->myUV.Y() << " nbPrev: "<<nbPrev<< endl;
1839 // cout << "_FIX_INIT_ fixedUV: " << newUV.X() << " "<<newUV.Y() << endl;
1843 internNodes.push_back( node );
1848 static int maxNbIter = 100;
1849 #ifdef DEB_COMPUVBYELASTICISOLINES
1851 bool useNbMoveNode = 0;
1852 static int maxNbNodeMove = 100;
1855 if ( !useNbMoveNode )
1856 maxNbIter = ( maxNbIter < 0 ) ? 100 : -1;
1861 if ( !needIteration) break;
1862 #ifdef DEB_COMPUVBYELASTICISOLINES
1863 if ( nbIter >= maxNbIter ) break;
1866 list < TIsoNode* >::iterator nIt = internNodes.begin();
1867 for ( ; nIt != internNodes.end(); nIt++ ) {
1868 #ifdef DEB_COMPUVBYELASTICISOLINES
1870 cout << nbNodeMove <<" =================================================="<<endl;
1872 TIsoNode * node = *nIt;
1876 for ( iDir = 0; iDir < 2; iDir++ )
1878 gp_XY & uv1 = node->GetNext( iDir, 0 )->myUV;
1879 gp_XY & uv2 = node->GetNext( iDir, 1 )->myUV;
1880 double r = node->myRatio[ iDir ];
1881 loc[ iDir ] = uv1 * ( 1 - r ) + uv2 * r;
1882 // line[ iDir ].SetLocation( loc[ iDir ] );
1883 // line[ iDir ].SetDirection( node->myDir[ iDir ] );
1886 double locR[2] = { 0, 0 };
1887 for ( iDir = 0; iDir < 2; iDir++ )
1889 const int iCoord = 2 - iDir; // coord changing along an isoline
1890 TIsoNode* bndNode1 = node->GetBoundaryNode( iDir, 0 );
1891 TIsoNode* bndNode2 = node->GetBoundaryNode( iDir, 1 );
1892 double par1 = bndNode1->myInitUV.Coord( iCoord );
1893 double par2 = node->myInitUV.Coord( iCoord );
1894 double par3 = bndNode2->myInitUV.Coord( iCoord );
1895 double r = ( par2 - par1 ) / ( par3 - par1 );
1896 r = Abs ( r - 0.5 ) * 2.0; // [0,1] - distance from the middle
1897 locR[ iDir ] = ( 1 - r * r ) * 0.25;
1899 //locR[0] = locR[1] = 0.25;
1900 // intersect the 2 lines and move a node
1901 //IntAna2d_AnaIntersection inter( line[0], line[1] );
1902 if ( /*inter.IsDone() && inter.NbPoints() ==*/ 1 )
1904 // double intR = 1 - locR[0] - locR[1];
1905 // gp_XY newUV = inter.Point(1).Value().XY();
1906 // if ( !checkQuads( node, newUV, reversed, CHECK_NEW_IN ))
1907 // newUV = ( locR[0] * loc[0] + locR[1] * loc[1] ) / ( 1 - intR );
1909 // newUV = intR * newUV + locR[0] * loc[0] + locR[1] * loc[1];
1910 gp_XY newUV = 0.5 * ( loc[0] + loc[1] );
1911 // avoid parallel isolines intersection
1912 checkQuads( node, newUV, reversed );
1914 maxMove = Max( maxMove, ( newUV - node->myUV ).SquareModulus());
1916 } // intersection found
1917 #ifdef DEB_COMPUVBYELASTICISOLINES
1918 if (useNbMoveNode && ++nbNodeMove >= maxNbNodeMove ) break;
1920 } // loop on internal nodes
1921 #ifdef DEB_COMPUVBYELASTICISOLINES
1922 if (useNbMoveNode && nbNodeMove >= maxNbNodeMove ) break;
1924 } while ( maxMove > 1e-8 && nbIter++ < maxNbIter );
1926 MESSAGE( "compUVByElasticIsolines(): Nb iterations " << nbIter << " dist: " << sqrt( maxMove ));
1928 if ( nbIter >= maxNbIter && sqrt(maxMove) > minUvSize * 0.05 ) {
1929 MESSAGE( "compUVByElasticIsolines() failed: "<<sqrt(maxMove)<<">"<<minUvSize * 0.05);
1930 #ifndef DEB_COMPUVBYELASTICISOLINES
1935 // Set computed UV to points
1937 for ( pIt = thePntToCompute.begin(); pIt != thePntToCompute.end(); pIt++ ) {
1938 TPoint* point = *pIt;
1939 //gp_XY oldUV = point->myUV;
1940 double minDist = DBL_MAX;
1941 list < TIsoNode >::iterator nIt = nodes.begin();
1942 for ( ; nIt != nodes.end(); nIt++ ) {
1943 double dist = ( (*nIt).myInitUV - point->myInitUV ).SquareModulus();
1944 if ( dist < minDist ) {
1946 point->myUV = (*nIt).myUV;
1956 //=======================================================================
1957 //function : setFirstEdge
1958 //purpose : choose the best first edge of theWire; return the summary distance
1959 // between point UV computed by isolines intersection and
1960 // eventual UV got from edge p-curves
1961 //=======================================================================
1963 //#define DBG_SETFIRSTEDGE
1964 double SMESH_Pattern::setFirstEdge (list< TopoDS_Edge > & theWire, int theFirstEdgeID)
1966 int iE, nbEdges = theWire.size();
1970 // Transform UVs computed by iso to fit bnd box of a wire
1972 // max nb of points on an edge
1974 int eID = theFirstEdgeID;
1975 for ( iE = 0; iE < nbEdges; iE++ )
1976 maxNbPnt = Max ( maxNbPnt, getShapePoints( eID++ ).size() );
1978 // compute bnd boxes
1979 TopoDS_Face face = TopoDS::Face( myShape );
1980 Bnd_Box2d bndBox, eBndBox;
1981 eID = theFirstEdgeID;
1982 list< TopoDS_Edge >::iterator eIt;
1983 list< TPoint* >::iterator pIt;
1984 for ( eIt = theWire.begin(); eIt != theWire.end(); eIt++ )
1986 // UV by isos stored in TPoint.myXYZ
1987 list< TPoint* > & ePoints = getShapePoints( eID++ );
1988 for ( pIt = ePoints.begin(); pIt != ePoints.end(); pIt++ ) {
1990 bndBox.Add( gp_Pnt2d( p->myXYZ.X(), p->myXYZ.Y() ));
1992 // UV by an edge p-curve
1994 Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface( *eIt, face, f, l );
1995 double dU = ( l - f ) / ( maxNbPnt - 1 );
1996 for ( int i = 0; i < maxNbPnt; i++ )
1997 eBndBox.Add( C2d->Value( f + i * dU ));
2000 // transform UVs by isos
2001 double minPar[2], maxPar[2], eMinPar[2], eMaxPar[2];
2002 bndBox.Get( minPar[0], minPar[1], maxPar[0], maxPar[1] );
2003 eBndBox.Get( eMinPar[0], eMinPar[1], eMaxPar[0], eMaxPar[1] );
2004 #ifdef DBG_SETFIRSTEDGE
2005 cout << "EDGES: X: " << eMinPar[0] << " - " << eMaxPar[0] << " Y: "
2006 << eMinPar[1] << " - " << eMaxPar[1] << endl;
2008 for ( int iC = 1, i = 0; i < 2; iC++, i++ ) // loop on 2 coordinates
2010 double dMin = eMinPar[i] - minPar[i];
2011 double dMax = eMaxPar[i] - maxPar[i];
2012 double dPar = maxPar[i] - minPar[i];
2013 eID = theFirstEdgeID;
2014 for ( iE = 0; iE < nbEdges; iE++ ) // loop on edges of a boundary
2016 list< TPoint* > & ePoints = getShapePoints( eID++ );
2017 for ( pIt = ++ePoints.begin(); pIt != ePoints.end(); pIt++ ) // loop on edge points
2019 double par = (*pIt)->myXYZ.Coord( iC );
2020 double r = ( par - minPar[i] ) / dPar;
2021 par += ( 1 - r ) * dMin + r * dMax;
2022 (*pIt)->myXYZ.SetCoord( iC, par );
2028 double minDist = DBL_MAX;
2029 for ( iE = 0 ; iE < nbEdges; iE++ )
2031 #ifdef DBG_SETFIRSTEDGE
2032 cout << " VARIANT " << iE << endl;
2034 // evaluate the distance between UV computed by the 2 methods:
2035 // by isos intersection ( myXYZ ) and by edge p-curves ( myUV )
2037 int eID = theFirstEdgeID;
2038 for ( eIt = theWire.begin(); eIt != theWire.end(); eIt++ )
2040 list< TPoint* > & ePoints = getShapePoints( eID++ );
2041 computeUVOnEdge( *eIt, ePoints );
2042 for ( pIt = ++ePoints.begin(); pIt != ePoints.end(); pIt++ ) {
2044 dist += ( p->myUV - gp_XY( p->myXYZ.X(), p->myXYZ.Y() )).SquareModulus();
2045 #ifdef DBG_SETFIRSTEDGE
2046 cout << " ISO : ( " << p->myXYZ.X() << ", "<< p->myXYZ.Y() << " ) PCURVE : ( " <<
2047 p->myUV.X() << ", " << p->myUV.Y() << ") " << endl;
2051 #ifdef DBG_SETFIRSTEDGE
2052 cout << "dist -- " << dist << endl;
2054 if ( dist < minDist ) {
2056 eBest = theWire.front();
2058 // check variant with another first edge
2059 theWire.splice( theWire.begin(), theWire, --theWire.end(), theWire.end() );
2061 // put the best first edge to the theWire front
2062 if ( eBest != theWire.front() ) {
2063 eIt = find ( theWire.begin(), theWire.end(), eBest );
2064 theWire.splice( theWire.begin(), theWire, eIt, theWire.end() );
2070 //=======================================================================
2071 //function : sortSameSizeWires
2072 //purpose : sort wires in theWireList from theFromWire until theToWire,
2073 // the wires are set in the order to correspond to the order
2074 // of boundaries; after sorting, edges in the wires are put
2075 // in a good order, point UVs on edges are computed and points
2076 // are appended to theEdgesPointsList
2077 //=======================================================================
2079 bool SMESH_Pattern::sortSameSizeWires (TListOfEdgesList & theWireList,
2080 const TListOfEdgesList::iterator& theFromWire,
2081 const TListOfEdgesList::iterator& theToWire,
2082 const int theFirstEdgeID,
2083 list< list< TPoint* > >& theEdgesPointsList )
2085 TopoDS_Face F = TopoDS::Face( myShape );
2086 int iW, nbWires = 0;
2087 TListOfEdgesList::iterator wlIt = theFromWire;
2088 while ( wlIt++ != theToWire )
2091 // Recompute key-point UVs by isolines intersection,
2092 // compute CG of key-points for each wire and bnd boxes of GCs
2095 gp_XY orig( gp::Origin2d().XY() );
2096 vector< gp_XY > vGcVec( nbWires, orig ), gcVec( nbWires, orig );
2097 Bnd_Box2d bndBox, vBndBox;
2098 int eID = theFirstEdgeID;
2099 list< TopoDS_Edge >::iterator eIt;
2100 for ( iW = 0, wlIt = theFromWire; wlIt != theToWire; wlIt++, iW++ )
2102 list< TopoDS_Edge > & wire = *wlIt;
2103 for ( eIt = wire.begin(); eIt != wire.end(); eIt++ )
2105 list< TPoint* > & ePoints = getShapePoints( eID++ );
2106 TPoint* p = ePoints.front();
2107 if ( !compUVByIsoIntersection( theEdgesPointsList, p->myInitUV, p->myUV, aBool )) {
2108 MESSAGE("cant sortSameSizeWires()");
2111 gcVec[iW] += p->myUV;
2112 bndBox.Add( gp_Pnt2d( p->myUV ));
2113 TopoDS_Vertex V = TopExp::FirstVertex( *eIt, true );
2114 gp_Pnt2d vXY = BRep_Tool::Parameters( V, F );
2115 vGcVec[iW] += vXY.XY();
2117 // keep the computed UV to compare against by setFirstEdge()
2118 p->myXYZ.SetCoord( p->myUV.X(), p->myUV.Y(), 0. );
2120 gcVec[iW] /= nbWires;
2121 vGcVec[iW] /= nbWires;
2122 // cout << " Wire " << iW << " iso: " << gcVec[iW].X() << " " << gcVec[iW].Y() << endl <<
2123 // " \t vertex: " << vGcVec[iW].X() << " " << vGcVec[iW].Y() << endl;
2126 // Transform GCs computed by isos to fit in bnd box of GCs by vertices
2128 double minPar[2], maxPar[2], vMinPar[2], vMaxPar[2];
2129 bndBox.Get( minPar[0], minPar[1], maxPar[0], maxPar[1] );
2130 vBndBox.Get( vMinPar[0], vMinPar[1], vMaxPar[0], vMaxPar[1] );
2131 for ( int iC = 1, i = 0; i < 2; iC++, i++ ) // loop on 2 coordinates
2133 double dMin = vMinPar[i] - minPar[i];
2134 double dMax = vMaxPar[i] - maxPar[i];
2135 double dPar = maxPar[i] - minPar[i];
2136 if ( Abs( dPar ) <= DBL_MIN )
2138 for ( iW = 0; iW < nbWires; iW++ ) { // loop on GCs of wires
2139 double par = gcVec[iW].Coord( iC );
2140 double r = ( par - minPar[i] ) / dPar;
2141 par += ( 1 - r ) * dMin + r * dMax;
2142 gcVec[iW].SetCoord( iC, par );
2146 // Define boundary - wire correspondence by GC closeness
2148 TListOfEdgesList tmpWList;
2149 tmpWList.splice( tmpWList.end(), theWireList, theFromWire, theToWire );
2150 typedef map< int, TListOfEdgesList::iterator > TIntWirePosMap;
2151 TIntWirePosMap bndIndWirePosMap;
2152 vector< bool > bndFound( nbWires, false );
2153 for ( iW = 0, wlIt = tmpWList.begin(); iW < nbWires; iW++, wlIt++ )
2155 // cout << " TRSF Wire " << iW << " iso: " << gcVec[iW].X() << " " << gcVec[iW].Y() << endl <<
2156 // " \t vertex: " << vGcVec[iW].X() << " " << vGcVec[iW].Y() << endl;
2157 double minDist = DBL_MAX;
2158 gp_XY & wGc = vGcVec[ iW ];
2160 for ( int iB = 0; iB < nbWires; iB++ ) {
2161 if ( bndFound[ iB ] ) continue;
2162 double dist = ( wGc - gcVec[ iB ] ).SquareModulus();
2163 if ( dist < minDist ) {
2168 bndFound[ bIndex ] = true;
2169 bndIndWirePosMap.insert( TIntWirePosMap::value_type( bIndex, wlIt ));
2174 TIntWirePosMap::iterator bIndWPosIt = bndIndWirePosMap.begin();
2175 eID = theFirstEdgeID;
2176 for ( ; bIndWPosIt != bndIndWirePosMap.end(); bIndWPosIt++ )
2178 TListOfEdgesList::iterator wirePos = (*bIndWPosIt).second;
2179 list < TopoDS_Edge > & wire = ( *wirePos );
2181 // choose the best first edge of a wire
2182 setFirstEdge( wire, eID );
2184 // compute eventual UV and fill theEdgesPointsList
2185 theEdgesPointsList.push_back( list< TPoint* >() );
2186 list< TPoint* > & edgesPoints = theEdgesPointsList.back();
2187 for ( eIt = wire.begin(); eIt != wire.end(); eIt++ )
2189 list< TPoint* > & ePoints = getShapePoints( eID++ );
2190 computeUVOnEdge( *eIt, ePoints );
2191 edgesPoints.insert( edgesPoints.end(), ePoints.begin(), (--ePoints.end()));
2193 // put wire back to theWireList
2195 theWireList.splice( theToWire, tmpWList, wlIt, wirePos );
2201 //=======================================================================
2203 //purpose : Compute nodes coordinates applying
2204 // the loaded pattern to <theFace>. The first key-point
2205 // will be mapped into <theVertexOnKeyPoint1>
2206 //=======================================================================
2208 bool SMESH_Pattern::Apply (const TopoDS_Face& theFace,
2209 const TopoDS_Vertex& theVertexOnKeyPoint1,
2210 const bool theReverse)
2212 MESSAGE(" ::Apply(face) " );
2213 TopoDS_Face face = theReverse ? TopoDS::Face( theFace.Reversed() ) : theFace;
2214 if ( !setShapeToMesh( face ))
2217 // find points on edges, it fills myNbKeyPntInBoundary
2218 if ( !findBoundaryPoints() )
2221 // Define the edges order so that the first edge starts at
2222 // theVertexOnKeyPoint1
2224 list< TopoDS_Edge > eList;
2225 list< int > nbVertexInWires;
2226 int nbWires = getOrderedEdges( face, theVertexOnKeyPoint1, eList, nbVertexInWires);
2227 if ( !theVertexOnKeyPoint1.IsSame( TopExp::FirstVertex( eList.front(), true )))
2229 MESSAGE( " theVertexOnKeyPoint1 not found in the outer wire ");
2230 return setErrorCode( ERR_APPLF_BAD_VERTEX );
2232 // check nb wires and edges
2233 list< int > l1 = myNbKeyPntInBoundary, l2 = nbVertexInWires;
2234 l1.sort(); l2.sort();
2237 MESSAGE( "Wrong nb vertices in wires" );
2238 return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
2241 // here shapes get IDs, for the outer wire IDs are OK
2242 list<TopoDS_Edge>::iterator elIt = eList.begin();
2243 for ( ; elIt != eList.end(); elIt++ ) {
2244 myShapeIDMap.Add( TopExp::FirstVertex( *elIt, true ));
2245 if ( BRep_Tool::IsClosed( *elIt, theFace ) )
2246 myShapeIDMap.Add( TopExp::LastVertex( *elIt, true ));
2248 int nbVertices = myShapeIDMap.Extent();
2250 for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
2251 myShapeIDMap.Add( *elIt );
2253 myShapeIDMap.Add( face );
2255 if ( myShapeIDToPointsMap.size() != myShapeIDMap.Extent()/* + nbSeamShapes*/ ) {
2256 MESSAGE( myShapeIDToPointsMap.size() <<" != " << myShapeIDMap.Extent());
2257 return setErrorCode( ERR_APPLF_INTERNAL_EEROR );
2260 // points on edges to be used for UV computation of in-face points
2261 list< list< TPoint* > > edgesPointsList;
2262 edgesPointsList.push_back( list< TPoint* >() );
2263 list< TPoint* > * edgesPoints = & edgesPointsList.back();
2264 list< TPoint* >::iterator pIt;
2266 // compute UV of points on the outer wire
2267 int iE, nbEdgesInOuterWire = nbVertexInWires.front();
2268 for (iE = 0, elIt = eList.begin();
2269 iE < nbEdgesInOuterWire && elIt != eList.end();
2272 list< TPoint* > & ePoints = getShapePoints( *elIt );
2274 computeUVOnEdge( *elIt, ePoints );
2275 // collect on-edge points (excluding the last one)
2276 edgesPoints->insert( edgesPoints->end(), ePoints.begin(), --ePoints.end());
2279 // If there are several wires, define the order of edges of inner wires:
2280 // compute UV of inner edge-points using 2 methods: the one for in-face points
2281 // and the one for on-edge points and then choose the best edge order
2282 // by the best correspondance of the 2 results
2285 // compute UV of inner edge-points using the method for in-face points
2286 // and devide eList into a list of separate wires
2288 list< list< TopoDS_Edge > > wireList;
2289 list<TopoDS_Edge>::iterator eIt = elIt;
2290 list<int>::iterator nbEIt = nbVertexInWires.begin();
2291 for ( nbEIt++; nbEIt != nbVertexInWires.end(); nbEIt++ )
2293 int nbEdges = *nbEIt;
2294 wireList.push_back( list< TopoDS_Edge >() );
2295 list< TopoDS_Edge > & wire = wireList.back();
2296 for ( iE = 0 ; iE < nbEdges; eIt++, iE++ )
2298 list< TPoint* > & ePoints = getShapePoints( *eIt );
2299 pIt = ePoints.begin();
2300 for ( pIt++; pIt != ePoints.end(); pIt++ ) {
2302 if ( !compUVByIsoIntersection( edgesPointsList, p->myInitUV, p->myUV, aBool )) {
2303 MESSAGE("cant Apply(face)");
2306 // keep the computed UV to compare against by setFirstEdge()
2307 p->myXYZ.SetCoord( p->myUV.X(), p->myUV.Y(), 0. );
2309 wire.push_back( *eIt );
2312 // remove inner edges from eList
2313 eList.erase( elIt, eList.end() );
2315 // sort wireList by nb edges in a wire
2316 sortBySize< TopoDS_Edge > ( wireList );
2318 // an ID of the first edge of a boundary
2319 int id1 = nbVertices + nbEdgesInOuterWire + 1;
2320 // if ( nbSeamShapes > 0 )
2321 // id1 += 2; // 2 vertices more
2323 // find points - edge correspondence for wires of unique size,
2324 // edge order within a wire should be defined only
2326 list< list< TopoDS_Edge > >::iterator wlIt = wireList.begin();
2327 while ( wlIt != wireList.end() )
2329 list< TopoDS_Edge >& wire = (*wlIt);
2330 int nbEdges = wire.size();
2332 if ( wlIt == wireList.end() || (*wlIt).size() != nbEdges ) // a unique size wire
2334 // choose the best first edge of a wire
2335 setFirstEdge( wire, id1 );
2337 // compute eventual UV and collect on-edge points
2338 edgesPointsList.push_back( list< TPoint* >() );
2339 edgesPoints = & edgesPointsList.back();
2341 for ( eIt = wire.begin(); eIt != wire.end(); eIt++ )
2343 list< TPoint* > & ePoints = getShapePoints( eID++ );
2344 computeUVOnEdge( *eIt, ePoints );
2345 edgesPoints->insert( edgesPoints->end(), ePoints.begin(), (--ePoints.end()));
2351 // find boundary - wire correspondence for several wires of same size
2353 id1 = nbVertices + nbEdgesInOuterWire + 1;
2354 wlIt = wireList.begin();
2355 while ( wlIt != wireList.end() )
2357 int nbSameSize = 0, nbEdges = (*wlIt).size();
2358 list< list< TopoDS_Edge > >::iterator wlIt2 = wlIt;
2360 while ( wlIt2 != wireList.end() && (*wlIt2).size() == nbEdges ) { // a same size wire
2364 if ( nbSameSize > 0 )
2365 if (!sortSameSizeWires(wireList, wlIt, wlIt2, id1, edgesPointsList))
2368 id1 += nbEdges * ( nbSameSize + 1 );
2371 // add well-ordered edges to eList
2373 for ( wlIt = wireList.begin(); wlIt != wireList.end(); wlIt++ )
2375 list< TopoDS_Edge >& wire = (*wlIt);
2376 eList.splice( eList.end(), wire, wire.begin(), wire.end() );
2379 // re-fill myShapeIDMap - all shapes get good IDs
2381 myShapeIDMap.Clear();
2382 for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
2383 myShapeIDMap.Add( TopExp::FirstVertex( *elIt, true ));
2384 for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
2385 myShapeIDMap.Add( *elIt );
2386 myShapeIDMap.Add( face );
2388 } // there are inner wires
2390 // Compute XYZ of on-edge points
2392 TopLoc_Location loc;
2393 for ( iE = nbVertices + 1, elIt = eList.begin(); elIt != eList.end(); elIt++ )
2396 Handle(Geom_Curve) C3d = BRep_Tool::Curve( *elIt, loc, f, l );
2397 const gp_Trsf & aTrsf = loc.Transformation();
2398 list< TPoint* > & ePoints = getShapePoints( iE++ );
2399 pIt = ePoints.begin();
2400 for ( pIt++; pIt != ePoints.end(); pIt++ )
2402 TPoint* point = *pIt;
2403 point->myXYZ = C3d->Value( point->myU );
2404 if ( !loc.IsIdentity() )
2405 aTrsf.Transforms( point->myXYZ.ChangeCoord() );
2409 // Compute UV and XYZ of in-face points
2411 // try to use a simple algo
2412 list< TPoint* > & fPoints = getShapePoints( face );
2413 bool isDeformed = false;
2414 for ( pIt = fPoints.begin(); !isDeformed && pIt != fPoints.end(); pIt++ )
2415 if ( !compUVByIsoIntersection( edgesPointsList, (*pIt)->myInitUV,
2416 (*pIt)->myUV, isDeformed )) {
2417 MESSAGE("cant Apply(face)");
2420 // try to use a complex algo if it is a difficult case
2421 if ( isDeformed && !compUVByElasticIsolines( edgesPointsList, fPoints ))
2423 for ( ; pIt != fPoints.end(); pIt++ ) // continue with the simple algo
2424 if ( !compUVByIsoIntersection( edgesPointsList, (*pIt)->myInitUV,
2425 (*pIt)->myUV, isDeformed )) {
2426 MESSAGE("cant Apply(face)");
2431 Handle(Geom_Surface) aSurface = BRep_Tool::Surface( face, loc );
2432 const gp_Trsf & aTrsf = loc.Transformation();
2433 for ( pIt = fPoints.begin(); pIt != fPoints.end(); pIt++ )
2435 TPoint * point = *pIt;
2436 point->myXYZ = aSurface->Value( point->myUV.X(), point->myUV.Y() );
2437 if ( !loc.IsIdentity() )
2438 aTrsf.Transforms( point->myXYZ.ChangeCoord() );
2441 myIsComputed = true;
2443 return setErrorCode( ERR_OK );
2446 //=======================================================================
2448 //purpose : Compute nodes coordinates applying
2449 // the loaded pattern to <theFace>. The first key-point
2450 // will be mapped into <theNodeIndexOnKeyPoint1>-th node
2451 //=======================================================================
2453 bool SMESH_Pattern::Apply (const SMDS_MeshFace* theFace,
2454 const int theNodeIndexOnKeyPoint1,
2455 const bool theReverse)
2457 MESSAGE(" ::Apply(MeshFace) " );
2459 if ( !IsLoaded() ) {
2460 MESSAGE( "Pattern not loaded" );
2461 return setErrorCode( ERR_APPL_NOT_LOADED );
2464 // check nb of nodes
2465 if (theFace->NbNodes() != myNbKeyPntInBoundary.front() ) {
2466 MESSAGE( myKeyPointIDs.size() << " != " << theFace->NbNodes() );
2467 return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
2470 // find points on edges, it fills myNbKeyPntInBoundary
2471 if ( !findBoundaryPoints() )
2474 // check that there are no holes in a pattern
2475 if (myNbKeyPntInBoundary.size() > 1 ) {
2476 return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
2479 // Define the nodes order
2481 list< const SMDS_MeshNode* > nodes;
2482 list< const SMDS_MeshNode* >::iterator n = nodes.end();
2483 SMDS_ElemIteratorPtr noIt = theFace->nodesIterator();
2485 while ( noIt->more() ) {
2486 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( noIt->next() );
2487 nodes.push_back( node );
2488 if ( iSub++ == theNodeIndexOnKeyPoint1 )
2491 if ( n != nodes.end() ) {
2493 if ( n != --nodes.end() )
2494 nodes.splice( nodes.begin(), nodes, ++n, nodes.end() );
2497 else if ( n != nodes.begin() )
2498 nodes.splice( nodes.end(), nodes, nodes.begin(), n );
2500 list< gp_XYZ > xyzList;
2501 myOrderedNodes.resize( theFace->NbNodes() );
2502 for ( iSub = 0, n = nodes.begin(); n != nodes.end(); ++n ) {
2503 xyzList.push_back( gp_XYZ( (*n)->X(), (*n)->Y(), (*n)->Z() ));
2504 myOrderedNodes[ iSub++] = *n;
2507 // Define a face plane
2509 list< gp_XYZ >::iterator xyzIt = xyzList.begin();
2510 gp_Pnt P ( *xyzIt++ );
2511 gp_Vec Vx( P, *xyzIt++ ), N;
2513 N = Vx ^ gp_Vec( P, *xyzIt++ );
2514 } while ( N.SquareMagnitude() <= DBL_MIN && xyzIt != xyzList.end() );
2515 if ( N.SquareMagnitude() <= DBL_MIN )
2516 return setErrorCode( ERR_APPLF_BAD_FACE_GEOM );
2517 gp_Ax2 pos( P, N, Vx );
2519 // Compute UV of key-points on a plane
2520 for ( xyzIt = xyzList.begin(), iSub = 1; xyzIt != xyzList.end(); xyzIt++, iSub++ )
2522 gp_Vec vec ( pos.Location(), *xyzIt );
2523 TPoint* p = getShapePoints( iSub ).front();
2524 p->myUV.SetX( vec * pos.XDirection() );
2525 p->myUV.SetY( vec * pos.YDirection() );
2529 // points on edges to be used for UV computation of in-face points
2530 list< list< TPoint* > > edgesPointsList;
2531 edgesPointsList.push_back( list< TPoint* >() );
2532 list< TPoint* > * edgesPoints = & edgesPointsList.back();
2533 list< TPoint* >::iterator pIt;
2535 // compute UV and XYZ of points on edges
2537 for ( xyzIt = xyzList.begin(); xyzIt != xyzList.end(); iSub++ )
2539 gp_XYZ& xyz1 = *xyzIt++;
2540 gp_XYZ& xyz2 = ( xyzIt != xyzList.end() ) ? *xyzIt : xyzList.front();
2542 list< TPoint* > & ePoints = getShapePoints( iSub );
2543 ePoints.back()->myInitU = 1.0;
2544 list< TPoint* >::const_iterator pIt = ++ePoints.begin();
2545 while ( *pIt != ePoints.back() )
2548 p->myXYZ = xyz1 * ( 1 - p->myInitU ) + xyz2 * p->myInitU;
2549 gp_Vec vec ( pos.Location(), p->myXYZ );
2550 p->myUV.SetX( vec * pos.XDirection() );
2551 p->myUV.SetY( vec * pos.YDirection() );
2553 // collect on-edge points (excluding the last one)
2554 edgesPoints->insert( edgesPoints->end(), ePoints.begin(), --ePoints.end());
2557 // Compute UV and XYZ of in-face points
2559 // try to use a simple algo to compute UV
2560 list< TPoint* > & fPoints = getShapePoints( iSub );
2561 bool isDeformed = false;
2562 for ( pIt = fPoints.begin(); !isDeformed && pIt != fPoints.end(); pIt++ )
2563 if ( !compUVByIsoIntersection( edgesPointsList, (*pIt)->myInitUV,
2564 (*pIt)->myUV, isDeformed )) {
2565 MESSAGE("cant Apply(face)");
2568 // try to use a complex algo if it is a difficult case
2569 if ( isDeformed && !compUVByElasticIsolines( edgesPointsList, fPoints ))
2571 for ( ; pIt != fPoints.end(); pIt++ ) // continue with the simple algo
2572 if ( !compUVByIsoIntersection( edgesPointsList, (*pIt)->myInitUV,
2573 (*pIt)->myUV, isDeformed )) {
2574 MESSAGE("cant Apply(face)");
2579 for ( pIt = fPoints.begin(); pIt != fPoints.end(); pIt++ )
2581 (*pIt)->myXYZ = ElSLib::PlaneValue( (*pIt)->myUV.X(), (*pIt)->myUV.Y(), pos );
2584 myIsComputed = true;
2586 return setErrorCode( ERR_OK );
2589 //=======================================================================
2590 //function : undefinedXYZ
2592 //=======================================================================
2594 static const gp_XYZ& undefinedXYZ()
2596 static gp_XYZ xyz( 1.e100, 0., 0. );
2600 //=======================================================================
2601 //function : isDefined
2603 //=======================================================================
2605 inline static bool isDefined(const gp_XYZ& theXYZ)
2607 return theXYZ.X() < 1.e100;
2610 //=======================================================================
2611 //function : mergePoints
2612 //purpose : Look for coincident points between myXYZs indexed with
2613 // list<int> of each element of xyzIndGroups. Coincident indices
2614 // are merged in myElemXYZIDs.
2615 //=======================================================================
2617 void SMESH_Pattern::mergePoints (map<TNodeSet, list<list<int> > >& indGroups,
2618 map< int, list< list< int >* > > & reverseConnectivity)
2620 map< TNodeSet, list< list< int > > >::iterator indListIt;
2621 for ( indListIt = indGroups.begin(); indListIt != indGroups.end(); indListIt++ )
2623 list<list< int > > groups = indListIt->second;
2624 if ( groups.size() < 2 )
2627 // const TNodeSet & nodes = indListIt->first;
2628 // TNodeSet::const_iterator n = nodes.begin();
2629 // for ( ; n != nodes.end(); n++ )
2634 list< int >& indices = groups.front();
2635 list< int >::iterator ind, ind1, ind2;
2636 for ( ind = indices.begin(); ind != indices.end(); ind++ )
2637 box.Add( gp_Pnt( myXYZ[ *ind ]));
2638 double x, y, z, X, Y, Z;
2639 box.Get( x, y, z, X, Y, Z );
2640 gp_Pnt p( x, y, z ), P( X, Y, Z );
2641 double tol2 = 1.e-4 * p.SquareDistance( P );
2643 // compare points, replace indices
2645 list< list< int > >::iterator grpIt1, grpIt2;
2646 for ( grpIt1 = groups.begin(); grpIt1 != groups.end(); grpIt1++ )
2648 list< int >& indices1 = *grpIt1;
2650 for ( grpIt2++; grpIt2 != groups.end(); grpIt2++ )
2652 list< int >& indices2 = *grpIt2;
2653 for ( ind1 = indices1.begin(); ind1 != indices1.end(); ind1++ )
2655 gp_XYZ& p1 = myXYZ[ *ind1 ];
2656 ind2 = indices2.begin();
2657 while ( ind2 != indices2.end() )
2659 gp_XYZ& p2 = myXYZ[ *ind2 ];
2660 //MESSAGE("COMP: " << *ind1 << " " << *ind2 << " X: " << p2.X() << " tol2: " << tol2);
2661 if ( ( p1 - p2 ).SquareModulus() <= tol2 )
2663 ASSERT( reverseConnectivity.find( *ind2 ) != reverseConnectivity.end() );
2664 list< list< int >* > & elemXYZIDsList = reverseConnectivity[ *ind2 ];
2665 list< list< int >* >::iterator elemXYZIDs = elemXYZIDsList.begin();
2666 for ( ; elemXYZIDs != elemXYZIDsList.end(); elemXYZIDs++ )
2668 ind = find( (*elemXYZIDs)->begin(), (*elemXYZIDs)->end(), *ind2 );
2669 //MESSAGE( " Replace " << *ind << " with " << *ind1 );
2670 myXYZ[ *ind ] = undefinedXYZ();
2673 ind2 = indices2.erase( ind2 );
2684 //=======================================================================
2686 //purpose : Compute nodes coordinates applying
2687 // the loaded pattern to <theFaces>. The first key-point
2688 // will be mapped into <theNodeIndexOnKeyPoint1>-th node
2689 //=======================================================================
2691 bool SMESH_Pattern::Apply (std::set<const SMDS_MeshFace*> theFaces,
2692 const int theNodeIndexOnKeyPoint1,
2693 const bool theReverse)
2695 MESSAGE(" ::Apply(set<MeshFace>) " );
2697 if ( !IsLoaded() ) {
2698 MESSAGE( "Pattern not loaded" );
2699 return setErrorCode( ERR_APPL_NOT_LOADED );
2702 // find points on edges, it fills myNbKeyPntInBoundary
2703 if ( !findBoundaryPoints() )
2706 // check that there are no holes in a pattern
2707 if (myNbKeyPntInBoundary.size() > 1 ) {
2708 return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
2712 myElemXYZIDs.clear();
2713 myXYZIdToNodeMap.clear();
2716 myXYZ.resize( myPoints.size() * theFaces.size(), undefinedXYZ() );
2717 myElements.reserve( theFaces.size() );
2719 // to find point index
2720 map< TPoint*, int > pointIndex;
2721 for ( int i = 0; i < myPoints.size(); i++ )
2722 pointIndex.insert( make_pair( & myPoints[ i ], i ));
2724 // to merge nodes on edges of the elements being refined
2725 typedef set<const SMDS_MeshNode*> TLink;
2726 map< TLink, list< list< int > > > linkPointIndListMap;
2727 map< int, list< list< int >* > > reverseConnectivity;
2729 int ind1 = 0; // lowest point index for a face
2731 // apply to each face in theFaces set
2732 set<const SMDS_MeshFace*>::iterator face = theFaces.begin();
2733 for ( ; face != theFaces.end(); ++face )
2735 if ( !Apply( *face, theNodeIndexOnKeyPoint1, theReverse )) {
2736 MESSAGE( "Failed on " << *face );
2739 myElements.push_back( *face );
2741 // store computed points belonging to elements
2742 list< list< int > >::iterator ll = myElemPointIDs.begin();
2743 for ( ; ll != myElemPointIDs.end(); ++ll )
2745 myElemXYZIDs.push_back();
2746 list< int >& xyzIds = myElemXYZIDs.back();
2747 list< int >& pIds = *ll;
2748 for ( list<int>::iterator id = pIds.begin(); id != pIds.end(); id++ ) {
2749 int pIndex = *id + ind1;
2750 xyzIds.push_back( pIndex );
2751 myXYZ[ pIndex ] = myPoints[ *id ].myXYZ.XYZ();
2752 reverseConnectivity[ pIndex ].push_back( & xyzIds );
2755 // put points on links to linkPointIndListMap
2756 int nbNodes = (*face)->NbNodes(), eID = nbNodes + 1;
2757 for ( int i = 0; i < nbNodes; i++ )
2759 const SMDS_MeshNode* n1 = myOrderedNodes[ i ];
2760 const SMDS_MeshNode* n2 = myOrderedNodes[ i + 1 == nbNodes ? 0 : i + 1 ];
2761 // make a link of node pointers
2765 // add the link to the map
2766 list< list< int > >& groups = linkPointIndListMap[ link ];
2768 list< int >& indList = groups.back();
2769 list< TPoint* > & linkPoints = getShapePoints( eID++ );
2770 list< TPoint* >::iterator p = linkPoints.begin();
2771 // map the first link point to n1
2772 myXYZIdToNodeMap[ pointIndex[ *p ] + ind1 ] = n1;
2773 // add points to the map excluding the end points
2774 for ( p++; *p != linkPoints.back(); p++ )
2775 indList.push_back( pointIndex[ *p ] + ind1 );
2777 ind1 += myPoints.size();
2780 mergePoints( linkPointIndListMap, reverseConnectivity );
2782 return !myElemXYZIDs.empty();
2785 //=======================================================================
2787 //purpose : Compute nodes coordinates applying
2788 // the loaded pattern to <theVolumes>. The (0,0,0) key-point
2789 // will be mapped into <theNode000Index>-th node. The
2790 // (0,0,1) key-point will be mapped into <theNode000Index>-th
2792 //=======================================================================
2794 bool SMESH_Pattern::Apply (std::set<const SMDS_MeshVolume*> theVolumes,
2795 const int theNode000Index,
2796 const int theNode001Index)
2798 MESSAGE(" ::Apply(set<MeshVolumes>) " );
2800 if ( !IsLoaded() ) {
2801 MESSAGE( "Pattern not loaded" );
2802 return setErrorCode( ERR_APPL_NOT_LOADED );
2805 // bind ID to points
2806 if ( !findBoundaryPoints() )
2809 // check that there are no holes in a pattern
2810 if (myNbKeyPntInBoundary.size() > 1 ) {
2811 return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
2815 myElemXYZIDs.clear();
2816 myXYZIdToNodeMap.clear();
2819 myXYZ.resize( myPoints.size() * theVolumes.size(), undefinedXYZ() );
2820 myElements.reserve( theVolumes.size() );
2822 // to find point index
2823 map< TPoint*, int > pointIndex;
2824 for ( int i = 0; i < myPoints.size(); i++ )
2825 pointIndex.insert( make_pair( & myPoints[ i ], i ));
2827 // to merge nodes on edges and faces of the elements being refined
2828 map< TNodeSet, list< list< int > > > subPointIndListMap;
2829 map< int, list< list< int >* > > reverseConnectivity;
2831 int ind1 = 0; // lowest point index for an element
2833 // apply to each element in theVolumes set
2834 set<const SMDS_MeshVolume*>::iterator vol = theVolumes.begin();
2835 for ( ; vol != theVolumes.end(); ++vol )
2837 if ( !Apply( *vol, theNode000Index, theNode001Index )) {
2838 MESSAGE( "Failed on " << *vol );
2841 myElements.push_back( *vol );
2843 // store computed points belonging to elements
2844 list< list< int > >::iterator ll = myElemPointIDs.begin();
2845 for ( ; ll != myElemPointIDs.end(); ++ll )
2847 myElemXYZIDs.push_back();
2848 list< int >& xyzIds = myElemXYZIDs.back();
2849 list< int >& pIds = *ll;
2850 for ( list<int>::iterator id = pIds.begin(); id != pIds.end(); id++ ) {
2851 int pIndex = *id + ind1;
2852 xyzIds.push_back( pIndex );
2853 myXYZ[ pIndex ] = myPoints[ *id ].myXYZ.XYZ();
2854 reverseConnectivity[ pIndex ].push_back( & xyzIds );
2857 // put points on edges and faces to subPointIndListMap
2858 for ( int Id = SMESH_Block::ID_V000; Id <= SMESH_Block::ID_F1yz; Id++ )
2860 // make a set of sub-points
2862 vector< int > subIDs;
2863 if ( SMESH_Block::IsVertexID( Id )) {
2864 // use nodes of refined volumes for merge
2866 else if ( SMESH_Block::IsEdgeID( Id )) {
2867 SMESH_Block::GetEdgeVertexIDs( Id, subIDs );
2868 subNodes.insert( myOrderedNodes[ subIDs.front() - 1 ]);
2869 subNodes.insert( myOrderedNodes[ subIDs.back() - 1 ]);
2872 SMESH_Block::GetFaceEdgesIDs( Id, subIDs );
2873 int e1 = subIDs[ 0 ], e2 = subIDs[ 1 ];
2874 SMESH_Block::GetEdgeVertexIDs( e1, subIDs );
2875 subNodes.insert( myOrderedNodes[ subIDs.front() - 1 ]);
2876 subNodes.insert( myOrderedNodes[ subIDs.back() - 1 ]);
2877 SMESH_Block::GetEdgeVertexIDs( e2, subIDs );
2878 subNodes.insert( myOrderedNodes[ subIDs.front() - 1 ]);
2879 subNodes.insert( myOrderedNodes[ subIDs.back() - 1 ]);
2881 list< list< int > >& groups = subPointIndListMap[ subNodes ];
2883 list< int >& indList = groups.back();
2885 list< TPoint* > & points = getShapePoints( Id );
2886 list< TPoint* >::iterator p = points.begin();
2887 if ( subNodes.empty() ) // vertex case
2888 myXYZIdToNodeMap[ pointIndex[ *p ] + ind1 ] = myOrderedNodes[ Id - 1 ];
2890 for ( ; p != points.end(); p++ )
2891 indList.push_back( pointIndex[ *p ] + ind1 );
2893 ind1 += myPoints.size();
2896 mergePoints( subPointIndListMap, reverseConnectivity );
2898 return !myElemXYZIDs.empty();
2901 //=======================================================================
2903 //purpose : Create a pattern from the mesh built on <theBlock>
2904 //=======================================================================
2906 bool SMESH_Pattern::Load (SMESH_Mesh* theMesh,
2907 const TopoDS_Shell& theBlock)
2909 MESSAGE(" ::Load(volume) " );
2912 SMESHDS_Mesh * aMeshDS = theMesh->GetMeshDS();
2914 // load shapes in myShapeIDMap
2916 TopoDS_Vertex v1, v2;
2917 if ( !block.LoadBlockShapes( theBlock, v1, v2, myShapeIDMap ))
2918 return setErrorCode( ERR_LOADV_BAD_SHAPE );
2921 int nbNodes = 0, shapeID;
2922 for ( shapeID = 1; shapeID <= myShapeIDMap.Extent(); shapeID++ )
2924 const TopoDS_Shape& S = myShapeIDMap( shapeID );
2925 SMESHDS_SubMesh * aSubMesh = aMeshDS->MeshElements( S );
2927 nbNodes += aSubMesh->NbNodes();
2929 myPoints.resize( nbNodes );
2931 // load U of points on edges
2932 TNodePointIDMap nodePointIDMap;
2934 for ( shapeID = 1; shapeID <= myShapeIDMap.Extent(); shapeID++ )
2936 const TopoDS_Shape& S = myShapeIDMap( shapeID );
2937 list< TPoint* > & shapePoints = getShapePoints( shapeID );
2938 SMESHDS_SubMesh * aSubMesh = aMeshDS->MeshElements( S );
2939 if ( ! aSubMesh ) continue;
2940 SMDS_NodeIteratorPtr nIt = aSubMesh->GetNodes();
2941 if ( !nIt->more() ) continue;
2943 // store a node and a point
2944 while ( nIt->more() ) {
2945 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nIt->next() );
2946 nodePointIDMap.insert( make_pair( node, iPoint ));
2947 if ( block.IsVertexID( shapeID ))
2948 myKeyPointIDs.push_back( iPoint );
2949 TPoint* p = & myPoints[ iPoint++ ];
2950 shapePoints.push_back( p );
2951 p->myXYZ.SetCoord( node->X(), node->Y(), node->Z() );
2952 p->myInitXYZ.SetCoord( 0,0,0 );
2954 list< TPoint* >::iterator pIt = shapePoints.begin();
2957 switch ( S.ShapeType() )
2962 for ( ; pIt != shapePoints.end(); pIt++ ) {
2963 double * coef = block.GetShapeCoef( shapeID );
2964 for ( int iCoord = 1; iCoord <= 3; iCoord++ )
2965 if ( coef[ iCoord - 1] > 0 )
2966 (*pIt)->myInitXYZ.SetCoord( iCoord, 1. );
2968 if ( S.ShapeType() == TopAbs_VERTEX )
2971 const TopoDS_Edge& edge = TopoDS::Edge( S );
2973 BRep_Tool::Range( edge, f, l );
2974 int iCoord = SMESH_Block::GetCoordIndOnEdge( shapeID );
2975 bool isForward = SMESH_Block::IsForwardEdge( edge, myShapeIDMap );
2976 pIt = shapePoints.begin();
2977 nIt = aSubMesh->GetNodes();
2978 for ( ; nIt->more(); pIt++ )
2980 const SMDS_MeshNode* node =
2981 static_cast<const SMDS_MeshNode*>( nIt->next() );
2982 const SMDS_EdgePosition* epos =
2983 static_cast<const SMDS_EdgePosition*>(node->GetPosition().get());
2984 double u = ( epos->GetUParameter() - f ) / ( l - f );
2985 (*pIt)->myInitXYZ.SetCoord( iCoord, isForward ? u : 1 - u );
2990 for ( ; pIt != shapePoints.end(); pIt++ )
2992 if ( !block.ComputeParameters( (*pIt)->myXYZ, (*pIt)->myInitXYZ, shapeID )) {
2993 MESSAGE( "!block.ComputeParameters()" );
2994 return setErrorCode( ERR_LOADV_COMPUTE_PARAMS );
2998 } // loop on block sub-shapes
3002 SMESHDS_SubMesh * aSubMesh = aMeshDS->MeshElements( theBlock );
3005 SMDS_ElemIteratorPtr elemIt = aSubMesh->GetElements();
3006 while ( elemIt->more() ) {
3007 SMDS_ElemIteratorPtr nIt = elemIt->next()->nodesIterator();
3008 myElemPointIDs.push_back( list< int >() );
3009 list< int >& elemPoints = myElemPointIDs.back();
3010 while ( nIt->more() )
3011 elemPoints.push_back( nodePointIDMap[ nIt->next() ]);
3015 myIsBoundaryPointsFound = true;
3017 return setErrorCode( ERR_OK );
3020 //=======================================================================
3022 //purpose : Compute nodes coordinates applying
3023 // the loaded pattern to <theBlock>. The (0,0,0) key-point
3024 // will be mapped into <theVertex000>. The (0,0,1)
3025 // fifth key-point will be mapped into <theVertex001>.
3026 //=======================================================================
3028 bool SMESH_Pattern::Apply (const TopoDS_Shell& theBlock,
3029 const TopoDS_Vertex& theVertex000,
3030 const TopoDS_Vertex& theVertex001)
3032 MESSAGE(" ::Apply(volume) " );
3034 if (!findBoundaryPoints() || // bind ID to points
3035 !setShapeToMesh( theBlock )) // check theBlock is a suitable shape
3038 SMESH_Block block; // bind ID to shape
3039 if (!block.LoadBlockShapes( theBlock, theVertex000, theVertex001, myShapeIDMap ))
3040 return setErrorCode( ERR_APPLV_BAD_SHAPE );
3042 // compute XYZ of points on shapes
3044 for ( int shapeID = 1; shapeID <= myShapeIDMap.Extent(); shapeID++ )
3046 list< TPoint* > & shapePoints = getShapePoints( shapeID );
3047 list< TPoint* >::iterator pIt = shapePoints.begin();
3048 const TopoDS_Shape& S = myShapeIDMap( shapeID );
3049 switch ( S.ShapeType() )
3051 case TopAbs_VERTEX: {
3053 for ( ; pIt != shapePoints.end(); pIt++ )
3054 block.VertexPoint( shapeID, (*pIt)->myXYZ.ChangeCoord() );
3059 for ( ; pIt != shapePoints.end(); pIt++ )
3060 block.EdgePoint( shapeID, (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
3065 for ( ; pIt != shapePoints.end(); pIt++ )
3066 block.FacePoint( shapeID, (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
3070 for ( ; pIt != shapePoints.end(); pIt++ )
3071 block.ShellPoint( (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
3073 } // loop on block sub-shapes
3075 myIsComputed = true;
3077 return setErrorCode( ERR_OK );
3080 //=======================================================================
3082 //purpose : Compute nodes coordinates applying
3083 // the loaded pattern to <theVolume>. The (0,0,0) key-point
3084 // will be mapped into <theNode000Index>-th node. The
3085 // (0,0,1) key-point will be mapped into <theNode000Index>-th
3087 //=======================================================================
3089 bool SMESH_Pattern::Apply (const SMDS_MeshVolume* theVolume,
3090 const int theNode000Index,
3091 const int theNode001Index)
3093 MESSAGE(" ::Apply(MeshVolume) " );
3095 if (!findBoundaryPoints()) // bind ID to points
3098 SMESH_Block block; // bind ID to shape
3099 if (!block.LoadMeshBlock( theVolume, theNode000Index, theNode001Index, myOrderedNodes ))
3100 return setErrorCode( ERR_APPLV_BAD_SHAPE );
3101 // compute XYZ of points on shapes
3103 for ( int ID = SMESH_Block::ID_V000; ID <= SMESH_Block::ID_Shell; ID++ )
3105 list< TPoint* > & shapePoints = getShapePoints( ID );
3106 list< TPoint* >::iterator pIt = shapePoints.begin();
3108 if ( block.IsVertexID( ID ))
3109 for ( ; pIt != shapePoints.end(); pIt++ ) {
3110 block.VertexPoint( ID, (*pIt)->myXYZ.ChangeCoord() );
3112 else if ( block.IsEdgeID( ID ))
3113 for ( ; pIt != shapePoints.end(); pIt++ ) {
3114 block.EdgePoint( ID, (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
3116 else if ( block.IsFaceID( ID ))
3117 for ( ; pIt != shapePoints.end(); pIt++ ) {
3118 block.FacePoint( ID, (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
3121 for ( ; pIt != shapePoints.end(); pIt++ )
3122 block.ShellPoint( (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
3123 } // loop on block sub-shapes
3125 myIsComputed = true;
3127 return setErrorCode( ERR_OK );
3130 //=======================================================================
3131 //function : MakeMesh
3132 //purpose : Create nodes and elements in <theMesh> using nodes
3133 // coordinates computed by either of Apply...() methods
3134 //=======================================================================
3136 bool SMESH_Pattern::MakeMesh(SMESH_Mesh* theMesh)
3138 MESSAGE(" ::MakeMesh() " );
3139 if ( !myIsComputed )
3140 return setErrorCode( ERR_MAKEM_NOT_COMPUTED );
3142 SMESHDS_Mesh* aMeshDS = theMesh->GetMeshDS();
3143 SMESH_MeshEditor editor( theMesh );
3145 // clear elements and nodes existing on myShape
3147 if ( !myShape.IsNull() )
3149 SMESH_subMesh * aSubMesh = theMesh->GetSubMeshContaining( myShape );
3150 SMESHDS_SubMesh * aSubMeshDS = aMeshDS->MeshElements( myShape );
3152 aSubMesh->ComputeStateEngine( SMESH_subMesh::CLEAN );
3153 else if ( aSubMeshDS )
3155 SMDS_ElemIteratorPtr eIt = aSubMeshDS->GetElements();
3156 while ( eIt->more() )
3157 aMeshDS->RemoveElement( eIt->next() );
3158 SMDS_NodeIteratorPtr nIt = aSubMeshDS->GetNodes();
3159 while ( nIt->more() )
3160 aMeshDS->RemoveNode( static_cast<const SMDS_MeshNode*>( nIt->next() ));
3164 bool onMeshElements = ( !myElements.empty() );
3166 // loop on sub-shapes of myShape: create nodes and build point-node map
3168 vector< const SMDS_MeshNode* > nodesVector;
3169 map< TPoint*, const SMDS_MeshNode* > pointNodeMap;
3170 if ( onMeshElements )
3172 nodesVector.resize( myXYZ.size() );
3173 for ( int i = 0; i < myXYZ.size(); ++i ) {
3174 map< int, const SMDS_MeshNode*>::iterator idNode = myXYZIdToNodeMap.find( i );
3175 if ( idNode != myXYZIdToNodeMap.end() )
3176 nodesVector[ i ] = idNode->second;
3177 else if ( isDefined( myXYZ[ i ] ))
3178 nodesVector[ i ] = aMeshDS->AddNode (myXYZ[ i ].X(),
3185 map< int, list< TPoint* > >::iterator idPointIt = myShapeIDToPointsMap.begin();
3186 for ( ; idPointIt != myShapeIDToPointsMap.end(); idPointIt++ )
3189 SMESHDS_SubMesh * subMeshDS = 0;
3190 if ( !myShapeIDMap.IsEmpty() ) {
3191 S = myShapeIDMap( idPointIt->first );
3192 subMeshDS = aMeshDS->MeshElements( S );
3194 list< TPoint* > & points = idPointIt->second;
3195 list< TPoint* >::iterator pIt = points.begin();
3196 for ( ; pIt != points.end(); pIt++ )
3198 TPoint* point = *pIt;
3199 if ( pointNodeMap.find( point ) != pointNodeMap.end() )
3201 SMDS_MeshNode* node = aMeshDS->AddNode (point->myXYZ.X(),
3204 pointNodeMap.insert( make_pair( point, node ));
3206 switch ( S.ShapeType() ) {
3207 case TopAbs_VERTEX: {
3208 aMeshDS->SetNodeOnVertex( node, TopoDS::Vertex( S ));
3212 aMeshDS->SetNodeOnEdge( node, TopoDS::Edge( S ));
3213 SMDS_EdgePosition* epos =
3214 dynamic_cast<SMDS_EdgePosition *>(node->GetPosition().get());
3215 epos->SetUParameter( point->myU );
3219 aMeshDS->SetNodeOnFace( node, TopoDS::Face( S ));
3220 SMDS_FacePosition* pos =
3221 dynamic_cast<SMDS_FacePosition *>(node->GetPosition().get());
3222 pos->SetUParameter( point->myUV.X() );
3223 pos->SetVParameter( point->myUV.Y() );
3227 aMeshDS->SetNodeInVolume( node, TopoDS::Shell( S ));
3236 // shapes and groups myElements are on
3237 vector< int > shapeIDs;
3238 vector< list< SMESHDS_Group* > > groups;
3239 if ( onMeshElements )
3241 shapeIDs.resize( myElements.size() );
3242 groups.resize( myElements.size() );
3243 const set<SMESHDS_GroupBase*>& allGroups = aMeshDS->GetGroups();
3244 set<SMESHDS_GroupBase*>::const_iterator grIt;
3245 for ( int i = 0; i < myElements.size(); i++ )
3247 shapeIDs[ i ] = editor.FindShape( myElements[ i ] );
3248 for ( grIt = allGroups.begin(); grIt != allGroups.end(); grIt++ ) {
3249 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
3250 if ( group && group->SMDSGroup().Contains( myElements[ i ] ))
3251 groups[ i ].push_back( group );
3255 int nbElems = myElemPointIDs.size(); // nb elements in a pattern
3257 list<list< int > >::iterator epIt, epEnd;
3258 if ( onMeshElements ) {
3259 epIt = myElemXYZIDs.begin();
3260 epEnd = myElemXYZIDs.end();
3263 epIt = myElemPointIDs.begin();
3264 epEnd = myElemPointIDs.end();
3266 for ( int iElem = 0; epIt != epEnd; epIt++, iElem++ )
3268 list< int > & elemPoints = *epIt;
3270 const SMDS_MeshNode* nodes[ 8 ];
3271 list< int >::iterator iIt = elemPoints.begin();
3273 for ( nbNodes = 0; iIt != elemPoints.end(); iIt++ ) {
3274 if ( onMeshElements )
3275 nodes[ nbNodes++ ] = nodesVector[ *iIt ];
3277 nodes[ nbNodes++ ] = pointNodeMap[ & myPoints[ *iIt ]];
3280 const SMDS_MeshElement* elem = 0;
3282 switch ( nbNodes ) {
3284 elem = aMeshDS->AddFace( nodes[0], nodes[1], nodes[2] ); break;
3286 elem = aMeshDS->AddFace( nodes[0], nodes[1], nodes[2], nodes[3] ); break;
3288 ASSERT( nbNodes < 8 );
3292 switch ( nbNodes ) {
3294 elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3] ); break;
3296 elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3],
3299 elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3],
3300 nodes[4], nodes[5] ); break;
3302 elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3],
3303 nodes[4], nodes[5], nodes[6], nodes[7] ); break;
3305 ASSERT( nbNodes < 8 );
3308 // set element on a shape
3309 if ( elem && onMeshElements ) // applied to mesh elements
3311 int elemIndex = iElem / nbElems;
3312 int shapeID = shapeIDs[ elemIndex ];
3313 if ( shapeID > 0 ) {
3314 aMeshDS->SetMeshElementOnShape( elem, shapeID );
3315 // set nodes on a shape
3316 TopoDS_Shape S = aMeshDS->IndexToShape( shapeID );
3317 if ( S.ShapeType() == TopAbs_SOLID ) {
3318 TopoDS_Iterator shellIt( S );
3319 if ( shellIt.More() )
3320 shapeID = aMeshDS->ShapeToIndex( shellIt.Value() );
3322 SMDS_ElemIteratorPtr noIt = elem->nodesIterator();
3323 while ( noIt->more() ) {
3324 SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>
3325 ( static_cast<const SMDS_MeshNode*>( noIt->next() ));
3326 if ( !node->GetPosition() || !node->GetPosition()->GetShapeId() ) {
3327 if ( S.ShapeType() == TopAbs_FACE )
3328 aMeshDS->SetNodeOnFace( node, shapeID );
3330 aMeshDS->SetNodeInVolume( node, shapeID );
3334 // add elem in groups
3335 list< SMESHDS_Group* >::iterator g = groups[ elemIndex ].begin();
3336 for ( ; g != groups[ elemIndex ].end(); ++g )
3337 (*g)->SMDSGroup().Add( elem );
3339 if ( elem && !myShape.IsNull() ) // applied to shape
3340 aMeshDS->SetMeshElementOnShape( elem, myShape );
3343 // make that SMESH_subMesh::_computeState = COMPUTE_OK
3344 // so that operations with hypotheses will erase the mesh being built
3346 SMESH_subMesh * subMesh;
3347 if ( !myShape.IsNull() ) {
3348 subMesh = theMesh->GetSubMeshContaining( myShape );
3350 subMesh->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
3352 if ( onMeshElements ) {
3353 list< int > elemIDs;
3354 for ( int i = 0; i < myElements.size(); i++ )
3356 int shapeID = shapeIDs[ i ];
3357 if ( shapeID > 0 ) {
3358 TopoDS_Shape S = aMeshDS->IndexToShape( shapeID );
3359 subMesh = theMesh->GetSubMeshContaining( S );
3361 subMesh->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
3363 elemIDs.push_back( myElements[ i ]->GetID() );
3365 // remove refined elements
3366 editor.Remove( elemIDs, false );
3369 return setErrorCode( ERR_OK );
3373 //=======================================================================
3374 //function : arrangeBoundaries
3375 //purpose : if there are several wires, arrange boundaryPoints so that
3376 // the outer wire goes first and fix inner wires orientation
3377 // update myKeyPointIDs to correspond to the order of key-points
3378 // in boundaries; sort internal boundaries by the nb of key-points
3379 //=======================================================================
3381 void SMESH_Pattern::arrangeBoundaries (list< list< TPoint* > >& boundaryList)
3383 typedef list< list< TPoint* > >::iterator TListOfListIt;
3384 TListOfListIt bndIt;
3385 list< TPoint* >::iterator pIt;
3387 int nbBoundaries = boundaryList.size();
3388 if ( nbBoundaries > 1 )
3390 // sort boundaries by nb of key-points
3391 if ( nbBoundaries > 2 )
3393 // move boundaries in tmp list
3394 list< list< TPoint* > > tmpList;
3395 tmpList.splice( tmpList.begin(), boundaryList, boundaryList.begin(), boundaryList.end());
3396 // make a map nb-key-points to boundary-position-in-tmpList,
3397 // boundary-positions get ordered in it
3398 typedef map< int, TListOfListIt > TNbKpBndPosMap;
3399 TNbKpBndPosMap nbKpBndPosMap;
3400 bndIt = tmpList.begin();
3401 list< int >::iterator nbKpIt = myNbKeyPntInBoundary.begin();
3402 for ( ; nbKpIt != myNbKeyPntInBoundary.end(); nbKpIt++, bndIt++ ) {
3403 int nb = *nbKpIt * nbBoundaries;
3404 while ( nbKpBndPosMap.find ( nb ) != nbKpBndPosMap.end() )
3406 nbKpBndPosMap.insert( TNbKpBndPosMap::value_type( nb, bndIt ));
3408 // move boundaries back to boundaryList
3409 TNbKpBndPosMap::iterator nbKpBndPosIt = nbKpBndPosMap.begin();
3410 for ( ; nbKpBndPosIt != nbKpBndPosMap.end(); nbKpBndPosIt++ ) {
3411 TListOfListIt & bndPos2 = (*nbKpBndPosIt).second;
3412 TListOfListIt bndPos1 = bndPos2++;
3413 boundaryList.splice( boundaryList.end(), tmpList, bndPos1, bndPos2 );
3417 // Look for the outer boundary: the one with the point with the least X
3418 double leastX = DBL_MAX;
3419 TListOfListIt outerBndPos;
3420 for ( bndIt = boundaryList.begin(); bndIt != boundaryList.end(); bndIt++ )
3422 list< TPoint* >& boundary = (*bndIt);
3423 for ( pIt = boundary.begin(); pIt != boundary.end(); pIt++)
3425 TPoint* point = *pIt;
3426 if ( point->myInitXYZ.X() < leastX ) {
3427 leastX = point->myInitXYZ.X();
3428 outerBndPos = bndIt;
3433 if ( outerBndPos != boundaryList.begin() )
3434 boundaryList.splice( boundaryList.begin(), boundaryList, outerBndPos, ++outerBndPos );
3436 } // if nbBoundaries > 1
3438 // Check boundaries orientation and re-fill myKeyPointIDs
3440 set< TPoint* > keyPointSet;
3441 list< int >::iterator kpIt = myKeyPointIDs.begin();
3442 for ( ; kpIt != myKeyPointIDs.end(); kpIt++ )
3443 keyPointSet.insert( & myPoints[ *kpIt ]);
3444 myKeyPointIDs.clear();
3446 // update myNbKeyPntInBoundary also
3447 list< int >::iterator nbKpIt = myNbKeyPntInBoundary.begin();
3449 for ( bndIt = boundaryList.begin(); bndIt != boundaryList.end(); bndIt++, nbKpIt++ )
3451 // find the point with the least X
3452 double leastX = DBL_MAX;
3453 list< TPoint* >::iterator xpIt;
3454 list< TPoint* >& boundary = (*bndIt);
3455 for ( pIt = boundary.begin(); pIt != boundary.end(); pIt++)
3457 TPoint* point = *pIt;
3458 if ( point->myInitXYZ.X() < leastX ) {
3459 leastX = point->myInitXYZ.X();
3463 // find points next to the point with the least X
3464 TPoint* p = *xpIt, *pPrev, *pNext;
3465 if ( p == boundary.front() )
3466 pPrev = *(++boundary.rbegin());
3472 if ( p == boundary.back() )
3473 pNext = *(++boundary.begin());
3478 // vectors of boundary direction near <p>
3479 gp_Vec2d v1( pPrev->myInitUV, p->myInitUV ), v2( p->myInitUV, pNext->myInitUV );
3480 double sqMag1 = v1.SquareMagnitude(), sqMag2 = v2.SquareMagnitude();
3481 if ( sqMag1 > DBL_MIN && sqMag2 > DBL_MIN ) {
3482 double yPrev = v1.Y() / sqrt( sqMag1 );
3483 double yNext = v2.Y() / sqrt( sqMag2 );
3484 double sumY = yPrev + yNext;
3486 if ( bndIt == boundaryList.begin() ) // outer boundary
3494 // Put key-point IDs of a well-oriented boundary in myKeyPointIDs
3495 (*nbKpIt) = 0; // count nb of key-points again
3496 pIt = boundary.begin();
3497 for ( ; pIt != boundary.end(); pIt++)
3499 TPoint* point = *pIt;
3500 if ( keyPointSet.find( point ) == keyPointSet.end() )
3502 // find an index of a keypoint
3504 vector< TPoint >::const_iterator pVecIt = myPoints.begin();
3505 for ( ; pVecIt != myPoints.end(); pVecIt++, index++ )
3506 if ( &(*pVecIt) == point )
3508 myKeyPointIDs.push_back( index );
3511 myKeyPointIDs.pop_back(); // remove the first key-point from the back
3514 } // loop on a list of boundaries
3516 ASSERT( myKeyPointIDs.size() == keyPointSet.size() );
3519 //=======================================================================
3520 //function : findBoundaryPoints
3521 //purpose : if loaded from file, find points to map on edges and faces and
3522 // compute their parameters
3523 //=======================================================================
3525 bool SMESH_Pattern::findBoundaryPoints()
3527 if ( myIsBoundaryPointsFound ) return true;
3529 MESSAGE(" findBoundaryPoints() ");
3533 set< TPoint* > pointsInElems;
3535 // Find free links of elements:
3536 // put links of all elements in a set and remove links encountered twice
3538 typedef pair< TPoint*, TPoint*> TLink;
3539 set< TLink > linkSet;
3540 list<list< int > >::iterator epIt = myElemPointIDs.begin();
3541 for ( ; epIt != myElemPointIDs.end(); epIt++ )
3543 list< int > & elemPoints = *epIt;
3544 list< int >::iterator pIt = elemPoints.begin();
3545 int prevP = elemPoints.back();
3546 for ( ; pIt != elemPoints.end(); pIt++ ) {
3547 TPoint* p1 = & myPoints[ prevP ];
3548 TPoint* p2 = & myPoints[ *pIt ];
3549 TLink link(( p1 < p2 ? p1 : p2 ), ( p1 < p2 ? p2 : p1 ));
3550 ASSERT( link.first != link.second );
3551 pair<set< TLink >::iterator,bool> itUniq = linkSet.insert( link );
3552 if ( !itUniq.second )
3553 linkSet.erase( itUniq.first );
3556 pointsInElems.insert( p1 );
3559 // Now linkSet contains only free links,
3560 // find the points order that they have in boundaries
3562 // 1. make a map of key-points
3563 set< TPoint* > keyPointSet;
3564 list< int >::iterator kpIt = myKeyPointIDs.begin();
3565 for ( ; kpIt != myKeyPointIDs.end(); kpIt++ )
3566 keyPointSet.insert( & myPoints[ *kpIt ]);
3568 // 2. chain up boundary points
3569 list< list< TPoint* > > boundaryList;
3570 boundaryList.push_back( list< TPoint* >() );
3571 list< TPoint* > * boundary = & boundaryList.back();
3573 TPoint *point1, *point2, *keypoint1;
3574 kpIt = myKeyPointIDs.begin();
3575 point1 = keypoint1 = & myPoints[ *kpIt++ ];
3576 // loop on free links: look for the next point
3578 set< TLink >::iterator lIt = linkSet.begin();
3579 while ( lIt != linkSet.end() )
3581 if ( (*lIt).first == point1 )
3582 point2 = (*lIt).second;
3583 else if ( (*lIt).second == point1 )
3584 point2 = (*lIt).first;
3589 linkSet.erase( lIt );
3590 lIt = linkSet.begin();
3592 if ( keyPointSet.find( point2 ) == keyPointSet.end() ) // not a key-point
3594 boundary->push_back( point2 );
3596 else // a key-point found
3598 keyPointSet.erase( point2 ); // keyPointSet contains not found key-points only
3600 if ( point2 != keypoint1 ) // its not the boundary end
3602 boundary->push_back( point2 );
3604 else // the boundary end reached
3606 boundary->push_front( keypoint1 );
3607 boundary->push_back( keypoint1 );
3608 myNbKeyPntInBoundary.push_back( iKeyPoint );
3609 if ( keyPointSet.empty() )
3610 break; // all boundaries containing key-points are found
3612 // prepare to search for the next boundary
3613 boundaryList.push_back( list< TPoint* >() );
3614 boundary = & boundaryList.back();
3615 point2 = keypoint1 = (*keyPointSet.begin());
3619 } // loop on the free links set
3621 if ( boundary->empty() ) {
3622 MESSAGE(" a separate key-point");
3623 return setErrorCode( ERR_READ_BAD_KEY_POINT );
3626 // if there are several wires, arrange boundaryPoints so that
3627 // the outer wire goes first and fix inner wires orientation;
3628 // sort myKeyPointIDs to correspond to the order of key-points
3630 arrangeBoundaries( boundaryList );
3632 // Find correspondence shape ID - points,
3633 // compute points parameter on edge
3635 keyPointSet.clear();
3636 for ( kpIt = myKeyPointIDs.begin(); kpIt != myKeyPointIDs.end(); kpIt++ )
3637 keyPointSet.insert( & myPoints[ *kpIt ]);
3639 set< TPoint* > edgePointSet; // to find in-face points
3640 int vertexID = 1; // the first index in TopTools_IndexedMapOfShape
3641 int edgeID = myKeyPointIDs.size() + 1;
3643 list< list< TPoint* > >::iterator bndIt = boundaryList.begin();
3644 for ( ; bndIt != boundaryList.end(); bndIt++ )
3646 boundary = & (*bndIt);
3647 double edgeLength = 0;
3648 list< TPoint* >::iterator pIt = boundary->begin();
3649 getShapePoints( edgeID ).push_back( *pIt );
3650 getShapePoints( vertexID++ ).push_back( *pIt );
3651 for ( pIt++; pIt != boundary->end(); pIt++)
3653 list< TPoint* > & edgePoints = getShapePoints( edgeID );
3654 TPoint* prevP = edgePoints.empty() ? 0 : edgePoints.back();
3655 TPoint* point = *pIt;
3656 edgePointSet.insert( point );
3657 if ( keyPointSet.find( point ) == keyPointSet.end() ) // inside-edge point
3659 edgePoints.push_back( point );
3660 edgeLength += ( point->myInitUV - prevP->myInitUV ).Modulus();
3661 point->myInitU = edgeLength;
3665 // treat points on the edge which ends up: compute U [0,1]
3666 edgePoints.push_back( point );
3667 if ( edgePoints.size() > 2 ) {
3668 edgeLength += ( point->myInitUV - prevP->myInitUV ).Modulus();
3669 list< TPoint* >::iterator epIt = edgePoints.begin();
3670 for ( ; epIt != edgePoints.end(); epIt++ )
3671 (*epIt)->myInitU /= edgeLength;
3673 // begin the next edge treatment
3676 if ( point != boundary->front() ) { // not the first key-point again
3677 getShapePoints( edgeID ).push_back( point );
3678 getShapePoints( vertexID++ ).push_back( point );
3684 // find in-face points
3685 list< TPoint* > & facePoints = getShapePoints( edgeID );
3686 vector< TPoint >::iterator pVecIt = myPoints.begin();
3687 for ( ; pVecIt != myPoints.end(); pVecIt++ ) {
3688 TPoint* point = &(*pVecIt);
3689 if ( edgePointSet.find( point ) == edgePointSet.end() &&
3690 pointsInElems.find( point ) != pointsInElems.end())
3691 facePoints.push_back( point );
3698 // bind points to shapes according to point parameters
3699 vector< TPoint >::iterator pVecIt = myPoints.begin();
3700 for ( int i = 0; pVecIt != myPoints.end(); pVecIt++, i++ ) {
3701 TPoint* point = &(*pVecIt);
3702 int shapeID = SMESH_Block::GetShapeIDByParams( point->myInitXYZ );
3703 getShapePoints( shapeID ).push_back( point );
3704 // detect key-points
3705 if ( SMESH_Block::IsVertexID( shapeID ))
3706 myKeyPointIDs.push_back( i );
3710 myIsBoundaryPointsFound = true;
3711 return myIsBoundaryPointsFound;
3714 //=======================================================================
3716 //purpose : clear fields
3717 //=======================================================================
3719 void SMESH_Pattern::Clear()
3721 myIsComputed = myIsBoundaryPointsFound = false;
3724 myKeyPointIDs.clear();
3725 myElemPointIDs.clear();
3726 myShapeIDToPointsMap.clear();
3727 myShapeIDMap.Clear();
3729 myNbKeyPntInBoundary.clear();
3732 //=======================================================================
3733 //function : setShapeToMesh
3734 //purpose : set a shape to be meshed. Return True if meshing is possible
3735 //=======================================================================
3737 bool SMESH_Pattern::setShapeToMesh(const TopoDS_Shape& theShape)
3739 if ( !IsLoaded() ) {
3740 MESSAGE( "Pattern not loaded" );
3741 return setErrorCode( ERR_APPL_NOT_LOADED );
3744 TopAbs_ShapeEnum aType = theShape.ShapeType();
3745 bool dimOk = ( myIs2D ? aType == TopAbs_FACE : aType == TopAbs_SHELL );
3747 MESSAGE( "Pattern dimention mismatch" );
3748 return setErrorCode( ERR_APPL_BAD_DIMENTION );
3751 // check if a face is closed
3752 int nbNodeOnSeamEdge = 0;
3754 TopoDS_Face face = TopoDS::Face( theShape );
3755 TopExp_Explorer eExp( theShape, TopAbs_EDGE );
3756 for ( ; eExp.More() && nbNodeOnSeamEdge == 0; eExp.Next() )
3757 if ( BRep_Tool::IsClosed( TopoDS::Edge( eExp.Current() ), face ))
3758 nbNodeOnSeamEdge = 2;
3761 // check nb of vertices
3762 TopTools_IndexedMapOfShape vMap;
3763 TopExp::MapShapes( theShape, TopAbs_VERTEX, vMap );
3764 if ( vMap.Extent() + nbNodeOnSeamEdge != myKeyPointIDs.size() ) {
3765 MESSAGE( myKeyPointIDs.size() << " != " << vMap.Extent() );
3766 return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
3769 myShapeIDMap.Clear();
3774 //=======================================================================
3775 //function : GetMappedPoints
3776 //purpose : Return nodes coordinates computed by Apply() method
3777 //=======================================================================
3779 bool SMESH_Pattern::GetMappedPoints ( list< const gp_XYZ * > & thePoints ) const
3782 if ( !myIsComputed )
3785 if ( myElements.empty() ) { // applied to shape
3786 vector< TPoint >::const_iterator pVecIt = myPoints.begin();
3787 for ( ; pVecIt != myPoints.end(); pVecIt++ )
3788 thePoints.push_back( & (*pVecIt).myXYZ.XYZ() );
3790 else { // applied to mesh elements
3791 const gp_XYZ * definedXYZ = & myPoints[ myKeyPointIDs.front() ].myXYZ.XYZ();
3792 vector<gp_XYZ>::const_iterator xyz = myXYZ.begin();
3793 for ( ; xyz != myXYZ.end(); ++xyz )
3794 if ( !isDefined( *xyz ))
3795 thePoints.push_back( definedXYZ );
3797 thePoints.push_back( & (*xyz) );
3799 return !thePoints.empty();
3803 //=======================================================================
3804 //function : GetPoints
3805 //purpose : Return nodes coordinates of the pattern
3806 //=======================================================================
3808 bool SMESH_Pattern::GetPoints ( list< const gp_XYZ * > & thePoints ) const
3815 vector< TPoint >::const_iterator pVecIt = myPoints.begin();
3816 for ( ; pVecIt != myPoints.end(); pVecIt++ )
3817 thePoints.push_back( & (*pVecIt).myInitXYZ );
3819 return ( thePoints.size() > 0 );
3822 //=======================================================================
3823 //function : getShapePoints
3824 //purpose : return list of points located on theShape
3825 //=======================================================================
3827 list< SMESH_Pattern::TPoint* > &
3828 SMESH_Pattern::getShapePoints(const TopoDS_Shape& theShape)
3831 if ( !myShapeIDMap.Contains( theShape ))
3832 aShapeID = myShapeIDMap.Add( theShape );
3834 aShapeID = myShapeIDMap.FindIndex( theShape );
3836 return myShapeIDToPointsMap[ aShapeID ];
3839 //=======================================================================
3840 //function : getShapePoints
3841 //purpose : return list of points located on the shape
3842 //=======================================================================
3844 list< SMESH_Pattern::TPoint* > & SMESH_Pattern::getShapePoints(const int theShapeID)
3846 return myShapeIDToPointsMap[ theShapeID ];
3849 //=======================================================================
3850 //function : DumpPoints
3852 //=======================================================================
3854 void SMESH_Pattern::DumpPoints() const
3857 vector< TPoint >::const_iterator pVecIt = myPoints.begin();
3858 for ( int i = 0; pVecIt != myPoints.end(); pVecIt++, i++ )
3859 cout << i << ": " << *pVecIt;
3863 //=======================================================================
3864 //function : TPoint()
3866 //=======================================================================
3868 SMESH_Pattern::TPoint::TPoint()
3871 myInitXYZ.SetCoord(0,0,0);
3872 myInitUV.SetCoord(0.,0.);
3874 myXYZ.SetCoord(0,0,0);
3875 myUV.SetCoord(0.,0.);
3880 //=======================================================================
3881 //function : operator <<
3883 //=======================================================================
3885 ostream & operator <<(ostream & OS, const SMESH_Pattern::TPoint& p)
3887 gp_XYZ xyz = p.myInitXYZ;
3888 OS << "\tinit( xyz( " << xyz.X() << " " << xyz.Y() << " " << xyz.Z() << " )";
3889 gp_XY xy = p.myInitUV;
3890 OS << " uv( " << xy.X() << " " << xy.Y() << " )";
3891 double u = p.myInitU;
3892 OS << " u( " << u << " )) " << &p << endl;
3893 xyz = p.myXYZ.XYZ();
3894 OS << "\t ( xyz( " << xyz.X() << " " << xyz.Y() << " " << xyz.Z() << " )";
3896 OS << " uv( " << xy.X() << " " << xy.Y() << " )";
3898 OS << " u( " << u << " ))" << endl;