Visual Servoing Platform  version 3.2.1 under development (2019-07-16)
vpArray2D.h
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2019 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See http://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * This class implements an 2D array as a template class.
33  *
34  * Authors:
35  * Fabien Spindler
36  *
37  *****************************************************************************/
38 #ifndef _vpArray2D_h_
39 #define _vpArray2D_h_
40 
41 #include <fstream>
42 #include <iostream>
43 #include <limits>
44 #include <math.h>
45 #include <ostream>
46 #include <sstream>
47 #include <stdlib.h>
48 #include <string.h>
49 
50 #include <visp3/core/vpConfig.h>
51 #include <visp3/core/vpException.h>
52 
131 template <class Type> class vpArray2D
132 {
133 protected:
135  unsigned int rowNum;
137  unsigned int colNum;
139  Type **rowPtrs;
141  unsigned int dsize;
142 
143 public:
145  Type *data;
146 
147 public:
152  vpArray2D<Type>() : rowNum(0), colNum(0), rowPtrs(NULL), dsize(0), data(NULL) {}
153 
158  #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
159  vpArray2D<Type>()
160  #else
161  rowNum(0), colNum(0), rowPtrs(NULL), dsize(0), data(NULL)
162  #endif
163  {
164  resize(A.rowNum, A.colNum, false, false);
165  memcpy(data, A.data, (size_t)rowNum * (size_t)colNum * sizeof(Type));
166  }
167 
174  vpArray2D<Type>(unsigned int r, unsigned int c) :
175  #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
176  vpArray2D<Type>()
177  #else
178  rowNum(0), colNum(0), rowPtrs(NULL), dsize(0), data(NULL)
179  #endif
180  {
181  resize(r, c);
182  }
183 
191  vpArray2D<Type>(unsigned int r, unsigned int c, Type val) :
192  #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
193  vpArray2D<Type>()
194  #else
195  rowNum(0), colNum(0), rowPtrs(NULL), dsize(0), data(NULL)
196  #endif
197  {
198  resize(r, c, false, false);
199  *this = val;
200  }
201 
202 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
204  {
205  rowNum = A.rowNum;
206  colNum = A.colNum;
207  rowPtrs = A.rowPtrs;
208  dsize = A.dsize;
209  data = A.data;
210 
211  A.rowNum = 0;
212  A.colNum = 0;
213  A.rowPtrs = NULL;
214  A.dsize = 0;
215  A.data = NULL;
216  }
217 
218  explicit vpArray2D<Type>(const std::initializer_list<Type> &list) : vpArray2D<Type>()
219  {
220  resize(1, static_cast<unsigned int>(list.size()), false, false);
221  std::copy(list.begin(), list.end(), data);
222  }
223 
224  explicit vpArray2D<Type>(unsigned int nrows, unsigned int ncols, const std::initializer_list<Type> &list)
225  : rowNum(0), colNum(0), rowPtrs(NULL), dsize(0), data(NULL)
226  {
227  if (nrows * ncols != static_cast<unsigned int>(list.size())) {
228  std::ostringstream oss;
229  oss << "Cannot create a vpArray2D of size (" << nrows << ", " << ncols
230  << ") with a list of size " << list.size();
231  throw vpException(vpException::dimensionError, oss.str());
232  }
233 
234  resize(nrows, ncols, false, false);
235  std::copy(list.begin(), list.end(), data);
236  }
237 
238  explicit vpArray2D<Type>(const std::initializer_list<std::initializer_list<Type> > &lists) : vpArray2D<Type>()
239  {
240  unsigned int nrows = static_cast<unsigned int>(lists.size()), ncols = 0;
241  for (auto& l : lists) {
242  if (static_cast<unsigned int>(l.size()) > ncols) {
243  ncols = static_cast<unsigned int>(l.size());
244  }
245  }
246 
247  resize(nrows, ncols, false, false);
248  auto it = lists.begin();
249  for (unsigned int i = 0; i < rowNum; i++, ++it) {
250  std::copy(it->begin(), it->end(), rowPtrs[i]);
251  }
252  }
253 #endif
254 
258  virtual ~vpArray2D<Type>()
259  {
260  if (data != NULL) {
261  free(data);
262  data = NULL;
263  }
264 
265  if (rowPtrs != NULL) {
266  free(rowPtrs);
267  rowPtrs = NULL;
268  }
269  rowNum = colNum = dsize = 0;
270  }
271 
274 
279  inline unsigned int getCols() const { return colNum; }
280 
281  Type getMaxValue() const;
282 
283  Type getMinValue() const;
284 
289  inline unsigned int getRows() const { return rowNum; }
291  inline unsigned int size() const { return colNum * rowNum; }
292 
305  void resize(const unsigned int nrows, const unsigned int ncols, const bool flagNullify = true,
306  const bool recopy_ = true)
307  {
308  if ((nrows == rowNum) && (ncols == colNum)) {
309  if (flagNullify && this->data != NULL) {
310  memset(this->data, 0, this->dsize * sizeof(Type));
311  }
312  } else {
313  bool recopy = !flagNullify && recopy_; // priority to flagNullify
314  const bool recopyNeeded = (ncols != this->colNum && this->colNum > 0 && ncols > 0 && (!flagNullify || recopy));
315  Type *copyTmp = NULL;
316  unsigned int rowTmp = 0, colTmp = 0;
317 
318  // Recopy case per case is required if number of cols has changed;
319  // structure of Type array is not the same in this case.
320  if (recopyNeeded && this->data != NULL) {
321  copyTmp = new Type[this->dsize];
322  memcpy(copyTmp, this->data, sizeof(Type) * this->dsize);
323  rowTmp = this->rowNum;
324  colTmp = this->colNum;
325  }
326 
327  // Reallocation of this->data array
328  this->dsize = nrows * ncols;
329  this->data = (Type *)realloc(this->data, this->dsize * sizeof(Type));
330  if ((NULL == this->data) && (0 != this->dsize)) {
331  if (copyTmp != NULL) {
332  delete[] copyTmp;
333  }
334  throw(vpException(vpException::memoryAllocationError, "Memory allocation error when allocating 2D array data"));
335  }
336 
337  this->rowPtrs = (Type **)realloc(this->rowPtrs, nrows * sizeof(Type *));
338  if ((NULL == this->rowPtrs) && (0 != this->dsize)) {
339  if (copyTmp != NULL) {
340  delete[] copyTmp;
341  }
343  "Memory allocation error when allocating 2D array rowPtrs"));
344  }
345 
346  // Update rowPtrs
347  {
348  Type **t_ = rowPtrs;
349  for (unsigned int i = 0; i < dsize; i += ncols) {
350  *t_++ = this->data + i;
351  }
352  }
353 
354  this->rowNum = nrows;
355  this->colNum = ncols;
356 
357  // Recopy of this->data array values or nullify
358  if (flagNullify) {
359  memset(this->data, 0, (size_t)(this->dsize) * sizeof(Type));
360  } else if (recopyNeeded && this->rowPtrs != NULL) {
361  // Recopy...
362  const unsigned int minRow = (this->rowNum < rowTmp) ? this->rowNum : rowTmp;
363  const unsigned int minCol = (this->colNum < colTmp) ? this->colNum : colTmp;
364  for (unsigned int i = 0; i < this->rowNum; ++i) {
365  for (unsigned int j = 0; j < this->colNum; ++j) {
366  if ((minRow > i) && (minCol > j)) {
367  (*this)[i][j] = copyTmp[i * colTmp + j];
368  } else {
369  (*this)[i][j] = 0;
370  }
371  }
372  }
373  }
374 
375  if (copyTmp != NULL) {
376  delete[] copyTmp;
377  }
378  }
379  }
380 
381  void reshape(unsigned int nrows, unsigned int ncols)
382  {
383  if (dsize == 0) {
384  resize(nrows, ncols);
385  return;
386  }
387 
388  if (nrows * ncols != dsize) {
389  std::ostringstream oss;
390  oss << "Cannot reshape array of total size " << dsize
391  << " into shape (" << nrows << ", " << ncols << ")";
392  throw vpException(vpException::dimensionError, oss.str());
393  }
394 
395  rowNum = nrows;
396  colNum = ncols;
397  rowPtrs = reinterpret_cast<Type **>(realloc(rowPtrs, nrows * sizeof(Type *)));
398  // Update rowPtrs
399  Type **t_ = rowPtrs;
400  for (unsigned int i = 0; i < dsize; i += ncols) {
401  *t_++ = data + i;
402  }
403  }
404 
407  {
408  std::fill(data, data + dsize, x);
409  return *this;
410  }
411 
416  {
417  resize(A.rowNum, A.colNum, false, false);
418  if (data != NULL && A.data != NULL && data != A.data) {
419  memcpy(data, A.data, (size_t)rowNum * (size_t)colNum * sizeof(Type));
420  }
421  return *this;
422  }
423 
424 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
426  {
427  if (this != &other) {
428  free(data);
429  free(rowPtrs);
430 
431  rowNum = other.rowNum;
432  colNum = other.colNum;
433  rowPtrs = other.rowPtrs;
434  dsize = other.dsize;
435  data = other.data;
436 
437  other.rowNum = 0;
438  other.colNum = 0;
439  other.rowPtrs = NULL;
440  other.dsize = 0;
441  other.data = NULL;
442  }
443 
444  return *this;
445  }
446 
447  vpArray2D<Type> &operator=(const std::initializer_list<Type> &list)
448  {
449  if (dsize != static_cast<unsigned int>(list.size())) {
450  resize(1, static_cast<unsigned int>(list.size()), false, false);
451  }
452  std::copy(list.begin(), list.end(), data);
453 
454  return *this;
455  }
456 
457  vpArray2D<Type> &operator=(const std::initializer_list<std::initializer_list<Type> > &lists)
458  {
459  unsigned int nrows = static_cast<unsigned int>(lists.size()), ncols = 0;
460  for (auto& l : lists) {
461  if (static_cast<unsigned int>(l.size()) > ncols) {
462  ncols = static_cast<unsigned int>(l.size());
463  }
464  }
465 
466  resize(nrows, ncols, false, false);
467  auto it = lists.begin();
468  for (unsigned int i = 0; i < rowNum; i++, ++it) {
469  std::copy(it->begin(), it->end(), rowPtrs[i]);
470  }
471 
472  return *this;
473  }
474 #endif
475 
477  inline Type *operator[](unsigned int i) { return rowPtrs[i]; }
479  inline Type *operator[](unsigned int i) const { return rowPtrs[i]; }
480 
486  friend std::ostream &operator<<(std::ostream &s, const vpArray2D<Type> &A)
487  {
488  if (A.data == NULL || A.size() == 0) {
489  return s;
490  }
491  std::ios_base::fmtflags original_flags = s.flags();
492 
493  s.precision(10);
494  for (unsigned int i = 0; i < A.getRows(); i++) {
495  for (unsigned int j = 0; j < A.getCols() - 1; j++) {
496  s << A[i][j] << " ";
497  }
498  // We don't add " " after the last row element
499  s << A[i][A.getCols() - 1];
500  // We don't add a \n char on the end of the last array line
501  if (i < A.getRows() - 1) {
502  s << std::endl;
503  }
504  }
505 
506  s.flags(original_flags); // restore s to standard state
507 
508  return s;
509  }
510 
511  vpArray2D<Type> hadamard(const vpArray2D<Type> &m) const;
513 
514  //---------------------------------
515  // Inherited array I/O Static Public Member Functions
516  //---------------------------------
533  static bool load(const std::string &filename, vpArray2D<Type> &A, const bool binary = false, char *header = NULL)
534  {
535  std::fstream file;
536 
537  if (!binary) {
538  file.open(filename.c_str(), std::fstream::in);
539  }
540  else {
541  file.open(filename.c_str(), std::fstream::in | std::fstream::binary);
542  }
543 
544  if (!file) {
545  file.close();
546  return false;
547  }
548 
549  if (!binary) {
550  std::string h;
551  bool headerIsDecoded = false;
552  do {
553  std::streampos pos = file.tellg();
554  char line[256];
555  file.getline(line, 256);
556  std::string prefix("# ");
557  std::string line_(line);
558  if (line_.compare(0, 2, prefix.c_str()) == 0) {
559  // Line is a comment
560  // If we are not on the first line, we should add "\n" to the end of
561  // the previous line
562  if (pos) {
563  h += "\n";
564  }
565  h += line_.substr(2); // Remove "# "
566  } else {
567  // rewind before the line
568  file.seekg(pos, file.beg);
569  headerIsDecoded = true;
570  }
571  } while (!headerIsDecoded);
572 
573  if (header != NULL) {
574 #if defined(__MINGW32__) || \
575  !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) // UNIX
576  sprintf(header, "%s", h.c_str());
577 #else
578  _snprintf_s(header, h.size() + 1, _TRUNCATE, "%s", h.c_str());
579 #endif
580  }
581 
582  unsigned int rows, cols;
583  file >> rows;
584  file >> cols;
585 
586  if (rows >= (std::numeric_limits<unsigned int>::max)() || cols >= (std::numeric_limits<unsigned int>::max)()) {
587  throw vpException(vpException::badValue, "Array exceed the max size.");
588  }
589 
590  A.resize(rows, cols);
591 
592  Type value;
593  for (unsigned int i = 0; i < rows; i++) {
594  for (unsigned int j = 0; j < cols; j++) {
595  file >> value;
596  A[i][j] = value;
597  }
598  }
599  } else {
600  char c = '0';
601  std::string h;
602  // Decode header until '\0' char that ends the header string
603  while (c != '\0') {
604  file.read(&c, 1);
605  h += c;
606  }
607  if (header != NULL) {
608 #if defined(__MINGW32__) || \
609  !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) // UNIX
610  sprintf(header, "%s", h.c_str());
611 #else
612  _snprintf_s(header, h.size() + 1, _TRUNCATE, "%s", h.c_str());
613 #endif
614  }
615 
616  unsigned int rows, cols;
617  file.read((char *)&rows, sizeof(unsigned int));
618  file.read((char *)&cols, sizeof(unsigned int));
619  A.resize(rows, cols);
620 
621  Type value;
622  for (unsigned int i = 0; i < rows; i++) {
623  for (unsigned int j = 0; j < cols; j++) {
624  file.read((char *)&value, sizeof(Type));
625  A[i][j] = value;
626  }
627  }
628  }
629 
630  file.close();
631  return true;
632  }
645  static bool loadYAML(const std::string &filename, vpArray2D<Type> &A, char *header = NULL)
646  {
647  std::fstream file;
648 
649  file.open(filename.c_str(), std::fstream::in);
650 
651  if (!file) {
652  file.close();
653  return false;
654  }
655 
656  unsigned int rows = 0, cols = 0;
657  std::string h;
658  std::string line, subs;
659  bool inheader = true;
660  unsigned int i = 0, j;
661  unsigned int lineStart = 0;
662 
663  while (getline(file, line)) {
664  if (inheader) {
665  if (rows == 0 && line.compare(0, 5, "rows:") == 0) {
666  std::stringstream ss(line);
667  ss >> subs;
668  ss >> rows;
669  } else if (cols == 0 && line.compare(0, 5, "cols:") == 0) {
670  std::stringstream ss(line);
671  ss >> subs;
672  ss >> cols;
673  } else if (line.compare(0, 5, "data:") == 0) {
674  inheader = false;
675  }
676  else {
677  h += line + "\n";
678  }
679  } else {
680  // if i == 0, we just got out of the header: initialize matrix
681  // dimensions
682  if (i == 0) {
683  if (rows == 0 || cols == 0) {
684  file.close();
685  return false;
686  }
687  A.resize(rows, cols);
688  // get indentation level which is common to all lines
689  lineStart = (unsigned int)line.find("[") + 1;
690  }
691  std::stringstream ss(line.substr(lineStart, line.find("]") - lineStart));
692  j = 0;
693  while (getline(ss, subs, ',')) {
694  A[i][j++] = atof(subs.c_str());
695  }
696  i++;
697  }
698  }
699 
700  if (header != NULL) {
701  std::string h_ = h.substr(0, h.size() - 1); // Remove last '\n' char
702 #if defined(__MINGW32__) || \
703  !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) // UNIX
704  sprintf(header, "%s", h_.c_str());
705 #else
706  _snprintf_s(header, h_.size() + 1, _TRUNCATE, "%s", h_.c_str());
707 #endif
708  }
709 
710  file.close();
711  return true;
712  }
713 
730  static bool save(const std::string &filename, const vpArray2D<Type> &A, const bool binary = false,
731  const char *header = "")
732  {
733  std::fstream file;
734 
735  if (!binary) {
736  file.open(filename.c_str(), std::fstream::out);
737  }
738  else {
739  file.open(filename.c_str(), std::fstream::out | std::fstream::binary);
740  }
741 
742  if (!file) {
743  file.close();
744  return false;
745  }
746 
747  if (!binary) {
748  unsigned int i = 0;
749  file << "# ";
750  while (header[i] != '\0') {
751  file << header[i];
752  if (header[i] == '\n') {
753  file << "# ";
754  }
755  i++;
756  }
757  file << std::endl;
758  file << A.getRows() << "\t" << A.getCols() << std::endl;
759  file << A << std::endl;
760  } else {
761  int headerSize = 0;
762  while (header[headerSize] != '\0') {
763  headerSize++;
764  }
765  file.write(header, (size_t)headerSize + (size_t)1);
766  unsigned int matrixSize;
767  matrixSize = A.getRows();
768  file.write((char *)&matrixSize, sizeof(unsigned int));
769  matrixSize = A.getCols();
770  file.write((char *)&matrixSize, sizeof(unsigned int));
771  Type value;
772  for (unsigned int i = 0; i < A.getRows(); i++) {
773  for (unsigned int j = 0; j < A.getCols(); j++) {
774  value = A[i][j];
775  file.write((char *)&value, sizeof(Type));
776  }
777  }
778  }
779 
780  file.close();
781  return true;
782  }
823  static bool saveYAML(const std::string &filename, const vpArray2D<Type> &A, const char *header = "")
824  {
825  std::fstream file;
826 
827  file.open(filename.c_str(), std::fstream::out);
828 
829  if (!file) {
830  file.close();
831  return false;
832  }
833 
834  unsigned int i = 0;
835  bool inIndent = false;
836  std::string indent = "";
837  bool checkIndent = true;
838  while (header[i] != '\0') {
839  file << header[i];
840  if (checkIndent) {
841  if (inIndent) {
842  if (header[i] == ' ') {
843  indent += " ";
844  }
845  else if (indent.length() > 0) {
846  checkIndent = false;
847  }
848  }
849  if (header[i] == '\n' || (inIndent && header[i] == ' ')) {
850  inIndent = true;
851  }
852  else {
853  inIndent = false;
854  }
855  }
856  i++;
857  }
858 
859  if (i != 0) {
860  file << std::endl;
861  }
862  file << "rows: " << A.getRows() << std::endl;
863  file << "cols: " << A.getCols() << std::endl;
864 
865  if (indent.length() == 0) {
866  indent = " ";
867  }
868 
869  file << "data: " << std::endl;
870  unsigned int j;
871  for (i = 0; i < A.getRows(); ++i) {
872  file << indent << "- [";
873  for (j = 0; j < A.getCols() - 1; ++j) {
874  file << A[i][j] << ", ";
875  }
876  file << A[i][j] << "]" << std::endl;
877  }
878 
879  file.close();
880  return true;
881  }
883 };
884 
888 template <class Type> Type vpArray2D<Type>::getMinValue() const
889 {
890  Type *dataptr = data;
891  Type min = *dataptr;
892  dataptr++;
893  for (unsigned int i = 0; i < dsize - 1; i++) {
894  if (*dataptr < min) {
895  min = *dataptr;
896  }
897  dataptr++;
898  }
899  return min;
900 }
901 
905 template <class Type> Type vpArray2D<Type>::getMaxValue() const
906 {
907  Type *dataptr = data;
908  Type max = *dataptr;
909  dataptr++;
910  for (unsigned int i = 0; i < dsize - 1; i++) {
911  if (*dataptr > max) {
912  max = *dataptr;
913  }
914  dataptr++;
915  }
916  return max;
917 }
918 
925 template <class Type> vpArray2D<Type> vpArray2D<Type>::hadamard(const vpArray2D<Type> &m) const
926 {
927  if (m.getRows() != rowNum || m.getCols() != colNum) {
928  throw(vpException(vpException::dimensionError, "Hadamard product: bad dimensions!"));
929  }
930 
931  vpArray2D<Type> out;
932  out.resize(rowNum, colNum, false);
933 
934  for (unsigned int i = 0; i < dsize; i++) {
935  out.data[i] = data[i] * m.data[i];
936  }
937 
938  return out;
939 }
940 
941 #endif
Used to indicate that a value is not in the allowed range.
Definition: vpException.h:97
static bool save(const std::string &filename, const vpArray2D< Type > &A, const bool binary=false, const char *header="")
Definition: vpArray2D.h:730
static bool saveYAML(const std::string &filename, const vpArray2D< Type > &A, const char *header="")
Definition: vpArray2D.h:823
vpArray2D< Type > & operator=(Type x)
Set all the elements of the array to x.
Definition: vpArray2D.h:406
static bool loadYAML(const std::string &filename, vpArray2D< Type > &A, char *header=NULL)
Definition: vpArray2D.h:645
void resize(const unsigned int nrows, const unsigned int ncols, const bool flagNullify=true, const bool recopy_=true)
Definition: vpArray2D.h:305
error that can be emited by ViSP classes.
Definition: vpException.h:71
Type * data
Address of the first element of the data array.
Definition: vpArray2D.h:145
Implementation of a generic 2D array used as base class for matrices and vectors. ...
Definition: vpArray2D.h:131
unsigned int size() const
Return the number of elements of the 2D array.
Definition: vpArray2D.h:291
unsigned int getCols() const
Definition: vpArray2D.h:279
vpArray2D< Type > & operator=(vpArray2D< Type > &&other)
Definition: vpArray2D.h:425
unsigned int rowNum
Number of rows in the array.
Definition: vpArray2D.h:135
vpArray2D< Type > & operator=(const vpArray2D< Type > &A)
Definition: vpArray2D.h:415
static bool load(const std::string &filename, vpArray2D< Type > &A, const bool binary=false, char *header=NULL)
Definition: vpArray2D.h:533
Memory allocation error.
Definition: vpException.h:88
vpArray2D< Type > & operator=(const std::initializer_list< Type > &list)
Definition: vpArray2D.h:447
unsigned int getRows() const
Definition: vpArray2D.h:289
unsigned int colNum
Number of columns in the array.
Definition: vpArray2D.h:137
vpArray2D< Type > hadamard(const vpArray2D< Type > &m) const
Definition: vpArray2D.h:925
Type * operator[](unsigned int i)
Set element using A[i][j] = x.
Definition: vpArray2D.h:477
Type * operator[](unsigned int i) const
Get element using x = A[i][j].
Definition: vpArray2D.h:479
unsigned int dsize
Current array size (rowNum * colNum)
Definition: vpArray2D.h:141
Type getMaxValue() const
Definition: vpArray2D.h:905
Type getMinValue() const
Definition: vpArray2D.h:888
void reshape(unsigned int nrows, unsigned int ncols)
Definition: vpArray2D.h:381
Type ** rowPtrs
Address of the first element of each rows.
Definition: vpArray2D.h:139
vpArray2D< Type > & operator=(const std::initializer_list< std::initializer_list< Type > > &lists)
Definition: vpArray2D.h:457