Пример #1
0
int edge_normal
(const MVertex *const vertex, const int zoneIndex, const GEdge *const gEdge,
 const CCon::FaceVector<MZoneBoundary<2>::GlobalVertexData<MEdge>::FaceDataB>
 &faces, SVector3 &boNormal, const int onlyFace = -1)
{

  double par=0.0;
  // Note: const_cast used to match MVertex.cpp interface
  if(!reparamMeshVertexOnEdge(const_cast<MVertex*>(vertex), gEdge, par)) return 1;

  const SVector3 tangent(gEdge->firstDer(par));
                                        // Tangent to the boundary face
  SPoint3 interior(0., 0., 0.);         // An interior point
  SVector3 meshPlaneNormal(0.);         // This normal is perpendicular to the
                                        // plane of the mesh

  // The interior point and mesh plane normal are computed from all elements in
  // the zone.
  int cFace = 0;
  int iFace = 0;
  int nFace = faces.size();
  if ( onlyFace >= 0 ) {
    iFace = onlyFace;
    nFace = onlyFace + 1;
  }
  for(; iFace != nFace; ++iFace) {
    if(faces[iFace].zoneIndex == zoneIndex) {
      ++cFace;
      interior += faces[iFace].parentElement->barycenter();
      // 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;
    }
  }
  interior /= cFace;
  // Normal to the boundary edge (but unknown direction)
  boNormal = crossprod(tangent, meshPlaneNormal);
  boNormal.normalize();
  // Direction vector from vertex to interior (inwards).  The normal should
  // point in the same direction.
  if(dot(boNormal, SVector3(vertex->point(), interior)) < 0.)
    boNormal.negate();
  return 0;

}
Пример #2
0
void updateBoVec<3, MFace>(
  const int normalSource, const MVertex *const vertex, const int zoneIndex,
  const int vertIndex,
  const CCon::FaceVector<MZoneBoundary<3>::GlobalVertexData<MFace>::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:
    case 1:

      /*--------------------------------------------------------------------*
       * In this case, there are possibly multiple GFaces from this zone
       * connected to the vertex.  One patch for each GFace will be written.
       *--------------------------------------------------------------------*/

      {
        //--Get a list of face entities connected to 'ent'

        std::list<GFace *> gFaceList;
        switch(ent->dim()) {
        case 0: {
          std::vector<GEdge *> gEdgeList = ent->edges();
          std::list<GFace *> gFaceList;
          for(std::vector<GEdge *>::const_iterator gEIt = gEdgeList.begin();
              gEIt != gEdgeList.end(); ++gEIt) {
            std::vector<GFace *> alist = (*gEIt)->faces();
            gFaceList.insert(gFaceList.end(), alist.begin(), alist.end());
          }
          // Remove duplicates
          gFaceList.sort();
          gFaceList.unique();
        } break;
        case 1: {
          std::vector<GFace *> fac = ent->faces();
          gFaceList.insert(gFaceList.end(), fac.begin(), fac.end());
        } break;
        }

        //--Get a list of face entities connected to the 'vertex' that are also
        // in the
        //--zone

        std::list<const GFace *> useGFace;
        std::vector<GEdge *> gEdgeList;
        const int nFace = faces.size();
        for(int iFace = 0; iFace != nFace; ++iFace) {
          if(zoneIndex == faces[iFace].zoneIndex) {
            bool matchedFace = false;
            MFace mFace =
              faces[iFace].parentElement->getFace(faces[iFace].parentFace);
            const int nVOnF = mFace.getNumVertices();
            int vertexOnF = 0; // The index of 'vertex' in the face
            for(int iVOnF = 0; iVOnF != nVOnF; ++iVOnF) {
              const MVertex *const vertex2 = mFace.getVertex(iVOnF);
              if(vertex == vertex2)
                vertexOnF = iVOnF;
              else {
                const GEntity *const ent2 = vertex2->onWhat();
                if(ent2->dim() == 2) {
                  matchedFace = true;
                  useGFace.push_back(static_cast<const GFace *>(ent2));
                  break;
                }
              }
            }
            // Triangle MElements are a total P.I.T.A.:
            // - If the original 'ent' is a vertex, one MVertex can be on the
            //   GVertex, and the other two on GEdges, and then the MElement is
            //   still on the GFace.
            // - If the original 'ent' is an edge, one MVertex can be on the
            //   original GEdge, another on a GVertex, and the final on another
            //   GEdge, and then the MElement is still on the GFace.  There is
            //   also the unlikely case where the two other MVertex are both on
            //   edges ... and the MElement is still on the GFace.
            if(!matchedFace && (3 == nVOnF)) {
              const MVertex *vertex2 = 0;
              const MVertex *vertex3 = 0;
              switch(vertexOnF) {
              case 0:
                vertex2 = mFace.getVertex(1);
                vertex3 = mFace.getVertex(2);
                break;
              case 1:
                vertex2 = mFace.getVertex(0);
                vertex3 = mFace.getVertex(2);
                break;
              case 2:
                vertex2 = mFace.getVertex(0);
                vertex3 = mFace.getVertex(1);
                break;
              }
              if(vertex2 && vertex3) {
                const GEntity *const ent2 = vertex2->onWhat();
                const GEntity *const ent3 = vertex3->onWhat();
                if(ent2 && ent3) {
                  if(ent2->dim() == 1 && ent3->dim() == 1) {
                    // Which GFace is bounded by edges ent2 and ent3?
                    for(std::list<GFace *>::const_iterator gFIt =
                          gFaceList.begin();
                        gFIt != gFaceList.end(); ++gFIt) {
                      gEdgeList = (*gFIt)->edges();
                      if((std::find(gEdgeList.begin(), gEdgeList.end(), ent2) !=
                          gEdgeList.end()) &&
                         (std::find(gEdgeList.begin(), gEdgeList.end(), ent3) !=
                          gEdgeList.end())) {
                        // Edges ent2 and ent3 bound this face
                        useGFace.push_back(*gFIt);
                        break;
                      }
                    }
                  }
                  else if(ent->dim() == 1 && (ent2->dim() + ent3->dim() == 1)) {
                    const GEntity *entCmp;
                    if(ent2->dim() == 1)
                      entCmp = ent2;
                    else
                      entCmp = ent3;
                    // Which GFace is bounded by entCmp
                    for(std::list<GFace *>::const_iterator gFIt =
                          gFaceList.begin();
                        gFIt != gFaceList.end(); ++gFIt) {
                      gEdgeList = (*gFIt)->edges();
                      if(std::find(gEdgeList.begin(), gEdgeList.end(),
                                   entCmp) != gEdgeList.end()) {
                        // Edge entCmp and the original edge bound this face
                        useGFace.push_back(*gFIt);
                        break;
                      }
                    }
                  }
                }
              }
            } // Stupid triangles
          } // End if face in zone
        } // End loop over faces
        // Duplicates are a possibility, remove
        useGFace.sort();
        useGFace.unique();

        //--'useGFace' now contains the face entities that connect to vertex.  A
        // BC
        //--patch will be written for each of them.

        for(std::list<const GFace *>::const_iterator gFIt = useGFace.begin();
            gFIt != useGFace.end(); ++gFIt) {
          SPoint2 par;
          if(!reparamMeshVertexOnFace(const_cast<MVertex *>(vertex), *gFIt,
                                      par))
            goto getNormalFromElements; // :P  After all that!

          SVector3 boNormal = (*gFIt)->normal(par);
          SPoint3 interior(0., 0., 0.);
          int cFace = 0;
          const int nFace = faces.size();
          for(int iFace = 0; iFace != nFace; ++iFace) {
            if(faces[iFace].zoneIndex == zoneIndex) {
              ++cFace;
              interior += faces[iFace].parentElement->barycenter();
            }
          }
          interior /= cFace;
          if(dot(boNormal, SVector3(vertex->point(), interior)) < 0.)
            boNormal.negate();

          zoneBoVec.push_back(
            VertexBoundary(zoneIndex, (*gFIt)->tag(), boNormal,
                           const_cast<MVertex *>(vertex), vertIndex));
          patch.add((*gFIt)->tag());
        }
      }
      break;
    case 2:

      /*--------------------------------------------------------------------*
       * The vertex exists on a face and belongs to only 1 BC patch.
       *--------------------------------------------------------------------*/

      {
        const GFace *const gFace = static_cast<const GFace *>(ent);
        SPoint2 par;
        if(!reparamMeshVertexOnFace(const_cast<MVertex *>(vertex), gFace, par))
          goto getNormalFromElements;

        SVector3 boNormal = static_cast<const GFace *>(ent)->normal(par);
        SPoint3 interior(0., 0., 0.);
        int cFace = 0;
        const int nFace = faces.size();
        for(int iFace = 0; iFace != nFace; ++iFace) {
          if(faces[iFace].zoneIndex == zoneIndex) {
            ++cFace;
            interior += faces[iFace].parentElement->barycenter();
          }
        }
        interior /= cFace;
        if(dot(boNormal, SVector3(vertex->point(), interior)) < 0.)
          boNormal.negate();

        zoneBoVec.push_back(VertexBoundary(zoneIndex, gFace->tag(), boNormal,
                                           const_cast<MVertex *>(vertex),
                                           vertIndex));
        patch.add(gFace->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;
    }
    // Sum the normals from each element connected to the vertex and in the
    // zone.  Each normal has to be converted independently into an inwards-
    // pointing normal.
    //**Weight each normal by the area of the boundary element?
    SVector3 boNormal(0.);
    const int nFace = faces.size();
    for(int iFace = 0; iFace != nFace; ++iFace) {
      if(faces[iFace].zoneIndex == zoneIndex) {
        // Normal to the boundary (unknown direction)
        SVector3 bnt =
          faces[iFace].parentElement->getFace(faces[iFace].parentFace).normal();
        // 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);
  }
}
Пример #3
0
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);
  }
}