1 // Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
22 // File : SMESH_MAT2d.cxx
23 // Created : Thu May 28 17:49:53 2015
24 // Author : Edward AGAPOV (eap)
26 #include "SMESH_MAT2d.hxx"
30 #include <BRepAdaptor_CompCurve.hxx>
31 #include <BRepBuilderAPI_MakeEdge.hxx>
32 #include <BRepBuilderAPI_MakeVertex.hxx>
33 #include <BRep_Builder.hxx>
34 #include <BRep_Tool.hxx>
35 #include <Bnd_B2d.hxx>
36 //#include <GCPnts_AbscissaPoint.hxx>
37 #include <GCPnts_TangentialDeflection.hxx>
38 // #include <GCPnts_UniformAbscissa.hxx>
39 // #include <GCPnts_UniformDeflection.hxx>
40 #include <Geom2d_Curve.hxx>
41 //#include <GeomAdaptor_Curve.hxx>
42 #include <Geom2dAdaptor_Curve.hxx>
43 #include <Geom_Curve.hxx>
44 #include <Geom_Surface.hxx>
46 #include <TopoDS_Vertex.hxx>
47 #include <TopoDS_Wire.hxx>
50 #include "SMESH_File.hxx"
51 #include "SMESH_Comment.hxx"
55 using boost::polygon::x;
56 using boost::polygon::y;
57 using SMESH_MAT2d::TVD;
58 using SMESH_MAT2d::TVDEdge;
59 using SMESH_MAT2d::TVDCell;
60 using SMESH_MAT2d::TVDVertex;
64 // Input data for construct_voronoi()
65 // -------------------------------------------------------------------------------------
71 InPoint(int x, int y, double param) : _a(x), _b(y), _param(param) {}
72 InPoint() : _a(0), _b(0), _param(0) {}
75 list< const TVDEdge* > _edges; // MA edges of a concave InPoint in CCW order
77 size_t index( const vector< InPoint >& inPoints ) const { return this - &inPoints[0]; }
78 bool operator==( const InPoint& other ) const { return _a == other._a && _b == other._b; }
80 // -------------------------------------------------------------------------------------
88 size_t _geomEdgeInd; // EDGE index within the FACE
90 list< const TVDEdge* > _edges; // MA edges in CCW order within _cell
92 InSegment( InPoint * p0, InPoint * p1, size_t iE)
93 : _p0(p0), _p1(p1), _geomEdgeInd(iE) {}
94 InSegment() : _p0(0), _p1(0), _geomEdgeInd(0) {}
96 inline bool isConnected( const TVDEdge* edge );
98 inline bool isExternal( const TVDEdge* edge );
100 static void setGeomEdgeToCell( const TVDCell* cell, size_t eID ) { cell->color( eID ); }
102 static size_t getGeomEdge( const TVDCell* cell ) { return cell->color(); }
105 // check if a TVDEdge begins at my end or ends at my start
106 inline bool InSegment::isConnected( const TVDEdge* edge )
108 return ((Abs( edge->vertex0()->x() - _p1->_a ) < 1.&&
109 Abs( edge->vertex0()->y() - _p1->_b ) < 1. ) ||
110 (Abs( edge->vertex1()->x() - _p0->_a ) < 1.&&
111 Abs( edge->vertex1()->y() - _p0->_b ) < 1. ));
114 // check if a MA TVDEdge is outside of a domain
115 inline bool InSegment::isExternal( const TVDEdge* edge )
117 double dot = // x1*x2 + y1*y2; (x1,y1) - internal normal of InSegment
118 ( _p0->_b - _p1->_b ) * ( 0.5 * ( edge->vertex0()->x() + edge->vertex1()->x() ) - _p0->_a ) +
119 ( _p1->_a - _p0->_a ) * ( 0.5 * ( edge->vertex0()->y() + edge->vertex1()->y() ) - _p0->_b );
123 // // -------------------------------------------------------------------------------------
124 // const size_t theExternMA = 111; // to mark external MA edges
126 // bool isExternal( const TVDEdge* edge )
128 // return ( SMESH_MAT2d::Branch::getBndSegment( edge ) == theExternMA );
131 // // mark external MA edges
132 // void markExternalEdges( const TVDEdge* edge )
134 // if ( isExternal( edge ))
136 // SMESH_MAT2d::Branch::setBndSegment( theExternMA, edge );
137 // SMESH_MAT2d::Branch::setBndSegment( theExternMA, edge->twin() );
138 // if ( edge->is_primary() && edge->vertex1() )
140 // const TVDVertex * v = edge->vertex1();
141 // edge = v->incident_edge();
143 // markExternalEdges( edge );
144 // edge = edge->rot_next();
145 // } while ( edge != v->incident_edge() );
149 // -------------------------------------------------------------------------------------
151 // writes segments into a txt file readable by voronoi_visualizer
152 void inSegmentsToFile( vector< InSegment>& inSegments)
154 if ( inSegments.size() > 1000 )
156 const char* fileName = "/misc/dn25/salome/eap/salome/misc/Code/C++/MAdebug.txt";
157 SMESH_File file(fileName, false );
158 file.openForWriting();
160 text << "0\n"; // nb points
161 text << inSegments.size() << "\n"; // nb segments
162 for ( size_t i = 0; i < inSegments.size(); ++i )
164 text << inSegments[i]._p0->_a << " "
165 << inSegments[i]._p0->_b << " "
166 << inSegments[i]._p1->_a << " "
167 << inSegments[i]._p1->_b << "\n";
170 file.write( text.c_str(), text.size() );
171 cout << "Write " << fileName << endl;
173 void dumpEdge( const TVDEdge* edge )
175 cout << "*Edge_" << edge;
176 if ( !edge->vertex0() )
177 cout << " ( INF, INF";
179 cout << " ( " << edge->vertex0()->x() << ", " << edge->vertex0()->y();
180 if ( !edge->vertex1() )
181 cout << ") -> ( INF, INF";
183 cout << ") -> (" << edge->vertex1()->x() << ", " << edge->vertex1()->y();
184 cout << ")\t cell=" << edge->cell()
185 << " iBnd=" << edge->color()
186 << " twin=" << edge->twin()
187 << " twin_cell=" << edge->twin()->cell()
188 << " prev=" << edge->prev() << " next=" << edge->next()
189 << ( edge->is_primary() ? " MA " : " SCND" )
190 << ( edge->is_linear() ? " LIN " : " CURV" )
193 void dumpCell( const TVDCell* cell )
195 cout << "**Cell_" << cell << " GEOM=" << cell->color() << " ";
196 cout << ( cell->contains_segment() ? " SEG " : " PNT " );
197 if ( cell-> is_degenerate() )
202 const TVDEdge* edge = cell->incident_edge();
206 cout << " - " << ++i << " ";
208 } while (edge != cell->incident_edge());
212 void inSegmentsToFile( vector< InSegment>& inSegments) {}
213 void dumpEdge( const TVDEdge* edge ) {}
214 void dumpCell( const TVDCell* cell ) {}
217 // -------------------------------------------------------------------------------------
223 struct geometry_concept<InPoint> {
224 typedef point_concept type;
227 struct point_traits<InPoint> {
228 typedef int coordinate_type;
230 static inline coordinate_type get(const InPoint& point, orientation_2d orient) {
231 return (orient == HORIZONTAL) ? point._a : point._b;
236 struct geometry_concept<InSegment> {
237 typedef segment_concept type;
241 struct segment_traits<InSegment> {
242 typedef int coordinate_type;
243 typedef InPoint point_type;
245 static inline point_type get(const InSegment& segment, direction_1d dir) {
246 return *(dir.to_int() ? segment._p1 : segment._p0);
249 } // namespace polygon
251 // -------------------------------------------------------------------------------------
255 const int theNoBrachID = 0; // std::numeric_limits<int>::max();
257 // -------------------------------------------------------------------------------------
259 * \brief Intermediate DS to create InPoint's
265 UVU( gp_Pnt2d uv, double u ): _uv(uv), _u(u) {}
266 InPoint getInPoint( double scale[2] )
268 return InPoint( int( _uv.X() * scale[0]), int( _uv.Y() * scale[1]), _u );
271 // -------------------------------------------------------------------------------------
273 * \brief A segment on EDGE, used to create BndPoints
278 const TVDEdge* _edge;
280 int _branchID; // negative ID means reverse direction
282 BndSeg( InSegment* seg, const TVDEdge* edge, double u ):
283 _inSeg(seg), _edge(edge), _uLast(u), _branchID( theNoBrachID ) {}
285 void setIndexToEdge( size_t id )
287 SMESH_MAT2d::Branch::setBndSegment( id, _edge );
290 int branchID() const { return Abs( _branchID ); }
292 size_t geomEdge() const { return _inSeg->_geomEdgeInd; }
294 void setBranch( int branchID, vector< BndSeg >& bndSegs )
296 _branchID = branchID;
298 if ( _edge ) // pass branch to an opposite BndSeg
300 size_t oppSegIndex = SMESH_MAT2d::Branch::getBndSegment( _edge->twin() );
301 if ( oppSegIndex < bndSegs.size() /*&& bndSegs[ oppSegIndex ]._branchID == theNoBrachID*/ )
302 bndSegs[ oppSegIndex ]._branchID = -branchID;
305 bool hasOppositeEdge( const size_t noEdgeID )
307 if ( !_edge ) return false;
308 return ( _inSeg->getGeomEdge( _edge->twin()->cell() ) != noEdgeID );
311 // check a next segment in CW order
312 bool isSameBranch( const BndSeg& seg2 )
314 if ( !_edge || !seg2._edge )
317 const TVDCell* cell1 = this->_edge->twin()->cell();
318 const TVDCell* cell2 = seg2. _edge->twin()->cell();
319 if ( cell1 == cell2 )
322 const TVDEdge* edgeMedium1 = this->_edge->twin()->next();
323 const TVDEdge* edgeMedium2 = seg2. _edge->twin()->prev();
325 if ( edgeMedium1->is_secondary() && edgeMedium2->is_secondary() )
327 if ( edgeMedium1->twin() == edgeMedium2 )
329 // edgeMedium's are edges whose twin()->cell is built on an end point of inSegment
330 // and is located between cell1 and cell2
331 if ( edgeMedium1->twin() == edgeMedium2->twin() ) // is this possible???
333 if ( edgeMedium1->twin() == edgeMedium2->twin()->next() &&
334 edgeMedium1->twin()->cell()->contains_point() )
337 else if ( edgeMedium1->is_primary() && edgeMedium2->is_primary() )
339 if ( edgeMedium1->twin() == edgeMedium2 &&
340 SMESH_MAT2d::Branch::getBndSegment( edgeMedium1 ) ==
341 SMESH_MAT2d::Branch::getBndSegment( edgeMedium2 ))
342 // this is an ignored MA edge between inSegment's on one EDGE forming a convex corner
350 //================================================================================
352 * \brief Computes length of of TVDEdge
354 //================================================================================
356 double length( const TVDEdge* edge )
358 gp_XY d( edge->vertex0()->x() - edge->vertex1()->x(),
359 edge->vertex0()->y() - edge->vertex1()->y() );
363 //================================================================================
365 * \brief Compute scale to have the same 2d proportions as in 3d
367 //================================================================================
369 void computeProportionScale( const TopoDS_Face& face,
370 const Bnd_B2d& uvBox,
373 scale[0] = scale[1] = 1.;
374 if ( uvBox.IsVoid() ) return;
377 Handle(Geom_Surface) surface = BRep_Tool::Surface( face, loc );
379 const int nbDiv = 30;
380 gp_XY uvMin = uvBox.CornerMin(), uvMax = uvBox.CornerMax();
381 gp_XY uvMid = 0.5 * ( uvMin + uvMax );
382 double du = ( uvMax.X() - uvMin.X() ) / nbDiv;
383 double dv = ( uvMax.Y() - uvMin.Y() ) / nbDiv;
385 double uLen3d = 0, vLen3d = 0;
386 gp_Pnt uPrevP = surface->Value( uvMin.X(), uvMid.Y() );
387 gp_Pnt vPrevP = surface->Value( uvMid.X(), uvMin.Y() );
388 for (int i = 1; i <= nbDiv; i++)
390 double u = uvMin.X() + du * i;
391 double v = uvMin.Y() + dv * i;
392 gp_Pnt uP = surface->Value( u, uvMid.Y() );
393 gp_Pnt vP = surface->Value( uvMid.X(), v );
394 uLen3d += uP.Distance( uPrevP );
395 vLen3d += vP.Distance( vPrevP );
399 scale[0] = uLen3d / ( uvMax.X() - uvMin.X() );
400 scale[1] = vLen3d / ( uvMax.Y() - uvMin.Y() );
403 //================================================================================
405 * \brief Fill input data for construct_voronoi()
407 //================================================================================
409 bool makeInputData(const TopoDS_Face& face,
410 const std::vector< TopoDS_Edge >& edges,
411 const double minSegLen,
412 vector< InPoint >& inPoints,
413 vector< InSegment>& inSegments,
416 const double theDiscrCoef = 0.5; // to decrease minSegLen for discretization
419 // discretize the EDGEs to get 2d points and segments
421 vector< vector< UVU > > uvuVec( edges.size() );
423 for ( size_t iE = 0; iE < edges.size(); ++iE )
425 vector< UVU > & points = uvuVec[ iE ];
428 Handle(Geom_Curve) c3d = BRep_Tool::Curve ( edges[ iE ], loc, f, l );
429 Handle(Geom2d_Curve) c2d = BRep_Tool::CurveOnSurface( edges[ iE ], face, f, l );
430 if ( c2d.IsNull() ) return false;
432 points.push_back( UVU( c2d->Value( f ), f ));
433 uvBox.Add( points.back()._uv );
435 Geom2dAdaptor_Curve c2dAdaptor (c2d, f,l );
436 double curDeflect = 0.3; //0.01; //Curvature deflection
437 double angDeflect = 0.2; // 0.09; //Angular deflection
439 GCPnts_TangentialDeflection discret(c2dAdaptor, angDeflect, curDeflect);
440 // if ( discret.NbPoints() > 2 )
445 // discret.Initialize( c2dAdaptor, 100, curDeflect );
446 // cout << "C " << curDeflect << " " << discret.NbPoints() << endl;
447 // curDeflect *= 1.5;
449 // while ( discret.NbPoints() > 5 );
453 // discret.Initialize( c2dAdaptor, angDeflect, 100 );
454 // cout << "A " << angDeflect << " " << discret.NbPoints() << endl;
455 // angDeflect *= 1.5;
457 // while ( discret.NbPoints() > 5 );
461 pPrev = c3d->Value( f );
462 for ( int i = 2; i <= discret.NbPoints(); i++ ) // skip the 1st point
464 double u = discret.Parameter(i);
468 int nbDiv = int( p.Distance( pPrev ) / minSegLen / theDiscrCoef );
469 double dU = ( u - points.back()._u ) / nbDiv;
470 for ( int iD = 1; iD < nbDiv; ++iD )
472 double uD = points.back()._u + dU;
473 points.push_back( UVU( c2d->Value( uD ), uD ));
477 points.push_back( UVU( c2d->Value( u ), u ));
478 uvBox.Add( points.back()._uv );
480 // if ( !c3d.IsNull() )
482 // vector<double> params;
483 // GeomAdaptor_Curve c3dAdaptor( c3d,f,l );
486 // const double deflection = minSegLen * 0.1;
487 // GCPnts_UniformDeflection discret( c3dAdaptor, deflection, f, l, true );
488 // if ( !discret.IsDone() )
490 // int nbP = discret.NbPoints();
491 // for ( int i = 2; i < nbP; i++ ) // skip 1st and last points
492 // params.push_back( discret.Parameter(i) );
496 // double eLen = GCPnts_AbscissaPoint::Length( c3dAdaptor );
497 // int nbSeg = Max( 1, int( eLen / minSegLen / theDiscrCoef ));
498 // double segLen = eLen / nbSeg;
499 // GCPnts_UniformAbscissa discret( c3dAdaptor, segLen, f, l );
500 // int nbP = Min( discret.NbPoints(), nbSeg + 1 );
501 // for ( int i = 2; i < nbP; i++ ) // skip 1st and last points
502 // params.push_back( discret.Parameter(i) );
504 // for ( size_t i = 0; i < params.size(); ++i )
506 // points.push_back( UVU( c2d->Value( params[i] ), params[i] ));
507 // uvBox.Add( points.back()._uv );
510 if ( points.size() < 2 )
512 points.push_back( UVU( c2d->Value( l ), l ));
513 uvBox.Add( points.back()._uv );
515 if ( edges[ iE ].Orientation() == TopAbs_REVERSED )
516 std::reverse( points.begin(), points.end() );
519 // make connected EDGEs have same UV at shared VERTEX
520 TopoDS_Vertex vShared;
521 for ( size_t iE = 0; iE < edges.size(); ++iE )
523 size_t iE2 = (iE+1) % edges.size();
524 if ( !TopExp::CommonVertex( edges[iE], edges[iE2], vShared ))
526 if ( !vShared.IsSame( TopExp::LastVertex( edges[iE], true )))
528 vector< UVU > & points1 = uvuVec[ iE ];
529 vector< UVU > & points2 = uvuVec[ iE2 ];
530 gp_Pnt2d & uv1 = points1.back() ._uv;
531 gp_Pnt2d & uv2 = points2.front()._uv;
532 uv1 = uv2 = 0.5 * ( uv1.XY() + uv2.XY() );
535 // get scale to have the same 2d proportions as in 3d
536 computeProportionScale( face, uvBox, scale );
538 // make scale to have coordinates precise enough when converted to int
540 gp_XY uvMin = uvBox.CornerMin(), uvMax = uvBox.CornerMax();
541 uvMin.ChangeCoord(1) = uvMin.X() * scale[0];
542 uvMin.ChangeCoord(2) = uvMin.Y() * scale[1];
543 uvMax.ChangeCoord(1) = uvMax.X() * scale[0];
544 uvMax.ChangeCoord(2) = uvMax.Y() * scale[1];
545 double vMax[2] = { Max( Abs( uvMin.X() ), Abs( uvMax.X() )),
546 Max( Abs( uvMin.Y() ), Abs( uvMax.Y() )) };
547 int iMax = ( vMax[0] > vMax[1] ) ? 0 : 1;
548 const double precision = 1e-5;
549 double preciScale = Min( vMax[iMax] / precision,
550 std::numeric_limits<int>::max() / vMax[iMax] );
551 preciScale /= scale[iMax];
552 double roundedScale = 10; // to ease debug
553 while ( roundedScale * 10 < preciScale )
555 scale[0] *= roundedScale;
556 scale[1] *= roundedScale;
558 // create input points and segments
563 for ( size_t iE = 0; iE < uvuVec.size(); ++iE )
564 nbPnt += uvuVec[ iE ].size();
565 inPoints.resize( nbPnt );
566 inSegments.reserve( nbPnt );
569 if ( face.Orientation() == TopAbs_REVERSED )
571 for ( int iE = uvuVec.size()-1; iE >= 0; --iE )
573 vector< UVU > & points = uvuVec[ iE ];
574 inPoints[ iP++ ] = points.back().getInPoint( scale );
575 for ( size_t i = points.size()-1; i >= 1; --i )
577 inPoints[ iP++ ] = points[i-1].getInPoint( scale );
578 inSegments.push_back( InSegment( & inPoints[ iP-2 ], & inPoints[ iP-1 ], iE ));
584 for ( size_t iE = 0; iE < uvuVec.size(); ++iE )
586 vector< UVU > & points = uvuVec[ iE ];
587 inPoints[ iP++ ] = points[0].getInPoint( scale );
588 for ( size_t i = 1; i < points.size(); ++i )
590 inPoints[ iP++ ] = points[i].getInPoint( scale );
591 inSegments.push_back( InSegment( & inPoints[ iP-2 ], & inPoints[ iP-1 ], iE ));
598 //================================================================================
600 * \brief Create MA branches and FACE boundary data
601 * \param [in] vd - voronoi diagram of \a inSegments
602 * \param [in] inPoints - FACE boundary points
603 * \param [in,out] inSegments - FACE boundary segments
604 * \param [out] branch - MA branches to fill
605 * \param [out] branchEnd - ends of MA branches to fill
606 * \param [out] boundary - FACE boundary to fill
608 //================================================================================
610 void makeMA( const TVD& vd,
611 vector< InPoint >& inPoints,
612 vector< InSegment > & inSegments,
613 vector< SMESH_MAT2d::Branch >& branch,
614 vector< const SMESH_MAT2d::BranchEnd* >& branchPnt,
615 SMESH_MAT2d::Boundary& boundary )
617 const size_t noEdgeID = inSegments.size() + 1; // ID of non-existent geom EDGE
619 // Associate MA cells with inSegments
620 for (TVD::const_cell_iterator it = vd.cells().begin(); it != vd.cells().end(); ++it)
622 const TVDCell* cell = &(*it);
623 if ( cell->contains_segment() )
625 InSegment& seg = inSegments[ cell->source_index() ];
627 seg.setGeomEdgeToCell( cell, seg._geomEdgeInd );
631 InSegment::setGeomEdgeToCell( cell, noEdgeID );
635 vector< bool > inPntChecked( inPoints.size(), false );
637 // Find MA edges of each inSegment
639 for ( size_t i = 0; i < inSegments.size(); ++i )
641 InSegment& inSeg = inSegments[i];
643 // get edges around the cell lying on MA
644 bool hasSecondary = false;
645 const TVDEdge* edge = inSeg._cell->incident_edge();
647 edge = edge->next(); // Returns the CCW next edge within the cell.
648 if ( edge->is_primary() && !inSeg.isExternal( edge ) )
649 inSeg._edges.push_back( edge ); // edge equidistant from two InSegments
652 } while (edge != inSeg._cell->incident_edge());
654 // there can be several continuous MA edges but maEdges can begin in the middle of
655 // a chain of continuous MA edges. Make the chain continuous.
656 list< const TVDEdge* >& maEdges = inSeg._edges;
657 if ( maEdges.empty() )
660 while ( maEdges.back()->next() == maEdges.front() )
661 maEdges.splice( maEdges.end(), maEdges, maEdges.begin() );
663 // remove maEdges equidistant from two neighbor InSegments of the same geom EDGE
664 list< const TVDEdge* >::iterator e = maEdges.begin();
665 while ( e != maEdges.end() )
667 const TVDCell* cell2 = (*e)->twin()->cell(); // cell on the other side of a MA edge
668 size_t geoE2 = InSegment::getGeomEdge( cell2 );
669 bool toRemove = ( inSeg._geomEdgeInd == geoE2 && inSeg.isConnected( *e ));
671 e = maEdges.erase( e );
675 if ( maEdges.empty() )
678 // add MA edges corresponding to concave InPoints
679 for ( int is2nd = 0; is2nd < 2; ++is2nd ) // loop on two ends of inSeg
681 InPoint& inPnt = *( is2nd ? inSeg._p1 : inSeg._p0 );
682 size_t pInd = inPnt.index( inPoints );
683 if ( inPntChecked[ pInd ] )
686 inPntChecked[ pInd-1 ] &&
687 inPoints[ pInd-1 ] == inPnt )
689 inPntChecked[ pInd ] = true;
691 const TVDEdge* edge = // a TVDEdge passing through an end of inSeg
692 is2nd ? maEdges.front()->prev() : maEdges.back()->next();
695 if ( edge->is_primary() ) break; // this should not happen
696 const TVDEdge* edge2 = edge->twin(); // we are in a neighbor cell, add MA edges to inPnt
697 if ( inSeg.getGeomEdge( edge2->cell() ) != noEdgeID )
698 break; // cell of an InSegment
699 bool hasInfinite = false;
700 list< const TVDEdge* > pointEdges;
704 edge = edge->next(); // Returns the CCW next edge within the cell.
705 if ( edge->is_infinite() )
707 else if ( edge->is_primary() && !inSeg.isExternal( edge ))
708 pointEdges.push_back( edge );
710 while ( edge != edge2 && !hasInfinite );
712 if ( hasInfinite || pointEdges.empty() )
714 inPnt._edges.splice( inPnt._edges.end(), pointEdges );
715 inSeg.setGeomEdgeToCell( edge->cell(), inSeg._geomEdgeInd );
717 edge = is2nd ? inPnt._edges.front()->prev() : inPnt._edges.back()->next();
719 } // add MA edges corresponding to concave InPoints
721 } // loop on inSegments to find corresponding MA edges
724 // -------------------------------------------
725 // Create Branches and BndPoints for each EDGE
726 // -------------------------------------------
728 if ( inPoints.front() == inPoints.back() /*&& !inPoints[0]._edges.empty()*/ )
730 inPntChecked[0] = false; // do not use the 1st point twice
731 //InSegment::setGeomEdgeToCell( inPoints[0]._edges.back()->cell(), noEdgeID );
732 inPoints[0]._edges.clear();
735 // Divide InSegment's into BndSeg's
737 vector< BndSeg > bndSegs;
738 bndSegs.reserve( inSegments.size() * 3 );
740 list< const TVDEdge* >::reverse_iterator e;
741 for ( size_t i = 0; i < inSegments.size(); ++i )
743 InSegment& inSeg = inSegments[i];
745 // segments around 1st concave point
746 size_t ip0 = inSeg._p0->index( inPoints );
747 if ( inPntChecked[ ip0 ] )
748 for ( e = inSeg._p0->_edges.rbegin(); e != inSeg._p0->_edges.rend(); ++e )
749 bndSegs.push_back( BndSeg( &inSeg, *e, inSeg._p0->_param ));
750 inPntChecked[ ip0 ] = false;
752 // segments of InSegment's
753 size_t nbMaEdges = inSeg._edges.size();
754 switch ( nbMaEdges ) {
755 case 0: // "around" circle center
756 bndSegs.push_back( BndSeg( &inSeg, 0, inSeg._p1->_param )); break;
758 bndSegs.push_back( BndSeg( &inSeg, inSeg._edges.back(), inSeg._p1->_param )); break;
760 vector< double > len;
762 for ( e = inSeg._edges.rbegin(); e != inSeg._edges.rend(); ++e )
763 len.push_back( len.back() + length( *e ));
765 e = inSeg._edges.rbegin();
766 for ( size_t l = 1; l < len.size(); ++e, ++l )
768 double dl = len[l] / len.back();
769 double u = dl * inSeg._p1->_param + ( 1. - dl ) * inSeg._p0->_param;
770 bndSegs.push_back( BndSeg( &inSeg, *e, u ));
773 // segments around 2nd concave point
774 size_t ip1 = inSeg._p1->index( inPoints );
775 if ( inPntChecked[ ip1 ] )
776 for ( e = inSeg._p1->_edges.rbegin(); e != inSeg._p1->_edges.rend(); ++e )
777 bndSegs.push_back( BndSeg( &inSeg, *e, inSeg._p1->_param ));
778 inPntChecked[ ip1 ] = false;
781 // make TVDEdge's know it's BndSeg to enable passing branchID to
782 // an opposite BndSeg in BndSeg::setBranch()
783 for ( size_t i = 0; i < bndSegs.size(); ++i )
784 bndSegs[i].setIndexToEdge( i );
787 // Find TVDEdge's of Branches and associate them with bndSegs
789 vector< vector<const TVDEdge*> > branchEdges;
790 branchEdges.reserve( boundary.nbEdges() * 4 );
792 map< const TVDVertex*, SMESH_MAT2d::BranchEndType > endType;
794 int branchID = 1; // we code orientation as branchID sign
795 branchEdges.resize( branchID + 1 );
798 while ( i1st < bndSegs.size() && !bndSegs[i1st].hasOppositeEdge( noEdgeID ))
800 bndSegs[i1st].setBranch( branchID, bndSegs ); // set to i-th and the opposite bndSeg
801 branchEdges[ branchID ].push_back( bndSegs[i1st]._edge );
803 for ( size_t i = i1st+1; i < bndSegs.size(); ++i )
805 if ( bndSegs[i].branchID() )
807 branchID = bndSegs[i]._branchID; // with sign
809 if ( bndSegs[i]._branchID == -bndSegs[i-1]._branchID &&
812 SMESH_MAT2d::BranchEndType type =
813 ( bndSegs[i]._inSeg->isConnected( bndSegs[i]._edge ) ?
814 SMESH_MAT2d::BE_ON_VERTEX :
815 SMESH_MAT2d::BE_END );
816 endType.insert( make_pair( bndSegs[i]._edge->vertex1(), type ));
820 if ( !bndSegs[i-1].isSameBranch( bndSegs[i] ))
822 branchEdges.resize(( branchID = branchEdges.size()) + 1 );
823 if ( bndSegs[i]._edge )
824 endType.insert( make_pair( bndSegs[i]._edge->vertex1(),
825 SMESH_MAT2d::BE_BRANCH_POINT ));
827 bndSegs[i].setBranch( branchID, bndSegs ); // set to i-th and the opposite bndSeg
828 if ( bndSegs[i].hasOppositeEdge( noEdgeID ))
829 branchEdges[ bndSegs[i].branchID() ].push_back( bndSegs[i]._edge );
831 // define BranchEndType of the first TVDVertex
832 if ( bndSegs.front()._branchID == -bndSegs.back()._branchID )
834 if ( bndSegs[0]._edge )
836 SMESH_MAT2d::BranchEndType type =
837 ( bndSegs[0]._inSeg->isConnected( bndSegs[0]._edge ) ?
838 SMESH_MAT2d::BE_ON_VERTEX :
839 SMESH_MAT2d::BE_END );
840 endType.insert( make_pair( bndSegs[0]._edge->vertex1(), type ));
842 else if ( bndSegs.back()._edge )
844 SMESH_MAT2d::BranchEndType type =
845 ( bndSegs.back()._inSeg->isConnected( bndSegs.back()._edge ) ?
846 SMESH_MAT2d::BE_ON_VERTEX :
847 SMESH_MAT2d::BE_END );
848 endType.insert( make_pair( bndSegs.back()._edge->vertex0(), type ));
851 // join the 1st and the last branch edges if it is the same branch
852 if ( bndSegs.back().branchID() != bndSegs.front().branchID() &&
853 bndSegs.back().isSameBranch( bndSegs.front() ))
855 vector<const TVDEdge*> & br1 = branchEdges[ bndSegs.front().branchID() ];
856 vector<const TVDEdge*> & br2 = branchEdges[ bndSegs.back().branchID() ];
857 br1.insert( br1.begin(), br2.begin(), br2.end() );
861 // associate branchIDs and the input branch vector (arg)
862 vector< const SMESH_MAT2d::Branch* > branchByID( branchEdges.size(), 0 );
864 for ( size_t i = 0; i < branchEdges.size(); ++i )
866 nbBranches += ( !branchEdges[i].empty() );
868 branch.resize( nbBranches );
869 for ( size_t iBr = 0, brID = 0; brID < branchEdges.size(); ++brID )
871 if ( !branchEdges[ brID ].empty() )
872 branchByID[ brID ] = & branch[ iBr++ ];
875 // Fill in BndPoints of each EDGE of the boundary
878 int edgeInd = -1, dInd = 0;
879 while ( iSeg < bndSegs.size() )
881 const size_t geomID = bndSegs[ iSeg ].geomEdge();
882 SMESH_MAT2d::BndPoints & bndPoints = boundary.getPoints( geomID );
885 for ( size_t i = iSeg; i < bndSegs.size() && geomID == bndSegs[ i ].geomEdge(); ++i )
887 size_t iSegEnd = iSeg + nbSegs;
889 // make TVDEdge know an index of bndSegs within BndPoints
890 for ( size_t i = iSeg; i < iSegEnd; ++i )
891 if ( bndSegs[i]._edge )
892 SMESH_MAT2d::Branch::setBndSegment( i - iSeg, bndSegs[i]._edge );
894 // parameters on EDGE
896 bndPoints._params.reserve( nbSegs + 1 );
897 bndPoints._params.push_back( bndSegs[ iSeg ]._inSeg->_p0->_param );
899 for ( size_t i = iSeg; i < iSegEnd; ++i )
900 bndPoints._params.push_back( bndSegs[ i ]._uLast );
904 bndPoints._maEdges.reserve( nbSegs );
906 for ( size_t i = iSeg; i < iSegEnd; ++i )
908 const size_t brID = bndSegs[ i ].branchID();
909 const SMESH_MAT2d::Branch* br = branchByID[ brID ];
911 if ( bndSegs[ i ]._edge && !branchEdges[ brID ].empty() )
916 edgeInd >= (int) branchEdges[ brID ].size() ) ||
917 ( branchEdges[ brID ][ edgeInd ] != bndSegs[ i ]._edge &&
918 branchEdges[ brID ][ edgeInd ]->twin() != bndSegs[ i ]._edge ))
920 if ( bndSegs[ i ]._branchID < 0 )
923 for ( edgeInd = branchEdges[ brID ].size() - 1; edgeInd > 0; --edgeInd )
924 if ( branchEdges[ brID ][ edgeInd ]->twin() == bndSegs[ i ]._edge )
927 else // bndSegs[ i ]._branchID > 0
930 for ( edgeInd = 0; edgeInd < branchEdges[ brID ].size(); ++edgeInd )
931 if ( branchEdges[ brID ][ edgeInd ] == bndSegs[ i ]._edge )
938 // no MA edge, bndSeg corresponds to an end point of a branch
939 if ( bndPoints._maEdges.empty() )
941 // should not get here according to algo design???
946 edgeInd = branchEdges[ brID ].size();
947 dInd = bndSegs[ i ]._branchID > 0 ? +1 : -1;
951 bndPoints._maEdges.push_back( make_pair( br, ( 1 + edgeInd ) * dInd ));
953 } // loop on bndSegs of an EDGE
957 } // loop on all bndSegs
960 // fill the branches with MA edges
961 for ( size_t iBr = 0, brID = 0; brID < branchEdges.size(); ++brID )
962 if ( !branchEdges[brID].empty() )
964 branch[ iBr ].init( branchEdges[brID], & boundary, endType );
967 // set branches to branch ends
968 for ( size_t i = 0; i < branch.size(); ++i )
969 branch[i].setBranchesToEnds( branch );
971 // fill branchPnt arg
972 map< const TVDVertex*, const SMESH_MAT2d::BranchEnd* > v2end;
973 for ( size_t i = 0; i < branch.size(); ++i )
975 if ( branch[i].getEnd(0)->_branches.size() > 2 )
976 v2end.insert( make_pair( branch[i].getEnd(0)->_vertex, branch[i].getEnd(0) ));
977 if ( branch[i].getEnd(1)->_branches.size() > 2 )
978 v2end.insert( make_pair( branch[i].getEnd(1)->_vertex, branch[i].getEnd(1) ));
980 branchPnt.resize( v2end.size() );
981 map< const TVDVertex*, const SMESH_MAT2d::BranchEnd* >::iterator v2e = v2end.begin();
982 for ( size_t i = 0; v2e != v2end.end(); ++v2e, ++i )
983 branchPnt[ i ] = v2e->second;
989 //================================================================================
991 * \brief MedialAxis constructor
992 * \param [in] face - a face to create MA for
993 * \param [in] edges - edges of the face (possibly not all) on the order they
994 * encounter in the face boundary.
995 * \param [in] minSegLen - minimal length of a mesh segment used to discretize
996 * the edges. It is used to define precision of MA approximation
998 //================================================================================
1000 SMESH_MAT2d::MedialAxis::MedialAxis(const TopoDS_Face& face,
1001 const std::vector< TopoDS_Edge >& edges,
1002 const double minSegLen,
1003 const bool ignoreCorners):
1004 _face( face ), _boundary( edges.size() )
1006 // input to construct_voronoi()
1007 vector< InPoint > inPoints;
1008 vector< InSegment> inSegments;
1009 if ( !makeInputData( face, edges, minSegLen, inPoints, inSegments, _scale ))
1012 //inSegmentsToFile( inSegments );
1014 // build voronoi diagram
1015 construct_voronoi( inSegments.begin(), inSegments.end(), &_vd );
1018 makeMA( _vd, inPoints, inSegments, _branch, _branchPnt, _boundary );
1021 //================================================================================
1023 * \brief Return UVs of ends of MA edges of a branch
1025 //================================================================================
1027 void SMESH_MAT2d::MedialAxis::getPoints( const Branch& branch,
1028 std::vector< gp_XY >& points) const
1030 branch.getPoints( points, _scale );
1033 //================================================================================
1035 * \brief Returns a BranchPoint corresponding to a given point on a geom EDGE
1036 * \param [in] iGeomEdge - index of geom EDGE within a vector passed at MA construction
1037 * \param [in] u - parameter of the point on EDGE curve
1038 * \param [out] p - the found BranchPoint
1039 * \return bool - is OK
1041 //================================================================================
1043 bool SMESH_MAT2d::Boundary::getBranchPoint( const std::size_t iEdge,
1045 BranchPoint& p ) const
1047 if ( iEdge >= _pointsPerEdge.size() || _pointsPerEdge[iEdge]._params.empty() )
1050 const BndPoints& points = _pointsPerEdge[ iEdge ];
1051 const bool edgeReverse = ( points._params[0] > points._params.back() );
1053 if ( u < ( edgeReverse ? points._params.back() : points._params[0] ))
1054 u = edgeReverse ? points._params.back() : points._params[0];
1055 else if ( u > ( edgeReverse ? points._params[0] : points._params.back()) )
1056 u = edgeReverse ? points._params[0] : points._params.back();
1058 double r = ( u - points._params[0] ) / ( points._params.back() - points._params[0] );
1059 int i = int( r * double( points._maEdges.size()-1 ));
1062 while ( points._params[i ] < u ) --i;
1063 while ( points._params[i+1] > u ) ++i;
1067 while ( points._params[i ] > u ) --i;
1068 while ( points._params[i+1] < u ) ++i;
1071 double edgeParam = ( u - points._params[i] ) / ( points._params[i+1] - points._params[i] );
1073 if ( !points._maEdges[ i ].second ) // no branch at the EDGE end
1075 if ( i < points._maEdges.size() / 2 ) // near 1st point
1077 while ( i < points._maEdges.size()-1 && !points._maEdges[ i ].second )
1079 edgeParam = edgeReverse;
1081 else // near last point
1083 while ( i > 0 && !points._maEdges[ i ].second )
1085 edgeParam = !edgeReverse;
1088 const std::pair< const Branch*, int >& maE = points._maEdges[ i ];
1089 bool maReverse = ( maE.second < 0 );
1091 p._branch = maE.first;
1092 p._iEdge = ( maReverse ? -maE.second : maE.second ) - 1; // countered from 1 to store sign
1093 p._edgeParam = maReverse ? ( 1. - edgeParam ) : edgeParam;
1098 //================================================================================
1100 * \brief Check if a given boundary segment is a null-length segment on a concave
1102 * \param [in] iEdge - index of a geom EDGE
1103 * \param [in] iSeg - index of a boundary segment
1104 * \return bool - true if the segment is on concave corner
1106 //================================================================================
1108 bool SMESH_MAT2d::Boundary::IsConcaveSegment( std::size_t iEdge, std::size_t iSeg ) const
1110 if ( iEdge >= _pointsPerEdge.size() || _pointsPerEdge[iEdge]._params.empty() )
1113 const BndPoints& points = _pointsPerEdge[ iEdge ];
1114 if ( points._params.size() >= iSeg+1 )
1117 return Abs( points._params[ iEdge ] - points._params[ iEdge+1 ]) < 1e-20;
1120 //================================================================================
1122 * \brief Creates a 3d curve corresponding to a Branch
1123 * \param [in] branch - the Branch
1124 * \return Adaptor3d_Curve* - the new curve the caller is to delete
1126 //================================================================================
1128 Adaptor3d_Curve* SMESH_MAT2d::MedialAxis::make3DCurve(const Branch& branch) const
1130 Handle(Geom_Surface) surface = BRep_Tool::Surface( _face );
1131 if ( surface.IsNull() )
1135 branch.getPoints( uv, _scale );
1136 if ( uv.size() < 2 )
1139 vector< TopoDS_Vertex > vertex( uv.size() );
1140 for ( size_t i = 0; i < uv.size(); ++i )
1141 vertex[i] = BRepBuilderAPI_MakeVertex( surface->Value( uv[i].X(), uv[i].Y() ));
1144 BRep_Builder aBuilder;
1145 aBuilder.MakeWire(aWire);
1146 for ( size_t i = 1; i < vertex.size(); ++i )
1148 TopoDS_Edge edge = BRepBuilderAPI_MakeEdge( vertex[i-1], vertex[i] );
1149 aBuilder.Add( aWire, edge );
1152 // if ( myEdge.size() == 2 && FirstVertex().IsSame( LastVertex() ))
1153 // aWire.Closed(true); // issue 0021141
1155 return new BRepAdaptor_CompCurve( aWire );
1158 //================================================================================
1160 * \brief Copy points of an EDGE
1162 //================================================================================
1164 void SMESH_MAT2d::Branch::init( vector<const TVDEdge*>& maEdges,
1165 const Boundary* boundary,
1166 map< const TVDVertex*, BranchEndType > endType )
1168 if ( maEdges.empty() ) return;
1170 _boundary = boundary;
1171 _maEdges.swap( maEdges );
1174 _params.reserve( _maEdges.size() + 1 );
1175 _params.push_back( 0. );
1176 for ( size_t i = 0; i < _maEdges.size(); ++i )
1177 _params.push_back( _params.back() + length( _maEdges[i] ));
1179 for ( size_t i = 1; i < _params.size(); ++i )
1180 _params[i] /= _params.back();
1183 _endPoint1._vertex = _maEdges.front()->vertex1();
1184 _endPoint2._vertex = _maEdges.back ()->vertex0();
1186 if ( endType.count( _endPoint1._vertex ))
1187 _endPoint1._type = endType[ _endPoint1._vertex ];
1188 if ( endType.count( _endPoint2._vertex ))
1189 _endPoint2._type = endType[ _endPoint2._vertex ];
1192 //================================================================================
1194 * \brief fill BranchEnd::_branches of its ends
1196 //================================================================================
1198 void SMESH_MAT2d::Branch::setBranchesToEnds( const vector< Branch >& branches )
1200 for ( size_t i = 0; i < branches.size(); ++i )
1202 if ( this->_endPoint1._vertex == branches[i]._endPoint1._vertex ||
1203 this->_endPoint1._vertex == branches[i]._endPoint2._vertex )
1204 this->_endPoint1._branches.push_back( &branches[i] );
1206 if ( this->_endPoint2._vertex == branches[i]._endPoint1._vertex ||
1207 this->_endPoint2._vertex == branches[i]._endPoint2._vertex )
1208 this->_endPoint2._branches.push_back( &branches[i] );
1212 //================================================================================
1214 * \brief Returns points on two EDGEs, equidistant from a given point of this Branch
1215 * \param [in] param - [0;1] normalized param on the Branch
1216 * \param [out] bp1 - BoundaryPoint on EDGE with a lower index
1217 * \param [out] bp2 - BoundaryPoint on EDGE with a higher index
1218 * \return bool - true if the BoundaryPoint's found
1220 //================================================================================
1222 bool SMESH_MAT2d::Branch::getBoundaryPoints(double param,
1224 BoundaryPoint& bp2 ) const
1226 if ( param < _params[0] || param > _params.back() )
1229 // look for an index of a MA edge by param
1230 double ip = param * _params.size();
1231 size_t i = size_t( Min( int( _maEdges.size()-1), int( ip )));
1233 while ( param < _params[i ] ) --i;
1234 while ( param > _params[i+1] ) ++i;
1236 double r = ( param - _params[i] ) / ( _params[i+1] - _params[i] );
1238 return getBoundaryPoints( i, r, bp1, bp2 );
1241 //================================================================================
1243 * \brief Returns points on two EDGEs, equidistant from a given point of this Branch
1244 * \param [in] iMAEdge - index of a MA edge within this Branch
1245 * \param [in] maEdgeParam - [0;1] normalized param on the \a iMAEdge
1246 * \param [out] bp1 - BoundaryPoint on EDGE with a lower index
1247 * \param [out] bp2 - BoundaryPoint on EDGE with a higher index
1248 * \return bool - true if the BoundaryPoint's found
1250 //================================================================================
1252 bool SMESH_MAT2d::Branch::getBoundaryPoints(std::size_t iMAEdge,
1255 BoundaryPoint& bp2 ) const
1257 if ( iMAEdge > _maEdges.size() )
1259 if ( iMAEdge == _maEdges.size() )
1260 iMAEdge = _maEdges.size() - 1;
1262 size_t iGeom1 = getGeomEdge( _maEdges[ iMAEdge ] );
1263 size_t iGeom2 = getGeomEdge( _maEdges[ iMAEdge ]->twin() );
1264 size_t iSeg1 = getBndSegment( _maEdges[ iMAEdge ] );
1265 size_t iSeg2 = getBndSegment( _maEdges[ iMAEdge ]->twin() );
1267 return ( _boundary->getPoint( iGeom1, iSeg1, maEdgeParam, bp1 ) &&
1268 _boundary->getPoint( iGeom2, iSeg2, maEdgeParam, bp2 ));
1271 //================================================================================
1273 * \brief Returns points on two EDGEs, equidistant from a given point of this Branch
1275 //================================================================================
1277 bool SMESH_MAT2d::Branch::getBoundaryPoints(const BranchPoint& p,
1279 BoundaryPoint& bp2 ) const
1281 return ( p._branch ? p._branch : this )->getBoundaryPoints( p._iEdge, p._edgeParam, bp1, bp2 );
1284 //================================================================================
1286 * \brief Return a parameter of a BranchPoint normalized within this Branch
1288 //================================================================================
1290 bool SMESH_MAT2d::Branch::getParameter(const BranchPoint & p, double & u ) const
1292 if ( p._iEdge > _params.size()-1 )
1294 if ( p._iEdge == _params.size()-1 )
1297 u = ( _params[ p._iEdge ] * ( 1 - p._edgeParam ) +
1298 _params[ p._iEdge+1 ] * p._edgeParam );
1303 //================================================================================
1305 * \brief Check type of both ends
1307 //================================================================================
1309 bool SMESH_MAT2d::Branch::hasEndOfType(BranchEndType type) const
1311 return ( _endPoint1._type == type || _endPoint2._type == type );
1314 //================================================================================
1316 * \brief Returns MA points
1317 * \param [out] points - the 2d points
1318 * \param [in] scale - the scale that was used to scale the 2d space of MA
1320 //================================================================================
1322 void SMESH_MAT2d::Branch::getPoints( std::vector< gp_XY >& points,
1323 const double scale[2]) const
1325 points.resize( _maEdges.size() + 1 );
1327 points[0].SetCoord( _maEdges[0]->vertex1()->x() / scale[0], // CCW order! -> vertex1 not vertex0
1328 _maEdges[0]->vertex1()->y() / scale[1] );
1330 for ( size_t i = 0; i < _maEdges.size(); ++i )
1331 points[i+1].SetCoord( _maEdges[i]->vertex0()->x() / scale[0],
1332 _maEdges[i]->vertex0()->y() / scale[1] );
1335 //================================================================================
1337 * \brief Return indices of EDGEs equidistant from this branch
1339 //================================================================================
1341 void SMESH_MAT2d::Branch::getGeomEdges( std::vector< std::size_t >& edgeIDs1,
1342 std::vector< std::size_t >& edgeIDs2 ) const
1344 edgeIDs1.push_back( getGeomEdge( _maEdges[0] ));
1345 edgeIDs2.push_back( getGeomEdge( _maEdges[0]->twin() ));
1347 for ( size_t i = 1; i < _maEdges.size(); ++i )
1349 size_t ie1 = getGeomEdge( _maEdges[i] );
1350 size_t ie2 = getGeomEdge( _maEdges[i]->twin() );
1352 if ( edgeIDs1.back() != ie1 ) edgeIDs1.push_back( ie1 );
1353 if ( edgeIDs2.back() != ie2 ) edgeIDs2.push_back( ie2 );
1357 //================================================================================
1359 * \brief Looks for a BranchPoint position around a concave VERTEX
1361 //================================================================================
1363 bool SMESH_MAT2d::Branch::addDivPntForConcaVertex( std::vector< std::size_t >& edgeIDs1,
1364 std::vector< std::size_t >& edgeIDs2,
1365 std::vector< BranchPoint >& divPoints,
1366 const vector<const TVDEdge*>& maEdges,
1367 const vector<const TVDEdge*>& maEdgesTwin,
1370 // if there is a concave vertex between EDGEs
1371 // then position of a dividing BranchPoint is undefined, it is somewhere
1372 // on an arc-shaped part of the Branch around the concave vertex.
1373 // Chose this position by a VERTEX of the opposite EDGE, or put it in the middle
1374 // of the arc if there is no opposite VERTEX.
1375 // All null-length segments around a VERTEX belong to one of EDGEs.
1377 BranchPoint divisionPnt;
1378 divisionPnt._branch = this;
1380 size_t ie1 = getGeomEdge( maEdges [i] );
1381 size_t ie2 = getGeomEdge( maEdgesTwin[i] );
1383 size_t iSeg1 = getBndSegment( maEdges[ i-1 ] );
1384 size_t iSeg2 = getBndSegment( maEdges[ i ] );
1385 bool isConcaPrev = _boundary->IsConcaveSegment( edgeIDs1.back(), iSeg1 );
1386 bool isConcaNext = _boundary->IsConcaveSegment( ie1, iSeg2 );
1387 if ( !isConcaNext && !isConcaPrev )
1390 bool isConcaveV = false;
1392 int iPrev = i-1, iNext = i;
1393 if ( isConcaNext ) // all null-length segments follow
1395 // look for a VERTEX of the opposite EDGE
1396 ++iNext; // end of null-length segments
1397 while ( iNext < maEdges.size() )
1399 iSeg2 = getBndSegment( maEdges[ iNext ] );
1400 if ( _boundary->IsConcaveSegment( ie1, iSeg2 ))
1405 bool vertexFound = false;
1406 for ( size_t iE = i+1; iE < iNext; ++iE )
1408 ie2 = getGeomEdge( maEdgesTwin[iE] );
1409 if ( ie2 != edgeIDs2.back() )
1411 // opposite VERTEX found
1412 divisionPnt._iEdge = iE;
1413 divisionPnt._edgeParam = 0;
1414 divPoints.push_back( divisionPnt );
1415 edgeIDs1.push_back( ie1 );
1416 edgeIDs2.push_back( ie2 );
1426 else if ( isConcaPrev )
1428 // all null-length segments passed, find their beginning
1429 while ( iPrev-1 >= 0 )
1431 iSeg1 = getBndSegment( maEdges[ iPrev-1 ] );
1432 if ( _boundary->IsConcaveSegment( edgeIDs1.back(), iSeg1 ))
1439 if ( iPrev < i-1 || iNext > i )
1441 // no VERTEX on the opposite EDGE, put the Branch Point in the middle
1442 double par1 = _params[ iPrev ], par2 = _params[ iNext ];
1443 double midPar = 0.5 * ( par1 + par2 );
1444 divisionPnt._iEdge = iPrev;
1445 while ( _params[ divisionPnt._iEdge + 1 ] < midPar )
1446 ++divisionPnt._iEdge;
1447 divisionPnt._edgeParam =
1448 ( _params[ divisionPnt._iEdge + 1 ] - midPar ) /
1449 ( _params[ divisionPnt._iEdge + 1 ] - _params[ divisionPnt._iEdge ] );
1450 divPoints.push_back( divisionPnt );
1457 //================================================================================
1459 * \brief Return indices of opposite parts of EDGEs equidistant from this branch
1460 * \param [out] edgeIDs1 - EDGE index opposite to the edgeIDs2[i]-th EDGE
1461 * \param [out] edgeIDs2 - EDGE index opposite to the edgeIDs1[i]-th EDGE
1462 * \param [out] divPoints - BranchPoint's located between two successive unique
1463 * pairs of EDGE indices. A \a divPoints[i] can separate e.g. two following pairs
1464 * of EDGE indices < 0, 2 > and < 0, 1 >. Number of \a divPoints is one less
1465 * than number of \a edgeIDs
1467 //================================================================================
1469 void SMESH_MAT2d::Branch::getOppositeGeomEdges( std::vector< std::size_t >& edgeIDs1,
1470 std::vector< std::size_t >& edgeIDs2,
1471 std::vector< BranchPoint >& divPoints) const
1477 edgeIDs1.push_back( getGeomEdge( _maEdges[0] ));
1478 edgeIDs2.push_back( getGeomEdge( _maEdges[0]->twin() ));
1480 std::vector<const TVDEdge*> twins( _maEdges.size() );
1481 for ( size_t i = 0; i < _maEdges.size(); ++i )
1482 twins[i] = _maEdges[i]->twin();
1484 // size_t lastConcaE1 = _boundary.nbEdges();
1485 // size_t lastConcaE2 = _boundary.nbEdges();
1487 BranchPoint divisionPnt;
1488 divisionPnt._branch = this;
1490 for ( size_t i = 0; i < _maEdges.size(); ++i )
1492 size_t ie1 = getGeomEdge( _maEdges[i] );
1493 size_t ie2 = getGeomEdge( _maEdges[i]->twin() );
1495 if ( edgeIDs1.back() != ie1 || edgeIDs2.back() != ie2 )
1497 bool isConcaveV = false;
1498 if ( edgeIDs1.back() != ie1 && edgeIDs2.back() == ie2 )
1500 isConcaveV = addDivPntForConcaVertex( edgeIDs1, edgeIDs2, divPoints, _maEdges, twins, i );
1502 if ( edgeIDs1.back() == ie1 && edgeIDs2.back() != ie2 )
1504 isConcaveV = addDivPntForConcaVertex( edgeIDs2, edgeIDs1, divPoints, twins, _maEdges, i );
1509 ie1 = getGeomEdge( _maEdges[i] );
1510 ie2 = getGeomEdge( _maEdges[i]->twin() );
1512 if (( !isConcaveV ) ||
1513 ( edgeIDs1.back() != ie1 || edgeIDs2.back() != ie2 ))
1515 edgeIDs1.push_back( ie1 );
1516 edgeIDs2.push_back( ie2 );
1518 if ( divPoints.size() < edgeIDs1.size() - 1 )
1520 divisionPnt._iEdge = i;
1521 divisionPnt._edgeParam = 0;
1522 divPoints.push_back( divisionPnt );
1525 } // if ( edgeIDs1.back() != ie1 || edgeIDs2.back() != ie2 )
1526 } // loop on _maEdges
1529 //================================================================================
1531 * \brief Store data of boundary segments in TVDEdge
1533 //================================================================================
1535 void SMESH_MAT2d::Branch::setGeomEdge( std::size_t geomIndex, const TVDEdge* maEdge )
1537 if ( maEdge ) maEdge->cell()->color( geomIndex );
1539 std::size_t SMESH_MAT2d::Branch::getGeomEdge( const TVDEdge* maEdge )
1541 return maEdge ? maEdge->cell()->color() : std::string::npos;
1543 void SMESH_MAT2d::Branch::setBndSegment( std::size_t segIndex, const TVDEdge* maEdge )
1545 if ( maEdge ) maEdge->color( segIndex );
1547 std::size_t SMESH_MAT2d::Branch::getBndSegment( const TVDEdge* maEdge )
1549 return maEdge ? maEdge->color() : std::string::npos;
1552 //================================================================================
1554 * \brief Returns a boundary point on a given EDGE
1555 * \param [in] iEdge - index of the EDGE within MedialAxis
1556 * \param [in] iSeg - index of a boundary segment within this Branch
1557 * \param [in] u - [0;1] normalized param within \a iSeg-th segment
1558 * \param [out] bp - the found BoundaryPoint
1559 * \return bool - true if the BoundaryPoint is found
1561 //================================================================================
1563 bool SMESH_MAT2d::Boundary::getPoint( std::size_t iEdge,
1566 BoundaryPoint& bp ) const
1568 if ( iEdge >= _pointsPerEdge.size() )
1570 if ( iSeg+1 >= _pointsPerEdge[ iEdge ]._params.size() )
1573 // This method is called by Branch that can have an opposite orientation,
1574 // hence u is inverted depending on orientation coded as a sign of _maEdge index
1575 bool isReverse = ( _pointsPerEdge[ iEdge ]._maEdges[ iSeg ].second < 0 );
1579 double p0 = _pointsPerEdge[ iEdge ]._params[ iSeg ];
1580 double p1 = _pointsPerEdge[ iEdge ]._params[ iSeg+1 ];
1582 bp._param = p0 * ( 1. - u ) + p1 * u;
1583 bp._edgeIndex = iEdge;