/* ---- This file is part of SECONDO. Copyright (C) 2007, 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 ---- //[_] [\_] //[toc] [\setcounter{page}{1} \renewcommand{\thepage}{\Roman{page}} \tableofcontents] //[etoc][\clearpage \setcounter{page}{1} \renewcommand{\thepage}{\arabic{page}}] //[title] [ \thispagestyle{empty} \title{TopOps-Algebra} \author{Thomas Behr} \maketitle] //[times] [\ensuremath{\times}] //[x] [\ensuremath{\times}] //[->] [\ensuremath{\rightarrow}] //[<=] [\ensuremath{\leq{}}] //[>=] [\ensuremath{\ge{}}] //[secondo] [\textsc{Secondo}] //[{] [\}] //[}] [\}] [title] [toc] [etoc] 1 General Description This algebra connects the TopRelAlgebra and the SpatialAlgebra. It implements functions computing the topological relationships of spatial values. Furthermore it provides some functions checking whether two objects are part of a cluster which is given by a name together with a predicategroup. Basically, this can also be implemented by computing the topological relationship and check whether the result is contained in the given cluster. The advantage of a separate implementation is that we can exit the computation early in many cases. Additionally, this algebra provides some topological predicates using the standard predicate group. Moreover, in this algebra set operations for spatial types (union2, intersection2, difference2, commonborder2) are implemented. 2 Includes, Constants, and Definitions */ #include #include #include #include #include "NestedList.h" #include "Algebra.h" #include "QueryProcessor.h" #include "LogMsg.h" #include "Symbols.h" #include "TopOpsAlgebra.h" #include "Algebras/Spatial/SpatialAlgebra.h" #include "AvlTree.h" #include "TopRel.h" #include "StandardTypes.h" #include "Algebras/Spatial/AVLSegment.h" #include "MMRTree.h" /* ~A Macro useful for debugging ~ */ //#define __TRACE__ cout << __FILE__ << "@" << __LINE__ << endl; #define __TRACE__ extern NestedList* nl; extern QueryProcessor* qp; using namespace toprel; using namespace std; namespace topops{ /* 5 Some Auxiliary Functions */ inline void SetII(Int9M& m, const bool useCluster, Cluster& cluster,bool& done){ if(!m.GetII()){ m.SetII(true); if(useCluster){ cluster.Restrict(II,true,false); done = done || cluster.isExtension(m) || cluster.IsEmpty(); } } } inline void SetIB(Int9M& m, const bool useCluster, Cluster& cluster, bool& done){ if(!m.GetIB()){ m.SetIB(true); if(useCluster){ cluster.Restrict(IB,true,false); done = done || cluster.isExtension(m)|| cluster.IsEmpty(); } } } inline void SetIE(Int9M& m, const bool useCluster, Cluster& cluster, bool& done){ if(!m.GetIE()){ m.SetIE(true); if(useCluster){ cluster.Restrict(IE,true,false); done = done || cluster.isExtension(m)|| cluster.IsEmpty(); } } } inline void SetBI(Int9M& m, const bool useCluster, Cluster& cluster, bool& done){ if(!m.GetBI()){ m.SetBI(true); if(useCluster){ cluster.Restrict(BI,true,false); done = done || cluster.isExtension(m)|| cluster.IsEmpty(); } } } inline void SetBB(Int9M& m, const bool useCluster, Cluster& cluster, bool& done){ if(!m.GetBB()){ m.SetBB(true); if(useCluster){ cluster.Restrict(BB,true,false); done = done || cluster.isExtension(m)|| cluster.IsEmpty(); } } } inline void SetBE(Int9M& m, const bool useCluster, Cluster& cluster, bool& done){ if(!m.GetBE()){ m.SetBE(true); if(useCluster){ cluster.Restrict(BE,true,false); done = done || cluster.isExtension(m)|| cluster.IsEmpty(); } } } inline void SetEI(Int9M& m, const bool useCluster, Cluster& cluster, bool& done){ if(!m.GetEI()){ m.SetEI(true); if(useCluster){ cluster.Restrict(EI,true,false); done = done || cluster.isExtension(m)|| cluster.IsEmpty(); } } } inline void SetEB(Int9M& m, const bool useCluster, Cluster& cluster, bool& done){ if(!m.GetEB()){ m.SetEB(true); if(useCluster){ cluster.Restrict(EB,true,false); done = done || cluster.isExtension(m)|| cluster.IsEmpty(); } } } inline void SetEE(Int9M& m, const bool useCluster, Cluster& cluster, bool& done){ if(!m.GetEE()){ m.SetEE(true); if(useCluster){ cluster.Restrict(EE,true,false); done = done || cluster.isExtension(m)|| cluster.IsEmpty(); } } } /* 7 Computation of the 9 intersection matrices The following functions compute the 9 intersection matrices for different combinations of spatial data types. 7.1 ~point~ [x] ~point~ This function computes the 9-intersection matrix between two point values. Because a single point is very simple, no bounding box tests are performed. Complexity: O(1) */ bool GetInt9M(Point* p1 , Point* p2,Int9M& res, const bool useCluster= false, Cluster cluster = Cluster()){ res.SetValue(0); // in each case, the exteriors intersect res.SetEE(true); if(AlmostEqual(*p1,*p2)){ res.SetII(true); }else{ res.SetIE(true); res.SetEI(true); } if(useCluster){ return cluster.Contains(res); } else { return true; } } /* 7.2 ~point~ [x] ~points~ The next function computes the 9 intersection matrix between a point value and a points value. Complexity: O(log(n) + 1) where ~n~ is the number of points in the __ps__ value. */ bool GetInt9M(Points* ps, Point* p,Int9M& res, const bool useCluster=false, Cluster cluster = Cluster()){ // initialization res.SetValue(0); res.SetEE(true); // holds always for bounded objects // check for emptyness if(ps->IsEmpty()){ // the simples case res.SetEI(true); if(useCluster){ return cluster.Contains(res); } else { return true; } } // bounding box check Rectangle<2> box_ps = ps->BoundingBox(); Rectangle<2> box_p = p->BoundingBox(); if(!box_p.Intersects(box_ps)){ // disjointness of the bounding boxes res.SetIE(true); res.SetEI(true); if(useCluster){ return cluster.Contains(res); } else { return true; } } int size = ps->Size(); if(size>1){ res.SetIE(true); if(useCluster){ cluster.Restrict(IE,true,false); if(cluster.IsEmpty()){ return false; } } } if(!(ps->Contains(*p))){ // Contains uses binary search res.SetEI(true); res.SetIE(true); } else{ res.SetII(true); } if(useCluster){ return cluster.Contains(res); } else { return true; } } /* 7.3 ~points~ [x] ~points~ This function computes the 9 intersection matrix describing the topological relationship between two __points__ values. Complexity: O(~n~+~m~ + 1) , where ~n~ and ~m~ is the size of ~ps~1 and ~ps~2 respectively. If ~useCluster~ is set to be __false__, the return value is always __true__. In this case, the parameter __res__ will contain the 9 intersection matrix describing the topological relationship between ~p1~1 and ~ps~2. In the other case, the matrix is not computed completely. Instead, the return value will indicate whether the topological relationship is part of ~cluster~. */ bool GetInt9M(Points* ps1, Points* ps2, Int9M& res, const bool useCluster = false, Cluster cluster = Cluster(false)){ if(useCluster && cluster.IsEmpty()){ return false; } int n1 = ps1->Size(); int n2 = ps2->Size(); if(useCluster){ // restrict cluster to matrices which are realizable // for the points/points combination int cb = cluster.checkBoxes(ps1->BoundingBox(),n1, ps2->BoundingBox(),n2); if(cb==1) { return true; } if(cb==2){ return false; } cluster.Restrict(EE,true,false); // the extreiors always intersect // the boundary of a points value is empty, thereby no intersections // of this part with any other part may exist Int9M r(true, false, true, false, false, false, true,false,true); cluster.Restrict(r,false,false); if(cluster.IsEmpty()){ return false; } } res.SetValue(0); res.SetEE(true); if(n1<=0 && n2<=0){ // there are no inner parts which can intersect any part if(useCluster){ return cluster.Contains(res); } else { return true; } } if(n1<=0){ // some points of ps2 are in the exterior of ps1 res.SetEI(true); if(useCluster){ return cluster.Contains(res); } else { return true; } } if(n2<=0){ // symmetrically to the previous case res.SetIE(true); if(useCluster){ return cluster.Contains(res); } else { return true; } } // bounding box check Rectangle<2> bbox1 = ps1->BoundingBox(); Rectangle<2> bbox2 = ps2->BoundingBox(); if(!bbox1.IntersectsUD(bbox2)){ // non empty disjoint points values res.SetIE(true); res.SetEI(true); if(useCluster){ return cluster.Contains(res); } else { return true; } } // bounding box check failed, perform an parallel scan Point p1; Point p2; int i1=0; int i2=0; bool done = false; do{ ps1->Get(i1,p1); ps2->Get(i2,p2); int cmp = p1.Compare(&p2); if(cmp==0){ //p1==p2 SetII(res,useCluster,cluster,done); i1++; i2++; } else if (cmp<0){ // p1 in the exterior of p2 SetIE(res,useCluster,cluster,done); i1++; } else{ // p1 > p2 SetEI(res,useCluster,cluster,done); i2++; } done= done || ((i1>=n1-1) || (i2>=n2-1)) || // end of one points value reached (res.GetII() && res.GetIE() && res.GetEI()); if(useCluster){ done = done || cluster.IsEmpty(); } }while(!done); // end of scan if(res.GetII() && res.GetIE() && res.GetEI()){ // maximum count of intersections if(!useCluster){ return true; } else { return cluster.Contains(res); } } if((i1IsEmpty()){ res.SetEI(true); return true; } // the interior of a non-empty line has always // an intersection with the exterior of a single point // because of the difference in the dimension res.SetIE(true); pointdone = false; // the line contains at least one halfsegment Rectangle<2> bbox_line = line->BoundingBox(); Rectangle<2> bbox_point = point->BoundingBox(); // both objects are disjoint if(!bbox_line.Intersects(bbox_point)){ res.SetIE(true); res.SetEI(true); pointdone = true; } return false; } bool initBox(Line const* const line, Points const* const point, Int9M& res, bool & pointdone){ res.SetValue(0); res.SetEE(true); pointdone = false; if(line->IsEmpty()){ if(point->IsEmpty()){ pointdone = true; return true; } else { res.SetEI(true); return true; } } // the interior of a non-empty line has always // an intersection with the exterior of a single point // because of the difference in the dimension res.SetIE(true); if(point->IsEmpty()){ pointdone = true; return false; // search for boundary points } // line and point are non empty Rectangle<2> bbox_line = line->BoundingBox(); Rectangle<2> bbox_point = point->BoundingBox(); // both objects are disjoint if(!bbox_line.Intersects(bbox_point)){ res.SetIE(true); res.SetEI(true); } return false; } /* ~isDone~ This function checks whether all possible intersections for the parameter combination of the first two parameters are set in in the matrix. */ bool isDone(Line const* const line, Point const* const point, Int9M m, const bool useCluster, const Cluster& cluster){ bool res = m.GetBE() && // endpoint of the line has been found (m.GetII() || m.GetBI() || m.GetEI()); if(useCluster){ return res || cluster.IsEmpty() || cluster.isExtension(m); } else { return res; } } bool isDone(Line const* const line, Points const* const point, Int9M m, const bool useCluster, const Cluster& cluster){ bool res = m.GetBE() && // endpoint of the line has been found (m.GetII() && m.GetBI() && m.GetEI()); if(useCluster){ return res || cluster.IsEmpty() || cluster.isExtension(m); } else { return res; } } bool isEmpty(const Point& p){ return false; } bool isEmpty(const Points& ps){ return ps.IsEmpty(); } /* ~GetInt9M~ The template parameter can be instantiated with ~Point~ or ~Points~. */ template bool GetInt9M(Line const* const line, Pclass const* const point, Int9M& res, const bool useCluster, Cluster& cluster, const bool forceThrow/*=false*/){ bool pointdone1 = false; if(initBox(line,point,res,pointdone1)){ if(useCluster){ return cluster.Contains(res); } else { return true; } } if(useCluster){ // line is not empty int cb = cluster.checkBoxes(line->BoundingBox(),line->Size()==0, point->BoundingBox(), isEmpty(*point)); if(cb==1) { return true; } if(cb==2){ return false; } } // restrict the cluster to valid matrices if(useCluster){ cluster.Restrict(EE,true,false); // hold in each case cluster.Restrict(IE,true,false); // nonempty line // boundary of a point is empty Int9M m(true, false, true, true,false,true, true,false,true); cluster.Restrict(m,false,false); if(cluster.IsEmpty()){ return false; } } // prefilter unsuccessful -> scan the halfsegments avltree::AVLTree sss; priority_queue, greater > q; bool done = false; int posline = 0; // position within the line array avlseg::ownertype owner; int posPoint = pointdone1?1:0; avlseg::ExtendedHalfSegment resHs; Point resPoi; Point lastDomPoint; int lastDomPointCount = 0; // avoid unneeded expensive restrictions of the cluster avlseg::AVLSegment tmpL,tmpR; while(!done && ((owner=selectNext(*line,q,posline,*point, posPoint,resHs,resPoi))!=avlseg::none)){ if(owner==avlseg::second){ // event comes from the point(s) value avlseg::AVLSegment current(resPoi,avlseg::second); avlseg::AVLSegment* leftN=0; avlseg::AVLSegment* rightN=0; avlseg::AVLSegment* member= sss.getMember(current,leftN,rightN); if(leftN){ tmpL = *leftN; leftN = &tmpL; } if(rightN){ tmpR = *rightN; rightN = &tmpR; } if(!member){ // point outside current, check lastdompoint if(lastDomPointCount>0 && AlmostEqual(lastDomPoint,resPoi)){ // point located in the last dominating point if(lastDomPointCount==1){ // on boundary SetBI(res,useCluster,cluster,done); } else { SetII(res,useCluster,cluster,done); } lastDomPointCount++; } else { // point outside the line SetEI(res,useCluster,cluster,done); // update dompoint if(lastDomPointCount==1){ // last point was boundary SetBE(res,useCluster,cluster,done); } lastDomPoint = resPoi; lastDomPointCount = 0; } } else { double x = resPoi.GetX(); double y = resPoi.GetY(); if((leftN && leftN->contains(x,y)) || (rightN && rightN->contains(x,y))|| ( member->ininterior(x,y))){ SetII(res,useCluster,cluster,done); } else { // point located on an endpoint of member if(lastDomPointCount>0 && AlmostEqual(resPoi,lastDomPoint)){ if(lastDomPointCount==1){ SetBI(res,useCluster,cluster,done); } else { SetII(res,useCluster,cluster,done); } lastDomPointCount++; } else { SetEI(res,useCluster,cluster,done); lastDomPointCount = 0; } } } done = done || isDone(line,point,res,useCluster,cluster); lastDomPoint = resPoi; } else { // an halfsegment assert(owner==avlseg::first); // check for endpoints Point domPoint = resHs.GetDomPoint(); // only check for dompoints if the segment is a new one (left) // or its actually stored in the tree avlseg::AVLSegment current(resHs, avlseg::first); avlseg::AVLSegment* leftN=0; avlseg::AVLSegment* rightN=0; avlseg::AVLSegment* member= sss.getMember(current,leftN,rightN); if(leftN){ tmpL = *leftN; leftN = &tmpL; } if(rightN){ tmpR = *rightN; rightN = &tmpR; } if(resHs.IsLeftDomPoint() || (member && member->exactEqualsTo(current))){ if(lastDomPointCount==0 || !AlmostEqual(domPoint,lastDomPoint)){ if(lastDomPointCount==1){ SetBE(res,useCluster,cluster,done); } lastDomPoint = domPoint; lastDomPointCount = 1; } else{ lastDomPointCount++; lastDomPoint = domPoint; } } if(resHs.IsLeftDomPoint()){ // left event avlseg::AVLSegment left1, left2, right1, right2; if(member){ //overlapping segment found if((!AlmostEqual(member->getX2(),current.getX2())) && (member->getX2() < current.getX2() )){ // current is an extension of member current.splitAt(member->getX2(), member->getY2(),left1,right1); // create events for the remaining parts q.push(right1.convertToExtendedHs(true,avlseg::first)); q.push(right1.convertToExtendedHs(false,avlseg::first)); } } else { // there is no overlapping segment splitByNeighbour(sss,current,leftN,q,q, forceThrow); splitByNeighbour(sss,current,rightN,q,q, forceThrow); sss.insert(current); } // no overlapping segment } else { // right event avlseg::AVLSegment left1, left2, right1, right2; if(member && member->exactEqualsTo(current)){ // segment found sss.remove(current); splitNeighbours(sss,leftN,rightN,q,q, forceThrow); } } } done = done || isDone(line,point,res,useCluster, cluster); } // end sweep if(lastDomPointCount==1) { // last Point of the line is an endpoint SetBE(res,useCluster,cluster,done); } if(useCluster){ return cluster.Contains(res); }else { return true; } } /* Instantiations of the template function */ bool GetInt9M(Line const* const line, Point const* const point,Int9M& res, const bool useCluster=false, Cluster cluster = Cluster(), const bool forceThrow = false){ return GetInt9M(line,point,res, useCluster, cluster, forceThrow); } bool GetInt9M(Line const* const line, Points const* const point,Int9M& res, const bool useCluster=false, Cluster cluster = Cluster(), const bool forceThrow= false){ return GetInt9M(line,point,res, useCluster, cluster, forceThrow); } /* 7.5 ~region~ [x] ~point~ Computation of the 9 intersection matrix for a single point and a region value. ~pointAbove~ Auxiliary function checking if ~p~ is located above ~hs~. */ bool pointAbove(const HalfSegment* hs, const Point* p) { double x1 = hs->GetLeftPoint().GetX(); double y1 = hs->GetLeftPoint().GetY(); double x2 = hs->GetRightPoint().GetX(); double y2 = hs->GetRightPoint().GetY(); double x = p->GetX(); double y = p->GetY(); if(AlmostEqual(x1,x2)){ // vertical segment return y > max(y1,y2); } double d = (x-x1)/(x2-x1); double ys = y1 + d*(y2-y1); return (!AlmostEqual(y,ys) && y > ys); } bool GetInt9M(Region const* const reg, Point const* const p, Int9M& res, const bool useCluster= false, Cluster cluster = Cluster()){ res.SetValue(0); res.SetEE(true); if(reg->IsEmpty()){ res.SetEI(true); if(useCluster){ return cluster.Contains(res); } else { return true; } } res.SetIE(true); // the point can't cover an infinite set of points res.SetBE(true); Rectangle<2> bboxreg = reg->BoundingBox(); Rectangle<2> bboxp = p->BoundingBox(); if(!bboxreg.Intersects(bboxp)){ res.SetEI(true); if(useCluster){ return cluster.Contains(res); } else { return true; } } if(useCluster){ int cb = cluster.checkBoxes(reg->BoundingBox(),false, p->BoundingBox(), false); if(cb==1) { return true; } if(cb==2){ return false; } } // bbox check failed, we have to compute the result int size = reg->Size(); double x = p->GetX(); avlseg::ExtendedHalfSegment hs; int number = 0; for(int i=0;iGet(i,hs1); hs = hs1; if(hs.IsLeftDomPoint()){ if(hs.Contains(*p)){ res.SetBI(true); //point on boundary if(useCluster){ return cluster.Contains(res); } else { return true; } } if(!hs.IsVertical()){ if(pointAbove(&hs,p)){ if((AlmostEqual(hs.GetRightPoint().GetX(),x)) || ( !AlmostEqual(hs.GetLeftPoint().GetX(),x) && hs.GetLeftPoint().GetX()=x)){ number++; } } } } } if(number % 2 == 0){ res.SetEI(true); } else{ res.SetII(true); } if(useCluster){ return cluster.Contains(res); } else { return true; } } /* 7.6 ~region~ [x] ~points~ Computation of the 9 intersection matrix for a set of points and a region value. ~selectNext~ If the event caused by the region is smaller then the one caused by the points value, the result of the function will be ~first~. Otherwise, the result will be ~second~. The region itself may consist of the original halfsegments and halfsegments produced by dividing original halfsegments. The positions indicate the current elements of the halfsegment arrays. They are updated automatically within this function. Depending on the return value, one of the parameter ~resultHs~ or ~resultPoint~ is set to the value of the next event. If the region and the points value are already processed, the return value will be ~none~. */ avlseg::ownertype selectNext(const Region* reg, priority_queue, greater >& q1, int& pos1, Points const* const p, int& pos2, avlseg::ExtendedHalfSegment& resultHS, Point& resultPoint){ assert(pos1>=0); assert(pos2>=0); int sizereg = reg->Size(); int sizepoint = p->Size(); const avlseg::ExtendedHalfSegment* rhs=0; const avlseg::ExtendedHalfSegment* qhs = 0; avlseg::ExtendedHalfSegment qhsc; const avlseg::ExtendedHalfSegment* minhs=0; const Point* cp=0; avlseg::ExtendedHalfSegment rhs1; if(pos1Get(pos1, hstmp); rhs1 = hstmp; rhs = &rhs1; } if(!q1.empty()){ qhsc = q1.top(); qhs = &qhsc; } Point cp1; if(pos2Get(pos2,cp1); cp = &cp1; } int src = 0; // none if(rhs){ src = 1; minhs = rhs; } if(qhs){ if(src==0) { src = 1; minhs = qhs; } else { // rhs and qhs exist if(*qhs < *rhs){ src = 2; minhs = qhs; } } } if(cp){ if(!minhs){ src = 3; } else { double px = cp->GetX(); double hx = minhs->GetDomPoint().GetX(); if(AlmostEqual(px,hx)){ double py = cp->GetY(); double hy = minhs->GetDomPoint().GetY(); if(AlmostEqual(py,hy)){ if(!minhs->IsLeftDomPoint()){ // left < point < right src = 3; } } else if(pySize()]; memset(puses,0,ps->Size() * sizeof(bool)); res.SetValue(0); res.SetEE(true); mmrtree::RtreeT<2,int> tree(4,8); Point p; for(int i=0;iSize();i++){ ps->Get(i,p); tree.insert(p.BoundingBox(),i); } // find points of boundary of the region HalfSegment hs; for(int i=0;iSize();i++){ reg->Get(i,hs); if(hs.IsLeftDomPoint()){ mmrtree::RtreeT<2,int>::iterator* it = tree.find(hs.BoundingBox()); int const* pos; while( (pos = it->next()) != 0){ ps->Get(*pos,p); if(hs.Contains(p)){ puses[*pos] = true; res.SetBI(true); } } delete it; } } // the unused points are inside or outside the region bool ii=false; bool ei = false; for(int i=0;iSize();i++){ if(!puses[i]){ ps->Get(i,p); if(reg->InnerContains(p)){ ii = true; res.SetII(true); } else { ei = true; res.SetEI(true); } if(ii && ei){ delete[] puses; return cluster.Contains(res); } } } delete[] puses; return cluster.Contains(res); } bool GetInt9M(Region const* const reg, Points const* const ps, Int9M& res, const bool useCluster=false, Cluster cluster = Cluster(), const bool forceThrow = false){ try{ res.SetValue(0); // test for emptyness res.SetEE(true); if(reg->IsEmpty()){ if(ps->IsEmpty()){ if(useCluster){ return cluster.Contains(res); } else { return true; } } res.SetEI(true); if(useCluster){ return cluster.Contains(res);; } else { return true; } } res.SetIE(true); res.SetBE(true); if(ps->IsEmpty()){ // no more intersections can be found if(useCluster){ return cluster.Contains(res); } else { return true; } } // bounding box test Rectangle<2> regbox = reg->BoundingBox(); Rectangle<2> pbox = ps->BoundingBox(); if(!regbox.Intersects(pbox)){ // disjoint objects res.SetEI(true); if(useCluster){ return cluster.Contains(res); } else { return true; } } if(useCluster){ int cb = cluster.checkBoxes(regbox, false, pbox, false); if(cb==1) { return true; } if(cb==2){ return false; } } // bbox failed, perform a plane sweep if(useCluster){ // restrict the cluster to possible values // boundary of an points value is empty Int9M m1(true,false,true, true,false,true, true,false,true); cluster.Restrict(m1,false,false); cluster.Restrict(res,true,false); if(cluster.IsEmpty()){ return false; } if(cluster.isExtension(res)){ return true; } } // queue for splitted segments of the region priority_queue, greater > q1; avltree::AVLTree sss; avlseg::ownertype owner; bool done = false; int pos1 =0; int pos2 =0; Point CP; avlseg::ExtendedHalfSegment CH; avlseg::AVLSegment tmpL,tmpR; while (!done && ( (owner= selectNext(reg,q1,pos1, ps,pos2,CH,CP))!=avlseg::none)){ if(owner==avlseg::second){ // the point avlseg::AVLSegment current(CP,avlseg::second); avlseg::AVLSegment* left=0; avlseg::AVLSegment* right=0; avlseg::AVLSegment* member = sss.getMember(current, left, right); if(left){ tmpL = *left; left = &tmpL; } if(right){ tmpR = *right; right = &tmpR; } if(member){ // point located on boundary SetBI(res,useCluster,cluster,done); } else if(left){ if(left->getInsideAbove_first()){ SetII(res,useCluster,cluster,done); } else { SetEI(res,useCluster,cluster,done); } } else { // there is nothing under cp SetEI(res,useCluster,cluster,done); } done = done || (res.GetII() && res.GetBI() && res.GetEI()); } else { // the next element comes from the region avlseg::AVLSegment current(CH,avlseg::first); avlseg::AVLSegment* leftN = 0; avlseg::AVLSegment* rightN = 0; avlseg::AVLSegment* member = sss.getMember(current,leftN,rightN); if(leftN){ tmpL = *leftN; leftN = &tmpL; } if(rightN){ tmpR = *rightN; rightN = &tmpR; } if(CH.IsLeftDomPoint()){ // left Event if(member){ cout << "found overlapping segments" " within a single region" << endl; cout << "Segment1 " << setprecision(16) << current << endl; cout << "Segment2 " << setprecision(16) << (*member) << endl; throw myexception("found overlapping segments") ; } assert(!member); // a single region can't //contain overlapping segments splitByNeighbour(sss,current,leftN,q1,q1, forceThrow); splitByNeighbour(sss,current,rightN,q1,q1, forceThrow); sss.insert(current); } else { // right event if(member && member->exactEqualsTo(current)){ sss.remove(current); splitNeighbours(sss,leftN,rightN,q1,q1, forceThrow); } } } // element from region } // while if(useCluster){ return cluster.Contains(res); } else{ return true; } } catch(...){ return GetInt9MRob(reg, ps, res, useCluster, cluster ); } } /* The Class ~OwnedPoint~ This class contains a point together with its owner. */ class OwnedPoint{ public: OwnedPoint(){ defined = false; } OwnedPoint(Point p0, avlseg::ownertype o){ p = p0; owner = o; defined = true; } OwnedPoint(const OwnedPoint& src){ p = src.p; owner = src.owner; defined = src.defined; } OwnedPoint& operator=(const OwnedPoint& src){ p = src.p; owner = src.owner; defined = src.defined; return *this; } Point p; avlseg::ownertype owner; bool defined; }; /* 7.7 ~region~ [x] ~region~ */ bool GetInt9M(Region const* const reg1, Region const* const reg2, Int9M& res, const bool useCluster =false, Cluster cluster = Cluster(), const bool forceThrow = false){ res.SetValue(0);; res.SetEE(true); // check for emptyness if(reg1->IsEmpty()){ if(reg2->IsEmpty()){ // no more intersection possible if(useCluster){ return cluster.Contains(res); } else { return true; } }else{ res.SetEI(true); res.SetEB(true); if(useCluster){ return cluster.Contains(res); } else { return true; } } } if(reg2->IsEmpty()){ res.SetIE(true); res.SetBE(true); if(useCluster){ return cluster.Contains(res); } else { return true; } } // bounding box check Rectangle<2> bbox1 = reg1->BoundingBox(); Rectangle<2> bbox2 = reg2->BoundingBox(); if(!bbox1.IntersectsUD(bbox2)){ res.SetIE(true); res.SetEI(true); res.SetBE(true); res.SetEB(true); if(useCluster){ return cluster.Contains(res); } else{ return true; } } if(useCluster){ int cb = cluster.checkBoxes(bbox1, false, bbox2, false); if(cb==1) { return true; } if(cb==2){ return false; } cluster.Restrict(res,true,false); if(cluster.IsEmpty() ){ return false; } if(cluster.isExtension(res)){ return true; } } avltree::AVLTree sss; // sweep state structure // dynamic parts of the sweep event structure priority_queue, greater > q1; priority_queue, greater > q2; int pos1=0; // current position in the halfsegment array of reg1 int pos2=0; // current position in the halfsegment array of reg2 int size1 = reg1->Size(); int size2 = reg2->Size(); bool done = false; avlseg::ExtendedHalfSegment nextSeg; avlseg::AVLSegment* member=0; // current member stored in the tree avlseg::AVLSegment* leftN=0; // the left neightboor of member avlseg::AVLSegment* rightN=0; // the right neighbour of member avlseg::ownertype owner; OwnedPoint lastDomPoint; // initialized to be undefined int src =0; avlseg::AVLSegment tmpL,tmpR,tmpM; bool empty1 = false; bool empty2 = false; while(((owner=selectNext(*reg1, pos1, *reg2, pos2, q1,q2, nextSeg,src))!=avlseg::none) && !done){ avlseg::AVLSegment current(nextSeg,owner); member = sss.getMember(current,leftN,rightN); if(leftN){ tmpL = *leftN; leftN = &tmpL; } if(rightN){ tmpR = *rightN; rightN = &tmpR; } if(member){ tmpM = *member; member = &tmpM; } /* Because right events are processed before left events, we have to store the last dominating point to detect intersections of the boundaries within a single point. */ Point p = nextSeg.GetDomPoint(); empty1 = (pos1>=size1) && q1.empty() && (owner!=avlseg::first) && ( ((p.GetX()>lastDomPoint.p.GetX() && !AlmostEqual(p.GetX(),lastDomPoint.p.GetX())) || lastDomPoint.owner==avlseg::second)); empty2 = (pos2>=size2) && q2.empty() && (owner!=avlseg::second) && (( (p.GetX()>lastDomPoint.p.GetX() && !AlmostEqual(p.GetX(),lastDomPoint.p.GetX())) || lastDomPoint.owner==avlseg::first)); if(!lastDomPoint.defined || !AlmostEqual(lastDomPoint.p,p)){ lastDomPoint.defined = true; lastDomPoint.p = p; lastDomPoint.owner = owner; } else { // same point as before if(lastDomPoint.owner != owner){ SetBB(res,useCluster,cluster,done); } } if(nextSeg.IsLeftDomPoint()){ avlseg::AVLSegment left, common, right; if(member){ // there is an overlapping segment in the tree // check for valid region representation if(forceThrow){ if(member->getOwner() != current.getOwner()){ cerr << "overlapping segments within one region detected" << endl; cerr << "Segment 1 : " << member << endl; cerr << "Segment 2 : " << current << endl; cerr << "owner = " << member->getOwner() << endl; throw myexception("Overlapping segments " "within one region detected"); } if(member->getOwner() == avlseg::both){ cerr << "overlapping segments within one region detected" << endl; cerr << "Segment 1 : " << member << endl; cerr << "Segment 2 : " << current << endl; cerr << "owner = " << current.getOwner() << endl; throw myexception("Overlapping segments " "within one region detected"); } } assert(member->getOwner() != current.getOwner()); assert(member->getOwner() != avlseg::both); SetBB(res,useCluster,cluster,done); // common boundary found bool iac = current.getOwner()==avlseg::first ?current.getInsideAbove_first() :current.getInsideAbove_second(); bool iam = member->getOwner()==avlseg::first ?member->getInsideAbove_first() :member->getInsideAbove_second(); if(iac!=iam){ SetIE(res,useCluster,cluster,done); SetEI(res,useCluster,cluster,done); } else { SetII(res,useCluster,cluster,done); // res.setEE(true); // already done in initialization } int parts = member->split(current,left,common,right); sss.remove(*member); if(parts & avlseg::LEFT){ // there is a left part sss.insert(left); // simulates a left event. insertEvents(left,false,true,q1,q2); } assert(parts & avlseg::COMMON); // there must exist a common part // update con_above if(iac){ common.con_above++; } else { common.con_above--; } sss.insert(common); // insert the corresponding right event into one of the queues insertEvents(common,false,true,q1,q2); if(parts & avlseg::RIGHT) { // there is an exclusive right part // create the events for the remainder insertEvents(right,true,true,q1,q2); } /* Note: Here no check again the neighbours is performed because all parts inserted into sss here are part of this structure before inserting the removed element 'member'. */ } else{ // there is no overlapping segment // check crossing left if(leftN && leftN->crosses(current)){ // a inner intersection assert(leftN->getOwner()!=current.getOwner()); // computation of the intersections res.Fill(); done = true; if(useCluster){ return cluster.Contains(res); } else { return true; } } // check crossing right if(rightN && rightN->crosses(current)){ assert(rightN->getOwner()!=current.getOwner()); // computation of the intersections res.Fill(); done = true; if(useCluster){ return cluster.Contains(res); } else { return true; } } // check for disjointness with both neighbours if( ( !leftN || leftN->innerDisjoint(current)) && ( !rightN || rightN->innerDisjoint(current))){ // update coverage numbers bool iac = current.getOwner()==avlseg::first ?current.getInsideAbove_first() :current.getInsideAbove_second(); iac = current.getOwner()==avlseg::first ?current.getInsideAbove_first() :current.getInsideAbove_second(); 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; } } // derive intersections from the coverage numbers if(current.con_below == 0){ ; // EE is set already in initialization //res.SetEE(true); } else if (current.con_below == 1) { if(current.getInsideAbove()){ if(current.getOwner()==avlseg::first){ SetEI(res,useCluster,cluster,done); } else { SetIE(res,useCluster,cluster,done); } } else { if(current.getOwner()==avlseg::first){ SetIE(res,useCluster,cluster,done); } else { SetEI(res,useCluster,cluster,done); } } } else { assert(current.con_below==2); SetII(res,useCluster,cluster,done); } // check for possible common endpoints with the neighbours if(leftN && leftN->getOwner()!=current.getOwner()){ if(leftN->intersects(current)){ SetBB(res,useCluster,cluster,done); } } if(rightN && rightN->getOwner()!=current.getOwner()){ if(rightN->intersects(current)){ SetBB(res,useCluster,cluster,done); } } sss.insert(current); } else { // inner intersection with at least one neighbour // check for possible common points with the neighbours if(leftN && leftN->getOwner()!=current.getOwner()){ if(leftN->intersects(current)){ SetBB(res,useCluster,cluster,done); } } if(rightN && rightN->getOwner()!=current.getOwner()){ if(rightN->intersects(current)){ SetBB(res,useCluster,cluster,done); } } splitByNeighbour(sss,current,leftN,q1,q2, forceThrow); splitByNeighbour(sss,current,rightN,q1,q2, forceThrow); // insert current (may be shortened) into sss // update coverage numbers bool iac = current.getOwner()==avlseg::first? current.getInsideAbove_first() :current.getInsideAbove_second(); 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; } } // derive intersections from the coverage numbers if(current.con_below == 0){ ; // res.SetEE(true); // already done in initialization } else if (current.con_below == 1) { if(current.getInsideAbove()){ if(current.getOwner()==avlseg::first){ SetEI(res,useCluster,cluster,done); } else { SetIE(res,useCluster,cluster,done); } } else { if(current.getOwner()==avlseg::first){ SetIE(res,useCluster,cluster,done); } else { SetEI(res,useCluster,cluster,done); } } } else if(current.con_below==2){ SetII(res,useCluster,cluster,done); } else { cerr << "invalid value for con_below " << current.con_below << endl; if(!leftN){ cerr << "no predecessor found" << endl; } else { cerr << "Left= " << *leftN << endl; cerr << "extension : " << current.extends(*leftN) << endl; cerr << "vertical : " << leftN->isVertical() << endl; } assert(false); } assert(current.con_above>=0 && current.con_above<=2); assert(current.con_below + current.con_above > 0); sss.insert(current); } } } else { // right endpoint of an halfsegment if(member){ // element found in sss, may be an old splitted element // check if where member is located if(member->getOwner()!=avlseg::both){ // member is located in the interior or in the exterior of the // other region if(member->con_below==0 || member->con_above==0){ // in exterior switch(member->getOwner()){ case avlseg::first: SetBE(res,useCluster,cluster,done); SetIE(res,useCluster,cluster,done); //res.SetEE(true); break; case avlseg::second: SetEB(res,useCluster,cluster,done); SetEI(res,useCluster,cluster,done); //res.SetEE(true); break; default: assert(false); } } else if(member->con_below==2 || member->con_above==2){ //interior switch(member->getOwner()){ case avlseg::first: SetBI(res,useCluster,cluster,done); SetII(res,useCluster,cluster,done); SetEI(res,useCluster,cluster,done); break; case avlseg::second: SetIB(res,useCluster,cluster,done); SetII(res,useCluster,cluster,done); SetIE(res,useCluster,cluster,done); break; default: assert(false); } }else { assert(false); } } sss.remove(*member); if( leftN && rightN && !leftN->innerDisjoint(*rightN)){ if(leftN->crosses(*rightN)){ assert(leftN->getOwner() != rightN->getOwner()); res.Fill(); // we are done if(useCluster){ return cluster.Contains(res); } else { return true; } } splitNeighbours(sss,leftN,rightN,q1,q2, forceThrow); } } } if(res.IsFull()){ done = true; } if(useCluster){ done = done || cluster.IsEmpty(); } if(empty1 || empty2){ done = true; if(!empty1){ res.SetBE(true); res.SetIE(true); if(!res.GetBB()){ owner=selectNext(*reg1,pos1, *reg2,pos2, q1,q2,nextSeg,src); if(owner==avlseg::second && lastDomPoint.owner!=avlseg::second){ Point dP = nextSeg.GetDomPoint(); if(AlmostEqual(dP,lastDomPoint.p)){ res.SetBB(true); } } } } if(!empty2){ res.SetEB(true); res.SetEI(true); if(!res.GetBB()){ owner=selectNext(*reg1,pos1, *reg2,pos2, q1,q2,nextSeg,src); if(owner==avlseg::first && lastDomPoint.owner!=avlseg::first){ Point dP = nextSeg.GetDomPoint(); if(AlmostEqual(dP,lastDomPoint.p)){ res.SetBB(true); } } } } } } // sweep if(useCluster){ return cluster.Contains(res); } else { return true; } } // GetInt9M (region x region) /* ~updateDomPoints~ This functions does all the things caused by the next dominating point. This function only works correct with two line values. */ void updateDomPoints_Line_Line( Point& lastDomPoint, const Point& newDomPoint, int& lastDomPointCount1, int& lastDomPointCount2, avlseg::ownertype owner, Int9M& res, bool useCluster, Cluster& cluster, bool& done){ // update dominating point information int sum = lastDomPointCount1 + lastDomPointCount2; if( sum == 0 || !AlmostEqual(lastDomPoint,newDomPoint)){ // dominating point changed if(lastDomPointCount1 == 1){ if(lastDomPointCount2 == 1){ SetBB(res,useCluster,cluster,done); } else if(lastDomPointCount2>1){ SetBI(res,useCluster,cluster,done); } else { SetBE(res,useCluster,cluster,done); } } else if(lastDomPointCount1 > 1){ if(lastDomPointCount2 == 1){ SetIB(res,useCluster,cluster,done); } else if(lastDomPointCount2>1){ SetII(res,useCluster,cluster,done); } else { SetIE(res,useCluster,cluster,done); } } else { // lastDomPointCount1 == 0 if(lastDomPointCount2 == 1){ SetEB(res,useCluster,cluster,done); } else if(lastDomPointCount2>1){ SetEI(res,useCluster,cluster,done); } else { ; // SetEE(res,useCluster,cluster,done); } } // update dompoint and counter lastDomPoint = newDomPoint; switch(owner){ case avlseg::first: lastDomPointCount1 = 1; lastDomPointCount2 = 0; break; case avlseg::second: lastDomPointCount1 = 0; lastDomPointCount2 = 1; break; case avlseg::both: lastDomPointCount1 = 1; lastDomPointCount2 = 1; break; default : assert(false); } } else { // dominating point not changed switch(owner){ case avlseg::first : lastDomPointCount1++; break; case avlseg::second: lastDomPointCount2++; break; case avlseg::both : lastDomPointCount1++; lastDomPointCount2++; break; default : assert(false); } } } bool GetInt9M(Line const* const line1, Line const* const line2, Int9M& res, const bool useCluster=false, Cluster cluster = Cluster(), const bool forceThrow = false ){ // we can only ommit the planesweep if both lines are empty // disjointness of the lines is not sufficient to compute the // result completely because it's not known if one of the line has // any endpoints. For this reason, we ommit the bounding box check res.SetValue(0); res.SetEE(true); if(line1->IsEmpty() && line2->IsEmpty()){ if(useCluster){ return cluster.Contains(res); }else { return true; // no further intersections can be found } } bool done = false; if(useCluster){ int cb = cluster.checkBoxes(line1->BoundingBox(),line1->IsEmpty(), line2->BoundingBox(),line2->IsEmpty()); if(cb==1) { return true; } if(cb==2){ return false; } } if(line1->IsEmpty()){ // line2 is non empty SetEI(res,useCluster,cluster,done); if(useCluster){ Int9M m(false,false,false, false,false,false, true,true,true); cluster.Restrict(m,false,false); } } if(line2->IsEmpty()){ SetIE(res,useCluster,cluster,done); if(useCluster){ Int9M m(false, false, true, false,false,true, false,false,true); cluster.Restrict(m,false,false); } } if(!line1->IsEmpty() && !line2->IsEmpty()){ if(!line1->BoundingBox().Intersects(line2->BoundingBox()) && useCluster){ Int9M m(false,false,true,false,false,true,true,true,true); cluster.Restrict(m,false,false); } } if(useCluster){ if(cluster.IsEmpty()){ return false; } if(cluster.isExtension(res)){ return true; } } // initialise the sweep state structure avltree::AVLTree sss; // initialize priority queues for remaining parts of splitted // segments priority_queue, greater > q1; priority_queue, greater > q2; int pos1=0; int pos2=0; int size1 = line1->Size(); int size2 = line2->Size(); avlseg::ExtendedHalfSegment nextHs; avlseg::ownertype owner; avlseg::AVLSegment* leftN=0; avlseg::AVLSegment* rightN=0; avlseg::AVLSegment* member=0; Point lastDomPoint; int lastDomPointCount1 = 0; int lastDomPointCount2 = 0; avlseg::AVLSegment left1,right1,left2,right2,common; int src=0; avlseg::AVLSegment tmpL,tmpR; bool empty1 = false; // flag indicating end of line 1 bool empty1eval = false; // empty1 already evaluated bool empty2 = false; bool empty2eval = false; while(!done && ((owner=selectNext(*line1,pos1,*line2, pos2,q1,q2,nextHs,src))!=avlseg::none) ){ avlseg::AVLSegment current(nextHs,owner); // debug::start // cout << "process segment " << current << " " // << (nextHs.IsLeftDomPoint() // ?"avlseg::avlseg::LEFT" // :"avlseg::RIGHT") << endl; // debug::end empty1 = pos1>=size1 && q1.empty() && lastDomPointCount1==0 && owner!=avlseg::first; empty2 = pos2>=size2 && q2.empty() && lastDomPointCount2==0 && owner!=avlseg::second; // try to find an overlapping segment in sss member = sss.getMember(current,leftN,rightN); if(leftN){ tmpL = *leftN; leftN = &tmpL; } if(rightN){ tmpR = *rightN; rightN = &tmpR; } if(nextHs.IsLeftDomPoint()){ // left event if(member){ // overlapping segment found in sss if(member->getOwner()==avlseg::both || member->getOwner()==owner){ // member and owner comes from the same line // create events for the remaining part if(!AlmostEqual(member->getX2(),current.getX2()) && current.getX2() > member->getX2()){ // current is an extension of member current.splitAt(member->getX2(),member->getY2(),left1,right1); insertEvents(right1,true,true,q1,q2); } // otherwise we can ignore current } else { // owner of member and current are different // there is a common inner part SetII(res,useCluster,cluster,done); int parts = member->split(current, left1, common, right1); // remove the old entry in sss sss.remove(*member); member = &common; // insert left and common to sss if(parts&avlseg::LEFT){ bool ok = sss.insert(left1); assert(ok); insertEvents(left1,false,true,q1,q2); } assert(parts & avlseg::COMMON); bool ok = sss.insert(common); assert(ok); insertEvents(common,false,true,q1,q2); // create events for right if(parts & avlseg::RIGHT){ insertEvents(right1,true,true,q1,q2); } Point newDomPoint = nextHs.GetDomPoint(); avlseg::ownertype owner2 = owner; if(parts & avlseg::LEFT){ owner2 = avlseg::both; } updateDomPoints_Line_Line(lastDomPoint,newDomPoint, lastDomPointCount1,lastDomPointCount2,owner2, res, useCluster, cluster, done); } } else { // no overlapping segment stored in sss splitByNeighbour(sss,current,leftN,q1,q2, forceThrow); splitByNeighbour(sss,current,rightN,q1,q2, forceThrow); updateDomPoints_Line_Line(lastDomPoint,nextHs.GetDomPoint(), lastDomPointCount1, lastDomPointCount2, owner,res,useCluster,cluster,done); bool ok = sss.insert(current); assert(ok); } } else { // right Event // check if current is stored in sss if(member && member->exactEqualsTo(current)){ Point newDomPoint = nextHs.GetDomPoint(); updateDomPoints_Line_Line(lastDomPoint,newDomPoint, lastDomPointCount1,lastDomPointCount2, member->getOwner(), res, useCluster, cluster, done); avlseg::AVLSegment copy(*member); sss.remove(current); member = © switch(member->getOwner()){ case avlseg::first: SetIE(res,useCluster,cluster,done); break; case avlseg::second: SetEI(res,useCluster,cluster,done); break; case avlseg::both : SetII(res,useCluster,cluster,done); break; default: assert(false); } splitNeighbours(sss,leftN,rightN,q1,q2, forceThrow); } // otherwise current comes from a splitted segment and is ignored } done = done || res.IsFull(); if(empty1) { // end of line1 reached if(res.GetEI() && res.GetEB()){ done = true; } else if(useCluster && !empty1eval){ Int9M tmp = res; tmp.SetEI(true); tmp.SetEB(true); cluster.Restrict(tmp,false,false); if(cluster.IsEmpty()){ return false; } } } if(empty2) { // end of line1 reached if(res.GetIE() && res.GetBE()){ done = true; } else if(useCluster && !empty2eval){ Int9M tmp = res; tmp.SetIE(true); tmp.SetBE(true); cluster.Restrict(tmp,false,false); if(cluster.IsEmpty()){ return false; } } } } // end of sweep // create a point which is different to the last domPoint Point newDP(lastDomPoint); newDP.Translate(100,0); updateDomPoints_Line_Line(lastDomPoint, newDP, lastDomPointCount1, lastDomPointCount2, avlseg::first,res,useCluster,cluster,done); if(useCluster){ return cluster.Contains(res); } else { return true; } } // line x line /* ~updateDomPointInfo[_]Line[_]Region~ Does the things required by the switch from ~lastDomPoint~ to ~newDomPoint~. */ void updateDomPointInfo_Line_Region(Point& lastDomPoint, const Point& newDomPoint, int& count_line, int& count_region, int& lastCoverage_Num, const int newCoverageNum, const avlseg::ownertype owner, Int9M& res, const bool useCluster, Cluster& cluster, bool& done){ int sum = count_line + count_region; if(sum == 0 || !AlmostEqual(newDomPoint,lastDomPoint)){ // dominating point changed if(count_line==0) { // exterior of the line if(count_region>0){ // boundary of the region SetEB(res,useCluster,cluster,done); } else { ; // SetEE(res,useCluster,cluster,done); } } else if(count_line == 1) { // boundary of the line if(count_region>0){ // boundary of the region SetBB(res,useCluster,cluster,done); } else { if(lastCoverage_Num==0){ SetBE(res,useCluster,cluster,done); } else { SetBI(res,useCluster,cluster,done); } } } else { // interior of the line if(count_region > 0){ SetIB(res,useCluster,cluster,done); } else { if(lastCoverage_Num==0){ SetIE(res,useCluster,cluster,done); } else { SetII(res,useCluster,cluster,done); } } } lastDomPoint = newDomPoint; switch(owner){ case avlseg::first : count_line = 1; count_region = 0; break; case avlseg::second: count_line = 0; count_region = 1; break; case avlseg::both : count_line = 1; count_region = 1; break; default : assert(false); } } else { // dompoint was not changed switch(owner){ case avlseg::first : count_line++; break; case avlseg::second: count_region++; break; case avlseg::both : count_line++; count_region++; break; default : assert(false); } } lastCoverage_Num = newCoverageNum; } /* ~GetInt9M~ ~line~ [x] ~region~ */ bool GetInt9M(Line const* const line, Region const* const region, Int9M& res, const bool useCluster=false, Cluster cluster = Cluster(), const bool forceThrow = false){ res.SetValue(0); res.SetEE(true); if(line->IsEmpty()){ if(region->IsEmpty()){ if(useCluster){ return cluster.Contains(res); } else { return true; } } else { res.SetEI(true); res.SetEB(true); res.SetEE(true); if(useCluster){ return cluster.Contains(res); } else { return true; } } } if(!region->IsEmpty()){ res.SetEI(true); } Rectangle<2> bbox1 = line->BoundingBox(); Rectangle<2> bbox2 = region->BoundingBox(); if(useCluster){ int cb = cluster.checkBoxes(bbox1, line->IsEmpty(), bbox2, region->IsEmpty()); if(cb==1) { return true; } if(cb==2){ return false; } cluster.Restrict(res,true,false); if(cluster.IsEmpty() ){ return false; } if(cluster.isExtension(res)){ return true; } } if(!bbox1.IntersectsUD(bbox2)){ res.SetIE(true); // line is not empty if(!region->IsEmpty()){ res.SetEB(true); } if(useCluster){ Int9M m(false,false,true, false, false, true, true,true,true); cluster.Restrict(m,false,false); } } if(useCluster){ cluster.Restrict(res,true,false); if(region->IsEmpty()){ Int9M m(false,false,true,false,false,true,false,false,true); cluster.Restrict(m,false,false); } if(cluster.IsEmpty()){ return false; } if(cluster.isExtension(res)){ return true; } } // initialise the sweep state structure avltree::AVLTree sss; // initialize priority queues for remaining parts of splitted // segments priority_queue, greater > q1; priority_queue, greater > q2; int pos1=0; int pos2=0; bool done = false; avlseg::ExtendedHalfSegment nextHs; avlseg::ownertype owner; avlseg::AVLSegment* leftN=0; avlseg::AVLSegment* rightN=0; avlseg::AVLSegment* member=0; Point lastDomPoint; int lastDomPointCount1 = 0; int lastDomPointCount2 = 0; avlseg::AVLSegment left1,right1,left2,right2,common; avlseg::AVLSegment tmpL,tmpR; int src=0; int lastCoverageNum = 0; // plane sweep while(!done && ((owner=selectNext(*line,pos1,*region, pos2,q1,q2,nextHs,src))!=avlseg::none)){ avlseg::AVLSegment current(nextHs,owner); member = sss.getMember(current,leftN,rightN); if(leftN){ tmpL = *leftN; leftN = &tmpL; } if(rightN){ tmpR = *rightN; rightN = &tmpR; } avlseg::ownertype owner2 = owner; if(nextHs.IsLeftDomPoint()){ // left end point if(member){ // overlapping segment found if(member->getOwner()==avlseg::both || member->getOwner()==owner){ // current is part of member if( (member->getX2() < current.getX2()) && !AlmostEqual(member->getX2(), current.getX2())){ current.splitAt(member->getX2(),member->getY2(),left1,right1); insertEvents(right1,true,true,q1,q2); } // otherwise there is nothing to do } else { // stored segment come from the other spatial object SetIB(res,useCluster,cluster,done); int parts = member->split(current,left1,common,right1); sss.remove(*member); member = &common; if(parts & avlseg::LEFT){ sss.insert(left1); insertEvents(left1,false,true,q1,q2); } assert(parts & avlseg::COMMON); // update coverage numbers if(owner==avlseg::first){ // the line common.con_below = member->con_below; common.con_above = member->con_above; } else { // a region common.con_below = member->con_below; if(current.isVertical()){ common.con_above = current.con_below; } else { // non-vertical if(nextHs.attr.insideAbove){ common.con_above = common.con_below +1; } else { common.con_above = common.con_below -1; } } } assert(current.con_below + current.con_above >= 0); assert(current.con_below + current.con_above <= 1); sss.insert(common); insertEvents(common,false,true,q1,q2); if(parts & avlseg::RIGHT){ insertEvents(right1,true,true,q1,q2); } if(parts & avlseg::LEFT){ // this dominating point comes from both // halfsegments owner2 = avlseg::both; } // update counter for dominating points Point domPoint = nextHs.GetDomPoint(); updateDomPointInfo_Line_Region(lastDomPoint, domPoint, lastDomPointCount1, lastDomPointCount2, lastCoverageNum,current.con_below, owner2,res, useCluster, cluster, done); } } else { // no overlapping segment found // check if current or an existing segment must be divided splitByNeighbour(sss,current,leftN,q1,q2, forceThrow); splitByNeighbour(sss,current,rightN,q1,q2, forceThrow); // update coverage numbers if(owner==avlseg::second){ // 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(current.extends(*leftN)){ current.con_below = leftN->con_below; current.con_above = leftN->con_above; } else if(leftN->isVertical()){ current.con_below = leftN->con_below; } else { current.con_below = leftN->con_above; } } else { // no left neighbour found current.con_below = 0; } current.con_above = current.con_below; } // update dominating points Point domPoint = nextHs.GetDomPoint(); updateDomPointInfo_Line_Region(lastDomPoint, domPoint, lastDomPointCount1, lastDomPointCount2, lastCoverageNum, current.con_below, owner2, res, useCluster, cluster, done); sss.insert(current); } } else { // right event if(member && member->exactEqualsTo(current)){ avlseg::AVLSegment tmp = *member; sss.remove(*member); member = &tmp; splitNeighbours(sss,leftN,rightN,q1,q2, forceThrow); // update dominating point information Point domPoint = nextHs.GetDomPoint(); updateDomPointInfo_Line_Region(lastDomPoint, domPoint, lastDomPointCount1, lastDomPointCount2, lastCoverageNum, member->con_below, member->getOwner(), res, useCluster,cluster, done); // detect intersections switch(member->getOwner()){ case avlseg::first : if(member->con_above==0){ // the line SetIE(res,useCluster,cluster,done); } else { SetII(res,useCluster,cluster,done); } break; case avlseg::second: SetEB(res,useCluster,cluster,done); break; case avlseg::both : SetIB(res,useCluster,cluster,done); break; default : assert(false); } } } } // sweep done, check the last dominating point Point domPoint(lastDomPoint); domPoint.Translate(100,0); updateDomPointInfo_Line_Region(lastDomPoint,domPoint, lastDomPointCount1, lastDomPointCount2, lastCoverageNum, 0, avlseg::both, res, useCluster, cluster,done); if(useCluster){ return cluster.Contains(res); } else { return true; } } /* 8 Integrating Operators in [secondo] 8.1 Type Mapping Functions */ /* ~TopPredTypeMap~ This function is the type mapping for the ~toppred~ operator. The signature of this operator is: t1 [x] t2 [x] cluster [->] bool where t1, t2 in [{]point, points, line, region[}]. */ ListExpr TopPredTypeMap(ListExpr args){ if(nl->ListLength(args)!=3){ ErrorReporter::ReportError("three arguments required"); return nl->TypeError(); } ListExpr cl = nl->Third(args); if(!nl->IsEqual(cl,"cluster")){ ErrorReporter::ReportError("the third argument must" " be of type cluster\n"); return nl->TypeError(); } ListExpr o1 = nl->First(args); ListExpr o2 = nl->Second(args); if(!IsSpatialType(o1)){ ErrorReporter::ReportError("The first argument must be a spatial type"); return nl->TypeError(); } if(!IsSpatialType(o2)){ ErrorReporter::ReportError("The second argument" " must be a spatial type"); return nl->TypeError(); } return nl->SymbolAtom(CcBool::BasicType()); } /* ~TopRelTypeMap~ This function is the type mapping for the ~toprel~ operator. The signature is t1 [x] t2 [->] int9m where t1, t2 in [{]point, points, line, region[}] */ ListExpr TopRelTypeMap(ListExpr args){ if(nl->ListLength(args)!=2){ ErrorReporter::ReportError("two arguments expected"); return nl->TypeError(); } if(!IsSpatialType(nl->First(args)) || !IsSpatialType(nl->Second(args))){ ErrorReporter::ReportError("Spatial types expected"); return (nl->TypeError()); } return nl->SymbolAtom("int9m"); } /* ~StdPredTypeMap~ t1 [x] t2 [->] bool, where t1,t2 in [{]point, points, line, region[}]. */ ListExpr StdPredTypeMap(ListExpr args){ if(nl->ListLength(args)!=2){ ErrorReporter::ReportError("two arguments expected"); return nl->SymbolAtom(Symbol::TYPEERROR()); } if(!IsSpatialType(nl->First(args)) || !IsSpatialType(nl->Second(args))){ ErrorReporter::ReportError("Spatial types expected"); return (nl->TypeError()); } return nl->SymbolAtom(CcBool::BasicType()); } /* 8.2 Value Mappings ~TopRel~ This value mapping can be instantiated with all combinations where a function ~GetInt9M~ exists for the type combination ~type1~ [x] ~type2~. */ template int TopRel(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); type1* p1 = static_cast(args[0].addr); type2* p2 = static_cast(args[1].addr); Int9M matrix; GetInt9M(p1,p2,matrix); *(static_cast(result.addr)) = matrix; return 0; } /* This function is symmetrical to the ~TopRel~ function. This function avoids the implementation of symmetric ~GetInt9M~ functions. */ template int TopRelSym(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); type1* p1 = static_cast(args[0].addr); type2* p2 = static_cast(args[1].addr); Int9M matrix(0); GetInt9M(p2,p1,matrix); matrix.Transpose(); *(static_cast(result.addr))=matrix; // correct the swapping return 0; } /* Value Mapping for the ~toppred~ operator */ template int TopPred(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); t1* v1 = static_cast(args[0].addr); t2* v2 = static_cast(args[1].addr); Cluster* cluster = static_cast(args[2].addr); if(!cluster->IsDefined() || !v1->IsDefined() || !v2->IsDefined()){ (static_cast(result.addr))->Set(false,false); return 0; } Int9M matrix; try{ bool res = GetInt9M(v1,v2,matrix,true,*cluster); (static_cast(result.addr))->Set(true,res); } catch(...){ cerr << "Toppred failed, set to undefined, TODO: robust toppred" << endl; (static_cast(result.addr))->Set(false,false); } return 0; } /* As for the ~toprel~ opererator there is a symmetric value mapping. */ template int TopPredSym(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); t1* v1 = static_cast(args[0].addr); t2* v2 = static_cast(args[1].addr); Cluster* cluster = static_cast(args[2].addr); if(!cluster->IsDefined()){// name not found within group (static_cast(result.addr))->Set(false,false); return 0; } Int9M matrix; Cluster tmp(cluster); tmp.Transpose(); bool res = GetInt9M(v2,v1,matrix,true,tmp); (static_cast(result.addr))->Set(true,res); return 0; } template int TopPredSym2(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); t1* v1 = static_cast(args[0].addr); t2* v2 = static_cast(args[1].addr); Cluster* cluster = static_cast(args[2].addr); if(!cluster->IsDefined()){// name not found within group (static_cast(result.addr))->Set(false,false); return 0; } Int9M matrix; bool res = GetInt9M(v2,v1,matrix,true,*cluster,true); (static_cast(result.addr))->Set(true,res); return 0; } /* ~Standard Topological Predicates~ In the following section, we define predicates implementing our imagination of topological predicates. They can be used without an explicit definition of a cluster. */ /* ~Standard Cluster~ For each standard predicate, we hold a variable of type cluster. The variables are initialized once at the algebra initialization. */ static Cluster cl_disjoint; static Cluster cl_adjacent; static Cluster cl_overlap; static Cluster cl_covers; static Cluster cl_coveredBy; static Cluster cl_inside; static Cluster cl_contains; static Cluster cl_equal; static Cluster cl_wcontains; // contains || covers /* Value Mappings for standard predicates */ template int StdPred(Word* args, Word& result, int message, Word& local, Supplier s, Cluster& cl){ result = qp->ResultStorage(s); t1* v1 = static_cast(args[0].addr); t2* v2 = static_cast(args[1].addr); Int9M matrix; bool res = GetInt9M(v1,v2,matrix,true,cl); (static_cast(result.addr))->Set(true,res); return 0; } bool overlaps(Region* r1, Region* r2){ Int9M matrix; return GetInt9M(r1, r2, matrix, true, cl_overlap); } template int StdPredSym(Word* args, Word& result, int message, Word& local, Supplier s, Cluster& cl){ result = qp->ResultStorage(s); t1* v1 = static_cast(args[0].addr); t2* v2 = static_cast(args[1].addr); Int9M matrix; Cluster tmp(cl); tmp.Transpose(); bool res = GetInt9M(v2,v1,matrix,true,tmp); (static_cast(result.addr))->Set(true,res); return 0; } template int TrAdjacentVM(Word* args, Word& result, int message, Word& local, Supplier s){ return StdPred(args,result,message,local,s,cl_adjacent); } template int TrAdjacentVMSymm(Word* args, Word& result, int message, Word& local, Supplier s){ return StdPredSym(args,result,message,local,s,cl_adjacent); } template int TrInsideVM(Word* args, Word& result, int message, Word& local, Supplier s){ return StdPred(args,result,message,local,s,cl_inside); } template int TrInsideVMSymm(Word* args, Word& result, int message, Word& local, Supplier s){ return StdPredSym(args,result,message,local,s,cl_inside); } template int TrCoversVM(Word* args, Word& result, int message, Word& local, Supplier s){ return StdPred(args,result,message,local,s,cl_covers); } template int TrCoversVMSymm(Word* args, Word& result, int message, Word& local, Supplier s){ return StdPredSym(args,result,message,local,s,cl_covers); } template int TrCoveredByVM(Word* args, Word& result, int message, Word& local, Supplier s){ return StdPred(args,result,message,local,s,cl_coveredBy); } template int TrCoveredByVMSymm(Word* args, Word& result, int message, Word& local, Supplier s){ return StdPredSym(args,result,message,local,s,cl_coveredBy); } template int TrEqualVM(Word* args, Word& result, int message, Word& local, Supplier s){ return StdPred(args,result,message,local,s,cl_equal); } template int TrEqualVMSymm(Word* args, Word& result, int message, Word& local, Supplier s){ return StdPredSym(args,result,message,local,s,cl_equal); } template int TrDisjointVM(Word* args, Word& result, int message, Word& local, Supplier s){ return StdPred(args,result,message,local,s,cl_disjoint); } template int TrDisjointVMSymm(Word* args, Word& result, int message, Word& local, Supplier s){ return StdPredSym(args,result,message,local,s,cl_disjoint); } template int TrOverlapVM(Word* args, Word& result, int message, Word& local, Supplier s){ return StdPred(args,result,message,local,s,cl_overlap); } template int TrOverlapVMSymm(Word* args, Word& result, int message, Word& local, Supplier s){ return StdPredSym(args,result,message,local,s,cl_overlap); } template int TrContainsVM(Word* args, Word& result, int message, Word& local, Supplier s){ return StdPred(args,result,message,local,s,cl_contains); } template int TrContainsVMSymm(Word* args, Word& result, int message, Word& local, Supplier s){ return StdPredSym(args,result,message,local,s,cl_contains); } /* ~initClusters~ This function initializes the standard clusters. */ static void initClusters(){ PredicateGroup pg(0); pg.SetToDefault(); Cluster* cl = pg.GetClusterOf("disjoint"); assert(cl); cl_disjoint = *cl; delete cl; cl = pg.GetClusterOf("meet"); assert(cl); cl_adjacent = *cl; delete cl; cl = pg.GetClusterOf("overlap"); assert(cl); cl_overlap = *cl; delete cl; cl = pg.GetClusterOf("covers"); assert(cl); cl_covers = *cl; delete cl; cl = pg.GetClusterOf("coveredBy"); assert(cl); cl_coveredBy = *cl; delete cl; cl = pg.GetClusterOf("inside"); assert(cl); cl_inside = *cl; delete cl; cl = pg.GetClusterOf("contains"); assert(cl); cl_contains = *cl; delete cl; cl = pg.GetClusterOf("equal"); assert(cl); cl_equal = *cl; delete cl; cl_wcontains = cl_contains; cl_wcontains.Union(&cl_covers); } /* 9.3 Operator Specifications Here, the operator descriptions are defined. */ const string TopRelSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( {point, points, line, region} x " " {points, points, line, region} -> int9m " " \" toprel(_ _) \" " " computes the 9 intersection matrix describing the" " topological relationship between the arguments" " \" query toprel(reg1, reg2) \" ))"; const string TopPredSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( so1 x so2 x cluster -> bool " " where o1, o2 in {point, points, line, region}" " \" topred(_, _, _) \" " " checks whether the topological relationship between" " the spatial objects is part of the cluster " " \" query toppred(l1,r1,cl_equals) \" ))"; const string TrAdjacentSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( t1 x t2 -> bool, t1,t2 in {point, points, line, region}" " \" _ tradjacent _ \" " " checks whether the arguments have exacly a common border " " \" query r1 tradjacent r2 \" ))"; const string TrInsideSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( t1 x t2 -> bool, t1,t2 in {point, points, line, region}" " \" _ trinside _ \" " " checks whether the first argument is" " part of the second one " " \" query r1 trinside r2 \" ))"; const string TrContainsSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( t1 x t2 -> bool, t1,t2 in {point, points, line, region}" " \" _ trcontains _ \" " " checks whether the second argument is part of" " the first one " " \" query r1 trcontains r2 \" ))"; const string TrCoversSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( t1 x t2 -> bool, t1,t2 in {point, points, line, region}" " \" _ trcovers _ \" " " checks whether the first argument is part of the second one and" " the boundaries touches each other " " \" query r1 trcovers r2 \" ))"; const string TrCoveredBySpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( t1 x t2 -> bool, t1,t2 in {point, points, line, region}" " \" _ trcoveredby _ \" " " checks whether the second argument is part of the first one and" " the boundaries touches each other " " \" query r1 trcoveredby r2 \" ))"; const string TrEqualSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( t1 x t2 -> bool, t1,t2 in {point, points, line, region}" " \" _ trequal _ \" " " checks whether the arguments have the same geometry " " \" query r1 trequal r2 \" ))"; const string TrOverlapSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( t1 x t2 -> bool, t1,t2 in {point, points, line, region}" " \" _ toverlap _ \" " " checks whether the arguments have a common part ans " "also exclusive ones " " \" query r1 troverlaps r2 \" ))"; const string TrDisjointSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( t1 x t2 -> bool, t1,t2 in {point, points, line, region}" " \" _ trdisjoint _ \" " " checks if the arguments have no common part " " \" query r1 trdisjoint r2 \" ))"; /* 8.4 Value Mapping Arrays The following arrays collect the value mappings to enable overloaded operations. */ ValueMapping TopRelMap[] = { TopRel , TopRel, TopRelSym, TopRel, TopRel, TopRelSym,TopRel,TopRelSym, TopRel,TopRelSym, TopRel, TopRelSym,TopRel, TopRel, TopRel, TopRelSym}; ValueMapping TopPredMap[] = { TopPred , TopPred, TopPredSym, TopPred, TopPred, TopPredSym, TopPred, TopPredSym, TopPred, TopPredSym, TopPred, TopPredSym, TopPred, TopPred, TopPred, TopPredSym }; ValueMapping AdjacentMap[] = { TrAdjacentVM , TrAdjacentVM, TrAdjacentVMSymm, TrAdjacentVM, TrAdjacentVM, TrAdjacentVMSymm, TrAdjacentVM, TrAdjacentVMSymm, TrAdjacentVM, TrAdjacentVMSymm, TrAdjacentVM, TrAdjacentVMSymm, TrAdjacentVM, TrAdjacentVM, TrAdjacentVM, TrAdjacentVMSymm}; ValueMapping InsideMap[] = { TrInsideVM , TrInsideVM, TrInsideVMSymm, TrInsideVM, TrInsideVM, TrInsideVMSymm, TrInsideVM, TrInsideVMSymm, TrInsideVM, TrInsideVMSymm, TrInsideVM, TrInsideVMSymm, TrInsideVM, TrInsideVM, TrInsideVM, TrInsideVMSymm}; ValueMapping CoversMap[] = { TrCoversVM , TrCoversVM, TrCoversVMSymm, TrCoversVM, TrCoversVM, TrCoversVMSymm, TrCoversVM, TrCoversVMSymm, TrCoversVM, TrCoversVMSymm, TrCoversVM, TrCoversVMSymm, TrCoversVM, TrCoversVM, TrCoversVM, TrCoversVMSymm}; ValueMapping CoveredByMap[] = { TrCoveredByVM , TrCoveredByVM, TrCoveredByVMSymm, TrCoveredByVM, TrCoveredByVM, TrCoveredByVMSymm, TrCoveredByVM, TrCoveredByVMSymm, TrCoveredByVM, TrCoveredByVMSymm, TrCoveredByVM, TrCoveredByVMSymm, TrCoveredByVM, TrCoveredByVM, TrCoveredByVM, TrCoveredByVMSymm}; ValueMapping EqualMap[] = { TrEqualVM , TrEqualVM, TrEqualVMSymm, TrEqualVM, TrEqualVM, TrEqualVMSymm, TrEqualVM, TrEqualVMSymm, TrEqualVM, TrEqualVMSymm, TrEqualVM, TrEqualVMSymm, TrEqualVM, TrEqualVM, TrEqualVM, TrEqualVMSymm}; ValueMapping DisjointMap[] = { TrDisjointVM , TrDisjointVM, TrDisjointVMSymm, TrDisjointVM, TrDisjointVM, TrDisjointVMSymm, TrDisjointVM, TrDisjointVMSymm, TrDisjointVM, TrDisjointVMSymm, TrDisjointVM, TrDisjointVMSymm, TrDisjointVM, TrDisjointVM, TrDisjointVM, TrDisjointVMSymm}; ValueMapping OverlapMap[] = { TrOverlapVM , TrOverlapVM, TrOverlapVMSymm, TrOverlapVM, TrOverlapVM, TrOverlapVMSymm, TrOverlapVM, TrOverlapVMSymm, TrOverlapVM, TrOverlapVMSymm, TrOverlapVM, TrOverlapVMSymm, TrOverlapVM, TrOverlapVM, TrOverlapVM, TrOverlapVMSymm}; ValueMapping ContainsMap[] = { TrContainsVM , TrContainsVM, TrContainsVMSymm, TrContainsVM, TrContainsVM, TrContainsVMSymm, TrContainsVM, TrContainsVMSymm, TrContainsVM, TrContainsVMSymm, TrContainsVM, TrContainsVMSymm, TrContainsVM, TrContainsVM, TrContainsVM, TrContainsVMSymm}; /* 8.5 Selection Functions */ static int TopOpsSelect(ListExpr args){ string type1 = nl->SymbolValue(nl->First(args)); string type2 = nl->SymbolValue(nl->Second(args)); if( (type1==Point::BasicType()) && (type2==Point::BasicType())){ return 0; } if( (type1==Points::BasicType()) && (type2==Point::BasicType())){ return 1; } if((type1==Point::BasicType()) && (type2==Points::BasicType())){ return 2; } if((type1==Points::BasicType()) && (type2==Points::BasicType())){ return 3; } if((type1==Line::BasicType()) && (type2==Point::BasicType())){ return 4; } if((type1==Point::BasicType()) && (type2==Line::BasicType())){ return 5; } if((type1==Line::BasicType()) && (type2==Points::BasicType())){ return 6; } if((type1==Points::BasicType()) && (type2==Line::BasicType())){ return 7; } if((type1==Region::BasicType()) && (type2==Point::BasicType())){ return 8; } if((type1==Point::BasicType()) && (type2==Region::BasicType())){ return 9; } if( type1==Region::BasicType() && (type2==Points::BasicType())){ return 10; } if(type1==Points::BasicType() && (type2==Region::BasicType())){ return 11; } if(type1==Region::BasicType() && (type2==Region::BasicType())){ return 12; } if( (type1==Line::BasicType()) && (type2==Line::BasicType())){ return 13; } if( (type1==Line::BasicType()) && (type2==Region::BasicType())){ return 14; } if( (type1==Region::BasicType()) && (type2==Line::BasicType())){ return 15; } return -1; } /* 8.6 Creating Instances of Operators In this section instances of the algebra operators are built. */ Operator optoprel( "toprel", // name TopRelSpec, // specification sizeof(TopRelMap)/sizeof(ValueMapping), // number of functions TopRelMap, // array of value mappings TopOpsSelect, TopRelTypeMap ); Operator toppred( "toppred", // name TopPredSpec, // specification sizeof(TopPredMap)/sizeof(ValueMapping), // number of functions TopPredMap, // array of value mappings TopOpsSelect, TopPredTypeMap ); Operator trAdjacent( "tradjacent", // name TrAdjacentSpec, // specification sizeof(AdjacentMap)/sizeof(ValueMapping), // number of functions AdjacentMap, // array of value mappings TopOpsSelect, StdPredTypeMap ); Operator trContains( "trcontains", // name TrContainsSpec, // specification sizeof(ContainsMap)/sizeof(ValueMapping), // number of functions ContainsMap, // array of value mappings TopOpsSelect, StdPredTypeMap ); Operator trOverlap( "troverlaps", // name TrOverlapSpec, // specification sizeof(OverlapMap)/sizeof(ValueMapping), // number of functions OverlapMap, // array of value mappings TopOpsSelect, StdPredTypeMap ); Operator trDisjoint( "trdisjoint", // name TrDisjointSpec, // specification sizeof(DisjointMap)/sizeof(ValueMapping), // number of functions DisjointMap, // array of value mappings TopOpsSelect, StdPredTypeMap ); Operator trEqual( "trequal", // name TrEqualSpec, // specification sizeof(EqualMap)/sizeof(ValueMapping), // number of functions EqualMap, // array of value mappings TopOpsSelect, StdPredTypeMap ); Operator trCoveredBy( "trcoveredby", // name TrCoveredBySpec, // specification sizeof(CoveredByMap)/sizeof(ValueMapping), // number of functions CoveredByMap, // array of value mappings TopOpsSelect, StdPredTypeMap ); Operator trCovers( "trcovers", // name TrCoversSpec, // specification sizeof(CoversMap)/sizeof(ValueMapping), // number of functions CoversMap, // array of value mappings TopOpsSelect, StdPredTypeMap ); Operator trInside( "trinside", // name TrInsideSpec, // specification sizeof(InsideMap)/sizeof(ValueMapping), // number of functions InsideMap, // array of value mappings TopOpsSelect, StdPredTypeMap ); /* 8.7 Creating the Algebra */ class TopOpsAlgebra : public Algebra { public: TopOpsAlgebra() : Algebra() { AddOperator(&optoprel); AddOperator(&toppred); AddOperator(&trAdjacent); AddOperator(&trInside); AddOperator(&trCovers); AddOperator(&trCoveredBy); AddOperator(&trEqual); AddOperator(&trDisjoint); AddOperator(&trOverlap); AddOperator(&trContains); } ~TopOpsAlgebra(){} }; /* Functions exported in the header file. */ bool wcontains(const Region* reg1, const Region* reg2){ Int9M dummy; return topops::GetInt9M(reg1, reg2, dummy, true, topops::cl_wcontains); } } // end of namespace topops /* 8.8 Initialization of the Algebra */ extern "C" Algebra* InitializeTopOpsAlgebra( NestedList* nlRef, QueryProcessor* qpRef ) { nl = nlRef; qp = qpRef; topops::initClusters(); return (new topops::TopOpsAlgebra()); }