3330 lines
66 KiB
C++
3330 lines
66 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] Implementation file for the class ~RobustPlaneSweepAlgebra~
|
||
|
|
|
||
|
|
[TOC]
|
||
|
|
|
||
|
|
1 Overview
|
||
|
|
|
||
|
|
This file contains all structs and classes required for the
|
||
|
|
RobustPlaneSweepAlgebra.
|
||
|
|
|
||
|
|
1 Includes and defines
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
// #define OUTPUT_HALFSEGMENTS
|
||
|
|
#include "Algebras/Spatial/SpatialAlgebra.h"
|
||
|
|
#include "RobustPlaneSweepAlgebra.h"
|
||
|
|
#include "Algebras/Temporal/TemporalAlgebra.h"
|
||
|
|
#include "Algebras/Spatial/DLine.h"
|
||
|
|
|
||
|
|
#include "Algorithm/Hobby.h"
|
||
|
|
|
||
|
|
#include "RobustOperators.h"
|
||
|
|
|
||
|
|
using namespace temporalalgebra;
|
||
|
|
using namespace std;
|
||
|
|
|
||
|
|
namespace RobustPlaneSweep
|
||
|
|
{
|
||
|
|
/*
|
||
|
|
|
||
|
|
1 Data classes
|
||
|
|
|
||
|
|
1.1 Data class for operations with two HalfSegment-Collections (Line or Region)
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class TINPUT1, class TINPUT2>
|
||
|
|
class HalfSegmentHalfSegmentData :
|
||
|
|
public IntersectionAlgorithmData
|
||
|
|
{
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Member variables
|
||
|
|
|
||
|
|
*/
|
||
|
|
private:
|
||
|
|
const TINPUT1& _source1;
|
||
|
|
int _source1Index;
|
||
|
|
int _source1Size;
|
||
|
|
HalfSegment _source1segment;
|
||
|
|
|
||
|
|
const TINPUT2& _source2;
|
||
|
|
int _source2Index;
|
||
|
|
int _source2Size;
|
||
|
|
HalfSegment _source2segment;
|
||
|
|
|
||
|
|
public:
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Constructor
|
||
|
|
|
||
|
|
*/
|
||
|
|
HalfSegmentHalfSegmentData(const TINPUT1& source1,
|
||
|
|
const TINPUT2& source2) :
|
||
|
|
_source1(source1),
|
||
|
|
_source1Index(0),
|
||
|
|
_source1Size(-1),
|
||
|
|
_source2(source2),
|
||
|
|
_source2Index(0),
|
||
|
|
_source2Size(-1)
|
||
|
|
{
|
||
|
|
#ifdef OUTPUT_HALFSEGMENTS
|
||
|
|
cout.precision(15);
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Destructor
|
||
|
|
|
||
|
|
*/
|
||
|
|
~HalfSegmentHalfSegmentData()
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~InitializeFetch~
|
||
|
|
|
||
|
|
*/
|
||
|
|
void InitializeFetch()
|
||
|
|
{
|
||
|
|
#ifdef OUTPUT_HALFSEGMENTS
|
||
|
|
cout << "\n";
|
||
|
|
#endif
|
||
|
|
_source1Index = 0;
|
||
|
|
_source1Size = _source1.Size();
|
||
|
|
if (_source1Index < _source1Size) {
|
||
|
|
_source1.Get(_source1Index, _source1segment);
|
||
|
|
}
|
||
|
|
|
||
|
|
_source2Index = 0;
|
||
|
|
_source2Size = _source2.Size();
|
||
|
|
if (_source2Index < _source2Size) {
|
||
|
|
_source2.Get(_source2Index, _source2segment);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~FetchInput~
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool FetchInput(HalfSegment &segment,
|
||
|
|
Point &point,
|
||
|
|
bool &belongsToSecondGeometry)
|
||
|
|
{
|
||
|
|
point.SetDefined(false);
|
||
|
|
if (_source1Index < _source1Size && _source2Index < _source2Size) {
|
||
|
|
if (_source1segment.Compare(_source2segment) < 0) {
|
||
|
|
belongsToSecondGeometry = false;
|
||
|
|
} else {
|
||
|
|
belongsToSecondGeometry = true;
|
||
|
|
}
|
||
|
|
} else if (_source1Index < _source1Size) {
|
||
|
|
belongsToSecondGeometry = false;
|
||
|
|
} else if (_source2Index < _source2Size) {
|
||
|
|
belongsToSecondGeometry = true;
|
||
|
|
} else {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!belongsToSecondGeometry) {
|
||
|
|
segment = _source1segment;
|
||
|
|
if ((++_source1Index) < _source1Size) {
|
||
|
|
_source1.Get(_source1Index, _source1segment);
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
segment = _source2segment;
|
||
|
|
if ((++_source2Index) < _source2Size) {
|
||
|
|
_source2.Get(_source2Index, _source2segment);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#ifdef OUTPUT_HALFSEGMENTS
|
||
|
|
if (!segment.IsLeftDomPoint()) {
|
||
|
|
cout << "// ";
|
||
|
|
}
|
||
|
|
|
||
|
|
cout << "s.Add(new LineSegment(" <<
|
||
|
|
(belongsToSecondGeometry?"1":"0") << ", " <<
|
||
|
|
(segment.attr.edgeno) << ", " <<
|
||
|
|
" new Base.Point(" <<
|
||
|
|
segment.GetLeftPoint().GetX() << "," <<
|
||
|
|
segment.GetLeftPoint().GetY() << "), " <<
|
||
|
|
" new Base.Point(" <<
|
||
|
|
segment.GetRightPoint().GetX() << "," <<
|
||
|
|
segment.GetRightPoint().GetY() << "), " <<
|
||
|
|
(segment.attr.insideAbove?"true":"false") <<
|
||
|
|
"));\n";
|
||
|
|
#endif
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~GetBoundingBox~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const Rectangle<2> GetBoundingBox()
|
||
|
|
{
|
||
|
|
return _source1.BoundingBox().Union(_source2.BoundingBox());
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~FirstGeometryIsRegion~
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool FirstGeometryIsRegion() const
|
||
|
|
{
|
||
|
|
return std::is_same<TINPUT1, Region>::value;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~SecondGeometryIsRegion~
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool SecondGeometryIsRegion() const
|
||
|
|
{
|
||
|
|
return std::is_same<TINPUT2, Region>::value;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1 Data class for operations with HalfSegment-Collection and Point(s)
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class THALFSEGMENT, class TPOINTS>
|
||
|
|
class HalfSegmentPointsData :
|
||
|
|
public IntersectionAlgorithmData
|
||
|
|
{
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1 Template specialization class for operations with
|
||
|
|
HalfSegment-Collection x Points
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class THALFSEGMENT>
|
||
|
|
class HalfSegmentPointsData<THALFSEGMENT, Points> :
|
||
|
|
public IntersectionAlgorithmData
|
||
|
|
{
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Member variables
|
||
|
|
|
||
|
|
*/
|
||
|
|
private:
|
||
|
|
const THALFSEGMENT& _source1;
|
||
|
|
int _source1Index;
|
||
|
|
int _source1Size;
|
||
|
|
HalfSegment _source1segment;
|
||
|
|
|
||
|
|
const Points& _source2;
|
||
|
|
int _source2Index;
|
||
|
|
int _source2Size;
|
||
|
|
Point _source2Point;
|
||
|
|
|
||
|
|
public:
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Constructor
|
||
|
|
|
||
|
|
*/
|
||
|
|
HalfSegmentPointsData(const THALFSEGMENT& source1,
|
||
|
|
const Points& source2) :
|
||
|
|
_source1(source1),
|
||
|
|
_source1Index(0),
|
||
|
|
_source1Size(-1),
|
||
|
|
_source2(source2),
|
||
|
|
_source2Index(0),
|
||
|
|
_source2Size(-1)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Destructor
|
||
|
|
|
||
|
|
*/
|
||
|
|
~HalfSegmentPointsData()
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~InitializeFetch~
|
||
|
|
|
||
|
|
*/
|
||
|
|
void InitializeFetch()
|
||
|
|
{
|
||
|
|
_source1Index = 0;
|
||
|
|
_source1Size = _source1.Size();
|
||
|
|
if (_source1Index < _source1Size) {
|
||
|
|
_source1.Get(_source1Index, _source1segment);
|
||
|
|
}
|
||
|
|
|
||
|
|
_source2Index = 0;
|
||
|
|
_source2Size = _source2.Size();
|
||
|
|
if (_source2Index < _source2Size) {
|
||
|
|
_source2.Get(_source2Index, _source2Point);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~FetchInput~
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool FetchInput(HalfSegment &segment,
|
||
|
|
Point &point,
|
||
|
|
bool &belongsToSecondGeometry)
|
||
|
|
{
|
||
|
|
if (_source1Index < _source1Size && _source2Index < _source2Size) {
|
||
|
|
if (_source1segment.GetDomPoint() < _source2Point) {
|
||
|
|
belongsToSecondGeometry = false;
|
||
|
|
} else {
|
||
|
|
belongsToSecondGeometry = true;
|
||
|
|
}
|
||
|
|
} else if (_source1Index < _source1Size) {
|
||
|
|
belongsToSecondGeometry = false;
|
||
|
|
} else if (_source2Index < _source2Size) {
|
||
|
|
belongsToSecondGeometry = true;
|
||
|
|
} else {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!belongsToSecondGeometry) {
|
||
|
|
point.SetDefined(false);
|
||
|
|
segment = _source1segment;
|
||
|
|
if ((++_source1Index) < _source1Size) {
|
||
|
|
_source1.Get(_source1Index, _source1segment);
|
||
|
|
}
|
||
|
|
#ifdef OUTPUT_HALFSEGMENTS
|
||
|
|
if (!segment.IsLeftDomPoint()) {
|
||
|
|
cout << "// ";
|
||
|
|
}
|
||
|
|
|
||
|
|
cout << "s.Add(new LineSegment(" <<
|
||
|
|
(belongsToSecondGeometry?"1":"0") << ", " <<
|
||
|
|
(segment.attr.edgeno) << ", " <<
|
||
|
|
" new Base.Point(" <<
|
||
|
|
segment.GetLeftPoint().GetX() << "," <<
|
||
|
|
segment.GetLeftPoint().GetY() << "), " <<
|
||
|
|
" new Base.Point(" <<
|
||
|
|
segment.GetRightPoint().GetX() << "," <<
|
||
|
|
segment.GetRightPoint().GetY() << "), " <<
|
||
|
|
(segment.attr.insideAbove?"true":"false") <<
|
||
|
|
"));\n";
|
||
|
|
#endif
|
||
|
|
} else {
|
||
|
|
point = _source2Point;
|
||
|
|
if ((++_source2Index) < _source2Size) {
|
||
|
|
_source2.Get(_source2Index, _source2Point);
|
||
|
|
}
|
||
|
|
#ifdef OUTPUT_HALFSEGMENTS
|
||
|
|
cout << "s.Add(new LineSegment(" <<
|
||
|
|
(belongsToSecondGeometry?"1":"0") << ", " <<
|
||
|
|
"-1, " <<
|
||
|
|
" new Base.Point(" <<
|
||
|
|
point.GetX() << "," <<
|
||
|
|
point.GetY() << "), " <<
|
||
|
|
" new Base.Point(" <<
|
||
|
|
point.GetX() << "," <<
|
||
|
|
point.GetY() << "), " <<
|
||
|
|
"false" <<
|
||
|
|
"));\n";
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~GetBoundingBox~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const Rectangle<2> GetBoundingBox()
|
||
|
|
{
|
||
|
|
return _source1.BoundingBox().Union(_source2.BoundingBox());
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~FirstGeometryIsRegion~
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool FirstGeometryIsRegion() const
|
||
|
|
{
|
||
|
|
return std::is_same<THALFSEGMENT, Region>::value;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~SecondGeometryIsRegion~
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool SecondGeometryIsRegion() const
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1 Template specialization class for operations with
|
||
|
|
HalfSegment-Collection x Point
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class THALFSEGMENT>
|
||
|
|
class HalfSegmentPointsData<THALFSEGMENT, Point> :
|
||
|
|
public IntersectionAlgorithmData
|
||
|
|
{
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Member variables
|
||
|
|
|
||
|
|
*/
|
||
|
|
private:
|
||
|
|
const THALFSEGMENT& _source1;
|
||
|
|
int _source1Index;
|
||
|
|
int _source1Size;
|
||
|
|
HalfSegment _source1segment;
|
||
|
|
|
||
|
|
const Point& _source2Point;
|
||
|
|
bool _source2PointRead;
|
||
|
|
|
||
|
|
public:
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Constructor
|
||
|
|
|
||
|
|
*/
|
||
|
|
HalfSegmentPointsData(const THALFSEGMENT& source1,
|
||
|
|
const Point& source2) :
|
||
|
|
_source1(source1),
|
||
|
|
_source1Index(0),
|
||
|
|
_source1Size(-1),
|
||
|
|
_source2Point(source2),
|
||
|
|
_source2PointRead(false)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Destructor
|
||
|
|
|
||
|
|
*/
|
||
|
|
~HalfSegmentPointsData()
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~InitializeFetch~
|
||
|
|
|
||
|
|
*/
|
||
|
|
void InitializeFetch()
|
||
|
|
{
|
||
|
|
_source1Index = 0;
|
||
|
|
_source1Size = _source1.Size();
|
||
|
|
if (_source1Index < _source1Size) {
|
||
|
|
_source1.Get(_source1Index, _source1segment);
|
||
|
|
}
|
||
|
|
|
||
|
|
_source2PointRead = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~FetchInput~
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool FetchInput(HalfSegment &segment,
|
||
|
|
Point &point,
|
||
|
|
bool &belongsToSecondGeometry)
|
||
|
|
{
|
||
|
|
if (_source1Index < _source1Size && !_source2PointRead) {
|
||
|
|
if (_source1segment.GetDomPoint() < _source2Point) {
|
||
|
|
belongsToSecondGeometry = false;
|
||
|
|
} else {
|
||
|
|
belongsToSecondGeometry = true;
|
||
|
|
}
|
||
|
|
} else if (_source1Index < _source1Size) {
|
||
|
|
belongsToSecondGeometry = false;
|
||
|
|
} else if (!_source2PointRead) {
|
||
|
|
belongsToSecondGeometry = true;
|
||
|
|
} else {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!belongsToSecondGeometry) {
|
||
|
|
point.SetDefined(false);
|
||
|
|
segment = _source1segment;
|
||
|
|
if ((++_source1Index) < _source1Size) {
|
||
|
|
_source1.Get(_source1Index, _source1segment);
|
||
|
|
}
|
||
|
|
|
||
|
|
#ifdef OUTPUT_HALFSEGMENTS
|
||
|
|
if (!segment.IsLeftDomPoint()) {
|
||
|
|
cout << "// ";
|
||
|
|
}
|
||
|
|
|
||
|
|
cout << "s.Add(new LineSegment(" <<
|
||
|
|
(belongsToSecondGeometry?"1":"0") << ", " <<
|
||
|
|
(segment.attr.edgeno) << ", " <<
|
||
|
|
" new Base.Point(" <<
|
||
|
|
segment.GetLeftPoint().GetX() << "," <<
|
||
|
|
segment.GetLeftPoint().GetY() << "), " <<
|
||
|
|
" new Base.Point(" <<
|
||
|
|
segment.GetRightPoint().GetX() << "," <<
|
||
|
|
segment.GetRightPoint().GetY() << "), " <<
|
||
|
|
(segment.attr.insideAbove?"true":"false") <<
|
||
|
|
"));\n";
|
||
|
|
#endif
|
||
|
|
|
||
|
|
} else {
|
||
|
|
point = _source2Point;
|
||
|
|
_source2PointRead = true;
|
||
|
|
|
||
|
|
#ifdef OUTPUT_HALFSEGMENTS
|
||
|
|
cout << "s.Add(new LineSegment(" <<
|
||
|
|
(belongsToSecondGeometry?"1":"0") << ", " <<
|
||
|
|
"-1, " <<
|
||
|
|
" new Base.Point(" <<
|
||
|
|
point.GetX() << "," <<
|
||
|
|
point.GetY() << "), " <<
|
||
|
|
" new Base.Point(" <<
|
||
|
|
point.GetX() << "," <<
|
||
|
|
point.GetY() << "), " <<
|
||
|
|
"false" <<
|
||
|
|
"));\n";
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~GetBoundingBox~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const Rectangle<2> GetBoundingBox()
|
||
|
|
{
|
||
|
|
return _source1.BoundingBox().Union(_source2Point.BoundingBox());
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~FirstGeometryIsRegion~
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool FirstGeometryIsRegion() const
|
||
|
|
{
|
||
|
|
return std::is_same<THALFSEGMENT, Region>::value;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~SecondGeometryIsRegion~
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool SecondGeometryIsRegion() const
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1 Enum class for set operation types
|
||
|
|
|
||
|
|
*/
|
||
|
|
enum class SetOpType
|
||
|
|
{
|
||
|
|
Union = 1,
|
||
|
|
Intersection = 2,
|
||
|
|
Minus = 3
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1 Data class for line set operations
|
||
|
|
|
||
|
|
*/
|
||
|
|
class LineLineSetOp :
|
||
|
|
public HalfSegmentHalfSegmentData<Line, Line>
|
||
|
|
{
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Member variables
|
||
|
|
|
||
|
|
*/
|
||
|
|
private:
|
||
|
|
SetOpType _setOpType;
|
||
|
|
|
||
|
|
Line& _result;
|
||
|
|
int _outputSegments;
|
||
|
|
|
||
|
|
public:
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Constructor
|
||
|
|
|
||
|
|
*/
|
||
|
|
LineLineSetOp(const Line& source1,
|
||
|
|
const Line& source2,
|
||
|
|
SetOpType setOpType,
|
||
|
|
Line& result) :
|
||
|
|
HalfSegmentHalfSegmentData<Line, Line>(source1, source2),
|
||
|
|
_setOpType(setOpType),
|
||
|
|
_result(result),
|
||
|
|
_outputSegments(0)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Destructor
|
||
|
|
|
||
|
|
*/
|
||
|
|
~LineLineSetOp()
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~OutputData~
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool OutputData() const
|
||
|
|
{
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~OutputHalfSegment~
|
||
|
|
|
||
|
|
*/
|
||
|
|
void OutputHalfSegment(const HalfSegment& segment,
|
||
|
|
const InternalAttribute& attribute)
|
||
|
|
{
|
||
|
|
switch (_setOpType) {
|
||
|
|
case SetOpType::Union:
|
||
|
|
break;
|
||
|
|
|
||
|
|
case SetOpType::Intersection:
|
||
|
|
if (!attribute.IsBoundaryInBoth()) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
case SetOpType::Minus:
|
||
|
|
if (attribute.IsBoundaryInSecond()) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
default:
|
||
|
|
throw new std::logic_error("setOpType");
|
||
|
|
}
|
||
|
|
|
||
|
|
// cout << "O:" << _outputSegments << "\n";
|
||
|
|
HalfSegment s1 = segment;
|
||
|
|
HalfSegment s2 = segment;
|
||
|
|
s1.SetLeftDomPoint(true);
|
||
|
|
s2.SetLeftDomPoint(false);
|
||
|
|
s1.attr.edgeno = _outputSegments;
|
||
|
|
s2.attr.edgeno = _outputSegments;
|
||
|
|
_result += s1;
|
||
|
|
_result += s2;
|
||
|
|
_outputSegments++;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~SetOp~
|
||
|
|
|
||
|
|
*/
|
||
|
|
static void SetOp(const Line& line1,
|
||
|
|
const Line& line2,
|
||
|
|
SetOpType setOpType,
|
||
|
|
Line& result)
|
||
|
|
{
|
||
|
|
result.StartBulkLoad();
|
||
|
|
LineLineSetOp data(line1, line2, setOpType, result);
|
||
|
|
Hobby hobby(&data);
|
||
|
|
hobby.DetermineIntersections();
|
||
|
|
result.EndBulkLoad(true, false);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1 Data class for region set operations
|
||
|
|
|
||
|
|
*/
|
||
|
|
class RegionRegionSetOp :
|
||
|
|
public HalfSegmentHalfSegmentData<Region, Region>
|
||
|
|
{
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Member variables
|
||
|
|
|
||
|
|
*/
|
||
|
|
private:
|
||
|
|
SetOpType _setOpType;
|
||
|
|
|
||
|
|
Region& _result;
|
||
|
|
int _outputSegments;
|
||
|
|
|
||
|
|
public:
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Constructor
|
||
|
|
|
||
|
|
*/
|
||
|
|
RegionRegionSetOp(const Region& source1,
|
||
|
|
const Region& source2,
|
||
|
|
SetOpType setOpType,
|
||
|
|
Region& result) :
|
||
|
|
HalfSegmentHalfSegmentData<Region, Region>(source1, source2),
|
||
|
|
_setOpType(setOpType),
|
||
|
|
_result(result),
|
||
|
|
_outputSegments(0)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Destructor
|
||
|
|
|
||
|
|
*/
|
||
|
|
~RegionRegionSetOp()
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~OutputData~
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool OutputData() const
|
||
|
|
{
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~OutputHalfSegment~
|
||
|
|
|
||
|
|
*/
|
||
|
|
void OutputHalfSegment(const HalfSegment& segment,
|
||
|
|
const InternalAttribute& attribute)
|
||
|
|
{
|
||
|
|
bool include;
|
||
|
|
bool insideAbove;
|
||
|
|
|
||
|
|
switch (_setOpType) {
|
||
|
|
case SetOpType::Union:
|
||
|
|
include = attribute.IsInUnionRegion(insideAbove);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case SetOpType::Intersection:
|
||
|
|
include = attribute.IsInIntersectionRegion(insideAbove);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case SetOpType::Minus:
|
||
|
|
include = attribute.IsInMinusRegion(insideAbove);
|
||
|
|
break;
|
||
|
|
|
||
|
|
default:
|
||
|
|
throw new std::logic_error("setOpType");
|
||
|
|
}
|
||
|
|
|
||
|
|
#ifdef OUTPUT_HALFSEGMENTS
|
||
|
|
cout << "O: " <<
|
||
|
|
_outputSegments << " (" <<
|
||
|
|
segment.GetLeftPoint().GetX() << "," <<
|
||
|
|
segment.GetLeftPoint().GetY() << ") - (" <<
|
||
|
|
segment.GetRightPoint().GetX() << "," <<
|
||
|
|
segment.GetRightPoint().GetY() << ") (" <<
|
||
|
|
(attribute.IsFirstAbove()?"A":"_") <<
|
||
|
|
(attribute.IsFirstBelow()?"B":"_") << "/" <<
|
||
|
|
(attribute.IsSecondAbove()?"A":"_") <<
|
||
|
|
(attribute.IsSecondBelow()?"B":"_") << ")" <<
|
||
|
|
(include?" Inc ":" - ") <<
|
||
|
|
(insideAbove?" Above ":" Below ") <<
|
||
|
|
"\n";
|
||
|
|
#endif
|
||
|
|
|
||
|
|
if (!include) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// cout << "O:" << _outputSegments << "\n";
|
||
|
|
HalfSegment s1 = segment;
|
||
|
|
HalfSegment s2 = segment;
|
||
|
|
s1.SetLeftDomPoint(true);
|
||
|
|
s2.SetLeftDomPoint(false);
|
||
|
|
s1.attr.edgeno = _outputSegments;
|
||
|
|
s1.attr.insideAbove = insideAbove;
|
||
|
|
s2.attr.edgeno = _outputSegments;
|
||
|
|
s2.attr.insideAbove = insideAbove;
|
||
|
|
_result += s1;
|
||
|
|
_result += s2;
|
||
|
|
_outputSegments++;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~SetOp~
|
||
|
|
|
||
|
|
*/
|
||
|
|
static void SetOp(const Region& region1,
|
||
|
|
const Region& region2,
|
||
|
|
SetOpType setOpType,
|
||
|
|
Region& result)
|
||
|
|
{
|
||
|
|
result.StartBulkLoad();
|
||
|
|
RegionRegionSetOp data(region1, region2, setOpType, result);
|
||
|
|
Hobby hobby(&data);
|
||
|
|
hobby.DetermineIntersections();
|
||
|
|
result.EndBulkLoad();
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1 Data class for region/line set operations
|
||
|
|
|
||
|
|
*/
|
||
|
|
class RegionLineSetOp :
|
||
|
|
public HalfSegmentHalfSegmentData<Region, Line>
|
||
|
|
{
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Member variables
|
||
|
|
|
||
|
|
*/
|
||
|
|
private:
|
||
|
|
SetOpType _setOpType;
|
||
|
|
|
||
|
|
Line& _result;
|
||
|
|
int _outputSegments;
|
||
|
|
|
||
|
|
public:
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Constructor
|
||
|
|
|
||
|
|
*/
|
||
|
|
RegionLineSetOp(const Region& source1,
|
||
|
|
const Line& source2,
|
||
|
|
SetOpType setOpType,
|
||
|
|
Line& result) :
|
||
|
|
HalfSegmentHalfSegmentData<Region, Line>(source1, source2),
|
||
|
|
_setOpType(setOpType),
|
||
|
|
_result(result),
|
||
|
|
_outputSegments(0)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Destructor
|
||
|
|
|
||
|
|
*/
|
||
|
|
~RegionLineSetOp()
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~OutputData~
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool OutputData() const
|
||
|
|
{
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~OutputHalfSegment~
|
||
|
|
|
||
|
|
*/
|
||
|
|
void OutputHalfSegment(const HalfSegment& segment,
|
||
|
|
const InternalAttribute& attribute)
|
||
|
|
{
|
||
|
|
bool include;
|
||
|
|
|
||
|
|
switch (_setOpType) {
|
||
|
|
case SetOpType::Intersection:
|
||
|
|
include = (attribute.GetFirst() != BoundaryType::OutsideInterior &&
|
||
|
|
attribute.IsBoundaryInSecond());
|
||
|
|
break;
|
||
|
|
|
||
|
|
case SetOpType::Minus:
|
||
|
|
include = (attribute.GetFirst() == BoundaryType::OutsideInterior &&
|
||
|
|
attribute.IsBoundaryInSecond());
|
||
|
|
break;
|
||
|
|
|
||
|
|
default:
|
||
|
|
throw new std::logic_error("setOpType");
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!include) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// cout << "O:" << _outputSegments << "\n";
|
||
|
|
HalfSegment s1 = segment;
|
||
|
|
HalfSegment s2 = segment;
|
||
|
|
s1.SetLeftDomPoint(true);
|
||
|
|
s2.SetLeftDomPoint(false);
|
||
|
|
s1.attr.edgeno = _outputSegments;
|
||
|
|
s2.attr.edgeno = _outputSegments;
|
||
|
|
_result += s1;
|
||
|
|
_result += s2;
|
||
|
|
_outputSegments++;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~SetOp~
|
||
|
|
|
||
|
|
*/
|
||
|
|
static void SetOp(const Region& region,
|
||
|
|
const Line& line,
|
||
|
|
SetOpType setOpType,
|
||
|
|
Line& result)
|
||
|
|
{
|
||
|
|
// set result to a highly estimated value to avoid
|
||
|
|
// frequent enlargements of the underlying DbArray
|
||
|
|
result.Resize(line.Size());
|
||
|
|
result.StartBulkLoad();
|
||
|
|
RegionLineSetOp data(region, line, setOpType, result);
|
||
|
|
Hobby hobby(&data);
|
||
|
|
hobby.DetermineIntersections();
|
||
|
|
result.EndBulkLoad();
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1 Data class for {region, line} x {region, line} intersects operator
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class TINPUT1, class TINPUT2>
|
||
|
|
class RegionLineIntersects :
|
||
|
|
public HalfSegmentHalfSegmentData<TINPUT1, TINPUT2>
|
||
|
|
{
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Member variables
|
||
|
|
|
||
|
|
*/
|
||
|
|
private:
|
||
|
|
bool _intersects;
|
||
|
|
|
||
|
|
public:
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Constructor
|
||
|
|
|
||
|
|
*/
|
||
|
|
RegionLineIntersects(const TINPUT1& source1,
|
||
|
|
const TINPUT2& source2) :
|
||
|
|
HalfSegmentHalfSegmentData<TINPUT1, TINPUT2>(source1, source2),
|
||
|
|
_intersects(false)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Destructor
|
||
|
|
|
||
|
|
*/
|
||
|
|
~RegionLineIntersects()
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~OnGeometryIntersectionFound~
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool OnGeometryIntersectionFound()
|
||
|
|
{
|
||
|
|
_intersects = true;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~Intersects~
|
||
|
|
|
||
|
|
*/
|
||
|
|
static bool Intersects(const TINPUT1& source1,
|
||
|
|
const TINPUT2& source2)
|
||
|
|
{
|
||
|
|
RegionLineIntersects<TINPUT1, TINPUT2> data(source1, source2);
|
||
|
|
BentleyOttmann bentleyOttmann(&data);
|
||
|
|
bentleyOttmann.DetermineIntersections();
|
||
|
|
|
||
|
|
return data._intersects;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1 Data class for {region, line} x points set operations
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class THALFSEGMENT, class TPOINTS>
|
||
|
|
class RegionLinePointsSetOp :
|
||
|
|
public HalfSegmentPointsData<THALFSEGMENT, TPOINTS>
|
||
|
|
{
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Member Variables
|
||
|
|
|
||
|
|
*/
|
||
|
|
private:
|
||
|
|
SetOpType _setOpType;
|
||
|
|
Points& _result;
|
||
|
|
|
||
|
|
public:
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Constructor
|
||
|
|
|
||
|
|
*/
|
||
|
|
RegionLinePointsSetOp(const THALFSEGMENT& source1,
|
||
|
|
const TPOINTS& source2,
|
||
|
|
SetOpType setOpType,
|
||
|
|
Points& result) :
|
||
|
|
HalfSegmentPointsData<THALFSEGMENT, TPOINTS>(source1, source2),
|
||
|
|
_setOpType(setOpType),
|
||
|
|
_result(result)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Destructor
|
||
|
|
|
||
|
|
*/
|
||
|
|
~RegionLinePointsSetOp()
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~OutputData~
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool OutputData() const
|
||
|
|
{
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~OutputHalfSegment~
|
||
|
|
|
||
|
|
*/
|
||
|
|
void OutputHalfSegment(const HalfSegment& segment,
|
||
|
|
const InternalAttribute& attribute)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~OutputPoint~
|
||
|
|
|
||
|
|
*/
|
||
|
|
void OutputPoint(const Point& point,
|
||
|
|
const InternalAttribute& attribute)
|
||
|
|
{
|
||
|
|
bool include;
|
||
|
|
|
||
|
|
switch (_setOpType) {
|
||
|
|
case SetOpType::Intersection:
|
||
|
|
include = (attribute.GetFirst() != BoundaryType::OutsideInterior);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case SetOpType::Minus:
|
||
|
|
include = (attribute.GetFirst() == BoundaryType::OutsideInterior);
|
||
|
|
break;
|
||
|
|
|
||
|
|
default:
|
||
|
|
throw new std::logic_error("setOpType");
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!include) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
_result += point;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~SetOp~
|
||
|
|
|
||
|
|
*/
|
||
|
|
static void SetOp(const THALFSEGMENT& source,
|
||
|
|
const TPOINTS& points,
|
||
|
|
SetOpType setOpType,
|
||
|
|
Points& result)
|
||
|
|
{
|
||
|
|
result.StartBulkLoad();
|
||
|
|
RegionLinePointsSetOp data(source, points, setOpType, result);
|
||
|
|
BentleyOttmann bentleyOttmann(&data);
|
||
|
|
bentleyOttmann.DetermineIntersections();
|
||
|
|
result.EndBulkLoad();
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1 Data class for {region, line} x {point, points} intersects operator
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class THALFSEGMENT, class TPOINTS>
|
||
|
|
class RegionLinePointsIntersects :
|
||
|
|
public HalfSegmentPointsData<THALFSEGMENT, TPOINTS>
|
||
|
|
{
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Member variables
|
||
|
|
|
||
|
|
*/
|
||
|
|
private:
|
||
|
|
bool _intersects;
|
||
|
|
|
||
|
|
public:
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Constructor
|
||
|
|
|
||
|
|
*/
|
||
|
|
RegionLinePointsIntersects(const THALFSEGMENT& source1,
|
||
|
|
const Points& source2) :
|
||
|
|
HalfSegmentPointsData<THALFSEGMENT, TPOINTS>(source1, source2),
|
||
|
|
_intersects(false)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Destructor
|
||
|
|
|
||
|
|
*/
|
||
|
|
~RegionLinePointsIntersects()
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~OnGeometryIntersectionFound~
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool OnGeometryIntersectionFound()
|
||
|
|
{
|
||
|
|
_intersects = true;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~Intersects~
|
||
|
|
|
||
|
|
*/
|
||
|
|
static bool Intersects(const THALFSEGMENT& source,
|
||
|
|
const Points& points)
|
||
|
|
{
|
||
|
|
RegionLinePointsIntersects data(source, points);
|
||
|
|
BentleyOttmann bentleyOttmann(&data);
|
||
|
|
bentleyOttmann.DetermineIntersections();
|
||
|
|
|
||
|
|
return data._intersects;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1 Data class for crossing operator
|
||
|
|
|
||
|
|
*/
|
||
|
|
class CrossingsData :
|
||
|
|
public HalfSegmentHalfSegmentData<Line, Line>
|
||
|
|
{
|
||
|
|
private:
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Internal Point comparer struct.
|
||
|
|
|
||
|
|
The coordinates were integer values and the transformation should be
|
||
|
|
deterministic, so there is no need for AlmostEqual.
|
||
|
|
|
||
|
|
*/
|
||
|
|
struct PointComparer
|
||
|
|
{
|
||
|
|
size_t operator()(const Point &x) const
|
||
|
|
{
|
||
|
|
return ((size_t)((int)x.GetX())) ^ ((size_t)((int)x.GetY()));
|
||
|
|
}
|
||
|
|
|
||
|
|
bool operator()(const Point &x, const Point &y) const
|
||
|
|
{
|
||
|
|
return (x.GetX() == y.GetX()) && (x.GetY() == y.GetY());
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Member Variables
|
||
|
|
|
||
|
|
*/
|
||
|
|
std::unordered_set<Point, PointComparer> _overlappingPoints;
|
||
|
|
std::vector<Point> _possibleCrossings;
|
||
|
|
|
||
|
|
Points& _result;
|
||
|
|
|
||
|
|
public:
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Constructor
|
||
|
|
|
||
|
|
*/
|
||
|
|
CrossingsData(const Line& source1,
|
||
|
|
const Line& source2,
|
||
|
|
Points& result) :
|
||
|
|
HalfSegmentHalfSegmentData<Line, Line>(source1, source2),
|
||
|
|
_result(result)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Destructor
|
||
|
|
|
||
|
|
*/
|
||
|
|
~CrossingsData()
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~FirstGeometryIsRegion~
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool FirstGeometryIsRegion() const
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~SecondGeometryIsRegion~
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool SecondGeometryIsRegion() const
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~ReportIntersections~
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool ReportIntersections() const
|
||
|
|
{
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~ReportIntersection~
|
||
|
|
|
||
|
|
*/
|
||
|
|
void ReportIntersection(const Point& intersectionPoint,
|
||
|
|
const bool overlappingIntersection)
|
||
|
|
{
|
||
|
|
if (overlappingIntersection) {
|
||
|
|
_overlappingPoints.insert(intersectionPoint);
|
||
|
|
} else {
|
||
|
|
_possibleCrossings.push_back(intersectionPoint);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~OutputFinished~
|
||
|
|
|
||
|
|
*/
|
||
|
|
virtual void OutputFinished()
|
||
|
|
{
|
||
|
|
for (std::vector<Point>::const_iterator i = _possibleCrossings.begin();
|
||
|
|
i != _possibleCrossings.end(); ++i) {
|
||
|
|
if (_overlappingPoints.find (*i) == _overlappingPoints.end()) {
|
||
|
|
_result += *i;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~Crossings~
|
||
|
|
|
||
|
|
*/
|
||
|
|
static void Crossings(const Line& line1,
|
||
|
|
const Line& line2,
|
||
|
|
Points& result)
|
||
|
|
{
|
||
|
|
result.Clear();
|
||
|
|
if (!line1.IsDefined() || !line2.IsDefined()) {
|
||
|
|
result.SetDefined(false);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
result.SetDefined(true);
|
||
|
|
if (line1.IsEmpty() || line2.IsEmpty()) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// assert(line1.IsOrdered());
|
||
|
|
// assert(line2.IsOrdered());
|
||
|
|
|
||
|
|
result.StartBulkLoad();
|
||
|
|
if (line1.BoundingBox().IntersectsUD(line2.BoundingBox())) {
|
||
|
|
CrossingsData data(line1, line2, result);
|
||
|
|
BentleyOttmann bo(&data);
|
||
|
|
bo.DetermineIntersections();
|
||
|
|
}
|
||
|
|
|
||
|
|
result.EndBulkLoad(true, true); // sort and remove duplicates
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1 Data class for line minize
|
||
|
|
|
||
|
|
*/
|
||
|
|
class LineMinize : public IntersectionAlgorithmData
|
||
|
|
{
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Member Variables
|
||
|
|
|
||
|
|
*/
|
||
|
|
private:
|
||
|
|
const Line& _source;
|
||
|
|
int _currentSourceIndex;
|
||
|
|
Line& _result;
|
||
|
|
int _outputSegments;
|
||
|
|
|
||
|
|
public:
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Constructor
|
||
|
|
|
||
|
|
*/
|
||
|
|
LineMinize(const Line& src, Line& result) :
|
||
|
|
_source(src),
|
||
|
|
_currentSourceIndex(0),
|
||
|
|
_result(result),
|
||
|
|
_outputSegments(0)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Destructor
|
||
|
|
|
||
|
|
*/
|
||
|
|
~LineMinize()
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~InitializeFetch~
|
||
|
|
|
||
|
|
*/
|
||
|
|
void InitializeFetch()
|
||
|
|
{
|
||
|
|
_currentSourceIndex = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~FetchInput~
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool FetchInput(HalfSegment &segment,
|
||
|
|
Point& point,
|
||
|
|
bool &belongsToSecondGeometry)
|
||
|
|
{
|
||
|
|
point.SetDefined(false);
|
||
|
|
if (_currentSourceIndex < _source.Size()) {
|
||
|
|
_source.Get(_currentSourceIndex++, segment);
|
||
|
|
belongsToSecondGeometry = false;
|
||
|
|
return true;
|
||
|
|
} else {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~OutputData~
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool OutputData() const
|
||
|
|
{
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~OutputHalfSegment~
|
||
|
|
|
||
|
|
*/
|
||
|
|
void OutputHalfSegment(const HalfSegment& segment,
|
||
|
|
const InternalAttribute& attribute)
|
||
|
|
{
|
||
|
|
HalfSegment s1 = segment;
|
||
|
|
HalfSegment s2 = segment;
|
||
|
|
s1.SetLeftDomPoint(true);
|
||
|
|
s2.SetLeftDomPoint(false);
|
||
|
|
s1.attr.edgeno = _outputSegments;
|
||
|
|
s2.attr.edgeno = _outputSegments;
|
||
|
|
_result += s1;
|
||
|
|
_result += s2;
|
||
|
|
_outputSegments++;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~GetBoundingBox~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const Rectangle<2> GetBoundingBox()
|
||
|
|
{
|
||
|
|
return _source.BoundingBox();
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~FirstGeometryIsRegion~
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool FirstGeometryIsRegion() const
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~SecondGeometryIsRegion~
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool SecondGeometryIsRegion() const
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~IsInputOrderedByX~
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool IsInputOrderedByX() const
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~Realminize~
|
||
|
|
|
||
|
|
*/
|
||
|
|
static void Realminize(const Line& src, Line& result)
|
||
|
|
{
|
||
|
|
result.Clear();
|
||
|
|
if (!src.IsDefined()) {
|
||
|
|
result.SetDefined(false);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
result.SetDefined(true);
|
||
|
|
if (src.Size() == 0) { // empty line, nothing to realminize
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
result.StartBulkLoad();
|
||
|
|
LineMinize data(src, result);
|
||
|
|
Hobby hobby(&data);
|
||
|
|
hobby.DetermineIntersections();
|
||
|
|
// BentleyOttmann bo(&data);
|
||
|
|
// bo.DetermineIntersections();
|
||
|
|
|
||
|
|
result.StartBulkLoad(); // ordered = true
|
||
|
|
result.EndBulkLoad(true, false);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1 Data class for conversion from DLine to Line
|
||
|
|
|
||
|
|
*/
|
||
|
|
class DLineToLine : public IntersectionAlgorithmData
|
||
|
|
{
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Member Variables
|
||
|
|
|
||
|
|
*/
|
||
|
|
private:
|
||
|
|
const DLine& _source;
|
||
|
|
size_t _currentSourceIndex;
|
||
|
|
Line& _result;
|
||
|
|
int _outputSegments;
|
||
|
|
|
||
|
|
public:
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Constructor
|
||
|
|
|
||
|
|
*/
|
||
|
|
DLineToLine(const DLine& src, Line& result) :
|
||
|
|
_source(src),
|
||
|
|
_currentSourceIndex(0),
|
||
|
|
_result(result),
|
||
|
|
_outputSegments(0)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Destructor
|
||
|
|
|
||
|
|
*/
|
||
|
|
~DLineToLine()
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~InitializeFetch~
|
||
|
|
|
||
|
|
*/
|
||
|
|
void InitializeFetch()
|
||
|
|
{
|
||
|
|
_currentSourceIndex = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~FetchInput~
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool FetchInput(HalfSegment &segment,
|
||
|
|
Point &point,
|
||
|
|
bool &belongsToSecondGeometry)
|
||
|
|
{
|
||
|
|
point.SetDefined(false);
|
||
|
|
// there is no Size()-method?
|
||
|
|
while (_currentSourceIndex < _source.HashValue()) {
|
||
|
|
SimpleSegment s;
|
||
|
|
_source.get(_currentSourceIndex++, s);
|
||
|
|
Point p1 = Point(true, s.x1, s.y1);
|
||
|
|
Point p2 = Point(true, s.x2, s.y2);
|
||
|
|
if (!AlmostEqual(p1, p2)) {
|
||
|
|
segment = HalfSegment(true, p1, p2);
|
||
|
|
belongsToSecondGeometry = false;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~OutputData~
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool OutputData() const
|
||
|
|
{
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~IsInputOrderedByX~
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool IsInputOrderedByX() const
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~OutputHalfSegment~
|
||
|
|
|
||
|
|
*/
|
||
|
|
void OutputHalfSegment(const HalfSegment& segment,
|
||
|
|
const InternalAttribute& attribute)
|
||
|
|
{
|
||
|
|
// cout << "O:" << _outputSegments << "\n";
|
||
|
|
HalfSegment s1 = segment;
|
||
|
|
HalfSegment s2 = segment;
|
||
|
|
s1.SetLeftDomPoint(true);
|
||
|
|
s2.SetLeftDomPoint(false);
|
||
|
|
s1.attr.edgeno = _outputSegments;
|
||
|
|
s2.attr.edgeno = _outputSegments;
|
||
|
|
_result += s1;
|
||
|
|
_result += s2;
|
||
|
|
_outputSegments++;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~OutputPoint~
|
||
|
|
|
||
|
|
*/
|
||
|
|
void OutputPoint(const Point& poiint,
|
||
|
|
const InternalAttribute& attribute)
|
||
|
|
{
|
||
|
|
throw new std::logic_error("there shouldn't be any points to output!");
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~GetBoundingBox~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const Rectangle<2> GetBoundingBox()
|
||
|
|
{
|
||
|
|
if (_source.HashValue() == 0) {
|
||
|
|
return Rectangle<2>(false);
|
||
|
|
}
|
||
|
|
|
||
|
|
double minX = 1e300;
|
||
|
|
double maxX = -1e300;
|
||
|
|
double minY = 1e300;
|
||
|
|
double maxY = -1e300;
|
||
|
|
|
||
|
|
SimpleSegment segment;
|
||
|
|
for (size_t i = 0; i < _source.HashValue(); i++) {
|
||
|
|
_source.get(i, segment);
|
||
|
|
|
||
|
|
if (segment.x1 < minX) {
|
||
|
|
minX = segment.x1;
|
||
|
|
}
|
||
|
|
if (segment.y1 < minY) {
|
||
|
|
minY = segment.y1;
|
||
|
|
}
|
||
|
|
if (segment.x2 < minX) {
|
||
|
|
minX = segment.x2;
|
||
|
|
}
|
||
|
|
if (segment.y2 < minY) {
|
||
|
|
minY = segment.y2;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (segment.x1 > maxX) {
|
||
|
|
maxX = segment.x1;
|
||
|
|
}
|
||
|
|
if (segment.y1 > maxY) {
|
||
|
|
maxY = segment.y1;
|
||
|
|
}
|
||
|
|
if (segment.x2 > maxX) {
|
||
|
|
maxX = segment.x2;
|
||
|
|
}
|
||
|
|
if (segment.y2 > maxY) {
|
||
|
|
maxY = segment.y2;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
double minMax[] = {minX, maxX, minY, maxY};
|
||
|
|
return Rectangle<2>(true,minMax );
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~FirstGeometryIsRegion~
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool FirstGeometryIsRegion() const
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~SecondGeometryIsRegion~
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool SecondGeometryIsRegion() const
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ~ToLine~
|
||
|
|
|
||
|
|
*/
|
||
|
|
static void ToLine(const DLine& src, Line& result)
|
||
|
|
{
|
||
|
|
result.Clear();
|
||
|
|
if (!src.IsDefined()) {
|
||
|
|
result.SetDefined(false);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
result.SetDefined(true);
|
||
|
|
if (src.HashValue() == 0) { // empty line, nothing to realminize
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
result.StartBulkLoad();
|
||
|
|
DLineToLine data(src, result);
|
||
|
|
Hobby hobby(&data);
|
||
|
|
hobby.DetermineIntersections();
|
||
|
|
|
||
|
|
result.StartBulkLoad(); // ordered = true
|
||
|
|
result.EndBulkLoad(true, false);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1 Operators with strongly typed parameters
|
||
|
|
|
||
|
|
1.1 Trajectory2 operator
|
||
|
|
|
||
|
|
*/
|
||
|
|
void MPointTrajectory(MPoint* mpoint, Line& line)
|
||
|
|
{
|
||
|
|
line.Clear();
|
||
|
|
if (!mpoint->IsDefined()) {
|
||
|
|
line.SetDefined(false);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
line.SetDefined(true);
|
||
|
|
line.StartBulkLoad();
|
||
|
|
|
||
|
|
HalfSegment hs;
|
||
|
|
UPoint unit;
|
||
|
|
int edgeno = 0;
|
||
|
|
|
||
|
|
int size = mpoint->GetNoComponents();
|
||
|
|
if (size > 0)
|
||
|
|
line.Resize(size);
|
||
|
|
|
||
|
|
Point p0(false); // starting point
|
||
|
|
Point p1(false); // end point of the first unit
|
||
|
|
Point p_last(false); // last point of the connected segment
|
||
|
|
|
||
|
|
for (int i = 0; i < size; i++) {
|
||
|
|
mpoint->Get(i, unit);
|
||
|
|
|
||
|
|
if (!AlmostEqual(unit.p0, unit.p1)) {
|
||
|
|
if (!p0.IsDefined()) { // first unit
|
||
|
|
p0 = unit.p0;
|
||
|
|
p1 = unit.p1;
|
||
|
|
p_last = unit.p1;
|
||
|
|
} else { // segment already exists
|
||
|
|
if (p_last != unit.p0) { // spatial jump
|
||
|
|
hs.Set(true, p0, p_last);
|
||
|
|
hs.attr.edgeno = ++edgeno;
|
||
|
|
line += hs;
|
||
|
|
hs.SetLeftDomPoint(!hs.IsLeftDomPoint());
|
||
|
|
line += hs;
|
||
|
|
p0 = unit.p0;
|
||
|
|
p1 = unit.p1;
|
||
|
|
p_last = unit.p1;
|
||
|
|
} else { // an extension, check direction
|
||
|
|
if (!AlmostEqual(p0, unit.p1)) {
|
||
|
|
HalfSegment tmp(true, p0, unit.p1);
|
||
|
|
double dist = tmp.Distance(p1);
|
||
|
|
double dist2 = tmp.Distance(p_last);
|
||
|
|
if (AlmostEqual(dist, 0.0) && AlmostEqual(dist2, 0.0)) {
|
||
|
|
p_last = unit.p1;
|
||
|
|
} else {
|
||
|
|
hs.Set(true, p0, p_last);
|
||
|
|
hs.attr.edgeno = ++edgeno;
|
||
|
|
line += hs;
|
||
|
|
hs.SetLeftDomPoint(!hs.IsLeftDomPoint());
|
||
|
|
line += hs;
|
||
|
|
p0 = unit.p0;
|
||
|
|
p1 = unit.p1;
|
||
|
|
p_last = unit.p1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (p0.IsDefined() && p_last.IsDefined() && !AlmostEqual(p0, p_last)) {
|
||
|
|
hs.Set(true, p0, p_last);
|
||
|
|
hs.attr.edgeno = ++edgeno;
|
||
|
|
line += hs;
|
||
|
|
hs.SetLeftDomPoint(!hs.IsLeftDomPoint());
|
||
|
|
line += hs;
|
||
|
|
}
|
||
|
|
|
||
|
|
Line line2(0);
|
||
|
|
LineMinize::Realminize(line, line2);
|
||
|
|
line.CopyFrom(&line2);
|
||
|
|
line2.Destroy();
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1 Intersection2 operator
|
||
|
|
|
||
|
|
1.1.1 Points $\times$ Line $\rightarrow$ Points
|
||
|
|
|
||
|
|
*/
|
||
|
|
void IntersectionOp(const Points& points,
|
||
|
|
const Line& line,
|
||
|
|
Points& result)
|
||
|
|
{
|
||
|
|
RegionLinePointsSetOp<Line, Points>::SetOp(line,
|
||
|
|
points,
|
||
|
|
SetOpType::Intersection,
|
||
|
|
result);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Points $\times$ Region $\rightarrow$ Points
|
||
|
|
|
||
|
|
*/
|
||
|
|
void IntersectionOp(const Points& points,
|
||
|
|
const Region& region,
|
||
|
|
Points& result)
|
||
|
|
{
|
||
|
|
RegionLinePointsSetOp<Region, Points>::SetOp(region,
|
||
|
|
points,
|
||
|
|
SetOpType::Intersection,
|
||
|
|
result);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Line $\times$ Point $\rightarrow$ Points
|
||
|
|
|
||
|
|
*/
|
||
|
|
void IntersectionOp(const Line& line,
|
||
|
|
const Point& point,
|
||
|
|
Points& result)
|
||
|
|
{
|
||
|
|
RegionLinePointsSetOp<Line, Point>::SetOp(line,
|
||
|
|
point,
|
||
|
|
SetOpType::Intersection,
|
||
|
|
result);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Line $\times$ Points $\rightarrow$ Points
|
||
|
|
|
||
|
|
*/
|
||
|
|
void IntersectionOp(const Line& line,
|
||
|
|
const Points& points,
|
||
|
|
Points& result)
|
||
|
|
{
|
||
|
|
RegionLinePointsSetOp<Line, Points>::SetOp(line,
|
||
|
|
points,
|
||
|
|
SetOpType::Intersection,
|
||
|
|
result);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Line $\times$ Line $\rightarrow$ Line
|
||
|
|
|
||
|
|
*/
|
||
|
|
void IntersectionOp(const Line& line1,
|
||
|
|
const Line& line2,
|
||
|
|
Line& result)
|
||
|
|
{
|
||
|
|
LineLineSetOp::SetOp(line1,
|
||
|
|
line2,
|
||
|
|
SetOpType::Intersection,
|
||
|
|
result);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Region $\times$ Point $\rightarrow$ Points
|
||
|
|
|
||
|
|
*/
|
||
|
|
void IntersectionOp(const Region& region,
|
||
|
|
const Point& point,
|
||
|
|
Points& result)
|
||
|
|
{
|
||
|
|
RegionLinePointsSetOp<Region, Point>::SetOp(region,
|
||
|
|
point,
|
||
|
|
SetOpType::Intersection,
|
||
|
|
result);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Region $\times$ Points $\rightarrow$ Points
|
||
|
|
|
||
|
|
*/
|
||
|
|
void IntersectionOp(const Region& region,
|
||
|
|
const Points& points,
|
||
|
|
Points& result)
|
||
|
|
{
|
||
|
|
RegionLinePointsSetOp<Region, Points>::SetOp(region,
|
||
|
|
points,
|
||
|
|
SetOpType::Intersection,
|
||
|
|
result);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Region $\times$ Line $\rightarrow$ Line
|
||
|
|
|
||
|
|
*/
|
||
|
|
void IntersectionOp(const Region& region,
|
||
|
|
const Line& line,
|
||
|
|
Line& result)
|
||
|
|
{
|
||
|
|
RegionLineSetOp::SetOp(region,
|
||
|
|
line,
|
||
|
|
SetOpType::Intersection,
|
||
|
|
result);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Region $\times$ Region $\rightarrow$ Region
|
||
|
|
|
||
|
|
*/
|
||
|
|
void IntersectionOp(const Region& region1,
|
||
|
|
const Region& region2,
|
||
|
|
Region& result)
|
||
|
|
{
|
||
|
|
RegionRegionSetOp::SetOp(region1,
|
||
|
|
region2,
|
||
|
|
SetOpType::Intersection,
|
||
|
|
result);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1 Union2 operator
|
||
|
|
|
||
|
|
1.1.1 Line $\times$ Line $\rightarrow$ Line
|
||
|
|
|
||
|
|
*/
|
||
|
|
void UnionOp(const Line& line1,
|
||
|
|
const Line& line2,
|
||
|
|
Line& result)
|
||
|
|
{
|
||
|
|
LineLineSetOp::SetOp(line1,
|
||
|
|
line2,
|
||
|
|
SetOpType::Union,
|
||
|
|
result);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Region $\times$ Region $\rightarrow$ Region
|
||
|
|
|
||
|
|
*/
|
||
|
|
void UnionOp(const Region& region1,
|
||
|
|
const Region& region2,
|
||
|
|
Region& result)
|
||
|
|
{
|
||
|
|
RegionRegionSetOp::SetOp(region1,
|
||
|
|
region2,
|
||
|
|
SetOpType::Union,
|
||
|
|
result);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1 Minus2 operator
|
||
|
|
|
||
|
|
1.1.1 Point $\times$ Line $\rightarrow$ Points
|
||
|
|
|
||
|
|
*/
|
||
|
|
void MinusOp(const Point& point,
|
||
|
|
const Line& line,
|
||
|
|
Points& result)
|
||
|
|
{
|
||
|
|
RegionLinePointsSetOp<Line, Point>::SetOp(line,
|
||
|
|
point,
|
||
|
|
SetOpType::Minus,
|
||
|
|
result);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Point $\times$ Region $\rightarrow$ Points
|
||
|
|
|
||
|
|
*/
|
||
|
|
void MinusOp(const Point& point,
|
||
|
|
const Region& region,
|
||
|
|
Points& result)
|
||
|
|
{
|
||
|
|
RegionLinePointsSetOp<Region, Point>::SetOp(region,
|
||
|
|
point,
|
||
|
|
SetOpType::Minus,
|
||
|
|
result);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Points $\times$ Line $\rightarrow$ Points
|
||
|
|
|
||
|
|
*/
|
||
|
|
void MinusOp(const Points& points,
|
||
|
|
const Line& line,
|
||
|
|
Points& result)
|
||
|
|
{
|
||
|
|
RegionLinePointsSetOp<Line, Points>::SetOp(line,
|
||
|
|
points,
|
||
|
|
SetOpType::Minus,
|
||
|
|
result);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Points $\times$ Region $\rightarrow$ Points
|
||
|
|
|
||
|
|
*/
|
||
|
|
void MinusOp(const Points& points,
|
||
|
|
const Region& region,
|
||
|
|
Points& result)
|
||
|
|
{
|
||
|
|
RegionLinePointsSetOp<Region, Points>::SetOp(region,
|
||
|
|
points,
|
||
|
|
SetOpType::Minus,
|
||
|
|
result);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Line $\times$ Line $\rightarrow$ Line
|
||
|
|
|
||
|
|
*/
|
||
|
|
void MinusOp(const Line& line1,
|
||
|
|
const Line& line2,
|
||
|
|
Line& result)
|
||
|
|
{
|
||
|
|
LineLineSetOp::SetOp(line1,
|
||
|
|
line2,
|
||
|
|
SetOpType::Minus,
|
||
|
|
result);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Line $\times$ Region $\rightarrow$ Line
|
||
|
|
|
||
|
|
*/
|
||
|
|
void MinusOp(const Line& line,
|
||
|
|
const Region& region,
|
||
|
|
Line& result)
|
||
|
|
{
|
||
|
|
RegionLineSetOp::SetOp(region,
|
||
|
|
line,
|
||
|
|
SetOpType::Minus,
|
||
|
|
result);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Region $\times$ Region $\rightarrow$ Region
|
||
|
|
|
||
|
|
*/
|
||
|
|
void MinusOp(const Region& region1,
|
||
|
|
const Region& region2,
|
||
|
|
Region& result)
|
||
|
|
{
|
||
|
|
RegionRegionSetOp::SetOp(region1,
|
||
|
|
region2,
|
||
|
|
SetOpType::Minus,
|
||
|
|
result);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1 Intersects2 operator
|
||
|
|
|
||
|
|
1.1.1 Points $\times$ Line
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool IntersectsOp(const Points& points,
|
||
|
|
const Line& line)
|
||
|
|
{
|
||
|
|
return
|
||
|
|
RegionLinePointsIntersects<Line, Points>::Intersects(line, points);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Points $\times$ Region
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool IntersectsOp(const Points& points,
|
||
|
|
const Region& region)
|
||
|
|
{
|
||
|
|
return
|
||
|
|
RegionLinePointsIntersects<Region, Points>::Intersects(region, points);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Line $\times$ Line
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool IntersectsOp(const Line& line1,
|
||
|
|
const Line& line2)
|
||
|
|
{
|
||
|
|
return RegionLineIntersects<Line, Line>::Intersects(line1, line2);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Line $\times$ Region
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool IntersectsOp(const Line& line,
|
||
|
|
const Region& region)
|
||
|
|
{
|
||
|
|
return RegionLineIntersects<Line, Region>::Intersects(line, region);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Region $\times$ Region
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool IntersectsOp(const Region& region1,
|
||
|
|
const Region& region2)
|
||
|
|
{
|
||
|
|
return RegionLineIntersects<Region, Region>::Intersects(region1, region2);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1 Crossings2 operator
|
||
|
|
|
||
|
|
*/
|
||
|
|
void CrossingsLine(const Line& line1,
|
||
|
|
const Line& line2,
|
||
|
|
Points& result)
|
||
|
|
{
|
||
|
|
CrossingsData::Crossings(line1,
|
||
|
|
line2,
|
||
|
|
result);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1 ToLine operator
|
||
|
|
|
||
|
|
*/
|
||
|
|
void ToLine(const DLine& dline,
|
||
|
|
Line& result)
|
||
|
|
{
|
||
|
|
DLineToLine::ToLine(dline, result);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1 Helpers
|
||
|
|
|
||
|
|
1.1 ~SpatialReturnFirstParameter~
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class T1, class T2, class TResult>
|
||
|
|
int SpatialReturnFirstParameter(Word* args,
|
||
|
|
Word& result,
|
||
|
|
int message,
|
||
|
|
Word& local,
|
||
|
|
Supplier s)
|
||
|
|
{
|
||
|
|
result = qp->ResultStorage(s);
|
||
|
|
|
||
|
|
T1* arg1 = static_cast<T1*>(args[0].addr);
|
||
|
|
T2* arg2 = static_cast<T2*>(args[1].addr);
|
||
|
|
TResult* res = static_cast<TResult*>(result.addr);
|
||
|
|
|
||
|
|
res->Clear();
|
||
|
|
if (!arg1->IsDefined() || !arg2->IsDefined()) {
|
||
|
|
res->SetDefined(false);
|
||
|
|
} else {
|
||
|
|
res->SetDefined(true);
|
||
|
|
res->CopyFrom(arg1);
|
||
|
|
}
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1 ~SpatialReturnSecondParameter~
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class T1, class T2, class TResult>
|
||
|
|
int SpatialReturnSecondParameter(Word* args,
|
||
|
|
Word& result,
|
||
|
|
int message,
|
||
|
|
Word& local,
|
||
|
|
Supplier s)
|
||
|
|
{
|
||
|
|
result = qp->ResultStorage(s);
|
||
|
|
|
||
|
|
T1* arg1 = static_cast<T1*>(args[0].addr);
|
||
|
|
T2* arg2 = static_cast<T2*>(args[1].addr);
|
||
|
|
TResult* res = static_cast<TResult*>(result.addr);
|
||
|
|
|
||
|
|
res->Clear();
|
||
|
|
if (!arg1->IsDefined() || !arg2->IsDefined()) {
|
||
|
|
res->SetDefined(false);
|
||
|
|
} else {
|
||
|
|
res->SetDefined(true);
|
||
|
|
res->CopyFrom(arg2);
|
||
|
|
}
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1 Helper template to determine the size of an object
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class T>
|
||
|
|
struct SizeHelper
|
||
|
|
{
|
||
|
|
static int Size(const T* obj)
|
||
|
|
{
|
||
|
|
return obj->Size();
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1 Template specialization to determine the size of an point (always 1)
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<>
|
||
|
|
struct SizeHelper<Point>
|
||
|
|
{
|
||
|
|
static int Size(const Point* obj)
|
||
|
|
{
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1 Operator with Secondo parameters
|
||
|
|
|
||
|
|
1.1 Trajectory2
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
int MPointTrajectory(Word* args,
|
||
|
|
Word& result,
|
||
|
|
int message,
|
||
|
|
Word& local,
|
||
|
|
Supplier s)
|
||
|
|
{
|
||
|
|
result = qp->ResultStorage(s);
|
||
|
|
|
||
|
|
Line *line = ((Line*)result.addr);
|
||
|
|
MPoint *mpoint = ((MPoint*)args[0].addr);
|
||
|
|
|
||
|
|
MPointTrajectory(mpoint, *line);
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1 Intersection2
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class T1, class T2, class TResult, bool reverseT1T2>
|
||
|
|
int SpatialIntersectionGeneric(Word* args,
|
||
|
|
Word& result,
|
||
|
|
int message,
|
||
|
|
Word& local,
|
||
|
|
Supplier s)
|
||
|
|
{
|
||
|
|
result = qp->ResultStorage(s);
|
||
|
|
|
||
|
|
T1* arg1;
|
||
|
|
T2* arg2;
|
||
|
|
|
||
|
|
if (!reverseT1T2) {
|
||
|
|
arg1 = static_cast<T1*>(args[0].addr);
|
||
|
|
arg2 = static_cast<T2*>(args[1].addr);
|
||
|
|
} else {
|
||
|
|
arg1 = static_cast<T1*>(args[1].addr);
|
||
|
|
arg2 = static_cast<T2*>(args[0].addr);
|
||
|
|
}
|
||
|
|
TResult* res = static_cast<TResult*>(result.addr);
|
||
|
|
|
||
|
|
res->Clear();
|
||
|
|
if (!arg1->IsDefined() || !arg2->IsDefined()) {
|
||
|
|
res->SetDefined(false);
|
||
|
|
} else {
|
||
|
|
res->SetDefined(true);
|
||
|
|
if (SizeHelper<T1>::Size(arg1) == 0 || SizeHelper<T2>::Size(arg2) == 0
|
||
|
|
|| !(arg1->BoundingBox().IntersectsUD(arg2->BoundingBox()))) {
|
||
|
|
// empty result
|
||
|
|
// Clear doesn't clear everything?
|
||
|
|
res->StartBulkLoad();
|
||
|
|
res->EndBulkLoad();
|
||
|
|
} else {
|
||
|
|
IntersectionOp(*arg1, *arg2, *res);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1 Minus2
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class T1, class T2, class TResult>
|
||
|
|
int SpatialMinusGeneric(Word* args,
|
||
|
|
Word& result,
|
||
|
|
int message,
|
||
|
|
Word& local,
|
||
|
|
Supplier s)
|
||
|
|
{
|
||
|
|
result = qp->ResultStorage(s);
|
||
|
|
T1* arg1 = static_cast<T1*>(args[0].addr);
|
||
|
|
T2* arg2 = static_cast<T2*>(args[1].addr);
|
||
|
|
TResult* res = static_cast<TResult*>(result.addr);
|
||
|
|
|
||
|
|
res->Clear();
|
||
|
|
if (!arg1->IsDefined() || !arg2->IsDefined()) {
|
||
|
|
res->SetDefined(false);
|
||
|
|
} else {
|
||
|
|
res->SetDefined(true);
|
||
|
|
if (SizeHelper<T1>::Size(arg1) == 0) {
|
||
|
|
// empty result;
|
||
|
|
// Clear doesn't clear everything?
|
||
|
|
res->StartBulkLoad();
|
||
|
|
res->EndBulkLoad();
|
||
|
|
} else if (std::is_same<T1, TResult>::value
|
||
|
|
&& (SizeHelper<T2>::Size(arg2) == 0 ||
|
||
|
|
!(arg1->BoundingBox().IntersectsUD(arg2->BoundingBox())))) {
|
||
|
|
res->CopyFrom(arg1);
|
||
|
|
} else {
|
||
|
|
MinusOp(*arg1, *arg2, *res);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1 Union2
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
template<class T1, class T2, class TResult>
|
||
|
|
int robustUnionT(T1* arg1, T2*arg2, TResult* res){
|
||
|
|
res->Clear();
|
||
|
|
if (!arg1->IsDefined() || !arg2->IsDefined()) {
|
||
|
|
res->SetDefined(false);
|
||
|
|
} else {
|
||
|
|
res->SetDefined(true);
|
||
|
|
if (std::is_same<T2, TResult>::value && SizeHelper<T1>::Size(arg1) == 0) {
|
||
|
|
res->CopyFrom(arg2);
|
||
|
|
} else if (std::is_same<T1, TResult>::value
|
||
|
|
&& SizeHelper<T2>::Size(arg2) == 0) {
|
||
|
|
res->CopyFrom(arg1);
|
||
|
|
} else if (!(arg1->BoundingBox().IntersectsUD(arg2->BoundingBox()))) {
|
||
|
|
res->StartBulkLoad();
|
||
|
|
int edgeno = 0;
|
||
|
|
int s = arg1->Size();
|
||
|
|
HalfSegment hs;
|
||
|
|
for (int i = 0; i < s; i++) {
|
||
|
|
arg1->Get(i, hs);
|
||
|
|
if (hs.IsLeftDomPoint()) {
|
||
|
|
HalfSegment HS(hs);
|
||
|
|
HS.attr.edgeno = edgeno;
|
||
|
|
(*res) += HS;
|
||
|
|
HS.SetLeftDomPoint(false);
|
||
|
|
(*res) += HS;
|
||
|
|
edgeno++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
s = arg2->Size();
|
||
|
|
for (int i = 0; i < s; i++) {
|
||
|
|
arg2->Get(i, hs);
|
||
|
|
if (hs.IsLeftDomPoint()) {
|
||
|
|
HalfSegment HS(hs);
|
||
|
|
HS.attr.edgeno = edgeno;
|
||
|
|
(*res) += HS;
|
||
|
|
HS.SetLeftDomPoint(false);
|
||
|
|
(*res) += HS;
|
||
|
|
edgeno++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (std::is_same<TResult, Region>::value) {
|
||
|
|
res->EndBulkLoad();
|
||
|
|
} else {
|
||
|
|
res->EndBulkLoad(true, false);
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
UnionOp(*arg1, *arg2, *res);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
template<class T1, class T2, class TResult>
|
||
|
|
int SpatialUnionGeneric(
|
||
|
|
Word* args,
|
||
|
|
Word& result,
|
||
|
|
int message,
|
||
|
|
Word& local,
|
||
|
|
Supplier s)
|
||
|
|
{
|
||
|
|
result = qp->ResultStorage(s);
|
||
|
|
T1* arg1 = static_cast<T1*>(args[0].addr);
|
||
|
|
T2* arg2 = static_cast<T2*>(args[1].addr);
|
||
|
|
TResult* res = static_cast<TResult*>(result.addr);
|
||
|
|
return robustUnionT<T1,T2,TResult>(arg1,arg2,res);
|
||
|
|
}
|
||
|
|
|
||
|
|
void robustUnion(Region& arg1, Region& arg2, Region& result){
|
||
|
|
robustUnionT<Region,Region,Region>(&arg1,&arg2,&result);
|
||
|
|
}
|
||
|
|
|
||
|
|
void robustUnion(Line& arg1, Line& arg2, Line& result){
|
||
|
|
robustUnionT<Line,Line,Line>(&arg1,&arg2,&result);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1 Crossings2
|
||
|
|
|
||
|
|
*/
|
||
|
|
int CrossingsLine(Word* args,
|
||
|
|
Word& result,
|
||
|
|
int message,
|
||
|
|
Word& local,
|
||
|
|
Supplier s)
|
||
|
|
{
|
||
|
|
result = qp->ResultStorage(s);
|
||
|
|
Line* arg1 = static_cast<Line*>(args[0].addr);
|
||
|
|
Line* arg2 = static_cast<Line*>(args[1].addr);
|
||
|
|
Points* res = static_cast<Points*>(result.addr);
|
||
|
|
CrossingsLine(*arg1, *arg2, *res);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1 ToLine
|
||
|
|
|
||
|
|
*/
|
||
|
|
int ToLine(Word* args,
|
||
|
|
Word& result,
|
||
|
|
int message,
|
||
|
|
Word& local,
|
||
|
|
Supplier s)
|
||
|
|
{
|
||
|
|
result = qp->ResultStorage(s);
|
||
|
|
DLine* arg1 = static_cast<DLine*>(args[0].addr);
|
||
|
|
Line* res = static_cast<Line*>(result.addr);
|
||
|
|
ToLine(*arg1, *res);
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1 Intersects2
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class A, class B, bool symm>
|
||
|
|
int SpatialIntersectsVM(Word* args, Word& result, int message,
|
||
|
|
Word& local,
|
||
|
|
Supplier s)
|
||
|
|
{
|
||
|
|
result = qp->ResultStorage(s);
|
||
|
|
CcBool* res = static_cast<CcBool*>(result.addr);
|
||
|
|
A* a;
|
||
|
|
B* b;
|
||
|
|
if (symm) {
|
||
|
|
a = static_cast<A*>(args[1].addr);
|
||
|
|
b = static_cast<B*>(args[0].addr);
|
||
|
|
} else {
|
||
|
|
a = static_cast<A*>(args[0].addr);
|
||
|
|
b = static_cast<B*>(args[1].addr);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!a->IsDefined() || !b->IsDefined()) {
|
||
|
|
res->Set(false, false);
|
||
|
|
} else if (!(a->BoundingBox().IntersectsUD(b->BoundingBox()))) {
|
||
|
|
res->Set(true, false);
|
||
|
|
} else {
|
||
|
|
bool result = IntersectsOp(*a, *b);
|
||
|
|
res->Set(true, result);
|
||
|
|
}
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1 Operator definitions
|
||
|
|
|
||
|
|
1.1 Signatures
|
||
|
|
|
||
|
|
1.1.1 Trajectory2
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string TemporalSpecTrajectory =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
||
|
|
"( <text>mpoint -> line</text--->"
|
||
|
|
"<text> trajectory2( _ )</text--->"
|
||
|
|
"<text>Get the trajectory of the corresponding"
|
||
|
|
" moving point object.</text--->"
|
||
|
|
"<text>trajectory2( mp1 )</text--->"
|
||
|
|
") )";
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ToLine
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string ToLineSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
||
|
|
"( <text>dline -> line</text--->"
|
||
|
|
"<text>toline( _ )</text--->"
|
||
|
|
"<text>Converts a dline into a line</text--->"
|
||
|
|
"<text>toline( dline )</text--->"
|
||
|
|
") )";
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Intersection2
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string SpatialIntersectionSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
||
|
|
"( <text>{point, points, line, region } x"
|
||
|
|
" {point, points, line, region} -> T, "
|
||
|
|
" where T = points if any point or point type is one of the "
|
||
|
|
" arguments or the argument having the smaller dimension </text--->"
|
||
|
|
"<text>intersection2(arg1, arg2)</text--->"
|
||
|
|
"<text>intersection of two spatial objects</text--->"
|
||
|
|
"<text>query intersection2(tiergarten, thecenter) </text--->"
|
||
|
|
") )";
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Minus2
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string SpatialMinusSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
||
|
|
"( <text>{point, points, line, region } x"
|
||
|
|
" {point, points, line, sline region} -> T "
|
||
|
|
" </text--->"
|
||
|
|
"<text>arg1 minus2 arg2</text--->"
|
||
|
|
"<text>difference of two spatial objects</text--->"
|
||
|
|
"<text>query tiergarten minus2 thecenter </text--->"
|
||
|
|
") )";
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Union2
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string SpatialUnionSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
||
|
|
"( <text>{point , points, line, region } x"
|
||
|
|
" {point, points, line, region} -> T "
|
||
|
|
" </text--->"
|
||
|
|
"<text>arg1 union2 arg2</text--->"
|
||
|
|
"<text>union of two spatial objects</text--->"
|
||
|
|
"<text>query tiergarten union2 thecenter </text--->"
|
||
|
|
") )";
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Crossings2
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string SpatialSpecCrossings =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
||
|
|
"( <text>(line x line) -> points</text--->"
|
||
|
|
"<text>crossings2( _, _ )</text--->"
|
||
|
|
"<text>crossing points of two lines.</text--->"
|
||
|
|
"<text>query crossings2(line1, line2)</text--->"
|
||
|
|
") )";
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Intersects2
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string SpatialSpecIntersects =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )"
|
||
|
|
"( <text>(points||line||region x points||line||region) -> bool"
|
||
|
|
" </text--->"
|
||
|
|
"<text>_ intersects2 _</text--->"
|
||
|
|
"<text>TRUE, iff both arguments intersect.</text--->"
|
||
|
|
"<text>query region1 intersects2 region2</text--->"
|
||
|
|
") )";
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1 Value Mapping
|
||
|
|
|
||
|
|
1.1.1 Intersection2
|
||
|
|
|
||
|
|
*/
|
||
|
|
ValueMapping spatialintersectionVM[] = {
|
||
|
|
SpatialIntersectionGeneric<Line, Point, Points, true>,
|
||
|
|
SpatialIntersectionGeneric<Region, Point, Points, true>,
|
||
|
|
|
||
|
|
SpatialIntersectionGeneric<Points, Line, Points, false>,
|
||
|
|
SpatialIntersectionGeneric<Points, Region, Points, false>,
|
||
|
|
|
||
|
|
SpatialIntersectionGeneric<Line, Point, Points, false>,
|
||
|
|
SpatialIntersectionGeneric<Line, Points, Points, false>,
|
||
|
|
SpatialIntersectionGeneric<Line, Line, Line, false>,
|
||
|
|
SpatialIntersectionGeneric<Region, Line, Line, true>,
|
||
|
|
|
||
|
|
SpatialIntersectionGeneric<Region, Point, Points, false>,
|
||
|
|
SpatialIntersectionGeneric<Region, Points, Points, false>,
|
||
|
|
SpatialIntersectionGeneric<Region, Line, Line, false>,
|
||
|
|
SpatialIntersectionGeneric<Region, Region, Region, false>
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Minus2
|
||
|
|
|
||
|
|
*/
|
||
|
|
ValueMapping spatialminusVM[] = {
|
||
|
|
SpatialMinusGeneric<Point, Line, Points>,
|
||
|
|
SpatialMinusGeneric<Point, Region, Points>,
|
||
|
|
|
||
|
|
SpatialMinusGeneric<Points, Line, Points>,
|
||
|
|
SpatialMinusGeneric<Points, Region, Points>,
|
||
|
|
|
||
|
|
SpatialReturnFirstParameter<Line, Point, Line>,
|
||
|
|
SpatialReturnFirstParameter<Line, Points, Line>,
|
||
|
|
SpatialMinusGeneric<Line, Line, Line>,
|
||
|
|
SpatialMinusGeneric<Line, Region, Line>,
|
||
|
|
|
||
|
|
SpatialReturnFirstParameter<Region, Point, Region>,
|
||
|
|
SpatialReturnFirstParameter<Region, Points, Region>,
|
||
|
|
SpatialReturnFirstParameter<Region, Line, Region>,
|
||
|
|
SpatialMinusGeneric<Region, Region, Region>
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Union2
|
||
|
|
|
||
|
|
*/
|
||
|
|
ValueMapping spatialunionVM[] = {
|
||
|
|
SpatialReturnSecondParameter<Point, Line, Line>,
|
||
|
|
SpatialReturnSecondParameter<Point, Region, Region>,
|
||
|
|
|
||
|
|
SpatialReturnSecondParameter<Points, Line, Line>,
|
||
|
|
SpatialReturnSecondParameter<Points, Region, Region>,
|
||
|
|
|
||
|
|
SpatialReturnFirstParameter<Line, Point, Line>,
|
||
|
|
SpatialReturnFirstParameter<Line, Points, Line>,
|
||
|
|
SpatialUnionGeneric<Line, Line, Line>,
|
||
|
|
SpatialReturnSecondParameter<Line, Region, Region>,
|
||
|
|
|
||
|
|
SpatialReturnFirstParameter<Region, Point, Region>,
|
||
|
|
SpatialReturnFirstParameter<Region, Points, Region>,
|
||
|
|
SpatialReturnFirstParameter<Region, Line, Region>,
|
||
|
|
SpatialUnionGeneric<Region, Region, Region>
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Intersects
|
||
|
|
|
||
|
|
*/
|
||
|
|
ValueMapping spatialintersectsmap[] = {
|
||
|
|
SpatialIntersectsVM<Points, Line, false>,
|
||
|
|
SpatialIntersectsVM<Points, Region, false>,
|
||
|
|
SpatialIntersectsVM<Points, Line, true>,
|
||
|
|
SpatialIntersectsVM<Line, Line, false>,
|
||
|
|
SpatialIntersectsVM<Line, Region, false>,
|
||
|
|
SpatialIntersectsVM<Points, Region, true>,
|
||
|
|
SpatialIntersectsVM<Line, Region, true>,
|
||
|
|
SpatialIntersectsVM<Region, Region, false>
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1 Selection methods
|
||
|
|
|
||
|
|
1.1.1 SpatialSetOpSelect
|
||
|
|
|
||
|
|
used for set operations
|
||
|
|
|
||
|
|
*/
|
||
|
|
int SpatialSetOpSelect(ListExpr args)
|
||
|
|
{
|
||
|
|
string a1 = nl->SymbolValue(nl->First(args));
|
||
|
|
string a2 = nl->SymbolValue(nl->Second(args));
|
||
|
|
|
||
|
|
if (a1 == Point::BasicType()) {
|
||
|
|
if (a2 == Line::BasicType()) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a2 == Region::BasicType()) {
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a1 == Points::BasicType()) {
|
||
|
|
if (a2 == Line::BasicType()) {
|
||
|
|
return 2;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a2 == Region::BasicType()) {
|
||
|
|
return 3;
|
||
|
|
}
|
||
|
|
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a1 == Line::BasicType()) {
|
||
|
|
if (a2 == Point::BasicType()) {
|
||
|
|
return 4;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a2 == Points::BasicType()) {
|
||
|
|
return 5;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a2 == Line::BasicType()) {
|
||
|
|
return 6;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a2 == Region::BasicType()) {
|
||
|
|
return 7;
|
||
|
|
}
|
||
|
|
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a1 == Region::BasicType()) {
|
||
|
|
if (a2 == Point::BasicType()) {
|
||
|
|
return 8;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a2 == Points::BasicType()) {
|
||
|
|
return 9;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a2 == Line::BasicType()) {
|
||
|
|
return 10;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a2 == Region::BasicType()) {
|
||
|
|
return 11;
|
||
|
|
}
|
||
|
|
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
enum SpatialType
|
||
|
|
{
|
||
|
|
stpoint,
|
||
|
|
stpoints,
|
||
|
|
stline,
|
||
|
|
stregion,
|
||
|
|
stbox,
|
||
|
|
sterror,
|
||
|
|
stsline
|
||
|
|
};
|
||
|
|
|
||
|
|
SpatialType SpatialTypeOfSymbol(ListExpr symbol)
|
||
|
|
{
|
||
|
|
if (nl->AtomType(symbol) == SymbolType) {
|
||
|
|
string s = nl->SymbolValue(symbol);
|
||
|
|
if (s == Point::BasicType()) {
|
||
|
|
return (stpoint);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (s == Points::BasicType()) {
|
||
|
|
return (stpoints);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (s == Line::BasicType()) {
|
||
|
|
return (stline);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (s == Region::BasicType()) {
|
||
|
|
return (stregion);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (s == Rectangle<2>::BasicType()) {
|
||
|
|
return (stbox);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (s == SimpleLine::BasicType()) {
|
||
|
|
return (stsline);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return (sterror);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 SpatialSelectIntersects
|
||
|
|
|
||
|
|
used for intersects2 operator
|
||
|
|
|
||
|
|
*/
|
||
|
|
int SpatialSelectIntersects(ListExpr args)
|
||
|
|
{
|
||
|
|
ListExpr arg1 = nl->First(args);
|
||
|
|
ListExpr arg2 = nl->Second(args);
|
||
|
|
|
||
|
|
if (SpatialTypeOfSymbol(arg1) == stpoints
|
||
|
|
&& SpatialTypeOfSymbol(arg2) == stline) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (SpatialTypeOfSymbol(arg1) == stpoints
|
||
|
|
&& SpatialTypeOfSymbol(arg2) == stregion) {
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (SpatialTypeOfSymbol(arg1) == stline
|
||
|
|
&& SpatialTypeOfSymbol(arg2) == stpoints) {
|
||
|
|
return 2;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (SpatialTypeOfSymbol(arg1) == stline
|
||
|
|
&& SpatialTypeOfSymbol(arg2) == stline) {
|
||
|
|
return 3;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (SpatialTypeOfSymbol(arg1) == stline
|
||
|
|
&& SpatialTypeOfSymbol(arg2) == stregion) {
|
||
|
|
return 4;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (SpatialTypeOfSymbol(arg1) == stregion
|
||
|
|
&& SpatialTypeOfSymbol(arg2) == stpoints) {
|
||
|
|
return 5;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (SpatialTypeOfSymbol(arg1) == stregion
|
||
|
|
&& SpatialTypeOfSymbol(arg2) == stline) {
|
||
|
|
return 6;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (SpatialTypeOfSymbol(arg1) == stregion
|
||
|
|
&& SpatialTypeOfSymbol(arg2) == stregion) {
|
||
|
|
return 7;
|
||
|
|
}
|
||
|
|
|
||
|
|
return -1; // This point should never be reached
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1 Type mapping
|
||
|
|
|
||
|
|
1.1.1 Trajectory2
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr MovingTypeMapSpatial(ListExpr args)
|
||
|
|
{
|
||
|
|
if (nl->ListLength(args) == 1) {
|
||
|
|
ListExpr arg1 = nl->First(args);
|
||
|
|
|
||
|
|
if (nl->IsEqual(arg1, MPoint::BasicType())) {
|
||
|
|
return nl->SymbolAtom(Line::BasicType());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 ToLine
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr ToLineTypeMap(ListExpr args)
|
||
|
|
{
|
||
|
|
if (nl->ListLength(args) == 1) {
|
||
|
|
ListExpr arg1 = nl->First(args);
|
||
|
|
|
||
|
|
if (nl->IsEqual(arg1, DLine::BasicType())) {
|
||
|
|
return nl->SymbolAtom(Line::BasicType());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Union2
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr SpatialUnionTypeMap(ListExpr args)
|
||
|
|
{
|
||
|
|
if (nl->ListLength(args) != 2) {
|
||
|
|
return listutils::typeError("wrong number of arguments");
|
||
|
|
}
|
||
|
|
|
||
|
|
ListExpr arg1 = nl->First(args);
|
||
|
|
ListExpr arg2 = nl->Second(args);
|
||
|
|
if (!listutils::isSymbol(arg1)) {
|
||
|
|
return listutils::typeError("first arg is not a supported spatial type");
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!listutils::isSymbol(arg2)) {
|
||
|
|
return listutils::typeError("second arg is not a supported spatial type");
|
||
|
|
}
|
||
|
|
|
||
|
|
string a1 = nl->SymbolValue(arg1);
|
||
|
|
string a2 = nl->SymbolValue(arg2);
|
||
|
|
|
||
|
|
if (a1 == Point::BasicType()) {
|
||
|
|
if (a2 == Line::BasicType()) {
|
||
|
|
return nl->SymbolAtom(Line::BasicType());
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a2 == Region::BasicType()) {
|
||
|
|
return nl->SymbolAtom(Region::BasicType());
|
||
|
|
}
|
||
|
|
|
||
|
|
return listutils::typeError("second arg is not a supported spatial type");
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a1 == Points::BasicType()) {
|
||
|
|
if (a2 == Line::BasicType()) {
|
||
|
|
return nl->SymbolAtom(Line::BasicType());
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a2 == Region::BasicType()) {
|
||
|
|
return nl->SymbolAtom(Region::BasicType());
|
||
|
|
}
|
||
|
|
|
||
|
|
return listutils::typeError("second arg is not a supported spatial type");
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a1 == Line::BasicType()) {
|
||
|
|
if (a2 == Point::BasicType()) {
|
||
|
|
return nl->SymbolAtom(Line::BasicType());
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a2 == Points::BasicType()) {
|
||
|
|
return nl->SymbolAtom(Line::BasicType());
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a2 == Line::BasicType()) {
|
||
|
|
return nl->SymbolAtom(Line::BasicType());
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a2 == Region::BasicType()) {
|
||
|
|
return nl->SymbolAtom(Region::BasicType());
|
||
|
|
}
|
||
|
|
|
||
|
|
return listutils::typeError("second arg is not a supported spatial type");
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a1 == Region::BasicType()) {
|
||
|
|
if (a2 == Point::BasicType()) {
|
||
|
|
return nl->SymbolAtom(Region::BasicType());
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a2 == Points::BasicType()) {
|
||
|
|
return nl->SymbolAtom(Region::BasicType());
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a2 == Line::BasicType()) {
|
||
|
|
return nl->SymbolAtom(Region::BasicType());
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a2 == Region::BasicType()) {
|
||
|
|
return nl->SymbolAtom(Region::BasicType());
|
||
|
|
}
|
||
|
|
|
||
|
|
return listutils::typeError("second arg is not a supported spatial type");
|
||
|
|
}
|
||
|
|
|
||
|
|
return listutils::typeError("first arg is not a supported spatial type");
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Crossings2
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr SpatialCrossingsTM(ListExpr args)
|
||
|
|
{
|
||
|
|
ListExpr arg1, arg2;
|
||
|
|
if (nl->ListLength(args) == 2) {
|
||
|
|
arg1 = nl->First(args);
|
||
|
|
arg2 = nl->Second(args);
|
||
|
|
|
||
|
|
string a1 = nl->SymbolValue(arg1);
|
||
|
|
string a2 = nl->SymbolValue(arg2);
|
||
|
|
|
||
|
|
if (a1 == Line::BasicType() && a2 == Line::BasicType()) {
|
||
|
|
return nl->SymbolAtom(Points::BasicType());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return listutils::typeError("line x line expected");
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Minus2
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr SpatialMinusTypeMap(ListExpr args)
|
||
|
|
{
|
||
|
|
if (nl->ListLength(args) != 2) {
|
||
|
|
return listutils::typeError("wrong number of arguments");
|
||
|
|
}
|
||
|
|
|
||
|
|
ListExpr arg1 = nl->First(args);
|
||
|
|
ListExpr arg2 = nl->Second(args);
|
||
|
|
if (!listutils::isSymbol(arg1)) {
|
||
|
|
return listutils::typeError("first arg is not a supported spatial type");
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!listutils::isSymbol(arg2)) {
|
||
|
|
return listutils::typeError("second arg is not a supported spatial type");
|
||
|
|
}
|
||
|
|
|
||
|
|
string a1 = nl->SymbolValue(arg1);
|
||
|
|
string a2 = nl->SymbolValue(arg2);
|
||
|
|
|
||
|
|
if (a1 == Point::BasicType()) {
|
||
|
|
if (a2 == Line::BasicType()) {
|
||
|
|
return nl->SymbolAtom(Points::BasicType());
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a2 == Region::BasicType()) {
|
||
|
|
return nl->SymbolAtom(Points::BasicType());
|
||
|
|
}
|
||
|
|
|
||
|
|
return listutils::typeError("second arg is not a supported spatial type");
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a1 == Points::BasicType()) {
|
||
|
|
if (a2 == Line::BasicType()) {
|
||
|
|
return nl->SymbolAtom(Points::BasicType());
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a2 == Region::BasicType()) {
|
||
|
|
return nl->SymbolAtom(Points::BasicType());
|
||
|
|
}
|
||
|
|
return listutils::typeError("second arg is not a supported spatial type");
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a1 == Line::BasicType()) {
|
||
|
|
if (a2 == Point::BasicType()) {
|
||
|
|
return nl->SymbolAtom(Line::BasicType());
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a2 == Points::BasicType()) {
|
||
|
|
return nl->SymbolAtom(Line::BasicType());
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a2 == Line::BasicType()) {
|
||
|
|
return nl->SymbolAtom(Line::BasicType());
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a2 == Region::BasicType()) {
|
||
|
|
return nl->SymbolAtom(Line::BasicType());
|
||
|
|
}
|
||
|
|
|
||
|
|
return listutils::typeError("second arg is not a supported spatial type");
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a1 == Region::BasicType()) {
|
||
|
|
if (a2 == Point::BasicType()) {
|
||
|
|
return nl->SymbolAtom(Region::BasicType());
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a2 == Points::BasicType()) {
|
||
|
|
return nl->SymbolAtom(Region::BasicType());
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a2 == Line::BasicType()) {
|
||
|
|
return nl->SymbolAtom(Region::BasicType());
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a2 == Region::BasicType()) {
|
||
|
|
return nl->SymbolAtom(Region::BasicType());
|
||
|
|
}
|
||
|
|
|
||
|
|
return listutils::typeError("second arg is not a supported spatial type");
|
||
|
|
}
|
||
|
|
|
||
|
|
return listutils::typeError("first arg is not a supported spatial type");
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Intersection2
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr SpatialIntersectionTypeMap(ListExpr args)
|
||
|
|
{
|
||
|
|
if (nl->ListLength(args) != 2) {
|
||
|
|
return listutils::typeError("wrong number of arguments");
|
||
|
|
}
|
||
|
|
|
||
|
|
ListExpr arg1 = nl->First(args);
|
||
|
|
ListExpr arg2 = nl->Second(args);
|
||
|
|
|
||
|
|
if (!listutils::isSymbol(arg1)) {
|
||
|
|
return listutils::typeError("first arg is not a supported spatial type");
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!listutils::isSymbol(arg2)) {
|
||
|
|
return listutils::typeError("second arg is not a supported spatial type");
|
||
|
|
}
|
||
|
|
|
||
|
|
string a1 = nl->SymbolValue(arg1);
|
||
|
|
string a2 = nl->SymbolValue(arg2);
|
||
|
|
|
||
|
|
if (a1 == Point::BasicType()) {
|
||
|
|
if (a2 == Line::BasicType() || a2 == Region::BasicType())
|
||
|
|
return nl->SymbolAtom(Points::BasicType());
|
||
|
|
|
||
|
|
return listutils::typeError("second arg is not a supported spatial type");
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a1 == Points::BasicType()) {
|
||
|
|
if (a2 == Line::BasicType() || a2 == Region::BasicType()) {
|
||
|
|
return nl->SymbolAtom(Points::BasicType());
|
||
|
|
}
|
||
|
|
|
||
|
|
return listutils::typeError("second arg is not a supported spatial type");
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a1 == Line::BasicType()) {
|
||
|
|
if (a2 == Point::BasicType() || a2 == Points::BasicType()) {
|
||
|
|
return nl->SymbolAtom(Points::BasicType());
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a2 == Line::BasicType() || a2 == Region::BasicType()) {
|
||
|
|
return nl->SymbolAtom(Line::BasicType());
|
||
|
|
}
|
||
|
|
|
||
|
|
return listutils::typeError("second arg is not a supported spatial type");
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a1 == Region::BasicType()) {
|
||
|
|
if (a2 == Point::BasicType() || a2 == Points::BasicType()) {
|
||
|
|
return nl->SymbolAtom(Points::BasicType());
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a2 == Line::BasicType()) {
|
||
|
|
return nl->SymbolAtom(Line::BasicType());
|
||
|
|
}
|
||
|
|
|
||
|
|
if (a2 == Region::BasicType()) {
|
||
|
|
return nl->SymbolAtom(Region::BasicType());
|
||
|
|
}
|
||
|
|
|
||
|
|
return listutils::typeError("second arg is not a supported spatial type");
|
||
|
|
}
|
||
|
|
|
||
|
|
return listutils::typeError("first arg not a supported spatial type");
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1.1 Intersects2
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr IntersectsTM(ListExpr args)
|
||
|
|
{
|
||
|
|
ListExpr arg1, arg2;
|
||
|
|
if (nl->ListLength(args) == 2) {
|
||
|
|
arg1 = nl->First(args);
|
||
|
|
arg2 = nl->Second(args);
|
||
|
|
SpatialType st1 = SpatialTypeOfSymbol(arg1);
|
||
|
|
SpatialType st2 = SpatialTypeOfSymbol(arg2);
|
||
|
|
|
||
|
|
if (st1 != stpoints || st2 != stpoints) {
|
||
|
|
if (((st1 == stpoints) || (st1 == stline) || (st1 == stregion)) &&
|
||
|
|
((st2 == stpoints) || (st2 == stline) || (st2 == stregion))) {
|
||
|
|
return nl->SymbolAtom(CcBool::BasicType());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return listutils::typeError(" t_1 x t_2 expected,"
|
||
|
|
" with t_1, t_2 in {points,line,region}");
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1.1 Definitions
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
Operator temporaltrajectory2("trajectory2",
|
||
|
|
TemporalSpecTrajectory,
|
||
|
|
MPointTrajectory,
|
||
|
|
Operator::SimpleSelect,
|
||
|
|
MovingTypeMapSpatial);
|
||
|
|
|
||
|
|
Operator toline("toline",
|
||
|
|
ToLineSpec,
|
||
|
|
ToLine,
|
||
|
|
Operator::SimpleSelect,
|
||
|
|
ToLineTypeMap);
|
||
|
|
|
||
|
|
Operator spatialcrossings2("crossings",
|
||
|
|
SpatialSpecCrossings,
|
||
|
|
CrossingsLine,
|
||
|
|
Operator::SimpleSelect,
|
||
|
|
SpatialCrossingsTM);
|
||
|
|
|
||
|
|
Operator spatialintersection2("intersection",
|
||
|
|
SpatialIntersectionSpec,
|
||
|
|
12,
|
||
|
|
spatialintersectionVM,
|
||
|
|
SpatialSetOpSelect,
|
||
|
|
SpatialIntersectionTypeMap);
|
||
|
|
|
||
|
|
Operator spatialminus2("minus",
|
||
|
|
SpatialMinusSpec,
|
||
|
|
12,
|
||
|
|
spatialminusVM,
|
||
|
|
SpatialSetOpSelect,
|
||
|
|
SpatialMinusTypeMap);
|
||
|
|
|
||
|
|
Operator spatialunion2("union",
|
||
|
|
SpatialUnionSpec,
|
||
|
|
12,
|
||
|
|
spatialunionVM,
|
||
|
|
SpatialSetOpSelect,
|
||
|
|
SpatialUnionTypeMap);
|
||
|
|
|
||
|
|
Operator spatialintersects2("intersects",
|
||
|
|
SpatialSpecIntersects,
|
||
|
|
8,
|
||
|
|
spatialintersectsmap,
|
||
|
|
SpatialSelectIntersects,
|
||
|
|
IntersectsTM);
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
1 Algebra definition
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
RobustPlaneSweepAlgebra::RobustPlaneSweepAlgebra()
|
||
|
|
{
|
||
|
|
AddOperator(&temporaltrajectory2);
|
||
|
|
AddOperator(&toline);
|
||
|
|
AddOperator(&spatialintersection2);
|
||
|
|
AddOperator(&spatialminus2);
|
||
|
|
AddOperator(&spatialunion2);
|
||
|
|
AddOperator(&spatialcrossings2);
|
||
|
|
AddOperator(&spatialintersects2);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
extern "C"
|
||
|
|
Algebra* InitializeRobustPlaneSweepAlgebra(
|
||
|
|
NestedList* nlRef,
|
||
|
|
QueryProcessor* qpRef)
|
||
|
|
{
|
||
|
|
// The C++ scope-operator :: must be used to qualify the full name
|
||
|
|
return new RobustPlaneSweep::RobustPlaneSweepAlgebra();
|
||
|
|
}
|