Пример #1
0
double qmQuadrangleAngles (MQuadrangle *e) {
  double a = 100;
  double worst_quality = std::numeric_limits<double>::max();
  double mat[3][3];
  double mat2[3][3];
  double den = atan(a*(M_PI/4)) + atan(a*(2*M_PI/4 - (M_PI/4)));

  // This matrix is used to "rotate" the triangle to get each vertex
  // as the "origin" of the mapping in turn
  //double rot[3][3];
  //rot[0][0]=-1; rot[0][1]=1; rot[0][2]=0;
  //rot[1][0]=-1; rot[1][1]=0; rot[1][2]=0;
  //rot[2][0]= 0; rot[2][1]=0; rot[2][2]=1;
  //double tmp[3][3];

  const double u[9] = {-1,-1, 1, 1, 0,0,1,-1,0};
  const double v[9] = {-1, 1, 1,-1, -1,1,0,0,0};

  for (int i = 0; i < 9; i++) {

    e->getJacobian(u[i], v[i], 0, mat);
    e->getPrimaryJacobian(u[i],v[i],0,mat2);
    //for (int j = 0; j < i; j++) {
    //  matmat(rot,mat,tmp);
    //  memcpy(mat, tmp, sizeof(mat));
    //}

    //get angle
    double v1[3] = {mat[0][0],  mat[0][1],  mat[0][2] };
    double v2[3] = {mat[1][0],  mat[1][1],  mat[1][2] };
    double v3[3] = {mat2[0][0],  mat2[0][1],  mat2[0][2] };
    double v4[3] = {mat2[1][0],  mat2[1][1],  mat2[1][2] };
    norme(v1);
    norme(v2);
    norme(v3);
    norme(v4);
    double v12[3], v34[3];
    prodve(v1,v2,v12);
    prodve(v3,v4,v34);
    norme(v12);
    norme(v34);
    double orientation;
    prosca(v12,v34,&orientation);

    // If the if the triangle is "flipped" it's no good
    //    if (orientation < 0)
    //      return -std::numeric_limits<double>::max();

    double c;
    prosca(v1,v2,&c);
    double x = fabs(acos(c))-M_PI/2;
    //double angle = fabs(acos(c))*180/M_PI;
    double quality = (atan(a*(x+M_PI/4)) + atan(a*(2*M_PI/4 - (x+M_PI/4))))/den;
    worst_quality = std::min(worst_quality, quality);
  }
  
  return worst_quality;

}
Пример #2
0
 bool operator()(const AlphaElement &e1, const AlphaElement &e2) const
 {
   double cg1[3] = { 0., 0., 0. }, cg2[3] = { 0., 0., 0.};
   for(int i = 0; i < numVertices; i++) {
     cg1[0] += e1.v[3 * i];
     cg1[1] += e1.v[3 * i + 1];
     cg1[2] += e1.v[3 * i + 2];
     cg2[0] += e2.v[3 * i];
     cg2[1] += e2.v[3 * i + 1];
     cg2[2] += e2.v[3 * i + 2];
   }
   return prosca(eye, cg1) < prosca(eye, cg2);
 }
Пример #3
0
SPoint2 gmshFace::parFromPoint(const SPoint3 &qp, bool onSurface) const
{
  if(s->Typ == MSH_SURF_PLAN){
    double x, y, z, VX[3], VY[3];
    getMeanPlaneData(VX, VY, x, y, z);
    double u, v, vec[3] = {qp.x() - x, qp.y() - y, qp.z() - z};
    prosca(vec, VX, &u);
    prosca(vec, VY, &v);
    return SPoint2(u, v);
  }
  else{
    return GFace::parFromPoint(qp, onSurface);
  }
}
Пример #4
0
bool edgeSwapTestAngle(BDS_Edge *e, double min_cos)
{
  BDS_Face *f1 = e->faces(0);
  BDS_Face *f2 = e->faces(1);
  BDS_Point *n1[4];
  BDS_Point *n2[4];
  f1->getNodes(n1);
  f2->getNodes(n2);
  double norm1[3];
  double norm2[3];
  normal_triangle(n1[0], n1[1], n1[2], norm1);
  normal_triangle(n2[0], n2[1], n2[2], norm2);
  double cosa;prosca (norm1, norm2, &cosa);
  return cosa > min_cos;
}
Пример #5
0
int IsoSimplex(double *X, double *Y, double *Z, double *Val, double V,
               double *Xp, double *Yp, double *Zp, double n[3])
{
  if(Val[0] == Val[1] && Val[0] == Val[2] && Val[0] == Val[3])
    return 0;

  int nb = 0;
  if((Val[0] >= V && Val[1] <= V) || (Val[1] >= V && Val[0] <= V)) {
    InterpolateIso(X, Y, Z, Val, V, 0, 1, &Xp[nb], &Yp[nb], &Zp[nb]);
    nb++;
  }
  if((Val[0] >= V && Val[2] <= V) || (Val[2] >= V && Val[0] <= V)) {
    InterpolateIso(X, Y, Z, Val, V, 0, 2, &Xp[nb], &Yp[nb], &Zp[nb]);
    nb++;
  }
  if((Val[0] >= V && Val[3] <= V) || (Val[3] >= V && Val[0] <= V)) {
    InterpolateIso(X, Y, Z, Val, V, 0, 3, &Xp[nb], &Yp[nb], &Zp[nb]);
    nb++;
  }
  if((Val[1] >= V && Val[2] <= V) || (Val[2] >= V && Val[1] <= V)) {
    InterpolateIso(X, Y, Z, Val, V, 1, 2, &Xp[nb], &Yp[nb], &Zp[nb]);
    nb++;
  }
  if((Val[1] >= V && Val[3] <= V) || (Val[3] >= V && Val[1] <= V)) {
    InterpolateIso(X, Y, Z, Val, V, 1, 3, &Xp[nb], &Yp[nb], &Zp[nb]);
    nb++;
  }
  if((Val[2] >= V && Val[3] <= V) || (Val[3] >= V && Val[2] <= V)) {
    InterpolateIso(X, Y, Z, Val, V, 2, 3, &Xp[nb], &Yp[nb], &Zp[nb]);
    nb++;
  }

  // Remove identical nodes (this can happen if an edge belongs to the
  // zero levelset). We should be doing this even for nb < 4, but it
  // would slow us down even more (and we don't really care if some
  // nodes in a postprocessing element are identical)
  if(nb > 4) {
    double xi[6], yi[6], zi[6];
    affect(xi, yi, zi, 0, Xp, Yp, Zp, 0);
    int ni = 1;
    for(int j = 1; j < nb; j++) {
      for(int i = 0; i < ni; i++) {
        if(fabs(Xp[j] - xi[i]) < 1.e-12 &&
           fabs(Yp[j] - yi[i]) < 1.e-12 &&
           fabs(Zp[j] - zi[i]) < 1.e-12) {
          break;
        }
        if(i == ni - 1) {
          affect(xi, yi, zi, i + 1, Xp, Yp, Zp, j);
          ni++;
        }
      }
    }
    for(int i = 0; i < ni; i++)
      affect(Xp, Yp, Zp, i, xi, yi, zi, i);
    nb = ni;
  }

  if(nb < 3 || nb > 4)
    return 0;

  // 3 possible quads at this point: (0,2,5,3), (0,1,5,4) or
  // (1,2,4,3), so simply invert the 2 last vertices for having the
  // quad ordered
  if(nb == 4) {
    double x = Xp[3], y = Yp[3], z = Zp[3];
    Xp[3] = Xp[2];
    Yp[3] = Yp[2];
    Zp[3] = Zp[2];
    Xp[2] = x;
    Yp[2] = y;
    Zp[2] = z;
  }

  // to get a nice isosurface, we should have n . grad v > 0, where n
  // is the normal to the polygon and v is the unknown field we want
  // to draw
  double v1[3] = {Xp[2] - Xp[0], Yp[2] - Yp[0], Zp[2] - Zp[0]};
  double v2[3] = {Xp[1] - Xp[0], Yp[1] - Yp[0], Zp[1] - Zp[0]};
  prodve(v1, v2, n);
  norme(n);

  double g[3];
  gradSimplex(X, Y, Z, Val, g);

  double gdotn;
  prosca(g, n, &gdotn);

  if(gdotn > 0.) {
    double Xpi[6], Ypi[6], Zpi[6];
    for(int i = 0; i < nb; i++) {
      Xpi[i] = Xp[i];
      Ypi[i] = Yp[i];
      Zpi[i] = Zp[i];
    }
    for(int i = 0; i < nb; i++) {
      Xp[i] = Xpi[nb - i - 1];
      Yp[i] = Ypi[nb - i - 1];
      Zp[i] = Zpi[nb - i - 1];
    }
  }
  else {
    n[0] = -n[0];
    n[1] = -n[1];
    n[2] = -n[2];
  }

  return nb;
}
Пример #6
0
int CutTriangle(double *X, double *Y, double *Z, double *Val,
                double V1, double V2, 
                double *Xp2, double *Yp2, double *Zp2, double *Vp2)
{
  // fill io so that it contains an indexing of the nodes such that
  // Val[io[i]] > Val[io[j]] if i > j
  int io[3] = {0, 1, 2};
  for(int i = 0; i < 2; i++) {
    for(int j = i + 1; j < 3; j++) {
      if(Val[io[i]] > Val[io[j]]) {
        int iot = io[i];
        io[i] = io[j];
        io[j] = iot;
      }
    }
  }

  if(Val[io[0]] > V2 || Val[io[2]] < V1) return 0;

  if(V1 <= Val[io[0]] && Val[io[2]] <= V2) {
    for(int i = 0; i < 3; i++) {
      Vp2[i] = Val[i];
      Xp2[i] = X[i];
      Yp2[i] = Y[i];
      Zp2[i] = Z[i];
    }
    return 3;
  }

  int Np = 0, Fl = 0;
  double Xp[10], Yp[10], Zp[10], Vp[10];

  if(V1 <= Val[io[0]]) {
    Vp[Np] = Val[io[0]];
    Xp[Np] = X[io[0]];
    Yp[Np] = Y[io[0]];
    Zp[Np] = Z[io[0]];
    Np++;
    Fl = 1;
  }
  else if(Val[io[0]] < V1 && V1 <= Val[io[1]]) {
    Vp[Np] = V1;
    InterpolateIso(X, Y, Z, Val, V1, io[0], io[2], &Xp[Np], &Yp[Np], &Zp[Np]);
    Np++;
    Vp[Np] = V1;
    InterpolateIso(X, Y, Z, Val, V1, io[0], io[1], &Xp[Np], &Yp[Np], &Zp[Np]);
    Np++;
    Fl = 1;
  }
  else {
    Vp[Np] = V1;
    InterpolateIso(X, Y, Z, Val, V1, io[0], io[2], &Xp[Np], &Yp[Np], &Zp[Np]);
    Np++;
    Vp[Np] = V1;
    InterpolateIso(X, Y, Z, Val, V1, io[1], io[2], &Xp[Np], &Yp[Np], &Zp[Np]);
    Np++;
    Fl = 0;
  }

  if(V2 == Val[io[0]]) {
    return 0;
  }
  else if((Val[io[0]] < V2) && (V2 < Val[io[1]])) {
    Vp[Np] = V2;
    InterpolateIso(X, Y, Z, Val, V2, io[0], io[1], &Xp[Np], &Yp[Np], &Zp[Np]);
    Np++;
    Vp[Np] = V2;
    InterpolateIso(X, Y, Z, Val, V2, io[0], io[2], &Xp[Np], &Yp[Np], &Zp[Np]);
    Np++;
  }
  else if(V2 < Val[io[2]]) {
    if(Fl) {
      Vp[Np] = Val[io[1]];
      Xp[Np] = X[io[1]];
      Yp[Np] = Y[io[1]];
      Zp[Np] = Z[io[1]];
      Np++;
    }
    Vp[Np] = V2;
    InterpolateIso(X, Y, Z, Val, V2, io[1], io[2], &Xp[Np], &Yp[Np], &Zp[Np]);
    Np++;
    Vp[Np] = V2;
    InterpolateIso(X, Y, Z, Val, V2, io[0], io[2], &Xp[Np], &Yp[Np], &Zp[Np]);
    Np++;
  }
  else {
    if(Fl) {
      Vp[Np] = Val[io[1]];
      Xp[Np] = X[io[1]];
      Yp[Np] = Y[io[1]];
      Zp[Np] = Z[io[1]];
      Np++;
    }
    Vp[Np] = Val[io[2]];
    Xp[Np] = X[io[2]];
    Yp[Np] = Y[io[2]];
    Zp[Np] = Z[io[2]];
    Np++;
  }

  Vp2[0] = Vp[0];
  Xp2[0] = Xp[0];
  Yp2[0] = Yp[0];
  Zp2[0] = Zp[0];

  int Np2 = 1;

  for(int i = 1; i < Np; i++) {
    if((Xp[i] != Xp2[Np2 - 1]) || (Yp[i] != Yp2[Np2 - 1]) || 
       (Zp[i] != Zp2[Np2 - 1])){
      Vp2[Np2] = Vp[i];
      Xp2[Np2] = Xp[i];
      Yp2[Np2] = Yp[i];
      Zp2[Np2] = Zp[i];
      Np2++;
    }
  }

  if(Xp2[0] == Xp2[Np2 - 1] && Yp2[0] == Yp2[Np2 - 1] && 
     Zp2[0] == Zp2[Np2 - 1]) {
    Np2--;
  }

  // check and fix orientation
  double in1[3] = {X[1] - X[0], Y[1] - Y[0], Z[1] - Z[0]};
  double in2[3] = {X[2] - X[0], Y[2] - Y[0], Z[2] - Z[0]};
  double inn[3];
  prodve(in1, in2, inn);
  double out1[3] = {Xp2[1] - Xp2[0], Yp2[1] - Yp2[0], Zp2[1] - Zp2[0]};
  double out2[3] = {Xp2[2] - Xp2[0], Yp2[2] - Yp2[0], Zp2[2] - Zp2[0]};
  double outn[3];
  prodve(out1, out2, outn);
  double res;
  prosca(inn, outn, &res);
  if(res < 0){
    for(int i = 0; i < Np2; i++){
      Vp[i] = Vp2[Np2 - i - 1];
      Xp[i] = Xp2[Np2 - i - 1];
      Yp[i] = Yp2[Np2 - i - 1];
      Zp[i] = Zp2[Np2 - i - 1];
    }
    for(int i = 0; i < Np2; i++){
      Vp2[i] = Vp[i];
      Xp2[i] = Xp[i];
      Yp2[i] = Yp[i];
      Zp2[i] = Zp[i];
    }
  }

  return Np2;
}
Пример #7
0
bool evalSwapForOptimize(BDS_Edge *e, GFace *gf, BDS_Mesh &m)
{
  if(e->numfaces() != 2) return false;

  BDS_Point *p11, *p12, *p13;
  BDS_Point *p21, *p22, *p23;
  BDS_Point *p31, *p32, *p33;
  BDS_Point *p41, *p42, *p43;
  swap_config(e, &p11, &p12, &p13, &p21, &p22, &p23, &p31, &p32, &p33, &p41,
              &p42, &p43);

  // First, evaluate what we gain in element quality if the
  // swap is performed
  double qa1 = qmTriangle(p11, p12, p13, QMTRI_RHO);
  double qa2 = qmTriangle(p21, p22, p23, QMTRI_RHO);
  double qb1 = qmTriangle(p31, p32, p33, QMTRI_RHO);
  double qb2 = qmTriangle(p41, p42, p43, QMTRI_RHO);
  double qa = std::min(qa1, qa2);
  double qb = std::min(qb1, qb2);
  double qualIndicator = qb - qa;
  bool qualShouldSwap = qb > 2*qa;
  bool qualCouldSwap  = !(qb < qa * .5) && qb > .05;

  // then evaluate if swap produces smoother surfaces
  double norm11[3];
  double norm12[3];
  double norm21[3];
  double norm22[3];
  normal_triangle(p11, p12, p13, norm11);
  normal_triangle(p21, p22, p23, norm12);
  normal_triangle(p31, p32, p33, norm21);
  normal_triangle(p41, p42, p43, norm22);
  double cosa; prosca(norm11, norm12, &cosa);
  double cosb; prosca(norm21, norm22, &cosb);
  // double smoothIndicator = cosb - cosa;
  // bool smoothShouldSwap = (cosa < 0.1 && cosb > 0.3);
  // bool smoothCouldSwap = !(cosb < cosa * .5);

  double la  = computeEdgeLinearLength(p11, p12);
  double la_ = computeEdgeLinearLength(p11, p12, gf, m.scalingU, m.scalingV);
  double lb  = computeEdgeLinearLength(p13, p23);
  double lb_ = computeEdgeLinearLength(p13, p23, gf, m.scalingU, m.scalingV);

  double LA = (la_ -la) / la_;
  double LB = (lb_ -lb) / lb_;

  double distanceIndicator = LA - LB;
  bool distanceShouldSwap = (LB < .5 * LA) && LA > 1.e-2;
  bool distanceCouldSwap = !(LB > 2 * LA) || LB < 1.e-2;

  if (20 * qa < qb) return true;
  // if (LB > .025 && distanceIndicator > 0 && qb > .25) return true;
  // if (LB > .05 && distanceIndicator > 0 && qb > .15) return true;
  // if (LB > .1 && distanceIndicator > 0 && qb > .1) return true;
  // if (LB > .2 && distanceIndicator > 0 && qb > .05) return true;
  // if (LB > .3 && distanceIndicator > 0 && qb > .025) return true;

  // if swap enhances both criterion, the do it!
  if (distanceIndicator > 0 && qualIndicator > 0) return true;
  if (distanceShouldSwap && qualCouldSwap) return true;
  if (distanceCouldSwap && qualShouldSwap) return true;
  // if (smoothIndicator > 0 && qualIndicator > 0) return true;
  // if (smoothShouldSwap && qualCouldSwap) return true;
  // if (smoothCouldSwap && qualShouldSwap) return true;
  // if (distanceShouldSwap && qualCouldSwap) return true;
  // if (distanceCouldSwap && qualShouldSwap) return true;
  if (cosa < 0 && cosb > 0 && qb > 0.0)
    return true;
  return false;
}
Пример #8
0
double qmTriangleAngles (MTriangle *e) {
  double a = 500;
  double worst_quality = std::numeric_limits<double>::max();
  double mat[3][3];
  double mat2[3][3];
  double den = atan(a*(M_PI/9)) + atan(a*(M_PI/9));

  // This matrix is used to "rotate" the triangle to get each vertex
  // as the "origin" of the mapping in turn
  double rot[3][3];
  rot[0][0]=-1; rot[0][1]=1; rot[0][2]=0;
  rot[1][0]=-1; rot[1][1]=0; rot[1][2]=0;
  rot[2][0]= 0; rot[2][1]=0; rot[2][2]=1;
  double tmp[3][3];

  //double minAngle = 120.0;
  for (int i = 0; i < e->getNumPrimaryVertices(); i++) {
    const double u = i == 1 ? 1 : 0;
    const double v = i == 2 ? 1 : 0;
    const double w = 0;
    e->getJacobian(u, v, w, mat);
    e->getPrimaryJacobian(u,v,w,mat2);
    for (int j = 0; j < i; j++) {
      matmat(rot,mat,tmp);
      memcpy(mat, tmp, sizeof(mat));
    }
    //get angle
    double v1[3] = {mat[0][0],  mat[0][1],  mat[0][2] };
    double v2[3] = {mat[1][0],  mat[1][1],  mat[1][2] };
    double v3[3] = {mat2[0][0],  mat2[0][1],  mat2[0][2] };
    double v4[3] = {mat2[1][0],  mat2[1][1],  mat2[1][2] };
    norme(v1);
    norme(v2);
    norme(v3);
    norme(v4);
    double v12[3], v34[3];
    prodve(v1,v2,v12);
    prodve(v3,v4,v34);
    norme(v12);
    norme(v34);
    double orientation;
    prosca(v12,v34,&orientation);

    // If the triangle is "flipped" it's no good
    if (orientation < 0)
      return -std::numeric_limits<double>::max();

    double c;
    prosca(v1,v2,&c);
    double x = acos(c)-M_PI/3;
    //double angle = (x+M_PI/3)/M_PI*180;
    double quality = (atan(a*(x+M_PI/9)) + atan(a*(M_PI/9-x)))/den;
    worst_quality = std::min(worst_quality, quality);

    //minAngle = std::min(angle, minAngle);
    //printf("Angle %g ", angle);
    // printf("Quality %g\n",quality);
  }
  //printf("MinAngle %g \n", minAngle);
  //return minAngle;

  return worst_quality;
}
Пример #9
0
void GMSH_LevelsetPlugin::_cutAndAddElements(PViewData *vdata, PViewData *wdata,
                                             int ent, int ele, int vstep, int wstep,
                                             double x[8], double y[8], double z[8],
                                             double levels[8], double scalarValues[8],
                                             PViewDataList* out)
{
  int stepmin = vstep, stepmax = vstep + 1, otherstep = wstep;
  if(stepmin < 0){
    stepmin = vdata->getFirstNonEmptyTimeStep();
    stepmax = vdata->getNumTimeSteps();
  }
  if(wstep < 0) otherstep = wdata->getFirstNonEmptyTimeStep();

  int numNodes = vdata->getNumNodes(stepmin, ent, ele);
  int numEdges = vdata->getNumEdges(stepmin, ent, ele);
  int numComp = wdata->getNumComponents(otherstep, ent, ele);
  int type = vdata->getType(stepmin, ent, ele);

  // decompose the element into simplices
  for(int simplex = 0; simplex < numSimplexDec(type); simplex++){

    int n[4], ep[12], nsn, nse;
    getSimplexDec(numNodes, numEdges, type, simplex, n[0], n[1], n[2], n[3],
                  nsn, nse);

    // loop over time steps
    for(int step = stepmin; step < stepmax; step++){

      // check which edges cut the iso and interpolate the value
      if(wstep < 0) otherstep = step;

      if(!wdata->hasTimeStep(otherstep)) continue;

      int np = 0;
      double xp[12], yp[12], zp[12], valp[12][9];
      for(int i = 0; i < nse; i++){
        int n0 = exn[nse][i][0], n1 = exn[nse][i][1];
        if(levels[n[n0]] * levels[n[n1]] <= 0.) {
          double c = InterpolateIso(x, y, z, levels, 0., n[n0], n[n1],
                                    &xp[np], &yp[np], &zp[np]);
          for(int comp = 0; comp < numComp; comp++){
            double v0, v1;
            wdata->getValue(otherstep, ent, ele, n[n0], comp, v0);
            wdata->getValue(otherstep, ent, ele, n[n1], comp, v1);
            valp[np][comp] = v0 + c * (v1 - v0);
          }
          ep[np++] = i + 1;
        }
      }

      // remove identical nodes (this can happen if an edge actually
      // belongs to the zero levelset, i.e., if levels[] * levels[] == 0)
      if(np > 1) removeIdenticalNodes(&np, numComp, xp, yp, zp, valp, ep);

      // if there are no cuts and we extract the volume, save the full
      // element if it is on the correct side of the levelset
      if(np <= 1 && _extractVolume){
        bool add = true;
        for(int nod = 0; nod < nsn; nod++){
          if((_extractVolume < 0. && levels[n[nod]] > 0.) ||
             (_extractVolume > 0. && levels[n[nod]] < 0.)){
            add = false;
            break;
          }
        }
        if(add){
          for(int nod = 0; nod < nsn; nod++){
            xp[nod] = x[n[nod]];
            yp[nod] = y[n[nod]];
            zp[nod] = z[n[nod]];
            for(int comp = 0; comp < numComp; comp++)
              wdata->getValue(otherstep, ent, ele, n[nod], comp, valp[nod][comp]);
          }
          _addElement(nsn, nse, numComp, xp, yp, zp, valp, out, step == stepmin);
        }
        continue;
      }

      // discard invalid cases
      if(numEdges > 4 && np < 3) // 3D input should only lead to 2D output
        continue;
      else if(numEdges > 1 && np < 2) // 2D input should only lead to 1D output
        continue;
      else if(np < 1 || np > 4) // can't deal with this
        continue;

      // avoid "butterflies"
      if(np == 4) reorderQuad(numComp, xp, yp, zp, valp, ep);

      // orient the triangles and the quads to get the normals right
      if(!_extractVolume && (np == 3 || np == 4)) {
        // compute invertion test only once for spatially-fixed views
        if(step == stepmin || !_valueIndependent) {
          double v1[3] = {xp[2] - xp[0], yp[2] - yp[0], zp[2] - zp[0]};
          double v2[3] = {xp[1] - xp[0], yp[1] - yp[0], zp[1] - zp[0]};
          double gr[3], normal[3];
          prodve(v1, v2, normal);
          switch (_orientation) {
          case MAP:
            gradSimplex(x, y, z, scalarValues, gr);
            prosca(gr, normal, &_invert);
            break;
          case PLANE:
            prosca(normal, _ref, &_invert);
            break;
          case SPHERE:
            gr[0] = xp[0] - _ref[0];
            gr[1] = yp[0] - _ref[1];
            gr[2] = zp[0] - _ref[2];
            prosca(gr, normal, &_invert);
          case NONE:
          default:
            break;
          }
        }
        if(_invert > 0.) {
          double xpi[12], ypi[12], zpi[12], valpi[12][9];
          int epi[12];
          for(int k = 0; k < np; k++)
            affect(xpi, ypi, zpi, valpi, epi, k, xp, yp, zp, valp, ep, k, numComp);
          for(int k = 0; k < np; k++)
            affect(xp, yp, zp, valp, ep, k, xpi, ypi, zpi, valpi, epi, np - k - 1, numComp);
        }
      }

      // if we extract volumes, add the nodes on the chosen side
      // (FIXME: when cutting 2D views, the elts can have the wrong
      // orientation)
      if(_extractVolume){
        int nbCut = np;
        for(int nod = 0; nod < nsn; nod++){
          if((_extractVolume < 0. && levels[n[nod]] < 0.) ||
             (_extractVolume > 0. && levels[n[nod]] > 0.)){
            xp[np] = x[n[nod]];
            yp[np] = y[n[nod]];
            zp[np] = z[n[nod]];
            for(int comp = 0; comp < numComp; comp++)
              wdata->getValue(otherstep, ent, ele, n[nod], comp, valp[np][comp]);
            ep[np] = -(nod + 1); // store node num!
            np++;
          }
        }
        removeIdenticalNodes(&np, numComp, xp, yp, zp, valp, ep);
        if(np == 4 && numEdges <= 4)
          reorderQuad(numComp, xp, yp, zp, valp, ep);
        if(np == 6)
          reorderPrism(numComp, xp, yp, zp, valp, ep, nbCut);
        if(np > 8) // can't deal with this
          continue;
      }

      // finally, add the new element
      _addElement(np, numEdges, numComp, xp, yp, zp, valp, out, step == stepmin);

    }

    if(vstep < 0){
      for(int i = stepmin; i < stepmax; i++) {
	out->Time.push_back(vdata->getTime(i));
      }
    }

  }
}