Files
secondo/Algebras/MovingRegion2/MovingRegion2Algebra.cpp
2026-01-23 17:03:45 +08:00

11884 lines
314 KiB
C++

/*
//paragraph [1] Title: [{\Large \bf \begin {center}] [\end {center}}]
//[TOC] [\tableofcontents]
//[ue] [\"u]
//[ae] [\"a]
//[oe] [\"o]
\setcounter{tocdepth}{4}
[1] The ~MovingRegion2Algebra~
May 2012, initial version created by Stefanie Renner for master
thesis with Prof. Dr. G[ue]ting, Fachbereich Informatik,
Fernuniversit[ae]t Hagen.
[TOC]
1 Introduction
The ~MovingRegion2Algebra~ provides data types and operators relating to
moving regions. It is the second attempt to implement an algebra for moving regions
and focuses especially on numerical robustness. Therefor all coordinates are
split into an integer part and the non-integer rest. Calculations are first done on
the integer grid using the integer coordinates only. If no decision can be made
that way, the precise coordinates are taken into account.
Due to the deadline of the master's thesis and the
complexity of the ~MovingRegion2Algebra~, the current version should be
considered as prototype or proof of concept only, and needs to be finalized
before production usage.
The class definitions of ~MSegmentData2~, PreciseMSegmentData, PreciseInterval,
~URegionEmb2~, ~URegion2~ and ~MRegion2~, which
are implemented in ~MovingRegion2Algebra.cpp~, have been moved to
the header file ~MovingRegion2Algebra.h~ to facilitate development work on
top of the ~MovingRegion2Algebra~ without modifying the ~MovingRegion2Algebra~
itself. This file contains detailed descriptions for the usage of the methods
of these classes too.
1 Defines and includes
\label{defines}
*/
#include <queue>
#include <stdexcept>
//includes for the Gnu Multiple Precision (GMP) library
#include <gmp.h>
#include <gmpxx.h>
#include "NestedList.h"
#include "QueryProcessor.h"
#include "StandardTypes.h"
#include "Algebras/Temporal/TemporalAlgebra.h"
#include "MovingRegion2Algebra.h"
#include "DateTime.h"
#include "Symbols.h"
extern NestedList* nl;
extern QueryProcessor* qp;
using namespace temporalalgebra;
using namespace std;
using namespace datetime;
/*
Set ~MR2\_DEBUG~ to ~true~ for debug output. Please note that debug output is
very verbose and has significant negative input on the algebra's performance.
Only enable debug output if you know what you are doing!
*/
const bool MR2_DEBUG = false;
/*
~eps2~ is used for comparison of two double values.
*/
double eps2 = 0.000000001;
/*
~gmpCharNum~ specifies the number of elements reserved for each coordinate in the
DbArray$<$char$>$ for the preciseCoordinates and preciseInstants. If a given coordinate
value needs more elements, another ~gmpCharNum~ elements will be used, and so on.
the last element of each group of ~gmpCharNum~ elements is always the index of the
next of these groups representing the same coordinate.
*/
unsigned int gmpCharNum = 20;
/*
1.1 Function ~simpleSelect()~
Simple selection function for non-overloaded operators.
*/
static int simpleSelect(ListExpr args) {
return 0;
}
/*
1.1 Comparison functions for ~double~
To avoid rounding issues, comparisons for equality are done using constant
~eps2~.
1.1.1 Function ~nearlyEqual()~
Returns ~true~ if $-eps2 \le a-b \le eps2$.
*/
static bool nearlyEqual(double a, double b) {
return abs(a-b) <= eps2;
}
/*
1 Helper functions
1.1 General helper functions
1.1.1 Numerical comparison functions
1.1.1.1 Function ~minmax8()~
Returns the minimum and maximum value of $a$, $b$, $c$, $d$, $e$, $f$, $g$
and $h$ in $min$ and $max$.
*/
static void minmax8(
double a,
double b,
double c,
double d,
double e,
double f,
double g,
double h,
double& min,
double& max) {
min = a;
max = a;
if (b < min) min = b;
if (b > max) max = b;
if (c < min) min = c;
if (c > max) max = c;
if (d < min) min = d;
if (d > max) max = d;
if (e < min) min = e;
if (e > max) max = e;
if (f < min) min = f;
if (f > max) max = f;
if (g < min) min = g;
if (g > max) max = g;
if (h < min) min = h;
if (h > max) max = h;
}
/*
1.1.1.1 Function ~minmax4()~
Returns the minimum and maximum value of $a$, $b$, $c$ and $d$ in $min$
and $max$.
*/
static void minmax4(
int a,
int b,
int c,
int d,
int& min,
int& max) {
min = a;
max = a;
if (b < min) min = b;
if (b > max) max = b;
if (c < min) min = c;
if (c > max) max = c;
if (d < min) min = d;
if (d > max) max = d;
}
static void minmax4(
mpq_class a,
mpq_class b,
mpq_class c,
mpq_class d,
mpq_class& min,
mpq_class& max) {
min = a;
max = a;
if (cmp(b, min) < 0) min = b;
if (cmp(b, max) > 0) max = b;
if (cmp(c, min) < 0) min = c;
if (cmp(c, max) > 0) max = c;
if (cmp(d, min) < 0) min = d;
if (cmp(d, max) > 0) max = d;
}
/*
1.1.1.1 Function ~maybeEqual()~
Checks if two values may be equal, having in mind there respective maximal errors.
Function ~maybeEqual()~ is provided for data type double and for the different
geometric classes, like GridPoint, GridPointSegment, ProvisionalPoint, and so on.
These functions will help to detect such situations where a recalculation with
precise coordinates is needed.
*/
static bool maybeEqual(double a, double b, double aErr, double bErr) {
if (a + aErr + bErr < b || b + aErr + bErr < a)
{
return false;
}
else
{
return true;
}
}
static bool maybeEqual(ProvisionalPoint point1,
ProvisionalPoint point2) {
return (maybeEqual(point1.x, point2.x, point1.xErr, point2.xErr) &&
maybeEqual(point1.y, point2.y, point1.yErr, point2.yErr));
}
static bool maybeEqual(GridPoint point1, GridPoint point2) {
return (maybeEqual(point1.x, point2.x, 1.0, 1.0) &&
maybeEqual(point1.y, point2.y, 1.0, 1.0));
}
static bool maybeEqual(ProvisionalSegment segment1,
ProvisionalSegment segment2) {
return ((maybeEqual(segment1.point1, segment2.point1) &&
maybeEqual(segment1.point2, segment2.point2)) ||
(maybeEqual(segment1.point2, segment2.point1) &&
maybeEqual(segment1.point1, segment2.point2)));
}
static bool maybeEqual(GridPointSegment segment1,
GridPointSegment segment2) {
return ((maybeEqual(segment1.point1, segment2.point1) &&
maybeEqual(segment1.point2, segment2.point2)) ||
(maybeEqual(segment1.point2, segment2.point1) &&
maybeEqual(segment1.point1, segment2.point2)));
}
static bool maybeEqual(ProvisionalTrapezium trapezium1,
ProvisionalTrapezium trapezium2) {
return ((maybeEqual(trapezium1.segment1, trapezium2.segment1)
&& maybeEqual(trapezium1.segment2, trapezium2.segment2)) ||
(maybeEqual(trapezium1.segment2, trapezium2.segment1)
&& maybeEqual(trapezium1.segment1, trapezium2.segment2)));
}
static bool maybeEqual(GridPointTrapezium trapezium1,
GridPointTrapezium trapezium2) {
return ((maybeEqual(trapezium1.segment1, trapezium2.segment1)
&& maybeEqual(trapezium1.segment2, trapezium2.segment2)) ||
(maybeEqual(trapezium1.segment2, trapezium2.segment1)
&& maybeEqual(trapezium1.segment1, trapezium2.segment2)));
}
/*
1.1.1.1 Function ~lowerOrMaybeEqual()~
Checks if two values are closer to each other than the critical radius,
or if the first value is below the second.
Needed to detect such situations where a recalculation with precise coordinates
is needed.
*/
static bool lowerOrMaybeEqual
(double a, double b, double aErr, double bErr) {
if (a < b || maybeEqual(a, b, aErr, bErr))
{
return true;
}
else
{
return false;
}
}
/*
1.1.1.1 Function ~isLower()~
Checks if a is lower than b, keeping in mind the respective errors, so that no
precise recalculation is needed.
*/
static bool isLower
(double a, double b, double aErr, double bErr) {
if (a + aErr < b - bErr)
{
return true;
}
else
{
return false;
}
}
/*
1.1.1.1 Function ~isGreater()~
Checks if a is greater than b, keeping in mind the respective errors, so that no
precise recalculation is needed.
*/
static bool isGreater
(double a, double b, double aErr, double bErr) {
if (a - aErr > b + bErr)
{
return true;
}
return false;
}
/*
1.1.1.1 Function ~greaterOrMaybeEqual()~
Checks if value a is greater or maybe equal with value b, keeping in mind
their respective errors.
Needed to detect such situations where a recalculation with precise coordinates
is needed.
*/
static bool greaterOrMaybeEqual
(double a, double b, double aErr, double bErr) {
if (a > b || maybeEqual(a, b, aErr, bErr))
{
return true;
}
return false;
}
/*
1.1.1.1 Function ~isBetween()~
Returns true if b is between a and c for sure, keeping in mind the
respective errors in the case of double parameters, so that no precise
recalculation is needed.
*/
static bool isBetween(double a, double b, double c, double aErr,
double bErr, double cErr) {
if ((a + aErr < b - bErr && b + bErr < c - cErr) ||
(c + cErr < b - bErr && b + bErr < a - aErr))
{
return true;
}
return false;
}
static bool preciseBetween
(mpq_class a, mpq_class b, mpq_class c) {
if ((cmp(a,b) < 0 && cmp(b,c) < 0 )
|| (cmp(c,b) < 0 && cmp(b,a) < 0 ))
{
return true;
}
return false;
}
static bool preciseBetweenOrEqual
(mpq_class a, mpq_class b, mpq_class c) {
if ((cmp(a,b) <= 0 && cmp(b,c) <= 0 )
|| (cmp(c,b) <= 0 && cmp(b,a) <= 0 ))
{
return true;
}
return false;
}
static bool isBetween
(mpq_class a, double b, mpq_class c) {
if ((cmp(a,b) < 0 && cmp(b,c) < 0 )
|| (cmp(c,b) < 0 && cmp(b,a) < 0 ))
{
return true;
}
return false;
}
static bool isBetween
(double a, mpq_class b, double c) {
if ((cmp(a,b) < 0 && cmp(b,c) < 0 )
|| (cmp(c,b) < 0 && cmp(b,a) < 0 ))
{
return true;
}
return false;
}
/*
1.1.1.1 Function ~betweenOrMaybeEqual()~
Returns true if b is between a and c or maybe of equal value with one of the two
or with both, so that it might be between the two values.
*/
static bool betweenOrMaybeEqual(double a, double b, double c,
double aErr, double bErr, double cErr) {
if (isBetween(a, b, c, aErr, bErr, cErr)
|| maybeEqual(a, b, aErr, bErr) ||
maybeEqual(b, c, bErr, cErr))
{
return true;
}
return false;
}
/*
1.1.1 Other mathematical helper functions
1.1.1.1 Function ~roundedUp()~
Rounds a double up to the next higher integer.
*/
static int roundedUp (double doubleValue)
{
return ((int)doubleValue ==
doubleValue ? (int)doubleValue :
(int)doubleValue + 1);
}
/*
1.1.1.1 Function ~broughtDown()~
Brings a double down to the next lower integer (same as cast, just for readability).
*/
static int broughtDown (double doubleValue)
{
return (int)doubleValue;
}
/*
1.1.1.1 Function ~GaussTransform()~
Apply the Gauss transformation to system of equations. The left hand sides
of the equations are in matrix $a$ with $n$ rows and $m$ columns and the
right hand sides are in vector $b$ with $n$ rows.
The maximal errors of the left hand side components are in matrix $aMaxErr$,
the maximal errors of the right hand side components are in vector $bMaxErr$.
The maximal errors can be used to detect cases where a precise recalculation
will be necessary at some point.
In order to keep the maximal errors small, the equations will be sorted during
the transformation, so that factors by which an equation needs to be
multiplied remain as small as possible.
The transformed matrix and vector are returned in $a$ and $b$ if successfull.
*/
static void GaussTransform(const unsigned int n,
const unsigned int m,
double** a,
double* b,
double** aMaxErr,
double* bMaxErr) {
if (MR2_DEBUG)
{
cerr << "GaussTransform() called, n="
<< n << " m=" << m << endl;
for (unsigned int j = 0; j < n; j++)
{
for (unsigned int k = 0; k < m; k++)
{
fprintf(stderr, "%7.3f ", a[j][k]);
}
fprintf(stderr, "| %7.3f\n", b[j]);
}
cerr << endl;
cerr << "Maximal errors will be transformed as well."
<< endl;
for (unsigned int j = 0; j < n; j++)
{
for (unsigned int k = 0; k < m; k++)
{
fprintf(stderr, "%7.3f ", aMaxErr[j][k]);
}
fprintf(stderr, "| %7.3f\n", bMaxErr[j]);
}
cerr << "============================="
<< "============================="
<< endl;
}
double currentPivotValue;
unsigned int currentPivotLine;
/*
For each row...
*/
for (unsigned int i = 0; i < n-1; i++)
{
/*
Check for non-zero element in column $i$ below and including row $i$, which
can be used as pivot. Search for the greatest possible pivot in these rows.
*/
if (MR2_DEBUG)
{
cerr << "i=" << i << endl;
}
currentPivotValue = 0.0;
currentPivotLine = i;
unsigned int j;
for (j = i; j < n; j++)
{
if (a[j][i] == 0)
{
if (MR2_DEBUG)
{
cerr << " failed as pivot: a["
<< j
<< "]["
<< i
<< "]="
<< a[j][i]
<< endl;
}
}
else
{
if (MR2_DEBUG)
{
cerr << " possible pivot: a["
<< j
<< "]["
<< i
<< "]="
<< a[j][i]
<< endl;
}
if (currentPivotValue < a[j][i])
{
currentPivotValue = a[j][i];
currentPivotLine = j;
}
}
}
/*
If we found a pivot, apply it to the rows below row $i$. If we did not find
a pivot, column $i$ is already zero below and including row $i$ and we do
not have to do anything.
*/
if (currentPivotValue != 0.0)
{
if (MR2_DEBUG)
{
cerr << " taking as pivot: a["
<< currentPivotLine
<< "]["
<< i
<< "]="
<< currentPivotValue
<< endl;
}
/*
The pivot is in row $currentPivotLine$. If $currentPivotLine\ne i$, the pivot is in another row than row $i$.
Swap rows $i$ and $currentPivotLine$ in this case.
Apply the same operation on the maximal errors of the respective components.
*/
if (currentPivotLine != i)
{
double dummy = b[i];
double dummyErr = bMaxErr[i];
b[i] = b[currentPivotLine];
bMaxErr[i] = bMaxErr[currentPivotLine];
b[currentPivotLine] = dummy;
bMaxErr[currentPivotLine] = dummyErr;
for (unsigned int k = 0; k < m; k++)
{
dummy = a[i][k];
dummyErr = aMaxErr[i][k];
a[i][k] = a[currentPivotLine][k];
aMaxErr[i][k] = aMaxErr[currentPivotLine][k];
a[currentPivotLine][k] = dummy;
aMaxErr[currentPivotLine][k] = dummyErr;
}
}
/*
Subtract row $i$ from each row below row $i$, multiplied with factor $f$,
which is calculated so that it sets the element in column $i$ of each row
to $0$ during the substraction.
The maximal error of the respective component is also multiplied with the
same factor, taking its absolute value, and during the substraction
the maximal errors of the respective components are added.
*/
for (j = i+1; j < n; j++)
{
double f = a[j][i]/a[i][i];
if (MR2_DEBUG && f > 1)
{
cerr << "Warning: "
<< "GaussTransform not optimal! "
<< "Error in implementation "
"of line sorting! "
<< endl <<
"Maximal errors "
"not kept minimal! " <<
"Factor > 1 calculated!"
<< endl << endl;
}
if (MR2_DEBUG)
{
cerr << " j=" << j << endl;
cerr << " f=" << f << endl;
}
a[j][i] = 0;
aMaxErr[j][i] += aMaxErr[i][i]*abs(f);
for (unsigned int k = i+1; k < m; k++)
{
a[j][k] -= a[i][k]*f;
aMaxErr[j][k] += aMaxErr[i][k]*abs(f);
}
b[j] -= b[i]*f;
bMaxErr[j] += bMaxErr[i]*abs(f);
}
}
if (MR2_DEBUG)
{
for (j = 0; j < n; j++)
{
for (unsigned int k = 0; k < m; k++)
{
fprintf(stderr, "%7.3f ", a[j][k]);
}
fprintf(stderr, "| %7.3f\n", b[j]);
}
cerr << endl;
cerr << "Maximal errors:" << endl;
for (j = 0; j < n; j++)
{
for (unsigned int k = 0; k < m; k++)
{
fprintf(stderr, "%7.3f ", aMaxErr[j][k]);
}
fprintf(stderr, "| %7.3f\n", bMaxErr[j]);
}
cerr
<< "-----------------------------"
<< "-----------------------------"
<< endl;
}
}
}
static void GaussTransform(const unsigned int n,
const unsigned int m,
mpq_class** a,
mpq_class* b) {
if (MR2_DEBUG) {
cerr << "GaussTransform() called, n="
<< n << " m=" << m << endl;
cerr << "============================="
<< endl;
}
/*
For each row...
*/
for (unsigned int i = 0; i < n-1; i++) {
/*
Check for non-zero element in column $i$ below and including row $i$, which
can be used as pivot.
*/
if (MR2_DEBUG) cerr << "i=" << i << endl;
unsigned int j;
for (j = i; j < n && cmp(a[j][i], 0) == 0; j++)
if (MR2_DEBUG)
cerr << " failed as pivot: a["
<< j
<< "]["
<< i
<< "]"
<< endl;
/*
If we found a pivot, apply it to the rows below row $i$. If we did not find
a pivot, column $i$ is already zero below and including row $i$ and we do
not have to do anything.
*/
if (j != n) {
if (MR2_DEBUG)
cerr << " pivot: a["
<< j
<< "]["
<< i
<< "]"
<< endl;
/*
The pivot is in row $j$. If $j\ne i$, the pivot is in another row than row $i$.
Swap rows $i$ and $j$ in this case.
*/
if (j != i) {
mpq_class dummy = b[i];
b[i] = b[j];
b[j] = dummy;
for (unsigned int k = 0; k < m; k++) {
dummy = a[i][k];
a[i][k] = a[j][k];
a[j][k] = dummy;
}
}
/*
Subtract row $i$ from each row below row $i$, multiplied with factor $f$,
which is calculated so that it sets the element in column $i$ of each row
to $0$ during the substraction.
*/
for (j = i+1; j < n; j++) {
mpq_class f = a[j][i]/a[i][i];
a[j][i] = 0;
for (unsigned int k = i+1; k < m; k++)
a[j][k] -= a[i][k]*f;
b[j] -= b[i]*f;
}
}
}
}
/*
1.1.1 Type conversions for GMP types
1.1.1.1 Function ~fromDouble()~
Reads from the doulbe value inValue and returns its representation as mpq\_class.
*/
static mpq_class fromDouble(double inValue) {
/*
We first convert inValue to string, then count the number of digits
after the point. That tells us which will be our denominator...
Note: A special hack for positive values is needed: We add 0.5 to
the numerator in order to have it correctly rounded.
*/
std::stringstream stringvalue;
stringvalue << inValue;
string s = stringvalue.str();
if (MR2_DEBUG)
{
cerr << "function fromDouble, value = " << s << endl;
}
int index = s.find('.');
if (index == -1)
{
//inValue is an integer
int intinValue = inValue + 0.5;
if (MR2_DEBUG)
cerr << "int number, value " << intinValue << endl;
mpq_class result(intinValue, 1);
return result;
}
string subs = s.substr(s.find('.') + 1, s.size() - (s.find('.') + 1));
int digits = subs.size();
int denom = 1;
for (int i = 0; i < digits; i++)
{
denom *= 10;
}
int num;
if (inValue > 0)
{
num = (inValue * denom) + 0.5; //correct rounding
}
else
{
num = inValue * denom;
}
mpq_class result(num, denom);
result.canonicalize();
return result;
}
/*
1.1.1.1 Function ~gmpTypeToTextType()~
Reads from inValue and stores its representation as TextType in resultList.
*/
static void gmpTypeToTextType
(const mpq_class& inValue, ListExpr& resultList) {
if (MR2_DEBUG)
{
cerr << "gmpTypeToTextType called with gmp input "
<< inValue << "." << endl;
}
int n = 1000000;
stringstream theStream;
theStream << inValue;
resultList = nl->TextAtom();
while (theStream.good())
{
int i = 0;
char* theArray = new char[n];
while (theStream.good() && i < n)
{
char c;
theStream.get(c);
if (theStream.good())
{
theArray[i] = c;
i++;
}
}
for (int j = i; j < n; j++)
{
theArray[j] = 0;
}
string str = string(theArray);
nl->AppendText(resultList, str);
}
}
/*
1.1.1.1 Function ~textTypeToGmpType()~
Reads from inList and stores its representation as mpq\_class in outValue.
*/
static void textTypeToGmpType
(const ListExpr& inList, mpq_class& outValue) {
if (MR2_DEBUG)
{
cerr << "textTypeToGmpType() called with text input "
<< nl->ToString(inList) << endl;
}
TextScan theScan = nl->CreateTextScan(inList);
stringstream theStream;
char lastChar = '*'; //just a random initialization...
for (unsigned int i = 0; i < nl->TextLength(inList); i++)
{
string str = "";
nl->GetText(theScan, 1, str);
//Checking for valid character
if ((int)str[0] < 47 || (int)str[0] > 57
|| (i == 0 && (int)str[0] == 48
&& nl->TextLength(inList) > 1)
|| (lastChar == '/' && (int)str[0] == 48))
{
stringstream message;
message << "Precise coordinate not valid: "
<< nl->ToString(inList)
<< endl << "Only characters 1, 2, 3, 4, 5, "
"6, 7, 8, 9, 0 and / allowed." << endl
<< "0 mustn't be leading "
"character when "
"more than one character "
"in total are given"
<< endl << ", and 0 is "
"not allowed directly after /";
throw invalid_argument(message.str());
}
theStream.put(str[0]);
lastChar = str[0];
}
if (MR2_DEBUG)
cerr << endl;
theStream >> outValue;
outValue.canonicalize();
if (MR2_DEBUG)
cerr << "The resulting gmp value is "
<< outValue << " after canonicalization."
<< endl;
//Checking the value - must be between 0 and 1
if (outValue >= 1 || outValue < 0)
{
stringstream message;
message << "Precise coordinate not valid: "
<< nl->ToString(inList)
<< endl
<< "Resulting value is not between 0 and 1, "
"where 0 is allowed, but 1 is not.";
throw invalid_argument(message.str());
}
}
/*
1.1 Geometrical helper types
1.1.1 Class ~GridPoint~
1.1.1.1 Constructors
*/
GridPoint::GridPoint(int x, int y) :
x (x),
y (y),
isBasic (false),
xErr (1),
yErr (1) {}
GridPoint::GridPoint(int x, int y, bool isBasic) :
x (x),
y (y),
isBasic (isBasic),
xErr (isBasic ? 0 : 1),
yErr (isBasic ? 0 : 1) {}
/*
1.1.1.1 Transformation functions
*/
ProvisionalPoint GridPoint::transformToProvisional() {
ProvisionalPoint result((double)x,
(double)y, (isBasic? 0.0 : 1.0),
(isBasic? 0.0 : 1.0));
return result;
}
/*
1.1.1.1 Operator ==
*/
bool GridPoint::operator==(const GridPoint& other) const {
return (this->x == other.x && this->y ==
other.y && this->isBasic == other.isBasic);
}
/*
1.1.1 Class ~ProvisionalPoint~
1.1.1.1 Constructor
*/
ProvisionalPoint::ProvisionalPoint(double x,
double y, double xErr, double yErr) :
x (x),
y (y),
xErr (xErr),
yErr (yErr) {}
/*
1.1.1.1 Operator ==
*/
bool ProvisionalPoint::operator==
(const ProvisionalPoint& other) const {
return (this->x == other.x && this->y == other.y);
}
/*
1.1.1 Class ~PrecisePoint~
1.1.1.1 Constructors
*/
PrecisePoint::PrecisePoint(mpq_class x, mpq_class y) :
x (x),
y (y) {
}
PrecisePoint::PrecisePoint(mpq_class x1, int x2,
mpq_class y1, int y2) :
x (x1 + x2),
y (y1 + y2) {
}
/*
1.1.1.1 Operator ==
*/
bool PrecisePoint::operator==(const PrecisePoint& other) const {
return (cmp(this->x, other.x) == 0
&& cmp(this->y, other.y) == 0);
}
/*
1.1.1 Class ~GridPointSegment~
1.1.1.1 Constructors
*/
GridPointSegment::GridPointSegment(GridPoint point1,
GridPoint point2) :
point1 (point1),
point2 (point2),
isBasic (point1.isBasic && point2.isBasic) {}
GridPointSegment::GridPointSegment(GridPoint point1,
GridPoint point2, bool isBasic) :
point1 (point1),
point2 (point2),
isBasic (isBasic) {}
/*
1.1.1.1 Access methods
*/
BasicBBox2D GridPointSegment::getBasicBbox2D() {
int minX;
int maxX;
int minY;
int maxY;
minX = point1.x < point2.x ? point1.x : point2.x;
minY = point1.y < point2.y ? point1.y : point2.y;
if (isBasic)
{
maxX = point1.x < point2.x ? point2.x : point1.x;
maxY = point1.y < point2.y ? point2.y : point1.y;
}
else
{
maxX = point1.x < point2.x ?
point2.x + 1 : point1.x + 1;
maxY = point1.y < point2.y ?
point2.y + 1 : point1.y + 1;
}
BasicBBox2D result(minX, maxX+1, minY, maxY+1);
return result;
}
/*
1.1.1.1 Operator ==
*/
bool GridPointSegment::operator==
(const GridPointSegment& other) const {
return ((this->point1 == other.point1
&& this->point2 == other.point2) ||
(this->point2 == other.point1
&& this->point1 == other.point2));
}
/*
1.1.1.1 Transformation functions
*/
ProvisionalSegment GridPointSegment::transformToProvisional() {
ProvisionalSegment result(point1.transformToProvisional(),
point2.transformToProvisional());
return result;
}
/*
1.1.1 Class ~ProvisionalSegment~
1.1.1.1 Constructor
*/
ProvisionalSegment::ProvisionalSegment(ProvisionalPoint point1,
ProvisionalPoint point2) :
point1 (point1),
point2 (point2) {}
/*
1.1.1.1 Operator ==
*/
bool ProvisionalSegment::operator==
(const ProvisionalSegment& other) const {
return ((this->point1 == other.point1
&& this->point2 == other.point2) ||
(this->point2 == other.point1
&& this->point1 == other.point2));
}
/*
1.1.1 Class ~PreciseSegment~
1.1.1.1 Constructor
*/
PreciseSegment::PreciseSegment(PrecisePoint point1,
PrecisePoint point2) :
point1 (point1),
point2 (point2) {}
/*
1.1.1.1 Operator ==
*/
bool PreciseSegment::operator==(const PreciseSegment& other) const {
return ((this->point1 == other.point1
&& this->point2 == other.point2) ||
(this->point2 == other.point1
&& this->point1 == other.point2));
}
/*
1.1.1 Class ~GridPointTrapezium~
1.1.1.1 Constructors
*/
GridPointTrapezium::GridPointTrapezium
(GridPointSegment segment1, GridPointSegment segment2) :
segment1 (segment1),
segment2 (segment2),
isBasic (segment1.isBasic
&& segment2.isBasic) {}
GridPointTrapezium::GridPointTrapezium
(GridPointSegment segment1, GridPointSegment segment2, bool isBasic) :
segment1 (segment1),
segment2 (segment2),
isBasic (isBasic) {}
/*
1.1.1.1 Access methods
*/
BasicBBox2D GridPointTrapezium::getBasicBbox2D() {
int minX;
int maxX;
int minY;
int maxY;
minmax4(segment1.point1.x, segment1.point2.x,
segment2.point1.x, segment2.point2.x, minX, maxX);
minmax4(segment1.point1.y, segment1.point2.y,
segment2.point1.y, segment2.point2.y, minY, maxY);
if (isBasic)
{
return BasicBBox2D(minX, maxX, minY, maxY);
}
else
{
return BasicBBox2D(minX, maxX+1, minY, maxY+1);
}
}
GridPointSegment GridPointTrapezium::getConnectingSegment1() {
GridPointSegment result(segment1.point1, segment2.point1,
(segment1.isBasic && segment2.isBasic));
return result;
}
GridPointSegment GridPointTrapezium::getConnectingSegment2() {
GridPointSegment result(segment1.point2, segment2.point2,
(segment1.isBasic && segment2.isBasic));
return result;
}
/*
1.1.1.1 Operator ==
*/
bool GridPointTrapezium::operator==(const GridPointTrapezium& other) const {
return ((this->segment1 == other.segment1
&& this->segment2 == other.segment2) ||
(this->segment2 == other.segment1
&& this->segment1 == other.segment2));
}
/*
1.1.1 Class ~ProvisionalTrapezium~
1.1.1.1 Constructor
*/
ProvisionalTrapezium::ProvisionalTrapezium(ProvisionalSegment segment1,
ProvisionalSegment segment2) :
segment1 (segment1),
segment2 (segment2) {}
/*
1.1.1.1 Access methods
*/
ProvisionalBBox2D ProvisionalTrapezium::getProvisionalBbox2D() {
double minX;
double maxX;
double minY;
double maxY;
minmax8(segment1.point1.x - segment1.point1.xErr,
segment1.point1.x + segment1.point1.xErr,
segment1.point2.x - segment1.point2.xErr,
segment1.point2.x + segment1.point2.xErr,
segment2.point1.x - segment2.point1.xErr,
segment2.point1.x + segment2.point1.xErr,
segment2.point2.x - segment2.point2.xErr,
segment2.point2.x + segment2.point2.xErr,
minX, maxX);
minmax8(segment1.point1.y - segment1.point1.yErr,
segment1.point1.y + segment1.point1.yErr,
segment1.point2.y - segment1.point2.yErr,
segment1.point2.y + segment1.point2.yErr,
segment2.point1.y - segment2.point1.yErr,
segment2.point1.y + segment2.point1.yErr,
segment2.point2.y - segment2.point2.yErr,
segment2.point2.y + segment2.point2.yErr,
minY, maxY);
ProvisionalBBox2D result(minX, maxX, minY, maxY);
return result;
}
ProvisionalSegment ProvisionalTrapezium::getConnectingSegment1() {
ProvisionalSegment result(segment1.point1, segment2.point1);
return result;
}
ProvisionalSegment ProvisionalTrapezium::getConnectingSegment2() {
ProvisionalSegment result(segment2.point1, segment2.point2);
return result;
}
/*
1.1.1.1 Operator ==
*/
bool ProvisionalTrapezium::operator==
(const ProvisionalTrapezium& other) const {
return ((this->segment1 == other.segment1
&& this->segment2 == other.segment2) ||
(this->segment2 == other.segment1
&& this->segment1 == other.segment2));
}
/*
1.1.1 Class ~PreciseTrapezium~
1.1.1.1 Constructor
*/
PreciseTrapezium::PreciseTrapezium(PreciseSegment segment1,
PreciseSegment segment2) :
segment1 (segment1),
segment2 (segment2) {}
/*
1.1.1.1 Access methods
*/
PreciseBBox2D PreciseTrapezium::getPreciseBbox2D() {
mpq_class minX;
mpq_class maxX;
mpq_class minY;
mpq_class maxY;
minmax4(segment1.point1.x, segment1.point2.x,
segment2.point1.x, segment2.point2.x,
minX, maxX);
minmax4(segment1.point1.y, segment1.point2.y,
segment2.point1.y, segment2.point2.y,
minY, maxY);
PreciseBBox2D result(minX, maxX, minY, maxY);
return result;
}
PreciseSegment PreciseTrapezium::getConnectingSegment1() {
PreciseSegment result(segment1.point1, segment2.point1);
return result;
}
PreciseSegment PreciseTrapezium::getConnectingSegment2() {
PreciseSegment result(segment2.point1, segment2.point2);
return result;
}
/*
1.1.1.1 Operator ==
*/
bool PreciseTrapezium::operator==
(const PreciseTrapezium& other) const {
return ((this->segment1 == other.segment1
&& this->segment2 == other.segment2) ||
(this->segment2 == other.segment1
&& this->segment1 == other.segment2));
}
/*
1.1.1 Class ~BasicBBox2D~
1.1.1.1 Constructor
*/
BasicBBox2D::BasicBBox2D(int minX, int minY,
int maxX, int maxY) :
minX (minX),
maxX (maxX),
minY (minY),
maxY (maxY) {}
/*
1.1.1.1 Function ~overlapsWith()~
Checks if the bounding boxes of two geometric elements overlap.
The bboxes take already care of the possible error of the elements, so that
if true is returned, the bboxes of the precise representation may overlap.
This function is provided for basic and provisional bboxes and one for a
combination of both types.
*/
bool BasicBBox2D::overlapsWith (BasicBBox2D& other) {
if (minX > other.maxX ||
other.minX > maxX ||
minY > other.maxY ||
other.minY > maxY)
{
return false;
}
else
{
return true;
}
}
/*
1.1.1 Class ~ProvisionalBBox2D~
1.1.1.1 Constructor
*/
ProvisionalBBox2D::ProvisionalBBox2D(double minX, double minY,
double maxX, double maxY) :
minX (minX),
maxX (maxX),
minY (minY),
maxY (maxY) {}
/*
1.1.1.1 Function ~overlapsWith()~
Checks if the bounding boxes of two geometric elements overlap.
The bboxes take already care of the possible error of the elements, so that
if true is returned, the bboxes of the precise representation may overlap.
This function is provided for basic and provisional bboxes and one for a
combination of both types.
*/
bool ProvisionalBBox2D::overlapsWith (ProvisionalBBox2D& other) {
if (minX > other.maxX ||
other.minX > maxX ||
minY > other.maxY ||
other.minY > maxY)
{
return false;
}
else
{
return true;
}
}
bool ProvisionalBBox2D::overlapsWith (BasicBBox2D& other) {
if (minX > other.maxX ||
other.minX > maxX ||
minY > other.maxY ||
other.minY > maxY)
{
return false;
}
else
{
return true;
}
}
/*
1.1.1 Class ~PreciseBBox2D~
1.1.1.1 Constructor
*/
PreciseBBox2D::PreciseBBox2D(mpq_class minX, mpq_class minY,
mpq_class maxX, mpq_class maxY) :
minX (minX),
maxX (maxX),
minY (minY),
maxY (maxY) {}
/*
1.1.1.1 Function ~overlapsWith()~
*/
bool PreciseBBox2D::overlapsWith (PreciseBBox2D& other) {
if (cmp(minX, other.maxX) > 0 ||
cmp(other.minX, maxX) > 0 ||
cmp(minY, other.maxY) > 0 ||
cmp(other.minY, maxY) > 0)
{
return false;
}
else
{
return true;
}
}
/*
1.1 Geometrical helper functions
1.1.1 Basic geometrical functions
1.1.1.1 Function ~touching()~
This function is provided for the different geometric helper types like
GridPointSegment, PreciseSegment, PreciseTrapezium, and so on. It returns true
if the two parameters touch (in the case of precise parameters) or may touch
(in the case of integer grid parameters).
*/
static bool touching (GridPointSegment segment1,
GridPointSegment segment2) {
if (segment1.point1 == segment2.point1
|| segment1.point1 == segment2.point2 ||
segment1.point2 == segment2.point1
|| segment1.point2 == segment2.point2)
{
return true;
}
else
{
return false;
}
}
static bool touching (PreciseSegment segment1,
PreciseSegment segment2) {
if (segment1.point1 == segment2.point1
|| segment1.point1 == segment2.point2 ||
segment1.point2 == segment2.point1
|| segment1.point2 == segment2.point2)
{
return true;
}
else
{
return false;
}
}
static bool touching (GridPointTrapezium trapezium1,
GridPointTrapezium trapezium2) {
if (trapezium1.segment1 == trapezium2.segment1
|| trapezium1.segment2 == trapezium2.segment2
|| trapezium1.segment1 == trapezium2.segment2
|| trapezium1.segment2 == trapezium2.segment1
|| trapezium1.getConnectingSegment1() ==
trapezium2.getConnectingSegment1()
|| trapezium1.getConnectingSegment2() ==
trapezium2.getConnectingSegment2()
|| trapezium1.getConnectingSegment1() ==
trapezium2.getConnectingSegment2()
|| trapezium1.getConnectingSegment2() ==
trapezium2.getConnectingSegment1())
{
return true;
}
return false;
}
static bool touching (PreciseTrapezium trapezium1,
PreciseTrapezium trapezium2) {
if (trapezium1.segment1 == trapezium2.segment1
|| trapezium1.segment2 == trapezium2.segment2
|| trapezium1.segment1 == trapezium2.segment2
|| trapezium1.segment2 == trapezium2.segment1
|| trapezium1.getConnectingSegment1() ==
trapezium2.getConnectingSegment1()
|| trapezium1.getConnectingSegment2() ==
trapezium2.getConnectingSegment2()
|| trapezium1.getConnectingSegment1() ==
trapezium2.getConnectingSegment2()
|| trapezium1.getConnectingSegment2() ==
trapezium2.getConnectingSegment1())
{
return true;
}
return false;
}
/*
1.1.1 Intersections between segments or between a segment and a line
1.1.1.1 Function ~segmentsMayIntersect()~ for integer
\label{smi}
Returns ~true~ if the two specified segments may intersect on integer grid
in three-dimensional space $(x, y, t)$.
It is not considered as intersection if they touch in their end points.
If the integer coordinates of the segments end points are the exact coordinates,
this will be used to come to an early conclusion.
The segments both have start point at time $t=0$ and end point at time $t=dt$.
*/
static bool segmentsMayIntersect(int dt,
GridPointSegment& segment1,
GridPointSegment& segment2,
double& zMin, double& zMax) {
if (MR2_DEBUG)
{
cerr << "segmentsMayIntersect() for integer called"
<< endl;
cerr << "segmentsMayIntersect() segment 1: ("
<< segment1.point1.x
<< ", "
<< segment1.point1.y
<< ", 0.0)-("
<< segment1.point2.x
<< ", "
<< segment1.point2.y
<< ", "
<< dt
<< "), isBasic = "
<< segment1.isBasic
<< endl;
cerr << "segmentsMayIntersect() segment 2: ("
<< segment2.point1.x
<< ", "
<< segment2.point1.y
<< ", 0.0)-("
<< segment2.point2.x
<< ", "
<< segment2.point2.y
<< ", "
<< dt
<< "), isBasic = "
<< segment2.isBasic
<< endl;
}
/*
Check if both segments are identical or touch in their endpoints on integer grid.
*/
if (segment1 == segment2)
{
if (MR2_DEBUG)
{
cerr << "segmentsMayIntersect1(): "
"Segments identical on integer grid!"
<< endl;
}
if (segment1.isBasic && segment2.isBasic)
{
return false;
}
zMin = -1;
zMax = dt + 1;
return true;
}
else if (segment1.point1 == segment2.point1)
{
if (MR2_DEBUG)
{
cerr << "segmentsMayIntersect(): "
<< "segments touch in ("
<< segment1.point1.x << ", "
<< segment1.point1.y << ") "
<< "on integer grid!"
<< endl;
}
if (segment1.isBasic && segment2.isBasic)
{
return false;
}
zMin = -1;
zMax = 1;
return true;
}
else if (segment1.point2 == segment2.point2)
{
if (MR2_DEBUG)
{
cerr << "specialSegmentIntersects(): "
<< "segments touch in ("
<< segment1.point2.x << ", "
<< segment2.point2.y << ") "
<< "on integer grid!"
<< endl;
}
if (segment1.isBasic && segment2.isBasic)
{
return false;
}
zMin = dt -1;
zMax = dt + 1;
return true;
}
/*
The line through segment (seg) 1 is
$(seg1.p1.x, seg1.p1.y, 0) + (seg1.p2.x-seg1.p1.x,
seg1.p2.y-seg1.p1.y, dt)\cdot s$.\\
The line through segment 2 is
$(seg2.p1.x, seg2.p1.y, 0) + (seg2.p2.x-seg2.p1.x,
seg2.p2.y-seg2.p1.y, dt)\cdot s$.
The intersection of the two lines is the solution of the following
linear system of equations:
\begin{eqnarray}
\begin{array}{ccc}
\begin{array}{cc}
seg1.p2.x-seg1.p1.x & seg2.p1.x-seg2.p2.x \\
seg1.p2.y-seg1.p1.y & seg2.p1.y-seg2.p2.y \\
dt & -dt
\end{array} & \left| \begin{array}{c}
seg2.p1.x-seg1.p1.x \\
seg2.p1.y-seg1.p1.y \\
0
\end{array} \right.
\end{array}
\nonumber\end{eqnarray}
We put the left handed sides of the equations in matrix $a$ and the right
handed sides into array $b$ and are applying the Gaussian elimination to these.
The maximal errors of each component are also passed in $aMaxErr$ and $bMaxErr$,
respectively:
*/
double A[3][2] =
{{ segment1.point2.x-segment1.point1.x,
segment2.point1.x-segment2.point2.x },
{ segment1.point2.y-segment1.point1.y,
segment2.point1.y-segment2.point2.y },
{ dt, -dt}};
double B[3] =
{ segment2.point1.x-segment1.point1.x,
segment2.point1.y-segment1.point1.y, 0 };
double* Ap[] = { A[0], A[1], A[2] };
double AMaxErr[3][2] = {{ 2, 2 }, { 2, 2 }, { 1, 1 }};
double BMaxErr[3] = { 2, 2, 1 };
double* ApMaxErr[] = { AMaxErr[0], AMaxErr[1], AMaxErr[2] };
GaussTransform(3, 2, Ap, B, ApMaxErr, BMaxErr);
/*
Now, we will determine the solution $t$ from the transformed system.
We examine each row from the bottom to the top:
*/
for (int i = 2; i >= 0; i--)
{
if (!(Ap[i][0] == 0.0))
{
//We reached the first line, nothing more to do here
break;
}
/*
Row is in format $0 c \left| b \right.$.
*/
if (Ap[i][1] == 0.0) {
/*
Row is in format $0 0 \left| b \right.$. Check if there is a contradiction
indicating that there are no solutions.
Keep in mind the errors of each component!
*/
if (abs(B[i]) <= BMaxErr[i])
{
//We cannot be sure that B is really also zero,
//but we cannot be sure it is a contradiction either!
continue;
}
else
{
if (MR2_DEBUG)
cerr << "segmentsMayIntersect1() "
<< "do not intersect #1"
<< " - found contradiction "
"in system of equations!"
<< endl;
return false;
}
} else
{
//Calculate the z coordinate of the intersection point
//and check if it is in the interval [0, dt]
//Calculate also maximal error for z
double z = dt*B[i]/Ap[i][1];
double zMaxError = 2*BMaxErr[i]*ApMaxErr[i][1];
zMin = z - zMaxError;
zMax = z + zMaxError;
/*
Row is in format $0 c \left| b \right.$ with $c\ne 0$. All rows below are
entirely 0.
Inserting $t=b/c$ into the equation of line 2 yields the value $z=dt\cdot b/c$
for the third component. If $0\le z \le dt$, the two segments intersect. If
$z=0$ or $z=dt$, they touch at one of their end points, which is not considered
as intersection.
Again we need to keep in mind the maximal errors! We only return false if we
are sure that there is no intersection!
*/
if (MR2_DEBUG)
cerr << "segmentsMayIntersect() z="
<< z << "maxError="
<< zMaxError
<< endl;
if (lowerOrMaybeEqual(0, z, 1, zMaxError)
&& lowerOrMaybeEqual(z, dt, zMaxError, 1))
{
if (MR2_DEBUG)
cerr << "segmentsMayIntersect() "
<< "intersect"
<< endl;
if (maybeEqual(z, 0, zMaxError, 1)
|| maybeEqual(z, dt, zMaxError, 1))
{
if (MR2_DEBUG)
cerr << "segmentsMayIntersect() "
<< "may only touch, not intersect. "
<< "Recheck necessary!"
<< endl;
}
return true;
} else {
if (MR2_DEBUG)
cerr << "segmentsMayIntersect() "
<< "do not intersect #2"
<< endl;
return false;
}
}
}
/*
Both segments are located on the same line. We have to check whether they
are overlapping. As they are on the same line, it is sufficient to check if
one of the coordinates is overlapping...
*/
if (segment1.isBasic && segment2.isBasic
&& touching(segment1, segment2))
{
//Touching is not intersecting!
return false;
}
else if (betweenOrMaybeEqual(segment1.point1.x,
segment2.point1.x, segment1.point2.x, 1, 1, 1)
|| betweenOrMaybeEqual(segment1.point1.x,
segment2.point2.x, segment1.point2.x, 1, 1, 1)
|| betweenOrMaybeEqual(segment2.point1.x,
segment1.point1.x, segment2.point2.x, 1, 1, 1)
|| betweenOrMaybeEqual(segment2.point1.x,
segment1.point2.x, segment2.point2.x, 1, 1, 1))
{
//Segments may intersect,
//a precise recheck is necessary
return true;
}
else
{
//Segments are quite far from each other,
//surely no intersection
return false;
}
}
/*
1.1.1.1 Function ~segmentsMayIntersect()~ for double
\label{smi2}
Returns ~true~ if the two specified segments may intersect
in three-dimensional space $(x, y, t)$.
It is not considered as intersection if they touch in their end points.
The segments both have start point at time $t=0$ and end point at time $t=dt$.
The values zMin and zMax return the minimum and maximum value for the
z coordinate of the intersection point in case of an intersection. The value
of zMin and zMax is always a relative value, since no real instants are passed to
that function but just the time difference dt.
*/
static bool segmentsMayIntersect(int dt,
ProvisionalSegment& segment1,
ProvisionalSegment& segment2,
double& zMin, double& zMax) {
if (MR2_DEBUG)
{
cerr << "segmentsMayIntersect1() for double "
<< "(with zMin and zMax) called"
<< endl;
cerr << "segmentsMayIntersect1() segment 1: ("
<< segment1.point1.x
<< ", "
<< segment1.point1.y
<< ", 0.0)-("
<< segment1.point2.x
<< ", "
<< segment1.point2.y
<< ", "
<< dt
<< endl;
cerr << "segmentsMayIntersect1() segment 2: ("
<< segment2.point1.x
<< ", "
<< segment2.point1.y
<< ", 0.0)-("
<< segment2.point2.x
<< ", "
<< segment2.point2.y
<< ", "
<< dt
<< endl;
cerr << "maximum errors for segment 1: ("
<< segment1.point1.xErr
<< ", "
<< segment1.point1.yErr
<< ", "
<< segment1.point2.xErr
<< ", "
<< segment1.point2.yErr
<< endl;
cerr << "maximum errors for segment 2: ("
<< segment2.point1.xErr
<< ", "
<< segment2.point1.yErr
<< ", "
<< segment2.point2.xErr
<< ", "
<< segment2.point2.yErr
<< endl;
}
//Initialize zMin and zMax with random values
zMin = -1000;
zMax = 1000;
/*
Check if both segments are identical or touch in their endpoints -
then we need a precise recalculation for sure!
Take also care about the maximum errors here!
*/
if (segment1 == segment2)
{
if (MR2_DEBUG)
cerr << "segmentsMayIntersect(): Segments identical "
"on double precision, they may intersect in reality!"
<< endl;
zMin = 0 - 1;
zMax = dt + 1;
return true;
}
else if (segment1.point1 == segment2.point1)
{
if (MR2_DEBUG)
cerr << "segmentsMayIntersect(): "
<< "segments touch in ("
<< segment1.point1.x << ", "
<< segment1.point1.y << ") "
<< "on double precision, they may intersect in reality!"
<< endl;
zMin = 0 - 1;
zMax = 0 + 1;
return true;
}
else if (segment1.point2 == segment2.point2)
{
if (MR2_DEBUG)
cerr << "segmentsMayIntersect(): "
<< "segments touch in ("
<< segment1.point2.x << ", " << segment2.point2.y << ") "
<< "on double precision, they may intersect in reality!"
<< endl;
zMin = dt - 1;
zMax = dt + 1;
return true;
}
/*
The line through segment 1 is
$(segment1.point1.x, segment1.point1.y, 0)+(segment1.point2.x-segment1.point1.x,
segment1.point2.y-segment1.point1.y, dt)\cdot s$.\\
The line through segment 2 is
$(segment2.point1.x, segment2.point1.y, 0)+(segment2.point2.x-segment2.point1.x,
segment2.point2.y-segment2.point1.y, dt)\cdot s$.
The intersection of the two lines is the solution of the following
linear system of equations:
\begin{eqnarray}
\begin{array}{ccc}
\begin{array}{cc}
seg1.p2.x-seg1.p1.x & seg2.p1.x-seg2.p2.x \\
seg1.p2.y-seg1.p1.y & seg2.p1.y-seg2.p2.y \\
dt & -dt
\end{array} & \left| \begin{array}{c}
seg2.p1.x-seg1.p1.x \\
seg2.p1.y-seg1.p1.y \\
0
\end{array} \right.
\end{array}
\nonumber\end{eqnarray}
We put the left handed sides of the equations in matrix $a$ and the right
handed sides into array $b$ and are applying the Gaussian elimination to these.
The maximal errors of each component are also passed in $aMaxErr$ and $bMaxErr$,
respectively:
*/
double A[3][2] =
{{ segment1.point2.x-segment1.point1.x,
segment2.point1.x-segment2.point2.x },
{ segment1.point2.y-segment1.point1.y,
segment2.point1.y-segment2.point2.y },
{ dt, -dt}};
double B[3] =
{ segment2.point1.x-segment1.point1.x,
segment2.point1.y-segment1.point1.y, 0 };
double* Ap[] = { A[0], A[1], A[2] };
/*
We also need to pass the maximum errors for each component: If values are subtracted,
their respective errors must be added.
*/
double AMaxErr[3][2] =
{{ segment1.point2.xErr + segment1.point1.xErr,
segment2.point1.xErr + segment2.point2.xErr },
{ segment1.point2.yErr + segment1.point1.yErr,
segment2.point1.yErr + segment2.point2.yErr },
{ 1, 1 }};
double BMaxErr[3] = { segment2.point1.xErr + segment1.point1.xErr,
segment2.point1.yErr + segment1.point1.yErr, 1 };
double* ApMaxErr[] = { AMaxErr[0], AMaxErr[1], AMaxErr[2] };
GaussTransform(3, 2, Ap, B, ApMaxErr, BMaxErr);
/*
Now, we will determine the solution $t$ from the transformed system.
We examine each row from the bottom to the top:
*/
for (int i = 2; i >= 0; i--)
{
if (!(Ap[i][0] == 0.0))
{
//We reached the first line, nothing more to do here
break;
}
/*
Row is in format $0 c \left| b \right.$.
*/
if (Ap[i][1] == 0.0) {
/*
Row is in format $0 0 \left| b \right.$. Check if there is a contradiction
indicating that there are no solutions.
Keep in mind the errors of each component!
*/
if (abs(B[i]) <= BMaxErr[i])
{
//We cannot be sure that it is a contradiction!
//B[i] is too close to zero!
continue;
}
else
{
if (MR2_DEBUG)
cerr << "segmentsMayIntersect1() "
<< "do not intersect #1"
<< " - found contradiction in system of equations!"
<< endl;
return false;
}
} else
{
//Calculate the z coordinate of the intersection point
//and check if it is in the interval [0, dt]
//Calculate also maximal error for z
double z = dt*B[i]/Ap[i][1];
double zMaxError = 2*BMaxErr[i]*ApMaxErr[i][1];
zMin = z - zMaxError;
zMax = z + zMaxError;
/*
Row is in format $0 c \left| b \right.$ with $c\ne 0$. All rows below are
entirely 0.
Inserting $t=b/c$ into the equation of line 2 yields the value $z=dt\cdot b/c$
for the third component. If $0\le z \le dt$, the two segments intersect. If
$z=0$ or $z=dt$, they touch at one of their end points, which is not considered
as intersection.
Again we need to keep in mind the maximal errors! We only return false if we
are sure that there is no intersection!
*/
if (MR2_DEBUG)
cerr << "segmentsMayIntersect() z="
<< z << "maxError="
<< zMaxError << endl;
if (lowerOrMaybeEqual(0, z, 1, zMaxError)
&& lowerOrMaybeEqual(z, dt, zMaxError, 1))
{
if (MR2_DEBUG)
cerr << "segmentsMayIntersect() "
<< "may intersect"
<< endl;
if (maybeEqual(z, 0, zMaxError, 1)
|| maybeEqual(z, dt, zMaxError, 1))
{
if (MR2_DEBUG)
cerr << "segmentsMayIntersect() "
<< "may only touch, not intersect. "
<< "Recheck necessary!"
<< endl;
}
return true;
} else {
if (MR2_DEBUG)
cerr << "segmentsMayIntersect() "
<< "do not intersect"
<< endl;
return false;
}
}
}
/*
Both segments are located on the same line. We have to check whether they
are overlapping. As they are on the same line, it is sufficient to check if
one of the coordinates is overlapping...
*/
if (betweenOrMaybeEqual
(segment1.point1.x, segment2.point1.x,
segment1.point2.x, segment1.point1.xErr,
segment2.point1.xErr, segment1.point2.xErr)
|| betweenOrMaybeEqual(segment1.point1.x,
segment2.point2.x, segment1.point2.x,
segment1.point1.xErr, segment2.point2.xErr,
segment1.point2.xErr)
|| betweenOrMaybeEqual(segment2.point1.x,
segment1.point1.x, segment2.point2.x,
segment2.point1.xErr, segment1.point1.xErr,
segment2.point2.xErr)
|| betweenOrMaybeEqual(segment2.point1.x,
segment1.point2.x, segment2.point2.x,
segment2.point1.xErr, segment1.point2.xErr,
segment2.point2.xErr))
{
//Segments may intersect, a precise recheck is necessary
return true;
}
else
{
//Segments are quite far from each other, surely no intersection
return false;
}
}
static bool segmentsMayIntersect(int dt,
GridPointSegment& segment1,
GridPointSegment& segment2) {
if (MR2_DEBUG)
cerr << "segemntsMayIntersect "
"without z for integer called" << endl;
double dummy1;
double dummy2;
return segmentsMayIntersect
(dt, segment1, segment2, dummy1, dummy2);
}
/*
1.1.1.1 Function ~preciseSegmentsIntersect()~ for precise coordinates
\label{psi}
Returns ~true~ if the two specified segments intersect
in three-dimensional space $(x, y, t)$.
It is not considered as intersection if they touch in their end points.
The segments both have start point at time $t=0$ and end point at time $t=dt$.
*/
static bool preciseSegmentsIntersect(mpq_class dt,
PreciseSegment& segment1,
PreciseSegment& segment2,
mpq_class& z) {
if (MR2_DEBUG)
cerr << "preciseSegmentsIntersect() called"
<< endl;
/*
Check if both segments are identical or touch in their endpoints -
then we need a precise recalculation for sure!
Take also care about the maximum errors here!
*/
if (segment1 == segment2)
{
if (MR2_DEBUG)
cerr << "preciseSegmentsIntersect(): Segments identical!"
<< endl;
return false;
}
else if (segment1.point1 == segment2.point1)
{
if (MR2_DEBUG)
cerr << "preciseSegmentsIntersect(): "
<< "segments touch at z=0."
<< endl;
return false;
}
else if (segment1.point2 == segment2.point2)
{
if (MR2_DEBUG)
cerr << "preciseSegmentsIntersect(): "
<< "segments touch at z=dt."
<< endl;
return false;
}
/*
The line through segment 1 is
$(segment1.point1.x, segment1.point1.y, 0)+(segment1.point2.x-segment1.point1.x,
segment1.point2.y-segment1.point1.y, dt)\cdot s$.\\
The line through segment 2 is
$(segment2.point1.x, segment2.point1.y, 0)+(segment2.point2.x-segment2.point1.x,
segment2.point2.y-segment2.point1.y, dt)\cdot s$.
The intersection of the two lines is the solution of the following
linear system of equations:
\begin{eqnarray}
\begin{array}{ccc}
\begin{array}{cc}
seg1.p2.x-seg1.p1.x & seg2.p1.x-seg2.p2.x \\
seg1.p2.y-seg1.p1.y & seg2.p1.y-seg2.p2.y \\
dt & -dt
\end{array} & \left| \begin{array}{c}
seg2.p1.x-seg1.p1.x \\
seg2.p1.y-seg1.p1.y \\
0
\end{array} \right.
\end{array}
\nonumber\end{eqnarray}
We put the left handed sides of the equations in matrix $a$ and the right
handed sides into array $b$ and are applying the Gaussian elimination to these.
The maximal errors of each component are also passed in $aMaxErr$ and $bMaxErr$,
respectively:
*/
mpq_class A[3][2] =
{{ segment1.point2.x-segment1.point1.x,
segment2.point1.x-segment2.point2.x },
{ segment1.point2.y-segment1.point1.y,
segment2.point1.y-segment2.point2.y },
{ dt, -dt}};
mpq_class B[3] =
{ segment2.point1.x-segment1.point1.x,
segment2.point1.y-segment1.point1.y, 0 };
mpq_class* Ap[] = { A[0], A[1], A[2] };
GaussTransform(3, 2, Ap, B);
/*
Now, we will determine the solution $t$ from the transformed system.
We examine each row from the bottom to the top:
*/
for (int i = 2; i >= 0; i--)
{
if (cmp(Ap[i][0], 0) != 0)
{
break;
}
/*
Row is in format $0 c \left| b \right.$.
*/
if (cmp(Ap[i][1], 0) == 0) {
/*
Row is in format $0 0 \left| b \right.$. Check if there is a contradiction
indicating that there are no solutions.
Keep in mind the errors of each component!
*/
if (cmp(B[i], 0) == 0)
{
continue;
}
else
{
if (MR2_DEBUG)
cerr << "preciseSegmentsIntersect() "
<< "do not intersect"
<< " - found contradiction in system of equations!"
<< endl;
return false;
}
} else
{
//Calculate the z coordinate of
//the intersection point and check
//if it is in the interval [0, dt]
z = dt*B[i]/Ap[i][1];
/*
Row is in format $0 c \left| b \right.$ with $c\ne 0$. All rows below are
entirely 0.
Inserting $t=b/c$ into the equation of line 2 yields the value $z=dt\cdot b/c$
for the third component. If $0\le z \le dt$, the two segments intersect. If
$z=0$ or $z=dt$, they touch at one of their end points, which is not considered
as intersection.
Again we need to keep in mind the maximal errors! We only return false if we
are sure that there is no intersection!
*/
if (cmp(0, z) < 0 && cmp(z, dt) < 0)
{
if (MR2_DEBUG)
cerr << "preciseSegmentsIntersect() "
<< "intersect"
<< endl;
return true;
} else {
if (MR2_DEBUG)
cerr << "preciseSegmentsIntersect() "
<< "do not intersect (they may touch, but not intersect)"
<< endl;
return false;
}
}
}
/*
Both segments are located on the same line. We have to check whether they
are overlapping. As they are on the same line, it is sufficient to check if
one of the coordinates is overlapping...
*/
if ((segment1.point1.x < segment2.point1.x
&& segment2.point1.x < segment1.point2.x)
|| (segment1.point1.x < segment2.point2.x
&& segment2.point2.x < segment1.point2.x)
|| (segment2.point1.x < segment1.point1.x
&& segment1.point1.x < segment2.point2.x)
|| (segment2.point1.x < segment1.point2.x
&& segment1.point2.x < segment2.point2.x))
{
return true;
}
else
{
return false;
}
}
static bool preciseSegmentsIntersect(mpq_class dt,
PreciseSegment& segment1,
PreciseSegment& segment2) {
if (MR2_DEBUG)
cerr << "preciseSegmentsIntersect without z called"
<< endl;
mpq_class dummy;
return preciseSegmentsIntersect(dt, segment1, segment2, dummy);
}
/*
1.1.1.1 Function ~segmentAndLineMayIntersect()~
Returns ~true~ if the specified segment and line may intersect
in three-dimensional space $(x, y, t)$.
The segment is parallel to the $(x, y)$-plane.
The line is $P+Q\cdot t$. The line must not be parallel to the $(x, y)-plane$.
*/
static bool segmentAndLineMayIntersect(int z,
GridPointSegment& segment,
double* P,
double* Q,
double* PErr,
double* QErr) {
if (MR2_DEBUG) {
cerr << "segmentAndLineMayIntersect() called"
<< endl;
cerr << "segmentAndLineMayIntersect() segment: ("
<< segment.point1.x
<< ", "
<< segment.point1.y
<< ", "
<< z
<< ")-("
<< segment.point2.x
<< ", "
<< segment.point2.y
<< ", "
<< z
<< ")"
<< endl;
cerr << "segmentAndLineMayIntersect() line: ("
<< P[0]
<< ", "
<< P[1]
<< ", "
<< P[2]
<< ")-("
<< Q[0]
<< ", "
<< Q[1]
<< ", "
<< Q[2]
<< ")*t"
<< endl;
cerr << "segmentAndLineMayIntersect() maximum errors of segment: "
<< "1 in each component, as this segment is on integer grid."
<< endl;
cerr << "segmentAndLineMayIntersect() maximum errors "
<< "of line: P errors: ("
<< PErr[0]
<< ", "
<< PErr[1]
<< ", "
<< PErr[2]
<< "), Q errors: ("
<< QErr[0]
<< ", "
<< QErr[1]
<< ", "
<< QErr[2]
<< "), where line = P - Q*t"
<< endl;
}
if (segment.point1 == segment.point2 && segment.isBasic) {
/*
The segment is actually a point.
*/
if (MR2_DEBUG)
cerr
<< "segmentAndLineMayIntersect() "
<< "no intersection #1 - segment is just a point!"
<< endl;
return false;
}
/*
Calculate point $(x, y)$ where the line intersects the plane parallel to the
$(x, y)$-plane with distance z from the $(x, y)$-plane.
*/
double t2 = (z-P[2])/Q[2];
double t2Err = (1 + PErr[2]) * QErr[2];
if (MR2_DEBUG)
cerr << "segmentAndLineMayIntersect(), "
<< "line intersects with plane parallel to (x,y) "
<< "at distance z at "
<< endl << "t= " << t2 << ", tErr = " << t2Err
<< endl;
double x = P[0]+Q[0]*t2;
double y = P[1]+Q[1]*t2;
double xErr = PErr[0] + QErr[0]*t2Err;
double yErr = PErr[1] + QErr[1]*t2Err;
if (MR2_DEBUG)
cerr << "segmentAndLineMayIntersect() x="
<< x
<< " y="
<< y
<< " xErr=" << xErr << ", yErr=" << yErr
<< endl;
/*
Next we check if the bounding box of the segment overlaps with the bounding box
built of the points coordinates and their respective maximum errors.
*/
BasicBBox2D segmentBbox = segment.getBasicBbox2D();
if (MR2_DEBUG)
cerr << "segmentAndLineMayIntersect() segments "
<< "bounding box is: " << endl
<< "minX="
<< segmentBbox.minX
<< ", maxX="
<< segmentBbox.maxX
<< ", minY="
<< segmentBbox.minY
<< ", maxY="
<< segmentBbox.maxY
<< endl;
ProvisionalBBox2D intersectionPointBbox
(x - xErr, y - yErr, x + xErr, y + yErr);
if (!intersectionPointBbox.overlapsWith(segmentBbox))
{
if (MR2_DEBUG)
cerr << "segmentAndLineMayIntersect() "
<< "do not intersect - bboxes do not overlap "
<< "on plane parallel to (x,y) at distance z!"
<< endl;
return false;
}
/*
Next we check for special cases. Is the segment vertical or horizontal in $(x, y)$?
*/
if (segment.point1.x == segment.point2.x)
{
/*
The segment is vertical in the $(x, y)$-plane.
We already know that the bounding boxes overlap.
We cannot make a more precise check because of the insecurity of the
precise point coordinates. Thus, line and segment may overlap.
*/
if (MR2_DEBUG)
cerr << "segmentAndLineMayIntersect() "
<< "may intersect - segment is vertical "
<< "in (x,y) and bbox overlaps"
<< " with the one of the intersection point!"
<< endl;
return true;
}
else if (segment.point1.y == segment.point2.y)
{
/*
The segment is horizontal in the $(x, y)$-plane.
We already know that the bounding boxes overlap.
We cannot make a more precise check because of the insecurity of the
precise point coordinates. Thus, line and segment may overlap.
*/
if (MR2_DEBUG)
cerr << "segmentAndLineMayIntersect() "
<< "may intersect - segment is horizontal "
<< "in (x,y) and bbox overlaps"
<< " with the one of the intersection point!"
<< endl;
return true;
}
/*
If the segment is neither vertical nor horizontal in $(x, y)$, we can make a finer
decision than just that based on the bounding box (the bbox is very imprecise here).
We now calculate the line built by the segment. We then calculate
the distance of the intersection point $(x, y)$ from the line both by its x- and
y-Komponent. If and only if these distances are smaller than the sum of the
respective errors, line and segment may intersect.
*/
//Calculate the y-component of the point on the line at x
double lineY = (x - segment.point1.x) /
(segment.point2.x - segment.point1.x)
* (segment.point2.y - segment.point1.y) +
segment.point1.y;
if (MR2_DEBUG)
cerr << "segmentAndLineMayIntersect() "
<< "y on segment where x is same as line intersection point: "
<< lineY << endl
<< "Will compare with intersection point y: " << y
<< " and its error: " << yErr << endl;
//Calculate the x-component of the point on the line at y
double lineX = (y - segment.point1.y) /
(segment.point2.y - segment.point1.y)
* (segment.point2.x - segment.point1.x) +
segment.point1.x;
if (MR2_DEBUG)
cerr << "segmentAndLineMayIntersect() "
<< "x on segment where y is same as line intersection point: "
<< lineX << endl
<< "Will compare with intersection point x: " << x
<< " and its error: " << xErr << endl;
if (lineX + 1 < x - xErr || lineX - 1 > x + xErr )
{
if (MR2_DEBUG)
cerr << "segmentAndLineMayIntersect() cannot intersect, "
<< "intersection point "
<< "too far from line!"
<< endl;
return false;
}
else
{
if (MR2_DEBUG)
cerr << "segmentAndLineMayIntersect() may intersect. "
<< endl;
return true;
}
}
static bool segmentsMayIntersect(int dt,
ProvisionalSegment& segment1,
ProvisionalSegment& segment2) {
if (MR2_DEBUG)
cerr << "segmentsMayIntersect without z "
<< "for double called"
<< endl;
double dummy1;
double dummy2;
return segmentsMayIntersect
(dt, segment1, segment2, dummy1, dummy2);
}
/*
1.1.1.1 Function ~preciseSegmentAndLineIntersect()~
Returns ~true~ if the specified segment and line intersect
in three-dimensional space $(x, y, t)$.
The segment is parallel to the $(x, y)$-plane.
The line is $P+Q\cdot t$. The line must not be parallel to the $(x, y)$-plane.
*/
static bool preciseSegmentAndLineIntersect(mpq_class z,
PreciseSegment& segment,
mpq_class* P,
mpq_class* Q) {
if (MR2_DEBUG) {
cerr << "preciseSegmentAndLineIntersect() called"
<< endl;
}
if (segment.point1 == segment.point2) {
/*
The segment is actually a point.
*/
if (MR2_DEBUG)
cerr << "preciseSegmentAndLineIntersect() "
<< "no intersection - segment is just a point!"
<< endl;
return false;
}
/*
Calculate point $(x, y)$ where the line intersects the plane parallel to the
$(x, y)$-plane with distance z from the $(x, y)$-plane.
*/
mpq_class t2 = (z-P[2])/Q[2];
if (MR2_DEBUG)
cerr << "preciseSegmentAndLineIntersect(), "
<< "line intersects with plane parallel to (x,y) "
<< "at distance z"
<< endl;
mpq_class x = P[0]+Q[0]*t2;
mpq_class y = P[1]+Q[1]*t2;
mpq_class l1MinX =
cmp(segment.point1.x, segment.point2.x) < 0 ?
segment.point1.x : segment.point2.x;
mpq_class l1MaxX =
cmp(segment.point1.x, segment.point2.x) > 0 ?
segment.point1.x : segment.point2.x;
mpq_class l1MinY =
cmp(segment.point1.y, segment.point2.y) < 0 ?
segment.point1.y : segment.point2.y;
mpq_class l1MaxY =
cmp(segment.point1.y, segment.point2.y) > 0 ?
segment.point1.y : segment.point2.y;
/*
Next we check for special cases. Is the segment vertical or horizontal in $(x, y)$?
*/
if (cmp(segment.point1.x , segment.point2.x) == 0)
{
/*
The segment is vertical in the $(x, y)$-plane.
*/
if (cmp(x, segment.point1.x) == 0
&& cmp(y, l1MaxY) < 0 && cmp(l1MinY, y) < 0)
{
if (MR2_DEBUG)
cerr << "preciseSegmentAndLineIntersect() "
<< "intersect - segment is vertical "
<< "in (x,y)!" << endl;
return true;
}
else
{
if (MR2_DEBUG)
cerr << "preciseSegmentAndLineIntersect() "
<< "no intersection."
<< endl;
return false;
}
}
else if (cmp(segment.point1.y, segment.point2.y) == 0)
{
/*
The segment is horizontal in the $(x, y)$-plane.
*/
if (cmp(y, segment.point1.y) == 0
&& cmp(x, l1MaxX) < 0 && cmp(l1MinX, x) < 0)
{
if (MR2_DEBUG)
cerr << "preciseSegmentAndLineIntersect() "
<< "intersect - segment is horizontal "
<< "in (x,y)!" << endl;
return true;
}
else
{
if (MR2_DEBUG)
cerr << "preciseSegmentAndLineIntersect() "
<< "no intersection." << endl;
return false;
}
}
/*
If the segment is neither vertical nor horizontal in $(x, y)$, we can use the equations below
without running into problems dividing through zero.
We now calculate the line built by the segment.
First, check whether $(x, y)$ is on the line through the segment.
*/
mpq_class t1 =
(x-segment.point1.x)/(segment.point2.x-segment.point1.x);
if (cmp(t1, (y - segment.point1.y)/
(segment.point2.y - segment.point1.y)) != 0)
{
if (MR2_DEBUG)
cerr << "preciseSegmentAndLineIntersect() "
<< "no intersection" << endl;
return false;
}
/*
Verify that $(x, y)$ is actually on the segment: As we already know that
it is on the line through the segment, we just have to check its bounding
box parallel to the $(x, y)$-plane.
*/
if (cmp(x, l1MinX) < 0
|| cmp(l1MaxX, x) < 0
|| cmp(y, l1MinY) < 0
|| cmp(l1MaxY, y) < 0) {
if (MR2_DEBUG)
cerr << "preciseSegmentAndLineIntersect() "
<< "no intersection" << endl;
return false;
}
if (MR2_DEBUG)
cerr << "preciseSegmentAndLineIntersect() "
<< "intersects" << endl;
return true;
}
/*
1.1.1 Intersections between two trapeziums
1.1.1.1 Function ~trapeziumsMayIntersect()~
\label{stinu}
Returns ~true~ if the two specified trapeziums may intersect in three-dimensional
space $(x, y, t)$.
The two trapeziums must meet the following conditions. These conditions are
not checked in the function. If the conditions are not met, the function will
deliver incorrect results.
Both trapeziums are spanned by two segments which are parallel to the plane (x,y).
Of each trapezium one segment, called segment1, one is in distance z=0 while the
other segment, called segment2, is in distance z=dt.
For both trapeziums, it is allowed that either the segment between the two
points at instant 0 or the segment between the two points at instant dt reduces
to a single point, but never both.
The segment between the two points at instant 0 and the segment between the two
points at instant dt must be collinear, and this must be true for both trapeziums.
$dt$ must be greater than $0$.
The coordinates of all points spanning the trapeziums are given on the integer grid.
If the methods returns true, the calculation needs to be repeated with precise
coordinates to ensure that the trapeziums really intersect with each other.
*/
static bool trapeziumsMayIntersect(
int dt,
GridPointTrapezium trapezium1,
GridPointTrapezium trapezium2) {
if (MR2_DEBUG) {
cerr << "trapeziumsMayIntersect() called"
<< endl;
cerr << "Trapezium 1: ("
<< trapezium1.segment1.point1.x << ", "
<< trapezium1.segment1.point1.y
<< "), ("
<< trapezium1.segment1.point2.x << ", "
<< trapezium1.segment1.point2.y
<< "), ("
<< trapezium1.segment2.point1.x << ", "
<< trapezium1.segment2.point1.y
<< "), ("
<< trapezium1.segment2.point2.x << ", "
<< trapezium1.segment2.point2.y
<< ")"
<< endl;
cerr << "Trapezium2: ("
<< trapezium2.segment1.point1.x << ", "
<< trapezium2.segment1.point1.y
<< "), ("
<< trapezium2.segment1.point2.x << ", "
<< trapezium2.segment1.point2.y
<< "), ("
<< trapezium2.segment2.point1.x << ", "
<< trapezium2.segment2.point1.y
<< "), ("
<< trapezium2.segment2.point2.x << ", "
<< trapezium2.segment2.point2.y
<< ")"
<< endl;
}
/*
First, lets check the bounding boxes in the $(x, y)$-plane of the two
trapeziums. If they don't overlap, we are finished.
*/
BasicBBox2D bboxT1 = trapezium1.getBasicBbox2D();
BasicBBox2D bboxT2 = trapezium2.getBasicBbox2D();
bool doOverlap = bboxT1.overlapsWith(bboxT2);
if (!doOverlap)
{
if (MR2_DEBUG) {
cerr << "trapeziumsMayIntersect() "
<< "bboxes do not overlap"
<< endl;
}
return false;
}
if (MR2_DEBUG) {
cerr << "trapeziumsMayIntersect() "
<< "bboxes overlap" << endl;
}
/*
Now, lets see if the trapeziums are equal or touch in one segment.
For basic trapeziums, that means that they do not intersect, but for
non-basic trapeziums, that means that they are sufficiently close to
each other, so that we need a precise recalculation!
*/
if (trapezium1 == trapezium2 ||
touching(trapezium1, trapezium2))
{
if (trapezium1.isBasic && trapezium2.isBasic)
{
if (MR2_DEBUG)
cerr << "trapeziumsMayIntersect(): "
<< "Trapeziums are basic and equal "
<< "or only touching!"
<< endl;
return false;
}
else
{
if (MR2_DEBUG)
cerr << "trapeziumsMayIntersect() equal "
<< "or touching on integer grid. "
<< "Recheck with precise coordinates!"
<< endl;
return true;
}
}
/*
The bounding boxes of the trapeziums overlap but they do not touch in one
segment and are not equal.
To determine if they really intersect, we first calculate the
intersection of the two planes spanned by the trapezium.
Create equations for the two planes spanned by the trapeziums,
considering that one edge of
each trapezium may be a single point: Plane 1 is
$T1B+T1A\cdot (s, t)$ and Plane 2 is $T2B+T1A\cdot (s', t')$.
*/
double T1A[3][2]; //left side of equations for trapezium1
double T1B[3]; //right side of equations for trapezium1
double T2A[3][2]; //left side of equations for trapezium2
double T2B[3]; //right side of equations for trapezium2
double T1aErr[3][2]; //maximal errors, left side
double T2aErr[3][2]; //maximal errors, left side
double T1bErr[3]; //maximal errors, right side
double T2bErr[3]; //maximal errors, right side
if (trapezium1.segment1.point1 ==
trapezium1.segment1.point2) {
//Trapezium1 is a triangle, the first segment
//is just a point - we use the second segment instead
T1A[0][0] = trapezium1.segment2.point2.x
-trapezium1.segment2.point1.x;
T1aErr[0][0] = trapezium1.segment2.point2.xErr
+ trapezium1.segment2.point1.xErr;
T1A[1][0] = trapezium1.segment2.point2.y
- trapezium1.segment2.point1.y;
T1aErr[1][0] = trapezium1.segment2.point2.yErr
+ trapezium1.segment2.point1.yErr;
T1A[2][0] = 0;
T1aErr[2][0] = 1;
T1A[0][1] = trapezium1.segment1.point1.x
-trapezium1.segment2.point1.x;
T1aErr[0][1] = trapezium1.segment1.point1.xErr
+ trapezium1.segment2.point1.xErr;
T1A[1][1] = trapezium1.segment1.point1.y
-trapezium1.segment2.point1.y;
T1aErr[1][1] = trapezium1.segment1.point1.yErr
+ trapezium1.segment2.point1.yErr;
T1A[2][1] = -dt;
T1aErr[2][1] = 1;
T1B[0] = trapezium1.segment2.point1.x;
T1bErr[0] = trapezium1.segment2.point1.xErr;
T1B[1] = trapezium1.segment2.point1.y;
T1bErr[1] = trapezium1.segment2.point1.yErr;
T1B[2] = dt;
T1bErr[2] = 1;
} else {
//The first segment is no point, we can use it
T1A[0][0] = trapezium1.segment1.point2.x
-trapezium1.segment1.point1.x;
T1A[1][0] = trapezium1.segment1.point2.y
-trapezium1.segment1.point1.y;
T1aErr[0][0] = trapezium1.segment1.point2.xErr
+ trapezium1.segment1.point1.xErr;
T1aErr[1][0] = trapezium1.segment1.point2.yErr
+ trapezium1.segment1.point1.yErr;
T1A[2][0] = 0;
T1aErr[2][0] = 1;
T1A[0][1] = trapezium1.segment2.point1.x
-trapezium1.segment1.point1.x;
T1A[1][1] = trapezium1.segment2.point1.y
-trapezium1.segment1.point1.y;
T1aErr[0][0] = trapezium1.segment2.point1.xErr
+ trapezium1.segment1.point1.xErr;
T1aErr[1][1] = trapezium1.segment2.point1.yErr
+ trapezium1.segment1.point1.yErr;
T1A[2][1] = dt;
T1aErr[2][1] = 1;
T1B[0] = trapezium1.segment1.point1.x;
T1B[1] = trapezium1.segment1.point1.y;
T1bErr[0] = trapezium1.segment1.point1.xErr;
T1bErr[1] = trapezium1.segment1.point1.yErr;
T1B[2] = 0;
T1bErr[2] = 1;
}
if (trapezium2.segment1.point1 ==
trapezium2.segment1.point2) {
//Trapezium2 is a triangle, the first segment
//is just a point - we use segment 2 instead
T2A[0][0] = trapezium2.segment2.point2.x
-trapezium2.segment2.point1.x;
T2A[1][0] = trapezium2.segment2.point2.y
-trapezium2.segment2.point1.y;
T2aErr[0][0] = trapezium2.segment2.point2.xErr
+ trapezium2.segment2.point1.xErr;
T2aErr[1][0] = trapezium2.segment2.point2.yErr
+ trapezium2.segment2.point1.yErr;
T2A[2][0] = 0;
T2aErr[2][0] = 1;
T2A[0][1] = trapezium2.segment1.point1.x
-trapezium2.segment2.point1.x;
T2A[1][1] = trapezium2.segment1.point1.y
-trapezium2.segment2.point1.y;
T2aErr[0][1] = trapezium2.segment1.point1.xErr
+ trapezium2.segment2.point1.xErr;
T2aErr[1][1] = trapezium2.segment1.point1.yErr
+ trapezium2.segment2.point1.yErr;
T2A[2][1] = -dt;
T2aErr[2][1] = 1;
T2B[0] = trapezium2.segment2.point1.x;
T2B[1] = trapezium2.segment2.point1.y;
T2bErr[0] = trapezium2.segment2.point1.xErr;
T2bErr[1] = trapezium2.segment2.point1.yErr;
T2B[2] = dt;
T2bErr[2] = 1;
} else {
//The first segment is no point, so we can use it
T2A[0][0] = trapezium2.segment1.point2.x
-trapezium2.segment1.point1.x;
T2A[1][0] = trapezium2.segment1.point2.y
-trapezium2.segment1.point1.y;
T2aErr[0][0] = trapezium2.segment1.point2.xErr
+ trapezium2.segment1.point1.xErr;
T2aErr[1][0] = trapezium2.segment1.point2.yErr
+ trapezium2.segment1.point1.yErr;
T2A[2][0] = 0;
T2aErr[2][0] = 1;
T2A[0][1] = trapezium2.segment2.point1.x
-trapezium2.segment1.point1.x;
T2A[1][1] = trapezium2.segment2.point1.y
-trapezium2.segment1.point1.y;
T2aErr[0][1] = trapezium2.segment2.point1.xErr
+ trapezium2.segment1.point1.xErr;
T2aErr[1][1] = trapezium2.segment2.point1.yErr
+ trapezium2.segment1.point1.yErr;
T2A[2][1] = dt;
T2aErr[2][1] = 1;
T2B[0] = trapezium2.segment1.point1.x;
T2B[1] = trapezium2.segment1.point1.y;
T2bErr[0] = trapezium2.segment1.point1.xErr;
T2bErr[1] = trapezium2.segment1.point1.yErr;
T2B[2] = 0;
T2bErr[2] = 1;
}
if (MR2_DEBUG) {
cerr << "T1B T1A "
<< "T2B T2A"
<< endl;
cerr << "------- --------------- "
<< "------- ---------------"
<< endl;
for (unsigned int i = 0; i < 3; i++)
fprintf(stderr,
"%7.3f %7.3f %7.3f"
"%7.3f %7.3f %7.3f\n",
T1B[i],
T1A[i][0],
T1A[i][1],
T2B[i],
T2A[i][0],
T2A[i][1]);
cerr << "T1bErr T1aErr "
<< "T2bErr T2aErr"
<< endl;
cerr << "------- --------------- "
<< "------- ---------------"
<< endl;
for (unsigned int i = 0; i < 3; i++)
fprintf(stderr,
"%7.3f %7.3f %7.3f"
"%7.3f %7.3f %7.3f\n",
T1bErr[i],
T1aErr[i][0],
T1aErr[i][1],
T2bErr[i],
T2aErr[i][0],
T2aErr[i][1]);
}
/*
Create a linear system of equations for the intersection of the two calculated
planes. The system of equations is created in $A$ and $B$, which represents
$T1B+T1A\cdot (s, t)=T2B+T2A\cdot (s', t')$. Apply Gaussian elimination to
$A$ and $B$.
*/
double A[3][4]; //left side of equations
double B[3]; //right side of equations
double* Ap[3];
double Aerr[3][4];
double Berr[3];
double* ApErr[3];
for (unsigned int i = 0; i < 3; i++) {
A[i][0] = T1A[i][0];
Aerr[i][0] = T1aErr[i][0];
A[i][1] = T1A[i][1];
Aerr[i][1] = T1aErr[i][1];
A[i][2] = -T2A[i][0];
Aerr[i][2] = T2aErr[i][0];
A[i][3] = -T2A[i][1];
Aerr[i][3] = T2aErr[i][1];
B[i] = T2B[i]-T1B[i];
Berr[i] = T2bErr[i] + T1bErr[i];
Ap[i] = A[i];
ApErr[i] = Aerr[i];
}
GaussTransform(3, 4, Ap, B, ApErr, Berr);
/*
Now, the linear system of equation has the following format
\begin{eqnarray}
\begin{array}{ccc}
\begin{array}{cccc}
\ast & \ast & \ast & \ast \\
0 & \ast & \ast & \ast \\
0 & 0 & c1 & c2
\end{array} & \left| \begin{array}{c}
\ast \\
\ast \\
b
\end{array} \right.
\end{array}
\nonumber\end{eqnarray}
The asterisk denotes arbitrary values.
If $c1=0$, $c2=0$ and $b\ne0$, the two planes are parallel and not identical:
They do not intersect. If $c1=0$, $c2=0$ and $b=0$, the two planes are
identical and we have to check if the two trapeziums overlap.
*/
if (Ap[2][2] == 0 && Ap[2][3] == 0)
{
//The two planes are parallel.
//Check if it is the same plane:
if (B[2] == 0)
{
if (MR2_DEBUG)
cerr << "trapeziumsMayIntersect() "
<< "identical plane"
<< endl;
/*
The two planes are identical.
The trapeziums overlap if one of the segments of each trapezium, which is not
parallel to the $(x, y)$-plane, intersects with another of such segments
of the other trapezium.
If - because of the imprecision on the integer grid - the two planes are not
really identical but just almost parallel, the function will return true,
because segmentsMayIntersect will return true for at least one of the below
calls. Therefor we can ignore this kind of insecurity.
*/
GridPointSegment trapez1connecting1 =
trapezium1.getConnectingSegment1();
GridPointSegment trapez1connecting2 =
trapezium1.getConnectingSegment2();
GridPointSegment trapez2connecting1 =
trapezium2.getConnectingSegment1();
GridPointSegment trapez2connecting2 =
trapezium2.getConnectingSegment2();
if (segmentsMayIntersect
(dt, trapez1connecting1, trapez2connecting1)
|| segmentsMayIntersect
(dt, trapez1connecting1, trapez2connecting2)
|| segmentsMayIntersect
(dt, trapez1connecting2, trapez2connecting1)
|| segmentsMayIntersect
(dt, trapez1connecting2, trapez2connecting2))
{
if (MR2_DEBUG) {
cerr << "trapeziumsMayIntersect() "
<< "intersects"
<< endl;
cerr << ::std::fixed
<< ::std::setprecision(6);
for (unsigned int i = 0; i < 3; i++)
cerr <<Ap[i][0]<<" "
<<Ap[i][1]<<" "
<<Ap[i][2]<<" "
<<Ap[i][3]
<<"|"
<<B[i]
<<endl;
}
return true;
} else {
if (MR2_DEBUG)
cerr << "trapeziumsMayIntersect() "
<< "do not intersect"
<< endl;
return false;
}
} else {
//parallel, but not identical plane:
//No intersection possible if the
//distance between the two parallel planes
//is larger than the insecurity
//about the fact if they are really
//parallel or just almost...
if (ApErr[2][2] + ApErr[2][3] <
B[2] - Berr[2])
{
//There is a contradiction
//in the system of equations,
//and it is greater than
//the error about it!
if (MR2_DEBUG)
cerr << "trapeziumsMayIntersect()"
<< " parallel" << endl;
return false;
}
}
}
/*
Otherwise, the two planes intersect in a line, which we need to
calculate now. We have to consider the following cases: For $c1=0$, it
follows that $t'=b/c2$ with $s'$ arbitrary; for $c2=0$, it follows that
$s'=b/c1$ with $t'$ arbitrary; otherwise, it follows that
$s'=(b-c2\cdot t')/c1$ with $t'$ arbitrary.
Inserting $s'$ and $t'$ into the equation of the plane spanned by
trapezium 2 provides the equation of the intersection line, which we
will use in notation $P+Q\cdot u$.
*/
double P[3];
double Q[3];
double Perr[3];
double Qerr[3];
if (maybeEqual(Ap[2][2], 0, ApErr[2][2], 0))
{
/*
Case 1: $c1=0$.
*/
double f = B[2]/Ap[2][3]; // = b/c2
double fErr = Berr[2] * ApErr[2][3];
if (MR2_DEBUG)
cerr << "trapeziumsMayIntersect() c1=0 f="
<< f << "fErr = " << fErr
<< endl;
for (unsigned int i = 0; i < 3; i++)
{
P[i] = T2B[i]+T2A[i][1]*f;
Perr[i] = T2bErr[i] + T2aErr[i][i]*fErr;
Q[i] = T2A[i][0];
Qerr[i] = T2aErr[i][0];
}
} else if (maybeEqual(Ap[2][3], 0.0, ApErr[2][3], 0))
{
/*
Case 2: $c2=0$.
*/
double f = B[2]/Ap[2][2]; // = b/c1
double fErr = Berr[2] * ApErr[2][2];
if (MR2_DEBUG)
cerr << "trapeziumsMayIntersect() c2=0 f="
<< f << "fErr = " << fErr
<< endl;
for (unsigned int i = 0; i < 3; i++) {
P[i] = T2B[i]+T2A[i][0]*f;
Perr[i] = T2bErr[i] + T2aErr[i][0] * fErr;
Q[i] = T2A[i][1];
Qerr[i] = T2aErr[i][1];
}
} else
{
/*
Case 3: $c1\ne 0$ and $c2\ne 0$.
Inserting $s'=(b-c2\cdot t')/c1$ into $T2B+T2A\cdot (s', t')$ yields
\begin{eqnarray}
\left(
\begin{array}{c}
T2B[0] \\
T2B[1] \\
T2B[2]
\end{array}
\right)+\left(
\begin{array}{c}
T2A[0][0] \\
T2A[1][0] \\
T2A[2][0]
\end{array}
\right)\cdot (b-c2\cdot t')/c1+\left(
\begin{array}{c}
T2A[0][1] \\
T2A[1][1] \\
T2A[2][1]
\end{array}
\right)\cdot t'
\nonumber\end{eqnarray}
and
\begin{eqnarray}
\left(
\begin{array}{c}
T2B[0]+T2A[0][0]\cdot b/c1 \\
T2B[1]+T2A[1][0]\cdot b/c1 \\
T2B[2]+T2A[2][0]\cdot b/c1
\end{array}
\right)+
\left(
\begin{array}{c}
T2A[0][1]-T2A[0][0]\cdot c2/c1 \\
T2A[1][1]-T2A[1][0]\cdot c2/c1 \\
T2A[2][1]-T2A[2][0]\cdot c2/c1
\end{array}
\right)\cdot t'
\nonumber\end{eqnarray}
*/
double f1 = B[2]/Ap[2][2]; // = b/c1
double f2 = A[2][3]/Ap[2][2]; // = c2/c1
double f1Err = Berr[2] * ApErr[2][2];
double f2Err = Aerr[2][3] * ApErr[2][2];
if (MR2_DEBUG)
cerr << "trapeziumsMayIntersect() f1="
<< f1 << "f1Err = " << f1Err
<< " f2="
<< f2 << "f2Err = " << f2Err
<< endl;
for (unsigned int i = 0; i < 3; i++) {
P[i] = T2B[i]+T2A[i][0]*f1;
Q[i] = T2A[i][1]-T2A[i][0]*f2;
Perr[i] = T2bErr[i] + T2aErr[i][0] * f1Err;
Qerr[i] = T2aErr[i][1] + T2aErr[i][0] * f2Err;
}
if (MR2_DEBUG)
cerr << "trapeziumsMayIntersect(): "
<< "Intersection line is ("
<< P[0]
<< ", "
<< P[1]
<< ", "
<< P[2]
<< ")+("
<< Q[0]
<< ", "
<< Q[1]
<< ", "
<< Q[2]
<< ")*u"
<< "Errors: ("
<< Perr[0]
<< ", "
<< Perr[1]
<< ", "
<< Perr[2]
<< "), ("
<< Qerr[0]
<< ", "
<< Qerr[1]
<< ", "
<< Qerr[2]
<< ")."
<< endl;
}
/*
Now, we have to check whether the intersection line may intersect
at least with one of the segments of each trapezium.
If $Q[2]=0$, the intersection line is parallel to the $(x, y)$-plane.
*/
if (maybeEqual(Q[2], 0.0, Qerr[2], 0))
{
if (MR2_DEBUG)
cerr << "trapeziumsMayIntersect() intersection line "
<< "parallel to (x, y)-plane"
<< endl;
/*
Check whether the intersection line is within the z-Range covered by the two
trapeziums.
Here we need to be extremely careful, as the information that the line is
parallel to (x,y) in somewhat insecure due to the error in $Q[2]$. This
insecurity adds to the one of $P[2]$.
We take the length of the longer segment of the trapezium, and calculate how
much the z coordinate of the line can change on that length because of the maximal
possible error in $Q[2]$, and then we add this error to the one of $P[2]$.
*/
double segmentLength1 =
sqrt(trapezium1.segment1.point1.x *
trapezium1.segment1.point1.x +
trapezium1.segment1.point2.x *
trapezium1.segment1.point2.x);
double segmentLength2 =
sqrt(trapezium1.segment2.point1.x *
trapezium1.segment2.point1.x +
trapezium1.segment2.point2.x *
trapezium1.segment2.point2.x);
double segmentLength3 =
sqrt(trapezium2.segment1.point1.x *
trapezium2.segment1.point1.x +
trapezium2.segment1.point2.x *
trapezium2.segment1.point2.x);
double segmentLength4 =
sqrt(trapezium2.segment2.point1.x *
trapezium2.segment2.point1.x +
trapezium2.segment2.point2.x *
trapezium2.segment2.point2.x);
double maxLength = segmentLength1;
maxLength = segmentLength2 > maxLength ?
segmentLength2 : maxLength;
maxLength = segmentLength3 > maxLength ?
segmentLength3 : maxLength;
maxLength = segmentLength4 > maxLength ?
segmentLength4 : maxLength;
double maxError = Perr[2] + Qerr[2] *
maxLength / sqrt(Q[0]*Q[0] + Q[1]*Q[1] +
Q[2]*Q[2]);
if (isLower(P[2], 0, maxError, 1)
|| isLower(dt, P[2], 1, maxError))
{
if (MR2_DEBUG)
cerr << "trapeziumsMayIntersect() "
<< "no intersection"
<< endl;
return false;
}
/*
Calculate the points where the trapeziums' segments intersect with the
intersection line.
*/
double ip1x = trapezium1.segment1.point1.x +
(trapezium1.segment2.point1.x -
trapezium1.segment1.point1.x) * P[2]/dt;
double ip1y = trapezium1.segment1.point1.y +
(trapezium1.segment2.point1.y -
trapezium1.segment1.point1.y) * P[2]/dt;
double ip2x = trapezium1.segment1.point2.x +
(trapezium1.segment2.point2.x -
trapezium1.segment1.point2.x) * P[2]/dt;
double ip2y = trapezium1.segment1.point2.y +
(trapezium1.segment2.point2.y -
trapezium1.segment1.point2.y) * P[2]/dt;
double ip3x = trapezium2.segment1.point1.x +
(trapezium2.segment2.point1.x -
trapezium1.segment1.point1.x) * P[2]/dt;
double ip3y = trapezium2.segment1.point1.y +
(trapezium2.segment2.point1.y -
trapezium1.segment1.point1.y) * P[2]/dt;
double ip4x = trapezium2.segment1.point2.x +
(trapezium2.segment2.point2.x -
trapezium2.segment1.point2.x) * P[2]/dt;
double ip4y = trapezium2.segment1.point2.y +
(trapezium2.segment2.point2.y -
trapezium2.segment1.point2.y) * P[2]/dt;
double intersectionPointError = 1 + (2*Perr[2]);
//same for x and y and for all points
/*
Check for overlaps of the bounding boxes of the two intersection segments.
If they overlap, the sections may intersect.
*/
double ip1ip2MinX = ip1x < ip2x ? ip1x : ip2x;
double ip1ip2MaxX = ip1x > ip2x ? ip1x : ip2x;
double ip1ip2MinY = ip1y < ip2y ? ip1y : ip2y;
double ip1ip2MaxY = ip1y > ip2y ? ip1y : ip2y;
double ip3ip4MinX = ip3x < ip4x ? ip3x : ip4x;
double ip3ip4MaxX = ip3x > ip4x ? ip3x : ip4x;
double ip3ip4MinY = ip3y < ip4y ? ip3y : ip4y;
double ip3ip4MaxY = ip3y > ip4y ? ip3y : ip4y;
if (isLower(ip1ip2MaxX, ip3ip4MinX,
intersectionPointError, intersectionPointError)
|| isLower(ip3ip4MaxX, ip1ip2MinX,
intersectionPointError, intersectionPointError)
|| isLower(ip1ip2MaxY, ip3ip4MinY,
intersectionPointError, intersectionPointError)
|| isLower(ip3ip4MaxY, ip1ip2MinY,
intersectionPointError,intersectionPointError))
{
if (MR2_DEBUG)
cerr << "trapeziumsMayIntersect() "
<< "no intersection"
<< endl;
return false;
} else
{
if (MR2_DEBUG)
cerr << "trapeziumsMayIntersect() "
<< "trapeziums intersect"
<< endl;
return true;
}
} else
{
/*
Intersection line hits $(x, y)$-plane in $(P[0], P[1], 0)$ and the
plane parallel to $(x, y)$-plane in distance $dt$ in
$(P[0]+Q[0], P[1]+Q[1], dt)$ as we have handled the case $Q[2]=0$
separately.
*/
double zMin;
double zMax;
double t1zMin = dt;
double t1zMax = 0;
bool t1Intersects = false;
if (segmentAndLineMayIntersect
(0, trapezium1.segment1, P, Q, Perr, Qerr)) {
t1zMin = t1zMin > 0 ? 0 : t1zMin;
t1zMax = t1zMax < 0 ? 0 : t1zMax;
t1Intersects = true;
}
if (segmentAndLineMayIntersect
(dt, trapezium1.segment2, P, Q, Perr, Qerr)) {
t1zMin = t1zMin > dt ? dt : t1zMin;
t1zMax = t1zMax < dt ? dt : t1zMax;
t1Intersects = true;
}
ProvisionalSegment connectingSegment1 =
trapezium1.getConnectingSegment1().
transformToProvisional();
ProvisionalSegment connectingSegment2 =
trapezium1.getConnectingSegment2().
transformToProvisional();
ProvisionalPoint point1(P[0], P[1], Perr[0], Perr[1]);
ProvisionalPoint point2(P[0]+Q[0], P[1]+Q[1], Perr[0]
+Qerr[0], Perr[1]+Qerr[1]);
ProvisionalSegment lineSegment(point1, point2);
if (segmentsMayIntersect
(dt, connectingSegment1, lineSegment,
zMin, zMax)) {
t1zMin = t1zMin > zMin ? zMin : t1zMin;
t1zMax = t1zMax < zMax ? zMax : t1zMax;
t1Intersects = true;
}
if (segmentsMayIntersect
(dt, connectingSegment2, lineSegment,
zMin, zMax)) {
t1zMin = t1zMin > zMin ? zMin : t1zMin;
t1zMax = t1zMax < zMax ? zMax : t1zMax;
t1Intersects = true;
}
double t2zMin = dt;
double t2zMax = 0;
bool t2Intersects = false;
if (segmentAndLineMayIntersect
(0, trapezium2.segment1, P, Q, Perr, Qerr)) {
t2zMin = t2zMin > 0 ? 0 : t2zMin;
t2zMax = t2zMax < 0 ? 0 : t2zMax;
t2Intersects = true;
}
if (segmentAndLineMayIntersect
(dt, trapezium2.segment2, P, Q, Perr, Qerr)) {
t2zMin = t2zMin > dt ? dt : t2zMin;
t2zMax = t2zMax < dt ? dt : t2zMax;
t2Intersects = true;
}
ProvisionalSegment connectingSegment3 =
trapezium2.getConnectingSegment1().
transformToProvisional();
ProvisionalSegment connectingSegment4 =
trapezium2.getConnectingSegment2().
transformToProvisional();
if (segmentsMayIntersect
(dt, connectingSegment3, lineSegment, zMin,
zMax)) {
t2zMin = t2zMin > zMin ? zMin : t2zMin;
t2zMax = t2zMax < zMax ? zMax : t2zMax;
t2Intersects = true;
}
if (segmentsMayIntersect
(dt, connectingSegment4, lineSegment, zMin,
zMax)) {
t2zMin = t2zMin > zMin ? zMin : t2zMin;
t2zMax = t2zMax < zMax ? zMax : t2zMax;
t2Intersects = true;
}
if (MR2_DEBUG) {
cerr << "trapeziumsMayIntersect() dt="
<< dt
<< endl;
cerr << "trapeziumsMayIntersect() t1Intersects="
<< t1Intersects
<< endl;
if (t1Intersects)
cerr << "trapeziumsMayIntersect() t1zMin="
<< t1zMin
<< " t1zMax="
<< t1zMax
<< endl;
cerr << "trapeziumsMayIntersect() t2Intersects="
<< t2Intersects
<< endl;
if (t2Intersects)
cerr << "trapeziumsMayIntersect() t2zMin="
<< t2zMin
<< " t2zMax="
<< t2zMax
<< endl;
}
if (t1Intersects
&& t2Intersects
&& !(t1zMax < t2zMin || t2zMax < t1zMin)
&& !(t1zMax == 0.0 && t1zMin == 0.0
&& t2zMax == 0.0 && t2zMin == 0.0)
&& !(t1zMax == dt && t1zMin == dt
&& t2zMax == dt && t2zMin == dt))
{
if (MR2_DEBUG)
cerr << "trapeziumsMayIntersect() intersect"
<< endl;
return true;
} else
{
if (MR2_DEBUG)
cerr << "trapeziumsMayIntersect() "
<< "no intersection"
<< endl;
return false;
}
}
}
/*
1.1.1.1 Function ~preciseTrapeziumsIntersect()~
Returns ~true~ if the specified trapeziums intersect
in three-dimensional space $(x, y, t)$.
*/
static bool preciseTrapeziumsIntersect(
mpq_class dt,
PreciseTrapezium trapezium1,
PreciseTrapezium trapezium2) {
/*
First, lets see if the trapeziums are equal or touch in one segment.
*/
if (trapezium1 == trapezium2 || touching(trapezium1, trapezium2))
{
return false;
}
/*
The segments do not touch in one segment and are not equal.
To determine if they really intersect, we first calculate the
intersection of the two planes spanned by the trapezium.
Create equations for the two planes spanned by the trapeziums,
considering that one edge of
each trapezium may be a single point: Plane 1 is
$T1B+T1A\cdot (s, t)$ and Plane 2 is $T2B+T1A\cdot (s', t')$.
*/
mpq_class T1A[3][2]; //left side of equations for trapezium1
mpq_class T1B[3]; //right side of equations for trapezium1
if (trapezium1.segment1.point1 == trapezium1.segment1.point2)
{
//Trapezium1 is a triangle, the first segment
//is just a point - we use the second segment instead
T1A[0][0] = trapezium1.segment2.point2.x
- trapezium1.segment2.point1.x;
T1A[1][0] = trapezium1.segment2.point2.y
- trapezium1.segment2.point1.y;
T1A[2][0] = 0;
T1A[0][1] = trapezium1.segment1.point1.x
- trapezium1.segment2.point1.x;
T1A[1][1] = trapezium1.segment1.point1.y
- trapezium1.segment2.point1.y;
T1A[2][1] = -dt;
T1B[0] = trapezium1.segment2.point1.x;
T1B[1] = trapezium1.segment2.point1.y;
T1B[2] = dt;
} else {
//The first segment is no point, we can use it
T1A[0][0] = trapezium1.segment1.point2.x
- trapezium1.segment1.point1.x;
T1A[1][0] = trapezium1.segment1.point2.y
- trapezium1.segment1.point1.y;
T1A[2][0] = 0;
T1A[0][1] = trapezium1.segment2.point1.x
- trapezium1.segment1.point1.x;
T1A[1][1] = trapezium1.segment2.point1.y
- trapezium1.segment1.point1.y;
T1A[2][1] = dt;
T1B[0] = trapezium1.segment1.point1.x;
T1B[1] = trapezium1.segment1.point1.y;
T1B[2] = 0;
}
mpq_class T2A[3][2]; //left side of equations for trapezium2
mpq_class T2B[3]; //right side of equations for trapezium2
if (trapezium2.segment1.point1 == trapezium2.segment1.point2)
{
//Trapezium2 is a triangle, the first segment
//is just a point - we use segment 2 instead
T2A[0][0] = trapezium2.segment2.point2.x
- trapezium2.segment2.point1.x;
T2A[1][0] = trapezium2.segment2.point2.y
- trapezium2.segment2.point1.y;
T2A[2][0] = 0;
T2A[0][1] = trapezium2.segment1.point1.x
- trapezium2.segment2.point1.x;
T2A[1][1] = trapezium2.segment1.point1.y
- trapezium2.segment2.point1.y;
T2A[2][1] = -dt;
T2B[0] = trapezium2.segment2.point1.x;
T2B[1] = trapezium2.segment2.point1.y;
T2B[2] = dt;
} else {
//The first segment is no point, so we can use it
T2A[0][0] = trapezium2.segment1.point2.x
- trapezium2.segment1.point1.x;
T2A[1][0] = trapezium2.segment1.point2.y
- trapezium2.segment1.point1.y;
T2A[2][0] = 0;
T2A[0][1] = trapezium2.segment2.point1.x
- trapezium2.segment1.point1.x;
T2A[1][1] = trapezium2.segment2.point1.y
- trapezium2.segment1.point1.y;
T2A[2][1] = dt;
T2B[0] = trapezium2.segment1.point1.x;
T2B[1] = trapezium2.segment1.point1.y;
T2B[2] = 0;
}
if (MR2_DEBUG) {
cerr << "Creating system of equations."
<< endl;
}
/*
Create a linear system of equations for the intersection of the two calculated
planes. The system of equations is created in $A$ and $B$, which represents
$T1B+T1A\cdot (s, t)=T2B+T2A\cdot (s', t')$. Apply Gaussian elimination to
$A$ and $B$.
*/
mpq_class A[3][4]; //left side of equations
mpq_class B[3]; //right side of equations
mpq_class* Ap[3];
for (unsigned int i = 0; i < 3; i++) {
A[i][0] = T1A[i][0];
A[i][1] = T1A[i][1];
A[i][2] = -T2A[i][0];
A[i][3] = -T2A[i][1];
B[i] = T2B[i]-T1B[i];
Ap[i] = A[i];
}
GaussTransform(3, 4, Ap, B);
/*
Now, the linear system of equation has the following format
\begin{eqnarray}
\begin{array}{ccc}
\begin{array}{cccc}
\ast & \ast & \ast & \ast \\
0 & \ast & \ast & \ast \\
0 & 0 & c1 & c2
\end{array} & \left| \begin{array}{c}
\ast \\
\ast \\
b
\end{array} \right.
\end{array}
\nonumber\end{eqnarray}
The asterisk denotes arbitrary values.
If $c1=0$, $c2=0$ and $b\ne0$, the two planes are parallel and not identical:
They do not intersect. If $c1=0$, $c2=0$ and $b=0$, the two planes are
identical and we have to check if the two trapeziums overlap.
*/
if (cmp(Ap[2][2], 0) == 0 && cmp(Ap[2][3], 0) == 0)
{
//The two planes are parallel.
//Check if it is the same plane:
if (cmp(B[2], 0) == 0)
{
if (MR2_DEBUG)
cerr << "preciseTrapeziumsIntersect() "
<< "identical plane"
<< endl;
/*
The two planes are identical.
The trapeziums overlap if one of the segments of each trapezium, which is not
parallel to the $(x, y)$-plane, intersects with another of such segments
of the other trapezium.
If - because of the imprecision on the integer grid - the two planes are not
really identical but just almost parallel, the function will return true,
because segmentsMayIntersect will return true for at least one of the below
calls. Therefor we can ignore this kind of insecurity.
*/
PreciseSegment trapez1connecting1 =
trapezium1.getConnectingSegment1();
PreciseSegment trapez1connecting2 =
trapezium1.getConnectingSegment2();
PreciseSegment trapez2connecting1 =
trapezium2.getConnectingSegment1();
PreciseSegment trapez2connecting2 =
trapezium2.getConnectingSegment2();
if (preciseSegmentsIntersect(dt,
trapez1connecting1, trapez2connecting1)
|| preciseSegmentsIntersect(dt,
trapez1connecting1, trapez2connecting2)
|| preciseSegmentsIntersect(dt,
trapez1connecting2, trapez2connecting1)
|| preciseSegmentsIntersect(dt,
trapez1connecting2, trapez2connecting2))
{
if (MR2_DEBUG) {
cerr << "preciseTrapeziumsIntersect()"
<< " intersect"
<< endl;
}
return true;
} else {
if (MR2_DEBUG)
cerr << "preciseTrapeziumsIntersect() "
<< "do not intersect"
<< endl;
return false;
}
} else {
//parallel, but not identical plane:
//No intersection possible
if (MR2_DEBUG)
cerr << "preciseTrapeziumsIntersect()"
<< " parallel"
<< endl;
return false;
}
}
/*
Otherwise, the two planes intersect in a line, which we need to
calculate now. We have to consider the following cases: For $c1=0$, it
follows that $t'=b/c2$ with $s'$ arbitrary; for $c2=0$, it follows that
$s'=b/c1$ with $t'$ arbitrary; otherwise, it follows that
$s'=(b-c2\cdot t')/c1$ with $t'$ arbitrary.
Inserting $s'$ and $t'$ into the equation of the plane spanned by
trapezium 2 provides the equation of the intersection line, which we
will use in notation $P+Q\cdot u$.
*/
mpq_class P[3];
mpq_class Q[3];
if (cmp(Ap[2][2], 0) == 0)
{
/*
Case 1: $c1=0$.
*/
mpq_class f = B[2]/Ap[2][3]; // = b/c2
if (MR2_DEBUG)
cerr << "preciseTrapeziumsIntersect() c1=0 f="
<< f
<< endl;
for (unsigned int i = 0; i < 3; i++)
{
P[i] = T2B[i]+T2A[i][1]*f;
Q[i] = T2A[i][0];
}
} else if (cmp(Ap[2][3], 0) ==0)
{
/*
Case 2: $c2=0$.
*/
mpq_class f = B[2]/Ap[2][2]; // = b/c1
if (MR2_DEBUG)
cerr << "preciseTrapeziumsIntersect() c2=0 f="
<< f
<< endl;
for (unsigned int i = 0; i < 3; i++) {
P[i] = T2B[i]+T2A[i][0]*f;
Q[i] = T2A[i][1];
}
} else
{
/*
Case 3: $c1\ne 0$ and $c2\ne 0$.
Inserting $s'=(b-c2\cdot t')/c1$ into $T2B+T2A\cdot (s', t')$ yields
\begin{eqnarray}
\left(
\begin{array}{c}
T2B[0] \\
T2B[1] \\
T2B[2]
\end{array}
\right)+\left(
\begin{array}{c}
T2A[0][0] \\
T2A[1][0] \\
T2A[2][0]
\end{array}
\right)\cdot (b-c2\cdot t')/c1+\left(
\begin{array}{c}
T2A[0][1] \\
T2A[1][1] \\
T2A[2][1]
\end{array}
\right)\cdot t'
\nonumber\end{eqnarray}
and
\begin{eqnarray}
\left(
\begin{array}{c}
T2B[0]+T2A[0][0]\cdot b/c1 \\
T2B[1]+T2A[1][0]\cdot b/c1 \\
T2B[2]+T2A[2][0]\cdot b/c1
\end{array}
\right)+
\left(
\begin{array}{c}
T2A[0][1]-T2A[0][0]\cdot c2/c1 \\
T2A[1][1]-T2A[1][0]\cdot c2/c1 \\
T2A[2][1]-T2A[2][0]\cdot c2/c1
\end{array}
\right)\cdot t'
\nonumber\end{eqnarray}
*/
mpq_class f1 = B[2]/Ap[2][2]; // = b/c1
mpq_class f2 = A[2][3]/Ap[2][2]; // = c2/c1
if (MR2_DEBUG)
cerr << "preciseTrapeziumsIntersect() f1="
<< f1
<< " f2="
<< f2
<< endl;
for (unsigned int i = 0; i < 3; i++) {
P[i] = T2B[i]+T2A[i][0]*f1;
Q[i] = T2A[i][1]-T2A[i][0]*f2;
}
}
/*
Now, we have to check whether the intersection line may intersect
at least with one of the segments of each trapezium.
If $Q[2]=0$, the intersection line is parallel to the $(x, y)$-plane.
*/
if (cmp(Q[2], 0) == 0)
{
if (MR2_DEBUG)
cerr << "preciseTrapeziumsIntersect()"
<< " intersection line "
<< "parallel to (x, y)-plane"
<< endl;
/*
Check whether the intersection line is within the z-Range covered by the two
trapeziums.
*/
if (cmp(P[2], 0) <= 0 || cmp(dt, P[2]) <= 0) {
if (MR2_DEBUG)
cerr << "preciseTrapeziumsIntersect() "
<< "no intersection"
<< endl;
return false;
}
/*
Calculate the points where the trapeziums' segments intersect with the
intersection line.
*/
mpq_class ip1x = trapezium1.segment1.point1.x
+ (trapezium1.segment2.point1.x
- trapezium1.segment1.point1.x) * P[2]/dt;
mpq_class ip1y = trapezium1.segment1.point1.y
+ (trapezium1.segment2.point1.y
- trapezium1.segment1.point1.y) * P[2]/dt;
mpq_class ip2x = trapezium1.segment1.point2.x
+ (trapezium1.segment2.point2.x
- trapezium1.segment1.point2.x) * P[2]/dt;
mpq_class ip2y = trapezium1.segment1.point2.y
+ (trapezium1.segment2.point2.y
- trapezium1.segment1.point2.y) * P[2]/dt;
mpq_class ip3x = trapezium2.segment1.point1.x
+ (trapezium2.segment2.point1.x
- trapezium1.segment1.point1.x) * P[2]/dt;
mpq_class ip3y = trapezium2.segment1.point1.y
+ (trapezium2.segment2.point1.y
- trapezium1.segment1.point1.y) * P[2]/dt;
mpq_class ip4x = trapezium2.segment1.point2.x
+ (trapezium2.segment2.point2.x
- trapezium2.segment1.point2.x) * P[2]/dt;
mpq_class ip4y = trapezium2.segment1.point2.y
+ (trapezium2.segment2.point2.y
- trapezium2.segment1.point2.y) * P[2]/dt;
/*
Check for overlaps of the bounding boxes of the two intersection segments.
If they overlap, the sections may intersect.
*/
mpq_class ip1ip2MinX = cmp(ip1x, ip2x) < 0 ?
ip1x : ip2x;
mpq_class ip1ip2MaxX = cmp(ip1x, ip2x) > 0 ?
ip1x : ip2x;
mpq_class ip1ip2MinY = cmp(ip1y, ip2y) < 0 ?
ip1y : ip2y;
mpq_class ip1ip2MaxY = cmp(ip1y, ip2y) > 0 ?
ip1y : ip2y;
mpq_class ip3ip4MinX = cmp(ip3x, ip4x) < 0 ?
ip3x : ip4x;
mpq_class ip3ip4MaxX = cmp(ip3x, ip4x) > 0 ?
ip3x : ip4x;
mpq_class ip3ip4MinY = cmp(ip3y, ip4y) < 0 ?
ip3y : ip4y;
mpq_class ip3ip4MaxY = cmp(ip3y, ip4y) > 0 ?
ip3y : ip4y;
if (cmp(ip1ip2MaxX, ip3ip4MinX) < 0
|| cmp(ip3ip4MaxX, ip1ip2MinX) < 0
|| cmp(ip1ip2MaxY, ip3ip4MinY) < 0
|| cmp(ip3ip4MaxY, ip1ip2MinY) < 0)
{
if (MR2_DEBUG)
cerr << "preciseTrapeziumsIntersect() "
<< "no intersection"
<< endl;
return false;
} else
{
if (MR2_DEBUG)
cerr << "preciseTrapeziumsIntersect() "
<< "trapeziums intersect"
<< endl;
return true;
}
} else
{
/*
Intersection line hits $(x, y)$-plane in $(P[0], P[1], 0)$ and the
plane parallel to $(x, y)$-plane in distance $dt$ in
$(P[0]+Q[0], P[1]+Q[1], dt)$ as we have handled the case $Q[2]=0$
separately.
*/
mpq_class z;
mpq_class t1zMin = dt;
mpq_class t1zMax = 0;
bool t1Intersects = false;
if (preciseSegmentAndLineIntersect
(0, trapezium1.segment1, P, Q)) {
t1zMin = cmp(t1zMin, 0) > 0 ? 0 : t1zMin;
t1zMax = cmp(t1zMax, 0) < 0 ? 0 : t1zMax;
t1Intersects = true;
}
if (preciseSegmentAndLineIntersect
(dt, trapezium1.segment2, P, Q)) {
t1zMin = cmp(t1zMin, dt) > 0 ? dt : t1zMin;
t1zMax = cmp(t1zMax, dt) < 0 ? dt : t1zMax;
t1Intersects = true;
}
PreciseSegment connectingSegment1 =
trapezium1.getConnectingSegment1();
PreciseSegment connectingSegment2 =
trapezium1.getConnectingSegment2();
PrecisePoint point1(P[0], P[1]);
PrecisePoint point2(P[0]+Q[0], P[1]+Q[1]);
PreciseSegment lineSegment(point1, point2);
if (preciseSegmentsIntersect
(dt, connectingSegment1, lineSegment, z)) {
t1zMin = cmp(t1zMin, z) > 0 ? z : t1zMin;
t1zMax = cmp(t1zMax, z) < 0 ? z : t1zMax;
t1Intersects = true;
}
if (preciseSegmentsIntersect
(dt, connectingSegment2, lineSegment, z)) {
t1zMin = cmp(t1zMin, z) > 0 ? z : t1zMin;
t1zMax = cmp(t1zMax, z) < 0 ? z : t1zMax;
t1Intersects = true;
}
mpq_class t2zMin = dt;
mpq_class t2zMax = 0;
bool t2Intersects = false;
if (preciseSegmentAndLineIntersect(0,
trapezium2.segment1, P, Q)) {
t2zMin = cmp(t2zMin, 0) > 0 ? 0 : t2zMin;
t2zMax = cmp(t2zMax, 0) < 0 ? 0 : t2zMax;
t2Intersects = true;
}
if (preciseSegmentAndLineIntersect(dt,
trapezium2.segment2, P, Q)) {
t2zMin = cmp(t2zMin, dt) > 0 ? dt : t2zMin;
t2zMax = cmp(t2zMax, dt) < 0 ? dt : t2zMax;
t2Intersects = true;
}
PreciseSegment connectingSegment3 =
trapezium2.getConnectingSegment1();
PreciseSegment connectingSegment4 =
trapezium2.getConnectingSegment2();
if (preciseSegmentsIntersect
(dt, connectingSegment3, lineSegment, z)) {
t2zMin = cmp(t2zMin, z) > 0 ? z : t2zMin;
t2zMax = cmp(t2zMax, z) < 0 ? z : t2zMax;
t2Intersects = true;
}
if (preciseSegmentsIntersect
(dt, connectingSegment4, lineSegment, z)) {
t2zMin = cmp(t2zMin, z) > 0 ? z : t2zMin;
t2zMax = cmp(t2zMax, z) < 0 ? z : t2zMax;
t2Intersects = true;
}
if (MR2_DEBUG) {
cerr << "preciseTrapeziumsIntersect() "
<< "t1Intersects="
<< t1Intersects
<< endl;
if (t1Intersects)
cerr << "preciseTrapeziumsIntersect() "
<< "t2Intersects="
<< t2Intersects
<< endl;
}
if (t1Intersects
&& t2Intersects
&& !(cmp(t1zMax, t2zMin) < 0
|| cmp(t2zMax, t1zMin) < 0)
&& !(cmp(t1zMax, 0) == 0
&& cmp(t1zMin, 0) == 0
&& cmp(t2zMax, 0) == 0
&& cmp(t2zMin, 0) == 0)
&& !(cmp(t1zMax, dt) == 0
&& cmp(t1zMin, dt) == 0
&& cmp(t2zMax, dt) == 0
&& cmp(t2zMin, dt) == 0))
{
if (MR2_DEBUG)
cerr << "preciseTrapeziumsIntersect() "
<< "intersect"
<< endl;
return true;
} else
{
if (MR2_DEBUG)
cerr << "preciseTrapeziumsIntersect() "
<< "no intersection"
<< endl;
return false;
}
}
}
/*
1.1.1 Intersections between segments and trapeziums
1.1.1.1 Function ~segmentAndTrapeziumMayIntersect()~
1.1.1.1 Function ~preciseSegmentAndTrapeziumIntersect()~
1.1.1 Relative positions of points and segments
1.1.1.1 Function ~maybeInside()~
*/
bool maybeInside(int tPoint,
GridPoint point,
int t1Trapezium,
int t2Trapezium,
GridPointTrapezium trapezium) {
if (MR2_DEBUG) cerr << "maybeInside() called" << endl;
/*
Check if $t1Trapezium <= tPoint <= t2Trapezium$ or $t2Trapezium <= tPoint < t1Trapezium$ holds.
If not, no intersection can occur.
*/
if (!(lowerOrMaybeEqual(t1Trapezium, tPoint, 1, 1)
&& lowerOrMaybeEqual(tPoint, t2Trapezium, 1, 1))
&& !(lowerOrMaybeEqual(t2Trapezium, tPoint, 1, 1)
&& lowerOrMaybeEqual(tPoint, t1Trapezium, 1, 1))) {
if (MR2_DEBUG) cerr << "sIPT() t check failed" << endl;
return false;
}
if (MR2_DEBUG) cerr << "maybeInside() t check succeeded" << endl;
/*
Calculate the segment parallel to segment1 and segment2 of the trapezium and
at instant tPoint, which will be between the two of the trapeziums segments.
*/
ProvisionalPoint point1(trapezium.segment1.point1.x,
trapezium.segment1.point1.y, 1, 1);
ProvisionalPoint point2(trapezium.segment1.point2.x,
trapezium.segment1.point2.y, 1, 1);
ProvisionalSegment segment(point1, point2);
if (maybeEqual(t1Trapezium, t2Trapezium, 1, 1)) {
segment.point1.x = trapezium.segment1.point1.x;
segment.point1.y = trapezium.segment1.point1.y;
segment.point2.x = trapezium.segment1.point2.x;
segment.point2.y = trapezium.segment1.point2.y;
} else {
double f = (tPoint-t1Trapezium)/(t2Trapezium-t1Trapezium);
double fErr = 4;
if (MR2_DEBUG) cerr << "maybeInside() f=" << f << endl;
segment.point1.x = trapezium.segment1.point1.x
+ (trapezium.segment2.point1.x
- trapezium.segment1.point1.x) * f;
segment.point1.y = trapezium.segment1.point1.y
+ (trapezium.segment2.point1.y
- trapezium.segment1.point1.y) * f;
segment.point2.x = trapezium.segment1.point2.x
+ (trapezium.segment2.point2.x
- trapezium.segment1.point2.x) * f;
segment.point2.y = trapezium.segment1.point2.y
+ (trapezium.segment2.point2.y
+ trapezium.segment1.point2.y) * f;
segment.point1.xErr = 1+2*fErr;
segment.point2.xErr = 1+2*fErr;
segment.point1.yErr = 1+2*fErr;
segment.point2.yErr = 1+2*fErr;
}
if (MR2_DEBUG)
cerr << "maybeEqual() x1=" << segment.point1.x
<< " y1=" << segment.point1.y
<< " x2=" << segment.point2.x
<< " y2=" << segment.point2.y
<< endl;
/*
If the point maybe located on this resulting segment, the point may also be
inside the trapezium, and it is for sure outside otherwise.
*/
if (((lowerOrMaybeEqual(segment.point1.x, point.x, 9, 1)
&& lowerOrMaybeEqual(point.x, segment.point2.x, 1, 9))
|| (lowerOrMaybeEqual(segment.point2.x, point.x, 9, 1)
&& lowerOrMaybeEqual(point.x, segment.point1.x, 1, 9)))
&& ((lowerOrMaybeEqual(segment.point1.y, point.y, 9, 1)
&& lowerOrMaybeEqual(point.y, segment.point2.y, 1, 9))
|| (lowerOrMaybeEqual(segment.point2.y, point.y, 9, 1)
&& lowerOrMaybeEqual(point.y, segment.point1.y,
1, 9)))) {
if (MR2_DEBUG) cerr << "maybeInside() inside" << endl;
return true;
} else {
if (MR2_DEBUG) cerr << "maybeInside() not inside" << endl;
return false;
}
}
/*
1.1.1.1 Function ~preciseInside()~
*/
bool preciseInside(mpq_class tPoint,
PrecisePoint point,
mpq_class t1Trapezium,
mpq_class t2Trapezium,
PreciseTrapezium trapezium) {
if (MR2_DEBUG) cerr << "preciseInside() called" << endl;
/*
Check if $t1Trapezium <= tPoint <= t2Trapezium$ or $t2Trapezium <= tPoint < t1Trapezium$ holds.
If not, no intersection can occur.
*/
if (!(cmp(t1Trapezium, tPoint) <= 0
&& cmp(tPoint, t2Trapezium) <= 0 )
&& !(cmp(t2Trapezium, tPoint) <= 0
&& cmp(tPoint, t1Trapezium) <= 0))
{
if (MR2_DEBUG)
cerr << "preciseInside() t check failed" << endl;
return false;
}
if (MR2_DEBUG)
cerr << "preciseInside() t check succeeded" << endl;
/*
Calculate the segment parallel to segment1 and segment2 of the trapezium and
at instant tPoint, which will be between the two of the trapeziums segments.
*/
PrecisePoint point1(trapezium.segment1.point1.x,
trapezium.segment1.point1.y);
PrecisePoint point2(trapezium.segment1.point2.x,
trapezium.segment1.point2.y);
PreciseSegment segment(point1, point2);
if (cmp(t1Trapezium, t2Trapezium) != 0) {
mpq_class f =
(tPoint-t1Trapezium)/(t2Trapezium-t1Trapezium);
if (MR2_DEBUG) cerr << "preciseInside() f=" << f << endl;
segment.point1.x = trapezium.segment1.point1.x
+ (trapezium.segment2.point1.x
- trapezium.segment1.point1.x) * f;
segment.point1.y = trapezium.segment1.point1.y
+ (trapezium.segment2.point1.y
- trapezium.segment1.point1.y) * f;
segment.point2.x = trapezium.segment1.point2.x
+ (trapezium.segment2.point2.x
- trapezium.segment1.point2.x) * f;
segment.point2.y = trapezium.segment1.point2.y
+ (trapezium.segment2.point2.y
- trapezium.segment1.point2.y) * f;
}
if (MR2_DEBUG)
cerr << "preciseInside() x1=" << segment.point1.x
<< " y1=" << segment.point1.y
<< " x2=" << segment.point2.x
<< " y2=" << segment.point2.y
<< endl;
/*
If the point is located on this resulting segment, it is also
inside the trapezium, and outside otherwise.
*/
if (((cmp(segment.point1.x, point.x) <= 0
&& cmp(point.x, segment.point2.x) <= 0)
|| (cmp(segment.point2.x, point.x) <= 0
&& cmp(point.x, segment.point1.x) <= 0))
&& ((cmp(segment.point1.y, point.y) <= 0
&& cmp(point.y, segment.point2.y) <= 0)
|| (cmp(segment.point2.y, point.y) <= 0
&& cmp(point.y, segment.point1.y) <= 0))) {
if (MR2_DEBUG) cerr << "preciseInside() inside" << endl;
return true;
} else {
if (MR2_DEBUG)
cerr << "preciseInside() not inside"
<< endl;
return false;
}
}
/*
1.1.1 Relative positions of points and trapeziums
1.1.1.1 Function ~maybeLeftOrAbove()~
*/
static bool maybeLeftOrAbove(GridPoint point,
GridPointSegment segment) {
if (MR2_DEBUG)
cerr << "maybeLeftOrAbove() called p=("
<< point.x << " " << point.y
<< ") p1=(" << segment.point1.x
<< " " << segment.point1.y
<< ") p2=(" << segment.point2.x << " "
<< segment.point2.y << ")"
<< endl;
if (maybeEqual(segment.point1.x, segment.point2.x, 1, 1)) {
if (MR2_DEBUG)
cerr << "maybeLeftOrAbove() segment is horizontal"
<< endl;
return lowerOrMaybeEqual(point.x, segment.point1.x, 1, 1);
} else if (maybeEqual(segment.point1.y, segment.point2.y, 1, 1)) {
if (MR2_DEBUG)
cerr << "maybeLeftOrAbove() segment is vertical"
<< endl;
return greaterOrMaybeEqual(point.y, segment.point1.y, 1, 1);
} else {
if (MR2_DEBUG)
cerr << "maybeLeftOrAbove() "
<< "segment is not horizontal nor vertical"
<< endl;
double t = (point.x- segment.point1.x)/(segment.point2.x
- segment.point1.x); //maxError 4
double py = segment.point1.y + (segment.point2.y
- segment.point1.y) * t; //maxError 9
if (MR2_DEBUG)
cerr << "maybeLeftOrAbove() py=" << py << endl;
return greaterOrMaybeEqual(point.y, py, 1, 9);
}
}
/*
1.1.1.1 Function ~preciseLeftOrAbove()~
*/
static bool preciseLeftOrAbove(PrecisePoint point,
PreciseSegment segment) {
if (MR2_DEBUG)
cerr << "preciseLeftOrAbove() called p=("
<< point.x << " " << point.y
<< ") p1=(" << segment.point1.x << " "
<< segment.point1.y
<< ") p2=(" << segment.point2.x << " "
<< segment.point2.y << ")"
<< endl;
if (cmp(segment.point1.x, segment.point2.x) == 0) {
if (MR2_DEBUG)
cerr << "preciseLeftOrAbove() segment is horizontal"
<< endl;
return cmp(point.x, segment.point1.x) <= 0;
} else if (cmp(segment.point1.y, segment.point2.y) == 0) {
if (MR2_DEBUG)
cerr << "preciseLeftOrAbove() segment is vertical"
<< endl;
return cmp(point.y, segment.point1.y) >= 0;
} else {
if (MR2_DEBUG)
cerr << "preciseLeftOrAbove() segment is not "
<< "horizontal nor vertical" << endl;
mpq_class t = (point.x- segment.point1.x)/
(segment.point2.x - segment.point1.x);
mpq_class py = segment.point1.y +
(segment.point2.y - segment.point1.y) * t;
if (MR2_DEBUG)
cerr << "preciseLeftOrAbove() py=" << py << endl;
return cmp(point.y, py) >= 0;
}
}
/*
1.1 Other helper functions
1.1.1 Function ~restrictUPointToInterval()~
*/
static void restrictUPointToInterval(const UPoint& up,
const Interval<Instant> iv,
UPoint& rUp) {
if (MR2_DEBUG)
cerr << "restrictUPointToInterval() called" << endl;
if (nearlyEqual(iv.start.ToDouble(), iv.end.ToDouble()))
rUp = up;
else {
double ti =
(iv.start.ToDouble()
-up.timeInterval.start.ToDouble())
/(up.timeInterval.end.ToDouble()
-up.timeInterval.start.ToDouble());
double tf =
(iv.end.ToDouble()
-up.timeInterval.start.ToDouble())
/(up.timeInterval.end.ToDouble()
-up.timeInterval.start.ToDouble());
UPoint dummy(
iv,
up.p0.GetX()+(up.p1.GetX()-up.p0.GetX())*ti,
up.p0.GetY()+(up.p1.GetY()-up.p0.GetY())*ti,
up.p0.GetX()+(up.p1.GetX()-up.p0.GetX())*tf,
up.p0.GetY()+(up.p1.GetY()-up.p0.GetY())*tf);
rUp = dummy;
}
}
/*
1 Supporting classes
Supporting classes are those, which are not registered as SECONDO datatypes
but are used to implement the SECONDO datatypes ~intimeregion2~, ~uregion2~ and
~movingregion2~.
1.1 Class ~MSegmentData2~
This class is used to represent the segments, which are used to represent
region units in section \ref{uregion2}.
1.1.1 Class definition
The class definition has been moved to ~MovingRegion2Algebra.h~.
1.1.1 Constructor for a basic segment
\label{collinear}
*/
MSegmentData2::MSegmentData2(
unsigned int fno,
unsigned int cno,
unsigned int sno,
bool ia,
int isx,
int isy,
int iex,
int iey,
int fsx,
int fsy,
int fex,
int fey) :
faceno(fno),
cycleno(cno),
segmentno(sno),
insideAbove(ia),
isBasicSegment(true),
degeneratedInitialNext(-1),
degeneratedFinalNext(-1),
degeneratedInitial(DGM_UNKNOWN),
degeneratedFinal(DGM_UNKNOWN),
initialStartX(isx),
initialStartY(isy),
initialEndX(iex),
initialEndY(iey),
finalStartX(fsx),
finalStartY(fsy),
finalEndX(fex),
finalEndY(fey) {
if (MR2_DEBUG)
cerr << "MSegmentData2::MSegmentData2() #2 "
<< "called counter=["
<< faceno << " " << cycleno << " " << segmentno
<< "] flags=["
<< insideAbove
<< " " << degeneratedInitialNext
<< " " << degeneratedFinalNext
<< "] initial=["
<< initialStartX << " " << initialStartY
<< " "
<< initialEndX << " " << initialEndY
<< "] final=["
<< finalStartX << " " << finalStartY
<< " "
<< finalEndX << " " << finalEndY
<< "]"
<< endl;
/*
Calculate whether segment is point in initial or final instant.
*/
pointInitial = (isx == iex && isy == iey);
pointFinal = (fsx == fex && fsy == fey);
/*
Check whether initial and final segment are colinear,
*/
bool collinear;
if (pointInitial && pointFinal) {
/*
Error: A segment may not be reduced to a point both in initial and final
instant.
*/
if (MR2_DEBUG)
cerr << "MSegmentData2::MSegmentData2() "
<< "both reduced"
<< endl;
throw invalid_argument(
"both initial and final segment "
"reduced to point, which is not "
"allowed");
} else if (pointInitial) {
/*
Only initial segment reduced to point. Initial and final segment are trivially
colinear.
*/
if (MR2_DEBUG)
cerr << "MSegmentData2::MSegmentData2() "
<< "initial reduced"
<< endl;
collinear = true;
} else if (pointFinal) {
/*
Only final segment reduced to point. Initial and final segment are trivially
colinear.
*/
if (MR2_DEBUG)
cerr << "MSegmentData2::MSegmentData2() "
<< "final reduced"
<< endl;
collinear = true;
} else if (isx == iex && fsx == fex) {
/*
Both segments are vertical. Check if both segments have the same
orientation.
*/
if (MR2_DEBUG)
cerr << "MSegmentData2::MSegmentData2() "
<< "both vertical"
<< endl;
collinear = ((isy <= iey && fsy <= fey)
|| (isy >= iey && fsy >= fey));
} else if (isx == iex || fsx == fex) {
/*
Only initial or final segment is vertical but not both.
*/
if (MR2_DEBUG)
cerr << "MSegmentData2::MSegmentData2() "
<< "one vertical" << endl;
collinear = false;
} else {
/*
Both segments are not vertical.
*/
if (MR2_DEBUG)
cerr << "MSegmentData2::MSegmentData2() "
<< "none vertical"
<< endl;
double deltaIY = iey - isy;
double deltaIX = iex - isx;
double deltaFY = fey - fsy;
double deltaFX = fex - fsx;
collinear =
deltaIY / deltaIX == deltaFY / deltaFX
|| deltaIY * deltaFX == deltaFY * deltaIX;
if (!collinear) {
cerr << setprecision(10)
<< "parameters for "
<< "segment orientation comparison:"
<< endl
<< " 1. (iey-isy)/(iex-isx) = "
<< deltaIY / deltaIX
<< endl
<< " 2. (fey-fsy)/(fex-fsx) = "
<< deltaFY / deltaFX
<< endl
<< " 3. (iey-isy)*(fex-fsx) = "
<< deltaIY * deltaFX
<< endl
<< " 4. (fey-fsy)*(iex-isx) = "
<< deltaFY * deltaIX
<< endl
<< "1. and 2. or 3. and 4. should be equal."
<<"("<<isx<<";"<<isy<<")"
<<"("<<iex<<";"<<iey<<")"
<<"("<<fsx<<";"<<fsy<<")"
<<"("<<fex<<";"<<fey<<")"
<<fno<<" "
<<cno<<" "
<<sno
<< endl;
}
if (MR2_DEBUG) {
cerr << ::std::fixed << ::std::setprecision(6);
cerr << "MSegmentData2::MSegmentData2() isx="
<< isx
<< " isy=" << isy
<< " iex=" << iex
<< " iey=" << iey
<< " fsx=" << fsx
<< " fsy=" << fsy
<< " fex=" << fex
<< " fey=" << fey
<< endl;
cerr << "MSegmentData2::MSegmentData2() "
<< "(iey-isy)/(iex-isx)="
<< deltaIY / deltaIX << endl;
cerr << "MSegmentData2::MSegmentData2() "
<< "(fey-fsy)/(fex-fsx)="
<< deltaFY / deltaFX << endl;
cerr << "MSegmentData2::MSegmentData2() "
<< "(iey-isy)*(fex-fsx)="
<< deltaIY * deltaFX << endl;
cerr << "MSegmentData2::MSegmentData2() "
<< "(fey-fsy)*(iex-isx)="
<< deltaFY * deltaIX << endl;
cerr << "MSegmentData2::MSegmentData2() "
<< "collinear="
<< collinear << endl;
}
} //Check if collinear
if (!collinear) {
throw invalid_argument(
"initial and final segment not collinear");
}
} //End of constructor for a basic segment
/*
1.1.1 Constructor for a non-basic segment
\label{collinear2}
*/
MSegmentData2::MSegmentData2(
unsigned int fno,
unsigned int cno,
unsigned int sno,
bool ia,
int isx,
int isy,
int iex,
int iey,
int fsx,
int fsy,
int fex,
int fey,
PreciseMSegmentData& preciseSegment,
DbArray<int>* preciseCoordinates) :
faceno(fno),
cycleno(cno),
segmentno(sno),
insideAbove(ia),
isBasicSegment(false),
degeneratedInitialNext(-1),
degeneratedFinalNext(-1),
degeneratedInitial(DGM_UNKNOWN),
degeneratedFinal(DGM_UNKNOWN),
initialStartX(isx),
initialStartY(isy),
initialEndX(iex),
initialEndY(iey),
finalStartX(fsx),
finalStartY(fsy),
finalEndX(fex),
finalEndY(fey) {
if (MR2_DEBUG)
cerr << "MSegmentData2::MSegmentData2() #2 "
<< "called for non-basic segment. counter=["
<< faceno << " " << cycleno << " " << segmentno
<< "] flags=["
<< insideAbove
<< " " << degeneratedInitialNext
<< " " << degeneratedFinalNext
<< "]" << endl
<< "initial=["
<< initialStartX << " " << initialStartY
<< " "
<< initialEndX << " " << initialEndY
<< "] final=["
<< finalStartX << " " << finalStartY
<< " "
<< finalEndX << " " << finalEndY
<< "]"
<< endl;
/*
Calculate whether segment is point in initial or final instant.
*/
pointInitial = (maybeEqual(isx, iex, 1, 1)
&& maybeEqual(isy, iey, 1, 1)
&& (preciseSegment.GetInitialStartY
(preciseCoordinates) + isx ==
preciseSegment.GetInitialEndX
(preciseCoordinates) + iex)
&& (preciseSegment.GetInitialStartY
(preciseCoordinates) + isy ==
preciseSegment.GetInitialEndY
(preciseCoordinates) + iey));
pointFinal = (maybeEqual(fsx, fex, 1, 1)
&& maybeEqual(fsy, fey, 1, 1)
&& (preciseSegment.GetFinalStartX
(preciseCoordinates) + fsx ==
preciseSegment.GetFinalEndX
(preciseCoordinates) + fex)
&& (preciseSegment.GetFinalStartY
(preciseCoordinates) + fsy ==
preciseSegment.GetFinalEndY
(preciseCoordinates) + fey));
/*
Check whether initial and final segment are collinear,
*/
bool collinear;
if (pointInitial && pointFinal) {
/*
Error: A segment may not be reduced to a point both in initial and final
instant.
*/
if (MR2_DEBUG)
cerr << "MSegmentData2::MSegmentData2() "
<< "segments both reduced to point!"
<< endl;
throw invalid_argument
("both initial and final segment "
"reduced to point, which is not "
"allowed");
} else if (pointInitial) {
/*
Only initial segment reduced to point. Initial and final segment are trivially
collinear.
*/
collinear = true;
} else if (pointFinal) {
/*
Only final segment reduced to point. Initial and final segment are trivially
collinear.
*/
collinear = true;
} else if (maybeEqual(isx, iex, 1, 1)
&& maybeEqual(fsx, fex, 1, 1)
&& (preciseSegment.GetInitialStartX
(preciseCoordinates) + isx ==
preciseSegment.GetInitialEndX
(preciseCoordinates) + iex)
&& (preciseSegment.GetFinalStartX
(preciseCoordinates) + fsx ==
preciseSegment.GetFinalEndX
(preciseCoordinates) + fex)) {
/*
Both segments are vertical. Check if both segments have the same
orientation.
*/
collinear = ((isLower(isy, iey, 1, 1)
&& isLower(fsy, fey, 1, 1))
|| (isGreater(isy, iey, 1, 1)
&& isGreater(fsy, fey, 1, 1)));
if (!collinear)
{
if ((maybeEqual(isy, iey, 1, 1)
&& maybeEqual(fsy, fey, 1, 1))
|| (maybeEqual(isy, iey, 1, 1)
&& maybeEqual(fsy, fey, 1, 1)))
{
collinear = (cmp(preciseSegment.GetInitialStartY
(preciseCoordinates) + isy,
preciseSegment.GetInitialEndY
(preciseCoordinates) + iey) < 0
&& cmp(preciseSegment.GetFinalStartY
(preciseCoordinates) + fsy,
preciseSegment.GetFinalEndY
(preciseCoordinates) + fey) < 0)
|| (cmp(preciseSegment.GetInitialStartY
(preciseCoordinates) + isy,
preciseSegment.GetInitialEndY
(preciseCoordinates) + iey) > 0
&& cmp(preciseSegment.GetFinalStartY
(preciseCoordinates) + fsy,
preciseSegment.GetFinalEndY
(preciseCoordinates) + fey) > 0);
}
}
} else if ((maybeEqual(isx, iex, 1, 1)
|| maybeEqual(fsx, fex, 1, 1))
&& ((preciseSegment.GetInitialStartX
(preciseCoordinates) + isx ==
preciseSegment.GetInitialEndX
(preciseCoordinates) + iex)
|| (preciseSegment.GetFinalStartX(preciseCoordinates)
+ fsx == preciseSegment.GetFinalEndX
(preciseCoordinates) + fex))) {
/*
Only initial or final segment is vertical but not both.
*/
collinear = false;
} else {
/*
Both segments are not vertical. We first try to find out with grid coordinates if the segments are collinear or not. If they seem to be collinear, we make a precise recheck.
Here we must be extremely careful not to divide by zero! If the denominator is zero, we cannot make the check on integer grid and have to do a precise check at once!
*/
bool denumZero = (iex == isx || fex == fsx );
if (!denumZero)
{
collinear = maybeEqual((iey-isy)/(iex-isx),
(fey-fsy)/(fex-fsx), 4, 4)
|| maybeEqual((iey-isy)*(fex-fsx),
(fey-fsy)*(iex-isx), 4, 4);
}
if (denumZero || collinear)
{
collinear = ((preciseSegment.GetInitialEndY
(preciseCoordinates) + iey
- (preciseSegment.GetInitialStartY
(preciseCoordinates) + isy)) /
(preciseSegment.GetInitialEndX
(preciseCoordinates) + iex
- (preciseSegment.GetInitialStartX
(preciseCoordinates) + isx)) ==
(preciseSegment.GetFinalEndY(preciseCoordinates)
+ fey - (preciseSegment.GetFinalStartY
(preciseCoordinates) + fsy)) /
(preciseSegment.GetFinalEndX(preciseCoordinates)
+ fex -
(preciseSegment.GetFinalStartX
(preciseCoordinates) + fsx)));
if (!collinear)
{
//Check if second part of the OR is true:
collinear = ((preciseSegment.GetInitialEndY
(preciseCoordinates) + iey -
(preciseSegment.GetInitialStartY
(preciseCoordinates) + isy)) *
(preciseSegment.GetFinalEndX
(preciseCoordinates) + fex -
(preciseSegment.GetFinalStartX
(preciseCoordinates) + fsx)) ==
(preciseSegment.GetFinalEndY
(preciseCoordinates) + fey -
(preciseSegment.GetFinalStartY
(preciseCoordinates) + fsy)) *
(preciseSegment.GetInitialEndX
(preciseCoordinates) + iex -
(preciseSegment.GetInitialStartX
(preciseCoordinates) + isx)));
}
}
} //Check if collinear
if (!collinear) {
throw invalid_argument(
"initial and final segment not collinear");
}
} //End of constructor for a non-basic segment
/*
1.1.1 Constructor for a segment from a segment pointer.
*/
MSegmentData2::MSegmentData2(MSegmentData2* segmentPointer) :
faceno(segmentPointer->faceno),
cycleno(segmentPointer->cycleno),
segmentno(segmentPointer->segmentno),
insideAbove(segmentPointer->insideAbove),
isBasicSegment(segmentPointer->isBasicSegment),
degeneratedInitialNext(segmentPointer->degeneratedInitialNext),
degeneratedFinalNext(segmentPointer->degeneratedFinalNext),
degeneratedInitial(segmentPointer->degeneratedInitial),
degeneratedFinal(segmentPointer->degeneratedFinal),
initialStartX(segmentPointer->initialStartX),
initialStartY(segmentPointer->initialStartY),
initialEndX(segmentPointer->initialEndX),
initialEndY(segmentPointer->initialEndY),
finalStartX(segmentPointer->finalStartX),
finalStartY(segmentPointer->finalStartY),
finalEndX(segmentPointer->finalEndX),
finalEndY(segmentPointer->finalEndY) {
if (MR2_DEBUG)
cerr << "MSegmentData2::MSegmentData2() #3 "
<< "called for segment from segment pointer. counter=["
<< faceno << " " << cycleno << " " << segmentno
<< "] flags=["
<< insideAbove
<< " " << degeneratedInitialNext
<< " " << degeneratedFinalNext
<< "]" << endl
<< "isBasicSegment is " << isBasicSegment << endl
<< "initial=["
<< initialStartX << " " << initialStartY
<< " "
<< initialEndX << " " << initialEndY
<< "] final=["
<< finalStartX << " " << finalStartY
<< " "
<< finalEndX << " " << finalEndY
<< "]"
<< endl;
}
/*
1.1.1 Method ~ToString()~
*/
string MSegmentData2::ToString(void) const {
ostringstream tmp;
tmp << "f/c/s=" << faceno
<< "/" << cycleno
<< "/" << segmentno
<< " initial: p/d/dn=" << pointInitial
<< "/" << degeneratedInitial
<< "/" << degeneratedInitialNext
<< " (" << initialStartX
<< ", " << initialStartY
<< ")-(" << initialEndX
<< ", " << initialEndY
<< ") final: p/d/dn=" << pointFinal
<< "/" << degeneratedFinal
<< "/" << degeneratedFinalNext
<< " (" << finalStartX
<< ", " << finalStartY
<< ")-(" << finalEndX
<< ", " << finalEndY
<< ")";
return tmp.str();
}
/*
1.1 Class ~PreciseMSegmentData~
This class is used to represent the precise segments
1.1.1 Class definition
The class definition has been moved to ~MovingRegion2Algebra.h~.
1.1.1 Constructors
The integer arguments serve to initialize the array indices.
An index of -1 means that elements will be attached at the end
of the array, and indices will be set accordingly.
*/
PreciseMSegmentData::PreciseMSegmentData(int isxPos, int isyPos,
int iexPos, int ieyPos,
int fsxPos, int fsyPos, int fexPos, int feyPos,
int isxNum, int isyNum, int iexNum, int ieyNum,
int fsxNum, int fsyNum, int fexNum, int feyNum) :
isxStartPos(isxPos),
isyStartPos(isyPos),
iexStartPos(iexPos),
ieyStartPos(ieyPos),
fsxStartPos(fsxPos),
fsyStartPos(fsyPos),
fexStartPos(fexPos),
feyStartPos(feyPos),
isxNumOfChars(isxNum),
isyNumOfChars(isyNum),
iexNumOfChars(iexNum),
ieyNumOfChars(ieyNum),
fsxNumOfChars(fsxNum),
fsyNumOfChars(fsyNum),
fexNumOfChars(fexNum),
feyNumOfChars(feyNum) {}
PreciseMSegmentData::PreciseMSegmentData(int startPos) :
isxStartPos(startPos),
isyStartPos(startPos),
iexStartPos(startPos),
ieyStartPos(startPos),
fsxStartPos(startPos),
fsyStartPos(startPos),
fexStartPos(startPos),
feyStartPos(startPos),
isxNumOfChars(0),
isyNumOfChars(0),
iexNumOfChars(0),
ieyNumOfChars(0),
fsxNumOfChars(0),
fsyNumOfChars(0),
fexNumOfChars(0),
feyNumOfChars(0) {}
/*
1.1.1 Write access methods.
All these methods take the argument of type mpq-class, convert it to an
arbitrary number of chars and stores these chars in the given DbArray. The
private attributes representing the array indices to restore the coordinates
are of course also updated.
*/
void PreciseMSegmentData::SetInitialStartX (mpq_class x,
DbArray<int>* preciseCoordinates) {
if (MR2_DEBUG)
cerr << "PreciseMSegmentData::SetInitialStartX() "
<< "called with isx = " << x
<< ", starting at array position "
<< isxStartPos << ", array address is "
<< preciseCoordinates << endl;
stringstream theStream;
theStream << x;
if (isxStartPos == -1) isxStartPos = preciseCoordinates->Size();
int index = isxStartPos;
if (index >= preciseCoordinates->Size())
{
preciseCoordinates->resize(preciseCoordinates->Size()
+ gmpCharNum);
}
for (int i = 0; theStream.good(); i++)
{
char nextChar;
theStream.get(nextChar);
if (i > 0 && i % gmpCharNum == (gmpCharNum - 1))
{
if (MR2_DEBUG)
cerr << "resizing array..." << endl;
/*
A new group of int values is needed since the one(s) used so far is / are not enough to represent this mpq-class value.
*/
int nextGroupsIndex = preciseCoordinates->Size();
if (nextGroupsIndex == index)
nextGroupsIndex++;
preciseCoordinates->Put(index, nextGroupsIndex);
if (MR2_DEBUG)
cerr << "Index of next group is "
<< nextGroupsIndex << endl;
index = nextGroupsIndex;
preciseCoordinates->resize
(preciseCoordinates->Size() + gmpCharNum);
}
if (theStream.good())
{
preciseCoordinates->Put(index, (int)nextChar);
index++;
}
else
{
isxNumOfChars = i;
for (int j = index; j % gmpCharNum > 0; j++)
{
preciseCoordinates->Put(j, -1);
}
}
}
}
void PreciseMSegmentData::SetInitialStartY (mpq_class x,
DbArray<int>* preciseCoordinates) {
if (MR2_DEBUG)
cerr << "PreciseMSegmentData::SetInitialStartY() called"
<< endl;
stringstream theStream;
theStream << x;
if (isyStartPos == -1) isyStartPos = preciseCoordinates->Size();
int index = isyStartPos;
if (index >= preciseCoordinates->Size())
{
preciseCoordinates->resize(preciseCoordinates->Size()
+ gmpCharNum);
}
for (int i = 0; theStream.good(); i++)
{
char nextChar;
theStream.get(nextChar);
if (i > 0 && i % gmpCharNum == (gmpCharNum - 1))
{
if (MR2_DEBUG)
cerr << "resizing array..." << endl;
/*
A new group of int values is needed since the one(s) used so far is / are not enough to represent this mpq-class value.
*/
int nextGroupsIndex = preciseCoordinates->Size();
if (nextGroupsIndex == index)
nextGroupsIndex++;
preciseCoordinates->Put(index, nextGroupsIndex);
if (MR2_DEBUG)
cerr << "Index of next group is "
<< nextGroupsIndex << endl;
index = nextGroupsIndex;
preciseCoordinates->resize
(preciseCoordinates->Size() + gmpCharNum);
}
if (theStream.good())
{
preciseCoordinates->Put(index, (int)nextChar);
index++;
}
else
{
isyNumOfChars = i;
for (int j = index; j % gmpCharNum > 0; j++)
{
preciseCoordinates->Put(j, -1);
}
}
}
}
void PreciseMSegmentData::SetInitialEndX (mpq_class x,
DbArray<int>* preciseCoordinates) {
stringstream theStream;
theStream << x;
if (iexStartPos == -1) iexStartPos = preciseCoordinates->Size();
int index = iexStartPos;
if (index >= preciseCoordinates->Size())
{
preciseCoordinates->resize
(preciseCoordinates->Size() + gmpCharNum);
}
for (int i = 0; theStream.good(); i++)
{
char nextChar;
theStream.get(nextChar);
if (i > 0 && i % gmpCharNum == (gmpCharNum - 1))
{
if (MR2_DEBUG)
cerr << "resizing array..." << endl;
/*
A new group of int values is needed since the one(s) used so far is / are not enough to represent this mpq-class value.
*/
int nextGroupsIndex = preciseCoordinates->Size();
if (nextGroupsIndex == index)
nextGroupsIndex++;
preciseCoordinates->Put(index, nextGroupsIndex);
if (MR2_DEBUG)
cerr << "Index of next group is "
<< nextGroupsIndex << endl;
index = nextGroupsIndex;
preciseCoordinates->resize
(preciseCoordinates->Size() + gmpCharNum);
}
if (theStream.good())
{
preciseCoordinates->Put(index, (int)nextChar);
index++;
}
else
{
iexNumOfChars = i;
for (int j = index; j % gmpCharNum > 0; j++)
{
preciseCoordinates->Put(j, -1);
}
}
}
}
void PreciseMSegmentData::SetInitialEndY (mpq_class x,
DbArray<int>* preciseCoordinates) {
stringstream theStream;
theStream << x;
if (ieyStartPos == -1) ieyStartPos = preciseCoordinates->Size();
int index = ieyStartPos;
if (index >= preciseCoordinates->Size())
{
preciseCoordinates->resize(preciseCoordinates->Size()
+ gmpCharNum);
}
for (int i = 0; theStream.good(); i++)
{
char nextChar;
theStream.get(nextChar);
if (i > 0 && i % gmpCharNum == (gmpCharNum - 1))
{
if (MR2_DEBUG)
cerr << "resizing array..." << endl;
/*
A new group of int values is needed since the one(s) used so far is / are not enough to represent this mpq-class value.
*/
int nextGroupsIndex = preciseCoordinates->Size();
if (nextGroupsIndex == index)
nextGroupsIndex++;
preciseCoordinates->Put(index, nextGroupsIndex);
if (MR2_DEBUG)
cerr << "Index of next group is "
<< nextGroupsIndex << endl;
index = nextGroupsIndex;
preciseCoordinates->resize
(preciseCoordinates->Size() + gmpCharNum);
}
if (theStream.good())
{
preciseCoordinates->Put(index, (int)nextChar);
index++;
}
else
{
ieyNumOfChars = i;
for (int j = index; j % gmpCharNum > 0; j++)
{
preciseCoordinates->Put(j, -1);
}
}
}
}
void PreciseMSegmentData::SetFinalStartX (mpq_class x,
DbArray<int>* preciseCoordinates) {
stringstream theStream;
theStream << x;
if (fsxStartPos == -1) fsxStartPos = preciseCoordinates->Size();
int index = fsxStartPos;
if (index >= preciseCoordinates->Size())
{
preciseCoordinates->resize
(preciseCoordinates->Size() + gmpCharNum);
}
for (int i = 0; theStream.good(); i++)
{
char nextChar;
theStream.get(nextChar);
if (i > 0 && i % gmpCharNum == (gmpCharNum - 1))
{
if (MR2_DEBUG)
cerr << "resizing array..." << endl;
/*
A new group of int values is needed since the one(s) used so far is / are not enough to represent this mpq-class value.
*/
int nextGroupsIndex = preciseCoordinates->Size();
if (nextGroupsIndex == index)
nextGroupsIndex++;
preciseCoordinates->Put(index, nextGroupsIndex);
if (MR2_DEBUG)
cerr << "Index of next group is "
<< nextGroupsIndex << endl;
index = nextGroupsIndex;
preciseCoordinates->resize
(preciseCoordinates->Size() + gmpCharNum);
}
if (theStream.good())
{
preciseCoordinates->Put(index, (int)nextChar);
index++;
}
else
{
fsxNumOfChars = i;
for (int j = index; j % gmpCharNum > 0; j++)
{
preciseCoordinates->Put(j, -1);
}
}
}
}
void PreciseMSegmentData::SetFinalStartY (mpq_class x,
DbArray<int>* preciseCoordinates) {
stringstream theStream;
theStream << x;
if (fsyStartPos == -1) fsyStartPos = preciseCoordinates->Size();
int index = fsyStartPos;
if (index >= preciseCoordinates->Size())
{
preciseCoordinates->resize(preciseCoordinates->Size()
+ gmpCharNum);
}
for (int i = 0; theStream.good(); i++)
{
char nextChar;
theStream.get(nextChar);
if (i > 0 && i % gmpCharNum == (gmpCharNum - 1))
{
if (MR2_DEBUG)
cerr << "resizing array..." << endl;
/*
A new group of int values is needed since the one(s) used so far is / are not enough to represent this mpq-class value.
*/
int nextGroupsIndex = preciseCoordinates->Size();
if (nextGroupsIndex == index)
nextGroupsIndex++;
preciseCoordinates->Put(index, nextGroupsIndex);
if (MR2_DEBUG)
cerr << "Index of next group is "
<< nextGroupsIndex << endl;
index = nextGroupsIndex;
preciseCoordinates->resize
(preciseCoordinates->Size()
+ gmpCharNum);
}
if (theStream.good())
{
preciseCoordinates->Put(index, (int)nextChar);
index++;
}
else
{
fsyNumOfChars = i;
for (int j = index; j % gmpCharNum > 0; j++)
{
preciseCoordinates->Put(j, -1);
}
}
}
}
void PreciseMSegmentData::SetFinalEndX (mpq_class x,
DbArray<int>* preciseCoordinates) {
stringstream theStream;
theStream << x;
if (fexStartPos == -1) fexStartPos = preciseCoordinates->Size();
int index = fexStartPos;
if (index >= preciseCoordinates->Size())
{
preciseCoordinates->resize(preciseCoordinates->Size()
+ gmpCharNum);
}
for (int i = 0; theStream.good(); i++)
{
char nextChar;
theStream.get(nextChar);
if (i > 0 && i % gmpCharNum == (gmpCharNum - 1))
{
if (MR2_DEBUG)
cerr << "resizing array..." << endl;
/*
A new group of int values is needed since the one(s) used so far is / are not enough to represent this mpq-class value.
*/
int nextGroupsIndex = preciseCoordinates->Size();
if (nextGroupsIndex == index)
nextGroupsIndex++;
preciseCoordinates->Put(index, nextGroupsIndex);
if (MR2_DEBUG)
cerr << "Index of next group is "
<< nextGroupsIndex << endl;
index = nextGroupsIndex;
preciseCoordinates->resize(
preciseCoordinates->Size() + gmpCharNum);
}
if (theStream.good())
{
preciseCoordinates->Put(index, (int)nextChar);
index++;
}
else
{
fexNumOfChars = i;
for (int j = index; j % gmpCharNum > 0; j++)
{
preciseCoordinates->Put(j, -1);
}
}
}
}
void PreciseMSegmentData::SetFinalEndY (mpq_class x,
DbArray<int>* preciseCoordinates) {
stringstream theStream;
theStream << x;
if (feyStartPos == -1) feyStartPos = preciseCoordinates->Size();
int index = feyStartPos;
if (index >= preciseCoordinates->Size())
{
preciseCoordinates->resize(preciseCoordinates->Size()
+ gmpCharNum);
}
for (int i = 0; theStream.good(); i++)
{
char nextChar;
theStream.get(nextChar);
if (i > 0 && i % gmpCharNum == (gmpCharNum - 1))
{
if (MR2_DEBUG)
cerr << "resizing array..." << endl;
/*
A new group of int values is needed since the one(s) used so far is / are not enough to represent this mpq-class value.
*/
int nextGroupsIndex = preciseCoordinates->Size();
if (nextGroupsIndex == index)
nextGroupsIndex++;
preciseCoordinates->Put(index, nextGroupsIndex);
if (MR2_DEBUG)
cerr << "Index of next group is "
<< nextGroupsIndex << endl;
index = nextGroupsIndex;
preciseCoordinates->resize(
preciseCoordinates->Size() + gmpCharNum);
}
if (theStream.good())
{
preciseCoordinates->Put(index, (int)nextChar);
index++;
}
else
{
feyNumOfChars = i;
for (int j = index; j % gmpCharNum > 0; j++)
{
preciseCoordinates->Put(j, -1);
}
}
}
}
/*
1.1.1 Read access methods
All these methods fetch the chars representing the given coordinate from the
DbArray using the indices given in this instance's private attributes, and
convert them to the correct instance of type mpq-class, representing the value
of the given coordinate.
*/
mpq_class PreciseMSegmentData::GetInitialStartX(const
DbArray<int>* preciseCoordinates) const {
if (MR2_DEBUG)
cerr << "PreciseMSegmentData::GetInitialStartX(),"
<< " isxNumOfChars: " << isxNumOfChars
<< ", isxStartPos: " << isxStartPos
<< ", array size: "
<< preciseCoordinates->Size() << endl;
stringstream theStream;
mpq_class theValue(0);
int index = isxStartPos;
if (index == -1) return theValue;
for (int i = 0; i < isxNumOfChars; i++)
{
if (i > 0 && i % gmpCharNum == gmpCharNum-1)
{
int nextIndex;
preciseCoordinates->Get(index, nextIndex);
index = nextIndex;
}
char nextChar;
int nextInt;
preciseCoordinates->Get(index, nextInt);
nextChar = static_cast<char>(nextInt);
theStream.put(nextChar);
index++;
}
theStream >> theValue;
return theValue;
}
mpq_class PreciseMSegmentData::GetInitialStartY(const
DbArray<int>* preciseCoordinates) const {
stringstream theStream;
mpq_class theValue(0);
int index = isyStartPos;
if (index == -1) return theValue;
for (int i = 0; i < isyNumOfChars; i++)
{
if (i > 0 && i % gmpCharNum == gmpCharNum-1)
{
int nextIndex;
preciseCoordinates->Get(index, nextIndex);
index = nextIndex;
}
char nextChar;
int nextInt;
preciseCoordinates->Get(index, nextInt);
nextChar = static_cast<char>(nextInt);
theStream.put(nextChar);
index++;
}
theStream >> theValue;
return theValue;
}
mpq_class PreciseMSegmentData::GetInitialEndX(const
DbArray<int>* preciseCoordinates) const {
stringstream theStream;
mpq_class theValue(0);
int index = iexStartPos;
if (index == -1) return theValue;
for (int i = 0; i < iexNumOfChars; i++)
{
if (i > 0 && i % gmpCharNum == gmpCharNum-1)
{
int nextIndex;
preciseCoordinates->Get(index, nextIndex);
index = nextIndex;
}
char nextChar;
int nextInt;
preciseCoordinates->Get(index, nextInt);
nextChar = static_cast<char>(nextInt);
theStream.put(nextChar);
index++;
}
theStream >> theValue;
return theValue;
}
mpq_class PreciseMSegmentData::GetInitialEndY(const
DbArray<int>* preciseCoordinates) const {
stringstream theStream;
mpq_class theValue(0);
int index = ieyStartPos;
if (index == -1) return theValue;
for (int i = 0; i < ieyNumOfChars; i++)
{
if (i > 0 && i % gmpCharNum == gmpCharNum-1)
{
int nextIndex;
preciseCoordinates->Get(index, nextIndex);
index = nextIndex;
}
char nextChar;
int nextInt;
preciseCoordinates->Get(index, nextInt);
nextChar = static_cast<char>(nextInt);
theStream.put(nextChar);
index++;
}
theStream >> theValue;
return theValue;
}
mpq_class PreciseMSegmentData::GetFinalStartX(const
DbArray<int>* preciseCoordinates) const {
stringstream theStream;
mpq_class theValue(0);
int index = fsxStartPos;
if (index == -1) return theValue;
for (int i = 0; i < fsxNumOfChars; i++)
{
if (i > 0 && i % gmpCharNum == gmpCharNum-1)
{
int nextIndex;
preciseCoordinates->Get(index, nextIndex);
index = nextIndex;
}
char nextChar;
int nextInt;
preciseCoordinates->Get(index, nextInt);
nextChar = static_cast<char>(nextInt);
theStream.put(nextChar);
index++;
}
theStream >> theValue;
return theValue;
}
mpq_class PreciseMSegmentData::GetFinalStartY(const
DbArray<int>* preciseCoordinates) const {
stringstream theStream;
mpq_class theValue(0);
int index = fsyStartPos;
if (index == -1) return theValue;
for (int i = 0; i < fsyNumOfChars; i++)
{
if (i > 0 && i % gmpCharNum == gmpCharNum-1)
{
int nextIndex;
preciseCoordinates->Get(index, nextIndex);
index = nextIndex;
}
char nextChar;
int nextInt;
preciseCoordinates->Get(index, nextInt);
nextChar = static_cast<char>(nextInt);
theStream.put(nextChar);
index++;
}
theStream >> theValue;
return theValue;
}
mpq_class PreciseMSegmentData::GetFinalEndX(const
DbArray<int>* preciseCoordinates) const {
stringstream theStream;
mpq_class theValue(0);
int index = fexStartPos;
if (index == -1) return theValue;
for (int i = 0; i < fexNumOfChars; i++)
{
if (i > 0 && i % gmpCharNum == gmpCharNum-1)
{
int nextIndex;
preciseCoordinates->Get(index, nextIndex);
index = nextIndex;
}
char nextChar;
int nextInt;
preciseCoordinates->Get(index, nextInt);
nextChar = static_cast<char>(nextInt);
theStream.put(nextChar);
index++;
}
theStream >> theValue;
return theValue;
}
mpq_class PreciseMSegmentData::GetFinalEndY(const
DbArray<int>* preciseCoordinates) const {
stringstream theStream;
mpq_class theValue(0);
int index = feyStartPos;
if (index == -1) return theValue;
for (int i = 0; i < feyNumOfChars; i++)
{
if (i > 0 && i % gmpCharNum == gmpCharNum-1)
{
int nextIndex;
preciseCoordinates->Get(index, nextIndex);
index = nextIndex;
}
char nextChar;
int nextInt;
preciseCoordinates->Get(index, nextInt);
nextChar = static_cast<char>(nextInt);
theStream.put(nextChar);
index++;
}
theStream >> theValue;
return theValue;
}
/*
1.1 Class ~PreciseInterval~
This class is used to represent the precise time intervals for region units.
1.1.1 Class definition
The class definition has been moved to ~MovingRegion2Algebra.h~.
1.1.1 Constructors
The integer parameters are taken to initialize the array indices. Values
-1 mean the indices will be set to the arrays size, the new element will
be attached at the end of the array.
*/
PreciseInterval::PreciseInterval(int startPos, int endPos,
int startNum, int endNum) :
startStartPos(startPos),
endStartPos(endPos),
startNumOfChars(startNum),
endNumOfChars(endNum) {}
PreciseInterval::PreciseInterval(int pos) :
startStartPos(pos),
endStartPos(pos),
startNumOfChars(0),
endNumOfChars(0) {}
/*
1.1.1 Attribute read and write access methods
The internal functionality of these access methods is just like of those
from class PreciseMSegmentData. Private attributes are used as indices to the
given char arrays to retrieve the objects, and when object values are updated,
the indices are updated as well.
*/
mpq_class PreciseInterval::GetPreciseInitialInstant (
const DbArray<int>* preciseInstants)
{
if (MR2_DEBUG)
cerr << "PreciseInterval::GetPreciseInitialInstant() called"
<< endl
<< "StartPos is " << startStartPos
<< endl
<< "Size of Array is " << preciseInstants->Size()
<< endl;
stringstream theStream;
mpq_class theValue(0);
int index = startStartPos;
if (index == -1) return theValue;
for (int i = 0; i < startNumOfChars; i++)
{
if (i > 0 && i % gmpCharNum == gmpCharNum-1)
{
int nextIndex;
preciseInstants->Get(index, nextIndex);
index = nextIndex;
}
char nextChar;
int nextInt;
preciseInstants->Get(index, nextInt);
nextChar = static_cast<char>(nextInt);
theStream.put(nextChar);
index++;
}
theStream >> theValue;
return theValue;
}
mpq_class PreciseInterval::GetPreciseFinalInstant
(const DbArray<int>* preciseInstants)
{
stringstream theStream;
mpq_class theValue(0);
int index = endStartPos;
if (index == -1) return theValue;
for (int i = 0; i < endNumOfChars; i++)
{
if (i > 0 && i % gmpCharNum == gmpCharNum-1)
{
int nextIndex;
preciseInstants->Get(index, nextIndex);
index = nextIndex;
}
char nextChar;
int nextInt;
preciseInstants->Get(index, nextInt);
nextChar = static_cast<char>(nextInt);
theStream.put(nextChar);
index++;
}
theStream >> theValue;
return theValue;
}
void PreciseInterval::SetPreciseInitialInstant (
mpq_class initial, DbArray<int>* preciseInstants)
{
if (MR2_DEBUG)
cerr << "PreciseInterval::SetPreciseInitialInstant()"
<< " with start value: " << initial << endl;
stringstream theStream;
theStream << initial;
if (startStartPos == -1) startStartPos =
preciseInstants->Size();
int index = startStartPos;
if (index >= preciseInstants->Size())
{
preciseInstants->resize
(preciseInstants->Size() + gmpCharNum);
}
for (int i = 0; theStream.good(); i++)
{
char nextChar;
theStream.get(nextChar);
if (i > 0 && i % gmpCharNum == (gmpCharNum - 1))
{
if (MR2_DEBUG)
cerr << "resizing array..." << endl;
/*
A new group of int values is needed since the one(s) used so far is / are not enough to represent this mpq\_class value.
*/
int nextGroupsIndex =
preciseInstants->Size();
if (nextGroupsIndex == index)
nextGroupsIndex++;
preciseInstants->Put(
index, nextGroupsIndex);
if (MR2_DEBUG)
cerr << "Index of next group is "
<< nextGroupsIndex << endl;
index = nextGroupsIndex;
preciseInstants->resize(
preciseInstants->Size() + gmpCharNum);
}
if (theStream.good())
{
preciseInstants->Put(index, (int)nextChar);
index++;
}
else
{
startNumOfChars = i;
for (int j = index; j % gmpCharNum > 0; j++)
{
preciseInstants->Put(j, -1);
}
}
}
}
void PreciseInterval::SetPreciseFinalInstant (mpq_class final,
DbArray<int>* preciseInstants)
{
if (MR2_DEBUG)
cerr << "PreciseInterval::SetPreciseFinalInstant() "
<< "with end value " << final << endl;
stringstream theStream;
theStream << final;
if (endStartPos == -1) endStartPos =
preciseInstants->Size();
int index = endStartPos;
if (index >= preciseInstants->Size())
{
preciseInstants->resize(
preciseInstants->Size() + gmpCharNum);
}
for (int i = 0; theStream.good(); i++)
{
char nextChar;
theStream.get(nextChar);
if (i > 0 && i % gmpCharNum == (gmpCharNum - 1))
{
if (MR2_DEBUG)
cerr << "resizing array..." << endl;
/*
A new group of chars is needed since the one(s) used so far is / are not enough to represent this mpq\_class value.
*/
int nextGroupsIndex = preciseInstants->Size();
if (nextGroupsIndex == index)
nextGroupsIndex++;
preciseInstants->Put(index, nextGroupsIndex);
if (MR2_DEBUG)
cerr << "Index of next group is "
<< nextGroupsIndex << endl;
index = nextGroupsIndex;
preciseInstants->resize(preciseInstants->Size()
+ gmpCharNum);
}
if (theStream.good())
{
preciseInstants->Put(index, (int)nextChar);
index++;
}
else
{
endNumOfChars = i;
for (int j = index; j % gmpCharNum > 0; j++)
{
preciseInstants->Put(j, -1);
}
}
}
}
/*
1 Data type ~iregion2~
1.1 Class ~IRegion2~
1.1.1 Class definition
The class definition has been moved to ~MovingRegion2Algebra.h~.
1.1.1 Constructors
*/
IRegion2::IRegion2(bool dummy): Intime<Region>(0) {
if (MR2_DEBUG) cerr << "IRegion2::IRegion2() #2 called" << endl;
/*
This is quite ugly and may not work with other compilers than gcc.
Since the ~Intime<Alpha>()~ constructors do not properly initialise their
~value~ attribute (which if of type ~Region~ in this case), there is
no better solution right now to assure that ~value~ has a valid DBArray.
*/
/*Region* tmp = new Region(0);
memcpy(&value, tmp, sizeof(*tmp));
delete(tmp);*/
value.SetEmpty();
value.SetDefined(true);
SetDefined(true);
}
IRegion2::IRegion2(const IRegion2& ir) : Intime<Region>(0) {
if (MR2_DEBUG) cerr << "IRegion2::IRegion2() #2 called" << endl;
instant = ir.instant;
del.isDefined = ir.del.isDefined;
/*
This is quite ugly and may not work with other compilers than gcc.
Since the ~Intime<Alpha>()~ constructors do not properly initialise their
~value~ attribute (which if of type ~Region~ in this case), there is
no better solution right now to assure that ~value~ has a valid DBArray.
*/
/*Region* tmp = new Region(0);
memcpy(&value, tmp, sizeof(*tmp));
delete(tmp);*/
value.SetEmpty();
if (ir.del.isDefined) value.CopyFrom(&ir.value);
}
/*
1.1.1 Methods for algebra integration
1.1.1.1 Method ~Clone()~
*/
IRegion2* IRegion2::Clone(void) const {
if (MR2_DEBUG) cerr << "IRegion2::Clone() called" << endl;
return new IRegion2(*this);
}
/*
1.1.1.1 ~DBArray~ access
*/
int IRegion2::NumOfFLOBs(void) const {
if (MR2_DEBUG) cerr << "IRegion2::NumOfFLOBs() called" << endl;
return 1;
}
Flob* IRegion2::GetFLOB(const int i) {
if (MR2_DEBUG) cerr << "IRegion2::GetFLOB() called" << endl;
assert(i == 0);
return value.GetFLOB(0);
}
/*
1.1 Algebra integration
1.1.1 Function ~IRegion2Property()~
*/
static ListExpr IRegion2Property() {
if (MR2_DEBUG) cerr << "IRegion2Property() called" << endl;
ListExpr example = nl->TextAtom();
nl->AppendText(example,
"(\"2003-01-10\" ((((1.0 3.5)(2.0 5.5)(3.0 6.5)(4.0 6.5)"
"(4.0 5.5)(5.0 4.5)(5.0 2.5)(4.0 1.5)(3.0 1.5))"
"((2.0 3.0)(2.0 4.0)(3.0 4.0)(3.0 3.0)))))");
return
nl->TwoElemList(
nl->FourElemList(
nl->StringAtom("Signature"),
nl->StringAtom("Example Type List"),
nl->StringAtom("List Rep"),
nl->StringAtom("Example List")),
nl->FourElemList(
nl->StringAtom("-> UNIT"),
nl->StringAtom("(iregion2)"),
nl->StringAtom("(<instant> <region>)"),
example));
}
/*
1.1.1 Function ~CheckIRegion2()~
*/
static bool CheckIRegion2(ListExpr type, ListExpr& errorInfo) {
if (MR2_DEBUG) cerr << "CheckIRegion2() called" << endl;
return nl->IsEqual(type, IRegion2::BasicType())
|| nl->IsEqual(type, "intimeregion2"); // backward-compatibility!
}
/*
1.1.1 Function ~CreateIRegion2()~
*/
static Word CreateIRegion2(const ListExpr typeInfo) {
if (MR2_DEBUG) cerr << "CreateIRegion2() called" << endl;
return SetWord(new IRegion2(false));
}
/*
1.1.1 Type constructor ~intimeregion2~
*/
static TypeConstructor intimeregion2(
IRegion2::BasicType(),
IRegion2Property,
OutIntime<Region, OutRegion>,
InIntime<Region, InRegion>,
0, 0, // SaveToList, RestoreFromList
CreateIRegion2,
DeleteIntime<Region>,
OpenAttribute<Intime<Region> >,
SaveAttribute<Intime<Region> >, // object open and save
CloseIntime<Region>,
CloneIntime<Region>,
CastIntime<Region>,
SizeOfIntime<Region>,
CheckIRegion2 );
/*
1 Class ~URegionEmb2~
1.1 Class definition
The class definition has been moved to ~MovingRegion2Algebra.h~.
1.1 Constructors
*/
URegionEmb2::URegionEmb2( const bool Defined ) :
segmentsStartPos(0),
segmentsNum(0),
bbox(false)
{
if (MR2_DEBUG)
cerr << "URegionEmb2::URegionEmb2(bool) called"
<< endl;
}
URegionEmb2::URegionEmb2(const Interval<Instant>& tiv,
const PreciseInterval& piv,
unsigned int pos) :
segmentsStartPos(pos),
segmentsNum(0),
bbox(false),
timeInterval(tiv),
pInterval(piv){
if (MR2_DEBUG)
cerr << "URegionEmb2::URegionEmb2(tiv, piv, pos) called"
<< endl;
}
URegionEmb2::URegionEmb2(DbArray<MSegmentData2>* segments,
DbArray<PreciseMSegmentData>* preciseSegments,
DbArray<int>* preciseCoordinates,
DbArray<int>* preciseInstants,
const Interval<Instant>& tiv,
PreciseInterval& piv,
const URegionEmb& origUremb,
const DbArray<MSegmentData>* origSegments,
unsigned int pos,
unsigned int scaleFactor) :
segmentsStartPos(pos),
segmentsNum(0),
timeInterval(tiv),
pInterval(piv){
if (MR2_DEBUG)
cerr << "URegionEmb2::URegionEmb2 called "
<< "with coarse uremb input"
<< endl
<< "Number of segments in orig uremb instance: "
<< origUremb.GetSegmentsNum() << endl
<< "Number of elements in the orig DbArray: "
<< origSegments->Size() << endl
<< "Start position is "
<< origUremb.GetStartPos()
<< endl;
//Store precise part of time interval
double rest_start =
origUremb.timeInterval.start.ToDouble() -
tiv.start.ToDouble();
double rest_end =
origUremb.timeInterval.end.ToDouble() -
tiv.end.ToDouble();
if (rest_start > 0)
{
int num = 1;
int denom = 1;
while (!nearlyEqual(((rest_start*denom) - num), 0)
&& denom < 1000000000)
{
denom *= 10;
num = broughtDown(rest_start * denom);
}
mpq_class prestS(num, denom);
mpq_class testrest(rest_start);
prestS.canonicalize();
if (denom == 1000000000)
pInterval.SetPreciseInitialInstant(
testrest, preciseInstants);
else
pInterval.SetPreciseInitialInstant(
prestS, preciseInstants);
}
if (rest_end > 0)
{
int num = 1;
int denom = 1;
while (!nearlyEqual(((rest_end*denom) - num), 0)
&& denom < 1000000000)
{
denom *= 10;
num = broughtDown(rest_end * denom);
}
mpq_class prestE(num, denom);
mpq_class testrest(rest_end);
prestE.canonicalize();
if (denom == 1000000000)
pInterval.SetPreciseFinalInstant(
testrest, preciseInstants);
else
pInterval.SetPreciseFinalInstant(
prestE, preciseInstants);
}
//Store all the segments
for (int i = 0; i < origUremb.GetSegmentsNum(); i++)
{
if (MR2_DEBUG)
cerr << "URegionEmb2::URegionEmb2() processing segment "
<< i
<< ", which is segment number "
<< origUremb.GetStartPos() + i
<< " in the DbArray from "
<< origSegments->Size()
<< " elements in total..." << endl;
//Get the original MSegmentData and split coordinates
MSegmentData seg;
origUremb.GetSegment(origSegments, i, seg);
MSegmentData segment(seg);
if (MR2_DEBUG) cerr
<< "Successfully retrieved coarse segment number "
<< i << endl;
if (MR2_DEBUG)
cerr << "orig coordinates: " << endl << "isx: "
<< segment.GetInitialStartX()
<< "isy: " << segment.GetInitialStartY() << "..." << endl;
//calculate new coordinates...
int isx = broughtDown(segment.GetInitialStartX() * scaleFactor);
double restisx = segment.GetInitialStartX() * scaleFactor - isx;
mpq_class pisx(restisx);
int isy = broughtDown(segment.GetInitialStartY() * scaleFactor);
int iex = broughtDown(segment.GetInitialEndX() * scaleFactor);
int iey = broughtDown(segment.GetInitialEndY() * scaleFactor);
int fsx = broughtDown(segment.GetFinalStartX() * scaleFactor);
int fsy = broughtDown(segment.GetFinalStartY() * scaleFactor);
int fex = broughtDown(segment.GetFinalEndX() * scaleFactor);
int fey = broughtDown(segment.GetFinalEndY() * scaleFactor);
mpq_class pisy(segment.GetInitialStartY() * scaleFactor - isy);
mpq_class piex(segment.GetInitialEndX() * scaleFactor - iex);
mpq_class piey(segment.GetInitialEndY() * scaleFactor - iey);
mpq_class pfsx(segment.GetFinalStartX() * scaleFactor - fsx);
mpq_class pfsy(segment.GetFinalStartY() * scaleFactor - fsy);
mpq_class pfex(segment.GetFinalEndX() * scaleFactor - fex);
mpq_class pfey(segment.GetFinalEndY() * scaleFactor - fey);
bool isBasic = true;
if (pfey != 0 || pfex != 0 || pfsx != 0 || pfsy != 0
|| piey != 0 || piex != 0
|| pisy != 0 || pisx != 0)
{
isBasic = false;
}
if (MR2_DEBUG)
{
cerr << "Calculating new segment with isBasic = "
<< isBasic
<< endl
<< "orig isx: " << segment.GetInitialStartX()
<< ", to integer grid: " << isx
<< ", rest for precise representation: "
<< pisx << ", scaleFactor was: "
<< scaleFactor
<< endl
<< "orig isy: " << segment.GetInitialStartY()
<< ", to integer grid: " << isy
<< ", rest for precise representation: "
<< pisy << ", scaleFactor was: " << scaleFactor
<< endl
<< "orig iex: " << segment.GetInitialEndX()
<< ", to integer grid: " << iex
<< ", rest for precise representation: "
<< piex << ", scaleFactor was: " << scaleFactor
<< endl
<< "orig iey: " << segment.GetInitialEndY()
<< ", to integer grid: " << iey
<< ", rest for precise representation: "
<< piey << ", scaleFactor was: " << scaleFactor
<< endl
<< "orig fsx: " << segment.GetFinalStartX()
<< ", to integer grid: " << fsx
<< ", rest for precise representation: "
<< pfsx << ", scaleFactor was: " << scaleFactor
<< endl
<< "orig fsy: " << segment.GetFinalStartY()
<< ", to integer grid: " << fsy
<< ", rest for precise representation: "
<< pfsy << ", scaleFactor was: " << scaleFactor
<< endl
<< "orig fex: " << segment.GetFinalEndX()
<< ", to integer grid: " << fex
<< ", rest for precise representation: "
<< pfex << ", scaleFactor was: " << scaleFactor
<< endl
<< "orig fey: " << segment.GetFinalEndY()
<< ", to integer grid: " << fey
<< ", rest for precise representation: "
<< pfey << ", scaleFactor was: " << scaleFactor
<< endl;
}
/*
In the precise segment, only the difference between the absolute precise value and the grid cell edge is stored
*/
try
{
PreciseMSegmentData preciseSegment(-1);
MSegmentData2* auxDms;
preciseSegment.SetInitialStartX(pisx, preciseCoordinates);
preciseSegment.SetInitialStartY(pisy, preciseCoordinates);
preciseSegment.SetInitialEndX(piex, preciseCoordinates);
preciseSegment.SetInitialEndY(piey, preciseCoordinates);
preciseSegment.SetFinalStartX(pfsx, preciseCoordinates);
preciseSegment.SetFinalStartY(pfsy, preciseCoordinates);
preciseSegment.SetFinalEndX(pfex, preciseCoordinates);
preciseSegment.SetFinalEndY(pfey, preciseCoordinates);
if (isBasic)
{
auxDms = new MSegmentData2(
segment.GetFaceNo(),
segment.GetCycleNo(),
segment.GetSegmentNo(),
segment.GetInsideAbove(),
isx,
isy,
iex,
iey,
fsx,
fsy,
fex,
fey);
}
else
{
auxDms = new MSegmentData2(
segment.GetFaceNo(),
segment.GetCycleNo(),
segment.GetSegmentNo(),
segment.GetInsideAbove(),
isx,
isy,
iex,
iey,
fsx,
fsy,
fex,
fey,
preciseSegment,
preciseCoordinates);
}
MSegmentData2 dms(auxDms);
delete auxDms;
dms.SetDegeneratedInitial(DGM_NONE);
dms.SetDegeneratedFinal(DGM_NONE);
//Store the segments in the DbArrays
segments->Put(segmentsStartPos+segmentsNum, dms);
preciseSegments->Put(
segmentsStartPos+segmentsNum, preciseSegment);
segmentsNum++;
}
catch (...)
{
//We need to make two segments out of one, were not collinear...
//First segment...
try
{
PreciseMSegmentData preciseSegment_1(-1);
MSegmentData2* auxDms_1;
preciseSegment_1.SetInitialStartX(pisx, preciseCoordinates);
preciseSegment_1.SetInitialStartY(pisy, preciseCoordinates);
preciseSegment_1.SetInitialEndX(piex, preciseCoordinates);
preciseSegment_1.SetInitialEndY(piey, preciseCoordinates);
preciseSegment_1.SetFinalStartX(pfsx, preciseCoordinates);
preciseSegment_1.SetFinalStartY(pfsy, preciseCoordinates);
preciseSegment_1.SetFinalEndX(pfsx, preciseCoordinates);
preciseSegment_1.SetFinalEndY(pfsy, preciseCoordinates);
if (isBasic)
{
auxDms_1 = new MSegmentData2(
segment.GetFaceNo(),
segment.GetCycleNo(),
segment.GetSegmentNo(),
segment.GetInsideAbove(),
isx,
isy,
iex,
iey,
fsx,
fsy,
fsx,
fsy);
}
else
{
auxDms_1 = new MSegmentData2(
segment.GetFaceNo(),
segment.GetCycleNo(),
segment.GetSegmentNo(),
segment.GetInsideAbove(),
isx,
isy,
iex,
iey,
fsx,
fsy,
fsx,
fsy,
preciseSegment_1,
preciseCoordinates);
}
MSegmentData2 dms_1(auxDms_1);
delete auxDms_1;
dms_1.SetDegeneratedInitial(DGM_NONE);
dms_1.SetDegeneratedFinal(DGM_NONE);
//Store the segments in the DbArrays
segments->Put(segmentsStartPos+segmentsNum, dms_1);
preciseSegments->Put(
segmentsStartPos+segmentsNum, preciseSegment_1);
segmentsNum++;
}
catch (...)
{}
try
{
//Second segment...
PreciseMSegmentData preciseSegment_2(-1);
MSegmentData2* auxDms_2;
preciseSegment_2.SetInitialStartX(piex, preciseCoordinates);
preciseSegment_2.SetInitialStartY(piey, preciseCoordinates);
preciseSegment_2.SetInitialEndX(piex, preciseCoordinates);
preciseSegment_2.SetInitialEndY(piey, preciseCoordinates);
preciseSegment_2.SetFinalStartX(pfsx, preciseCoordinates);
preciseSegment_2.SetFinalStartY(pfsy, preciseCoordinates);
preciseSegment_2.SetFinalEndX(pfsx, preciseCoordinates);
preciseSegment_2.SetFinalEndY(pfsy, preciseCoordinates);
if (isBasic)
{
auxDms_2 = new MSegmentData2(
segment.GetFaceNo(),
segment.GetCycleNo(),
segment.GetSegmentNo() + 1,
segment.GetInsideAbove(),
iex,
iey,
iex,
iey,
fsx,
fsy,
fsx,
fsy);
}
else
{
auxDms_2 = new MSegmentData2(
segment.GetFaceNo(),
segment.GetCycleNo(),
segment.GetSegmentNo() + 1,
segment.GetInsideAbove(),
iex,
iey,
iex,
iey,
fsx,
fsy,
fsx,
fsy,
preciseSegment_2,
preciseCoordinates);
}
MSegmentData2 dms_2(auxDms_2);
delete auxDms_2;
dms_2.SetDegeneratedInitial(DGM_NONE);
dms_2.SetDegeneratedFinal(DGM_NONE);
//Store the segments in the DbArrays
segments->Put(segmentsStartPos+segmentsNum, dms_2);
preciseSegments->Put(
segmentsStartPos+segmentsNum, preciseSegment_2);
segmentsNum++;
}
catch (...)
{}
}
}
/*
The bbox is calculated on the integer grid, using the down left corner
of the respective cell for the minimum values and the upper right corner
for the maximum values.
We take the bbox values from the coarse region and round the values
accordingly.
*/
const Rectangle<3> rbb = origUremb.BoundingBox();
double min[3] = { broughtDown(rbb.MinD(0)),
broughtDown(rbb.MinD(1)),
timeInterval.start.ToDouble() };
double max[3] = { roundedUp(rbb.MaxD(0)),
roundedUp(rbb.MaxD(1)),
timeInterval.end.ToDouble() };
bbox.Set(true, min, max);
}
/*
1.1 Methods for database operators
1.1.1 Method ~Transform()~
*/
void URegionEmb2::Transform(double deltaX, double deltaY,
DbArray<MSegmentData2>* segments,
DbArray<PreciseMSegmentData>* preciseSegments,
DbArray<int>* preciseCoordinates)
{
if (MR2_DEBUG)
cerr << "URegionEmb2::Transform() called" << endl;
/*
First transform double paramters into fractions in order to avoid
rounding errors.
*/
int num = 1;
int denom = 1;
while (!nearlyEqual(((deltaX*denom) - num), 0) && denom < 1000000000)
{
denom *= 10;
num = broughtDown(deltaX * denom);
}
mpq_class pDeltaX(num, denom);
pDeltaX.canonicalize();
if (pDeltaX == 0)
pDeltaX = deltaX;
if (MR2_DEBUG) cerr << "new deltaX: " << pDeltaX << endl;
num = 1;
denom = 1;
while (!nearlyEqual(((deltaY*denom) - num), 0) && denom < 1000000000)
{
denom *= 10;
num = broughtDown(deltaY * denom);
}
mpq_class pDeltaY(num, denom);
pDeltaY.canonicalize();
if (pDeltaY == 0)
pDeltaY = deltaY;
if (MR2_DEBUG) cerr << "new deltaY: " << pDeltaY << endl;
for (int j = 0; j < this->GetSegmentsNum(); j++)
{
if (MR2_DEBUG)
cerr << "Transforming segment number " << j
<< " by deltaX = " << pDeltaX <<", deltaY = "
<< pDeltaY << " " << endl;
MSegmentData2 segment;
this->GetSegment(segments, j, segment);
PreciseMSegmentData psegment;
this->GetPreciseSegment(preciseSegments, j, psegment);
/*
Calculate the new coordinates by adding the deltas.
*/
mpq_class newInitialStartX =
psegment.GetInitialStartX(preciseCoordinates)
+ segment.GetInitialStartX() + pDeltaX;
mpq_class newInitialStartY =
psegment.GetInitialStartY(preciseCoordinates)
+ segment.GetInitialStartY() + pDeltaY;
mpq_class newInitialEndX =
psegment.GetInitialEndX(preciseCoordinates)
+ segment.GetInitialEndX() + pDeltaX;
mpq_class newInitialEndY =
psegment.GetInitialEndY(preciseCoordinates)
+ segment.GetInitialEndY() + pDeltaY;
mpq_class newFinalStartX =
psegment.GetFinalStartX(preciseCoordinates) +
segment.GetFinalStartX() + pDeltaX;
mpq_class newFinalStartY =
psegment.GetFinalStartY(preciseCoordinates) +
segment.GetFinalStartY() + pDeltaY;
mpq_class newFinalEndX =
psegment.GetFinalEndX(preciseCoordinates) +
segment.GetFinalEndX() + pDeltaX;
mpq_class newFinalEndY =
psegment.GetFinalEndY(preciseCoordinates) +
segment.GetFinalEndY() + pDeltaY;
if (MR2_DEBUG)
cerr << "New coordinates: "
<< endl
<< "(" << newInitialStartX << ", "
<< newInitialStartY << ", "
<< newInitialEndX
<< ", " << newInitialEndY << ", "
<< newFinalStartX << ", "
<< newFinalStartY << ", "
<< newFinalEndX << ", "
<< newFinalEndY << "): "
<< "Splitting now..." << endl;
/*
Split the absolute precise coordinates in integer part and precise rest and
writes the resulting coordinates back to the db arrays.
Also reset the isBasicSegment flag and sets it accoring to new values.
*/
segment.SetIsBasicSegment(true);
int temp = broughtDown(newInitialStartX.get_d());
segment.SetInitialStartX(temp);
psegment.SetInitialStartX(
newInitialStartX - temp, preciseCoordinates);
if (newInitialStartX - temp != 0)
segment.SetIsBasicSegment(false);
temp = broughtDown(newInitialStartY.get_d());
segment.SetInitialStartY(temp);
psegment.SetInitialStartY(
newInitialStartY - temp, preciseCoordinates);
if (newInitialStartY - temp != 0)
segment.SetIsBasicSegment(false);
temp = broughtDown(newInitialEndX.get_d());
segment.SetInitialEndX(temp);
psegment.SetInitialEndX(
newInitialEndX - temp, preciseCoordinates);
if (newInitialEndX - temp != 0)
segment.SetIsBasicSegment(false);
temp = broughtDown(newInitialEndY.get_d());
segment.SetInitialEndY(temp);
psegment.SetInitialEndY(
newInitialEndY - temp, preciseCoordinates);
if (newInitialEndY - temp != 0)
segment.SetIsBasicSegment(false);
temp = broughtDown(newFinalStartX.get_d());
segment.SetFinalStartX(temp);
psegment.SetFinalStartX(
newFinalStartX - temp, preciseCoordinates);
if (newFinalStartX - temp != 0)
segment.SetIsBasicSegment(false);
temp = broughtDown(newFinalStartY.get_d());
segment.SetFinalStartY(temp);
psegment.SetFinalStartY(
newFinalStartY - temp, preciseCoordinates);
if (newFinalStartY - temp != 0)
segment.SetIsBasicSegment(false);
temp = broughtDown(newFinalEndX.get_d());
segment.SetFinalEndX(temp);
psegment.SetFinalEndX(
newFinalEndX - temp, preciseCoordinates);
if (newFinalEndX - temp != 0)
segment.SetIsBasicSegment(false);
temp = broughtDown(newFinalEndY.get_d());
segment.SetFinalEndY(temp);
psegment.SetFinalEndY(
newFinalEndY - temp, preciseCoordinates);
if (newFinalEndY - temp != 0)
segment.SetIsBasicSegment(false);
//Write the segments back
this->PutSegment(segments, j, segment, false);
this->PutPreciseSegment(preciseSegments, j, psegment);
}
}
/*
1.1.1 Method ~Scale()~
*/
void URegionEmb2::Scale(double deltaX, double deltaY,
DbArray<MSegmentData2>* segments,
DbArray<PreciseMSegmentData>* preciseSegments,
DbArray<int>* preciseCoordinates)
{
if (MR2_DEBUG)
cerr << "URegionEmb2::Scale() called" << endl;
/*
First transform the double paramters into fractions in order to avoid
rounding errors.
*/
int num = 1;
int denom = 1;
while (!nearlyEqual(((deltaX*denom) - num), 0))
{
denom *= 10;
num = broughtDown(deltaX * denom);
}
mpq_class pDeltaX(num, denom);
pDeltaX.canonicalize();
if (pDeltaX == 0)
pDeltaX = deltaX;
if (MR2_DEBUG) cerr << "new deltaX: " << pDeltaX << endl;
num = 1;
denom = 1;
while (!nearlyEqual(((deltaY*denom) - num), 0))
{
denom *= 10;
num = broughtDown(deltaY * denom);
}
mpq_class pDeltaY(num, denom);
pDeltaY.canonicalize();
if (pDeltaY == 0)
pDeltaY = deltaY;
if (MR2_DEBUG) cerr << "new deltaY: " << pDeltaY << endl;
for (int j = 0; j < this->GetSegmentsNum(); j++)
{
if (MR2_DEBUG)
cerr << "Scaling segment " << j
<< ", factors are: " << pDeltaX << ", "
<< pDeltaY << " " << endl;
MSegmentData2 segment;
this->GetSegment(segments, j, segment);
PreciseMSegmentData psegment;
this->GetPreciseSegment(preciseSegments, j, psegment);
/*
Calculate the new coordinates (precise calculation)
*/
mpq_class newInitialStartX =
(psegment.GetInitialStartX(preciseCoordinates) +
segment.GetInitialStartX()) * pDeltaX;
mpq_class newInitialStartY =
(psegment.GetInitialStartY(preciseCoordinates) +
segment.GetInitialStartY()) * pDeltaY;
mpq_class newInitialEndX =
(psegment.GetInitialEndX(preciseCoordinates) +
segment.GetInitialEndX()) * pDeltaX;
mpq_class newInitialEndY =
(psegment.GetInitialEndY(preciseCoordinates) +
segment.GetInitialEndY()) * pDeltaY;
mpq_class newFinalStartX =
(psegment.GetFinalStartX(preciseCoordinates) +
segment.GetFinalStartX()) * pDeltaX;
mpq_class newFinalStartY =
(psegment.GetFinalStartY(preciseCoordinates) +
segment.GetFinalStartY()) * pDeltaY;
mpq_class newFinalEndX =
(psegment.GetFinalEndX(preciseCoordinates) +
segment.GetFinalEndX()) * pDeltaX;
mpq_class newFinalEndY =
(psegment.GetFinalEndY(preciseCoordinates) +
segment.GetFinalEndY()) * pDeltaY;
if (MR2_DEBUG)
cerr << "New coordinates: "
<< endl
<< "(" << newInitialStartX << ", "
<< newInitialStartY << ", "
<< newInitialEndX
<< ", " << newInitialEndY << ", "
<< newFinalStartX << ", "
<< newFinalStartY << ", "
<< newFinalEndX << ", "
<< newFinalEndY << "): "
<< "Splitting now..." << endl;
/*
Split results in integer part and precise rest.
Also reset flag isBasicSegment.
*/
segment.SetIsBasicSegment(true);
int temp = broughtDown(newInitialStartX.get_d());
segment.SetInitialStartX(temp);
psegment.SetInitialStartX(
newInitialStartX - temp, preciseCoordinates);
if (newInitialStartX - temp != 0)
segment.SetIsBasicSegment(false);
temp = broughtDown(newInitialStartY.get_d());
segment.SetInitialStartY(temp);
psegment.SetInitialStartY(
newInitialStartY - temp, preciseCoordinates);
if (newInitialStartY - temp != 0)
segment.SetIsBasicSegment(false);
temp = broughtDown(newInitialEndX.get_d());
segment.SetInitialEndX(temp);
psegment.SetInitialEndX(
newInitialEndX - temp, preciseCoordinates);
if (newInitialEndX - temp != 0)
segment.SetIsBasicSegment(false);
temp = broughtDown(newInitialEndY.get_d());
segment.SetInitialEndY(temp);
psegment.SetInitialEndY(
newInitialEndY - temp, preciseCoordinates);
if (newInitialEndY - temp != 0)
segment.SetIsBasicSegment(false);
temp = broughtDown(newFinalStartX.get_d());
segment.SetFinalStartX(temp);
psegment.SetFinalStartX(
newFinalStartX - temp, preciseCoordinates);
if (newFinalStartX - temp != 0)
segment.SetIsBasicSegment(false);
temp = broughtDown(newFinalStartY.get_d());
segment.SetFinalStartY(temp);
psegment.SetFinalStartY(
newFinalStartY - temp, preciseCoordinates);
if (newFinalStartY - temp != 0)
segment.SetIsBasicSegment(false);
temp = broughtDown(newFinalEndX.get_d());
segment.SetFinalEndX(temp);
psegment.SetFinalEndX(
newFinalEndX - temp, preciseCoordinates);
if (newFinalEndX - temp != 0)
segment.SetIsBasicSegment(false);
temp = broughtDown(newFinalEndY.get_d());
segment.SetFinalEndY(temp);
psegment.SetFinalEndY(
newFinalEndY - temp, preciseCoordinates);
if (newFinalEndY - temp != 0)
segment.SetIsBasicSegment(false);
//Write the segments back
this->PutSegment(segments, j, segment, false);
this->PutPreciseSegment(preciseSegments, j, psegment);
}
}
/*
1.1.1 Method ~TemporalFunction()~
This method calculates the resulting Region instance by evaluating the
URegionEmb2 instance at one single instant t.
The coordinates are first calculated at full precision. As region uses
double coordinates, the result is then transformed to double by
ignoring the precise part of the coordinates and multiplying the integer
part with scaleFactor.
Note that because of ignoring the precise parts, the result might not be
a valid region instance in all cases. Therefor ~res~ might be not defined
at the end in spite of valid parameters.
*/
void URegionEmb2::TemporalFunction(
const DbArray<MSegmentData2>* segments,
const DbArray<PreciseMSegmentData>* preciseSegments,
const DbArray<int>* preciseCoordinates,
const DbArray<int>* preciseInstants,
const Instant& t,
const mpq_class& preciseInstant,
const int scaleFactor,
Region& res,
bool ignoreLimits ) const {
if (MR2_DEBUG){
cerr << "URegionEmb2::TemporalFunction() called" << endl;
}
/*
Calculate segments at specified instant using full precision in all
three dimensions.
Coarse the resulting segments by simply ignoring the precise part of
each coordinate, after multiplication with scaleFactor.
Remove degenerated segments of initial or final instant, when they
are not border of any region, and try to create region. If the result
is no valid region instance, ~res~ is set to not defined.
*/
PreciseInterval pInt = pInterval;
mpq_class pt0 = pInt.GetPreciseInitialInstant(preciseInstants) +
timeInterval.start.ToDouble();
mpq_class pt1 = pInt.GetPreciseFinalInstant(preciseInstants) +
timeInterval.end.ToDouble();
mpq_class pt;
bool instantContained = false;
assert(t.IsDefined());
/*
We now check if the given instant is contained in the time interval.
If this is not the case the result value is set to not defined.
*/
if (t.IsDefined())
{
pt = t.ToDouble() + preciseInstant;
if (MR2_DEBUG)
cerr << "Werte für check von instantContained: "
<< endl
<< "pt0, pt, pt1: "
<< pt0 << ", " << pt << ", " << pt1
<< endl
<< "Damit ergibt preciseBetween(pt0, pt, pt1) "
<< preciseBetween(pt0, pt, pt1)
<< endl
<< "und cmp(pt0, pt) " << cmp(pt0, pt)
<< endl
<< "und cmp(pt1, pt) " << cmp(pt1, pt)
<< endl;
instantContained = (preciseBetween(pt0, pt, pt1)
|| (((cmp(pt0, pt) == 0 && timeInterval.lc)
|| (cmp(pt1, pt) == 0 && timeInterval.rc))));
if (!instantContained && !ignoreLimits)
{
if (MR2_DEBUG)
cerr << "instant not contained in interval" << endl;
res.SetDefined(false);
return;
}
}
assert(ignoreLimits || instantContained);
res.Clear();
if(!t.IsDefined() || !(ignoreLimits || instantContained) ) {
res.SetDefined( false );
return;
}
res.SetDefined( true );
bool initialInstant = cmp(pt0, pt) == 0;
bool finalInstant = cmp(pt1, pt) == 0;
mpq_class f;
if (cmp(pt0, pt1) == 0)
{
f = 0;
}
else
{
f = (pt - pt0)/(pt1 - pt0);
}
int partnerno = 0;
res.StartBulkLoad();
for (unsigned int i = 0; i < segmentsNum; i++) {
if (MR2_DEBUG){
cerr << "URegionEmb2::TemporalFunction() segment #"
<< i
<< "/"
<< segmentsNum
<< " ("
<< segmentsStartPos
<< ")"
<< endl;
}
MSegmentData2 dms;
segments->Get(segmentsStartPos+i, &dms);
PreciseMSegmentData pdms;
preciseSegments->Get(segmentsStartPos+i, &pdms);
mpq_class pxs =
dms.GetInitialStartX() +
pdms.GetInitialStartX(preciseCoordinates)
+ (dms.GetFinalStartX() +
pdms.GetFinalStartX(preciseCoordinates) -
(dms.GetInitialStartX() +
pdms.GetInitialStartX(preciseCoordinates)))*f;
mpq_class pys =
dms.GetInitialStartY() +
pdms.GetInitialStartY(preciseCoordinates)
+ (dms.GetFinalStartY() +
pdms.GetFinalStartY(preciseCoordinates) -
(dms.GetInitialStartY() +
pdms.GetInitialStartY(preciseCoordinates)))*f;
mpq_class pxe =
dms.GetInitialEndX() +
pdms.GetInitialEndX(preciseCoordinates)
+ (dms.GetFinalEndX() +
pdms.GetFinalEndX(preciseCoordinates) -
(dms.GetInitialEndX() +
pdms.GetInitialEndX(preciseCoordinates)))*f;
mpq_class pye =
dms.GetInitialEndY() +
pdms.GetInitialEndY(preciseCoordinates)
+ (dms.GetFinalEndY() +
pdms.GetFinalEndY(preciseCoordinates) -
(dms.GetInitialEndY() +
pdms.GetInitialEndY(preciseCoordinates)))*f;
if (MR2_DEBUG){
cerr << "URegionEmb2::TemporalFunction() "
<< "next precise segment is ("
<< pxs << ", " << pys << ", " << pxe << ", "
<< pye << ")" << endl;
cerr << "Scaling now with scale factor " << scaleFactor
<< " and converting to double values." << endl;
}
pxs = pxs / scaleFactor;
pys = pys / scaleFactor;
pxe = pxe / scaleFactor;
pye = pye / scaleFactor;
double xs = pxs.get_d();
double ys = pys.get_d();
double xe = pxe.get_d();
double ye = pye.get_d();
if (MR2_DEBUG){
cerr << "URegionEmb2::TemporalFunction() "
<< "next value is ("
<< xs << ", " << ys << ", " << xe << ", "
<< ye << ")"
<< endl;
}
if (nearlyEqual(xs, xe) && nearlyEqual(ys, ye)) {
if (MR2_DEBUG){
cerr << "URegionEmb2::TemporalFunction() "
<< "reduced to point"
<< endl;
}
continue;
}
assert(dms.GetDegeneratedInitial() != DGM_UNKNOWN);
assert(dms.GetDegeneratedFinal() != DGM_UNKNOWN);
if ((initialInstant
&& dms.GetDegeneratedInitial() == DGM_IGNORE)
|| (finalInstant
&& dms.GetDegeneratedFinal() == DGM_IGNORE)) {
if (MR2_DEBUG){
cerr << "URegionEmb2::TemporalFunction() "
<< "ignored degenerated"
<< endl;
}
continue;
}
Point s(true, xs, ys);
Point e(true, xe, ye);
if (AlmostEqual(s, e))
{
cerr << endl
<< "--------------------------------------------------"
<< endl
<< "URegionEmb2::TemporalFunction() "
<< "halfsegment creation failure, both "
<< "points almost equal."
<< endl
<< "No valid region instance can be created."
<< endl
<< "--------------------------------------------------"
<< endl;
res.SetDefined(false);
return;
}
HalfSegment hs(true, s, e);
hs.attr.faceno = 0;
hs.attr.cycleno = 0;
hs.attr.edgeno = partnerno;
hs.attr.partnerno = partnerno++;
if (initialInstant
&& dms.GetDegeneratedInitial() == DGM_INSIDEABOVE){
hs.attr.insideAbove = true;
}else if (initialInstant
&& dms.GetDegeneratedInitial() == DGM_NOTINSIDEABOVE){
hs.attr.insideAbove = false;
}else if (finalInstant
&& dms.GetDegeneratedFinal() == DGM_INSIDEABOVE){
hs.attr.insideAbove = true;
}else if (finalInstant
&& dms.GetDegeneratedFinal() == DGM_NOTINSIDEABOVE){
hs.attr.insideAbove = false;
}else{
hs.attr.insideAbove = dms.GetInsideAbove();
}
if (MR2_DEBUG){
cerr << "URegionEmb2::TemporalFunction() "
<< "Adding hs="
<< hs
<< endl;
}
if (!res.InsertOk(hs))
{
if (MR2_DEBUG){
cerr << "URegionEmb2::TemporalFunction() "
<< "adding hs failed! "
<< "Ignoring hs="
<< hs
<< endl;
}
}
else {
res += hs;
hs.SetLeftDomPoint(!hs.IsLeftDomPoint());
if (MR2_DEBUG){
cerr << "URegionEmb2::TemporalFunction() "
<< "Adding hs="
<< hs
<< endl;
}
res += hs;
}
}
//Try region calculation
res.EndBulkLoad();
if (!res.IsDefined())
{
if (MR2_DEBUG)
{
cerr << "URegionEmb2::TemporalFunction() failed. "
<< "EndBulkLoad method did not return a valid region unit."
<< endl;
}
res.SetDefined(false);
return;
}
if (MR2_DEBUG){
for (int i = 0; i < res.Size(); i++) {
HalfSegment hs;
res.Get(i, hs);
cerr << "URegionEmb2::TemporalFunction() segment #"
<< i
<< " lp=("
<< hs.GetLeftPoint().GetX()
<< ", "
<< hs.GetLeftPoint().GetY()
<< ") rp=("
<< hs.GetRightPoint().GetX()
<< ", "
<< hs.GetRightPoint().GetY()
<< ") ldp="
<< hs.IsLeftDomPoint()
<< " attr="
<< hs.attr.faceno
<< " "
<< hs.attr.cycleno
<< " "
<< hs.attr.edgeno
<< " "
<< hs.attr.partnerno
<< " "
<< hs.attr.insideAbove
<< endl;
}
}
}
/*
1.1 Methods required to act as unit in ~Mapping~ template
1.1.1 Method ~IsValid()~
*/
bool URegionEmb2::IsValid(void) const {
return true;
}
/*
1.1.1 Operator ~==~
*/
bool URegionEmb2::operator==(const URegionEmb2& ur) const {
return (timeInterval == ur.timeInterval);
}
/*
1.1.1 Method ~Before()~
*/
bool URegionEmb2::Before(const URegionEmb2& ur) const {
return timeInterval.Before(ur.timeInterval);
}
/*
1.1.1 Method ~Compare()~
*/
bool URegionEmb2::Compare(const URegionEmb2* ur) const {
assert(false);
return false;
}
/*
1.1 Access methods
1.1.1 Method ~SetSegmentsNum()~
*/
void URegionEmb2::SetSegmentsNum(int i){
segmentsNum=i;
}
/*
1.1.1 Method ~SetStartPos()~
*/
void URegionEmb2::SetStartPos(int i){
segmentsStartPos=i;
}
/*
1.1.1 Method ~GetSegmentsNum()~
*/
int URegionEmb2::GetSegmentsNum(void) const {
if (MR2_DEBUG)
cerr << "URegionEmb2::GetSegmentsNum() called, num="
<< segmentsNum
<< endl;
return segmentsNum;
}
/*
1.1.1 Method ~GetStartPos()~
*/
const int URegionEmb2::GetStartPos() const{
if (MR2_DEBUG)
cerr << "URegionEmb2::GetStartPos() called, sp="
<< segmentsStartPos
<< endl;
return segmentsStartPos;
}
/*
1.1.1 Method ~BoundingBox()~
*/
const Rectangle<3> URegionEmb2::BoundingBox(const Geoid* geoid /*=0*/) const {
if (MR2_DEBUG) cerr << "URegionEmb2::BoundingBox() called" << endl;
if(geoid){
cerr << __PRETTY_FUNCTION__ << ": Spherical geometry not implemented."
<< endl;
assert( !geoid ); // TODO: implement spherical geometry case
}
return bbox;
}
/*
1.1.1 Assignment Operator
*/
URegionEmb2& URegionEmb2::operator=(const URegionEmb2& U) {
segmentsStartPos = U.segmentsStartPos;
segmentsNum = U.segmentsNum;
bbox = U.bbox;
timeInterval = U.timeInterval;
return *this;
}
/*
1.1.1 Method ~GetSegment()~
*/
void URegionEmb2::GetSegment(
const DbArray<MSegmentData2>* segments,
int pos,
MSegmentData2& dms) const {
if (MR2_DEBUG)
cerr << "URegionEmb2::GetSegment() called, pos=" << pos
<< ", segments="
<< segments
<< endl;
segments->Get(segmentsStartPos+pos, dms);
}
/*
1.1.1 Method ~GetPreciseSegment()~
*/
void URegionEmb2::GetPreciseSegment(
const DbArray<PreciseMSegmentData>* preciseSegments,
int pos,
PreciseMSegmentData& pdms) const {
preciseSegments->Get(segmentsStartPos+pos, pdms);
}
/*
1.1.1 Method ~PutSegment()~
*/
void URegionEmb2::PutSegment(
DbArray<MSegmentData2>* segments,
int pos,
const MSegmentData2& dms,
const bool isNew) {
if (MR2_DEBUG)
cerr << "URegionEmb2::PutSegment() called, pos=" << pos <<
" " << segmentsStartPos << dms.ToString() << endl;
segments->Put(segmentsStartPos+pos, dms);
if(isNew){
segmentsNum++;
}
}
/*
1.1.1 Method ~PutPreciseSegment()~
*/
void URegionEmb2::PutPreciseSegment(
DbArray<PreciseMSegmentData>* segments,
int pos,
const PreciseMSegmentData& dms) {
if (MR2_DEBUG)
cerr << "UregionEmb2::PutPreciseSegment() called, pos= "
<< pos << endl;
segments->Put(segmentsStartPos+pos, dms);
}
/*
1.1.1 Method ~PutCoordinate()~
*/
void URegionEmb2::PutCoordinate(
DbArray<int>* coords,
int pos,
const int& c) {
if (MR2_DEBUG)
cerr << "URegionEmb2::PutCoordinate() called, pos= "
<< pos << endl;
coords->Put(pos, c);
}
/*
1.1.1 Method ~SetSegmentInsideAbove()~
*/
void URegionEmb2::SetSegmentInsideAbove(
DbArray<MSegmentData2>* segments,
int pos,
bool insideAbove) {
if (MR2_DEBUG)
cerr << "URegionEmb2::SetSegmentInsideAbove() called, segments="
<< segments
<< endl;
MSegmentData2 auxDms;
segments->Get(segmentsStartPos+pos, &auxDms);
MSegmentData2 dms( auxDms );
dms.SetInsideAbove(insideAbove);
segments->Put(segmentsStartPos+pos, dms);
}
/*
1.1 In and out functions
1.1.1 Function ~InURegionEmbedded2()~
*/
static URegionEmb2* InURegionEmbedded2(
const ListExpr instance,
const int errorPos,
ListExpr& errorInfo,
DbArray<MSegmentData2>* segments,
DbArray<PreciseMSegmentData>* preciseSegments,
DbArray<int>* preciseCoordinates,
DbArray<int>* preciseInstants,
unsigned int segmentsStartPos) {
if (MR2_DEBUG)
cerr << "InURegionEmbedded2() called, segmentsStartPos = "
<< segmentsStartPos << endl;
/*
Please that ~Region~ creation is done as shown in ~SpatialAlgebra~.
See there for more details.
*/
if (nl->ListLength(instance) <= 1) {
cerr << "uregion not in format "
<< "(<interval> <faces>)"
<< endl;
return 0;
}
if (MR2_DEBUG)
cerr << "InURegionEmbedded() (<interval> <faces>) found"
<< endl;
//Get Inner List representing the time interval
ListExpr interval = nl->First(instance);
/*
First we check the syntactical correctness of the list expression representing the time interval.
No syntax check will be done for the fifth part, which is the representation of
the precise time interval.
The syntax check of this part will be done later, and - if it fails - the part will be ignored
and a basic interval will be created instead.
*/
if (nl->ListLength(interval) != 5
|| !nl->IsAtom(nl->First(interval))
|| (nl->AtomType(nl->First(interval)) != StringType
&& nl->AtomType(nl->First(interval)) != RealType
&& nl->AtomType(nl->First(interval)) != IntType)
|| !nl->IsAtom(nl->Second(interval))
|| (nl->AtomType(nl->Second(interval)) != StringType
&& nl->AtomType(nl->Second(interval)) != RealType
&& nl->AtomType(nl->Second(interval)) != IntType)
|| !nl->IsAtom(nl->Third(interval))
|| nl->AtomType(nl->Third(interval)) != BoolType
|| !nl->IsAtom(nl->Fourth(interval))
|| nl->AtomType(nl->Fourth(interval)) != BoolType) {
cerr << "uregion interval not in correct format "
<< endl;
return 0;
}
/*
Create first a basic interval (one in the integer grid). The part of the list
expression describing the time information may already be given as integer values,
but we cannot be sure about that. Therefor the components for start and end time
need to be split into an integer component and maybe some fraction that will later
be added to the precise time interval given in nl->fifth(interval).
*/
int int_start = 0;
int int_end = 0;
double rest_start = 0.0;
double rest_end = 0.0;
bool correct;
Instant *start;
Instant *end;
if (nl->AtomType(nl->First(interval)) == RealType)
{
int_start = (int)nl->RealValue(
nl->First(interval));
rest_start = nl->RealValue(nl->First(interval))
- int_start;
ListExpr newStart =
nl->RealAtom((double)int_start);
start = (Instant *) InInstant(
nl->TheEmptyList(),
newStart,
errorPos,
errorInfo,
correct).addr;
if (!correct) {
if (!correct) {
cerr << "uregion interval invalid start"
<< " time" << endl;
return 0;
}
return 0;
}
}
else if (nl->AtomType(nl->First(interval)) == IntType){
int_start = nl->IntValue(nl->First(interval));
ListExpr newStart =
nl->RealAtom((double)int_start);
start = (Instant *) InInstant(
nl->TheEmptyList(),
newStart,
errorPos,
errorInfo,
correct).addr;
if (!correct) {
if (!correct) {
cerr << "uregion interval invalid start"
<<" time" << endl;
return 0;
}
return 0;
}
}
else {
Instant *help =
(Instant *) InInstant(nl->TheEmptyList(),
nl->First(interval),
errorPos,
errorInfo,
correct).addr;
int_start = broughtDown(help->ToDouble());
rest_start = help->ToDouble() - int_start;
ListExpr newStart =
nl->RealAtom((double)int_start);
start = (Instant *) InInstant(
nl->TheEmptyList(),
newStart,
errorPos,
errorInfo,
correct).addr;
delete help;
}
if (nl->AtomType(nl->Second(interval)) == RealType)
{
int_end = (int)nl->RealValue(
nl->Second(interval));
rest_end = nl->RealValue(nl->Second(interval))
- int_end;
ListExpr newEnd = nl->IntAtom((double)int_end);
end = (Instant *) InInstant(nl->TheEmptyList(),
newEnd,
errorPos,
errorInfo,
correct ).addr;
if (!correct) {
correct = false;
delete start;
cerr << "uregion interval invalid end time"
<< endl;
return 0;
}
}
else if (nl->AtomType(nl->Second(interval)) == IntType){
int_end = nl->IntValue(nl->Second(interval));
ListExpr newEnd = nl->IntAtom((double)int_end);
end = (Instant *) InInstant(nl->TheEmptyList(),
newEnd,
errorPos,
errorInfo,
correct ).addr;
if (!correct) {
correct = false;
delete start;
cerr << "uregion interval invalid end time"
<< endl;
return 0;
}
}
else {
Instant *help =
(Instant *) InInstant(nl->TheEmptyList(),
nl->Second(interval),
errorPos,
errorInfo,
correct).addr;
int_end = broughtDown(help->ToDouble());
rest_end = help->ToDouble() - int_end;
ListExpr new_end =
nl->RealAtom((double)int_end);
end = (Instant *) InInstant(
nl->TheEmptyList(),
new_end,
errorPos,
errorInfo,
correct).addr;
delete help;
}
bool lc = nl->BoolValue(nl->Third(interval));
bool rc = nl->BoolValue(nl->Fourth(interval));
/*
Now create the precise interval. Don't forget to add precise information
obtained by splitting the first two components of the interval list.
After creation of the precise interval, the syntax of the complete time
interval can be checked.
*/
ListExpr preciseInterval = nl->Fifth(interval);
PreciseInterval preciseTimeInterval(-1);
preciseTimeInterval.SetPreciseInitialInstant(
mpq_class(0), preciseInstants);
preciseTimeInterval.SetPreciseFinalInstant(
mpq_class(0), preciseInstants);
bool hasPreciseRepresentation = true;
/*
Check if we have precise time interval information from the splitting before.
*/
if (rest_start > 0)
{
int num = 1;
int denom = 1;
while (!nearlyEqual(((rest_start*denom) -
num), 0) && denom < 1000000000)
{
denom *= 10;
num = broughtDown(rest_start * denom);
}
mpq_class prestS(num, denom);
mpq_class testrest(rest_start);
prestS.canonicalize();
if (denom == 1000000000 || prestS == 0)
preciseTimeInterval.
SetPreciseInitialInstant(
testrest, preciseInstants);
else
preciseTimeInterval.
SetPreciseInitialInstant(
prestS, preciseInstants);
}
if (rest_end > 0)
{
int num = 1;
int denom = 1;
while (!nearlyEqual(((rest_end*denom) - num), 0)
&& denom < 1000000000)
{
denom *= 10;
num = broughtDown(rest_end * denom);
}
mpq_class prestE(num, denom);
mpq_class testrest(rest_end);
prestE.canonicalize();
if (denom == 1000000000 || prestE == 0)
preciseTimeInterval.SetPreciseFinalInstant
(testrest, preciseInstants);
else
preciseTimeInterval.
SetPreciseFinalInstant
(prestE, preciseInstants);
}
/*
Check the syntax for the precise representation of the time interval,
and simply ignore it if it is not okay.
*/
if (nl->ListLength(preciseInterval) != 2
|| !nl->IsAtom(nl->First(preciseInterval))
|| nl->AtomType(nl->First
(preciseInterval)) != TextType
|| !nl->IsAtom(nl->Second(preciseInterval))
|| nl->AtomType(nl->Second
(preciseInterval)) != TextType){
hasPreciseRepresentation = false;
}
if (hasPreciseRepresentation){
mpq_class pstart2;
mpq_class pend2;
try
{
textTypeToGmpType(nl->First
(preciseInterval), pstart2);
textTypeToGmpType(nl->Second
(preciseInterval), pend2);
}
catch (invalid_argument& e)
{
cerr << endl
<< "--------------------------------"
<< "-------------------------------" << endl
<< "Checking time interval failed." << endl
<< e.what() << endl
<< "----------------------------------"
<< "-----------------------------" << endl;
return 0;
}
preciseTimeInterval.SetPreciseInitialInstant(
preciseTimeInterval.GetPreciseInitialInstant
(preciseInstants) +
pstart2, preciseInstants);
preciseTimeInterval.SetPreciseFinalInstant(
preciseTimeInterval.GetPreciseFinalInstant
(preciseInstants) +
pend2, preciseInstants);
}
/*
Now we check the syntax of the time interval. If we don't have a correct interval
on the integer grid, we check if it is correct considering the precise part of it.
*/
if (end->ToDouble() <= start->ToDouble()) {
if (MR2_DEBUG)
cerr << "Time interval on integer grid invalid"
<< " or start and end equal"
<< endl
<< "Check with precise values..."
<< endl
<< "start to double is " << start->ToDouble()
<< endl
<< "end to double is " << end->ToDouble()
<< endl;
int compare_value =
cmp(preciseTimeInterval.
GetPreciseFinalInstant(preciseInstants),
preciseTimeInterval.
GetPreciseInitialInstant(preciseInstants));
if (MR2_DEBUG)
cerr << "Precise start is "
<< preciseTimeInterval.
GetPreciseFinalInstant(preciseInstants)
<< endl
<< "Precise end is "
<< preciseTimeInterval.
GetPreciseInitialInstant(preciseInstants)
<< "cmp(preciseEnd, preciseStart) is "
<< cmp(preciseTimeInterval.
GetPreciseFinalInstant(preciseInstants),
preciseTimeInterval.
GetPreciseInitialInstant(preciseInstants))
<< endl;
if (end->ToDouble() < start->ToDouble()
|| (end->ToDouble() == start->ToDouble()
&& compare_value < 0)
|| (compare_value == 0
&& end->ToDouble() == start->ToDouble()
&& !(lc && rc)))
{
cerr << "uregion invalid interval"
<< endl;
delete start;
delete end;
return 0;
}
}
Interval<Instant> tinterval(*start, *end, lc, rc);
DateTime intervalLen = *end-*start;
delete start;
delete end;
/*
Create ~URegionEmb2~ instance and pass storage of segments, if we received
any.
A detailed syntax check is needed in order to be sure that a correct unit
will result. For that purpose, all the segments are checked and compared to each other:
So far this is done by inserting the segments into a region and relying on the
algorithms there for syntax check.
Note that this way region units that are correct just because of their precise
coordinate information will be deleted because of this syntax check fails!
This is only a temporarely solution!
*/
URegionEmb2* uregion = new URegionEmb2(
tinterval, preciseTimeInterval, segmentsStartPos);
unsigned int faceno = 0;
unsigned int partnerno = 0;
ListExpr faces = nl->Second(instance);
Region cr(0);
cr.StartBulkLoad();
if (nl->ListLength(faces) == 0) {
cerr << "uregion should contain at least one face"
<< endl;
delete uregion;
return 0;
}
/*
... all this is similar to ~Region~ creation in ~SpatialAlgebra~...
*/
while (!nl->IsEmpty(faces)) {
if (MR2_DEBUG)
cerr << "InURegionEmbedded2() face #"
<< faceno << endl;
ListExpr cycles = nl->First(faces); //first face
if (nl->ListLength(cycles) == 0) {
cerr << "uregion face should contain at least one cycle"
<< endl;
delete uregion;
return 0;
}
unsigned int cycleno = 0;
unsigned int pointno = 0;
while (!nl->IsEmpty(cycles)) {
if (MR2_DEBUG)
cerr << "InURegionEmbedded2() cycle #"
<< cycleno << endl;
/*
For each cycle a region is created and the segments are inserted to it
in order to get the direction information.
*/
Region rDir(0);
rDir.StartBulkLoad();
ListExpr cyclepoints = nl->First(cycles); //first cycle
if (nl->ListLength(cyclepoints) < 3) {
cerr << "uregion cycle should contain at "
<< "least three points"
<< endl;
delete uregion;
return 0;
}
ListExpr firstPoint = nl->First(cyclepoints);
//the first point of this cycle
ListExpr prevPoint = 0;
unsigned int initialSegmentsNum =
uregion->GetSegmentsNum();
while (!nl->IsEmpty(cyclepoints)) {
if (MR2_DEBUG)
cerr << "InURegionEmbedded2() point #"
<< pointno
<< endl;
ListExpr point = nl->First(cyclepoints);
/*
In the following, the segments will be added to the region unit.
In method ~AddSegment()~ some syntax checks will also be done. So far
this syntax check relies on the one of datatype Region, that means that
double values will be used for the check.
This can only be a temporarely solution because the syntax check might fail
in cases where the syntax is actually correct because of the precise
coordinate information.
*/
if (prevPoint != 0
&& !uregion->AddSegment(segments,
preciseSegments,
preciseCoordinates,
preciseInstants,
cr,
rDir,
faceno,
cycleno,
pointno++,
partnerno++,
intervalLen,
prevPoint,
point)) {
cerr << "uregion's segment checks failed"
<< endl;
delete uregion;
return 0;
}
prevPoint = point;
cyclepoints = nl->Rest(cyclepoints);
// pointno++;
// partnerno++;
}
if (!uregion->AddSegment(segments,
preciseSegments,
preciseCoordinates,
preciseInstants,
cr,
rDir,
faceno,
cycleno,
pointno++,
partnerno++,
intervalLen,
prevPoint,
firstPoint)) {
cerr << "uregion's segment checks failed "
<< "with closing segment"
<< endl;
delete uregion;
return 0;
}
//partnerno++;
rDir.EndBulkLoad(true, true, false, false);
bool direction = rDir.GetCycleDirection();
int h = cr.Size()-(rDir.Size()*2);
int i = initialSegmentsNum;
while (h < cr.Size()) {
HalfSegment hsInsideAbove;
bool insideAbove;
cr.Get(h, hsInsideAbove);
if (MR2_DEBUG)
cerr << "InURegionEmbedded2() i="
<< i
<< " insideAbove="
<< hsInsideAbove.attr.insideAbove
<< endl;
if (direction == hsInsideAbove.attr.insideAbove)
insideAbove = false;
else
insideAbove = true;
if (cycleno > 0) insideAbove = !insideAbove;
uregion->SetSegmentInsideAbove(segments, i, insideAbove);
h += 2;
i++;
}
cycles = nl->Rest(cycles);
cycleno++;
}
faces = nl->Rest(faces);
faceno++;
}
cr.EndBulkLoad();
if (MR2_DEBUG)
for (int i = 0; i < uregion->GetSegmentsNum(); i++) {
MSegmentData2 dms;
uregion->GetSegment(segments, i, dms);
cerr << "InURegionEmbedded2() segment #"
<< i
<< ": "
<< dms.ToString()
<< endl;
}
/*
This is different from ~Region~ handling in ~SpatialAlgebra~. We have
to go through the lists of degenerated segments and count how often
a region is inside above in each list. If there are more inside above
segments than others, we need one inside above segment for the
~TemporalFunction()~ and set all others to ignore. Vice versa if there
are more inside below segments. If there is the same number of inside above
and inside below segments, we can ignore the entire list.
*/
for (int i = 0; i < uregion->GetSegmentsNum(); i++) {
MSegmentData2 auxDms;
uregion->GetSegment(segments, i, auxDms);
MSegmentData2 dms( auxDms );
if (dms.GetDegeneratedInitial() == DGM_UNKNOWN) {
if (dms.GetDegeneratedInitialNext() >= 0) {
MSegmentData2 auxDegenDms;
MSegmentData2 degenDms;
unsigned int numInsideAbove = 0;
unsigned int numNotInsideAbove = 0;
for (int j = i+1;
j != 0;
j = degenDms.GetDegeneratedInitialNext()) {
uregion->GetSegment(segments, j-1, auxDegenDms);
degenDms = auxDegenDms;
if (MR2_DEBUG)
cerr << "InURegionEmbedded2() degen-magic-i "
<< i
<< " "
<< j-1
<< endl;
if (degenDms.GetInsideAbove())
numInsideAbove++;
else
numNotInsideAbove++;
if (j != i+1) {
degenDms.SetDegeneratedInitial(DGM_IGNORE);
uregion->PutSegment(segments, j-1, degenDms);
}
}
if (MR2_DEBUG)
cerr << "InURegionEmbedded2() degen-magic-i result "
<< numInsideAbove
<< " "
<< numNotInsideAbove
<< endl;
if (numInsideAbove == numNotInsideAbove) {
dms.SetDegeneratedInitial(DGM_IGNORE);
} else if (numInsideAbove == numNotInsideAbove+1) {
dms.SetDegeneratedInitial(DGM_INSIDEABOVE);
} else if (numInsideAbove+1 == numNotInsideAbove) {
dms.SetDegeneratedInitial(DGM_NOTINSIDEABOVE);
} else {
cerr << "segment ("
<< dms.GetInitialStartX()
<< ", " << dms.GetInitialStartY()
<< ")-(" << dms.GetInitialEndX()
<< ", " << dms.GetInitialEndY()
<< ") / (" << dms.GetFinalStartX()
<< ", " << dms.GetFinalStartY()
<< ")-(" << dms.GetFinalEndX()
<< ", " << dms.GetFinalEndY()
<< ") incorrectly degenerated "
<< "in initial instant"
<< endl;
delete uregion;
return 0;
}
} else
dms.SetDegeneratedInitial(DGM_NONE);
}
if (dms.GetDegeneratedFinal() == DGM_UNKNOWN) {
if (dms.GetDegeneratedFinalNext() >= 0) {
MSegmentData2 auxDegenDms;
MSegmentData2 degenDms;
unsigned int numInsideAbove = 0;
unsigned int numNotInsideAbove = 0;
for (int j = i+1;
j != 0;
j = degenDms.GetDegeneratedFinalNext()) {
uregion->GetSegment(segments, j-1, auxDegenDms);
degenDms = auxDegenDms;
if (MR2_DEBUG)
cerr << "InURegionEmbedded2() degen-magic-f "
<< i
<< " "
<< j-1
<< endl;
if (degenDms.GetInsideAbove())
numInsideAbove++;
else
numNotInsideAbove++;
if (j != i+1) {
degenDms.SetDegeneratedFinal(DGM_IGNORE);
uregion->PutSegment(segments, j-1, degenDms);
}
}
if (MR2_DEBUG)
cerr << "InURegionEmbedded2() degen-magic-f result "
<< numInsideAbove
<< " "
<< numNotInsideAbove
<< endl;
if (numInsideAbove == numNotInsideAbove) {
dms.SetDegeneratedFinal(DGM_IGNORE);
} else if (numInsideAbove == numNotInsideAbove+1) {
dms.SetDegeneratedFinal(DGM_INSIDEABOVE);
} else if (numInsideAbove+1 == numNotInsideAbove) {
dms.SetDegeneratedFinal(DGM_NOTINSIDEABOVE);
} else {
cerr << "segment ("
<< dms.GetInitialStartX()
<< ", " << dms.GetInitialStartY()
<< ")-(" << dms.GetInitialEndX()
<< ", " << dms.GetInitialEndY()
<< ") / (" << dms.GetFinalStartX()
<< ", " << dms.GetFinalStartY()
<< ")-(" << dms.GetFinalEndX()
<< ", " << dms.GetFinalEndY()
<< ") incorrectly degenerated "
<< "in final instant"
<< endl;
delete uregion;
return 0;
}
} else
dms.SetDegeneratedFinal(DGM_NONE);
}
uregion->PutSegment(segments, i, dms);
}
if (MR2_DEBUG)
for (int i = 0; i < uregion->GetSegmentsNum(); i++) {
MSegmentData2 dms;
uregion->GetSegment(segments, i, dms);
cerr << "InURegionEmbedded2() resulting segment #"
<< i
<< ": "
<< dms.ToString()
<< endl;
}
return uregion;
} //end of function InURegionEmbedded2
/*
1.1.1 Function ~OutURegionEmbedded()~
*/
static ListExpr OutURegionEmbedded2(
const URegionEmb2* ur,
DbArray<MSegmentData2>* segments,
DbArray<PreciseMSegmentData>* preciseSegments,
DbArray<int>* preciseCoordinates,
DbArray<int>* preciseInstants) {
if (MR2_DEBUG)
cerr << "OutURegionEmbedded2() called" << endl;
/*
Conversion to list representation is straightforward. Just loop through
faces, cylces and segments and make sure that it is realised when one of
these changes.
*/
int num = ur->GetSegmentsNum();
ListExpr faces = nl->TheEmptyList();
ListExpr facesLastElem = faces;
ListExpr face = nl->TheEmptyList();
ListExpr faceLastElem = face;
ListExpr cycle = nl->TheEmptyList();
ListExpr cycleLastElem = cycle;
//cycle over all the segments the unit contains of...
for (int i = 0; i < num; i++) {
if (MR2_DEBUG)
cerr << "OutURegionEmbedded2() segment #" << i << endl;
//Get segment in integer-grid
MSegmentData2 dms;
ur->GetSegment(segments, i, dms);
if (MR2_DEBUG)
cerr << "OutURegionEmbedded2() returned, dms="
<< &dms << endl;
if (MR2_DEBUG)
cerr << "OutURegionEmbedded2() point is "
<< dms.GetFaceNo()
<< " "
<< dms.GetCycleNo()
<< " ("
<< dms.GetInitialStartX()
<< ", "
<< dms.GetInitialStartY()
<< ", "
<< dms.GetFinalStartX()
<< ", "
<< dms.GetFinalStartY()
<< ")"
<< endl;
/*
We check if the segment has precise coordinate information, and - if so -
we get this information and also construct a list representation for it.
*/
ListExpr preciseList;
if (!dms.GetIsBasicSegment())
{
PreciseMSegmentData pdms;
ur->GetPreciseSegment(preciseSegments, i, pdms);
const mpq_class preciseInitialStartX =
pdms.GetInitialStartX(preciseCoordinates);
const mpq_class preciseInitialStartY =
pdms.GetInitialStartY(preciseCoordinates);
const mpq_class preciseFinalStartX =
pdms.GetFinalStartX(preciseCoordinates);
const mpq_class preciseFinalStartY =
pdms.GetFinalStartY(preciseCoordinates);
ListExpr l1;
ListExpr l2;
ListExpr l3;
ListExpr l4;
gmpTypeToTextType(preciseInitialStartX, l1);
gmpTypeToTextType(preciseInitialStartY, l2);
gmpTypeToTextType(preciseFinalStartX, l3);
gmpTypeToTextType(preciseFinalStartY, l4);
preciseList = nl->FourElemList(l1, l2, l3, l4);
}
else {
preciseList = nl->TheEmptyList();
}
ListExpr p = nl->FiveElemList(
nl->IntAtom(dms.GetInitialStartX()),
nl->IntAtom(dms.GetInitialStartY()),
nl->IntAtom(dms.GetFinalStartX()),
nl->IntAtom(dms.GetFinalStartY()),
preciseList);
if (cycle == nl->TheEmptyList()) {
if (MR2_DEBUG)
cerr << "OutURegionEmbedded2() new cycle"
<< endl;
cycle = nl->OneElemList(p);
cycleLastElem = cycle;
} else {
if (MR2_DEBUG)
cerr << "OutURegionEmbedded2() existing cycle"
<< endl;
cycleLastElem = nl->Append(cycleLastElem, p);
}
MSegmentData2 nextDms;
if (i < num-1) {
ur->GetSegment(segments, i+1, nextDms);
}
if (i == num-1
|| dms.GetCycleNo() != nextDms.GetCycleNo()
|| dms.GetFaceNo() != nextDms.GetFaceNo()) {
if (MR2_DEBUG)
cerr << "OutURegionEmbedded2() end of cycle" << endl;
if (face == nl->TheEmptyList()) {
if (MR2_DEBUG)
cerr << "OutURegionEmbedded2() new face" << endl;
face = nl->OneElemList(cycle);
faceLastElem = face;
} else {
if (MR2_DEBUG)
cerr << "OutURegionEmbedded2() existing face"
<< endl;
faceLastElem = nl->Append(faceLastElem, cycle);
}
if (i == num-1
|| dms.GetFaceNo() != nextDms.GetFaceNo()) {
if (MR2_DEBUG)
cerr << "OutURegionEmbedded2() end of face"
<< endl;
if (faces == nl->TheEmptyList()) {
faces = nl->OneElemList(face);
facesLastElem = faces;
} else
facesLastElem = nl->Append(facesLastElem, face);
face = nl->TheEmptyList();
faceLastElem = face;
}
cycle = nl->TheEmptyList();
cycleLastElem = cycle;
}
}
PreciseInterval pInt = ur->pInterval;
ListExpr preciseTimeInterval;
if (MR2_DEBUG) cerr << "Processing precise time interval..." << endl;
if (pInt.GetPreciseInitialInstant(preciseInstants) != 0 ||
pInt.GetPreciseFinalInstant(preciseInstants) != 0)
{
ListExpr pStart;
ListExpr pEnd;
gmpTypeToTextType(
pInt.GetPreciseInitialInstant(preciseInstants),
pStart);
gmpTypeToTextType(
pInt.GetPreciseFinalInstant(preciseInstants),
pEnd);
preciseTimeInterval = nl->TwoElemList(
pStart,
pEnd);
}
else
preciseTimeInterval = nl->TheEmptyList();
ListExpr res =
nl->TwoElemList(
nl->FiveElemList(
OutDateTime(nl->TheEmptyList(),
SetWord((void*) &ur->timeInterval.start)),
OutDateTime(nl->TheEmptyList(),
SetWord((void*) &ur->timeInterval.end)),
nl->BoolAtom(ur->timeInterval.lc),
nl->BoolAtom(ur->timeInterval.rc),
preciseTimeInterval),
faces);
return res;
}
/*
1.1.1 Method ~AddSegment()~
This method is only called from InURegionEmbedded2. It returns ~true~
if the new segment can be added successfully to the region unit.
Therefor currently this method relies on the syntax check made by the
method EndBulkLoad from data type Region from SpatialAlgebra. this is
a workaround until MRegion2 and URegion2 have its own method
implementation for EndBulkLoad, or until a new data type for Region
with precise coordinates is supported.
*/
bool URegionEmb2::AddSegment(
DbArray<MSegmentData2>* segments,
DbArray<PreciseMSegmentData>* preciseSegments,
DbArray<int>* preciseCoordinates,
DbArray<int>* preciseInstants,
Region& cr,
Region& rDir,
unsigned int faceno,
unsigned int cycleno,
unsigned int segmentno,
unsigned int partnerno,
DateTime& intervalLen,
ListExpr start,
ListExpr end) {
if (MR2_DEBUG)
cerr << "URegionEmb2::AddSegment() called "
<< faceno
<< " "
<< cycleno
<< " "
<< segmentno
<< endl;
/*
To avoid awkward return value handling, we throw an exception if we find
a mistake. This is caught and converted into a proper error message and
return value.
*/
try {
/*
Check list representation.
*/
if (nl->ListLength(start) != 5
|| !nl->IsAtom(nl->First(start))
|| !nl->IsAtom(nl->Second(start))
|| !nl->IsAtom(nl->Third(start))
|| !nl->IsAtom(nl->Fourth(start))
|| nl->AtomType(nl->First(start)) != IntType
|| nl->AtomType(nl->Second(start)) != IntType
|| nl->AtomType(nl->Third(start)) != IntType
|| nl->AtomType(nl->Fourth(start)) != IntType)
{
throw invalid_argument(
" Start point "
+ nl->ToString(start)
+ " not in format "
+ "(<number> <number> <number> <number> <ListExpr>)");
}
if (nl->ListLength(start) != 5
|| !nl->IsAtom(nl->First(end))
|| !nl->IsAtom(nl->Second(end))
|| !nl->IsAtom(nl->Third(end))
|| !nl->IsAtom(nl->Fourth(end))
|| nl->AtomType(nl->First(end)) != IntType
|| nl->AtomType(nl->Second(end)) != IntType
|| nl->AtomType(nl->Third(end)) != IntType
|| nl->AtomType(nl->Fourth(end)) != IntType)
{
throw invalid_argument(
" End point "
+nl->ToString(end)
+" not in format "
+ "(<number> <number> <number> <number> <ListExpr>)");
}
/*
Create segment from list representation.
If we have precise information for this segment, basic and precise
segments must be created, otherwise only basic segment.
*/
MSegmentData2* pointDms=0;
PreciseMSegmentData pdms(-1);
if (nl->ListLength(nl->Fifth(start)) >= 1
|| nl->ListLength(nl->Fifth(end)) >= 1)
{
if (MR2_DEBUG)
cerr << "URegionEmb2::AddSegment(): "
<< "There is precise coordinate information!"
<< endl;
mpq_class piStartX(0);
mpq_class piStartY(0);
mpq_class piEndX(0);
mpq_class piEndY(0);
mpq_class pfStartX(0);
mpq_class pfStartY(0);
mpq_class pfEndX(0);
mpq_class pfEndY(0);
if (nl->ListLength(nl->Fifth(start)) >= 1)
{
//Check syntax
if (nl->ListLength(nl->Fifth(start)) == 4
&& nl->IsAtom(
nl->First(nl->Fifth(start)))
&& nl->AtomType(nl->First(
nl->Fifth(start))) == TextType
&& nl->IsAtom(nl->Second(
nl->Fifth(start)))
&& nl->AtomType(nl->Second(
nl->Fifth(start))) == TextType
&& nl->IsAtom(nl->Third(
nl->Fifth(start)))
&& nl->AtomType(nl->Third(
nl->Fifth(start))) == TextType
&& nl->IsAtom(nl->Fourth(
nl->Fifth(start)))
&& nl->AtomType(nl->Fourth(
nl->Fifth(start))) == TextType)
{
textTypeToGmpType(nl->First(
nl->Fifth(start)), piStartX);
textTypeToGmpType(nl->Second(
nl->Fifth(start)), piStartY);
textTypeToGmpType(nl->Third(
nl->Fifth(start)), pfStartX);
textTypeToGmpType(nl->Fourth(
nl->Fifth(start)), pfStartY);
}
}
if (nl->ListLength(nl->Fifth(end)) >= 1)
{
//Check syntax
if (nl->ListLength(nl->Fifth(start)) == 4
&& nl->IsAtom(nl->First(
nl->Fifth(end)))
&& nl->AtomType(nl->First(
nl->Fifth(end))) == TextType
&& nl->IsAtom(nl->Second(
nl->Fifth(end)))
&& nl->AtomType(nl->Second(
nl->Fifth(end))) == TextType
&& nl->IsAtom(nl->Third(
nl->Fifth(end)))
&& nl->AtomType(nl->Third(
nl->Fifth(end))) == TextType
&& nl->IsAtom(nl->Fourth(
nl->Fifth(end)))
&& nl->AtomType(nl->Fourth(
nl->Fifth(end))) == TextType)
{
textTypeToGmpType(nl->First(
nl->Fifth(end)), piEndX);
textTypeToGmpType(nl->Second(
nl->Fifth(end)), piEndY);
textTypeToGmpType(nl->Third(
nl->Fifth(end)), pfEndX);
textTypeToGmpType(nl->Fourth(
nl->Fifth(end)), pfEndY);
}
}
pdms.SetInitialStartX(piStartX, preciseCoordinates);
pdms.SetInitialStartY(piStartY, preciseCoordinates);
pdms.SetInitialEndX(piEndX, preciseCoordinates);
pdms.SetInitialEndY(piEndY, preciseCoordinates);
pdms.SetFinalStartX(pfStartX, preciseCoordinates);
pdms.SetFinalStartY(pfStartY, preciseCoordinates);
pdms.SetFinalEndX(pfEndX, preciseCoordinates);
pdms.SetFinalEndY(pfEndY, preciseCoordinates);
pointDms = new MSegmentData2(faceno,
cycleno,
segmentno,
false,
nl->IntValue(nl->First(start)),
nl->IntValue(nl->Second(start)),
nl->IntValue(nl->First(end)),
nl->IntValue(nl->Second(end)),
nl->IntValue(nl->Third(start)),
nl->IntValue(nl->Fourth(start)),
nl->IntValue(nl->Third(end)),
nl->IntValue(nl->Fourth(end)),
pdms,
preciseCoordinates);
}
else
{
if (MR2_DEBUG)
cerr << "URegionEmb2::AddSegment(): "
<< "No precise coordinate information, "
<< "basic segment." << endl;
mpq_class dummyValue(0);
pdms.SetAll(dummyValue, preciseCoordinates);
pointDms = new MSegmentData2(faceno,
cycleno,
segmentno,
false,
nl->IntValue(nl->First(start)),
nl->IntValue(nl->Second(start)),
nl->IntValue(nl->First(end)),
nl->IntValue(nl->Second(end)),
nl->IntValue(nl->Third(start)),
nl->IntValue(nl->Fourth(start)),
nl->IntValue(nl->Third(end)),
nl->IntValue(nl->Fourth(end)));
} //if-else-check for precise-information...
if (MR2_DEBUG)
cerr << "URegionEmb2::AddSegment() segmentsNum="
<< segmentsNum
<< endl;
MSegmentData2 dms(*pointDms);
delete pointDms;
/*
For each of the already existing segments:
*/
for (int i = segmentsNum-1; i >= 0; i--) {
if (MR2_DEBUG)
cerr << "URegionEmb2::AddSegment() i="
<< i << endl;
MSegmentData2 auxExistingDms;
PreciseMSegmentData auxExistingPdms;
segments->Get(segmentsStartPos+i, auxExistingDms);
MSegmentData2 existingDms( auxExistingDms );
preciseSegments->Get(
segmentsStartPos+i, auxExistingPdms);
PreciseMSegmentData existingPdms( auxExistingPdms );
/*
Check whether the current segment degenerates with this segment in the
initial instant. Note that segments reduced to points are excluded from
this.
All segments, which degenerate into each other, are collected in a list
using the ~degeneratedInitialNext~ attribute.
*/
bool degenerationFound = false;
if (dms.GetDegeneratedInitialNext() < 0
&& !dms.GetPointInitial()
&& !existingDms.GetPointInitial())
{
if (dms.GetIsBasicSegment()
&& existingDms.GetIsBasicSegment())
{
if (((dms.GetInitialStartX() ==
existingDms.GetInitialStartX()
&& dms.GetInitialStartY() ==
existingDms.GetInitialStartY()
&& dms.GetInitialEndX() ==
existingDms.GetInitialEndX()
&& dms.GetInitialEndY() ==
existingDms.GetInitialEndY())
|| (dms.GetInitialStartX() ==
existingDms.GetInitialEndX()
&& dms.GetInitialStartY() ==
existingDms.GetInitialEndY()
&& dms.GetInitialEndX() ==
existingDms.GetInitialStartX()
&& dms.GetInitialEndY() ==
existingDms.GetInitialStartY())))
{
if (MR2_DEBUG)
cerr << "Both segments are basic, "
<< "and they degenerate in "
<< "initial instant!"
<< endl;
degenerationFound = true;
}
}
else if ((maybeEqual(
dms.GetInitialStartX(),
existingDms.GetInitialStartX(), 1, 1)
&& maybeEqual(dms.GetInitialStartY(),
existingDms.GetInitialStartY(), 1, 1)
&& maybeEqual(dms.GetInitialEndX(),
existingDms.GetInitialEndX(), 1, 1)
&& maybeEqual(dms.GetInitialEndY(),
existingDms.GetInitialEndY(), 1, 1))
|| (maybeEqual(dms.GetInitialStartX(),
existingDms.GetInitialEndX(), 1, 1)
&& maybeEqual(dms.GetInitialStartY(),
existingDms.GetInitialEndY(), 1, 1)
&& maybeEqual(
dms.GetInitialEndX(),
existingDms.GetInitialStartX(), 1, 1)
&& maybeEqual(
dms.GetInitialEndY(),
existingDms.GetInitialStartY(), 1, 1)))
{
if (MR2_DEBUG)
cerr << "At least one segment not"
<< " basic, precise check for"
<< " degeneration..." << endl;
//Check if degenerated with precise coordinate information...
if ((cmp(pdms.GetInitialStartX
(preciseCoordinates) +
dms.GetInitialStartX(),
existingPdms.GetInitialStartX
(preciseCoordinates) +
existingDms.GetInitialStartX()) == 0
&& cmp(pdms.GetInitialStartY
(preciseCoordinates) +
dms.GetInitialStartY(),
existingPdms.GetInitialStartY
(preciseCoordinates) +
existingDms.GetInitialStartY()) == 0
&& cmp(pdms.GetInitialEndX
(preciseCoordinates) +
dms.GetInitialEndX(),
existingPdms.GetInitialEndX
(preciseCoordinates) +
existingDms.GetInitialEndX()) == 0
&& cmp(pdms.GetInitialEndY
(preciseCoordinates) +
dms.GetInitialEndY(),
existingPdms.GetInitialEndY
(preciseCoordinates) +
existingDms.GetInitialEndY()) == 0)
|| (cmp(pdms.GetInitialStartX
(preciseCoordinates) +
dms.GetInitialStartX(),
existingPdms.GetInitialEndX
(preciseCoordinates) +
existingDms.GetInitialEndX()) == 0
&& cmp(pdms.GetInitialStartY
(preciseCoordinates) +
dms.GetInitialStartY(),
existingPdms.GetInitialEndY
(preciseCoordinates) +
existingDms.GetInitialEndY()) == 0
&& cmp(pdms.GetInitialEndX
(preciseCoordinates) +
dms.GetInitialEndX(),
existingPdms.GetInitialStartX
(preciseCoordinates) +
existingDms.GetInitialStartX()) == 0
&& cmp(pdms.GetInitialEndY
(preciseCoordinates) +
dms.GetInitialEndY(),
existingPdms.GetInitialStartY
(preciseCoordinates) +
existingDms.GetInitialStartY()) == 0))
{
if (MR2_DEBUG)
cerr << "URegionEmb2::Addsegment():"
<< " DegenerationFound in"
<< " preciseCheck!" << endl;
degenerationFound = true;
}
}
}
if (degenerationFound)
{
if (MR2_DEBUG)
cerr << "URegionEmb2::AddSegment() "
<< "degenerated initial in " << i
<< endl;
dms.SetDegeneratedInitialNext(0);
existingDms.SetDegeneratedInitialNext
(segmentsNum+1);
segments->Put(segmentsStartPos+i, existingDms);
}
/*
Same for the final instant.
*/
degenerationFound = false;
if (dms.GetDegeneratedFinalNext() < 0
&& !dms.GetPointFinal()
&& !existingDms.GetPointFinal())
{
if (dms.GetIsBasicSegment() &&
existingDms.GetIsBasicSegment())
{
if (((dms.GetFinalStartX() ==
existingDms.GetFinalStartX()
&& dms.GetFinalStartY() ==
existingDms.GetFinalStartY()
&& dms.GetFinalEndX() ==
existingDms.GetFinalEndX()
&& dms.GetFinalEndY() ==
existingDms.GetFinalEndY())
|| (dms.GetFinalStartX() ==
existingDms.GetFinalEndX()
&& dms.GetFinalStartY() ==
existingDms.GetFinalEndY()
&& dms.GetFinalEndX() ==
existingDms.GetFinalStartX()
&& dms.GetFinalEndY() ==
existingDms.GetFinalStartY())))
{
if (MR2_DEBUG)
cerr << "Both segments are basic"
<< " and degenerate in final"
<< " instant" << endl;
degenerationFound = true;
}
}
else if ((maybeEqual(
dms.GetFinalStartX(),
existingDms.GetFinalStartX(), 1, 1)
&& maybeEqual(
dms.GetFinalStartY(),
existingDms.GetFinalStartY(), 1, 1)
&& maybeEqual(
dms.GetFinalEndX(),
existingDms.GetFinalEndX(), 1, 1)
&& maybeEqual(
dms.GetFinalEndY(),
existingDms.GetFinalEndY(), 1, 1))
|| (maybeEqual(
dms.GetFinalStartX(),
existingDms.GetFinalEndX(), 1, 1)
&& maybeEqual(
dms.GetFinalStartY(),
existingDms.GetFinalEndY(), 1, 1)
&& maybeEqual(
dms.GetFinalEndX(),
existingDms.GetFinalStartX(), 1, 1)
&& maybeEqual(
dms.GetFinalEndY(),
existingDms.GetFinalStartY(),
1, 1)))
{
if (MR2_DEBUG)
cerr << "At least one segment is not"
<< " basic, precise check for "
<< "degeneration..." << endl;
//Check if degenerated with precise coordinate information...
if ((cmp(pdms.GetFinalStartX
(preciseCoordinates) +
dms.GetFinalStartX(),
existingPdms.GetFinalStartX
(preciseCoordinates) +
existingDms.GetFinalStartX()) == 0
&& cmp(pdms.GetFinalStartY
(preciseCoordinates) +
dms.GetFinalStartY(),
existingPdms.GetFinalStartY
(preciseCoordinates) +
existingDms.GetFinalStartY()) == 0
&& cmp(pdms.GetFinalEndX
(preciseCoordinates) +
dms.GetFinalEndX(),
existingPdms.GetFinalEndX
(preciseCoordinates) +
existingDms.GetFinalEndX()) == 0
&& cmp(pdms.GetFinalEndY
(preciseCoordinates) +
dms.GetFinalEndY(),
existingPdms.GetFinalEndY
(preciseCoordinates) +
existingDms.GetFinalEndY()) == 0)
|| (cmp(pdms.GetFinalStartX
(preciseCoordinates) +
dms.GetFinalStartX(),
existingPdms.GetFinalEndX
(preciseCoordinates) +
existingDms.GetFinalEndX()) == 0
&& cmp(pdms.GetFinalStartY
(preciseCoordinates) +
dms.GetFinalStartY(),
existingPdms.GetFinalEndY
(preciseCoordinates) +
existingDms.GetFinalEndY()) == 0
&& cmp(pdms.GetFinalEndX
(preciseCoordinates) +
dms.GetFinalEndX(),
existingPdms.GetFinalStartX
(preciseCoordinates) +
existingDms.GetFinalStartX()) == 0
&& cmp(pdms.GetFinalEndY
(preciseCoordinates) +
dms.GetFinalEndY(),
existingPdms.GetFinalStartY
(preciseCoordinates) +
existingDms.GetFinalStartY()) == 0))
{
if (MR2_DEBUG)
cerr << "URegionEmb2::AddSegment():"
<< " Degeneration found in "
<< "precise check!" << endl;
degenerationFound = true;
}
}
}
if (degenerationFound)
{
if (MR2_DEBUG)
cerr << "URegionEmb2::AddSegment() "
<< "degenerated final in " << i
<< endl;
dms.SetDegeneratedFinalNext(0);
existingDms.SetDegeneratedFinalNext
(segmentsNum+1);
segments->Put(segmentsStartPos+i,
existingDms);
}
/*
If we have a point time interval, degeneration is not allowed.
*/
if (intervalLen.IsZero() &&
cmp(pInterval.GetPreciseInitialInstant
(preciseInstants),
pInterval.GetPreciseFinalInstant
(preciseInstants)) == 0
&& (dms.GetDegeneratedInitialNext() >= 0
|| dms.GetDegeneratedFinalNext() >= 0)) {
stringstream msg;
msg << " Units with zero length time"
<< " interval must not"
<< " be degenerated." << endl
<< " New segment:" << endl
<< " Initial: ("
<< dms.GetInitialStartX()
<< " "
<< dms.GetInitialStartY()
<< ") - ("
<< dms.GetInitialEndX()
<< " "
<< dms.GetInitialEndY()
<< ")" << endl
<< " Final: ("
<< dms.GetFinalStartX()
<< " "
<< dms.GetFinalStartY()
<< ") - ("
<< dms.GetFinalEndX()
<< " "
<< dms.GetFinalEndY();
throw invalid_argument(msg.str());
} else if ((!intervalLen.IsZero()
|| cmp(pInterval.GetPreciseInitialInstant
(preciseInstants),
pInterval.GetPreciseFinalInstant
(preciseInstants)) != 0)
&& dms.GetDegeneratedInitialNext()
>= 0
&& dms.GetDegeneratedFinalNext()
>= 0) {
stringstream msg;
msg << "URegionEmb2::AddSegment() "
<< "degeneration check failed!"
<< " Units must not degenerate both "
<< "in initial and"
<< " final instant." << endl
<< " New segment:" << endl
<< " Initial: ("
<< dms.GetInitialStartX()
<< " "
<< dms.GetInitialStartY()
<< ") - ("
<< dms.GetInitialEndX()
<< " "
<< dms.GetInitialEndY()
<< ")" << endl
<< " Final: ("
<< dms.GetFinalStartX()
<< " "
<< dms.GetFinalStartY()
<< ") - ("
<< dms.GetFinalEndX()
<< " "
<< dms.GetFinalEndY()
<< ")" << endl;
throw invalid_argument(msg.str());
}
/*
Check if the current segment intersects with the existing segment.
Since both are moving segments and are spanning a trapezium in 3d space
$(x, y, t)$, this is equivalent to the intersection of two trapeziums.
*/
GridPoint point1(dms.GetInitialStartX(),
dms.GetInitialStartY(),
dms.GetIsBasicSegment());
GridPoint point2(dms.GetInitialEndX(),
dms.GetInitialEndY(),
dms.GetIsBasicSegment());
GridPoint point3(dms.GetFinalStartX(),
dms.GetFinalStartY(),
dms.GetIsBasicSegment());
GridPoint point4(dms.GetFinalEndX(),
dms.GetFinalEndY(),
dms.GetIsBasicSegment());
GridPointSegment segment1(point1, point2);
GridPointSegment segment2(point3, point4);
GridPoint point5(existingDms.GetInitialStartX(),
existingDms.GetInitialStartY(),
existingDms.GetIsBasicSegment());
GridPoint point6(existingDms.GetInitialEndX(),
existingDms.GetInitialEndY(),
existingDms.GetIsBasicSegment());
GridPoint point7(existingDms.GetFinalStartX(),
existingDms.GetFinalStartY(),
existingDms.GetIsBasicSegment());
GridPoint point8(existingDms.GetFinalEndX(),
existingDms.GetFinalEndY(),
existingDms.GetIsBasicSegment());
GridPointSegment segment3(point5, point6);
GridPointSegment segment4(point7, point8);
GridPointTrapezium trapezium1(segment1, segment2);
GridPointTrapezium trapezium2(segment3, segment4);
if (trapeziumsMayIntersect(broughtDown
(intervalLen.ToDouble()), trapezium1,
trapezium2))
{
bool trapeziumsIntersect;
if (existingDms.GetIsBasicSegment()
&& dms.GetIsBasicSegment())
{
//precise coordinates are all zero, trivially true
trapeziumsIntersect = true;
}
else {
/*
We create the precise trapeziums and recheck if they really intersect. Therefor we need to add coordinates of precise and integer representation to get the absolute values.
*/
PrecisePoint ppoint1
(pdms.GetInitialStartX
(preciseCoordinates)+
dms.GetInitialStartX(),
pdms.GetInitialStartY
(preciseCoordinates)+
dms.GetInitialStartY());
PrecisePoint ppoint2(pdms.GetInitialEndX
(preciseCoordinates)
+dms.GetInitialEndX(),
pdms.GetInitialEndY
(preciseCoordinates)
+dms.GetInitialEndY());
PrecisePoint ppoint3(pdms.GetFinalStartX
(preciseCoordinates)
+dms.GetFinalStartX(),
pdms.GetFinalStartY
(preciseCoordinates)
+dms.GetFinalStartY());
PrecisePoint ppoint4(pdms.GetFinalEndX
(preciseCoordinates)
+dms.GetFinalEndX(),
pdms.GetFinalEndY
(preciseCoordinates)
+dms.GetFinalEndY());
PreciseSegment psegment1(ppoint1,
ppoint2);
PreciseSegment psegment2(ppoint3,
ppoint4);
PreciseTrapezium ptrapezium1(psegment1,
psegment2);
PrecisePoint ppoint5
(existingPdms.GetInitialStartX
(preciseCoordinates)+
existingDms.GetInitialStartX(),
existingPdms.GetInitialStartY
(preciseCoordinates)+
existingDms.GetInitialStartY());
PrecisePoint ppoint6
(existingPdms.GetInitialEndX
(preciseCoordinates)+
existingDms.GetInitialEndX(),
existingPdms.GetInitialEndY
(preciseCoordinates)+
existingDms.GetInitialEndY());
PrecisePoint ppoint7
(existingPdms.GetFinalStartX
(preciseCoordinates)+
existingDms.GetFinalStartX(),
existingPdms.GetFinalStartY
(preciseCoordinates)+
existingDms.GetFinalStartY());
PrecisePoint ppoint8(existingPdms.
GetFinalEndX(preciseCoordinates)+
existingDms.GetFinalEndX(),
existingPdms.GetFinalEndY
(preciseCoordinates)+
existingDms.GetFinalEndY());
PreciseSegment psegment3(ppoint5,
ppoint6);
PreciseSegment psegment4(ppoint7,
ppoint8);
PreciseTrapezium ptrapezium2(
psegment3, psegment4);
mpq_class pdt(pInterval.
GetPreciseFinalInstant
(preciseInstants) -
pInterval.GetPreciseInitialInstant
(preciseInstants) +
intervalLen.ToDouble());
trapeziumsIntersect =
preciseTrapeziumsIntersect(pdt,
ptrapezium1, ptrapezium2);
}
if (trapeziumsIntersect)
{
stringstream msg;
msg << " Moving segments intersect "
<< endl
<< " Existing segment:" << endl
<< " Initial: ("
<< existingDms.GetInitialStartX()
<< " "
<< existingDms.GetInitialStartY()
<< ") - ("
<< existingDms.GetInitialEndX()
<< " "
<< existingDms.GetInitialEndY()
<< ")" << endl
<< " Final: ("
<< existingDms.GetFinalStartX()
<< " "
<< existingDms.GetFinalStartY()
<< ") - ("
<< existingDms.GetFinalEndX()
<< " "
<< existingDms.GetFinalEndY()
<< ")" << endl
<< " New segment:" << endl
<< " Initial: ("
<< dms.GetInitialStartX()
<< " "
<< dms.GetInitialStartY()
<< ") - ("
<< dms.GetInitialEndX()
<< " "
<< dms.GetInitialEndY()
<< ")" << endl
<< " Final: ("
<< dms.GetFinalStartX()
<< " "
<< dms.GetFinalStartY()
<< ") - ("
<< dms.GetFinalEndX()
<< " "
<< dms.GetFinalEndY();
throw invalid_argument(msg.str());
} //if precise trapeziums intersect
} //if trapeziums may intersect
} //for: for each of the already existing segments...
/*
Add half segments to $cr$ and $rDir$ for region check and direction
computation.
Note that the syntax check done in Region may fail although we have a
syntactically correct moving region value, because syntactical correctness
may depend on precise coordinates which are not passed to region!
This can only be a provisional solution, but not the final one!
*/
double t = intervalLen.IsZero() ? 0 : 0.5;
double xs =
dms.GetInitialStartX()
+(dms.GetFinalStartX()-dms.GetInitialStartX())*t;
double ys =
dms.GetInitialStartY()
+(dms.GetFinalStartY()-dms.GetInitialStartY())*t;
double xe =
dms.GetInitialEndX()
+(dms.GetFinalEndX()-dms.GetInitialEndX())*t;
double ye =
dms.GetInitialEndY()
+(dms.GetFinalEndY()-dms.GetInitialEndY())*t;
Point s(true, xs, ys);
Point e(true, xe, ye);
/*
Here we need an extra check, because HalfSegment creation will lead to a failed
assertion if start and end point are equal or almost equal.
This might happen on the integer grid, although the precise coordinates of both
points are different!
*/
if (AlmostEqual(s, e))
{
cerr << endl
<< "--------------------------------------------------"
<< endl
<< "URegionEmb2::AddSegment() returns false, "
<< "failure reason is:"
<< endl
<< "Halfsegment creation not possible with start "
<< "and end point almost equal."
<< endl
<< "Start point: (" << xs << ", " << ys << ")"
<< endl
<< "End point: (" << xe << ", " << ye << ")"
<< endl
<< "Try input with larger coordinates "
<< "and scale afterwards with scale operator!"
<< endl
<< "--------------------------------------------------"
<< endl;
return false;
}
HalfSegment hs(true, s, e);
hs.attr.faceno = faceno;
hs.attr.cycleno = cycleno;
hs.attr.partnerno = partnerno;
hs.attr.edgeno = segmentno;
hs.attr.insideAbove = hs.GetLeftPoint() == s;
if (MR2_DEBUG)
cerr << "URegionEmb2::AddSegment() "
<< dms.ToString()
<< endl;
if (MR2_DEBUG)
cerr << "URegionEmb2::AddSegment() "
<< faceno
<< " "
<< cycleno
<< " "
<< partnerno
<< " ("
<< xs
<< ", "
<< ys
<< ")-("
<< xe
<< ", "
<< ye
<< ") ia="
<< hs.attr.insideAbove
<< endl;
if (!cr.InsertOk(hs)) {
stringstream msg;
msg << " Region checks for segment failed." << endl
<< " New segment:" << endl
<< " Initial: ("
<< dms.GetInitialStartX()
<< " "
<< dms.GetInitialStartY()
<< ") - ("
<< dms.GetInitialEndX()
<< " "
<< dms.GetInitialEndY()
<< ")" << endl
<< " Final: ("
<< dms.GetFinalStartX()
<< " "
<< dms.GetFinalStartY()
<< ") - ("
<< dms.GetFinalEndX()
<< " "
<< dms.GetFinalEndY();
throw invalid_argument(msg.str());
}
cr += hs;
if( hs.IsLeftDomPoint() )
{
rDir += hs;
hs.SetLeftDomPoint( false );
}
else
{
hs.SetLeftDomPoint( true );
rDir += hs;
}
cr += hs;
segments->resize(segmentsStartPos+segmentsNum+1);
segments->Put(segmentsStartPos+segmentsNum, dms);
//The same for the precise segment!
preciseSegments->resize(segmentsStartPos+segmentsNum+1);
preciseSegments->Put(segmentsStartPos+segmentsNum, pdms);
segmentsNum++;
/*
The bbox is calculated on the integer grid. We use the down left corner
of the respective grid cell for the minimum values and the upper right
corner of the grid cell for the max values.
As the coordinate's representation on the grid already use the down left
corners, just for the maximum values we need to adapt them...
*/
if (bbox.IsDefined()) {
double min[3] = { bbox.MinD(0), bbox.MinD(1),
bbox.MinD(2) };
double max[3] = { bbox.MaxD(0), bbox.MaxD(1),
bbox.MaxD(2) };
if (dms.GetInitialStartX() < min[0])
min[0] = dms.GetInitialStartX();
if (dms.GetFinalStartX() < min[0])
min[0] = dms.GetFinalStartX();
if (dms.GetInitialStartY() < min[1])
min[1] = dms.GetInitialStartY();
if (dms.GetFinalStartY() < min[1])
min[1] = dms.GetFinalStartY();
if ((dms.GetInitialStartX()+1) > max[0])
max[0] = dms.GetInitialStartX()+1;
if ((dms.GetFinalStartX()+1) > max[0])
max[0] = dms.GetFinalStartX()+1;
if ((dms.GetInitialStartY()+1) > max[1])
max[1] = dms.GetInitialStartY()+1;
if ((dms.GetFinalStartY()+1) > max[1])
max[1] = dms.GetFinalStartY()+1;
bbox.Set(true, min, max);
} else {
double min[3] =
{ dms.GetInitialStartX() < dms.GetFinalStartX() ?
dms.GetInitialStartX() : dms.GetFinalStartX(),
dms.GetInitialStartY() < dms.GetFinalStartY() ?
dms.GetInitialStartY() : dms.GetFinalStartY(),
timeInterval.start.ToDouble() };
double max[3] =
{ dms.GetInitialStartX() > dms.GetFinalStartX() ?
dms.GetInitialStartX()+1 : dms.GetFinalStartX()+1,
dms.GetInitialStartY() > dms.GetFinalStartY() ?
dms.GetInitialStartY()+1 : dms.GetFinalStartY()+1,
timeInterval.end.ToDouble() };
bbox.Set(true, min, max);
} //if-else...
} //try
catch (invalid_argument& e) {
cerr << endl
<< "-----------------------------------------------------------"
<< endl
<< "Checking segment failed."
<< endl
<< e.what()
<< endl
<< "-----------------------------------------------------------"
<< endl;
return false;
}
return true;
}
/*
1 Data type ~uregion2~
1.1 Class ~URegion2~
1.1.1 Class definition
The class definition has been moved to ~MovingRegion2Algebra.h~.
1.1.1 Constructors
*/
URegion2::URegion2(unsigned int n) :
SpatialTemporalUnit<Region, 3>(true),
segments(n),
preciseSegments(n),
preciseCoordinates(0),
preciseInstants(0) {
SetDefined(true);
if (MR2_DEBUG)
cerr << "URegion2::URegion2() #1 called"
<< endl;
}
/*
This constructor creates a URegion2 object from an existing URegion object, by splitting the double
coordinates into an integer part and the remaining rest, which will be stored as mpq\_class values in
PreciseMSegmentData instances...
In a first step, the double coordinates are multiplied with scaleFactor to get the integer grid values.
*/
URegion2::URegion2(URegion& coarseRegion, const int scaleFactor) :
segments(coarseRegion.GetMSegmentData()->Size()),
preciseSegments(coarseRegion.GetMSegmentData()->Size()),
preciseCoordinates(0),
preciseInstants(0) {
if (MR2_DEBUG)
cerr << "URegion2::URegion2(coarseRegion, scaleFactor) called"
<< endl
<< "ScaleFactor: " << scaleFactor << " " << endl
<< "Number of segments: "
<< coarseRegion.GetMSegmentData()->Size() << " " << endl;
this->scaleFactor = scaleFactor;
//Transform the time interval to integer grid coordinates -
//preciseInterval is calculated in URegionEmb2-Constructor
double initial = (double)broughtDown
(coarseRegion.timeInterval.start.ToDouble());
double final = (double)broughtDown
(coarseRegion.timeInterval.end.ToDouble());
Instant initInst(initial);
Instant finInst(final);
Interval<Instant> interval(initInst, finInst,
coarseRegion.timeInterval.lc, coarseRegion.timeInterval.rc);
//initialize precise time interval
PreciseInterval pInt(-1);
URegionEmb origUremb = coarseRegion.GetEmbedded();
origUremb.SetSegmentsNum(coarseRegion.GetMSegmentData()->Size());
origUremb.timeInterval = coarseRegion.timeInterval; // O.Feuer
URegionEmb2 uremb(&segments, &preciseSegments, &preciseCoordinates,
&preciseInstants,
interval, pInt, origUremb, // O.Feuer
coarseRegion.GetMSegmentData(), 0, scaleFactor);
SetEmbedded(&uremb);
timeInterval = uremb.timeInterval;
}
/*
1.1.1 Function ~AddURegion2()~
*/
void URegion2::AddURegion2(URegion2 *newRegion)
{
if(timeInterval != newRegion->timeInterval)
{
throw invalid_argument("Intervals are not equal");
}
const DbArray<int> *insts = newRegion->GetPreciseInstants();
if (uremb.pInterval.GetPreciseInitialInstant(&preciseInstants) !=
newRegion->uremb.pInterval.GetPreciseInitialInstant(insts)
|| uremb.pInterval.GetPreciseFinalInstant
(&preciseInstants) !=
newRegion->uremb.pInterval.GetPreciseFinalInstant(insts))
{
throw invalid_argument("Precise Intervals are not equal");
}
const DbArray<MSegmentData2> *lines = newRegion->GetMSegmentData2();
const DbArray<PreciseMSegmentData> *pLines =
newRegion->GetPreciseMSegmentData();
const DbArray<int> *coords = newRegion->GetPreciseCoordinates();
for(int i = 0; i < lines->Size(); i++)
{
MSegmentData2 line;
lines->Get(i, line);
AddSegment(line);
PreciseMSegmentData pLine;
pLines->Get(i, pLine);
AddPreciseSegment(pLine);
}
for (int i = 0; i < coords->Size(); i++)
{
int coord;
coords->Get(i, coord);
AddCoordinate(coord);
}
}
/*
1.1.1 Function ~AddSegment()~
The bounding boxes are calculated on the integer grid, using the
down left corner of the respective cell for the minimum values and
the upper right corner for the maximum values.
*/
void URegion2::AddSegment(MSegmentData2 newSeg)
{
uremb.PutSegment(&segments, segments.Size(), newSeg, true);
if (uremb.BoundingBox().IsDefined())
{
double min[3] =
{ uremb.BoundingBox().MinD(0),
uremb.BoundingBox().MinD(1),
uremb.BoundingBox().MinD(2) };
double max[3] =
{ uremb.BoundingBox().MaxD(0),
uremb.BoundingBox().MaxD(1),
uremb.BoundingBox().MaxD(2) };
if (newSeg.GetInitialStartX() < min[0])
min[0] = newSeg.GetInitialStartX();
if (newSeg.GetFinalStartX() < min[0])
min[0] = newSeg.GetFinalStartX();
if (newSeg.GetInitialStartY() < min[1])
min[1] = newSeg.GetInitialStartY();
if (newSeg.GetFinalStartY() < min[1])
min[1] = newSeg.GetFinalStartY();
if (newSeg.GetInitialStartX()+1 > max[0])
max[0] = newSeg.GetInitialStartX()+1;
if (newSeg.GetFinalStartX()+1 > max[0])
max[0] = newSeg.GetFinalStartX()+1;
if (newSeg.GetInitialStartY()+1 > max[1])
max[1] = newSeg.GetInitialStartY()+1;
if (newSeg.GetFinalStartY()+1 > max[1])
max[1] = newSeg.GetFinalStartY()+1;
uremb.SetBBox(Rectangle<3>(true, min, max));
} else {
double min[3] =
{ newSeg.GetInitialStartX() < newSeg.GetFinalStartX()
? newSeg.GetInitialStartX() : newSeg.GetFinalStartX(),
newSeg.GetInitialStartY() < newSeg.GetFinalStartY()
? newSeg.GetInitialStartY() : newSeg.GetFinalStartY(),
uremb.timeInterval.start.ToDouble() };
double max[3] =
{ newSeg.GetInitialStartX() > newSeg.GetFinalStartX()
? newSeg.GetInitialStartX()+1 : newSeg.GetFinalStartX()+1,
newSeg.GetInitialStartY() > newSeg.GetFinalStartY()
? newSeg.GetInitialStartY()+1 : newSeg.GetFinalStartY()+1,
uremb.timeInterval.end.ToDouble() };
uremb.SetBBox(Rectangle<3>(true, min, max));
}
}
/*
1.1.1 Function ~AddPreciseSegment()~
*/
void URegion2::AddPreciseSegment(PreciseMSegmentData newSeg)
{
uremb.PutPreciseSegment(&preciseSegments, preciseSegments.Size(), newSeg);
}
/*
1.1.1 Function ~AddCoordinate()~
*/
void URegion2::AddCoordinate(int newCoord)
{
uremb.PutCoordinate(
&preciseCoordinates, preciseCoordinates.Size(), newCoord);
}
size_t URegionEmb2::HashValue() const{
return ( timeInterval.start.HashValue() ^ timeInterval.end.HashValue() );
}
/*
1.1.1 Methods for database operators
1.1.1.1 Method ~BoundingBox()~
*/
const Rectangle<3> URegion2::BoundingBox(const Geoid* geoid /*=0*/) const {
if (MR2_DEBUG) cerr << "URegion2::BoundingBox() called" << endl;
if(geoid){
cerr << __PRETTY_FUNCTION__ << ": Spherical geometry not implemented."
<< endl;
assert( !geoid ); // TODO: implement spherical geometry case
}
return uremb.BoundingBox();
}
/*
1.1.1.1 Method ~TemporalFunction()~
*/
void URegion2::TemporalFunction(const Instant& t,
Region& res,
bool ignoreLimits ) const {
if (MR2_DEBUG)
cerr << "URegion2::TemporalFunction() called" << endl;
res.Clear();
if( !IsDefined() || !t.IsDefined()) {
res.SetDefined( false );
} else {
res.SetDefined( true );
const mpq_class pt(0);
uremb.TemporalFunction(&segments, &preciseSegments,
&preciseCoordinates, &preciseInstants,
t, pt, scaleFactor, res, ignoreLimits);
}
}
/*
1.1.1.1 Method ~At()~
This method is not part of the master thesis but a stub is required to make
~URegion2~ non-abstract. To assure that accidential calls of this method are
recognized, its body contains a failed assertion.
*/
bool URegion2::At(const Region& val, TemporalUnit<Region>& result) const {
if (MR2_DEBUG) cerr << "URegion2::At() called" << endl;
assert( IsDefined() );
assert( val.IsDefined() );
cerr << __PRETTY_FUNCTION__ << " not implemented!" << endl;
assert(false);
URegion2* res = static_cast<URegion2*>(&result);
res->SetDefined( false );
return false;
}
/*
1.1.1.1 Method ~Passes()~
This method is not part of the master thesis but a stub is required to make
~URegion2~ non-abstract. To assure that accidential calls of this method are
recognized, its body contains a failed assertion.
*/
bool URegion2::Passes(const Region& val) const {
if (MR2_DEBUG) cerr << "URegion2::At() called" << endl;
assert( IsDefined() );
assert( val.IsDefined() );
cerr << __PRETTY_FUNCTION__ << " not implemented!" << endl;
assert(false);
return false;
}
/*
1.1.1.1 Method ~Clone()~
*/
URegion2* URegion2::Clone(void) const {
if (MR2_DEBUG) cerr << "URegion2::Clone() called" << endl;
URegion2* res = new URegion2( (unsigned int)0 );
res->CopyFrom(this);
res->SetDefined( this->del.isDefined );
return res;
}
/*
1.1.1.1 Method ~CopyFrom()~
*/
void URegion2::CopyFrom(const Attribute* right) {
if (MR2_DEBUG) cerr << "URegion2::CopyFrom() called" << endl;
const URegion2* ur = (const URegion2*) right;
*this = *ur;
this->SetDefined( ur->IsDefined() );
}
/*
1.1.1.1 Assignment operator
*/
URegion2& URegion2::operator= ( const URegion2& U) {
if(!U.IsDefined())
{
uremb = U.uremb;
segments = U.segments;
preciseSegments = U.preciseSegments;
preciseCoordinates = U.preciseCoordinates;
preciseInstants = U.preciseInstants;
SetDefined(false);
return *this;
}
timeInterval = U.timeInterval; // copy units copy of deftime!
// copy bbox, timeInterval, segmentsNum and pInterval
uremb = U.uremb;
uremb.SetStartPos(0); // set uremb.segmentsStartPos = 0
scaleFactor = U.scaleFactor;
URegionEmb2 Uuremb = U.uremb;
uremb.pInterval = Uuremb.pInterval;
del.isDefined = U.del.isDefined;
int start = U.uremb.GetStartPos(); //this is always zero!
int numsegs = U.uremb.GetSegmentsNum();
segments.clean();
segments.resize( U.uremb.GetSegmentsNum() );
preciseSegments.resize( U.uremb.GetSegmentsNum() );
preciseCoordinates.resize( U.uremb.GetSegmentsNum()*gmpCharNum*8);
for( int i=0 ; i<numsegs ; i++ )
{// copy single movingsegment
MSegmentData2 seg;
U.segments.Get(i+start, &seg);
segments.Put(i, seg);
PreciseMSegmentData pSeg;
U.preciseSegments.Get(i+start, &pSeg);
preciseSegments.Put(i, pSeg);
}
int numCoords = U.preciseCoordinates.Size();
for (int i = 0; i < numCoords; i++)
{
// copy single int
int coord;
U.preciseCoordinates.Get(i, &coord);
preciseCoordinates.Put(i, coord);
}
int numInsts = U.preciseInstants.Size();
for (int i = 0; i < numInsts; i++)
{
// copy single int
int inst;
U.preciseInstants.Get(i, &inst);
preciseInstants.Put(i, inst);
}
return *this;
}
/*
1.1.1 Functions for DbArray-Access
*/
int URegion2::NumOfFLOBs() const {
return 4;
}
Flob* URegion2::GetFLOB(const int i) {
assert(i >= 0 && i <= 3);
if (i==0) {
return &segments;
}
else if (i == 1) {
return &preciseSegments;
}
else if (i == 2) {
return &preciseCoordinates;
}
else {
return &preciseInstants;
}
}
/*
1.1.1 Access methods
*/
const int URegion2::GetScaleFactor() {
return scaleFactor;
}
void URegion2::SetScaleFactor(int factor) {
scaleFactor = factor;
}
/*
1.1.1 In- and Out-Functions
1.1.1.1 Function ~OutURegion2()~
*/
static ListExpr OutURegion2(ListExpr typeInfo, Word value) {
if (MR2_DEBUG)
cerr << "OutURegion2() called" << endl;
URegion2* ur = (URegion2*) value.addr;
// check for undefined value
if( !ur->IsDefined() )
return (nl->SymbolAtom("undef"));
ListExpr l =
OutURegionEmbedded2(
ur->GetEmbedded(),
(DbArray<MSegmentData2>*) ur->GetFLOB(0),
(DbArray<PreciseMSegmentData>*) ur->GetFLOB(1),
(DbArray<int>*) ur->GetFLOB(2),
(DbArray<int>*) ur->GetFLOB(3));
return nl->TwoElemList(nl->IntAtom(ur->GetScaleFactor()), l);
}
/*
1.1.1.1 Function ~InURegion2()~
*/
static Word InURegion2(const ListExpr typeInfo,
const ListExpr instance,
const int errorPos,
ListExpr& errorInfo,
bool& correct) {
if (MR2_DEBUG) cerr << "InURegion2() called" << endl;
URegion2* ur = new URegion2((unsigned int)0);
// Check for undefined value
if ( listutils::isSymbolUndefined( instance ) )
{
ur->SetDefined(false);
correct = true;
return SetWord ( ur );
}
if (nl->ListLength(instance) != 2
|| !nl->IsAtom(nl->First(instance))
|| nl->AtomType(nl->First(instance)) != IntType)
{
cerr << endl
<< "--------------------------------------------------"
<< endl
<< "ListExpr not in format (<int> <unit-list>)"
<< endl
<< "--------------------------------------------------"
<< endl;
return SetWord(Address(0));
}
if (nl->IntValue(nl->First(instance)) < 1)
{
cerr << endl
<< "--------------------------------------------------"
<< endl
<< "First element scale factor must be greater than zero!"
<< endl
<< "--------------------------------------------------"
<< endl;
return SetWord(Address(0));
}
ur->SetScaleFactor(nl->IntValue(nl->First(instance)));
URegionEmb2* uremb =
InURegionEmbedded2(
nl->Second(instance),
errorPos,
errorInfo,
(DbArray<MSegmentData2>*) ur->GetFLOB(0),
(DbArray<PreciseMSegmentData>*) ur->GetFLOB(1),
(DbArray<int>*) ur->GetFLOB(2),
(DbArray<int>*) ur->GetFLOB(3),
0);
if (!uremb) {
cerr << "Could not grok list representation of region unit."
<< endl;
delete ur;
correct = false;
return SetWord(Address(0));
}
ur->timeInterval = uremb->timeInterval;
ur->SetEmbedded(uremb);
ur->SetDefined(true);
delete uremb;
correct = true;
return SetWord(Address(ur));
}
/*
1.1 Algebra Integration
1.1.1 Function ~URegionProperty2()~
*/
static ListExpr URegionProperty2() {
ListExpr listrep = nl->TextAtom();
nl->AppendText(listrep,
"(<int> (<interval> <face>*)), where <int> "
"represents the scaleFactor, <interval> is "
"(<int> <int> <bool> <bool> <preciseInterval>) "
"and where <preciseInterval> is (<text> <text>) "
"or an empty list, "
"representing the initial and final instant. "
"<face> is (<outercycle> <holecycle>*), "
"where <outercycle> and <holecycle> are "
"(<int> <int> <int> <int> <precisePoint>), "
"and where <precisePoint> is "
"(<text> <text> <text> <text>) "
"or an empty list, representing "
"start X, start Y, end X and end Y values.");
ListExpr example = nl->TextAtom();
nl->AppendText(example,
"(10 ((0 10 TRUE TRUE ())"
"((((10 35 15 15 ())"
"(20 55 30 45 ())"
"(30 65 35 50 ())"
"(40 65 55 50 ())"
"(40 55 55 45 ())"
"(50 45 75 25 ())"
"(50 25 75 10 ())"
"(40 15 70 5 ())"
"(30 15 25 5 ()))"
"((20 30 30 20 ())"
"(20 40 30 30 ())"
"(30 40 40 30 ())"
"(30 30 40 20 ()))))))");
ListExpr remarks = nl->TextAtom();
nl->AppendText(remarks,
"All <holecycle> must be completely within "
"corresponding <outercylce>.");
return
nl->TwoElemList(
nl->FiveElemList(
nl->StringAtom("Signature"),
nl->StringAtom("Example Type List"),
nl->StringAtom("List Rep"),
nl->StringAtom("Example List"),
nl->StringAtom("Remarks")),
nl->FiveElemList(
nl->StringAtom("-> UNIT"),
nl->StringAtom("(uregion2)"),
listrep,
example,
remarks));
}
/*
1.1.1 Function ~CheckURegion2()~
*/
static bool CheckURegion2(ListExpr type, ListExpr& errorInfo) {
if (MR2_DEBUG) cerr << "CheckURegion2() called" << endl;
return nl->IsEqual(type, URegion2::BasicType());
}
/*
1.1.1 Function ~CreateURegion2()~
*/
static Word CreateURegion2(const ListExpr typeInfo) {
if (MR2_DEBUG) cerr << "CreateURegion2() called" << endl;
return (SetWord(new URegion2((unsigned int)0)));
}
/*
1.1.1 Function ~DeleteURegion2()~
*/
static void DeleteURegion2(const ListExpr typeInfo, Word& w) {
if (MR2_DEBUG) cerr << "DeleteURegion2() called" << endl;
URegion2 *ur = (URegion2*)w.addr;
delete ur;
w.addr = 0;
}
/*
1.1.1 Function ~CloseURegion2()~
*/
static void CloseURegion2(const ListExpr typeInfo, Word& w) {
if (MR2_DEBUG) cerr << "CloseURegion2() called" << endl;
delete (URegion2*) w.addr;
w.addr = 0;
}
/*
1.1.1 Function ~CloneURegion2()~
*/
static Word CloneURegion2(const ListExpr typeInfo, const Word& w) {
if (MR2_DEBUG) cerr << "CloneURegion2() called" << endl;
return SetWord(((URegion2*)w.addr)->Clone());
}
/*
1.1.1 Function ~CastURegion2()~
*/
static void* CastURegion2(void* addr) {
if (MR2_DEBUG) cerr << "CastURegion2() called" << endl;
return new (addr) URegion2;
}
/*
1.1.1 Method ~Sizeof()~
*/
size_t URegion2::Sizeof() const {
if (MR2_DEBUG) cerr << "URegion2::Sizeof() called" << endl;
return sizeof(*this);
}
/*
1.1.1 Function ~SizeOfURegion2()~
*/
static int SizeOfURegion2() {
if (MR2_DEBUG) cerr << "SizeOfURegion2() called" << endl;
return sizeof(URegion2);
}
/*
1.1.1 Function ~OpenURegion2()~
*/
bool OpenURegion2(SmiRecord& rec,
size_t& offset,
const ListExpr typeInfo,
Word& w) {
if (MR2_DEBUG) cerr << "OpenURegion2() called" << endl;
w = SetWord(Attribute::Open(rec, offset, typeInfo));
return true;
}
/*
1.1.1 Function ~SaveURegion2()~
Makes sense on ~URegion2~ instances with own segment storage only and will
run into failed assertion for other instances.
*/
static bool SaveURegion2(SmiRecord& rec,
size_t& offset,
const ListExpr typeInfo,
Word& w) {
if (MR2_DEBUG) cerr << "SaveURegion2() called" << endl;
URegion2* ur = static_cast<URegion2*> (w.addr);
Attribute::Save(rec, offset, typeInfo, ur);
return true;
}
/*
1.1.1 Type constructor ~uregion2~
*/
static TypeConstructor uregion2(
"uregion2",
URegionProperty2,
OutURegion2,
InURegion2,
0, 0, // SaveToList, RestoreFromList
CreateURegion2,
DeleteURegion2,
OpenURegion2,
SaveURegion2,
CloseURegion2,
CloneURegion2,
CastURegion2,
SizeOfURegion2,
CheckURegion2);
/*
1 Data type ~mregion2~
1.1 Class ~MRegion2~
1.1.1 Class definition
The class definition has been moved to ~MovingRegion2Algebra.h~.
1.1.1 Constructors
*/
MRegion2::MRegion2(const int n) :
Mapping<URegionEmb2, Region>(n),
msegmentdata(n),
preciseSegmentData(n),
preciseCoordinates(0),
preciseInstants(0){
if (MR2_DEBUG)
cerr << "MRegion2::MRegion2(int) called" << endl;
}
/*
This constructor creates a MRegion2 object from an existing MRegion object, by splitting the double
coordinates into an integer part and the remaining rest, which will be stored as mpq\_class values in
PreciseMSegmentData instances...
In a first step, the double coordinates are multiplied with scaleFactor to get the integer grid values.
*/
MRegion2::MRegion2(MRegion& coarseRegion, const int scaleFactor) :
Mapping<URegionEmb2, Region>(coarseRegion.GetNoComponents()),
msegmentdata(coarseRegion.GetMSegmentData()->Size()),
preciseSegmentData(coarseRegion.GetMSegmentData()->Size()),
preciseCoordinates(0),
preciseInstants(0){
if (MR2_DEBUG)
cerr << "MRegion2::MRegion2"
<< "(coarseRegion, scaleFactor) called" << endl
<< "ScaleFactor: " << scaleFactor << " " << endl
<< "Number of Units: " << coarseRegion.GetNoComponents()
<< " " << endl
<< "Number of segments: "
<< coarseRegion.GetMSegmentData()->Size() << " " << endl;
if (scaleFactor < 1)
{
cerr << endl
<< "--------------------------------------------------"
<< endl
<< "Scale factor must be greater than zero!"
<< endl
<< "--------------------------------------------------"
<< endl;
SetDefined(false);
return;
}
this->scaleFactor = scaleFactor;
//For each of the units of coarseRegion
for (int i = 0; i < coarseRegion.GetNoComponents(); i++)
{
URegionEmb origUremb;
coarseRegion.Get(i, origUremb);
if (MR2_DEBUG)
cerr << "MRegion2::MRegion2, handling unit "
<< i << " of coarseRegion" << endl;
//Transform the time interval to integer grid coordinates -
//preciseInterval is calculated in URegionEmb2-Constructor
double initial = (double)broughtDown
(origUremb.timeInterval.start.ToDouble());
double final = (double)broughtDown
(origUremb.timeInterval.end.ToDouble());
Instant initInst(initial);
Instant finInst(final);
Interval<Instant> interval(initInst, finInst,
origUremb.timeInterval.lc,
origUremb.timeInterval.rc);
//initialize precise time interval
PreciseInterval pInt(-1);
URegionEmb2 uremb(&msegmentdata, &preciseSegmentData,
&preciseCoordinates, &preciseInstants,
interval, pInt, origUremb, // O.Feuer
coarseRegion.GetMSegmentData(),
origUremb.GetStartPos(), scaleFactor);
this->Put(i, uremb);
}
}
/*
1.1.1 Attribute access methods
Get ~URegionEmb2~ unit ~i~ from this ~MRegion2~ instance and return it in ~ur~.
*/
void MRegion2::Get(const int i, URegionEmb2& ur) const {
Mapping<URegionEmb2, Region>::Get(i, ur);
}
const DbArray<MSegmentData2>* MRegion2::GetMSegmentData2(void) {
return &msegmentdata;
}
const DbArray<PreciseMSegmentData>* MRegion2::GetPreciseMSegmentData(void) {
return &preciseSegmentData;
}
const DbArray<int>* MRegion2::GetPreciseCoordinates(void) {
return &preciseCoordinates;
}
const DbArray<int>* MRegion2::GetPreciseInstants(void) {
return &preciseInstants;
}
const int MRegion2::GetScaleFactor(void) {
return scaleFactor;
}
void MRegion2::SetScaleFactor(int factor) {
scaleFactor = factor;
}
/*
1.1.1 Methods for database operators
1.1.1.1 Method ~Transform()~
*/
void MRegion2::Transform(double deltaX, double deltaY) {
if (MR2_DEBUG)
cerr << "MRegion2::Transform() called" << endl;
//for every unit
for (int i = 0; i < this->GetNoComponents(); i++)
{
URegionEmb2 uremb;
this->Get(i, uremb);
uremb.Transform(deltaX, deltaY, &msegmentdata,
&preciseSegmentData, &preciseCoordinates);
}
}
/*
1.1.1.1 Method ~Scale()~
*/
void MRegion2::Scale(double deltaX, double deltaY) {
if (MR2_DEBUG)
cerr << "MRegion2::Scale() called" << endl;
if (deltaX <= 0 || deltaY <= 0)
{
cerr << endl
<< "--------------------------------------------------"
<< endl
<< "Scale factors must be greater than zero!"
<< endl
<< "--------------------------------------------------"
<< endl;
SetDefined(false);
return;
}
//for every unit
for (int i = 0; i < this->GetNoComponents(); i++)
{
URegionEmb2 uremb;
this->Get(i, uremb);
uremb.Scale(deltaX, deltaY, &msegmentdata,
&preciseSegmentData, &preciseCoordinates);
}
}
/*
1.1.1.1 Method ~AtInstant()~
*/
void MRegion2::AtInstant(const Instant& t, Intime<Region>& result) {
if (MR2_DEBUG) cerr << "MRegion2::AtInstant() called" << endl;
assert(IsOrdered() && t.IsDefined());
int pos = Position(t );
if( pos == -1 )
{
//try with precise coordinates...
Instant help((double)broughtDown(t.ToDouble()));
pos = Position(help );
if (pos == -1)
result.SetDefined(false);
}
if (pos != -1)
{
URegionEmb2 posUnit;
Get(pos, posUnit);
result.SetDefined(true);
const mpq_class pt(0);
posUnit.TemporalFunction(&msegmentdata, &preciseSegmentData,
&preciseCoordinates, &preciseInstants,
t, pt, scaleFactor, result.value);
result.instant.CopyFrom(&t);
if (!result.value.IsDefined())
result.SetDefined(false);
}
}
/*
1.1.1.1 Method ~Initial()~
*/
void MRegion2::Initial(Intime<Region>& result) {
if (MR2_DEBUG) cerr << "MRegion2::Initial() called" << endl;
if ( !IsDefined() || IsEmpty() ) {
result.SetDefined(false);
return;
}
result.SetDefined(true);
assert(IsOrdered());
URegionEmb2 unit;
Get(0, unit);
if (!unit.timeInterval.lc) {
result.SetDefined(false);
return;
}
result.value.Clear();
result.value.SetDefined(true);
result.SetDefined(true);
unit.TemporalFunction(
&msegmentdata,
&preciseSegmentData,
&preciseCoordinates,
&preciseInstants,
unit.timeInterval.start,
unit.pInterval.GetPreciseInitialInstant(&preciseInstants),
scaleFactor,
result.value);
Instant inst(unit.timeInterval.start.ToDouble()+
unit.pInterval.GetPreciseInitialInstant(
&preciseInstants).get_d());
result.instant.CopyFrom(&inst);
}
/*
1.1.1.1 Method ~Final()~
*/
void MRegion2::Final(Intime<Region>& result) {
if (MR2_DEBUG) cerr << "MRegion2::Final() called" << endl;
if ( !IsDefined() || IsEmpty() ) {
result.SetDefined(false);
return;
}
result.SetDefined(true);
assert(IsOrdered());
URegionEmb2 unit;
Get(GetNoComponents()-1, unit);
if (!unit.timeInterval.rc) {
result.SetDefined(false);
return;
}
result.value.Clear();
result.value.SetDefined(true);
result.SetDefined(true);
unit.TemporalFunction(
&msegmentdata,
&preciseSegmentData,
&preciseCoordinates,
&preciseInstants,
unit.timeInterval.end,
unit.pInterval.GetPreciseFinalInstant(&preciseInstants),
scaleFactor,
result.value);
Instant inst(unit.timeInterval.end.ToDouble()+
unit.pInterval.GetPreciseFinalInstant(
&preciseInstants).get_d());
result.instant.CopyFrom(&inst);
}
/*
1.1.1 Methods for algebra integration
1.1.1.1 Method ~Clone()~
*/
MRegion2* MRegion2::Clone(void) const {
if (MR2_DEBUG) cerr << "MRegion2::Clone() called" << endl;
MRegion2* res = new MRegion2(0);
res->CopyFrom(this);
return res;
}
/*
1.1.1.1 Method ~CopyFrom()~
*/
void MRegion2::CopyFrom(const Attribute* right) {
if (MR2_DEBUG)
cerr << "MRegion2::CopyFrom() called, this="
<< this
<< ", &msegmentdata="
<< &msegmentdata
<< endl;
MRegion2* mr = (MRegion2*) right;
Clear();
if( !mr->IsDefined() ){
SetDefined( false );
return;
}
SetDefined( true );
if (MR2_DEBUG)
cerr << "MRegion2::CopyFrom() called, &mr->msegmentdata="
<< &mr->msegmentdata
<< endl;
/*
~InMRegion2()~ sorts the region units, therefore the following assumption
should hold.
*/
assert(mr->IsOrdered());
/*
Copy the units and assure that their pointer to the ~DBAarry~ containing
their moving segments points to this instance's ~DBArray~.
*/
StartBulkLoad();
for(int i = 0; i < mr->GetNoComponents(); i++) {
URegionEmb2 ur;
mr->Get(i, ur);
Add(ur);
}
EndBulkLoad(false);
/*
Copy the moving segments.
*/
msegmentdata.clean();
if (mr->msegmentdata.Size() > 0)
msegmentdata.resize(mr->msegmentdata.Size());
for (int i = 0; i < mr->msegmentdata.Size(); i++) {
MSegmentData2 dms;
mr->msegmentdata.Get(i, dms);
if (MR2_DEBUG)
cerr << "MRegion2::CopyFrom() segment "
<< i
<< ": initial=["
<< dms.GetInitialStartX()
<< " " << dms.GetInitialStartY()
<< " " << dms.GetInitialEndX()
<< " " << dms.GetInitialEndY()
<< "] final=["
<< dms.GetFinalStartX()
<< " " << dms.GetFinalStartY()
<< " " << dms.GetFinalEndX()
<< " " << dms.GetFinalEndY()
<< "]"
<< endl;
msegmentdata.Put(i, dms);
}
/*
Also copy the precise moving segments and the precise intervals.
*/
preciseSegmentData.clean();
if (mr->preciseSegmentData.Size() > 0)
{
preciseSegmentData.resize(mr->preciseSegmentData.Size());
}
for (int i = 0; i < mr->preciseSegmentData.Size(); i++) {
PreciseMSegmentData pdms;
mr->preciseSegmentData.Get(i, pdms);
if (MR2_DEBUG)
cerr << "MRegion2::CopyFrom(), copy precise segment "
<< i << endl;
preciseSegmentData.Put(i, pdms);
}
preciseCoordinates.clean();
if (mr->preciseCoordinates.Size() > 0)
{
preciseCoordinates.resize(mr->preciseCoordinates.Size());
}
for (int i = 0; i < mr->preciseCoordinates.Size(); i++) {
int coord;
mr->preciseCoordinates.Get(i, coord);
preciseCoordinates.Put(i, coord);
}
preciseInstants.clean();
if (mr->preciseInstants.Size() > 0)
{
preciseInstants.resize(mr->preciseInstants.Size());
}
for (int i = 0; i < mr->preciseInstants.Size(); i++)
{
int inst;
mr->preciseInstants.Get(i, inst);
preciseInstants.Put(i, inst);
}
if (MR2_DEBUG)
cerr << "copied " << preciseCoordinates.Size()
<< " coordinate's chars and "
<< preciseInstants.Size() << " instant's chars" << endl;
/*
And finally don't forget the scale factor!
*/
scaleFactor = mr->GetScaleFactor();
}
/*
1.1.1.1 ~DBArray~ access
*/
int MRegion2::NumOfFLOBs() const {
return 5;
}
Flob* MRegion2::GetFLOB(const int i) {
assert(i >= 0 && i <= 4);
if (i == 0)
{
return Mapping<URegionEmb2, Region>::GetFLOB(0); //Units-FLOB
}
else if (i == 1)
{
return &msegmentdata; //segments in the integer-grid
}
else if (i == 2)
{
return &preciseSegmentData; //precise segments
}
else if (i == 3)
{
return &preciseCoordinates; //coordinates of precise segments
}
else
{
return &preciseInstants; //coordinates of precise interval
}
}
/*
1.1 In- and Out-Functions
1.1.1 Function ~OutMRegion2()~
*/
static ListExpr OutMRegion2(ListExpr typeInfo, Word value) {
if (MR2_DEBUG)
cerr << "OutMRegion2() called" << endl;
MRegion2* mr = (MRegion2*) value.addr;
if (mr->IsEmpty()) return (nl->TheEmptyList());
assert(mr->IsOrdered());
ListExpr l = nl->TheEmptyList();
ListExpr lastElem;
//Do this for every unit of the Moving Region:
for (int i = 0; i < mr->GetNoComponents(); i++) {
URegionEmb2 ur;
mr->Get(i, ur);
ListExpr unitList =
OutURegionEmbedded2(
&ur,
(DbArray<MSegmentData2>*) mr->GetFLOB(1),
(DbArray<PreciseMSegmentData>*) mr->GetFLOB(2),
(DbArray<int>*) mr->GetFLOB(3),
(DbArray<int>*) mr->GetFLOB(4));
if (l == nl->TheEmptyList()) {
l = nl->Cons(unitList, nl->TheEmptyList());
lastElem = l;
} else
lastElem = nl->Append(lastElem, unitList);
}
return nl->TwoElemList(nl->IntAtom(mr->GetScaleFactor()), l);
}
/*
1.1.1 Function ~InMRegion2()~
*/
Word InMRegion2(const ListExpr typeInfo,
const ListExpr instance,
const int errorPos,
ListExpr& errorInfo,
bool& correct) {
if (MR2_DEBUG) cerr << "InMRegion2() called" << endl;
MRegion2* mr = new MRegion2(0);
mr->StartBulkLoad();
/*
First get the scaleFactor from the list.
*/
if (!nl->IsEmpty(instance))
{
if (nl->ListLength(instance) != 2
|| !nl->IsAtom(nl->First(instance))
|| nl->AtomType(nl->First(instance)) != IntType)
{
cerr << endl
<< "--------------------------------------------------"
<< endl
<< "ListExpr is not in correct format "
<< "(<int> (u1 u2 ... un))."
<< endl
<< "First element must be atom of IntType and "
<< "number of elements must be 2."
<< endl
<< "--------------------------------------------------"
<< endl;
return SetWord(Address(0));
}
if (nl->IntValue(nl->First(instance)) < 1)
{
cerr << endl
<< "--------------------------------------------------"
<< endl
<< "First element scale factor must be greater "
<< "than zero!"
<< endl
<< "--------------------------------------------------"
<< endl;
return SetWord(Address(0));
}
mr->SetScaleFactor(nl->IntValue(nl->First(instance)));
}
else {
cerr << endl
<< "--------------------------------------------------"
<< endl
<< "ListExpr is not in correct format (<int> (u1 u2 ... un))"
<< " but is empty!"
<< endl
<< "--------------------------------------------------" << endl;
return SetWord(Address(0));
}
ListExpr rest = nl->Second(instance);
//Get the units one by one from the ListExpr
while(!nl->IsEmpty(rest)) {
ListExpr first = nl->First(rest);
rest = nl->Rest(rest);
URegionEmb2* ur =
(URegionEmb2*) InURegionEmbedded2(
first,
errorPos,
errorInfo,
&mr->msegmentdata,
&mr->preciseSegmentData,
&mr->preciseCoordinates,
&mr->preciseInstants,
mr->msegmentdata.Size());
if (!ur) {
correct = false;
mr->Destroy();
delete mr;
return SetWord(Address(0));
}
mr->Add(*ur);
delete ur;
}
mr->EndBulkLoad(true);
if (mr->IsValid()) {
correct = true;
return SetWord(mr);
} else {
correct = false;
mr->Destroy();
delete mr;
return SetWord(Address(0));
}
}
/*
1.1 Algebra integration
1.1.1 Function ~MRegion2Property()~
*/
static ListExpr MRegion2Property() {
ListExpr listrep = nl->TextAtom();
nl->AppendText(listrep,
"(<int> (u1 ... un)) with ui uregion2 list representations, "
"and n >= 1. The <int> value is the scaleFactor for "
"transformation "
"of coordinates to double. Each ui is of format "
"(<interval> <faces>), where <interval> is "
"(<int> <int> <bool> <bool> <preciseInterval>) and where "
"<preciseInterval> is (<text> <text>) or an empty list, "
"representing precise initial and final instant. "
"Each <face> in <faces> is (<outercycle> <holecycle>*), "
"where <outercycle> and <holecycle> are "
"(<int> <int> <int> <int> <precisePoint>), and where "
"<precisePoint> is (<text> <text> <text> <text>) or "
"an empty list, and the <int> and <text> values representing "
"initial start X, initial start Y, final start X "
"and final start Y values.");
ListExpr example = nl->TextAtom();
nl->AppendText(example,
"(1000 (((0 10 TRUE TRUE ())"
"((((10 35 15 15 ())"
"(20 55 30 45 ())"
"(30 65 35 50 ())"
"(40 65 55 50 ())"
"(40 55 55 45 ())"
"(50 45 75 25 ())"
"(50 25 75 10 ())"
"(40 15 70 5 ())"
"(30 15 25 5 ()))"
"((20 30 30 20 ())"
"(20 40 30 30 ())"
"(30 40 40 30 ())"
"(30 30 40 20 ())))))))");
return
nl->TwoElemList(
nl->FourElemList(
nl->StringAtom("Signature"),
nl->StringAtom("Example Type List"),
nl->StringAtom("List Rep"),
nl->StringAtom("Example List")),
nl->FourElemList(
nl->StringAtom("-> MAPPING"),
nl->StringAtom("(mregion2)"),
listrep,
example));
}
/*
1.1.1 Function ~CheckMRegion2()~
*/
static bool CheckMRegion2(ListExpr type, ListExpr& errorInfo) {
if (MR2_DEBUG) cerr << "CheckMRegion2() called" << endl;
return nl->IsEqual(type, MRegion2::BasicType())
|| nl->IsEqual(type, "movingregion2");
}
/*
1.1.1 Function ~OpenMRegion2()~
*/
bool OpenMRegion2(SmiRecord& rec,
size_t& offset,
const ListExpr typeInfo,
Word& w) {
if (MR2_DEBUG) cerr << "OpenMRegion2() called" << endl;
w = SetWord(Attribute::Open(rec, offset, typeInfo));
return true;
}
/*
1.1.1 Function ~SaveMRegion2()~
*/
static bool SaveMRegion2(SmiRecord& rec,
size_t& offset,
const ListExpr typeInfo,
Word& w) {
if (MR2_DEBUG) cerr << "SaveMRegion2() called" << endl;
MRegion2* mr = static_cast<MRegion2*> (w.addr);
Attribute::Save(rec, offset, typeInfo, mr);
return true;
}
/*
1.1.1 Function ~CreateMregion2~
*/
static Word CreateMRegion2(const ListExpr typeInfo) {
if (MR2_DEBUG) cerr << "CreateMRegion2() called" << endl;
return SetWord(new MRegion2(0));
}
/*
1.1.1 Function ~DeleteMregion2~
*/
static void DeleteMRegion2(const ListExpr typeInfo, Word& w) {
if (MR2_DEBUG) cerr << "DeleteMRegion2() called" << endl;
((MRegion2*) w.addr)->Destroy();
delete (MRegion2*) w.addr;
w.addr = 0;
}
/*
1.1.1 Function ~CloseMregion2~
*/
static void CloseMRegion2(const ListExpr typeInfo, Word& w) {
if (MR2_DEBUG) cerr << "CloseMRegion2() called" << endl;
delete (MRegion2*) w.addr;
w.addr = 0;
}
/*
1.1.1 Function ~CloneMregion2~
*/
static Word CloneMRegion2(const ListExpr typeInfo, const Word& w) {
if (MR2_DEBUG) cerr << "CloneMRegion2() called" << endl;
return SetWord(((MRegion2*) w.addr)->Clone());
}
/*
1.1.1 Function ~CastMregion2~
*/
static void* CastMRegion2(void* addr) {
if (MR2_DEBUG) cerr << "CastMRegion2() called" << endl;
return new (addr) MRegion2;
}
/*
1.1.1 Function ~SizeOfMregion2~
*/
static int SizeOfMRegion2() {
if (MR2_DEBUG) cerr << "SizeOfMRegion2() called" << endl;
return sizeof(MRegion2);
}
/*
1.1.1 Type constructor ~mregion2~
*/
static TypeConstructor movingregion2(
MRegion2::BasicType(),
MRegion2Property,
OutMRegion2,
InMRegion2,
0, 0, // SaveToList, RestoreFromList
CreateMRegion2, DeleteMRegion2,
OpenMRegion2, SaveMRegion2,
CloseMRegion2, CloneMRegion2,
CastMRegion2,
SizeOfMRegion2,
CheckMRegion2);
/*
1.1 Helper function(s)
Create ~MPoint~ instance from intervals in units in ~MRegion2~ instance
~mr~ and the constant point ~p~.
*/
static MPoint CreateMPointFromPoint(MRegion2* mr, Point* p) {
if (MR2_DEBUG) cerr << "CreateMPointFromPoint() called" << endl;
MPoint mp(0);
if( !mr->IsDefined() || !p->IsDefined() ){
mp.SetDefined( false );
} else {
mp.SetDefined( true );
for (int i = 0; i < mr->GetNoComponents(); i++) {
URegionEmb2 ur;
mr->Get(i, ur);
UPoint up(ur.timeInterval,
p->GetX(), p->GetY(),
p->GetX(), p->GetY());
mp.Add(up);
}
}
return mp;
}
/*
1 Operator definition
1.1 Type mapping functions
1.1.1 Generic
Used by ~intersection~:
*/
static ListExpr MPointMRegion2ToMPointTypeMap(ListExpr args)
{
if (MR2_DEBUG)
{
cerr << "MPointMRegion2ToMPointTypeMap() called" << endl;
cerr << nl->SymbolValue(nl->First(args)) << endl;
cerr << nl->SymbolValue(nl->Second(args)) << endl;
}
if (nl->ListLength(args) == 2
&& nl->IsEqual(nl->First(args), MPoint::BasicType())
&& nl->IsEqual(nl->Second(args), MRegion2::BasicType()))
return nl->SymbolAtom(MPoint::BasicType());
else
return nl->SymbolAtom(Symbol::TYPEERROR());
}
/*
Used by ~inside~:
*/
static ListExpr MPointMRegion2ToMBoolTypeMap(ListExpr args) {
if (MR2_DEBUG)
cerr << "MPointMRegion2ToMBoolTypeMap() called" << endl;
if (nl->ListLength(args) == 2
&& nl->IsEqual(nl->First(args), MPoint::BasicType())
&& nl->IsEqual(nl->Second(args), MRegion2::BasicType()))
return nl->SymbolAtom(MBool::BasicType());
else
return nl->SymbolAtom(Symbol::TYPEERROR());
}
/*
Used by ~initial~ and ~final~:
*/
static ListExpr MRegion2ToIRegion2TypeMap(ListExpr args) {
if (MR2_DEBUG)
cerr << "MRegion2ToIRegion2TypeMap() called" << endl;
if (nl->ListLength(args) == 1
&& nl->IsEqual(nl->First(args), MRegion2::BasicType()))
return nl->SymbolAtom(IRegion2::BasicType());
else
return nl->SymbolAtom(Symbol::TYPEERROR());
}
/*
Used by ~atinstant~:
*/
static ListExpr AtInstantTypeMap(ListExpr args) {
if (MR2_DEBUG)
cerr << "AtInstantTypeMap() called" << endl;
if (nl->ListLength(args) == 2
&& nl->IsEqual(nl->First(args), MRegion2::BasicType())
&& nl->IsEqual(nl->Second(args), Instant::BasicType()))
return nl->SymbolAtom(IRegion2::BasicType());
else if (nl->ListLength(args) == 2
&& nl->IsEqual(nl->First(args), URegion2::BasicType())
&& nl->IsEqual(nl->Second(args), Instant::BasicType()))
return nl->SymbolAtom(IRegion2::BasicType());
else
return nl->SymbolAtom(Symbol::TYPEERROR());
}
/*
Used by ~mregiontomregion2~:
*/
static ListExpr MRegionToMRegion2TypeMap(ListExpr args){
if (MR2_DEBUG) cout << "MRegionToMRegion2TypeMap called " << endl;
if (nl->ListLength(args)!=2){
ErrorReporter::ReportError("invalid number of arguments");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
if(!nl->IsEqual(nl->First(args),MRegion::BasicType())){
ErrorReporter::ReportError(
"MRegion as first argument required");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
if(!nl->IsEqual(nl->Second(args),CcInt::BasicType())){
ErrorReporter::ReportError(
"int as second argument required");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
if (MR2_DEBUG) cout << "Typemap returns mregion2" << endl;
return nl->SymbolAtom(MRegion2::BasicType());
}
/*
Used by ~uregiontouregion2~:
*/
static ListExpr URegionToURegion2TypeMap(ListExpr args) {
if (MR2_DEBUG) cout << "URegionToURegion2TypeMap called " << endl;
if (nl->ListLength(args) != 2) {
ErrorReporter::ReportError("invalid number of arguments");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
if (!nl->IsEqual(nl->First(args), URegion::BasicType())) {
ErrorReporter::ReportError(
"URegion as first argument required");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
if (!nl->IsEqual(nl->Second(args), CcInt::BasicType())) {
ErrorReporter::ReportError(
"int as second argument required");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
if (MR2_DEBUG) cout << "Typemap returns uregion2" << endl;
return nl->SymbolAtom(URegion2::BasicType());
}
/*
Used by ~scale~:
*/
static ListExpr ScaleTypeMap(ListExpr args){
if (MR2_DEBUG) cout << "ScaleTypeMap called " << endl;
if (nl->ListLength(args) != 3){
ErrorReporter::ReportError("invalid number of arguments");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
if (!nl->IsEqual(nl->First(args),MRegion2::BasicType())){
ErrorReporter::ReportError(
"MRegion2 as first argument required");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
if (!nl->IsEqual(nl->Second(args),CcReal::BasicType())){
ErrorReporter::ReportError(
"double as second argument required");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
if (!nl->IsEqual(nl->Third(args),CcReal::BasicType())){
ErrorReporter::ReportError(
"double as third argument required");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
if(MR2_DEBUG) cout << "Typemap returns mregion2" << endl;
return nl->SymbolAtom(MRegion2::BasicType());
}
/*
Used by ~transform~:
*/
static ListExpr TransformTypeMap(ListExpr args){
if (MR2_DEBUG) cout << "TransformTypeMap called " << endl;
if (nl->ListLength(args) != 3){
ErrorReporter::ReportError("invalid number of arguments");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
if (!nl->IsEqual(nl->First(args),MRegion2::BasicType())){
ErrorReporter::ReportError(
"MRegion2 as first argument required");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
if (!nl->IsEqual(nl->Second(args),CcReal::BasicType())){
ErrorReporter::ReportError(
"double as second argument required");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
if (!nl->IsEqual(nl->Third(args),CcReal::BasicType())){
ErrorReporter::ReportError(
"double as third argument required");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
if(MR2_DEBUG) cout << "Typemap returns mregion2" << endl;
return nl->SymbolAtom(MRegion2::BasicType());
}
/*
1.1 Selection functions
1.1.1 Generic
Used by ~intersection~ and ~inside~:
*/
static int MPointMRegion2Select(ListExpr args) {
if (MR2_DEBUG)
cerr << "MPointMRegion2Select() called" << endl;
if (nl->ListLength(args) == 2
&& nl->SymbolValue(nl->First(args)) == MPoint::BasicType()
&& nl->SymbolValue(nl->Second(args)) == MRegion2::BasicType())
return 0;
else
return -1;
}
/*
Used by ~initial~, ~final~, ~deftime~ and ~traversed~:
*/
static int MRegion2Select(ListExpr args) {
if (MR2_DEBUG)
cerr << "MRegion2Select() called" << endl;
if (nl->ListLength(args) == 1
&& nl->SymbolValue(nl->First(args)) == MRegion2::BasicType())
return 0;
else
return -1;
}
/*
Used by ~atinstant~:
*/
static int AtInstantSelect(ListExpr args) {
if (MR2_DEBUG)
cerr << "AtInstantSelect() called" << endl;
if (nl->ListLength(args) == 2
&& nl->SymbolValue(nl->First(args)) == MRegion2::BasicType()
&& nl->SymbolValue(nl->Second(args)) == Instant::BasicType())
return 0;
else if (nl->ListLength(args) == 2
&& nl->SymbolValue(nl->First(args)) == URegion2::BasicType()
&& nl->SymbolValue(nl->Second(args)) == Instant::BasicType())
return 1;
else
return -1;
}
/*
1.1 Value mapping functions
1.1.1 Normal value mapping functions
*/
static int AtInstantValueMap_URegion2(Word* args,
Word& result,
int message,
Word& local,
Supplier s) {
if (MR2_DEBUG) cerr << "AtInstantValueMap_URegion2() called" << endl;
result = qp->ResultStorage(s);
Intime<Region>* res = (Intime<Region>*) result.addr;
URegion2* ur = (URegion2*) args[0].addr;
Instant* inst = (Instant*) args[1].addr;
if (ur->IsDefined()) {
ur->TemporalFunction(*inst, res->value);
if ((res->value).IsDefined())
{
if (MR2_DEBUG) cerr << "success!" << endl;
res->instant.CopyFrom(inst);
res->SetDefined(true);
}
else
{
if (MR2_DEBUG) cerr << "Not defined..." << endl;
res->SetDefined(false);
}
} else {
res->SetDefined(false);
}
return 0;
}
static int MRegionToMRegion2ValueMap(Word* args,
Word& result,
int message,
Word& local,
Supplier s) {
result = qp->ResultStorage(s);
MRegion* mr = (MRegion*) args[0].addr;
int factor = StdTypes::GetInt(args[1]);
MRegion2 res(*mr, factor);
((MRegion2*)result.addr)->CopyFrom(&res);
res.Destroy();
return (0);
}
static int URegionToURegion2ValueMap(Word* args,
Word& result,
int message,
Word& local,
Supplier s) {
result = qp->ResultStorage(s);
URegion* ur = (URegion*) args[0].addr;
int factor = StdTypes::GetInt(args[1]);
if (factor < 1)
{
cerr << endl
<< "--------------------------------------------------"
<< endl
<< "Scale factor must be greater than zero!"
<< endl
<< "--------------------------------------------------"
<< endl;
((URegion2*)result.addr)->SetDefined(false);
return 0;
}
URegion2 res(*ur, factor);
((URegion2*)result.addr)->CopyFrom(&res);
return(0);
}
static int ScaleValueMap(Word* args,
Word& result,
int message,
Word& local,
Supplier s) {
result = qp->ResultStorage(s);
MRegion2* mr = (MRegion2*) args[0].addr;
CcReal* deltaX = static_cast<CcReal*>(args[1].addr);
CcReal* deltaY = static_cast<CcReal*>(args[2].addr);
MRegion2 res(true);
res.CopyFrom(*&mr);
res.Scale(deltaX->GetRealval(), deltaY->GetRealval());
((MRegion2*)result.addr)->CopyFrom(&res);
return (0);
}
static int TransformValueMap(Word* args,
Word& result,
int message,
Word& local,
Supplier s) {
result = qp->ResultStorage(s);
MRegion2* mr = (MRegion2*) args[0].addr;
CcReal* deltaX = static_cast<CcReal*>(args[1].addr);
CcReal* deltaY = static_cast<CcReal*>(args[2].addr);
MRegion2 res(true);
res.CopyFrom(*&mr);
res.Transform(deltaX->GetRealval(), deltaY->GetRealval());
((MRegion2*)result.addr)->CopyFrom(&res);
return (0);
}
/*
1.1 Value mapping arrays
*/
static ValueMapping atinstantvaluemap[] =
{ MappingAtInstant<MRegion2, Region>,
AtInstantValueMap_URegion2 };
static ValueMapping initialvaluemap[] =
{ MappingInitial<MRegion2, URegionEmb2, Region> };
static ValueMapping finalvaluemap[] =
{ MappingFinal<MRegion2, URegionEmb2, Region> };
/*
1.1 Operator specifications
*/
static const string atinstantspec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
" ( <text>(mregion2 instant) -> iregion2, "
" (uregion2 instant) -> iregion2,</text--->"
" <text>_ atinstant _ </text--->"
" <text>Get the iregion2 value corresponding "
"to the instant.</text--->"
" <text>mregion2_1 atinstant instant1</text---> ) )";
static const string initialspec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
" ( <text>mregion2 -> iregion2</text--->"
" <text>initial( _ )</text--->"
" <text>Get the iregion2 value corresponding to "
"the initial instant."
" </text--->"
" <text>initial( mregion2_1 )</text---> ) )";
static const string finalspec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
" ( <text>mregion2 -> iregion2</text--->"
" <text>final( _ )</text--->"
" <text>Get the iregion2 value corresponding to "
"the final instant."
" </text--->"
" <text>final( mregion2_1 )</text---> ) )";
static const string mregiontomregion2spec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
" ( <text>mregion x int -> mregion2</text--->"
" <text>mregiontomregion2( _, _)</text--->"
" <text>Creates a moving region2 from the given moving region"
" using the int value as scale factor </text--->"
" <text>query mregiontomregion2(mr, sfac)</text--->) )";
static const string uregiontouregion2spec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
" ( <text>uregion x int -> uregion2</text--->"
" <text>uregiontouregion2(_, _)</text--->"
" <text>Creates a moving region2 unit"
" from the given moving region unit"
" using the int value as scale factor </text--->"
" <text>query uregiontouregion2(ur, sfac)</text--->) )";
static const string scalespec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
" ( <text>mregion2 x double x double -> mregion2</text--->"
" <text>scale( _, _, _)</text--->"
" <text>Changes a given moving region2 through scaling,"
" using the double values as scale factors for x and y </text--->"
" <text>query scale(mr2, deltax, deltay)</text--->) )";
static const string transformspec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
" ( <text>mregion2 x double x double -> mregion2</text--->"
" <text>transform( _, _, _)</text--->"
" <text>Changes a given moving region2 through transforming"
" using the double values to transform each point"
" in x and y direction </text--->"
" <text>query transform(mr2, deltax, deltay)</text--->) )";
/*
1.1 Operator creation
*/
static Operator atinstant("atinstant",
atinstantspec,
2,
atinstantvaluemap,
AtInstantSelect,
AtInstantTypeMap);
static Operator initial("initial",
initialspec,
1,
initialvaluemap,
MRegion2Select,
MRegion2ToIRegion2TypeMap);
static Operator final("final",
finalspec,
1,
finalvaluemap,
MRegion2Select,
MRegion2ToIRegion2TypeMap);
static Operator mregiontomregion2("mregiontomregion2",
mregiontomregion2spec,
MRegionToMRegion2ValueMap,
simpleSelect,
MRegionToMRegion2TypeMap);
static Operator uregiontouregion2("uregiontouregion2",
uregiontouregion2spec,
URegionToURegion2ValueMap,
simpleSelect,
URegionToURegion2TypeMap);
static Operator scale("scale",
scalespec,
ScaleValueMap,
simpleSelect,
ScaleTypeMap);
static Operator mra2transform("mra2transform",
transformspec,
TransformValueMap,
simpleSelect,
TransformTypeMap);
/*
1 Algebra creation
*/
class MovingRegion2Algebra : public Algebra {
public:
MovingRegion2Algebra() : Algebra() {
AddTypeConstructor(&intimeregion2);
AddTypeConstructor(&uregion2);
AddTypeConstructor(&movingregion2);
intimeregion2.AssociateKind(Kind::TEMPORAL());
intimeregion2.AssociateKind(Kind::DATA());
uregion2.AssociateKind(Kind::TEMPORAL());
uregion2.AssociateKind(Kind::DATA());
movingregion2.AssociateKind(Kind::TEMPORAL());
movingregion2.AssociateKind(Kind::DATA());
AddOperator(&atinstant);
AddOperator(&initial);
AddOperator(&final);
AddOperator(&mregiontomregion2);
AddOperator(&uregiontouregion2);
AddOperator(&scale);
AddOperator(&mra2transform);
//AddOperator(&addURegion2);
}
~MovingRegion2Algebra() {}
};
extern "C"
Algebra* InitializeMovingRegion2Algebra(NestedList* nlRef,
QueryProcessor *qpRef) {
nl = nlRef;
qp = qpRef;
return new MovingRegion2Algebra();
}