1894 lines
44 KiB
C++
1894 lines
44 KiB
C++
/*
|
|
|
|
|
|
//[_] [\_]
|
|
//[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 <vector>
|
|
#include <set>
|
|
#include <queue>
|
|
#include <stdexcept>
|
|
#include <iostream>
|
|
#include <string.h>
|
|
#include <string>
|
|
#include <cmath>
|
|
#include <algorithm>
|
|
#include <ctime>
|
|
#include <queue>
|
|
#include <iterator>
|
|
#include <sstream>
|
|
#include <limits>
|
|
#include <errno.h>
|
|
#include <cerrno>
|
|
|
|
#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\" ) "
|
|
"( <text>{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 </text--->"
|
|
"<text>intersectionBO(arg1, arg2)</text--->"
|
|
"<text>intersectionBO of two spatial objects</text--->"
|
|
"<text>query intersectionBO(tiergarten, thecenter) </text--->"
|
|
") )";
|
|
|
|
/*
|
|
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<robustGeometry::BOEvent, robustGeometry::CompBOEventXY>
|
|
& get_BOEvents( ){ return boEvents; };
|
|
|
|
|
|
private:
|
|
/*
|
|
sweepLine
|
|
|
|
*/
|
|
set<robustGeometry::BOLine, robustGeometry::CompBOLine > sL;
|
|
/*
|
|
input event queue
|
|
|
|
*/
|
|
set<robustGeometry::BOEvent, robustGeometry::CompBOEventXY> initialEvents;
|
|
/*
|
|
event queue
|
|
|
|
*/
|
|
set<robustGeometry::BOEvent, robustGeometry::CompBOEventXY> 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 <robustGeometry::BOEvent, robustGeometry::CompBOEventXY>
|
|
::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<robustGeometry::BOEvent>::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<robustGeometry::BOEvent>::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<robustGeometry::BOEvent,
|
|
robustGeometry::CompBOEventXY> & 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<robustGeometry::BOLine>& get_result_segments( )
|
|
{ return segments; };
|
|
|
|
private:
|
|
set<robustGeometry::ToleranceSquare,
|
|
robustGeometry::CompToleranceSquareY> tolSquare;
|
|
|
|
set<robustGeometry::BOEvent,
|
|
robustGeometry::CompBOEventXY> mainActive;
|
|
|
|
set<robustGeometry::BOEvent,
|
|
robustGeometry::CompBOEventXY> events_org;
|
|
|
|
set<robustGeometry::HOBatch,
|
|
robustGeometry::CompBatch> batch;
|
|
|
|
set<robustGeometry::BOLine,
|
|
robustGeometry::CompBOLineXYOwn> result_line;
|
|
|
|
vector<robustGeometry::BOEvent> result_e;
|
|
vector<robustGeometry::BOLine> 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<robustGeometry::BOLine>::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()<j.getY());
|
|
return (i.getX()<j.getX());
|
|
|
|
}
|
|
|
|
bool sortRoundedLines( const robustGeometry::BOLine &i,
|
|
const robustGeometry::BOLine &j){
|
|
|
|
if ( i.getX1_round() < j.getX1_round() )
|
|
return true;
|
|
else if ( (i.getX1_round() == j.getX1_round() ) &&
|
|
(i.getY1_round() < j.getY1_round() ) )
|
|
return true;
|
|
else if ( (i.getX1_round() == j.getX1_round() ) &&
|
|
(i.getY1_round() == j.getY1_round() ) &&
|
|
(i.getX2_round() < j.getX2_round() ) )
|
|
return true;
|
|
else if ( (i.getX1_round() == j.getX1_round() ) &&
|
|
(i.getY1_round() == j.getY1_round() ) &&
|
|
(i.getX2_round() == j.getX2_round() ) &&
|
|
(i.getY2_round() < j.getY2_round() ) )
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
bool sortSegment( const robustGeometry::BOLine &i,
|
|
const robustGeometry::BOLine &j){
|
|
|
|
return i < j ;
|
|
}
|
|
double MakeHobby::getRoundFactor(const double & x ){
|
|
return ceil(floor( x / robustGeometry::ScaleFactor)
|
|
* robustGeometry::ScaleFactor);
|
|
}
|
|
|
|
void MakeHobby::sortSegments( ){
|
|
sort(segments.begin() , segments.end(), sortSegment);
|
|
}
|
|
void MakeHobby::sortRoundedSegments( ){
|
|
sort(segments.begin() , segments.end(), sortRoundedLines);
|
|
}
|
|
void MakeHobby::doHO()
|
|
{
|
|
|
|
//build batch, round events
|
|
robustGeometry::BOEvent be;
|
|
set< robustGeometry::BOEvent,
|
|
robustGeometry::CompBOEventXY >::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<robustGeometry::ToleranceSquare,
|
|
robustGeometry::CompToleranceSquareY>::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<robustGeometry::BOEvent,
|
|
robustGeometry::CompBOEventXY>::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<robustGeometry::BOEvent>::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<robustGeometry::BOEvent>::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<robustGeometry::BOEvent>::iterator it;
|
|
for ( it = result_e.begin(); it != result_e.end(); it++)
|
|
{
|
|
cout << "result_e: x " <<it->getX() << " y " << it->getY();
|
|
cout << endl;
|
|
}
|
|
}
|
|
|
|
void MakeHobby::printHOResult_lines( ){
|
|
|
|
set<robustGeometry::BOLine>::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<robustGeometry::BOEvent, robustGeometry::CompBOEventXY>::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<robustGeometry::BOEvent, robustGeometry::CompBOEventXY>::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<robustGeometry::BOLine>::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<robustGeometry::BOEvent>::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<robustGeometry::BOLine>::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<robustGeometry::BOEvent>::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<robustGeometry::BOLine>::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<robustGeometry::BOEvent>::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<robustGeometry::ToleranceSquare,
|
|
robustGeometry::CompToleranceSquareY>::
|
|
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<robustGeometry::BOEvent, robustGeometry::CompBOEventXY >::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<avlseg::ExtendedHalfSegment, vector<
|
|
avlseg::ExtendedHalfSegment> ,
|
|
greater<avlseg::ExtendedHalfSegment> >
|
|
q1;
|
|
priority_queue<avlseg::ExtendedHalfSegment, vector<
|
|
avlseg::ExtendedHalfSegment> ,
|
|
greater<avlseg::ExtendedHalfSegment> >
|
|
q2;
|
|
|
|
avltree::AVLTree<avlseg::AVLSegment> 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<robustGeometry::BOLine> segments = makeHO->get_result_segments();
|
|
|
|
vector<robustGeometry::BOLine>::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<Line*> (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<Line*> (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());
|
|
};
|
|
|