</hypotheses-set-group>
</meshers>
~~~~~~
+ If the file contents are incorrect, there can be an error at
+ activation of Mesh module: <em>"fatal parsing error: error
+ triggered by consumer in line ..."</em>
<br>
<center>
\image html hypo_sets.png
Medial Axis Projection algorithm can be used for meshing faces with
sinuous borders and having channel-like shape, for which is it
difficult to define 1D hypotheses so that generated quadrangles to be
-of good shape.
+of good shape. The algorithm can be also applied to faces with ring
+topology, which can be viewed as a closed 'channel'. In the latter
+case radial discretization of a ring can be specified by
+using <em>Number of Layers</em> or <em>Distribution of Layers</em>
+hypothesis.
-\image html quad_from_ma_mesh.png "A mesh of a river model"
+\image html quad_from_ma_mesh.png "A mesh of a river model to the left and of a ring-face to the right"
The algorithm assures good shape of quadrangles by constructing Medial
Axis between sinuous borders of the face and using it to
-discretize the borders.
+discretize the borders. (Shape of quadrangles can be not perfect at
+locations where opposite sides of a 'channel' are far from being parallel.)
\image html quad_from_ma_medial_axis.png "Medial Axis between two blue sinuous borders"
{
if ( sm )
_sm_current.push_back( sm );
- else
+
+ else if ( !_sm_current.empty() )
_sm_current.pop_back();
}
ASSERT( theTrack );
SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
+ if ( !pSubMeshDS )
+ return ExtrusionAlongTrack( theElements, theTrack->GetFather(), theN1,
+ theHasAngles, theAngles, theLinearVariation,
+ theHasRefPoint, theRefPoint, theMakeGroups );
aItE = pSubMeshDS->GetElements();
while ( aItE->more() ) {
if ( !_edge || !seg2._edge )
return true;
+ if ( _edge->twin() == seg2._edge )
+ return true;
+
const TVDCell* cell1 = this->_edge->twin()->cell();
const TVDCell* cell2 = seg2. _edge->twin()->cell();
if ( cell1 == cell2 )
else if ( edgeMedium1->is_primary() && edgeMedium2->is_primary() )
{
if ( edgeMedium1->twin() == edgeMedium2 &&
- SMESH_MAT2d::Branch::getBndSegment( edgeMedium1 ) ==
- SMESH_MAT2d::Branch::getBndSegment( edgeMedium2 ))
+ SMESH_MAT2d::Branch::getGeomEdge( edgeMedium1 ) ==
+ SMESH_MAT2d::Branch::getGeomEdge( edgeMedium2 ))
// this is an ignored MA edge between inSegment's on one EDGE forming a convex corner
return true;
}
*/
//================================================================================
- void bndSegsToMesh( const vector< BndSeg >& bndSegs )
+ void bndSegsToMesh( const vector< vector< BndSeg > >& bndSegsPerEdge )
{
#ifdef _MYDEBUG_
if ( !getenv("bndSegsToMesh")) return;
text << "from salome.smesh import smeshBuilder\n";
text << "smesh = smeshBuilder.New(salome.myStudy)\n";
text << "m=smesh.Mesh()\n";
- for ( size_t i = 0; i < bndSegs.size(); ++i )
+ for ( size_t iE = 0; iE < bndSegsPerEdge.size(); ++iE )
{
- if ( !bndSegs[i]._edge )
- text << "# " << i << " NULL edge\n";
- else if ( !bndSegs[i]._edge->vertex0() ||
- !bndSegs[i]._edge->vertex1() )
- text << "# " << i << " INFINITE edge\n";
- else if ( addedEdges.insert( bndSegs[i]._edge ).second &&
- addedEdges.insert( bndSegs[i]._edge->twin() ).second )
+ const vector< BndSeg >& bndSegs = bndSegsPerEdge[ iE ];
+ for ( size_t i = 0; i < bndSegs.size(); ++i )
{
- v2n = v2Node.insert( make_pair( bndSegs[i]._edge->vertex0(), v2Node.size() + 1 )).first;
- int n0 = v2n->second;
- if ( n0 == v2Node.size() )
- text << "n" << n0 << " = m.AddNode( "
- << bndSegs[i]._edge->vertex0()->x() / theScale[0] << ", "
- << bndSegs[i]._edge->vertex0()->y() / theScale[1] << ", 0 )\n";
-
- v2n = v2Node.insert( make_pair( bndSegs[i]._edge->vertex1(), v2Node.size() + 1 )).first;
- int n1 = v2n->second;
- if ( n1 == v2Node.size() )
- text << "n" << n1 << " = m.AddNode( "
- << bndSegs[i]._edge->vertex1()->x() / theScale[0] << ", "
- << bndSegs[i]._edge->vertex1()->y() / theScale[1] << ", 0 )\n";
-
- text << "e" << i << " = m.AddEdge([ n" << n0 << ", n" << n1 << " ])\n";
+ if ( !bndSegs[i]._edge )
+ text << "# E=" << iE << " i=" << i << " NULL edge\n";
+ else if ( !bndSegs[i]._edge->vertex0() ||
+ !bndSegs[i]._edge->vertex1() )
+ text << "# E=" << iE << " i=" << i << " INFINITE edge\n";
+ else if ( addedEdges.insert( bndSegs[i]._edge ).second &&
+ addedEdges.insert( bndSegs[i]._edge->twin() ).second )
+ {
+ v2n = v2Node.insert( make_pair( bndSegs[i]._edge->vertex0(), v2Node.size() + 1 )).first;
+ int n0 = v2n->second;
+ if ( n0 == v2Node.size() )
+ text << "n" << n0 << " = m.AddNode( "
+ << bndSegs[i]._edge->vertex0()->x() / theScale[0] << ", "
+ << bndSegs[i]._edge->vertex0()->y() / theScale[1] << ", 0 )\n";
+
+ v2n = v2Node.insert( make_pair( bndSegs[i]._edge->vertex1(), v2Node.size() + 1 )).first;
+ int n1 = v2n->second;
+ if ( n1 == v2Node.size() )
+ text << "n" << n1 << " = m.AddNode( "
+ << bndSegs[i]._edge->vertex1()->x() / theScale[0] << ", "
+ << bndSegs[i]._edge->vertex1()->y() / theScale[1] << ", 0 )\n";
+
+ text << "e" << i << " = m.AddEdge([ n" << n0 << ", n" << n1 << " ])\n";
+ }
}
}
text << "\n";
bndSegs[0].setIndexToEdge( 0 );
}
- //bndSegsToMesh( bndSegsPerEdge ); // debug: visually check found MA edges
+ bndSegsToMesh( bndSegsPerEdge ); // debug: visually check found MA edges
// Find TVDEdge's of Branches and associate them with bndSegs
while ( points._params[i+1] < u ) ++i;
}
+ if ( points._params[i] == points._params[i+1] ) // coincident points at some end
+ {
+ int di = ( points._params[0] == points._params[i] ) ? +1 : -1;
+ while ( points._params[i] == points._params[i+1] )
+ i += di;
+ if ( i < 0 || i+1 >= points._params.size() )
+ i = 0;
+ }
+
double edgeParam = ( u - points._params[i] ) / ( points._params[i+1] - points._params[i] );
if ( !points._maEdges[ i ].second ) // no branch at the EDGE end, look for a closest branch
{
SMESH::Filter::Criterion& crit = criteria[ i ];
- if ( SMESH::FunctorType( crit.Type ) == SMESH::FT_BelongToMeshGroup )
+ if ( SMESH::FunctorType( crit.Type ) == SMESH::FT_BelongToMeshGroup &&
+ crit.ThresholdID.in() && crit.ThresholdID.in()[0] )
{
CORBA::Object_var obj = SMESH_Gen_i::GetORB()->string_to_object( crit.ThresholdID );
if ( SMESH_GroupBase_i * g = SMESH::DownCast< SMESH_GroupBase_i*>( obj ))
if ( !aMeshImp ) return aGroups._retn();
TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( thePathShape );
aSubMesh = aMeshImp->GetImpl().GetSubMesh( aShape );
- if ( !aSubMesh || !aSubMesh->GetSubMeshDS() )
+ if ( !aSubMesh /*|| !aSubMesh->GetSubMeshDS()*/ )
return aGroups._retn();
}
pass # end of StdMeshersBuilder_Prism3D class
-## Defines a Prism 3D algorithm, which is either "Extrusion 3D" or "Radial Prism"
-# depending on geometry
+## Defines a Prism 3D algorithm
#
# It is created by calling smeshBuilder.Mesh.Prism(geom=0)
#
self.nbLayers = None
return
-## Defines a Radial Quadrangle 1D-2D algorithm
+## Base class for algorithms supporting radial distribution hypotheses
#
-# It is created by calling smeshBuilder.Mesh.Quadrangle(smeshBuilder.RADIAL_QUAD,geom=0)
-#
-# @ingroup l2_algos_radialq
-class StdMeshersBuilder_RadialQuadrangle1D2D(Mesh_Algorithm):
-
- ## name of the dynamic method in smeshBuilder.Mesh class
- # @internal
- meshMethod = "Quadrangle"
- ## type of algorithm used with helper function in smeshBuilder.Mesh class
- # @internal
- algoType = RADIAL_QUAD
- ## doc string of the method
- # @internal
- docHelper = "Creates quadrangle 1D-2D algorithm for faces having a shape of disk or a disk segment"
+class StdMeshersBuilder_RadialAlgorithm(Mesh_Algorithm):
- ## Private constructor.
- # @param mesh parent mesh object algorithm is assigned to
- # @param geom geometry (shape/sub-shape) algorithm is assigned to;
- # if it is @c 0 (default), the algorithm is assigned to the main shape
- def __init__(self, mesh, geom=0):
+ def __init__(self):
Mesh_Algorithm.__init__(self)
- self.Create(mesh, geom, self.algoType)
self.distribHyp = None #self.Hypothesis("LayerDistribution2D", UseExisting=0)
self.nbLayers = None
pass # end of StdMeshersBuilder_RadialQuadrangle1D2D class
+## Defines a Radial Quadrangle 1D-2D algorithm
+#
+# It is created by calling smeshBuilder.Mesh.Quadrangle(smeshBuilder.RADIAL_QUAD,geom=0)
+#
+# @ingroup l2_algos_radialq
+class StdMeshersBuilder_RadialQuadrangle1D2D(StdMeshersBuilder_RadialAlgorithm):
+
+ ## name of the dynamic method in smeshBuilder.Mesh class
+ # @internal
+ meshMethod = "Quadrangle"
+ ## type of algorithm used with helper function in smeshBuilder.Mesh class
+ # @internal
+ algoType = RADIAL_QUAD
+ ## doc string of the method
+ # @internal
+ docHelper = "Creates quadrangle 1D-2D algorithm for faces having a shape of disk or a disk segment"
+
+ ## Private constructor.
+ # @param mesh parent mesh object algorithm is assigned to
+ # @param geom geometry (shape/sub-shape) algorithm is assigned to;
+ # if it is @c 0 (default), the algorithm is assigned to the main shape
+ def __init__(self, mesh, geom=0):
+ StdMeshersBuilder_RadialAlgorithm.__init__(self)
+ self.Create(mesh, geom, self.algoType)
+
+ self.distribHyp = None #self.Hypothesis("LayerDistribution2D", UseExisting=0)
+ self.nbLayers = None
+ pass
+
+
## Defines a Quadrangle (Medial Axis Projection) 1D-2D algorithm
#
# It is created by calling smeshBuilder.Mesh.Quadrangle(smeshBuilder.QUAD_MA_PROJ,geom=0)
#
# @ingroup l2_algos_quad_ma
-class StdMeshersBuilder_QuadMA_1D2D(Mesh_Algorithm):
+class StdMeshersBuilder_QuadMA_1D2D(StdMeshersBuilder_RadialAlgorithm):
## name of the dynamic method in smeshBuilder.Mesh class
# @internal
# @param geom geometry (shape/sub-shape) algorithm is assigned to;
# if it is @c 0 (default), the algorithm is assigned to the main shape
def __init__(self, mesh, geom=0):
- Mesh_Algorithm.__init__(self)
+ StdMeshersBuilder_RadialAlgorithm.__init__(self)
self.Create(mesh, geom, self.algoType)
pass
if isinstance( RefPoint, geomBuilder.GEOM._objref_GEOM_Object):
RefPoint = self.smeshpyD.GetPointStruct(RefPoint)
if isinstance( RefPoint, list ):
+ if not RefPoint: RefPoint = [0,0,0]
RefPoint = SMESH.PointStruct( *RefPoint )
if isinstance( PathMesh, Mesh ):
PathMesh = PathMesh.GetMesh()
# only SMESH::Extrusion_Error otherwise
# @ingroup l2_modif_extrurev
def ExtrusionAlongPathX(self, Base, Path, NodeStart,
- HasAngles, Angles, LinearVariation,
- HasRefPoint, RefPoint, MakeGroups, ElemType):
+ HasAngles=False, Angles=[], LinearVariation=False,
+ HasRefPoint=False, RefPoint=[0,0,0], MakeGroups=False,
+ ElemType=SMESH.FACE):
n,e,f = [],[],[]
if ElemType == SMESH.NODE: n = Base
if ElemType == SMESH.EDGE: e = Base
# only SMESH::Extrusion_Error otherwise
# @ingroup l2_modif_extrurev
def ExtrusionAlongPath(self, IDsOfElements, PathMesh, PathShape, NodeStart,
- HasAngles, Angles, HasRefPoint, RefPoint,
+ HasAngles=False, Angles=[], HasRefPoint=False, RefPoint=[],
MakeGroups=False, LinearVariation=False):
n,e,f = [],IDsOfElements,IDsOfElements
gr,er = self.ExtrusionAlongPathObjects(n,e,f, PathMesh, PathShape,
# only SMESH::Extrusion_Error otherwise
# @ingroup l2_modif_extrurev
def ExtrusionAlongPathObject(self, theObject, PathMesh, PathShape, NodeStart,
- HasAngles, Angles, HasRefPoint, RefPoint,
+ HasAngles=False, Angles=[], HasRefPoint=False, RefPoint=[],
MakeGroups=False, LinearVariation=False):
n,e,f = [],theObject,theObject
gr,er = self.ExtrusionAlongPathObjects(n,e,f, PathMesh, PathShape, NodeStart,
# only SMESH::Extrusion_Error otherwise
# @ingroup l2_modif_extrurev
def ExtrusionAlongPathObject1D(self, theObject, PathMesh, PathShape, NodeStart,
- HasAngles, Angles, HasRefPoint, RefPoint,
+ HasAngles=False, Angles=[], HasRefPoint=False, RefPoint=[],
MakeGroups=False, LinearVariation=False):
n,e,f = [],theObject,[]
gr,er = self.ExtrusionAlongPathObjects(n,e,f, PathMesh, PathShape, NodeStart,
# only SMESH::Extrusion_Error otherwise
# @ingroup l2_modif_extrurev
def ExtrusionAlongPathObject2D(self, theObject, PathMesh, PathShape, NodeStart,
- HasAngles, Angles, HasRefPoint, RefPoint,
+ HasAngles=False, Angles=[], HasRefPoint=False, RefPoint=[],
MakeGroups=False, LinearVariation=False):
n,e,f = [],[],theObject
gr,er = self.ExtrusionAlongPathObjects(n,e,f, PathMesh, PathShape, NodeStart,
attr = hypo_so_i.FindAttribute("AttributeIOR")[1]
if attr is not None:
anIOR = attr.Value()
+ if not anIOR: continue # prevent exception in orb.string_to_object()
hypo_o_i = salome.orb.string_to_object(anIOR)
if hypo_o_i is not None:
# Check if this is a hypothesis
attr = algo_so_i.FindAttribute("AttributeIOR")[1]
if attr is not None:
anIOR = attr.Value()
+ if not anIOR: continue # prevent exception in orb.string_to_object()
algo_o_i = salome.orb.string_to_object(anIOR)
if algo_o_i is not None:
# Check if this is an algorithm
const vector< Handle(Geom_Curve) >& theCurves = theSinuFace._sinuCurves;
double uMA;
- SMESH_MAT2d::BoundaryPoint bp[2];
+ SMESH_MAT2d::BoundaryPoint bp[2]; // 2 sinuous sides
const SMESH_MAT2d::Branch& branch = *theMA.getBranch(0);
{
// add to thePointsOnE NodePoint's of ends of theSinuEdges
// projection is set to the BoundaryPoint of this projection
// evaluate distance to neighbor projections
- const double rShort = 0.2;
+ const double rShort = 0.33;
bool isShortPrev[2], isShortNext[2], isPrevCloser[2];
TMAPar2NPoints::iterator u2NPPrev = u2NP, u2NPNext = u2NP;
--u2NPPrev; ++u2NPNext;
TIterator u2NPprev = sameU2NP.front();
TIterator u2NPnext = sameU2NP.back() ;
- if ( u2NPprev->first > 0. ) --u2NPprev;
- if ( u2NPnext->first < 1. ) ++u2NPprev;
+ if ( u2NPprev->first < 0. ) ++u2NPprev;
+ if ( u2NPnext->first > 1. ) --u2NPnext;
set< int >::iterator edgeID = edgeInds.begin();
for ( ; edgeID != edgeInds.end(); ++edgeID )
if ( u0 == u1 )
{
- if ( np->_node ) --u2NPprev;
- else ++u2NPnext;
+ if ( u2NPprev != thePointsOnE.begin() ) --u2NPprev;
+ if ( u2NPnext != --thePointsOnE.end() ) ++u2NPnext;
np = &get( u2NPprev->second, iSide );
u0 = getUOnEdgeByPoint( *edgeID, np, theSinuFace );
np = &get( u2NPnext->second, iSide );
}
// distribute points and create nodes
- double du = ( u1 - u0 ) / ( sameU2NP.size() + !existingNode );
+ double du = ( u1 - u0 ) / ( sameU2NP.size() + 1 /*!existingNode*/ );
double u = u0 + du;
for ( size_t i = 0; i < sameU2NP.size(); ++i )
{
theFace._quad->side[ 1 ] = StdMeshers_FaceSide::New( uvsNew );
}
- if ( theFace._quad->side[ 1 ].NbPoints() !=
- theFace._quad->side[ 3 ].NbPoints())
+ if ( theFace._quad->side[ 1 ].GetUVPtStruct().empty() ||
+ theFace._quad->side[ 3 ].GetUVPtStruct().empty() )
return false;
} // if ( theFace.IsRing() )
vector< int > edgeIDs ( theSinuEdges.size() ); // IDs in the main shape
vector< bool > isComputed( theSinuEdges.size() );
curves.resize( theSinuEdges.size(), 0 );
+ bool allComputed = true;
for ( size_t i = 0; i < theSinuEdges.size(); ++i )
{
curves[i] = BRep_Tool::Curve( theSinuEdges[i], f,l );
SMESH_subMesh* sm = mesh->GetSubMesh( theSinuEdges[i] );
edgeIDs [i] = sm->GetId();
isComputed[i] = ( !sm->IsEmpty() );
+ if ( !isComputed[i] )
+ allComputed = false;
}
const SMESH_MAT2d::Branch& branch = *theMA.getBranch(0);
vector< std::size_t > edgeIDs1, edgeIDs2; // indices in theSinuEdges
vector< SMESH_MAT2d::BranchPoint > divPoints;
- branch.getOppositeGeomEdges( edgeIDs1, edgeIDs2, divPoints );
+ if ( !allComputed )
+ branch.getOppositeGeomEdges( edgeIDs1, edgeIDs2, divPoints );
+
for ( size_t i = 0; i < edgeIDs1.size(); ++i )
if ( isComputed[ edgeIDs1[i]] &&
isComputed[ edgeIDs2[i]] )
return false;
}
- // map param on MA to parameters of nodes on a pair of theSinuEdges
+ // map (param on MA) to (parameters of nodes on a pair of theSinuEdges)
TMAPar2NPoints pointsOnE;
vector<double> maParams;
+ set<int> projectedEdges; // treated EDGEs which 'isComputed'
// compute params of nodes on EDGEs by projecting division points from MA
for ( size_t iEdgePair = 0; iEdgePair < edgeIDs1.size(); ++iEdgePair )
// loop on pairs of opposite EDGEs
{
+ if ( projectedEdges.count( edgeIDs1[ iEdgePair ]) ||
+ projectedEdges.count( edgeIDs2[ iEdgePair ]) )
+ continue;
+
// --------------------------------------------------------------------------------
if ( isComputed[ edgeIDs1[ iEdgePair ]] != // one EDGE is meshed
isComputed[ edgeIDs2[ iEdgePair ]])
if ( !SMESH_Algo::GetSortedNodesOnEdge( meshDS, theSinuEdges[ iEdgeComputed ], /*skipMedium=*/true, nodeParams ))
return false;
+ projectedEdges.insert( iEdgeComputed );
+
SMESH_MAT2d::BoundaryPoint& bndPnt = bp[ 1-iSideComputed ];
SMESH_MAT2d::BranchPoint brp;
NodePoint npN, npB; // NodePoint's initialized by node and BoundaryPoint
double maParam1st, maParamLast, maParam;
if ( !theMA.getBoundary().getBranchPoint( iEdgeComputed, nodeParams.begin()->first, brp ))
- return false;
+ return false;
branch.getParameter( brp, maParam1st );
if ( !theMA.getBoundary().getBranchPoint( iEdgeComputed, nodeParams.rbegin()->first, brp ))
- return false;
+ return false;
branch.getParameter( brp, maParamLast );
map< double, const SMDS_MeshNode* >::iterator u2n = nodeParams.begin(), u2nEnd = nodeParams.end();
npB = NodePoint( bndPnt );
pos = pointsOnE.insert( hint, make_pair( maParam, make_pair( np0, np1 )));
}
-
- // move iEdgePair forward;
- // find divPoints most close to max MA param
- if ( edgeIDs1.size() > 1 )
- {
- maParamLast = pointsOnE.rbegin()->first;
- int iClosest;
- double minDist = 1.;
- for ( ; iEdgePair < edgeIDs1.size()-1; ++iEdgePair )
- {
- branch.getParameter( divPoints[iEdgePair], maParam );
- double d = Abs( maParamLast - maParam );
- if ( d < minDist )
- minDist = d, iClosest = iEdgePair;
- else
- break;
- }
- if ( Abs( maParamLast - 1. ) < minDist )
- break; // the last pair treated
- else
- iEdgePair = iClosest;
- }
}
// --------------------------------------------------------------------------------
else if ( !isComputed[ edgeIDs1[ iEdgePair ]] && // none of EDGEs is meshed