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

412 lines
9.9 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 class ~Hobby~
[TOC]
1 Overview
This header file contains all structs and classes required for the
class ~Hobby~.
This class implements the (slightly modified) Hobby algorithm.
To use this class, derive a data class from ~IntersectionAlgorithmData~ and
overwrite the necessary methods.
1 Includes
*/
#pragma once
#include <limits>
#include <unordered_set>
#include "BentleyOttmann.h"
namespace RobustPlaneSweep
{
/*
1 Class ~Hobby~
*/
class Hobby : public BentleyOttmann
{
private:
/*
1.1 Private enum class ~HobbyEventType~
*/
enum class HobbyEventType
{
Undefined,
EndTolaranceSquare,
BeginTolaranceSquare,
SegmentEnter,
SegmentStart,
SegmentEnd,
SegmentExit,
};
/*
1.1 Private class ~HobbyEvent~
*/
class HobbyEvent
{
/*
1.1.1 Member variables
*/
private:
Rational _y;
InternalLineSegment* _segment;
HobbyEventType _eventType;
public:
/*
1.1.1 Constructor
*/
HobbyEvent(HobbyEventType eventType,
Rational y,
InternalLineSegment* segment) :
_y(y),
_segment(segment),
_eventType(eventType)
{
}
/*
1.1.1 ~GetEventType~
*/
HobbyEventType GetEventType() const
{
return _eventType;
}
/*
1.1.1 ~GetY~
*/
Rational GetY() const
{
return _y;
}
/*
1.1.1 ~GetSegment~
*/
InternalLineSegment* GetSegment() const
{
return _segment;
}
/*
1.1.1 ~Compare~
*/
static int Compare(const HobbyEvent &x, const HobbyEvent &y)
{
int result = Rational::Compare(x._y, y._y);
if (result == 0) {
HobbyEventType xe = x._eventType;
HobbyEventType ye = y._eventType;
if (x._eventType == HobbyEventType::SegmentExit
&& y._eventType == HobbyEventType::SegmentExit) {
if (x._segment->GetSlope() < y._segment->GetSlope()) {
result = 1;
return result;
} else if (x._segment->GetSlope() > y._segment->GetSlope()) {
result = -1;
return result;
}
} else if (x._eventType == HobbyEventType::SegmentExit) {
if (x._segment->GetSlope() < 0) {
result = 1;
return result;
} else if (x._segment->GetSlope() > 0) {
result = -1;
return result;
}
} else if (y._eventType == HobbyEventType::SegmentExit) {
if (y._segment->GetSlope() < 0) {
result = -1;
return result;
} else if (y._segment->GetSlope() > 0) {
result = 1;
return result;
}
}
if (xe == HobbyEventType::BeginTolaranceSquare
&& ye == HobbyEventType::EndTolaranceSquare) {
return 1;
} else if (xe == HobbyEventType::EndTolaranceSquare
&& ye == HobbyEventType::BeginTolaranceSquare) {
return -1;
}
if (xe == HobbyEventType::EndTolaranceSquare) {
return -1;
} else if (ye == HobbyEventType::EndTolaranceSquare) {
return 1;
}
if (xe == HobbyEventType::BeginTolaranceSquare) {
return -1;
} else if (ye == HobbyEventType::BeginTolaranceSquare) {
return 1;
}
}
return result;
}
/*
1.1 ~operator\textless~
*/
bool operator<(const HobbyEvent &y) const
{
return Compare(*this, y) < 0;
}
};
/*
1.1 Private struct ~IgnoredIntersectionsComparer~
*/
struct IgnoredIntersectionsComparer
{
size_t operator()(const std::pair<int, InternalLineSegment*> &x) const
{
return ((size_t)x.first) ^ ((size_t)x.second);
}
bool operator()(const std::pair<int, InternalLineSegment*> &x,
const std::pair<int, InternalLineSegment*> &y) const
{
return (x.first == y.first && x.second == y.second);
}
};
/*
1.1 Member variables
*/
int _currentHammock;
int _currentHammockStart;
int _currentHammockEnd;
std::unordered_set<InternalLineSegment*> _addedSegments;
std::unordered_set<InternalLineSegment*> _openSegments;
std::unordered_set<
std::pair<int, InternalLineSegment*>,
IgnoredIntersectionsComparer,
IgnoredIntersectionsComparer> _ignoredIntersections;
std::vector<HobbyEvent> _events;
std::unordered_set<int> _addedSquares;
int _spacing;
void ProcessEvents();
void AddEvents();
bool AddSegmentEvent(int topSquareEdge,
int bottomSquareEdge,
int direction,
InternalLineSegment* segment);
AvlTreeNode<InternalLineSegment*, SweepStateData*>*
GetStartNode(const Rational& searchY) const;
protected:
/*
1.1 Methods
1.1.1 ~GetInitialScaleFactor~
*/
int GetInitialScaleFactor() const
{
return 2;
}
/*
1.1.1 ~GetBreakupUntil~
*/
int GetBreakupUntil() const
{
return _currentHammock - _spacing - 1;
}
/*
1.1.1 ~DetermineIntersectionsInternal~
*/
void DetermineIntersectionsInternal();
/*
1.1.1 ~OnXChanged~
*/
bool OnXChanged(const Rational& /* oldx */, const Rational& newX)
{
if (newX >= _currentHammockEnd) {
ProcessEvents();
_currentHammock = GetTransformation()->RoundRational(newX);
_currentHammockStart = _currentHammock - _spacing;
_currentHammockEnd = _currentHammock + _spacing;
return true;
} else {
return false;
}
}
/*
1.1.1 ~BeforeProcessEvent~
*/
void BeforeProcessEvent(SweepEvent* sweepEvent)
{
int square = GetTransformation()->
RoundRational(sweepEvent->GetPoint().GetY());
if (_addedSquares.insert(square).second) {
_events.push_back(HobbyEvent(HobbyEventType::BeginTolaranceSquare,
Rational(square - _spacing, 0, 1),
NULL));
_events.push_back(HobbyEvent(HobbyEventType::EndTolaranceSquare,
Rational(square + _spacing, 0, 1),
NULL));
}
if (sweepEvent->GetEventType() == SweepEventType::Start) {
if (!_addedSegments.insert(sweepEvent->GetSegment()).second) {
throw new std::logic_error("segment could not be "
"added to _addedSegments!");
}
if (!_openSegments.insert(sweepEvent->GetSegment()).second) {
throw new std::logic_error("segment could not be "
"added to _openSegments!");
}
_ignoredIntersections.insert(std::make_pair(square,
sweepEvent->GetSegment()));
_events.push_back(HobbyEvent(HobbyEventType::SegmentStart,
sweepEvent->GetPoint().GetY(),
sweepEvent->GetSegment()));
} else if (sweepEvent->GetEventType() == SweepEventType::End) {
if (_openSegments.erase(sweepEvent->GetSegment()) == 0) {
_events.push_back(HobbyEvent(HobbyEventType::SegmentEnter,
sweepEvent->GetSegment()->
GetYValueAt(_currentHammockStart),
sweepEvent->GetSegment()));
if (!_addedSegments.insert(sweepEvent->GetSegment()).second) {
throw new std::logic_error("segment could not be "
"added to _addedSegments!");
}
}
_ignoredIntersections.insert(std::make_pair(square,
sweepEvent->GetSegment()));
_events.push_back(HobbyEvent(HobbyEventType::SegmentEnd,
sweepEvent->GetPoint().GetY(),
sweepEvent->GetSegment()));
} else if (sweepEvent->GetEventType() == SweepEventType::Intersection) {
std::unordered_set<InternalLineSegment*>* intersectedSegments =
sweepEvent->GetIntersectedSegments();
for (std::unordered_set<InternalLineSegment*>::const_iterator
s = intersectedSegments->begin();
s != intersectedSegments->end(); ++s) {
_ignoredIntersections.insert(std::make_pair(square, *s));
if (_openSegments.insert(*s).second) {
_events.push_back(HobbyEvent(HobbyEventType::SegmentEnter,
(*s)->GetYValueAt(_currentHammockStart),
*s));
if (!_addedSegments.insert(*s).second) {
throw new std::logic_error("segment could not be "
"added to _addedSegments!");
}
}
}
} else if (sweepEvent->GetEventType() == SweepEventType::Point) {
} else {
throw new std::invalid_argument("sweepEvent");
}
}
/*
1.1.1 ~Finished~
*/
void Finished()
{
ProcessEvents();
}
public:
/*
1.1.1 Constructor
*/
explicit Hobby(IntersectionAlgorithmData* data) :
BentleyOttmann(data),
_currentHammock(std::numeric_limits<int>::min()),
_currentHammockStart(std::numeric_limits<int>::min()),
_currentHammockEnd(std::numeric_limits<int>::min()),
_spacing(0)
{
}
};
}