Skip to content
Snippets Groups Projects
Select Git revision
  • 3b86cf6119b6abf3ae983fa9569d6a0e65815a35
  • master default protected
  • pluginMeshQuality
  • fixBugsAmaury
  • hierarchical-basis
  • alphashapes
  • bl
  • relaying
  • new_export_boris
  • oras_vs_osm
  • reassign_partitions
  • distributed_fwi
  • rename-classes
  • fix/fortran-api-example-t4
  • robust_partitions
  • reducing_files
  • fix_overlaps
  • 3115-issue-fix
  • 3023-Fillet2D-Update
  • convert_fdivs
  • tmp_jcjc24
  • gmsh_4_14_0
  • gmsh_4_13_1
  • gmsh_4_13_0
  • gmsh_4_12_2
  • gmsh_4_12_1
  • gmsh_4_12_0
  • gmsh_4_11_1
  • gmsh_4_11_0
  • gmsh_4_10_5
  • gmsh_4_10_4
  • gmsh_4_10_3
  • gmsh_4_10_2
  • gmsh_4_10_1
  • gmsh_4_10_0
  • gmsh_4_9_5
  • gmsh_4_9_4
  • gmsh_4_9_3
  • gmsh_4_9_2
  • gmsh_4_9_1
  • gmsh_4_9_0
41 results

Numeric.h

Blame
  • VertexArray.cpp 11.28 KiB
    // Gmsh - Copyright (C) 1997-2019 C. Geuzaine, J.-F. Remacle
    //
    // See the LICENSE.txt file for license information. Please report all
    // issues on https://gitlab.onelab.info/gmsh/gmsh/issues.
    
    #include <string.h>
    #include <algorithm>
    #include "GmshMessage.h"
    #include "VertexArray.h"
    #include "Context.h"
    #include "Numeric.h"
    #include "OS.h"
    
    template<int N> float ElementDataLessThan<N>::tolerance = 0.0F;
    float BarycenterLessThan::tolerance = 0.0F;
    
    VertexArray::VertexArray(int numVerticesPerElement, int numElements)
      : _numVerticesPerElement(numVerticesPerElement)
    {
      int nb = (numElements ? numElements : 1) * _numVerticesPerElement;
    
      double memv = (nb * 3. * sizeof(float)) / 1024. / 1024.;
      double memmax = TotalRam() / 3.;
      if(memv > memmax){
        int old = nb;
        nb = memmax / (3. * sizeof(float)) * 1024 * 1024;
        Msg::Debug("Reduce preallocation of vertex array (%d -> %d)", old, nb);
      }
      _vertices.reserve(nb * 3);
      _normals.reserve(nb * 3);
      _colors.reserve(nb * 4);
    }
    
    double VertexArray::getMemoryInMb()
    {
      int bytes = _vertices.size() * sizeof(float) +
                  _normals.size() * sizeof(normal_type) +
                  _colors.size() * sizeof(unsigned char);
      return (double)bytes / 1024. / 1024.;
    }
    
    void VertexArray::_addVertex(float x, float y, float z)
    {
      _vertices.push_back(x);
      _vertices.push_back(y);
      _vertices.push_back(z);
    }
    
    void VertexArray::_addNormal(float nx, float ny, float nz)
    {
    #if defined(HAVE_VISUDEV)
      _normals.push_back(nx);
      _normals.push_back(ny);
      _normals.push_back(nz);
    #else
      // storing the normals as bytes hurts rendering performance, but it
      // significantly reduces the memory footprint
      char cx = float2char(nx);
      char cy = float2char(ny);
      char cz = float2char(nz);
      _normals.push_back(cx);
      _normals.push_back(cy);
      _normals.push_back(cz);
    #endif
    }
    
    void VertexArray::_addColor(unsigned char r, unsigned char g, unsigned char b,
                                unsigned char a)
    {
      _colors.push_back(r);
      _colors.push_back(g);
      _colors.push_back(b);
      _colors.push_back(a);
    }
    
    void VertexArray::_addElement(MElement *ele)
    {
      if(ele && CTX::instance()->pickElements) _elements.push_back(ele);
    }
    
    void VertexArray::add(double *x, double *y, double *z, SVector3 *n,
                          unsigned int *col, MElement *ele, bool unique, bool boundary)
    {
      if(col){
        unsigned char r[100], g[100], b[100], a[100];
        int npe = getNumVerticesPerElement();
        for(int i = 0; i < npe; i++){
          r[i] = CTX::instance()->unpackRed(col[i]);
          g[i] = CTX::instance()->unpackGreen(col[i]);
          b[i] = CTX::instance()->unpackBlue(col[i]);
          a[i] = CTX::instance()->unpackAlpha(col[i]);
        }
        add(x, y, z, n, r, g, b, a, ele, unique, boundary);
      }
      else
        add(x, y, z, n, 0, 0, 0, 0, ele, unique, boundary);
    }
    
    void VertexArray::add(double *x, double *y, double *z, SVector3 *n, unsigned char *r,
                          unsigned char *g, unsigned char *b, unsigned char *a,
                          MElement *ele, bool unique, bool boundary)
    {
      int npe = getNumVerticesPerElement();
    
      if(boundary && npe == 3){
        ElementData<3> e(x, y, z, n, r, g, b, a, ele);
        ElementDataLessThan<3>::tolerance = (float)(CTX::instance()->lc * 1.e-12);
        std::set<ElementData<3>, ElementDataLessThan<3> >::iterator it = _data3.find(e);
        if(it == _data3.end())
          _data3.insert(e);
        else
          _data3.erase(it);
        return;
      }
    
      // enabling this will reduce memory and rendering time; but will increase the
      // time it takes to create the vertex array
    #if 0
      if(unique){
        Barycenter pc(0.0F, 0.0F, 0.0F);
        for(int i = 0; i < npe; i++)
          pc += Barycenter(x[i], y[i], z[i]);
        BarycenterLessThan::tolerance = (float)(CTX::instance()->lc * 1.e-12);
        if(_barycenters.find(pc) != _barycenters.end())
          return;
        _barycenters.insert(pc);
      }
    #endif
    
      for(int i = 0; i < npe; i++){
        _addVertex((float)x[i], (float)y[i], (float)z[i]);
        if(n) _addNormal((float)n[i].x(), (float)n[i].y(), (float)n[i].z());
        if(r && g && b && a) _addColor(r[i], g[i], b[i], a[i]);
        _addElement(ele);
      }
    }
    
    void VertexArray::finalize()
    {
      if(_data3.size()){
        std::set<ElementData<3>, ElementDataLessThan<3> >::iterator it = _data3.begin();
        for(; it != _data3.end(); it++){
          for(int i = 0; i < 3; i++){
            _addVertex(it->x(i), it->y(i), it->z(i));
            _addNormal(it->nx(i), it->ny(i), it->nz(i));
            _addColor(it->r(i), it->g(i), it->b(i), it->a(i));
            _addElement(it->ele());
          }
        }
        _data3.clear();
      }
      _barycenters.clear();
    }
    
    class AlphaElement {
     public:
      AlphaElement(float *vp, normal_type *np, unsigned char *cp) : v(vp), n(np), c(cp) {}
      float *v;
      normal_type *n;
      unsigned char *c;
    };
    
    class AlphaElementLessThan {
     public:
      static int numVertices;
      static double eye[3];
      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);
      }
    };
    
    int AlphaElementLessThan::numVertices = 0;
    double AlphaElementLessThan::eye[3] = {0., 0., 0.};
    
    void VertexArray::sort(double x, double y, double z)
    {
      // This simplementation is pretty bad: it copies the whole data
      // twice. We should think about a more efficient way to sort the
      // three arrays in place.
    
      int npe = getNumVerticesPerElement();
      int n = getNumVertices() / npe;
    
      AlphaElementLessThan::numVertices = npe;
      AlphaElementLessThan::eye[0] = x;
      AlphaElementLessThan::eye[1] = y;
      AlphaElementLessThan::eye[2] = z;
    
      std::vector<AlphaElement> elements;
      elements.reserve(n);
      for(int i = 0; i < n; i++){
        float *vp = &_vertices[3 * npe * i];
        normal_type *np = _normals.empty() ? 0 : &_normals[3 * npe * i];
        unsigned char *cp = _colors.empty() ? 0 : &_colors[4 * npe * i];
        elements.push_back(AlphaElement(vp, np, cp));
      }
      std::sort(elements.begin(), elements.end(), AlphaElementLessThan());
    
      std::vector<float> sortedVertices;
      std::vector<normal_type> sortedNormals;
      std::vector<unsigned char> sortedColors;
      sortedVertices.reserve(_vertices.size());
      sortedNormals.reserve(_normals.size());
      sortedColors.reserve(_colors.size());
    
      for(int i = 0; i < n; i++){
        for(int j = 0; j < npe; j++){
          for(int k = 0; k < 3; k++)
            sortedVertices.push_back(elements[i].v[3 * j + k]);
          if(elements[i].n)
            for(int k = 0; k < 3; k++)
              sortedNormals.push_back(elements[i].n[3 * j + k]);
          if(elements[i].c)
            for(int k = 0; k < 4; k++)
              sortedColors.push_back(elements[i].c[4 * j + k]);
        }
      }
    
      _vertices = sortedVertices;
      _normals = sortedNormals;
      _colors = sortedColors;
    }
    
    char *VertexArray::toChar(int num, const std::string &name, int type,
                              double min, double max, int numsteps, double time,
                              const SBoundingBox3d &bbox, int &len)
    {
      int vn = _vertices.size(), nn = _normals.size(), cn = _colors.size();
      int vs = vn * sizeof(float),
          ns = nn * sizeof(normal_type),
          cs = cn * sizeof(unsigned char);
      int is = sizeof(int), ds = sizeof(double);
      int ss = name.size();
      double xmin = bbox.min().x(), ymin = bbox.min().y(), zmin = bbox.min().z();
      double xmax = bbox.max().x(), ymax = bbox.max().y(), zmax = bbox.max().z();
    
      len = ss + 7 * is + 9 * ds + vs + ns + cs;
      char *bytes = new char[len];
      int index = 0;
      memcpy(&bytes[index], &num, is); index += is;
      memcpy(&bytes[index], &ss, is); index += is;
      memcpy(&bytes[index], name.c_str(), ss); index += ss;
      memcpy(&bytes[index], &type, is); index += is;
      memcpy(&bytes[index], &min, ds); index += ds;
      memcpy(&bytes[index], &max, ds); index += ds;
      memcpy(&bytes[index], &numsteps, is); index += is;
      memcpy(&bytes[index], &time, ds); index += ds;
      memcpy(&bytes[index], &xmin, ds); index += ds;
      memcpy(&bytes[index], &ymin, ds); index += ds;
      memcpy(&bytes[index], &zmin, ds); index += ds;
      memcpy(&bytes[index], &xmax, ds); index += ds;
      memcpy(&bytes[index], &ymax, ds); index += ds;
      memcpy(&bytes[index], &zmax, ds); index += ds;
      memcpy(&bytes[index], &vn, is); index += is;
      if(vs){ memcpy(&bytes[index], &_vertices[0], vs); index += vs; }
      memcpy(&bytes[index], &nn, is); index += is;
      if(ns){ memcpy(&bytes[index], &_normals[0], ns); index += ns; }
      memcpy(&bytes[index], &cn, is); index += is;
      if(cs){ memcpy(&bytes[index], &_colors[0], cs); /* index += cs; */ }
      return bytes;
    }
    
    int VertexArray::decodeHeader(int length, const char *bytes, int swap,
                                  std::string &name, int &tag, int &type,
                                  double &min, double &max, int &numSteps, double &time,
                                  double &xmin, double &ymin, double &zmin,
                                  double &xmax, double &ymax, double &zmax)
    {
      int is = sizeof(int), ds = sizeof(double);
    
      if(length < 4 * is + 9 * ds){
        Msg::Error("Too few bytes to create vertex array: %d", length);
        return 0;
      }
    
      if(swap){
        Msg::Error("Should swap bytes in vertex array--not implemented yet");
        return 0;
      }
    
      int index = 0;
      memcpy(&tag, &bytes[index], is); index += is;
      int ss; memcpy(&ss, &bytes[index], is); index += is;
      if(ss){
        std::vector<char> n(ss);
        memcpy(&n[0], &bytes[index], ss); index += ss;
        for(std::size_t i = 0; i < n.size(); i++) name += n[i];
      }
      memcpy(&type, &bytes[index], is); index += is;
      memcpy(&min, &bytes[index], ds); index += ds;
      memcpy(&max, &bytes[index], ds); index += ds;
      memcpy(&numSteps, &bytes[index], is); index += is;
      memcpy(&time, &bytes[index], ds); index += ds;
      memcpy(&xmin, &bytes[index], ds); index += ds;
      memcpy(&ymin, &bytes[index], ds); index += ds;
      memcpy(&zmin, &bytes[index], ds); index += ds;
      memcpy(&xmax, &bytes[index], ds); index += ds;
      memcpy(&ymax, &bytes[index], ds); index += ds;
      memcpy(&zmax, &bytes[index], ds); index += ds;
      return index;
    }
    
    void VertexArray::fromChar(int length, const char *bytes, int swap)
    {
      std::string name;
      int tag, type, numSteps;
      double min, max, time, xmin, ymin, zmin, xmax, ymax, zmax;
      int index = decodeHeader(length, bytes, swap, name, tag, type, min, max,
                               numSteps, time, xmin, ymin, zmin, xmax, ymax, zmax);
      if(!index) return;
    
      int is = sizeof(int);
      int vn; memcpy(&vn, &bytes[index], is); index += is;
      if(vn){
        _vertices.resize(vn); int vs = vn * sizeof(float);
        memcpy(&_vertices[0], &bytes[index], vs); index += vs;
      }
    
      int nn; memcpy(&nn, &bytes[index], is); index += is;
      if(nn){
        _normals.resize(nn);
        int ns = nn * sizeof(normal_type);
        memcpy(&_normals[0], &bytes[index], ns); index += ns;
      }
    
      int cn; memcpy(&cn, &bytes[index], is); index += is;
      if(cn){
        _colors.resize(cn); int cs = cn * sizeof(unsigned char);
        memcpy(&_colors[0], &bytes[index], cs); /* index += cs; */
      }
    }
    
    void VertexArray::merge(VertexArray* va)
    {
      if(va->getNumVertices() != 0) {
        _vertices.insert(_vertices.end(), va->firstVertex(), va->lastVertex());
        _normals.insert(_normals.end(), va->firstNormal(), va->lastNormal());
        _colors.insert(_colors.end(), va->firstColor(), va->lastColor());
        _elements.insert(_elements.end(), va->firstElementPointer(),
                         va->lastElementPointer());
      }
    }