diff --git a/Mesh/Field.cpp b/Mesh/Field.cpp index 5e86dfac0767f419a8b2c64e7de12c225aef507e..114d8928035094360d30132e5e92c9fb3cfbc520 100644 --- a/Mesh/Field.cpp +++ b/Mesh/Field.cpp @@ -2186,6 +2186,165 @@ class AttractorField : public Field } }; +class OctreeField : public Field { + // octree field + class Cell { + void *_data; + bool _isleaf; + public: + double evaluate(double x, double y, double z) const { + if (_isleaf) + return *(double*)_data; + Cell *sub = (Cell*)_data; + int i = x > 0.5 ? 1 : 0; + int j = y > 0.5 ? 1 : 0; + int k = z > 0.5 ? 1 : 0; + return sub[i*4+j*2+k].evaluate(2*x-i, 2*y-j, 2*z-k); + } + Cell(){}; + void init(double x0, double y0, double z0, double l, Field &field, int level) { +#if 0 + double v[8] = { + field(x0,y0,z0),field(x0,y0,z0+l),field(x0,y0+l,z0),field(x0,y0+l,z0+l), + field(x0+l,y0,z0),field(x0+l,y0,z0+l),field(x0+l,y0+l,z0),field(x0+l,y0+l,z0+l) + }; + double dmax = 0; + double vmin = v[0]; + double vc = field(x0+l/2,y0+l/2,z0+l/2); + for (int i = 0; i < 8; ++i){ + dmax = fmax(dmax, std::abs(vc-v[i])); + vmin = fmin(vmin, v[i]); + } +#else + double dmax = 0; + double vc = field(x0+l/2,y0+l/2,z0+l/2); + double vmin = vc; + bool split = level > 0; + if (level > -4) { +#define NSAMPLE 2 + double dl = l/NSAMPLE; + for (int i = 0; i <= NSAMPLE; ++i){ + for (int j = 0; j <= NSAMPLE; ++j){ + for (int k = 0; k <= NSAMPLE; ++k){ + double w = field(x0 + i*dl, y0+j*dl, z0+k*dl); + dmax = fmax(dmax, std::abs(vc-w)); + vmin = fmin(vmin, w); + split |= (dmax/vmin > 0.2 && vmin < l); + if(split) + break; + } + } + } +#endif + } + if (split) { + _isleaf = false; + Cell *sub = new Cell[8]; + double l2 = l/2; + sub[0].init(x0, y0, z0, l2, field, level-1); + sub[1].init(x0, y0, z0+l2, l2, field, level-1); + sub[2].init(x0, y0+l2, z0, l2, field, level-1); + sub[3].init(x0, y0+l2, z0+l2, l2, field, level-1); + sub[4].init(x0+l2, y0, z0, l2, field, level-1); + sub[5].init(x0+l2, y0, z0+l2, l2, field, level-1); + sub[6].init(x0+l2, y0+l2, z0, l2, field, level-1); + sub[7].init(x0+l2, y0+l2, z0+l2, l2, field, level-1); + _data = (void*)sub; + } + else { + _isleaf = true; + _data = (void*)new double; + *(double*)_data = vc; + } + } + ~Cell() { + if (_isleaf) { + delete (double*)_data; + } + else { + Cell *sub = (Cell*)_data; + delete []sub; + } + } + void print(double x0, double y0, double z0, double l, FILE *f) { + if (_isleaf) { + fprintf(f, "SP(%g, %g, %g) {%g};\n", x0+l/2, y0+l/2, z0+l/2, *(double*)_data); + } + else { + Cell *sub = (Cell*)_data; + double l2 = l/2; + sub[0].print(x0, y0, z0, l2, f); + sub[1].print(x0, y0, z0+l2, l2, f); + sub[2].print(x0, y0+l2, z0, l2, f); + sub[3].print(x0, y0+l2, z0+l2, l2, f); + sub[4].print(x0+l2, y0, z0, l2, f); + sub[5].print(x0+l2, y0, z0+l2, l2, f); + sub[6].print(x0+l2, y0+l2, z0, l2, f); + sub[7].print(x0+l2, y0+l2, z0+l2, l2, f); + } + } + }; + Cell *_root; + int _inFieldId; + Field *_inField; + SBoundingBox3d bounds; + double _l0; + public: + OctreeField() + { + options["InField"] = new FieldOptionInt + (_inFieldId, "Id of the field to use as x coordinate.", &update_needed); + _root = NULL; + } + ~OctreeField() + { + if (_root) + delete _root; + } + const char *getName() + { + return "Octree"; + } + std::string getDescription() + { + return "Pre compute another field on an octree to speed-up evalution"; + } + virtual double operator() (double X, double Y, double Z, GEntity *ge=0) + { + if(update_needed) { + update_needed = false; + if (_root) { + delete _root; + _root = NULL; + } + } + if(!_root) { + _inField = _inFieldId >= 0 ? (GModel::current()->getFields()->get(_inFieldId)) : NULL; + if (!_inField) + return 0.; + bounds = GModel::current()->bounds(); + _root = new Cell; + SVector3 d = bounds.max() - bounds.min(); + _l0 = std::max(std::max(d.x(), d.y()), d.z()); + _root->init(bounds.min().x(), bounds.min().y(), bounds.min().z(), _l0, *_inField, 4); + + + /*printf("octree built\n"); + + FILE *f = fopen("test.pos", "w"); + fprintf(f, "View \"test\" {\n"); + _root->print(bounds.min().x(), bounds.min().y(), bounds.min().z(), _l0, f); + fprintf(f, "};\n"); + fclose(f);*/ + + + } + SPoint3 xmin = bounds.min(); + SVector3 d = bounds.max() - xmin; + return _root->evaluate((X-xmin.x())/_l0,(Y-xmin.y())/_l0,(Z-xmin.z())/_l0); + } +}; + const char *BoundaryLayerField::getName() { return "BoundaryLayer"; @@ -2553,6 +2712,7 @@ FieldManager::FieldManager() map_type_name["PostView"] = new FieldFactoryT<PostViewField>(); #endif map_type_name["Gradient"] = new FieldFactoryT<GradientField>(); + map_type_name["Octree"] = new FieldFactoryT<OctreeField>(); map_type_name["Restrict"] = new FieldFactoryT<RestrictField>(); map_type_name["Min"] = new FieldFactoryT<MinField>(); map_type_name["MinAniso"] = new FieldFactoryT<MinAnisoField>(); @@ -2680,3 +2840,5 @@ void GenericField::setCallbackWithData(ptrfunction fct, void *data){ user_data.push_back(data); cbs.push_back(fct); } + +