Files
secondo/Algebras/Pointcloud2/basicOperators/opStreamingOperators.cpp
2026-01-23 17:03:45 +08:00

443 lines
14 KiB
C++

/*
----
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
0 Pointcloud2 Streaming Operators
These operators are "feed" and "collect2pc".
They allow to feed a pc2-object into a tuple-stream
and to collect a pc2-object from a tuple-stream.
In this way one can leverage all the existing operators working on tuple streams.
*/
#include "opStreamingOperators.h"
#include <set>
#include "Stream.h"
#include "Algebras/Spatial/Point.h"
using namespace pointcloud2;
extern NestedList *nl;
/*
1 Implementation feed Operator
*/
ListExpr op_feed::feedTM(ListExpr args) {
const std::string err("pointcloud2 expected");
// input like: ((pointcloud2 (EUCLID (tuple ((Name string)(Val real)) ))))
// checking it:
// (?)
if (!nl->HasLength(args,1)) {
return listutils::typeError(err + " (wrong number of arguments)");
}
// ( (? ?) )
ListExpr typeInfo = nl->First(args);
if (!nl->HasLength(typeInfo,2)) {
return listutils::typeError(err + " (wrong format - 1)");
}
// ( (pointcloud2 ?) )
if (!listutils::isSymbol(nl->First(typeInfo),Pointcloud2::BasicType())) {
return listutils::typeError(err);
}
bool hasTupleInformation = false;
ListExpr typeInfo2 = nl->Second(typeInfo);
// ( (pointcloud (RS)) ) || ( (pointcloud2 (RS TT)) )
if (nl->HasLength(typeInfo2,2)) {
hasTupleInformation = true;
} else if (nl->ListLength(typeInfo2) != -1) {
return listutils::typeError(err + " (wrong format - 2)");
}
// construction of return value:
// point type for Tuple - (P point)
ListExpr pointType = nl->TwoElemList(
nl->SymbolAtom("P"),
listutils::basicSymbol<Point>()
);
// Z coordinate - (Alt real)
ListExpr pointHeight = nl->TwoElemList(
nl->SymbolAtom("Alt"),
listutils::basicSymbol<CcReal>()
);
// streamTuple: ( (P point) (Alt real) )
ListExpr streamTuple = nl->OneElemList(pointType);
ListExpr last = nl->Append(streamTuple, pointHeight);
if(hasTupleInformation) {
ListExpr attributes = nl->Second(nl->Second(typeInfo2));
std::set<std::string> attributeNames = {"P", "Alt"};
while(!nl->IsEmpty(attributes))
{
ListExpr first = nl->First(attributes);
attributes = nl->Rest(attributes);
//TODO: Fix variable names....
ListExpr attributeName = nl->First(first);
std::string arttibuteNameAsString = nl->ToString(attributeName);
int counter = 1;
while(attributeNames.find(arttibuteNameAsString)
!= attributeNames.end()){
arttibuteNameAsString = arttibuteNameAsString +
"_" + std::to_string(counter++);
}
attributeNames.insert(arttibuteNameAsString);
// streamTuple: ((P point)(Alt real)(attrNameStr attrType){n})
last = nl->Append(last,
nl->TwoElemList(
nl->SymbolAtom(
arttibuteNameAsString),
nl->Second(first)));
}
}
// ( tuple
// ((P point)(Alt real)(attrNameStr attrType){n}) )
streamTuple = nl->TwoElemList(
nl->SymbolAtom(Tuple::BasicType()), streamTuple);
// ( stream
// ( tuple
// ((P point)(Alt real)(attrNameStr attrType){n}) ))
const ListExpr streamExpr = nl->TwoElemList(
nl->SymbolAtom(Symbol::STREAM()), streamTuple);
return streamExpr;
}
int op_feed::feedVM(Word* args, Word& result, int message,
Word& local, Supplier s) {
FeedLocalInfo *li = static_cast<FeedLocalInfo *>(local.addr);
switch (message)
{
case OPEN:
{
if (li) delete li;
ListExpr resultType = GetTupleResultType( s );
local.addr=new FeedLocalInfo(static_cast<Pointcloud2*>(args[0].addr),
nl->Second(resultType));
return 0;
}
case REQUEST:
result.addr = li ? li->getNext() : nullptr;
return result.addr ? YIELD : CANCEL;
case CLOSE:
if (li)
{
delete li;
local.addr = nullptr;
}
return 0;
}
return 0;
}
std::string op_feed::getOperatorSpec(){
return OperatorSpec(
" pointcloud2 -> stream(...)",
" _ feed ",
" Returns the points as a tuple stream ",
" query pc2 feed"
).getStr();
}
std::shared_ptr<Operator> op_feed::getOperator(){
return std::make_shared<Operator>("feed",
getOperatorSpec(),
&op_feed::feedVM,
Operator::SimpleSelect,
&op_feed::feedTM);
}
/*
1.1 Implementation of FeedLocalInfo Functions
*/
Tuple* FeedLocalInfo::getNext()
{
++_pos;
if(_pos <= _countOfPoints)
{
Tuple* result = new Tuple(_resultType);
_pc2->getPoint(_pos, _currentPoint.get());
result->PutAttribute(0, new Point(true, _currentPoint->_x,
_currentPoint->_y));
result->PutAttribute(1, new CcReal(_currentPoint->_z));
if(_currentPoint->_tupleId){
Tuple* tuple = _pc2->getTuple(_currentPoint->_tupleId);
for(int i = 2, j = 0; j < tuple->GetNoAttributes(); ++i, ++j) {
// we must clone the attribute from the source tuple
// in order to be able to delete the source tuple
result->PutAttribute(i, tuple->GetAttribute(j)->Clone());
}
tuple->DeleteIfAllowed();
}
return result;
}
return nullptr;
}
/*
2 The Pointcloud2 CollectPc2 Operator
collectPc2: stream(tuple(...) xP xA xREF xZ1...Zn
-> pointcloud2(REF, (tuple(|Z1:t1,...,Zn:tn|)))
2.1 Type Mapping
Arg: Stream(tuple), AttrName point, alt(int,real), REF, Z1..Z2
*/
ListExpr OPCollectPc2::collectPc2TM(ListExpr args){
std::string err = "Stream(tuple), AttrName point, alt, REF, Z1..Z2";
if(!(nl->HasLength(args,5))){
//5th argument is list that could be empty
return listutils::typeError("expected 4 or more arguments");
}
const ListExpr arg1 = nl->First(args); //tuple-stream
const ListExpr arg2 = nl->Second(args); //point
const ListExpr arg3 = nl->Third(args); //alt
const ListExpr arg4 = nl->Fourth(args); //REF
ListExpr tupleAttr = nl->Fifth(args); //Attr-List
if(!Stream<Tuple>::checkType(arg1)){
return listutils::typeError("first arg is not a tuple stream");
}
if(nl->AtomType(arg2) != SymbolType){
return listutils::typeError("second arg is not a valid attribute name");
}
if(nl->AtomType(arg3) != SymbolType){
return listutils::typeError("third arg is not a valid attribute name");
}
// check for REF
if(!listutils::isSymbol(arg4)){
return listutils::typeError(err + " (REF)");
} else {
try {
Referencesystem::toEnum(nl->SymbolValue(arg4));
} catch(std::invalid_argument&) {
return listutils::typeError(err + " (REF)");
}
}
// extract the attribute list
ListExpr attrList = nl->Second(nl->Second(arg1));
ListExpr type = nl->TheEmptyList();
ListExpr result = nl->OneElemList(nl->TheEmptyList());
ListExpr lastRes = result;
//Point
const std::string p = nl->SymbolValue(arg2);
//Attr.position
int j = listutils::findAttribute(attrList, p, type);
if (!Point::checkType(type)){
return listutils::typeError(err + " ( Attr. no Point)");
}
//Pos 1 is point, pos 2 alt and the rest tuple-attr
ListExpr indexes = nl->OneElemList(nl->IntAtom(j));
ListExpr lastIndex = indexes;
//Alt
const std::string alt = nl->SymbolValue(arg3);
j = listutils::findAttribute(attrList, alt, type);
if (!(CcInt::checkType(type) || CcReal::checkType(type))){
return listutils::typeError(err + " ( Alt no Int/Real)");
}
lastIndex = nl->Append(lastIndex, nl->IntAtom(j));
lastIndex = nl->Append(lastIndex, nl->IntAtom(CcInt::checkType(type)));
//attr. for tuple of Pc2
std::string attrName;
while (!nl->IsEmpty(tupleAttr)){
attrName = nl->SymbolValue(nl->First(tupleAttr));
j = listutils::findAttribute(attrList, attrName, type);
if (j > 0){
lastIndex = nl->Append(lastIndex, nl->IntAtom(j));
lastRes = nl->Append(lastRes,
nl->TwoElemList(nl->First(tupleAttr),type));
}
tupleAttr = nl->Rest(tupleAttr);
}
result = nl->Rest(result);
//DEBUG
std::cout << nl->ToString(result) << endl;
if (nl->IsEmpty(result)){
result = nl->TwoElemList(listutils::basicSymbol<Pointcloud2>(),
arg4);
} else {
result = nl->TwoElemList(listutils::basicSymbol<Tuple>(),result);
result = nl->TwoElemList(arg4, result);
result = nl->TwoElemList(listutils::basicSymbol<Pointcloud2>(),result);
}
ListExpr append = nl->OneElemList(nl->IntAtom(nl->ListLength(indexes)));
ListExpr lastAppend = append;
while (!nl->IsEmpty(indexes)){
lastAppend = nl->Append(lastAppend, nl->First(indexes));
indexes = nl->Rest(indexes);
}
//DEBUG
std::cout<<"return: " << nl->ToString(result) << endl;
std::cout<<"return: " << nl->ToString(append) << endl;
return nl->ThreeElemList(
nl->SymbolAtom(Symbols::APPEND()),
append,
result);
}
int OPCollectPc2::collectPc2VMT( Word* args, Word& result, int message,
Word& local, Supplier s ){
result = qp->ResultStorage(s);
Pointcloud2* pc2 = static_cast<pointcloud2::Pointcloud2*>(result.addr);
//read append structure
//(index Point, index Alt, type Alt (0/1 real/int), index Attr)
const int arg5 = static_cast<CcInt*>(args[5].addr)->GetIntval();
const int countIndex = 6 + arg5;
//only point or attributes?
bool tupleExist = false;
if (countIndex > 9){
tupleExist = true;
}
std::vector<int> index(arg5);
index.clear(); //TODO: Warum ist das notwendig??
for (int i = 6; i < countIndex; i++){//all appended index
CcInt* x = static_cast<CcInt*>(args[i].addr);
index.emplace_back(x->GetIntval());
}
std::unique_ptr<TupleType> tt;
if (tupleExist){
const ListExpr resultType = GetTupleResultType(s);
tt.reset(new TupleType(nl->Second(nl->Second(resultType))));
}
Stream<Tuple> stream(args[0]);
stream.open();
Tuple* elem;
pc2->startInsert();
while( (elem = stream.request()) != 0 ){
//x, y, z;
Point* p = static_cast<Point*>(elem->GetAttribute(index[0]-1));
if (!p->IsDefined()){
elem->DeleteIfAllowed();
continue;
}
const double x = p->GetX();
const double y = p->GetY();
double z = 0.0;
constexpr int altInt = 1;
if (index[2] == altInt){ //Int/Real
CcInt* zTup = static_cast<CcInt*>(elem->GetAttribute(index[1]-1));
if (!zTup->IsDefined()){
elem->DeleteIfAllowed();
continue;
}
z = zTup->GetIntval();
}else{
CcReal* zTup = static_cast<CcReal*>(elem->GetAttribute(index[1]-1));
if (!zTup->IsDefined()){
elem->DeleteIfAllowed();
continue;
}
z = zTup->GetRealval();
}
// build tuple for pointcloud2
if (tupleExist){
Tuple* attrTuple = new Tuple(tt.get());
// number of attributes in result tuple
for (int i = 3; i < arg5; i++){ //all attributes
attrTuple->CopyAttribute(index[i]-1, elem, i-3);
}
PcPoint pcPoint {x, y, z};
pc2->insert(pcPoint, attrTuple);
} else{
pc2->insert({x,y,z});
}
elem->DeleteIfAllowed();
}
stream.close();
pc2->finalizeInsert();
if (local.addr) {
local.addr = nullptr;
}
return 0;
}
std::string OPCollectPc2::getOperatorSpec(){
return OperatorSpec(
"stream(...) -> pointcloud2(REF, tuple)",
"_ collectPc2[_,_,_]",
"collect stream P,A,REF,Attr in PC2",
"query xx collectPc2 [P,Alt,ECULID]"
).getStr();
}
std::shared_ptr<Operator> OPCollectPc2::getOperator(){
return std::make_shared<Operator>("collectPc2",
getOperatorSpec(),
OPCollectPc2::collectPc2VMT,
Operator::SimpleSelect,
&OPCollectPc2::collectPc2TM);
}