/* //[_] [\_] //[TOC] [\tableofcontents] //[Title] [ \title{RobustGeometry} \author{Katja Koch} \maketitle] //[times] [\ensuremath{\times}] //[->] [\ensuremath{\rightarrow}] [1] Implementation of the RobustGeometryAlgebra [TOC] 1 Overview This algebra implements the Snap Rounding technique described in Hobby, Guibas and Marimont to compute a fully rounded arrangement from a set of linesegments. Snap Rounding assumes that all vertices lie on a uniform grid. Hence all the input vertices must be rounded to a given precision. This implementation uses an iteration over the line segments and appears to be fully robust using an adjustable precision model. To change the precision adapt the ScaleFactor. This algebra provides just the type constructors ~line~ for the intersection operation. There are tree steps to provide a robust operation in SECONDO. First Step is a plane-sweep-algorithm to find the intersection points, then snap rounding and finally a operation specific check. 1 Preliminaries 1.1 Includes and global declarations */ #include "Algebra.h" #include "NestedList.h" #include "ListUtils.h" #include "GenericTC.h" #include "QueryProcessor.h" #include "StandardTypes.h" #include "SecondoConfig.h" #include "AvlTree.h" #include "AlmostEqual.h" #include "Algebras/Relation-C++/RelationAlgebra.h" #include "Symbols.h" #include "NList.h" #include "LogMsg.h" #include "ConstructorTemplates.h" #include "TypeMapUtils.h" #include "Algebras/Spatial/SpatialAlgebra.h" #include "RobustGeometryAlgebra.h" #include "Algebras/Spatial/AVLSegment.h" #include "Algebras/Spatial/HalfSegment.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef M_PI const double M_PI = acos( -1.0 ); #endif using namespace std; extern NestedList* nl; extern QueryProcessor* qp; /* Algebra Implementation Type Mapping Functions check whether the correct argument types are supplied for an operator; if so, returns a list expression for the result type, otherwise the symbol ~typeerror~. This implementation uses the implementation of the classes ~line~ and ~region~ from SpatialAlgebra. So see SpatialAlgebra for Type Mapping Functions */ /* An algebra module must provide for each type functions which take a nested list and create an instance of the class representing the type and vice versa. These functions are called In- and Out-functions. [->] see SpatialAlgebra */ enum SpatialTypeRG { stpoint, stpoints, stline, stregion, stbox, sterror }; SpatialTypeRG SpatialTypeOfSymbolRG(ListExpr symbol) { if (nl->AtomType(symbol) == SymbolType) { string s = nl->SymbolValue(symbol); if (s == Point::BasicType()) return (stpoint); if (s == Points::BasicType()) return (stpoints); if (s == Line::BasicType()) return (stline); if (s == Region::BasicType()) return (stregion); if (s == Rectangle<2>::BasicType()) return (stbox); } return (sterror); } /* 10.1.2 Type Mapping for intersection Signature is line x line [->] line */ static ListExpr intersectionTM(ListExpr args) { ListExpr arg1, arg2; if (nl->ListLength(args) == 2) { arg1 = nl->First(args); arg2 = nl->Second(args); if (SpatialTypeOfSymbolRG(arg1) == stline && SpatialTypeOfSymbolRG(arg2) == stline) return (nl->SymbolAtom(Line::BasicType())); } return (nl->SymbolAtom(Symbol::TYPEERROR())); } int RobustGeometrySetOpSelect(ListExpr args) { string a1 = nl->SymbolValue(nl->First(args)); string a2 = nl->SymbolValue(nl->Second(args)); if (a1 == Line::BasicType()) { if (a2 == Line::BasicType()) return 1; return -1; } return -1; } /* 10.5.2 Definition of specification strings */ const string intersectionSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " "( {line} x" " {line} -> T, " " where T = points if any point or point type is one of the " " arguments or the argument having the smaller dimension " "intersectionBO(arg1, arg2)" "intersectionBO of two spatial objects" "query intersectionBO(tiergarten, thecenter) " ") )"; /* 3 Implementation of Class ~BOLine~ */ /* documentation see RobustGeometryAlgebra.h */ robustGeometry::BOLine::BOLine(const BOLine& line){ x1 = line.getX1(); x2 = line.getX2(); y1 = line.getY1(); y2 = line.getY2(); owner = line.getOwner(); x1_r = line.getX1_round(); y1_r = line.getY1_round(); x2_r = line.getX2_round(); y2_r = line.getY2_round(); } robustGeometry::BOLine::BOLine( const double x1, const double y1, const double x2, const double y2, const robustGeometry::BOOwnerType owner ) { setX1( x1 ); setY1( y1 ); setX2( x2 ); setY2( y2 ); setOwner( owner ); }; void robustGeometry::BOLine::setX1( const double x ) const { this->x1 = x; }; void robustGeometry::BOLine::setX2( const double x ) const { this->x2 = x; }; void robustGeometry::BOLine::setY1( const double y ) const { this->y1 = y; }; void robustGeometry::BOLine::setY2( const double y ) const { this->y2 = y; }; void robustGeometry::BOLine::setX1_round( const double x ) { this->x1_r = x; }; void robustGeometry::BOLine::setX2_round( const double x ) { this->x2_r = x; }; void robustGeometry::BOLine::setY1_round( const double y ) { this->y1_r = y; }; void robustGeometry::BOLine::setY2_round( const double y ) { this->y2_r = y; }; void robustGeometry::BOLine::setOwner( const BOOwnerType owner ) { this->owner = owner; }; /* 3 Implementation of Class ~BOEvent~ */ robustGeometry::BOEvent::BOEvent(const double x, const double y, const robustGeometry::BOPointType pType, const robustGeometry::BOOwnerType owner) { setX( x ); setY( y ); origX = x; origY = y; setPointType( pType ); }; robustGeometry::BOEvent::BOEvent(const double x, const double y, const robustGeometry::BOPointType pType, const robustGeometry::BOOwnerType owner, const robustGeometry::BOLine& line) { setX( x ); setY( y ); origX = x; origY = y; setPointType( pType ); setOwner( owner); setLine( line ); }; robustGeometry::BOEvent::BOEvent(const double x, const double y, const robustGeometry::BOPointType pType, const robustGeometry::BOOwnerType owner, const robustGeometry::BOLine& line1, const robustGeometry::BOLine& line2) { setX( x ); setY( y ); origX = x; origY = y; setPointType( pType ); setOwner( owner); setLine1(line1); setLine2(line2); if ( line1.getY1() > line2.getY1()){ lineAbove = line1; lineBelow = line2; } else { lineAbove = line2; lineBelow = line1; }; }; void robustGeometry::BOEvent::setX( const double x ) { this->x = x; }; void robustGeometry::BOEvent::setY( const double y ) { this->y = y; }; void robustGeometry::BOEvent::setPointType( const BOPointType pointType ) { this->pointType = pointType; }; void robustGeometry::BOEvent::setOwner( const BOOwnerType owner ) { this->owner = owner; }; void robustGeometry::BOEvent::setLine( const BOLine & line ) { this->line = line; }; void robustGeometry::BOEvent::setLine1( const BOLine & line1 ) { this->line1 = line1; }; void robustGeometry::BOEvent::setLine2( const BOLine & line2 ) { this->line2 = line2; }; void robustGeometry::BOEvent::Print(ostream& out) const { out << "X : " << getX( ) << ",Y : " << getY( ) << ", owner : " << getOwner( ); }; void robustGeometry::Point::setX( const double x ) { this->x = x; }; void robustGeometry::Point::setY( const double y ) { this->y = y; }; /* 3 Implementation of Class ~HOBatch~ */ robustGeometry::HOBatch::HOBatch(const double x, const double y){ setX( x ); setY( y ); } void robustGeometry::HOBatch::setX( const double x ) { this->x = x; }; void robustGeometry::HOBatch::setY( const double y ) { this->y = y; }; /* 3 Implementation of Class ~ToleranceSquare~ */ void robustGeometry::ToleranceSquare::setX11( const double x11 ) { this->x11 = x11; }; void robustGeometry::ToleranceSquare::setY11( const double y11 ) { this->y11 = y11; }; void robustGeometry::ToleranceSquare::setX12( const double x12 ) { this->x12 = x12; }; void robustGeometry::ToleranceSquare::setY12( const double y12 ) { this->y12 = y12; }; void robustGeometry::ToleranceSquare::setX21( const double x21 ) { this->x21 = x21; }; void robustGeometry::ToleranceSquare::setY21( const double y21 ) { this->y21 = y21; }; void robustGeometry::ToleranceSquare::setX22( const double x22 ) { this->x22 = x22; }; void robustGeometry::ToleranceSquare::setY22( const double y22 ) { this->y22 = y22; }; void robustGeometry::ToleranceSquare::setSnapX( const double snap_x ) { this->snap_x = snap_x; }; void robustGeometry::ToleranceSquare::setSnapY( const double snap_y ) { this->snap_y = snap_y; }; void robustGeometry::ToleranceSquare::setBOEvent( const BOEvent & boEv ) { this->boEv = boEv; }; /* 1 Implementation of Class ~MakeBO~ Class for plane-sweep-algorithm like [Bentley/Ottmann 1979] */ class MakeBO { public: /* 3.1 Constructors and Destructors */ MakeBO() { }; ~MakeBO() {}; /* 3.2 Operation ~intersection~ */ void IntersectionBO(const Line& line1, const Line& line2, Line& result); /* 10.1 Functions for computing intersection points */ /* compute the intersection point from two segments Returns zero[->]OK, one[->]lines parallel, two[->]no intersection point */ int intersect(const double l1_x1,const double l1_y1, const double l1_x2,const double l1_y2, const double l2_x1,const double l2_y1, const double l2_x2,const double l2_y2, double& x,double& y); /* check intesection, if exists and intersectionpoint i is not in event queue boEvents insert i into boEvents */ void checkIS(robustGeometry::BOEvent& currEv, const robustGeometry::BOLine& currSeg); /* check intesection for line object, if exists and intersectionpoint i is not in event queue boEvents insert i into boEvents */ void checkIS(const robustGeometry::BOLine& line1, const robustGeometry::BOLine& line2); /* Swap their positions so that above and below are interchanged; */ void findAndSwap(const robustGeometry::BOLine& aboveSeg, const robustGeometry::BOLine& belowSeg); /* Gets the line above according to the x,y value */ const robustGeometry::BOLine* getAbove(const double x, const double y); /* Gets the line below according to the x,y value */ const robustGeometry::BOLine* getBelow(const double aktXPos,double aktYPos); /* Gets the line above according to the current event */ const robustGeometry::BOLine* getAbove(robustGeometry::BOEvent& event); /* Gets the line below according to the current event */ const robustGeometry::BOLine* getBelow(robustGeometry::BOEvent& event); /* Add line to the sweep-line */ void addLineToSweepLine(const robustGeometry::BOLine& line ); /* Add event to event queue boEvents */ void addBOEvent(const robustGeometry::BOEvent& event ); /* event e is a left endpoint */ void doBOCaseA( robustGeometry::BOEvent & event ); /* event e is a right endpoint */ void doBOCaseB( robustGeometry::BOEvent & event ); /* event e is a intersectionpoint */ void doBOCaseC( robustGeometry::BOEvent & event ); /* add event to event queue boEvents */ void addInitialEvent(const robustGeometry::BOEvent& event ); /* find and delete event in event queue boEvents */ void findEventAndDelete( robustGeometry::BOEvent & event ); /* call the case processing *Precondition:* ~there are elements in boEvents~ */ void doBOCases( ); void printInitialEvents(); void printBOEvents(); set & get_BOEvents( ){ return boEvents; }; private: /* sweepLine */ set sL; /* input event queue */ set initialEvents; /* event queue */ set boEvents; }; void MakeBO::doBOCaseA( robustGeometry::BOEvent & event ){ addBOEvent(event); addLineToSweepLine(event.getLine()); const robustGeometry::BOLine* segAbove = 0; segAbove = getAbove( event); if ( segAbove!= 0 ){ checkIS(event,*segAbove); }; const robustGeometry::BOLine* segBelow = 0; segBelow=getBelow(event); if ( segBelow != 0 ){ checkIS(event,*segBelow); }; } void MakeBO::doBOCaseB( robustGeometry::BOEvent & event ){ addBOEvent(event); const robustGeometry::BOLine* segAbove = 0; segAbove=getAbove(event); const robustGeometry::BOLine* segBelow = 0; segBelow = getBelow(event); findEventAndDelete( event ); if ( ( segAbove != 0 ) && ( segBelow != 0 )){ checkIS(*segAbove,*segBelow); }; } void MakeBO::doBOCaseC( robustGeometry::BOEvent & event ){ addBOEvent(event); const robustGeometry::BOLine* seg1 = &event.getLineAbove( ); const robustGeometry::BOLine* seg2 = &event.getLineBelow( ); findAndSwap(*seg1,*seg2); const robustGeometry::BOLine *segAbove = 0; segAbove=getAbove(seg2->getX2(), seg2->getY2()); const robustGeometry::BOLine *segBelow = 0; segBelow=getBelow(seg1->getX2(), seg1->getY2()); if ( ( segAbove != 0 ) && ( seg2 != 0 )){ checkIS(*segAbove,*seg2); }; if ( ( segBelow != 0 ) && ( seg1 != 0 )){ checkIS(*seg1, *segBelow); }; } void MakeBO::doBOCases(){ set ::iterator event_it; boEvents.clear(); sL.clear(); for ( event_it = initialEvents.begin(); event_it != initialEvents.end(); ++event_it){ robustGeometry::BOEvent event = *event_it; if ( event.getPointType()==robustGeometry::start ){ doBOCaseA( event ); } else if ( event.getPointType()==robustGeometry::end ){ doBOCaseB( event ); } else if ( event.getPointType()==robustGeometry::intersect ){ doBOCaseC( event ); }; } } void MakeBO::printInitialEvents( ){ set::iterator it; for ( it = initialEvents.begin(); it != initialEvents.end(); ++it){ cout << it->getX() << " " << it->getY() << " Pointtype "; if ( it->getPointType() == robustGeometry::start ) cout << "start"; else if ( it->getPointType() == robustGeometry::end ) cout << "end"; else cout << "intersect"; cout << endl; } } void MakeBO::printBOEvents( ){ set::iterator it; for ( it = boEvents.begin(); it != boEvents.end(); ++it){ cout << it->getX() << " " << it->getY(); if ( it->getPointType() == robustGeometry::start ) cout << "start"; else if ( it->getPointType() == robustGeometry::end ) cout << "end"; else { robustGeometry::BOEvent tmpEv = *it; cout << "intersect" << " line1 " << tmpEv.getLine1().getX1() << " line2 " << tmpEv.getLine1().getX2(); } cout << endl; } } const robustGeometry::BOLine * MakeBO::getAbove( const double x, const double y) { set< robustGeometry::BOLine>::iterator seg_it; for ( seg_it = sL.begin(); seg_it != sL.end(); ++seg_it) { robustGeometry::BOLine tmpSeg = *seg_it; if ( ( x > seg_it->getX1() ) && ( x < seg_it->getX2() ) && ( y < seg_it->getY1() ) ) { return &*seg_it; } if ( tmpSeg.getX1() > x ) break; } return 0; } const robustGeometry::BOLine * MakeBO::getAbove( robustGeometry::BOEvent& event) { return getAbove( event.getX(), event.getY()); } const robustGeometry::BOLine * MakeBO::getBelow (const double x, const double y) { set< robustGeometry::BOLine, robustGeometry::CompBOLine >::iterator seg_it; for ( seg_it = sL.begin(); seg_it != sL.end(); ++seg_it) { robustGeometry::BOLine tmpSeg = *seg_it; if ( ( x > tmpSeg.getX1() ) && ( x < tmpSeg.getX2() ) && ( y > tmpSeg.getY1() ) ) { return &*seg_it; } if ( tmpSeg.getX1() > x ) break; } return 0; } const robustGeometry::BOLine * MakeBO::getBelow(robustGeometry::BOEvent& event){ return getBelow(event.getX(), event.getY()); } void MakeBO::findEventAndDelete( robustGeometry::BOEvent & event ){ if ( sL.size() == 0) return; robustGeometry::BOLine eventSeg = event.getLine(); sL.erase(robustGeometry::BOLine(eventSeg.getX1(), eventSeg.getY1(), eventSeg.getX2(), eventSeg.getY2(), eventSeg.getOwner() )); } void MakeBO::findAndSwap(const robustGeometry::BOLine& aboveSeg, const robustGeometry::BOLine& belowSeg) { int pos1=-1; int pos2=-1; set< robustGeometry::BOLine, robustGeometry::CompBOLine >::iterator sL_it; int i = 0; double tempx1=0.0; double tempy1=0.0; for ( sL_it = sL.begin(); sL_it != sL.end(); ++sL_it) { robustGeometry::BOLine tmpSeg = *sL_it; tempx1=tmpSeg.getX1(); tempy1=tmpSeg.getY1(); if((tempx1 == aboveSeg.getX1()) && (tempy1 == aboveSeg.getY1()) &&(tempx1 == aboveSeg.getX2()) && (tempy1 == aboveSeg.getY2())) { pos1=i; } if((tempx1 == belowSeg.getX1()) && (tempy1 == belowSeg.getY1()) &&(tempx1 == belowSeg.getX2()) && (tempy1 == belowSeg.getY2())) { pos2=i; } i++; if(pos1>=0 && pos2>=0) { robustGeometry::BOLine tmp = aboveSeg; } } } int MakeBO::intersect(const double l1_x1,const double l1_y1, const double l1_x2,const double l1_y2, const double l2_x1,const double l2_y1, const double l2_x2,const double l2_y2, double & x,double & y){ //return =0 OK, 1 lines parallel, 2 no intersection point //x,y intersection point double a1=0.0; double a2=0.0; double b1=0.0; double b2=0.0; double c1=0.0; double c2=0.0; // Coefficients of line double m=0.0; a1= l1_y2 - l1_y1; b1= l1_x1 - l1_x2; c1= l1_x2 * l1_y1 - l1_x1 * l1_y2; //a1*x + b1*y + c1 = 0 is segment 1 a2= l2_y2 - l2_y1; b2= l2_x1 - l2_x2; c2= l2_x2 * l2_y1 - l2_x1 * l2_y2; //a2*x + b2*y + c2 = 0 is segment 2 m= a1*b2-a2*b1; if (m == 0) return 1; x=(b1*c2-b2*c1)/m; // intersection range if(x < l1_x1 || x < l2_x1 || x > l1_x2 || x > l2_x2) return 2; //y=(a2*c1-a1*c2)/m; return 0; } void MakeBO::checkIS(const robustGeometry::BOLine& line1, const robustGeometry::BOLine& line2) { double sx1=0.0; double sy1=0.0; double ex1=0.0; double ey1=0.0; double sx2=0.0; double sy2=0.0; double ex2=0.0; double ey2=0.0; double is_x=0.0; double is_y=0.0; int isIntersected = 1; robustGeometry::BOOwnerType currOwner; robustGeometry::BOOwnerType nextOwner; sx2 = line2.getX1(); sy2 = line2.getY1(); ex2 = line2.getX2(); ey2 = line2.getY2(); nextOwner = line2.getOwner(); sx1 = line1.getX1();; sy1 = line1.getY1(); ex1 = line1.getX2(); ey1 = line1.getY2(); currOwner = line1.getOwner(); //check owner first if (currOwner != nextOwner) { isIntersected = intersect (sx1,sy1,ex1,ey1,sx2,sy2,ex2,ey2,is_x,is_y); if (isIntersected==0) { robustGeometry::BOEvent intersP = robustGeometry::BOEvent( is_x, is_y, robustGeometry::intersect, robustGeometry::both, line1, line2); addLineToSweepLine(intersP.getLine()); addBOEvent(intersP); } } } void MakeBO::checkIS(robustGeometry::BOEvent& currEv, const robustGeometry::BOLine& currSeg){ checkIS( currEv.getLine(), currSeg); } void MakeBO::addLineToSweepLine( const robustGeometry::BOLine& line ) { sL.insert(line); } void MakeBO::addBOEvent( const robustGeometry::BOEvent& event ) { boEvents.insert( event ); } void MakeBO::addInitialEvent( const robustGeometry::BOEvent& event ) { initialEvents.insert( event ); } /* 1 Implementation of Class ~MakeHobby~ This class implements the snap rounding technique described in papers by Hobby, Guibas and Marimont. */ class MakeHobby { public: /* 3.1 Constructors and Destructors */ MakeHobby() { }; ~MakeHobby() { }; /* 10.1 Functions for computing a rounded arrangement of line segments */ /* processing the step for the hobby algorithm */ void doHO(); /* compute ToleranceSquare for all BOEvents */ void computeToleranceSq(); /* add BOEvent to batch */ void addBatch(robustGeometry::BOEvent& boEv); /* locate value in the mainActive list */ void locateValue(robustGeometry::ToleranceSquare & ts); /* round to the value corresponding to the ScaleFactor */ double getRoundFactor(const double & x ); /* round the x,-y coordinates of the BOEvent to the center of the ToleranceSquare */ void snapSegment(robustGeometry::BOEvent & boEv, robustGeometry::ToleranceSquare & tolS); /* compute all possible intersections of the given BOEvent and the given ToleranceSquare */ bool computeAllIntersections(robustGeometry::BOEvent & boEv, robustGeometry::ToleranceSquare & tolS); /* tests whether the BOEvent from the argument intersects a ToleranceSquare */ void intersectsToleranceSquare(robustGeometry::BOEvent & boEv); /* update the main active list corresponding to the given range */ void updateMainActive(double von, double bis); /* set values to BOEvent */ void set_BOEvents( set & events) { events_org = events;}; /* split segments except at intersection points */ void splitSegment(robustGeometry::BOEvent & boEv); /* split segments at intersection points */ void splitIntersectedSegments(); /* 3.2 Functions for printing out */ void printHOInitialEvents(); void printHOEvents(); void printHOResult_events(); void printHOResult_lines(); void printSegment(); void addSegment( robustGeometry::BOLine& line ); void sortSegments(); void sortRoundedSegments(); vector& get_result_segments( ) { return segments; }; private: set tolSquare; set mainActive; set events_org; set batch; set result_line; vector result_e; vector segments; /* compute the intersection of a given segment */ int intersect(double sx1, double sy1, double ex2, double ey2, double sx3, double sy3, double ex4, double ey4); }; /* speed up the search for a segment */ struct FindSegment{ private : robustGeometry::BOLine line_; public: FindSegment( const robustGeometry::BOLine& line) : line_(line){} bool operator()(const robustGeometry::BOLine & line) const{ return line == line_; } }; void MakeHobby::addSegment( robustGeometry::BOLine& line ) { segments.push_back( line ); } void MakeHobby::printSegment( ){ vector::iterator sg_it; int i = 0; for (sg_it = segments.begin(); sg_it != segments.end(); ++sg_it ){ cout << ++i << " X1 : " << sg_it->getX1() << " Y1 : " << sg_it->getY1() << " X2 : " << sg_it->getX2() << " Y2 " << sg_it->getY2() << " X1_r : " << sg_it->getX1_round() << " Y1_r : " << sg_it->getY1_round() << " X2 _r : " << sg_it->getX2_round() << " Y2_r " << sg_it->getY2_round() << " Owner " << sg_it->getOwner() << endl; } } bool sortEvents( const robustGeometry::BOEvent &i, const robustGeometry::BOEvent &j){ if( i.getX()==j.getX()) return (i.getY()::iterator row_it = events_org.begin(); for (; row_it != events_org.end(); ++row_it) { be = *row_it; addBatch(be); } //build tolerance square for events computeToleranceSq(); set< robustGeometry::HOBatch, robustGeometry::CompBatch >::iterator batch_it = batch.begin(); for (; batch_it != batch.end(); ++batch_it) { robustGeometry::HOBatch ba_tmp; ba_tmp = *batch_it; double x = ba_tmp.getX(); updateMainActive(x-robustGeometry::ScaleFactor- robustGeometry::Epsilon, x+robustGeometry::ScaleFactor); //locate y values in „main active list“ and snap robustGeometry::BOEvent be; robustGeometry::ToleranceSquare ts; set::iterator ts_it = tolSquare.begin(); for (; ts_it != tolSquare.end(); ts_it++ ) { ts = *ts_it; locateValue(ts); } //update „main active list“ valid for X=i-Epsilon updateMainActive(x-robustGeometry::Epsilon, x+robustGeometry::ScaleFactor); set::iterator bo_it = mainActive.begin(); robustGeometry::BOEvent boEv_tmp; for (; bo_it != bo_it; bo_it++) { boEv_tmp = *bo_it; intersectsToleranceSquare(boEv_tmp); } //update „main active list“ valid for x=i+1/2-Epsilon } splitIntersectedSegments(); sortSegments(); } void MakeHobby::printHOInitialEvents( ){ set::iterator it; for ( it = events_org.begin(); it != events_org.end(); ++it){ cout << it->getX() << " " << it->getY() << " Pointtype "; if ( it->getPointType() == robustGeometry::start ) cout << "start"; else if ( it->getPointType() == robustGeometry::end ) cout << "end"; else { robustGeometry::BOEvent tmpEv = *it; cout << "intersect" << " line1 " << tmpEv.getLine1().getX1() << " line2 " << tmpEv.getLine1().getX2(); } cout << endl; } } void MakeHobby::printHOEvents( ){ vector::iterator it; for ( it =result_e.begin(); it != result_e.end(); ++it){ robustGeometry::BOEvent boev = *it; cout << " X " << it->getX() << " Y " << it->getY(); if ( it->getPointType() == robustGeometry::start ) cout << " start line x1 " << boev.getLine().getX1() << " y1 " << boev.getLine().getY1() << " x2 " << boev.getLine().getX2() << " y2 " << boev.getLine().getY2(); else if ( it->getPointType() == robustGeometry::end ) cout << " end line x1 " << boev.getLine().getX1() << " y1 " << boev.getLine().getY1() << " x2 " << boev.getLine().getX2() << " y2 " << boev.getLine().getY2(); else cout << " intersect line1 x1 " << boev.getLine1().getX1() << " y1 " << boev.getLine1().getY1() << " x2 " << boev.getLine1().getX2() << " y2 " << boev.getLine1().getY2() << " line2 x1 " << boev.getLine2().getX1() << " y1 " << boev.getLine2().getY1() << " x2 " << boev.getLine2().getX2() << " y2 " << boev.getLine2().getY2(); cout << endl; } } void MakeHobby::printHOResult_events( ){ vector::iterator it; for ( it = result_e.begin(); it != result_e.end(); it++) { cout << "result_e: x " <getX() << " y " << it->getY(); cout << endl; } } void MakeHobby::printHOResult_lines( ){ set::iterator it; for ( it = result_line.begin(); it != result_line.end(); it++) { cout << it->getX1() << " " << it->getY1() << " "; cout << it->getX2() << " " << it->getY2(); cout << endl; } } int MakeHobby::intersect(double sx1, double sy1, double ex2, double ey2, double sx3, double sy3, double ex4, double ey4) { //return =0 OK, 1 lines parallel, 2 no intersection point //x,y intersection point double a1 = 0.0; double a2 = 0.0; double b1 = 0.0; double b2 = 0.0; double c1 = 0.0; double c2 = 0.0; double m = 0.0; double x; // double y a1 = ey2 - sy1; b1 = sx1 - ex2; c1 = ex2 * sy1 - sx1 * ey2; a2 = ey4 - sy3; b2 = sx3 - ex4; c2 = ex4 * sy3 - sx3 * ey4; m = a1 * b2 - a2 * b1; if (m == 0) return 1; x = (b1 * c2 - b2 * c1) / m; //intersection range if (x < sx1 || x < sx3 || x > ex2 || x > ex4) return 2; //y = (a2 * c1 - a1 * c2) / m; return 0; } void MakeHobby::updateMainActive(double von, double bis ) { robustGeometry::BOEvent bo_tmp; mainActive.clear(); set::iterator bo_it = events_org.begin(); for (; bo_it != events_org.end(); bo_it++) { if ((bo_it->getX() >= von) && (bo_it->getX() < bis)) { bo_tmp = *bo_it; mainActive.insert(bo_tmp); } else if (bo_it->getX() > bis ) break; } } void MakeHobby::locateValue(robustGeometry::ToleranceSquare & ts) { robustGeometry::BOEvent boEv; set::iterator ma_it = mainActive.begin(); for (; ma_it != mainActive.end(); ++ma_it) { boEv = *ma_it; double y_org = boEv.getY(); double x_org = boEv.getX(); if ( (y_org < ts.getY11() ) && (y_org >= ts.getY21() ) && (x_org >= ts.getX11() ) && (x_org < ts.getX12() )) { snapSegment(boEv,ts); } } } void MakeHobby::snapSegment(robustGeometry::BOEvent & boEv, robustGeometry::ToleranceSquare & ts) { double x = 0.0; double y = 0.0; x = ts.getSnapX(); y = ts.getSnapY(); boEv.setX(x); boEv.setY(y); result_e.push_back( boEv ); if ( boEv.getPointType() == robustGeometry::intersect){ return; } vector::iterator sg_it; sg_it = find_if(segments.begin(), segments.end(), FindSegment(boEv.getLine()) ); if ( sg_it != segments.end()){ if ( boEv.getPointType() == robustGeometry::start){ sg_it->setX1_round(x); sg_it->setY1_round(y); } else { sg_it->setX2_round(x); sg_it->setY2_round(y); }; } } void MakeHobby::splitIntersectedSegments(){ sort(result_e.begin(),result_e.end(),sortEvents); vector::iterator re_it = result_e.begin(); for (; re_it != result_e.end(); re_it++){ if ( re_it->getPointType( ) != robustGeometry::intersect ) continue; robustGeometry::BOEvent boEv = * re_it; //if there isn't a start or endpunkt from linie 1 if ( (boEv.getOrigX() != boEv.getLine1().getX1() ) && (boEv.getOrigY() != boEv.getLine1().getY1() ) && (boEv.getOrigX() != boEv.getLine1().getX2() ) && (boEv.getOrigY() != boEv.getLine1().getY2() ) ){ re_it->getLine1().setX2(boEv.getOrigX() ); re_it->getLine1().setY2(boEv.getOrigY() ); vector::iterator sg_it = find_if(segments.begin(), segments.end(),FindSegment(boEv.getLine1()) ); if ( sg_it != segments.end()){ robustGeometry::BOLine sg_new = *sg_it; sg_it->setX2(boEv.getOrigX()); sg_it->setY2(boEv.getOrigY()); sg_it->setX2_round(boEv.getX()); sg_it->setY2_round(boEv.getY()); //new segment sg_new.setX1(boEv.getOrigX()); sg_new.setY1(boEv.getOrigY()); sg_new.setX1_round(boEv.getX()); sg_new.setY1_round(boEv.getY()); addSegment(sg_new); //update all other intersections vector::iterator re_it_z; robustGeometry::BOEvent boEv_z; for ( re_it_z = result_e.begin(); re_it_z != result_e.end(); re_it_z++){ if ( ( re_it_z->getPointType( ) != robustGeometry::intersect ) ) continue; boEv_z = *re_it_z; if ( boEv_z.getLine1() == boEv.getLine1() ){ re_it_z->getLine1( ).setX1(boEv.getOrigX()); re_it_z->getLine1( ).setY1(boEv.getOrigY()); } else if ( re_it_z->getLine2() == boEv.getLine1() ){ re_it_z->getLine2( ).setX1(boEv.getOrigX()); re_it_z->getLine2( ).setY1(boEv.getOrigY()); } } } } if ( (boEv.getOrigX() != boEv.getLine2().getX1() ) && (boEv.getOrigY() != boEv.getLine2().getY1() ) && (boEv.getOrigX() != boEv.getLine2().getX2() ) && (boEv.getOrigY() != boEv.getLine2().getY2() ) ){ re_it->getLine2().setX2(boEv.getOrigX() ); re_it->getLine2().setY2(boEv.getOrigY() ); vector::iterator sg_it = find_if(segments.begin(), segments.end(), FindSegment(boEv.getLine2()) ); if ( sg_it != segments.end()){ robustGeometry::BOLine sg_new = *sg_it; sg_it->setX2(boEv.getOrigX()); sg_it->setY2(boEv.getOrigY()); sg_it->setX2_round(boEv.getX()); sg_it->setY2_round(boEv.getY()); //new segment sg_new.setX1(boEv.getOrigX()); sg_new.setY1(boEv.getOrigY()); sg_new.setX1_round(boEv.getX()); sg_new.setY1_round(boEv.getY()); addSegment(sg_new); //update all other intersections vector::iterator re_it_z; robustGeometry::BOEvent boEv_z; for (re_it_z = result_e.begin(); re_it_z != result_e.end(); re_it_z++){ if ( re_it_z->getPointType( ) != robustGeometry::intersect ) continue; boEv_z = *re_it_z; if ( boEv_z.getLine1() == boEv.getLine2() ){ re_it_z->getLine1( ).setX1(boEv.getOrigX()); re_it_z->getLine1( ).setY1(boEv.getOrigY()); } else if ( re_it_z->getLine2() == boEv.getLine2() ){ re_it_z->getLine2( ).setX1(boEv.getOrigX()); re_it_z->getLine2( ).setY1(boEv.getOrigY()); } } } } } } /* tolerance square is open along right. It's sufficient to check intersection: * with the segment and any hot pixel edge * between the segment and both the left and bottom edges */ bool MakeHobby::computeAllIntersections(robustGeometry::BOEvent & boEv, robustGeometry::ToleranceSquare & tolS) { double x1 = 0.0; double y1 = 0.0; double x2 = 0.0; double y2 = 0.0; double i11 = 0.0; double j11 = 0.0; double i12 = 0.0; double j12 = 0.0; double i21 = 0.0; double j21 = 0.0; double i22 = 0.0; double j22 = 0.0; int isIntersected = 1; x1 = boEv.getLine().getX1(); y1 = boEv.getLine().getY1(); x2 = boEv.getLine().getX2(); y2 = boEv.getLine().getY2(); i11 = tolS.getX11(); j11 = tolS.getY11(); i12 = tolS.getX12(); j12 = tolS.getY12(); i21 = tolS.getX21(); j21 = tolS.getY21(); i22 = tolS.getX22(); j22 = tolS.getY22(); //top isIntersected = intersect(x1, y1, x2, y2, i11, j11, i12,j12); if (isIntersected == 0) return true; //bottom isIntersected = intersect(x1, y1, x2, y2, i21, j21, i22, j22); if (isIntersected == 0) return true; //left isIntersected = intersect(x1, y1, x2, y2, i11, j11, i21, j21); if (isIntersected == 0) return true; //right isIntersected = intersect(x1, y1, x2, y2, i12, j12 , i22, j22 ); if (isIntersected == 0) return true; return false; } void MakeHobby::intersectsToleranceSquare(robustGeometry::BOEvent & boEv) { bool isIntersected = false; double y_org = 0.0; //search corresponding tolerance square y_org = boEv.getY(); set:: iterator ts_it = tolSquare.begin(); for (; ts_it != tolSquare.end(); ++ts_it) { if ((y_org >= (ts_it->getY11() - robustGeometry::ScaleFactor)) && (y_org <= (ts_it->getY12() + robustGeometry::ScaleFactor))) { robustGeometry::ToleranceSquare tolSq = *ts_it; isIntersected = computeAllIntersections(boEv, tolSq); if (isIntersected == true) { snapSegment(boEv,tolSq); } } } } void MakeHobby::addBatch(robustGeometry::BOEvent & boEv) { double x = 0.0; double y = 0.0; x = getRoundFactor( boEv.getX()); y = getRoundFactor( boEv.getY()); robustGeometry::HOBatch ba = robustGeometry::HOBatch(x, y); batch.insert(ba); } ; void MakeHobby::computeToleranceSq() { double x11 = 0.0; double y11 = 0.0; double x12 = 0.0; double y12 = 0.0; double x21 = 0.0; double y21 = 0.0; double x22 = 0.0; double y22 = 0.0; double snap_x = 0.0; double snap_y = 0.0; robustGeometry::BOEvent boEv; set::iterator ev_it1 = events_org.begin(); for (; ev_it1 != events_org.end(); ++ev_it1) { robustGeometry::BOEvent boEv = *ev_it1; snap_x = getRoundFactor(boEv.getX()); snap_y = getRoundFactor(boEv.getY()); x11 = snap_x - robustGeometry::ScaleFactor -robustGeometry::Epsilon; y11 = snap_y + robustGeometry::ScaleFactor; x12 = snap_x + robustGeometry::ScaleFactor; y12 = y11; x21 = x11; y21 = snap_y - robustGeometry::ScaleFactor -robustGeometry::Epsilon; x22 = x12; y22 = y21; robustGeometry::ToleranceSquare ts = robustGeometry::ToleranceSquare(x11, y11, x12, y12, x21, y21, x22, y22,snap_x, snap_y, boEv); tolSquare.insert(ts); } }; void MakeBO::IntersectionBO(const Line& line1, const Line& line2, Line& result) { // Initialisation result.Clear(); result.SetDefined(true); if (line1.Size() == 0 || line2.Size() == 0) { return; //empty line } //Initialize event queue: all segment endpoints //Sort x by increasing x and y priority_queue , greater > q1; priority_queue , greater > q2; avltree::AVLTree sss; avlseg::ownertype owner; int pos1 = 0; int pos2 = 0; avlseg::ExtendedHalfSegment nextExtHs; int src = 0; avlseg::AVLSegment left1, right1, common1, left2, right2; avlseg::AVLSegment tmpL, tmpR; robustGeometry::BOOwnerType boOwner; MakeHobby* makeHO = new MakeHobby(); result.StartBulkLoad(); while ((owner = selectNext(line1, pos1, line2, pos2, q1, q2, nextExtHs, src)) != avlseg::none) { if (owner == avlseg::first) boOwner = robustGeometry::first; else boOwner = robustGeometry::second; if ( owner == 1 ) boOwner = robustGeometry::first; else boOwner = robustGeometry::second; robustGeometry::BOLine boLine = robustGeometry::BOLine( nextExtHs.GetLeftPoint().GetX(), nextExtHs.GetLeftPoint().GetY(), nextExtHs.GetRightPoint().GetX(), nextExtHs.GetRightPoint().GetY(), boOwner); robustGeometry::BOEvent boEvent_s = robustGeometry::BOEvent( nextExtHs.GetLeftPoint().GetX(), nextExtHs.GetLeftPoint().GetY(), robustGeometry::start,boOwner, boLine); addInitialEvent(boEvent_s); robustGeometry::BOEvent boEvent_e = robustGeometry::BOEvent( nextExtHs.GetRightPoint().GetX(), nextExtHs.GetRightPoint().GetY(), robustGeometry::end, boOwner, boLine); addInitialEvent(boEvent_e); makeHO->addSegment(boLine); }; //printInitialEvents(); doBOCases(); printBOEvents(); makeHO->set_BOEvents( get_BOEvents()); makeHO->printHOInitialEvents(); makeHO->doHO( ); makeHO->printHOEvents(); makeHO->printHOResult_events(); makeHO->printHOResult_lines(); makeHO->sortRoundedSegments(); vector segments = makeHO->get_result_segments(); vector::iterator it = segments.begin(); robustGeometry::BOLine boL = *it; it++; int edgeno = 0; for (; it != segments.end(); ++it ){ if ( ( boL.getOwner() != it->getOwner() ) && ( boL.getX1_round() == it->getX1_round() ) && ( boL.getY1_round() == it->getY1_round() ) && ( boL.getX2_round() == it->getX2_round() ) && ( boL.getY2_round() == it->getY2_round() ) ){ Point p,q; p.Set(it->getX1(), it->getY1()); q.Set(it->getX2(), it->getY2()); HalfSegment hs1(true,p,q); HalfSegment hs2(false,p,q); hs1.attr.edgeno = edgeno; hs2.attr.edgeno = edgeno; edgeno++; result += hs1; result += hs2; cout << " Intersected Line 1 Owner " << boL.getOwner() << " Original X1 " << boL.getX1() << " Y1 " << boL.getY1() << " x2 " << boL.getX2() << " y2 " << boL.getY2() << " Roundedl X1 " << boL.getX1_round() << " Y1 " << boL.getY1_round() << " x2 " << boL.getX2_round() << " y2 " << boL.getY2_round() << endl; cout << " Line 2 Owner " << it->getOwner() << " Original X1 " << it->getX1() << " Y1 " << it->getY1() << " x2 " << it->getX2() << " y2 " << it->getY2() << " Roundedl X1 " << it->getX1_round() << " Y1 " << it->getY1_round() << " x2 " << it->getX2_round() << " y2 " << it->getY2_round() << endl; } boL = *it; } // result.EndBulkLoad(true, false); result.EndBulkLoad(true, true); } /* ~Intersection~ operator for objects line -line */ static int intersectionBO_ll(Word* args, Word& result, int message, Word& local, Supplier s) { result = qp->ResultStorage(s); Line *line1 = ((Line*) args[0].addr); Line *line2 = ((Line*) args[1].addr); cerr << "line1 = "; line1->Print(cerr); cerr << endl; cerr << "line2 = "; line2->Print(cerr); cerr << endl; if (line1->IsDefined() && line2->IsDefined()) { if (line1->IsEmpty() || line2->IsEmpty()) { cout << __PRETTY_FUNCTION__ << ": " "lines are empty!" << endl; ((Line *) result.addr)->SetDefined(false); return (0); } else if (line1->BoundingBox().IsDefined() && line2->BoundingBox().IsDefined()) { if (line1->BoundingBox(). Intersects(line2->BoundingBox())) { MakeBO bo; cout << __PRETTY_FUNCTION__ << ": " "BoundingBox Intersects!" << endl; bo.IntersectionBO(*line1, *line2, *static_cast (result.addr)); return (0); } else { cout << __PRETTY_FUNCTION__ << ": " "BoundingBox don't intersects!" << endl; ((Line *) result.addr)->Clear(); return (0); } } else { MakeBO bo; cout << __PRETTY_FUNCTION__ << ": " "BoundingBox isn't defined!" << endl; bo.IntersectionBO(*line1, *line2, *static_cast (result.addr)); return (0); } } else { cout << __PRETTY_FUNCTION__ << ": " "lines aren't defined!" << endl; cout << __PRETTY_FUNCTION__ << ": value mapping " "implemented only for lines." << endl; ((Line *) result.addr)->Clear(); ((Line *) result.addr)->SetDefined(false); //assert(false); // TODO: Implement IntersectionBOGeneric. return (0); } } /* Operator Description */ struct intersectionInfo: OperatorInfo { intersectionInfo() { name = "intersectionBO"; signature = Line::BasicType() + " x " + Line::BasicType() + " -> " + Line::BasicType(); syntax = "_ intersectionBO _"; meaning = "Intersection predicate for two Lines."; } }; /* 10.3 Selection functions A selection function is quite similar to a type mapping function. The only difference is that it doesn't return a type but the index of a value mapping function being able to deal with the respective combination of input parameter types. Note that a selection function does not need to check the correctness of argument types; it has already been checked by the type mapping function that it is applied to correct arguments. 10.1.1 Selection function ~RGSetOpSelect~ This select function is used for the ~intersectionBO~ operator */ int RGSetOpSelect(ListExpr args) { string a1 = nl->SymbolValue(nl->First(args)); string a2 = nl->SymbolValue(nl->Second(args)); if (a1 == Line::BasicType()) { if (a2 == Line::BasicType()) return 0; return -1; } return -1; } /* 10.4 Value mapping functions A value mapping function implements an operator's main functionality: it takes input arguments and computes the result. Each operator consists of at least one value mapping function. In the case of overloaded operators there are several value mapping functions, one for each possible combination of input parameter types. 10.4.1 Value mapping functions of operator ~intersection~ */ ValueMapping intersectionVM[] = { intersectionBO_ll }; /* Definition of the operators */ Operator test("intersectionBO", intersectionSpec, 1, intersectionVM, RGSetOpSelect, intersectionTM); /* 5 Creating the Algebra */ class RobustGeometryAlgebra: public Algebra { public: RobustGeometryAlgebra() : Algebra() { AddOperator(&test); } ~RobustGeometryAlgebra() { } ; }; /* 12 Initialization Each algebra module needs an initialization function. The algebra manager has a reference to this function if this algebra is included in the list of required algebras, thus forcing the linker to include this module. The algebra manager invokes this function to get a reference to the instance of the algebra class and to provide references to the global nested list container (used to store constructor, type, operator and object information) and to the query processor. The function has a C interface to make it possible to load the algebra dynamically at runtime. */ extern "C" Algebra* InitializeRobustGeometryAlgebra(NestedList* nlRef, QueryProcessor* qpRef) { nl = nlRef; qp = qpRef; return (new RobustGeometryAlgebra()); };