Files
secondo/Algebras/TIN/Edge.cpp

711 lines
15 KiB
C++
Raw Normal View History

2026-01-23 17:03:45 +08:00
/*
----
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 "Edge.h"
#include "TinHelper.h"
#include "Vector2D.h"
#include "Vertex.h"
#include "Triangle.h"
#define CLEAN_UP_INTERSECTS mpq_clear(tmp);\
mpq_clear(tmp2);\
mpq_clear(tmp3);\
mpq_clear(f1);\
mpq_clear(vec1dx);\
mpq_clear(vec1dy);\
mpq_clear(p1x);\
mpq_clear(p1y);\
mpq_clear(f2);\
mpq_clear(vec2dx);\
mpq_clear(vec2dy);\
mpq_clear(p2x);\
mpq_clear(p2y);
namespace tin {
Vertex Edge::intersection_point = Vertex(0, 0, 0);
Vertex Edge::intersection_point_2 = Vertex(0, 0, 0);
const Edge Edge::nulledge = Edge();
Edge::Edge(const Vertex* iv1, const Vertex* iv2) {
if (iv1 == 0 || iv2 == 0)
throw std::invalid_argument(E_EDGE_EDGE0);
v1 = iv1;
v2 = iv2;
}
Edge::~Edge() {
}
NeighborEdge::NeighborEdge(const Vertex *iv1, const Vertex * iv2,
Triangle * t1, Triangle * t2) :
Edge(iv1, iv2) {
n1 = t1;
n2 = t2;
}
void NeighborEdge::setN1(Triangle * t) {
n1 = t;
}
void NeighborEdge::setN2(Triangle * t) {
n2 = t;
}
Triangle* NeighborEdge::getN1() {
return n1;
}
Triangle* NeighborEdge::getN2() {
return n2;
}
NeighborEdge NeighborEdge::getNextEdge() {
if (n2 != VORONOI_OPEN_END && n2) {
return n2->getNextEdge(*this);
} else
return NeighborEdge();
}
NeighborEdge NeighborEdge::getPriorEdge() {
if (n1 != VORONOI_OPEN_END && n1) {
return n1->getNextEdge(*this);
} else
return NeighborEdge();
}
NeighborEdge NeighborEdge::getNextEdge_noload() {
if (n2 != VORONOI_OPEN_END && n2) {
return n2->getNextEdge_noload(*this);
} else
return NeighborEdge();
}
NeighborEdge NeighborEdge::getPriorEdge_noload() {
if (n1 != VORONOI_OPEN_END && n1) {
return n1->getNextEdge_noload(*this);
} else
return NeighborEdge();
}
bool NeighborEdge::operator==(const NeighborEdge& ne) {
return Edge::operator ==(ne);
}
bool NeighborEdge::operator==(const Edge& ne) {
return ((*v1 == *(ne.getV1()) && *v2 == *(ne.getV2()))
|| (*v1 == *(ne.getV2()) && *v2 == *(ne.getV2())));
}
bool Edge::contains(const Point & p) const {
if (isPoint())
return p.x == v1->getX() && p.y == v1->getY();
Vector2D vec1 = v1->minus2D(*v2);
bool inxrange = ((p.x <= v1->getX() && p.x >= v2->getX())
|| (p.x >= v1->getX() && p.x <= v2->getX()));
if (!vec1.isVertical()) {
PreciseDouble y = v2->getY();
PreciseDouble ycalc = y
+ (p.x - (PreciseDouble) v2->getX()) * vec1.dydx();
return inxrange && (p.y == ycalc);
} else {
return inxrange
&& ((p.y <= v1->getY() && p.y >= v2->getY())
|| (p.y >= v1->getY() && p.y <= v2->getY()));
}
}
bool Edge::hasVertex(const Vertex* v) const {
return ((*v) == (*v1) || (*v) == (*v2));
}
Vector2D Edge::getVector2D() const {
PreciseDouble dx = (PreciseDouble) v2->getX()
- (PreciseDouble) v1->getX();
PreciseDouble dy = (PreciseDouble) v2->getY()
- (PreciseDouble) v1->getY();
return Vector2D(dx, dy);
}
Vector2D_mp Edge::getVector2D_mp() const {
mpq_t dx, dy, tmp1, tmp2;
mpq_init(dx);
mpq_init(tmp1);
mpq_init(tmp2);
mpq_init(dy);
mpq_set_d(tmp1, v1->getX());
mpq_set_d(tmp2, v2->getX());
mpq_sub(dx, tmp2, tmp1);
mpq_set_d(tmp1, v1->getY());
mpq_set_d(tmp2, v2->getY());
mpq_sub(dy, tmp2, tmp1);
mpq_clear(tmp1);
mpq_clear(tmp2);
Vector2D_mp ret(dx, dy);
mpq_clear(dy);
mpq_clear(dx);
return ret;
}
bool Edge::operator==(const Edge & e) const {
if ((*e.v1 == *v1 && *e.v2 == *v2) || (*e.v1 == *v2 && *e.v2 == *v1)) {
return true;
} else
return false;
}
bool Edge::intersection_sec(const Edge& e, Edge& result) const {
Point p;
Point_p p1(e.v1->getX(), e.v1->getY());
Point_p p2(e.v2->getX(), e.v2->getY());
PreciseDouble f1, f2;
result.v1 = &Vertex::nullvertex;
result.v2 = &Vertex::nullvertex;
SecureOperator::startSecureCalc();
Vector2D vec1 = v1->minus2D(*v2);
Vector2D vec2 = e.v1->minus2D(*e.v2);
//TODO bbox check
if (vec1.hasEqualDir(vec2)) //edges with the same direction
{
if (!SecureOperator::isSecureResult())
return intersection_mp(e, result); //direction not secure ->recalculate mp
//from here on check whether vertices
//are contained in the other edge
if (e.contains(v1)) {
result.v1 = v1; //and keep result vertices
}
if (e.contains(v2)) {
result.v2 = v2;
}
if (contains(e.v1)) {
intersection_point.setX(e.v1->getX());
intersection_point.setY(e.v1->getY());
intersection_point.setZ(this->getZat(p1));
if (result.v1 == &Vertex::nullvertex) {
result.v1 = &intersection_point;
} else {
result.v2 = &intersection_point;
}
}
if (contains(e.v2)) {
intersection_point_2.setX(e.v2->getX());
intersection_point_2.setY(e.v2->getY());
intersection_point_2.setZ(this->getZat(p2));
if (result.v1 == &Vertex::nullvertex) {
result.v1 = &intersection_point_2;
} else {
result.v2 = &intersection_point_2;
}
}
if (!SecureOperator::isSecureResult())
return intersection_mp(e, result);
if (!(result.v1 == &Vertex::nullvertex)) {
if (result.v2 == &Vertex::nullvertex) {
result.v2 = result.v1;
}
return true;
}
if (!(result.v2 == &Vertex::nullvertex)) {
if (result.v1 == &Vertex::nullvertex) {
result.v1 = result.v2;
}
return true;
}
return false;
}
if (!SecureOperator::isSecureResult())
return intersection_mp(e, result); //direction not secure ->recalculate mp
//now edges cannot have the same direction -> calculate the cutting point
f1 = ((vec2.getDx() * e.v2->getY()) + (vec2.getDy() * v2->getX())
- (vec2.getDy() * e.v2->getX()) - (vec2.getDx() * v2->getY()))
/ ((vec1.getDy() * vec2.getDx()) - (vec2.getDy() * vec1.getDx()));
//avoid zero division
//-> dy and dx cannot both be zero due to precondition
if (vec2.getDx() == 0)
f2 = ((vec1.getDy() * f1) + v2->getY() - e.v2->getY()) / vec2.getDy();
else
f2 = ((vec1.getDx() * f1) + v2->getX() - e.v2->getX()) / vec2.getDx();
if (f1 <= 1 && f1 >= 0) //cutting point within length of this edge
{
if (!SecureOperator::isSecureResult())
return intersection_mp(e, result); //not secure->recalculate mp
if (f2 <= 1 && f2 >= 0) //and cutting point within length of *e*
{
if (!SecureOperator::isSecureResult())
return intersection_mp(e, result); //not secure->recalculate mp
p = *v2 + vec1 * f1;
intersection_point.setX(p.x.getRoundedVal());
intersection_point.setY(p.y.getRoundedVal());
intersection_point.setZ(v2->getZ() + f1.l * (v1->getZ() - v2->getZ()));
//build zero length edge at intersection point for result
result.v1 = &intersection_point;
result.v2 = result.v1;
return true;
}
} else {
return false;
}
return false;
}
bool Edge::intersection_mp(const Edge& e, Edge& result) const {
mpq_t f1, f2, vec1dx, vec1dy, vec2dx, vec2dy, p1x, p1y, p2x, p2y, tmp,
tmp2, tmp3;
Point_p p1(e.v1->getX(), e.v1->getY());
Point_p p2(e.v2->getX(), e.v2->getY());
Vector2D_mp vec1 = v1->minus2D_mp(*v2);
Vector2D_mp vec2 = e.v1->minus2D_mp(*e.v2);
//TODO bbox check
SecureOperator::startSecureCalc();
result.v1 = &Vertex::nullvertex;
result.v2 = &Vertex::nullvertex;
//TODO mp calculation here !
if (vec1.hasEqualDir(vec2)) {
if (e.contains(v1)) {
result.v1 = v1;
}
if (e.contains(v2)) {
result.v2 = v2;
}
if (contains(e.v1)) {
intersection_point.setX(e.v1->getX());
intersection_point.setY(e.v1->getY());
intersection_point.setZ(this->getZat(p1));
if (result.v1 == &Vertex::nullvertex) {
result.v1 = &intersection_point;
} else {
result.v2 = &intersection_point;
}
}
if (contains(e.v2)) {
intersection_point_2.setX(e.v2->getX());
intersection_point_2.setY(e.v2->getY());
intersection_point_2.setZ(this->getZat(p2));
if (result.v1 == &Vertex::nullvertex) {
result.v1 = &intersection_point_2;
} else {
result.v2 = &intersection_point_2;
}
}
if (!(result.v1 == &Vertex::nullvertex)) {
if (result.v2 == &Vertex::nullvertex) {
result.v2 = result.v1;
}
return true;
}
if (!(result.v2 == &Vertex::nullvertex)) {
if (result.v1 == &Vertex::nullvertex) {
result.v1 = result.v2;
}
return true;
}
return false;
}
mpq_init(f1);
mpq_init(vec1dx);
mpq_init(vec1dy);
mpq_init(p1x);
mpq_init(p1y);
mpq_init(f2);
mpq_init(vec2dx);
mpq_init(vec2dy);
mpq_init(p2x);
mpq_init(p2y);
mpq_init(tmp);
mpq_init(tmp2);
mpq_init(tmp3);
mpq_set(vec1dx, vec1.dx.get_mpq_t());
mpq_set(vec1dy, vec1.dy.get_mpq_t());
mpq_set_d(p1x, v2->getX());
mpq_set_d(p1y, v2->getY());
mpq_set(vec2dx, vec2.dx.get_mpq_t());
mpq_set(vec2dy, vec2.dy.get_mpq_t());
mpq_set_d(p2x, e.v2->getX());
mpq_set_d(p2y, e.v2->getY());
mpq_mul(tmp, vec2dx, p2y);
mpq_mul(tmp2, vec2dy, p1x);
mpq_add(tmp, tmp, tmp2);
mpq_mul(tmp2, vec2dy, p2x);
mpq_sub(tmp, tmp, tmp2);
mpq_mul(tmp2, vec2dx, p1y);
mpq_sub(tmp, tmp, tmp2);
mpq_mul(tmp2, vec1dy, vec2dx);
mpq_mul(tmp3, vec2dy, vec1dx);
mpq_sub(tmp2, tmp2, tmp3);
if (mpq_cmp(tmp2, f1) == 0) {
CLEAN_UP_INTERSECTS
throw std::runtime_error("intersects_mp: tmp2 should not be null ");
}
mpq_div(f1, tmp, tmp2);
if (mpq_cmp(vec2dy, f2) == 0) {
mpq_mul(tmp, vec1dx, f1);
mpq_add(tmp, tmp, p1x);
mpq_sub(tmp, tmp, p2x);
mpq_div(f2, tmp, vec2dx);
} else {
mpq_mul(tmp, vec1dy, f1);
mpq_add(tmp, tmp, p1y);
mpq_sub(tmp, tmp, p2y);
mpq_div(f2, tmp, vec2dy);
}
mpq_set_d(tmp, 0.0);
mpq_set_d(tmp2, 1.0);
if (mpq_cmp(f1, tmp) >= 0 && mpq_cmp(f1, tmp2) <= 0
&& mpq_cmp(f2, tmp) >= 0 && mpq_cmp(f2, tmp2) <= 0) {
mpq_mul(tmp, f1, vec1dx);
mpq_add(tmp, tmp, p1x);
mpq_mul(tmp2, f1, vec1dy);
mpq_add(tmp2, tmp2, p1y);
intersection_point.setX(mpq_get_d(tmp));
intersection_point.setY(mpq_get_d(tmp2));
intersection_point.setZ(
v2->getZ() + mpq_get_d(f1) * (v1->getZ() - v2->getZ()));
result.v1 = &intersection_point;
result.v2 = result.v1;
CLEAN_UP_INTERSECTS
return true;
} else {
CLEAN_UP_INTERSECTS
return false;
}
CLEAN_UP_INTERSECTS
return false;
}
bool Edge::equal3D(const Edge & e) const {
if ((e.v1->equal3D(*v1) && e.v2->equal3D(*v2))
|| (e.v2->equal3D(*v1) && e.v1->equal3D(*v2))) {
return true;
}
return false;
}
Point_p Edge::getMiddle() const {
Vector2D vec = getVector2D();
Point result = *v1 + vec * (PreciseDouble) 0.5;
return (Point_p) result;
}
int Edge::getSide_sec(const Point_p& p) {
SecureOperator::startSecureCalc();
if (*v1 == p || *v2 == p)
return 0;
Line l(*v1, *v2);
int side = l.getSide(Point(p));
if (!SecureOperator::isSecureResult()) {
Line_mp lmp(*v1, *v2);
side = lmp.getSide_mp(Point_mp(p));
}
return side;
}
bool Edge::intersects_sec(const Edge* e) const {
SecureOperator::startSecureCalc();
PreciseDouble f2, f1;
Vector2D vec1 = v1->minus2D(*v2);
Vector2D vec2 = e->v1->minus2D(*e->v2);
if (e->isPoint()) {
if (this->contains(e->v1)) {
if (!SecureOperator::isSecureResult())
return intersects_mp(e);
return true;
} else
return false;
}
if (isPoint()) {
if (e->contains(v1)) {
if (!SecureOperator::isSecureResult())
return intersects_mp(e);
return true;
} else
return false;
}
if (vec1.hasEqualDir(vec2)) {
if (e->contains(v1) || e->contains(v2) || contains(e->v1)) {
if (!SecureOperator::isSecureResult())
return intersects_mp(e);
return true;
} else {
if (!SecureOperator::isSecureResult())
return intersects_mp(e);
return false;
}
}
if (!SecureOperator::isSecureResult())
return intersects_mp(e);
f1 = ((vec2.getDx() * e->v2->getY()) + (vec2.getDy() * v2->getX())
- (vec2.getDy() * e->v2->getX()) - (vec2.getDx() * v2->getY()))
/ ((vec1.getDy() * vec2.getDx()) - (vec2.getDy() * vec1.getDx()));
if (vec2.getDx() == 0)
f2 = ((vec1.getDy() * f1) + v2->getY() - e->v2->getY()) / vec2.getDy();
else
f2 = ((vec1.getDx() * f1) + v2->getX() - e->v2->getX()) / vec2.getDx();
if (f1 <= 1 && f1 >= 0) {
if (!SecureOperator::isSecureResult())
return intersects_mp(e);
if (f2 <= 1 && f2 >= 0) {
if (!SecureOperator::isSecureResult())
return intersects_mp(e);
return true;
}
} else {
return false;
}
return false;
}
bool Edge::intersects_mp(const Edge* e) const {
mpq_t f1, f2, vec1dx, vec1dy, vec2dx, vec2dy, p1x, p1y, p2x, p2y, tmp,
tmp2, tmp3;
Vector2D_mp vec1 = v1->minus2D_mp(*v2);
Vector2D_mp vec2 = e->v1->minus2D_mp(*e->v2);
//TODO bbox check
//TODO make mp calc for contains
if (e->isPoint()) {
if (this->contains(e->v1)) {
return true;
} else
return false;
}
if (isPoint()) {
if (e->contains(v1)) {
return true;
} else
return false;
}
if (vec1.hasEqualDir(vec2)) {
if (e->contains(v1) || e->contains(v2) || contains(e->v1)) {
return true;
} else {
return false;
}
}
mpq_init(f1);
mpq_init(vec1dx);
mpq_init(vec1dy);
mpq_init(p1x);
mpq_init(p1y);
mpq_init(f2);
mpq_init(vec2dx);
mpq_init(vec2dy);
mpq_init(p2x);
mpq_init(p2y);
mpq_init(tmp);
mpq_init(tmp2);
mpq_init(tmp3);
mpq_set(vec1dx, vec1.dx.get_mpq_t());
mpq_set(vec1dy, vec1.dy.get_mpq_t());
mpq_set_d(p1x, v2->getX());
mpq_set_d(p1y, v2->getY());
mpq_set(vec2dx, vec2.dx.get_mpq_t());
mpq_set(vec2dy, vec2.dy.get_mpq_t());
mpq_set_d(p2x, e->v2->getX());
mpq_set_d(p2y, e->v2->getY());
mpq_mul(tmp, vec2dx, p2y);
mpq_mul(tmp2, vec2dy, p1x);
mpq_add(tmp, tmp, tmp2);
mpq_mul(tmp2, vec2dy, p2x);
mpq_sub(tmp, tmp, tmp2);
mpq_mul(tmp2, vec2dx, p1y);
mpq_sub(tmp, tmp, tmp2);
mpq_mul(tmp2, vec1dy, vec2dx);
mpq_mul(tmp3, vec2dy, vec1dx);
mpq_sub(tmp2, tmp2, tmp3);
if (mpq_cmp(tmp2, f1) == 0) {
CLEAN_UP_INTERSECTS
throw std::runtime_error("intersects_mp: tmp2 should not be null ");
}
mpq_div(f1, tmp, tmp2);
if (mpq_cmp(vec2dy, f2) == 0) {
mpq_mul(tmp, vec1dx, f1);
mpq_add(tmp, tmp, p1x);
mpq_sub(tmp, tmp, p2x);
mpq_div(f2, tmp, vec2dx);
} else {
mpq_mul(tmp, vec1dy, f1);
mpq_add(tmp, tmp, p1y);
mpq_sub(tmp, tmp, p2y);
mpq_div(f2, tmp, vec2dy);
}
mpq_set_d(tmp, 0.0);
mpq_set_d(tmp2, 1.0);
if (mpq_cmp(f1, tmp) >= 0 && mpq_cmp(f1, tmp2) <= 0
&& mpq_cmp(f2, tmp) >= 0 && mpq_cmp(f2, tmp2) <= 0) {
CLEAN_UP_INTERSECTS
return true;
} else {
CLEAN_UP_INTERSECTS
return false;
}
CLEAN_UP_INTERSECTS
return false;
}
/* namespace tin*/
bool Edge::isPoint() const {
return (*v1 == *v2);
}
bool Edge::operator <(const Edge& e) const {
const Vertex* min, *max, *min2, *max2;
if ((*v1) < (*v2)) {
min = v1;
max = v2;
} else {
min = v2;
max = v1;
}
if ((*e.v1) < (*e.v2)) {
min2 = e.v1;
max2 = e.v2;
} else {
min2 = e.v2;
max2 = e.v1;
}
if ((*min) < (*min2)) {
return true;
}
if (*min2 < *min) {
return false;
}
if (*max < *max2) {
return true;
}
if (*max2 < *max) {
return false;
}
return false;
}
VERTEX_Z Edge::getZat(const Point_p& p) const {
Vector3D vec1 = v1->minus3D(*v2);
if (!(vec1.getDx() == 0)) {
return ((p.x - v2->getX()) / vec1.getDx().l) * vec1.getDz().l
+ v2->getZ();
}
if (!(vec1.getDy() == 0)) {
return ((p.y - v2->getY()) / vec1.getDy().l) * vec1.getDz().l
+ v2->getZ();
}
return v2->getZ();
}
}