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 ).Modulus();
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,
887 gp_XY loc1 = uv11 * ( 1 - r1 ) + uv12 * r1;
888 gp_XY loc2 = uv21 * ( 1 - r2 ) + uv22 * r2;
889 resUV = 0.5 * ( loc1 + loc2 );
890 isDeformed = ( loc1 - loc2 ).SquareModulus() > 1e-8;
891 // double len1 = ( uv11 - uv12 ).Modulus();
892 // double len2 = ( uv21 - uv22 ).Modulus();
893 // resUV = loc1 * len2 / ( len1 + len2 ) + loc2 * len1 / ( len1 + len2 );
897 // gp_Lin2d line1( uv11, uv12 - uv11 );
898 // gp_Lin2d line2( uv21, uv22 - uv21 );
899 // double angle = Abs( line1.Angle( line2 ) );
901 // IntAna2d_AnaIntersection inter;
902 // inter.Perform( line1.Normal( loc1 ), line2.Normal( loc2 ) );
903 // if ( inter.IsDone() && inter.NbPoints() == 1 )
905 // gp_Pnt2d interUV = inter.Point(1).Value();
906 // resUV += interUV.XY();
907 // inter.Perform( line1, line2 );
908 // interUV = inter.Point(1).Value();
909 // resUV += interUV.XY();
916 //=======================================================================
917 //function : compUVByIsoIntersection
919 //=======================================================================
921 bool SMESH_Pattern::compUVByIsoIntersection (const list< list< TPoint* > >& theBndPoints,
922 const gp_XY& theInitUV,
924 bool & theIsDeformed )
926 // compute UV by intersection of 2 iso lines
927 //gp_Lin2d isoLine[2];
928 gp_XY uv1[2], uv2[2];
930 const double zero = DBL_MIN;
931 for ( int iIso = 0; iIso < 2; iIso++ )
933 // to build an iso line:
934 // find 2 pairs of consequent edge-points such that the range of their
935 // initial parameters encloses the in-face point initial parameter
936 gp_XY UV[2], initUV[2];
937 int nbUV = 0, iCoord = iIso + 1;
938 double initParam = theInitUV.Coord( iCoord );
940 list< list< TPoint* > >::const_iterator bndIt = theBndPoints.begin();
941 for ( ; bndIt != theBndPoints.end(); bndIt++ )
943 const list< TPoint* > & bndPoints = * bndIt;
944 TPoint* prevP = bndPoints.back(); // this is the first point
945 list< TPoint* >::const_iterator pIt = bndPoints.begin();
946 bool coincPrev = false;
947 // loop on the edge-points
948 for ( ; pIt != bndPoints.end(); pIt++ )
950 double paramDiff = initParam - (*pIt)->myInitUV.Coord( iCoord );
951 double prevParamDiff = initParam - prevP->myInitUV.Coord( iCoord );
952 double sumOfDiff = Abs(prevParamDiff) + Abs(paramDiff);
953 if (!coincPrev && // ignore if initParam coincides with prev point param
954 sumOfDiff > zero && // ignore if both points coincide with initParam
955 prevParamDiff * paramDiff <= zero )
957 // find UV in parametric space of theFace
958 double r = Abs(prevParamDiff) / sumOfDiff;
959 gp_XY uvInit = (*pIt)->myInitUV * r + prevP->myInitUV * ( 1 - r );
962 // throw away uv most distant from <theInitUV>
963 gp_XY vec0 = initUV[0] - theInitUV;
964 gp_XY vec1 = initUV[1] - theInitUV;
965 gp_XY vec = uvInit - theInitUV;
966 bool isBetween = ( vec0 * vec1 < 0 ); // is theInitUV between initUV[0] and initUV[1]
967 double dist0 = vec0.SquareModulus();
968 double dist1 = vec1.SquareModulus();
969 double dist = vec .SquareModulus();
970 if ( !isBetween || dist < dist0 || dist < dist1 ) {
971 i = ( dist0 < dist1 ? 1 : 0 );
972 if ( isBetween && vec.Dot( i ? vec1 : vec0 ) < 0 )
973 i = 3; // theInitUV must remain between
977 initUV[ i ] = uvInit;
978 UV[ i ] = (*pIt)->myUV * r + prevP->myUV * ( 1 - r );
980 coincPrev = ( Abs(paramDiff) <= zero );
987 if ( nbUV < 2 || (UV[0]-UV[1]).SquareModulus() <= DBL_MIN*DBL_MIN ) {
988 MESSAGE(" consequent edge-points not found, nb UV found: " << nbUV <<
989 ", for point: " << theInitUV.X() <<" " << theInitUV.Y() );
990 return setErrorCode( ERR_APPLF_BAD_TOPOLOGY );
992 // an iso line should be normal to UV[0] - UV[1] direction
993 // and be located at the same relative distance as from initial ends
994 //gp_Lin2d iso( UV[0], UV[0] - UV[1] );
996 (initUV[0]-theInitUV).Modulus() / (initUV[0]-initUV[1]).Modulus();
997 //gp_Pnt2d isoLoc = UV[0] * ( 1 - r ) + UV[1] * r;
998 //isoLine[ iIso ] = iso.Normal( isoLoc );
1000 uv2[ iIso ] = UV[1];
1003 if ( !intersectIsolines( uv1[0], uv2[0], ratio[0],
1004 uv1[1], uv2[1], ratio[1], theUV, theIsDeformed )) {
1005 MESSAGE(" Cant intersect isolines for a point "<<theInitUV.X()<<", "<<theInitUV.Y());
1006 return setErrorCode( ERR_APPLF_BAD_TOPOLOGY );
1013 // ==========================================================
1014 // structure representing a node of a grid of iso-poly-lines
1015 // ==========================================================
1022 gp_Dir2d myDir[2]; // boundary tangent dir for boundary nodes, iso dir for internal ones
1023 TIsoNode* myNext[4]; // order: (iDir=0,isForward=0), (1,0), (0,1), (1,1)
1024 TIsoNode* myBndNodes[4]; // order: (iDir=0,i=0), (1,0), (0,1), (1,1)
1025 TIsoNode(double initU, double initV):
1026 myInitUV( initU, initV ), myUV( 1e100, 1e100 ), myIsMovable(true)
1027 { myNext[0] = myNext[1] = myNext[2] = myNext[3] = 0; }
1028 bool IsUVComputed() const
1029 { return myUV.X() != 1e100; }
1030 bool IsMovable() const
1031 { return myIsMovable && myNext[0] && myNext[1] && myNext[2] && myNext[3]; }
1032 void SetNotMovable()
1033 { myIsMovable = false; }
1034 void SetBoundaryNode(TIsoNode* node, int iDir, int i)
1035 { myBndNodes[ iDir + i * 2 ] = node; }
1036 TIsoNode* GetBoundaryNode(int iDir, int i)
1037 { return myBndNodes[ iDir + i * 2 ]; }
1038 void SetNext(TIsoNode* node, int iDir, int isForward)
1039 { myNext[ iDir + isForward * 2 ] = node; }
1040 TIsoNode* GetNext(int iDir, int isForward)
1041 { return myNext[ iDir + isForward * 2 ]; }
1044 //=======================================================================
1045 //function : getNextNode
1047 //=======================================================================
1049 static inline TIsoNode* getNextNode(const TIsoNode* node, int dir )
1051 TIsoNode* n = node->myNext[ dir ];
1052 if ( n && !n->IsUVComputed()/* && node->IsMovable()*/ ) {
1053 n = 0;//node->myBndNodes[ dir ];
1054 // MESSAGE("getNextNode: use bnd for node "<<
1055 // node->myInitUV.X()<<" "<<node->myInitUV.Y());
1059 //=======================================================================
1060 //function : checkQuads
1061 //purpose : check if newUV destortes quadrangles around node,
1062 // and if ( crit == FIX_OLD ) fix newUV in this case
1063 //=======================================================================
1065 enum { CHECK_NEW_IN, CHECK_NEW_OK, FIX_OLD };
1067 static bool checkQuads (const TIsoNode* node,
1069 const bool reversed,
1070 const int crit = FIX_OLD,
1071 double fixSize = 0.)
1073 gp_XY oldUV = node->myUV, oldUVFixed[4], oldUVImpr[4];
1074 int nbOldFix = 0, nbOldImpr = 0;
1075 double newBadRate = 0, oldBadRate = 0;
1076 bool newIsOk = true, newIsIn = true, oldIsIn = true, oldIsOk = true;
1077 int i, dir1 = 0, dir2 = 3;
1078 for ( ; dir1 < 4; dir1++, dir2++ ) // loop on 4 quadrangles around <node>
1080 if ( dir2 > 3 ) dir2 = 0;
1082 // walking counterclockwise around a quad,
1083 // nodes are in the order: node, n[0], n[1], n[2]
1084 n[0] = getNextNode( node, dir1 );
1085 n[2] = getNextNode( node, dir2 );
1086 if ( !n[0] || !n[2] ) continue;
1087 n[1] = getNextNode( n[0], dir2 );
1088 if ( !n[1] ) n[1] = getNextNode( n[2], dir1 );
1089 bool isTriangle = ( !n[1] );
1091 TIsoNode* tmp = n[0]; n[0] = n[2]; n[2] = tmp;
1093 // if ( fixSize != 0 ) {
1094 // cout<<"NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<" UV: "<<node->myUV.X()<<" "<<node->myUV.Y()<<endl;
1095 // cout<<"\t0: "<<n[0]->myInitUV.X()<<" "<<n[0]->myInitUV.Y()<<" UV: "<<n[0]->myUV.X()<<" "<<n[0]->myUV.Y()<<endl;
1096 // cout<<"\t1: "<<n[1]->myInitUV.X()<<" "<<n[1]->myInitUV.Y()<<" UV: "<<n[1]->myUV.X()<<" "<<n[1]->myUV.Y()<<endl;
1097 // cout<<"\t2: "<<n[2]->myInitUV.X()<<" "<<n[2]->myInitUV.Y()<<" UV: "<<n[2]->myUV.X()<<" "<<n[2]->myUV.Y()<<endl;
1099 // check if a quadrangle is degenerated
1101 ((( n[0]->myUV - n[1]->myUV ).SquareModulus() <= DBL_MIN ) ||
1102 (( n[2]->myUV - n[1]->myUV ).SquareModulus() <= DBL_MIN )))
1105 ( n[0]->myUV - n[2]->myUV ).SquareModulus() <= DBL_MIN )
1108 // find min size of the diagonal node-n[1]
1109 double minDiag = fixSize;
1110 if ( minDiag == 0. ) {
1111 double maxLen2 = ( node->myUV - n[0]->myUV ).SquareModulus();
1112 if ( !isTriangle ) {
1113 maxLen2 = Max( maxLen2, ( n[0]->myUV - n[1]->myUV ).SquareModulus() );
1114 maxLen2 = Max( maxLen2, ( n[1]->myUV - n[2]->myUV ).SquareModulus() );
1116 maxLen2 = Max( maxLen2, ( n[2]->myUV - node->myUV ).SquareModulus() );
1117 minDiag = sqrt( maxLen2 ) * PI / 60.; // ~ maxLen * Sin( 3 deg )
1120 // check if newUV is behind 3 dirs: n[0]-n[1], n[1]-n[2] and n[0]-n[2]
1121 // ( behind means "to the right of")
1123 // 1. newUV is not behind 01 and 12 dirs
1124 // 2. or newUV is not behind 02 dir and n[2] is convex
1125 bool newIn[3] = { true, true, true }, newOk[3] = { true, true, true };
1126 bool wasIn[3] = { true, true, true }, wasOk[3] = { true, true, true };
1127 gp_Vec2d moveVec[3], outVec[3];
1128 for ( i = isTriangle ? 2 : 0; i < 3; i++ )
1130 bool isDiag = ( i == 2 );
1131 if ( isDiag && newOk[0] && newOk[1] && !isTriangle )
1135 sideDir = gp_Vec2d( n[0]->myUV, n[2]->myUV );
1137 sideDir = gp_Vec2d( n[i]->myUV, n[i+1]->myUV );
1139 gp_Vec2d outDir( sideDir.Y(), -sideDir.X() ); // to the right
1141 gp_Vec2d newDir( n[i]->myUV, newUV );
1142 gp_Vec2d oldDir( n[i]->myUV, oldUV );
1144 if ( newIsOk ) newOk[i] = ( outDir * newDir < -minDiag );
1145 if ( newIsIn ) newIn[i] = ( outDir * newDir < 0 );
1146 if ( crit == FIX_OLD ) {
1147 wasIn[i] = ( outDir * oldDir < 0 );
1148 wasOk[i] = ( outDir * oldDir < -minDiag );
1150 newBadRate += outDir * newDir;
1152 oldBadRate += outDir * oldDir;
1155 double oldDist = - outDir * oldDir;//, l2 = outDir * newDir;
1156 // double r = ( l1 - minDiag ) / ( l1 + l2 );
1157 // moveVec[i] = r * gp_Vec2d( node->myUV, newUV );
1158 moveVec[i] = ( oldDist - minDiag ) * outDir;
1163 // check if n[2] is convex
1166 convex = ( outVec[0] * gp_Vec2d( n[1]->myUV, n[2]->myUV ) < 0 );
1168 bool isNewOk = ( newOk[0] && newOk[1] ) || ( newOk[2] && convex );
1169 bool isNewIn = ( newIn[0] && newIn[1] ) || ( newIn[2] && convex );
1170 newIsOk = ( newIsOk && isNewOk );
1171 newIsIn = ( newIsIn && isNewIn );
1173 if ( crit != FIX_OLD ) {
1174 if ( crit == CHECK_NEW_OK && !newIsOk ) break;
1175 if ( crit == CHECK_NEW_IN && !newIsIn ) break;
1179 bool isOldIn = ( wasIn[0] && wasIn[1] ) || ( wasIn[2] && convex );
1180 bool isOldOk = ( wasOk[0] && wasOk[1] ) || ( wasOk[2] && convex );
1181 oldIsIn = ( oldIsIn && isOldIn );
1182 oldIsOk = ( oldIsOk && isOldIn );
1185 if ( !isOldIn ) { // node is outside a quadrangle
1186 // move newUV inside a quadrangle
1187 //MESSAGE("Quad "<< dir1 << " WAS IN " << wasIn[0]<<" "<<wasIn[1]<<" "<<wasIn[2]);
1188 // node and newUV are outside: push newUV inside
1190 if ( convex || isTriangle ) {
1191 uv = 0.5 * ( n[0]->myUV + n[2]->myUV ) - minDiag * outVec[2].XY();
1194 gp_Vec2d out = outVec[0].Normalized() + outVec[1].Normalized();
1195 double outSize = out.Magnitude();
1196 if ( outSize > DBL_MIN )
1199 out.SetCoord( -outVec[1].Y(), outVec[1].X() );
1200 uv = n[1]->myUV - minDiag * out.XY();
1202 oldUVFixed[ nbOldFix++ ] = uv;
1203 //node->myUV = newUV;
1205 else if ( !isOldOk ) {
1206 // try to fix old UV: move node inside as less as possible
1207 //MESSAGE("Quad "<< dir1 << " old is BAD, try to fix old, minDiag: "<< minDiag);
1208 gp_XY uv1, uv2 = node->myUV;
1209 for ( i = isTriangle ? 2 : 0; i < 3; i++ ) // mark not computed vectors
1211 moveVec[ i ].SetCoord( 1, 2e100); // not use this vector
1212 while ( !isOldOk ) {
1213 // find the least moveVec
1215 double minMove2 = 1e100;
1216 for ( i = isTriangle ? 2 : 0; i < 3; i++ )
1218 if ( moveVec[i].Coord(1) < 1e100 ) {
1219 double move2 = moveVec[i].SquareMagnitude();
1220 if ( move2 < minMove2 ) {
1229 // move node to newUV
1230 uv1 = node->myUV + moveVec[ iMin ].XY();
1231 uv2 += moveVec[ iMin ].XY();
1232 moveVec[ iMin ].SetCoord( 1, 2e100); // not use this vector more
1233 // check if uv1 is ok
1234 for ( i = isTriangle ? 2 : 0; i < 3; i++ )
1235 wasOk[i] = ( outVec[i] * gp_Vec2d( n[i]->myUV, uv1 ) < -minDiag );
1236 isOldOk = ( wasOk[0] && wasOk[1] ) || ( wasOk[2] && convex );
1238 oldUVImpr[ nbOldImpr++ ] = uv1;
1240 // check if uv2 is ok
1241 for ( i = isTriangle ? 2 : 0; i < 3; i++ )
1242 wasOk[i] = ( outVec[i] * gp_Vec2d( n[i]->myUV, uv2 ) < -minDiag );
1243 isOldOk = ( wasOk[0] && wasOk[1] ) || ( wasOk[2] && convex );
1245 oldUVImpr[ nbOldImpr++ ] = uv2;
1250 } // loop on 4 quadrangles around <node>
1252 if ( crit == CHECK_NEW_OK )
1254 if ( crit == CHECK_NEW_IN )
1263 if ( oldIsIn && nbOldImpr ) {
1264 // MESSAGE(" Try to improve UV, init: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<
1265 // " uv: "<<oldUV.X()<<" "<<oldUV.Y() );
1266 gp_XY uv = oldUVImpr[ 0 ];
1267 for ( int i = 1; i < nbOldImpr; i++ )
1268 uv += oldUVImpr[ i ];
1270 if ( checkQuads( node, uv, reversed, CHECK_NEW_OK )) {
1275 //MESSAGE(" Cant improve UV, uv: "<<uv.X()<<" "<<uv.Y());
1278 if ( !oldIsIn && nbOldFix ) {
1279 // MESSAGE(" Try to fix UV, init: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<
1280 // " uv: "<<oldUV.X()<<" "<<oldUV.Y() );
1281 gp_XY uv = oldUVFixed[ 0 ];
1282 for ( int i = 1; i < nbOldFix; i++ )
1283 uv += oldUVFixed[ i ];
1285 if ( checkQuads( node, uv, reversed, CHECK_NEW_IN )) {
1290 //MESSAGE(" Cant fix UV, uv: "<<uv.X()<<" "<<uv.Y());
1293 if ( newIsIn && oldIsIn )
1294 newUV = ( newBadRate < oldBadRate ) ? newUV : oldUV;
1295 else if ( !newIsIn )
1302 //=======================================================================
1303 //function : compUVByElasticIsolines
1304 //purpose : compute UV as nodes of iso-poly-lines consisting of
1305 // segments keeping relative size as in the pattern
1306 //=======================================================================
1307 //#define DEB_COMPUVBYELASTICISOLINES
1308 bool SMESH_Pattern::
1309 compUVByElasticIsolines(const list< list< TPoint* > >& theBndPoints,
1310 const list< TPoint* >& thePntToCompute)
1312 //cout << "============================== KEY POINTS =============================="<<endl;
1313 // list< int >::iterator kpIt = myKeyPointIDs.begin();
1314 // for ( ; kpIt != myKeyPointIDs.end(); kpIt++ ) {
1315 // TPoint& p = myPoints[ *kpIt ];
1316 // cout << "INIT: " << p.myInitUV.X() << " " << p.myInitUV.Y() <<
1317 // " UV: " << p.myUV.X() << " " << p.myUV.Y() << endl;
1319 //cout << "=============================="<<endl;
1321 // Define parameters of iso-grid nodes in U and V dir
1323 set< double > paramSet[ 2 ];
1324 list< list< TPoint* > >::const_iterator pListIt;
1325 list< TPoint* >::const_iterator pIt;
1326 for ( pListIt = theBndPoints.begin(); pListIt != theBndPoints.end(); pListIt++ ) {
1327 const list< TPoint* > & pList = * pListIt;
1328 for ( pIt = pList.begin(); pIt != pList.end(); pIt++ ) {
1329 paramSet[0].insert( (*pIt)->myInitUV.X() );
1330 paramSet[1].insert( (*pIt)->myInitUV.Y() );
1333 for ( pIt = thePntToCompute.begin(); pIt != thePntToCompute.end(); pIt++ ) {
1334 paramSet[0].insert( (*pIt)->myInitUV.X() );
1335 paramSet[1].insert( (*pIt)->myInitUV.Y() );
1337 // unite close parameters and split too long segments
1340 for ( iDir = 0; iDir < 2; iDir++ )
1342 set< double > & params = paramSet[ iDir ];
1343 double range = ( *params.rbegin() - *params.begin() );
1344 double toler = range / 1e6;
1345 tol[ iDir ] = toler;
1346 // double maxSegment = range / params.size() / 2.;
1348 // set< double >::iterator parIt = params.begin();
1349 // double prevPar = *parIt;
1350 // for ( parIt++; parIt != params.end(); parIt++ )
1352 // double segLen = (*parIt) - prevPar;
1353 // if ( segLen < toler )
1354 // ;//params.erase( prevPar ); // unite
1355 // else if ( segLen > maxSegment )
1356 // params.insert( prevPar + 0.5 * segLen ); // split
1357 // prevPar = (*parIt);
1361 // Make nodes of a grid of iso-poly-lines
1363 list < TIsoNode > nodes;
1364 typedef list < TIsoNode *> TIsoLine;
1365 map < double, TIsoLine > isoMap[ 2 ];
1367 set< double > & params0 = paramSet[ 0 ];
1368 set< double >::iterator par0It = params0.begin();
1369 for ( ; par0It != params0.end(); par0It++ )
1371 TIsoLine & isoLine0 = isoMap[0][ *par0It ]; // vertical isoline with const U
1372 set< double > & params1 = paramSet[ 1 ];
1373 set< double >::iterator par1It = params1.begin();
1374 for ( ; par1It != params1.end(); par1It++ )
1376 nodes.push_back( TIsoNode( *par0It, *par1It ) );
1377 isoLine0.push_back( & nodes.back() );
1378 isoMap[1][ *par1It ].push_back( & nodes.back() );
1382 // Compute intersections of boundaries with iso-lines:
1383 // only boundary nodes will have computed UV so far
1386 list< list< TPoint* > >::const_iterator bndIt = theBndPoints.begin();
1387 list< TIsoNode* > bndNodes; // nodes corresponding to outer theBndPoints
1388 for ( ; bndIt != theBndPoints.end(); bndIt++ )
1390 const list< TPoint* > & bndPoints = * bndIt;
1391 TPoint* prevP = bndPoints.back(); // this is the first point
1392 list< TPoint* >::const_iterator pIt = bndPoints.begin();
1393 // loop on the edge-points
1394 for ( ; pIt != bndPoints.end(); pIt++ )
1396 TPoint* point = *pIt;
1397 for ( iDir = 0; iDir < 2; iDir++ )
1399 const int iCoord = iDir + 1;
1400 const int iOtherCoord = 2 - iDir;
1401 double par1 = prevP->myInitUV.Coord( iCoord );
1402 double par2 = point->myInitUV.Coord( iCoord );
1403 double parDif = par2 - par1;
1404 if ( Abs( parDif ) <= DBL_MIN )
1406 // find iso-lines intersecting a bounadry
1407 double toler = tol[ 1 - iDir ];
1408 double minPar = Min ( par1, par2 );
1409 double maxPar = Max ( par1, par2 );
1410 map < double, TIsoLine >& isos = isoMap[ iDir ];
1411 map < double, TIsoLine >::iterator isoIt = isos.begin();
1412 for ( ; isoIt != isos.end(); isoIt++ )
1414 double isoParam = (*isoIt).first;
1415 if ( isoParam < minPar || isoParam > maxPar )
1417 double r = ( isoParam - par1 ) / parDif;
1418 gp_XY uv = ( 1 - r ) * prevP->myUV + r * point->myUV;
1419 gp_XY initUV = ( 1 - r ) * prevP->myInitUV + r * point->myInitUV;
1420 double otherPar = initUV.Coord( iOtherCoord ); // along isoline
1421 // find existing node with otherPar or insert a new one
1422 TIsoLine & isoLine = (*isoIt).second;
1424 TIsoLine::iterator nIt = isoLine.begin();
1425 for ( ; nIt != isoLine.end(); nIt++ ) {
1426 nodePar = (*nIt)->myInitUV.Coord( iOtherCoord );
1427 if ( nodePar >= otherPar )
1431 if ( Abs( nodePar - otherPar ) <= toler )
1432 node = ( nIt == isoLine.end() ) ? isoLine.back() : (*nIt);
1434 nodes.push_back( TIsoNode( initUV.X(), initUV.Y() ) );
1435 node = & nodes.back();
1436 isoLine.insert( nIt, node );
1438 node->SetNotMovable();
1440 uvBnd.Add( gp_Pnt2d( uv ));
1441 // cout << "bnd: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<" UV: "<<node->myUV.X()<<" "<<node->myUV.Y()<<endl;
1443 gp_XY tgt( point->myUV - prevP->myUV );
1444 if ( ::IsEqual( r, 1. ))
1445 node->myDir[ 0 ] = tgt;
1446 else if ( ::IsEqual( r, 0. ))
1447 node->myDir[ 1 ] = tgt;
1449 node->myDir[ 1 ] = node->myDir[ 0 ] = tgt;
1450 // keep boundary nodes corresponding to boundary points
1451 if ( bndIt == theBndPoints.begin() && ::IsEqual( r, 1. ))
1452 if ( bndNodes.empty() || bndNodes.back() != node )
1453 bndNodes.push_back( node );
1454 } // loop on isolines
1455 } // loop on 2 directions
1457 } // loop on boundary points
1458 } // loop on boundaries
1460 // Define orientation
1462 // find the point with the least X
1463 double leastX = DBL_MAX;
1464 TIsoNode * leftNode;
1465 list < TIsoNode >::iterator nodeIt = nodes.begin();
1466 for ( ; nodeIt != nodes.end(); nodeIt++ ) {
1467 TIsoNode & node = *nodeIt;
1468 if ( node.IsUVComputed() && node.myUV.X() < leastX ) {
1469 leastX = node.myUV.X();
1472 // if ( node.IsUVComputed() ) {
1473 // cout << "bndNode INIT: " << node.myInitUV.X()<<" "<<node.myInitUV.Y()<<" UV: "<<
1474 // node.myUV.X()<<" "<<node.myUV.Y()<<endl<<
1475 // " dir0: "<<node.myDir[0].X()<<" "<<node.myDir[0].Y() <<
1476 // " dir1: "<<node.myDir[1].X()<<" "<<node.myDir[1].Y() << endl;
1479 bool reversed = ( leftNode->myDir[0].Y() + leftNode->myDir[1].Y() > 0 );
1480 //SCRUTE( reversed );
1482 // Prepare internal nodes:
1484 // 2. compute ratios
1485 // 3. find boundary nodes for each node
1486 // 4. remove nodes out of the boundary
1487 for ( iDir = 0; iDir < 2; iDir++ )
1489 const int iCoord = 2 - iDir; // coord changing along an isoline
1490 map < double, TIsoLine >& isos = isoMap[ iDir ];
1491 map < double, TIsoLine >::iterator isoIt = isos.begin();
1492 for ( ; isoIt != isos.end(); isoIt++ )
1494 TIsoLine & isoLine = (*isoIt).second;
1495 bool firstCompNodeFound = false;
1496 TIsoLine::iterator lastCompNodePos, nPrevIt, nIt, nNextIt, nIt2;
1497 nPrevIt = nIt = nNextIt = isoLine.begin();
1499 nNextIt++; nNextIt++;
1500 while ( nIt != isoLine.end() )
1502 // 1. connect prev - cur
1503 TIsoNode* node = *nIt, * prevNode = *nPrevIt;
1504 if ( !firstCompNodeFound && prevNode->IsUVComputed() ) {
1505 firstCompNodeFound = true;
1506 lastCompNodePos = nPrevIt;
1508 if ( firstCompNodeFound ) {
1509 node->SetNext( prevNode, iDir, 0 );
1510 prevNode->SetNext( node, iDir, 1 );
1513 if ( nNextIt != isoLine.end() ) {
1514 double par1 = prevNode->myInitUV.Coord( iCoord );
1515 double par2 = node->myInitUV.Coord( iCoord );
1516 double par3 = (*nNextIt)->myInitUV.Coord( iCoord );
1517 node->myRatio[ iDir ] = ( par2 - par1 ) / ( par3 - par1 );
1519 // 3. find boundary nodes
1520 if ( node->IsUVComputed() )
1521 lastCompNodePos = nIt;
1522 else if ( firstCompNodeFound && nNextIt != isoLine.end() ) {
1523 TIsoNode* bndNode1 = *lastCompNodePos, *bndNode2 = 0;
1524 for ( nIt2 = nNextIt; nIt2 != isoLine.end(); nIt2++ )
1525 if ( (*nIt2)->IsUVComputed() )
1527 if ( nIt2 != isoLine.end() ) {
1529 node->SetBoundaryNode( bndNode1, iDir, 0 );
1530 node->SetBoundaryNode( bndNode2, iDir, 1 );
1531 // cout << "--------------------------------------------------"<<endl;
1532 // cout << "bndNode1: " << bndNode1->myUV.X()<<" "<<bndNode1->myUV.Y()<<endl<<
1533 // " dir0: "<<bndNode1->myDir[0].X()<<" "<<bndNode1->myDir[0].Y() <<
1534 // " dir1: "<<bndNode1->myDir[1].X()<<" "<<bndNode1->myDir[1].Y() << endl;
1535 // cout << "bndNode2: " << bndNode2->myUV.X()<<" "<<bndNode2->myUV.Y()<<endl<<
1536 // " dir0: "<<bndNode2->myDir[0].X()<<" "<<bndNode2->myDir[0].Y() <<
1537 // " dir1: "<<bndNode2->myDir[1].X()<<" "<<bndNode2->myDir[1].Y() << endl;
1541 if ( nNextIt != isoLine.end() ) nNextIt++;
1542 // 4. remove nodes out of the boundary
1543 if ( !firstCompNodeFound )
1544 isoLine.pop_front();
1545 } // loop on isoLine nodes
1547 // remove nodes after the boundary
1548 // for ( nIt = ++lastCompNodePos; nIt != isoLine.end(); nIt++ )
1549 // (*nIt)->SetNotMovable();
1550 isoLine.erase( ++lastCompNodePos, isoLine.end() );
1551 } // loop on isolines
1552 } // loop on 2 directions
1554 // Compute local isoline direction for internal nodes
1557 map < double, TIsoLine >& isos = isoMap[ 0 ]; // vertical isolines with const U
1558 map < double, TIsoLine >::iterator isoIt = isos.begin();
1559 for ( ; isoIt != isos.end(); isoIt++ )
1561 TIsoLine & isoLine = (*isoIt).second;
1562 TIsoLine::iterator nIt = isoLine.begin();
1563 for ( ; nIt != isoLine.end(); nIt++ )
1565 TIsoNode* node = *nIt;
1566 if ( node->IsUVComputed() || !node->IsMovable() )
1568 gp_Vec2d aTgt[2], aNorm[2];
1571 for ( iDir = 0; iDir < 2; iDir++ )
1573 TIsoNode* bndNode1 = node->GetBoundaryNode( iDir, 0 );
1574 TIsoNode* bndNode2 = node->GetBoundaryNode( iDir, 1 );
1575 if ( !bndNode1 || !bndNode2 ) {
1579 const int iCoord = 2 - iDir; // coord changing along an isoline
1580 double par1 = bndNode1->myInitUV.Coord( iCoord );
1581 double par2 = node->myInitUV.Coord( iCoord );
1582 double par3 = bndNode2->myInitUV.Coord( iCoord );
1583 ratio[ iDir ] = ( par2 - par1 ) / ( par3 - par1 );
1585 gp_Vec2d tgt1( bndNode1->myDir[0].XY() + bndNode1->myDir[1].XY() );
1586 gp_Vec2d tgt2( bndNode2->myDir[0].XY() + bndNode2->myDir[1].XY() );
1587 if ( bool( iDir ) == reversed ) tgt2.Reverse(); // along perpend. isoline
1588 else tgt1.Reverse();
1589 //cout<<" tgt: " << tgt1.X()<<" "<<tgt1.Y()<<" | "<< tgt2.X()<<" "<<tgt2.Y()<<endl;
1591 if ( ratio[ iDir ] < 0.5 )
1592 aNorm[ iDir ] = gp_Vec2d( -tgt1.Y(), tgt1.X() ); // rotate tgt to the left
1594 aNorm[ iDir ] = gp_Vec2d( -tgt2.Y(), tgt2.X() );
1596 aNorm[ iDir ].Reverse(); // along iDir isoline
1598 double angle = tgt1.Angle( tgt2 ); // [-PI, PI]
1599 // maybe angle is more than |PI|
1600 if ( Abs( angle ) > PI / 2. ) {
1601 // check direction of the last but one perpendicular isoline
1602 TIsoNode* prevNode = bndNode2->GetNext( iDir, 0 );
1603 bndNode1 = prevNode->GetBoundaryNode( 1 - iDir, 0 );
1604 bndNode2 = prevNode->GetBoundaryNode( 1 - iDir, 1 );
1605 gp_Vec2d isoDir( bndNode1->myUV, bndNode2->myUV );
1606 if ( isoDir * tgt2 < 0 )
1608 double angle2 = tgt1.Angle( isoDir );
1609 //cout << " isoDir: "<< isoDir.X() <<" "<<isoDir.Y() << " ANGLE: "<< angle << " "<<angle2<<endl;
1610 if (angle2 * angle < 0 && // check the sign of an angle close to PI
1611 Abs ( Abs ( angle ) - PI ) <= PI / 180. ) {
1612 //MESSAGE("REVERSE ANGLE");
1615 if ( Abs( angle2 ) > Abs( angle ) ||
1616 ( angle2 * angle < 0 && Abs( angle2 ) > Abs( angle - angle2 ))) {
1617 //MESSAGE("Add PI");
1618 // cout << "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
1619 // cout <<"ISO: " << isoParam << " " << (*iso2It).first << endl;
1620 // cout << "bndNode1: " << bndNode1->myUV.X()<<" "<<bndNode1->myUV.Y()<< endl;
1621 // cout << "bndNode2: " << bndNode2->myUV.X()<<" "<<bndNode2->myUV.Y()<<endl;
1622 // cout <<" tgt: " << tgt1.X()<<" "<<tgt1.Y()<<" "<< tgt2.X()<<" "<<tgt2.Y()<<endl;
1623 angle += ( angle < 0 ) ? 2. * PI : -2. * PI;
1626 aTgt[ iDir ] = tgt1.Rotated( angle * ratio[ iDir ] ).XY();
1630 for ( iDir = 0; iDir < 2; iDir++ )
1632 aTgt[iDir].Normalize();
1633 aNorm[1-iDir].Normalize();
1634 double r = Abs ( ratio[iDir] - 0.5 ) * 2.0; // [0,1] - distance from the middle
1637 node->myDir[iDir] = //aTgt[iDir];
1638 aNorm[1-iDir] * r + aTgt[iDir] * ( 1. - r );
1640 // cout << "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
1641 // cout <<" tgt: " << tgt1.X()<<" "<<tgt1.Y()<<" - "<< tgt2.X()<<" "<<tgt2.Y()<<endl;
1642 // cout << " isoDir: "<< node->myDir[0].X() <<" "<<node->myDir[0].Y()<<" | "
1643 // << node->myDir[1].X() <<" "<<node->myDir[1].Y()<<endl;
1645 } // loop on iso nodes
1646 } // loop on isolines
1648 // Find nodes to start computing UV from
1650 list< TIsoNode* > startNodes;
1651 list< TIsoNode* >::iterator nIt = bndNodes.end();
1652 TIsoNode* node = *(--nIt);
1653 TIsoNode* prevNode = *(--nIt);
1654 for ( nIt = bndNodes.begin(); nIt != bndNodes.end(); nIt++ )
1656 TIsoNode* nextNode = *nIt;
1657 gp_Vec2d initTgt1( prevNode->myInitUV, node->myInitUV );
1658 gp_Vec2d initTgt2( node->myInitUV, nextNode->myInitUV );
1659 double initAngle = initTgt1.Angle( initTgt2 );
1660 double angle = node->myDir[0].Angle( node->myDir[1] );
1661 if ( reversed ) angle = -angle;
1662 if ( initAngle > angle && initAngle - angle > PI / 2.1 ) {
1663 // find a close internal node
1664 TIsoNode* nClose = 0;
1665 list< TIsoNode* > testNodes;
1666 testNodes.push_back( node );
1667 list< TIsoNode* >::iterator it = testNodes.begin();
1668 for ( ; !nClose && it != testNodes.end(); it++ )
1670 for (int i = 0; i < 4; i++ )
1672 nClose = (*it)->myNext[ i ];
1674 if ( !nClose->IsUVComputed() )
1677 testNodes.push_back( nClose );
1683 startNodes.push_back( nClose );
1684 // cout << "START: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<" UV: "<<
1685 // node->myUV.X()<<" "<<node->myUV.Y()<<endl<<
1686 // "initAngle: " << initAngle << " angle: " << angle << endl;
1687 // cout <<" init tgt: " << initTgt1.X()<<" "<<initTgt1.Y()<<" | "<< initTgt2.X()<<" "<<initTgt2.Y()<<endl;
1688 // cout << " tgt: "<< node->myDir[ 0 ].X() <<" "<<node->myDir[ 0 ].Y()<<" | "<<
1689 // node->myDir[ 1 ].X() <<" "<<node->myDir[ 1 ].Y()<<endl;
1690 // cout << "CLOSE: "<<nClose->myInitUV.X()<<" "<<nClose->myInitUV.Y()<<endl;
1696 // Compute starting UV of internal nodes
1698 list < TIsoNode* > internNodes;
1699 bool needIteration = true;
1700 if ( startNodes.empty() ) {
1701 MESSAGE( " Starting UV by compUVByIsoIntersection()");
1702 needIteration = false;
1703 map < double, TIsoLine >& isos = isoMap[ 0 ];
1704 map < double, TIsoLine >::iterator isoIt = isos.begin();
1705 for ( ; isoIt != isos.end(); isoIt++ )
1707 TIsoLine & isoLine = (*isoIt).second;
1708 TIsoLine::iterator nIt = isoLine.begin();
1709 for ( ; !needIteration && nIt != isoLine.end(); nIt++ )
1711 TIsoNode* node = *nIt;
1712 if ( !node->IsUVComputed() && node->IsMovable() ) {
1713 internNodes.push_back( node );
1715 if ( !compUVByIsoIntersection(theBndPoints, node->myInitUV,
1716 node->myUV, needIteration ))
1717 node->myUV = node->myInitUV;
1721 if ( needIteration )
1722 for ( nIt = bndNodes.begin(); nIt != bndNodes.end(); nIt++ )
1724 TIsoNode* node = *nIt, *nClose = 0;
1725 list< TIsoNode* > testNodes;
1726 testNodes.push_back( node );
1727 list< TIsoNode* >::iterator it = testNodes.begin();
1728 for ( ; !nClose && it != testNodes.end(); it++ )
1730 for (int i = 0; i < 4; i++ )
1732 nClose = (*it)->myNext[ i ];
1734 if ( !nClose->IsUVComputed() && nClose->IsMovable() )
1737 testNodes.push_back( nClose );
1743 startNodes.push_back( nClose );
1747 double aMin[2], aMax[2], step[2];
1748 uvBnd.Get( aMin[0], aMin[1], aMax[0], aMax[1] );
1749 double minUvSize = Min ( aMax[0]-aMin[0], aMax[1]-aMin[1] );
1750 step[0] = minUvSize / paramSet[ 0 ].size() / 10;
1751 step[1] = minUvSize / paramSet[ 1 ].size() / 10;
1752 //cout << "STEPS: " << step[0] << " " << step[1]<< endl;
1754 for ( nIt = startNodes.begin(); nIt != startNodes.end(); nIt++ )
1756 TIsoNode* prevN[2], *node = *nIt;
1757 if ( node->IsUVComputed() || !node->IsMovable() )
1759 gp_XY newUV( 0, 0 ), sumDir( 0, 0 );
1760 int nbComp = 0, nbPrev = 0;
1761 for ( iDir = 0; iDir < 2; iDir++ )
1763 TIsoNode* prevNode1 = 0, *prevNode2 = 0;
1764 TIsoNode* n = node->GetNext( iDir, 0 );
1765 if ( n->IsUVComputed() )
1768 startNodes.push_back( n );
1769 n = node->GetNext( iDir, 1 );
1770 if ( n->IsUVComputed() )
1773 startNodes.push_back( n );
1775 prevNode1 = prevNode2;
1778 if ( prevNode1 ) nbPrev++;
1779 if ( prevNode2 ) nbPrev++;
1782 double prevPar = prevNode1->myInitUV.Coord( 2 - iDir );
1783 double par = node->myInitUV.Coord( 2 - iDir );
1784 bool isEnd = ( prevPar > par );
1785 // dir = node->myDir[ 1 - iDir ].XY() * ( isEnd ? -1. : 1. );
1786 //cout << "__________"<<endl<< "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
1787 TIsoNode* bndNode = node->GetBoundaryNode( iDir, isEnd );
1788 gp_XY tgt( bndNode->myDir[0].XY() + bndNode->myDir[1].XY() );
1789 dir.SetCoord( 1, tgt.Y() * ( reversed ? 1 : -1 ));
1790 dir.SetCoord( 2, tgt.X() * ( reversed ? -1 : 1 ));
1791 //cout << "bndNode UV: " << bndNode->myUV.X()<<" "<<bndNode->myUV.Y()<< endl;
1792 // cout << " tgt: "<< bndNode->myDir[ 0 ].X() <<" "<<bndNode->myDir[ 0 ].Y()<<" | "<<
1793 // bndNode->myDir[ 1 ].X() <<" "<<bndNode->myDir[ 1 ].Y()<<endl;
1794 //cout << "prevNode UV: " << prevNode1->myUV.X()<<" "<<prevNode1->myUV.Y()<<
1795 //" par: " << prevPar << endl;
1796 // cout <<" tgt: " << tgt.X()<<" "<<tgt.Y()<<endl;
1797 //cout << " DIR: "<< dir.X() <<" "<<dir.Y()<<endl;
1799 //cout << "____2next______"<<endl<< "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
1800 gp_XY & uv1 = prevNode1->myUV;
1801 gp_XY & uv2 = prevNode2->myUV;
1802 // dir = ( uv2 - uv1 );
1803 // double len = dir.Modulus();
1804 // if ( len > DBL_MIN )
1805 // dir /= len * 0.5;
1806 double r = node->myRatio[ iDir ];
1807 newUV += uv1 * ( 1 - r ) + uv2 * r;
1810 newUV += prevNode1->myUV + dir * step[ iDir ];
1813 prevN[ iDir ] = prevNode1;
1819 //cout << "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
1821 // check if a quadrangle is not distorted
1823 //int crit = ( nbPrev == 4 ) ? FIX_OLD : CHECK_NEW_IN;
1824 if ( !checkQuads( node, newUV, reversed, FIX_OLD, step[0] + step[1] )) {
1825 //cout <<" newUV: " << node->myUV.X() << " "<<node->myUV.Y() << " nbPrev: "<<nbPrev<< endl;
1826 // cout << "_FIX_INIT_ fixedUV: " << newUV.X() << " "<<newUV.Y() << endl;
1830 internNodes.push_back( node );
1835 static int maxNbIter = 100;
1836 #ifdef DEB_COMPUVBYELASTICISOLINES
1838 bool useNbMoveNode = 0;
1839 static int maxNbNodeMove = 100;
1842 if ( !useNbMoveNode )
1843 maxNbIter = ( maxNbIter < 0 ) ? 100 : -1;
1848 if ( !needIteration) break;
1849 #ifdef DEB_COMPUVBYELASTICISOLINES
1850 if ( nbIter >= maxNbIter ) break;
1853 list < TIsoNode* >::iterator nIt = internNodes.begin();
1854 for ( ; nIt != internNodes.end(); nIt++ ) {
1855 #ifdef DEB_COMPUVBYELASTICISOLINES
1857 cout << nbNodeMove <<" =================================================="<<endl;
1859 TIsoNode * node = *nIt;
1863 for ( iDir = 0; iDir < 2; iDir++ )
1865 gp_XY & uv1 = node->GetNext( iDir, 0 )->myUV;
1866 gp_XY & uv2 = node->GetNext( iDir, 1 )->myUV;
1867 double r = node->myRatio[ iDir ];
1868 loc[ iDir ] = uv1 * ( 1 - r ) + uv2 * r;
1869 // line[ iDir ].SetLocation( loc[ iDir ] );
1870 // line[ iDir ].SetDirection( node->myDir[ iDir ] );
1873 double locR[2] = { 0, 0 };
1874 for ( iDir = 0; iDir < 2; iDir++ )
1876 const int iCoord = 2 - iDir; // coord changing along an isoline
1877 TIsoNode* bndNode1 = node->GetBoundaryNode( iDir, 0 );
1878 TIsoNode* bndNode2 = node->GetBoundaryNode( iDir, 1 );
1879 double par1 = bndNode1->myInitUV.Coord( iCoord );
1880 double par2 = node->myInitUV.Coord( iCoord );
1881 double par3 = bndNode2->myInitUV.Coord( iCoord );
1882 double r = ( par2 - par1 ) / ( par3 - par1 );
1883 r = Abs ( r - 0.5 ) * 2.0; // [0,1] - distance from the middle
1884 locR[ iDir ] = ( 1 - r * r ) * 0.25;
1886 //locR[0] = locR[1] = 0.25;
1887 // intersect the 2 lines and move a node
1888 //IntAna2d_AnaIntersection inter( line[0], line[1] );
1889 if ( /*inter.IsDone() && inter.NbPoints() ==*/ 1 )
1891 // double intR = 1 - locR[0] - locR[1];
1892 // gp_XY newUV = inter.Point(1).Value().XY();
1893 // if ( !checkQuads( node, newUV, reversed, CHECK_NEW_IN ))
1894 // newUV = ( locR[0] * loc[0] + locR[1] * loc[1] ) / ( 1 - intR );
1896 // newUV = intR * newUV + locR[0] * loc[0] + locR[1] * loc[1];
1897 gp_XY newUV = 0.5 * ( loc[0] + loc[1] );
1898 // avoid parallel isolines intersection
1899 checkQuads( node, newUV, reversed );
1901 maxMove = Max( maxMove, ( newUV - node->myUV ).SquareModulus());
1903 } // intersection found
1904 #ifdef DEB_COMPUVBYELASTICISOLINES
1905 if (useNbMoveNode && ++nbNodeMove >= maxNbNodeMove ) break;
1907 } // loop on internal nodes
1908 #ifdef DEB_COMPUVBYELASTICISOLINES
1909 if (useNbMoveNode && nbNodeMove >= maxNbNodeMove ) break;
1911 } while ( maxMove > 1e-8 && nbIter++ < maxNbIter );
1913 MESSAGE( "compUVByElasticIsolines(): Nb iterations " << nbIter << " dist: " << sqrt( maxMove ));
1915 if ( nbIter >= maxNbIter && sqrt(maxMove) > minUvSize * 0.05 ) {
1916 MESSAGE( "compUVByElasticIsolines() failed: "<<sqrt(maxMove)<<">"<<minUvSize * 0.05);
1917 #ifndef DEB_COMPUVBYELASTICISOLINES
1922 // Set computed UV to points
1924 for ( pIt = thePntToCompute.begin(); pIt != thePntToCompute.end(); pIt++ ) {
1925 TPoint* point = *pIt;
1926 //gp_XY oldUV = point->myUV;
1927 double minDist = DBL_MAX;
1928 list < TIsoNode >::iterator nIt = nodes.begin();
1929 for ( ; nIt != nodes.end(); nIt++ ) {
1930 double dist = ( (*nIt).myInitUV - point->myInitUV ).SquareModulus();
1931 if ( dist < minDist ) {
1933 point->myUV = (*nIt).myUV;
1943 //=======================================================================
1944 //function : setFirstEdge
1945 //purpose : choose the best first edge of theWire; return the summary distance
1946 // between point UV computed by isolines intersection and
1947 // eventual UV got from edge p-curves
1948 //=======================================================================
1950 //#define DBG_SETFIRSTEDGE
1951 double SMESH_Pattern::setFirstEdge (list< TopoDS_Edge > & theWire, int theFirstEdgeID)
1953 int iE, nbEdges = theWire.size();
1957 // Transform UVs computed by iso to fit bnd box of a wire
1959 // max nb of points on an edge
1961 int eID = theFirstEdgeID;
1962 for ( iE = 0; iE < nbEdges; iE++ )
1963 maxNbPnt = Max ( maxNbPnt, getShapePoints( eID++ ).size() );
1965 // compute bnd boxes
1966 TopoDS_Face face = TopoDS::Face( myShape );
1967 Bnd_Box2d bndBox, eBndBox;
1968 eID = theFirstEdgeID;
1969 list< TopoDS_Edge >::iterator eIt;
1970 list< TPoint* >::iterator pIt;
1971 for ( eIt = theWire.begin(); eIt != theWire.end(); eIt++ )
1973 // UV by isos stored in TPoint.myXYZ
1974 list< TPoint* > & ePoints = getShapePoints( eID++ );
1975 for ( pIt = ePoints.begin(); pIt != ePoints.end(); pIt++ ) {
1977 bndBox.Add( gp_Pnt2d( p->myXYZ.X(), p->myXYZ.Y() ));
1979 // UV by an edge p-curve
1981 Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface( *eIt, face, f, l );
1982 double dU = ( l - f ) / ( maxNbPnt - 1 );
1983 for ( int i = 0; i < maxNbPnt; i++ )
1984 eBndBox.Add( C2d->Value( f + i * dU ));
1987 // transform UVs by isos
1988 double minPar[2], maxPar[2], eMinPar[2], eMaxPar[2];
1989 bndBox.Get( minPar[0], minPar[1], maxPar[0], maxPar[1] );
1990 eBndBox.Get( eMinPar[0], eMinPar[1], eMaxPar[0], eMaxPar[1] );
1991 #ifdef DBG_SETFIRSTEDGE
1992 cout << "EDGES: X: " << eMinPar[0] << " - " << eMaxPar[0] << " Y: "
1993 << eMinPar[1] << " - " << eMaxPar[1] << endl;
1995 for ( int iC = 1, i = 0; i < 2; iC++, i++ ) // loop on 2 coordinates
1997 double dMin = eMinPar[i] - minPar[i];
1998 double dMax = eMaxPar[i] - maxPar[i];
1999 double dPar = maxPar[i] - minPar[i];
2000 eID = theFirstEdgeID;
2001 for ( iE = 0; iE < nbEdges; iE++ ) // loop on edges of a boundary
2003 list< TPoint* > & ePoints = getShapePoints( eID++ );
2004 for ( pIt = ++ePoints.begin(); pIt != ePoints.end(); pIt++ ) // loop on edge points
2006 double par = (*pIt)->myXYZ.Coord( iC );
2007 double r = ( par - minPar[i] ) / dPar;
2008 par += ( 1 - r ) * dMin + r * dMax;
2009 (*pIt)->myXYZ.SetCoord( iC, par );
2015 double minDist = DBL_MAX;
2016 for ( iE = 0 ; iE < nbEdges; iE++ )
2018 #ifdef DBG_SETFIRSTEDGE
2019 cout << " VARIANT " << iE << endl;
2021 // evaluate the distance between UV computed by the 2 methods:
2022 // by isos intersection ( myXYZ ) and by edge p-curves ( myUV )
2024 int eID = theFirstEdgeID;
2025 for ( eIt = theWire.begin(); eIt != theWire.end(); eIt++ )
2027 list< TPoint* > & ePoints = getShapePoints( eID++ );
2028 computeUVOnEdge( *eIt, ePoints );
2029 for ( pIt = ++ePoints.begin(); pIt != ePoints.end(); pIt++ ) {
2031 dist += ( p->myUV - gp_XY( p->myXYZ.X(), p->myXYZ.Y() )).SquareModulus();
2032 #ifdef DBG_SETFIRSTEDGE
2033 cout << " ISO : ( " << p->myXYZ.X() << ", "<< p->myXYZ.Y() << " ) PCURVE : ( " <<
2034 p->myUV.X() << ", " << p->myUV.Y() << ") " << endl;
2038 #ifdef DBG_SETFIRSTEDGE
2039 cout << "dist -- " << dist << endl;
2041 if ( dist < minDist ) {
2043 eBest = theWire.front();
2045 // check variant with another first edge
2046 theWire.splice( theWire.begin(), theWire, --theWire.end(), theWire.end() );
2048 // put the best first edge to the theWire front
2049 if ( eBest != theWire.front() ) {
2050 eIt = find ( theWire.begin(), theWire.end(), eBest );
2051 theWire.splice( theWire.begin(), theWire, eIt, theWire.end() );
2057 //=======================================================================
2058 //function : sortSameSizeWires
2059 //purpose : sort wires in theWireList from theFromWire until theToWire,
2060 // the wires are set in the order to correspond to the order
2061 // of boundaries; after sorting, edges in the wires are put
2062 // in a good order, point UVs on edges are computed and points
2063 // are appended to theEdgesPointsList
2064 //=======================================================================
2066 bool SMESH_Pattern::sortSameSizeWires (TListOfEdgesList & theWireList,
2067 const TListOfEdgesList::iterator& theFromWire,
2068 const TListOfEdgesList::iterator& theToWire,
2069 const int theFirstEdgeID,
2070 list< list< TPoint* > >& theEdgesPointsList )
2072 TopoDS_Face F = TopoDS::Face( myShape );
2073 int iW, nbWires = 0;
2074 TListOfEdgesList::iterator wlIt = theFromWire;
2075 while ( wlIt++ != theToWire )
2078 // Recompute key-point UVs by isolines intersection,
2079 // compute CG of key-points for each wire and bnd boxes of GCs
2082 gp_XY orig( gp::Origin2d().XY() );
2083 vector< gp_XY > vGcVec( nbWires, orig ), gcVec( nbWires, orig );
2084 Bnd_Box2d bndBox, vBndBox;
2085 int eID = theFirstEdgeID;
2086 list< TopoDS_Edge >::iterator eIt;
2087 for ( iW = 0, wlIt = theFromWire; wlIt != theToWire; wlIt++, iW++ )
2089 list< TopoDS_Edge > & wire = *wlIt;
2090 for ( eIt = wire.begin(); eIt != wire.end(); eIt++ )
2092 list< TPoint* > & ePoints = getShapePoints( eID++ );
2093 TPoint* p = ePoints.front();
2094 if ( !compUVByIsoIntersection( theEdgesPointsList, p->myInitUV, p->myUV, aBool )) {
2095 MESSAGE("cant sortSameSizeWires()");
2098 gcVec[iW] += p->myUV;
2099 bndBox.Add( gp_Pnt2d( p->myUV ));
2100 TopoDS_Vertex V = TopExp::FirstVertex( *eIt, true );
2101 gp_Pnt2d vXY = BRep_Tool::Parameters( V, F );
2102 vGcVec[iW] += vXY.XY();
2104 // keep the computed UV to compare against by setFirstEdge()
2105 p->myXYZ.SetCoord( p->myUV.X(), p->myUV.Y(), 0. );
2107 gcVec[iW] /= nbWires;
2108 vGcVec[iW] /= nbWires;
2109 // cout << " Wire " << iW << " iso: " << gcVec[iW].X() << " " << gcVec[iW].Y() << endl <<
2110 // " \t vertex: " << vGcVec[iW].X() << " " << vGcVec[iW].Y() << endl;
2113 // Transform GCs computed by isos to fit in bnd box of GCs by vertices
2115 double minPar[2], maxPar[2], vMinPar[2], vMaxPar[2];
2116 bndBox.Get( minPar[0], minPar[1], maxPar[0], maxPar[1] );
2117 vBndBox.Get( vMinPar[0], vMinPar[1], vMaxPar[0], vMaxPar[1] );
2118 for ( int iC = 1, i = 0; i < 2; iC++, i++ ) // loop on 2 coordinates
2120 double dMin = vMinPar[i] - minPar[i];
2121 double dMax = vMaxPar[i] - maxPar[i];
2122 double dPar = maxPar[i] - minPar[i];
2123 if ( Abs( dPar ) <= DBL_MIN )
2125 for ( iW = 0; iW < nbWires; iW++ ) { // loop on GCs of wires
2126 double par = gcVec[iW].Coord( iC );
2127 double r = ( par - minPar[i] ) / dPar;
2128 par += ( 1 - r ) * dMin + r * dMax;
2129 gcVec[iW].SetCoord( iC, par );
2133 // Define boundary - wire correspondence by GC closeness
2135 TListOfEdgesList tmpWList;
2136 tmpWList.splice( tmpWList.end(), theWireList, theFromWire, theToWire );
2137 typedef map< int, TListOfEdgesList::iterator > TIntWirePosMap;
2138 TIntWirePosMap bndIndWirePosMap;
2139 vector< bool > bndFound( nbWires, false );
2140 for ( iW = 0, wlIt = tmpWList.begin(); iW < nbWires; iW++, wlIt++ )
2142 // cout << " TRSF Wire " << iW << " iso: " << gcVec[iW].X() << " " << gcVec[iW].Y() << endl <<
2143 // " \t vertex: " << vGcVec[iW].X() << " " << vGcVec[iW].Y() << endl;
2144 double minDist = DBL_MAX;
2145 gp_XY & wGc = vGcVec[ iW ];
2147 for ( int iB = 0; iB < nbWires; iB++ ) {
2148 if ( bndFound[ iB ] ) continue;
2149 double dist = ( wGc - gcVec[ iB ] ).SquareModulus();
2150 if ( dist < minDist ) {
2155 bndFound[ bIndex ] = true;
2156 bndIndWirePosMap.insert( TIntWirePosMap::value_type( bIndex, wlIt ));
2161 TIntWirePosMap::iterator bIndWPosIt = bndIndWirePosMap.begin();
2162 eID = theFirstEdgeID;
2163 for ( ; bIndWPosIt != bndIndWirePosMap.end(); bIndWPosIt++ )
2165 TListOfEdgesList::iterator wirePos = (*bIndWPosIt).second;
2166 list < TopoDS_Edge > & wire = ( *wirePos );
2168 // choose the best first edge of a wire
2169 setFirstEdge( wire, eID );
2171 // compute eventual UV and fill theEdgesPointsList
2172 theEdgesPointsList.push_back( list< TPoint* >() );
2173 list< TPoint* > & edgesPoints = theEdgesPointsList.back();
2174 for ( eIt = wire.begin(); eIt != wire.end(); eIt++ )
2176 list< TPoint* > & ePoints = getShapePoints( eID++ );
2177 computeUVOnEdge( *eIt, ePoints );
2178 edgesPoints.insert( edgesPoints.end(), ePoints.begin(), (--ePoints.end()));
2180 // put wire back to theWireList
2182 theWireList.splice( theToWire, tmpWList, wlIt, wirePos );
2188 //=======================================================================
2190 //purpose : Compute nodes coordinates applying
2191 // the loaded pattern to <theFace>. The first key-point
2192 // will be mapped into <theVertexOnKeyPoint1>
2193 //=======================================================================
2195 bool SMESH_Pattern::Apply (const TopoDS_Face& theFace,
2196 const TopoDS_Vertex& theVertexOnKeyPoint1,
2197 const bool theReverse)
2199 MESSAGE(" ::Apply(face) " );
2200 TopoDS_Face face = theReverse ? TopoDS::Face( theFace.Reversed() ) : theFace;
2201 if ( !setShapeToMesh( face ))
2204 // find points on edges, it fills myNbKeyPntInBoundary
2205 if ( !findBoundaryPoints() )
2208 // Define the edges order so that the first edge starts at
2209 // theVertexOnKeyPoint1
2211 list< TopoDS_Edge > eList;
2212 list< int > nbVertexInWires;
2213 int nbWires = getOrderedEdges( face, theVertexOnKeyPoint1, eList, nbVertexInWires);
2214 if ( !theVertexOnKeyPoint1.IsSame( TopExp::FirstVertex( eList.front(), true )))
2216 MESSAGE( " theVertexOnKeyPoint1 not found in the outer wire ");
2217 return setErrorCode( ERR_APPLF_BAD_VERTEX );
2219 // check nb wires and edges
2220 list< int > l1 = myNbKeyPntInBoundary, l2 = nbVertexInWires;
2221 l1.sort(); l2.sort();
2224 MESSAGE( "Wrong nb vertices in wires" );
2225 return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
2228 // here shapes get IDs, for the outer wire IDs are OK
2229 list<TopoDS_Edge>::iterator elIt = eList.begin();
2230 for ( ; elIt != eList.end(); elIt++ ) {
2231 myShapeIDMap.Add( TopExp::FirstVertex( *elIt, true ));
2232 if ( BRep_Tool::IsClosed( *elIt, theFace ) )
2233 myShapeIDMap.Add( TopExp::LastVertex( *elIt, true ));
2235 int nbVertices = myShapeIDMap.Extent();
2237 //int nbSeamShapes = 0; // count twice seam edge and its vertices
2238 for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
2239 myShapeIDMap.Add( *elIt );
2241 myShapeIDMap.Add( face );
2243 if ( myShapeIDToPointsMap.size() != myShapeIDMap.Extent()/* + nbSeamShapes*/ ) {
2244 MESSAGE( myShapeIDToPointsMap.size() <<" != " << myShapeIDMap.Extent());
2245 return setErrorCode( ERR_APPLF_INTERNAL_EEROR );
2248 // points on edges to be used for UV computation of in-face points
2249 list< list< TPoint* > > edgesPointsList;
2250 edgesPointsList.push_back( list< TPoint* >() );
2251 list< TPoint* > * edgesPoints = & edgesPointsList.back();
2252 list< TPoint* >::iterator pIt;
2254 // compute UV of points on the outer wire
2255 int iE, nbEdgesInOuterWire = nbVertexInWires.front();
2256 for (iE = 0, elIt = eList.begin();
2257 iE < nbEdgesInOuterWire && elIt != eList.end();
2260 list< TPoint* > & ePoints = getShapePoints( *elIt );
2262 computeUVOnEdge( *elIt, ePoints );
2263 // collect on-edge points (excluding the last one)
2264 edgesPoints->insert( edgesPoints->end(), ePoints.begin(), --ePoints.end());
2267 // If there are several wires, define the order of edges of inner wires:
2268 // compute UV of inner edge-points using 2 methods: the one for in-face points
2269 // and the one for on-edge points and then choose the best edge order
2270 // by the best correspondance of the 2 results
2273 // compute UV of inner edge-points using the method for in-face points
2274 // and devide eList into a list of separate wires
2276 list< list< TopoDS_Edge > > wireList;
2277 list<TopoDS_Edge>::iterator eIt = elIt;
2278 list<int>::iterator nbEIt = nbVertexInWires.begin();
2279 for ( nbEIt++; nbEIt != nbVertexInWires.end(); nbEIt++ )
2281 int nbEdges = *nbEIt;
2282 wireList.push_back( list< TopoDS_Edge >() );
2283 list< TopoDS_Edge > & wire = wireList.back();
2284 for ( iE = 0 ; iE < nbEdges; eIt++, iE++ )
2286 list< TPoint* > & ePoints = getShapePoints( *eIt );
2287 pIt = ePoints.begin();
2288 for ( pIt++; pIt != ePoints.end(); pIt++ ) {
2290 if ( !compUVByIsoIntersection( edgesPointsList, p->myInitUV, p->myUV, aBool )) {
2291 MESSAGE("cant Apply(face)");
2294 // keep the computed UV to compare against by setFirstEdge()
2295 p->myXYZ.SetCoord( p->myUV.X(), p->myUV.Y(), 0. );
2297 wire.push_back( *eIt );
2300 // remove inner edges from eList
2301 eList.erase( elIt, eList.end() );
2303 // sort wireList by nb edges in a wire
2304 sortBySize< TopoDS_Edge > ( wireList );
2306 // an ID of the first edge of a boundary
2307 int id1 = nbVertices + nbEdgesInOuterWire + 1;
2308 // if ( nbSeamShapes > 0 )
2309 // id1 += 2; // 2 vertices more
2311 // find points - edge correspondence for wires of unique size,
2312 // edge order within a wire should be defined only
2314 list< list< TopoDS_Edge > >::iterator wlIt = wireList.begin();
2315 while ( wlIt != wireList.end() )
2317 list< TopoDS_Edge >& wire = (*wlIt);
2318 int nbEdges = wire.size();
2320 if ( wlIt == wireList.end() || (*wlIt).size() != nbEdges ) // a unique size wire
2322 // choose the best first edge of a wire
2323 setFirstEdge( wire, id1 );
2325 // compute eventual UV and collect on-edge points
2326 edgesPointsList.push_back( list< TPoint* >() );
2327 edgesPoints = & edgesPointsList.back();
2329 for ( eIt = wire.begin(); eIt != wire.end(); eIt++ )
2331 list< TPoint* > & ePoints = getShapePoints( eID++ );
2332 computeUVOnEdge( *eIt, ePoints );
2333 edgesPoints->insert( edgesPoints->end(), ePoints.begin(), (--ePoints.end()));
2339 // find boundary - wire correspondence for several wires of same size
2341 id1 = nbVertices + nbEdgesInOuterWire + 1;
2342 wlIt = wireList.begin();
2343 while ( wlIt != wireList.end() )
2345 int nbSameSize = 0, nbEdges = (*wlIt).size();
2346 list< list< TopoDS_Edge > >::iterator wlIt2 = wlIt;
2348 while ( wlIt2 != wireList.end() && (*wlIt2).size() == nbEdges ) { // a same size wire
2352 if ( nbSameSize > 0 )
2353 if (!sortSameSizeWires(wireList, wlIt, wlIt2, id1, edgesPointsList))
2356 id1 += nbEdges * ( nbSameSize + 1 );
2359 // add well-ordered edges to eList
2361 for ( wlIt = wireList.begin(); wlIt != wireList.end(); wlIt++ )
2363 list< TopoDS_Edge >& wire = (*wlIt);
2364 eList.splice( eList.end(), wire, wire.begin(), wire.end() );
2367 // re-fill myShapeIDMap - all shapes get good IDs
2369 myShapeIDMap.Clear();
2370 for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
2371 myShapeIDMap.Add( TopExp::FirstVertex( *elIt, true ));
2372 for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
2373 myShapeIDMap.Add( *elIt );
2374 myShapeIDMap.Add( face );
2376 } // there are inner wires
2378 // Compute XYZ of on-edge points
2380 TopLoc_Location loc;
2381 for ( iE = nbVertices + 1, elIt = eList.begin(); elIt != eList.end(); elIt++ )
2384 Handle(Geom_Curve) C3d = BRep_Tool::Curve( *elIt, loc, f, l );
2385 const gp_Trsf & aTrsf = loc.Transformation();
2386 list< TPoint* > & ePoints = getShapePoints( iE++ );
2387 pIt = ePoints.begin();
2388 for ( pIt++; pIt != ePoints.end(); pIt++ )
2390 TPoint* point = *pIt;
2391 point->myXYZ = C3d->Value( point->myU );
2392 if ( !loc.IsIdentity() )
2393 aTrsf.Transforms( point->myXYZ.ChangeCoord() );
2397 // Compute UV and XYZ of in-face points
2399 // try to use a simple algo
2400 list< TPoint* > & fPoints = getShapePoints( face );
2401 bool isDeformed = false;
2402 for ( pIt = fPoints.begin(); !isDeformed && pIt != fPoints.end(); pIt++ )
2403 if ( !compUVByIsoIntersection( edgesPointsList, (*pIt)->myInitUV,
2404 (*pIt)->myUV, isDeformed )) {
2405 MESSAGE("cant Apply(face)");
2408 // try to use a complex algo if it is a difficult case
2409 if ( isDeformed && !compUVByElasticIsolines( edgesPointsList, fPoints ))
2411 for ( ; pIt != fPoints.end(); pIt++ ) // continue with the simple algo
2412 if ( !compUVByIsoIntersection( edgesPointsList, (*pIt)->myInitUV,
2413 (*pIt)->myUV, isDeformed )) {
2414 MESSAGE("cant Apply(face)");
2419 Handle(Geom_Surface) aSurface = BRep_Tool::Surface( face, loc );
2420 const gp_Trsf & aTrsf = loc.Transformation();
2421 for ( pIt = fPoints.begin(); pIt != fPoints.end(); pIt++ )
2423 TPoint * point = *pIt;
2424 point->myXYZ = aSurface->Value( point->myUV.X(), point->myUV.Y() );
2425 if ( !loc.IsIdentity() )
2426 aTrsf.Transforms( point->myXYZ.ChangeCoord() );
2429 myIsComputed = true;
2431 return setErrorCode( ERR_OK );
2434 // =========================================================
2435 // class calculating coordinates of 3D points by normalized
2436 // parameters inside the block and vice versa
2437 // =========================================================
2439 class TBlock: public math_FunctionSetWithDerivatives
2442 enum TBlockShapeID { // ids of the block sub-shapes
2443 ID_V000 = 1, ID_V100, ID_V010, ID_V110, ID_V001, ID_V101, ID_V011, ID_V111,
2445 ID_Ex00, ID_Ex10, ID_Ex01, ID_Ex11,
2446 ID_E0y0, ID_E1y0, ID_E0y1, ID_E1y1,
2447 ID_E00z, ID_E10z, ID_E01z, ID_E11z,
2449 ID_Fxy0, ID_Fxy1, ID_Fx0z, ID_Fx1z, ID_F0yz, ID_F1yz,
2454 bool IsVertexID( int theShapeID )
2455 { return ( theShapeID >= ID_V000 && theShapeID <= ID_V111 ); }
2456 static inline bool IsEdgeID( int theShapeID )
2457 { return ( theShapeID >= ID_Ex00 && theShapeID <= ID_E11z ); }
2458 static inline bool IsFaceID( int theShapeID )
2459 { return ( theShapeID >= ID_Fxy0 && theShapeID <= ID_F1yz ); }
2462 TBlock (const TopoDS_Shell& theBlock):
2463 myShell( theBlock ), myNbIterations(0), mySumDist(0.) {}
2465 bool LoadBlockShapes(const TopoDS_Vertex& theVertex000,
2466 const TopoDS_Vertex& theVertex001,
2467 // TopTools_IndexedMapOfShape& theShapeIDMap
2468 TopTools_IndexedMapOfOrientedShape& theShapeIDMap );
2469 // add sub-shapes of theBlock to theShapeIDMap so that they get
2470 // IDs acoording to enum TBlockShapeID
2472 static int GetShapeIDByParams ( const gp_XYZ& theParams );
2473 // define an id of the block sub-shape by point parameters
2475 bool VertexPoint( const int theVertexID, gp_XYZ& thePoint ) const {
2476 if ( !IsVertexID( theVertexID )) return false;
2477 thePoint = myPnt[ theVertexID - ID_V000 ]; return true;
2479 // return vertex coordinates
2481 bool EdgePoint( const int theEdgeID, const gp_XYZ& theParams, gp_XYZ& thePoint ) const {
2482 if ( !IsEdgeID( theEdgeID )) return false;
2483 thePoint = myEdge[ theEdgeID - ID_Ex00 ].Point( theParams ); return true;
2485 // return coordinates of a point on edge
2487 bool FacePoint( const int theFaceID, const gp_XYZ& theParams, gp_XYZ& thePoint ) const {
2488 if ( !IsFaceID ( theFaceID )) return false;
2489 thePoint = myFace[ theFaceID - ID_Fxy0 ].Point( theParams ); return true;
2491 // return coordinates of a point on face
2493 bool ShellPoint( const gp_XYZ& theParams, gp_XYZ& thePoint ) const;
2494 // return coordinates of a point in shell
2496 bool ComputeParameters (const gp_Pnt& thePoint,
2498 const int theShapeID = ID_Shell);
2499 // compute point parameters in the block
2501 static void GetFaceEdgesIDs (const int faceID, vector< int >& edgeVec );
2502 // return edges IDs of a face in the order u0, u1, 0v, 1v
2504 static int GetCoordIndOnEdge (const int theEdgeID)
2505 { return (theEdgeID < ID_E0y0) ? 1 : (theEdgeID < ID_E00z) ? 2 : 3; }
2506 // return an index of a coordinate which varies along the edge
2508 static double* GetShapeCoef (const int theShapeID);
2509 // for theShapeID( TBlockShapeID ), returns 3 coefficients used
2510 // to compute an addition of an on-theShape point to coordinates
2511 // of an in-shell point. If an in-shell point has parameters (Px,Py,Pz),
2512 // then the addition of a point P is computed as P*kx*ky*kz and ki is
2513 // defined by the returned coef like this:
2514 // ki = (coef[i] == 0) ? 1 : (coef[i] < 0) ? 1 - Pi : Pi
2516 static bool IsForwardEdge (const TopoDS_Edge & theEdge,
2517 //TopTools_IndexedMapOfShape& theShapeIDMap
2518 TopTools_IndexedMapOfOrientedShape& theShapeIDMap) {
2519 int v1ID = theShapeIDMap.FindIndex( TopExp::FirstVertex( theEdge ).Oriented( TopAbs_FORWARD ));
2520 int v2ID = theShapeIDMap.FindIndex( TopExp::LastVertex( theEdge ).Oriented( TopAbs_FORWARD ));
2521 return ( v1ID < v2ID );
2523 // Return true if an in-block parameter increases along theEdge curve
2525 static void Swap(double& a, double& b) { double tmp = a; a = b; b = tmp; }
2527 // methods of math_FunctionSetWithDerivatives
2528 Standard_Integer NbVariables() const;
2529 Standard_Integer NbEquations() const;
2530 Standard_Boolean Value(const math_Vector& X,math_Vector& F) ;
2531 Standard_Boolean Derivatives(const math_Vector& X,math_Matrix& D) ;
2532 Standard_Boolean Values(const math_Vector& X,math_Vector& F,math_Matrix& D) ;
2533 Standard_Integer GetStateNumber ();
2535 static ostream& DumpShapeID (const int theBlockShapeID, ostream& stream);
2536 // DEBUG: dump an id of a block sub-shape
2544 Handle(Geom_Curve) myC3d;
2546 double GetU( const gp_XYZ& theParams ) const;
2547 gp_XYZ Point( const gp_XYZ& theParams ) const;
2551 // 4 edges in the order u0, u1, 0v, 1v
2552 int myCoordInd[ 4 ];
2553 double myFirst [ 4 ];
2554 double myLast [ 4 ];
2555 Handle(Geom2d_Curve) myC2d [ 4 ];
2556 // 4 corner points in the order 00, 10, 11, 01
2557 gp_XY myCorner [ 4 ];
2559 Handle(Geom_Surface) myS;
2561 gp_XY GetUV( const gp_XYZ& theParams ) const;
2562 gp_XYZ Point( const gp_XYZ& theParams ) const;
2563 int GetUInd() const { return myCoordInd[ 0 ]; }
2564 int GetVInd() const { return myCoordInd[ 2 ]; }
2567 TopoDS_Shell myShell;
2576 // for param computation
2583 gp_XYZ myPoint; // the given point
2584 gp_XYZ myParam; // the best parameters guess
2585 double myValues[ 4 ]; // values computed at myParam
2587 typedef pair<gp_XYZ,gp_XYZ> TxyzPair;
2588 TxyzPair my3x3x3GridNodes[ 27 ];
2589 bool myGridComputed;
2592 //=======================================================================
2594 //purpose : Create a pattern from the mesh built on <theBlock>
2595 //=======================================================================
2597 bool SMESH_Pattern::Load (SMESH_Mesh* theMesh,
2598 const TopoDS_Shell& theBlock)
2600 MESSAGE(" ::Load(volume) " );
2603 SMESHDS_Mesh * aMeshDS = theMesh->GetMeshDS();
2605 // load shapes in myShapeIDMap
2606 TBlock block( theBlock );
2607 TopoDS_Vertex v1, v2;
2608 if ( !block.LoadBlockShapes( v1, v2, myShapeIDMap ))
2609 return setErrorCode( ERR_LOADV_BAD_SHAPE );
2612 int nbNodes = 0, shapeID;
2613 for ( shapeID = 1; shapeID <= myShapeIDMap.Extent(); shapeID++ )
2615 const TopoDS_Shape& S = myShapeIDMap( shapeID );
2616 SMESHDS_SubMesh * aSubMesh = aMeshDS->MeshElements( S );
2618 nbNodes += aSubMesh->NbNodes();
2620 myPoints.resize( nbNodes );
2622 // load U of points on edges
2623 TNodePointIDMap nodePointIDMap;
2625 for ( shapeID = 1; shapeID <= myShapeIDMap.Extent(); shapeID++ )
2627 const TopoDS_Shape& S = myShapeIDMap( shapeID );
2628 list< TPoint* > & shapePoints = getShapePoints( shapeID );
2629 SMESHDS_SubMesh * aSubMesh = aMeshDS->MeshElements( S );
2630 if ( ! aSubMesh ) continue;
2631 SMDS_NodeIteratorPtr nIt = aSubMesh->GetNodes();
2632 if ( !nIt->more() ) continue;
2634 // store a node and a point
2635 while ( nIt->more() ) {
2636 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nIt->next() );
2637 nodePointIDMap.insert( TNodePointIDMap::value_type( node, iPoint ));
2638 if ( block.IsVertexID( shapeID ))
2639 myKeyPointIDs.push_back( iPoint );
2640 TPoint* p = & myPoints[ iPoint++ ];
2641 shapePoints.push_back( p );
2642 p->myXYZ.SetCoord( node->X(), node->Y(), node->Z() );
2643 p->myInitXYZ.SetCoord( 0,0,0 );
2645 list< TPoint* >::iterator pIt = shapePoints.begin();
2648 switch ( S.ShapeType() )
2653 for ( ; pIt != shapePoints.end(); pIt++ ) {
2654 double * coef = block.GetShapeCoef( shapeID );
2655 for ( int iCoord = 1; iCoord <= 3; iCoord++ )
2656 if ( coef[ iCoord - 1] > 0 )
2657 (*pIt)->myInitXYZ.SetCoord( iCoord, 1. );
2659 if ( S.ShapeType() == TopAbs_VERTEX )
2662 const TopoDS_Edge& edge = TopoDS::Edge( S );
2664 BRep_Tool::Range( edge, f, l );
2665 int iCoord = TBlock::GetCoordIndOnEdge( shapeID );
2666 bool isForward = TBlock::IsForwardEdge( edge, myShapeIDMap );
2667 pIt = shapePoints.begin();
2668 nIt = aSubMesh->GetNodes();
2669 for ( ; nIt->more(); pIt++ )
2671 const SMDS_MeshNode* node =
2672 static_cast<const SMDS_MeshNode*>( nIt->next() );
2673 const SMDS_EdgePosition* epos =
2674 static_cast<const SMDS_EdgePosition*>(node->GetPosition().get());
2675 double u = ( epos->GetUParameter() - f ) / ( l - f );
2676 (*pIt)->myInitXYZ.SetCoord( iCoord, isForward ? u : 1 - u );
2681 for ( ; pIt != shapePoints.end(); pIt++ )
2683 if ( !block.ComputeParameters( (*pIt)->myXYZ, (*pIt)->myInitXYZ, shapeID )) {
2684 MESSAGE( "!block.ComputeParameters()" );
2685 return setErrorCode( ERR_LOADV_COMPUTE_PARAMS );
2689 } // loop on block sub-shapes
2693 SMESHDS_SubMesh * aSubMesh = aMeshDS->MeshElements( theBlock );
2696 SMDS_ElemIteratorPtr elemIt = aSubMesh->GetElements();
2697 while ( elemIt->more() ) {
2698 SMDS_ElemIteratorPtr nIt = elemIt->next()->nodesIterator();
2699 myElemPointIDs.push_back( list< int >() );
2700 list< int >& elemPoints = myElemPointIDs.back();
2701 while ( nIt->more() )
2702 elemPoints.push_back( nodePointIDMap[ nIt->next() ]);
2706 myIsBoundaryPointsFound = true;
2708 return setErrorCode( ERR_OK );
2711 //=======================================================================
2713 //purpose : Compute nodes coordinates applying
2714 // the loaded pattern to <theBlock>. The (0,0,0) key-point
2715 // will be mapped into <theVertex000>. The (0,0,1)
2716 // fifth key-point will be mapped into <theVertex001>.
2717 //=======================================================================
2719 bool SMESH_Pattern::Apply (const TopoDS_Shell& theBlock,
2720 const TopoDS_Vertex& theVertex000,
2721 const TopoDS_Vertex& theVertex001)
2723 MESSAGE(" ::Apply(volume) " );
2725 TBlock block( theBlock );
2727 if (!findBoundaryPoints() || // bind ID to points
2728 !setShapeToMesh( theBlock )) // check theBlock is a suitable shape
2731 if (!block.LoadBlockShapes( theVertex000, theVertex001, myShapeIDMap )) // bind ID to shape
2732 return setErrorCode( ERR_APPLV_BAD_SHAPE );
2734 // compute XYZ of points on shapes
2736 for ( int shapeID = 1; shapeID <= myShapeIDMap.Extent(); shapeID++ )
2738 list< TPoint* > & shapePoints = getShapePoints( shapeID );
2739 list< TPoint* >::iterator pIt = shapePoints.begin();
2740 const TopoDS_Shape& S = myShapeIDMap( shapeID );
2741 switch ( S.ShapeType() )
2743 case TopAbs_VERTEX: {
2745 for ( ; pIt != shapePoints.end(); pIt++ )
2746 block.VertexPoint( shapeID, (*pIt)->myXYZ.ChangeCoord() );
2751 for ( ; pIt != shapePoints.end(); pIt++ )
2752 block.EdgePoint( shapeID, (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
2757 for ( ; pIt != shapePoints.end(); pIt++ )
2758 block.FacePoint( shapeID, (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
2762 for ( ; pIt != shapePoints.end(); pIt++ )
2763 block.ShellPoint( (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
2765 } // loop on block sub-shapes
2767 myIsComputed = true;
2769 return setErrorCode( ERR_OK );
2772 //=======================================================================
2773 //function : MakeMesh
2774 //purpose : Create nodes and elements in <theMesh> using nodes
2775 // coordinates computed by either of Apply...() methods
2776 //=======================================================================
2778 bool SMESH_Pattern::MakeMesh(SMESH_Mesh* theMesh)
2780 MESSAGE(" ::MakeMesh() " );
2781 if ( !myIsComputed )
2782 return setErrorCode( ERR_MAKEM_NOT_COMPUTED );
2784 SMESHDS_Mesh* aMeshDS = theMesh->GetMeshDS();
2786 // clear elements and nodes existing on myShape
2787 SMESH_subMesh * aSubMesh = theMesh->GetSubMeshContaining( myShape );
2788 SMESHDS_SubMesh * aSubMeshDS = aMeshDS->MeshElements( myShape );
2790 aSubMesh->ComputeStateEngine( SMESH_subMesh::CLEAN );
2791 else if ( aSubMeshDS )
2793 SMDS_ElemIteratorPtr eIt = aSubMeshDS->GetElements();
2794 while ( eIt->more() )
2795 aMeshDS->RemoveElement( eIt->next() );
2796 SMDS_NodeIteratorPtr nIt = aSubMeshDS->GetNodes();
2797 while ( nIt->more() )
2798 aMeshDS->RemoveNode( static_cast<const SMDS_MeshNode*>( nIt->next() ));
2801 // loop on sub-shapes of myShape: create nodes and build point-node map
2802 typedef map< TPoint*, const SMDS_MeshNode* > TPointNodeMap;
2803 TPointNodeMap pointNodeMap;
2804 map< int, list< TPoint* > >::iterator idPointIt = myShapeIDToPointsMap.begin();
2805 for ( ; idPointIt != myShapeIDToPointsMap.end(); idPointIt++ )
2807 const TopoDS_Shape & S = myShapeIDMap( (*idPointIt).first );
2808 list< TPoint* > & points = (*idPointIt).second;
2809 SMESHDS_SubMesh * subMeshDS = aMeshDS->MeshElements( S );
2810 SMESH_subMesh * subMesh = theMesh->GetSubMeshContaining( myShape );
2811 list< TPoint* >::iterator pIt = points.begin();
2812 for ( ; pIt != points.end(); pIt++ )
2814 TPoint* point = *pIt;
2815 if ( pointNodeMap.find( point ) != pointNodeMap.end() )
2817 SMDS_MeshNode* node = aMeshDS->AddNode (point->myXYZ.X(),
2820 pointNodeMap.insert( TPointNodeMap::value_type( point, node ));
2822 switch ( S.ShapeType() ) {
2823 case TopAbs_VERTEX: {
2824 aMeshDS->SetNodeOnVertex( node, TopoDS::Vertex( S ));
2828 aMeshDS->SetNodeOnEdge( node, TopoDS::Edge( S ));
2829 SMDS_EdgePosition* epos =
2830 dynamic_cast<SMDS_EdgePosition *>(node->GetPosition().get());
2831 epos->SetUParameter( point->myU );
2835 aMeshDS->SetNodeOnFace( node, TopoDS::Face( S ));
2836 SMDS_FacePosition* pos =
2837 dynamic_cast<SMDS_FacePosition *>(node->GetPosition().get());
2838 pos->SetUParameter( point->myUV.X() );
2839 pos->SetVParameter( point->myUV.Y() );
2843 aMeshDS->SetNodeInVolume( node, TopoDS::Shell( S ));
2847 // make that SMESH_subMesh::_computeState = COMPUTE_OK
2848 // so that operations with hypotheses will erase the mesh
2851 subMesh->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
2855 list<list< int > >::iterator epIt = myElemPointIDs.begin();
2856 for ( ; epIt != myElemPointIDs.end(); epIt++ )
2858 list< int > & elemPoints = *epIt;
2860 const SMDS_MeshNode* nodes[ 8 ];
2861 list< int >::iterator iIt = elemPoints.begin();
2863 for ( nbNodes = 0; iIt != elemPoints.end(); iIt++ ) {
2864 nodes[ nbNodes++ ] = pointNodeMap[ & myPoints[ *iIt ]];
2867 const SMDS_MeshElement* elem = 0;
2869 switch ( nbNodes ) {
2871 elem = aMeshDS->AddFace( nodes[0], nodes[1], nodes[2] ); break;
2873 elem = aMeshDS->AddFace( nodes[0], nodes[1], nodes[2], nodes[3] ); break;
2878 switch ( nbNodes ) {
2880 elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3] ); break;
2882 elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3],
2885 elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3],
2886 nodes[4], nodes[5] ); break;
2888 elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3],
2889 nodes[4], nodes[5], nodes[6], nodes[7] ); break;
2894 aMeshDS->SetMeshElementOnShape( elem, myShape );
2897 return setErrorCode( ERR_OK );
2901 //=======================================================================
2902 //function : arrangeBoundaries
2903 //purpose : if there are several wires, arrange boundaryPoints so that
2904 // the outer wire goes first and fix inner wires orientation
2905 // update myKeyPointIDs to correspond to the order of key-points
2906 // in boundaries; sort internal boundaries by the nb of key-points
2907 //=======================================================================
2909 void SMESH_Pattern::arrangeBoundaries (list< list< TPoint* > >& boundaryList)
2911 typedef list< list< TPoint* > >::iterator TListOfListIt;
2912 TListOfListIt bndIt;
2913 list< TPoint* >::iterator pIt;
2915 int nbBoundaries = boundaryList.size();
2916 if ( nbBoundaries > 1 )
2918 // sort boundaries by nb of key-points
2919 if ( nbBoundaries > 2 )
2921 // move boundaries in tmp list
2922 list< list< TPoint* > > tmpList;
2923 tmpList.splice( tmpList.begin(), boundaryList, boundaryList.begin(), boundaryList.end());
2924 // make a map nb-key-points to boundary-position-in-tmpList,
2925 // boundary-positions get ordered in it
2926 typedef map< int, TListOfListIt > TNbKpBndPosMap;
2927 TNbKpBndPosMap nbKpBndPosMap;
2928 bndIt = tmpList.begin();
2929 list< int >::iterator nbKpIt = myNbKeyPntInBoundary.begin();
2930 for ( ; nbKpIt != myNbKeyPntInBoundary.end(); nbKpIt++, bndIt++ ) {
2931 int nb = *nbKpIt * nbBoundaries;
2932 while ( nbKpBndPosMap.find ( nb ) != nbKpBndPosMap.end() )
2934 nbKpBndPosMap.insert( TNbKpBndPosMap::value_type( nb, bndIt ));
2936 // move boundaries back to boundaryList
2937 TNbKpBndPosMap::iterator nbKpBndPosIt = nbKpBndPosMap.begin();
2938 for ( ; nbKpBndPosIt != nbKpBndPosMap.end(); nbKpBndPosIt++ ) {
2939 TListOfListIt & bndPos2 = (*nbKpBndPosIt).second;
2940 TListOfListIt bndPos1 = bndPos2++;
2941 boundaryList.splice( boundaryList.end(), tmpList, bndPos1, bndPos2 );
2945 // Look for the outer boundary: the one with the point with the least X
2946 double leastX = DBL_MAX;
2947 TListOfListIt outerBndPos;
2948 for ( bndIt = boundaryList.begin(); bndIt != boundaryList.end(); bndIt++ )
2950 list< TPoint* >& boundary = (*bndIt);
2951 for ( pIt = boundary.begin(); pIt != boundary.end(); pIt++)
2953 TPoint* point = *pIt;
2954 if ( point->myInitXYZ.X() < leastX ) {
2955 leastX = point->myInitXYZ.X();
2956 outerBndPos = bndIt;
2961 if ( outerBndPos != boundaryList.begin() )
2962 boundaryList.splice( boundaryList.begin(), boundaryList, outerBndPos, ++outerBndPos );
2964 } // if nbBoundaries > 1
2966 // Check boundaries orientation and re-fill myKeyPointIDs
2968 set< TPoint* > keyPointSet;
2969 list< int >::iterator kpIt = myKeyPointIDs.begin();
2970 for ( ; kpIt != myKeyPointIDs.end(); kpIt++ )
2971 keyPointSet.insert( & myPoints[ *kpIt ]);
2972 myKeyPointIDs.clear();
2974 // update myNbKeyPntInBoundary also
2975 list< int >::iterator nbKpIt = myNbKeyPntInBoundary.begin();
2977 for ( bndIt = boundaryList.begin(); bndIt != boundaryList.end(); bndIt++, nbKpIt++ )
2979 // find the point with the least X
2980 double leastX = DBL_MAX;
2981 list< TPoint* >::iterator xpIt;
2982 list< TPoint* >& boundary = (*bndIt);
2983 for ( pIt = boundary.begin(); pIt != boundary.end(); pIt++)
2985 TPoint* point = *pIt;
2986 if ( point->myInitXYZ.X() < leastX ) {
2987 leastX = point->myInitXYZ.X();
2991 // find points next to the point with the least X
2992 TPoint* p = *xpIt, *pPrev, *pNext;
2993 if ( p == boundary.front() )
2994 pPrev = *(++boundary.rbegin());
3000 if ( p == boundary.back() )
3001 pNext = *(++boundary.begin());
3006 // vectors of boundary direction near <p>
3007 gp_Vec2d v1( pPrev->myInitUV, p->myInitUV ), v2( p->myInitUV, pNext->myInitUV );
3008 // rotate vectors counterclockwise
3009 v1.SetCoord( -v1.Y(), v1.X() );
3010 v2.SetCoord( -v2.Y(), v2.X() );
3011 // in-face direction
3012 gp_Vec2d dirInFace = v1 + v2;
3013 // for the outer boundary dirInFace should go to the right
3015 if ( bndIt == boundaryList.begin() ) // outer boundary
3016 reverse = dirInFace.X() < 0;
3018 reverse = dirInFace.X() > 0;
3022 // Put key-point IDs of a well-oriented boundary in myKeyPointIDs
3023 (*nbKpIt) = 0; // count nb of key-points again
3024 pIt = boundary.begin();
3025 for ( ; pIt != boundary.end(); pIt++)
3027 TPoint* point = *pIt;
3028 if ( keyPointSet.find( point ) == keyPointSet.end() )
3030 // find an index of a keypoint
3032 vector< TPoint >::const_iterator pVecIt = myPoints.begin();
3033 for ( ; pVecIt != myPoints.end(); pVecIt++, index++ )
3034 if ( &(*pVecIt) == point )
3036 myKeyPointIDs.push_back( index );
3039 myKeyPointIDs.pop_back(); // remove the first key-point from the back
3042 } // loop on a list of boundaries
3044 ASSERT( myKeyPointIDs.size() == keyPointSet.size() );
3047 //=======================================================================
3048 //function : findBoundaryPoints
3049 //purpose : if loaded from file, find points to map on edges and faces and
3050 // compute their parameters
3051 //=======================================================================
3053 bool SMESH_Pattern::findBoundaryPoints()
3055 if ( myIsBoundaryPointsFound ) return true;
3057 MESSAGE(" findBoundaryPoints() ");
3061 set< TPoint* > pointsInElems;
3063 // Find free links of elements:
3064 // put links of all elements in a set and remove links encountered twice
3066 typedef pair< TPoint*, TPoint*> TLink;
3067 set< TLink > linkSet;
3068 list<list< int > >::iterator epIt = myElemPointIDs.begin();
3069 for ( ; epIt != myElemPointIDs.end(); epIt++ )
3071 list< int > & elemPoints = *epIt;
3072 list< int >::iterator pIt = elemPoints.begin();
3073 int prevP = elemPoints.back();
3074 for ( ; pIt != elemPoints.end(); pIt++ ) {
3075 TPoint* p1 = & myPoints[ prevP ];
3076 TPoint* p2 = & myPoints[ *pIt ];
3077 TLink link(( p1 < p2 ? p1 : p2 ), ( p1 < p2 ? p2 : p1 ));
3078 ASSERT( link.first != link.second );
3079 pair<set< TLink >::iterator,bool> itUniq = linkSet.insert( link );
3080 if ( !itUniq.second )
3081 linkSet.erase( itUniq.first );
3084 pointsInElems.insert( p1 );
3087 // Now linkSet contains only free links,
3088 // find the points order that they have in boundaries
3090 // 1. make a map of key-points
3091 set< TPoint* > keyPointSet;
3092 list< int >::iterator kpIt = myKeyPointIDs.begin();
3093 for ( ; kpIt != myKeyPointIDs.end(); kpIt++ )
3094 keyPointSet.insert( & myPoints[ *kpIt ]);
3096 // 2. chain up boundary points
3097 list< list< TPoint* > > boundaryList;
3098 boundaryList.push_back( list< TPoint* >() );
3099 list< TPoint* > * boundary = & boundaryList.back();
3101 TPoint *point1, *point2, *keypoint1;
3102 kpIt = myKeyPointIDs.begin();
3103 point1 = keypoint1 = & myPoints[ *kpIt++ ];
3104 // loop on free links: look for the next point
3106 set< TLink >::iterator lIt = linkSet.begin();
3107 while ( lIt != linkSet.end() )
3109 if ( (*lIt).first == point1 )
3110 point2 = (*lIt).second;
3111 else if ( (*lIt).second == point1 )
3112 point2 = (*lIt).first;
3117 linkSet.erase( lIt );
3118 lIt = linkSet.begin();
3120 if ( keyPointSet.find( point2 ) == keyPointSet.end() ) // not a key-point
3122 boundary->push_back( point2 );
3124 else // a key-point found
3126 keyPointSet.erase( point2 ); // keyPointSet contains not found key-points only
3128 if ( point2 != keypoint1 ) // its not the boundary end
3130 boundary->push_back( point2 );
3132 else // the boundary end reached
3134 boundary->push_front( keypoint1 );
3135 boundary->push_back( keypoint1 );
3136 myNbKeyPntInBoundary.push_back( iKeyPoint );
3137 if ( keyPointSet.empty() )
3138 break; // all boundaries containing key-points are found
3140 // prepare to search for the next boundary
3141 boundaryList.push_back( list< TPoint* >() );
3142 boundary = & boundaryList.back();
3143 point2 = keypoint1 = (*keyPointSet.begin());
3147 } // loop on the free links set
3149 if ( boundary->empty() ) {
3150 MESSAGE(" a separate key-point");
3151 return setErrorCode( ERR_READ_BAD_KEY_POINT );
3154 // if there are several wires, arrange boundaryPoints so that
3155 // the outer wire goes first and fix inner wires orientation;
3156 // sort myKeyPointIDs to correspond to the order of key-points
3158 arrangeBoundaries( boundaryList );
3160 // Find correspondence shape ID - points,
3161 // compute points parameter on edge
3163 keyPointSet.clear();
3164 for ( kpIt = myKeyPointIDs.begin(); kpIt != myKeyPointIDs.end(); kpIt++ )
3165 keyPointSet.insert( & myPoints[ *kpIt ]);
3167 set< TPoint* > edgePointSet; // to find in-face points
3168 int vertexID = 1; // the first index in TopTools_IndexedMapOfShape
3169 int edgeID = myKeyPointIDs.size() + 1;
3171 list< list< TPoint* > >::iterator bndIt = boundaryList.begin();
3172 for ( ; bndIt != boundaryList.end(); bndIt++ )
3174 boundary = & (*bndIt);
3175 double edgeLength = 0;
3176 list< TPoint* >::iterator pIt = boundary->begin();
3177 getShapePoints( edgeID ).push_back( *pIt );
3178 for ( pIt++; pIt != boundary->end(); pIt++)
3180 list< TPoint* > & edgePoints = getShapePoints( edgeID );
3181 TPoint* prevP = edgePoints.empty() ? 0 : edgePoints.back();
3182 TPoint* point = *pIt;
3183 edgePointSet.insert( point );
3184 if ( keyPointSet.find( point ) == keyPointSet.end() ) // inside-edge point
3186 edgePoints.push_back( point );
3187 edgeLength += ( point->myInitUV - prevP->myInitUV ).Modulus();
3188 point->myInitU = edgeLength;
3192 // treat points on the edge which ends up: compute U [0,1]
3193 edgePoints.push_back( point );
3194 if ( edgePoints.size() > 2 ) {
3195 edgeLength += ( point->myInitUV - prevP->myInitUV ).Modulus();
3196 list< TPoint* >::iterator epIt = edgePoints.begin();
3197 for ( ; epIt != edgePoints.end(); epIt++ )
3198 (*epIt)->myInitU /= edgeLength;
3200 // begin the next edge treatment
3202 getShapePoints( vertexID++ ).push_back( point );
3204 if ( point != boundary->front() )
3205 getShapePoints( edgeID ).push_back( point );
3210 // find in-face points
3211 list< TPoint* > & facePoints = getShapePoints( edgeID );
3212 vector< TPoint >::iterator pVecIt = myPoints.begin();
3213 for ( ; pVecIt != myPoints.end(); pVecIt++ ) {
3214 TPoint* point = &(*pVecIt);
3215 if ( edgePointSet.find( point ) == edgePointSet.end() &&
3216 pointsInElems.find( point ) != pointsInElems.end())
3217 facePoints.push_back( point );
3224 // bind points to shapes according to point parameters
3225 vector< TPoint >::iterator pVecIt = myPoints.begin();
3226 for ( int i = 0; pVecIt != myPoints.end(); pVecIt++, i++ ) {
3227 TPoint* point = &(*pVecIt);
3228 int shapeID = TBlock::GetShapeIDByParams( point->myInitXYZ );
3229 getShapePoints( shapeID ).push_back( point );
3230 // detect key-points
3231 if ( TBlock::IsVertexID( shapeID ))
3232 myKeyPointIDs.push_back( i );
3236 myIsBoundaryPointsFound = true;
3237 return myIsBoundaryPointsFound;
3240 //=======================================================================
3242 //purpose : clear fields
3243 //=======================================================================
3245 void SMESH_Pattern::Clear()
3247 myIsComputed = myIsBoundaryPointsFound = false;
3250 myKeyPointIDs.clear();
3251 myElemPointIDs.clear();
3252 myShapeIDToPointsMap.clear();
3253 myShapeIDMap.Clear();
3255 myNbKeyPntInBoundary.clear();
3258 //=======================================================================
3259 //function : setShapeToMesh
3260 //purpose : set a shape to be meshed. Return True if meshing is possible
3261 //=======================================================================
3263 bool SMESH_Pattern::setShapeToMesh(const TopoDS_Shape& theShape)
3265 if ( !IsLoaded() ) {
3266 MESSAGE( "Pattern not loaded" );
3267 return setErrorCode( ERR_APPL_NOT_LOADED );
3270 TopAbs_ShapeEnum aType = theShape.ShapeType();
3271 bool dimOk = ( myIs2D ? aType == TopAbs_FACE : aType == TopAbs_SHELL );
3273 MESSAGE( "Pattern dimention mismatch" );
3274 return setErrorCode( ERR_APPL_BAD_DIMENTION );
3277 // check if a face is closed
3278 int nbNodeOnSeamEdge = 0;
3280 TopoDS_Face face = TopoDS::Face( theShape );
3281 TopExp_Explorer eExp( theShape, TopAbs_EDGE );
3282 for ( ; eExp.More() && nbNodeOnSeamEdge == 0; eExp.Next() )
3283 if ( BRep_Tool::IsClosed( TopoDS::Edge( eExp.Current() ), face ))
3284 nbNodeOnSeamEdge = 2;
3287 // check nb of vertices
3288 TopTools_IndexedMapOfShape vMap;
3289 TopExp::MapShapes( theShape, TopAbs_VERTEX, vMap );
3290 if ( vMap.Extent() + nbNodeOnSeamEdge != myKeyPointIDs.size() ) {
3291 MESSAGE( myKeyPointIDs.size() << " != " << vMap.Extent() );
3292 return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
3295 myShapeIDMap.Clear();
3300 //=======================================================================
3301 //function : GetMappedPoints
3302 //purpose : Return nodes coordinates computed by Apply() method
3303 //=======================================================================
3305 bool SMESH_Pattern::GetMappedPoints ( list< const gp_XYZ * > & thePoints )
3308 if ( !myIsComputed )
3311 vector< TPoint >::iterator pVecIt = myPoints.begin();
3312 for ( ; pVecIt != myPoints.end(); pVecIt++ )
3313 thePoints.push_back( & (*pVecIt).myXYZ.XYZ() );
3315 return ( thePoints.size() > 0 );
3319 //=======================================================================
3320 //function : GetPoints
3321 //purpose : Return nodes coordinates of the pattern
3322 //=======================================================================
3324 bool SMESH_Pattern::GetPoints ( list< const gp_XYZ * > & thePoints ) const
3331 vector< TPoint >::const_iterator pVecIt = myPoints.begin();
3332 for ( ; pVecIt != myPoints.end(); pVecIt++ )
3333 thePoints.push_back( & (*pVecIt).myInitXYZ );
3335 return ( thePoints.size() > 0 );
3338 //=======================================================================
3339 //function : getShapePoints
3340 //purpose : return list of points located on theShape
3341 //=======================================================================
3343 list< SMESH_Pattern::TPoint* > &
3344 SMESH_Pattern::getShapePoints(const TopoDS_Shape& theShape)
3347 if ( !myShapeIDMap.Contains( theShape ))
3348 aShapeID = myShapeIDMap.Add( theShape );
3350 aShapeID = myShapeIDMap.FindIndex( theShape );
3352 return myShapeIDToPointsMap[ aShapeID ];
3355 //=======================================================================
3356 //function : getShapePoints
3357 //purpose : return list of points located on the shape
3358 //=======================================================================
3360 list< SMESH_Pattern::TPoint* > & SMESH_Pattern::getShapePoints(const int theShapeID)
3362 return myShapeIDToPointsMap[ theShapeID ];
3365 //=======================================================================
3366 //function : DumpPoints
3368 //=======================================================================
3370 void SMESH_Pattern::DumpPoints() const
3373 vector< TPoint >::const_iterator pVecIt = myPoints.begin();
3374 for ( int i = 0; pVecIt != myPoints.end(); pVecIt++, i++ )
3375 cout << i << ": " << *pVecIt;
3379 //=======================================================================
3380 //function : TPoint()
3382 //=======================================================================
3384 SMESH_Pattern::TPoint::TPoint()
3387 myInitXYZ.SetCoord(0,0,0);
3388 myInitUV.SetCoord(0.,0.);
3390 myXYZ.SetCoord(0,0,0);
3391 myUV.SetCoord(0.,0.);
3396 //=======================================================================
3397 //function : operator <<
3399 //=======================================================================
3401 ostream & operator <<(ostream & OS, const SMESH_Pattern::TPoint& p)
3403 gp_XYZ xyz = p.myInitXYZ;
3404 OS << "\tinit( xyz( " << xyz.X() << " " << xyz.Y() << " " << xyz.Z() << " )";
3405 gp_XY xy = p.myInitUV;
3406 OS << " uv( " << xy.X() << " " << xy.Y() << " )";
3407 double u = p.myInitU;
3408 OS << " u( " << u << " )) " << &p << endl;
3409 xyz = p.myXYZ.XYZ();
3410 OS << "\t ( xyz( " << xyz.X() << " " << xyz.Y() << " " << xyz.Z() << " )";
3412 OS << " uv( " << xy.X() << " " << xy.Y() << " )";
3414 OS << " u( " << u << " ))" << endl;
3419 //=======================================================================
3420 //function : TBlock::TEdge::GetU
3422 //=======================================================================
3424 double TBlock::TEdge::GetU( const gp_XYZ& theParams ) const
3426 double u = theParams.Coord( myCoordInd );
3427 return ( 1 - u ) * myFirst + u * myLast;
3430 //=======================================================================
3431 //function : TBlock::TEdge::Point
3433 //=======================================================================
3435 gp_XYZ TBlock::TEdge::Point( const gp_XYZ& theParams ) const
3437 gp_XYZ p = myC3d->Value( GetU( theParams )).XYZ();
3438 if ( myTrsf.Form() != gp_Identity )
3439 myTrsf.Transforms( p );
3443 //=======================================================================
3444 //function : TBlock::TFace::GetUV
3446 //=======================================================================
3448 gp_XY TBlock::TFace::GetUV( const gp_XYZ& theParams ) const
3451 double dU = theParams.Coord( GetUInd() );
3452 double dV = theParams.Coord( GetVInd() );
3453 for ( int iE = 0; iE < 4; iE++ ) // loop on 4 edges
3455 double Ecoef = 0, Vcoef = 0;
3458 Ecoef = ( 1 - dV ); // u0
3459 Vcoef = ( 1 - dU ) * ( 1 - dV ); break; // 00
3462 Vcoef = dU * ( 1 - dV ); break; // 10
3464 Ecoef = ( 1 - dU ); // 0v
3465 Vcoef = dU * dV ; break; // 11
3468 Vcoef = ( 1 - dU ) * dV ; break; // 01
3472 double u = theParams.Coord( myCoordInd[ iE ] );
3473 u = ( 1 - u ) * myFirst[ iE ] + u * myLast[ iE ];
3474 uv += Ecoef * myC2d[ iE ]->Value( u ).XY();
3476 uv -= Vcoef * myCorner[ iE ];
3481 //=======================================================================
3482 //function : TBlock::TFace::Point
3484 //=======================================================================
3486 gp_XYZ TBlock::TFace::Point( const gp_XYZ& theParams ) const
3488 gp_XY uv = GetUV( theParams );
3489 gp_XYZ p = myS->Value( uv.X(), uv.Y() ).XYZ();
3490 if ( myTrsf.Form() != gp_Identity )
3491 myTrsf.Transforms( p );
3495 //=======================================================================
3496 //function : GetShapeCoef
3498 //=======================================================================
3500 double* TBlock::GetShapeCoef (const int theShapeID)
3502 static double shapeCoef[][3] = {
3503 // V000, V100, V010, V110
3504 { -1,-1,-1 }, { 1,-1,-1 }, { -1, 1,-1 }, { 1, 1,-1 },
3505 // V001, V101, V011, V111,
3506 { -1,-1, 1 }, { 1,-1, 1 }, { -1, 1, 1 }, { 1, 1, 1 },
3507 // Ex00, Ex10, Ex01, Ex11,
3508 { 0,-1,-1 }, { 0, 1,-1 }, { 0,-1, 1 }, { 0, 1, 1 },
3509 // E0y0, E1y0, E0y1, E1y1,
3510 { -1, 0,-1 }, { 1, 0,-1 }, { -1, 0, 1 }, { 1, 0, 1 },
3511 // E00z, E10z, E01z, E11z,
3512 { -1,-1, 0 }, { 1,-1, 0 }, { -1, 1, 0 }, { 1, 1, 0 },
3513 // Fxy0, Fxy1, Fx0z, Fx1z, F0yz, F1yz,
3514 { 0, 0,-1 }, { 0, 0, 1 }, { 0,-1, 0 }, { 0, 1, 0 }, { -1, 0, 0 }, { 1, 0, 0 },
3518 if ( theShapeID < ID_V000 || theShapeID > ID_F1yz )
3519 return shapeCoef[ ID_Shell - 1 ];
3521 return shapeCoef[ theShapeID - 1 ];
3524 //=======================================================================
3525 //function : ShellPoint
3526 //purpose : return coordinates of a point in shell
3527 //=======================================================================
3529 bool TBlock::ShellPoint( const gp_XYZ& theParams, gp_XYZ& thePoint ) const
3531 thePoint.SetCoord( 0., 0., 0. );
3532 for ( int shapeID = ID_V000; shapeID < ID_Shell; shapeID++ )
3535 double* coefs = GetShapeCoef( shapeID );
3537 for ( int iCoef = 0; iCoef < 3; iCoef++ ) {
3538 if ( coefs[ iCoef ] != 0 ) {
3539 if ( coefs[ iCoef ] < 0 )
3540 k *= ( 1. - theParams.Coord( iCoef + 1 ));
3542 k *= theParams.Coord( iCoef + 1 );
3547 if ( shapeID < ID_Ex00 ) // vertex
3548 VertexPoint( shapeID, Ps );
3549 else if ( shapeID < ID_Fxy0 ) { // edge
3550 EdgePoint( shapeID, theParams, Ps );
3553 FacePoint( shapeID, theParams, Ps );
3560 //=======================================================================
3561 //function : NbVariables
3563 //=======================================================================
3565 Standard_Integer TBlock::NbVariables() const
3570 //=======================================================================
3571 //function : NbEquations
3573 //=======================================================================
3575 Standard_Integer TBlock::NbEquations() const
3580 //=======================================================================
3583 //=======================================================================
3585 Standard_Boolean TBlock::Value(const math_Vector& theXYZ, math_Vector& theFxyz)
3587 gp_XYZ P, params( theXYZ(1), theXYZ(2), theXYZ(3) );
3588 if ( params.IsEqual( myParam, DBL_MIN )) { // same param
3589 theFxyz( 1 ) = myValues[ 0 ];
3592 ShellPoint( params, P );
3593 gp_Vec dP( P - myPoint );
3594 theFxyz(1) = SQRT_FUNC ? dP.SquareMagnitude() : dP.Magnitude();
3599 //=======================================================================
3600 //function : Derivatives
3602 //=======================================================================
3604 Standard_Boolean TBlock::Derivatives(const math_Vector& XYZ,math_Matrix& Df)
3606 MESSAGE( "TBlock::Derivatives()");
3608 return Values(XYZ,F,Df);
3611 //=======================================================================
3614 //=======================================================================
3616 Standard_Boolean TBlock::Values(const math_Vector& theXYZ,
3617 math_Vector& theFxyz,
3620 // MESSAGE( endl<<"TBlock::Values( "<<theXYZ(1)<<", "<<theXYZ(2)<<", "<<theXYZ(3)<<")");
3622 gp_XYZ P, params( theXYZ(1), theXYZ(2), theXYZ(3) );
3623 if ( params.IsEqual( myParam, DBL_MIN )) { // same param
3624 theFxyz( 1 ) = myValues[ 0 ];
3625 theDf( 1,1 ) = myValues[ 1 ];
3626 theDf( 1,2 ) = myValues[ 2 ];
3627 theDf( 1,3 ) = myValues[ 3 ];
3631 ShellPoint( params, P );
3632 //myNbIterations++; // how many time call ShellPoint()
3634 gp_Vec dP( P - myPoint );
3635 theFxyz(1) = SQRT_FUNC ? dP.SquareMagnitude() : dP.Magnitude();
3636 if ( theFxyz(1) < 1e-6 ) {
3645 if ( theFxyz(1) < myValues[0] )
3647 // 3 partial derivatives
3649 for ( int iP = 1; iP <= 3; iP++ ) {
3651 params.SetCoord( iP, theXYZ( iP ) + 0.001 );
3652 ShellPoint( params, Pi );
3653 params.SetCoord( iP, theXYZ( iP ) ); // restore params
3654 gp_Vec dPi ( P, Pi );
3655 double mag = dPi.Magnitude();
3656 if ( mag > DBL_MIN )
3658 drv[ iP - 1 ] = dPi;
3660 for ( int iP = 0; iP < 3; iP++ ) {
3661 if ( iP == myFaceIndex )
3662 theDf( 1, iP + 1 ) = myFaceParam;
3664 // like IntAna_IntConicQuad::Perform (const gp_Lin& L, const gp_Pln& P)
3665 // where L is (P -> myPoint), P is defined by the 2 other derivative direction
3666 int iPrev = ( iP ? iP - 1 : 2 );
3667 int iNext = ( iP == 2 ? 0 : iP + 1 );
3668 gp_Vec plnNorm = drv[ iPrev ].Crossed( drv [ iNext ] );
3669 double Direc = plnNorm * drv[ iP ];
3670 if ( Abs(Direc) <= DBL_MIN )
3671 theDf( 1, iP + 1 ) = dP * drv[ iP ];
3673 double Dis = plnNorm * P - plnNorm * myPoint;
3674 theDf( 1, iP + 1 ) = Dis/Direc;
3678 //myNbIterations +=3; // how many time call ShellPoint()
3680 // store better values
3682 myValues[0]= theFxyz(1);
3683 myValues[1]= theDf(1,1);
3684 myValues[2]= theDf(1,2);
3685 myValues[3]= theDf(1,3);
3687 // SCRUTE( theFxyz(1) );
3688 // SCRUTE( theDf( 1,1 ));
3689 // SCRUTE( theDf( 1,2 ));
3690 // SCRUTE( theDf( 1,3 ));
3696 //=======================================================================
3697 //function : ComputeParameters
3698 //purpose : compute point parameters in the block
3699 //=======================================================================
3701 bool TBlock::ComputeParameters(const gp_Pnt& thePoint,
3703 const int theShapeID)
3705 // MESSAGE( endl<<"TBlock::ComputeParameters( "
3706 // <<thePoint.X()<<", "<<thePoint.Y()<<", "<<thePoint.Z()<<")");
3708 myPoint = thePoint.XYZ();
3710 myParam.SetCoord( -1,-1,-1 );
3711 myValues[0] = 1e100;
3713 const bool isOnFace = IsFaceID( theShapeID );
3714 double * coef = GetShapeCoef( theShapeID );
3717 math_Vector start( 1, 3, 0.0 );
3718 if ( !myGridComputed )
3720 // define the first guess by thePoint projection on lines
3721 // connecting vertices
3722 bool needGrid = false;
3723 gp_XYZ par000( 0, 0, 0 ), par111( 1, 1, 1 );
3724 double zero = DBL_MIN * DBL_MIN;
3725 for ( int iEdge = 0, iParam = 1; iParam <= 3 && !needGrid; iParam++ )
3727 if ( isOnFace && coef[ iParam - 1 ] != 0 ) {
3731 for ( int iE = 0; iE < 4; iE++, iEdge++ ) { // loop on 4 parallel edges
3732 gp_Pnt p0 = myEdge[ iEdge ].Point( par000 );
3733 gp_Pnt p1 = myEdge[ iEdge ].Point( par111 );
3734 gp_Vec v01( p0, p1 ), v0P( p0, thePoint );
3735 double len2 = v01.SquareMagnitude();
3737 if ( len2 > zero ) {
3738 par = v0P.Dot( v01 ) / len2;
3739 if ( par < 0 || par > 1 ) {
3744 start( iParam ) += par;
3746 start( iParam ) /= 4.;
3749 // compute nodes of 3 x 3 x 3 grid
3751 for ( double x = 0.25; x < 0.9; x += 0.25 )
3752 for ( double y = 0.25; y < 0.9; y += 0.25 )
3753 for ( double z = 0.25; z < 0.9; z += 0.25 ) {
3754 TxyzPair & prmPtn = my3x3x3GridNodes[ iNode++ ];
3755 prmPtn.first.SetCoord( x, y, z );
3756 ShellPoint( prmPtn.first, prmPtn.second );
3758 myGridComputed = true;
3761 if ( myGridComputed ) {
3762 double minDist = DBL_MAX;
3763 gp_XYZ* bestParam = 0;
3764 for ( int iNode = 0; iNode < 27; iNode++ ) {
3765 TxyzPair & prmPtn = my3x3x3GridNodes[ iNode ];
3766 double dist = ( thePoint.XYZ() - prmPtn.second ).SquareModulus();
3767 if ( dist < minDist ) {
3769 bestParam = & prmPtn.first;
3772 start( 1 ) = bestParam->X();
3773 start( 2 ) = bestParam->Y();
3774 start( 3 ) = bestParam->Z();
3777 int myFaceIndex = -1;
3779 // put a point on the face
3780 for ( int iCoord = 0; iCoord < 3; iCoord++ )
3781 if ( coef[ iCoord ] ) {
3782 myFaceIndex = iCoord;
3783 myFaceParam = ( coef[ myFaceIndex ] < 0.5 ) ? 0.0 : 1.0;
3784 start( iCoord + 1 ) = myFaceParam;
3787 math_Vector low ( 1, 3, 0.0 );
3788 math_Vector up ( 1, 3, 1.0 );
3789 math_Vector tol ( 1, 3, 1e-4 );
3790 math_FunctionSetRoot paramSearch( *this, tol );
3793 while ( myValues[0] > 1e-1 && nbLoops++ < 10 ) {
3794 paramSearch.Perform ( *this, start, low, up );
3795 if ( !paramSearch.IsDone() ) {
3796 //MESSAGE( " !paramSearch.IsDone() " );
3799 //MESSAGE( " NB ITERATIONS: " << paramSearch.NbIterations() );
3801 start( 1 ) = myParam.X();
3802 start( 2 ) = myParam.Y();
3803 start( 3 ) = myParam.Z();
3804 //MESSAGE( "Distance: " << ( SQRT_FUNC ? sqrt(myValues[0]) : myValues[0] ));
3806 // MESSAGE( endl << myParam.X() << " " << myParam.Y() << " " << myParam.Z() << endl);
3807 // mySumDist += myValues[0];
3808 // MESSAGE( " TOTAL NB ITERATIONS: " << myNbIterations <<
3809 // " DIST: " << ( SQRT_FUNC ? sqrt(mySumDist) : mySumDist ));
3812 theParams = myParam;
3817 //=======================================================================
3818 //function : GetStateNumber
3820 //=======================================================================
3822 Standard_Integer TBlock::GetStateNumber ()
3824 // MESSAGE( endl<<"TBlock::GetStateNumber( "<<myParam.X()<<", "<<
3825 // myParam.Y()<<", "<<myParam.Z()<<") DISTANCE: " << myValues[0]);
3826 return myValues[0] < 1e-1;
3829 //=======================================================================
3830 //function : DumpShapeID
3831 //purpose : debug an id of a block sub-shape
3832 //=======================================================================
3834 #define CASEDUMP(id,strm) case id: strm << #id; break;
3836 ostream& TBlock::DumpShapeID (const int id, ostream& stream)
3839 CASEDUMP( ID_V000, stream );
3840 CASEDUMP( ID_V100, stream );
3841 CASEDUMP( ID_V010, stream );
3842 CASEDUMP( ID_V110, stream );
3843 CASEDUMP( ID_V001, stream );
3844 CASEDUMP( ID_V101, stream );
3845 CASEDUMP( ID_V011, stream );
3846 CASEDUMP( ID_V111, stream );
3847 CASEDUMP( ID_Ex00, stream );
3848 CASEDUMP( ID_Ex10, stream );
3849 CASEDUMP( ID_Ex01, stream );
3850 CASEDUMP( ID_Ex11, stream );
3851 CASEDUMP( ID_E0y0, stream );
3852 CASEDUMP( ID_E1y0, stream );
3853 CASEDUMP( ID_E0y1, stream );
3854 CASEDUMP( ID_E1y1, stream );
3855 CASEDUMP( ID_E00z, stream );
3856 CASEDUMP( ID_E10z, stream );
3857 CASEDUMP( ID_E01z, stream );
3858 CASEDUMP( ID_E11z, stream );
3859 CASEDUMP( ID_Fxy0, stream );
3860 CASEDUMP( ID_Fxy1, stream );
3861 CASEDUMP( ID_Fx0z, stream );
3862 CASEDUMP( ID_Fx1z, stream );
3863 CASEDUMP( ID_F0yz, stream );
3864 CASEDUMP( ID_F1yz, stream );
3865 CASEDUMP( ID_Shell, stream );
3866 default: stream << "ID_INVALID";
3871 //=======================================================================
3872 //function : GetShapeIDByParams
3873 //purpose : define an id of the block sub-shape by normlized point coord
3874 //=======================================================================
3876 int TBlock::GetShapeIDByParams ( const gp_XYZ& theCoord )
3878 // id ( 0 - 26 ) computation:
3880 // vertex ( 0 - 7 ) : id = 1*x + 2*y + 4*z
3882 // edge || X ( 8 - 11 ) : id = 8 + 1*y + 2*z
3883 // edge || Y ( 12 - 15 ): id = 1*x + 12 + 2*z
3884 // edge || Z ( 16 - 19 ): id = 1*x + 2*y + 16
3886 // face || XY ( 20 - 21 ): id = 8 + 12 + 1*z - 0
3887 // face || XZ ( 22 - 23 ): id = 8 + 1*y + 16 - 2
3888 // face || YZ ( 24 - 25 ): id = 1*x + 12 + 16 - 4
3890 static int iAddBnd[] = { 1, 2, 4 };
3891 static int iAddNotBnd[] = { 8, 12, 16 };
3892 static int iFaceSubst[] = { 0, 2, 4 };
3895 int iOnBoundary = 0;
3896 for ( int iCoord = 0; iCoord < 3; iCoord++ )
3898 double val = theCoord.Coord( iCoord + 1 );
3901 else if ( val == 1.0 )
3902 id += iAddBnd[ iOnBoundary++ ];
3904 id += iAddNotBnd[ iCoord ];
3906 if ( iOnBoundary == 1 ) // face
3907 id -= iFaceSubst[ (id - 20) / 4 ];
3908 else if ( iOnBoundary == 0 ) // shell
3911 if ( id > 26 || id < 0 ) {
3912 MESSAGE( "GetShapeIDByParams() = " << id
3913 <<" "<< theCoord.X() <<" "<< theCoord.Y() <<" "<< theCoord.Z() );
3916 return id + 1; // shape ids start at 1
3919 //=======================================================================
3920 //function : LoadBlockShapes
3921 //purpose : add sub-shapes of theBlock to theShapeIDMap so that they get
3922 // IDs acoording to enum TBlockShapeID
3923 //=======================================================================
3925 bool TBlock::LoadBlockShapes(const TopoDS_Vertex& theVertex000,
3926 const TopoDS_Vertex& theVertex001,
3927 // TopTools_IndexedMapOfShape& theShapeIDMap
3928 TopTools_IndexedMapOfOrientedShape& theShapeIDMap )
3930 MESSAGE(" ::LoadBlockShapes()");
3931 myGridComputed = false;
3934 TopoDS_Shape V000, V100, V010, V110, V001, V101, V011, V111;
3936 TopoDS_Shape Ex00, Ex10, Ex01, Ex11;
3937 TopoDS_Shape E0y0, E1y0, E0y1, E1y1;
3938 TopoDS_Shape E00z, E10z, E01z, E11z;
3940 TopoDS_Shape Fxy0, Fx0z, F0yz, Fxy1, Fx1z, F1yz;
3942 // nb of faces bound to a vertex in TopTools_IndexedDataMapOfShapeListOfShape
3943 // filled by TopExp::MapShapesAndAncestors()
3944 const int NB_FACES_BY_VERTEX = 6;
3946 TopTools_IndexedDataMapOfShapeListOfShape vfMap;
3947 TopExp::MapShapesAndAncestors( myShell, TopAbs_VERTEX, TopAbs_FACE, vfMap );
3948 if ( vfMap.Extent() != 8 ) {
3949 MESSAGE(" Wrong nb of vertices in the block: " << vfMap.Extent() );
3953 V000 = theVertex000;
3954 V001 = theVertex001;
3956 if ( V000.IsNull() ) {
3957 // find vertex 000 - the one with smallest coordinates
3958 double minVal = DBL_MAX, minX, val;
3959 for ( int i = 1; i <= 8; i++ ) {
3960 const TopoDS_Vertex& v = TopoDS::Vertex( vfMap.FindKey( i ));
3961 gp_Pnt P = BRep_Tool::Pnt( v );
3962 val = P.X() + P.Y() + P.Z();
3963 if ( val < minVal || ( val == minVal && P.X() < minX )) {
3969 // find vertex 001 - the one on the most vertical edge passing through V000
3970 TopTools_IndexedDataMapOfShapeListOfShape veMap;
3971 TopExp::MapShapesAndAncestors( myShell, TopAbs_VERTEX, TopAbs_EDGE, veMap );
3972 gp_Vec dir001 = gp::DZ();
3973 gp_Pnt p000 = BRep_Tool::Pnt( TopoDS::Vertex( V000 ));
3974 double maxVal = -DBL_MAX;
3975 TopTools_ListIteratorOfListOfShape eIt ( veMap.FindFromKey( V000 ));
3976 for ( ; eIt.More(); eIt.Next() ) {
3977 const TopoDS_Edge& e = TopoDS::Edge( eIt.Value() );
3978 TopoDS_Vertex v = TopExp::FirstVertex( e );
3979 if ( v.IsSame( V000 ))
3980 v = TopExp::LastVertex( e );
3981 val = dir001 * gp_Vec( p000, BRep_Tool::Pnt( v )).Normalized();
3982 if ( val > maxVal ) {
3989 // find the bottom (Fxy0), Fx0z and F0yz faces
3991 const TopTools_ListOfShape& f000List = vfMap.FindFromKey( V000 );
3992 const TopTools_ListOfShape& f001List = vfMap.FindFromKey( V001 );
3993 if (f000List.Extent() != NB_FACES_BY_VERTEX ||
3994 f001List.Extent() != NB_FACES_BY_VERTEX ) {
3995 MESSAGE(" LoadBlockShapes() " << f000List.Extent() << " " << f001List.Extent());
3998 TopTools_ListIteratorOfListOfShape f001It, f000It ( f000List );
3999 int i, j, iFound1, iFound2;
4000 for ( j = 0; f000It.More(); f000It.Next(), j++ )
4002 if ( NB_FACES_BY_VERTEX == 6 && j % 2 ) continue; // each face encounters twice
4003 const TopoDS_Shape& F = f000It.Value();
4004 for ( i = 0, f001It.Initialize( f001List ); f001It.More(); f001It.Next(), i++ ) {
4005 if ( NB_FACES_BY_VERTEX == 6 && i % 2 ) continue; // each face encounters twice
4006 if ( F.IsSame( f001It.Value() ))
4009 if ( f001It.More() ) // Fx0z or F0yz found
4010 if ( Fx0z.IsNull() ) {
4017 else // F is the bottom face
4020 if ( Fxy0.IsNull() || Fx0z.IsNull() || F0yz.IsNull() ) {
4021 MESSAGE( Fxy0.IsNull() <<" "<< Fx0z.IsNull() <<" "<< F0yz.IsNull() );
4025 // choose the top face (Fxy1)
4026 for ( i = 0, f001It.Initialize( f001List ); f001It.More(); f001It.Next(), i++ ) {
4027 if ( NB_FACES_BY_VERTEX == 6 && i % 2 ) continue; // each face encounters twice
4028 if ( i != iFound1 && i != iFound2 )
4031 Fxy1 = f001It.Value();
4032 if ( Fxy1.IsNull() ) {
4033 MESSAGE(" LoadBlockShapes() error ");
4037 // find bottom edges and veritices
4038 list< TopoDS_Edge > eList;
4039 list< int > nbVertexInWires;
4040 getOrderedEdges( TopoDS::Face( Fxy0 ), TopoDS::Vertex( V000 ), eList, nbVertexInWires );
4041 if ( nbVertexInWires.size() != 1 || nbVertexInWires.front() != 4 ) {
4042 MESSAGE(" LoadBlockShapes() error ");
4045 list< TopoDS_Edge >::iterator elIt = eList.begin();
4046 for ( i = 0; elIt != eList.end(); elIt++, i++ )
4048 case 0: E0y0 = *elIt; V010 = TopExp::LastVertex( *elIt, true ); break;
4049 case 1: Ex10 = *elIt; V110 = TopExp::LastVertex( *elIt, true ); break;
4050 case 2: E1y0 = *elIt; V100 = TopExp::LastVertex( *elIt, true ); break;
4051 case 3: Ex00 = *elIt; break;
4054 if ( i != 4 || E0y0.IsNull() || Ex10.IsNull() || E1y0.IsNull() || Ex00.IsNull() ) {
4055 MESSAGE(" LoadBlockShapes() error, eList.size()=" << eList.size());
4060 // find top edges and veritices
4062 getOrderedEdges( TopoDS::Face( Fxy1 ), TopoDS::Vertex( V001 ), eList, nbVertexInWires );
4063 if ( nbVertexInWires.size() != 1 || nbVertexInWires.front() != 4 ) {
4064 MESSAGE(" LoadBlockShapes() error ");
4067 for ( i = 0, elIt = eList.begin(); elIt != eList.end(); elIt++, i++ )
4069 case 0: Ex01 = *elIt; V101 = TopExp::LastVertex( *elIt, true ); break;
4070 case 1: E1y1 = *elIt; V111 = TopExp::LastVertex( *elIt, true ); break;
4071 case 2: Ex11 = *elIt; V011 = TopExp::LastVertex( *elIt, true ); break;
4072 case 3: E0y1 = *elIt; break;
4075 if ( i != 4 || Ex01.IsNull() || E1y1.IsNull() || Ex11.IsNull() || E0y1.IsNull() ) {
4076 MESSAGE(" LoadBlockShapes() error, eList.size()=" << eList.size());
4080 // swap Fx0z and F0yz if necessary
4081 TopExp_Explorer exp( Fx0z, TopAbs_VERTEX );
4082 for ( ; exp.More(); exp.Next() ) // Fx0z shares V101 and V100
4083 if ( V101.IsSame( exp.Current() ) || V100.IsSame( exp.Current() ))
4084 break; // V101 or V100 found
4085 if ( !exp.More() ) { // not found
4086 TopoDS_Shape f = Fx0z; Fx0z = F0yz; F0yz = f;
4089 // find Fx1z and F1yz faces
4090 const TopTools_ListOfShape& f111List = vfMap.FindFromKey( V111 );
4091 const TopTools_ListOfShape& f110List = vfMap.FindFromKey( V110 );
4092 if (f111List.Extent() != NB_FACES_BY_VERTEX ||
4093 f110List.Extent() != NB_FACES_BY_VERTEX ) {
4094 MESSAGE(" LoadBlockShapes() " << f111List.Extent() << " " << f110List.Extent());
4097 TopTools_ListIteratorOfListOfShape f111It, f110It ( f110List);
4098 for ( j = 0 ; f110It.More(); f110It.Next(), j++ ) {
4099 if ( NB_FACES_BY_VERTEX == 6 && j % 2 ) continue; // each face encounters twice
4100 const TopoDS_Shape& F = f110It.Value();
4101 for ( i = 0, f111It.Initialize( f111List ); f111It.More(); f111It.Next(), i++ ) {
4102 if ( NB_FACES_BY_VERTEX == 6 && i % 2 ) continue; // each face encounters twice
4103 if ( F.IsSame( f111It.Value() )) { // Fx1z or F1yz found
4104 if ( Fx1z.IsNull() )
4111 if ( Fx1z.IsNull() || F1yz.IsNull() ) {
4112 MESSAGE(" LoadBlockShapes() error ");
4116 // swap Fx1z and F1yz if necessary
4117 for ( exp.Init( Fx1z, TopAbs_VERTEX ); exp.More(); exp.Next() )
4118 if ( V010.IsSame( exp.Current() ) || V011.IsSame( exp.Current() ))
4120 if ( !exp.More() ) {
4121 TopoDS_Shape f = Fx1z; Fx1z = F1yz; F1yz = f;
4124 // find vertical edges
4125 for ( exp.Init( Fx0z, TopAbs_EDGE ); exp.More(); exp.Next() ) {
4126 const TopoDS_Edge& edge = TopoDS::Edge( exp.Current() );
4127 const TopoDS_Shape& vFirst = TopExp::FirstVertex( edge, true );
4128 if ( vFirst.IsSame( V001 ))
4130 else if ( vFirst.IsSame( V100 ))
4133 if ( E00z.IsNull() || E10z.IsNull() ) {
4134 MESSAGE(" LoadBlockShapes() error ");
4137 for ( exp.Init( Fx1z, TopAbs_EDGE ); exp.More(); exp.Next() ) {
4138 const TopoDS_Edge& edge = TopoDS::Edge( exp.Current() );
4139 const TopoDS_Shape& vFirst = TopExp::FirstVertex( edge, true );
4140 if ( vFirst.IsSame( V111 ))
4142 else if ( vFirst.IsSame( V010 ))
4145 if ( E01z.IsNull() || E11z.IsNull() ) {
4146 MESSAGE(" LoadBlockShapes() error ");
4150 // load shapes in theShapeIDMap
4152 theShapeIDMap.Clear();
4154 theShapeIDMap.Add(V000.Oriented( TopAbs_FORWARD ));
4155 theShapeIDMap.Add(V100.Oriented( TopAbs_FORWARD ));
4156 theShapeIDMap.Add(V010.Oriented( TopAbs_FORWARD ));
4157 theShapeIDMap.Add(V110.Oriented( TopAbs_FORWARD ));
4158 theShapeIDMap.Add(V001.Oriented( TopAbs_FORWARD ));
4159 theShapeIDMap.Add(V101.Oriented( TopAbs_FORWARD ));
4160 theShapeIDMap.Add(V011.Oriented( TopAbs_FORWARD ));
4161 theShapeIDMap.Add(V111.Oriented( TopAbs_FORWARD ));
4163 theShapeIDMap.Add(Ex00);
4164 theShapeIDMap.Add(Ex10);
4165 theShapeIDMap.Add(Ex01);
4166 theShapeIDMap.Add(Ex11);
4168 theShapeIDMap.Add(E0y0);
4169 theShapeIDMap.Add(E1y0);
4170 theShapeIDMap.Add(E0y1);
4171 theShapeIDMap.Add(E1y1);
4173 theShapeIDMap.Add(E00z);
4174 theShapeIDMap.Add(E10z);
4175 theShapeIDMap.Add(E01z);
4176 theShapeIDMap.Add(E11z);
4178 theShapeIDMap.Add(Fxy0);
4179 theShapeIDMap.Add(Fxy1);
4180 theShapeIDMap.Add(Fx0z);
4181 theShapeIDMap.Add(Fx1z);
4182 theShapeIDMap.Add(F0yz);
4183 theShapeIDMap.Add(F1yz);
4185 theShapeIDMap.Add(myShell);
4187 if ( theShapeIDMap.Extent() != 27 ) {
4188 MESSAGE("LoadBlockShapes() " << theShapeIDMap.Extent() );
4192 // store shapes geometry
4193 for ( int shapeID = 1; shapeID < theShapeIDMap.Extent(); shapeID++ )
4195 const TopoDS_Shape& S = theShapeIDMap( shapeID );
4196 switch ( S.ShapeType() )
4198 case TopAbs_VERTEX: {
4200 if ( shapeID > ID_V111 ) {
4201 MESSAGE(" shapeID =" << shapeID );
4204 myPnt[ shapeID - ID_V000 ] =
4205 BRep_Tool::Pnt( TopoDS::Vertex( S )).XYZ();
4210 const TopoDS_Edge& edge = TopoDS::Edge( S );
4211 if ( shapeID < ID_Ex00 || shapeID > ID_E11z || edge.IsNull() ) {
4212 MESSAGE(" shapeID =" << shapeID );
4215 TEdge& tEdge = myEdge[ shapeID - ID_Ex00 ];
4216 tEdge.myCoordInd = GetCoordIndOnEdge( shapeID );
4217 TopLoc_Location loc;
4218 tEdge.myC3d = BRep_Tool::Curve( edge, loc, tEdge.myFirst, tEdge.myLast );
4219 if ( !IsForwardEdge( edge, theShapeIDMap ))
4220 Swap( tEdge.myFirst, tEdge.myLast );
4226 const TopoDS_Face& face = TopoDS::Face( S );
4227 if ( shapeID < ID_Fxy0 || shapeID > ID_F1yz || face.IsNull() ) {
4228 MESSAGE(" shapeID =" << shapeID );
4231 TFace& tFace = myFace[ shapeID - ID_Fxy0 ];
4233 vector< int > edgeIdVec(4, -1);
4234 GetFaceEdgesIDs( shapeID, edgeIdVec );
4235 for ( int iE = 0; iE < 4; iE++ ) // loop on 4 edges
4237 const TopoDS_Edge& edge = TopoDS::Edge( theShapeIDMap( edgeIdVec[ iE ]));
4238 tFace.myCoordInd[ iE ] = GetCoordIndOnEdge( edgeIdVec[ iE ] );
4240 BRep_Tool::CurveOnSurface( edge, face, tFace.myFirst[iE], tFace.myLast[iE] );
4241 if ( !IsForwardEdge( edge, theShapeIDMap ))
4242 Swap( tFace.myFirst[ iE ], tFace.myLast[ iE ] );
4245 tFace.myCorner[ 0 ] = tFace.myC2d[ 0 ]->Value( tFace.myFirst[0] ).XY();
4246 tFace.myCorner[ 1 ] = tFace.myC2d[ 0 ]->Value( tFace.myLast[0] ).XY();
4247 tFace.myCorner[ 2 ] = tFace.myC2d[ 1 ]->Value( tFace.myLast[1] ).XY();
4248 tFace.myCorner[ 3 ] = tFace.myC2d[ 1 ]->Value( tFace.myFirst[1] ).XY();
4250 TopLoc_Location loc;
4251 tFace.myS = BRep_Tool::Surface( face, loc );
4257 } // loop on shapes in theShapeIDMap
4262 //=======================================================================
4263 //function : GetFaceEdgesIDs
4264 //purpose : return edges IDs in the order u0, u1, 0v, 1v
4265 // u0 means "|| u, v == 0"
4266 //=======================================================================
4268 void TBlock::GetFaceEdgesIDs (const int faceID, vector< int >& edgeVec )
4272 edgeVec[ 0 ] = ID_Ex00;
4273 edgeVec[ 1 ] = ID_Ex10;
4274 edgeVec[ 2 ] = ID_E0y0;
4275 edgeVec[ 3 ] = ID_E1y0;
4278 edgeVec[ 0 ] = ID_Ex01;
4279 edgeVec[ 1 ] = ID_Ex11;
4280 edgeVec[ 2 ] = ID_E0y1;
4281 edgeVec[ 3 ] = ID_E1y1;
4284 edgeVec[ 0 ] = ID_Ex00;
4285 edgeVec[ 1 ] = ID_Ex01;
4286 edgeVec[ 2 ] = ID_E00z;
4287 edgeVec[ 3 ] = ID_E10z;
4290 edgeVec[ 0 ] = ID_Ex10;
4291 edgeVec[ 1 ] = ID_Ex11;
4292 edgeVec[ 2 ] = ID_E01z;
4293 edgeVec[ 3 ] = ID_E11z;
4296 edgeVec[ 0 ] = ID_E0y0;
4297 edgeVec[ 1 ] = ID_E0y1;
4298 edgeVec[ 2 ] = ID_E00z;
4299 edgeVec[ 3 ] = ID_E01z;
4302 edgeVec[ 0 ] = ID_E1y0;
4303 edgeVec[ 1 ] = ID_E1y1;
4304 edgeVec[ 2 ] = ID_E10z;
4305 edgeVec[ 3 ] = ID_E11z;
4308 MESSAGE(" GetFaceEdgesIDs(), wrong face ID: " << faceID );