1 // File : SMESH_Pattern.cxx
2 // Created : Thu Aug 5 11:09:29 2004
3 // Author : Edward AGAPOV (eap)
4 // Copyright : Open CASCADE
7 #include "SMESH_Pattern.hxx"
9 #include <Bnd_Box2d.hxx>
10 #include <BRepTools.hxx>
11 #include <BRepTools_WireExplorer.hxx>
12 #include <BRep_Tool.hxx>
13 #include <Geom2d_Curve.hxx>
14 #include <Geom_Curve.hxx>
15 #include <Geom_Surface.hxx>
16 #include <IntAna2d_AnaIntersection.hxx>
17 #include <TopAbs_ShapeEnum.hxx>
19 #include <TopLoc_Location.hxx>
21 #include <TopoDS_Edge.hxx>
22 #include <TopoDS_Face.hxx>
23 #include <TopoDS_Iterator.hxx>
24 #include <TopoDS_Shell.hxx>
25 #include <TopoDS_Vertex.hxx>
26 #include <TopoDS_Wire.hxx>
27 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
28 #include <TopTools_ListIteratorOfListOfShape.hxx>
29 #include <TopTools_ListOfShape.hxx>
30 #include <gp_Lin2d.hxx>
31 #include <gp_Pnt2d.hxx>
32 #include <gp_Trsf.hxx>
35 #include <math_FunctionSetRoot.hxx>
36 #include <math_FunctionSetWithDerivatives.hxx>
37 #include <math_Matrix.hxx>
38 #include <math_Vector.hxx>
39 #include <Extrema_GenExtPS.hxx>
40 #include <Extrema_POnSurf.hxx>
41 #include <GeomAdaptor_Surface.hxx>
43 #include "SMDS_EdgePosition.hxx"
44 #include "SMDS_FacePosition.hxx"
45 #include "SMDS_MeshElement.hxx"
46 #include "SMDS_MeshNode.hxx"
47 #include "SMESHDS_Mesh.hxx"
48 #include "SMESHDS_SubMesh.hxx"
49 #include "SMESH_Mesh.hxx"
51 #include "utilities.h"
55 typedef map< const SMDS_MeshElement*, int > TNodePointIDMap;
59 //=======================================================================
60 //function : SMESH_Pattern
62 //=======================================================================
64 SMESH_Pattern::SMESH_Pattern ()
67 //=======================================================================
70 //=======================================================================
72 static inline int getInt( const char * theSring )
74 if ( *theSring < '0' || *theSring > '9' )
78 int val = strtol( theSring, &ptr, 10 );
79 if ( ptr == theSring ||
80 // there must not be neither '.' nor ',' nor 'E' ...
81 (*ptr != ' ' && *ptr != '\n' && *ptr != '\0'))
87 //=======================================================================
88 //function : getDouble
90 //=======================================================================
92 static inline double getDouble( const char * theSring )
95 return strtod( theSring, &ptr );
98 //=======================================================================
100 //purpose : Put token starting positions in theFields until '\n' or '\0'
101 // Return the number of the found tokens
102 //=======================================================================
104 static int readLine (list <const char*> & theFields,
105 const char* & theLineBeg,
106 const bool theClearFields )
108 if ( theClearFields )
113 /* switch ( symbol ) { */
114 /* case white-space: */
115 /* look for a non-space symbol; */
116 /* case string-end: */
119 /* case comment beginning: */
120 /* skip all till a line-end; */
122 /* put its position in theFields, skip till a white-space;*/
128 bool stopReading = false;
131 bool isNumber = false;
132 switch ( *theLineBeg )
134 case ' ': // white space
139 case '\n': // a line ends
140 stopReading = ( nbRead > 0 );
145 while ( *theLineBeg != '\n' && *theLineBeg != '\0' );
149 case '\0': // file ends
152 case '-': // real number
157 isNumber = isNumber || ( *theLineBeg >= '0' && *theLineBeg <= '9' );
159 theFields.push_back( theLineBeg );
162 while (*theLineBeg != ' ' &&
163 *theLineBeg != '\n' &&
164 *theLineBeg != '\0');
168 return 0; // incorrect file format
174 } while ( !stopReading );
179 //=======================================================================
181 //purpose : Load a pattern from <theFile>
182 //=======================================================================
184 bool SMESH_Pattern::Load (const char* theFileContents)
186 MESSAGE("Load( file ) ");
190 // ! This is a comment
191 // NB_POINTS ! 1 integer - the number of points in the pattern.
192 // X1 Y1 [Z1] ! 2 or 3 reals - nodes coordinates within 2D or 3D domain:
193 // X2 Y2 [Z2] ! the pattern dimention is defined by the number of coordinates
195 // [ ID1 ID2 ... IDn ] ! Indices of key-points for a 2D pattern (only).
196 // ! elements description goes after all
197 // ID1 ID2 ... IDn ! 2-4 or 4-8 integers - nodal connectivity of a 2D or 3D element.
202 const char* lineBeg = theFileContents;
203 list <const char*> fields;
204 const bool clearFields = true;
206 // NB_POINTS ! 1 integer - the number of points in the pattern.
208 if ( readLine( fields, lineBeg, clearFields ) != 1 ) {
209 MESSAGE("Error reading NB_POINTS");
210 return setErrorCode( ERR_READ_NB_POINTS );
212 int nbPoints = getInt( fields.front() );
214 // X1 Y1 [Z1] ! 2 or 3 reals - nodes coordinates within 2D or 3D domain:
216 // read the first point coordinates to define pattern dimention
217 int dim = readLine( fields, lineBeg, clearFields );
223 MESSAGE("Error reading points: wrong nb of coordinates");
224 return setErrorCode( ERR_READ_POINT_COORDS );
226 if ( nbPoints <= dim ) {
227 MESSAGE(" Too few points ");
228 return setErrorCode( ERR_READ_TOO_FEW_POINTS );
231 // read the rest points
233 for ( iPoint = 1; iPoint < nbPoints; iPoint++ )
234 if ( readLine( fields, lineBeg, !clearFields ) != dim ) {
235 MESSAGE("Error reading points : wrong nb of coordinates ");
236 return setErrorCode( ERR_READ_POINT_COORDS );
238 // store point coordinates
239 myPoints.resize( nbPoints );
240 list <const char*>::iterator fIt = fields.begin();
241 for ( iPoint = 0; iPoint < nbPoints; iPoint++ )
243 TPoint & p = myPoints[ iPoint ];
244 for ( int iCoord = 1; iCoord <= dim; iCoord++, fIt++ )
246 double coord = getDouble( *fIt );
247 if ( !myIs2D && ( coord < 0.0 || coord > 1.0 )) {
248 MESSAGE("Error reading 3D points, value should be in [0,1]: " << coord);
250 return setErrorCode( ERR_READ_3D_COORD );
252 p.myInitXYZ.SetCoord( iCoord, coord );
254 p.myInitUV.SetCoord( iCoord, coord );
258 // [ ID1 ID2 ... IDn ] ! Indices of key-points for a 2D pattern (only).
261 if ( readLine( fields, lineBeg, clearFields ) == 0 ) {
262 MESSAGE("Error: missing key-points");
264 return setErrorCode( ERR_READ_NO_KEYPOINT );
267 for ( fIt = fields.begin(); fIt != fields.end(); fIt++ )
269 int pointIndex = getInt( *fIt );
270 if ( pointIndex >= nbPoints || pointIndex < 0 ) {
271 MESSAGE("Error: invalid point index " << pointIndex );
273 return setErrorCode( ERR_READ_BAD_INDEX );
275 if ( idSet.insert( pointIndex ).second ) // unique?
276 myKeyPointIDs.push_back( pointIndex );
280 // ID1 ID2 ... IDn ! 2-4 or 4-8 integers - nodal connectivity of a 2D or 3D element.
282 while ( readLine( fields, lineBeg, clearFields ))
284 myElemPointIDs.push_back( list< int >() );
285 list< int >& elemPoints = myElemPointIDs.back();
286 for ( fIt = fields.begin(); fIt != fields.end(); fIt++ )
288 int pointIndex = getInt( *fIt );
289 if ( pointIndex >= nbPoints || pointIndex < 0 ) {
290 MESSAGE("Error: invalid point index " << pointIndex );
292 return setErrorCode( ERR_READ_BAD_INDEX );
294 elemPoints.push_back( pointIndex );
296 // check the nb of nodes in element
298 switch ( elemPoints.size() ) {
299 case 3: if ( !myIs2D ) Ok = false; break;
303 case 8: if ( myIs2D ) Ok = false; break;
307 MESSAGE("Error: wrong nb of nodes in element " << elemPoints.size() );
309 return setErrorCode( ERR_READ_ELEM_POINTS );
312 if ( myElemPointIDs.empty() ) {
313 MESSAGE("Error: no elements");
315 return setErrorCode( ERR_READ_NO_ELEMS );
318 findBoundaryPoints(); // sort key-points
320 return setErrorCode( ERR_OK );
323 //=======================================================================
325 //purpose : Save the loaded pattern into the file <theFileName>
326 //=======================================================================
328 bool SMESH_Pattern::Save (ostream& theFile)
330 MESSAGE(" ::Save(file) " );
332 MESSAGE(" Pattern not loaded ");
333 return setErrorCode( ERR_SAVE_NOT_LOADED );
336 theFile << "!!! SALOME Mesh Pattern file" << endl;
337 theFile << "!!!" << endl;
338 theFile << "!!! Nb of points:" << endl;
339 theFile << myPoints.size() << endl;
343 // theFile.width( 8 );
344 // theFile.setf(ios::fixed);// use 123.45 floating notation
345 // theFile.setf(ios::right);
346 // theFile.flags( theFile.flags() & ~ios::showpoint); // do not show trailing zeros
347 // theFile.setf(ios::showpoint); // do not show trailing zeros
348 vector< TPoint >::const_iterator pVecIt = myPoints.begin();
349 for ( int i = 0; pVecIt != myPoints.end(); pVecIt++, i++ ) {
350 const gp_XYZ & xyz = (*pVecIt).myInitXYZ;
351 theFile << " " << setw( width ) << xyz.X() << " " << setw( width ) << xyz.Y();
352 if ( !myIs2D ) theFile << " " << setw( width ) << xyz.Z();
353 theFile << " !- " << i << endl; // point id to ease reading by a human being
357 theFile << "!!! Indices of " << myKeyPointIDs.size() << " key-points:" << endl;
358 list< int >::const_iterator kpIt = myKeyPointIDs.begin();
359 for ( ; kpIt != myKeyPointIDs.end(); kpIt++ )
360 theFile << " " << *kpIt;
361 if ( !myKeyPointIDs.empty() )
365 theFile << "!!! Indices of points of " << myElemPointIDs.size() << " elements:" << endl;
366 list<list< int > >::const_iterator epIt = myElemPointIDs.begin();
367 for ( ; epIt != myElemPointIDs.end(); epIt++ )
369 const list< int > & elemPoints = *epIt;
370 list< int >::const_iterator iIt = elemPoints.begin();
371 for ( ; iIt != elemPoints.end(); iIt++ )
372 theFile << " " << *iIt;
378 return setErrorCode( ERR_OK );
381 //=======================================================================
382 //function : sortBySize
383 //purpose : sort theListOfList by size
384 //=======================================================================
386 template<typename T> struct TSizeCmp {
387 bool operator ()( const list < T > & l1, const list < T > & l2 )
388 const { return l1.size() < l2.size(); }
391 template<typename T> void sortBySize( list< list < T > > & theListOfList )
393 if ( theListOfList.size() > 2 ) {
395 list < T > & aFront = theListOfList.front();
396 // sort the whole list
397 TSizeCmp< T > SizeCmp;
398 theListOfList.sort( SizeCmp );
402 //=======================================================================
403 //function : getOrderedEdges
404 //purpose : return nb wires and a list of oredered edges
405 //=======================================================================
407 static int getOrderedEdges (const TopoDS_Face& theFace,
408 const TopoDS_Vertex& theFirstVertex,
409 list< TopoDS_Edge >& theEdges,
410 list< int > & theNbVertexInWires)
412 // put wires in a list, so that an outer wire comes first
413 list<TopoDS_Wire> aWireList;
414 TopoDS_Wire anOuterWire = BRepTools::OuterWire( theFace );
415 aWireList.push_back( anOuterWire );
416 for ( TopoDS_Iterator wIt (theFace); wIt.More(); wIt.Next() )
417 if ( !anOuterWire.IsSame( wIt.Value() ))
418 aWireList.push_back( TopoDS::Wire( wIt.Value() ));
420 // loop on edges of wires
421 theNbVertexInWires.clear();
422 list<TopoDS_Wire>::iterator wlIt = aWireList.begin();
423 for ( ; wlIt != aWireList.end(); wlIt++ )
426 BRepTools_WireExplorer wExp( *wlIt, theFace );
427 for ( iE = 0; wExp.More(); wExp.Next(), iE++ )
429 TopoDS_Edge edge = wExp.Current();
430 edge = TopoDS::Edge( edge.Oriented( wExp.Orientation() ));
431 theEdges.push_back( edge );
433 theNbVertexInWires.push_back( iE );
435 if ( wlIt == aWireList.begin() && theEdges.size() > 1 ) { // the outer wire
436 // orient closed edges
437 list< TopoDS_Edge >::iterator eIt, eIt2;
438 for ( eIt = theEdges.begin(); eIt != theEdges.end(); eIt++ )
440 TopoDS_Edge& edge = *eIt;
441 if ( TopExp::FirstVertex( edge ).IsSame( TopExp::LastVertex( edge ) ))
444 bool isNext = ( eIt2 == theEdges.begin() );
445 TopoDS_Edge edge2 = isNext ? *(++eIt2) : *(--eIt2);
447 Handle(Geom2d_Curve) c1 = BRep_Tool::CurveOnSurface( edge, theFace, f1,l1 );
448 Handle(Geom2d_Curve) c2 = BRep_Tool::CurveOnSurface( edge2, theFace, f2,l2 );
449 gp_Pnt2d pf = c1->Value( edge.Orientation() == TopAbs_FORWARD ? f1 : l1 );
450 gp_Pnt2d pl = c1->Value( edge.Orientation() == TopAbs_FORWARD ? l1 : f1 );
451 bool isFirst = ( edge2.Orientation() == TopAbs_FORWARD ? isNext : !isNext );
452 gp_Pnt2d p2 = c2->Value( isFirst ? f2 : l2 );
453 isFirst = ( p2.SquareDistance( pf ) < p2.SquareDistance( pl ));
454 if ( isNext ? isFirst : !isFirst )
458 // rotate theEdges until it begins from theFirstVertex
459 if ( ! theFirstVertex.IsNull() )
460 while ( !theFirstVertex.IsSame( TopExp::FirstVertex( theEdges.front(), true )))
462 theEdges.splice(theEdges.end(), theEdges,
463 theEdges.begin(), ++ theEdges.begin());
464 if ( iE++ > theNbVertexInWires.back() )
465 break; // break infinite loop
470 return aWireList.size();
473 //=======================================================================
476 //=======================================================================
478 static gp_XY project (const SMDS_MeshNode* theNode,
479 Extrema_GenExtPS & theProjectorPS)
481 gp_Pnt P( theNode->X(), theNode->Y(), theNode->Z() );
482 theProjectorPS.Perform( P );
483 if ( !theProjectorPS.IsDone() ) {
484 MESSAGE( "SMESH_Pattern: point projection FAILED");
487 double u, v, minVal = DBL_MAX;
488 for ( int i = theProjectorPS.NbExt(); i > 0; i-- )
489 if ( theProjectorPS.Value( i ) < minVal ) {
490 minVal = theProjectorPS.Value( i );
491 theProjectorPS.Point( i ).Parameter( u, v );
493 return gp_XY( u, v );
496 //=======================================================================
497 //function : isMeshBoundToShape
498 //purpose : return true if all 2d elements are bound to shape
499 //=======================================================================
501 static bool isMeshBoundToShape(SMESH_Mesh* theMesh)
503 // check faces binding
504 SMESHDS_Mesh * aMeshDS = theMesh->GetMeshDS();
505 SMESHDS_SubMesh * aMainSubMesh = aMeshDS->MeshElements( aMeshDS->ShapeToMesh() );
506 if ( aMeshDS->NbFaces() != aMainSubMesh->NbElements() )
509 // check face nodes binding
510 SMDS_FaceIteratorPtr fIt = aMeshDS->facesIterator();
511 while ( fIt->more() )
513 SMDS_ElemIteratorPtr nIt = fIt->next()->nodesIterator();
514 while ( nIt->more() )
516 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nIt->next() );
517 SMDS_PositionPtr pos = node->GetPosition();
518 if ( !pos || !pos->GetShapeId() )
525 //=======================================================================
527 //purpose : Create a pattern from the mesh built on <theFace>.
528 // <theProject>==true makes override nodes positions
529 // on <theFace> computed by mesher
530 //=======================================================================
532 bool SMESH_Pattern::Load (SMESH_Mesh* theMesh,
533 const TopoDS_Face& theFace,
536 MESSAGE(" ::Load(face) " );
540 SMESHDS_Mesh * aMeshDS = theMesh->GetMeshDS();
541 SMESHDS_SubMesh * fSubMesh = aMeshDS->MeshElements( theFace );
543 int nbNodes = ( !fSubMesh ? 0 : fSubMesh->NbNodes() );
544 int nbElems = ( !fSubMesh ? 0 : fSubMesh->NbElements() );
545 if ( nbElems == 0 && aMeshDS->NbFaces() == 0 )
547 MESSAGE( "No elements bound to the face");
548 return setErrorCode( ERR_LOAD_EMPTY_SUBMESH );
551 // check that face is not closed
553 list<TopoDS_Edge> eList;
554 getOrderedEdges( theFace, bidon, eList, myNbKeyPntInBoundary );
555 list<TopoDS_Edge>::iterator elIt = eList.begin();
556 for ( ; elIt != eList.end() ; elIt++ )
557 if ( BRep_Tool::IsClosed( *elIt , theFace ))
558 return setErrorCode( ERR_LOADF_CLOSED_FACE );
561 Extrema_GenExtPS projector;
562 GeomAdaptor_Surface aSurface( BRep_Tool::Surface( theFace ));
563 if ( theProject || nbElems == 0 )
564 projector.Initialize( aSurface, 20,20, 1e-5,1e-5 );
567 TNodePointIDMap nodePointIDMap;
569 if ( nbElems == 0 || (theProject &&
570 theMesh->IsMainShape( theFace ) &&
571 !isMeshBoundToShape( theMesh )))
573 MESSAGE("Project the whole mesh");
574 // ---------------------------------------------------------------
575 // The case where the whole mesh is projected to theFace
576 // ---------------------------------------------------------------
578 // put nodes of all faces in the nodePointIDMap and fill myElemPointIDs
579 SMDS_FaceIteratorPtr fIt = aMeshDS->facesIterator();
580 while ( fIt->more() )
582 myElemPointIDs.push_back( list< int >() );
583 list< int >& elemPoints = myElemPointIDs.back();
584 SMDS_ElemIteratorPtr nIt = fIt->next()->nodesIterator();
585 while ( nIt->more() )
587 const SMDS_MeshElement* node = nIt->next();
588 TNodePointIDMap::iterator nIdIt = nodePointIDMap.find( node );
589 if ( nIdIt == nodePointIDMap.end() )
591 elemPoints.push_back( iPoint );
592 nodePointIDMap.insert( TNodePointIDMap::value_type( node, iPoint++ ));
595 elemPoints.push_back( (*nIdIt).second );
598 myPoints.resize( iPoint );
600 // project all nodes of 2d elements to theFace
601 TNodePointIDMap::iterator nIdIt = nodePointIDMap.begin();
602 for ( ; nIdIt != nodePointIDMap.end(); nIdIt++ )
604 const SMDS_MeshNode* node =
605 static_cast<const SMDS_MeshNode*>( (*nIdIt).first );
606 TPoint * p = & myPoints[ (*nIdIt).second ];
607 p->myInitUV = project( node, projector );
608 p->myInitXYZ.SetCoord( p->myInitUV.X(), p->myInitUV.Y(), 0 );
610 // find key-points: the points most close to UV of vertices
611 TopExp_Explorer vExp( theFace, TopAbs_VERTEX );
612 set<int> foundIndices;
613 for ( ; vExp.More(); vExp.Next() ) {
614 const TopoDS_Vertex v = TopoDS::Vertex( vExp.Current() );
615 gp_Pnt2d uv = BRep_Tool::Parameters( v, theFace );
616 double minDist = DBL_MAX;
618 vector< TPoint >::const_iterator pVecIt = myPoints.begin();
619 for ( iPoint = 0; pVecIt != myPoints.end(); pVecIt++, iPoint++ ) {
620 double dist = uv.SquareDistance( (*pVecIt).myInitUV );
621 if ( dist < minDist ) {
626 if ( foundIndices.insert( index ).second ) // unique?
627 myKeyPointIDs.push_back( index );
629 myIsBoundaryPointsFound = false;
634 // ---------------------------------------------------------------------
635 // The case where a pattern is being made from the mesh built by mesher
636 // ---------------------------------------------------------------------
638 // Load shapes in the consequent order and count nb of points
641 for ( elIt = eList.begin(); elIt != eList.end(); elIt++ ) {
642 myShapeIDMap.Add( TopExp::FirstVertex( *elIt, true ));
643 SMESHDS_SubMesh * eSubMesh = aMeshDS->MeshElements( *elIt );
645 nbNodes += eSubMesh->NbNodes() + 1;
648 for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
649 myShapeIDMap.Add( *elIt );
651 myShapeIDMap.Add( theFace );
653 myPoints.resize( nbNodes );
655 // Load U of points on edges
657 for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
659 TopoDS_Edge & edge = *elIt;
660 list< TPoint* > & ePoints = getShapePoints( edge );
662 Handle(Geom2d_Curve) C2d;
664 C2d = BRep_Tool::CurveOnSurface( edge, theFace, f, l );
665 bool isForward = ( edge.Orientation() == TopAbs_FORWARD );
667 // the forward key-point
668 TopoDS_Shape v = TopExp::FirstVertex( edge, true );
669 list< TPoint* > & vPoint = getShapePoints( v );
670 if ( vPoint.empty() )
672 SMESHDS_SubMesh * vSubMesh = aMeshDS->MeshElements( v );
673 if ( vSubMesh && vSubMesh->NbNodes() ) {
674 myKeyPointIDs.push_back( iPoint );
675 SMDS_NodeIteratorPtr nIt = vSubMesh->GetNodes();
676 const SMDS_MeshNode* node = nIt->next();
677 nodePointIDMap.insert( TNodePointIDMap::value_type( node, iPoint ));
679 TPoint* keyPoint = &myPoints[ iPoint++ ];
680 vPoint.push_back( keyPoint );
682 keyPoint->myInitUV = project( node, projector );
684 keyPoint->myInitUV = C2d->Value( isForward ? f : l ).XY();
685 keyPoint->myInitXYZ.SetCoord (keyPoint->myInitUV.X(), keyPoint->myInitUV.Y(), 0);
688 if ( !vPoint.empty() )
689 ePoints.push_back( vPoint.front() );
692 SMESHDS_SubMesh * eSubMesh = aMeshDS->MeshElements( edge );
693 if ( eSubMesh && eSubMesh->NbNodes() )
695 // loop on nodes of an edge: sort them by param on edge
696 typedef map < double, const SMDS_MeshNode* > TParamNodeMap;
697 TParamNodeMap paramNodeMap;
698 SMDS_NodeIteratorPtr nIt = eSubMesh->GetNodes();
699 while ( nIt->more() )
701 const SMDS_MeshNode* node =
702 static_cast<const SMDS_MeshNode*>( nIt->next() );
703 const SMDS_EdgePosition* epos =
704 static_cast<const SMDS_EdgePosition*>(node->GetPosition().get());
705 double u = epos->GetUParameter();
706 paramNodeMap.insert( TParamNodeMap::value_type( u, node ));
708 // put U in [0,1] so that the first key-point has U==0
710 TParamNodeMap::iterator unIt = paramNodeMap.begin();
711 TParamNodeMap::reverse_iterator unRIt = paramNodeMap.rbegin();
712 while ( unIt != paramNodeMap.end() )
714 TPoint* p = & myPoints[ iPoint ];
715 ePoints.push_back( p );
716 const SMDS_MeshNode* node = isForward ? (*unIt).second : (*unRIt).second;
717 nodePointIDMap.insert ( TNodePointIDMap::value_type( node, iPoint ));
720 p->myInitUV = project( node, projector );
722 double u = isForward ? (*unIt).first : (*unRIt).first;
723 p->myInitU = isForward ? (( u - f ) / du ) : ( 1.0 - ( u - f ) / du );
724 p->myInitUV = C2d->Value( u ).XY();
726 p->myInitXYZ.SetCoord( p->myInitUV.X(), p->myInitUV.Y(), 0 );
731 // the reverse key-point
732 v = TopExp::LastVertex( edge, true ).Reversed();
733 list< TPoint* > & vPoint2 = getShapePoints( v );
734 if ( vPoint2.empty() )
736 SMESHDS_SubMesh * vSubMesh = aMeshDS->MeshElements( v );
737 if ( vSubMesh && vSubMesh->NbNodes() ) {
738 myKeyPointIDs.push_back( iPoint );
739 SMDS_NodeIteratorPtr nIt = vSubMesh->GetNodes();
740 const SMDS_MeshNode* node = nIt->next();
741 nodePointIDMap.insert( TNodePointIDMap::value_type( node, iPoint ));
743 TPoint* keyPoint = &myPoints[ iPoint++ ];
744 vPoint2.push_back( keyPoint );
746 keyPoint->myInitUV = project( node, projector );
748 keyPoint->myInitUV = C2d->Value( isForward ? l : f ).XY();
749 keyPoint->myInitXYZ.SetCoord( keyPoint->myInitUV.X(), keyPoint->myInitUV.Y(), 0 );
752 if ( !vPoint2.empty() )
753 ePoints.push_back( vPoint2.front() );
755 // compute U of edge-points
758 double totalDist = 0;
759 list< TPoint* >::iterator pIt = ePoints.begin();
760 TPoint* prevP = *pIt;
761 prevP->myInitU = totalDist;
762 for ( pIt++; pIt != ePoints.end(); pIt++ ) {
764 totalDist += ( p->myInitUV - prevP->myInitUV ).SquareModulus();
765 p->myInitU = totalDist;
768 if ( totalDist > DBL_MIN)
769 for ( pIt = ePoints.begin(); pIt != ePoints.end(); pIt++ ) {
771 p->myInitU /= totalDist;
774 } // loop on edges of a wire
776 // Load in-face points and elements
778 if ( fSubMesh && fSubMesh->NbElements() )
780 list< TPoint* > & fPoints = getShapePoints( theFace );
781 SMDS_NodeIteratorPtr nIt = fSubMesh->GetNodes();
782 while ( nIt->more() )
784 const SMDS_MeshNode* node =
785 static_cast<const SMDS_MeshNode*>( nIt->next() );
786 nodePointIDMap.insert( TNodePointIDMap::value_type( node, iPoint ));
787 TPoint* p = &myPoints[ iPoint++ ];
788 fPoints.push_back( p );
790 p->myInitUV = project( node, projector );
792 const SMDS_FacePosition* pos =
793 static_cast<const SMDS_FacePosition*>(node->GetPosition().get());
794 p->myInitUV.SetCoord( pos->GetUParameter(), pos->GetVParameter() );
796 p->myInitXYZ.SetCoord( p->myInitUV.X(), p->myInitUV.Y(), 0 );
799 SMDS_ElemIteratorPtr elemIt = fSubMesh->GetElements();
800 while ( elemIt->more() ) {
801 SMDS_ElemIteratorPtr nIt = elemIt->next()->nodesIterator();
802 myElemPointIDs.push_back( list< int >() );
803 list< int >& elemPoints = myElemPointIDs.back();
804 while ( nIt->more() )
805 elemPoints.push_back( nodePointIDMap[ nIt->next() ]);
809 myIsBoundaryPointsFound = true;
812 // Assure that U range is proportional to V range
815 vector< TPoint >::iterator pVecIt = myPoints.begin();
816 for ( ; pVecIt != myPoints.end(); pVecIt++ )
817 bndBox.Add( gp_Pnt2d( (*pVecIt).myInitUV ));
818 double minU, minV, maxU, maxV;
819 bndBox.Get( minU, minV, maxU, maxV );
820 double dU = maxU - minU, dV = maxV - minV;
821 if ( dU <= DBL_MIN || dV <= DBL_MIN ) {
823 return setErrorCode( ERR_LOADF_NARROW_FACE );
825 double ratio = dU / dV, maxratio = 3, scale;
827 if ( ratio > maxratio ) {
828 scale = ratio / maxratio;
831 else if ( ratio < 1./maxratio ) {
832 scale = maxratio / ratio;
837 for ( pVecIt = myPoints.begin(); pVecIt != myPoints.end(); pVecIt++ ) {
838 TPoint & p = *pVecIt;
839 p.myInitUV.SetCoord( iCoord, p.myInitUV.Coord( iCoord ) * scale );
840 p.myInitXYZ.SetCoord( p.myInitUV.X(), p.myInitUV.Y(), 0 );
843 if ( myElemPointIDs.empty() ) {
844 MESSAGE( "No elements bound to the face");
845 return setErrorCode( ERR_LOAD_EMPTY_SUBMESH );
848 return setErrorCode( ERR_OK );
851 //=======================================================================
852 //function : computeUVOnEdge
853 //purpose : compute coordinates of points on theEdge
854 //=======================================================================
856 void SMESH_Pattern::computeUVOnEdge (const TopoDS_Edge& theEdge,
857 const list< TPoint* > & ePoints )
859 bool isForward = ( theEdge.Orientation() == TopAbs_FORWARD );
861 Handle(Geom2d_Curve) C2d =
862 BRep_Tool::CurveOnSurface( theEdge, TopoDS::Face( myShape ), f, l );
864 ePoints.back()->myInitU = 1.0;
865 list< TPoint* >::const_iterator pIt = ePoints.begin();
866 for ( pIt++; pIt != ePoints.end(); pIt++ )
868 TPoint* point = *pIt;
870 double du = ( isForward ? point->myInitU : 1 - point->myInitU );
871 point->myU = ( f * ( 1 - du ) + l * du );
873 point->myUV = C2d->Value( point->myU ).XY();
877 //=======================================================================
878 //function : intersectIsolines
880 //=======================================================================
882 static bool intersectIsolines(const gp_XY& uv11, const gp_XY& uv12, const double r1,
883 const gp_XY& uv21, const gp_XY& uv22, const double r2,
886 gp_XY loc1 = uv11 * ( 1 - r1 ) + uv12 * r1;
887 gp_XY loc2 = uv21 * ( 1 - r2 ) + uv22 * r2;
888 // resUV = 0.5 * ( loc1 + loc2 );
889 double len1 = ( uv11 - uv12 ).SquareModulus();
890 double len2 = ( uv21 - uv22 ).SquareModulus();
891 resUV = loc1 * len2 / ( len1 + len2 ) + loc2 * len1 / ( len1 + len2 );
895 // gp_Lin2d line1( uv11, uv12 - uv11 );
896 // gp_Lin2d line2( uv21, uv22 - uv21 );
897 // double angle = Abs( line1.Angle( line2 ) );
899 // IntAna2d_AnaIntersection inter;
900 // inter.Perform( line1.Normal( loc1 ), line2.Normal( loc2 ) );
901 // if ( inter.IsDone() && inter.NbPoints() == 1 )
903 // gp_Pnt2d interUV = inter.Point(1).Value();
904 // resUV += interUV.XY();
905 // inter.Perform( line1, line2 );
906 // interUV = inter.Point(1).Value();
907 // resUV += interUV.XY();
914 //=======================================================================
915 //function : compUVByIsoIntersection
917 //=======================================================================
919 bool SMESH_Pattern::compUVByIsoIntersection (const list< list< TPoint* > >& theBndPoints,
920 const gp_XY& theInitUV,
923 // compute UV by intersection of 2 iso lines
924 //gp_Lin2d isoLine[2];
925 gp_XY uv1[2], uv2[2];
927 const double zero = DBL_MIN;
928 for ( int iIso = 0; iIso < 2; iIso++ )
930 // to build an iso line:
931 // find 2 pairs of consequent edge-points such that the range of their
932 // initial parameters encloses the in-face point initial parameter
933 gp_XY UV[2], initUV[2];
934 int nbUV = 0, iCoord = iIso + 1;
935 double initParam = theInitUV.Coord( iCoord );
937 list< list< TPoint* > >::const_iterator bndIt = theBndPoints.begin();
938 for ( ; bndIt != theBndPoints.end(); bndIt++ )
940 const list< TPoint* > & bndPoints = * bndIt;
941 TPoint* prevP = bndPoints.back(); // this is the first point
942 list< TPoint* >::const_iterator pIt = bndPoints.begin();
943 bool coincPrev = false;
944 // loop on the edge-points
945 for ( ; pIt != bndPoints.end(); pIt++ )
947 double paramDiff = initParam - (*pIt)->myInitUV.Coord( iCoord );
948 double prevParamDiff = initParam - prevP->myInitUV.Coord( iCoord );
949 double sumOfDiff = Abs(prevParamDiff) + Abs(paramDiff);
950 if (!coincPrev && // ignore if initParam coincides with prev point param
951 sumOfDiff > zero && // ignore if both points coincide with initParam
952 prevParamDiff * paramDiff <= zero )
954 // find UV in parametric space of theFace
955 double r = Abs(prevParamDiff) / sumOfDiff;
956 gp_XY uvInit = (*pIt)->myInitUV * r + prevP->myInitUV * ( 1 - r );
959 // throw away uv most distant from <theInitUV>
960 gp_XY vec0 = initUV[0] - theInitUV;
961 gp_XY vec1 = initUV[1] - theInitUV;
962 gp_XY vec = uvInit - theInitUV;
963 bool isBetween = ( vec0 * vec1 < 0 ); // is theInitUV between initUV[0] and initUV[1]
964 double dist0 = vec0.SquareModulus();
965 double dist1 = vec1.SquareModulus();
966 double dist = vec .SquareModulus();
967 if ( !isBetween || dist < dist0 || dist < dist1 ) {
968 i = ( dist0 < dist1 ? 1 : 0 );
969 if ( isBetween && vec.Dot( i ? vec1 : vec0 ) < 0 )
970 i = 3; // theInitUV must remain between
974 initUV[ i ] = uvInit;
975 UV[ i ] = (*pIt)->myUV * r + prevP->myUV * ( 1 - r );
977 coincPrev = ( Abs(paramDiff) <= zero );
984 if ( nbUV < 2 || (UV[0]-UV[1]).SquareModulus() <= DBL_MIN*DBL_MIN ) {
985 MESSAGE(" consequent edge-points not found, nb UV found: " << nbUV <<
986 ", for point: " << theInitUV.X() <<" " << theInitUV.Y() );
987 return setErrorCode( ERR_APPLF_BAD_TOPOLOGY );
989 // an iso line should be normal to UV[0] - UV[1] direction
990 // and be located at the same relative distance as from initial ends
991 //gp_Lin2d iso( UV[0], UV[0] - UV[1] );
993 (initUV[0]-theInitUV).Modulus() / (initUV[0]-initUV[1]).Modulus();
994 gp_Pnt2d isoLoc = UV[0] * ( 1 - r ) + UV[1] * r;
995 //isoLine[ iIso ] = iso.Normal( isoLoc );
1000 if ( !intersectIsolines( uv1[0], uv2[0], ratio[0],
1001 uv1[1], uv2[1], ratio[1], theUV )) {
1002 MESSAGE(" Cant intersect isolines for a point "<<theInitUV.X()<<", "<<theInitUV.Y());
1003 return setErrorCode( ERR_APPLF_BAD_TOPOLOGY );
1009 // ==========================================================
1010 // structure representing a node of a grid of iso-poly-lines
1011 // ==========================================================
1019 TIsoNode(double initU, double initV): myInitUV( initU, initV ), myUV( 1e100, 1e100 )
1020 { myPrevUV[0] = myPrevUV[1] = myNextUV[0] = myNextUV[1] = 0; }
1021 bool IsUVComputed() const
1022 { return myUV.X() != 1e100; }
1023 bool IsMovable() const
1024 { return myPrevUV[0] && myPrevUV[1] && myNextUV[0] && myNextUV[1]; }
1025 void SetNotMovable()
1026 { myPrevUV[0] = 0; }
1029 //=======================================================================
1030 //function : compUVByElasticIsolines
1031 //purpose : compute UV as nodes of iso-poly-lines consisting of
1032 // segments keeping relative size as in the pattern
1033 //=======================================================================
1035 bool SMESH_Pattern::
1036 compUVByElasticIsolines(const list< list< TPoint* > >& theBndPoints,
1037 const list< TPoint* >& thePntToCompute)
1039 // Define parameters of iso-grid nodes in U and V dir
1041 set< double > paramSet[ 2 ];
1042 list< list< TPoint* > >::const_iterator pListIt;
1043 list< TPoint* >::const_iterator pIt;
1044 // for ( pListIt = theBndPoints.begin(); pListIt != theBndPoints.end(); pListIt++ ) {
1045 // const list< TPoint* > & pList = * pListIt;
1046 // for ( pIt = pList.begin(); pIt != pList.end(); pIt++ ) {
1047 // paramSet[0].insert( (*pIt)->myInitUV.X() );
1048 // paramSet[1].insert( (*pIt)->myInitUV.Y() );
1051 for ( pIt = thePntToCompute.begin(); pIt != thePntToCompute.end(); pIt++ ) {
1052 paramSet[0].insert( (*pIt)->myInitUV.X() );
1053 paramSet[1].insert( (*pIt)->myInitUV.Y() );
1055 // unite close parameters and split too long segments
1058 for ( iDir = 0; iDir < 2; iDir++ )
1060 set< double > & params = paramSet[ iDir ];
1061 double range = ( *params.rbegin() - *params.begin() );
1062 double toler = range / 1e6;
1063 double maxSegment = range / params.size() / 2.;
1064 tol[ iDir ] = toler;
1066 // set< double >::iterator parIt = params.begin();
1067 // double prevPar = *parIt;
1068 // for ( parIt++; parIt != params.end(); parIt++ )
1070 // double segLen = (*parIt) - prevPar;
1071 // if ( segLen < toler )
1072 // params.erase( prevPar ); // unite
1073 // else if ( segLen > maxSegment )
1074 // params.insert( prevPar + 0.5 * segLen ); // split
1075 // prevPar = (*parIt);
1079 // Make nodes of a grid of iso-poly-lines
1081 list < TIsoNode > nodes;
1082 typedef list < TIsoNode *> TIsoLine;
1083 map < double, TIsoLine > isoMap[ 2 ];
1085 set< double > & params0 = paramSet[ 0 ];
1086 set< double >::iterator par0It = params0.begin();
1087 for ( ; par0It != params0.end(); par0It++ )
1089 TIsoLine & isoLine0 = isoMap[0][ *par0It ]; // isoline with const U
1090 set< double > & params1 = paramSet[ 1 ];
1091 set< double >::iterator par1It = params1.begin();
1092 for ( ; par1It != params1.end(); par1It++ )
1094 nodes.push_back( TIsoNode( *par0It, *par1It ) );
1095 isoLine0.push_back( & nodes.back() );
1096 isoMap[1][ *par1It ].push_back( & nodes.back() );
1100 // Compute intersections of boundaries with iso-lines
1103 list< list< TPoint* > >::const_iterator bndIt = theBndPoints.begin();
1104 for ( ; bndIt != theBndPoints.end(); bndIt++ )
1106 const list< TPoint* > & bndPoints = * bndIt;
1107 TPoint* prevP = bndPoints.back(); // this is the first point
1108 list< TPoint* >::const_iterator pIt = bndPoints.begin();
1109 // loop on the edge-points
1110 for ( ; pIt != bndPoints.end(); pIt++ )
1112 TPoint* point = *pIt;
1113 uvBox.Add( gp_Pnt2d( point->myUV ));
1114 for ( iDir = 0; iDir < 2; iDir++ )
1116 const int iCoord = iDir + 1;
1117 const int iOtherCoord = 2 - iDir;
1118 double par1 = prevP->myInitUV.Coord( iCoord );
1119 double par2 = point->myInitUV.Coord( iCoord );
1120 double parDif = par2 - par1;
1121 if ( Abs( parDif ) <= DBL_MIN )
1123 // find iso-lines intersecting a bounadry
1124 double toler = tol[ 1 - iDir ];
1125 double minPar = Min ( par1, par2 );
1126 double maxPar = Max ( par1, par2 );
1127 map < double, TIsoLine >& isos = isoMap[ iDir ];
1128 map < double, TIsoLine >::iterator isoIt = isos.begin();
1129 for ( ; isoIt != isos.end(); isoIt++ )
1131 double isoParam = (*isoIt).first;
1132 if ( isoParam < minPar || isoParam > maxPar )
1134 double r = ( isoParam - par1 ) / parDif;
1135 gp_XY uv = ( 1 - r ) * prevP->myUV + r * point->myUV;
1136 gp_XY initUV = ( 1 - r ) * prevP->myInitUV + r * point->myInitUV;
1137 double otherPar = initUV.Coord( iOtherCoord ); // along isoline
1138 // find existing node with otherPar or insert a new one
1139 TIsoLine & isoLine = (*isoIt).second;
1141 TIsoLine::iterator nIt = isoLine.begin();
1142 for ( ; nIt != isoLine.end(); nIt++ ) {
1143 nodePar = (*nIt)->myInitUV.Coord( iOtherCoord );
1144 if ( nodePar >= otherPar )
1148 if ( Abs( nodePar - otherPar ) <= toler )
1151 nodes.push_back( TIsoNode( initUV.X(), initUV.Y() ) );
1152 node = & nodes.back();
1153 isoLine.insert( nIt, node );
1159 } // loop on boundary points
1160 } // loop on boundaries
1162 // Connect XY of nodes and mark not movable nodes out of the boundary
1164 for ( iDir = 0; iDir < 2; iDir++ )
1166 const int iCoord = 2 - iDir;
1167 map < double, TIsoLine >& isos = isoMap[ iDir ];
1168 map < double, TIsoLine >::iterator isoIt = isos.begin();
1169 for ( ; isoIt != isos.end(); isoIt++ )
1171 TIsoLine & isoLine = (*isoIt).second;
1172 bool firstCompNodeFound = false;
1173 TIsoLine::iterator lastCompNodePos, nPrevIt, nIt, nNextIt;
1174 nPrevIt = nIt = nNextIt = isoLine.begin();
1176 nNextIt++; nNextIt++;
1177 while ( nIt != isoLine.end() )
1179 // connect prev - cur for internal nodes
1180 TIsoNode* node = *nIt, * prevNode = *nPrevIt;
1181 if ( !node->IsUVComputed() )
1182 node->myPrevUV[ iDir ] = & prevNode->myUV;
1183 if ( !prevNode->IsUVComputed() )
1184 prevNode->myNextUV[ iDir ] = & node->myUV;
1186 if ( nNextIt != isoLine.end() ) {
1187 double par1 = prevNode->myInitUV.Coord( iCoord );
1188 double par2 = node->myInitUV.Coord( iCoord );
1189 double par3 = (*nNextIt)->myInitUV.Coord( iCoord );
1190 node->myRatio[ iDir ] = ( par2 - par1 ) / ( par3 - par1 );
1193 // mark not movable before the boundary
1194 if ( !firstCompNodeFound ) {
1195 if ( !prevNode->IsUVComputed() )
1196 prevNode->SetNotMovable();
1198 firstCompNodeFound = true;
1200 if ( node->IsUVComputed() )
1201 lastCompNodePos = nIt;
1204 // mark not movable after the boundary
1205 for ( nIt = ++lastCompNodePos; nIt != isoLine.end(); nIt++ )
1206 (*nIt)->SetNotMovable();
1210 // Compute starting UV of internal nodes by iso intersection
1212 map < double, TIsoLine >& isos = isoMap[ 0 ];
1213 map < double, TIsoLine >::iterator isoIt = isos.begin();
1214 for ( ; isoIt != isos.end(); isoIt++ )
1216 TIsoLine & isoLine = (*isoIt).second;
1217 TIsoLine::iterator nIt = isoLine.begin();
1218 for ( ; nIt != isoLine.end(); nIt++ )
1220 TIsoNode* node = *nIt;
1221 if ( !node->IsUVComputed() && node->IsMovable() )
1222 if ( !compUVByIsoIntersection( theBndPoints, node->myInitUV, node->myUV ))
1223 node->myUV = node->myInitUV;
1229 static int maxNbIter = 100; // -1
1231 maxNbIter = ( maxNbIter < 0 ) ? 100 : -1;
1236 if ( nbIter >= maxNbIter ) break;
1238 list < TIsoNode >::iterator nIt = nodes.begin();
1239 for ( ; nIt != nodes.end(); nIt++ ) {
1240 TIsoNode & node = *nIt;
1241 if ( node.IsMovable() )
1245 bool lineFound = true;
1246 for ( iDir = 0; iDir < 2; iDir++ )
1249 gp_XY uv1( *node.myPrevUV[ iDir ] ), uv2( *node.myNextUV[ iDir ] );
1250 gp_XY dUV( uv2 - uv1 );
1251 if ( dUV.SquareModulus() <= DBL_MIN * DBL_MIN ) {
1255 double r = node.myRatio[ iDir ];
1256 gp_Lin2d l( uv1, dUV );
1257 gp_XY loc = uv1 * ( 1 - r ) + uv2 * r;
1258 location[ iDir ] = loc;
1259 line[ iDir ] = l/*.Normal( loc )*/;
1261 // intersect the 2 lines and move a node
1264 intersectIsolines (*node.myPrevUV[0], *node.myNextUV[0], node.myRatio[0],
1265 *node.myPrevUV[0], *node.myNextUV[0], node.myRatio[0],
1267 !uvBox.IsOut( newUV ) )
1269 maxMove = Max( maxMove, ( newUV - node.myUV ).SquareModulus());
1274 } while ( maxMove > 1e-8 && nbIter++ < maxNbIter );
1276 MESSAGE( "compUVByElasticIsolines(): Nb iterations " << nbIter << " dist: " << sqrt( maxMove ));
1278 // Set computed UV to points
1280 for ( pIt = thePntToCompute.begin(); pIt != thePntToCompute.end(); pIt++ ) {
1281 TPoint* point = *pIt;
1282 gp_XY oldUV = point->myUV;
1283 double minDist = DBL_MAX;
1284 list < TIsoNode >::iterator nIt = nodes.begin();
1285 for ( ; nIt != nodes.end(); nIt++ ) {
1286 double dist = ( (*nIt).myInitUV - point->myInitUV ).SquareModulus();
1287 if ( dist < minDist ) {
1289 point->myUV = (*nIt).myUV;
1299 //=======================================================================
1300 //function : setFirstEdge
1301 //purpose : choose the best first edge of theWire; return the summary distance
1302 // between point UV computed by isolines intersection and
1303 // eventual UV got from edge p-curves
1304 //=======================================================================
1306 //#define DBG_SETFIRSTEDGE
1307 double SMESH_Pattern::setFirstEdge (list< TopoDS_Edge > & theWire, int theFirstEdgeID)
1309 int iE, nbEdges = theWire.size();
1313 // Transform UVs computed by iso to fit bnd box of a wire
1315 // max nb of points on an edge
1317 int eID = theFirstEdgeID;
1318 for ( iE = 0; iE < nbEdges; iE++ )
1319 maxNbPnt = Max ( maxNbPnt, getShapePoints( eID++ ).size() );
1321 // compute bnd boxes
1322 TopoDS_Face face = TopoDS::Face( myShape );
1323 Bnd_Box2d bndBox, eBndBox;
1324 eID = theFirstEdgeID;
1325 list< TopoDS_Edge >::iterator eIt;
1326 list< TPoint* >::iterator pIt;
1327 for ( eIt = theWire.begin(); eIt != theWire.end(); eIt++ )
1329 // UV by isos stored in TPoint.myXYZ
1330 list< TPoint* > & ePoints = getShapePoints( eID++ );
1331 for ( pIt = ePoints.begin(); pIt != ePoints.end(); pIt++ ) {
1333 bndBox.Add( gp_Pnt2d( p->myXYZ.X(), p->myXYZ.Y() ));
1335 // UV by an edge p-curve
1337 Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface( *eIt, face, f, l );
1338 double dU = ( l - f ) / ( maxNbPnt - 1 );
1339 for ( int i = 0; i < maxNbPnt; i++ )
1340 eBndBox.Add( C2d->Value( f + i * dU ));
1343 // transform UVs by isos
1344 double minPar[2], maxPar[2], eMinPar[2], eMaxPar[2];
1345 bndBox.Get( minPar[0], minPar[1], maxPar[0], maxPar[1] );
1346 eBndBox.Get( eMinPar[0], eMinPar[1], eMaxPar[0], eMaxPar[1] );
1347 #ifdef DBG_SETFIRSTEDGE
1348 cout << "EDGES: X: " << eMinPar[0] << " - " << eMaxPar[0] << " Y: "
1349 << eMinPar[1] << " - " << eMaxPar[1] << endl;
1351 for ( int iC = 1, i = 0; i < 2; iC++, i++ ) // loop on 2 coordinates
1353 double dMin = eMinPar[i] - minPar[i];
1354 double dMax = eMaxPar[i] - maxPar[i];
1355 double dPar = maxPar[i] - minPar[i];
1356 eID = theFirstEdgeID;
1357 for ( iE = 0; iE < nbEdges; iE++ ) // loop on edges of a boundary
1359 list< TPoint* > & ePoints = getShapePoints( eID++ );
1360 for ( pIt = ++ePoints.begin(); pIt != ePoints.end(); pIt++ ) // loop on edge points
1362 double par = (*pIt)->myXYZ.Coord( iC );
1363 double r = ( par - minPar[i] ) / dPar;
1364 par += ( 1 - r ) * dMin + r * dMax;
1365 (*pIt)->myXYZ.SetCoord( iC, par );
1371 double minDist = DBL_MAX;
1372 for ( iE = 0 ; iE < nbEdges; iE++ )
1374 #ifdef DBG_SETFIRSTEDGE
1375 cout << " VARIANT " << iE << endl;
1377 // evaluate the distance between UV computed by the 2 methods:
1378 // by isos intersection ( myXYZ ) and by edge p-curves ( myUV )
1380 int eID = theFirstEdgeID;
1381 for ( eIt = theWire.begin(); eIt != theWire.end(); eIt++ )
1383 list< TPoint* > & ePoints = getShapePoints( eID++ );
1384 computeUVOnEdge( *eIt, ePoints );
1385 for ( pIt = ++ePoints.begin(); pIt != ePoints.end(); pIt++ ) {
1387 dist += ( p->myUV - gp_XY( p->myXYZ.X(), p->myXYZ.Y() )).SquareModulus();
1388 #ifdef DBG_SETFIRSTEDGE
1389 cout << " ISO : ( " << p->myXYZ.X() << ", "<< p->myXYZ.Y() << " ) PCURVE : ( " <<
1390 p->myUV.X() << ", " << p->myUV.Y() << ") " << endl;
1394 #ifdef DBG_SETFIRSTEDGE
1395 cout << "dist -- " << dist << endl;
1397 if ( dist < minDist ) {
1399 eBest = theWire.front();
1401 // check variant with another first edge
1402 theWire.splice( theWire.begin(), theWire, --theWire.end(), theWire.end() );
1404 // put the best first edge to the theWire front
1405 if ( eBest != theWire.front() ) {
1406 eIt = find ( theWire.begin(), theWire.end(), eBest );
1407 theWire.splice( theWire.begin(), theWire, eIt, theWire.end() );
1413 //=======================================================================
1414 //function : sortSameSizeWires
1415 //purpose : sort wires in theWireList from theFromWire until theToWire,
1416 // the wires are set in the order to correspond to the order
1417 // of boundaries; after sorting, edges in the wires are put
1418 // in a good order, point UVs on edges are computed and points
1419 // are appended to theEdgesPointsList
1420 //=======================================================================
1422 bool SMESH_Pattern::sortSameSizeWires (TListOfEdgesList & theWireList,
1423 const TListOfEdgesList::iterator& theFromWire,
1424 const TListOfEdgesList::iterator& theToWire,
1425 const int theFirstEdgeID,
1426 list< list< TPoint* > >& theEdgesPointsList )
1428 TopoDS_Face F = TopoDS::Face( myShape );
1429 int iE, nbEdgeInWire = (*theFromWire).size();
1430 int iW, nbWires = 0;
1431 TListOfEdgesList::iterator wlIt = theFromWire;
1432 while ( wlIt++ != theToWire )
1435 // Recompute key-point UVs by isolines intersection,
1436 // compute CG of key-points for each wire and bnd boxes of GCs
1438 gp_XY orig( gp::Origin2d().XY() );
1439 vector< gp_XY > vGcVec( nbWires, orig ), gcVec( nbWires, orig );
1440 Bnd_Box2d bndBox, vBndBox;
1441 int eID = theFirstEdgeID;
1442 list< TopoDS_Edge >::iterator eIt;
1443 for ( iW = 0, wlIt = theFromWire; wlIt != theToWire; wlIt++, iW++ )
1445 list< TopoDS_Edge > & wire = *wlIt;
1446 for ( eIt = wire.begin(); eIt != wire.end(); eIt++ )
1448 list< TPoint* > & ePoints = getShapePoints( eID++ );
1449 TPoint* p = ePoints.front();
1450 if ( !compUVByIsoIntersection( theEdgesPointsList, p->myInitUV, p->myUV )) {
1451 MESSAGE("cant sortSameSizeWires()");
1454 gcVec[iW] += p->myUV;
1455 bndBox.Add( gp_Pnt2d( p->myUV ));
1456 TopoDS_Vertex V = TopExp::FirstVertex( *eIt, true );
1457 gp_Pnt2d vXY = BRep_Tool::Parameters( V, F );
1458 vGcVec[iW] += vXY.XY();
1460 // keep the computed UV to compare against by setFirstEdge()
1461 p->myXYZ.SetCoord( p->myUV.X(), p->myUV.Y(), 0. );
1463 gcVec[iW] /= nbWires;
1464 vGcVec[iW] /= nbWires;
1465 // cout << " Wire " << iW << " iso: " << gcVec[iW].X() << " " << gcVec[iW].Y() << endl <<
1466 // " \t vertex: " << vGcVec[iW].X() << " " << vGcVec[iW].Y() << endl;
1469 // Transform GCs computed by isos to fit in bnd box of GCs by vertices
1471 double minPar[2], maxPar[2], vMinPar[2], vMaxPar[2];
1472 bndBox.Get( minPar[0], minPar[1], maxPar[0], maxPar[1] );
1473 vBndBox.Get( vMinPar[0], vMinPar[1], vMaxPar[0], vMaxPar[1] );
1474 for ( int iC = 1, i = 0; i < 2; iC++, i++ ) // loop on 2 coordinates
1476 double dMin = vMinPar[i] - minPar[i];
1477 double dMax = vMaxPar[i] - maxPar[i];
1478 double dPar = maxPar[i] - minPar[i];
1479 if ( Abs( dPar ) <= DBL_MIN )
1481 for ( iW = 0; iW < nbWires; iW++ ) { // loop on GCs of wires
1482 double par = gcVec[iW].Coord( iC );
1483 double r = ( par - minPar[i] ) / dPar;
1484 par += ( 1 - r ) * dMin + r * dMax;
1485 gcVec[iW].SetCoord( iC, par );
1489 // Define boundary - wire correspondence by GC closeness
1491 TListOfEdgesList tmpWList;
1492 tmpWList.splice( tmpWList.end(), theWireList, theFromWire, theToWire );
1493 typedef map< int, TListOfEdgesList::iterator > TIntWirePosMap;
1494 TIntWirePosMap bndIndWirePosMap;
1495 vector< bool > bndFound( nbWires, false );
1496 for ( iW = 0, wlIt = tmpWList.begin(); iW < nbWires; iW++, wlIt++ )
1498 // cout << " TRSF Wire " << iW << " iso: " << gcVec[iW].X() << " " << gcVec[iW].Y() << endl <<
1499 // " \t vertex: " << vGcVec[iW].X() << " " << vGcVec[iW].Y() << endl;
1500 double minDist = DBL_MAX;
1501 gp_XY & wGc = vGcVec[ iW ];
1503 for ( int iB = 0; iB < nbWires; iB++ ) {
1504 if ( bndFound[ iB ] ) continue;
1505 double dist = ( wGc - gcVec[ iB ] ).SquareModulus();
1506 if ( dist < minDist ) {
1511 bndFound[ bIndex ] = true;
1512 bndIndWirePosMap.insert( TIntWirePosMap::value_type( bIndex, wlIt ));
1517 TIntWirePosMap::iterator bIndWPosIt = bndIndWirePosMap.begin();
1518 eID = theFirstEdgeID;
1519 for ( ; bIndWPosIt != bndIndWirePosMap.end(); bIndWPosIt++ )
1521 TListOfEdgesList::iterator wirePos = (*bIndWPosIt).second;
1522 list < TopoDS_Edge > & wire = ( *wirePos );
1524 // choose the best first edge of a wire
1525 setFirstEdge( wire, eID );
1527 // compute eventual UV and fill theEdgesPointsList
1528 theEdgesPointsList.push_back( list< TPoint* >() );
1529 list< TPoint* > & edgesPoints = theEdgesPointsList.back();
1530 for ( eIt = wire.begin(); eIt != wire.end(); eIt++ )
1532 list< TPoint* > & ePoints = getShapePoints( eID++ );
1533 computeUVOnEdge( *eIt, ePoints );
1535 // put wire back to theWireList
1537 theWireList.splice( theToWire, tmpWList, wlIt, wirePos );
1543 //=======================================================================
1545 //purpose : Compute nodes coordinates applying
1546 // the loaded pattern to <theFace>. The first key-point
1547 // will be mapped into <theVertexOnKeyPoint1>
1548 //=======================================================================
1550 bool SMESH_Pattern::Apply (const TopoDS_Face& theFace,
1551 const TopoDS_Vertex& theVertexOnKeyPoint1,
1552 const bool theReverse)
1554 MESSAGE(" ::Apply(face) " );
1555 TopoDS_Face face = theReverse ? TopoDS::Face( theFace.Reversed() ) : theFace;
1556 if ( !setShapeToMesh( face ))
1559 // find points on edges, it fills myNbKeyPntInBoundary
1560 if ( !findBoundaryPoints() )
1563 // Define the edges order so that the first edge starts at
1564 // theVertexOnKeyPoint1
1566 list< TopoDS_Edge > eList;
1567 list< int > nbVertexInWires;
1568 int nbWires = getOrderedEdges( face, theVertexOnKeyPoint1, eList, nbVertexInWires);
1569 if ( !theVertexOnKeyPoint1.IsSame( TopExp::FirstVertex( eList.front(), true )))
1571 MESSAGE( " theVertexOnKeyPoint1 not found in the outer wire ");
1572 return setErrorCode( ERR_APPLF_BAD_VERTEX );
1574 // check nb wires and edges
1575 list< int > l1 = myNbKeyPntInBoundary, l2 = nbVertexInWires;
1576 l1.sort(); l2.sort();
1579 MESSAGE( "Wrong nb vertices in wires" );
1580 return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
1583 // here shapes get IDs, for the outer wire IDs are OK
1584 list<TopoDS_Edge>::iterator elIt = eList.begin();
1585 for ( ; elIt != eList.end(); elIt++ ) {
1586 myShapeIDMap.Add( TopExp::FirstVertex( *elIt, true ));
1587 if ( BRep_Tool::IsClosed( *elIt, theFace ) )
1588 myShapeIDMap.Add( TopExp::LastVertex( *elIt, true ));
1590 int nbVertices = myShapeIDMap.Extent();
1592 //int nbSeamShapes = 0; // count twice seam edge and its vertices
1593 for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
1594 myShapeIDMap.Add( *elIt );
1596 myShapeIDMap.Add( face );
1598 if ( myShapeIDToPointsMap.size() != myShapeIDMap.Extent()/* + nbSeamShapes*/ ) {
1599 MESSAGE( myShapeIDToPointsMap.size() <<" != " << myShapeIDMap.Extent());
1600 return setErrorCode( ERR_APPLF_INTERNAL_EEROR );
1603 // points on edges to be used for UV computation of in-face points
1604 list< list< TPoint* > > edgesPointsList;
1605 edgesPointsList.push_back( list< TPoint* >() );
1606 list< TPoint* > * edgesPoints = & edgesPointsList.back();
1607 list< TPoint* >::iterator pIt;
1609 // compute UV of points on the outer wire
1610 int iE, nbEdgesInOuterWire = nbVertexInWires.front();
1611 for (iE = 0, elIt = eList.begin();
1612 iE < nbEdgesInOuterWire && elIt != eList.end();
1615 list< TPoint* > & ePoints = getShapePoints( *elIt );
1617 computeUVOnEdge( *elIt, ePoints );
1618 // collect on-edge points (excluding the last one)
1619 edgesPoints->insert( edgesPoints->end(), ePoints.begin(), --ePoints.end());
1622 // If there are several wires, define the order of edges of inner wires:
1623 // compute UV of inner edge-points using 2 methods: the one for in-face points
1624 // and the one for on-edge points and then choose the best edge order
1625 // by the best correspondance of the 2 results
1628 // compute UV of inner edge-points using the method for in-face points
1629 // and devide eList into a list of separate wires
1630 list< list< TopoDS_Edge > > wireList;
1631 list<TopoDS_Edge>::iterator eIt = elIt;
1632 list<int>::iterator nbEIt = nbVertexInWires.begin();
1633 for ( nbEIt++; nbEIt != nbVertexInWires.end(); nbEIt++ )
1635 int nbEdges = *nbEIt;
1636 wireList.push_back( list< TopoDS_Edge >() );
1637 list< TopoDS_Edge > & wire = wireList.back();
1638 for ( iE = 0 ; iE < nbEdges; eIt++, iE++ )
1640 list< TPoint* > & ePoints = getShapePoints( *eIt );
1641 pIt = ePoints.begin();
1642 for ( pIt++; pIt != ePoints.end(); pIt++ ) {
1644 if ( !compUVByIsoIntersection( edgesPointsList, p->myInitUV, p->myUV )) {
1645 MESSAGE("cant Apply(face)");
1648 // keep the computed UV to compare against by setFirstEdge()
1649 p->myXYZ.SetCoord( p->myUV.X(), p->myUV.Y(), 0. );
1651 wire.push_back( *eIt );
1654 // remove inner edges from eList
1655 eList.erase( elIt, eList.end() );
1657 // sort wireList by nb edges in a wire
1658 sortBySize< TopoDS_Edge > ( wireList );
1660 // an ID of the first edge of a boundary
1661 int id1 = nbVertices + nbEdgesInOuterWire + 1;
1662 // if ( nbSeamShapes > 0 )
1663 // id1 += 2; // 2 vertices more
1665 // find points - edge correspondence for wires of unique size,
1666 // edge order within a wire should be defined only
1668 list< list< TopoDS_Edge > >::iterator wlIt = wireList.begin();
1669 while ( wlIt != wireList.end() )
1671 list< TopoDS_Edge >& wire = (*wlIt);
1672 int nbEdges = wire.size();
1674 if ( wlIt == wireList.end() || (*wlIt).size() != nbEdges ) // a unique size wire
1676 // choose the best first edge of a wire
1677 setFirstEdge( wire, id1 );
1679 // compute eventual UV and collect on-edge points
1680 edgesPointsList.push_back( list< TPoint* >() );
1681 edgesPoints = & edgesPointsList.back();
1683 for ( eIt = wire.begin(); eIt != wire.end(); eIt++ )
1685 list< TPoint* > & ePoints = getShapePoints( eID++ );
1686 computeUVOnEdge( *eIt, ePoints );
1687 edgesPoints->insert( edgesPoints->end(), ePoints.begin(), (--ePoints.end()));
1693 // find boundary - wire correspondence for several wires of same size
1695 id1 = nbVertices + nbEdgesInOuterWire + 1;
1696 wlIt = wireList.begin();
1697 while ( wlIt != wireList.end() )
1699 int nbSameSize = 0, nbEdges = (*wlIt).size();
1700 list< list< TopoDS_Edge > >::iterator wlIt2 = wlIt;
1702 while ( wlIt2 != wireList.end() && (*wlIt2).size() == nbEdges ) { // a same size wire
1706 if ( nbSameSize > 0 )
1707 if (!sortSameSizeWires(wireList, wlIt, wlIt2, id1, edgesPointsList))
1710 id1 += nbEdges * ( nbSameSize + 1 );
1713 // add well-ordered edges to eList
1715 for ( wlIt = wireList.begin(); wlIt != wireList.end(); wlIt++ )
1717 list< TopoDS_Edge >& wire = (*wlIt);
1718 eList.splice( eList.end(), wire, wire.begin(), wire.end() );
1721 // re-fill myShapeIDMap - all shapes get good IDs
1723 myShapeIDMap.Clear();
1724 for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
1725 myShapeIDMap.Add( TopExp::FirstVertex( *elIt, true ));
1726 for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
1727 myShapeIDMap.Add( *elIt );
1728 myShapeIDMap.Add( face );
1730 } // there are inner wires
1732 // Compute XYZ of on-edge points
1734 TopLoc_Location loc;
1735 for ( iE = nbVertices + 1, elIt = eList.begin(); elIt != eList.end(); elIt++ )
1738 Handle(Geom_Curve) C3d = BRep_Tool::Curve( *elIt, loc, f, l );
1739 const gp_Trsf & aTrsf = loc.Transformation();
1740 list< TPoint* > & ePoints = getShapePoints( iE++ );
1741 pIt = ePoints.begin();
1742 for ( pIt++; pIt != ePoints.end(); pIt++ )
1744 TPoint* point = *pIt;
1745 point->myXYZ = C3d->Value( point->myU );
1746 if ( !loc.IsIdentity() )
1747 aTrsf.Transforms( point->myXYZ.ChangeCoord() );
1751 // Compute UV and XYZ of in-face points by intersection of 2 iso lines
1753 list< TPoint* > & fPoints = getShapePoints( face );
1754 for ( pIt = fPoints.begin(); pIt != fPoints.end(); pIt++ )
1756 TPoint * point = *pIt;
1757 if ( !compUVByIsoIntersection( edgesPointsList, point->myInitUV, point->myUV )) {
1758 MESSAGE("cant Apply(face)");
1763 // compUVByElasticIsolines( edgesPointsList, fPoints );
1765 Handle(Geom_Surface) aSurface = BRep_Tool::Surface( face, loc );
1766 const gp_Trsf & aTrsf = loc.Transformation();
1767 for ( pIt = fPoints.begin(); pIt != fPoints.end(); pIt++ )
1769 TPoint * point = *pIt;
1770 point->myXYZ = aSurface->Value( point->myUV.X(), point->myUV.Y() );
1771 if ( !loc.IsIdentity() )
1772 aTrsf.Transforms( point->myXYZ.ChangeCoord() );
1775 myIsComputed = true;
1777 return setErrorCode( ERR_OK );
1780 // =========================================================
1781 // class calculating coordinates of 3D points by normalized
1782 // parameters inside the block and vice versa
1783 // =========================================================
1785 class TBlock: public math_FunctionSetWithDerivatives
1788 enum TBlockShapeID { // ids of the block sub-shapes
1789 ID_V000 = 1, ID_V100, ID_V010, ID_V110, ID_V001, ID_V101, ID_V011, ID_V111,
1791 ID_Ex00, ID_Ex10, ID_Ex01, ID_Ex11,
1792 ID_E0y0, ID_E1y0, ID_E0y1, ID_E1y1,
1793 ID_E00z, ID_E10z, ID_E01z, ID_E11z,
1795 ID_Fxy0, ID_Fxy1, ID_Fx0z, ID_Fx1z, ID_F0yz, ID_F1yz,
1800 bool IsVertexID( int theShapeID )
1801 { return ( theShapeID >= ID_V000 && theShapeID <= ID_V111 ); }
1802 static inline bool IsEdgeID( int theShapeID )
1803 { return ( theShapeID >= ID_Ex00 && theShapeID <= ID_E11z ); }
1804 static inline bool IsFaceID( int theShapeID )
1805 { return ( theShapeID >= ID_Fxy0 && theShapeID <= ID_F1yz ); }
1808 TBlock (const TopoDS_Shell& theBlock):
1809 myShell( theBlock ), myNbIterations(0), mySumDist(0.) {}
1811 bool LoadBlockShapes(const TopoDS_Vertex& theVertex000,
1812 const TopoDS_Vertex& theVertex001,
1813 // TopTools_IndexedMapOfShape& theShapeIDMap
1814 TopTools_IndexedMapOfOrientedShape& theShapeIDMap );
1815 // add sub-shapes of theBlock to theShapeIDMap so that they get
1816 // IDs acoording to enum TBlockShapeID
1818 static int GetShapeIDByParams ( const gp_XYZ& theParams );
1819 // define an id of the block sub-shape by point parameters
1821 bool VertexPoint( const int theVertexID, gp_XYZ& thePoint ) const {
1822 if ( !IsVertexID( theVertexID )) return false;
1823 thePoint = myPnt[ theVertexID - ID_V000 ]; return true;
1825 // return vertex coordinates
1827 bool EdgePoint( const int theEdgeID, const gp_XYZ& theParams, gp_XYZ& thePoint ) const {
1828 if ( !IsEdgeID( theEdgeID )) return false;
1829 thePoint = myEdge[ theEdgeID - ID_Ex00 ].Point( theParams ); return true;
1831 // return coordinates of a point on edge
1833 bool FacePoint( const int theFaceID, const gp_XYZ& theParams, gp_XYZ& thePoint ) const {
1834 if ( !IsFaceID ( theFaceID )) return false;
1835 thePoint = myFace[ theFaceID - ID_Fxy0 ].Point( theParams ); return true;
1837 // return coordinates of a point on face
1839 bool ShellPoint( const gp_XYZ& theParams, gp_XYZ& thePoint ) const;
1840 // return coordinates of a point in shell
1842 bool ComputeParameters (const gp_Pnt& thePoint,
1844 const int theShapeID = ID_Shell);
1845 // compute point parameters in the block
1847 static void GetFaceEdgesIDs (const int faceID, vector< int >& edgeVec );
1848 // return edges IDs of a face in the order u0, u1, 0v, 1v
1850 static int GetCoordIndOnEdge (const int theEdgeID)
1851 { return (theEdgeID < ID_E0y0) ? 1 : (theEdgeID < ID_E00z) ? 2 : 3; }
1852 // return an index of a coordinate which varies along the edge
1854 static double* GetShapeCoef (const int theShapeID);
1855 // for theShapeID( TBlockShapeID ), returns 3 coefficients used
1856 // to compute an addition of an on-theShape point to coordinates
1857 // of an in-shell point. If an in-shell point has parameters (Px,Py,Pz),
1858 // then the addition of a point P is computed as P*kx*ky*kz and ki is
1859 // defined by the returned coef like this:
1860 // ki = (coef[i] == 0) ? 1 : (coef[i] < 0) ? 1 - Pi : Pi
1862 static bool IsForwardEdge (const TopoDS_Edge & theEdge,
1863 //TopTools_IndexedMapOfShape& theShapeIDMap
1864 TopTools_IndexedMapOfOrientedShape& theShapeIDMap) {
1865 int v1ID = theShapeIDMap.FindIndex( TopExp::FirstVertex( theEdge ).Oriented( TopAbs_FORWARD ));
1866 int v2ID = theShapeIDMap.FindIndex( TopExp::LastVertex( theEdge ).Oriented( TopAbs_FORWARD ));
1867 return ( v1ID < v2ID );
1869 // Return true if an in-block parameter increases along theEdge curve
1871 static void Swap(double& a, double& b) { double tmp = a; a = b; b = tmp; }
1873 // methods of math_FunctionSetWithDerivatives
1874 Standard_Integer NbVariables() const;
1875 Standard_Integer NbEquations() const;
1876 Standard_Boolean Value(const math_Vector& X,math_Vector& F) ;
1877 Standard_Boolean Derivatives(const math_Vector& X,math_Matrix& D) ;
1878 Standard_Boolean Values(const math_Vector& X,math_Vector& F,math_Matrix& D) ;
1879 Standard_Integer GetStateNumber ();
1881 static ostream& DumpShapeID (const int theBlockShapeID, ostream& stream);
1882 // DEBUG: dump an id of a block sub-shape
1890 Handle(Geom_Curve) myC3d;
1892 double GetU( const gp_XYZ& theParams ) const;
1893 gp_XYZ Point( const gp_XYZ& theParams ) const;
1897 // 4 edges in the order u0, u1, 0v, 1v
1898 int myCoordInd[ 4 ];
1899 double myFirst [ 4 ];
1900 double myLast [ 4 ];
1901 Handle(Geom2d_Curve) myC2d [ 4 ];
1902 // 4 corner points in the order 00, 10, 11, 01
1903 gp_XY myCorner [ 4 ];
1905 Handle(Geom_Surface) myS;
1907 gp_XY GetUV( const gp_XYZ& theParams ) const;
1908 gp_XYZ Point( const gp_XYZ& theParams ) const;
1909 int GetUInd() const { return myCoordInd[ 0 ]; }
1910 int GetVInd() const { return myCoordInd[ 2 ]; }
1913 TopoDS_Shell myShell;
1922 // for param computation
1929 gp_XYZ myPoint; // the given point
1930 gp_XYZ myParam; // the best parameters guess
1931 double myValues[ 4 ]; // values computed at myParam
1933 typedef pair<gp_XYZ,gp_XYZ> TxyzPair;
1934 TxyzPair my3x3x3GridNodes[ 27 ];
1935 bool myGridComputed;
1938 //=======================================================================
1940 //purpose : Create a pattern from the mesh built on <theBlock>
1941 //=======================================================================
1943 bool SMESH_Pattern::Load (SMESH_Mesh* theMesh,
1944 const TopoDS_Shell& theBlock)
1946 MESSAGE(" ::Load(volume) " );
1949 SMESHDS_Mesh * aMeshDS = theMesh->GetMeshDS();
1951 // load shapes in myShapeIDMap
1952 TBlock block( theBlock );
1953 TopoDS_Vertex v1, v2;
1954 if ( !block.LoadBlockShapes( v1, v2, myShapeIDMap ))
1955 return setErrorCode( ERR_LOADV_BAD_SHAPE );
1958 int nbNodes = 0, shapeID;
1959 for ( shapeID = 1; shapeID <= myShapeIDMap.Extent(); shapeID++ )
1961 const TopoDS_Shape& S = myShapeIDMap( shapeID );
1962 SMESHDS_SubMesh * aSubMesh = aMeshDS->MeshElements( S );
1964 nbNodes += aSubMesh->NbNodes();
1966 myPoints.resize( nbNodes );
1968 // load U of points on edges
1969 TNodePointIDMap nodePointIDMap;
1971 for ( shapeID = 1; shapeID <= myShapeIDMap.Extent(); shapeID++ )
1973 const TopoDS_Shape& S = myShapeIDMap( shapeID );
1974 list< TPoint* > & shapePoints = getShapePoints( shapeID );
1975 SMESHDS_SubMesh * aSubMesh = aMeshDS->MeshElements( S );
1976 if ( ! aSubMesh ) continue;
1977 SMDS_NodeIteratorPtr nIt = aSubMesh->GetNodes();
1978 if ( !nIt->more() ) continue;
1980 // store a node and a point
1981 while ( nIt->more() ) {
1982 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nIt->next() );
1983 nodePointIDMap.insert( TNodePointIDMap::value_type( node, iPoint ));
1984 if ( block.IsVertexID( shapeID ))
1985 myKeyPointIDs.push_back( iPoint );
1986 TPoint* p = & myPoints[ iPoint++ ];
1987 shapePoints.push_back( p );
1988 p->myXYZ.SetCoord( node->X(), node->Y(), node->Z() );
1989 p->myInitXYZ.SetCoord( 0,0,0 );
1991 list< TPoint* >::iterator pIt = shapePoints.begin();
1994 switch ( S.ShapeType() )
1999 for ( ; pIt != shapePoints.end(); pIt++ ) {
2000 double * coef = block.GetShapeCoef( shapeID );
2001 for ( int iCoord = 1; iCoord <= 3; iCoord++ )
2002 if ( coef[ iCoord - 1] > 0 )
2003 (*pIt)->myInitXYZ.SetCoord( iCoord, 1. );
2005 if ( S.ShapeType() == TopAbs_VERTEX )
2008 const TopoDS_Edge& edge = TopoDS::Edge( S );
2010 BRep_Tool::Range( edge, f, l );
2011 int iCoord = TBlock::GetCoordIndOnEdge( shapeID );
2012 bool isForward = TBlock::IsForwardEdge( edge, myShapeIDMap );
2013 pIt = shapePoints.begin();
2014 nIt = aSubMesh->GetNodes();
2015 for ( ; nIt->more(); pIt++ )
2017 const SMDS_MeshNode* node =
2018 static_cast<const SMDS_MeshNode*>( nIt->next() );
2019 const SMDS_EdgePosition* epos =
2020 static_cast<const SMDS_EdgePosition*>(node->GetPosition().get());
2021 double u = ( epos->GetUParameter() - f ) / ( l - f );
2022 (*pIt)->myInitXYZ.SetCoord( iCoord, isForward ? u : 1 - u );
2027 for ( ; pIt != shapePoints.end(); pIt++ )
2029 if ( !block.ComputeParameters( (*pIt)->myXYZ, (*pIt)->myInitXYZ, shapeID )) {
2030 MESSAGE( "!block.ComputeParameters()" );
2031 return setErrorCode( ERR_LOADV_COMPUTE_PARAMS );
2035 } // loop on block sub-shapes
2039 SMESHDS_SubMesh * aSubMesh = aMeshDS->MeshElements( theBlock );
2042 SMDS_ElemIteratorPtr elemIt = aSubMesh->GetElements();
2043 while ( elemIt->more() ) {
2044 SMDS_ElemIteratorPtr nIt = elemIt->next()->nodesIterator();
2045 myElemPointIDs.push_back( list< int >() );
2046 list< int >& elemPoints = myElemPointIDs.back();
2047 while ( nIt->more() )
2048 elemPoints.push_back( nodePointIDMap[ nIt->next() ]);
2052 myIsBoundaryPointsFound = true;
2054 return setErrorCode( ERR_OK );
2057 //=======================================================================
2059 //purpose : Compute nodes coordinates applying
2060 // the loaded pattern to <theBlock>. The (0,0,0) key-point
2061 // will be mapped into <theVertex000>. The (0,0,1)
2062 // fifth key-point will be mapped into <theVertex001>.
2063 //=======================================================================
2065 bool SMESH_Pattern::Apply (const TopoDS_Shell& theBlock,
2066 const TopoDS_Vertex& theVertex000,
2067 const TopoDS_Vertex& theVertex001)
2069 MESSAGE(" ::Apply(volume) " );
2071 TBlock block( theBlock );
2073 if (!findBoundaryPoints() || // bind ID to points
2074 !setShapeToMesh( theBlock )) // check theBlock is a suitable shape
2077 if (!block.LoadBlockShapes( theVertex000, theVertex001, myShapeIDMap )) // bind ID to shape
2078 return setErrorCode( ERR_APPLV_BAD_SHAPE );
2080 // compute XYZ of points on shapes
2082 for ( int shapeID = 1; shapeID <= myShapeIDMap.Extent(); shapeID++ )
2084 list< TPoint* > & shapePoints = getShapePoints( shapeID );
2085 list< TPoint* >::iterator pIt = shapePoints.begin();
2086 const TopoDS_Shape& S = myShapeIDMap( shapeID );
2087 switch ( S.ShapeType() )
2089 case TopAbs_VERTEX: {
2091 for ( ; pIt != shapePoints.end(); pIt++ )
2092 block.VertexPoint( shapeID, (*pIt)->myXYZ.ChangeCoord() );
2097 for ( ; pIt != shapePoints.end(); pIt++ )
2098 block.EdgePoint( shapeID, (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
2103 for ( ; pIt != shapePoints.end(); pIt++ )
2104 block.FacePoint( shapeID, (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
2108 for ( ; pIt != shapePoints.end(); pIt++ )
2109 block.ShellPoint( (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
2111 } // loop on block sub-shapes
2113 myIsComputed = true;
2115 return setErrorCode( ERR_OK );
2118 //=======================================================================
2119 //function : MakeMesh
2120 //purpose : Create nodes and elements in <theMesh> using nodes
2121 // coordinates computed by either of Apply...() methods
2122 //=======================================================================
2124 bool SMESH_Pattern::MakeMesh(SMESH_Mesh* theMesh)
2126 MESSAGE(" ::MakeMesh() " );
2127 if ( !myIsComputed )
2128 return setErrorCode( ERR_MAKEM_NOT_COMPUTED );
2130 SMESHDS_Mesh* aMeshDS = theMesh->GetMeshDS();
2132 // clear elements and nodes existing on myShape
2133 SMESH_subMesh * aSubMesh = theMesh->GetSubMeshContaining( myShape );
2134 SMESHDS_SubMesh * aSubMeshDS = aMeshDS->MeshElements( myShape );
2136 aSubMesh->ComputeStateEngine( SMESH_subMesh::CLEAN );
2137 else if ( aSubMeshDS )
2139 SMDS_ElemIteratorPtr eIt = aSubMeshDS->GetElements();
2140 while ( eIt->more() )
2141 aMeshDS->RemoveElement( eIt->next() );
2142 SMDS_NodeIteratorPtr nIt = aSubMeshDS->GetNodes();
2143 while ( nIt->more() )
2144 aMeshDS->RemoveNode( static_cast<const SMDS_MeshNode*>( nIt->next() ));
2147 // loop on sub-shapes of myShape: create nodes and build point-node map
2148 typedef map< TPoint*, const SMDS_MeshNode* > TPointNodeMap;
2149 TPointNodeMap pointNodeMap;
2150 map< int, list< TPoint* > >::iterator idPointIt = myShapeIDToPointsMap.begin();
2151 for ( ; idPointIt != myShapeIDToPointsMap.end(); idPointIt++ )
2153 const TopoDS_Shape & S = myShapeIDMap( (*idPointIt).first );
2154 list< TPoint* > & points = (*idPointIt).second;
2155 SMESHDS_SubMesh * subMeshDS = aMeshDS->MeshElements( S );
2156 SMESH_subMesh * subMesh = theMesh->GetSubMeshContaining( myShape );
2157 list< TPoint* >::iterator pIt = points.begin();
2158 for ( ; pIt != points.end(); pIt++ )
2160 TPoint* point = *pIt;
2161 if ( pointNodeMap.find( point ) != pointNodeMap.end() )
2163 SMDS_MeshNode* node = aMeshDS->AddNode (point->myXYZ.X(),
2166 pointNodeMap.insert( TPointNodeMap::value_type( point, node ));
2168 switch ( S.ShapeType() ) {
2169 case TopAbs_VERTEX: {
2170 aMeshDS->SetNodeOnVertex( node, TopoDS::Vertex( S ));
2174 aMeshDS->SetNodeOnEdge( node, TopoDS::Edge( S ));
2175 SMDS_EdgePosition* epos =
2176 dynamic_cast<SMDS_EdgePosition *>(node->GetPosition().get());
2177 epos->SetUParameter( point->myU );
2181 aMeshDS->SetNodeOnFace( node, TopoDS::Face( S ));
2182 SMDS_FacePosition* pos =
2183 dynamic_cast<SMDS_FacePosition *>(node->GetPosition().get());
2184 pos->SetUParameter( point->myUV.X() );
2185 pos->SetVParameter( point->myUV.Y() );
2189 aMeshDS->SetNodeInVolume( node, TopoDS::Shell( S ));
2193 // make that SMESH_subMesh::_computeState = COMPUTE_OK
2194 // so that operations with hypotheses will erase the mesh
2197 subMesh->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
2201 list<list< int > >::iterator epIt = myElemPointIDs.begin();
2202 for ( ; epIt != myElemPointIDs.end(); epIt++ )
2204 list< int > & elemPoints = *epIt;
2206 const SMDS_MeshNode* nodes[ 8 ];
2207 list< int >::iterator iIt = elemPoints.begin();
2209 for ( nbNodes = 0; iIt != elemPoints.end(); iIt++ ) {
2210 nodes[ nbNodes++ ] = pointNodeMap[ & myPoints[ *iIt ]];
2213 const SMDS_MeshElement* elem = 0;
2215 switch ( nbNodes ) {
2217 elem = aMeshDS->AddFace( nodes[0], nodes[1], nodes[2] ); break;
2219 elem = aMeshDS->AddFace( nodes[0], nodes[1], nodes[2], nodes[3] ); break;
2224 switch ( nbNodes ) {
2226 elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3] ); break;
2228 elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3],
2231 elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3],
2232 nodes[4], nodes[5] ); break;
2234 elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3],
2235 nodes[4], nodes[5], nodes[6], nodes[7] ); break;
2240 aMeshDS->SetMeshElementOnShape( elem, myShape );
2243 return setErrorCode( ERR_OK );
2247 //=======================================================================
2248 //function : arrangeBoundaries
2249 //purpose : if there are several wires, arrange boundaryPoints so that
2250 // the outer wire goes first and fix inner wires orientation
2251 // update myKeyPointIDs to correspond to the order of key-points
2252 // in boundaries; sort internal boundaries by the nb of key-points
2253 //=======================================================================
2255 void SMESH_Pattern::arrangeBoundaries (list< list< TPoint* > >& boundaryList)
2257 int nbBoundaries = boundaryList.size();
2258 if ( nbBoundaries < 2 ) return;
2260 typedef list< list< TPoint* > >::iterator TListOfListIt;
2261 TListOfListIt bndIt;
2263 // sort boundaries by nb of key-points
2264 if ( nbBoundaries > 2 )
2266 // move boundaries in tmp list
2267 list< list< TPoint* > > tmpList;
2268 tmpList.splice( tmpList.begin(), boundaryList, boundaryList.begin(), boundaryList.end());
2269 // make a map nb-key-points to boundary-position-in-tmpList,
2270 // boundary-positions get ordered in it
2271 typedef map< int, TListOfListIt > TNbKpBndPosMap;
2272 TNbKpBndPosMap nbKpBndPosMap;
2273 bndIt = tmpList.begin();
2274 list< int >::iterator nbKpIt = myNbKeyPntInBoundary.begin();
2275 for ( ; nbKpIt != myNbKeyPntInBoundary.end(); nbKpIt++, bndIt++ ) {
2276 int nb = *nbKpIt * nbBoundaries;
2277 while ( nbKpBndPosMap.find ( nb ) != nbKpBndPosMap.end() )
2279 nbKpBndPosMap.insert( TNbKpBndPosMap::value_type( nb, bndIt ));
2281 // move boundaries back to boundaryList
2282 TNbKpBndPosMap::iterator nbKpBndPosIt = nbKpBndPosMap.begin();
2283 for ( ; nbKpBndPosIt != nbKpBndPosMap.end(); nbKpBndPosIt++ ) {
2284 TListOfListIt & bndPos2 = (*nbKpBndPosIt).second;
2285 TListOfListIt bndPos1 = bndPos2++;
2286 boundaryList.splice( boundaryList.end(), tmpList, bndPos1, bndPos2 );
2290 // Look for the outer boundary: the one with the point with the least X
2291 double leastX = DBL_MAX;
2292 list< TPoint* >::iterator pIt;
2293 TListOfListIt outerBndPos;
2294 for ( bndIt = boundaryList.begin(); bndIt != boundaryList.end(); bndIt++ )
2296 list< TPoint* >& boundary = (*bndIt);
2297 for ( pIt = boundary.begin(); pIt != boundary.end(); pIt++)
2299 TPoint* point = *pIt;
2300 if ( point->myInitXYZ.X() < leastX ) {
2301 leastX = point->myInitXYZ.X();
2302 outerBndPos = bndIt;
2307 if ( outerBndPos != boundaryList.begin() )
2308 boundaryList.splice( boundaryList.begin(), boundaryList, outerBndPos, ++outerBndPos );
2311 // Check boundaries orientation and re-fill myKeyPointIDs
2313 set< TPoint* > keyPointSet;
2314 list< int >::iterator kpIt = myKeyPointIDs.begin();
2315 for ( ; kpIt != myKeyPointIDs.end(); kpIt++ )
2316 keyPointSet.insert( & myPoints[ *kpIt ]);
2317 myKeyPointIDs.clear();
2319 // update myNbKeyPntInBoundary also
2320 list< int >::iterator nbKpIt = myNbKeyPntInBoundary.begin();
2322 for ( bndIt = boundaryList.begin(); bndIt != boundaryList.end(); bndIt++, nbKpIt++ )
2324 // find the point with the least X
2325 double leastX = DBL_MAX;
2326 list< TPoint* >::iterator xpIt;
2327 list< TPoint* >& boundary = (*bndIt);
2328 for ( pIt = boundary.begin(); pIt != boundary.end(); pIt++)
2330 TPoint* point = *pIt;
2331 if ( point->myInitXYZ.X() < leastX ) {
2332 leastX = point->myInitXYZ.X();
2336 // find points next to the point with the least X
2337 TPoint* p = *xpIt, *pPrev, *pNext;
2338 if ( p == boundary.front() )
2339 pPrev = boundary.back();
2345 if ( p == boundary.back() )
2346 pNext = boundary.front();
2351 // vectors of boundary direction near <p>
2352 gp_Vec2d v1( pPrev->myInitUV, p->myInitUV ), v2( p->myInitUV, pNext->myInitUV );
2353 // rotate vectors counterclockwise
2354 v1.SetCoord( -v1.Y(), v1.X() );
2355 v2.SetCoord( -v2.Y(), v2.X() );
2356 // in-face direction
2357 gp_Vec2d dirInFace = v1 + v2;
2358 // for the outer boundary dirInFace should go to the right
2360 if ( bndIt == boundaryList.begin() ) // outer boundary
2361 reverse = dirInFace.X() < 0;
2363 reverse = dirInFace.X() > 0;
2367 // Put key-point IDs of a well-oriented boundary in myKeyPointIDs
2368 (*nbKpIt) = 0; // count nb of key-points again
2369 pIt = boundary.begin();
2370 for ( ; pIt != boundary.end(); pIt++)
2372 TPoint* point = *pIt;
2373 if ( keyPointSet.find( point ) == keyPointSet.end() )
2375 // find an index of a keypoint
2377 vector< TPoint >::const_iterator pVecIt = myPoints.begin();
2378 for ( ; pVecIt != myPoints.end(); pVecIt++, index++ )
2379 if ( &(*pVecIt) == point )
2381 myKeyPointIDs.push_back( index );
2384 myKeyPointIDs.pop_back(); // remove the first key-point from the back
2387 } // loop on a list of boundaries
2389 ASSERT( myKeyPointIDs.size() == keyPointSet.size() );
2392 //=======================================================================
2393 //function : findBoundaryPoints
2394 //purpose : if loaded from file, find points to map on edges and faces and
2395 // compute their parameters
2396 //=======================================================================
2398 bool SMESH_Pattern::findBoundaryPoints()
2400 if ( myIsBoundaryPointsFound ) return true;
2402 MESSAGE(" findBoundaryPoints() ");
2406 set< TPoint* > pointsInElems;
2408 // Find free links of elements:
2409 // put links of all elements in a set and remove links encountered twice
2411 typedef pair< TPoint*, TPoint*> TLink;
2412 set< TLink > linkSet;
2413 list<list< int > >::iterator epIt = myElemPointIDs.begin();
2414 for ( ; epIt != myElemPointIDs.end(); epIt++ )
2416 list< int > & elemPoints = *epIt;
2417 list< int >::iterator pIt = elemPoints.begin();
2418 int prevP = elemPoints.back();
2419 for ( ; pIt != elemPoints.end(); pIt++ ) {
2420 TPoint* p1 = & myPoints[ prevP ];
2421 TPoint* p2 = & myPoints[ *pIt ];
2422 TLink link(( p1 < p2 ? p1 : p2 ), ( p1 < p2 ? p2 : p1 ));
2423 ASSERT( link.first != link.second );
2424 pair<set< TLink >::iterator,bool> itUniq = linkSet.insert( link );
2425 if ( !itUniq.second )
2426 linkSet.erase( itUniq.first );
2429 pointsInElems.insert( p1 );
2432 // Now linkSet contains only free links,
2433 // find the points order that they have in boundaries
2435 // 1. make a map of key-points
2436 set< TPoint* > keyPointSet;
2437 list< int >::iterator kpIt = myKeyPointIDs.begin();
2438 for ( ; kpIt != myKeyPointIDs.end(); kpIt++ )
2439 keyPointSet.insert( & myPoints[ *kpIt ]);
2441 // 2. chain up boundary points
2442 list< list< TPoint* > > boundaryList;
2443 boundaryList.push_back( list< TPoint* >() );
2444 list< TPoint* > * boundary = & boundaryList.back();
2446 TPoint *point1, *point2, *keypoint1;
2447 kpIt = myKeyPointIDs.begin();
2448 point1 = keypoint1 = & myPoints[ *kpIt++ ];
2449 // loop on free links: look for the next point
2451 set< TLink >::iterator lIt = linkSet.begin();
2452 while ( lIt != linkSet.end() )
2454 if ( (*lIt).first == point1 )
2455 point2 = (*lIt).second;
2456 else if ( (*lIt).second == point1 )
2457 point2 = (*lIt).first;
2462 linkSet.erase( lIt );
2463 lIt = linkSet.begin();
2465 if ( keyPointSet.find( point2 ) == keyPointSet.end() ) // not a key-point
2467 boundary->push_back( point2 );
2469 else // a key-point found
2471 keyPointSet.erase( point2 ); // keyPointSet contains not found key-points only
2473 if ( point2 != keypoint1 ) // its not the boundary end
2475 boundary->push_back( point2 );
2477 else // the boundary end reached
2479 boundary->push_front( keypoint1 );
2480 boundary->push_back( keypoint1 );
2481 myNbKeyPntInBoundary.push_back( iKeyPoint );
2482 if ( keyPointSet.empty() )
2483 break; // all boundaries containing key-points are found
2485 // prepare to search for the next boundary
2486 boundaryList.push_back( list< TPoint* >() );
2487 boundary = & boundaryList.back();
2488 point2 = keypoint1 = (*keyPointSet.begin());
2492 } // loop on the free links set
2494 if ( boundary->empty() ) {
2495 MESSAGE(" a separate key-point");
2496 return setErrorCode( ERR_READ_BAD_KEY_POINT );
2499 // if there are several wires, arrange boundaryPoints so that
2500 // the outer wire goes first and fix inner wires orientation;
2501 // sort myKeyPointIDs to correspond to the order of key-points
2503 arrangeBoundaries( boundaryList );
2505 // Find correspondence shape ID - points,
2506 // compute points parameter on edge
2508 keyPointSet.clear();
2509 for ( kpIt = myKeyPointIDs.begin(); kpIt != myKeyPointIDs.end(); kpIt++ )
2510 keyPointSet.insert( & myPoints[ *kpIt ]);
2512 set< TPoint* > edgePointSet; // to find in-face points
2513 int vertexID = 1; // the first index in TopTools_IndexedMapOfShape
2514 int edgeID = myKeyPointIDs.size() + 1;
2516 list< list< TPoint* > >::iterator bndIt = boundaryList.begin();
2517 for ( ; bndIt != boundaryList.end(); bndIt++ )
2519 boundary = & (*bndIt);
2520 double edgeLength = 0;
2521 list< TPoint* >::iterator pIt = boundary->begin();
2522 getShapePoints( edgeID ).push_back( *pIt );
2523 for ( pIt++; pIt != boundary->end(); pIt++)
2525 list< TPoint* > & edgePoints = getShapePoints( edgeID );
2526 TPoint* prevP = edgePoints.empty() ? 0 : edgePoints.back();
2527 TPoint* point = *pIt;
2528 edgePointSet.insert( point );
2529 if ( keyPointSet.find( point ) == keyPointSet.end() ) // inside-edge point
2531 edgePoints.push_back( point );
2532 edgeLength += ( point->myInitUV - prevP->myInitUV ).SquareModulus();
2533 point->myInitU = edgeLength;
2537 // treat points on the edge which ends up: compute U [0,1]
2538 edgePoints.push_back( point );
2539 if ( edgePoints.size() > 2 ) {
2540 edgeLength += ( point->myInitUV - prevP->myInitUV ).SquareModulus();
2541 list< TPoint* >::iterator epIt = edgePoints.begin();
2542 for ( ; epIt != edgePoints.end(); epIt++ )
2543 (*epIt)->myInitU /= edgeLength;
2545 // begin the next edge treatment
2547 getShapePoints( vertexID++ ).push_back( point );
2549 if ( point != boundary->front() )
2550 getShapePoints( edgeID ).push_back( point );
2555 // find in-face points
2556 list< TPoint* > & facePoints = getShapePoints( edgeID );
2557 vector< TPoint >::iterator pVecIt = myPoints.begin();
2558 for ( ; pVecIt != myPoints.end(); pVecIt++ ) {
2559 TPoint* point = &(*pVecIt);
2560 if ( edgePointSet.find( point ) == edgePointSet.end() &&
2561 pointsInElems.find( point ) != pointsInElems.end())
2562 facePoints.push_back( point );
2569 // bind points to shapes according to point parameters
2570 vector< TPoint >::iterator pVecIt = myPoints.begin();
2571 for ( int i = 0; pVecIt != myPoints.end(); pVecIt++, i++ ) {
2572 TPoint* point = &(*pVecIt);
2573 int shapeID = TBlock::GetShapeIDByParams( point->myInitXYZ );
2574 getShapePoints( shapeID ).push_back( point );
2575 // detect key-points
2576 if ( TBlock::IsVertexID( shapeID ))
2577 myKeyPointIDs.push_back( i );
2581 myIsBoundaryPointsFound = true;
2582 return myIsBoundaryPointsFound;
2585 //=======================================================================
2587 //purpose : clear fields
2588 //=======================================================================
2590 void SMESH_Pattern::Clear()
2592 myIsComputed = myIsBoundaryPointsFound = false;
2595 myKeyPointIDs.clear();
2596 myElemPointIDs.clear();
2597 myShapeIDToPointsMap.clear();
2598 myShapeIDMap.Clear();
2600 myNbKeyPntInBoundary.clear();
2603 //=======================================================================
2604 //function : setShapeToMesh
2605 //purpose : set a shape to be meshed. Return True if meshing is possible
2606 //=======================================================================
2608 bool SMESH_Pattern::setShapeToMesh(const TopoDS_Shape& theShape)
2610 if ( !IsLoaded() ) {
2611 MESSAGE( "Pattern not loaded" );
2612 return setErrorCode( ERR_APPL_NOT_LOADED );
2615 TopAbs_ShapeEnum aType = theShape.ShapeType();
2616 bool dimOk = ( myIs2D ? aType == TopAbs_FACE : aType == TopAbs_SHELL );
2618 MESSAGE( "Pattern dimention mismatch" );
2619 return setErrorCode( ERR_APPL_BAD_DIMENTION );
2622 // check if a face is closed
2623 int nbNodeOnSeamEdge = 0;
2625 TopoDS_Face face = TopoDS::Face( theShape );
2626 TopExp_Explorer eExp( theShape, TopAbs_EDGE );
2627 for ( ; eExp.More() && nbNodeOnSeamEdge == 0; eExp.Next() )
2628 if ( BRep_Tool::IsClosed( TopoDS::Edge( eExp.Current() ), face ))
2629 nbNodeOnSeamEdge = 2;
2632 // check nb of vertices
2633 TopTools_IndexedMapOfShape vMap;
2634 TopExp::MapShapes( theShape, TopAbs_VERTEX, vMap );
2635 if ( vMap.Extent() + nbNodeOnSeamEdge != myKeyPointIDs.size() ) {
2636 MESSAGE( myKeyPointIDs.size() << " != " << vMap.Extent() );
2637 return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
2640 myShapeIDMap.Clear();
2645 //=======================================================================
2646 //function : GetMappedPoints
2647 //purpose : Return nodes coordinates computed by Apply() method
2648 //=======================================================================
2650 bool SMESH_Pattern::GetMappedPoints ( list< const gp_XYZ * > & thePoints )
2653 if ( !myIsComputed )
2656 vector< TPoint >::iterator pVecIt = myPoints.begin();
2657 for ( ; pVecIt != myPoints.end(); pVecIt++ )
2658 thePoints.push_back( & (*pVecIt).myXYZ.XYZ() );
2660 return ( thePoints.size() > 0 );
2664 //=======================================================================
2665 //function : GetPoints
2666 //purpose : Return nodes coordinates of the pattern
2667 //=======================================================================
2669 bool SMESH_Pattern::GetPoints ( list< const gp_XYZ * > & thePoints ) const
2676 vector< TPoint >::const_iterator pVecIt = myPoints.begin();
2677 for ( ; pVecIt != myPoints.end(); pVecIt++ )
2678 thePoints.push_back( & (*pVecIt).myInitXYZ );
2680 return ( thePoints.size() > 0 );
2683 //=======================================================================
2684 //function : getShapePoints
2685 //purpose : return list of points located on theShape
2686 //=======================================================================
2688 list< SMESH_Pattern::TPoint* > &
2689 SMESH_Pattern::getShapePoints(const TopoDS_Shape& theShape)
2692 if ( !myShapeIDMap.Contains( theShape ))
2693 aShapeID = myShapeIDMap.Add( theShape );
2695 aShapeID = myShapeIDMap.FindIndex( theShape );
2697 return myShapeIDToPointsMap[ aShapeID ];
2700 //=======================================================================
2701 //function : getShapePoints
2702 //purpose : return list of points located on the shape
2703 //=======================================================================
2705 list< SMESH_Pattern::TPoint* > & SMESH_Pattern::getShapePoints(const int theShapeID)
2707 return myShapeIDToPointsMap[ theShapeID ];
2710 //=======================================================================
2711 //function : DumpPoints
2713 //=======================================================================
2715 void SMESH_Pattern::DumpPoints() const
2718 vector< TPoint >::const_iterator pVecIt = myPoints.begin();
2719 for ( int i = 0; pVecIt != myPoints.end(); pVecIt++, i++ )
2720 cout << i << ": " << *pVecIt;
2724 //=======================================================================
2725 //function : TPoint()
2727 //=======================================================================
2729 SMESH_Pattern::TPoint::TPoint()
2732 myInitXYZ.SetCoord(0,0,0);
2733 myInitUV.SetCoord(0.,0.);
2735 myXYZ.SetCoord(0,0,0);
2736 myUV.SetCoord(0.,0.);
2741 //=======================================================================
2742 //function : operator <<
2744 //=======================================================================
2746 ostream & operator <<(ostream & OS, const SMESH_Pattern::TPoint& p)
2748 gp_XYZ xyz = p.myInitXYZ;
2749 OS << "\tinit( xyz( " << xyz.X() << " " << xyz.Y() << " " << xyz.Z() << " )";
2750 gp_XY xy = p.myInitUV;
2751 OS << " uv( " << xy.X() << " " << xy.Y() << " )";
2752 double u = p.myInitU;
2753 OS << " u( " << u << " )) " << &p << endl;
2754 xyz = p.myXYZ.XYZ();
2755 OS << "\t ( xyz( " << xyz.X() << " " << xyz.Y() << " " << xyz.Z() << " )";
2757 OS << " uv( " << xy.X() << " " << xy.Y() << " )";
2759 OS << " u( " << u << " ))" << endl;
2764 //=======================================================================
2765 //function : TBlock::TEdge::GetU
2767 //=======================================================================
2769 double TBlock::TEdge::GetU( const gp_XYZ& theParams ) const
2771 double u = theParams.Coord( myCoordInd );
2772 return ( 1 - u ) * myFirst + u * myLast;
2775 //=======================================================================
2776 //function : TBlock::TEdge::Point
2778 //=======================================================================
2780 gp_XYZ TBlock::TEdge::Point( const gp_XYZ& theParams ) const
2782 gp_XYZ p = myC3d->Value( GetU( theParams )).XYZ();
2783 if ( myTrsf.Form() != gp_Identity )
2784 myTrsf.Transforms( p );
2788 //=======================================================================
2789 //function : TBlock::TFace::GetUV
2791 //=======================================================================
2793 gp_XY TBlock::TFace::GetUV( const gp_XYZ& theParams ) const
2796 double dU = theParams.Coord( GetUInd() );
2797 double dV = theParams.Coord( GetVInd() );
2798 for ( int iE = 0; iE < 4; iE++ ) // loop on 4 edges
2800 double Ecoef = 0, Vcoef = 0;
2803 Ecoef = ( 1 - dV ); // u0
2804 Vcoef = ( 1 - dU ) * ( 1 - dV ); break; // 00
2807 Vcoef = dU * ( 1 - dV ); break; // 10
2809 Ecoef = ( 1 - dU ); // 0v
2810 Vcoef = dU * dV ; break; // 11
2813 Vcoef = ( 1 - dU ) * dV ; break; // 01
2817 double u = theParams.Coord( myCoordInd[ iE ] );
2818 u = ( 1 - u ) * myFirst[ iE ] + u * myLast[ iE ];
2819 uv += Ecoef * myC2d[ iE ]->Value( u ).XY();
2821 uv -= Vcoef * myCorner[ iE ];
2826 //=======================================================================
2827 //function : TBlock::TFace::Point
2829 //=======================================================================
2831 gp_XYZ TBlock::TFace::Point( const gp_XYZ& theParams ) const
2833 gp_XY uv = GetUV( theParams );
2834 gp_XYZ p = myS->Value( uv.X(), uv.Y() ).XYZ();
2835 if ( myTrsf.Form() != gp_Identity )
2836 myTrsf.Transforms( p );
2840 //=======================================================================
2841 //function : GetShapeCoef
2843 //=======================================================================
2845 double* TBlock::GetShapeCoef (const int theShapeID)
2847 static double shapeCoef[][3] = {
2848 // V000, V100, V010, V110
2849 { -1,-1,-1 }, { 1,-1,-1 }, { -1, 1,-1 }, { 1, 1,-1 },
2850 // V001, V101, V011, V111,
2851 { -1,-1, 1 }, { 1,-1, 1 }, { -1, 1, 1 }, { 1, 1, 1 },
2852 // Ex00, Ex10, Ex01, Ex11,
2853 { 0,-1,-1 }, { 0, 1,-1 }, { 0,-1, 1 }, { 0, 1, 1 },
2854 // E0y0, E1y0, E0y1, E1y1,
2855 { -1, 0,-1 }, { 1, 0,-1 }, { -1, 0, 1 }, { 1, 0, 1 },
2856 // E00z, E10z, E01z, E11z,
2857 { -1,-1, 0 }, { 1,-1, 0 }, { -1, 1, 0 }, { 1, 1, 0 },
2858 // Fxy0, Fxy1, Fx0z, Fx1z, F0yz, F1yz,
2859 { 0, 0,-1 }, { 0, 0, 1 }, { 0,-1, 0 }, { 0, 1, 0 }, { -1, 0, 0 }, { 1, 0, 0 },
2863 if ( theShapeID < ID_V000 || theShapeID > ID_F1yz )
2864 return shapeCoef[ ID_Shell - 1 ];
2866 return shapeCoef[ theShapeID - 1 ];
2869 //=======================================================================
2870 //function : ShellPoint
2871 //purpose : return coordinates of a point in shell
2872 //=======================================================================
2874 bool TBlock::ShellPoint( const gp_XYZ& theParams, gp_XYZ& thePoint ) const
2876 thePoint.SetCoord( 0., 0., 0. );
2877 for ( int shapeID = ID_V000; shapeID < ID_Shell; shapeID++ )
2880 double* coefs = GetShapeCoef( shapeID );
2882 for ( int iCoef = 0; iCoef < 3; iCoef++ ) {
2883 if ( coefs[ iCoef ] != 0 ) {
2884 if ( coefs[ iCoef ] < 0 )
2885 k *= ( 1. - theParams.Coord( iCoef + 1 ));
2887 k *= theParams.Coord( iCoef + 1 );
2892 if ( shapeID < ID_Ex00 ) // vertex
2893 VertexPoint( shapeID, Ps );
2894 else if ( shapeID < ID_Fxy0 ) { // edge
2895 EdgePoint( shapeID, theParams, Ps );
2898 FacePoint( shapeID, theParams, Ps );
2905 //=======================================================================
2906 //function : NbVariables
2908 //=======================================================================
2910 Standard_Integer TBlock::NbVariables() const
2915 //=======================================================================
2916 //function : NbEquations
2918 //=======================================================================
2920 Standard_Integer TBlock::NbEquations() const
2925 //=======================================================================
2928 //=======================================================================
2930 Standard_Boolean TBlock::Value(const math_Vector& theXYZ, math_Vector& theFxyz)
2932 gp_XYZ P, params( theXYZ(1), theXYZ(2), theXYZ(3) );
2933 if ( params.IsEqual( myParam, DBL_MIN )) { // same param
2934 theFxyz( 1 ) = myValues[ 0 ];
2937 ShellPoint( params, P );
2938 gp_Vec dP( P - myPoint );
2939 theFxyz(1) = SQRT_FUNC ? dP.SquareMagnitude() : dP.Magnitude();
2944 //=======================================================================
2945 //function : Derivatives
2947 //=======================================================================
2949 Standard_Boolean TBlock::Derivatives(const math_Vector& XYZ,math_Matrix& Df)
2951 MESSAGE( "TBlock::Derivatives()");
2953 return Values(XYZ,F,Df);
2956 //=======================================================================
2959 //=======================================================================
2961 Standard_Boolean TBlock::Values(const math_Vector& theXYZ,
2962 math_Vector& theFxyz,
2965 // MESSAGE( endl<<"TBlock::Values( "<<theXYZ(1)<<", "<<theXYZ(2)<<", "<<theXYZ(3)<<")");
2967 gp_XYZ P, params( theXYZ(1), theXYZ(2), theXYZ(3) );
2968 if ( params.IsEqual( myParam, DBL_MIN )) { // same param
2969 theFxyz( 1 ) = myValues[ 0 ];
2970 theDf( 1,1 ) = myValues[ 1 ];
2971 theDf( 1,2 ) = myValues[ 2 ];
2972 theDf( 1,3 ) = myValues[ 3 ];
2976 ShellPoint( params, P );
2977 //myNbIterations++; // how many time call ShellPoint()
2979 gp_Vec dP( P - myPoint );
2980 theFxyz(1) = SQRT_FUNC ? dP.SquareMagnitude() : dP.Magnitude();
2981 if ( theFxyz(1) < 1e-6 ) {
2990 if ( theFxyz(1) < myValues[0] )
2992 // 3 partial derivatives
2994 for ( int iP = 1; iP <= 3; iP++ ) {
2996 params.SetCoord( iP, theXYZ( iP ) + 0.001 );
2997 ShellPoint( params, Pi );
2998 params.SetCoord( iP, theXYZ( iP ) ); // restore params
2999 gp_Vec dPi ( P, Pi );
3000 double mag = dPi.Magnitude();
3001 if ( mag > DBL_MIN )
3003 drv[ iP - 1 ] = dPi;
3005 for ( int iP = 0; iP < 3; iP++ ) {
3006 if ( iP == myFaceIndex )
3007 theDf( 1, iP + 1 ) = myFaceParam;
3009 // like IntAna_IntConicQuad::Perform (const gp_Lin& L, const gp_Pln& P)
3010 // where L is (P -> myPoint), P is defined by the 2 other derivative direction
3011 int iPrev = ( iP ? iP - 1 : 2 );
3012 int iNext = ( iP == 2 ? 0 : iP + 1 );
3013 gp_Vec plnNorm = drv[ iPrev ].Crossed( drv [ iNext ] );
3014 double Direc = plnNorm * drv[ iP ];
3015 if ( Abs(Direc) <= DBL_MIN )
3016 theDf( 1, iP + 1 ) = dP * drv[ iP ];
3018 double Dis = plnNorm * P - plnNorm * myPoint;
3019 theDf( 1, iP + 1 ) = Dis/Direc;
3023 //myNbIterations +=3; // how many time call ShellPoint()
3025 // store better values
3027 myValues[0]= theFxyz(1);
3028 myValues[1]= theDf(1,1);
3029 myValues[2]= theDf(1,2);
3030 myValues[3]= theDf(1,3);
3032 // SCRUTE( theFxyz(1) );
3033 // SCRUTE( theDf( 1,1 ));
3034 // SCRUTE( theDf( 1,2 ));
3035 // SCRUTE( theDf( 1,3 ));
3041 //=======================================================================
3042 //function : ComputeParameters
3043 //purpose : compute point parameters in the block
3044 //=======================================================================
3046 bool TBlock::ComputeParameters(const gp_Pnt& thePoint,
3048 const int theShapeID)
3050 // MESSAGE( endl<<"TBlock::ComputeParameters( "
3051 // <<thePoint.X()<<", "<<thePoint.Y()<<", "<<thePoint.Z()<<")");
3053 myPoint = thePoint.XYZ();
3055 myParam.SetCoord( -1,-1,-1 );
3056 myValues[0] = 1e100;
3058 const bool isOnFace = IsFaceID( theShapeID );
3059 double * coef = GetShapeCoef( theShapeID );
3062 math_Vector start( 1, 3, 0.0 );
3063 if ( !myGridComputed )
3065 // define the first guess by thePoint projection on lines
3066 // connecting vertices
3067 bool needGrid = false;
3068 gp_XYZ par000( 0, 0, 0 ), par111( 1, 1, 1 );
3069 double zero = DBL_MIN * DBL_MIN;
3070 for ( int iEdge = 0, iParam = 1; iParam <= 3 && !needGrid; iParam++ )
3072 if ( isOnFace && coef[ iParam - 1 ] != 0 ) {
3076 for ( int iE = 0; iE < 4; iE++, iEdge++ ) { // loop on 4 parallel edges
3077 gp_Pnt p0 = myEdge[ iEdge ].Point( par000 );
3078 gp_Pnt p1 = myEdge[ iEdge ].Point( par111 );
3079 gp_Vec v01( p0, p1 ), v0P( p0, thePoint );
3080 double len2 = v01.SquareMagnitude();
3082 if ( len2 > zero ) {
3083 par = v0P.Dot( v01 ) / len2;
3084 if ( par < 0 || par > 1 ) {
3089 start( iParam ) += par;
3091 start( iParam ) /= 4.;
3094 // compute nodes of 3 x 3 x 3 grid
3096 for ( double x = 0.25; x < 0.9; x += 0.25 )
3097 for ( double y = 0.25; y < 0.9; y += 0.25 )
3098 for ( double z = 0.25; z < 0.9; z += 0.25 ) {
3099 TxyzPair & prmPtn = my3x3x3GridNodes[ iNode++ ];
3100 prmPtn.first.SetCoord( x, y, z );
3101 ShellPoint( prmPtn.first, prmPtn.second );
3103 myGridComputed = true;
3106 if ( myGridComputed ) {
3107 double minDist = DBL_MAX;
3108 gp_XYZ* bestParam = 0;
3109 for ( int iNode = 0; iNode < 27; iNode++ ) {
3110 TxyzPair & prmPtn = my3x3x3GridNodes[ iNode ];
3111 double dist = ( thePoint.XYZ() - prmPtn.second ).SquareModulus();
3112 if ( dist < minDist ) {
3114 bestParam = & prmPtn.first;
3117 start( 1 ) = bestParam->X();
3118 start( 2 ) = bestParam->Y();
3119 start( 3 ) = bestParam->Z();
3122 int myFaceIndex = -1;
3124 // put a point on the face
3125 for ( int iCoord = 0; iCoord < 3; iCoord++ )
3126 if ( coef[ iCoord ] ) {
3127 myFaceIndex = iCoord;
3128 myFaceParam = ( coef[ myFaceIndex ] < 0.5 ) ? 0.0 : 1.0;
3129 start( iCoord + 1 ) = myFaceParam;
3132 math_Vector low ( 1, 3, 0.0 );
3133 math_Vector up ( 1, 3, 1.0 );
3134 math_Vector tol ( 1, 3, 1e-4 );
3135 math_FunctionSetRoot paramSearch( *this, tol );
3138 while ( myValues[0] > 1e-1 && nbLoops++ < 10 ) {
3139 paramSearch.Perform ( *this, start, low, up );
3140 if ( !paramSearch.IsDone() ) {
3141 //MESSAGE( " !paramSearch.IsDone() " );
3144 //MESSAGE( " NB ITERATIONS: " << paramSearch.NbIterations() );
3146 start( 1 ) = myParam.X();
3147 start( 2 ) = myParam.Y();
3148 start( 3 ) = myParam.Z();
3149 //MESSAGE( "Distance: " << ( SQRT_FUNC ? sqrt(myValues[0]) : myValues[0] ));
3151 // MESSAGE( endl << myParam.X() << " " << myParam.Y() << " " << myParam.Z() << endl);
3152 // mySumDist += myValues[0];
3153 // MESSAGE( " TOTAL NB ITERATIONS: " << myNbIterations <<
3154 // " DIST: " << ( SQRT_FUNC ? sqrt(mySumDist) : mySumDist ));
3157 theParams = myParam;
3162 //=======================================================================
3163 //function : GetStateNumber
3165 //=======================================================================
3167 Standard_Integer TBlock::GetStateNumber ()
3169 // MESSAGE( endl<<"TBlock::GetStateNumber( "<<myParam.X()<<", "<<
3170 // myParam.Y()<<", "<<myParam.Z()<<") DISTANCE: " << myValues[0]);
3171 return myValues[0] < 1e-1;
3174 //=======================================================================
3175 //function : DumpShapeID
3176 //purpose : debug an id of a block sub-shape
3177 //=======================================================================
3179 #define CASEDUMP(id,strm) case id: strm << #id; break;
3181 ostream& TBlock::DumpShapeID (const int id, ostream& stream)
3184 CASEDUMP( ID_V000, stream );
3185 CASEDUMP( ID_V100, stream );
3186 CASEDUMP( ID_V010, stream );
3187 CASEDUMP( ID_V110, stream );
3188 CASEDUMP( ID_V001, stream );
3189 CASEDUMP( ID_V101, stream );
3190 CASEDUMP( ID_V011, stream );
3191 CASEDUMP( ID_V111, stream );
3192 CASEDUMP( ID_Ex00, stream );
3193 CASEDUMP( ID_Ex10, stream );
3194 CASEDUMP( ID_Ex01, stream );
3195 CASEDUMP( ID_Ex11, stream );
3196 CASEDUMP( ID_E0y0, stream );
3197 CASEDUMP( ID_E1y0, stream );
3198 CASEDUMP( ID_E0y1, stream );
3199 CASEDUMP( ID_E1y1, stream );
3200 CASEDUMP( ID_E00z, stream );
3201 CASEDUMP( ID_E10z, stream );
3202 CASEDUMP( ID_E01z, stream );
3203 CASEDUMP( ID_E11z, stream );
3204 CASEDUMP( ID_Fxy0, stream );
3205 CASEDUMP( ID_Fxy1, stream );
3206 CASEDUMP( ID_Fx0z, stream );
3207 CASEDUMP( ID_Fx1z, stream );
3208 CASEDUMP( ID_F0yz, stream );
3209 CASEDUMP( ID_F1yz, stream );
3210 CASEDUMP( ID_Shell, stream );
3211 default: stream << "ID_INVALID";
3216 //=======================================================================
3217 //function : GetShapeIDByParams
3218 //purpose : define an id of the block sub-shape by normlized point coord
3219 //=======================================================================
3221 int TBlock::GetShapeIDByParams ( const gp_XYZ& theCoord )
3223 // id ( 0 - 26 ) computation:
3225 // vertex ( 0 - 7 ) : id = 1*x + 2*y + 4*z
3227 // edge || X ( 8 - 11 ) : id = 8 + 1*y + 2*z
3228 // edge || Y ( 12 - 15 ): id = 1*x + 12 + 2*z
3229 // edge || Z ( 16 - 19 ): id = 1*x + 2*y + 16
3231 // face || XY ( 20 - 21 ): id = 8 + 12 + 1*z - 0
3232 // face || XZ ( 22 - 23 ): id = 8 + 1*y + 16 - 2
3233 // face || YZ ( 24 - 25 ): id = 1*x + 12 + 16 - 4
3235 static int iAddBnd[] = { 1, 2, 4 };
3236 static int iAddNotBnd[] = { 8, 12, 16 };
3237 static int iFaceSubst[] = { 0, 2, 4 };
3240 int iOnBoundary = 0;
3241 for ( int iCoord = 0; iCoord < 3; iCoord++ )
3243 double val = theCoord.Coord( iCoord + 1 );
3246 else if ( val == 1.0 )
3247 id += iAddBnd[ iOnBoundary++ ];
3249 id += iAddNotBnd[ iCoord ];
3251 if ( iOnBoundary == 1 ) // face
3252 id -= iFaceSubst[ (id - 20) / 4 ];
3253 else if ( iOnBoundary == 0 ) // shell
3256 if ( id > 26 || id < 0 ) {
3257 MESSAGE( "GetShapeIDByParams() = " << id
3258 <<" "<< theCoord.X() <<" "<< theCoord.Y() <<" "<< theCoord.Z() );
3261 return id + 1; // shape ids start at 1
3264 //=======================================================================
3265 //function : LoadBlockShapes
3266 //purpose : add sub-shapes of theBlock to theShapeIDMap so that they get
3267 // IDs acoording to enum TBlockShapeID
3268 //=======================================================================
3270 bool TBlock::LoadBlockShapes(const TopoDS_Vertex& theVertex000,
3271 const TopoDS_Vertex& theVertex001,
3272 // TopTools_IndexedMapOfShape& theShapeIDMap
3273 TopTools_IndexedMapOfOrientedShape& theShapeIDMap )
3275 MESSAGE(" ::LoadBlockShapes()");
3276 myGridComputed = false;
3279 TopoDS_Shape V000, V100, V010, V110, V001, V101, V011, V111;
3281 TopoDS_Shape Ex00, Ex10, Ex01, Ex11;
3282 TopoDS_Shape E0y0, E1y0, E0y1, E1y1;
3283 TopoDS_Shape E00z, E10z, E01z, E11z;
3285 TopoDS_Shape Fxy0, Fx0z, F0yz, Fxy1, Fx1z, F1yz;
3287 // nb of faces bound to a vertex in TopTools_IndexedDataMapOfShapeListOfShape
3288 // filled by TopExp::MapShapesAndAncestors()
3289 const int NB_FACES_BY_VERTEX = 6;
3291 TopTools_IndexedDataMapOfShapeListOfShape vfMap;
3292 TopExp::MapShapesAndAncestors( myShell, TopAbs_VERTEX, TopAbs_FACE, vfMap );
3293 if ( vfMap.Extent() != 8 ) {
3294 MESSAGE(" Wrong nb of vertices in the block: " << vfMap.Extent() );
3298 V000 = theVertex000;
3299 V001 = theVertex001;
3301 if ( V000.IsNull() ) {
3302 // find vertex 000 - the one with smallest coordinates
3303 double minVal = DBL_MAX, minX, val;
3304 for ( int i = 1; i <= 8; i++ ) {
3305 const TopoDS_Vertex& v = TopoDS::Vertex( vfMap.FindKey( i ));
3306 gp_Pnt P = BRep_Tool::Pnt( v );
3307 val = P.X() + P.Y() + P.Z();
3308 if ( val < minVal || ( val == minVal && P.X() < minX )) {
3314 // find vertex 001 - the one on the most vertical edge passing through V000
3315 TopTools_IndexedDataMapOfShapeListOfShape veMap;
3316 TopExp::MapShapesAndAncestors( myShell, TopAbs_VERTEX, TopAbs_EDGE, veMap );
3317 gp_Vec dir001 = gp::DZ();
3318 gp_Pnt p000 = BRep_Tool::Pnt( TopoDS::Vertex( V000 ));
3319 double maxVal = -DBL_MAX;
3320 TopTools_ListIteratorOfListOfShape eIt ( veMap.FindFromKey( V000 ));
3321 for ( ; eIt.More(); eIt.Next() ) {
3322 const TopoDS_Edge& e = TopoDS::Edge( eIt.Value() );
3323 TopoDS_Vertex v = TopExp::FirstVertex( e );
3324 if ( v.IsSame( V000 ))
3325 v = TopExp::LastVertex( e );
3326 val = dir001 * gp_Vec( p000, BRep_Tool::Pnt( v )).Normalized();
3327 if ( val > maxVal ) {
3334 // find the bottom (Fxy0), Fx0z and F0yz faces
3336 const TopTools_ListOfShape& f000List = vfMap.FindFromKey( V000 );
3337 const TopTools_ListOfShape& f001List = vfMap.FindFromKey( V001 );
3338 if (f000List.Extent() != NB_FACES_BY_VERTEX ||
3339 f001List.Extent() != NB_FACES_BY_VERTEX ) {
3340 MESSAGE(" LoadBlockShapes() " << f000List.Extent() << " " << f001List.Extent());
3343 TopTools_ListIteratorOfListOfShape f001It, f000It ( f000List );
3344 int i, j, iFound1, iFound2;
3345 for ( j = 0; f000It.More(); f000It.Next(), j++ )
3347 if ( NB_FACES_BY_VERTEX == 6 && j % 2 ) continue; // each face encounters twice
3348 const TopoDS_Shape& F = f000It.Value();
3349 for ( i = 0, f001It.Initialize( f001List ); f001It.More(); f001It.Next(), i++ ) {
3350 if ( NB_FACES_BY_VERTEX == 6 && i % 2 ) continue; // each face encounters twice
3351 if ( F.IsSame( f001It.Value() ))
3354 if ( f001It.More() ) // Fx0z or F0yz found
3355 if ( Fx0z.IsNull() ) {
3362 else // F is the bottom face
3365 if ( Fxy0.IsNull() || Fx0z.IsNull() || F0yz.IsNull() ) {
3366 MESSAGE( Fxy0.IsNull() <<" "<< Fx0z.IsNull() <<" "<< F0yz.IsNull() );
3370 // choose the top face (Fxy1)
3371 for ( i = 0, f001It.Initialize( f001List ); f001It.More(); f001It.Next(), i++ ) {
3372 if ( NB_FACES_BY_VERTEX == 6 && i % 2 ) continue; // each face encounters twice
3373 if ( i != iFound1 && i != iFound2 )
3376 Fxy1 = f001It.Value();
3377 if ( Fxy1.IsNull() ) {
3378 MESSAGE(" LoadBlockShapes() error ");
3382 // find bottom edges and veritices
3383 list< TopoDS_Edge > eList;
3384 list< int > nbVertexInWires;
3385 getOrderedEdges( TopoDS::Face( Fxy0 ), TopoDS::Vertex( V000 ), eList, nbVertexInWires );
3386 if ( nbVertexInWires.size() != 1 || nbVertexInWires.front() != 4 ) {
3387 MESSAGE(" LoadBlockShapes() error ");
3390 list< TopoDS_Edge >::iterator elIt = eList.begin();
3391 for ( i = 0; elIt != eList.end(); elIt++, i++ )
3393 case 0: E0y0 = *elIt; V010 = TopExp::LastVertex( *elIt, true ); break;
3394 case 1: Ex10 = *elIt; V110 = TopExp::LastVertex( *elIt, true ); break;
3395 case 2: E1y0 = *elIt; V100 = TopExp::LastVertex( *elIt, true ); break;
3396 case 3: Ex00 = *elIt; break;
3399 if ( i != 4 || E0y0.IsNull() || Ex10.IsNull() || E1y0.IsNull() || Ex00.IsNull() ) {
3400 MESSAGE(" LoadBlockShapes() error, eList.size()=" << eList.size());
3405 // find top edges and veritices
3407 getOrderedEdges( TopoDS::Face( Fxy1 ), TopoDS::Vertex( V001 ), eList, nbVertexInWires );
3408 if ( nbVertexInWires.size() != 1 || nbVertexInWires.front() != 4 ) {
3409 MESSAGE(" LoadBlockShapes() error ");
3412 for ( i = 0, elIt = eList.begin(); elIt != eList.end(); elIt++, i++ )
3414 case 0: Ex01 = *elIt; V101 = TopExp::LastVertex( *elIt, true ); break;
3415 case 1: E1y1 = *elIt; V111 = TopExp::LastVertex( *elIt, true ); break;
3416 case 2: Ex11 = *elIt; V011 = TopExp::LastVertex( *elIt, true ); break;
3417 case 3: E0y1 = *elIt; break;
3420 if ( i != 4 || Ex01.IsNull() || E1y1.IsNull() || Ex11.IsNull() || E0y1.IsNull() ) {
3421 MESSAGE(" LoadBlockShapes() error, eList.size()=" << eList.size());
3425 // swap Fx0z and F0yz if necessary
3426 TopExp_Explorer exp( Fx0z, TopAbs_VERTEX );
3427 for ( ; exp.More(); exp.Next() ) // Fx0z shares V101 and V100
3428 if ( V101.IsSame( exp.Current() ) || V100.IsSame( exp.Current() ))
3429 break; // V101 or V100 found
3430 if ( !exp.More() ) { // not found
3431 TopoDS_Shape f = Fx0z; Fx0z = F0yz; F0yz = f;
3434 // find Fx1z and F1yz faces
3435 const TopTools_ListOfShape& f111List = vfMap.FindFromKey( V111 );
3436 const TopTools_ListOfShape& f110List = vfMap.FindFromKey( V110 );
3437 if (f111List.Extent() != NB_FACES_BY_VERTEX ||
3438 f110List.Extent() != NB_FACES_BY_VERTEX ) {
3439 MESSAGE(" LoadBlockShapes() " << f111List.Extent() << " " << f110List.Extent());
3442 TopTools_ListIteratorOfListOfShape f111It, f110It ( f110List);
3443 for ( j = 0 ; f110It.More(); f110It.Next(), j++ ) {
3444 if ( NB_FACES_BY_VERTEX == 6 && j % 2 ) continue; // each face encounters twice
3445 const TopoDS_Shape& F = f110It.Value();
3446 for ( i = 0, f111It.Initialize( f111List ); f111It.More(); f111It.Next(), i++ ) {
3447 if ( NB_FACES_BY_VERTEX == 6 && i % 2 ) continue; // each face encounters twice
3448 if ( F.IsSame( f111It.Value() )) { // Fx1z or F1yz found
3449 if ( Fx1z.IsNull() )
3456 if ( Fx1z.IsNull() || F1yz.IsNull() ) {
3457 MESSAGE(" LoadBlockShapes() error ");
3461 // swap Fx1z and F1yz if necessary
3462 for ( exp.Init( Fx1z, TopAbs_VERTEX ); exp.More(); exp.Next() )
3463 if ( V010.IsSame( exp.Current() ) || V011.IsSame( exp.Current() ))
3465 if ( !exp.More() ) {
3466 TopoDS_Shape f = Fx1z; Fx1z = F1yz; F1yz = f;
3469 // find vertical edges
3470 for ( exp.Init( Fx0z, TopAbs_EDGE ); exp.More(); exp.Next() ) {
3471 const TopoDS_Edge& edge = TopoDS::Edge( exp.Current() );
3472 const TopoDS_Shape& vFirst = TopExp::FirstVertex( edge, true );
3473 if ( vFirst.IsSame( V001 ))
3475 else if ( vFirst.IsSame( V100 ))
3478 if ( E00z.IsNull() || E10z.IsNull() ) {
3479 MESSAGE(" LoadBlockShapes() error ");
3482 for ( exp.Init( Fx1z, TopAbs_EDGE ); exp.More(); exp.Next() ) {
3483 const TopoDS_Edge& edge = TopoDS::Edge( exp.Current() );
3484 const TopoDS_Shape& vFirst = TopExp::FirstVertex( edge, true );
3485 if ( vFirst.IsSame( V111 ))
3487 else if ( vFirst.IsSame( V010 ))
3490 if ( E01z.IsNull() || E11z.IsNull() ) {
3491 MESSAGE(" LoadBlockShapes() error ");
3495 // load shapes in theShapeIDMap
3497 theShapeIDMap.Clear();
3499 theShapeIDMap.Add(V000.Oriented( TopAbs_FORWARD ));
3500 theShapeIDMap.Add(V100.Oriented( TopAbs_FORWARD ));
3501 theShapeIDMap.Add(V010.Oriented( TopAbs_FORWARD ));
3502 theShapeIDMap.Add(V110.Oriented( TopAbs_FORWARD ));
3503 theShapeIDMap.Add(V001.Oriented( TopAbs_FORWARD ));
3504 theShapeIDMap.Add(V101.Oriented( TopAbs_FORWARD ));
3505 theShapeIDMap.Add(V011.Oriented( TopAbs_FORWARD ));
3506 theShapeIDMap.Add(V111.Oriented( TopAbs_FORWARD ));
3508 theShapeIDMap.Add(Ex00);
3509 theShapeIDMap.Add(Ex10);
3510 theShapeIDMap.Add(Ex01);
3511 theShapeIDMap.Add(Ex11);
3513 theShapeIDMap.Add(E0y0);
3514 theShapeIDMap.Add(E1y0);
3515 theShapeIDMap.Add(E0y1);
3516 theShapeIDMap.Add(E1y1);
3518 theShapeIDMap.Add(E00z);
3519 theShapeIDMap.Add(E10z);
3520 theShapeIDMap.Add(E01z);
3521 theShapeIDMap.Add(E11z);
3523 theShapeIDMap.Add(Fxy0);
3524 theShapeIDMap.Add(Fxy1);
3525 theShapeIDMap.Add(Fx0z);
3526 theShapeIDMap.Add(Fx1z);
3527 theShapeIDMap.Add(F0yz);
3528 theShapeIDMap.Add(F1yz);
3530 theShapeIDMap.Add(myShell);
3532 if ( theShapeIDMap.Extent() != 27 ) {
3533 MESSAGE("LoadBlockShapes() " << theShapeIDMap.Extent() );
3537 // store shapes geometry
3538 for ( int shapeID = 1; shapeID < theShapeIDMap.Extent(); shapeID++ )
3540 const TopoDS_Shape& S = theShapeIDMap( shapeID );
3541 switch ( S.ShapeType() )
3543 case TopAbs_VERTEX: {
3545 if ( shapeID > ID_V111 ) {
3546 MESSAGE(" shapeID =" << shapeID );
3549 myPnt[ shapeID - ID_V000 ] =
3550 BRep_Tool::Pnt( TopoDS::Vertex( S )).XYZ();
3555 const TopoDS_Edge& edge = TopoDS::Edge( S );
3556 if ( shapeID < ID_Ex00 || shapeID > ID_E11z || edge.IsNull() ) {
3557 MESSAGE(" shapeID =" << shapeID );
3560 TEdge& tEdge = myEdge[ shapeID - ID_Ex00 ];
3561 tEdge.myCoordInd = GetCoordIndOnEdge( shapeID );
3562 TopLoc_Location loc;
3563 tEdge.myC3d = BRep_Tool::Curve( edge, loc, tEdge.myFirst, tEdge.myLast );
3564 if ( !IsForwardEdge( edge, theShapeIDMap ))
3565 Swap( tEdge.myFirst, tEdge.myLast );
3571 const TopoDS_Face& face = TopoDS::Face( S );
3572 if ( shapeID < ID_Fxy0 || shapeID > ID_F1yz || face.IsNull() ) {
3573 MESSAGE(" shapeID =" << shapeID );
3576 TFace& tFace = myFace[ shapeID - ID_Fxy0 ];
3578 vector< int > edgeIdVec(4, -1);
3579 GetFaceEdgesIDs( shapeID, edgeIdVec );
3580 for ( int iE = 0; iE < 4; iE++ ) // loop on 4 edges
3582 const TopoDS_Edge& edge = TopoDS::Edge( theShapeIDMap( edgeIdVec[ iE ]));
3583 tFace.myCoordInd[ iE ] = GetCoordIndOnEdge( edgeIdVec[ iE ] );
3585 BRep_Tool::CurveOnSurface( edge, face, tFace.myFirst[iE], tFace.myLast[iE] );
3586 if ( !IsForwardEdge( edge, theShapeIDMap ))
3587 Swap( tFace.myFirst[ iE ], tFace.myLast[ iE ] );
3590 tFace.myCorner[ 0 ] = tFace.myC2d[ 0 ]->Value( tFace.myFirst[0] ).XY();
3591 tFace.myCorner[ 1 ] = tFace.myC2d[ 0 ]->Value( tFace.myLast[0] ).XY();
3592 tFace.myCorner[ 2 ] = tFace.myC2d[ 1 ]->Value( tFace.myLast[1] ).XY();
3593 tFace.myCorner[ 3 ] = tFace.myC2d[ 1 ]->Value( tFace.myFirst[1] ).XY();
3595 TopLoc_Location loc;
3596 tFace.myS = BRep_Tool::Surface( face, loc );
3602 } // loop on shapes in theShapeIDMap
3607 //=======================================================================
3608 //function : GetFaceEdgesIDs
3609 //purpose : return edges IDs in the order u0, u1, 0v, 1v
3610 // u0 means "|| u, v == 0"
3611 //=======================================================================
3613 void TBlock::GetFaceEdgesIDs (const int faceID, vector< int >& edgeVec )
3617 edgeVec[ 0 ] = ID_Ex00;
3618 edgeVec[ 1 ] = ID_Ex10;
3619 edgeVec[ 2 ] = ID_E0y0;
3620 edgeVec[ 3 ] = ID_E1y0;
3623 edgeVec[ 0 ] = ID_Ex01;
3624 edgeVec[ 1 ] = ID_Ex11;
3625 edgeVec[ 2 ] = ID_E0y1;
3626 edgeVec[ 3 ] = ID_E1y1;
3629 edgeVec[ 0 ] = ID_Ex00;
3630 edgeVec[ 1 ] = ID_Ex01;
3631 edgeVec[ 2 ] = ID_E00z;
3632 edgeVec[ 3 ] = ID_E10z;
3635 edgeVec[ 0 ] = ID_Ex10;
3636 edgeVec[ 1 ] = ID_Ex11;
3637 edgeVec[ 2 ] = ID_E01z;
3638 edgeVec[ 3 ] = ID_E11z;
3641 edgeVec[ 0 ] = ID_E0y0;
3642 edgeVec[ 1 ] = ID_E0y1;
3643 edgeVec[ 2 ] = ID_E00z;
3644 edgeVec[ 3 ] = ID_E01z;
3647 edgeVec[ 0 ] = ID_E1y0;
3648 edgeVec[ 1 ] = ID_E1y1;
3649 edgeVec[ 2 ] = ID_E10z;
3650 edgeVec[ 3 ] = ID_E11z;
3653 MESSAGE(" GetFaceEdgesIDs(), wrong face ID: " << faceID );