ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
FeaturesInterface.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 "FeaturesInterface.h"
9 
10 // qCC_db
11 #include <QtCompat.h>
12 #include <ecvScalarField.h>
13 
14 // system
15 #include <assert.h>
16 
17 using namespace masc;
18 
19 bool Feature::CheckSFExistence(ccPointCloud* cloud, const char* resultSFName) {
20  if (!cloud || !resultSFName) {
21  assert(false);
22  return false;
23  }
24 
25  int sfIdx = cloud->getScalarFieldIndexByName(resultSFName);
26  return (sfIdx >= 0);
27 }
28 
30  ccPointCloud* cloud,
31  const char* resultSFName,
32  SFCollector* generatedScalarFields /*=nullptr*/,
33  SFCollector::Behavior behavior /*=SFCollector::CAN_REMOVE*/) {
34  if (!cloud || !resultSFName) {
35  // invalid input parameters
36  assert(false);
37  return nullptr;
38  }
39 
40  cloudViewer::ScalarField* resultSF = nullptr;
41  int sfIdx = cloud->getScalarFieldIndexByName(resultSFName);
42  if (sfIdx >= 0) {
43  // CVLog::Warning("Existing SF: " + QString(resultSFName) + ", do not
44  // store in generatedScalarFields");
45  resultSF = cloud->getScalarField(sfIdx);
46  } else {
47  // CVLog::Warning("SF does not exist, create it: " +
48  // QString(resultSFName) + ", SFCollector::Behavior " +
49  // QString::number(behavior));
50  ccScalarField* newSF = new ccScalarField(resultSFName);
51  if (!newSF->resizeSafe(cloud->size())) {
52  CVLog::Warning("Not enough memory");
53  newSF->release();
54  return nullptr;
55  }
56  cloud->addScalarField(newSF);
57 
58  if (generatedScalarFields) {
59  // track the generated scalar-field
60  generatedScalarFields->push(cloud, newSF, behavior);
61  }
62 
63  resultSF = newSF;
64  resultSF->fill(NAN_VALUE);
65  }
66 
67  assert(resultSF);
68 
69  return resultSF;
70 }
71 
72 ScalarType Feature::PerformMathOp(double s1, double s2, Operation op) {
73  ScalarType s = NAN_VALUE;
74  switch (op) {
75  case Feature::MINUS:
76  s = static_cast<ScalarType>(s1 - s2);
77  break;
78  case Feature::PLUS:
79  s = static_cast<ScalarType>(s1 + s2);
80  break;
81  case Feature::DIVIDE:
82  if (std::abs(s2) > std::numeric_limits<ScalarType>::epsilon())
83  s = static_cast<ScalarType>(s1 / s2);
84  break;
85  case Feature::MULTIPLY:
86  s = static_cast<ScalarType>(s1 * s2);
87  break;
88  default:
89  assert(false);
90  break;
91  }
92  return s;
93 }
94 
96  const cloudViewer::ScalarField* sf2,
97  Feature::Operation op) {
98  if (!sf1 || !sf2 || sf1->size() != sf2->size() ||
100  // invalid input parameters
101  assert(false);
102  return false;
103  }
104 
105  for (unsigned i = 0; i < sf1->size(); ++i) {
106  ScalarType s1 = sf1->getValue(i);
107  ScalarType s2 = sf2->getValue(i);
108  ScalarType s = PerformMathOp(s1, s2, op);
109  sf1->setValue(i, s);
110  }
111  sf1->computeMinAndMax();
112 
113  return true;
114 }
115 
117  const IScalarFieldWrapper& sf2,
118  Operation op,
119  cloudViewer::ScalarField* outSF) {
120  if (!outSF || sf1.size() != sf2.size() || sf1.size() != outSF->size() ||
122  // invalid input parameters
123  assert(false);
124  return false;
125  }
126 
127  for (unsigned i = 0; i < sf1.size(); ++i) {
128  double s1 = sf1.pointValue(i);
129  double s2 = sf2.pointValue(i);
130  ScalarType s = PerformMathOp(s1, s2, op);
131  outSF->setValue(i, s);
132  }
133  outSF->computeMinAndMax();
134 
135  return true;
136 }
137 
138 bool Feature::SaveSources(const Source::Set& sources, QString filename) {
139  QFile file(filename);
140  if (!file.open(QFile::WriteOnly | QFile::Text)) {
141  CVLog::Warning("Failed to open file for writing: " + filename);
142  return false;
143  }
144 
145  QTextStream stream(&file);
146  stream << "#Features_SF" << QtCompat::endl;
147  for (const Source& s : sources) {
148  stream << s.type << ":" << s.name << QtCompat::endl;
149  }
150 
151  return true;
152 }
153 
154 bool Feature::LoadSources(Source::Set& sources, QString filename) {
155  QFile file(filename);
156  if (!file.open(QFile::ReadOnly | QFile::Text)) {
157  CVLog::Warning("Failed to open file for reading: " + filename);
158  return false;
159  }
160 
161  QTextStream stream(&file);
162  QString header = stream.readLine();
163  if (!header.startsWith("#Features_SF")) {
164  CVLog::Warning("Unexpected header");
165  return false;
166  }
167 
168  while (true) {
169  QString line = stream.readLine();
170  if (line.isNull()) break;
171  if (line.isEmpty()) continue; // unexpected but we can survive
172  QStringList tokens = line.split(':');
173  if (tokens.size() != 2) {
174  CVLog::Warning("Malformed file");
175  return false;
176  }
177 
178  Source src;
179  bool ok = false;
180  int sourceType = tokens[0].toInt(&ok);
181  if (!ok || sourceType < Feature::Source::ScalarField ||
182  sourceType > Feature::Source::Blue) {
183  CVLog::Warning("Unhandled source type");
184  return false;
185  }
186  src.type = static_cast<Feature::Source::Type>(sourceType);
187  src.name = tokens[1];
188 
189  sources.push_back(src);
190  }
191 
192  return true;
193 }
194 
195 bool Feature::ExtractSources(const Set& features, Source::Set& sources) {
196  sources.clear();
197  try {
198  sources.reserve(features.size());
199  } catch (const std::bad_alloc&) {
200  CVLog::Warning("Not enough memory");
201  return false;
202  }
203 
204  for (Feature::Shared f : features) {
205  sources.push_back(f->source);
206  }
207 
208  return true;
209 }
constexpr ScalarType NAN_VALUE
NaN as a ScalarType value.
Definition: CVConst.h:76
std::string filename
virtual void release()
Decrease counter and deletes object when 0.
Definition: CVShareable.cpp:35
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
Definition: CVLog.cpp:133
virtual size_t size() const =0
virtual double pointValue(unsigned index) const =0
SF collector.
void push(ccPointCloud *cloud, cloudViewer::ScalarField *sf, Behavior behavior)
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
int addScalarField(const char *uniqueName) override
Creates a new scalar field and registers it.
A scalar field associated to display-related parameters.
int getScalarFieldIndexByName(const char *name) const
Returns the index of a scalar field represented by its name.
ScalarField * getScalarField(int index) const
Returns a pointer to a specific scalar field.
unsigned size() const override
Definition: PointCloudTpl.h:38
A simple scalar field (to be associated to a point cloud)
Definition: ScalarField.h:25
void fill(ScalarType fillValue=0)
Fills the array with a particular value.
Definition: ScalarField.h:77
virtual void computeMinAndMax()
Determines the min and max values.
Definition: ScalarField.h:123
ScalarType & getValue(std::size_t index)
Definition: ScalarField.h:92
void setValue(std::size_t index, ScalarType value)
Definition: ScalarField.h:96
bool resizeSafe(std::size_t count, bool initNewElements=false, ScalarType valueForNewElements=0)
Resizes memory (no exception thrown)
Definition: ScalarField.cpp:81
__host__ __device__ int2 abs(int2 v)
Definition: cutil_math.h:1267
QTextStream & endl(QTextStream &stream)
Definition: QtCompat.h:718
3DMASC classifier
Sources of values for this feature.
std::vector< Source > Set
static bool CheckSFExistence(ccPointCloud *cloud, const char *resultSFName)
static bool ExtractSources(const Set &features, Source::Set &sources)
Extracts the set of 'sources' from a set of features.
static bool SaveSources(const Source::Set &sources, QString filename)
Saves a set of 'sources' to a file.
std::vector< Shared > Set
Set of features.
static bool LoadSources(Source::Set &sources, QString filename)
Loads a set of 'sources' from a file.
QSharedPointer< Feature > Shared
Shared type.
static ScalarType PerformMathOp(double s1, double s2, Operation op)
Performs a mathematical operation between two scalars.
static cloudViewer::ScalarField * PrepareSF(ccPointCloud *cloud, const char *resultSFName, SFCollector *generatedScalarFields, SFCollector::Behavior behavior)