typename viennagrid::result_of::point< viennagrid::element<CellTagT, WrappedConfigT> >::type outer_cell_normal_at_facet(viennagrid::element<CellTagT, WrappedConfigT> const & cell, viennagrid::element<viennagrid::line_tag, WrappedConfigT> const & facet) { typedef viennagrid::element<viennagrid::line_tag, WrappedConfigT> FacetType; typedef typename viennagrid::result_of::point<FacetType>::type PointType; typedef typename viennagrid::result_of::const_vertex_range<FacetType>::type VertexRange; VertexRange facet_vertices(facet); PointType facet_vec = viennagrid::point(facet_vertices[1]) - viennagrid::point(facet_vertices[0]); PointType facet_centroid_vec = viennagrid::centroid(cell) - viennagrid::point(facet_vertices[0]); PointType edge_normal(facet_vec[1], -facet_vec[0]); // create one normal to line if (viennagrid::inner_prod(facet_centroid_vec, edge_normal) > 0) // normal vector is pointing into cell, hence flip edge_normal *= -1; return edge_normal / viennagrid::norm(edge_normal); }
void updateBoVec<2, MEdge>( const int normalSource, const MVertex *const vertex, const int zoneIndex, const int vertIndex, const CCon::FaceVector<MZoneBoundary<2>::GlobalVertexData<MEdge>::FaceDataB> &faces, ZoneBoVec &zoneBoVec, BCPatchIndex &patch, bool &warnNormFromElem) { GEntity *ent; if(normalSource == NormalSourceElement) goto getNormalFromElements; ent = vertex->onWhat(); if(ent == 0) { goto getNormalFromElements; // No entity: try to find a normal from the faces } else { switch(ent->dim()) { case 0: /*--------------------------------------------------------------------* * In this case, there are possibly two GEdges from this zone * connected to the vertex. If the angle between the two edges is * significant, the BC patch will be split and this vertex will be * written in both patches with different normals. If the angle is * small, or only one GEdge belongs to this zone, then the vertex will * only be written to one patch. *--------------------------------------------------------------------*/ { // Find edge entities that are connected to elements in the zone std::vector<std::pair<GEdge *, int> > useGEdge; const int nFace = faces.size(); for(int iFace = 0; iFace != nFace; ++iFace) { if(zoneIndex == faces[iFace].zoneIndex) { MEdge mEdge = faces[iFace].parentElement->getEdge(faces[iFace].parentFace); // Get the other vertex on the mesh edge. MVertex *vertex2 = mEdge.getMinVertex(); if(vertex2 == vertex) vertex2 = mEdge.getMaxVertex(); // Check if the entity associated with vertex2 is a line and // is also connected to vertex. If so, add it to the container of // edge entities that will be used to determine the normal GEntity *const ent2 = vertex2->onWhat(); if(ent2->dim() == 1) { useGEdge.push_back( std::pair<GEdge *, int>(static_cast<GEdge *>(ent2), iFace)); } } } //--'useGEdge' now contains the edge entities that will be used to // determine //--the normals switch(useGEdge.size()) { case 0: // goto getNormalFromElements; // We probably don't want BC data if none of the faces attatched to // this vertex and in this zone are on the boundary. break; case 1: { const GEdge *const gEdge = static_cast<const GEdge *>(useGEdge[0].first); SVector3 boNormal; if(edge_normal(vertex, zoneIndex, gEdge, faces, boNormal)) goto getNormalFromElements; zoneBoVec.push_back(VertexBoundary(zoneIndex, gEdge->tag(), boNormal, const_cast<MVertex *>(vertex), vertIndex)); patch.add(gEdge->tag()); } break; case 2: { // Get the first normal const GEdge *const gEdge1 = static_cast<const GEdge *>(useGEdge[0].first); SVector3 boNormal1; if(edge_normal(vertex, zoneIndex, gEdge1, faces, boNormal1, useGEdge[0].second)) goto getNormalFromElements; // Get the second normal const GEdge *const gEdge2 = static_cast<const GEdge *>(useGEdge[1].first); SVector3 boNormal2; if(edge_normal(vertex, zoneIndex, gEdge2, faces, boNormal2, useGEdge[1].second)) goto getNormalFromElements; if(dot(boNormal1, boNormal2) < 0.98) { //--Write 2 separate patches zoneBoVec.push_back( VertexBoundary(zoneIndex, gEdge1->tag(), boNormal1, const_cast<MVertex *>(vertex), vertIndex)); patch.add(gEdge1->tag()); zoneBoVec.push_back( VertexBoundary(zoneIndex, gEdge2->tag(), boNormal2, const_cast<MVertex *>(vertex), vertIndex)); patch.add(gEdge2->tag()); } else { //--Write one patch boNormal1 += boNormal2; boNormal1 *= 0.5; zoneBoVec.push_back( VertexBoundary(zoneIndex, gEdge1->tag(), boNormal1, const_cast<MVertex *>(vertex), vertIndex)); patch.addPair(gEdge1->tag(), gEdge2->tag()); } } break; default: Msg::Error("Internal error based on 2-D boundary assumptions (file " "\'MZoneBoundary.cpp'). Boundary vertices may be " "incorrect"); break; } } break; case 1: /*--------------------------------------------------------------------* * The vertex exists on an edge and belongs to only 1 BC patch. *--------------------------------------------------------------------*/ { SVector3 boNormal; if(edge_normal(vertex, zoneIndex, static_cast<const GEdge *>(ent), faces, boNormal)) goto getNormalFromElements; zoneBoVec.push_back(VertexBoundary(zoneIndex, ent->tag(), boNormal, const_cast<MVertex *>(vertex), vertIndex)); patch.add(ent->tag()); } break; default: goto getNormalFromElements; } } return; getNormalFromElements:; /*--------------------------------------------------------------------* * Geometry information cannot be used - generate normals from the * elements *--------------------------------------------------------------------*/ { if(warnNormFromElem && normalSource == 1) { Msg::Warning("Some or all boundary normals were determined from mesh " "elements instead of from the geometry"); warnNormFromElem = false; } // The mesh plane normal is computed from all elements attached to the // vertex SVector3 meshPlaneNormal(0.); // This normal is perpendicular to the // plane of the mesh const int nFace = faces.size(); for(int iFace = 0; iFace != nFace; ++iFace) { if(faces[iFace].zoneIndex == zoneIndex) { // Make sure all the planes go in the same direction //**Required? SVector3 mpnt = faces[iFace].parentElement->getFace(0).normal(); if(dot(mpnt, meshPlaneNormal) < 0.) mpnt.negate(); meshPlaneNormal += mpnt; } } // Sum the normals from each element. The tangent is computed from all // faces in the zone attached to the vertex and is weighted by the length of // the edge. Each tangent has to be converted independently into an // inwards-pointing normal. SVector3 boNormal(0.); for(int iFace = 0; iFace != nFace; ++iFace) { if(faces[iFace].zoneIndex == zoneIndex) { const SVector3 tangent = faces[iFace] .parentElement->getEdge(faces[iFace].parentFace) .tangent(); // Normal to the boundary (unknown direction) SVector3 bnt = crossprod(tangent, meshPlaneNormal); // Inwards normal const SVector3 inwards(vertex->point(), faces[iFace].parentElement->barycenter()); if(dot(bnt, inwards) < 0.) bnt.negate(); boNormal += bnt; } } boNormal.normalize(); zoneBoVec.push_back(VertexBoundary( zoneIndex, 0, boNormal, const_cast<MVertex *>(vertex), vertIndex)); patch.add(0); } }