2000 lines
70 KiB
C++
2000 lines
70 KiB
C++
/*
|
|
----
|
|
This file is part of SECONDO.
|
|
|
|
Copyright (C) 2007, University in Hagen, Department of Computer Science,
|
|
Database Systems for New Applications.
|
|
|
|
SECONDO is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
SECONDO is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with SECONDO; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
----
|
|
|
|
//paragraph [1] Title: [{\Large \bf ] [}]
|
|
//[->] [\ensuremath{\rightarrow}]
|
|
|
|
[1] Secondo SimulationAlgebra
|
|
|
|
|
|
April 04, 2007 C. Duentgen created the algebra
|
|
|
|
\begin{center}
|
|
\footnotesize
|
|
\tableofcontents
|
|
\end{center}
|
|
|
|
|
|
1 Overview
|
|
|
|
This algebra provides operators to create movement data for simulated vehicles.
|
|
|
|
|
|
2 Includes
|
|
|
|
We have to include some GSL headers and the GSLAlgebra.
|
|
|
|
*/
|
|
|
|
#include "Algebra.h"
|
|
#include "NestedList.h"
|
|
#include "QueryProcessor.h"
|
|
#include "StandardTypes.h"
|
|
#include "Messages.h"
|
|
#include "ListUtils.h"
|
|
#include "NList.h"
|
|
#include "DateTime.h"
|
|
#include "Symbols.h"
|
|
|
|
#include <cstdlib>
|
|
#include <iostream>
|
|
#include <string>
|
|
#include <sstream>
|
|
#include <vector>
|
|
|
|
#include <math.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
|
|
#include <NList.h>
|
|
|
|
#include "Algebras/Relation-C++/RelationAlgebra.h"
|
|
#include "Algebras/Temporal/TemporalAlgebra.h"
|
|
#include "Algebras/GSL/GSLAlgebra.h"
|
|
|
|
#ifndef SECONDO_WIN32
|
|
#define HAVE_INLINE
|
|
#endif
|
|
#include <gsl/gsl_rng.h>
|
|
#include <gsl/gsl_randist.h>
|
|
|
|
using namespace std;
|
|
using namespace datetime;
|
|
|
|
namespace temporalalgebra {
|
|
|
|
/*
|
|
3. Static Objects and Parameter Settings
|
|
|
|
This algebra uses its own random number generator to stay independent from
|
|
other random generator states.
|
|
|
|
You can change most of the parameters at runtime using operators
|
|
~sim\_set\_rng~, ~sim\_set\_dest\_params~ and ~sim\_set\_event\_params~.
|
|
|
|
*/
|
|
|
|
// setting up the RNG
|
|
unsigned long simRngSeed = 0; // 0 = use standard random seed
|
|
int simRngType = 14; // index of random number generator to use
|
|
// is gsl_rng_mt19937
|
|
static GslRandomgen simRNG( simRngType, simRngSeed );
|
|
|
|
// parameter set for waiting at destination node
|
|
double sim_dest_param_mu = 15000; // mean for exponential [ms]
|
|
// distribution [ms]
|
|
double sim_dest_param_ss = 0.33; // probabilities for forced stops
|
|
double sim_dest_param_sm = 0.66; // at crossings...
|
|
double sim_dest_param_sf = 1.00;
|
|
double sim_dest_param_ms = 0.33;
|
|
double sim_dest_param_mm = 0.50;
|
|
double sim_dest_param_mf = 0.66;
|
|
double sim_dest_param_fs = 0.05;
|
|
double sim_dest_param_fm = 0.33;
|
|
double sim_dest_param_ff = 0.10;
|
|
|
|
// maximum allowed velocities for different street types:
|
|
double sim_vmax_sidestreet = 30.0;
|
|
double sim_vmax_mainstreet = 50.0;
|
|
double sim_vmax_freeway = 70.0;
|
|
|
|
// parameter set for subsegment events
|
|
double sim_event_param_subsegmentlength = 5.0; // maximum length of subsections
|
|
// in [m]
|
|
double sim_event_param_propconst = 1.0; // constant c of proportionality
|
|
// p(event) = c/v_max
|
|
double sim_event_param_probstop = 0.1; // prob.(event == forced stop)
|
|
// balanced by deceleration
|
|
double sim_event_param_acceleration =12.0; // acceleration constant:
|
|
// increase step [m/s]
|
|
// within a single subsegment
|
|
|
|
// further parameters
|
|
double sim_startpoint_tolerance = 0.5; // tolerance for search of a line's
|
|
// starting point. Set to negative value
|
|
// for exact matching.
|
|
|
|
/*
|
|
4. General Typemapping Functions
|
|
|
|
*/
|
|
|
|
// real^N -> bool
|
|
template<int N>
|
|
ListExpr sim_realN2bool_TM ( ListExpr args )
|
|
{
|
|
ListExpr arg1, args2;
|
|
std::ostringstream oss;
|
|
oss << N;
|
|
// cout << "sim_realN2bool_TM<" << N << "> called." << endl;
|
|
if ( nl->ListLength( args ) == N ){
|
|
args2 = args;
|
|
for(int i=0; i<N; i++){
|
|
// cout << "\targs[" << i << "] " << endl;
|
|
arg1 = nl->First( args2 );
|
|
args2 = nl->Rest( args );
|
|
if ( !(nl->AtomType( arg1 ) == SymbolType) ||
|
|
!(nl->SymbolValue( arg1 ) == CcReal::BasicType())
|
|
){
|
|
ErrorReporter::ReportError("SimulationAlgebra::sim_realN2bool_TM "
|
|
"expects (real)^" + oss.str() + "." );
|
|
return (nl->SymbolAtom( Symbol::TYPEERROR() ));
|
|
}
|
|
}
|
|
return (nl->SymbolAtom( CcBool::BasicType() ));
|
|
}
|
|
ErrorReporter::ReportError("SimulationAlgebra::sim_realN2bool_TM "
|
|
"expects a list of length " + oss.str() + ".");
|
|
return (nl->SymbolAtom( Symbol::TYPEERROR() ));
|
|
}
|
|
|
|
|
|
/*
|
|
5. Operators
|
|
|
|
We will define the following operators:
|
|
|
|
----
|
|
|
|
sim_set_rng: int x int -> bool
|
|
sim_set_dest_params: real x real x real x real x real x real
|
|
x real x real x real x real x real
|
|
x real x real x real -> bool
|
|
sim_set_event_params: real x real x real x real -> bool
|
|
sim_create_trip: stream(tuple( ... (a_m line) ... (a_n real) ... ))
|
|
x instant x real [x real [x geoid] ]-> mpoint
|
|
|
|
----
|
|
|
|
*/
|
|
|
|
/*
|
|
5.1 Operator ~sim\_set\_rng~
|
|
|
|
Initialize the RNG with the passed type and random seed
|
|
|
|
*/
|
|
|
|
// int x int -> bool
|
|
ListExpr sim_set_rng_TM ( ListExpr args )
|
|
{
|
|
ListExpr arg1, arg2;
|
|
if ( nl->ListLength( args ) == 2 ){
|
|
arg1 = nl->First( args );
|
|
arg2 = nl->Second( args );
|
|
if ( nl->AtomType( arg1 ) == SymbolType &&
|
|
nl->SymbolValue( arg1 ) == CcInt::BasicType() &&
|
|
nl->AtomType( arg2 ) == SymbolType &&
|
|
nl->SymbolValue( arg2 ) == CcInt::BasicType() ) {
|
|
return (nl->SymbolAtom( CcBool::BasicType() ));
|
|
}
|
|
}
|
|
ErrorReporter::
|
|
ReportError("SimulationAlgebra: sim_set_rng expected int x int");
|
|
return (nl->SymbolAtom( Symbol::TYPEERROR() ));
|
|
}
|
|
|
|
int sim_set_rng_VM ( Word* args, Word& result,
|
|
int message, Word& local, Supplier s )
|
|
{
|
|
result = qp->ResultStorage( s );
|
|
CcBool *res = ((CcBool*)result.addr);
|
|
CcInt *arg1 = ((CcInt*)args[0].addr);
|
|
CcInt *arg2 = ((CcInt*)args[1].addr);
|
|
if ( arg1->IsDefined() && arg2->IsDefined() ) {
|
|
// overflow save implementation
|
|
long type = arg1->GetIntval();
|
|
unsigned long seed = arg2->GetIntval();
|
|
if( type >= 0 && type < GslRandomgen::rngType_getNoOfGenerators() ) {
|
|
simRNG = GslRandomgen(type, seed);
|
|
res->Set(true, true);
|
|
} else {
|
|
res->Set(true, false);
|
|
}
|
|
} else {
|
|
res->Set(true, false);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
const string sim_set_rng_Spec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )"
|
|
"( <text> int x int -> bool</text--->"
|
|
"<text>sim_set_rng( Type , Seed )</text--->"
|
|
"<text>Initialize the random number generator to be "
|
|
"of type 'Type' and use a random seed 'Seed'.</text--->"
|
|
"<text>query sim_set_rng( 14, 0 )</text--->"
|
|
") )";
|
|
|
|
Operator sim_set_rng(
|
|
"sim_set_rng",
|
|
sim_set_rng_Spec,
|
|
sim_set_rng_VM,
|
|
Operator::SimpleSelect,
|
|
sim_set_rng_TM) ;
|
|
|
|
/*
|
|
5.2 Operator ~sim\_set\_dest\_params~
|
|
|
|
Set parameters for stops at the destination node
|
|
|
|
*/
|
|
|
|
int sim_set_dest_params_VM ( Word* args, Word& result,
|
|
int message, Word& local, Supplier s )
|
|
{
|
|
result = qp->ResultStorage( s );
|
|
CcBool *res = ((CcBool*)result.addr);
|
|
CcReal* cArgs[14];
|
|
double dArgs[14];
|
|
for(int i=0; i<14; i++) {
|
|
cArgs[i] = (CcReal*) args[i].addr;
|
|
if ( !cArgs[i]->IsDefined() ) {
|
|
res->Set(true, false);
|
|
ErrorReporter::ReportError("SimulationAlgebra::sim_set_dest_params "
|
|
"expected defined param.");
|
|
return 0;
|
|
}
|
|
dArgs[i] = cArgs[i]->GetRealval();
|
|
if ( i>0 && (dArgs[i] < 0.0 || ( i<10 && dArgs[i] > 1.0 ) ) ) {
|
|
res->Set(true, false);
|
|
ErrorReporter::ReportError("SimulationAlgebra::sim_set_dest_params: "
|
|
"Probability out of bounds");
|
|
return 0;
|
|
}
|
|
}
|
|
sim_dest_param_mu = dArgs[0]/86400000.0;
|
|
sim_dest_param_ss = dArgs[1];
|
|
sim_dest_param_sm = dArgs[2];
|
|
sim_dest_param_sf = dArgs[3];
|
|
sim_dest_param_ms = dArgs[4];
|
|
sim_dest_param_mm = dArgs[5];
|
|
sim_dest_param_mf = dArgs[6];
|
|
sim_dest_param_fs = dArgs[7];
|
|
sim_dest_param_fm = dArgs[8];
|
|
sim_dest_param_ff = dArgs[9];
|
|
sim_vmax_sidestreet = dArgs[10];
|
|
sim_vmax_mainstreet = dArgs[11];
|
|
sim_vmax_freeway = dArgs[12];
|
|
sim_startpoint_tolerance = dArgs[13];
|
|
res->Set(true, true);
|
|
return 0;
|
|
}
|
|
|
|
const string sim_set_dest_params_Spec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )"
|
|
"( <text> real x real x real x real x real x real x real x "
|
|
" real x real x real x real x real x real x real -> bool</text--->"
|
|
"<text>sim_set_dest_params( ExpMu, SS, SM, SF, MS, MM, MF, FS, FM, "
|
|
"FF, VmaxS, VmaxM, VmaxF, SPT)"
|
|
"</text--->"
|
|
"<text>Set the parameters for stops at destination nodes: Set mean of "
|
|
"exponential distribution of waiting times to 'ExpMu' (in milliseconds). "
|
|
"Set probabilities "
|
|
"for forced stops at transitions between street types. 'XY' means "
|
|
"transition X -> Y, where S= small street, M= main street F= freeway. "
|
|
"Observe 0.0 <= p <= 1.0 for all probabilities p. "
|
|
"Set maximum allpwed velocities for sidestreets (VmaxS), mainstreets "
|
|
"(VmaxM) and freewayf (VmaxF) [1000/h]. Set the startpoint tolerance "
|
|
"to SPT [1]. Returns 'TRUE', iff the parameters have been set "
|
|
"correctly.</text--->"
|
|
"<text>query sim_set_dest_params( 1500.0, 0.33, 0.66, 1.0, 0.33, 0.5, "
|
|
"0.66, 0.05, 0.33, 0.10, 30.0, 50.0, 70.0, 0.5 )</text--->"
|
|
") )";
|
|
|
|
Operator sim_set_dest_params(
|
|
"sim_set_dest_params",
|
|
sim_set_dest_params_Spec,
|
|
sim_set_dest_params_VM,
|
|
Operator::SimpleSelect,
|
|
sim_realN2bool_TM<14>) ;
|
|
|
|
/*
|
|
5.3 Operator ~sim\_set\_event\_params~
|
|
|
|
Set parameters for enroute-event generation.
|
|
|
|
*/
|
|
|
|
int sim_set_event_params_VM ( Word* args, Word& result,
|
|
int message, Word& local, Supplier s )
|
|
{
|
|
result = qp->ResultStorage( s );
|
|
CcBool *res = ((CcBool*)result.addr);
|
|
CcReal* cArgs[4];
|
|
double dArgs[4];
|
|
for(int i=0; i<4; i++) {
|
|
cArgs[i] = (CcReal*) args[i].addr;
|
|
if ( !cArgs[i]->IsDefined() ) {
|
|
res->Set(true, false);
|
|
ErrorReporter::ReportError("SimulationAlgebra::sim_set_event_params "
|
|
"expected defined param.");
|
|
return 0;
|
|
}
|
|
dArgs[i] = cArgs[i]->GetRealval();
|
|
if ( (i==0 || i==4) && dArgs[i] <= 0.0 ) {
|
|
res->Set(true, false);
|
|
ErrorReporter::ReportError("SimulationAlgebra::sim_set_event_params: "
|
|
"1st parameter 'Length' must be positive!");
|
|
return 0;
|
|
}
|
|
if ( i==1 && dArgs[i] < 0.0 ) {
|
|
res->Set(true, false);
|
|
ErrorReporter::ReportError("SimulationAlgebra::sim_set_event_params: "
|
|
"2nd parameter 'Proportionality constant' must be <= 0.0!");
|
|
return 0;
|
|
}
|
|
if ( i==2 && (dArgs[i] < 0.0 || dArgs[i] > 1.0 ) ) {
|
|
res->Set(true, false);
|
|
ErrorReporter::ReportError("SimulationAlgebra::sim_set_event_params: "
|
|
"3rd parameter 'Probability' out of bounds!");
|
|
return 0;
|
|
}
|
|
}
|
|
sim_event_param_subsegmentlength = dArgs[0]; // maximum length of subsections
|
|
sim_event_param_propconst = dArgs[1]; // constant of proportionality
|
|
sim_event_param_probstop = dArgs[2]; // prob. for event = forced stop
|
|
sim_event_param_acceleration = dArgs[3]; // acceleration rate
|
|
// [km/h/sim_event_param_subsegmentlength]
|
|
res->Set(true, true);
|
|
return 0;
|
|
}
|
|
|
|
const string sim_set_event_params_Spec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )"
|
|
"( <text> real x real x real x real -> bool</text--->"
|
|
"<text>sim_set_event_params( Length, C, P, Acc)"
|
|
"</text--->"
|
|
"<text>Set the parameters for enroute-events: Routes will be divided into "
|
|
"subsegments of maximum length 'Length'. The probability of an event is "
|
|
"proprtional to C / Vmax. The probability for an event being a forced "
|
|
"stop is given by 0.0 <= P <= 1.0 (the balance, 1-P, is meant to trigger "
|
|
"deceleration events). Acceleration is set to 'Acc'."
|
|
"Returns 'TRUE', iff the parameters have been set correctly.</text--->"
|
|
"<text>sim_set_event_params( 5.0, 1.0, 0.1, 12.0 )</text--->"
|
|
") )";
|
|
|
|
Operator sim_set_event_params(
|
|
"sim_set_event_params",
|
|
sim_set_event_params_Spec,
|
|
sim_set_event_params_VM,
|
|
Operator::SimpleSelect,
|
|
sim_realN2bool_TM<4>) ;
|
|
|
|
|
|
/*
|
|
5.3 Operator ~sim\_create\_trip~
|
|
|
|
Create a moving point from a stream of lines and a startung instant.
|
|
|
|
*/
|
|
|
|
ListExpr sim_create_trip_TM ( ListExpr args )
|
|
{
|
|
int len = nl->ListLength(args);
|
|
if((len != 6) && (len != 7) && (len != 8)) {
|
|
return listutils::typeError("6, 7, or 8 arguments expected.");
|
|
}
|
|
|
|
// 1st arg: stream
|
|
ListExpr arg1 = nl->First(args);
|
|
if(!listutils::isTupleStream(arg1)) {
|
|
return listutils::typeError("1st argument must be a stream(tuple(X)).");
|
|
}
|
|
// extract the attribute names (2nd & 3rd argument)
|
|
ListExpr a1list = nl->Second(args);
|
|
ListExpr a2list = nl->Third(args);
|
|
if(!listutils::isSymbol(a1list) || !listutils::isSymbol(a2list)){
|
|
return listutils::typeError("2nd and 3rd argument must be identifiers.");
|
|
}
|
|
ListExpr attrlist = nl->Second(nl->Second(arg1));
|
|
ListExpr type1;
|
|
int a1index= listutils::findAttribute(attrlist,nl->SymbolValue(a1list),type1);
|
|
if (a1index == 0){
|
|
return listutils::typeError("Argument 2 must name an attribute from "
|
|
"the tuple stream!");
|
|
}
|
|
if(!listutils::isSymbol(type1,Line::BasicType())){
|
|
return listutils::typeError("Argument 2 must name an attribute of type "
|
|
"'line'!");
|
|
}
|
|
ListExpr type2;
|
|
int a2index= listutils::findAttribute(attrlist,nl->SymbolValue(a2list),type2);
|
|
if (a2index == 0){
|
|
return listutils::typeError("Argument 3 must name an attribute from "
|
|
"the tuple stream!");
|
|
}
|
|
if(!listutils::isSymbol(type2,CcReal::BasicType())){
|
|
return listutils::typeError("Argument 3 must name an attribute of type "
|
|
"'real'!");
|
|
}
|
|
a1index--; // translate position to attribute index to use in VM
|
|
a2index--; // translate position to attribute index to use in VM
|
|
|
|
// 4th argument: instant
|
|
ListExpr arg4 = nl->Fourth(args);
|
|
if(!listutils::isSymbol(arg4,DateTime::BasicType())){
|
|
return listutils::typeError("Argument 4 must be of type 'instant'!");
|
|
}
|
|
// 5th argument: point
|
|
ListExpr arg5 = nl->Fifth(args);
|
|
if(!listutils::isSymbol(arg5,Point::BasicType())){
|
|
return listutils::typeError("Argument 5 must be of type 'point'!");
|
|
}
|
|
// 6th argument: real
|
|
ListExpr arg6 = nl->Nth(6,args);
|
|
if ( !listutils::isSymbol(arg6,CcReal::BasicType()) ) {
|
|
return listutils::typeError("Argument 6 must be of type 'real'" );
|
|
}
|
|
|
|
ListExpr ind;
|
|
|
|
if ( (len == 7) || (len == 8) ) {// explicit starting velocity
|
|
ListExpr arg7 = nl->Nth(7,args);
|
|
if ( !listutils::isSymbol(arg7,CcReal::BasicType()) ) {
|
|
return listutils::typeError("Optional 7th argument must be of type "
|
|
"'real'" );
|
|
}
|
|
|
|
if(len==8){
|
|
ListExpr arg8 = nl->Nth(8,args);
|
|
if(!listutils::isSymbol(arg8,Geoid::BasicType())) {
|
|
return listutils::typeError("Optional 8th argument must be of type '"+
|
|
Geoid::BasicType()+"'.");
|
|
}
|
|
}
|
|
ind = nl->TwoElemList(nl->IntAtom(a1index),
|
|
nl->IntAtom(a2index));
|
|
} else {// all is correct, starting velocity == 0.0
|
|
ind = nl->ThreeElemList(nl->RealAtom(0.0),
|
|
nl->IntAtom(a1index),
|
|
nl->IntAtom(a2index));
|
|
}
|
|
|
|
return nl->ThreeElemList(nl->SymbolAtom(Symbol::APPEND()),
|
|
ind,
|
|
nl->SymbolAtom(MPoint::BasicType()));
|
|
}
|
|
|
|
|
|
struct Subsegment
|
|
{
|
|
Point start;
|
|
Point end;
|
|
};
|
|
|
|
|
|
int sim_create_trip_VM ( Word* args, Word& result,
|
|
int message, Word& local, Supplier s )
|
|
{
|
|
// cout << "sim_create_trip_VM received message: ";
|
|
// if (message == OPEN) cout << "OPEN" << endl;
|
|
// else if (message == REQUEST) cout << "REQUEST" << endl;
|
|
// else if (message == CLOSE) cout << "CLOSE" << endl;
|
|
// else if (message == YIELD) cout << "YIELD" << endl;
|
|
// else if (message == CANCEL) cout << "CANCEL" << endl;
|
|
// else if (message == CARDINALITY) cout << "CARDINALITY" << endl;
|
|
// else if (message == PROGRESS) cout << "PROGRESS" << endl;
|
|
// else cout << "(unknown message)" << endl;
|
|
|
|
result = qp->ResultStorage( s );
|
|
Geoid* geoid = 0;
|
|
int argoffset = 0;
|
|
if(qp->GetNoSons(s)==10){
|
|
argoffset = 1;
|
|
geoid = static_cast<Geoid*>(args[7].addr);
|
|
}
|
|
MPoint* res = static_cast<MPoint*>(result.addr);
|
|
CcInt* cLineIndex = static_cast<CcInt*>(args[7+argoffset].addr);
|
|
CcInt* cVmaxIndex = static_cast<CcInt*>(args[8+argoffset].addr);
|
|
Instant* instStart = static_cast<Instant*>(args[3].addr);
|
|
Point* pointStart = static_cast<Point*>(args[4].addr);
|
|
CcReal* cTopSpeed = static_cast<CcReal*>(args[5].addr);
|
|
CcReal* cVstart = static_cast<CcReal*>(args[6].addr);
|
|
long tuplesReceived = 0;
|
|
long tuplesAccepted = 0;
|
|
long invalidUnitsCreated = 0;
|
|
|
|
// cout << "cLineIndex = "; cLineIndex->Print(cout); cout << endl;
|
|
// cout << "cVmaxIndex = "; cVmaxIndex->Print(cout); cout << endl;
|
|
// cout << "instStart = "; instStart->Print(cout); cout << endl;
|
|
// cout << "pointStart = "; pointStart->Print(cout); cout << endl;
|
|
// cout << "cTopSpeed = "; topSpeed->Print(cout); cout << endl;
|
|
// cout << "cVstart = "; cVstart->Print(cout); cout << endl;
|
|
// cout << "geoid = "; if(geoid){ cout << *geoid; } else { cout << "0"; }
|
|
// cout << endl;
|
|
|
|
res->Clear();
|
|
res->SetDefined( true );
|
|
res->StartBulkLoad();
|
|
MessageCenter* msg = MessageCenter::GetInstance();
|
|
|
|
if( instStart->IsDefined() && pointStart->IsDefined() &&
|
|
cVstart->IsDefined() &&
|
|
cLineIndex->IsDefined() && cTopSpeed->IsDefined() &&
|
|
cVmaxIndex->IsDefined() ){
|
|
vector<Subsegment> subsegments(0);
|
|
int lineIndex = cLineIndex->GetIntval();
|
|
int VmaxIndex = cVmaxIndex->GetIntval();
|
|
Instant currentInst = *instStart;
|
|
double Vtop = cTopSpeed->GetValue();
|
|
double currentSpeed = cVstart->GetRealval();
|
|
if( Vtop<=0.0 ){
|
|
string msgstr = "Warning: invalid top speed in operator create_sim_trip!";
|
|
msg->Send(nl, listutils::simpleMessage(msgstr));
|
|
}
|
|
if( currentSpeed<0.0 ){
|
|
string msgstr = "Warning: invalid top speed in operator create_sim_trip!";
|
|
msg->Send(nl, listutils::simpleMessage(msgstr));
|
|
}
|
|
if( (Vtop<=0.0) || (currentSpeed<0.0) ){
|
|
res->SetDefined( false );
|
|
return 0;
|
|
}
|
|
Instant currentTime = *instStart;
|
|
Point currentPosition = *pointStart;
|
|
double currentVmax = MIN(Vtop,currentSpeed);
|
|
double localVmax = 0.0;
|
|
double lastMaxSpeed = -1.0;
|
|
bool stopAfterThis = false;
|
|
bool ok = true; // flag for DistanceOrthodrome
|
|
Point startPoint(true,0,0);
|
|
Point endPoint(true,0,0);
|
|
DateTime dummyDuration(0,0,durationtype);
|
|
Line* currentLineC = 0;
|
|
SimpleLine currentLine(0);
|
|
Word wActualTuple;
|
|
qp->Open(args[0].addr);
|
|
qp->Request(args[0].addr, wActualTuple);
|
|
while (qp->Received(args[0].addr)) {
|
|
tuplesReceived++;
|
|
// speed == 0.0 signals to wait for a random duration before the
|
|
// movement may be continued!
|
|
Tuple* tuple = (Tuple*) (wActualTuple.addr);
|
|
currentLineC = (Line*) (tuple->GetAttribute(lineIndex));
|
|
currentLine.fromLine(*currentLineC);
|
|
CcReal *CcurrentVmax = (CcReal*)(tuple->GetAttribute(VmaxIndex));
|
|
|
|
// search for the first segment (starts with point currentPosition)
|
|
assert( currentPosition.IsDefined() );
|
|
if( currentLine.IsDefined() &&
|
|
CcurrentVmax->IsDefined() &&
|
|
!currentLine.IsEmpty() &&
|
|
currentLine.SelectInitialSegment(currentPosition,
|
|
sim_startpoint_tolerance) ) {
|
|
// all args defined and current position found in currentLine
|
|
tuplesAccepted++;
|
|
currentVmax = CcurrentVmax->GetRealval();
|
|
startPoint = currentPosition;
|
|
endPoint = currentPosition;
|
|
while( currentLine.getWaypoint(endPoint) ) { // for each line segment:
|
|
assert( endPoint.IsDefined() );
|
|
Subsegment s;
|
|
double l = geoid?startPoint.DistanceOrthodrome(endPoint,*geoid, ok)
|
|
:startPoint.Distance(endPoint);
|
|
assert(ok);
|
|
double incrX = sim_event_param_subsegmentlength
|
|
* (endPoint.GetX() - startPoint.GetX()) / l;
|
|
double incrY = sim_event_param_subsegmentlength
|
|
* (endPoint.GetY() - startPoint.GetY()) / l;
|
|
if(AlmostEqual(incrX, 0.0) && AlmostEqual(incrY, 0.0)) {
|
|
cout << " X- and Y-Increment == 0.0! -> BREAK" << endl;
|
|
break;
|
|
}
|
|
Point interimStart = startPoint;
|
|
Point interimEnd = startPoint;
|
|
while( (geoid?interimEnd.DistanceOrthodrome(endPoint,*geoid, ok)
|
|
:interimEnd.Distance(endPoint)) >=
|
|
sim_event_param_subsegmentlength ) {
|
|
assert(ok);
|
|
// divide the remaining segment into subsegments
|
|
interimEnd.Translate(incrX,incrY);
|
|
s.start = interimStart;
|
|
s.end = interimEnd;
|
|
if(!AlmostEqual(s.start,s.end)){
|
|
subsegments.push_back(s);
|
|
}
|
|
interimStart = interimEnd;
|
|
}
|
|
assert(ok);
|
|
// add the last subsegment
|
|
s.start = interimStart;
|
|
s.end = endPoint;
|
|
assert( endPoint.IsDefined() );
|
|
if(!AlmostEqual(s.start,s.end)){
|
|
subsegments.push_back(s);
|
|
}
|
|
startPoint = endPoint;
|
|
currentLine.SelectSubsequentSegment();
|
|
}
|
|
// iterate vector to determine the speed at the end of each subsegment:
|
|
for(unsigned int i=0 ; i<subsegments.size(); i++) {
|
|
localVmax = currentVmax; // base for further calculations
|
|
if ( lastMaxSpeed >= 0.0 ) {
|
|
// Special Case:
|
|
// Handle last subsegment of preceeding line:
|
|
localVmax = lastMaxSpeed; // recall lastMaxSpeed for
|
|
// reenqueued subsegment
|
|
// check whether to stop at the crossing
|
|
double pWait = 0.0;
|
|
if ( lastMaxSpeed <= sim_vmax_sidestreet ) {
|
|
if ( currentVmax <= sim_vmax_sidestreet ) {
|
|
pWait = sim_dest_param_ss;
|
|
}
|
|
else if ( currentVmax <= sim_vmax_mainstreet ) {
|
|
pWait = sim_dest_param_sm;
|
|
}
|
|
else if ( currentVmax <= sim_vmax_freeway ) {
|
|
pWait = sim_dest_param_sf;
|
|
}
|
|
else {
|
|
cout << " S->? "; pWait = 0.0;
|
|
}
|
|
}
|
|
else if ( lastMaxSpeed <= sim_vmax_mainstreet ) {
|
|
if ( currentVmax <= sim_vmax_sidestreet ) {
|
|
pWait = sim_dest_param_ms;}
|
|
else if ( currentVmax <= sim_vmax_mainstreet ) {
|
|
pWait = sim_dest_param_mm;
|
|
}
|
|
else if ( currentVmax <= sim_vmax_freeway ) {
|
|
pWait = sim_dest_param_mf;
|
|
}
|
|
else {
|
|
cout << " M->? "; pWait = 0.0;
|
|
}
|
|
}
|
|
else if ( lastMaxSpeed <= sim_vmax_freeway ) {
|
|
if ( currentVmax <= sim_vmax_sidestreet ) {
|
|
pWait = sim_dest_param_fs;
|
|
}
|
|
else if ( currentVmax <= sim_vmax_mainstreet ) {
|
|
pWait = sim_dest_param_fm;
|
|
}
|
|
else if ( currentVmax <= sim_vmax_freeway ) {
|
|
pWait = sim_dest_param_ff;
|
|
}
|
|
else {
|
|
cout << " F->? "; pWait = 0.0;
|
|
}
|
|
} else {
|
|
cout << " ?->? ";
|
|
pWait = 0.0;
|
|
}
|
|
if(simRNG.NextReal() <= pWait) {
|
|
// Force waiting at the crossing...
|
|
stopAfterThis = true;
|
|
}
|
|
lastMaxSpeed = -1.0; // avoid double waits
|
|
}
|
|
if ( AlmostEqual(currentSpeed, 0.0) ) {
|
|
// speed == 0.0 indicates, that we have to wait,
|
|
// before we may continue the voyage:
|
|
// Determine waiting duration using exponential distribution:
|
|
double waittime =
|
|
gsl_ran_exponential(simRNG.GetGenerator(),
|
|
sim_dest_param_mu/86400000.0);
|
|
dummyDuration.ReadFrom(waittime);
|
|
if( dummyDuration > DateTime(0,0,durationtype) ) {
|
|
const Interval<Instant>
|
|
interval( currentInst,
|
|
currentInst + dummyDuration,
|
|
true,
|
|
false );
|
|
UPoint up( interval,
|
|
subsegments[i].start, subsegments[i].start);
|
|
if( up.IsValid() ) {
|
|
res->MergeAdd(up);
|
|
currentInst += dummyDuration;
|
|
} else {
|
|
invalidUnitsCreated++;
|
|
cout << "Invalid unit up = "; up.Print(cout); cout << endl;
|
|
}
|
|
}
|
|
}
|
|
if (i<subsegments.size()-1) {
|
|
// This is not the last subsegment for this line
|
|
if( simRNG.NextReal() <= (sim_event_param_propconst/currentVmax) ) {
|
|
// An event occurrs
|
|
if( simRNG.NextReal() <= (sim_event_param_probstop) ) {
|
|
// forced stop after this sub-segment
|
|
stopAfterThis = true;
|
|
} else {
|
|
// forced deceleration. Use binomial distrib.
|
|
// to determine amount of speed loss
|
|
localVmax =
|
|
localVmax * gsl_ran_binomial(simRNG.GetGenerator(),
|
|
0.5,
|
|
20)
|
|
/20.0;
|
|
localVmax = MAX(localVmax, 1.0);
|
|
}
|
|
} else {
|
|
// no event: accelerate up to localVmax
|
|
localVmax =
|
|
MIN(MIN(currentSpeed+sim_event_param_acceleration,
|
|
currentVmax),
|
|
Vtop);
|
|
}
|
|
// calculate steepness of curves
|
|
double alpha =
|
|
!AlmostEqual(subsegments[i].end, subsegments[i+1].end)
|
|
? Point::calcEnclosedAngle(subsegments[i].start,
|
|
subsegments[i].end,
|
|
subsegments[i+1].end,
|
|
geoid)
|
|
: 0.0;
|
|
cout.precision(16);
|
|
// cout << "alpha = " << alpha << endl;
|
|
// cout << "currentVmax = " << currentVmax << endl;
|
|
double curveMax =
|
|
(1.0-( fmod(fabs(alpha - 180.0), 180.0) )/180.0)
|
|
* currentVmax;
|
|
// cout << "curveMax = " << curveMax << endl;
|
|
localVmax = MIN(MIN( localVmax, curveMax ), Vtop );
|
|
currentSpeed = localVmax;
|
|
} else if (i == subsegments.size()-1 ) {
|
|
// This is the last subsegment. Delete all subsegments,
|
|
// but the last one
|
|
Subsegment lastSubSeg = subsegments[i];
|
|
subsegments.clear();
|
|
subsegments.push_back(lastSubSeg);
|
|
lastMaxSpeed = currentVmax; // prepare special treatment
|
|
// of this subsegment
|
|
currentPosition = subsegments.back().end; //required to find next
|
|
// subsegment within the next line
|
|
break; // this exits the for()-loop
|
|
}
|
|
// Create a unit for the current subsegment
|
|
double dist = geoid?
|
|
subsegments[i].start.DistanceOrthodrome(subsegments[i].end,*geoid,ok)
|
|
:subsegments[i].start.Distance(subsegments[i].end);
|
|
assert(ok);
|
|
dummyDuration.ReadFrom(dist/currentSpeed/24000L);
|
|
// ^^^^ time used to travel the subsegment t=s/v ^^^
|
|
const Interval<Instant>
|
|
interval( currentInst,
|
|
currentInst + dummyDuration,
|
|
true,
|
|
false );
|
|
UPoint up( interval, subsegments[i].start, subsegments[i].end);
|
|
if( up.IsValid() ) {
|
|
res->MergeAdd(up);
|
|
currentInst += dummyDuration;
|
|
} else {
|
|
invalidUnitsCreated++;
|
|
// cout << "Invalid unit up = "; up.Print(cout); cout << endl;
|
|
}
|
|
currentPosition = subsegments[i].end;
|
|
if (stopAfterThis) {
|
|
currentSpeed = 0.0;
|
|
stopAfterThis = false;
|
|
}
|
|
} // endfor(unsigned int i=0 ; i<subsegments.size(); i++)
|
|
assert( currentPosition.IsDefined() );
|
|
} // endif( currentLine->SelectInitialSegment(currentPosition) )
|
|
else { // undef/empty/complex/cyclic line or undef vmax or cuppentPos
|
|
// not found: do nothing
|
|
cout << "current position (= " ;
|
|
currentPosition.Print(cout);
|
|
cout << " ) NOT found in currentLine" << endl;
|
|
}
|
|
tuple->DeleteIfAllowed();
|
|
qp->Request(args[0].addr, wActualTuple);
|
|
}
|
|
// create and append the final unit
|
|
if( subsegments.size() == 1 ) {
|
|
// there is a subsegment left. Nothing happens here.
|
|
currentSpeed = MAX(currentSpeed, 5.0);
|
|
double dist = geoid?
|
|
subsegments[0].start.DistanceOrthodrome(subsegments[0].end,*geoid,ok)
|
|
:subsegments[0].start.Distance(subsegments[0].end);
|
|
assert(ok);
|
|
dummyDuration.ReadFrom(dist/currentSpeed/24000); // time used to travel
|
|
// the subsegment t=s/v
|
|
const Interval<Instant>
|
|
interval( currentInst,
|
|
currentInst + dummyDuration,
|
|
true,
|
|
false );
|
|
UPoint up( interval, subsegments[0].start, subsegments[0].end);
|
|
if( up.IsValid() ) {
|
|
res->MergeAdd(up);
|
|
currentInst += dummyDuration;
|
|
} else {
|
|
invalidUnitsCreated++;
|
|
cout << "Invalid unit up = "; up.Print(cout); cout << endl;
|
|
}
|
|
currentPosition = subsegments.back().end; // set currentPosition to
|
|
} // endwhile (qp->Received(args[0].addr))
|
|
else {
|
|
// ( subsegments.size() != 1 )
|
|
cout << "sim_create_trip_VM: Something's wrong: subsegments.size() = "
|
|
<< subsegments.size() << "." << endl;
|
|
}
|
|
qp->Close(args[0].addr);
|
|
}
|
|
else
|
|
{ // some undef argument:
|
|
cout << "sim_create_trip_VM: undefined Argument: " << endl;
|
|
cout << " StartInstant: " << instStart->IsDefined() << endl;
|
|
cout << " StartPoint: " << pointStart->IsDefined() << endl;
|
|
cout << " TopSpeed: " << cTopSpeed->IsDefined(); cout << endl;
|
|
cout << " StartVelocity: " << cVstart->IsDefined() << endl;
|
|
cout << " LineIndex: " << cLineIndex->IsDefined() << endl;
|
|
cout << " VelocityIndex: " << cVmaxIndex->IsDefined() << endl;
|
|
res->SetDefined( false );
|
|
}
|
|
res->EndBulkLoad(false,true);
|
|
// cout << "sim_create_trip_VM: Finished!" << endl;
|
|
// cout << " tuplesReceived = " << tuplesReceived << endl;
|
|
// cout << " tuplesAccepted = " << tuplesAccepted << endl;
|
|
// cout << " units created = " << res->GetNoComponents() << endl;
|
|
// cout << " invalidUnitsCreated = " << invalidUnitsCreated << endl << endl;
|
|
// cout << "sim_create_trip_VM: returned result.";
|
|
return 0;
|
|
}
|
|
|
|
const string sim_create_trip_Spec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
|
"( <text>stream(tuple(a1: t1) ... (an,tn) x ai x aj x instant x point "
|
|
"x real [x real [x geoid] ] -> mpoint,\n"
|
|
"for ti = line, tj = real, tk = point</text--->"
|
|
"<text>_ sim_create_trip [LineAttr, VmaxAttr, StartInst, StartPoint, "
|
|
"Vtop [, Vstart [, Geoid] ]</text--->"
|
|
"<text>Creates a mpoint value representing a simulated vehicle, "
|
|
"starting at instant 'StartInst' and 'StartPoint' and moving along a "
|
|
"trajectory formed by the stream of lines received from the stream "
|
|
"argument. The stream contains tuples describing subsequent parts of the "
|
|
"trajectory and the maximum allowed speed for that street section. The "
|
|
"velocity of the vehicle reflects street topology and random events. "
|
|
"The sixth argument 'Vtop' is to object's top speed. 'Vstart' is optional "
|
|
"and sets the vehicle's initial velocity. If omitted, Vmax is set to 0.0."
|
|
" The last parameter 'Geoid' must be used when working with geographic "
|
|
"(LAT,LON) coordinates. "
|
|
"Otherwise euclidean (Easting,Northing) coordinates are used.</text--->"
|
|
"<text>query _ sim_create_trip[ _ ]</text--->"
|
|
") )";
|
|
|
|
Operator sim_create_trip(
|
|
"sim_create_trip",
|
|
sim_create_trip_Spec,
|
|
sim_create_trip_VM,
|
|
Operator::SimpleSelect,
|
|
sim_create_trip_TM) ;
|
|
|
|
|
|
/*
|
|
5.4 Operator ~sim\_print\_params~
|
|
|
|
Prints the parameter settings to the console.
|
|
|
|
*/
|
|
|
|
ListExpr sim_empty2bool_TM ( ListExpr args )
|
|
{
|
|
if ( nl->ListLength( args ) == 0 ) {
|
|
return (nl->SymbolAtom( CcBool::BasicType() ));
|
|
}
|
|
ErrorReporter::ReportError("SimulationAlgebra::sim_empty2bool_TM "
|
|
"expects a list of length 0.");
|
|
return (nl->SymbolAtom( Symbol::TYPEERROR() ));
|
|
}
|
|
|
|
|
|
int sim_print_params_VM ( Word* args, Word& result,
|
|
int message, Word& local, Supplier s )
|
|
{
|
|
result = qp->ResultStorage( s );
|
|
CcBool *res = ((CcBool*)result.addr);
|
|
|
|
cout << endl;
|
|
cout << "***********************************************************" <<endl;
|
|
cout << "* SimulationAlgera Parameter Settings *" << endl;
|
|
cout << "***********************************************************" <<endl;
|
|
cout << "* RANDOM NUMBER GENERATOR:" << endl;
|
|
cout << "* simRngSeed = " << simRngSeed << endl;
|
|
cout << "* simRngType = " << simRngType << endl;
|
|
cout << "***********************************************************" <<endl;
|
|
cout << "* CROSSING PARAMETERS" << endl;
|
|
cout << "* sim_dest_param_mu = " << sim_dest_param_mu << "[ms]" << endl;
|
|
cout << "* sim_dest_param_ss = " << sim_dest_param_ss<< "[0,1]" << endl;
|
|
cout << "* sim_dest_param_sm = " << sim_dest_param_sm<< "[0,1]" << endl;
|
|
cout << "* sim_dest_param_sf = " << sim_dest_param_sf<< "[0,1]" << endl;
|
|
cout << "* sim_dest_param_ms = " << sim_dest_param_ms<< "[0,1]" << endl;
|
|
cout << "* sim_dest_param_mm = " << sim_dest_param_mm<< "[0,1]" << endl;
|
|
cout << "* sim_dest_param_ms = " << sim_dest_param_mf<< "[0,1]" << endl;
|
|
cout << "* sim_dest_param_fs = " << sim_dest_param_fs<< "[0,1]" << endl;
|
|
cout << "* sim_dest_param_fm = " << sim_dest_param_fm<< "[0,1]" << endl;
|
|
cout << "* sim_dest_param_ff = " << sim_dest_param_ff<< "[0,1]" << endl;
|
|
cout << "* sim_vmax_sidestreet = " << sim_vmax_sidestreet<< "[km/h]" <<endl;
|
|
cout << "* sim_vmax_mainstreet = " << sim_vmax_mainstreet<< "[km/h]" <<endl;
|
|
cout << "* sim_vmax_freeway = " << sim_vmax_freeway<< "[km/h]" << endl;
|
|
cout << "* sim_startpoint_tolerance = " << sim_vmax_freeway<< "[>0.0]"
|
|
<< endl;
|
|
cout << "***********************************************************" <<endl;
|
|
cout << "* SUBSEGMENT PARAMETERS" << endl;
|
|
cout << "* sim_event_param_subsegmentlength = "
|
|
<< sim_event_param_subsegmentlength<< "[m]" << endl;
|
|
cout << "* sim_event_param_propconst = " << sim_event_param_propconst
|
|
<< "[>0]" << endl;
|
|
cout << "* sim_event_param_acceleration = "
|
|
<< sim_event_param_acceleration << "[m/s^2]" << endl;
|
|
cout << "***********************************************************" <<endl;
|
|
res->Set(true, true);
|
|
return 0;
|
|
}
|
|
|
|
const string sim_print_params_Spec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )"
|
|
"( <text> -> bool</text--->"
|
|
"<text>sim_print_params( )</text--->"
|
|
"<text>Prints the paramter settings to the console. Always "
|
|
"returns 'TRUE'</text--->"
|
|
"<text>sim_print_params()</text--->"
|
|
") )";
|
|
|
|
Operator sim_print_params(
|
|
"sim_print_params",
|
|
sim_print_params_Spec,
|
|
sim_print_params_VM,
|
|
Operator::SimpleSelect,
|
|
sim_empty2bool_TM) ;
|
|
|
|
|
|
/*
|
|
5.5 Operator ~sim\_fillup\_mpoint~
|
|
|
|
Fills the undefined intervals within an mpoint with the known positions.
|
|
immedeately before/after the ``dark periods''.
|
|
|
|
----
|
|
sim_fillup_mpoint:
|
|
(mpoint x instant x instant x bool x bool x bool) --> mpoint
|
|
|
|
----
|
|
|
|
*/
|
|
|
|
ListExpr sim_fillup_mpoint_TM ( ListExpr args )
|
|
{
|
|
ListExpr arg1, arg2, arg3, arg4, arg5, arg6;
|
|
if ( nl->ListLength( args ) == 6 ) {
|
|
arg1 = nl->First( args );
|
|
arg2 = nl->Second( args );
|
|
arg3 = nl->Third( args );
|
|
arg4 = nl->Fourth( args );
|
|
arg5 = nl->Fifth( args );
|
|
arg6 = nl->Sixth( args );
|
|
|
|
if ( nl->AtomType( arg1 ) == SymbolType &&
|
|
nl->SymbolValue( arg1 ) == MPoint::BasicType() &&
|
|
nl->AtomType( arg2 ) == SymbolType &&
|
|
nl->SymbolValue( arg2 ) == Instant::BasicType() &&
|
|
nl->AtomType( arg3 ) == SymbolType &&
|
|
nl->SymbolValue( arg3 ) == Instant::BasicType() &&
|
|
nl->AtomType( arg4 ) == SymbolType &&
|
|
nl->SymbolValue( arg4 ) == CcBool::BasicType() &&
|
|
nl->AtomType( arg5 ) == SymbolType &&
|
|
nl->SymbolValue( arg5 ) == CcBool::BasicType() &&
|
|
nl->AtomType( arg6 ) == SymbolType &&
|
|
nl->SymbolValue( arg6 ) == CcBool::BasicType() ) {
|
|
return (nl->SymbolAtom( MPoint::BasicType() ));
|
|
}
|
|
}
|
|
ErrorReporter::
|
|
ReportError("SimulationAlgebra: sim_fillup_mpoint expected "
|
|
"mpoint x instant x instant x bool x bool x bool");
|
|
return (nl->SymbolAtom( Symbol::TYPEERROR() ));
|
|
}
|
|
|
|
int sim_fillup_mpoint_VM ( Word* args, Word& result,
|
|
int message, Word& local, Supplier s )
|
|
{
|
|
result = qp->ResultStorage( s );
|
|
MPoint *res = ((MPoint*)result.addr);
|
|
res->Clear();
|
|
|
|
MPoint *Input = (MPoint*) args[0].addr;
|
|
Instant *Start = (Instant*) args[1].addr;
|
|
Instant *End = (Instant*) args[2].addr;
|
|
CcBool *LC = (CcBool*) args[3].addr;
|
|
CcBool *RC = (CcBool*) args[4].addr;
|
|
CcBool *CONN = (CcBool*) args[5].addr;
|
|
|
|
if( !Input->IsDefined() ||
|
|
!LC->IsDefined() || !RC->IsDefined() ||
|
|
!Start->IsDefined() || !End->IsDefined() ||
|
|
*Start > *End ||
|
|
( *Start == *End && (!LC->GetBoolval() || !RC->GetBoolval())) ||
|
|
!CONN->IsDefined()
|
|
) {
|
|
// undefined arguments: return undefined and empty result
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
res->SetDefined(true);
|
|
int size = Input->GetNoComponents();
|
|
if( size == 0 ) {
|
|
// empty input: return defined and empty result
|
|
res->SetDefined(true);
|
|
return 0;
|
|
}
|
|
|
|
UPoint u1(true), u2(true), resunit(true);
|
|
Interval<DateTime> gap(*Start,*Start,true,true);
|
|
res->SetDefined(true);
|
|
|
|
bool connect = CONN->GetBoolval();
|
|
int pos = 0;
|
|
//test whether to insert a prequel unit
|
|
Input->Get(pos, u1);
|
|
// cout << "First Unit = "; u1.Print(cout);
|
|
if ( *Start < u1.timeInterval.start ) {
|
|
// Start before first unit
|
|
gap = Interval<DateTime>( *Start, u1.timeInterval.start,
|
|
LC->GetBoolval(), !u1.timeInterval.lc );
|
|
resunit = UPoint(gap, u1.p0, u1.p0);
|
|
// cout << " Inserting prequel unit: "; resunit.Print(cout);
|
|
res->MergeAdd( resunit );
|
|
u2 = u1;
|
|
pos++;
|
|
} else if ( *Start == u1.timeInterval.start &&
|
|
LC->GetBoolval() &&
|
|
!u1.timeInterval.lc
|
|
) {
|
|
// extend first unit by changing lc to true
|
|
resunit = UPoint(Interval<DateTime>(u1.timeInterval.start,
|
|
u1.timeInterval.end,
|
|
true,
|
|
u1.timeInterval.rc),
|
|
u1.p0, u1.p0);
|
|
u2 = resunit;
|
|
// cout << " >>Extended first unit: "; resunit.Print(cout);
|
|
pos++;
|
|
} else {
|
|
// just prepare insertion of first unit
|
|
u2 = u1;
|
|
pos++;
|
|
// cout << " >>Nothing to do" << endl;
|
|
}
|
|
while(pos < size) {
|
|
Input->Get(pos, u1);
|
|
// cout << "pos/size = " << pos << "/" << size << endl;
|
|
// cout << " u2 = "; u2.Print(cout);
|
|
// cout << " u1 = "; u1.Print(cout);
|
|
if ( u2.timeInterval.end == u1.timeInterval.start ) {
|
|
// Case 1): u2.end == u1.start
|
|
if ( !u2.timeInterval.rc && !u1.timeInterval.lc ) {
|
|
// 1a) minimum gap between open intervals
|
|
// --> make u2 rightclosed and append it.
|
|
u2.timeInterval.rc = true;
|
|
// cout << " Case 1a): Adding: "; u2.Print(cout);
|
|
res->MergeAdd( u2 );
|
|
u2 = u1;
|
|
pos++;
|
|
} else {
|
|
// 1b) u2.rc != u1.lc: No gap
|
|
// --> just add the original unit u2
|
|
// cout << " Case 1b): Adding: "; u2.Print(cout);
|
|
res->MergeAdd( u2 );
|
|
u2 = u1;
|
|
pos++;
|
|
}
|
|
} else if( u2.timeInterval.end < u1.timeInterval.start ) {
|
|
// Case 2) simple case: start and ending instant are not equal
|
|
// (large gap of at least nearly 1 tick/ms)
|
|
// --> append u2 and a unit for the gap
|
|
// cout << " Case 2) : Adding: "; u2.Print(cout);
|
|
res->MergeAdd( u2 );
|
|
resunit = UPoint( Interval<DateTime>( u2.timeInterval.end,
|
|
u1.timeInterval.start,
|
|
!u2.timeInterval.rc,
|
|
!u1.timeInterval.lc),
|
|
(connect ? u1.p0 : u2.p1), u2.p1);
|
|
// cout << " Adding: "; resunit.Print(cout);
|
|
res->MergeAdd( resunit );
|
|
u2 = u1;
|
|
pos++;
|
|
} else {
|
|
// u2-timeInterval.end > u1.timeInterval.start
|
|
// --> Error!
|
|
cerr << "sim_fillup_mpoint_VM: Error calculating gap unit:" << endl;
|
|
cerr << "\tu2 = "; u2.Print(cerr);
|
|
cerr << "\tu1 = "; u1.Print(cerr); cerr << endl;
|
|
res->Clear();
|
|
res->SetDefined( false );
|
|
return 0;
|
|
}
|
|
}
|
|
// test whether to insert a sequel unit
|
|
if ( u2.timeInterval.end < *End ) {
|
|
// cout << "Adding last unit: "; u2.Print(cout);
|
|
res->MergeAdd( u2 );
|
|
resunit = UPoint( Interval<DateTime>( u2.timeInterval.end,
|
|
*End,
|
|
!u2.timeInterval.rc,
|
|
RC->GetBoolval() ),
|
|
u2.p1, u2.p1);
|
|
// cout << "Adding Sequel unit: "; resunit.Print(cout); cout << endl;
|
|
res->MergeAdd( resunit );
|
|
} else if ( u2.timeInterval.end == *End &&
|
|
!u2.timeInterval.rc &&
|
|
RC->GetBoolval()
|
|
) {
|
|
// extend the last unit by right-closing the timeInterval
|
|
resunit = UPoint( Interval<DateTime>( u2.timeInterval.start,
|
|
u2.timeInterval.end,
|
|
u2.timeInterval.lc,
|
|
!u2.timeInterval.rc),
|
|
u2.p0, u2.p1);
|
|
res->MergeAdd( resunit );
|
|
// cout << "Adding modified last unit: "; resunit.Print(cout); cout << endl;
|
|
} else {
|
|
// just append u2
|
|
// cout << "Adding last unit: "; u2.Print(cout); cout << endl;
|
|
res->MergeAdd( u2 );
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
const string sim_fillup_mpoint_Spec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )"
|
|
"( <text> mpoint x instant x instant x bool x bool x bool -> mpoint"
|
|
"</text--->"
|
|
"<text>M sim_fillup_mpoint[ S, E, LC, RC, CONN ]"
|
|
"</text--->"
|
|
"<text>Fills up the definition of mpoint 'M', during the "
|
|
"interval defined by starting instant 'S' and ending instant 'E', having "
|
|
"closedness as specified by LC (leftclosed) and RC (rightclosed). "
|
|
"The mpoint will not be trimmed to the interval. "
|
|
"Gaps are filled using the last known position. For "
|
|
"periods before M's initial instant, M's initial position is used. "
|
|
"If M is empty, the result will be empty, too. An invalid interval "
|
|
"specification will produce an empty/undefined result. If 'CONN' = TRUE, "
|
|
"temporal gaps will be filled units connecting even the spatial positions."
|
|
"</text--->"
|
|
"<text>query trains feed extract[Trip] sim_fillup_mpoint[six30 - "
|
|
"create_duration(-0.05), six30 - create_duration(0.5), TRUE, FALSE, FALSE]"
|
|
"</text--->"
|
|
") )";
|
|
|
|
Operator sim_fillup_mpoint(
|
|
"sim_fillup_mpoint",
|
|
sim_fillup_mpoint_Spec,
|
|
sim_fillup_mpoint_VM,
|
|
Operator::SimpleSelect,
|
|
sim_fillup_mpoint_TM) ;
|
|
|
|
|
|
/*
|
|
5.6 Operator ~sim\_trips~
|
|
|
|
Creates a stream of mpoints from a single mpoint by splitting it into single
|
|
trips. Endings of trips are identified by constant values for longer than a
|
|
given duration. Or by definition time gaps of any duration.
|
|
|
|
Undefined periods will be suppressed, but defined periods of constant value
|
|
will result in separate trips, if their duration is longer than the given
|
|
minimum pause duration.
|
|
|
|
Units are defined as stationary, if
|
|
(i) their start and end point are AlmostEqual, or
|
|
(ii) their starting and ending instant are identical, or
|
|
(iii) their velocity is below ~minVelocity~
|
|
|
|
Parameter ~minVelocity~ can be passed as an optional third argument. The unit is
|
|
m/h. It has a default value of
|
|
1.0 m/d (=0.04167 m/h = 0.6944 mm/min = 0.01157 mm/s)
|
|
|
|
----
|
|
sim_trips: (mpoint x duration ) --> (stream mpoint)
|
|
sim_trips: (mpoint x duration x real [x geoid]) --> (stream mpoint)
|
|
|
|
----
|
|
|
|
*/
|
|
|
|
ListExpr sim_trips_TM ( ListExpr args )
|
|
{
|
|
int noargs = nl->ListLength( args );
|
|
string errmsg = "Expected (mpoint x duration [x real [x geoid]]).";
|
|
if((noargs < 2) || (noargs >4)){
|
|
return listutils::typeError(errmsg);
|
|
}
|
|
if( !MPoint::checkType(nl->First(args))
|
|
|| !Duration::checkType(nl->Second(args))){
|
|
return listutils::typeError(errmsg);
|
|
}
|
|
|
|
if((noargs>2) && (!CcReal::checkType(nl->Third(args)))){
|
|
return listutils::typeError(errmsg);
|
|
}
|
|
if((noargs==4) && (!Geoid::checkType(nl->Fourth(args)))){
|
|
return listutils::typeError(errmsg);
|
|
}
|
|
return nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->SymbolAtom(MPoint::BasicType()));
|
|
}
|
|
|
|
/*
|
|
~IsAlmostStationaryPoint~
|
|
|
|
This function checks whether the UPoint u is static
|
|
(equal start and end point or a single instant unit) or moves mith a speed
|
|
of less than ~minVelocity~. If the geoid is given (not null), the speed
|
|
is measured in meters per day otherwise the speed is units per day where
|
|
units depends on the coordinates.
|
|
|
|
*/
|
|
|
|
bool IsAlmostStationaryUPoint(const UPoint u, const double minVelocity,
|
|
const Geoid* geoid, bool &ok)
|
|
{
|
|
ok = true; // return parameter becomes false, iff invalid coordinates are used
|
|
if( !u.IsDefined() ){
|
|
assert (false);
|
|
return false;
|
|
}
|
|
if (AlmostEqual(u.p0,u.p1) || (u.timeInterval.start == u.timeInterval.end) ){
|
|
return true;
|
|
}
|
|
|
|
double ds = 0.0;
|
|
if(geoid){ // geographic coordinates
|
|
ds = u.p0.DistanceOrthodrome(u.p1,*geoid,ok);
|
|
if(!ok) {
|
|
return false;
|
|
}
|
|
} else { //euclidean coordinate
|
|
ds = u.p0.Distance(u.p1);
|
|
}
|
|
double dt = (u.timeInterval.end - u.timeInterval.start).ToDouble();
|
|
if (ds/dt < minVelocity)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
struct SplitMpointLocalInfo
|
|
{
|
|
SplitMpointLocalInfo():
|
|
pos( 0 ), size( 0 ), finished( true ), u1 ( UPoint(false) ), geoid( 0 )
|
|
{}
|
|
|
|
int pos; // unit counter
|
|
int size; // number of units
|
|
int trip; // number of current trip
|
|
bool finished; // whether we are finished or not
|
|
double minVelocity;
|
|
UPoint u1;
|
|
Geoid* geoid;
|
|
};
|
|
|
|
|
|
|
|
struct Sequence{
|
|
Sequence(): isStatic(false), pos1(0), pos2(0),
|
|
start(datetime::instanttype),
|
|
end(datetime::instanttype),
|
|
endsWithGap(false){}
|
|
Sequence(const Sequence& s):
|
|
isStatic(s.isStatic),
|
|
pos1(s.pos1), pos2(s.pos2),
|
|
start(s.start), end(s.end),
|
|
endsWithGap(s.endsWithGap) {}
|
|
|
|
~Sequence() {}
|
|
|
|
Sequence& operator=(const Sequence& s){
|
|
isStatic = s.isStatic;
|
|
pos1 = s.pos1;
|
|
pos2 = s.pos2;
|
|
start = s.start;
|
|
end = s.end;
|
|
endsWithGap = s.endsWithGap;
|
|
return *this;
|
|
}
|
|
|
|
bool isStatic;
|
|
int pos1;
|
|
int pos2;
|
|
DateTime start;
|
|
DateTime end;
|
|
bool endsWithGap;
|
|
};
|
|
|
|
ostream& operator<<(ostream& os, const Sequence& s){
|
|
os << "(" << (s.isStatic?"static":"moving") << ", " << s.pos1
|
|
<< " - " << s.pos2 << ", " << s.start << " , " << s.end << " , "
|
|
<< (s.end-s.start) << ", "
|
|
<< (s.endsWithGap?"gap":"con");
|
|
return os;
|
|
}
|
|
|
|
|
|
class SimTripsInfo{
|
|
public:
|
|
SimTripsInfo(const MPoint* mp, const DateTime* dur,
|
|
const double _minVel, const Geoid* geo):
|
|
source(mp), duration(dur), minVel(_minVel), geoid(geo),
|
|
pos(0),move(0), pause(0),pausedur(datetime::durationtype),
|
|
end(datetime::instanttype), rc(false) {
|
|
assert(mp->IsDefined());
|
|
assert(dur->IsDefined());
|
|
if(geo){
|
|
assert(geo->IsDefined());
|
|
}
|
|
}
|
|
|
|
MPoint* nextMPoint(){
|
|
|
|
appendUnits();
|
|
if(move){
|
|
MPoint* res = move;
|
|
move = 0;
|
|
res->EndBulkLoad(false,false);
|
|
return res;
|
|
}
|
|
MPoint* res = pause;
|
|
|
|
pause = 0;
|
|
if(res){
|
|
res->EndBulkLoad(false,false);
|
|
}
|
|
pausedur.SetToZero();
|
|
return res;
|
|
}
|
|
|
|
|
|
private:
|
|
const MPoint* source; // the mpoint to split
|
|
const DateTime* duration; // the minimum duration
|
|
double minVel; // minimum velocity for "static" unit
|
|
const Geoid* geoid; // geoid for computing "static" for a unit
|
|
int pos; // current position in source
|
|
MPoint* move; // last moving units
|
|
MPoint* pause; // last static units
|
|
DateTime pausedur; // duration of pauseA
|
|
DateTime end; // end of the last appended unit
|
|
bool rc; // rightclosed of the last appened unit
|
|
|
|
|
|
void appendPauseToMove(){
|
|
pausedur.SetToZero();
|
|
if(pause){
|
|
if(!move){
|
|
move = pause;
|
|
pause = 0;
|
|
return;
|
|
}
|
|
UPoint up;
|
|
for(int i=0;i<pause->GetNoComponents();i++){
|
|
pause->Get(i,up);
|
|
move->MergeAdd(up);
|
|
}
|
|
delete pause;
|
|
pause = 0;
|
|
}
|
|
}
|
|
|
|
void appendUnits(){
|
|
while(pos < source->GetNoComponents()){
|
|
UPoint up;
|
|
source->Get(pos,up);
|
|
bool ok;
|
|
if(pause!=0 || move!=0){
|
|
if( (up.timeInterval.start > end) ||
|
|
((up.timeInterval.start == end) && !rc && !up.timeInterval.lc)){
|
|
// found definition gap
|
|
if(move != 0 && (pausedur< *duration)){
|
|
appendPauseToMove();
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
bool isStatic = IsAlmostStationaryUPoint(up,minVel, geoid, ok);
|
|
|
|
if(isStatic){
|
|
appendToPause(up);
|
|
pos++;
|
|
} else {
|
|
if(pause && (pausedur >= *duration)){ // ensure to return pause
|
|
return;
|
|
}
|
|
if(pause){
|
|
appendPauseToMove();
|
|
}
|
|
appendToMove(up);
|
|
pos++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void appendToPause(UPoint& up){
|
|
if(!pause){
|
|
pause = new MPoint(16);
|
|
pause->StartBulkLoad();
|
|
}
|
|
pause->MergeAdd(up);
|
|
pausedur += (up.timeInterval.end - up.timeInterval.start);
|
|
end = up.timeInterval.end;
|
|
rc = up.timeInterval.rc;
|
|
}
|
|
void appendToMove(UPoint& up){
|
|
if(!move){
|
|
move = new MPoint(16);
|
|
move->StartBulkLoad();
|
|
}
|
|
move->MergeAdd(up);
|
|
end = up.timeInterval.end;
|
|
rc = up.timeInterval.rc;
|
|
}
|
|
};
|
|
|
|
|
|
|
|
int sim_trips_VM ( Word* args, Word& result,
|
|
int message, Word& local, Supplier s )
|
|
{
|
|
SimTripsInfo* li = (SimTripsInfo*) local.addr;
|
|
switch(message){
|
|
case OPEN : {
|
|
if(li){
|
|
delete li;
|
|
li=0;
|
|
local.addr = 0;
|
|
}
|
|
MPoint* mp = (MPoint*) args[0].addr;
|
|
DateTime* dur = (DateTime*) args[1].addr;
|
|
if(!mp->IsDefined() || !dur->IsDefined()){
|
|
return 0;
|
|
}
|
|
CcReal minVel(true,1.0/24.0);
|
|
Geoid* geoid = 0;
|
|
int sons = qp->GetNoSons(s);
|
|
if(sons>2){ // minVel is present
|
|
CcReal* minVelArg = (CcReal*) args[2].addr;
|
|
if(!minVelArg->IsDefined()){
|
|
return 0;
|
|
}
|
|
minVel = (*minVelArg);
|
|
}
|
|
if(sons>3){ // Geoid is present
|
|
Geoid* geoidarg = (Geoid*) args[3].addr;
|
|
if(!geoidarg->IsDefined()){
|
|
return 0;
|
|
}
|
|
geoid = geoidarg;
|
|
}
|
|
local.addr = new SimTripsInfo(mp,dur,
|
|
minVel.GetValue()*24,geoid);
|
|
return 0;
|
|
}
|
|
case REQUEST: { result.addr = li?li->nextMPoint():0;
|
|
return result.addr?YIELD:CANCEL;
|
|
}
|
|
case CLOSE: {
|
|
if(li){
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
return -1; // should never be reached
|
|
|
|
}
|
|
|
|
|
|
int sim_trips_VM_old ( Word* args, Word& result,
|
|
int message, Word& local, Supplier s )
|
|
{
|
|
SplitMpointLocalInfo *sli;
|
|
MPoint *mpoint = (MPoint*)(args[0].addr);
|
|
DateTime *mindur = (DateTime*)(args[1].addr);
|
|
result = qp->ResultStorage( s );
|
|
MPoint *res = 0;
|
|
bool newtrip = false;
|
|
bool ok = true;
|
|
|
|
switch (message)
|
|
{
|
|
case OPEN :
|
|
|
|
// cout << "sim_trips_VM received OPEN" << endl;
|
|
sli = new SplitMpointLocalInfo;
|
|
sli->pos = 0;
|
|
sli->trip = 0;
|
|
sli->minVelocity = 1.0; // default value for minimum velocity
|
|
|
|
if( (qp->GetNoSons(s)==3) || (qp->GetNoSons(s)==4) )
|
|
{
|
|
CcReal* mv = (CcReal*)args[2].addr;
|
|
if(!mv->IsDefined())
|
|
{ // undefined optional argument -> return empty stream
|
|
sli->finished = true;
|
|
sli->u1 = UPoint(false);
|
|
return 0;
|
|
}
|
|
sli->minVelocity = mv->GetRealval() * 24.0;
|
|
|
|
if(qp->GetNoSons(s)==4) {
|
|
sli->geoid = static_cast<Geoid*>(args[3].addr);
|
|
if(!sli->geoid->IsDefined()){
|
|
sli->minVelocity = 0;
|
|
sli->finished = true;
|
|
sli->u1 = UPoint(false);
|
|
return 0;
|
|
}
|
|
}
|
|
if(sli->minVelocity < 0.0)
|
|
{ // negative minimal velocity -> return empty stream
|
|
sli->minVelocity = 0;
|
|
sli->finished = true;
|
|
sli->u1 = UPoint(false);
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{ // no optional argument
|
|
sli->minVelocity = 1.0;
|
|
}
|
|
local.setAddr(sli);
|
|
|
|
if ( !mpoint->IsDefined() ||
|
|
mpoint->IsEmpty() ||
|
|
!mindur->IsDefined() ||
|
|
mindur->GetType() != durationtype ||
|
|
*mindur <= DateTime(0,0,durationtype)
|
|
)
|
|
{ // argument undefined or invalid
|
|
// -> return empty stream
|
|
sli->finished = true;
|
|
sli->u1 = UPoint(false);
|
|
return 0;
|
|
}
|
|
sli->size = mpoint->GetNoComponents();
|
|
sli->finished = false;
|
|
return 0;
|
|
|
|
case REQUEST :
|
|
|
|
// cout << "sim_trips_VM received REQUEST" << endl;
|
|
|
|
if (local.addr == 0)
|
|
{
|
|
// cout << "We have already finished!" << endl;
|
|
result.setAddr(0);
|
|
return CANCEL;
|
|
}
|
|
sli = (SplitMpointLocalInfo*) local.addr;
|
|
if ( sli->finished )
|
|
{
|
|
// cout << "We have already finished!" << endl;
|
|
result.setAddr(0);
|
|
return CANCEL;
|
|
}
|
|
|
|
if ( sli->pos >= sli->size )
|
|
{
|
|
if ( sli->pos == sli->size && sli->u1.IsDefined() )
|
|
{ // special case: last unit of the mpoint is stationary and
|
|
// was scheduled to form an own trip
|
|
sli->trip++;
|
|
res = new MPoint(0);
|
|
res->Clear();
|
|
res->StartBulkLoad();
|
|
// cout << " Starting New Trip #" << sli->trip << ":" << endl;
|
|
// cout << " => Finished. Final single unit trip" << endl;
|
|
// cout << " Adding (0)"; sli->u1.Print(cout); cout << endl;
|
|
res->MergeAdd( sli->u1 );
|
|
res->EndBulkLoad( false, true ); // do not sort units
|
|
// cout << " Finished Trip " << sli->trip << "." << endl;
|
|
assert( res->IsValid() ); // XRIS: only for debugging
|
|
result.setAddr( res );
|
|
sli->u1.SetDefined( false );
|
|
sli->finished = true;
|
|
return YIELD;
|
|
}
|
|
else
|
|
{ // We have just finished the complete mpoint
|
|
// cout << "We have already finished!" << endl;
|
|
sli->finished = true;
|
|
result.setAddr(0);
|
|
return CANCEL;
|
|
}
|
|
}
|
|
|
|
// else: regular case
|
|
newtrip = false;
|
|
sli->trip++;
|
|
res = new MPoint(0);
|
|
res->Clear();
|
|
res->StartBulkLoad();
|
|
// cout << " Starting Trip " << sli->trip << ":" << endl;
|
|
|
|
while( sli->pos < sli->size && !newtrip)
|
|
{
|
|
// cout << "pos/size = " << sli->pos << "/" << sli->size << endl;
|
|
UPoint u2(true);
|
|
mpoint->Get(sli->pos++, u2);
|
|
// cout << endl;
|
|
// cout << " u1 = "; sli->u1.Print(cout); cout << endl;
|
|
// cout << " u2 = "; u2.Print(cout); cout << endl;
|
|
assert( u2.IsDefined() );
|
|
if ( !sli->u1.IsDefined() )
|
|
{ // sli->u1 is undefined
|
|
// This means we just started to process mpoint
|
|
// Do nothing, but move u2 to u1 for next iteration
|
|
sli->u1 = u2;
|
|
}
|
|
else // ELSE: Inside a running trip
|
|
if( sli->u1.timeInterval.end < u2.timeInterval.start ||
|
|
( (sli->u1.timeInterval.end == u2.timeInterval.start) &&
|
|
!sli->u1.timeInterval.rc &&
|
|
!u2.timeInterval.lc
|
|
)
|
|
)
|
|
{ // found GAP between sli->u1 and u2
|
|
// cout << " => Gap between u1, u2." << endl;
|
|
// cout << " Adding (1)"; sli->u1.Print(cout); cout << endl;
|
|
res->MergeAdd(sli->u1);
|
|
sli->u1 = u2;
|
|
newtrip = true;
|
|
}
|
|
else // ELSE: No Gap --- consecutive units
|
|
{
|
|
if ( IsAlmostStationaryUPoint(sli->u1, sli->minVelocity,
|
|
sli->geoid, ok) )
|
|
// if ( AlmostEqual(sli->u1.p0, sli->u1.p1) )
|
|
{ // sli->u1 is constant
|
|
if(!ok){
|
|
MessageCenter* msg = MessageCenter::GetInstance();
|
|
string msgstr = "Warning: invalid geografic coordinate found!";
|
|
msg->Send(nl, listutils::simpleMessage(msgstr));
|
|
sli->finished = true;
|
|
result.setAddr(0);
|
|
return CANCEL;
|
|
}
|
|
// if ( AlmostEqual(u2.p0, u2.p1) )
|
|
if ( IsAlmostStationaryUPoint(u2, sli->minVelocity, sli->geoid, ok))
|
|
{ // sli->u1 is constant and u2 is constant
|
|
if(!ok){
|
|
MessageCenter* msg = MessageCenter::GetInstance();
|
|
string msgstr = "Warning: invalid geografic coordinate found!";
|
|
msg->Send(nl, listutils::simpleMessage(msgstr));
|
|
sli->finished = true;
|
|
result.setAddr(0);
|
|
return CANCEL;
|
|
}
|
|
|
|
if ( AlmostEqual(sli->u1.p1, u2.p0) )
|
|
// if ( AlmostEqual(sli->u1.p0, u2.p0) )
|
|
{ // sli->u1 and u2 are constant AND equalvalue
|
|
// extend u1 by u2
|
|
sli->u1.timeInterval.end = u2.timeInterval.end;
|
|
sli->u1.timeInterval.rc = u2.timeInterval.rc;
|
|
sli->u1.p1 = u2.p1;
|
|
if ( (sli->u1.timeInterval.end - sli->u1.timeInterval.start)
|
|
>= *mindur )
|
|
{ // concatenation sli->u1+u2 is long enough
|
|
if(res->GetNoComponents() == 0)
|
|
{ // this is a new trip. We can use it for the pause.
|
|
// We do not need re-visit current unit u2
|
|
// cout << " => merged u1, u2. Immediate Pause." << endl;
|
|
// cout << " Adding (2)"; sli->u1.Print(cout); cout << endl;
|
|
res->MergeAdd( sli->u1 );
|
|
newtrip = true;
|
|
}
|
|
else
|
|
{ // this trip was already used. We need to close it and
|
|
// create a new trip.
|
|
// We do not need re-visit current unit u2
|
|
// cout << " => merged u1, u2. Deferred Pause." << endl;
|
|
newtrip = true;
|
|
}
|
|
}
|
|
else
|
|
{ // extended u1 is not long enough for a pause.
|
|
// still do not add anything (u1 might be needed to extended
|
|
// further)
|
|
// cout << " => merged u1, u2. No pause yet." << endl;
|
|
}
|
|
}
|
|
else // sli->u1 and u2 are constant BUT have different values
|
|
{
|
|
if ( (sli->u1.timeInterval.end - sli->u1.timeInterval.start)
|
|
>= *mindur )
|
|
{ // sli->u1 is long enough to form a separate pause trip;
|
|
// u1 needs to form a separate trip.
|
|
if(res->GetNoComponents() == 0)
|
|
{ // the current trip is empty, so we can use it for u1
|
|
// cout << " => Immediate Pause u1." << endl;
|
|
// cout << " Adding (3)"; sli->u1.Print(cout); cout << endl;
|
|
res->MergeAdd( sli->u1 );
|
|
sli->u1 = u2;
|
|
newtrip = true;
|
|
}
|
|
else
|
|
{ // The current trip was already used. We need to close it
|
|
// and start a new one for u1.
|
|
// cout << " => Deferred Pause u1. Revisit u2" << endl;
|
|
sli->pos--; // re-visit u2
|
|
newtrip = true;
|
|
}
|
|
}
|
|
else
|
|
{ // sli->u1 is not long enough for a pause.
|
|
// cout << " => No pause u1." << endl;
|
|
// cout << " Adding (4)"; sli->u1.Print(cout); cout << endl;
|
|
res->MergeAdd( sli->u1 );
|
|
sli->u1 = u2;
|
|
}
|
|
}
|
|
}
|
|
else // sli->u1 is constant, u2 is nonconstant
|
|
{
|
|
if(!ok){
|
|
MessageCenter* msg = MessageCenter::GetInstance();
|
|
string msgstr = "Warning: invalid geografic coordinate found!";
|
|
msg->Send(nl, listutils::simpleMessage(msgstr));
|
|
sli->finished = true;
|
|
result.setAddr(0);
|
|
return CANCEL;
|
|
}
|
|
|
|
if ( (sli->u1.timeInterval.end - sli->u1.timeInterval.start )
|
|
>= *mindur )
|
|
{ // u1 is a pause.
|
|
if(res->GetNoComponents() == 0)
|
|
{ // the current trip is empty, so we can use it for u1
|
|
// cout << " => Immediate Pause u1" << endl;
|
|
// cout << " Adding (5)"; sli->u1.Print(cout); cout << endl;
|
|
res->MergeAdd( sli->u1 );
|
|
sli->u1 = u2;
|
|
newtrip = true;
|
|
}
|
|
else
|
|
{ // The current trip was already used. We need to close it
|
|
// and start a new one for u1.
|
|
// cout << " => Deferred Pause u1, revisit u2" << endl;
|
|
sli->pos--; // re-visit current unit u2
|
|
newtrip = true;
|
|
}
|
|
}
|
|
else
|
|
{ // u1 is not a pause
|
|
// cout << " => Continue u1, u2." << endl;
|
|
// cout << " Adding (6)"; sli->u1.Print(cout); cout << endl;
|
|
res->MergeAdd( sli->u1 );
|
|
sli->u1 = u2;
|
|
}
|
|
}
|
|
} // end sli->u1 is constant
|
|
else // sli->u1 is nonconstant
|
|
{
|
|
if(!ok){
|
|
MessageCenter* msg = MessageCenter::GetInstance();
|
|
string msgstr = "Warning: invalid geografic coordinate found!";
|
|
msg->Send(nl, listutils::simpleMessage(msgstr));
|
|
sli->finished = true;
|
|
result.setAddr(0);
|
|
return CANCEL;
|
|
}
|
|
if ( IsAlmostStationaryUPoint(u2, sli->minVelocity, sli->geoid, ok))
|
|
// if (AlmostEqual(u2.p0, u2.p1))
|
|
{ // sli->u1 is nonconstant and u2 is constant
|
|
// Add u1 to current trip.
|
|
// cout << " => Continue u1." << endl;
|
|
// cout << " Adding (7)"; sli->u1.Print(cout); cout << endl;
|
|
if(!ok){
|
|
MessageCenter* msg = MessageCenter::GetInstance();
|
|
string msgstr = "Warning: invalid geografic coordinate found!";
|
|
msg->Send(nl, listutils::simpleMessage(msgstr));
|
|
sli->finished = true;
|
|
result.setAddr(0);
|
|
return CANCEL;
|
|
}
|
|
|
|
res->MergeAdd( sli->u1 );
|
|
sli->u1 = u2;
|
|
if ( (u2.timeInterval.end - u2.timeInterval.start ) >= *mindur )
|
|
{ // start a new trip for current unit u2
|
|
// cout << " => Deferred Pause u2. No revisit." << endl;
|
|
newtrip = true;
|
|
}
|
|
else
|
|
{
|
|
// cout << " => Continue u2." << endl;
|
|
}
|
|
}
|
|
else
|
|
{ // sli->u1 and u2 are nonconstant
|
|
// cout << " => Continue u1, u2." << endl;
|
|
// cout << " Adding (8)"; sli->u1.Print(cout); cout << endl;
|
|
if(!ok){
|
|
MessageCenter* msg = MessageCenter::GetInstance();
|
|
string msgstr = "Warning: invalid geografic coordinate found!";
|
|
msg->Send(nl, listutils::simpleMessage(msgstr));
|
|
sli->finished = true;
|
|
result.setAddr(0);
|
|
return CANCEL;
|
|
}
|
|
|
|
res->MergeAdd( sli->u1 );
|
|
sli->u1 = u2;
|
|
}
|
|
}
|
|
} // end No Gap --- consecutive unit
|
|
} // end while( sli->pos < sli->size && !newtrip )
|
|
if ( !newtrip && sli->u1.IsDefined() )
|
|
{ // insert the final unit
|
|
// cout << " => Global final unit append." << endl;
|
|
// cout << " Adding Final (9)"; sli->u1.Print(cout); cout << endl;
|
|
res->MergeAdd( sli->u1 );
|
|
sli->u1.SetDefined( false ); // invalidate unit (for additional safety)
|
|
sli->finished = true; // we have finished
|
|
}
|
|
res->EndBulkLoad( false, true ); // do not sort units
|
|
// cout << " Finished Trip #" << sli->trip << "." << endl;
|
|
result.setAddr( res );
|
|
// cout << endl
|
|
// << "===================================================" << endl;
|
|
return YIELD;
|
|
|
|
case CLOSE :
|
|
|
|
// cout << "sim_trips_VM received CLOSE" << endl;
|
|
if (local.addr != 0)
|
|
{
|
|
sli = (SplitMpointLocalInfo*) local.addr;
|
|
delete sli;
|
|
sli = 0;
|
|
local.setAddr(0);
|
|
}
|
|
return 0;
|
|
|
|
} // end switch
|
|
return 0; // should not be reached
|
|
}
|
|
|
|
const string sim_trips_Spec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )"
|
|
"( <text> mpoint x duration [ x real [ x geoid ] ] "
|
|
"-> stream(mpoint)</text--->"
|
|
"<text>M sim_trips[ D ], "
|
|
"M sim_trips[ D , Vmin [, Geoid] ]</text--->"
|
|
"<text>Splits a single mpoint 'M' into a stream of mpoints representing"
|
|
"single 'trips'. Endings of trips are recognized by 1) stationary "
|
|
"intervals with a duration of at least 'D', and 2) enclosed undefined "
|
|
"intervals of any length. A unit is considered stationary, if "
|
|
"(i) its starting and ending positions are equal, or "
|
|
"(ii) its starting and ending instants are identical, or "
|
|
"(iii) its velocity is smaller than stated by the (optional) parameter "
|
|
"'Vmin' (given in unit [m/h]). If 'Vmin' is omitted, a standart value "
|
|
"of 0.041667 m/h (corresponding to 1.0 m/d) is applied. "
|
|
"Stationary intervals are interpreted as "
|
|
"'pauses' and will be returned as separate trips. For definition gaps, "
|
|
"no Trip will be created. The parameter 'D' must be "
|
|
"positive ( > create_duration(0) ), 'Vmin' must be non-negative. If the "
|
|
"optional last parameter Geoid is used, geografic (LON,LAT) coordinates "
|
|
"are used, otherwise euclidean (Easting,Northing) coordinates are "
|
|
"processed.</text--->"
|
|
"<text>query train7 sim_trips[create_duration(0,1000)] count"
|
|
"</text--->"
|
|
") )";
|
|
|
|
Operator sim_trips(
|
|
"sim_trips",
|
|
sim_trips_Spec,
|
|
sim_trips_VM,
|
|
Operator::SimpleSelect,
|
|
sim_trips_TM) ;
|
|
|
|
/*
|
|
6 Class ~SimulationAlgebra~
|
|
|
|
The last steps in adding an algebra to the Secondo system are
|
|
|
|
* Associating value mapping functions with their operators
|
|
|
|
* ``Bunching'' all
|
|
type constructors and operators in one instance of class ~Algebra~.
|
|
|
|
Therefore, a new subclass ~SimulationAlgebra~ of class ~Algebra~ is
|
|
declared. The only
|
|
specialization with respect to class ~Algebra~ takes place within the
|
|
constructor: all type constructors and operators are registered at the actual
|
|
algebra.
|
|
|
|
After declaring the new class, its only instance ~simulationAlgebra~ is defined.
|
|
|
|
*/
|
|
|
|
|
|
class SimulationAlgebra : public Algebra
|
|
{
|
|
public:
|
|
SimulationAlgebra() : Algebra()
|
|
{
|
|
AddOperator( &sim_set_rng );
|
|
AddOperator( &sim_set_event_params );
|
|
AddOperator( &sim_set_dest_params );
|
|
AddOperator( &sim_create_trip );
|
|
AddOperator( &sim_print_params );
|
|
AddOperator( &sim_fillup_mpoint );
|
|
AddOperator( &sim_trips );
|
|
}
|
|
~SimulationAlgebra() {};
|
|
|
|
private:
|
|
};
|
|
|
|
} // end of namespace temporalalgebra
|
|
|
|
|
|
/*
|
|
7 Initialization
|
|
|
|
Each algebra module needs an initialization function. The algebra manager
|
|
has a reference to this function if this algebra is included in the list
|
|
of required algebras, thus forcing the linker to include this module.
|
|
|
|
The algebra manager invokes this function to get a reference to the instance
|
|
of the algebra class and to provide references to the global nested list
|
|
container (used to store constructor, type, operator and object information)
|
|
and to the query processor.
|
|
|
|
The function has a C interface to make it possible to load the algebra
|
|
dynamically at runtime.
|
|
|
|
*/
|
|
|
|
extern "C"
|
|
Algebra*
|
|
InitializeSimulationAlgebra( NestedList* nlRef, QueryProcessor* qpRef )
|
|
{
|
|
nl = nlRef;
|
|
qp = qpRef;
|
|
return (new temporalalgebra::SimulationAlgebra());
|
|
}
|