Files
secondo/Algebras/RobustPlaneSweep/Helper/InternalGeometries.h
2026-01-23 17:03:45 +08:00

1635 lines
35 KiB
C++

/*
----
This file is part of SECONDO.
Copyright (C) 2004, University in Hagen, Department of Computer Science,
Database Systems for New Applications.
SECONDO is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
SECONDO is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with SECONDO; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
----
//paragraph [1] Title: [{\Large \bf \begin {center}] [\end {center}}]
//[TOC] [\tableofcontents]
//[_] [\_]
[1] Header File for the internal geometry classes
[TOC]
1 Overview
This header file contains all internal geometry structs and classes.
1 Includes
*/
#pragma once
#include <vector>
#include <unordered_set>
#include <map>
#include <algorithm>
#include "Utility.h"
#include "AvlTree.h"
#ifdef RPS_TEST
#include "SpatialAlgebraStubs.h"
#else
#include "Algebras/Spatial/SpatialAlgebra.h"
#endif
#include "Rational.h"
namespace RobustPlaneSweep
{
/*
1 Forward declaration ~SweepStateData~
*/
class SweepStateData;
/*
1 Enum class ~BoundaryType~
*/
enum class BoundaryType
{
Undefined = 0,
Boundary = 1,
InteriorAbove = 2, /* implies Boundary */
InteriorBelow = 3, /* implies Boundary */
InsideInterior = 4, /* implies not Boundary */
OutsideInterior = 5, /* implies not Boundary */
};
/*
1 Class ~InternalAttribute~
This class represents an attribute of a part of an ~InternalLineSegment~.
It contains for each geometry a ~BoundaryType~.
*/
class InternalAttribute
{
/*
1.1 Member variables
*/
private:
bool _defined;
BoundaryType _first;
BoundaryType _second;
public:
/*
1.1 Constructors
*/
InternalAttribute() :
_defined(false),
_first(BoundaryType::Undefined),
_second(BoundaryType::Undefined)
{
}
InternalAttribute(BoundaryType first,
BoundaryType second) :
_defined(true),
_first(first),
_second(second)
{
if (first == BoundaryType::Undefined) {
throw new std::invalid_argument("first");
}
if (second == BoundaryType::Undefined) {
throw new std::invalid_argument("second");
}
}
/*
1.1 ~IsDefined~
*/
bool IsDefined() const
{
return _defined;
}
/*
1.1 ~GetFirst~
*/
BoundaryType GetFirst() const
{
return _first;
}
/*
1.1 ~IsBoundaryInFirst~
*/
bool IsBoundaryInFirst() const
{
return _first == BoundaryType::Boundary
|| _first == BoundaryType::InteriorAbove
|| _first == BoundaryType::InteriorBelow;
}
/*
1.1 ~IsFirstAbove~
*/
bool IsFirstAbove() const
{
return _first == BoundaryType::InteriorAbove
|| _first == BoundaryType::InsideInterior;
}
/*
1.1 ~IsFirstBelow~
*/
bool IsFirstBelow() const
{
return _first == BoundaryType::InteriorBelow
|| _first == BoundaryType::InsideInterior;
}
/*
1.1 ~GetSecond~
*/
BoundaryType GetSecond() const
{
return _second;
}
/*
1.1 ~IsBoundaryInSecond~
*/
bool IsBoundaryInSecond() const
{
return _second == BoundaryType::Boundary
|| _second == BoundaryType::InteriorAbove
|| _second == BoundaryType::InteriorBelow;
}
/*
1.1 ~IsSecondAbove~
*/
bool IsSecondAbove() const
{
return _second == BoundaryType::InteriorAbove
|| _second == BoundaryType::InsideInterior;
}
/*
1.1 ~IsSecondBelow~
*/
bool IsSecondBelow() const
{
return _second == BoundaryType::InteriorBelow
|| _second == BoundaryType::InsideInterior;
}
/*
1.1 ~IsBoundaryInBoth~
*/
bool IsBoundaryInBoth() const
{
return IsBoundaryInFirst() && IsBoundaryInSecond();
}
/*
1.1 ~IsInUnionRegion~
*/
bool IsInUnionRegion(bool& insideAbove) const
{
if(_first == BoundaryType::InteriorAbove
&& (_second == BoundaryType::InteriorAbove
|| _second == BoundaryType::OutsideInterior)) {
insideAbove = true;
return true;
} else if(_first == BoundaryType::InteriorBelow
&& (_second == BoundaryType::InteriorBelow
|| _second == BoundaryType::OutsideInterior)) {
insideAbove = false;
return true;
} else if(_first == BoundaryType::OutsideInterior
&& (_second == BoundaryType::InteriorAbove
|| _second == BoundaryType::InteriorBelow)) {
insideAbove = (_second == BoundaryType::InteriorAbove);
return true;
} else {
insideAbove = false;
return false;
}
}
/*
1.1 ~IsInIntersectionRegion~
*/
bool IsInIntersectionRegion(bool& insideAbove) const
{
if (IsBoundaryInFirst() || IsBoundaryInSecond()) {
if (IsFirstAbove() && IsSecondAbove()) {
insideAbove = true;
return true;
}
if (IsFirstBelow() && IsSecondBelow()) {
insideAbove = false;
return true;
}
}
insideAbove = false;
return false;
}
/*
1.1 ~IsInMinusRegion~
*/
bool IsInMinusRegion(bool& insideAbove) const
{
if(_first == BoundaryType::InteriorAbove
&& (_second == BoundaryType::InteriorBelow
|| _second == BoundaryType::OutsideInterior)) {
insideAbove = true;
return true;
} else if(_first == BoundaryType::InteriorBelow
&& (_second == BoundaryType::InteriorAbove
|| _second == BoundaryType::OutsideInterior)) {
insideAbove = false;
return true;
} else if(_first == BoundaryType::InsideInterior
&& (_second == BoundaryType::InteriorAbove
|| _second == BoundaryType::InteriorBelow)) {
insideAbove = (_second == BoundaryType::InteriorBelow);
return true;
} else {
insideAbove = false;
return false;
}
}
/*
1.1 ~Create~
*/
static InternalAttribute Create(bool belongsToSecondGeometry,
bool insideAbove,
bool isRegion)
{
if (isRegion) {
if (!belongsToSecondGeometry) {
return InternalAttribute((insideAbove ? BoundaryType::InteriorAbove :
BoundaryType::InteriorBelow),
BoundaryType::OutsideInterior);
} else {
return InternalAttribute(BoundaryType::OutsideInterior,
(insideAbove ? BoundaryType::InteriorAbove :
BoundaryType::InteriorBelow));
}
} else {
return InternalAttribute((!belongsToSecondGeometry ?
BoundaryType::Boundary :
BoundaryType::OutsideInterior),
(belongsToSecondGeometry ?
BoundaryType::Boundary :
BoundaryType::OutsideInterior));
}
}
/*
1.1 ~Merge~
If two segments collaps, then their attributes must be merged.
This method assumes that the ~boundary1~ belongs to the segment above the
second segment.
*/
static BoundaryType Merge(BoundaryType boundary1, BoundaryType boundary2)
{
if (boundary1 == BoundaryType::Boundary) {
switch (boundary2) {
case BoundaryType::Boundary:
case BoundaryType::OutsideInterior:
return BoundaryType::Boundary;
case BoundaryType::InteriorAbove:
case BoundaryType::InteriorBelow:
case BoundaryType::InsideInterior:
throw new std::logic_error("invalid boundary merge");
default:
throw new std::invalid_argument("boundary2");
}
} else if (boundary1 == BoundaryType::InteriorAbove) {
switch (boundary2) {
case BoundaryType::Boundary:
case BoundaryType::InteriorAbove:
throw new std::logic_error("invalid boundary merge");
case BoundaryType::InteriorBelow:
return BoundaryType::InsideInterior;
case BoundaryType::InsideInterior:
case BoundaryType::OutsideInterior:
return BoundaryType::InteriorAbove;
default:
throw new std::invalid_argument("boundary2");
}
} else if (boundary1 == BoundaryType::InteriorBelow) {
switch (boundary2) {
case BoundaryType::Boundary:
throw new std::logic_error("invalid boundary merge");
case BoundaryType::InteriorAbove:
return BoundaryType::OutsideInterior;
case BoundaryType::InteriorBelow:
throw new std::logic_error("");
case BoundaryType::InsideInterior:
case BoundaryType::OutsideInterior:
return BoundaryType::InteriorBelow;
default:
throw new std::invalid_argument("boundary2");
}
} else if (boundary1 == BoundaryType::InsideInterior) {
if (boundary2 == BoundaryType::OutsideInterior
|| boundary2 == BoundaryType::Boundary) {
throw new std::logic_error("invalid boundary merge");
}
return boundary2;
} else if (boundary1 == BoundaryType::OutsideInterior) {
if (boundary2 == BoundaryType::InsideInterior) {
throw new std::logic_error("invalid boundary merge");
}
return boundary2;
} else {
throw new std::invalid_argument("boundary1");
}
}
/*
1.1 ~FlipInteriorAbove~
*/
InternalAttribute FlipInteriorAbove() const
{
BoundaryType newFirst;
if (_first == BoundaryType::InteriorAbove) {
newFirst = BoundaryType::InteriorBelow;
} else if (_first == BoundaryType::InteriorBelow) {
newFirst = BoundaryType::InteriorAbove;
} else {
newFirst = _first;
}
BoundaryType newSecond;
if (_second == BoundaryType::InteriorAbove) {
newSecond = BoundaryType::InteriorBelow;
} else if (_second == BoundaryType::InteriorBelow) {
newSecond = BoundaryType::InteriorAbove;
} else {
newSecond = _second;
}
return InternalAttribute(newFirst, newSecond);
}
};
/*
1 Class ~InternalPoint~
This class represents an end point of an ~InternalLineSegment~.
*/
class InternalPoint
{
/*
1.1 Member variables
*/
private:
int _x;
int _y;
public:
/*
1.1 Constructor
*/
inline InternalPoint(const int x, const int y) :
_x(x), _y(y)
{
}
/*
1.1 ~IsEqual~
*/
inline static bool IsEqual(const InternalPoint& p0,
const InternalPoint& p1)
{
return (p0.GetX() == p1.GetX() && p0.GetY() == p1.GetY());
}
/*
1.1 ~Compare~
*/
inline static int Compare(const InternalPoint& p0,
const InternalPoint& p1)
{
if (p0._x < p1._x) {
return -1;
} else if (p0._x > p1._x) {
return 1;
} else {
// p0._x == p1._x
if (p0._y < p1._y) {
return -1;
} else if (p0._y > p1._y) {
return 1;
} else {
return 0;
}
}
}
/*
1.1 ~GetX~
*/
inline int GetX() const
{
return _x;
}
/*
1.1 ~GetY~
*/
inline int GetY() const
{
return _y;
}
};
/*
1 Struct ~InternalPointComparer~
*/
struct InternalPointComparer
{
/*
1.1 ~operator()~
*/
size_t operator()(const InternalPoint &x) const
{
return ((size_t)(x.GetX())) ^ ((size_t)(x.GetY()));
}
/*
1.1 ~operator()~
*/
bool operator()(const InternalPoint &x, const InternalPoint &y) const
{
return InternalPoint::IsEqual(x, y);
}
};
/*
1 Class ~InternalIntersectionPoint~
This class represents an intersection point. It is similar to the class
~InternalPoint~, except that it uses ~Rational~ instead of ~int~ for the
coordinates.
*/
class InternalIntersectionPoint
{
/*
1.1 Member variables
*/
private:
Rational _x;
Rational _y;
public:
/*
1.1 Constructors
*/
InternalIntersectionPoint() :
_x(0), _y(0)
{
}
inline InternalIntersectionPoint(const Rational& x, const Rational& y) :
_x(x), _y(y)
{
}
inline InternalIntersectionPoint(const int x, const int y) :
_x(Rational(x)), _y(Rational(y))
{
}
explicit inline InternalIntersectionPoint(const InternalPoint &p) :
_x(p.GetX()), _y(p.GetY())
{
}
/*
1.1 ~IsEqual~
*/
inline static bool IsEqual(const InternalIntersectionPoint &p0,
const InternalIntersectionPoint &p1)
{
return p0.GetX() == p1.GetX() && p0.GetY() == p1.GetY();
}
inline static bool IsEqual(const InternalIntersectionPoint &p0,
const InternalPoint &p1)
{
return p0.GetX() == p1.GetX() && p0.GetY() == p1.GetY();
}
/*
1.1 ~GetX~
*/
inline const Rational& GetX() const
{
return _x;
}
/*
1.1 ~GetY~
*/
inline const Rational& GetY() const
{
return _y;
}
};
/*
1 Struct ~InternalIntersectionPointComparer~
*/
struct InternalIntersectionPointComparer
{
/*
1.1 ~operator()~
*/
size_t operator()(const InternalIntersectionPoint &x) const
{
return
((size_t)(x.GetX().GetIntegerPart())) ^
((size_t)(x.GetY().GetIntegerPart()));
}
/*
1.1 ~operator()~
*/
bool operator()(const InternalIntersectionPoint &x,
const InternalIntersectionPoint &y) const
{
return InternalIntersectionPoint::IsEqual(x, y);
}
};
/*
1 Struct ~InternalIntersectionPointLess~
*/
struct InternalIntersectionPointLess
{
/*
1.1 ~operator()~
*/
bool operator()(const InternalIntersectionPoint &x,
const InternalIntersectionPoint &y) const
{
int result = Rational::Compare(x.GetX(), y.GetX());
if (result == 0) {
result = Rational::Compare(x.GetY(), y.GetY());
}
return result < 0;
}
};
/*
1 Class ~InternalPointTransformation~
This class is used to transform the SECONDO points into ~InternalPoints~ and
vice versa. It uses two offsets and a scale factor.
*/
class InternalPointTransformation
{
/*
1.1 Member variables
*/
private:
long long _offsetX;
long long _offsetY;
int _scaleFactor;
int _roundResultToDecimals;
int _roundingStep;
int _almostEqualSortMargin;
public:
/*
1.1 Constructor
*/
InternalPointTransformation(const long long offsetX,
const long long offsetY,
const int scaleFactor,
const int roundResultToDecimals,
const int roundingDecimalSteps);
/*
1.1 ~RoundRational~
*/
int RoundRational(const Rational& rat) const
{
return Rational::Round(rat, _roundingStep);
}
/*
1.1 ~RoundPoint~
*/
const InternalPoint RoundPoint(const InternalPoint& point) const
{
int newX = Rational::Round(Rational(point.GetX()), _roundingStep);
int newY = Rational::Round(Rational(point.GetY()), _roundingStep);
return InternalPoint(newX, newY);
}
const InternalPoint RoundPoint(const InternalIntersectionPoint& point) const
{
int newX = Rational::Round(point.GetX(), _roundingStep);
int newY = Rational::Round(point.GetY(), _roundingStep);
return InternalPoint(newX, newY);
}
/*
1.1 ~TransformToPoint~
*/
const Point TransformToPoint(const InternalPoint& point) const
{
const InternalPoint& temp = RoundPoint(point);
long long x = ((long long)temp.GetX()) + _offsetX;
long long y = ((long long)temp.GetY()) + _offsetY;
Point result(true,
Utility::Round(x / (double)_scaleFactor,
_roundResultToDecimals),
Utility::Round(y / (double)_scaleFactor,
_roundResultToDecimals));
return result;
}
const Point TransformToPoint(const InternalIntersectionPoint& point) const
{
const InternalPoint& temp = RoundPoint(point);
long long x = ((long long)temp.GetX()) + _offsetX;
long long y = ((long long)temp.GetY()) + _offsetY;
Point result(
true,
Utility::Round(x / (double)_scaleFactor,
_roundResultToDecimals),
Utility::Round(y / (double)_scaleFactor,
_roundResultToDecimals));
return result;
}
/*
1.1 ~TransformToInternalX~
*/
int TransformToInternalX(const Point& point) const
{
int intX = (int)(((long long)
Utility::Round(point.GetX() * _scaleFactor, 0))
- _offsetX);
return intX;
}
/*
1.1 ~TransformToInternalPoint~
*/
const InternalPoint TransformToInternalPoint(const Point& point) const
{
int intX = (int)(((long long)
Utility::Round(point.GetX() * _scaleFactor, 0))
- _offsetX);
int intY = (int)(((long long)
Utility::Round(point.GetY() * _scaleFactor, 0))
- _offsetY);
return InternalPoint(intX, intY);
}
/*
1.1 ~GetScaleFactor~
*/
int GetScaleFactor() const
{
return _scaleFactor;
}
/*
1.1 ~GetRoundResultToDecimals~
*/
int GetRoundResultToDecimals() const
{
return _roundResultToDecimals;
}
/*
1.1 ~GetMinimalRoundedStep~
*/
int GetMinimalRoundedStep() const
{
return _roundingStep;
}
/*
1.1 ~GetAlmostEqualSortMargin~
*/
int GetAlmostEqualSortMargin() const
{
return _almostEqualSortMargin;
}
};
/*
1 Class ~InternalResultLineSegment~
The ~InternalResultLineSegment~ class is equivalent to the ~HalfSegment~ class,
except that the end points are still ~InternalPoint~s.
*/
class InternalResultLineSegment
{
/*
1.1 Member variables
*/
private:
InternalPoint _originalStart;
InternalPoint _start;
InternalPoint _originalEnd;
InternalPoint _end;
InternalAttribute _internalAttribute;
public:
/*
1.1 Constructor
*/
inline InternalResultLineSegment(const InternalPoint& originalStart,
const InternalPoint& start,
const InternalPoint& originalEnd,
const InternalPoint& end,
const InternalAttribute& internalAttribute,
bool correctAttribute) :
_originalStart(originalStart),
_start(start),
_originalEnd(originalEnd),
_end(end),
_internalAttribute(internalAttribute)
{
if (correctAttribute
&& start.GetX() == end.GetX()
&& internalAttribute.IsDefined()) {
int dx, dy;
dx = _originalEnd.GetX() - _originalStart.GetX();
dy = _originalEnd.GetY() - _originalStart.GetY();
// segment is vertical after rounding, but was not so before ->
// adjust attributes if necessary
if ((dx > 0 && dy < 0) || (dx < 0 && dy > 0)) {
_internalAttribute = _internalAttribute.FlipInteriorAbove();
}
}
}
/*
1.1 ~GetStart~
*/
inline const InternalPoint& GetStart() const
{
return _start;
}
/*
1.1 ~GetOriginalStart~
*/
inline const InternalPoint& GetOriginalStart() const
{
return _originalStart;
}
/*
1.1 ~GetEnd~
*/
inline const InternalPoint& GetEnd() const
{
return _end;
}
/*
1.1 ~GetOriginalEnd~
*/
inline const InternalPoint& GetOriginalEnd() const
{
return _originalEnd;
}
/*
1.1 ~GetInternalAttribute~
*/
inline const InternalAttribute GetInternalAttribute() const
{
return _internalAttribute;
}
/*
1.1 ~MergeSegments~
*/
static InternalResultLineSegment
MergeSegments(const InternalResultLineSegment& s0,
const InternalResultLineSegment& s1);
/*
1.1 ~GetHalfSegment~
*/
HalfSegment
GetHalfSegment(const InternalPointTransformation* transformation) const
{
HalfSegment h(true,
transformation->TransformToPoint(_start),
transformation->TransformToPoint(_end));
return h;
}
};
/*
1 Class ~InternalLineSegment~
This class represents a line segment inside the ~BentleyOttmann~ class.
It contains a left and a right end points and all found intersections with the
necessary attributes.
*/
class InternalLineSegment
{
/*
1.1 Member variables
*/
private:
InternalPoint _left;
InternalPoint _right;
Rational _slope;
bool _isVertical;
InternalIntersectionPoint _breakupStart;
std::map<
InternalIntersectionPoint,
InternalAttribute,
InternalIntersectionPointLess> *_intersections;
InternalAttribute _initialAttribute;
mutable int _lastX1;
mutable Rational _lastY1;
mutable int _lastX2;
mutable Rational _lastY2;
AvlTreeNode<InternalLineSegment*, SweepStateData*>* _treeNode;
/*
1.1 Private constructor
*/
InternalLineSegment(InternalLineSegment&) :
_left(0, 0),
_right(0, 0),
_slope(0),
_breakupStart(0, 0),
_intersections(NULL),
_initialAttribute(),
_lastX1(std::numeric_limits<int>::min()),
_lastY1(std::numeric_limits<int>::min()),
_lastX2(std::numeric_limits<int>::min()),
_lastY2(std::numeric_limits<int>::min())
{
}
/*
1.1 ~GetInitialInsideAbove~
*/
static bool GetInitialInsideAbove(const Point& start,
const Point& end,
const InternalPoint& internalStart,
const InternalPoint& internalEnd,
bool insideAbove)
{
bool inputVertical = AlmostEqual(start.GetX(), end.GetX());
bool internalVertical = (internalStart.GetX() == internalEnd.GetX());
if (inputVertical == internalVertical) {
return insideAbove;
} else if (inputVertical) {
// !internalVertical
// not tested
int dx = internalEnd.GetX() - internalStart.GetX();
int dy = internalEnd.GetY() - internalStart.GetY();
if ((dx > 0 && dy < 0) || (dx < 0 && dy > 0)) {
return !insideAbove;
} else {
return insideAbove;
}
} else if (internalVertical) {
double dx = end.GetX() - start.GetX();
double dy = end.GetY() - start.GetY();
if ((dx > 0 && dy < 0) || (dx < 0 && dy > 0)) {
return !insideAbove;
} else {
return insideAbove;
}
} else {
throw new std::logic_error("not possible");
}
}
public:
/*
1.1 Constructor
*/
InternalLineSegment(const InternalPointTransformation &transformation,
const HalfSegment &segment,
const bool belongsToSecondGeometry,
const bool belongsToRegion) :
_left(0, 0),
_right(0, 0),
_slope(0),
_breakupStart(0, 0),
_intersections(NULL),
_initialAttribute(),
_lastX1(std::numeric_limits<int>::min()),
_lastY1(std::numeric_limits<int>::min()),
_lastX2(std::numeric_limits<int>::min()),
_lastY2(std::numeric_limits<int>::min())
{
_treeNode = NULL;
const InternalPoint start =
transformation.TransformToInternalPoint(segment.GetLeftPoint());
const InternalPoint end =
transformation.TransformToInternalPoint(segment.GetRightPoint());
bool isReverse = InternalPoint::Compare(start, end) > 0;
if (!isReverse) {
_left = start;
_right = end;
} else {
_left = end;
_right = start;
}
bool insideAbove = segment.attr.insideAbove;
if (belongsToRegion) {
insideAbove = GetInitialInsideAbove(segment.GetLeftPoint(),
segment.GetRightPoint(),
start,
end,
insideAbove);
}
_breakupStart = InternalIntersectionPoint(_left);
_initialAttribute = InternalAttribute::Create(belongsToSecondGeometry,
insideAbove,
belongsToRegion);
int dx = _right.GetX() - _left.GetX();
int dy = _right.GetY() - _left.GetY();
if (dx > 0) {
_isVertical = false;
_slope = Rational(dy, dx);
} else if (dx == 0) {
_isVertical = true;
_slope = Rational(0, 1);
} else {
throw new std::invalid_argument("segment");
}
}
/*
1.1 Destructor
*/
~InternalLineSegment()
{
if (_intersections != NULL) {
delete _intersections;
_intersections = NULL;
}
}
/*
1.1 ~IsStartEndPoint~
*/
inline bool
IsStartEndPoint(const InternalIntersectionPoint &intersectionPoint) const
{
if (InternalIntersectionPoint::IsEqual(intersectionPoint, _left)
|| InternalIntersectionPoint::IsEqual(intersectionPoint, _right)) {
return true;
} else {
return false;
}
}
/*
1.1 ~AddHobbyIntersection~
*/
void AddHobbyIntersection(int x,
int y,
int hobbySpacing);
/*
1.1 ~AddIntersection~
*/
void AddIntersection(const InternalIntersectionPoint& intersectionPoint)
{
if (!IsStartEndPoint(intersectionPoint)) {
if (_intersections == NULL) {
_intersections = new std::map<
InternalIntersectionPoint,
InternalAttribute,
InternalIntersectionPointLess>();
}
_intersections->insert(std::make_pair(intersectionPoint,
InternalAttribute()));
}
}
/*
1.1 ~GetLeft~
*/
inline const InternalPoint& GetLeft() const
{
return _left;
}
/*
1.1 ~GetRight~
*/
inline const InternalPoint& GetRight() const
{
return _right;
}
/*
1.1 ~GetYValueAt~
wrong results if x in p is not an integer
*/
const Rational& GetYValueAt(const InternalIntersectionPoint& p)
{
if (_isVertical) {
return p.GetY();
}
return GetYValueAt(p.GetX().GetIntegerPart());
}
/*
1.1 ~GetYValueAt~
*/
const Rational& GetYValueAt(int x) const
{
if (_lastX1 == x) {
return _lastY1;
}
if (_lastX2 == x) {
return _lastY2;
}
_lastX2 = _lastX1;
_lastY2 = _lastY1;
_lastX1 = x;
_lastY1 = _slope * (x - _left.GetX()) + _left.GetY();
return _lastY1;
}
/*
1.1 ~GetIntersections~
*/
std::map<
InternalIntersectionPoint,
InternalAttribute,
InternalIntersectionPointLess>*
GetIntersections()
{
return _intersections;
}
/*
1.1 ~BreakupLines~
*/
void BreakupLines(const InternalPointTransformation &transformation,
std::vector<InternalResultLineSegment>& target)
{
BreakupLines(transformation, target, false, 0);
}
void BreakupLines(const InternalPointTransformation &transformation,
std::vector<InternalResultLineSegment>& target,
bool observeMaxX,
int maxX)
{
if (_intersections == NULL || _intersections->size() == 0) {
if (observeMaxX) {
return;
}
InternalPoint start = transformation.RoundPoint(_breakupStart);
InternalPoint end = transformation.RoundPoint(_right);
if (!InternalPoint::IsEqual(start, end)) {
target.push_back(InternalResultLineSegment(_left,
start,
_right,
end,
_initialAttribute,
true));
}
return;
}
bool newBreakupStartSet = false;
InternalIntersectionPoint currentPosition = _breakupStart;
InternalAttribute currentAttribute = _initialAttribute;
InternalPoint currentPositionRounded =
transformation.RoundPoint(currentPosition);
std::map<
InternalIntersectionPoint,
InternalAttribute,
InternalIntersectionPointLess> *newIntersections = NULL;
for (std::map<
InternalIntersectionPoint,
InternalAttribute,
InternalIntersectionPointLess>::const_iterator i =
_intersections->begin(); i != _intersections->end(); ++i) {
InternalIntersectionPoint p = i->first;
if (!observeMaxX || transformation.RoundRational(p.GetX()) <= maxX) {
InternalPoint roundedP = transformation.RoundPoint(p);
if (!InternalPoint::IsEqual(currentPositionRounded, roundedP)) {
target.push_back(InternalResultLineSegment(_left,
currentPositionRounded,
_right,
roundedP,
currentAttribute,
true));
currentPosition = p;
currentPositionRounded = roundedP;
}
if (i->second.IsDefined()) {
currentAttribute = i->second;
}
} else {
if (!newBreakupStartSet) {
newBreakupStartSet = true;
_breakupStart = currentPosition;
_initialAttribute = currentAttribute;
}
if (newIntersections == NULL) {
newIntersections = new std::map<
InternalIntersectionPoint,
InternalAttribute,
InternalIntersectionPointLess>();
}
newIntersections->insert(*i);
}
}
if (!observeMaxX) {
InternalPoint roundedRight = transformation.RoundPoint(_right);
if (!InternalPoint::IsEqual(currentPositionRounded, roundedRight)) {
target.push_back(InternalResultLineSegment(_left,
currentPositionRounded,
_right,
roundedRight,
currentAttribute,
true));
}
} else {
if (!newBreakupStartSet) {
_breakupStart = currentPosition;
_initialAttribute = currentAttribute;
}
if (_intersections != NULL) {
delete _intersections;
_intersections = NULL;
}
_intersections = newIntersections;
}
}
/*
1.1 ~GetSlope~
*/
inline const Rational& GetSlope() const
{
if (_isVertical) {
throw new std::logic_error("Vertical");
}
return _slope;
}
/*
1.1 ~GetIsVertical~
*/
inline bool GetIsVertical() const
{
return _isVertical;
}
/*
1.1 ~GetTreeNode~
*/
AvlTreeNode<InternalLineSegment*, SweepStateData*>* GetTreeNode() const
{
return _treeNode;
}
/*
1.1 ~SetTreeNode~
*/
void SetTreeNode(AvlTreeNode<InternalLineSegment*, SweepStateData*>* treeNode)
{
if (_treeNode != NULL && treeNode != NULL && (_treeNode != treeNode)) {
throw new std::invalid_argument("treeNode");
}
_treeNode = treeNode;
}
/*
1.1 ~GetInitialAttribute~
*/
const InternalAttribute GetInitialAttribute() const
{
return _initialAttribute;
}
/*
1.1 ~GetAttributeAt~
*/
const InternalAttribute GetAttributeAt(const InternalIntersectionPoint& p,
bool includeP) const
{
InternalAttribute result = _initialAttribute;
if (_intersections != NULL) {
for (std::map<
InternalIntersectionPoint,
InternalAttribute,
InternalIntersectionPointLess>::const_iterator i =
_intersections->begin(); i != _intersections->end(); ++i) {
if (i->second.IsDefined()) {
if (!_isVertical) {
if (i->first.GetX() < p.GetX()
|| (includeP && i->first.GetX() == p.GetX())) {
result = i->second;
} else {
break;
}
} else {
if (i->first.GetY() < p.GetY()
|| (includeP && i->first.GetY() == p.GetY())) {
result = i->second;
} else {
break;
}
}
}
}
}
return result;
}
/*
1.1 ~AddAttributeEntry~
*/
void AddAttributeEntry(const InternalIntersectionPoint& p,
const InternalAttribute& attribute)
{
(*_intersections)[p] = attribute;
}
/*
1.1 ~SetAttributeNoBelow~
*/
void SetAttributeNoBelow(const bool setInitialAttribute,
const InternalIntersectionPoint& point)
{
InternalAttribute newAttribute;
if (_initialAttribute.IsBoundaryInFirst()) {
newAttribute = InternalAttribute(_initialAttribute.GetFirst(),
BoundaryType::OutsideInterior);
} else if (_initialAttribute.IsBoundaryInSecond()) {
newAttribute = InternalAttribute(BoundaryType::OutsideInterior,
_initialAttribute.GetSecond());
} else {
throw new std::logic_error("unknown attribute owner (noAbove)");
}
if (newAttribute.IsBoundaryInBoth()) {
throw new std::logic_error("attribute must belong to "
"exactly one geometry (noAbove)!");
}
if (setInitialAttribute) {
_initialAttribute = newAttribute;
} else {
AddAttributeEntry(point, newAttribute);
}
}
/*
1.1 ~SetAttribute~
*/
void SetAttribute(const InternalAttribute& attribute,
const bool setInitialAttribute,
const InternalIntersectionPoint& point)
{
InternalAttribute newAttribute;
InternalAttribute currentAttribute =
(setInitialAttribute ? _initialAttribute :
GetAttributeAt(point, false));
if (currentAttribute.IsBoundaryInFirst()) {
if (attribute.IsBoundaryInFirst() && !attribute.IsBoundaryInSecond()) {
newAttribute = InternalAttribute(currentAttribute.GetFirst(),
attribute.GetSecond());
} else {
newAttribute = InternalAttribute(currentAttribute.GetFirst(),
(attribute.IsSecondAbove() ?
BoundaryType::InsideInterior :
BoundaryType::OutsideInterior));
}
} else if (currentAttribute.IsBoundaryInSecond()) {
if (attribute.IsBoundaryInSecond() && !attribute.IsBoundaryInFirst()) {
newAttribute = InternalAttribute(attribute.GetFirst(),
currentAttribute.GetSecond());
} else {
newAttribute = InternalAttribute((attribute.IsFirstAbove() ?
BoundaryType::InsideInterior :
BoundaryType::OutsideInterior),
currentAttribute.GetSecond());
}
} else {
throw new std::logic_error("unknown attribute owner!");
}
if (newAttribute.IsBoundaryInBoth()) {
throw new std::logic_error("attribute must belong"
" to exactly one geometry!");
}
if (setInitialAttribute) {
_initialAttribute = newAttribute;
} else {
AddAttributeEntry(point, newAttribute);
}
}
/*
1.1 ~CompareSlope~
*/
int static CompareSlope(InternalLineSegment* x, InternalLineSegment* y)
{
int result;
if (x->GetIsVertical() && y->GetIsVertical()) {
result = 0;
} else if (x->GetIsVertical()) {
result = 1;
} else if (y->GetIsVertical()) {
result = -1;
} else {
result = Rational::Compare(x->GetSlope(), y->GetSlope());
}
return result;
}
};
}