3150 lines
96 KiB
C++
3150 lines
96 KiB
C++
|
|
/******************************************************************************
|
||
|
|
----
|
||
|
|
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] Declaration of UGridAlgebra
|
||
|
|
|
||
|
|
September 2010, Daniel Brockmann
|
||
|
|
|
||
|
|
1 Overview
|
||
|
|
|
||
|
|
UGrid-Algebra implements a UGrid index structure. The memory management is
|
||
|
|
based on SmiUpdateFile.
|
||
|
|
|
||
|
|
UGrid-Algebra offers the following methods:
|
||
|
|
|
||
|
|
- createUGrid -> Creates a new UGrid object.
|
||
|
|
- insertUpload -> Inserts a single upload into UGrid.
|
||
|
|
- insertStream -> Inserts a stream of uploads into UGrid.
|
||
|
|
- intersectsWindow -> Returns all history units which
|
||
|
|
intersect the search window.
|
||
|
|
- insideWindow -> Returns all history units
|
||
|
|
inside the search window.
|
||
|
|
- getTrajectory -> Returns all history units 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 "Algebras/SETI/UploadUnit.h"
|
||
|
|
#include "Symbols.h"
|
||
|
|
|
||
|
|
using namespace std;
|
||
|
|
using namespace temporalalgebra;
|
||
|
|
using namespace datetime;
|
||
|
|
|
||
|
|
extern NestedList* nl;
|
||
|
|
extern QueryProcessor *qp;
|
||
|
|
extern AlgebraManager *am;
|
||
|
|
|
||
|
|
namespace UGridAlgebra {
|
||
|
|
|
||
|
|
#include "UGridAlgebra.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.
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
UGridArea ModifyArea(UGridArea 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), (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;
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
3.5 CreateUGridBox
|
||
|
|
|
||
|
|
Creates an UGridBox which constists of a page number and a 3D-rectangle.
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
UGridBox* CreateUGridBox( UGridCell* CELLPTR, UGridNode* NODEPTR )
|
||
|
|
{
|
||
|
|
UGridBox* ugridBox = (UGridBox*)0;
|
||
|
|
|
||
|
|
if ( CELLPTR != 0 )
|
||
|
|
{
|
||
|
|
double minMax[] = {CELLPTR->pos1.x-tol, CELLPTR->pos2.x+tol,
|
||
|
|
CELLPTR->pos1.y-tol, CELLPTR->pos2.y+tol,
|
||
|
|
CELLPTR->tiv.start.ToDouble(),
|
||
|
|
CELLPTR->tiv.end.ToDouble()};
|
||
|
|
Rectangle<3> box(true, minMax);
|
||
|
|
ugridBox = new UGridBox(CELLPTR->currentPage, true, box);
|
||
|
|
|
||
|
|
// Reset cell
|
||
|
|
CELLPTR->pos1.x = 0;
|
||
|
|
CELLPTR->pos1.y = 0;
|
||
|
|
CELLPTR->pos2.x = 0;
|
||
|
|
CELLPTR->pos2.y = 0;
|
||
|
|
CELLPTR->tiv.lc = false;
|
||
|
|
CELLPTR->tiv.rc = false;
|
||
|
|
CELLPTR->numEntries = 0;
|
||
|
|
|
||
|
|
}
|
||
|
|
else if ( NODEPTR != 0 )
|
||
|
|
{
|
||
|
|
double minMax[] = {NODEPTR->pos1.x-tol, NODEPTR->pos2.x+tol,
|
||
|
|
NODEPTR->pos1.y-tol, NODEPTR->pos2.y+tol,
|
||
|
|
NODEPTR->tiv.start.ToDouble(),
|
||
|
|
NODEPTR->tiv.end.ToDouble()};
|
||
|
|
Rectangle<3> box(true,minMax);
|
||
|
|
|
||
|
|
ugridBox = new UGridBox(NODEPTR->currentPage, false, box);
|
||
|
|
|
||
|
|
// Reset node
|
||
|
|
NODEPTR->pos1.x = 0;
|
||
|
|
NODEPTR->pos1.y = 0;
|
||
|
|
NODEPTR->pos2.x = 0;
|
||
|
|
NODEPTR->pos2.y = 0;
|
||
|
|
NODEPTR->tiv.lc = false;
|
||
|
|
NODEPTR->tiv.rc = false;
|
||
|
|
}
|
||
|
|
return ugridBox;
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
3.6 ModifyUGridNode
|
||
|
|
|
||
|
|
Modifies the values of a UGridNode in dependence of the UgridBox.
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
void ModifyUGridNode( UGridNode* NODEPTR, UGridBox* BOX )
|
||
|
|
{
|
||
|
|
double x1(BOX->box.MinD(0));
|
||
|
|
double x2(BOX->box.MaxD(0));
|
||
|
|
double y1(BOX->box.MinD(1));
|
||
|
|
double y2(BOX->box.MaxD(1));
|
||
|
|
double t1(BOX->box.MinD(2));
|
||
|
|
double t2(BOX->box.MaxD(2));
|
||
|
|
|
||
|
|
Instant T1 = DateTime(0,0,instanttype);
|
||
|
|
Instant T2 = DateTime(0,0,instanttype);
|
||
|
|
T1.ReadFrom(t1);
|
||
|
|
T2.ReadFrom(t2);
|
||
|
|
|
||
|
|
if (x1 < NODEPTR->pos1.x) NODEPTR->pos1.x = x1;
|
||
|
|
if (y1 < NODEPTR->pos1.y) NODEPTR->pos1.y = y1;
|
||
|
|
if (x2 > NODEPTR->pos2.x) NODEPTR->pos2.x = x2;
|
||
|
|
if (y2 > NODEPTR->pos2.y) NODEPTR->pos2.y = y2;
|
||
|
|
|
||
|
|
if ((NODEPTR->tiv.lc == false) || (T1 < NODEPTR->tiv.start))
|
||
|
|
{
|
||
|
|
NODEPTR->tiv.start = T1;
|
||
|
|
NODEPTR->tiv.lc = true;
|
||
|
|
}
|
||
|
|
if ((NODEPTR->tiv.rc == false) || (T2 > NODEPTR->tiv.end))
|
||
|
|
{
|
||
|
|
NODEPTR->tiv.end = T2;
|
||
|
|
NODEPTR->tiv.rc = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
NODEPTR->numEntries++;
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
3.7 CheckUGridNode
|
||
|
|
|
||
|
|
Returns true if the UGridNode intersects the search window.
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
bool CheckUGridNode( UGridArea AREA, Instant TIME1, Instant TIME2,
|
||
|
|
UGridNode* NODEPTR )
|
||
|
|
{
|
||
|
|
if ( AREA.x1 <= NODEPTR->pos2.x && AREA.y1 <= NODEPTR->pos2.y &&
|
||
|
|
AREA.x2 >= NODEPTR->pos1.x && AREA.y2 >= NODEPTR->pos1.y &&
|
||
|
|
TIME1 <= NODEPTR->tiv.end && TIME2 >= NODEPTR->tiv.start )
|
||
|
|
{
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
3.8 CheckUGridBox
|
||
|
|
|
||
|
|
Returns true if the UGridBox intersects the search window.
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
bool CheckUGridBox(UGridArea AREA, Instant TIME1, Instant TIME2, UGridBox BOX)
|
||
|
|
{
|
||
|
|
double boxPos1x(BOX.box.MinD(0));
|
||
|
|
double boxPos2x(BOX.box.MaxD(0));
|
||
|
|
double boxPos1y(BOX.box.MinD(1));
|
||
|
|
double boxPos2y(BOX.box.MaxD(1));
|
||
|
|
double boxT1(BOX.box.MinD(2));
|
||
|
|
double boxT2(BOX.box.MaxD(2));
|
||
|
|
|
||
|
|
Instant* boxTivStart = new DateTime(0,0,instanttype);
|
||
|
|
Instant* boxTivEnd = new DateTime(0,0,instanttype);
|
||
|
|
boxTivStart->ReadFrom(boxT1);
|
||
|
|
boxTivEnd->ReadFrom(boxT2);
|
||
|
|
|
||
|
|
if ( AREA.x1 <= boxPos2x && AREA.y1 <= boxPos2y &&
|
||
|
|
AREA.x2 >= boxPos1x && AREA.y2 >= boxPos1y &&
|
||
|
|
TIME1 <= *boxTivEnd && TIME2 >= *boxTivStart )
|
||
|
|
{
|
||
|
|
delete boxTivStart;
|
||
|
|
delete boxTivEnd;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
delete boxTivStart;
|
||
|
|
delete boxTivEnd;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
4 Implementation of class UGrid
|
||
|
|
|
||
|
|
4.1 Basic constructor
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
UGrid::UGrid(UGridArea AREA, int SPLITS) : suf(0)
|
||
|
|
{
|
||
|
|
// Create UGrid Header
|
||
|
|
header = new UGridHeader(ModifyArea(AREA), SPLITS);
|
||
|
|
// Create SmiUpdateFile
|
||
|
|
suf = new SmiUpdateFile(pageSize);
|
||
|
|
suf->Create();
|
||
|
|
header->fileID = suf->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 cell pages
|
||
|
|
SmiUpdatePage* cellPage;
|
||
|
|
numEntries = 0;
|
||
|
|
for(int i = 0; i < 8; i++)
|
||
|
|
{
|
||
|
|
for(int j = 0; j < 8; j++)
|
||
|
|
{
|
||
|
|
AppendedPage = suf->AppendNewPage(cellPage);
|
||
|
|
assert( AppendedPage );
|
||
|
|
header->cellPageNo[j][i] = cellPage->GetPageNo();
|
||
|
|
// Initialize cell page
|
||
|
|
int PageSelected = suf->GetPage(header->cellPageNo[j][i], cellPage);
|
||
|
|
assert( PageSelected );
|
||
|
|
cellPage->Write(&numEntries, sizeof(db_pgno_t), 0);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Create and initialize first node page
|
||
|
|
SmiUpdatePage* nodePage;
|
||
|
|
AppendedPage = suf->AppendNewPage(nodePage);
|
||
|
|
assert( AppendedPage );
|
||
|
|
header->nodePageNo = nodePage->GetPageNo();
|
||
|
|
PageSelected = suf->GetPage(header->nodePageNo, nodePage);
|
||
|
|
assert( PageSelected );
|
||
|
|
nodePage->Write(&nextPageNo, sizeof(db_pgno_t), 0);
|
||
|
|
|
||
|
|
// Create a quad-tree like structure
|
||
|
|
header->rootNode = CreateUGridTree((UGridNode*)0, header->numCells,
|
||
|
|
header->splits, header->splits);
|
||
|
|
|
||
|
|
// Write header and tree into SmiUpdateFile
|
||
|
|
UpdateHeader();
|
||
|
|
UpdateUGridTree(header->rootNode, header->numCells,
|
||
|
|
header->splits, header->splits);
|
||
|
|
|
||
|
|
// Initialize semaphore
|
||
|
|
SetSemaphore(false);
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
4.2 Query constructor
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
UGrid::UGrid(SmiFileId FILEID) : suf(0)
|
||
|
|
{
|
||
|
|
// Open extisting file
|
||
|
|
suf = new SmiUpdateFile(pageSize);
|
||
|
|
suf->Open(FILEID, pageSize);
|
||
|
|
|
||
|
|
// Create header object
|
||
|
|
header = new UGridHeader();
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
4.3 Destructor
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
UGrid::~UGrid()
|
||
|
|
{
|
||
|
|
// Destruct UGrid-tree
|
||
|
|
DestructUGridTree( header->rootNode, header->numCells );
|
||
|
|
|
||
|
|
// Delete header
|
||
|
|
delete header;
|
||
|
|
|
||
|
|
// Clear frontline
|
||
|
|
for (int i = 0; i < flBuckets; i++)
|
||
|
|
{
|
||
|
|
frontline[i].clear();
|
||
|
|
}
|
||
|
|
|
||
|
|
// Delete file object
|
||
|
|
if(suf->IsOpen()) suf->Close();
|
||
|
|
delete suf;
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
4.4 The mandatory set of algebra support functions
|
||
|
|
|
||
|
|
4.4.1 In-method
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
Word UGrid::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;
|
||
|
|
}
|
||
|
|
UGridArea 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 (!(numPartitions == 4096 ||
|
||
|
|
numPartitions == 256 ||
|
||
|
|
numPartitions == 16 ||
|
||
|
|
numPartitions == 4))
|
||
|
|
{
|
||
|
|
// Wrong number of partitions -> create default UGrid
|
||
|
|
result.addr = new UGrid(ModifyArea(area), 4);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
result.addr = new UGrid(ModifyArea(area), (int)sqrt(numPartitions));
|
||
|
|
}
|
||
|
|
correct = true;
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
4.4.2 Out-method
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
ListExpr UGrid::Out(ListExpr typeInfo, Word value )
|
||
|
|
{
|
||
|
|
UGrid* ugridPtr = static_cast<UGrid*>(value.addr);
|
||
|
|
|
||
|
|
// Create area list
|
||
|
|
ListExpr area = nl->FourElemList(
|
||
|
|
nl->RealAtom(ugridPtr->header->area.x1),
|
||
|
|
nl->RealAtom(ugridPtr->header->area.x2),
|
||
|
|
nl->RealAtom(ugridPtr->header->area.y1),
|
||
|
|
nl->RealAtom(ugridPtr->header->area.y2));
|
||
|
|
|
||
|
|
// Create time interval list
|
||
|
|
ListExpr tiv;
|
||
|
|
if (ugridPtr->header->numEntries == 0)
|
||
|
|
{
|
||
|
|
// Time interval is undefined if no entry exist
|
||
|
|
tiv = nl->TwoElemList( nl->SymbolAtom(Symbol::UNDEFINED()),
|
||
|
|
nl->SymbolAtom(Symbol::UNDEFINED()));
|
||
|
|
}
|
||
|
|
else if (ugridPtr->header->numEntries == 1)
|
||
|
|
{
|
||
|
|
// End time is undefined if only one entry exist
|
||
|
|
tiv = nl->TwoElemList(
|
||
|
|
OutDateTime(nl->TheEmptyList(),
|
||
|
|
SetWord(&ugridPtr->header->tiv.start)),
|
||
|
|
nl->SymbolAtom(Symbol::UNDEFINED()));
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// Time interval is defined if UGrid has two entries or more
|
||
|
|
tiv = nl->TwoElemList( OutDateTime(nl->TheEmptyList(),
|
||
|
|
SetWord(&ugridPtr->header->tiv.start)),
|
||
|
|
OutDateTime(nl->TheEmptyList(),
|
||
|
|
SetWord(&ugridPtr->header->tiv.end)));
|
||
|
|
}
|
||
|
|
// Return output list
|
||
|
|
return nl->TwoElemList(area, tiv);
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
4.4.3 Create-method
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
Word UGrid::Create( const ListExpr typeInfo )
|
||
|
|
{
|
||
|
|
return SetWord(Address(0));
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
4.4.4 Delete-method
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
void UGrid::Delete( const ListExpr typeInfo, Word& w )
|
||
|
|
{
|
||
|
|
UGrid* ugridPtr = static_cast<UGrid*>(w.addr);
|
||
|
|
delete ugridPtr;
|
||
|
|
w.addr = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
4.4.5 Open-method
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
bool UGrid::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 UGrid object with existing file
|
||
|
|
UGrid* ugridPtr = new UGrid(fileID);
|
||
|
|
ugridPtr->header->fileID = fileID;
|
||
|
|
ugridPtr->header->headerPageNo = headerPageNo;
|
||
|
|
|
||
|
|
// Reader header, frontline and UGridTree information from file
|
||
|
|
ugridPtr->ReadHeader();
|
||
|
|
ugridPtr->ReadFLine();
|
||
|
|
UGridHeader* hPtr = ugridPtr->header;
|
||
|
|
hPtr->rootNode = ugridPtr->ReadUGridTree( (UGridNode*)0,
|
||
|
|
hPtr->area, hPtr->numCells, hPtr->splits, hPtr->splits );
|
||
|
|
|
||
|
|
value.addr = ugridPtr;
|
||
|
|
return ok;
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
4.4.6 Save-method
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
bool UGrid::Save( SmiRecord& valueRecord, size_t& offset,
|
||
|
|
const ListExpr typeInfo, Word& value )
|
||
|
|
{
|
||
|
|
UGrid* ugridPtr = static_cast<UGrid*>(value.addr);
|
||
|
|
bool ok = true;
|
||
|
|
SmiFileId fileID = ugridPtr->header->fileID;
|
||
|
|
db_pgno_t headerPageNo = ugridPtr->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 UGrid::Close( const ListExpr typeInfo, Word& w )
|
||
|
|
{
|
||
|
|
UGrid* ugridPtr = static_cast<UGrid*>(w.addr);
|
||
|
|
delete ugridPtr;
|
||
|
|
w.addr = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
4.4.8 Clone-method
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
Word UGrid::Clone( const ListExpr typeInfo, const Word& w )
|
||
|
|
{
|
||
|
|
return SetWord(Address(0));
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
4.4.9 Cast-method
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
void* UGrid::Cast( void* addr)
|
||
|
|
{
|
||
|
|
return (0);
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
4.4.10 SizeOfObj-method
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
int UGrid::SizeOfObj()
|
||
|
|
{
|
||
|
|
return sizeof(UGrid);
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
4.4.11 KindCheck-method
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
bool UGrid::KindCheck(ListExpr type, ListExpr& errorInfo)
|
||
|
|
{
|
||
|
|
return (nl->IsEqual(type, UGrid::BasicType()));
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
4.4.12 Property-method
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
ListExpr UGrid::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(UGrid::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 real, "
|
||
|
|
"p of type int."))));
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
4.5 CreateUGridTree
|
||
|
|
|
||
|
|
Creates an UGridTree (quad-tree like structure) and initializes all UGridCells
|
||
|
|
(leaf nodes).
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
UGridNode* UGrid::CreateUGridTree( UGridNode* FATHERNODE, int SQUARES,
|
||
|
|
int RIGHTCOL, int TOPROW )
|
||
|
|
{
|
||
|
|
// Create and initialize UGrideNode
|
||
|
|
UGridNode* node = new UGridNode();
|
||
|
|
node->fatherNode = FATHERNODE;
|
||
|
|
node->numEntries = 0;
|
||
|
|
node->currentPage = (db_pgno_t)0;
|
||
|
|
node->pos1 = UnitPos(0,0);
|
||
|
|
node->pos2 = UnitPos(0,0);
|
||
|
|
node->tiv.start = DateTime(0,0,instanttype);
|
||
|
|
node->tiv.end = DateTime(0,0,instanttype);
|
||
|
|
node->tiv.lc = false;
|
||
|
|
node->tiv.rc = false;
|
||
|
|
|
||
|
|
if (SQUARES > 4)
|
||
|
|
{
|
||
|
|
// Create left-bottom son
|
||
|
|
node->leftBottomSon = CreateUGridTree( node, (SQUARES/4),
|
||
|
|
(RIGHTCOL-((int)sqrt(SQUARES)/2)),
|
||
|
|
(TOPROW-((int)sqrt(SQUARES)/2)));
|
||
|
|
// Create right-bottom son
|
||
|
|
node->rightBottomSon = CreateUGridTree( node, (SQUARES/4), RIGHTCOL,
|
||
|
|
(TOPROW-((int)sqrt(SQUARES)/2)));
|
||
|
|
// Create left-top son
|
||
|
|
node->leftTopSon = CreateUGridTree( node, (SQUARES/4),
|
||
|
|
(RIGHTCOL-((int)sqrt(SQUARES)/2)), TOPROW );
|
||
|
|
// Create right-top son
|
||
|
|
node->rightTopSon = CreateUGridTree( node, (SQUARES/4), RIGHTCOL, TOPROW );
|
||
|
|
|
||
|
|
node->leftBottomCell = (UGridCell*)0;
|
||
|
|
node->rightBottomCell = (UGridCell*)0;
|
||
|
|
node->leftTopCell = (UGridCell*)0;
|
||
|
|
node->rightTopCell = (UGridCell*)0;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
node->leftBottomSon = (UGridNode*)0;
|
||
|
|
node->rightBottomSon = (UGridNode*)0;
|
||
|
|
node->leftTopSon = (UGridNode*)0;
|
||
|
|
node->leftBottomSon = (UGridNode*)0;
|
||
|
|
|
||
|
|
for (int i = 0; i < 4; i++)
|
||
|
|
{
|
||
|
|
int col = RIGHTCOL-1;
|
||
|
|
int row = TOPROW-1;
|
||
|
|
|
||
|
|
if ( i == 0 ) { col = col-1; row = row-1; } // left-bottom cell
|
||
|
|
if ( i == 1 ) { row = row-1; } // right-bottom cell
|
||
|
|
if ( i == 2 ) { col = col-1; } // left-top cell
|
||
|
|
|
||
|
|
// Create and initialize UGridCell
|
||
|
|
cells[col][row] = new UGridCell();
|
||
|
|
UGridCell* cellPtr = cells[col][row];
|
||
|
|
cellPtr->fatherNode = node;
|
||
|
|
cellPtr->numEntries = 0;
|
||
|
|
cellPtr->currentPage = (db_pgno_t)0;
|
||
|
|
cellPtr->pos1 = UnitPos(0,0);
|
||
|
|
cellPtr->pos2 = UnitPos(0,0);
|
||
|
|
cellPtr->tiv.start = DateTime(0,0,instanttype);
|
||
|
|
cellPtr->tiv.end = DateTime(0,0,instanttype);
|
||
|
|
cellPtr->tiv.lc = false;
|
||
|
|
cellPtr->tiv.rc = false;
|
||
|
|
|
||
|
|
if ( i == 0 ) node->leftBottomCell = cellPtr;
|
||
|
|
if ( i == 1 ) node->rightBottomCell = cellPtr;
|
||
|
|
if ( i == 2 ) node->leftTopCell = cellPtr;
|
||
|
|
if ( i == 3 ) node->rightTopCell = cellPtr;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return node;
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
4.6 InsertUGridBox
|
||
|
|
|
||
|
|
Inserts a UGridBox into the UGridTree.
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
void UGrid::InsertUGridBox( UGridNode* NODE, UGridBox* BOX )
|
||
|
|
{
|
||
|
|
if ( (NODE->numEntries%60) == 0 )
|
||
|
|
{
|
||
|
|
if ( NODE->currentPage == 0 )
|
||
|
|
{
|
||
|
|
// Current page does not exists -> create new page
|
||
|
|
SmiUpdatePage* currentPage;
|
||
|
|
int AppendedPage = suf->AppendNewPage(currentPage);
|
||
|
|
assert( AppendedPage );
|
||
|
|
NODE->currentPage = currentPage->GetPageNo();
|
||
|
|
|
||
|
|
// Initialize page
|
||
|
|
db_pgno_t nextRootPageNo = 0;
|
||
|
|
int PageSelected = suf->GetPage(NODE->currentPage, currentPage);
|
||
|
|
assert( PageSelected );
|
||
|
|
currentPage->Write(&nextRootPageNo, sizeof(db_pgno_t), 0);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if ((NODE->leftBottomCell != 0) &&
|
||
|
|
(NODE->fatherNode != 0))
|
||
|
|
{
|
||
|
|
SmiUpdatePage* currentPage;
|
||
|
|
int PageSelected = suf->GetPage(NODE->currentPage, currentPage);
|
||
|
|
assert( PageSelected );
|
||
|
|
|
||
|
|
UGridBox* box;
|
||
|
|
// Current page is nearly full up
|
||
|
|
// -> write the boxes of all four son cells into page
|
||
|
|
size_t offset = sizeof(db_pgno_t) + (boxSize * NODE->numEntries);
|
||
|
|
|
||
|
|
// Insert boxes from all four sons(cells)
|
||
|
|
for (int i = 0; i < 4; i++)
|
||
|
|
{
|
||
|
|
// Current page of cell is not empty
|
||
|
|
if (i == 0) box =CreateUGridBox(NODE->leftBottomCell, (UGridNode*)0);
|
||
|
|
if (i == 1) box =CreateUGridBox(NODE->rightBottomCell,(UGridNode*)0);
|
||
|
|
if (i == 2) box =CreateUGridBox(NODE->leftTopCell, (UGridNode*)0);
|
||
|
|
if (i == 3) box =CreateUGridBox(NODE->rightTopCell, (UGridNode*)0);
|
||
|
|
|
||
|
|
if (box != 0)
|
||
|
|
{
|
||
|
|
ModifyUGridNode( NODE, box );
|
||
|
|
|
||
|
|
double minD0(box->box.MinD(0)); double maxD0(box->box.MaxD(0));
|
||
|
|
double minD1(box->box.MinD(1)); double maxD1(box->box.MaxD(1));
|
||
|
|
double minD2(box->box.MinD(2)); double maxD2(box->box.MaxD(2));
|
||
|
|
|
||
|
|
currentPage->Write(&box->pageID, sizeof(db_pgno_t), offset);
|
||
|
|
offset += sizeof(db_pgno_t);
|
||
|
|
currentPage->Write(&box->huPageID, sizeof(bool), offset);
|
||
|
|
offset += sizeof(bool);
|
||
|
|
currentPage->Write(&minD0, sizeof(double), offset);
|
||
|
|
offset += sizeof(double);
|
||
|
|
currentPage->Write(&maxD0, sizeof(double), offset);
|
||
|
|
offset += sizeof(double);
|
||
|
|
currentPage->Write(&minD1, sizeof(double), offset);
|
||
|
|
offset += sizeof(double);
|
||
|
|
currentPage->Write(&maxD1, sizeof(double), offset);
|
||
|
|
offset += sizeof(double);
|
||
|
|
currentPage->Write(&minD2, sizeof(double), offset);
|
||
|
|
offset += sizeof(double);
|
||
|
|
currentPage->Write(&maxD2, sizeof(double), offset);
|
||
|
|
offset += sizeof(double);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (NODE->fatherNode != 0)
|
||
|
|
{
|
||
|
|
// Create page box
|
||
|
|
UGridBox* box = CreateUGridBox( (UGridCell*)0, NODE );
|
||
|
|
if (box != 0)
|
||
|
|
{
|
||
|
|
// Reset number of node entries
|
||
|
|
NODE->numEntries = 0;
|
||
|
|
|
||
|
|
// Put current node page back to file
|
||
|
|
//suf->PutPage(NODE->currentPage, true);
|
||
|
|
|
||
|
|
// Insert box from son node into father node page
|
||
|
|
InsertUGridBox( NODE->fatherNode, box );
|
||
|
|
|
||
|
|
// Create new node page
|
||
|
|
SmiUpdatePage* currentPage;
|
||
|
|
int AppendedPage = suf->AppendNewPage(currentPage);
|
||
|
|
assert( AppendedPage );
|
||
|
|
NODE->currentPage = currentPage->GetPageNo();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// Create next page for root node
|
||
|
|
db_pgno_t prevPageNo = NODE->currentPage;
|
||
|
|
SmiUpdatePage* prevPage;
|
||
|
|
db_pgno_t nextRootPageNo;
|
||
|
|
SmiUpdatePage* nextRootPage;
|
||
|
|
|
||
|
|
do
|
||
|
|
{
|
||
|
|
int PageSelected = suf->GetPage(prevPageNo, prevPage);
|
||
|
|
assert( PageSelected );
|
||
|
|
prevPage->Read(&nextRootPageNo, sizeof(db_pgno_t), 0);
|
||
|
|
prevPageNo = nextRootPageNo;
|
||
|
|
}
|
||
|
|
while ( nextRootPageNo != 0 );
|
||
|
|
|
||
|
|
int AppendedPage = suf->AppendNewPage(nextRootPage);
|
||
|
|
assert( AppendedPage );
|
||
|
|
nextRootPageNo = nextRootPage->GetPageNo();
|
||
|
|
int PageSelected = suf->GetPage(nextRootPageNo, nextRootPage);
|
||
|
|
assert( PageSelected );
|
||
|
|
prevPage->Write(&nextRootPageNo, sizeof(db_pgno_t), 0);
|
||
|
|
nextRootPageNo = 0;
|
||
|
|
nextRootPage->Write(&nextRootPageNo, sizeof(db_pgno_t), 0);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
SmiUpdatePage* currentPage;
|
||
|
|
int PageSelected = suf->GetPage(NODE->currentPage, currentPage);
|
||
|
|
assert( PageSelected );
|
||
|
|
|
||
|
|
if (NODE->fatherNode != 0)
|
||
|
|
{
|
||
|
|
size_t offset = sizeof(db_pgno_t) + (boxSize * NODE->numEntries);
|
||
|
|
ModifyUGridNode( NODE, BOX );
|
||
|
|
|
||
|
|
// Insert new UGridBox into node page
|
||
|
|
double minD0(BOX->box.MinD(0)); double maxD0(BOX->box.MaxD(0));
|
||
|
|
double minD1(BOX->box.MinD(1)); double maxD1(BOX->box.MaxD(1));
|
||
|
|
double minD2(BOX->box.MinD(2)); double maxD2(BOX->box.MaxD(2));
|
||
|
|
|
||
|
|
currentPage->Write(&BOX->pageID, sizeof(db_pgno_t), offset);
|
||
|
|
offset += sizeof(db_pgno_t);
|
||
|
|
currentPage->Write(&BOX->huPageID, sizeof(bool), offset);
|
||
|
|
offset += sizeof(bool);
|
||
|
|
currentPage->Write(&minD0, sizeof(double), offset);
|
||
|
|
offset += sizeof(double);
|
||
|
|
currentPage->Write(&maxD0, sizeof(double), offset);
|
||
|
|
offset += sizeof(double);
|
||
|
|
currentPage->Write(&minD1, sizeof(double), offset);
|
||
|
|
offset += sizeof(double);
|
||
|
|
currentPage->Write(&maxD1, sizeof(double), offset);
|
||
|
|
offset += sizeof(double);
|
||
|
|
currentPage->Write(&minD2, sizeof(double), offset);
|
||
|
|
offset += sizeof(double);
|
||
|
|
currentPage->Write(&maxD2, sizeof(double), offset);
|
||
|
|
offset += sizeof(double);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// Insert new UGridBox into root page
|
||
|
|
db_pgno_t nextRootPageNo = NODE->currentPage;
|
||
|
|
SmiUpdatePage* nextRootPage;
|
||
|
|
do
|
||
|
|
{
|
||
|
|
int PageSelected = suf->GetPage(nextRootPageNo, nextRootPage);
|
||
|
|
assert( PageSelected );
|
||
|
|
nextRootPage->Read(&nextRootPageNo, sizeof(db_pgno_t), 0);
|
||
|
|
}
|
||
|
|
while ( nextRootPageNo != 0 );
|
||
|
|
|
||
|
|
size_t offset = sizeof(db_pgno_t) + (boxSize * (NODE->numEntries%60));
|
||
|
|
ModifyUGridNode( NODE, BOX );
|
||
|
|
|
||
|
|
double minD0(BOX->box.MinD(0)); double maxD0(BOX->box.MaxD(0));
|
||
|
|
double minD1(BOX->box.MinD(1)); double maxD1(BOX->box.MaxD(1));
|
||
|
|
double minD2(BOX->box.MinD(2)); double maxD2(BOX->box.MaxD(2));
|
||
|
|
|
||
|
|
nextRootPage->Write(&BOX->pageID, sizeof(db_pgno_t), offset);
|
||
|
|
offset += sizeof(db_pgno_t);
|
||
|
|
nextRootPage->Write(&BOX->huPageID, sizeof(bool), offset);
|
||
|
|
offset += sizeof(bool);
|
||
|
|
nextRootPage->Write(&minD0, sizeof(double), offset);
|
||
|
|
offset += sizeof(double);
|
||
|
|
nextRootPage->Write(&maxD0, sizeof(double), offset);
|
||
|
|
offset += sizeof(double);
|
||
|
|
nextRootPage->Write(&minD1, sizeof(double), offset);
|
||
|
|
offset += sizeof(double);
|
||
|
|
nextRootPage->Write(&maxD1, sizeof(double), offset);
|
||
|
|
offset += sizeof(double);
|
||
|
|
nextRootPage->Write(&minD2, sizeof(double), offset);
|
||
|
|
offset += sizeof(double);
|
||
|
|
nextRootPage->Write(&maxD2, sizeof(double), offset);
|
||
|
|
offset += sizeof(double);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
4.7 DestructUGridTree
|
||
|
|
|
||
|
|
Destructs the UGridTree.
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
void UGrid::DestructUGridTree( UGridNode* NODE, int SQUARES )
|
||
|
|
{
|
||
|
|
if (SQUARES > 4)
|
||
|
|
{
|
||
|
|
DestructUGridTree( NODE->leftBottomSon, (SQUARES/4));
|
||
|
|
DestructUGridTree( NODE->rightBottomSon, (SQUARES/4));
|
||
|
|
DestructUGridTree( NODE->leftTopSon, (SQUARES/4));
|
||
|
|
DestructUGridTree( NODE->rightTopSon, (SQUARES/4));
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
delete NODE->leftBottomCell;
|
||
|
|
delete NODE->rightBottomCell;
|
||
|
|
delete NODE->leftTopCell;
|
||
|
|
delete NODE->rightTopCell;
|
||
|
|
}
|
||
|
|
delete NODE;
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
4.8 ReadHeader-method
|
||
|
|
|
||
|
|
Reads UGrid-header information from file.
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
void UGrid::ReadHeader()
|
||
|
|
{
|
||
|
|
SmiUpdatePage* headerPage;
|
||
|
|
int PageSelected = suf->GetPage(header->headerPageNo, headerPage);
|
||
|
|
assert( PageSelected );
|
||
|
|
|
||
|
|
size_t offset = 0;
|
||
|
|
headerPage->Read(&header->flPageNo, sizeof(db_pgno_t), offset);
|
||
|
|
offset += sizeof(db_pgno_t);
|
||
|
|
for (int i = 0; i < 8; i++)
|
||
|
|
{
|
||
|
|
for (int j = 0; j < 8; j++)
|
||
|
|
{
|
||
|
|
headerPage->Read(&header->cellPageNo[j][i], sizeof(db_pgno_t), offset);
|
||
|
|
offset += sizeof(db_pgno_t);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
headerPage->Read(&header->nodePageNo, sizeof(db_pgno_t), offset);
|
||
|
|
offset += sizeof(db_pgno_t);
|
||
|
|
headerPage->Read(&header->rootNode, sizeof(UGridNode*), offset);
|
||
|
|
offset += sizeof(UGridNode*);
|
||
|
|
headerPage->Read(&header->area, sizeof(UGridArea), offset);
|
||
|
|
offset += sizeof(UGridArea);
|
||
|
|
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);
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
4.9 ReadFLine-method
|
||
|
|
|
||
|
|
Reads UGrid-front-line information from file.
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
void UGrid::ReadFLine()
|
||
|
|
{
|
||
|
|
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;
|
||
|
|
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));
|
||
|
|
size_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);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
4.10 ReadUGridTree
|
||
|
|
|
||
|
|
Reads UGridTree information from file.
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
UGridNode* UGrid::ReadUGridTree( UGridNode* FATHERNODE, UGridArea AREA,
|
||
|
|
int SQUARES, int RIGHTCOL, int TOPROW )
|
||
|
|
{
|
||
|
|
if((header->currentNodeRecord%64) == 0)
|
||
|
|
{
|
||
|
|
if (header->selectedNodePage == (SmiUpdatePage*)0)
|
||
|
|
{
|
||
|
|
// Select first node page
|
||
|
|
int PageSelected =
|
||
|
|
suf->GetPage(header->nodePageNo,header->selectedNodePage);
|
||
|
|
assert( PageSelected );
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// Select next node page
|
||
|
|
db_pgno_t nextPageNo;
|
||
|
|
header->selectedNodePage->Read(&nextPageNo,sizeof(db_pgno_t),0);
|
||
|
|
int PageSelected = suf->GetPage(nextPageNo,header->selectedNodePage);
|
||
|
|
assert( PageSelected );
|
||
|
|
}
|
||
|
|
header->currentNodeRecord = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Read node data from page
|
||
|
|
double tivStart, tivEnd;
|
||
|
|
bool tivLc, tivRc;
|
||
|
|
size_t offset = sizeof(db_pgno_t)+(header->currentNodeRecord*nodeSize);
|
||
|
|
header->currentNodeRecord++;
|
||
|
|
|
||
|
|
UGridNode* node = new UGridNode();
|
||
|
|
node->fatherNode = FATHERNODE;
|
||
|
|
|
||
|
|
header->selectedNodePage->Read(&node->numEntries, sizeof(int), offset);
|
||
|
|
offset += sizeof(int);
|
||
|
|
header->selectedNodePage->Read(&node->currentPage,sizeof(db_pgno_t),offset);
|
||
|
|
offset += sizeof(db_pgno_t);
|
||
|
|
header->selectedNodePage->Read(&node->pos1, sizeof(UnitPos), offset);
|
||
|
|
offset += sizeof(UnitPos);
|
||
|
|
header->selectedNodePage->Read(&node->pos2, sizeof(UnitPos), offset);
|
||
|
|
offset += sizeof(UnitPos);
|
||
|
|
header->selectedNodePage->Read(&tivStart, sizeof(double), offset);
|
||
|
|
offset += sizeof(double);
|
||
|
|
header->selectedNodePage->Read(&tivEnd, sizeof(double), offset);
|
||
|
|
offset += sizeof(double);
|
||
|
|
header->selectedNodePage->Read(&tivLc, sizeof(bool), offset);
|
||
|
|
offset += sizeof(bool);
|
||
|
|
header->selectedNodePage->Read(&tivRc, sizeof(bool), offset);
|
||
|
|
offset += sizeof(bool);
|
||
|
|
node->tiv.start = DateTime(0,0,instanttype);
|
||
|
|
node->tiv.end = DateTime(0,0,instanttype);
|
||
|
|
node->tiv.lc = tivLc;
|
||
|
|
node->tiv.rc = tivRc;
|
||
|
|
node->tiv.start.ReadFrom(tivStart);
|
||
|
|
node->tiv.end.ReadFrom(tivEnd);
|
||
|
|
|
||
|
|
if (SQUARES > 4)
|
||
|
|
{
|
||
|
|
node->leftBottomSon = ReadUGridTree( node, AREA, (SQUARES/4),
|
||
|
|
(RIGHTCOL-((int)sqrt(SQUARES)/2)),
|
||
|
|
(TOPROW-((int)sqrt(SQUARES)/2)));
|
||
|
|
|
||
|
|
node->rightBottomSon = ReadUGridTree( node, AREA, (SQUARES/4),
|
||
|
|
RIGHTCOL,
|
||
|
|
(TOPROW-((int)sqrt(SQUARES)/2)));
|
||
|
|
|
||
|
|
node->leftTopSon = ReadUGridTree( node, AREA, (SQUARES/4),
|
||
|
|
(RIGHTCOL-((int)sqrt(SQUARES)/2)),
|
||
|
|
TOPROW );
|
||
|
|
|
||
|
|
node->rightTopSon = ReadUGridTree( node, AREA, (SQUARES/4),
|
||
|
|
RIGHTCOL, TOPROW );
|
||
|
|
|
||
|
|
node->leftBottomCell = (UGridCell*)0;
|
||
|
|
node->rightBottomCell = (UGridCell*)0;
|
||
|
|
node->leftTopCell = (UGridCell*)0;
|
||
|
|
node->rightTopCell = (UGridCell*)0;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
node->leftBottomSon = (UGridNode*)0;
|
||
|
|
node->rightBottomSon = (UGridNode*)0;
|
||
|
|
node->leftTopSon = (UGridNode*)0;
|
||
|
|
node->rightTopSon = (UGridNode*)0;
|
||
|
|
|
||
|
|
// 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;
|
||
|
|
|
||
|
|
for (int i = 0; i < 4; i++)
|
||
|
|
{
|
||
|
|
int col = RIGHTCOL-1;
|
||
|
|
int row = TOPROW-1;
|
||
|
|
|
||
|
|
if ( i == 0 ) { col = col-1; row = row-1; } // leftBottomCell
|
||
|
|
if ( i == 1 ) { row = row-1; } // rightBottomCell
|
||
|
|
if ( i == 2 ) { col = col-1; } // leftTopCell
|
||
|
|
|
||
|
|
// Create new cell object
|
||
|
|
cells[col][row] = new UGridCell();
|
||
|
|
UGridCell* cellPtr = cells[col][row];
|
||
|
|
|
||
|
|
// Assign node pointer
|
||
|
|
cellPtr->fatherNode = node;
|
||
|
|
if ( i == 0 ) node->leftBottomCell = cells[col][row];
|
||
|
|
if ( i == 1 ) node->rightBottomCell = cells[col][row];
|
||
|
|
if ( i == 2 ) node->leftTopCell = cells[col][row];
|
||
|
|
if ( i == 3 ) node->rightTopCell = cells[col][row];
|
||
|
|
|
||
|
|
// Create cell area
|
||
|
|
cellPtr->area = UGridArea(0,0,0,0);
|
||
|
|
cellPtr->area.x1 = AREA.x1 + (cellLenX * col);
|
||
|
|
cellPtr->area.x2 = cellPtr->area.x1 + cellLenX;
|
||
|
|
cellPtr->area.y1 = AREA.y1 + (cellLenY * row);
|
||
|
|
cellPtr->area.y2 = cellPtr->area.y1 + cellLenY;
|
||
|
|
|
||
|
|
// Read cell data from cell page
|
||
|
|
db_pgno_t cellPageNo = header->cellPageNo[(col/8)][(row/8)];
|
||
|
|
SmiUpdatePage* cellPage;
|
||
|
|
int PageSelected = suf->GetPage(cellPageNo, cellPage);
|
||
|
|
assert( PageSelected );
|
||
|
|
|
||
|
|
offset = ((col%8)+((row%8)*8))*cellSize;
|
||
|
|
cellPage->Read(&cellPtr->numEntries, sizeof(int), offset);
|
||
|
|
offset += sizeof(int);
|
||
|
|
cellPage->Read(&cellPtr->currentPage, sizeof(db_pgno_t), offset);
|
||
|
|
offset += sizeof(db_pgno_t);
|
||
|
|
cellPage->Read(&cellPtr->pos1, sizeof(UnitPos), offset);
|
||
|
|
offset += sizeof(UnitPos);
|
||
|
|
cellPage->Read(&cellPtr->pos2, sizeof(UnitPos), offset);
|
||
|
|
offset += sizeof(UnitPos);
|
||
|
|
cellPage->Read(&tivStart, sizeof(double), offset);
|
||
|
|
offset += sizeof(double);
|
||
|
|
cellPage->Read(&tivEnd, sizeof(double), offset);
|
||
|
|
offset += sizeof(double);
|
||
|
|
cellPage->Read(&tivLc, sizeof(bool), offset);
|
||
|
|
offset += sizeof(bool);
|
||
|
|
cellPage->Read(&tivRc, sizeof(bool), offset);
|
||
|
|
|
||
|
|
cellPtr->tiv.start = DateTime(0,0,instanttype);
|
||
|
|
cellPtr->tiv.end = DateTime(0,0,instanttype);
|
||
|
|
cellPtr->tiv.lc = tivLc;
|
||
|
|
cellPtr->tiv.rc = tivRc;
|
||
|
|
cellPtr->tiv.start.ReadFrom(tivStart);
|
||
|
|
cellPtr->tiv.end.ReadFrom(tivEnd);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (SQUARES == header->numCells)
|
||
|
|
{
|
||
|
|
header->currentNodeRecord = 0;
|
||
|
|
header->selectedNodePage = (SmiUpdatePage*)0;
|
||
|
|
}
|
||
|
|
return node;
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
4.11 UpdateHeader-method
|
||
|
|
|
||
|
|
Writes UGrid-header information into file.
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
void UGrid::UpdateHeader()
|
||
|
|
{
|
||
|
|
SmiUpdatePage* headerPage;
|
||
|
|
int PageSelected = suf->GetPage(header->headerPageNo, headerPage);
|
||
|
|
assert( PageSelected );
|
||
|
|
|
||
|
|
size_t offset = 0;
|
||
|
|
headerPage->Write(&header->flPageNo, sizeof(db_pgno_t), offset);
|
||
|
|
offset += sizeof(db_pgno_t);
|
||
|
|
for (int i = 0; i < 8; i++)
|
||
|
|
{
|
||
|
|
for (int j = 0; j < 8; j++)
|
||
|
|
{
|
||
|
|
headerPage->Write(&header->cellPageNo[j][i], sizeof(db_pgno_t),offset);
|
||
|
|
offset += sizeof(db_pgno_t);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
headerPage->Write(&header->nodePageNo, sizeof(db_pgno_t), offset);
|
||
|
|
offset += sizeof(db_pgno_t);
|
||
|
|
headerPage->Write(&header->rootNode, sizeof(UGridNode*), offset);
|
||
|
|
offset += sizeof(UGridNode*);
|
||
|
|
headerPage->Write(&header->area, sizeof(UGridArea), offset);
|
||
|
|
offset += sizeof(UGridArea);
|
||
|
|
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);
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
4.12 UpdateFLine-method
|
||
|
|
|
||
|
|
Writes UGrid-front-line information into file.
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
void UGrid::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.13 UpdateUGridTree
|
||
|
|
|
||
|
|
Writes UGridTree information into file.
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
void UGrid::UpdateUGridTree( UGridNode* NODE, int SQUARES,
|
||
|
|
int RIGHTCOL, int TOPROW )
|
||
|
|
{
|
||
|
|
if((header->currentNodeRecord%64) == 0)
|
||
|
|
{
|
||
|
|
if (header->selectedNodePage == (SmiUpdatePage*)0)
|
||
|
|
{
|
||
|
|
// Select first node page
|
||
|
|
int PageSelected = suf->GetPage(header->nodePageNo,
|
||
|
|
header->selectedNodePage);
|
||
|
|
assert( PageSelected );
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// Select next node page
|
||
|
|
db_pgno_t nextPageNo;
|
||
|
|
header->selectedNodePage->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();
|
||
|
|
// Write next page number into previous page
|
||
|
|
header->selectedNodePage->Write(&nextPageNo, sizeof(db_pgno_t), 0);
|
||
|
|
}
|
||
|
|
int PageSelected = suf->GetPage(nextPageNo,header->selectedNodePage);
|
||
|
|
assert( PageSelected );
|
||
|
|
// Initialize next page number
|
||
|
|
nextPageNo = 0;
|
||
|
|
header->selectedNodePage->Write(&nextPageNo, sizeof(db_pgno_t), 0);
|
||
|
|
}
|
||
|
|
header->currentNodeRecord = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Write node data into page
|
||
|
|
size_t offset = sizeof(db_pgno_t) + (header->currentNodeRecord*nodeSize);
|
||
|
|
header->currentNodeRecord++;
|
||
|
|
|
||
|
|
double tivStart = NODE->tiv.start.ToDouble();
|
||
|
|
double tivEnd = NODE->tiv.end.ToDouble();
|
||
|
|
|
||
|
|
header->selectedNodePage->Write(&NODE->numEntries, sizeof(int), offset);
|
||
|
|
offset += sizeof(int);
|
||
|
|
header->selectedNodePage->Write(&NODE->currentPage,sizeof(db_pgno_t),offset);
|
||
|
|
offset += sizeof(db_pgno_t);
|
||
|
|
header->selectedNodePage->Write(&NODE->pos1, sizeof(UnitPos), offset);
|
||
|
|
offset += sizeof(UnitPos);
|
||
|
|
header->selectedNodePage->Write(&NODE->pos2, sizeof(UnitPos), offset);
|
||
|
|
offset += sizeof(UnitPos);
|
||
|
|
header->selectedNodePage->Write(&tivStart, sizeof(double), offset);
|
||
|
|
offset += sizeof(double);
|
||
|
|
header->selectedNodePage->Write(&tivEnd, sizeof(double), offset);
|
||
|
|
offset += sizeof(double);
|
||
|
|
header->selectedNodePage->Write(&NODE->tiv.lc, sizeof(bool), offset);
|
||
|
|
offset += sizeof(bool);
|
||
|
|
header->selectedNodePage->Write(&NODE->tiv.rc, sizeof(bool), offset);
|
||
|
|
offset += sizeof(bool);
|
||
|
|
|
||
|
|
if (SQUARES > 4)
|
||
|
|
{
|
||
|
|
UpdateUGridTree( NODE->leftBottomSon, (SQUARES/4),
|
||
|
|
(RIGHTCOL-((int)sqrt(SQUARES)/2)), (TOPROW-((int)sqrt(SQUARES)/2)));
|
||
|
|
|
||
|
|
UpdateUGridTree( NODE->rightBottomSon, (SQUARES/4),
|
||
|
|
RIGHTCOL, (TOPROW-((int)sqrt(SQUARES)/2)));
|
||
|
|
|
||
|
|
UpdateUGridTree( NODE->leftTopSon, (SQUARES/4),
|
||
|
|
(RIGHTCOL-((int)sqrt(SQUARES)/2)), TOPROW );
|
||
|
|
|
||
|
|
UpdateUGridTree( NODE->rightTopSon, (SQUARES/4), RIGHTCOL, TOPROW );
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
for (int i = 0; i < 4; i++)
|
||
|
|
{
|
||
|
|
int col = RIGHTCOL-1;
|
||
|
|
int row = TOPROW-1;
|
||
|
|
|
||
|
|
if ( i == 0 ) { col = col-1; row = row-1; } // leftBottomCell
|
||
|
|
if ( i == 1 ) { row = row-1; } // rightBottomCell
|
||
|
|
if ( i == 2 ) { col = col-1; } // leftTopCell
|
||
|
|
|
||
|
|
// Current cell pointer
|
||
|
|
UGridCell* cellPtr = cells[col][row];
|
||
|
|
|
||
|
|
// Select cell page
|
||
|
|
db_pgno_t cellPageNo = header->cellPageNo[(col/8)][(row/8)];
|
||
|
|
SmiUpdatePage* cellPage;
|
||
|
|
int PageSelected = suf->GetPage(cellPageNo, cellPage);
|
||
|
|
assert( PageSelected );
|
||
|
|
|
||
|
|
tivStart = cellPtr->tiv.start.ToDouble();
|
||
|
|
tivEnd = cellPtr->tiv.end.ToDouble();
|
||
|
|
|
||
|
|
// Write cell data into cell page
|
||
|
|
offset = ((col%8)+((row%8)*8))*cellSize;
|
||
|
|
cellPage->Write(&cellPtr->numEntries, sizeof(int), offset);
|
||
|
|
offset += sizeof(int);
|
||
|
|
cellPage->Write(&cellPtr->currentPage, sizeof(db_pgno_t), offset);
|
||
|
|
offset += sizeof(db_pgno_t);
|
||
|
|
cellPage->Write(&cellPtr->pos1, sizeof(UnitPos), offset);
|
||
|
|
offset += sizeof(UnitPos);
|
||
|
|
cellPage->Write(&cellPtr->pos2, sizeof(UnitPos), offset);
|
||
|
|
offset += sizeof(UnitPos);
|
||
|
|
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 (SQUARES == header->numCells)
|
||
|
|
{
|
||
|
|
header->currentNodeRecord = 0;
|
||
|
|
header->selectedNodePage = (SmiUpdatePage*)0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
4.14 UpdateUGrid-method
|
||
|
|
|
||
|
|
Writes all UGrid data into file.
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
bool UGrid::UpdateUGrid()
|
||
|
|
{
|
||
|
|
// 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 UGrid-tree
|
||
|
|
UpdateUGridTree( header->rootNode, header->numCells,
|
||
|
|
header->splits, header->splits );
|
||
|
|
|
||
|
|
// Release SmiUpdateFile
|
||
|
|
SetSemaphore(false);
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
4.15 insertPageID-method
|
||
|
|
|
||
|
|
Inserts HistoryUnit page id's into pages set.
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
void UGrid::insertPageID(db_pgno_t NODEPAGEID, bool HUPAGEID)
|
||
|
|
{
|
||
|
|
SmiUpdatePage* selectedNodePage;
|
||
|
|
int PageSelected = suf->GetPage(NODEPAGEID,selectedNodePage);
|
||
|
|
assert( PageSelected );
|
||
|
|
|
||
|
|
db_pgno_t pageID;
|
||
|
|
bool huPageID;
|
||
|
|
size_t offset = sizeof(db_pgno_t);
|
||
|
|
|
||
|
|
for (int i = 0; i < 60; i++)
|
||
|
|
{
|
||
|
|
selectedNodePage->Read(&pageID, sizeof(db_pgno_t), offset);
|
||
|
|
offset += sizeof(db_pgno_t);
|
||
|
|
selectedNodePage->Read(&huPageID, sizeof(bool), offset);
|
||
|
|
offset += (sizeof(bool) + (6*sizeof(double)));
|
||
|
|
|
||
|
|
if (huPageID && pageID != 0) pages.insert(pageID);
|
||
|
|
if (!huPageID) insertPageID(pageID, huPageID);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
4.16 FindHistoryPages-method
|
||
|
|
|
||
|
|
Finds HistoryUnit pages in the UGridTree.
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
void UGrid::FindHistoryPages(UGridArea AREA, Instant TIME1, Instant TIME2,
|
||
|
|
UGridNode* NODE, int SQUARES)
|
||
|
|
{
|
||
|
|
if ((NODE->numEntries > 0) &&
|
||
|
|
CheckUGridNode(AREA,TIME1,TIME2,NODE))
|
||
|
|
{
|
||
|
|
// Find UGridBoxes in node page
|
||
|
|
SmiUpdatePage* selectedNodePage;
|
||
|
|
int PageSelected = suf->GetPage(NODE->currentPage,selectedNodePage);
|
||
|
|
assert( PageSelected );
|
||
|
|
|
||
|
|
size_t offset = sizeof(db_pgno_t);
|
||
|
|
|
||
|
|
for (int i = 0; i < NODE->numEntries; i++)
|
||
|
|
{
|
||
|
|
if ((NODE->fatherNode == 0) && ((i%60) == 0) && (i > 0))
|
||
|
|
{
|
||
|
|
// For the root node read the following pages
|
||
|
|
db_pgno_t nextPageNo;
|
||
|
|
selectedNodePage->Read(&nextPageNo, sizeof(db_pgno_t), 0);
|
||
|
|
if (nextPageNo != 0)
|
||
|
|
{
|
||
|
|
PageSelected = suf->GetPage(nextPageNo, selectedNodePage);
|
||
|
|
assert( PageSelected );
|
||
|
|
offset = sizeof(db_pgno_t);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Read UGridBox
|
||
|
|
db_pgno_t pageID;
|
||
|
|
bool huPageID;
|
||
|
|
double minD0, maxD0, minD1, maxD1, minD2, maxD2;
|
||
|
|
selectedNodePage->Read(&pageID, sizeof(db_pgno_t), offset);
|
||
|
|
offset += sizeof(db_pgno_t);
|
||
|
|
selectedNodePage->Read(&huPageID, sizeof(bool), offset);
|
||
|
|
offset += sizeof(bool);
|
||
|
|
selectedNodePage->Read(&minD0, sizeof(double), offset);
|
||
|
|
offset += sizeof(double);
|
||
|
|
selectedNodePage->Read(&maxD0, sizeof(double), offset);
|
||
|
|
offset += sizeof(double);
|
||
|
|
selectedNodePage->Read(&minD1, sizeof(double), offset);
|
||
|
|
offset += sizeof(double);
|
||
|
|
selectedNodePage->Read(&maxD1, sizeof(double), offset);
|
||
|
|
offset += sizeof(double);
|
||
|
|
selectedNodePage->Read(&minD2, sizeof(double), offset);
|
||
|
|
offset += sizeof(double);
|
||
|
|
selectedNodePage->Read(&maxD2, sizeof(double), offset);
|
||
|
|
offset += sizeof(double);
|
||
|
|
|
||
|
|
double minMax[] = {minD0-tol, maxD0+tol,
|
||
|
|
minD1-tol, maxD1+tol,
|
||
|
|
minD2-tol, maxD2+tol};
|
||
|
|
Rectangle<3> rect(true,minMax);
|
||
|
|
|
||
|
|
UGridBox* box = new UGridBox(pageID, huPageID, rect);
|
||
|
|
|
||
|
|
if (CheckUGridBox(AREA,TIME1,TIME2,*box))
|
||
|
|
{
|
||
|
|
// UGridBox is in searchWindow
|
||
|
|
if (huPageID) pages.insert(pageID);
|
||
|
|
else insertPageID(pageID, false);
|
||
|
|
}
|
||
|
|
delete box;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (SQUARES > 4)
|
||
|
|
{
|
||
|
|
FindHistoryPages(AREA,TIME1,TIME2,NODE->leftBottomSon,(SQUARES/4));
|
||
|
|
FindHistoryPages(AREA,TIME1,TIME2,NODE->rightBottomSon,(SQUARES/4));
|
||
|
|
FindHistoryPages(AREA,TIME1,TIME2,NODE->leftTopSon,(SQUARES/4));
|
||
|
|
FindHistoryPages(AREA,TIME1,TIME2,NODE->rightTopSon,(SQUARES/4));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
4.17 GetUpdateFile-method
|
||
|
|
|
||
|
|
Returns the UGrid file id.
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
SmiUpdateFile* UGrid::GetUpdateFile()
|
||
|
|
{
|
||
|
|
return suf;
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
4.18 GetHeader-method
|
||
|
|
|
||
|
|
Returns the pointer to the UGrid header.
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
UGridHeader* UGrid::GetHeader()
|
||
|
|
{
|
||
|
|
return header;
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
4.19 GetCell-method
|
||
|
|
|
||
|
|
Returns the pointer to the stated cell.
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
UGridCell* UGrid::GetCell(int COL, int ROW)
|
||
|
|
{
|
||
|
|
return cells[COL][ROW];
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
4.20 GetSemaphore-method
|
||
|
|
|
||
|
|
Returns the state of the semaphore.
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
bool UGrid::GetSemaphore()
|
||
|
|
{
|
||
|
|
bool value;
|
||
|
|
SmiUpdatePage* headerPage;
|
||
|
|
int PageSelected = suf->GetPage(header->headerPageNo, headerPage);
|
||
|
|
assert( PageSelected );
|
||
|
|
headerPage->Read(&value, sizeof(bool), sizeof(UGridHeader));
|
||
|
|
|
||
|
|
// Wait until file is released or timeout is 0
|
||
|
|
int timeout = 100000;
|
||
|
|
while(value && (timeout >= 0))
|
||
|
|
{
|
||
|
|
headerPage->Read(&value, sizeof(bool), sizeof(UGridHeader));
|
||
|
|
for(int i = 0; i < 10000; i++);
|
||
|
|
timeout--;
|
||
|
|
}
|
||
|
|
return value;
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
4.21 SetSemaphore-method
|
||
|
|
|
||
|
|
Sets the state of the semaphore.
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
void UGrid::SetSemaphore(bool value)
|
||
|
|
{
|
||
|
|
SmiUpdatePage* headerPage;
|
||
|
|
int PageSelected = suf->GetPage(header->headerPageNo, headerPage);
|
||
|
|
assert( PageSelected );
|
||
|
|
headerPage->Write(&value, sizeof(bool), sizeof(UGridHeader));
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
4.22 Type constructor
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
TypeConstructor UGridTC(
|
||
|
|
UGrid::BasicType(), // name
|
||
|
|
UGrid::Property, // property function
|
||
|
|
UGrid::Out, UGrid::In, // Out and In functions
|
||
|
|
0, 0, // SaveTo and RestoreFrom functions
|
||
|
|
UGrid::Create, UGrid::Delete, // object creation and deletion
|
||
|
|
UGrid::Open, UGrid::Save, // object open and save
|
||
|
|
UGrid::Close, UGrid::Clone, // object close and clone
|
||
|
|
UGrid::Cast, // cast function
|
||
|
|
UGrid::SizeOfObj, // sizeof function
|
||
|
|
UGrid::KindCheck ); // kind checking function
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
5 createUGrid operator
|
||
|
|
|
||
|
|
Creates a new UGrid object.
|
||
|
|
|
||
|
|
5.1 createUGrid - 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(UGrid::BasicType()));
|
||
|
|
}
|
||
|
|
ErrorReporter::ReportError("rect x int expected!");
|
||
|
|
return (nl->SymbolAtom( Symbol::TYPEERROR() ));
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
5.2 createUGrid - Value mapping method
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
int CreateVM(Word* args, Word& result, int message, Word& local, Supplier s)
|
||
|
|
{
|
||
|
|
UGrid* ugridPtr = static_cast<UGrid*>(qp->ResultStorage(s).addr);
|
||
|
|
|
||
|
|
Rectangle<2>* rect = static_cast<Rectangle<2>*>(args[0].addr);
|
||
|
|
CcInt* partitions = static_cast<CcInt*>(args[1].addr);
|
||
|
|
|
||
|
|
// Create UGrid area
|
||
|
|
double x1(rect->MinD(0));
|
||
|
|
double x2(rect->MaxD(0));
|
||
|
|
double y1(rect->MinD(1));
|
||
|
|
double y2(rect->MaxD(1));
|
||
|
|
UGridArea area(x1,y1,x2,y2);
|
||
|
|
area = ModifyArea(area);
|
||
|
|
|
||
|
|
|
||
|
|
// Check number of partitions
|
||
|
|
int numPartitions = partitions->GetValue();
|
||
|
|
|
||
|
|
if (!(numPartitions == 4096 ||
|
||
|
|
numPartitions == 256 ||
|
||
|
|
numPartitions == 16 ||
|
||
|
|
numPartitions == 4 ))
|
||
|
|
{
|
||
|
|
// Wrong number of partitions -> create default UGrid
|
||
|
|
numPartitions = 16;
|
||
|
|
}
|
||
|
|
// Create UGrid with the stated number of partitions
|
||
|
|
|
||
|
|
ugridPtr = new UGrid(area,(int)sqrt(numPartitions));
|
||
|
|
result.setAddr( ugridPtr );
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
5.3 createUGrid - Specification of operator
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
struct CreateInfo : OperatorInfo {
|
||
|
|
CreateInfo()
|
||
|
|
{
|
||
|
|
name = "createUGrid";
|
||
|
|
signature = "rect x int -> ugrid";
|
||
|
|
syntax = "createUGrid( _, _ )";
|
||
|
|
meaning = "UGrid construction operator. The second argument must be 4, "
|
||
|
|
"16, 256 or 4096, otherwise it will be set a default value.";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
6 insertUpload operator
|
||
|
|
|
||
|
|
Inserts a single upload into UGrid.
|
||
|
|
|
||
|
|
6.1 ComputeHistoryUnit-method
|
||
|
|
|
||
|
|
Computes a history unit and returns it to the insertHandle method.
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
HistoryUnit* ComputeHistoryUnit( UGridArea 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 history unit
|
||
|
|
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;
|
||
|
|
|
||
|
|
HistoryUnit* hu = new HistoryUnit(0, 0, TIV.start.ToDouble(),
|
||
|
|
TIV.end.ToDouble(), POS1, p);
|
||
|
|
return hu;
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
6.2 InsertHandle-method
|
||
|
|
|
||
|
|
Inserts an upload into the UGrid index structure. The insertUpload and
|
||
|
|
the insertStream operator make use of this method.
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
int InsertHandle(UGrid* UGRIDPTR, UploadUnit* UNITPTR)
|
||
|
|
{
|
||
|
|
SmiUpdateFile* suf = UGRIDPTR->GetUpdateFile();
|
||
|
|
UGridHeader* hPtr = UGRIDPTR->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 = UGRIDPTR->frontline[moID%flBuckets].find(moID);
|
||
|
|
|
||
|
|
if ( it == UGRIDPTR->frontline[moID%flBuckets].end() )
|
||
|
|
{
|
||
|
|
// No entry found -> Place UploadUnit in front line
|
||
|
|
UGRIDPTR->frontline[moID%flBuckets].insert(make_pair(moID,*UNITPTR));
|
||
|
|
hPtr->numFlEntries++;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// Entry found
|
||
|
|
if(!suf->IsOpen()) suf->Open(hPtr->fileID, pageSize);
|
||
|
|
HistoryUnit* hu;
|
||
|
|
UnitPos pos1 = it->second.GetPos();
|
||
|
|
UnitPos pos2 = UNITPTR->GetPos();
|
||
|
|
Interval<Instant> huTiv;
|
||
|
|
huTiv.start = it->second.GetTime();
|
||
|
|
huTiv.end = UNITPTR->GetTime();
|
||
|
|
huTiv.lc = true;
|
||
|
|
huTiv.rc = true;
|
||
|
|
|
||
|
|
// Check if the current upload is younger than the last upload
|
||
|
|
if(huTiv.start >= huTiv.end) return 3;
|
||
|
|
|
||
|
|
// Replace UploadUnit in frontline
|
||
|
|
UGRIDPTR->frontline[moID%flBuckets][moID] = *UNITPTR;
|
||
|
|
|
||
|
|
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);
|
||
|
|
UGridCell* cellPtr = UGRIDPTR->GetCell(col,row);
|
||
|
|
|
||
|
|
SmiUpdatePage* page;
|
||
|
|
if ((cellPtr->numEntries % maxHistoryUnits) == 0)
|
||
|
|
{
|
||
|
|
if(cellPtr->currentPage != 0)
|
||
|
|
{
|
||
|
|
// Insert UGridBox into UGrid-tree
|
||
|
|
UGridBox* box = CreateUGridBox( cellPtr, (UGridNode*)0 );
|
||
|
|
if (box != 0) UGRIDPTR->InsertUGridBox( cellPtr->fatherNode, box );
|
||
|
|
|
||
|
|
// Put current page back to disk
|
||
|
|
//suf->PutPage(cellPtr->currentPage, true);
|
||
|
|
}
|
||
|
|
// 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 history unit
|
||
|
|
hu = ComputeHistoryUnit( hPtr->area, hPtr->splits, pos1, pos2, huTiv );
|
||
|
|
hu->moID = moID;
|
||
|
|
hu->huID = hPtr->numEntries;
|
||
|
|
|
||
|
|
// Check/modify pos1 and pos2 of cell
|
||
|
|
if ((!cellPtr->tiv.lc) || (cellPtr->pos1.x > hu->pos1.x))
|
||
|
|
cellPtr->pos1.x = hu->pos1.x;
|
||
|
|
if ((!cellPtr->tiv.lc) || (cellPtr->pos1.x > hu->pos2.x))
|
||
|
|
cellPtr->pos1.x = hu->pos2.x;
|
||
|
|
if ((!cellPtr->tiv.lc) || (cellPtr->pos1.y > hu->pos1.y))
|
||
|
|
cellPtr->pos1.y = hu->pos1.y;
|
||
|
|
if ((!cellPtr->tiv.lc) || (cellPtr->pos1.y > hu->pos2.y))
|
||
|
|
cellPtr->pos1.y = hu->pos2.y;
|
||
|
|
if ((!cellPtr->tiv.rc) || (cellPtr->pos2.x < hu->pos1.x))
|
||
|
|
cellPtr->pos2.x = hu->pos1.x;
|
||
|
|
if ((!cellPtr->tiv.rc) || (cellPtr->pos2.x < hu->pos2.x))
|
||
|
|
cellPtr->pos2.x = hu->pos2.x;
|
||
|
|
if ((!cellPtr->tiv.rc) || (cellPtr->pos2.y < hu->pos1.y))
|
||
|
|
cellPtr->pos2.y = hu->pos1.y;
|
||
|
|
if ((!cellPtr->tiv.rc) || (cellPtr->pos2.y < hu->pos2.y))
|
||
|
|
cellPtr->pos2.y = hu->pos2.y;
|
||
|
|
|
||
|
|
// Check/modify UGrid time interval
|
||
|
|
if ((!hPtr->tiv.lc) || (hPtr->tiv.start > huTiv.start))
|
||
|
|
{
|
||
|
|
hPtr->tiv.start = huTiv.start;
|
||
|
|
hPtr->tiv.lc = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ((!hPtr->tiv.rc) || (hPtr->tiv.end < huTiv.end))
|
||
|
|
{
|
||
|
|
hPtr->tiv.end = huTiv.end;
|
||
|
|
hPtr->tiv.rc = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Check/modify cell time interval
|
||
|
|
if ((!cellPtr->tiv.lc) || (cellPtr->tiv.start > huTiv.start))
|
||
|
|
{
|
||
|
|
cellPtr->tiv.start = huTiv.start;
|
||
|
|
cellPtr->tiv.lc = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ((!cellPtr->tiv.rc) || (cellPtr->tiv.end < huTiv.end))
|
||
|
|
{
|
||
|
|
cellPtr->tiv.end = huTiv.end;
|
||
|
|
cellPtr->tiv.rc = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Initialize tiv and number of entries in page
|
||
|
|
if ((cellPtr->numEntries % maxHistoryUnits) == 0)
|
||
|
|
{
|
||
|
|
int pageEntries = 0;
|
||
|
|
page->Write(&pageEntries, sizeof(int), 0);
|
||
|
|
page->Write(&huTiv,sizeof(Interval<Instant>), sizeof(int));
|
||
|
|
}
|
||
|
|
|
||
|
|
// Check/modify page time interval
|
||
|
|
Interval<Instant> pageTiv;
|
||
|
|
page->Read(&pageTiv, sizeof(Interval<Instant> ), sizeof(int));
|
||
|
|
if (huTiv.start < pageTiv.start) pageTiv.start = huTiv.start;
|
||
|
|
if (huTiv.end > pageTiv.end) pageTiv.end = huTiv.end;
|
||
|
|
|
||
|
|
// Read number of entries in page
|
||
|
|
int pageEntries;
|
||
|
|
page->Read( &pageEntries, sizeof(int), 0 );
|
||
|
|
|
||
|
|
// Write HistoryUnit in page
|
||
|
|
size_t offset = sizeof(int) + sizeof(Interval<Instant>) +
|
||
|
|
+ ((pageEntries)*(sizeof(HistoryUnit)));
|
||
|
|
page->Write(&hu->moID, sizeof(int), offset );
|
||
|
|
offset += sizeof(int);
|
||
|
|
page->Write( &hu->huID, sizeof(int), offset );
|
||
|
|
offset += sizeof(int);
|
||
|
|
page->Write(&hu->tivStart, sizeof(double), offset);
|
||
|
|
offset += sizeof(double);
|
||
|
|
page->Write(&hu->tivEnd, sizeof(double), offset);
|
||
|
|
offset += sizeof(double);
|
||
|
|
page->Write( &hu->pos1, sizeof(UnitPos), offset );
|
||
|
|
offset += sizeof(UnitPos);
|
||
|
|
page->Write( &hu->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 = hu->pos2.x + tol;
|
||
|
|
else if (intersects[1] == true) pos1.x = hu->pos2.x - tol;
|
||
|
|
else pos1.x = hu->pos2.x;
|
||
|
|
if (intersects[2] == true) pos1.y = hu->pos2.y + tol;
|
||
|
|
else if (intersects[3] == true) pos1.y = hu->pos2.y - tol;
|
||
|
|
else pos1.y = hu->pos2.y;
|
||
|
|
}
|
||
|
|
while ( !(CompareFloats(pos2.x, hu->pos2.x) &&
|
||
|
|
CompareFloats(pos2.y, hu->pos2.y)) );
|
||
|
|
}
|
||
|
|
hPtr->numEntries++;
|
||
|
|
|
||
|
|
if ((hPtr->numEntries % updateCycle) == 0)
|
||
|
|
{
|
||
|
|
// Update file
|
||
|
|
if(!UGRIDPTR->UpdateUGrid()) 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), UGrid::BasicType()) &&
|
||
|
|
nl->IsEqual(nl->Second(args), UploadUnit::BasicType()))
|
||
|
|
{
|
||
|
|
return (nl->SymbolAtom(CcBool::BasicType()));
|
||
|
|
}
|
||
|
|
return listutils::typeError("Expected ugrid x uploadunit!");
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
6.5 insertUpload - Value mapping method
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
int InsertUploadVM(Word* args, Word& result, int message, Word& local,
|
||
|
|
Supplier s)
|
||
|
|
{
|
||
|
|
UGrid* ugridPtr = static_cast<UGrid*>(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(ugridPtr, unitPtr);
|
||
|
|
|
||
|
|
// Memorize error
|
||
|
|
if (res == 1) error[0] = true;
|
||
|
|
if (res == 2) error[1] = true;
|
||
|
|
if (res == 3) error[2] = true;
|
||
|
|
|
||
|
|
// Update file
|
||
|
|
if(!ugridPtr->UpdateUGrid()) 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 = "ugrid x uploadunit -> bool";
|
||
|
|
syntax = "insertUpload( _, _)";
|
||
|
|
meaning = "UGrid insert upload operator.";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
7 insertStream operator
|
||
|
|
|
||
|
|
Inserts a stream of uploads into UGrid.
|
||
|
|
|
||
|
|
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), UGrid::BasicType()) )
|
||
|
|
{
|
||
|
|
return NList::typeError( "UGrid 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;
|
||
|
|
UGrid* ugridPtr = static_cast<UGrid*>(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(ugridPtr, 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(!ugridPtr->UpdateUGrid()) 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 ugrid x ai) -> bool";
|
||
|
|
syntax = "_ insertStream[ _, _ ]";
|
||
|
|
meaning = "UGrid insert upload stream operator.";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
8 IntersectsWindow operator
|
||
|
|
|
||
|
|
Returns all history units which intersects the search window.
|
||
|
|
|
||
|
|
8.1 FindHistoryUnits-method
|
||
|
|
|
||
|
|
Finds all history units which intersect the search window. The
|
||
|
|
intersectsWindow and the insideWindow operator make use of this method.
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
set<HistoryUnit*> FindHistoryUnits( UGrid* UGRIDPTR, UGridArea AREA,
|
||
|
|
Instant TIME1, Instant TIME2)
|
||
|
|
{
|
||
|
|
UGridHeader* hPtr = UGRIDPTR->GetHeader();
|
||
|
|
set<db_pgno_t>::iterator pIt;
|
||
|
|
map<int,HistoryUnit*>::iterator huIt;
|
||
|
|
map<int,HistoryUnit*> historyUnits;
|
||
|
|
set<HistoryUnit*> hits;
|
||
|
|
|
||
|
|
// Check if SmiUpdateFile is released
|
||
|
|
if(UGRIDPTR->GetSemaphore()) return hits;;
|
||
|
|
|
||
|
|
// Lock SmiUpdateFile
|
||
|
|
UGRIDPTR->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 UGrid 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 current pages of 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);
|
||
|
|
|
||
|
|
// Clear page set
|
||
|
|
UGRIDPTR->pages.clear();
|
||
|
|
|
||
|
|
for (int i = bottom; i <= top; i++)
|
||
|
|
{
|
||
|
|
for (int j = left; j <= right; j++)
|
||
|
|
{
|
||
|
|
if (UGRIDPTR->GetCell(j,i)->currentPage != 0)
|
||
|
|
{
|
||
|
|
// Insert current page number
|
||
|
|
UGRIDPTR->pages.insert(UGRIDPTR->GetCell(j,i)->currentPage);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Find history pages in UGridTree
|
||
|
|
UGRIDPTR->FindHistoryPages(AREA,TIME1,TIME2,UGRIDPTR->GetHeader()->rootNode,
|
||
|
|
UGRIDPTR->GetHeader()->numCells);
|
||
|
|
|
||
|
|
db_pgno_t pageID;
|
||
|
|
SmiRecord pageRec;
|
||
|
|
int moID;
|
||
|
|
int huID;
|
||
|
|
double tivStart;
|
||
|
|
double tivEnd;
|
||
|
|
UnitPos pos1;
|
||
|
|
UnitPos pos2;
|
||
|
|
|
||
|
|
// Find HistoryUnits in pages
|
||
|
|
for (pIt = UGRIDPTR->pages.begin(); pIt != UGRIDPTR->pages.end();)
|
||
|
|
{
|
||
|
|
pageID = *pIt;
|
||
|
|
SmiUpdatePage* page;
|
||
|
|
int PageSelected = UGRIDPTR->GetUpdateFile()->GetPage(pageID, page);
|
||
|
|
assert( PageSelected );
|
||
|
|
|
||
|
|
// Read number of HistoryUnits in page
|
||
|
|
int numHU;
|
||
|
|
page->Read( &numHU, sizeof(int), 0 );
|
||
|
|
size_t offset = sizeof(int) + sizeof(Interval<Instant>);
|
||
|
|
|
||
|
|
// Read HistoryUnits
|
||
|
|
for (int i = 0; i < numHU; i++)
|
||
|
|
{
|
||
|
|
page->Read( &moID, sizeof(int), offset );
|
||
|
|
offset += sizeof(int);
|
||
|
|
page->Read( &huID, 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 HistoryUnits if necessary
|
||
|
|
bool found = false;
|
||
|
|
huIt = historyUnits.find(huID);
|
||
|
|
if ( huIt != historyUnits.end() )
|
||
|
|
{
|
||
|
|
HistoryUnit* huPtr = huIt->second;
|
||
|
|
if ( CompareFloats(huPtr->pos2.x, pos1.x) &&
|
||
|
|
CompareFloats(huPtr->pos2.y, pos1.y) )
|
||
|
|
{
|
||
|
|
huPtr->tivEnd = tivEnd;
|
||
|
|
huPtr->pos2 = pos2;
|
||
|
|
found = true;
|
||
|
|
}
|
||
|
|
if ( CompareFloats(huPtr->pos1.x, pos2.x) &&
|
||
|
|
CompareFloats(huPtr->pos1.y, pos2.y) )
|
||
|
|
{
|
||
|
|
huPtr->tivStart = tivStart;
|
||
|
|
huPtr->pos1 = pos1;
|
||
|
|
found = true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (!found) historyUnits.insert(make_pair( huID,
|
||
|
|
new HistoryUnit( moID, huID, tivStart, tivEnd, pos1, pos2)));
|
||
|
|
}
|
||
|
|
// Drop page
|
||
|
|
UGRIDPTR->GetUpdateFile()->PutPage(page->GetPageNo(),false);
|
||
|
|
UGRIDPTR->pages.erase(pIt++);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Check if history unit intersects window
|
||
|
|
for (huIt = historyUnits.begin(); huIt != historyUnits.end();)
|
||
|
|
{
|
||
|
|
HistoryUnit* huPtr = huIt->second;;
|
||
|
|
Instant huStart(instanttype);
|
||
|
|
Instant huEnd(instanttype);
|
||
|
|
huStart.ReadFrom(huPtr->tivStart);
|
||
|
|
huEnd.ReadFrom(huPtr->tivEnd);
|
||
|
|
|
||
|
|
if ( TIME1 <= huEnd &&
|
||
|
|
TIME2 >= huStart &&
|
||
|
|
((AREA.x1 <= huPtr->pos1.x && AREA.y1 <= huPtr->pos1.y &&
|
||
|
|
AREA.x2 >= huPtr->pos1.x && AREA.y2 >= huPtr->pos1.y) ||
|
||
|
|
(AREA.x1 <= huPtr->pos2.x && AREA.y1 <= huPtr->pos2.y &&
|
||
|
|
AREA.x2 >= huPtr->pos2.x && AREA.y2 >= huPtr->pos2.y)))
|
||
|
|
hits.insert(huPtr);
|
||
|
|
else delete huPtr;
|
||
|
|
historyUnits.erase(huIt++);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Release SmiUpdateFile
|
||
|
|
UGRIDPTR->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),UGrid::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("ugrid 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("HistoryUnit"),
|
||
|
|
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<HistoryUnit*> hits;
|
||
|
|
set<HistoryUnit*>::iterator it;
|
||
|
|
|
||
|
|
Iterator(set<HistoryUnit*> HITS)
|
||
|
|
{
|
||
|
|
hits = HITS;
|
||
|
|
it = hits.begin();
|
||
|
|
}
|
||
|
|
set<HistoryUnit*>::iterator GetIterator() {return it;}
|
||
|
|
};
|
||
|
|
|
||
|
|
Iterator* iterator = static_cast<Iterator*>(local.addr);
|
||
|
|
|
||
|
|
switch( message )
|
||
|
|
{
|
||
|
|
case OPEN:
|
||
|
|
{
|
||
|
|
UGrid* ugridPtr = static_cast<UGrid*>(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 UGrid area
|
||
|
|
double x1(rect->MinD(0));
|
||
|
|
double x2(rect->MaxD(0));
|
||
|
|
double y1(rect->MinD(1));
|
||
|
|
double y2(rect->MaxD(1));
|
||
|
|
UGridArea area(x1,y1,x2,y2);
|
||
|
|
area = ModifyArea(area);
|
||
|
|
|
||
|
|
// Find history units which intersect the search window
|
||
|
|
set<HistoryUnit*> hits = FindHistoryUnits(ugridPtr,area,*time1,*time2);
|
||
|
|
|
||
|
|
// Initialize iterator
|
||
|
|
iterator = new Iterator(hits);
|
||
|
|
local.addr = iterator;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
case REQUEST:
|
||
|
|
{
|
||
|
|
if ( (iterator != 0) && (iterator->it != iterator->hits.end()) )
|
||
|
|
{
|
||
|
|
HistoryUnit* hu = *iterator->GetIterator();
|
||
|
|
CcInt* moID = new CcInt(true, hu->moID);
|
||
|
|
Interval<Instant>* tiv = new Interval<Instant>(
|
||
|
|
DateTime(0,0,instanttype),
|
||
|
|
DateTime(0,0,instanttype),
|
||
|
|
true, true );
|
||
|
|
tiv->start.ReadFrom(hu->tivStart);
|
||
|
|
tiv->end.ReadFrom(hu->tivEnd);
|
||
|
|
|
||
|
|
UPoint* upoint = new UPoint(*tiv, hu->pos1.x, hu->pos1.y,
|
||
|
|
hu->pos2.x, hu->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 hu;
|
||
|
|
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 = "ugrid x rect x instant x instant -> "
|
||
|
|
"stream (tuple (MovObjId int)(HistoryUnit upoint))";
|
||
|
|
syntax = "intersectsWindow ( _, _, _, _ )";
|
||
|
|
meaning = "Returns all history units which"
|
||
|
|
"intersect the search window.";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
9 insideWindow operator
|
||
|
|
|
||
|
|
Returns all history units 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),UGrid::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("ugrid 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("HistoryUnit"),
|
||
|
|
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<HistoryUnit*> hits;
|
||
|
|
set<HistoryUnit*>::iterator it;
|
||
|
|
|
||
|
|
Iterator(set<HistoryUnit*> HITS)
|
||
|
|
{
|
||
|
|
hits = HITS;
|
||
|
|
it = hits.begin();
|
||
|
|
}
|
||
|
|
set<HistoryUnit*>::iterator GetIterator() {return it;}
|
||
|
|
};
|
||
|
|
|
||
|
|
Iterator* iterator = static_cast<Iterator*>(local.addr);
|
||
|
|
|
||
|
|
switch( message )
|
||
|
|
{
|
||
|
|
case OPEN:
|
||
|
|
{
|
||
|
|
UGrid* ugridPtr = static_cast<UGrid*>(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 UGrid area
|
||
|
|
double x1(rect->MinD(0));
|
||
|
|
double x2(rect->MaxD(0));
|
||
|
|
double y1(rect->MinD(1));
|
||
|
|
double y2(rect->MaxD(1));
|
||
|
|
UGridArea area(x1,y1,x2,y2);
|
||
|
|
area = ModifyArea(area);
|
||
|
|
|
||
|
|
// Find history units which intersects the search window
|
||
|
|
set<HistoryUnit*> tempHits =FindHistoryUnits(ugridPtr,area,*time1,*time2);
|
||
|
|
|
||
|
|
// Check if all history units are inside the window
|
||
|
|
set<HistoryUnit*>::iterator itTempHits;
|
||
|
|
set<HistoryUnit*> hits;
|
||
|
|
for (itTempHits = tempHits.begin(); itTempHits != tempHits.end();
|
||
|
|
itTempHits++)
|
||
|
|
{
|
||
|
|
HistoryUnit* ugridPtr = *itTempHits;
|
||
|
|
Instant huStart(instanttype);
|
||
|
|
Instant huEnd(instanttype);
|
||
|
|
huStart.ReadFrom(ugridPtr->tivStart);
|
||
|
|
huEnd.ReadFrom(ugridPtr->tivEnd);
|
||
|
|
|
||
|
|
if ( *time1 <= huStart &&
|
||
|
|
*time2 >= huEnd &&
|
||
|
|
area.x1 <= ugridPtr->pos1.x && area.x1 <= ugridPtr->pos2.x &&
|
||
|
|
area.x2 >= ugridPtr->pos1.x && area.x2 >= ugridPtr->pos2.x &&
|
||
|
|
area.y1 <= ugridPtr->pos1.y && area.y1 <= ugridPtr->pos2.y &&
|
||
|
|
area.y2 >= ugridPtr->pos1.y && area.y2 >= ugridPtr->pos2.y )
|
||
|
|
{
|
||
|
|
hits.insert(ugridPtr);
|
||
|
|
}
|
||
|
|
else delete ugridPtr;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Initialize iterator
|
||
|
|
iterator = new Iterator(hits);
|
||
|
|
local.addr = iterator;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
case REQUEST:
|
||
|
|
{
|
||
|
|
if ( (iterator != 0) && (iterator->it != iterator->hits.end()) )
|
||
|
|
{
|
||
|
|
HistoryUnit* hu = *iterator->GetIterator();
|
||
|
|
CcInt* moID = new CcInt(true, hu->moID);
|
||
|
|
Interval<Instant>* tiv = new Interval<Instant>(
|
||
|
|
DateTime(0,0,instanttype),
|
||
|
|
DateTime(0,0,instanttype),
|
||
|
|
true, true );
|
||
|
|
tiv->start.ReadFrom(hu->tivStart);
|
||
|
|
tiv->end.ReadFrom(hu->tivEnd);
|
||
|
|
|
||
|
|
UPoint* upoint = new UPoint(*tiv, hu->pos1.x, hu->pos1.y,
|
||
|
|
hu->pos2.x, hu->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 );
|
||
|
|
iterator->it++;
|
||
|
|
result.addr = tup;
|
||
|
|
delete tiv;
|
||
|
|
delete hu;
|
||
|
|
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 = "ugrid x rect x instant x instant -> "
|
||
|
|
"stream (tuple (MovObjId int)(HistoryUnit upoint))";
|
||
|
|
syntax = "insideWindow ( _, _, _, _ )";
|
||
|
|
meaning = "Returns all history units inside the search window.";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
10 getTrajectory operator
|
||
|
|
|
||
|
|
Returns all history units 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),UGrid::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("HistoryUnit"),
|
||
|
|
nl->SymbolAtom(UPoint::BasicType())));
|
||
|
|
ListExpr streamList = nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
||
|
|
nl->TwoElemList(nl->SymbolAtom(Tuple::BasicType()),
|
||
|
|
tupleList));
|
||
|
|
return streamList;
|
||
|
|
}
|
||
|
|
ErrorReporter::ReportError("ugrid 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<HistoryUnit*> hits;
|
||
|
|
set<HistoryUnit*>::iterator it;
|
||
|
|
|
||
|
|
Iterator(set<HistoryUnit*> HITS)
|
||
|
|
{
|
||
|
|
hits = HITS;
|
||
|
|
it = hits.begin();
|
||
|
|
}
|
||
|
|
set<HistoryUnit*>::iterator GetIterator() {return it;}
|
||
|
|
};
|
||
|
|
|
||
|
|
Iterator* iterator = static_cast<Iterator*>(local.addr);
|
||
|
|
|
||
|
|
switch( message )
|
||
|
|
{
|
||
|
|
case OPEN:
|
||
|
|
{
|
||
|
|
UGrid* ugritPtr = static_cast<UGrid*>(args[0].addr);
|
||
|
|
CcInt* movObjId = static_cast<CcInt*>(args[1].addr);
|
||
|
|
int moID = movObjId->GetValue();
|
||
|
|
|
||
|
|
UGridArea area (ugritPtr->GetHeader()->area.x1,
|
||
|
|
ugritPtr->GetHeader()->area.y1,
|
||
|
|
ugritPtr->GetHeader()->area.x2,
|
||
|
|
ugritPtr->GetHeader()->area.y2);
|
||
|
|
|
||
|
|
// Find all history units
|
||
|
|
set<HistoryUnit*> tempHits = FindHistoryUnits( ugritPtr, ModifyArea(area),
|
||
|
|
ugritPtr->GetHeader()->tiv.start,
|
||
|
|
ugritPtr->GetHeader()->tiv.end );
|
||
|
|
|
||
|
|
// Filter all history units which belongs to the stated moving object id
|
||
|
|
set<HistoryUnit*>::iterator itTempHits;
|
||
|
|
set<HistoryUnit*> hits;
|
||
|
|
for (itTempHits = tempHits.begin(); itTempHits != tempHits.end();
|
||
|
|
itTempHits++)
|
||
|
|
{
|
||
|
|
HistoryUnit* ugritPtr = *itTempHits;
|
||
|
|
|
||
|
|
if ( moID == ugritPtr->moID )
|
||
|
|
{
|
||
|
|
hits.insert(ugritPtr);
|
||
|
|
}
|
||
|
|
else delete ugritPtr;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Initialize iterator
|
||
|
|
iterator = new Iterator(hits);
|
||
|
|
local.addr = iterator;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
case REQUEST:
|
||
|
|
{
|
||
|
|
if ( iterator->it != iterator->hits.end() )
|
||
|
|
{
|
||
|
|
HistoryUnit* hu = *iterator->GetIterator();
|
||
|
|
CcInt* moID = new CcInt(true, hu->moID);
|
||
|
|
Interval<Instant>* tiv = new Interval<Instant>(
|
||
|
|
DateTime(0,0,instanttype),
|
||
|
|
DateTime(0,0,instanttype),
|
||
|
|
true, true );
|
||
|
|
tiv->start.ReadFrom(hu->tivStart);
|
||
|
|
tiv->end.ReadFrom(hu->tivEnd);
|
||
|
|
|
||
|
|
UPoint* upoint = new UPoint(*tiv, hu->pos1.x, hu->pos1.y,
|
||
|
|
hu->pos2.x, hu->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 );
|
||
|
|
iterator->it++;
|
||
|
|
result.addr = tup;
|
||
|
|
delete tiv;
|
||
|
|
delete hu;
|
||
|
|
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 = "ugrid x int -> "
|
||
|
|
"stream (tuple (MovObjId int)(HistoryUnit upoint))";
|
||
|
|
syntax = "getTrajectory ( _, _ )";
|
||
|
|
meaning = "Returns all history units which belongs"
|
||
|
|
"to the stated moving object id.";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
11 currentUpload operator
|
||
|
|
|
||
|
|
Returns the current UploadUnit.
|
||
|
|
|
||
|
|
11.1 currentUpload - Type mapping method
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
ListExpr CurrentUploadTM(ListExpr args)
|
||
|
|
{
|
||
|
|
if( nl->ListLength( args ) == 2 &&
|
||
|
|
nl->IsEqual(nl->First(args),UGrid::BasicType()) &&
|
||
|
|
nl->IsEqual(nl->Second(args),CcInt::BasicType()) )
|
||
|
|
{
|
||
|
|
return nl->SymbolAtom(UploadUnit::BasicType());
|
||
|
|
}
|
||
|
|
ErrorReporter::ReportError("ugrid 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)
|
||
|
|
{
|
||
|
|
UGrid* ugridPtr = static_cast<UGrid*>(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 = ugridPtr->frontline[id%flBuckets].find(id);
|
||
|
|
if ( it == ugridPtr->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 = "ugrid x int -> uploadunit";
|
||
|
|
syntax = "currentUpload ( _, _ )";
|
||
|
|
meaning = "Returns the current UploadUnit.";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
12 UGridAlgebra
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
class UGridAlgebra : public Algebra
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
UGridAlgebra() : Algebra()
|
||
|
|
{
|
||
|
|
AddTypeConstructor(&UGridTC);
|
||
|
|
|
||
|
|
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 );
|
||
|
|
}
|
||
|
|
~UGridAlgebra() {};
|
||
|
|
};
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
|
||
|
|
13 Initialization
|
||
|
|
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
extern "C"
|
||
|
|
Algebra*
|
||
|
|
InitializeUGridAlgebra( NestedList *nlRef,
|
||
|
|
QueryProcessor *qpRef,
|
||
|
|
AlgebraManager* amRef )
|
||
|
|
{
|
||
|
|
nl = nlRef;
|
||
|
|
qp = qpRef;
|
||
|
|
am = amRef;
|
||
|
|
return (new UGridAlgebra());
|
||
|
|
}
|
||
|
|
} // End of UGridAlgebra namespace
|