예제 #1
0
//memory write access to - mesh->coords...
void smooth_job(Mesh * mesh, size_t colour, double * quality_cache, bool * vertice_in_cache, int iter, int start_range, int end_range){
  for(size_t vi = start_range; vi < end_range; vi++){
    int vertex = slices[colour][vi];
    // If this is a corner node, it cannot be moved.
    if(mesh->isCornerNode(vertex))
      continue;

    // Find the quality of the worst element adjacent to vid
    double worst_q=1.0;

    //parallelize
    for(std::set<size_t>::const_iterator it=mesh->NEList[vertex].begin();
        it!=mesh->NEList[vertex].end(); ++it){
      double v_quality;

      //compute quality only not in the cache
      if( !vertice_in_cache[*it] ){
        v_quality = quality_cache[*it] = mesh->element_quality(*it);
        vertice_in_cache[*it] = true;
      } else{
        v_quality = quality_cache[*it];
      }

      worst_q = std::min(worst_q, v_quality);
    }

    const double * m0 = &mesh->metric[3*vertex]; //const

    const double x0 = mesh->coords[2*vertex];
    const double y0 = mesh->coords[2*vertex+1];

    double A[4] = {0.0, 0.0, 0.0, 0.0}; //const
    double q[2] = {0.0, 0.0};

    // Iterate over all edges and assemble matrices A and q.
    for(std::vector<size_t>::const_iterator it=mesh->NNList[vertex].begin();
        it!=mesh->NNList[vertex].end(); ++it){
      size_t il = *it;

      const double *m1 = &mesh->metric[3*il]; //const

      // Find the metric in the middle of the edge.
      // Vectorize
      double ml00 = 0.5*(m0[0] + m1[0]); //const
      double ml01 = 0.5*(m0[1] + m1[1]); //const
      double ml11 = 0.5*(m0[2] + m1[2]); //const

      double x = mesh->coords[2*il] - x0;
      double y = mesh->coords[2*il+1] - y0;

      // Calculate and accumulate the contribution of
      // this vertex to the barycentre of the cavity.
      //Vectorize
      q[0] += (ml00*x + ml01*y);
      q[1] += (ml01*x + ml11*y);

      //Vectorize
      if(iter == 0){
        A[0] += ml00; //const
        A[1] += ml01; //const
        A[3] += ml11; //const
      }
    }

    // The metric tensor is symmetric, i.e. ml01=ml10, so A[2]=A[1].
    A[2]=A[1];

    // Displacement vector for vid
    double p[2];

    svd_solve_2x2(vertex, A, p, q);

    /* If this is a surface vertex, restrict the displacement
     * to the surface. The new displacement is the projection
     * of the old displacement on the surface.
     */
    if(mesh->isSurfaceNode(vertex)){
      p[0] -= p[0]*fabs(mesh->normals[2*vertex]);
      p[1] -= p[1]*fabs(mesh->normals[2*vertex+1]);
    }

    // Actually change something
    // Update the coordinates
    mesh->coords[2*vertex] += p[0];
    mesh->coords[2*vertex+1] += p[1];

    double new_worst_q=1.0;

    //parallelize
    for(std::set<size_t>::const_iterator it=mesh->NEList[vertex].begin();
        it!=mesh->NEList[vertex].end(); ++it){

      //store in cache new quality measure
      double v_quality = quality_cache[*it] = mesh->element_quality(*it);
      vertice_in_cache[*it] = true;

      new_worst_q = std::min(new_worst_q, v_quality);
    }

    //Undo the change
    if(new_worst_q < worst_q){
      mesh->coords[2*vertex] -= p[0];
      mesh->coords[2*vertex+1] -= p[1];

      for(std::set<size_t>::const_iterator it=mesh->NEList[vertex].begin();
        it!=mesh->NEList[vertex].end(); ++it){
        vertice_in_cache[*it] = false;
      }
    }
  }
}
예제 #2
0
void smooth(Mesh* mesh, size_t niter){
  // For the specified number of iterations, loop over all mesh vertices.
  for(size_t iter=0; iter<niter; ++iter){
    for(size_t vid=0; vid<mesh->NNodes; ++vid){
      // If this is a corner node, it cannot be moved.
      if(mesh->isCornerNode(vid))
        continue;

      // Find the quality of the worst element adjacent to vid
      double worst_q=1.0;
      for(std::set<size_t>::const_iterator it=mesh->NEList[vid].begin();
          it!=mesh->NEList[vid].end(); ++it){
        worst_q = std::min(worst_q, mesh->element_quality(*it));
      }

      /* Find the barycentre (centre of mass) of the cavity. A cavity is
       * defined as the set containing vid and all its adjacent vertices and
       * triangles. Since we work on metric space, all lengths have to measured
       * using the metric. The metric tensor is a 2x2 symmetric matrix which
       * encodes the ideal length and orientation of an edge containing vid. As
       * an edge is defined by two vertices, we calculate the edge length using
       * the value of the metric in the middle of the edge, i.e. the average of
       * the two metric tensors of the vertices defining the edge.
       */

      const double * m0 = &mesh->metric[3*vid];

      double x0 = mesh->coords[2*vid];
      double y0 = mesh->coords[2*vid+1];

      double A[4] = {0.0, 0.0, 0.0, 0.0};
      double q[2] = {0.0, 0.0};

      // Iterate over all edges and assemble matrices A and q.
      for(std::vector<size_t>::const_iterator it=mesh->NNList[vid].begin();
          it!=mesh->NNList[vid].end(); ++it){
        size_t il = *it;

        const double *m1 = &mesh->metric[3*il];

        // Find the metric in the middle of the edge.
        double ml00 = 0.5*(m0[0] + m1[0]);
        double ml01 = 0.5*(m0[1] + m1[1]);
        double ml11 = 0.5*(m0[2] + m1[2]);

        double x = mesh->coords[2*il] - x0;
        double y = mesh->coords[2*il+1] - y0;

        // Calculate and accumulate the contribution of
        // this vertex to the barycentre of the cavity.
        q[0] += (ml00*x + ml01*y);
        q[1] += (ml01*x + ml11*y);

        A[0] += ml00;
        A[1] += ml01;
        A[3] += ml11;
      }

      // The metric tensor is symmetric, i.e. ml01=ml10, so A[2]=A[1].
      A[2]=A[1];

      // Displacement vector for vid
      double p[2];

      /* The displacement p for vid is found by solving the linear system:
       * ┌─       ─┐   ┌    ┐   ┌    ┐
       * │A[0] A[1]│   │p[0]│   │q[0]│
       * │         │ x │    │ = │    │
       * │A[2] A[3]│   │p[1]│   │q[0]│
       * └─       ─┘   └    ┘   └    ┘
       */
      svd_solve_2x2(A, p, q);

      /* If this is a surface vertex, restrict the displacement
       * to the surface. The new displacement is the projection
       * of the old displacement on the surface.
       */
      if(mesh->isSurfaceNode(vid)){
        p[0] -= p[0]*fabs(mesh->normals[2*vid]);
        p[1] -= p[1]*fabs(mesh->normals[2*vid+1]);
      }

      // Update the coordinates
      mesh->coords[2*vid] += p[0];
      mesh->coords[2*vid+1] += p[1];

      /************************************************************************
       * At this point we must also interpolate the metric tensors from all   *
       * neighbouring vertices in order to calculate the new value of vid's   *
       * metric tensor at the new location. This is a quite complex procedure *
       * and has been omitted for simplicity of the exercise. A vertex will   *
       * always use its original metric tensor, no matter whether it has been *
       * relocated or not.                                                    *
       ************************************************************************/

      /* Find the quality of the worst element after smoothing. If an element
       * of the cavity was inverted, i.e. if vid was relocated outside the
       * interior convex hull of the cavity, then the calculated area of that
       * element will be negative and mesh->element_quality() will return a
       * negative number. In such a case, the smoothing operation has to be
       * rejected.
       */
      double new_worst_q=1.0;
      for(std::set<size_t>::const_iterator it=mesh->NEList[vid].begin();
          it!=mesh->NEList[vid].end(); ++it){
        new_worst_q = std::min(new_worst_q, mesh->element_quality(*it));
      }

      /* If quality is worse than before, either because of element inversion
       * or just because relocating vid to the barycentre of the cavity does
       * not improve quality, revert the changes.
       */
      if(new_worst_q < worst_q){
        mesh->coords[2*vid] -= p[0];
        mesh->coords[2*vid+1] -= p[1];
      }
    }
  }
}