ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
PVFilter.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #include "PVFilter.h"
9 
10 // CV_CORE_LIB
11 #include <CVLog.h>
12 
13 // CV_DB_LIB
14 #include <ecvHObjectCaster.h>
15 #include <ecvPointCloud.h>
16 #include <ecvProgressDialog.h>
17 #include <ecvScalarField.h>
18 
19 // Qt
20 #include <QFile>
21 
23  : FileIOFilter(
24  {"_Point+Value Filter",
25  DEFAULT_PRIORITY, // priority
26  QStringList{"pv"}, "pv", QStringList{"Point+Value cloud (*.pv)"},
27  QStringList{"Point+Value cloud (*.pv)"}, Import | Export}) {}
28 
30  bool& multiple,
31  bool& exclusive) const {
32  if (type == CV_TYPES::POINT_CLOUD) {
33  multiple = false;
34  exclusive = true;
35  return true;
36  }
37  return false;
38 }
39 
41  const QString& filename,
42  const SaveParameters& parameters) {
43  if (!entity || filename.isEmpty()) return CC_FERR_BAD_ARGUMENT;
44 
45  // the cloud to save
46  ccGenericPointCloud* theCloud =
48  if (!theCloud) {
49  CVLog::Warning("[PV] This filter can only save one cloud at a time!");
51  }
52  unsigned numberOfPoints = theCloud->size();
53 
54  if (numberOfPoints == 0) {
55  CVLog::Warning("[PV] Input cloud is empty!");
56  return CC_FERR_NO_SAVE;
57  }
58 
59  // open binary file for writing
60  QFile out(filename);
61  if (!out.open(QIODevice::WriteOnly)) return CC_FERR_WRITING;
62 
63  // Has the cloud been recentered?
64  if (theCloud->isShifted())
65  CVLog::Warning(QString("[PVFilter::save] Can't recenter or rescale "
66  "cloud '%1' when saving it in a PN file!")
67  .arg(theCloud->getName()));
68 
69  // for point clouds with multiple SFs, we must set the currently displayed
70  // one as 'input' SF if (theCloud->isA(CV_TYPES::POINT_CLOUD))
71  //{
72  // ccPointCloud* pc = static_cast<ccPointCloud*>(theCloud);
73  // pc->setCurrentInScalarField(pc->getCurrentDisplayedScalarFieldIndex());
74  // }
75  bool hasSF = theCloud->hasDisplayedScalarField();
76  if (!hasSF)
77  CVLog::Warning(QString("[PVFilter::save] Cloud '%1' has no displayed "
78  "scalar field (we will save points with a "
79  "default scalar value)!")
80  .arg(theCloud->getName()));
81 
82  float val = std::numeric_limits<float>::quiet_NaN();
83 
84  // progress dialog
85  QScopedPointer<ecvProgressDialog> pDlg(0);
86  if (parameters.parentWidget) {
87  pDlg.reset(new ecvProgressDialog(
88  true, parameters.parentWidget)); // cancel available
89  pDlg->setMethodTitle(QObject::tr("Save PV file"));
90  pDlg->setInfo(QObject::tr("Points: %L1").arg(numberOfPoints));
91  pDlg->start();
92  }
93  cloudViewer::NormalizedProgress nprogress(pDlg.data(), numberOfPoints);
94 
96 
97  for (unsigned i = 0; i < numberOfPoints; i++) {
98  // write point
99  {
100  const CCVector3* P = theCloud->getPoint(i);
101 
102  // conversion to float
103  float wBuff[3] = {(float)P->x, (float)P->y, (float)P->z};
104  if (out.write((const char*)wBuff, 3 * sizeof(float)) < 0) {
106  break;
107  }
108  }
109 
110  // write scalar value
111  if (hasSF) val = static_cast<float>(theCloud->getPointScalarValue(i));
112  if (out.write((const char*)&val, sizeof(float)) < 0) {
114  break;
115  }
116 
117  if (pDlg && !nprogress.oneStep()) {
119  break;
120  }
121  }
122 
123  out.close();
124 
125  return result;
126 }
127 
129  ccHObject& container,
130  LoadParameters& parameters) {
131  // opening file
132  QFile in(filename);
133  if (!in.open(QIODevice::ReadOnly)) return CC_FERR_READING;
134 
135  // we deduce the points number from the file size
136  qint64 fileSize = in.size();
137  qint64 singlePointSize = 4 * sizeof(float);
138  // check that size is ok
139  if (fileSize == 0) return CC_FERR_NO_LOAD;
140  if ((fileSize % singlePointSize) != 0) return CC_FERR_MALFORMED_FILE;
141  unsigned numberOfPoints = static_cast<unsigned>(fileSize / singlePointSize);
142 
143  // progress dialog
144  QScopedPointer<ecvProgressDialog> pDlg(0);
145  if (parameters.parentWidget) {
146  pDlg.reset(new ecvProgressDialog(
147  true, parameters.parentWidget)); // cancel available
148  pDlg->setMethodTitle(QObject::tr("Open PV file"));
149  pDlg->setInfo(QObject::tr("Points: %L1").arg(numberOfPoints));
150  pDlg->start();
151  }
152  cloudViewer::NormalizedProgress nprogress(pDlg.data(), numberOfPoints);
153 
154  ccPointCloud* loadedCloud = 0;
155  // if the file is too big, it will be chuncked in multiple parts
156  unsigned chunkIndex = 0;
157  unsigned fileChunkPos = 0;
158  unsigned fileChunkSize = 0;
159  // number of points read for the current cloud part
160  unsigned pointsRead = 0;
162 
163  for (unsigned i = 0; i < numberOfPoints; i++) {
164  // if we reach the max. cloud size limit, we cerate a new chunk
165  if (pointsRead == fileChunkPos + fileChunkSize) {
166  if (loadedCloud) {
167  int sfIdx = loadedCloud->getCurrentInScalarFieldIndex();
168  if (sfIdx >= 0) {
170  loadedCloud->getScalarField(sfIdx);
171  sf->computeMinAndMax();
172  loadedCloud->setCurrentDisplayedScalarField(sfIdx);
173  loadedCloud->showSF(true);
174  }
175  container.addChild(loadedCloud);
176  }
177  fileChunkPos = pointsRead;
178  fileChunkSize =
179  std::min<unsigned>(numberOfPoints - pointsRead,
181  loadedCloud = new ccPointCloud(
182  QString("unnamed - Cloud #%1").arg(++chunkIndex));
183  if (!loadedCloud ||
184  !loadedCloud->reserveThePointsTable(fileChunkSize) ||
185  !loadedCloud->enableScalarField()) {
187  if (loadedCloud) delete loadedCloud;
188  loadedCloud = 0;
189  break;
190  }
191  }
192 
193  // we read the 3 coordinates of the point
194  float rBuff[3];
195  if (in.read((char*)rBuff, 3 * sizeof(float)) >= 0) {
196  // conversion to CCVector3
197  CCVector3 P((PointCoordinateType)rBuff[0],
198  (PointCoordinateType)rBuff[1],
199  (PointCoordinateType)rBuff[2]);
200  loadedCloud->addPoint(P);
201  } else {
203  break;
204  }
205 
206  // then the scalar value
207  if (in.read((char*)rBuff, sizeof(float)) >= 0) {
208  loadedCloud->setPointScalarValue(pointsRead, (ScalarType)rBuff[0]);
209  } else {
210  // add fake scalar value for consistency then break
211  loadedCloud->setPointScalarValue(pointsRead, 0);
213  break;
214  }
215 
216  ++pointsRead;
217 
218  if (pDlg && !nprogress.oneStep()) {
220  break;
221  }
222  }
223 
224  in.close();
225 
226  if (loadedCloud) {
227  loadedCloud->shrinkToFit();
228  int sfIdx = loadedCloud->getCurrentInScalarFieldIndex();
229  if (sfIdx >= 0) {
230  cloudViewer::ScalarField* sf = loadedCloud->getScalarField(sfIdx);
231  sf->computeMinAndMax();
232  loadedCloud->setCurrentDisplayedScalarField(sfIdx);
233  loadedCloud->showSF(true);
234  }
235  container.addChild(loadedCloud);
236  }
237 
238  return result;
239 }
float PointCoordinateType
Type of the coordinates of a (N-D) point.
Definition: CVTypes.h:16
int64_t CV_CLASS_ENUM
Type of object type flags (64 bits)
Definition: CVTypes.h:97
std::string filename
char type
CC_FILE_ERROR
Typical I/O filter errors.
Definition: FileIOFilter.h:20
@ CC_FERR_CANCELED_BY_USER
Definition: FileIOFilter.h:30
@ CC_FERR_NO_LOAD
Definition: FileIOFilter.h:28
@ CC_FERR_WRITING
Definition: FileIOFilter.h:25
@ CC_FERR_MALFORMED_FILE
Definition: FileIOFilter.h:32
@ CC_FERR_BAD_ARGUMENT
Definition: FileIOFilter.h:22
@ CC_FERR_NO_SAVE
Definition: FileIOFilter.h:27
@ CC_FERR_NO_ERROR
Definition: FileIOFilter.h:21
@ CC_FERR_BAD_ENTITY_TYPE
Definition: FileIOFilter.h:29
@ CC_FERR_READING
Definition: FileIOFilter.h:26
@ CC_FERR_NOT_ENOUGH_MEMORY
Definition: FileIOFilter.h:31
core::Tensor result
Definition: VtkUtils.cpp:76
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
Definition: CVLog.cpp:133
Generic file I/O filter.
Definition: FileIOFilter.h:46
static constexpr float DEFAULT_PRIORITY
Definition: FileIOFilter.h:313
virtual bool canSave(CV_CLASS_ENUM type, bool &multiple, bool &exclusive) const override
Returns whether this I/O filter can save the specified type of entity.
Definition: PVFilter.cpp:29
virtual CC_FILE_ERROR saveToFile(ccHObject *entity, const QString &filename, const SaveParameters &parameters) override
Saves an entity (or a group of) to a file.
Definition: PVFilter.cpp:40
PVFilter()
Definition: PVFilter.cpp:22
virtual CC_FILE_ERROR loadFile(const QString &filename, ccHObject &container, LoadParameters &parameters) override
Loads one or more entities from a file.
Definition: PVFilter.cpp:128
Type y
Definition: CVGeom.h:137
Type x
Definition: CVGeom.h:137
Type z
Definition: CVGeom.h:137
virtual bool hasDisplayedScalarField() const
Returns whether an active scalar field is available or not.
virtual void showSF(bool state)
Sets active scalarfield visibility.
A 3D cloud interface with associated features (color, normals, octree, etc.)
static ccGenericPointCloud * ToGenericPointCloud(ccHObject *obj, bool *isLockedVertices=nullptr)
Converts current object to 'equivalent' ccGenericPointCloud.
Hierarchical CLOUDVIEWER Object.
Definition: ecvHObject.h:25
virtual bool addChild(ccHObject *child, int dependencyFlags=DP_PARENT_OF_OTHER, int insertIndex=-1)
Adds a child.
virtual QString getName() const
Returns object name.
Definition: ecvObject.h:72
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
void setCurrentDisplayedScalarField(int index)
Sets the currently displayed scalar field.
void shrinkToFit()
Removes unused capacity.
bool reserveThePointsTable(unsigned _numberOfPoints)
Reserves memory to store the points coordinates.
bool isShifted() const
Returns whether the cloud is shifted or not.
virtual unsigned size() const =0
Returns the number of points.
virtual ScalarType getPointScalarValue(unsigned pointIndex) const =0
Returns the ith point associated scalar value.
virtual const CCVector3 * getPoint(unsigned index) const =0
Returns the ith point.
bool oneStep()
Increments total progress value of a single unit.
int getCurrentInScalarFieldIndex()
Returns current INPUT scalar field index (or -1 if none)
ScalarField * getScalarField(int index) const
Returns a pointer to a specific scalar field.
void setPointScalarValue(unsigned pointIndex, ScalarType value) override
void addPoint(const CCVector3 &P)
Adds a 3D point to the database.
bool enableScalarField() override
Definition: PointCloudTpl.h:77
A simple scalar field (to be associated to a point cloud)
Definition: ScalarField.h:25
virtual void computeMinAndMax()
Determines the min and max values.
Definition: ScalarField.h:123
Graphical progress indicator (thread-safe)
const unsigned CC_MAX_NUMBER_OF_POINTS_PER_CLOUD
@ POINT_CLOUD
Definition: CVTypes.h:104
#define fileChunkSize(nChunkSize)
Definition: sqlite3.c:96908
Generic loading parameters.
Definition: FileIOFilter.h:51
QWidget * parentWidget
Parent widget (if any)
Definition: FileIOFilter.h:78
Generic saving parameters.
Definition: FileIOFilter.h:84
QWidget * parentWidget
Parent widget (if any)
Definition: FileIOFilter.h:93