From c53eae2db1abb2677e768b7cbfcdd94e4601e8c3 Mon Sep 17 00:00:00 2001 From: Uriah Liggett Date: Mon, 20 Apr 2015 01:25:40 +0000 Subject: [PATCH] Added support for binary PLY files. Added support for specifying the ground plane height. Added support for centimeters. Improved the progress reporting --- src/CriticalSection.cpp | 2 + src/CriticalSection.h | 1 + src/HttpServer.cpp | 20 +++- src/LaserResultsMerger.cpp | 12 +- src/LaserResultsMerger.h | 4 +- src/LocationMapper.cpp | 6 +- src/LocationMapper.h | 1 + src/Main.cpp | 47 ++++++-- src/Main.h | 6 +- src/Makefile | 12 +- src/PlyWriter.cpp | 102 +++++++++++++++-- src/PlyWriter.h | 8 +- src/Preset.cpp | 16 ++- src/Preset.h | 4 + src/Progress.cpp | 73 ++++++++++++ src/{ScanResultsWriter.h => Progress.h} | 34 +++--- src/ScanResultsWriter.cpp | 141 ------------------------ src/Scanner.cpp | 108 +++++++----------- src/Scanner.h | 23 ++-- src/Setup.cpp | 8 +- src/StlWriter.cpp | 17 ++- src/StlWriter.h | 3 +- src/WebContent.cpp | 52 ++++++++- src/WebContent.h | 9 +- src/XyzWriter.cpp | 22 +++- src/XyzWriter.h | 4 +- 26 files changed, 442 insertions(+), 293 deletions(-) create mode 100644 src/Progress.cpp rename src/{ScanResultsWriter.h => Progress.h} (72%) delete mode 100644 src/ScanResultsWriter.cpp diff --git a/src/CriticalSection.cpp b/src/CriticalSection.cpp index b43334a..811aa8a 100644 --- a/src/CriticalSection.cpp +++ b/src/CriticalSection.cpp @@ -32,6 +32,7 @@ CriticalSection::CriticalSection() } } + CriticalSection::~CriticalSection() { if (pthread_mutex_destroy(&m_handle) != 0) @@ -40,6 +41,7 @@ CriticalSection::~CriticalSection() } } + void CriticalSection::enter() { if (pthread_mutex_lock(&m_handle) != 0) diff --git a/src/CriticalSection.h b/src/CriticalSection.h index 485ab21..4f6b478 100644 --- a/src/CriticalSection.h +++ b/src/CriticalSection.h @@ -29,6 +29,7 @@ class CriticalSection public: CriticalSection(); ~CriticalSection(); + void enter(); void leave(); diff --git a/src/HttpServer.cpp b/src/HttpServer.cpp index 0bcbbc5..33517c6 100644 --- a/src/HttpServer.cpp +++ b/src/HttpServer.cpp @@ -29,6 +29,7 @@ #include "Camera.h" #include "Calibrator.h" #include "UpdateManager.h" +#include "Progress.h" #define POSTBUFFERSIZE 2048 #define MAX_PIN 7 @@ -165,6 +166,10 @@ static void SavePreset(RequestInfo * reqInfo) { PresetManager * profMgr = PresetManager::get(); Preset * preset = &profMgr->getActivePreset(); + Setup * setup = Setup::get(); + + // Get the original units in case we need to convert + UnitOfLength srcUnits = setup->unitOfLength; // If the name does not exist, create a new preset std::string presetName = reqInfo->arguments[WebContent::PROFILE_NAME]; @@ -232,6 +237,13 @@ static void SavePreset(RequestInfo * reqInfo) } preset->generatePly = !reqInfo->arguments[WebContent::GENERATE_PLY].empty(); + + std::string plyDataFormat = reqInfo->arguments[WebContent::PLY_DATA_FORMAT]; + if (! plyDataFormat.empty()) + { + preset->plyDataFormat = (PlyWriter::DataFormat) ToInt(plyDataFormat); + } + preset->generateStl = !reqInfo->arguments[WebContent::GENERATE_STL].empty(); preset->generateXyz = !reqInfo->arguments[WebContent::GENERATE_XYZ].empty(); @@ -245,6 +257,12 @@ static void SavePreset(RequestInfo * reqInfo) preset->generatePly = true; } + std::string groundPlaneHeight = reqInfo->arguments[WebContent::GROUND_PLANE_HEIGHT]; + if (!groundPlaneHeight.empty()) + { + preset->groundPlaneHeight = ConvertUnitOfLength(ToReal(groundPlaneHeight), srcUnits, UL_MILLIMETERS); + } + /** Save the properties */ SaveProperties(); } @@ -409,7 +427,7 @@ static int ShowScanProgress(RequestInfo * reqInfo) // Show the scan progress page HttpServer * server = reqInfo->server; Scanner * scanner = server->getScanner(); - real progress = scanner->getProgress() * 100.0; + Progress& progress = scanner->getProgress(); real remainingTime = scanner->getRemainingTime(); std::string page = WebContent::scanRunning(progress, remainingTime); diff --git a/src/LaserResultsMerger.cpp b/src/LaserResultsMerger.cpp index 88aea8a..ac9a0bc 100644 --- a/src/LaserResultsMerger.cpp +++ b/src/LaserResultsMerger.cpp @@ -52,8 +52,12 @@ void LaserResultsMerger::merge(std::vector & out, int numFramesPerRevolution, int numFramesBetweenLaserPlanes, int maxPointY, - Preset::LaserMergeAction mergeAction) + Preset::LaserMergeAction mergeAction, + Progress& progress) { + progress.setLabel("Merging laser results"); + progress.setPercent(0); + // Sanity check if (mergeAction != Preset::LMA_PREFER_RIGHT_LASER && mergeAction != Preset::LMA_SEPARATE_BY_COLOR) { @@ -109,6 +113,7 @@ void LaserResultsMerger::merge(std::vector & out, } } + progress.setPercent(10); for (size_t iLeft = 0; iLeft < leftLaserResults.size(); iLeft++) { NeutralFileRecord& left = leftLaserResults[iLeft]; @@ -131,6 +136,7 @@ void LaserResultsMerger::merge(std::vector & out, } } + progress.setPercent(20); int numCulledPoints = 0; // @@ -144,6 +150,8 @@ void LaserResultsMerger::merge(std::vector & out, mask[getIndex(right)] = 1; } + progress.setPercent(50); + // // Only add left lasers that don't map to a cube by the right laser // @@ -172,6 +180,8 @@ void LaserResultsMerger::merge(std::vector & out, std::cout << "Culled " << numCulledPoints << ", " << (100 * (real)numCulledPoints / leftLaserResults.size()) << "% of the left laser points." << std::endl; } + + progress.setPercent(100); } } // ns diff --git a/src/LaserResultsMerger.h b/src/LaserResultsMerger.h index 9aad34c..4211b68 100644 --- a/src/LaserResultsMerger.h +++ b/src/LaserResultsMerger.h @@ -21,6 +21,7 @@ #pragma once #include "Preset.h" +#include "Progress.h" namespace freelss { @@ -42,7 +43,8 @@ public: int numFramesPerRevolution, int numFramesBetweenLaserPlanes, int maxPointY, - Preset::LaserMergeAction mergeAction); + Preset::LaserMergeAction mergeAction, + Progress& progress); private: diff --git a/src/LocationMapper.cpp b/src/LocationMapper.cpp index 4376256..ab960be 100644 --- a/src/LocationMapper.cpp +++ b/src/LocationMapper.cpp @@ -32,7 +32,8 @@ LocationMapper::LocationMapper(const Vector3& laserLoc, const Vector3& cameraLoc m_laserZ(laserLoc.z), m_cameraX(cameraLoc.x), m_cameraY(cameraLoc.y), - m_cameraZ(cameraLoc.z) + m_cameraZ(cameraLoc.z), + m_groundPlaneHeight(0) { Camera * camera = Camera::getInstance(); m_imageHeight = camera->getImageHeight(); @@ -42,6 +43,7 @@ LocationMapper::LocationMapper(const Vector3& laserLoc, const Vector3& cameraLoc m_sensorHeight = camera->getSensorHeight(); m_maxObjectSize = PresetManager::get()->getActivePreset().maxObjectSize; + m_groundPlaneHeight = PresetManager::get()->getActivePreset().groundPlaneHeight; calculateLaserPlane(); } @@ -85,7 +87,7 @@ void LocationMapper::mapPoints(PixelLocation * laserLocations, // The point must be above the turn table and less than the max distance from the center of the turn table real distXZSq = point->x * point->x + point->z * point->z; - if (point->y >= 0.0 && distXZSq < maxXZDistFromOriginSq && point->y < m_maxObjectSize) + if (point->y >= m_groundPlaneHeight && distXZSq < maxXZDistFromOriginSq && point->y < m_maxObjectSize) { // Set the color if (haveImage) diff --git a/src/LocationMapper.h b/src/LocationMapper.h index 3c427dd..b480b1b 100644 --- a/src/LocationMapper.h +++ b/src/LocationMapper.h @@ -70,6 +70,7 @@ private: real m_sensorWidth; real m_sensorHeight; real m_maxObjectSize; + real m_groundPlaneHeight; }; } diff --git a/src/Main.cpp b/src/Main.cpp index 807b327..0b82c8d 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -344,19 +344,48 @@ void SaveProperties() real ConvertUnitOfLength(real value, UnitOfLength srcUnits, UnitOfLength dstUnits) { - real out; - + // Shortcut if (srcUnits == dstUnits) { - out = value; + return value; } - else if (srcUnits == UL_MILLIMETERS && dstUnits == UL_INCHES) + + // + // Convert to millimeters + // + real mmValue; + if (srcUnits == UL_MILLIMETERS) { - out = value / 25.4; + mmValue = value; } - else if (srcUnits == UL_INCHES && dstUnits == UL_MILLIMETERS) + else if (srcUnits == UL_CENTIMETERS) { - out = value * 25.4; + mmValue = value * 10.0; + } + else if (srcUnits == UL_INCHES ) + { + mmValue = value * 25.4; + } + else + { + throw Exception("Unsupported Unit of Length"); + } + + // + // Convert to destination units + // + real out; + if (dstUnits == UL_MILLIMETERS) + { + out = mmValue; + } + else if (dstUnits == UL_CENTIMETERS) + { + out = mmValue / 10.0; + } + else if (dstUnits == UL_INCHES) + { + out = mmValue / 25.4; } else { @@ -394,6 +423,10 @@ std::string ToString(UnitOfLength unit) out = "mm"; break; + case UL_CENTIMETERS: + out = "cm"; + break; + case UL_INCHES: out = "in"; break; diff --git a/src/Main.h b/src/Main.h index e113c09..eb5a5d3 100644 --- a/src/Main.h +++ b/src/Main.h @@ -82,8 +82,8 @@ The origin is the center of the turn table. // Non-configurable settings #define FREELSS_VERSION_MAJOR 1 -#define FREELSS_VERSION_MINOR 2 -#define FREELSS_VERSION_NAME "FreeLSS 1.2" +#define FREELSS_VERSION_MINOR 3 +#define FREELSS_VERSION_NAME "FreeLSS 1.3" #define PI 3.14159265359 @@ -258,7 +258,7 @@ struct SoftwareUpdate }; /** Units of length */ -enum UnitOfLength { UL_UNKNOWN, UL_MILLIMETERS, UL_INCHES }; +enum UnitOfLength { UL_UNKNOWN, UL_MILLIMETERS, UL_INCHES, UL_CENTIMETERS }; /** Returns the current point in time in ms */ double GetTimeInSeconds(); diff --git a/src/Makefile b/src/Makefile index ffb597c..55780b5 100644 --- a/src/Makefile +++ b/src/Makefile @@ -12,10 +12,10 @@ OBJECTS=WebContent.o PropertyReaderWriter.o Main.o \ Thread.o A4988TurnTable.o RelayLaser.o LocationMapper.o \ PlyWriter.o Calibrator.o RaspistillCamera.o \ NeutralFileWriter.o NeutralFileReader.o RaspicamCamera.o \ - Camera.o ScanResultsWriter.o MmalStillCamera.o \ + Camera.o MmalStillCamera.o \ MmalVideoCamera.o PixelLocationWriter.o StlWriter.o TurnTable.o \ Laser.o Preset.o PresetManager.o Setup.o LaserResultsMerger.o\ - XyzWriter.o UpdateManager.o + XyzWriter.o UpdateManager.o Progress.o all: freelss @@ -91,9 +91,6 @@ NeutralFileReader.o: NeutralFileReader.cpp NeutralFileReader.h Main.h Camera.o: Camera.cpp Camera.h Main.h $(CC) -c $(CFLAGS) Camera.cpp -ScanResultsWriter.o: ScanResultsWriter.cpp ScanResultsWriter.h Main.h - $(CC) -c $(CFLAGS) ScanResultsWriter.cpp - StlWriter.o: StlWriter.cpp StlWriter.h Main.h $(CC) -c $(CFLAGS) StlWriter.cpp @@ -121,12 +118,13 @@ XyzWriter.o: XyzWriter.cpp XyzWriter.h Main.h UpdateManager.o: UpdateManager.cpp UpdateManager.h Main.h $(CC) -c $(CFLAGS) UpdateManager.cpp +Progress.o: Progress.cpp Progress.h Main.h + $(CC) -c $(CFLAGS) Progress.cpp + github: mkdir -p ../../github mkdir -p ../../github/src - mkdir -p ../../github/contrib cp -f *.h *.cpp Makefile ../../github/src - cp -f ../contrib/*.hpp ../../github/contrib run: freelss sudo ./freelss diff --git a/src/PlyWriter.cpp b/src/PlyWriter.cpp index 47ee621..1605f33 100644 --- a/src/PlyWriter.cpp +++ b/src/PlyWriter.cpp @@ -20,13 +20,15 @@ #include "Main.h" #include "PlyWriter.h" +#include "Preset.h" namespace freelss { PlyWriter::PlyWriter() : m_filename(), - m_totalNumPoints(0) + m_totalNumPoints(0), + m_dataFormat(PLY_BINARY) { // Do nothing } @@ -39,18 +41,43 @@ PlyWriter::~PlyWriter() } } -void PlyWriter::begin(const char * filename) +void PlyWriter::setDataFormat(DataFormat dataRepresentation) { - m_filename = filename; + m_dataFormat = dataRepresentation; +} + +void PlyWriter::begin(const std::string& baseFilename) +{ + if (m_fout.is_open()) + { + m_fout.close(); + } + + m_filename = baseFilename + ".ply"; m_totalNumPoints = 0; - m_fout.open(filename); + m_fout.open(m_filename.c_str()); if (!m_fout.is_open()) { - throw Exception(std::string("Error opening points file, ") + filename); + throw Exception(std::string("Error opening points file, ") + m_filename); } m_fout << "ply" << std::endl; - m_fout << "format ascii 1.0" << std::endl; + m_fout << "format "; + + if (m_dataFormat == PlyWriter::PLY_ASCII) + { + m_fout << "ascii"; + } + else if (m_dataFormat == PlyWriter::PLY_BINARY) + { + m_fout << "binary_little_endian"; + } + else + { + throw Exception("Unsupported PLY data format"); + } + + m_fout << " 1.0" << std::endl; m_fout << "element vertex " << std::endl; // Leave space for updating the vertex count m_fout << "property float x" << std::endl; m_fout << "property float y" << std::endl; @@ -67,6 +94,22 @@ void PlyWriter::begin(const char * filename) } void PlyWriter::writePoints(ColoredPoint * points, int numPoints) +{ + if (m_dataFormat == PlyWriter::PLY_ASCII) + { + writeAsciiPoints(points, numPoints); + } + else if (m_dataFormat == PlyWriter::PLY_BINARY) + { + writeBinaryPoints(points, numPoints); + } + else + { + throw Exception("Unsupported PLY data format"); + } +} + +void PlyWriter::writeAsciiPoints(ColoredPoint * points, int numPoints) { m_totalNumPoints += numPoints; for (int iPt = 0; iPt < numPoints; iPt++) @@ -78,6 +121,41 @@ void PlyWriter::writePoints(ColoredPoint * points, int numPoints) } } +void PlyWriter::writeBinaryPoints(ColoredPoint * points, int numPoints) +{ + m_totalNumPoints += numPoints; + for (int iPt = 0; iPt < numPoints; iPt++) + { + const ColoredPoint & point = points[iPt]; + + // + // Make sure we have the proper data types/sizes + // + real32 x = point.x; + real32 y = point.y; + real32 z = point.z; + real32 nx = point.normal.x; + real32 ny = point.normal.y; + real32 nz = point.normal.z; + unsigned char r = point.r; + unsigned char g = point.g; + unsigned char b = point.b; + + // + // Write the record + // + m_fout.write((const char *)&x, sizeof(x)); + m_fout.write((const char *)&y, sizeof(y)); + m_fout.write((const char *)&z, sizeof(z)); + m_fout.write((const char *)&nx, sizeof(nx)); + m_fout.write((const char *)&ny, sizeof(ny)); + m_fout.write((const char *)&nz, sizeof(nz)); + m_fout.write((const char *)&r, sizeof(r)); + m_fout.write((const char *)&g, sizeof(g)); + m_fout.write((const char *)&b, sizeof(b)); + } +} + void PlyWriter::end() { // Close the file @@ -86,7 +164,17 @@ void PlyWriter::end() // Re-open the file and update the point count if (m_totalNumPoints > 0) { - int filePos = 36; // The file position where we should write the point count + int filePos = 31; // The file position where we should write the point count + + if (m_dataFormat == PlyWriter::PLY_ASCII) + { + filePos += (int) std::string("ascii").size(); + } + else if (m_dataFormat == PlyWriter::PLY_BINARY) + { + filePos += (int) std::string("binary_little_endian").size(); + } + std::fstream fout (m_filename.c_str()); if (!fout.is_open()) { diff --git a/src/PlyWriter.h b/src/PlyWriter.h index 15871f5..c75e25e 100644 --- a/src/PlyWriter.h +++ b/src/PlyWriter.h @@ -28,13 +28,19 @@ public: PlyWriter(); ~PlyWriter(); - void begin(const char * filename); + enum DataFormat { PLY_ASCII, PLY_BINARY }; + void setDataFormat(DataFormat dataRepresentation); + void begin(const std::string& baseFilename); void writePoints(ColoredPoint * points, int numPoints); void end(); private: + + void writeAsciiPoints(ColoredPoint * points, int numPoints); + void writeBinaryPoints(ColoredPoint * points, int numPoints); std::ofstream m_fout; std::string m_filename; int m_totalNumPoints; + DataFormat m_dataFormat; }; } diff --git a/src/Preset.cpp b/src/Preset.cpp index 6fef8e5..23c1f1d 100644 --- a/src/Preset.cpp +++ b/src/Preset.cpp @@ -42,7 +42,9 @@ Preset::Preset() : generateXyz (false), generateStl(true), generatePly(true), - laserMergeAction (LMA_PREFER_RIGHT_LASER) + groundPlaneHeight(0), + laserMergeAction (LMA_PREFER_RIGHT_LASER), + plyDataFormat(PlyWriter::PLY_BINARY) { // Do nothing } @@ -64,7 +66,9 @@ void Preset::encodeProperties(std::vector& properties, bool isActivePr properties.push_back(Property("presets." + name + ".generateXyz", ToString(generateXyz))); properties.push_back(Property("presets." + name + ".generateStl", ToString(generateStl))); properties.push_back(Property("presets." + name + ".generatePly", ToString(generatePly))); + properties.push_back(Property("presets." + name + ".groundPlaneHeight", ToString(groundPlaneHeight))); properties.push_back(Property("presets." + name + ".laserMergeAction", ToString((int)laserMergeAction))); + properties.push_back(Property("presets." + name + ".plyDataFormat", ToString((int)plyDataFormat))); if (isActivePreset) { @@ -144,9 +148,17 @@ void Preset::decodeProperties(const std::vector& properties, const std { generatePly = ToBool(prop.value); } + else if (EndsWith(prop.name, name + ".groundPlaneHeight")) + { + groundPlaneHeight = ToReal(prop.value); + } else if (EndsWith(prop.name, name + ".laserMergeAction")) { - laserMergeAction = (LaserMergeAction)ToInt(prop.value); + laserMergeAction = (LaserMergeAction) ToInt(prop.value); + } + else if (EndsWith(prop.name, name + ".plyDataFormat")) + { + plyDataFormat = (PlyWriter::DataFormat) ToInt(prop.value); } } } diff --git a/src/Preset.h b/src/Preset.h index 2fd0659..77e04a5 100644 --- a/src/Preset.h +++ b/src/Preset.h @@ -22,6 +22,7 @@ #include "Laser.h" #include "Camera.h" +#include "PlyWriter.h" namespace freelss { @@ -37,6 +38,7 @@ public: /** The action that should be taken to merge laser results */ enum LaserMergeAction {LMA_PREFER_RIGHT_LASER, LMA_SEPARATE_BY_COLOR }; + Preset(); /** Encodes property information to the properties vector */ @@ -66,7 +68,9 @@ public: bool generateXyz; bool generateStl; bool generatePly; + real groundPlaneHeight; LaserMergeAction laserMergeAction; + PlyWriter::DataFormat plyDataFormat; }; } diff --git a/src/Progress.cpp b/src/Progress.cpp new file mode 100644 index 0000000..d6b4e84 --- /dev/null +++ b/src/Progress.cpp @@ -0,0 +1,73 @@ +/* + **************************************************************************** + * Copyright (c) 2014 Uriah Liggett * + * This file is part of FreeLSS. * + * * + * FreeLSS is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * FreeLSS is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with FreeLSS. If not, see . * + **************************************************************************** +*/ + +#include "Main.h" +#include "Progress.h" + +namespace freelss +{ + + +Progress::Progress() : + m_percent(0), + m_label(""), + m_cs() +{ + // Do nothing +} + + +real Progress::getPercent() +{ + real out; + + m_cs.enter(); + out = m_percent; + m_cs.leave(); + + return out; +} + +std::string Progress::getLabel() +{ + std::string out; + + m_cs.enter(); + out = m_label; + m_cs.leave(); + + return out; +} + +void Progress::setPercent(real percent) +{ + m_cs.enter(); + m_percent = percent; + m_cs.leave(); +} + +void Progress::setLabel(const std::string& label) +{ + m_cs.enter(); + m_label = label; + m_cs.leave(); +} + +} diff --git a/src/ScanResultsWriter.h b/src/Progress.h similarity index 72% rename from src/ScanResultsWriter.h rename to src/Progress.h index ab9cb9d..4713051 100644 --- a/src/ScanResultsWriter.h +++ b/src/Progress.h @@ -19,38 +19,32 @@ */ #pragma once -#include "Thread.h" + #include "CriticalSection.h" namespace freelss { -/** - * Writes the scan results in a separate thread so that the scan doesn't have to wait - * on the I/O to complete. - */ -class ScanResultsWriter : public Thread +/** Tracks the progress of a task in a thread-safe manner. */ +class Progress { public: + Progress(); - /** Constructor */ - ScanResultsWriter(); - void setBaseFilePath(const std::string& baseFilePath); - void write(const NeutralFileRecord& record); + real getPercent(); + std::string getLabel(); - /** The number of records not written yet */ - size_t getNumPendingRecords(); - -protected: - - /** The thread function */ - void run(); + void setPercent(real percent); + void setLabel(const std::string& label); private: + // DISABLE COPY SEMANTICS + Progress(const Progress&) { } + Progress& operator = (const Progress&) { return *this; } + real m_percent; + std::string m_label; CriticalSection m_cs; - std::list m_records; - std::string m_nfFilename; - std::string m_plyFilename; }; + } diff --git a/src/ScanResultsWriter.cpp b/src/ScanResultsWriter.cpp deleted file mode 100644 index 0c38445..0000000 --- a/src/ScanResultsWriter.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/* - **************************************************************************** - * Copyright (c) 2014 Uriah Liggett * - * This file is part of FreeLSS. * - * * - * FreeLSS is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, either version 3 of the License, or * - * (at your option) any later version. * - * * - * FreeLSS is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with FreeLSS. If not, see . * - **************************************************************************** -*/ -#include "Main.h" -#include "ScanResultsWriter.h" -#include "NeutralFileWriter.h" -#include "PlyWriter.h" - -namespace freelss -{ - -ScanResultsWriter::ScanResultsWriter() : - m_cs(), - m_records(), - m_nfFilename(""), - m_plyFilename("") -{ - // Do nothing -} - -void ScanResultsWriter::setBaseFilePath(const std::string& baseFilePath) -{ - m_cs.enter(); - m_nfFilename = baseFilePath + ".db"; - m_plyFilename = baseFilePath + ".ply"; - m_cs.leave(); -} - -void ScanResultsWriter::write(const NeutralFileRecord& record) -{ - m_cs.enter(); - m_records.push_back(record); - m_cs.leave(); -} - -size_t ScanResultsWriter::getNumPendingRecords() -{ - size_t numPending; - - m_cs.enter(); - numPending = m_records.size(); - m_cs.leave(); - - return numPending; -} - -void ScanResultsWriter::run() -{ - std::string nfFilename, plyFilename; - - //NeutralFileWriter nfWriter; - PlyWriter plyWriter; - - m_cs.enter(); - nfFilename = m_nfFilename; - plyFilename = m_plyFilename; - m_cs.leave(); - - try - { - //nfWriter.open(nfFilename); - plyWriter.begin(plyFilename.c_str()); - - bool acquiredRecord = false; - NeutralFileRecord record; - - //nfWriter.beginBatch(); - int numWritten = 0; - - while (!Thread::m_stopRequested) - { - // Check to see if there is work to be done - m_cs.enter(); - if (!m_records.empty()) - { - record = m_records.front(); - m_records.pop_front(); - acquiredRecord = true; - } - else - { - acquiredRecord = false; - } - m_cs.leave(); - - - // If there is data, do work - if (acquiredRecord) - { - //nfWriter.write(record); - plyWriter.writePoints(&record.point, 1); - numWritten++; - } - else - { - Thread::usleep(1000); - } - - // Write to the neutral file in batches - if ((numWritten % 2000) == 0) - { - //nfWriter.commit(); - //nfWriter.beginBatch(); - } - } - } - catch (Exception& ex) - { - std::cerr << "Error: " << ex << std::endl; - } - catch (...) - { - std::cerr << "!! Unknown error occurred!!!" << std::endl; - } - - // Flush any remaining records - //nfWriter.commit(); - - // Close the output files - //nfWriter.close(); - plyWriter.end(); - -} - -} diff --git a/src/Scanner.cpp b/src/Scanner.cpp index 40f4157..266e7ee 100644 --- a/src/Scanner.cpp +++ b/src/Scanner.cpp @@ -62,7 +62,7 @@ Scanner::Scanner() : m_running(false), m_range(360), m_filename(""), - m_progress(0.0), + m_progress(), m_status(), m_maxNumFrameRetries(5), // TODO: Place this in Database m_maxPercentPixelsOverThreshold(3), // TODO: Place this in Database @@ -81,7 +81,6 @@ Scanner::Scanner() : m_rangeFout(), m_numFramesBetweenLaserPlanes(0), m_laserSelection(Laser::ALL_LASERS), - m_currentOperationName(""), m_task(GENERATE_SCAN) { // Do nothing @@ -115,15 +114,9 @@ bool Scanner::isRunning() return running; } -real Scanner::getProgress() +Progress& Scanner::getProgress() { - real progress; - - m_status.enter(); - progress = m_progress; - m_status.leave(); - - return progress; + return m_progress; } real Scanner::getRemainingTime() @@ -157,21 +150,22 @@ void Scanner::prepareScan() { m_status.enter(); m_running = true; - m_progress = 0.0; + m_progress.setPercent(0); + m_startTimeSec = GetTimeInSeconds(); m_remainingTime = 0; if (m_task == Scanner::GENERATE_SCAN) { - m_currentOperationName = "Scanning"; + m_progress.setLabel("Scanning"); } else if (m_task == Scanner::GENERATE_DEBUG) { - m_currentOperationName = "Generating debug info"; + m_progress.setLabel("Generating debug info"); } else { - m_currentOperationName = "Unknown"; + m_progress.setLabel("Unknown"); } // Get handles to our hardware devices @@ -342,8 +336,9 @@ void Scanner::run() double fullTimeSec = 100.0 / percentPerSecond; double remainingSec = fullTimeSec - timeElapsed; + m_progress.setPercent(progress * 100); + m_status.enter(); - m_progress = progress; m_remainingTime = remainingSec; m_status.leave(); @@ -358,7 +353,6 @@ void Scanner::run() m_status.enter(); m_running = false; m_status.leave(); - finishWritingToOutput(); if (m_writeRangeCsvEnabled) { @@ -372,12 +366,6 @@ void Scanner::run() m_turnTable->setMotorEnabled(false); - // Build the mesh - m_status.enter(); - m_progress = 0.5; - m_currentOperationName = "Building mesh"; - m_status.leave(); - std::cout << "Merging laser results..." << std::endl; time1 = GetTimeInSeconds(); @@ -386,7 +374,7 @@ void Scanner::run() std::vector results; LaserResultsMerger merger; merger.merge(results, leftLaserResults, rightLaserResults, maxFramesPerRevolution, - m_numFramesBetweenLaserPlanes, Camera::getInstance()->getImageHeight(), preset.laserMergeAction); + m_numFramesBetweenLaserPlanes, Camera::getInstance()->getImageHeight(), preset.laserMergeAction, m_progress); // Sort by pseudo-step and row std::cout << "Sort 2... " << std::endl; @@ -402,19 +390,30 @@ void Scanner::run() std::cout << "Starting output thread..." << std::endl; if (preset.generatePly) { + m_progress.setLabel("Generating PLY file"); + m_progress.setPercent(0); + std::cout << "Writing PLY file..." << std::endl; time1 = GetTimeInSeconds(); - m_scanResultsWriter.setBaseFilePath(m_filename); - m_scanResultsWriter.execute(); - + m_plyWriter.setDataFormat(preset.plyDataFormat); + m_plyWriter.begin(m_filename); + real percent = 0; for (size_t iRec = 0; iRec < results.size(); iRec++) { - m_scanResultsWriter.write(results[iRec]); + real newPct = 100.0f * iRec / results.size(); + if (newPct - percent > 0.1) + { + m_progress.setPercent(newPct); + percent = newPct; + } + + m_plyWriter.writePoints(&results[iRec].point, 1); } - finishWritingToOutput(); - timingStats.fileWritingTime += GetTimeInSeconds() - time1; + m_plyWriter.end(); + + timingStats.pointCloudWritingTime += GetTimeInSeconds() - time1; } // Generate the XYZ file @@ -423,8 +422,8 @@ void Scanner::run() std::cout << "Generating XYZ file..." << std::endl; time1 = GetTimeInSeconds(); XyzWriter xyzWriter; - xyzWriter.write(m_filename, results); - timingStats.fileWritingTime += GetTimeInSeconds() - time1; + xyzWriter.write(m_filename, results, m_progress); + timingStats.pointCloudWritingTime += GetTimeInSeconds() - time1; } // Generate the STL file @@ -433,35 +432,21 @@ void Scanner::run() std::cout << "Generating STL mesh..." << std::endl; time1 = GetTimeInSeconds(); StlWriter stlWriter; - stlWriter.write(m_filename, results, m_range > 359); - timingStats.meshBuildTime = GetTimeInSeconds() - time1; + stlWriter.write(m_filename, results, m_range > 359, m_progress); + timingStats.meshWritingTime = GetTimeInSeconds() - time1; } logTimingStats(timingStats); + m_progress.setPercent(100); + m_status.enter(); m_running = false; - m_progress = 1.0; m_status.leave(); std::cout << "Done." << std::endl; } - - -void Scanner::finishWritingToOutput() -{ - // Wait for all the I/O writing to complete - while (m_scanResultsWriter.getNumPendingRecords() > 0) - { - Thread::usleep(100000); - } - - // Wait for the thread to stop - m_scanResultsWriter.stop(); - m_scanResultsWriter.join(); -} - void Scanner::generateDebugInfo(Laser::LaserSide laserSide) { // Prepare for scanning @@ -497,9 +482,10 @@ void Scanner::generateDebugInfo(Laser::LaserSide laserSide) Image::overlayPixels(debuggingImage, m_laserLocations, numLocations); locWriter.writeImage(debuggingImage, debuggingImage.getWidth(), debuggingImage.getHeight(), baseFilename + "5.png"); + m_progress.setPercent(100); + m_status.enter(); m_running = false; - m_progress = 1.0; m_status.leave(); std::cout << "Done." << std::endl; } @@ -667,8 +653,6 @@ bool Scanner::processScan(std::vector & results, int frame, f // Rotate the points rotatePoints(m_columnPoints, rotation, numLocationsMapped); - timingStats->pointProcessingTime += GetTimeInSeconds() - time1; - // Write to the neutral file time1 = GetTimeInSeconds(); for (int iLoc = 0; iLoc < numLocationsMapped; iLoc++) @@ -681,7 +665,7 @@ bool Scanner::processScan(std::vector & results, int frame, f record.laserSide = (int) laserSide; results.push_back(record); } - timingStats->fileWritingTime += GetTimeInSeconds() - time1; + timingStats->pointProcessingTime += GetTimeInSeconds() - time1; } return true; @@ -769,8 +753,8 @@ void Scanner::logTimingStats(const Scanner::TimingStats& stats) double now = GetTimeInSeconds(); double totalTime = now - stats.startTime; - double accountedTime = stats.meshBuildTime + stats.imageAcquisitionTime + stats.imageProcessingTime + stats.pointMappingTime - + stats.pointProcessingTime + stats.rotationTime + stats.fileWritingTime + stats.laserTime + stats.laserMergeTime; + double accountedTime = stats.meshWritingTime + stats.imageAcquisitionTime + stats.imageProcessingTime + stats.pointMappingTime + + stats.pointProcessingTime + stats.rotationTime + stats.pointCloudWritingTime + stats.laserTime + stats.laserMergeTime; double unaccountedTime = totalTime - accountedTime; double rate = totalTime / stats.numFrames; @@ -784,8 +768,8 @@ void Scanner::logTimingStats(const Scanner::TimingStats& stats) std::cout << "Point Rotating:\t" << (100.0 * stats.pointProcessingTime / totalTime) << "%" << std::endl; std::cout << "Table Rotation:\t" << (100.0 * stats.rotationTime / totalTime) << "%" << std::endl; std::cout << "Laser Merging:\t" << (100.0 * stats.laserMergeTime / totalTime) << "%" << std::endl; - std::cout << "File Writing:\t" << (100.0 * stats.fileWritingTime / totalTime) << "%" << std::endl; - std::cout << "Mesh Construction:\t" << (100.0 * stats.meshBuildTime / totalTime) << "%" << std::endl; + std::cout << "Point Cloud Writing:\t" << (100.0 * stats.pointCloudWritingTime / totalTime) << "%" << std::endl; + std::cout << "Mesh Writing:\t" << (100.0 * stats.meshWritingTime / totalTime) << "%" << std::endl; std::cout << "Num Frame Retries:\t" << stats.numFrameRetries << std::endl; std::cout << "Num Frames:\t" << stats.numFrames << std::endl; std::cout << "Total Time (min):\t" << (totalTime / 60.0) << std::endl << std::endl; @@ -854,16 +838,6 @@ std::vector Scanner::getPastScanResults() return results; } -std::string Scanner::getCurrentOperationName() -{ - std::string operation; - - m_status.enter(); - operation = m_currentOperationName; - m_status.leave(); - - return operation; -} void Scanner::acquireImage(Image * image) { diff --git a/src/Scanner.h b/src/Scanner.h index e7a0e43..3f7dd8b 100644 --- a/src/Scanner.h +++ b/src/Scanner.h @@ -23,8 +23,9 @@ #include "ImageProcessor.h" #include "Thread.h" #include "CriticalSection.h" -#include "ScanResultsWriter.h" +#include "PlyWriter.h" #include "Laser.h" +#include "Progress.h" namespace freelss { @@ -70,14 +71,11 @@ public: bool isRunning(); /** Returns the progress of the current scan from 0 to 1 */ - real getProgress(); + Progress& getProgress(); /** Get the remaining time for the scan in seconds */ real getRemainingTime(); - /** Returns the name of the current operation taking place */ - std::string getCurrentOperationName(); - /** Generate debugging images and information */ void generateDebugInfo(Laser::LaserSide laserSide); @@ -90,8 +88,8 @@ private: double rotationTime; double startTime; double pointProcessingTime; - double fileWritingTime; - double meshBuildTime; + double pointCloudWritingTime; + double meshWritingTime; double laserTime; double laserMergeTime; int numFrameRetries; @@ -111,8 +109,6 @@ private: /** Free the points data */ void clearPoints(); - void finishWritingToOutput(); - /** * Returns true if the scan was processed successfully and false if there was a problem and the frame needs to be again. */ @@ -158,7 +154,7 @@ private: std::string m_filename; /** The progress of the current scan */ - real m_progress; + Progress m_progress; /** Protection for the running, progress, and any other status parameters */ CriticalSection m_status; @@ -184,8 +180,8 @@ private: /** Location of the first left laser line detected in the last image */ int m_firstRowLeftLaserCol; - /** Writes the results to a neutral file, PLY file, or other output file */ - ScanResultsWriter m_scanResultsWriter; + /** Writes the results to a PLY file */ + PlyWriter m_plyWriter; /** Max number of pixel locations */ unsigned m_maxNumLocations; @@ -217,9 +213,6 @@ private: /** The laser to scan with */ Laser::LaserSide m_laserSelection; - /** The name of current operation taking place */ - std::string m_currentOperationName; - /** The task to perform */ Scanner::Task m_task; }; diff --git a/src/Setup.cpp b/src/Setup.cpp index 9bae315..d1e130b 100644 --- a/src/Setup.cpp +++ b/src/Setup.cpp @@ -45,11 +45,11 @@ Setup::Setup() : cameraLocation(), leftLaserLocation(), rightLaserLocation(), - rightLaserPin(0), + rightLaserPin(5), leftLaserPin(4), - motorEnablePin(1), - motorStepPin(2), - motorDirPin(3), + motorEnablePin(0), + motorStepPin(7), + motorDirPin(1), motorDirPinValue(0), laserOnValue(1), stepsPerRevolution(3200), diff --git a/src/StlWriter.cpp b/src/StlWriter.cpp index 0a70a56..853a3fc 100644 --- a/src/StlWriter.cpp +++ b/src/StlWriter.cpp @@ -23,6 +23,7 @@ #include "StlWriter.h" #include "Camera.h" #include "Laser.h" +#include "Progress.h" namespace freelss { @@ -48,8 +49,11 @@ StlWriter::StlWriter() : } -void StlWriter::write(const std::string& baseFilename, const std::vector& results, bool connectLastFrameToFirst) +void StlWriter::write(const std::string& baseFilename, const std::vector& results, bool connectLastFrameToFirst, Progress& progress) { + progress.setLabel("Generating STL file"); + progress.setPercent(0); + std::string stlFilename = baseFilename + ".stl"; std::ofstream fout (stlFilename.c_str()); if (!fout.is_open()) @@ -80,8 +84,17 @@ void StlWriter::write(const std::string& baseFilename, const std::vector 0.1) + { + progress.setPercent(newPct); + percent = newPct; + } + // Reduce the number of result rows and filter out some of the noise NeutralFileRecord::lowpassFilter(* currentFrame, frameC, maxNumRows, numRowBins); @@ -143,7 +156,7 @@ void StlWriter::writeHeader(std::ofstream& fout) { unsigned char header[80]; memset(header, 0, sizeof(header)); - strcpy((char *)header, "2014 Uriah Liggett"); + strcpy((char *)header, "2015 Uriah Liggett"); // Write header string fout.write((const char *)header, sizeof(unsigned char) * 80); diff --git a/src/StlWriter.h b/src/StlWriter.h index 5825a45..307a4dd 100644 --- a/src/StlWriter.h +++ b/src/StlWriter.h @@ -23,13 +23,14 @@ namespace freelss { +class Progress; class StlWriter { public: StlWriter(); - void write(const std::string& filename, const std::vector& results, bool connectLastFrameToFirst); + void write(const std::string& filename, const std::vector& results, bool connectLastFrameToFirst, Progress& progress); private: void writeHeader(std::ofstream& fout); diff --git a/src/WebContent.cpp b/src/WebContent.cpp index ba5d56f..71f8181 100644 --- a/src/WebContent.cpp +++ b/src/WebContent.cpp @@ -24,6 +24,7 @@ #include "Setup.h" #include "Laser.h" #include "Camera.h" +#include "Progress.h" namespace freelss { @@ -236,6 +237,8 @@ const std::string WebContent::GENERATE_PLY = "GENERATE_PLY"; const std::string WebContent::SEPARATE_LASERS_BY_COLOR = "SEPARATE_LASERS_BY_COLOR"; const std::string WebContent::UNIT_OF_LENGTH = "UNIT_OF_LENGTH"; const std::string WebContent::VERSION_NAME = "VERSION_NAME"; +const std::string WebContent::GROUND_PLANE_HEIGHT = "GROUND_PLANE_HEIGHT"; +const std::string WebContent::PLY_DATA_FORMAT = "PLY_DATA_FORMAT"; const std::string WebContent::SERIAL_NUMBER_DESCR = "The serial number of the ATLAS 3D scanner"; const std::string WebContent::CAMERA_X_DESCR = "X-compoment of camera location. ie: The camera is always at X = 0."; @@ -266,6 +269,8 @@ const std::string WebContent::GENERATE_XYZ_DESCR = "Whether to generate an XYZ p const std::string WebContent::GENERATE_STL_DESCR = "Whether to generate an STL mesh from the scan."; const std::string WebContent::GENERATE_PLY_DESCR = "Whether to generate a PLY point clould from the scan."; const std::string WebContent::SEPARATE_LASERS_BY_COLOR_DESCR = "Calibration debugging option to separate the results from different lasers by color (requires PLY)."; +const std::string WebContent::GROUND_PLANE_HEIGHT_DESCR = "Any scan data less than this height above the turntable will not be included in the output files."; +const std::string WebContent::PLY_DATA_FORMAT_DESCR = "Whether to generate binary or ASCII PLY files."; std::string WebContent::scan(const std::vector& pastScans) { @@ -363,8 +368,10 @@ std::string WebContent::scanResult(size_t index, const ScanResult& result) return sstr.str(); } -std::string WebContent::scanRunning(real progress, real remainingTime) +std::string WebContent::scanRunning(Progress& progress, real remainingTime) { + real minRemaining = remainingTime / 60.0; + std::stringstream sstr; sstr << "" << "" @@ -373,11 +380,20 @@ std::string WebContent::scanRunning(real progress, real remainingTime) << JAVASCRIPT << std::endl << "" - << "

Scan is " - << progress - << "% complete with " - << (remainingTime / 60.0) - << " minutes remaining.

" + << "

" + << progress.getLabel() + << " is " + << progress.getPercent() + << "% complete"; + + if (minRemaining > 0.01) + { + sstr << " with " + << minRemaining + << " minutes remaining"; + } + + sstr << ".

" << "
" << "" << "" @@ -539,11 +555,13 @@ std::string WebContent::setup(const std::string& message) sstr << setting(WebContent::SERIAL_NUMBER, "Serial Number", setup->serialNumber, SERIAL_NUMBER_DESCR); std::string mmSel = setup->unitOfLength == UL_MILLIMETERS ? " SELECTED" : ""; + std::string cmSel = setup->unitOfLength == UL_CENTIMETERS ? " SELECTED" : ""; std::string inSel = setup->unitOfLength == UL_INCHES ? " SELECTED" : ""; sstr << "
Unit of Length
"; sstr << "
"; sstr << "
The unit of length for future values entered on the setup page.
\n"; @@ -580,6 +598,9 @@ std::string WebContent::setup(const std::string& message) std::string WebContent::settings(const std::string& message) { + const Setup * setup = Setup::get(); + UnitOfLength srcUnit = UL_MILLIMETERS; // Lengths are always represented in millimeters internally + UnitOfLength dstUnit = setup->unitOfLength; const Preset& preset = PresetManager::get()->getActivePreset(); @@ -652,6 +673,7 @@ std::string WebContent::settings(const std::string& message) sstr << ""; sstr << "
The laser(s) that will be used when scanning.
\n"; + // // Camera Mode UI // @@ -674,11 +696,29 @@ std::string WebContent::settings(const std::string& message) sstr << setting(WebContent::FRAMES_PER_REVOLUTION, "Frames Per Revolution", preset.framesPerRevolution, FRAMES_PER_REVOLUTION_DESCR); sstr << setting(WebContent::LASER_MAGNITUDE_THRESHOLD, "Laser Threshold", preset.laserThreshold, LASER_MAGNITUDE_THRESHOLD_DESCR); + sstr << setting(WebContent::GROUND_PLANE_HEIGHT, "Ground Plane Height", ConvertUnitOfLength(preset.groundPlaneHeight, srcUnit, dstUnit), GROUND_PLANE_HEIGHT_DESCR, ToString(dstUnit) + ".", false); sstr << setting(WebContent::LASER_DELAY, "Laser Delay", preset.laserDelay, LASER_DELAY_DESCR, "μs"); sstr << setting(WebContent::STABILITY_DELAY, "Stability Delay", preset.stabilityDelay, STABILITY_DELAY_DESCR, "μs"); sstr << setting(WebContent::MAX_LASER_WIDTH, "Max Laser Width", preset.maxLaserWidth, MAX_LASER_WIDTH_DESCR, "px."); sstr << setting(WebContent::MIN_LASER_WIDTH, "Min Laser Width", preset.minLaserWidth, MIN_LASER_WIDTH_DESCR, "px."); + + + // + // PLY Data Format UI + // + PlyWriter::DataFormat plyDataFormat = preset.plyDataFormat; + std::string plyAsciiSel = plyDataFormat == PlyWriter::PLY_ASCII ? " SELECTED" : ""; + std::string plyBinarySel = plyDataFormat == PlyWriter::PLY_BINARY ? " SELECTED" : ""; + sstr << checkbox(WebContent::GENERATE_PLY, "Generate PLY File", preset.generatePly, GENERATE_PLY_DESCR); + + sstr << "
PLY Data Format
"; + sstr << "
"; + sstr << "
" << WebContent::PLY_DATA_FORMAT_DESCR << "
\n"; + sstr << checkbox(WebContent::GENERATE_STL, "Generate STL File", preset.generateStl, GENERATE_STL_DESCR); sstr << checkbox(WebContent::GENERATE_XYZ, "Generate XYZ File", preset.generateXyz, GENERATE_XYZ_DESCR); sstr << checkbox(WebContent::SEPARATE_LASERS_BY_COLOR, "Separate the Lasers", preset.laserMergeAction == Preset::LMA_SEPARATE_BY_COLOR, SEPARATE_LASERS_BY_COLOR_DESCR); diff --git a/src/WebContent.h b/src/WebContent.h index 72b816f..02c2dad 100644 --- a/src/WebContent.h +++ b/src/WebContent.h @@ -24,6 +24,8 @@ namespace freelss { +class Progress; + class WebContent { public: @@ -37,7 +39,7 @@ public: }; static std::string scan(const std::vector& pastScans); - static std::string scanRunning(real progress, real remainingTime); + static std::string scanRunning(Progress& progress, real remainingTime); static std::string cal1(const std::string& message); static std::string settings(const std::string& message); static std::string setup(const std::string& message); @@ -79,6 +81,9 @@ public: static const std::string SEPARATE_LASERS_BY_COLOR; static const std::string UNIT_OF_LENGTH; static const std::string VERSION_NAME; + static const std::string GROUND_PLANE_HEIGHT; + static const std::string PLY_DATA_FORMAT; + private: static std::string setting(const std::string& name, const std::string& label, @@ -125,6 +130,8 @@ private: static const std::string GENERATE_STL_DESCR; static const std::string GENERATE_PLY_DESCR; static const std::string SEPARATE_LASERS_BY_COLOR_DESCR; + static const std::string GROUND_PLANE_HEIGHT_DESCR; + static const std::string PLY_DATA_FORMAT_DESCR; }; } diff --git a/src/XyzWriter.cpp b/src/XyzWriter.cpp index 592a614..59ed038 100644 --- a/src/XyzWriter.cpp +++ b/src/XyzWriter.cpp @@ -21,12 +21,22 @@ #include "Main.h" #include "XyzWriter.h" #include "Camera.h" +#include "Progress.h" namespace freelss { -void XyzWriter::write(const std::string& baseFilename, const std::vector& results) +void XyzWriter::write(const std::string& baseFilename, const std::vector& results, Progress& progress) { + // Sanity check + if (results.empty()) + { + return; + } + + progress.setLabel("Generating XYZ file"); + progress.setPercent(0); + std::string xyzFilename = baseFilename + ".xyz"; std::ofstream xyz (xyzFilename.c_str()); if (!xyz.is_open()) @@ -39,14 +49,20 @@ void XyzWriter::write(const std::string& baseFilename, const std::vector frameA; std::vector currentFrame; size_t resultIndex = 0; + real percent = 0; while (NeutralFileRecord::readNextFrame(frameA, results, resultIndex)) { + real newPct = 100.0f * resultIndex / results.size(); + if (newPct - percent > 0.1) + { + progress.setPercent(newPct); + percent = newPct; + } + // Reduce the number of result rows and filter out some of the noise NeutralFileRecord::lowpassFilter(currentFrame, frameA, maxNumRows, numRowBins); diff --git a/src/XyzWriter.h b/src/XyzWriter.h index a409a8f..88ea819 100644 --- a/src/XyzWriter.h +++ b/src/XyzWriter.h @@ -23,6 +23,8 @@ namespace freelss { +class Progress; + /** * Writes the scan results as an XYZ file. */ @@ -30,7 +32,7 @@ class XyzWriter { public: - void write(const std::string& filename, const std::vector& results); + void write(const std::string& filename, const std::vector& results, Progress& progress); }; }