/* ---- This file is part of SECONDO. Copyright (C) 2004, University in Hagen, Department of Computer Science, Database Systems for New Applications. SECONDO is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. SECONDO is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with SECONDO; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ---- 1 Implementation of AVLSegment */ #include "SpatialAlgebra.h" #include "AVLSegment.h" #include "RobustSetOps.h" #include #include using namespace std; /* ~Shift~ Operator for ~ownertype~ */ ostream& avlseg::operator<<(ostream& o, const avlseg::ownertype& owner){ switch(owner){ case avlseg::none : o << "none" ; break; case avlseg::first : o << "first"; break; case avlseg::second : o << "second"; break; case avlseg::both : o << "both"; break; default : assert(false); } return o; } ostream& operator<<(ostream& o, const avlseg::ExtendedHalfSegment& hs) { return hs.Print(o); } bool PointOnSegment(double x, double y, double x1, double y1, double x2, double y2){ double len = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)); double len1 = sqrt((x1-x)*(x1-x) + (y1-y)*(y1-y)); double len2 = sqrt((x2-x)*(x2-x) + (y2-y)*(y2-y)); return AlmostEqual(len, len1+len2); } /* 3 Implementation of ~AVLSegment~ 3.0 static variables */ bool avlseg::AVLSegment::x_error = false; double avlseg::AVLSegment::error_value = 0.0; /* 3.1 Constructors ~Standard Constructor~ */ avlseg::AVLSegment::AVLSegment(): con_below(0), con_above(0),x1(0),x2(0),y1(0),y2(0), insideAbove_first(false), insideAbove_second(false),owner(none), originX1(0),originX2(0),originY1(0),originY2(0) { } /* ~Constructor~ This constructor creates a new segment from the given HalfSegment. As owner only __first__ and __second__ are the allowed values. */ avlseg::AVLSegment::AVLSegment(const avlseg::ExtendedHalfSegment& hs, ownertype owner){ assert(hs.isInitialized()); x1 = hs.GetLeftPoint().GetX(); y1 = hs.GetLeftPoint().GetY(); x2 = hs.GetRightPoint().GetX(); y2 = hs.GetRightPoint().GetY(); originX1 = hs.getOriginX1(); originX2 = hs.getOriginX2(); originY1 = hs.getOriginY1(); originY2 = hs.getOriginY2(); if( (AlmostEqual(x1,x2) && (y2owner = owner; switch(owner){ case first: { insideAbove_first = hs.GetAttr().insideAbove; insideAbove_second = false; break; } case second: { insideAbove_second = hs.GetAttr().insideAbove; insideAbove_first = false; break; } default: { assert(false); } } con_below = 0; con_above = 0; originX1 = hs.getOriginX1(); originX2 = hs.getOriginX2(); originY1 = hs.getOriginY1(); originY2 = hs.getOriginY2(); // assert(CheckPoints()); } /* ~Constructor~ Create a Segment only consisting of a single point. */ avlseg::AVLSegment::AVLSegment(const Point& p, ownertype owner){ x1 = p.GetX(); x2 = x1; y1 = p.GetY(); y2 = y1; this->owner = owner; insideAbove_first = false; insideAbove_second = false; con_below = 0; con_above = 0; originX1 = x1; originX2 = x2; originY1 = y1; originY2 = y2; // assert(CheckPoints()); } /* ~Copy Constructor~ */ avlseg::AVLSegment::AVLSegment(const AVLSegment& src): con_below(src.con_below), con_above(src.con_above), x1(src.x1), x2(src.x2), y1(src.y1), y2(src.y2), insideAbove_first (src.insideAbove_first), insideAbove_second(src.insideAbove_second), owner(src.owner), originX1(src.originX1), originX2(src.originX2), originY1(src.originY1), originY2(src.originY2) { // assert(CheckPoints()); } /* 3.3 Operators */ avlseg::AVLSegment& avlseg::AVLSegment::operator=( const avlseg::AVLSegment& src){ x1 = src.x1; x2 = src.x2; y1 = src.y1; y2 = src.y2; owner = src.owner; insideAbove_first = src.insideAbove_first; insideAbove_second = src.insideAbove_second; con_below = src.con_below; con_above = src.con_above; originX1 = src.originX1; originX2 = src.originX2; originY1 = src.originY1; originY2 = src.originY2; // assert(CheckPoints()); return *this; } bool avlseg::AVLSegment::operator==(const avlseg::AVLSegment& s) const{ return compareTo(s)==0; } bool avlseg::AVLSegment::operator<(const avlseg::AVLSegment& s) const{ int res = compareTo(s); return res<0; } bool avlseg::AVLSegment::operator>(const avlseg::AVLSegment& s) const{ return compareTo(s)>0; } /* 3.3 Further Needful Functions ~Print~ This function writes this segment to __out__. */ void avlseg::AVLSegment::Print(ostream& out)const{ out << "Segment("< (" << x2 << ", " << y2 <<") " << owner << " [ " << insideAbove_first << ", " << insideAbove_second << "] con(" << con_below << ", " << con_above << ")" << "orig = ( (" << originX1 << ", " << originY1 << ") -> (" << originX2 << ", " << originY2 << "))"; } /* ~CheckPoints~ This function checks whether the points (x1,y1) and (x2,y2) are located on the segment defined by (orinigX1, originY1) and (originY2, originY2). Furthermore, the distance from (x1,y1) to (originX1,originY1) must be smaller than the distance to (originX2, originY2). */ bool avlseg::AVLSegment::CheckPoints() const{ if(!PointOnSegment(x1,y1,originX1,originY1, originX2, originY2)){ HalfSegment hs(true, Point(originX1,originY1),Point(originX2,originY2)); double dist = hs.Distance(Point(x1,y1)); if(!AlmostEqual(dist,0.0)){ // rounding errors? cerr.precision(16); cerr << "Left Point not on OriginSegment" << endl; cerr << "this = " << (*this) << endl; cerr << "distance = " << dist << endl; return false; } } if(!PointOnSegment(x2,y2,originX1,originY1, originX2, originY2)){ HalfSegment hs(true, Point(originX1,originY1),Point(originX2,originY2)); double dist = hs.Distance(Point(x2,y2)); if(!AlmostEqual(dist,0.0)){ // rounding errors? cerr.precision(16); cerr << "right Point not on OriginSegment" << endl; cerr << "this = " << (*this) << endl; cerr << "distance = " << dist << endl; return false; } } double d1 = (x1-originX1)*(x1-originX1) + (y1-originY1)*(y1-originY1); double d2 = (x2-originX1)*(x2-originX1) + (y2-originY1)*(y2-originY1); if(d2 x2){ // (X,Y) right of this return false; } if(isVertical()){ return ((y>y1) && (yy2)) ; } double ys = getY(x); return AlmostEqual(y,ys); } /* ~contains~ Checks whether the point defined by (x,y) is located anywhere on this segment. */ bool avlseg::AVLSegment::contains(const double x,const double y)const{ if(pointEqual(x,y,x1,y1) || pointEqual(x,y,x2,y2)){ return true; } if(isPoint()){ return false; } if(!PointOnSegment(x,y,originX1, originY1, originX2, originY2)){ return false; } return innerBoxContains(x,y); } /* 3.6 Comparison Compares this with s. The x intervals must overlap. */ int avlseg::AVLSegment::compareTo(const avlseg::AVLSegment& s) const{ if(!xOverlaps(s) && !avlseg::AVLSegment::x_error){ cerr << "Warning: compare AVLSegments with disjoint x intervals" << endl; cerr << "This may be a problem of roundig errors!" << endl; cerr << "*this = " << *this << endl; cerr << " s = " << s << endl; x_error = true; error_value = max(x1,s.x1); } if(isPoint()){ if(s.isPoint()){ return comparePoints(x1,y1,s.x1,s.y1); } else { if(s.contains(x1,y1)){ return 0; } else { double y = s.getY(x1); if(y1s.y2)){ // this is above s return 1; } if(AlmostEqual(s.y1,y2) || (s.y1>y2)){ // s above this return 1; } // proper overlapping part return 0; } else { // one segment is vertical double x = v1? x1 : s.x1; // x coordinate of the vertical segment double y1 = getY(x); double y2 = s.getY(x); if(AlmostEqual(y1,y2)){ return v1?1:-1; // vertical segments have the greatest slope } else if(y1owner = o; } /* 3.7 Some ~Get~ Functions ~getInsideAbove~ Returns the insideAbove value for such segments for which this value is unique, e.g. for segments having owner __first__ or __second__. */ bool avlseg::AVLSegment::getInsideAbove() const{ switch(owner){ case first : return insideAbove_first; case second: return insideAbove_second; default : assert(false); } return false; } /* 3.8 Split Functions ~split~ This function splits two overlapping segments. Preconditions: 1) this segment and ~s~ have to overlap. 2) the owner of this and ~s~ must be different ~left~, ~common~ and ~right~ will contain the explicitely left part, a common part, and an explicitely right part. The left and/or right part may be empty. The existence can be checked using the return value of this function. Let ret the return value. It holds: __ret | LEFT__: the left part exists __ret | COMMON__: the common part exist (always true) __ret | RIGHT__: the right part exists The constants LEFT, COMMON, and RIGHT have been defined earlier. */ uint32_t avlseg::AVLSegment::split(const avlseg::AVLSegment& s, avlseg::AVLSegment& left, avlseg::AVLSegment& common, avlseg::AVLSegment& right, const bool checkOwner/* = true*/) const{ assert(overlaps(s)); if(checkOwner){ assert( (this->owner==first && s.owner==second) || (this->owner==second && s.owner==first)); } uint32_t result = 0; int cmp = comparePoints(x1,y1,s.x1,s.y1); if(cmp==0){ // there is no left part left.x1 = x1; left.y1 = y1; left.x2 = x1; left.y2 = y1; left.originX1 = x1; left.originY1 = y1; left.originX2 = x2; left.originY2 = y2; } else { // there is a left part result = result | avlseg::LEFT; if(cmp<0){ // this is smaller left.x1 = x1; left.y1 = y1; left.x2 = s.x1; left.y2 = s.y1; left.owner = this->owner; left.con_above = this->con_above; left.con_below = this->con_below; left.insideAbove_first = this->insideAbove_first; left.insideAbove_second = this->insideAbove_second; left.originX1 = originX1; left.originX2 = originX2; left.originY1 = originY1; left.originY2 = originY2; } else { // s is smaller than this left.x1 = s.x1; left.y1 = s.y1; left.x2 = this->x1; left.y2 = this->y1; left.owner = s.owner; left.con_above = s.con_above; left.con_below = s.con_below; left.insideAbove_first = s.insideAbove_first; left.insideAbove_second = s.insideAbove_second; left.originX1 = s.originX1; left.originX2 = s.originX2; left.originY1 = s.originY1; left.originY2 = s.originY2; } } // there is an overlapping part result = result | COMMON; cmp = comparePoints(x2,y2,s.x2,s.y2); common.owner = both; common.x1 = left.x2; common.y1 = left.y2; if(this->owner==first){ common.insideAbove_first = insideAbove_first; common.insideAbove_second = s.insideAbove_second; } else { common.insideAbove_first = s.insideAbove_first; common.insideAbove_second = insideAbove_second; } common.con_above = this->con_above; common.con_below = this->con_below; // for the common part, the origin is not clear. we take just the // line with maximum length; common.originX1 = left.originX1; common.originY1 = left.originY1; if(cmp<0){ common.x2 = x2; common.y2 = y2; } else { common.x2 = s.x2; common.y2 = s.y2; } if(cmp==0){ // common right endpoint common.originX2 = common.x2; common.originY2 = common.y2; // assert(left.CheckPoints()); // assert(common.CheckPoints()); return result; } result = result | avlseg::RIGHT; right.x1 = common.x2; right.y1 = common.y2; if(cmp<0){ // right part comes from s right.owner = s.owner; right.x2 = s.x2; right.y2 = s.y2; right.insideAbove_first = s.insideAbove_first; right.insideAbove_second = s.insideAbove_second; right.con_below = s.con_below; right.con_above = s.con_above; right.originX1 = s.originX1; right.originY1 = s.originY1; right.originX2 = s.originX2; right.originY2 = s.originY2; } else { // right part comes from this right.owner = this->owner; right.x2 = this->x2; right.y2 = this->y2; right.insideAbove_first = this->insideAbove_first; right.insideAbove_second = this->insideAbove_second; right.con_below = this->con_below; right.con_above = this->con_above; right.originX1 = originX1; right.originY1 = originY1; right.originX2 = originX2; right.originY2 = originY2; } common.originX2 = right.originX2; common.originY2 = right.originY2; // assert(left.CheckPoints()); // assert(common.CheckPoints()); // assert(right.CheckPoints()); return result; } /* ~splitAt~ This function divides a segment into two parts at the point provided by (x, y). The point must be on the interior of this segment. */ void avlseg::AVLSegment::splitAt(const double x, const double y, avlseg::AVLSegment& left, avlseg::AVLSegment& right)const{ left.x1=x1; left.y1=y1; left.x2 = x; left.y2 = y; left.owner = owner; left.insideAbove_first = insideAbove_first; left.insideAbove_second = insideAbove_second; left.con_below = con_below; left.con_above = con_above; right.x1=x; right.y1=y; right.x2 = x2; right.y2 = y2; right.owner = owner; right.insideAbove_first = insideAbove_first; right.insideAbove_second = insideAbove_second; right.con_below = con_below; right.con_above = con_above; left.originX1 = originX1; left.originX2 = originX2; left.originY1 = originY1; left.originY2 = originY2; right.originX1 = originX1; right.originX2 = originX2; right.originY1 = originY1; right.originY2 = originY2; //assert(left.CheckPoints()); //assert(right.CheckPoints()); } void avlseg::AVLSegment::splitAtRight(const double x, const double y, avlseg::AVLSegment& right)const{ if(AlmostEqual(x,x1) && AlmostEqual(y,y1)){ right = *this; return; } if(AlmostEqual(x,x2) && AlmostEqual(y,y2)){ // return only the right endpoint right = *this; right.x1 = x2; right.y1 = y2; return; } if(!AlmostEqual(x,x1) && (x < x1)){ right = *this; return; } right.x1=x; right.y1=y; right.x2 = x2; right.y2 = y2; right.owner = owner; right.insideAbove_first = insideAbove_first; right.insideAbove_second = insideAbove_second; right.con_below = con_below; right.con_above = con_above; right.originX1 = originX1; right.originX2 = originX2; right.originY1 = originY1; right.originY2 = originY2; //assert(right.CheckPoints()); } /* ~splitCross~ Splits two crossing segments into the 4 corresponding parts. Both segments have to cross each other. */ void avlseg::AVLSegment::splitCross(const avlseg::AVLSegment& s, avlseg::AVLSegment& left1, avlseg::AVLSegment& right1, avlseg::AVLSegment& left2, avlseg::AVLSegment& right2) const{ double x,y; bool cross = crosses(s,x,y); assert(cross); splitAt(x, y, left1, right1); s.splitAt(x, y, left2, right2); //assert(left1.CheckPoints()); //assert(right1.CheckPoints()); //assert(left2.CheckPoints()); //assert(right2.CheckPoints()); } /* 3.9 Converting Functions ~ConvertToHs~ This functions creates a ~HalfSegment~ from this segment. The owner must be __first__ or __second__. */ avlseg::ExtendedHalfSegment avlseg::AVLSegment::convertToExtendedHs(bool lpd, avlseg::ownertype owner/* = both*/)const{ //assert( owner!=both || this->owner==first || this->owner==second); //assert( owner==both || owner==first || owner==second); bool insideAbove; if(owner==both){ insideAbove = this->owner==first?insideAbove_first :insideAbove_second; } else { insideAbove = owner==first?insideAbove_first :insideAbove_second; } Point p1(true,x1,y1); Point p2(true,x2,y2); HalfSegment hs(lpd, p1, p2); hs.attr.insideAbove = insideAbove; avlseg::ExtendedHalfSegment extHs(hs); extHs.setOrigin(originX1, originY1, originX2, originY2); return extHs; } /* ~pointequal~ This function checks if the points defined by (x1, y1) and (x2,y2) are equals using the ~AlmostEqual~ function. */ bool avlseg::AVLSegment::pointEqual(const double x1, const double y1, const double x2, const double y2){ return AlmostEqual(x1,x2) && AlmostEqual(y1,y2); } /* ~pointSmaller~ This function checks if the point defined by (x1, y1) is smaller than the point defined by (x2, y2). */ bool avlseg::AVLSegment::pointSmaller(const double x1, const double y1, const double x2, const double y2) { return comparePoints(x1,y1,x2,y2) < 0; } /* ~comparePoints~ */ int avlseg::AVLSegment::comparePoints(const double x1,const double y1, const double x2,const double y2){ if(AlmostEqual(x1,x2)){ if(AlmostEqual(y1,y2)){ return 0; } else if(y1res2 result = 1; } return result; } /* ~roundPoint~ whenever the point (x,y) is almostequal to an endpoint, its rounded to that endpoint. */ void avlseg::AVLSegment::roundPoint(double& x , double& y) const{ if(pointEqual(x,y,originX1,originY1)){ x = originX1; y = originY1; return; } if(pointEqual(x,y,originX2,originY2)){ x = originX2; y = originY2; return; } if(pointEqual(x,y,x1,y1)){ x = x1; y = y1; return; } if(pointEqual(x,y,x2,y2)){ x = x2; y = y2; return; } } /* ~XOverlaps~ Checks whether the x interval of this segment overlaps the x interval of ~s~. */ bool avlseg::AVLSegment::xOverlaps(const avlseg::AVLSegment& s) const{ if(!AlmostEqual(x1,s.x2) && x1 > s.x2){ // left of s return false; } if(!AlmostEqual(x2,s.x1) && x2 < s.x1){ // right of s return false; } return true; } bool avlseg::AVLSegment::yOverlaps(const avlseg::AVLSegment& s) const{ if(AlmostEqual(y1,s.y1) || AlmostEqual(y1,s.y2) || AlmostEqual(y2,s.y1) || AlmostEqual(y2,s.y2)){ return true; } double ymin = y1y2?y1:y2; if((ymin>s.y1) && (ymin>s.y2)) return false; if((ymaxx){ return false; } if(!AlmostEqual(x2,x) && x2diff2?diff1:diff2); cerr << "difference to x is " << diff << endl; cerr << "The segment is " << *this << endl; //assert(diff < 1.0); } if(isVertical()){ return y1; } if(AlmostEqual(x,x1)){ return y1; } if(AlmostEqual(x,x2)){ return y2; } double d = (x-originX1)/(originX2-originX1); return originY1 + d*(originY2-originY1); } /* 3.12 Shift Operator */ ostream& avlseg::operator<<(ostream& o, const avlseg::AVLSegment& s){ s.Print(o); return o; } /* ~insertEvents~ Creates events for the ~AVLSegment~ and insert them into ~q1~ and/ or ~q1~. The target queue(s) is (are) determined by the owner of ~seg~. The flags ~createLeft~ and ~createRight~ determine whether the left and / or the right events should be created. */ void insertEvents(const avlseg::AVLSegment& seg, const bool createLeft, const bool createRight, priority_queue, greater >& q1, priority_queue, greater >& q2){ if(seg.isPoint()){ return; } switch(seg.getOwner()){ case avlseg::first: { if(createLeft){ q1.push(seg.convertToExtendedHs(true, avlseg::first)); } if(createRight){ q1.push(seg.convertToExtendedHs(false, avlseg::first)); } break; } case avlseg::second:{ if(createLeft){ q2.push(seg.convertToExtendedHs(true, avlseg::second)); } if(createRight){ q2.push(seg.convertToExtendedHs(false, avlseg::second)); } break; } case avlseg::both : { if(createLeft){ q1.push(seg.convertToExtendedHs(true, avlseg::first)); q2.push(seg.convertToExtendedHs(true, avlseg::second)); } if(createRight){ q1.push(seg.convertToExtendedHs(false, avlseg::first)); q2.push(seg.convertToExtendedHs(false, avlseg::second)); } break; } default: { assert(false); } } } /* ~splitByNeighbour~ ~neighbour~ has to be an neighbour from ~current~ within ~sss~. The return value is true, if current was changed. */ bool splitByNeighbour(avltree::AVLTree& sss, avlseg::AVLSegment& current, avlseg::AVLSegment *& neighbour, priority_queue, greater >& q1, priority_queue, greater >& q2, const bool forceThrow ){ avlseg::AVLSegment left1, right1, left2, right2; if(neighbour && !neighbour->innerDisjoint(current)){ if(neighbour->ininterior(current.getX1(),current.getY1())){ neighbour->splitAt(current.getX1(),current.getY1(),left1,right1); sss.remove(*neighbour); if(!left1.isPoint()){ // debug::start avlseg::AVLSegment* x = sss.getMember(left1); if(x){ cerr << "we have a problem " << __LINE__ << endl; cerr << " left1 = " << left1 << endl; cerr << " *x = " << *x << endl; } // debug::end neighbour = sss.insert2(left1); insertEvents(left1,false,true,q1,q2); } insertEvents(right1,true,true,q1,q2); return false; } else if(neighbour->ininterior(current.getX2(),current.getY2())){ neighbour->splitAt(current.getX2(),current.getY2(),left1,right1); sss.remove(*neighbour); if(!left1.isPoint()){ // debug::start const avlseg::AVLSegment* x = sss.getMember(left1); if(x){ cerr << "we have a problem " << __LINE__ << endl; cerr << " left1 = " << left1 << endl; cerr << " *x = " << *x << endl; } // debug::end neighbour = sss.insert2(left1); insertEvents(left1,false,true,q1,q2); } insertEvents(right1,true,true,q1,q2); return false; } else if(current.ininterior(neighbour->getX2(),neighbour->getY2())){ current.splitAt(neighbour->getX2(),neighbour->getY2(),left1,right1); current = left1; insertEvents(left1,false,true,q1,q2); insertEvents(right1,true,true,q1,q2); return true; } else if(current.crosses(*neighbour)){ neighbour->splitCross(current,left1,right1,left2,right2); sss.remove(*neighbour); if(!left1.isPoint()){ neighbour = sss.insert2(left1); } current = left2; insertEvents(left1,false,true,q1,q2); insertEvents(right1,true,true,q1,q2); insertEvents(left2,false,true,q1,q2); insertEvents(right2,true,true,q1,q2); return true; } else { // forgotten case or wrong order of halfsegments if(forceThrow){ throw myexception("Invalid halfsegment order"); } cerr.precision(16); cerr << "Warning wrong order in halfsegment array detected" << endl; cerr << "current" << current << endl << "neighbour " << (*neighbour) << endl; if(current.overlaps(*neighbour)){ // a common line cerr << "1 : The segments overlaps" << endl; } if(neighbour->ininterior(current.getX1(),current.getY1())){ cerr << "2 : neighbour->ininterior(current.x1,current.y1)" << endl; } if(neighbour->ininterior(current.getX2(),current.getY2())){ cerr << "3 : neighbour->ininterior(current.getX2()" << ",current.getY2()" << endl; } if(current.ininterior(neighbour->getX1(),neighbour->getY1())){ cerr << " case 4 : current.ininterior(neighbour->getX1()," << "neighbour.getY1()" << endl; cerr << "may be an effect of rounding errors" << endl; cerr << "remove left part from current" << endl; current.splitAt(neighbour->getX1(),neighbour->getY1(), left1,right1); cerr << "removed part is " << left1 << endl; current = right1; insertEvents(current,false,true,q1,q2); return true; } if(current.ininterior(neighbour->getX2(),neighbour->getY2())){ cerr << " 5 : current.ininterior(neighbour->getX2()," << "neighbour->getY2())" << endl; } if(current.crosses(*neighbour)){ cerr << "6 : crosses" << endl; } throw myexception("Invalid order of halfsegments"); assert(false); return true; } } else { return false; } } /* ~splitNeighbours~ Checks if the left and the right neighbour are intersecting in their interiors and performs the required actions. */ void splitNeighbours(avltree::AVLTree& sss, avlseg::AVLSegment *& leftN, avlseg::AVLSegment *& rightN, priority_queue, greater >& q1, priority_queue, greater >& q2, const bool forceThrow){ if(leftN && rightN && !leftN->innerDisjoint(*rightN)){ avlseg::AVLSegment left1, right1, left2, right2; if(leftN->ininterior(rightN->getX2(),rightN->getY2())){ // right endpoint of rightN in interior of leftN leftN->splitAt(rightN->getX2(),rightN->getY2(),left1,right1); sss.remove(*leftN); if(!left1.isPoint()){ leftN = sss.insert2(left1); insertEvents(left1,false,true,q1,q2); } insertEvents(right1,true,true,q1,q2); } else if(rightN->ininterior(leftN->getX2(),leftN->getY2())){ // right endpoint of leftN in interior of rightN rightN->splitAt(leftN->getX2(),leftN->getY2(),left1,right1); sss.remove(*rightN); if(!left1.isPoint()){ rightN = sss.insert2(left1); insertEvents(left1,false,true,q1,q2); } insertEvents(right1,true,true,q1,q2); } else if (rightN->crosses(*leftN)){ // leftN and rightN are crossing leftN->splitCross(*rightN,left1,right1,left2,right2); sss.remove(*leftN); sss.remove(*rightN); if(!left1.isPoint()) { leftN = sss.insert2(left1); } if(!left2.isPoint()){ rightN = sss.insert2(left2); } insertEvents(left1,false,true,q1,q2); insertEvents(left2,false,true,q1,q2); insertEvents(right1,true,true,q1,q2); insertEvents(right2,true,true,q1,q2); } else if(leftN->ininterior(rightN->getX1(), rightN->getY1())){ if(forceThrow){ throw myexception("found element to split too late"); } cerr << __LINE__ << "Warning found an element to split too late" << endl; sss.remove(*leftN); leftN->splitAt(rightN->getX1(), rightN->getY1(), left1, right1); if(!left1.isPoint()){ leftN = sss.insert2(left1); insertEvents(left1, false,true,q1,q2); } insertEvents(right1, true,true,q1,q2); } else if(rightN->ininterior(leftN->getX1(), leftN->getY1())){ if(forceThrow){ throw myexception("found element to split too late"); } cerr << __LINE__ << "Warning found an element to split too late" << endl; sss.remove(*rightN); rightN->splitAt(leftN->getX1(), leftN->getY1(), left1, right1); if(!left1.isPoint()){ rightN = sss.insert2(left1); insertEvents(left1, false, true, q1,q2); } insertEvents(right1, true,true,q1,q2); } else { // forgotten case or overlapping segments (rounding errors) if(leftN->overlaps(*rightN)){ if(forceThrow){ throw myexception("found element to split too late"); } cerr << "Overlapping neighbours found" << endl; cerr << "leftN = " << *leftN << endl; cerr << "rightN = " << *rightN << endl; avlseg::AVLSegment left; avlseg::AVLSegment common; avlseg::AVLSegment right; uint32_t parts = leftN->split(*rightN, left,common,right,false); sss.remove(*leftN); sss.remove(*rightN); if(parts & avlseg::LEFT){ if(!left.isPoint()){ cerr << "insert left part" << left << endl; leftN = sss.insert2(left); insertEvents(left,false,true,q1,q2); } } if(parts & avlseg::COMMON){ if(!common.isPoint()){ cerr << "insert common part" << common << endl; rightN = sss.insert2(common); insertEvents(common,false,true,q1,q2); } } if(parts & avlseg::RIGHT){ if(!right.isPoint()){ cerr << "insert events for the right part" << right << endl;; insertEvents(right,true,true,q1,q2); } } } else { if(forceThrow){ throw myexception("found element to split too late"); } cout.precision(16); cout << "Found to segments which are in no valid relation " << endl; cout << " leftN = " << (*leftN) << endl; cout << " rightN = " << (*rightN) << endl; cout << "leftN.isVertical : " << leftN->isVertical() << endl; cout << "rightN.isVertical : " << rightN->isVertical() << endl; cout << "leftN.innerDisjoint(rightN) : " << leftN->innerDisjoint(*rightN) << endl; cout << "rightN.innerDisjoint(leftN) : " << rightN->innerDisjoint(*leftN) << endl; cout << "leftN.intersects(rightN) : " << leftN->intersects(*rightN) << endl; cout << "rightN.intersects(leftN) : " << rightN->intersects(*leftN) << endl; cout << "leftN.overlaps(rightN) : " << leftN->overlaps(*rightN) << endl; cout << "rightN.overlaps(leftN) : " << rightN->overlaps(*leftN) << endl; cout << "leftN.compareTo(rightN) : " << leftN->compareTo(*rightN) << endl; cout << "rightN.compareTo(leftN) : " << rightN->compareTo(*leftN) << endl; cout << "leftN.compareSlopes(rightN) : " << leftN->compareSlopes(*rightN) << endl; cout << "rightN.compareSlopes(leftN) : " << rightN->compareSlopes(*leftN) << endl; cout << "leftN.xOverlaps(rightN) : " << leftN->xOverlaps(*rightN) << endl; cout << "rightN.xOverlaps(leftN) : " << rightN->xOverlaps(*leftN) << endl; cout << "leftN.yOverlaps(rightN) : " << leftN->yOverlaps(*rightN) << endl; cout << "rightN.yOverlaps(leftN) : " << rightN->yOverlaps(*leftN) << endl; leftN->printInnerDisjoint(*rightN); assert(false); } } } // intersecting neighbours } /* 9 Set Operations (union, intersection, difference) The following functions implement the operations ~union~, ~intersection~ and ~difference~ for some combinations of spatial types. */