27 (
static_cast<quint16
>(42) |
static_cast<quint16
>(42 << 8));
32 QStringList{
"sbf",
"data"},
"sbf",
33 QStringList{
"Simple binary file (*.sbf)"},
34 QStringList{
"Simple binary file (*.sbf)"},
39 bool& exclusive)
const {
59 QString dataFilename =
filename +
".data";
61 CVLog::Print(QString(
"[SBF] Saving file '%1'...").arg(headerFilename));
65 QSettings headerFile(headerFilename, QSettings::IniFormat);
67 headerFile.beginGroup(
"SBF");
68 headerFile.setValue(
"Points", cloud->
size());
72 if (globalShift.
norm2() != 0) {
73 QStringList strGlobalShift;
74 strGlobalShift << QString::number(globalShift.
x,
'f', 6);
75 strGlobalShift << QString::number(globalShift.
y,
'f', 6);
76 strGlobalShift << QString::number(globalShift.
z,
'f', 6);
77 headerFile.setValue(
"GlobalShift", strGlobalShift);
81 if (globalScale != 1.0) {
82 headerFile.setValue(
"GlobalScale", globalScale);
88 headerFile.setValue(
"SFCount", sfCount);
91 for (
int i = 0; i < static_cast<int>(sfCount); ++i) {
92 QString key = QString(
"SF%1").arg(i + 1);
108 QString precisionKey = QString(
"{%1}.precision").arg(sfName);
114 tokens <<
"p=" + QString::number(precision,
'f', 12);
118 headerFile.setValue(key, tokens);
122 headerFile.endGroup();
127 QFile dataFile(dataFilename);
128 if (!dataFile.open(QFile::WriteOnly)) {
133 QDataStream dataStream(&dataFile);
141 size_t writtenBytes = 0;
142 dataStream.setFloatingPointPrecision(
143 QDataStream::DoublePrecision);
152 quint64 pointCount = cloud->
size();
153 dataStream << pointCount;
161 dataStream << sfCount;
167 dataStream << coordinatesShift.
x;
168 dataStream << coordinatesShift.
y;
169 dataStream << coordinatesShift.
z;
181 unsigned pointCount = cloud->
size();
183 QScopedPointer<ecvProgressDialog> pDlg(
nullptr);
186 pDlg->setMethodTitle(QObject::tr(
"Simple BIN file"));
187 pDlg->setInfo(QObject::tr(
"Saving %1 points / %2 scalar field(s)")
190 pDlg->setModal(
true);
197 dataStream.setFloatingPointPrecision(
198 QDataStream::SinglePrecision);
200 for (
unsigned i = 0; i < pointCount; ++i) {
204 dataStream << coords.
x;
205 dataStream << coords.
y;
206 dataStream << coords.
z;
209 for (
unsigned j = 0; j < sfCount; ++j) {
211 float fVal =
static_cast<float>(val);
226 double precision = std::numeric_limits<double>::quiet_NaN();
235 std::vector<SFDescriptor>
SFs;
250 QString headerFilename;
251 QString dataFilename;
261 CVLog::Print(QString(
"[SBF] Loading file '%1'...").arg(headerFilename));
265 if (QFileInfo::exists(headerFilename)) {
266 QSettings headerFile(headerFilename, QSettings::IniFormat);
268 if (!headerFile.childGroups().contains(
"SBF")) {
272 headerFile.beginGroup(
"SBF");
274 if (headerFile.contains(
"Points")) {
277 descriptor.
pointCount = headerFile.value(
"Points").toLongLong(&ok);
285 if (headerFile.contains(
"GlobalShift")) {
286 QStringList strGlobalShift =
287 headerFile.value(
"GlobalShift").toStringList();
288 if (strGlobalShift.size() != 3) {
292 bool ok[3] = {
false,
false,
false};
293 descriptor.
globalShift.
x = strGlobalShift[0].toDouble(ok);
294 descriptor.
globalShift.
y = strGlobalShift[1].toDouble(ok + 1);
295 descriptor.
globalShift.
z = strGlobalShift[2].toDouble(ok + 2);
296 if (!ok[0] || !ok[1] || !ok[2]) {
304 if (headerFile.contains(
"GlobalScale")) {
307 headerFile.value(
"GlobalScale").toDouble(&ok);
315 if (headerFile.contains(
"SFCount")) {
317 int sfCount = headerFile.value(
"SFCount").toInt(&ok);
318 if (!ok || sfCount < 0) {
324 descriptor.
SFs.resize(
static_cast<size_t>(sfCount));
325 }
catch (
const std::bad_alloc&) {
331 for (
int i = 0; i < sfCount; ++i) {
332 QString key = QString(
"SF%1").arg(i + 1);
333 QStringList tokens = headerFile.value(key).toStringList();
334 if (!tokens.empty()) {
335 descriptor.
SFs[i].name = tokens[0];
336 for (
int k = 1; k < tokens.size(); ++k) {
337 QString token = tokens[k];
338 if (token.startsWith(
"s=")) {
339 token = token.mid(2);
340 double shift = token.toDouble(&ok);
343 "description (shift)")
347 descriptor.
SFs[i].shift = shift;
349 if (token.startsWith(
"p=")) token = token.mid(2);
350 descriptor.
SFs[i].precision = token.toDouble(&ok);
353 "description (precision)")
362 headerFile.endGroup();
369 QFile dataFile(dataFilename);
370 if (!dataFile.open(QFile::ReadOnly)) {
379 QDataStream dataStream(&dataFile);
383 size_t readBytes = 0;
384 dataStream.setFloatingPointPrecision(
385 QDataStream::DoublePrecision);
390 quint16 headerFlag = 0;
391 dataStream >> headerFlag;
400 quint64 pointCount = 0;
401 dataStream >> pointCount;
405 "[SBF] Inconsistent number of points between the "
406 "header and the data file!");
409 descriptor.
pointCount =
static_cast<size_t>(pointCount);
416 dataStream >> sfCount;
418 if (sfCount != descriptor.
SFs.size()) {
420 "[SBF] Inconsistent number of scalar fields between "
421 "the header and the data file!");
425 descriptor.
SFs.resize(sfCount);
426 }
catch (
const std::bad_alloc&) {
435 dataStream >> coordinatesShift.
x;
436 dataStream >> coordinatesShift.
y;
437 dataStream >> coordinatesShift.
z;
449 size_t sizePerPoint = (3 + descriptor.
SFs.size()) *
453 if (totalSize != dataFile.size()) {
458 QScopedPointer<ccPointCloud> cloud(
new ccPointCloud(
"unnamed"));
459 if (!cloud->reserve(
static_cast<unsigned>(descriptor.
pointCount))) {
463 QScopedPointer<ecvProgressDialog> pDlg(
nullptr);
466 pDlg->setMethodTitle(QObject::tr(
"Simple BIN file"));
467 pDlg->setInfo(QObject::tr(
"Loading %1 points / %2 scalar field(s)")
469 .arg(descriptor.
SFs.size()));
470 pDlg->setModal(
true);
474 pDlg.data(),
static_cast<unsigned>(descriptor.
pointCount));
477 for (
size_t i = 0; i < descriptor.
SFs.size(); ++i) {
479 if (sfDesc.
name.isEmpty()) {
480 sfDesc.
name = QString(
"Scalar field #%1").arg(i + 1);
484 static_cast<unsigned>(descriptor.
pointCount))) {
490 if (sfDesc.
shift != 0) {
494 cloud->addScalarField(sfDesc.
sf);
498 cloud->setMetaData(QString(
"{%1}.precision").arg(sfDesc.
name),
504 dataStream.setFloatingPointPrecision(
505 QDataStream::SinglePrecision);
507 for (
size_t i = 0; i < descriptor.
pointCount; ++i) {
520 bool useGlobalShift =
false;
531 useGlobalShift =
true;
541 bool preserveCoordinateShift =
true;
546 if (preserveCoordinateShift) {
550 "[SBF] Cloud has been recentered! Translation: (%.2f ; "
577 if (cloud->size() == 0) {
579 }
else if (cloud->size() < descriptor.
pointCount) {
580 cloud->shrinkToFit();
584 if (!descriptor.
SFs.empty()) {
585 for (
auto& SF : descriptor.
SFs) {
586 SF.sf->computeMinAndMax();
588 cloud->setCurrentDisplayedScalarField(0);
int64_t CV_CLASS_ENUM
Type of object type flags (64 bits)
CC_FILE_ERROR
Typical I/O filter errors.
@ CC_FERR_CANCELED_BY_USER
@ CC_FERR_NOT_ENOUGH_MEMORY
static const size_t c_headerSize
static const quint16 s_headerFlagSBF
virtual void release()
Decrease counter and deletes object when 0.
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
static bool Print(const char *format,...)
Prints out a formatted message in console.
static bool Error(const char *format,...)
Display an error dialog with formatted message.
static bool HandleGlobalShift(const CCVector3d &P, CCVector3d &Pshift, bool &preserveCoordinateShift, LoadParameters &loadParameters, bool useInputCoordinatesShiftIfPossible=false)
Shortcut to the ecvGlobalShiftManager mechanism specific for files.
virtual CC_FILE_ERROR loadFile(const QString &filename, ccHObject &container, LoadParameters ¶meters) override
Loads one or more entities from a file.
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.
virtual CC_FILE_ERROR saveToFile(ccHObject *entity, const QString &filename, const SaveParameters ¶meters) override
Saves an entity (or a group of) to a file.
Type norm2() const
Returns vector square norm.
static Vector3Tpl fromArray(const int a[3])
Constructor from an int array.
static ccPointCloud * ToPointCloud(ccHObject *obj, bool *isLockedVertices=nullptr)
Converts current object to 'equivalent' ccPointCloud.
Hierarchical CLOUDVIEWER Object.
virtual bool addChild(ccHObject *child, int dependencyFlags=DP_PARENT_OF_OTHER, int insertIndex=-1)
Adds a child.
bool isA(CV_CLASS_ENUM type) const
QVariant getMetaData(const QString &key) const
Returns a given associated meta data.
bool hasMetaData(const QString &key) const
Returns whether a meta-data element with the given key exists or not.
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
bool hasScalarFields() const override
Returns whether one or more scalar fields are instantiated.
A scalar field associated to display-related parameters.
void setGlobalShift(double shift)
Sets the global shift.
double getGlobalShift() const
Returns the global shift (if any)
CCVector3d toGlobal3d(const Vector3Tpl< T > &Plocal) const
Returns the point back-projected into the original coordinates system.
virtual const CCVector3d & getGlobalShift() const
Returns the shift applied to original coordinates.
virtual double getGlobalScale() const
Returns the scale applied to original coordinates.
bool oneStep()
Increments total progress value of a single unit.
ScalarField * getScalarField(int index) const
Returns a pointer to a specific scalar field.
unsigned getNumberOfScalarFields() const
Returns the number of associated (and active) scalar fields.
unsigned size() const override
const char * getScalarFieldName(int index) const
Returns the name of a specific scalar field.
const CCVector3 * getPoint(unsigned index) const override
void addElement(ScalarType value)
ScalarType & getValue(std::size_t index)
bool reserveSafe(std::size_t count)
Reserves memory (no exception thrown)
Mode
Strategy to handle coordinates shift/scale.
Graphical progress indicator (thread-safe)
constexpr QRegularExpression::PatternOption CaseInsensitive
Generic loading parameters.
ecvGlobalShiftManager::Mode shiftHandlingMode
How to handle big coordinates.
QWidget * parentWidget
Parent widget (if any)
bool * coordinatesShiftEnabled
Whether shift on load has been applied after loading (optional)
Generic saving parameters.
QWidget * parentWidget
Parent widget (if any)
std::vector< SFDescriptor > SFs