12669 lines
382 KiB
C++
12669 lines
382 KiB
C++
/*
|
|
----
|
|
This file is part of SECONDO.
|
|
|
|
Copyright (C) 2004, University in Hagen, Department of 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
|
|
----
|
|
|
|
//paragraph [1] title: [{\Large \bf ] [}]
|
|
//characters [2] verbatim: [\verb@] [@]
|
|
//[ue] [\"{u}]
|
|
//[toc] [\tableofcontents]
|
|
|
|
""[2]
|
|
|
|
[1] NearestNeighbor Algebra
|
|
|
|
November 2008, A. Braese
|
|
15 October 2009 Mahmoud Sakr: Added the isknn operator
|
|
|
|
[toc]
|
|
|
|
0 Overview
|
|
|
|
This example algebra provides a distance-scan for a point set
|
|
in a R-Tree. A new datatype is not given but there are some operators:
|
|
|
|
1. ~distancescan~, which gives out k objects stored in a relation, ordered
|
|
in a r-tree in the order ascending to their distance to a
|
|
given object with the same dimension
|
|
|
|
2. ~knearest~, which gives out the k-nearest elements to a moving point.
|
|
|
|
3. ~knearestvector~, the same as knearest, but uses a vector to store
|
|
the active elements, than a unbalanced tree
|
|
|
|
1 Preliminaries
|
|
|
|
1.1 Includes
|
|
|
|
*/
|
|
#include <vector>
|
|
#include <queue>
|
|
#include <iterator>
|
|
#include <iostream>
|
|
#include <ostream>
|
|
|
|
#include "Algebra.h"
|
|
#include "NestedList.h"
|
|
#include "QueryProcessor.h"
|
|
#include "StandardTypes.h"
|
|
#include "Algebras/RTree/RTreeAlgebra.h"
|
|
#include "NearestNeighborAlgebra.h"
|
|
#include "Algebras/Temporal/TemporalAlgebra.h"
|
|
#include "BBTree.h"
|
|
#include "Algebras/BTree/BTreeAlgebra.h"
|
|
#include "Algebras/TBTree/TBTree.h"
|
|
#include "ListUtils.h"
|
|
#include "Stream.h"
|
|
#include "CoverInterval.h"
|
|
#include "AlmostEqual.h"
|
|
#include "Symbols.h"
|
|
#include "ClosestPair.h"
|
|
#include "TypeMapUtils.h"
|
|
#include "Symbols.h"
|
|
#include <sys/timeb.h>
|
|
#include <string>
|
|
|
|
extern NestedList* nl;
|
|
extern QueryProcessor *qp;
|
|
|
|
using namespace temporalalgebra;
|
|
|
|
/*
|
|
The file "Algebra.h" is included, since the new algebra must be a subclass of
|
|
class Algebra. All of the data available in Secondo has a nested list
|
|
representation. Therefore, conversion functions have to be written for this
|
|
algebra, too, and "NestedList.h" is needed for this purpose. The result of an
|
|
operation is passed directly to the query processor. An instance of
|
|
"QueryProcessor" serves for this. Secondo provides some standard data types,
|
|
e.g. "CcInt", "CcReal", "CcString", "CcBool", which is needed as the
|
|
result type of the implemented operations. To use them "StandardTypes.h"
|
|
needs to be included. The file "RtreeAlgebra.h" is included because
|
|
some operators get a rtree as argument.
|
|
|
|
*/
|
|
|
|
|
|
/*
|
|
The variables above define some global references to unique system-wide
|
|
instances of the query processor and the nested list storage.
|
|
|
|
1.2 Auxiliaries
|
|
|
|
Within this algebra module implementation, we have to handle values of
|
|
four different types defined in namespace ~symbols~: ~INT~ and ~REAL~, ~BOOL~
|
|
and ~STRING~. They are constant values of the C++-string class.
|
|
|
|
Moreover, for type mappings some auxiliary helper functions are defined in the
|
|
file "TypeMapUtils.h" which defines a namespace ~mappings~.
|
|
|
|
*/
|
|
|
|
|
|
double difftimeb( struct timeb* t1, struct timeb* t2 )
|
|
{
|
|
double dt1 = t1->time + (double)t1->millitm / 1000.0;
|
|
double dt2 = t2->time + (double)t2->millitm / 1000.0;
|
|
return dt1 - dt2;
|
|
}
|
|
|
|
|
|
struct timeb gt1;
|
|
struct timeb gt2;
|
|
|
|
/*
|
|
The implementation of the algebra is embedded into
|
|
a namespace ~near~ in order to avoid name conflicts with other modules.
|
|
|
|
*/
|
|
|
|
namespace near {
|
|
|
|
//const double DISTDELTA = 0.000000001;
|
|
//const double DISTDELTA = 0.00000000001;
|
|
|
|
const double DISTDELTA = 0.00001;
|
|
const double RDELTA = -0.000000015;
|
|
const double QUADDIFF = 0.0001;
|
|
|
|
|
|
inline bool almostEqual(double d1, double d2){
|
|
return std::abs(d1-d2) <= DISTDELTA;
|
|
}
|
|
|
|
|
|
inline bool almostSmaller(double d1, double slope1, double d2, double slope2){
|
|
if(almostEqual(d1,d2) && slope1<slope2){
|
|
return true;
|
|
}
|
|
return d1 < d2;
|
|
}
|
|
|
|
inline bool almostGreater(double d1, double slope1, double d2, double slope2){
|
|
if(almostEqual(d1,d2) && slope1>slope2){
|
|
return true;
|
|
}
|
|
return d1 > d2;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
2 Creating Operators
|
|
|
|
2.1 Type Mapping Functions
|
|
|
|
A type mapping function checks whether the correct argument types are supplied
|
|
for an operator; if so, it returns a list expression for the result type,
|
|
otherwise the symbol ~typeerror~. Again we use interface ~NList.h~ for
|
|
manipulating list expressions. For every operator is one type mapping
|
|
function given.
|
|
|
|
The function distanceScanTypeMap is the type map for distancescan.
|
|
|
|
*/
|
|
ListExpr
|
|
distanceScanTypeMap( ListExpr args )
|
|
{
|
|
|
|
std::string errmsg = "rtree x rel x rectangle x int expected";
|
|
if(nl->ListLength(args)!=4){
|
|
ErrorReporter::ReportError(errmsg + "(wrong number of arguments)");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
/* Split argument in four parts */
|
|
ListExpr rtreeDescription = nl->First(args);
|
|
ListExpr relDescription = nl->Second(args);
|
|
ListExpr searchWindow = nl->Third(args);
|
|
ListExpr quantity = nl->Fourth(args);
|
|
|
|
// check for fourth argument type == int
|
|
if(!nl->IsEqual(quantity,CcInt::BasicType())){
|
|
ErrorReporter::ReportError(errmsg + "(fourth arg not of type int)");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
if( ! listutils::isSpatialType(searchWindow) &&
|
|
! listutils::isRectangle(searchWindow)){
|
|
ErrorReporter::ReportError(errmsg +
|
|
"(searchwindow neither of kind spatial nor a rectangle)");
|
|
return listutils::typeError();
|
|
}
|
|
|
|
if(!listutils::isRTreeDescription(rtreeDescription)){
|
|
ErrorReporter::ReportError(errmsg + "(invalid rtree description)");
|
|
return listutils::typeError();
|
|
}
|
|
|
|
|
|
ListExpr rtreeKeyType = listutils::getRTreeType(rtreeDescription);
|
|
|
|
if( !listutils::isSpatialType(rtreeKeyType) &&
|
|
!listutils::isRectangle(rtreeKeyType)){
|
|
ErrorReporter::ReportError(errmsg + "(tree not over a spatial attribute)");
|
|
return listutils::typeError();
|
|
}
|
|
|
|
if(!listutils::isRelDescription(relDescription)){
|
|
ErrorReporter::ReportError(errmsg + "(second arg is not a relation)");
|
|
return listutils::typeError();
|
|
}
|
|
|
|
ListExpr rtreeTupleDescription = nl->Second(rtreeDescription);
|
|
if(!nl->Equal(rtreeTupleDescription, nl->Second(relDescription))){
|
|
ErrorReporter::ReportError(errmsg +
|
|
"(type of rtree and relation are different)");
|
|
return listutils::typeError();
|
|
}
|
|
|
|
// check for same dimension in rtree and query window
|
|
AlgebraManager *algMgr = SecondoSystem::GetAlgebraManager();
|
|
ListExpr errorInfo = listutils::emptyErrorInfo();
|
|
if( !(
|
|
( algMgr->CheckKind(Kind::SPATIAL2D(), rtreeKeyType, errorInfo) &&
|
|
nl->IsEqual(searchWindow, Rectangle<2>::BasicType()) ) ||
|
|
( algMgr->CheckKind(Kind::SPATIAL2D(), rtreeKeyType, errorInfo) &&
|
|
algMgr->CheckKind(Kind::SPATIAL2D(), searchWindow, errorInfo) ) ||
|
|
( nl->IsEqual(rtreeKeyType, Rectangle<2>::BasicType()) &&
|
|
nl->IsEqual(searchWindow, Rectangle<2>::BasicType()) ) ||
|
|
( algMgr->CheckKind(Kind::SPATIAL3D(), rtreeKeyType, errorInfo) &&
|
|
nl->IsEqual(searchWindow, Rectangle<3>::BasicType()) ) ||
|
|
( algMgr->CheckKind(Kind::SPATIAL3D(), rtreeKeyType, errorInfo) &&
|
|
algMgr->CheckKind(Kind::SPATIAL3D(), searchWindow, errorInfo) ) ||
|
|
( nl->IsEqual(rtreeKeyType, Rectangle<3>::BasicType()) &&
|
|
nl->IsEqual(searchWindow, Rectangle<3>::BasicType()) ) ||
|
|
( algMgr->CheckKind(Kind::SPATIAL4D(), rtreeKeyType, errorInfo) &&
|
|
nl->IsEqual(searchWindow, Rectangle<4>::BasicType()) ) ||
|
|
( algMgr->CheckKind(Kind::SPATIAL4D(), rtreeKeyType, errorInfo) &&
|
|
algMgr->CheckKind(Kind::SPATIAL4D(), searchWindow, errorInfo) ) ||
|
|
( nl->IsEqual(rtreeKeyType, Rectangle<4>::BasicType()) &&
|
|
nl->IsEqual(searchWindow, Rectangle<4>::BasicType()) ) ||
|
|
( algMgr->CheckKind(Kind::SPATIAL8D(), rtreeKeyType, errorInfo) &&
|
|
nl->IsEqual(searchWindow, Rectangle<8>::BasicType()) ) ||
|
|
( algMgr->CheckKind(Kind::SPATIAL8D(), rtreeKeyType, errorInfo) &&
|
|
algMgr->CheckKind(Kind::SPATIAL8D(), searchWindow, errorInfo) ) ||
|
|
( nl->IsEqual(rtreeKeyType, Rectangle<8>::BasicType()) &&
|
|
nl->IsEqual(searchWindow, Rectangle<8>::BasicType()) ))){
|
|
ErrorReporter::ReportError(errmsg + "(different dimensions)");
|
|
return nl->TypeError();
|
|
}
|
|
return
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->Second(relDescription));
|
|
}
|
|
|
|
|
|
ListExpr
|
|
distanceScan2STypeMap( ListExpr args ) {
|
|
|
|
std::string err = "rtree x SPATIAL x int expected";
|
|
if(!nl->HasLength(args,3)){
|
|
return listutils::typeError(err + " (wrong number of args)");
|
|
}
|
|
ListExpr rtree = nl->First(args);
|
|
ListExpr spatial = nl->Second(args);
|
|
ListExpr count = nl->Third(args);
|
|
if(!CcInt::checkType(count)){
|
|
return listutils::typeError(err + "(third arg is not an int)");
|
|
}
|
|
if( ! listutils::isSpatialType(spatial) &&
|
|
! listutils::isRectangle(spatial)){
|
|
return listutils::typeError(err + "(second arg is not SPATIAL)");
|
|
}
|
|
if(!listutils::isRTreeDescription(rtree)){
|
|
return listutils::typeError(err + "(first arg is not an r-tree)");
|
|
}
|
|
|
|
ListExpr rtreeKeyType = listutils::getRTreeType(rtree);
|
|
|
|
if( !listutils::isSpatialType(rtreeKeyType) &&
|
|
!listutils::isRectangle(rtreeKeyType)){
|
|
return listutils::typeError(err + "(invalid keyTpe in r-tree)");
|
|
}
|
|
// check for equal dimension in rtreekeyType and spatial
|
|
|
|
AlgebraManager *algMgr = SecondoSystem::GetAlgebraManager();
|
|
ListExpr errorInfo = listutils::emptyErrorInfo();
|
|
if( !(
|
|
( algMgr->CheckKind(Kind::SPATIAL2D(), rtreeKeyType, errorInfo) &&
|
|
nl->IsEqual(spatial, Rectangle<2>::BasicType()) ) ||
|
|
( algMgr->CheckKind(Kind::SPATIAL2D(), rtreeKeyType, errorInfo) &&
|
|
algMgr->CheckKind(Kind::SPATIAL2D(), spatial, errorInfo) ) ||
|
|
( nl->IsEqual(rtreeKeyType, Rectangle<2>::BasicType()) &&
|
|
nl->IsEqual(spatial, Rectangle<2>::BasicType()) ) ||
|
|
( algMgr->CheckKind(Kind::SPATIAL3D(), rtreeKeyType, errorInfo) &&
|
|
nl->IsEqual(spatial, Rectangle<3>::BasicType()) ) ||
|
|
( algMgr->CheckKind(Kind::SPATIAL3D(), rtreeKeyType, errorInfo) &&
|
|
algMgr->CheckKind(Kind::SPATIAL3D(), spatial, errorInfo) ) ||
|
|
( nl->IsEqual(rtreeKeyType, Rectangle<3>::BasicType()) &&
|
|
nl->IsEqual(spatial, Rectangle<3>::BasicType()) ) ||
|
|
( algMgr->CheckKind(Kind::SPATIAL4D(), rtreeKeyType, errorInfo) &&
|
|
nl->IsEqual(spatial, Rectangle<4>::BasicType()) ) ||
|
|
( algMgr->CheckKind(Kind::SPATIAL4D(), rtreeKeyType, errorInfo) &&
|
|
algMgr->CheckKind(Kind::SPATIAL4D(), spatial, errorInfo) ) ||
|
|
( nl->IsEqual(rtreeKeyType, Rectangle<4>::BasicType()) &&
|
|
nl->IsEqual(spatial, Rectangle<4>::BasicType()) ) ||
|
|
( algMgr->CheckKind(Kind::SPATIAL8D(), rtreeKeyType, errorInfo) &&
|
|
nl->IsEqual(spatial, Rectangle<8>::BasicType()) ) ||
|
|
( algMgr->CheckKind(Kind::SPATIAL8D(), rtreeKeyType, errorInfo) &&
|
|
algMgr->CheckKind(Kind::SPATIAL8D(), spatial, errorInfo) ) ||
|
|
( nl->IsEqual(rtreeKeyType, Rectangle<8>::BasicType()) &&
|
|
nl->IsEqual(spatial, Rectangle<8>::BasicType()) ))){
|
|
return listutils::typeError("different dimensions rtree x spatial");
|
|
}
|
|
|
|
ListExpr res =
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->TwoElemList(
|
|
listutils::basicSymbol<Tuple>(),
|
|
nl->OneElemList(
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("Id"),
|
|
listutils::basicSymbol<TupleIdentifier>()))));
|
|
return res;
|
|
}
|
|
|
|
|
|
|
|
ListExpr
|
|
distanceScan3TypeMap( ListExpr args ) {
|
|
|
|
bool maxD = false;
|
|
|
|
if(nl->ListLength(args) > 2){
|
|
ListExpr last = nl->TheEmptyList();
|
|
ListExpr args2 = nl->TheEmptyList();
|
|
bool first = true;
|
|
while(!nl->IsEmpty(args)){
|
|
ListExpr f = nl->First(args);
|
|
args = nl->Rest(args);
|
|
if(nl->IsEmpty(args)){ // f is the last argument
|
|
if(CcReal::checkType(f)){
|
|
maxD = true;
|
|
} else {
|
|
last = nl->Append(last, f);
|
|
}
|
|
} else {
|
|
if(first){
|
|
args2 = nl->OneElemList(f);
|
|
last = args2;
|
|
first = false;
|
|
} else {
|
|
last = nl->Append(last, f);
|
|
}
|
|
}
|
|
}
|
|
args = args2;
|
|
}
|
|
|
|
|
|
ListExpr res1;
|
|
ListExpr rtreetype;
|
|
int j = -1;
|
|
if(nl->ListLength(args)==5){
|
|
ListExpr First4 = nl->FourElemList(
|
|
nl->First(args),
|
|
nl->Second(args),
|
|
nl->Third(args),
|
|
nl->Fourth(args));
|
|
|
|
res1 = distanceScanTypeMap(First4);
|
|
if(nl->Equal(res1,nl->TypeError())){
|
|
return res1;
|
|
}
|
|
ListExpr attrNameList = nl->Fifth(args);
|
|
if(nl->AtomType(attrNameList)!=SymbolType){
|
|
ErrorReporter::ReportError("Invalid attribute name "
|
|
"given as fifth element");
|
|
return nl->TypeError();
|
|
}
|
|
std::string attrName = nl->SymbolValue(attrNameList);
|
|
ListExpr attrList = nl->Second(nl->Second(nl->Second(args)));
|
|
|
|
rtreetype = nl->Third(nl->First(args));
|
|
ListExpr attrType;
|
|
j = FindAttribute(attrList, attrName, attrType);
|
|
if(j==0){
|
|
ErrorReporter::ReportError("Attribute "+ attrName + " not found");
|
|
return nl->TypeError();
|
|
}
|
|
if(!nl->Equal(attrType,rtreetype)){
|
|
ErrorReporter::ReportError("different types of "
|
|
"attribute and rtree key");
|
|
return nl->TypeError();
|
|
}
|
|
} else if(nl->ListLength(args)!=4){
|
|
ErrorReporter::ReportError("Wronmg numer of parameters");
|
|
return nl->TypeError();
|
|
} else { // four parameter, spatial type must be unique
|
|
res1 = distanceScanTypeMap(args);
|
|
if(nl->Equal(res1,nl->TypeError())){
|
|
return nl->TypeError();
|
|
}
|
|
ListExpr attrList = nl->Second(nl->Second(nl->Second(args)));
|
|
rtreetype = nl->Third(nl->First(args));
|
|
|
|
// search for rtreetype in attrList and check if unique
|
|
int pos = 0;
|
|
while(!nl->IsEmpty(attrList)){
|
|
pos++;
|
|
ListExpr first = nl->First(attrList);
|
|
attrList = nl->Rest(attrList);
|
|
ListExpr type = nl->Second(first);
|
|
if(nl->Equal(type,rtreetype)){
|
|
if(j>0){
|
|
ErrorReporter::ReportError("Attribute not unique, "
|
|
"please append attribute name ");
|
|
return nl->TypeError();
|
|
} else {
|
|
j = pos;
|
|
}
|
|
}
|
|
}
|
|
if(j<0){
|
|
ErrorReporter::ReportError("tuple stream does not "
|
|
"contain an indexed attribute");
|
|
return nl->TypeError();
|
|
}
|
|
}
|
|
|
|
// check for allowed combinations
|
|
ListExpr queryTypeList = nl->Third(args);
|
|
if(nl->AtomType(queryTypeList)!=SymbolType){
|
|
ErrorReporter::ReportError("Unsupported type as querytype");
|
|
return nl->TypeError();
|
|
}
|
|
if(nl->AtomType(rtreetype)!=SymbolType){
|
|
ErrorReporter::ReportError("Unsupported type within the rtree");
|
|
return nl->TypeError();
|
|
}
|
|
std::string rt = nl->SymbolValue(rtreetype);
|
|
std::string qt = nl->SymbolValue(queryTypeList);
|
|
|
|
if( (rt != Point::BasicType()) && (rt != Points::BasicType()) &&
|
|
(rt != Line::BasicType()) && (rt != Region::BasicType()) &&
|
|
(rt != Rectangle<2>::BasicType())){
|
|
ErrorReporter::ReportError("Unsupported type within the rtree");
|
|
return nl->TypeError();
|
|
}
|
|
if( (qt != Point::BasicType()) && (qt != Points::BasicType()) &&
|
|
(qt != Line::BasicType()) && (qt != Region::BasicType()) &&
|
|
(qt != Rectangle<2>::BasicType())){
|
|
ErrorReporter::ReportError("Unsupported type for query object");
|
|
return nl->TypeError();
|
|
}
|
|
return nl->ThreeElemList(
|
|
nl->SymbolAtom(Symbol::APPEND()),
|
|
nl->TwoElemList( nl->IntAtom(j-1),
|
|
nl->BoolAtom(maxD)),
|
|
res1);
|
|
}
|
|
|
|
/*
|
|
rtree3(upoint) x rel x point x instant x int [ x attrname]
|
|
|
|
*/
|
|
|
|
ListExpr distanceScan4TypeMap(ListExpr args){
|
|
std::string err = "rtree3(upoint) x rel x point x "
|
|
"instant x int [x attrname] expected";
|
|
int len = nl->ListLength(args);
|
|
if((len!=5) && (len!=6)){
|
|
ErrorReporter::ReportError(err + " (invalid number of arguments)");
|
|
return listutils::typeError();
|
|
}
|
|
if(!listutils::isRTreeDescription(nl->First(args))){
|
|
ErrorReporter::ReportError(err + " (invalid rtree)");
|
|
return listutils::typeError();
|
|
}
|
|
if(!nl->IsEqual(nl->First(nl->First(args)),RTree3TID::BasicType())){
|
|
ErrorReporter::ReportError(err + " (invalid rtree dimension)");
|
|
return listutils::typeError();
|
|
}
|
|
|
|
if(!listutils::isRelDescription(nl->Second(args))){
|
|
ErrorReporter::ReportError(err + " (invalid relation)");
|
|
return listutils::typeError();
|
|
}
|
|
if(!nl->IsEqual(nl->Third(args),Point::BasicType())){
|
|
ErrorReporter::ReportError(err + " (invalid point)");
|
|
return listutils::typeError();
|
|
}
|
|
if(!nl->IsEqual(nl->Fourth(args),Instant::BasicType())){
|
|
ErrorReporter::ReportError(err + " (invalid instant)");
|
|
return listutils::typeError();
|
|
}
|
|
if(!nl->IsEqual(nl->Fifth(args),CcInt::BasicType())){
|
|
ErrorReporter::ReportError(err + " (invalid int)");
|
|
return listutils::typeError();
|
|
}
|
|
|
|
// relation and rtree must have the same tuple type
|
|
if(!nl->Equal(nl->Second(nl->First(args)), nl->Second(nl->Second(args)))){
|
|
ErrorReporter::ReportError(err + " (different type of rtree and rel)");
|
|
return listutils::typeError();
|
|
}
|
|
ListExpr rtreekey = listutils::getRTreeType(nl->First(args));
|
|
if(!nl->IsEqual(rtreekey,UPoint::BasicType())){
|
|
ErrorReporter::ReportError(err + " (rtree not build on upoint)");
|
|
return listutils::typeError();
|
|
}
|
|
|
|
ListExpr attrList = nl->Second(nl->Second(nl->Second(args)));
|
|
ListExpr res1 = nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->Second(nl->Second(args)));
|
|
if(len==6){
|
|
ListExpr aname = nl->Sixth(args);
|
|
if(nl->AtomType(aname)!=SymbolType){
|
|
ErrorReporter::ReportError(err + " (invalid attribute name)");
|
|
return listutils::typeError();
|
|
}
|
|
std::string name = nl->SymbolValue(aname);
|
|
ListExpr type;
|
|
int j = listutils::findAttribute(attrList, name, type);
|
|
if(!j){
|
|
ErrorReporter::ReportError(err + " (attribute not found)");
|
|
return listutils::typeError();
|
|
}
|
|
if(!nl->IsEqual(type,UPoint::BasicType()) ){
|
|
ErrorReporter::ReportError(err + " (attribute not a upoint)");
|
|
return listutils::typeError();
|
|
}
|
|
return nl->ThreeElemList(nl->SymbolAtom(Symbol::APPEND()),
|
|
nl->OneElemList(nl->IntAtom(j)),
|
|
res1);
|
|
} else { // length ==5
|
|
std::string name;
|
|
int j = listutils::findType(attrList,
|
|
nl->SymbolAtom(UPoint::BasicType()),name);
|
|
if(!j){
|
|
ErrorReporter::ReportError(err + " (no upoint stored in relation)");
|
|
return listutils::typeError();
|
|
}
|
|
int j2 = listutils::findType(attrList,
|
|
nl->SymbolAtom(UPoint::BasicType()),
|
|
name,
|
|
j+1);
|
|
if(j2){
|
|
ErrorReporter::ReportError(err + " (upoint stored twice in relation)");
|
|
return listutils::typeError();
|
|
}
|
|
return nl->ThreeElemList(nl->SymbolAtom(Symbol::APPEND()),
|
|
nl->TwoElemList(nl->IntAtom(j), nl->IntAtom(j)),
|
|
res1);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
The function knearestTypeMap is the type map for the operator knearest
|
|
|
|
*/
|
|
template<bool allowZone>
|
|
ListExpr KnearestTypeMap( ListExpr args )
|
|
{
|
|
std::string msg = "stream x attrname x mpoint x int ";
|
|
if(allowZone){
|
|
msg += "[x int] expected";
|
|
} else {
|
|
msg += "expected";
|
|
}
|
|
|
|
int len = nl->ListLength(args);
|
|
if(len !=4 && len!=5){
|
|
return listutils::typeError(msg + "(invalid number of arguments)");
|
|
}
|
|
if(!allowZone && len!=4){
|
|
return listutils::typeError(msg + "(invalid number of arguments)");
|
|
}
|
|
|
|
ListExpr stream = nl->First(args);
|
|
ListExpr attrName = nl->Second(args);
|
|
ListExpr mpoint = nl->Third(args);
|
|
ListExpr card = nl->Fourth(args);
|
|
|
|
if(!Stream<Tuple>::checkType(stream)){
|
|
return listutils::typeError(msg+" (first arg is not a stream)");
|
|
}
|
|
if(!MPoint::checkType(mpoint)){
|
|
return listutils::typeError(msg+" (third arg is not an mpoint)");
|
|
}
|
|
if(!CcInt::checkType(card)){
|
|
return listutils::typeError(msg+" (fourth arg is not an int)");
|
|
}
|
|
if(nl->AtomType(attrName)!=SymbolType){
|
|
return listutils::typeError(msg+" (second arg is not an attrname)");
|
|
}
|
|
|
|
int j;
|
|
ListExpr attrType;
|
|
std::string attr = nl->SymbolValue(attrName);
|
|
j = FindAttribute(nl->Second(nl->Second(stream)),
|
|
attr,attrType);
|
|
|
|
if(j==0) {
|
|
return listutils::typeError(msg+" (attrName " + attr
|
|
+ "not found in attributes)");
|
|
}
|
|
if(!UPoint::checkType(attrType)){
|
|
return listutils::typeError(msg+" (attrName " + attr
|
|
+ " does not refer to an upoint)");
|
|
}
|
|
|
|
if(len==5){ // zone given
|
|
ListExpr zone = nl->Fifth(args);
|
|
if(!CcInt::checkType(zone)){
|
|
return listutils::typeError(msg + " (fifth argument is not an int)");
|
|
}
|
|
}
|
|
return nl->ThreeElemList(
|
|
nl->SymbolAtom(Symbol::APPEND()),
|
|
nl->OneElemList(nl->IntAtom(j)),
|
|
stream);
|
|
}
|
|
|
|
|
|
/*
|
|
The function knearestdistTypeMap is the type map for the operator knearestdist
|
|
|
|
*/
|
|
ListExpr knearestdistTypeMap( ListExpr args )
|
|
{
|
|
std::string msg = "stream x attrname x mpoint x int expected";
|
|
if(nl->ListLength(args)!=4){
|
|
ErrorReporter::ReportError(msg + "(invalid number of arguments");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
ListExpr stream = nl->First(args);
|
|
ListExpr attrName = nl->Second(args);
|
|
ListExpr mpoint = nl->Third(args);
|
|
ListExpr card = nl->Fourth(args);
|
|
|
|
if(!IsStreamDescription(stream)){
|
|
ErrorReporter::ReportError(msg+" (first arg is not a stream)");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
if(!nl->IsEqual(mpoint,MPoint::BasicType())){
|
|
ErrorReporter::ReportError(msg+" (third arg is not an mpoint)");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
if(!(nl->IsEqual(card,CcInt::BasicType()) ||
|
|
nl->IsEqual(card,CcReal::BasicType()))){
|
|
ErrorReporter::ReportError(msg+" (fourth arg is not an int)");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
if(nl->AtomType(attrName)!=SymbolType){
|
|
ErrorReporter::ReportError(msg+" (second arg is not an attrname)");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
int j;
|
|
ListExpr attrType;
|
|
j = FindAttribute(nl->Second(nl->Second(stream)),
|
|
nl->SymbolValue(attrName),attrType);
|
|
|
|
if(j==0) {
|
|
ErrorReporter::ReportError(msg+" (attrName not found in attributes)");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
if(!nl->IsEqual(attrType,UPoint::BasicType())){
|
|
ErrorReporter::ReportError(msg+" (attrName does not refer to an upoint)");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
ListExpr res = nl->TypeError();
|
|
if(nl->IsEqual(card,CcReal::BasicType())){
|
|
res = nl->TwoElemList(
|
|
nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom(Tuple::BasicType()),
|
|
|
|
// nl->TwoElemList(
|
|
// nl->TwoElemList(
|
|
// nl->SymbolAtom("KNeighbor"),
|
|
// nl->SymbolAtom(UPoint::BasicType())),
|
|
// nl->TwoElemList(
|
|
// nl->SymbolAtom("Dist"),
|
|
// nl->SymbolAtom(MReal::BasicType()))
|
|
// )));
|
|
|
|
nl->OneElemList(
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("KNeighbor"),
|
|
nl->SymbolAtom(UPoint::BasicType()))
|
|
)));
|
|
|
|
}
|
|
if(nl->IsEqual(card,CcInt::BasicType())){
|
|
res = nl->SymbolAtom(MReal::BasicType());
|
|
}
|
|
|
|
|
|
return nl->ThreeElemList(
|
|
nl->SymbolAtom(Symbol::APPEND()),
|
|
nl->OneElemList(nl->IntAtom(j)),
|
|
res);
|
|
|
|
|
|
}
|
|
|
|
/*
|
|
The function oldknearestFilterTypeMap is the type map for the
|
|
operator knearestfilter
|
|
|
|
*/
|
|
ListExpr
|
|
oldknearestFilterTypeMap( ListExpr args )
|
|
{
|
|
AlgebraManager *algMgr = SecondoSystem::GetAlgebraManager();
|
|
ListExpr errorInfo = nl->OneElemList( nl->SymbolAtom( "ERROR" ) );
|
|
|
|
std::string errmsg = "rtree x relation x mpoint x int expected";
|
|
|
|
if(nl->ListLength(args)!=4){
|
|
ErrorReporter::ReportError(errmsg);
|
|
return nl->TypeError();
|
|
}
|
|
ListExpr rtreeDescription = nl->First(args);
|
|
ListExpr relDescription = nl->Second(args);
|
|
ListExpr mpoint = nl->Third(args);
|
|
ListExpr quantity = nl->Fourth(args);
|
|
|
|
// the third element has to be of type mpoint
|
|
if(!nl->IsEqual(mpoint,MPoint::BasicType())){
|
|
ErrorReporter::ReportError(errmsg);
|
|
return nl->TypeError();
|
|
}
|
|
|
|
// the third element has to be of type mpoint
|
|
if(!nl->IsEqual(quantity,CcInt::BasicType())){
|
|
ErrorReporter::ReportError(errmsg);
|
|
return nl->TypeError();
|
|
}
|
|
|
|
// an rtree description must have length 4
|
|
if(nl->ListLength(rtreeDescription)!=4){
|
|
ErrorReporter::ReportError(errmsg);
|
|
return nl->TypeError();
|
|
}
|
|
|
|
ListExpr rtreeSymbol = nl->First(rtreeDescription),
|
|
rtreeTupleDescription = nl->Second(rtreeDescription),
|
|
rtreeKeyType = nl->Third(rtreeDescription),
|
|
rtreeTwoLayer = nl->Fourth(rtreeDescription);
|
|
|
|
if(!nl->IsEqual(rtreeSymbol, RTree3TID::BasicType())){
|
|
ErrorReporter::ReportError(errmsg);
|
|
return nl->TypeError();
|
|
}
|
|
|
|
// the keytype of the rtree must be of kind SPATIAL3D
|
|
if(!algMgr->CheckKind(Kind::SPATIAL3D(), rtreeKeyType, errorInfo) &&
|
|
!nl->IsEqual(rtreeKeyType,Rectangle<3>::BasicType())){
|
|
ErrorReporter::ReportError(errmsg);
|
|
return nl->TypeError();
|
|
}
|
|
|
|
if(nl->ListLength(rtreeTupleDescription)!=2){
|
|
ErrorReporter::ReportError(errmsg);
|
|
return nl->TypeError();
|
|
}
|
|
|
|
if(!nl->IsEqual(nl->First(rtreeTupleDescription),Tuple::BasicType())){
|
|
ErrorReporter::ReportError(errmsg);
|
|
return nl->TypeError();
|
|
}
|
|
|
|
if(!IsTupleDescription(nl->Second(rtreeTupleDescription))){
|
|
ErrorReporter::ReportError(errmsg);
|
|
return nl->TypeError();
|
|
}
|
|
|
|
if(nl->AtomType(rtreeTwoLayer)!=BoolType){
|
|
ErrorReporter::ReportError(errmsg);
|
|
return nl->TypeError();
|
|
}
|
|
|
|
if(!IsRelDescription(relDescription)){
|
|
ErrorReporter::ReportError(errmsg);
|
|
return nl->TypeError();
|
|
}
|
|
|
|
ListExpr rtreeAttrList = nl->Second(rtreeTupleDescription);
|
|
ListExpr relAttrList = nl->Second(nl->Second(relDescription));
|
|
|
|
if(!nl->Equal(rtreeAttrList, relAttrList)){
|
|
ErrorReporter::ReportError("relation and rtree have"
|
|
" not the same attrlist");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
return
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->Second(nl->Second(args)));
|
|
}
|
|
|
|
|
|
/*
|
|
2.1.10 rect2periods TypeMap
|
|
|
|
signatur ist rect3 -> periods
|
|
|
|
*/
|
|
ListExpr rect2periodsTypeMap(ListExpr args){
|
|
if(nl->ListLength(args)!=1){
|
|
ErrorReporter::ReportError("Invalid number of arguments");
|
|
return nl->TypeError();
|
|
}
|
|
ListExpr arg = nl->First(args);
|
|
if(!nl->IsEqual(arg,Rectangle<3>::BasicType())){
|
|
ErrorReporter::ReportError("rect3 expected");
|
|
return nl->TypeError();
|
|
}
|
|
return nl->SymbolAtom(Periods::BasicType());
|
|
}
|
|
|
|
/*
|
|
2.1.11 isknn TypeMap
|
|
|
|
v in {int | string} x string(rel) x string(btree) x
|
|
string(MBool) x string(ID) -> APPEND v mbool
|
|
|
|
*/
|
|
ListExpr isknnTypeMap(ListExpr args){
|
|
std::string idtype="";
|
|
if(nl->ListLength(args)!=5){
|
|
ErrorReporter::ReportError("isknn: Invalid number of arguments");
|
|
return nl->TypeError();
|
|
}
|
|
ListExpr arg1 = nl->First(args);
|
|
idtype = nl->ToString(arg1);
|
|
if(!nl->IsEqual(arg1,CcInt::BasicType()) &&
|
|
!nl->IsEqual(arg1,CcString::BasicType()) ){
|
|
ErrorReporter::ReportError("isknn: expected int or string identifier");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
ListExpr arg2 = nl->Second(args);
|
|
if(!nl->IsEqual(arg2,CcString::BasicType())){
|
|
ErrorReporter::ReportError("isknn: expected relation name");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
ListExpr arg3 = nl->Third(args);
|
|
if(!nl->IsEqual(arg3,CcString::BasicType())){
|
|
ErrorReporter::ReportError("isknn: expected btree name");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
ListExpr arg4 = nl->Fourth(args);
|
|
if(!nl->IsEqual(arg4,CcString::BasicType())){
|
|
ErrorReporter::ReportError("isknn: expected a valid mpoint attribute name");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
ListExpr arg5 = nl->Fifth(args);
|
|
if(!nl->IsEqual(arg5,CcString::BasicType())){
|
|
ErrorReporter::ReportError("isknn: expected a valid id attribute name");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
ListExpr res= nl->ThreeElemList( nl->SymbolAtom(Symbol::APPEND()),
|
|
nl->OneElemList(nl->StringAtom(idtype)),
|
|
nl->SymbolAtom(MBool::BasicType()));
|
|
cout<< nl->ToString(res);
|
|
cout.flush();
|
|
return res;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
2.2 Selection Function
|
|
|
|
A selection function is quite similar to a type mapping function. The only
|
|
difference is that it doesn't return a type but the index of a value
|
|
mapping function being able to deal with the respective combination of
|
|
input parameter types.
|
|
|
|
Note that a selection function does not need to check the correctness of
|
|
argument types; this has already been checked by the type mapping function.
|
|
A selection function is only called if the type mapping was successful. This
|
|
makes programming easier as one can rely on a correct structure of the list
|
|
~args~.
|
|
|
|
*/
|
|
|
|
int
|
|
distanceScanSelect( ListExpr args )
|
|
{
|
|
AlgebraManager *algMgr = SecondoSystem::GetAlgebraManager();
|
|
ListExpr searchWindow;
|
|
if(nl->HasLength(args,3)){
|
|
searchWindow = nl->Second(args);
|
|
} else {
|
|
searchWindow = nl->Third(args);
|
|
}
|
|
ListExpr errorInfo = nl->OneElemList( nl->SymbolAtom( Symbol::ERRORS() ) );
|
|
|
|
if (nl->SymbolValue(searchWindow) == Rectangle<2>::BasicType() ||
|
|
algMgr->CheckKind(Kind::SPATIAL2D(), searchWindow, errorInfo))
|
|
return 0;
|
|
else if (nl->SymbolValue(searchWindow) == Rectangle<3>::BasicType() ||
|
|
algMgr->CheckKind(Kind::SPATIAL3D(), searchWindow, errorInfo))
|
|
return 1;
|
|
else if (nl->SymbolValue(searchWindow) == Rectangle<4>::BasicType() ||
|
|
algMgr->CheckKind(Kind::SPATIAL4D(), searchWindow, errorInfo))
|
|
return 2;
|
|
else if (nl->SymbolValue(searchWindow) == Rectangle<8>::BasicType() ||
|
|
algMgr->CheckKind(Kind::SPATIAL8D(), searchWindow, errorInfo))
|
|
return 3;
|
|
|
|
return -1; /* should not happen */
|
|
}
|
|
|
|
int distanceScan3Select(ListExpr args){
|
|
// type indxed by the rtree
|
|
std::string t1 = nl->SymbolValue(nl->Third(nl->First(args)));
|
|
// typr of query object
|
|
std::string t2 = nl->SymbolValue(nl->Third(args));
|
|
|
|
if(t1==Point::BasicType()){
|
|
if(t2==Point::BasicType()) return 0;
|
|
if(t2==Points::BasicType()) return 1;
|
|
if(t2==Line::BasicType()) return 2;
|
|
if(t2==Region::BasicType()) return 3;
|
|
if(t2==Rectangle<2>::BasicType()) return 4;
|
|
}
|
|
if(t1==Points::BasicType()){
|
|
if(t2==Point::BasicType()) return 5;
|
|
if(t2==Points::BasicType()) return 6;
|
|
if(t2==Line::BasicType()) return 7;
|
|
if(t2==Region::BasicType()) return 8;
|
|
if(t2==Rectangle<2>::BasicType()) return 9;
|
|
}
|
|
if(t1==Line::BasicType()){
|
|
if(t2==Point::BasicType()) return 10;
|
|
if(t2==Points::BasicType()) return 11;
|
|
if(t2==Line::BasicType()) return 12;
|
|
if(t2==Region::BasicType()) return 13;
|
|
if(t2==Rectangle<2>::BasicType()) return 14;
|
|
}
|
|
if(t1==Region::BasicType()){
|
|
if(t2==Point::BasicType()) return 15;
|
|
if(t2==Points::BasicType()) return 16;
|
|
if(t2==Line::BasicType()) return 17;
|
|
if(t2==Region::BasicType()) return 18;
|
|
if(t2==Rectangle<2>::BasicType()) return 19;
|
|
}
|
|
if(t1==Rectangle<2>::BasicType()){
|
|
if(t2==Point::BasicType()) return 20;
|
|
if(t2==Points::BasicType()) return 21;
|
|
if(t2==Line::BasicType()) return 22;
|
|
if(t2==Region::BasicType()) return 23;
|
|
if(t2==Rectangle<2>::BasicType()) return 24;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int knearestdistSelect(ListExpr args)
|
|
{
|
|
std::string msg = "stream x attrname x mpoint x int expected";
|
|
if(nl->ListLength(args)!=4){
|
|
ErrorReporter::ReportError(msg + "(invalid number of arguments");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
ListExpr stream = nl->First(args);
|
|
ListExpr mpoint = nl->Third(args);
|
|
ListExpr card = nl->Fourth(args);
|
|
|
|
if(!IsStreamDescription(stream)){
|
|
ErrorReporter::ReportError(msg+" (first arg is not a stream)");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
if(!nl->IsEqual(mpoint,MPoint::BasicType())){
|
|
ErrorReporter::ReportError(msg+" (third arg is not an mpoint)");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
if(nl->IsEqual(card,CcReal::BasicType())){
|
|
return 0;
|
|
}
|
|
|
|
if(nl->IsEqual(card,CcInt::BasicType())){
|
|
return 1;
|
|
}
|
|
|
|
return -1;
|
|
|
|
|
|
}
|
|
|
|
/*
|
|
2.3 Value Mapping Functions
|
|
|
|
For any operator a value mapping function must be defined. It contains
|
|
the code which gives an operator its functionality
|
|
|
|
The struct DistanceScanLocalInfo is needed to save the data
|
|
from one to next function call
|
|
|
|
*/
|
|
|
|
template <unsigned dim, class LeafInfo>
|
|
struct DistanceScanLocalInfo
|
|
{
|
|
Relation* relation;
|
|
R_Tree<dim, TupleId>* rtree;
|
|
BBox<dim> position;
|
|
int quantity, noFound;
|
|
bool scanFlag;
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
The ~distanceScan~ results a stream of all input tuples in the
|
|
right order. It returns the k tuples with the lowest distance to a given
|
|
reference point. The are ordered by distance to the given reference point.
|
|
If the last parameter k has a value <= 0, all tuples of the input stream
|
|
will returned.
|
|
|
|
*/
|
|
|
|
template <unsigned dim>
|
|
int distanceScanFun (Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
DistanceScanLocalInfo<dim, TupleId> *localInfo =
|
|
(DistanceScanLocalInfo<dim, TupleId>*) local.addr;
|
|
|
|
switch (message)
|
|
{
|
|
case OPEN :
|
|
{
|
|
if(localInfo){
|
|
localInfo->rtree->LastDistanceScan();
|
|
delete localInfo;
|
|
}
|
|
localInfo = new DistanceScanLocalInfo<dim, TupleId>;
|
|
localInfo->rtree = (R_Tree<dim, TupleId>*)args[0].addr;
|
|
localInfo->relation = (Relation*)args[1].addr;
|
|
StandardSpatialAttribute<dim>* pos =
|
|
(StandardSpatialAttribute<dim> *)args[2].addr;
|
|
localInfo->position = pos->BoundingBox();
|
|
|
|
localInfo->quantity = ((CcInt*)args[3].addr)->GetIntval();
|
|
localInfo->noFound = 0;
|
|
localInfo->scanFlag = true;
|
|
|
|
assert(localInfo->rtree != 0);
|
|
assert(localInfo->relation != 0);
|
|
localInfo->rtree->FirstDistanceScan(localInfo->position);
|
|
local = SetWord(localInfo);
|
|
return 0;
|
|
}
|
|
|
|
case REQUEST :
|
|
{
|
|
if(!local.addr){
|
|
return CANCEL;
|
|
}
|
|
localInfo = (DistanceScanLocalInfo<dim, TupleId>*)local.addr;
|
|
if ( !localInfo->scanFlag )
|
|
{
|
|
return CANCEL;
|
|
}
|
|
|
|
if ( (localInfo->quantity <= 0) ||
|
|
(localInfo->noFound >=localInfo->quantity))
|
|
{
|
|
return CANCEL;
|
|
}
|
|
|
|
TupleId tid;
|
|
if ( localInfo->rtree->NextDistanceScan( localInfo->position, tid ) )
|
|
{
|
|
Tuple *tuple = localInfo->relation->GetTuple(tid, false);
|
|
result = SetWord(tuple);
|
|
++(localInfo->noFound);
|
|
return YIELD;
|
|
}
|
|
else
|
|
{
|
|
return CANCEL;
|
|
}
|
|
}
|
|
|
|
case CLOSE :
|
|
{
|
|
if(localInfo){
|
|
localInfo->rtree->LastDistanceScan();
|
|
delete localInfo;
|
|
local.addr = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
/* alternative implementation using only standard functions of the rtree */
|
|
template <unsigned dim>
|
|
class DSEntry{
|
|
public:
|
|
|
|
/*
|
|
~constructors~
|
|
|
|
*/
|
|
DSEntry(const R_TreeNode<dim, TupleId>& node1,
|
|
const StandardSpatialAttribute<dim>* qo1,
|
|
const int level1):
|
|
isTuple(false), node( new R_TreeNode<dim, TupleId>(node1)),
|
|
tupleId(0),level(level1){
|
|
distance = qo1->Distance(node1.BoundingBox());
|
|
}
|
|
|
|
DSEntry(const TupleId id,
|
|
const BBox<dim>& rect,
|
|
const StandardSpatialAttribute<dim>* qo,
|
|
const int level1):
|
|
isTuple(true), node(0), tupleId(id), level(level1){
|
|
distance = qo->Distance(rect);
|
|
}
|
|
|
|
DSEntry(const DSEntry<dim>& src):
|
|
isTuple(src.isTuple), node(0), tupleId(src.tupleId),
|
|
level(src.level), distance(src.distance){
|
|
if(src.node){
|
|
node = new R_TreeNode<dim, TupleId>(*src.node);
|
|
}
|
|
}
|
|
|
|
/*
|
|
~Assignment operator~
|
|
|
|
*/
|
|
DSEntry<dim>& operator=(const DSEntry<dim>& src){
|
|
isTuple = src.isTuple;
|
|
if(node){
|
|
delete node;
|
|
}
|
|
if(src.node){
|
|
node = new R_TreeNode<dim, TupleId>(*src.node);
|
|
} else {
|
|
node = 0;
|
|
}
|
|
tupleId = src.tupleId;
|
|
level = src.level;
|
|
distance = src.distance;
|
|
return *this;
|
|
}
|
|
|
|
/*
|
|
~Destructor~
|
|
|
|
*/
|
|
|
|
~DSEntry(){ delete node;}
|
|
|
|
|
|
/*
|
|
Check for a tuple entry.
|
|
|
|
*/
|
|
bool isTupleEntry() const{
|
|
return isTuple;
|
|
}
|
|
|
|
bool getLevel() const{
|
|
return level;
|
|
}
|
|
|
|
TupleId getTupleId() const{
|
|
return tupleId;
|
|
}
|
|
|
|
const R_TreeNode<dim,TupleId>* getNode() const {
|
|
return node;
|
|
}
|
|
|
|
inline int compare(const DSEntry<dim>& e) const{
|
|
if(distance < e.distance){
|
|
return -1;
|
|
}
|
|
if(distance > e.distance){
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
private:
|
|
bool isTuple;
|
|
R_TreeNode<dim, TupleId>* node;
|
|
TupleId tupleId;
|
|
int level;
|
|
double distance;
|
|
};
|
|
|
|
template<unsigned dim>
|
|
class DSEComp {
|
|
public:
|
|
bool operator()(const DSEntry<dim>* d1, const DSEntry<dim>* d2) const{
|
|
return d1->compare(*d2) >= 0;
|
|
}
|
|
};
|
|
|
|
|
|
|
|
template <unsigned dim>
|
|
class DSLocalInfo{
|
|
public:
|
|
DSLocalInfo( R_Tree<dim, TupleId>* rtree, Relation* rel,
|
|
StandardSpatialAttribute<dim>* queryObj, CcInt* k,
|
|
ListExpr resType){
|
|
// check if all things are defined
|
|
if( (rel!=0 && rel->GetNoTuples()==0) ||
|
|
!queryObj->IsDefined() ||
|
|
queryObj->IsEmpty() ||
|
|
!k->IsDefined()){
|
|
this->tree=0;
|
|
this->rel=0;
|
|
this->queryObj = 0;
|
|
this->k = 0;
|
|
this->returned = 0;
|
|
return;
|
|
}
|
|
if(!nl->IsEmpty(resType)){
|
|
tt = new TupleType(resType);
|
|
} else {
|
|
tt = 0;
|
|
}
|
|
|
|
this->tree = rtree;
|
|
this->rel = rel;
|
|
this->queryObj = queryObj;
|
|
this->k = k->GetIntval();
|
|
returned = 0;
|
|
R_TreeNode<dim, TupleId> root = rtree->Root();
|
|
// check for an emty tree
|
|
BBox<dim> box = root.BoundingBox();
|
|
if(!box.IsDefined()){
|
|
this->tree=0;
|
|
this->rel=0;
|
|
this->queryObj = 0;
|
|
this->k = 0;
|
|
this->returned = 0;
|
|
return;
|
|
}
|
|
height = tree->Height();
|
|
minInnerEntries = tree->MinEntries(0);
|
|
maxInnerEntries = tree->MaxEntries(0);
|
|
minLeafEntries = tree->MinEntries(height);
|
|
maxLeafEntries = tree->MaxEntries(height);
|
|
DSEntry<dim>* first = new DSEntry<dim>(root,queryObj, 0);
|
|
dsqueue.push(first);
|
|
}
|
|
|
|
~DSLocalInfo(){
|
|
while(!dsqueue.empty()){
|
|
DSEntry<dim>* t = dsqueue.top();
|
|
delete t;
|
|
dsqueue.pop();
|
|
}
|
|
if(tt){
|
|
tt->DeleteIfAllowed();
|
|
tt = 0;
|
|
}
|
|
}
|
|
|
|
|
|
TupleId* nextTupleID1(){
|
|
if(!tree){
|
|
return 0;
|
|
}
|
|
if(k>0 && returned==k){
|
|
return 0;
|
|
}
|
|
if(dsqueue.empty()){
|
|
return 0;
|
|
}
|
|
|
|
|
|
DSEntry<dim>* top = dsqueue.top();
|
|
// replace top entry of the queue by its sons
|
|
// until it's a tuple entry
|
|
while(!top->isTupleEntry()){
|
|
dsqueue.pop(); // remove top element
|
|
int level = top->getLevel();
|
|
// insert all sons
|
|
int minEntries,maxEntries;
|
|
level++; // level for the sons is increased
|
|
|
|
if(level>=height){
|
|
minEntries = this->minLeafEntries;
|
|
maxEntries = this->maxLeafEntries;
|
|
} else {
|
|
minEntries = this->minInnerEntries;
|
|
maxEntries = this->maxInnerEntries;
|
|
}
|
|
|
|
if(!top->getNode()->IsLeaf()){
|
|
for(int i = 0; i< top->getNode()->EntryCount();i++){
|
|
R_TreeInternalEntry<dim>* next=top->getNode()->GetInternalEntry(i);
|
|
SmiRecordId rid = next->pointer;
|
|
R_TreeNode<dim, TupleId> nextNode(true, minEntries, maxEntries);
|
|
tree->GetNode(rid, nextNode);
|
|
DSEntry<dim>* nextEntry =
|
|
new DSEntry<dim>(nextNode, queryObj, level);
|
|
dsqueue.push(nextEntry);
|
|
}
|
|
} else { // topmost node was a leaf
|
|
for(int i=0;i<top->getNode()->EntryCount();i++){
|
|
R_TreeLeafEntry<dim, TupleId>* le =
|
|
top->getNode()->GetLeafEntry(i);
|
|
DSEntry<dim>* nextEntry =
|
|
new DSEntry<dim>(le->info, le->box, queryObj, level);
|
|
dsqueue.push(nextEntry);
|
|
}
|
|
}
|
|
delete top; // delete the replaced top element
|
|
top = dsqueue.top();
|
|
}
|
|
dsqueue.pop();
|
|
// now we have a tuple
|
|
returned++;
|
|
TupleId* res = new TupleId(top->getTupleId());
|
|
delete top;
|
|
return res;
|
|
}
|
|
|
|
Tuple* nextTuple(){
|
|
TupleId* id = nextTupleID1();
|
|
if(id==0){
|
|
return 0;
|
|
} else {
|
|
Tuple* res = rel->GetTuple(*id, false);
|
|
delete id;
|
|
return res;
|
|
}
|
|
}
|
|
|
|
/* TupleIdentifier* nextTupleID(){
|
|
TupleId* id = nextTupleID1();
|
|
if(id==0){
|
|
return 0;
|
|
} else {
|
|
TupleIdentifier* res = new TupleIdentifier(true,*id);
|
|
delete id;
|
|
return res;
|
|
}
|
|
}
|
|
*/
|
|
Tuple* nextTIDTuple(){
|
|
TupleId* id = nextTupleID1();
|
|
if(id==0){
|
|
return 0;
|
|
} else {
|
|
TupleIdentifier* tid = new TupleIdentifier(true,*id);
|
|
delete id;
|
|
Tuple* res = new Tuple(tt);
|
|
res->PutAttribute(0,tid);
|
|
return res;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
R_Tree<dim, TupleId>* tree;
|
|
Relation* rel;
|
|
StandardSpatialAttribute<dim>* queryObj;
|
|
int k;
|
|
int returned; // number of returned tuples
|
|
int height;
|
|
int minInnerEntries;
|
|
int maxInnerEntries;
|
|
int minLeafEntries;
|
|
int maxLeafEntries;
|
|
std::priority_queue< DSEntry<dim>*,
|
|
std::vector<DSEntry<dim>* >,
|
|
DSEComp<dim> > dsqueue;
|
|
TupleType* tt;
|
|
};
|
|
|
|
|
|
template <unsigned dim>
|
|
int distanceScan2Fun (Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
switch(message){
|
|
case OPEN : {
|
|
if(local.addr){
|
|
DSLocalInfo<dim>* li = static_cast<DSLocalInfo<dim>*>(local.addr);
|
|
delete li;
|
|
}
|
|
R_Tree<dim, TupleId>* rtree =
|
|
static_cast<R_Tree<dim, TupleId> *>(args[0].addr);
|
|
Relation* rel = static_cast<Relation*>(args[1].addr);
|
|
StandardSpatialAttribute<dim>* queryObj =
|
|
static_cast<StandardSpatialAttribute<dim>*>(args[2].addr);
|
|
CcInt* k = static_cast<CcInt*>(args[3].addr);
|
|
local.addr = new DSLocalInfo<dim>(rtree, rel, queryObj, k,
|
|
nl->TheEmptyList());
|
|
return 0;
|
|
}
|
|
|
|
case REQUEST: {
|
|
if(!local.addr){
|
|
return CANCEL;
|
|
} else {
|
|
DSLocalInfo<dim>* li = static_cast<DSLocalInfo<dim>*>(local.addr);
|
|
result.addr = li->nextTuple();
|
|
return result.addr ? YIELD : CANCEL;
|
|
}
|
|
}
|
|
|
|
case CLOSE:{
|
|
if(local.addr){
|
|
DSLocalInfo<dim>* li = static_cast<DSLocalInfo<dim>*>(local.addr);
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
default : assert(false);
|
|
}
|
|
}
|
|
|
|
|
|
template <unsigned dim>
|
|
int distanceScan2SFun (Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
switch(message){
|
|
case OPEN : {
|
|
if(local.addr){
|
|
DSLocalInfo<dim>* li = static_cast<DSLocalInfo<dim>*>(local.addr);
|
|
delete li;
|
|
}
|
|
R_Tree<dim, TupleId>* rtree =
|
|
static_cast<R_Tree<dim, TupleId> *>(args[0].addr);
|
|
StandardSpatialAttribute<dim>* queryObj =
|
|
static_cast<StandardSpatialAttribute<dim>*>(args[1].addr);
|
|
CcInt* k = static_cast<CcInt*>(args[2].addr);
|
|
local.addr = new DSLocalInfo<dim>(rtree, 0, queryObj, k,
|
|
nl->Second(GetTupleResultType(s)));
|
|
return 0;
|
|
}
|
|
|
|
case REQUEST: {
|
|
if(!local.addr){
|
|
return CANCEL;
|
|
} else {
|
|
DSLocalInfo<dim>* li = static_cast<DSLocalInfo<dim>*>(local.addr);
|
|
result.addr = li->nextTIDTuple();
|
|
return result.addr ? YIELD : CANCEL;
|
|
}
|
|
}
|
|
|
|
case CLOSE:{
|
|
if(local.addr){
|
|
DSLocalInfo<dim>* li = static_cast<DSLocalInfo<dim>*>(local.addr);
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
default : assert(false);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
~distanceScan 3~
|
|
|
|
The distance scan 3 works for all 2 dimensional spatial attributes.
|
|
|
|
*/
|
|
|
|
template <unsigned dim, class IndexedType, class QueryType, class DistFun>
|
|
class DS3Entry{
|
|
public:
|
|
|
|
/*
|
|
~constructors~
|
|
|
|
*/
|
|
DS3Entry(const R_TreeNode<dim, TupleId>& node1,
|
|
const QueryType* qo1,
|
|
const int level1):
|
|
isTuple(false), node( new R_TreeNode<dim, TupleId>(node1)),
|
|
tupleId(0),level(level1){
|
|
distance = qo1->Distance(node1.BoundingBox());
|
|
}
|
|
|
|
DS3Entry(const TupleId id,
|
|
const BBox<dim>& rect,
|
|
const QueryType* qo,
|
|
const int level1,
|
|
const Relation* relation,
|
|
const int attrpos,
|
|
const DistFun& df):
|
|
isTuple(true), node(0), tupleId(id), level(level1){
|
|
|
|
Tuple* tuple = relation->GetTuple(id,false);
|
|
const IndexedType* obj =
|
|
static_cast<IndexedType*>(tuple->GetAttribute(attrpos));
|
|
distance = df(*qo,*obj);
|
|
tuple->DeleteIfAllowed();
|
|
}
|
|
|
|
DS3Entry(const DS3Entry<dim, IndexedType, QueryType, DistFun>& src):
|
|
isTuple(src.isTuple), node(0), tupleId(src.tupleId),
|
|
level(src.level), distance(src.distance){
|
|
if(src.node){
|
|
node = new R_TreeNode<dim, TupleId>(*src.node);
|
|
}
|
|
}
|
|
|
|
/*
|
|
~Assignment operator~
|
|
|
|
*/
|
|
DS3Entry<dim,IndexedType, QueryType, DistFun>&
|
|
operator=(const DS3Entry<dim, IndexedType, QueryType, DistFun>& src){
|
|
isTuple = src.isTuple;
|
|
if(node){
|
|
delete node;
|
|
}
|
|
if(src.node){
|
|
node = new R_TreeNode<dim, TupleId>(*src.node);
|
|
} else {
|
|
node = 0;
|
|
}
|
|
tupleId = src.tupleId;
|
|
level = src.level;
|
|
distance = src.distance;
|
|
return *this;
|
|
}
|
|
|
|
/*
|
|
~Destructor~
|
|
|
|
*/
|
|
|
|
~DS3Entry(){ delete node;}
|
|
|
|
|
|
/*
|
|
Check for a tuple entry.
|
|
|
|
*/
|
|
bool isTupleEntry() const{
|
|
return isTuple;
|
|
}
|
|
|
|
bool getLevel() const{
|
|
return level;
|
|
}
|
|
|
|
TupleId getTupleId() const{
|
|
return tupleId;
|
|
}
|
|
|
|
const R_TreeNode<dim,TupleId>* getNode() const {
|
|
return node;
|
|
}
|
|
|
|
inline int compare(const DS3Entry<dim, IndexedType,
|
|
QueryType, DistFun>& e) const{
|
|
if(distance < e.distance){
|
|
return -1;
|
|
}
|
|
if(distance > e.distance){
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
double getDistance() const{
|
|
return distance;
|
|
}
|
|
|
|
private:
|
|
bool isTuple;
|
|
R_TreeNode<dim, TupleId>* node;
|
|
TupleId tupleId;
|
|
int level;
|
|
double distance;
|
|
};
|
|
|
|
template<unsigned dim, class IndexedType, class QueryType, class DistFun>
|
|
class DSE3Comp {
|
|
public:
|
|
bool operator()(
|
|
const DS3Entry<dim, IndexedType, QueryType, DistFun>* d1,
|
|
const DS3Entry<dim, IndexedType, QueryType, DistFun>* d2) const{
|
|
return d1->compare(*d2) >= 0;
|
|
}
|
|
};
|
|
|
|
template <unsigned dim, class IndexedType, class QueryType, class DistFun>
|
|
class DS3LocalInfo{
|
|
public:
|
|
DS3LocalInfo( R_Tree<dim, TupleId>* rtree, Relation* rel,
|
|
QueryType* queryObj, CcInt* k, int position,
|
|
CcReal& _maxDist){
|
|
|
|
// process maxDist
|
|
if(!_maxDist.IsDefined()){
|
|
useMaxDist = false;
|
|
maxDist = 0.0;
|
|
} else {
|
|
useMaxDist = true;
|
|
maxDist = _maxDist.GetValue();
|
|
}
|
|
|
|
// check if all things are defined
|
|
this->position = position;
|
|
if(rel->GetNoTuples()==0 ||
|
|
!queryObj->IsDefined() ||
|
|
queryObj->IsEmpty() ||
|
|
!k->IsDefined()){
|
|
this->tree=0;
|
|
this->rel=0;
|
|
this->queryObj = 0;
|
|
this->k = 0;
|
|
this->returned = 0;
|
|
return;
|
|
}
|
|
this->tree = rtree;
|
|
this->rel = rel;
|
|
this->queryObj = queryObj;
|
|
this->k = k->GetIntval();
|
|
returned = 0;
|
|
R_TreeNode<dim, TupleId> root = rtree->Root();
|
|
// check for an emty tree
|
|
BBox<dim> box = root.BoundingBox();
|
|
if(!box.IsDefined()){
|
|
this->tree=0;
|
|
this->rel=0;
|
|
this->queryObj = 0;
|
|
this->k = 0;
|
|
this->returned = 0;
|
|
return;
|
|
}
|
|
height = tree->Height();
|
|
minInnerEntries = tree->MinEntries(0);
|
|
maxInnerEntries = tree->MaxEntries(0);
|
|
minLeafEntries = tree->MinEntries(height);
|
|
maxLeafEntries = tree->MaxEntries(height);
|
|
DS3Entry<dim, IndexedType, QueryType, DistFun>* first =
|
|
new DS3Entry<dim,IndexedType, QueryType, DistFun>(root,queryObj, 0);
|
|
dsqueue.push(first);
|
|
}
|
|
|
|
~DS3LocalInfo(){
|
|
while(!dsqueue.empty()){
|
|
DS3Entry<dim, IndexedType, QueryType, DistFun>* t = dsqueue.top();
|
|
delete t;
|
|
dsqueue.pop();
|
|
}
|
|
}
|
|
|
|
|
|
Tuple* nextTuple(){
|
|
if(!tree){
|
|
return 0;
|
|
}
|
|
if(k>0 && returned==k){
|
|
return 0;
|
|
}
|
|
if(dsqueue.empty()){
|
|
return 0;
|
|
}
|
|
|
|
|
|
DS3Entry<dim, IndexedType, QueryType, DistFun>* top = dsqueue.top();
|
|
// replace top entry of the queue by its sons
|
|
// until it's a tuple entry
|
|
while(!top->isTupleEntry()){
|
|
dsqueue.pop(); // remove top element
|
|
int level = top->getLevel();
|
|
// insert all sons
|
|
int minEntries,maxEntries;
|
|
level++; // level for the sons is increased
|
|
|
|
if(level>=height){
|
|
minEntries = this->minLeafEntries;
|
|
maxEntries = this->maxLeafEntries;
|
|
} else {
|
|
minEntries = this->minInnerEntries;
|
|
maxEntries = this->maxInnerEntries;
|
|
}
|
|
|
|
if(!top->getNode()->IsLeaf()){
|
|
for(int i = 0; i< top->getNode()->EntryCount();i++){
|
|
R_TreeInternalEntry<dim>* next=top->getNode()->GetInternalEntry(i);
|
|
SmiRecordId rid = next->pointer;
|
|
R_TreeNode<dim, TupleId> nextNode(true, minEntries, maxEntries);
|
|
tree->GetNode(rid, nextNode);
|
|
DS3Entry<dim, IndexedType, QueryType, DistFun>* nextEntry =
|
|
new DS3Entry<dim, IndexedType,
|
|
QueryType, DistFun>(nextNode, queryObj, level);
|
|
dsqueue.push(nextEntry);
|
|
}
|
|
} else { // topmost node was a leaf
|
|
for(int i=0;i<top->getNode()->EntryCount();i++){
|
|
R_TreeLeafEntry<dim, TupleId>* le =
|
|
top->getNode()->GetLeafEntry(i);
|
|
DS3Entry<dim, IndexedType, QueryType, DistFun>* nextEntry =
|
|
new DS3Entry<dim, IndexedType,
|
|
QueryType, DistFun>(le->info, le->box,
|
|
queryObj, level, rel, position, distFun);
|
|
dsqueue.push(nextEntry);
|
|
}
|
|
}
|
|
delete top; // delete the replaced top element
|
|
top = dsqueue.top();
|
|
}
|
|
dsqueue.pop();
|
|
|
|
if(useMaxDist && (top->getDistance()>maxDist)){
|
|
//cout << "maxDist reached" << endl;
|
|
//cout << "currentDist = " << top->getDistance();
|
|
//cout << "maxDist = " << maxDist << endl;
|
|
k = returned;
|
|
delete top;
|
|
return 0;
|
|
}
|
|
|
|
// now we have a tuple
|
|
returned++;
|
|
Tuple* res = rel->GetTuple(top->getTupleId(), false);
|
|
delete top;
|
|
return res;
|
|
}
|
|
private:
|
|
R_Tree<dim, TupleId>* tree;
|
|
Relation* rel;
|
|
int position;
|
|
const QueryType* queryObj;
|
|
int k;
|
|
int returned; // number of returned tuples
|
|
int height;
|
|
int minInnerEntries;
|
|
int maxInnerEntries;
|
|
int minLeafEntries;
|
|
int maxLeafEntries;
|
|
std::priority_queue< DS3Entry<dim, IndexedType, QueryType, DistFun>*,
|
|
std::vector<DS3Entry<dim, IndexedType, QueryType, DistFun>* >,
|
|
DSE3Comp<dim, IndexedType, QueryType, DistFun> > dsqueue;
|
|
DistFun distFun;
|
|
|
|
bool useMaxDist;
|
|
double maxDist;
|
|
|
|
};
|
|
|
|
template <unsigned dim, class IndexedType, class QueryType, class DistFun>
|
|
int distanceScan3Fun (Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
switch(message){
|
|
case OPEN : {
|
|
if(local.addr){
|
|
DS3LocalInfo<dim, IndexedType, QueryType, DistFun>* li =
|
|
static_cast<DS3LocalInfo<dim, IndexedType,
|
|
QueryType, DistFun>*>(local.addr);
|
|
delete li;
|
|
}
|
|
R_Tree<dim, TupleId>* rtree =
|
|
static_cast<R_Tree<dim, TupleId> *>(args[0].addr);
|
|
Relation* rel = static_cast<Relation*>(args[1].addr);
|
|
QueryType* queryObj = static_cast<QueryType*>(args[2].addr);
|
|
CcInt* k = static_cast<CcInt*>(args[3].addr);
|
|
int index = qp->GetNoSons(s)-2;
|
|
int pos = (static_cast<CcInt*>(args[index].addr))->GetIntval();
|
|
|
|
bool useMaxDist = (static_cast<CcBool*>
|
|
(args[qp->GetNoSons(s)-1].addr))->GetValue();
|
|
CcReal maxD(false);
|
|
if(useMaxDist){
|
|
maxD.CopyFrom( (CcReal*)args[qp->GetNoSons(s)-3].addr);
|
|
}
|
|
|
|
|
|
local.addr = new
|
|
DS3LocalInfo<dim,IndexedType,QueryType, DistFun>(rtree,
|
|
rel, queryObj, k, pos, maxD);
|
|
return 0;
|
|
}
|
|
|
|
case REQUEST: {
|
|
if(!local.addr){
|
|
return CANCEL;
|
|
} else {
|
|
DS3LocalInfo<dim, IndexedType, QueryType, DistFun>* li =
|
|
static_cast<DS3LocalInfo<dim, IndexedType,
|
|
QueryType,DistFun>*>(local.addr);
|
|
result.addr = li->nextTuple();
|
|
return result.addr ? YIELD : CANCEL;
|
|
}
|
|
}
|
|
|
|
case CLOSE:{
|
|
if(local.addr){
|
|
DS3LocalInfo<dim, IndexedType, QueryType, DistFun>* li =
|
|
static_cast<DS3LocalInfo<dim, IndexedType,
|
|
QueryType, DistFun>*>(local.addr);
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
default : assert(false);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
Distancescan4 compute the k nearest mpoints for a given point for
|
|
a certain instant.
|
|
|
|
rtree(upoint) x rel x point x instant x int x attrname x attrpos
|
|
|
|
*/
|
|
|
|
class DS4Entry{
|
|
public:
|
|
|
|
/*
|
|
~constructors~
|
|
|
|
*/
|
|
DS4Entry(const R_TreeNode<3, TupleId>& node1,
|
|
const Point* qo1,
|
|
const int level1,
|
|
double instantAsDouble):
|
|
isTuple(false), node( new R_TreeNode<3, TupleId>(node1)),
|
|
tupleId(0),level(level1){
|
|
Rectangle<3> r(node1.BoundingBox());
|
|
if(!Contains(r,instantAsDouble)){
|
|
distance = -1;
|
|
} else {
|
|
distance = qo1->Distance(project(node1.BoundingBox()));
|
|
}
|
|
}
|
|
|
|
|
|
DS4Entry(const TupleId id,
|
|
const BBox<3>& rect,
|
|
const Point* qo,
|
|
const int level1,
|
|
const Relation* relation,
|
|
const int attrpos,
|
|
const Instant& instant):
|
|
isTuple(true), node(0), tupleId(id), level(level1){
|
|
|
|
Tuple* tuple = relation->GetTuple(id, false);
|
|
const UPoint* obj =
|
|
static_cast<UPoint*>(tuple->GetAttribute(attrpos));
|
|
distance = computeDistance(obj, qo, instant);
|
|
tuple->DeleteIfAllowed();
|
|
}
|
|
|
|
DS4Entry(const DS4Entry& src):
|
|
isTuple(src.isTuple), node(0), tupleId(src.tupleId),
|
|
level(src.level), distance(src.distance){
|
|
if(src.node){
|
|
node = new R_TreeNode<3, TupleId>(*src.node);
|
|
}
|
|
}
|
|
|
|
/*
|
|
~Assignment operator~
|
|
|
|
*/
|
|
DS4Entry& operator=(const DS4Entry& src){
|
|
isTuple = src.isTuple;
|
|
if(node){
|
|
delete node;
|
|
}
|
|
if(src.node){
|
|
node = new R_TreeNode<3, TupleId>(*src.node);
|
|
} else {
|
|
node = 0;
|
|
}
|
|
tupleId = src.tupleId;
|
|
level = src.level;
|
|
distance = src.distance;
|
|
return *this;
|
|
}
|
|
|
|
/*
|
|
~Destructor~
|
|
|
|
*/
|
|
|
|
~DS4Entry(){ delete node;}
|
|
|
|
|
|
/*
|
|
Check for a tuple entry.
|
|
|
|
*/
|
|
bool isTupleEntry() const{
|
|
return isTuple;
|
|
}
|
|
|
|
bool getLevel() const{
|
|
return level;
|
|
}
|
|
|
|
TupleId getTupleId() const{
|
|
return tupleId;
|
|
}
|
|
|
|
double getDistance() const { return distance; }
|
|
|
|
const R_TreeNode<3,TupleId>* getNode() const {
|
|
return node;
|
|
}
|
|
|
|
inline int compare(const DS4Entry& e) const{
|
|
if(distance < e.distance){
|
|
return -1;
|
|
}
|
|
if(distance > e.distance){
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
private:
|
|
bool isTuple;
|
|
R_TreeNode<3, TupleId>* node;
|
|
TupleId tupleId;
|
|
int level;
|
|
double distance;
|
|
|
|
|
|
inline Rectangle<2> project(const Rectangle<3> r3){
|
|
double minMax[] = { r3.MinD(0),r3.MaxD(0),r3.MinD(1),r3.MaxD(1)};
|
|
Rectangle<2> result(true,minMax);
|
|
return result;
|
|
}
|
|
|
|
inline double computeDistance(const UPoint* up,
|
|
const Point* p,
|
|
const Instant& i){
|
|
|
|
|
|
if(!up->timeInterval.Contains(i)){
|
|
return -1;
|
|
}
|
|
Point p2(0,0);
|
|
up->TemporalFunction(i, p2);
|
|
return p->Distance(p2);
|
|
}
|
|
|
|
/*
|
|
Checks whether the instant is inside the time interval stored within r.
|
|
|
|
*/
|
|
inline bool Contains(const Rectangle<3> r, double instant){
|
|
return (r.MinD(2) <= instant) && (instant <= r.MaxD(2));
|
|
}
|
|
|
|
};
|
|
|
|
class DSE4Comp {
|
|
public:
|
|
bool operator()(
|
|
const DS4Entry* d1,
|
|
const DS4Entry* d2) const{
|
|
return d1->compare(*d2) >= 0;
|
|
}
|
|
};
|
|
|
|
class DS4LocalInfo{
|
|
public:
|
|
DS4LocalInfo( R_Tree<3, TupleId>* rtree,
|
|
Relation* rel,
|
|
Point* point,
|
|
Instant* instant,
|
|
CcInt* k, int position){
|
|
// check if all things are defined
|
|
this->position = position;
|
|
if(rel->GetNoTuples()==0 ||
|
|
!point->IsDefined() ||
|
|
!instant->IsDefined() ||
|
|
!k->IsDefined()){
|
|
this->tree=0;
|
|
this->rel=0;
|
|
this->point = 0;
|
|
this->k = 0;
|
|
this->returned = 0;
|
|
return;
|
|
}
|
|
this->tree = rtree;
|
|
this->rel = rel;
|
|
this->point = point;
|
|
this->k = k->GetIntval();
|
|
this->instant = *instant;
|
|
this->instantAsDouble = instant->ToDouble();
|
|
returned = 0;
|
|
R_TreeNode<3, TupleId> root = rtree->Root();
|
|
// check for an empty tree
|
|
BBox<3> box = root.BoundingBox();
|
|
if(!box.IsDefined()){
|
|
this->tree=0;
|
|
this->rel=0;
|
|
this->point = 0;
|
|
this->k = 0;
|
|
this->returned = 0;
|
|
return;
|
|
}
|
|
height = tree->Height();
|
|
minInnerEntries = tree->MinEntries(0);
|
|
maxInnerEntries = tree->MaxEntries(0);
|
|
minLeafEntries = tree->MinEntries(height);
|
|
maxLeafEntries = tree->MaxEntries(height);
|
|
DS4Entry* first = new DS4Entry(root,point, 0, instantAsDouble);
|
|
if(first->getDistance()>=0){
|
|
dsqueue.push(first);
|
|
}
|
|
}
|
|
|
|
~DS4LocalInfo(){
|
|
while(!dsqueue.empty()){
|
|
DS4Entry* t = dsqueue.top();
|
|
delete t;
|
|
dsqueue.pop();
|
|
}
|
|
}
|
|
|
|
|
|
Tuple* nextTuple(){
|
|
if(!tree){
|
|
return 0;
|
|
}
|
|
if(k>0 && returned==k){
|
|
return 0;
|
|
}
|
|
if(dsqueue.empty()){
|
|
return 0;
|
|
}
|
|
|
|
|
|
DS4Entry* top = dsqueue.top();
|
|
// replace top entry of the queue by its sons
|
|
// until it's a tuple entry
|
|
while(!dsqueue.empty() && !top->isTupleEntry()){
|
|
dsqueue.pop(); // remove top element
|
|
int level = top->getLevel();
|
|
// insert all sons
|
|
int minEntries,maxEntries;
|
|
level++; // level for the sons is increased
|
|
|
|
if(level>=height){
|
|
minEntries = this->minLeafEntries;
|
|
maxEntries = this->maxLeafEntries;
|
|
} else {
|
|
minEntries = this->minInnerEntries;
|
|
maxEntries = this->maxInnerEntries;
|
|
}
|
|
|
|
if(!top->getNode()->IsLeaf()){
|
|
for(int i = 0; i< top->getNode()->EntryCount();i++){
|
|
R_TreeInternalEntry<3>* next=top->getNode()->GetInternalEntry(i);
|
|
SmiRecordId rid = next->pointer;
|
|
R_TreeNode<3, TupleId> nextNode(true, minEntries, maxEntries);
|
|
tree->GetNode(rid, nextNode);
|
|
DS4Entry* nextEntry = new DS4Entry(nextNode, point,
|
|
level, instantAsDouble);
|
|
if(nextEntry->getDistance() >=0){
|
|
dsqueue.push(nextEntry);
|
|
} else {
|
|
delete nextEntry;
|
|
}
|
|
}
|
|
} else { // topmost node was a leaf
|
|
for(int i=0;i<top->getNode()->EntryCount();i++){
|
|
R_TreeLeafEntry<3, TupleId>* le =
|
|
top->getNode()->GetLeafEntry(i);
|
|
DS4Entry* nextEntry = new DS4Entry(le->info, le->box,
|
|
point, level, rel, position, instant);
|
|
if(nextEntry->getDistance()>=0){
|
|
dsqueue.push(nextEntry);
|
|
} else {
|
|
delete nextEntry;
|
|
}
|
|
}
|
|
}
|
|
delete top; // delete the replaced top element
|
|
if(!dsqueue.empty()){
|
|
top = dsqueue.top();
|
|
}
|
|
}
|
|
if(dsqueue.empty()){
|
|
return 0;
|
|
}
|
|
dsqueue.pop();
|
|
// now we have a tuple
|
|
returned++;
|
|
Tuple* res = rel->GetTuple(top->getTupleId(), false);
|
|
delete top;
|
|
return res;
|
|
}
|
|
private:
|
|
R_Tree<3, TupleId>* tree;
|
|
Relation* rel;
|
|
int position;
|
|
const Point* point;
|
|
int k;
|
|
int returned; // number of returned tuples
|
|
int height;
|
|
int minInnerEntries;
|
|
int maxInnerEntries;
|
|
int minLeafEntries;
|
|
int maxLeafEntries;
|
|
std::priority_queue< DS4Entry*,
|
|
std::vector<DS4Entry* >,
|
|
DSE4Comp > dsqueue;
|
|
Instant instant;
|
|
double instantAsDouble;
|
|
};
|
|
|
|
|
|
|
|
int distanceScan4Fun (Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
switch(message){
|
|
case OPEN: {
|
|
R_Tree<3, TupleId>* rtree =
|
|
static_cast<R_Tree<3,TupleId>*> (args[0].addr);
|
|
Relation* rel = static_cast<Relation*>(args[1].addr);
|
|
Point* point = static_cast<Point*>(args[2].addr);
|
|
Instant* instant = static_cast<Instant*>(args[3].addr);
|
|
CcInt* k = static_cast<CcInt*>(args[4].addr);
|
|
// ignore attrname
|
|
int attrpos = (static_cast<CcInt*>(args[6].addr))->GetIntval()-1;
|
|
if(!point->IsDefined() || !instant->IsDefined() || !k->IsDefined()){
|
|
local.setAddr(0);
|
|
} else {
|
|
local.addr = new DS4LocalInfo(rtree, rel, point, instant,
|
|
k, attrpos);
|
|
}
|
|
return 0;
|
|
}
|
|
case REQUEST: {
|
|
if(!local.addr){
|
|
return CANCEL;
|
|
}
|
|
DS4LocalInfo* li = static_cast<DS4LocalInfo*>(local.addr);
|
|
result.addr = li->nextTuple();
|
|
return result.addr ? YIELD : CANCEL;
|
|
}
|
|
case CLOSE: {
|
|
if(local.addr){
|
|
DS4LocalInfo* li = static_cast<DS4LocalInfo*>(local.addr);
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
default: assert(false);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
The ~knearest~ operator results a stream of all input tuples which
|
|
contains the k-nearest units to the given mpoint. The tuples are splitted
|
|
into multiple tuples with disjoint units if necessary. The tuples in the
|
|
result stream are not necessarily ordered by time or distance to the
|
|
given mpoint
|
|
|
|
The struct knearestLocalInfo is needed to save the data
|
|
from one to next function call
|
|
the type EventElem and ActiveElem are defined in NearestNeighborAlgebra.h
|
|
|
|
*/
|
|
|
|
// instantiate static member currtime
|
|
Instant ActiveElem::currtime(datetime::instanttype);
|
|
|
|
typedef std::vector< ActiveElem >::iterator ITV;
|
|
typedef NNTree< ActiveElem >::iter IT;
|
|
|
|
/*
|
|
GetPosition calculates the position of a upoint at a specific time
|
|
|
|
*/
|
|
bool GetPosition( const UPoint& up, Instant t, Coord& x, Coord& y)
|
|
{
|
|
//calculates the pos. at time t. x and y is the result
|
|
Instant t0 = up.timeInterval.start;
|
|
Instant t1 = up.timeInterval.end;
|
|
if( t == t0 )
|
|
{
|
|
x = up.p0.GetX();
|
|
y = up.p0.GetY();
|
|
return true;
|
|
}
|
|
if( t == t1 )
|
|
{
|
|
x = up.p1.GetX();
|
|
y = up.p1.GetY();
|
|
return true;
|
|
}
|
|
if( t < t0 || t > t1 ){ return false;}
|
|
double factor = (t - t0) / (t1 - t0);
|
|
x = up.p0.GetX() + factor * (up.p1.GetX() - up.p0.GetX());
|
|
y = up.p0.GetY() + factor * (up.p1.GetY() - up.p0.GetY());
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
the function GetDistance calculates the distance.
|
|
Result is the MReal erg. The function expects a pointer to an empty MReal.
|
|
mpos ist the startposition in mp where the function start to look
|
|
This is a optimization cause the upoints are sorted
|
|
by time.A lower time cannot come
|
|
|
|
*/
|
|
void GetDistance( const MPoint* mp, const UPoint* up,
|
|
int &mpos, MReal *erg)
|
|
{
|
|
Instant time1 = up->timeInterval.start;
|
|
Instant time2 = up->timeInterval.end;
|
|
|
|
int noCo = mp->GetNoComponents();
|
|
UPoint upn;
|
|
|
|
for (int ii=mpos; ii < noCo; ii++)
|
|
{
|
|
mp->Get( ii, upn); // get the current Unit
|
|
if(time2 < upn.timeInterval.start ||
|
|
time1 > upn.timeInterval.end ||
|
|
(time2 == upn.timeInterval.start && up->timeInterval.rc == false))
|
|
continue;
|
|
|
|
if( time1 < upn.timeInterval.end ||
|
|
(time1 == upn.timeInterval.end && upn.timeInterval.rc))
|
|
{ // interval of mp intersects the interval of up
|
|
mpos = ii;
|
|
UReal firstu(true);
|
|
|
|
// take the bigger starting point
|
|
Instant start = up->timeInterval.start < upn.timeInterval.start
|
|
? upn.timeInterval.start : up->timeInterval.start;
|
|
|
|
// take the smaller end
|
|
Instant end = up->timeInterval.end < upn.timeInterval.end
|
|
? up->timeInterval.end : upn.timeInterval.end;
|
|
|
|
bool lc = up->timeInterval.lc;
|
|
if( lc && (start > up->timeInterval.start || (up->timeInterval.start
|
|
== upn.timeInterval.start && !up->timeInterval.lc)))
|
|
{
|
|
lc = false;
|
|
}
|
|
bool rc = up->timeInterval.rc;
|
|
if( rc && (end < up->timeInterval.end || (up->timeInterval.end
|
|
== upn.timeInterval.end && !upn.timeInterval.rc)))
|
|
{
|
|
rc = false;
|
|
}
|
|
|
|
Interval<Instant> iv(start, end, lc, rc);
|
|
|
|
|
|
Coord x1, y1, x2, y2;
|
|
GetPosition( *up, start, x1, y1);
|
|
GetPosition( *up, end, x2, y2);
|
|
UPoint up1(iv, x1, y1, x2, y2);
|
|
GetPosition( upn, start, x1, y1);
|
|
GetPosition( upn, end, x2, y2);
|
|
UPoint upMp(iv, x1, y1, x2, y2);
|
|
if( start != end)
|
|
{
|
|
up1.Distance(upMp, firstu);
|
|
}
|
|
else
|
|
{
|
|
//function Distance(UPoint...) has a bug if
|
|
//starttime and endtime are equal
|
|
Point rp1;
|
|
upMp.TemporalFunction( start, rp1, true);
|
|
up1.Distance(rp1,firstu);
|
|
}
|
|
erg->Add( firstu );
|
|
int jj = ii;
|
|
while( ++jj < noCo && (time2 > end
|
|
|| (time2 == end && !rc && up->timeInterval.rc)))
|
|
{
|
|
mp->Get( jj, upn);
|
|
UReal nextu(true);
|
|
start = end;
|
|
lc = true;
|
|
end = up->timeInterval.end < upn.timeInterval.end
|
|
? up->timeInterval.end : upn.timeInterval.end;
|
|
rc = up->timeInterval.rc;
|
|
if( rc && (end < up->timeInterval.end || (up->timeInterval.end
|
|
== upn.timeInterval.end && !upn.timeInterval.rc)))
|
|
{
|
|
rc = false;
|
|
}
|
|
Interval<Instant> iv(start, end, lc, rc);
|
|
Coord x1, y1, x2, y2;
|
|
GetPosition( *up, start, x1, y1);
|
|
GetPosition( *up, end, x2, y2);
|
|
UPoint up1(iv, x1, y1, x2, y2);
|
|
GetPosition( upn, start, x1, y1);
|
|
GetPosition( upn, end, x2, y2);
|
|
UPoint upMp(iv, x1, y1, x2, y2);
|
|
if( start != end)
|
|
{
|
|
up1.Distance(upMp, nextu);
|
|
}
|
|
else
|
|
{
|
|
//function Distance(UPoint...) has a bug if
|
|
//starttime and endtime are equal
|
|
Point rp1;
|
|
upMp.TemporalFunction( start, rp1, true);
|
|
up1.Distance(rp1,nextu);
|
|
}
|
|
erg->Add( nextu );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
input location data has a zone value
|
|
|
|
*/
|
|
void GetDistance2( const MPoint* mp, const UPoint* up, int &mpos, MReal *erg,
|
|
int zone)
|
|
{
|
|
WGSGK gk;
|
|
gk.setMeridian(zone);
|
|
|
|
Instant time1 = up->timeInterval.start;
|
|
Instant time2 = up->timeInterval.end;
|
|
|
|
int noCo = mp->GetNoComponents();
|
|
UPoint upn;
|
|
|
|
for (int ii=mpos; ii < noCo; ii++)
|
|
{
|
|
mp->Get( ii, upn); // get the current Unit
|
|
if(time2 < upn.timeInterval.start ||
|
|
time1 > upn.timeInterval.end ||
|
|
(time2 == upn.timeInterval.start && up->timeInterval.rc == false))
|
|
continue;
|
|
|
|
if( time1 < upn.timeInterval.end ||
|
|
(time1 == upn.timeInterval.end && upn.timeInterval.rc))
|
|
{ // interval of mp intersects the interval of up
|
|
mpos = ii;
|
|
UReal firstu(true);
|
|
|
|
// take the bigger starting point
|
|
Instant start = up->timeInterval.start < upn.timeInterval.start
|
|
? upn.timeInterval.start : up->timeInterval.start;
|
|
|
|
// take the smaller end
|
|
Instant end = up->timeInterval.end < upn.timeInterval.end
|
|
? up->timeInterval.end : upn.timeInterval.end;
|
|
|
|
bool lc = up->timeInterval.lc;
|
|
if( lc && (start > up->timeInterval.start || (up->timeInterval.start
|
|
== upn.timeInterval.start && !up->timeInterval.lc)))
|
|
{
|
|
lc = false;
|
|
}
|
|
bool rc = up->timeInterval.rc;
|
|
if( rc && (end < up->timeInterval.end || (up->timeInterval.end
|
|
== upn.timeInterval.end && !upn.timeInterval.rc)))
|
|
{
|
|
rc = false;
|
|
}
|
|
|
|
Interval<Instant> iv(start, end, lc, rc);
|
|
|
|
|
|
Coord x1, y1, x2, y2;
|
|
GetPosition( *up, start, x1, y1);
|
|
GetPosition( *up, end, x2, y2);
|
|
// UPoint up1(iv, x1, y1, x2, y2);
|
|
//////////////////////////////////////////////////
|
|
Point p1(true, x1, y1);
|
|
Point p2(true, x2, y2);
|
|
// UPoint up1(iv, p1, p2);
|
|
Point newp1, newp2;
|
|
gk.project(p1, newp1);
|
|
gk.project(p2, newp2);
|
|
UPoint up1(iv, newp1, newp2);
|
|
//////////////////////////////////////////////////
|
|
|
|
GetPosition( upn, start, x1, y1);
|
|
GetPosition( upn, end, x2, y2);
|
|
// UPoint upMp(iv, x1, y1, x2, y2);
|
|
//////////////////////////////////////////////////
|
|
Point q1(true, x1, y1);
|
|
Point q2(true, x2, y2);
|
|
// UPoint upMp(iv, q1, q2);
|
|
Point newq1, newq2;
|
|
gk.project(q1, newq1);
|
|
gk.project(q2, newq2);
|
|
UPoint upMp(iv, newq1, newq2);
|
|
/////////////////////////////////////////////////
|
|
if( start != end)
|
|
{
|
|
up1.Distance(upMp, firstu);
|
|
}
|
|
else
|
|
{
|
|
//function Distance(UPoint...) has a bug if
|
|
//starttime and endtime are equal
|
|
Point rp1;
|
|
upMp.TemporalFunction( start, rp1, true);
|
|
up1.Distance(rp1,firstu);
|
|
}
|
|
erg->Add( firstu );
|
|
int jj = ii;
|
|
while( ++jj < noCo && (time2 > end
|
|
|| (time2 == end && !rc && up->timeInterval.rc)))
|
|
{
|
|
mp->Get( jj, upn);
|
|
UReal nextu(true);
|
|
start = end;
|
|
lc = true;
|
|
end = up->timeInterval.end < upn.timeInterval.end
|
|
? up->timeInterval.end : upn.timeInterval.end;
|
|
rc = up->timeInterval.rc;
|
|
if( rc && (end < up->timeInterval.end || (up->timeInterval.end
|
|
== upn.timeInterval.end && !upn.timeInterval.rc)))
|
|
{
|
|
rc = false;
|
|
}
|
|
Interval<Instant> iv(start, end, lc, rc);
|
|
Coord x1, y1, x2, y2;
|
|
GetPosition( *up, start, x1, y1);
|
|
GetPosition( *up, end, x2, y2);
|
|
// UPoint up1(iv, x1, y1, x2, y2);
|
|
/////////////////////////////////////////////////////////////
|
|
Point p3(true, x1, y1);
|
|
Point p4(true, x2, y2);
|
|
// UPoint up1(iv, p3, p4);
|
|
Point newp3, newp4;
|
|
gk.project(p3, newp3);
|
|
gk.project(p4, newp4);
|
|
UPoint up1(iv, newp3, newp4);
|
|
/////////////////////////////////////////////////////////////
|
|
GetPosition( upn, start, x1, y1);
|
|
GetPosition( upn, end, x2, y2);
|
|
// UPoint upMp(iv, x1, y1, x2, y2);
|
|
////////////////////////////////////////////////////////////////
|
|
Point q3(true, x1, y1);
|
|
Point q4(true, x2, y2);
|
|
// UPoint upMp(iv, q3, q4);
|
|
Point newq3, newq4;
|
|
gk.project(q3, newq3);
|
|
gk.project(q4, newq4);
|
|
UPoint upMp(iv, newq3, newq4);
|
|
//////////////////////////////////////////////////////////////
|
|
if( start != end)
|
|
{
|
|
up1.Distance(upMp, nextu);
|
|
}
|
|
else
|
|
{
|
|
//function Distance(UPoint...) has a bug if
|
|
//starttime and endtime are equal
|
|
Point rp1;
|
|
upMp.TemporalFunction( start, rp1, true);
|
|
up1.Distance(rp1,nextu);
|
|
}
|
|
erg->Add( nextu );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
CalcDistance calculates the result of the given MReal mr
|
|
at the given time t. The value of the derivation (slope)
|
|
is also calculated.
|
|
|
|
*/
|
|
double CalcDistance( const MReal *mr, Instant t, double &slope)
|
|
{
|
|
|
|
int noCo = mr->GetNoComponents();
|
|
UReal ur;
|
|
if(noCo==0){
|
|
return -1;
|
|
}
|
|
|
|
// use binary search
|
|
int min = 0;
|
|
int max = noCo-1;
|
|
while(min<max){
|
|
int mid = (min+max) / 2;
|
|
mr->Get(mid,ur);
|
|
if( (ur.timeInterval.start< t) ||
|
|
((ur.timeInterval.start == t) && ur.timeInterval.lc)){
|
|
// t is after ur's start
|
|
if((ur.timeInterval.end > t) ||
|
|
((ur.timeInterval.end == t) && ur.timeInterval.rc)){
|
|
// found unit containing m
|
|
min = mid;
|
|
max = mid;
|
|
} else {
|
|
// t is after ur's end
|
|
min = mid + 1;
|
|
}
|
|
} else { // t is before ur's start
|
|
max = mid -1;
|
|
}
|
|
}
|
|
// now min==max holds, check if t is contained in ur
|
|
mr->Get(min,ur); // case mr contains only one unit
|
|
|
|
if( (ur.timeInterval.start<= t) // ignore closed flags
|
|
&& (ur.timeInterval.end >= t) ) {
|
|
double time = (t - ur.timeInterval.start).ToDouble();
|
|
double erg = ur.a * time * time + ur.b * time + ur.c;
|
|
if( ur.r && erg < 0) erg = 0;
|
|
erg = ( ur.r) ? sqrt(erg) : erg;
|
|
//the slope is if not r: 2a * time + b
|
|
// else 2a * time + b / 2 * erg
|
|
slope = 2 * ur.a * time + ur.b;
|
|
if( ur.r && erg){ slope /= 2 * erg; }
|
|
if( ur.r && !erg && ur.b == 0 && ur.c == 0 && ur.a > 0)
|
|
{
|
|
slope = sqrt(ur.a);
|
|
}
|
|
return erg;
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
double CalcSlope( const UReal& ur, Instant t)
|
|
{
|
|
if( t >= ur.timeInterval.start && t <= ur.timeInterval.end )
|
|
{
|
|
double time = (t - ur.timeInterval.start).ToDouble();
|
|
//the slope is if not r: 2a * time + b
|
|
// else 2a * time + b / div
|
|
double erg = 2 * ur.a * time + ur.b;
|
|
if( ur.r)
|
|
{
|
|
double div = ur.a * time * time + ur.b * time + ur.c;
|
|
if( div > 0){
|
|
erg /= 2 * sqrt(div);
|
|
}
|
|
else if(ur.b == 0 && ur.c == 0 && ur.a > 0)
|
|
{
|
|
erg = sqrt(ur.a);
|
|
}
|
|
else erg = 0;
|
|
}
|
|
return erg;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
intersects calculate the next intersection of two MReals
|
|
|
|
*/
|
|
bool intersects( MReal* m1, MReal* m2, Instant &start, Instant& result,
|
|
bool isInsert )
|
|
{
|
|
//returns true if m1 intersects m2. The first intersection time is the result
|
|
//Only intersections after the time start are calculated
|
|
int noCo1 = m1->GetNoComponents();
|
|
int ii = 0;
|
|
UReal u1;
|
|
if( !noCo1 ){ return false; }
|
|
m1->Get( ii, u1);
|
|
while( (start > u1.timeInterval.end || (start == u1.timeInterval.end
|
|
&& !u1.timeInterval.rc)) && ++ii < noCo1 )
|
|
{
|
|
m1->Get( ii, u1);
|
|
}
|
|
int noCo2 = m2->GetNoComponents();
|
|
UReal u2;
|
|
if( !noCo2 ){ return false; }
|
|
int jj = 0;
|
|
m2->Get( jj, u2);
|
|
while( (start > u2.timeInterval.end || (start == u2.timeInterval.end
|
|
&& !u2.timeInterval.rc)) && ++jj < noCo2 )
|
|
{
|
|
m2->Get( jj, u2);
|
|
}
|
|
if( ii >= noCo1 || jj >= noCo2 )
|
|
{
|
|
return false;
|
|
}
|
|
//u1, u2 are the ureals with the time start to begin with the calculation
|
|
//formula: t = (-b +- sqrt(b*b - 4ac)) / 2a where a,b,c are:
|
|
//a=a2-a1; b=b2-b1-2*a2*x; c=a2*x*x - b2*x + c2 - c1;
|
|
//x=u2->timeInterval.start - u1->timeInterval.start, u2 time is later
|
|
//if b*b - 4ac > 0 the equation has a result
|
|
bool hasResult = false;
|
|
double a, b, c, d, r1, r2, x;
|
|
double laterTime;
|
|
while( !hasResult && ii < noCo1 && jj < noCo2)
|
|
{
|
|
if( u1.timeInterval.start <= u2.timeInterval.start )
|
|
{
|
|
laterTime = u2.timeInterval.start.ToDouble();;
|
|
x = (u2.timeInterval.start - u1.timeInterval.start).ToDouble();
|
|
a = u1.a - u2.a;
|
|
b = u1.b - u2.b + 2 * u1.a * x;
|
|
c = u1.a * x * x + u1.b * x + u1.c - u2.c;
|
|
}
|
|
else
|
|
{
|
|
laterTime = u1.timeInterval.start.ToDouble();;
|
|
x = (u1.timeInterval.start - u2.timeInterval.start).ToDouble();
|
|
a = u2.a - u1.a;
|
|
b = u2.b - u1.b + 2 * u2.a * x;
|
|
c = u2.a * x * x + u2.b * x + u2.c - u1.c;
|
|
}
|
|
d = b * b - 4 * a * c;
|
|
if( std::abs(a) <= QUADDIFF || d >= 0)
|
|
{
|
|
if( std::abs(a) > QUADDIFF)
|
|
{
|
|
d = sqrt(d);
|
|
r1 = (-b - d) / (2 * a);
|
|
r2 = (-b + d) / (2 * a);
|
|
if( r1 < 0 && r1 > RDELTA) r1 = 0;
|
|
if( r2 < 0 && r2 > RDELTA) r2 = 0;
|
|
}
|
|
else
|
|
{
|
|
r1 = b ? -c / b : -1;
|
|
r2 = -1; //there is only one result
|
|
}
|
|
if( r1 > r2 ){ std::swap( r1, r2 );}
|
|
if( (std::abs(r1 - r2) < 0.000000001)
|
|
&& ( (u1.a==0 && u2.a!=0) || (u2.a==0 && u1.a!=0) ))
|
|
{
|
|
//straight line intersects curve in one point, only boundary point
|
|
r1 = -1;
|
|
r2 = -1;
|
|
}
|
|
if( r1 >= 0 )
|
|
{
|
|
result.ReadFrom(r1 + laterTime);
|
|
if( (result > start || (result == start && !isInsert))
|
|
&& result <= u1.timeInterval.end && result <= u2.timeInterval.end)
|
|
{
|
|
//now calculate the slope
|
|
double slope1, slope2;
|
|
slope1 = CalcSlope( u1,result);
|
|
slope2 = CalcSlope( u2,result);
|
|
if( slope1 > slope2 )
|
|
{
|
|
hasResult = true;
|
|
}
|
|
}
|
|
}
|
|
if( !hasResult && r2 >= 0 )
|
|
{
|
|
result.ReadFrom(r2 + laterTime);
|
|
if( (result > start || (result == start && !isInsert))
|
|
&& result <= u1.timeInterval.end && result <= u2.timeInterval.end)
|
|
{
|
|
double slope1, slope2;
|
|
slope1 = CalcSlope( u1,result);
|
|
slope2 = CalcSlope( u2,result);
|
|
if( slope1 > slope2 )
|
|
{
|
|
hasResult = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if( !hasResult )
|
|
{
|
|
if( u1.timeInterval.end < u2.timeInterval.end )
|
|
{
|
|
++ii;
|
|
}
|
|
else if( u2.timeInterval.end < u1.timeInterval.end )
|
|
{
|
|
++jj;
|
|
}
|
|
else
|
|
{
|
|
//both ends are the same
|
|
++ii;
|
|
++jj;
|
|
}
|
|
if( ii < noCo1 && jj < noCo2)
|
|
{
|
|
m1->Get( ii, u1);
|
|
m2->Get( jj, u2);
|
|
}
|
|
}
|
|
}
|
|
if( hasResult )
|
|
{
|
|
//if the intersection exact at the end of m1 or m2, do not take it
|
|
m1->Get( m1->GetNoComponents()-1, u1);
|
|
if( result == u1.timeInterval.end )
|
|
{
|
|
hasResult = false;
|
|
}
|
|
}
|
|
if( hasResult )
|
|
{
|
|
//if the intersection exact at the end of m1 or m2, do not take it
|
|
m2->Get( m2->GetNoComponents()-1, u1);
|
|
if( result == u1.timeInterval.end )
|
|
{
|
|
hasResult = false;
|
|
}
|
|
}
|
|
return hasResult;
|
|
}
|
|
|
|
/*
|
|
check is for debug purposes and to correct the order
|
|
|
|
*/
|
|
bool check(NNTree<ActiveElem> &t, Instant time)
|
|
{
|
|
double slope;
|
|
double d = 0;
|
|
IT itOld = t.begin();
|
|
for( IT ittest=t.begin(); ittest != t.end(); ++ittest)
|
|
{
|
|
double d2 = CalcDistance(ittest->distance,time,slope);
|
|
if(d-0.05 > d2)
|
|
{
|
|
//swap the two entries in activeline
|
|
ActiveElem e = *itOld;
|
|
*itOld = *ittest;
|
|
*ittest = e;
|
|
}
|
|
itOld = ittest;
|
|
d = CalcDistance(ittest->distance,time,slope);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool check(std::vector<ActiveElem> &v, Instant time)
|
|
{
|
|
double slope;
|
|
double d = 0;
|
|
ITV itOld = v.begin();
|
|
for( ITV ittest=v.begin(); ittest != v.end(); ++ittest)
|
|
{
|
|
if(d-0.05 > CalcDistance(ittest->distance,time,slope))
|
|
{
|
|
ActiveElem e = *itOld;
|
|
*itOld = *ittest;
|
|
*ittest = e;
|
|
}
|
|
itOld = ittest;
|
|
d = CalcDistance(ittest->distance,time,slope);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
changeTupleUnit change the unit attribut of the given tuple
|
|
new start and end times can set
|
|
|
|
*/
|
|
Tuple* changeTupleUnit( Tuple *tuple, int attrNr, Instant start,
|
|
Instant end, bool lc, bool rc)
|
|
{
|
|
Interval<Instant> iv( start, end, lc, rc);
|
|
if(! iv.IsValid())
|
|
return NULL;
|
|
|
|
Tuple* res = new Tuple( tuple->GetTupleType() );
|
|
for( int ii = 0; ii < tuple->GetNoAttributes(); ++ii)
|
|
{
|
|
if( ii != attrNr )
|
|
{
|
|
res->CopyAttribute( ii, tuple, ii);
|
|
}
|
|
else
|
|
{
|
|
const UPoint* upointAttr
|
|
= (const UPoint*)tuple->GetAttribute(attrNr);
|
|
Coord x1, y1, x2, y2;
|
|
GetPosition( *upointAttr, start, x1, y1);
|
|
GetPosition( *upointAttr, end, x2, y2);
|
|
// Interval<Instant> iv( start, end, lc, rc);
|
|
UPoint* up = new UPoint( iv, x1, y1, x2, y2);
|
|
res->PutAttribute( ii, up);
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
/*
|
|
insertActiveElem inserts an element to the container v
|
|
with the active elements. The sort order is the distance
|
|
and the slope if the distance is the same
|
|
|
|
*/
|
|
unsigned int insertActiveElem( std::vector<ActiveElem> &v, ActiveElem &e,
|
|
Instant time)
|
|
{
|
|
if( v.size() == 0)
|
|
{
|
|
v.push_back(e);
|
|
return 0;
|
|
}
|
|
|
|
int pos=0, start=0, max=0;
|
|
max = v.size() - 1;
|
|
start = 0;
|
|
bool havePos = false;
|
|
double slope1, slope2;
|
|
double dist = CalcDistance(e.distance,time,slope1);
|
|
while( !havePos && start <= max)
|
|
{
|
|
pos = (max + start) / 2;
|
|
double storeDistance = CalcDistance(v[pos].distance,time,slope2);
|
|
if( almostSmaller(dist, slope1, storeDistance, slope2)) {
|
|
max = pos - 1;
|
|
} else if( almostGreater(dist,slope1, storeDistance, slope2)) {
|
|
start = pos + 1;
|
|
} else { //same distance and same slope
|
|
while( almostEqual(dist, storeDistance ) && slope1 == slope2
|
|
&& ++pos < (int)v.size() ) {
|
|
storeDistance = CalcDistance(v[pos].distance,time,slope2);
|
|
}
|
|
havePos = true;
|
|
}
|
|
}
|
|
if( !havePos){ pos = start; }
|
|
if( v.capacity() - v.size() < 1)
|
|
{
|
|
v.reserve(v.size() + 100);
|
|
}
|
|
|
|
v.insert(v.begin() + (unsigned)pos,e);
|
|
return pos;
|
|
}
|
|
|
|
unsigned int findActiveElem( std::vector<ActiveElem> &v, MReal *distance,
|
|
Instant time, Tuple *tuple)
|
|
{
|
|
int pos(0), max(v.size()-1), start(0);
|
|
bool havePos = false;
|
|
double slope1, slope2;
|
|
double dist = CalcDistance(distance,time,slope1);
|
|
while( !havePos && start <= max)
|
|
{
|
|
pos = (max + start) / 2;
|
|
double storeDistance = CalcDistance(v[pos].distance,time,slope2);
|
|
if( dist < storeDistance || (dist == storeDistance && slope1 < slope2) )
|
|
{
|
|
max = pos - 1;
|
|
}
|
|
else if( dist > storeDistance ||
|
|
(dist == storeDistance && slope1 > slope2))
|
|
{
|
|
start = pos + 1;
|
|
}
|
|
else //same distance and same slope
|
|
{
|
|
havePos = true;
|
|
}
|
|
}
|
|
int i = pos;
|
|
if( tuple == v[pos].tuple){ havePos = true; }
|
|
else { havePos = false; }
|
|
while( !havePos && (pos < (int)v.size() || i > 0))
|
|
{
|
|
if( i > 0 )
|
|
{
|
|
--i;
|
|
if( tuple == v[i].tuple)
|
|
{
|
|
pos = i;
|
|
havePos = true;
|
|
};
|
|
}
|
|
|
|
if( !havePos && pos < (int)v.size() )
|
|
{
|
|
++pos;
|
|
if( pos < (int)v.size() && tuple == v[pos].tuple)
|
|
{
|
|
havePos = true;
|
|
}
|
|
}
|
|
}
|
|
return pos;
|
|
}
|
|
|
|
/*
|
|
insertActiveElem inserts an element to the container t
|
|
with the active elements. The sort order is the distance
|
|
and the slope if the distance is the same
|
|
this function builds an unbalanced binary tree
|
|
|
|
*/
|
|
|
|
IT insertActiveElem( NNTree<ActiveElem> &t, ActiveElem &e,
|
|
Instant time)
|
|
{
|
|
if( t.size() == 0)
|
|
{
|
|
return t.addFirst(e);
|
|
}
|
|
|
|
double slope1, slope2;
|
|
double dist = CalcDistance(e.distance,time,slope1);
|
|
IT it = t.root();
|
|
while( true)
|
|
{
|
|
double storeDistance = CalcDistance(it->distance,time,slope2);
|
|
if( almostSmaller(dist,slope1, storeDistance, slope2) )
|
|
{
|
|
if( it.hasLeft() )
|
|
{
|
|
it.leftItem();
|
|
}
|
|
else
|
|
{
|
|
return t.addLeft( e, it);
|
|
}
|
|
}
|
|
else if( almostGreater(dist, slope1, storeDistance, slope2))
|
|
{
|
|
if( it.hasRight() )
|
|
{
|
|
it.rightItem();
|
|
}
|
|
else
|
|
{
|
|
return t.addRight( e, it);
|
|
}
|
|
}
|
|
else //same distance and same slope
|
|
{
|
|
IT pos = it;
|
|
++pos;
|
|
while( pos != t.end()
|
|
&& almostEqual(dist, CalcDistance(pos->distance,time,slope2))
|
|
&& slope1 == slope2)
|
|
{
|
|
it = pos;
|
|
++pos;
|
|
}
|
|
return t.addElem( e, it );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
IT findActiveElem( NNTree<ActiveElem> &t, MReal *distance,
|
|
Instant time, Tuple *tuple)
|
|
{
|
|
double slope1, slope2;
|
|
double dist = CalcDistance(distance,time,slope1);
|
|
|
|
if(dist < 0){
|
|
cout << "found invalid dist " << dist << endl;
|
|
cout << "mreal is " << (*distance) << endl;
|
|
cout << "time is " << time << endl;
|
|
assert(dist>=0);
|
|
}
|
|
|
|
IT it = t.root();
|
|
bool havePos = false;
|
|
while( !havePos && it != t.end())
|
|
{
|
|
|
|
double storeDistance = CalcDistance(it->distance,time,slope2);
|
|
if(storeDistance < 0){
|
|
cout << "found invalid storedist " << storeDistance << endl;
|
|
cout << "mreal is " << (it->distance) << endl;
|
|
cout << "time is " << time << endl;
|
|
assert(false);
|
|
}
|
|
|
|
if( dist < storeDistance
|
|
|| (dist == storeDistance && slope1 < slope2))
|
|
{
|
|
if( it.hasLeft() )
|
|
it.leftItem();
|
|
else
|
|
{
|
|
havePos = true;
|
|
}
|
|
}
|
|
else if( dist > storeDistance
|
|
|| (dist == storeDistance && slope1 > slope2))
|
|
{
|
|
if( it.hasRight() )
|
|
it.rightItem();
|
|
else
|
|
{
|
|
havePos = true;
|
|
}
|
|
}
|
|
else //same distance and same slope
|
|
{
|
|
havePos = true;
|
|
}
|
|
}
|
|
if( tuple == it->tuple){ havePos = true; }
|
|
else { havePos = false; }
|
|
|
|
IT pos1 = it;
|
|
IT pos2 = it;
|
|
while( !havePos && (pos1 != t.begin() || pos2 != t.end()))
|
|
{
|
|
if( pos1 != t.begin() )
|
|
{
|
|
--pos1;
|
|
if( tuple == pos1->tuple)
|
|
{
|
|
pos2 = pos1;
|
|
havePos = true;
|
|
};
|
|
}
|
|
|
|
if( !havePos && pos2 != t.end() )
|
|
{
|
|
++pos2;
|
|
if( pos2 != t.end() && tuple == pos2->tuple)
|
|
{
|
|
havePos = true;
|
|
}
|
|
}
|
|
}
|
|
return pos2;
|
|
}
|
|
|
|
|
|
/*
|
|
tests if the given element is one of the first k
|
|
if yes then erg is set to true.
|
|
The k+1. element is returned if exist else v.end()
|
|
|
|
*/
|
|
IT checkFirstK(NNTree<ActiveElem> &t, unsigned int k, IT &it, bool &erg)
|
|
{
|
|
unsigned int ii = 0;
|
|
IT testit=t.begin();
|
|
erg = false;
|
|
for( ; testit != t.end() && ii < k; ++testit)
|
|
{
|
|
++ii;
|
|
if( testit == it )
|
|
{
|
|
erg = true;
|
|
}
|
|
}
|
|
return testit;
|
|
}
|
|
|
|
|
|
/*
|
|
tests if the given element the k. element
|
|
if yes then true is returned.
|
|
|
|
*/
|
|
bool checkK(NNTree<ActiveElem> &t, unsigned int k, IT &it)
|
|
{
|
|
unsigned int ii = 0;
|
|
for( IT testit=t.begin(); testit != t.end() && ii < k; ++testit)
|
|
{
|
|
++ii;
|
|
if( ii == k && testit == it )
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
/*
|
|
get the k ths element in the tree or list
|
|
|
|
*/
|
|
IT getKNeighbor(NNTree<ActiveElem> &t, unsigned int k, bool &erg,
|
|
Instant t_point)
|
|
{
|
|
unsigned int ii = 0;
|
|
IT testit=t.begin();
|
|
erg = false;
|
|
//double dist_k;
|
|
double slope;
|
|
|
|
for( ; testit != t.end() && ii < k; ++testit)
|
|
{
|
|
++ii;
|
|
if( ii == k){
|
|
//dist_k =
|
|
CalcDistance(testit->distance, t_point, slope);
|
|
erg = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// const double delta_dist = 0.001;
|
|
// for(; testit != t.end();++testit){
|
|
// double d = CalcDistance(testit->distance, t_point, slope);
|
|
// if(fabs(d - dist_k) < delta_dist){
|
|
// erg = true;
|
|
// return testit;
|
|
// }
|
|
// break;
|
|
// }
|
|
|
|
// if(erg)
|
|
// cout<<"k neighbor "<<testit->tuple->GetTupleId()<<endl;
|
|
|
|
return testit;
|
|
}
|
|
|
|
inline bool UPAtInstant(Tuple* tuple, Instant t, int attrNr)
|
|
{
|
|
UPoint* up = (UPoint*)tuple->GetAttribute(attrNr);
|
|
return up->timeInterval.Contains(t);
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
To use the plane sweep algrithmus a priority queue for the events and
|
|
a NNTree to save the active segments is needed.
|
|
|
|
*/
|
|
|
|
class KNearestQueue{
|
|
public:
|
|
/*
|
|
~Constructor~
|
|
|
|
consumes the stream until the first unit is found with an interval
|
|
which intersects the definition time of the moving point
|
|
|
|
*/
|
|
|
|
KNearestQueue(Word& src, QueryProcessor* qp1,
|
|
int pos1, const MPoint* mpoint1):
|
|
stream(src),qp(qp1),pos(pos1),mpoint(mpoint1), mpos(0),
|
|
lastStart(datetime::instanttype){
|
|
zone_flag = false;
|
|
init();
|
|
}
|
|
|
|
KNearestQueue(Word& src, QueryProcessor* qp1,
|
|
int pos1, const MPoint* mpoint1, int z):
|
|
stream(src),qp(qp1),pos(pos1),mpoint(mpoint1), mpos(0),
|
|
lastStart(datetime::instanttype),zone(z){
|
|
zone_flag = true;
|
|
init();
|
|
}
|
|
|
|
|
|
/*
|
|
~Destructor~
|
|
|
|
|
|
*/
|
|
~KNearestQueue(){
|
|
if(lastTuple){
|
|
lastTuple->DeleteIfAllowed();
|
|
lastTuple = 0;
|
|
}
|
|
}
|
|
|
|
|
|
inline bool empty() const{
|
|
if(lastTuple){
|
|
return false;
|
|
}
|
|
return queue.empty();
|
|
}
|
|
|
|
inline void push(EventElem e){
|
|
queue.push(e);
|
|
}
|
|
|
|
EventElem& top(){
|
|
next();
|
|
return const_cast<EventElem &>(queue.top());
|
|
}
|
|
|
|
void pop(){
|
|
next();
|
|
queue.pop();
|
|
}
|
|
int GetPos(){return pos;}
|
|
|
|
private:
|
|
Word stream; // source stream
|
|
QueryProcessor* qp; // query processor
|
|
int pos; // position of the attribute
|
|
const MPoint* mpoint;
|
|
int mpos;
|
|
datetime::DateTime lastStart;
|
|
Tuple* lastTuple; // last Tuple read from stream
|
|
datetime::DateTime tupleStart; // start instance of the next tuple
|
|
std::priority_queue<EventElem> queue; // the event queue
|
|
Interval<Instant> iv; // interval of the moving point
|
|
int zone;
|
|
bool zone_flag;
|
|
|
|
// forbid access to copy constructor and assignment operator
|
|
// => force call by reference
|
|
KNearestQueue(const KNearestQueue& src){
|
|
assert(false);
|
|
}
|
|
KNearestQueue& operator=(const KNearestQueue& src){
|
|
assert(false);
|
|
}
|
|
|
|
|
|
/*
|
|
~init~
|
|
|
|
common initialization in both constructors
|
|
|
|
*/
|
|
void init(){
|
|
lastStart.ToMinimum();
|
|
if(!mpoint->IsDefined() || mpoint->IsEmpty()){
|
|
lastTuple = 0;
|
|
return;
|
|
}
|
|
UPoint tmp;
|
|
mpoint->Get(0,tmp);
|
|
Instant tmpstart = tmp.timeInterval.start;
|
|
bool lc = tmp.timeInterval.lc;
|
|
mpoint->Get(mpoint->GetNoComponents()-1, tmp);
|
|
Instant tmpend = tmp.timeInterval.end;
|
|
bool rc = tmp.timeInterval.rc;
|
|
|
|
iv = Interval<Instant>(tmpstart, tmpend,lc,rc);
|
|
|
|
Word current(Address(0));
|
|
|
|
qp->Request(stream.addr,current);
|
|
|
|
if(!qp->Received(stream.addr)){ // stream is empty
|
|
lastTuple = 0;
|
|
return;
|
|
}
|
|
// search the first tuple in stream having a time interval
|
|
// intersecting the interval of the mving point
|
|
bool finished = false;
|
|
|
|
while(!finished){
|
|
lastTuple = static_cast<Tuple*>(current.addr);
|
|
UPoint* up = static_cast<UPoint*>(lastTuple->GetAttribute(pos));
|
|
if(up->timeInterval.start < lastStart){
|
|
std::cerr << "Detected invalid order in tuple stream" << endl;
|
|
lastTuple->DeleteIfAllowed();
|
|
lastTuple = 0;
|
|
return;
|
|
}
|
|
lastStart = up->timeInterval.start;
|
|
|
|
Instant tupleEnd(up->timeInterval.end);
|
|
if(up->timeInterval.end <= iv.start){
|
|
lastTuple->DeleteIfAllowed();
|
|
lastTuple = 0;
|
|
qp->Request(stream.addr,current);
|
|
finished = !qp->Received(stream.addr);
|
|
} else {
|
|
finished = true;
|
|
if(up->timeInterval.start > iv.end){
|
|
lastTuple->DeleteIfAllowed();
|
|
lastTuple = 0;
|
|
}
|
|
}
|
|
}
|
|
if(lastTuple){
|
|
tmp = *static_cast<UPoint*>(lastTuple->GetAttribute(pos));
|
|
tupleStart = tmp.timeInterval.start;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
~next~
|
|
|
|
This function checks whether the next Event comes from the stream or
|
|
from the queue. If it comes from the queue, the lastTuple is converted
|
|
to a EventElement and inserted into the queue.
|
|
|
|
*/
|
|
inline void next(){
|
|
if(lastTuple){ // otherwise, we have nothing to do
|
|
if(queue.empty()){
|
|
transfer(tupleStart);
|
|
} else {
|
|
datetime::DateTime i = queue.top().pointInTime;
|
|
transfer(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
~transfer~
|
|
|
|
Transfers all tuple with starting time <= i into the queue
|
|
|
|
*/
|
|
|
|
inline void transfer(datetime::DateTime& i){
|
|
bool t = false;
|
|
while( (lastTuple && tupleStart <= i) ||
|
|
(lastTuple && !t)){
|
|
t = transfersingle();
|
|
}
|
|
}
|
|
|
|
/*
|
|
~ transfers the next tuple into the queue~
|
|
lasttuple must be exist.
|
|
|
|
|
|
*/
|
|
inline bool transfersingle(){
|
|
|
|
assert(lastTuple);
|
|
|
|
// create a new Event for the queue
|
|
const UPoint* up = static_cast<UPoint*>(lastTuple->GetAttribute(pos));
|
|
|
|
bool transferred = false;
|
|
|
|
if(iv.Intersects(up->timeInterval) ){ // intersecting interval
|
|
MReal* mr = new MReal(0);
|
|
if(zone_flag){
|
|
GetDistance2(mpoint, up, mpos, mr, zone);
|
|
} else {
|
|
GetDistance(mpoint, up, mpos, mr);
|
|
}
|
|
Instant t1 = up->timeInterval.start;
|
|
Instant t2 = up->timeInterval.end;
|
|
Instant t3 = t1>= iv.start ? t1 : iv.start;
|
|
Instant t4 = t2 <= iv.end ? t2 : iv.end;
|
|
queue.push(EventElem(E_LEFT, t3, lastTuple, up, mr));
|
|
queue.push(EventElem(E_RIGHT, t4, lastTuple, up, mr));
|
|
// get the next tuple from the stream
|
|
transferred = true;
|
|
}else{
|
|
// if there is no Event created from the tuple, we just
|
|
// delete it
|
|
lastTuple->DeleteIfAllowed();
|
|
lastTuple = 0;
|
|
}
|
|
|
|
Word current(Address(0));
|
|
qp->Request(stream.addr,current);
|
|
if(qp->Received(stream.addr)){
|
|
lastTuple = static_cast<Tuple*>(current.addr);
|
|
const UPoint* up =
|
|
static_cast<const UPoint*>(lastTuple->GetAttribute(pos));
|
|
tupleStart = up->timeInterval.start;
|
|
if(tupleStart < lastStart){
|
|
cout << "Detected invalid order in tuple stream" << endl;
|
|
lastTuple->DeleteIfAllowed();
|
|
lastTuple = 0;
|
|
}
|
|
lastStart = tupleStart;
|
|
if(tupleStart > iv.end){
|
|
// tuple starts after the end of the query point
|
|
lastTuple->DeleteIfAllowed();
|
|
lastTuple = 0;
|
|
}
|
|
} else {
|
|
lastTuple = 0;
|
|
transferred = false;
|
|
}
|
|
return transferred;
|
|
}
|
|
|
|
};
|
|
|
|
/*
|
|
checks if there are intersections and puts them into the eventqueue
|
|
this is the right function if the eventqueue is a NNTree
|
|
|
|
*/
|
|
void checkIntersections(EventType type, Instant &time, IT pos,
|
|
NNTree< ActiveElem > &t,
|
|
KNearestQueue& evq, Instant &endTime)
|
|
{
|
|
switch ( type ){
|
|
case E_LEFT:
|
|
{
|
|
IT nextPos = pos;
|
|
++nextPos;
|
|
Instant intersectTime( time.GetType() );
|
|
if( nextPos != t.end())
|
|
{
|
|
if( intersects( pos->distance, nextPos->distance, time,
|
|
intersectTime, true ))
|
|
{
|
|
evq.push( EventElem(E_INTERSECT,
|
|
intersectTime, pos->tuple, nextPos->tuple, pos->distance) );
|
|
}
|
|
}
|
|
if( pos != t.begin())
|
|
{
|
|
IT prevPos = pos;
|
|
--prevPos;
|
|
if( intersects( prevPos->distance, pos->distance,
|
|
time, intersectTime, true ))
|
|
{
|
|
evq.push( EventElem(E_INTERSECT, intersectTime,
|
|
prevPos->tuple, pos->tuple, prevPos->distance) );
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case E_RIGHT:
|
|
{
|
|
if( pos != t.begin() && time < endTime)
|
|
{
|
|
IT posNext = pos;
|
|
++posNext;
|
|
if( posNext != t.end() )
|
|
{
|
|
IT posPrev = pos;
|
|
--posPrev;
|
|
Instant intersectTime( time.GetType() );
|
|
if( intersects( posPrev->distance, posNext->distance,
|
|
time, intersectTime, false ) )
|
|
{
|
|
evq.push( EventElem(E_INTERSECT, intersectTime,
|
|
posPrev->tuple, posNext->tuple, posPrev->distance) );
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case E_INTERSECT:
|
|
{
|
|
//look for intersections between the new neighbors
|
|
IT posSec = pos;
|
|
++posSec;
|
|
if( pos != t.begin() )
|
|
{
|
|
IT posPrev = pos;
|
|
--posPrev;
|
|
Instant intersectTime( time.GetType() );
|
|
if( intersects( posPrev->distance, posSec->distance,
|
|
time, intersectTime, false ) )
|
|
{
|
|
evq.push( EventElem(E_INTERSECT, intersectTime,
|
|
posPrev->tuple, posSec->tuple, posPrev->distance) );
|
|
}
|
|
}
|
|
IT posSecNext = posSec;
|
|
++posSecNext;
|
|
if( posSecNext != t.end() )
|
|
{
|
|
Instant intersectTime( time.GetType() );
|
|
if( intersects( pos->distance,posSecNext->distance,
|
|
time, intersectTime, false ) )
|
|
{
|
|
evq.push( EventElem(E_INTERSECT, intersectTime,
|
|
pos->tuple, posSecNext->tuple, pos->distance) );
|
|
}
|
|
}
|
|
//look for new intersections between the old neighbors
|
|
Instant intersectTime( time.GetType() );
|
|
if( intersects( posSec->distance, pos->distance,
|
|
time, intersectTime, true ) )
|
|
{
|
|
evq.push( EventElem(E_INTERSECT, intersectTime,
|
|
posSec->tuple, pos->tuple, posSec->distance) );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
Eliminates duplicate elements in the priority queue
|
|
|
|
*/
|
|
void deleteDupElements(KNearestQueue& evq, EventType type,
|
|
Tuple* tuple1, Tuple* tuple2, Instant& time)
|
|
{
|
|
while( !evq.empty() )
|
|
{
|
|
EventElem& e=evq.top();
|
|
//eleminate same elements
|
|
if( type != e.type || time != e.pointInTime
|
|
|| tuple1 != e.tuple || tuple2 != e.tuple2) {
|
|
// ignore other members of EventElement
|
|
return;
|
|
} else {
|
|
evq.pop();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
struct KnearestLocalInfo
|
|
{
|
|
|
|
public:
|
|
// temporarly make friendship to some functions
|
|
|
|
friend int newknearest_distFun1 (Word*, Word&,int, Word&, Supplier);
|
|
friend int newknearest_distFun2 (Word*, Word&,int, Word&, Supplier);
|
|
|
|
|
|
KnearestLocalInfo(Word& stream, int _attrPos,
|
|
const MPoint* mp, int k1):
|
|
k(k1), attrPos(_attrPos),
|
|
eventQueue(stream, qp, _attrPos, mp)
|
|
{
|
|
init(mp);
|
|
}
|
|
|
|
KnearestLocalInfo(Word& stream, int _attrPos,
|
|
const MPoint* mp, int k1, int zone):
|
|
k(k1), attrPos(_attrPos),
|
|
eventQueue(stream, qp, _attrPos, mp, zone){
|
|
init(mp);
|
|
}
|
|
|
|
Tuple* next(){
|
|
|
|
//int attrNr = ((CcInt*)args[qp->GetNoSons(s)-1].addr)->GetIntval() - 1;
|
|
while ( !eventQueue.empty() ) {
|
|
EventElem elem = eventQueue.top();
|
|
eventQueue.pop();
|
|
ActiveElem::currtime = elem.pointInTime;
|
|
deleteDupElements( eventQueue, elem.type,
|
|
elem.tuple, elem.tuple2, elem.pointInTime);
|
|
|
|
switch ( elem.type ){
|
|
case E_LEFT: {
|
|
Tuple* res = processLeft(elem);
|
|
if(res) return res;
|
|
break;
|
|
}
|
|
case E_RIGHT: {
|
|
Tuple* res = processRight(elem);
|
|
if(res) return res;
|
|
break;
|
|
}
|
|
|
|
|
|
case E_INTERSECT: {
|
|
Tuple* res = processIntersection(elem);
|
|
if(res) return res;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
private:
|
|
size_t k;
|
|
int attrPos;
|
|
KNearestQueue eventQueue;
|
|
Instant startTime;
|
|
Instant endTime;
|
|
NNTree< ActiveElem > activeLine;
|
|
unsigned int count;
|
|
std::vector<UPoint> up_list;
|
|
std::vector<MReal> dist_list;
|
|
TupleType* resulttype;
|
|
|
|
|
|
bool AddNewUnit(UPoint* up);
|
|
void MergeUnit(UPoint* up);
|
|
|
|
private:
|
|
void init(const MPoint* mp){
|
|
count = 0;
|
|
if(!mp || mp->IsEmpty()){
|
|
return;
|
|
}
|
|
UPoint up1, up2;
|
|
mp->Get( 0, up1);
|
|
mp->Get( mp->GetNoComponents() - 1, up2);
|
|
startTime = up1.timeInterval.start;
|
|
endTime = up2.timeInterval.end;
|
|
}
|
|
|
|
|
|
Tuple* processLeft(EventElem& elem){
|
|
bool lc = elem.pointInTime >= startTime
|
|
? elem.up->timeInterval.lc : false;
|
|
|
|
// convert EventElem into Active Elem
|
|
ActiveElem newElem(elem.distance, elem.tuple, elem.pointInTime,
|
|
elem.up->timeInterval.end, lc, elem.up->timeInterval.rc);
|
|
|
|
IT newPos = insertActiveElem( activeLine,
|
|
newElem, elem.pointInTime);
|
|
|
|
// check intersections
|
|
checkIntersections(E_LEFT, elem.pointInTime,
|
|
newPos, activeLine, eventQueue,endTime);
|
|
|
|
bool hasChangedFirstK = false;
|
|
IT posAfterK;
|
|
if( activeLine.size() > k ) {
|
|
posAfterK = checkFirstK(activeLine,k,newPos,hasChangedFirstK);
|
|
}
|
|
if( hasChangedFirstK) {
|
|
//something in the first k has changed
|
|
//now give out the k. element, but only until this time.
|
|
//Clone the tuple and change the unit-attribut to the
|
|
//new time interval
|
|
bool rc = newPos->lc ? false
|
|
: (posAfterK->end == elem.pointInTime ? posAfterK->rc : true);
|
|
if( posAfterK->start != elem.pointInTime
|
|
|| (rc && posAfterK->lc)) {
|
|
Tuple* cloneTuple = changeTupleUnit(
|
|
posAfterK->tuple, attrPos, posAfterK->start,
|
|
elem.pointInTime, posAfterK->lc, rc);
|
|
posAfterK->start = elem.pointInTime;
|
|
posAfterK->lc = false;
|
|
if(cloneTuple != NULL) {
|
|
return cloneTuple;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
Tuple* processRight(EventElem& elem){
|
|
//a unit ends. It has to be removed from the map
|
|
IT posDel = findActiveElem( activeLine,
|
|
elem.distance, elem.pointInTime, elem.tuple);
|
|
Tuple* cloneTuple = NULL;
|
|
if( posDel != activeLine.end())
|
|
{
|
|
//check if this tuple is one of the first k, then give out this
|
|
//and change the start of the k+1 and the following to this time
|
|
bool hasDelFirstK = false;
|
|
IT posAfterK;
|
|
posAfterK = checkFirstK(activeLine,k,posDel,hasDelFirstK);
|
|
|
|
if( hasDelFirstK && (posDel->start != elem.pointInTime
|
|
|| (posDel->lc && posDel->rc)))
|
|
{
|
|
if( posDel->start < endTime )
|
|
{
|
|
cloneTuple = changeTupleUnit(
|
|
posDel->tuple, attrPos, posDel->start, elem.pointInTime,
|
|
posDel->lc, posDel->rc);
|
|
}
|
|
for( ; posAfterK != activeLine.end(); ++posAfterK)
|
|
{
|
|
posAfterK->start = elem.pointInTime;
|
|
posAfterK->lc = false;
|
|
}
|
|
}
|
|
//now calculate the intersection of the neighbors
|
|
checkIntersections(E_RIGHT, elem.pointInTime,
|
|
posDel, activeLine, eventQueue,endTime);
|
|
|
|
activeLine.erase( posDel );
|
|
elem.distance->Destroy();
|
|
delete elem.distance;
|
|
elem.tuple->DeleteIfAllowed();
|
|
}
|
|
else
|
|
{
|
|
//the program should never be here. This is a program error!
|
|
double slope;
|
|
for( IT it=activeLine.begin();
|
|
it!=activeLine.end(); ++it)
|
|
{
|
|
cout << "dist: " << CalcDistance(it->distance,
|
|
elem.pointInTime,slope) << ", Tuple: " << it->tuple << endl;
|
|
}
|
|
assert(false);
|
|
}
|
|
return cloneTuple;
|
|
}
|
|
|
|
|
|
Tuple* processIntersection(EventElem& elem) {
|
|
IT posFirst = findActiveElem( activeLine,
|
|
elem.distance, elem.pointInTime, elem.tuple);
|
|
IT posNext = posFirst;
|
|
++posNext;
|
|
|
|
IT posSec;
|
|
if( posNext == activeLine.end() ) {
|
|
//perhaps changed before
|
|
bool t1 = check(activeLine ,elem.pointInTime);
|
|
assert(t1);
|
|
return 0;
|
|
}
|
|
if( posNext->tuple != elem.tuple2 ) {
|
|
posSec = findActiveElem( activeLine,
|
|
elem.distance, elem.pointInTime, elem.tuple2);
|
|
} else {
|
|
posSec = posNext;
|
|
}
|
|
|
|
//check if the first of the inters.-tuples is the k. and give it out
|
|
Tuple* cloneTuple = NULL;
|
|
if( checkK(activeLine,k,posFirst)) {
|
|
cloneTuple = changeTupleUnit( posFirst->tuple,
|
|
attrPos, posFirst->start, elem.pointInTime,
|
|
posFirst->lc,posFirst->rc);
|
|
posFirst->start = elem.pointInTime;
|
|
posFirst->lc = true;
|
|
if( posNext != activeLine.end() ) {
|
|
posNext->start = elem.pointInTime;
|
|
posNext->lc = true;
|
|
}
|
|
}
|
|
|
|
if( posNext == posSec) {
|
|
//look for intersections between the new neighbors
|
|
checkIntersections(E_INTERSECT, elem.pointInTime,
|
|
posFirst, activeLine, eventQueue, endTime);
|
|
|
|
//swap the two entries in activeline
|
|
ActiveElem e = *posFirst;
|
|
*posFirst = *posSec;
|
|
*posSec = e;
|
|
} else {
|
|
//the are some elements which has the same distance between
|
|
//the two intersect elements, so calc like delete then insert
|
|
std::vector<ActiveElem> va;
|
|
std::set<Tuple*> s;
|
|
std::pair< std::set<Tuple*>::iterator, bool > pr;
|
|
|
|
ActiveElem newElem1(posFirst->distance,
|
|
posFirst->tuple, elem.pointInTime,
|
|
posFirst->end, posFirst->lc, posFirst->rc);
|
|
va.push_back(newElem1);
|
|
s.insert(posFirst->tuple);
|
|
activeLine.erase( posFirst );
|
|
ActiveElem newElem2(posSec->distance,
|
|
posSec->tuple, elem.pointInTime,
|
|
posSec->end, posSec->lc, posSec->rc);
|
|
va.push_back(newElem2);
|
|
s.insert(posSec->tuple);
|
|
activeLine.erase( posSec );
|
|
|
|
while( !eventQueue.empty() )
|
|
{
|
|
//handle all intersections at the same time
|
|
EventElem elemIs = eventQueue.top();
|
|
|
|
if( elemIs.type == E_INTERSECT
|
|
&& elem.pointInTime == elemIs.pointInTime) {
|
|
|
|
eventQueue.pop();
|
|
//eleminate same elements
|
|
deleteDupElements( eventQueue, elemIs.type,
|
|
elemIs.tuple, elemIs.tuple2, elem.pointInTime);
|
|
|
|
pr = s.insert( elemIs.tuple );
|
|
if(pr.second == true) {
|
|
//the element was not removed yet
|
|
IT pos = findActiveElem(activeLine,
|
|
elemIs.distance, elemIs.pointInTime, elemIs.tuple);
|
|
ActiveElem newElem(pos->distance,
|
|
pos->tuple, elem.pointInTime,
|
|
pos->end, pos->lc, pos->rc);
|
|
activeLine.erase( pos );
|
|
va.push_back(newElem);
|
|
}
|
|
pr = s.insert( elemIs.tuple2 );
|
|
if(pr.second == true) {
|
|
//the element was not removed yet
|
|
IT pos = findActiveElem(activeLine,
|
|
elemIs.distance, elemIs.pointInTime, elemIs.tuple2);
|
|
ActiveElem newElem(pos->distance,
|
|
pos->tuple, elem.pointInTime,
|
|
pos->end, pos->lc, pos->rc);
|
|
activeLine.erase( pos );
|
|
va.push_back(newElem);
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
std::vector<IT> vit;
|
|
for( unsigned int ii=0; ii < va.size(); ++ii )
|
|
{
|
|
IT newPos = insertActiveElem( activeLine,
|
|
va[ii], elem.pointInTime);
|
|
vit.push_back(newPos);
|
|
}
|
|
// check intersections
|
|
for( unsigned int ii=0; ii < vit.size(); ++ii )
|
|
{
|
|
checkIntersections(E_LEFT, elem.pointInTime, vit[ii],
|
|
activeLine, eventQueue,endTime);
|
|
}
|
|
}
|
|
return cloneTuple;
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
/*
|
|
check wheter the unit can be merged added into the list
|
|
1. time interval adjacent
|
|
2. evaluation function equal
|
|
3. the end point of the first movement equals to the start point of the second
|
|
movement
|
|
4. the start point of the first movement not equal to the end point of the
|
|
second movement
|
|
|
|
*/
|
|
bool KnearestLocalInfo::AddNewUnit(UPoint* up)
|
|
{
|
|
if(up_list.size() > 0){
|
|
UPoint last_up = up_list[up_list.size() - 1];
|
|
|
|
Point p1_1 = last_up.p0;
|
|
Point p1_2 = last_up.p1;
|
|
|
|
Point p2_1 = up->p0;
|
|
Point p2_2 = up->p1;
|
|
|
|
Interval<Instant> iv( last_up.timeInterval.start,
|
|
up->timeInterval.end,
|
|
last_up.timeInterval.lc,
|
|
up->timeInterval.rc);
|
|
|
|
if(AlmostEqual(p1_1,p1_2) && AlmostEqual(p1_2,p2_1) &&
|
|
AlmostEqual(p2_1,p2_2)){
|
|
|
|
UPoint* temp_up = new UPoint( iv, p1_1.GetX(), p1_1.GetY(),
|
|
p1_1.GetX(), p1_1.GetY());
|
|
|
|
up_list[up_list.size() - 1] = *temp_up;
|
|
delete temp_up;
|
|
return true;
|
|
|
|
}else if(AlmostEqual(p1_1.GetX(), p1_2.GetX()) &&
|
|
AlmostEqual(p2_1.GetX(), p2_2.GetX()) &&
|
|
AlmostEqual(p1_2, p2_1) && !AlmostEqual(p1_1,p2_2)){
|
|
|
|
double duration1 =
|
|
(last_up.timeInterval.end.ToDouble() -
|
|
last_up.timeInterval.start.ToDouble())*86400.0;
|
|
|
|
double duration2 =
|
|
(up->timeInterval.end.ToDouble() -
|
|
up->timeInterval.start.ToDouble())*86400.0;
|
|
double speed1 = p1_1.Distance(p1_2)/duration1;
|
|
double speed2 = p2_1.Distance(p2_2)/duration2;
|
|
|
|
if(AlmostEqual(speed1, speed2)){
|
|
UPoint* temp_up = new UPoint( iv, p1_1.GetX(), p1_1.GetY(),
|
|
p2_2.GetX(), p2_2.GetY());
|
|
|
|
up_list[up_list.size() - 1] = *temp_up;
|
|
delete temp_up;
|
|
return true;
|
|
}
|
|
|
|
}else{
|
|
|
|
double a1 = (p1_2.GetY() - p1_1.GetY())/(p1_2.GetX()- p1_1.GetX());
|
|
double b1 = p1_1.GetY() - a1*p1_1.GetX();
|
|
|
|
double a2 = (p2_2.GetY() - p2_1.GetY())/(p2_2.GetX()- p2_1.GetX());
|
|
double b2 = p2_1.GetY() - a2*p2_1.GetX();
|
|
if(AlmostEqual(p1_2, p2_1) && !AlmostEqual(p1_1,p2_2) &&
|
|
AlmostEqual(a1,a2) && AlmostEqual(b1,b2)){
|
|
|
|
if((p1_2.GetX() > p1_1.GetX() && p2_2.GetX() > p2_1.GetX()) ||
|
|
(p1_2.GetX() < p1_1.GetX() && p2_2.GetX() < p2_1.GetX())){
|
|
UPoint* temp_up = new UPoint( iv, p1_1.GetX(), p1_1.GetY(),
|
|
p2_2.GetX(), p2_2.GetY());
|
|
|
|
up_list[up_list.size() - 1] = *temp_up;
|
|
delete temp_up;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
|
|
}
|
|
|
|
void KnearestLocalInfo::MergeUnit(UPoint* up)
|
|
{
|
|
UPoint last_up = up_list[up_list.size() - 1];
|
|
|
|
Point p1_1 = last_up.p0;
|
|
Point p1_2 = last_up.p1;
|
|
|
|
Point p2_1 = up->p0;
|
|
Point p2_2 = up->p1;
|
|
|
|
Interval<Instant> iv( last_up.timeInterval.start,
|
|
up->timeInterval.end,
|
|
last_up.timeInterval.lc,
|
|
up->timeInterval.rc);
|
|
|
|
UPoint* temp_up = new UPoint( iv, p1_1.GetX(), p1_1.GetY(),
|
|
p2_2.GetX(), p2_2.GetY());
|
|
|
|
up_list[up_list.size() - 1] = *temp_up;
|
|
delete temp_up;
|
|
}
|
|
|
|
/*
|
|
newknearestFun is the main function of the operator knearest
|
|
The argument vector contains the following values:
|
|
args[0] = stream of tuples,
|
|
the attribute given in args[1] has to be a unit
|
|
the operator expects that the tuples are sorted by the time of the units
|
|
args[1] = attribute name
|
|
args[2] = mpoint
|
|
args[3] = int k, how many nearest are searched
|
|
args[4] optional zone number, value is ignored
|
|
args[4] or args[5] = int j, attributenumber
|
|
|
|
*/
|
|
|
|
int knearestFun (Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
switch (message)
|
|
{
|
|
/*
|
|
in open the eventqueue is initialized with the left
|
|
and the right elements
|
|
|
|
*/
|
|
case OPEN :
|
|
{
|
|
qp->Open(args[0].addr);
|
|
CcInt* k = static_cast<CcInt*>(args[3].addr);
|
|
const MPoint* mp = static_cast<const MPoint*>(args[2].addr);
|
|
int attrPos = (static_cast<CcInt*>
|
|
(args[qp->GetNoSons(s)-1].addr))->GetIntval() - 1;
|
|
if(!mp->IsDefined() || mp->IsEmpty() || !k->IsDefined()){
|
|
local.addr = 0;
|
|
return 0;
|
|
}
|
|
int ik = k->GetValue();
|
|
if(ik<=0){ // invalid number of neighbors
|
|
local.addr = 0;
|
|
return 0;
|
|
}
|
|
int zone = -1;
|
|
if(qp->GetNoSons(s)==6){ // zone given as an int
|
|
// compute the zone from the first point of mpoint
|
|
int de = 3;
|
|
int count = 120;
|
|
std::vector<int> de_list;
|
|
for(int i = 0;i < count ;i ++){
|
|
de_list.push_back(i*de);
|
|
}
|
|
|
|
double delta = std::numeric_limits<double>::max();
|
|
UPoint up;
|
|
mp->Get( 0, up);
|
|
double x = up.p0.GetX();
|
|
int index = -1;
|
|
for(unsigned int i = 0;i < de_list.size();i++){
|
|
if(i == 0){
|
|
delta = fabs(x - de_list[i]);
|
|
index = i;
|
|
}else{
|
|
if(fabs(x - de_list[i]) < delta){
|
|
delta = fabs(x - de_list[i]);
|
|
index = i;
|
|
}
|
|
}
|
|
}
|
|
// ignore the value given by the user.
|
|
zone = index;
|
|
}
|
|
cout << "use zone " << zone << endl;
|
|
local.addr = zone<0? new KnearestLocalInfo(args[0], attrPos, mp,
|
|
k->GetValue())
|
|
: new KnearestLocalInfo(args[0], attrPos, mp,
|
|
k->GetValue(), zone);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
in request the eventqueue is executed. new intersect events
|
|
are computed
|
|
|
|
*/
|
|
case REQUEST :
|
|
{
|
|
KnearestLocalInfo* li = (KnearestLocalInfo*) local.addr;
|
|
result.addr = li?li->next(): 0;
|
|
return result.addr?YIELD:CANCEL;
|
|
}
|
|
|
|
|
|
case CLOSE :
|
|
{
|
|
qp->Close(args[0].addr);
|
|
KnearestLocalInfo* localInfo = (KnearestLocalInfo*)local.addr;
|
|
if(localInfo){
|
|
delete localInfo;
|
|
local.setAddr(0);
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
return kth neighbor
|
|
|
|
*/
|
|
|
|
int newknearest_distFun1 (Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
switch (message)
|
|
{
|
|
|
|
case INIT : {
|
|
TupleType* tt = new TupleType(nl->Second(GetTupleResultType(s)));
|
|
qp->GetLocal2(s).addr = tt;
|
|
return 0;
|
|
}
|
|
case FINISH : {
|
|
TupleType* tt = (TupleType*) qp->GetLocal2(s).addr;
|
|
if(tt){
|
|
tt->DeleteIfAllowed();
|
|
qp->GetLocal2(s).addr=0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
in open the eventqueue is initialized with the left
|
|
and the right elements
|
|
|
|
*/
|
|
case OPEN :
|
|
{
|
|
TupleType* tt = (TupleType*) qp->GetLocal2(s).addr;
|
|
qp->Open(args[0].addr);
|
|
// CcInt* k = static_cast<CcInt*>(args[3].addr);
|
|
int k = (int)static_cast<CcReal*>(args[3].addr)->GetRealval();
|
|
|
|
const MPoint* mp = static_cast<const MPoint*>(args[2].addr);
|
|
int attrPos = (static_cast<CcInt*>(args[4].addr))->GetIntval() - 1;
|
|
int attrNr = ((CcInt*)args[4].addr)->GetIntval() - 1;
|
|
|
|
if(!mp->IsDefined() || mp->IsEmpty() || k < 1){
|
|
local.addr = 0;
|
|
} else{
|
|
KnearestLocalInfo* localInfo =
|
|
new KnearestLocalInfo(args[0], attrPos, mp, k, true);
|
|
|
|
localInfo->resulttype = tt;
|
|
|
|
unsigned int last_result_tid = 0;
|
|
////////////////first calculate the result/////////////////////////
|
|
while ( !localInfo->eventQueue.empty() ){
|
|
EventElem elem = localInfo->eventQueue.top();
|
|
localInfo->eventQueue.pop();
|
|
|
|
// cout<<elem.pointInTime<<endl;
|
|
|
|
//eleminate same elements
|
|
deleteDupElements( localInfo->eventQueue, elem.type,
|
|
elem.tuple, elem.tuple2, elem.pointInTime);
|
|
|
|
switch ( elem.type ){
|
|
case E_LEFT:
|
|
{
|
|
// cout<<"left "<<elem.pointInTime<<endl;
|
|
bool lc = elem.pointInTime >= localInfo->startTime
|
|
? elem.up->timeInterval.lc : false;
|
|
ActiveElem newElem(elem.distance, elem.tuple, elem.pointInTime,
|
|
elem.up->timeInterval.end, lc, elem.up->timeInterval.rc);
|
|
IT newPos = insertActiveElem( localInfo->activeLine,
|
|
newElem, elem.pointInTime);
|
|
|
|
// check intersections
|
|
checkIntersections(E_LEFT, elem.pointInTime,
|
|
newPos, localInfo->activeLine, localInfo->eventQueue,
|
|
localInfo->endTime);
|
|
|
|
bool hasChangedFirstK = false;
|
|
IT posAfterK;
|
|
if( localInfo->activeLine.size() > (unsigned) (localInfo->k) ){
|
|
posAfterK = checkFirstK(localInfo->activeLine,
|
|
localInfo->k,newPos,hasChangedFirstK);
|
|
|
|
}
|
|
|
|
if( hasChangedFirstK){
|
|
//something in the first k has changed
|
|
//now give out the k. element, but only until this time.
|
|
//Clone the tuple and change the unit-attribut to the
|
|
//new time interval
|
|
bool rc = newPos->lc ? false
|
|
: (posAfterK->end == elem.pointInTime ? posAfterK->rc : true);
|
|
if( posAfterK->start != elem.pointInTime
|
|
|| (rc && posAfterK->lc)){
|
|
|
|
bool KNeighbor = false;
|
|
IT posK = getKNeighbor(localInfo->activeLine,
|
|
localInfo->k, KNeighbor, elem.pointInTime);
|
|
if(KNeighbor){
|
|
if(localInfo->up_list.size() == 0){
|
|
last_result_tid = posK->tuple->GetTupleId();
|
|
// cout<<"start "<<last_result_tid<<endl;
|
|
}
|
|
|
|
int index = localInfo->up_list.size() - 1;
|
|
Tuple* cloneTuple = NULL;
|
|
if(index < 0){
|
|
bool l =
|
|
UPAtInstant(posK->tuple, posK->start, attrNr);
|
|
bool r =
|
|
UPAtInstant(posK->tuple, elem.pointInTime, attrNr);
|
|
|
|
cloneTuple = changeTupleUnit(
|
|
posK->tuple, attrNr, posK->start,
|
|
elem.pointInTime, l, r);
|
|
}else{
|
|
UPoint temp_up = localInfo->up_list[index];
|
|
Instant up_end = temp_up.timeInterval.end;
|
|
|
|
|
|
if(up_end < elem.pointInTime){
|
|
bool l =
|
|
UPAtInstant(posK->tuple, up_end, attrNr);
|
|
bool r =
|
|
UPAtInstant(posK->tuple, elem.pointInTime, attrNr);
|
|
|
|
cloneTuple = changeTupleUnit(
|
|
posK->tuple, attrNr, up_end,
|
|
elem.pointInTime, l, r);
|
|
}
|
|
}
|
|
if(cloneTuple != NULL){
|
|
int pos = localInfo->eventQueue.GetPos();
|
|
UPoint* up = (UPoint*)cloneTuple->GetAttribute(pos);
|
|
|
|
// if(localInfo->AddNewUnit(up) == false)
|
|
// localInfo->up_list.push_back(*up);
|
|
if(localInfo->up_list.size() > 0 &&
|
|
last_result_tid == posK->tuple->GetTupleId())
|
|
localInfo->MergeUnit(up);
|
|
else
|
|
localInfo->up_list.push_back(*up);
|
|
|
|
delete cloneTuple;
|
|
|
|
////////////record when the unit changes /////////////
|
|
if(posK->tuple->GetTupleId() != last_result_tid){
|
|
// cout<<"left "<<last_result_tid<<endl;
|
|
last_result_tid = posK->tuple->GetTupleId();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
posAfterK->start = elem.pointInTime;
|
|
posAfterK->lc = false;
|
|
}
|
|
}
|
|
|
|
|
|
break;
|
|
}
|
|
case E_RIGHT:
|
|
{
|
|
// cout<<"right "<<elem.pointInTime<<endl;
|
|
|
|
//a unit ends. It has to be removed from the map
|
|
IT posDel = findActiveElem( localInfo->activeLine,
|
|
elem.distance, elem.pointInTime, elem.tuple);
|
|
|
|
if( posDel != localInfo->activeLine.end()){
|
|
|
|
//check if this tuple is one of the first k, then give out this
|
|
//and change the start of the k+1 and the following to this time
|
|
bool hasDelFirstK = false;
|
|
IT posAfterK;
|
|
|
|
posAfterK = checkFirstK(localInfo->activeLine,
|
|
localInfo->k,posDel,hasDelFirstK);
|
|
|
|
|
|
if( hasDelFirstK && (posDel->start != elem.pointInTime
|
|
|| (posDel->lc && posDel->rc))){
|
|
if( posDel->start < localInfo->endTime ){
|
|
|
|
}
|
|
for( ; posAfterK != localInfo->activeLine.end(); ++posAfterK){
|
|
posAfterK->start = elem.pointInTime;
|
|
posAfterK->lc = false;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
bool KNeighbor = false;
|
|
IT posK = getKNeighbor(localInfo->activeLine,
|
|
localInfo->k, KNeighbor, elem.pointInTime);
|
|
if(KNeighbor){
|
|
if(localInfo->up_list.size() == 0)
|
|
last_result_tid = posK->tuple->GetTupleId();
|
|
|
|
int index = localInfo->up_list.size() - 1;
|
|
Tuple* cloneTuple = NULL;
|
|
if(index < 0){
|
|
bool l =
|
|
UPAtInstant(posK->tuple, posK->start, attrNr);
|
|
bool r =
|
|
UPAtInstant(posK->tuple, elem.pointInTime, attrNr);
|
|
|
|
cloneTuple = changeTupleUnit(
|
|
posK->tuple, attrNr, posK->start,
|
|
elem.pointInTime, l, r);
|
|
}else{
|
|
UPoint temp_up = localInfo->up_list[index];
|
|
Instant up_end = temp_up.timeInterval.end;
|
|
|
|
bool l =
|
|
UPAtInstant(posK->tuple, up_end, attrNr);
|
|
bool r =
|
|
UPAtInstant(posK->tuple, elem.pointInTime, attrNr);
|
|
|
|
if(up_end < elem.pointInTime){
|
|
cloneTuple = changeTupleUnit(
|
|
posK->tuple, attrNr, up_end,
|
|
elem.pointInTime, l, r);
|
|
}
|
|
}
|
|
if(cloneTuple != NULL){
|
|
int pos = localInfo->eventQueue.GetPos();
|
|
UPoint* up = (UPoint*)cloneTuple->GetAttribute(pos);
|
|
|
|
// if(localInfo->AddNewUnit(up) == false)
|
|
// localInfo->up_list.push_back(*up);
|
|
|
|
if(localInfo->up_list.size() > 0 &&
|
|
last_result_tid == posK->tuple->GetTupleId())
|
|
localInfo->MergeUnit(up);
|
|
else
|
|
localInfo->up_list.push_back(*up);
|
|
|
|
delete cloneTuple;
|
|
|
|
////////////record when the unit changes /////////////
|
|
if(posK->tuple->GetTupleId() != last_result_tid){
|
|
// cout<<"right "<<last_result_tid<<endl;
|
|
last_result_tid = posK->tuple->GetTupleId();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
//now calculate the intersection of the neighbors
|
|
checkIntersections(E_RIGHT, elem.pointInTime,
|
|
posDel, localInfo->activeLine, localInfo->eventQueue,
|
|
localInfo->endTime);
|
|
|
|
|
|
localInfo->activeLine.erase( posDel );
|
|
elem.distance->Destroy();
|
|
delete elem.distance;
|
|
elem.tuple->DeleteIfAllowed();
|
|
}
|
|
else{
|
|
//the program should never be here. This is a program error!
|
|
assert(false);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case E_INTERSECT:
|
|
{
|
|
// cout<<"intersect "<<elem.pointInTime<<endl;
|
|
|
|
IT posFirst = findActiveElem( localInfo->activeLine,
|
|
elem.distance, elem.pointInTime, elem.tuple);
|
|
IT posNext = posFirst;
|
|
++posNext;
|
|
|
|
IT posSec;
|
|
if( posNext == localInfo->activeLine.end() ){
|
|
//perhaps changed before
|
|
bool t1 = check(localInfo->activeLine ,elem.pointInTime);
|
|
assert(t1);
|
|
|
|
break;
|
|
}
|
|
if( posNext->tuple != elem.tuple2 ){
|
|
posSec = findActiveElem( localInfo->activeLine,
|
|
elem.distance, elem.pointInTime, elem.tuple2);
|
|
}
|
|
else{
|
|
posSec = posNext;
|
|
}
|
|
|
|
bool KNeighbor = false;
|
|
IT posK = getKNeighbor(localInfo->activeLine,
|
|
localInfo->k, KNeighbor, elem.pointInTime);
|
|
if(KNeighbor){
|
|
if(localInfo->up_list.size() == 0)
|
|
last_result_tid = posK->tuple->GetTupleId();
|
|
|
|
int index = localInfo->up_list.size() - 1;
|
|
Tuple* cloneTuple = NULL;
|
|
if(index < 0){
|
|
bool l =
|
|
UPAtInstant(posK->tuple, posK->start, attrNr);
|
|
bool r =
|
|
UPAtInstant(posK->tuple, elem.pointInTime, attrNr);
|
|
|
|
cloneTuple = changeTupleUnit(
|
|
posK->tuple, attrNr, posK->start,
|
|
elem.pointInTime, l, r);
|
|
}else{
|
|
UPoint temp_up = localInfo->up_list[index];
|
|
Instant up_end = temp_up.timeInterval.end;
|
|
|
|
bool l =
|
|
UPAtInstant(posK->tuple, up_end, attrNr);
|
|
bool r =
|
|
UPAtInstant(posK->tuple, elem.pointInTime, attrNr);
|
|
|
|
if(up_end < elem.pointInTime){
|
|
cloneTuple = changeTupleUnit(
|
|
posK->tuple, attrNr, up_end,
|
|
elem.pointInTime, l, r);
|
|
}
|
|
}
|
|
if(cloneTuple != NULL){
|
|
int pos = localInfo->eventQueue.GetPos();
|
|
UPoint* up = (UPoint*)cloneTuple->GetAttribute(pos);
|
|
|
|
// if(localInfo->AddNewUnit(up) == false)
|
|
// localInfo->up_list.push_back(*up);
|
|
|
|
if(localInfo->up_list.size() > 0 &&
|
|
last_result_tid == posK->tuple->GetTupleId())
|
|
localInfo->MergeUnit(up);
|
|
else
|
|
localInfo->up_list.push_back(*up);
|
|
|
|
delete cloneTuple;
|
|
|
|
////////////record when the unit changes /////////////
|
|
if(posK->tuple->GetTupleId() != last_result_tid){
|
|
last_result_tid = posK->tuple->GetTupleId();
|
|
// cout<<"intersect "<<last_result_tid<<endl;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//check if the first of the inters.-tuples is the k. and give it out
|
|
|
|
if( checkK(localInfo->activeLine,localInfo->k,posFirst)){
|
|
|
|
posFirst->start = elem.pointInTime;
|
|
posFirst->lc = true;
|
|
if( posNext != localInfo->activeLine.end() ){
|
|
posNext->start = elem.pointInTime;
|
|
posNext->lc = true;
|
|
}
|
|
}
|
|
|
|
if( posNext == posSec){
|
|
//look for intersections between the new neighbors
|
|
checkIntersections(E_INTERSECT, elem.pointInTime,
|
|
posFirst, localInfo->activeLine, localInfo->eventQueue,
|
|
localInfo->endTime);
|
|
|
|
//swap the two entries in activeline
|
|
ActiveElem e = *posFirst;
|
|
*posFirst = *posSec;
|
|
*posSec = e;
|
|
}else{
|
|
//the are some elements which has the same distance between
|
|
//the two intersect elements, so calc like delete then insert
|
|
std::vector<ActiveElem> va;
|
|
std::set<Tuple*> s;
|
|
std::pair< std::set<Tuple*>::iterator, bool > pr;
|
|
|
|
ActiveElem newElem1(posFirst->distance,
|
|
posFirst->tuple, elem.pointInTime,
|
|
posFirst->end, posFirst->lc, posFirst->rc);
|
|
va.push_back(newElem1);
|
|
s.insert(posFirst->tuple);
|
|
localInfo->activeLine.erase( posFirst );
|
|
ActiveElem newElem2(posSec->distance,
|
|
posSec->tuple, elem.pointInTime,
|
|
posSec->end, posSec->lc, posSec->rc);
|
|
va.push_back(newElem2);
|
|
s.insert(posSec->tuple);
|
|
localInfo->activeLine.erase( posSec );
|
|
|
|
while( !localInfo->eventQueue.empty() ){
|
|
//handle all intersections at the same time
|
|
EventElem elemIs = localInfo->eventQueue.top();
|
|
|
|
if( elemIs.type == E_INTERSECT
|
|
&& elem.pointInTime == elemIs.pointInTime)
|
|
{
|
|
|
|
localInfo->eventQueue.pop();
|
|
//eleminate same elements
|
|
deleteDupElements( localInfo->eventQueue, elemIs.type,
|
|
elemIs.tuple, elemIs.tuple2, elem.pointInTime);
|
|
|
|
pr = s.insert( elemIs.tuple );
|
|
if(pr.second == true)
|
|
{
|
|
//the element was not removed yet
|
|
IT pos = findActiveElem( localInfo->activeLine,
|
|
elemIs.distance, elemIs.pointInTime, elemIs.tuple);
|
|
ActiveElem newElem(pos->distance,
|
|
pos->tuple, elem.pointInTime,
|
|
pos->end, pos->lc, pos->rc);
|
|
localInfo->activeLine.erase( pos );
|
|
va.push_back(newElem);
|
|
}
|
|
pr = s.insert( elemIs.tuple2 );
|
|
if(pr.second == true)
|
|
{
|
|
//the element was not removed yet
|
|
IT pos = findActiveElem( localInfo->activeLine,
|
|
elemIs.distance, elemIs.pointInTime, elemIs.tuple2);
|
|
ActiveElem newElem(pos->distance,
|
|
pos->tuple, elem.pointInTime,
|
|
pos->end, pos->lc, pos->rc);
|
|
localInfo->activeLine.erase( pos );
|
|
va.push_back(newElem);
|
|
}
|
|
}
|
|
else{break;}
|
|
}
|
|
|
|
std::vector<IT> vit;
|
|
for( unsigned int ii=0; ii < va.size(); ++ii ){
|
|
IT newPos = insertActiveElem( localInfo->activeLine,
|
|
va[ii], elem.pointInTime);
|
|
vit.push_back(newPos);
|
|
}
|
|
// check intersections
|
|
for( unsigned int ii=0; ii < vit.size(); ++ii ){
|
|
checkIntersections(E_LEFT, elem.pointInTime, vit[ii],
|
|
localInfo->activeLine, localInfo->eventQueue,
|
|
localInfo->endTime);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
local = SetWord(localInfo);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
in request the eventqueue is executed. new intersect events
|
|
are computed
|
|
|
|
*/
|
|
case REQUEST :
|
|
{
|
|
if(!local.addr){
|
|
return CANCEL;
|
|
}
|
|
KnearestLocalInfo* localInfo = (KnearestLocalInfo*)local.addr;
|
|
|
|
if ( !localInfo->k)
|
|
{
|
|
return CANCEL;
|
|
}
|
|
if(localInfo->count == localInfo->up_list.size()) return CANCEL;
|
|
|
|
Tuple* tuple = new Tuple(localInfo->resulttype);
|
|
|
|
tuple->PutAttribute(0,
|
|
new UPoint(localInfo->up_list[localInfo->count]));
|
|
/* tuple->PutAttribute(1,
|
|
new MReal(localInfo->dist_list[localInfo->count]));*/
|
|
result.setAddr(tuple);
|
|
localInfo->count++;
|
|
return YIELD;
|
|
|
|
}
|
|
|
|
case CLOSE :
|
|
{
|
|
|
|
qp->Close(args[0].addr);
|
|
KnearestLocalInfo* localInfo = (KnearestLocalInfo*)local.addr;
|
|
if(localInfo){
|
|
if(localInfo->resulttype != NULL) delete localInfo->resulttype;
|
|
|
|
delete localInfo;
|
|
local.setAddr(0);
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
return mreal for the distance of kth neighbor
|
|
|
|
*/
|
|
int newknearest_distFun2 (Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
qp->Open(args[0].addr);
|
|
CcInt* k = static_cast<CcInt*>(args[3].addr);
|
|
|
|
const MPoint* mp = static_cast<const MPoint*>(args[2].addr);
|
|
int attrPos = (static_cast<CcInt*>(args[4].addr))->GetIntval() - 1;
|
|
int attrNr = ((CcInt*)args[4].addr)->GetIntval() - 1;
|
|
|
|
|
|
result = qp->ResultStorage(s);
|
|
MReal* presult = (MReal*)result.addr;
|
|
|
|
if(!mp->IsDefined() || mp->IsEmpty() || k->GetIntval() < 1){
|
|
MReal* res = new MReal(0);
|
|
*presult = *res;
|
|
delete res;
|
|
qp->Close(args[0].addr);
|
|
return 0;
|
|
}
|
|
|
|
KnearestLocalInfo* localInfo =
|
|
new KnearestLocalInfo(args[0], attrPos, mp, k->GetIntval(), true);
|
|
|
|
////////////////first calculate the result/////////////////////////
|
|
unsigned int last_result_tid = 0;
|
|
////////////////first calculate the result/////////////////////////
|
|
while ( !localInfo->eventQueue.empty() ){
|
|
EventElem elem = localInfo->eventQueue.top();
|
|
localInfo->eventQueue.pop();
|
|
|
|
// cout<<elem.pointInTime<<endl;
|
|
|
|
//eleminate same elements
|
|
deleteDupElements( localInfo->eventQueue, elem.type,
|
|
elem.tuple, elem.tuple2, elem.pointInTime);
|
|
|
|
switch ( elem.type ){
|
|
case E_LEFT:
|
|
{
|
|
// cout<<"left "<<elem.pointInTime<<endl;
|
|
bool lc = elem.pointInTime >= localInfo->startTime
|
|
? elem.up->timeInterval.lc : false;
|
|
ActiveElem newElem(elem.distance, elem.tuple, elem.pointInTime,
|
|
elem.up->timeInterval.end, lc, elem.up->timeInterval.rc);
|
|
IT newPos = insertActiveElem( localInfo->activeLine,
|
|
newElem, elem.pointInTime);
|
|
|
|
// check intersections
|
|
checkIntersections(E_LEFT, elem.pointInTime,
|
|
newPos, localInfo->activeLine, localInfo->eventQueue,
|
|
localInfo->endTime);
|
|
|
|
bool hasChangedFirstK = false;
|
|
IT posAfterK;
|
|
if( localInfo->activeLine.size() > (unsigned) localInfo->k ){
|
|
posAfterK = checkFirstK(localInfo->activeLine,
|
|
localInfo->k,newPos,hasChangedFirstK);
|
|
|
|
}
|
|
|
|
if( hasChangedFirstK){
|
|
//something in the first k has changed
|
|
//now give out the k. element, but only until this time.
|
|
//Clone the tuple and change the unit-attribut to the
|
|
//new time interval
|
|
bool rc = newPos->lc ? false
|
|
: (posAfterK->end == elem.pointInTime ? posAfterK->rc : true);
|
|
if( posAfterK->start != elem.pointInTime
|
|
|| (rc && posAfterK->lc)){
|
|
|
|
bool KNeighbor = false;
|
|
IT posK = getKNeighbor(localInfo->activeLine,
|
|
localInfo->k, KNeighbor, elem.pointInTime);
|
|
if(KNeighbor){
|
|
if(localInfo->up_list.size() == 0){
|
|
last_result_tid = posK->tuple->GetTupleId();
|
|
// cout<<"start "<<last_result_tid<<endl;
|
|
}
|
|
|
|
int index = localInfo->up_list.size() - 1;
|
|
Tuple* cloneTuple = NULL;
|
|
if(index < 0){
|
|
bool l =
|
|
UPAtInstant(posK->tuple, posK->start, attrNr);
|
|
bool r =
|
|
UPAtInstant(posK->tuple, elem.pointInTime, attrNr);
|
|
|
|
cloneTuple = changeTupleUnit(
|
|
posK->tuple, attrNr, posK->start,
|
|
elem.pointInTime, l, r);
|
|
}else{
|
|
UPoint temp_up = localInfo->up_list[index];
|
|
Instant up_end = temp_up.timeInterval.end;
|
|
|
|
|
|
if(up_end < elem.pointInTime){
|
|
bool l =
|
|
UPAtInstant(posK->tuple, up_end, attrNr);
|
|
bool r =
|
|
UPAtInstant(posK->tuple, elem.pointInTime, attrNr);
|
|
|
|
cloneTuple = changeTupleUnit(
|
|
posK->tuple, attrNr, up_end,
|
|
elem.pointInTime, l, r);
|
|
}
|
|
}
|
|
if(cloneTuple != NULL){
|
|
int pos = localInfo->eventQueue.GetPos();
|
|
UPoint* up = (UPoint*)cloneTuple->GetAttribute(pos);
|
|
|
|
// if(localInfo->AddNewUnit(up) == false)
|
|
// localInfo->up_list.push_back(*up);
|
|
if(localInfo->up_list.size() > 0 &&
|
|
last_result_tid == posK->tuple->GetTupleId())
|
|
localInfo->MergeUnit(up);
|
|
else
|
|
localInfo->up_list.push_back(*up);
|
|
|
|
delete cloneTuple;
|
|
|
|
////////////record when the unit changes /////////////
|
|
if(posK->tuple->GetTupleId() != last_result_tid){
|
|
// cout<<"left "<<last_result_tid<<endl;
|
|
last_result_tid = posK->tuple->GetTupleId();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
posAfterK->start = elem.pointInTime;
|
|
posAfterK->lc = false;
|
|
}
|
|
}
|
|
|
|
|
|
break;
|
|
}
|
|
case E_RIGHT:
|
|
{
|
|
// cout<<"right "<<elem.pointInTime<<endl;
|
|
|
|
//a unit ends. It has to be removed from the map
|
|
IT posDel = findActiveElem( localInfo->activeLine,
|
|
elem.distance, elem.pointInTime, elem.tuple);
|
|
|
|
if( posDel != localInfo->activeLine.end()){
|
|
|
|
//check if this tuple is one of the first k, then give out this
|
|
//and change the start of the k+1 and the following to this time
|
|
bool hasDelFirstK = false;
|
|
IT posAfterK;
|
|
|
|
posAfterK = checkFirstK(localInfo->activeLine,
|
|
localInfo->k,posDel,hasDelFirstK);
|
|
|
|
|
|
if( hasDelFirstK && (posDel->start != elem.pointInTime
|
|
|| (posDel->lc && posDel->rc))){
|
|
if( posDel->start < localInfo->endTime ){
|
|
|
|
}
|
|
for( ; posAfterK != localInfo->activeLine.end(); ++posAfterK){
|
|
posAfterK->start = elem.pointInTime;
|
|
posAfterK->lc = false;
|
|
}
|
|
}
|
|
|
|
bool KNeighbor = false;
|
|
IT posK = getKNeighbor(localInfo->activeLine,
|
|
localInfo->k, KNeighbor, elem.pointInTime);
|
|
if(KNeighbor){
|
|
if(localInfo->up_list.size() == 0)
|
|
last_result_tid = posK->tuple->GetTupleId();
|
|
|
|
int index = localInfo->up_list.size() - 1;
|
|
Tuple* cloneTuple = NULL;
|
|
if(index < 0){
|
|
bool l =
|
|
UPAtInstant(posK->tuple, posK->start, attrNr);
|
|
bool r =
|
|
UPAtInstant(posK->tuple, elem.pointInTime, attrNr);
|
|
|
|
cloneTuple = changeTupleUnit(
|
|
posK->tuple, attrNr, posK->start,
|
|
elem.pointInTime, l, r);
|
|
}else{
|
|
UPoint temp_up = localInfo->up_list[index];
|
|
Instant up_end = temp_up.timeInterval.end;
|
|
|
|
bool l =
|
|
UPAtInstant(posK->tuple, up_end, attrNr);
|
|
bool r =
|
|
UPAtInstant(posK->tuple, elem.pointInTime, attrNr);
|
|
|
|
if(up_end < elem.pointInTime){
|
|
cloneTuple = changeTupleUnit(
|
|
posK->tuple, attrNr, up_end,
|
|
elem.pointInTime, l, r);
|
|
}
|
|
}
|
|
if(cloneTuple != NULL){
|
|
int pos = localInfo->eventQueue.GetPos();
|
|
UPoint* up = (UPoint*)cloneTuple->GetAttribute(pos);
|
|
|
|
// if(localInfo->AddNewUnit(up) == false)
|
|
// localInfo->up_list.push_back(*up);
|
|
|
|
if(localInfo->up_list.size() > 0 &&
|
|
last_result_tid == posK->tuple->GetTupleId())
|
|
localInfo->MergeUnit(up);
|
|
else
|
|
localInfo->up_list.push_back(*up);
|
|
|
|
delete cloneTuple;
|
|
|
|
////////////record when the unit changes /////////////
|
|
if(posK->tuple->GetTupleId() != last_result_tid){
|
|
// cout<<"right "<<last_result_tid<<endl;
|
|
last_result_tid = posK->tuple->GetTupleId();
|
|
}
|
|
}
|
|
}
|
|
|
|
//now calculate the intersection of the neighbors
|
|
checkIntersections(E_RIGHT, elem.pointInTime,
|
|
posDel, localInfo->activeLine, localInfo->eventQueue,
|
|
localInfo->endTime);
|
|
|
|
|
|
localInfo->activeLine.erase( posDel );
|
|
elem.distance->Destroy();
|
|
delete elem.distance;
|
|
elem.tuple->DeleteIfAllowed();
|
|
}
|
|
else{
|
|
//the program should never be here. This is a program error!
|
|
assert(false);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case E_INTERSECT:
|
|
{
|
|
// cout<<"intersect "<<elem.pointInTime<<endl;
|
|
|
|
IT posFirst = findActiveElem( localInfo->activeLine,
|
|
elem.distance, elem.pointInTime, elem.tuple);
|
|
IT posNext = posFirst;
|
|
++posNext;
|
|
|
|
IT posSec;
|
|
if( posNext == localInfo->activeLine.end() ){
|
|
//perhaps changed before
|
|
bool t1 = check(localInfo->activeLine ,elem.pointInTime);
|
|
assert(t1);
|
|
|
|
break;
|
|
}
|
|
if( posNext->tuple != elem.tuple2 ){
|
|
posSec = findActiveElem( localInfo->activeLine,
|
|
elem.distance, elem.pointInTime, elem.tuple2);
|
|
}
|
|
else
|
|
posSec = posNext;
|
|
|
|
bool KNeighbor = false;
|
|
IT posK = getKNeighbor(localInfo->activeLine,
|
|
localInfo->k, KNeighbor, elem.pointInTime);
|
|
if(KNeighbor){
|
|
if(localInfo->up_list.size() == 0)
|
|
last_result_tid = posK->tuple->GetTupleId();
|
|
|
|
int index = localInfo->up_list.size() - 1;
|
|
Tuple* cloneTuple = NULL;
|
|
if(index < 0){
|
|
bool l =
|
|
UPAtInstant(posK->tuple, posK->start, attrNr);
|
|
bool r =
|
|
UPAtInstant(posK->tuple, elem.pointInTime, attrNr);
|
|
|
|
cloneTuple = changeTupleUnit(
|
|
posK->tuple, attrNr, posK->start,
|
|
elem.pointInTime, l, r);
|
|
}else{
|
|
UPoint temp_up = localInfo->up_list[index];
|
|
Instant up_end = temp_up.timeInterval.end;
|
|
|
|
bool l =
|
|
UPAtInstant(posK->tuple, up_end, attrNr);
|
|
bool r =
|
|
UPAtInstant(posK->tuple, elem.pointInTime, attrNr);
|
|
|
|
if(up_end < elem.pointInTime){
|
|
cloneTuple = changeTupleUnit(
|
|
posK->tuple, attrNr, up_end,
|
|
elem.pointInTime, l, r);
|
|
}
|
|
}
|
|
if(cloneTuple != NULL){
|
|
int pos = localInfo->eventQueue.GetPos();
|
|
UPoint* up = (UPoint*)cloneTuple->GetAttribute(pos);
|
|
|
|
// if(localInfo->AddNewUnit(up) == false)
|
|
// localInfo->up_list.push_back(*up);
|
|
|
|
if(localInfo->up_list.size() > 0 &&
|
|
last_result_tid == posK->tuple->GetTupleId())
|
|
localInfo->MergeUnit(up);
|
|
else
|
|
localInfo->up_list.push_back(*up);
|
|
|
|
delete cloneTuple;
|
|
|
|
////////////record when the unit changes /////////////
|
|
if(posK->tuple->GetTupleId() != last_result_tid){
|
|
last_result_tid = posK->tuple->GetTupleId();
|
|
// cout<<"intersect "<<last_result_tid<<endl;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
//check if the first of the inters.-tuples is the k. and give it out
|
|
|
|
if( checkK(localInfo->activeLine,localInfo->k,posFirst)){
|
|
|
|
posFirst->start = elem.pointInTime;
|
|
posFirst->lc = true;
|
|
if( posNext != localInfo->activeLine.end() ){
|
|
posNext->start = elem.pointInTime;
|
|
posNext->lc = true;
|
|
}
|
|
}
|
|
|
|
if( posNext == posSec){
|
|
//look for intersections between the new neighbors
|
|
checkIntersections(E_INTERSECT, elem.pointInTime,
|
|
posFirst, localInfo->activeLine, localInfo->eventQueue,
|
|
localInfo->endTime);
|
|
|
|
//swap the two entries in activeline
|
|
ActiveElem e = *posFirst;
|
|
*posFirst = *posSec;
|
|
*posSec = e;
|
|
}else{
|
|
//the are some elements which has the same distance between
|
|
//the two intersect elements, so calc like delete then insert
|
|
std::vector<ActiveElem> va;
|
|
std::set<Tuple*> s;
|
|
std::pair< std::set<Tuple*>::iterator, bool > pr;
|
|
|
|
ActiveElem newElem1(posFirst->distance,
|
|
posFirst->tuple, elem.pointInTime,
|
|
posFirst->end, posFirst->lc, posFirst->rc);
|
|
va.push_back(newElem1);
|
|
s.insert(posFirst->tuple);
|
|
localInfo->activeLine.erase( posFirst );
|
|
ActiveElem newElem2(posSec->distance,
|
|
posSec->tuple, elem.pointInTime,
|
|
posSec->end, posSec->lc, posSec->rc);
|
|
va.push_back(newElem2);
|
|
s.insert(posSec->tuple);
|
|
localInfo->activeLine.erase( posSec );
|
|
|
|
while( !localInfo->eventQueue.empty() ){
|
|
//handle all intersections at the same time
|
|
EventElem elemIs = localInfo->eventQueue.top();
|
|
|
|
if( elemIs.type == E_INTERSECT
|
|
&& elem.pointInTime == elemIs.pointInTime)
|
|
{
|
|
|
|
localInfo->eventQueue.pop();
|
|
//eleminate same elements
|
|
deleteDupElements( localInfo->eventQueue, elemIs.type,
|
|
elemIs.tuple, elemIs.tuple2, elem.pointInTime);
|
|
|
|
pr = s.insert( elemIs.tuple );
|
|
if(pr.second == true)
|
|
{
|
|
//the element was not removed yet
|
|
IT pos = findActiveElem( localInfo->activeLine,
|
|
elemIs.distance, elemIs.pointInTime, elemIs.tuple);
|
|
ActiveElem newElem(pos->distance,
|
|
pos->tuple, elem.pointInTime,
|
|
pos->end, pos->lc, pos->rc);
|
|
localInfo->activeLine.erase( pos );
|
|
va.push_back(newElem);
|
|
}
|
|
pr = s.insert( elemIs.tuple2 );
|
|
if(pr.second == true)
|
|
{
|
|
//the element was not removed yet
|
|
IT pos = findActiveElem( localInfo->activeLine,
|
|
elemIs.distance, elemIs.pointInTime, elemIs.tuple2);
|
|
ActiveElem newElem(pos->distance,
|
|
pos->tuple, elem.pointInTime,
|
|
pos->end, pos->lc, pos->rc);
|
|
localInfo->activeLine.erase( pos );
|
|
va.push_back(newElem);
|
|
}
|
|
}
|
|
else{break;}
|
|
}
|
|
|
|
std::vector<IT> vit;
|
|
for( unsigned int ii=0; ii < va.size(); ++ii ){
|
|
IT newPos = insertActiveElem( localInfo->activeLine,
|
|
va[ii], elem.pointInTime);
|
|
vit.push_back(newPos);
|
|
}
|
|
// check intersections
|
|
for( unsigned int ii=0; ii < vit.size(); ++ii ){
|
|
checkIntersections(E_LEFT, elem.pointInTime, vit[ii],
|
|
localInfo->activeLine, localInfo->eventQueue,
|
|
localInfo->endTime);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/////////////calculate the distance//////////////////////////////
|
|
int mpos = 0;
|
|
presult->Clear();
|
|
presult->StartBulkLoad();
|
|
for(unsigned int i = 0;i < localInfo->up_list.size();i++){
|
|
MReal* mr = new MReal(0);
|
|
GetDistance( mp, &localInfo->up_list[i], mpos, mr);
|
|
for(int j = 0; j < mr->GetNoComponents(); j++){
|
|
UReal uReal;
|
|
mr->Get(j, uReal );
|
|
presult->MergeAdd(uReal);
|
|
}
|
|
delete mr;
|
|
}
|
|
presult->EndBulkLoad( false, false );
|
|
|
|
delete localInfo;
|
|
|
|
qp->Close(args[0].addr);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
checks if there are intersections and puts them into the eventqueue
|
|
this is the right function if the eventqueue is a vector
|
|
|
|
*/
|
|
void checkIntersections(EventType type, Instant &time, unsigned int pos,
|
|
std::vector< ActiveElem > &v,
|
|
KNearestQueue &evq, Instant &endTime)
|
|
{
|
|
switch ( type ){
|
|
case E_LEFT:
|
|
{
|
|
Instant intersectTime( time.GetType() );
|
|
if( pos + 1 < v.size() &&
|
|
intersects( v[pos].distance, v[pos+1].distance,
|
|
time, intersectTime, true ))
|
|
{
|
|
evq.push( EventElem(E_INTERSECT,
|
|
intersectTime, v[pos].tuple, v[pos+1].tuple, v[pos].distance) );
|
|
}
|
|
if( pos > 0 &&
|
|
intersects( v[pos-1].distance, v[pos].distance, time,
|
|
intersectTime, true ))
|
|
{
|
|
evq.push( EventElem(E_INTERSECT, intersectTime,
|
|
v[pos-1].tuple, v[pos].tuple, v[pos-1].distance) );
|
|
}
|
|
break;
|
|
}
|
|
case E_RIGHT:
|
|
{
|
|
if( pos > 0 && pos+1 < v.size() && time < endTime)
|
|
{
|
|
Instant intersectTime( time.GetType() );
|
|
if( intersects( v[pos-1].distance, v[pos+1].distance,
|
|
time, intersectTime, false ) )
|
|
{
|
|
evq.push( EventElem(E_INTERSECT, intersectTime,
|
|
v[pos-1].tuple, v[pos+1].tuple, v[pos-1].distance) );
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case E_INTERSECT:
|
|
{
|
|
//look for intersections between the new neighbors
|
|
if( pos > 0 )
|
|
{
|
|
Instant intersectTime( time.GetType() );
|
|
if( intersects( v[pos-1].distance, v[pos+1].distance,
|
|
time, intersectTime, false ) )
|
|
{
|
|
evq.push( EventElem(E_INTERSECT, intersectTime, v[pos-1].tuple,
|
|
v[pos+1].tuple, v[pos-1].distance) );
|
|
}
|
|
}
|
|
if( pos+2 < v.size() )
|
|
{
|
|
Instant intersectTime( time.GetType() );
|
|
if( intersects( v[pos].distance, v[pos+2].distance,
|
|
time, intersectTime, false ) )
|
|
{
|
|
evq.push( EventElem(E_INTERSECT, intersectTime, v[pos].tuple,
|
|
v[pos+2].tuple, v[pos].distance) );
|
|
}
|
|
}
|
|
//look for new intersections between the old neighbors
|
|
Instant intersectTime( time.GetType() );
|
|
if( intersects( v[pos+1].distance, v[pos].distance,
|
|
time, intersectTime, true ) )
|
|
{
|
|
evq.push( EventElem(E_INTERSECT, intersectTime,
|
|
v[pos+1].tuple, v[pos].tuple, v[pos+1].distance) );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
To use the plane sweep algrithmus a priority queue for the events and
|
|
a vector to save the active segments is needed.
|
|
|
|
*/
|
|
struct KnearestLocalInfoVector
|
|
{
|
|
KnearestLocalInfoVector(Word& stream, int attrPos,
|
|
const MPoint* mp, int k1, bool scanFlag1):
|
|
k(k1),scanFlag(scanFlag1), eventQueue(stream, qp, attrPos, mp){}
|
|
unsigned int k;
|
|
//int max;
|
|
bool scanFlag;
|
|
Instant startTime, endTime;
|
|
std::vector< ActiveElem > activeLine;
|
|
KNearestQueue eventQueue;
|
|
};
|
|
|
|
/*
|
|
knearestFunVector is the value function for the knearestvector operator
|
|
which uses a vector to handle the active elements. the functionality
|
|
is the same like knearestfun
|
|
The argument vector contains the following values:
|
|
args[0] = stream of tuples,
|
|
the attribute given in args[1] has to be a unit
|
|
the operator expects that the tuples are sorted by the time of the units
|
|
args[1] = attribute name
|
|
args[2] = mpoint
|
|
args[3] = int k, how many nearest are searched
|
|
args[4] = int j, attributenumber
|
|
|
|
*/
|
|
int knearestFunVector (Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
|
|
KnearestLocalInfoVector *localInfo;
|
|
|
|
switch (message)
|
|
{
|
|
case OPEN :
|
|
{
|
|
qp->Open(args[0].addr);
|
|
CcInt* CcK = static_cast<CcInt*>(args[3].addr);
|
|
if(!CcK->IsDefined()){
|
|
local.setAddr(0);
|
|
return 0;
|
|
}
|
|
int k = CcK->GetIntval();
|
|
int attrPos = ((CcInt*)args[4].addr)->GetIntval() - 1;
|
|
|
|
MPoint* mp = static_cast<MPoint*>(args[2].addr);
|
|
if(!mp->IsDefined() || mp->IsEmpty()){
|
|
local.setAddr(0);
|
|
return 0;
|
|
}
|
|
|
|
Word stream(args[0]);
|
|
localInfo = new KnearestLocalInfoVector(stream, attrPos, mp, k, true);
|
|
localInfo->activeLine.reserve(100);
|
|
local = SetWord(localInfo);
|
|
UPoint up1, up2;
|
|
mp->Get( 0, up1);
|
|
mp->Get( mp->GetNoComponents() - 1, up2);
|
|
localInfo->startTime = up1.timeInterval.start;
|
|
localInfo->endTime = up2.timeInterval.end;
|
|
return 0;
|
|
}
|
|
|
|
case REQUEST :
|
|
{
|
|
int attrNr = ((CcInt*)args[4].addr)->GetIntval() - 1;
|
|
localInfo = (KnearestLocalInfoVector*)local.addr;
|
|
if(!localInfo){
|
|
return CANCEL;
|
|
}
|
|
|
|
if ( !localInfo->scanFlag )
|
|
{
|
|
return CANCEL;
|
|
}
|
|
|
|
if ( !localInfo->k)
|
|
{
|
|
return CANCEL;
|
|
}
|
|
|
|
while ( !localInfo->eventQueue.empty() )
|
|
{
|
|
EventElem elem = localInfo->eventQueue.top();
|
|
localInfo->eventQueue.pop();
|
|
ActiveElem::currtime = elem.pointInTime;
|
|
while( !localInfo->eventQueue.empty() )
|
|
{
|
|
//eleminate same elements
|
|
EventElem elem2 = localInfo->eventQueue.top();
|
|
if( elem.type != elem2.type
|
|
|| elem.pointInTime != elem2.pointInTime
|
|
|| elem.tuple != elem2.tuple || elem.tuple2 != elem2.tuple2)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
localInfo->eventQueue.pop();
|
|
}
|
|
}
|
|
switch ( elem.type ){
|
|
case E_LEFT:
|
|
{
|
|
// insert new element
|
|
bool lc = elem.pointInTime >= localInfo->startTime
|
|
? elem.up->timeInterval.lc : false;
|
|
ActiveElem newElem(elem.distance, elem.tuple, elem.pointInTime,
|
|
elem.up->timeInterval.end, lc, elem.up->timeInterval.rc);
|
|
unsigned int newPos = insertActiveElem( localInfo->activeLine,
|
|
newElem, elem.pointInTime);
|
|
|
|
// check intersections
|
|
checkIntersections(E_LEFT, elem.pointInTime,
|
|
newPos, localInfo->activeLine, localInfo->eventQueue,
|
|
localInfo->endTime);
|
|
|
|
// check if one element must given out
|
|
if( localInfo->activeLine.size() > localInfo->k
|
|
&& newPos < localInfo->k)
|
|
{
|
|
//something in the first k has changed
|
|
//now give out the k. element, but only until this time.
|
|
//Clone the tuple and change the unit-attribut to the
|
|
//new time interval
|
|
bool rc = localInfo->activeLine[newPos].lc ? false
|
|
: (localInfo->activeLine[localInfo->k].end == elem.pointInTime
|
|
? localInfo->activeLine[localInfo->k].rc : true);
|
|
if( localInfo->activeLine[localInfo->k].start != elem.pointInTime
|
|
|| (rc && localInfo->activeLine[localInfo->k].lc))
|
|
{
|
|
Tuple* cloneTuple = changeTupleUnit(
|
|
localInfo->activeLine[localInfo->k].tuple,
|
|
attrNr, localInfo->activeLine[localInfo->k].start,
|
|
elem.pointInTime, localInfo->activeLine[localInfo->k].lc,
|
|
rc);
|
|
localInfo->activeLine[localInfo->k].start = elem.pointInTime;
|
|
localInfo->activeLine[localInfo->k].lc = false;
|
|
result = SetWord(cloneTuple);
|
|
return YIELD;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case E_RIGHT:
|
|
{
|
|
//a unit ends. It has to be removed from the map
|
|
//look for the right tuple
|
|
//(more elements can have the same distance)
|
|
unsigned int posDel = findActiveElem( localInfo->activeLine,
|
|
elem.distance, elem.pointInTime, elem.tuple);
|
|
|
|
Tuple* cloneTuple = NULL;
|
|
if( posDel < localInfo->activeLine.size())
|
|
{
|
|
//check if this tuple is one of the first k, then give out this
|
|
//and change the start of the k+1 and the following to this time
|
|
if( posDel < localInfo->k
|
|
&& (localInfo->activeLine[posDel].start != elem.pointInTime
|
|
|| (localInfo->activeLine[posDel].lc
|
|
&& localInfo->activeLine[posDel].rc)))
|
|
{
|
|
if( localInfo->activeLine[posDel].start < localInfo->endTime )
|
|
{
|
|
cloneTuple = changeTupleUnit(
|
|
localInfo->activeLine[posDel].tuple, attrNr,
|
|
localInfo->activeLine[posDel].start, elem.pointInTime,
|
|
localInfo->activeLine[posDel].lc,
|
|
localInfo->activeLine[posDel].rc);
|
|
}
|
|
if( localInfo->k < localInfo->activeLine.size() )
|
|
{
|
|
for( unsigned int ii = localInfo->k;
|
|
ii < localInfo->activeLine.size(); ++ii)
|
|
{
|
|
localInfo->activeLine[ii].start = elem.pointInTime;
|
|
localInfo->activeLine[ii].lc = false;
|
|
}
|
|
}
|
|
}
|
|
//now calculate the intersection of the neighbors
|
|
checkIntersections(E_RIGHT, elem.pointInTime,
|
|
posDel, localInfo->activeLine, localInfo->eventQueue,
|
|
localInfo->endTime);
|
|
|
|
//delete the element in the active elements
|
|
localInfo->activeLine.erase( localInfo->activeLine.begin()
|
|
+ posDel );
|
|
elem.distance->Destroy();
|
|
delete elem.distance;
|
|
elem.tuple->DeleteIfAllowed();
|
|
}
|
|
else
|
|
{
|
|
//the program should never be here. This is a program error!
|
|
double slope;
|
|
for( ITV it=localInfo->activeLine.begin();
|
|
it!=localInfo->activeLine.end(); ++it)
|
|
{
|
|
cout << "dist: " << CalcDistance(it->distance,
|
|
elem.pointInTime,slope) << ", Tuple: " << it->tuple << endl;
|
|
}
|
|
assert(false);
|
|
}
|
|
if( cloneTuple )
|
|
{
|
|
result = SetWord(cloneTuple);
|
|
return YIELD;
|
|
}
|
|
break;
|
|
}
|
|
case E_INTERSECT:
|
|
unsigned int pos = findActiveElem( localInfo->activeLine,
|
|
elem.distance, elem.pointInTime, elem.tuple);
|
|
|
|
unsigned int posnext = findActiveElem( localInfo->activeLine,
|
|
elem.distance, elem.pointInTime, elem.tuple2);
|
|
if( posnext < pos)
|
|
{
|
|
//perhaps changed before
|
|
bool t1 = check(localInfo->activeLine ,elem.pointInTime);
|
|
assert(t1);
|
|
break;
|
|
}
|
|
|
|
//check if the first of the inters.-tuples is the k. and give it out
|
|
Tuple* cloneTuple = NULL;
|
|
if( pos + 1 == localInfo->k )
|
|
{
|
|
cloneTuple = changeTupleUnit( localInfo->activeLine[pos].tuple,
|
|
attrNr, localInfo->activeLine[pos].start, elem.pointInTime,
|
|
localInfo->activeLine[pos].lc,localInfo->activeLine[pos].rc);
|
|
localInfo->activeLine[pos].start = elem.pointInTime;
|
|
localInfo->activeLine[pos].lc = true;
|
|
localInfo->activeLine[pos+1].start = elem.pointInTime;
|
|
localInfo->activeLine[pos+1].lc = true;
|
|
}
|
|
|
|
if( posnext == pos + 1)
|
|
{
|
|
//look for intersections between the new neighbors
|
|
//and the old neighbors
|
|
checkIntersections(E_INTERSECT, elem.pointInTime,
|
|
pos, localInfo->activeLine, localInfo->eventQueue,
|
|
localInfo->endTime);
|
|
|
|
//swap the two entries in activeline
|
|
ActiveElem e = localInfo->activeLine[pos];
|
|
localInfo->activeLine[pos] = localInfo->activeLine[pos+1];
|
|
localInfo->activeLine[pos+1] = e;
|
|
}
|
|
else
|
|
{
|
|
//the are some elements which has the same distance between
|
|
//the two intersect elements, so calc like delete then insert
|
|
checkIntersections(E_RIGHT, elem.pointInTime,
|
|
posnext, localInfo->activeLine, localInfo->eventQueue,
|
|
localInfo->endTime);
|
|
|
|
ActiveElem newElem(localInfo->activeLine[posnext].distance,
|
|
localInfo->activeLine[posnext].tuple, elem.pointInTime,
|
|
localInfo->activeLine[posnext].end,
|
|
localInfo->activeLine[posnext].lc,
|
|
localInfo->activeLine[posnext].rc);
|
|
localInfo->activeLine.erase( localInfo->activeLine.begin()
|
|
+ posnext );
|
|
unsigned int newPos = insertActiveElem( localInfo->activeLine,
|
|
newElem, elem.pointInTime);
|
|
|
|
// check intersections
|
|
checkIntersections(E_LEFT, elem.pointInTime, newPos,
|
|
localInfo->activeLine, localInfo->eventQueue,
|
|
localInfo->endTime);
|
|
}
|
|
if( cloneTuple )
|
|
{
|
|
result = SetWord(cloneTuple);
|
|
return YIELD;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return CANCEL;
|
|
}
|
|
|
|
case CLOSE :
|
|
{
|
|
qp->Close(args[0].addr);
|
|
localInfo = (KnearestLocalInfoVector*)local.addr;
|
|
if(localInfo){
|
|
delete localInfo;
|
|
local.setAddr(0);
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
The ~oldknearestfilter~ operator results a stream of all input tuples which
|
|
can be the k-nearest units to the given mpoint. With the result of this
|
|
operator the knearest operator kann immediate be called. The tuples in the
|
|
result stream ordered by time.
|
|
|
|
The struct KnearestFilterLocalInfo is needed to save the data
|
|
from one to next function call.
|
|
All needet types are defined in NearestNeighborAlgebra.h
|
|
|
|
*/
|
|
|
|
/*
|
|
make a 2 dimensional box of a three dimensional
|
|
|
|
*/
|
|
const BBox<2> makexyBox( const BBox<3> box)
|
|
{
|
|
double minMax[] = { box.MinD(0), box.MaxD(0),
|
|
box.MinD(1), box.MaxD(1)};
|
|
return BBox<2>( true,minMax);
|
|
}
|
|
|
|
/*
|
|
calculates the maximum distance of two 2 dimensional boxes
|
|
|
|
*/
|
|
double maxDistance( const BBox<2> box1, const BBox<2> box2)
|
|
{
|
|
//the points of the vertices are (x,y) = (minD(0), minD(1))
|
|
//and (maxD(0), maxD(1))
|
|
double ax1, ay1, ax2, ay2;
|
|
double bx1, by1, bx2, by2;
|
|
ax1 = box1.MinD(0);
|
|
ay1 = box1.MinD(1);
|
|
ax2 = box1.MaxD(0);
|
|
ay2 = box1.MaxD(1);
|
|
bx1 = box2.MinD(0);
|
|
by1 = box2.MinD(1);
|
|
bx2 = box2.MaxD(0);
|
|
by2 = box2.MaxD(1);
|
|
//make four diagonals and calc the length, the the maximum
|
|
double d1 = pow(bx2 - ax1,2) + pow(by2-ay1,2);
|
|
double d2 = pow(bx2 - ax1,2) + pow(by1-ay2,2);
|
|
double d3 = pow(bx1 - ax2,2) + pow(by2-ay1,2);
|
|
double d4 = pow(bx1 - ax2,2) + pow(by1-ay2,2);
|
|
// double d = MIN( (MIN( d1, d2)), (MIN( d3, d4)) );
|
|
double d = MAX( (MAX( d1, d2)), (MAX( d3, d4)));
|
|
return sqrt(d);
|
|
}
|
|
|
|
/*
|
|
the recursive helpfunction of the function coverage
|
|
|
|
*/
|
|
template<class timeType>
|
|
void helpcoverage(int cycle, std::map<timeType, int> &m,
|
|
R_Tree<3, TupleId>* rtree,
|
|
timeType &t, SmiRecordId nodeid, int level)
|
|
{
|
|
const int dim = 3;
|
|
R_TreeNode<dim, TupleId> *tmp = rtree->GetMyNode(
|
|
nodeid, false,
|
|
rtree->MinEntries( level ),
|
|
rtree->MaxEntries( level ) );
|
|
for ( int ii = 0; ii < tmp->EntryCount(); ++ii )
|
|
{
|
|
if ( tmp->IsLeaf() )
|
|
{
|
|
R_TreeLeafEntry<dim, TupleId> e =
|
|
(R_TreeLeafEntry<dim, TupleId>&)(*tmp)[ii];
|
|
timeType ts(e.box.MinD(2));
|
|
timeType te(e.box.MaxD(2));
|
|
if( cycle == 0)
|
|
{
|
|
if( ts < t ) m[ts] = 0;
|
|
if( te < t ) m[te] = 0;
|
|
}
|
|
else
|
|
{
|
|
typedef typename std::map<timeType, int>::iterator ITMAP;
|
|
ITMAP it = m.find(ts);
|
|
while( it != m.end() && it->first < te)
|
|
{
|
|
++(it->second);
|
|
++it;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
R_TreeInternalEntry<dim> e =
|
|
(R_TreeInternalEntry<dim>&)(*tmp)[ii];
|
|
helpcoverage<timeType>( cycle, m, rtree, t, e.pointer, level + 1);
|
|
}
|
|
}
|
|
delete tmp;
|
|
}
|
|
|
|
/*
|
|
calculates the minimum coverage of a rtree-node
|
|
in its timeintervall
|
|
|
|
*/
|
|
template<class timeType>
|
|
int coverage(R_Tree<3, TupleId>* rtree, timeType &tEnd,
|
|
SmiRecordId nodeid, int level)
|
|
{
|
|
std::map<timeType, int> m;
|
|
helpcoverage<timeType>( 0, m, rtree, tEnd, nodeid, level );
|
|
helpcoverage<timeType>( 1, m, rtree, tEnd, nodeid, level );
|
|
typedef typename std::map<timeType , int>::const_iterator ITMAP;
|
|
int result = 0;
|
|
ITMAP it = m.begin();
|
|
if( it != m.end() ) result = it->second;
|
|
for( ; it != m.end(); ++it)
|
|
{
|
|
if( it->second < result ) result = it->second;
|
|
}
|
|
return result;
|
|
}
|
|
int newcoverage(R_Tree<3, TupleId>* rtree, Instant &tEnd,
|
|
SmiRecordId nodeid, int level,Relation* rel,BTree* btree)
|
|
{
|
|
int result = 0;
|
|
CcInt* id = new CcInt(true,nodeid);
|
|
BTreeIterator* btreeiter = btree->ExactMatch(id);
|
|
while(btreeiter->Next()){
|
|
Tuple* tuple = rel->GetTuple(btreeiter->GetId(), false);
|
|
UInt* ut = (UInt*)tuple->GetAttribute(2);//NodeId, RecId, Uint
|
|
if(ut->timeInterval.Contains(tEnd))
|
|
result += ut->constValue.GetValue();
|
|
}
|
|
delete id;
|
|
return result;
|
|
}
|
|
/*
|
|
checks if the coverage k is reached. If yes, the new node or tuple
|
|
must not be inserted into the segment tree. If no, this
|
|
funtion inserts the node or tuple into the segment tree
|
|
|
|
*/
|
|
template<class timeType>
|
|
bool checkInsert( NNSegTree<timeType> &timeTree, SegEntry<timeType> &s,
|
|
BBox<2> mbox, int k, R_Tree<3, TupleId>* rtree, int level )
|
|
{
|
|
double reachedCoverage = timeTree.calcCoverage( s.start, s.end, s.mindist );
|
|
if( reachedCoverage >= k)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if( s.coverage != 1)
|
|
{
|
|
//for tuples the coverage must not be calculated
|
|
s.coverage = coverage<timeType>(rtree, s.end, s.nodeid, level);
|
|
}
|
|
timeTree.insert( s, k );
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
Some elements are needed to save between the knearestfilter calls.
|
|
|
|
*/
|
|
template<class timeType>
|
|
struct KnearestFilterLocalInfo
|
|
{
|
|
unsigned int k;
|
|
//int max;
|
|
bool scanFlag;
|
|
timeType startTime, endTime;
|
|
std::vector<FieldEntry<timeType> > vectorA;
|
|
std::vector<FieldEntry<timeType> > vectorB;
|
|
NNSegTree<timeType> timeTree;
|
|
Relation* relation;
|
|
R_Tree<3, TupleId>* rtree;
|
|
Relation* hats; //new
|
|
BTree* btreehats;//new
|
|
|
|
std::map<SegEntry<timeType>, TupleId> resultMap;
|
|
typedef typename std::map<SegEntry<timeType>, TupleId>::const_iterator CIMAP;
|
|
CIMAP mapit;
|
|
KnearestFilterLocalInfo( const timeType &s, const timeType &e) :
|
|
startTime(s), endTime(e), timeTree( s, e )
|
|
{}
|
|
};
|
|
|
|
/*
|
|
oldknearestFilterFun is the value function for the oldknearestfilter operator
|
|
It is a filter operator for the knearest operator. It can be called
|
|
if there exists a rtree for the unit attribute
|
|
The argument vector contains the following values:
|
|
args[0] = a rtree with the unit attribute as key
|
|
args[1] = the relation of the rtree
|
|
args[2] = mpoint
|
|
args[3] = int k, how many nearest are searched
|
|
|
|
*/
|
|
template<class timeType>
|
|
int oldknearestFilterFun (Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
const int dim = 3;
|
|
KnearestFilterLocalInfo<timeType> *localInfo;
|
|
|
|
switch (message)
|
|
{
|
|
case OPEN :
|
|
{
|
|
const MPoint *mp = (MPoint*)args[2].addr;
|
|
UPoint up1, up2;
|
|
mp->Get( 0, up1);
|
|
mp->Get( mp->GetNoComponents() - 1, up2);
|
|
BBTree<timeType>* t = new BBTree<timeType>(*mp);
|
|
|
|
localInfo = new KnearestFilterLocalInfo<timeType>(
|
|
up1.timeInterval.start.ToDouble(), up2.timeInterval.end.ToDouble());
|
|
localInfo->rtree = (R_Tree<dim, TupleId>*)args[0].addr;
|
|
localInfo->relation = (Relation*)args[1].addr;
|
|
localInfo->k = (unsigned)((CcInt*)args[3].addr)->GetIntval();
|
|
localInfo->scanFlag = true;
|
|
local = SetWord(localInfo);
|
|
if (mp->IsEmpty())
|
|
{
|
|
return 0;
|
|
}
|
|
/* build the segment tree */
|
|
SmiRecordId adr = localInfo->rtree->RootRecordId();
|
|
R_TreeNode<dim, TupleId> *tmp = localInfo->rtree->GetMyNode(
|
|
adr,
|
|
false,
|
|
localInfo->rtree->MinEntries( 0 ),
|
|
localInfo->rtree->MaxEntries( 0 ) );
|
|
|
|
timeType t1(tmp->BoundingBox().MinD(2));
|
|
timeType t2(tmp->BoundingBox().MaxD(2));
|
|
|
|
if( !(t1 >= localInfo->endTime || t2 <= localInfo->startTime))
|
|
{
|
|
localInfo->vectorA.push_back( FieldEntry<timeType>(
|
|
localInfo->rtree->RootRecordId(), 0, t1, t2, 0));
|
|
const BBox<2> xyBox = makexyBox( tmp->BoundingBox() );
|
|
SegEntry<timeType> se(xyBox,t1, t2, 0.0, 0.0, 0,
|
|
localInfo->rtree->RootRecordId(), -1);
|
|
localInfo->timeTree.insert( se, localInfo->k );
|
|
}
|
|
delete tmp;
|
|
while( !localInfo->vectorA.empty() )
|
|
{
|
|
unsigned int vpos;
|
|
for( vpos = 0; vpos < localInfo->vectorA.size(); ++vpos)
|
|
{
|
|
FieldEntry<timeType> &f = localInfo->vectorA[ vpos ];
|
|
SmiRecordId adr = f.nodeid;
|
|
// check if this entry is not deleted
|
|
if( localInfo->timeTree.erase( f.start, f.end, f.nodeid,
|
|
f.maxdist) )
|
|
{
|
|
R_TreeNode<dim, TupleId> *tmp = localInfo->rtree->GetMyNode(
|
|
adr, false,
|
|
localInfo->rtree->MinEntries( f.level ),
|
|
localInfo->rtree->MaxEntries( f.level ) );
|
|
for ( int ii = 0; ii < tmp->EntryCount(); ++ii )
|
|
{
|
|
if ( tmp->IsLeaf() )
|
|
{
|
|
R_TreeLeafEntry<dim, TupleId> e =
|
|
(R_TreeLeafEntry<dim, TupleId>&)(*tmp)[ii];
|
|
timeType t1(e.box.MinD(2));
|
|
timeType t2(e.box.MaxD(2));
|
|
if( !(t1 >= localInfo->endTime || t2 <= localInfo->startTime))
|
|
{
|
|
const BBox<2> xyBox = makexyBox( e.box );
|
|
Interval<timeType> d(t1,t2,true,true);
|
|
const BBox<2> mBox(t->getBox(d));
|
|
SegEntry<timeType> se(xyBox,t1, t2,
|
|
xyBox.Distance( mBox),
|
|
maxDistance( xyBox, mBox), 1,
|
|
-1, e.info);
|
|
checkInsert<timeType>( localInfo->timeTree, se, mBox,
|
|
localInfo->k, localInfo->rtree, f.level+1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
R_TreeInternalEntry<dim> e =
|
|
(R_TreeInternalEntry<dim>&)(*tmp)[ii];
|
|
timeType t1(e.box.MinD(2));
|
|
timeType t2(e.box.MaxD(2));
|
|
if( !(t1 >= localInfo->endTime || t2 <= localInfo->startTime))
|
|
{
|
|
const BBox<2> xyBox = makexyBox( e.box );
|
|
Interval<timeType> d(t1,t2,true,true);
|
|
const BBox<2> mBox(t->getBox(d));
|
|
SegEntry<timeType> se(xyBox,t1, t2,
|
|
xyBox.Distance( mBox),
|
|
maxDistance( xyBox, mBox), 0,
|
|
e.pointer, -1);
|
|
if( checkInsert<timeType>( localInfo->timeTree, se,
|
|
mBox, localInfo->k, localInfo->rtree, f.level+1))
|
|
{
|
|
localInfo->vectorB.push_back( FieldEntry<timeType>(
|
|
e.pointer, se.maxdist, t1, t2, f.level + 1));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
delete tmp;
|
|
}
|
|
}
|
|
localInfo->vectorA.clear();
|
|
localInfo->vectorA.swap( localInfo->vectorB );
|
|
}
|
|
delete t;
|
|
localInfo->timeTree.fillMap( localInfo->resultMap );
|
|
localInfo->mapit = localInfo->resultMap.begin();
|
|
return 0;
|
|
}
|
|
|
|
case REQUEST :
|
|
{
|
|
localInfo = (KnearestFilterLocalInfo<timeType>*)local.addr;
|
|
if ( !localInfo->scanFlag )
|
|
{
|
|
return CANCEL;
|
|
}
|
|
|
|
if ( !localInfo->k)
|
|
{
|
|
return CANCEL;
|
|
}
|
|
|
|
/* give out alle elements of the resultmap */
|
|
if ( localInfo->mapit != localInfo->resultMap.end() )
|
|
{
|
|
TupleId tid = localInfo->mapit->second;
|
|
Tuple *tuple = localInfo->relation->GetTuple(tid, false);
|
|
result = SetWord(tuple);
|
|
++localInfo->mapit;
|
|
return YIELD;
|
|
}
|
|
else
|
|
{
|
|
return CANCEL;
|
|
}
|
|
}
|
|
|
|
case CLOSE :
|
|
{
|
|
localInfo = (KnearestFilterLocalInfo<timeType>*)local.addr;
|
|
delete localInfo;
|
|
local.addr=0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
2.3.4 Coverage
|
|
|
|
This function computes the coverage number for a three dimensional r-tree.
|
|
|
|
|
|
*/
|
|
ListExpr coverageTypeMapCommon(ListExpr args, ListExpr result){
|
|
std::string err = " rtree(tuple(...) rect3 BOOL) expected";
|
|
if(nl->ListLength(args) != 1){
|
|
ErrorReporter::ReportError(err + "1");
|
|
return nl->TypeError();
|
|
}
|
|
ListExpr arg = nl->First(args);
|
|
if(nl->ListLength(arg)!=4){
|
|
ErrorReporter::ReportError(err + "2");
|
|
return nl->TypeError();
|
|
}
|
|
ListExpr rtree = nl->First(arg);
|
|
ListExpr tuple = nl->Second(arg);
|
|
/* The third element contains the type description for the
|
|
attribute from which the r-tree was created. Because
|
|
here we are not interested on that type, we can ignore it.
|
|
*/
|
|
ListExpr dind = nl->Fourth(arg);
|
|
|
|
if(!nl->IsEqual(rtree,RTree3TID::BasicType())){
|
|
ErrorReporter::ReportError(err + "3");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
if(nl->AtomType(dind)!=BoolType){
|
|
ErrorReporter::ReportError(err + "5");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
if(nl->ListLength(tuple)!=2){
|
|
ErrorReporter::ReportError(err + "6");
|
|
return nl->TypeError();
|
|
}
|
|
if(!nl->IsEqual(nl->First(tuple),Tuple::BasicType())){
|
|
ErrorReporter::ReportError(err + "7");
|
|
return nl->TypeError();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
inline ListExpr coverageTypeMap(ListExpr args){
|
|
return coverageTypeMapCommon(args,
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom(Tuple::BasicType()),
|
|
nl->ThreeElemList(
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("NodeId"),
|
|
nl->SymbolAtom(CcInt::BasicType())
|
|
),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("RecId"),
|
|
nl->SymbolAtom(CcInt::BasicType())
|
|
),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("Coverage"),
|
|
nl->SymbolAtom(UInt::BasicType())
|
|
)))));
|
|
}
|
|
|
|
|
|
inline ListExpr coverage2TypeMap(ListExpr args){
|
|
return coverageTypeMapCommon(args,
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom(Tuple::BasicType()),
|
|
nl->ThreeElemList(
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("NodeId"),
|
|
nl->SymbolAtom(CcInt::BasicType())
|
|
),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("Level"),
|
|
nl->SymbolAtom(CcInt::BasicType())
|
|
),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("Coverage"),
|
|
nl->SymbolAtom(MInt::BasicType())
|
|
)))));
|
|
}
|
|
|
|
const std::string coverageSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )"
|
|
"( <text>rtree(tuple ((x1 t1)...(xn tn)) ti) ->"
|
|
" (stream (tuple ((Nodeid is)(Coverage uint))))</text--->"
|
|
"<text> coverage(_) </text--->"
|
|
"<text>Computes the coverage numbers for a given r-tree </text--->"
|
|
"<text>query coverage(tree) count </text--->"
|
|
") )";
|
|
|
|
const std::string coverage2Spec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )"
|
|
"( <text>rtree(tuple ((x1 t1)...(xn tn)) ti) ->"
|
|
" (stream (tuple ((Nodeid is)(Level int)(Coverage mint))))</text--->"
|
|
"<text> coverage(_) </text--->"
|
|
"<text>Computes the coverage numbers for a given r-tree </text--->"
|
|
"<text>query coverage(tree) count </text--->"
|
|
") )";
|
|
|
|
struct CoverageEntry{
|
|
|
|
CoverageEntry(R_TreeNode<3, TupleId>& node1,int nodeid1,
|
|
SmiRecordId recId1):
|
|
node(node1), position(0),nodeId(nodeid1),
|
|
recId(recId1){
|
|
lastResult = new MInt(1);
|
|
}
|
|
|
|
CoverageEntry(const CoverageEntry& src):node(src.node),
|
|
position(src.position), lastResult(src.lastResult),
|
|
nodeId(src.nodeId),recId(src.recId){}
|
|
|
|
CoverageEntry& operator=(const CoverageEntry& src){
|
|
node = src.node;
|
|
position = src.position;
|
|
lastResult = src.lastResult;
|
|
nodeId = src.nodeId;
|
|
recId = src.recId;
|
|
return *this;
|
|
}
|
|
|
|
void destroyResult(){
|
|
if(lastResult){
|
|
delete lastResult;
|
|
lastResult = 0;
|
|
}
|
|
}
|
|
|
|
R_TreeNode<3, TupleId> node;
|
|
int position;
|
|
MInt* lastResult;
|
|
int nodeId; // id of the corrosponding node
|
|
SmiRecordId recId;
|
|
};
|
|
/*
|
|
for computing the newcoverage number
|
|
|
|
*/
|
|
|
|
class CoverageLocalInfo{
|
|
public:
|
|
|
|
/*
|
|
~Constructor~
|
|
|
|
Creates a new CoverageLocalInfo object.
|
|
|
|
*/
|
|
CoverageLocalInfo(R_Tree<3, TupleId>* tree, ListExpr tt){
|
|
this->tree = tree;
|
|
currentResult = 0;
|
|
currentPos = 0;
|
|
height = tree->Height();
|
|
minInner = tree->MinEntries(0);
|
|
maxInner = tree->MaxEntries(0);
|
|
minLeaf = tree->MinEntries(tree->Height());
|
|
maxLeaf = tree->MaxEntries(tree->Height());
|
|
nodeidcounter = 0;
|
|
// get the Root of the tree
|
|
CoverageEntry entry(tree->Root(),nodeidcounter,tree->RootRecordId());
|
|
nodeidcounter++;
|
|
estack.push(entry);
|
|
tupleType = new TupleType(tt);
|
|
completeResult = 0;
|
|
this->level = 0;
|
|
}
|
|
|
|
|
|
/*
|
|
~Destructor~
|
|
|
|
Detroys this object.
|
|
|
|
*/
|
|
~CoverageLocalInfo(){
|
|
while(!estack.empty()){
|
|
CoverageEntry e = estack.top();
|
|
estack.pop();
|
|
if(e.lastResult){
|
|
delete e.lastResult;
|
|
}
|
|
}
|
|
if(currentResult){
|
|
currentResult->Destroy();
|
|
delete currentResult;
|
|
}
|
|
tupleType->DeleteIfAllowed();
|
|
tupleType = 0;
|
|
if(completeResult){
|
|
completeResult->Destroy();
|
|
delete completeResult;
|
|
completeResult = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
~Returns the next Tuple~
|
|
|
|
If the tree is exhausted, NULL is returned.
|
|
|
|
*/
|
|
|
|
Tuple* nextTuple(){
|
|
if(currentResult && currentPos>=currentResult->GetNoComponents()){
|
|
// result completly processed
|
|
currentResult->Destroy();
|
|
delete currentResult;
|
|
currentResult = 0;
|
|
computeNextResult();
|
|
}else if(!currentResult){
|
|
// no result computed yet
|
|
computeNextResult();
|
|
}
|
|
if(!currentResult){
|
|
// tree exhausted
|
|
return 0;
|
|
}
|
|
// get the next result
|
|
UInt res;
|
|
currentResult->Get(currentPos,res);
|
|
currentPos++;
|
|
Tuple* resTuple = new Tuple(tupleType);
|
|
CcInt* ni = new CcInt(true,currentNodeId);
|
|
resTuple->PutAttribute(0,ni);
|
|
CcInt* ri = new CcInt(true,currentRecId);
|
|
resTuple->PutAttribute(1,ri);
|
|
resTuple->PutAttribute(2,new UInt(res));
|
|
return resTuple;
|
|
}
|
|
|
|
Tuple* nextTuple2(){
|
|
computeNextResult();
|
|
if(!completeResult){
|
|
return 0;
|
|
} else {
|
|
|
|
// completeResult->SortbyUnitTime();//to be sure sort by time
|
|
Tuple* resTuple = new Tuple(tupleType);
|
|
CcInt* ni = new CcInt(true,currentNodeId);
|
|
CcInt* level = new CcInt(true, this->level);
|
|
resTuple->PutAttribute(0,ni);
|
|
resTuple->PutAttribute(1,level);
|
|
|
|
resTuple->PutAttribute(2,completeResult);
|
|
completeResult = 0;
|
|
return resTuple;
|
|
}
|
|
}
|
|
|
|
private:
|
|
R_Tree<3, TupleId>* tree; // the tree
|
|
std::stack<CoverageEntry> estack; // the recursion stack
|
|
MInt* currentResult; // the currently computed result
|
|
int currentPos; // position within the current result
|
|
int currentNodeId; // the current nodeId
|
|
int currentRecId; // the current record id of the node
|
|
TupleType* tupleType; // the tupleType
|
|
int maxInner; // maximum number of entries of inner nodes
|
|
int minInner; // minimum number of entries of inner nodes
|
|
int maxLeaf; // maximum number of entries of leaf nodes
|
|
int minLeaf; // minimum number of entries of leaf nodes
|
|
unsigned int height; // height of the tree
|
|
int nodeidcounter; // counter for the current node id
|
|
MInt* completeResult; // result without applying the hat function
|
|
int level;
|
|
|
|
/*
|
|
~rect2uint~
|
|
|
|
Supporting function creates a uint from a rect3.
|
|
|
|
*/
|
|
UInt rect2uint(const Rectangle<3> rect){
|
|
double min = rect.MinD(2);
|
|
double max = rect.MaxD(2);
|
|
datetime::DateTime dt1(datetime::instanttype);
|
|
datetime::DateTime dt2(datetime::instanttype);
|
|
dt1.ReadFrom(min);
|
|
dt2.ReadFrom(max);
|
|
Interval<datetime::DateTime> iv(dt1,dt2,true,true);
|
|
CcInt v(true,1);
|
|
UInt res(iv,v);
|
|
return res;
|
|
}
|
|
|
|
/*
|
|
~computeNextResult~
|
|
|
|
This function computes the next result.
|
|
|
|
*/
|
|
void computeNextResult(){
|
|
// for a new result, the position is 0
|
|
currentPos = 0;
|
|
// delete old currentResult if present
|
|
if(currentResult){
|
|
currentResult->Destroy();
|
|
delete currentResult;
|
|
currentResult=0;
|
|
}
|
|
if(completeResult){
|
|
completeResult->Destroy();
|
|
delete completeResult;
|
|
completeResult=0;
|
|
}
|
|
|
|
if(estack.empty()){ // tree exhausted
|
|
return;
|
|
}
|
|
|
|
// get the topmost stack element
|
|
CoverageEntry coverageEntry = estack.top();
|
|
this->level = estack.size()-1;
|
|
if(!coverageEntry.node.IsLeaf()){
|
|
// process an inner node
|
|
if(coverageEntry.position>= coverageEntry.node.EntryCount()){
|
|
// node finished
|
|
currentResult = new MInt(1);
|
|
// if a node is finished, the final result is lastResult of that node
|
|
MInt* lastResult = coverageEntry.lastResult;
|
|
// compute the Hat for lastResult
|
|
assert(!completeResult);
|
|
completeResult = new MInt(1);
|
|
lastResult->fillUp(0,*completeResult);
|
|
completeResult->Hat(*currentResult);
|
|
currentPos = 0;
|
|
currentNodeId = coverageEntry.nodeId;
|
|
currentRecId = coverageEntry.recId;
|
|
estack.pop(); // remove the finished node from the stack
|
|
if(estack.empty()){ // root node
|
|
coverageEntry.destroyResult();
|
|
return;
|
|
}
|
|
// stack not empty -> update top element of the stack
|
|
coverageEntry = estack.top();
|
|
MInt tmp(1);
|
|
coverageEntry.lastResult->PlusExtend(lastResult,tmp);
|
|
coverageEntry.lastResult->CopyFrom(&tmp);
|
|
lastResult->Destroy();
|
|
delete lastResult;
|
|
lastResult = 0;
|
|
coverageEntry.position++; // this position has been computed
|
|
// bring changes to the stack
|
|
estack.pop();
|
|
estack.push(coverageEntry);
|
|
return; // computing the result finished
|
|
} else {
|
|
// not finished inner node
|
|
// -> go to a leaf storing the path in the stack
|
|
estack.pop(); // required to bring it again to the stack
|
|
while(!coverageEntry.node.IsLeaf()){
|
|
// push to stack
|
|
estack.push(coverageEntry);
|
|
R_TreeInternalEntry<3> next =
|
|
*(static_cast<R_TreeInternalEntry<3>*>(
|
|
&coverageEntry.node[coverageEntry.position]));
|
|
SmiRecordId rid = next.pointer;
|
|
int min;
|
|
int max;
|
|
if(estack.size() == height){
|
|
min = minLeaf;
|
|
max = maxLeaf;
|
|
} else {
|
|
min = minInner;
|
|
max = maxInner;
|
|
}
|
|
R_TreeNode<3, TupleId> nextNode(true,min,max);
|
|
tree->GetNode(rid, nextNode);
|
|
CoverageEntry nextEntry(nextNode,nodeidcounter,rid);
|
|
nodeidcounter++;
|
|
coverageEntry = nextEntry;
|
|
// start debug
|
|
}
|
|
// now entry is a leaf node
|
|
estack.push(coverageEntry);
|
|
}
|
|
this->level = estack.size()-1;
|
|
}
|
|
// the node to process is a leaf
|
|
// build a single MInt from the whole node
|
|
MInt res(1);
|
|
MInt v(1);
|
|
MInt tmp(1);
|
|
for(int i=0;i<coverageEntry.node.EntryCount();i++){
|
|
R_TreeLeafEntry<3, TupleId>* le = coverageEntry.node.GetLeafEntry(i);
|
|
UInt nextUnit(rect2uint(le->box));
|
|
v.Clear();
|
|
v.SetDefined(true);
|
|
v.Add(nextUnit);
|
|
res.PlusExtend(&v,tmp);
|
|
res.CopyFrom(&tmp);
|
|
}
|
|
nodeidcounter += coverageEntry.node.EntryCount();
|
|
currentResult = new MInt(1);
|
|
assert(!completeResult);
|
|
completeResult = new MInt(1);
|
|
res.fillUp(0,*completeResult);
|
|
completeResult->Hat(*currentResult);
|
|
currentPos = 0;
|
|
currentNodeId = coverageEntry.nodeId;
|
|
currentRecId = coverageEntry.recId;
|
|
// delete the result pointer from the leaf node
|
|
coverageEntry.destroyResult();
|
|
estack.pop();
|
|
if(estack.empty()){
|
|
return;
|
|
}
|
|
coverageEntry = estack.top();
|
|
tmp.Clear();
|
|
coverageEntry.lastResult->PlusExtend(&res, tmp);
|
|
coverageEntry.lastResult->CopyFrom(&tmp);
|
|
coverageEntry.position++;
|
|
estack.pop();
|
|
estack.push(coverageEntry);
|
|
}
|
|
};
|
|
|
|
int coverageFun (Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
switch (message){
|
|
case OPEN : {
|
|
ListExpr resultType =
|
|
SecondoSystem::GetCatalog()->NumericType(qp->GetType(s));
|
|
if(local.addr){
|
|
delete static_cast<CoverageLocalInfo*>(local.addr);
|
|
}
|
|
R_Tree<3, TupleId>* tree =
|
|
static_cast<R_Tree<3, TupleId>*>(args[0].addr);
|
|
local.addr = new CoverageLocalInfo(tree,
|
|
nl->Second(resultType));
|
|
return 0;
|
|
}
|
|
case REQUEST:{
|
|
CoverageLocalInfo* li =
|
|
static_cast<CoverageLocalInfo*>(local.addr);
|
|
Tuple* nextTuple = li->nextTuple();
|
|
result.addr = nextTuple;
|
|
return nextTuple?YIELD:CANCEL;
|
|
}
|
|
case CLOSE:{
|
|
CoverageLocalInfo* li =
|
|
static_cast<CoverageLocalInfo*>(local.addr);
|
|
if(li){
|
|
delete li;
|
|
local.setAddr(0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
default: assert(false); // unknown message
|
|
}
|
|
}
|
|
|
|
|
|
int coverage2Fun (Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
switch (message){
|
|
case OPEN : {
|
|
ListExpr resultType =
|
|
SecondoSystem::GetCatalog()->NumericType(qp->GetType(s));
|
|
if(local.addr){
|
|
delete static_cast<CoverageLocalInfo*>(local.addr);
|
|
}
|
|
R_Tree<3, TupleId>* tree =
|
|
static_cast<R_Tree<3, TupleId>*>(args[0].addr);
|
|
local.addr = new CoverageLocalInfo(tree,
|
|
nl->Second(resultType));
|
|
return 0;
|
|
}
|
|
case REQUEST:{
|
|
CoverageLocalInfo* li =
|
|
static_cast<CoverageLocalInfo*>(local.addr);
|
|
Tuple* nextTuple = li->nextTuple2();
|
|
result.addr = nextTuple;
|
|
return nextTuple?YIELD:CANCEL;
|
|
}
|
|
case CLOSE:{
|
|
CoverageLocalInfo* li =
|
|
static_cast<CoverageLocalInfo*>(local.addr);
|
|
if(li){
|
|
delete li;
|
|
local.setAddr(0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
default: assert(false); // unknown message
|
|
}
|
|
}
|
|
|
|
int isknnFun (Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
bool debugme= false;
|
|
|
|
std::string rel= ((CcString*)args[1].addr)->GetValue();
|
|
std::string btree= ((CcString*)args[2].addr)->GetValue();
|
|
std::string mboolAttr= ((CcString*)args[3].addr)->GetValue();
|
|
std::string idAttr= ((CcString*)args[4].addr)->GetValue();
|
|
std::string idType= ((CcString*)args[5].addr)->GetValue();
|
|
std::string id="";
|
|
//qp->Request(args[0].addr, idWord); //Strangely causes the program to crash
|
|
Word idWord;
|
|
Supplier arg0= qp->GetSupplierSon(s, 0);
|
|
qp->Request(arg0, idWord);
|
|
if(idType == CcString::BasicType())
|
|
id= ((CcString*) idWord.addr)->GetValue() ;
|
|
else if(idType == CcInt::BasicType())
|
|
id= int2string( ((CcInt*) idWord.addr)->GetValue());
|
|
|
|
if(debugme)
|
|
{
|
|
cout<<endl<<id<<endl<<rel<<endl<<btree<<
|
|
endl<<mboolAttr<<endl<<idAttr<<endl<<idType;
|
|
cout.flush();
|
|
}
|
|
|
|
std::string queryListStr=
|
|
" (ifthenelse"
|
|
" (="
|
|
" (count"
|
|
" (exactmatch " + btree + " " + rel + " " + id + "))"
|
|
" 0)"
|
|
" (mbool"
|
|
" ("
|
|
" ("
|
|
" (\"begin of time\" \"end of time\" FALSE FALSE)"
|
|
" FALSE)))"
|
|
" (extract"
|
|
" (exactmatch " + btree + " " + rel + " " + id + ")" +
|
|
mboolAttr + "))";
|
|
if(debugme)
|
|
{
|
|
cout<<endl<<queryListStr;
|
|
cout.flush();
|
|
}
|
|
|
|
Word queryResult;
|
|
QueryProcessor::ExecuteQuery( queryListStr, queryResult);
|
|
|
|
result = qp->ResultStorage( s );
|
|
((MBool*)result.addr)->CopyFrom((MBool*)queryResult.addr);
|
|
((MBool*)queryResult.addr)->DeleteIfAllowed();
|
|
return 0;
|
|
}
|
|
|
|
Operator coverageop (
|
|
"coverage", // name
|
|
coverageSpec, // specification
|
|
coverageFun, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
coverageTypeMap // type mapping
|
|
);
|
|
|
|
Operator coverage2op (
|
|
"coverage2", // name
|
|
coverage2Spec, // specification
|
|
coverage2Fun, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
coverage2TypeMap // type mapping
|
|
);
|
|
|
|
/*
|
|
2.4 Definition of value mapping vectors
|
|
|
|
*/
|
|
|
|
ValueMapping distanceScanMap [] = { distanceScanFun<2>,
|
|
distanceScanFun<3>,
|
|
distanceScanFun<4>,
|
|
distanceScanFun<8>};
|
|
|
|
ValueMapping distanceScan2Map [] = {distanceScan2Fun<2>,
|
|
distanceScan2Fun<3>,
|
|
distanceScan2Fun<4>,
|
|
distanceScan2Fun<8>};
|
|
|
|
|
|
ValueMapping distanceScan2SMap [] = {distanceScan2SFun<2>,
|
|
distanceScan2SFun<3>,
|
|
distanceScan2SFun<4>,
|
|
distanceScan2SFun<8>};
|
|
template<class T1, class T2>
|
|
class DistFun{
|
|
public:
|
|
inline double operator()(const T2& o1, const T1& o2) const{
|
|
return o2.Distance(o1);
|
|
}
|
|
};
|
|
|
|
template<class T1, class T2>
|
|
class DistFunSymm{
|
|
public:
|
|
inline double operator()(const T2& o1, const T1& o2) const{
|
|
return o1.Distance(o2);
|
|
}
|
|
};
|
|
|
|
ValueMapping distanceScan3Map [] = {
|
|
distanceScan3Fun<2, Point, Point, DistFun<Point,Point> >,
|
|
distanceScan3Fun<2, Point, Points, DistFunSymm<Point,Points> >,
|
|
distanceScan3Fun<2, Point, Line, DistFunSymm<Point,Line> >,
|
|
distanceScan3Fun<2, Point, Region, DistFunSymm<Point,Region> >,
|
|
distanceScan3Fun<2, Point, Rectangle<2>, DistFun<Point,Rectangle<2> > >,
|
|
|
|
distanceScan3Fun<2, Points, Point, DistFun<Points,Point> >,
|
|
distanceScan3Fun<2, Points, Points, DistFun<Points,Points> >,
|
|
distanceScan3Fun<2, Points, Line, DistFunSymm<Points,Line> >,
|
|
distanceScan3Fun<2, Points, Region, DistFunSymm<Points,Region> >,
|
|
distanceScan3Fun<2, Points, Rectangle<2>, DistFun<Points,Rectangle<2> > >,
|
|
|
|
distanceScan3Fun<2, Line, Point, DistFun<Line,Point> >,
|
|
distanceScan3Fun<2, Line, Points, DistFun<Line,Points> >,
|
|
distanceScan3Fun<2, Line, Line, DistFun<Line,Line> >,
|
|
distanceScan3Fun<2, Line, Region, DistFunSymm<Line,Region> >,
|
|
distanceScan3Fun<2, Line, Rectangle<2>, DistFun<Line,Rectangle<2> > >,
|
|
|
|
distanceScan3Fun<2, Region, Point, DistFun<Region,Point> >,
|
|
distanceScan3Fun<2, Region, Points, DistFun<Region,Points> >,
|
|
distanceScan3Fun<2, Region, Line, DistFun<Region,Line> >,
|
|
distanceScan3Fun<2, Region, Region, DistFun<Region,Region> >,
|
|
distanceScan3Fun<2, Region, Rectangle<2>, DistFun<Region,Rectangle<2> > >,
|
|
|
|
distanceScan3Fun<2, Rectangle<2>,Point,DistFunSymm<Rectangle<2> ,Point> >,
|
|
distanceScan3Fun<2, Rectangle<2>,Points,DistFunSymm<Rectangle<2> ,Points > >,
|
|
distanceScan3Fun<2, Rectangle<2>,Line,DistFunSymm<Rectangle<2> ,Line > >,
|
|
distanceScan3Fun<2, Rectangle<2>,Region,DistFunSymm<Rectangle<2>,Region > >,
|
|
distanceScan3Fun<2, Rectangle<2>,Rectangle<2>,
|
|
DistFun<Rectangle<2>,Rectangle<2> > >
|
|
|
|
};
|
|
|
|
ValueMapping newknearest_distMap [] = {
|
|
newknearest_distFun1,
|
|
newknearest_distFun2
|
|
};
|
|
|
|
int rect2periodsFun (Word* args, Word& result, int message,
|
|
Word& local, Supplier s) {
|
|
|
|
Rectangle<3>* arg = static_cast<Rectangle<3>*>(args[0].addr);
|
|
result = qp->ResultStorage(s);
|
|
Periods* res = static_cast<Periods*>(result.addr);
|
|
if(!arg->IsDefined()){
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
double min = arg->MinD(2);
|
|
double max = arg->MaxD(2);
|
|
datetime::DateTime dt1(datetime::instanttype);
|
|
datetime::DateTime dt2(datetime::instanttype);
|
|
dt1.ReadFrom(min);
|
|
dt2.ReadFrom(max);
|
|
Interval<datetime::DateTime> iv(dt1,dt2,true,true);
|
|
res->Clear();
|
|
res->Add(iv);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
2.5 Specification of operators
|
|
|
|
*/
|
|
|
|
const std::string distanceScanSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )"
|
|
"( <text>rtree(tuple ((x1 t1)...(xn tn))"
|
|
" ti) x rel(tuple ((x1 t1)...(xn tn))) x T x k ->"
|
|
" (stream (tuple ((x1 t1)...(xn tn))))\n"
|
|
"For T = ti and ti in SPATIAL<d>D, for"
|
|
" d in {2, 3, 4, 8}</text--->"
|
|
"<text>_ _ distancescan [ _, _ ]</text--->"
|
|
"<text> Computes the k nearest neighbors for a query object. "
|
|
" The query object as well as the objects stored in the r-tree "
|
|
" must be equal to their bounding boxes (i.e. point or retangle types)"
|
|
" to produce correct results. The result comes ordered by the distance"
|
|
" to the query object. If k <=0 all stored objects ordered by their"
|
|
" distance to the query object is returned. </text--->"
|
|
"<text>query kinos_geoData Kinos distancescan "
|
|
"[[const point value (10539.0 14412.0)], 5] consume; </text--->"
|
|
") )";
|
|
|
|
const std::string distanceScan2Spec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )"
|
|
"( <text>rtree(tuple ((x1 t1)...(xn tn))"
|
|
" ti) x rel(tuple ((x1 t1)...(xn tn))) x T x k ->"
|
|
" (stream (tuple ((x1 t1)...(xn tn))))\n"
|
|
"For T = ti and ti in SPATIAL<d>D, for"
|
|
" d in {2, 3, 4, 8}</text--->"
|
|
"<text>_ _ distancescan2 [ _, _ ]</text--->"
|
|
"<text> This operator works very similar to the distancescan "
|
|
" operator but it allows an arbitrary spatial type for the "
|
|
" query object. The objects indexed by the r-tree must be equal"
|
|
" to their bounding boxes (point or rectangle). </text--->"
|
|
"<text>query kinos_geoData Kinos distancescan2 "
|
|
"[zoogarten, 5] tconsume; </text--->"
|
|
") )";
|
|
|
|
const std::string distanceScan2SSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )"
|
|
"( <text>rtree(tuple ((x1 t1)...(xn tn))"
|
|
" ti) x T x k ->"
|
|
" (stream (tupleId))"
|
|
"For T = ti and ti in SPATIAL<d>D, for"
|
|
" d in {2, 3, 4, 8}</text--->"
|
|
"<text>_ distancescan2S [ _, _ ]</text--->"
|
|
"<text> This operator is a variant od the distancescan2 "
|
|
" operator. The differencs is that the relation is not required as"
|
|
" an argument and the result is a stream of tupleIds instead of tuples."
|
|
"<text>query kinos_geoData distancescan2S "
|
|
"[zoogarten, 5] transformstream tconsume; </text--->"
|
|
") )";
|
|
|
|
|
|
const std::string distanceScan3Spec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )"
|
|
"( <text>rtree(tuple ((x1 t1)...(xn tn))"
|
|
" ti) x rel(tuple ((x1 t1)...(xn tn))) x T x k [x attrname] [x real] ->"
|
|
" (stream (tuple ((x1 t1)...(xn tn))))\n"
|
|
"For T = ti and ti in {point, points, region, rect, rect},"
|
|
" </text--->"
|
|
"<text>_ _ distancescan [ _, _, _ ]</text--->"
|
|
"<text>This operator returns the k nearest neighbours to a"
|
|
" query object ordered by their distance to that object. "
|
|
" Both, the query object and the objects indexed by the r-tree"
|
|
" can be of an arbitrary supported spatial type."
|
|
" If the tuples of the rtree (and the relation) contain more "
|
|
" than one spatial attribute, the indexed attribute must be given"
|
|
" by its name as an argument. If it is unique, that parameter "
|
|
" can be omited. Because the distance calculation requires access to"
|
|
" the tuples, this operator is slower than the distancescan2 operator."
|
|
" For this reason, this operator should only ne used if the indexed "
|
|
" spatial objects are not of type point or rectangle."
|
|
" If the last argument is a real value, the output stream is finished,"
|
|
" if the current distance overcomes the given value. "
|
|
"</text--->"
|
|
"<text> query Flaechen creatertree[geoData] Flaechen "
|
|
"distancescan3[BGrenzenLine, 5] tconsume"
|
|
"</text--->"
|
|
") )";
|
|
|
|
const std::string distanceScan4Spec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )"
|
|
"( <text>rtree3 x rel(T) x point x instant x int [ x attrname] "
|
|
" -> stream(T) </text--->"
|
|
"<text>_ _ distancescan4 [ _, _, _ ]</text--->"
|
|
"<text> Computes the k nearest neighbours of a point from "
|
|
" a set of moving point units (stored in rel and indexed by the rtree)"
|
|
" for a given point in time. If the relation contains more than 1 "
|
|
" attributes of type upoint, the attribute name of the indexed "
|
|
" attribute must be a parameter of that operator </text--->"
|
|
"<text>query UnitTrains_rtree UnitTrains distancescan4 "
|
|
" [[const point value (10539.0 14412.0)], now(), 5] tconsume;"
|
|
"</text--->))";
|
|
|
|
const std::string knearestvectorSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )"
|
|
"( <text>stream(tuple ((x1 t1)...(xn tn))"
|
|
" ti) x xi x mpoint x k ->"
|
|
" (stream (tuple ((x1 t1)...(xn tn))))"
|
|
"</text--->"
|
|
"<text>_ knearestvector [_, _, _ ]</text--->"
|
|
"<text>The operator results a stream of all input tuples "
|
|
"which contains the k-nearest units to the given mpoint. "
|
|
"The tuples are splitted into multiple tuples with disjoint "
|
|
"units if necessary. The tuples in the result stream are "
|
|
"not necessarily ordered by time or distance to the given "
|
|
"mpoint. The operator expects that the input stream with "
|
|
"the tuples are sorted by the time of the units</text--->"
|
|
"<text>query query UnitTrains feed head[20] knearestvector "
|
|
"[UTrip,train1, 2] consume;</text--->"
|
|
") )";
|
|
|
|
const std::string knearestSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )"
|
|
"( <text>stream(tuple ((x1 t1)...(xn tn))"
|
|
" ti) x xi x mpoint x int [x int] ->"
|
|
" (stream (tuple ((x1 t1)...(xn tn))))"
|
|
"</text--->"
|
|
"<text>_ knearest [_, _, _ [, _] ]</text--->"
|
|
"<text>The purpose of the operator is to compute the time dependent"
|
|
" k nearest neighbors to a given moving point mp within a set of "
|
|
"moving objects S. Set S is provided as the first argument in the form"
|
|
" of a stream of units, i.e., a stream of tuples having a upoint "
|
|
"atribute. This stream of tuples MUST be ordered by unit start time. "
|
|
"Given a call s knearest[attr, mp, k], the result is a stream of tuples"
|
|
" in the same format as the input stream containing for each instant the"
|
|
" k closest units to mp. Note that the original units may have been "
|
|
"split into pieces. The tuples in the result stream are not "
|
|
"necessarily ordered by time or distance to the given mpoint.\n\n"
|
|
"The operator may not work correctly for geographical coordinates due"
|
|
" to numerical problems with small distance differences, if called as"
|
|
" described above. For moving objects with geographical (LON, LAT)"
|
|
" coordinates, use the second form with an additional int parameter j,"
|
|
" that is, s knearest[attr, mp, k, j]. The parameter, if present, "
|
|
"specifies that Gauss Krueger projection is to be used before computing"
|
|
" distances. The value of j, if in the range 0 <= j < 120 specifies a "
|
|
"meridian to be used in the Gauss Krueger projection (see the "
|
|
"explanation of the gk operator). If j is -1, then the location of the "
|
|
"first unit in the input stream is used to determine the Gauss Krueger "
|
|
"zone number. Other values of j lead to error messages. Also if a wrong"
|
|
" zone is specified (input data do not lie in the given zone), an error"
|
|
" message is generated. </text--->"
|
|
"<text>query query UnitTrains feed head[20] knearest "
|
|
"[UTrip,train1, 2] count;</text--->"
|
|
") )";
|
|
|
|
const std::string knearestdistSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )"
|
|
"( <text>stream(tuple ((x1 t1)...(xn tn))"
|
|
" ti) x xi x mpoint x k -> mreal </text--->"
|
|
"<text>_ knearest_dist [_, _, _ ]</text--->"
|
|
"<text>The operator results the distance of kth neighbor. </text--->"
|
|
"<text>query query UnitTrains feed head[20] knearest_dist "
|
|
"[UTrip,train1, 2];</text--->"
|
|
") )";
|
|
|
|
const std::string oldknearestFilterSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )"
|
|
"( <text>rtree(tuple ((x1 t1)...(xn tn))"
|
|
" ti) x rel(tuple ((x1 t1)...(xn tn))) x mpoint x k ->"
|
|
" (stream (tuple ((x1 t1)...(xn tn))))"
|
|
"</text--->"
|
|
"<text>_ _ oldknearestfilter [ _, _ ]</text--->"
|
|
"<text>The operator results a stream of all input tuples "
|
|
"which are the k-nearest tupels to the given mpoint. "
|
|
"The operator do not separate tupels if necessary. The "
|
|
"result may have more than the k-nearest tupels. It is a "
|
|
"filter operator for the knearest operator, if there are a great "
|
|
"many input tupels. "
|
|
"The operator expects a thee dimensional rtree where the "
|
|
"third dimension is the time</text--->"
|
|
"<text>query UTOrdered_RTree UTOrdered oldknearestfilter "
|
|
"[train1, 5] count;</text--->"
|
|
") )";
|
|
|
|
|
|
const std::string rect2periodsSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )"
|
|
"( <text>rect3 -> periods </text--->"
|
|
" <text> rect2periods(_)</text--->"
|
|
" <text> Creates a single-interval periods value from "
|
|
" the third dimension of a rectangle </text--->"
|
|
" <text>query rect2periods(rect1) </text--->"
|
|
") )";
|
|
|
|
const std::string isknnSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )"
|
|
"( <text>v in {int | string} x string(rel) x string(btree) x "
|
|
"string(MBool) x string(ID) -> APPEND v mbool"
|
|
" <text> isknn(_, _, _,_,_)</text--->"
|
|
" <text> This operator is implemented only in SQL. Unless you are"
|
|
" sure of what you are doing, do not use it. </text--->"
|
|
" <text>isknn(.Tripid,\"trainsnnTriptrain75NN\" , "
|
|
"\"trainsnnTriptrain75NN_Tripid_btree\" , \"MBoolRes\" "
|
|
", \"Tripid\")] </text--->"
|
|
") )";
|
|
|
|
/*
|
|
2.6 Definition of operators
|
|
|
|
*/
|
|
Operator distancescan (
|
|
"distancescan", // name
|
|
distanceScanSpec, // specification
|
|
4, //number of overloaded functions
|
|
distanceScanMap, // value mapping
|
|
distanceScanSelect,
|
|
distanceScanTypeMap // type mapping
|
|
);
|
|
|
|
Operator distancescan2 (
|
|
"distancescan2", // name
|
|
distanceScan2Spec, // specification
|
|
4, //number of overloaded functions
|
|
distanceScan2Map, // value mapping
|
|
distanceScanSelect,
|
|
distanceScanTypeMap // type mapping
|
|
);
|
|
|
|
Operator distancescan2S (
|
|
"distancescan2S", // name
|
|
distanceScan2SSpec, // specification
|
|
4, //number of overloaded functions
|
|
distanceScan2SMap, // value mapping
|
|
distanceScanSelect,
|
|
distanceScan2STypeMap // type mapping
|
|
);
|
|
|
|
Operator distancescan3 (
|
|
"distancescan3", // name
|
|
distanceScan3Spec, // specification
|
|
25, //number of overloaded functions
|
|
distanceScan3Map, // value mapping
|
|
distanceScan3Select,
|
|
distanceScan3TypeMap // type mapping
|
|
);
|
|
|
|
Operator distancescan4 (
|
|
"distancescan4", // name
|
|
distanceScan4Spec, // specification
|
|
distanceScan4Fun, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
distanceScan4TypeMap // type mapping
|
|
);
|
|
|
|
|
|
Operator knearest (
|
|
"knearest", // name
|
|
knearestSpec, // specification
|
|
knearestFun, // value mapping
|
|
Operator::SimpleSelect,
|
|
KnearestTypeMap<true> // type mapping
|
|
);
|
|
|
|
Operator knearest_dist (
|
|
"knearest_dist", // name
|
|
knearestdistSpec, // specification
|
|
2,
|
|
newknearest_distMap, // value mapping
|
|
knearestdistSelect,
|
|
knearestdistTypeMap // type mapping
|
|
);
|
|
|
|
Operator knearestvector (
|
|
"knearestvector", // name
|
|
knearestvectorSpec, // specification
|
|
knearestFunVector, // value mapping
|
|
Operator::SimpleSelect,// trivial selection function
|
|
KnearestTypeMap<false> // type mapping
|
|
);
|
|
|
|
Operator oldknearestfilter (
|
|
"oldknearestfilter", // name
|
|
oldknearestFilterSpec, // specification
|
|
oldknearestFilterFun<double>, // value mapping
|
|
//knearestFilterFun<Instant>, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
oldknearestFilterTypeMap // type mapping
|
|
);
|
|
|
|
|
|
Operator rect2periods (
|
|
"rect2periods", // name
|
|
rect2periodsSpec, // specification
|
|
rect2periodsFun, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
rect2periodsTypeMap // type mapping
|
|
);
|
|
|
|
Operator isknn (
|
|
"isknn", // name
|
|
isknnSpec, // specification
|
|
isknnFun, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
isknnTypeMap // type mapping
|
|
);
|
|
|
|
/*
|
|
6 Operator ~bboxes~
|
|
|
|
The operator bbox is for test proposes only. It receives a stream of
|
|
Periods values and a moving point. It produces a stream of rectangles
|
|
which are the bounding boxes of the moving point for each box of the
|
|
periods value.
|
|
|
|
*/
|
|
ListExpr bboxesTM(ListExpr args){
|
|
std::string err = "stream(periods) x mpoint expected";
|
|
if(nl->ListLength(args) != 2){
|
|
ErrorReporter::ReportError(err);
|
|
return nl->TypeError();
|
|
}
|
|
ListExpr stream = nl->First(args);
|
|
ListExpr mp = nl->Second(args);
|
|
if(!nl->IsEqual(mp,MPoint::BasicType())){
|
|
ErrorReporter::ReportError(err);
|
|
return nl->TypeError();
|
|
}
|
|
if(nl->ListLength(stream)!=2){
|
|
ErrorReporter::ReportError(err);
|
|
return nl->TypeError();
|
|
}
|
|
if(!nl->IsEqual(nl->First(stream),Symbol::STREAM()) ||
|
|
!nl->IsEqual(nl->Second(stream),Periods::BasicType())){
|
|
ErrorReporter::ReportError(err);
|
|
return nl->TypeError();
|
|
}
|
|
return nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->SymbolAtom(Rectangle<2>::BasicType()));
|
|
|
|
}
|
|
|
|
int bboxesFun(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
switch(message){
|
|
case OPEN: {
|
|
qp->Open(args[0].addr);
|
|
MPoint* mp = static_cast<MPoint*>(args[1].addr);
|
|
if(local.addr){
|
|
delete static_cast<BBTree<Instant>*>(local.addr);
|
|
local.addr = 0;
|
|
}
|
|
if(mp->IsDefined()){
|
|
BBTree<Instant>* t = new BBTree<Instant>(*mp);
|
|
local.addr = t;
|
|
//cout << "mp.size = " << mp->GetNoComponents() << endl;
|
|
//cout << "no_Leafs = " << t->noLeaves() << endl;
|
|
//cout << "noNodes = " << t->noNodes() << endl;
|
|
//cout << "height = " << t->height() << endl;
|
|
//cout << "tree " << endl << *t << endl << endl;
|
|
}
|
|
return 0;
|
|
}
|
|
case REQUEST: {
|
|
if(!local.addr){
|
|
return CANCEL;
|
|
}
|
|
|
|
Word elem;
|
|
qp->Request(args[0].addr,elem);
|
|
if(!qp->Received(args[0].addr)){
|
|
return CANCEL;
|
|
}
|
|
Range<Instant>* periods = static_cast<Range<Instant>* >(elem.addr);
|
|
if(!periods->IsDefined()){
|
|
result.addr = new Rectangle<2>(false);
|
|
periods->DeleteIfAllowed();
|
|
return YIELD;
|
|
}
|
|
Instant minInst;
|
|
periods->Minimum(minInst);
|
|
Instant maxInst;
|
|
periods->Maximum(maxInst);
|
|
Interval<Instant> d(minInst,maxInst,true,true);
|
|
BBTree<Instant>* t = static_cast<BBTree<Instant>*>(local.addr);
|
|
result.addr = new Rectangle<2>(t->getBox(d));
|
|
periods->DeleteIfAllowed();
|
|
return YIELD;
|
|
}
|
|
case CLOSE : {
|
|
qp->Close(args[0].addr);
|
|
if(local.addr){
|
|
delete static_cast<BBTree<Instant>*>(local.addr);
|
|
local.addr = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
const std::string bboxesSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )"
|
|
"( <text>stream(periods) x mpoint -> stream(rect)</text--->"
|
|
"<text>_ bboxes [ _ ]</text--->"
|
|
"<text>"
|
|
"The Operator builds for each periods value its enclosing interval."
|
|
"It returns for that interval the spatial bounding boc if the "
|
|
"moving point would be restricted to that interval."
|
|
"</text--->"
|
|
|
|
"<text>query query UnitTrains feed projectextend[; D : deftime[.UTrip]"
|
|
" transformstream bboxes[Train6] transformstream consume"
|
|
"</text--->"
|
|
") )";
|
|
|
|
|
|
Operator bboxes (
|
|
"bboxes", // name
|
|
bboxesSpec, // specification
|
|
bboxesFun, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
bboxesTM // type mapping
|
|
);
|
|
|
|
|
|
|
|
/*
|
|
|
|
knearestFilterFun is the value function for the knearestfilter operator
|
|
It is a filter operator for the knearest operator. It can be called
|
|
if there exists a rtree for the unit attribute and a btree for the units number
|
|
relation built on rtree node
|
|
The argument vector contains the following values:
|
|
args[0] = a rtree with the unit attribute as key
|
|
args[1] = the relation of the rtree
|
|
args[2] = a btree with nodeid as key
|
|
args[3] = the relation of the btree
|
|
args[4] = mpoint
|
|
args[5] = int k, how many nearest are searched
|
|
|
|
*/
|
|
template<class timeType>
|
|
bool CmpFiledEntry(const FieldEntry<timeType>& fe1,
|
|
const FieldEntry<timeType>& fe2)
|
|
{
|
|
const timeType& fe1e = fe1.end;
|
|
const timeType& fe2e = fe2.end;
|
|
|
|
if(fe1.start != fe2.start)
|
|
return fe1.start < fe2.start;
|
|
if(fe1e != fe2.start)
|
|
return fe1e < fe2e;
|
|
return fe1.nodeid < fe2.nodeid;
|
|
|
|
}
|
|
template<class timeType>
|
|
int knearestFilterFun (Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
const int dim = 3;
|
|
KnearestFilterLocalInfo<timeType> *localInfo;
|
|
|
|
switch (message)
|
|
{
|
|
case OPEN :
|
|
{
|
|
const MPoint *mp = (MPoint*)args[5].addr;//5 th parameter
|
|
UPoint up1, up2;
|
|
mp->Get( 0, up1);
|
|
mp->Get( mp->GetNoComponents() - 1, up2);
|
|
BBTree<timeType>* t = new BBTree<timeType>(*mp);
|
|
localInfo = new KnearestFilterLocalInfo<timeType>(
|
|
up1.timeInterval.start.ToDouble(), up2.timeInterval.end.ToDouble());
|
|
localInfo->rtree = (R_Tree<dim, TupleId>*)args[0].addr;
|
|
localInfo->relation = (Relation*)args[1].addr;
|
|
localInfo->btreehats = (BTree*)args[2].addr;
|
|
localInfo->hats = (Relation*)args[3].addr;
|
|
localInfo->k = (unsigned)((CcInt*)args[6].addr)->GetIntval();//the last
|
|
localInfo->scanFlag = true;
|
|
local = SetWord(localInfo);
|
|
if (mp->IsEmpty())
|
|
{
|
|
return 0;
|
|
}
|
|
/* build the segment tree */
|
|
SmiRecordId adr = localInfo->rtree->RootRecordId();
|
|
R_TreeNode<dim, TupleId> *tmp = localInfo->rtree->GetMyNode(
|
|
adr,
|
|
false,
|
|
localInfo->rtree->MinEntries( 0 ),
|
|
localInfo->rtree->MaxEntries( 0 ) );
|
|
timeType t1(tmp->BoundingBox().MinD(2));
|
|
timeType t2(tmp->BoundingBox().MaxD(2));
|
|
|
|
if( !(t1 >= localInfo->endTime || t2 <= localInfo->startTime))
|
|
{
|
|
localInfo->vectorA.push_back( FieldEntry<timeType>(
|
|
localInfo->rtree->RootRecordId(), 0, t1, t2, 0));
|
|
const BBox<2> xyBox = makexyBox( tmp->BoundingBox() );
|
|
SegEntry<timeType> se(xyBox,t1, t2, 0.0, 0.0, 0,
|
|
localInfo->rtree->RootRecordId(), -1);
|
|
localInfo->timeTree.insert( se, localInfo->k );
|
|
}
|
|
delete tmp;
|
|
///////////////////
|
|
std::vector<unsigned int> randnum;
|
|
srand(time(0));
|
|
unsigned int entrycount = localInfo->rtree->MaxEntries(0);
|
|
int count = 0;
|
|
for (unsigned int i = 0 ;i < entrycount;){
|
|
unsigned int num = rand() % entrycount;
|
|
srand(count);
|
|
count++;
|
|
i++;
|
|
unsigned int j = 0;
|
|
for(;j < randnum.size();j++){
|
|
if(randnum[j] == num){
|
|
i--;
|
|
break;
|
|
}
|
|
}
|
|
if(j == randnum.size())
|
|
randnum.push_back(num);
|
|
}
|
|
///////////////////
|
|
|
|
while( !localInfo->vectorA.empty() )
|
|
{
|
|
unsigned int vpos;
|
|
stable_sort(localInfo->vectorA.begin(),localInfo->vectorA.end(),
|
|
CmpFiledEntry<timeType>); //order by time
|
|
for( vpos = 0; vpos < localInfo->vectorA.size(); ++vpos)
|
|
{
|
|
FieldEntry<timeType> &f = localInfo->vectorA[ vpos ];
|
|
SmiRecordId adr = f.nodeid;
|
|
// check if this entry is not deleted
|
|
if( localInfo->timeTree.erase( f.start, f.end, f.nodeid,
|
|
f.maxdist) )
|
|
{
|
|
R_TreeNode<dim, TupleId> *tmp = localInfo->rtree->GetMyNode(
|
|
adr, false,
|
|
localInfo->rtree->MinEntries( f.level ),
|
|
localInfo->rtree->MaxEntries( f.level ) );
|
|
|
|
if(tmp->IsLeaf()){
|
|
// for ( int ii = 0; ii < tmp->EntryCount(); ++ii ){
|
|
for(unsigned int index = 0; index < randnum.size();index++){
|
|
int ii = randnum[index];
|
|
if(ii >= tmp->EntryCount())
|
|
continue;
|
|
|
|
R_TreeLeafEntry<dim, TupleId> e =
|
|
(R_TreeLeafEntry<dim, TupleId>&)(*tmp)[ii];
|
|
timeType t1((double)(e.box.MinD(2)));
|
|
timeType t2((double)(e.box.MaxD(2)));
|
|
if(t1 > f.end)
|
|
break;
|
|
if( !(t1 >= localInfo->endTime || t2 <= localInfo->startTime)){
|
|
const BBox<2> xyBox = makexyBox( e.box );
|
|
Interval<timeType> d(t1,t2,true,true);
|
|
const BBox<2> mBox(t->getBox(d));
|
|
SegEntry<timeType> se(xyBox,t1, t2,
|
|
xyBox.Distance( mBox),
|
|
maxDistance( xyBox, mBox), 1,
|
|
-1, e.info);
|
|
|
|
double reachcov =
|
|
localInfo->timeTree.calcCoverage(t1,t2,xyBox.Distance(mBox));
|
|
if(reachcov < localInfo->k)
|
|
localInfo->timeTree.insert(se,localInfo->k);
|
|
}
|
|
}
|
|
}else{ //Internal node
|
|
std::vector<Interval<Instant> > interv;
|
|
std::vector<int> covs;
|
|
CcInt* id = new CcInt(true,f.nodeid);
|
|
BTreeIterator* btreeiter = localInfo->btreehats->ExactMatch(id);
|
|
while(btreeiter->Next()){
|
|
Tuple* tuple = localInfo->hats->GetTuple(btreeiter->GetId()
|
|
, false);
|
|
UInt* ut = (UInt*)tuple->GetAttribute(2);//NodeId, RecId, Uint
|
|
//////////////////////////////////////////////
|
|
if(ut->constValue.GetValue() > 0){
|
|
interv.push_back(ut->timeInterval);
|
|
covs.push_back(ut->constValue.GetValue());
|
|
}
|
|
//////////////////////////////////////////////
|
|
tuple->DeleteIfAllowed();
|
|
}
|
|
delete id;
|
|
delete btreeiter;
|
|
|
|
// for ( int ii = 0; ii < tmp->EntryCount(); ++ii ){
|
|
for(unsigned int index = 0; index < randnum.size();index++){
|
|
int ii = randnum[index];
|
|
if(ii >= tmp->EntryCount())
|
|
continue;
|
|
R_TreeInternalEntry<dim> e =
|
|
(R_TreeInternalEntry<dim>&)(*tmp)[ii];
|
|
timeType t1(e.box.MinD(2));
|
|
timeType t2(e.box.MaxD(2));
|
|
if( !(t1 >= localInfo->endTime || t2 <= localInfo->startTime)){
|
|
const BBox<2> xyBox = makexyBox( e.box );
|
|
Interval<timeType> d(t1,t2,true,true);
|
|
const BBox<2> mBox(t->getBox(d));
|
|
if(interv.size() == 3){ //exit hat
|
|
int cov = 0;
|
|
|
|
// for(unsigned int j = 0;j < interv.size();j++){
|
|
// if(interv[j].Contains(t2)){
|
|
// cov = covs[j];
|
|
// break;
|
|
// }
|
|
// }
|
|
for(unsigned int j = 0;j < interv.size();j++){
|
|
if(interv[j].Contains(t2) && interv[j].Contains(t1)){
|
|
cov = covs[j];
|
|
break;
|
|
}
|
|
if(interv[0].Contains(t1) && interv[1].Contains(t2)){
|
|
cov = covs[0]<covs[1]?covs[0]:covs[1];
|
|
break;
|
|
}
|
|
if(interv[1].Contains(t1) && interv[2].Contains(t2)){
|
|
cov = covs[1]<covs[2]?covs[1]:covs[2];
|
|
break;
|
|
}
|
|
}
|
|
|
|
SegEntry<timeType> se(xyBox,t1, t2,
|
|
xyBox.Distance( mBox),
|
|
maxDistance( xyBox, mBox), cov,
|
|
e.pointer, -1);
|
|
double reachedCoverage =
|
|
localInfo->timeTree.calcCoverage( t1, t2, se.mindist );
|
|
if(reachedCoverage < localInfo->k){
|
|
localInfo->timeTree.insert( se, localInfo->k);
|
|
localInfo->vectorB.push_back(FieldEntry<timeType>(
|
|
se.nodeid, se.maxdist, se.start, se.end,
|
|
f.level+1));
|
|
}
|
|
}else{// no hat
|
|
SegEntry<timeType> se(xyBox,t1, t2,
|
|
xyBox.Distance( mBox),
|
|
maxDistance( xyBox, mBox), 0,
|
|
e.pointer, -1);
|
|
if( checkInsert( localInfo->timeTree, se,
|
|
mBox, localInfo->k, localInfo->rtree, f.level+1))
|
|
{
|
|
localInfo->vectorB.push_back( FieldEntry<timeType>(
|
|
e.pointer, se.maxdist, t1, t2, f.level + 1));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}//else
|
|
delete tmp;
|
|
}
|
|
}
|
|
localInfo->vectorA.clear();
|
|
localInfo->vectorA.swap( localInfo->vectorB );
|
|
}
|
|
delete t;
|
|
|
|
localInfo->timeTree.fillMap( localInfo->resultMap );
|
|
localInfo->mapit = localInfo->resultMap.begin();
|
|
|
|
return 0;
|
|
}
|
|
|
|
case REQUEST :
|
|
{
|
|
localInfo = (KnearestFilterLocalInfo<timeType>*)local.addr;
|
|
if ( !localInfo->scanFlag )
|
|
{
|
|
return CANCEL;
|
|
}
|
|
|
|
if ( !localInfo->k)
|
|
{
|
|
return CANCEL;
|
|
}
|
|
|
|
/* give out alle elements of the resultmap */
|
|
if ( localInfo->mapit != localInfo->resultMap.end() )
|
|
{
|
|
TupleId tid = localInfo->mapit->second;
|
|
Tuple *tuple = localInfo->relation->GetTuple(tid, false);
|
|
//split units
|
|
const MPoint *mp = (MPoint*)args[5].addr;//5 th parameter
|
|
UPoint up1, up2;
|
|
mp->Get( 0, up1);
|
|
mp->Get( mp->GetNoComponents() - 1, up2);
|
|
int attrpos = ((CcInt*)args[7].addr)->GetIntval() - 1;
|
|
UPoint* up = (UPoint*)tuple->GetAttribute(attrpos);
|
|
Point p0;
|
|
if(up->timeInterval.Contains(up1.timeInterval.start)){
|
|
up->TemporalFunction(up1.timeInterval.start,p0,true);
|
|
if(p0.IsDefined()){
|
|
up->timeInterval.start = up1.timeInterval.start;
|
|
up->p0 = p0;
|
|
}
|
|
}
|
|
Point p1;
|
|
if(up->timeInterval.Contains(up2.timeInterval.end)){
|
|
up->TemporalFunction(up2.timeInterval.end,p1,true);
|
|
if(p1.IsDefined()){
|
|
up->timeInterval.end = up2.timeInterval.end;
|
|
up->p1 = p1;
|
|
}
|
|
}
|
|
//
|
|
result = SetWord(tuple);
|
|
++localInfo->mapit;
|
|
return YIELD;
|
|
}
|
|
else
|
|
{
|
|
return CANCEL;
|
|
}
|
|
}
|
|
|
|
case CLOSE :
|
|
{
|
|
localInfo = (KnearestFilterLocalInfo<timeType>*)local.addr;
|
|
if(localInfo){
|
|
delete localInfo;
|
|
local.addr=0;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
The function knearestFilterTypeMap is the type map for the
|
|
operator knearestfilter
|
|
|
|
*/
|
|
ListExpr
|
|
knearestFilterTypeMap( ListExpr args )
|
|
{
|
|
|
|
if(nl->ListLength(args) != 7){
|
|
return listutils::typeError("7 arguments expected");
|
|
}
|
|
|
|
ListExpr rtreeDescription = nl->First(args);
|
|
ListExpr relDescription = nl->Second(args);
|
|
ListExpr btreeDescription = nl->Third(args);
|
|
ListExpr brelDescription = nl->Fourth(args);
|
|
ListExpr attrName = nl->Fifth(args);
|
|
ListExpr queryobject = nl->Sixth(args);
|
|
ListExpr quantity = nl->Nth(7,args);
|
|
|
|
std::string err = "rtree x rel x btree x attrname x mpoint x int expected";
|
|
|
|
if( !listutils::isRTreeDescription(rtreeDescription) ||
|
|
!listutils::isRelDescription(relDescription) ||
|
|
!listutils::isBTreeDescription(btreeDescription) ||
|
|
!listutils::isRelDescription(brelDescription) ||
|
|
!listutils::isSymbol(attrName) ||
|
|
!listutils::isSymbol(queryobject,MPoint::BasicType()) ||
|
|
!listutils::isSymbol(quantity,CcInt::BasicType())){
|
|
return listutils::typeError(err);
|
|
}
|
|
|
|
ListExpr attrType;
|
|
std::string aname = nl->SymbolValue(attrName);
|
|
int j = listutils::findAttribute(nl->Second(nl->Second(relDescription)),
|
|
aname,attrType);
|
|
if(j==0 || !listutils::isSymbol(attrType,UPoint::BasicType())){
|
|
return listutils::typeError("attr name " + aname + " not found "
|
|
"or not of type upoint");
|
|
}
|
|
|
|
ListExpr rtreeSymbol = nl->First(rtreeDescription);
|
|
ListExpr rtreeKeyType = nl->Third(rtreeDescription);
|
|
|
|
if(!listutils::isSymbol(rtreeKeyType)){
|
|
return listutils::typeError("rtree key type must be atomic");
|
|
}
|
|
if(!listutils::isKind(rtreeKeyType,Kind::SPATIAL3D()) &&
|
|
!listutils::isSymbol(rtreeKeyType,Rectangle<3>::BasicType())){
|
|
return listutils::typeError("rtree key type must in kind "
|
|
"SPATIAL3D or be a rect3");
|
|
}
|
|
|
|
if(!listutils::isSymbol(rtreeSymbol,RTree3TID::BasicType())){
|
|
return listutils::typeError("type of rtree is not rtree3");
|
|
}
|
|
|
|
/* check that rtree and rel have the same associated tuple type */
|
|
ListExpr attrList = nl->Second(nl->Second(relDescription));
|
|
ListExpr rtreeAttrList = nl->Second(nl->Second(rtreeDescription));
|
|
if(!nl->Equal(attrList, rtreeAttrList)){
|
|
return listutils::typeError("types of relation and rtree differ");
|
|
}
|
|
|
|
ListExpr res = nl->TwoElemList(
|
|
nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->Second(relDescription));
|
|
|
|
return nl->ThreeElemList(
|
|
nl->SymbolAtom(Symbol::APPEND()),
|
|
nl->OneElemList(nl->IntAtom(j)),
|
|
res);
|
|
}
|
|
const std::string knearestFilterSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )"
|
|
"( <text>rtree(tuple ((x1 t1)...(xn tn))"
|
|
" ti) x rel1(tuple ((x1 t1)...(xn tn))) x btree(tuple ((x1 t1)...(xn tn)))"
|
|
" x rel2(tuple ((x1 t1)...(xn tn))) x xi x mpoint x k ->"
|
|
" (stream (tuple ((x1 t1)...(xn tn))))"
|
|
"</text--->"
|
|
"<text>_ _ _ _ knearestfilter [_, _, _ ]</text--->"
|
|
"<text>The operator results a stream of all input tuples "
|
|
"which are the k-nearest tupels to the given mpoint. "
|
|
"The operator do not separate tupels if necessary. The "
|
|
"result may have more than the k-nearest tupels. It is a "
|
|
"filter operator for the knearest operator, if there are a great "
|
|
"many input tupels. "
|
|
"The operator expects a three dimensional rtree where the "
|
|
"third dimension is the time</text--->"
|
|
"<text>query UTOrdered_RTree UTOrdered btreehats hats knearestfilter "
|
|
"[UTrip,train1, 5] count;</text--->"
|
|
"))";
|
|
Operator knearestfilter (
|
|
"knearestfilter", // name
|
|
knearestFilterSpec, // specification
|
|
//newknearestFilterFun<Instant>, // value mapping
|
|
knearestFilterFun<double>, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
knearestFilterTypeMap // type mapping
|
|
);
|
|
|
|
|
|
struct PointNeighbor{
|
|
Point q; //query point
|
|
Point p; //data point
|
|
float dist;
|
|
PointNeighbor(){dist = 0.0;}
|
|
PointNeighbor(Point&a,Point& b):q(a),p(b){dist = q.Distance(p);}
|
|
PointNeighbor(const PointNeighbor& pn):q(pn.q),p(pn.p),dist(pn.dist){}
|
|
};
|
|
bool CmpPointNeighbor(const PointNeighbor& e1,const PointNeighbor& e2)
|
|
{
|
|
return e1.q.Distance(e1.p) < e2.q.Distance(e2.p);
|
|
}
|
|
struct PruneLeafNode{
|
|
long nodeid;
|
|
BBox<2> box;
|
|
PruneLeafNode(long id,BBox<2> b):nodeid(id),box(b){}
|
|
};
|
|
|
|
struct MQKnearest{
|
|
Relation* querypoints;
|
|
Relation* datapoints;
|
|
R_Tree<2,TupleId>* rtree;
|
|
Relation* cov;
|
|
BTree* btreecov;
|
|
Relation* leafcov;
|
|
BTree* btreeleafcov;
|
|
unsigned int k;
|
|
TupleType* resulttype;
|
|
std::vector<PointNeighbor> results;
|
|
std::vector<PointNeighbor>::iterator iter;
|
|
bool nextblock;
|
|
std::vector<Point> block; //split query objects into blocks
|
|
std::vector<Point> data; //the candidate for current block
|
|
int index; //position in rel querypoints
|
|
MQKnearest(){}
|
|
};
|
|
template<class timeType>
|
|
bool CmpFE(const FieldEntry<timeType>& fe1, const FieldEntry<timeType>& fe2)
|
|
{
|
|
if(fe1.mindist < fe2.mindist)
|
|
return true;
|
|
if(fe1.maxdist < fe2.maxdist)
|
|
return true;
|
|
return false;
|
|
}
|
|
template<class timeType>
|
|
bool CmpEFE(const EFieldEntry<timeType>& fe1, const EFieldEntry<timeType>& fe2)
|
|
{
|
|
if(fe1.mindist < fe2.mindist)
|
|
return true;
|
|
if(fe1.maxdist < fe2.maxdist)
|
|
return true;
|
|
return false;
|
|
}
|
|
void Mqkfilter(MQKnearest* mqk,std::vector<TupleId>& datanode,BBox<2> query)
|
|
{
|
|
int minentries = mqk->rtree->MinEntries(0);
|
|
int maxentries = mqk->rtree->MaxEntries(0);
|
|
SmiRecordId adr = mqk->rtree->RootRecordId();
|
|
std::vector<EFieldEntry<double> > array1;
|
|
std::vector<EFieldEntry<double> > array2;
|
|
std::vector<EFieldEntry<double> > candidate;
|
|
EFieldEntry<double> fe(adr,0,0,0,0,0);
|
|
array1.push_back(fe);
|
|
unsigned int pos;
|
|
//BF-first method
|
|
while(array1.empty() == false){
|
|
array2.clear();
|
|
for(pos = 0;pos < array1.size();pos++){
|
|
fe = array1[pos];
|
|
adr = fe.nodeid;
|
|
R_TreeNode<2,TupleId>* node = mqk->rtree->GetMyNode(
|
|
adr,false,minentries,maxentries);
|
|
if(node->IsLeaf()){
|
|
candidate.push_back(fe);//leaf node (id)
|
|
continue;
|
|
}
|
|
for(int i = 0; i < node->EntryCount();i++){ //Internal node
|
|
R_TreeInternalEntry<2> e = (R_TreeInternalEntry<2>&)(*node)[i];
|
|
EFieldEntry<double> fe1(e.pointer,query.Distance(e.box),
|
|
maxDistance(query,e.box),fe.level+1,0,0);
|
|
array2.push_back(fe1);
|
|
}
|
|
}
|
|
array1.clear();
|
|
sort(array2.begin(),array2.end(),CmpEFE<double>);
|
|
double dist = 0;
|
|
double num = 0;
|
|
for(unsigned int i = 0;i < array2.size();i++){
|
|
CcInt* id = new CcInt(true,array2[i].nodeid);
|
|
BTreeIterator* iter = mqk->btreecov->ExactMatch(id);
|
|
assert(iter->Next() != false);
|
|
Tuple* tuple = mqk->cov->GetTuple(iter->GetId(), false);
|
|
int val = ((CcInt*)tuple->GetAttribute(1))->GetIntval();
|
|
delete id;
|
|
tuple->DeleteIfAllowed();
|
|
if(num + val > mqk->k){
|
|
dist = array2[i].maxdist;
|
|
break;
|
|
}
|
|
num += val;
|
|
}
|
|
for(unsigned int i = 0;i < array2.size();i++){
|
|
if(array2[i].mindist > dist)
|
|
break;
|
|
array1.push_back(array2[i]);
|
|
}
|
|
}
|
|
//process leaf node
|
|
sort(candidate.begin(),candidate.end(),CmpEFE<double>);
|
|
double dist = 0;
|
|
double num = 0;
|
|
|
|
for(unsigned int i = 0;i < candidate.size();i++){
|
|
CcInt* id = new CcInt(true,candidate[i].nodeid);
|
|
BTreeIterator* iter = mqk->btreecov->ExactMatch(id);
|
|
assert(iter->Next() != false);
|
|
Tuple* tuple = mqk->cov->GetTuple(iter->GetId(), false);
|
|
int val = ((CcInt*)tuple->GetAttribute(1))->GetIntval();
|
|
delete id;
|
|
tuple->DeleteIfAllowed();
|
|
if(num + val > mqk->k){
|
|
dist = candidate[i].maxdist;
|
|
break;
|
|
}
|
|
num += val;
|
|
}
|
|
for(unsigned int i = 0;i < candidate.size();i++){
|
|
if(candidate[i].mindist > dist)
|
|
break;
|
|
datanode.push_back(candidate[i].nodeid);
|
|
}
|
|
|
|
//load data points into memory
|
|
for(unsigned int i = 0;i < datanode.size();i++){
|
|
adr = datanode[i];
|
|
R_TreeNode<2,TupleId>* node = mqk->rtree->GetMyNode(
|
|
adr,false,minentries,maxentries);
|
|
assert(node->IsLeaf());
|
|
for(int j = 0;j < node->EntryCount();j++){
|
|
R_TreeLeafEntry<2,TupleId> e =
|
|
(R_TreeLeafEntry<2,TupleId>&)(*node)[j];
|
|
Tuple* tuple = mqk->datapoints->GetTuple(e.info, false);
|
|
Point* p = (Point*)tuple->GetAttribute(0);
|
|
mqk->data.push_back(*p);
|
|
tuple->DeleteIfAllowed();
|
|
}
|
|
}
|
|
// cout<<"after R-tree filter data candidate size "<<mqk->data.size()<<endl;
|
|
}
|
|
struct Subleafnode{
|
|
int nodeid;
|
|
double mindist,maxdist;
|
|
BBox<2> box;
|
|
int quad;
|
|
Subleafnode(){}
|
|
Subleafnode(int id,double min,double max,BBox<2> b,int q)
|
|
:nodeid(id),mindist(min),maxdist(max),box(b),quad(q){}
|
|
Subleafnode& operator = (const Subleafnode& sln)
|
|
{
|
|
nodeid = sln.nodeid;
|
|
mindist = sln.mindist;
|
|
maxdist = sln.maxdist;
|
|
box = sln.box;
|
|
quad = sln.quad;
|
|
return *this;
|
|
}
|
|
|
|
Subleafnode(const Subleafnode& sln)
|
|
:nodeid(sln.nodeid),
|
|
mindist(sln.mindist),
|
|
maxdist(sln.maxdist),
|
|
box(sln.box),
|
|
quad(sln.quad)
|
|
{
|
|
|
|
}
|
|
};
|
|
bool CmpSLN(const Subleafnode& sln1,const Subleafnode& sln2)
|
|
{
|
|
if(sln1.mindist < sln2.mindist)
|
|
return true;
|
|
if(sln1.maxdist < sln2.maxdist)
|
|
return true;
|
|
if(sln1.nodeid < sln2.nodeid)
|
|
return true;
|
|
return false;
|
|
}
|
|
bool CmpSLNNodeid(const Subleafnode& sln1,const Subleafnode& sln2)
|
|
{
|
|
if(sln1.nodeid < sln2.nodeid)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
void MqkPartitionNode(MQKnearest* mqk, std::vector<Subleafnode> candidate,
|
|
std::vector<Point>& ps,BBox<2> box) //ps--query objects, box -- query box
|
|
{
|
|
for(unsigned int i = 0;i < candidate.size();i++){
|
|
BBox<2> b(candidate[i].box);
|
|
candidate[i].mindist = b.Distance(box);
|
|
candidate[i].maxdist = maxDistance(b,box);
|
|
}
|
|
stable_sort(candidate.begin(),candidate.end(),CmpSLN);
|
|
//set threshold distance value
|
|
double dist = 0;
|
|
double num = 0;
|
|
for(unsigned int i = 0;i < candidate.size();i++){
|
|
CcInt* id = new CcInt(true,candidate[i].nodeid);
|
|
BTreeIterator* iter = mqk->btreeleafcov->ExactMatch(id);
|
|
assert(iter->Next() != false);
|
|
Tuple* tuple = mqk->leafcov->GetTuple(iter->GetId(), false);
|
|
int val = ((CcInt*)tuple->GetAttribute(candidate[i].quad))->GetIntval();
|
|
delete id;
|
|
tuple->DeleteIfAllowed();
|
|
if(num + val > mqk->k){
|
|
dist = candidate[i].maxdist;
|
|
break;
|
|
}
|
|
num += val;
|
|
}
|
|
std::vector<Subleafnode> candata;//real candidate
|
|
for(unsigned int i = 0;i < candidate.size();i++){
|
|
|
|
if(candidate[i].mindist > dist)
|
|
break;
|
|
candata.push_back(candidate[i]);
|
|
}
|
|
stable_sort(candata.begin(),candata.end(),CmpSLNNodeid);//sort by nodeid
|
|
// cout<<"subleaf node "<<candata.size()<<endl;
|
|
std::vector<Point> datapoints;
|
|
R_TreeNode<2,TupleId>* node;
|
|
SmiRecordId adr;
|
|
int minentries = mqk->rtree->MinEntries(0);
|
|
int maxentries = mqk->rtree->MaxEntries(0);
|
|
for(unsigned int i = 0;i < candata.size();){
|
|
int nodeid = candata[i].nodeid;
|
|
std::vector<BBox<2> > range;
|
|
while(candata[i].nodeid == nodeid){
|
|
range.push_back(candata[i].box);
|
|
i++;
|
|
}
|
|
adr = nodeid;
|
|
node = mqk->rtree->GetMyNode(adr,false,minentries,maxentries);
|
|
for(int j = 0;j < node->EntryCount();j++){//open leaf node
|
|
R_TreeLeafEntry<2,TupleId> e =
|
|
(R_TreeLeafEntry<2,TupleId>&)(*node)[j];
|
|
Tuple* tuple = mqk->datapoints->GetTuple(e.info, false);
|
|
Point* p = (Point*)tuple->GetAttribute(0);
|
|
double x = p->GetX();
|
|
double y = p->GetY();
|
|
for(unsigned int k = 0;k < range.size();k++){
|
|
if(range[k].MinD(0) <= x && range[k].MinD(1) <= y &&
|
|
x < range[k].MaxD(0) && y < range[k].MaxD(1)){
|
|
datapoints.push_back(*p);
|
|
break;
|
|
}
|
|
}
|
|
tuple->DeleteIfAllowed();
|
|
}
|
|
}
|
|
// cout<<"query size "<<ps.size()<<endl;
|
|
// cout<<"datapoints size "<<datapoints.size()<<endl;
|
|
|
|
double x = 0;
|
|
double y = 0;
|
|
for(unsigned int i = 0;i < ps.size();i++){
|
|
x += ps[i].GetX();
|
|
y += ps[i].GetY();
|
|
}
|
|
|
|
Point* seedp = new Point(true, // choose centroid point as seed point
|
|
x/ps.size(),y/ps.size());
|
|
std::vector<PointNeighbor> distance; //data points ordered
|
|
for(unsigned int j = 0;j < datapoints.size();j++){
|
|
PointNeighbor* pd = new PointNeighbor(*seedp,datapoints[j]);
|
|
distance.push_back(*pd);
|
|
delete pd;
|
|
}
|
|
sort(distance.begin(),distance.end(),CmpPointNeighbor);
|
|
std::vector<PointNeighbor> tempstore;
|
|
for(unsigned int i = 0;i < ps.size();i++){
|
|
Point* p1 = &ps[i];
|
|
double threshold = 0;
|
|
for(unsigned int i = 0; i < mqk->k; i++)
|
|
if(p1->Distance(distance[i].p) > threshold)
|
|
threshold = p1->Distance(distance[i].p);
|
|
|
|
for(unsigned int j = 0;j < distance.size();j++){
|
|
double dist = distance[j].dist-p1->Distance(*seedp);
|
|
if(dist > threshold)
|
|
break;
|
|
PointNeighbor* pn = new PointNeighbor(*p1,distance[j].p);
|
|
tempstore.push_back(*pn);
|
|
delete pn;
|
|
}
|
|
sort(tempstore.begin(),tempstore.end(),CmpPointNeighbor);
|
|
for(unsigned int i = 0;i < mqk->k;i++)
|
|
mqk->results.push_back(tempstore[i]);
|
|
tempstore.clear();
|
|
}
|
|
|
|
delete seedp;
|
|
}
|
|
void MqkPartition(MQKnearest* mqk, std::vector<TupleId>& datanode,BBox<2>& box)
|
|
{
|
|
double minx = box.MinD(0);
|
|
double miny = box.MinD(1);
|
|
double maxx = box.MaxD(0);
|
|
double maxy = box.MaxD(1);
|
|
std::vector<Point> ps1;
|
|
std::vector<Point> ps2;
|
|
std::vector<Point> ps3;
|
|
std::vector<Point> ps4;
|
|
//partition query points into four quadrants
|
|
for(unsigned int i = 0;i < mqk->block.size();i++){
|
|
double x = mqk->block[i].GetX();
|
|
double y = mqk->block[i].GetY();
|
|
if(minx <= x && x< (minx+(maxx-minx)/2)){
|
|
if(miny <= y && y < (miny+(maxy-miny)/2))
|
|
ps3.push_back(mqk->block[i]);
|
|
else
|
|
ps2.push_back(mqk->block[i]);
|
|
}else{
|
|
if(miny <= y && y < (miny+(maxy-miny)/2))
|
|
ps4.push_back(mqk->block[i]);
|
|
else
|
|
ps1.push_back(mqk->block[i]);
|
|
}
|
|
}
|
|
assert(ps1.size() + ps2.size() + ps3.size() + ps4.size() == mqk->block.size());
|
|
double min[2],max[2];
|
|
//quadrant 3
|
|
min[0] = minx;
|
|
min[1] = miny;
|
|
max[0] = minx + (maxx-minx)/2;
|
|
max[1] = miny + (maxy-miny)/2;
|
|
BBox<2> b3(true,min,max);
|
|
//4 quadrant
|
|
min[0] = minx + (maxx-minx)/2;
|
|
min[1] = miny;
|
|
max[0] = maxx;
|
|
max[1] = miny + (maxy-miny)/2;
|
|
BBox<2> b4(true,min,max);
|
|
//1 quadrant
|
|
min[0] = minx + (maxx-minx)/2;
|
|
min[1] = miny + (maxy-miny)/2;
|
|
max[0] = maxx;
|
|
max[1] = maxy;
|
|
BBox<2> b1(true,min,max);
|
|
//2 quadrant
|
|
min[0] = minx;
|
|
min[1] = miny + (maxy-miny)/2;
|
|
max[0] = minx + (maxx-minx)/2;
|
|
max[1] = maxy;
|
|
BBox<2> b2(true,min,max);
|
|
//
|
|
std::vector<Subleafnode> candidate;//all subleaf node
|
|
R_TreeNode<2,TupleId>* node;
|
|
SmiRecordId adr;
|
|
int minentries = mqk->rtree->MinEntries(0);
|
|
int maxentries = mqk->rtree->MaxEntries(0);
|
|
|
|
for(unsigned int i = 0;i < datanode.size();i++){
|
|
adr = datanode[i];
|
|
node = mqk->rtree->GetMyNode(adr,false,minentries,maxentries);
|
|
assert(node->IsLeaf());
|
|
BBox<2> b = node->BoundingBox();
|
|
double minx = b.MinD(0);
|
|
double miny = b.MinD(1);
|
|
double maxx = b.MaxD(0);
|
|
double maxy = b.MaxD(1);
|
|
//3 quadrant
|
|
min[0] = minx;
|
|
min[1] = miny;
|
|
max[0] = minx + (maxx-minx)/2;
|
|
max[1] = miny + (maxy-miny)/2;
|
|
BBox<2> b3(true,min,max);
|
|
Subleafnode sln3(datanode[i],0,0,b3,3);
|
|
candidate.push_back(sln3);
|
|
//4 quadrant
|
|
min[0] = minx + (maxx-minx)/2;
|
|
min[1] = miny;
|
|
max[0] = maxx;
|
|
max[1] = miny + (maxy-miny)/2;
|
|
BBox<2> b4(true,min,max);
|
|
Subleafnode sln4(datanode[i],0,0,b4,4);
|
|
candidate.push_back(sln4);
|
|
//1 quadrant
|
|
min[0] = minx + (maxx-minx)/2;
|
|
min[1] = miny + (maxy-miny)/2;
|
|
max[0] = maxx;
|
|
max[1] = maxy;
|
|
BBox<2> b1(true,min,max);
|
|
Subleafnode sln1(datanode[i],0,0,b1,1);
|
|
candidate.push_back(sln1);
|
|
//2 quadrant
|
|
min[0] = minx;
|
|
min[1] = miny + (maxy-miny)/2;
|
|
max[0] = minx + (maxx-minx)/2;
|
|
max[1] = maxy;
|
|
BBox<2> b2(true,min,max);
|
|
Subleafnode sln2(datanode[i],0,0,b2,2);
|
|
candidate.push_back(sln2);
|
|
}
|
|
// cout<<"total subleaf node "<<candidate.size()<<endl;
|
|
MqkPartitionNode(mqk,candidate,ps1,b1);
|
|
MqkPartitionNode(mqk,candidate,ps2,b2);
|
|
MqkPartitionNode(mqk,candidate,ps3,b3);
|
|
MqkPartitionNode(mqk,candidate,ps4,b4);
|
|
mqk->block.clear();
|
|
mqk->iter = mqk->results.begin();
|
|
}
|
|
|
|
//for each point in querypoints, find its k closest point, put into vectors
|
|
void Mqknearest(MQKnearest* mqk)
|
|
{
|
|
double x = 0;
|
|
double y = 0;
|
|
//load query points into memory
|
|
const int blocksize = 128;
|
|
int start = 0;
|
|
double min[2];
|
|
double max[2];
|
|
Tuple* tuple = mqk->querypoints->GetTuple(1, false);
|
|
Point* p = (Point*)tuple->GetAttribute(0);
|
|
min[0] = max[0] = p->GetX();
|
|
min[1] = max[1] = p->GetY();
|
|
tuple->DeleteIfAllowed();
|
|
for(;start < blocksize &&
|
|
(start+mqk->index) <= mqk->querypoints->GetNoTuples(); start++){
|
|
Tuple* tuple = mqk->querypoints->GetTuple(start+mqk->index, false);
|
|
Point* p = (Point*)tuple->GetAttribute(0);
|
|
double xx = p->GetX();
|
|
double yy = p->GetY();
|
|
x += xx;
|
|
y += yy;
|
|
if(xx < min[0])
|
|
min[0] = xx;
|
|
if(xx > max[0])
|
|
max[0] = xx;
|
|
if(yy < min[1])
|
|
min[1] = yy;
|
|
if(yy > max[1])
|
|
max[1] = yy;
|
|
mqk->block.push_back(*p);
|
|
tuple->DeleteIfAllowed();
|
|
}
|
|
if((start+mqk->index) > mqk->querypoints->GetNoTuples()){
|
|
mqk->nextblock = false;
|
|
}else{
|
|
mqk->index += start;
|
|
}
|
|
BBox<2> box(true,min,max);
|
|
|
|
//process with R-tree rel on data points, return a set of leaf nodeid
|
|
std::vector<TupleId> datanode;
|
|
Mqkfilter(mqk,datanode,box);
|
|
MqkPartition(mqk,datanode,box);//partition method according to quadrant
|
|
|
|
//following does not partition
|
|
std::vector<PointNeighbor> distance; //data points ordered
|
|
|
|
//brute force algorithm
|
|
// for(int i = 1;i <= mqk->querypoints->GetNoTuples();i++){
|
|
// Tuple* tuple1 = mqk->querypoints->GetTuple(i);
|
|
// Point* p1 = (Point*)tuple1->GetAttribute(0);
|
|
// for(int j = 1;j <= mqk->datapoints->GetNoTuples();j++){
|
|
// Tuple* tuple2 = mqk->datapoints->GetTuple(j);
|
|
// Point* p2 = (Point*)tuple2->GetAttribute(0);
|
|
// PointNeighbor* pd = new PointNeighbor(*p1,*p2);
|
|
// distance.push_back(*pd);
|
|
// delete pd;
|
|
// }
|
|
// sort(distance.begin(),distance.end(),CmpPointNeighbor);
|
|
// for(unsigned int i = 0;i < mqk->k;i++){
|
|
// mqk->results.push_back(mqk->distance[i]);
|
|
// }
|
|
// distance.clear();
|
|
// }
|
|
// mqk->iter = mqk->results.begin();
|
|
|
|
//random seed point
|
|
// srand(time(0));
|
|
// int seed = 1 + rand()%(mqk->querypoints->GetNoTuples()-1);
|
|
// tuple = mqk->datapoints->GetTuple(seed);
|
|
// Point* seedp = (Point*)tuple->GetAttribute(0);
|
|
// tuple->DeleteIfAllowed();
|
|
|
|
|
|
// Point* seedp = new Point(true, // choose centroid point as seed point
|
|
// x/mqk->querypoints->GetNoTuples(),y/mqk->querypoints->GetNoTuples());
|
|
// vector<PointNeighbor> tempstore;
|
|
// for(int j = 1;j <= mqk->datapoints->GetNoTuples();j++){
|
|
// Tuple* tuple = mqk->datapoints->GetTuple(j);
|
|
// Point* p2 = (Point*)tuple->GetAttribute(0);
|
|
// PointNeighbor* pd = new PointNeighbor(*seedp,*p2);
|
|
// distance.push_back(*pd);
|
|
// delete pd;
|
|
// tuple->DeleteIfAllowed();
|
|
// }
|
|
// sort(distance.begin(),distance.end(),CmpPointNeighbor);
|
|
|
|
// for(unsigned int i = 0;i < mqk->block.size();i++){
|
|
// Point* p1 = &mqk->block[i];
|
|
// double threshold = 0;
|
|
// for(unsigned int i = 0; i < mqk->k; i++)
|
|
// if(p1->Distance(distance[i].p) > threshold)
|
|
// threshold = p1->Distance(distance[i].p);
|
|
// for(unsigned int j = 0;j < distance.size();j++){
|
|
// double dist = distance[j].dist-p1->Distance(*seedp);
|
|
// if(dist > threshold)
|
|
// break;
|
|
// PointNeighbor* pn = new PointNeighbor(*p1,distance[j].p);
|
|
// tempstore.push_back(*pn);
|
|
// delete pn;
|
|
// }
|
|
// sort(tempstore.begin(),tempstore.end(),CmpPointNeighbor);
|
|
// for(unsigned int i = 0;i < mqk->k;i++)
|
|
// mqk->results.push_back(tempstore[i]);
|
|
// tempstore.clear();
|
|
// }
|
|
// mqk->block.clear();
|
|
// mqk->iter = mqk->results.begin();
|
|
// delete seedp;
|
|
|
|
|
|
}
|
|
|
|
const std::string covleafnodeSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )"
|
|
"( <text> datarel(tuple ((x1 t1)...(xn tn))) "
|
|
" x rtree(tuple((x1 t1)...(xn tn)))"
|
|
" x covrel(tuple((x1 t1)))->"
|
|
" (stream (tuple ((x1 t1)...(xn tn))))"
|
|
"</text--->"
|
|
"<text>covleafnode(_ ,_,_ )</text--->"
|
|
"<text>The operator returns a stream of tuples "
|
|
"recording the number of units in leafnode of R-tree"
|
|
"according to different quadrants"
|
|
"</text--->"
|
|
"<text>not finished yet;</text--->"
|
|
") )";
|
|
ListExpr covleafnodeTypeMap(ListExpr args){
|
|
if(nl->ListLength(args) != 3){
|
|
ErrorReporter::ReportError("3 parameters expected");
|
|
return nl->TypeError();
|
|
}
|
|
ListExpr rtree2 = nl->Second(args);
|
|
std::string rtreedescription2;
|
|
nl->WriteToString(rtreedescription2,rtree2);
|
|
ListExpr rtsymbol2 = nl->First(rtree2);
|
|
|
|
if(nl->IsAtom(rtsymbol2) &&
|
|
nl->AtomType(rtsymbol2) == SymbolType &&
|
|
nl->SymbolValue(rtsymbol2) == RTree2TID::BasicType())
|
|
|
|
return
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom(Tuple::BasicType()),
|
|
nl->FiveElemList(
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("Nodeid"),
|
|
nl->SymbolAtom(CcInt::BasicType())
|
|
),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("Coverage"),//1 quadrant
|
|
nl->SymbolAtom(CcInt::BasicType())
|
|
),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("Coverage"),//2 quadrant
|
|
nl->SymbolAtom(CcInt::BasicType())
|
|
),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("Coverage"),//3 quadrant
|
|
nl->SymbolAtom(CcInt::BasicType())
|
|
),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("Coverage"),//4 quadrant
|
|
nl->SymbolAtom(CcInt::BasicType())
|
|
))));
|
|
ErrorReporter::ReportError("rtree expected");
|
|
return nl->TypeError();
|
|
|
|
}
|
|
struct Covleafnode{
|
|
Relation* data;
|
|
R_Tree<2,TupleId>* rtree;
|
|
Relation* cov;
|
|
TupleType* resulttype;
|
|
int covtid;
|
|
Covleafnode(){}
|
|
};
|
|
/*
|
|
Calculate the coverage number for each leafnode according to different
|
|
quadrants
|
|
|
|
*/
|
|
int covleafnodeFun(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
Covleafnode* localInfo;
|
|
switch(message){
|
|
case OPEN: {
|
|
localInfo = new Covleafnode();
|
|
localInfo->data = (Relation*)args[0].addr;
|
|
localInfo->rtree = (R_Tree<2,TupleId>*)args[1].addr;
|
|
localInfo->cov = (Relation*)args[2].addr;
|
|
localInfo->resulttype = new TupleType(nl->Second(GetTupleResultType(s)));
|
|
localInfo->covtid = 1;
|
|
local = SetWord(localInfo);
|
|
return 0;
|
|
}
|
|
case REQUEST: {
|
|
localInfo = (Covleafnode*)local.addr;
|
|
R_TreeNode<2,TupleId>* node = NULL;
|
|
int nodeid = 0;
|
|
while(localInfo->covtid <= localInfo->cov->GetNoTuples()){
|
|
Tuple* tuple = localInfo->cov->GetTuple(localInfo->covtid, false);
|
|
assert(tuple != NULL);
|
|
localInfo->covtid++;
|
|
nodeid = ((CcInt*)tuple->GetAttribute(0))->GetIntval();
|
|
tuple->DeleteIfAllowed();
|
|
SmiRecordId adr = nodeid;
|
|
node = localInfo->rtree->GetMyNode(
|
|
adr,false,
|
|
localInfo->rtree->MinEntries(0),localInfo->rtree->MaxEntries(0)
|
|
);
|
|
if(node->IsLeaf())
|
|
break;
|
|
|
|
}
|
|
if(localInfo->covtid > localInfo->cov->GetNoTuples())
|
|
return CANCEL;
|
|
assert(node != NULL);
|
|
BBox<2> box = node->BoundingBox();
|
|
double minx = box.MinD(0);
|
|
double miny = box.MinD(1);
|
|
double maxx = box.MaxD(0);
|
|
double maxy = box.MaxD(1);
|
|
int quad1,quad2,quad3,quad4;
|
|
quad1 = quad2 = quad3 = quad4 = 0;
|
|
for(int i = 0;i < node->EntryCount();i++){
|
|
R_TreeLeafEntry<2,TupleId> e = (R_TreeLeafEntry<2,TupleId>&)(*node)[i];
|
|
TupleId info = e.info;
|
|
Tuple* tuple = localInfo->data->GetTuple(info, false);
|
|
Point* p = (Point*)tuple->GetAttribute(0);
|
|
tuple->DeleteIfAllowed();
|
|
double x = p->GetX();
|
|
double y = p->GetY();
|
|
if(minx <= x && x< (minx+(maxx-minx)/2)){
|
|
if(miny <= y && y < (miny+(maxy-miny)/2))
|
|
quad3++;
|
|
else
|
|
quad2++;
|
|
}else{
|
|
if(miny <= y && y < (miny+(maxy-miny)/2))
|
|
quad4++;
|
|
else
|
|
quad1++;
|
|
}
|
|
}
|
|
assert(quad1+quad2+quad3+quad4 == node->EntryCount());
|
|
//coverage number for each quadrant
|
|
Tuple* tuple = new Tuple(localInfo->resulttype);
|
|
tuple->PutAttribute(0,new CcInt(true,nodeid));
|
|
tuple->PutAttribute(1,new CcInt(true,quad1));
|
|
tuple->PutAttribute(2,new CcInt(true,quad2));
|
|
tuple->PutAttribute(3,new CcInt(true,quad3));
|
|
tuple->PutAttribute(4,new CcInt(true,quad4));
|
|
result.setAddr(tuple);
|
|
return YIELD;
|
|
|
|
}
|
|
case CLOSE : {
|
|
localInfo = (Covleafnode*)local.addr;
|
|
if(localInfo){
|
|
localInfo->resulttype->DeleteIfAllowed();
|
|
delete localInfo;
|
|
local.addr = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
Operator covleafnode (
|
|
"covleafnode", // name
|
|
covleafnodeSpec, // specification
|
|
covleafnodeFun, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
covleafnodeTypeMap // type mapping
|
|
);
|
|
|
|
/*
|
|
Description message for knearest operators
|
|
Chinese algorithm and Greece algorithm
|
|
|
|
*/
|
|
const std::string GreeceknearestfilterSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )"
|
|
"( <text>rtree(tuple ((x1 t1)...(xn tn))"
|
|
" ti) x rel(tuple ((x1 t1)...(xn tn)))"
|
|
" x mpoint x k ->"
|
|
" (stream (tuple ((x1 t1)...(xn tn))))"
|
|
"</text--->"
|
|
"<text>_ _ greeceknearest [_, _, _ ]</text--->"
|
|
"<text>The operator results a stream of all input tuples "
|
|
"which are the k-nearest tupels to the given mpoint. "
|
|
"The operator do not separate tupels if necessary. The "
|
|
"result may have more than the k-nearest tupels. It is a "
|
|
"filter operator for the knearest operator, if there are a great "
|
|
"many input tupels. "
|
|
"The operator expects an r-tree built on moving objects</text--->"
|
|
"<text>query UnitTrains_UTrip UnitTrains "
|
|
" greeceknearest [UTrip,train1, 5] count;</text--->"
|
|
") )";
|
|
const std::string ChinaknearestSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )"
|
|
"( <text>tbtree(tuple ((x1 t1)...(xn tn))"
|
|
" ti) x rel(tuple ((x1 t1)...(xn tn))) x mpoint x k ->"
|
|
" (stream (tuple ((x1 t1)...(xn tn))))"
|
|
"</text--->"
|
|
"<text>_ _ hcknnknearest [_, _, _ ]</text--->"
|
|
"<text>The operator results a stream of all input tuples "
|
|
"which are the k-nearest tupels to the given mpoint. "
|
|
"The operator do not separate tupels if necessary. The "
|
|
"result may have more than the k-nearest tupels. It is a "
|
|
"filter operator for the knearest operator, if there are a great "
|
|
"many input tupels. "
|
|
"The operator expects a tb-tree built on moving objects </text--->"
|
|
"<text>query UnitTrains_UTrip_tbtree UnitTrains chinaknearest"
|
|
"[UTrip,train1, 5] count;</text--->"
|
|
") )";
|
|
|
|
/*
|
|
the same as UReal, but not store a,b,c the distance function
|
|
|
|
*/
|
|
|
|
struct myureal{
|
|
double a,b,c;
|
|
myureal():a(0.0),b(0.0),c(0.0){}
|
|
myureal(double x,double y,double z):a(x),b(y),c(z){}
|
|
myureal(const myureal& u):a(u.a),b(u.b),c(u.c){}
|
|
myureal& operator=(const myureal& u)
|
|
{
|
|
a = u.a;
|
|
b = u.b;
|
|
c = u.c;
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
|
|
/*
|
|
the same as UPoint, but not store p0,p1
|
|
|
|
*/
|
|
struct myupoint{
|
|
Point p0,p1;
|
|
myupoint():p0(true,0,0),p1(true,0,0){}
|
|
myupoint(Point& a,Point& b):p0(a),p1(b){}
|
|
myupoint(const myupoint& u):p0(u.p0),p1(u.p1){}
|
|
myupoint& operator=(const myupoint& u)
|
|
{
|
|
p0 = u.p0;
|
|
p1 = u.p1;
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
/*
|
|
element in Nearestlist, store nodeid, tid, mindist,maxdist, time interval
|
|
|
|
*/
|
|
|
|
struct hpelem{
|
|
myureal movdist;
|
|
// TupleId tid;
|
|
long tid;
|
|
myupoint dataup;
|
|
double mind,maxd;
|
|
long nodeid;
|
|
hpelem* next;
|
|
double nodets,nodete; //absolute value
|
|
bool operator<(const hpelem& e)const
|
|
{
|
|
if(mind < e.mind) return false;
|
|
return true;
|
|
|
|
}
|
|
|
|
hpelem(const hpelem& le)
|
|
:movdist(le.movdist),tid(le.tid),dataup(le.dataup),
|
|
mind(le.mind),maxd(le.maxd),nodeid(le.nodeid),
|
|
next(le.next), nodets(le.nodets),nodete(le.nodete)
|
|
{
|
|
assert(nodets<=nodete);
|
|
}
|
|
|
|
|
|
hpelem(TupleId id1,double d1,double d2,long id2)
|
|
:tid(id1),mind(d1),maxd(d2),nodeid(id2),next(0),
|
|
nodets(0),nodete(0){
|
|
}
|
|
|
|
inline hpelem& operator=(const hpelem& le);
|
|
inline void AssignURUP(UReal* movdist,UPoint* dataup);
|
|
inline void MyTemporalFunction(double& t,Point& result);
|
|
inline void URealMin(double& start);
|
|
inline void URealMax(double& start);
|
|
inline void URealTranslate(double& start);
|
|
};
|
|
|
|
inline hpelem& hpelem::operator=(const hpelem& le)
|
|
{
|
|
tid = le.tid;
|
|
nodeid = le.nodeid;
|
|
mind = le.mind;
|
|
maxd = le.maxd;
|
|
movdist = le.movdist;
|
|
dataup = le.dataup;
|
|
nodets = le.nodets;
|
|
nodete = le.nodete;
|
|
next = NULL;
|
|
return *this;
|
|
}
|
|
|
|
inline void hpelem::AssignURUP(UReal* movdist,UPoint* dataup)
|
|
{
|
|
this->movdist.a = movdist->a;
|
|
this->movdist.b = movdist->b;
|
|
this->movdist.c = movdist->c;
|
|
this->dataup.p0 = dataup->p0;
|
|
this->dataup.p1 = dataup->p1;
|
|
}
|
|
|
|
/*
|
|
The same function as ureal TemporalFunction
|
|
|
|
*/
|
|
inline void hpelem::MyTemporalFunction(double& t,Point& result)
|
|
{
|
|
if(t == this->nodets){
|
|
result = this->dataup.p0;
|
|
result.SetDefined(true);
|
|
return;
|
|
}
|
|
if(t == this->nodete){
|
|
result = this->dataup.p1;
|
|
result.SetDefined(true);
|
|
return;
|
|
}
|
|
Point p0 = this->dataup.p0;
|
|
Point p1 = this->dataup.p1;
|
|
double t0 = this->nodets;
|
|
double t1 = this->nodete;
|
|
double x = (p1.GetX()-p0.GetX())*((t - t0)/(t1-t0)) + p0.GetX();
|
|
double y = (p1.GetY()-p0.GetY())*((t - t0)/(t1-t0)) + p0.GetY();
|
|
result.Set(x,y);
|
|
result.SetDefined(true);
|
|
|
|
}
|
|
|
|
/*
|
|
the same function as Min in UReal
|
|
|
|
*/
|
|
inline void hpelem::URealMin(double& start)
|
|
{
|
|
double a = this->movdist.a;
|
|
double b = this->movdist.b;
|
|
double c = this->movdist.c;
|
|
|
|
double t_start = this->nodets - start;
|
|
double t_end = this->nodete - start;
|
|
double v1 = sqrt(a*t_start*t_start + b*t_start + c);
|
|
double v2 = sqrt(a*t_end*t_end + b*t_end + c);
|
|
double min = v1;
|
|
if(v2 < min)
|
|
min = v2;
|
|
if(AlmostEqual(a,0.0))
|
|
this->mind = min;
|
|
|
|
double asymx = (-1.0*b)/(2*a);
|
|
double v3 = min;
|
|
if(t_start < asymx && asymx < t_end){
|
|
v3 = sqrt(a*asymx*asymx+b*asymx+c);
|
|
if(v3 < min)
|
|
min = v3;
|
|
}
|
|
|
|
this->mind = min;
|
|
}
|
|
|
|
/*
|
|
the same function as Max in UReal
|
|
|
|
*/
|
|
|
|
inline void hpelem::URealMax(double& start)
|
|
{
|
|
double a = this->movdist.a;
|
|
double b = this->movdist.b;
|
|
double c = this->movdist.c;
|
|
double t_start = this->nodets - start;
|
|
double t_end = this->nodete - start;
|
|
|
|
double v1 = sqrt(a*t_start*t_start + b*t_start + c);
|
|
double v2 = sqrt(a*t_end*t_end + b*t_end + c);
|
|
double max = v1;
|
|
if(v2 > max)
|
|
max = v2;
|
|
if(AlmostEqual(a,0.0))
|
|
this->maxd = max;
|
|
|
|
double asymx = (-1.0*b)/(2*a);
|
|
double v3 = 0;
|
|
if(t_start < asymx && asymx < t_end){ //three values
|
|
v3 = sqrt(a*asymx*asymx+b*asymx+c);
|
|
if(v3 > max)
|
|
max = v3;
|
|
}
|
|
this->maxd = max;
|
|
}
|
|
|
|
/*
|
|
translate the start time of parabolas
|
|
|
|
*/
|
|
inline void hpelem::URealTranslate(double& start)
|
|
{
|
|
double b,c;
|
|
double ts = this->nodets - start;
|
|
b = 2*this->movdist.a*ts + this->movdist.b;
|
|
c = this->movdist.c + this->movdist.b*ts + this->movdist.a*ts*ts;
|
|
this->movdist.b = b;
|
|
this->movdist.c = c;
|
|
}
|
|
|
|
|
|
/*
|
|
Nearestlist structure, the top structure, it has k list structure
|
|
|
|
*/
|
|
|
|
struct Nearestlist{
|
|
double mind;
|
|
double maxd;
|
|
hpelem* head;
|
|
double startTime,endTime;
|
|
|
|
Nearestlist(double min,double max,hpelem* p,double s,double e)
|
|
:mind(min),maxd(max),head(p),startTime(s),endTime(e){}
|
|
|
|
Nearestlist(const Nearestlist& nl)
|
|
:mind(nl.mind),maxd(nl.maxd),head(nl.head),
|
|
startTime(nl.startTime),endTime(nl.endTime){}
|
|
};
|
|
|
|
/*
|
|
record prunedist, actuall the max value in nearestlist[k], and time
|
|
|
|
*/
|
|
|
|
struct Prunedist{
|
|
double dist;
|
|
double ts,te;
|
|
bool define;
|
|
Prunedist():dist(0),ts(0),te(0),define(false){}
|
|
};
|
|
|
|
/*
|
|
main structur for chinese and greece knn algorithm
|
|
|
|
*/
|
|
|
|
struct TBKnearestLocalInfo
|
|
{
|
|
unsigned int k;
|
|
unsigned int attrpos;
|
|
bool scanFlag;
|
|
Relation* relation;
|
|
tbtree::TBTree* tbtree;
|
|
R_Tree<3,TupleId>* rtree;
|
|
double startTime,endTime;
|
|
Line* mptraj;
|
|
CIC<double>* ci;//detect a time interval is fully covered
|
|
bool iscovered; //used to detect time interval in Nearest_list
|
|
std::vector<Nearestlist> nlist;//main structure for pruning and record results
|
|
Prunedist prunedist;
|
|
BBox<2> mpbox;
|
|
std::priority_queue<hpelem> hp;
|
|
std::vector<hpelem> result;
|
|
unsigned int counter;
|
|
CoverInterval<double>* cic;
|
|
|
|
|
|
TBKnearestLocalInfo(unsigned int nn):k(nn)
|
|
{
|
|
ci = NULL;
|
|
cic = NULL;
|
|
mptraj = NULL;
|
|
iscovered = false;
|
|
}
|
|
~TBKnearestLocalInfo()
|
|
{
|
|
if( ci != NULL)
|
|
delete ci;
|
|
if( cic != NULL)
|
|
delete cic;
|
|
if(mptraj != NULL)
|
|
delete mptraj;
|
|
}
|
|
/*public function*/
|
|
void UpdateInfoInNL(hpelem* elem,int i);
|
|
void ReportResult();
|
|
void ParabolasTM(hpelem& elem,std::vector<hpelem>& nextupdatelist,int i,
|
|
hpelem*& head,hpelem*& cur,double& intersect,
|
|
double& elemstart,double& curstart);
|
|
void ParabolasMT(hpelem& elem,std::vector<hpelem>& nextupdatelist,int i,
|
|
hpelem*& head,hpelem*& cur,double& intersect,
|
|
double& elemstart,double& curstart);
|
|
void Parabolas(hpelem& elem,std::vector<hpelem>& nextupdatelist,int i,
|
|
hpelem*& head,hpelem*& cur,double& elemstart,
|
|
double& curstart);
|
|
void UpdateNearest(hpelem& elem,std::vector<hpelem>& nextupdatelist,int i);
|
|
/*Greece algorithm function*/
|
|
bool CheckPrune(hpelem& elem);
|
|
void GreeceknnFunDF(MPoint* mp,int level,hpelem& elem);
|
|
void GreeceknnFunBF(MPoint* mp,int level,hpelem& elem);
|
|
void UpdatekNearestG(hpelem& elem);
|
|
void GreeceknearestInitialize(MPoint* mp);
|
|
void CheckCoveredG(hpelem& elem);
|
|
/*Chinese algorithm function*/
|
|
void ChinaknnInitialize(MPoint* mp);
|
|
void ChinaknnFun(MPoint* mp);
|
|
void UpdatekNearest(hpelem& elem);
|
|
void InitializePrunedist();
|
|
void CheckCovered(hpelem& elem);
|
|
};
|
|
/*
|
|
Initialization, knearestlist prunedist
|
|
|
|
*/
|
|
void TBKnearestLocalInfo::ChinaknnInitialize(MPoint* mp)
|
|
{
|
|
|
|
//Initialization NearestList and prunedist
|
|
for(unsigned int i = 0;i < k;i++){
|
|
double mind = std::numeric_limits<double>::max();
|
|
double maxd = std::numeric_limits<double>::min();
|
|
double st = startTime;
|
|
double et = startTime;
|
|
Nearestlist nl(mind,maxd,new hpelem(-1,0,0,-1),st,et);
|
|
nlist.push_back(nl);
|
|
}
|
|
|
|
prunedist.dist = std::numeric_limits<double>::max();
|
|
prunedist.define = false;
|
|
|
|
|
|
SmiRecordId adr = tbtree->getRootId();
|
|
tbtree::BasicNode<3>* root = tbtree->getNode(adr);
|
|
|
|
double t1((double)root->getBox().MinD(2));
|
|
double t2((double)root->getBox().MaxD(2));
|
|
if(!(t1 >= endTime || t2 <= startTime)) { // root covers time interval
|
|
Line* line = new Line(0);
|
|
mp->Trajectory(*line);
|
|
mptraj = new Line(*line);
|
|
delete line;
|
|
tbtree::InnerNode<3,tbtree::InnerInfo>* innernode =
|
|
dynamic_cast<tbtree::InnerNode<3,tbtree::InnerInfo>*>(root);
|
|
//insert all the entries of the root into hp
|
|
for(unsigned int i = 0;i < innernode->entryCount();i++){
|
|
const tbtree::Entry<3,tbtree::InnerInfo>* entry
|
|
= innernode->getEntry(i);
|
|
double tt1((double)entry->getBox().MinD(2));
|
|
double tt2((double)entry->getBox().MaxD(2));
|
|
if(!(tt1 >= endTime || tt2 <= startTime)){
|
|
BBox<2> entrybox = makexyBox(entry->getBox());//entry box
|
|
double mindist = mptraj->Distance(entrybox);
|
|
double maxdist = std::numeric_limits<double>::max();
|
|
hpelem le(-1,mindist,maxdist,entry->getInfo().getPointer());
|
|
le.nodets = tt1;
|
|
le.nodete = tt2;
|
|
hp.push(le);
|
|
}
|
|
}
|
|
}
|
|
delete root;
|
|
}
|
|
/*
|
|
Interpolate for between data entry and query entry
|
|
|
|
*/
|
|
|
|
void CreateUPoint_ne(const UPoint* up,UPoint*& ne,UPoint* data)
|
|
{
|
|
|
|
Instant start;
|
|
Instant end;
|
|
Point p0,p1;
|
|
|
|
if(data->timeInterval.start > up->timeInterval.start){
|
|
start = data->timeInterval.start;
|
|
p0 = data->p0;
|
|
}
|
|
else{
|
|
start = up->timeInterval.start;
|
|
data->TemporalFunction(start,p0,true);
|
|
}
|
|
if(data->timeInterval.end < up->timeInterval.end){
|
|
end = data->timeInterval.end;
|
|
p1 = data->p1;
|
|
}
|
|
else{
|
|
end = up->timeInterval.end;
|
|
data->TemporalFunction(end,p1,true);
|
|
}
|
|
ne->timeInterval.start = start;
|
|
ne->timeInterval.end = end;
|
|
ne->p0 = p0;
|
|
ne->p1 = p1;
|
|
|
|
}
|
|
/*
|
|
Interpolate for entry in MQ, split entries
|
|
|
|
*/
|
|
|
|
|
|
void CreateUPoint_nqe(const UPoint* up,UPoint*& nqe,UPoint* data)
|
|
{
|
|
Instant start;
|
|
Instant end;
|
|
Point p0,p1;
|
|
|
|
if(data->timeInterval.start > up->timeInterval.start){
|
|
start = data->timeInterval.start;
|
|
up->TemporalFunction(start,p0,true);
|
|
}
|
|
else{
|
|
start = up->timeInterval.start;
|
|
p0 = up->p0;
|
|
}
|
|
if(data->timeInterval.end < up->timeInterval.end){
|
|
end = data->timeInterval.end;
|
|
up->TemporalFunction(end,p1,true);
|
|
}
|
|
else{
|
|
end = up->timeInterval.end;
|
|
p1 = up->p1;
|
|
}
|
|
nqe->timeInterval.start = start;
|
|
nqe->timeInterval.end = end;
|
|
nqe->p0 = p0;
|
|
nqe->p1 = p1;
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
Update information in each NearestList, mind,maxd, startTime,endTime
|
|
after each new elem is inserted
|
|
|
|
*/
|
|
void TBKnearestLocalInfo::UpdateInfoInNL(hpelem* elem,int i)
|
|
{
|
|
if(elem->mind < nlist[i].mind)
|
|
nlist[i].mind = elem->mind;
|
|
if(elem->maxd > nlist[i].maxd)
|
|
nlist[i].maxd = elem->maxd;
|
|
if(elem->nodets < nlist[i].startTime)
|
|
nlist[i].startTime = elem->nodets;
|
|
if(elem->nodete > nlist[i].endTime)
|
|
nlist[i].endTime = elem->nodete;
|
|
|
|
//update prune_dist here
|
|
if(elem->nodets > prunedist.te ||
|
|
elem->nodete < prunedist.ts){ //time interval disjoint
|
|
if(elem->maxd > prunedist.dist){
|
|
prunedist.dist = elem->maxd;
|
|
prunedist.ts = elem->nodets;
|
|
prunedist.te = elem->nodete;
|
|
}
|
|
}else{
|
|
hpelem* head = nlist[k-1].head;
|
|
hpelem* cur = head->next;
|
|
hpelem* bigelem;
|
|
if(cur != NULL){
|
|
double max = cur->maxd;
|
|
bigelem = cur;
|
|
while(cur != NULL){
|
|
if(cur->maxd > max){
|
|
max = cur->maxd;
|
|
bigelem = cur;
|
|
}
|
|
cur = cur->next;
|
|
}
|
|
prunedist.dist = max;
|
|
prunedist.ts = bigelem->nodets;
|
|
prunedist.te = bigelem->nodete;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
interpolation parabolas
|
|
entry unit (in list) is first smaller than data (new elem), and then new
|
|
elem is smaller than entry (the one already stored in Nearestlist)
|
|
T is smaller first
|
|
|
|
*/
|
|
|
|
|
|
void TBKnearestLocalInfo::ParabolasTM(hpelem& elem
|
|
,std::vector<hpelem>& nextupdatelist,int i,hpelem*& head,hpelem*& cur,
|
|
double& intersect,double& elemstart,double& curstart)
|
|
{
|
|
|
|
hpelem* newelem1 = new hpelem(*cur);
|
|
newelem1->nodets = intersect;
|
|
Point start;
|
|
|
|
newelem1->MyTemporalFunction(intersect,start);
|
|
newelem1->dataup.p0 = start;
|
|
newelem1->next= NULL;
|
|
newelem1->URealMin(curstart);
|
|
newelem1->URealMax(curstart);
|
|
newelem1->URealTranslate(curstart);
|
|
|
|
cur->nodete = intersect;
|
|
Point end;
|
|
|
|
cur->MyTemporalFunction(intersect,end);
|
|
cur->dataup.p1 = end;
|
|
cur->URealMin(curstart);
|
|
cur->URealMax(curstart);
|
|
|
|
hpelem* newelem2 = new hpelem(elem);
|
|
newelem2->nodete = intersect;
|
|
|
|
newelem2->MyTemporalFunction(intersect,end);
|
|
newelem2->dataup.p1 = end;
|
|
newelem2->URealMin(elemstart);
|
|
newelem2->URealMax(elemstart);
|
|
|
|
nextupdatelist.push_back(*newelem1);
|
|
nextupdatelist.push_back(*newelem2);
|
|
|
|
delete newelem1;
|
|
delete newelem2;
|
|
|
|
|
|
hpelem* newelem3 = new hpelem(elem);
|
|
newelem3->nodets = intersect;
|
|
|
|
newelem3->MyTemporalFunction(intersect,start);
|
|
newelem3->dataup.p0 = start;
|
|
newelem3->next = cur->next;
|
|
|
|
|
|
cur->next = newelem3;
|
|
////////////////////////////////////
|
|
head = cur;
|
|
cur = newelem3;
|
|
////////////////////////////////
|
|
newelem3->URealMin(elemstart);
|
|
newelem3->URealMax(elemstart);
|
|
newelem3->URealTranslate(elemstart);
|
|
|
|
UpdateInfoInNL(cur,i);
|
|
UpdateInfoInNL(newelem3,i);
|
|
}
|
|
/*
|
|
interpolation parabolas
|
|
entry unit (in list) is first larger than data (new elem), and then new
|
|
elem is larger than entry (the one already stored in Nearestlist)
|
|
M is smaller first
|
|
|
|
*/
|
|
|
|
void TBKnearestLocalInfo::ParabolasMT(hpelem& elem
|
|
,std::vector<hpelem>& nextupdatelist,int i,hpelem*& head,hpelem*& cur,
|
|
double& intersect,double& elemstart,double& curstart)
|
|
{
|
|
|
|
Point end;
|
|
hpelem* newelem1 = new hpelem(elem);
|
|
|
|
newelem1->nodete = intersect;
|
|
|
|
newelem1->MyTemporalFunction(intersect,end);
|
|
newelem1->dataup.p1 = end;
|
|
newelem1->next = NULL;
|
|
newelem1->URealMin(elemstart);
|
|
newelem1->URealMax(elemstart);
|
|
|
|
hpelem* newelem2 = new hpelem(*cur);
|
|
|
|
newelem2->nodete = intersect;
|
|
|
|
newelem2->MyTemporalFunction(intersect,end);
|
|
newelem2->dataup.p1 = end;
|
|
newelem2->next= NULL;
|
|
newelem2->URealMin(curstart);
|
|
newelem2->URealMax(curstart);
|
|
|
|
|
|
cur->nodets = intersect;
|
|
Point start;
|
|
|
|
cur->MyTemporalFunction(intersect,start);
|
|
cur->dataup.p0 = start;
|
|
cur->URealMin(curstart);
|
|
cur->URealMax(curstart);
|
|
cur->URealTranslate(curstart);
|
|
|
|
|
|
|
|
head->next = newelem1;
|
|
newelem1->next = cur;
|
|
///////////////////////
|
|
head = newelem1;
|
|
////////////////////////
|
|
|
|
UpdateInfoInNL(newelem1,i);
|
|
UpdateInfoInNL(cur,i);
|
|
|
|
|
|
hpelem* newelem3 = new hpelem(elem);
|
|
|
|
newelem3->nodets = intersect;
|
|
|
|
newelem3->MyTemporalFunction(intersect,start);
|
|
newelem3->dataup.p0 = start;
|
|
newelem3->next = NULL;
|
|
newelem3->URealMin(elemstart);
|
|
newelem3->URealMax(elemstart);
|
|
newelem3->URealTranslate(elemstart);
|
|
|
|
|
|
nextupdatelist.push_back(*newelem2);
|
|
nextupdatelist.push_back(*newelem3);
|
|
|
|
delete newelem2;
|
|
delete newelem3;
|
|
}
|
|
|
|
/*
|
|
Process different splitting cases of parabolas
|
|
restrict to the same time interval and check whether the moving distance
|
|
function has to be split or not
|
|
|
|
*/
|
|
|
|
void TBKnearestLocalInfo::Parabolas(hpelem& elem
|
|
,std::vector<hpelem>& nextupdatelist,int i,hpelem*& head,hpelem*& cur,
|
|
double& elemstart,double& curstart)
|
|
{
|
|
// printf("%.12f %.12f\n",elem.nodets,elem.nodete);
|
|
// printf("%.12f %.12f\n",cur->nodets,cur->nodete);
|
|
// double factor = 0.000000001;
|
|
double ma,mb,mc; //data
|
|
double ta,tb,tc; //entry in list
|
|
double ttelem = elemstart;
|
|
double ttcur = curstart;
|
|
|
|
//a1(t-t1)*(t-t1) + b1(t-t1) + c1
|
|
//a2(t-t2)*(t-t2) + b2(t-t2) + c2
|
|
|
|
ma = elem.movdist.a;
|
|
mb = elem.movdist.b - 2*ma*ttelem;
|
|
mc = elem.movdist.c + ma*ttelem*ttelem- mb*ttelem;
|
|
ta = cur->movdist.a;
|
|
tb = cur->movdist.b - 2*ta*ttcur;
|
|
tc = cur->movdist.c + ta*ttcur*ttcur - tb*ttcur;
|
|
|
|
|
|
double start_m,start_t;
|
|
if(AlmostEqual(ttelem, elem.nodets)){
|
|
// if(fabs(ttelem- elem.nodets) < factor){
|
|
start_m = sqrt(elem.movdist.c);
|
|
}
|
|
else{
|
|
double delta_m = elem.nodets-elemstart;
|
|
start_m =
|
|
sqrt(ma*delta_m*delta_m + elem.movdist.b*delta_m + elem.movdist.c);
|
|
}
|
|
|
|
|
|
if(AlmostEqual(ttcur, cur->nodets)){
|
|
// if(fabs(ttcur - cur->nodets) < factor){
|
|
start_t = sqrt(cur->movdist.c);
|
|
}
|
|
else{
|
|
|
|
double delta_t = cur->nodets-curstart;
|
|
start_t =
|
|
sqrt(ta*delta_t*delta_t + cur->movdist.b*delta_t + cur->movdist.c);
|
|
}
|
|
|
|
if(AlmostEqual(ma ,ta ) && AlmostEqual(mb ,tb) && AlmostEqual(mc ,tc)){
|
|
// if(fabs(ma -ta ) < factor && fabs(mb-tb) < factor && fabs(mc -tc)<factor){
|
|
|
|
nextupdatelist.push_back(elem);
|
|
return;//for next
|
|
}
|
|
|
|
if(AlmostEqual(ma, ta) && AlmostEqual(mb ,tb)){
|
|
// if(fabs(ma - ta) < factor && fabs(mb - tb)< factor ){
|
|
if(start_t <= start_m){
|
|
|
|
nextupdatelist.push_back(elem);
|
|
return;
|
|
}else{// entry is to be replaced by data
|
|
|
|
hpelem* temppointer = cur->next;
|
|
UpdateInfoInNL(&elem,i);
|
|
cur->next = NULL;
|
|
nextupdatelist.push_back(*cur);
|
|
*cur = elem;
|
|
cur->next = temppointer;
|
|
return;
|
|
}
|
|
}
|
|
|
|
if(AlmostEqual(ma ,ta)){
|
|
// if(fabs(ma -ta) < factor){
|
|
assert(mb != tb);
|
|
double v1 = elem.nodets;
|
|
double v2 = elem.nodete;
|
|
|
|
//double time_m,time_t; //start time for cur and elem
|
|
//time_m = ttelem;//real start time
|
|
//time_t = ttcur; //real start time
|
|
double t = (tc-mc)/(mb-tb);
|
|
|
|
if(v1 >= t || t >= v2){ //intersection point is no use
|
|
if(start_t <= start_m){
|
|
|
|
nextupdatelist.push_back(elem);
|
|
return;//for next
|
|
}else{ //entry is to be replaced by data
|
|
|
|
hpelem* temppointer = cur->next;
|
|
UpdateInfoInNL(&elem,i);
|
|
cur->next = NULL;
|
|
nextupdatelist.push_back(*cur);
|
|
*cur = elem;
|
|
cur->next = temppointer;
|
|
return;
|
|
}
|
|
}else{ //needs to be interpolation
|
|
double intersect = t;
|
|
|
|
if(start_t <= start_m){
|
|
ParabolasTM(elem,nextupdatelist,i,head,cur,
|
|
intersect,elemstart,curstart);
|
|
return;
|
|
}else{ //
|
|
ParabolasMT(elem,nextupdatelist,i,head,cur,
|
|
intersect,elemstart,curstart);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
//a is not equal to a'
|
|
double mind_m = start_m;
|
|
double mind_t = start_t;
|
|
|
|
//double time_m,time_t; //start time for cur and elem
|
|
//time_m = ttelem;//real start time
|
|
//time_t = ttcur; //real start time
|
|
|
|
double delta_a = ma-ta;
|
|
double delta_b = mb-tb;
|
|
double delta_c = mc-tc;
|
|
double delta = delta_b*delta_b - 4*delta_a*delta_c;
|
|
|
|
if(fabs(delta) < 0.001){
|
|
if(mind_t <= mind_m){
|
|
|
|
nextupdatelist.push_back(elem);
|
|
return;
|
|
}else{ //entry is to be replaced by data
|
|
|
|
hpelem* temppointer = cur->next;
|
|
UpdateInfoInNL(&elem,i);
|
|
cur->next = NULL;
|
|
nextupdatelist.push_back(*cur);
|
|
*cur = elem;
|
|
cur->next = temppointer;
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
if(delta < 0) { //no intersects
|
|
if(mind_t <= mind_m){
|
|
|
|
nextupdatelist.push_back(elem);
|
|
return;
|
|
}else{ //entry is to be replaced by data
|
|
hpelem* temppointer = cur->next;
|
|
|
|
UpdateInfoInNL(&elem,i);
|
|
cur->next = NULL;
|
|
nextupdatelist.push_back(*cur);
|
|
*cur = elem;
|
|
cur->next = temppointer;
|
|
return;
|
|
}
|
|
}
|
|
//delta > 0
|
|
double x1 = (-delta_b-sqrt(delta))/(2*delta_a);
|
|
double x2 = (-delta_b+sqrt(delta))/(2*delta_a);
|
|
double intersect_t1,intersect_t2;
|
|
|
|
if(x1 < x2){
|
|
intersect_t1 = x1;
|
|
intersect_t2 = x2;
|
|
}else{
|
|
intersect_t1 = x2;
|
|
intersect_t2 = x1;
|
|
}
|
|
double intersect1 = intersect_t1;
|
|
double intersect2 = intersect_t2;
|
|
|
|
|
|
double elemts = elem.nodets;
|
|
double elemte = elem.nodete;
|
|
|
|
//intersection is no use
|
|
|
|
if(intersect_t2 <= elemts ||
|
|
intersect_t1 >= elemte ||
|
|
(intersect_t1 <= elemts&&
|
|
intersect_t2 >= elemte)){
|
|
|
|
if(mind_t <= mind_m){//entry is smaller
|
|
|
|
nextupdatelist.push_back(elem);
|
|
return;
|
|
}else{ //entry is to be replaced by data
|
|
|
|
|
|
hpelem* temppointer = cur->next;
|
|
UpdateInfoInNL(&elem,i);
|
|
cur->next = NULL;
|
|
nextupdatelist.push_back(*cur);
|
|
*cur = elem;
|
|
cur->next = temppointer;
|
|
return;
|
|
}
|
|
}
|
|
//one intersection point
|
|
|
|
if(intersect_t1 > elemts &&
|
|
intersect_t1 < elemte&&
|
|
intersect_t2 > elemte){
|
|
if(start_t <= start_m){
|
|
ParabolasTM(elem,nextupdatelist,i,head,cur,
|
|
intersect1,elemstart,curstart);
|
|
return;
|
|
}else{ //
|
|
ParabolasMT(elem,nextupdatelist,i,head,cur,
|
|
intersect1,elemstart,curstart);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if(intersect_t1 < elemts &&
|
|
intersect_t2 > elemts &&
|
|
intersect_t2 < elemte){
|
|
|
|
if(start_t <= start_m){
|
|
ParabolasTM(elem,nextupdatelist,i,head,cur,
|
|
intersect2,elemstart,curstart);
|
|
return;
|
|
}else{ //
|
|
ParabolasMT(elem,nextupdatelist,i,head,cur,
|
|
intersect2,elemstart,curstart);
|
|
return;
|
|
}
|
|
}
|
|
//two intersection points
|
|
//six sub parts
|
|
if(start_t <= start_m){
|
|
|
|
hpelem* next = cur->next;
|
|
Point start, end;
|
|
Point p0,p1;
|
|
|
|
hpelem* newhp1 = new hpelem(*cur);
|
|
newhp1->nodete = intersect1;
|
|
|
|
newhp1->MyTemporalFunction(intersect1,end);
|
|
newhp1->dataup.p1 = end;
|
|
newhp1->URealMin(curstart);
|
|
newhp1->URealMax(curstart);
|
|
|
|
|
|
hpelem* newhp2 = new hpelem(elem);
|
|
newhp2->nodets = intersect1;
|
|
newhp2->nodete = intersect2;
|
|
|
|
newhp2->MyTemporalFunction(intersect1,p0);
|
|
newhp2->MyTemporalFunction(intersect2,p1);
|
|
newhp2->dataup.p0 = p0;
|
|
newhp2->dataup.p1 = p1;
|
|
newhp2->URealMin(elemstart);
|
|
newhp2->URealMax(elemstart);
|
|
newhp2->URealTranslate(elemstart);
|
|
|
|
|
|
|
|
hpelem* newhp3 = new hpelem(*cur);
|
|
newhp3->nodets = intersect2;
|
|
|
|
newhp3->MyTemporalFunction(intersect2,start);
|
|
newhp3->dataup.p0 = start;
|
|
newhp3->URealMin(curstart);
|
|
newhp3->URealMax(curstart);
|
|
newhp3->URealTranslate(curstart);
|
|
|
|
|
|
|
|
hpelem* newhp4 = new hpelem(elem);
|
|
newhp4->nodete = intersect1;
|
|
|
|
newhp4->MyTemporalFunction(intersect1,end);
|
|
newhp4->dataup.p1 = end;
|
|
newhp4->next = NULL;
|
|
newhp4->URealMin(elemstart);
|
|
newhp4->URealMax(elemstart);
|
|
|
|
|
|
|
|
hpelem* newhp5 = new hpelem(*(cur));
|
|
newhp5->nodets = intersect1;
|
|
newhp5->nodete = intersect2;
|
|
|
|
newhp5->MyTemporalFunction(intersect1,p0);
|
|
newhp5->MyTemporalFunction(intersect2,p1);
|
|
newhp5->dataup.p0 = p0;
|
|
newhp5->dataup.p1 = p1;
|
|
newhp5->next = NULL;
|
|
newhp5->URealMin(curstart);
|
|
newhp5->URealMax(curstart);
|
|
newhp5->URealTranslate(curstart);
|
|
|
|
|
|
|
|
hpelem* newhp6 = new hpelem(elem);
|
|
newhp6->nodets = intersect2;
|
|
|
|
newhp6->MyTemporalFunction(intersect2,start);
|
|
newhp6->dataup.p0 = start;
|
|
newhp6->next = NULL;
|
|
newhp6->URealMin(elemstart);
|
|
newhp6->URealMax(elemstart);
|
|
newhp6->URealTranslate(elemstart);
|
|
|
|
|
|
head->next = newhp1;
|
|
newhp1->next = newhp2;
|
|
newhp2->next = newhp3;
|
|
newhp3->next = next;
|
|
|
|
UpdateInfoInNL(newhp2,i);
|
|
head = newhp2;
|
|
cur = newhp3;
|
|
|
|
|
|
nextupdatelist.push_back(*newhp4);
|
|
nextupdatelist.push_back(*newhp5);
|
|
nextupdatelist.push_back(*newhp6);
|
|
|
|
return;
|
|
}else{
|
|
|
|
hpelem* next = cur->next;
|
|
Point start, end;
|
|
Point p0,p1;
|
|
|
|
hpelem* newhp1 = new hpelem(elem);
|
|
newhp1->nodete = intersect1;
|
|
|
|
newhp1->MyTemporalFunction(intersect1,end);
|
|
newhp1->dataup.p1 = end;
|
|
newhp1->next = NULL;
|
|
newhp1->URealMin(elemstart);
|
|
newhp1->URealMax(elemstart);
|
|
|
|
|
|
hpelem* newhp2 = new hpelem(*(cur));
|
|
newhp2->nodets = intersect1;
|
|
newhp2->nodete = intersect2;
|
|
|
|
newhp2->MyTemporalFunction(intersect1,p0);
|
|
newhp2->MyTemporalFunction(intersect2,p1);
|
|
newhp2->dataup.p0 = p0;
|
|
newhp2->dataup.p1 = p1;
|
|
newhp2->next = NULL;
|
|
newhp2->URealMin(curstart);
|
|
newhp2->URealMax(curstart);
|
|
newhp2->URealTranslate(curstart);
|
|
|
|
|
|
hpelem* newhp3 = new hpelem(elem);
|
|
newhp3->nodets = intersect2;
|
|
|
|
newhp3->MyTemporalFunction(intersect2,start);
|
|
newhp3->dataup.p0 = start;
|
|
newhp3->next = NULL;
|
|
newhp3->URealMin(elemstart);
|
|
newhp3->URealMax(elemstart);
|
|
newhp3->URealTranslate(elemstart);
|
|
|
|
|
|
hpelem* newhp4 = new hpelem(*cur);
|
|
newhp4->nodete = intersect1;
|
|
|
|
newhp4->MyTemporalFunction(intersect1,end);
|
|
newhp4->dataup.p1 = end;
|
|
newhp4->URealMin(curstart);
|
|
newhp4->URealMax(curstart);
|
|
|
|
|
|
hpelem* newhp5 = new hpelem(elem);
|
|
newhp5->nodets = intersect1;
|
|
newhp5->nodete = intersect2;
|
|
|
|
newhp5->MyTemporalFunction(intersect1,p0);
|
|
newhp5->MyTemporalFunction(intersect2,p1);
|
|
newhp5->dataup.p0 = p0;
|
|
newhp5->dataup.p1 = p1;
|
|
newhp5->URealMin(elemstart);
|
|
newhp5->URealMax(elemstart);
|
|
newhp5->URealTranslate(elemstart);
|
|
|
|
|
|
hpelem* newhp6 = new hpelem(*cur);
|
|
newhp6->nodets = intersect2;
|
|
|
|
newhp6->MyTemporalFunction(intersect2,start);
|
|
newhp6->dataup.p0 = start;
|
|
newhp6->URealMin(curstart);
|
|
newhp6->URealMax(curstart);
|
|
newhp6->URealTranslate(curstart);
|
|
|
|
|
|
head->next = newhp1;
|
|
newhp1->next = newhp2;
|
|
newhp2->next = newhp3;
|
|
newhp3->next = next;
|
|
|
|
UpdateInfoInNL(newhp2,i);
|
|
head = newhp2;
|
|
cur = newhp3;
|
|
|
|
|
|
nextupdatelist.push_back(*newhp4);
|
|
nextupdatelist.push_back(*newhp5);
|
|
nextupdatelist.push_back(*newhp6);
|
|
return;
|
|
}
|
|
|
|
}
|
|
/*
|
|
Update k NearestList structure traverse the k nearest list
|
|
|
|
*/
|
|
|
|
void TBKnearestLocalInfo::UpdateNearest(hpelem& elem,
|
|
std::vector<hpelem>& nextupdatelist,int i)
|
|
{
|
|
|
|
double factor = 0.000000001;
|
|
hpelem* head = nlist[i].head;
|
|
assert(head != NULL);
|
|
hpelem* cur = head->next;
|
|
|
|
if(cur == NULL){
|
|
|
|
hpelem* newhp = new hpelem(elem);
|
|
head->next = newhp;
|
|
newhp->next = NULL;
|
|
nlist[i].mind = elem.mind;
|
|
nlist[i].maxd = elem.maxd;
|
|
|
|
nlist[i].startTime = elem.nodets;
|
|
nlist[i].endTime = elem.nodete;
|
|
|
|
return;
|
|
}else{
|
|
//the first elem
|
|
if(elem.nodete <= cur->nodets){
|
|
hpelem* newhp = new hpelem(elem);
|
|
head->next = newhp;
|
|
newhp->next = cur;
|
|
UpdateInfoInNL(newhp,i);
|
|
return;// no update list
|
|
}
|
|
while(cur != NULL){ //big program
|
|
|
|
if(cur->nodete <= elem.nodets){
|
|
if(cur->next == NULL){//the last element
|
|
hpelem* newhp = new hpelem(elem);
|
|
cur->next = newhp;
|
|
newhp->next = NULL;
|
|
UpdateInfoInNL(newhp,i);
|
|
return;// no update list
|
|
}else{
|
|
head = cur;
|
|
cur = cur->next;
|
|
continue;
|
|
}
|
|
}
|
|
if(head->tid != -1 && //not the head element
|
|
head->nodete <= elem.nodets && elem.nodete <= cur->nodets){
|
|
hpelem* newhp = new hpelem(elem);
|
|
head->next = newhp;
|
|
newhp->next = cur;
|
|
UpdateInfoInNL(newhp,i);
|
|
return;//no updatelist
|
|
}
|
|
if(elem.nodete < cur->nodets ||elem.nodets > cur->nodete){
|
|
head = cur;
|
|
cur = cur->next;
|
|
continue;
|
|
}
|
|
|
|
double mts = elem.nodets;
|
|
double mte = elem.nodete;
|
|
double tts = cur->nodets;
|
|
double tte = cur->nodete;
|
|
|
|
if(AlmostEqual(mts ,tts) && AlmostEqual(mte ,tte)){
|
|
// if(fabs(mts -tts) < factor && fabs(mte -tte) < factor){
|
|
mts = mts > tts ? mts:tts;
|
|
mte = mte < tte ? mte:tte;
|
|
if(mts > mte){
|
|
head = cur;
|
|
cur = cur->next;
|
|
continue;
|
|
}
|
|
elem.nodets = cur->nodets = mts;
|
|
elem.nodete = cur->nodete = mte;
|
|
|
|
//magic thing double not equal to double, but almost equal,split
|
|
/*if(elem.nodets < cur->nodets){
|
|
cur->nodets = elem.nodets;
|
|
tts = mts;
|
|
}else{
|
|
elem.nodets = cur->nodets;
|
|
mts = tts;
|
|
}
|
|
if(elem.nodete > cur->nodete){
|
|
cur->nodete = elem.nodete;
|
|
tte = mte;
|
|
}else{
|
|
elem.nodete = cur->nodete;
|
|
mte = tte;
|
|
}*/
|
|
|
|
elem.nodets = cur->nodets;
|
|
elem.nodete = cur->nodete;
|
|
|
|
mts = tts;
|
|
|
|
Parabolas(elem,nextupdatelist,i,head,cur,mts,tts);
|
|
return;
|
|
}else{// needs to be interpolation
|
|
|
|
//overlap
|
|
|
|
double ts = mts > tts ? mts:tts;
|
|
double te = mte < tte ? mte:tte;
|
|
|
|
if(mts < ts){
|
|
|
|
hpelem* newhp = new hpelem(elem);
|
|
newhp->nodete = ts;
|
|
|
|
Point end;
|
|
newhp->MyTemporalFunction(ts,end);
|
|
newhp->dataup.p1 = end;
|
|
|
|
newhp->URealMin(mts);
|
|
newhp->URealMax(mts);
|
|
|
|
head->next = newhp;
|
|
newhp->next = cur;
|
|
head = newhp;
|
|
|
|
UpdateInfoInNL(newhp,i);
|
|
|
|
elem.nodets = ts;
|
|
Point start;
|
|
|
|
elem.MyTemporalFunction(ts,start);
|
|
elem.dataup.p0 = start;
|
|
elem.URealMin(mts);
|
|
elem.URealMax(mts);
|
|
|
|
elem.URealTranslate(mts);
|
|
|
|
}
|
|
|
|
if(tts < ts){
|
|
|
|
hpelem* newhp = new hpelem(*cur);
|
|
|
|
newhp->nodete = ts;
|
|
Point end;
|
|
|
|
newhp->MyTemporalFunction(ts,end);
|
|
newhp->dataup.p1 = end;
|
|
newhp->URealMin(tts);
|
|
newhp->URealMax(tts);
|
|
|
|
|
|
head->next = newhp;
|
|
newhp->next = cur;
|
|
head = newhp;
|
|
|
|
cur->nodets = ts;
|
|
Point start;
|
|
|
|
cur->MyTemporalFunction(ts,start);
|
|
cur->dataup.p0 = start;
|
|
cur->URealMin(tts);
|
|
cur->URealMax(tts);
|
|
cur->URealTranslate(tts);
|
|
|
|
|
|
}
|
|
//up to now, cur and elem start at the same time interval
|
|
if(tte > te){ //M is finished here
|
|
|
|
hpelem* newhp = new hpelem(*cur);
|
|
|
|
newhp->nodets = te;
|
|
Point start;
|
|
|
|
newhp->MyTemporalFunction(te,start);
|
|
newhp->dataup.p0 = start;
|
|
newhp->URealMin(ts);
|
|
newhp->URealMax(ts);
|
|
newhp->URealTranslate(ts);
|
|
|
|
|
|
newhp->next = cur->next;
|
|
cur->next = newhp;
|
|
|
|
Point end;
|
|
cur->nodete = te;
|
|
|
|
cur->MyTemporalFunction(te,end);
|
|
cur->dataup.p1 = end;
|
|
cur->URealMin(ts);
|
|
cur->URealMax(ts);
|
|
|
|
|
|
Parabolas(elem,nextupdatelist,i,head,cur,ts,ts);
|
|
return;
|
|
}else{ //M is longer
|
|
|
|
// if(AlmostEqual(elem.nodete ,cur->nodete)){
|
|
if(fabs(elem.nodete - cur->nodete) < factor){
|
|
Parabolas(elem,nextupdatelist,i,head,cur,ts,ts);
|
|
return;
|
|
}else{
|
|
hpelem* newhp = new hpelem(elem);
|
|
|
|
newhp->nodets = te;
|
|
Point start;
|
|
newhp->MyTemporalFunction(te,start);
|
|
newhp->dataup.p0 = start;
|
|
newhp->URealMin(ts);
|
|
newhp->URealMax(ts);
|
|
newhp->URealTranslate(ts);
|
|
|
|
|
|
elem.nodete = te;
|
|
Point end;
|
|
|
|
elem.MyTemporalFunction(te,end);
|
|
elem.dataup.p1 = end;
|
|
elem.URealMin(ts);
|
|
elem.URealMax(ts);
|
|
|
|
Parabolas(elem,nextupdatelist,i,head,cur,ts,ts);
|
|
elem = *newhp;
|
|
|
|
delete newhp;
|
|
|
|
head = cur;
|
|
cur = cur->next;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
} //end big while
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
Check whether a node or entry has to be inserted or not
|
|
traverse the k nearest list
|
|
|
|
*/
|
|
|
|
bool TBKnearestLocalInfo::CheckPrune(hpelem& elem)
|
|
{
|
|
//linear traverse method
|
|
hpelem* head = nlist[k-1].head;
|
|
if(head->next == NULL)
|
|
return false; //not prune
|
|
hpelem* cur = head->next;
|
|
double curts = cur->nodets;
|
|
double curte = cur->nodete;
|
|
|
|
if(curts > elem.nodets)
|
|
return false;
|
|
while(cur != NULL){
|
|
curts = cur->nodets;
|
|
curte = cur->nodete;
|
|
|
|
if(elem.nodets < curts)
|
|
return false;
|
|
|
|
if(elem.nodets >= curte){
|
|
head = cur;
|
|
cur = cur->next;
|
|
continue;
|
|
}
|
|
|
|
if(curts <= elem.nodets && elem.nodete <= curte){
|
|
if(cur->maxd <= elem.mind)
|
|
return true;//prune
|
|
else
|
|
return false;
|
|
}
|
|
|
|
if(curts <= elem.nodets && elem.nodete > curte){
|
|
if(cur->maxd <= elem.mind){
|
|
if(cur->next == NULL)
|
|
return false;
|
|
hpelem* next = cur->next;
|
|
double nextts,nextte;
|
|
while(next != NULL){
|
|
nextts = next->nodets;
|
|
curte = cur->nodete;
|
|
if(nextts > curte) {
|
|
return false;
|
|
}
|
|
|
|
nextte = next->nodete;
|
|
|
|
if(nextte >= elem.nodete && next->maxd < elem.mind) {
|
|
return true;//prune
|
|
}
|
|
|
|
if(nextte < elem.nodete && next->maxd < elem.mind){
|
|
cur = next;
|
|
next = cur->next;
|
|
continue;
|
|
}
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
head = cur;
|
|
cur = cur->next;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
Detect whether the time interval in Nerestlist(k) is full
|
|
|
|
*/
|
|
|
|
void TBKnearestLocalInfo::CheckCovered(hpelem& elem)
|
|
{
|
|
ci->insert(elem.nodets,elem.nodete);
|
|
iscovered = ci->IsCovered();
|
|
}
|
|
|
|
void TBKnearestLocalInfo::CheckCoveredG(hpelem& elem)
|
|
{
|
|
|
|
// ci->insert(elem.nodets,elem.nodete);
|
|
struct CoverNode<double>* n = new CoverNode<double>(elem.nodets,elem.nodete);
|
|
cic->insert(n);
|
|
// iscovered = ci->IsCovered();
|
|
iscovered = cic->IsCovered();
|
|
}
|
|
|
|
/*
|
|
Initialize Prunedist check the maxdist in Nearestlist(k)
|
|
|
|
*/
|
|
|
|
void TBKnearestLocalInfo::InitializePrunedist()
|
|
{
|
|
if(prunedist.define == false && iscovered){
|
|
hpelem* head = nlist[k-1].head;
|
|
hpelem* cur = head->next;
|
|
hpelem* bigelem;
|
|
if(cur != NULL){
|
|
double max = cur->maxd;
|
|
bigelem = cur;
|
|
while(cur != NULL){
|
|
if(cur->maxd > max){
|
|
max = cur->maxd;
|
|
bigelem = cur;
|
|
}
|
|
cur = cur->next;
|
|
}
|
|
prunedist.dist = max;
|
|
prunedist.define = true;
|
|
prunedist.ts = bigelem->nodets;
|
|
prunedist.te = bigelem->nodete;
|
|
}
|
|
// ftime(>2);
|
|
// cout<<difftimeb(>2,>1)<<endl;
|
|
}
|
|
}
|
|
|
|
/*
|
|
Main function, update the k nearest list structure and prunedist
|
|
traverse k nearestlist, and update it
|
|
|
|
*/
|
|
|
|
void TBKnearestLocalInfo::UpdatekNearest(hpelem& elem)
|
|
{
|
|
std::list<hpelem> updatelist;
|
|
|
|
// if(CheckPrune(local,elem) == false){ //faster
|
|
if(elem.mind < prunedist.dist){
|
|
|
|
updatelist.push_back(elem);
|
|
std::vector<hpelem> auxiliarylist;
|
|
std::vector<hpelem> templist;
|
|
for(unsigned int i = 0;i < k;i++){//for each NearestList
|
|
while(updatelist.empty() == false){
|
|
hpelem top = updatelist.front();
|
|
updatelist.pop_front();
|
|
|
|
// if(CheckPrune(local,top) == false) //faster
|
|
if(top.mind < prunedist.dist)
|
|
UpdateNearest(top,templist,i); //key function
|
|
|
|
//check whether the time interval covers
|
|
if(i == k - 1 && iscovered == false)
|
|
CheckCovered(top);
|
|
|
|
for(unsigned int j = 0;j < templist.size();j++)//transfer step1
|
|
auxiliarylist.push_back(templist[j]);
|
|
templist.clear();
|
|
}
|
|
for(unsigned int j = 0;j < auxiliarylist.size();j++)//transfer step2
|
|
updatelist.push_back(auxiliarylist[j]);
|
|
auxiliarylist.clear();
|
|
|
|
if(iscovered && i == k - 1) //check prunedist
|
|
InitializePrunedist();
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
Main function for Greece algorithm,
|
|
update the k nearest list structure and prunedist using
|
|
checkprune function
|
|
|
|
*/
|
|
|
|
void TBKnearestLocalInfo::UpdatekNearestG(hpelem& elem)
|
|
{
|
|
std::list<hpelem> updatelist;
|
|
|
|
// if(elem.mind < prunedist.dist){
|
|
// if(CheckPrune(elem) == false){
|
|
|
|
updatelist.push_back(elem);
|
|
std::vector<hpelem> auxiliarylist;
|
|
std::vector<hpelem> templist;
|
|
for(unsigned int i = 0;i < k;i++){//for each NearestList
|
|
while(updatelist.empty() == false){
|
|
hpelem top = updatelist.front();
|
|
updatelist.pop_front();
|
|
|
|
if(top.mind < prunedist.dist && CheckPrune(top) == false)
|
|
// if(CheckPrune(top) == false)
|
|
UpdateNearest(top,templist,i); //key function
|
|
|
|
if(i == k - 1 && iscovered == false)
|
|
CheckCoveredG(top);
|
|
// CheckCovered(top);
|
|
|
|
for(unsigned int j = 0;j < templist.size();j++)//transfer step1
|
|
auxiliarylist.push_back(templist[j]);
|
|
templist.clear();
|
|
}
|
|
for(unsigned int j = 0;j < auxiliarylist.size();j++)//transfer step2
|
|
updatelist.push_back(auxiliarylist[j]);
|
|
auxiliarylist.clear();
|
|
if(iscovered && i == k - 1) //check prunedist
|
|
InitializePrunedist();
|
|
}
|
|
|
|
// }
|
|
}
|
|
|
|
/*
|
|
element is ordered by start time
|
|
|
|
*/
|
|
bool HpelemCompare(const hpelem& e1,const hpelem& e2)
|
|
{
|
|
return e1.nodets < e2.nodets;
|
|
}
|
|
|
|
/*
|
|
Report result
|
|
|
|
*/
|
|
|
|
void TBKnearestLocalInfo::ReportResult()
|
|
{
|
|
for(unsigned int i = 0; i < k;i++){ //traverse NearestList
|
|
hpelem* head = nlist[i].head;
|
|
hpelem* cur = head->next;
|
|
while(cur != NULL){
|
|
hpelem top = *cur;
|
|
assert(top.tid != -1 && top.nodeid == -1);
|
|
if(top.nodets != top.nodete)
|
|
result.push_back(top);
|
|
delete head;
|
|
head = cur;
|
|
cur = cur->next;
|
|
if(cur == NULL)
|
|
delete head;
|
|
}
|
|
|
|
}
|
|
stable_sort(result.begin(),result.end(),HpelemCompare);
|
|
}
|
|
|
|
|
|
/*
|
|
ChinaknnFun is the value function for the chineseknearest operator
|
|
It is a filter operator for the knearest operator. It can be called
|
|
if there exists an r-tree for the unit attribute
|
|
The main Function of chinese algorithm
|
|
using bf-first method
|
|
for leaf node, try to insert the entry into nearestlist
|
|
at the same time, update the prunedist
|
|
for each new element, using prunedist to check whether it needs to be inserted
|
|
into the heap structure
|
|
|
|
*/
|
|
|
|
void TBKnearestLocalInfo::ChinaknnFun(MPoint* mp)
|
|
{
|
|
BBox<2> mpbox = mptraj->BoundingBox();
|
|
if(mpbox.IsDefined() == false)
|
|
mpbox = makexyBox(mp->BoundingBox());
|
|
|
|
while(hp.empty() == false){
|
|
hpelem top = hp.top();
|
|
hp.pop();
|
|
|
|
if(top.mind > prunedist.dist)
|
|
break;
|
|
if(top.tid != -1 && top.nodeid == -1){ //an actual trajectory segment
|
|
UpdatekNearest(top);
|
|
}
|
|
else if(top.tid == -1 && top.nodeid != -1){ // a node
|
|
tbtree::BasicNode<3>* tbnode = tbtree->getNode(top.nodeid);
|
|
if(tbnode->isLeaf()){ //leaf node
|
|
tbtree::TBLeafNode<3,tbtree::TBLeafInfo>* leafnode =
|
|
dynamic_cast<tbtree::TBLeafNode<3,tbtree::TBLeafInfo>* > (tbnode);
|
|
for(unsigned int i = 0;i < leafnode->entryCount();i++){
|
|
const tbtree::Entry<3,tbtree::TBLeafInfo>* entry =
|
|
leafnode->getEntry(i);
|
|
double t1((double)entry->getBox().MinD(2));
|
|
double t2((double)entry->getBox().MaxD(2));
|
|
if(!(t1 >= endTime || t2 <= startTime)){
|
|
//for each unit in mp
|
|
UPoint up;
|
|
TupleId tid = entry->getInfo().getTupleId();
|
|
Tuple* tuple = this->relation->GetTuple(tid, false);
|
|
UPoint* data = (UPoint*)tuple->GetAttribute(attrpos);
|
|
|
|
for(int j = 0;j < mp->GetNoComponents();j++){
|
|
mp->Get(j,up);
|
|
double tt1 = (double)(up.timeInterval.start.ToDouble());
|
|
double tt2 = (double)(up.timeInterval.end.ToDouble());
|
|
if(tt1 > t2) //mq's time interval is larger than entry
|
|
break;
|
|
if(!(t1 >= tt2 || t2 <= tt1)){
|
|
Point p0(true,0,0);
|
|
Point p1(true,0,0);
|
|
UPoint* ne = new UPoint(up.timeInterval,p0,p1);
|
|
UPoint* nqe = new UPoint(up.timeInterval,p0,p1);
|
|
|
|
//interpolation restrict to the same time interval
|
|
|
|
CreateUPoint_ne(&up,ne,data);
|
|
CreateUPoint_nqe(&up,nqe,data);
|
|
|
|
double nodets = ne->timeInterval.start.ToDouble();
|
|
double nodete = ne->timeInterval.end.ToDouble();
|
|
|
|
if(AlmostEqual(nodets,nodete)){
|
|
delete ne;
|
|
delete nqe;
|
|
continue;
|
|
}
|
|
|
|
UReal* mdist = new UReal(true);
|
|
ne->Distance(*nqe,*mdist);
|
|
bool def = true;
|
|
double mind = mdist->Min(def);
|
|
double maxd = mdist->Max(def);
|
|
|
|
hpelem le(entry->getInfo().getTupleId(),mind,maxd,-1);
|
|
le.nodets = nodets;
|
|
le.nodete = nodete;
|
|
|
|
le.AssignURUP(mdist,ne);
|
|
|
|
if(le.mind < prunedist.dist)
|
|
hp.push(le);
|
|
|
|
delete mdist;
|
|
delete ne;
|
|
delete nqe;
|
|
}
|
|
}//end for
|
|
tuple->DeleteIfAllowed();
|
|
}
|
|
}
|
|
}else{ //inner node
|
|
tbtree::InnerNode<3,tbtree::InnerInfo>* innernode =
|
|
dynamic_cast<tbtree::InnerNode<3,tbtree::InnerInfo>* > (tbnode);
|
|
for(unsigned int i = 0;i < innernode->entryCount();i++){
|
|
const tbtree::Entry<3,tbtree::InnerInfo>* entry
|
|
= innernode->getEntry(i);
|
|
double t1((double)entry->getBox().MinD(2));
|
|
double t2((double)entry->getBox().MaxD(2));
|
|
if(!(t1 >= endTime || t2 <= startTime)){
|
|
BBox<2> entrybox = makexyBox(entry->getBox());//entry box
|
|
double mindist = mpbox.Distance(entrybox);
|
|
double maxdist = maxDistance(entrybox,mpbox);
|
|
|
|
hpelem le(-1,mindist,maxdist,entry->getInfo().getPointer());
|
|
le.nodets = t1;
|
|
le.nodete = t2;
|
|
if(le.mind < prunedist.dist)
|
|
hp.push(le);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ReportResult(); //results are stored in NearestList
|
|
}
|
|
|
|
/*
|
|
Initialization for greeceknearest operator
|
|
1---initialize nearest list structure
|
|
2---boundingbox, prunedist
|
|
|
|
*/
|
|
|
|
void TBKnearestLocalInfo::GreeceknearestInitialize(MPoint* mp)
|
|
{
|
|
//Initialization NearestList and prunedist
|
|
|
|
for(unsigned int i = 0;i < k;i++){
|
|
double mind = std::numeric_limits<double>::max();
|
|
double maxd = std::numeric_limits<double>::min();
|
|
double st = startTime;
|
|
double et = startTime;
|
|
Nearestlist nl(mind,maxd,new hpelem(-1,0,0,-1),st,et);
|
|
nlist.push_back(nl);
|
|
}
|
|
|
|
prunedist.dist = std::numeric_limits<double>::max();
|
|
prunedist.define = false;
|
|
|
|
Line* line = new Line(0);
|
|
mp->Trajectory(*line);
|
|
mptraj = new Line(*line);
|
|
delete line;
|
|
|
|
mpbox = mptraj->BoundingBox();
|
|
if(mpbox.IsDefined() == false)
|
|
mpbox = makexyBox(mp->BoundingBox());
|
|
}
|
|
|
|
/*
|
|
GreeceknnFun is the value function for the greeceknearest operator
|
|
It is a filter operator for the knearest operator. It can be called
|
|
if there exists an r-tree for the unit attribute
|
|
The argument vector contains the following values:
|
|
args[0] = an r-tree with the unit attribute as key
|
|
args[1] = the relation of the r-tree
|
|
args[2] = attribute UPoint
|
|
args[3] = mpoint
|
|
args[4] = int k, how many nearest are searched
|
|
|
|
*/
|
|
struct idtime{
|
|
long id;
|
|
double ts;
|
|
idtime(long a,double time):id(a),ts(time){}
|
|
idtime(const idtime& idt):id(idt.id),ts(idt.ts){}
|
|
bool operator<(const idtime& idt2) const
|
|
{
|
|
return ts < idt2.ts;
|
|
}
|
|
};
|
|
|
|
void TBKnearestLocalInfo::GreeceknnFunBF(MPoint* mp,int level,hpelem& elem)
|
|
{
|
|
hp.push(elem);
|
|
SmiRecordId adr;
|
|
|
|
while(hp.empty() == false){
|
|
hpelem top = hp.top();
|
|
hp.pop();
|
|
|
|
if(top.mind > prunedist.dist)
|
|
break;
|
|
if(top.tid != -1 && top.nodeid == -1){ //an actual trajectory segment
|
|
UpdatekNearestG(top);
|
|
}
|
|
else if(top.tid == -1 && top.nodeid != -1){ // a node
|
|
adr = top.nodeid;
|
|
R_TreeNode<3,TupleId>* tbnode =
|
|
rtree->GetMyNode(adr,false,
|
|
rtree->MinEntries(level),
|
|
rtree->MaxEntries(level));
|
|
|
|
if(tbnode->IsLeaf()){ //leaf node
|
|
std::vector<idtime> entryarray;
|
|
for(int i = 0; i < tbnode->EntryCount();i++){
|
|
R_TreeLeafEntry<3,TupleId> entry =
|
|
(R_TreeLeafEntry<3,TupleId>&)(*tbnode)[i];
|
|
double ts((double)entry.box.MinD(2));
|
|
idtime idt(i,ts);
|
|
entryarray.push_back(idt);
|
|
}
|
|
stable_sort(entryarray.begin(),entryarray.end());
|
|
for(unsigned int j = 0;j < entryarray.size();j++){
|
|
// for(unsigned int i = 0;i < tbnode->EntryCount();i++){
|
|
int i = entryarray[j].id;
|
|
R_TreeLeafEntry<3,TupleId> entry =
|
|
(R_TreeLeafEntry<3,TupleId>&)(*tbnode)[i];
|
|
|
|
double t1((double)entry.box.MinD(2));
|
|
double t2((double)entry.box.MaxD(2));
|
|
// The following lines were used in published experiments, that
|
|
// were done on a modified R-tree that scaled up the R-tree temporal
|
|
// dimension by the same factor. They are commented out for use with
|
|
// the standard R-tree.
|
|
|
|
// t1 = t1/864000.0;
|
|
// t2 = t2/864000.0;
|
|
|
|
if(!(t1 >= endTime || t2 <= startTime)){
|
|
//for each unit in mp
|
|
UPoint up;
|
|
TupleId tid = entry.info;
|
|
Tuple* tuple = this->relation->GetTuple(tid, false);
|
|
UPoint* data = (UPoint*)tuple->GetAttribute(attrpos);
|
|
|
|
for(int j = 0;j < mp->GetNoComponents();j++){
|
|
mp->Get(j,up);
|
|
double tt1 = (double)(up.timeInterval.start.ToDouble());
|
|
double tt2 = (double)(up.timeInterval.end.ToDouble());
|
|
if(tt1 > t2) //mq's time interval is larger than entry
|
|
break;
|
|
if(!(t1 >= tt2 || t2 <= tt1)){
|
|
Point p0(true,0,0);
|
|
Point p1(true,0,0);
|
|
UPoint* ne = new UPoint(up.timeInterval,p0,p1);
|
|
UPoint* nqe = new UPoint(up.timeInterval,p0,p1);
|
|
|
|
//interpolation restrict to the same time interval
|
|
|
|
CreateUPoint_ne(&up,ne,data);
|
|
CreateUPoint_nqe(&up,nqe,data);
|
|
|
|
double nodets = ne->timeInterval.start.ToDouble();
|
|
double nodete = ne->timeInterval.end.ToDouble();
|
|
|
|
if(AlmostEqual(nodets,nodete)){
|
|
delete ne;
|
|
delete nqe;
|
|
continue;
|
|
}
|
|
|
|
UReal* mdist = new UReal(true);
|
|
ne->Distance(*nqe,*mdist);
|
|
bool def = true;
|
|
double mind = mdist->Min(def);
|
|
double maxd = mdist->Max(def);
|
|
|
|
hpelem le(tid,mind,maxd,-1);
|
|
le.nodets = nodets;
|
|
le.nodete = nodete;
|
|
|
|
le.AssignURUP(mdist,ne);
|
|
|
|
if(le.mind < prunedist.dist)
|
|
hp.push(le);
|
|
|
|
delete mdist;
|
|
delete ne;
|
|
delete nqe;
|
|
}
|
|
}//end for
|
|
tuple->DeleteIfAllowed();
|
|
}
|
|
}
|
|
}else{ //inner node
|
|
|
|
std::vector<hpelem> branchlist;
|
|
for(int i = 0;i < tbnode->EntryCount();i++){
|
|
R_TreeInternalEntry<3> e =
|
|
(R_TreeInternalEntry<3>&)(*tbnode)[i];
|
|
double t1((double)e.box.MinD(2));
|
|
double t2((double)e.box.MaxD(2));
|
|
|
|
// The following lines were used in published experiments, that
|
|
// were done on a modified R-tree that scaled up the R-tree temporal
|
|
// dimension by the same factor. They are commented out for use with
|
|
// the standard R-tree.
|
|
|
|
// t1 = t1/864000.0;
|
|
// t2 = t2/864000.0;
|
|
|
|
if(!(t1 >= endTime || t2 <= startTime)){
|
|
BBox<2> entrybox = makexyBox(e.box);//entry box
|
|
double mindist = mpbox.Distance(entrybox);
|
|
double maxdist = maxDistance(entrybox,mpbox);
|
|
|
|
hpelem le(-1,mindist,maxdist,e.pointer);
|
|
le.nodets = t1;
|
|
le.nodete = t2;
|
|
branchlist.push_back(le);
|
|
}
|
|
}
|
|
stable_sort(branchlist.begin(),branchlist.end());
|
|
std::vector<hpelem> prunelist;
|
|
|
|
for(unsigned int i = 0; i < branchlist.size();i++){
|
|
if(branchlist[i].mind < prunedist.dist)
|
|
if(CheckPrune(branchlist[i]) == false)
|
|
prunelist.push_back(branchlist[i]);
|
|
}
|
|
for(unsigned int i = 0;i < prunelist.size();){
|
|
hp.push(prunelist[i]);
|
|
unsigned int j = i + 1;
|
|
while(j < prunelist.size() &&
|
|
prunelist[j].mind > prunedist.dist){
|
|
if(CheckPrune(prunelist[j]))
|
|
j++;//prune branchlist
|
|
else
|
|
break;
|
|
}
|
|
i = j;
|
|
}
|
|
|
|
}
|
|
delete tbnode;
|
|
}
|
|
}
|
|
}
|
|
|
|
void TBKnearestLocalInfo::GreeceknnFunDF(MPoint* mp,int level,hpelem& elem)
|
|
{
|
|
const int dim = 3;
|
|
|
|
SmiRecordId adr = elem.nodeid;
|
|
R_TreeNode<dim,TupleId>* tbnode = rtree->GetMyNode(
|
|
adr,false,rtree->MinEntries(level),rtree->MaxEntries(level));
|
|
|
|
if(tbnode->IsLeaf()){ //leaf node
|
|
|
|
std::vector<idtime> entryarray;
|
|
for(int i = 0;i < tbnode->EntryCount();i++){
|
|
R_TreeLeafEntry<dim,TupleId> e =
|
|
(R_TreeLeafEntry<dim,TupleId>&)(*tbnode)[i];
|
|
double ts((double)e.box.MinD(2));
|
|
idtime idt(i,ts);
|
|
entryarray.push_back(idt);
|
|
}
|
|
stable_sort(entryarray.begin(),entryarray.end());//sort by start time
|
|
|
|
// for(int i = 0;i < tbnode->EntryCount();i++){
|
|
for(unsigned int j = 0;j < entryarray.size();j++){
|
|
int i = entryarray[j].id;
|
|
R_TreeLeafEntry<dim,TupleId> e =
|
|
(R_TreeLeafEntry<dim,TupleId>&)(*tbnode)[i];
|
|
double t1((double)e.box.MinD(2));
|
|
double t2((double)e.box.MaxD(2));
|
|
|
|
// The following lines were used in published experiments, that
|
|
// were done on a modified R-tree that scaled up the R-tree temporal
|
|
// dimension by the same factor. They are commented out for use with
|
|
// the standard R-tree.
|
|
|
|
// t1 = t1/864000.0;
|
|
// t2 = t2/864000.0;
|
|
|
|
|
|
if(!(t1 >= endTime || t2 <= startTime)){
|
|
//for each unit in mp
|
|
UPoint up;
|
|
TupleId tid = e.info;
|
|
Tuple* tuple = relation->GetTuple(tid, false);
|
|
UPoint* data = (UPoint*)tuple->GetAttribute(attrpos);
|
|
|
|
for(int j = 0;j < mp->GetNoComponents();j++){
|
|
mp->Get(j,up);
|
|
double tt1 = (double)(up.timeInterval.start.ToDouble());
|
|
double tt2 = (double)(up.timeInterval.end.ToDouble());
|
|
|
|
if(tt1 > t2) //mq's time interval is larger than entry
|
|
break;
|
|
if(!(t1 >= tt2 || t2 <= tt1)){
|
|
Point p0(true,0,0);
|
|
Point p1(true,0,0);
|
|
UPoint* ne = new UPoint(up.timeInterval,p0,p1);
|
|
UPoint* nqe = new UPoint(up.timeInterval,p0,p1);
|
|
//interpolation restrict to the same time interval
|
|
|
|
CreateUPoint_ne(&up,ne,data);
|
|
CreateUPoint_nqe(&up,nqe,data);
|
|
|
|
double nodets = ne->timeInterval.start.ToDouble();
|
|
double nodete = ne->timeInterval.end.ToDouble();
|
|
if(AlmostEqual(nodets,nodete)){
|
|
delete ne;
|
|
delete nqe;
|
|
continue;
|
|
}
|
|
UReal* mdist = new UReal(true);
|
|
ne->Distance(*nqe,*mdist);
|
|
bool def = true;
|
|
double mind = mdist->Min(def);
|
|
double maxd = mdist->Max(def);
|
|
hpelem le(tid,mind,maxd,-1);
|
|
le.nodets = nodets;
|
|
le.nodete = nodete;
|
|
le.AssignURUP(mdist,ne);
|
|
// if(CheckPrune(le) == false)
|
|
// UpdatekNearestG(le);
|
|
// if(le.mind < prunedist.dist)
|
|
// UpdatekNearest(le);
|
|
|
|
if(le.mind < prunedist.dist)
|
|
UpdatekNearestG(le);
|
|
delete mdist;
|
|
delete ne;
|
|
delete nqe;
|
|
}
|
|
}//end for
|
|
tuple->DeleteIfAllowed();
|
|
}
|
|
}
|
|
}else{ //an internal node
|
|
std::vector<hpelem> branchlist;
|
|
for(int i = 0;i < tbnode->EntryCount();i++){
|
|
R_TreeInternalEntry<dim> e =
|
|
(R_TreeInternalEntry<dim>&)(*tbnode)[i];
|
|
double t1((double)e.box.MinD(2));
|
|
double t2((double)e.box.MaxD(2));
|
|
|
|
// The following lines were used in published experiments, that
|
|
// were done on a modified R-tree that scaled up the R-tree temporal
|
|
// dimension by the same factor. They are commented out for use with
|
|
// the standard R-tree.
|
|
|
|
// t1 = t1/864000.0;
|
|
// t2 = t2/864000.0;
|
|
|
|
if(!(t1 >= endTime || t2 <= startTime)){
|
|
BBox<2> entrybox = makexyBox(e.box);//entry box
|
|
double mindist = mpbox.Distance(entrybox);
|
|
double maxdist = maxDistance(entrybox,mpbox);
|
|
|
|
hpelem le(-1,mindist,maxdist,e.pointer);
|
|
le.nodets = t1;
|
|
le.nodete = t2;
|
|
branchlist.push_back(le);
|
|
}
|
|
}
|
|
stable_sort(branchlist.begin(),branchlist.end());
|
|
std::vector<hpelem> prunelist;
|
|
|
|
for(unsigned int i = 0; i < branchlist.size();i++){
|
|
// if(CheckPrune(branchlist[i]) == false)
|
|
// prunelist.push_back(branchlist[i]);
|
|
if(branchlist[i].mind < prunedist.dist)
|
|
if(CheckPrune(branchlist[i]) == false)
|
|
prunelist.push_back(branchlist[i]);
|
|
}
|
|
for(unsigned int i = 0;i < prunelist.size();){
|
|
GreeceknnFunDF(mp,level+1,prunelist[i]);
|
|
unsigned int j = i + 1;
|
|
|
|
while(j < prunelist.size() && prunelist[j].mind > prunedist.dist){
|
|
if(CheckPrune(prunelist[j]))
|
|
j++;//prune branchlist
|
|
else
|
|
break;
|
|
}
|
|
i = j;
|
|
|
|
// while(j < prunelist.size() &&
|
|
// prunelist[j].mind > prunedist.dist)j++;//prune branchlist
|
|
// i = j;
|
|
|
|
}
|
|
}
|
|
delete tbnode;
|
|
}
|
|
|
|
/*
|
|
Greeceknearest is the value function for the greeceknearest operator
|
|
It is a filter operator for the knearest operator. It can be called
|
|
if there exists an r-tree for the unit attribute
|
|
The argument vector contains the following values:
|
|
args[0] = an r-tree with the unit attribute as key
|
|
args[1] = the relation of the r-tree
|
|
args[2] = attribute UPoint
|
|
args[3] = mpoint
|
|
args[4] = int k, how many nearest are searched
|
|
|
|
*/
|
|
|
|
int Greeceknearest(Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
const int dim = 3;
|
|
TBKnearestLocalInfo *localInfo;
|
|
switch (message)
|
|
{
|
|
case OPEN :
|
|
{
|
|
//Initialize hp,kNearestLists and PruneDist
|
|
MPoint* mp = (MPoint*)args[3].addr;
|
|
if(mp->IsEmpty())
|
|
return 0;
|
|
UPoint up1;
|
|
UPoint up2;
|
|
mp->Get(0,up1);
|
|
mp->Get(mp->GetNoComponents()-1,up2);
|
|
const unsigned int k = (unsigned int)((CcInt*)args[4].addr)->GetIntval();
|
|
int attrpos = ((CcInt*)args[5].addr)->GetIntval()-1;
|
|
localInfo = new TBKnearestLocalInfo(k);
|
|
local = SetWord(localInfo);
|
|
localInfo->attrpos = attrpos;
|
|
localInfo->startTime = up1.timeInterval.start.ToDouble();
|
|
localInfo->endTime = up2.timeInterval.end.ToDouble();
|
|
localInfo->ci =
|
|
new CIC<double>(localInfo->startTime,localInfo->endTime);
|
|
|
|
localInfo->cic =
|
|
new CoverInterval<double>(localInfo->startTime,localInfo->endTime);
|
|
|
|
localInfo->rtree = (R_Tree<dim,TupleId>*)args[0].addr;
|
|
localInfo->relation = (Relation*)args[1].addr;
|
|
localInfo->counter = 0;
|
|
localInfo->scanFlag = true;
|
|
localInfo->GreeceknearestInitialize(mp);
|
|
|
|
SmiRecordId adr = localInfo->rtree->RootRecordId();
|
|
R_TreeNode<dim,TupleId>* root = localInfo->rtree->GetMyNode(adr,
|
|
false,localInfo->rtree->MinEntries(0),localInfo->rtree->MaxEntries(0));
|
|
|
|
double t1(root->BoundingBox().MinD(2));
|
|
double t2(root->BoundingBox().MaxD(2));
|
|
|
|
// The following lines were used in published experiments, that
|
|
// were done on a modified R-tree that scaled up the R-tree temporal
|
|
// dimension by the same factor. They are commented out for use with
|
|
// the standard R-tree.
|
|
|
|
// t1 = t1/864000.0;
|
|
// t2 = t2/864000.0;
|
|
|
|
if(!(t1 >= localInfo->endTime || t2 <= localInfo->startTime)){
|
|
BBox<2> entrybox = makexyBox(root->BoundingBox());
|
|
double mindist = localInfo->mptraj->Distance(entrybox);
|
|
double maxdist = maxDistance(entrybox,localInfo->mpbox);
|
|
hpelem le(-1,mindist,maxdist,adr);
|
|
le.nodets = t1;
|
|
le.nodete = t2;
|
|
// ftime(>1);
|
|
localInfo->GreeceknnFunDF(mp,0,le); //2,12s train1,5
|
|
// localInfo->GreeceknnFunBF(mp,0,le);//0.73s train1,5
|
|
localInfo->ReportResult();
|
|
}
|
|
delete root;
|
|
return 0;
|
|
}
|
|
case REQUEST :
|
|
{
|
|
localInfo = (TBKnearestLocalInfo*)local.addr;
|
|
if(localInfo->k == 0)
|
|
return CANCEL;
|
|
if(localInfo->counter < localInfo->result.size()){
|
|
TupleId tid = localInfo->result[localInfo->counter].tid;
|
|
Tuple* tuple = localInfo->relation->GetTuple(tid, false);
|
|
UPoint* up = (UPoint*)tuple->GetAttribute(localInfo->attrpos);
|
|
Point p0;
|
|
Point p1;
|
|
Instant t1(datetime::instanttype);
|
|
Instant t2(datetime::instanttype);
|
|
t1.ReadFrom(localInfo->result[localInfo->counter].nodets);
|
|
t2.ReadFrom(localInfo->result[localInfo->counter].nodete);
|
|
Interval<Instant> interv(t1,t2,true,true);
|
|
UPoint* temp = new UPoint(*up);
|
|
temp->TemporalFunction(t1,p0,true);
|
|
temp->TemporalFunction(t2,p1,true);
|
|
temp->p0 = p0;
|
|
temp->timeInterval.start = t1;
|
|
temp->p1 = p1;
|
|
temp->timeInterval.end = t2;
|
|
double factor = 0.0000001;
|
|
if((localInfo->result[localInfo->counter].nodete -
|
|
localInfo->result[localInfo->counter].nodets) < factor)
|
|
temp->timeInterval.lc = temp->timeInterval.rc = true;
|
|
|
|
tuple->PutAttribute(localInfo->attrpos,new UPoint(*temp));
|
|
delete temp;
|
|
|
|
result = SetWord(tuple);
|
|
localInfo->counter++;
|
|
return YIELD;
|
|
}else
|
|
return CANCEL;
|
|
}
|
|
|
|
case CLOSE :
|
|
{
|
|
localInfo = (TBKnearestLocalInfo*)local.addr;
|
|
if(localInfo){
|
|
delete localInfo;
|
|
local.addr=0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
return 0;
|
|
|
|
}
|
|
|
|
/*
|
|
ChinaknearestFun is the value function for the chinaknearest operator
|
|
It is a filter operator for the knearest operator. It can be called
|
|
if there exists a tb-tree for the unit attribute
|
|
The argument vector contains the following values:
|
|
args[0] = a tbtree with the unit attribute as key
|
|
args[1] = the relation of the tbtree
|
|
args[2] = attribute name UPoint
|
|
args[3] = mpoint
|
|
args[4] = int k, how many nearest are searched
|
|
args[5] = localtion of the UPoint attribute
|
|
|
|
*/
|
|
|
|
int ChinaknearestFun (Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
TBKnearestLocalInfo* localInfo;
|
|
switch (message)
|
|
{
|
|
case OPEN :
|
|
{
|
|
//Initialize hp,kNearestLists and PruneDist
|
|
MPoint* mp = (MPoint*)args[3].addr;
|
|
if(mp->IsEmpty()) {
|
|
return 0;
|
|
}
|
|
UPoint up1;
|
|
UPoint up2;
|
|
mp->Get(0,up1);
|
|
mp->Get(mp->GetNoComponents()-1,up2);
|
|
|
|
|
|
const unsigned int k = (unsigned int)((CcInt*)args[4].addr)->GetIntval();
|
|
int attrpos = ((CcInt*)args[5].addr)->GetIntval()-1;
|
|
|
|
|
|
localInfo = new TBKnearestLocalInfo(k);
|
|
local = SetWord(localInfo);
|
|
localInfo->attrpos = attrpos;
|
|
localInfo->startTime = up1.timeInterval.start.ToDouble();
|
|
localInfo->endTime = up2.timeInterval.end.ToDouble();
|
|
|
|
localInfo->ci =
|
|
new CIC<double>(localInfo->startTime,localInfo->endTime);
|
|
|
|
localInfo->cic =
|
|
new CoverInterval<double>(localInfo->startTime,localInfo->endTime);
|
|
|
|
localInfo->tbtree = (tbtree::TBTree*)args[0].addr;
|
|
localInfo->relation = (Relation*)args[1].addr;
|
|
localInfo->counter = 0;
|
|
localInfo->scanFlag = true;
|
|
localInfo->ChinaknnInitialize(mp);
|
|
localInfo->ChinaknnFun(mp);
|
|
return 0;
|
|
}
|
|
case REQUEST :
|
|
{
|
|
localInfo = (TBKnearestLocalInfo*)local.addr;
|
|
if(!localInfo){
|
|
cout << "no localinfo found" << endl;
|
|
return CANCEL;
|
|
}
|
|
if(localInfo->k == 0) {
|
|
cout << "k is zero" << endl;
|
|
return CANCEL;
|
|
}
|
|
if(localInfo->counter < localInfo->result.size()){
|
|
cout << "counter not reached" << endl;
|
|
TupleId tid = localInfo->result[localInfo->counter].tid;
|
|
Tuple* tuple = localInfo->relation->GetTuple(tid, false);
|
|
UPoint* up = (UPoint*)tuple->GetAttribute(localInfo->attrpos);
|
|
Point p0;
|
|
Point p1;
|
|
Instant t1(datetime::instanttype);
|
|
Instant t2(datetime::instanttype);
|
|
t1.ReadFrom(localInfo->result[localInfo->counter].nodets);
|
|
t2.ReadFrom(localInfo->result[localInfo->counter].nodete);
|
|
Interval<Instant> interv(t1,t2,true,true);
|
|
UPoint* temp = new UPoint(*up);
|
|
temp->TemporalFunction(t1,p0,true);
|
|
temp->TemporalFunction(t2,p1,true);
|
|
temp->p0 = p0;
|
|
temp->timeInterval.start = t1;
|
|
temp->p1 = p1;
|
|
temp->timeInterval.end = t2;
|
|
double factor = 0.0000001;
|
|
if((localInfo->result[localInfo->counter].nodete -
|
|
localInfo->result[localInfo->counter].nodets) < factor)
|
|
temp->timeInterval.lc = temp->timeInterval.rc = true;
|
|
|
|
tuple->PutAttribute(localInfo->attrpos,new UPoint(*temp));
|
|
delete temp;
|
|
|
|
result = SetWord(tuple);
|
|
localInfo->counter++;
|
|
return YIELD;
|
|
}else{
|
|
cout << " counter >= size" << endl;
|
|
cout << "counter = " << localInfo->counter << endl;
|
|
cout << "localInfo->result.size() = "
|
|
<< localInfo->result.size() << endl;
|
|
return CANCEL;
|
|
}
|
|
}
|
|
|
|
case CLOSE :
|
|
{
|
|
cout << "CLOSE called" << endl;
|
|
localInfo = (TBKnearestLocalInfo*)local.addr;
|
|
if(localInfo){
|
|
delete localInfo;
|
|
local.addr=0;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
The function hcknnknearestTypeMap is the type map for the
|
|
operator knearestfilter
|
|
|
|
*/
|
|
ListExpr ChinaknearestTypeMap( ListExpr args )
|
|
{
|
|
|
|
std::string errmsg = "tbtree x relation x utrip x mpoint x int expected";
|
|
|
|
if(nl->ListLength(args)!=5){
|
|
ErrorReporter::ReportError(errmsg);
|
|
return nl->TypeError();
|
|
}
|
|
ListExpr tbtreeDescription = nl->First(args);
|
|
ListExpr relDescription = nl->Second(args);
|
|
ListExpr attrName = nl->Third(args);
|
|
ListExpr mpoint = nl->Fourth(args);
|
|
ListExpr quantity = nl->Fifth(args);
|
|
|
|
// the third element has to be of type mpoint
|
|
if(!nl->IsEqual(mpoint,MPoint::BasicType())){
|
|
ErrorReporter::ReportError(errmsg);
|
|
return nl->TypeError();
|
|
}
|
|
|
|
// the third element has to be of type mpoint
|
|
if(!nl->IsEqual(quantity,CcInt::BasicType())){
|
|
ErrorReporter::ReportError(errmsg);
|
|
return nl->TypeError();
|
|
}
|
|
|
|
// an tbtree description must have length 4
|
|
if(nl->ListLength(tbtreeDescription)!=4){
|
|
ErrorReporter::ReportError(errmsg);
|
|
return nl->TypeError();
|
|
}
|
|
|
|
ListExpr tbtreeSymbol = nl->First(tbtreeDescription);
|
|
|
|
if(!nl->IsEqual(tbtreeSymbol, "tbtree")){
|
|
ErrorReporter::ReportError(errmsg);
|
|
return nl->TypeError();
|
|
}
|
|
|
|
if(!IsRelDescription(relDescription)){
|
|
ErrorReporter::ReportError(errmsg);
|
|
return nl->TypeError();
|
|
}
|
|
ListExpr attrType;
|
|
int j = listutils::findAttribute(nl->Second(nl->Second(relDescription)),
|
|
nl->SymbolValue(attrName),attrType);
|
|
if(j==0 || !listutils::isSymbol(attrType,UPoint::BasicType())){
|
|
return listutils::typeError("upoint expected");
|
|
}
|
|
ListExpr res = nl->TwoElemList(
|
|
nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->Second(nl->Second(args)));
|
|
|
|
return nl->ThreeElemList(nl->SymbolAtom(Symbol::APPEND()),
|
|
nl->OneElemList(nl->IntAtom(j)),res);
|
|
|
|
}
|
|
|
|
/*
|
|
The function rknearestFilterTypeMap is the type map for the
|
|
operator knearestfilter
|
|
|
|
*/
|
|
ListExpr GreeceknearestTypeMap( ListExpr args )
|
|
{
|
|
|
|
std::string errmsg = "rtree x relation x utrip x mpoint x int expected";
|
|
|
|
if(nl->ListLength(args)!=5){
|
|
ErrorReporter::ReportError(errmsg);
|
|
return nl->TypeError();
|
|
}
|
|
ListExpr tbtreeDescription = nl->First(args);
|
|
ListExpr relDescription = nl->Second(args);
|
|
ListExpr attrName = nl->Third(args);
|
|
ListExpr mpoint = nl->Fourth(args);
|
|
ListExpr quantity = nl->Fifth(args);
|
|
|
|
// the third element has to be of type mpoint
|
|
if(!nl->IsEqual(mpoint,MPoint::BasicType())){
|
|
ErrorReporter::ReportError(errmsg);
|
|
return nl->TypeError();
|
|
}
|
|
|
|
// the third element has to be of type mpoint
|
|
if(!nl->IsEqual(quantity,CcInt::BasicType())){
|
|
ErrorReporter::ReportError(errmsg);
|
|
return nl->TypeError();
|
|
}
|
|
|
|
// an tbtree description must have length 4
|
|
if(nl->ListLength(tbtreeDescription)!=4){
|
|
ErrorReporter::ReportError(errmsg);
|
|
return nl->TypeError();
|
|
}
|
|
|
|
ListExpr tbtreeSymbol = nl->First(tbtreeDescription);
|
|
|
|
if(!nl->IsEqual(tbtreeSymbol, RTree3TID::BasicType())){
|
|
ErrorReporter::ReportError(errmsg);
|
|
return nl->TypeError();
|
|
}
|
|
|
|
if(!IsRelDescription(relDescription)){
|
|
ErrorReporter::ReportError(errmsg);
|
|
return nl->TypeError();
|
|
}
|
|
|
|
ListExpr attrType;
|
|
int j = FindAttribute(nl->Second(nl->Second(relDescription)),
|
|
nl->SymbolValue(attrName),attrType);
|
|
if(j==0 || !listutils::isSymbol(attrType,UPoint::BasicType())){
|
|
return listutils::typeError("upoint expected");
|
|
}
|
|
ListExpr res = nl->TwoElemList(
|
|
nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->Second(nl->Second(args)));
|
|
|
|
return nl->ThreeElemList(nl->SymbolAtom(Symbol::APPEND()),
|
|
nl->OneElemList(nl->IntAtom(j)),res);
|
|
}
|
|
|
|
Operator greeceknearest (
|
|
"greeceknearest", // name
|
|
GreeceknearestfilterSpec, // specification
|
|
Greeceknearest, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
GreeceknearestTypeMap // type mapping
|
|
);
|
|
Operator chinaknearest (
|
|
"chinaknearest", // name
|
|
ChinaknearestSpec, // specification
|
|
ChinaknearestFun,// value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
ChinaknearestTypeMap // type mapping
|
|
);
|
|
|
|
const std::string CellIndexSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )"
|
|
"( <text>rtree(tuple ((x1 t1)...(xn tn))"
|
|
" ti) x cellno ->"
|
|
" (stream (tuple ((x1 t1)...(xn tn))))"
|
|
"</text--->"
|
|
"<text> cellindex (_, _)</text--->"
|
|
"<text>The operator results a stream of tuples "
|
|
"where each tuple corresponds to a cell. "
|
|
"and for each cell it records all nodes of index that intersect "
|
|
"it in space"
|
|
"The operator expects an r-tree and cell number </text--->"
|
|
"<text>query cellindex(strassen_geoData_rtree,10) count;</text--->"
|
|
") )";
|
|
|
|
/*
|
|
The function CellIndexTypeMap is the type map for the
|
|
operator cellindex
|
|
|
|
*/
|
|
ListExpr CellIndexTypeMap( ListExpr args )
|
|
{
|
|
|
|
std::string errmsg = "rtree x cellnumber expected";
|
|
|
|
if(nl->ListLength(args)!=2 ){
|
|
ErrorReporter::ReportError(errmsg);
|
|
return nl->TypeError();
|
|
}
|
|
|
|
ListExpr rtree = nl->First(args);
|
|
|
|
if(!listutils::isRTreeDescription(rtree)){
|
|
ErrorReporter::ReportError(errmsg);
|
|
return nl->TypeError();
|
|
}
|
|
|
|
|
|
std::string rtreedescription;
|
|
nl->WriteToString(rtreedescription,rtree);
|
|
|
|
|
|
|
|
|
|
ListExpr cellnumber = nl->Second(args);
|
|
ListExpr MBR_ATOM = nl->TheEmptyList();
|
|
|
|
if(!listutils::isRTreeDescription(rtree)){
|
|
return listutils::typeError("first argument must be an rtree");
|
|
}
|
|
ListExpr rtsymbol = nl->First(rtree);
|
|
|
|
|
|
if(nl->IsAtom(rtsymbol) &&
|
|
nl->AtomType(rtsymbol) == SymbolType &&
|
|
(nl->SymbolValue(rtsymbol) == RTree2TID::BasicType() ||
|
|
nl->SymbolValue(rtsymbol) == RTree3TID::BasicType())&&
|
|
nl->SymbolValue(cellnumber) == CcInt::BasicType()){
|
|
if(nl->SymbolValue(rtsymbol) == RTree2TID::BasicType())
|
|
MBR_ATOM = nl->SymbolAtom(Rectangle<2>::BasicType());
|
|
if(nl->SymbolValue(rtsymbol) == RTree3TID::BasicType())
|
|
MBR_ATOM = nl->SymbolAtom(Rectangle<3>::BasicType());
|
|
return
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom(Tuple::BasicType()),
|
|
nl->FourElemList(
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("Cellid"),
|
|
nl->SymbolAtom(CcInt::BasicType())
|
|
),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("MBR"),
|
|
MBR_ATOM
|
|
),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("Nodeid"),
|
|
nl->SymbolAtom(CcInt::BasicType())
|
|
),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("Nodelevel"),
|
|
nl->SymbolAtom(CcInt::BasicType())
|
|
))));
|
|
}
|
|
ErrorReporter::ReportError(errmsg);
|
|
return nl->TypeError();
|
|
}
|
|
/*
|
|
Partition the space into several cells, and for each cell it records the node of
|
|
index that intersects the cell and the level of node in index
|
|
|
|
*/
|
|
struct SubCell{
|
|
int nodeid;
|
|
int nodelevel;
|
|
SubCell(){}
|
|
SubCell(int id,int l):nodeid(id),nodelevel(l){}
|
|
SubCell(const SubCell& sc):nodeid(sc.nodeid),nodelevel(sc.nodelevel){}
|
|
SubCell& operator=(const SubCell& sc)
|
|
{
|
|
nodeid = sc.nodeid;
|
|
nodelevel = sc.nodelevel;
|
|
return *this;
|
|
}
|
|
};
|
|
template<unsigned dim>
|
|
struct Cell:public SubCell{
|
|
int id;
|
|
BBox<dim> box;
|
|
Cell(int i,BBox<dim> b,int nodeid,int l):SubCell(nodeid,l),id(i),box(b){}
|
|
Cell(const Cell& cell):SubCell(cell),id(cell.id),box(cell.box){}
|
|
Cell& operator=(const Cell& cell)
|
|
{
|
|
SubCell::operator=(cell);
|
|
id = cell.id;
|
|
box = cell.box;
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
|
|
template<unsigned dim>
|
|
struct CellIndex{
|
|
R_Tree<dim,TupleId>* rtree;
|
|
long cellno;
|
|
CellIndex(R_Tree<dim,TupleId>*r, long no)
|
|
:rtree(r),cellno(no){}
|
|
|
|
std::vector<Cell<dim> > cellq;
|
|
std::vector<double> gmin;
|
|
std::vector<double> gmax;
|
|
std::vector<double> cellsize;
|
|
SubCell tempcell;
|
|
|
|
unsigned int counter;
|
|
TupleType* resulttype;
|
|
~CellIndex(){delete resulttype;}
|
|
void Partition_Cell();
|
|
void Accessfunction(int,std::vector<long>&,std::vector<long>&,
|
|
std::vector<int>&);
|
|
};
|
|
/*
|
|
It partitions the space covered by an R-tree into several cells and for each
|
|
cell it records all nodes from the R-tree that their bounding boxes intersect
|
|
the cell.
|
|
|
|
*/
|
|
|
|
template<unsigned dim>
|
|
void CellIndex<dim>::Accessfunction(int depth,std::vector<long>& start_index,
|
|
std::vector<long>& end_index,std::vector<int>& pos)
|
|
{
|
|
if(depth == dim - 1){
|
|
for(long i = start_index[depth]; i <= end_index[depth];i++){
|
|
pos[depth] = i;
|
|
long cellid = 1;
|
|
for(int j = depth;j >= 0;j--){
|
|
int k = j - 1;
|
|
int size_low = 1;
|
|
while( k >= 0){
|
|
size_low = size_low * cellno;
|
|
k--;
|
|
}
|
|
cellid += size_low * pos[j];
|
|
// cout<<cellid<<endl;
|
|
}
|
|
double min[dim];
|
|
double max[dim];
|
|
for(unsigned int j = 0;j < dim;j++){
|
|
min[j] = gmin[j] + pos[j]*cellsize[j];
|
|
max[j] = gmin[j] + (pos[j]+1)*cellsize[j];
|
|
}
|
|
Rectangle<dim> cellbox(true,min,max);
|
|
cellq.push_back(Cell<dim>(cellid,cellbox,
|
|
tempcell.nodeid,tempcell.nodelevel));
|
|
}
|
|
}else{
|
|
for(long i = start_index[depth];i <= end_index[depth];i++){
|
|
pos[depth] = i;
|
|
Accessfunction(depth+1,start_index,end_index,pos);
|
|
}
|
|
}
|
|
|
|
}
|
|
template<unsigned dim>
|
|
void CellIndex<dim>::Partition_Cell()
|
|
{
|
|
// cout<<CI->cellq.max_size()<<endl;
|
|
BBox<dim> r_box = rtree->BoundingBox();
|
|
////
|
|
|
|
for(unsigned int i = 0; i < dim;i++){
|
|
gmin.push_back(r_box.MinD(i));
|
|
gmax.push_back(r_box.MaxD(i));
|
|
}
|
|
|
|
/*double minx = r_box.MinD(0);
|
|
double maxx = r_box.MaxD(0);
|
|
double miny = r_box.MinD(1);
|
|
double maxy = r_box.MaxD(1);*/
|
|
|
|
|
|
for(unsigned int i = 0; i < dim;i++){
|
|
// cout<<(long)floor((gmax[i]-gmin[i])/cellno)<<endl;
|
|
cellsize.push_back(floor((gmax[i]-gmin[i])/cellno));
|
|
}
|
|
/////////
|
|
/*double sizex = (long)floor((maxx-minx)/cellno);
|
|
double sizey = (long)floor((maxy-miny)/cellno);*/
|
|
|
|
std::queue<SubCell> q_node;
|
|
SmiRecordId adr = rtree->RootRecordId();
|
|
R_TreeNode<dim,TupleId>* node =
|
|
rtree->GetMyNode(adr,false,
|
|
rtree->MinEntries(0),
|
|
rtree->MaxEntries(0));
|
|
if(!node->IsLeaf()){
|
|
//skip root node
|
|
for(int i = 0; i < node->EntryCount();i++){
|
|
R_TreeInternalEntry<dim> e = (R_TreeInternalEntry<dim>&)(*node)[i];
|
|
q_node.push(SubCell(e.pointer,1));
|
|
}
|
|
}
|
|
delete node;
|
|
|
|
std::vector<int> pos;
|
|
|
|
std::vector<double> lower;
|
|
std::vector<double> upper;
|
|
std::vector<long> start_index;
|
|
std::vector<long> end_index;
|
|
|
|
while(q_node.empty() == false){
|
|
SubCell subcell = q_node.front();
|
|
q_node.pop();
|
|
adr = subcell.nodeid;
|
|
node =
|
|
rtree->GetMyNode(adr,false,
|
|
rtree->MinEntries(subcell.nodelevel),
|
|
rtree->MaxEntries(subcell.nodelevel));
|
|
|
|
/*double lowerx = node->BoundingBox().MinD(0);
|
|
double upperx = node->BoundingBox().MaxD(0);
|
|
double lowery = node->BoundingBox().MinD(1);
|
|
double uppery = node->BoundingBox().MaxD(1);
|
|
long start_i = (long)floor((lowerx-minx)/sizex);//starts from 1
|
|
long end_i = (long)floor((upperx-minx)/sizex);
|
|
long start_j = (long)floor((lowery-miny)/sizey);
|
|
long end_j = (long)floor((uppery-miny)/sizey);*/
|
|
|
|
///////////////
|
|
lower.clear();
|
|
upper.clear();
|
|
start_index.clear();
|
|
end_index.clear();
|
|
|
|
for(unsigned int i = 0;i < dim;i++){
|
|
lower.push_back(node->BoundingBox().MinD(i));
|
|
upper.push_back(node->BoundingBox().MaxD(i));
|
|
}
|
|
for(unsigned int i = 0;i < dim;i++){
|
|
start_index.push_back((long)floor((lower[i]-gmin[i])/cellsize[i]));
|
|
end_index.push_back((long)floor((upper[i]-gmin[i])/cellsize[i]));
|
|
}
|
|
// cout<<pos.size()<<endl;
|
|
tempcell = subcell;
|
|
pos.clear();
|
|
for(unsigned int i = 0;i < dim;i++)
|
|
pos.push_back(-1);
|
|
|
|
Accessfunction(0,start_index,end_index,pos);
|
|
|
|
////////////
|
|
/*for(;start_i <= end_i;start_i++){
|
|
for(long temp_j = start_j;temp_j <= end_j; temp_j++){
|
|
long cellid = temp_j*cellno + start_i + 1;
|
|
// long cellid = start_i*cellno + temp_j + 1;
|
|
double min[2];
|
|
double max[2];
|
|
min[0] = minx + start_i*sizex;
|
|
max[0] = minx + (start_i+1)*sizex;
|
|
min[1] = miny + temp_j*sizey;
|
|
max[1] = miny + (temp_j+1)*sizey;
|
|
BBox<dim> cellbox(true,min,max);
|
|
cellq.push_back(
|
|
Cell<dim>(cellid,cellbox,subcell.nodeid,subcell.nodelevel));
|
|
}
|
|
}*/
|
|
|
|
if(node->IsLeaf()){
|
|
delete node;
|
|
continue;
|
|
}
|
|
for(int i = 0; i < node->EntryCount();i++){
|
|
R_TreeInternalEntry<dim> e = (R_TreeInternalEntry<dim>&)(*node)[i];
|
|
q_node.push(SubCell(e.pointer,subcell.nodelevel+1));
|
|
}
|
|
delete node;
|
|
}
|
|
}
|
|
template<unsigned dim>
|
|
int CellIndexFun(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
CellIndex<dim>* localInfo;
|
|
switch(message){
|
|
case OPEN: {
|
|
localInfo = new CellIndex<dim>((R_Tree<dim,TupleId>*)args[0].addr,
|
|
((CcInt*)args[1].addr)->GetIntval());
|
|
localInfo->counter = 0;
|
|
localInfo->resulttype = new
|
|
TupleType(nl->Second(GetTupleResultType(s)));
|
|
localInfo->Partition_Cell();
|
|
local = SetWord(localInfo);
|
|
return 0;
|
|
}
|
|
case REQUEST: {
|
|
localInfo = (CellIndex<dim>*)local.addr;
|
|
if(localInfo->counter == localInfo->cellq.size())
|
|
return CANCEL;
|
|
Tuple* tuple = new Tuple(localInfo->resulttype);
|
|
Cell<dim> cell = localInfo->cellq[localInfo->counter] ;
|
|
tuple->PutAttribute(0,new CcInt(true,cell.id));
|
|
tuple->PutAttribute(1,new Rectangle<dim>(cell.box));
|
|
tuple->PutAttribute(2,new CcInt(true,cell.nodeid));
|
|
tuple->PutAttribute(3,new CcInt(true,cell.nodelevel));
|
|
localInfo->counter++;
|
|
result.setAddr(tuple);
|
|
return YIELD;
|
|
}
|
|
case CLOSE : {
|
|
localInfo = (CellIndex<dim>*)local.addr;
|
|
if(localInfo){
|
|
delete localInfo;
|
|
local.addr=0;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
ValueMapping CellIndexFunMap [] =
|
|
{
|
|
CellIndexFun<2>,
|
|
CellIndexFun<3>
|
|
};
|
|
int CellIndexSelect(ListExpr args)
|
|
{
|
|
ListExpr rtree = nl->First(args);
|
|
std::string rtreedescription;
|
|
nl->WriteToString(rtreedescription,rtree);
|
|
ListExpr rtsymbol = nl->First(rtree);
|
|
|
|
if(nl->IsAtom(rtsymbol) &&
|
|
nl->AtomType(rtsymbol) == SymbolType &&
|
|
nl->SymbolValue(rtsymbol) == RTree2TID::BasicType())
|
|
return 0;
|
|
if(nl->IsAtom(rtsymbol) &&
|
|
nl->AtomType(rtsymbol) == SymbolType &&
|
|
nl->SymbolValue(rtsymbol) == RTree3TID::BasicType())
|
|
return 1;
|
|
return -1;
|
|
}
|
|
Operator cellindex(
|
|
"cellindex",
|
|
CellIndexSpec,
|
|
2,
|
|
CellIndexFunMap,
|
|
CellIndexSelect,
|
|
CellIndexTypeMap
|
|
);
|
|
|
|
|
|
|
|
ListExpr GnuplotNodeTypeMap( ListExpr args )
|
|
{
|
|
|
|
std::string errmsg = "stream x attribute x string expected";
|
|
|
|
if(nl->ListLength(args)!=3){
|
|
ErrorReporter::ReportError(errmsg);
|
|
return nl->TypeError();
|
|
}
|
|
|
|
ListExpr stream = nl->First(args);
|
|
ListExpr attrName = nl->Second(args);
|
|
ListExpr filename = nl->Third(args);
|
|
if(!IsStreamDescription(stream)){
|
|
ErrorReporter::ReportError(errmsg);
|
|
return nl->TypeError();
|
|
}
|
|
if(nl->AtomType(attrName) != SymbolType){
|
|
ErrorReporter::ReportError(errmsg);
|
|
return nl->TypeError();
|
|
}
|
|
|
|
if(!(nl->SymbolValue(filename) == CcString::BasicType())){
|
|
ErrorReporter::ReportError(errmsg);
|
|
return nl->TypeError();
|
|
}
|
|
int j;
|
|
ListExpr attrType;
|
|
j = FindAttribute(nl->Second(nl->Second(stream)),
|
|
nl->SymbolValue(attrName),attrType);
|
|
|
|
return nl->ThreeElemList(nl->SymbolAtom(Symbol::APPEND()),
|
|
nl->OneElemList(nl->IntAtom(j)),
|
|
nl->SymbolAtom(CcInt::BasicType()));
|
|
}
|
|
|
|
/*
|
|
It outputs the coordinate of each box into a data file which will be
|
|
read by gnuplot program to visualize the data
|
|
|
|
*/
|
|
struct Box_data{
|
|
double minx;
|
|
double miny;
|
|
double mint;
|
|
double maxx;
|
|
double maxy;
|
|
double maxt;
|
|
Box_data(double a,double b,double c,double x,double y,double z)
|
|
:minx(a),miny(b),mint(c),maxx(x),maxy(y),maxt(z){}
|
|
Box_data(const Box_data& bd)
|
|
:minx(bd.minx),miny(bd.miny),mint(bd.mint),
|
|
maxx(bd.maxx),maxy(bd.maxy),maxt(bd.maxt){}
|
|
Box_data& operator=(const Box_data& bd)
|
|
{
|
|
minx = bd.minx;
|
|
miny = bd.miny;
|
|
mint = bd.mint;
|
|
maxx = bd.maxx;
|
|
maxy = bd.maxy;
|
|
maxt = bd.maxt;
|
|
return *this;
|
|
}
|
|
};
|
|
int gnuplotnodeFun (Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
int count = 0;
|
|
result = qp->ResultStorage(s);
|
|
Word stream = args[0];
|
|
Word current(Address(0));
|
|
qp->Open(args[0].addr);
|
|
qp->Request(stream.addr,current);
|
|
if(!qp->Received(stream.addr)){
|
|
((CcInt*)result.addr)->Set(true,0);
|
|
return 0;
|
|
}
|
|
CcString* file = (CcString*)args[2].addr;
|
|
std::ofstream datafile(file->GetValue().c_str());
|
|
int pos = ((CcInt*)args[3].addr)->GetIntval() - 1;
|
|
bool finished = false;
|
|
std::vector<Box_data> data;
|
|
double min = std::numeric_limits<double>::max();
|
|
while(!finished){
|
|
if(!finished){
|
|
Tuple* tuple = static_cast<Tuple*>(current.addr);
|
|
Rectangle<3>* box = (Rectangle<3>*)tuple->GetAttribute(pos);
|
|
// cout<<*box<<endl;
|
|
|
|
data.push_back(Box_data(box->MinD(0),box->MinD(1),box->MinD(2),
|
|
box->MaxD(0),box->MaxD(1),box->MaxD(2)));
|
|
if(box->MinD(2) < min)
|
|
min = box->MinD(2);
|
|
|
|
tuple->DeleteIfAllowed();
|
|
count++;
|
|
// if(count >= 50){
|
|
// cout<<"maximum number of nodes to plot is 50"<<endl;
|
|
// break;
|
|
// }
|
|
}
|
|
qp->Request(stream.addr,current);
|
|
finished = !qp->Received(stream.addr);
|
|
}
|
|
for(unsigned int i = 0; i < data.size();i++){
|
|
Box_data box_data = data[i];
|
|
datafile<<box_data.minx<<" "<<box_data.miny<<" "
|
|
<<864000*(box_data.maxt-min)<<endl;
|
|
datafile<<box_data.maxx<<" "<<box_data.miny<<" "
|
|
<<864000*(box_data.maxt-min)<<endl;
|
|
datafile<<box_data.maxx<<" "<<box_data.miny<<" "
|
|
<<864000*(box_data.mint-min)<<endl;
|
|
datafile<<box_data.minx<<" "<<box_data.miny<<" "
|
|
<<864000*(box_data.mint-min)<<endl;
|
|
datafile<<box_data.minx<<" "<<box_data.miny<<" "
|
|
<<864000*(box_data.maxt-min)<<endl;
|
|
datafile<<box_data.minx<<" "<<box_data.maxy<<" "
|
|
<<864000*(box_data.maxt-min)<<endl;
|
|
datafile<<box_data.maxx<<" "<<box_data.maxy<<" "
|
|
<<864000*(box_data.maxt-min)<<endl;
|
|
datafile<<box_data.maxx<<" "<<box_data.miny<<" "
|
|
<<864000*(box_data.maxt-min)<<endl;
|
|
datafile<<box_data.maxx<<" "<<box_data.miny<<" "
|
|
<<864000*(box_data.mint-min)<<endl;
|
|
datafile<<box_data.maxx<<" "<<box_data.maxy<<" "
|
|
<<864000*(box_data.mint-min)<<endl;
|
|
datafile<<box_data.minx<<" "<<box_data.maxy<<" "
|
|
<<864000*(box_data.mint-min)<<endl;
|
|
datafile<<box_data.minx<<" "<<box_data.miny<<" "
|
|
<<864000*(box_data.mint-min)<<endl;
|
|
datafile<<box_data.minx<<" "<<box_data.maxy<<" "
|
|
<<864000*(box_data.mint-min)<<endl;
|
|
datafile<<box_data.minx<<" "<<box_data.maxy<<" "
|
|
<<864000*(box_data.maxt-min)<<endl;
|
|
datafile<<box_data.minx<<" "<<box_data.maxy<<" "
|
|
<<864000*(box_data.mint-min)<<endl;
|
|
datafile<<box_data.maxx<<" "<<box_data.maxy<<" "
|
|
<<864000*(box_data.mint-min)<<endl;
|
|
datafile<<box_data.maxx<<" "<<box_data.maxy<<" "
|
|
<<864000*(box_data.maxt-min)<<endl;
|
|
datafile<<endl<<endl;
|
|
|
|
}
|
|
cout<<count<<" nodes output in file "<<file->GetValue()<<endl;
|
|
((CcInt*)result.addr)->Set(true,count);
|
|
return 0;
|
|
}
|
|
|
|
|
|
const std::string GnuplotnodeSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )"
|
|
"( <text>a stream of tuples with 3D box attribute x output_file->"
|
|
" output a file"
|
|
"</text--->"
|
|
"<text> gnuplotnode (_, _)</text--->"
|
|
"it outputs the data of bounding box from a certain level into "
|
|
"a file read by gnuplot"
|
|
"<text>query nodes(UnitTrains_UTrip) filter [.level=1] "
|
|
"gnuplot(MBR,\"file\"] count;</text--->"
|
|
"))";
|
|
|
|
Operator gnuplotnode(
|
|
"gnuplotnode",
|
|
GnuplotnodeSpec,
|
|
gnuplotnodeFun,
|
|
Operator::SimpleSelect,
|
|
GnuplotNodeTypeMap
|
|
);
|
|
|
|
|
|
struct PairElem{
|
|
myureal movdist;
|
|
TupleId tid1,tid2;
|
|
myupoint p1,p2;
|
|
long nid1,nid2;
|
|
double mind,maxd;
|
|
double stime,etime;
|
|
PairElem* next;
|
|
PairElem(TupleId id1,TupleId id2,long n1,long n2,double min,double max,
|
|
double s,double e)
|
|
:tid1(id1),tid2(id2),nid1(n1),nid2(n2),mind(min),maxd(max),stime(s),etime(e){}
|
|
};
|
|
|
|
struct PairList{
|
|
double mind,maxd;
|
|
PairElem* head;
|
|
double stime,etime;
|
|
PairList(double min,double max,PairElem* pe,double s,double e)
|
|
:mind(min),maxd(max),head(pe),stime(s),etime(e){}
|
|
PairList(const PairList& pl)
|
|
:mind(pl.mind),maxd(pl.maxd),head(pl.head),stime(pl.stime),etime(pl.etime){}
|
|
};
|
|
|
|
|
|
/*
|
|
It partitions the space into a list of cubes, and for each cube it records all
|
|
upoints inside. If the upoint intersect more than one cube, interpolates the
|
|
cube and put each sub part into its corresponding cube.
|
|
args[0] - 3D box
|
|
args[1] - an relation with attribute upoint
|
|
args[2] - attrName for upoint
|
|
args[3,4,5] - the number of cell for each dimension,x,y,t
|
|
|
|
*/
|
|
struct CellPart{
|
|
Rectangle<3>* box;
|
|
int attrpos;
|
|
int cellno[3];
|
|
int cellx,celly,cellt;
|
|
TupleType* resulttype;
|
|
unsigned int count;
|
|
unsigned int id;
|
|
Tuple* lasttuple;
|
|
double global_min;
|
|
std::vector<double> gmin;
|
|
std::vector<double> gmax;
|
|
std::vector<double> cellsize;
|
|
CellPart(Rectangle<3>* bbox,int x,int y,int z)
|
|
:box(bbox),cellx(x),celly(y),cellt(z){
|
|
count = 0;
|
|
id = 1;
|
|
resulttype = NULL;
|
|
for(unsigned int i = 0;i < 3;i++){
|
|
gmin.push_back(bbox->MinD(i));
|
|
gmax.push_back(bbox->MaxD(i));
|
|
}
|
|
cellsize.push_back(floor((gmax[0]-gmin[0])/cellx));
|
|
cellsize.push_back(floor((gmax[1]-gmin[1])/celly));
|
|
cellsize.push_back(floor((gmax[2]-gmin[2])/cellt));
|
|
cellno[0] = cellx;
|
|
cellno[1] = celly;
|
|
cellno[2] = cellt;
|
|
//
|
|
gmax[2] = gmax[2] - gmin[2];
|
|
global_min = gmin[2];
|
|
gmin[2] = 0;
|
|
//
|
|
for(unsigned int i = 0;i < 3;i++)
|
|
cout<<"size dimension "<<i<<" "<<cellsize[i]<<endl;
|
|
}
|
|
~CellPart(){if(resulttype != NULL)delete resulttype;}
|
|
|
|
std::vector<UPoint> ups;
|
|
std::vector<BBox<3> > cellbox; //store the box of each cell
|
|
|
|
void AssignUPinCell();
|
|
void AccessFunction(int depth,std::vector<long>& start_index,
|
|
std::vector<long>& end_index,std::vector<int>& pos,UPoint* up);
|
|
};
|
|
void CellPart::AccessFunction(int depth,std::vector<long>& start_index,
|
|
std::vector<long>& end_index,std::vector<int>& pos,UPoint* up)
|
|
{
|
|
if(depth == 2){
|
|
for(long i = start_index[depth]; i <= end_index[depth];i++){
|
|
pos[depth] = i;
|
|
long cellid = 1;
|
|
for(int j = depth;j >= 0;j--){
|
|
int k = j - 1;
|
|
int size_low = 1;
|
|
while( k >= 0){
|
|
size_low = size_low * cellno[k];
|
|
k--;
|
|
}
|
|
cellid += size_low * pos[j];
|
|
// cout<<cellid<<endl;
|
|
}
|
|
double min[3];
|
|
double max[3];
|
|
for(unsigned int j = 0;j < 3;j++){
|
|
min[j] = gmin[j] + pos[j]*cellsize[j];
|
|
max[j] = gmin[j] + (pos[j]+1)*cellsize[j];
|
|
}
|
|
Rectangle<3> cell_box(true,min,max);
|
|
// cell_box.Print(cout);
|
|
//interpolate up to small one
|
|
UPoint* tempup = new UPoint(*up);
|
|
if(tempup->timeInterval.start.ToDouble()*86400.0 - global_min < min[2]){
|
|
Instant start(datetime::instanttype);
|
|
start.ReadFrom((min[2] + global_min)/86400.0);
|
|
Point p0;
|
|
tempup->TemporalFunction(start,p0,true);
|
|
tempup->p0 = p0;
|
|
tempup->timeInterval.start = start;
|
|
|
|
}
|
|
if(tempup->timeInterval.end.ToDouble()*86400.0 - global_min > max[2]){
|
|
Instant end(datetime::instanttype);
|
|
end.ReadFrom((max[2] + global_min)/86400.0);
|
|
Point p1;
|
|
tempup->TemporalFunction(end,p1,true);
|
|
tempup->p1 = p1;
|
|
tempup->timeInterval.end = end;
|
|
|
|
}
|
|
if(tempup->p0.GetX() < min[0]){
|
|
double x = min[0];
|
|
double y = tempup->p0.GetY();
|
|
tempup->p0.Set(x,y);
|
|
}
|
|
if(tempup->p1.GetX() < min[0]){
|
|
double x = min[0];
|
|
double y = tempup->p1.GetY();
|
|
tempup->p0.Set(x,y);
|
|
}
|
|
if(tempup->p0.GetX() > max[0]){
|
|
double x = max[0];
|
|
double y = tempup->p0.GetY();
|
|
tempup->p0.Set(x,y);
|
|
}
|
|
if(tempup->p1.GetX() > max[0]){
|
|
double x = max[0];
|
|
double y = tempup->p1.GetY();
|
|
tempup->p0.Set(x,y);
|
|
}
|
|
if(tempup->p0.GetY() < min[1]){
|
|
double x = tempup->p0.GetX();
|
|
double y = min[1];
|
|
tempup->p0.Set(x,y);
|
|
}
|
|
if(tempup->p1.GetY() < min[1]){
|
|
double x = tempup->p0.GetX();
|
|
double y = min[1];
|
|
tempup->p1.Set(x,y);
|
|
}
|
|
if(tempup->p0.GetY() > max[1]){
|
|
double x = tempup->p0.GetX();
|
|
double y = max[1];
|
|
tempup->p0.Set(x,y);
|
|
}
|
|
if(tempup->p1.GetY() > max[1]){
|
|
double x = tempup->p0.GetX();
|
|
double y = max[1];
|
|
tempup->p1.Set(x,y);
|
|
}
|
|
// cout<<*tempup<<endl;
|
|
if(!AlmostEqual(tempup->timeInterval.start.ToDouble(),
|
|
tempup->timeInterval.end.ToDouble())){
|
|
cellbox.push_back(cell_box);
|
|
ups.push_back(*tempup);
|
|
}
|
|
delete tempup;
|
|
}
|
|
}else{
|
|
for(long i = start_index[depth];i <= end_index[depth];i++){
|
|
pos[depth] = i;
|
|
AccessFunction(depth+1,start_index,end_index,pos,up);
|
|
}
|
|
}
|
|
}
|
|
void CellPart::AssignUPinCell()
|
|
{
|
|
/*ups.clear();
|
|
cellbox.clear();
|
|
|
|
UPoint* up = (UPoint*)(lasttuple->GetAttribute(attrpos));
|
|
cout<<"proces unit "<<*up<<endl;
|
|
BBox<3> box = up->BoundingBox();
|
|
double boxmin[3],boxmax[3];
|
|
|
|
for(unsigned int i = 0;i < 3;i++){
|
|
boxmin[i] = box.MinD(i);
|
|
boxmax[i] = box.MaxD(i);
|
|
}
|
|
boxmin[2] = boxmin[2] * 86400.0 - global_min;
|
|
boxmax[2] = boxmax[2] * 86400.0 - global_min;
|
|
|
|
vector<double> lower;
|
|
vector<double> upper;
|
|
vector<long> start_index;
|
|
vector<long> end_index;
|
|
vector<int> pos;
|
|
|
|
for(unsigned int i = 0;i < 3;i++){
|
|
lower.push_back(boxmin[i]);
|
|
upper.push_back(boxmax[i]);
|
|
}
|
|
|
|
for(unsigned int i = 0;i < 3;i++){
|
|
start_index.push_back((long)floor((lower[i]-gmin[i])/cellsize[i]));
|
|
end_index.push_back((long)floor((upper[i]-gmin[i]) /cellsize[i]));
|
|
// cout<<"start "<<i<<" "<<start_index[i]<<endl;
|
|
// cout<<"end "<<i<<" "<<end_index[i]<<endl;
|
|
}
|
|
|
|
|
|
// cout<<"range "<<endl;
|
|
// for(unsigned int i = 0;i < 3;i++)
|
|
// cout<<boxmin[i]<<" "<<boxmax[i]<<endl;
|
|
|
|
// AccessFunction(0,start_index,end_index,pos,up);
|
|
|
|
///
|
|
vector<UPoint> tempups;
|
|
for(int i = start_index[2];i <= end_index[2];i++){
|
|
double t_min = gmin[2] + i*cellsize[2];
|
|
double t_max = gmin[2] + (i+1)*cellsize[2];
|
|
// cout<<t_min<<" "<<t_max<<endl;
|
|
Instant start(instanttype);
|
|
start.ReadFrom((t_min + global_min)/86400.0);
|
|
Instant end(instanttype);
|
|
end.ReadFrom((t_max + global_min)/86400.0);
|
|
// cout<<start<<" "<<end<<endl;
|
|
if(start < up->timeInterval.start)
|
|
start = up->timeInterval.start;
|
|
if(end > up->timeInterval.end)
|
|
end = up->timeInterval.end;
|
|
UPoint* upoint = new UPoint(*up);
|
|
Point p0,p1;
|
|
up->TemporalFunction(start,p0,true);;
|
|
up->TemporalFunction(end,p1,true);
|
|
upoint->p0 = p0;
|
|
upoint->p1 = p1;
|
|
upoint->timeInterval.start = start;
|
|
upoint->timeInterval.end = end;
|
|
tempups.push_back(*upoint);
|
|
cout<<*upoint<<endl;
|
|
delete upoint;
|
|
}
|
|
|
|
for(unsigned int i = 0;i < tempups.size();i++){
|
|
box = tempups[i].BoundingBox();
|
|
for(unsigned int j = 0;j < 3;j++){
|
|
boxmin[j] = box.MinD(j);
|
|
boxmax[j] = box.MaxD(j);
|
|
}
|
|
boxmin[2] = boxmin[2] * 86400.0 - global_min;
|
|
boxmax[2] = boxmax[2] * 86400.0 - global_min;
|
|
lower.clear();
|
|
upper.clear();
|
|
start_index.clear();
|
|
end_index.clear();
|
|
pos.clear();
|
|
for(unsigned int j = 0;j < 3;j++){
|
|
lower.push_back(boxmin[j]);
|
|
upper.push_back(boxmax[j]);
|
|
}
|
|
|
|
for(unsigned int j = 0;j < 3;i++){
|
|
start_index.push_back((long)floor((lower[j]-gmin[i])/cellsize[j]));
|
|
end_index.push_back((long)floor((upper[j]-gmin[i]) /cellsize[j]));
|
|
cout<<"start "<<j<<" "<<start_index[j]<<endl;
|
|
cout<<"end "<<j<<" "<<end_index[j]<<endl;
|
|
}
|
|
cout<<endl;
|
|
|
|
for(unsigned int i = 0;i < 3;i++)
|
|
pos.push_back(-1);
|
|
|
|
AccessFunction(0,start_index,end_index,pos,&tempups[i]);
|
|
/////////////
|
|
|
|
double min[3];
|
|
double max[3];
|
|
int position[2];
|
|
for(int i = start_index[0];i <= end_index[0];i++){
|
|
for(int j = start_index[1];j <= end_index[j];j++){
|
|
position[0] = i;
|
|
position[1] = j;
|
|
for(unsigned int k = 0;k < 2;k++){
|
|
min[k] = gmin[k] + position[k]*cellsize[k];
|
|
max[k] = gmin[k] + (position[k]+1)*cellsize[k];
|
|
}
|
|
//to be continued
|
|
}
|
|
}
|
|
|
|
}*/
|
|
|
|
}
|
|
|
|
/*const string MergertreeSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Example\" \"Comment\" ) "
|
|
"(<text>(rtree1<d> (tuple ((x1 t1)...(xn tn))) ti) x \n"
|
|
"(rtree2<d> (tuple ((x1 t1)...(xn tn))) ti) x "
|
|
" -> (rtree<d> (tuple ((x1 t1)...(xn tn))) ti)</text--->"
|
|
"<text>mergertree (_, _ )</text--->"
|
|
"<text>Merge Two RTrees (stored in the same file) </text--->"
|
|
"<text>query mergertree(rtree_1,rtree_2)</text--->"
|
|
"<text></text--->"
|
|
") )";*/
|
|
|
|
const std::string MergertreeSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Example\" \"Comment\" ) "
|
|
"(<text>(rtree1<d> (tuple ((x1 t1)...(xn tn))) ti) x \n"
|
|
"(rtree2<d> (tuple ((x1 t1)...(xn tn))) ti) x "
|
|
" -> (stream (tuple ((x1 t1)...(xn tn))) ti)</text--->"
|
|
"<text>mergertree (_, _ )</text--->"
|
|
"<text>Merge Two RTrees (stored in the same file) and "
|
|
"outputs the root node tuple</text--->"
|
|
"<text>query mergertree(rtree_1,rtree_2) consume</text--->"
|
|
"<text></text--->"
|
|
") )";
|
|
|
|
const std::string MergeCovSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Example\" \"Comment\" ) "
|
|
"(<text>(rtree1<d> (tuple ((x1 t1)...(xn tn))) ti) x \n"
|
|
"(rel1 (tuple ((x1 t1)...(xn tn)))) x (rel2 (tuple ((x1 t1)...(xn tn)))) x"
|
|
"(btree1 (tuple ((x1 t1)...(xn tn))) ti) x"
|
|
"(btree2 (tuple ((x1 t1)...(xn tn))) ti)"
|
|
" -> (stream (tuple ((x1 t1)...(xn tn)))) </text--->"
|
|
"<text>mergecov (_, _,_,_,_ )</text--->"
|
|
"<text>Merge Two Coverage Numbers </text--->"
|
|
"<text>query mergecov(rtree_1,rel1,rel2,btree1,btree2) count</text--->"
|
|
"<text></text--->"
|
|
") )";
|
|
|
|
const std::string MergeCov2Spec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Example\" \"Comment\" ) "
|
|
"(<text>(rtree1<d> (tuple ((x1 t1)...(xn tn))) ti) x \n"
|
|
"(rel1 (tuple ((x1 t1)...(xn tn)))) x (rel2 (tuple ((x1 t1)...(xn tn)))) x"
|
|
"(btree1 (tuple ((x1 t1)...(xn tn))) ti) x"
|
|
"(btree2 (tuple ((x1 t1)...(xn tn))) ti)"
|
|
" -> (stream (tuple ((x1 t1)...(xn tn)))) </text--->"
|
|
"<text>mergecov2(_,_,_)</text--->"
|
|
"<text>Update Coverage Numbers in some nodes in the rtree </text--->"
|
|
"<text>query mergecov2(rtree_1,rel,btree) count</text--->"
|
|
"<text></text--->"
|
|
") )";
|
|
|
|
/*
|
|
TypeMap fun for operator mergertree
|
|
|
|
*/
|
|
/*ListExpr MergeRTreeTypeMap(ListExpr args)
|
|
{
|
|
|
|
// check number of parameters
|
|
if( nl->IsEmpty(args) || nl->ListLength(args) != 2){
|
|
return listutils::typeError("Expecting exactly 2 arguments.");
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////
|
|
ListExpr firstpara = nl->First(args);
|
|
if(nl->ListLength(firstpara) != 4){
|
|
string err = "rtree(tuple(...) rect3 BOOL) expected";
|
|
ErrorReporter::ReportError(err);
|
|
return nl->TypeError();
|
|
}
|
|
|
|
if(!listutils::isRTreeDescription(firstpara)){
|
|
string err = "rtree(tuple(...) rect3 BOOL) expected";
|
|
ErrorReporter::ReportError(err);
|
|
return nl->TypeError();
|
|
}
|
|
|
|
|
|
if(!(nl->IsEqual(nl->First(firstpara),RTree2TID::BasicType()) ||
|
|
nl->IsEqual(nl->First(firstpara),RTree3TID::BasicType()) ||
|
|
nl->IsEqual(nl->First(firstpara),RTree4TID::BasicType()) ||
|
|
nl->IsEqual(nl->First(firstpara),RTree8TID::BasicType()))){
|
|
string err = "rtree(tuple(...) rect3 BOOL) expected";
|
|
ErrorReporter::ReportError(err);
|
|
return nl->TypeError();
|
|
}
|
|
///////////////////////////////////////////////////////////
|
|
|
|
ListExpr secondpara = nl->Second(args);
|
|
if(nl->ListLength(secondpara) != 4){
|
|
string err = "rtree(tuple(...) rect BOOL) expected";
|
|
ErrorReporter::ReportError(err);
|
|
return nl->TypeError();
|
|
}
|
|
if(!listutils::isRTreeDescription(secondpara)){
|
|
string err = "rtree(tuple(...) rect3 BOOL) expected";
|
|
ErrorReporter::ReportError(err);
|
|
return nl->TypeError();
|
|
}
|
|
|
|
if(!(nl->IsEqual(nl->First(firstpara),"rtree2") ||
|
|
nl->IsEqual(nl->First(firstpara),RTree3TID::BasicType()) ||
|
|
nl->IsEqual(nl->First(firstpara),RTree4TID::BasicType()) ||
|
|
nl->IsEqual(nl->First(firstpara),RTree8TID::BasicType()))){
|
|
string err = "rtree(tuple(...) rect BOOL) expected";
|
|
ErrorReporter::ReportError(err);
|
|
return nl->TypeError();
|
|
}
|
|
return nl->First(args);
|
|
}*/
|
|
|
|
/*
|
|
TypeMap fun for operator mergertree
|
|
|
|
*/
|
|
ListExpr MergeRTreeTypeMap(ListExpr args)
|
|
{
|
|
|
|
// check number of parameters
|
|
if( nl->IsEmpty(args) || nl->ListLength(args) != 2){
|
|
return listutils::typeError("Expecting exactly 2 arguments.");
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////
|
|
ListExpr firstpara = nl->First(args);
|
|
if(nl->ListLength(firstpara) != 4){
|
|
std::string err = "rtree(tuple(...) rect3 BOOL) expected";
|
|
ErrorReporter::ReportError(err);
|
|
return nl->TypeError();
|
|
}
|
|
|
|
if(!listutils::isRTreeDescription(firstpara)){
|
|
std::string err = "rtree(tuple(...) rect3 BOOL) expected";
|
|
ErrorReporter::ReportError(err);
|
|
return nl->TypeError();
|
|
}
|
|
|
|
|
|
if(!(nl->IsEqual(nl->First(firstpara),RTree2TID::BasicType()) ||
|
|
nl->IsEqual(nl->First(firstpara),RTree3TID::BasicType()) ||
|
|
nl->IsEqual(nl->First(firstpara),RTree4TID::BasicType()) ||
|
|
nl->IsEqual(nl->First(firstpara),RTree8TID::BasicType()))){
|
|
std::string err = "rtree(tuple(...) rect3 BOOL) expected";
|
|
ErrorReporter::ReportError(err);
|
|
return nl->TypeError();
|
|
}
|
|
///////////////////////////////////////////////////////////
|
|
|
|
ListExpr secondpara = nl->Second(args);
|
|
if(nl->ListLength(secondpara) != 4){
|
|
std::string err = "rtree(tuple(...) rect BOOL) expected";
|
|
ErrorReporter::ReportError(err);
|
|
return nl->TypeError();
|
|
}
|
|
if(!listutils::isRTreeDescription(secondpara)){
|
|
std::string err = "rtree(tuple(...) rect3 BOOL) expected";
|
|
ErrorReporter::ReportError(err);
|
|
return nl->TypeError();
|
|
}
|
|
|
|
if(!(nl->IsEqual(nl->First(firstpara),"rtree2") ||
|
|
nl->IsEqual(nl->First(firstpara),RTree3TID::BasicType()) ||
|
|
nl->IsEqual(nl->First(firstpara),RTree4TID::BasicType()) ||
|
|
nl->IsEqual(nl->First(firstpara),RTree8TID::BasicType()))){
|
|
std::string err = "rtree(tuple(...) rect BOOL) expected";
|
|
ErrorReporter::ReportError(err);
|
|
return nl->TypeError();
|
|
}
|
|
// return nl->First(args);
|
|
ListExpr reslist = nl->TwoElemList(
|
|
nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom(Tuple::BasicType()),
|
|
nl->TwoElemList(
|
|
nl->TwoElemList(nl->SymbolAtom("nodeId"),
|
|
nl->SymbolAtom(CcInt::BasicType())),
|
|
nl->TwoElemList(nl->SymbolAtom("level"),
|
|
nl->SymbolAtom(CcInt::BasicType()))
|
|
)
|
|
)
|
|
);
|
|
return reslist;
|
|
}
|
|
|
|
/*
|
|
TypeMap fun for operator mergecov
|
|
|
|
*/
|
|
ListExpr MergeCovTypeMap(ListExpr args)
|
|
{
|
|
|
|
// check number of parameters
|
|
if( nl->IsEmpty(args) || nl->ListLength(args) != 5){
|
|
return listutils::typeError("Expecting exactly 5 arguments.");
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////
|
|
ListExpr firstpara = nl->First(args);
|
|
if(nl->ListLength(firstpara) != 4){
|
|
std::string err = "rtree(tuple(...) rect3 BOOL) expected";
|
|
ErrorReporter::ReportError(err);
|
|
return nl->TypeError();
|
|
}
|
|
|
|
if(!listutils::isRTreeDescription(firstpara)){
|
|
std::string err = "rtree(tuple(...) rect3 BOOL) expected";
|
|
ErrorReporter::ReportError(err);
|
|
return nl->TypeError();
|
|
}
|
|
|
|
|
|
if(!(nl->IsEqual(nl->First(firstpara),RTree2TID::BasicType()) ||
|
|
nl->IsEqual(nl->First(firstpara),RTree3TID::BasicType()) ||
|
|
nl->IsEqual(nl->First(firstpara),RTree4TID::BasicType()) ||
|
|
nl->IsEqual(nl->First(firstpara),RTree8TID::BasicType()))){
|
|
std::string err = "rtree(tuple(...) rect3 BOOL) expected";
|
|
ErrorReporter::ReportError(err);
|
|
return nl->TypeError();
|
|
}
|
|
///////////////////////////////////////////////////////////
|
|
|
|
ListExpr second = nl->Second(args);
|
|
ListExpr third = nl->Third(args);
|
|
ListExpr fourth = nl->Fourth(args);
|
|
ListExpr fifth = nl->Fifth(args);
|
|
if(!listutils::isRelDescription(second) ||
|
|
!listutils::isRelDescription(third) ||
|
|
!listutils::isBTreeDescription(fourth) ||
|
|
!listutils::isBTreeDescription(fifth)){
|
|
std::string err = "rtree x rel1 x rel2 x btree1 x btree2 expected";
|
|
ErrorReporter::ReportError(err);
|
|
return nl->TypeError();
|
|
}
|
|
ListExpr res = nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->Second(nl->Third(args)));
|
|
return res;
|
|
|
|
/* return nl->TwoElemList(
|
|
nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom(Tuple::BasicType()),
|
|
nl->ThreeElemList(
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("NodeId"),
|
|
nl->SymbolAtom(CcInt::BasicType())
|
|
),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("RecId"),
|
|
nl->SymbolAtom(CcInt::BasicType())
|
|
),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("Coverage"),
|
|
nl->SymbolAtom(UInt::BasicType())
|
|
))));*/
|
|
}
|
|
|
|
/*
|
|
TypeMap fun for operator mergecov2
|
|
|
|
*/
|
|
ListExpr MergeCov2TypeMap(ListExpr args)
|
|
{
|
|
|
|
// check number of parameters
|
|
if( nl->IsEmpty(args) || nl->ListLength(args) != 3){
|
|
return listutils::typeError("Expecting exactly 3 arguments.");
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////
|
|
ListExpr firstpara = nl->First(args);
|
|
if(nl->ListLength(firstpara) != 4){
|
|
std::string err = "rtree(tuple(...) rect3 BOOL) expected";
|
|
ErrorReporter::ReportError(err);
|
|
return nl->TypeError();
|
|
}
|
|
|
|
if(!listutils::isRTreeDescription(firstpara)){
|
|
std::string err = "rtree(tuple(...) rect3 BOOL) expected";
|
|
ErrorReporter::ReportError(err);
|
|
return nl->TypeError();
|
|
}
|
|
|
|
|
|
if(!(nl->IsEqual(nl->First(firstpara),RTree2TID::BasicType()) ||
|
|
nl->IsEqual(nl->First(firstpara),RTree3TID::BasicType()) ||
|
|
nl->IsEqual(nl->First(firstpara),RTree4TID::BasicType()) ||
|
|
nl->IsEqual(nl->First(firstpara),RTree8TID::BasicType()))){
|
|
std::string err = "rtree(tuple(...) rect3 BOOL) expected";
|
|
ErrorReporter::ReportError(err);
|
|
return nl->TypeError();
|
|
}
|
|
///////////////////////////////////////////////////////////
|
|
|
|
ListExpr second = nl->Second(args);
|
|
ListExpr third = nl->Third(args);
|
|
if(!listutils::isRelDescription(second) ||
|
|
!listutils::isBTreeDescription(third)){
|
|
std::string err = "rtree x rel x btree";
|
|
ErrorReporter::ReportError(err);
|
|
return nl->TypeError();
|
|
}
|
|
ListExpr res = nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->Second(nl->Second(args)));
|
|
return res;
|
|
|
|
/* return nl->TwoElemList(
|
|
nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom(Tuple::BasicType()),
|
|
nl->ThreeElemList(
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("NodeId"),
|
|
nl->SymbolAtom(CcInt::BasicType())
|
|
),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("RecId"),
|
|
nl->SymbolAtom(CcInt::BasicType())
|
|
),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("Coverage"),
|
|
nl->SymbolAtom(UInt::BasicType())
|
|
))));*/
|
|
}
|
|
|
|
/*
|
|
Merge two input r-trees into one r-tree and record in the same file
|
|
|
|
*/
|
|
/*int MergeRTreeFun(Word* args, Word& result, int message,Word& local,
|
|
Supplier s)
|
|
{
|
|
R_Tree<3,TupleId>* rtree_in1 = static_cast<R_Tree<3,TupleId>*>(args[0].addr);
|
|
R_Tree<3,TupleId>* rtree_in2 = static_cast<R_Tree<3,TupleId>*>(args[1].addr);
|
|
|
|
R_Tree<3,TupleId>* rtree_temp = (R_Tree<3,TupleId>*)qp->ResultStorage(s).addr;
|
|
rtree_temp->CloseFile();
|
|
|
|
result = qp->ResultStorage(s);
|
|
R_Tree<3, TupleId> *rtree = new R_Tree<3,TupleId>(rtree_in1->FileId(),true);
|
|
rtree->MergeRtree(rtree_in1,rtree_in2);
|
|
result.setAddr(rtree);
|
|
return 0;
|
|
}*/
|
|
|
|
int MergeRTreeFun(Word* args, Word& result, int message,Word& local,
|
|
Supplier s)
|
|
{
|
|
static int flag = 0;
|
|
switch(message){
|
|
case OPEN:
|
|
return 0;
|
|
case REQUEST:
|
|
if(flag == 0){
|
|
R_Tree<3,TupleId>* rtree_in1 =
|
|
static_cast<R_Tree<3,TupleId>*>(args[0].addr);
|
|
rtree_in1->MergeRtree();
|
|
Tuple* t = new Tuple(nl->Second(GetTupleResultType(s)));
|
|
t->PutAttribute(0,new CcInt(true,rtree_in1->RootRecordId()));
|
|
t->PutAttribute(1,new CcInt(true,0));
|
|
result.setAddr(t);
|
|
flag = 1;
|
|
return YIELD;
|
|
}else{
|
|
flag = 0;
|
|
return CANCEL;
|
|
}
|
|
case CLOSE:
|
|
|
|
qp->SetModified(qp->GetSon(s,0));
|
|
// qp->SetModified(qp->GetSon(s,1));
|
|
local.setAddr(Address(0));
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
Merge two input coverage numbers
|
|
|
|
*/
|
|
struct Cov{
|
|
R_Tree<3,TupleId>* rtree;
|
|
Relation* cov1;
|
|
Relation* cov2;
|
|
BTree* btree1;
|
|
BTree* btree2;
|
|
TupleType* tupletype;
|
|
int index1;
|
|
int index2;
|
|
int index3;
|
|
bool first;
|
|
bool second;
|
|
bool third;
|
|
Relation* cov3;
|
|
Cov( R_Tree<3,TupleId>* rt, Relation* r1,Relation* r2,
|
|
BTree* bt1,BTree* bt2,ListExpr tt)
|
|
:rtree(rt),cov1(r1),cov2(r2),btree1(bt1),btree2(bt2)
|
|
{
|
|
index1 = index2 = index3 = 1;
|
|
first = true;
|
|
second = true;
|
|
third = false;
|
|
tupletype = new TupleType(tt);
|
|
cov3 = NULL;
|
|
}
|
|
Cov( R_Tree<3,TupleId>* rt, Relation* r1, BTree* bt1,ListExpr tt)
|
|
:rtree(rt),cov1(r1),cov2(NULL),btree1(bt1),btree2(NULL)
|
|
{
|
|
index3 = 1;
|
|
third = false;
|
|
tupletype = new TupleType(tt);
|
|
cov3 = NULL;
|
|
}
|
|
|
|
~Cov()
|
|
{
|
|
tupletype->DeleteIfAllowed();
|
|
tupletype = NULL;
|
|
if(cov3 != NULL)
|
|
delete cov3;
|
|
}
|
|
void CalCov()
|
|
{
|
|
cov3 = new Relation(tupletype,true);
|
|
// rtree->MergeCov(cov1,cov2,cov3,btree1,btree2);
|
|
const int dim = 3;
|
|
SmiRecordId header_path_rec_id = rtree->Record_Path_Id();
|
|
R_TreeNode<dim,TupleId>* node = rtree->GetMyNode(header_path_rec_id,
|
|
false, rtree->MinEntries(0),rtree->MaxEntries(0));
|
|
|
|
for(int i = 0;i < node->EntryCount();i++){
|
|
R_TreeInternalEntry<dim> e =
|
|
(R_TreeInternalEntry<dim>&)(*node)[i];
|
|
// cout<<"rec_id "<<e.pointer<<endl;
|
|
CcInt* id = new CcInt(true,e.pointer);
|
|
BTreeIterator* iter1 = btree1->ExactMatch(id);
|
|
BTreeIterator* iter2 = btree2->ExactMatch(id);
|
|
bool flag1 = false;
|
|
bool flag2 = false;
|
|
//get coverage from the first relation
|
|
//delete them from the relation and create new ones into it
|
|
int NodeId1=0;
|
|
|
|
while(iter1->Next()){
|
|
flag1 = true;
|
|
Tuple* tuple1 = cov1->GetTuple(iter1->GetId(), false);
|
|
NodeId1 = ((CcInt*)tuple1->GetAttribute(0))->GetIntval();
|
|
// assert(cov1->DeleteTuple(tuple1));
|
|
tuple1->DeleteIfAllowed();
|
|
}
|
|
|
|
//calculate the new coverage tuple and insert back to the relation
|
|
if(flag1){
|
|
R_TreeNode<dim,TupleId>* n = rtree->GetMyNode(e.pointer,false,
|
|
rtree->MinEntries(0),rtree->MaxEntries(0));
|
|
MInt tmp(0);
|
|
for(int j = 0;j < n->EntryCount();j++){
|
|
R_TreeInternalEntry<dim> entry =
|
|
(R_TreeInternalEntry<dim>&)(*n)[j];
|
|
CcInt* cur_id = new CcInt(true,entry.pointer);
|
|
BTreeIterator* iter1_1 = btree1->ExactMatch(cur_id);
|
|
MInt tmp1(0);
|
|
while(iter1_1->Next()){
|
|
Tuple* tuple1 = cov1->GetTuple(iter1_1->GetId(), false);
|
|
UInt* ui = (UInt*)tuple1->GetAttribute(2);
|
|
tmp1.Add(*ui);
|
|
tuple1->DeleteIfAllowed();
|
|
}
|
|
delete iter1_1;
|
|
BTreeIterator* iter2_2 = btree2->ExactMatch(cur_id);
|
|
MInt tmp2(0);
|
|
while(iter2_2->Next()){
|
|
Tuple* tuple2 = cov2->GetTuple(iter2_2->GetId(), false);
|
|
UInt* ui = (UInt*)tuple2->GetAttribute(2);
|
|
tmp2.Add(*ui);
|
|
tuple2->DeleteIfAllowed();
|
|
}
|
|
delete iter2_2;
|
|
delete cur_id;
|
|
// tmp1.Print(cout);
|
|
// tmp2.Print(cout);
|
|
MInt temp(0);
|
|
tmp.PlusExtend(&tmp1,temp);
|
|
tmp.CopyFrom(&temp);
|
|
tmp.PlusExtend(&tmp2,temp);
|
|
tmp.CopyFrom(&temp);
|
|
}
|
|
// tmp.Print(cout);
|
|
MInt result(0);
|
|
tmp.Hat(result);
|
|
// result.Print(cout);
|
|
for(int i = 0;i < result.GetNoComponents();i++){
|
|
UInt ui;
|
|
result.Get(i,ui);
|
|
Tuple* resTuple = new Tuple(cov3->GetTupleType());
|
|
CcInt* ni = new CcInt(true,NodeId1);
|
|
resTuple->PutAttribute(0,ni);
|
|
CcInt* ri = new CcInt(true,e.pointer);
|
|
resTuple->PutAttribute(1,ri);
|
|
resTuple->PutAttribute(2,new UInt(ui));
|
|
cov3->AppendTuple(resTuple);
|
|
// cout<<*resTuple<<endl;
|
|
resTuple->DeleteIfAllowed();
|
|
}
|
|
delete n;
|
|
}
|
|
delete iter1;
|
|
|
|
// int NodeId2;
|
|
//get coverage from the second relation
|
|
while(iter2->Next()){
|
|
flag2 = true;
|
|
Tuple* tuple2 = cov2->GetTuple(iter2->GetId(), false);
|
|
//NodeId2 = ((CcInt*)tuple2->GetAttribute(0))->GetIntval();
|
|
// assert(cov2->DeleteTuple(tuple2));
|
|
tuple2->DeleteIfAllowed();
|
|
}
|
|
|
|
//calculate the new coverage tuple and insert back to the relation
|
|
if(flag2){
|
|
R_TreeNode<dim,TupleId>* n = rtree->GetMyNode(e.pointer,false,
|
|
rtree->MinEntries(0),rtree->MaxEntries(0));
|
|
MInt tmp(0);
|
|
for(int j = 0;j < n->EntryCount();j++){
|
|
R_TreeInternalEntry<dim> entry =
|
|
(R_TreeInternalEntry<dim>&)(*n)[j];
|
|
CcInt* cur_id = new CcInt(true,entry.pointer);
|
|
BTreeIterator* iter1_1 = btree1->ExactMatch(cur_id);
|
|
MInt tmp1(0);
|
|
while(iter1_1->Next()){
|
|
Tuple* tuple1 = cov1->GetTuple(iter1_1->GetId(), false);
|
|
UInt* ui = (UInt*)tuple1->GetAttribute(2);
|
|
tmp1.Add(*ui);
|
|
tuple1->DeleteIfAllowed();
|
|
}
|
|
delete iter1_1;
|
|
BTreeIterator* iter2_2 = btree2->ExactMatch(cur_id);
|
|
MInt tmp2(0);
|
|
while(iter2_2->Next()){
|
|
Tuple* tuple2 = cov2->GetTuple(iter2_2->GetId(), false);
|
|
UInt* ui = (UInt*)tuple2->GetAttribute(2);
|
|
tmp2.Add(*ui);
|
|
tuple2->DeleteIfAllowed();
|
|
}
|
|
delete iter2_2;
|
|
delete cur_id;
|
|
MInt temp(0);
|
|
tmp.PlusExtend(&tmp1,temp);
|
|
tmp.CopyFrom(&temp);
|
|
tmp.PlusExtend(&tmp2,temp);
|
|
tmp.CopyFrom(&temp);
|
|
}
|
|
|
|
MInt result(0);
|
|
tmp.Hat(result);
|
|
for(int i = 0;i < result.GetNoComponents();i++){
|
|
UInt ui;
|
|
result.Get(i,ui);
|
|
Tuple* resTuple = new Tuple(cov3->GetTupleType());
|
|
CcInt* ni = new CcInt(true,NodeId1);
|
|
resTuple->PutAttribute(0,ni);
|
|
CcInt* ri = new CcInt(true,e.pointer);
|
|
resTuple->PutAttribute(1,ri);
|
|
resTuple->PutAttribute(2,new UInt(ui));
|
|
cov3->AppendTuple(resTuple);
|
|
resTuple->DeleteIfAllowed();
|
|
}
|
|
delete n;
|
|
}
|
|
delete iter2;
|
|
|
|
//a new node, get its sons from both coverage relation
|
|
if(flag1 == false && flag2 == false){
|
|
R_TreeNode<dim,TupleId>* n = rtree->GetMyNode(e.pointer,false,
|
|
rtree->MinEntries(0),rtree->MaxEntries(0));
|
|
MInt tmp(0);
|
|
assert(n->EntryCount() == 2);
|
|
for(int j = 0;j < n->EntryCount();j++){
|
|
R_TreeInternalEntry<dim> entry =
|
|
(R_TreeInternalEntry<dim>&)(*n)[j];
|
|
CcInt* cur_id = new CcInt(true,entry.pointer);
|
|
BTreeIterator* iter1_1 = btree1->ExactMatch(cur_id);
|
|
MInt tmp1(0);
|
|
while(iter1_1->Next()){
|
|
Tuple* tuple1 = cov1->GetTuple(iter1_1->GetId(), false);
|
|
UInt* ui = (UInt*)tuple1->GetAttribute(2);
|
|
tmp1.Add(*ui);
|
|
tuple1->DeleteIfAllowed();
|
|
}
|
|
delete iter1_1;
|
|
BTreeIterator* iter2_2 = btree2->ExactMatch(cur_id);
|
|
MInt tmp2(0);
|
|
while(iter2_2->Next()){
|
|
Tuple* tuple2 = cov2->GetTuple(iter2_2->GetId(), false);
|
|
UInt* ui = (UInt*)tuple2->GetAttribute(2);
|
|
tmp2.Add(*ui);
|
|
tuple2->DeleteIfAllowed();
|
|
}
|
|
delete iter2_2;
|
|
delete cur_id;
|
|
// tmp1.Print(cout);
|
|
// tmp2.Print(cout);
|
|
MInt temp(0);
|
|
tmp.PlusExtend(&tmp1,temp);
|
|
tmp.CopyFrom(&temp);
|
|
tmp.PlusExtend(&tmp2,temp);
|
|
tmp.CopyFrom(&temp);
|
|
}
|
|
// tmp.Print(cout);
|
|
MInt result(0);
|
|
tmp.Hat(result);
|
|
// result.Print(cout);
|
|
for(int i = 0;i < result.GetNoComponents();i++){
|
|
UInt ui;
|
|
result.Get(i,ui);
|
|
Tuple* resTuple = new Tuple(cov3->GetTupleType());
|
|
CcInt* ni = new CcInt(true,e.pointer);
|
|
resTuple->PutAttribute(0,ni);
|
|
CcInt* ri = new CcInt(true,e.pointer);
|
|
resTuple->PutAttribute(1,ri);
|
|
resTuple->PutAttribute(2,new UInt(ui));
|
|
cov3->AppendTuple(resTuple);
|
|
// cout<<*resTuple<<endl;
|
|
resTuple->DeleteIfAllowed();
|
|
}
|
|
delete n;
|
|
}
|
|
|
|
delete id;
|
|
assert(flag1 == false || flag2 == false);
|
|
}
|
|
|
|
delete node;
|
|
|
|
// cout<<"cov3 no_of_tuples "<<cov3->GetNoTuples()<<endl;
|
|
if(cov3->GetNoTuples() > 0)
|
|
third = true;
|
|
|
|
}
|
|
|
|
void CalCov2()
|
|
{
|
|
int attr_pos = 2;
|
|
cov3 = new Relation(tupletype,true);
|
|
// rtree->MergeCov(cov1,cov2,cov3,btree1,btree2);
|
|
const int dim = 3;
|
|
SmiRecordId header_path_rec_id = rtree->Record_Path_Id();
|
|
R_TreeNode<dim,TupleId>* node = rtree->GetMyNode(header_path_rec_id,
|
|
false, rtree->MinEntries(0),rtree->MaxEntries(0));
|
|
|
|
for(int i = 0;i < node->EntryCount();i++){
|
|
R_TreeInternalEntry<dim> e =
|
|
(R_TreeInternalEntry<dim>&)(*node)[i];
|
|
// cout<<"rec_id "<<e.pointer<<endl;
|
|
CcInt* id = new CcInt(true,e.pointer);
|
|
BTreeIterator* iter1 = btree1->ExactMatch(id);
|
|
|
|
bool flag1 = false;
|
|
//get coverage from the first relation
|
|
//delete them from the relation and create new ones into it
|
|
int NodeId1=0;
|
|
|
|
while(iter1->Next()){
|
|
flag1 = true;
|
|
Tuple* tuple1 = cov1->GetTuple(iter1->GetId(), false);
|
|
NodeId1 = ((CcInt*)tuple1->GetAttribute(0))->GetIntval();
|
|
// assert(cov1->DeleteTuple(tuple1));
|
|
tuple1->DeleteIfAllowed();
|
|
}
|
|
|
|
//calculate the new coverage tuple and insert back to the relation
|
|
if(flag1){
|
|
R_TreeNode<dim,TupleId>* n = rtree->GetMyNode(e.pointer,false,
|
|
rtree->MinEntries(0),rtree->MaxEntries(0));
|
|
MInt tmp(0);
|
|
for(int j = 0;j < n->EntryCount();j++){
|
|
R_TreeInternalEntry<dim> entry =
|
|
(R_TreeInternalEntry<dim>&)(*n)[j];
|
|
CcInt* cur_id = new CcInt(true,entry.pointer);
|
|
BTreeIterator* iter1_1 = btree1->ExactMatch(cur_id);
|
|
MInt tmp1(0);
|
|
while(iter1_1->Next()){
|
|
Tuple* tuple1 = cov1->GetTuple(iter1_1->GetId(), false);
|
|
// cout<<"before "<<*tuple1<<endl;
|
|
UInt* ui = (UInt*)tuple1->GetAttribute(2);
|
|
tmp1.Add(*ui);
|
|
tuple1->DeleteIfAllowed();
|
|
}
|
|
delete iter1_1;
|
|
delete cur_id;
|
|
// tmp1.Print(cout);
|
|
// tmp2.Print(cout);
|
|
MInt temp(0);
|
|
tmp.PlusExtend(&tmp1,temp);
|
|
tmp.CopyFrom(&temp);
|
|
}
|
|
// tmp.Print(cout);
|
|
MInt result(0);
|
|
tmp.Hat(result);
|
|
// result.Print(cout);
|
|
|
|
///////////////////Update the Attribute////////////////////
|
|
BTreeIterator* iter2 = btree1->ExactMatch(id);
|
|
while(iter2->Next()){
|
|
Tuple* tuple1 = cov1->GetTuple(iter2->GetId(), false);
|
|
// cout<<"before "<<endl;
|
|
UInt* ui = (UInt*)tuple1->GetAttribute(2);
|
|
std::vector<int> xindices;
|
|
std::vector<Attribute*> xattrs;
|
|
xindices.push_back(attr_pos);
|
|
UInt* newui = new UInt(*ui);
|
|
newui->constValue.Set(-1);
|
|
xattrs.push_back(new UInt(*newui));
|
|
delete newui;
|
|
cov1->UpdateTuple(tuple1,xindices,xattrs);
|
|
// cout<<"after "<<*tuple1<<endl;
|
|
//////////////////////////////////////////////////////////
|
|
tuple1->DeleteIfAllowed();
|
|
}
|
|
delete iter2;
|
|
|
|
|
|
for(int i = 0;i < result.GetNoComponents();i++){
|
|
UInt ui;
|
|
result.Get(i,ui);
|
|
Tuple* resTuple = new Tuple(cov3->GetTupleType());
|
|
CcInt* ni = new CcInt(true,NodeId1);
|
|
resTuple->PutAttribute(0,ni);
|
|
CcInt* ri = new CcInt(true,e.pointer);
|
|
resTuple->PutAttribute(1,ri);
|
|
resTuple->PutAttribute(2,new UInt(ui));
|
|
cov3->AppendTuple(resTuple);
|
|
// cout<<"newresult "<<*resTuple<<endl;
|
|
resTuple->DeleteIfAllowed();
|
|
}
|
|
delete n;
|
|
}
|
|
delete iter1;
|
|
|
|
|
|
//a new node, get its sons from both coverage relation
|
|
if(flag1 == false){
|
|
R_TreeNode<dim,TupleId>* n = rtree->GetMyNode(e.pointer,false,
|
|
rtree->MinEntries(0),rtree->MaxEntries(0));
|
|
MInt tmp(0);
|
|
// assert(n->EntryCount() == 2);/////
|
|
assert(1 <= n->EntryCount() && n->EntryCount() <= 2);
|
|
for(int j = 0;j < n->EntryCount();j++){
|
|
R_TreeInternalEntry<dim> entry =
|
|
(R_TreeInternalEntry<dim>&)(*n)[j];
|
|
CcInt* cur_id = new CcInt(true,entry.pointer);
|
|
BTreeIterator* iter1_1 = btree1->ExactMatch(cur_id);
|
|
MInt tmp1(0);
|
|
while(iter1_1->Next()){
|
|
Tuple* tuple1 = cov1->GetTuple(iter1_1->GetId(), false);
|
|
UInt* ui = (UInt*)tuple1->GetAttribute(2);
|
|
tmp1.Add(*ui);
|
|
tuple1->DeleteIfAllowed();
|
|
}
|
|
delete iter1_1;
|
|
|
|
delete cur_id;
|
|
// tmp1.Print(cout);
|
|
// tmp2.Print(cout);
|
|
MInt temp(0);
|
|
tmp.PlusExtend(&tmp1,temp);
|
|
tmp.CopyFrom(&temp);
|
|
}
|
|
// tmp.Print(cout);
|
|
MInt result(0);
|
|
tmp.Hat(result);
|
|
// result.Print(cout);
|
|
for(int i = 0;i < result.GetNoComponents();i++){
|
|
UInt ui;
|
|
result.Get(i,ui);
|
|
Tuple* resTuple = new Tuple(cov3->GetTupleType());
|
|
CcInt* ni = new CcInt(true,e.pointer);
|
|
resTuple->PutAttribute(0,ni);
|
|
CcInt* ri = new CcInt(true,e.pointer);
|
|
resTuple->PutAttribute(1,ri);
|
|
resTuple->PutAttribute(2,new UInt(ui));
|
|
cov3->AppendTuple(resTuple);
|
|
// cout<<*resTuple<<endl;
|
|
resTuple->DeleteIfAllowed();
|
|
}
|
|
delete n;
|
|
}
|
|
|
|
delete id;
|
|
|
|
}
|
|
|
|
delete node;
|
|
|
|
// cout<<"cov3 no_of_tuples "<<cov3->GetNoTuples()<<endl;
|
|
if(cov3->GetNoTuples() > 0)
|
|
third = true;
|
|
|
|
}
|
|
};
|
|
|
|
/*
|
|
Merge two input coverage numbers
|
|
|
|
*/
|
|
|
|
int MergeCovFun(Word* args, Word& result, int message,Word& local,
|
|
Supplier s)
|
|
{
|
|
switch(message){
|
|
case OPEN:{
|
|
// cout<<"Open"<<endl;
|
|
if(local.addr)
|
|
delete static_cast<Cov*>(local.addr);
|
|
ListExpr resultType =
|
|
SecondoSystem::GetCatalog()->NumericType(qp->GetType(s));
|
|
|
|
R_Tree<3,TupleId>* rtree_in = static_cast<R_Tree<3,TupleId>*>(args[0].addr);
|
|
|
|
Relation* cov1 = (Relation*)args[1].addr;
|
|
Relation* cov2 = (Relation*)args[2].addr;
|
|
BTree* btree1 = (BTree*)args[3].addr;
|
|
BTree* btree2 = (BTree*)args[4].addr;
|
|
local.addr =
|
|
new Cov(rtree_in,cov1,cov2,btree1,btree2,nl->Second(resultType));
|
|
Cov* cov = static_cast<Cov*>(local.addr);
|
|
cov->CalCov();
|
|
return 0;
|
|
|
|
// R_Tree<3, TupleId> *rtree = new R_Tree<3,TupleId>(rtree_in1->FileId(),true);
|
|
// rtree->MergeRtree(rtree_in1,rtree_in2);
|
|
|
|
}
|
|
case REQUEST:{
|
|
// cout<<"request"<<endl;
|
|
Cov* cov = static_cast<Cov*>(local.addr);
|
|
if(cov->first){ //copy the first coverage number rel
|
|
assert(cov->index1 <= cov->cov1->GetNoTuples());
|
|
Tuple* tuple = cov->cov1->GetTuple(cov->index1, false);
|
|
result.addr = tuple;
|
|
cov->index1++;
|
|
if(cov->index1 > cov->cov1->GetNoTuples())
|
|
cov->first = false;
|
|
return YIELD;
|
|
}
|
|
if(cov->second){
|
|
assert(cov->index2 <= cov->cov2->GetNoTuples());
|
|
Tuple* tuple = cov->cov2->GetTuple(cov->index2, false);
|
|
result.addr = tuple;
|
|
cov->index2++;
|
|
if(cov->index2 > cov->cov2->GetNoTuples())
|
|
cov->second = false;
|
|
return YIELD;
|
|
}
|
|
if(cov->third){
|
|
assert(cov->index3 <= cov->cov3->GetNoTuples());
|
|
Tuple* tuple = cov->cov3->GetTuple(cov->index3, false);
|
|
result.addr = tuple;
|
|
cov->index3++;
|
|
if(cov->index3 > cov->cov3->GetNoTuples())
|
|
cov->third = false;
|
|
return YIELD;
|
|
}
|
|
|
|
return CANCEL;
|
|
}
|
|
case CLOSE:{
|
|
Cov* cov = static_cast<Cov*>(local.addr);
|
|
if(cov){
|
|
delete cov;
|
|
local.setAddr(0);
|
|
}
|
|
return 0;
|
|
}
|
|
default: assert(false);
|
|
}
|
|
}
|
|
|
|
/*
|
|
Merge two input coverage numbers
|
|
|
|
*/
|
|
|
|
int MergeCov2Fun(Word* args, Word& result, int message,Word& local,
|
|
Supplier s)
|
|
{
|
|
switch(message){
|
|
case OPEN:{
|
|
// cout<<"Open"<<endl;
|
|
if(local.addr)
|
|
delete static_cast<Cov*>(local.addr);
|
|
ListExpr resultType =
|
|
SecondoSystem::GetCatalog()->NumericType(qp->GetType(s));
|
|
|
|
R_Tree<3,TupleId>* rtree_in = static_cast<R_Tree<3,TupleId>*>(args[0].addr);
|
|
|
|
Relation* cov1 = (Relation*)args[1].addr;
|
|
|
|
BTree* btree1 = (BTree*)args[2].addr;
|
|
local.addr =
|
|
new Cov(rtree_in,cov1,btree1,nl->Second(resultType));
|
|
Cov* cov = static_cast<Cov*>(local.addr);
|
|
cov->CalCov2();
|
|
return 0;
|
|
|
|
// R_Tree<3, TupleId> *rtree = new R_Tree<3,TupleId>(rtree_in1->FileId(),true);
|
|
// rtree->MergeRtree(rtree_in1,rtree_in2);
|
|
|
|
}
|
|
case REQUEST:{
|
|
// cout<<"request"<<endl;
|
|
Cov* cov = static_cast<Cov*>(local.addr);
|
|
if(cov->third){
|
|
assert(cov->index3 <= cov->cov3->GetNoTuples());
|
|
Tuple* tuple = cov->cov3->GetTuple(cov->index3, false);
|
|
result.addr = tuple;
|
|
cov->index3++;
|
|
if(cov->index3 > cov->cov3->GetNoTuples())
|
|
cov->third = false;
|
|
return YIELD;
|
|
}
|
|
|
|
return CANCEL;
|
|
}
|
|
case CLOSE:{
|
|
Cov* cov = static_cast<Cov*>(local.addr);
|
|
if(cov){
|
|
delete cov;
|
|
local.setAddr(0);
|
|
}
|
|
return 0;
|
|
}
|
|
default: assert(false);
|
|
}
|
|
}
|
|
Operator mergertree(
|
|
"mergertree",
|
|
MergertreeSpec,
|
|
MergeRTreeFun,
|
|
Operator::SimpleSelect,
|
|
MergeRTreeTypeMap
|
|
);
|
|
|
|
|
|
Operator mergecov(
|
|
"mergecov",
|
|
MergeCovSpec,
|
|
MergeCovFun,
|
|
Operator::SimpleSelect,
|
|
MergeCovTypeMap
|
|
);
|
|
|
|
Operator mergecov2(
|
|
"mergecov2",
|
|
MergeCov2Spec,
|
|
MergeCov2Fun,
|
|
Operator::SimpleSelect,
|
|
MergeCov2TypeMap
|
|
);
|
|
|
|
|
|
/*
|
|
Operator closestPair
|
|
|
|
Type Mapping and Value Mapping are defined in ClosestPair.h
|
|
|
|
*/
|
|
|
|
OperatorSpec closestPairsSpec(
|
|
" rtree x rel x rtree x rel x int",
|
|
" _ _ _ _ closestPair[_] ",
|
|
"Returns the k closest pairs of set defined by rtrees",
|
|
"query kinos_rtree kinos swp_rtree swp closestPairs[8]"
|
|
);
|
|
|
|
|
|
/*
|
|
4.38.4 Operator instance
|
|
|
|
*/
|
|
|
|
Operator closestPairsOP
|
|
(
|
|
"closestPairs", //name
|
|
closestPairsSpec.getStr(), //specification
|
|
closestPairsVM, //value mapping
|
|
Operator::SimpleSelect, //trivial selection function
|
|
closestPairsTM //type mapping
|
|
);
|
|
|
|
|
|
|
|
/*
|
|
4.39 Operator ~countUnits~
|
|
|
|
*/
|
|
|
|
ListExpr countUnitsTM(ListExpr args){
|
|
if(!nl->HasLength(args,2)){
|
|
return listutils::typeError("2 args expected");
|
|
}
|
|
if(!Stream<Tuple>::checkType(nl->First(args))){
|
|
return listutils::typeError("1st arg is not a tuple stream");
|
|
}
|
|
ListExpr an = nl->Second(args);
|
|
if(nl->AtomType(an)!=SymbolType){
|
|
return listutils::typeError("second arg is not an attribute name");
|
|
}
|
|
ListExpr attrList = nl->Second(nl->Second(nl->First(args)));
|
|
std::string name = nl->SymbolValue(an);
|
|
ListExpr attrType;
|
|
int index = listutils::findAttribute(attrList, name, attrType);
|
|
if(!index){
|
|
return listutils::typeError("attribute " + name + " not found");
|
|
}
|
|
if(!UPoint::checkType(attrType)){
|
|
return listutils::typeError("attribute " + name
|
|
+ " not of type upoint");
|
|
}
|
|
return nl->ThreeElemList(
|
|
nl->SymbolAtom(Symbols::APPEND()),
|
|
nl->OneElemList( nl->IntAtom(index-1)),
|
|
listutils::basicSymbol<MInt>());
|
|
}
|
|
|
|
|
|
|
|
|
|
class End{
|
|
public:
|
|
End(Instant _i, bool _rc): i(_i),rc(_rc){}
|
|
|
|
End(const End& e): i(e.i), rc(e.rc) {}
|
|
|
|
End& operator=(const End& e){
|
|
i = e.i;
|
|
rc = e.rc;
|
|
return *this;
|
|
}
|
|
|
|
bool operator<(const End& e)const{
|
|
if(i < e.i) return true;
|
|
if(i > e.i) return false;
|
|
if(!rc && e.rc) return true;
|
|
if(rc && !e.rc) return false;
|
|
return false;
|
|
}
|
|
|
|
bool operator>(const End& e)const{
|
|
if(i > e.i) return true;
|
|
if(i < e.i) return false;
|
|
if(!rc && e.rc) return false;
|
|
if(rc && !e.rc) return true;
|
|
return false;
|
|
}
|
|
|
|
|
|
bool operator==(const End& e) const{
|
|
return i==e.i && rc == e.rc;
|
|
}
|
|
|
|
bool equal(const Instant& _i, const bool _rc) const{
|
|
return i==_i && rc ==_rc;
|
|
}
|
|
|
|
bool smaller(const Instant& _i, const bool _rc) const{
|
|
if(i<_i) return true;
|
|
if(i>_i) return false;
|
|
if(!rc && _rc) return true;
|
|
return false;
|
|
}
|
|
|
|
bool smallerOrEqual(const Instant& _i, const bool _rc) const{
|
|
if(i<_i) return true;
|
|
if(i>_i) return false;
|
|
if(!rc && _rc) return true;
|
|
if(rc == _rc) return true;
|
|
return false;
|
|
}
|
|
|
|
bool greater(const Instant _i, const bool _rc) const{
|
|
if(i>_i) return true;
|
|
if(i<_i) return false;
|
|
if(!rc) return false;
|
|
return !_rc;
|
|
}
|
|
Instant i;
|
|
bool rc;
|
|
};
|
|
|
|
class iCompare{
|
|
public:
|
|
inline bool operator()(const End& e1, const End& e2) const{
|
|
return e1 > e2;
|
|
}
|
|
};
|
|
|
|
|
|
std::ostream& operator<<(std::ostream& o, const End& e){
|
|
o << e.i << ", " << e.rc;
|
|
return o;
|
|
}
|
|
|
|
class UnitCounter{
|
|
|
|
public:
|
|
UnitCounter(MInt* _res, Instant _start, Instant _end, bool _lc, bool _rc):
|
|
res(_res), current(_start), lc(_lc), lastStart(_start), lastClosed(_lc){
|
|
ends.push(End(_end,_rc));
|
|
count = 1;
|
|
}
|
|
|
|
void add(Instant _start, Instant _end, bool _lc, bool _rc){
|
|
|
|
if( (lastStart > _start)
|
|
|| ((lastStart == _start) && lastClosed && !lc)){
|
|
std::cerr << "Tuples are in invalid order " << endl;
|
|
}
|
|
lastStart = _start;
|
|
lastClosed = _lc;
|
|
|
|
if(_start==current && lc == _lc){
|
|
count++;
|
|
ends.push(End(_end,_rc));
|
|
return;
|
|
}
|
|
// new start after the current position
|
|
// step 1 process ends that are before the new start
|
|
bool done = false;
|
|
while(!done){
|
|
if(ends.empty()){
|
|
done = true;
|
|
} else {
|
|
End e = ends.top();
|
|
if(e.greater(_start,_lc)){ // after the new instant
|
|
done = true;
|
|
} else { // we hve to process the end
|
|
ends.pop();
|
|
if(e.equal(current,lc)){ // current instant
|
|
count--;
|
|
} else {
|
|
// e is after the current position,
|
|
//add a new unit to res and update current pos
|
|
if( (current < e.i) || ((current==e.i) && e.rc && lc)){
|
|
Interval<Instant> iv(current,e.i, lc, e.rc);
|
|
UInt ui(iv,CcInt(true,count));
|
|
res->MergeAdd(ui);
|
|
current = e.i;
|
|
lc = !e.rc;
|
|
}
|
|
count--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// all ends up to the new start are processed now
|
|
|
|
// step 2 if current is before start of new unit,
|
|
// add a unit to res and update current
|
|
if( (current < _start) || ((current == _start) && !lc && _lc)){
|
|
Interval<Instant> iv(current,_start, lc, !_rc);
|
|
UInt ui(iv,CcInt(true,count));
|
|
res->MergeAdd(ui);
|
|
current = _start;
|
|
lc = _lc;
|
|
}
|
|
count++;
|
|
ends.push(End(_end,_rc));
|
|
}
|
|
|
|
void finish(){
|
|
while(!ends.empty()){
|
|
End e = ends.top();
|
|
ends.pop();
|
|
if(e.equal(current,lc)){ // current instant
|
|
count--;
|
|
} else {
|
|
if( (current < e.i) || ((current == e.i) && lc && e.rc)){
|
|
Interval<Instant> iv(current,e.i, lc, e.rc);
|
|
UInt ui(iv, CcInt(true,count));
|
|
res->MergeAdd(ui);
|
|
}
|
|
count--;
|
|
current = e.i;
|
|
lc = !e.rc;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
private:
|
|
MInt* res;
|
|
Instant current;
|
|
bool lc;
|
|
std::priority_queue<End, std::vector<End>, iCompare> ends;
|
|
size_t count;
|
|
|
|
Instant lastStart;
|
|
bool lastClosed;
|
|
};
|
|
|
|
|
|
int countUnitsVM(Word* args, Word& result, int message,Word& local, Supplier s){
|
|
Stream<Tuple> in(args[0]);
|
|
int attrPos = ((CcInt*)args[2].addr)->GetValue();
|
|
result = qp->ResultStorage(s);
|
|
MInt* res = (MInt*) result.addr;
|
|
res->Clear();
|
|
res->SetDefined(true);
|
|
in.open();
|
|
Tuple* tuple;
|
|
UnitCounter* uc = 0;
|
|
while((tuple=in.request())){
|
|
UPoint* p = (UPoint*) tuple->GetAttribute(attrPos);
|
|
Instant start = p->timeInterval.start;
|
|
Instant end = p->timeInterval.end;
|
|
bool lc = p->timeInterval.lc;
|
|
bool rc = p->timeInterval.rc;
|
|
if(uc == 0){
|
|
uc = new UnitCounter(res, start, end, lc, rc);
|
|
} else {
|
|
uc->add(start,end,lc,rc);
|
|
}
|
|
tuple->DeleteIfAllowed();
|
|
}
|
|
if(uc){
|
|
uc->finish();
|
|
delete uc;
|
|
}
|
|
in.close();
|
|
return 0;
|
|
}
|
|
|
|
|
|
OperatorSpec countUnitsSpec(
|
|
" stream(tuple) x IDENT -> mint",
|
|
" _ op[_]",
|
|
" Counts how many units are present in the tuple stream. "
|
|
" The units have to be sorted by time. ",
|
|
" query UnitTrains feed sortby[UTrip] countUnits[UTrip] "
|
|
);
|
|
|
|
|
|
Operator countUnitsOp(
|
|
"countUnits",
|
|
countUnitsSpec.getStr(),
|
|
countUnitsVM,
|
|
Operator::SimpleSelect,
|
|
countUnitsTM
|
|
);
|
|
|
|
|
|
/*
|
|
4 Implementation of the Algebra Class
|
|
|
|
*/
|
|
|
|
class NearestNeighborAlgebra : public Algebra
|
|
{
|
|
public:
|
|
NearestNeighborAlgebra() : Algebra()
|
|
{
|
|
|
|
/*
|
|
5 Registration of Operators
|
|
|
|
*/
|
|
AddOperator( &distancescan );
|
|
AddOperator( &distancescan2 );
|
|
AddOperator( &distancescan2S );
|
|
AddOperator( &distancescan3 );
|
|
AddOperator( &knearest );
|
|
knearest.enableInitFinishSupport();
|
|
AddOperator( &knearestvector );
|
|
AddOperator( &oldknearestfilter );
|
|
AddOperator( &bboxes );
|
|
AddOperator( &rect2periods );
|
|
AddOperator( &coverageop );
|
|
AddOperator( &coverage2op );
|
|
AddOperator( &knearestfilter);
|
|
AddOperator( &distancescan4);
|
|
AddOperator( &greeceknearest);
|
|
AddOperator( &chinaknearest);
|
|
// AddOperator( &covleafnode);
|
|
AddOperator( &cellindex);
|
|
// AddOperator( &gnuplotnode);
|
|
AddOperator( &isknn);
|
|
AddOperator( &mergertree);
|
|
// AddOperator( &mergecov);
|
|
AddOperator( &mergecov2);
|
|
|
|
AddOperator( &knearest_dist);//return the k th nearghbor distanceA
|
|
|
|
AddOperator(&closestPairsOP);
|
|
|
|
AddOperator(&countUnitsOp);
|
|
|
|
|
|
}
|
|
~NearestNeighborAlgebra() {};
|
|
};
|
|
|
|
/*
|
|
6 Initialization
|
|
|
|
Each algebra module needs an initialization function. The algebra manager
|
|
has a reference to this function if this algebra is included in the list
|
|
of required algebras, thus forcing the linker to include this module.
|
|
|
|
The algebra manager invokes this function to get a reference to the instance
|
|
of the algebra class and to provide references to the global nested list
|
|
container (used to store constructor, type, operator and object information)
|
|
and to the query processor.
|
|
|
|
The function has a C interface to make it possible to load the algebra
|
|
dynamically at runtime (if it is built as a dynamic link library). The name
|
|
of the initialization function defines the name of the algebra module. By
|
|
convention it must start with "Initialize<AlgebraName>".
|
|
|
|
To link the algebra together with the system you must create an
|
|
entry in the file "makefile.algebra" and to define an algebra ID in the
|
|
file "Algebras/Management/AlgebraList.i.cfg".
|
|
|
|
*/
|
|
|
|
} // end of namespace ~near~
|
|
|
|
extern "C"
|
|
Algebra*
|
|
InitializeNearestNeighborAlgebra( NestedList* nlRef,
|
|
QueryProcessor* qpRef )
|
|
{
|
|
// The C++ scope-operator :: must be used to qualify the full name
|
|
return new near::NearestNeighborAlgebra;
|
|
}
|
|
|
|
/*
|
|
8 Examples and Tests
|
|
|
|
The file "NearestNeighbor.examples" contains for every operator one example.
|
|
This allows one to verify that the examples are running and to provide a
|
|
coarse regression test for all algebra modules. The command "Selftest <file>"
|
|
will execute the examples. Without any arguments, the examples for all active
|
|
algebras are executed. This helps to detect side effects, if you have touched
|
|
central parts of Secondo or existing types and operators.
|
|
|
|
In order to setup more comprehensive automated test procedures one can write a
|
|
test specification for the ~TestRunner~ application. You will find the file
|
|
"example.test" in directory "bin" and others in the directory "Tests/Testspecs".
|
|
There is also one for this algebra.
|
|
|
|
Accurate testing is often treated as an unpopular daunting task. But it is
|
|
absolutely inevitable if you want to provide a reliable algebra module.
|
|
|
|
Try to write tests covering every signature of your operators and consider
|
|
special cases, as undefined arguments, illegal argument values and critical
|
|
argument value combinations, etc.
|
|
|
|
|
|
*/
|
|
|