2565 lines
61 KiB
C++
2565 lines
61 KiB
C++
/*
|
|
----
|
|
This file is part of SECONDO.
|
|
|
|
Copyright (C) 2004-2007, 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
|
|
----
|
|
|
|
*/
|
|
|
|
#include "AlgoFortune.h"
|
|
#include "TinHelper.h"
|
|
#include "string"
|
|
#include <stack>
|
|
#include <typeinfo>
|
|
#include <initializer_list>
|
|
extern "C" {
|
|
#include "quadmath.h"
|
|
}
|
|
|
|
#include "gmpxx.h"
|
|
|
|
#ifdef FORTUNE_NO_LOGGING
|
|
#define LOGGING_SWITCH_OFF
|
|
#endif
|
|
#include <TinLogging.h>
|
|
|
|
namespace tin {
|
|
BeachLineNode BeachLineNode::nullnode = BeachLineNode();
|
|
//int VoronoiEdge::instanceCounter = 0;
|
|
const VERTEX_COORDINATE BeachLineNode::BREAK_X_UNSET =
|
|
-std::numeric_limits<VERTEX_COORDINATE>::max();
|
|
const __float128 BeachLineNode::PRECALC_UNSET = -std::numeric_limits<
|
|
VERTEX_COORDINATE>::max();
|
|
BeachLine::BeachLine() :
|
|
root(BeachLineNode()) {
|
|
ySweepLine = -std::numeric_limits<VERTEX_COORDINATE>::min();
|
|
|
|
}
|
|
|
|
BeachLine::~BeachLine() {
|
|
|
|
}
|
|
void BeachLine::rescueVertices(VertexContainerSet* rescueSet) {
|
|
|
|
BeachLineNode * current, *lbp, *rbp;
|
|
const Vertex * tmp;
|
|
bool newornot;
|
|
|
|
current = root.getLeftMost();
|
|
|
|
while (current) {
|
|
tmp = rescueSet->insertVertex(current->site1, newornot);
|
|
current->site1 = tmp;
|
|
lbp = current->getLeftBreakPoint();
|
|
if (lbp)
|
|
lbp->site2 = tmp;
|
|
rbp = current->getRightBreakPoint();
|
|
if (rbp)
|
|
rbp->site1 = tmp;
|
|
|
|
current = current->getRightNeighbor();
|
|
}
|
|
|
|
}
|
|
void BeachLine::print(std::ostream & os) const {
|
|
root.print(os, 1);
|
|
os << "-------Beachline left to right from sweepline---\n";
|
|
BeachLineNode * current = 0;
|
|
|
|
current = root.getRightMost();
|
|
while (current != 0) {
|
|
current->print(os);
|
|
current = current->getLeftNeighbor();
|
|
}
|
|
|
|
os << "\n Sweepline y: " << ySweepLine << " \n";
|
|
}
|
|
void BeachLine::print_small(std::ostream & os) const {
|
|
os << "-------Beachline left to right from sweepline---\n";
|
|
BeachLineNode * current = 0;
|
|
|
|
current = root.getRightMost();
|
|
while (current != 0) {
|
|
current->print(os);
|
|
current = current->getLeftNeighbor();
|
|
}
|
|
|
|
os << "\n Sweepline y: " << ySweepLine << " \n";
|
|
}
|
|
BeachLineNode * BeachLine::insert(const Vertex * psite,
|
|
BeachLineNode* pParabolaAbove) {
|
|
if (psite == 0)
|
|
throw std::invalid_argument(E_BEACHLINE_INSERT1);
|
|
if (psite->getY() < ySweepLine)
|
|
throw std::invalid_argument(E_BEACHLINE_INSERT);
|
|
|
|
if (pParabolaAbove == &root) {
|
|
root.pleftSon = new BeachLineNode(psite, &root);
|
|
root.site1 = psite;
|
|
root.site2 = 0;
|
|
return &root;
|
|
} else {
|
|
return pParabolaAbove->insert(psite);
|
|
}
|
|
}
|
|
|
|
void BeachLine::setSweepLine(VERTEX_COORDINATE iySweepLine) {
|
|
ySweepLine = iySweepLine;
|
|
}
|
|
BeachLineNode* BeachLine::find(const VERTEX_COORDINATE x) const {
|
|
|
|
return root.find(x, ySweepLine);
|
|
}
|
|
BeachLineNode::BeachLineNode() //construction of root
|
|
{
|
|
site1 = 0;
|
|
site2 = 0;
|
|
pleftSon = 0;
|
|
prightSon = 0;
|
|
parent = 0;
|
|
red = false; //root is always black
|
|
validIterator = false;
|
|
edge = 0;
|
|
precalc_circle = PRECALC_UNSET;
|
|
break_x = BREAK_X_UNSET;
|
|
}
|
|
|
|
BeachLineNode::BeachLineNode(BeachLineNode * iparent, bool leftins,
|
|
BeachLineNode* left, BeachLineNode* right) //construction of inner node
|
|
{
|
|
if (left == 0 || right == 0)
|
|
throw std::invalid_argument(E_BEACHLINENODE_CONSTRUCTOR);
|
|
|
|
edge = 0;
|
|
validIterator = false;
|
|
red = true; // inner node is red initially
|
|
|
|
pleftSon = left;
|
|
prightSon = right;
|
|
prightSon->parent = this;
|
|
pleftSon->parent = this;
|
|
|
|
site1 = left->getRightMost()->site1;
|
|
site2 = right->getLeftMost()->site1;
|
|
|
|
break_x = BREAK_X_UNSET;
|
|
precalc_circle = PRECALC_UNSET;
|
|
|
|
parent = iparent;
|
|
|
|
if (leftins) {
|
|
parent->pleftSon = this;
|
|
parent->site1 = this->getRightMost()->getSite();
|
|
} else {
|
|
parent->prightSon = this;
|
|
parent->site2 = this->getLeftMost()->getSite();
|
|
}
|
|
|
|
BeachLineNode * lbp = this->getLeftBreakPoint();
|
|
if (lbp) {
|
|
lbp->setSite2(this->getLeftMost()->getSite());
|
|
lbp->resetBreakX();
|
|
}
|
|
BeachLineNode * rbp = this->getRightBreakPoint();
|
|
|
|
if (rbp) {
|
|
rbp->setSite1(this->getRightMost()->getSite());
|
|
rbp->resetBreakX();
|
|
}
|
|
|
|
}
|
|
BeachLineNode::BeachLineNode(const Vertex* pV1, BeachLineNode * iparent) {
|
|
if (pV1 == 0)
|
|
throw std::invalid_argument(E_BEACHLINENODE_CONSTRUCTOR1);
|
|
validIterator = false;
|
|
site1 = pV1;
|
|
site2 = 0;
|
|
pleftSon = 0;
|
|
prightSon = 0;
|
|
parent = iparent;
|
|
red = false; //leaf is always black
|
|
edge = 0;
|
|
|
|
break_x = BREAK_X_UNSET;
|
|
precalc_circle = PRECALC_UNSET;
|
|
}
|
|
|
|
BeachLineNode::~BeachLineNode() {
|
|
if (pleftSon != 0 && pleftSon != &nullnode) {
|
|
delete pleftSon;
|
|
pleftSon = 0;
|
|
}
|
|
if (prightSon != 0 && prightSon != &nullnode) {
|
|
delete prightSon;
|
|
prightSon = 0;
|
|
}
|
|
|
|
if (edge)
|
|
edge->destroy();
|
|
|
|
}
|
|
BeachLineNode* BeachLineNode::insert_no_split(const Vertex* pV,
|
|
const VERTEX_COORDINATE sweepy) {
|
|
|
|
if (pV == 0)
|
|
throw std::invalid_argument(E_BEACHLINENODE_INSERT);
|
|
|
|
if (*pV == *site1)
|
|
throw std::invalid_argument(E_BEACHLINENODE_INSERT1);
|
|
|
|
if (!isLeaf())
|
|
throw std::runtime_error(E_BEACHLINENODE_INSERT2);
|
|
|
|
BeachLineNode * innerNode, *newarc, *lbp, *rbp;
|
|
POINT_COORDINATE bpleft, bpright;
|
|
|
|
lbp = this->getLeftBreakPoint();
|
|
rbp = this->getRightBreakPoint();
|
|
|
|
if (lbp)
|
|
bpleft = lbp->getParabolaIntersection_sec(sweepy);
|
|
if (rbp)
|
|
bpright = rbp->getParabolaIntersection_sec(sweepy);
|
|
|
|
newarc = new BeachLineNode(pV, &nullnode);
|
|
|
|
if ((!rbp && lbp)
|
|
|| (rbp && lbp
|
|
&& absolute(bpright - pV->getX()) > absolute(bpleft - pV->getX()))) {
|
|
//here the left breakpoints edge has to be rescued and overwritten
|
|
|
|
innerNode = new BeachLineNode(this->parent, this->isLeftChild(), newarc,
|
|
this);
|
|
innerNode->balanceTree();
|
|
|
|
newarc->rescueVoronoiEdge(lbp->edge);
|
|
lbp->edge = 0;
|
|
lbp->precalc_circle = BeachLineNode::PRECALC_UNSET;
|
|
//for SiteCircleEvents both breakpoints represent new edges
|
|
|
|
VoronoiEdge::getInstance(innerNode);
|
|
if (lbp)
|
|
VoronoiEdge::getInstance(lbp);
|
|
|
|
return newarc;
|
|
|
|
} else //insert left seen from the sweep line
|
|
{
|
|
//here the right breakpoints edge has to be rescued and overwritten
|
|
innerNode = new BeachLineNode(this->parent, this->isLeftChild(), this,
|
|
newarc);
|
|
innerNode->balanceTree();
|
|
|
|
newarc->rescueVoronoiEdge(rbp->edge);
|
|
rbp->edge = 0;
|
|
rbp->precalc_circle = BeachLineNode::PRECALC_UNSET;
|
|
//for SiteCircleEvents both breakpoints represent new edge
|
|
VoronoiEdge::getInstance(innerNode);
|
|
if (rbp)
|
|
VoronoiEdge::getInstance(rbp);
|
|
|
|
return newarc;
|
|
}
|
|
|
|
}
|
|
bool BeachLineNode::isVirtualRoot() const {
|
|
|
|
if (!isLeaf() && !isRoot() && parent->isRoot())
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
/*
|
|
The Method balanceTree balances the red black tree after insertion.
|
|
|
|
*/
|
|
void BeachLineNode::balanceTree() {
|
|
if (isLeaf())
|
|
throw std::runtime_error(E_BEACHLINENODE_BALANCETREE);
|
|
if (isRoot()) {
|
|
return;
|
|
}
|
|
if (isVirtualRoot()) {
|
|
red = false;
|
|
return;
|
|
}
|
|
if (!parent->red)
|
|
return;
|
|
|
|
if (getUncle() && getUncle()->red) {
|
|
parent->red = false;
|
|
getUncle()->red = false;
|
|
|
|
getGrandParent()->red = true;
|
|
|
|
getGrandParent()->balanceTree();
|
|
return;
|
|
}
|
|
|
|
if (isLeftChild() && !parent->isLeftChild()) {
|
|
parent->rotateLeft();
|
|
|
|
prightSon->getGrandParent()->red = true;
|
|
prightSon->parent->red = false;
|
|
prightSon->getGrandParent()->rotateRight();
|
|
return;
|
|
} else if (!isLeftChild() && parent->isLeftChild()) {
|
|
parent->rotateRight();
|
|
|
|
pleftSon->getGrandParent()->red = true;
|
|
pleftSon->parent->red = false;
|
|
pleftSon->getGrandParent()->rotateLeft();
|
|
return;
|
|
|
|
}
|
|
|
|
if (!isLeftChild() && !parent->isLeftChild()) {
|
|
getGrandParent()->red = true;
|
|
parent->red = false;
|
|
getGrandParent()->rotateRight();
|
|
return;
|
|
}
|
|
|
|
if (isLeftChild() && parent->isLeftChild()) {
|
|
getGrandParent()->red = true;
|
|
parent->red = false;
|
|
getGrandParent()->rotateLeft();
|
|
return;
|
|
}
|
|
|
|
throw std::runtime_error(E_BEACHLINENODE_BALANCETREE1);
|
|
|
|
}
|
|
void BeachLineNode::balanceTreeDeletion() {
|
|
BeachLineNode * bro, *brol, *bror;
|
|
|
|
if (isRoot()) {
|
|
return;
|
|
}
|
|
if (isVirtualRoot()) {
|
|
return;
|
|
}
|
|
|
|
bro = getBrother();
|
|
if (!bro)
|
|
return;
|
|
|
|
bror = bro->getRight();
|
|
brol = bro->getLeft();
|
|
|
|
if (!bror || !brol)
|
|
return;
|
|
|
|
if (!parent->red) {
|
|
if (bro->red) {
|
|
parent->red = true;
|
|
bro->red = false;
|
|
|
|
if (!isLeftChild()) {
|
|
parent->rotateLeft();
|
|
this->balanceTreeDeletion();
|
|
return;
|
|
} else {
|
|
parent->rotateRight();
|
|
this->balanceTreeDeletion();
|
|
return;
|
|
}
|
|
} else {
|
|
if (!bror->red && !brol->red) {
|
|
bro->red = true;
|
|
parent->balanceTreeDeletion();
|
|
return;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
if (!bro->red && !bror->red && !brol->red) {
|
|
parent->red = false;
|
|
bro->red = true;
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (bro->isLeftChild() && !bro->red && bror->red && !brol->red) {
|
|
bror->red = false;
|
|
bro->red = true;
|
|
bro->rotateRight();
|
|
bro = this->getBrother();
|
|
bror = bro->getRight();
|
|
brol = bro->getLeft();
|
|
} else if (!bro->isLeftChild() && !bro->red && !bror->red && brol->red) {
|
|
brol->red = false;
|
|
bro->red = true;
|
|
bro->rotateLeft();
|
|
bro = this->getBrother();
|
|
bror = bro->getRight();
|
|
brol = bro->getLeft();
|
|
}
|
|
|
|
if (!bror || !brol)
|
|
return;
|
|
if (bro->isLeaf())
|
|
return;
|
|
|
|
if (bro->isLeftChild()) {
|
|
if (bro->getLeft()->isLeaf())
|
|
return;
|
|
|
|
bro->red = parent->red;
|
|
parent->red = false;
|
|
brol->red = false;
|
|
bro->rotateLeft();
|
|
return;
|
|
} else {
|
|
if (bro->getRight()->isLeaf())
|
|
return;
|
|
|
|
bro->red = parent->red;
|
|
parent->red = false;
|
|
bror->red = false;
|
|
bro->rotateRight();
|
|
return;
|
|
}
|
|
|
|
throw std::runtime_error(E_BEACHLINENODE_BALANCETREE1);
|
|
|
|
}
|
|
void BeachLineNode::rotateLeft() {
|
|
if (isRoot())
|
|
return;
|
|
|
|
if (isLeaf() || !pleftSon || pleftSon->isLeaf())
|
|
throw std::runtime_error(E_BEACHLINENODE_ROTATELEFT);
|
|
|
|
BeachLineNode *switchNode;
|
|
|
|
if (isLeftChild()) {
|
|
parent->setLeft(pleftSon);
|
|
pleftSon->parent = parent;
|
|
} else {
|
|
parent->setRight(pleftSon);
|
|
pleftSon->parent = parent;
|
|
}
|
|
|
|
switchNode = pleftSon->getRight();
|
|
pleftSon->setRight(this);
|
|
this->parent = pleftSon;
|
|
|
|
this->setLeft(switchNode);
|
|
switchNode->parent = this;
|
|
}
|
|
void BeachLineNode::rotateRight() {
|
|
if (isRoot())
|
|
return;
|
|
|
|
if (isLeaf() || !prightSon || prightSon->isLeaf())
|
|
throw std::runtime_error(E_BEACHLINENODE_ROTATELEFT);
|
|
|
|
BeachLineNode *switchNode;
|
|
|
|
if (isLeftChild()) {
|
|
parent->setLeft(prightSon);
|
|
prightSon->parent = parent;
|
|
} else {
|
|
parent->setRight(prightSon);
|
|
prightSon->parent = parent;
|
|
}
|
|
|
|
switchNode = prightSon->getLeft();
|
|
prightSon->setLeft(this);
|
|
this->parent = prightSon;
|
|
|
|
this->setRight(switchNode);
|
|
switchNode->parent = this;
|
|
}
|
|
VoronoiEdge* BeachLineNode::getVoronoiEdge() const {
|
|
return edge;
|
|
}
|
|
void BeachLineNode::setVoronoiEdge(VoronoiEdge *e) {
|
|
|
|
edge = e;
|
|
}
|
|
void BeachLineNode::resetVoronoiEdge() {
|
|
if (isLeaf())
|
|
throw std::runtime_error("(BeachLineNode::setVoronoiEdge)");
|
|
|
|
if (edge)
|
|
edge->destroyHard();
|
|
|
|
edge = 0;
|
|
|
|
}
|
|
void BeachLineNode::resetRescuedVoronoiEdge() {
|
|
edge = 0;
|
|
}
|
|
void BeachLineNode::rescueVoronoiEdge(VoronoiEdge *e) {
|
|
if (edge)
|
|
throw std::runtime_error(
|
|
"The VoronoiEdge is already set.(BeachLineNode::rescueVoronoiEdge)");
|
|
|
|
edge = e;
|
|
}
|
|
BeachLineNode* BeachLineNode::insert(const Vertex* pV) {
|
|
if (pV == 0)
|
|
throw std::invalid_argument(E_BEACHLINENODE_INSERT);
|
|
|
|
if (*pV == *site1)
|
|
throw std::invalid_argument(E_BEACHLINENODE_INSERT1);
|
|
|
|
if (!isLeaf())
|
|
throw std::runtime_error(E_BEACHLINENODE_INSERT2);
|
|
|
|
BeachLineNode * innerNode, *newarc, *removededgebp, *lbp, *rbp;
|
|
|
|
newarc = new BeachLineNode(pV, &nullnode);
|
|
|
|
if (site1->getY() == pV->getY()) {
|
|
if (pV->getX() > site1->getX()) {
|
|
//on the right side seen from the sweep line
|
|
|
|
removededgebp = this->getLeftBreakPoint();
|
|
if (removededgebp)
|
|
removededgebp->resetVoronoiEdge();
|
|
//VoronoiEdge was wrong so remove it
|
|
|
|
innerNode = new BeachLineNode(this->parent, this->isLeftChild(), newarc,
|
|
this);
|
|
|
|
lbp = newarc->getLeftBreakPoint();
|
|
rbp = newarc->getRightBreakPoint();
|
|
|
|
innerNode->balanceTree();
|
|
|
|
//here a new edge is assigned to the (possible) two new breakpoints
|
|
if (rbp)
|
|
VoronoiEdge::getInstance(rbp)->addEnd(VORONOI_OPEN_END);
|
|
if (lbp)
|
|
VoronoiEdge::getInstance(lbp)->addEnd(VORONOI_OPEN_END);
|
|
|
|
return newarc;
|
|
|
|
} else {
|
|
|
|
removededgebp = this->getRightBreakPoint();
|
|
if (removededgebp)
|
|
removededgebp->resetVoronoiEdge();
|
|
//VoronoiEdge was wrong so remove it
|
|
|
|
innerNode = new BeachLineNode(this->parent, this->isLeftChild(), this,
|
|
newarc);
|
|
|
|
lbp = newarc->getLeftBreakPoint();
|
|
rbp = newarc->getRightBreakPoint();
|
|
|
|
innerNode->balanceTree();
|
|
//here a new edge is assigned to the (possible) two new breakpoints
|
|
if (rbp)
|
|
VoronoiEdge::getInstance(rbp)->addEnd(VORONOI_OPEN_END);
|
|
if (lbp)
|
|
VoronoiEdge::getInstance(lbp)->addEnd(VORONOI_OPEN_END);
|
|
|
|
return newarc;
|
|
}
|
|
} else //arc split
|
|
{
|
|
prightSon = new BeachLineNode(site1, this);
|
|
site2 = site1;
|
|
innerNode = new BeachLineNode(this, true,
|
|
new BeachLineNode(site1, &nullnode), newarc);
|
|
|
|
this->red = true;
|
|
this->balanceTree();
|
|
innerNode->balanceTree();
|
|
|
|
//here a new edge is assigned to the two new breakpoints
|
|
VoronoiEdge::getInstance(this, innerNode);
|
|
|
|
//this makes circle calculation faster
|
|
__float128 x1 = site2->getX();
|
|
__float128 y1 = site2->getY();
|
|
__float128 x2 = site1->getX();
|
|
__float128 y2 = site1->getY();
|
|
|
|
this->precalc_circle = (x1 * x1 + y1 * y1 - x2 * x2 - y2 * y2) / 2;
|
|
innerNode->precalc_circle = -this->precalc_circle;
|
|
|
|
return newarc;
|
|
}
|
|
|
|
}
|
|
BeachLineNode * BeachLineNode::getLeftBreakPoint() const {
|
|
const BeachLineNode * current;
|
|
current = this;
|
|
|
|
while (current && current->isLeftChild()) {
|
|
current = current->getParent();
|
|
}
|
|
|
|
if (!current)
|
|
return 0;
|
|
|
|
return current->getParent();
|
|
|
|
}
|
|
void BeachLineNode::setSite2(const Vertex * psite2) {
|
|
site2 = psite2;
|
|
|
|
}
|
|
void BeachLineNode::setSite1(const Vertex * psite1) {
|
|
site1 = psite1;
|
|
|
|
}
|
|
|
|
BeachLineNode * BeachLineNode::getRightBreakPoint() const {
|
|
const BeachLineNode * current;
|
|
current = this;
|
|
|
|
while (current && !current->isLeftChild()) {
|
|
current = current->getParent();
|
|
}
|
|
|
|
if (!current)
|
|
return 0;
|
|
if (current->getParent()->isRoot() && current->getParent()->isLeaf())
|
|
return 0;
|
|
|
|
return current->getParent();
|
|
|
|
}
|
|
|
|
BeachLineNode * BeachLineNode::getRightMost() const {
|
|
const BeachLineNode * current;
|
|
current = this;
|
|
|
|
if (isRoot() && isNull())
|
|
return 0;
|
|
|
|
if (isRoot() && isLeaf())
|
|
current = current->pleftSon;
|
|
|
|
while (!current->isLeaf()) {
|
|
current = current->getRight();
|
|
}
|
|
return const_cast<BeachLineNode*>(current);
|
|
}
|
|
BeachLineNode * BeachLineNode::getLeftMost() const {
|
|
const BeachLineNode * current;
|
|
current = this;
|
|
|
|
if (isRoot() && isNull())
|
|
return 0;
|
|
|
|
if (isRoot() && isLeaf())
|
|
current = current->pleftSon;
|
|
|
|
while (!current->isLeaf()) {
|
|
current = current->getLeft();
|
|
}
|
|
|
|
return const_cast<BeachLineNode*>(current);
|
|
|
|
}
|
|
BeachLineNode * BeachLineNode::getBrother() const {
|
|
if (parent == 0)
|
|
return 0;
|
|
|
|
if (parent->getLeft() == this)
|
|
return parent->getRight();
|
|
else
|
|
return parent->getLeft();
|
|
}
|
|
BeachLineNode * BeachLineNode::remove(Triangle * t) {
|
|
LOGP
|
|
LOG(this)
|
|
BeachLineNode * leftbp;
|
|
BeachLineNode * rightbp;
|
|
BeachLineNode * brother;
|
|
BeachLineNode * changedBp=0;
|
|
|
|
if (!isLeaf())
|
|
throw std::runtime_error(E_BEACHLINENODE_REMOVE1);
|
|
|
|
if (parent->isRoot()) {
|
|
if (isLeftChild()) {
|
|
parent->site1 = 0;
|
|
parent->pleftSon = 0;
|
|
} else {
|
|
parent->site2 = 0;
|
|
parent->prightSon = 0;
|
|
}
|
|
|
|
delete this;
|
|
return parent;
|
|
}
|
|
|
|
parent->edge->addEnd(t);
|
|
|
|
parent->edge = 0;
|
|
|
|
brother = getBrother();
|
|
brother->parent = parent->parent;
|
|
|
|
if (parent->isLeftChild()) {
|
|
parent->parent->pleftSon = brother;
|
|
} else {
|
|
parent->parent->prightSon = brother;
|
|
|
|
}
|
|
|
|
leftbp = brother->getLeftBreakPoint();
|
|
rightbp = brother->getRightBreakPoint();
|
|
if (leftbp) {
|
|
if (brother->isLeaf()) {
|
|
|
|
if (leftbp->site2 != brother->site1) {
|
|
leftbp->site2 = brother->site1;
|
|
|
|
leftbp->edge->addEnd(t);
|
|
leftbp->edge = 0;
|
|
|
|
leftbp->resetBreakX();
|
|
|
|
//this makes circle calculation faster
|
|
__float128 x1 = leftbp->site2->getX();
|
|
__float128 y1 = leftbp->site2->getY();
|
|
__float128 x2 = leftbp->site1->getX();
|
|
__float128 y2 = leftbp->site1->getY();
|
|
|
|
leftbp->precalc_circle = (x1 * x1 + y1 * y1 - x2 * x2 - y2 * y2) / 2;
|
|
|
|
VoronoiEdge::getInstance(leftbp)->addEnd(t);
|
|
changedBp = leftbp;
|
|
}
|
|
} else {
|
|
|
|
if (leftbp->site2 != brother->getLeftMost()->site1) {
|
|
leftbp->site2 = brother->getLeftMost()->site1;
|
|
|
|
leftbp->edge->addEnd(t);
|
|
leftbp->edge = 0;
|
|
leftbp->resetBreakX();
|
|
|
|
//this makes circle calculation faster
|
|
__float128 x1 = leftbp->site2->getX();
|
|
__float128 y1 = leftbp->site2->getY();
|
|
__float128 x2 = leftbp->site1->getX();
|
|
__float128 y2 = leftbp->site1->getY();
|
|
|
|
leftbp->precalc_circle = (x1 * x1 + y1 * y1 - x2 * x2 - y2 * y2) / 2;
|
|
|
|
VoronoiEdge::getInstance(leftbp)->addEnd(t);
|
|
changedBp = leftbp;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
if (rightbp) {
|
|
if (brother->isLeaf()) {
|
|
if (rightbp->site1 != brother->site1) {
|
|
rightbp->site1 = brother->site1;
|
|
rightbp->edge->addEnd(t);
|
|
rightbp->edge = 0;
|
|
|
|
rightbp->resetBreakX();
|
|
|
|
//this makes circle calculation faster
|
|
__float128 x1 = rightbp->site2->getX();
|
|
__float128 y1 = rightbp->site2->getY();
|
|
__float128 x2 = rightbp->site1->getX();
|
|
__float128 y2 = rightbp->site1->getY();
|
|
|
|
rightbp->precalc_circle = (x1 * x1 + y1 * y1 - x2 * x2 - y2 * y2) / 2;
|
|
|
|
VoronoiEdge::getInstance(rightbp)->addEnd(t);
|
|
changedBp = rightbp;
|
|
}
|
|
}
|
|
|
|
else {
|
|
if (rightbp->site1 != brother->getRightMost()->site1) {
|
|
rightbp->site1 = brother->getRightMost()->site1;
|
|
rightbp->edge->addEnd(t);
|
|
rightbp->edge = 0;
|
|
|
|
rightbp->resetBreakX();
|
|
|
|
//this makes circle calculation faster
|
|
__float128 x1 = rightbp->site2->getX();
|
|
__float128 y1 = rightbp->site2->getY();
|
|
__float128 x2 = rightbp->site1->getX();
|
|
__float128 y2 = rightbp->site1->getY();
|
|
|
|
rightbp->precalc_circle = (x1 * x1 + y1 * y1 - x2 * x2 - y2 * y2) / 2;
|
|
|
|
VoronoiEdge::getInstance(rightbp)->addEnd(t);
|
|
changedBp = rightbp;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
parent->pleftSon = 0;
|
|
parent->prightSon = 0;
|
|
//balancing only if a black node was deleted otherwise not necessary
|
|
if (!parent->red)
|
|
brother->balanceTreeDeletion();
|
|
|
|
delete parent;
|
|
delete this;
|
|
return changedBp;
|
|
|
|
}
|
|
BeachLineNode * BeachLineNode::removeMultiEvent(Triangle** t1,
|
|
Triangle** t2) {
|
|
LOGP
|
|
LOG(this)
|
|
BeachLineNode * leftbp;
|
|
BeachLineNode * rightbp;
|
|
BeachLineNode * brother;
|
|
BeachLineNode * changedBp=0;
|
|
|
|
if (!isLeaf())
|
|
throw std::runtime_error(E_BEACHLINENODE_REMOVE1);
|
|
|
|
if (parent->isRoot()) {
|
|
if (isLeftChild()) {
|
|
parent->site1 = 0;
|
|
parent->pleftSon = 0;
|
|
} else {
|
|
parent->site2 = 0;
|
|
parent->prightSon = 0;
|
|
}
|
|
|
|
delete this;
|
|
return parent;
|
|
}
|
|
|
|
*t1 = parent->edge->getOnlyEnd();
|
|
parent->edge->addEnd(VORONOI_OPEN_END);
|
|
parent->edge = 0;
|
|
|
|
brother = getBrother();
|
|
brother->parent = parent->parent;
|
|
|
|
if (parent->isLeftChild()) {
|
|
parent->parent->pleftSon = brother;
|
|
} else {
|
|
parent->parent->prightSon = brother;
|
|
|
|
}
|
|
|
|
leftbp = brother->getLeftBreakPoint();
|
|
rightbp = brother->getRightBreakPoint();
|
|
//find "new" breakpoint -> node is kept and changed
|
|
if (leftbp) {
|
|
if (brother->isLeaf()) {
|
|
|
|
if (leftbp->site2 != brother->site1) {
|
|
leftbp->site2 = brother->site1;
|
|
|
|
*t2 = leftbp->edge->getOnlyEnd();
|
|
leftbp->edge->addEnd(VORONOI_OPEN_END);
|
|
leftbp->edge = 0;
|
|
|
|
leftbp->resetBreakX();
|
|
|
|
//this makes circle calculation faster
|
|
__float128 x1 = leftbp->site2->getX();
|
|
__float128 y1 = leftbp->site2->getY();
|
|
__float128 x2 = leftbp->site1->getX();
|
|
__float128 y2 = leftbp->site1->getY();
|
|
|
|
leftbp->precalc_circle = (x1 * x1 + y1 * y1 - x2 * x2 - y2 * y2) / 2;
|
|
|
|
VoronoiEdge::getInstance(leftbp)->addEnd(VORONOI_OPEN_END);
|
|
changedBp = leftbp;
|
|
}
|
|
} else {
|
|
|
|
if (leftbp->site2 != brother->getLeftMost()->site1) {
|
|
leftbp->site2 = brother->getLeftMost()->site1;
|
|
|
|
*t2 = leftbp->edge->getOnlyEnd();
|
|
leftbp->edge->addEnd(VORONOI_OPEN_END);
|
|
leftbp->edge = 0;
|
|
leftbp->resetBreakX();
|
|
|
|
//this makes circle calculation faster
|
|
__float128 x1 = leftbp->site2->getX();
|
|
__float128 y1 = leftbp->site2->getY();
|
|
__float128 x2 = leftbp->site1->getX();
|
|
__float128 y2 = leftbp->site1->getY();
|
|
|
|
leftbp->precalc_circle = (x1 * x1 + y1 * y1 - x2 * x2 - y2 * y2) / 2;
|
|
|
|
VoronoiEdge::getInstance(leftbp)->addEnd(VORONOI_OPEN_END);
|
|
changedBp = leftbp;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
if (rightbp) {
|
|
if (brother->isLeaf()) {
|
|
if (rightbp->site1 != brother->site1) {
|
|
rightbp->site1 = brother->site1;
|
|
|
|
*t2 = rightbp->edge->getOnlyEnd();
|
|
|
|
rightbp->edge->addEnd(VORONOI_OPEN_END);
|
|
rightbp->edge = 0;
|
|
|
|
rightbp->resetBreakX();
|
|
|
|
//this makes circle calculation faster
|
|
__float128 x1 = rightbp->site2->getX();
|
|
__float128 y1 = rightbp->site2->getY();
|
|
__float128 x2 = rightbp->site1->getX();
|
|
__float128 y2 = rightbp->site1->getY();
|
|
|
|
rightbp->precalc_circle = (x1 * x1 + y1 * y1 - x2 * x2 - y2 * y2) / 2;
|
|
|
|
VoronoiEdge::getInstance(rightbp)->addEnd(VORONOI_OPEN_END);
|
|
changedBp = rightbp;
|
|
}
|
|
}
|
|
|
|
else {
|
|
if (rightbp->site1 != brother->getRightMost()->site1) {
|
|
rightbp->site1 = brother->getRightMost()->site1;
|
|
*t2 = rightbp->edge->getOnlyEnd();
|
|
rightbp->edge->addEnd(VORONOI_OPEN_END);
|
|
rightbp->edge = 0;
|
|
|
|
rightbp->resetBreakX();
|
|
|
|
//this makes circle calculation faster
|
|
__float128 x1 = rightbp->site2->getX();
|
|
__float128 y1 = rightbp->site2->getY();
|
|
__float128 x2 = rightbp->site1->getX();
|
|
__float128 y2 = rightbp->site1->getY();
|
|
|
|
rightbp->precalc_circle = (x1 * x1 + y1 * y1 - x2 * x2 - y2 * y2) / 2;
|
|
|
|
VoronoiEdge::getInstance(rightbp)->addEnd(VORONOI_OPEN_END);
|
|
changedBp = rightbp;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
parent->pleftSon = 0;
|
|
parent->prightSon = 0;
|
|
//balancing only if a black node was deleted otherwise not necessary
|
|
if (!parent->red)
|
|
brother->balanceTreeDeletion();
|
|
|
|
delete parent;
|
|
delete this;
|
|
return changedBp;
|
|
|
|
}
|
|
|
|
BeachLineNode* BeachLineNode::find(const VERTEX_COORDINATE x,
|
|
const VERTEX_COORDINATE ySweepLine) const {
|
|
bool goLeft;
|
|
|
|
if (isNull())
|
|
return const_cast<BeachLineNode*>(this);
|
|
if (isRoot() && site1 != 0 && site2 == 0)
|
|
return pleftSon->find(x, ySweepLine);
|
|
if (isRoot() && site2 != 0 && site1 == 0)
|
|
throw std::runtime_error("should not occur");
|
|
|
|
if (isLeaf())
|
|
return const_cast<BeachLineNode*>(this);
|
|
|
|
//try to use value of the last calculation
|
|
if (break_x != BREAK_X_UNSET) {
|
|
BREAK_DIRECTION dir = getBreakXDirection();
|
|
if (dir == BREAK_X_LEFT && x < break_x)
|
|
return prightSon->find(x, ySweepLine);
|
|
if (dir == BREAK_X_RIGHT && x > break_x)
|
|
return pleftSon->find(x, ySweepLine);
|
|
if (dir == BREAK_X_VERTICAL && x < break_x)
|
|
return prightSon->find(x, ySweepLine);
|
|
if (dir == BREAK_X_VERTICAL && x > break_x)
|
|
return pleftSon->find(x, ySweepLine);
|
|
}
|
|
|
|
//no decision possible based on direction so calculate anew
|
|
break_x = this->getParabolaIntersection(ySweepLine);
|
|
|
|
goLeft = ((x)) > break_x;
|
|
|
|
if (goLeft) {
|
|
return pleftSon->find(x, ySweepLine);
|
|
} else {
|
|
return prightSon->find(x, ySweepLine);
|
|
}
|
|
}
|
|
bool BeachLineNode::isNull() const {
|
|
return (site1 == 0 ? true : false);
|
|
}
|
|
|
|
bool BeachLineNode::isLeftChild() const {
|
|
if (parent != 0)
|
|
return (parent->pleftSon == this);
|
|
return false;
|
|
}
|
|
|
|
bool BeachLineNode::isLeaf() const {
|
|
|
|
return (site1 != 0 && site2 == 0 ? true : false);
|
|
}
|
|
bool BeachLineNode::isRoot() const {
|
|
return (parent == 0);
|
|
}
|
|
/*
|
|
Method determineBreakXDirection returns the x direction of
|
|
the movement of the break point defined by parameters
|
|
~vsite1~ and ~vsite2~. ATTENTION vsite1 has to be site1
|
|
and vsite2 has to be site2 !
|
|
|
|
*/
|
|
BREAK_DIRECTION BeachLineNode::determineBreakXDirection(
|
|
const Vertex* vsite1, const Vertex* vsite2) const {
|
|
//direction seen from the beach
|
|
if (vsite1->getY() < vsite2->getY()) //Parabola site1 on top
|
|
{
|
|
return BREAK_X_RIGHT;
|
|
} else if (vsite1->getY() > vsite2->getY()) //Parabola site2 on top
|
|
{
|
|
return BREAK_X_LEFT;
|
|
} else {
|
|
return BREAK_X_VERTICAL;
|
|
}
|
|
|
|
}
|
|
BREAK_DIRECTION BeachLineNode::determineBreakYDirection(
|
|
const Vertex* vsite1, const Vertex* vsite2) const {
|
|
//direction seen from the beach
|
|
if (vsite1->getX() < vsite2->getX()) {
|
|
return BREAK_Y_UP;
|
|
} else if (vsite1->getX() > vsite2->getX()) {
|
|
return BREAK_Y_DOWN;
|
|
} else {
|
|
return BREAK_Y_HORIZONTAL;
|
|
}
|
|
|
|
}
|
|
BeachLineNode* BeachLineNode::getLeft() const {
|
|
return pleftSon;
|
|
}
|
|
|
|
BeachLineNode* BeachLineNode::getRight() const {
|
|
return prightSon;
|
|
}
|
|
|
|
void BeachLineNode::setLeft(BeachLineNode* nl) {
|
|
pleftSon = nl;
|
|
}
|
|
|
|
void BeachLineNode::setRight(BeachLineNode* nr) {
|
|
prightSon = nr;
|
|
}
|
|
void BeachLineNode::print_simple(std::ostream& os) const {
|
|
|
|
os << (isLeaf() ? "Leaf" : "") << "* BeachLineNode - "
|
|
|
|
<< (isLeaf() ? "Leaf" : "InnerNode") << "\t" << this << " color red: "
|
|
<< red << " VoronoiEdge: " << edge << "\n";
|
|
if (validIterator)
|
|
os << "Connected Event: " << (*event).second << "\n";
|
|
|
|
os << " site1: ";
|
|
if (site1 != 0)
|
|
site1->print(os);
|
|
|
|
os << "\t site2: ";
|
|
if (site2 != 0)
|
|
site2->print(os);
|
|
if (parent != 0) {
|
|
os << "\n" << " parent site: ";
|
|
if (parent->site1 != 0)
|
|
parent->site1->print();
|
|
if (parent->site2 != 0)
|
|
parent->site2->print();
|
|
}
|
|
}
|
|
void BeachLineNode::print(std::ostream& os, int tab) const {
|
|
std::string str;
|
|
str.append(tab, '\t');
|
|
os << (isLeaf() ? "Leaf" : "") << str << "* BeachLineNode - "
|
|
|
|
<< (isLeaf() ? "Leaf" : "InnerNode") << "\t" << this << " color red: "
|
|
<< red << " VoronoiEdge: " << edge << "\n";
|
|
if (validIterator)
|
|
os << "Connected Event: " << (*event).second << "\n";
|
|
|
|
os << str << " site1: ";
|
|
if (site1 != 0)
|
|
site1->print(os);
|
|
|
|
os << "\t site2: ";
|
|
if (site2 != 0)
|
|
site2->print(os);
|
|
|
|
if (parent != 0) {
|
|
os << "\n" << str << " parent site: ";
|
|
if (parent->site1 != 0)
|
|
parent->site1->print();
|
|
if (parent->site2 != 0)
|
|
parent->site2->print();
|
|
}
|
|
os << "\n";
|
|
tab++;
|
|
if (pleftSon != 0)
|
|
pleftSon->print(os, tab);
|
|
|
|
if (prightSon != 0)
|
|
prightSon->print(os, tab);
|
|
}
|
|
BeachLineNode* BeachLineNode::getLeftNeighbor() const {
|
|
if (!isLeaf())
|
|
throw std::runtime_error(E_BEACHLINENODE_GETNEIGHBOR);
|
|
|
|
BeachLineNode * current;
|
|
|
|
current = getLeftBreakPoint();
|
|
|
|
if (current == 0)
|
|
return 0;
|
|
|
|
current = current->getLeft();
|
|
if (current == 0)
|
|
return 0;
|
|
while (!current->isLeaf())
|
|
current = current->getRight();
|
|
|
|
return current;
|
|
|
|
}
|
|
BeachLineNode* BeachLineNode::getLeftNeighbor(BeachLineNode** bp) const {
|
|
if (!isLeaf())
|
|
throw std::runtime_error(E_BEACHLINENODE_GETNEIGHBOR);
|
|
|
|
BeachLineNode * current;
|
|
|
|
current = getLeftBreakPoint();
|
|
(*bp) = current;
|
|
|
|
if (current == 0)
|
|
return 0;
|
|
|
|
current = current->getLeft();
|
|
if (current == 0)
|
|
return 0;
|
|
while (!current->isLeaf())
|
|
current = current->getRight();
|
|
|
|
return current;
|
|
|
|
}
|
|
BeachLineNode* BeachLineNode::getLeftNeighbor(POINT_COORDINATE& breakpoint,
|
|
const VERTEX_COORDINATE sweepliney) const {
|
|
if (!isLeaf())
|
|
throw std::runtime_error(E_BEACHLINENODE_GETNEIGHBOR);
|
|
|
|
BeachLineNode * current;
|
|
|
|
current = getLeftBreakPoint();
|
|
|
|
if (current == 0)
|
|
return 0;
|
|
|
|
breakpoint = current->getParabolaIntersection_sec(sweepliney);
|
|
|
|
current = current->getLeft();
|
|
if (current == 0)
|
|
return 0;
|
|
|
|
while (!current->isLeaf())
|
|
current = current->getRight();
|
|
|
|
return current;
|
|
|
|
}
|
|
void BeachLineNode::check() const {
|
|
if (isRoot() && isLeaf()) {
|
|
pleftSon->check();
|
|
}
|
|
if (!isLeaf() && !isNull()) {
|
|
if (pleftSon->getRightMost()->site1 != site1
|
|
|| prightSon->getLeftMost()->site1 != site2) {
|
|
LOG(this)
|
|
throw std::runtime_error("Wrong");
|
|
|
|
}
|
|
|
|
pleftSon->check();
|
|
prightSon->check();
|
|
}
|
|
|
|
}
|
|
void BeachLine::checkTree() const {
|
|
root.check();
|
|
}
|
|
BeachLineNode * BeachLineNode::getParent() const {
|
|
return parent;
|
|
}
|
|
|
|
BeachLineNode * BeachLineNode::getGrandParent() const {
|
|
if (parent)
|
|
return parent->parent;
|
|
|
|
return 0;
|
|
}
|
|
BeachLineNode * BeachLineNode::getUncle() const {
|
|
BeachLineNode * p;
|
|
BeachLineNode * gp;
|
|
|
|
p = getParent();
|
|
if (!p)
|
|
return 0;
|
|
|
|
gp = getGrandParent();
|
|
if (!gp)
|
|
return 0;
|
|
|
|
if (p->isLeftChild()) {
|
|
return gp->getRight();
|
|
} else
|
|
return gp->getLeft();
|
|
}
|
|
|
|
BeachLineNode* BeachLineNode::getRightNeighbor() const {
|
|
if (!isLeaf())
|
|
throw std::runtime_error(E_BEACHLINENODE_GETNEIGHBOR);
|
|
|
|
BeachLineNode * current;
|
|
|
|
current = getRightBreakPoint();
|
|
|
|
if (current == 0)
|
|
return 0;
|
|
current = current->getRight();
|
|
if (current == 0)
|
|
return 0;
|
|
|
|
while (!current->isLeaf())
|
|
current = current->getLeft();
|
|
|
|
return current;
|
|
}
|
|
BeachLineNode* BeachLineNode::getRightNeighbor(BeachLineNode** bp) const {
|
|
if (!isLeaf())
|
|
throw std::runtime_error(E_BEACHLINENODE_GETNEIGHBOR);
|
|
|
|
BeachLineNode * current;
|
|
|
|
current = getRightBreakPoint();
|
|
|
|
(*bp) = current;
|
|
|
|
if (current == 0)
|
|
return 0;
|
|
current = current->getRight();
|
|
if (current == 0)
|
|
return 0;
|
|
|
|
while (!current->isLeaf())
|
|
current = current->getLeft();
|
|
|
|
return current;
|
|
}
|
|
BeachLineNode* BeachLineNode::getRightNeighbor(
|
|
POINT_COORDINATE& breakpoint, const VERTEX_COORDINATE sweepliney) const {
|
|
if (!isLeaf())
|
|
throw std::runtime_error(E_BEACHLINENODE_GETNEIGHBOR);
|
|
|
|
BeachLineNode * current;
|
|
current = getRightBreakPoint();
|
|
|
|
if (current == 0)
|
|
return 0;
|
|
|
|
breakpoint = current->getParabolaIntersection_sec(sweepliney);
|
|
|
|
current = current->getRight();
|
|
if (current == 0)
|
|
return 0;
|
|
|
|
while (!current->isLeaf())
|
|
current = current->getLeft();
|
|
|
|
return current;
|
|
}
|
|
|
|
void BeachLineNode::setParent(BeachLineNode* p) {
|
|
parent = p;
|
|
}
|
|
POINT_COORDINATE BeachLineNode::getParabolaIntersection_sec(
|
|
const VERTEX_COORDINATE ySweepLine) const {
|
|
PreciseDouble result, c01, c02, c1, c2, a, b, c, sol, sol1, sol2;
|
|
if ((site1->getY() - ySweepLine) <= 0.000001) //TODO make accurate
|
|
return site1->getX();
|
|
if ((site2->getY() - ySweepLine) <= 0.000001)
|
|
return site2->getX();
|
|
|
|
SecureOperator::startSecureCalc();
|
|
|
|
c1 = (PreciseDouble) ((1))
|
|
/ ((PreciseDouble) (((site1->getY() - ySweepLine))) * 2);
|
|
c2 = (PreciseDouble) ((1))
|
|
/ ((PreciseDouble) (((site2->getY() - ySweepLine))) * 2);
|
|
c01 = c1
|
|
* ((PreciseDouble) ((site1->getX())) * (PreciseDouble) ((site1->getX()))
|
|
- (PreciseDouble) ((ySweepLine)) * (PreciseDouble) ((ySweepLine))
|
|
+ (PreciseDouble) ((site1->getY()))
|
|
* (PreciseDouble) ((site1->getY())));
|
|
c02 = c2
|
|
* ((PreciseDouble) ((site2->getX())) * (PreciseDouble) ((site2->getX()))
|
|
- (PreciseDouble) ((ySweepLine)) * (PreciseDouble) ((ySweepLine))
|
|
+ (PreciseDouble) ((site2->getY()))
|
|
* (PreciseDouble) ((site2->getY())));
|
|
a = c1 - c2;
|
|
b = (c2 * (PreciseDouble) ((site2->getX()))
|
|
- c1 * (PreciseDouble) ((site1->getX()))) * 2;
|
|
c = c01 - c02;
|
|
|
|
if (a == 0) {
|
|
result = -c / b;
|
|
|
|
} else {
|
|
PreciseArithmetic::error_sqrt(b * b - a * 4 * c, sol);
|
|
|
|
sol1 = (-b + sol) / (a * 2);
|
|
sol2 = (-b - sol) / (a * 2);
|
|
//TODO SC same Y?
|
|
//site2 on top of site1 (from sweep line)
|
|
if (site1->getY() > site2->getY())
|
|
result = (sol1 > sol2 ? sol1 : sol2); //bigger solution
|
|
else
|
|
//site1 is on top
|
|
result = (sol1 > sol2 ? sol2 : sol1); //smaller solution
|
|
|
|
}
|
|
|
|
return result;
|
|
}
|
|
VERTEX_COORDINATE BeachLineNode::getParabolaIntersection(
|
|
const VERTEX_COORDINATE ySweepLine) const {
|
|
VERTEX_COORDINATE result, c01, c02, c1, c2, a, b, c, sol, sol1, sol2;
|
|
|
|
if (((site1->getY() - ySweepLine) <= 0.000001)
|
|
&& site1->getY() == site2->getY())
|
|
return (site1->getX() + site2->getX()) / 2;
|
|
if ((site1->getY() - ySweepLine) <= 0.000001)
|
|
return site1->getX();
|
|
if ((site2->getY() - ySweepLine) <= 0.000001)
|
|
return site2->getX();
|
|
|
|
SecureOperator::startSecureCalc();
|
|
|
|
c1 = 1 / (((site1->getY() - ySweepLine)) * 2);
|
|
c2 = 1 / (((site2->getY() - ySweepLine)) * 2);
|
|
c01 = c1
|
|
* (site1->getX() * ((site1->getX())) - ((ySweepLine)) * ((ySweepLine))
|
|
+ ((site1->getY())) * ((site1->getY())));
|
|
c02 = c2
|
|
* (((site2->getX())) * ((site2->getX()))
|
|
- ((ySweepLine)) * ((ySweepLine))
|
|
+ ((site2->getY())) * ((site2->getY())));
|
|
a = c1 - c2;
|
|
b = (c2 * ((site2->getX())) - c1 * ((site1->getX()))) * 2;
|
|
c = c01 - c02;
|
|
|
|
if (a == 0) {
|
|
result = -c / b;
|
|
|
|
} else {
|
|
sol = std::sqrt(b * b - a * 4 * c);
|
|
|
|
sol1 = (-b + sol) / (a * 2);
|
|
sol2 = (-b - sol) / (a * 2);
|
|
//TODO SC same Y?
|
|
//site2 on top of site1 (from sweep line)
|
|
if (site1->getY() > site2->getY())
|
|
result = (sol1 > sol2 ? sol1 : sol2); //bigger solution
|
|
else
|
|
//site1 is on top
|
|
result = (sol1 > sol2 ? sol2 : sol1); //smaller solution
|
|
|
|
}
|
|
|
|
break_x = result;
|
|
|
|
return result;
|
|
}
|
|
void BeachLineNode::getParabolaIntersection_mp(
|
|
const VERTEX_COORDINATE ySweepLine, mpq_class & result) const {
|
|
double sol;
|
|
mpq_class mp_ySweepLine(ySweepLine);
|
|
mpq_class mp_site1X(site1->getX());
|
|
mpq_class mp_site1Y(site1->getY());
|
|
mpq_class mp_site2X(site2->getX());
|
|
mpq_class mp_site2Y(site2->getY());
|
|
|
|
if ((site1->getY() - ySweepLine) <= 0.00001) {
|
|
result = site1->getX();
|
|
return;
|
|
}
|
|
if ((site2->getY() - ySweepLine) <= 0.00001) {
|
|
result = site2->getX();
|
|
return;
|
|
}
|
|
|
|
mpq_class mp_c1((1 / ((mp_site1Y - mp_ySweepLine) * 2)));
|
|
mpq_class mp_c2((1 / ((mp_site2Y - mp_ySweepLine) * 2)));
|
|
|
|
mpq_class mp_c01(
|
|
mp_c1
|
|
* (mp_site1X * mp_site1X - mp_ySweepLine * mp_ySweepLine
|
|
+ mp_site1Y * mp_site1Y));
|
|
mpq_class mp_c02(
|
|
mp_c2
|
|
* (mp_site2X * mp_site2X - mp_ySweepLine * mp_ySweepLine
|
|
+ mp_site2Y * mp_site2Y));
|
|
|
|
mpq_class mp_a(mp_c1 - mp_c2);
|
|
|
|
mpq_class mp_b((mp_c2 * mp_site2X - mp_c1 * mp_site1X) * 2);
|
|
mpq_class mp_c(mp_c01 - mp_c02);
|
|
|
|
if (mp_a == 0) {
|
|
result = ((-mp_c) / mp_b);
|
|
} else {
|
|
mpq_class mp_sol(mp_b * mp_b - mp_a * 4 * mp_c);
|
|
sol = std::sqrt(mp_sol.get_d());
|
|
|
|
mpq_class sol1(((-mp_b) + sol) / (mp_a * 2));
|
|
mpq_class sol2(((-mp_b) - sol) / (mp_a * 2));
|
|
//TODO SC same Y?
|
|
//site2 on top of site1 (from sweep line)
|
|
if (site1->getY() > site2->getY())
|
|
result = ((sol1 > sol2 ? sol1 : sol2)); //bigger solution
|
|
else
|
|
//site1 is on top
|
|
result = ((sol1 > sol2 ? sol2 : sol1)); //smaller solution
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CircleEvent::CircleEvent(Point_p im, BeachLineNode *iarc) {
|
|
sweep = im;
|
|
arc = iarc;
|
|
LOG("Construct CircleEvent")
|
|
LOG(this)
|
|
}
|
|
CircleEvent::~CircleEvent() {
|
|
|
|
}
|
|
void CircleEvent::removeArcMultiEvent(Triangle ** t1, Triangle ** t2) {
|
|
if (arc != 0) {
|
|
arc->removeMultiEvent(t1, t2);
|
|
arc = 0;
|
|
}
|
|
}
|
|
|
|
bool EventQueue::isCircleAlreadyInQueue(const Point_p& sweeppoint) const {
|
|
|
|
std::multimap<Point_p, CircleEvent *>::const_iterator it =
|
|
circleEventQueue.find(sweeppoint);
|
|
|
|
return it != circleEventQueue.end();
|
|
|
|
}
|
|
const std::multimap<Point_p, CircleEvent*>::iterator EventQueue::addCircleEvent(
|
|
CircleEvent& e, bool & alreadyExists) {
|
|
std::pair<Point_p, CircleEvent*> ins(e.getSweepPoint(), &e);
|
|
LOGP
|
|
alreadyExists = false;
|
|
return circleEventQueue.insert(ins);
|
|
}
|
|
|
|
void EventQueue::removeEvent(BeachLineNode* arc) {
|
|
LOGP
|
|
if (arc && arc->isValidEvent()) //if exists remove event
|
|
{
|
|
delete arc->getEvent()->second;
|
|
circleEventQueue.erase(arc->getEvent());
|
|
arc->resetEvent();
|
|
}
|
|
LOGP}
|
|
|
|
EventQueue::~EventQueue() {
|
|
if (verticesPriorSection)
|
|
delete verticesPriorSection;
|
|
|
|
}
|
|
void EventQueue::createTriangle(const Vertex * v1, const Vertex * v2,
|
|
const Vertex * v3, Triangle** newtriangle) {
|
|
try {
|
|
this->tt->addTriangle_p(*v1, *v2, *v3, newtriangle);
|
|
} catch (std::exception & e) {
|
|
MSG_TO_USER(e.what());
|
|
*newtriangle = 0;
|
|
}
|
|
}
|
|
/*
|
|
The method doFortuneAlgorithm really executes the Fortunes Algorithm
|
|
on the Vertices provided by ~currentSection~. The bool ~finalSection~
|
|
tells whether it is the last section. The last section will free all
|
|
memory occupied by the Algorithm itself.
|
|
|
|
*/
|
|
void EventQueue::doFortuneAlgorithm(VertexContainerSet * currentSection,
|
|
bool finalSection) {
|
|
VertexContainerSet * tmpRescuedVertices = 0;
|
|
std::multimap<Point_p, CircleEvent*>::iterator itc;
|
|
std::multimap<Point_p, CircleEvent*>::iterator it_end_same_circle;
|
|
std::multimap<Point_p, CircleEvent*>::iterator it_end_same_circle_tmp;
|
|
VERTEX_COORDINATE begin_section_y, end_section_y, end_priorsection_y=0;
|
|
const Vertex * v;
|
|
|
|
LOG_EXP(eventId = 0)
|
|
|
|
//Get reverse_iterator as SiteEventQueue
|
|
siteEventQueue = currentSection->getIteratorRbegin();
|
|
|
|
if (currentSection && currentSection->getNoVertices() > 0) {
|
|
begin_section_y = currentSection->getVertexByYIndex(
|
|
currentSection->getNoVertices() - 1)->getY();
|
|
end_section_y = currentSection->getVertexByYIndex(0)->getY();
|
|
} else {
|
|
begin_section_y = -std::numeric_limits<VERTEX_COORDINATE>::max();
|
|
end_section_y = -std::numeric_limits<VERTEX_COORDINATE>::max();
|
|
}
|
|
|
|
if (!verticesPriorSection) {
|
|
end_priorsection_y = std::numeric_limits<VERTEX_COORDINATE>::max();
|
|
verticesPriorSection = new VertexContainerSet(VERTEX_CONTAINER_BIG_SIZE);
|
|
} else {
|
|
v = verticesPriorSection->getVertexByYIndex(0);
|
|
if (v)
|
|
end_priorsection_y = v->getY();
|
|
|
|
}
|
|
//sections from top to bottom and no overlapping !
|
|
if (begin_section_y >= end_priorsection_y)
|
|
throw std::runtime_error(E_EVENTQUEUE_DOFORTUNEALGORITHM);
|
|
|
|
LOG_EXP(this->print())
|
|
|
|
//Handle all events
|
|
while (true) {
|
|
LOG_EXP(eventId++)
|
|
itc = circleEventQueue.end();
|
|
if (circleEventQueue.size() > 0)
|
|
--itc;
|
|
|
|
if (itc == circleEventQueue.end()
|
|
&& siteEventQueue == currentSection->getIteratorRend())
|
|
break; //no more Events
|
|
|
|
//decide which Queue
|
|
//the Event above comes first, but in case of equality SiteEvents first
|
|
//do only events above the end of section in the final section do all
|
|
if ((itc != circleEventQueue.end()
|
|
&& (((*itc).first.y >= end_section_y) || finalSection))
|
|
&& (siteEventQueue == currentSection->getIteratorRend()
|
|
|| ((*itc).first.y > (*siteEventQueue).getY()))) {
|
|
//so CircleEvent is next
|
|
LOG_EXP(this->print())
|
|
|
|
//treats special case more than 3 points on a circle
|
|
//-> check all circles being at the same place
|
|
it_end_same_circle = circleEventQueue.end();
|
|
--it_end_same_circle;
|
|
|
|
if (it_end_same_circle != circleEventQueue.begin()) {
|
|
--it_end_same_circle;
|
|
|
|
while ((*itc).second->isEqual((*it_end_same_circle).second)
|
|
&& it_end_same_circle != circleEventQueue.begin()) {
|
|
--it_end_same_circle;
|
|
}
|
|
|
|
if (!(*itc).second->isEqual((*it_end_same_circle).second)) {
|
|
++it_end_same_circle;
|
|
}
|
|
|
|
}
|
|
//here it_end_same_circle points to
|
|
//the last equal circle or both point to a SiteEvent
|
|
|
|
if (it_end_same_circle == itc) {
|
|
//regular case 3 points on a circle
|
|
//or SiteEvent (since SiteEvents are always different
|
|
//in order there is always only one)
|
|
|
|
(*itc).second->handleEvent(*this);
|
|
delete (*itc).second;
|
|
circleEventQueue.erase(itc);
|
|
} else {
|
|
//special case more than 3 points on a circle
|
|
//-> several circle events at the same place
|
|
static_cast<CircleEvent*>((*itc).second)->handleMultiEvent(*this,
|
|
it_end_same_circle, itc);
|
|
}
|
|
|
|
} else if (siteEventQueue != currentSection->getIteratorRend()
|
|
&& (((*siteEventQueue).getY() >= end_section_y) || finalSection)) {
|
|
SiteEvent::handleEvent(siteEventQueue, *this);
|
|
siteEventQueue++;
|
|
} else {
|
|
|
|
break; //stop at the end of section
|
|
}
|
|
}
|
|
|
|
if (verticesPriorSection && !finalSection) {
|
|
//rescue the vertices needed from the last section
|
|
tmpRescuedVertices = new VertexContainerSet(VERTEX_CONTAINER_BIG_SIZE);
|
|
bl.rescueVertices(tmpRescuedVertices);
|
|
delete verticesPriorSection;
|
|
verticesPriorSection = tmpRescuedVertices;
|
|
delete currentSection;
|
|
}
|
|
|
|
if (finalSection) {
|
|
if (verticesPriorSection)
|
|
delete verticesPriorSection;
|
|
verticesPriorSection = 0;
|
|
delete currentSection;
|
|
}
|
|
LOG("Finished Fortune Algorithm")
|
|
|
|
}
|
|
|
|
bool CircleEvent::isEqual(CircleEvent * e) const {
|
|
|
|
if (absolute(e->sweep.x - sweep.x) < 0.0000001
|
|
&& absolute(e->sweep.y - sweep.y) < 0.0000001)
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
VERTEX_COORDINATE CircleEvent::getY() const {
|
|
return sweep.y;
|
|
}
|
|
|
|
EventQueue::EventQueue(Tin * itt) {
|
|
tt = itt;
|
|
verticesPriorSection = 0;
|
|
}
|
|
void CircleEvent::print(std::ostream& os) const {
|
|
|
|
os << "CircleEvent --- " << this << " sweep: ";
|
|
sweep.print(os);
|
|
os << "\n";
|
|
if (arc != 0) {
|
|
arc->getLeftNeighbor()->print();
|
|
arc->print(os);
|
|
arc->getRightNeighbor()->print();
|
|
|
|
}
|
|
|
|
}
|
|
bool CircleEvent::isIdentical(CircleEvent * e) const {
|
|
|
|
const Vertex * v1=0, *v2=0, *v3=0;
|
|
const Vertex * ev1=0, *ev2=0, *ev3=0;
|
|
BeachLineNode* ln, *rn;
|
|
|
|
ev1 = e->arc->getSite();
|
|
|
|
ln = e->arc->getLeftNeighbor();
|
|
rn = e->arc->getRightNeighbor();
|
|
if (ln)
|
|
ev2 = ln->getSite();
|
|
if (rn)
|
|
ev3 = rn->getSite();
|
|
|
|
v1 = arc->getSite();
|
|
|
|
ln = arc->getLeftNeighbor();
|
|
rn = arc->getRightNeighbor();
|
|
if (ln)
|
|
v2 = ln->getSite();
|
|
if (rn)
|
|
v3 = rn->getSite();
|
|
|
|
if (*ev1 == *v1 && *ev2 == *v2 && *ev3 == *v3)
|
|
return true;
|
|
if (*ev1 == *v1 && *ev2 == *v3 && *ev3 == *v2)
|
|
return true;
|
|
if (*ev1 == *v2 && *ev2 == *v1 && *ev3 == *v3)
|
|
return true;
|
|
if (*ev1 == *v2 && *ev2 == *v3 && *ev3 == *v1)
|
|
return true;
|
|
if (*ev1 == *v3 && *ev2 == *v2 && *ev3 == *v1)
|
|
return true;
|
|
if (*ev1 == *v3 && *ev2 == *v1 && *ev3 == *v2)
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
bool CircleEvent::isIdentical(BeachLineNode * n) const {
|
|
|
|
const Vertex * v1, *v2, *v3;
|
|
const Vertex * ev1, *ev2, *ev3;
|
|
BeachLineNode* ln, *rn;
|
|
|
|
if (!n)
|
|
return false;
|
|
|
|
ev1 = n->getSite();
|
|
|
|
ln = n->getLeftNeighbor();
|
|
rn = n->getRightNeighbor();
|
|
if (ln)
|
|
ev2 = ln->getSite();
|
|
else
|
|
return false;
|
|
|
|
if (rn)
|
|
ev3 = rn->getSite();
|
|
else
|
|
return false;
|
|
v1 = arc->getSite();
|
|
|
|
ln = arc->getLeftNeighbor();
|
|
rn = arc->getRightNeighbor();
|
|
if (ln)
|
|
v2 = ln->getSite();
|
|
else
|
|
return false;
|
|
if (rn)
|
|
v3 = rn->getSite();
|
|
else
|
|
return false;
|
|
|
|
if (*ev1 == *v1 && *ev2 == *v2 && *ev3 == *v3)
|
|
return true;
|
|
if (*ev1 == *v1 && *ev2 == *v3 && *ev3 == *v2)
|
|
return true;
|
|
if (*ev1 == *v2 && *ev2 == *v1 && *ev3 == *v3)
|
|
return true;
|
|
if (*ev1 == *v2 && *ev2 == *v3 && *ev3 == *v1)
|
|
return true;
|
|
if (*ev1 == *v3 && *ev2 == *v2 && *ev3 == *v1)
|
|
return true;
|
|
if (*ev1 == *v3 && *ev2 == *v1 && *ev3 == *v2)
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
Point_p CircleEvent::calculateSweepPoint_mp(const Vertex * p1,
|
|
const Vertex * p2, const Vertex * p3) {
|
|
mpq_class v12, v23, v13, xm, ym, r, x1, y1, x2, y2, x3, y3, sol;
|
|
Point_p sweeppoint;
|
|
|
|
x1 = p1->getX();
|
|
y1 = p1->getY();
|
|
x2 = p2->getX();
|
|
y2 = p2->getY();
|
|
x3 = p3->getX();
|
|
y3 = p3->getY();
|
|
|
|
if (p1 == p2 || p1 == p3 || p2 == p3)
|
|
throw std::invalid_argument(E_CIRCLEEVENT_CALCULATESWEEPPOINT);
|
|
|
|
v12 = (x1 * x1 + y1 * y1 - x2 * x2 - y2 * y2) / 2;
|
|
|
|
if (!(y2 == y3)) {
|
|
|
|
v23 = (x2 * x2 + y2 * y2 - x3 * x3 - y3 * y3) / 2;
|
|
|
|
xm = (v12 - (v23 * (y1 - y2) / (y2 - y3)));
|
|
sol = ((x1 - x2) + ((x3 - x2) / (y2 - y3)) * (y1 - y2));
|
|
|
|
if (sol != 0)
|
|
xm = xm / sol;
|
|
else {
|
|
sweeppoint.x = ERROR_VALUE;
|
|
return sweeppoint;
|
|
}
|
|
|
|
ym = (v23 - xm * (x2 - x3)) / (y2 - y3);
|
|
} else if (!(y1 == y3)) {
|
|
|
|
v13 = (y1 * y1 + x1 * x1 - y3 * y3 - x3 * x3) / 2;
|
|
|
|
xm = (v12 - (v13 * (y1 - y2) / (y1 - y3)));
|
|
sol = ((x1 - x2) + ((x3 - x1) / (y1 - y3)) * (y1 - y2));
|
|
|
|
if (sol != 0)
|
|
xm = xm / sol;
|
|
else {
|
|
sweeppoint.x = ERROR_VALUE;
|
|
return sweeppoint;
|
|
}
|
|
|
|
ym = (v13 - xm * (x1 - x3)) / (y1 - y3);
|
|
} else // all points on a horizontal line
|
|
{
|
|
sweeppoint.x = ERROR_VALUE;
|
|
return sweeppoint;
|
|
}
|
|
|
|
sol = (x3 - xm) * (x3 - xm) + (y3 - ym) * (y3 - ym);
|
|
r = std::sqrt(sol.get_d());
|
|
|
|
sweeppoint.x = xm.get_d();
|
|
sol = ym - r;
|
|
sweeppoint.y = sol.get_d();
|
|
|
|
return sweeppoint;
|
|
}
|
|
Point_p CircleEvent::calculateSweepPoint(Point_p p1, Point_p p2,
|
|
Point_p p3) {
|
|
double v12, v23, v13, xm, ym, r, x1, y1, x2, y2, x3, y3, sol;
|
|
Point_p sweeppoint;
|
|
|
|
if (p1 < p2) {
|
|
sweeppoint = p1;
|
|
p1 = p2;
|
|
p2 = sweeppoint;
|
|
}
|
|
|
|
if (p2 < p3) {
|
|
sweeppoint = p2;
|
|
p2 = p3;
|
|
p3 = sweeppoint;
|
|
|
|
if (p1 < p2) {
|
|
sweeppoint = p1;
|
|
p1 = p2;
|
|
p2 = sweeppoint;
|
|
}
|
|
}
|
|
|
|
x1 = p1.x;
|
|
y1 = p1.y;
|
|
x2 = p2.x;
|
|
y2 = p2.y;
|
|
x3 = p3.x;
|
|
y3 = p3.y;
|
|
|
|
if (p1 == p2 || p1 == p3 || p2 == p3)
|
|
throw std::invalid_argument(E_CIRCLEEVENT_CALCULATESWEEPPOINT);
|
|
|
|
v12 = (x1 * x1 + y1 * y1 - x2 * x2 - y2 * y2) / 2;
|
|
|
|
if (!(y2 == y3)) {
|
|
|
|
v23 = (x2 * x2 + y2 * y2 - x3 * x3 - y3 * y3) / 2;
|
|
|
|
xm = (v12 - (v23 * (y1 - y2) / (y2 - y3)));
|
|
sol = ((x1 - x2) + ((x3 - x2) / (y2 - y3)) * (y1 - y2));
|
|
|
|
if (sol != 0)
|
|
xm = xm / sol;
|
|
else {
|
|
sweeppoint.x = ERROR_VALUE;
|
|
return sweeppoint;
|
|
}
|
|
|
|
ym = (v23 - xm * (x2 - x3)) / (y2 - y3);
|
|
} else if (!(y1 == y3)) {
|
|
|
|
v13 = (y1 * y1 + x1 * x1 - y3 * y3 - x3 * x3) / 2;
|
|
|
|
xm = (v12 - (v13 * (y1 - y2) / (y1 - y3)));
|
|
sol = ((x1 - x2) + ((x3 - x1) / (y1 - y3)) * (y1 - y2));
|
|
|
|
if (sol != 0)
|
|
xm = xm / sol;
|
|
else {
|
|
sweeppoint.x = ERROR_VALUE;
|
|
return sweeppoint;
|
|
}
|
|
|
|
ym = (v13 - xm * (x1 - x3)) / (y1 - y3);
|
|
} else // all points on a horizontal line
|
|
{
|
|
sweeppoint.x = ERROR_VALUE;
|
|
return sweeppoint;
|
|
}
|
|
|
|
sol = (x3 - xm) * (x3 - xm) + (y3 - ym) * (y3 - ym);
|
|
r = std::sqrt(sol);
|
|
|
|
sweeppoint.x = xm;
|
|
sol = ym - r;
|
|
sweeppoint.y = sol;
|
|
|
|
return sweeppoint;
|
|
}
|
|
inline Point_p CircleEvent::calculateSweepPoint_quad(const Vertex* s1,
|
|
const Vertex* s2, const Vertex* s3, const __float128 & precalc12,
|
|
const __float128 & precalc23) {
|
|
|
|
__float128 v12, v23, v13, xm, ym, r, x1, y1, x2, y2, x3, y3, sol;
|
|
|
|
Point_p sweeppoint;
|
|
|
|
x1 = s1->getX();
|
|
y1 = s1->getY();
|
|
x2 = s2->getX();
|
|
y2 = s2->getY();
|
|
x3 = s3->getX();
|
|
y3 = s3->getY();
|
|
|
|
if (precalc12 == BeachLineNode::PRECALC_UNSET)
|
|
v12 = (x1 * x1 + y1 * y1 - x2 * x2 - y2 * y2) / 2;
|
|
else {
|
|
v12 = precalc12;
|
|
}
|
|
|
|
if (!(y2 == y3)) {
|
|
|
|
if (precalc23 == BeachLineNode::PRECALC_UNSET)
|
|
v23 = (x2 * x2 + y2 * y2 - x3 * x3 - y3 * y3) / 2;
|
|
else
|
|
v23 = precalc23;
|
|
|
|
xm = (v12 - (v23 * (y1 - y2) / (y2 - y3)));
|
|
sol = ((x1 - x2) + ((x3 - x2) / (y2 - y3)) * (y1 - y2));
|
|
|
|
if (sol != 0)
|
|
xm = xm / sol;
|
|
else {
|
|
sweeppoint.x = ERROR_VALUE;
|
|
return sweeppoint;
|
|
}
|
|
|
|
ym = (v23 - xm * (x2 - x3)) / (y2 - y3);
|
|
} else if (!(y1 == y3)) {
|
|
|
|
v13 = (y1 * y1 + x1 * x1 - y3 * y3 - x3 * x3) / 2;
|
|
|
|
xm = (v12 - (v13 * (y1 - y2) / (y1 - y3)));
|
|
sol = ((x1 - x2) + ((x3 - x1) / (y1 - y3)) * (y1 - y2));
|
|
|
|
if (sol != 0)
|
|
xm = xm / sol;
|
|
else {
|
|
sweeppoint.x = ERROR_VALUE;
|
|
return sweeppoint;
|
|
}
|
|
|
|
ym = (v13 - xm * (x1 - x3)) / (y1 - y3);
|
|
} else // all points on a horizontal line
|
|
{
|
|
sweeppoint.x = ERROR_VALUE;
|
|
return sweeppoint;
|
|
}
|
|
|
|
sol = (x3 - xm) * (x3 - xm) + (y3 - ym) * (y3 - ym);
|
|
r = sqrtq(sol);
|
|
|
|
sweeppoint.x = xm;
|
|
sol = ym - r;
|
|
sweeppoint.y = sol;
|
|
|
|
return sweeppoint;
|
|
}
|
|
|
|
bool CircleEvent::isVertexInside(Point_p & middle, double radius,
|
|
const Vertex & v) {
|
|
Vector2D dmiddle = Point(middle.x, middle.y) - v;
|
|
|
|
PreciseDouble lx = dmiddle.getDx() * dmiddle.getDx();
|
|
PreciseDouble ly = dmiddle.getDy() * dmiddle.getDy();
|
|
|
|
if ((PreciseDouble) radius * (PreciseDouble) radius > lx + ly + 1)
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
Point_p CircleEvent::calculateCircle_mp(const Vertex& v1, const Vertex& v2,
|
|
const Vertex& v3, double& r) {
|
|
mpq_class v12, v23, v13, xm, ym, x1, y1, x2, y2, x3, y3, sol;
|
|
Point_p middle, p1, p3, p2;
|
|
p1 = Point_p(v1.getX(), v1.getY());
|
|
p2 = Point_p(v2.getX(), v2.getY());
|
|
p3 = Point_p(v3.getX(), v3.getY());
|
|
|
|
x1 = p1.x;
|
|
y1 = p1.y;
|
|
x2 = p2.x;
|
|
y2 = p2.y;
|
|
x3 = p3.x;
|
|
y3 = p3.y;
|
|
|
|
if (p1 == p2 || p1 == p3 || p2 == p3)
|
|
throw std::invalid_argument(E_CIRCLEEVENT_CALCULATESWEEPPOINT);
|
|
|
|
v12 = (x1 * x1 + y1 * y1 - x2 * x2 - y2 * y2) / 2;
|
|
|
|
if (!(y2 == y3)) {
|
|
|
|
v23 = (x2 * x2 + y2 * y2 - x3 * x3 - y3 * y3) / 2;
|
|
|
|
xm = (v12 - (v23 * (y1 - y2) / (y2 - y3)));
|
|
sol = ((x1 - x2) + ((x3 - x2) / (y2 - y3)) * (y1 - y2));
|
|
|
|
if (sol != 0)
|
|
xm = xm / sol;
|
|
else {
|
|
middle.x = ERROR_VALUE;
|
|
return middle;
|
|
}
|
|
|
|
ym = (v23 - xm * (x2 - x3)) / (y2 - y3);
|
|
} else if (!(y1 == y3)) {
|
|
|
|
v13 = (y1 * y1 + x1 * x1 - y3 * y3 - x3 * x3) / 2;
|
|
|
|
xm = (v12 - (v13 * (y1 - y2) / (y1 - y3)));
|
|
sol = ((x1 - x2) + ((x3 - x1) / (y1 - y3)) * (y1 - y2));
|
|
|
|
if (sol != 0)
|
|
xm = xm / sol;
|
|
else {
|
|
middle.x = ERROR_VALUE;
|
|
return middle;
|
|
}
|
|
|
|
ym = (v13 - xm * (x1 - x3)) / (y1 - y3);
|
|
} else // all points on a horizontal line
|
|
{
|
|
middle.x = ERROR_VALUE;
|
|
return middle;
|
|
}
|
|
|
|
sol = (x3 - xm) * (x3 - xm) + (y3 - ym) * (y3 - ym);
|
|
r = std::sqrt(sol.get_d());
|
|
|
|
middle.x = xm.get_d();
|
|
middle.y = ym.get_d();
|
|
|
|
return middle;
|
|
}
|
|
void CircleEvent::handleEvent(EventQueue & eq) {
|
|
LOGP
|
|
LOG(this)
|
|
BeachLineNode * rneigh = 0;
|
|
BeachLineNode * lneigh = 0;
|
|
BeachLineNode * crneigh = 0;
|
|
BeachLineNode * clneigh = 0;
|
|
BeachLineNode * parabolaAbove = 0;
|
|
BeachLineNode * cmid = 0;
|
|
BeachLineNode * lbp = 0;
|
|
BeachLineNode * mbp = 0;
|
|
BeachLineNode * rbp = 0;
|
|
Triangle* newtriangle = 0;
|
|
|
|
eq.getBeachLine()->setSweepLine(sweep.y);
|
|
|
|
parabolaAbove = arc;
|
|
|
|
rneigh = parabolaAbove->getRightNeighbor();
|
|
lneigh = parabolaAbove->getLeftNeighbor();
|
|
|
|
eq.createTriangle(lneigh->getSite(), parabolaAbove->getSite(),
|
|
rneigh->getSite(), &newtriangle);
|
|
|
|
//this condition treats the special case where
|
|
//a circle is founded by a site on the sweep line
|
|
//here the circle must not be removed
|
|
//because the arc lives on despite the circle event
|
|
if ((sweep.y != arc->getSite()->getY())) { //regular case here
|
|
|
|
arc->resetEvent();
|
|
mbp = parabolaAbove->remove(newtriangle);
|
|
arc = 0;
|
|
|
|
// remove neighbor events ,
|
|
//this event is deleted by the event loop (doFortuneAlgorithm)
|
|
|
|
eq.removeEvent(rneigh);
|
|
eq.removeEvent(lneigh);
|
|
|
|
//now check for new CircleEvents
|
|
LOG("Check Event")
|
|
cmid = lneigh;
|
|
clneigh = lneigh->getLeftNeighbor(&lbp);
|
|
crneigh = rneigh;
|
|
|
|
eq.checkEventAndInsert(crneigh, cmid, clneigh, mbp, lbp);
|
|
|
|
cmid = rneigh;
|
|
clneigh = lneigh;
|
|
crneigh = rneigh->getRightNeighbor(&rbp);
|
|
|
|
eq.checkEventAndInsert(crneigh, cmid, clneigh, rbp, mbp);
|
|
|
|
} else { //here special case SiteCircleEvent
|
|
//std::cout<<"SiteCircle ! \n";
|
|
//now that the triangle is known add it to the rescued edge
|
|
arc->getVoronoiEdge()->addEnd(newtriangle);
|
|
//and get rid of the rescued edge
|
|
arc->resetRescuedVoronoiEdge();
|
|
|
|
//also special treatment of the new edges created by former insertion
|
|
arc->getLeftBreakPoint()->getVoronoiEdge()->addEnd(newtriangle);
|
|
arc->getRightBreakPoint()->getVoronoiEdge()->addEnd(newtriangle);
|
|
|
|
arc->resetEvent();
|
|
}
|
|
|
|
}
|
|
void CircleEvent::handleMultiEvent(EventQueue & eq,
|
|
std::multimap<Point_p, CircleEvent*>::iterator from,
|
|
std::multimap<Point_p, CircleEvent*>::iterator to) {
|
|
LOGP
|
|
LOG(this)
|
|
std::multimap<Point_p, CircleEvent*>::iterator it;
|
|
std::multimap<Point_p, CircleEvent*>::iterator toplus;
|
|
VertexContainerSet vc;
|
|
std::deque<Triangle *> neighborMatch;
|
|
Point pt;
|
|
int sidenextvertex, sidevertextriangle;
|
|
BeachLineNode * rmost = 0;
|
|
BeachLineNode * lmost = 0;
|
|
BeachLineNode * currentbp = 0;
|
|
BeachLineNode * bplmostrmost = 0;
|
|
BeachLineNode * nneigh = 0;
|
|
BeachLineNode * sitecircle = 0;
|
|
CircleEvent * cev;
|
|
POINT_COORDINATE bp_left = -std::numeric_limits<double>::max();
|
|
POINT_COORDINATE bp_right = std::numeric_limits<double>::max();
|
|
Triangle* newtriangle, *t1, *t2;
|
|
toplus = to;
|
|
|
|
if (toplus != eq.getCircleQueue()->end())
|
|
toplus++;
|
|
|
|
eq.getBeachLine()->setSweepLine(sweep.y);
|
|
|
|
//remove events including the direct neighbors
|
|
//of the range and remove arcs in range
|
|
|
|
it = from;
|
|
|
|
while (true) {
|
|
//delete all events in range and determine
|
|
//leftmost and rightmost arc and remove arcs
|
|
cev = (*it).second;
|
|
|
|
LOG_EXP(cev->print())
|
|
|
|
if (it == to) {
|
|
lmost = cev->arc->getLeftNeighbor();
|
|
rmost = cev->arc->getRightNeighbor();
|
|
}
|
|
|
|
//remember site for triangulation
|
|
vc.insertVertex_p(cev->arc->getSite());
|
|
|
|
if ((cev->arc->getSite()->getY() == sweep.y)) {
|
|
cev->arc->resetEvent();
|
|
sitecircle = cev->arc;
|
|
} else {
|
|
cev->removeArcMultiEvent(&t1, &t2);
|
|
neighborMatch.push_back(t1);
|
|
neighborMatch.push_back(t2);
|
|
}
|
|
delete cev;
|
|
|
|
if (it == to)
|
|
break;
|
|
++it;
|
|
}
|
|
|
|
eq.getCircleQueue()->erase(from, toplus);
|
|
|
|
if (sitecircle) {
|
|
lmost = sitecircle->getLeftNeighbor();
|
|
rmost = sitecircle->getRightNeighbor();
|
|
}
|
|
|
|
vc.insertVertex_p(lmost->getSite()); //remember site for triangulation
|
|
vc.insertVertex_p(rmost->getSite()); //remember site for triangulation
|
|
//remove neighbor events of the range
|
|
eq.removeEvent(lmost);
|
|
eq.removeEvent(rmost);
|
|
|
|
/////////////triangulation///////////////////////////////////////////////
|
|
//begin with the first 3 vertices
|
|
LOGP
|
|
eq.createTriangle(vc.getVertexByYIndex(0), vc.getVertexByYIndex(1),
|
|
vc.getVertexByYIndex(2), &newtriangle);
|
|
//TODO remove Bug -> references can get lost due to unloading.
|
|
//.. implement the reference counting in this section
|
|
//set the real end to the only outgoing new voronoi
|
|
//edge of the circle - now that it is known
|
|
|
|
if (sitecircle) {
|
|
VoronoiEdge * rescuedEdge = sitecircle->getVoronoiEdge();
|
|
rescuedEdge->addEnd(VORONOI_OPEN_END);
|
|
sitecircle->resetRescuedVoronoiEdge();
|
|
|
|
BeachLineNode * lbpsce = sitecircle->getLeftBreakPoint();
|
|
BeachLineNode * rbpsce = sitecircle->getRightBreakPoint();
|
|
|
|
if (lbpsce && lbpsce->getVoronoiEdge())
|
|
lbpsce->getVoronoiEdge()->setOnlyEnd(VORONOI_OPEN_END);
|
|
if (rbpsce && rbpsce->getVoronoiEdge())
|
|
rbpsce->getVoronoiEdge()->setOnlyEnd(VORONOI_OPEN_END);
|
|
|
|
} else {
|
|
bplmostrmost = lmost->getRightBreakPoint();
|
|
bplmostrmost->getVoronoiEdge()->setOnlyEnd(newtriangle);
|
|
}
|
|
|
|
neighborMatch.push_back(newtriangle);
|
|
|
|
for (int i = 3; i < vc.getNoVertices(); i++) {
|
|
//then find the common edge
|
|
if (newtriangle) {
|
|
Edge common = Edge(newtriangle->getMinYVertex(),
|
|
newtriangle->getMaxYVertex());
|
|
pt.x = newtriangle->getMaxYVertex()->getX();
|
|
pt.y = newtriangle->getMaxYVertex()->getY();
|
|
|
|
Line lcommonedge = Line(common.getVector2D(), pt);
|
|
pt.x = vc.getVertexByYIndex(i)->getX();
|
|
pt.y = vc.getVertexByYIndex(i)->getY();
|
|
sidenextvertex = lcommonedge.getSide(pt);
|
|
|
|
pt.x = newtriangle->getMiddleYVertex()->getX();
|
|
pt.y = newtriangle->getMiddleYVertex()->getY();
|
|
sidevertextriangle = lcommonedge.getSide(pt);
|
|
|
|
if (sidevertextriangle != sidenextvertex) {
|
|
|
|
eq.createTriangle(newtriangle->getMaxYVertex(),
|
|
newtriangle->getMinYVertex(), vc.getVertexByYIndex(i), &newtriangle);
|
|
neighborMatch.push_back(newtriangle);
|
|
|
|
} else {
|
|
eq.createTriangle(newtriangle->getMaxYVertex(),
|
|
newtriangle->getMiddleYVertex(), vc.getVertexByYIndex(i),
|
|
&newtriangle);
|
|
neighborMatch.push_back(newtriangle);
|
|
}
|
|
}
|
|
}
|
|
|
|
//Matching the neighbors, since in case of MultiEvent
|
|
//this is not done by the VoronoiEdges
|
|
LOGP
|
|
std::deque<Triangle *>::iterator itneigh;
|
|
|
|
for (itneigh = neighborMatch.begin(); itneigh != neighborMatch.end();
|
|
++itneigh) {
|
|
if ((*itneigh) && (*itneigh) != VORONOI_OPEN_END)
|
|
(*itneigh)->matchNeighbors(neighborMatch.begin(), neighborMatch.end());
|
|
}
|
|
|
|
LOGP
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
//build the new events
|
|
if (!sitecircle) //regular case
|
|
{
|
|
nneigh = lmost->getLeftNeighbor(¤tbp);
|
|
eq.checkEventAndInsert(rmost, lmost, nneigh, bplmostrmost, currentbp);
|
|
nneigh = rmost->getRightNeighbor(¤tbp);
|
|
eq.checkEventAndInsert(nneigh, rmost, lmost, currentbp, bplmostrmost);
|
|
} else //SC SiteCircleEvent during MultiEvent
|
|
{
|
|
lmost = sitecircle->getLeftNeighbor();
|
|
rmost = sitecircle->getRightNeighbor();
|
|
//eq.checkEventAndInsert(lmost, sitecircle, rmost); cannot happen
|
|
nneigh = rmost->getRightNeighbor(¤tbp);
|
|
eq.checkEventAndInsert(nneigh, rmost, sitecircle, currentbp,
|
|
rmost->getLeftBreakPoint());
|
|
nneigh = lmost->getLeftNeighbor(¤tbp);
|
|
eq.checkEventAndInsert(sitecircle, lmost, nneigh,
|
|
lmost->getRightBreakPoint(), currentbp);
|
|
|
|
}
|
|
}
|
|
bool EventQueue::checkSiteCircleEvent(BeachLineNode* clneigh,
|
|
const Vertex * vmid, BeachLineNode* crneigh, Point_p & sweep) {
|
|
LOGP
|
|
sweep.x = ERROR_VALUE;
|
|
|
|
if (clneigh != 0 && vmid != 0 && crneigh != 0) {
|
|
LOG("Check SiteCircleEvent")
|
|
|
|
if (clneigh->getSite() != vmid && crneigh->getSite() != vmid
|
|
&& clneigh->getSite() != crneigh->getSite()) {
|
|
|
|
sweep = CircleEvent::calculateSweepPoint_quad(clneigh->getSite(), vmid,
|
|
crneigh->getSite(), BeachLineNode::PRECALC_UNSET,
|
|
BeachLineNode::PRECALC_UNSET);
|
|
|
|
if (sweep.x == ERROR_VALUE) //special case 3 sites on a line
|
|
return false;
|
|
|
|
if (std::abs(sweep.y - vmid->getY()) <= 0.0000001) //circle top is vertex
|
|
{
|
|
return true;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
void EventQueue::print(std::ostream& os) {
|
|
|
|
os << "\n";
|
|
os << "VoronoiEdgeInstances currently............\n";
|
|
os << "Events in the Queue.......................\n";
|
|
std::multimap<Point_p, CircleEvent*>::const_iterator itc =
|
|
circleEventQueue.begin();
|
|
|
|
os << "CircleEventQueue\n\n";
|
|
while (itc != circleEventQueue.end()) {
|
|
os << "\n";
|
|
(*itc).second->print(os);
|
|
itc++;
|
|
}
|
|
|
|
os << "Current BeachLineTree.....................\n";
|
|
|
|
bl.print(os);
|
|
|
|
os << "Event handling............................\n";
|
|
}
|
|
void EventQueue::checkEventAndInsert(BeachLineNode* crneigh,
|
|
BeachLineNode * cmid, BeachLineNode* clneigh, BeachLineNode* rbp,
|
|
BeachLineNode* lbp) {
|
|
LOGP
|
|
CircleEvent * cev;
|
|
std::multimap<Point_p, CircleEvent*>::iterator it;
|
|
bool alreadyInQueue = false;
|
|
|
|
if (clneigh != 0 && cmid != 0 && crneigh != 0) {
|
|
|
|
if (clneigh->getSite() != cmid->getSite()
|
|
&& crneigh->getSite() != cmid->getSite()
|
|
&& clneigh->getSite() != crneigh->getSite()) {
|
|
|
|
//try to find out the collapse the easy way
|
|
int percol = cmid->isCollapsing_performance();
|
|
if (percol == 0)
|
|
return;
|
|
|
|
Point_p sweeppoint = CircleEvent::calculateSweepPoint_quad(
|
|
crneigh->getSite(), cmid->getSite(), clneigh->getSite(),
|
|
rbp->getPrecalc(), lbp->getPrecalc());
|
|
|
|
if (sweeppoint.x == ERROR_VALUE) //special case 3 sites on a line
|
|
return;
|
|
|
|
//Special case boundary arc: can be false alarm,
|
|
//since arcs on the boundary are not necessarily destroyed
|
|
//here check whether arc is really zero length, only then it will be added
|
|
|
|
if ((percol == -1) && !cmid->isCollapsing_mp(sweeppoint.y)) {
|
|
return;
|
|
}
|
|
|
|
removeEvent(cmid);
|
|
|
|
cev = new CircleEvent(sweeppoint, cmid);
|
|
it = addCircleEvent(*cev, alreadyInQueue);
|
|
cmid->setEvent(it);
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
void EventQueue::checkEventAndInsert(BeachLineNode* mid, Point_p& sweep) {
|
|
LOGP
|
|
CircleEvent * cev;
|
|
std::multimap<Point_p, CircleEvent*>::iterator it;
|
|
bool alreadyInQueue = false;
|
|
|
|
if (sweep.x == ERROR_VALUE) //no potential CircleEvent
|
|
return;
|
|
|
|
//try to find out the collapse the easy way
|
|
int percol = mid->isCollapsing_performance();
|
|
if (percol == 0)
|
|
return;
|
|
//Special case boundary arc: can be false alarm,
|
|
//since arcs on the boundary are not necessarily destroyed
|
|
//here check whether arc is really zero length,
|
|
//only then it will be added
|
|
|
|
if ((percol == -1) && !mid->isCollapsing_mp(sweep.y))
|
|
return;
|
|
|
|
removeEvent(mid);
|
|
|
|
cev = new CircleEvent(sweep, mid);
|
|
it = addCircleEvent(*cev, alreadyInQueue);
|
|
mid->setEvent(it);
|
|
|
|
}
|
|
void EventQueue::insertSiteCircleEvent(BeachLineNode* arc) {
|
|
LOGP
|
|
CircleEvent * cev;
|
|
Point_p sweeppoint;
|
|
std::multimap<Point_p, CircleEvent*>::iterator it;
|
|
bool alreadyInQueue = false;
|
|
|
|
LOG("Insert SiteCircle Event")
|
|
|
|
sweeppoint.x = arc->getSite()->getX();
|
|
sweeppoint.y = arc->getSite()->getY();
|
|
|
|
cev = new CircleEvent(sweeppoint, arc);
|
|
it = addCircleEvent(*cev, alreadyInQueue);
|
|
arc->setEvent(it);
|
|
|
|
}
|
|
void SiteEvent::handleEvent(
|
|
std::set<Vertex>::reverse_iterator currentVertex, EventQueue & eq) {
|
|
LOGP
|
|
BeachLineNode * newarc = 0;
|
|
BeachLineNode * rneigh = 0;
|
|
BeachLineNode * lneigh = 0;
|
|
BeachLineNode * mid = 0;
|
|
BeachLineNode * lbp = 0;
|
|
BeachLineNode * rbp = 0;
|
|
Point_p sweeppoint;
|
|
Point_p sweeprneigh;
|
|
Point_p sweeplneigh;
|
|
|
|
LOG("Handling SiteEvent")
|
|
LOG_EXP((*currentVertex).print())
|
|
LOG("siteevent")
|
|
|
|
eq.getBeachLine()->setSweepLine((*currentVertex).getY());
|
|
BeachLineNode* pParabolaAbove = eq.getBeachLine()->find(
|
|
(*currentVertex).getX());
|
|
|
|
if (pParabolaAbove->isRoot()) {
|
|
eq.getBeachLine()->insert(&(*currentVertex), pParabolaAbove);
|
|
//for root just insert
|
|
return;
|
|
}
|
|
|
|
//delete CircleEvents interfered by new circle
|
|
eq.removeEvent(pParabolaAbove);
|
|
|
|
rneigh = pParabolaAbove->getRightNeighbor();
|
|
lneigh = pParabolaAbove->getLeftNeighbor();
|
|
|
|
//special case SiteEvent at the bottom of a circle
|
|
//-> SiteEvent and corresponding CircleEvent coincide
|
|
if (eq.checkSiteCircleEvent(pParabolaAbove, &(*currentVertex), rneigh,
|
|
sweeprneigh)) {
|
|
// lneigh pParabolaAbove rneigh
|
|
//-> lneigh pParabolaAbove newarc rneigh
|
|
|
|
//SiteCircleEvents do not split the arc below
|
|
newarc = pParabolaAbove->insert_no_split(&(*currentVertex),
|
|
eq.getBeachLine()->getSweepLineY());
|
|
//SiteCircleEvents are inserted without checks
|
|
//since these are done by checkSiteCircleEvent
|
|
eq.insertSiteCircleEvent(newarc);
|
|
|
|
rneigh = newarc->getRightNeighbor();
|
|
lneigh = newarc->getLeftNeighbor();
|
|
|
|
eq.removeEvent(rneigh);
|
|
eq.removeEvent(lneigh);
|
|
// makes sure Event wont be reinserted below
|
|
sweeprneigh.x = ERROR_VALUE;
|
|
|
|
} else if (eq.checkSiteCircleEvent(pParabolaAbove, &(*currentVertex),
|
|
lneigh, sweeplneigh)) {
|
|
// lneigh pParabolaAbove rneigh
|
|
//-> lneigh newarc pParabolaAbove rneigh
|
|
|
|
newarc = pParabolaAbove->insert_no_split(&(*currentVertex),
|
|
eq.getBeachLine()->getSweepLineY());
|
|
|
|
eq.insertSiteCircleEvent(newarc);
|
|
|
|
rneigh = newarc->getRightNeighbor();
|
|
lneigh = newarc->getLeftNeighbor();
|
|
|
|
eq.removeEvent(rneigh);
|
|
eq.removeEvent(lneigh);
|
|
// makes sure Event wont be reinserted below
|
|
sweeplneigh.x = ERROR_VALUE;
|
|
|
|
} else //regular case
|
|
{
|
|
// lneigh pParabolaAbove rneigh
|
|
//-> lneigh pParabolaAbove' newarc pParabolaAbove'' rneigh
|
|
|
|
newarc = eq.getBeachLine()->insert(&(*currentVertex), pParabolaAbove);
|
|
|
|
if (newarc) {
|
|
if (sweeprneigh.x != ERROR_VALUE) {
|
|
mid = newarc->getRightNeighbor();
|
|
eq.checkEventAndInsert(mid, sweeprneigh);
|
|
}
|
|
if (sweeplneigh.x != ERROR_VALUE) {
|
|
mid = newarc->getLeftNeighbor();
|
|
eq.checkEventAndInsert(mid, sweeplneigh);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//now check for new CircleEvents to the left and to the right
|
|
if (newarc) {
|
|
mid = newarc->getLeftNeighbor(&rbp);
|
|
if (mid != 0)
|
|
lneigh = mid->getLeftNeighbor(&lbp);
|
|
rneigh = newarc;
|
|
|
|
eq.checkEventAndInsert(rneigh, mid, lneigh, rbp, lbp);
|
|
|
|
mid = newarc->getRightNeighbor(&lbp);
|
|
if (mid != 0)
|
|
rneigh = mid->getRightNeighbor(&rbp);
|
|
lneigh = newarc;
|
|
|
|
eq.checkEventAndInsert(rneigh, mid, lneigh, rbp, lbp);
|
|
}
|
|
}
|
|
|
|
}
|
|
|