Files
secondo/Algebras/SETI/SETIAlgebra.cpp

2654 lines
79 KiB
C++
Raw Permalink Normal View History

2026-01-23 17:03:45 +08:00
/******************************************************************************
----
This file is part of SECONDO.
Copyright (C) 2004-2010, University in Hagen, Faculty of Mathematics and
Computer Science, Database Systems for New Applications.
SECONDO is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
SECONDO is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with SECONDO; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
----
//paragraph [1] Title: [{\Large \bf] [}]
//paragraph [10] Footnote: [{\footnote{] [}}]
//[TOC] [\tableofcontents]
[1] Implementation of SETIAlgebra
September 2010, Daniel Brockmann
1 Overview
SETI-Algebra implements a SETI index structure. The implementation makes
use of the existing SECONDO component RTree-Algebra. The memory management
is based on SmiUpdateFile. In addition the UploadUnit is an object type of
this Algebra.
SETI-Algebra offers the following methods:
- createSETI -> Creates a new SETI object.
- insertUpload -> Inserts a single upload into SETI.
- insertStream -> Inserts a stream of uploads into SETI.
- intersectsWindow -> Returns all trajectory segments which
intersect the search window.
- insideWindow -> Returns all trajectory segments
inside the search window.
- getTrajectory -> Returns all trajectory segments wich belongs
to the stated moving object.
- currentUpload -> Returns the current upload.
2 Includes and globals
******************************************************************************/
#include <iostream>
#include <fstream>
#include <map>
#include "WinUnix.h"
#include "SecondoSystem.h"
#include "QueryProcessor.h"
#include "Algebra.h"
#include "NestedList.h"
#include "ListUtils.h"
#include "Attribute.h"
#include "DateTime.h"
#include "Algebras/RTree/RTreeAlgebra.h"
#include "Algebras/Rectangle/RectangleAlgebra.h"
#include "Algebras/Temporal/TemporalAlgebra.h"
#include "UploadUnit.h"
#include "Symbols.h"
extern NestedList* nl;
extern QueryProcessor *qp;
extern AlgebraManager *am;
using namespace std;
using namespace temporalalgebra;
using namespace datetime;
namespace SETIAlgebra {
#include "SETIAlgebra.h"
/******************************************************************************
3. Auxiliary functions
3.1 CompareFloats
Returns 'true' if the two floating-point numbers are almost equal.
******************************************************************************/
bool CompareFloats(double F1 ,double F2)
{
if ( F1 <= (F2 + 0.001) &&
F1 >= (F2 - 0.001) )
{
return true;
}
else return false;
}
/******************************************************************************
3.2 ModifyArea
Modifies the given area. x1/x2 and y1/y2 will be swapped if necessary.
******************************************************************************/
SETIArea ModifyArea(SETIArea AREA)
{
double tempX = 0;
double tempY = 0;
if (AREA.x1 > AREA.x2)
{
tempX = AREA.x2;
AREA.x2 = AREA.x1;
AREA.x1 = tempX;
}
if (AREA.y1 > AREA.y2)
{
tempY = AREA.y2;
AREA.y2 = AREA.y1;
AREA.y1 = tempY;
}
AREA.x1 = AREA.x1 - tol;
AREA.y1 = AREA.y1 - tol;
AREA.x2 = AREA.x2 + tol;
AREA.y2 = AREA.y2 + tol;
return AREA;
}
/******************************************************************************
3.3 ComputeLine
Identifies a column or a row in a grid in dependence of a given position.
******************************************************************************/
int ComputeLine(double BORDER1 ,double BORDER2, int SPLITS, double POS)
{
double len = abs(BORDER1-BORDER2) / SPLITS;
int i = 0;
while ((BORDER1 + (i*len)) <= POS) i++;
return i-1;
}
/******************************************************************************
3.4 ComputeIntersection
Computes the intersection point of two lines (A,B) and (C,D).
******************************************************************************/
bool ComputeIntersection( double Ax, double Ay,
double Bx, double By,
double Cx, double Cy,
double Dx, double Dy,
UnitPos* is )
{
double distAB, cos, sin, newX, ABpos ;
if ( ((Ax==Bx) && (Ay==By)) || ((Cx==Dx) && (Cy==Dy)) ) return false;
if ( ((Ax==Cx) && (Ay==Cy)) || ((Bx==Cx) && (By==Cy))
|| ((Ax==Dx) && (Ay==Dy)) || ((Bx==Dx) && (By==Dy)) ) return false;
Bx-=Ax; By-=Ay;
Cx-=Ax; Cy-=Ay;
Dx-=Ax; Dy-=Ay;
distAB=sqrt(Bx*Bx+By*By);
cos=Bx/distAB;
sin=By/distAB;
newX=Cx*cos+Cy*sin;
Cy =Cy*cos-Cx*sin; Cx=newX;
newX=Dx*cos+Dy*sin;
Dy =Dy*cos-Dx*sin; Dx=newX;
if ( ((Cy<0) && (Dy<0)) || ((Cy>=0) && (Dy>=0)) ) return false;
ABpos=Dx+(Cx-Dx)*Dy/(Dy-Cy);
if ( (ABpos<0) || (ABpos>distAB) ) return false;
is->x = Ax+ABpos*cos;
is->y = Ay+ABpos*sin;
return true;
}
/******************************************************************************
4 Implementation of class SETI
4.1 Basic constructor
******************************************************************************/
SETI::SETI(SETIArea AREA, int SPLITS) : suf(0), rtreeFile(0)
{
// Create SETI Header
header = new SETIHeader(ModifyArea(AREA), SPLITS);
// Create SmiUpdateFile
suf = new SmiUpdateFile(pageSize);
suf->Create();
header->fileID = suf->GetFileId();
// Create RTree file
rtreeFile = new SmiRecordFile(true, rtreePageSize);
rtreeFile->Create();
header->rtreeFileID = rtreeFile->GetFileId();
// Create header page
SmiUpdatePage* headerPage;
int AppendedPage = suf->AppendNewPage(headerPage);
assert( AppendedPage );
header->headerPageNo = headerPage->GetPageNo();
// Create and initialize fontline pages
SmiUpdatePage* flPage;
db_pgno_t nextPageNo = 0;
int numEntries = 0;
AppendedPage = suf->AppendNewPage(flPage);
assert( AppendedPage );
header->flPageNo = flPage->GetPageNo();
int PageSelected = suf->GetPage(header->flPageNo, flPage);
assert( PageSelected );
size_t offset = 0;
for(int i = 0; i < flBuckets; i++)
{
SmiUpdatePage* bucketPage;
db_pgno_t bucketPageNo;
// Create new bucket page
AppendedPage = suf->AppendNewPage(bucketPage);
assert( AppendedPage );
bucketPageNo = bucketPage->GetPageNo();
// Write bucket page number into flPage
flPage->Write(&bucketPageNo, sizeof(db_pgno_t), offset);
offset += sizeof(db_pgno_t);
// Initialize bucket page
PageSelected = suf->GetPage(bucketPageNo, bucketPage);
assert( PageSelected );
bucketPage->Write(&nextPageNo, sizeof(db_pgno_t), 0);
bucketPage->Write(&numEntries, sizeof(int), sizeof(db_pgno_t));
suf->PutPage(bucketPageNo, true);
}
// Create and initialize first cell page
SmiUpdatePage* cellPage;
AppendedPage = suf->AppendNewPage(cellPage);
assert( AppendedPage );
header->cellPageNo = cellPage->GetPageNo();
PageSelected = suf->GetPage(header->cellPageNo, cellPage);
assert( PageSelected );
cellPage->Write(&nextPageNo, sizeof(db_pgno_t), 0);
cellPage->Write(&numEntries, sizeof(int), sizeof(db_pgno_t));
// Calculate x/y cell length
double areaLenX = abs(AREA.x2 - AREA.x1);
double areaLenY = abs(AREA.y2 - AREA.y1);
double cellLenX = areaLenX / header->splits;
double cellLenY = areaLenY / header->splits;
// Create an area partition
SETIArea partition(0,0,0,0);
for (int i = 0; i < header->splits; i++)
{
for (int j = 0; j < header->splits; j++)
{
partition.x1 = AREA.x1 + (cellLenX * j);
partition.x2 = partition.x1 + cellLenX;
partition.y1 = AREA.y1 + (cellLenY * i);
partition.y2 = partition.y1 + cellLenY;
// Create and initialize a new cell object
cells[j][i] = new SETICell();
cells[j][i]->numEntries = 0;
cells[j][i]->area = partition;
cells[j][i]->currentPage = (db_pgno_t)0;
cells[j][i]->tiv.start = DateTime(0,0,instanttype);
cells[j][i]->tiv.end = DateTime(0,0,instanttype);
cells[j][i]->tiv.lc = false;
cells[j][i]->tiv.rc = false;
// Create RTree for cell
cells[j][i]->rtreePtr = new R_Tree<2,TupleId>(rtreeFile);
cells[j][i]->rtreeRecID = cells[j][i]->rtreePtr->HeaderRecordId();
}
}
// Write header and cell page into SmiUpdateFile
UpdateHeader();
UpdateCells();
// Initialize semaphore
SetSemaphore(false);
}
/******************************************************************************
4.2 Query constructor
******************************************************************************/
SETI::SETI(SmiFileId FILEID) : suf(0)
{
// Open existing file
suf = new SmiUpdateFile(pageSize);
suf->Open(FILEID, pageSize);
// Create header object
header = new SETIHeader();
}
/******************************************************************************
4.3 Destructor
******************************************************************************/
SETI::~SETI()
{
// Delete cells
for (int i = 0; i < header->splits; i++)
{
for (int j = 0; j < header->splits; j++)
{
delete cells[j][i]->rtreePtr;
delete cells[j][i];
}
}
// Delete header
delete header;
// Clear frontline
for (int i = 0; i < flBuckets; i++)
{
frontline[i].clear();
}
// Delete file objects
if(suf->IsOpen()) suf->Close();
delete suf;
if(rtreeFile->IsOpen()) rtreeFile->Close();
delete rtreeFile;
}
/******************************************************************************
4.4 The mandatory set of algebra support functions
4.4.1 In-method
******************************************************************************/
Word SETI::In( ListExpr typeInfo, ListExpr instance, int errorPos,
ListExpr& errorInfo, bool& correct )
{
correct = false;
Word result = SetWord(Address(0));
// Check list length
if ( nl->ListLength(instance) != 2 )
{
cmsg.inFunError("A list of length two expected!");
return result;
}
// Check area types
ListExpr areaList = nl->First(instance);
if ( !(nl->ListLength(areaList) == 4 &&
nl->IsAtom( nl->First(areaList) ) &&
nl->AtomType( nl->First(areaList) ) == RealType &&
nl->IsAtom( nl->Second(areaList) ) &&
nl->AtomType( nl->Second(areaList ) ) == RealType &&
nl->IsAtom( nl->Third(areaList) ) &&
nl->AtomType( nl->Third(areaList) ) == RealType &&
nl->IsAtom( nl->Fourth(areaList) ) &&
nl->AtomType( nl->Fourth(areaList) ) == RealType ))
{
cmsg.inFunError("A list of four real type values is "
"expected for the first argument!");
return result;
}
// Area values
double x1 = nl->RealValue( nl->First(areaList) );
double x2 = nl->RealValue( nl->Second(areaList) );
double y1 = nl->RealValue( nl->Third(areaList) );
double y2 = nl->RealValue( nl->Fourth(areaList) );
if (( x2 == x1 ) || (y1 == y2 ))
{
cmsg.inFunError("x1/x2 and y1/y2 must be different!");
return result;
}
SETIArea area(x1,y1,x2,y2);
// Check number of partitions type
if ( !(nl->IsAtom( nl->Second( instance ) ) &&
nl->AtomType( nl->Second( instance ) ) == IntType ))
{
cmsg.inFunError("An integer value is expected for second argument!");
return result;
}
// Check number of partitions
int numPartitions = nl->IntValue( nl->Second(instance) );
if (!(CompareFloats(fmod(sqrt(numPartitions),1),0) &&
numPartitions >= 1 &&
numPartitions <= 4096))
{
// Wrong number of partitions -> create default SETI
result.addr = new SETI(ModifyArea(area), 1);
}
else
{
result.addr = new SETI(ModifyArea(area), (int)sqrt(numPartitions));
}
correct = true;
return result;
}
/******************************************************************************
4.4.2 Out-method
******************************************************************************/
ListExpr SETI::Out(ListExpr typeInfo, Word value )
{
SETI* setiPtr = static_cast<SETI*>(value.addr);
// Create area list
ListExpr area = nl->FourElemList(
nl->RealAtom(setiPtr->header->area.x1),
nl->RealAtom(setiPtr->header->area.x2),
nl->RealAtom(setiPtr->header->area.y1),
nl->RealAtom(setiPtr->header->area.y2));
// Create time interval list
ListExpr tiv;
if (setiPtr->header->numEntries == 0)
{
// Time interval is undefined if no entry exist
tiv = nl->TwoElemList( nl->StringAtom("undefined"),
nl->StringAtom("undefined"));
}
else if (setiPtr->header->numEntries == 1)
{
// End time is undefined if only one entry exist
tiv = nl->TwoElemList(
OutDateTime(nl->TheEmptyList(),
SetWord(&setiPtr->header->tiv.start)),
nl->StringAtom("undefined"));
}
else
{
// Time interval is defined if SETI has two entries or more
tiv = nl->TwoElemList(
OutDateTime(nl->TheEmptyList(),
SetWord(&setiPtr->header->tiv.start)),
OutDateTime(nl->TheEmptyList(),
SetWord(&setiPtr->header->tiv.end)));
}
// Return output list
return nl->TwoElemList(area, tiv);
}
/******************************************************************************
4.4.3 Create-method
******************************************************************************/
Word SETI::Create( const ListExpr typeInfo )
{
return SetWord(Address(0));
}
/******************************************************************************
4.4.4 Delete-method
******************************************************************************/
void SETI::Delete( const ListExpr typeInfo, Word& w )
{
SETI* setiPtr = static_cast<SETI*>(w.addr);
setiPtr->rtreeFile->Close();
if(setiPtr->rtreeFile->IsOpen()) setiPtr->rtreeFile->Drop();
delete setiPtr;
w.addr = 0;
}
/******************************************************************************
4.4.5 Open-method
******************************************************************************/
bool SETI::Open( SmiRecord& valueRecord, size_t& offset,
const ListExpr typeInfo, Word& value )
{
SmiFileId fileID;
db_pgno_t headerPageNo;
bool ok = true;
ok = ok && valueRecord.Read( &fileID, sizeof(SmiFileId), offset );
offset += sizeof(SmiFileId);
ok = ok && valueRecord.Read( &headerPageNo, sizeof(db_pgno_t), offset );
offset += sizeof(db_pgno_t);
if(!ok){
return false;
}
// Create new SETI object with existing file
SETI* setiPtr = new SETI(fileID);
setiPtr->header->fileID = fileID;
setiPtr->header->headerPageNo = headerPageNo;
// Reader header, frontline and cells information from file
setiPtr->ReadSETI();
value.addr = setiPtr;
return ok;
}
/******************************************************************************
4.4.6 Save-method
******************************************************************************/
bool SETI::Save( SmiRecord& valueRecord, size_t& offset,
const ListExpr typeInfo, Word& value )
{
SETI* setiPtr = static_cast<SETI*>(value.addr);
bool ok = true;
SmiFileId fileID = setiPtr->header->fileID;
db_pgno_t headerPageNo = setiPtr->header->headerPageNo;
ok = ok && valueRecord.Write(&fileID, sizeof(SmiFileId), offset );
offset += sizeof(SmiFileId);
ok = ok && valueRecord.Write(&headerPageNo, sizeof(db_pgno_t), offset );
offset += sizeof(db_pgno_t);
return ok;
}
/******************************************************************************
4.4.7 Close-method
******************************************************************************/
void SETI::Close( const ListExpr typeInfo, Word& w )
{
SETI* setiPtr = static_cast<SETI*>(w.addr);
delete setiPtr;
w.addr = 0;
}
/******************************************************************************
4.4.8 Clone-method
******************************************************************************/
Word SETI::Clone( const ListExpr typeInfo, const Word& w )
{
return SetWord(Address(0));
}
/******************************************************************************
4.4.9 Cast-method
******************************************************************************/
void* SETI::Cast( void* addr)
{
return (0);
}
/******************************************************************************
4.4.10 SizeOfObj-method
******************************************************************************/
int SETI::SizeOfObj()
{
return sizeof(SETI);
}
/******************************************************************************
4.4.11 KindCheck-method
******************************************************************************/
bool SETI::KindCheck(ListExpr type, ListExpr& errorInfo)
{
return (nl->IsEqual(type, SETI::BasicType()));
}
/******************************************************************************
4.4.12 Property-method
******************************************************************************/
ListExpr SETI::Property()
{
return (nl->TwoElemList(
nl->FiveElemList(nl->StringAtom("Signature"),
nl->StringAtom("Example Type List"),
nl->StringAtom("List Rep"),
nl->StringAtom("Example List"),
nl->StringAtom("Remarks")),
nl->FiveElemList(nl->StringAtom("-> DATA"),
nl->StringAtom(SETI::BasicType()),
nl->StringAtom("((<x1> <x2> <y1> <y2>) p)"),
nl->StringAtom("((8.2 1.6 9.7 4,6) 4096)"),
nl->StringAtom("x/y must be of type double, "
"p of type int."))));
}
/******************************************************************************
4.5 ReadSETI-method
Reads header, frontline and cell information from file.
******************************************************************************/
void SETI::ReadSETI()
{
// Read header --------------------------------------------------------------
SmiUpdatePage* headerPage;
int PageSelected = suf->GetPage(header->headerPageNo, headerPage);
assert( PageSelected );
size_t offset = 0;
headerPage->Read(&header->rtreeFileID, sizeof(SmiFileId), offset);
offset += sizeof(SmiFileId);
headerPage->Read(&header->flPageNo, sizeof(db_pgno_t), offset);
offset += sizeof(db_pgno_t);
headerPage->Read(&header->cellPageNo, sizeof(db_pgno_t), offset);
offset += sizeof(db_pgno_t);
headerPage->Read(&header->area, sizeof(SETIArea), offset);
offset += sizeof(SETIArea);
headerPage->Read(&header->splits, sizeof(int), offset);
offset += sizeof(int);
headerPage->Read(&header->numCells, sizeof(int), offset);
offset += sizeof(int);
headerPage->Read(&header->numEntries, sizeof(int), offset);
offset += sizeof(int);
headerPage->Read(&header->numFlEntries, sizeof(int), offset);
offset += sizeof(int);
headerPage->Read(&header->tiv, sizeof(Interval<Instant>), offset);
offset += sizeof(Interval<Instant>);
// Read frontline -----------------------------------------------------------
SmiUpdatePage* flPage;
PageSelected = suf->GetPage(header->flPageNo, flPage);
assert( PageSelected );
size_t flPageOffset = 0;
for (int i = 0; i < flBuckets; i++)
{
SmiUpdatePage* bucketPage;
db_pgno_t bucketPageNo;
db_pgno_t nextPageNo;
int numEntries;
// Select bucket page
flPage->Read( &bucketPageNo, sizeof(db_pgno_t), flPageOffset);
flPageOffset += sizeof(db_pgno_t);
do
{
PageSelected = suf->GetPage(bucketPageNo, bucketPage);
assert( PageSelected );
bucketPage->Read(&nextPageNo, sizeof(db_pgno_t), 0);
bucketPage->Read(&numEntries, sizeof(int), sizeof(db_pgno_t));
offset = sizeof(db_pgno_t) + sizeof(int);
for (int j = 0; j < numEntries; j++)
{
UploadUnit unit;
bucketPage->Read(&unit, sizeof(UploadUnit), offset);
offset += sizeof(UploadUnit);
frontline[unit.GetID()%flBuckets].insert(make_pair(unit.GetID(),unit));
}
if ( nextPageNo != 0 ) bucketPageNo = nextPageNo;
}
while(nextPageNo != 0);
}
// Read cells ---------------------------------------------------------------
SmiUpdatePage* cellPage;
db_pgno_t cellPageNo = header->cellPageNo;
db_pgno_t nextPageNo;
int j = 1;
int i = 1;
double tivStart;
double tivEnd;
int numEntries;
// Open RTree file
rtreeFile = new SmiRecordFile(pageSize);
rtreeFile->Open(header->rtreeFileID);
do
{
PageSelected = suf->GetPage(cellPageNo, cellPage);
assert( PageSelected );
cellPage->Read(&nextPageNo, sizeof(db_pgno_t), 0);
cellPage->Read(&numEntries, sizeof(int), sizeof(db_pgno_t));
offset = sizeof(db_pgno_t) + sizeof(int);
for (int k = 0; k < numEntries; k++)
{
cells[j-1][i-1] = new SETICell();
SETICell* cellPtr = cells[j-1][i-1];
cellPage->Read(&cellPtr->numEntries, sizeof(int), offset);
offset += sizeof(int);
cellPage->Read(&cellPtr->area, sizeof(SETIArea), offset);
offset += sizeof(SETIArea);
cellPage->Read(&cellPtr->rtreeRecID, sizeof(SmiRecordId), offset);
offset += sizeof(SmiRecordId);
cellPage->Read(&cellPtr->currentPage, sizeof(db_pgno_t), offset);
offset += sizeof(db_pgno_t);
cellPage->Read(&tivStart, sizeof(double), offset);
offset += sizeof(double);
cellPage->Read(&tivEnd, sizeof(double), offset);
offset += sizeof(double);
cellPage->Read(&cellPtr->tiv.lc, sizeof(bool), offset);
offset += sizeof(bool);
cellPage->Read(&cellPtr->tiv.rc, sizeof(bool), offset);
offset += sizeof(bool);
cellPtr->tiv.start = DateTime(0,0,instanttype);
cellPtr->tiv.start.ReadFrom(tivStart);
cellPtr->tiv.end = DateTime(0,0,instanttype);
cellPtr->tiv.end.ReadFrom(tivEnd);
// Create new RTree with existing RTree file/header
cellPtr->rtreePtr = new R_Tree<2,TupleId>( rtreeFile,
cellPtr->rtreeRecID );
if ((j % header->splits) == 0) { j = 0; i++; }
j++;
}
if ( nextPageNo != 0 ) cellPageNo = nextPageNo;
} while(nextPageNo != 0);
}
/******************************************************************************
4.6 UpdateHeader-method
Writes header information into file.
******************************************************************************/
void SETI::UpdateHeader()
{
SmiUpdatePage* headerPage;
int PageSelected = suf->GetPage(header->headerPageNo, headerPage);
assert( PageSelected );
size_t offset = 0;
headerPage->Write(&header->rtreeFileID, sizeof(SmiFileId), offset);
offset += sizeof(SmiFileId);
headerPage->Write(&header->flPageNo, sizeof(db_pgno_t), offset);
offset += sizeof(db_pgno_t);
headerPage->Write(&header->cellPageNo, sizeof(db_pgno_t), offset);
offset += sizeof(db_pgno_t);
headerPage->Write(&header->area, sizeof(SETIArea), offset);
offset += sizeof(SETIArea);
headerPage->Write(&header->splits, sizeof(int), offset);
offset += sizeof(int);
headerPage->Write(&header->numCells, sizeof(int), offset);
offset += sizeof(int);
headerPage->Write(&header->numEntries, sizeof(int), offset);
offset += sizeof(int);
headerPage->Write(&header->numFlEntries, sizeof(int), offset);
offset += sizeof(int);
headerPage->Write(&header->tiv, sizeof(Interval<Instant>), offset);
offset += sizeof(Interval<Instant>);
}
/******************************************************************************
4.7 UpdateFLine-method
Writes front-line information into file.
******************************************************************************/
void SETI::UpdateFLine()
{
SmiUpdatePage* flPage;
int PageSelected = suf->GetPage(header->flPageNo, flPage);
assert( PageSelected );
size_t flPageOffset = 0;
for (int i = 0; i < flBuckets; i++)
{
SmiUpdatePage* bucketPage;
db_pgno_t bucketPageNo;
db_pgno_t nextPageNo;
// Select bucket page
flPage->Read( &bucketPageNo, sizeof(db_pgno_t),flPageOffset);
flPageOffset += sizeof(db_pgno_t);
PageSelected = suf->GetPage(bucketPageNo, bucketPage);
assert( PageSelected );
int numEntries = 0;
size_t bucketPageOffset = sizeof(db_pgno_t) + sizeof(int);
for (map<int,UploadUnit>::iterator it = frontline[i].begin();
it != frontline[i].end(); it++)
{
numEntries++;
bucketPage->Write( &numEntries, sizeof(int), sizeof(db_pgno_t) );
bucketPage->Write( &it->second, sizeof(UploadUnit), bucketPageOffset );
bucketPageOffset += sizeof(UploadUnit);
if((numEntries%70) == 0)
{
// Page is full up
bucketPageOffset = sizeof(db_pgno_t) + sizeof(int);
// Get next page
bucketPage->Read(&nextPageNo, sizeof(db_pgno_t), 0);
if(nextPageNo == 0)
{
// No next page exist -> create new next page
SmiUpdatePage* newPage;
int AppendedPage = suf->AppendNewPage(newPage);
assert( AppendedPage );
nextPageNo = newPage->GetPageNo();
bucketPage->Write(&nextPageNo, sizeof(db_pgno_t), 0);
}
// Select and initialize next page
PageSelected = suf->GetPage(nextPageNo, bucketPage);
assert( PageSelected );
nextPageNo = 0;
numEntries = 0;
bucketPage->Write(&nextPageNo, sizeof(db_pgno_t), 0);
bucketPage->Write(&numEntries, sizeof(int), sizeof(db_pgno_t));
}
}
}
}
/******************************************************************************
4.8 UpdateCells-method
Writes cell information into file.
******************************************************************************/
void SETI::UpdateCells()
{
SmiUpdatePage* cellPage;
db_pgno_t nextPageNo;
int numEntries = 0;
int PageSelected = suf->GetPage(header->cellPageNo, cellPage);
assert( PageSelected );
size_t offset = sizeof(db_pgno_t) + sizeof(int);
for (int i = 0; i < header->splits; i++)
{
for (int j = 0; j < header->splits; j++)
{
// Increase number of entries in page
numEntries++;
cellPage->Write( &numEntries, sizeof(int), sizeof(db_pgno_t) );
SETICell* cellPtr = cells[j][i];
double tivStart = cellPtr->tiv.start.ToDouble();
double tivEnd = cellPtr->tiv.end.ToDouble();
cellPage->Write(&cellPtr->numEntries, sizeof(int), offset);
offset += sizeof(int);
cellPage->Write(&cellPtr->area, sizeof(SETIArea), offset);
offset += sizeof(SETIArea);
cellPage->Write(&cellPtr->rtreeRecID, sizeof(SmiRecordId), offset);
offset += sizeof(SmiRecordId);
cellPage->Write(&cellPtr->currentPage, sizeof(db_pgno_t), offset);
offset += sizeof(db_pgno_t);
cellPage->Write(&tivStart, sizeof(double), offset);
offset += sizeof(double);
cellPage->Write(&tivEnd, sizeof(double), offset);
offset += sizeof(double);
cellPage->Write(&cellPtr->tiv.lc, sizeof(bool), offset);
offset += sizeof(bool);
cellPage->Write(&cellPtr->tiv.rc, sizeof(bool), offset);
offset += sizeof(bool);
if((numEntries%64) == 0)
{
// If page is full up get next page
cellPage->Read(&nextPageNo, sizeof(db_pgno_t), 0);
if(nextPageNo == 0)
{
// No next page exist -> create new next page
SmiUpdatePage* newPage;
int AppendedPage = suf->AppendNewPage(newPage);
assert( AppendedPage );
nextPageNo = newPage->GetPageNo();
cellPage->Write(&nextPageNo, sizeof(db_pgno_t), 0);
}
// Select and initialize next page
PageSelected = suf->GetPage(nextPageNo, cellPage);
assert( PageSelected );
nextPageNo = 0;
numEntries = 0;
offset = sizeof(db_pgno_t) + sizeof(int);
cellPage->Write(&nextPageNo, sizeof(db_pgno_t), 0);
cellPage->Write(&numEntries, sizeof(int), sizeof(db_pgno_t));
}
}
}
}
/******************************************************************************
4.9 UpdateSETI-method
Writes all SETI data into file.
******************************************************************************/
bool SETI::UpdateSETI()
{
// Check if SmiUpdateFile is released
if(GetSemaphore())
{
return false;
}
else
{
// Lock SmiUpdateFile
SetSemaphore(true);
// Update header in SmiUpdateFile
UpdateHeader();
// Update front line in SmiUpdateFile
UpdateFLine();
// Update cells
UpdateCells();
// Release SmiUpdateFile
SetSemaphore(false);
return true;
}
}
/******************************************************************************
4.10 GetUpdateFile-method
Returns the SETI file id.
******************************************************************************/
SmiUpdateFile* SETI::GetUpdateFile()
{
return suf;
}
/******************************************************************************
4.11 GetHeader-method
Returns the pointer to the SETI header.
******************************************************************************/
SETIHeader* SETI::GetHeader()
{
return header;
}
/******************************************************************************
4.12 GetCell-method
Returns the pointer to the stated cell.
******************************************************************************/
SETICell* SETI::GetCell(int COL, int ROW)
{
return cells[COL][ROW];
}
/******************************************************************************
4.13 GetSemaphore-method
Returns the state of the semaphore.
******************************************************************************/
bool SETI::GetSemaphore()
{
bool value;
SmiUpdatePage* headerPage;
int PageSelected = suf->GetPage(header->headerPageNo, headerPage);
assert( PageSelected );
headerPage->Read(&value, sizeof(bool), sizeof(SETIHeader));
// Wait until file is released or timeout is 0
int timeout = 100000;
while(value && (timeout >= 0))
{
headerPage->Read(&value, sizeof(bool), sizeof(SETIHeader));
for(int i = 0; i < 10000; i++);
timeout--;
}
return value;
}
/******************************************************************************
4.14 SetSemaphore-method
Sets the state of the semaphore.
******************************************************************************/
void SETI::SetSemaphore(bool value)
{
SmiUpdatePage* headerPage;
int PageSelected = suf->GetPage(header->headerPageNo, headerPage);
assert( PageSelected );
headerPage->Write(&value, sizeof(bool), sizeof(SETIHeader));
}
/******************************************************************************
4.15 Type constructor
******************************************************************************/
TypeConstructor SETITC(
SETI::BasicType(), // name
SETI::Property, // property function
SETI::Out, SETI::In, // Out and In functions
0, 0, // SaveTo and RestoreFrom functions
SETI::Create, SETI::Delete, // object creation and deletion
SETI::Open, SETI::Save, // object open and save
SETI::Close, SETI::Clone, // object close and clone
SETI::Cast, // cast function
SETI::SizeOfObj, // sizeof function
SETI::KindCheck ); // kind checking function
/******************************************************************************
5 setiCreate operator
Creates a new SETI object.
5.1 createSETI - Type mapping method
******************************************************************************/
ListExpr CreateTM(ListExpr args)
{
if( nl->ListLength( args ) == 2 &&
nl->IsEqual(nl->First(args),Rectangle<2>::BasicType()) &&
nl->IsEqual(nl->Second(args),CcInt::BasicType()) )
{
return (nl->SymbolAtom(SETI::BasicType()));
}
ErrorReporter::ReportError("rect x int expected!");
return (nl->SymbolAtom( Symbol::TYPEERROR() ));
}
/******************************************************************************
5.2 createSETI - Value mapping method
******************************************************************************/
int CreateVM(Word* args, Word& result, int message, Word& local, Supplier s)
{
SETI* setiPtr = static_cast<SETI*>(qp->ResultStorage(s).addr);
Rectangle<2>* rect = static_cast<Rectangle<2>*>(args[0].addr);
CcInt* partitions = static_cast<CcInt*>(args[1].addr);
// Create SETI area
double x1(rect->MinD(0));
double x2(rect->MaxD(0));
double y1(rect->MinD(1));
double y2(rect->MaxD(1));
SETIArea area(x1,y1,x2,y2);
area = ModifyArea(area);
// Check number of partitions
int numPartitions = partitions->GetValue();
if (!(CompareFloats(fmod(sqrt(numPartitions),1),0) &&
numPartitions >= 1 &&
numPartitions <= 4096))
{
// Wrong number of partitions -> create default SETI
setiPtr = new SETI(area,1);
}
else
{
// Create SETI with the stated number of partitions
setiPtr = new SETI(area,(int)sqrt(numPartitions));
}
result.setAddr( setiPtr );
return 0;
}
/******************************************************************************
5.3 createSETI - Specification of operator
******************************************************************************/
struct CreateInfo : OperatorInfo {
CreateInfo()
{
name = "createSETI";
signature = "rect x int -> seti";
syntax = "createSETI( _, _ )";
meaning = "SETI construction operator. The second argument must be a "
"sqare number, otherwise it will be set a default value.";
}
};
/******************************************************************************
6 insertUpload operator
Inserts a single upload into SETI.
6.1 ComputeTrjSegment-method
Computes a trajectory segment and returns it to the insertHandle method.
******************************************************************************/
TrjSeg* ComputeTrjSegment( SETIArea AREA, int SPLITS,
UnitPos POS1, UnitPos POS2,
Interval<Instant> TIV )
{
int startCol = ComputeLine(AREA.x1, AREA.x2, SPLITS, POS1.x);
int startRow = ComputeLine(AREA.y1, AREA.y2, SPLITS, POS1.y);
double xLen = abs(AREA.x1-AREA.x2) / SPLITS;
double yLen = abs(AREA.y1-AREA.y2) / SPLITS;
double right = (startCol+1)*xLen + AREA.x1;
double left = (startCol)*xLen + AREA.x1;
double top = (startRow+1)*yLen + AREA.y1;
double bottom = (startRow)*yLen + AREA.y1;
// Compute intersection points
UnitPos* isR = new UnitPos(0,0);
UnitPos* isL = new UnitPos(0,0);
UnitPos* isT = new UnitPos(0,0);
UnitPos* isB = new UnitPos(0,0);
bool intersectsRight = ComputeIntersection(right, bottom, right, top,
POS1.x, POS1.y, POS2.x, POS2.y, isR);
bool intersectsLeft = ComputeIntersection(left, bottom, left,top,
POS1.x, POS1.y, POS2.x, POS2.y, isL);
bool intersectsTop = ComputeIntersection(left, top, right, top,
POS1.x, POS1.y, POS2.x, POS2.y, isT);
bool intersectsBottom = ComputeIntersection(left, bottom, right, bottom,
POS1.x, POS1.y, POS2.x, POS2.y, isB);
// Create new end point for segment
UnitPos p(POS2.x,POS2.y);
for (int i = 0; i < 4; i++) intersects[i] = false;
if (intersectsRight) {p.x = isR->x; p.y = isR->y; intersects[0] = true;}
if (intersectsLeft) {p.x = isL->x; p.y = isL->y; intersects[1] = true;}
if (intersectsTop) {p.x = isT->x; p.y = isT->y; intersects[2] = true;}
if (intersectsBottom) {p.x = isB->x; p.y = isB->y; intersects[3] = true;}
delete isR;
delete isL;
delete isT;
delete isB;
TrjSeg* segment = new TrjSeg(0, 0, TIV.start.ToDouble(),
TIV.end.ToDouble(), POS1, p);
return segment;
}
/******************************************************************************
6.2 InsertHandle-method
Inserts an upload into the SETI index structure. The insertUnit and
the insertStream operator make use of this method.
******************************************************************************/
int InsertHandle(SETI* SETIPTR, UploadUnit* UNITPTR)
{
SmiUpdateFile* suf = SETIPTR->GetUpdateFile();
SETIHeader* hPtr = SETIPTR->GetHeader();
// Ceck UploadUnit
if (hPtr->area.x1 < hPtr->area.x2)
{
if (UNITPTR->GetPos().x < hPtr->area.x1+tol ||
UNITPTR->GetPos().x > hPtr->area.x2-tol ) return 2;
}
else if (UNITPTR->GetPos().x < hPtr->area.x2+tol ||
UNITPTR->GetPos().x > hPtr->area.x1-tol ) return 2;
if (hPtr->area.y1 < hPtr->area.y2)
{
if (UNITPTR->GetPos().y < hPtr->area.y1+tol ||
UNITPTR->GetPos().y > hPtr->area.y2-tol ) return 2;
}
else if (UNITPTR->GetPos().y < hPtr->area.y2+tol ||
UNITPTR->GetPos().y > hPtr->area.y1-tol ) return 2;
// Find entry in the frontline
int moID = UNITPTR->GetID();
map<int,UploadUnit>::iterator it;
it = SETIPTR->frontline[moID%flBuckets].find(moID);
if ( it == SETIPTR->frontline[moID%flBuckets].end() )
{
// No entry found -> Place UploadUnit in front line
SETIPTR->frontline[moID%flBuckets].insert(make_pair(moID,*UNITPTR));
hPtr->numFlEntries++;
}
else
{
// Entry found
if(!suf->IsOpen()) suf->Open(hPtr->fileID, pageSize);
TrjSeg* segment;
UnitPos pos1 = it->second.GetPos();
UnitPos pos2 = UNITPTR->GetPos();
Interval<Instant> segTiv;
segTiv.start = it->second.GetTime();
segTiv.end = UNITPTR->GetTime();
segTiv.lc = true;
segTiv.rc = true;
// Check if the current upload is younger than the last upload
if(segTiv.start >= segTiv.end) return 3;
// Replace UploadUnit in frontline
SETIPTR->frontline[moID%flBuckets][moID] = *UNITPTR;
// Insert trajectory segment
do
{
// Find cell
int col =ComputeLine(hPtr->area.x1, hPtr->area.x2, hPtr->splits, pos1.x);
int row =ComputeLine(hPtr->area.y1, hPtr->area.y2, hPtr->splits, pos1.y);
SETICell* cellPtr = SETIPTR->GetCell(col, row);
SmiUpdatePage* page;
if ((cellPtr->numEntries % maxTrjSeg) == 0)
{
// Current cell page is full up or does not exist.
if(cellPtr->currentPage != 0)
{
// Insert temporal entry into the RTree
Interval<Instant> pageTiv;
int PageSelected = suf->GetPage(cellPtr->currentPage, page);
assert( PageSelected );
page->Read(&pageTiv, sizeof(Interval<Instant> ), sizeof(int));
double minMax[] = {pageTiv.start.ToDouble()-tol,
pageTiv.end.ToDouble()+tol,
-1.0, 1.0};
Rectangle<2> box = Rectangle<2>(true,minMax );
R_TreeLeafEntry<2,TupleId> e(box,cellPtr->currentPage);
cellPtr->rtreePtr->Insert(e);
// Put current page back to disk
//suf->PutPage(cellPtr->currentPage, true);
// Reset cell data
cellPtr->numEntries = 0;
cellPtr->tiv.lc = false;
cellPtr->tiv.rc = false;
}
// Create new page if no page exist or current page is full up
int AppendedPage = suf->AppendNewPage(page);
assert( AppendedPage );
cellPtr->currentPage = page->GetPageNo();
}
int PageSelected = suf->GetPage(cellPtr->currentPage, page);
assert( PageSelected );
// Create/split new segment
segment = ComputeTrjSegment(hPtr->area,hPtr->splits,pos1,pos2,segTiv);
segment->moID = moID;
segment->segID = hPtr->numEntries;
// Check/modify SETI time interval
if ((!hPtr->tiv.lc) || (hPtr->tiv.start > segTiv.start))
{
hPtr->tiv.start = segTiv.start;
hPtr->tiv.lc = true;
}
if ((!hPtr->tiv.rc) || (hPtr->tiv.end < segTiv.end))
{
hPtr->tiv.end = segTiv.end;
hPtr->tiv.rc = true;
}
// Check/modify cell time interval
if ((!cellPtr->tiv.lc) || (cellPtr->tiv.start > segTiv.start))
{
cellPtr->tiv.start = segTiv.start;
cellPtr->tiv.lc = true;
}
if ((!cellPtr->tiv.rc) || (cellPtr->tiv.end < segTiv.end))
{
cellPtr->tiv.end = segTiv.end;
cellPtr->tiv.rc = true;
}
// Initialize tiv and number of entries in page
if ((cellPtr->numEntries % maxTrjSeg) == 0)
{
int pageEntries = 0;
page->Write(&pageEntries, sizeof(int), 0);
page->Write(&segTiv,sizeof(Interval<Instant>), sizeof(int));
}
// Check/modify page time interval
Interval<Instant> pageTiv;
page->Read(&pageTiv, sizeof(Interval<Instant> ), sizeof(int));
if (segTiv.start < pageTiv.start) pageTiv.start = segTiv.start;
if (segTiv.end > pageTiv.end) pageTiv.end = segTiv.end;
// Read number of entries in page
int pageEntries;
page->Read( &pageEntries, sizeof(int), 0 );
// Write segment in page
size_t offset = sizeof(int) + sizeof(Interval<Instant>) +
+ ((pageEntries)*(sizeof(TrjSeg)));
page->Write(&segment->moID, sizeof(int), offset );
offset += sizeof(int);
page->Write( &segment->segID, sizeof(int), offset );
offset += sizeof(int);
page->Write(&segment->tivStart, sizeof(double), offset);
offset += sizeof(double);
page->Write(&segment->tivEnd, sizeof(double), offset);
offset += sizeof(double);
page->Write( &segment->pos1, sizeof(UnitPos), offset );
offset += sizeof(UnitPos);
page->Write( &segment->pos2, sizeof(UnitPos), offset );
offset += sizeof(UnitPos);
// Increase number of entries in cell and page
cellPtr->numEntries++;
pageEntries++;
page->Write(&pageEntries, sizeof(int), 0);
// Compute offset for next cell
if (intersects[0] == true) pos1.x = segment->pos2.x + tol;
else if (intersects[1] == true) pos1.x = segment->pos2.x - tol;
else pos1.x = segment->pos2.x;
if (intersects[2] == true) pos1.y = segment->pos2.y + tol;
else if (intersects[3] == true) pos1.y = segment->pos2.y - tol;
else pos1.y = segment->pos2.y;
}
while ( !(CompareFloats(pos2.x, segment->pos2.x) &&
CompareFloats(pos2.y, segment->pos2.y)) );
}
hPtr->numEntries++;
if ((hPtr->numEntries % updateCycle) == 0)
{
// Update file
if(!SETIPTR->UpdateSETI()) return 1;
}
return 0;
}
/******************************************************************************
6.3 GenerateErrorMsg-method
Generates error messages. The insertUpload and the insertStream operator make
use of this method.
******************************************************************************/
void GenerateErrorMsg(bool error[3])
{
static MessageCenter* msg = MessageCenter::GetInstance();
if (error[0])
{
NList msgList( NList("simple"),NList("Could not access update file!") );
msg->Send(nl, msgList.listExpr());
}
if (error[1])
{
NList msgList( NList("simple"),NList("Upload(s) is/are out of area!") );
msg->Send(nl,msgList.listExpr());
}
if (error[2])
{
NList msgList( NList("simple"),NList("Upload(s) is/are out of date!") );
msg->Send(nl,msgList.listExpr());
}
}
/******************************************************************************
6.4 insertUpload - Type mapping method
******************************************************************************/
ListExpr InsertUploadTM(ListExpr args)
{
if ( nl->ListLength( args ) == 2 &&
nl->IsEqual(nl->First(args), SETI::BasicType()) &&
nl->IsEqual(nl->Second(args), UploadUnit::BasicType()))
{
return (nl->SymbolAtom(CcBool::BasicType()));
}
return listutils::typeError("Expected seti x uploadunit!");
}
/******************************************************************************
6.5 insertUpload - Value mapping method
******************************************************************************/
int InsertUploadVM(Word* args, Word& result, int message,
Word& local, Supplier s)
{
SETI* setiPtr = static_cast<SETI*>(args[0].addr);
UploadUnit* unitPtr = static_cast<UploadUnit*>(args[1].addr);
bool error[3];
for (int i = 0; i < 3; i++) error[i] = false;
// Insert UploadUnit
int res = InsertHandle(setiPtr, unitPtr);
// Memorize error
if (res == 1) error[0] = true;
if (res == 2) error[1] = true;
if (res == 3) error[2] = true;
// Update file
if(!setiPtr->UpdateSETI()) error[0] = true;
// Print error messages
GenerateErrorMsg(error);
// Set result
result = qp->ResultStorage(s);
if(error[0] || error[1] || error[2])
{
static_cast<CcBool*>( result.addr )->Set(true, false);
}
else
{
static_cast<CcBool*>( result.addr )->Set(true, true);
}
return 0;
}
/******************************************************************************
6.6 insertUpload - Specification of operator
******************************************************************************/
struct InsertUploadInfo : OperatorInfo {
InsertUploadInfo()
{
name = "insertUpload";
signature = "seti x uploadunit -> bool";
syntax = "insertUpload( _, _)";
meaning = "SETI insert upload operator.";
}
};
/******************************************************************************
7 insertStream operator
Inserts a stream of uploads into SETI.
7.1 insertStream - Type mapping method
******************************************************************************/
ListExpr InsertStreamTM(ListExpr args)
{
NList type(args);
if ( !type.hasLength(3) )
{
return listutils::typeError("Expecting three arguments.");
}
NList first = type.first();
if ( !first.hasLength(2) ||
!first.first().isSymbol(Symbol::STREAM()) ||
!first.second().hasLength(2) ||
!first.second().first().isSymbol(Tuple::BasicType()) ||
!IsTupleDescription( first.second().second().listExpr() ))
{
return listutils::typeError("Error in first argument!");
}
if ( !nl->IsEqual(nl->Second(args), SETI::BasicType()) )
{
return NList::typeError( "SETI object for second argument expected!" );
}
NList third = type.third();
if ( !third.isSymbol() )
{
return NList::typeError( "Attribute name for third argument expected!" );
}
string attrname = type.third().str();
ListExpr attrtype = nl->Empty();
int j = FindAttribute(first.second().second().listExpr(),attrname,attrtype);
if ( j != 0 )
{
if ( nl->SymbolValue(attrtype) != UploadUnit::BasicType() )
{
return NList::typeError("Attribute type is not of type uploadunit.");
}
NList resType = NList(CcBool::BasicType());
return NList( NList(Symbol::APPEND()), NList(j).enclose(),
resType ).listExpr();
}
else
{
return NList::typeError( "Attribute name '" + attrname +"' is not known!");
}
}
/******************************************************************************
7.2 insertStream - Value mapping method
******************************************************************************/
int InsertStreamVM(Word* args, Word& result, int message,
Word& local, Supplier s)
{
Word currentTupleWord(Address(0));
int attributeIndex = static_cast<CcInt*>( args[3].addr )->GetIntval() - 1;
SETI* setiPtr = static_cast<SETI*>(args[1].addr);
bool error[3];
for (int i = 0; i < 3; i++) error[i] = false;
qp->Open(args[0].addr);
qp->Request(args[0].addr, currentTupleWord);
while(qp->Received(args[0].addr))
{
Tuple* currentTuple = static_cast<Tuple*>( currentTupleWord.addr );
UploadUnit* currentAttr =
static_cast<UploadUnit*>(currentTuple->GetAttribute(attributeIndex));
if( currentAttr->IsDefined() )
{
// Insert upload
int res = InsertHandle(setiPtr, currentAttr);
// Memorize error
if (res == 1) error[0] = true;
if (res == 2) error[1] = true;
if (res == 3) error[2] = true;
}
currentTuple->DeleteIfAllowed();
qp->Request(args[0].addr, currentTupleWord);
}
qp->Close(args[0].addr);
// Update file
if(!setiPtr->UpdateSETI()) error[0] = true;
// Print error messages
GenerateErrorMsg(error);
// Set result
result = qp->ResultStorage(s);
if(error[0] || error[1] || error[2])
{
static_cast<CcBool*>( result.addr )->Set(true, false);
}
else
{
static_cast<CcBool*>( result.addr )->Set(true, true);
}
return 0;
}
/******************************************************************************
7.3 insertStream - Specification of operator
******************************************************************************/
struct InsertStreamInfo : OperatorInfo {
InsertStreamInfo()
{
name = "insertStream";
signature = "((stream (tuple([a1:d1, ..., ai:uploadunit, "
"..., an:dn]))) x seti x ai) -> bool";
syntax = "_ insertStream[ _, _ ]";
meaning = "SETI insert upload stream operator.";
}
};
/******************************************************************************
8 intersectsWindow operator
Returns all trajectory segments which intersects the search window.
8.1 FindTrjSegments-method
Finds all trajectory segments which intersects the search window. The
intersectsWindow and the insideWindow operator make use of this method.
******************************************************************************/
set<TrjSeg*> FindTrjSegments( SETI* SETIPTR, SETIArea AREA,
Instant TIME1, Instant TIME2)
{
SETIHeader* hPtr = SETIPTR->GetHeader();
set<db_pgno_t>::iterator pIt;
set<db_pgno_t> pages;
map<int,TrjSeg*>::iterator sIt;
map<int,TrjSeg*> segments;
set<TrjSeg*> hits;
// Check if SmiUpdateFile is released
if(SETIPTR->GetSemaphore()) return hits;;
// Lock SmiUpdateFile
SETIPTR->SetSemaphore(true);
// Check/modify search window
if ((AREA.x2 < hPtr->area.x1) ||
(AREA.x1 > hPtr->area.x2) ||
(AREA.y2 < hPtr->area.y1) ||
(AREA.y1 > hPtr->area.y2))
return hits; // Search window does not intersect the SETI area
if (AREA.x1<hPtr->area.x1) AREA.x1 = hPtr->area.x1+tol;
if (AREA.x2>hPtr->area.x2) AREA.x2 = hPtr->area.x2-tol;
if (AREA.y1<hPtr->area.y1) AREA.y1 = hPtr->area.y1+tol;
if (AREA.y2>hPtr->area.y2) AREA.y2 = hPtr->area.y2-tol;
// Find pages which belong to the stated cell candidates
int left = ComputeLine(hPtr->area.x1,hPtr->area.x2,hPtr->splits,AREA.x1);
int right = ComputeLine(hPtr->area.x1,hPtr->area.x2,hPtr->splits,AREA.x2);
int bottom = ComputeLine(hPtr->area.y1,hPtr->area.y2,hPtr->splits,AREA.y1);
int top = ComputeLine(hPtr->area.y1,hPtr->area.y2,hPtr->splits,AREA.y2);
double minMax[] = {TIME1.ToDouble()-0.1,
TIME2.ToDouble()+0.1,
-1.0, 1.0};
Rectangle<2> searchBox = Rectangle<2>(true,minMax );
for (int i = bottom; i <= top; i++)
{
for (int j = left; j <= right; j++)
{
if (SETIPTR->GetCell(j,i)->currentPage != 0)
{
// Insert current page number
pages.insert(SETIPTR->GetCell(j,i)->currentPage);
}
R_TreeLeafEntry<2, TupleId> e;
if ( SETIPTR->GetCell(j,i)->rtreePtr->First( searchBox, e ) )
{
// Insert page numbers found in RTree
pages.insert((db_pgno_t)e.info);
while ( SETIPTR->GetCell(j,i)->rtreePtr->Next(e) )
{
pages.insert((db_pgno_t)e.info);
}
}
}
}
db_pgno_t pageID;
SmiRecord pageRec;
int moID;
int segID;
double tivStart;
double tivEnd;
UnitPos pos1;
UnitPos pos2;
// Find segments in pages
for (pIt = pages.begin(); pIt != pages.end();)
{
pageID = *pIt;
SmiUpdatePage* page;
int PageSelected = SETIPTR->GetUpdateFile()->GetPage(pageID, page);
assert( PageSelected );
// Read number of segments in page
int numSegments;
page->Read( &numSegments, sizeof(int), 0 );
size_t offset = sizeof(int) + sizeof(Interval<Instant>);
// Read segments in page
for (int i = 0; i < numSegments; i++)
{
page->Read( &moID, sizeof(int), offset );
offset += sizeof(int);
page->Read( &segID, sizeof(int), offset );
offset += sizeof(int);
page->Read( &tivStart, sizeof(double), offset );
offset += sizeof(double);
page->Read( &tivEnd, sizeof(double), offset );
offset += sizeof(double);
page->Read( &pos1, sizeof(UnitPos), offset );
offset += sizeof(UnitPos);
page->Read( &pos2, sizeof(UnitPos), offset );
offset += sizeof(UnitPos);
// Merge segments if necessary
bool found = false;
sIt = segments.find(segID);
if ( sIt != segments.end() )
{
TrjSeg* segPtr = sIt->second;
if ( CompareFloats(segPtr->pos2.x, pos1.x) &&
CompareFloats(segPtr->pos2.y, pos1.y) )
{
segPtr->tivEnd = tivEnd;
segPtr->pos2 = pos2;
found = true;
}
if ( CompareFloats(segPtr->pos1.x, pos2.x) &&
CompareFloats(segPtr->pos1.y, pos2.y) )
{
segPtr->tivStart = tivStart;
segPtr->pos1 = pos1;
found = true;
}
}
if(!found) segments.insert(make_pair(segID,
new TrjSeg( moID, segID, tivStart, tivEnd, pos1, pos2 )));
}
// Drop page
SETIPTR->GetUpdateFile()->PutPage(page->GetPageNo(),false);
pages.erase(pIt++);
}
// Check if segment intersects window
for (sIt = segments.begin(); sIt != segments.end();)
{
TrjSeg* segPtr = sIt->second;
Instant segStart(instanttype);
Instant segEnd(instanttype);
segStart.ReadFrom(segPtr->tivStart);
segEnd.ReadFrom(segPtr->tivEnd);
if ( TIME1 <= segEnd &&
TIME2 >= segStart &&
((AREA.x1 <= segPtr->pos1.x && AREA.y1 <= segPtr->pos1.y &&
AREA.x2 >= segPtr->pos1.x && AREA.y2 >= segPtr->pos1.y) ||
(AREA.x1 <= segPtr->pos2.x && AREA.y1 <= segPtr->pos2.y &&
AREA.x2 >= segPtr->pos2.x && AREA.y2 >= segPtr->pos2.y)))
hits.insert(segPtr);
else delete segPtr;
segments.erase(sIt++);
}
// Release SmiUpdateFile
SETIPTR->SetSemaphore(false);
return hits;
}
/******************************************************************************
8.2 intersectsWindow - Type mapping method
******************************************************************************/
ListExpr IntersectsWinTM(ListExpr args)
{
// Check nested list
if(!(nl->ListLength( args ) == 4 &&
nl->IsEqual(nl->First(args),SETI::BasicType()) &&
nl->IsEqual(nl->Second(args),Rectangle<2>::BasicType()) &&
nl->IsEqual(nl->Third(args),Instant::BasicType()) &&
nl->IsEqual(nl->Fourth(args),Instant::BasicType())))
{
ErrorReporter::ReportError("seti x rect x instant x instant expected!");
return (nl->SymbolAtom( Symbol::TYPEERROR() ));
}
// Create output list
ListExpr tupleList = nl->TwoElemList(
nl->TwoElemList(nl->SymbolAtom("MovObjId"),
nl->SymbolAtom(CcInt::BasicType())),
nl->TwoElemList(nl->SymbolAtom("TrjSeg"),
nl->SymbolAtom(UPoint::BasicType())));
ListExpr streamList = nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
nl->TwoElemList(nl->SymbolAtom(Tuple::BasicType()),
tupleList));
return streamList;
}
/******************************************************************************
8.3 intersectsWindow - Value mapping method
******************************************************************************/
int IntersectsWinVM(Word* args, Word& result, int message,
Word& local, Supplier s)
{
struct Iterator
{
set<TrjSeg*> hits;
set<TrjSeg*>::iterator it;
Iterator(set<TrjSeg*> HITS)
{
hits = HITS;
it = hits.begin();
}
set<TrjSeg*>::iterator GetIterator() {return it;}
};
Iterator* iterator = static_cast<Iterator*>(local.addr);
switch( message )
{
case OPEN:
{
SETI* setiPtr = static_cast<SETI*>(args[0].addr);
Rectangle<2>* rect = static_cast<Rectangle<2>*>(args[1].addr);
Instant* time1 = static_cast<Instant*>(args[2].addr);
Instant* time2 = static_cast<Instant*>(args[3].addr);
// Change instant values if necessary
if (*time1 > *time2 )
{
Instant* temp = time2;
time2 = time1;
time1 = temp;
}
// Create SETI area
double x1(rect->MinD(0));
double x2(rect->MaxD(0));
double y1(rect->MinD(1));
double y2(rect->MaxD(1));
SETIArea area(x1,y1,x2,y2);
area = ModifyArea(area);
// Find trajectory segments which intersect the search window
set<TrjSeg*> hits = FindTrjSegments( setiPtr, area, *time1, *time2);
// Initialize iterator
iterator = new Iterator(hits);
local.addr = iterator;
return 0;
}
case REQUEST:
{
if ( (iterator != 0) && (iterator->it != iterator->hits.end()) )
{
TrjSeg* segment = *iterator->GetIterator();
CcInt* moID = new CcInt(true, segment->moID);
Interval<Instant>* tiv = new Interval<Instant>(
DateTime(0,0,instanttype),
DateTime(0,0,instanttype),
true, true );
tiv->start.ReadFrom(segment->tivStart);
tiv->end.ReadFrom(segment->tivEnd);
UPoint* upoint = new UPoint(*tiv, segment->pos1.x, segment->pos1.y,
segment->pos2.x, segment->pos2.y );
TupleType* tupType = new TupleType(nl->Second(GetTupleResultType(s)));
Tuple* tup = new Tuple( tupType );
tup->PutAttribute( 0, ( Attribute* ) moID );
tup->PutAttribute( 1, ( Attribute* ) upoint );
result.addr = tup;
delete tiv;
delete segment;
iterator->hits.erase(iterator->it++);
return YIELD;
}
else
{
result.addr = 0;
return CANCEL;
}
}
case CLOSE:
{
if (iterator != 0)
{
delete iterator;
local.addr = 0;
}
return 0;
}
default:
{
return -1;
}
}
}
/******************************************************************************
8.4 intersectsWindow - Specification of operator
******************************************************************************/
struct IntersectsWinInfo : OperatorInfo {
IntersectsWinInfo()
{
name = "intersectsWindow";
signature = "seti x rect x instant x instant -> "
"stream (tuple (MovObjId int)(TrjSeg upoint))";
syntax = "intersectsWindow ( _, _, _, _ )";
meaning = "Returns all trajectory segments which"
"intersect the search window.";
}
};
/******************************************************************************
9 insideWindow operator
Returns all trajectory segments inside the search window.
9.1 insideWindow - Type mapping method
******************************************************************************/
ListExpr InsideWinTM(ListExpr args)
{
// Check nested list
if(!(nl->ListLength( args ) == 4 &&
nl->IsEqual(nl->First(args),SETI::BasicType()) &&
nl->IsEqual(nl->Second(args),Rectangle<2>::BasicType()) &&
nl->IsEqual(nl->Third(args),Instant::BasicType()) &&
nl->IsEqual(nl->Fourth(args),Instant::BasicType())))
{
ErrorReporter::ReportError("seti x rect x instant x instant expected!");
return (nl->SymbolAtom( Symbol::TYPEERROR() ));
}
// Create output list
ListExpr tupleList = nl->TwoElemList(
nl->TwoElemList(nl->SymbolAtom("MovObjId"),
nl->SymbolAtom(CcInt::BasicType())),
nl->TwoElemList(nl->SymbolAtom("TrjSeg"),
nl->SymbolAtom(UPoint::BasicType())));
ListExpr streamList = nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
nl->TwoElemList(nl->SymbolAtom(Tuple::BasicType()),
tupleList));
return streamList;
}
/******************************************************************************
9.2 insideWindow - Value mapping method
******************************************************************************/
int InsideWinVM(Word* args, Word& result,int message,Word& local,Supplier s)
{
struct Iterator
{
set<TrjSeg*> hits;
set<TrjSeg*>::iterator it;
Iterator(set<TrjSeg*> HITS)
{
hits = HITS;
it = hits.begin();
}
set<TrjSeg*>::iterator GetIterator() {return it;}
};
Iterator* iterator = static_cast<Iterator*>(local.addr);
switch( message )
{
case OPEN:
{
SETI* setiPtr = static_cast<SETI*>(args[0].addr);
Rectangle<2>* rect = static_cast<Rectangle<2>*>(args[1].addr);
Instant* time1 = static_cast<Instant*>(args[2].addr);
Instant* time2 = static_cast<Instant*>(args[3].addr);
// Change time values if necessary
if (*time1 > *time2 )
{
Instant* temp = time2;
time2 = time1;
time1 = temp;
}
// Create SETI area
double x1(rect->MinD(0));
double x2(rect->MaxD(0));
double y1(rect->MinD(1));
double y2(rect->MaxD(1));
SETIArea area(x1,y1,x2,y2);
area = ModifyArea(area);
// Find trajectory segments which the intersects search window
set<TrjSeg*> tempHits = FindTrjSegments( setiPtr, area, *time1, *time2);
// Check if all segments are inside the window
set<TrjSeg*>::iterator itTempHits;
set<TrjSeg*> hits;
for (itTempHits = tempHits.begin(); itTempHits != tempHits.end();
itTempHits++)
{
TrjSeg* segPtr = *itTempHits;
Instant segStart(instanttype);
Instant segEnd(instanttype);
segStart.ReadFrom(segPtr->tivStart);
segEnd.ReadFrom(segPtr->tivEnd);
if ( *time1 <= segStart &&
*time2 >= segEnd &&
area.x1 <= segPtr->pos1.x && area.x1 <= segPtr->pos2.x &&
area.x2 >= segPtr->pos1.x && area.x2 >= segPtr->pos2.x &&
area.y1 <= segPtr->pos1.y && area.y1 <= segPtr->pos2.y &&
area.y2 >= segPtr->pos1.y && area.y2 >= segPtr->pos2.y )
{
hits.insert(segPtr);
}
else delete segPtr;
}
// Initialize iterator
iterator = new Iterator(hits);
local.addr = iterator;
return 0;
}
case REQUEST:
{
if ( (iterator != 0) && (iterator->it != iterator->hits.end()) )
{
TrjSeg* segment = *iterator->GetIterator();
CcInt* moID = new CcInt(true, segment->moID);
Interval<Instant>* tiv = new Interval<Instant>(
DateTime(0,0,instanttype),
DateTime(0,0,instanttype),
true, true );
tiv->start.ReadFrom(segment->tivStart);
tiv->end.ReadFrom(segment->tivEnd);
UPoint* upoint = new UPoint(*tiv, segment->pos1.x, segment->pos1.y,
segment->pos2.x, segment->pos2.y );
TupleType* tupType = new TupleType(nl->Second(GetTupleResultType(s)));
Tuple* tup = new Tuple( tupType );
tup->PutAttribute( 0, ( Attribute* ) moID );
tup->PutAttribute( 1, ( Attribute* ) upoint );
result.addr = tup;
delete tiv;
delete segment;
iterator->hits.erase(iterator->it++);
return YIELD;
}
else
{
result.addr = 0;
return CANCEL;
}
}
case CLOSE:
{
if (iterator != 0)
{
delete iterator;
local.addr = 0;
}
return 0;
}
default:
{
return -1;
}
}
}
/******************************************************************************
9.3 insideWindow - Specification of operator
******************************************************************************/
struct InsideWinInfo : OperatorInfo {
InsideWinInfo()
{
name = "insideWindow";
signature = "seti x rect x instant x instant -> "
"stream (tuple (MovObjId int)(TrjSeg upoint))";
syntax = "insideWindow ( _, _, _, _ )";
meaning = "Returns all trajectory segments inside the search window.";
}
};
/******************************************************************************
10 getTrajectory operator
Returns all trajectory segments wich belongs to the stated moving object.
10.1 getTrajectory - Type mapping method
******************************************************************************/
ListExpr GetTrajectoryTM(ListExpr args)
{
if( nl->ListLength( args ) == 2 &&
nl->IsEqual(nl->First(args),SETI::BasicType()) &&
nl->IsEqual(nl->Second(args),CcInt::BasicType()))
{
ListExpr tupleList = nl->TwoElemList(
nl->TwoElemList(nl->SymbolAtom("MovObjId"),
nl->SymbolAtom(CcInt::BasicType())),
nl->TwoElemList(nl->SymbolAtom("TrjSeg"),
nl->SymbolAtom(UPoint::BasicType())));
ListExpr streamList = nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
nl->TwoElemList(nl->SymbolAtom(Tuple::BasicType()),
tupleList));
return streamList;
}
ErrorReporter::ReportError("seti x int expected!");
return (nl->SymbolAtom( Symbol::TYPEERROR() ));
}
/******************************************************************************
10.2 getTrajectory - Value mapping method
******************************************************************************/
int GetTrajectoryVM( Word* args, Word& result, int message, Word& local,
Supplier s )
{
struct Iterator
{
set<TrjSeg*> hits;
set<TrjSeg*>::iterator it;
Iterator(set<TrjSeg*> HITS)
{
hits = HITS;
it = hits.begin();
}
set<TrjSeg*>::iterator GetIterator() {return it;}
};
Iterator* iterator = static_cast<Iterator*>(local.addr);
switch( message )
{
case OPEN:
{
SETI* setiPtr = static_cast<SETI*>(args[0].addr);
CcInt* movObjId = static_cast<CcInt*>(args[1].addr);
int moID = movObjId->GetValue();
SETIArea area (setiPtr->GetHeader()->area.x1,
setiPtr->GetHeader()->area.y1,
setiPtr->GetHeader()->area.x2,
setiPtr->GetHeader()->area.y2);
// Find all trajectory segments
set<TrjSeg*> tempHits = FindTrjSegments( setiPtr, ModifyArea(area),
setiPtr->GetHeader()->tiv.start,
setiPtr->GetHeader()->tiv.end );
// Filter all segments which belongs to the stated moving object id
set<TrjSeg*>::iterator itTempHits;
set<TrjSeg*> hits;
for (itTempHits = tempHits.begin(); itTempHits != tempHits.end();
itTempHits++)
{
TrjSeg* segPtr = *itTempHits;
if ( moID == segPtr->moID )
{
hits.insert(segPtr);
}
else delete segPtr;
}
// Initialize iterator
iterator = new Iterator(hits);
local.addr = iterator;
return 0;
}
case REQUEST:
{
if ( iterator->it != iterator->hits.end() )
{
TrjSeg* segment = *iterator->GetIterator();
CcInt* moID = new CcInt(true, segment->moID);
Interval<Instant>* tiv = new Interval<Instant>(
DateTime(0,0,instanttype),
DateTime(0,0,instanttype),
true, true );
tiv->start.ReadFrom(segment->tivStart);
tiv->end.ReadFrom(segment->tivEnd);
UPoint* upoint = new UPoint(*tiv, segment->pos1.x, segment->pos1.y,
segment->pos2.x, segment->pos2.y );
TupleType* tupType = new TupleType(nl->Second(GetTupleResultType(s)));
Tuple* tup = new Tuple( tupType );
tup->PutAttribute( 0, ( Attribute* ) moID );
tup->PutAttribute( 1, ( Attribute* ) upoint );
result.addr = tup;
delete tiv;
delete segment;
iterator->hits.erase(iterator->it++);
return YIELD;
}
else
{
result.addr = 0;
return CANCEL;
}
}
case CLOSE:
{
if (iterator != 0)
{
delete iterator;
local.addr = 0;
}
return 0;
}
default:
{
return -1;
}
}
}
/******************************************************************************
10.3 getTrajectory - Specification of operator
******************************************************************************/
struct GetTrajectoryInfo : OperatorInfo {
GetTrajectoryInfo()
{
name = "getTrajectory";
signature = "seti x int -> "
"stream (tuple (MovObjId int)(TrjSeg upoint))";
syntax = "getTrajectory ( _, _ )";
meaning = "Returns all trajectory segments which belongs"
"to the stated moving object id.";
}
};
/******************************************************************************
11 currentUpload operator
Returns the current upload.
11.1 currentUpload - Type mapping method
******************************************************************************/
ListExpr CurrentUploadTM(ListExpr args)
{
if( nl->ListLength( args ) == 2 &&
nl->IsEqual(nl->First(args),SETI::BasicType()) &&
nl->IsEqual(nl->Second(args),CcInt::BasicType()) )
{
return nl->SymbolAtom(UploadUnit::BasicType());
}
ErrorReporter::ReportError("seti x int expected!");
return (nl->SymbolAtom( Symbol::TYPEERROR() ));
}
/******************************************************************************
11.2 currentUpload - Value mapping method
******************************************************************************/
int CurrentUploadVM(Word* args,Word& result,int message,Word& local,Supplier s)
{
SETI* setiPtr = static_cast<SETI*>(args[0].addr);
CcInt* moID = static_cast<CcInt*>(args[1].addr);
UploadUnit* unitPtr = static_cast<UploadUnit*>(qp->ResultStorage(s).addr);
// Find UploadUnit in frontline
int id = moID->GetValue();
map<int,UploadUnit>::iterator it;
it = setiPtr->frontline[id%flBuckets].find(id);
if ( it == setiPtr->frontline[id%flBuckets].end() )
{
unitPtr = new UploadUnit();
unitPtr->SetDefined(false);
}
else
{
unitPtr = new UploadUnit(it->second);
unitPtr->SetDefined(true);
}
result.setAddr( unitPtr );
return 0;
}
/******************************************************************************
11.3 currentUpload - Specification of operator
******************************************************************************/
struct CurrentUploadInfo : OperatorInfo {
CurrentUploadInfo()
{
name = "currentUpload";
signature = "seti x int -> uploadunit";
syntax = "currentUpload ( _, _ )";
meaning = "Returns the current UploadUnit.";
}
};
/******************************************************************************
12 ConvertMP2UUTM operator
Converts a stream of mpoints/moids into a stream of uploadunits.
12.1 convertMP2UUTM - Type mapping method
******************************************************************************/
bool isMPoint = true;
ListExpr ConvertMP2UUTM(ListExpr args)
{
NList type(args);
if ( !type.hasLength(4) )
{
return listutils::typeError("Expecting four arguments.");
}
NList first = type.first();
if ( !first.hasLength(2) ||
!first.first().isSymbol(Symbol::STREAM()) ||
!first.second().hasLength(2) ||
!first.second().first().isSymbol(Tuple::BasicType()) ||
!IsTupleDescription( first.second().second().listExpr() ))
{
return listutils::typeError("Error in first argument!");
}
if ( !nl->IsEqual(nl->Second(args), CcInt::BasicType()) )
{
return NList::typeError( "int for second argument expected!" );
}
NList third = type.third();
if ( !third.isSymbol() )
{
return NList::typeError( "Attribute name for third argument expected!" );
}
NList fourth = type.fourth();
if ( !fourth.isSymbol() )
{
return NList::typeError( "Attribute name for fourth argument expected!" );
}
string attrname1 = type.third().str();
ListExpr attrtype1 = nl->Empty();
int j = FindAttribute(first.second().second().listExpr(),attrname1,attrtype1);
string attrname2 = type.fourth().str();
ListExpr attrtype2 = nl->Empty();
int k = FindAttribute(first.second().second().listExpr(),attrname2,attrtype2);
if ( j != 0 )
{
if ( nl->SymbolValue(attrtype1) != CcInt::BasicType() )
{
return NList::typeError("First attribute type is not of type int.");
}
}
else
{
return NList::typeError("Unknown attribute name '" + attrname1 + "' !");
}
if ( k != 0 )
{
if ( nl->SymbolValue(attrtype2) != "mpoint" &&
nl->SymbolValue(attrtype2) != UPoint::BasicType())
{
return NList::typeError("Second attribute is not of type"
" mpoint or upoint.");
}
if ( nl->SymbolValue(attrtype2) == UPoint::BasicType()) isMPoint = false;
else isMPoint = true;
}
else
{
return NList::typeError("Unknown attribute name '" + attrname2 + "' !");
}
// Create output list
ListExpr tupleList = nl->OneElemList(
nl->TwoElemList(nl->SymbolAtom("Upload"),
nl->SymbolAtom(UploadUnit::BasicType())));
ListExpr outputstream = nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
nl->TwoElemList(nl->SymbolAtom(Tuple::BasicType()),
tupleList));
return NList( NList(Symbol::APPEND()),
nl->TwoElemList(nl->IntAtom(j), nl->IntAtom(k)),
outputstream ).listExpr();
}
/******************************************************************************
12.2 convertMP2UUVM - Value mapping method
******************************************************************************/
int ConvertMP2UUVM(Word* args, Word& result, int message,
Word& local, Supplier s)
{
struct Iterator
{
Iterator()
{
it = 0;
cnt = 0;
}
int it;
int cnt;
Word currentTupleWord;
};
Iterator* iterator = static_cast<Iterator*>(local.addr);
switch( message )
{
case OPEN:
{
iterator = new Iterator();
local.addr = iterator;
qp->Open(args[0].addr);
return 0;
}
case REQUEST:
{
int numUploads = static_cast<CcInt*>( args[1].addr )->GetIntval();
int attr1 = static_cast<CcInt*>( args[4].addr )->GetIntval() - 1;
int attr2 = static_cast<CcInt*>( args[5].addr )->GetIntval() - 1;
bool received = true;
if (iterator->it == 0)
{
qp->Request( args[0].addr, iterator->currentTupleWord );
received = qp->Received(args[0].addr);
}
if ( received && iterator->cnt < numUploads )
{
Tuple* currentTuple = static_cast<Tuple*>
( iterator->currentTupleWord.addr );
int moID = static_cast<CcInt*>(currentTuple->GetAttribute(attr1))
->GetIntval();
if (isMPoint)
{
MPoint* mp = static_cast<MPoint*>(currentTuple->GetAttribute(attr2));
UPoint up;
mp->Get(iterator->it,up);
UnitPos pos( up.p1.GetX(), up.p1.GetY() );
UploadUnit* uu = new UploadUnit(moID, up.timeInterval.end, pos );
TupleType* tupType =new TupleType(nl->Second(GetTupleResultType(s)));
Tuple* tup = new Tuple( tupType );
tup->PutAttribute( 0, ( Attribute* ) uu );
result.addr = tup;
iterator->it++;
iterator->cnt++;
if (iterator->it == mp->GetNoComponents()) iterator->it = 0;
}
else
{
UPoint* up = static_cast<UPoint*>(currentTuple->GetAttribute(attr2));
UnitPos pos( up->p1.GetX(), up->p1.GetY() );
UploadUnit* uu = new UploadUnit(moID, up->timeInterval.end, pos );
TupleType* tupType =new TupleType(nl->Second(GetTupleResultType(s)));
Tuple* tup = new Tuple( tupType );
tup->PutAttribute( 0, ( Attribute* ) uu );
result.addr = tup;
iterator->cnt++;
}
return YIELD;
}
else
{
delete iterator;
local.addr = 0;
result.addr = 0;
return CANCEL;
}
}
case CLOSE:
{
return 0;
}
default:
{
return -1;
}
}
}
/******************************************************************************
12.3 convertMP2UU - Specification of operator
******************************************************************************/
struct ConvertMP2UUInfo : OperatorInfo {
ConvertMP2UUInfo()
{
name = "convertMP2UU";
signature = "((stream (tuple([a1:d1, ..., ai:int, ..., "
"aj:mpoint|upoint, ..., an:dn]))) x int x ai x aj)"
" -> stream (tuple (Upload uploadunit))";
syntax = "_ convertMP2UU [ _, _, _ ]";
meaning = "Converts mpoints into upload units.";
}
};
/******************************************************************************
13 Type constructor of class UploadUnit
******************************************************************************/
TypeConstructor UploadUnitTC(
UploadUnit::BasicType(), // name
UploadUnit::Property, // property function
UploadUnit::Out, UploadUnit::In, // Out and In functions
0, 0, // SaveTo and RestoreFrom functions
UploadUnit::Create, UploadUnit::Delete, // object creation and deletion
UploadUnit::Open, UploadUnit::Save, // object open and save
UploadUnit::Close, UploadUnit::Clone, // object close and clone
UploadUnit::Cast, // cast function
UploadUnit::SizeOfObj, // sizeof function
UploadUnit::KindCheck ); // kind checking function
/******************************************************************************
14 Declaration of SETIAlgebra
******************************************************************************/
class SETIAlgebra : public Algebra
{
public:
SETIAlgebra() : Algebra()
{
AddTypeConstructor(&UploadUnitTC);
AddTypeConstructor(&SETITC);
UploadUnitTC.AssociateKind( Kind::DATA() );
AddOperator( CreateInfo(), CreateVM, CreateTM );
AddOperator( InsertUploadInfo(), InsertUploadVM, InsertUploadTM );
AddOperator( InsertStreamInfo(), InsertStreamVM, InsertStreamTM );
AddOperator( IntersectsWinInfo(), IntersectsWinVM, IntersectsWinTM );
AddOperator( InsideWinInfo(), InsideWinVM, InsideWinTM );
AddOperator( CurrentUploadInfo(), CurrentUploadVM, CurrentUploadTM );
AddOperator( GetTrajectoryInfo(), GetTrajectoryVM, GetTrajectoryTM );
AddOperator( ConvertMP2UUInfo(), ConvertMP2UUVM, ConvertMP2UUTM );
}
~SETIAlgebra() {};
};
/******************************************************************************
15 Initialization of SETIAlgebra
******************************************************************************/
extern "C"
Algebra*
InitializeSETIAlgebra( NestedList *nlRef,
QueryProcessor *qpRef,
AlgebraManager* amRef )
{
nl = nlRef;
qp = qpRef;
am = amRef;
return (new SETIAlgebra());
}
} // End of SETIAlgebra namespace