Files
secondo/Algebras/Pointcloud2/basicOperators/opMerge.cpp

316 lines
12 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 Implementation of the Merge Operator
*/
#include <set>
#include "opMerge.h"
using namespace pointcloud2;
extern NestedList *nl;
extern QueryProcessor *qp;
/*
1.7 The Pointcloud2 Merge Operator
*/
ListExpr op_merge::mergeTM(ListExpr args) {
const std::string err("pointcloud2 x pointcloud2 expected");
if (!nl->HasLength(args,2)) {
return listutils::typeError(err + " (wrong number of arguments)");
}
ListExpr errorInfo = nl->TheEmptyList();
const ListExpr pc1 = nl->First(args);
if (!Pointcloud2::TypeCheck(pc1, errorInfo)) {
return listutils::typeError(err
+ " (first argument is not a pointcloud2)");
}
const ListExpr pc2 = nl->Second(args);
if (!Pointcloud2::TypeCheck(pc2, errorInfo)) {
return listutils::typeError(err
+ " (second argument is not a pointcloud2) ");
}
//Do both pointcloud2s have the same reference system
Referencesystem::Type pc1ref, pc2ref;
try {
pc1ref = nl->IsAtom(nl->Second(pc1))
? Referencesystem::toEnum(nl->SymbolValue(nl->Second(pc1)))
: Referencesystem::toEnum(
nl->SymbolValue(nl->First(nl->Second(pc1))));
pc2ref = nl->IsAtom(nl->Second(pc2))
? Referencesystem::toEnum(nl->SymbolValue(nl->Second(pc2)))
: Referencesystem::toEnum(
nl->SymbolValue(nl->First(nl->Second(pc2))));
if (pc1ref!=pc2ref) {
return listutils::typeError(err
+ " (2 different reference systems)");
}
} catch(std::invalid_argument&) {
return listutils::typeError(err
+ " (impossible reference system error)");
}
ListExpr appendList = nl->OneElemList(nl->IntAtom(0));
//Do both pointcloud2s have attributes
if ((!nl->HasLength(nl->Second(pc1), 2)) ||
(!nl->HasLength(nl->Second(pc2), 2))){
return nl->ThreeElemList(
nl->SymbolAtom(Symbols::APPEND()),
appendList,
nl->TwoElemList(
listutils::basicSymbol<Pointcloud2>(),
nl->SymbolAtom(Referencesystem::toString(pc1ref))
)
);
}
const ListExpr pc1TupletypeInfo = nl->Second(nl->Second(pc1));
if (!listutils::isTupleDescription(pc1TupletypeInfo)){
return listutils::typeError(err + " (error in pc1 tuple description)");
}
const ListExpr pc2TupletypeInfo = nl->Second(nl->Second(pc2));
if (!listutils::isTupleDescription(pc2TupletypeInfo)){
return listutils::typeError(err + " (error in pc2 tuple description)");
}
ListExpr pc1Attrs = nl->Second(pc1TupletypeInfo);
const ListExpr pc2Attrs = nl->Second(pc2TupletypeInfo);
//Are attributes not empty
if ((nl->IsEmpty(pc1Attrs)) || (nl->IsEmpty(pc2Attrs))) {
return nl->ThreeElemList(
nl->SymbolAtom(Symbols::APPEND()),
appendList,
nl->TwoElemList(
listutils::basicSymbol<Pointcloud2>(),
nl->SymbolAtom(Referencesystem::toString(pc1ref))
)
);
}
// //Differs the attribute structure (aka tuple schema) of the two pc2s
// TupleType* tt1 = new TupleType(pc1TupletypeInfo);
// TupleType* tt2 = new TupleType(pc2TupletypeInfo);
// if (tt1->equalSchema(*tt2)) {
// delete tt1, tt2;
// appendList = nl->OneElemList(nl->IntAtom(-1));
// const ListExpr type = nl->TwoElemList(
// listutils::basicSymbol<Pointcloud2>(),
// nl->TwoElemList(
// nl->SymbolAtom(
// Referencesystem::toString(pc1ref)),
// pc1TupletypeInfo));
// return nl->ThreeElemList(
// nl->SymbolAtom(Symbols::APPEND()),
// appendList,
// type);
// }
// delete tt1, tt2;
//What attributes do both pc2s have.
//Creating 3 lists. The attribute list for tuple type of result pc2,
//and the index lists for append mechanism.
ListExpr attrList = nl->TheEmptyList();
ListExpr indexListpc1 = nl->TheEmptyList();
ListExpr indexListpc2 = nl->TheEmptyList();
ListExpr lastAttr = nl->TheEmptyList(),
lastIndex1 = nl->TheEmptyList(),
lastIndex2 = nl->TheEmptyList();
int pc1AttrIndex = 0;
while (!nl->IsEmpty(pc1Attrs)) {
const ListExpr current = nl->First(pc1Attrs);
pc1AttrIndex++;
if ((!nl->HasLength(current,2))
|| !listutils::isSymbol(nl->First(current))
|| !listutils::isSymbol(nl->Second(current))){
return listutils::typeError(err
+ " (error in reading attribute types of first pointcloud)");
}
const ListExpr attrName = nl->First(current);
const ListExpr attrType = nl->Second(current);
ListExpr pc2AttrType;
const int pc2AttrIndex = listutils::findAttribute(
pc2Attrs,
nl->SymbolValue(attrName),
pc2AttrType);
if ((pc2AttrIndex != 0)
&& (nl->IsEqual(attrType,nl->SymbolValue(pc2AttrType)))) {
const ListExpr attr = nl->TwoElemList(attrName,attrType);
if (nl->IsEmpty(attrList)) {
attrList = nl->OneElemList(attr);
lastAttr = attrList;
indexListpc1 = nl->OneElemList(nl->IntAtom(pc1AttrIndex));
lastIndex1 = indexListpc1;
indexListpc2 = nl->OneElemList(nl->IntAtom(pc2AttrIndex));
lastIndex2 = indexListpc2;
} else {
lastAttr = nl->Append(lastAttr, attr);
lastIndex1 = nl->Append(lastIndex1, nl->IntAtom(pc1AttrIndex));
lastIndex2 = nl->Append(lastIndex2, nl->IntAtom(pc2AttrIndex));
}
}
pc1Attrs = nl->Rest(pc1Attrs);
} // end while
//Is there any attribute both pc2s have
if (nl->IsEmpty(attrList)) {
return nl->ThreeElemList(
nl->SymbolAtom(Symbols::APPEND()),
appendList,
nl->TwoElemList(
listutils::basicSymbol<Pointcloud2>(),
nl->SymbolAtom(Referencesystem::toString(pc1ref))
));
}
const ListExpr tupletypeinfo = nl->TwoElemList(
listutils::basicSymbol<Tuple>(),
attrList);
if (!listutils::isTupleDescription(tupletypeinfo)) {
return listutils::typeError(err
+ " (error in creating tupletypeinfo)");
}
appendList = nl->OneElemList(nl->IntAtom(nl->ListLength(indexListpc1)));
ListExpr lastAppend = appendList;
while (!nl->IsEmpty(indexListpc1)){
lastAppend = nl->Append(lastAppend, nl->First(indexListpc1));
indexListpc1 = nl->Rest(indexListpc1);
}
while (!nl->IsEmpty(indexListpc2)){
lastAppend = nl->Append(lastAppend, nl->First(indexListpc2));
indexListpc2 = nl->Rest(indexListpc2);
}
const ListExpr type = nl->TwoElemList(
listutils::basicSymbol<Pointcloud2>(),
nl->TwoElemList(
nl->SymbolAtom(
Referencesystem::toString(pc1ref)),
tupletypeinfo
)
);
const ListExpr result = nl->ThreeElemList(
nl->SymbolAtom(Symbols::APPEND()),
appendList,
type);
return result;
}
int op_merge::mergeVM(Word* args, Word& result, int message,
Word& local, Supplier s) {
Pointcloud2* pc1 = static_cast<Pointcloud2*>(args[0].addr);
Pointcloud2* pc2 = static_cast<Pointcloud2*>(args[1].addr);
result = qp->ResultStorage(s);
Pointcloud2* res = static_cast<Pointcloud2*>(result.addr);
if (!pc1 || !pc2 || (!pc1->isDefined() && !pc2->isDefined())) {
res->setDefined(false);
return 0;
}
const int attrCount = static_cast<CcInt*>(args[2].addr)->GetIntval();
const bool hasTuple = attrCount > 0;
const ListExpr tupleTypeInfo = hasTuple
? nl->Second(nl->Second(GetTupleResultType(s)))
: nl->TheEmptyList();
std::vector<int> attrIndexPc1(attrCount);
std::vector<int> attrIndexPc2(attrCount);
if (hasTuple) {
attrIndexPc1.clear();
for (int i = 3; i < attrCount+3; i++){//appended pc1IndexList
CcInt* x = static_cast<CcInt*>(args[i].addr);
attrIndexPc1.emplace_back(x->GetIntval());
}
attrIndexPc2.clear();
for (int i = attrCount+3; i < (2*attrCount)+3; i++){//appended pc2Index
CcInt* x = static_cast<CcInt*>(args[i].addr);
attrIndexPc2.emplace_back(x->GetIntval());
}
}
// a timer may be used for testing:
// Timer timer { Timer::UNIT::millis };
// stringstream st;
// size_t pointCount1 = pc1->getPointCount();
// size_t pointCount2 = pc2->getPointCount();
// st << "merge clouds with " << pointCount1 << " + " << pointCount2
// << " = " << (pointCount1 + pointCount2) << " points "
// "and " << attrCount << " attributes";
// timer.startTask(st.str());
res->startInsert();
res->merge(pc1, hasTuple, attrIndexPc1, tupleTypeInfo);
res->merge(pc2, hasTuple, attrIndexPc2, tupleTypeInfo);
res->finalizeInsert();
res->setDefined(true);
// timer.stopTask();
// cout << timer.getReportForAllTasks() << endl;
return 0;
}
std::string op_merge::getOperatorSpec(){
return OperatorSpec(
" pointcloud2 x pointcloud2 -> pointcloud2",
" merge( _ , _ ) ",
" merges two pointcloud2s ",
" query merge(pc1,pc2) "
).getStr();
}
std::shared_ptr<Operator> op_merge::getOperator(){
return std::make_shared<Operator>("merge",
getOperatorSpec(),
&op_merge::mergeVM,
Operator::SimpleSelect,
&op_merge::mergeTM);
}