From 8a11eb57e149ed2502f6682e6c3b788e0f431672 Mon Sep 17 00:00:00 2001 From: Christophe Geuzaine <cgeuzaine@ulg.ac.be> Date: Sun, 29 May 2011 10:03:35 +0000 Subject: [PATCH] several fixes to levelset plugin (multi-step non-simplexs, extract volume for non-simplex, adaptive prisms) --- Plugin/Levelset.cpp | 327 +++++++++++++++++++++++++----------------- Plugin/Levelset.h | 2 +- Post/adaptiveData.cpp | 2 +- 3 files changed, 194 insertions(+), 137 deletions(-) diff --git a/Plugin/Levelset.cpp b/Plugin/Levelset.cpp index 079750ded8..a6ed07b067 100644 --- a/Plugin/Levelset.cpp +++ b/Plugin/Levelset.cpp @@ -94,7 +94,7 @@ static void removeIdenticalNodes(int *np, int numComp, fabs(zp[j] - zpi[i]) < 1.e-12) { break; } - if(i == npi-1) { + if(i == npi - 1) { affect(xpi, ypi, zpi, valpi, epi, npi, xp, yp, zp, valp, ep, j, numComp); npi++; break; @@ -261,144 +261,163 @@ void GMSH_LevelsetPlugin::_addElement(int np, int numEdges, int numComp, } void GMSH_LevelsetPlugin::_cutAndAddElements(PViewData *vdata, PViewData *wdata, - int ent, int ele, int step, int wstep, + 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, bool firstStep) + PViewDataList* out) { - int numNodes = vdata->getNumNodes(step, ent, ele); - int numEdges = vdata->getNumEdges(step, ent, ele); - int numComp = wdata->getNumComponents(wstep, ent, ele); - int type = vdata->getType(step, ent, ele); + 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++){ - double xp[12], yp[12], zp[12], valp[12][9]; - int n[4], np = 0, ep[12], nsn, nse; - getSimplexDec(numNodes, numEdges, type, simplex, n[0], n[1], n[2], n[3], nsn, nse); - - 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(wstep, ent, ele, n[n0], comp, v0); - wdata->getValue(wstep, 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; + 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; + 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; } } - if(add){ - double xp[12], yp[12], zp[12], valp[12][9]; + + // 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++){ - xp[nod] = x[n[nod]]; - yp[nod] = y[n[nod]]; - zp[nod] = z[n[nod]]; - for(int comp = 0; comp < numComp; comp++) - wdata->getValue(wstep, ent, ele, nod, comp, valp[n[nod]][comp]); + 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); } - _addElement(nsn, nse, numComp, xp, yp, zp, valp, out, firstStep); + continue; } - continue; - } - 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)) { - if(firstStep || !_valueIndependent) { - // test this only once for spatially-fixed views - 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; + // 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(_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 compute isovolumes, 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(wstep, ent, ele, n[nod], comp, valp[np][comp]); - ep[np] = -(nod + 1); // store node num! - np++; + + // 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; } - 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; - } - _addElement(np, numEdges, numComp, xp, yp, zp, valp, out, firstStep); + // finally, add the new element + _addElement(np, numEdges, numComp, xp, yp, zp, valp, out, step == stepmin); + + } } } PView *GMSH_LevelsetPlugin::execute(PView *v) { - // FIXME: we can only run the plugin on one step at a time + // for adapted views we can only run the plugin on one step at a time if(v->getData()->isAdaptive()){ PViewOptions *opt = v->getOptions(); v->getData()->getAdaptiveData()->changeResolution @@ -406,7 +425,6 @@ PView *GMSH_LevelsetPlugin::execute(PView *v) v->setChanged(true); } - // get adaptive data if available PViewData *vdata = getPossiblyAdaptiveData(v), *wdata; if(_valueView < 0) { wdata = vdata; @@ -446,17 +464,11 @@ PView *GMSH_LevelsetPlugin::execute(PView *v) for(int ele = 0; ele < vdata->getNumElements(firstNonEmptyStep, ent); ele++){ if(vdata->skipElement(firstNonEmptyStep, ent, ele)) continue; for(int nod = 0; nod < vdata->getNumNodes(firstNonEmptyStep, ent, ele); nod++){ - vdata->getNode(0, ent, ele, nod, x[nod], y[nod], z[nod]); + vdata->getNode(firstNonEmptyStep, ent, ele, nod, x[nod], y[nod], z[nod]); levels[nod] = levelset(x[nod], y[nod], z[nod], 0.); } - for(int step = 0; step < vdata->getNumTimeSteps(); step++){ - if(vdata->hasTimeStep(step)){ - int wstep = (_valueTimeStep < 0) ? step : _valueTimeStep; - bool firstStep = (step == firstNonEmptyStep); - _cutAndAddElements(vdata, wdata, ent, ele, step, wstep, x, y, z, - levels, scalarValues, out, firstStep); - } - } + _cutAndAddElements(vdata, wdata, ent, ele, -1, _valueTimeStep, x, y, z, + levels, scalarValues, out); } } out->setName(vdata->getName() + "_Levelset"); @@ -477,7 +489,7 @@ PView *GMSH_LevelsetPlugin::execute(PView *v) } int wstep = (_valueTimeStep < 0) ? step : _valueTimeStep; _cutAndAddElements(vdata, wdata, ent, ele, step, wstep, x, y, z, - levels, scalarValues, out, true); + levels, scalarValues, out); } } char tmp[246]; @@ -501,7 +513,7 @@ static bool recur_sign_change(adaptiveTriangle *t, double v1 = plug->levelset(t->p[0]->X, t->p[0]->Y, t->p[0]->Z, t->p[0]->val); double v2 = plug->levelset(t->p[1]->X, t->p[1]->Y, t->p[1]->Z, t->p[1]->val); double v3 = plug->levelset(t->p[2]->X, t->p[2]->Y, t->p[2]->Z, t->p[2]->val); - if(v1 * v2 > 0 && v1 * v3 > 0 && v2 * v3 > 0) + if(v1 * v2 > 0 && v1 * v3 > 0) t->visible = false; else t->visible = true; @@ -638,6 +650,47 @@ static bool recur_sign_change(adaptiveHexahedron *t, } } +static bool recur_sign_change(adaptivePrism *t, + const GMSH_LevelsetPlugin *plug) +{ + if (!t->e[0] || t->visible){ + double v1 = plug->levelset(t->p[0]->X, t->p[0]->Y, t->p[0]->Z, t->p[0]->val); + double v2 = plug->levelset(t->p[1]->X, t->p[1]->Y, t->p[1]->Z, t->p[1]->val); + double v3 = plug->levelset(t->p[2]->X, t->p[2]->Y, t->p[2]->Z, t->p[2]->val); + double v4 = plug->levelset(t->p[3]->X, t->p[3]->Y, t->p[3]->Z, t->p[3]->val); + double v5 = plug->levelset(t->p[4]->X, t->p[4]->Y, t->p[4]->Z, t->p[4]->val); + double v6 = plug->levelset(t->p[5]->X, t->p[5]->Y, t->p[5]->Z, t->p[5]->val); + if(v1 * v2 > 0 && v1 * v3 > 0 && v1 * v4 > 0 && v1 * v5 > 0 && v1 * v6 > 0) + t->visible = false; + else + t->visible = true; + return t->visible; + } + else{ + bool sc1 = recur_sign_change(t->e[0], plug); + bool sc2 = recur_sign_change(t->e[1], plug); + bool sc3 = recur_sign_change(t->e[2], plug); + bool sc4 = recur_sign_change(t->e[3], plug); + bool sc5 = recur_sign_change(t->e[4], plug); + bool sc6 = recur_sign_change(t->e[5], plug); + bool sc7 = recur_sign_change(t->e[6], plug); + bool sc8 = recur_sign_change(t->e[7], plug); + if(sc1 || sc2 || sc3 || sc4 || sc5 || sc6 || sc7 || sc8){ + if (!sc1) t->e[0]->visible = true; + if (!sc2) t->e[1]->visible = true; + if (!sc3) t->e[2]->visible = true; + if (!sc4) t->e[3]->visible = true; + if (!sc5) t->e[4]->visible = true; + if (!sc6) t->e[5]->visible = true; + if (!sc7) t->e[6]->visible = true; + if (!sc8) t->e[7]->visible = true; + return true; + } + t->visible = false; + return false; + } +} + void GMSH_LevelsetPlugin::assignSpecificVisibility() const { if(adaptiveTriangle::all.size()){ @@ -645,15 +698,19 @@ void GMSH_LevelsetPlugin::assignSpecificVisibility() const if(!t->visible) t->visible = !recur_sign_change(t, this); } if(adaptiveQuadrangle::all.size()){ - adaptiveQuadrangle *qe = *adaptiveQuadrangle::all.begin(); - if(!qe->visible) qe->visible = !recur_sign_change(qe, this); + adaptiveQuadrangle *q = *adaptiveQuadrangle::all.begin(); + if(!q->visible) q->visible = !recur_sign_change(q, this); } if(adaptiveTetrahedron::all.size()){ - adaptiveTetrahedron *te = *adaptiveTetrahedron::all.begin(); - if(!te->visible) te->visible = !recur_sign_change(te, this); + adaptiveTetrahedron *t = *adaptiveTetrahedron::all.begin(); + if(!t->visible) t->visible = !recur_sign_change(t, this); } if(adaptiveHexahedron::all.size()){ - adaptiveHexahedron *he = *adaptiveHexahedron::all.begin(); - if(!he->visible) he->visible = !recur_sign_change(he, this); + adaptiveHexahedron *h = *adaptiveHexahedron::all.begin(); + if(!h->visible) h->visible = !recur_sign_change(h, this); + } + if(adaptivePrism::all.size()){ + adaptivePrism *p = *adaptivePrism::all.begin(); + if(!p->visible) p->visible = !recur_sign_change(p, this); } } diff --git a/Plugin/Levelset.h b/Plugin/Levelset.h index fb5956aae6..b0b48caa55 100644 --- a/Plugin/Levelset.h +++ b/Plugin/Levelset.h @@ -20,7 +20,7 @@ class GMSH_LevelsetPlugin : public GMSH_PostPlugin int ent, int ele, int step, int wstep, double x[8], double y[8], double z[8], double levels[8], double scalarValues[8], - PViewDataList *out, bool firstStep); + PViewDataList *out); protected: double _ref[3], _targetError; int _valueTimeStep, _valueView, _valueIndependent, _recurLevel, _extractVolume; diff --git a/Post/adaptiveData.cpp b/Post/adaptiveData.cpp index c97a1ddb01..b667d16cb5 100644 --- a/Post/adaptiveData.cpp +++ b/Post/adaptiveData.cpp @@ -659,7 +659,7 @@ void adaptiveHexahedron::recurCreate(adaptiveHexahedron *h, int maxlevel, int le (p03, p0347, pc, p0312, p3, p37, p2367, p23); // p3 recurCreate(h7, maxlevel, level); adaptiveHexahedron *h8 = new adaptiveHexahedron - (p0312, pc, p1256, p12, p23, p2367, p26, p2); //p2 + (p0312, pc, p1256, p12, p23, p2367, p26, p2); // p2 recurCreate(h8, maxlevel, level); h->e[0] = h1; h->e[1] = h2; -- GitLab