Files
secondo/Algebras/Pointcloud2/analyzeOperators/opAnalyzeRaster.cpp

1964 lines
60 KiB
C++
Raw Normal View History

2026-01-23 17:03:45 +08:00
/*
----
This file is part of SECONDO.
Copyright (C) 2019,
Faculty of Mathematics and Computer Science,
Database Systems for New Applications.
SECONDO 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 2 of the License, or
(at your option) any later version.
SECONDO 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 SECONDO; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
----
//[<] [\ensuremath{<}]
//[>] [\ensuremath{>}]
\setcounter{tocdepth}{3}
\tableofcontents
1 Pointcloud2 "AnalyzeRaster" Operator
They identify objects in pointcloud2 and
cluster them.
analyzeRaster: pointcloud2(R,tuple(Z1...Zn))
-> pointcloud2(R,tuple(Z1...Zn,ObjID:int,CatID:int))
use only with metric pointClouds
if non metric use project operator to transfer to UTM
Parameters:
* CELL\_SIZE\_IN\_M 0.15; min: 0.01 max: 100.0
* DELTA\_ALT\_IN\_M 5.0; min: 0.0 max: 100.0
* NEIGHBOUR\_CELLS false; true 8 cells, false only 4
* THRESHOLD\_MERGE 0.5; min: 0.0, no limits
* DISTANCE\_SIG\_MAXIMA 0.1; min: 0.0, no limits
* OVERLAP\_RASTERS 0.1; min: 0.0% max: 50.0%
* MIN\_GROUND\_CELLS 100; min: 1 no limits
* MAX\_CELLS\_AT\_EDGE 3
* RASTER\_CLASSIFY\_EPSILON 1.0
* RASTER\_CLASSIFY\_MINPTS 3
*/
#include "opAnalyzeRaster.h"
#include "ARClassify.h"
#include <math.h>
#include <stack>
#include <set>
#include <bitset>
#include "NestedList.h"
using namespace pointcloud2;
extern NestedList *nl;
/*
1.1 Type Mapping
*/
ListExpr op_analyzeRaster::analyzeRasterTM(ListExpr args)
{
if (!(nl->HasLength(args, 1) && Pointcloud2::TypeCheck(nl->First(args))))
{
return listutils::typeError("wrong input");
}
ListExpr cloudType = nl->First(args);
ListExpr pc2Ref = nl->Second(cloudType);
if ((nl->IsAtom(pc2Ref) && !nl->IsEqual(pc2Ref,"EUCLID",false))
|| (!nl->IsAtom(pc2Ref)
&& !nl->IsEqual(nl->First(pc2Ref),"EUCLID",false))) {
return listutils::typeError("Ref has to be EUCLID - use projectUTM");
}
//intensity
int posIntensity;
if (!nl->IsAtom(pc2Ref)){
ListExpr type = nl->TheEmptyList();
ListExpr attrList = nl->Second(Pointcloud2::getTupleType(cloudType));
posIntensity = listutils::findAttribute(attrList, "Intensity", type);
//red, blue, green not realized
//int posRed = listutils::findAttribute(attrList, "Red", type);
//int posGreen = listutils::findAttribute(attrList, "Green", type);
//int posBlue = listutils::findAttribute(attrList, "Blue", type);
}
else
{
posIntensity = 0;
}
ListExpr newCloudType, appendage;
if (Pointcloud2::GET_RASTER_NOT_PC) {
newCloudType = nl->TwoElemList(
listutils::basicSymbol<Pointcloud2>(),
nl->SymbolAtom(Referencesystem::toString(Referencesystem::EUCLID)));
appendage = nl->FiveElemList(
nl->TwoElemList(nl->SymbolAtom("Count"),
listutils::basicSymbol<CcInt>()),
nl->TwoElemList(nl->SymbolAtom("AltMin"),
listutils::basicSymbol<CcReal>()),
nl->TwoElemList(nl->SymbolAtom("AltMax"),
listutils::basicSymbol<CcReal>()),
nl->TwoElemList(nl->SymbolAtom("AltAvg"),
listutils::basicSymbol<CcReal>()),
nl->TwoElemList(nl->SymbolAtom("IntensityAvg"),
listutils::basicSymbol<CcInt>())
);
cloudType = Pointcloud2::appendAttributesToCloud(newCloudType,
appendage);
}
// we want to return the input cloud-type with these two attributes appended
appendage = nl->TwoElemList(
nl->TwoElemList(nl->SymbolAtom("ObjID"),
listutils::basicSymbol<CcInt>()),
nl->TwoElemList(nl->SymbolAtom("CatID"),
listutils::basicSymbol<CcInt>()));
newCloudType = Pointcloud2::appendAttributesToCloud(cloudType,
appendage);
std::cout<<nl->ToString(newCloudType)<<endl;
//position of attributes ObjID and CatID
int pos = 0;
pos = nl->ListLength(
nl->Second(
Pointcloud2::getTupleType(newCloudType))) - 2;
return nl->ThreeElemList(
nl->SymbolAtom(Symbols::APPEND()),
nl->TwoElemList(nl->IntAtom(pos), nl->IntAtom(posIntensity)),
newCloudType);
}
/*
1.2 Value Mapping
*/
int op_analyzeRaster::analyzeRasterVM(Word *args, Word &result, int message,
Word &local, Supplier s)
{
result = qp->ResultStorage(s);
Pointcloud2 *res = static_cast<Pointcloud2 *>(result.addr);
Pointcloud2 *pc2Source =
static_cast<Pointcloud2 *>(args[0].addr);
//starting position of new attributes
CcInt *posAppend = static_cast<CcInt *>(args[1].addr);
const size_t pos = posAppend->GetIntval();
//position of intensity
const size_t posIntensity = static_cast<CcInt *>(args[2].addr)->GetIntval();
//calculate memory structure
const size_t maxMemory = qp->GetMemorySize(s) * 1024 * 1024;
const ListExpr resultType = GetTupleResultType(s);
op_analyzeRaster analyzeRaster(pc2Source, maxMemory,
pos, posIntensity, resultType);
//raster with overlapping OVERLAP
using namespace pointcloud2::analyzeRasterConstants;
//resize raster if complete pc2 fits in memory
double distX = analyzeRaster._bb.MaxD(0) - analyzeRaster._bb.MinD(0);
double distY = analyzeRaster._bb.MaxD(1) - analyzeRaster._bb.MinD(1);
{
//tie(distX, distY) = rasterSize;
if (analyzeRaster.getSizeRaster() > std::max(ceil(distX), ceil(distY)))
{
const int newSizeRaster = std::max(ceil(distX), ceil(distY));
analyzeRaster.setSizeRaster(newSizeRaster);
analyzeRaster.setSizeRasterOverlap(analyzeRaster.getSizeRaster());
const size_t newPointInMem = ceil(newSizeRaster /
Pointcloud2::CELL_SIZE_IN_M);
analyzeRaster.setPointInMem(newPointInMem);
}
}
analyzeRaster.setNeighbor(); analyzeRaster.setNeighborD();
//statistics about analyzeRaster
std::cout<<"Number of points of source pointcloud2: "
<<pc2Source->getPointCount()<<endl;
std::cout<<"Grid: "<<Pointcloud2::CELL_SIZE_IN_M<<", ";
std::cout<<"Point density in points/cell: "
<<pc2Source->getPointCount() /
((distX/Pointcloud2::CELL_SIZE_IN_M) *
(distY/Pointcloud2::CELL_SIZE_IN_M))<<endl;
Rectangle<3> bboxSource = pc2Source->getBoundingBox();
std::cout<<"Size of Pc2 in Grids: ";
std::cout<<(bboxSource.MaxD(0) - bboxSource.MinD(0)) /
Pointcloud2::CELL_SIZE_IN_M<<" x ";
std::cout<<(bboxSource.MaxD(1) - bboxSource.MinD(1)) /
Pointcloud2::CELL_SIZE_IN_M<<endl;
std::cout<<"Raster in Memory: "<<analyzeRaster._sizeRaster<<endl;
std::cout<<"Using "<<ceil((bboxSource.MaxD(0) - bboxSource.MinD(0)) /
analyzeRaster._sizeRasterOverlap)<<" x "
<<ceil((bboxSource.MaxD(1) - bboxSource.MinD(1)) /
analyzeRaster._sizeRasterOverlap)
<<" temporary rasters"<<endl;
//IDs/Bbox of persisted temporary rasters
std::vector<SmiFileId> rasters;
std::vector<Rect3> rastersBbox;
//build raster and calculate objects
try{
analyzeRaster.calculateObjects(rasters, rastersBbox);
}catch(const std::runtime_error&){
std::cout<<"error"<<endl;
return 0;
}
//classify objects and find double objects
std::shared_ptr<std::unordered_map<int,int>> duples =
std::make_shared<std::unordered_map<int,int>>();
std::shared_ptr<std::unordered_map<int,size_t>> classMap =
ARClassify::classify(rasters, rastersBbox,
analyzeRaster.getPointInMem(), duples);
//write pc2 back
analyzeRaster.saveRasterToPc2(rasters, rastersBbox, classMap, duples, res);
rastersBbox.clear();
rasters.clear();
if (local.addr)
{
local.addr = nullptr;
}
//DEBUG
std::cout<<"Number of points of result pointcloud2: "
<<res->getPointCount()<<endl;
return 0;
}
std::string op_analyzeRaster::getOperatorSpec()
{
return OperatorSpec(
" pointcloud2 -> pointcloud2(...,ObjID,CatID)",
" pc2 analyzeRaster ",
" Returns classified pc2 ",
" query pc2 analyzeRaster")
.getStr();
}
std::shared_ptr<Operator> op_analyzeRaster::getOperator()
{
return std::make_shared<Operator>("analyzeRaster",
getOperatorSpec(),
&op_analyzeRaster::analyzeRasterVM,
Operator::SimpleSelect,
&op_analyzeRaster::analyzeRasterTM);
}
/*
1.3 calculate objects
fill raster
compute objects
find local maxima, combine them to significant maxima
and split object by significant maxima
*/
void
op_analyzeRaster::calculateObjects(std::vector<SmiFileId>& rasters,
std::vector<Rect3>& rastersBbox) const{
std::tuple<double, double> &&xDimension = getXDimension();
std::tuple<double, double> &&yDimension = getYDimension();
int areaNumber = 0;
std::cout<<"Start calc Rasters: "<<endl;
std::cout<<"X: "<<floor(std::get<0>(xDimension))<<
"-"<<ceil(std::get<1>(xDimension))<<endl;
std::cout<<"Y: "<<floor(std::get<0>(yDimension))<<
"-"<<ceil(std::get<1>(yDimension))<<endl;
double y = std::get<0>(yDimension);
for (; y < std::get<1>(yDimension); y += _sizeRasterOverlap)
{
double x = std::get<0>(xDimension);
for (; x < std::get<1>(xDimension); x += _sizeRasterOverlap)
{
//calculate single raster partition
auto pc2RasterPart = calculateRasterRartition(x, y);
rastersBbox.push_back(pc2RasterPart->getBoundingBox());
//memory structure of raster partition
std::vector<RasterPoint> rasterMem =
fillrastermem(*pc2RasterPart, x, y);
//flooding & calculation ground & split
int maxObjectN = flooding(rasterMem, areaNumber, rastersBbox.back());
//init SMI file for temp raster
const bool makefixed = true;
const bool temporary = false;
SmiSize reclen = sizeof(RasterPointDB);
SmiRecordFile rf(makefixed, reclen, temporary);
if (rf.Create())
{
std::cout << "temporary SMI_Raster initialized" << endl;
}
else
{
std::cout << "error initializing temporary SMI_Raster" << endl;
throw std::runtime_error("error initializing temporary SMI_Raster");
}
rasters.push_back(rf.GetFileId());
//save raster partition to smi-file
size_t arrayCount = 0;
for (; arrayCount < _pointInMem2; arrayCount++)
{
SmiRecord r;
SmiRecordId rid;
RasterPoint bufferRM = rasterMem[arrayCount];
RasterPointDB buffer = structToSecondo(bufferRM);
rf.AppendRecord(rid, r);
r.Write(buffer);
}
rf.Close(rf.GetFileId());
areaNumber = maxObjectN;
}
}
}
/*
1.4 fill raster in memory
calculate raster points and their attributes
from partition of the pointcloud2 in memory raster
*/
std::vector<RasterPoint>
op_analyzeRaster::fillrastermem(Pointcloud2& pc2RasterPart, double x, double y)
const {
double grid_m = Pointcloud2::CELL_SIZE_IN_M;
//scan raster cell in pc2
PcPoint pcPoint;
SmiRecordFileIterator *it = pc2RasterPart.getFileIterator();
SmiRecord record;
std::vector<RasterPoint> rasterMem(_pointInMem2);
while (it->Next(record))
{
pc2RasterPart.getPoint(record.GetId(), &pcPoint);
//position in raster array
unsigned int partX = floor((pcPoint._x - x) / grid_m);
unsigned int partY = floor((pcPoint._y - y) / grid_m);
unsigned int arrayCount = partX + _pointInMem * partY;
if (partX >= _pointInMem || partY >= _pointInMem ||
partX < 0 || partY < 0){
continue;
}
rasterMem[arrayCount].objectID = -1;
rasterMem[arrayCount].classID = -1;
rasterMem[arrayCount].count++;
if (rasterMem[arrayCount].initialized)
{
if (rasterMem[arrayCount].minAlt > pcPoint._z)
{
rasterMem[arrayCount].minAlt = pcPoint._z;
}
}
else
{
rasterMem[arrayCount].minAlt = pcPoint._z;
}
if (rasterMem[arrayCount].initialized)
{
if (rasterMem[arrayCount].maxAlt < pcPoint._z)
{
rasterMem[arrayCount].maxAlt = pcPoint._z;
}
}
else
{
rasterMem[arrayCount].maxAlt = pcPoint._z;
}
rasterMem[arrayCount].averageAlt =
(rasterMem[arrayCount].averageAlt *
(rasterMem[arrayCount].count - 1) +
pcPoint._z) /
rasterMem[arrayCount].count;
if (_posIntensity > 0)
{
Tuple *elem = pc2RasterPart.getTuple(pcPoint._tupleId);
CcInt *intensityCcInt = (CcInt*) (elem->GetAttribute(_posIntensity - 1));
int intensity = intensityCcInt->GetValue();
rasterMem[arrayCount].averageIntensity =
(rasterMem[arrayCount].averageIntensity *
(rasterMem[arrayCount].count - 1) +
intensity) /
rasterMem[arrayCount].count;
elem->DeleteIfAllowed();
}
}
delete it;
//outside of pc2 initialized = false
Rect3 bboxPart = pc2RasterPart.getBoundingBox();
unsigned int partX = floor((bboxPart.MaxD(0) - x) / grid_m) + 1;
unsigned int partY = floor((bboxPart.MaxD(1) - y) / grid_m) + 1;
if (partX < _pointInMem)
{
for (unsigned int x = partX; x < _pointInMem; x++)
{
for (unsigned int y = 0; y < _pointInMem; y++)
{
unsigned int arrayCount = x + _pointInMem * y;
rasterMem[arrayCount].initialized = false;
}
}
}
if (partY < _pointInMem)
{
for (unsigned int arrayCount = _pointInMem * partY;
arrayCount < _pointInMem2; arrayCount++)
{
rasterMem[arrayCount].initialized = false;
}
}
return rasterMem;
}
/*
1.5 flooding
calculate objects by flooding
call methods
calculate local maxima
calculate significant maxima
split objects
*/
int
op_analyzeRaster::flooding(std::vector<RasterPoint>& rasterMem,
int areaNumber, const Rect3 rasterBbox) const{
//bbox of right and upper overlapping
const double offset = ceil(_sizeRasterOverlap / Pointcloud2::CELL_SIZE_IN_M);
Rect rightOverlap;
Rect upperOverlap;
double min[] = {offset, 0.0};
double max[] = {_pointInMem + 0., _pointInMem + 0.};
rightOverlap.Set(true, min, max);
min[0] = 0.0; min[1] = offset;
upperOverlap.Set(true, min, max);
bool xEdge = (rasterBbox.MaxD(0) >= _bb.MaxD(0));
bool yEdge = (rasterBbox.MaxD(0) >= _bb.MaxD(0));
//flooding
for (size_t arrayCount = 0; arrayCount < _pointInMem2;
arrayCount++)
{
if (rasterMem[arrayCount].objectID < 0 &&
rasterMem[arrayCount].initialized)
{
areaNumber++;
//ground turns false if one edge cell has lower neighbor
bool ground = true;
//edge turns 0 if object is open to edge min cells
size_t edge = Pointcloud2::MAX_CELLS_AT_EDGE;
double min[] = {(arrayCount % _pointInMem) + 0.,
(arrayCount / _pointInMem) + 0.};
double max[] = {(arrayCount % _pointInMem) + 0.,
(arrayCount / _pointInMem) + 0.};
Rect bboxObj;
bboxObj.Set(true, min, max);
size_t cellCount = 0;
std::stack<size_t> s;
s.emplace(arrayCount);
while (!s.empty())
{
size_t nF = s.top();
s.pop();
recalcBbox(bboxObj, nF);
++cellCount;
rasterMem[nF].objectID = areaNumber;
checkNeighbors(s, rasterMem, _neighbor, nF, ground, edge);
//also diagonal neighbors
if (_pc2->NEIGHBOUR_CELLS)
{
checkNeighbors(s, rasterMem, _neighborD, nF, ground, edge);
}
}
//ground? open to edge? fill objectID & classID with 0 for ground;
//objects up to 2 points are ground, too
const size_t min_ground = Pointcloud2::MIN_GROUND_CELLS;
if ((ground && (cellCount >= min_ground )) || edge == 0 || cellCount <= 2)
{
constexpr int areaNumberGround = 0;
deleteAreaNumber(rasterMem, areaNumber, bboxObj, areaNumberGround);
--areaNumber;
}
else if (cellCount < _pc2->MIN_OBJ_SIZE){
constexpr int areaNumberNoObj = -1;
deleteAreaNumber(rasterMem, areaNumber, bboxObj, areaNumberNoObj);
--areaNumber;
}
//erase double objects
else if ((!xEdge && rightOverlap.Contains(bboxObj)) ||
(!yEdge && upperOverlap.Contains(bboxObj)))
{
constexpr int areaNumberGround = 0;
deleteAreaNumber(rasterMem, areaNumber, bboxObj, areaNumberGround);
--areaNumber;
}
else
{
if (_pc2->SPLIT){
//find local maximum
int areaNumberM = calcLocMax(rasterMem, areaNumber, bboxObj);
//merge local maxima
calcEdgeForMerge(rasterMem, areaNumber, bboxObj);
//split object
splitObjects(rasterMem, areaNumber, bboxObj);
//start counting with max LocMax
areaNumber = areaNumberM;
}
}
}
}
return areaNumber;
}
/*
1.6 calculate local maxima in one object
*/
int
op_analyzeRaster::calcLocMax(std::vector<RasterPoint>& rasterMem,
int areaNumber, Rect bboxObj) const{
int areaNumberM= areaNumber;
//local maxima
for (size_t y = floor(bboxObj.MinD(1)); y <= ceil(bboxObj.MaxD(1)); y++){
for (size_t x = floor(bboxObj.MinD(0)); x <= ceil(bboxObj.MaxD(0)); x++){
size_t arrayCount = y * _pointInMem + x;
//test only cell being part of current object
if (rasterMem[arrayCount].objectID == areaNumber){
bool found = true;
size_t edge = 0;
++areaNumberM;
std::stack<size_t> s;
s.push(arrayCount);
double min[] = {x + 0., y + 0.};
double max[] = {x + 0., y + 0.};
Rect bboxLoc;
bboxLoc.Set(true, min, max);
size_t cellCount = 0;
while (!s.empty())
{
size_t nF = s.top();
recalcBbox(bboxLoc, nF);
s.pop();
++cellCount;
rasterMem[nF].objectID = areaNumberM;
checkNeighborsMaximum(s, rasterMem, _neighbor, nF,
found, edge, areaNumber);
//also diagonal neighbors
if (_pc2->NEIGHBOUR_CELLS)
{
size_t noCoundEdge;
checkNeighborsMaximum(s, rasterMem, _neighborD, nF,
found, noCoundEdge, areaNumber);
}
//no local maximum or nearly complete object is local maximum
if (!found){
//delete stack
std::stack<size_t> e;
swap(e,s);
}
}
if (!found || edge <= analyzeRasterConstants::MIN_NEIGBOR_LOC_MAX ||
analyzeRasterConstants::LOC_MAX_NEARLY_OBJ * bboxObj.Area()
<= bboxLoc.Area() || cellCount < _pc2->MIN_LOC_MAX_SIZE)
{
deleteAreaNumber(rasterMem, areaNumberM, bboxLoc, areaNumber);
--areaNumberM;
}
}
}//end for
}//end for
return areaNumberM;
}
/*
1.7 calculate edge cells of local maxima
and call method for merging local maxima to significant maximum
*/
void
op_analyzeRaster::calcEdgeForMerge(std::vector<RasterPoint>& rasterMem,
int areaNumber, Rect bboxObj) const{
for (size_t y = floor(bboxObj.MinD(1)); y <= ceil(bboxObj.MaxD(1)); y++){
for (size_t x = floor(bboxObj.MinD(0)); x <= ceil(bboxObj.MaxD(0)); x++){
size_t arrayCount = y * _pointInMem + x;
if (rasterMem[arrayCount].objectID > areaNumber){
//test only edge points of local maxima
constexpr int arraySize = 4;
bool edge = false;
for (int i = 0; i < arraySize; ++i)
{
size_t arrayCountNew = _neighbor[i] + arrayCount;
size_t xNew = arrayCountNew % _pointInMem;
if (arrayCountNew >= 0 && arrayCountNew < _pointInMem2 &&
xNew < _pointInMem && rasterMem[arrayCountNew].objectID !=
rasterMem[arrayCount].objectID &&
rasterMem[arrayCountNew].objectID >= areaNumber){
edge = true;
}
}
//test for local maximum
if (edge){
//compute merge with Horn algorithm for circles
//fill gap with Gift-Wrapping algorithm (convex hull)
mergeLocMax(rasterMem, arrayCount, areaNumber);
}
}
}
}
}
/*
1.8 split objects by significant maxima
*/
void
op_analyzeRaster::splitObjects(std::vector<RasterPoint>& rasterMem,
int areaNumber, Rect bboxObj) const{
constexpr int arraySize = 4;
//data structure for edge points of local maxima and directions to expand
std::vector<std::tuple<size_t, int>> edgePoints;
do{
//fill vector
edgePoints.clear();
for (size_t y = floor(bboxObj.MinD(1)); y <= ceil(bboxObj.MaxD(1)); y++)
{
for (size_t x = floor(bboxObj.MinD(0)); x <= ceil(bboxObj.MaxD(0)); x++)
{
size_t arrayCount = y * _pointInMem + x;
//cell of local maximum
if (rasterMem[arrayCount].objectID > areaNumber){
for (size_t i = 0; i < arraySize; i++)
{
int nCell = _neighbor[i] + arrayCount;
size_t nCellX = nCell % _pointInMem;
size_t nCellY = nCell / _pointInMem;
if (nCellX < _pointInMem && nCellY < _pointInMem &&
rasterMem[nCell].objectID == areaNumber &&
(rasterMem[nCell].maxAlt < rasterMem[arrayCount].maxAlt ||
testForOtherMin(rasterMem, arrayCount,
_neighbor[i], areaNumber)))
{
edgePoints.emplace_back(arrayCount, _neighbor[i]);
}
nCell = _neighborD[i] + arrayCount;
nCellX = nCell % _pointInMem;
nCellY = nCell / _pointInMem;
if (nCellX < _pointInMem && nCellY < _pointInMem &&
rasterMem[nCell].objectID == areaNumber)
{
//diagonal only pointed corners
int bi = (i == 0) ? 3 : (i - 1);
int ai = i;
if (_neighbor[ai] + arrayCount < _pointInMem2 &&
_neighbor[bi] + arrayCount < _pointInMem2 &&
rasterMem[_neighbor[bi] + arrayCount].objectID -
rasterMem[_neighbor[ai] + arrayCount].objectID == 0 &&
(rasterMem[nCell].maxAlt < rasterMem[arrayCount].maxAlt ||
testForOtherMin(rasterMem, arrayCount,
_neighbor[i], areaNumber)))
{
edgePoints.emplace_back(arrayCount, _neighborD[i]);
}
}
}
}
}
}
//increase local maxima to find split lines
for (size_t i = 0; i < edgePoints.size(); i++)
{
size_t cellOld = std::get<0>(edgePoints[i]);
int xNew = std::get<1>(edgePoints[i])
+ std::get<0>(edgePoints[i]) % _pointInMem;
int yNew = std::get<1>(edgePoints[i])
+ std::get<0>(edgePoints[i]) / _pointInMem;
size_t cellNew = std::get<1>(edgePoints[i]) + std::get<0>(edgePoints[i]);
if ((xNew < 0 && xNew >= (int)_pointInMem &&
yNew < 0 && yNew >= (int)_pointInMem )||
rasterMem[cellNew].objectID != areaNumber)
{
edgePoints.erase(edgePoints.begin() + i);
}
else
{
if (rasterMem[cellNew].objectID == areaNumber){
rasterMem[cellNew].objectID = rasterMem[cellOld].objectID;
}
}
}
}while (!edgePoints.empty());
}
/*
1.9 test for other minimum
test if between count and other locale maximum lower minimum
or if reaching the edge
true if found
*/
bool
op_analyzeRaster::testForOtherMin(std::vector<RasterPoint>& rasterMem,
size_t arrayCount, int neighbor, int areaNumber) const{
bool found = false;
int count = 1;
double firstMin = rasterMem[arrayCount].maxAlt;
while (!found &&
arrayCount + count * neighbor < _pointInMem2 &&
rasterMem[arrayCount +
count * neighbor].objectID <= areaNumber)
{
if (rasterMem[arrayCount +
count * neighbor].maxAlt <= firstMin ||
rasterMem[arrayCount +
(count) * neighbor].objectID <= 0){
found = true;
}
++count;
}
return found;
}
void
op_analyzeRaster::checkNeighbors(std::stack<size_t>& s,
std::vector<RasterPoint>& rasterMem,
std::vector<int> neighbor, size_t nF, bool& ground, size_t& edge) const{
const double delta_alt = _pc2->DELTA_ALT_IN_M;
constexpr int arraySize = 4;
for (int i = 0; i < arraySize; i++)
{
int nN = neighbor[i] + nF;
const int x = nN % _pointInMem;
const int y = nN / _pointInMem;
if (x >= 0 && x < (int)_pointInMem &&
y >= 0 && y < (int)_pointInMem && rasterMem[nN].initialized)
{
const auto absAverange = std::abs(rasterMem[nN].maxAlt -
rasterMem[nF].maxAlt);
if (rasterMem[nN].objectID < 0 &&
absAverange < delta_alt)
{
s.emplace(nN);
}
//ground: neighbor of edge cell must not be lower altitude
else {
if ((rasterMem[nF].maxAlt - rasterMem[nN].maxAlt)
> delta_alt)
{
ground = false;
}
}
}
else{
//objects open to edge are ground if more the EDGE_MAX edge cells
if (edge >= 1){
--edge;
}
}
}
}
/*
1.12 check neighbor cells for flooding to find local maxima
definition for new neighbor cell
is part of object and all cells have same height roughly
is higher than all neighbor cells
has minimum of three neighbor cells
*/
void
op_analyzeRaster::checkNeighborsMaximum(std::stack<size_t>& s,
std::vector<RasterPoint>& rasterMem, std::vector<int> neighbor,
size_t nF, bool& found, size_t& edge, int const areaNumber) const{
const double threshold_loc = _pc2->THRESHOLD_MERGE;
constexpr int arraySize = 4;
for (int i = 0; i < arraySize; i++)
{
int nN = neighbor[i] + nF;
int x = nN % _pointInMem;
int y = nN / _pointInMem;
if (x >= 0 && x < (int)_pointInMem && y >= 0 && y < (int)_pointInMem &&
rasterMem[nN].objectID == areaNumber)
{
const auto absAverange = std::abs(rasterMem[nN].maxAlt -
rasterMem[nF].maxAlt);
if (absAverange <= threshold_loc)
{
s.push(nN);
}
//local max are higher than all neighbours
else {
++ edge;
if ((rasterMem[nF].maxAlt - rasterMem[nN].maxAlt)
< 0)
{
found = false;
}
}
}
}
}
/*
1.13 delete object
overwrite one areaNumber with other areaNumber
*/
void
op_analyzeRaster::deleteAreaNumber(std::vector<RasterPoint>& rasterMem,
int areaNumber, Rect bboxLoc, int areaNumberOld) const{
for (size_t y = floor(bboxLoc.MinD(1)); y <= ceil(bboxLoc.MaxD(1)); y++){
for (size_t x = floor(bboxLoc.MinD(0)); x <= ceil(bboxLoc.MaxD(0)); x++){
size_t arrayCount = y * _pointInMem + x;
if (rasterMem[arrayCount].objectID == areaNumber){
rasterMem[arrayCount].objectID = areaNumberOld;
}
}
}
}
/*
1.14 merge local maxima
*/
void op_analyzeRaster::mergeLocMax(std::vector<RasterPoint>& rasterMem,
size_t const arrayCount, int const areaNumber) const{
const int areaNumberLocMax = rasterMem[arrayCount].objectID;
//initialize data structure for all points to be merged with local maximum
std::vector<std::pair <size_t,size_t>> newLocMax =
fillVectorWithLocMax(rasterMem, arrayCount);
bool countLocMax =
calcNearLocMaxByHorn(rasterMem, arrayCount, areaNumber, newLocMax);
//fill gap by Gift-Wrapping algorithm (convex hull)
if (countLocMax){
std::vector<std::pair <size_t,size_t>> hullLocMax =
calcConvexHull(newLocMax);
//fill convex hull to compute significant maximum by edge list algorithm
fillConvexHull(rasterMem, hullLocMax, areaNumberLocMax);
}
}
/*
1.15 fill vector with local maxima
preparation for calculating convex hull
*/
std::vector<std::pair <size_t,size_t>>
op_analyzeRaster::fillVectorWithLocMax(std::vector<RasterPoint>& rasterMem,
size_t const arrayCount) const{
const int areaNumberLocMax = rasterMem[arrayCount].objectID;
const size_t x_0 = arrayCount % _pointInMem;
const size_t y_0 = arrayCount / _pointInMem;
//data structure for all points of merged locMax
std::vector<std::pair <size_t,size_t>> newLocMax;
newLocMax.emplace_back(x_0, y_0);
bool foundP;
int delta = 0;
do
{
++delta;
foundP = false;
for (int i = - delta; i <= + delta; i++){
size_t count;
if ((((int)x_0 + i) >= 0) && ((x_0 + i) < _pointInMem)){
if ((y_0 + delta) < _pointInMem){
count = (y_0 + delta) * _pointInMem + (x_0 + i);
if (rasterMem[count].objectID == areaNumberLocMax){
newLocMax.emplace_back(x_0 + i, y_0 + delta);
foundP = true;
}
}
if (((int)y_0 - delta) >= 0){
count = (y_0 - delta) * _pointInMem + (x_0 + i);
if (rasterMem[count].objectID == areaNumberLocMax){
newLocMax.emplace_back(x_0 + i, y_0 - delta);
foundP = true;
}
}
}
//no double corners
if (delta != abs(i) && (((int)y_0 + i) >= 0)
&& ((y_0 + i) < _pointInMem)){
if ((x_0 + delta) < _pointInMem){
count = (y_0 + i) * _pointInMem + (x_0 + delta);
if (rasterMem[count].objectID == areaNumberLocMax){
newLocMax.emplace_back(x_0 + delta, y_0 + i);
foundP = true;
}
}
if (((int)x_0 - delta) >= 0){
count = (y_0 + i) * _pointInMem + (x_0 - delta);
if (rasterMem[count].objectID == areaNumberLocMax){
newLocMax.emplace_back(x_0 - delta, y_0 + i);
foundP = true;
}
}
}
}//end for
}//end do
while (foundP);
return newLocMax;
}
/*
1.16 add local maximum to be merged to vector
preparation for calculating convex hull
*/
void
op_analyzeRaster::fillVectorWithOtherLocMax(std::vector<RasterPoint>& rasterMem,
const size_t arrayCount, const int areaNumberLocMax,
std::vector<std::pair <size_t,size_t>>& newLocMax) const{
const int areaNumberLocMaxOther = rasterMem[arrayCount].objectID;
const size_t x_0 = arrayCount % _pointInMem;
const size_t y_0 = arrayCount / _pointInMem;
newLocMax.emplace_back(x_0, y_0);
rasterMem[arrayCount].objectID = areaNumberLocMax;
bool foundP;
int delta = 0;
do
{
++delta;
foundP = false;
for (int i = - delta; i <= + delta; i++){
size_t count;
if ((((int)x_0 + i) >= 0) && ((x_0 + i) < _pointInMem)){
if ((y_0 + delta) < _pointInMem){
count = (y_0 + delta) * _pointInMem + (x_0 + i);
if (rasterMem[count].objectID == areaNumberLocMaxOther){
newLocMax.emplace_back(x_0 + i, y_0 + delta);
rasterMem[count].objectID = areaNumberLocMax;
foundP = true;
}
}
if (((int)y_0 - delta) >= 0){
count = (y_0 - delta) * _pointInMem + (x_0 + i);
if (rasterMem[count].objectID == areaNumberLocMaxOther){
newLocMax.emplace_back(x_0 + i, y_0 - delta);
rasterMem[count].objectID = areaNumberLocMax;
foundP = true;
}
}
}
//no double corners
if (delta != abs(i) && (((int)y_0 + i) >= 0)
&& ((y_0 + i) < _pointInMem)){
if ((x_0 + delta) < _pointInMem){
count = (y_0 + i) * _pointInMem + (x_0 + delta);
if (rasterMem[count].objectID == areaNumberLocMaxOther){
newLocMax.emplace_back(x_0 + delta, y_0 + i);
rasterMem[count].objectID = areaNumberLocMax;
foundP = true;
}
}
if (((int)x_0 - delta) >= 0){
count = (y_0 + i) * _pointInMem + (x_0 - delta);
if (rasterMem[count].objectID == areaNumberLocMaxOther){
newLocMax.emplace_back(x_0 - delta, y_0 + i);
rasterMem[count].objectID = areaNumberLocMax;
foundP = true;
}
}
}
}//end for
}//end do
while (foundP);
}
/*
1.17 compute local maxima to be merged
by Horn algorithm for drawing circles
Horn algorithm is a derivation of Bresenham
*/
bool
op_analyzeRaster::calcNearLocMaxByHorn(std::vector<RasterPoint>& rasterMem,
size_t const arrayCount, int const areaNumber,
std::vector<std::pair <size_t,size_t>>& newLocMax) const{
bool countLocMax = false;
//max. distance next local maximum in cells
const int r = ceil(_pc2->DISTANCE_SIG_MAXIMA
/ _pc2->CELL_SIZE_IN_M);
const int areaNumberLocMax = rasterMem[arrayCount].objectID;
const int x_0 = arrayCount % _pointInMem;
const int y_0 = arrayCount / _pointInMem;
int x = 0;
int y = r;
//test in x direction -R, R
testOtherLocMax(rasterMem, ((x_0 - r < 0) ? 0 : (size_t)(x_0 - r)),
(((size_t)(x_0 + r) > _pointInMem) ? _pointInMem : (size_t)(x_0 + r)),
(size_t)y_0, areaNumber, areaNumberLocMax, countLocMax, newLocMax);
//test y = R, -R
if (y_0 - r >= 0){
size_t arrayCount = (size_t)(x_0 + (y_0 - r) * _pointInMem);
if (rasterMem[arrayCount].objectID > areaNumber
&& rasterMem[arrayCount].objectID != areaNumberLocMax){
rasterMem[arrayCount].objectID = areaNumberLocMax;
countLocMax = true;
newLocMax.emplace_back((size_t)x_0, (size_t)(y_0 - r));
}
}
if ((size_t)(y_0 + r) < _pointInMem){
size_t arrayCount = (size_t)(x_0 + (y_0 + r) * _pointInMem);
if (rasterMem[arrayCount].objectID > areaNumber
&& rasterMem[arrayCount].objectID != areaNumberLocMax){
rasterMem[arrayCount].objectID = areaNumberLocMax;
countLocMax = true;
newLocMax.emplace_back((size_t)x_0, (size_t)(y_0 + r));
}
}
int f = 1 - r;
while (x < y){
++x;
if (f < 0){
f += 2 * x -1;
} else{
f += 2 * (x - y);
--y;
}
//four tests for computed lines in x direction in circle (r)
if ((size_t)(y + y_0) < _pointInMem){
testOtherLocMax(rasterMem,
(((x + x_0 - r) < 0) ? 0 : (size_t)(x + x_0 - r)),
(((size_t)(x + x_0 + r) > _pointInMem)
? _pointInMem : (size_t)(x + x_0 + r)),
(size_t)(y + y_0),
areaNumber, areaNumberLocMax, countLocMax, newLocMax);
}
if ((y_0 - y) >= 0){
testOtherLocMax(rasterMem,
(((x_0 + x - r) < 0) ? 0 : (size_t)(x_0 + x - r)),
(((size_t)(x_0 + x + r) > _pointInMem)
? _pointInMem : (size_t)(x_0 + x + r)),
(size_t)(y_0 - y),
areaNumber, areaNumberLocMax, countLocMax, newLocMax);
}
if ((size_t)(x + y_0) < _pointInMem){
testOtherLocMax(rasterMem,
(((y + x_0 - r) < 0) ? 0 : (size_t)(y + x_0 - r)) ,
(((size_t)(y + x_0 + r) > _pointInMem)
? _pointInMem : (size_t)(y + x_0 + r)),
(size_t)(x + y_0),
areaNumber, areaNumberLocMax, countLocMax, newLocMax);
}
if ((y_0 - x) >= 0){
testOtherLocMax(rasterMem,
(((y + x_0 - r) < 0) ? 0 : (size_t)(y+ x_0 - r)),
(((size_t)(y + x_0 + r) > _pointInMem)
? _pointInMem : (size_t)(y + x_0 + r)),
(size_t)(y_0 - x),
areaNumber, areaNumberLocMax, countLocMax, newLocMax);
}
}
return countLocMax;
}
/*
1.18 calculate convex hull
by Gift Wrapping algorithm
to merge local maxima to significant maximum
*/
std::vector<std::pair <size_t,size_t>>
op_analyzeRaster::calcConvexHull(
const std::vector<std::pair <size_t,size_t>> newLocMax) const{
//leftmost point
size_t firstpoint = 0;
size_t yFirst = newLocMax[0].second;
size_t n = newLocMax.size();
bool sameY = true;
for (size_t i = 0; i < n; i++){
if ((std::get<0>(newLocMax[i]) < std::get<0>(newLocMax[firstpoint]))){
firstpoint = i;
} else if (((std::get<0>(newLocMax[i]) ==
std::get<0>(newLocMax[firstpoint])))
&& (std::get<1>(newLocMax[i]) < std::get<1>(newLocMax[firstpoint]))){
firstpoint = i;
}
if (newLocMax[i].second != yFirst){
sameY = false;
}
}
std::vector<std::pair <size_t,size_t>> hullLocMax;
if (!sameY && n > 3){
size_t current = firstpoint;
hullLocMax.emplace_back(newLocMax[firstpoint].first,
newLocMax[firstpoint].second);
std::vector<size_t> collinear;
size_t nextTarget;
while (true) {
nextTarget = 0;
for (size_t i = 0; i < n; i++){
if (i == current){
continue;
}
int orientation =
((int)newLocMax[current].second
- (int)newLocMax[i].second) *
((int)newLocMax[current].first
- (int)newLocMax[nextTarget].first) -
((int)newLocMax[current].first
- (int)newLocMax[i].first) *
((int)newLocMax[current].second
- (int)newLocMax[nextTarget].second);
if (orientation > 0){
nextTarget = i;
collinear.clear();
}
else if (orientation == 0)
{
if(distanceComp(newLocMax[current],
newLocMax[nextTarget], newLocMax[i]) < 0) {
collinear.push_back(nextTarget);
nextTarget = i;
}else{
collinear.push_back(i);
}
}
}
for (auto coll : collinear){
hullLocMax.emplace_back(newLocMax[coll].first, newLocMax[coll].second);
}
if (nextTarget == firstpoint){
break;
}
hullLocMax.emplace_back(newLocMax[nextTarget].first,
newLocMax[nextTarget].second);
current = nextTarget;
}
hullLocMax.emplace_back(newLocMax[nextTarget].first,
newLocMax[nextTarget].second);
}
else
{
for (size_t i = 0; i < newLocMax.size(); i++){
hullLocMax.emplace_back(std::get<0>(newLocMax[i]),
std::get<1>(newLocMax[i]));
}
hullLocMax.emplace_back(std::get<0>(newLocMax[0]),
std::get<1>(newLocMax[0]));
}
return hullLocMax;
}
int op_analyzeRaster::distanceComp(std::pair <size_t,size_t> a,
std::pair <size_t,size_t> b,
std::pair <size_t,size_t> c) const{
int y1 = (int)a.second - b.second;
int y2 = (int)a.second - c.second;
int x1 = (int)a.first - b.first;
int x2 = (int)a.first - c.first;
int item1 = (y1*y1 + x1*x1);
int item2 = (y2*y2 + x2*x2);
if(item1 == item2)
return 0; //when b and c are in same distance from a
else if(item1 < item2)
return -1; //when b is closer to a
return 1; //when c is closer to a
}
/*
1.19 fill convex hull
to compute significant maximum by edge list algorithm
*/
void
op_analyzeRaster::fillConvexHull(std::vector<RasterPoint>& rasterMem,
std::vector<std::pair <size_t,size_t>> hullLocMax,
const int areaNumberLocMax) const{
//compute edge list
std::vector<std::pair <size_t,size_t>> edgeList;
for (size_t i = 0; i < hullLocMax.size() - 1; i++){
bool calc = computeEdgeLine(edgeList, hullLocMax[i], hullLocMax[i+1]);
//in y-increasing or decreasing segments no double points
if (calc){
size_t posPlus = i + 1;
size_t posPlusPlus = ((posPlus + 1) < hullLocMax.size()) ? posPlus +1 : 1;
int deltaSeg1 = (int) hullLocMax[i].second
- (int) hullLocMax[posPlus].second;
int deltaSeg2 = (int) hullLocMax[posPlus].second
- (int) hullLocMax[posPlusPlus].second;
if ((deltaSeg1 > 0 && deltaSeg2 > 0) ||
(deltaSeg1 < 0 && deltaSeg2 < 0))
{
edgeList.pop_back();
}
else
{
while (deltaSeg2 == 0)
{
posPlusPlus = ((posPlusPlus + 1) < hullLocMax.size()) ?
posPlusPlus +1 : 1;
deltaSeg2 = (int) hullLocMax[posPlus].second
- (int) hullLocMax[posPlusPlus].second;
}
if ((deltaSeg1 > 0 && deltaSeg2 > 0) ||
(deltaSeg1 < 0 && deltaSeg2 < 0)){
edgeList.pop_back();
}
}
}
}
//sort by y and when equal by x
std::sort(edgeList.begin(), edgeList.end(),
[](const std::pair<size_t, size_t> &a,
const std::pair<size_t, size_t> &b)
{if (a.second == b.second){
return (a.first < b.first);
}
return (a.second > b.second);});
//fill points between pairs with same y in x direction
for (size_t i = 0; i < edgeList.size(); i += 2)
{
assert(edgeList[i].first <= edgeList[i+1].first);
for (size_t x = edgeList[i].first;
x <= edgeList[i+1].first; ++x)
{
size_t arrayCount = edgeList[i].second * _pointInMem + x;
rasterMem[arrayCount].objectID = areaNumberLocMax;
}
}
}
/*
1.20 test for new local maximum
in distance of central local maxima and flood
*/
void
op_analyzeRaster::testOtherLocMax(std::vector<RasterPoint>& rasterMem,
size_t const xMin, size_t const xMax, size_t const y,
const int areaNumberObj, const int areaNumberLocMax,
bool& countLocMax, std::vector<std::pair <size_t,size_t>>& newLocMax) const{
const size_t arrayCountMin = xMin + y * _pointInMem;
const size_t arrayCountMax = xMax + y * _pointInMem;
for (size_t i = arrayCountMin; i <= arrayCountMax; i++){
int areaNumberLocMax2 = rasterMem[i].objectID;
if (areaNumberLocMax2 > areaNumberObj
&& areaNumberLocMax2 != areaNumberLocMax){
countLocMax = true;
//flood merged locMax by areaNumberLocMax
fillVectorWithOtherLocMax(rasterMem, i, areaNumberLocMax, newLocMax);
}
}
}
/*
1.21 calculating points in edge line of convex hull
ignores horizontal lines
*/
bool
op_analyzeRaster::computeEdgeLine(
std::vector<std::pair <size_t,size_t>> &edgeList,
const std::pair<size_t, size_t> a,
const std::pair<size_t, size_t> b) const{
//ignore horizontal lines
if (a.second != b.second)
{
if (a.first != b.first)
{
int x1 = (int)a.first; int y1 = (int)a.second;
int x2 = (int)b.first; int y2 = (int)b.second;
if (y1 < y2){
for (int y = y1; y <= y2; y++)
{
double m = (x2 - x1 + 0.) / (y2 - y1 + 0.);
double n = (y1 * x2 - y2 * x1 + 0.) / (x2 - x1 + 0.);
int x = rint(m * (y - n));
edgeList.emplace_back(std::make_pair((size_t) x, (size_t) y));
}
}
else
{
for (int y = y1; y >= y2; y--)
{
double m = (x2 - x1 + 0.) / (y2 - y1 + 0.);
double n = (y1 * x2 - y2 * x1 + 0.) / (x2 - x1 + 0.);
int x = m * (y - n);
edgeList.emplace_back(std::make_pair((size_t) x, (size_t) y));
}
}
return true;
}
else
{
if (a.second < b.second){
for (size_t y = a.second; y <= b.second; y++)
{
edgeList.emplace_back(std::make_pair(a.first, y));
}
}
else
{
for (size_t y = a.second; y >= b.second; y--)
{
edgeList.emplace_back(std::make_pair(a.first, y));
}
}
return true;
}
}
return false;
}
/*
1.22 write back raster to pointcloud2
*/
void
op_analyzeRaster::saveRasterToPc2(std::vector<SmiFileId>& rasters,
std::vector<Rect3> rastersBbox,
std::shared_ptr<std::unordered_map<int,size_t>> classMap,
std::shared_ptr<std::unordered_map<int,int>> duples,
Pointcloud2* res) const{
std::cout<<"Reading "<<rasters.size()<<" temporary rasters"<<endl;
if (Pointcloud2::GET_RASTER_NOT_PC) {
res->startInsert();
TupleType *tt = new TupleType(nl->Second(nl->Second(_resultType)));
cout<<"pointcloud rastercount should be:"
<<std::to_string(rasters.size()*_pointInMem2)<<endl;
//_pc2->clear();
for (size_t i = 0; i < rasters.size(); i++)
{
//open tempRaster
SmiFileId tempRasterId = rasters[i];
std::cout << "Loading temporary raster: " << tempRasterId << endl;
//vector<RasterPoint> rasterMem(_pointInMem2);
RasterPoint rasterMem;
const bool makefixed = true;
const bool temporary = false;
SmiSize reclen = sizeof(RasterPointDBSave);
SmiRecordFile rf(makefixed, reclen, temporary);
if (rf.Open(tempRasterId))
{
SmiRecordId rid = 1;
RasterPointDB bufferDB;
size_t arrayCount = 0;
const Rectangle<3>& fileBbox = rastersBbox[i];
const int rasterOffsetX = floor(
fileBbox.MinD(0) / Pointcloud2::CELL_SIZE_IN_M);
const int rasterOffsetY = floor(
fileBbox.MinD(1) / Pointcloud2::CELL_SIZE_IN_M);
PcPoint point;
for (; arrayCount < _pointInMem2; arrayCount++)
{
SmiRecord record;
rf.SelectRecord(rid, record, SmiFile::ReadOnly);
record.Read(&bufferDB, reclen);
rasterMem = secondoToStruct(bufferDB);
Tuple *elem = new Tuple(tt);
elem->PutAttribute(0, new CcInt(rasterMem.count));
elem->PutAttribute(1, new CcReal(rasterMem.minAlt));
elem->PutAttribute(2, new CcReal(rasterMem.maxAlt));
elem->PutAttribute(3, new CcReal(rasterMem.averageAlt));
elem->PutAttribute(4, new CcInt(rasterMem.averageIntensity));
elem->PutAttribute(5, new CcInt(rasterMem.objectID));
int classID = 0;
if (rasterMem.objectID!=0)
try {
classID = classMap.get()->at(rasterMem.objectID);
} catch(std::exception &e) {
}
elem->PutAttribute(6, new CcInt(classID));
point._x = ((arrayCount % _pointInMem) + 0.) +
rasterOffsetX;
point._y = ((arrayCount / _pointInMem) + 0.) +
rasterOffsetY;
point._z = rasterMem.averageAlt;
res->insert(point, elem);
++rid;
}
}
rf.Close(tempRasterId);
rf.Drop();
}
res->finalizeInsert();
tt->DeleteIfAllowed();
return;
}
else
{
//horizontal overlapping
std::vector <RasterPointSave> rasterOverlapH;
//two vertical lines of overlapping
std::vector<std::vector<RasterPointSave>> rasterOverlapUnder;
std::vector<std::vector<RasterPointSave>> rasterOverlapUnderEdge;
std::vector<std::vector<RasterPointSave>> rasterOverlapOver;
std::vector<std::vector<RasterPointSave>> rasterOverlapOverEdge;
res->startInsert();
for (size_t i = 0; i < rasters.size(); i++)
{
//open tempRaster
SmiFileId tempRasterId = rasters[i];
std::cout << "Loading temporary raster: " << tempRasterId << endl;
std::vector<RasterPointSave> rasterMem(_pointInMem2);
const bool makefixed = true;
const bool temporary = false;
SmiSize reclen = sizeof(RasterPointDBSave);
SmiRecordFile rf(makefixed, reclen, temporary);
//size_t arrayCount = 0;
if (rf.Open(tempRasterId))
{
SmiRecordId rid = 1;
RasterPointDBSave bufferDB;
//RasterPointSave buffer;
size_t arrayCount = 0;
for (; arrayCount < rasterMem.size(); arrayCount++)
{
SmiRecord record;
rf.SelectRecord(rid, record, SmiFile::ReadOnly);
record.Read(&bufferDB, reclen);
rasterMem[arrayCount] = secondoToStructSave(bufferDB);
++rid;
}
}
rf.Close(tempRasterId);
rf.Drop();
if (rasters.size() > 1)
{
recalcOverlapping(rasterMem, rastersBbox[i], i, duples,
rasterOverlapH, rasterOverlapUnder, rasterOverlapUnderEdge,
rasterOverlapOver, rasterOverlapOverEdge);
}
//calculate part of raster rartition to write in this pass
double xMin = rastersBbox[i].MinD(0);
double yMin = rastersBbox[i].MinD(1);
double xMax = rastersBbox[i].MaxD(0);
double yMax = rastersBbox[i].MaxD(1);
double overlapXMax = (xMax < _bb.MaxD(0)) ?
(xMin + _sizeRasterOverlap) : xMax;
double overlapYMax = (yMax < _bb.MaxD(1)) ?
(yMin + _sizeRasterOverlap) : yMax;
double min[] = {xMin, yMin, rastersBbox[i].MinD(2)};
double max[] = {overlapXMax, overlapYMax, rastersBbox[i].MaxD(2)};
Rect3 rasterBbox;
rasterBbox.Set(true, min, max);
//load pc2-source with bbox of actual partition
auto pc2RasterPart = calculateRasterRartition(rasterBbox);
//save to pc2
PcPoint pcPoint;
SmiRecordFileIterator *it;
it = pc2RasterPart->getFileIterator();
SmiRecord record;
while (it->Next(record))
{
savePoint(res, *pc2RasterPart, rastersBbox[i],
record, pcPoint, rasterMem, classMap);
}
delete it;
std::cout << "save to pc2, pass " << i + 1 <<endl;
}
res->finalizeInsert();
}
}
/*
1.23 write points to pc2
with ObjectID and ClassID
*/
void op_analyzeRaster::savePoint(Pointcloud2* res,
const Pointcloud2& rasterPart,
const Rect3 rasterBbox,
const SmiRecord& record,
PcPoint& pcPoint,
std::vector<RasterPointSave> const &rasterMem,
std::shared_ptr<std::unordered_map<int,size_t>> classMap) const{
const double grid_m = Pointcloud2::CELL_SIZE_IN_M;
double x = rasterBbox.MinD(0);
double y = rasterBbox.MinD(1);
rasterPart.getPoint(record.GetId(), &pcPoint);
//position in raster array
unsigned int partX = floor((pcPoint._x - x) / grid_m);
unsigned int partY = floor((pcPoint._y - y) / grid_m);
unsigned int arrayCount = partX + _pointInMem * partY;
if (partX < _pointInMem && partY < _pointInMem &&
partX >= 0 && partY >= 0)
{
TupleType *tt = new TupleType(nl->Second(nl->Second(_resultType)));
Tuple *elem = new Tuple(tt);
//pc2 with attributes? then copy
if (getPositionNewAttributes() > 0)
{
Tuple *elemSrc = rasterPart.getTuple(pcPoint._tupleId);
for (size_t i = 0; i < getPositionNewAttributes(); i++)
{
elem->CopyAttribute(i, elemSrc, i);
}
elemSrc->DeleteIfAllowed();
}
const int objectID = rasterMem[arrayCount].objectID;
elem->PutAttribute(getPositionNewAttributes(),
new CcInt(objectID));
int classID = 0;
if (objectID!=0)
try {
classID = classMap.get()->at(objectID);
} catch(std::exception &e) {
}
elem->PutAttribute(getPositionNewAttributes() + 1,
new CcInt(classID));
res->insert(pcPoint, elem);
tt->DeleteIfAllowed();
}
}
/*
1.24 erase double objects in overlappings
using memory structure for overlappings tested in other raster partitions
*/
void
op_analyzeRaster::recalcOverlapping(std::vector<RasterPointSave> &rasterMem,
const Rect3 rasterBbox, const size_t i,
const std::shared_ptr<std::unordered_map<int,int>> duples,
std::vector <RasterPointSave> &rasterOverlapH,
std::vector<std::vector<RasterPointSave>> &rasterOverlapUnder,
std::vector<std::vector<RasterPointSave>> &rasterOverlapUnderEdge,
std::vector<std::vector<RasterPointSave>> &rasterOverlapOver,
std::vector<std::vector<RasterPointSave>> &rasterOverlapOverEdge) const{
//structure for overlapping
Rect3 bboxSource = _pc2->getBoundingBox();
const size_t rastersInX = ceil((bboxSource.MaxD(0) - bboxSource.MinD(0)) /
_sizeRasterOverlap);
const size_t rastersInY = ceil((bboxSource.MaxD(1) - bboxSource.MinD(1)) /
_sizeRasterOverlap);
const unsigned int offset = _sizeRaster - _sizeRasterOverlap;
const unsigned int overlapRXMin =
ceil(offset / Pointcloud2::CELL_SIZE_IN_M);
const unsigned int overlapRXMax =
_pointInMem - overlapRXMin -1;
const unsigned int overlapRYMin =
ceil(offset / Pointcloud2::CELL_SIZE_IN_M);
const unsigned int overlapRYMax =
_pointInMem - overlapRYMin -1;
//test for objects in saved overlapping
//horizontal line under no edge
if (i / rastersInX > 0)
{
if (rastersInX != 1 && i % rastersInX != 0){
for (size_t arrayCount = 0;
arrayCount < rasterOverlapUnderEdge.front().size(); arrayCount++){
int objID = rasterOverlapUnderEdge.front().at(arrayCount).objectID;
if (objID > 0){
size_t arrayCountR = (arrayCount / overlapRXMin) * _pointInMem
+ (arrayCount % overlapRXMin);
rasterMem[arrayCountR].objectID = objID;
}
}
rasterOverlapUnderEdge.erase(rasterOverlapUnderEdge.begin());
}
bool first = ((i % rastersInX) == 0);
bool last = ((i % rastersInX) == rastersInX - 1);
size_t line;
if (first && last){
line = _pointInMem;
}
else if (first || last){
line = _pointInMem - overlapRXMin;
}
else {
line = _pointInMem - 2 * overlapRXMin;
}
for (size_t arrayCount = 0;
arrayCount < rasterOverlapUnder.front().size(); arrayCount++){
int objID = rasterOverlapUnder.front().at(arrayCount).objectID;
if (objID > 0){
size_t arrayCountR = (arrayCount / line) * _pointInMem
+ (arrayCount % line);
rasterMem[arrayCountR].objectID = objID;
}
}
rasterOverlapUnder.erase(rasterOverlapUnder.begin());
}
//vertical line no edge
if (rastersInX != 1 && (i + 1) % rastersInX == 0)
{
bool first = (i / rastersInX == 0);
for (size_t arrayCount = 0;
arrayCount < rasterOverlapH.size(); arrayCount++){
int objID = rasterOverlapH[arrayCount].objectID;
if (objID > 0){
size_t arrayCountR = (arrayCount / overlapRXMin) * _pointInMem
+ overlapRXMax + (arrayCount % overlapRXMin);
if (!first){
arrayCountR += (overlapRYMin) * _pointInMem;
}
rasterMem[arrayCountR].objectID = objID;
}
}
rasterOverlapH.clear();
}
//recalculate overlapping structure
//horizontal line under no edge
//under
if (rastersInY != 1 && (i / rastersInX) > 0 && (i + 1) % rastersInX != 0)
{
for (size_t arrayCount = 0;
arrayCount < rasterOverlapUnderEdge[0].size(); arrayCount++){
size_t arrayCountR = (arrayCount / overlapRXMin) * _pointInMem
+ (arrayCount % overlapRXMin) + overlapRXMax;
const int objID = rasterMem[arrayCountR].objectID;
if (objID > 0){
rasterOverlapUnderEdge[0][arrayCount].objectID = objID;
rasterOverlapUnderEdge[0][arrayCount].classID =
rasterMem[arrayCountR].classID;
}
}
}
//over
if (rastersInY != 1 && i / rastersInX < rastersInY -1 && i % rastersInX != 0)
{
size_t numRecalc = rastersInX - 2;
for (size_t arrayCount = 0;
arrayCount < rasterOverlapOverEdge[numRecalc].size(); arrayCount++){
size_t arrayCountR =
(arrayCount / overlapRXMin + overlapRYMax) * _pointInMem
+ (arrayCount % overlapRXMin) + overlapRXMax;
const int objID = rasterMem[arrayCountR].objectID;
if (objID > 0){
rasterOverlapOverEdge[numRecalc][arrayCount].objectID = objID;
rasterOverlapOverEdge[numRecalc][arrayCount].classID =
rasterMem[arrayCountR].classID;
}
}
}
//generate new overlapping structure
//horizontal line no edge
if (i / rastersInX < rastersInY - 1)
{
rasterOverlapOver.resize(rasterOverlapOver.size()+1);
size_t startAC = ((i % rastersInX) == 0) ? (_pointInMem * overlapRYMax) :
(_pointInMem * overlapRYMax + overlapRXMin);
size_t endAC = ((i % rastersInX) == rastersInX- 1) ?
_pointInMem2 : (_pointInMem2 - overlapRYMin);
for (size_t arrayCount = startAC; arrayCount < endAC; arrayCount++){
const int objID = rasterMem[arrayCount].objectID;
const int classID = rasterMem[arrayCount].classID;
rasterOverlapOver.back().push_back({objID, classID});
if (((i % rastersInX) == rastersInX- 1) ?
((arrayCount + 1) % _pointInMem == 0) :
((arrayCount + 1 +overlapRXMin) % _pointInMem == 0)){
arrayCount += overlapRXMin + 1;
}
}
if (rastersInX != 1 && (i % rastersInX) != rastersInX- 1){
rasterOverlapOverEdge.resize(rasterOverlapOverEdge.size()+1);
for (size_t arrayCount = (overlapRYMax * _pointInMem) + overlapRXMax;
arrayCount < _pointInMem2; arrayCount++){
const int objID = rasterMem[arrayCount].objectID;
const int classID = rasterMem[arrayCount].classID;
rasterOverlapOverEdge.back().push_back({objID, classID});
if ((arrayCount + 1) % _pointInMem == 0){
arrayCount += overlapRXMax + 1;
}
}
}
}
//vertical line no edge
if ((i +1) % rastersInX != 0)
{
size_t startAC = ((i / rastersInX) == 0) ?
overlapRXMax : (_pointInMem * overlapRYMin + overlapRXMax);
size_t endAC = ((i / rastersInX) == rastersInY - 1) ?
_pointInMem2 : (_pointInMem * overlapRYMax);
for (size_t arrayCountR = startAC; arrayCountR < endAC; arrayCountR++){
const int objID = rasterMem[arrayCountR].objectID;
const int classID = rasterMem[arrayCountR].classID;
rasterOverlapH.push_back({objID, classID});
if ((arrayCountR + 1) % _pointInMem == 0){
arrayCountR += overlapRXMax + 1;
}
}
}
//new x-line
if ((i +1) % rastersInX == 0){
rasterOverlapUnder.swap(rasterOverlapOver);
rasterOverlapUnderEdge.swap(rasterOverlapOverEdge);
}
}
/*
1.25 recalculate bbox by newly discovered points
*/
void
op_analyzeRaster::recalcBbox(Rect& bboxObj, size_t nF) const{
double minX = bboxObj.MinD(0);
double maxX = bboxObj.MaxD(0);
double minY = bboxObj.MinD(1);
double maxY = bboxObj.MaxD(1);
if (minX > (nF % _pointInMem)){
minX = (nF % _pointInMem) + 0.;
}
if (maxX < (nF % _pointInMem)){
maxX = (nF % _pointInMem) + 0.;
}
if (minY > (nF / _pointInMem)){
minY = (nF / _pointInMem) + 0.;
}
if (maxY < (nF / _pointInMem)){
maxY = (nF / _pointInMem) + 0.;
}
double min[] = {minX, minY};
double max[] = {maxX, maxY};
bboxObj.Set(true, min, max);
}
/*
1.26 convert rasterpoint to secondo representation
*/
RasterPointDB
op_analyzeRaster::structToSecondo(RasterPoint grid) const{
RasterPointDB buffer;
buffer.averageAlt.Set(true,grid.averageAlt);
buffer.averageIntensity.Set(true,grid.averageIntensity);
buffer.classID.Set(true,grid.classID);
buffer.objectID.Set(true,grid.objectID);
buffer.count.Set(true,grid.count);
buffer.initialized.Set(true,grid.initialized);
buffer.maxAlt.Set(true,grid.maxAlt);
buffer.minAlt.Set(true,grid.minAlt);
return buffer;
}
/*
1.27 convert secondo representation to rasterpoint
*/
RasterPoint
op_analyzeRaster::secondoToStruct(RasterPointDB bufferDB){
RasterPoint buffer;
buffer.averageAlt = bufferDB.averageAlt.GetRealval();
buffer.averageIntensity = bufferDB.averageIntensity.GetIntval();
buffer.classID = bufferDB.classID.GetIntval();
buffer.objectID = bufferDB.objectID.GetIntval();
buffer.count = (size_t) bufferDB.count.GetIntval();
buffer.initialized = bufferDB.initialized.GetBoolval();
buffer.maxAlt = bufferDB.maxAlt.GetRealval();
buffer.minAlt = bufferDB.minAlt.GetRealval();
buffer.objectID = bufferDB.objectID.GetIntval();
return buffer;
}
/*
1.28 convert secondo representation to rasterpoint
reduced struct for save back
*/
RasterPointSave
op_analyzeRaster::secondoToStructSave(RasterPointDBSave bufferDB) const{
RasterPointSave buffer;
buffer.classID = bufferDB.classID.GetIntval();
buffer.objectID = bufferDB.objectID.GetIntval();
return buffer;
}
/*
1.29 calculate raster rartition
calculate bbox for pc2 partition
*/
std::unique_ptr<Pointcloud2, std::function<void(Pointcloud2*)>>
op_analyzeRaster::calculateRasterRartition(double x,
double y) const
{
double minMax[] = {
x,
double(x + _sizeRaster),
y,
double(y + _sizeRaster),
_pc2->getBoundingBox().MinD(2),
_pc2->getBoundingBox().MaxD(2)
};
Rect3 bboxRaster({true, minMax});
const PcBox intersectionBbox =
bboxRaster.Intersection(_pc2->getBoundingBox());
assert (!intersectionBbox.IsEmpty());
return calculateRasterRartition(bboxRaster);
}
/*
1.30 calculate raster partition
calculate partition of pc2 to calculate temporary representation
or if complete raster fits in memory use source pc2
*/
std::unique_ptr<Pointcloud2, std::function<void(Pointcloud2*)>>
op_analyzeRaster::calculateRasterRartition(Rect3 bboxRaster) const{
ListExpr type = nl->Second(nl->Second(nl->Second(_resultType)));
ListExpr refPc2 = nl->SymbolAtom(Referencesystem::toString(
pointcloud2::Referencesystem::EUCLID));
if (nl->ListLength(type) == 2){
type = nl->OneElemList(refPc2);
}
else
{
ListExpr tuple = nl->OneElemList(nl->First(type));
type = nl->Rest(type);
ListExpr last = tuple;
while (!nl->HasLength(type, 2)){
last = nl->Append(last, nl->First(type));
type = nl->Rest(type);
}
type = nl->TwoElemList(nl->First(
nl->Second(nl->Second(_resultType))), tuple);
type = nl->TwoElemList(refPc2, type);
}
size_t sizeR = _sizeRaster;
size_t sizeROverlap = _sizeRasterOverlap;
if (sizeR != sizeROverlap) {
std::unique_ptr<Pointcloud2, std::function<void(Pointcloud2*)>>
pc2RasterPart(new Pointcloud2(type), [&type](Pointcloud2* p) {
Word w;
w.addr = p;
Pointcloud2::Delete(type, w);
});
pc2RasterPart->copySelectionFrom(_pc2, &bboxRaster);
return pc2RasterPart;
} else {
std::unique_ptr<Pointcloud2, std::function<void(Pointcloud2*)>>
pc2RasterPart(_pc2, [](Pointcloud2* p) {
// do NOT delete _pc2
});
return pc2RasterPart;
}
}