/* ---- 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 restrict Operators These Operators are: * restrictPc2 * restrictXY * restrictZ * restrictAttr * restrictRnd */ #include "opRestrictOperators.h" using namespace pointcloud2; extern NestedList *nl; extern QueryProcessor *qp; /* 1.1 The Pointcloud2 restrict Operator */ ListExpr op_restrict::restrictTM(ListExpr args) { const std::string err("pointcloud2 x rect" + std::to_string(DIMENSIONS) + " expected"); if (!nl->HasLength(args, 2)) { return listutils::typeError(err + " (two arguments expected)"); } ListExpr pc2Type = nl->First(args); if (!Pointcloud2::TypeCheck(pc2Type)) { return listutils::typeError(err + " (error in first argument)"); } if (!PcBox::checkType(nl->Second(args))) { return listutils::typeError(err + " (error in second argument)"); } // create the result type (Pointcloud2) return pc2Type; } int op_restrict::restrictVM(Word* args, Word& result, int message, Word& local, Supplier s) { Pointcloud2* pc2Source = static_cast(args[0].addr); PcBox* bbox = static_cast(args[1].addr); result = qp->ResultStorage(s); Pointcloud2* pc2Dest = static_cast(result.addr); pc2Dest->copySelectionFrom(pc2Source, bbox); return 0; } std::string op_restrict::getOperatorSpec(){ return OperatorSpec( " pointcloud2(X) x rect<" + std::to_string(DIMENSIONS) +">" + " -> pointcloud2(X)", " _ restrictPc2[ _ ] ", " Creates a new pointcloud2 with the points in the given rect3 ", " query pc2 restrictPc2[ [const rect3 value (0 10 0 20 0 50)] ]" ).getStr(); } std::shared_ptr op_restrict::getOperator(){ return std::make_shared("restrictPc2", getOperatorSpec(), &op_restrict::restrictVM, Operator::SimpleSelect, &op_restrict::restrictTM); } /* 1.2 The Pointcloud2 restrictXY Operator */ ListExpr op_restrictXY::restrictXYTM(ListExpr args) { const std::string err("pointcloud2 x rect expected"); if (!nl->HasLength(args, 2)) { return listutils::typeError(err + " (two arguments expected)"); } ListExpr pc2Type = nl->First(args); if (!Pointcloud2::TypeCheck(pc2Type)) { return listutils::typeError(err + " (error in first argument)"); } if (!Rect::checkType(nl->Second(args))) { return listutils::typeError(err + " (error in second argument)"); } // create the result type (Pointcloud2) return pc2Type; } int op_restrictXY::restrictXYVM(Word* args, Word& result, int message, Word& local, Supplier s) { Pointcloud2* pc2Source = static_cast(args[0].addr); PcBox sourceBbox = pc2Source->getBoundingBox(); Rect* rect = static_cast(args[1].addr); // to express unlimited Z range, we use the sourceBbox values rather // than a minimum/maximum double value (which would cause an overflow in // Rectangle::Area()). An alternative maximum value would be // pow(std::numeric_limits::max(), 1.0 / DIMENSIONS) / 2.0 - FACTOR // as this avoids an overflow in Area. // do not use rect->getMinX() etc. which always returns 0.0! double minMax[] = { rect->MinD(0), rect->MaxD(0), rect->MinD(1), rect->MaxD(1), sourceBbox.MinD(2), sourceBbox.MaxD(2) }; PcBox bbox({rect->IsDefined(), minMax}); result = qp->ResultStorage(s); Pointcloud2* pc2Dest = static_cast(result.addr); pc2Dest->copySelectionFrom(pc2Source, &bbox); return 0; } std::string op_restrictXY::getOperatorSpec(){ return OperatorSpec( " pointcloud2(X) x rect -> pointcloud2(X)", " _ restrictXY( _ ) ", " Creates a new pointcloud2 with the points in the given XY-rect ", " query pc2 restrictXY[ [const rect value (0 10 0 20)] ]" ).getStr(); } std::shared_ptr op_restrictXY::getOperator(){ return std::make_shared("restrictXY", getOperatorSpec(), &op_restrictXY::restrictXYVM, Operator::SimpleSelect, &op_restrictXY::restrictXYTM); } /* 1.3 The Pointcloud2 restrictZ Operator */ ListExpr op_restrictZ::restrictZTM(ListExpr args) { const std::string err("pointcloud2 x real x real expected"); if (!nl->HasLength(args, 3)) { return listutils::typeError(err + " (three arguments expected)"); } ListExpr pc2Type = nl->First(args); if (!Pointcloud2::TypeCheck(pc2Type)) { return listutils::typeError(err + " (error in first argument)"); } if (!CcReal::checkType(nl->Second(args))) { return listutils::typeError(err + " (error in second argument)"); } if (!CcReal::checkType(nl->Third(args))) { return listutils::typeError(err + " (error in third argument)"); } // create the result type (Pointcloud2) return pc2Type; } int op_restrictZ::restrictZVM(Word* args, Word& result, int message, Word& local, Supplier s) { Pointcloud2* pc2Source = static_cast(args[0].addr); PcBox sourceBbox = pc2Source->getBoundingBox(); CcReal* minZ = static_cast(args[1].addr); CcReal* maxZ = static_cast(args[2].addr); const bool isDefined = minZ->IsDefined() && maxZ->IsDefined(); // to express unlimited XY range, we use the sourceBbox values rather // than a minimum/maximum double value (which would cause an overflow in // Rectangle::Area()). See remarks in restrictXYVM double minMax[] = { sourceBbox.MinD(0), sourceBbox.MaxD(0), sourceBbox.MinD(1), sourceBbox.MaxD(1), minZ->GetRealval(), maxZ->GetRealval() }; PcBox bbox({isDefined, minMax}); result = qp->ResultStorage(s); Pointcloud2* pc2Dest = static_cast(result.addr); pc2Dest->copySelectionFrom(pc2Source, &bbox); return 0; } std::string op_restrictZ::getOperatorSpec(){ return OperatorSpec( " pointcloud2(X) x real x real -> pointcloud2(X)", " _ restrictZ( _, _ ) ", " Creates a new pointcloud2 with the points in the given Z-interval ", " query pc2 restrictZ[ -5.0, 5.0 ]" ).getStr(); } std::shared_ptr op_restrictZ::getOperator(){ return std::make_shared("restrictZ", getOperatorSpec(), &op_restrictZ::restrictZVM, Operator::SimpleSelect, &op_restrictZ::restrictZTM); } /* 1.4 restrictAttr Operator */ ListExpr op_restrictAttr::restrictAttrTM( ListExpr args ) { // work in progress // (? ?) if( !nl->HasLength(args, 2) ) { return listutils::typeError("wrong number of arguments"); } // (pointcloud2<> ?) if( !Pointcloud2::TypeCheck(nl->First(args)) ) { return listutils::typeError(R"(first argument " "must be a pointcloud2)"); } if( !Pointcloud2::isTupleCloud( nl->First(args)) ) { return listutils::typeError(R"(pointcloud must have attributes " "for this operator to have a point)"); } // (pointcloud2<> (map ? ?)) if( !listutils::isMap<1>( nl->Second(args)) ) { return listutils::typeError(R"(second argument " "has to be a map with one argument)"); } // (pointcloud2<> (map tuple ?)) if( !Tuple::checkType( nl->Second(nl->Second(args))) ) { return listutils::typeError(R"(argument to the map " "in restrictAttr must be a Tuple)"); } // (pointcloud2<> (map tuple bool)) if( !CcBool::checkType( nl->Third(nl->Second(args))) ) { return listutils::typeError(R"(result of the map " "in restrictAttr must be Boolean)"); } return nl->First(args); } int op_restrictAttr::restrictAttrVM(Word* args, Word& result, int message, Word& local, Supplier s) { // work in progress result = qp->ResultStorage(s); Pointcloud2* pc2source = static_cast(args[0].addr); Pointcloud2* pc2dest = static_cast(result.addr); // case undefined pc2dest->setDefined(pc2source->isDefined()); if( !pc2dest->isDefined() ) { return 0; } Word f = args[1]; ArgVectorPointer funargs = qp->Argument(f.addr); Word funres; PcPoint pcPoint; SmiRecordFileIterator *it = pc2source->getFileIterator(); SmiRecord record; pc2dest->startInsert(); while( it->Next(record) ) { pc2source->getPoint(record.GetId(), &pcPoint); Tuple *t = pc2source->getTuple(pcPoint._tupleId); // function application *funargs[0] = t; qp->Request(f.addr, funres); CcBool *res = static_cast(funres.addr); if (res->GetBoolval()) { pc2dest->insert(pcPoint, t); } else { t->DeleteIfAllowed(); } } delete it; pc2dest->finalizeInsert(); return 0; } std::string op_restrictAttr::getOperatorSpec() { return OperatorSpec( "pointcloud2(X) x (fun: T -> bool) -> pointcloud2(X)", "_ restrictAttr[_] ", "restrict to points fulfilling the given predicate", "query pc2 restrictAttr[]" ).getStr(); } std::shared_ptr op_restrictAttr::getOperator() { return std::make_shared("restrictAttr", getOperatorSpec(), &op_restrictAttr::restrictAttrVM, Operator::SimpleSelect, &op_restrictAttr::restrictAttrTM); } /* 1.5 The Pointcloud2 restrictRnd Operator */ ListExpr op_restrictRnd::restrictRndTM(ListExpr args) { const std::string err("pointcloud2 x int expected"); if (!nl->HasLength(args, 2)) { return listutils::typeError(err + " (two arguments expected)"); } ListExpr pc2Type = nl->First(args); if (!Pointcloud2::TypeCheck(pc2Type)) { return listutils::typeError(err + " (error in first argument)"); } if (!CcInt::checkType(nl->Second(args))) { return listutils::typeError(err + " (error in second argument)"); } // create the result type (Pointcloud2) return pc2Type; } int op_restrictRnd::restrictRndVM(Word* args, Word& result, int message, Word& local, Supplier s) { Pointcloud2* pc2Source = static_cast(args[0].addr); PcBox sourceBbox = pc2Source->getBoundingBox(); CcInt* count = static_cast(args[1].addr); const bool isDefined = count->IsDefined(); size_t countValue = count->GetValue() < 0 ? 0 : size_t(count->GetValue()); result = qp->ResultStorage(s); Pointcloud2* pc2Dest = static_cast(result.addr); if (!isDefined || countValue <= 0) { // do nothing } else if (countValue >= pc2Source->getPointCount()) { pc2Dest->copyAllFrom(pc2Source); } else { BitArray bitMap { pc2Source->getPointCount(), true }; bitMap.initializeRandom(countValue); pc2Dest->copySelectionFrom(pc2Source, bitMap); } return 0; } std::string op_restrictRnd::getOperatorSpec(){ return OperatorSpec( " pointcloud2(X) x int -> pointcloud2(X)", " _ restrictRnd[_] ", " Creates a new pointcloud2 with a random selection of n points ", " query pc2 restrictRnd[ 1000 ]" ).getStr(); } std::shared_ptr op_restrictRnd::getOperator(){ return std::make_shared("restrictRnd", getOperatorSpec(), &op_restrictRnd::restrictRndVM, Operator::SimpleSelect, &op_restrictRnd::restrictRndTM); }