20 #include <QCoreApplication>
28 :
public QMap<ccRasterGrid::ExportableFields, QString> {
68 unsigned& gridHeight) {
69 gridWidth = gridHeight = 0;
79 const unsigned char X = Z == 2 ? 0 : Z + 1;
80 const unsigned char Y =
X == 2 ? 0 :
X + 1;
84 if (boxDiag.
u[
X] <= 0 || boxDiag.
u[Y] <= 0) {
86 "[ccRasterGrid::ComputeGridSize] Invalid cloud bounding box!");
92 gridWidth = 1 +
static_cast<unsigned>(boxDiag.
u[
X] /
gridStep + 0.5);
93 gridHeight = 1 +
static_cast<unsigned>(boxDiag.
u[Y] /
gridStep + 0.5);
132 }
catch (
const std::bad_alloc&) {
150 bool interpolateEmptyCells,
159 if (gridTotalSize == 0) {
177 for (
unsigned i = 0; i < sfCount; ++i) {
180 std::numeric_limits<SF::value_type>::quiet_NaN());
182 }
catch (
const std::bad_alloc&) {
186 "[Rasterize] Failed to allocate memory for scalar "
190 interpolateSF =
false;
195 unsigned pointCount = cloud->
size();
197 if (progressDialog) {
199 progressDialog->
setInfo(QObject::tr(
"Points: %L1\nCells: %L2 x %L3")
203 progressDialog->
start();
204 progressDialog->show();
205 QCoreApplication::processEvents();
211 const unsigned char X = Z == 2 ? 0 : Z + 1;
212 const unsigned char Y =
X == 2 ? 0 :
X + 1;
217 for (
unsigned n = 0; n < pointCount; ++n) {
223 int i =
static_cast<int>((relativePos.
u[
X] /
gridStep + 0.5));
224 int j =
static_cast<int>((relativePos.
u[Y] /
gridStep + 0.5));
227 if (i < 0 || i >=
static_cast<int>(
width) || j < 0 ||
228 j >=
static_cast<int>(
height)) {
235 assert(i >= 0 && j >= 0);
281 if (distToP < distToQ) {
312 int pos = j *
static_cast<int>(
width) + i;
313 assert(pos <
static_cast<int>(gridTotalSize));
322 ScalarType sfValue = sf->
getValue(n);
326 if (aCell.
nbPoints && std::isfinite(formerValue)) {
327 switch (sfInterpolation) {
331 formerValue, sfValue);
340 formerValue, sfValue);
367 assert(!scalarField.empty());
369 double* _gridSF = scalarField.data();
370 for (
unsigned j = 0; j <
height; ++j) {
372 for (
unsigned i = 0; i <
width; ++i, ++_gridSF) {
373 if (row[i].nbPoints > 1) {
374 if (std::isfinite(*_gridSF))
376 *_gridSF /= row[i].nbPoints;
387 for (
unsigned j = 0; j <
height; ++j) {
389 for (
unsigned i = 0; i <
width; ++i) {
405 switch (projectionType) {
427 for (
unsigned i = 0; i <
height; ++i)
428 for (
unsigned j = 0; j <
width; ++j)
433 if (interpolateEmptyCells) {
434 std::vector<CCVector2> the2DPoints;
437 "[Rasterize] Not enough non-empty cells for "
444 }
catch (
const std::bad_alloc&) {
447 "[Rasterize] Not enough memory to interpolate empty "
453 if (!the2DPoints.empty()) {
455 for (
unsigned j = 0; j <
height; ++j) {
457 for (
unsigned i = 0; i <
width; ++i) {
458 if (row[i].nbPoints) {
460 the2DPoints[index++] =
470 std::string errorStr;
475 unsigned triNum = delaunayMesh.
size();
478 for (
unsigned k = 0; k < triNum; ++k) {
483 int xMin = 0, yMin = 0, xMax = 0, yMax = 0;
485 for (
unsigned j = 0; j < 3; ++j) {
486 const CCVector2& P2D = the2DPoints[tsi->
i[j]];
487 P[j][0] =
static_cast<int>(P2D.
x);
488 P[j][1] =
static_cast<int>(P2D.
y);
490 xMin = std::min(std::min(P[0][0], P[1][0]), P[2][0]);
491 yMin = std::min(std::min(P[0][1], P[1][1]), P[2][1]);
492 xMax = std::max(std::max(P[0][0], P[1][0]), P[2][0]);
493 yMax = std::max(std::max(P[0][1], P[1][1]), P[2][1]);
498 const double& valA =
rows[P[0][1]][P[0][0]].h;
499 const double& valB =
rows[P[1][1]][P[1][0]].h;
500 const double& valC =
rows[P[2][1]][P[2][0]].h;
502 double det =
static_cast<double>(
503 (P[1][1] - P[2][1]) * (P[0][0] - P[2][0]) +
504 (P[2][0] - P[1][0]) * (P[0][1] - P[2][1]));
506 for (
int j = yMin; j <= yMax; ++j) {
507 Row& row =
rows[
static_cast<unsigned>(j)];
509 for (
int i = xMin; i <= xMax; ++i) {
511 if (!row[i].nbPoints) {
517 for (
int ti = 0; ti < 3; ++ti) {
518 const int* P1 = P[ti];
519 const int* P2 = P[(ti + 1) % 3];
520 if ((P2[1] <= j && j < P1[1]) ||
521 (P1[1] <= j && j < P2[1])) {
522 int t = (i - P2[0]) *
526 if (P1[1] < P2[1]) t = -t;
527 if (t < 0) inside = !inside;
532 double l1 = ((P[1][1] - P[2][1]) *
534 (P[2][0] - P[1][0]) *
537 double l2 = ((P[2][1] - P[0][1]) *
539 (P[0][0] - P[2][0]) *
542 double l3 = 1.0 - l1 - l2;
544 row[i].h = l1 * valA + l2 * valB +
546 assert(std::isfinite(row[i].h));
551 rows[P[0][1]][P[0][0]]
554 rows[P[1][1]][P[1][0]]
557 rows[P[2][1]][P[2][0]]
559 row[i].color = l1 * colA +
566 assert(!gridSF.empty());
568 const double& sfValA =
571 const double& sfValB =
574 const double& sfValC =
577 assert(i + j *
width <
579 gridSF[i + j *
width] =
580 l1 * sfValA + l2 * sfValB +
591 "failed: Triangle lib. said '%1'")
592 .arg(QString::fromStdString(errorStr)));
604 for (
unsigned i = 0; i <
height; ++i) {
605 for (
unsigned j = 0; j <
width; ++j) {
606 double h =
rows[i][j].h;
608 if (std::isfinite(h))
639 for (
unsigned i = 0; i <
height; ++i)
640 for (
unsigned j = 0; j <
width; ++j)
651 size_t emptyCellCount = 0;
653 for (
unsigned i = 0; i <
height; ++i) {
654 for (
unsigned j = 0; j <
width; ++j) {
655 double h =
rows[i][j].h;
657 if (std::isfinite(h))
683 double customCellHeight ) {
687 double defaultHeight = std::numeric_limits<double>::quiet_NaN();
688 switch (fillEmptyCellsStrategy) {
696 defaultHeight = customCellHeight;
705 assert(defaultHeight != 0);
707 for (
unsigned i = 0; i <
height; ++i) {
708 for (
unsigned j = 0; j <
width; ++j) {
709 if (!std::isfinite(
rows[i][j].h))
711 rows[i][j].h = defaultHeight;
719 const std::vector<ExportableFields>& exportedFields,
722 bool resampleInputCloudXY,
723 bool resampleInputCloudZ,
728 double emptyCellsHeight,
729 bool exportToOriginalCS)
const {
741 if (pointsCount == 0) {
751 if (resampleInputCloudXY) {
754 "[Rasterize] Internal error: no input clouds specified "
765 for (
unsigned j = 0; j <
height; ++j) {
766 for (
unsigned i = 0; i <
width; ++i) {
775 assert(refCloud.
size() != 0);
778 ->partialClone(&refCloud)
787 if (!resampleInputCloudZ) {
790 unsigned pointIndex = 0;
791 for (
unsigned j = 0; j <
height; ++j) {
792 for (
unsigned i = 0; i <
width; ++i) {
816 std::vector<cloudViewer::ScalarField*> exportedSFs;
817 if (!exportedFields.empty()) {
818 exportedSFs.resize(exportedFields.size(),
nullptr);
819 for (
size_t i = 0; i < exportedFields.size(); ++i) {
821 switch (exportedFields[i]) {
837 QString(
"[Rasterize] Scalar field '%1' already "
838 "exists. It will be overwritten.")
851 "[Rasterize] Couldn't allocate scalar field(s)! Try to "
852 "free some memory ...");
857 assert(exportedSFs[i]);
861 if (resampleInputCloudXY) {
873 if (!cloudGrid->
reserve(pointsCount)) {
881 "[Rasterize] Not enough memory to interpolate colors!");
888 const unsigned char X = (Z == 2 ? 0 : Z + 1);
889 const unsigned char Y = (
X == 2 ? 0 :
X + 1);
891 const unsigned char outX = (exportToOriginalCS ?
X : 0);
892 const unsigned char outY = (exportToOriginalCS ? Y : 1);
893 const unsigned char outZ = (exportToOriginalCS ? Z : 2);
897 unsigned nonEmptyCellIndex = 0;
903 for (
unsigned j = 0; j <
height; ++j) {
907 for (
unsigned i = 0; i <
width; ++i, ++aCell) {
913 if (!resampleInputCloudXY || aCell->
nbPoints == 0) {
935 assert(!resampleInputCloudXY || inputCloud);
936 assert(!resampleInputCloudXY ||
944 assert(exportedSFs.size() == exportedFields.size());
945 for (
size_t k = 0; k < exportedSFs.size(); ++k) {
952 switch (exportedFields[k]) {
954 sVal =
static_cast<ScalarType
>(aCell->
h);
957 sVal =
static_cast<ScalarType
>(aCell->
nbPoints);
960 sVal =
static_cast<ScalarType
>(aCell->
minHeight);
963 sVal =
static_cast<ScalarType
>(aCell->
maxHeight);
966 sVal =
static_cast<ScalarType
>(aCell->
avgHeight);
972 sVal =
static_cast<ScalarType
>(aCell->
maxHeight -
980 if (resampleInputCloudXY) {
983 assert(nonEmptyCellIndex < inputCloud->
size());
984 assert(nonEmptyCellIndex < sf->
size());
985 sf->
setValue(nonEmptyCellIndex, sVal);
988 assert(sf->size() < sf->capacity());
993 assert(sf->size() < sf->capacity());
1020 assert(exportedSFs.size() == exportedFields.size());
1021 for (
size_t k = 0; k < exportedSFs.size(); ++k) {
1030 static_cast<ScalarType
>(emptyCellsHeight);
1031 assert(sf->size() < sf->capacity());
1034 assert(sf->size() < sf->capacity());
1047 for (
auto sf : exportedSFs) {
1049 sf->computeMinAndMax();
1054 if (!resampleInputCloudXY) {
1056 if (interpolateSF && inputCloud &&
1075 QString(formerSf->
getName()).append(
".old")));
1080 "[Rasterize] Failed to allocate a new scalar field "
1081 "for storing SF '%s' values! Try to free some "
1090 const ScalarType emptyCellSFValue =
1093 for (
unsigned j = 0; j <
height; ++j) {
1095 for (
unsigned i = 0; i <
width; ++i, ++_sfGrid) {
1101 static_cast<ScalarType
>(*_sfGrid);
1104 sf->
setValue(n++, emptyCellSFValue);
1124 QString gridName = QString(
"raster(%1)").arg(
gridStep);
1126 gridName.prepend(inputCloud->
getName() + QString(
"."));
constexpr ScalarType NAN_VALUE
NaN as a ScalarType value.
Vector2Tpl< double > CCVector2d
Double 2D Vector.
Vector2Tpl< PointCoordinateType > CCVector2
Default 2D Vector.
Vector3Tpl< double > CCVector3d
Double 3D Vector.
float PointCoordinateType
Type of the coordinates of a (N-D) point.
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
static bool Error(const char *format,...)
Display an error dialog with formatted message.
static Vector3Tpl fromArray(const int a[3])
Constructor from an int array.
virtual bool hasColors() const
Returns whether colors are enabled or not.
A 3D cloud interface with associated features (color, normals, octree, etc.)
void setPointSize(unsigned size=0)
Sets point size.
virtual const ecvColor::Rgb & getPointColor(unsigned pointIndex) const =0
Returns color corresponding to a given point.
virtual QString getName() const
Returns object name.
bool isA(CV_CLASS_ENUM type) const
virtual void setName(const QString &name)
Sets object name.
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
void unallocateColors()
Erases the cloud colors.
int addScalarField(const char *uniqueName) override
Creates a new scalar field and registers it.
bool reserve(unsigned numberOfPoints) override
Reserves memory for all the active features.
static ccPointCloud * From(const cloudViewer::GenericIndexedCloud *cloud, const ccGenericPointCloud *sourceCloud=nullptr)
Creates a new point cloud object from a GenericIndexedCloud.
bool reserveTheRGBTable()
Reserves memory to store the RGB colors.
bool hasColors() const override
Returns whether colors are enabled or not.
void addRGBColor(const ecvColor::Rgb &C)
Pushes an RGB color on stack.
bool hasScalarFields() const override
Returns whether one or more scalar fields are instantiated.
A scalar field associated to display-related parameters.
void computeMinAndMax() override
Determines the min and max values.
void importParametersFrom(const ccScalarField *sf)
Imports the parameters from another scalar field.
const Vector3Tpl< T > & maxCorner() const
Returns max corner (const)
const Vector3Tpl< T > & minCorner() const
Returns min corner (const)
bool isValid() const
Returns whether bounding box is valid or not.
A class to compute and handle a Delaunay 2D mesh on a subset of points.
virtual unsigned size() const override
Returns the number of triangles.
void placeIteratorAtBeginning() override
Places the mesh iterator at the beginning.
virtual bool buildMesh(const std::vector< CCVector2 > &points2D, std::size_t pointCountToUse, std::string &outputErrorStr)
Build the Delaunay mesh on top a set of 2D points.
VerticesIndexes * getNextTriangleVertIndexes() override
static constexpr int USE_ALL_POINTS
virtual unsigned size() const =0
Returns the number of points.
virtual const CCVector3 * getPoint(unsigned index) const =0
Returns the ith point.
bool oneStep()
Increments total progress value of a single unit.
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 getNumberOfScalarFields() const
Returns the number of associated (and active) scalar fields.
void addPoint(const CCVector3 &P)
Adds a 3D point to the database.
unsigned size() const override
unsigned capacity() const
Returns cloud capacity (i.e. reserved size)
const CCVector3 * getPoint(unsigned index) const override
A very simple point cloud (no point duplication)
virtual bool addPointIndex(unsigned globalIndex)
Point global index insertion mechanism.
unsigned size() const override
Returns the number of points.
virtual bool reserve(unsigned n)
Reserves some memory for hosting the point references.
A simple scalar field (to be associated to a point cloud)
void addElement(ScalarType value)
static ScalarType NaN()
Returns the specific NaN value.
ScalarType & getValue(std::size_t index)
void setValue(std::size_t index, ScalarType value)
const char * getName() const
Returns scalar field name.
bool resizeSafe(std::size_t count, bool initNewElements=false, ScalarType valueForNewElements=0)
Resizes memory (no exception thrown)
static bool ValidValue(ScalarType value)
Returns whether a scalar value is valid or not.
unsigned currentSize() const
Graphical progress indicator (thread-safe)
virtual void setInfo(const char *infoStr) override
Notifies some information about the ongoing process.
virtual void start() override
virtual void setMethodTitle(const char *methodTitle) override
Notifies the algorithm title.
unsigned char ColorCompType
Default color components type (R,G and B)
static DefaultFieldNames s_defaultFieldNames
bool interpolateColors(const ccHObject::Container &selectedEntities, QWidget *parent)
Interpolate colors from on entity and transfer them to another one.
constexpr Rgb black(0, 0, 0)
double avgHeight
Average height value.
unsigned nbPoints
Number of points projected in this cell.
unsigned pointIndex
Nearest point index (if any)
PointCoordinateType maxHeight
Max height value.
PointCoordinateType minHeight
Min height value.
double stdDevHeight
Height std.dev.
ExportableFields
Exportable fields.
@ PER_CELL_UNIQUE_COUNT_VALUE
@ PER_CELL_PERCENTILE_VALUE
void updateCellStats()
Updates the statistics about the cells.
void clear()
Clears the grid.
unsigned validCellCount
Number of VALID cells.
unsigned nonEmptyCellCount
Number of NON-EMPTY cells.
void setValid(bool state)
Sets valid.
ProjectionType
Types of projection.
@ INVALID_PROJECTION_TYPE
double gridStep
Grid step ('pixel' size)
ccRasterGrid()
Default constructor.
std::vector< ccRasterCell > Row
Row.
unsigned height
Number of rows.
bool hasColors
Whether the (average) colors are available or not.
bool init(unsigned w, unsigned h, double gridStep, const CCVector3d &minCorner)
Initializes / resets the grid.
double meanHeight
Average height (computed on the NON-EMPTY or INTERPOLATED cells)
bool fillWith(ccGenericPointCloud *cloud, unsigned char projectionDimension, ProjectionType projectionType, bool interpolateEmptyCells, ProjectionType sfInterpolation=INVALID_PROJECTION_TYPE, ecvProgressDialog *progressDialog=nullptr)
Fills the grid with a point cloud.
std::vector< SF > scalarFields
Associated scalar fields.
static QString GetDefaultFieldName(ExportableFields field)
Returns the default name of a given field.
CCVector3d minCorner
Min corner (3D)
void reset()
Resets the grid.
std::vector< Row > rows
All cells.
double maxHeight
Max height (computed on the NON-EMPTY or INTERPOLATED cells)
virtual ~ccRasterGrid()
Destructor.
unsigned updateNonEmptyCellCount()
Updates the number of non-empty cells.
bool isValid() const
Returns whether the grid is 'valid' or not.
unsigned width
Number of columns.
ccPointCloud * convertToCloud(const std::vector< ExportableFields > &exportedFields, bool interpolateSF, bool interpolateColors, bool resampleInputCloudXY, bool resampleInputCloudZ, ccGenericPointCloud *inputCloud, unsigned char Z, const ccBBox &box, bool fillEmptyCells, double emptyCellsHeight, bool exportToOriginalCS) const
Converts the grid to a cloud with scalar field(s)
EmptyCellFillOption
Option for handling empty cells.
static bool ComputeGridSize(unsigned char Z, const ccBBox &box, double gridStep, unsigned &width, unsigned &height)
Computes the raster size for a given bounding-box.
double minHeight
Min height (computed on the NON-EMPTY or INTERPOLATED cells)
void fillEmptyCells(EmptyCellFillOption fillEmptyCellsStrategy, double customCellHeight=0)
Fills the empty cell (for all strategies but 'INTERPOLATE_DELAUNAY')
Triangle described by the indexes of its 3 vertices.