Files
secondo/Algebras/MTopRel/MTopRelAlgs.h
2026-01-23 17:03:45 +08:00

1667 lines
45 KiB
C++

/*
----
This file is part of SECONDO.
Copyright (C) 2011,
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
----
*/
#include <vector>
#include <queue>
#include "TopRel.h"
#include "Algebras/Temporal/TemporalAlgebra.h"
#include "Algebras/Spatial/SpatialAlgebra.h"
#include "Algebras/Temporal/RefinementStream.h"
namespace temporalalgebra{
/*
0 Declaration of auxiliary functions;
*/
/*
0.1 ~mergeAdd~
Appends a new element to a container. If possible, the last element of the
container is extened instead of appending a new element. We can merge two
pairs, if the interval of the second pair extends the interval of the first
one and the second components of both pairs are equal.
*/
void mergeAdd(std::vector<std::pair<Interval<Instant>, toprel::Int9M> >& vec,
const std::pair<Interval<Instant>, toprel::Int9M>& elem);
void mergeAdd(std::queue<std::pair<Interval<Instant>, toprel::Int9M> >& q,
const std::pair<Interval<Instant>, toprel::Int9M>& elem);
void mergeAdd(std::vector<std::pair<Interval<Instant>, toprel::Cluster> >& vec,
const std::pair<Interval<Instant>, toprel::Cluster> & elem);
void mergeAdd(std::queue<std::pair<Interval<Instant>, toprel::Cluster> >& q,
const std::pair<Interval<Instant>, toprel::Cluster> & elem);
/*
0.2 computeInstant
Computes the instant when the up is on the point defined by (x,y).
Note that there is no check, whether this point is actually reached.
In this case, the instant may be outside the time interval of the
upoint.
*/
Instant computeInstant(const UPoint& up, const double x, const double y);
/*
0.3 selectNext
returns the segment with the smallest x value from reg (unit at posreg)
qreg, and qup. The segment is removed from the corresponding container
(for the region, just the position counter is increased).
*/
avlseg::ownertype SelectNext(
const Region& reg,
int& posreg,
std::priority_queue<avlseg::ExtendedHalfSegment,
std::vector<avlseg::ExtendedHalfSegment>,
std::greater<avlseg::ExtendedHalfSegment> >& qreg,
std::priority_queue<avlseg::ExtendedHalfSegment,
std::vector<avlseg::ExtendedHalfSegment>,
std::greater<avlseg::ExtendedHalfSegment> >& qup,
avlseg::ExtendedHalfSegment& result );
/*
0.4 ~pcompare~
Checks whther the first component of the firt pair is smaller than
the first component of the second pair;
*/
bool pCompare (const std::pair<Interval<Instant>, toprel::Int9M>& p1,
const std::pair<Interval<Instant>, toprel::Int9M>& p2);
/*
0.5 ~computeInterval~
Computes the interval when the upoint is at the given segment.
*/
Interval<Instant> computeInterval(const UPoint& up,
const avlseg::AVLSegment& seg);
/*
1 Computing topological relationship between a static point and unit(point)
The complete result ist computed within the constructor. Methods
allow to iterate over the result.
*/
template<bool sym>
class MTopRelAlg_PUP_T {
public:
/*
1.1 Constructors
*/
MTopRelAlg_PUP_T(const Point* p, const UPoint* up);
MTopRelAlg_PUP_T(const Point* p, const UPoint* up,
const toprel::PredicateGroup* pg);
/*
1.2 hasNext
Checks whether more topological relationships are available.
*/
bool hasNext() const;
/*
1.3 next
Precondition: hasNext()
Returns the next element of the result. The result consists of a time interval
and the corresponding topological relationship between the time interval.
*/
std::pair<Interval<Instant>, toprel::Int9M> next();
/*
1.4 hasNextCluster
Checks whether at least one more cluster is available in the result.
*/
bool hasNextCluster() const;
/*
1.5 nextCluster
Precondition: hasNextCluster
Returns the next cluster with its corresponding time interval.
*/
std::pair<Interval<Instant>, toprel::Cluster> nextCluster();
private:
std::vector<std::pair<Interval<Instant>, toprel::Int9M> > toprels;
std::vector<std::pair<Interval<Instant>, toprel::Cluster> >clusters;
unsigned int currentIndexInt9M;
unsigned int currentIndexCluster;
void init( const Point* p, const UPoint* up,
const toprel::PredicateGroup* pg);
};
/*
1.2 Implementation
*/
/*
1.1 Constructors
*/
template<bool sym>
MTopRelAlg_PUP_T<sym>::MTopRelAlg_PUP_T(const Point* p,
const UPoint* up):
currentIndexInt9M(0), currentIndexCluster(0){
init(p, up, 0);
}
template<bool sym>
MTopRelAlg_PUP_T<sym>::MTopRelAlg_PUP_T(const Point* p, const UPoint* up,
const toprel::PredicateGroup* pg){
init(p,up,pg);
}
/*
1.2 hasNext
Checks whether more topological relationships are available.
*/
template<bool sym>
bool MTopRelAlg_PUP_T<sym>::hasNext() const{
return currentIndexInt9M < toprels.size();
}
/*
1.3 next
Precondition: hasNext()
Returns the next element of the result. The result consists of a time interval
and the corresponding topological relationship between the time interval.
*/
template<bool sym>
std::pair<Interval<Instant>, toprel::Int9M> MTopRelAlg_PUP_T<sym>::next(){
assert(hasNext());
currentIndexInt9M++;
return toprels[currentIndexInt9M-1];
}
/*
1.4 hasNextCluster
Checks whether at least one more cluster is available in the result.
*/
template<bool sym>
bool MTopRelAlg_PUP_T<sym>::hasNextCluster() const{
return currentIndexCluster < clusters.size();
}
/*
1.5 nextCluster
Precondition: hasNextCluster
Returns the next cluster with its corresponding time interval.
*/
template<bool sym>
std::pair<Interval<Instant>, toprel::Cluster>
MTopRelAlg_PUP_T<sym>::nextCluster(){
assert(hasNextCluster());
currentIndexCluster++;
return clusters[currentIndexCluster-1];
}
/*
1.6 init
This functions computes the result and stores it into the private members.
*/
template<bool sym>
void MTopRelAlg_PUP_T<sym>::init(const Point* p, const UPoint* up,
const toprel::PredicateGroup* pg){
toprels.clear();
clusters.clear();
currentIndexInt9M = 0;
currentIndexCluster = 0;
if(!p->IsDefined() || !up->IsDefined()){
return; // no result
}
// step 1: compute the 9 intersection matrices
toprel::Int9M m(0);
if(AlmostEqual(up->p0, up->p1)){
if(AlmostEqual(*p, up->p0)){
m.Set(1,0,0, 0,0,0, 0,0,1); // set to "equal"
} else {
m.Set(0,0,1, 0,0,0, 1,0,1); // set to "disjoint"
}
if(sym){
m.Transpose();
}
std::pair<Interval<Instant>, toprel::Int9M> r(up->timeInterval, m);
toprels.push_back(r);
} else { // nonstatic upoint
HalfSegment hs(true,up->p0, up->p1);
if(!hs.Contains(*p)){ // never on line
m.Set(0,0,1, 0,0,0, 1,0,1); // set to "disjoint"
if(sym){
m.Transpose();
}
std::pair<Interval<Instant>, toprel::Int9M> r(up->timeInterval, m);
toprels.push_back(r);
} else {
// compute the instant when the points are equal
double deltaX = up->p1.GetX() - up->p0.GetX();
double deltaY = up->p1.GetY() - up->p0.GetY();
double delta = deltaX>deltaY? (p->GetX() - up->p0.GetX()) / deltaX
: (p->GetY() - up->p0.GetY()) / deltaY;
datetime::DateTime dur(datetime::durationtype);
dur = up->timeInterval.end - up->timeInterval.start;
dur.Mul(delta);
datetime::DateTime in(datetime::instanttype);
in = up->timeInterval.start + dur;
std::vector<Interval<Instant> > v = up->timeInterval.splitAround(in);
for(unsigned int i=0; i < v.size(); i++){
Interval<Instant> ci = v[i];
if(ci.Contains(in)){
m.Set(1,0,0, 0,0,0, 0,0,1); // set to "equal"
} else {
m.Set(0,0,1, 0,0,0, 1,0,1);
}
if(sym){
m.Transpose();
}
std::pair<Interval<Instant>, toprel::Int9M> r(ci, m);
toprels.push_back(r);
}
}
}
// step 2: build the cluster vector from the int9m's
if(pg==0){
return;
}
if(!pg->IsDefined()){
return;
}
if(toprels.size()==0){
return;
}
std::pair<Interval<Instant>, toprel::Int9M> cpi = toprels[0];
toprel::Cluster* cl = pg->GetClusterOf(cpi.second);
std::pair<Interval<Instant>, toprel::Cluster> cpc(cpi.first, *cl);
delete cl;
for(unsigned int i=1; i< toprels.size(); i++){
std::pair<Interval<Instant>, toprel::Int9M> npi = toprels[i];
cl = pg->GetClusterOf(npi.second);
if(cpc.second == *cl){ // toprel within the same cluster,
//just enlarge the interval
cpc.first.end = npi.first.end;
cpc.first.rc = npi.first.rc;
} else {
clusters.push_back(cpc);
cpc.first = npi.first;
cpc.second = *cl;
}
delete cl;
}
clusters.push_back(cpc);
}
typedef MTopRelAlg_PUP_T<false> MTopRelAlg_PUP;
typedef MTopRelAlg_PUP_T<true> MTopRelAlg_UPP;
/*
2 Computing topological relationship between a static object and moving(object)
Note. This class stores a reference to a moving point given in the constructor
SO is the type of the static object
MO is the type of the moving object
UO is the unit type of MO
UP is the class for the unitprocessor processing SO and UO where UP is the
unit type of MO
*/
template<class SO, class MO, class UO, class UP>
class MTopRelAlg_SMO {
public:
/*
1.1 Constructors
*/
MTopRelAlg_SMO(const SO* _so, const MO* _mo):
currentUnitTopRel(), currentUnitCluster(), posTopRel(0),
posCluster(0), so(_so), mo(_mo), pg(0){
init();
}
MTopRelAlg_SMO(const SO* _so, const MO* _mo,
const toprel::PredicateGroup* _pg):
currentUnitTopRel(), currentUnitCluster(), posTopRel(0),
posCluster(0), so(_so), mo(_mo), pg(_pg){
init();
}
~MTopRelAlg_SMO() {}
/*
1.2 hasNext
Checks whether more topological relationships are available.
*/
bool hasNext() const{
return currentUnitTopRel.size() > 0;
}
/*
1.3 next
Precondition: hasNext()
Returns the next element of the result. The result consists of a time interval
and the corresponding topological relationship between the time interval.
*/
std::pair<Interval<Instant>, toprel::Int9M> next(){
assert(hasNext());
std::pair<Interval<Instant>, toprel::Int9M> result =
currentUnitTopRel.front();
currentUnitTopRel.pop();
computeNextTopRel();
return result;
}
/*
1.4 hasNextCluster
Checks whether at least one more cluster is available in the result.
*/
bool hasNextCluster() const{
return currentUnitCluster.size() > 0;
}
/*
1.5 nextCluster
Precondition: hasNextCluster
Returns the next cluster with its corresponding time interval.
*/
std::pair<Interval<Instant>, toprel::Cluster> nextCluster(){
assert(hasNextCluster());
std::pair<Interval<Instant>, toprel::Cluster> result =
currentUnitCluster.front();
currentUnitCluster.pop();
computeNextCluster();
return result;
}
private:
/*
1.6 Members
*/
std::queue<std::pair<Interval<Instant>, toprel::Int9M> > currentUnitTopRel;
std::queue<std::pair<Interval<Instant>,
toprel::Cluster> > currentUnitCluster;
int32_t posTopRel; // position in MO
int32_t posCluster; // position in MO
const SO* so; // the point
const MO* mo; // the mpoint
const toprel::PredicateGroup* pg; // used predicategroup
/*
1.7 Auxiliary functions
1.7.1 init
Checks parameters and fills the vectors with first values
*/
void init(){
if(so->IsDefined() && mo->IsDefined()){
computeNextTopRel();
if(pg && pg->IsDefined()){
computeNextCluster();
}
}
}
/*
1.7.2 canBeConnected
Checks whether i2 can be appended to i1.
*/
bool canBeConnected(const Interval<Instant>& i1,
const Interval<Instant>& i2) const{
return i1.end == i2.start;
}
/*
1.7.2 canBeConnected
Checks whether s can be appended to f. This is the case when the
corresponding intervals can be connected and the topologocal relationships
of s and f are equal.
*/
bool canBeConnected(const std::pair<Interval<Instant>, toprel::Int9M>& f,
const std::pair<Interval<Instant>, toprel::Int9M>& s) const{
return canBeConnected(f.first, s.first) && (f.second == s.second);
}
/*
1.7.3 connect
Appends s to f.
Precondition: canBeConnected(f,s).
*/
void connect(std::pair<Interval<Instant>, toprel::Int9M>& f,
const std::pair<Interval<Instant>, toprel::Int9M>& s){
assert(canBeConnected(f,s));
f.first.end = s.first.end;
f.first.rc = s.first.rc;
}
/*
1.7.4 computeNextTopRel
Processes the units of mo while mo has more elements and the
toprel vector contains less than 2 elements. We need at least two elements in
this vector to be sure that all connections are done before returning the
next top rel.
*/
void computeNextTopRel(){
if(currentUnitTopRel.size() > 1){ // we have already enough entries
return;
}
// make a first entry
if(currentUnitTopRel.empty()){
if(posTopRel >= mo->GetNoComponents()){
// no more units available
return;
}
UO uo(1);
mo->Get(posTopRel, uo);
posTopRel++;
UP up(so,&uo,pg); // create a unit processor
while(up.hasNext()){
currentUnitTopRel.push(up.next());
}
}
// extend the last entry while it is possible
// (elements available and makes sense (only 1 element)
assert(currentUnitTopRel.size()>0);
while( (currentUnitTopRel.size()<2) &&
(posTopRel < mo->GetNoComponents())){
UO uo(1);
mo->Get(posTopRel, uo);
posTopRel++;
UP up(so,&uo,pg);
while(up.hasNext()){
std::pair<Interval<Instant>, toprel::Int9M> n = up.next();
if(canBeConnected(currentUnitTopRel.back(), n)){
connect(currentUnitTopRel.back(), n);
} else {
currentUnitTopRel.push(n);
}
}
}
}
bool canBeConnected(
const std::pair<Interval<Instant>, toprel::Cluster>& f,
const std::pair<Interval<Instant>, toprel::Cluster>& s) const{
return canBeConnected(f.first, s.first) && (f.second == s.second);
}
void connect(std::pair<Interval<Instant>, toprel::Cluster>& f,
const std::pair<Interval<Instant>, toprel::Cluster>& s){
assert(canBeConnected(f,s));
f.first.end = s.first.end;
f.first.rc = s.first.rc;
}
void computeNextCluster(){
if(currentUnitCluster.size() > 1){ // enough elements
return;
}
// make a first entry
if(currentUnitCluster.empty()){
if(posCluster >= mo->GetNoComponents()){
// no more units available
return;
}
UO uo(1);
mo->Get(posCluster, uo);
posCluster++;
UP up(so,&uo,pg);
while(up.hasNextCluster()){
currentUnitCluster.push(up.nextCluster());
}
}
assert(currentUnitCluster.size()>0);
while( (currentUnitCluster.size()<2) &&
(posCluster < mo->GetNoComponents())){
UO uo(1);
mo->Get(posCluster, uo);
posCluster++;
UP up(so,&uo,pg);
while(up.hasNextCluster()){
std::pair<Interval<Instant>, toprel::Cluster> n
= up.nextCluster();
if(canBeConnected(currentUnitCluster.back(), n)){
connect(currentUnitCluster.back(), n);
} else {
currentUnitCluster.push(n);
}
}
}
}
};
/*
2 Computing topological relationship between a static point and moving(point)
*/
typedef MTopRelAlg_SMO<Point, MPoint, UPoint, MTopRelAlg_PUP> MTopRelAlg_PMP;
typedef MTopRelAlg_SMO<Point, MPoint, UPoint, MTopRelAlg_UPP> MTopRelAlg_MPP;
/*
2 Computing topological relationship between two UPoint values
If the time intervals are not equal, the topological relationship
will be undefined for such time intervals where only one of the
upoints is defined. The complete result is computed in the constructor
and stored within a vector. This is possible, because the maximum number
of resulting relationships is 5 ( 2 undefined plus three for the common
time interval).
*/
class MTopRelAlg_UPUP {
public:
/*
1.1 Constructors
*/
MTopRelAlg_UPUP(const UPoint* up1, const UPoint* up2);
MTopRelAlg_UPUP(const UPoint* up1, const UPoint* up2,
const toprel::PredicateGroup* pg);
~MTopRelAlg_UPUP() {}
/*
1.2 hasNext
Checks whether more topological relationships are available.
*/
bool hasNext() const;
/*
1.3 next
Precondition: hasNext()
Returns the next element of the result. The result consists of a time interval
and the corresponding topological relationship between the time interval.
*/
std::pair<Interval<Instant>, toprel::Int9M> next();
/*
1.4 hasNextCluster
Checks whether at least one more cluster is available in the result.
*/
bool hasNextCluster() const;
/*
1.5 nextCluster
Precondition: hasNextCluster
Returns the next cluster with its corresponding time interval.
*/
std::pair<Interval<Instant>, toprel::Cluster> nextCluster();
private:
std::vector< std::pair<Interval<Instant>, toprel::Int9M> > toprels;
std::vector< std::pair<Interval<Instant>, toprel::Cluster> > clusters;
uint8_t toprelPos;
uint8_t clusterPos;
void init( const UPoint* up1, const UPoint* up2,
const toprel::PredicateGroup* pg);
void computeClustersFromTopRels( const toprel::PredicateGroup* pg);
};
/*
2 Computing topological relationship between a upoint and an mpoint
*/
template<bool sym>
class MTopRelAlg_UPMP_T{
public:
/*
1.1 Constructors
*/
MTopRelAlg_UPMP_T(const UPoint* up, const MPoint* mp);
MTopRelAlg_UPMP_T(const UPoint* up, const MPoint* mp,
const toprel::PredicateGroup* pg);
~MTopRelAlg_UPMP_T() {}
/*
1.2 hasNext
Checks whether more topological relationships are available.
*/
bool hasNext() const;
/*
1.3 next
Precondition: hasNext()
Returns the next element of the result. The result consists of a time interval
and the corresponding topological relationship between the time interval.
*/
std::pair<Interval<Instant>, toprel::Int9M> next();
/*
1.4 hasNextCluster
Checks whether at least one more cluster is available in the result.
*/
bool hasNextCluster() const;
/*
1.5 nextCluster
Precondition: hasNextCluster
Returns the next cluster with its corresponding time interval.
*/
std::pair<Interval<Instant>, toprel::Cluster> nextCluster();
private:
const UPoint* up;
const MPoint* mp;
RefinementStream<MPoint, MPoint, UPoint, UPoint> toprelRefinement;
RefinementStream<MPoint, MPoint, UPoint, UPoint> clusterRefinement;
const toprel::PredicateGroup* pg;
std::queue<std::pair<Interval<Instant> , toprel::Int9M> > toprelqueue;
std::queue<std::pair<Interval<Instant> , toprel::Cluster> > clusterqueue;
void init();
void computeNextTopRel();
void computeNextCluster();
};
/*
4.2 Implementation
*/
template<bool sym>
MTopRelAlg_UPMP_T<sym>::MTopRelAlg_UPMP_T(const UPoint* _up,
const MPoint* _mp):
up(_up), mp(_mp), toprelRefinement(_up,_mp),
clusterRefinement(_up,_mp),
pg(0), toprelqueue(), clusterqueue(){
init();
}
/*
template<bool sym>
MTopRelAlg_UPMP_T<sym>::MTopRelAlg_UPMP_T(const UPoint* _up,
const MPoint* _mp,
const toprel::PredicateGroup* _pg):
up(_up), mp(_mp), toprelRefinement(_up,_mp),
clusterRefinement(_up,_mp),
pg(_pg), toprelqueue(), clusterqueue(){
init();
}
*/
/*
1.2 hasNext
Checks whether more topological relationships are available.
*/
template<bool sym>
bool MTopRelAlg_UPMP_T<sym>::hasNext() const{
return toprelqueue.size()>0;
}
/*
1.3 next
Precondition: hasNext()
Returns the next element of the result. The result consists of a time interval
and the corresponding topological relationship between the time interval.
*/
template<bool sym>
std::pair<Interval<Instant>,
toprel::Int9M> MTopRelAlg_UPMP_T<sym>::next(){
assert(hasNext());
std::pair<Interval<Instant>, toprel::Int9M> res = toprelqueue.front();
toprelqueue.pop();
computeNextTopRel();
return res;
}
/*
1.4 hasNextCluster
Checks whether at least one more cluster is available in the result.
*/
template<bool sym>
bool MTopRelAlg_UPMP_T<sym>::hasNextCluster() const{
return clusterqueue.size() > 0;
}
/*
1.5 nextCluster
Precondition: hasNextCluster
Returns the next cluster with its corresponding time interval.
*/
template<bool sym>
std::pair<Interval<Instant>, toprel::Cluster>
MTopRelAlg_UPMP_T<sym>::nextCluster(){
assert(hasNextCluster());
std::pair<Interval<Instant>, toprel::Cluster> res
= clusterqueue.front();
clusterqueue.pop();
computeNextCluster();
return res;
}
template<bool sym>
void MTopRelAlg_UPMP_T<sym>::init(){
if( !up || !mp){
return;
}
if(!up->IsDefined() || ! mp->IsDefined()){
return;
}
computeNextTopRel();
if(pg && pg->IsDefined()){
computeNextCluster();
}
}
template<bool sym>
void MTopRelAlg_UPMP_T<sym>::computeNextTopRel(){
Interval<Instant> iv;
int pos1;
int pos2;
toprel::Int9M undef(false);
undef.SetDefined(false);
while(toprelqueue.size() < 2 && toprelRefinement.hasNext()){
toprelRefinement.getNext(iv, pos1,pos2);
if(pos1<0 || pos2 <0){
std::pair<Interval<Instant> , toprel::Int9M> p(iv, undef);
mergeAdd(toprelqueue,p);
} else { // wow, found a common interval
UPoint up1(1);
up->AtInterval(iv,up1);
UPoint up2_1(0);
mp->Get(pos2,up2_1);
UPoint up2(0);
up2_1.AtInterval(iv,up2);
MTopRelAlg_UPUP alg(&up1,&up2);
while(alg.hasNext()){
std::pair<Interval<Instant>, toprel::Int9M> p = alg.next();
if(sym){
p.second.Transpose();
}
mergeAdd(toprelqueue,p);
}
}
}
}
template<bool sym>
void MTopRelAlg_UPMP_T<sym>::computeNextCluster(){
if(!pg){
return;
}
Interval<Instant> iv;
int pos1;
int pos2;
toprel::Cluster undef(false);
undef.SetDefined(false);
while(clusterqueue.size() < 2 && clusterRefinement.hasNext()){
clusterRefinement.getNext(iv, pos1,pos2);
if(pos1<0 || pos2 <0){
std::pair<Interval<Instant> , toprel::Cluster> p(iv, undef);
mergeAdd(clusterqueue,p);
} else { // wow, found a common interval
UPoint up1(1);
up->AtInterval(iv,up1);
UPoint up2_1(0);
mp->Get(pos2,up2_1);
UPoint up2;
up2_1.AtInterval(iv,up2);
MTopRelAlg_UPUP alg(&up1,&up2);
while(alg.hasNext()){
std::pair<Interval<Instant>, toprel::Int9M> p1 = alg.next();
if(sym){
p1.second.Transpose();
}
std::pair<Interval<Instant>, toprel::Cluster>
p2(p1.first, pg->GetClusterOf(p1.second));
mergeAdd(clusterqueue,p2);
}
}
}
}
typedef MTopRelAlg_UPMP_T<false> MTopRelAlg_UPMP;
typedef MTopRelAlg_UPMP_T<true> MTopRelAlg_MPUP;
/*
4 Computation between two mpoints.
*/
class MTopRelAlg_MPMP {
public:
/*
1.1 Constructors
*/
MTopRelAlg_MPMP(const MPoint* mp1, const MPoint* mp2);
MTopRelAlg_MPMP(const MPoint* mp1, const MPoint* mp2,
const toprel::PredicateGroup* pg);
~MTopRelAlg_MPMP() {}
/*
1.2 hasNext
Checks whether more topological relationships are available.
*/
bool hasNext() const;
/*
1.3 next
Precondition: hasNext()
Returns the next element of the result. The result consists of a time interval
and the corresponding topological relationship between the time interval.
*/
std::pair<Interval<Instant>, toprel::Int9M> next();
/*
1.4 hasNextCluster
Checks whether at least one more cluster is available in the result.
*/
bool hasNextCluster() const;
/*
1.5 nextCluster
Precondition: hasNextCluster
Returns the next cluster with its corresponding time interval.
*/
std::pair<Interval<Instant>, toprel::Cluster> nextCluster();
private:
const MPoint* mp1;
const MPoint* mp2;
RefinementStream<MPoint, MPoint, UPoint, UPoint> toprelRefinement;
RefinementStream<MPoint, MPoint, UPoint, UPoint> clusterRefinement;
const toprel::PredicateGroup* pg;
std::queue<std::pair<Interval<Instant> , toprel::Int9M> > toprelqueue;
std::queue<std::pair<Interval<Instant> , toprel::Cluster> > clusterqueue;
void init();
void computeNextTopRel();
void computeNextCluster();
};
/*
6 Combination Region x UPoint
*/
template<bool sym>
class MTopRelAlg_RUP_T {
public:
/*
1.1 Constructors
*/
MTopRelAlg_RUP_T(const Region* reg, const UPoint* up);
MTopRelAlg_RUP_T(const Region* reg, const UPoint* up,
const toprel::PredicateGroup* pg);
~MTopRelAlg_RUP_T() {}
/*
1.2 hasNext
Checks whether more topological relationships are available.
*/
bool hasNext() const;
/*
1.3 next
Precondition: hasNext()
Returns the next element of the result. The result consists of a time interval
and the corresponding topological relationship between the time interval.
*/
std::pair<Interval<Instant>, toprel::Int9M> next();
/*
1.4 hasNextCluster
Checks whether at least one more cluster is available in the result.
*/
bool hasNextCluster() const;
/*
1.5 nextCluster
Precondition: hasNextCluster
Returns the next cluster with its corresponding time interval.
*/
std::pair<Interval<Instant>, toprel::Cluster> nextCluster();
private:
std::vector<std::pair<Interval<Instant>, toprel::Int9M> > toprelvector;
std::vector<std::pair<Interval<Instant>, toprel::Cluster> >
clustervector;
size_t toprelpos;
size_t clusterpos;
void init(const Region* reg, const UPoint* up,
const toprel::PredicateGroup* pg,
const bool forceThrow = false);
};
/*
5.1 Implementation
*/
template<bool sym>
MTopRelAlg_RUP_T<sym>::MTopRelAlg_RUP_T(const Region* reg,
const UPoint* up):
toprelvector(), clustervector(), toprelpos(0), clusterpos(0){
init(reg, up, 0);
}
template<bool sym>
MTopRelAlg_RUP_T<sym>::MTopRelAlg_RUP_T(const Region* reg,
const UPoint* up,
const toprel::PredicateGroup* pg):
toprelvector(), clustervector(), toprelpos(0), clusterpos(0){
init(reg,up,pg);
}
/*
1.2 hasNext
Checks whether more topological relationships are available.
*/
template<bool sym>
bool MTopRelAlg_RUP_T<sym>::hasNext() const {
return toprelpos < toprelvector.size();
}
/*
1.3 next
Precondition: hasNext()
Returns the next element of the result. The result consists of a time interval
and the corresponding topological relationship between the time interval.
*/
template<bool sym>
std::pair<Interval<Instant>, toprel::Int9M> MTopRelAlg_RUP_T<sym>::next(){
assert(hasNext());
std::pair<Interval<Instant>, toprel::Int9M> res
= toprelvector[toprelpos];
toprelpos++;
return res;
}
/*
1.4 hasNextCluster
Checks whether at least one more cluster is available in the result.
*/
template<bool sym>
bool MTopRelAlg_RUP_T<sym>::hasNextCluster() const{
return clusterpos < clustervector.size();
}
/*
1.5 nextCluster
Precondition: hasNextCluster
Returns the next cluster with its corresponding time interval.
*/
template<bool sym>
std::pair<Interval<Instant>, toprel::Cluster>
MTopRelAlg_RUP_T<sym>::nextCluster(){
assert(hasNextCluster());
std::pair<Interval<Instant>, toprel::Cluster>
res = clustervector[clusterpos];
clusterpos++;
return res;
}
template<bool sym>
void MTopRelAlg_RUP_T<sym>::init( const Region* reg, const UPoint* up,
const toprel::PredicateGroup* pg,
const bool forceThrow/* = false*/ ){
if(!reg || !up){
return;
}
if(!reg->IsDefined() || !up->IsDefined()){
return;
}
// define sime topological predicates for furthe use
toprel::Int9M disjoint(0,0,1, 0,0,1, 1,0,1);
toprel::Int9M onborder(0,0,1, 1,0,0, 0,0,1);
toprel::Int9M ininterior(1,0,1, 0,0,1, 0,0,1);
toprel::Int9M noreg(0,0,0, 0,0,0, 1,0,1);
if(sym){
disjoint.Transpose();
onborder.Transpose();
ininterior.Transpose();
noreg.Transpose();
}
std::vector<std::pair<Interval<Instant>, toprel::Int9M> > tmpvector;
if(reg->IsEmpty()){
std::pair<Interval<Instant>, toprel::Int9M> p(up->timeInterval, noreg);
tmpvector.push_back(p);
} else { // nonempty region
if(!reg->BoundingBox().Intersects(up->BoundingBoxSpatial())){
std::pair<Interval<Instant>, toprel::Int9M>
p(up->timeInterval, disjoint);
tmpvector.push_back(p);
} else if(AlmostEqual(up->p0, up->p1)){ // static upoint
if(reg->InInterior(up->p0)){
std::pair<Interval<Instant>, toprel::Int9M>
p(up->timeInterval, ininterior);
tmpvector.push_back(p);
} else if(reg->OnBorder(up->p0)){
std::pair<Interval<Instant>, toprel::Int9M>
p(up->timeInterval, onborder);
tmpvector.push_back(p);
} else {
std::pair<Interval<Instant>, toprel::Int9M>
p(up->timeInterval, disjoint);
tmpvector.push_back(p);
}
} else { // non-empty region, non-static upoint
if(up->timeInterval.lc && reg->OnBorder(up->p0)){
std::pair<Interval<Instant>, toprel::Int9M>
p(Interval<Instant>(up->timeInterval.start,
up->timeInterval.start,
true,true),
onborder);
tmpvector.push_back(p);
}
// we perform a plane sweep algorithm
// first, we create an AVLSegment from the unit and
// insert it into a
// priority queue. So we don't have to care about the queue
// and the upoint in parallel
//priority queue for the splitted sgements of the region
std::priority_queue<avlseg::ExtendedHalfSegment,
std::vector<avlseg::ExtendedHalfSegment>,
std::greater<avlseg::ExtendedHalfSegment> > qreg;
// periority queue for the upoint's halgsegments
std::priority_queue<avlseg::ExtendedHalfSegment,
std::vector<avlseg::ExtendedHalfSegment>,
std::greater<avlseg::ExtendedHalfSegment> > qup;
avlseg::ExtendedHalfSegment hs1(HalfSegment(true, up->p0, up->p1));
avlseg::ExtendedHalfSegment hs2(HalfSegment(false,
up->p0, up->p1));
qup.push(hs1);
qup.push(hs2);
int posreg=0;
avlseg::ownertype currentOwner;
avlseg::ExtendedHalfSegment cur;
bool done = false;
avltree::AVLTree<avlseg::AVLSegment> sss;
avlseg::AVLSegment* leftN;
avlseg::AVLSegment* rightN;
avlseg::AVLSegment tmpL, tmpR, left1, common1, right1;
while( ((currentOwner = SelectNext(*reg, posreg,
qreg, qup, cur)) != avlseg::none) &&
!done ){
avlseg::AVLSegment current(cur,currentOwner);
avlseg::AVLSegment* member =
sss.getMember(current,leftN,rightN);
// make copies from the nieghbours to be able
// to manipulate the avl tree entries
if(leftN){
tmpL = *leftN;
leftN = &tmpL;
}
if(rightN){
tmpR = *rightN;
rightN = &tmpR;
}
if(cur.IsLeftDomPoint()){
if(member){ // there is an overlapping segment found
assert(member->getOwner() != avlseg::both);
assert(member->getOwner() != currentOwner);
// split to extract the common part
uint32_t parts =
member->split(current,left1,common1,right1);
// remove member from sss
sss.remove(*member);
// by some numeric instabilities it's possibnle
// to have a part left of current
if(parts & avlseg::LEFT){
if(!left1.isPoint()){
sss.insert(left1);
insertEvents(left1,false,true,qreg,qup);
}
}
// process common part
if(currentOwner==avlseg::first) { // the region
if(current.getInsideAbove()){
common1.con_above++;
} else {
common1.con_above--;
}
} // for a upoint (line) is nothing to do
if(!common1.isPoint()){
sss.insert(common1);
insertEvents(common1,false,true,qreg,qup);
} else {
Interval<Instant> iv = computeInterval(*up, common1);
std::pair<Interval<Instant>, toprel::Int9M>
p(iv, onborder);
tmpvector.push_back(p);
}
if(parts & avlseg::RIGHT){
insertEvents(right1,true,true,qreg,qup);
}
} else { // no overlapping part found in sss
// check for possible intersections with neighbours
splitByNeighbour(sss,current,leftN,qreg,qup, forceThrow);
splitByNeighbour(sss,current,rightN,qreg,qup, forceThrow);
// update coverage numbers
if(currentOwner==avlseg::first){ // the region
bool iac = current.getInsideAbove();
if(leftN && current.extends(*leftN)){
current.con_below = leftN->con_below;
current.con_above = leftN->con_above;
}else{
if(leftN && leftN->isVertical()){
current.con_below = leftN->con_below;
} else if(leftN){
current.con_below = leftN->con_above;
} else {
current.con_below = 0;
}
if(iac){
current.con_above = current.con_below+1;
} else {
current.con_above = current.con_below-1;
}
}
} else { // the line
if(leftN){
if(leftN->isVertical()){
current.con_below = leftN->con_below;
} else {
current.con_below = leftN->con_above;
}
}
current.con_above = current.con_below;
}
// insert element
if(!current.isPoint()){
sss.insert(current);
insertEvents(current,false,true,qreg,qup);
}
}
} else { // right end point
if(member && member->exactEqualsTo(current)){
if( (member->getOwner()==avlseg::both)){
Interval<Instant> iv = computeInterval(*up, *member);
std::pair<Interval<Instant>, toprel::Int9M> p(iv, onborder);
tmpvector.push_back(p);
}
if( (member->getOwner()==avlseg::second)) {
Interval<Instant> iv = computeInterval(*up, *member);
if(member->con_above>0){
std::pair<Interval<Instant>, toprel::Int9M>
p(iv, ininterior);
tmpvector.push_back(p);
} else {
// create a disjoint toprel for member
std::pair<Interval<Instant>, toprel::Int9M>
p(iv, disjoint);
tmpvector.push_back(p);
}
}
sss.remove(*member);
splitNeighbours(sss,leftN,rightN,qreg,qup, forceThrow);
}
}
} // while
if(up->timeInterval.rc && reg->OnBorder(up->p1)){
std::pair<Interval<Instant>, toprel::Int9M> p(
Interval<Instant>(up->timeInterval.end,
up->timeInterval.end,
true,true),
onborder);
tmpvector.push_back(p);
}
}
}
sort(tmpvector.begin(), tmpvector.end(), pCompare);
// go trough the vector and assign all interval
// endings to the "onborder predicate"
// parallel merge intervals having the same relationship
toprelvector.clear();
if(tmpvector.size() > 0){
std::pair<Interval<Instant>, toprel::Int9M>
p1(Interval<Instant>(), toprel::Int9M(1));
std::pair<Interval<Instant>, toprel::Int9M>
p2(Interval<Instant>(), toprel::Int9M(1));
p1 = tmpvector[0];
for(size_t i = 1; i<tmpvector.size(); i++){
p2 = tmpvector[i];
if(p1.first.end != p2.first.start){
//cout << "crazy intervals found" << endl;
//cout << "p1 = " << p1.first << endl;
//cout << "p2 = " << p2.first << endl;
}
if(p1.second == p2.second){ // same relationship, extend
p1.first.Union(p2.first);
} else {
if(p1.first.rc && p2.first.lc){
if(p1.second == onborder){
if(p1.first.Intersects(up->timeInterval)){
p1.first.IntersectionWith(up->timeInterval);
toprelvector.push_back(p1);
p2.first.lc = false;
}
p1 = p2;
} else if (p2.second == onborder){
p1.first.rc = false;
if(p1.first.Intersects(up->timeInterval)){
p1.first.IntersectionWith(up->timeInterval);
toprelvector.push_back(p1);
}
p1 = p2;
} else { // change from disjoint to ininterior or vice versa
p1.first.rc = false;
if(p1.first.Intersects(up->timeInterval)){
p1.first.IntersectionWith(up->timeInterval);
toprelvector.push_back(p1);
}
std::pair<Interval<Instant>, toprel::Int9M>
p3(Interval<Instant>(p1.first.end,
p1.first.end,true,true),
onborder);
if(p3.first.Intersects(up->timeInterval)){
toprelvector.push_back(p3);
}
p2.first.lc = false;
p1 = p2;
}
} else if(!p1.first.lc && !p2.first.lc){ // small gap
if(p1.first.Intersects(up->timeInterval)){
p1.first.IntersectionWith(up->timeInterval);
toprelvector.push_back(p1);
}
std::pair<Interval<Instant>, toprel::Int9M>
p3(Interval<Instant>(p1.first.end,
p1.first.end,true,true),
onborder);
if(p3.first.Intersects(up->timeInterval)){
toprelvector.push_back(p3);
}
p1 = p2;
}
}
}
if(up->timeInterval.Intersects(p1.first)){
p1.first.IntersectionWith(up->timeInterval);
toprelvector.push_back(p1);
}
}
// create cluster vector from toprel vector
if(pg==0){
return;
}
if(!pg->IsDefined()){
return;
}
if(toprelvector.size()==0){
return;
}
std::pair<Interval<Instant>, toprel::Int9M> cpi = toprelvector[0];
toprel::Cluster* cl = pg->GetClusterOf(cpi.second);
std::pair<Interval<Instant>, toprel::Cluster> cpc(cpi.first, *cl);
delete cl;
for(unsigned int i=1; i< toprelvector.size(); i++){
std::pair<Interval<Instant>, toprel::Int9M> npi = toprelvector[i];
cl = pg->GetClusterOf(npi.second);
if(cpc.second == *cl){ // toprel within the same cluster,
//just enlarge the interval
cpc.first.end = npi.first.end;
cpc.first.rc = npi.first.rc;
} else {
clustervector.push_back(cpc);
cpc.first = npi.first;
cpc.second = *cl;
}
delete cl;
}
clustervector.push_back(cpc);
}
typedef MTopRelAlg_RUP_T<false> MTopRelAlg_RUP;
typedef MTopRelAlg_RUP_T<true> MTopRelAlg_UPR;
/*
6 Computing topological relationship between a static region and moving(point)
Note. This class stores references to the region and to the moving point.
After deleting the sources,
this class will crash if further functions are called.
*/
typedef MTopRelAlg_SMO<Region, MPoint, UPoint, MTopRelAlg_RUP> MTopRelAlg_RMP;
typedef MTopRelAlg_SMO<Region, MPoint, UPoint, MTopRelAlg_UPR> MTopRelAlg_MPR;
} // end of namespace